diff --git a/es.h b/es.h index ff00040..4064163 100644 --- a/es.h +++ b/es.h @@ -150,11 +150,9 @@ 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); -extern List *pathsearch(Term *term); extern unsigned long evaldepth, maxevaldepth; #define MINmaxevaldepth 100 diff --git a/eval.c b/eval.c index be50054..a5701d1 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); @@ -345,17 +304,19 @@ extern Binding *bindargs(Tree *params, List *args, Binding *binding) { RefReturn(result); } -/* pathsearch -- evaluate fn %pathsearch + some argument */ -extern List *pathsearch(Term *term) { - List *list; - Ref(List *, search, NULL); - search = varlookup("fn-%pathsearch", NULL); +/* whatis -- evaluate fn %whatis + some argument */ +static List *whatis(Term *term, char *name) { + Ref(List *, list, NULL); + Ref(List *, search, varlookup("fn-%whatis", NULL)); if (search == NULL) - fail("es:pathsearch", "%E: fn %%pathsearch undefined", term); - list = mklist(term, NULL); + fail("es:whatis", "%E: fn %%whatis undefined", term); + gcdisable(); + list = mklist(term, name == NULL ? NULL : mklist(mkstr(name), NULL)); list = append(search, list); RefEnd(search); - return eval(list, NULL, 0); + gcenable(); + list = eval(list, NULL, 0); + RefReturn(list); } /* eval -- evaluate a list, producing a list */ @@ -439,8 +400,6 @@ extern List *eval(List *list0, Binding *binding0, int flags) { goto done; } - /* the logic here is duplicated in $&whatis */ - Ref(char *, name, getstr(list->term)); fn = varlookup2("fn-", name, binding); if (fn != NULL) { @@ -449,28 +408,9 @@ extern List *eval(List *list0, Binding *binding0, int flags) { RefPop(name); goto restart; } - if (isabsolute(name)) { - char *error = checkexecutable(name); - if (error != NULL) - fail("$&whatis", "%s: %s", name, error); - if (funcname != NULL) { - Term *fn = mkstr(funcname); - list = mklist(fn, list->next); - } - list = forkexec(name, list, flags & eval_inchild); - RefPop(name); - goto done; - } RefEnd(name); - fn = pathsearch(list->term); - 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; - } - + fn = whatis(list->term, funcname); if (fn != NULL) funcname = getstr(list->term); list = append(fn, list->next); diff --git a/initial.es b/initial.es index 987919a..1b56499 100644 --- a/initial.es +++ b/initial.es @@ -147,7 +147,27 @@ fn-%newfd = $&newfd fn-%run = $&run fn-%split = $&split fn-%var = $&var -fn-%whatis = $&whatis + +# The %whatis function is called by the shell to convert anything that +# isn't a function into a function that it can call. The shell performs +# its own function lookup, but %whatis does too for user convenience. +# +# $name is the optional name used to refer to the current term being +# looked up, which comes up in cases like `fn-name = /path/to/bin`. + +fn %whatis term name { + if {~ $#name 0} { + name = $term + } + if {!~ $#(fn-$term) 0} { + result $(fn-$term) + } {~ $term /* ./* ../*} { + result %run $term $name + } { + let (searched = <={%pathsearch $term}) + result %run $searched(1) $name $searched(2 ...) + } +} # These builtins are only around as a matter of convenience, so # users don't have to type the infamous <= (nee <>) operator. @@ -165,7 +185,14 @@ fn whatis { echo >[1=2] $message result = $result 1 } { - echo <={%whatis $i} + # Hide the %run call in this "sugary" case. + let (r = <={%whatis $i}) { + if {~ $r(1) %run} { + echo $r(2) $r(4 ...) + } { + echo $r + } + } result = $result 0 } } diff --git a/prim-etc.c b/prim-etc.c index c2dd788..c58dc68 100644 --- a/prim-etc.c +++ b/prim-etc.c @@ -88,32 +88,6 @@ PRIM(flatten) { RefReturn(lp); } -PRIM(whatis) { - /* the logic in here is duplicated in eval() */ - if (list == NULL || list->next != NULL) - fail("$&whatis", "usage: $&whatis program"); - Ref(Term *, term, list->term); - if (getclosure(term) == NULL) { - List *fn; - Ref(char *, prog, getstr(term)); - assert(prog != NULL); - fn = varlookup2("fn-", prog, NULL); - if (fn != NULL) - list = fn; - else { - if (isabsolute(prog)) { - char *error = checkexecutable(prog); - if (error != NULL) - fail("$&whatis", "%s: %s", prog, error); - } else - list = pathsearch(term); - } - RefEnd(prog); - } - RefEnd(term); - return list; -} - PRIM(split) { char *sep; if (list == NULL) @@ -355,7 +329,6 @@ extern Dict *initprims_etc(Dict *primdict) { X(exec); X(dot); X(flatten); - X(whatis); X(split); X(fsplit); X(var); diff --git a/prim-sys.c b/prim-sys.c index 29c2006..a40a386 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)