To: vim_dev@googlegroups.com Subject: Patch 8.2.3889 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3889 Problem: Duplicate code for translating script-local function name. Solution: Move the code to get_scriptlocal_funcname(). (Yegappan Lakshmanan, closes #9393) Files: src/evalfunc.c, src/evalvars.c, src/option.c, src/userfunc.c, src/proto/userfunc.pro, src/testdir/test_expr.vim, src/testdir/test_normal.vim *** ../vim-8.2.3888/src/evalfunc.c 2021-12-24 12:02:38.638058816 +0000 --- src/evalfunc.c 2021-12-24 20:44:00.676432618 +0000 *************** *** 4050,4071 **** list_T *list = NULL; if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "", 5) == 0) - { - char sid_buf[25]; - int off = *s == 's' ? 2 : 5; - // Expand s: and into 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, "%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); ! } ! } else name = vim_strsave(s); --- 4050,4060 ---- list_T *list = NULL; if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "", 5) == 0) // Expand s: and into 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. ! name = get_scriptlocal_funcname(s); else name = vim_strsave(s); *** ../vim-8.2.3888/src/evalvars.c 2021-12-17 20:15:30.448830724 +0000 --- src/evalvars.c 2021-12-24 20:44:00.676432618 +0000 *************** *** 4450,4456 **** 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. res.cb_name = arg->vval.v_string; func_ref(res.cb_name); } --- 4450,4467 ---- r = FAIL; else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_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); } *** ../vim-8.2.3888/src/option.c 2021-12-17 16:21:14.911650274 +0000 --- src/option.c 2021-12-24 20:44:00.676432618 +0000 *************** *** 7205,7237 **** // 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 nr_ ! sprintf(sid_buf, "%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)); ! } if (tv == NULL) return FAIL; --- 7205,7212 ---- // Lambda expression or a funcref tv = eval_expr(optval, NULL); else // treat everything else as a function name string ! tv = alloc_string_tv(vim_strsave(optval)); if (tv == NULL) return FAIL; *** ../vim-8.2.3888/src/userfunc.c 2021-12-16 20:56:52.956098576 +0000 --- src/userfunc.c 2021-12-24 20:44:00.680432611 +0000 *************** *** 3876,3881 **** --- 3876,3921 ---- } /* + * If the 'funcname' starts with "s:" or "", 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, "", 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 nr_ + vim_snprintf(sid_buf, sizeof(sid_buf), "%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. */ *** ../vim-8.2.3888/src/proto/userfunc.pro 2021-12-11 16:13:32.227721221 +0000 --- src/proto/userfunc.pro 2021-12-24 20:46:20.360217198 +0000 *************** *** 35,40 **** --- 35,41 ---- 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); *** ../vim-8.2.3888/src/testdir/test_expr.vim 2021-12-19 21:34:01.699292755 +0000 --- src/testdir/test_expr.vim 2021-12-24 20:44:00.676432618 +0000 *************** *** 639,644 **** --- 639,659 ---- 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 not in a', readfile('Xtest.out')[0]) + call RunVim([], [], "-c \"echo funcref('s:abc')\" -S Xverify.vim") + call assert_match('E81: Using 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 *** ../vim-8.2.3888/src/testdir/test_normal.vim 2021-12-17 16:21:14.911650274 +0000 --- src/testdir/test_normal.vim 2021-12-24 20:44:00.676432618 +0000 *************** *** 642,647 **** --- 642,659 ---- 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 not in a', readfile('Xtest.out')[0]) + call delete('Xtest.out') + call delete('Xverify.vim') + " cleanup set opfunc& delfunc OpFunc1 *** ../vim-8.2.3888/src/version.c 2021-12-24 20:27:58.033861527 +0000 --- src/version.c 2021-12-24 20:45:54.200257184 +0000 *************** *** 751,752 **** --- 751,754 ---- { /* Add new patch number below this line */ + /**/ + 3889, /**/ -- From "know your smileys": :-* A big kiss! /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///