changeset 32200:730eebd56f48 v9.0.1431

patch 9.0.1431: getscriptinfo() loops even when specific SID is given Commit: https://github.com/vim/vim/commit/2d68b722e3bca7532eb0d83ce773934618f12db5 Author: zeertzjq <zeertzjq@outlook.com> Date: Thu Mar 30 21:50:37 2023 +0100 patch 9.0.1431: getscriptinfo() loops even when specific SID is given Problem: getscriptinfo() loops even when specific SID is given. Solution: Only loop when needed. Give a clearer error message. (closes #12207)
author Bram Moolenaar <Bram@vim.org>
date Thu, 30 Mar 2023 23:00:06 +0200
parents dc4f9a9d07a1
children ac20568109be
files src/scriptfile.c src/testdir/test_scriptnames.vim src/version.c
diffstat 3 files changed, 34 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -1299,7 +1299,7 @@ ex_options(
  * ":source" and associated commands.
  */
 
-#ifdef FEAT_EVAL
+#if defined(FEAT_EVAL) || defined(PROTO)
 /*
  * Return the address holding the next breakpoint line for a source cookie.
  */
@@ -2096,7 +2096,6 @@ get_script_local_funcs(scid_T sid)
     void
 f_getscriptinfo(typval_T *argvars, typval_T *rettv)
 {
-    int		i;
     list_T	*l;
     char_u	*pat = NULL;
     regmatch_T	regmatch;
@@ -2116,8 +2115,22 @@ f_getscriptinfo(typval_T *argvars, typva
 
     if (argvars[0].v_type == VAR_DICT)
     {
-	sid = dict_get_number_def(argvars[0].vval.v_dict, "sid", -1);
-	if (sid == -1)
+	dictitem_T *sid_di = dict_find(argvars[0].vval.v_dict,
+							   (char_u *)"sid", 3);
+	if (sid_di != NULL)
+	{
+	    int error = FALSE;
+	    sid = tv_get_number_chk(&sid_di->di_tv, &error);
+	    if (error)
+		return;
+	    if (sid <= 0)
+	    {
+		semsg(e_invalid_value_for_argument_str_str, "sid",
+						tv_get_string(&sid_di->di_tv));
+		return;
+	    }
+	}
+	else
 	{
 	    pat = dict_get_string(argvars[0].vval.v_dict, "name", TRUE);
 	    if (pat != NULL)
@@ -2127,7 +2140,8 @@ f_getscriptinfo(typval_T *argvars, typva
 	}
     }
 
-    for (i = 1; i <= script_items.ga_len; ++i)
+    for (varnumber_T i = sid > 0 ? sid : 1;
+		       (i == sid || sid <= 0) && i <= script_items.ga_len; ++i)
     {
 	scriptitem_T	*si = SCRIPT_ITEM(i);
 	dict_T		*d;
@@ -2138,9 +2152,6 @@ f_getscriptinfo(typval_T *argvars, typva
 	if (filterpat && !vim_regexec(&regmatch, si->sn_name, (colnr_T)0))
 	    continue;
 
-	if (sid != -1 && sid != i)
-	    continue;
-
 	if ((d = dict_alloc()) == NULL
 		|| list_append_dict(l, d) == FAIL
 		|| dict_add_string(d, "name", si->sn_name) == FAIL
@@ -2151,10 +2162,9 @@ f_getscriptinfo(typval_T *argvars, typva
 				si->sn_state == SN_STATE_NOT_LOADED) == FAIL)
 	    return;
 
-	// When a filter pattern is specified to return information about only
-	// specific script(s), also add the script-local variables and
-	// functions.
-	if (sid != -1)
+	// When a script ID is specified, return information about only the
+	// specified script, and add the script-local variables and functions.
+	if (sid > 0)
 	{
 	    dict_T	*var_dict;
 
--- a/src/testdir/test_scriptnames.vim
+++ b/src/testdir/test_scriptnames.vim
@@ -91,6 +91,16 @@ func Test_getscriptinfo()
   call assert_fails("echo getscriptinfo('foobar')", 'E1206:')
 
   call assert_fails("echo getscriptinfo({'sid': []})", 'E745:')
+  call assert_fails("echo getscriptinfo({'sid': {}})", 'E728:')
+  call assert_fails("echo getscriptinfo({'sid': 0})", 'E475:')
+  call assert_fails("echo getscriptinfo({'sid': -1})", 'E475:')
+  call assert_fails("echo getscriptinfo({'sid': -999})", 'E475:')
+
+  echo getscriptinfo({'sid': '1'})
+  call assert_fails("vim9cmd echo getscriptinfo({'sid': '1'})", 'E1030:')
+
+  let max_sid = max(map(getscriptinfo(), { k, v -> v.sid }))
+  call assert_equal([], getscriptinfo({'sid': max_sid + 1}))
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1431,
+/**/
     1430,
 /**/
     1429,