summaryrefslogtreecommitdiff
path: root/Src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c141
1 files changed, 106 insertions, 35 deletions
diff --git a/Src/exec.c b/Src/exec.c
index f021a0805..978a32d20 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2642,6 +2642,27 @@ execcmd_analyse(Estate state, Execcmd_params eparams)
}
/*
+ * Transfer the first node of args to preargs, performing
+ * prefork expansion on the way if necessary.
+ */
+static void execcmd_getargs(LinkList preargs, LinkList args, int expand)
+{
+ if (!firstnode(args)) {
+ return;
+ } else if (expand) {
+ local_list0(svl);
+ init_list0(svl);
+ /* not init_list1, as we need real nodes */
+ addlinknode(&svl, uremnode(args, firstnode(args)));
+ /* Analysing commands, so vanilla options to prefork */
+ prefork(&svl, 0, NULL);
+ joinlists(preargs, &svl);
+ } else {
+ addlinknode(preargs, uremnode(args, firstnode(args)));
+ }
+}
+
+/*
* Execute a command at the lowest level of the hierarchy.
*/
@@ -2671,6 +2692,11 @@ execcmd_exec(Estate state, Execcmd_params eparams,
LinkList redir = eparams->redir;
Wordcode varspc = eparams->varspc;
int type = eparams->type;
+ /*
+ * preargs comes from expanding the head of the args list
+ * in order to check for prefix commands.
+ */
+ LinkList preargs;
doneps4 = 0;
@@ -2725,9 +2751,19 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* command if it contains some tokens (e.g. x=ex; ${x}port), so this *
* only works in simple cases. has_token() is called to make sure *
* this really is a simple case. */
- if (type == WC_SIMPLE || type == WC_TYPESET) {
- while (args && nonempty(args)) {
- char *cmdarg = (char *) peekfirst(args);
+ if ((type == WC_SIMPLE || type == WC_TYPESET) && args) {
+ /*
+ * preargs contains args that have been expanded by prefork.
+ * Running execcmd_getargs() causes the any argument available
+ * in args to be exanded where necessary and transferred to
+ * preargs. We call execcmd_getargs() every time we need to
+ * analyse an argument not available in preargs, though there is
+ * no guarantee a further argument will be available.
+ */
+ preargs = newlinklist();
+ execcmd_getargs(preargs, args, eparams->htok);
+ while (nonempty(preargs)) {
+ char *cmdarg = (char *) peekfirst(preargs);
checked = !has_token(cmdarg);
if (!checked)
break;
@@ -2766,7 +2802,19 @@ execcmd_exec(Estate state, Execcmd_params eparams,
break;
}
checked = 0;
- if ((cflags & BINF_COMMAND) && nextnode(firstnode(args))) {
+ /*
+ * We usually don't need the argument containing the
+ * precommand modifier itself. Exception: when "command"
+ * will implemented by a call to "whence", in which case
+ * we'll simply re-insert the argument.
+ */
+ uremnode(preargs, firstnode(preargs));
+ if (!firstnode(preargs)) {
+ execcmd_getargs(preargs, args, eparams->htok);
+ if (!firstnode(preargs))
+ break;
+ }
+ if ((cflags & BINF_COMMAND)) {
/*
* Check for options to "command".
* If just -p, this is handled here: use the default
@@ -2776,10 +2824,11 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* Otherwise, just leave marked as BINF_COMMAND
* modifier with no additional action.
*/
- LinkNode argnode = nextnode(firstnode(args));
- char *argdata = (char *) getdata(argnode);
- char *cmdopt;
+ LinkNode argnode, oldnode;
+ char *argdata, *cmdopt;
int has_p = 0, has_vV = 0, has_other = 0;
+ argnode = firstnode(preargs);
+ argdata = (char *) getdata(argnode);
while (IS_DASH(*argdata)) {
/* Just to be definite, stop on single "-", too, */
if (!argdata[1] ||
@@ -2812,25 +2861,30 @@ execcmd_exec(Estate state, Execcmd_params eparams,
break;
}
+ oldnode = argnode;
argnode = nextnode(argnode);
- if (!argnode)
- break;
+ if (!argnode) {
+ execcmd_getargs(preargs, args, eparams->htok);
+ if (!(argnode = nextnode(oldnode)))
+ break;
+ }
argdata = (char *) getdata(argnode);
}
if (has_vV) {
- /* Leave everything alone, dispatch to whence */
+ /*
+ * Leave everything alone, dispatch to whence.
+ * We need to put the name back in the list.
+ */
+ pushnode(preargs, "command");
hn = &commandbn.node;
is_builtin = 1;
break;
} else if (has_p) {
- /* Use default path; absorb command and option. */
- uremnode(args, firstnode(args));
+ /* Use default path */
use_defpath = 1;
- if ((argnode = nextnode(firstnode(args))))
- argdata = (char *) getdata(argnode);
}
/*
- * Else just absorb command and any trailing
+ * Else just any trailing
* end-of-options marker. This can only occur
* if we just had -p or something including more
* than just -p, -v and -V, in which case we behave
@@ -2838,16 +2892,16 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* isn't a good place for standard option handling.
*/
if (IS_DASH(argdata[0]) && IS_DASH(argdata[1]) && !argdata[2])
- uremnode(args, firstnode(args));
- }
- if ((cflags & BINF_EXEC) && nextnode(firstnode(args))) {
+ uremnode(preargs, argnode);
+ } else if (cflags & BINF_EXEC) {
/*
* Check for compatibility options to exec builtin.
* It would be nice to do these more generically,
* but currently we don't have a mechanism for
* precommand modifiers.
*/
- char *next = (char *) getdata(nextnode(firstnode(args)));
+ LinkNode argnode = firstnode(preargs), oldnode;
+ char *argdata = (char *) getdata(argnode);
char *cmdopt, *exec_argv0 = NULL;
/*
* Careful here: we want to make sure a final dash
@@ -2857,17 +2911,23 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* people aren't likely to mix the option style
* with the zsh style.
*/
- while (next && IS_DASH(*next) && strlen(next) >= 2) {
- if (!firstnode(args)) {
+ while (argdata && IS_DASH(*argdata) && strlen(argdata) >= 2) {
+ oldnode = argnode;
+ argnode = nextnode(oldnode);
+ if (!argnode) {
+ execcmd_getargs(preargs, args, eparams->htok);
+ argnode = nextnode(oldnode);
+ }
+ if (!argnode) {
zerr("exec requires a command to execute");
lastval = 1;
errflag |= ERRFLAG_ERROR;
goto done;
}
- uremnode(args, firstnode(args));
- if (IS_DASH(next[0]) && IS_DASH(next[1]) && !next[2])
+ uremnode(preargs, oldnode);
+ if (IS_DASH(argdata[0]) && IS_DASH(argdata[1]) && !argdata[2])
break;
- for (cmdopt = &next[1]; *cmdopt; ++cmdopt) {
+ for (cmdopt = &argdata[1]; *cmdopt; ++cmdopt) {
switch (*cmdopt) {
case 'a':
/* argument is ARGV0 string */
@@ -2876,21 +2936,25 @@ execcmd_exec(Estate state, Execcmd_params eparams,
/* position on last non-NULL character */
cmdopt += strlen(cmdopt+1);
} else {
- if (!firstnode(args)) {
+ if (!argnode) {
zerr("exec requires a command to execute");
lastval = 1;
errflag |= ERRFLAG_ERROR;
goto done;
}
- if (!nextnode(firstnode(args))) {
+ if (!nextnode(argnode))
+ execcmd_getargs(preargs, args,
+ eparams->htok);
+ if (!nextnode(argnode)) {
zerr("exec flag -a requires a parameter");
lastval = 1;
errflag |= ERRFLAG_ERROR;
goto done;
}
- exec_argv0 = (char *)
- getdata(nextnode(firstnode(args)));
- uremnode(args, firstnode(args));
+ exec_argv0 = (char *) getdata(argnode);
+ oldnode = argnode;
+ argnode = nextnode(argnode);
+ uremnode(args, oldnode);
}
break;
case 'c':
@@ -2906,8 +2970,9 @@ execcmd_exec(Estate state, Execcmd_params eparams,
return;
}
}
- if (firstnode(args) && nextnode(firstnode(args)))
- next = (char *) getdata(nextnode(firstnode(args)));
+ if (!argnode)
+ break;
+ argdata = (char *) getdata(argnode);
}
if (exec_argv0) {
char *str, *s;
@@ -2919,12 +2984,14 @@ execcmd_exec(Estate state, Execcmd_params eparams,
zputenv(str);
}
}
- uremnode(args, firstnode(args));
hn = NULL;
if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS))
break;
+ if (!nonempty(preargs))
+ execcmd_getargs(preargs, args, eparams->htok);
}
- }
+ } else
+ preargs = NULL;
/* if we get this far, it is OK to pay attention to lastval again */
if (noerrexit == 2 && !is_shfunc)
@@ -2946,8 +3013,12 @@ execcmd_exec(Estate state, Execcmd_params eparams,
esprefork = (magic_assign ||
(isset(MAGICEQUALSUBST) && type != WC_TYPESET)) ?
PREFORK_TYPESET : 0;
- if (args && eparams->htok)
- prefork(args, esprefork, NULL);
+ if (args) {
+ if (eparams->htok)
+ prefork(args, esprefork, NULL);
+ if (preargs)
+ args = joinlists(preargs, args);
+ }
if (type == WC_SIMPLE || type == WC_TYPESET) {
int unglobbed = 0;