Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: Question with no answer, a="1+1"; $(( mathfun($a) ))
- X-seq: zsh-workers 40622
- From: Peter Stephenson <p.stephenson@xxxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: Re: Question with no answer, a="1+1"; $(( mathfun($a) ))
- Date: Thu, 23 Feb 2017 10:11:09 +0000
- Cms-type: 201P
- In-reply-to: <1487840080.4078992.890215168.6CBEA51D@webmail.messagingengine.com>
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
- Organization: Samsung Cambridge Solution Centre
- References: <CGME20170223085553epcas1p380bee4b00b62d96a31c996e00e758903@epcas1p3.samsung.com> <1487840080.4078992.890215168.6CBEA51D@webmail.messagingengine.com>
On Thu, 23 Feb 2017 00:54:40 -0800
Sebastian Gniazdowski <psprint2@xxxxxxxxxxxx> 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"
Messages sorted by:
Reverse Date,
Date,
Thread,
Author