commit 5556dde4d3ad4e34267320b1411fc090b18a24b0
parent 26bb34cf036027dfa22dfae8d8fc2f6bfd6acb75
Author: Byron Rakitzis <byron@archone.tamu.edu>
Date: Mon, 7 Mar 1994 00:00:01 +0000
beta: rc-1.5betadev1
Diffstat:
M | CHANGES | | | 92 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | Makefile | | | 2 | +- |
M | README | | | 13 | ++++++++++++- |
M | builtins.c | | | 60 | +++++++++++++++++++++++++++++++++++++++++++----------------- |
M | except.c | | | 2 | +- |
M | exec.c | | | 13 | ++++++++++++- |
M | fn.c | | | 33 | ++++++++++++--------------------- |
M | footobar.c | | | 175 | +++++++++++++++++++++++++++++++++---------------------------------------------- |
M | glob.c | | | 50 | ++++++++++++++++++++++++++++++++++++++++---------- |
M | glom.c | | | 20 | +++++++++++++------- |
M | hash.c | | | 16 | +++++++++------- |
M | history/history.c | | | 12 | ++++++++++-- |
M | input.c | | | 83 | ++++++++++++++++++++++++++++++++++--------------------------------------------- |
M | lex.c | | | 5 | +---- |
M | main.c | | | 18 | ++++++++++++------ |
M | nalloc.c | | | 2 | ++ |
M | print.c | | | 20 | +++++++++++++++----- |
M | proto.h | | | 1 | + |
M | rc.1 | | | 7 | ++++--- |
M | rc.h | | | 8 | +++----- |
M | signal.c | | | 4 | +--- |
M | status.c | | | 34 | +++++++++++++++++++++------------- |
M | trip.rc | | | 0 | |
M | utils.c | | | 11 | +---------- |
M | var.c | | | 11 | +++++------ |
M | version.c | | | 2 | +- |
M | wait.c | | | 7 | ++++--- |
M | walk.c | | | 30 | ++++++++++++++++++++++-------- |
28 files changed, 446 insertions(+), 285 deletions(-)
diff --git a/CHANGES b/CHANGES
@@ -169,3 +169,95 @@ on.
A memory leak in treefree() was plugged up --- the root node of a
function was not getting freed.
+
+Changes since rc-1.4:
+
+General changes:
+
+ Some small memory leaks/uninit references revealed by Purify.
+
+ $bqstatus for querying the exit status of a backquote.
+
+ Globbing through unreadable directories.
+
+ More options to whatis.
+
+ History append which always re-opens the file (avoids
+ inconsistencies over multiple NFS-mounted accesses to
+ $history).
+
+ Support "rc -s".
+
+---------
+
+Makefile: Added comment referring to README for yacc/malloc problem.
+
+uiltins.c: Added more options to whatis, protected rlimit prototypes
+ with #ifndef SYSVR4, renamed SIGCHK to sigchk.
+
+except.c: Patched nl_on_intr printing to happen only in interactive
+ shells.
+
+exec.c: Added comment explaining nl_on_intr variable, renamed SIGCHK
+ to sigchk.
+
+fn.c: Replaced by-hand consing of exception stack etc. for signal
+ handler execution with call to funcall(). Replaced fun2str
+ call with call on print routines.
+
+footobar.c: Got rid of memory leak in get_name(), parenthesize count,
+ flat and var nodes for correctness in unparsing, removed
+ list2str, made get_name use nalloc space, merge in a
+ better parse_var from es.
+
+glob.c: Split out a test so that closedir is called correctly, renamed
+ SIGCHK to sigchk.
+
+glom.c: Added bqstatus, renamed SIGCHK to sigchk, removed spurious
+ setsigdefaults, patched uninit memory reference, rename
+ "clear" to "memzero", wait for bq subproc to finish on EINTR.
+
+hash.c: Added options to function/variable print code.
+
+history/history.c: Added '@' to the list of chars which can precede an
+ ignored '-'.
+
+input.c: Got rid of tiny memory leak in closefds, got rid of uninit
+ memory reference in popinput, moved nul ignored check into
+ realgchar(), changed history append to always reopen the
+ history file, replaced SIGCHK with sigchk. Freed memory
+ returned by call to readline().
+
+lex.c: Corrected typo in comment, moved nul character ignore code
+ to input routines.
+
+main.c: Added -s flag.
+
+nalloc.c: Added convenience feature to erealloc. (Allow NULL parameter)
+
+print.c: Changed use of va_start so broken compilers can compile
+ print code.
+
+proto.h: Added fake memset.
+
+rc.h: Replaced clear() function prototype with a macro call on
+ memset(), removed SIGCHK, fixed prototypes.
+
+signal.c: Removed unconditional exit in catcher code, renamed SIGCHK
+ to sigchk.
+
+status.c: Rewrite sgetstatus breaking out strstatus so that bqstatus
+ can be set from glom routines.
+
+utils.c: Got rid of clear() (use memset from C library), rename SIGCHK
+ to sigchk.
+
+var.c: Got rid of memory leak in listassign(), converted list2str()
+ call to something using the print routines.
+
+version.c: New version string.
+
+wait.c: Got rid of memory leak in rc_fork, renamed SIGCHK to sigchk.
+
+walk.c: Fixed pre-redirection bug, removed spurious setsigdefaults(),
+ renamed SIGCHK to sigchk.
diff --git a/Makefile b/Makefile
@@ -21,7 +21,7 @@ CFLAGS=
LDFLAGS=
# You may substitute "bison -y" for yacc. (You want to choose the one that
-# makes a smaller y.tab.c.)
+# makes a smaller y.tab.c. Also see the README about Sun's yacc.)
YACC=yacc
OBJS=$(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \
diff --git a/README b/README
@@ -1,4 +1,4 @@
-This is release 1.4 of rc.
+This is release 1.5 of rc.
Read COPYRIGHT for copying information. All files are
@@ -63,6 +63,17 @@ to get rc to work in a reasonable fashion on a real (i.e., commercial,
non-Labs) UNIX system; a few were changes motivated by concern
about some inadequacies in the original design.
+YACC
+
+The yacc that Sun ships with SunOS 4.1.1 calls malloc() to allocate
+space for the state stack, and requires a call to YYACCEPT or YYABORT
+to free this memory. This means that if rc takes an interrupt while
+parsing a command (say, if ^C is typed), yacc will leak away this
+memory. The solution is to use a yacc which statically allocates
+this array, such as the yacc in the BSD distribution. Berkeley yacc-
+generated y.tab.c and y.tab.h are shipped with rc in case you cannot
+get hold of Berkeley yacc.
+
OLD C
If you need to convert rc's source into K&R C, you need to run the
diff --git a/builtins.c b/builtins.c
@@ -12,6 +12,7 @@
#include <errno.h>
#include "rc.h"
#include "jbwrap.h"
+#include "sigmsgs.h"
#ifndef NOLIMITS
#include <sys/time.h>
#include <sys/resource.h>
@@ -266,7 +267,7 @@ static void b_wait(char **av) {
setstatus(pid, stat);
else
set(FALSE);
- SIGCHK;
+ sigchk();
}
/*
@@ -274,46 +275,69 @@ static void b_wait(char **av) {
is defined as a variable, function or pathname.
*/
+#define not(b) ((b)^TRUE)
+#define show(b) (not(eff|vee|pee|bee|ess)|(b))
+
+static bool issig(char *s) {
+ int i;
+ for (i = 0; i < NUMOFSIGNALS; i++)
+ if (streq(s, signals[i].name))
+ return TRUE;
+ return FALSE;
+}
+
static void b_whatis(char **av) {
+ bool ess, eff, vee, pee, bee;
bool f, found;
- bool ess = FALSE;
int i, ac, c;
List *s;
Node *n;
char *e;
for (rc_optind = ac = 0; av[ac] != NULL; ac++)
; /* count the arguments for getopt */
- while ((c = rc_getopt(ac, av, "s")) == 's')
- ess = TRUE;
- if (c != -1) {
- set(FALSE);
- return;
- }
+ ess = eff = vee = pee = bee = FALSE;
+ while ((c = rc_getopt(ac, av, "sfvpb")) != -1)
+ switch (c) {
+ default: set(FALSE); return;
+ case 's': ess = TRUE; break;
+ case 'f': eff = TRUE; break;
+ case 'v': vee = TRUE; break;
+ case 'p': pee = TRUE; break;
+ case 'b': bee = TRUE; break;
+ }
av += rc_optind;
- if (*av == NULL && !ess) {
- whatare_all_vars();
+ if (*av == NULL) {
+ if (vee|eff)
+ whatare_all_vars(eff, vee);
+ if (ess)
+ whatare_all_signals();
+ if (bee)
+ for (i = 0; i < arraysize(builtins); i++)
+ fprint(1, "builtin %s\n", builtins[i].name);
+ if (pee)
+ fprint(2, "whatis -p: must specify argument\n");
+ if (show(FALSE)) /* no options? */
+ whatare_all_vars(TRUE, TRUE);
set(TRUE);
return;
}
- if (ess)
- whatare_all_signals();
found = TRUE;
for (i = 0; av[i] != NULL; i++) {
f = FALSE;
errno = ENOENT;
- if ((s = varlookup(av[i])) != NULL) {
+ if (show(vee) && (s = varlookup(av[i])) != NULL) {
f = TRUE;
prettyprint_var(1, av[i], s);
}
- if ((n = fnlookup(av[i])) != NULL) {
+ if (((show(ess)&&issig(av[i])) || show(eff)) && (n = fnlookup(av[i])) != NULL) {
f = TRUE;
prettyprint_fn(1, av[i], n);
- } else if (isbuiltin(av[i]) != NULL) {
+ } else if (show(bee) && isbuiltin(av[i]) != NULL) {
f = TRUE;
fprint(1, "builtin %s\n", av[i]);
- } else if ((e = which(av[i], FALSE)) != NULL) {
+ } else if (show(pee) && (e = which(av[i], FALSE)) != NULL) {
f = TRUE;
- fprint(1, "%s\n", e);
+ fprint(1, "%S\n", e);
}
if (!f) {
found = FALSE;
@@ -440,8 +464,10 @@ static const Limit limits[] = {
{ NULL, 0, NULL }
};
+#ifndef SYSVR4
extern int getrlimit(int, struct rlimit *);
extern int setrlimit(int, struct rlimit *);
+#endif
static void printlimit(const Limit *limit, bool hard) {
struct rlimit rlim;
diff --git a/except.c b/except.c
@@ -131,7 +131,7 @@ extern void sigint(int s) {
if (s != SIGINT)
panic("s != SIGINT in sigint catcher");
/* this is the newline you see when you hit ^C while typing a command */
- if (nl_on_intr)
+ if (interactive && nl_on_intr)
fprint(2, "\n");
nl_on_intr = TRUE;
redirq = NULL;
diff --git a/exec.c b/exec.c
@@ -110,9 +110,20 @@ extern void exec(List *s, bool parent) {
redirq = NULL;
rc_wait4(pid, &stat, TRUE);
setstatus(-1, stat);
+ /*
+ There is a very good reason for having this weird
+ nl_on_intr variable: when rc and its child both
+ process a SIGINT, (i.e., the child has a SIGINT
+ catcher installed) then you don't want rc to print
+ a newline when the child finally exits. Here's an
+ example: ed, <type ^C>, <type "q">. rc does not
+ and should not print a newline before the next
+ prompt, even though there's a SIGINT in its signal
+ vector.
+ */
if ((stat & 0xff) == 0)
nl_on_intr = FALSE;
- SIGCHK;
+ sigchk();
nl_on_intr = TRUE;
pop_cmdarg(TRUE);
}
diff --git a/fn.c b/fn.c
@@ -12,9 +12,9 @@ static void fn_handler(int), dud_handler(int);
static bool runexit = FALSE;
static Node *handlers[NUMOFSIGNALS], null;
-static void (*def_sigint)(int) = SIG_DFL,
- (*def_sigquit)(int) = SIG_DFL,
- (*def_sigterm)(int) = SIG_DFL;
+static void (*def_sigint)(int) = SIG_DFL;
+static void (*def_sigquit)(int) = SIG_DFL;
+static void (*def_sigterm)(int) = SIG_DFL;
/*
Set signals to default values for rc. This means that interactive
@@ -106,13 +106,12 @@ extern void setsigdefaults(bool sysvbackground) {
/* rc's exit. if runexit is set, run the sigexit function. */
extern void rc_exit(int stat) {
- static char *sigexit[2] = {
- "sigexit",
- NULL
- };
if (runexit) {
+ char *sig[2];
+ sig[0] = "sigexit";
+ sig[1] = NULL;
runexit = FALSE;
- funcall(sigexit);
+ funcall(sig);
stat = getstatus();
}
exit(stat);
@@ -121,22 +120,14 @@ extern void rc_exit(int stat) {
/* The signal handler for all functions. calls walk() */
static void fn_handler(int s) {
- List *dollarzero;
- Estack e;
- Edata star;
+ char *sig[2];
int olderrno;
if (s < 1 || s >= NUMOFSIGNALS)
panic("unknown signal");
olderrno = errno;
- dollarzero = nnew(List);
- dollarzero->w = signals[s].name;
- dollarzero->n = NULL;
- varassign("*", dollarzero, TRUE);
- star.name = "*";
- except(eVarstack, star, &e);
- walk(handlers[s], TRUE);
- varrm("*", TRUE);
- unexcept(); /* eVarstack */
+ sig[0] = signals[s].name;
+ sig[1] = NULL;
+ funcall(sig);
errno = olderrno;
}
@@ -217,7 +208,7 @@ extern char *fnlookup_string(char *name) {
return NULL;
if (look->extdef != NULL)
return look->extdef;
- return look->extdef = fun2str(name, look->def);
+ return look->extdef = mprint("fn_%F={%T}", name, look->def);
}
/*
diff --git a/footobar.c b/footobar.c
@@ -5,15 +5,12 @@
#include "rc.h"
-#define FSCHAR '\1'
-#define FSSTRING "\1"
-
-static char *getenvw(char *, bool);
+/* protect an exported name from brain-dead shells */
#ifdef PROTECT_ENV
-static bool Fconv(Format *f, int ignore) { /* protect an exported name from brain-dead shells */
- int c;
+static bool Fconv(Format *f, int ignore) {
unsigned const char *s = va_arg(f->args, unsigned const char *);
+ int c;
while ((c = *s++) != '\0')
if (dnw[c] || c == '*' || (c == '_' && *s == '_'))
@@ -24,12 +21,6 @@ static bool Fconv(Format *f, int ignore) { /* protect an exported name from brai
}
#endif
-/* used to turn a function in Node * form into something we can export to the environment */
-
-extern char *fun2str(char *name, Node *n) {
- return mprint("fn_%F={%T}", name, n);
-}
-
/* convert a redirection to a printable form */
static bool Dconv(Format *f, int ignore) {
@@ -63,14 +54,11 @@ static bool Tconv(Format *f, int ignore) {
switch (n->type) {
case nWord: fmtprint(f, "%S", n->u[0].s); break;
case nQword: fmtprint(f, "%#S", n->u[0].s); break;
- case nBang: fmtprint(f, "! %T", n->u[0].p); break;
+ case nBang: fmtprint(f, "!%T", n->u[0].p); break;
case nCase: fmtprint(f, "case %T", n->u[0].p); break;
case nNowait: fmtprint(f, "%T&", n->u[0].p); break;
- case nCount: fmtprint(f, "$#%T", n->u[0].p); break;
- case nFlat: fmtprint(f, "$^%T", n->u[0].p); break;
case nRmfn: fmtprint(f, "fn %T", n->u[0].p); break;
case nSubshell: fmtprint(f, "@ %T", n->u[0].p); break;
- case nVar: fmtprint(f, "$%T", n->u[0].p); break;
case nAndalso: fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p); break;
case nAssign: fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p); break;
case nConcat: fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p); break;
@@ -81,10 +69,25 @@ static bool Tconv(Format *f, int ignore) {
case nArgs: fmtprint(f, "%T %T", n->u[0].p, n->u[1].p); break;
case nSwitch: fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p); break;
case nMatch: fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p); break;
- case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break;
case nWhile: fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p); break;
case nLappend: fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p); break;
case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break;
+ case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break;
+ case nCount: case nFlat: case nVar: {
+ char *lp = "", *rp = "";
+ Node *n0 = n->u[0].p;
+
+ if (n0->type != nWord && n0->type != nQword)
+ lp = "(", rp = ")";
+
+ switch (n->type) {
+ default: panic("this can't happen"); break;
+ case nCount: fmtprint(f, "$#%s%T%s", lp, n0, rp); break;
+ case nFlat: fmtprint(f, "$^%s%T%s", lp, n0, rp); break;
+ case nVar: fmtprint(f, "$%s%T%s", lp, n0, rp); break;
+ }
+ break;
+ }
case nDup:
if (n->u[2].i != -1)
fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i);
@@ -154,65 +157,41 @@ static bool Tconv(Format *f, int ignore) {
return FALSE;
}
-/* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */
-
-extern char *list2str(char *name, List *s) {
- SIZE_T size, step;
- List *t;
- char *w, *x;
- name = nprint("%F", name);
- size = strlen(name) + listlen(s);
- w = ealloc(size + 2);
- t = s;
- x = w;
- strcpy(x, name);
- strcpy(x += strlen(name), "=");
- strcpy(x += conststrlen("="), t->w);
- for (x += strlen(t->w), s = s->n; s != NULL; s = s->n) {
- memcpy(x, FSSTRING, step = conststrlen(FSSTRING));
- x += step;
- memcpy(x, s->w, step = strlen(s->w));
- x += step;
- }
- *x = '\0';
- return w;
-}
-
/* convert a List to an array, for execve() */
extern char **list2array(List *s, bool print) {
- char **av;
- int i;
+ char **argv, **av;
- /* 4 == 1 for the null terminator + 2 for the fake execve() + 1 for defaulting to sh */
- av = nalloc((listnel(s) + 4) * sizeof (char *));
- av += 3; /* hide the two free spots from rc (two for #! emulation, one for defaulting to sh) */
if (print)
fprint(2, "%L\n", s, " ");
- for (i = 0; s != NULL; i++) {
- av[i] = s->w;
+ /*
+ Allocate 3 extra spots (2 for the fake execve & 1 for defaulting to
+ sh) and hide these from exec().
+ */
+ argv = av = (char **) nalloc((listnel(s) + 4) * sizeof *av) + 3;
+ while (s != NULL) {
+ *av++ = s->w;
s = s->n;
}
- av[i] = NULL;
- return av;
+ *av = NULL;
+ return argv;
}
-/* figure out the name of a variable given an environment string. copy this into malloc space */
+/* figure out the name of a variable given an environment string. */
extern char *get_name(char *s) {
+ char *eq = strchr(s, '=');
+ char *r, *result;
int c;
- SIZE_T i;
- char *r, *namebuf;
- for (i = 0; s[i] != '\0' && s[i] != '='; i++)
- ;
- if (s[i] == '\0')
+
+ if (eq == NULL)
return NULL;
- r = namebuf = ealloc(i + 1);
+ r = result = nalloc(eq - s + 1);
while (1)
switch (c = *s++) {
case '=':
*r++ = '\0';
- return namebuf;
+ return result;
#ifdef PROTECT_ENV
case '_':
if (*s == '_') {
@@ -233,55 +212,45 @@ extern char *get_name(char *s) {
}
}
-/* get the next word from a variable's value as represented in the environment. */
-
-static char *getenvw(char *s, bool saw_alpha) {
- SIZE_T i;
- char *r;
- for (i = 0; s[i] != '\0' && s[i] != FSCHAR; i++)
- ;
- if (i == 0) {
- if (s[i] == '\0' && !saw_alpha)
- return NULL;
- else
- return clear(enew(char), (SIZE_T) 1);
- }
- r = strncpy(ealloc(i + 1), s, i);
- r[i] = '\0';
- return r;
-}
+/*
+ Hacky routine to split a ^A-separated environment variable. Scans
+ backwards. Be VERY CAREFUL with the loop boundary conditions. e.g.,
+ notice what happens when there is no ^A in the extdef. (It does
+ the right thing, of course :-)
+*/
-/* take an environment entry for a variable (elements ^A separated) and turn it into a List */
+#define skipleft(p) do --p; while (*p != '\0' && *p != '\001');
extern List *parse_var(char *name, char *extdef) {
- List *r, *top;
- char *f;
- bool saw_alpha;
- top = r = enew(List);
- extdef = strchr(extdef, '=') + 1;
- if ((f = getenvw(extdef, FALSE)) == NULL) {
- r->w = "";
- r->m = NULL;
- r->n = NULL;
- } else {
- while (1) {
- r->w = f;
- r->m = NULL;
- extdef += strlen(f);
- if (*extdef == FSCHAR) {
- extdef++;
- saw_alpha = TRUE;
- } else {
- saw_alpha = FALSE;
- }
- if ((f = getenvw(extdef, saw_alpha)) == NULL) {
- r->n = NULL;
- break;
- }
- r = r->n = enew(List);
- }
+ char *endp, *realend, *sepp;
+ List *tailp, *new;
+
+ extdef = strchr(extdef, '=');
+ *extdef++ = '\0'; /* null "initiate" the string for rtol scanning */
+
+ sepp = realend = strchr(extdef, '\0');
+ tailp = NULL;
+
+ while (1) {
+ endp = sepp; /* set endp to end of current mebmer */
+ skipleft(sepp); /* advance sepp to the previous \1, */
+ *endp = '\0'; /* and null terminate the member. */
+
+ new = enew(List);
+ new->w = ecpy(sepp+1);
+ new->m = NULL;
+ new->n = tailp;
+ tailp = new;
+
+ if (sepp < extdef) /* break when sepp hits the null "initiator" */
+ break;
+ if (endp != realend) /* else restore the \1 in between members */
+ *endp = '\001';
}
- return top;
+ if (endp != realend)
+ *endp = '\001';
+ *--extdef = '='; /* restore extdef '=' */
+ return tailp;
}
/* get an environment entry for a function and have rc parse it. */
diff --git a/glob.c b/glob.c
@@ -94,11 +94,39 @@ static List *dmatch(char *d, char *p, char *m) {
extern DIR *opendir(const char *);
extern struct dirent *readdir(DIR *);
/*extern int closedir(DIR *);*/
+ int i;
+
+ /*
+ return a match if there are no metacharacters; allows globbing through
+ directories with no read permission. make sure the file exists, though.
+ */
+ matched = TRUE;
+ if (m != NULL)
+ for (i = 0; p[i] != '\0'; i++)
+ if (m[i]) {
+ matched = FALSE;
+ break;
+ }
+
+ if (matched) {
+ char *path = nprint("%s/%s", d, p);
+ if (stat(path, &s) < 0)
+ return NULL;
+ r = nnew(List);
+ r->w = ncpy(p);
+ r->m = NULL;
+ r->n = NULL;
+ return r;
+ }
top = r = NULL;
+ if ((dirp = opendir(d)) == NULL)
+ return NULL;
/* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
- if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR || (dirp = opendir(d)) == NULL)
+ if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR) {
+ closedir(dirp);
return NULL;
+ }
while ((dp = readdir(dirp)) != NULL)
if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
matched = TRUE;
@@ -125,15 +153,17 @@ static List *dmatch(char *d, char *p, char *m) {
static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
List *q, *r, *top, foo;
- static List slash;
- static SIZE_T slashsize = 0;
- if (slashcount + 1 > slashsize) {
- slash.w = ealloc(slashcount + 1);
- slashsize = slashcount;
+ static struct {
+ List l;
+ SIZE_T size;
+ } slash;
+ if (slashcount+1 > slash.size) {
+ slash.size = 2*(slashcount+1);
+ slash.l.w = erealloc(slash.l.w, slash.size);
}
- slash.w[slashcount] = '\0';
+ slash.l.w[slashcount] = '\0';
while (slashcount > 0)
- slash.w[--slashcount] = '/';
+ slash.l.w[--slashcount] = '/';
for (top = r = NULL; s != NULL; s = s->n) {
q = dmatch(s->w, p, m);
if (q != NULL) {
@@ -141,7 +171,7 @@ static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
foo.m = NULL;
foo.n = NULL;
if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
- q = concat(&slash, q); /* dir/name with slash */
+ q = concat(&slash.l, q); /* dir/name with slash */
q = concat(&foo, q);
if (r == NULL)
top = r = q;
@@ -209,7 +239,7 @@ static List *doglob(char *w, char *m) {
}
do {
SIZE_T slashcount;
- SIGCHK;
+ sigchk();
for (slashcount = 0; *s == '/'; s++, m++)
slashcount++; /* skip slashes */
while (*s != '/' && *s != '\0')
diff --git a/glom.c b/glom.c
@@ -3,6 +3,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
+#include <errno.h>
#include "rc.h"
#if !defined(S_IFIFO) && !defined(DEVFD)
#define NOCMDARG
@@ -68,11 +69,11 @@ extern List *concat(List *s1, List *s2) {
} else {
r->m = nalloc(z);
if (s1->m == NULL)
- clear(r->m, x);
+ memzero(r->m, x);
else
memcpy(r->m, s1->m, x);
if (s2->m == NULL)
- clear(&r->m[x], y);
+ memzero(&r->m[x], y);
else
memcpy(&r->m[x], s2->m, y);
r->m[z] = 0;
@@ -183,7 +184,7 @@ static List *bqinput(List *ifs, int fd) {
char isifs[256];
int n, state; /* a simple FSA is used to read in data */
- clear(isifs, sizeof isifs);
+ memzero(isifs, sizeof isifs);
for (isifs['\0'] = TRUE; ifs != NULL; ifs = ifs->n)
for (s = ifs->w; *s != '\0'; s++)
isifs[*(unsigned char *)s] = TRUE;
@@ -209,8 +210,12 @@ static List *bqinput(List *ifs, int fd) {
if ((n = rc_read(fd, end, remain)) <= 0) {
if (n == 0)
/* break */ break;
- uerror("backquote read");
- rc_error(NULL);
+ else if (errno == EINTR)
+ return NULL; /* interrupted, wait for subproc */
+ else {
+ uerror("backquote read");
+ rc_error(NULL);
+ }
}
remain -= n;
for (bufend = &end[n]; end < bufend; end++)
@@ -218,6 +223,7 @@ static List *bqinput(List *ifs, int fd) {
if (!isifs[*(unsigned char *)end]) {
state = 1;
r->w = end;
+ r->m = NULL;
}
} else {
if (isifs[*(unsigned char *)end]) {
@@ -252,7 +258,6 @@ static List *backq(Node *ifs, Node *n) {
rc_error(NULL);
}
if ((pid = rc_fork()) == 0) {
- setsigdefaults(FALSE);
mvfd(p[1], 1);
close(p[0]);
redirq = NULL;
@@ -264,7 +269,8 @@ static List *backq(Node *ifs, Node *n) {
close(p[0]);
rc_wait4(pid, &sp, TRUE);
statprint(-1, sp);
- SIGCHK;
+ varassign("bqstatus", word(strstatus(sp), NULL), FALSE);
+ sigchk();
return bq;
}
diff --git a/hash.c b/hash.c
@@ -279,15 +279,17 @@ extern char **makeenv() {
return env;
}
-extern void whatare_all_vars() {
+extern void whatare_all_vars(bool showfn, bool showvar) {
int i;
List *s;
- for (i = 0; i < vsize; i++)
- if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
- prettyprint_var(1, vp[i].name, s);
- for (i = 0; i < fsize; i++)
- if (fp[i].name != NULL && fp[i].name != dead)
- prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
+ if (showvar)
+ for (i = 0; i < vsize; i++)
+ if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
+ prettyprint_var(1, vp[i].name, s);
+ if (showfn)
+ for (i = 0; i < fsize; i++)
+ if (fp[i].name != NULL && fp[i].name != dead)
+ prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
}
/* fake getenv() for readline() follows: */
diff --git a/history/history.c b/history/history.c
@@ -246,7 +246,7 @@ again: s = last;
/*
* if the command contains the "me" character at the start of the line
- * or after any of [`{|()] then try again
+ * or after any of [`{|()@] then try again
*/
for (t = s; *t != '\0'; t++)
@@ -254,8 +254,16 @@ again: s = last;
char *u = t - 1;
while (u >= s && (*u == ' ' || *u == '\t'))
--u;
- if (u < s || *u == '`' || *u == '{' || *u == '|' || *u == '(' || *u == ')')
+ if (u < s)
goto again;
+ switch (*u) {
+ case '`': case '@':
+ case '(': case ')':
+ case '{': case '|':
+ goto again;
+ default:
+ break;
+ }
}
return s;
}
diff --git a/input.c b/input.c
@@ -40,8 +40,6 @@ static char *inbuf;
static SIZE_T istacksize, chars_out, chars_in;
static bool eofread = FALSE, save_lineno = TRUE;
static Input *istack, *itop;
-static char *histstr;
-static int histfd;
static int (*realgchar)(void);
static void (*realugchar)(int);
@@ -49,11 +47,17 @@ static void (*realugchar)(int);
int last;
extern int gchar() {
+ int c;
+
if (eofread) {
eofread = FALSE;
return last = EOF;
}
- return (*realgchar)();
+
+ while ((c = (*realgchar)()) == '\0')
+ pr_error("warning: null character ignored");
+
+ return c;
}
extern void ugchar(int c) {
@@ -99,7 +103,7 @@ static char *rc_readline(char *prompt) {
slow = FALSE;
if (r == NULL)
errno = EINTR;
- SIGCHK;
+ sigchk();
return r;
}
#else
@@ -128,14 +132,14 @@ static int fdgchar() {
inbuf = ealloc(chars_in + 3);
strcpy(inbuf+2, rlinebuf);
strcat(inbuf+2, "\n");
+ efree(rlinebuf);
}
} else
#endif
{
long /*ssize_t*/ r = rc_read(istack->fd, inbuf + 2, BUFSIZE);
+ sigchk();
if (r < 0) {
- if (errno == EINTR)
- continue; /* Suppose it was interrupted by a signal */
uerror("read");
rc_exit(1);
}
@@ -214,7 +218,7 @@ extern void popinput() {
efree(inbuf);
--istack;
realgchar = (istack->t == iString ? stringgchar : fdgchar);
- if (istack->fd == -1) { /* top of input stack */
+ if (istack->t == iFd && istack->fd == -1) { /* top of input stack */
realgchar = dead;
realugchar = ugdead;
}
@@ -258,7 +262,7 @@ extern Node *doit(bool execit) {
Edata block;
block.b = newblock();
except(eArena, block, &e2);
- SIGCHK;
+ sigchk();
if (dashell) {
char *fname[3];
fname[1] = concat(varlookup("home"), word("/.rcrc", NULL))->w;
@@ -314,57 +318,42 @@ extern Node *parseline(char *extdef) {
return fun;
}
-/* write last command out to a file. Check to see if $history has changed, also */
+/* write last command out to a file if interactive && $history is set */
static void history() {
- List *histlist;
+ List *hist;
SIZE_T a;
- if (!interactive)
- return;
- if ((histlist = varlookup("history")) == NULL) {
- if (histstr != NULL) {
- efree(histstr);
- close(histfd);
- histstr = NULL;
- }
+
+ if (!interactive || (hist = varlookup("history")) == NULL)
return;
- }
- if (histstr == NULL || !streq(histstr, histlist->w)) { /* open new file */
- if (histstr != NULL) {
- efree(histstr);
- close(histfd);
- }
- histstr = ecpy(histlist->w);
- histfd = rc_open(histstr, rAppend);
- if (histfd < 0) {
- uerror(histstr);
- efree(histstr);
- histstr = NULL;
- varrm("history", FALSE);
- }
- }
- /*
- Small unix hack: since read() reads only up to a newline
- from a terminal, then presumably this write() will write at
- most only one input line at a time.
- */
- for (a = 2; a < chars_in + 2; a++) { /* skip empty lines and comments in history. */
- if (inbuf[a] == '#' || inbuf[a] == '\n')
- return;
- if (inbuf[a] != ' ' && inbuf[a] != '\t')
+
+ for (a = 0; a < chars_in; a++) {
+ char c = inbuf[a+2];
+
+ /* skip empty lines and comments */
+ if (c == '#' || c == '\n')
break;
+
+ /* line matches [ \t]*[^#\n] so it's ok to write out */
+ if (c != ' ' && c != '\t') {
+ char *name = hist->w;
+ int fd = rc_open(name, rAppend);
+ if (fd < 0) {
+ uerror(name);
+ varrm(name, TRUE);
+ } else {
+ writeall(fd, inbuf + 2, chars_in);
+ close(fd);
+ }
+ break;
+ }
}
- writeall(histfd, inbuf + 2, chars_in);
}
/* close file descriptors after a fork() */
extern void closefds() {
Input *i;
- if (histstr != NULL) { /* Close an open history file */
- close(histfd);
- histstr = NULL; /* But prevent re-closing of the same file-descriptor */
- }
for (i = istack; i != itop; --i) /* close open scripts */
if (i->t == iFd && i->fd > 2) {
close(i->fd);
diff --git a/lex.c b/lex.c
@@ -10,7 +10,7 @@
The lexical analyzer is fairly straightforward. The only really
unclean part concerns backslash continuation and "double
backslashes". A backslash followed by a newline is treated as a
- space, otherwise backslash is not a special characeter (i.e.,
+ space, otherwise backslash is not a special character (i.e.,
it can be part of a word). This introduces a host of unwanted
special cases. In our case, \ cannot be a word character, since
we wish to read in all word characters in a tight loop.
@@ -155,9 +155,6 @@ top: while ((c = gchar()) == ' ' || c == '\t')
w = KW;
}
switch (c) {
- case '\0':
- pr_error("warning: null character ignored");
- goto top;
case '!':
return BANG;
case '@':
diff --git a/main.c b/main.c
@@ -3,7 +3,7 @@
#include "rc.h"
bool dashdee, dashee, dashvee, dashex, dashell, dasheye,
- dashen, dashpee, interactive;
+ dashen, dashpee, dashess, interactive;
int rc_pid;
static bool dashoh;
@@ -19,7 +19,7 @@ extern void main(int argc, char *argv[], char *envp[]) {
dollarzero = argv[0];
rc_pid = getpid();
dashell = (*argv[0] == '-'); /* Unix tradition */
- while ((c = rc_getopt(argc, argv, "nolpeivdxc:")) != -1)
+ while ((c = rc_getopt(argc, argv, "nolpeivdxsc:")) != -1)
switch (c) {
case 'l':
dashell = TRUE;
@@ -39,6 +39,9 @@ extern void main(int argc, char *argv[], char *envp[]) {
case 'd':
dashdee = TRUE;
break;
+ case 's':
+ dashess = dasheye = interactive = TRUE;
+ break;
case 'c':
dashsee[0] = rc_optarg;
goto quitopts;
@@ -56,8 +59,8 @@ extern void main(int argc, char *argv[], char *envp[]) {
}
quitopts:
argv += rc_optind;
- /* use isatty() iff -i is not set, and iff the input is not from a script or -c flag */
- if (!dasheye && dashsee[0] == NULL && *argv == NULL)
+ /* use isatty() iff -i is not set, and iff the input is not from a script or -c or -s flags */
+ if (!dasheye && !dashess && dashsee[0] == NULL && *argv == NULL)
interactive = isatty(0);
if (!dashoh) {
checkfd(0, rFrom);
@@ -78,10 +81,13 @@ quitopts:
null[0] = NULL;
starassign(dollarzero, null, FALSE); /* assign $0 to $* */
inithandler();
- if (dashsee[0] != NULL) { /* input from the -c flag? */
+ if (dashsee[0] != NULL || dashess) { /* input from -c or -s? */
if (*argv != NULL)
starassign(dollarzero, argv, FALSE);
- pushstring(dashsee, TRUE);
+ if (dashess)
+ pushfd(0);
+ else
+ pushstring(dashsee, TRUE);
} else if (*argv != NULL) { /* else from a file? */
b_dot(--argv);
rc_exit(getstatus());
diff --git a/nalloc.c b/nalloc.c
@@ -122,6 +122,8 @@ extern void *ealloc(SIZE_T n) {
extern void *erealloc(void *p, SIZE_T n) {
extern void *realloc(void *, SIZE_T);
+ if (p == NULL) /* convenience feature */
+ return ealloc(n);
if ((p = realloc(p, n)) == NULL) {
uerror("realloc");
rc_exit(1);
diff --git a/print.c b/print.c
@@ -270,9 +270,11 @@ extern int printfmt(Format *format, const char *fmt) {
extern int fmtprint(Format *format, const char *fmt,...) {
int n = -format->flushed;
- va_list saveargs = format->args;
+ va_list ap, saveargs;
- va_start(format->args, fmt);
+ va_start(ap, fmt);
+ saveargs = format->args;
+ format->args = ap;
n += printfmt(format, fmt);
va_end(format->args);
format->args = saveargs;
@@ -292,6 +294,7 @@ static void fprint_flush(Format *format, SIZE_T more) {
extern int fprint(int fd, const char *fmt,...) {
char buf[1024];
Format format;
+ va_list ap;
format.buf = buf;
format.bufbegin = buf;
@@ -300,7 +303,8 @@ extern int fprint(int fd, const char *fmt,...) {
format.flushed = 0;
format.u.n = fd;
- va_start(format.args, fmt);
+ va_start(ap, fmt);
+ format.args = ap;
printfmt(&format, fmt);
va_end(format.args);
@@ -340,8 +344,11 @@ static char *memprint(Format *format, const char *fmt, char *buf, SIZE_T len) {
extern char *mprint(const char *fmt,...) {
Format format;
char *result;
+ va_list ap;
+
format.u.n = 1;
- va_start(format.args, fmt);
+ va_start(ap, fmt);
+ format.args = ap;
result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
va_end(format.args);
return result;
@@ -350,8 +357,11 @@ extern char *mprint(const char *fmt,...) {
extern char *nprint(const char *fmt,...) {
Format format;
char *result;
+ va_list ap;
+
format.u.n = 0;
- va_start(format.args, fmt);
+ va_start(ap, fmt);
+ format.args = ap;
result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
va_end(format.args);
return result;
diff --git a/proto.h b/proto.h
@@ -47,6 +47,7 @@ extern char *strncpy(char *, const char *, SIZE_T);
extern char *strcat(char *, const char *);
extern char *strncat(char *, const char *, SIZE_T);
extern void *memcpy(void *, const void *, SIZE_T);
+extern void *memset(void *, int, SIZE_T);
/* fake unistd.h */
diff --git a/rc.1 b/rc.1
@@ -490,6 +490,7 @@ This allows the unambiguous use of variables adjacent to text, as in
.Ds
.Cr $variable^follow
.De
+.PP
To include a literal
.Cr $
in a here document when an unquoted end-of-file marker is being used,
@@ -683,8 +684,8 @@ the first command exits with a zero exit status (``true'' in Unix).
.Cr "command || command"
.De
.PP
-executes the first command executing the second command if and only if
-the second command exits with a nonzero exit status (``false'' in Unix).
+executes the first command and then executes the second command if and only if
+the first command exits with a nonzero exit status (``false'' in Unix).
.Ds
.Cr "! command"
.De
@@ -1625,7 +1626,7 @@ If no
.I pid
is specified,
.I rc
-waits for any child process to exit.
+waits for all child processes to exit.
.TP
\fBwhatis \fR[\fB\-s\fR] [\fB\-\|\-\fR] [\fIname ...\fR]
Prints a definition of the named objects.
diff --git a/rc.h b/rc.h
@@ -150,6 +150,7 @@ enum {
#define a2u(x) n2u(x, 10)
#define o2u(x) n2u(x, 8)
#define arraysize(a) ((int)(sizeof(a)/sizeof(*a)))
+#define memzero(s, n) memset(s, 0, n)
#define enew(x) ((x *) ealloc(sizeof(x)))
#define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1), x)
#define lookup_fn(s) ((Function *) lookup(s, fp))
@@ -192,8 +193,6 @@ extern void exec(List *, bool);
extern void doredirs(void);
/* footobar.c */
-extern char *fun2str(char *, Node *);
-extern char *list2str(char *, List *);
extern char **list2array(List *, bool);
extern char *get_name(char *);
extern List *parse_var(char *, char *);
@@ -245,7 +244,7 @@ extern void setsigdefaults(bool);
extern void inithandler(void);
extern void varassign(char *, List *, bool);
extern void varrm(char *, bool);
-extern void whatare_all_vars(void);
+extern void whatare_all_vars(bool, bool);
extern void whatare_all_signals(void);
extern void prettyprint_var(int, char *, List *);
extern void prettyprint_fn(int, char *, Node *);
@@ -338,7 +337,6 @@ extern void sigchk(void);
extern void (*rc_signal(int, void (*)(int)))(int);
extern void (*sighandlers[])(int);
extern volatile SIG_ATOMIC_T slow, interrupt_happened;
-#define SIGCHK sigchk()
/* status.c */
extern int istrue(void);
@@ -349,6 +347,7 @@ extern List *sgetstatus(void);
extern void setpipestatus(int [], int);
extern void statprint(int, int);
extern void ssetstatus(char **);
+extern char *strstatus(int s);
/* tree.c */
extern Node *mk(int /*nodetype*/,...);
@@ -362,7 +361,6 @@ extern int rc_read(int, char *, SIZE_T);
extern int mvfd(int, int);
extern int starstrcmp(const void *, const void *);
extern void pr_error(char *);
-extern char *clear(char *, SIZE_T);
extern void panic(char *);
extern void uerror(char *);
extern void writeall(int, char *, SIZE_T);
diff --git a/signal.c b/signal.c
@@ -13,8 +13,6 @@ void (*sighandlers[NUMOFSIGNALS])(int);
static volatile SIG_ATOMIC_T sigcount, caught[NUMOFSIGNALS];
extern void catcher(int s) {
- if (forked)
- exit(1); /* exit unconditionally on a signal in a child process */
if (caught[s] == 0) {
sigcount++;
caught[s] = 1;
@@ -52,7 +50,7 @@ extern void sigchk() {
extern void (*rc_signal(int s, void (*h)(int)))(int) {
void (*old)(int);
- SIGCHK;
+ sigchk();
old = sighandlers[s];
if (h == SIG_DFL || h == SIG_IGN) {
signal(s, h);
diff --git a/status.c b/status.c
@@ -80,27 +80,35 @@ extern void statprint(int pid, int i) {
/* prepare a list to be passed back. Used whenever $status is dereferenced */
extern List *sgetstatus() {
- List *r;
+ List *r = NULL;
int i;
- for (r = NULL, i = 0; i < pipelength; i++) {
+
+ for (i = 0; i < pipelength; i++) {
List *q = nnew(List);
- int s = statuses[i];
- int t;
+ q->w = strstatus(statuses[i]);
+ q->m = NULL;
q->n = r;
r = q;
- if ((t = s & 0x7f) != 0) {
- const char *core = (s & 0x80) ? "+core" : "";
- if (t < NUMOFSIGNALS && *signals[t].name != '\0')
- r->w = nprint("%s%s", signals[t].name, core);
- else
- r->w = nprint("-%d%s", t, core); /* unknown signals are negated */
- } else
- r->w = nprint("%d", (s >> 8) & 0xff);
- r->m = NULL;
}
+
return r;
}
+/* return status as a string (used above and for bqstatus) */
+
+extern char *strstatus(int s) {
+ int t = s & 0x7f;
+
+ if (t != 0) {
+ const char *core = (s & 0x80) ? "+core" : "";
+ if (t < NUMOFSIGNALS && *signals[t].name != '\0')
+ return nprint("%s%s", signals[t].name, core);
+ else
+ return nprint("-%d%s", t, core); /* unknown signals are negated */
+ } else
+ return nprint("%d", (s >> 8) & 0xff);
+}
+
extern void ssetstatus(char **av) {
int i, j, k, l;
bool found;
diff --git a/trip.rc b/trip.rc
Binary files differ.
diff --git a/utils.c b/utils.c
@@ -82,7 +82,7 @@ extern void writeall(int fd, char *buf, SIZE_T remain) {
slow = FALSE;
}
slow = FALSE;
- SIGCHK;
+ sigchk();
}
extern int rc_read(int fd, char *buf, SIZE_T n) {
@@ -101,18 +101,9 @@ extern int rc_read(int fd, char *buf, SIZE_T n) {
errno = EINTR;
r = -1;
}
- SIGCHK;
return r;
}
-/* clear out z bytes from character string s */
-
-extern char *clear(char *s, SIZE_T z) {
- while (z != 0)
- s[--z] = 0;
- return s;
-}
-
/* duplicate a fd and close the old one only if necessary */
extern int mvfd(int i, int j) {
diff --git a/var.c b/var.c
@@ -104,7 +104,7 @@ extern char *varlookup_string(char *name) {
return look->extdef;
if (look->def == NULL)
return NULL;
- return look->extdef = list2str(name, look->def);
+ return look->extdef = mprint("%F=%-L", name, look->def, "\001");
}
/* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
@@ -166,16 +166,15 @@ static void listassign(char *name, List *def, bool stack) {
return;
}
v = def->w;
- r = val = enew(List);
+ r = val = nnew(List);
while ((w = strchr(v, ':')) != NULL) {
*w = '\0';
- r->w = ecpy(v);
+ r->w = ncpy(v);
*w = ':';
v = w + 1;
- r->n = enew(List);
- r = r->n;
+ r = r->n = nnew(List);
}
- r->w = ecpy(v);
+ r->w = ncpy(v);
r->n = NULL;
varassign(name, val, stack);
}
diff --git a/version.c b/version.c
@@ -1 +1 @@
-const char id[] = "@(#)rc version 1.4, 5/26/92.";
+const char id[] = "@(#)rc version 1.5betadev-1, 1/9/94.";
diff --git a/wait.c b/wait.c
@@ -16,7 +16,7 @@ static struct Pid {
} *plist = NULL;
extern int rc_fork() {
- Pid *new = enew(Pid);
+ Pid *new;
int pid = fork();
switch (pid) {
case -1:
@@ -25,9 +25,10 @@ extern int rc_fork() {
/* NOTREACHED */
case 0:
forked = TRUE;
- SIGCHK;
+ sigchk();
return 0;
default:
+ new = enew(Pid);
new->pid = pid;
new->alive = TRUE;
new->n = plist;
@@ -98,7 +99,7 @@ extern void waitforall() {
setstatus(pid, stat);
else
set(FALSE);
- SIGCHK;
+ sigchk();
}
}
diff --git a/walk.c b/walk.c
@@ -11,6 +11,7 @@
*/
bool cond = FALSE;
+static bool haspreredir(Node *);
static bool isallpre(Node *);
static bool dofork(bool);
static void dopipe(Node *);
@@ -22,7 +23,7 @@ static void dopipe(Node *);
/* walk the parse-tree. "obvious". */
extern bool walk(Node *n, bool parent) {
-top: SIGCHK;
+top: sigchk();
if (n == NULL) {
if (!parent)
exit(0);
@@ -147,7 +148,6 @@ top: SIGCHK;
}
case nSubshell:
if (dofork(TRUE)) {
- setsigdefaults(FALSE);
walk(n->u[0].p, FALSE);
rc_exit(getstatus());
}
@@ -214,8 +214,14 @@ top: SIGCHK;
case nPre: {
List *v;
if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) {
+ if (redirq == NULL && !dofork(parent)) /* subshell on first preredir */
+ break;
qredir(n->u[0].p);
- walk(n->u[1].p, parent);
+ if (!haspreredir(n->u[1].p))
+ doredirs(); /* no more preredirs, empty queue */
+ walk(n->u[1].p, FALSE);
+ rc_exit(getstatus());
+ /* NOTREACHED */
} else if (n->u[0].p->type == nAssign) {
if (isallpre(n->u[1].p)) {
walk(n->u[0].p, TRUE);
@@ -239,7 +245,6 @@ top: SIGCHK;
if (n->u[1].p == NULL) {
WALK(n->u[0].p, parent);
} else if (dofork(parent)) {
- setsigdefaults(FALSE);
walk(n->u[1].p, TRUE); /* Do redirections */
redirq = NULL; /* Reset redirection queue */
walk(n->u[0].p, FALSE); /* Do commands */
@@ -265,6 +270,17 @@ top: SIGCHK;
return istrue();
}
+/* checks to see whether there are any pre-redirections left in the tree */
+
+static bool haspreredir(Node *n) {
+ while (n != NULL && n->type == nPre) {
+ if (n->u[0].p->type == nDup || n->u[0].p->type == nRedir)
+ return TRUE;
+ n = n->u[1].p;
+ }
+ return FALSE;
+}
+
/* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */
static bool isallpre(Node *n) {
@@ -286,7 +302,7 @@ static bool dofork(bool parent) {
redirq = NULL; /* clear out the pre-redirection queue in the parent */
rc_wait4(pid, &sp, TRUE);
setstatus(-1, sp);
- SIGCHK;
+ sigchk();
return FALSE;
}
@@ -304,7 +320,6 @@ static void dopipe(Node *n) {
rc_error(NULL);
}
if ((pid = rc_fork()) == 0) {
- setsigdefaults(FALSE);
redirq = NULL; /* clear preredir queue */
mvfd(p[0], r->u[1].i);
if (fd_prev != 1)
@@ -321,7 +336,6 @@ static void dopipe(Node *n) {
close(p[0]);
}
if ((pid = rc_fork()) == 0) {
- setsigdefaults(FALSE);
mvfd(fd_prev, fd_out);
walk(r, FALSE);
exit(getstatus());
@@ -340,5 +354,5 @@ static void dopipe(Node *n) {
intr |= (sp == SIGINT);
}
setpipestatus(stats, i);
- SIGCHK;
+ sigchk();
}