]> granicus.if.org Git - vim/commitdiff
patch 8.2.0056: execution stack is incomplete and inefficient v8.2.0056
authorBram Moolenaar <Bram@vim.org>
Sun, 29 Dec 2019 22:04:25 +0000 (23:04 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 29 Dec 2019 22:04:25 +0000 (23:04 +0100)
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.

23 files changed:
src/autocmd.c
src/buffer.c
src/debugger.c
src/ex_docmd.c
src/ex_eval.c
src/globals.h
src/highlight.c
src/kword_test.c
src/main.c
src/map.c
src/message.c
src/option.c
src/profiler.c
src/proto/scriptfile.pro
src/scriptfile.c
src/spellfile.c
src/structs.h
src/term.c
src/testdir/test_debugger.vim
src/testing.c
src/usercmd.c
src/userfunc.c
src/version.c

index de24dd219c5b283952f50e85b16b2f082c287e83..983a155c60fd9111ebbfd0443534d4af428758ee 100644 (file)
@@ -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();
                    }
                }
index 2502dee6271d1cc877a7c995ee99e4628a6c4b7f..dd3593fb52430c5bbbc4d93efaee5139cf6e11da 100644 (file)
@@ -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;
index 0a25e0b8847004b146ef9f70a7ce7c67bf7185d1..5dfc54e82f251a5e309d6d330fa1816696c012d5 100644 (file)
@@ -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);
 }
index ba51640664ba700bfd2414e231332f9838dbe312..a3442edbe7507b6aecb8ad55b20e72818f8bf494 100644 (file)
@@ -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
index 4d76572dcc94fa96904add94e7c9763842bdeac1..382e99e0d2b96aea8c4a750c05e30f4d86fbdc4f 100644 (file)
@@ -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)
     {
index 87f7b0be54bda3524baf7269720d6bf8b6f008b5..acdce7096812dd17985f547c465c2c3fc3bf819b 100644 (file)
@@ -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
index 40dda6452e5372ae293e23182a2fcc5fec1708e0..19aafffe5afd382c8cf428ca0605c893d16d5c89 100644 (file)
@@ -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
     }
 
index c02ba4312c8da4d0ec41e55a8e34e8def9e9590a..92ea052bb8e9cc2ce12ab761d10c0e214b71fd23 100644 (file)
@@ -76,6 +76,7 @@ test_isword_funcs_utf8(void)
     int
 main(void)
 {
+    estack_init();
     test_isword_funcs_utf8();
     return 0;
 }
index eec02ea85bd38650b7ac7f0d4bd3053ef073db10..51b8970b9bb34f8ec14135032edc2a80216758ca 100644 (file)
@@ -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
index 1b2660fa804f6c92ec38d643d50c63b838107fe2..451190d445fcf76dfbca8f03c2d9ec43c4c21b36 100644 (file)
--- 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)
index 2ea939f193f8009937aa49d65aa9926b9d628845..4040e5ba568d290a556e24feea69a86f6cae84b5 100644 (file)
@@ -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;
            }
        }
index 5c99c6966baf51699b35b11f95f3d57bc3f57c2d..7c37326f931b62a73589b39e8f5f5030d3e2269c 100644 (file)
@@ -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.
index 0bfce86960ea986a6c42a45fbf2338c28cc027cb..cd962cabd4cbd5ef24c36b4b9efece5961d07aca 100644 (file)
@@ -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)
        {
index 8104b27d3ca595ed32014c20afbfcfa9d2cc2a49..7972e849a9a803c6336f165b02f5853d6b50f373 100644 (file)
@@ -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);
index 740950f0537f91fdd3af923ff3f15009a2480441..d471839f079553671a62c25811c80634292bf599 100644 (file)
 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}"
  */
@@ -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();
-           if (sourcing_name == NULL)
+           if (SOURCING_NAME == NULL)
                smsg(_("could not source \"%s\""), fname);
            else
                smsg(_("line %ld: could not source \"%s\""),
-                                                       sourcing_lnum, fname);
+                                                       SOURCING_LNUM, fname);
            verbose_leave();
        }
        goto theend;
