From b7474e065b82d930f8da472440282ea7654d491d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 19 Apr 2006 16:09:06 +0000 Subject: 22416, tweaked: math functions via shell functions unposted: add styles to pick-web-browser --- Src/builtin.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- Src/exec.c | 11 +--- Src/math.c | 64 +++++++++++++++++---- Src/module.c | 10 ++-- Src/zsh.h | 5 +- 5 files changed, 239 insertions(+), 27 deletions(-) (limited to 'Src') diff --git a/Src/builtin.c b/Src/builtin.c index 7dca28a58..05203d485 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -46,7 +46,7 @@ static struct builtin builtins[] = BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL), BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL), BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmrs", NULL), - BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "tUXwkz", "u"), + BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "ktUwXz", "u"), BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL), BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL), BUILTIN("bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL), @@ -72,7 +72,7 @@ static struct builtin builtins[] = BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "nlre:IRWAdDfEimpPa", NULL), BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"), - BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmtuUz", NULL), + BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtuUz", 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), @@ -2476,6 +2476,43 @@ eval_autoload(Shfunc shf, char *name, Options ops, int func) (OPT_ISSET(ops,'z') ? 0 : 1)), 1); } + +/* List a user-defined math function. */ +static void +listusermathfunc(MathFunc p) +{ + int showargs; + + if (p->module) + showargs = 3; + else if (p->maxargs != (p->minargs ? p->minargs : -1)) + showargs = 2; + else if (p->minargs) + showargs = 1; + else + showargs = 0; + + printf("functions -M %s", p->name); + if (showargs) { + printf(" %d", p->minargs); + showargs--; + } + if (showargs) { + printf(" %d", p->maxargs); + showargs--; + } + if (showargs) { + /* + * function names are not required to consist of ident characters + */ + putchar(' '); + quotedzputs(p->module, stdout); + showargs--; + } + putchar('\n'); +} + + /* Display or change the attributes of shell functions. * * If called as autoload, it will define a new autoloaded * * (undefined) shell function. */ @@ -2522,6 +2559,141 @@ bin_functions(char *name, char **argv, Options ops, int func) if (OPT_PLUS(ops,'f') || OPT_ISSET(ops,'+')) pflags |= PRINT_NAMEONLY; + if (OPT_MINUS(ops,'M') || OPT_PLUS(ops,'M')) { + MathFunc p, q; + /* + * Add/remove/list function as mathematical. + */ + if (on || off || pflags || OPT_ISSET(ops,'X') || OPT_ISSET(ops,'u') + || OPT_ISSET(ops,'U') || OPT_ISSET(ops,'w')) { + zwarnnam(name, "invalid option(s)", NULL, 0); + return 1; + } + if (!*argv) { + /* List functions. */ + queue_signals(); + for (p = mathfuncs; p; p = p->next) + if (p->flags & MFF_USERFUNC) + listusermathfunc(p); + unqueue_signals(); + } else if (OPT_ISSET(ops,'m')) { + /* List matching functions. */ + for (; *argv; argv++) { + tokenize(*argv); + if ((pprog = patcompile(*argv, PAT_STATIC, 0))) { + queue_signals(); + for (p = mathfuncs, q = NULL; p; q = p, p = p->next) { + MathFunc next; + do { + next = NULL; + if ((p->flags & MFF_USERFUNC) && + pattry(pprog, p->name)) { + if (OPT_PLUS(ops,'M')) { + next = p->next; + removemathfunc(q, p); + p = next; + } else + listusermathfunc(p); + } + /* if we deleted one, retry with the new p */ + } while (next); + } + unqueue_signals(); + } else { + untokenize(*argv); + zwarnnam(name, "bad pattern : %s", *argv, 0); + returnval = 1; + } + } + } else if (OPT_PLUS(ops,'M')) { + /* Delete functions. -m is allowed but is handled above. */ + for (; *argv; argv++) { + queue_signals(); + for (p = mathfuncs, q = NULL; p; q = p, p = p->next) { + if (!strcmp(p->name, *argv)) { + if (!(p->flags & MFF_USERFUNC)) { + zwarnnam(name, "+M %s: is a library function", + *argv, 0); + returnval = 1; + break; + } + removemathfunc(q, p); + break; + } + } + unqueue_signals(); + } + } else { + /* Add a function */ + int minargs = 0, maxargs = -1; + char *funcname = *argv++; + char *modname = NULL; + char *ptr; + + for (ptr = funcname; *ptr; ptr++) + if (!iident(*ptr)) + break; + if (idigit(*funcname) || funcname == ptr || *ptr) { + zwarnnam(name, "-M %s: bad math function name", funcname, 0); + return 1; + } + + if (*argv) { + minargs = (int)zstrtol(*argv, &ptr, 0); + if (minargs < 0 || *ptr) { + zwarnnam(name, "-M: invalid min number of arguments: %s", + *argv, 0); + return 1; + } + maxargs = minargs; + argv++; + } + if (*argv) { + maxargs = (int)zstrtol(*argv, &ptr, 0); + if (maxargs < -1 || + (maxargs != -1 && maxargs < minargs) || + *ptr) { + zwarnnam(name, + "-M: invalid max number of arguments: %s", + *argv, 0); + return 1; + } + argv++; + } + if (*argv) + modname = *argv++; + if (*argv) { + zwarnnam(name, "-M: too many arguments", NULL, 0); + return 1; + } + + p = (MathFunc)zshcalloc(sizeof(struct mathfunc)); + p->name = ztrdup(funcname); + p->flags = MFF_USERFUNC; + p->module = modname ? ztrdup(modname) : NULL; + p->minargs = minargs; + p->maxargs = maxargs; + + queue_signals(); + for (q = mathfuncs; q; q = q->next) { + if (!strcmp(q->name, funcname)) { + zwarnnam(name, "-M %s: function already exists", + funcname, 0); + zsfree(p->name); + zsfree(p->module); + zfree(p, sizeof(struct mathfunc)); + return 1; + } + } + + p->next = mathfuncs; + mathfuncs = p; + unqueue_signals(); + } + + return returnval; + } + /* If no arguments given, we will print functions. If flags * * are given, we will print only functions containing these * * flags, else we'll print them all. */ diff --git a/Src/exec.c b/Src/exec.c index bb0e4161e..4612c9c1e 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -142,7 +142,6 @@ mod_export Funcstack funcstack; #define execerr() if (!forked) { lastval = 1; goto done; } else _exit(1) -static LinkList args; static int doneps4; static char *STTYval; @@ -464,7 +463,7 @@ isgooderr(int e, char *dir) /**/ void -execute(UNUSED(Cmdnam cmdname), int dash, int defpath) +execute(LinkList args, int dash, int defpath) { Cmdnam cn; char buf[MAXCMDLEN], buf2[MAXCMDLEN]; @@ -482,15 +481,12 @@ execute(UNUSED(Cmdnam cmdname), int dash, int defpath) * we first run the stty command with the value of this * * parameter as it arguments. */ if ((s = STTYval) && isatty(0) && (GETPGRP() == getpid())) { - LinkList exargs = args; char *t = tricat("stty", " ", s); STTYval = 0; /* this prevents infinite recursion */ zsfree(s); - args = NULL; execstring(t, 1, 0); zsfree(t); - args = exargs; } else if (s) { STTYval = 0; zsfree(s); @@ -1827,6 +1823,7 @@ static void execcmd(Estate state, int input, int output, int how, int last1) { HashNode hn = NULL; + LinkList args; LinkNode node; Redir fn; struct multio *mfds[10]; @@ -2638,7 +2635,7 @@ execcmd(Estate state, int input, int output, int how, int last1) zsfree(STTYval); STTYval = 0; } - execute((Cmdnam) hn, cflags & BINF_DASH, use_defpath); + execute(args, cflags & BINF_DASH, use_defpath); } else { /* ( ... ) */ DPUTS(varspc, "BUG: assignment before complex command"); @@ -4094,7 +4091,6 @@ execsave(void) struct execstack *es; es = (struct execstack *) malloc(sizeof(struct execstack)); - es->args = args; es->list_pipe_pid = list_pipe_pid; es->nowait = nowait; es->pline_level = pline_level; @@ -4122,7 +4118,6 @@ execrestore(void) struct execstack *en; DPUTS(!exstack, "BUG: execrestore() without execsave()"); - args = exstack->args; list_pipe_pid = exstack->list_pipe_pid; nowait = exstack->nowait; pline_level = exstack->pline_level; diff --git a/Src/math.c b/Src/math.c index acf7bdd11..b14c1cd7a 100644 --- a/Src/math.c +++ b/Src/math.c @@ -42,6 +42,14 @@ int noeval; /**/ mod_export mnumber zero_mnumber; +/* + * The last value we computed: note this isn't cleared + * until the next computation, unlike unlike yyval. + * Everything else is saved and returned to allow recursive calls. + */ +/**/ +mnumber lastmathval; + /* last input base we used */ /**/ @@ -582,22 +590,42 @@ callmathfunc(char *o) a[strlen(a) - 1] = '\0'; if ((f = getmathfunc(n, 1))) { - if (f->flags & MFF_STR) + if (f->flags & MFF_STR) { return f->sfunc(n, a, f->funcid); - else { + } else { int argc = 0; - mnumber *argv = NULL, *q; + mnumber *argv = NULL, *q, marg; LinkList l = newlinklist(); LinkNode node; + if (f->flags & MFF_USERFUNC) { + /* first argument is function name: always use mathfunc */ + addlinknode(l, n); + } + while (iblank(*a)) a++; while (*a) { if (*a) { argc++; - q = (mnumber *) zhalloc(sizeof(mnumber)); - *q = mathevall(a, ARGPREC, &a); - addlinknode(l, q); + if (f->flags & MFF_USERFUNC) { + /* need to pass strings */ + char *str; + marg = mathevall(a, ARGPREC, &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 { + q = (mnumber *) zhalloc(sizeof(mnumber)); + *q = mathevall(a, ARGPREC, &a); + addlinknode(l, q); + } if (errflag || mtok != COMMA) break; } @@ -608,12 +636,24 @@ callmathfunc(char *o) if (!errflag) { if (argc >= f->minargs && (f->maxargs < 0 || argc <= f->maxargs)) { - if (argc) { - q = argv = (mnumber *)zhalloc(argc * sizeof(mnumber)); - for (node = firstnode(l); node; incnode(node)) - *q++ = *(mnumber *)getdata(node); + if (f->flags & MFF_USERFUNC) { + char *shfnam = f->module ? f->module : n; + Eprog prog = getshfunc(shfnam); + if (prog == &dummy_eprog) + zerr("no such function: %s", shfnam, 0); + else { + doshfunc(n, prog, l, 0, 1); + return lastmathval; + } + } else { + if (argc) { + q = argv = + (mnumber *)zhalloc(argc * sizeof(mnumber)); + for (node = firstnode(l); node; incnode(node)) + *q++ = *(mnumber *)getdata(node); + } + return f->nfunc(n, argc, argv, f->funcid); } - return f->nfunc(n, argc, argv, f->funcid); } else zerr("wrong number of arguments: %s", o, 0); } @@ -1013,7 +1053,7 @@ mathevall(char *s, int prek, char **ep) sp = xsp; stack = xstack; } - return ret; + return lastmathval = ret; } diff --git a/Src/module.c b/Src/module.c index 17daffc2d..de3fd9932 100644 --- a/Src/module.c +++ b/Src/module.c @@ -1384,7 +1384,7 @@ bin_zmodload_math(char *nam, char **args, Options ops) MathFunc p; for (p = mathfuncs; p; p = p->next) { - if (p->module) { + if (!(p->flags & MFF_USERFUNC) && p->module) { if (OPT_ISSET(ops,'L')) { fputs("zmodload -af", stdout); printf(" %s %s\n", p->module, p->name); @@ -2085,7 +2085,8 @@ add_autoparam(char *nam, char *module) MathFunc mathfuncs; /**/ -static void removemathfunc(MathFunc previous, MathFunc current) +void +removemathfunc(MathFunc previous, MathFunc current) { if (previous) previous->next = current->next; @@ -2105,7 +2106,7 @@ getmathfunc(char *name, int autol) for (p = mathfuncs; p; q = p, p = p->next) if (!strcmp(name, p->name)) { - if (autol && p->module) { + if (autol && p->module && !(p->flags & MFF_USERFUNC)) { char *n = dupstring(p->module); removemathfunc(q, p); @@ -2131,7 +2132,7 @@ addmathfunc(MathFunc f) for (p = mathfuncs; p; q = p, p = p->next) if (!strcmp(f->name, p->name)) { - if (p->module) { + if (p->module && !(p->flags & MFF_USERFUNC)) { /* * Autoloadable, replace. */ @@ -2206,6 +2207,7 @@ deletemathfunc(MathFunc f) else mathfuncs = f->next; + /* the following applies to both unloaded and user-defined functions */ if (f->module) { zsfree(f->name); zsfree(f->module); diff --git a/Src/zsh.h b/Src/zsh.h index 6a6ff2fe4..092e05c0c 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -86,8 +86,12 @@ struct mathfunc { int funcid; }; +/* Math function takes a string argument */ #define MFF_STR 1 +/* Math function has been loaded from library */ #define MFF_ADDED 2 +/* Math function is implemented by a shell function */ +#define MFF_USERFUNC 4 #define NUMMATHFUNC(name, func, min, max, id) \ { NULL, name, 0, func, NULL, NULL, min, max, id } @@ -815,7 +819,6 @@ struct process { struct execstack { struct execstack *next; - LinkList args; pid_t list_pipe_pid; int nowait; int pline_level; -- cgit 1.4.1