diff src/userfunc.c @ 17606:ff097edaae89 v8.1.1800

patch 8.1.1800: function call functions have too many arguments commit https://github.com/vim/vim/commit/c6538bcc1cdd1fb83732f22fdc69bd9bb66f968a Author: Bram Moolenaar <Bram@vim.org> Date: Sat Aug 3 18:17:11 2019 +0200 patch 8.1.1800: function call functions have too many arguments Problem: Function call functions have too many arguments. Solution: Pass values in a funcexe_T struct.
author Bram Moolenaar <Bram@vim.org>
date Sat, 03 Aug 2019 18:30:07 +0200
parents 9088fafff9b3
children e259d11e2900
line wrap: on
line diff
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -432,12 +432,7 @@ get_func_tv(
     int		len,		// length of "name" or -1 to use strlen()
     typval_T	*rettv,
     char_u	**arg,		// argument, pointing to the '('
-    linenr_T	firstline,	// first line of range
-    linenr_T	lastline,	// last line of range
-    int		*doesrange,	// return: function handled range
-    int		evaluate,
-    partial_T	*partial,	// for extra arguments
-    dict_T	*selfdict)	// Dictionary for "self"
+    funcexe_T	*funcexe)	// various values
 {
     char_u	*argp;
     int		ret = OK;
@@ -448,12 +443,13 @@ get_func_tv(
      * Get the arguments.
      */
     argp = *arg;
-    while (argcount < MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc))
+    while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0
+						  : funcexe->partial->pt_argc))
     {
 	argp = skipwhite(argp + 1);	    /* skip the '(' or ',' */
 	if (*argp == ')' || *argp == ',' || *argp == NUL)
 	    break;
-	if (eval1(&argp, &argvars[argcount], evaluate) == FAIL)
+	if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL)
 	{
 	    ret = FAIL;
 	    break;
@@ -483,8 +479,7 @@ get_func_tv(
 								  &argvars[i];
 	}
 
-	ret = call_func(name, len, rettv, argcount, argvars, NULL,
-		 firstline, lastline, doesrange, evaluate, partial, selfdict);
+	ret = call_func(name, len, rettv, argcount, argvars, funcexe);
 
 	funcargs.ga_len -= i;
     }
@@ -1416,7 +1411,6 @@ func_call(
     listitem_T	*item;
     typval_T	argv[MAX_FUNC_ARGS + 1];
     int		argc = 0;
-    int		dummy;
     int		r = 0;
 
     for (item = args->vval.v_list->lv_first; item != NULL;
@@ -1434,9 +1428,18 @@ func_call(
     }
 
     if (item == NULL)
-	r = call_func(name, -1, rettv, argc, argv, NULL,
-				 curwin->w_cursor.lnum, curwin->w_cursor.lnum,
-					     &dummy, TRUE, partial, selfdict);
+    {
+	funcexe_T funcexe;
+
+	funcexe.argv_func = NULL;
+	funcexe.firstline = curwin->w_cursor.lnum;
+	funcexe.lastline = curwin->w_cursor.lnum;
+	funcexe.doesrange = NULL;
+	funcexe.evaluate = TRUE;
+	funcexe.partial = partial;
+	funcexe.selfdict = selfdict;
+	r = call_func(name, -1, rettv, argc, argv, &funcexe);
+    }
 
     /* Free the arguments. */
     while (argc > 0)
@@ -1454,28 +1457,21 @@ call_callback(
     int		len,		// length of "name" or -1 to use strlen()
     typval_T	*rettv,		// return value goes here
     int		argcount,	// number of "argvars"
-    typval_T	*argvars,	// vars for arguments, must have "argcount"
+    typval_T	*argvars)	// vars for arguments, must have "argcount"
 				// PLUS ONE elements!
-    int		(* argv_func)(int, typval_T *, int),
-				// function to fill in argvars
-    linenr_T	firstline,	// first line of range
-    linenr_T	lastline,	// last line of range
-    int		*doesrange,	// return: function handled range
-    int		evaluate,
-    dict_T	*selfdict)	// Dictionary for "self"
 {
+    funcexe_T	funcexe;
+
+    vim_memset(&funcexe, 0, sizeof(funcexe));
+    funcexe.evaluate = TRUE;
+    funcexe.partial = callback->cb_partial;
     return call_func(callback->cb_name, len, rettv, argcount, argvars,
-	    argv_func, firstline, lastline, doesrange, evaluate,
-	    callback->cb_partial, selfdict);
+								     &funcexe);
 }
 
 /*
  * Call a function with its resolved parameters
  *
- * "argv_func", when not NULL, can be used to fill in arguments only when the
- * invoked function uses them.  It is called like this:
- *   new_argcount = argv_func(current_argcount, argv, called_func_argcount)
- *
  * Return FAIL when the function can't be called,  OK otherwise.
  * Also returns OK when an error was encountered while executing the function.
  */
