summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/builtins.yo13
-rw-r--r--Src/builtin.c17
-rw-r--r--Src/exec.c155
-rw-r--r--Src/hashtable.h1
-rw-r--r--acconfig.h3
-rw-r--r--zshconfig.ac14
7 files changed, 159 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index c60c1d04c..6a73aa012 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2003-09-11 Oliver Kiddle <opk@zsh.org>
+
+ * 19059: acconfig.h, zshconfig.ac, Src/builtin.c, Src/exec.c,
+ Src/hashtable.h, Doc/Zsh/builtins.yo: add -v, -V and -p flags
+ required by POSIX to the command builtin
+
2003-09-10 Wayne Davison <wayned@users.sourceforge.net>
* users/6529 + unposted: StartupFiles/zshenv: updated the comments
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 731474555..b5217abaf 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -194,7 +194,18 @@ followed regardless of the state of the tt(CHASE_LINKS) option.
)
alias(chdir)(cd)
module(clone)(zsh/clone)
-prefix(command)
+findex(command)
+item(tt(command) [ tt(-pvV) ] var(simple command))(
+The simple command argument is taken as an external command instead of
+a function or builtin and is executed. If the tt(POSIX_BUILTINS) option
+is set, builtins will also be executed but certain special properties
+of them are suppressed. The tt(-p) flag causes a default path to be
+searched instead of that in tt($path). With the tt(-v) flag, tt(command)
+is similar to tt(whence) and with tt(-V), it is equivalent to tt(whence
+-v).
+
+See also noderef(Precommand Modifiers).
+)
module(comparguments)(zsh/computil)
module(compcall)(zsh/compctl)
module(compctl)(zsh/compctl)
diff --git a/Src/builtin.c b/Src/builtin.c
index 057800df6..62426facb 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2593,7 +2593,7 @@ bin_unset(char *name, char **argv, Options ops, int func)
return returnval;
}
-/* type, whence, which */
+/* type, whence, which, command */
/**/
int
@@ -2603,6 +2603,7 @@ bin_whence(char *nam, char **argv, Options ops, int func)
Patprog pprog;
int returnval = 0;
int printflags = 0;
+ int aliasflags;
int csh, all, v, wd;
int informed;
char *cnam;
@@ -2624,6 +2625,18 @@ bin_whence(char *nam, char **argv, Options ops, int func)
if (OPT_ISSET(ops,'f'))
printflags |= PRINT_WHENCE_FUNCDEF;
+ if (func == BIN_COMMAND)
+ if (OPT_ISSET(ops,'V')) {
+ printflags = aliasflags = PRINT_WHENCE_VERBOSE;
+ v = 1;
+ } else {
+ aliasflags = PRINT_LIST;
+ printflags = PRINT_WHENCE_SIMPLE;
+ v = 0;
+ }
+ else
+ aliasflags = printflags;
+
/* With -m option -- treat arguments as a glob patterns */
if (OPT_ISSET(ops,'m')) {
for (; *argv; argv++) {
@@ -2677,7 +2690,7 @@ bin_whence(char *nam, char **argv, Options ops, int func)
/* Look for alias */
if ((hn = aliastab->getnode(aliastab, *argv))) {
- aliastab->printnode(hn, printflags);
+ aliastab->printnode(hn, aliasflags);
if (!all)
continue;
informed = 1;
diff --git a/Src/exec.c b/Src/exec.c
index ad992e23e..ba3026e37 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -143,6 +143,10 @@ static int (*execfuncs[]) _((Estate, int)) = {
execarith, execautofn
};
+/* structure for command builtin for when it is used with -v or -V */
+static struct builtin commandbn =
+ BUILTIN(0, 0, bin_whence, 0, -1, BIN_COMMAND, "vV", NULL);
+
/* parse string into a list */
/**/
@@ -243,7 +247,7 @@ zfork(void)
* In zsh this traditionally executes the loop in the current shell, which
* is nice to have if the loop does something to change the shell, like
* setting parameters or calling builtins.
- * Putting the loop in a sub-shell makes live easy, because the shell only
+ * Putting the loop in a sub-shell makes life easy, because the shell only
* has to put it into the job-structure and then treats it as a normal
* process. Suspending and interrupting is no problem then.
* Some years ago, zsh either couldn't suspend such things at all, or
@@ -257,7 +261,7 @@ zfork(void)
* execlist->execpline->execcmd->execwhile->execlist->execpline
*
* (when waiting for the grep, ignoring execpline2 for now). At this time,
- * zsh has build two job-table entries for it: one for the cat and one for
+ * zsh has built two job-table entries for it: one for the cat and one for
* the grep. If the user hits ^Z at this point (and jobbing is used), the
* shell is notified that the grep was suspended. The list_pipe flag is
* used to tell the execpline where it was waiting that it was in a pipeline
@@ -442,7 +446,7 @@ isgooderr(int e, char *dir)
/**/
void
-execute(Cmdnam not_used_yet, int dash)
+execute(Cmdnam not_used_yet, int dash, int defpath)
{
Cmdnam cn;
char buf[MAXCMDLEN], buf2[MAXCMDLEN];
@@ -451,7 +455,7 @@ execute(Cmdnam not_used_yet, int dash)
int eno = 0, ee;
arg0 = (char *) peekfirst(args);
- if (isset(RESTRICTED) && strchr(arg0, '/')) {
+ if (isset(RESTRICTED) && (strchr(arg0, '/') || defpath)) {
zerr("%s: restricted", arg0, 0);
_exit(1);
}
@@ -474,8 +478,6 @@ execute(Cmdnam not_used_yet, int dash)
zsfree(s);
}
- cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0);
-
/* If ARGV0 is in the commands environment, we use *
* that as argv[0] for this external command */
if (unset(RESTRICTED) && (z = zgetenv("ARGV0"))) {
@@ -507,51 +509,89 @@ execute(Cmdnam not_used_yet, int dash)
break;
}
- if (cn) {
- char nn[PATH_MAX], *dptr;
+ /* for command -p, search the default path */
+ if (defpath) {
+ char *s, pbuf[PATH_MAX];
+ char *dptr, *pe, *ps = DEFAULT_PATH;
- if (cn->flags & HASHED)
- strcpy(nn, cn->u.cmd);
- else {
- for (pp = path; pp < cn->u.name; pp++)
- if (!**pp || (**pp == '.' && (*pp)[1] == '\0')) {
- ee = zexecve(arg0, argv);
- if (isgooderr(ee, *pp))
- eno = ee;
- } else if (**pp != '/') {
- z = buf;
- strucpy(&z, *pp);
- *z++ = '/';
- strcpy(z, arg0);
- ee = zexecve(buf, argv);
- if (isgooderr(ee, *pp))
- eno = ee;
- }
- strcpy(nn, cn->u.name ? *(cn->u.name) : "");
- strcat(nn, "/");
- strcat(nn, cn->nam);
+ for(;ps;ps = pe ? pe+1 : NULL) {
+ pe = strchr(ps, ':');
+ if (*ps == '/') {
+ s = pbuf;
+ if (pe)
+ struncpy(&s, ps, pe-ps);
+ else
+ strucpy(&s, ps);
+ *s++ = '/';
+ if ((s - pbuf) + strlen(arg0) >= PATH_MAX)
+ continue;
+ strucpy(&s, arg0);
+ if (iscom(pbuf))
+ break;
+ }
}
- ee = zexecve(nn, argv);
- if ((dptr = strrchr(nn, '/')))
+ if (!ps) {
+ zerr("command not found: %s", arg0, 0);
+ _exit(127);
+ }
+
+ ee = zexecve(pbuf, argv);
+
+ if ((dptr = strrchr(pbuf, '/')))
*dptr = '\0';
- if (isgooderr(ee, *nn ? nn : "/"))
+ if (isgooderr(ee, *pbuf ? pbuf : "/"))
eno = ee;
- }
- for (pp = path; *pp; pp++)
- if (!(*pp)[0] || ((*pp)[0] == '.' && !(*pp)[1])) {
- ee = zexecve(arg0, argv);
- if (isgooderr(ee, *pp))
- eno = ee;
- } else {
- z = buf;
- strucpy(&z, *pp);
- *z++ = '/';
- strcpy(z, arg0);
- ee = zexecve(buf, argv);
- if (isgooderr(ee, *pp))
+
+ } else {
+
+ if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) {
+ char nn[PATH_MAX], *dptr;
+
+ if (cn->flags & HASHED)
+ strcpy(nn, cn->u.cmd);
+ else {
+ for (pp = path; pp < cn->u.name; pp++)
+ if (!**pp || (**pp == '.' && (*pp)[1] == '\0')) {
+ ee = zexecve(arg0, argv);
+ if (isgooderr(ee, *pp))
+ eno = ee;
+ } else if (**pp != '/') {
+ z = buf;
+ strucpy(&z, *pp);
+ *z++ = '/';
+ strcpy(z, arg0);
+ ee = zexecve(buf, argv);
+ if (isgooderr(ee, *pp))
+ eno = ee;
+ }
+ strcpy(nn, cn->u.name ? *(cn->u.name) : "");
+ strcat(nn, "/");
+ strcat(nn, cn->nam);
+ }
+ ee = zexecve(nn, argv);
+
+ if ((dptr = strrchr(nn, '/')))
+ *dptr = '\0';
+ if (isgooderr(ee, *nn ? nn : "/"))
eno = ee;
}
+ for (pp = path; *pp; pp++)
+ if (!(*pp)[0] || ((*pp)[0] == '.' && !(*pp)[1])) {
+ ee = zexecve(arg0, argv);
+ if (isgooderr(ee, *pp))
+ eno = ee;
+ } else {
+ z = buf;
+ strucpy(&z, *pp);
+ *z++ = '/';
+ strcpy(z, arg0);
+ ee = zexecve(buf, argv);
+ if (isgooderr(ee, *pp))
+ eno = ee;
+ }
+ }
+
if (eno)
zerr("%e: %s", arg0, eno);
else
@@ -1692,7 +1732,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
int save[10];
int fil, dfil, is_cursh, type, do_exec = 0, i, htok = 0;
int nullexec = 0, assign = 0, forked = 0;
- int is_shfunc = 0, is_builtin = 0, is_exec = 0;
+ int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0;
/* Various flags to the command. */
int cflags = 0, checked = 0, oautocont = opts[AUTOCONTINUE];
LinkList redir;
@@ -1782,9 +1822,30 @@ execcmd(Estate state, int input, int output, int how, int last1)
}
cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
cflags |= hn->flags;
+ checked = 0;
+ if (cflags & BINF_COMMAND && nextnode(firstnode(args))) {
+ // check for options to command builtin
+ char *next = (char *) getdata(nextnode(firstnode(args)));
+ char *cmdopt;
+ if (next && *next == '-' && strlen(next) == 2 &&
+ (cmdopt = strchr("pvV", next[1])))
+ {
+ if (*cmdopt == 'p') {
+ uremnode(args, firstnode(args));
+ use_defpath = 1;
+ if (nextnode(firstnode(args)))
+ next = (char *) getdata(nextnode(firstnode(args)));
+ } else {
+ hn = (HashNode)&commandbn;
+ is_builtin = 1;
+ break;
+ }
+ }
+ if (!strcmp(next, "--"))
+ uremnode(args, firstnode(args));
+ }
uremnode(args, firstnode(args));
hn = NULL;
- checked = 0;
if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS))
break;
}
@@ -2401,7 +2462,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
zsfree(STTYval);
STTYval = 0;
}
- execute((Cmdnam) hn, cflags & BINF_DASH);
+ execute((Cmdnam) hn, cflags & BINF_DASH, use_defpath);
} else { /* ( ... ) */
DPUTS(varspc,
"BUG: assignment before complex command");
diff --git a/Src/hashtable.h b/Src/hashtable.h
index fdb9ab4fc..131c15c7b 100644
--- a/Src/hashtable.h
+++ b/Src/hashtable.h
@@ -58,6 +58,7 @@
#define BIN_DISABLE 24
#define BIN_ENABLE 25
#define BIN_PRINTF 26
+#define BIN_COMMAND 27
/* These currently depend on being 0 and 1. */
#define BIN_SETOPT 0
diff --git a/acconfig.h b/acconfig.h
index 9887254cd..6de2e387c 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -52,6 +52,9 @@
* anything */
#undef GLOBAL_ZLOGOUT
+/* The default path; used when running commands with command -p */
+#undef DEFAULT_PATH
+
/* Define to 1 if compiler could initialise a union */
#undef HAVE_UNION_INIT
diff --git a/zshconfig.ac b/zshconfig.ac
index b8ae886e0..48bb3c069 100644
--- a/zshconfig.ac
+++ b/zshconfig.ac
@@ -1323,6 +1323,20 @@ if test $zsh_cv_rlimit_vmem_is_as = yes; then
fi
+dnl --------------------------------------------
+dnl CHECK FOR DEFAULT PATH (used for command -p)
+dnl --------------------------------------------
+AC_CACHE_VAL(zsh_cv_cs_path,
+[if getconf _CS_PATH >/dev/null 2>&1; then
+ zsh_cv_cs_path=`getconf _CS_PATH`
+elif getconf CS_PATH >/dev/null 2>&1; then
+ zsh_cv_cs_path=`getconf CS_PATH`
+else
+ zsh_cv_cs_path="/bin:/usr/bin"
+fi])
+AC_DEFINE_UNQUOTED(DEFAULT_PATH, "$zsh_cv_cs_path")
+
+
dnl ----------------------------
dnl CHECK FOR /dev/fd FILESYSTEM
dnl ----------------------------