]> granicus.if.org Git - vim/commitdiff
updated for version 7.3.1149 v7.3.1149
authorBram Moolenaar <Bram@vim.org>
Sat, 8 Jun 2013 16:19:48 +0000 (18:19 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 8 Jun 2013 16:19:48 +0000 (18:19 +0200)
Problem:    New regexp engine: Matching plain text could be faster.
Solution:   Detect a plain text match and handle it specifically.  Add
            vim_regfree().

28 files changed:
src/buffer.c
src/edit.c
src/eval.c
src/ex_cmds.c
src/ex_cmds2.c
src/ex_docmd.c
src/ex_eval.c
src/ex_getln.c
src/fileio.c
src/gui.c
src/macros.h
src/misc1.c
src/misc2.c
src/option.c
src/proto/regexp.pro
src/quickfix.c
src/regexp.c
src/regexp.h
src/regexp_nfa.c
src/screen.c
src/search.c
src/spell.c
src/syntax.c
src/tag.c
src/testdir/test64.in
src/testdir/test64.ok
src/version.c
src/window.c

index a46e30ed1c893ed3ec3055fae111ce6ca0280a39..6e3fa55b8bfc37f18e188b67e4c6d914fdd13368 100644 (file)
@@ -1898,7 +1898,7 @@ free_buf_options(buf, free_p_ff)
 #ifdef FEAT_SPELL
     clear_string_option(&buf->b_s.b_p_spc);
     clear_string_option(&buf->b_s.b_p_spf);
-    vim_free(buf->b_s.b_cap_prog);
+    vim_regfree(buf->b_s.b_cap_prog);
     buf->b_s.b_cap_prog = NULL;
     clear_string_option(&buf->b_s.b_p_spl);
 #endif
@@ -2246,7 +2246,7 @@ buflist_findpat(pattern, pattern_end, unlisted, diffmode, curtab_only)
                        match = buf->b_fnum;    /* remember first match */
                    }
 
-               vim_free(prog);
+               vim_regfree(prog);
                if (match >= 0)                 /* found one match */
                    break;
            }
@@ -2355,14 +2355,14 @@ ExpandBufnames(pat, num_file, file, options)
                *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
                if (*file == NULL)
                {
-                   vim_free(prog);
+                   vim_regfree(prog);
                    if (patc != pat)
                        vim_free(patc);
                    return FAIL;
                }
            }
        }
-       vim_free(prog);
+       vim_regfree(prog);
        if (count)              /* match(es) found, break here */
            break;
     }
index c9a271d66cc020fdaeda1dc23cb0428206df511f..4eab20eb6b493f8fc0ec70813cd5a8ed1f0e028a 100644 (file)
@@ -3134,7 +3134,7 @@ ins_compl_dictionaries(dict_start, pat, flags, thesaurus)
 
 theend:
     p_scs = save_p_scs;
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
     vim_free(buf);
 }
 
index d0d154dc56cde4bc7bc173a4df84d38d4fed9fc7..da3d2bd7921b97fa7534c55c9836bc8b2c9aed0b 100644 (file)
@@ -4560,7 +4560,7 @@ eval4(arg, rettv, evaluate)
                            if (regmatch.regprog != NULL)
                            {
                                n1 = vim_regexec_nl(&regmatch, s1, (colnr_T)0);
-                               vim_free(regmatch.regprog);
+                               vim_regfree(regmatch.regprog);
                                if (type == TYPE_NOMATCH)
                                    n1 = !n1;
                            }
@@ -13981,7 +13981,7 @@ find_some_match(argvars, rettv, type)
                rettv->vval.v_number += (varnumber_T)(str - expr);
            }
        }
-       vim_free(regmatch.regprog);
+       vim_regfree(regmatch.regprog);
     }
 
 theend:
@@ -17214,7 +17214,7 @@ f_split(argvars, rettv)
            str = regmatch.endp[0];
        }
 
-       vim_free(regmatch.regprog);
+       vim_regfree(regmatch.regprog);
     }
 
     p_cpo = save_cpo;
@@ -21066,7 +21066,7 @@ ex_function(eap)
                            list_func_head(fp, FALSE);
                    }
                }
-               vim_free(regmatch.regprog);
+               vim_regfree(regmatch.regprog);
            }
        }
        if (*p == '/')
@@ -24220,7 +24220,7 @@ do_string_sub(str, pat, sub, flags)
        if (ga.ga_data != NULL)
            STRCPY((char *)ga.ga_data + ga.ga_len, tail);
 
-       vim_free(regmatch.regprog);
+       vim_regfree(regmatch.regprog);
     }
 
     ret = vim_strsave(ga.ga_data == NULL ? str : (char_u *)ga.ga_data);
index cd6772ed521225c06f676abd3339dd45939d738b..a61bcdd39eeaa60eb2d826cd38d08ca17eb65e58 100644 (file)
@@ -571,7 +571,7 @@ sortend:
     vim_free(nrs);
     vim_free(sortbuf1);
     vim_free(sortbuf2);
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
     if (got_int)
        EMSG(_(e_interr));
 }
