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