forked from aniani/vim
patch 9.1.0409: too many strlen() calls in the regexp engine
Problem: too many strlen() calls in the regexp engine Solution: refactor code to retrieve strlen differently, make use of bsearch() for getting the character class (John Marriott) closes: #14648 Signed-off-by: John Marriott <basilisk@internode.on.net> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
86f6e2c2ee
commit
82792db631
410
src/regexp.c
410
src/regexp.c
@@ -161,6 +161,7 @@ re_multi_type(int c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char_u *reg_prev_sub = NULL;
|
static char_u *reg_prev_sub = NULL;
|
||||||
|
static size_t reg_prev_sublen = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* REGEXP_INRANGE contains all characters which are always special in a []
|
* REGEXP_INRANGE contains all characters which are always special in a []
|
||||||
@@ -197,6 +198,30 @@ backslash_trans(int c)
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CLASS_ALNUM = 0,
|
||||||
|
CLASS_ALPHA,
|
||||||
|
CLASS_BLANK,
|
||||||
|
CLASS_CNTRL,
|
||||||
|
CLASS_DIGIT,
|
||||||
|
CLASS_GRAPH,
|
||||||
|
CLASS_LOWER,
|
||||||
|
CLASS_PRINT,
|
||||||
|
CLASS_PUNCT,
|
||||||
|
CLASS_SPACE,
|
||||||
|
CLASS_UPPER,
|
||||||
|
CLASS_XDIGIT,
|
||||||
|
CLASS_TAB,
|
||||||
|
CLASS_RETURN,
|
||||||
|
CLASS_BACKSPACE,
|
||||||
|
CLASS_ESCAPE,
|
||||||
|
CLASS_IDENT,
|
||||||
|
CLASS_KEYWORD,
|
||||||
|
CLASS_FNAME,
|
||||||
|
CLASS_NONE = 99
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for a character class name "[:name:]". "pp" points to the '['.
|
* Check for a character class name "[:name:]". "pp" points to the '['.
|
||||||
* Returns one of the CLASS_ items. CLASS_NONE means that no item was
|
* Returns one of the CLASS_ items. CLASS_NONE means that no item was
|
||||||
@@ -205,58 +230,56 @@ backslash_trans(int c)
|
|||||||
static int
|
static int
|
||||||
get_char_class(char_u **pp)
|
get_char_class(char_u **pp)
|
||||||
{
|
{
|
||||||
static const char *(class_names[]) =
|
// must be sorted by the 'value' field because it is used by bsearch()!
|
||||||
|
static keyvalue_T char_class_tab[] =
|
||||||
{
|
{
|
||||||
"alnum:]",
|
KEYVALUE_ENTRY(CLASS_ALNUM, "alnum:]"),
|
||||||
#define CLASS_ALNUM 0
|
KEYVALUE_ENTRY(CLASS_ALPHA, "alpha:]"),
|
||||||
"alpha:]",
|
KEYVALUE_ENTRY(CLASS_BACKSPACE, "backspace:]"),
|
||||||
#define CLASS_ALPHA 1
|
KEYVALUE_ENTRY(CLASS_BLANK, "blank:]"),
|
||||||
"blank:]",
|
KEYVALUE_ENTRY(CLASS_CNTRL, "cntrl:]"),
|
||||||
#define CLASS_BLANK 2
|
KEYVALUE_ENTRY(CLASS_DIGIT, "digit:]"),
|
||||||
"cntrl:]",
|
KEYVALUE_ENTRY(CLASS_ESCAPE, "escape:]"),
|
||||||
#define CLASS_CNTRL 3
|
KEYVALUE_ENTRY(CLASS_FNAME, "fname:]"),
|
||||||
"digit:]",
|
KEYVALUE_ENTRY(CLASS_GRAPH, "graph:]"),
|
||||||
#define CLASS_DIGIT 4
|
KEYVALUE_ENTRY(CLASS_IDENT, "ident:]"),
|
||||||
"graph:]",
|
KEYVALUE_ENTRY(CLASS_KEYWORD, "keyword:]"),
|
||||||
#define CLASS_GRAPH 5
|
KEYVALUE_ENTRY(CLASS_LOWER, "lower:]"),
|
||||||
"lower:]",
|
KEYVALUE_ENTRY(CLASS_PRINT, "print:]"),
|
||||||
#define CLASS_LOWER 6
|
KEYVALUE_ENTRY(CLASS_PUNCT, "punct:]"),
|
||||||
"print:]",
|
KEYVALUE_ENTRY(CLASS_RETURN, "return:]"),
|
||||||
#define CLASS_PRINT 7
|
KEYVALUE_ENTRY(CLASS_SPACE, "space:]"),
|
||||||
"punct:]",
|
KEYVALUE_ENTRY(CLASS_TAB, "tab:]"),
|
||||||
#define CLASS_PUNCT 8
|
KEYVALUE_ENTRY(CLASS_UPPER, "upper:]"),
|
||||||
"space:]",
|
KEYVALUE_ENTRY(CLASS_XDIGIT, "xdigit:]")
|
||||||
#define CLASS_SPACE 9
|
|
||||||
"upper:]",
|
|
||||||
#define CLASS_UPPER 10
|
|
||||||
"xdigit:]",
|
|
||||||
#define CLASS_XDIGIT 11
|
|
||||||
"tab:]",
|
|
||||||
#define CLASS_TAB 12
|
|
||||||
"return:]",
|
|
||||||
#define CLASS_RETURN 13
|
|
||||||
"backspace:]",
|
|
||||||
#define CLASS_BACKSPACE 14
|
|
||||||
"escape:]",
|
|
||||||
#define CLASS_ESCAPE 15
|
|
||||||
"ident:]",
|
|
||||||
#define CLASS_IDENT 16
|
|
||||||
"keyword:]",
|
|
||||||
#define CLASS_KEYWORD 17
|
|
||||||
"fname:]",
|
|
||||||
#define CLASS_FNAME 18
|
|
||||||
};
|
};
|
||||||
#define CLASS_NONE 99
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ((*pp)[1] == ':')
|
// check that the value of "pp" has a chance of matching
|
||||||
|
if ((*pp)[1] == ':' && ASCII_ISLOWER((*pp)[2])
|
||||||
|
&& ASCII_ISLOWER((*pp)[3]) && ASCII_ISLOWER((*pp)[4]))
|
||||||
{
|
{
|
||||||
for (i = 0; i < (int)ARRAY_LENGTH(class_names); ++i)
|
keyvalue_T target;
|
||||||
if (STRNCMP(*pp + 2, class_names[i], STRLEN(class_names[i])) == 0)
|
keyvalue_T *entry;
|
||||||
{
|
// this function can be called repeatedly with the same value for "pp"
|
||||||
*pp += STRLEN(class_names[i]) + 2;
|
// so we cache the last found entry.
|
||||||
return i;
|
static keyvalue_T *last_entry = NULL;
|
||||||
}
|
|
||||||
|
target.key = 0;
|
||||||
|
target.value = (char *)*pp + 2;
|
||||||
|
target.length = 0; // not used, see cmp_keyvalue_value_n()
|
||||||
|
|
||||||
|
if (last_entry != NULL && cmp_keyvalue_value_n(&target, last_entry) == 0)
|
||||||
|
entry = last_entry;
|
||||||
|
else
|
||||||
|
entry = (keyvalue_T *)bsearch(&target, &char_class_tab,
|
||||||
|
ARRAY_LENGTH(char_class_tab),
|
||||||
|
sizeof(char_class_tab[0]), cmp_keyvalue_value_n);
|
||||||
|
if (entry != NULL)
|
||||||
|
{
|
||||||
|
last_entry = entry;
|
||||||
|
*pp += entry->length + 2;
|
||||||
|
return entry->key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return CLASS_NONE;
|
return CLASS_NONE;
|
||||||
}
|
}
|
||||||
@@ -619,17 +642,20 @@ skip_regexp_ex(
|
|||||||
{
|
{
|
||||||
if (dirc == '?' && newp != NULL && p[1] == '?')
|
if (dirc == '?' && newp != NULL && p[1] == '?')
|
||||||
{
|
{
|
||||||
|
size_t startplen;
|
||||||
|
|
||||||
// change "\?" to "?", make a copy first.
|
// change "\?" to "?", make a copy first.
|
||||||
if (*newp == NULL)
|
if (*newp == NULL)
|
||||||
{
|
{
|
||||||
*newp = vim_strsave(startp);
|
startplen = STRLEN(startp);
|
||||||
|
*newp = vim_strnsave(startp, startplen);
|
||||||
if (*newp != NULL)
|
if (*newp != NULL)
|
||||||
p = *newp + (p - startp);
|
p = *newp + (p - startp);
|
||||||
}
|
}
|
||||||
if (dropped != NULL)
|
if (dropped != NULL)
|
||||||
++*dropped;
|
++*dropped;
|
||||||
if (*newp != NULL)
|
if (*newp != NULL)
|
||||||
STRMOVE(p, p + 1);
|
mch_memmove(p, p + 1, (startplen - ((p + 1) - *newp)) + 1);
|
||||||
else
|
else
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
@@ -1189,20 +1215,114 @@ reg_iswordc(int c)
|
|||||||
return vim_iswordc_buf(c, rex.reg_buf);
|
return vim_iswordc_buf(c, rex.reg_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
static int can_f_submatch = FALSE; // TRUE when submatch() can be used
|
||||||
|
|
||||||
|
// This struct is used for reg_submatch(). Needed for when the
|
||||||
|
// substitution string is an expression that contains a call to substitute()
|
||||||
|
// and submatch().
|
||||||
|
typedef struct {
|
||||||
|
regmatch_T *sm_match;
|
||||||
|
regmmatch_T *sm_mmatch;
|
||||||
|
linenr_T sm_firstlnum;
|
||||||
|
linenr_T sm_maxline;
|
||||||
|
int sm_line_lbr;
|
||||||
|
} regsubmatch_T;
|
||||||
|
|
||||||
|
static regsubmatch_T rsm; // can only be used when can_f_submatch is TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RGLF_LINE = 0x01,
|
||||||
|
RGLF_LENGTH = 0x02
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
,
|
||||||
|
RGLF_SUBMATCH = 0x04
|
||||||
|
#endif
|
||||||
|
} reg_getline_flags_T;
|
||||||
|
|
||||||
|
//
|
||||||
|
// common code for reg_getline(), reg_getline_len(), reg_getline_submatch() and
|
||||||
|
// reg_getline_submatch_len().
|
||||||
|
// the flags argument (which is a bitmask) controls what info is to be returned and whether
|
||||||
|
// or not submatch is in effect.
|
||||||
|
// note:
|
||||||
|
// submatch is available only if FEAT_EVAL is defined.
|
||||||
|
static void
|
||||||
|
reg_getline_common(linenr_T lnum, reg_getline_flags_T flags, char_u **line, colnr_T *length)
|
||||||
|
{
|
||||||
|
int get_line = flags & RGLF_LINE;
|
||||||
|
int get_length = flags & RGLF_LENGTH;
|
||||||
|
linenr_T firstlnum;
|
||||||
|
linenr_T maxline;
|
||||||
|
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
if (flags & RGLF_SUBMATCH)
|
||||||
|
{
|
||||||
|
firstlnum = rsm.sm_firstlnum + lnum;
|
||||||
|
maxline = rsm.sm_maxline;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
firstlnum = rex.reg_firstlnum + lnum;
|
||||||
|
maxline = rex.reg_maxline;
|
||||||
|
}
|
||||||
|
|
||||||
|
// when looking behind for a match/no-match lnum is negative. but we
|
||||||
|
// can't go before line 1.
|
||||||
|
if (firstlnum < 1)
|
||||||
|
{
|
||||||
|
if (get_line)
|
||||||
|
*line = NULL;
|
||||||
|
if (get_length)
|
||||||
|
*length = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lnum > maxline)
|
||||||
|
{
|
||||||
|
// must have matched the "\n" in the last line.
|
||||||
|
if (get_line)
|
||||||
|
*line = (char_u *)"";
|
||||||
|
if (get_length)
|
||||||
|
*length = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_line)
|
||||||
|
*line = ml_get_buf(rex.reg_buf, firstlnum, FALSE);
|
||||||
|
if (get_length)
|
||||||
|
*length = ml_get_buf_len(rex.reg_buf, firstlnum);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get pointer to the line "lnum", which is relative to "reg_firstlnum".
|
* Get pointer to the line "lnum", which is relative to "reg_firstlnum".
|
||||||
*/
|
*/
|
||||||
static char_u *
|
static char_u *
|
||||||
reg_getline(linenr_T lnum)
|
reg_getline(linenr_T lnum)
|
||||||
{
|
{
|
||||||
// when looking behind for a match/no-match lnum is negative. But we
|
char_u *line;
|
||||||
// can't go before line 1
|
|
||||||
if (rex.reg_firstlnum + lnum < 1)
|
reg_getline_common(lnum, RGLF_LINE, &line, NULL);
|
||||||
return NULL;
|
|
||||||
if (lnum > rex.reg_maxline)
|
return line;
|
||||||
// Must have matched the "\n" in the last line.
|
}
|
||||||
return (char_u *)"";
|
|
||||||
return ml_get_buf(rex.reg_buf, rex.reg_firstlnum + lnum, FALSE);
|
/*
|
||||||
|
* Get length of line "lnum", which is relative to "reg_firstlnum".
|
||||||
|
*/
|
||||||
|
static colnr_T
|
||||||
|
reg_getline_len(linenr_T lnum)
|
||||||
|
{
|
||||||
|
colnr_T length;
|
||||||
|
|
||||||
|
reg_getline_common(lnum, RGLF_LENGTH, NULL, &length);
|
||||||
|
|
||||||
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEAT_SYN_HL
|
#ifdef FEAT_SYN_HL
|
||||||
@@ -1484,7 +1604,7 @@ match_with_backref(
|
|||||||
if (clnum == end_lnum)
|
if (clnum == end_lnum)
|
||||||
len = end_col - ccol;
|
len = end_col - ccol;
|
||||||
else
|
else
|
||||||
len = (int)STRLEN(p + ccol);
|
len = (int)reg_getline_len(clnum) - ccol;
|
||||||
|
|
||||||
if (cstrncmp(p + ccol, rex.input, &len) != 0)
|
if (cstrncmp(p + ccol, rex.input, &len) != 0)
|
||||||
return RA_NOMATCH; // doesn't match
|
return RA_NOMATCH; // doesn't match
|
||||||
@@ -1745,49 +1865,71 @@ regtilde(char_u *source, int magic)
|
|||||||
{
|
{
|
||||||
char_u *newsub = source;
|
char_u *newsub = source;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
size_t newsublen = 0;
|
||||||
|
char_u tilde[3] = {'~', NUL, NUL};
|
||||||
|
size_t tildelen = 1;
|
||||||
|
int error = FALSE;
|
||||||
|
|
||||||
|
if (!magic)
|
||||||
|
{
|
||||||
|
tilde[0] = '\\';
|
||||||
|
tilde[1] = '~';
|
||||||
|
tilde[2] = NUL;
|
||||||
|
tildelen = 2;
|
||||||
|
}
|
||||||
|
|
||||||
for (p = newsub; *p; ++p)
|
for (p = newsub; *p; ++p)
|
||||||
{
|
{
|
||||||
if ((*p == '~' && magic) || (*p == '\\' && *(p + 1) == '~' && !magic))
|
if (STRNCMP(p, tilde, tildelen) == 0)
|
||||||
{
|
{
|
||||||
if (reg_prev_sub != NULL)
|
size_t prefixlen = p - newsub; // not including the tilde
|
||||||
|
char_u *postfix = p + tildelen;
|
||||||
|
size_t postfixlen;
|
||||||
|
size_t tmpsublen;
|
||||||
|
|
||||||
|
if (newsublen == 0)
|
||||||
|
newsublen = STRLEN(newsub);
|
||||||
|
newsublen -= tildelen;
|
||||||
|
postfixlen = newsublen - prefixlen;
|
||||||
|
tmpsublen = prefixlen + reg_prev_sublen + postfixlen;
|
||||||
|
|
||||||
|
if (tmpsublen > 0 && reg_prev_sub != NULL)
|
||||||
{
|
{
|
||||||
// length = len(newsub) - 1 + len(prev_sub) + 1
|
char_u *tmpsub;
|
||||||
|
|
||||||
// Avoid making the text longer than MAXCOL, it will cause
|
// Avoid making the text longer than MAXCOL, it will cause
|
||||||
// trouble at some point.
|
// trouble at some point.
|
||||||
size_t prevsublen = STRLEN(reg_prev_sub);
|
if (tmpsublen > MAXCOL)
|
||||||
size_t newsublen = STRLEN(newsub);
|
|
||||||
if (prevsublen > MAXCOL || newsublen > MAXCOL
|
|
||||||
|| newsublen + prevsublen > MAXCOL)
|
|
||||||
{
|
{
|
||||||
emsg(_(e_resulting_text_too_long));
|
emsg(_(e_resulting_text_too_long));
|
||||||
|
error = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
char_u *tmpsub = alloc(newsublen + prevsublen);
|
tmpsub = alloc(tmpsublen + 1);
|
||||||
if (tmpsub != NULL)
|
if (tmpsub == NULL)
|
||||||
{
|
{
|
||||||
// copy prefix
|
emsg(_(e_out_of_memory));
|
||||||
size_t prefixlen = p - newsub; // not including ~
|
error = TRUE;
|
||||||
mch_memmove(tmpsub, newsub, prefixlen);
|
break;
|
||||||
// interpret tilde
|
|
||||||
mch_memmove(tmpsub + prefixlen, reg_prev_sub,
|
|
||||||
prevsublen);
|
|
||||||
// copy postfix
|
|
||||||
if (!magic)
|
|
||||||
++p; // back off backslash
|
|
||||||
STRCPY(tmpsub + prefixlen + prevsublen, p + 1);
|
|
||||||
|
|
||||||
if (newsub != source) // allocated newsub before
|
|
||||||
vim_free(newsub);
|
|
||||||
newsub = tmpsub;
|
|
||||||
p = newsub + prefixlen + prevsublen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy prefix
|
||||||
|
mch_memmove(tmpsub, newsub, prefixlen);
|
||||||
|
// interpret tilde
|
||||||
|
mch_memmove(tmpsub + prefixlen, reg_prev_sub, reg_prev_sublen);
|
||||||
|
// copy postfix
|
||||||
|
STRCPY(tmpsub + prefixlen + reg_prev_sublen, postfix);
|
||||||
|
|
||||||
|
if (newsub != source) // allocated newsub before
|
||||||
|
vim_free(newsub);
|
||||||
|
newsub = tmpsub;
|
||||||
|
newsublen = tmpsublen;
|
||||||
|
p = newsub + prefixlen + reg_prev_sublen;
|
||||||
}
|
}
|
||||||
else if (magic)
|
|
||||||
STRMOVE(p, p + 1); // remove '~'
|
|
||||||
else
|
else
|
||||||
STRMOVE(p, p + 2); // remove '\~'
|
mch_memmove(p, postfix, postfixlen + 1); // remove the tilde (+1 for the NUL)
|
||||||
|
|
||||||
--p;
|
--p;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1799,31 +1941,33 @@ regtilde(char_u *source, int magic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (newsub != source)
|
||||||
|
vim_free(newsub);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
// Store a copy of newsub in reg_prev_sub. It is always allocated,
|
// Store a copy of newsub in reg_prev_sub. It is always allocated,
|
||||||
// because recursive calls may make the returned string invalid.
|
// because recursive calls may make the returned string invalid.
|
||||||
vim_free(reg_prev_sub);
|
// Only store it if there something to store.
|
||||||
reg_prev_sub = vim_strsave(newsub);
|
newsublen = p - newsub;
|
||||||
|
if (newsublen == 0)
|
||||||
|
VIM_CLEAR(reg_prev_sub);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vim_free(reg_prev_sub);
|
||||||
|
reg_prev_sub = vim_strnsave(newsub, newsublen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg_prev_sub == NULL)
|
||||||
|
reg_prev_sublen = 0;
|
||||||
|
else
|
||||||
|
reg_prev_sublen = newsublen;
|
||||||
|
|
||||||
return newsub;
|
return newsub;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEAT_EVAL
|
|
||||||
static int can_f_submatch = FALSE; // TRUE when submatch() can be used
|
|
||||||
|
|
||||||
// These pointers are used for reg_submatch(). Needed for when the
|
|
||||||
// substitution string is an expression that contains a call to substitute()
|
|
||||||
// and submatch().
|
|
||||||
typedef struct {
|
|
||||||
regmatch_T *sm_match;
|
|
||||||
regmmatch_T *sm_mmatch;
|
|
||||||
linenr_T sm_firstlnum;
|
|
||||||
linenr_T sm_maxline;
|
|
||||||
int sm_line_lbr;
|
|
||||||
} regsubmatch_T;
|
|
||||||
|
|
||||||
static regsubmatch_T rsm; // can only be used when can_f_submatch is TRUE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2028,12 +2172,16 @@ vim_regsub_both(
|
|||||||
// "flags & REGSUB_COPY" != 0.
|
// "flags & REGSUB_COPY" != 0.
|
||||||
if (copy)
|
if (copy)
|
||||||
{
|
{
|
||||||
if (eval_result[nested] != NULL &&
|
if (eval_result[nested] != NULL)
|
||||||
(int)STRLEN(eval_result[nested]) < destlen)
|
|
||||||
{
|
{
|
||||||
STRCPY(dest, eval_result[nested]);
|
int eval_len = (int)STRLEN(eval_result[nested]);
|
||||||
dst += STRLEN(eval_result[nested]);
|
|
||||||
VIM_CLEAR(eval_result[nested]);
|
if (eval_len < destlen)
|
||||||
|
{
|
||||||
|
STRCPY(dest, eval_result[nested]);
|
||||||
|
dst += eval_len;
|
||||||
|
VIM_CLEAR(eval_result[nested]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2325,7 +2473,7 @@ vim_regsub_both(
|
|||||||
len = rex.reg_mmatch->endpos[no].col
|
len = rex.reg_mmatch->endpos[no].col
|
||||||
- rex.reg_mmatch->startpos[no].col;
|
- rex.reg_mmatch->startpos[no].col;
|
||||||
else
|
else
|
||||||
len = (int)STRLEN(s);
|
len = (int)reg_getline_len(clnum) - rex.reg_mmatch->startpos[no].col;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2360,7 +2508,7 @@ vim_regsub_both(
|
|||||||
if (rex.reg_mmatch->endpos[no].lnum == clnum)
|
if (rex.reg_mmatch->endpos[no].lnum == clnum)
|
||||||
len = rex.reg_mmatch->endpos[no].col;
|
len = rex.reg_mmatch->endpos[no].col;
|
||||||
else
|
else
|
||||||
len = (int)STRLEN(s);
|
len = (int)reg_getline_len(clnum);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@@ -2465,26 +2613,25 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
/*
|
|
||||||
* Call reg_getline() with the line numbers from the submatch. If a
|
|
||||||
* substitute() was used the reg_maxline and other values have been
|
|
||||||
* overwritten.
|
|
||||||
*/
|
|
||||||
static char_u *
|
static char_u *
|
||||||
reg_getline_submatch(linenr_T lnum)
|
reg_getline_submatch(linenr_T lnum)
|
||||||
{
|
{
|
||||||
char_u *s;
|
char_u *line;
|
||||||
linenr_T save_first = rex.reg_firstlnum;
|
|
||||||
linenr_T save_max = rex.reg_maxline;
|
|
||||||
|
|
||||||
rex.reg_firstlnum = rsm.sm_firstlnum;
|
reg_getline_common(lnum, RGLF_LINE | RGLF_SUBMATCH, &line, NULL);
|
||||||
rex.reg_maxline = rsm.sm_maxline;
|
|
||||||
|
|
||||||
s = reg_getline(lnum);
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
rex.reg_firstlnum = save_first;
|
static colnr_T
|
||||||
rex.reg_maxline = save_max;
|
reg_getline_submatch_len(linenr_T lnum)
|
||||||
return s;
|
{
|
||||||
|
colnr_T length;
|
||||||
|
|
||||||
|
reg_getline_common(lnum, RGLF_LENGTH | RGLF_SUBMATCH, NULL, &length);
|
||||||
|
|
||||||
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2533,7 +2680,7 @@ reg_submatch(int no)
|
|||||||
{
|
{
|
||||||
// Multiple lines: take start line from start col, middle
|
// Multiple lines: take start line from start col, middle
|
||||||
// lines completely and end line up to end col.
|
// lines completely and end line up to end col.
|
||||||
len = (int)STRLEN(s);
|
len = (int)reg_getline_submatch_len(lnum) - rsm.sm_mmatch->startpos[no].col;
|
||||||
if (round == 2)
|
if (round == 2)
|
||||||
{
|
{
|
||||||
STRCPY(retval, s);
|
STRCPY(retval, s);
|
||||||
@@ -2543,13 +2690,14 @@ reg_submatch(int no)
|
|||||||
++lnum;
|
++lnum;
|
||||||
while (lnum < rsm.sm_mmatch->endpos[no].lnum)
|
while (lnum < rsm.sm_mmatch->endpos[no].lnum)
|
||||||
{
|
{
|
||||||
s = reg_getline_submatch(lnum++);
|
s = reg_getline_submatch(lnum);
|
||||||
if (round == 2)
|
if (round == 2)
|
||||||
STRCPY(retval + len, s);
|
STRCPY(retval + len, s);
|
||||||
len += (int)STRLEN(s);
|
len += (int)reg_getline_submatch_len(lnum);
|
||||||
if (round == 2)
|
if (round == 2)
|
||||||
retval[len] = '\n';
|
retval[len] = '\n';
|
||||||
++len;
|
++len;
|
||||||
|
++lnum;
|
||||||
}
|
}
|
||||||
if (round == 2)
|
if (round == 2)
|
||||||
STRNCPY(retval + len, reg_getline_submatch(lnum),
|
STRNCPY(retval + len, reg_getline_submatch(lnum),
|
||||||
@@ -2624,9 +2772,11 @@ reg_submatch_list(int no)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int max_lnum = elnum - slnum;
|
||||||
|
|
||||||
if (list_append_string(list, s, -1) == FAIL)
|
if (list_append_string(list, s, -1) == FAIL)
|
||||||
error = TRUE;
|
error = TRUE;
|
||||||
for (i = 1; i < elnum - slnum; i++)
|
for (i = 1; i < max_lnum; i++)
|
||||||
{
|
{
|
||||||
s = reg_getline_submatch(slnum + i);
|
s = reg_getline_submatch(slnum + i);
|
||||||
if (list_append_string(list, s, -1) == FAIL)
|
if (list_append_string(list, s, -1) == FAIL)
|
||||||
|
@@ -2564,14 +2564,22 @@ bt_regcomp(char_u *expr, int re_flags)
|
|||||||
if ((flags & SPSTART || OP(scan) == BOW || OP(scan) == EOW)
|
if ((flags & SPSTART || OP(scan) == BOW || OP(scan) == EOW)
|
||||||
&& !(flags & HASNL))
|
&& !(flags & HASNL))
|
||||||
{
|
{
|
||||||
|
size_t scanlen;
|
||||||
|
|
||||||
longest = NULL;
|
longest = NULL;
|
||||||
len = 0;
|
len = 0;
|
||||||
for (; scan != NULL; scan = regnext(scan))
|
for (; scan != NULL; scan = regnext(scan))
|
||||||
if (OP(scan) == EXACTLY && STRLEN(OPERAND(scan)) >= (size_t)len)
|
{
|
||||||
|
if (OP(scan) == EXACTLY)
|
||||||
{
|
{
|
||||||
longest = OPERAND(scan);
|
scanlen = STRLEN(OPERAND(scan));
|
||||||
len = (int)STRLEN(OPERAND(scan));
|
if (scanlen >= (size_t)len)
|
||||||
|
{
|
||||||
|
longest = OPERAND(scan);
|
||||||
|
len = (int)scanlen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
r->regmust = longest;
|
r->regmust = longest;
|
||||||
r->regmlen = len;
|
r->regmlen = len;
|
||||||
}
|
}
|
||||||
@@ -3406,8 +3414,7 @@ regmatch(
|
|||||||
{
|
{
|
||||||
colnr_T pos_col = pos->lnum == rex.lnum + rex.reg_firstlnum
|
colnr_T pos_col = pos->lnum == rex.lnum + rex.reg_firstlnum
|
||||||
&& pos->col == MAXCOL
|
&& pos->col == MAXCOL
|
||||||
? (colnr_T)STRLEN(reg_getline(
|
? reg_getline_len(pos->lnum - rex.reg_firstlnum)
|
||||||
pos->lnum - rex.reg_firstlnum))
|
|
||||||
: pos->col;
|
: pos->col;
|
||||||
|
|
||||||
if ((pos->lnum == rex.lnum + rex.reg_firstlnum
|
if ((pos->lnum == rex.lnum + rex.reg_firstlnum
|
||||||
@@ -4695,7 +4702,7 @@ regmatch(
|
|||||||
// right.
|
// right.
|
||||||
if (rex.line == NULL)
|
if (rex.line == NULL)
|
||||||
break;
|
break;
|
||||||
rex.input = rex.line + STRLEN(rex.line);
|
rex.input = rex.line + reg_getline_len(rex.lnum);
|
||||||
fast_breakcheck();
|
fast_breakcheck();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -5249,8 +5256,10 @@ regprop(char_u *op)
|
|||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
static char buf[50];
|
static char buf[50];
|
||||||
|
static size_t buflen = 0;
|
||||||
|
|
||||||
STRCPY(buf, ":");
|
STRCPY(buf, ":");
|
||||||
|
buflen = 1;
|
||||||
|
|
||||||
switch ((int) OP(op))
|
switch ((int) OP(op))
|
||||||
{
|
{
|
||||||
@@ -5491,7 +5500,7 @@ regprop(char_u *op)
|
|||||||
case MOPEN + 7:
|
case MOPEN + 7:
|
||||||
case MOPEN + 8:
|
case MOPEN + 8:
|
||||||
case MOPEN + 9:
|
case MOPEN + 9:
|
||||||
sprintf(buf + STRLEN(buf), "MOPEN%d", OP(op) - MOPEN);
|
buflen += sprintf(buf + buflen, "MOPEN%d", OP(op) - MOPEN);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
case MCLOSE + 0:
|
case MCLOSE + 0:
|
||||||
@@ -5506,7 +5515,7 @@ regprop(char_u *op)
|
|||||||
case MCLOSE + 7:
|
case MCLOSE + 7:
|
||||||
case MCLOSE + 8:
|
case MCLOSE + 8:
|
||||||
case MCLOSE + 9:
|
case MCLOSE + 9:
|
||||||
sprintf(buf + STRLEN(buf), "MCLOSE%d", OP(op) - MCLOSE);
|
buflen += sprintf(buf + buflen, "MCLOSE%d", OP(op) - MCLOSE);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
case BACKREF + 1:
|
case BACKREF + 1:
|
||||||
@@ -5518,7 +5527,7 @@ regprop(char_u *op)
|
|||||||
case BACKREF + 7:
|
case BACKREF + 7:
|
||||||
case BACKREF + 8:
|
case BACKREF + 8:
|
||||||
case BACKREF + 9:
|
case BACKREF + 9:
|
||||||
sprintf(buf + STRLEN(buf), "BACKREF%d", OP(op) - BACKREF);
|
buflen += sprintf(buf + buflen, "BACKREF%d", OP(op) - BACKREF);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
case NOPEN:
|
case NOPEN:
|
||||||
@@ -5537,7 +5546,7 @@ regprop(char_u *op)
|
|||||||
case ZOPEN + 7:
|
case ZOPEN + 7:
|
||||||
case ZOPEN + 8:
|
case ZOPEN + 8:
|
||||||
case ZOPEN + 9:
|
case ZOPEN + 9:
|
||||||
sprintf(buf + STRLEN(buf), "ZOPEN%d", OP(op) - ZOPEN);
|
buflen += sprintf(buf + buflen, "ZOPEN%d", OP(op) - ZOPEN);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
case ZCLOSE + 1:
|
case ZCLOSE + 1:
|
||||||
@@ -5549,7 +5558,7 @@ regprop(char_u *op)
|
|||||||
case ZCLOSE + 7:
|
case ZCLOSE + 7:
|
||||||
case ZCLOSE + 8:
|
case ZCLOSE + 8:
|
||||||
case ZCLOSE + 9:
|
case ZCLOSE + 9:
|
||||||
sprintf(buf + STRLEN(buf), "ZCLOSE%d", OP(op) - ZCLOSE);
|
buflen += sprintf(buf + buflen, "ZCLOSE%d", OP(op) - ZCLOSE);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
case ZREF + 1:
|
case ZREF + 1:
|
||||||
@@ -5561,7 +5570,7 @@ regprop(char_u *op)
|
|||||||
case ZREF + 7:
|
case ZREF + 7:
|
||||||
case ZREF + 8:
|
case ZREF + 8:
|
||||||
case ZREF + 9:
|
case ZREF + 9:
|
||||||
sprintf(buf + STRLEN(buf), "ZREF%d", OP(op) - ZREF);
|
bulen += sprintf(buf + buflen, "ZREF%d", OP(op) - ZREF);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@@ -5602,7 +5611,7 @@ regprop(char_u *op)
|
|||||||
case BRACE_COMPLEX + 7:
|
case BRACE_COMPLEX + 7:
|
||||||
case BRACE_COMPLEX + 8:
|
case BRACE_COMPLEX + 8:
|
||||||
case BRACE_COMPLEX + 9:
|
case BRACE_COMPLEX + 9:
|
||||||
sprintf(buf + STRLEN(buf), "BRACE_COMPLEX%d", OP(op) - BRACE_COMPLEX);
|
buflen += sprintf(buf + buflen, "BRACE_COMPLEX%d", OP(op) - BRACE_COMPLEX);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
case MULTIBYTECODE:
|
case MULTIBYTECODE:
|
||||||
@@ -5612,12 +5621,12 @@ regprop(char_u *op)
|
|||||||
p = "NEWL";
|
p = "NEWL";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(buf + STRLEN(buf), "corrupt %d", OP(op));
|
buflen += sprintf(buf + buflen, "corrupt %d", OP(op));
|
||||||
p = NULL;
|
p = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
STRCAT(buf, p);
|
STRCPY(buf + buflen, p);
|
||||||
return (char_u *)buf;
|
return (char_u *)buf;
|
||||||
}
|
}
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
|
@@ -5387,7 +5387,7 @@ recursive_regmatch(
|
|||||||
rex.input = rex.line;
|
rex.input = rex.line;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rex.input = rex.line + STRLEN(rex.line);
|
rex.input = rex.line + reg_getline_len(rex.lnum);
|
||||||
}
|
}
|
||||||
if ((int)(rex.input - rex.line) >= state->val)
|
if ((int)(rex.input - rex.line) >= state->val)
|
||||||
{
|
{
|
||||||
@@ -6937,8 +6937,7 @@ nfa_regmatch(
|
|||||||
{
|
{
|
||||||
colnr_T pos_col = pos->lnum == rex.lnum + rex.reg_firstlnum
|
colnr_T pos_col = pos->lnum == rex.lnum + rex.reg_firstlnum
|
||||||
&& pos->col == MAXCOL
|
&& pos->col == MAXCOL
|
||||||
? (colnr_T)STRLEN(reg_getline(
|
? reg_getline_len(pos->lnum - rex.reg_firstlnum)
|
||||||
pos->lnum - rex.reg_firstlnum))
|
|
||||||
: pos->col;
|
: pos->col;
|
||||||
|
|
||||||
result = (pos->lnum == rex.lnum + rex.reg_firstlnum
|
result = (pos->lnum == rex.lnum + rex.reg_firstlnum
|
||||||
|
@@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
409,
|
||||||
/**/
|
/**/
|
||||||
408,
|
408,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user