@@ -5261,7 +5261,7 @@ outofmem:
        changed_window_setting();
 #endif
 
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
 }
 
 /*
@@ -5436,7 +5436,7 @@ ex_global(eap)
        global_exe(cmd);
 
     ml_clearmarked();     /* clear rest of the marks */
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
 }
 
 /*
index 40ad9a67f909f8c58a71fc5a195f3bf96e7bea30..66b7e4e167e73331dc9790d2f4482d38baf9ba7d 100644 (file)
@@ -652,7 +652,7 @@ ex_breakdel(eap)
        while (gap->ga_len > 0)
        {
            vim_free(DEBUGGY(gap, todel).dbg_name);
-           vim_free(DEBUGGY(gap, todel).dbg_prog);
+           vim_regfree(DEBUGGY(gap, todel).dbg_prog);
            --gap->ga_len;
            if (todel < gap->ga_len)
                mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
@@ -1985,7 +1985,7 @@ do_arglist(str, what, after)
                    --match;
                }
 
-           vim_free(regmatch.regprog);
+           vim_regfree(regmatch.regprog);
            vim_free(p);
            if (!didone)
                EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
index a8b0fb320a1fb725d350f3e305e6ebb8b60ad791..3efb3814b583952688346e05b91b9ee6c20695f7 100644 (file)
@@ -7779,7 +7779,7 @@ ex_open(eap)
                curwin->w_cursor.col = (colnr_T)(regmatch.startp[0] - p);
            else
                EMSG(_(e_nomatch));
-           vim_free(regmatch.regprog);
+           vim_regfree(regmatch.regprog);
        }
        /* Move to the NUL, ignore any other arguments. */
        eap->arg += STRLEN(eap->arg);
index 5b849696e09cba8569cd3a93e23fe4c9956fc51c..1ad696f4973932f92fd2a1a9cec5a3026c3e0c21 100644 (file)
@@ -1576,7 +1576,7 @@ ex_catch(eap)
                    caught = vim_regexec_nl(&regmatch, current_exception->value,
                            (colnr_T)0);
                    got_int |= prev_got_int;
-                   vim_free(regmatch.regprog);
+                   vim_regfree(regmatch.regprog);
                }
            }
        }
index 6fe91488c254b58488caacdc8ef8a9daef4a85ae..4bebe2309a34d588fb7ef68cf6d8f2a5082e736a 100644 (file)
@@ -4717,7 +4717,7 @@ ExpandFromContext(xp, pat, num_file, file, options)
            }
     }
 
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
 
     return ret;
 #endif /* FEAT_CMDL_COMPL */
@@ -5785,7 +5785,7 @@ del_history_entry(histype, str)
        if (history[histype][idx].hisstr == NULL)
            hisidx[histype] = -1;
     }
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
     return found;
 }
 
index b93ae1b41c71cfd00485a25abcbff59735efc267..f1db98364c5d5245ba8c585ef07a8eea2099e225 100644 (file)
@@ -7921,7 +7921,7 @@ au_cleanup()
            if (ap->pat == NULL)
            {
                *prev_ap = ap->next;
-               vim_free(ap->reg_prog);
+               vim_regfree(ap->reg_prog);
                vim_free(ap);
            }
            else
@@ -10070,7 +10070,7 @@ match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
        result = TRUE;
 
     if (prog == NULL)
-       vim_free(regmatch.regprog);
+       vim_regfree(regmatch.regprog);
     return result;
 }
 #endif
index 0c21976f7cdc3a1d9732e2d882e28bb758bf24b3..0bb0422cc7862e04539e59aaf35bd8c916fe9680 100644 (file)
--- a/src/gui.c
+++ b/src/gui.c
@@ -5319,7 +5319,7 @@ gui_do_findrepl(flags, find_text, repl_text, down)
            }
            else
                MSG(_("No match at cursor, finding next"));
-           vim_free(regmatch.regprog);
+           vim_regfree(regmatch.regprog);
        }
     }
 
index 9e3ba44b4e26899f5350f6f7e9e4a19967d2d005..1737cfa54815597cf2e9029204584b5f49c55d91 100644 (file)
 
 # define MB_COPY_CHAR(f, t) if (has_mbyte) mb_copy_char(&f, &t); else *t++ = *f++
 # define MB_CHARLEN(p)     (has_mbyte ? mb_charlen(p) : (int)STRLEN(p))
+# define MB_CHAR2LEN(c)            (has_mbyte ? mb_char2len(c) : 1)
 # define PTR2CHAR(p)       (has_mbyte ? mb_ptr2char(p) : (int)*(p))
 #else
 # define MB_PTR2LEN(p)         1
 # define mb_ptr_back(s, p)     --p
 # define MB_COPY_CHAR(f, t)    *t++ = *f++
 # define MB_CHARLEN(p)         STRLEN(p)
+# define MB_CHAR2LEN(c)                1
 # define PTR2CHAR(p)           ((int)*(p))
 #endif
 
