about summary refs log tree commit diff
path: root/Src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c155
1 files changed, 108 insertions, 47 deletions
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");