]> granicus.if.org Git - vim/commitdiff
patch 8.2.3889: duplicate code for translating script-local function name v8.2.3889
authorYegappan Lakshmanan <yegappan@yahoo.com>
Fri, 24 Dec 2021 20:47:38 +0000 (20:47 +0000)
committerBram Moolenaar <Bram@vim.org>
Fri, 24 Dec 2021 20:47:38 +0000 (20:47 +0000)
Problem:    Duplicate code for translating script-local function name.
Solution:   Move the code to get_scriptlocal_funcname(). (Yegappan Lakshmanan,
            closes #9393)

src/evalfunc.c
src/evalvars.c
src/option.c
src/proto/userfunc.pro
src/testdir/test_expr.vim
src/testdir/test_normal.vim
src/userfunc.c
src/version.c

index 778d16d77b096d1ef57712a3156ad3ab94c18327..8f5205393817478f5e636aadb4692eafbb594d15 100644 (file)
@@ -4050,22 +4050,11 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
        list_T  *list = NULL;
 
        if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
-       {
-           char        sid_buf[25];
-           int         off = *s == 's' ? 2 : 5;
-
            // Expand s: and <SID> into <SNR>nr_, so that the function can
            // also be called from another script. Using trans_function_name()
            // would also work, but some plugins depend on the name being
            // printable text.
-           sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
-           name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
-           if (name != NULL)
-           {
-               STRCPY(name, sid_buf);
-               STRCAT(name, s + off);
-           }
-       }
+           name = get_scriptlocal_funcname(s);
        else
            name = vim_strsave(s);
 
index d002e57b450ff77d581be09234b28b405e658027..34cc014ad61311b8011d2cddd06e7aa8a9708be4 100644 (file)
@@ -4450,7 +4450,18 @@ get_callback(typval_T *arg)
            r = FAIL;
        else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
        {
-           // Note that we don't make a copy of the string.
+           if (arg->v_type == VAR_STRING)
+           {
+               char_u *name;
+
+               name = get_scriptlocal_funcname(arg->vval.v_string);
+               if (name != NULL)
+               {
+                   vim_free(arg->vval.v_string);
+                   arg->vval.v_string = name;
+               }
+           }
+
            res.cb_name = arg->vval.v_string;
            func_ref(res.cb_name);
        }
index b55789dba533ef23ce99235e26a6d799da100fcb..739b29adfaa4aa1a3ba753d920699c0bbc02fc42 100644 (file)
@@ -7205,33 +7205,8 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
        // Lambda expression or a funcref
        tv = eval_expr(optval, NULL);
     else
-    {
        // treat everything else as a function name string
-
-       // Function name starting with "s:" are supported only in a vimscript
-       // context.
-       if (STRNCMP(optval, "s:", 2) == 0)
-       {
-           char        sid_buf[25];
-           char_u      *funcname;
-
-           if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
-           {
-               emsg(_(e_using_sid_not_in_script_context));
-               return FAIL;
-           }
-           // Expand s: prefix into <SNR>nr_<name>
-           sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
-           funcname = alloc(STRLEN(sid_buf) + STRLEN(optval + 2) + 1);
-           if (funcname == NULL)
-               return FAIL;
-           STRCPY(funcname, sid_buf);
-           STRCAT(funcname, optval + 2);
-           tv = alloc_string_tv(funcname);
-       }
-       else
-           tv = alloc_string_tv(vim_strsave(optval));
-    }
+       tv = alloc_string_tv(vim_strsave(optval));
     if (tv == NULL)
        return FAIL;
 
index bb38143524c63a0d1a680f10c816e1ee2954685d..0320f09d36729e70f391cc064236b3dcad6c78ca 100644 (file)
@@ -35,6 +35,7 @@ int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typva
 char_u *printable_func_name(ufunc_T *fp);
 char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type);
 char_u *untrans_function_name(char_u *name);