index 5d035328ee59d844aee028458492d3e4482b5eb9..eb685cdc887b472aee917be3a46fc05b3016d2e9 100644 (file)
@@ -456,8 +456,8 @@ get_number_indent(lnum)
            pos.coladd = 0;
 #endif
        }
+       vim_regfree(regmatch.regprog);
     }
-    vim_free(regmatch.regprog);
 
     if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL)
        return -1;
@@ -9751,7 +9751,7 @@ dos_expandpath(
 # endif
 #endif
     vim_free(buf);
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
     vim_free(matchname);
 
     matches = gap->ga_len - start_len;
@@ -9993,7 +9993,7 @@ unix_expandpath(gap, path, wildoff, flags, didstar)
     }
 
     vim_free(buf);
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
 
     matches = gap->ga_len - start_len;
     if (matches > 0)
@@ -10358,7 +10358,7 @@ theend:
        vim_free(in_curdir);
     }
     ga_clear_strings(&path_ga);
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
 
     if (sort_again)
        remove_duplicates(gap);
index 4d350c4fa4c3dbd35320cd495de4da08fa569e5e..196641fade262118fec82736fecb3e155092fc29 100644 (file)
@@ -1134,7 +1134,7 @@ free_all_mem()
     /* Free some global vars. */
     vim_free(username);
 # ifdef FEAT_CLIPBOARD
-    vim_free(clip_exclude_prog);
+    vim_regfree(clip_exclude_prog);
 # endif
     vim_free(last_cmdline);
 # ifdef FEAT_CMDHIST
@@ -5008,8 +5008,8 @@ vim_findfile(search_ctx_arg)
 #endif
                {
                    /*
-                    * we don't have further wildcards to expand, so we have to
-                    * check for the final file now
+                    * We don't have further wildcards to expand, so we have to
+                    * check for the final file now.
                     */
                    for (i = stackp->ffs_filearray_cur;
                                          i < stackp->ffs_filearray_size; ++i)
index fa28e840ac2d0ec482b2d41b1cc42a7b5313087a..c18672e4f432ae2b3e8918f17d0d821f76a6849c 100644 (file)
@@ -7491,7 +7491,7 @@ check_clipboard_option()
        clip_autoselect_plus = new_autoselect_plus;
        clip_autoselectml = new_autoselectml;
        clip_html = new_html;
-       vim_free(clip_exclude_prog);
+       vim_regfree(clip_exclude_prog);
        clip_exclude_prog = new_exclude_prog;
 #ifdef FEAT_GUI_GTK
        if (gui.in_use)
@@ -7502,7 +7502,7 @@ check_clipboard_option()
 #endif
     }
     else
-       vim_free(new_exclude_prog);
+       vim_regfree(new_exclude_prog);
 
     return errmsg;
 }
@@ -7529,16 +7529,16 @@ compile_cap_prog(synblock)
        if (re != NULL)
        {
            synblock->b_cap_prog = vim_regcomp(re, RE_MAGIC);
+           vim_free(re);
            if (synblock->b_cap_prog == NULL)
            {
                synblock->b_cap_prog = rp; /* restore the previous program */
                return e_invarg;
            }
-           vim_free(re);
        }
     }
 
-    vim_free(rp);
+    vim_regfree(rp);
     return NULL;
 }
 #endif
index 5cd1731c331f85249a865a6b64c1fb898a220c03..38c9c33c4e932966088b47e0a525cc2972b29133 100644 (file)
@@ -2,16 +2,17 @@
 int re_multiline __ARGS((regprog_T *prog));
 int re_lookbehind __ARGS((regprog_T *prog));
 char_u *skip_regexp __ARGS((char_u *startp, int dirc, int magic, char_u **newp));
-regprog_T *vim_regcomp __ARGS((char_u *expr, int re_flags));
 int vim_regcomp_had_eol __ARGS((void));
 void free_regexp_stuff __ARGS((void));
-int vim_regexec __ARGS((regmatch_T *rmp, char_u *line, colnr_T col));
-int vim_regexec_nl __ARGS((regmatch_T *rmp, char_u *line, colnr_T col));
-long vim_regexec_multi __ARGS((regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm));
 reg_extmatch_T *ref_extmatch __ARGS((reg_extmatch_T *em));
 void unref_extmatch __ARGS((reg_extmatch_T *em));
 char_u *regtilde __ARGS((char_u *source, int magic));
 int vim_regsub __ARGS((regmatch_T *rmp, char_u *source, char_u *dest, int copy, int magic, int backslash));
 int vim_regsub_multi __ARGS((regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *dest, int copy, int magic, int backslash));
 char_u *reg_submatch __ARGS((int no));
+regprog_T *vim_regcomp __ARGS((char_u *expr_arg, int re_flags));
+void vim_regfree __ARGS((regprog_T *prog));
+int vim_regexec __ARGS((regmatch_T *rmp, char_u *line, colnr_T col));
+int vim_regexec_nl __ARGS((regmatch_T *rmp, char_u *line, colnr_T col));
+long vim_regexec_multi __ARGS((regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm));
 /* vim: set ft=c : */
index a8fc010139f0a5ea990f7fa57028b8d81dedfe2b..3ac534dc14df9ba7d562ab679b68242e6f65889d 100644 (file)
@@ -863,7 +863,7 @@ qf_init_ok:
     for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first)
     {
        fmt_first = fmt_ptr->next;
-       vim_free(fmt_ptr->prog);
+       vim_regfree(fmt_ptr->prog);
        vim_free(fmt_ptr);
     }
     qf_clean_dir_stack(&dir_stack);
@@ -3487,7 +3487,7 @@ theend:
     vim_free(dirname_now);
     vim_free(dirname_start);
     vim_free(target_dir);
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
 }
 
 /*
@@ -4178,7 +4178,7 @@ ex_helpgrep(eap)
            }
        }
 
-       vim_free(regmatch.regprog);
+       vim_regfree(regmatch.regprog);
 #ifdef FEAT_MBYTE
        if (vc.vc_type != CONV_NONE)
            convert_setup(&vc, NULL, NULL);
index ae29ef53b9192f513f590591b50329b520432704..ef8c78db68d02861f96de6dd4a781e4d5a59e3bd 100644 (file)
@@ -1297,7 +1297,8 @@ skip_regexp(startp, dirc, magic, newp)
     return p;
 }
 
-static regprog_T    *bt_regcomp __ARGS((char_u *expr, int re_flags));
+static regprog_T  *bt_regcomp __ARGS((char_u *expr, int re_flags));
+static void bt_regfree __ARGS((regprog_T *prog));
 
 /*
  * bt_regcomp() - compile a regular expression into internal code for the
@@ -1454,6 +1455,16 @@ bt_regcomp(expr, re_flags)
     return (regprog_T *)r;
 }
 
+/*
+ * Free a compiled regexp program, returned by bt_regcomp().
+ */
+    static void
+bt_regfree(prog)
+    regprog_T   *prog;
+{
+    vim_free(prog);
+}
+
 /*
  * Setup to parse the regexp.  Used once to get the length and once to do it.
  */
@@ -7876,6 +7887,7 @@ reg_submatch(no)
 static regengine_T bt_regengine =
 {
     bt_regcomp,
+    bt_regfree,
     bt_regexec,
 #if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \
        || defined(FIND_REPLACE_DIALOG) || defined(PROTO)
@@ -7893,6 +7905,7 @@ static regengine_T bt_regengine =
 static regengine_T nfa_regengine =
 {
     nfa_regcomp,
+    nfa_regfree,
     nfa_regexec,
 #if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \
        || defined(FIND_REPLACE_DIALOG) || defined(PROTO)
@@ -7920,7 +7933,9 @@ static char_u regname[][30] = {
 
 /*
  * Compile a regular expression into internal code.
- * Returns the program in allocated memory.  Returns NULL for an error.
+ * Returns the program in allocated memory.
+ * Use vim_regfree() to free the memory.
+ * Returns NULL for an error.
  */
     regprog_T *
 vim_regcomp(expr_arg, re_flags)
@@ -7996,6 +8011,17 @@ vim_regcomp(expr_arg, re_flags)
     return prog;
 }
 
+/*
+ * Free a compiled regexp program, returned by vim_regcomp().
+ */
+    void
+vim_regfree(prog)
+    regprog_T   *prog;
+{
+    if (prog != NULL)
+       prog->engine->regfree(prog);
+}
+
 /*
  * Match a regexp against a string.
  * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
index 184228213d58d953d8066377c419501ad16f7dba..976927e04acd5aecbe2bca9c3adc4323ff4ecc4f 100644 (file)
@@ -89,6 +89,7 @@ typedef struct
 
     int                        reganch;        /* pattern starts with ^ */
     int                        regstart;       /* char at start of pattern */
+    char_u             *match_text;    /* plain text to match with */
 
     int                        has_zend;       /* pattern contains \ze */
     int                        has_backref;    /* pattern contains \1 .. \9 */
@@ -147,6 +148,7 @@ typedef struct
 struct regengine
 {
     regprog_T  *(*regcomp)(char_u*, int);
+    void       (*regfree)(regprog_T *);
     int                (*regexec)(regmatch_T*, char_u*, colnr_T);
 #if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \
        || defined(FIND_REPLACE_DIALOG) || defined(PROTO)
index b03d09aeb7e1b6d91e1c237b5957e4a5c2673a77..f0e7744322308e72151f6155353c950106c867ef 100644 (file)
@@ -270,6 +270,7 @@ static int nfa_ll_index = 0;
 static int nfa_regcomp_start __ARGS((char_u *expr, int re_flags));
 static int nfa_get_reganch __ARGS((nfa_state_T *start, int depth));
 static int nfa_get_regstart __ARGS((nfa_state_T *start, int depth));
+static char_u *nfa_get_match_text __ARGS((nfa_state_T *start));
 static int nfa_recognize_char_class __ARGS((char_u *start, char_u *end, int extra_newl));
 static int nfa_emit_equi_class __ARGS((int c));
 static int nfa_regatom __ARGS((void));
@@ -295,6 +296,7 @@ static int nfa_re_num_cmp __ARGS((long_u val, int op, long_u pos));
 static long nfa_regtry __ARGS((nfa_regprog_T *prog, colnr_T col));
 static long nfa_regexec_both __ARGS((char_u *line, colnr_T col));
 static regprog_T *nfa_regcomp __ARGS((char_u *expr, int re_flags));
+static void nfa_regfree __ARGS((regprog_T *prog));
 static int nfa_regexec __ARGS((regmatch_T *rmp, char_u *line, colnr_T col));
 static long nfa_regexec_multi __ARGS((regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm));
 
@@ -492,6 +494,52 @@ nfa_get_regstart(start, depth)
     return 0;
 }
 
+/*
+ * Figure out if the NFA state list contains just literal text and nothing
+ * else.  If so return a string with what must match after regstart.
+ * Otherwise return NULL.
+ */
+    static char_u *
+nfa_get_match_text(start)
+    nfa_state_T *start;
+{
+    nfa_state_T *p = start;
+    int                len = 0;
+    char_u     *ret;
+    char_u     *s;
+
+    if (p->c != NFA_MOPEN)
+       return NULL; /* just in case */
+    p = p->out;
+    while (p->c > 0)
+    {
+       len += MB_CHAR2LEN(p->c);
+       p = p->out;
+    }
+    if (p->c != NFA_MCLOSE || p->out->c != NFA_MATCH)
+       return NULL;
+
+    ret = alloc(len);
+    if (ret != NULL)
+    {
+       len = 0;
+       p = start->out->out; /* skip first char, it goes into regstart */
+       s = ret;
+       while (p->c > 0)
+       {
+#ifdef FEAT_MBYTE
+           if (has_mbyte)
+               s += (*mb_char2bytes)(p->c, s);
+           else
+#endif
+               *s++ = p->c;
+           p = p->out;
+       }
+       *s = NUL;
+    }
+    return ret;
+}
+
 /*
  * Allocate more space for post_start.  Called when
  * running above the estimated number of states.
@@ -2280,8 +2328,13 @@ nfa_dump(prog)
     {
        nfa_print_state(debugf, prog->start);
 
-       fprintf(debugf, "reganch: %d\n", prog->reganch);
-       fprintf(debugf, "regstart: %d\n", prog->regstart);
+       if (prog->reganch)
+           fprintf(debugf, "reganch: %d\n", prog->reganch);
+       if (prog->regstart != NUL)
+           fprintf(debugf, "regstart: %c (decimal: %d)\n",
+                                             prog->regstart, prog->regstart);
+       if (prog->match_text != NULL)
+           fprintf(debugf, "match_text: \"%s\"\n", prog->match_text);
 
        fclose(debugf);
     }
@@ -4154,6 +4207,7 @@ recursive_regmatch(state, prog, submatch, m, listids)
 
 static int failure_chance __ARGS((nfa_state_T *state, int depth));
 static int skip_to_start __ARGS((int c, colnr_T *colp));
+static long find_match_text __ARGS((colnr_T startcol, int regstart, char_u *match_text));
 
 /*
  * Estimate the chance of a match with "state" failing.
@@ -4330,6 +4384,69 @@ skip_to_start(c, colp)
     return OK;
 }
 
+/*
+ * Check for a match with match_text.
+ * Called after skip_to_start() has find regstart.
+ * Returns zero for no match, 1 for a match.
+ */
+    static long
+find_match_text(startcol, regstart, match_text)
+    colnr_T startcol;
+    int            regstart;
+    char_u  *match_text;
+{
+    colnr_T col = startcol;
+    int            c1, c2;
+    int            len1, len2;
+    int            match;
+
+    for (;;)
+    {
+       match = TRUE;
+       len2 = MB_CHAR2LEN(regstart); /* skip regstart */
+       for (len1 = 0; match_text[len1] != NUL; len1 += MB_CHAR2LEN(c1))
+       {
+           c1 = PTR2CHAR(match_text + len1);
+           c2 = PTR2CHAR(regline + col + len2);
+           if (c1 != c2 && (!ireg_ic || MB_TOLOWER(c1) != MB_TOLOWER(c2)))
+           {
+               match = FALSE;
+               break;
+           }
+           len2 += MB_CHAR2LEN(c2);
+       }
+       if (match
+#ifdef FEAT_MBYTE
+               /* check that no composing char follows */
+               && !(enc_utf8
+                          && utf_iscomposing(PTR2CHAR(regline + col + len2)))
+#endif
+               )
+       {
+           cleanup_subexpr();
+           if (REG_MULTI)
+           {
+               reg_startpos[0].lnum = reglnum;
+               reg_startpos[0].col = col;
+               reg_endpos[0].lnum = reglnum;
+               reg_endpos[0].col = col + len2;
+           }
+           else
+           {
+               reg_startp[0] = regline + col;
+               reg_endp[0] = regline + col + len2;
+           }
+           return 1L;
+       }
+
+       /* Try finding regstart after the current match. */
+       col += MB_CHAR2LEN(regstart); /* skip regstart */
+       if (skip_to_start(regstart, &col) == FAIL)
+           break;
+    }
+    return 0L;
+}
+
 /*
  * Main matching routine.
  *
@@ -5584,17 +5701,6 @@ nfa_regtry(prog, col)
 #endif
 
     reginput = regline + col;
-    need_clear_subexpr = TRUE;
-#ifdef FEAT_SYN_HL
-    /* Clear the external match subpointers if necessary. */
-    if (prog->reghasz == REX_SET)
-    {
-       nfa_has_zsubexpr = TRUE;
-       need_clear_zsubexpr = TRUE;
-    }
-    else
-       nfa_has_zsubexpr = FALSE;
-#endif
 
 #ifdef ENABLE_LOG
     f = fopen(NFA_REGEXP_RUN_LOG, "a");
@@ -5764,12 +5870,31 @@ nfa_regexec_both(line, startcol)
     if (prog->reganch && col > 0)
        return 0L;
 
+    need_clear_subexpr = TRUE;
+#ifdef FEAT_SYN_HL
+    /* Clear the external match subpointers if necessary. */
+    if (prog->reghasz == REX_SET)
+    {
+       nfa_has_zsubexpr = TRUE;
+       need_clear_zsubexpr = TRUE;
+    }
+    else
+       nfa_has_zsubexpr = FALSE;
+#endif
+
     if (prog->regstart != NUL)
+    {
        /* Skip ahead until a character we know the match must start with.
         * When there is none there is no match. */
        if (skip_to_start(prog->regstart, &col) == FAIL)
            return 0L;
 
+       /* If match_text is set it contains the full text that must match.
+        * Nothing else to try. Doesn't handle combining chars well. */
+       if (prog->match_text != NULL && !ireg_icombine)
+           return find_match_text(col, prog->regstart, prog->match_text);
+    }
+
     /* If the start column is past the maximum column: no need to try. */
     if (ireg_maxcol > 0 && col >= ireg_maxcol)
        goto theend;
@@ -5876,6 +6001,8 @@ nfa_regcomp(expr, re_flags)
     prog->reganch = nfa_get_reganch(prog->start, 0);
     prog->regstart = nfa_get_regstart(prog->start, 0);
 
+    prog->match_text = nfa_get_match_text(prog->start);
+
 #ifdef ENABLE_LOG
     nfa_postfix_dump(expr, OK);
     nfa_dump(prog);
@@ -5885,7 +6012,7 @@ nfa_regcomp(expr, re_flags)
     prog->reghasz = re_has_z;
 #endif
 #ifdef DEBUG
-    prog->pattern = vim_strsave(expr); /* memory will leak */
+    prog->pattern = vim_strsave(expr);
     nfa_regengine.expr = NULL;
 #endif
 
@@ -5907,6 +6034,22 @@ fail:
     goto out;
 }
 
+/*
+ * Free a compiled regexp program, returned by nfa_regcomp().
+ */
+    static void
+nfa_regfree(prog)
+    regprog_T   *prog;
+{
+    if (prog != NULL)
+    {
+       vim_free(((nfa_regprog_T *)prog)->match_text);
+#ifdef DEBUG
+       vim_free(((nfa_regprog_T *)prog)->pattern);
+#endif
+       vim_free(prog);
+    }
+}
 
 /*
  * Match a regexp against a string.
index 86d43cb1b290176213e24e063ecc2e44931a5d44..ca13709971d12f6ede522359c0839d5c58e273c6 100644 (file)
@@ -7082,7 +7082,7 @@ end_search_hl()
 {
     if (search_hl.rm.regprog != NULL)
     {
-       vim_free(search_hl.rm.regprog);
+       vim_regfree(search_hl.rm.regprog);
        search_hl.rm.regprog = NULL;
     }
 }
@@ -7284,7 +7284,7 @@ next_search_hl(win, shl, lnum, mincol)
            if (shl == &search_hl)
            {
                /* don't free regprog in the match list, it's a copy */
-               vim_free(shl->rm.regprog);
+               vim_regfree(shl->rm.regprog);
                no_hlsearch = TRUE;
            }
            shl->rm.regprog = NULL;
index 0e4f4246f199878c611b436a4ba9ef90ece2a6fa..40928c8a03ce3298192ec000de088b6379216968 100644 (file)
@@ -972,7 +972,7 @@ searchit(win, buf, pos, dir, pat, count, options, pat_use, stop_lnum, tm)
     }
     while (--count > 0 && found);   /* stop after count matches or no match */
 
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
 
     called_emsg |= save_called_emsg;
 
@@ -4680,7 +4680,7 @@ is_zerowidth(pattern)
     }
 
     called_emsg |= save_called_emsg;
-    vim_free(regmatch.regprog);
+    vim_regfree(regmatch.regprog);
     return result;
 }
 #endif /* FEAT_VISUAL */
@@ -5402,9 +5402,9 @@ exit_matched:
 
 fpip_end:
     vim_free(file_line);
-    vim_free(regmatch.regprog);
-    vim_free(incl_regmatch.regprog);
-    vim_free(def_regmatch.regprog);
+    vim_regfree(regmatch.regprog);
+    vim_regfree(incl_regmatch.regprog);
+    vim_regfree(def_regmatch.regprog);
 }
 
     static void
index 29356bf9e98d37dd87861b33f91025144ce63b80..e558a99e4a2cd481664af2ae5d7c0f1ac347dcac 100644 (file)
@@ -2658,7 +2658,7 @@ slang_clear(lp)
     ga_clear(gap);
 
     for (i = 0; i < lp->sl_prefixcnt; ++i)