@@ -1487,14 +1483,7 @@ call_func(
     int		argcount_in,	// number of "argvars"
     typval_T	*argvars_in,	// vars for arguments, must have "argcount"
 				// PLUS ONE elements!
-    int		(* argv_func)(int, typval_T *, int),
-				// function to fill in argvars
-    linenr_T	firstline,	// first line of range
-    linenr_T	lastline,	// last line of range
-    int		*doesrange,	// return: function handled range
-    int		evaluate,
-    partial_T	*partial,	// optional, can be NULL
-    dict_T	*selfdict_in)	// Dictionary for "self"
+    funcexe_T	*funcexe)	// more arguments
 {
     int		ret = FAIL;
     int		error = ERROR_NONE;
@@ -1506,9 +1495,10 @@ call_func(
     char_u	*name;
     int		argcount = argcount_in;
     typval_T	*argvars = argvars_in;
-    dict_T	*selfdict = selfdict_in;
+    dict_T	*selfdict = funcexe->selfdict;
     typval_T	argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */
     int		argv_clear = 0;
+    partial_T	*partial = funcexe->partial;
 
     // Make a copy of the name, if it comes from a funcref variable it could
     // be changed or deleted in the called function.
@@ -1518,15 +1508,15 @@ call_func(
 
     fname = fname_trans_sid(name, fname_buf, &tofree, &error);
 
-    *doesrange = FALSE;
+    if (funcexe->doesrange != NULL)
+	*funcexe->doesrange = FALSE;
 
     if (partial != NULL)
     {
 	/* When the function has a partial with a dict and there is a dict
 	 * argument, use the dict argument.  That is backwards compatible.
 	 * When the dict was bound explicitly use the one from the partial. */
-	if (partial->pt_dict != NULL
-		&& (selfdict_in == NULL || !partial->pt_auto))
+	if (partial->pt_dict != NULL && (selfdict == NULL || !partial->pt_auto))
 	    selfdict = partial->pt_dict;
 	if (error == ERROR_NONE && partial->pt_argc > 0)
 	{
@@ -1542,7 +1532,7 @@ call_func(
     /*
      * Execute the function if executing and no errors were detected.
      */
-    if (!evaluate)
+    if (!funcexe->evaluate)
     {
 	// Not evaluating, which means the return value is unknown.  This
 	// matters for giving error messages.
@@ -1590,11 +1580,12 @@ call_func(
 		error = ERROR_DELETED;
 	    else if (fp != NULL)
 	    {
-		if (argv_func != NULL)
-		    argcount = argv_func(argcount, argvars, fp->uf_args.ga_len);
-
-		if (fp->uf_flags & FC_RANGE)
-		    *doesrange = TRUE;
+		if (funcexe->argv_func != NULL)
+		    argcount = funcexe->argv_func(argcount, argvars,
+							   fp->uf_args.ga_len);
+
+		if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL)
+		    *funcexe->doesrange = TRUE;
 		if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len)
 		    error = ERROR_TOOFEW;
 		else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len)
@@ -1621,7 +1612,7 @@ call_func(
 		    }
 		    ++fp->uf_calls;
 		    call_user_func(fp, argcount, argvars, rettv,
-					       firstline, lastline,
+					 funcexe->firstline, funcexe->lastline,
 				  (fp->uf_flags & FC_DICT) ? selfdict : NULL);
 		    if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
 			/* Function was unreferenced while being used, free it
@@ -3112,6 +3103,8 @@ ex_call(exarg_T *eap)
 	lnum = eap->line1;
     for ( ; lnum <= eap->line2; ++lnum)
     {
+	funcexe_T funcexe;
+
 	if (!eap->skip && eap->addr_count > 0)
 	{
 	    if (lnum > curbuf->b_ml.ml_line_count)
@@ -3126,9 +3119,15 @@ ex_call(exarg_T *eap)
 	    curwin->w_cursor.coladd = 0;
 	}
 	arg = startarg;
-	if (get_func_tv(name, -1, &rettv, &arg,
-		    eap->line1, eap->line2, &doesrange,
-				   !eap->skip, partial, fudi.fd_dict) == FAIL)
+
+	funcexe.argv_func = NULL;
+	funcexe.firstline = eap->line1;
+	funcexe.lastline = eap->line2;
+	funcexe.doesrange = &doesrange;
+	funcexe.evaluate = !eap->skip;
+	funcexe.partial = partial;
+	funcexe.selfdict = fudi.fd_dict;
+	if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL)
 	{
 	    failed = TRUE;
 	    break;