@@ -1055,11 +1169,10 @@ do_source(
     if (p_verbose > 1)
     {
        verbose_enter();
-       if (sourcing_name == NULL)
+       if (SOURCING_NAME == NULL)
            smsg(_("sourcing \"%s\""), fname);
        else
-           smsg(_("line %ld: sourcing \"%s\""),
-                                                       sourcing_lnum, fname);
+           smsg(_("line %ld: sourcing \"%s\""), SOURCING_LNUM, fname);
        verbose_leave();
     }
     if (is_vimrc == DOSO_VIMRC)
@@ -1090,10 +1203,7 @@ do_source(
 #endif
 
     // Keep the sourcing name/lnum, for recursive calls.
-    save_sourcing_name = sourcing_name;
-    sourcing_name = fname_exp;
-    save_sourcing_lnum = sourcing_lnum;
-    sourcing_lnum = 0;
+    estack_push(ETYPE_SCRIPT, fname_exp, 0);
 
 #ifdef STARTUPTIME
     if (time_fd != NULL)
@@ -1233,14 +1343,13 @@ do_source(
 
     if (got_int)
        emsg(_(e_interr));
-    sourcing_name = save_sourcing_name;
-    sourcing_lnum = save_sourcing_lnum;
+    estack_pop();
     if (p_verbose > 1)
     {
        verbose_enter();
        smsg(_("finished sourcing %s"), fname);
-       if (sourcing_name != NULL)
-           smsg(_("continuing in %s"), sourcing_name);
+       if (SOURCING_NAME != NULL)
+           smsg(_("continuing in %s"), SOURCING_NAME);
        verbose_leave();
     }
 #ifdef STARTUPTIME
@@ -1381,7 +1490,7 @@ get_sourced_lnum(char_u *(*fgetline)(int, void *, int, int), void *cookie)
 {
     return fgetline == getsourceline
                        ? ((struct source_cookie *)cookie)->sourcing_lnum
-                       : sourcing_lnum;
+                       : SOURCING_LNUM;
 }
 
     static char_u *
@@ -1507,7 +1616,7 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
     // If breakpoints have been added/deleted need to check for it.
     if (sp->dbg_tick < debug_tick)
     {
-       sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
+       sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM);
        sp->dbg_tick = debug_tick;
     }
 # ifdef FEAT_PROFILE
@@ -1517,7 +1626,7 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
 #endif
 
     // Set the current sourcing line number.
-    sourcing_lnum = sp->sourcing_lnum + 1;
+    SOURCING_LNUM = sp->sourcing_lnum + 1;
 
     // Get current line.  If there is a read-ahead line, use it, otherwise get
     // one now.
@@ -1602,11 +1711,11 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
 
 #ifdef FEAT_EVAL
     // Did we encounter a breakpoint?
-    if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
+    if (sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM)
     {
-       dbg_breakpoint(sp->fname, sourcing_lnum);
+       dbg_breakpoint(sp->fname, SOURCING_LNUM);
        // Find next breakpoint.
-       sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
+       sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM);
        sp->dbg_tick = debug_tick;
     }
 #endif
index b9451ecd6d28751fd722bb079d451c7fa9b43fb4..6cad202fd3a6ac5f0c3b5b035d68c9263cdc5120 100644 (file)
@@ -349,8 +349,6 @@ spell_load_file(
     int                i;
     int                n;
     int                len;
-    char_u     *save_sourcing_name = sourcing_name;
-    linenr_T   save_sourcing_lnum = sourcing_lnum;
     slang_T    *lp = NULL;
     int                c = 0;
     int                res;
@@ -393,8 +391,7 @@ spell_load_file(
        lp = old_lp;
 
     // Set sourcing_name, so that error messages mention the file name.
-    sourcing_name = fname;
-    sourcing_lnum = 0;
+    estack_push(ETYPE_SPELL, fname, 0);
 
     /*
      * <HEADER>: <fileID>
@@ -581,8 +578,7 @@ endFAIL:
 endOK:
     if (fd != NULL)
        fclose(fd);
-    sourcing_name = save_sourcing_name;
-    sourcing_lnum = save_sourcing_lnum;
+    estack_pop();
 
     return lp;
 }
index 9f1d479ceff10f6ae210d3e694d243b7c308c779..c995d4beb02be47bdc1276d7ba57d1d6bc324c00 100644 (file)
@@ -1496,6 +1496,8 @@ typedef struct
                                // used for s: variables
     int                uf_refcount;    // reference count, see func_name_refcount()
     funccall_T *uf_scoped;     // l: local variables for closure
+    char_u     *uf_name_exp;   // if "uf_name[]" starts with SNR the name with
+                               // "<SNR>" as a string, otherwise NULL
     char_u     uf_name[1];     // name of function (actually longer); can
                                // start with <SNR>123_ (<SNR> is K_SPECIAL
                                // KS_EXTRA KE_SNR)
@@ -1665,6 +1667,38 @@ struct partial_S
     dict_T     *pt_dict;       // dict for "self"
 };
 
+typedef struct AutoPatCmd_S AutoPatCmd;
+
+/*
+ * Entry in the execution stack "exestack".
+ */
+typedef enum {
+    ETYPE_TOP,             // toplevel
+    ETYPE_SCRIPT,           // sourcing script, use es_info.sctx
+    ETYPE_UFUNC,            // user function, use es_info.ufunc
+    ETYPE_AUCMD,            // autocomand, use es_info.aucmd
+    ETYPE_MODELINE,         // modeline, use es_info.sctx
+    ETYPE_EXCEPT,           // exception, use es_info.exception
+    ETYPE_ARGS,             // command line argument
+    ETYPE_ENV,              // environment variable
+    ETYPE_INTERNAL,         // internal operation
+    ETYPE_SPELL,            // loading spell file
+} etype_T;
+
+typedef struct {
+    long      es_lnum;      // replaces "sourcing_lnum"
+    char_u    *es_name;     // replaces "sourcing_name"
+    etype_T   es_type;
+    union {
+       sctx_T  *sctx;      // script and modeline info
+#if defined(FEAT_EVAL)
+       ufunc_T *ufunc;     // function info
+#endif
+       AutoPatCmd *aucmd;  // autocommand info
+       except_T   *except; // exception info
+    } es_info;
+} estack_T;
+
 // Information returned by get_tty_info().
 typedef struct {
     int backspace;     // what the Backspace key produces
index b0ab7c634afe44fe504e193a1dc37c0dbb86a3a3..389b06f375a0de529f82ede3082e69fbaf22bf35 100644 (file)
@@ -2277,7 +2277,7 @@ add_termcap_entry(char_u *name, int force)
     }
 #endif
 
-    if (sourcing_name == NULL)
+    if (SOURCING_NAME == NULL)
     {
 #ifdef HAVE_TGETENT
        if (error_msg != NULL)
index 861bd6fc08e51d3a51f33ed7c63956eba1877b34..c5418025bdd251d1f4ce9bc0443622685ec770d4 100644 (file)
@@ -14,7 +14,7 @@ func RunDbgCmd(buf, cmd, ...)
     " Verify the expected output
     let lnum = 20 - len(a:1)
     for l in a:1
-      call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))})
+      call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200)
       let lnum += 1
     endfor
   endif