-       vim_free(lp->sl_prefprog[i]);
+       vim_regfree(lp->sl_prefprog[i]);
     lp->sl_prefixcnt = 0;
     vim_free(lp->sl_prefprog);
     lp->sl_prefprog = NULL;
@@ -2669,7 +2669,7 @@ slang_clear(lp)
     vim_free(lp->sl_midword);
     lp->sl_midword = NULL;
 
-    vim_free(lp->sl_compprog);
+    vim_regfree(lp->sl_compprog);
     vim_free(lp->sl_comprules);
     vim_free(lp->sl_compstartflags);
     vim_free(lp->sl_compallflags);
@@ -5802,7 +5802,7 @@ spell_read_aff(spin, fname)
                                        {
                                            sprintf((char *)buf, "^%s",
                                                          aff_entry->ae_cond);
-                                           vim_free(aff_entry->ae_prog);
+                                           vim_regfree(aff_entry->ae_prog);
                                            aff_entry->ae_prog = vim_regcomp(
                                                    buf, RE_MAGIC + RE_STRING);
                                        }
@@ -6507,7 +6507,7 @@ spell_free_aff(aff)
                --todo;
                ah = HI2AH(hi);
                for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next)
-                   vim_free(ae->ae_prog);
+                   vim_regfree(ae->ae_prog);
            }
        }
        if (ht == &aff->af_suff)
index 323889ef8c265dfdb460898c8a3a4c78d06f15f0..a8de63a6e103810d1af7b48f96247c90329abc9d 100644 (file)
@@ -3495,7 +3495,7 @@ syntax_clear(block)
     block->b_syn_sync_maxlines = 0;
     block->b_syn_sync_linebreaks = 0;
 
-    vim_free(block->b_syn_linecont_prog);
+    vim_regfree(block->b_syn_linecont_prog);
     block->b_syn_linecont_prog = NULL;
     vim_free(block->b_syn_linecont_pat);
     block->b_syn_linecont_pat = NULL;
@@ -3544,7 +3544,7 @@ syntax_sync_clear()
     curwin->w_s->b_syn_sync_maxlines = 0;
     curwin->w_s->b_syn_sync_linebreaks = 0;
 
-    vim_free(curwin->w_s->b_syn_linecont_prog);
+    vim_regfree(curwin->w_s->b_syn_linecont_prog);
     curwin->w_s->b_syn_linecont_prog = NULL;
     vim_free(curwin->w_s->b_syn_linecont_pat);
     curwin->w_s->b_syn_linecont_pat = NULL;
@@ -3583,7 +3583,7 @@ syn_clear_pattern(block, i)
     int                i;
 {
     vim_free(SYN_ITEMS(block)[i].sp_pattern);
-    vim_free(SYN_ITEMS(block)[i].sp_prog);
+    vim_regfree(SYN_ITEMS(block)[i].sp_prog);
     /* Only free sp_cont_list and sp_next_list of first start pattern */
     if (i == 0 || SYN_ITEMS(block)[i - 1].sp_type != SPTYPE_START)
     {
@@ -4991,7 +4991,7 @@ syn_cmd_match(eap, syncing)
     /*
      * Something failed, free the allocated memory.
      */
-    vim_free(item.sp_prog);
+    vim_regfree(item.sp_prog);
     vim_free(item.sp_pattern);
     vim_free(syn_opt_arg.cont_list);
     vim_free(syn_opt_arg.cont_in_list);
@@ -5248,7 +5248,7 @@ syn_cmd_region(eap, syncing)
        {
            if (!success)
            {
-               vim_free(ppp->pp_synp->sp_prog);
+               vim_regfree(ppp->pp_synp->sp_prog);
                vim_free(ppp->pp_synp->sp_pattern);
            }
            vim_free(ppp->pp_synp);
@@ -6022,7 +6022,7 @@ get_id_list(arg, keylen, list)
                            id = -1;        /* remember that we found one */
                        }
                    }
-                   vim_free(regmatch.regprog);
+                   vim_regfree(regmatch.regprog);
                }
            }
            vim_free(name);
@@ -6295,7 +6295,7 @@ ex_ownsyntax(eap)
        curwin->w_p_spell = FALSE;      /* No spell checking */
        clear_string_option(&curwin->w_s->b_p_spc);
        clear_string_option(&curwin->w_s->b_p_spf);
-       vim_free(curwin->w_s->b_cap_prog);
+       vim_regfree(curwin->w_s->b_cap_prog);
        curwin->w_s->b_cap_prog = NULL;
        clear_string_option(&curwin->w_s->b_p_spl);
 #endif
