📄 pattern.c
字号:
min->tm_mon = max->tm_mon; max->tm_mon = tmp; tmp = min->tm_mday; min->tm_mday = max->tm_mday; max->tm_mday = tmp; min->tm_hour = min->tm_min = min->tm_sec = 0; max->tm_hour = 23; max->tm_min = max->tm_sec = 59; }}static const char * parse_date_range (const char* pc, struct tm *min, struct tm *max, int haveMin, struct tm *baseMin, BUFFER *err){ int flag = M_PDR_NONE; while (*pc && ((flag & M_PDR_DONE) == 0)) { const char *pt; char ch = *pc++; SKIPWS (pc); switch (ch) { case '-': { /* try a range of absolute date minus offset of Ndwmy */ pt = get_offset (min, pc, -1); if (pc == pt) { if (flag == M_PDR_NONE) { /* nothing yet and no offset parsed => absolute date? */ if (!getDate (pc, max, err)) flag |= (M_PDR_ABSOLUTE | M_PDR_ERRORDONE); /* done bad */ else { /* reestablish initial base minimum if not specified */ if (!haveMin) memcpy (min, baseMin, sizeof(struct tm)); flag |= (M_PDR_ABSOLUTE | M_PDR_DONE); /* done good */ } } else flag |= M_PDR_ERRORDONE; } else { pc = pt; if (flag == M_PDR_NONE && !haveMin) { /* the very first "-3d" without a previous absolute date */ max->tm_year = min->tm_year; max->tm_mon = min->tm_mon; max->tm_mday = min->tm_mday; } flag |= M_PDR_MINUS; } } break; case '+': { /* enlarge plusRange */ pt = get_offset (max, pc, 1); if (pc == pt) flag |= M_PDR_ERRORDONE; else { pc = pt; flag |= M_PDR_PLUS; } } break; case '*': { /* enlarge window in both directions */ pt = get_offset (min, pc, -1); if (pc == pt) flag |= M_PDR_ERRORDONE; else { pc = get_offset (max, pc, 1); flag |= M_PDR_WINDOW; } } break; default: flag |= M_PDR_ERRORDONE; } SKIPWS (pc); } if ((flag & M_PDR_ERROR) && !(flag & M_PDR_ABSOLUTE)) { /* getDate has its own error message, don't overwrite it here */ snprintf (err->data, err->dsize, _("Invalid relative date: %s"), pc-1); } return ((flag & M_PDR_ERROR) ? NULL : pc);}static int eat_date (pattern_t *pat, BUFFER *s, BUFFER *err){ BUFFER buffer; struct tm min, max; memset (&buffer, 0, sizeof (buffer)); if (mutt_extract_token (&buffer, s, M_TOKEN_COMMENT | M_TOKEN_PATTERN) != 0 || !buffer.data) { strfcpy (err->data, _("error in expression"), err->dsize); return (-1); } memset (&min, 0, sizeof (min)); /* the `0' time is Jan 1, 1970 UTC, so in order to prevent a negative time when doing timezone conversion, we use Jan 2, 1970 UTC as the base here */ min.tm_mday = 2; min.tm_year = 70; memset (&max, 0, sizeof (max)); /* Arbitrary year in the future. Don't set this too high or mutt_mktime() returns something larger than will fit in a time_t on some systems */ max.tm_year = 130; max.tm_mon = 11; max.tm_mday = 31; max.tm_hour = 23; max.tm_min = 59; max.tm_sec = 59; if (strchr ("<>=", buffer.data[0])) { /* offset from current time <3d less than three days ago >3d more than three days ago =3d exactly three days ago */ time_t now = time (NULL); struct tm *tm = localtime (&now); int exact = 0; if (buffer.data[0] == '<') { memcpy (&min, tm, sizeof (min)); tm = &min; } else { memcpy (&max, tm, sizeof (max)); tm = &max; if (buffer.data[0] == '=') exact++; } tm->tm_hour = 23; tm->tm_min = tm->tm_sec = 59; /* force negative offset */ get_offset (tm, buffer.data + 1, -1); if (exact) { /* start at the beginning of the day in question */ memcpy (&min, &max, sizeof (max)); min.tm_hour = min.tm_sec = min.tm_min = 0; } } else { const char *pc = buffer.data; int haveMin = FALSE; int untilNow = FALSE; if (isdigit ((unsigned char)*pc)) { /* mininum date specified */ if ((pc = getDate (pc, &min, err)) == NULL) { FREE (&buffer.data); return (-1); } haveMin = TRUE; SKIPWS (pc); if (*pc == '-') { const char *pt = pc + 1; SKIPWS (pt); untilNow = (*pt == '\0'); } } if (!untilNow) { /* max date or relative range/window */ struct tm baseMin; if (!haveMin) { /* save base minimum and set current date, e.g. for "-3d+1d" */ time_t now = time (NULL); struct tm *tm = localtime (&now); memcpy (&baseMin, &min, sizeof(baseMin)); memcpy (&min, tm, sizeof (min)); min.tm_hour = min.tm_sec = min.tm_min = 0; } /* preset max date for relative offsets, if nothing follows we search for messages on a specific day */ max.tm_year = min.tm_year; max.tm_mon = min.tm_mon; max.tm_mday = min.tm_mday; if (!parse_date_range (pc, &min, &max, haveMin, &baseMin, err)) { /* bail out on any parsing error */ FREE (&buffer.data); return (-1); } } } /* Since we allow two dates to be specified we'll have to adjust that. */ adjust_date_range (&min, &max); pat->min = mutt_mktime (&min, 1); pat->max = mutt_mktime (&max, 1); FREE (&buffer.data); return 0;}static int patmatch (const pattern_t* pat, const char* buf){ if (pat->stringmatch) return !strstr (buf, pat->p.str); else if (pat->groupmatch) return !mutt_group_match (pat->p.g, buf); else return regexec (pat->p.rx, buf, 0, NULL, 0);}static struct pattern_flags *lookup_tag (char tag){ int i; for (i = 0; Flags[i].tag; i++) if (Flags[i].tag == tag) return (&Flags[i]); return NULL;}static /* const */ char *find_matching_paren (/* const */ char *s){ int level = 1; for (; *s; s++) { if (*s == '(') level++; else if (*s == ')') { level--; if (!level) break; } } return s;}void mutt_pattern_free (pattern_t **pat){ pattern_t *tmp; while (*pat) { tmp = *pat; *pat = (*pat)->next; if (tmp->stringmatch) FREE (&tmp->p.str); else if (tmp->groupmatch) tmp->p.g = NULL; else if (tmp->p.rx) { regfree (tmp->p.rx); FREE (&tmp->p.rx); } if (tmp->child) mutt_pattern_free (&tmp->child); FREE (&tmp); }}pattern_t *mutt_pattern_comp (/* const */ char *s, int flags, BUFFER *err){ pattern_t *curlist = NULL; pattern_t *tmp; pattern_t *last = NULL; int not = 0; int alladdr = 0; int or = 0; int implicit = 1; /* used to detect logical AND operator */ struct pattern_flags *entry; char *p; char *buf; BUFFER ps; memset (&ps, 0, sizeof (ps)); ps.dptr = s; ps.dsize = mutt_strlen (s); while (*ps.dptr) { SKIPWS (ps.dptr); switch (*ps.dptr) { case '^': ps.dptr++; alladdr = !alladdr; break; case '!': ps.dptr++; not = !not; break; case '|': if (!or) { if (!curlist) { snprintf (err->data, err->dsize, _("error in pattern at: %s"), ps.dptr); return NULL; } if (curlist->next) { /* A & B | C == (A & B) | C */ tmp = new_pattern (); tmp->op = M_AND; tmp->child = curlist; curlist = tmp; last = curlist; } or = 1; } ps.dptr++; implicit = 0; not = 0; alladdr = 0; break; case '%': case '=': case '~': if (implicit && or) { /* A | B & C == (A | B) & C */ tmp = new_pattern (); tmp->op = M_OR; tmp->child = curlist; curlist = tmp; last = tmp; or = 0; } tmp = new_pattern (); tmp->not = not; tmp->alladdr = alladdr; tmp->stringmatch = (*ps.dptr == '=') ? 1 : 0; tmp->groupmatch = (*ps.dptr == '%') ? 1 : 0; not = 0; alladdr = 0; if (last) last->next = tmp; else curlist = tmp; last = tmp; ps.dptr++; /* move past the ~ */ if ((entry = lookup_tag (*ps.dptr)) == NULL) { snprintf (err->data, err->dsize, _("%c: invalid command"), *ps.dptr); mutt_pattern_free (&curlist); return NULL; } if (entry->class && (flags & entry->class) == 0) { snprintf (err->data, err->dsize, _("%c: not supported in this mode"), *ps.dptr); mutt_pattern_free (&curlist); return NULL; } tmp->op = entry->op; ps.dptr++; /* eat the operator and any optional whitespace */ SKIPWS (ps.dptr); if (entry->eat_arg) { if (!*ps.dptr) { snprintf (err->data, err->dsize, _("missing parameter")); mutt_pattern_free (&curlist); return NULL; } if (entry->eat_arg (tmp, &ps, err) == -1) { mutt_pattern_free (&curlist); return NULL; } } implicit = 1; break; case '(': p = find_matching_paren (ps.dptr + 1); if (*p != ')') { snprintf (err->data, err->dsize, _("mismatched parenthesis: %s"), ps.dptr); mutt_pattern_free (&curlist); return NULL; } /* compile the sub-expression */ buf = mutt_substrdup (ps.dptr + 1, p); if ((tmp = mutt_pattern_comp (buf, flags, err)) == NULL) { FREE (&buf); mutt_pattern_free (&curlist); return NULL; } FREE (&buf); if (last) last->next = tmp; else curlist = tmp; last = tmp; tmp->not ^= not; tmp->alladdr |= alladdr; not = 0; alladdr = 0; ps.dptr = p + 1; /* restore location */ break; default: snprintf (err->data, err->dsize, _("error in pattern at: %s"), ps.dptr); mutt_pattern_free (&curlist); return NULL; } } if (!curlist) { strfcpy (err->data, _("empty pattern"), err->dsize); return NULL; } if (curlist->next) { tmp = new_pattern (); tmp->op = or ? M_OR : M_AND; tmp->child = curlist; curlist = tmp; } return (curlist);}static intperform_and (pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, HEADER *hdr){ for (; pat; pat = pat->next) if (mutt_pattern_exec (pat, flags, ctx, hdr) <= 0) return 0; return 1;}static intperform_or (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, HEADER *hdr){ for (; pat; pat = pat->next) if (mutt_pattern_exec (pat, flags, ctx, hdr) > 0) return 1; return 0;}static int match_adrlist (pattern_t *pat, int match_personal, int n, ...){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -