comparison src/ex_cmds.c @ 9890:064effd222a3 v7.4.2219

commit https://github.com/vim/vim/commit/f5a39447a8ebe162ee62caa2ee502cd0e65eecaa Author: Bram Moolenaar <Bram@vim.org> Date: Tue Aug 16 21:04:41 2016 +0200 patch 7.4.2219 Problem: Recursive call to substitute gets stuck in sandbox. (Nikolai Pavlov) Solution: Handle the recursive call. (Christian Brabandt, closes https://github.com/vim/vim/issues/950) Add a test.
author Christian Brabandt <cb@256bit.org>
date Tue, 16 Aug 2016 21:15:06 +0200
parents dc2237f19ce2
children 5a667a3a3743
comparison
equal deleted inserted replaced
9889:d5f40458a686 9890:064effd222a3
4745 } 4745 }
4746 4746
4747 static char_u *old_sub = NULL; /* previous substitute pattern */ 4747 static char_u *old_sub = NULL; /* previous substitute pattern */
4748 static int global_need_beginline; /* call beginline() after ":g" */ 4748 static int global_need_beginline; /* call beginline() after ":g" */
4749 4749
4750 /*
4751 * Flags that are kept between calls to :substitute.
4752 */
4753 typedef struct {
4754 int do_all; /* do multiple substitutions per line */
4755 int do_ask; /* ask for confirmation */
4756 int do_count; /* count only */
4757 int do_error; /* if false, ignore errors */
4758 int do_print; /* print last line with subs. */
4759 int do_list; /* list last line with subs. */
4760 int do_number; /* list last line with line nr*/
4761 int do_ic; /* ignore case flag */
4762 } subflags_T;
4763
4750 /* do_sub() 4764 /* do_sub()
4751 * 4765 *
4752 * Perform a substitution from line eap->line1 to line eap->line2 using the 4766 * Perform a substitution from line eap->line1 to line eap->line2 using the
4753 * command pointed to by eap->arg which should be of the form: 4767 * command pointed to by eap->arg which should be of the form:
4754 * 4768 *
4760 do_sub(exarg_T *eap) 4774 do_sub(exarg_T *eap)
4761 { 4775 {
4762 linenr_T lnum; 4776 linenr_T lnum;
4763 long i = 0; 4777 long i = 0;
4764 regmmatch_T regmatch; 4778 regmmatch_T regmatch;
4765 static int do_all = FALSE; /* do multiple substitutions per line */ 4779 static subflags_T subflags = {FALSE, FALSE, FALSE, TRUE, FALSE,
4766 static int do_ask = FALSE; /* ask for confirmation */ 4780 FALSE, FALSE, 0};
4767 static int do_count = FALSE; /* count only */ 4781 #ifdef FEAT_EVAL
4768 static int do_error = TRUE; /* if false, ignore errors */ 4782 subflags_T subflags_save;
4769 static int do_print = FALSE; /* print last line with subs. */ 4783 #endif
4770 static int do_list = FALSE; /* list last line with subs. */
4771 static int do_number = FALSE; /* list last line with line nr*/
4772 static int do_ic = 0; /* ignore case flag */
4773 int save_do_all; /* remember user specified 'g' flag */ 4784 int save_do_all; /* remember user specified 'g' flag */
4774 int save_do_ask; /* remember user specified 'c' flag */ 4785 int save_do_ask; /* remember user specified 'c' flag */
4775 char_u *pat = NULL, *sub = NULL; /* init for GCC */ 4786 char_u *pat = NULL, *sub = NULL; /* init for GCC */
4776 int delimiter; 4787 int delimiter;
4777 int sublen; 4788 int sublen;
4955 else 4966 else
4956 { 4967 {
4957 if (!p_ed) 4968 if (!p_ed)
4958 { 4969 {
4959 if (p_gd) /* default is global on */ 4970 if (p_gd) /* default is global on */
4960 do_all = TRUE; 4971 subflags.do_all = TRUE;
4961 else 4972 else
4962 do_all = FALSE; 4973 subflags.do_all = FALSE;
4963 do_ask = FALSE; 4974 subflags.do_ask = FALSE;
4964 } 4975 }
4965 do_error = TRUE; 4976 subflags.do_error = TRUE;
4966 do_print = FALSE; 4977 subflags.do_print = FALSE;
4967 do_count = FALSE; 4978 subflags.do_count = FALSE;
4968 do_number = FALSE; 4979 subflags.do_number = FALSE;
4969 do_ic = 0; 4980 subflags.do_ic = 0;
4970 } 4981 }
4971 while (*cmd) 4982 while (*cmd)
4972 { 4983 {
4973 /* 4984 /*
4974 * Note that 'g' and 'c' are always inverted, also when p_ed is off. 4985 * Note that 'g' and 'c' are always inverted, also when p_ed is off.
4975 * 'r' is never inverted. 4986 * 'r' is never inverted.
4976 */ 4987 */
4977 if (*cmd == 'g') 4988 if (*cmd == 'g')
4978 do_all = !do_all; 4989 subflags.do_all = !subflags.do_all;
4979 else if (*cmd == 'c') 4990 else if (*cmd == 'c')
4980 do_ask = !do_ask; 4991 subflags.do_ask = !subflags.do_ask;
4981 else if (*cmd == 'n') 4992 else if (*cmd == 'n')
4982 do_count = TRUE; 4993 subflags.do_count = TRUE;
4983 else if (*cmd == 'e') 4994 else if (*cmd == 'e')
4984 do_error = !do_error; 4995 subflags.do_error = !subflags.do_error;
4985 else if (*cmd == 'r') /* use last used regexp */ 4996 else if (*cmd == 'r') /* use last used regexp */
4986 which_pat = RE_LAST; 4997 which_pat = RE_LAST;
4987 else if (*cmd == 'p') 4998 else if (*cmd == 'p')
4988 do_print = TRUE; 4999 subflags.do_print = TRUE;
4989 else if (*cmd == '#') 5000 else if (*cmd == '#')
4990 { 5001 {
4991 do_print = TRUE; 5002 subflags.do_print = TRUE;
4992 do_number = TRUE; 5003 subflags.do_number = TRUE;
4993 } 5004 }
4994 else if (*cmd == 'l') 5005 else if (*cmd == 'l')
4995 { 5006 {
4996 do_print = TRUE; 5007 subflags.do_print = TRUE;
4997 do_list = TRUE; 5008 subflags.do_list = TRUE;
4998 } 5009 }
4999 else if (*cmd == 'i') /* ignore case */ 5010 else if (*cmd == 'i') /* ignore case */
5000 do_ic = 'i'; 5011 subflags.do_ic = 'i';
5001 else if (*cmd == 'I') /* don't ignore case */ 5012 else if (*cmd == 'I') /* don't ignore case */
5002 do_ic = 'I'; 5013 subflags.do_ic = 'I';
5003 else 5014 else
5004 break; 5015 break;
5005 ++cmd; 5016 ++cmd;
5006 } 5017 }
5007 if (do_count) 5018 if (subflags.do_count)
5008 do_ask = FALSE; 5019 subflags.do_ask = FALSE;
5009 5020
5010 save_do_all = do_all; 5021 save_do_all = subflags.do_all;
5011 save_do_ask = do_ask; 5022 save_do_ask = subflags.do_ask;
5012 5023
5013 /* 5024 /*
5014 * check for a trailing count 5025 * check for a trailing count
5015 */ 5026 */
5016 cmd = skipwhite(cmd); 5027 cmd = skipwhite(cmd);
5017 if (VIM_ISDIGIT(*cmd)) 5028 if (VIM_ISDIGIT(*cmd))
5018 { 5029 {
5019 i = getdigits(&cmd); 5030 i = getdigits(&cmd);
5020 if (i <= 0 && !eap->skip && do_error) 5031 if (i <= 0 && !eap->skip && subflags.do_error)
5021 { 5032 {
5022 EMSG(_(e_zerocount)); 5033 EMSG(_(e_zerocount));
5023 return; 5034 return;
5024 } 5035 }
5025 eap->line1 = eap->line2; 5036 eap->line1 = eap->line2;
5043 } 5054 }
5044 5055
5045 if (eap->skip) /* not executing commands, only parsing */ 5056 if (eap->skip) /* not executing commands, only parsing */
5046 return; 5057 return;
5047 5058
5048 if (!do_count && !curbuf->b_p_ma) 5059 if (!subflags.do_count && !curbuf->b_p_ma)
5049 { 5060 {
5050 /* Substitution is not allowed in non-'modifiable' buffer */ 5061 /* Substitution is not allowed in non-'modifiable' buffer */
5051 EMSG(_(e_modifiable)); 5062 EMSG(_(e_modifiable));
5052 return; 5063 return;
5053 } 5064 }
5054 5065
5055 if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, &regmatch) == FAIL) 5066 if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, &regmatch) == FAIL)
5056 { 5067 {
5057 if (do_error) 5068 if (subflags.do_error)
5058 EMSG(_(e_invcmd)); 5069 EMSG(_(e_invcmd));
5059 return; 5070 return;
5060 } 5071 }
5061 5072
5062 /* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */ 5073 /* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */
5063 if (do_ic == 'i') 5074 if (subflags.do_ic == 'i')
5064 regmatch.rmm_ic = TRUE; 5075 regmatch.rmm_ic = TRUE;
5065 else if (do_ic == 'I') 5076 else if (subflags.do_ic == 'I')
5066 regmatch.rmm_ic = FALSE; 5077 regmatch.rmm_ic = FALSE;
5067 5078
5068 sub_firstline = NULL; 5079 sub_firstline = NULL;
5069 5080
5070 /* 5081 /*
5229 5240
5230 /* 5241 /*
5231 * 2. If do_count is set only increase the counter. 5242 * 2. If do_count is set only increase the counter.
5232 * If do_ask is set, ask for confirmation. 5243 * If do_ask is set, ask for confirmation.
5233 */ 5244 */
5234 if (do_count) 5245 if (subflags.do_count)
5235 { 5246 {
5236 /* For a multi-line match, put matchcol at the NUL at 5247 /* For a multi-line match, put matchcol at the NUL at
5237 * the end of the line and set nmatch to one, so that 5248 * the end of the line and set nmatch to one, so that
5238 * we continue looking for a match on the next line. 5249 * we continue looking for a match on the next line.
5239 * Avoids that ":s/\nB\@=//gc" get stuck. */ 5250 * Avoids that ":s/\nB\@=//gc" get stuck. */
5251 if (!(sub[0] == '\\' && sub[1] == '=')) 5262 if (!(sub[0] == '\\' && sub[1] == '='))
5252 #endif 5263 #endif
5253 goto skip; 5264 goto skip;
5254 } 5265 }
5255 5266
5256 if (do_ask) 5267 if (subflags.do_ask)
5257 { 5268 {
5258 int typed = 0; 5269 int typed = 0;
5259 5270
5260 /* change State to CONFIRM, so that the mouse works 5271 /* change State to CONFIRM, so that the mouse works
5261 * properly */ 5272 * properly */
5272 ++no_u_sync; 5283 ++no_u_sync;
5273 5284
5274 /* 5285 /*
5275 * Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed. 5286 * Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
5276 */ 5287 */
5277 while (do_ask) 5288 while (subflags.do_ask)
5278 { 5289 {
5279 if (exmode_active) 5290 if (exmode_active)
5280 { 5291 {
5281 char_u *resp; 5292 char_u *resp;
5282 colnr_T sc, ec; 5293 colnr_T sc, ec;
5283 5294
5284 print_line_no_prefix(lnum, do_number, do_list); 5295 print_line_no_prefix(lnum,
5296 subflags.do_number, subflags.do_list);
5285 5297
5286 getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL); 5298 getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL);
5287 curwin->w_cursor.col = regmatch.endpos[0].col - 1; 5299 curwin->w_cursor.col = regmatch.endpos[0].col - 1;
5288 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec); 5300 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
5289 if (do_number || curwin->w_p_nu) 5301 if (subflags.do_number || curwin->w_p_nu)
5290 { 5302 {
5291 int numw = number_width(curwin) + 1; 5303 int numw = number_width(curwin) + 1;
5292 sc += numw; 5304 sc += numw;
5293 ec += numw; 5305 ec += numw;
5294 } 5306 }
5418 if (typed == 'y') 5430 if (typed == 'y')
5419 break; 5431 break;
5420 if (typed == 'l') 5432 if (typed == 'l')
5421 { 5433 {
5422 /* last: replace and then stop */ 5434 /* last: replace and then stop */
5423 do_all = FALSE; 5435 subflags.do_all = FALSE;
5424 line2 = lnum; 5436 line2 = lnum;
5425 break; 5437 break;
5426 } 5438 }
5427 if (typed == 'a') 5439 if (typed == 'a')
5428 { 5440 {
5429 do_ask = FALSE; 5441 subflags.do_ask = FALSE;
5430 break; 5442 break;
5431 } 5443 }
5432 #ifdef FEAT_INS_EXPAND 5444 #ifdef FEAT_INS_EXPAND
5433 if (typed == Ctrl_E) 5445 if (typed == Ctrl_E)
5434 scrollup_clamp(); 5446 scrollup_clamp();
5467 5479
5468 /* 5480 /*
5469 * 3. substitute the string. 5481 * 3. substitute the string.
5470 */ 5482 */
5471 #ifdef FEAT_EVAL 5483 #ifdef FEAT_EVAL
5472 if (do_count) 5484 if (subflags.do_count)
5473 { 5485 {
5474 /* prevent accidentally changing the buffer by a function */ 5486 /* prevent accidentally changing the buffer by a function */
5475 save_ma = curbuf->b_p_ma; 5487 save_ma = curbuf->b_p_ma;
5476 curbuf->b_p_ma = FALSE; 5488 curbuf->b_p_ma = FALSE;
5477 sandbox++; 5489 sandbox++;
5478 } 5490 }
5491 /* Save flags for recursion. They can change for e.g.
5492 * :s/^/\=execute("s#^##gn") */
5493 subflags_save = subflags;
5479 #endif 5494 #endif
5480 /* get length of substitution part */ 5495 /* get length of substitution part */
5481 sublen = vim_regsub_multi(&regmatch, 5496 sublen = vim_regsub_multi(&regmatch,
5482 sub_firstlnum - regmatch.startpos[0].lnum, 5497 sub_firstlnum - regmatch.startpos[0].lnum,
5483 sub, sub_firstline, FALSE, p_magic, TRUE); 5498 sub, sub_firstline, FALSE, p_magic, TRUE);
5484 #ifdef FEAT_EVAL 5499 #ifdef FEAT_EVAL
5485 if (do_count) 5500 /* Don't keep flags set by a recursive call. */
5501 subflags = subflags_save;
5502 if (subflags.do_count)
5486 { 5503 {
5487 curbuf->b_p_ma = save_ma; 5504 curbuf->b_p_ma = save_ma;
5488 sandbox--; 5505 if (sandbox > 0)
5506 sandbox--;
5489 goto skip; 5507 goto skip;
5490 } 5508 }
5491 #endif 5509 #endif
5492 5510
5493 /* When the match included the "$" of the last line it may 5511 /* When the match included the "$" of the last line it may
5576 sub_firstline = vim_strsave(ml_get(sub_firstlnum)); 5594 sub_firstline = vim_strsave(ml_get(sub_firstlnum));
5577 /* When going beyond the last line, stop substituting. */ 5595 /* When going beyond the last line, stop substituting. */
5578 if (sub_firstlnum <= line2) 5596 if (sub_firstlnum <= line2)
5579 do_again = TRUE; 5597 do_again = TRUE;
5580 else 5598 else
5581 do_all = FALSE; 5599 subflags.do_all = FALSE;
5582 } 5600 }
5583 5601
5584 /* Remember next character to be copied. */ 5602 /* Remember next character to be copied. */
5585 copycol = regmatch.endpos[0].col; 5603 copycol = regmatch.endpos[0].col;
5586 5604
5611 { 5629 {
5612 *p1 = NUL; /* truncate up to the CR */ 5630 *p1 = NUL; /* truncate up to the CR */
5613 ml_append(lnum - 1, new_start, 5631 ml_append(lnum - 1, new_start,
5614 (colnr_T)(p1 - new_start + 1), FALSE); 5632 (colnr_T)(p1 - new_start + 1), FALSE);
5615 mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L); 5633 mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
5616 if (do_ask) 5634 if (subflags.do_ask)
5617 appended_lines(lnum - 1, 1L); 5635 appended_lines(lnum - 1, 1L);
5618 else 5636 else
5619 { 5637 {
5620 if (first_line == 0) 5638 if (first_line == 0)
5621 first_line = lnum; 5639 first_line = lnum;
5652 * break. */ 5670 * break. */
5653 lastone = (skip_match 5671 lastone = (skip_match
5654 || got_int 5672 || got_int
5655 || got_quit 5673 || got_quit
5656 || lnum > line2 5674 || lnum > line2
5657 || !(do_all || do_again) 5675 || !(subflags.do_all || do_again)
5658 || (sub_firstline[matchcol] == NUL && nmatch <= 1 5676 || (sub_firstline[matchcol] == NUL && nmatch <= 1
5659 && !re_multiline(regmatch.regprog))); 5677 && !re_multiline(regmatch.regprog)));
5660 nmatch = -1; 5678 nmatch = -1;
5661 5679
5662 /* 5680 /*
5706 break; 5724 break;
5707 for (i = 0; i < nmatch_tl; ++i) 5725 for (i = 0; i < nmatch_tl; ++i)
5708 ml_delete(lnum, (int)FALSE); 5726 ml_delete(lnum, (int)FALSE);
5709 mark_adjust(lnum, lnum + nmatch_tl - 1, 5727 mark_adjust(lnum, lnum + nmatch_tl - 1,
5710 (long)MAXLNUM, -nmatch_tl); 5728 (long)MAXLNUM, -nmatch_tl);
5711 if (do_ask) 5729 if (subflags.do_ask)
5712 deleted_lines(lnum, nmatch_tl); 5730 deleted_lines(lnum, nmatch_tl);
5713 --lnum; 5731 --lnum;
5714 line2 -= nmatch_tl; /* nr of lines decreases */ 5732 line2 -= nmatch_tl; /* nr of lines decreases */
5715 nmatch_tl = 0; 5733 nmatch_tl = 0;
5716 } 5734 }
5717 5735
5718 /* When asking, undo is saved each time, must also set 5736 /* When asking, undo is saved each time, must also set
5719 * changed flag each time. */ 5737 * changed flag each time. */
5720 if (do_ask) 5738 if (subflags.do_ask)
5721 changed_bytes(lnum, 0); 5739 changed_bytes(lnum, 0);
5722 else 5740 else
5723 { 5741 {
5724 if (first_line == 0) 5742 if (first_line == 0)
5725 first_line = lnum; 5743 first_line = lnum;
5777 5795
5778 outofmem: 5796 outofmem:
5779 vim_free(sub_firstline); /* may have to free allocated copy of the line */ 5797 vim_free(sub_firstline); /* may have to free allocated copy of the line */
5780 5798
5781 /* ":s/pat//n" doesn't move the cursor */ 5799 /* ":s/pat//n" doesn't move the cursor */
5782 if (do_count) 5800 if (subflags.do_count)
5783 curwin->w_cursor = old_cursor; 5801 curwin->w_cursor = old_cursor;
5784 5802
5785 if (sub_nsubs > start_nsubs) 5803 if (sub_nsubs > start_nsubs)
5786 { 5804 {
5787 /* Set the '[ and '] marks. */ 5805 /* Set the '[ and '] marks. */
5789 curbuf->b_op_end.lnum = line2; 5807 curbuf->b_op_end.lnum = line2;
5790 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 5808 curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
5791 5809
5792 if (!global_busy) 5810 if (!global_busy)
5793 { 5811 {
5794 if (!do_ask) /* when interactive leave cursor on the match */ 5812 /* when interactive leave cursor on the match */
5813 if (!subflags.do_ask)
5795 { 5814 {
5796 if (endcolumn) 5815 if (endcolumn)
5797 coladvance((colnr_T)MAXCOL); 5816 coladvance((colnr_T)MAXCOL);
5798 else 5817 else
5799 beginline(BL_WHITE | BL_FIX); 5818 beginline(BL_WHITE | BL_FIX);
5800 } 5819 }
5801 if (!do_sub_msg(do_count) && do_ask) 5820 if (!do_sub_msg(subflags.do_count) && subflags.do_ask)
5802 MSG(""); 5821 MSG("");
5803 } 5822 }
5804 else 5823 else
5805 global_need_beginline = TRUE; 5824 global_need_beginline = TRUE;
5806 if (do_print) 5825 if (subflags.do_print)
5807 print_line(curwin->w_cursor.lnum, do_number, do_list); 5826 print_line(curwin->w_cursor.lnum,
5827 subflags.do_number, subflags.do_list);
5808 } 5828 }
5809 else if (!global_busy) 5829 else if (!global_busy)
5810 { 5830 {
5811 if (got_int) /* interrupted */ 5831 if (got_int) /* interrupted */
5812 EMSG(_(e_interr)); 5832 EMSG(_(e_interr));
5813 else if (got_match) /* did find something but nothing substituted */ 5833 else if (got_match) /* did find something but nothing substituted */
5814 MSG(""); 5834 MSG("");
5815 else if (do_error) /* nothing found */ 5835 else if (subflags.do_error) /* nothing found */
5816 EMSG2(_(e_patnotf2), get_search_pat()); 5836 EMSG2(_(e_patnotf2), get_search_pat());
5817 } 5837 }
5818 5838
5819 #ifdef FEAT_FOLDING 5839 #ifdef FEAT_FOLDING
5820 if (do_ask && hasAnyFolding(curwin)) 5840 if (subflags.do_ask && hasAnyFolding(curwin))
5821 /* Cursor position may require updating */ 5841 /* Cursor position may require updating */
5822 changed_window_setting(); 5842 changed_window_setting();
5823 #endif 5843 #endif
5824 5844
5825 vim_regfree(regmatch.regprog); 5845 vim_regfree(regmatch.regprog);
5826 5846
5827 /* Restore the flag values, they can be used for ":&&". */ 5847 /* Restore the flag values, they can be used for ":&&". */
5828 do_all = save_do_all; 5848 subflags.do_all = save_do_all;
5829 do_ask = save_do_ask; 5849 subflags.do_ask = save_do_ask;
5830 } 5850 }
5831 5851
5832 /* 5852 /*
5833 * Give message for number of substitutions. 5853 * Give message for number of substitutions.
5834 * Can also be used after a ":global" command. 5854 * Can also be used after a ":global" command.