index 34e9c4ff2728c4e8ddbe4734b18032e57cd9d6fe..248280c7c9ac5e80cd48bac4fd7899091274ef4e 100644 (file)
--- a/src/tag.c
+++ b/src/tag.c
@@ -2491,7 +2491,7 @@ line_read_in:
 
 findtag_end:
     vim_free(lbuf);
-    vim_free(orgpat.regmatch.regprog);
+    vim_regfree(orgpat.regmatch.regprog);
     vim_free(tag_fname);
 #ifdef FEAT_EMACS_TAGS
     vim_free(ebuf);
index 0ba833fed4bbe681a3ba133d6fdf44e666ea44f8..42703c2e2ecde8efbece782f2796d0f67fcc68b6 100644 (file)
@@ -260,6 +260,8 @@ STARTTEST
 :call add(tl, [2, '[^[:alpha:]]\+','abcccadfoij7787ysf287yrnccdu','7787'])
 :call add(tl, [2, '[-a]', '-', '-'])
 :call add(tl, [2, '[a-]', '-', '-'])
+:call add(tl, [2, '[a-f]*\c','ABCDEFGH','ABCDEF'])
+:call add(tl, [2, '[abc][xyz]\c','-af-AF-BY--','BY'])
 :" filename regexp
 :call add(tl, [2, '[-./[:alnum:]_~]\+', 'log13.file', 'log13.file'])
 :" special chars
@@ -385,6 +387,12 @@ STARTTEST
 :call add(tl, [2, '\(<<\)\@2<=span.', 'xxspanxxxx<spanxx<<spanyyy', 'spany', '<<'])
 :call add(tl, [2, '\(foo\)\@<!bar.', 'xx foobar1 xbar2 xx', 'bar2'])
 :"
+:" look-behind match in front of a zero-width item
+:call add(tl, [2, '\v\C%(<Last Changed:\s+)@<=.*$', '" test header'])
+:call add(tl, [2, '\v\C%(<Last Changed:\s+)@<=.*$', '" Last Changed: 1970', '1970'])
+:call add(tl, [2, '\(foo\)\@<=\>', 'foobar'])
+:call add(tl, [2, '\(foo\)\@<=\>', 'barfoo', '', 'foo'])
+:"
 :""""" \@>
 :call add(tl, [2, '\(a*\)\@>a', 'aaaa'])
 :call add(tl, [2, '\(a*\)\@>b', 'aaab', 'aaab', 'aaa'])
index 49a570ae250fc8183798e1518136b48dd875e5f0..0e25737dd050568968fbe688d012aa6ea27c0d55 100644 (file)
@@ -584,6 +584,12 @@ OK 2 - [-a]
 OK 0 - [a-]
 OK 1 - [a-]
 OK 2 - [a-]
+OK 0 - [a-f]*\c
+OK 1 - [a-f]*\c
+OK 2 - [a-f]*\c
+OK 0 - [abc][xyz]\c
+OK 1 - [abc][xyz]\c
+OK 2 - [abc][xyz]\c
 OK 0 - [-./[:alnum:]_~]\+
 OK 1 - [-./[:alnum:]_~]\+
 OK 2 - [-./[:alnum:]_~]\+
@@ -872,6 +878,18 @@ OK 2 - \(<<\)\@2<=span.
 OK 0 - \(foo\)\@<!bar.
 OK 1 - \(foo\)\@<!bar.
 OK 2 - \(foo\)\@<!bar.
+OK 0 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 1 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 2 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 0 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 1 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 2 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 0 - \(foo\)\@<=\>
+OK 1 - \(foo\)\@<=\>
+OK 2 - \(foo\)\@<=\>
+OK 0 - \(foo\)\@<=\>
+OK 1 - \(foo\)\@<=\>
+OK 2 - \(foo\)\@<=\>
 OK 0 - \(a*\)\@>a
 OK 1 - \(a*\)\@>a
 OK 2 - \(a*\)\@>a
index 5ed91706491597b316e6963d67098a54b1daede1..c92b22275487510ae4050cc4a47fe78ceedd3f6e 100644 (file)
@@ -728,6 +728,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1149,
 /**/
     1148,
 /**/
index 41e77068fc00b00b8d691c71177e4e3be3d44bfc..881be8bbeb2b0f3e470497734fbf9f3d27e54f99 100644 (file)
@@ -6818,7 +6818,7 @@ match_delete(wp, id, perr)
        wp->w_match_head = cur->next;
     else
        prev->next = cur->next;
-    vim_free(cur->match.regprog);
+    vim_regfree(cur->match.regprog);
     vim_free(cur->pattern);
     vim_free(cur);
     redraw_later(SOME_VALID);
@@ -6837,7 +6837,7 @@ clear_matches(wp)
     while (wp->w_match_head != NULL)
     {
        m = wp->w_match_head->next;
-       vim_free(wp->w_match_head->match.regprog);
+       vim_regfree(wp->w_match_head->match.regprog);
        vim_free(wp->w_match_head->pattern);
        vim_free(wp->w_match_head);
        wp->w_match_head = m;