summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2006-04-19 16:09:06 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2006-04-19 16:09:06 +0000
commitb7474e065b82d930f8da472440282ea7654d491d (patch)
tree07ae2866628b6fd4f180824d566de06be94796ed /Src
parent5c2d5b013e1d8cab43ca19507bf669693c95cd95 (diff)
downloadzsh-b7474e065b82d930f8da472440282ea7654d491d.tar.gz
zsh-b7474e065b82d930f8da472440282ea7654d491d.zip
22416, tweaked: math functions via shell functions
unposted: add styles to pick-web-browser
Diffstat (limited to 'Src')
-rw-r--r--Src/builtin.c176
-rw-r--r--Src/exec.c11
-rw-r--r--Src/math.c64
-rw-r--r--Src/module.c10
-rw-r--r--Src/zsh.h5
5 files changed, 239 insertions, 27 deletions
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;