ast@cs.vu.nl (Andy Tanenbaum) (10/06/88)
: This is a shar archive. Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'sh3.c'
sed 's/^X//' > 'sh3.c' << '+ END-OF-FILE ''sh3.c'
X#define Extern extern
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include "sh.h"
X
X/* -------- exec.c -------- */
X/* #include "sh.h" */
X
X/*
X * execute tree
X */
X
Xstatic char *signame[] = {
X "Signal 0",
X "Hangup",
X NULL, /* interrupt */
X "Quit",
X "Illegal instruction",
X "Trace/BPT trap",
X "abort",
X "EMT trap",
X "Floating exception",
X "Killed",
X "Bus error",
X "Memory fault",
X "Bad system call",
X NULL, /* broken pipe */
X "Alarm clock",
X "Terminated",
X};
X#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
X
Xstatic struct op *findcase();
Xstatic void brkset();
Xstatic void echo();
Xstatic int forkexec();
Xstatic int parent();
X
Xint
Xexecute(t, pin, pout, act)
Xregister struct op *t;
Xint *pin, *pout;
Xint act;
X{
X register struct op *t1;
X int i, pv[2], rv, child, a;
X char *cp, **wp, **wp2;
X struct var *vp;
X struct brkcon bc;
X
X if (t == NULL)
X return(0);
X rv = 0;
X a = areanum++;
X wp = (wp2 = t->words) != NULL? eval(wp2, DOALL): NULL;
X
X switch(t->type) {
X case TPAREN:
X case TCOM:
X rv = forkexec(t, pin, pout, act, wp, &child);
X if (child) {
X exstat = rv;
X leave();
X }
X break;
X
X case TPIPE:
X if ((rv = openpipe(pv)) < 0)
X break;
X pv[0] = remap(pv[0]);
X pv[1] = remap(pv[1]);
X (void) execute(t->left, pin, pv, 0);
X rv = execute(t->right, pv, pout, 0);
X break;
X
X case TLIST:
X (void) execute(t->left, pin, pout, 0);
X rv = execute(t->right, pin, pout, 0);
X break;
X
X case TASYNC:
X i = parent();
X if (i != 0) {
X if (i != -1) {
X if (pin != NULL)
X closepipe(pin);
X if (talking) {
X prs(putn(i));
X prs("\n");
X }
X } else
X rv = -1;
X setstatus(rv);
X } else {
X signal(SIGINT, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X if (talking)
X signal(SIGTERM, SIG_DFL);
X talking = 0;
X if (pin == NULL) {
X close(0);
X open("/dev/null", 0);
X }
X exit(execute(t->left, pin, pout, FEXEC));
X }
X break;
X
X case TOR:
X case TAND:
X rv = execute(t->left, pin, pout, 0);
X if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND))
X rv = execute(t1, pin, pout, 0);
X break;
X
X case TFOR:
X if (wp == NULL) {
X wp = dolv+1;
X if ((i = dolc) < 0)
X i = 0;
X } else
X i = -1;
X vp = lookup(t->str);
X while (setjmp(bc.brkpt))
X if (isbreak)
X goto broken;
X brkset(&bc);
X for (t1 = t->left; i-- && *wp != NULL;) {
X setval(vp, *wp++);
X rv = execute(t1, pin, pout, 0);
X }
X brklist = brklist->nextlev;
X break;
X
X case TWHILE:
X case TUNTIL:
X while (setjmp(bc.brkpt))
X if (isbreak)
X goto broken;
X brkset(&bc);
X t1 = t->left;
X while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
X rv = execute(t->right, pin, pout, 0);
X brklist = brklist->nextlev;
X break;
X
X case TIF:
X case TELIF:
X rv = !execute(t->left, pin, pout, 0)?
X execute(t->right->left, pin, pout, 0):
X execute(t->right->right, pin, pout, 0);
X break;
X
X case TCASE:
X if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0)
X cp = "";
X if ((t1 = findcase(t->left, cp)) != NULL)
X rv = execute(t1, pin, pout, 0);
X break;
X
X case TBRACE:
X/*
X if (iopp = t->ioact)
X while (*iopp)
X if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
X rv = -1;
X break;
X }
X*/
X if (rv >= 0 && (t1 = t->left))
X rv = execute(t1, pin, pout, 0);
X break;
X }
X
Xbroken:
X t->words = wp2;
X isbreak = 0;
X freehere(areanum);
X freearea(areanum);
X areanum = a;
X if (intr) {
X closeall();
X fail();
X }
X return(rv);
X}
X
Xstatic int
Xforkexec(t, pin, pout, act, wp, pforked)
Xregister struct op *t;
Xint *pin, *pout;
Xint act;
Xchar **wp;
Xint *pforked;
X{
X int i, rv, (*shcom)();
X int doexec();
X register int f;
X char *cp;
X struct ioword **iopp;
X int resetsig;
X
X resetsig = 0;
X *pforked = 0;
X shcom = NULL;
X rv = -1; /* system-detected error */
X if (t->type == TCOM) {
X /* strip all initial assignments */
X /* not correct wrt PATH=yyy command etc */
X if (flag['x'])
X echo(wp);
X while ((cp = *wp++) != NULL && assign(cp, COPYV))
X ;
X wp--;
X if (cp == NULL && t->ioact == NULL)
X return(setstatus(0));
X else if (cp != NULL)
X shcom = inbuilt(cp);
X }
X t->words = wp;
X f = act;
X if (shcom == NULL && (f & FEXEC) == 0) {
X i = parent();
X if (i != 0) {
X if (i == -1)
X return(rv);
X if (pin != NULL)
X closepipe(pin);
X return(pout==NULL? setstatus(waitfor(i,0)): 0);
X }
X if (talking) {
X signal(SIGINT, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X resetsig = 1;
X }
X talking = 0;
X intr = 0;
X (*pforked)++;
X brklist = 0;
X execflg = 0;
X }
X#ifdef COMPIPE
X if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
X err("piping to/from shell builtins not yet done");
X return(-1);
X }
X#endif
X if (pin != NULL) {
X dup2(pin[0], 0);
X closepipe(pin);
X }
X if (pout != NULL) {
X dup2(pout[1], 1);
X closepipe(pout);
X }
X if ((iopp = t->ioact) != NULL) {
X if (shcom != NULL && shcom != doexec) {
X prs(cp);
X err(": cannot redirect shell command");
X return(-1);
X }
X while (*iopp)
X if (iosetup(*iopp++, pin!=NULL, pout!=NULL))
X return(rv);
X }
X if (shcom)
X return(setstatus((*shcom)(t)));
X /* should use FIOCEXCL */
X for (i=FDBASE; i<NOFILE; i++)
X close(i);
X if (resetsig) {
X signal(SIGINT, SIG_DFL);
X signal(SIGQUIT, SIG_DFL);
X }
X if (t->type == TPAREN)
X exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
X if (wp[0] == NULL)
X exit(0);
X cp = rexecve(wp[0], wp, makenv(wp));
X prs(wp[0]); prs(": "); warn(cp);
X if (!execflg)
X trap[0] = NULL;
X leave();
X /* NOTREACHED */
X}
X
X/*
X * common actions when creating a new child
X */
Xstatic int
Xparent()
X{
X register int i;
X
X i = fork();
X if (i != 0) {
X if (i == -1)
X warn("try again");
X setval(lookup("!"), putn(i));
X }
X return(i);
X}
X
X/*
X * 0< 1> are ignored as required
X * within pipelines.
X */
Xiosetup(iop, pipein, pipeout)
Xregister struct ioword *iop;
Xint pipein, pipeout;
X{
X register u;
X char *cp, *msg;
X
X if (iop->io_unit == IODEFAULT) /* take default */
X iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1;
X if (pipein && iop->io_unit == 0)
X return(0);
X if (pipeout && iop->io_unit == 1)
X return(0);
X msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create";
X if ((iop->io_flag & IOHERE) == 0) {
X cp = iop->io_name;
X if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL)
X return(1);
X }
X if (iop->io_flag & IODUP) {
X if (cp[1] || !digit(*cp) && *cp != '-') {
X prs(cp);
X err(": illegal >& argument");
X return(1);
X }
X if (*cp == '-')
X iop->io_flag = IOCLOSE;
X iop->io_flag &= ~(IOREAD|IOWRITE);
X }
X switch (iop->io_flag) {
X case IOREAD:
X u = open(cp, 0);
X break;
X
X case IOHERE:
X case IOHERE|IOXHERE:
X u = herein(iop->io_name, iop->io_flag&IOXHERE);
X cp = "here file";
X break;
X
X case IOWRITE|IOCAT:
X if ((u = open(cp, 1)) >= 0) {
X lseek(u, (long)0, 2);
X break;
X }
X case IOWRITE:
X u = creat(cp, 0666);
X break;
X
X case IODUP:
X u = dup2(*cp-'0', iop->io_unit);
X break;
X
X case IOCLOSE:
X close(iop->io_unit);
X return(0);
X }
X if (u < 0) {
X prs(cp);
X prs(": cannot ");
X warn(msg);
X return(1);
X } else {
X if (u != iop->io_unit) {
X dup2(u, iop->io_unit);
X close(u);
X }
X }
X return(0);
X}
X
Xstatic void
Xecho(wp)
Xregister char **wp;
X{
X register i;
X
X prs("+");
X for (i=0; wp[i]; i++) {
X if (i)
X prs(" ");
X prs(wp[i]);
X }
X prs("\n");
X}
X
Xstatic struct op **
Xfind1case(t, w)
Xstruct op *t;
Xchar *w;
X{
X register struct op *t1;
X struct op **tp;
X register char **wp, *cp;
X
X if (t == NULL)
X return(NULL);
X if (t->type == TLIST) {
X if ((tp = find1case(t->left, w)) != NULL)
X return(tp);
X t1 = t->right; /* TPAT */
X } else
X t1 = t;
X for (wp = t1->words; *wp;)
X if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
X return(&t1->left);
X return(NULL);
X}
X
Xstatic struct op *
Xfindcase(t, w)
Xstruct op *t;
Xchar *w;
X{
X register struct op **tp;
X
X return((tp = find1case(t, w)) != NULL? *tp: NULL);
X}
X
X/*
X * Enter a new loop level (marked for break/continue).
X */
Xstatic void
Xbrkset(bc)
Xstruct brkcon *bc;
X{
X bc->nextlev = brklist;
X brklist = bc;
X}
X
X/*
X * Wait for the last process created.
X * Print a message for each process found
X * that was killed by a signal.
X * Ignore interrupt signals while waiting
X * unless `canintr' is true.
X */
Xint
Xwaitfor(lastpid, canintr)
Xregister int lastpid;
Xint canintr;
X{
X register int pid, rv;
X int s;
X
X rv = 0;
X do {
X pid = wait(&s);
X if (pid == -1) {
X if (errno != EINTR || canintr)
X break;
X } else {
X if ((rv = WAITSIG(s)) != 0) {
X if (rv < NSIGNAL) {
X if (signame[rv] != NULL) {
X if (pid != lastpid) {
X prn(pid);
X prs(": ");
X }
X prs(signame[rv]);
X }
X } else {
X if (pid != lastpid) {
X prn(pid);
X prs(": ");
X }
X prs("Signal "); prn(rv); prs(" ");
X }
X if (WAITCORE(s))
X prs(" - core dumped");
X prs("\n");
X rv = -1;
X } else
X rv = WAITVAL(s);
X }
X/* Special patch for MINIX: sync before each command */
X sync();
X } while (pid != lastpid);
X return(rv);
X}
X
Xint
Xsetstatus(s)
Xregister int s;
X{
X exstat = s;
X setval(lookup("?"), putn(s));
X return(s);
X}
X
X/*
X * PATH-searching interface to execve.
X * If getenv("PATH") were kept up-to-date,
X * execvp might be used.
X */
Xchar *
Xrexecve(c, v, envp)
Xchar *c, **v, **envp;
X{
X register int i;
X register char *sp, *tp;
X int eacces = 0, asis = 0;
X extern int errno;
X
X sp = any('/', c)? "": path->value;
X asis = *sp == '\0';
X while (asis || *sp != '\0') {
X asis = 0;
X tp = e.linep;
X for (; *sp != '\0'; tp++)
X if ((*tp = *sp++) == ':') {
X asis = *sp == '\0';
X break;
X }
X if (tp != e.linep)
X *tp++ = '/';
X for (i = 0; (*tp++ = c[i++]) != '\0';)
X ;
X execve(e.linep, v, envp);
X switch (errno) {
X case ENOEXEC:
X *v = e.linep;
X tp = *--v;
X *v = e.linep;
X execve("/bin/sh", v, envp);
X *v = tp;
X return("no Shell");
X
X case ENOMEM:
X return("program too big");
X
X case E2BIG:
X return("argument list too long");
X
X case EACCES:
X eacces++;
X break;
X }
X }
X return(errno==ENOENT ? "not found" : "cannot execute");
X}
X
X/*
X * Run the command produced by generator `f'
X * applied to stream `arg'.
X */
Xrun(arg, f)
Xstruct ioarg arg;
Xint (*f)();
X{
X struct op *otree;
X struct wdblock *swdlist;
X struct wdblock *siolist;
X jmp_buf ev, rt;
X xint *ofail;
X int rv;
X
X areanum++;
X swdlist = wdlist;
X siolist = iolist;
X otree = outtree;
X ofail = failpt;
X rv = -1;
X if (newenv(setjmp(errpt = ev)) == 0) {
X wdlist = 0;
X iolist = 0;
X pushio(arg, f);
X e.iobase = e.iop;
X yynerrs = 0;
X if (setjmp(failpt = rt) == 0 && yyparse() == 0)
X rv = execute(outtree, NOPIPE, NOPIPE, 0);
X quitenv();
X }
X wdlist = swdlist;
X iolist = siolist;
X failpt = ofail;
X outtree = otree;
X freearea(areanum--);
X return(rv);
X}
X
X/* -------- do.c -------- */
X/* #include "sh.h" */
X
X/*
X * built-in commands: doX
X */
X
Xstatic void rdexp();
Xstatic void badid();
Xstatic int brkcontin();
X
Xdolabel()
X{
X return(0);
X}
X
Xdochdir(t)
Xregister struct op *t;
X{
X register char *cp, *er;
X
X if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
X er = ": no home directory";
X else if(chdir(cp) < 0)
X er = ": bad directory";
X else
X return(0);
X prs(cp != NULL? cp: "cd");
X err(er);
X return(1);
X}
X
Xdoshift(t)
Xregister struct op *t;
X{
X register n;
X
X n = t->words[1]? getn(t->words[1]): 1;
X if(dolc < n) {
X err("nothing to shift");
X return(1);
X }
X dolv[n] = dolv[0];
X dolv += n;
X dolc -= n;
X setval(lookup("#"), putn(dolc));
X return(0);
X}
X
X/*
X * execute login and newgrp directly
X */
Xdologin(t)
Xstruct op *t;
X{
X register char *cp;
X
X if (talking) {
X signal(SIGINT, SIG_DFL);
X signal(SIGQUIT, SIG_DFL);
X }
X cp = rexecve(t->words[0], t->words, makenv(t->words));
X prs(t->words[0]); prs(": "); err(cp);
X return(1);
X}
X
Xdoumask(t)
Xregister struct op *t;
X{
X register int i, n;
X register char *cp;
X
X if ((cp = t->words[1]) == NULL) {
X i = umask(0);
X umask(i);
X for (n=3*4; (n-=3) >= 0;)
X putc('0'+((i>>n)&07));
X putc('\n');
X } else {
X for (n=0; *cp>='0' && *cp<='9'; cp++)
X n = n*8 + (*cp-'0');
X umask(n);
X }
X return(0);
X}
X
Xdoexec(t)
Xregister struct op *t;
X{
X register i;
X jmp_buf ex;
X xint *ofail;
X
X t->ioact = NULL;
X for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++)
X ;
X if (i == 0)
X return(1);
X execflg = 1;
X ofail = failpt;
X if (setjmp(failpt = ex) == 0)
X execute(t, NOPIPE, NOPIPE, FEXEC);
X failpt = ofail;
X execflg = 0;
X return(1);
X}
X
Xdodot(t)
Xstruct op *t;
X{
X register i;
X register char *sp, *tp;
X char *cp;
X
X if ((cp = t->words[1]) == NULL)
X return(0);
X sp = any('/', cp)? ":": path->value;
X while (*sp) {
X tp = e.linep;
X while (*sp && (*tp = *sp++) != ':')
X tp++;
X if (tp != e.linep)
X *tp++ = '/';
X for (i = 0; (*tp++ = cp[i++]) != '\0';)
X ;
X if ((i = open(e.linep, 0)) >= 0) {
X exstat = 0;
X next(remap(i));
X return(exstat);
X }
X }
X prs(cp);
X err(": not found");
X return(-1);
X}
X
Xdowait(t)
Xstruct op *t;
X{
X register i;
X register char *cp;
X
X if ((cp = t->words[1]) != NULL) {
X i = getn(cp);
X if (i == 0)
X return(0);
X } else
X i = -1;
X if (talking)
X signal(SIGINT, onintr);
X setstatus(waitfor(i, 1));
X if (talking)
X signal(SIGINT, SIG_IGN);
X return(0);
X}
X
Xdoread(t)
Xstruct op *t;
X{
X register char *cp, **wp;
X register nb;
X
X if (t->words[1] == NULL) {
X err("Usage: read name ...");
X return(1);
X }
X for (wp = t->words+1; *wp; wp++) {
X for (cp = e.linep; cp < elinep-1; cp++)
X if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
X *cp == '\n' ||
X wp[1] && any(*cp, ifs->value))
X break;
X *cp = 0;
X if (nb <= 0)
X break;
X setval(lookup(*wp), e.linep);
X }
X return(nb <= 0);
X}
X
Xdoeval(t)
Xregister struct op *t;
X{
X int wdchar();
X
X return(RUN(awordlist, t->words+1, wdchar));
X}
X
Xdotrap(t)
Xregister struct op *t;
X{
X register char *s;
X register n, i;
X
X if (t->words[1] == NULL) {
X for (i=0; i<NSIG; i++)
X if (trap[i]) {
X prn(i);
X prs(": ");
X prs(trap[i]);
X prs("\n");
X }
X return(0);
X }
X n = getsig((s = t->words[2])!=NULL? s: t->words[1]);
X xfree(trap[n]);
X trap[n] = 0;
X if (s != NULL) {
X if ((i = strlen(s = t->words[1])) != 0) {
X trap[n] = strsave(s, 0);
X setsig(n, sig);
X } else
X setsig(n, SIG_IGN);
X } else
X setsig(n, (n == SIGINT || n == SIGQUIT) && talking? SIG_IGN: SIG_DFL);
X return(0);
X}
X
Xgetsig(s)
Xchar *s;
X{
X register int n;
X
X if ((n = getn(s)) < 0 || n >= NSIG) {
X err("trap: bad signal number");
X n = 0;
X }
X return(n);
X}
X
Xsetsig(n, f)
Xregister n;
Xint (*f)();
X{
X if (n == 0)
X return;
X if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
X ourtrap[n] = 1;
X signal(n, f);
X }
X}
X
Xgetn(as)
Xchar *as;
X{
X register char *s;
X register n, m;
X
X s = as;
X m = 1;
X if (*s == '-') {
X m = -1;
X s++;
X }
X for (n = 0; digit(*s); s++)
X n = (n*10) + (*s-'0');
X if (*s) {
X prs(as);
X err(": bad number");
X }
X return(n*m);
X}
X
Xdobreak(t)
Xstruct op *t;
X{
X return(brkcontin(t->words[1], 1));
X}
X
Xdocontinue(t)
Xstruct op *t;
X{
X return(brkcontin(t->words[1], 0));
X}
X
Xstatic int
Xbrkcontin(cp, val)
Xregister char *cp;
X{
X register struct brkcon *bc;
X register nl;
X
X nl = cp == NULL? 1: getn(cp);
X if (nl <= 0)
X nl = 999;
X do {
X if ((bc = brklist) == NULL)
X break;
X brklist = bc->nextlev;
X } while (--nl);
X if (nl) {
X err("bad break/continue level");
X return(1);
X }
X isbreak = val;
X longjmp(bc->brkpt, 1);
X /* NOTREACHED */
X}
X
Xdoexit(t)
Xstruct op *t;
X{
X register char *cp;
X
X execflg = 0;
X if ((cp = t->words[1]) != NULL)
X exstat = getn(cp);
X leave();
X}
X
Xdoexport(t)
Xstruct op *t;
X{
X rdexp(t->words+1, export, EXPORT);
X return(0);
X}
X
Xdoreadonly(t)
Xstruct op *t;
X{
X rdexp(t->words+1, ronly, RONLY);
X return(0);
X}
X
Xstatic void
Xrdexp(wp, f, key)
Xregister char **wp;
Xvoid (*f)();
Xint key;
X{
X if (*wp != NULL) {
X for (; *wp != NULL; wp++)
X if (checkname(*wp))
X (*f)(lookup(*wp));
X else
X badid(*wp);
X } else
X putvlist(key, 1);
X}
X
Xstatic void
Xbadid(s)
Xregister char *s;
X{
X prs(s);
X err(": bad identifier");
X}
X
Xdoset(t)
Xregister struct op *t;
X{
X register struct var *vp;
X register char *cp;
X register n;
X
X if ((cp = t->words[1]) == NULL) {
X for (vp = vlist; vp; vp = vp->next)
X varput(vp->name, 1);
X return(0);
X }
X if (*cp == '-') {
X t->words++;
X if (*++cp == 0)
X flag['x'] = flag['v'] = 0;
X else
X for (; *cp; cp++)
X switch (*cp) {
X case 'e':
X if (!talking)
X flag['e']++;
X break;
X
X default:
X if (*cp>='a' && *cp<='z')
X flag[*cp]++;
X break;
X }
X setdash();
X }
X if (t->words[1]) {
X t->words[0] = dolv[0];
X for (n=1; t->words[n]; n++)
X setarea((char *)t->words[n], 0);
X dolc = n-1;
X dolv = t->words;
X setval(lookup("#"), putn(dolc));
X setarea((char *)(dolv-1), 0);
X }
X return(0);
X}
X
Xvarput(s, out)
Xregister char *s;
X{
X if (letnum(*s)) {
X write(out, s, strlen(s));
X write(out, "\n", 1);
X }
X}
X
X
Xstruct builtin {
X char *command;
X int (*fn)();
X};
Xstatic struct builtin builtin[] = {
X ":", dolabel,
X "cd", dochdir,
X "shift", doshift,
X "exec", doexec,
X "wait", dowait,
X "read", doread,
X "eval", doeval,
X "trap", dotrap,
X "break", dobreak,
X "continue", docontinue,
X "exit", doexit,
X "export", doexport,
X "readonly", doreadonly,
X "set", doset,
X ".", dodot,
X "umask", doumask,
X "login", dologin,
X "newgrp", dologin,
X 0,
X};
X
Xint (*inbuilt(s))()
Xregister char *s;
X{
X register struct builtin *bp;
X
X for (bp = builtin; bp->command != NULL; bp++)
X if (strcmp(bp->command, s) == 0)
X return(bp->fn);
X return(NULL);
X}
X
+ END-OF-FILE sh3.c
chmod 'u=rw,g=r,o=r' 'sh3.c'
set `wc -c 'sh3.c'`
count=$1
case $count in
16895) :;;
*) echo 'Bad character count in ''sh3.c' >&2
echo 'Count should be 16895' >&2
esac
echo Extracting 'sh4.c'
sed 's/^X//' > 'sh4.c' << '+ END-OF-FILE ''sh4.c'
X#define Extern extern
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#include "sh.h"
X
X/* -------- eval.c -------- */
X/* #include "sh.h" */
X/* #include "word.h" */
X
X/*
X * ${}
X * `command`
X * blank interpretation
X * quoting
X * glob
X */
X
Xstatic char *blank();
Xstatic int grave();
Xstatic int expand();
Xstatic int dollar();
X
Xchar **
Xeval(ap, f)
Xregister char **ap;
X{
X struct wdblock *wb;
X char **wp;
X jmp_buf ev;
X
X inword++;
X wp = NULL;
X wb = NULL;
X if (newenv(setjmp(errpt = ev)) == 0) {
X wb = addword((char *)0, wb); /* space for shell name, if command file */
X while (expand(*ap++, &wb, f))
X ;
X wb = addword((char *)0, wb);
X wp = getwords(wb) + 1;
X quitenv();
X } else
X gflg = 1;
X inword--;
X return(gflg? NULL: wp);
X}
X
X/*
X * Make the exported environment from the exported
X * names in the dictionary. Keyword assignments
X * ought to be taken from wp (the list of words on the command line)
X * but aren't, yet. Until then: ARGSUSED
X */
Xchar **
Xmakenv(wp)
Xchar **wp;
X{
X register struct wdblock *wb;
X register struct var *vp;
X
X wb = NULL;
X for (vp = vlist; vp; vp = vp->next)
X if (vp->status & EXPORT)
X wb = addword(vp->name, wb);
X wb = addword((char *)0, wb);
X return(getwords(wb));
X}
X
Xchar *
Xevalstr(cp, f)
Xregister char *cp;
Xint f;
X{
X struct wdblock *wb;
X
X inword++;
X wb = NULL;
X if (expand(cp, &wb, f)) {
X if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL)
X cp = "";
X DELETE(wb);
X } else
X cp = NULL;
X inword--;
X return(cp);
X}
X
Xstatic int
Xexpand(cp, wbp, f)
Xregister char *cp;
Xregister struct wdblock **wbp;
X{
X jmp_buf ev;
X
X gflg = 0;
X if (cp == NULL)
X return(0);
X if (!anys("$`'\"", cp) &&
X !anys(ifs->value, cp) &&
X ((f&DOGLOB)==0 || !anys("[*?", cp))) {
X cp = strsave(cp, areanum);
X if (f & DOTRIM)
X unquote(cp);
X *wbp = addword(cp, *wbp);
X return(1);
X }
X if (newenv(setjmp(errpt = ev)) == 0) {
X PUSHIO(aword, cp, strchar);
X e.iobase = e.iop;
X while ((cp = blank(f)) && gflg == 0) {
X e.linep = cp;
X cp = strsave(cp, areanum);
X if ((f&DOGLOB) == 0) {
X if (f & DOTRIM)
X unquote(cp);
X *wbp = addword(cp, *wbp);
X } else
X *wbp = glob(cp, *wbp);
X }
X quitenv();
X } else
X gflg = 1;
X return(gflg == 0);
X}
X
X/*
X * Blank interpretation and quoting
X */
Xstatic char *
Xblank(f)
X{
X register c, c1;
X register char *sp;
X
X sp = e.linep;
X
Xloop:
X switch (c = subgetc('"', 0)) {
X case 0:
X if (sp == e.linep)
X return(0);
X *e.linep++ = 0;
X return(sp);
X
X default:
X if (f & DOBLANK && any(c, ifs->value))
X goto loop;
X break;
X
X case '"':
X case '\'':
X if (INSUB())
X break;
X for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
X if (c == 0)
X break;
X if (c == '\'' || !any(c, "$`\""))
X c |= QUOTE;
X *e.linep++ = c;
X }
X c = 0;
X }
X unget(c);
X for (;;) {
X c = subgetc('"', 0);
X if (c == 0 ||
X f & DOBLANK && any(c, ifs->value) ||
X !INSUB() && any(c, "\"'`")) {
X unget(c);
X if (any(c, "\"'`"))
X goto loop;
X break;
X }
X *e.linep++ = c;
X }
X *e.linep++ = 0;
X return(sp);
X}
X
X/*
X * Get characters, substituting for ` and $
X */
Xint
Xsubgetc(ec, quoted)
Xregister char ec;
Xint quoted;
X{
X register char c;
X
Xagain:
X c = getc(ec);
X if (!INSUB() && ec != '\'') {
X if (c == '`') {
X if (grave(quoted) == 0)
X return(0);
X e.iop->task = XGRAVE;
X goto again;
X }
X if (c == '$' && (c = dollar(quoted)) == 0) {
X e.iop->task = XDOLL;
X goto again;
X }
X }
X return(c);
X}
X
X/*
X * Prepare to generate the string returned by ${} substitution.
X */
Xstatic int
Xdollar(quoted)
Xint quoted;
X{
X int otask;
X struct io *oiop;
X char *dolp;
X register char *s, c, *cp;
X struct var *vp;
X
X c = readc();
X s = e.linep;
X if (c != '{') {
X *e.linep++ = c;
X if (letter(c)) {
X while ((c = readc())!=0 && letnum(c))
X if (e.linep < elinep)
X *e.linep++ = c;
X unget(c);
X }
X c = 0;
X } else {
X oiop = e.iop;
X otask = e.iop->task;
X e.iop->task = XOTHER;
X while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n')
X if (e.linep < elinep)
X *e.linep++ = c;
X if (oiop == e.iop)
X e.iop->task = otask;
X if (c != '}') {
X err("unclosed ${");
X gflg++;
X return(c);
X }
X }
X if (e.linep >= elinep) {
X err("string in ${} too long");
X gflg++;
X e.linep -= 10;
X }
X *e.linep = 0;
X if (*s)
X for (cp = s+1; *cp; cp++)
X if (any(*cp, "=-+?")) {
X c = *cp;
X *cp++ = 0;
X break;
X }
X if (s[1] == 0 && (*s == '*' || *s == '@')) {
X if (dolc > 1) {
X /* currently this does not distinguish $* and $@ */
X /* should check dollar */
X e.linep = s;
X PUSHIO(awordlist, dolv+1, dolchar);
X return(0);
X } else { /* trap the nasty ${=} */
X s[0] = '1';
X s[1] = 0;
X }
X }
X vp = lookup(s);
X if ((dolp = vp->value) == null) {
X switch (c) {
X case '=':
X if (digit(*s)) {
X err("cannot use ${...=...} with $n");
X gflg++;
X break;
X }
X setval(vp, cp);
X dolp = vp->value;
X break;
X
X case '-':
X dolp = strsave(cp, areanum);
X break;
X
X case '?':
X if (*cp == 0) {
X prs("missing value for ");
X err(s);
X } else
X err(cp);
X gflg++;
X break;
X }
X } else if (c == '+')
X dolp = strsave(cp, areanum);
X if (flag['u'] && dolp == null) {
X prs("unset variable: ");
X err(s);
X gflg++;
X }
X e.linep = s;
X PUSHIO(aword, dolp, strchar);
X return(0);
X}
X
X/*
X * Run the command in `...` and read its output.
X */
Xstatic int
Xgrave(quoted)
Xint quoted;
X{
X register char *cp;
X register int i;
X int pf[2];
X
X for (cp = e.iop->arg.aword; *cp != '`'; cp++)
X if (*cp == 0) {
X err("no closing `");
X return(0);
X }
X if (openpipe(pf) < 0)
X return(0);
X if ((i = fork()) == -1) {
X closepipe(pf);
X err("try again");
X return(0);
X }
X if (i != 0) {
X e.iop->arg.aword = ++cp;
X close(pf[1]);
X PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar);
X return(1);
X }
X *cp = 0;
X /* allow trapped signals */
X for (i=0; i<NSIG; i++)
X if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
X signal(i, SIG_DFL);
X dup2(pf[1], 1);
X closepipe(pf);
X flag['e'] = 0;
X flag['v'] = 0;
X flag['n'] = 0;
X cp = strsave(e.iop->arg.aword, 0);
X areanum = 1;
X freehere(areanum);
X freearea(areanum); /* free old space */
X e.oenv = NULL;
X e.iop = (e.iobase = iostack) - 1;
X unquote(cp);
X talking = 0;
X PUSHIO(aword, cp, nlchar);
X onecommand();
X exit(1);
X}
X
Xchar *
Xunquote(as)
Xregister char *as;
X{
X register char *s;
X
X if ((s = as) != NULL)
X while (*s)
X *s++ &= ~QUOTE;
X return(as);
X}
X
X/* -------- glob.c -------- */
X/* #include "sh.h" */
X
X/*
X * glob
X */
X
X#define scopy(x) strsave((x), areanum)
X#define BLKSIZ 512
X#define NDENT ((BLKSIZ+sizeof(struct direct)-1)/sizeof(struct direct))
X
Xstatic struct wdblock *cl, *nl;
Xstatic char spcl[] = "[?*";
Xstatic int xstrcmp();
Xstatic char *generate();
Xstatic int anyspcl();
X
Xstruct wdblock *
Xglob(cp, wb)
Xchar *cp;
Xstruct wdblock *wb;
X{
X register i;
X register char *pp;
X
X if (cp == 0)
X return(wb);
X i = 0;
X for (pp = cp; *pp; pp++)
X if (any(*pp, spcl))
X i++;
X else if (!any(*pp & ~QUOTE, spcl))
X *pp &= ~QUOTE;
X if (i != 0) {
X for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) {
X nl = newword(cl->w_nword*2);
X for(i=0; i<cl->w_nword; i++) { /* for each argument */
X for (pp = cl->w_words[i]; *pp; pp++)
X if (any(*pp, spcl)) {
X globname(cl->w_words[i], pp);
X break;
X }
X if (*pp == '\0')
X nl = addword(scopy(cl->w_words[i]), nl);
X }
X for(i=0; i<cl->w_nword; i++)
X DELETE(cl->w_words[i]);
X DELETE(cl);
X }
X for(i=0; i<cl->w_nword; i++)
X unquote(cl->w_words[i]);
X glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
X if (cl->w_nword) {
X for (i=0; i<cl->w_nword; i++)
X wb = addword(cl->w_words[i], wb);
X DELETE(cl);
X return(wb);
X }
X }
X wb = addword(unquote(cp), wb);
X return(wb);
X}
X
Xglobname(we, pp)
Xchar *we;
Xregister char *pp;
X{
X register char *np, *cp;
X char *name, *gp, *dp;
X int dn, j, n, k;
X struct direct ent[NDENT];
X char dname[DIRSIZ+1];
X struct stat dbuf;
X
X for (np = we; np != pp; pp--)
X if (pp[-1] == '/')
X break;
X for (dp = cp = space((int)(pp-np)+3); np < pp;)
X *cp++ = *np++;
X *cp++ = '.';
X *cp = '\0';
X for (gp = cp = space(strlen(pp)+1); *np && *np != '/';)
X *cp++ = *np++;
X *cp = '\0';
X dn = open(dp, 0);
X if (dn < 0) {
X DELETE(dp);
X DELETE(gp);
X return;
X }
X dname[DIRSIZ] = '\0';
X while ((n = read(dn, (char *)ent, sizeof(ent))) >= sizeof(*ent)) {
X n /= sizeof(*ent);
X for (j=0; j<n; j++) {
X if (ent[j].d_ino == 0)
X continue;
X strncpy(dname, ent[j].d_name, DIRSIZ);
X if (dname[0] == '.')
X if (*gp != '.')
X continue;
X for(k=0; k<DIRSIZ; k++)
X if (any(dname[k], spcl))
X dname[k] |= QUOTE;
X if (gmatch(dname, gp)) {
X name = generate(we, pp, dname, np);
X if (*np && !anys(np, spcl)) {
X if (stat(name,&dbuf)) {
X DELETE(name);
X continue;
X }
X }
X nl = addword(name, nl);
X }
X }
X }
X close(dn);
X DELETE(dp);
X DELETE(gp);
X}
X
X/*
X * generate a pathname as below.
X * start..end1 / middle end
X * the slashes come for free
X */
Xstatic char *
Xgenerate(start1, end1, middle, end)
Xchar *start1;
Xregister char *end1;
Xchar *middle, *end;
X{
X char *p;
X register char *op, *xp;
X
X p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2);
X for (xp = start1; xp != end1;)
X *op++ = *xp++;
X for (xp = middle; (*op++ = *xp++) != '\0';)
X ;
X op--;
X for (xp = end; (*op++ = *xp++) != '\0';)
X ;
X return(p);
X}
X
Xstatic int
Xanyspcl(wb)
Xregister struct wdblock *wb;
X{
X register i;
X register char **wd;
X
X wd = wb->w_words;
X for (i=0; i<wb->w_nword; i++)
X if (anys(spcl, *wd++))
X return(1);
X return(0);
X}
X
Xstatic int
Xxstrcmp(p1, p2)
Xchar *p1, *p2;
X{
X return(strcmp(*(char **)p1, *(char **)p2));
X}
X
X/* -------- word.c -------- */
X/* #include "sh.h" */
X/* #include "word.h" */
Xchar *memcpy();
X
X#define NSTART 16 /* default number of words to allow for initially */
X
Xstruct wdblock *
Xnewword(nw)
Xregister nw;
X{
X register struct wdblock *wb;
X
X wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *));
X wb->w_bsize = nw;
X wb->w_nword = 0;
X return(wb);
X}
X
Xstruct wdblock *
Xaddword(wd, wb)
Xchar *wd;
Xregister struct wdblock *wb;
X{
X register struct wdblock *wb2;
X register nw;
X
X if (wb == NULL)
X wb = newword(NSTART);
X if ((nw = wb->w_nword) >= wb->w_bsize) {
X wb2 = newword(nw * 2);
X memcpy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
X wb2->w_nword = nw;
X DELETE(wb);
X wb = wb2;
X }
X wb->w_words[wb->w_nword++] = wd;
X return(wb);
X}
X
Xchar **
Xgetwords(wb)
Xregister struct wdblock *wb;
X{
X register char **wd;
X register nb;
X
X if (wb == NULL)
X return(NULL);
X if (wb->w_nword == 0) {
X DELETE(wb);
X return(NULL);
X }
X wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
X memcpy((char *)wd, (char *)wb->w_words, nb);
X DELETE(wb); /* perhaps should done by caller */
X return(wd);
X}
X
Xint (*func)();
Xint globv;
X
Xglob0(a0, a1, a2, a3)
Xchar *a0;
Xunsigned a1;
Xint a2;
Xint (*a3)();
X{
X func = a3;
X globv = a2;
X glob1(a0, a0 + a1 * a2);
X}
X
Xglob1(base, lim)
Xchar *base, *lim;
X{
X register char *i, *j;
X int v2;
X char **k;
X char *lptr, *hptr;
X int c;
X unsigned n;
X
X
X v2 = globv;
X
Xtop:
X if ((n=(int)(lim-base)) <= v2)
X return;
X n = v2 * (n / (2*v2));
X hptr = lptr = base+n;
X i = base;
X j = lim-v2;
X for(;;) {
X if (i < lptr) {
X if ((c = (*func)(i, lptr)) == 0) {
X glob2(i, lptr -= v2);
X continue;
X }
X if (c < 0) {
X i += v2;
X continue;
X }
X }
X
Xbegin:
X if (j > hptr) {
X if ((c = (*func)(hptr, j)) == 0) {
X glob2(hptr += v2, j);
X goto begin;
X }
X if (c > 0) {
X if (i == lptr) {
X glob3(i, hptr += v2, j);
X i = lptr += v2;
X goto begin;
X }
X glob2(i, j);
X j -= v2;
X i += v2;
X continue;
X }
X j -= v2;
X goto begin;
X }
X
X
X if (i == lptr) {
X if (lptr-base >= lim-hptr) {
X glob1(hptr+v2, lim);
X lim = lptr;
X } else {
X glob1(base, lptr);
X base = hptr+v2;
X }
X goto top;
X }
X
X
X glob3(j, lptr -= v2, i);
X j = hptr -= v2;
X }
X}
X
Xglob2(i, j)
Xchar *i, *j;
X{
X register char *index1, *index2, c;
X int m;
X
X m = globv;
X index1 = i;
X index2 = j;
X do {
X c = *index1;
X *index1++ = *index2;
X *index2++ = c;
X } while(--m);
X}
X
Xglob3(i, j, k)
Xchar *i, *j, *k;
X{
X register char *index1, *index2, *index3;
X int c;
X int m;
X
X m = globv;
X index1 = i;
X index2 = j;
X index3 = k;
X do {
X c = *index1;
X *index1++ = *index3;
X *index3++ = *index2;
X *index2++ = c;
X } while(--m);
X}
X
Xchar *
Xmemcpy(ato, from, nb)
Xregister char *ato, *from;
Xregister int nb;
X{
X register char *to;
X
X to = ato;
X while (--nb >= 0)
X *to++ = *from++;
X return(ato);
X}
+ END-OF-FILE sh4.c
chmod 'u=rw,g=r,o=r' 'sh4.c'
set `wc -c 'sh4.c'`
count=$1
case $count in
12321) :;;
*) echo 'Bad character count in ''sh4.c' >&2
echo 'Count should be 12321' >&2
esac
echo Extracting 'sh5.c'
sed 's/^X//' > 'sh5.c' << '+ END-OF-FILE ''sh5.c'
X#define Extern extern
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include "sh.h"
X
X/* -------- io.c -------- */
X/* #include "sh.h" */
X
X/*
X * shell IO
X */
X
X
Xint
Xgetc(ec)
Xregister int ec;
X{
X register int c;
X
X if(e.linep > elinep) {
X while((c=readc()) != '\n' && c)
X ;
X err("input line too long");
X gflg++;
X return(c);
X }
X c = readc();
X if (ec != '\'' && ec != '`' && e.iop->task != XGRAVE) {
X if(c == '\\') {
X c = readc();
X if (c == '\n' && ec != '\"')
X return(getc(ec));
X c |= QUOTE;
X }
X }
X return(c);
X}
X
Xvoid
Xunget(c)
X{
X if (e.iop >= e.iobase)
X e.iop->peekc = c;
X}
X
Xint
Xreadc()
X{
X register c;
X static int eofc;
X
X for (; e.iop >= e.iobase; e.iop--)
X if ((c = e.iop->peekc) != '\0') {
X e.iop->peekc = 0;
X return(c);
X } else if ((c = (*e.iop->iofn)(&e.iop->arg, e.iop)) != '\0') {
X if (c == -1) {
X e.iop++;
X continue;
X }
X if (e.iop == iostack)
X ioecho(c);
X return(c);
X }
X if (e.iop >= iostack ||
X multiline && eofc++ < 3)
X return(0);
X leave();
X /* NOTREACHED */
X}
X
Xvoid
Xioecho(c)
Xchar c;
X{
X if (flag['v'])
X write(2, &c, sizeof c);
X}
X
Xvoid
Xpushio(arg, fn)
Xstruct ioarg arg;
Xint (*fn)();
X{
X if (++e.iop >= &iostack[NPUSH]) {
X e.iop--;
X err("Shell input nested too deeply");
X gflg++;
X return;
X }
X e.iop->iofn = fn;
X e.iop->arg = arg;
X e.iop->peekc = 0;
X e.iop->xchar = 0;
X e.iop->nlcount = 0;
X if (fn == filechar || fn == linechar || fn == nextchar)
X e.iop->task = XIO;
X else if (fn == gravechar || fn == qgravechar)
X e.iop->task = XGRAVE;
X else
X e.iop->task = XOTHER;
X}
X
Xstruct io *
Xsetbase(ip)
Xstruct io *ip;
X{
X register struct io *xp;
X
X xp = e.iobase;
X e.iobase = ip;
X return(xp);
X}
X
X/*
X * Input generating functions
X */
X
X/*
X * Produce the characters of a string, then a newline, then EOF.
X */
Xint
Xnlchar(ap)
Xregister struct ioarg *ap;
X{
X register int c;
X
X if (ap->aword == NULL)
X return(0);
X if ((c = *ap->aword++) == 0) {
X ap->aword = NULL;
X return('\n');
X }
X return(c);
X}
X
X/*
X * Given a list of words, produce the characters
X * in them, with a space after each word.
X */
Xint
Xwdchar(ap)
Xregister struct ioarg *ap;
X{
X register char c;
X register char **wl;
X
X if ((wl = ap->awordlist) == NULL)
X return(0);
X if (*wl != NULL) {
X if ((c = *(*wl)++) != 0)
X return(c & 0177);
X ap->awordlist++;
X return(' ');
X }
X ap->awordlist = NULL;
X return('\n');
X}
X
X/*
X * Return the characters of a list of words,
X * producing a space between them.
X */
Xstatic int xxchar(), qqchar();
X
Xint
Xdolchar(ap)
Xregister struct ioarg *ap;
X{
X register char *wp;
X
X if ((wp = *ap->awordlist++) != NULL) {
X PUSHIO(aword, wp, *ap->awordlist == NULL? qqchar: xxchar);
X return(-1);
X }
X return(0);
X}
X
Xstatic int
Xxxchar(ap)
Xregister struct ioarg *ap;
X{
X register int c;
X
X if (ap->aword == NULL)
X return(0);
X if ((c = *ap->aword++) == '\0') {
X ap->aword = NULL;
X return(' ');
X }
X return(c);
X}
X
Xstatic int
Xqqchar(ap)
Xregister struct ioarg *ap;
X{
X register int c;
X
X if (ap->aword == NULL || (c = *ap->aword++) == '\0')
X return(0);
X return(c);
X}
X
X/*
X * Produce the characters from a single word (string).
X */
Xint
Xstrchar(ap)
Xregister struct ioarg *ap;
X{
X register int c;
X
X if (ap->aword == 0 || (c = *ap->aword++) == 0)
X return(0);
X return(c);
X}
X
X/*
X * Return the characters from a file.
X */
Xint
Xfilechar(ap)
Xregister struct ioarg *ap;
X{
X register int i;
X char c;
X extern int errno;
X
X do {
X i = read(ap->afile, &c, sizeof(c));
X } while (i < 0 && errno == EINTR);
X return(i == sizeof(c)? c&0177: (closef(ap->afile), 0));
X}
X
X/*
X * Return the characters from a here temp file.
X */
Xint
Xherechar(ap)
Xregister struct ioarg *ap;
X{
X char c;
X
X
X if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
X close(ap->afile);
X c = 0;
X }
X return (c);
X
X}
X
X/*
X * Return the characters produced by a process (`...`).
X * Quote them if required, and remove any trailing newline characters.
X */
Xint
Xgravechar(ap, iop)
Xstruct ioarg *ap;
Xstruct io *iop;
X{
X register int c;
X
X if ((c = qgravechar(ap, iop)&~QUOTE) == '\n')
X c = ' ';
X return(c);
X}
X
Xint
Xqgravechar(ap, iop)
Xregister struct ioarg *ap;
Xstruct io *iop;
X{
X register int c;
X
X if (iop->xchar) {
X if (iop->nlcount) {
X iop->nlcount--;
X return('\n'|QUOTE);
X }
X c = iop->xchar;
X iop->xchar = 0;
X } else if ((c = filechar(ap)) == '\n') {
X iop->nlcount = 1;
X while ((c = filechar(ap)) == '\n')
X iop->nlcount++;
X iop->xchar = c;
X if (c == 0)
X return(c);
X iop->nlcount--;
X c = '\n';
X }
X return(c!=0? c|QUOTE: 0);
X}
X
X/*
X * Return a single command (usually the first line) from a file.
X */
Xint
Xlinechar(ap)
Xregister struct ioarg *ap;
X{
X register int c;
X
X if ((c = filechar(ap)) == '\n') {
X if (!multiline) {
X closef(ap->afile);
X ap->afile = -1; /* illegal value */
X }
X }
X return(c);
X}
X
X/*
X * Return the next character from the command source,
X * prompting when required.
X */
Xint
Xnextchar(ap)
Xregister struct ioarg *ap;
X{
X register int c;
X
X if ((c = filechar(ap)) != 0)
X return(c);
X if (talking && e.iop <= iostack+1)
X prs(prompt->value);
X return(0);
X}
X
Xvoid
Xprs(s)
Xregister char *s;
X{
X if (*s)
X write(2, s, strlen(s));
X}
X
Xvoid
Xputc(c)
Xchar c;
X{
X write(2, &c, sizeof c);
X}
X
Xvoid
Xprn(u)
Xunsigned u;
X{
X prs(itoa(u, 0));
X}
X
Xvoid
Xclosef(i)
Xregister i;
X{
X if (i > 2)
X close(i);
X}
X
Xvoid
Xcloseall()
X{
X register u;
X
X for (u=NUFILE; u<NOFILE;)
X close(u++);
X}
X
X/*
X * remap fd into Shell's fd space
X */
Xint
Xremap(fd)
Xregister int fd;
X{
X register int i;
X int map[NOFILE];
X
X if (fd < e.iofd) {
X for (i=0; i<NOFILE; i++)
X map[i] = 0;
X do {
X map[fd] = 1;
X fd = dup(fd);
X } while (fd >= 0 && fd < e.iofd);
X for (i=0; i<NOFILE; i++)
X if (map[i])
X close(i);
X if (fd < 0)
X err("too many files open in shell");
X }
X return(fd);
X}
X
Xint
Xopenpipe(pv)
Xregister int *pv;
X{
X register int i;
X
X if ((i = pipe(pv)) < 0)
X err("can't create pipe - try again");
X return(i);
X}
X
Xvoid
Xclosepipe(pv)
Xregister int *pv;
X{
X if (pv != NULL) {
X close(*pv++);
X close(*pv);
X }
X}
X
X/* -------- here.c -------- */
X/* #include "sh.h" */
X
X/*
X * here documents
X */
X
Xstruct here {
X char *h_tag;
X int h_dosub;
X struct ioword *h_iop;
X struct here *h_next;
X};
X
Xstatic struct here *inhere; /* list of hear docs while parsing */
Xstatic struct here *acthere; /* list of active here documents */
X
Xstatic char *readhere();
X
X#define NCPB 100 /* here text block allocation unit */
X
Xmarkhere(s, iop)
Xregister char *s;
Xstruct ioword *iop;
X{
X register struct here *h, *lh;
X
X h = (struct here *) space(sizeof(struct here));
X if (h == 0)
X return;
X h->h_tag = evalstr(s, DOSUB);
X if (h->h_tag == 0)
X return;
X h->h_iop = iop;
X h->h_next = NULL;
X if (inhere == 0)
X inhere = h;
X else
X for (lh = inhere; lh!=NULL; lh = lh->h_next)
X if (lh->h_next == 0) {
X lh->h_next = h;
X break;
X }
X iop->io_flag |= IOHERE|IOXHERE;
X for (s = h->h_tag; *s; s++)
X if (*s & QUOTE) {
X iop->io_flag &= ~ IOXHERE;
X *s &= ~ QUOTE;
X }
X h->h_dosub = iop->io_flag & IOXHERE;
X}
X
Xgethere()
X{
X register struct here *h;
X
X for (h = inhere; h != NULL; h = inhere) {
X h->h_iop->io_name = readhere(h->h_tag, h->h_dosub? 0: '\'');
X /* relink from inhere to acthere list */
X inhere = h->h_next;
X h->h_next = acthere;
X acthere = h;
X }
X inhere = h;
X}
X
Xstatic char *
Xreadhere(s, ec)
Xregister char *s;
X{
X int tf;
X char tname[30];
X register c;
X jmp_buf ev;
X char line [LINELIM+1];
X char *next;
X
X tempname(tname);
X tf = creat(tname, 0600);
X if (tf < 0)
X return (0);
X if (newenv(setjmp(errpt = ev)) != 0)
X return (0);
X if (e.iop == iostack && e.iop->iofn == filechar) {
X pushio(e.iop->arg, filechar);
X e.iobase = e.iop;
X }
X for (;;) {
X if (talking && e.iop <= iostack)
X prs(cprompt->value);
X next = line;
X while ((c = getc(ec)) != '\n' && c) {
X if (ec == '\'')
X c &= ~ QUOTE;
X if (next >= &line[LINELIM]) {
X c = 0;
X break;
X }
X *next++ = c;
X }
X *next = 0;
X if (strcmp(s, line) == 0 || c == 0)
X break;
X *next++ = '\n';
X write (tf, line, (int)(next-line));
X }
X if (c == 0) {
X prs("here document `"); prs(s); err("' unclosed");
X }
X close(tf);
X quitenv();
X /* correct area? */
X return (strsave(tname, areanum));
X}
X
X/*
X * open here temp file.
X * if unquoted here, expand here temp file into second temp file.
X */
Xherein(hname, xdoll)
Xchar *hname;
X{
X register hf, tf;
X
X if (hname == 0)
X return(-1);
X hf = open(hname, 0);
X if (hf < 0)
X return (-1);
X if (xdoll) {
X char c;
X char tname[30];
X jmp_buf ev;
X
X tempname(tname);
X if ((tf = creat(tname, 0600)) < 0)
X return (-1);
X if (newenv(setjmp(errpt = ev)) == 0) {
X PUSHIO(afile, hf, herechar);
X setbase(e.iop);
X while ((c = subgetc(0, 0)) != 0) {
X c &= ~ QUOTE;
X write(tf, &c, sizeof c);
X }
X quitenv();
X } else
X unlink(tname);
X close(tf);
X tf = open(tname, 0);
X unlink(tname);
X return (tf);
X } else
X return (hf);
X}
X
Xscraphere()
X{
X inhere = NULL;
X}
X
X/* unlink here temp files before a freearea(area) */
Xfreehere(area)
Xint area;
X{
X register struct here *h, *hl;
X
X hl = NULL;
X for (h = acthere; h != NULL; hl = h, h = h->h_next)
X if (getarea(h) >= area) {
X if (h->h_iop->io_name != NULL)
X unlink(h->h_iop->io_name);
X if (hl == NULL)
X acthere = h->h_next;
X else
X hl->h_next = h->h_next;
X }
X}
X
Xtempname(tname)
Xchar *tname;
X{
X static int inc;
X register char *cp, *lp;
X
X for (cp = tname, lp = "/tmp/shtm"; (*cp = *lp++) != '\0'; cp++)
X ;
X lp = putn(getpid()*1000 + inc++);
X for (; (*cp = *lp++) != '\0'; cp++)
X ;
X}
+ END-OF-FILE sh5.c
chmod 'u=rw,g=r,o=r' 'sh5.c'
set `wc -c 'sh5.c'`
count=$1
case $count in
9258) :;;
*) echo 'Bad character count in ''sh5.c' >&2
echo 'Count should be 9258' >&2
esac
echo Extracting 'sh6.c'
sed 's/^X//' > 'sh6.c' << '+ END-OF-FILE ''sh6.c'
X#define Extern
X
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include "sh.h"
X
+ END-OF-FILE sh6.c
chmod 'u=rw,g=r,o=r' 'sh6.c'
set `wc -c 'sh6.c'`
count=$1
case $count in
92) :;;
*) echo 'Bad character count in ''sh6.c' >&2
echo 'Count should be 92' >&2
esac
exit 0