mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 7.4.2219
Problem: Recursive call to substitute gets stuck in sandbox. (Nikolai Pavlov) Solution: Handle the recursive call. (Christian Brabandt, closes #950) Add a test.
This commit is contained in:
parent
13d216d302
commit
f5a39447a8
140
src/ex_cmds.c
140
src/ex_cmds.c
@ -4747,6 +4747,20 @@ check_secure(void)
|
|||||||
static char_u *old_sub = NULL; /* previous substitute pattern */
|
static char_u *old_sub = NULL; /* previous substitute pattern */
|
||||||
static int global_need_beginline; /* call beginline() after ":g" */
|
static int global_need_beginline; /* call beginline() after ":g" */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags that are kept between calls to :substitute.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int do_all; /* do multiple substitutions per line */
|
||||||
|
int do_ask; /* ask for confirmation */
|
||||||
|
int do_count; /* count only */
|
||||||
|
int do_error; /* if false, ignore errors */
|
||||||
|
int do_print; /* print last line with subs. */
|
||||||
|
int do_list; /* list last line with subs. */
|
||||||
|
int do_number; /* list last line with line nr*/
|
||||||
|
int do_ic; /* ignore case flag */
|
||||||
|
} subflags_T;
|
||||||
|
|
||||||
/* do_sub()
|
/* do_sub()
|
||||||
*
|
*
|
||||||
* Perform a substitution from line eap->line1 to line eap->line2 using the
|
* Perform a substitution from line eap->line1 to line eap->line2 using the
|
||||||
@ -4762,14 +4776,11 @@ do_sub(exarg_T *eap)
|
|||||||
linenr_T lnum;
|
linenr_T lnum;
|
||||||
long i = 0;
|
long i = 0;
|
||||||
regmmatch_T regmatch;
|
regmmatch_T regmatch;
|
||||||
static int do_all = FALSE; /* do multiple substitutions per line */
|
static subflags_T subflags = {FALSE, FALSE, FALSE, TRUE, FALSE,
|
||||||
static int do_ask = FALSE; /* ask for confirmation */
|
FALSE, FALSE, 0};
|
||||||
static int do_count = FALSE; /* count only */
|
#ifdef FEAT_EVAL
|
||||||
static int do_error = TRUE; /* if false, ignore errors */
|
subflags_T subflags_save;
|
||||||
static int do_print = FALSE; /* print last line with subs. */
|
#endif
|
||||||
static int do_list = FALSE; /* list last line with subs. */
|
|
||||||
static int do_number = FALSE; /* list last line with line nr*/
|
|
||||||
static int do_ic = 0; /* ignore case flag */
|
|
||||||
int save_do_all; /* remember user specified 'g' flag */
|
int save_do_all; /* remember user specified 'g' flag */
|
||||||
int save_do_ask; /* remember user specified 'c' flag */
|
int save_do_ask; /* remember user specified 'c' flag */
|
||||||
char_u *pat = NULL, *sub = NULL; /* init for GCC */
|
char_u *pat = NULL, *sub = NULL; /* init for GCC */
|
||||||
@ -4957,16 +4968,16 @@ do_sub(exarg_T *eap)
|
|||||||
if (!p_ed)
|
if (!p_ed)
|
||||||
{
|
{
|
||||||
if (p_gd) /* default is global on */
|
if (p_gd) /* default is global on */
|
||||||
do_all = TRUE;
|
subflags.do_all = TRUE;
|
||||||
else
|
else
|
||||||
do_all = FALSE;
|
subflags.do_all = FALSE;
|
||||||
do_ask = FALSE;
|
subflags.do_ask = FALSE;
|
||||||
}
|
}
|
||||||
do_error = TRUE;
|
subflags.do_error = TRUE;
|
||||||
do_print = FALSE;
|
subflags.do_print = FALSE;
|
||||||
do_count = FALSE;
|
subflags.do_count = FALSE;
|
||||||
do_number = FALSE;
|
subflags.do_number = FALSE;
|
||||||
do_ic = 0;
|
subflags.do_ic = 0;
|
||||||
}
|
}
|
||||||
while (*cmd)
|
while (*cmd)
|
||||||
{
|
{
|
||||||
@ -4975,40 +4986,40 @@ do_sub(exarg_T *eap)
|
|||||||
* 'r' is never inverted.
|
* 'r' is never inverted.
|
||||||
*/
|
*/
|
||||||
if (*cmd == 'g')
|
if (*cmd == 'g')
|
||||||
do_all = !do_all;
|
subflags.do_all = !subflags.do_all;
|
||||||
else if (*cmd == 'c')
|
else if (*cmd == 'c')
|
||||||
do_ask = !do_ask;
|
subflags.do_ask = !subflags.do_ask;
|
||||||
else if (*cmd == 'n')
|
else if (*cmd == 'n')
|
||||||
do_count = TRUE;
|
subflags.do_count = TRUE;
|
||||||
else if (*cmd == 'e')
|
else if (*cmd == 'e')
|
||||||
do_error = !do_error;
|
subflags.do_error = !subflags.do_error;
|
||||||
else if (*cmd == 'r') /* use last used regexp */
|
else if (*cmd == 'r') /* use last used regexp */
|
||||||
which_pat = RE_LAST;
|
which_pat = RE_LAST;
|
||||||
else if (*cmd == 'p')
|
else if (*cmd == 'p')
|
||||||
do_print = TRUE;
|
subflags.do_print = TRUE;
|
||||||
else if (*cmd == '#')
|
else if (*cmd == '#')
|
||||||
{
|
{
|
||||||
do_print = TRUE;
|
subflags.do_print = TRUE;
|
||||||
do_number = TRUE;
|
subflags.do_number = TRUE;
|
||||||
}
|
}
|
||||||
else if (*cmd == 'l')
|
else if (*cmd == 'l')
|
||||||
{
|
{
|
||||||
do_print = TRUE;
|
subflags.do_print = TRUE;
|
||||||
do_list = TRUE;
|
subflags.do_list = TRUE;
|
||||||
}
|
}
|
||||||
else if (*cmd == 'i') /* ignore case */
|
else if (*cmd == 'i') /* ignore case */
|
||||||
do_ic = 'i';
|
subflags.do_ic = 'i';
|
||||||
else if (*cmd == 'I') /* don't ignore case */
|
else if (*cmd == 'I') /* don't ignore case */
|
||||||
do_ic = 'I';
|
subflags.do_ic = 'I';
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
++cmd;
|
++cmd;
|
||||||
}
|
}
|
||||||
if (do_count)
|
if (subflags.do_count)
|
||||||
do_ask = FALSE;
|
subflags.do_ask = FALSE;
|
||||||
|
|
||||||
save_do_all = do_all;
|
save_do_all = subflags.do_all;
|
||||||
save_do_ask = do_ask;
|
save_do_ask = subflags.do_ask;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check for a trailing count
|
* check for a trailing count
|
||||||
@ -5017,7 +5028,7 @@ do_sub(exarg_T *eap)
|
|||||||
if (VIM_ISDIGIT(*cmd))
|
if (VIM_ISDIGIT(*cmd))
|
||||||
{
|
{
|
||||||
i = getdigits(&cmd);
|
i = getdigits(&cmd);
|
||||||
if (i <= 0 && !eap->skip && do_error)
|
if (i <= 0 && !eap->skip && subflags.do_error)
|
||||||
{
|
{
|
||||||
EMSG(_(e_zerocount));
|
EMSG(_(e_zerocount));
|
||||||
return;
|
return;
|
||||||
@ -5045,7 +5056,7 @@ do_sub(exarg_T *eap)
|
|||||||
if (eap->skip) /* not executing commands, only parsing */
|
if (eap->skip) /* not executing commands, only parsing */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!do_count && !curbuf->b_p_ma)
|
if (!subflags.do_count && !curbuf->b_p_ma)
|
||||||
{
|
{
|
||||||
/* Substitution is not allowed in non-'modifiable' buffer */
|
/* Substitution is not allowed in non-'modifiable' buffer */
|
||||||
EMSG(_(e_modifiable));
|
EMSG(_(e_modifiable));
|
||||||
@ -5054,15 +5065,15 @@ do_sub(exarg_T *eap)
|
|||||||
|
|
||||||
if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, ®match) == FAIL)
|
if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, ®match) == FAIL)
|
||||||
{
|
{
|
||||||
if (do_error)
|
if (subflags.do_error)
|
||||||
EMSG(_(e_invcmd));
|
EMSG(_(e_invcmd));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */
|
/* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */
|
||||||
if (do_ic == 'i')
|
if (subflags.do_ic == 'i')
|
||||||
regmatch.rmm_ic = TRUE;
|
regmatch.rmm_ic = TRUE;
|
||||||
else if (do_ic == 'I')
|
else if (subflags.do_ic == 'I')
|
||||||
regmatch.rmm_ic = FALSE;
|
regmatch.rmm_ic = FALSE;
|
||||||
|
|
||||||
sub_firstline = NULL;
|
sub_firstline = NULL;
|
||||||
@ -5231,7 +5242,7 @@ do_sub(exarg_T *eap)
|
|||||||
* 2. If do_count is set only increase the counter.
|
* 2. If do_count is set only increase the counter.
|
||||||
* If do_ask is set, ask for confirmation.
|
* If do_ask is set, ask for confirmation.
|
||||||
*/
|
*/
|
||||||
if (do_count)
|
if (subflags.do_count)
|
||||||
{
|
{
|
||||||
/* For a multi-line match, put matchcol at the NUL at
|
/* For a multi-line match, put matchcol at the NUL at
|
||||||
* the end of the line and set nmatch to one, so that
|
* the end of the line and set nmatch to one, so that
|
||||||
@ -5253,7 +5264,7 @@ do_sub(exarg_T *eap)
|
|||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_ask)
|
if (subflags.do_ask)
|
||||||
{
|
{
|
||||||
int typed = 0;
|
int typed = 0;
|
||||||
|
|
||||||
@ -5274,19 +5285,20 @@ do_sub(exarg_T *eap)
|
|||||||
/*
|
/*
|
||||||
* Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
|
* Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
|
||||||
*/
|
*/
|
||||||
while (do_ask)
|
while (subflags.do_ask)
|
||||||
{
|
{
|
||||||
if (exmode_active)
|
if (exmode_active)
|
||||||
{
|
{
|
||||||
char_u *resp;
|
char_u *resp;
|
||||||
colnr_T sc, ec;
|
colnr_T sc, ec;
|
||||||
|
|
||||||
print_line_no_prefix(lnum, do_number, do_list);
|
print_line_no_prefix(lnum,
|
||||||
|
subflags.do_number, subflags.do_list);
|
||||||
|
|
||||||
getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL);
|
getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL);
|
||||||
curwin->w_cursor.col = regmatch.endpos[0].col - 1;
|
curwin->w_cursor.col = regmatch.endpos[0].col - 1;
|
||||||
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
|
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
|
||||||
if (do_number || curwin->w_p_nu)
|
if (subflags.do_number || curwin->w_p_nu)
|
||||||
{
|
{
|
||||||
int numw = number_width(curwin) + 1;
|
int numw = number_width(curwin) + 1;
|
||||||
sc += numw;
|
sc += numw;
|
||||||
@ -5420,13 +5432,13 @@ do_sub(exarg_T *eap)
|
|||||||
if (typed == 'l')
|
if (typed == 'l')
|
||||||
{
|
{
|
||||||
/* last: replace and then stop */
|
/* last: replace and then stop */
|
||||||
do_all = FALSE;
|
subflags.do_all = FALSE;
|
||||||
line2 = lnum;
|
line2 = lnum;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (typed == 'a')
|
if (typed == 'a')
|
||||||
{
|
{
|
||||||
do_ask = FALSE;
|
subflags.do_ask = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef FEAT_INS_EXPAND
|
#ifdef FEAT_INS_EXPAND
|
||||||
@ -5469,23 +5481,29 @@ do_sub(exarg_T *eap)
|
|||||||
* 3. substitute the string.
|
* 3. substitute the string.
|
||||||
*/
|
*/
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
if (do_count)
|
if (subflags.do_count)
|
||||||
{
|
{
|
||||||
/* prevent accidentally changing the buffer by a function */
|
/* prevent accidentally changing the buffer by a function */
|
||||||
save_ma = curbuf->b_p_ma;
|
save_ma = curbuf->b_p_ma;
|
||||||
curbuf->b_p_ma = FALSE;
|
curbuf->b_p_ma = FALSE;
|
||||||
sandbox++;
|
sandbox++;
|
||||||
}
|
}
|
||||||
|
/* Save flags for recursion. They can change for e.g.
|
||||||
|
* :s/^/\=execute("s#^##gn") */
|
||||||
|
subflags_save = subflags;
|
||||||
#endif
|
#endif
|
||||||
/* get length of substitution part */
|
/* get length of substitution part */
|
||||||
sublen = vim_regsub_multi(®match,
|
sublen = vim_regsub_multi(®match,
|
||||||
sub_firstlnum - regmatch.startpos[0].lnum,
|
sub_firstlnum - regmatch.startpos[0].lnum,
|
||||||
sub, sub_firstline, FALSE, p_magic, TRUE);
|
sub, sub_firstline, FALSE, p_magic, TRUE);
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
if (do_count)
|
/* Don't keep flags set by a recursive call. */
|
||||||
|
subflags = subflags_save;
|
||||||
|
if (subflags.do_count)
|
||||||
{
|
{
|
||||||
curbuf->b_p_ma = save_ma;
|
curbuf->b_p_ma = save_ma;
|
||||||
sandbox--;
|
if (sandbox > 0)
|
||||||
|
sandbox--;
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -5578,7 +5596,7 @@ do_sub(exarg_T *eap)
|
|||||||
if (sub_firstlnum <= line2)
|
if (sub_firstlnum <= line2)
|
||||||
do_again = TRUE;
|
do_again = TRUE;
|
||||||
else
|
else
|
||||||
do_all = FALSE;
|
subflags.do_all = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remember next character to be copied. */
|
/* Remember next character to be copied. */
|
||||||
@ -5613,7 +5631,7 @@ do_sub(exarg_T *eap)
|
|||||||
ml_append(lnum - 1, new_start,
|
ml_append(lnum - 1, new_start,
|
||||||
(colnr_T)(p1 - new_start + 1), FALSE);
|
(colnr_T)(p1 - new_start + 1), FALSE);
|
||||||
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
|
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
|
||||||
if (do_ask)
|
if (subflags.do_ask)
|
||||||
appended_lines(lnum - 1, 1L);
|
appended_lines(lnum - 1, 1L);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -5654,7 +5672,7 @@ skip:
|
|||||||
|| got_int
|
|| got_int
|
||||||
|| got_quit
|
|| got_quit
|
||||||
|| lnum > line2
|
|| lnum > line2
|
||||||
|| !(do_all || do_again)
|
|| !(subflags.do_all || do_again)
|
||||||
|| (sub_firstline[matchcol] == NUL && nmatch <= 1
|
|| (sub_firstline[matchcol] == NUL && nmatch <= 1
|
||||||
&& !re_multiline(regmatch.regprog)));
|
&& !re_multiline(regmatch.regprog)));
|
||||||
nmatch = -1;
|
nmatch = -1;
|
||||||
@ -5708,7 +5726,7 @@ skip:
|
|||||||
ml_delete(lnum, (int)FALSE);
|
ml_delete(lnum, (int)FALSE);
|
||||||
mark_adjust(lnum, lnum + nmatch_tl - 1,
|
mark_adjust(lnum, lnum + nmatch_tl - 1,
|
||||||
(long)MAXLNUM, -nmatch_tl);
|
(long)MAXLNUM, -nmatch_tl);
|
||||||
if (do_ask)
|
if (subflags.do_ask)
|
||||||
deleted_lines(lnum, nmatch_tl);
|
deleted_lines(lnum, nmatch_tl);
|
||||||
--lnum;
|
--lnum;
|
||||||
line2 -= nmatch_tl; /* nr of lines decreases */
|
line2 -= nmatch_tl; /* nr of lines decreases */
|
||||||
@ -5717,7 +5735,7 @@ skip:
|
|||||||
|
|
||||||
/* When asking, undo is saved each time, must also set
|
/* When asking, undo is saved each time, must also set
|
||||||
* changed flag each time. */
|
* changed flag each time. */
|
||||||
if (do_ask)
|
if (subflags.do_ask)
|
||||||
changed_bytes(lnum, 0);
|
changed_bytes(lnum, 0);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -5779,7 +5797,7 @@ outofmem:
|
|||||||
vim_free(sub_firstline); /* may have to free allocated copy of the line */
|
vim_free(sub_firstline); /* may have to free allocated copy of the line */
|
||||||
|
|
||||||
/* ":s/pat//n" doesn't move the cursor */
|
/* ":s/pat//n" doesn't move the cursor */
|
||||||
if (do_count)
|
if (subflags.do_count)
|
||||||
curwin->w_cursor = old_cursor;
|
curwin->w_cursor = old_cursor;
|
||||||
|
|
||||||
if (sub_nsubs > start_nsubs)
|
if (sub_nsubs > start_nsubs)
|
||||||
@ -5791,20 +5809,22 @@ outofmem:
|
|||||||
|
|
||||||
if (!global_busy)
|
if (!global_busy)
|
||||||
{
|
{
|
||||||
if (!do_ask) /* when interactive leave cursor on the match */
|
/* when interactive leave cursor on the match */
|
||||||
|
if (!subflags.do_ask)
|
||||||
{
|
{
|
||||||
if (endcolumn)
|
if (endcolumn)
|
||||||
coladvance((colnr_T)MAXCOL);
|
coladvance((colnr_T)MAXCOL);
|
||||||
else
|
else
|
||||||
beginline(BL_WHITE | BL_FIX);
|
beginline(BL_WHITE | BL_FIX);
|
||||||
}
|
}
|
||||||
if (!do_sub_msg(do_count) && do_ask)
|
if (!do_sub_msg(subflags.do_count) && subflags.do_ask)
|
||||||
MSG("");
|
MSG("");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
global_need_beginline = TRUE;
|
global_need_beginline = TRUE;
|
||||||
if (do_print)
|
if (subflags.do_print)
|
||||||
print_line(curwin->w_cursor.lnum, do_number, do_list);
|
print_line(curwin->w_cursor.lnum,
|
||||||
|
subflags.do_number, subflags.do_list);
|
||||||
}
|
}
|
||||||
else if (!global_busy)
|
else if (!global_busy)
|
||||||
{
|
{
|
||||||
@ -5812,12 +5832,12 @@ outofmem:
|
|||||||
EMSG(_(e_interr));
|
EMSG(_(e_interr));
|
||||||
else if (got_match) /* did find something but nothing substituted */
|
else if (got_match) /* did find something but nothing substituted */
|
||||||
MSG("");
|
MSG("");
|
||||||
else if (do_error) /* nothing found */
|
else if (subflags.do_error) /* nothing found */
|
||||||
EMSG2(_(e_patnotf2), get_search_pat());
|
EMSG2(_(e_patnotf2), get_search_pat());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEAT_FOLDING
|
#ifdef FEAT_FOLDING
|
||||||
if (do_ask && hasAnyFolding(curwin))
|
if (subflags.do_ask && hasAnyFolding(curwin))
|
||||||
/* Cursor position may require updating */
|
/* Cursor position may require updating */
|
||||||
changed_window_setting();
|
changed_window_setting();
|
||||||
#endif
|
#endif
|
||||||
@ -5825,8 +5845,8 @@ outofmem:
|
|||||||
vim_regfree(regmatch.regprog);
|
vim_regfree(regmatch.regprog);
|
||||||
|
|
||||||
/* Restore the flag values, they can be used for ":&&". */
|
/* Restore the flag values, they can be used for ":&&". */
|
||||||
do_all = save_do_all;
|
subflags.do_all = save_do_all;
|
||||||
do_ask = save_do_ask;
|
subflags.do_ask = save_do_ask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -30,3 +30,12 @@ func Test_equivalence_re2()
|
|||||||
set re=2
|
set re=2
|
||||||
call s:equivalence_test()
|
call s:equivalence_test()
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_recursive_substitute()
|
||||||
|
new
|
||||||
|
s/^/\=execute("s#^##gn")
|
||||||
|
" check we are now not in the sandbox
|
||||||
|
call setwinvar(1, 'myvar', 1)
|
||||||
|
bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
@ -763,6 +763,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 */
|
||||||
|
/**/
|
||||||
|
2219,
|
||||||
/**/
|
/**/
|
||||||
2218,
|
2218,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user