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.
Files: src/ex_cmds.c, src/testdir/test_regexp_latin.vim
*** ../vim-7.4.2218/src/ex_cmds.c 2016-07-30 23:18:44.644927811 +0200
--- src/ex_cmds.c 2016-08-16 20:58:17.915413520 +0200
***************
*** 4747,4752 ****
--- 4747,4766 ----
static char_u *old_sub = NULL; /* previous substitute pattern */
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()
*
* Perform a substitution from line eap->line1 to line eap->line2 using the
***************
*** 4762,4775 ****
linenr_T lnum;
long i = 0;
regmmatch_T regmatch;
! static int do_all = FALSE; /* do multiple substitutions
per line */
! static int do_ask = FALSE; /* ask for confirmation */
! static int do_count = FALSE; /* count only */
! static int do_error = TRUE; /* if false, ignore errors */
! static int do_print = FALSE; /* print last line with subs. */
! 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_ask; /* remember user specified 'c'
flag */
char_u *pat = NULL, *sub = NULL; /* init for GCC */
--- 4776,4786 ----
linenr_T lnum;
long i = 0;
regmmatch_T regmatch;
! static subflags_T subflags = {FALSE, FALSE, FALSE, TRUE, FALSE,
! FALSE, FALSE, 0};
! #ifdef FEAT_EVAL
! subflags_T subflags_save;
! #endif
int save_do_all; /* remember user specified 'g'
flag */
int save_do_ask; /* remember user specified 'c'
flag */
char_u *pat = NULL, *sub = NULL; /* init for GCC */
***************
*** 4957,4972 ****
if (!p_ed)
{
if (p_gd) /* default is global on */
! do_all = TRUE;
else
! do_all = FALSE;
! do_ask = FALSE;
}
! do_error = TRUE;
! do_print = FALSE;
! do_count = FALSE;
! do_number = FALSE;
! do_ic = 0;
}
while (*cmd)
{
--- 4968,4983 ----
if (!p_ed)
{
if (p_gd) /* default is global on */
! subflags.do_all = TRUE;
else
! subflags.do_all = FALSE;
! subflags.do_ask = FALSE;
}
! subflags.do_error = TRUE;
! subflags.do_print = FALSE;
! subflags.do_count = FALSE;
! subflags.do_number = FALSE;
! subflags.do_ic = 0;
}
while (*cmd)
{
***************
*** 4975,5014 ****
* 'r' is never inverted.
*/
if (*cmd == 'g')
! do_all = !do_all;
else if (*cmd == 'c')
! do_ask = !do_ask;
else if (*cmd == 'n')
! do_count = TRUE;
else if (*cmd == 'e')
! do_error = !do_error;
else if (*cmd == 'r') /* use last used regexp */
which_pat = RE_LAST;
else if (*cmd == 'p')
! do_print = TRUE;
else if (*cmd == '#')
{
! do_print = TRUE;
! do_number = TRUE;
}
else if (*cmd == 'l')
{
! do_print = TRUE;
! do_list = TRUE;
}
else if (*cmd == 'i') /* ignore case */
! do_ic = 'i';
else if (*cmd == 'I') /* don't ignore case */
! do_ic = 'I';
else
break;
++cmd;
}
! if (do_count)
! do_ask = FALSE;
! save_do_all = do_all;
! save_do_ask = do_ask;
/*
* check for a trailing count
--- 4986,5025 ----
* 'r' is never inverted.
*/
if (*cmd == 'g')
! subflags.do_all = !subflags.do_all;
else if (*cmd == 'c')
! subflags.do_ask = !subflags.do_ask;
else if (*cmd == 'n')
! subflags.do_count = TRUE;
else if (*cmd == 'e')
! subflags.do_error = !subflags.do_error;
else if (*cmd == 'r') /* use last used regexp */
which_pat = RE_LAST;
else if (*cmd == 'p')
! subflags.do_print = TRUE;
else if (*cmd == '#')
{
! subflags.do_print = TRUE;
! subflags.do_number = TRUE;
}
else if (*cmd == 'l')
{
! subflags.do_print = TRUE;
! subflags.do_list = TRUE;
}
else if (*cmd == 'i') /* ignore case */
! subflags.do_ic = 'i';
else if (*cmd == 'I') /* don't ignore case */
! subflags.do_ic = 'I';
else
break;
++cmd;
}
! if (subflags.do_count)
! subflags.do_ask = FALSE;
! save_do_all = subflags.do_all;
! save_do_ask = subflags.do_ask;
/*
* check for a trailing count
***************
*** 5017,5023 ****
if (VIM_ISDIGIT(*cmd))
{
i = getdigits(&cmd);
! if (i <= 0 && !eap->skip && do_error)
{
EMSG(_(e_zerocount));
return;
--- 5028,5034 ----
if (VIM_ISDIGIT(*cmd))
{
i = getdigits(&cmd);
! if (i <= 0 && !eap->skip && subflags.do_error)
{
EMSG(_(e_zerocount));
return;
***************
*** 5045,5051 ****
if (eap->skip) /* not executing commands, only parsing */
return;
! if (!do_count && !curbuf->b_p_ma)
{
/* Substitution is not allowed in non-'modifiable' buffer */
EMSG(_(e_modifiable));
--- 5056,5062 ----
if (eap->skip) /* not executing commands, only parsing */
return;
! if (!subflags.do_count && !curbuf->b_p_ma)
{
/* Substitution is not allowed in non-'modifiable' buffer */
EMSG(_(e_modifiable));
***************
*** 5054,5068 ****
if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, ®match) ==
FAIL)
{
! if (do_error)
EMSG(_(e_invcmd));
return;
}
/* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */
! if (do_ic == 'i')
regmatch.rmm_ic = TRUE;
! else if (do_ic == 'I')
regmatch.rmm_ic = FALSE;
sub_firstline = NULL;
--- 5065,5079 ----
if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, ®match) ==
FAIL)
{
! if (subflags.do_error)
EMSG(_(e_invcmd));
return;
}
/* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */
! if (subflags.do_ic == 'i')
regmatch.rmm_ic = TRUE;
! else if (subflags.do_ic == 'I')
regmatch.rmm_ic = FALSE;
sub_firstline = NULL;
***************
*** 5231,5237 ****
* 2. If do_count is set only increase the counter.
* If do_ask is set, ask for confirmation.
*/
! if (do_count)
{
/* For a multi-line match, put matchcol at the NUL at
* the end of the line and set nmatch to one, so that
--- 5242,5248 ----
* 2. If do_count is set only increase the counter.
* If do_ask is set, ask for confirmation.
*/
! if (subflags.do_count)
{
/* For a multi-line match, put matchcol at the NUL at
* the end of the line and set nmatch to one, so that
***************
*** 5253,5259 ****
goto skip;
}
! if (do_ask)
{
int typed = 0;
--- 5264,5270 ----
goto skip;
}
! if (subflags.do_ask)
{
int typed = 0;
***************
*** 5274,5292 ****
/*
* Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
*/
! while (do_ask)
{
if (exmode_active)
{
char_u *resp;
colnr_T sc, ec;
! print_line_no_prefix(lnum, do_number, do_list);
getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL);
curwin->w_cursor.col = regmatch.endpos[0].col - 1;
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
! if (do_number || curwin->w_p_nu)
{
int numw = number_width(curwin) + 1;
sc += numw;
--- 5285,5304 ----
/*
* Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
*/
! while (subflags.do_ask)
{
if (exmode_active)
{
char_u *resp;
colnr_T sc, ec;
! print_line_no_prefix(lnum,
! subflags.do_number, subflags.do_list);
getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL);
curwin->w_cursor.col = regmatch.endpos[0].col - 1;
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
! if (subflags.do_number || curwin->w_p_nu)
{
int numw = number_width(curwin) + 1;
sc += numw;
***************
*** 5420,5432 ****
if (typed == 'l')
{
/* last: replace and then stop */
! do_all = FALSE;
line2 = lnum;
break;
}
if (typed == 'a')
{
! do_ask = FALSE;
break;
}
#ifdef FEAT_INS_EXPAND
--- 5432,5444 ----
if (typed == 'l')
{
/* last: replace and then stop */
! subflags.do_all = FALSE;
line2 = lnum;
break;
}
if (typed == 'a')
{
! subflags.do_ask = FALSE;
break;
}
#ifdef FEAT_INS_EXPAND
***************
*** 5469,5491 ****
* 3. substitute the string.
*/
#ifdef FEAT_EVAL
! if (do_count)
{
/* prevent accidentally changing the buffer by a function */
save_ma = curbuf->b_p_ma;
curbuf->b_p_ma = FALSE;
sandbox++;
}
#endif
/* get length of substitution part */
sublen = vim_regsub_multi(®match,
sub_firstlnum - regmatch.startpos[0].lnum,
sub, sub_firstline, FALSE, p_magic, TRUE);
#ifdef FEAT_EVAL
! if (do_count)
{
curbuf->b_p_ma = save_ma;
! sandbox--;
goto skip;
}
#endif
--- 5481,5509 ----
* 3. substitute the string.
*/
#ifdef FEAT_EVAL
! if (subflags.do_count)
{
/* prevent accidentally changing the buffer by a function */
save_ma = curbuf->b_p_ma;
curbuf->b_p_ma = FALSE;
sandbox++;
}
+ /* Save flags for recursion. They can change for e.g.
+ * :s/^/\=execute("s#^##gn") */
+ subflags_save = subflags;
#endif
/* get length of substitution part */
sublen = vim_regsub_multi(®match,
sub_firstlnum - regmatch.startpos[0].lnum,
sub, sub_firstline, FALSE, p_magic, TRUE);
#ifdef FEAT_EVAL
! /* Don't keep flags set by a recursive call. */
! subflags = subflags_save;
! if (subflags.do_count)
{
curbuf->b_p_ma = save_ma;
! if (sandbox > 0)
! sandbox--;
goto skip;
}
#endif
***************
*** 5578,5584 ****
if (sub_firstlnum <= line2)
do_again = TRUE;
else
! do_all = FALSE;
}
/* Remember next character to be copied. */
--- 5596,5602 ----
if (sub_firstlnum <= line2)
do_again = TRUE;
else
! subflags.do_all = FALSE;
}
/* Remember next character to be copied. */
***************
*** 5613,5619 ****
ml_append(lnum - 1, new_start,
(colnr_T)(p1 - new_start + 1), FALSE);
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
! if (do_ask)
appended_lines(lnum - 1, 1L);
else
{
--- 5631,5637 ----
ml_append(lnum - 1, new_start,
(colnr_T)(p1 - new_start + 1), FALSE);
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
! if (subflags.do_ask)
appended_lines(lnum - 1, 1L);
else
{
***************
*** 5654,5660 ****
|| got_int
|| got_quit
|| lnum > line2
! || !(do_all || do_again)
|| (sub_firstline[matchcol] == NUL && nmatch <= 1
&& !re_multiline(regmatch.regprog)));
nmatch = -1;
--- 5672,5678 ----
|| got_int
|| got_quit
|| lnum > line2
! || !(subflags.do_all || do_again)
|| (sub_firstline[matchcol] == NUL && nmatch <= 1
&& !re_multiline(regmatch.regprog)));
nmatch = -1;
***************
*** 5708,5714 ****
ml_delete(lnum, (int)FALSE);
mark_adjust(lnum, lnum + nmatch_tl - 1,
(long)MAXLNUM, -nmatch_tl);
! if (do_ask)
deleted_lines(lnum, nmatch_tl);
--lnum;
line2 -= nmatch_tl; /* nr of lines decreases */
--- 5726,5732 ----
ml_delete(lnum, (int)FALSE);
mark_adjust(lnum, lnum + nmatch_tl - 1,
(long)MAXLNUM, -nmatch_tl);
! if (subflags.do_ask)
deleted_lines(lnum, nmatch_tl);
--lnum;
line2 -= nmatch_tl; /* nr of lines decreases */
***************
*** 5717,5723 ****
/* When asking, undo is saved each time, must also set
* changed flag each time. */
! if (do_ask)
changed_bytes(lnum, 0);
else
{
--- 5735,5741 ----
/* When asking, undo is saved each time, must also set
* changed flag each time. */
! if (subflags.do_ask)
changed_bytes(lnum, 0);
else
{
***************
*** 5779,5785 ****
vim_free(sub_firstline); /* may have to free allocated copy of the line */
/* ":s/pat//n" doesn't move the cursor */
! if (do_count)
curwin->w_cursor = old_cursor;
if (sub_nsubs > start_nsubs)
--- 5797,5803 ----
vim_free(sub_firstline); /* may have to free allocated copy of the line */
/* ":s/pat//n" doesn't move the cursor */
! if (subflags.do_count)
curwin->w_cursor = old_cursor;
if (sub_nsubs > start_nsubs)
***************
*** 5791,5810 ****
if (!global_busy)
{
! if (!do_ask) /* when interactive leave cursor on the match */
{
if (endcolumn)
coladvance((colnr_T)MAXCOL);
else
beginline(BL_WHITE | BL_FIX);
}
! if (!do_sub_msg(do_count) && do_ask)
MSG("");
}
else
global_need_beginline = TRUE;
! if (do_print)
! print_line(curwin->w_cursor.lnum, do_number, do_list);
}
else if (!global_busy)
{
--- 5809,5830 ----
if (!global_busy)
{
! /* when interactive leave cursor on the match */
! if (!subflags.do_ask)
{
if (endcolumn)
coladvance((colnr_T)MAXCOL);
else
beginline(BL_WHITE | BL_FIX);
}
! if (!do_sub_msg(subflags.do_count) && subflags.do_ask)
MSG("");
}
else
global_need_beginline = TRUE;
! if (subflags.do_print)
! print_line(curwin->w_cursor.lnum,
! subflags.do_number, subflags.do_list);
}
else if (!global_busy)
{
***************
*** 5812,5823 ****
EMSG(_(e_interr));
else if (got_match) /* did find something but nothing substituted */
MSG("");
! else if (do_error) /* nothing found */
EMSG2(_(e_patnotf2), get_search_pat());
}
#ifdef FEAT_FOLDING
! if (do_ask && hasAnyFolding(curwin))
/* Cursor position may require updating */
changed_window_setting();
#endif
--- 5832,5843 ----
EMSG(_(e_interr));
else if (got_match) /* did find something but nothing substituted */
MSG("");
! else if (subflags.do_error) /* nothing found */
EMSG2(_(e_patnotf2), get_search_pat());
}
#ifdef FEAT_FOLDING
! if (subflags.do_ask && hasAnyFolding(curwin))
/* Cursor position may require updating */
changed_window_setting();
#endif
***************
*** 5825,5832 ****
vim_regfree(regmatch.regprog);
/* Restore the flag values, they can be used for ":&&". */
! do_all = save_do_all;
! do_ask = save_do_ask;
}
/*
--- 5845,5852 ----
vim_regfree(regmatch.regprog);
/* Restore the flag values, they can be used for ":&&". */
! subflags.do_all = save_do_all;
! subflags.do_ask = save_do_ask;
}
/*
*** ../vim-7.4.2218/src/testdir/test_regexp_latin.vim 2016-04-03
14:00:29.324148917 +0200
--- src/testdir/test_regexp_latin.vim 2016-08-16 20:56:37.128331249 +0200
***************
*** 30,32 ****
--- 30,41 ----
set re=2
call s:equivalence_test()
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
+
*** ../vim-7.4.2218/src/version.c 2016-08-16 19:21:05.528394945 +0200
--- src/version.c 2016-08-16 21:03:20.316658751 +0200
***************
*** 765,766 ****
--- 765,768 ----
{ /* Add new patch number below this line */
+ /**/
+ 2219,
/**/
--
How To Keep A Healthy Level Of Insanity:
12. Sing along at the opera.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.