+char_u *get_scriptlocal_funcname(char_u *funcname);
 char_u *save_function_name(char_u **name, int *is_global, int skip, int flags, funcdict_T *fudi);
 void list_functions(regmatch_T *regmatch);
 ufunc_T *define_function(exarg_T *eap, char_u *name_arg);
index 99cb9a1374032db9da38ff880f6157e2c383c4a0..ba2e2597a00bcbc923119baa0de3155ccdace85d 100644 (file)
@@ -639,6 +639,21 @@ func Test_funcref()
   call assert_fails('echo test_null_function()->funcref()', 'E475: Invalid argument: NULL')
 endfunc
 
+" Test for calling function() and funcref() outside of a Vim script context.
+func Test_function_outside_script()
+  let cleanup =<< trim END
+    call writefile([execute('messages')], 'Xtest.out')
+    qall
+  END
+  call writefile(cleanup, 'Xverify.vim')
+  call RunVim([], [], "-c \"echo function('s:abc')\" -S Xverify.vim")
+  call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
+  call RunVim([], [], "-c \"echo funcref('s:abc')\" -S Xverify.vim")
+  call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
+  call delete('Xtest.out')
+  call delete('Xverify.vim')
+endfunc
+
 func Test_setmatches()
   let lines =<< trim END
       hi def link 1 Comment
index 08539deb050526585a550dd4eb05422c7a186aeb..57ea6d3ecce9d642e95830083ca725440282696e 100644 (file)
@@ -642,6 +642,18 @@ func Test_opfunc_callback()
   END
   call CheckScriptSuccess(lines)
 
+  " setting 'opfunc' to a script local function outside of a script context
+  " should fail
+  let cleanup =<< trim END
+    call writefile([execute('messages')], 'Xtest.out')
+    qall
+  END
+  call writefile(cleanup, 'Xverify.vim')
+  call RunVim([], [], "-c \"set opfunc=s:abc\" -S Xverify.vim")
+  call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
+  call delete('Xtest.out')
+  call delete('Xverify.vim')
+
   " cleanup
   set opfunc&
   delfunc OpFunc1
index 7f6754444d8f4a443bf44e75f6d0e372be49ab4d..8971740922bf2d62070a286657639497d28f3699 100644 (file)
@@ -3875,6 +3875,46 @@ untrans_function_name(char_u *name)
     return NULL;
 }
 
+/*
+ * If the 'funcname' starts with "s:" or "<SID>", then expands it to the
+ * current script ID and returns the expanded function name. The caller should
+ * free the returned name. If not called from a script context or the function
+ * name doesn't start with these prefixes, then returns NULL.
+ * This doesn't check whether the script-local function exists or not.
+ */
+    char_u *
+get_scriptlocal_funcname(char_u *funcname)
+{
+    char       sid_buf[25];
+    int                off;
+    char_u     *newname;
+
+    if (funcname == NULL)
+       return NULL;
+
+    if (STRNCMP(funcname, "s:", 2) != 0
+               && STRNCMP(funcname, "<SID>", 5) != 0)
+       // The function name is not a script-local function name
+       return NULL;
+
+    if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
+    {
+       emsg(_(e_using_sid_not_in_script_context));
+       return NULL;
+    }
+    // Expand s: prefix into <SNR>nr_<name>
+    vim_snprintf(sid_buf, sizeof(sid_buf), "<SNR>%ld_",
+           (long)current_sctx.sc_sid);
+    off = *funcname == 's' ? 2 : 5;
+    newname = alloc(STRLEN(sid_buf) + STRLEN(funcname + off) + 1);
+    if (newname == NULL)
+       return NULL;
+    STRCPY(newname, sid_buf);
+    STRCAT(newname, funcname + off);
+
+    return newname;
+}
+
 /*
  * Call trans_function_name(), except that a lambda is returned as-is.
  * Returns the name in allocated memory.
index 78baffdec88d4c3779ec9c0dfe2aa61dd01ca419..cd4d157751401303ef8170a937ecf26cc71803c3 100644 (file)
@@ -749,6 +749,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3889,
 /**/
     3888,
 /**/