int start_nsubs;
#ifdef FEAT_EVAL
int save_ma = 0;
+ int save_sandbox = 0;
#endif
cmd = eap->arg;
*/
#ifdef FEAT_EVAL
save_ma = curbuf->b_p_ma;
+ save_sandbox = sandbox;
if (subflags.do_count)
{
// prevent accidentally changing the buffer by a function
// Disallow changing text or switching window in an expression.
++textlock;
#endif
- // get length of substitution part
+ // Get length of substitution part, including the NUL.
+ // When it fails sublen is zero.
sublen = vim_regsub_multi(®match,
sub_firstlnum - regmatch.startpos[0].lnum,
sub, sub_firstline, 0,
// the replacement.
// Don't keep flags set by a recursive call.
subflags = subflags_save;
- if (aborting() || subflags.do_count)
+ if (sublen == 0 || aborting() || subflags.do_count)
{
curbuf->b_p_ma = save_ma;
- if (sandbox > 0)
- sandbox--;
+ sandbox = save_sandbox;
goto skip;
}
#endif
return result;
}
+#if defined(FEAT_EVAL) || defined(PROTO)
+// When nesting more than a couple levels it's probably a mistake.
+# define MAX_REGSUB_NESTING 4
+static char_u *eval_result[MAX_REGSUB_NESTING] = {NULL, NULL, NULL, NULL};
+
+# if defined(EXITFREE) || defined(PROTO)
+ void
+free_resub_eval_result(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_REGSUB_NESTING; ++i)
+ VIM_CLEAR(eval_result[i]);
+}
+# endif
+#endif
+
static int
vim_regsub_both(
char_u *source,
linenr_T clnum = 0; // init for GCC
int len = 0; // init for GCC
#ifdef FEAT_EVAL
- static char_u *eval_result = NULL;
+ static int nesting = 0;
+ int nested;
#endif
int copy = flags & REGSUB_COPY;
}
if (prog_magic_wrong())
return 0;
+#ifdef FEAT_EVAL
+ if (nesting == MAX_REGSUB_NESTING)
+ {
+ emsg(_(e_substitute_nesting_too_deep));
+ return 0;
+ }
+ nested = nesting;
+#endif
src = source;
dst = dest;
// "flags & REGSUB_COPY" != 0.
if (copy)
{
- if (eval_result != NULL)
+ if (eval_result[nested] != NULL)
{
- STRCPY(dest, eval_result);
- dst += STRLEN(eval_result);
- VIM_CLEAR(eval_result);
+ STRCPY(dest, eval_result[nested]);
+ dst += STRLEN(eval_result[nested]);
+ VIM_CLEAR(eval_result[nested]);
}
}
else
int prev_can_f_submatch = can_f_submatch;
regsubmatch_T rsm_save;
- VIM_CLEAR(eval_result);
+ VIM_CLEAR(eval_result[nested]);
// The expression may contain substitute(), which calls us
// recursively. Make sure submatch() gets the text from the first
rsm.sm_maxline = rex.reg_maxline;
rsm.sm_line_lbr = rex.reg_line_lbr;
+ // Although unlikely, it is possible that the expression invokes a
+ // substitute command (it might fail, but still). Therefore keep
+ // an array if eval results.
+ ++nesting;
+
if (expr != NULL)
{
typval_T argv[2];
if (rettv.v_type == VAR_UNKNOWN)
// something failed, no need to report another error
- eval_result = NULL;
+ eval_result[nested] = NULL;
else
{
- eval_result = tv_get_string_buf_chk(&rettv, buf);
- if (eval_result != NULL)
- eval_result = vim_strsave(eval_result);
+ eval_result[nested] = tv_get_string_buf_chk(&rettv, buf);
+ if (eval_result[nested] != NULL)
+ eval_result[nested] = vim_strsave(eval_result[nested]);
}
clear_tv(&rettv);
}
else if (substitute_instr != NULL)
// Execute instructions from ISN_SUBSTITUTE.
- eval_result = exe_substitute_instr();
+ eval_result[nested] = exe_substitute_instr();
else
- eval_result = eval_to_string(source + 2, TRUE);
+ eval_result[nested] = eval_to_string(source + 2, TRUE);
+ --nesting;
- if (eval_result != NULL)
+ if (eval_result[nested] != NULL)
{
int had_backslash = FALSE;
- for (s = eval_result; *s != NUL; MB_PTR_ADV(s))
+ for (s = eval_result[nested]; *s != NUL; MB_PTR_ADV(s))
{
// Change NL to CR, so that it becomes a line break,
// unless called from vim_regexec_nl().
if (had_backslash && (flags & REGSUB_BACKSLASH))
{
// Backslashes will be consumed, need to double them.
- s = vim_strsave_escaped(eval_result, (char_u *)"\\");
+ s = vim_strsave_escaped(eval_result[nested], (char_u *)"\\");
if (s != NULL)
{
- vim_free(eval_result);
- eval_result = s;
+ vim_free(eval_result[nested]);
+ eval_result[nested] = s;
}
}
- dst += STRLEN(eval_result);
+ dst += STRLEN(eval_result[nested]);
}
can_f_submatch = prev_can_f_submatch;