diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-12-29 23:04:25 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-12-29 23:04:25 +0100 |
commit | 1a47ae32cdc19b0fd5a82e19fe5fddf45db1a506 (patch) | |
tree | 8f5dc27f3eeea927ad3ca8de42fe0df06a041dd5 /src | |
parent | 257a396879ff67a0482841a39237f30a8e1e27c5 (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.
Diffstat (limited to 'src')
-rw-r--r-- | src/autocmd.c | 33 | ||||
-rw-r--r-- | src/buffer.c | 14 | ||||
-rw-r--r-- | src/debugger.c | 36 | ||||
-rw-r--r-- | src/ex_docmd.c | 48 | ||||
-rw-r--r-- | src/ex_eval.c | 7 | ||||
-rw-r--r-- | src/globals.h | 11 | ||||
-rw-r--r-- | src/highlight.c | 6 | ||||
-rw-r--r-- | src/kword_test.c | 1 | ||||
-rw-r--r-- | src/main.c | 20 | ||||
-rw-r--r-- | src/map.c | 11 | ||||
-rw-r--r-- | src/message.c | 39 | ||||
-rw-r--r-- | src/option.c | 2 | ||||
-rw-r--r-- | src/profiler.c | 12 | ||||
-rw-r--r-- | src/proto/scriptfile.pro | 5 | ||||
-rw-r--r-- | src/scriptfile.c | 151 | ||||
-rw-r--r-- | src/spellfile.c | 8 | ||||
-rw-r--r-- | src/structs.h | 34 | ||||
-rw-r--r-- | src/term.c | 2 | ||||
-rw-r--r-- | src/testdir/test_debugger.vim | 2 | ||||
-rw-r--r-- | src/testing.c | 16 | ||||
-rw-r--r-- | src/usercmd.c | 4 | ||||
-rw-r--r-- | src/userfunc.c | 161 | ||||
-rw-r--r-- | src/version.c | 2 |
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 @@ -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; - |