index 569a57c8e8b2a6329c764c88d16c6486b8d99b13..3e6ba8e03e9c9c460f6d869652ff935a23444b39 100644 (file)
     static void
 prepare_assert_error(garray_T *gap)
 {
-    char buf[NUMBUFLEN];
+    char    buf[NUMBUFLEN];
+    char_u  *sname = estack_sfile();
 
     ga_init2(gap, 1, 100);
-    if (sourcing_name != NULL)
+    if (sname != NULL)
     {
-       ga_concat(gap, sourcing_name);
-       if (sourcing_lnum > 0)
+       ga_concat(gap, sname);
+       if (SOURCING_LNUM > 0)
            ga_concat(gap, (char_u *)" ");
     }
-    if (sourcing_lnum > 0)
+    if (SOURCING_LNUM > 0)
     {
-       sprintf(buf, "line %ld", (long)sourcing_lnum);
+       sprintf(buf, "line %ld", (long)SOURCING_LNUM);
        ga_concat(gap, (char_u *)buf);
     }
-    if (sourcing_name != NULL || sourcing_lnum > 0)
+    if (sname != NULL || SOURCING_LNUM > 0)
        ga_concat(gap, (char_u *)": ");
+    vim_free(sname);
 }
 
 /*
index 1a6fbeebc62a33414dc5ad11976f381b88a5d827..7ff7f02d7eb5143ff83f38c3178c5fd4b5ea7da7 100644 (file)
@@ -191,7 +191,7 @@ find_ucmd(
                    {
                        xp->xp_arg = uc->uc_compl_arg;
                        xp->xp_script_ctx = uc->uc_script_ctx;
-                       xp->xp_script_ctx.sc_lnum += sourcing_lnum;
+                       xp->xp_script_ctx.sc_lnum += SOURCING_LNUM;
                    }
 # endif
                    // Do not search for further abbreviations
@@ -956,7 +956,7 @@ uc_add_command(
     cmd->uc_compl = compl;
 #ifdef FEAT_EVAL
     cmd->uc_script_ctx = current_sctx;
-    cmd->uc_script_ctx.sc_lnum += sourcing_lnum;
+    cmd->uc_script_ctx.sc_lnum += SOURCING_LNUM;
     cmd->uc_compl_arg = compl_arg;
 #endif
     cmd->uc_addr_type = addr_type;
index b3a7558a913d277ac3df07f539ac578a14d66f65..56dbf9e71f997979cdf63279a8736525ecd96577 100644 (file)
@@ -226,6 +226,22 @@ register_closure(ufunc_T *fp)
     return OK;
 }
 
+    static void
+set_ufunc_name(ufunc_T *fp, char_u *name)
+{
+    STRCPY(fp->uf_name, name);
+
+    if (name[0] == K_SPECIAL)
+    {
+       fp->uf_name_exp = alloc(STRLEN(name) + 3);
+       if (fp->uf_name_exp != NULL)
+       {
+           STRCPY(fp->uf_name_exp, "<SNR>");
+           STRCAT(fp->uf_name_exp, fp->uf_name + 3);
+       }
+    }
+}
+
 /*
  * Parse a lambda expression and get a Funcref from "*arg".
  * Return OK or FAIL.  Returns NOTDONE for dict or {expr}.
@@ -309,7 +325,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
        vim_strncpy(p + 7, s, e - s);
 
        fp->uf_refcount = 1;
-       STRCPY(fp->uf_name, name);
+       set_ufunc_name(fp, name);
        hash_add(&func_hashtab, UF2HIKEY(fp));
        fp->uf_args = newargs;
        ga_init(&fp->uf_def_args);
@@ -333,7 +349,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
        fp->uf_flags = flags;
        fp->uf_calls = 0;
        fp->uf_script_ctx = current_sctx;
-       fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len;
+       fp->uf_script_ctx.sc_lnum += SOURCING_LNUM - newlines.ga_len;
 
        pt->pt_func = fp;
        pt->pt_refcount = 1;
@@ -759,8 +775,6 @@ call_user_func(
     linenr_T   lastline,       // last line of range
     dict_T     *selfdict)      // Dictionary for "self"
 {
-    char_u     *save_sourcing_name;
-    linenr_T   save_sourcing_lnum;
     sctx_T     save_current_sctx;
     int                using_sandbox = FALSE;
     funccall_T *fc;
@@ -774,7 +788,6 @@ call_user_func(
     int                islambda = FALSE;
     char_u     numbuf[NUMBUFLEN];
     char_u     *name;
-    size_t     len;
 #ifdef FEAT_PROFILE
     proftime_T wait_start;
     proftime_T call_start;
@@ -948,9 +961,6 @@ call_user_func(
 
     // Don't redraw while executing the function.
     ++RedrawingDisabled;
-    save_sourcing_name = sourcing_name;
-    save_sourcing_lnum = sourcing_lnum;
-    sourcing_lnum = 1;
 
     if (fp->uf_flags & FC_SANDBOX)
     {
@@ -958,65 +968,51 @@ call_user_func(
        ++sandbox;
     }
 
-    // need space for function name + ("function " + 3) or "[number]"
-    len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name))
-                                                  + STRLEN(fp->uf_name) + 20;
-    sourcing_name = alloc(len);
-    if (sourcing_name != NULL)
+    estack_push_ufunc(ETYPE_UFUNC, fp, 1);
+    if (p_verbose >= 12)
     {
-       if (save_sourcing_name != NULL
-                         && STRNCMP(save_sourcing_name, "function ", 9) == 0)
-           sprintf((char *)sourcing_name, "%s[%d]..",
-                                save_sourcing_name, (int)save_sourcing_lnum);
-       else
-           STRCPY(sourcing_name, "function ");
-       cat_func_name(sourcing_name + STRLEN(sourcing_name), fp);
+       ++no_wait_return;
+       verbose_enter_scroll();
 
-       if (p_verbose >= 12)
+       smsg(_("calling %s"), SOURCING_NAME);
+       if (p_verbose >= 14)
        {
-           ++no_wait_return;
-           verbose_enter_scroll();
+           char_u      buf[MSG_BUF_LEN];
+           char_u      numbuf2[NUMBUFLEN];
+           char_u      *tofree;
+           char_u      *s;
 
-           smsg(_("calling %s"), sourcing_name);
-           if (p_verbose >= 14)
+           msg_puts("(");
+           for (i = 0; i < argcount; ++i)
            {
-               char_u  buf[MSG_BUF_LEN];
-               char_u  numbuf2[NUMBUFLEN];
-               char_u  *tofree;
-               char_u  *s;
-
-               msg_puts("(");
-               for (i = 0; i < argcount; ++i)
+               if (i > 0)
+                   msg_puts(", ");
+               if (argvars[i].v_type == VAR_NUMBER)
+                   msg_outnum((long)argvars[i].vval.v_number);
+               else
                {
-                   if (i > 0)
-                       msg_puts(", ");
-                   if (argvars[i].v_type == VAR_NUMBER)
-                       msg_outnum((long)argvars[i].vval.v_number);
-                   else
+                   // Do not want errors such as E724 here.
+                   ++emsg_off;
+                   s = tv2string(&argvars[i], &tofree, numbuf2, 0);
+                   --emsg_off;
+                   if (s != NULL)
                    {
-                       // Do not want errors such as E724 here.
-                       ++emsg_off;
-                       s = tv2string(&argvars[i], &tofree, numbuf2, 0);
-                       --emsg_off;
-                       if (s != NULL)
+                       if (vim_strsize(s) > MSG_BUF_CLEN)
                        {
-                           if (vim_strsize(s) > MSG_BUF_CLEN)
-                           {
-                               trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
-                               s = buf;
-                           }
-                           msg_puts((char *)s);
-                           vim_free(tofree);
+                           trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
+                           s = buf;
                        }
+                       msg_puts((char *)s);
+                       vim_free(tofree);
                    }
                }
-               msg_puts(")");
            }
-           msg_puts("\n");   // don't overwrite this either
-
-           verbose_leave_scroll();
-           --no_wait_return;
+           msg_puts(")");
        }
+       msg_puts("\n");   // don't overwrite this either
+
+       verbose_leave_scroll();
+       --no_wait_return;
     }
 #ifdef FEAT_PROFILE
     if (do_profiling == PROF_YES)
@@ -1085,9 +1081,9 @@ call_user_func(
        verbose_enter_scroll();
 
        if (aborting())
-           smsg(_("%s aborted"), sourcing_name);
+           smsg(_("%s aborted"), SOURCING_NAME);
        else if (fc->rettv->v_type == VAR_NUMBER)
-           smsg(_("%s returning #%ld"), sourcing_name,
+           smsg(_("%s returning #%ld"), SOURCING_NAME,
                                               (long)fc->rettv->vval.v_number);
        else
        {
@@ -1109,7 +1105,7 @@ call_user_func(
                    trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
                    s = buf;
                }
-               smsg(_("%s returning %s"), sourcing_name, s);
+               smsg(_("%s returning %s"), SOURCING_NAME, s);
                vim_free(tofree);
            }
        }
@@ -1119,9 +1115,7 @@ call_user_func(
        --no_wait_return;
     }
 
-    vim_free(sourcing_name);
-    sourcing_name = save_sourcing_name;
-    sourcing_lnum = save_sourcing_lnum;
+    estack_pop();
     current_sctx = save_current_sctx;
 #ifdef FEAT_PROFILE
     if (do_profiling == PROF_YES)
@@ -1130,12 +1124,12 @@ call_user_func(
     if (using_sandbox)
        --sandbox;
 
-    if (p_verbose >= 12 && sourcing_name != NULL)
+    if (p_verbose >= 12 && SOURCING_NAME != NULL)
     {
        ++no_wait_return;
        verbose_enter_scroll();
 
-       smsg(_("continuing in %s"), sourcing_name);
+       smsg(_("continuing in %s"), SOURCING_NAME);
        msg_puts("\n");   // don't overwrite this either
 
        verbose_leave_scroll();
@@ -1204,13 +1198,11 @@ func_clear_items(ufunc_T *fp)
     ga_clear_strings(&(fp->uf_args));
     ga_clear_strings(&(fp->uf_def_args));
     ga_clear_strings(&(fp->uf_lines));
+    VIM_CLEAR(fp->uf_name_exp);
 #ifdef FEAT_PROFILE
-    vim_free(fp->uf_tml_count);
-    fp->uf_tml_count = NULL;
-    vim_free(fp->uf_tml_total);
-    fp->uf_tml_total = NULL;
-    vim_free(fp->uf_tml_self);
-    fp->uf_tml_self = NULL;
+    VIM_CLEAR(fp->uf_tml_count);
+    VIM_CLEAR(fp->uf_tml_total);
+    VIM_CLEAR(fp->uf_tml_self);
 #endif
 }
 
@@ -1736,11 +1728,8 @@ list_func_head(ufunc_T *fp, int indent)
     if (indent)
        msg_puts("   ");
     msg_puts("function ");
-    if (fp->uf_name[0] == K_SPECIAL)
-    {
-       msg_puts_attr("<SNR>", HL_ATTR(HLF_8));
-       msg_puts((char *)fp->uf_name + 3);
-    }
+    if (fp->uf_name_exp != NULL)
+       msg_puts((char *)fp->uf_name_exp);
     else
        msg_puts((char *)fp->uf_name);
     msg_putchar('(');
@@ -2308,7 +2297,7 @@ ex_function(exarg_T *eap)
     }
 
     // Save the starting line number.
-    sourcing_lnum_top = sourcing_lnum;
+    sourcing_lnum_top = SOURCING_LNUM;
 
     indent = 2;
     nesting = 0;
@@ -2351,10 +2340,10 @@ ex_function(exarg_T *eap)
            goto erret;
        }
 
-       // Detect line continuation: sourcing_lnum increased more than one.
+       // Detect line continuation: SOURCING_LNUM increased more than one.
        sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
-       if (sourcing_lnum < sourcing_lnum_off)
-           sourcing_lnum_off -= sourcing_lnum;
+       if (SOURCING_LNUM < sourcing_lnum_off)
+           sourcing_lnum_off -= SOURCING_LNUM;
        else
            sourcing_lnum_off = 0;
 
@@ -2631,16 +2620,16 @@ ex_function(exarg_T *eap)
 
            // Check that the autoload name matches the script name.
            j = FAIL;
-           if (sourcing_name != NULL)
+           if (SOURCING_NAME != NULL)
            {
                scriptname = autoload_name(name);
                if (scriptname != NULL)
                {
                    p = vim_strchr(scriptname, '/');
                    plen = (int)STRLEN(p);
-                   slen = (int)STRLEN(sourcing_name);
+                   slen = (int)STRLEN(SOURCING_NAME);
                    if (slen > plen && fnamecmp(p,
-                                           sourcing_name + slen - plen) == 0)
+                                           SOURCING_NAME + slen - plen) == 0)
                        j = OK;
                    vim_free(scriptname);
                }
@@ -2685,7 +2674,7 @@ ex_function(exarg_T *eap)
        }
 
        // insert the new function in the function list
-       STRCPY(fp->uf_name, name);
+       set_ufunc_name(fp, name);
        if (overwrite)
        {
            hi = hash_find(&func_hashtab, name);
@@ -3353,7 +3342,7 @@ get_func_line(
     if (fcp->dbg_tick != debug_tick)
     {
        fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
-                                                              sourcing_lnum);
+                                                              SOURCING_LNUM);
        fcp->dbg_tick = debug_tick;
     }
 #ifdef FEAT_PROFILE
@@ -3376,7 +3365,7 @@ get_func_line(
        else
        {
            retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
-           sourcing_lnum = fcp->linenr;
+           SOURCING_LNUM = fcp->linenr;
 #ifdef FEAT_PROFILE
            if (do_profiling == PROF_YES)
                func_line_start(cookie);
@@ -3385,12 +3374,12 @@ get_func_line(
     }
 
     // Did we encounter a breakpoint?
-    if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum)
+    if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM)
     {
-       dbg_breakpoint(fp->uf_name, sourcing_lnum);
+       dbg_breakpoint(fp->uf_name, SOURCING_LNUM);
        // Find next breakpoint.
        fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
-                                                              sourcing_lnum);
+                                                              SOURCING_LNUM);
        fcp->dbg_tick = debug_tick;
     }
 
index 98a9ca4a13663440c99be62b8486bac90951c676..984ac7bcf6a83a8e2503456fbbe0fc8ce5a3cae8 100644 (file)
@@ -742,6 +742,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    56,
 /**/
     55,
 /**/