zsh-workers
 help / color / mirror / code / Atom feed
* Re: Question with no answer, a="1+1"; $(( mathfun($a) ))
       [not found] ` <1487840080.4078992.890215168.6CBEA51D@webmail.messagingengine.com>
@ 2017-02-23 10:11   ` Peter Stephenson
  2017-02-23 10:38     ` Sebastian Gniazdowski
  0 siblings, 1 reply; 2+ messages in thread
From: Peter Stephenson @ 2017-02-23 10:11 UTC (permalink / raw)
  To: zsh-workers

On Thu, 23 Feb 2017 00:54:40 -0800
Sebastian Gniazdowski <psprint2@fastmail.com> wrote:
> But:
> 
> % mfun() { echo "dbg: $1"; }; functions -M mfun 1 1; val="1+2"; echo $((
> mfun($val) ))
> dbg: 3
> 3
> 
> This is probably a show stopper, but maybe I can accomplish the "nicer"
> goal some other way, maybe even with math functions after all?

(Moved to workers as this is a new implementation.)

This isn't actually difficult to fix, and it fills a gap since
internally implemented math functions have always had an option for
string arguments.

Note there is no halfway house: if you get a string argument, it's
*exactly* what's been passed in after substitution, and you get to
extract white space, commas, whatever, yourself.

pws

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index bdd1ad1..65bebdf 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -840,7 +840,7 @@ point numbers are not permitted.
 )
 findex(functions)
 xitem(tt(functions) [ {tt(PLUS())|tt(-)}tt(UkmtTuWz) ] [ tt(-x) var(num) ] [ var(name) ... ])
-xitem(tt(functions -M) var(mathfn) [ var(min) [ var(max) [ var(shellfn) ] ] ])
+xitem(tt(functions -M) [tt(-s)] var(mathfn) [ var(min) [ var(max) [ var(shellfn) ] ] ])
 xitem(tt(functions -M) [ tt(-m) var(pattern) ... ])
 item(tt(functions +M) [ tt(-m) ] var(mathfn) ... )(
 Equivalent to tt(typeset -f), with the exception of the tt(-x),
@@ -882,6 +882,13 @@ The result of the last arithmetical expression evaluated
 inside the shell function (even if it is a form that normally only returns
 a status) gives the result of the mathematical function.
 
+If the additional option tt(-s) is given to tt(functions -M), the
+argument to the function is a single string: anything between the
+opening and matching closing parenthesis is passed to the function as a
+single argument, even if it includes commas or white space.  The minimum
+and maximum argument specifiers must thererfore be 1 if given.  An empty
+argument list is passed as a zero-length string.
+
 tt(functions -M) with no arguments lists all such user-defined functions in
 the same form as a definition.  With the additional option tt(-m) and
 a list of arguments, all functions whose var(mathfn) matches one of
@@ -898,6 +905,13 @@ For example, the following prints the cube of 3:
 example(zmath_cube+LPAR()RPAR() { (( $1 * $1 * $1 )) }
 functions -M cube 1 1 zmath_cube
 print $(( cube+LPAR()3+RPAR() )))
+
+The following string function takes a single argument, including
+the commas, so prints 11:
+
+example(stringfn+LPAR()RPAR() { (( $#1 )) }
+functions -Ms stringfn
+print $(( stringfn+LPAR()foo,bar,rod+RPAR() )))
 )
 module(getcap)(zsh/cap)
 findex(getln)
diff --git a/Src/builtin.c b/Src/builtin.c
index 16784d7..b72a7a4 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -72,7 +72,7 @@ static struct builtin builtins[] =
     BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL),
     BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
     BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"),
-    BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtTuUWx:z", NULL),
+    BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMstTuUWx:z", NULL),
     BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
     BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
     BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "Ldfmrv", NULL),
@@ -2993,7 +2993,7 @@ listusermathfunc(MathFunc p)
     else
 	showargs = 0;
 
-    printf("functions -M %s", p->name);
+    printf("functions -M%s %s", (p->flags & MFF_STR) ? "s" : "", p->name);
     if (showargs) {
 	printf(" %d", p->minargs);
 	showargs--;
@@ -3220,11 +3220,18 @@ bin_functions(char *name, char **argv, Options ops, int func)
 	    }
 	} else {
 	    /* Add a function */
-	    int minargs = 0, maxargs = -1;
+	    int minargs, maxargs;
 	    char *funcname = *argv++;
 	    char *modname = NULL;
 	    char *ptr;
 
+	    if (OPT_ISSET(ops,'s')) {
+		minargs = maxargs = 1;
+	    } else {
+		minargs = 0;
+		maxargs = -1;
+	    }
+
 	    ptr = itype_end(funcname, IIDENT, 0);
 	    if (idigit(*funcname) || funcname == ptr || *ptr) {
 		zwarnnam(name, "-M %s: bad math function name", funcname);
@@ -3238,6 +3245,10 @@ bin_functions(char *name, char **argv, Options ops, int func)
 			     *argv);
 		    return 1;
 		}
+		if (OPT_ISSET(ops,'s') && minargs != 1) {
+		    zwarnnam(name, "-Ms: must take a single string argumet");
+		    return 1;
+		}
 		maxargs = minargs;
 		argv++;
 	    }
@@ -3251,6 +3262,10 @@ bin_functions(char *name, char **argv, Options ops, int func)
 			     *argv);
 		    return 1;
 		}
+		if (OPT_ISSET(ops,'s') && maxargs != 1) {
+		    zwarnnam(name, "-Ms: must take a single string argumet");
+		    return 1;
+		}
 		argv++;
 	    }
 	    if (*argv)
@@ -3263,6 +3278,8 @@ bin_functions(char *name, char **argv, Options ops, int func)
 	    p = (MathFunc)zshcalloc(sizeof(struct mathfunc));
 	    p->name = ztrdup(funcname);
 	    p->flags = MFF_USERFUNC;
+	    if (OPT_ISSET(ops,'s'))
+		p->flags |= MFF_STR;
 	    p->module = modname ? ztrdup(modname) : NULL;
 	    p->minargs = minargs;
 	    p->maxargs = maxargs;
diff --git a/Src/math.c b/Src/math.c
index 37981cf..f19c0ed 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -974,7 +974,7 @@ callmathfunc(char *o)
     a[strlen(a) - 1] = '\0';
 
     if ((f = getmathfunc(n, 1))) {
-	if (f->flags & MFF_STR) {
+	if ((f->flags & (MFF_STR|MFF_USERFUNC)) == MFF_STR) {
 	    return f->sfunc(n, a, f->funcid);
 	} else {
 	    int argc = 0;
@@ -987,22 +987,34 @@ callmathfunc(char *o)
 		addlinknode(l, n);
 	    }
 
-	    while (iblank(*a))
-		a++;
+	    if (f->flags & MFF_STR) {
+		if (!*a) {
+		    addlinknode(l, dupstring(""));
+		    argc++;
+		}
+	    } else {
+		while (iblank(*a))
+		    a++;
+	    }
 	    while (*a) {
 		if (*a) {
 		    argc++;
 		    if (f->flags & MFF_USERFUNC) {
 			/* need to pass strings */
 			char *str;
-			marg = mathevall(a, MPREC_ARG, &a);
-			if (marg.type & MN_FLOAT) {
-			    /* convfloat is off the heap */
-			    str = convfloat(marg.u.d, 0, 0, NULL);
+			if (f->flags & MFF_STR) {
+			    str = dupstring(a);
+			    a = "";
 			} else {
-			    char buf[BDIGBUFSIZE];
-			    convbase(buf, marg.u.l, 10);
-			    str = dupstring(buf);
+			    marg = mathevall(a, MPREC_ARG, &a);
+			    if (marg.type & MN_FLOAT) {
+				/* convfloat is off the heap */
+				str = convfloat(marg.u.d, 0, 0, NULL);
+			    } else {
+				char buf[BDIGBUFSIZE];
+				convbase(buf, marg.u.l, 10);
+				str = dupstring(buf);
+			    }
 			}
 			addlinknode(l, str);
 		    } else {
diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst
index 0cf2b58..6a675e0 100644
--- a/Test/C04funcdef.ztst
+++ b/Test/C04funcdef.ztst
@@ -102,6 +102,24 @@
 >4
 >5
 
+  strmathfunc() {
+    if [[ $0 = stralpha ]]; then
+       set -- ${1//[^[:alpha:]]}
+    fi
+    (( $#1 ))
+  }
+  functions -Ms strlen 1 1 strmathfunc
+  functions -Ms stralpha 1 1 strmathfunc
+  print $(( strlen(this, is, a, raw, string) ))
+  print $(( strlen() ))
+  print $(( stralpha(this, is, a, raw, string) ))
+  print $(( stralpha() ))
+0:User-defined math functions, string arguments
+>24
+>0
+>16
+>0
+
   command_not_found_handler() {
     print "Great News!  I've handled the command:"
     print "$1"


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Question with no answer, a="1+1"; $(( mathfun($a) ))
  2017-02-23 10:11   ` Question with no answer, a="1+1"; $(( mathfun($a) )) Peter Stephenson
