diff --git a/doc/es.1 b/doc/es.1 index 3fb8e790..f0a4c169 100644 --- a/doc/es.1 +++ b/doc/es.1 @@ -2550,6 +2550,15 @@ to the name of a file which contains the output of running the command .IR input . .TP +.Cr "%run \fIprogram argv0 args ...\fP" +Run the named program, which is not searched for in +.Cr $path , +with the argument vector set to the remaining arguments. +This builtin can be used to set +.Cr argv[0] +(by convention, the name of the program) +to something other than file name. +.TP .Cr "%seq \fIcmd ...\fP" Runs the commands, in order. .TP @@ -2614,15 +2623,6 @@ rather than .Cr "%newfd" Returns a file descriptor that the shell thinks is not currently in use. .TP -.Cr "%run \fIprogram argv0 args ...\fP" -Run the named program, which is not searched for in -.Cr $path , -with the argument vector set to the remaining arguments. -This builtin can be used to set -.Cr argv[0] -(by convention, the name of the program) -to something other than file name. -.TP .Cr "%split \fIseparator \fR[\fPargs ...\fR]" Splits its arguments into separate strings at every occurrence of any of the characters in the string diff --git a/es.h b/es.h index 3ef04f7d..495b0d2e 100644 --- a/es.h +++ b/es.h @@ -150,7 +150,6 @@ extern Binding *reversebindings(Binding *binding); /* eval.c */ extern Binding *bindargs(Tree *params, List *args, Binding *binding); -extern List *forkexec(char *file, List *list, Boolean inchild); extern List *walk(Tree *tree, Binding *binding, int flags); extern List *eval(List *list, Binding *binding, int flags); extern List *eval1(Term *term, int flags); diff --git a/eval.c b/eval.c index aaa2d98a..c871f488 100644 --- a/eval.c +++ b/eval.c @@ -4,47 +4,6 @@ unsigned long evaldepth = 0, maxevaldepth = MAXmaxevaldepth; -static Noreturn failexec(char *file, List *args) { - List *fn; - assert(gcisblocked()); - fn = varlookup("fn-%exec-failure", NULL); - if (fn != NULL) { - int olderror = errno; - Ref(List *, list, append(fn, mklist(mkstr(file), args))); - RefAdd(file); - gcenable(); - RefRemove(file); - eval(list, NULL, 0); - RefEnd(list); - errno = olderror; - } - eprint("%s: %s\n", file, esstrerror(errno)); - esexit(1); -} - -/* forkexec -- fork (if necessary) and exec */ -extern List *forkexec(char *file, List *list, Boolean inchild) { - int pid, status; - Vector *env; - gcdisable(); - env = mkenv(); - pid = efork(!inchild, FALSE); - if (pid == 0) { - execve(file, vectorize(list)->vector, env->vector); - failexec(file, list); - } - gcenable(); - status = ewaitfor(pid); - if ((status & 0xff) == 0) { - sigint_newline = FALSE; - SIGCHK(); - sigint_newline = TRUE; - } else - SIGCHK(); - printstatus(0, status); - return mklist(mkterm(mkstatus(status), NULL), NULL); -} - /* assign -- bind a list of values to a list of variables */ static List *assign(Tree *varform, Tree *valueform0, Binding *binding0) { Ref(List *, result, NULL); @@ -449,13 +408,16 @@ extern List *eval(List *list0, Binding *binding0, int flags) { char *error = checkexecutable(name); if (error != NULL) fail("$&whatis", "%s: %s", name, error); + gcdisable(); if (funcname != NULL) { Term *fn = mkstr(funcname); list = mklist(fn, list->next); + funcname = NULL; } - list = forkexec(name, list, flags & eval_inchild); + list = mklist(mkstr("%run"), mklist(mkstr(name), list)); + gcenable(); RefPop(name); - goto done; + goto restart; } RefEnd(name); @@ -463,8 +425,10 @@ extern List *eval(List *list0, Binding *binding0, int flags) { if (fn != NULL && fn->next == NULL && (cp = getclosure(fn->term)) == NULL) { char *name = getstr(fn->term); - list = forkexec(name, list, flags & eval_inchild); - goto done; + gcdisable(); + list = mklist(mkstr("%run"), mklist(mkstr(name), list)); + gcenable(); + goto restart; } if (fn != NULL) diff --git a/prim-sys.c b/prim-sys.c index c0b4f982..6712442d 100644 --- a/prim-sys.c +++ b/prim-sys.c @@ -60,6 +60,47 @@ PRIM(fork) { return mklist(mkstr(mkstatus(status)), NULL); } +static Noreturn failexec(char *file, List *args) { + List *fn; + assert(gcisblocked()); + fn = varlookup("fn-%exec-failure", NULL); + if (fn != NULL) { + int olderror = errno; + Ref(List *, list, append(fn, mklist(mkstr(file), args))); + RefAdd(file); + gcenable(); + RefRemove(file); + eval(list, NULL, 0); + RefEnd(list); + errno = olderror; + } + eprint("%s: %s\n", file, esstrerror(errno)); + esexit(1); +} + +/* forkexec -- fork (if necessary) and exec */ +static List *forkexec(char *file, List *list, Boolean inchild) { + int pid, status; + Vector *env; + gcdisable(); + env = mkenv(); + pid = efork(!inchild, FALSE); + if (pid == 0) { + execve(file, vectorize(list)->vector, env->vector); + failexec(file, list); + } + gcenable(); + status = ewaitfor(pid); + if ((status & 0xff) == 0) { + sigint_newline = FALSE; + SIGCHK(); + sigint_newline = TRUE; + } else + SIGCHK(); + printstatus(0, status); + return mklist(mkterm(mkstatus(status), NULL), NULL); +} + PRIM(run) { char *file; if (list == NULL)