summaryrefslogtreecommitdiff
path: root/Src/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/builtin.c')
-rw-r--r--Src/builtin.c1512
1 files changed, 985 insertions, 527 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index 31f396d93..dd0d3e523 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -42,29 +42,30 @@ static struct builtin builtins[] =
BUILTIN("[", 0, bin_test, 0, -1, BIN_BRACKET, NULL, NULL),
BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL),
- BUILTIN("alias", BINF_MAGICEQUALS, bin_alias, 0, -1, 0, "Lgmr", NULL),
- BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "t", "u"),
+ BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmr", NULL),
+ BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "tUXwkz", "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),
BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL),
BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL),
BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL),
- BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfilrtux", NULL),
+ BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFLRTUZafghilrtux", NULL),
BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL),
BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL),
BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
BUILTIN("echo", BINF_PRINTOPTS | BINF_ECHOPTS, bin_print, 0, -1, BIN_ECHO, "neE", "-"),
BUILTIN("echotc", 0, bin_echotc, 1, -1, 0, NULL, NULL),
- BUILTIN("emulate", 0, bin_emulate, 1, 1, 0, "R", NULL),
+ BUILTIN("emulate", 0, bin_emulate, 1, 1, 0, "LR", NULL),
BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL),
BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
- BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZfilrtu", "x"),
+ BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "EFLRTUZafhilrtu", "xg"),
BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", NULL),
BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
- BUILTIN("functions", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "mtu", NULL),
+ BUILTIN("float", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "EFghlrtux", "E"),
+ BUILTIN("functions", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "mtuU", 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, "dfmrv", NULL),
@@ -74,11 +75,11 @@ static struct builtin builtins[] =
#endif
BUILTIN("history", 0, bin_fc, 0, -1, BIN_FC, "nrdDfEim", "l"),
- BUILTIN("integer", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "lrtux", "i"),
+ BUILTIN("integer", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ghlrtux", "i"),
BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL),
BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL),
BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
- BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZilrtu", NULL),
+ BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFLRTUZahilrtu", NULL),
BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL),
@@ -86,14 +87,18 @@ static struct builtin builtins[] =
BUILTIN("mem", 0, bin_mem, 0, 0, 0, "v", NULL),
#endif
+#if defined(ZSH_PAT_DEBUG)
+ BUILTIN("patdebug", 0, bin_patdebug, 1, -1, 0, "p", NULL),
+#endif
+
BUILTIN("popd", 0, bin_cd, 0, 2, BIN_POPD, NULL, NULL),
- BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "RDPnrslzNu0123456789pioOcm-", NULL),
+ BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "RDPbnrslzNu0123456789pioOcm-", NULL),
BUILTIN("pushd", 0, bin_cd, 0, 2, BIN_PUSHD, NULL, NULL),
BUILTIN("pushln", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, NULL, "-nz"),
BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL),
BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL),
BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL),
- BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfiltux", "r"),
+ BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFLRTUZafghiltux", "r"),
BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"),
BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL),
BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL),
@@ -107,7 +112,7 @@ static struct builtin builtins[] =
BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL),
BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL),
BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"),
- BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfilrtuxm", NULL),
+ BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFLRTUZafghilrtuxm", NULL),
BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL),
BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"),
BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"),
@@ -118,10 +123,8 @@ static struct builtin builtins[] =
BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL),
BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"),
BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"),
-
-#ifdef DYNAMIC
- BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "Laudi", NULL),
-#endif
+ BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ILabcfdipue", NULL),
+ BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL),
};
/****************************************/
@@ -131,7 +134,7 @@ static struct builtin builtins[] =
/* hash table containing builtin commands */
/**/
-HashTable builtintab;
+mod_export HashTable builtintab;
/**/
void
@@ -142,6 +145,7 @@ createbuiltintable(void)
builtintab->hash = hasher;
builtintab->emptytable = NULL;
builtintab->filltable = NULL;
+ builtintab->cmpnodes = strcmp;
builtintab->addnode = addhashnode;
builtintab->getnode = gethashnode;
builtintab->getnode2 = gethashnode2;
@@ -206,9 +210,10 @@ int
execbuiltin(LinkList args, Builtin bn)
{
LinkNode n;
- char ops[MAX_OPS], *arg, *pp, *name, **argv, **oargv, *optstr;
+ char ops[MAX_OPS], *arg, *pp, *name, *optstr;
char *oxarg, *xarg = NULL;
- int flags, sense, argc = 0, execop;
+ char typenumstr[] = TYPESET_OPTNUM;
+ int flags, sense, argc = 0, execop, xtr = isset(XTRACE), lxarg = 0;
/* initialise some static variables */
auxdata = NULL;
@@ -220,14 +225,11 @@ execbuiltin(LinkList args, Builtin bn)
arg = (char *) ugetnode(args);
-#ifdef DYNAMIC
if (!bn->handlerfunc) {
zwarnnam(name, "autoload failed", NULL, 0);
deletebuiltin(bn->nam);
return 1;
}
-#endif
-
/* get some information about the command */
flags = bn->flags;
optstr = bn->optstr;
@@ -249,12 +251,21 @@ execbuiltin(LinkList args, Builtin bn)
break;
}
/* save the options in xarg, for execution tracing */
- if (xarg) {
- oxarg = tricat(xarg, " ", arg);
- zsfree(xarg);
- xarg = oxarg;
- } else
- xarg = ztrdup(arg);
+ if (xtr) {
+ if (xarg) {
+ int l = strlen(arg) + lxarg + 1;
+
+ oxarg = zhalloc(l + 1);
+ strcpy(oxarg, xarg);
+ oxarg[lxarg] = ' ';
+ strcpy(oxarg + lxarg + 1, arg);
+ xarg = oxarg;
+ lxarg = l + 1;
+ } else {
+ xarg = dupstring(arg);
+ lxarg = strlen(xarg);
+ }
+ }
/* handle -- or - (ops['-']), and + (ops['-'] and ops['+']) */
if (arg[1] == '-')
arg++;
@@ -273,8 +284,7 @@ execbuiltin(LinkList args, Builtin bn)
/* "typeset" may take a numeric argument *
* at the tail of the options */
if (idigit(*arg) && (flags & BINF_TYPEOPT) &&
- (arg[-1] == 'L' || arg[-1] == 'R' ||
- arg[-1] == 'Z' || arg[-1] == 'i'))
+ strchr(typenumstr, arg[-1]))
auxlen = (int)zstrtol(arg, &arg, 10);
/* The above loop may have exited on an invalid option. (We *
* assume that any option requiring metafication is invalid.) */
@@ -282,7 +292,6 @@ execbuiltin(LinkList args, Builtin bn)
if(*arg == Meta)
*++arg ^= 32;
zerr("bad option: -%c", NULL, *arg);
- zsfree(xarg);
return 1;
}
arg = (char *) ugetnode(args);
@@ -300,9 +309,9 @@ execbuiltin(LinkList args, Builtin bn)
auxdata = arg;
arg = (char *) ugetnode(args);
}
- /* for "typeset", -L, -R, -Z and -i take a numeric extra argument */
- if ((flags & BINF_TYPEOPT) && (execop == 'L' || execop == 'R' ||
- execop == 'Z' || execop == 'i') && arg && idigit(*arg)) {
+ /* some "typeset" options take a numeric extra argument */
+ if ((flags & BINF_TYPEOPT) && strchr(typenumstr, execop) &&
+ arg && idigit(*arg)) {
auxlen = atoi(arg);
arg = (char *) ugetnode(args);
}
@@ -322,39 +331,42 @@ execbuiltin(LinkList args, Builtin bn)
while (n)
argc++, incnode(n);
}
- /* Get the actual arguments, into argv. Oargv saves the *
- * beginning of the array for later reference. */
- oargv = argv = (char **)ncalloc(sizeof(char **) * (argc + 1));
- if ((*argv++ = arg))
- while ((*argv++ = (char *)ugetnode(args)));
- argv = oargv;
- if (errflag) {
- zsfree(xarg);
- errflag = 0;
- return 1;
- }
+ {
+ VARARR(char *, argarr, (argc + 1));
+ char **argv, **oargv;
+
+ /* Get the actual arguments, into argv. Oargv saves the *
+ * beginning of the array for later reference. */
+ oargv = argv = argarr;
+ if ((*argv++ = arg))
+ while ((*argv++ = (char *)ugetnode(args)));
+ argv = oargv;
+ if (errflag) {
+ errflag = 0;
+ return 1;
+ }
- /* check that the argument count lies within the specified bounds */
- if (argc < bn->minargs || (argc > bn->maxargs && bn->maxargs != -1)) {
- zwarnnam(name, (argc < bn->minargs)
- ? "not enough arguments" : "too many arguments", NULL, 0);
- zsfree(xarg);
- return 1;
- }
+ /* check that the argument count lies within the specified bounds */
+ if (argc < bn->minargs || (argc > bn->maxargs && bn->maxargs != -1)) {
+ zwarnnam(name, (argc < bn->minargs)
+ ? "not enough arguments" : "too many arguments", NULL, 0);
+ return 1;
+ }
- /* display execution trace information, if required */
- if (isset(XTRACE)) {
- fprintf(stderr, "%s%s", (prompt4) ? prompt4 : "", name);
- if (xarg)
- fprintf(stderr, " %s", xarg);
- while (*oargv)
- fprintf(stderr, " %s", *oargv++);
- fputc('\n', stderr);
- fflush(stderr);
+ /* display execution trace information, if required */
+ if (xtr) {
+ printprompt4();
+ fprintf(xtrerr, "%s", name);
+ if (xarg)
+ fprintf(xtrerr, " %s", xarg);
+ while (*oargv)
+ fprintf(xtrerr, " %s", *oargv++);
+ fputc('\n', xtrerr);
+ fflush(xtrerr);
+ }
+ /* call the handler function, and return its return value */
+ return (*(bn->handlerfunc)) (name, argv, ops, bn->funcid);
}
- zsfree(xarg);
- /* call the handler function, and return its return value */
- return (*(bn->handlerfunc)) (name, argv, ops, bn->funcid);
}
/* Enable/disable an element in one of the internal hash tables. *
@@ -368,7 +380,7 @@ bin_enable(char *name, char **argv, char *ops, int func)
HashTable ht;
HashNode hn;
ScanFunc scanfunc;
- Comp com;
+ Patprog pprog;
int flags1 = 0, flags2 = 0;
int match = 0, returnval = 0;
@@ -405,8 +417,8 @@ bin_enable(char *name, char **argv, char *ops, int func)
for (; *argv; argv++) {
/* parse pattern */
tokenize(*argv);
- if ((com = parsereg(*argv)))
- match += scanmatchtable(ht, com, 0, 0, scanfunc, 0);
+ if ((pprog = patcompile(*argv, PAT_STATIC, 0)))
+ match += scanmatchtable(ht, pprog, 0, 0, scanfunc, 0);
else {
untokenize(*argv);
zwarnnam(name, "bad pattern : %s", *argv, 0);
@@ -537,9 +549,7 @@ bin_set(char *nam, char **args, char *ops, int func)
} else {
/* set shell arguments */
freearray(pparams);
- PERMALLOC {
- pparams = arrdup(args);
- } LASTALLOC;
+ pparams = zarrdup(args);
}
return 0;
}
@@ -567,7 +577,7 @@ bin_pwd(char *name, char **argv, char *ops, int func)
/* the directory stack */
/**/
-LinkList dirstack;
+mod_export LinkList dirstack;
/* dirs: list the directory stack, or replace it with a provided list */
@@ -598,15 +608,13 @@ bin_dirs(char *name, char **argv, char *ops, int func)
return 0;
}
/* replace the stack with the specified directories */
- PERMALLOC {
- l = newlinklist();
- if (*argv) {
- while (*argv)
- addlinknode(l, ztrdup(*argv++));
- freelinklist(dirstack, freestr);
- dirstack = l;
- }
- } LASTALLOC;
+ l = znewlinklist();
+ if (*argv) {
+ while (*argv)
+ zaddlinknode(l, ztrdup(*argv++));
+ freelinklist(dirstack, freestr);
+ dirstack = l;
+ }
return 0;
}
@@ -618,6 +626,8 @@ set_pwd_env(void)
{
Param pm;
+ /* update the PWD and OLDPWD shell parameters */
+
pm = (Param) paramtab->getnode(paramtab, "PWD");
if (pm && PM_TYPE(pm->flags) != PM_SCALAR) {
pm->flags &= ~PM_READONLY;
@@ -634,17 +644,22 @@ set_pwd_env(void)
setsparam("OLDPWD", ztrdup(oldpwd));
pm = (Param) paramtab->getnode(paramtab, "PWD");
- if (!(pm->flags & PM_EXPORTED)) {
+ if (!(pm->flags & PM_EXPORTED) &&
+ (!pm->level || (isset(ALLEXPORT) && !pm->old))) {
pm->flags |= PM_EXPORTED;
- pm->env = addenv("PWD", pwd);
+ pm->env = addenv("PWD", pwd, pm->flags);
}
pm = (Param) paramtab->getnode(paramtab, "OLDPWD");
- if (!(pm->flags & PM_EXPORTED)) {
+ if (!(pm->flags & PM_EXPORTED) &&
+ (!pm->level || (isset(ALLEXPORT) && !pm->old))) {
pm->flags |= PM_EXPORTED;
- pm->env = addenv("PWD", pwd);
+ pm->env = addenv("OLDPWD", oldpwd, pm->flags);
}
}
+/* set if we are resolving links to their true paths */
+static int chasinglinks;
+
/* The main pwd changing function. The real work is done by other *
* functions. cd_get_dest() does the initial argument processing; *
* cd_do_chdir() actually changes directory, if possible; cd_new_pwd() *
@@ -657,7 +672,6 @@ bin_cd(char *nam, char **argv, char *ops, int func)
{
LinkNode dir;
struct stat st1, st2;
- int chaselinks;
if (isset(RESTRICTED)) {
zwarnnam(nam, "restricted", NULL, 0);
@@ -678,33 +692,32 @@ bin_cd(char *nam, char **argv, char *ops, int func)
goto brk;
}
} while (*++s);
- for (s = *argv; *++s; ops[*s] = 1);
+ for (s = *argv; *++s; ops[STOUC(*s)] = 1);
}
brk:
- chaselinks = ops['P'] || (isset(CHASELINKS) && !ops['L']);
- PERMALLOC {
- pushnode(dirstack, ztrdup(pwd));
- if (!(dir = cd_get_dest(nam, argv, ops, func))) {
- zsfree(getlinknode(dirstack));
- LASTALLOC_RETURN 1;
- }
- } LASTALLOC;
- cd_new_pwd(func, dir, chaselinks);
+ chasinglinks = ops['P'] || (isset(CHASELINKS) && !ops['L']);
+ zpushnode(dirstack, ztrdup(pwd));
+ if (!(dir = cd_get_dest(nam, argv, ops, func))) {
+ zsfree(getlinknode(dirstack));
+ return 1;
+ }
+ cd_new_pwd(func, dir);
if (stat(unmeta(pwd), &st1) < 0) {
+ setjobpwd();
zsfree(pwd);
pwd = metafy(zgetcwd(), -1, META_DUP);
} else if (stat(".", &st2) < 0)
chdir(unmeta(pwd));
else if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) {
- if (chaselinks) {
+ if (chasinglinks) {
+ setjobpwd();
zsfree(pwd);
pwd = metafy(zgetcwd(), -1, META_DUP);
} else {
chdir(unmeta(pwd));
}
}
- set_pwd_env();
return 0;
}
@@ -726,9 +739,9 @@ cd_get_dest(char *nam, char **argv, char *ops, int func)
if (func == BIN_PUSHD && unset(PUSHDTOHOME))
dir = nextnode(firstnode(dirstack));
if (dir)
- insertlinknode(dirstack, dir, getlinknode(dirstack));
+ zinsertlinknode(dirstack, dir, getlinknode(dirstack));
else if (func != BIN_POPD)
- pushnode(dirstack, ztrdup(home));
+ zpushnode(dirstack, ztrdup(home));
} else if (!argv[1]) {
int dd;
char *end;
@@ -749,8 +762,8 @@ cd_get_dest(char *nam, char **argv, char *ops, int func)
}
}
if (!dir)
- pushnode(dirstack, ztrdup(strcmp(argv[0], "-")
- ? (doprintdir--, argv[0]) : oldpwd));
+ zpushnode(dirstack, ztrdup(strcmp(argv[0], "-")
+ ? (doprintdir--, argv[0]) : oldpwd));
} else {
char *u, *d;
int len1, len2, len3;
@@ -766,7 +779,7 @@ cd_get_dest(char *nam, char **argv, char *ops, int func)
strncpy(d, pwd, len3);
strcpy(d + len3, argv[1]);
strcat(d, u + len1);
- pushnode(dirstack, d);
+ zpushnode(dirstack, d);
doprintdir++;
}
@@ -789,7 +802,7 @@ cd_get_dest(char *nam, char **argv, char *ops, int func)
zsfree(remnode(dirstack, dir));
return NULL;
}
- if (dest != getdata(dir)) {
+ if (dest != (char *)getdata(dir)) {
zsfree(getdata(dir));
setdata(dir, dest);
}
@@ -903,40 +916,54 @@ static char *
cd_try_chdir(char *pfix, char *dest, int hard)
{
char *buf;
+ int dlen, dochaselinks = 0;
/* handle directory prefix */
if (pfix && *pfix) {
if (*pfix == '/')
buf = tricat(pfix, "/", dest);
else {
- int pwl = strlen(pwd);
int pfl = strlen(pfix);
+ dlen = strlen(pwd);
- buf = zalloc(pwl + pfl + strlen(dest) + 3);
+ buf = zalloc(dlen + pfl + strlen(dest) + 3);
strcpy(buf, pwd);
- buf[pwl] = '/';
- strcpy(buf + pwl + 1, pfix);
- buf[pwl + 1 + pfl] = '/';
- strcpy(buf + pwl + pfl + 2, dest);
+ buf[dlen] = '/';
+ strcpy(buf + dlen + 1, pfix);
+ buf[dlen + 1 + pfl] = '/';
+ strcpy(buf + dlen + pfl + 2, dest);
}
} else if (*dest == '/')
buf = ztrdup(dest);
else {
- int pwl = strlen(pwd);
-
- buf = zalloc(pwl + strlen(dest) + 2);
+ dlen = strlen(pwd);
+ if (pwd[dlen-1] == '/')
+ --dlen;
+ buf = zalloc(dlen + strlen(dest) + 2);
strcpy(buf, pwd);
- buf[pwl] = '/';
- strcpy(buf + pwl + 1, dest);
+ buf[dlen] = '/';
+ strcpy(buf + dlen + 1, dest);
}
- /* Normalise path. See the definition of fixdir() for what this means. */
- fixdir(buf);
-
- if (lchdir(buf, NULL, hard)) {
- zsfree(buf);
+ /* Normalise path. See the definition of fixdir() for what this means.
+ * We do not do this if we are chasing links.
+ */
+ if (!chasinglinks)
+ dochaselinks = fixdir(buf);
+ else
+ unmetafy(buf, &dlen);
+
+ /* We try the full path first. If that fails, try the
+ * argument to cd relatively. This is useful if the cwd
+ * or a parent directory is renamed in the interim.
+ */
+ if (lchdir(buf, NULL, hard) && lchdir(dest, NULL, hard)) {
+ free(buf);
return NULL;
}
+ /* the chdir succeeded, so decide if we should force links to be chased */
+ if (dochaselinks)
+ chasinglinks = 1;
return metafy(buf, -1, META_NOALLOC);
}
@@ -944,10 +971,9 @@ cd_try_chdir(char *pfix, char *dest, int hard)
/**/
static void
-cd_new_pwd(int func, LinkNode dir, int chaselinks)
+cd_new_pwd(int func, LinkNode dir)
{
- Param pm;
- List l;
+ Eprog prog;
char *new_pwd, *s;
int dirstacksize;
@@ -961,7 +987,7 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks)
} else if (func == BIN_CD && unset(AUTOPUSHD))
zsfree(getlinknode(dirstack));
- if (chaselinks) {
+ if (chasinglinks) {
s = new_pwd;
new_pwd = findpwd(s);
zsfree(s);
@@ -980,14 +1006,10 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks)
current (i.e. new) pwd */
zsfree(oldpwd);
oldpwd = pwd;
+ setjobpwd();
pwd = new_pwd;
- /* update the PWD and OLDPWD shell parameters */
- if ((pm = (Param) paramtab->getnode(paramtab, "PWD")) &&
- (pm->flags & PM_EXPORTED) && pm->env)
- pm->env = replenv(pm->env, pwd);
- if ((pm = (Param) paramtab->getnode(paramtab, "OLDPWD")) &&
- (pm->flags & PM_EXPORTED) && pm->env)
- pm->env = replenv(pm->env, oldpwd);
+ set_pwd_env();
+
if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE))
printdirstack();
else if (doprintdir) {
@@ -996,10 +1018,14 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks)
}
/* execute the chpwd function */
- if ((l = getshfunc("chpwd")) != &dummy_list) {
+ if ((prog = getshfunc("chpwd")) != &dummy_eprog) {
+ int osc = sfcontext;
+
fflush(stdout);
fflush(stderr);
- doshfunc(l, NULL, 0, 1);
+ sfcontext = SFC_HOOK;
+ doshfunc("chpwd", prog, NULL, 0, 1);
+ sfcontext = osc;
}
dirstacksize = getiparam("DIRSTACKSIZE");
@@ -1029,14 +1055,20 @@ printdirstack(void)
}
/* Normalise a path. Segments consisting of ., and foo/.. *
- * combinations, are removed and the path is unmetafied. */
+ * combinations, are removed and the path is unmetafied.
+ * Returns 1 if we found a ../ path which should force links to
+ * be chased, 0 otherwise.
+ */
/**/
-static void
+int
fixdir(char *src)
{
- char *dest = src;
- char *d0 = dest;
+ char *dest = src, *d0 = dest;
+#ifdef __CYGWIN__
+ char *s0 = src;
+#endif
+ int ret = 0;
/*** if have RFS superroot directory ***/
#ifdef HAVE_SUPERROOT
@@ -1053,6 +1085,11 @@ fixdir(char *src)
for (;;) {
/* compress multiple /es into single */
if (*src == '/') {
+#ifdef __CYGWIN__
+ /* allow leading // under cygwin */
+ if (src == s0 && src[1] == '/')
+ *dest++ = *src++;
+#endif
*dest++ = *src++;
while (*src == '/')
src++;
@@ -1063,17 +1100,40 @@ fixdir(char *src)
while (dest > d0 + 1 && dest[-1] == '/')
dest--;
*dest = '\0';
- return;
+ return ret;
}
- if (dest > d0 + 1 && src[0] == '.' && src[1] == '.' &&
- (src[2] == '\0' || src[2] == '/')) {
- /* remove a foo/.. combination */
- for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--);
- if (dest[-1] != '/')
- dest--;
- src++;
- while (*++src == '/');
- } else if (src[0] == '.' && (src[1] == '/' || src[1] == '\0')) {
+ if (src[0] == '.' && src[1] == '.' &&
+ (src[2] == '\0' || src[2] == '/')) {
+ if (isset(CHASEDOTS)) {
+ ret = 1;
+ /* and treat as normal path segment */
+ } else {
+ if (dest > d0 + 1) {
+ /*
+ * remove a foo/.. combination:
+ * first check foo exists, else return.
+ */
+ struct stat st;
+ *dest = '\0';
+ if (stat(d0, &st) < 0 || !S_ISDIR(st.st_mode)) {
+ char *ptrd, *ptrs;
+ if (dest == src)
+ *dest = '.';
+ for (ptrs = src, ptrd = dest; *ptrs; ptrs++, ptrd++)
+ *ptrd = (*ptrs == Meta) ? (*++ptrs ^ 32) : *ptrs;
+ *ptrd = '\0';
+ return 1;
+ }
+ for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--);
+ if (dest[-1] != '/')
+ dest--;
+ }
+ src++;
+ while (*++src == '/');
+ continue;
+ }
+ }
+ if (src[0] == '.' && (src[1] == '/' || src[1] == '\0')) {
/* skip a . section */
while (*++src == '/');
} else {
@@ -1086,7 +1146,7 @@ fixdir(char *src)
}
/**/
-void
+mod_export void
printqt(char *str)
{
/* Print str, but turn any single quote into '\'' or ''. */
@@ -1098,7 +1158,7 @@ printqt(char *str)
}
/**/
-void
+mod_export void
printif(char *str, int c)
{
/* If flag c has an argument, print that */
@@ -1119,7 +1179,7 @@ bin_fc(char *nam, char **argv, char *ops, int func)
int first = -1, last = -1, retval, minflag = 0;
char *s;
struct asgment *asgf = NULL, *asgl = NULL;
- Comp com = NULL;
+ Patprog pprog = NULL;
/* fc is only permitted in interactive shells */
if (!interact) {
@@ -1130,33 +1190,31 @@ bin_fc(char *nam, char **argv, char *ops, int func)
* as a pattern that history lines have to match */
if (*argv && ops['m']) {
tokenize(*argv);
- if (!(com = parsereg(*argv++))) {
+ if (!(pprog = patcompile(*argv++, 0, NULL))) {
zwarnnam(nam, "invalid match pattern", NULL, 0);
return 1;
}
}
if (ops['R']) {
/* read history from a file */
- readhistfile(*argv ? *argv : getsparam("HISTFILE"), 1);
+ readhistfile(*argv, 1, ops['I'] ? HFILE_SKIPOLD : 0);
return 0;
}
if (ops['W']) {
/* write history to a file */
- savehistfile(*argv ? *argv : getsparam("HISTFILE"), 1,
- (ops['I'] ? 2 : 0));
+ savehistfile(*argv, 1, ops['I'] ? HFILE_SKIPOLD : 0);
return 0;
}
if (ops['A']) {
/* append history to a file */
- savehistfile(*argv ? *argv : getsparam("HISTFILE"), 1,
- (ops['I'] ? 3 : 1));
+ savehistfile(*argv, 1, HFILE_APPEND | (ops['I'] ? HFILE_SKIPOLD : 0));
return 0;
}
if (!(ops['l'] && unset(HISTNOSTORE)))
remhist();
/* put foo=bar type arguments into the substitution list */
while (*argv && equalsplit(*argv, &s)) {
- Asgment a = (Asgment) alloc(sizeof *a);
+ Asgment a = (Asgment) zhalloc(sizeof *a);
if (!asgf)
asgf = asgl = a;
@@ -1191,9 +1249,9 @@ bin_fc(char *nam, char **argv, char *ops, int func)
}
/* default values of first and last, and range checking */
if (first == -1)
- first = (ops['l']) ? curhist - 16 : curhist - 1;
+ first = ops['l']? addhistnum(curhist,-16,0) : addhistnum(curhist,-1,0);
if (last == -1)
- last = (ops['l']) ? curhist - 1 : first;
+ last = ops['l']? addhistnum(curhist,-1,0) : first;
if (first < firsthist())
first = firsthist();
if (last == -1)
@@ -1204,7 +1262,7 @@ bin_fc(char *nam, char **argv, char *ops, int func)
/* list the required part of the history */
retval = fclist(stdout, !ops['n'], ops['r'], ops['D'],
ops['d'] + ops['f'] * 2 + ops['E'] * 4 + ops['i'] * 8,
- first, last, asgf, com);
+ first, last, asgf, pprog);
else {
/* edit history file, and (if successful) use the result as a new command */
int tempfd;
@@ -1218,20 +1276,21 @@ bin_fc(char *nam, char **argv, char *ops, int func)
((out = fdopen(tempfd, "w")) == NULL)) {
zwarnnam("fc", "can't open temp file: %e", NULL, errno);
} else {
- if (!fclist(out, 0, ops['r'], 0, 0, first, last, asgf, com)) {
+ if (!fclist(out, 0, ops['r'], 0, 0, first, last, asgf, pprog)) {
char *editor;
editor = auxdata ? auxdata : getsparam("FCEDIT");
if (!editor)
editor = DEFAULT_FCEDIT;
- if (fcedit(editor, fil))
+ if (fcedit(editor, fil)) {
if (stuff(fil))
zwarnnam("fc", "%e: %s", s, errno);
else {
loop(0,1);
retval = lastval;
}
+ }
}
}
unlink(fil);
@@ -1257,7 +1316,7 @@ fcgetcomm(char *s)
* numbers indicate reversed numbering. */
if ((cmd = atoi(s))) {
if (cmd < 0)
- cmd = curhist + cmd;
+ cmd = addhistnum(curhist,cmd,HIST_FOREIGN);
if (cmd >= curhist) {
zwarnnam("fc", "bad history number: %d", 0, cmd);
return -1;
@@ -1289,7 +1348,7 @@ fcsubs(char **sp, struct asgment *sub)
oldpos = s;
/* loop over occurences of oldstr in s, replacing them with newstr */
while ((newpos = (char *)strstr(oldpos, oldstr))) {
- newmem = (char *) alloc(1 + (newpos - s)
+ newmem = (char *) zhalloc(1 + (newpos - s)
+ strlen(newstr) + strlen(newpos + strlen(oldstr)));
ztrncpy(newmem, s, newpos - s);
strcat(newmem, newstr);
@@ -1318,10 +1377,10 @@ fcsubs(char **sp, struct asgment *sub)
/**/
static int
-fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment *subs, Comp com)
+fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment *subs, Patprog pprog)
{
int fclistdone = 0;
- char *s, *hs;
+ char *s;
Histent ent;
/* reverse range if required */
@@ -1334,28 +1393,31 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment
if (!subs)
fclistdone = 1;
- for (;;) {
- hs = quietgetevent(first);
- if (!hs) {
+ ent = gethistent(first, first < last? GETHIST_DOWNWARD : GETHIST_UPWARD);
+ if (!ent || (first < last? ent->histnum > last : ent->histnum < last)) {
+ if (first == last)
zwarnnam("fc", "no such event: %d", NULL, first);
- return 1;
- }
- s = dupstring(hs);
+ else
+ zwarnnam("fc", "no events in that range", NULL, 0);
+ return 1;
+ }
+
+ for (;;) {
+ s = dupstring(ent->text);
/* this if does the pattern matching, if required */
- if (!com || domatch(s, com, 0)) {
+ if (!pprog || pattry(pprog, s)) {
/* perform substitution */
fclistdone |= fcsubs(&s, subs);
/* do numbering */
- if (n)
- fprintf(f, "%5d ", first);
- ent = NULL;
+ if (n) {
+ fprintf(f, "%5d%c ", ent->histnum,
+ ent->flags & HIST_FOREIGN? '*' : ' ');
+ }
/* output actual time (and possibly date) of execution of the
command, if required */
if (d) {
struct tm *ltm;
- if (!ent)
- ent = gethistent(first);
ltm = localtime(&ent->stim);
if (d >= 2) {
if (d >= 8) {
@@ -1377,8 +1439,6 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment
/* display the time taken by the command, if required */
if (D) {
long diff;
- if (!ent)
- ent = gethistent(first);
diff = (ent->ftim) ? ent->ftim - ent->stim : 0;
fprintf(f, "%ld:%02ld ", diff / 60, diff % 60);
}
@@ -1391,12 +1451,14 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment
fprintf(f, "%s\n", s);
}
/* move on to the next history line, or quit the loop */
- if (first == last)
- break;
- else if (first > last)
- first--;
- else
- first++;
+ if (first < last) {
+ if (!(ent = down_histent(ent)) || ent->histnum > last)
+ break;
+ }
+ else {
+ if (!(ent = up_histent(ent)) || ent->histnum < last)
+ break;
+ }
}
/* final processing */
@@ -1465,6 +1527,265 @@ getasg(char *s)
return &asg;
}
+/* function to set a single parameter */
+
+/**/
+Param
+typeset_single(char *cname, char *pname, Param pm, int func,
+ int on, int off, int roff, char *value, Param altpm)
+{
+ int usepm, tc, keeplocal = 0, newspecial = 0;
+
+ /*
+ * Do we use the existing pm? Note that this isn't the end of the
+ * story, because if we try and create a new pm at the same
+ * locallevel as an unset one we use the pm struct anyway: that's
+ * handled in createparam(). Here we just avoid using it for the
+ * present tests if it's unset.
+ */
+ usepm = pm && !(pm->flags & PM_UNSET);
+
+ /*
+ * We need to compare types with an existing pm if special,
+ * even if that's unset
+ */
+ if (pm && (pm->flags & PM_SPECIAL))
+ usepm = 1;
+
+ /*
+ * Don't use an existing param if
+ * - the local level has changed, and
+ * - we are really locallizing the parameter
+ */
+ if (usepm && locallevel != pm->level && (on & PM_LOCAL)) {
+ /*
+ * If the original parameter was special and we're creating
+ * a new one, we need to keep it special.
+ *
+ * The -h (hide) flags prevents an existing special being made
+ * local. It can be applied either to the special or in the
+ * typeset/local statement for the local variable.
+ */
+ newspecial = (pm->flags & PM_SPECIAL)
+ && !(on & PM_HIDE) && !(pm->flags & PM_HIDE & ~off);
+ usepm = 0;
+ }
+
+ /* attempting a type conversion, or making a tied colonarray? */
+ tc = 0;
+ if (usepm || newspecial) {
+ int chflags = ((off & pm->flags) | (on & ~pm->flags)) &
+ (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED|
+ PM_ARRAY|PM_TIED|PM_AUTOLOAD);
+ /* keep the parameter if just switching between floating types */
+ if ((tc = chflags && chflags != (PM_EFLOAT|PM_FFLOAT)))
+ usepm = 0;
+ }
+ if (tc && (pm->flags & PM_SPECIAL)) {
+ zerrnam(cname, "%s: can't change type of a special parameter",
+ pname, 0);
+ return NULL;
+ }
+
+ /*
+ * According to the manual, local parameters don't get exported.
+ * A parameter will be local if
+ * 1. we are re-using an existing local parameter
+ * or
+ * 2. we are not using an existing parameter, but
+ * i. there is already a parameter, which will be hidden
+ * or
+ * ii. we are creating a new local parameter
+ */
+ if ((usepm && pm->level) ||
+ (!usepm && (pm || (locallevel && (on & PM_LOCAL)))))
+ on &= ~PM_EXPORTED;
+
+ if (usepm) {
+ on &= ~PM_LOCAL;
+ if (!on && !roff && !value) {
+ paramtab->printnode((HashNode)pm, 0);
+ return pm;
+ }
+ if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+ zerrnam(cname, "%s: restricted", pname, 0);
+ return pm;
+ }
+ if ((on & PM_UNIQUE) && !(pm->flags & PM_READONLY & ~off)) {
+ Param apm;
+ if (PM_TYPE(pm->flags) == PM_ARRAY)
+ uniqarray((*pm->gets.afn) (pm));
+ else if (PM_TYPE(pm->flags) == PM_SCALAR && pm->ename &&
+ (apm = (Param) paramtab->getnode(paramtab, pm->ename)))
+ uniqarray((*apm->gets.afn) (apm));
+ }
+ pm->flags = (pm->flags | on) & ~(off | PM_UNSET);
+ /* This auxlen/pm->ct stuff is a nasty hack. */
+ if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER |
+ PM_EFLOAT | PM_FFLOAT)) &&
+ auxlen)
+ pm->ct = auxlen;
+ if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
+ if (pm->flags & PM_EXPORTED) {
+ if (!(pm->flags & PM_UNSET) && !pm->env && !value)
+ pm->env = addenv(pname, getsparam(pname), pm->flags);
+ } else if (pm->env &&
+ (!pm->level || (isset(ALLEXPORT) && !pm->old))) {
+ delenv(pm->env);
+ zsfree(pm->env);
+ pm->env = NULL;
+ }
+ if (value)
+ setsparam(pname, ztrdup(value));
+ } else if (value) {
+ zwarnnam(cname, "can't assign new value for array %s", pname, 0);
+ return NULL;
+ }
+ return pm;
+ }
+
+ /*
+ * We're here either because we're creating a new parameter,
+ * or we're adding a parameter at a different local level,
+ * or we're converting the type of a parameter. In the
+ * last case only, we need to delete the old parameter.
+ */
+ if (tc) {
+ /* Maintain existing readonly/exported status... */
+ on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->flags;
+ /* ...but turn off existing readonly so we can delete it */
+ pm->flags &= ~PM_READONLY;
+ /*
+ * If we're just changing the type, we should keep the
+ * variable at the current level of localness.
+ */
+ keeplocal = pm->level;
+ /*
+ * Try to carry over a value, but not when changing from,
+ * to, or between non-scalar types.
+ */
+ if (!value && !((pm->flags|on) & (PM_ARRAY|PM_HASHED)))
+ value = dupstring(getsparam(pname));
+ /* pname may point to pm->nam which is about to disappear */
+ pname = dupstring(pname);
+ unsetparam_pm(pm, 0, 1);
+ }
+
+ if (newspecial) {
+ Param tpm, pm2;
+ if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+ zerrnam(cname, "%s: restricted", pname, 0);
+ return pm;
+ }
+ /*
+ * For specials, we keep the same struct but zero everything.
+ * Maybe it would be easier to create a new struct but copy
+ * the get/set methods.
+ */
+ tpm = (Param) zalloc(sizeof *tpm);
+
+ tpm->nam = pm->nam;
+ if (pm->ename &&
+ (pm2 = (Param) paramtab->getnode(paramtab, pm->ename)) &&
+ pm2->level == locallevel) {
+ /* This is getting silly, but anyway: if one of a path/PATH
+ * pair has already been made local at the current level, we
+ * have to make sure that the other one does not have its value
+ * saved: since that comes from an internal variable it will
+ * already reflect the local value, so restoring it on exit
+ * would be wrong.
+ *
+ * This problem is also why we make sure we have a copy
+ * of the environment entry in tpm->env, rather than relying
+ * on the restored value to provide it.
+ */
+ tpm->flags = pm->flags | PM_NORESTORE;
+ } else {
+ copyparam(tpm, pm, 1);
+ }
+ tpm->old = pm->old;
+ tpm->level = pm->level;
+ tpm->ct = pm->ct;
+ tpm->env = pm->env;
+
+ pm->old = tpm;
+ /*
+ * The remaining on/off flags should be harmless to use,
+ * because we've checked for unpleasant surprises above.
+ */
+ pm->flags = (PM_TYPE(pm->flags) | on | PM_SPECIAL) & ~off;
+ /*
+ * Final tweak: if we've turned on one of the flags with
+ * numbers, we should use the appropriate integer.
+ */
+ if (on & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z|PM_INTEGER|
+ PM_EFLOAT|PM_FFLOAT))
+ pm->ct = auxlen;
+ else
+ pm->ct = 0;
+ pm->env = NULL;
+ } else {
+ /*
+ * Create a new node for a parameter with the flags in `on' minus the
+ * readonly flag
+ */
+ pm = createparam(pname, on & ~PM_READONLY);
+ DPUTS(!pm, "BUG: parameter not created");
+ pm->ct = auxlen;
+ }
+
+ if (altpm && PM_TYPE(pm->flags) == PM_SCALAR) {
+ /*
+ * It seems safer to set this here than in createparam(),
+ * to make sure we only ever use the colonarr functions
+ * when u.data is correctly set.
+ */
+ pm->sets.cfn = colonarrsetfn;
+ pm->gets.cfn = colonarrgetfn;
+ pm->u.data = &altpm->u.arr;
+ }
+
+ if (keeplocal)
+ pm->level = keeplocal;
+ else if (on & PM_LOCAL)
+ pm->level = locallevel;
+ if (value && !(pm->flags & (PM_ARRAY|PM_HASHED)))
+ setsparam(pname, ztrdup(value));
+ else if (newspecial && !(pm->old->flags & PM_NORESTORE)) {
+ /*
+ * We need to use the special setting function to re-initialise
+ * the special parameter to empty.
+ */
+ switch (PM_TYPE(pm->flags)) {
+ case PM_SCALAR:
+ pm->sets.cfn(pm, ztrdup(""));
+ break;
+ case PM_INTEGER:
+ pm->sets.ifn(pm, 0);
+ break;
+ case PM_EFLOAT:
+ case PM_FFLOAT:
+ pm->sets.ffn(pm, 0.0);
+ break;
+ case PM_ARRAY:
+ pm->sets.afn(pm, mkarray(NULL));
+ break;
+ case PM_HASHED:
+ pm->sets.hfn(pm, newparamtable(17, pm->nam));
+ break;
+ }
+ }
+ pm->flags |= (on & PM_READONLY);
+ if (value && (pm->flags & (PM_ARRAY|PM_HASHED))) {
+ zerrnam(cname, "%s: can't assign initial value for array", pname, 0);
+ /* the only safe thing to do here seems to be unset the param */
+ unsetparam_pm(pm, 0, 1);
+ return NULL;
+ }
+
+ return pm;
+}
+
/* declare, export, integer, local, readonly, typeset */
/**/
@@ -1473,10 +1794,10 @@ bin_typeset(char *name, char **argv, char *ops, int func)
{
Param pm;
Asgment asg;
- Comp com;
- char *optstr = "iLRZlurtxU";
- int on = 0, off = 0, roff, bit = PM_INTEGER;
- int initon, initoff, of, i;
+ Patprog pprog;
+ char *optstr = TYPESET_OPTSTR;
+ int on = 0, off = 0, roff, bit = PM_ARRAY;
+ int i;
int returnval = 0, printflags = 0;
/* hash -f is really the builtin `functions' */
@@ -1487,25 +1808,40 @@ bin_typeset(char *name, char **argv, char *ops, int func)
* Unfortunately, this depends on the order *
* these flags are defined in zsh.h */
for (; *optstr; optstr++, bit <<= 1)
- if (ops[*optstr] == 1)
+ if (ops[STOUC(*optstr)] == 1)
on |= bit;
- else if (ops[*optstr] == 2)
+ else if (ops[STOUC(*optstr)] == 2)
off |= bit;
roff = off;
/* Sanity checks on the options. Remove conficting options. */
+ if (on & PM_FFLOAT) {
+ off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
+ PM_HASHED | PM_INTEGER | PM_EFLOAT;
+ /* Allow `float -F' to work even though float sets -E by default */
+ on &= ~PM_EFLOAT;
+ }
+ if (on & PM_EFLOAT)
+ off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
+ PM_HASHED | PM_INTEGER | PM_FFLOAT;
if (on & PM_INTEGER)
- off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY;
+ off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
+ PM_HASHED | PM_EFLOAT | PM_FFLOAT;
if (on & PM_LEFT)
- off |= PM_RIGHT_B | PM_INTEGER;
+ off |= PM_RIGHT_B | PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
if (on & PM_RIGHT_B)
- off |= PM_LEFT | PM_INTEGER;
+ off |= PM_LEFT | PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
if (on & PM_RIGHT_Z)
- off |= PM_INTEGER;
+ off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
if (on & PM_UPPER)
off |= PM_LOWER;
if (on & PM_LOWER)
off |= PM_UPPER;
+ if (on & PM_HASHED)
+ off |= PM_ARRAY;
+ if (on & PM_TIED)
+ off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED;
+
on &= ~off;
/* Given no arguments, list whatever the options specify. */
@@ -1518,148 +1854,171 @@ bin_typeset(char *name, char **argv, char *ops, int func)
return 0;
}
+ if (!ops['g'] && !ops['x'])
+ on |= PM_LOCAL;
+
+ if (on & PM_TIED) {
+ Param apm;
+ struct asgment asg0;
+ char *oldval = NULL;
+
+ if (ops['m']) {
+ zwarnnam(name, "incompatible options for -T", NULL, 0);
+ return 1;
+ }
+ on &= ~off;
+ if (!argv[1] || argv[2]) {
+ zwarnnam(name, "-T requires names of scalar and array", NULL, 0);
+ return 1;
+ }
+
+ if (!(asg = getasg(argv[0])))
+ return 1;
+ asg0 = *asg;
+ if (!(asg = getasg(argv[1])))
+ return 1;
+ if (!strcmp(asg0.name, asg->name)) {
+ zerrnam(name, "can't tie a variable to itself", NULL, 0);
+ return 1;
+ }
+ /*
+ * Keep the old value of the scalar. We need to do this
+ * here as if it is already tied to the same array it
+ * will be unset when we retie the array. This is all
+ * so that typeset -T is idempotent.
+ *
+ * We also need to remember here whether the damn thing is
+ * exported and pass that along. Isn't the world complicated?
+ */
+ if ((pm = (Param) paramtab->getnode(paramtab, asg0.name))
+ && !(pm->flags & PM_UNSET)
+ && (locallevel == pm->level || !(on & PM_LOCAL))) {
+ if (!asg0.value && !(PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)))
+ oldval = ztrdup(getsparam(asg0.name));
+ on |= (pm->flags & PM_EXPORTED);
+ }
+ /*
+ * Create the tied array; this is normal except that
+ * it has the PM_TIED flag set. Do it first because
+ * we need the address.
+ */
+ if (!(apm=typeset_single(name, asg->name,
+ (Param)paramtab->getnode(paramtab,
+ asg->name),
+ func, (on | PM_ARRAY) & ~PM_EXPORTED,
+ off, roff, asg->value, NULL)))
+ return 1;
+
+ /*
+ * Create the tied colonarray. We make it as a normal scalar
+ * and fix up the oddities later.
+ */
+ if (!(pm=typeset_single(name, asg0.name,
+ (Param)paramtab->getnode(paramtab,
+ asg0.name),
+ func, on, off, roff, asg0.value, apm))) {
+ if (oldval)
+ zsfree(oldval);
+ unsetparam_pm(apm, 1, 1);
+ return 1;
+ }
+
+ pm->ename = ztrdup(asg->name);
+ apm->ename = ztrdup(asg0.name);
+ if (oldval)
+ setsparam(asg0.name, oldval);
+
+ return 0;
+ }
+ if (off & PM_TIED) {
+ zerrnam(name, "use unset to remove tied variables", NULL, 0);
+ return 1;
+ }
+
/* With the -m option, treat arguments as glob patterns */
if (ops['m']) {
while ((asg = getasg(*argv++))) {
+ LinkList pmlist = newlinklist();
+ LinkNode pmnode;
+
tokenize(asg->name); /* expand argument */
- if (!(com = parsereg(asg->name))) {
+ if (!(pprog = patcompile(asg->name, 0, NULL))) {
untokenize(asg->name);
zwarnnam(name, "bad pattern : %s", argv[-1], 0);
returnval = 1;
continue;
}
- /* If no options or values are given, display all *
- * parameters matching the glob pattern. */
- if (!(on || roff || asg->value)) {
- scanmatchtable(paramtab, com, 0, 0, paramtab->printnode, 0);
- continue;
- }
- /* Since either options or values are given, we search *
- * through the parameter table and change all parameters *
- * matching the glob pattern to have these flags and/or *
- * value. */
+ /*
+ * Search through the parameter table and change all parameters
+ * matching the glob pattern to have these flags and/or value.
+ * Bad news: if the parameter gets altered, e.g. by
+ * a type conversion, then paramtab can be shifted around,
+ * so we need to store the parameters to alter on a separate
+ * list for later use.
+ */
for (i = 0; i < paramtab->hsize; i++) {
- for (pm = (Param) paramtab->nodes[i]; pm; pm = (Param) pm->next) {
- if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED))
+ for (pm = (Param) paramtab->nodes[i]; pm;
+ pm = (Param) pm->next) {
+ if (((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) ||
+ (pm->flags & PM_UNSET))
continue;
- if (domatch(pm->nam, com, 0)) {
- /* set up flags if we have any */
- if (on || roff) {
- if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
- !(pm->flags & PM_READONLY & ~off))
- uniqarray((*pm->gets.afn) (pm));
- pm->flags = (pm->flags | on) & ~off;
- if (PM_TYPE(pm->flags) != PM_ARRAY) {
- if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && auxlen)
- pm->ct = auxlen;
- /* did we just export this? */
- if ((pm->flags & PM_EXPORTED) && !pm->env) {
- pm->env = addenv(pm->nam, (asg->value) ? asg->value : getsparam(pm->nam));
- } else if (!(pm->flags & PM_EXPORTED) && pm->env) {
- /* did we just unexport this? */
- delenv(pm->env);
- zsfree(pm->env);
- pm->env = NULL;
- }
- }
- }
- /* set up a new value if given */
- if (asg->value) {
- setsparam(pm->nam, ztrdup(asg->value));
- }
- }
+ if (pattry(pprog, pm->nam))
+ addlinknode(pmlist, pm);
}
}
+ for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) {
+ pm = (Param) getdata(pmnode);
+ if (!typeset_single(name, pm->nam, pm, func, on, off, roff,
+ asg->value, NULL))
+ returnval = 1;
+ }
}
return returnval;
}
- /* Save the values of on, off, and func */
- initon = on;
- initoff = off;
- of = func;
-
/* Take arguments literally. Don't glob */
while ((asg = getasg(*argv++))) {
- /* restore the original values of on, off, and func */
- on = initon;
- off = initoff;
- func = of;
- on &= ~PM_ARRAY;
-
/* check if argument is a valid identifier */
if (!isident(asg->name)) {
zerr("not an identifier: %s", asg->name, 0);
returnval = 1;
continue;
}
- bit = 0; /* flag for switching int<->not-int */
- if ((pm = (Param)paramtab->getnode(paramtab, asg->name)) &&
- (((pm->flags & PM_SPECIAL) && pm->level == locallevel) ||
- (!(pm->flags & PM_UNSET) &&
- ((locallevel == pm->level) || func == BIN_EXPORT) &&
- !(bit = ((off & pm->flags) | (on & ~pm->flags)) & PM_INTEGER)))) {
- /* if no flags or values are given, just print this parameter */
- if (!on && !roff && !asg->value) {
- paramtab->printnode((HashNode) pm, 0);
- continue;
- }
- if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
- zerrnam(name, "%s: restricted", pm->nam, 0);
- returnval = 1;
- continue;
- }
- if((pm->flags & PM_SPECIAL) &&
- PM_TYPE((pm->flags | on) & ~off) != PM_TYPE(pm->flags)) {
- zerrnam(name, "%s: cannot change type of a special parameter",
- pm->nam, 0);
- returnval = 1;
- continue;
- }
- if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
- !(pm->flags & PM_READONLY & ~off))
- uniqarray((*pm->gets.afn) (pm));
- pm->flags = (pm->flags | on) & ~off;
- if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) &&
- auxlen)
- pm->ct = auxlen;
- if (PM_TYPE(pm->flags) != PM_ARRAY) {
- if (pm->flags & PM_EXPORTED) {
- if (!(pm->flags & PM_UNSET) && !pm->env && !asg->value)
- pm->env = addenv(asg->name, getsparam(asg->name));
- } else if (pm->env) {
- delenv(pm->env);
- zsfree(pm->env);
- pm->env = NULL;
- }
- if (asg->value)
- setsparam(asg->name, ztrdup(asg->value));
- }
- } else {
- if (bit) {
- if (pm->flags & PM_READONLY) {
- on |= ~off & PM_READONLY;
- pm->flags &= ~PM_READONLY;
- }
- if (!asg->value)
- asg->value = dupstring(getsparam(asg->name));
- unsetparam(asg->name);
- }
- /* create a new node for a parameter with the *
- * flags in `on' minus the readonly flag */
- pm = createparam(ztrdup(asg->name), on & ~PM_READONLY);
- DPUTS(!pm, "BUG: parameter not created");
- pm->ct = auxlen;
- if (func != BIN_EXPORT)
- pm->level = locallevel;
- if (asg->value)
- setsparam(asg->name, ztrdup(asg->value));
- pm->flags |= (on & PM_READONLY);
- }
+ if (!typeset_single(name, asg->name,
+ (Param) (paramtab == realparamtab ?
+ gethashnode2(paramtab, asg->name) :
+ paramtab->getnode(paramtab, asg->name)),
+ func, on, off, roff, asg->value, NULL))
+ returnval = 1;
}
return returnval;
}
+/* Helper for bin_functions() when run as "autoload -X" */
+
+/**/
+int
+eval_autoload(Shfunc shf, char *name, char *ops, int func)
+{
+ if (!(shf->flags & PM_UNDEFINED))
+ return 1;
+
+ if (shf->funcdef) {
+ freeeprog(shf->funcdef);
+ shf->funcdef = &dummy_eprog;
+ }
+ if (ops['X'] == 1) {
+ char *fargv[3];
+ fargv[0] = name;
+ fargv[1] = "\"$@\"";
+ fargv[2] = 0;
+ shf->funcdef = mkautofn(shf);
+ return bin_eval(name, fargv, ops, func);
+ }
+
+ return !loadautofn(shf, (ops['k'] ? 2 : (ops['z'] ? 0 : 1)), 1);
+}
+
/* Display or change the attributes of shell functions. *
* If called as autoload, it will define a new autoloaded *
* (undefined) shell function. */
@@ -1668,34 +2027,55 @@ bin_typeset(char *name, char **argv, char *ops, int func)
int
bin_functions(char *name, char **argv, char *ops, int func)
{
- Comp com;
+ Patprog pprog;
Shfunc shf;
int i, returnval = 0;
- int on = 0, off = 0;
+ int on = 0, off = 0, pflags = 0;
/* Do we have any flags defined? */
- if (ops['u'] || ops['t']) {
- if (ops['u'] == 1)
- on |= PM_UNDEFINED;
- else if (ops['u'] == 2)
- off |= PM_UNDEFINED;
-
- if (ops['t'] == 1)
- on |= PM_TAGGED;
- else if (ops['t'] == 2)
- off |= PM_TAGGED;
- }
-
- if (off & PM_UNDEFINED) {
+ if (ops['u'] == 2)
+ off |= PM_UNDEFINED;
+ else if (ops['u'] == 1 || ops['X'])
+ on |= PM_UNDEFINED;
+ if (ops['U'] == 1)
+ on |= PM_UNALIASED|PM_UNDEFINED;
+ else if (ops['U'] == 2)
+ off |= PM_UNALIASED;
+ if (ops['t'] == 1)
+ on |= PM_TAGGED;
+ else if (ops['t'] == 2)
+ off |= PM_TAGGED;
+
+ if ((off & PM_UNDEFINED) || (ops['k'] && ops['z']) ||
+ (ops['X'] != 2 && (ops['k'] || ops['z'])) ||
+ (ops['X'] == 1 && (ops['m'] || *argv || !scriptname))) {
zwarnnam(name, "invalid option(s)", NULL, 0);
return 1;
}
+ if (ops['f'] == 2 || ops['+'])
+ pflags |= PRINT_NAMEONLY;
+
/* 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. */
if (!*argv) {
- scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode, 0);
+ if (ops['X'] == 1) {
+ if ((shf = (Shfunc) shfunctab->getnode(shfunctab, scriptname))) {
+ DPUTS(!shf->funcdef,
+ "BUG: Calling autoload from empty function");
+ } else {
+ shf = (Shfunc) zcalloc(sizeof *shf);
+ shfunctab->addnode(shfunctab, ztrdup(scriptname), shf);
+ }
+ shf->flags = on;
+ return eval_autoload(shf, scriptname, ops, func);
+ } else {
+ if (ops['U'] && !ops['u'])
+ on &= ~PM_UNDEFINED;
+ scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode,
+ pflags);
+ }
return 0;
}
@@ -1705,16 +2085,25 @@ bin_functions(char *name, char **argv, char *ops, int func)
for (; *argv; argv++) {
/* expand argument */
tokenize(*argv);
- if ((com = parsereg(*argv))) {
+ if ((pprog = patcompile(*argv, PAT_STATIC, 0))) {
/* with no options, just print all functions matching the glob pattern */
if (!(on|off)) {
- scanmatchtable(shfunctab, com, 0, DISABLED, shfunctab->printnode, 0);
+ scanmatchtable(shfunctab, pprog, 0, DISABLED,
+ shfunctab->printnode, pflags);
} else {
/* apply the options to all functions matching the glob pattern */
for (i = 0; i < shfunctab->hsize; i++) {
- for (shf = (Shfunc) shfunctab->nodes[i]; shf; shf = (Shfunc) shf->next)
- if (domatch(shf->nam, com, 0) && !(shf->flags & DISABLED))
- shf->flags = (shf->flags | on) & (~off);
+ for (shf = (Shfunc) shfunctab->nodes[i]; shf;
+ shf = (Shfunc) shf->next)
+ if (pattry(pprog, shf->nam) &&
+ !(shf->flags & DISABLED)) {
+ shf->flags = (shf->flags |
+ (on & ~PM_UNDEFINED)) & ~off;
+ if (ops['X'] &&
+ eval_autoload(shf, shf->nam, ops, func)) {
+ returnval = 1;
+ }
+ }
}
}
} else {
@@ -1728,14 +2117,21 @@ bin_functions(char *name, char **argv, char *ops, int func)
/* Take the arguments literally -- do not glob */
for (; *argv; argv++) {
- if ((shf = (Shfunc) shfunctab->getnode(shfunctab, *argv))) {
+ if (ops['w']) {
+ if (dump_autoload(*argv, on, ops, func)) {
+ zwarnnam(name, "invalid wordcode file: %s", *argv, 0);
+ returnval = 1;
+ }
+ } else if ((shf = (Shfunc) shfunctab->getnode(shfunctab, *argv))) {
/* if any flag was given */
- if (on|off)
+ if (on|off) {
/* turn on/off the given flags */
shf->flags = (shf->flags | (on & ~PM_UNDEFINED)) & ~off;
- else
+ if (ops['X'] && eval_autoload(shf, shf->nam, ops, func))
+ returnval = 1;
+ } else
/* no flags, so just print */
- shfunctab->printnode((HashNode) shf, 0);
+ shfunctab->printnode((HashNode) shf, pflags);
} else if (on & PM_UNDEFINED) {
/* Add a new undefined (autoloaded) function to the *
* hash table with the corresponding flags set. */
@@ -1743,6 +2139,8 @@ bin_functions(char *name, char **argv, char *ops, int func)
shf->flags = on;
shf->funcdef = mkautofn(shf);
shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
+ if (ops['X'] && eval_autoload(shf, shf->nam, ops, func))
+ returnval = 1;
} else
returnval = 1;
}
@@ -1750,30 +2148,28 @@ bin_functions(char *name, char **argv, char *ops, int func)
}
/**/
-static List
+Eprog
mkautofn(Shfunc shf)
{
- List l;
- Sublist s;
- Pline p;
- Cmd c;
- AutoFn a;
- PERMALLOC {
- a = (AutoFn)allocnode(N_AUTOFN);
- a->shf = shf;
- c = (Cmd)allocnode(N_CMD);
- c->type = AUTOFN;
- c->u.autofn = a;
- p = (Pline)allocnode(N_PLINE);
- p->left = c;
- p->type = END;
- s = (Sublist)allocnode(N_SUBLIST);
- s->left = p;
- l = (List)allocnode(N_LIST);
- l->left = s;
- l->type = Z_SYNC;
- } LASTALLOC;
- return l;
+ Eprog p;
+
+ p = (Eprog) zalloc(sizeof(*p));
+ p->len = 5 * sizeof(wordcode);
+ p->prog = (Wordcode) zalloc(p->len);
+ p->strs = NULL;
+ p->shf = shf;
+ p->npats = 0;
+ p->pats = NULL;
+ p->flags = EF_REAL;
+ p->dump = NULL;
+
+ p->prog[0] = WCB_LIST((Z_SYNC | Z_END), 0);
+ p->prog[1] = WCB_SUBLIST(WC_SUBLIST_END, 0, 3);
+ p->prog[2] = WCB_PIPE(WC_PIPE_END, 0);
+ p->prog[3] = WCB_AUTOFN();
+ p->prog[4] = WCB_END();
+
+ return p;
}
/* unset: unset parameters */
@@ -1783,7 +2179,7 @@ int
bin_unset(char *name, char **argv, char *ops, int func)
{
Param pm, next;
- Comp com;
+ Patprog pprog;
char *s;
int match = 0, returnval = 0;
int i;
@@ -1797,15 +2193,16 @@ bin_unset(char *name, char **argv, char *ops, int func)
while ((s = *argv++)) {
/* expand */
tokenize(s);
- if ((com = parsereg(s))) {
+ if ((pprog = patcompile(s, PAT_STATIC, NULL))) {
/* Go through the parameter table, and unset any matches */
for (i = 0; i < paramtab->hsize; i++) {
for (pm = (Param) paramtab->nodes[i]; pm; pm = next) {
/* record pointer to next, since we may free this one */
next = (Param) pm->next;
if ((!(pm->flags & PM_RESTRICTED) ||
- unset(RESTRICTED)) && domatch(pm->nam, com, 0)) {
- unsetparam(pm->nam);
+ unset(RESTRICTED)) &&
+ pattry(pprog, pm->nam)) {
+ unsetparam_pm(pm, 0, 1);
match++;
}
}
@@ -1824,14 +2221,41 @@ bin_unset(char *name, char **argv, char *ops, int func)
/* do not glob -- unset the given parameter */
while ((s = *argv++)) {
- pm = (Param) paramtab->getnode(paramtab, s);
+ char *ss = strchr(s, '[');
+ char *sse = ss;
+ if (ss) {
+ if (skipparens('[', ']', &sse) || *sse) {
+ zerrnam(name, "%s: invalid parameter name", s, 0);
+ returnval = 1;
+ continue;
+ }
+ *ss = 0;
+ }
+ pm = (Param) (paramtab == realparamtab ?
+ gethashnode2(paramtab, s) :
+ paramtab->getnode(paramtab, s));
if (!pm)
returnval = 1;
else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerrnam(name, "%s: restricted", pm->nam, 0);
returnval = 1;
+ } else if (ss) {
+ if (PM_TYPE(pm->flags) == PM_HASHED) {
+ HashTable tht = paramtab;
+ if ((paramtab = pm->gets.hfn(pm))) {
+ *--sse = 0;
+ unsetparam(ss+1);
+ *sse = ']';
+ }
+ paramtab = tht;
+ } else {
+ zerrnam(name, "%s: invalid element for unset", s, 0);
+ returnval = 1;
+ }
} else
- unsetparam(s);
+ unsetparam_pm(pm, 0, 1);
+ if (ss)
+ *ss = '[';
}
return returnval;
}
@@ -1843,7 +2267,7 @@ int
bin_whence(char *nam, char **argv, char *ops, int func)
{
HashNode hn;
- Comp com;
+ Patprog pprog;
int returnval = 0;
int printflags = 0;
int csh, all, v, wd;
@@ -1872,7 +2296,7 @@ bin_whence(char *nam, char **argv, char *ops, int func)
for (; *argv; argv++) {
/* parse the pattern */
tokenize(*argv);
- if (!(com = parsereg(*argv))) {
+ if (!(pprog = patcompile(*argv, PAT_STATIC, NULL))) {
untokenize(*argv);
zwarnnam(nam, "bad pattern : %s", *argv, 0);
returnval = 1;
@@ -1883,21 +2307,26 @@ bin_whence(char *nam, char **argv, char *ops, int func)
* We're not using it, so search for ... */
/* aliases ... */
- scanmatchtable(aliastab, com, 0, DISABLED, aliastab->printnode, printflags);
+ scanmatchtable(aliastab, pprog, 0, DISABLED,
+ aliastab->printnode, printflags);
/* and reserved words ... */
- scanmatchtable(reswdtab, com, 0, DISABLED, reswdtab->printnode, printflags);
+ scanmatchtable(reswdtab, pprog, 0, DISABLED,
+ reswdtab->printnode, printflags);
/* and shell functions... */
- scanmatchtable(shfunctab, com, 0, DISABLED, shfunctab->printnode, printflags);
+ scanmatchtable(shfunctab, pprog, 0, DISABLED,
+ shfunctab->printnode, printflags);
/* and builtins. */
- scanmatchtable(builtintab, com, 0, DISABLED, builtintab->printnode, printflags);
+ scanmatchtable(builtintab, pprog, 0, DISABLED,
+ builtintab->printnode, printflags);
}
/* Done search for `internal' commands, if the -p option *
* was not used. Now search the path. */
cmdnamtab->filltable(cmdnamtab);
- scanmatchtable(cmdnamtab, com, 0, 0, cmdnamtab->printnode, printflags);
+ scanmatchtable(cmdnamtab, pprog, 0, 0,
+ cmdnamtab->printnode, printflags);
}
return returnval;
@@ -1979,7 +2408,7 @@ bin_whence(char *nam, char **argv, char *ops, int func)
puts(wd ? ": none" : " not found");
returnval = 1;
}
- } else if ((cnam = findcmd(*argv))) {
+ } else if ((cnam = findcmd(*argv, 1))) {
/* Found external command. */
if (wd) {
printf("%s: command\n", *argv);
@@ -1991,7 +2420,6 @@ bin_whence(char *nam, char **argv, char *ops, int func)
print_if_link(cnam);
fputc('\n', stdout);
}
- zsfree(cnam);
} else {
/* Not found at all. */
if (v || csh || wd)
@@ -2027,7 +2455,7 @@ int
bin_hash(char *name, char **argv, char *ops, int func)
{
HashTable ht;
- Comp com;
+ Patprog pprog;
Asgment asg;
int returnval = 0;
@@ -2065,9 +2493,9 @@ bin_hash(char *name, char **argv, char *ops, int func)
if (ops['m']) {
/* with the -m option, treat the argument as a glob pattern */
tokenize(*argv); /* expand */
- if ((com = parsereg(*argv))) {
+ if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
/* display matching hash table elements */
- scanmatchtable(ht, com, 0, 0, ht->printnode, 0);
+ scanmatchtable(ht, pprog, 0, 0, ht->printnode, 0);
} else {
untokenize(*argv);
zwarnnam(name, "bad pattern : %s", *argv, 0);
@@ -2124,7 +2552,7 @@ bin_unhash(char *name, char **argv, char *ops, int func)
{
HashTable ht;
HashNode hn, nhn;
- Comp com;
+ Patprog pprog;
int match = 0, returnval = 0;
int i;
@@ -2144,13 +2572,13 @@ bin_unhash(char *name, char **argv, char *ops, int func)
for (; *argv; argv++) {
/* expand argument */
tokenize(*argv);
- if ((com = parsereg(*argv))) {
+ if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
/* remove all nodes matching glob pattern */
for (i = 0; i < ht->hsize; i++) {
for (hn = ht->nodes[i]; hn; hn = nhn) {
/* record pointer to next, since we may free this one */
nhn = hn->next;
- if (domatch(hn->nam, com, 0)) {
+ if (pattry(pprog, hn->nam)) {
ht->freenode(ht->removenode(ht, hn->nam));
match++;
}
@@ -2189,7 +2617,7 @@ int
bin_alias(char *name, char **argv, char *ops, int func)
{
Alias a;
- Comp com;
+ Patprog pprog;
Asgment asg;
int haveflags = 0, returnval = 0;
int flags1 = 0, flags2 = DISABLED;
@@ -2210,6 +2638,8 @@ bin_alias(char *name, char **argv, char *ops, int func)
if (ops['L'])
printflags |= PRINT_LIST;
+ else if (ops['r'] == 2 || ops['g'] == 2 || ops['m'] == 2 || ops['+'])
+ printflags |= PRINT_NAMEONLY;
/* In the absence of arguments, list all aliases. If a command *
* line flag is specified, list only those of that type. */
@@ -2223,9 +2653,10 @@ bin_alias(char *name, char **argv, char *ops, int func)
if (ops['m']) {
for (; *argv; argv++) {
tokenize(*argv); /* expand argument */
- if ((com = parsereg(*argv))) {
+ if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
/* display the matching aliases */
- scanmatchtable(aliastab, com, flags1, flags2, aliastab->printnode, printflags);
+ scanmatchtable(aliastab, pprog, flags1, flags2,
+ aliastab->printnode, printflags);
} else {
untokenize(*argv);
zwarnnam(name, "bad pattern : %s", *argv, 0);
@@ -2278,7 +2709,7 @@ bin_false(char *name, char **argv, char *ops, int func)
/* the zle buffer stack */
/**/
-LinkList bufstack;
+mod_export LinkList bufstack;
/* echo, print, pushln */
@@ -2294,38 +2725,46 @@ bin_print(char *name, char **args, char *ops, int func)
/* -m option -- treat the first argument as a pattern and remove
* arguments not matching */
if (ops['m']) {
- Comp com;
+ Patprog pprog;
char **t, **p;
tokenize(*args);
- if (!(com = parsereg(*args))) {
+ if (!(pprog = patcompile(*args, PAT_STATIC, NULL))) {
untokenize(*args);
zwarnnam(name, "bad pattern : %s", *args, 0);
return 1;
}
for (p = ++args; *p; p++)
- if (!domatch(*p, com, 0))
+ if (!pattry(pprog, *p))
for (t = p--; (*t = t[1]); t++);
}
/* compute lengths, and interpret according to -P, -D, -e, etc. */
argc = arrlen(args);
- len = (int *)ncalloc(argc * sizeof(int));
+ len = (int *) hcalloc(argc * sizeof(int));
for(n = 0; n < argc; n++) {
/* first \ sequences */
if (!ops['e'] && (ops['R'] || ops['r'] || ops['E']))
unmetafy(args[n], &len[n]);
else
- args[n] = getkeystring(args[n], &len[n],
- func != BIN_ECHO && !ops['e'], &nnl);
+ args[n] = getkeystring(args[n], &len[n], ops['b'] ? 2 :
+ (func != BIN_ECHO && !ops['e']), &nnl);
/* -P option -- interpret as a prompt sequence */
- if(ops['P'])
- args[n] = unmetafy(promptexpand(metafy(args[n], len[n],
- META_NOALLOC), 0, NULL, NULL), &len[n]);
+ if(ops['P']) {
+ /*
+ * promptexpand uses permanent storage: to avoid
+ * messy memory management, stick it on the heap
+ * instead.
+ */
+ char *str = unmetafy(promptexpand(metafy(args[n], len[n],
+ META_NOALLOC), 0, NULL, NULL), &len[n]);
+ args[n] = dupstring(str);
+ free(str);
+ }
/* -D option -- interpret as a directory, and use ~ */
if(ops['D']) {
Nameddir d = finddir(args[n]);
if(d) {
- char *arg = alloc(strlen(args[n]) + 1);
+ char *arg = zhalloc(strlen(args[n]) + 1);
sprintf(arg, "~%s%s", d->nam,
args[n] + strlen(d->dir));
args[n] = arg;
@@ -2336,9 +2775,7 @@ bin_print(char *name, char **args, char *ops, int func)
/* -z option -- push the arguments onto the editing buffer stack */
if (ops['z']) {
- PERMALLOC {
- pushnode(bufstack, sepjoin(args, NULL));
- } LASTALLOC;
+ zpushnode(bufstack, sepjoin(args, NULL, 0));
return 0;
}
/* -s option -- add the arguments to the history list */
@@ -2346,28 +2783,24 @@ bin_print(char *name, char **args, char *ops, int func)
int nwords = 0, nlen, iwords;
char **pargs = args;
- PERMALLOC {
- ent = gethistent(++curhist);
- zsfree(ent->text);
- if (ent->nwords)
- zfree(ent->words, ent->nwords*2*sizeof(short));
- while (*pargs++)
- nwords++;
- if ((ent->nwords = nwords)) {
- ent->words = (short *)zalloc(nwords*2*sizeof(short));
- nlen = iwords = 0;
- for (pargs = args; *pargs; pargs++) {
- ent->words[iwords++] = nlen;
- nlen += strlen(*pargs);
- ent->words[iwords++] = nlen;
- nlen++;
- }
- } else
- ent->words = (short *)NULL;
- ent->text = zjoin(args, ' ');
- ent->stim = ent->ftim = time(NULL);
- ent->flags = 0;
- } LASTALLOC;
+ ent = prepnexthistent(++curhist);
+ while (*pargs++)
+ nwords++;
+ if ((ent->nwords = nwords)) {
+ ent->words = (short *)zalloc(nwords*2*sizeof(short));
+ nlen = iwords = 0;
+ for (pargs = args; *pargs; pargs++) {
+ ent->words[iwords++] = nlen;
+ nlen += strlen(*pargs);
+ ent->words[iwords++] = nlen;
+ nlen++;
+ }
+ } else
+ ent->words = (short *)NULL;
+ ent->text = zjoin(args, ' ', 0);
+ ent->stim = ent->ftim = time(NULL);
+ ent->flags = 0;
+ addhistnode(histtab, ent->text, ent);
return 0;
}
/* -u and -p -- output to other than standard output */
@@ -2534,7 +2967,7 @@ bin_shift(char *name, char **argv, char *ops, int func)
/* optional argument can be either numeric or an array */
if (*argv && !getaparam(*argv))
- num = matheval(*argv++);
+ num = mathevali(*argv++);
if (num < 0) {
zwarnnam(name, "argument to shift must be non-negative", NULL, 0);
@@ -2549,9 +2982,7 @@ bin_shift(char *name, char **argv, char *ops, int func)
ret++;
continue;
}
- PERMALLOC {
- s = arrdup(s + num);
- } LASTALLOC;
+ s = zarrdup(s + num);
setaparam(*argv, s);
}
} else {
@@ -2570,6 +3001,9 @@ bin_shift(char *name, char **argv, char *ops, int func)
return ret;
}
+/**/
+int optcind;
+
/* getopts: automagical option handling for shell scripts */
/**/
@@ -2579,7 +3013,6 @@ bin_getopts(char *name, char **argv, char *ops, int func)
int lenstr, lenoptstr, quiet, lenoptbuf;
char *optstr = unmetafy(*argv++, &lenoptstr), *var = *argv++;
char **args = (*argv) ? argv : pparams;
- static int optcind = 0;
char *str, optbuf[2] = " ", *p, opch;
/* zoptind keeps count of the current argument number. The *
@@ -2627,14 +3060,14 @@ bin_getopts(char *name, char **argv, char *ops, int func)
if(opch == ':' || !(p = memchr(optstr, opch, lenoptstr))) {
p = "?";
err:
- zsfree(zoptarg);
+ zsfree(zoptarg);
+ setsparam(var, ztrdup(p));
if(quiet) {
- setsparam(var, ztrdup(p));
zoptarg = metafy(optbuf, lenoptbuf, META_DUP);
} else {
zerr(*p == '?' ? "bad option: -%c" :
"argument expected after -%c option", NULL, opch);
- zoptarg=ztrdup("");
+ zoptarg=ztrdup("");
errflag = 0;
}
return 0;
@@ -2674,7 +3107,7 @@ bin_break(char *name, char **argv, char *ops, int func)
/* handle one optional numeric argument */
if (*argv) {
- num = matheval(*argv++);
+ num = mathevali(*argv++);
nump = 1;
}
@@ -2720,7 +3153,7 @@ bin_break(char *name, char **argv, char *ops, int func)
/* we have printed a 'you have stopped (running) jobs.' message */
/**/
-int stopmsg;
+mod_export int stopmsg;
/* check to see if user has jobs running/stopped */
@@ -2754,42 +3187,45 @@ checkjobs(void)
* because of a signal. */
/**/
-void
+mod_export void
zexit(int val, int from_signal)
{
static int in_exit;
- HEAPALLOC {
- if (isset(MONITOR) && !stopmsg && !from_signal) {
- scanjobs(); /* check if jobs need printing */
+ if (isset(MONITOR) && !stopmsg && !from_signal) {
+ scanjobs(); /* check if jobs need printing */
+ if (isset(CHECKJOBS))
checkjobs(); /* check if any jobs are running/stopped */
- if (stopmsg) {
- stopmsg = 2;
- LASTALLOC_RETURN;
- }
- }
- if (in_exit++ && from_signal)
+ if (stopmsg) {
+ stopmsg = 2;
LASTALLOC_RETURN;
- if (isset(MONITOR))
- /* send SIGHUP to any jobs left running */
- killrunjobs(from_signal);
- if (isset(RCS) && interact) {
- if (!nohistsave)
- savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0);
- if (islogin && !subsh) {
- sourcehome(".zlogout");
+ }
+ }
+ if (in_exit++ && from_signal)
+ return;
+
+ if (isset(MONITOR)) {
+ /* send SIGHUP to any jobs left running */
+ killrunjobs(from_signal);
+ }
+ if (isset(RCS) && interact) {
+ if (!nohistsave)
+ savehistfile(NULL, 1, HFILE_USE_OPTIONS);
+ if (islogin && !subsh) {
+ sourcehome(".zlogout");
#ifdef GLOBAL_ZLOGOUT
+ if (isset(RCS) && isset(GLOBALRCS))
source(GLOBAL_ZLOGOUT);
#endif
- }
}
- if (sigtrapped[SIGEXIT])
- dotrap(SIGEXIT);
- if (mypid != getpid())
- _exit(val);
- else
- exit(val);
- } LASTALLOC;
+ }
+ if (sigtrapped[SIGEXIT])
+ dotrap(SIGEXIT);
+ runhookdef(EXITHOOK, NULL);
+ if (mypid != getpid())
+ _exit(val);
+ else
+ exit(val);
}
/* . (dot), source */
@@ -2808,11 +3244,9 @@ bin_dot(char *name, char **argv, char *ops, int func)
return 0;
old = pparams;
/* get arguments for the script */
- if (argv[1]) {
- PERMALLOC {
- pparams = arrdup(argv + 1);
- } LASTALLOC;
- }
+ if (argv[1])
+ pparams = zarrdup(argv + 1);
+
enam = arg0 = ztrdup(*argv);
if (isset(FUNCTIONARGZERO)) {
old0 = argzero;
@@ -2880,6 +3314,8 @@ int
bin_emulate(char *nam, char **argv, char *ops, int func)
{
emulate(*argv, ops['R']);
+ if (ops['L'])
+ opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1;
return 0;
}
@@ -2889,19 +3325,14 @@ bin_emulate(char *nam, char **argv, char *ops, int func)
int
bin_eval(char *nam, char **argv, char *ops, int func)
{
- List list;
-
- inpush(zjoin(argv, ' '), 0, NULL);
- strinbeg();
- stophist = 2;
- list = parse_list();
- strinend();
- inpop();
- if (!list) {
+ Eprog prog;
+
+ prog = parse_string(zjoin(argv, ' ', 1), 0);
+ if (!prog) {
errflag = 0;
return 1;
}
- execlist(list, 1, 0);
+ execode(prog, 1, 0);
if (errflag) {
lastval = errflag;
errflag = 0;
@@ -2928,7 +3359,7 @@ bin_read(char *name, char **args, char *ops, int func)
char *reply, *readpmpt;
int bsiz, c = 0, gotnl = 0, al = 0, first, nchars = 1, bslash;
int haso = 0; /* true if /dev/tty has been opened specially */
- int isem = !strcmp(term, "emacs");
+ int isem = !strcmp(term, "emacs"), izle = zleactive && getkeyptr;
char *buf, *bptr, *firstarg, *zbuforig;
LinkList readll = newlinklist();
@@ -2937,12 +3368,11 @@ bin_read(char *name, char **args, char *ops, int func)
nchars = 1;
args++;
}
-
- firstarg = *args;
- if (*args && **args == '?')
- args++;
- /* default result parameter */
+ /* This `*args++ : *args' looks a bit weird, but it works around a bug
+ * in gcc-2.8.1 under DU 4.0. */
+ firstarg = (*args && **args == '?' ? *args++ : *args);
reply = *args ? *args++ : ops['A'] ? "reply" : "REPLY";
+
if (ops['A'] && *args) {
zwarnnam(name, "only one array argument allowed", NULL, 0);
return 1;
@@ -2953,33 +3383,37 @@ bin_read(char *name, char **args, char *ops, int func)
return compctlread(name, args, ops, reply);
if ((ops['k'] && !ops['u'] && !ops['p']) || ops['q']) {
- if (SHTTY == -1) {
- /* need to open /dev/tty specially */
- SHTTY = open("/dev/tty", O_RDWR|O_NOCTTY);
- haso = 1;
- }
- /* We should have a SHTTY opened by now. */
- if (SHTTY == -1) {
- /* Unfortunately, we didn't. */
- fprintf(stderr, "not interactive and can't open terminal\n");
- fflush(stderr);
- return 1;
+ if (!zleactive) {
+ if (SHTTY == -1) {
+ /* need to open /dev/tty specially */
+ SHTTY = open("/dev/tty", O_RDWR|O_NOCTTY);
+ haso = 1;
+ }
+ /* We should have a SHTTY opened by now. */
+ if (SHTTY == -1) {
+ /* Unfortunately, we didn't. */
+ fprintf(stderr, "not interactive and can't open terminal\n");
+ fflush(stderr);
+ return 1;
+ }
+ if (unset(INTERACTIVE))
+ gettyinfo(&shttyinfo);
+ /* attach to the tty */
+ attachtty(mypgrp);
+ if (!isem && ops['k'])
+ setcbreak();
+ readfd = SHTTY;
}
- if (unset(INTERACTIVE))
- gettyinfo(&shttyinfo);
- /* attach to the tty */
- attachtty(mypgrp);
- if (!isem && ops['k'])
- setcbreak();
- readfd = SHTTY;
} else if (ops['u'] && !ops['p']) {
/* -u means take input from the specified file descriptor. *
* -up means take input from the coprocess. */
for (readfd = 9; readfd && !ops[readfd + '0']; --readfd);
- } else if (ops['p'])
+ izle = 0;
+ } else if (ops['p']) {
readfd = coprocin;
- else
- readfd = 0;
+ izle = 0;
+ } else
+ readfd = izle = 0;
/* handle prompt */
if (firstarg) {
@@ -3003,18 +3437,25 @@ bin_read(char *name, char **args, char *ops, int func)
bptr = buf = (char *)zalloc(nchars+1);
do {
- /* If read returns 0, is end of file */
- if ((val = read(readfd, bptr, nchars)) <= 0)
- break;
+ if (izle) {
+ if ((val = getkeyptr(0)) < 0)
+ break;
+ *bptr++ = (char) val;
+ nchars--;
+ } else {
+ /* If read returns 0, is end of file */
+ if ((val = read(readfd, bptr, nchars)) <= 0)
+ break;
- /* decrement number of characters read from number required */
- nchars -= val;
+ /* decrement number of characters read from number required */
+ nchars -= val;
- /* increment pointer past read characters */
- bptr += val;
+ /* increment pointer past read characters */
+ bptr += val;
+ }
} while (nchars > 0);
- if (!ops['u'] && !ops['p']) {
+ if (!izle && !ops['u'] && !ops['p']) {
/* dispose of result appropriately, etc. */
if (isem)
while (val > 0 && read(SHTTY, &d, 1) == 1 && d != '\n');
@@ -3043,14 +3484,19 @@ bin_read(char *name, char **args, char *ops, int func)
readbuf[1] = '\0';
/* get, and store, reply */
- readbuf[0] = ((char)getquery(NULL, 0)) == 'y' ? 'y' : 'n';
+ if (izle) {
+ int key = getkeyptr(0);
- /* dispose of result appropriately, etc. */
- if (haso) {
- close(SHTTY);
- SHTTY = -1;
- }
+ readbuf[0] = (key == 'y' ? 'y' : 'n');
+ } else {
+ readbuf[0] = ((char)getquery(NULL, 0)) == 'y' ? 'y' : 'n';
+ /* dispose of result appropriately, etc. */
+ if (haso) {
+ close(SHTTY);
+ SHTTY = -1;
+ }
+ }
if (ops['e'] || ops['E'])
printf("%s\n", readbuf);
if (!ops['e'])
@@ -3072,7 +3518,7 @@ bin_read(char *name, char **args, char *ops, int func)
buf = bptr = (char *)zalloc(bsiz = 64);
/* get input, a character at a time */
while (!gotnl) {
- c = zread();
+ c = zread(izle);
/* \ at the end of a line indicates a continuation *
* line, except in raw mode (-r option) */
if (bslash && c == '\n') {
@@ -3162,7 +3608,7 @@ bin_read(char *name, char **args, char *ops, int func)
bslash = 0;
if (!gotnl)
for (;;) {
- c = zread();
+ c = zread(izle);
/* \ at the end of a line introduces a continuation line, except in
raw mode (-r option) */
if (bslash && c == '\n') {
@@ -3171,13 +3617,14 @@ bin_read(char *name, char **args, char *ops, int func)
}
if (c == EOF || (c == '\n' && !zbuf))
break;
- if (!bslash && isep(c) && bptr == buf)
+ if (!bslash && isep(c) && bptr == buf) {
if (iwsep(c))
continue;
else if (!first) {
first = 1;
continue;
}
+ }
bslash = c == '\\' && !bslash && !ops['r'];
if (bslash)
continue;
@@ -3225,12 +3672,17 @@ bin_read(char *name, char **args, char *ops, int func)
/**/
static int
-zread(void)
+zread(int izle)
{
char cc, retry = 0;
+ if (izle) {
+ int c = getkeyptr(0);
+
+ return (c < 0 ? EOF : c);
+ }
/* use zbuf if possible */
- if (zbuf)
+ if (zbuf) {
/* If zbuf points to anything, it points to the next character in the
buffer. This may be a null byte to indicate EOF. If reading from the
buffer, move on the buffer pointer. */
@@ -3238,6 +3690,7 @@ zread(void)
return zbuf++, STOUC(*zbuf++ ^ 32);
else
return (*zbuf) ? STOUC(*zbuf++) : EOF;
+ }
for (;;) {
/* read a character from readfd */
switch (read(readfd, &cc, 1)) {
@@ -3305,7 +3758,8 @@ int
bin_test(char *name, char **argv, char *ops, int func)
{
char **s;
- Cond c;
+ Eprog prog;
+ struct estate state;
/* if "test" was invoked as "[", it needs a matching "]" *
* which is subsequently ignored */
@@ -3325,7 +3779,7 @@ bin_test(char *name, char **argv, char *ops, int func)
tok = NULLTOK;
condlex = testlex;
testlex();
- c = par_cond();
+ prog = parse_cond();
condlex = yylex;
if (errflag) {
@@ -3333,13 +3787,19 @@ bin_test(char *name, char **argv, char *ops, int func)
return 1;
}
- if (!c || tok == LEXERR) {
+ if (!prog || tok == LEXERR) {
zwarnnam(name, tokstr ? "parse error" : "argument expected", NULL, 0);
return 1;
}
/* syntax is OK, so evaluate */
- return !evalcond(c);
+
+ state.prog = prog;
+ state.pc = prog->prog;
+ state.strs = prog->strs;
+
+
+ return !evalcond(&state);
}
/* display a time, provided in units of 1/60s, as minutes and seconds */
@@ -3374,7 +3834,7 @@ bin_times(char *name, char **argv, char *ops, int func)
int
bin_trap(char *name, char **argv, char *ops, int func)
{
- List l;
+ Eprog prog;
char *arg, *s;
int sig;
@@ -3396,7 +3856,7 @@ bin_trap(char *name, char **argv, char *ops, int func)
if (!sigfuncs[sig])
printf("trap -- '' %s\n", sigs[sig]);
else {
- s = getpermtext((void *) dupstruct((void *) sigfuncs[sig]));
+ s = getpermtext(sigfuncs[sig], NULL);
printf("trap -- ");
quotedzputs(s, stdout);
printf(" %s\n", sigs[sig]);
@@ -3422,26 +3882,24 @@ bin_trap(char *name, char **argv, char *ops, int func)
/* Sort out the command to execute on trap */
arg = *argv++;
if (!*arg)
- l = NULL;
- else if (!(l = parse_string(arg))) {
+ prog = &dummy_eprog;
+ else if (!(prog = parse_string(arg, 0))) {
zwarnnam(name, "couldn't parse trap command", NULL, 0);
return 1;
}
/* set traps */
for (; *argv; argv++) {
- List t;
+ Eprog t;
sig = getsignum(*argv);
if (sig == -1) {
zwarnnam(name, "undefined signal: %s", *argv, 0);
break;
}
- PERMALLOC {
- t = (List) dupstruct(l);
- } LASTALLOC;
+ t = dupeprog(prog, 0);
if (settrap(sig, t))
- freestruct(t);
+ freeeprog(t);
}
return *argv != NULL;
}
@@ -3465,10 +3923,10 @@ bin_ttyctl(char *name, char **argv, char *ops, int func)
int
bin_let(char *name, char **argv, char *ops, int func)
{
- long val = 0;
+ zlong val = 0;
while (*argv)
- val = matheval(*argv++);
+ val = mathevali(*argv++);
/* Errors in math evaluation in let are non-fatal. */
errflag = 0;
return !val;
@@ -3591,7 +4049,7 @@ bin_umask(char *nam, char **args, char *ops, int func)
/* Generic builtin for facilities not available on this OS */
/**/
-int
+mod_export int
bin_notavail(char *nam, char **argv, char *ops, int func)
{
zwarnnam(nam, "not available on this system", NULL, 0);