1
0
Fork 0
mirror of git://slackware.nl/current.git synced 2025-02-14 08:48:37 +01:00
slackware-current/source/ap/ash/patches/ash-builtin.patch

844 lines
20 KiB
Diff
Raw Normal View History

diff -urN netbsd-sh/builtins.def ash-0.3.7.orig/builtins.def
--- netbsd-sh/builtins.def Mon Apr 10 13:02:58 2000
+++ ash-0.3.7.orig/builtins.def Mon Apr 23 22:16:46 2001
@@ -49,12 +49,13 @@
#
# NOTE: bltincmd must come first!
-bltincmd command
+bltincmd builtin
#alloccmd alloc
bgcmd -j bg
breakcmd break continue
#catfcmd catf
cdcmd cd chdir
+commandcmd command
dotcmd .
echocmd echo
evalcmd eval
diff -urN netbsd-sh/eval.c ash-0.3.7.orig/eval.c
--- netbsd-sh/eval.c Tue May 23 12:03:18 2000
+++ ash-0.3.7.orig/eval.c Mon Apr 23 22:16:46 2001
@@ -45,7 +45,9 @@
#endif
#endif /* not lint */
+#include <sys/types.h>
#include <signal.h>
+#include <malloc.h>
#include <unistd.h>
/*
@@ -101,6 +103,8 @@
STATIC void evalpipe __P((union node *));
STATIC void evalcommand __P((union node *, int, struct backcmd *));
STATIC void prehash __P((union node *));
+STATIC int is_assignment_builtin __P((const char *));
+STATIC const char *get_standard_path __P((void));
/*
@@ -257,6 +261,11 @@
evalcase(n, flags);
break;
case NDEFUN:
+ if (is_special_builtin(n->narg.text)) {
+ outfmt(out2, "%s is a special built-in\n", n->narg.text);
+ exitstatus = 1;
+ break;
+ }
defun(n->narg.text, n->narg.next);
exitstatus = 0;
break;
@@ -497,9 +507,14 @@
close(0);
copyfd(prevfd, 0);
close(prevfd);
+ if (pip[0] == 0) {
+ pip[0] = -1;
+ }
}
if (pip[1] >= 0) {
- close(pip[0]);
+ if (pip[0] >= 0) {
+ close(pip[0]);
+ }
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1);
@@ -607,6 +622,7 @@
int argc;
char **envp;
int varflag;
+ int pseudovarflag;
struct strlist *sp;
int mode;
int pip[2];
@@ -619,12 +635,17 @@
struct localvar *volatile savelocalvars;
volatile int e;
char *lastarg;
+ int not_special;
+ const char *path;
+ const char *standard_path;
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &argv;
(void) &argc;
(void) &lastarg;
(void) &flags;
+ (void) &not_special;
+ (void) &standard_path;
#endif
/* First expand the arguments. */
@@ -632,21 +653,31 @@
setstackmark(&smark);
arglist.lastp = &arglist.list;
varlist.lastp = &varlist.list;
+ arglist.list = 0;
varflag = 1;
+ pseudovarflag = 0;
oexitstatus = exitstatus;
exitstatus = 0;
+ not_special = 0;
+ path = pathval();
+ standard_path = NULL;
for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
char *p = argp->narg.text;
- if (varflag && is_name(*p)) {
+ if ((varflag || pseudovarflag) && is_name(*p)) {
do {
p++;
} while (is_in_name(*p));
if (*p == '=') {
- expandarg(argp, &varlist, EXP_VARTILDE);
+ if (varflag)
+ expandarg(argp, &varlist, EXP_VARTILDE);
+ else
+ expandarg(argp, &arglist, EXP_VARTILDE);
continue;
}
}
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ if (varflag && arglist.list && is_assignment_builtin(arglist.list->text))
+ pseudovarflag = 1;
varflag = 0;
}
*arglist.lastp = NULL;
@@ -688,37 +719,75 @@
cmdentry.u.index = BLTINCMD;
} else {
static const char PATH[] = "PATH=";
- const char *path = pathval();
+ const char *oldpath = NULL;
+ int findflag = DO_ERR;
/*
* Modify the command lookup path, if a PATH= assignment
* is present
*/
for (sp = varlist.list ; sp ; sp = sp->next)
- if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
+ if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
path = sp->text + sizeof(PATH) - 1;
-
- find_command(argv[0], &cmdentry, DO_ERR, path);
- if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
- exitstatus = 127;
- flushout(&errout);
- return;
- }
- /* implement the bltin builtin here */
- if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
- for (;;) {
+ findflag |= DO_BRUTE;
+ }
+ for(;;) {
+ find_command(argv[0], &cmdentry, findflag, path);
+ if (oldpath) {
+ path = oldpath;
+ oldpath = NULL;
+ }
+ if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
+ exitstatus = 127;
+ flushout(&errout);
+ goto out;
+ }
+ /* implement the bltin builtin here */
+ if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
+ not_special = 1;
+ for(;;) {
+ argv++;
+ if (--argc == 0)
+ break;
+ if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
+ outfmt(&errout, "%s: not found\n", *argv);
+ exitstatus = 127;
+ flushout(&errout);
+ goto out;
+ }
+ if (cmdentry.u.index != BLTINCMD)
+ break;
+ }
+ }
+ if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == COMMANDCMD) {
+ not_special = 1;
argv++;
- if (--argc == 0)
- break;
- if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
- outfmt(&errout, "%s: not found\n", *argv);
- exitstatus = 127;
- flushout(&errout);
- return;
+ if (--argc == 0) {
+ exitstatus = 0;
+ goto out;
}
- if (cmdentry.u.index != BLTINCMD)
- break;
+ if (*argv[0] == '-') {
+ if (!equal(argv[0], "-p")) {
+ argv--;
+ argc++;
+ break;
+ }
+ argv++;
+ if (--argc == 0) {
+ exitstatus = 0;
+ goto out;
+ }
+ if (!standard_path) {
+ standard_path = get_standard_path();
+ }
+ oldpath = path;
+ path = standard_path;
+ findflag |= DO_BRUTE;
+ }
+ findflag |= DO_NOFUN;
+ continue;
}
+ break;
}
}
@@ -756,13 +825,12 @@
#ifdef DEBUG
trputs("Shell function: "); trargs(argv);
#endif
+ exitstatus = oexitstatus;
redirect(cmd->ncmd.redirect, REDIR_PUSH);
saveparam = shellparam;
shellparam.malloc = 0;
- shellparam.reset = 1;
shellparam.nparam = argc - 1;
shellparam.p = argv + 1;
- shellparam.optnext = NULL;
INTOFF;
savelocalvars = localvars;
localvars = NULL;
@@ -772,6 +840,8 @@
freeparam((volatile struct shparam *)
&saveparam);
} else {
+ saveparam.optind = shellparam.optind;
+ saveparam.optoff = shellparam.optoff;
freeparam(&shellparam);
shellparam = saveparam;
}
@@ -790,6 +860,8 @@
INTOFF;
poplocalvars();
localvars = savelocalvars;
+ saveparam.optind = shellparam.optind;
+ saveparam.optoff = shellparam.optoff;
freeparam(&shellparam);
shellparam = saveparam;
handler = savehandler;
@@ -832,6 +908,8 @@
out1 = &output;
out2 = &errout;
freestdout();
+ if (!not_special && is_special_builtin(commandname))
+ listsetvar(cmdenviron);
cmdenviron = NULL;
if (e != EXSHELLPROC) {
commandname = savecmdname;
@@ -867,7 +953,7 @@
for (sp = varlist.list ; sp ; sp = sp->next)
setvareq(sp->text, VEXPORT|VSTACK);
envp = environment();
- shellexec(argv, envp, pathval(), cmdentry.u.index);
+ shellexec(argv, envp, path, cmdentry.u.index);
}
goto out;
@@ -1025,4 +1111,49 @@
shellexec(argv + 1, environment(), pathval(), 0);
}
return 0;
+}
+
+STATIC int
+is_assignment_builtin (command)
+ const char *command;
+{
+ static const char *assignment_builtins[] = {
+ "alias", "declare", "export", "local", "readonly", "typeset",
+ (char *)NULL
+ };
+ int i;
+
+ for (i = 0; assignment_builtins[i]; i++)
+ if (strcmp(command, assignment_builtins[i]) == 0) return 1;
+ return 0;
+}
+
+int
+is_special_builtin(name)
+ const char *name;
+{
+ static const char *special_builtins[] = {
+ "break", ":", ".", "continue", "eval", "exec", "exit",
+ "export", "readonly", "return", "set", "shift", "times",
+ "trap", "unset", (char *)NULL
+ };
+ int i;
+
+ if (!name) return 0;
+ for (i = 0; special_builtins[i]; i++)
+ if (equal(name, special_builtins[i])) return 1;
+ return 0;
+}
+
+STATIC const char *
+get_standard_path()
+{
+ char *p;
+ size_t len;
+
+ len = confstr(_CS_PATH, NULL, 0);
+ p = stalloc(len + 2);
+ *p = '\0';
+ confstr(_CS_PATH, p, len);
+ return p;
}
diff -urN netbsd-sh/eval.h ash-0.3.7.orig/eval.h
--- netbsd-sh/eval.h Fri Jan 28 13:03:00 2000
+++ ash-0.3.7.orig/eval.h Mon Apr 23 22:16:46 2001
@@ -61,6 +61,7 @@
int falsecmd __P((int, char **));
int truecmd __P((int, char **));
int execcmd __P((int, char **));
+int is_special_builtin __P((const char *));
/* in_function returns nonzero if we are currently evaluating a function */
#define in_function() funcnest
diff -urN netbsd-sh/exec.c ash-0.3.7.orig/exec.c
--- netbsd-sh/exec.c Fri Jan 12 17:50:35 2001
+++ ash-0.3.7.orig/exec.c Mon Apr 23 22:16:46 2001
@@ -51,6 +51,7 @@
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
+#include <sysexits.h>
/*
* When commands are first encountered, they are entered in a hash table.
@@ -108,6 +109,9 @@
STATIC void clearcmdentry __P((int));
STATIC struct tblentry *cmdlookup __P((char *, int));
STATIC void delete_cmd_entry __P((void));
+STATIC int describe_command __P((char *, int));
+STATIC int path_change __P((const char *, int *));
+STATIC int is_regular_builtin __P((const char *));
@@ -164,7 +172,7 @@
char **envp;
{
int e;
-#ifndef BSD
+#if !defined(BSD) && !defined(linux)
char *p;
#endif
@@ -180,7 +188,7 @@
initshellproc();
setinputfile(cmd, 0);
commandname = arg0 = savestr(argv[0]);
-#ifndef BSD
+#if !defined(BSD) && !defined(linux)
pgetc(); pungetc(); /* fill up input buffer */
p = parsenextc;
if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
@@ -195,7 +203,7 @@
}
-#ifndef BSD
+#if !defined(BSD) && !defined(linux)
/*
* Execute an interpreter introduced by "#!", for systems where this
* feature has not been built into the kernel. If the interpreter is
@@ -351,27 +359,29 @@
if (*argptr == NULL) {
for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
- printentry(cmdp, verbose);
+ if (cmdp->cmdtype != CMDBUILTIN) {
+ printentry(cmdp, verbose);
+ }
}
}
return 0;
}
+ c = 0;
while ((name = *argptr) != NULL) {
if ((cmdp = cmdlookup(name, 0)) != NULL
&& (cmdp->cmdtype == CMDNORMAL
|| (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
delete_cmd_entry();
find_command(name, &entry, DO_ERR, pathval());
- if (verbose) {
- if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */
- cmdp = cmdlookup(name, 0);
- printentry(cmdp, verbose);
- }
+ if (entry.cmdtype == CMDUNKNOWN) c = 1;
+ else if (verbose) {
+ cmdp = cmdlookup(name, 0);
+ if (cmdp) printentry(cmdp, verbose);
flushall();
}
argptr++;
}
- return 0;
+ return c;
}
@@ -435,6 +445,10 @@
struct stat statb;
int e;
int i;
+ int bltin;
+ int firstchange;
+ int updatetbl;
+ int regular;
/* If name contains a slash, don't use the hash table */
if (strchr(name, '/') != NULL) {
@@ -459,12 +473,54 @@
return;
}
+ updatetbl = 1;
+ if (act & DO_BRUTE) {
+ firstchange = path_change(path, &bltin);
+ } else {
+ bltin = builtinloc;
+ firstchange = 9999;
+ }
+
/* If name is in the table, and not invalidated by cd, we're done */
- if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
- goto success;
+ if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
+ if (cmdp->cmdtype == CMDFUNCTION) {
+ if (act & DO_NOFUN) {
+ updatetbl = 0;
+ } else {
+ goto success;
+ }
+ } else if (act & DO_BRUTE) {
+ if ((cmdp->cmdtype == CMDNORMAL &&
+ cmdp->param.index >= firstchange) ||
+ (cmdp->cmdtype == CMDBUILTIN &&
+ ((builtinloc < 0 && bltin >= 0) ?
+ bltin : builtinloc) >= firstchange)) {
+ /* need to recompute the entry */
+ } else {
+ goto success;
+ }
+ } else {
+ goto success;
+ }
+ }
+
+ if ((regular = is_regular_builtin(name))) {
+ if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
+ goto success;
+ }
+ } else if (act & DO_BRUTE) {
+ if (firstchange == 0) {
+ updatetbl = 0;
+ }
+ }
/* If %builtin not in path, check for builtin next */
- if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
+ if ((bltin < 0 || regular) && (i = find_builtin(name)) >= 0) {
+ if (!updatetbl) {
+ entry->cmdtype = CMDBUILTIN;
+ entry->u.index = i;
+ return;
+ }
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
@@ -475,7 +531,7 @@
/* We have to search path. */
prev = -1; /* where to start */
- if (cmdp) { /* doing a rehash */
+ if (cmdp && cmdp->rehash) { /* doing a rehash */
if (cmdp->cmdtype == CMDBUILTIN)
prev = builtinloc;
else
@@ -488,26 +544,38 @@
while ((fullname = padvance(&path, name)) != NULL) {
stunalloc(fullname);
idx++;
+ if (idx >= firstchange) {
+ updatetbl = 0;
+ }
if (pathopt) {
if (prefix("builtin", pathopt)) {
- if ((i = find_builtin(name)) < 0)
- goto loop;
- INTOFF;
- cmdp = cmdlookup(name, 1);
- cmdp->cmdtype = CMDBUILTIN;
- cmdp->param.index = i;
- INTON;
- goto success;
- } else if (prefix("func", pathopt)) {
+ if ((i = find_builtin(name)) >= 0) {
+ if (!updatetbl) {
+ entry->cmdtype = CMDBUILTIN;
+ entry->u.index = i;
+ return;
+ }
+ INTOFF;
+ cmdp = cmdlookup(name, 1);
+ cmdp->cmdtype = CMDBUILTIN;
+ cmdp->param.index = i;
+ INTON;
+ goto success;
+ } else {
+ continue;
+ }
+ } else if (!(act & DO_NOFUN) &&
+ prefix("func", pathopt)) {
/* handled below */
} else {
- goto loop; /* ignore unimplemented options */
+ continue; /* ignore unimplemented options */
}
}
/* if rehash, don't redo absolute path names */
- if (fullname[0] == '/' && idx <= prev) {
+ if (fullname[0] == '/' && idx <= prev &&
+ idx < firstchange) {
if (idx < prev)
- goto loop;
+ continue;
TRACE(("searchexec \"%s\": no change\n", name));
goto success;
}
@@ -522,7 +590,7 @@
}
e = EACCES; /* if we fail, this will be the error */
if (!S_ISREG(statb.st_mode))
- goto loop;
+ continue;
if (pathopt) { /* this is a %func directory */
stalloc(strlen(fullname) + 1);
readcmdfile(fullname);
@@ -544,6 +612,13 @@
}
#endif
TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
+ /* If we aren't called with DO_BRUTE and cmdp is set, it must
+ be a function and we're being called with DO_NOFUN */
+ if (!updatetbl) {
+ entry->cmdtype = CMDNORMAL;
+ entry->u.index = idx;
+ return;
+ }
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDNORMAL;
@@ -553,7 +628,7 @@
}
/* We failed. If there was an entry for this command, delete it */
- if (cmdp)
+ if (cmdp && updatetbl)
delete_cmd_entry();
if (act & DO_ERR)
outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
@@ -618,37 +693,12 @@
changepath(newval)
const char *newval;
{
- const char *old, *new;
- int idx;
int firstchange;
int bltin;
- old = pathval();
- new = newval;
- firstchange = 9999; /* assume no change */
- idx = 0;
- bltin = -1;
- for (;;) {
- if (*old != *new) {
- firstchange = idx;
- if ((*old == '\0' && *new == ':')
- || (*old == ':' && *new == '\0'))
- firstchange++;
- old = new; /* ignore subsequent differences */
- }
- if (*new == '\0')
- break;
- if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
- bltin = idx;
- if (*new == ':') {
- idx++;
- }
- new++, old++;
- }
+ firstchange = path_change(newval, &bltin);
if (builtinloc < 0 && bltin >= 0)
builtinloc = bltin; /* zap builtins */
- if (builtinloc >= 0 && bltin < 0)
- firstchange = 0;
clearcmdentry(firstchange);
builtinloc = bltin;
}
@@ -838,11 +888,9 @@
{
struct cmdentry entry;
- INTOFF;
entry.cmdtype = CMDFUNCTION;
entry.u.func = copyfunc(func);
addcmdentry(name, &entry);
- INTON;
}
@@ -944,4 +992,190 @@
}
}
return err;
+}
+
+STATIC int
+describe_command(command, verbose)
+ char *command;
+ int verbose;
+{
+ struct cmdentry entry;
+ struct tblentry *cmdp;
+ char **pp;
+ struct alias *ap;
+ extern char *const parsekwd[];
+
+ for (pp = (char **)parsekwd; *pp; pp++)
+ if (**pp == *command && equal(*pp, command))
+ break;
+
+ if (*pp) {
+ if (verbose) {
+ out1fmt("%s is a reserved word\n", command);
+ } else {
+ out1fmt("%s\n", command);
+ }
+ return 0;
+ }
+
+ /* Then look at the aliases */
+ if ((ap = lookupalias(command, 1)) != NULL) {
+ if (verbose) {
+ out1fmt("%s is aliased to `%s'\n", command, ap->val);
+ } else {
+ out1fmt("alias %s='%s'\n", command, ap->val);
+ }
+ return 0;
+ }
+
+ /* Then check if it is a tracked alias */
+ if ((cmdp = cmdlookup(command, 0)) != NULL) {
+ entry.cmdtype = cmdp->cmdtype;
+ entry.u = cmdp->param;
+ }
+ else {
+ /* Finally use brute force */
+ find_command(command, &entry, DO_ABS, pathval());
+ }
+
+ switch (entry.cmdtype) {
+ case CMDNORMAL: {
+ int j = entry.u.index;
+ const char *path = pathval();
+ char *name;
+ if (j == -1)
+ name = command;
+ else {
+ do {
+ name = padvance(&path, command);
+ stunalloc(name);
+ } while (--j >= 0);
+ }
+ if (verbose) {
+ out1fmt("%s is %s\n", command, name);
+ } else {
+ out1fmt("%s\n", name);
+ }
+ break;
+ }
+ case CMDFUNCTION:
+ if (verbose) {
+ out1fmt("%s is a function\n", command);
+ } else {
+ out1fmt("%s\n", command);
+ }
+ break;
+ case CMDBUILTIN:
+ if (verbose) {
+ if (is_special_builtin(command)) {
+ out1fmt("%s is a special built-in utility\n", command);
+ } else {
+ out1fmt("%s is a built-in utility\n", command);
+ }
+ } else {
+ out1fmt("%s\n", command);
+ }
+ break;
+ default:
+ outfmt(out2, "%s not found\n", command);
+ return 127;
+ }
+
+ return 0;
+}
+
+int
+commandcmd(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int default_path = 0;
+ int verify_only = 0;
+ int verbose_verify_only = 0;
+
+ while ((c = nextopt("pvV")) != '\0')
+ switch (c) {
+ case 'p':
+ default_path = 1;
+ break;
+ case 'v':
+ verify_only = 1;
+ break;
+ case 'V':
+ verbose_verify_only = 1;
+ break;
+ default:
+ outfmt(out2,
+"command: nextopt returned character code 0%o\n", c);
+ return EX_SOFTWARE;
+ }
+
+ if (default_path + verify_only + verbose_verify_only > 1 ||
+ !*argptr) {
+ outfmt(out2,
+"command [-p] command [arg ...]\n");
+ outfmt(out2,
+"command {-v|-V} command\n");
+ return EX_USAGE;
+ }
+
+ if (verify_only || verbose_verify_only) {
+ return describe_command(*argptr, verbose_verify_only);
+ }
+
+ return 0;
+}
+
+STATIC int
+path_change(newval, bltin)
+ const char *newval;
+ int *bltin;
+{
+ const char *old, *new;
+ int idx;
+ int firstchange;
+
+ old = pathval();
+ new = newval;
+ firstchange = 9999; /* assume no change */
+ idx = 0;
+ *bltin = -1;
+ for (;;) {
+ if (*old != *new) {
+ firstchange = idx;
+ if ((*old == '\0' && *new == ':')
+ || (*old == ':' && *new == '\0'))
+ firstchange++;
+ old = new; /* ignore subsequent differences */
+ }
+ if (*new == '\0')
+ break;
+ if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
+ *bltin = idx;
+ if (*new == ':') {
+ idx++;
+ }
+ new++, old++;
+ }
+ if (builtinloc >= 0 && *bltin < 0)
+ firstchange = 0;
+ return firstchange;
+}
+
+STATIC int
+is_regular_builtin(name)
+ const char *name;
+{
+ static const char *regular_builtins[] = {
+ "alias", "bg", "cd", "command", "false", "fc", "fg",
+ "getopts", "jobs", "kill", "newgrp", "read", "true",
+ "umask", "unalias", "wait", (char *)NULL
+ };
+ int i;
+
+ if (!name) return 0;
+ for (i = 0; regular_builtins[i]; i++)
+ if (equal(name, regular_builtins[i])) return 1;
+ return 0;
}
diff -urN netbsd-sh/exec.h ash-0.3.7.orig/exec.h
--- netbsd-sh/exec.h Tue May 23 12:03:19 2000
+++ ash-0.3.7.orig/exec.h Mon Apr 23 22:16:46 2001
@@ -56,6 +56,8 @@
#define DO_ERR 1 /* find_command prints errors */
#define DO_ABS 2 /* find_command checks absolute paths */
+#define DO_NOFUN 4 /* find_command ignores functions */
+#define DO_BRUTE 8 /* find_command ignores hash table */
extern const char *pathopt; /* set by padvance */
extern int exerrno; /* last exec error */
@@ -74,3 +76,4 @@
void defun __P((char *, union node *));
int unsetfunc __P((char *));
int typecmd __P((int, char **));
+int commandcmd __P((int, char **));