aboutsummaryrefslogtreecommitdiff
path: root/release/picobsd/tinyware/msh/sh3.c
diff options
context:
space:
mode:
Diffstat (limited to 'release/picobsd/tinyware/msh/sh3.c')
-rw-r--r--release/picobsd/tinyware/msh/sh3.c1143
1 files changed, 1143 insertions, 0 deletions
diff --git a/release/picobsd/tinyware/msh/sh3.c b/release/picobsd/tinyware/msh/sh3.c
new file mode 100644
index 000000000000..5959f2735424
--- /dev/null
+++ b/release/picobsd/tinyware/msh/sh3.c
@@ -0,0 +1,1143 @@
+#define Extern extern
+#include <sys/types.h>
+#include <signal.h>
+#define _NSIG NSIG
+#include <errno.h>
+#include <setjmp.h>
+#include <stddef.h>
+#include <time.h>
+#include <sys/times.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#undef NULL
+#include "sh.h"
+
+/* -------- exec.c -------- */
+/* #include "sh.h" */
+
+/*
+ * execute tree
+ */
+
+static char *signame[] = {
+ "Signal 0",
+ "Hangup",
+ (char *)NULL, /* interrupt */
+ "Quit",
+ "Illegal instruction",
+ "Trace/BPT trap",
+ "Abort",
+ "EMT trap",
+ "Floating exception",
+ "Killed",
+ "Bus error",
+ "Memory fault",
+ "Bad system call",
+ (char *)NULL, /* broken pipe */
+ "Alarm clock",
+ "Terminated",
+};
+#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
+
+
+_PROTOTYPE(static int forkexec, (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked ));
+_PROTOTYPE(static int parent, (void));
+_PROTOTYPE(int iosetup, (struct ioword *iop, int pipein, int pipeout ));
+_PROTOTYPE(static void echo, (char **wp ));
+_PROTOTYPE(static struct op **find1case, (struct op *t, char *w ));
+_PROTOTYPE(static struct op *findcase, (struct op *t, char *w ));
+_PROTOTYPE(static void brkset, (struct brkcon *bc ));
+_PROTOTYPE(int dolabel, (void));
+_PROTOTYPE(int dochdir, (struct op *t ));
+_PROTOTYPE(int doshift, (struct op *t ));
+_PROTOTYPE(int dologin, (struct op *t ));
+_PROTOTYPE(int doumask, (struct op *t ));
+_PROTOTYPE(int doexec, (struct op *t ));
+_PROTOTYPE(int dodot, (struct op *t ));
+_PROTOTYPE(int dowait, (struct op *t ));
+_PROTOTYPE(int doread, (struct op *t ));
+_PROTOTYPE(int doeval, (struct op *t ));
+_PROTOTYPE(int dotrap, (struct op *t ));
+_PROTOTYPE(int getsig, (char *s ));
+_PROTOTYPE(void setsig, (int n, void (*f)()));
+_PROTOTYPE(int getn, (char *as ));
+_PROTOTYPE(int dobreak, (struct op *t ));
+_PROTOTYPE(int docontinue, (struct op *t ));
+_PROTOTYPE(static int brkcontin, (char *cp, int val ));
+_PROTOTYPE(int doexit, (struct op *t ));
+_PROTOTYPE(int doexport, (struct op *t ));
+_PROTOTYPE(int doreadonly, (struct op *t ));
+_PROTOTYPE(static void rdexp, (char **wp, void (*f)(), int key));
+_PROTOTYPE(static void badid, (char *s ));
+_PROTOTYPE(int doset, (struct op *t ));
+_PROTOTYPE(void varput, (char *s, int out ));
+_PROTOTYPE(int dotimes, (void));
+
+int
+execute(t, pin, pout, act)
+register struct op *t;
+int *pin, *pout;
+int act;
+{
+ register struct op *t1;
+ int i, pv[2], rv, child, a;
+ char *cp, **wp, **wp2;
+ struct var *vp;
+ struct brkcon bc;
+
+ if (t == NULL)
+ return(0);
+ rv = 0;
+ a = areanum++;
+ wp = (wp2 = t->words) != NULL
+ ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
+ : NULL;
+
+ switch(t->type) {
+ case TPAREN:
+ case TCOM:
+ rv = forkexec(t, pin, pout, act, wp, &child);
+ if (child) {
+ exstat = rv;
+ leave();
+ }
+ break;
+
+ case TPIPE:
+ if ((rv = openpipe(pv)) < 0)
+ break;
+ pv[0] = remap(pv[0]);
+ pv[1] = remap(pv[1]);
+ (void) execute(t->left, pin, pv, 0);
+ rv = execute(t->right, pv, pout, 0);
+ break;
+
+ case TLIST:
+ (void) execute(t->left, pin, pout, 0);
+ rv = execute(t->right, pin, pout, 0);
+ break;
+
+ case TASYNC:
+ i = parent();
+ if (i != 0) {
+ if (i != -1) {
+ setval(lookup("!"), putn(i));
+ if (pin != NULL)
+ closepipe(pin);
+ if (talking) {
+ prs(putn(i));
+ prs("\n");
+ }
+ } else
+ rv = -1;
+ setstatus(rv);
+ } else {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ if (talking)
+ signal(SIGTERM, SIG_DFL);
+ talking = 0;
+ if (pin == NULL) {
+ close(0);
+ open("/dev/null", 0);
+ }
+ exit(execute(t->left, pin, pout, FEXEC));
+ }
+ break;
+
+ case TOR:
+ case TAND:
+ rv = execute(t->left, pin, pout, 0);
+ if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND))
+ rv = execute(t1, pin, pout, 0);
+ break;
+
+ case TFOR:
+ if (wp == NULL) {
+ wp = dolv+1;
+ if ((i = dolc) < 0)
+ i = 0;
+ } else {
+ i = -1;
+ while (*wp++ != NULL)
+ ;
+ }
+ vp = lookup(t->str);
+ while (setjmp(bc.brkpt))
+ if (isbreak)
+ goto broken;
+ brkset(&bc);
+ for (t1 = t->left; i-- && *wp != NULL;) {
+ setval(vp, *wp++);
+ rv = execute(t1, pin, pout, 0);
+ }
+ brklist = brklist->nextlev;
+ break;
+
+ case TWHILE:
+ case TUNTIL:
+ while (setjmp(bc.brkpt))
+ if (isbreak)
+ goto broken;
+ brkset(&bc);
+ t1 = t->left;
+ while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
+ rv = execute(t->right, pin, pout, 0);
+ brklist = brklist->nextlev;
+ break;
+
+ case TIF:
+ case TELIF:
+ if (t->right != NULL) {
+ rv = !execute(t->left, pin, pout, 0) ?
+ execute(t->right->left, pin, pout, 0):
+ execute(t->right->right, pin, pout, 0);
+ }
+ break;
+
+ case TCASE:
+ if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0)
+ cp = "";
+ if ((t1 = findcase(t->left, cp)) != NULL)
+ rv = execute(t1, pin, pout, 0);
+ break;
+
+ case TBRACE:
+/*
+ if (iopp = t->ioact)
+ while (*iopp)
+ if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
+ rv = -1;
+ break;
+ }
+*/
+ if (rv >= 0 && (t1 = t->left))
+ rv = execute(t1, pin, pout, 0);
+ break;
+ }
+
+broken:
+ t->words = wp2;
+ isbreak = 0;
+ freehere(areanum);
+ freearea(areanum);
+ areanum = a;
+ if (talking && intr) {
+ closeall();
+ fail();
+ }
+ if ((i = trapset) != 0) {
+ trapset = 0;
+ runtrap(i);
+ }
+ return(rv);
+}
+
+static int
+forkexec(t, pin, pout, act, wp, pforked)
+register struct op *t;
+int *pin, *pout;
+int act;
+char **wp;
+int *pforked;
+{
+ int i, rv, (*shcom)();
+ register int f;
+ char *cp;
+ struct ioword **iopp;
+ int resetsig;
+ char **owp;
+
+ owp = wp;
+ resetsig = 0;
+ *pforked = 0;
+ shcom = NULL;
+ rv = -1; /* system-detected error */
+ if (t->type == TCOM) {
+ while ((cp = *wp++) != NULL)
+ ;
+ cp = *wp;
+
+ /* strip all initial assignments */
+ /* not correct wrt PATH=yyy command etc */
+ if (flag['x'])
+ echo (cp ? wp: owp);
+ if (cp == NULL && t->ioact == NULL) {
+ while ((cp = *owp++) != NULL && assign(cp, COPYV))
+ ;
+ return(setstatus(0));
+ }
+ else if (cp != NULL)
+ shcom = inbuilt(cp);
+ }
+ t->words = wp;
+ f = act;
+ if (shcom == NULL && (f & FEXEC) == 0) {
+ i = parent();
+ if (i != 0) {
+ if (i == -1)
+ return(rv);
+ if (pin != NULL)
+ closepipe(pin);
+ return(pout==NULL? setstatus(waitfor(i,0)): 0);
+ }
+ if (talking) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ resetsig = 1;
+ }
+ talking = 0;
+ intr = 0;
+ (*pforked)++;
+ brklist = 0;
+ execflg = 0;
+ }
+ if (owp != NULL)
+ while ((cp = *owp++) != NULL && assign(cp, COPYV))
+ if (shcom == NULL)
+ export(lookup(cp));
+#ifdef COMPIPE
+ if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
+ err("piping to/from shell builtins not yet done");
+ return(-1);
+ }
+#endif
+ if (pin != NULL) {
+ dup2(pin[0], 0);
+ closepipe(pin);
+ }
+ if (pout != NULL) {
+ dup2(pout[1], 1);
+ closepipe(pout);
+ }
+ if ((iopp = t->ioact) != NULL) {
+ if (shcom != NULL && shcom != doexec) {
+ prs(cp);
+ err(": cannot redirect shell command");
+ return(-1);
+ }
+ while (*iopp)
+ if (iosetup(*iopp++, pin!=NULL, pout!=NULL))
+ return(rv);
+ }
+ if (shcom)
+ return(setstatus((*shcom)(t)));
+ /* should use FIOCEXCL */
+ for (i=FDBASE; i<NOFILE; i++)
+ close(i);
+ if (resetsig) {
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ }
+ if (t->type == TPAREN)
+ exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
+ if (wp[0] == NULL)
+ exit(0);
+ cp = rexecve(wp[0], wp, makenv());
+ prs(wp[0]); prs(": "); warn(cp);
+ if (!execflg)
+ trap[0] = NULL;
+ leave();
+ /* NOTREACHED */
+}
+
+/*
+ * common actions when creating a new child
+ */
+static int
+parent()
+{
+ register int i;
+
+ i = fork();
+ if (i != 0) {
+ if (i == -1)
+ warn("try again");
+ }
+ return(i);
+}
+
+/*
+ * 0< 1> are ignored as required
+ * within pipelines.
+ */
+int
+iosetup(iop, pipein, pipeout)
+register struct ioword *iop;
+int pipein, pipeout;
+{
+ register u;
+ char *cp, *msg;
+
+ if (iop->io_unit == IODEFAULT) /* take default */
+ iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1;
+ if (pipein && iop->io_unit == 0)
+ return(0);
+ if (pipeout && iop->io_unit == 1)
+ return(0);
+ msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create";
+ if ((iop->io_flag & IOHERE) == 0) {
+ cp = iop->io_name;
+ if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL)
+ return(1);
+ }
+ if (iop->io_flag & IODUP) {
+ if (cp[1] || (!digit(*cp) && *cp != '-')) {
+ prs(cp);
+ err(": illegal >& argument");
+ return(1);
+ }
+ if (*cp == '-')
+ iop->io_flag = IOCLOSE;
+ iop->io_flag &= ~(IOREAD|IOWRITE);
+ }
+ switch (iop->io_flag) {
+ case IOREAD:
+ u = open(cp, 0);
+ break;
+
+ case IOHERE:
+ case IOHERE|IOXHERE:
+ u = herein(iop->io_name, iop->io_flag&IOXHERE);
+ cp = "here file";
+ break;
+
+ case IOWRITE|IOCAT:
+ if ((u = open(cp, 1)) >= 0) {
+ lseek(u, (long)0, 2);
+ break;
+ }
+ case IOWRITE:
+ u = creat(cp, 0666);
+ break;
+
+ case IODUP:
+ u = dup2(*cp-'0', iop->io_unit);
+ break;
+
+ case IOCLOSE:
+ close(iop->io_unit);
+ return(0);
+ }
+ if (u < 0) {
+ prs(cp);
+ prs(": cannot ");
+ warn(msg);
+ return(1);
+ } else {
+ if (u != iop->io_unit) {
+ dup2(u, iop->io_unit);
+ close(u);
+ }
+ }
+ return(0);
+}
+
+static void
+echo(wp)
+register char **wp;
+{
+ register i;
+
+ prs("+");
+ for (i=0; wp[i]; i++) {
+ if (i)
+ prs(" ");
+ prs(wp[i]);
+ }
+ prs("\n");
+}
+
+static struct op **
+find1case(t, w)
+struct op *t;
+char *w;
+{
+ register struct op *t1;
+ struct op **tp;
+ register char **wp, *cp;
+
+ if (t == NULL)
+ return((struct op **)NULL);
+ if (t->type == TLIST) {
+ if ((tp = find1case(t->left, w)) != NULL)
+ return(tp);
+ t1 = t->right; /* TPAT */
+ } else
+ t1 = t;
+ for (wp = t1->words; *wp;)
+ if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
+ return(&t1->left);
+ return((struct op **)NULL);
+}
+
+static struct op *
+findcase(t, w)
+struct op *t;
+char *w;
+{
+ register struct op **tp;
+
+ return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL);
+}
+
+/*
+ * Enter a new loop level (marked for break/continue).
+ */
+static void
+brkset(bc)
+struct brkcon *bc;
+{
+ bc->nextlev = brklist;
+ brklist = bc;
+}
+
+/*
+ * Wait for the last process created.
+ * Print a message for each process found
+ * that was killed by a signal.
+ * Ignore interrupt signals while waiting
+ * unless `canintr' is true.
+ */
+int
+waitfor(lastpid, canintr)
+register int lastpid;
+int canintr;
+{
+ register int pid, rv;
+ int s;
+ int oheedint = heedint;
+
+ heedint = 0;
+ rv = 0;
+ do {
+ pid = wait(&s);
+ if (pid == -1) {
+ if (errno != EINTR || canintr)
+ break;
+ } else {
+ if ((rv = WAITSIG(s)) != 0) {
+ if (rv < NSIGNAL) {
+ if (signame[rv] != NULL) {
+ if (pid != lastpid) {
+ prn(pid);
+ prs(": ");
+ }
+ prs(signame[rv]);
+ }
+ } else {
+ if (pid != lastpid) {
+ prn(pid);
+ prs(": ");
+ }
+ prs("Signal "); prn(rv); prs(" ");
+ }
+ if (WAITCORE(s))
+ prs(" - core dumped");
+ if (rv >= NSIGNAL || signame[rv])
+ prs("\n");
+ rv = -1;
+ } else
+ rv = WAITVAL(s);
+ }
+ } while (pid != lastpid);
+ heedint = oheedint;
+ if (intr)
+ if (talking) {
+ if (canintr)
+ intr = 0;
+ } else {
+ if (exstat == 0) exstat = rv;
+ onintr(0);
+ }
+ return(rv);
+}
+
+int
+setstatus(s)
+register int s;
+{
+ exstat = s;
+ setval(lookup("?"), putn(s));
+ return(s);
+}
+
+/*
+ * PATH-searching interface to execve.
+ * If getenv("PATH") were kept up-to-date,
+ * execvp might be used.
+ */
+char *
+rexecve(c, v, envp)
+char *c, **v, **envp;
+{
+ register int i;
+ register char *sp, *tp;
+ int eacces = 0, asis = 0;
+
+ sp = any('/', c)? "": path->value;
+ asis = *sp == '\0';
+ while (asis || *sp != '\0') {
+ asis = 0;
+ tp = e.linep;
+ for (; *sp != '\0'; tp++)
+ if ((*tp = *sp++) == ':') {
+ asis = *sp == '\0';
+ break;
+ }
+ if (tp != e.linep)
+ *tp++ = '/';
+ for (i = 0; (*tp++ = c[i++]) != '\0';)
+ ;
+ execve(e.linep, v, envp);
+ switch (errno) {
+ case ENOEXEC:
+ *v = e.linep;
+ tp = *--v;
+ *v = e.linep;
+ execve("/bin/sh", v, envp);
+ *v = tp;
+ return("no Shell");
+
+ case ENOMEM:
+ return("program too big");
+
+ case E2BIG:
+ return("argument list too long");
+
+ case EACCES:
+ eacces++;
+ break;
+ }
+ }
+ return(errno==ENOENT ? "not found" : "cannot execute");
+}
+
+/*
+ * Run the command produced by generator `f'
+ * applied to stream `arg'.
+ */
+int
+run(argp, f)
+struct ioarg *argp;
+int (*f)();
+{
+ struct op *otree;
+ struct wdblock *swdlist;
+ struct wdblock *siolist;
+ jmp_buf ev, rt;
+ xint *ofail;
+ int rv;
+
+ areanum++;
+ swdlist = wdlist;
+ siolist = iolist;
+ otree = outtree;
+ ofail = failpt;
+ rv = -1;
+ if (newenv(setjmp(errpt = ev)) == 0) {
+ wdlist = 0;
+ iolist = 0;
+ pushio(argp, f);
+ e.iobase = e.iop;
+ yynerrs = 0;
+ if (setjmp(failpt = rt) == 0 && yyparse() == 0)
+ rv = execute(outtree, NOPIPE, NOPIPE, 0);
+ quitenv();
+ }
+ wdlist = swdlist;
+ iolist = siolist;
+ failpt = ofail;
+ outtree = otree;
+ freearea(areanum--);
+ return(rv);
+}
+
+/* -------- do.c -------- */
+/* #include "sh.h" */
+
+/*
+ * built-in commands: doX
+ */
+
+int
+dolabel()
+{
+ return(0);
+}
+
+int
+dochdir(t)
+register struct op *t;
+{
+ register char *cp, *er;
+
+ if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
+ er = ": no home directory";
+ else if(chdir(cp) < 0)
+ er = ": bad directory";
+ else
+ return(0);
+ prs(cp != NULL? cp: "cd");
+ err(er);
+ return(1);
+}
+
+int
+doshift(t)
+register struct op *t;
+{
+ register n;
+
+ n = t->words[1]? getn(t->words[1]): 1;
+ if(dolc < n) {
+ err("nothing to shift");
+ return(1);
+ }
+ dolv[n] = dolv[0];
+ dolv += n;
+ dolc -= n;
+ setval(lookup("#"), putn(dolc));
+ return(0);
+}
+
+/*
+ * execute login and newgrp directly
+ */
+int
+dologin(t)
+struct op *t;
+{
+ register char *cp;
+
+ if (talking) {
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ }
+ cp = rexecve(t->words[0], t->words, makenv());
+ prs(t->words[0]); prs(": "); err(cp);
+ return(1);
+}
+
+int
+doumask(t)
+register struct op *t;
+{
+ register int i, n;
+ register char *cp;
+
+ if ((cp = t->words[1]) == NULL) {
+ i = umask(0);
+ umask(i);
+ for (n=3*4; (n-=3) >= 0;)
+ putc('0'+((i>>n)&07));
+ putc('\n');
+ } else {
+ for (n=0; *cp>='0' && *cp<='9'; cp++)
+ n = n*8 + (*cp-'0');
+ umask(n);
+ }
+ return(0);
+}
+
+int
+doexec(t)
+register struct op *t;
+{
+ register i;
+ jmp_buf ex;
+ xint *ofail;
+
+ t->ioact = NULL;
+ for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++)
+ ;
+ if (i == 0)
+ return(1);
+ execflg = 1;
+ ofail = failpt;
+ if (setjmp(failpt = ex) == 0)
+ execute(t, NOPIPE, NOPIPE, FEXEC);
+ failpt = ofail;
+ execflg = 0;
+ return(1);
+}
+
+int
+dodot(t)
+struct op *t;
+{
+ register i;
+ register char *sp, *tp;
+ char *cp;
+
+ if ((cp = t->words[1]) == NULL)
+ return(0);
+ sp = any('/', cp)? ":": path->value;
+ while (*sp) {
+ tp = e.linep;
+ while (*sp && (*tp = *sp++) != ':')
+ tp++;
+ if (tp != e.linep)
+ *tp++ = '/';
+ for (i = 0; (*tp++ = cp[i++]) != '\0';)
+ ;
+ if ((i = open(e.linep, 0)) >= 0) {
+ exstat = 0;
+ next(remap(i));
+ return(exstat);
+ }
+ }
+ prs(cp);
+ err(": not found");
+ return(-1);
+}
+
+int
+dowait(t)
+struct op *t;
+{
+ register i;
+ register char *cp;
+
+ if ((cp = t->words[1]) != NULL) {
+ i = getn(cp);
+ if (i == 0)
+ return(0);
+ } else
+ i = -1;
+ setstatus(waitfor(i, 1));
+ return(0);
+}
+
+int
+doread(t)
+struct op *t;
+{
+ register char *cp, **wp;
+ register nb;
+ register int nl = 0;
+
+ if (t->words[1] == NULL) {
+ err("Usage: read name ...");
+ return(1);
+ }
+ for (wp = t->words+1; *wp; wp++) {
+ for (cp = e.linep; !nl && cp < elinep-1; cp++)
+ if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
+ (nl = (*cp == '\n')) ||
+ (wp[1] && any(*cp, ifs->value)))
+ break;
+ *cp = 0;
+ if (nb <= 0)
+ break;
+ setval(lookup(*wp), e.linep);
+ }
+ return(nb <= 0);
+}
+
+int
+doeval(t)
+register struct op *t;
+{
+ return(RUN(awordlist, t->words+1, wdchar));
+}
+
+int
+dotrap(t)
+register struct op *t;
+{
+ register int n, i;
+ register int resetsig;
+
+ if (t->words[1] == NULL) {
+ for (i=0; i<=_NSIG; i++)
+ if (trap[i]) {
+ prn(i);
+ prs(": ");
+ prs(trap[i]);
+ prs("\n");
+ }
+ return(0);
+ }
+ resetsig = digit(*t->words[1]);
+ for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
+ n = getsig(t->words[i]);
+ xfree(trap[n]);
+ trap[n] = 0;
+ if (!resetsig) {
+ if (*t->words[1] != '\0') {
+ trap[n] = strsave(t->words[1], 0);
+ setsig(n, sig);
+ } else
+ setsig(n, SIG_IGN);
+ } else {
+ if (talking)
+ if (n == SIGINT)
+ setsig(n, onintr);
+ else
+ setsig(n, n == SIGQUIT ? SIG_IGN
+ : SIG_DFL);
+ else
+ setsig(n, SIG_DFL);
+ }
+ }
+ return(0);
+}
+
+int
+getsig(s)
+char *s;
+{
+ register int n;
+
+ if ((n = getn(s)) < 0 || n > _NSIG) {
+ err("trap: bad signal number");
+ n = 0;
+ }
+ return(n);
+}
+
+void
+setsig(n, f)
+register n;
+_PROTOTYPE(void (*f), (int));
+{
+ if (n == 0)
+ return;
+ if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
+ ourtrap[n] = 1;
+ signal(n, f);
+ }
+}
+
+int
+getn(as)
+char *as;
+{
+ register char *s;
+ register n, m;
+
+ s = as;
+ m = 1;
+ if (*s == '-') {
+ m = -1;
+ s++;
+ }
+ for (n = 0; digit(*s); s++)
+ n = (n*10) + (*s-'0');
+ if (*s) {
+ prs(as);
+ err(": bad number");
+ }
+ return(n*m);
+}
+
+int
+dobreak(t)
+struct op *t;
+{
+ return(brkcontin(t->words[1], 1));
+}
+
+int
+docontinue(t)
+struct op *t;
+{
+ return(brkcontin(t->words[1], 0));
+}
+
+static int
+brkcontin(cp, val)
+register char *cp;
+int val;
+{
+ register struct brkcon *bc;
+ register nl;
+
+ nl = cp == NULL? 1: getn(cp);
+ if (nl <= 0)
+ nl = 999;
+ do {
+ if ((bc = brklist) == NULL)
+ break;
+ brklist = bc->nextlev;
+ } while (--nl);
+ if (nl) {
+ err("bad break/continue level");
+ return(1);
+ }
+ isbreak = val;
+ longjmp(bc->brkpt, 1);
+ /* NOTREACHED */
+}
+
+int
+doexit(t)
+struct op *t;
+{
+ register char *cp;
+
+ execflg = 0;
+ if ((cp = t->words[1]) != NULL)
+ setstatus(getn(cp));
+ leave();
+ /* NOTREACHED */
+}
+
+int
+doexport(t)
+struct op *t;
+{
+ rdexp(t->words+1, export, EXPORT);
+ return(0);
+}
+
+int
+doreadonly(t)
+struct op *t;
+{
+ rdexp(t->words+1, ronly, RONLY);
+ return(0);
+}
+
+static void
+rdexp(wp, f, key)
+register char **wp;
+void (*f)();
+int key;
+{
+ if (*wp != NULL) {
+ for (; *wp != NULL; wp++)
+ if (checkname(*wp))
+ (*f)(lookup(*wp));
+ else
+ badid(*wp);
+ } else
+ putvlist(key, 1);
+}
+
+static void
+badid(s)
+register char *s;
+{
+ prs(s);
+ err(": bad identifier");
+}
+
+int
+doset(t)
+register struct op *t;
+{
+ register struct var *vp;
+ register char *cp;
+ register n;
+
+ if ((cp = t->words[1]) == NULL) {
+ for (vp = vlist; vp; vp = vp->next)
+ varput(vp->name, 1);
+ return(0);
+ }
+ if (*cp == '-') {
+ /* bad: t->words++; */
+ for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++)
+ ;
+ if (*++cp == 0)
+ flag['x'] = flag['v'] = 0;
+ else
+ for (; *cp; cp++)
+ switch (*cp) {
+ case 'e':
+ if (!talking)
+ flag['e']++;
+ break;
+
+ default:
+ if (*cp>='a' && *cp<='z')
+ flag[*cp]++;
+ break;
+ }
+ setdash();
+ }
+ if (t->words[1]) {
+ t->words[0] = dolv[0];
+ for (n=1; t->words[n]; n++)
+ setarea((char *)t->words[n], 0);
+ dolc = n-1;
+ dolv = t->words;
+ setval(lookup("#"), putn(dolc));
+ setarea((char *)(dolv-1), 0);
+ }
+ return(0);
+}
+
+void
+varput(s, out)
+register char *s;
+int out;
+{
+ if (letnum(*s)) {
+ write(out, s, strlen(s));
+ write(out, "\n", 1);
+ }
+}
+
+
+#define SECS 60L
+#define MINS 3600L
+
+int
+dotimes()
+{
+ struct tms tbuf;
+
+ times(&tbuf);
+
+ prn((int)(tbuf.tms_cutime / MINS));
+ prs("m");
+ prn((int)((tbuf.tms_cutime % MINS) / SECS));
+ prs("s ");
+ prn((int)(tbuf.tms_cstime / MINS));
+ prs("m");
+ prn((int)((tbuf.tms_cstime % MINS) / SECS));
+ prs("s\n");
+ return(0);
+}
+
+struct builtin {
+ char *command;
+ int (*fn)();
+};
+static struct builtin builtin[] = {
+ ":", dolabel,
+ "cd", dochdir,
+ "shift", doshift,
+ "exec", doexec,
+ "wait", dowait,
+ "read", doread,
+ "eval", doeval,
+ "trap", dotrap,
+ "break", dobreak,
+ "continue", docontinue,
+ "exit", doexit,
+ "export", doexport,
+ "readonly", doreadonly,
+ "set", doset,
+ ".", dodot,
+ "umask", doumask,
+ "login", dologin,
+ "newgrp", dologin,
+ "times", dotimes,
+ 0,
+};
+
+int (*inbuilt(s))()
+register char *s;
+{
+ register struct builtin *bp;
+
+ for (bp = builtin; bp->command != NULL; bp++)
+ if (strcmp(bp->command, s) == 0)
+ return(bp->fn);
+ return((int(*)())NULL);
+}
+