From: Kevin McCarthy Date: Mon, 26 Nov 2018 03:48:49 +0000 (-0800) Subject: Prevent trying to match a failing color body regex repeatedly X-Git-Tag: 2019-10-25~450^2~11 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6a6c3bbd0eececd2f149084b45755f29983ad0f2;p=neomutt Prevent trying to match a failing color body regex repeatedly Emails with really long lines (e.g. spam), can suffer performance if a complicated regex is matched to no effect over and over. If the regex failed at the beginning, it won't match at the end of another's regex match range, so turn it off. --- diff --git a/mutt_curses.h b/mutt_curses.h index d8e8158fc..265c53e66 100644 --- a/mutt_curses.h +++ b/mutt_curses.h @@ -186,6 +186,8 @@ struct ColorLine short bg; int pair; STAILQ_ENTRY(ColorLine) entries; + + bool stop_matching : 1; ///< used by the pager for body patterns, to prevent the color from being retried once it fails }; STAILQ_HEAD(ColorLineHead, ColorLine); diff --git a/pager.c b/pager.c index 6a74a15ea..34511ab18 100644 --- a/pager.c +++ b/pager.c @@ -894,6 +894,7 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n, bool *force_redraw, bool q_classify) { struct ColorLine *color_line = NULL; + struct ColorLineHead *head = NULL; regmatch_t pmatch[1]; bool found; bool null_rx; @@ -1012,6 +1013,14 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n, i = 0; offset = 0; line_info[n].chunks = 0; + if (line_info[n].type == MT_COLOR_HDEFAULT) + head = &ColorHdrList; + else + head = &ColorBodyList; + STAILQ_FOREACH(color_line, head, entries) + { + color_line->stop_matching = false; + } do { if (!buf[offset]) @@ -1019,15 +1028,10 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n, found = false; null_rx = false; - struct ColorLineHead *head = NULL; - if (line_info[n].type == MT_COLOR_HDEFAULT) - head = &ColorHdrList; - else - head = &ColorBodyList; STAILQ_FOREACH(color_line, head, entries) { - if (regexec(&color_line->regex, buf + offset, 1, pmatch, - (offset ? REG_NOTBOL : 0)) == 0) + if (!color_line->stop_matching && regexec(&color_line->regex, buf + offset, 1, pmatch, + (offset ? REG_NOTBOL : 0)) == 0) { if (pmatch[0].rm_eo != pmatch[0].rm_so) { @@ -1063,6 +1067,13 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n, else null_rx = true; /* empty regex; don't add it, but keep looking */ } + else + { + /* Once a regexp fails to match, don't try matching it again. + * On very long lines this can cause a performance issue if there + * are other regexps that have many matches. */ + color_line->stop_matching = true; + } } if (null_rx)