@ 2017-02-23 10:38     ` Sebastian Gniazdowski
  0 siblings, 0 replies; 2+ messages in thread
From: Sebastian Gniazdowski @ 2017-02-23 10:38 UTC (permalink / raw)
  To: zsh-workers

Hello,
that's cool. I've spotted those:

 +                   zwarnnam(name, "-Ms: must take a single string
 argumet");

 +                   zwarnnam(name, "-Ms: must take a single string
 argumet");

-- 
  Sebastian Gniazdowski
  psprint2@fastmail.com

On Thu, Feb 23, 2017, at 02:11 AM, Peter Stephenson wrote:
> On Thu, 23 Feb 2017 00:54:40 -0800
> Sebastian Gniazdowski <psprint2@fastmail.com> wrote:
> > But:
> > 
> > % mfun() { echo "dbg: $1"; }; functions -M mfun 1 1; val="1+2"; echo $((
> > mfun($val) ))
> > dbg: 3
> > 3
> > 
> > This is probably a show stopper, but maybe I can accomplish the "nicer"
> > goal some other way, maybe even with math functions after all?
> 
> (Moved to workers as this is a new implementation.)
> 
> This isn't actually difficult to fix, and it fills a gap since
> internally implemented math functions have always had an option for
> string arguments.
> 
> Note there is no halfway house: if you get a string argument, it's
> *exactly* what's been passed in after substitution, and you get to
> extract white space, commas, whatever, yourself.
> 
> pws
> 
> diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
> index bdd1ad1..65bebdf 100644
> --- a/Doc/Zsh/builtins.yo
> +++ b/Doc/Zsh/builtins.yo
> @@ -840,7 +840,7 @@ point numbers are not permitted.
>  )
>  findex(functions)
>  xitem(tt(functions) [ {tt(PLUS())|tt(-)}tt(UkmtTuWz) ] [ tt(-x) var(num)
>  ] [ var(name) ... ])
> -xitem(tt(functions -M) var(mathfn) [ var(min) [ var(max) [ var(shellfn)
> ] ] ])
> +xitem(tt(functions -M) [tt(-s)] var(mathfn) [ var(min) [ var(max) [
> var(shellfn) ] ] ])
>  xitem(tt(functions -M) [ tt(-m) var(pattern) ... ])
>  item(tt(functions +M) [ tt(-m) ] var(mathfn) ... )(
>  Equivalent to tt(typeset -f), with the exception of the tt(-x),
> @@ -882,6 +882,13 @@ The result of the last arithmetical expression
> evaluated
>  inside the shell function (even if it is a form that normally only
>  returns
>  a status) gives the result of the mathematical function.
>  
> +If the additional option tt(-s) is given to tt(functions -M), the
> +argument to the function is a single string: anything between the
> +opening and matching closing parenthesis is passed to the function as a
> +single argument, even if it includes commas or white space.  The minimum
> +and maximum argument specifiers must thererfore be 1 if given.  An empty
> +argument list is passed as a zero-length string.
> +
>  tt(functions -M) with no arguments lists all such user-defined functions
>  in
>  the same form as a definition.  With the additional option tt(-m) and
>  a list of arguments, all functions whose var(mathfn) matches one of
> @@ -898,6 +905,13 @@ For example, the following prints the cube of 3:
>  example(zmath_cube+LPAR()RPAR() { (( $1 * $1 * $1 )) }
>  functions -M cube 1 1 zmath_cube
>  print $(( cube+LPAR()3+RPAR() )))
> +
> +The following string function takes a single argument, including
> +the commas, so prints 11:
> +
> +example(stringfn+LPAR()RPAR() { (( $#1 )) }
> +functions -Ms stringfn
> +print $(( stringfn+LPAR()foo,bar,rod+RPAR() )))
>  )
>  module(getcap)(zsh/cap)
>  findex(getln)
> diff --git a/Src/builtin.c b/Src/builtin.c
> index 16784d7..b72a7a4 100644
> --- a/Src/builtin.c
> +++ b/Src/builtin.c
> @@ -72,7 +72,7 @@ static struct builtin builtins[] =
>      BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W",
>      NULL),
>      BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
>      BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL |
>      BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0,
>      "E:%F:%HL:%R:%Z:%ghlprtux", "E"),
> -    BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0,
> "kmMtTuUWx:z", NULL),
> +    BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0,
> "kmMstTuUWx:z", NULL),
>      BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
>      BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
>      BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "Ldfmrv",
>      NULL),
> @@ -2993,7 +2993,7 @@ listusermathfunc(MathFunc p)
>      else
>  	showargs = 0;
>  
> -    printf("functions -M %s", p->name);
> +    printf("functions -M%s %s", (p->flags & MFF_STR) ? "s" : "",
> p->name);
>      if (showargs) {
>  	printf(" %d", p->minargs);
>  	showargs--;
> @@ -3220,11 +3220,18 @@ bin_functions(char *name, char **argv, Options
> ops, int func)
>  	    }
>  	} else {
>  	    /* Add a function */
> -           int minargs = 0, maxargs = -1;
> +           int minargs, maxargs;
>  	    char *funcname = *argv++;
>  	    char *modname = NULL;
>  	    char *ptr;
>  
> +           if (OPT_ISSET(ops,'s')) {
> +               minargs = maxargs = 1;
> +           } else {
> +               minargs = 0;
> +               maxargs = -1;
> +           }
> +
>  	    ptr = itype_end(funcname, IIDENT, 0);
>  	    if (idigit(*funcname) || funcname == ptr || *ptr) {
>  		zwarnnam(name, "-M %s: bad math function name", funcname);
> @@ -3238,6 +3245,10 @@ bin_functions(char *name, char **argv, Options
> ops, int func)
>  			     *argv);
>  		    return 1;
>  		}
> +               if (OPT_ISSET(ops,'s') && minargs != 1) {
> +                   zwarnnam(name, "-Ms: must take a single string
> argumet");
> +                   return 1;
> +               }
>  		maxargs = minargs;
>  		argv++;
>  	    }
> @@ -3251,6 +3262,10 @@ bin_functions(char *name, char **argv, Options
> ops, int func)
>  			     *argv);
>  		    return 1;
>  		}
> +               if (OPT_ISSET(ops,'s') && maxargs != 1) {
> +                   zwarnnam(name, "-Ms: must take a single string
> argumet");
> +                   return 1;
> +               }
>  		argv++;
>  	    }
>  	    if (*argv)
> @@ -3263,6 +3278,8 @@ bin_functions(char *name, char **argv, Options ops,
> int func)
>  	    p = (MathFunc)zshcalloc(sizeof(struct mathfunc));
>  	    p->name = ztrdup(funcname);
>  	    p->flags = MFF_USERFUNC;
> +           if (OPT_ISSET(ops,'s'))
> +               p->flags |= MFF_STR;
>  	    p->module = modname ? ztrdup(modname) : NULL;
>  	    p->minargs = minargs;
>  	    p->maxargs = maxargs;
> diff --git a/Src/math.c b/Src/math.c
> index 37981cf..f19c0ed 100644
> --- a/Src/math.c
> +++ b/Src/math.c
> @@ -974,7 +974,7 @@ callmathfunc(char *o)
>      a[strlen(a) - 1] = '\0';
>  
>      if ((f = getmathfunc(n, 1))) {
> -       if (f->flags & MFF_STR) {
> +       if ((f->flags & (MFF_STR|MFF_USERFUNC)) == MFF_STR) {
>  	    return f->sfunc(n, a, f->funcid);
>  	} else {
>  	    int argc = 0;
> @@ -987,22 +987,34 @@ callmathfunc(char *o)
>  		addlinknode(l, n);
>  	    }
>  
> -           while (iblank(*a))
> -               a++;
> +           if (f->flags & MFF_STR) {
> +               if (!*a) {
> +                   addlinknode(l, dupstring(""));
> +                   argc++;
> +               }
> +           } else {
> +               while (iblank(*a))
> +                   a++;
> +           }
>  	    while (*a) {
>  		if (*a) {
>  		    argc++;
>  		    if (f->flags & MFF_USERFUNC) {
>  			/* need to pass strings */
>  			char *str;
> -                       marg = mathevall(a, MPREC_ARG, &a);
> -                       if (marg.type & MN_FLOAT) {
> -                           /* convfloat is off the heap */
> -                           str = convfloat(marg.u.d, 0, 0, NULL);
> +                       if (f->flags & MFF_STR) {
> +                           str = dupstring(a);
> +                           a = "";
>  			} else {
> -                           char buf[BDIGBUFSIZE];
> -                           convbase(buf, marg.u.l, 10);
> -                           str = dupstring(buf);
> +                           marg = mathevall(a, MPREC_ARG, &a);
> +                           if (marg.type & MN_FLOAT) {
> +                               /* convfloat is off the heap */
> +                               str = convfloat(marg.u.d, 0, 0, NULL);
> +                           } else {
> +                               char buf[BDIGBUFSIZE];
> +                               convbase(buf, marg.u.l, 10);
> +                               str = dupstring(buf);
> +                           }
>  			}
>  			addlinknode(l, str);
>  		    } else {
> diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst
> index 0cf2b58..6a675e0 100644
> --- a/Test/C04funcdef.ztst
> +++ b/Test/C04funcdef.ztst
> @@ -102,6 +102,24 @@
>  >4
>  >5
>  
> +  strmathfunc() {
> +    if [[ $0 = stralpha ]]; then
> +       set -- ${1//[^[:alpha:]]}
> +    fi
> +    (( $#1 ))
> +  }
> +  functions -Ms strlen 1 1 strmathfunc
> +  functions -Ms stralpha 1 1 strmathfunc
> +  print $(( strlen(this, is, a, raw, string) ))
> +  print $(( strlen() ))
> +  print $(( stralpha(this, is, a, raw, string) ))
> +  print $(( stralpha() ))
> +0:User-defined math functions, string arguments
> +>24
> +>0
> +>16
> +>0
> +
>    command_not_found_handler() {
>      print "Great News!  I've handled the command:"
>      print "$1"


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-02-23 10:38 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20170223085553epcas1p380bee4b00b62d96a31c996e00e758903@epcas1p3.samsung.com>
     [not found] ` <1487840080.4078992.890215168.6CBEA51D@webmail.messagingengine.com>
2017-02-23 10:11   ` Question with no answer, a="1+1"; $(( mathfun($a) )) Peter Stephenson
2017-02-23 10:38     ` Sebastian Gniazdowski

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).