summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-12-29 23:04:25 +0100
committerBram Moolenaar <Bram@vim.org>2019-12-29 23:04:25 +0100
commit1a47ae32cdc19b0fd5a82e19fe5fddf45db1a506 (patch)
tree8f5dc27f3eeea927ad3ca8de42fe0df06a041dd5
parent257a396879ff67a0482841a39237f30a8e1e27c5 (diff)
patch 8.2.0056: execution stack is incomplete and inefficientv8.2.0056
Problem: Execution stack is incomplete and inefficient. Solution: Introduce a proper execution stack and use it instead of sourcing_name/sourcing_lnum. Create a string only when used.
-rw-r--r--src/autocmd.c33
-rw-r--r--src/buffer.c14
-rw-r--r--src/debugger.c36
-rw-r--r--src/ex_docmd.c48
-rw-r--r--src/ex_eval.c7
-rw-r--r--src/globals.h11
-rw-r--r--src/highlight.c6
-rw-r--r--src/kword_test.c1
-rw-r--r--src/main.c20
-rw-r--r--src/map.c11
-rw-r--r--src/message.c39
-rw-r--r--src/option.c2
-rw-r--r--src/profiler.c12
-rw-r--r--src/proto/scriptfile.pro5
-rw-r--r--src/scriptfile.c151
-rw-r--r--src/spellfile.c8
-rw-r--r--src/structs.h34
-rw-r--r--src/term.c2
-rw-r--r--src/testdir/test_debugger.vim2
-rw-r--r--src/testing.c16
-rw-r--r--src/usercmd.c4
-rw-r--r--src/userfunc.c161
-rw-r--r--src/version.c2
23 files changed, 385 insertions, 240 deletions
diff --git a/src/autocmd.c b/src/autocmd.c
index de24dd219c..983a155c60 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -218,7 +218,7 @@ static AutoPat *last_autopat[NUM_EVENTS] =
/*
* struct used to keep status while executing autocommands for an event.
*/
-typedef struct AutoPatCmd
+struct AutoPatCmd_S
{
AutoPat *curpat; // next AutoPat to examine
AutoCmd *nextcmd; // next AutoCmd to execute
@@ -229,8 +229,8 @@ typedef struct AutoPatCmd
event_T event; // current event
int arg_bufnr; // Initially equal to <abuf>, set to zero when
// buf is deleted.
- struct AutoPatCmd *next; // chain of active apc-s for auto-invalidation
-} AutoPatCmd;
+ AutoPatCmd *next; // chain of active apc-s for auto-invalidation
+};
static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands
@@ -1242,7 +1242,7 @@ do_autocmd_event(
ac->cmd = vim_strsave(cmd);
#ifdef FEAT_EVAL
ac->script_ctx = current_sctx;
- ac->script_ctx.sc_lnum += sourcing_lnum;
+ ac->script_ctx.sc_lnum += SOURCING_LNUM;
#endif
if (ac->cmd == NULL)
{
@@ -1805,8 +1805,6 @@ apply_autocmds_group(
int save_changed;
buf_T *old_curbuf;
int retval = FALSE;
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
char_u *save_autocmd_fname;
int save_autocmd_fname_full;
int save_autocmd_bufnr;
@@ -2020,10 +2018,9 @@ apply_autocmds_group(
// Don't redraw while doing autocommands.
++RedrawingDisabled;
- save_sourcing_name = sourcing_name;
- sourcing_name = NULL; // don't free this one
- save_sourcing_lnum = sourcing_lnum;
- sourcing_lnum = 0; // no line number here
+
+ // name and lnum are filled in later
+ estack_push(ETYPE_AUCMD, NULL, 0);
#ifdef FEAT_EVAL
save_current_sctx = current_sctx;
@@ -2126,9 +2123,8 @@ apply_autocmds_group(
autocmd_busy = save_autocmd_busy;
filechangeshell_busy = FALSE;
autocmd_nested = save_autocmd_nested;
- vim_free(sourcing_name);
- sourcing_name = save_sourcing_name;
- sourcing_lnum = save_sourcing_lnum;
+ vim_free(SOURCING_NAME);
+ estack_pop();
vim_free(autocmd_fname);
autocmd_fname = save_autocmd_fname;
autocmd_fname_full = save_autocmd_fname_full;
@@ -2256,8 +2252,9 @@ auto_next_pat(
AutoCmd *cp;
char_u *name;
char *s;
+ char_u **sourcing_namep = &SOURCING_NAME;
- VIM_CLEAR(sourcing_name);
+ VIM_CLEAR(*sourcing_namep);
for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
{
@@ -2277,16 +2274,16 @@ auto_next_pat(
{
name = event_nr2name(apc->event);
s = _("%s Autocommands for \"%s\"");
- sourcing_name = alloc(STRLEN(s)
+ *sourcing_namep = alloc(STRLEN(s)
+ STRLEN(name) + ap->patlen + 1);
- if (sourcing_name != NULL)
+ if (*sourcing_namep != NULL)
{
- sprintf((char *)sourcing_name, s,
+ sprintf((char *)*sourcing_namep, s,
(char *)name, (char *)ap->pat);
if (p_verbose >= 8)
{
verbose_enter();
- smsg(_("Executing %s"), sourcing_name);
+ smsg(_("Executing %s"), *sourcing_namep);
verbose_leave();
}
}
diff --git a/src/buffer.c b/src/buffer.c
index 2502dee627..dd3593fb52 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5279,8 +5279,6 @@ chk_modeline(
int vers;
int end;
int retval = OK;
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
#ifdef FEAT_EVAL
sctx_T save_current_sctx;
#endif
@@ -5325,10 +5323,8 @@ chk_modeline(
if (linecopy == NULL)
return FAIL;
- save_sourcing_lnum = sourcing_lnum;
- save_sourcing_name = sourcing_name;
- sourcing_lnum = lnum; // prepare for emsg()
- sourcing_name = (char_u *)"modelines";
+ // prepare for emsg()
+ estack_push(ETYPE_MODELINE, (char_u *)"modelines", lnum);
end = FALSE;
while (end == FALSE)
@@ -5371,7 +5367,7 @@ chk_modeline(
save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_MODELINE;
current_sctx.sc_seq = 0;
- current_sctx.sc_lnum = 0;
+ current_sctx.sc_lnum = lnum;
current_sctx.sc_version = 1;
#endif
// Make sure no risky things are executed as a side effect.
@@ -5389,9 +5385,7 @@ chk_modeline(
s = e + 1; // advance to next part
}
- sourcing_lnum = save_sourcing_lnum;
- sourcing_name = save_sourcing_name;
-
+ estack_pop();
vim_free(linecopy);
}
return retval;
diff --git a/src/debugger.c b/src/debugger.c
index 0a25e0b884..5dfc54e82f 100644
--- a/src/debugger.c
+++ b/src/debugger.c
@@ -51,6 +51,7 @@ do_debug(char_u *cmd)
int n;
char_u *cmdline = NULL;
char_u *p;
+ char_u *sname;
char *tail = NULL;
static int last_cmd = 0;
#define CMD_CONT 1
@@ -104,10 +105,12 @@ do_debug(char_u *cmd)
vim_free(debug_newval);
debug_newval = NULL;
}
- if (sourcing_name != NULL)
- msg((char *)sourcing_name);
- if (sourcing_lnum != 0)
- smsg(_("line %ld: %s"), (long)sourcing_lnum, cmd);
+ sname = estack_sfile();
+ if (sname != NULL)
+ msg((char *)sname);
+ vim_free(sname);
+ if (SOURCING_LNUM != 0)
+ smsg(_("line %ld: %s"), SOURCING_LNUM, cmd);
else
smsg(_("cmd: %s"), cmd);
@@ -300,14 +303,14 @@ do_debug(char_u *cmd)
}
static int
-get_maxbacktrace_level(void)
+get_maxbacktrace_level(char_u *sname)
{
char *p, *q;
int maxbacktrace = 0;
- if (sourcing_name != NULL)
+ if (sname != NULL)
{
- p = (char *)sourcing_name;
+ p = (char *)sname;
while ((q = strstr(p, "..")) != NULL)
{
p = q + 2;
@@ -341,27 +344,32 @@ do_checkbacktracelevel(void)
}
else
{
- int max = get_maxbacktrace_level();
+ char_u *sname = estack_sfile();
+ int max = get_maxbacktrace_level(sname);
if (debug_backtrace_level > max)
{
debug_backtrace_level = max;
smsg(_("frame at highest level: %d"), max);
}
+ vim_free(sname);
}
}
static void
do_showbacktrace(char_u *cmd)
{
+ char_u *sname;
char *cur;
char *next;
int i = 0;
- int max = get_maxbacktrace_level();
+ int max;
- if (sourcing_name != NULL)
+ sname = estack_sfile();
+ max = get_maxbacktrace_level(sname);
+ if (sname != NULL)
{
- cur = (char *)sourcing_name;
+ cur = (char *)sname;
while (!got_int)
{
next = strstr(cur, "..");
@@ -377,9 +385,11 @@ do_showbacktrace(char_u *cmd)
*next = '.';
cur = next + 2;
}
+ vim_free(sname);
}
- if (sourcing_lnum != 0)
- smsg(_("line %ld: %s"), (long)sourcing_lnum, cmd);
+
+ if (SOURCING_LNUM != 0)
+ smsg(_("line %ld: %s"), (long)SOURCING_LNUM, cmd);
else
smsg(_("cmd: %s"), cmd);
}
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index ba51640664..a3442edbe7 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -703,7 +703,7 @@ do_cmdline(
}
else if (getline_equal(fgetline, cookie, getsourceline))
{
- fname = sourcing_name;
+ fname = SOURCING_NAME;
breakpoint = source_breakpoint(real_cookie);
dbg_tick = source_dbg_tick(real_cookie);
}
@@ -819,22 +819,22 @@ do_cmdline(
{
*breakpoint = dbg_find_breakpoint(
getline_equal(fgetline, cookie, getsourceline),
- fname, sourcing_lnum);
+ fname, SOURCING_LNUM);
*dbg_tick = debug_tick;
}
next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line;
- sourcing_lnum = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum;
+ SOURCING_LNUM = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum;
// Did we encounter a breakpoint?
if (breakpoint != NULL && *breakpoint != 0
- && *breakpoint <= sourcing_lnum)
+ && *breakpoint <= SOURCING_LNUM)
{
- dbg_breakpoint(fname, sourcing_lnum);
+ dbg_breakpoint(fname, SOURCING_LNUM);
// Find next breakpoint.
*breakpoint = dbg_find_breakpoint(
getline_equal(fgetline, cookie, getsourceline),
- fname, sourcing_lnum);
+ fname, SOURCING_LNUM);
*dbg_tick = debug_tick;
}
# ifdef FEAT_PROFILE
@@ -963,8 +963,8 @@ do_cmdline(
}
}
- if (p_verbose >= 15 && sourcing_name != NULL)
- msg_verbose_cmd(sourcing_lnum, cmdline_copy);
+ if (p_verbose >= 15 && SOURCING_NAME != NULL)
+ msg_verbose_cmd(SOURCING_LNUM, cmdline_copy);
/*
* 2. Execute one '|' separated command.
@@ -1081,7 +1081,7 @@ do_cmdline(
// Check for the next breakpoint after a watchexpression
if (breakpoint != NULL && has_watchexpr())
{
- *breakpoint = dbg_find_breakpoint(FALSE, fname, sourcing_lnum);
+ *breakpoint = dbg_find_breakpoint(FALSE, fname, SOURCING_LNUM);
*dbg_tick = debug_tick;
}
@@ -1092,7 +1092,7 @@ do_cmdline(
{
if (lines_ga.ga_len > 0)
{
- sourcing_lnum =
+ SOURCING_LNUM =
((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum;
free_cmdlines(&lines_ga);
}
@@ -1234,8 +1234,6 @@ do_cmdline(
if (did_throw)
{
void *p = NULL;
- char_u *saved_sourcing_name;
- int saved_sourcing_lnum;
struct msglist *messages = NULL, *next;
/*
@@ -1260,10 +1258,8 @@ do_cmdline(
break;
}
- saved_sourcing_name = sourcing_name;
- saved_sourcing_lnum = sourcing_lnum;
- sourcing_name = current_exception->throw_name;
- sourcing_lnum = current_exception->throw_lnum;
+ estack_push(ETYPE_EXCEPT, current_exception->throw_name,
+ current_exception->throw_lnum);
current_exception->throw_name = NULL;
discard_current_exception(); // uses IObuff if 'verbose'
@@ -1287,9 +1283,8 @@ do_cmdline(
emsg(p);
vim_free(p);
}
- vim_free(sourcing_name);
- sourcing_name = saved_sourcing_name;
- sourcing_lnum = saved_sourcing_lnum;
+ vim_free(SOURCING_NAME);
+ estack_pop();
}
/*
@@ -1428,7 +1423,7 @@ get_loop_line(int c, void *cookie, int indent, int do_concat)
KeyTyped = FALSE;
++cp->current_line;
wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line;
- sourcing_lnum = wp->lnum;
+ SOURCING_LNUM = wp->lnum;
return vim_strsave(wp->line);
}
@@ -1441,7 +1436,7 @@ store_loop_line(garray_T *gap, char_u *line)
if (ga_grow(gap, 1) == FAIL)
return FAIL;
((wcmd_T *)(gap->ga_data))[gap->ga_len].line = vim_strsave(line);
- ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = sourcing_lnum;
+ ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = SOURCING_LNUM;
++gap->ga_len;
return OK;
}
@@ -8171,33 +8166,34 @@ eval_vars(
break;
case SPEC_SFILE: // file name for ":so" command
- result = sourcing_name;
+ result = estack_sfile();
if (result == NULL)
{
*errormsg = _("E498: no :source file name to substitute for \"<sfile>\"");
return NULL;
}
+ resultbuf = result; // remember allocated string
break;
case SPEC_SLNUM: // line in file for ":so" command
- if (sourcing_name == NULL || sourcing_lnum == 0)
+ if (SOURCING_NAME == NULL || SOURCING_LNUM == 0)
{
*errormsg = _("E842: no line number to use for \"<slnum>\"");
return NULL;
}
- sprintf((char *)strbuf, "%ld", (long)sourcing_lnum);
+ sprintf((char *)strbuf, "%ld", SOURCING_LNUM);
result = strbuf;
break;
#ifdef FEAT_EVAL
case SPEC_SFLNUM: // line in script file
- if (current_sctx.sc_lnum + sourcing_lnum == 0)
+ if (current_sctx.sc_lnum + SOURCING_LNUM == 0)
{
*errormsg = _("E961: no line number to use for \"<sflnum>\"");
return NULL;
}
sprintf((char *)strbuf, "%ld",
- (long)(current_sctx.sc_lnum + sourcing_lnum));
+ (long)(current_sctx.sc_lnum + SOURCING_LNUM));
result = strbuf;
break;
#endif
diff --git a/src/ex_eval.c b/src/ex_eval.c
index 4d76572dcc..382e99e0d2 100644
--- a/src/ex_eval.c
+++ b/src/ex_eval.c
@@ -534,15 +534,16 @@ throw_exception(void *value, except_type_T type, char_u *cmdname)
goto nomem;
excp->type = type;
- excp->throw_name = vim_strsave(sourcing_name == NULL
- ? (char_u *)"" : sourcing_name);
+ excp->throw_name = estack_sfile();
+ if (excp->throw_name == NULL)
+ excp->throw_name = vim_strsave((char_u *)"");
if (excp->throw_name == NULL)
{
if (should_free)
vim_free(excp->value);
goto nomem;
}
- excp->throw_lnum = sourcing_lnum;
+ excp->throw_lnum = SOURCING_LNUM;
if (p_verbose >= 13 || debug_break_level > 0)
{
diff --git a/src/globals.h b/src/globals.h
index 87f7b0be54..acdce70968 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -266,8 +266,15 @@ EXTERN int lines_left INIT(= -1); // lines left for listing
EXTERN int msg_no_more INIT(= FALSE); // don't use more prompt, truncate
// messages
-EXTERN char_u *sourcing_name INIT( = NULL);// name of error message source
-EXTERN linenr_T sourcing_lnum INIT(= 0); // line number of the source file
+/*
+ * Stack of execution contexts. Each entry is an estack_T.
+ * Current context is at ga_len - 1.
+ */
+EXTERN garray_T exestack INIT(= {0 COMMA 0 COMMA sizeof(estack_T) COMMA 50 COMMA NULL});
+// name of error message source
+#define SOURCING_NAME (((estack_T *)exestack.ga_data)[exestack.ga_len - 1].es_name)
+// line number in the message source or zero
+#define SOURCING_LNUM (((estack_T *)exestack.ga_data)[exestack.ga_len - 1].es_lnum)
#ifdef FEAT_EVAL
EXTERN int ex_nesting_level INIT(= 0); // nesting level
diff --git a/src/highlight.c b/src/highlight.c
index 40dda6452e..19aafffe5a 100644
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -748,7 +748,7 @@ do_highlight(
if (to_id > 0 && !forceit && !init
&& hl_has_settings(from_id - 1, dodefault))
{
- if (sourcing_name == NULL && !dodefault)
+ if (SOURCING_NAME == NULL && !dodefault)
emsg(_("E414: group has settings, highlight link ignored"));
}
else if (HL_TABLE()[from_id - 1].sg_link != to_id
@@ -763,7 +763,7 @@ do_highlight(
HL_TABLE()[from_id - 1].sg_link = to_id;
#ifdef FEAT_EVAL
HL_TABLE()[from_id - 1].sg_script_ctx = current_sctx;
- HL_TABLE()[from_id - 1].sg_script_ctx.sc_lnum += sourcing_lnum;
+ HL_TABLE()[from_id - 1].sg_script_ctx.sc_lnum += SOURCING_LNUM;
#endif
HL_TABLE()[from_id - 1].sg_cleared = FALSE;
redraw_all_later(SOME_VALID);
@@ -1518,7 +1518,7 @@ do_highlight(
set_hl_attr(idx);
#ifdef FEAT_EVAL
HL_TABLE()[idx].sg_script_ctx = current_sctx;
- HL_TABLE()[idx].sg_script_ctx.sc_lnum += sourcing_lnum;
+ HL_TABLE()[idx].sg_script_ctx.sc_lnum += SOURCING_LNUM;
#endif
}
diff --git a/src/kword_test.c b/src/kword_test.c
index c02ba4312c..92ea052bb8 100644
--- a/src/kword_test.c
+++ b/src/kword_test.c
@@ -76,6 +76,7 @@ test_isword_funcs_utf8(void)
int
main(void)
{
+ estack_init();
test_isword_funcs_utf8();
return 0;
}
diff --git a/src/main.c b/src/main.c
index eec02ea85b..51b8970b9b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -911,6 +911,7 @@ vim_main2(void)
void
common_init(mparm_T *paramp)
{
+ estack_init();
cmdline_init();
(void)mb_init(); // init mb_bytelen_tab[] to ones
@@ -3089,13 +3090,13 @@ exe_pre_commands(mparm_T *parmp)
if (cnt > 0)
{
curwin->w_cursor.lnum = 0; // just in case..
- sourcing_name = (char_u *)_("pre-vimrc command line");
+ estack_push(ETYPE_ARGS, (char_u *)_("pre-vimrc command line"), 0);
# ifdef FEAT_EVAL
current_sctx.sc_sid = SID_CMDARG;
# endif
for (i = 0; i < cnt; ++i)
do_cmdline_cmd(cmds[i]);
- sourcing_name = NULL;
+ estack_pop();
# ifdef FEAT_EVAL
current_sctx.sc_sid = 0;
# endif
@@ -3119,7 +3120,7 @@ exe_commands(mparm_T *parmp)
msg_scroll = TRUE;
if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1)
curwin->w_cursor.lnum = 0;
- sourcing_name = (char_u *)"command line";
+ estack_push(ETYPE_ARGS, (char_u *)"command line", 0);
#ifdef FEAT_EVAL
current_sctx.sc_sid = SID_CARG;
current_sctx.sc_seq = 0;
@@ -3130,7 +3131,7 @@ exe_commands(mparm_T *parmp)
if (parmp->cmds_tofree[i])
vim_free(parmp->commands[i]);
}
- sourcing_name = NULL;
+ estack_pop();
#ifdef FEAT_EVAL
current_sctx.sc_sid = 0;
#endif
@@ -3336,8 +3337,6 @@ process_env(
int is_viminit) // when TRUE, called for VIMINIT
{
char_u *initstr;
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
#ifdef FEAT_EVAL
sctx_T save_current_sctx;
#endif
@@ -3346,10 +3345,7 @@ process_env(
{
if (is_viminit)
vimrc_found(NULL, NULL);
- save_sourcing_name = sourcing_name;
- save_sourcing_lnum = sourcing_lnum;
- sourcing_name = env;
- sourcing_lnum = 0;
+ estack_push(ETYPE_ENV, env, 0);
#ifdef FEAT_EVAL
save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_ENV;
@@ -3358,8 +3354,8 @@ process_env(
current_sctx.sc_version = 1;
#endif
do_cmdline_cmd(initstr);
- sourcing_name = save_sourcing_name;
- sourcing_lnum = save_sourcing_lnum;
+
+ estack_pop();
#ifdef FEAT_EVAL
current_sctx = save_current_sctx;
#endif
diff --git a/src/map.c b/src/map.c
index 1b2660fa80..451190d445 100644
--- a/src/map.c
+++ b/src/map.c
@@ -697,7 +697,7 @@ do_map(
#ifdef FEAT_EVAL
mp->m_expr = expr;
mp->m_script_ctx = current_sctx;
- mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ mp->m_script_ctx.sc_lnum += SOURCING_LNUM;
#endif
did_it = TRUE;
}
@@ -796,7 +796,7 @@ do_map(
#ifdef FEAT_EVAL
mp->m_expr = expr;
mp->m_script_ctx = current_sctx;
- mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ mp->m_script_ctx.sc_lnum += SOURCING_LNUM;
#endif
// add the new entry in front of the abbrlist or maphash[] list
@@ -1915,14 +1915,13 @@ check_map_keycodes(void)
char_u *p;
int i;
char_u buf[3];
- char_u *save_name;
int abbr;
int hash;
buf_T *bp;
validate_maphash();
- save_name = sourcing_name;
- sourcing_name = (char_u *)"mappings"; // avoids giving error messages
+ // avoids giving error messages
+ estack_push(ETYPE_INTERNAL, (char_u *)"mappings", 0);
// Do this once for each buffer, and then once for global
// mappings/abbreviations with bp == NULL
@@ -1979,7 +1978,7 @@ check_map_keycodes(void)
if (bp == NULL)
break;
}
- sourcing_name = save_name;
+ estack_pop();
}
#if defined(FEAT_EVAL) || defined(PROTO)
diff --git a/src/message.c b/src/message.c
index 2ea939f193..4040e5ba56 100644
--- a/src/message.c
+++ b/src/message.c
@@ -434,15 +434,15 @@ reset_last_sourcing(void)
}
/*
- * Return TRUE if "sourcing_name" differs from "last_sourcing_name".
+ * Return TRUE if "SOURCING_NAME" differs from "last_sourcing_name".
*/
static int
other_sourcing_name(void)
{
- if (sourcing_name != NULL)
+ if (SOURCING_NAME != NULL)
{
if (last_sourcing_name != NULL)
- return STRCMP(sourcing_name, last_sourcing_name) != 0;
+ return STRCMP(SOURCING_NAME, last_sourcing_name) != 0;
return TRUE;
}
return FALSE;
@@ -458,12 +458,19 @@ get_emsg_source(void)
{
char_u *Buf, *p;
- if (sourcing_name != NULL && other_sourcing_name())
+ if (SOURCING_NAME != NULL && other_sourcing_name())
{
+ char_u *sname = estack_sfile();
+ char_u *tofree = sname;
+
+ if (sname == NULL)
+ sname = SOURCING_NAME;
+
p = (char_u *)_("Error detected while processing %s:");
- Buf = alloc(STRLEN(sourcing_name) + STRLEN(p));
+ Buf = alloc(STRLEN(sname) + STRLEN(p));
if (Buf != NULL)
- sprintf((char *)Buf, (char *)p, sourcing_name);
+ sprintf((char *)Buf, (char *)p, sname);
+ vim_free(tofree);
return Buf;
}
return NULL;
@@ -481,14 +488,14 @@ get_emsg_lnum(void)
// lnum is 0 when executing a command from the command line
// argument, we don't want a line number then
- if (sourcing_name != NULL
- && (other_sourcing_name() || sourcing_lnum != last_sourcing_lnum)
- && sourcing_lnum != 0)
+ if (SOURCING_NAME != NULL
+ && (other_sourcing_name() || SOURCING_LNUM != last_sourcing_lnum)
+ && SOURCING_LNUM != 0)
{
p = (char_u *)_("line %4ld:");
Buf = alloc(STRLEN(p) + 20);
if (Buf != NULL)
- sprintf((char *)Buf, (char *)p, (long)sourcing_lnum);
+ sprintf((char *)Buf, (char *)p, (long)SOURCING_LNUM);
return Buf;
}
return NULL;
@@ -516,17 +523,17 @@ msg_source(int attr)
{
msg_attr((char *)p, HL_ATTR(HLF_N));
vim_free(p);
- last_sourcing_lnum = sourcing_lnum; // only once for each line
+ last_sourcing_lnum = SOURCING_LNUM; // only once for each line
}
// remember the last sourcing name printed, also when it's empty
- if (sourcing_name == NULL || other_sourcing_name())
+ if (SOURCING_NAME == NULL || other_sourcing_name())
{
vim_free(last_sourcing_name);
- if (sourcing_name == NULL)
+ if (SOURCING_NAME == NULL)
last_sourcing_name = NULL;
else
- last_sourcing_name = vim_strsave(sourcing_name);
+ last_sourcing_name = vim_strsave(SOURCING_NAME);
}
--no_wait_return;
}
@@ -2312,7 +2319,7 @@ inc_msg_scrolled(void)
#ifdef FEAT_EVAL
if (*get_vim_var_str(VV_SCROLLSTART) == NUL)
{
- char_u *p = sourcing_name;
+ char_u *p = SOURCING_NAME;
char_u *tofree = NULL;
int len;
@@ -2327,7 +2334,7 @@ inc_msg_scrolled(void)
if (tofree != NULL)
{
vim_snprintf((char *)tofree, len, _("%s line %ld"),
- p, (long)sourcing_lnum);
+ p, (long)SOURCING_LNUM);
p = tofree;
}
}
diff --git a/src/option.c b/src/option.c
index 5c99c6966b..7c37326f93 100644
--- a/src/option.c
+++ b/src/option.c
@@ -2435,7 +2435,7 @@ set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
int indir = (int)options[opt_idx].indir;
sctx_T new_script_ctx = script_ctx;
- new_script_ctx.sc_lnum += sourcing_lnum;
+ new_script_ctx.sc_lnum += SOURCING_LNUM;
// Remember where the option was set. For local options need to do that
// in the buffer or window structure.
diff --git a/src/profiler.c b/src/profiler.c
index 0bfce86960..cd962cabd4 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -602,10 +602,10 @@ func_line_start(void *cookie)
funccall_T *fcp = (funccall_T *)cookie;
ufunc_T *fp = fcp->func;
- if (fp->uf_profiling && sourcing_lnum >= 1
- && sourcing_lnum <= fp->uf_lines.ga_len)
+ if (fp->uf_profiling && SOURCING_LNUM >= 1
+ && SOURCING_LNUM <= fp->uf_lines.ga_len)
{
- fp->uf_tml_idx = sourcing_lnum - 1;
+ fp->uf_tml_idx = SOURCING_LNUM - 1;
// Skip continuation lines.
while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL)
--fp->uf_tml_idx;
@@ -906,13 +906,13 @@ script_line_start(void)
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_sctx.sc_sid);
- if (si->sn_prof_on && sourcing_lnum >= 1)
+ if (si->sn_prof_on && SOURCING_LNUM >= 1)
{
// Grow the array before starting the timer, so that the time spent
// here isn't counted.
(void)ga_grow(&si->sn_prl_ga,
- (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
- si->sn_prl_idx = sourcing_lnum - 1;
+ (int)(SOURCING_LNUM - si->sn_prl_ga.ga_len));
+ si->sn_prl_idx = SOURCING_LNUM - 1;
while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
&& si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
{
diff --git a/src/proto/scriptfile.pro b/src/proto/scriptfile.pro
index 8104b27d3c..7972e849a9 100644
--- a/src/proto/scriptfile.pro
+++ b/src/proto/scriptfile.pro
@@ -1,4 +1,9 @@
/* scriptfile.c */
+void estack_init(void);
+estack_T *estack_push(etype_T type, char_u *name, long lnum);
+void estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum);
+void estack_pop(void);
+char_u *estack_sfile(void);
void ex_runtime(exarg_T *eap);
int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
diff --git a/src/scriptfile.c b/src/scriptfile.c
index 740950f053..d471839f07 100644
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -19,6 +19,122 @@ static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
#endif
/*
+ * Initialize the execution stack.
+ */
+ void
+estack_init(void)
+{
+ estack_T *entry;
+
+ if (ga_grow(&exestack, 10) == FAIL)
+ mch_exit(0);
+ entry = ((estack_T *)exestack.ga_data) + exestack.ga_len;
+ entry->es_type = ETYPE_TOP;
+ entry->es_name = NULL;
+ entry->es_lnum = 0;
+ entry->es_info.ufunc = NULL;
+ ++exestack.ga_len;
+}
+
+/*
+ * Add an item to the execution stack.
+ * Returns the new entry or NULL when out of memory.
+ */
+ estack_T *
+estack_push(etype_T type, char_u *name, long lnum)
+{
+ estack_T *entry;
+
+ // If memory allocation fails then we'll pop more than we push, eventually
+ // at the top level it will be OK again.
+ if (ga_grow(&exestack, 1) == OK)
+ {
+ entry = ((estack_T *)exestack.ga_data) + exestack.ga_len;
+ entry->es_type = type;
+ entry->es_name = name;
+ entry->es_lnum = lnum;
+ entry->es_info.ufunc = NULL;
+ ++exestack.ga_len;
+ return entry;
+ }
+ return NULL;
+}
+
+/*
+ * Add a user function to the execution stack.
+ */
+ void
+estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum)
+{
+ estack_T *entry = estack_push(type,
+ ufunc->uf_name_exp != NULL
+ ? ufunc->uf_name_exp : ufunc->uf_name, lnum);
+ if (entry != NULL)
+ entry->es_info.ufunc = ufunc;
+}
+
+/*
+ * Take an item off of the execution stack.
+ */
+ void
+estack_pop(void)
+{
+ if (exestack.ga_len > 1)
+ --exestack.ga_len;
+}
+
+/*
+ * Get the current value for <sfile> in allocated memory.
+ */
+ char_u *
+estack_sfile(void)
+{
+ int len;
+ int idx;
+ estack_T *entry;
+ char *res;
+ int done;
+
+ entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
+ if (entry->es_name == NULL)
+ return NULL;
+ if (entry->es_info.ufunc == NULL)
+ return vim_strsave(entry->es_name);
+
+ // For a function we compose the call stack, as it was done in the past:
+ // "function One[123]..Two[456]..Three"
+ len = STRLEN(entry->es_name) + 10;
+ for (idx = exestack.ga_len - 2; idx >= 0; --idx)
+ {
+ entry = ((estack_T *)exestack.ga_data) + idx;
+ if (entry->es_name == NULL || entry->es_info.ufunc == NULL)
+ {
+ ++idx;
+ break;
+ }
+ len += STRLEN(entry->es_name) + 15;
+ }
+
+ res = (char *)alloc(len);
+ if (res != NULL)
+ {
+ STRCPY(res, "function ");
+ while (idx < exestack.ga_len - 1)
+ {
+ done = STRLEN(res);
+ entry = ((estack_T *)exestack.ga_data) + idx;
+ vim_snprintf(res + done, len - done, "%s[%ld]..",
+ entry->es_name, entry->es_lnum);
+ ++idx;
+ }
+ done = STRLEN(res);
+ entry = ((estack_T *)exestack.ga_data) + idx;
+ vim_snprintf(res + done, len - done, "%s", entry->es_name);
+ }
+ return (char_u *)res;
+}
+
+/*
* ":runtime [what] {name}"
*/
void
@@ -947,8 +1063,6 @@ do_source(
int is_vimrc) // DOSO_ value
{
struct source_cookie cookie;
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
char_u *p;
char_u *fname_exp;
char_u *firstline = NULL;
@@ -1039,11 +1153,11 @@ do_source(
if (p_verbose > 0)
{
verbose_enter();