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 'makefile' sed 's/^X//' > 'makefile' << '+ END-OF-FILE ''makefile' XCFLAGS=-F Xl=/lib X Xshobj = sh1.s sh2.s sh3.s sh4.s sh5.s sh6.s Xsh: $(shobj) sh.h X @cc -i -o sh -T. $(shobj) X @chmem =13000 sh X + END-OF-FILE makefile chmod 'u=rw,g=r,o=r' 'makefile' set `wc -c 'makefile'` count=$1 case $count in 127) :;; *) echo 'Bad character count in ''makefile' >&2 echo 'Count should be 127' >&2 esac echo Extracting 'sh.h' sed 's/^X//' > 'sh.h' << '+ END-OF-FILE ''sh.h' X/* -------- sh.h -------- */ X/* X * shell X */ X X#define NULL 0 X#define LINELIM 1000 X#define NPUSH 8 /* limit to input nesting */ X X#define NOFILE 20 /* Number of open files */ X#define NUFILE 10 /* Number of user-accessible files */ X#define FDBASE 10 /* First file usable by Shell */ X X/* X * values returned by wait X */ X#define WAITSIG(s) ((s)&0177) X#define WAITVAL(s) (((s)>>8)&0377) X#define WAITCORE(s) (((s)&0200)!=0) X X/* X * library and system defintions X */ Xtypedef int xint; /* base type of jmp_buf, for broken compilers */ X X/* X * shell components X */ X/* #include "area.h" */ X/* #include "word.h" */ X/* #include "io.h" */ X/* #include "var.h" */ X X#define QUOTE 0200 X X#define NOBLOCK ((struct op *)NULL) X#define NOWORD ((char *)NULL) X#define NOWORDS ((char **)NULL) X#define NOPIPE ((int *)NULL) X X/* X * Description of a command or an operation on commands. X * Might eventually use a union. X */ Xstruct op { X int type; /* operation type, see below */ X char **words; /* arguments to a command */ X struct ioword **ioact; /* IO actions (eg, < > >>) */ X struct op *left; X struct op *right; X char *str; /* identifier for case and for */ X}; X X#define TCOM 1 /* command */ X#define TPAREN 2 /* (c-list) */ X#define TPIPE 3 /* a | b */ X#define TLIST 4 /* a [&;] b */ X#define TOR 5 /* || */ X#define TAND 6 /* && */ X#define TFOR 7 X#define TDO 8 X#define TCASE 9 X#define TIF 10 X#define TWHILE 11 X#define TUNTIL 12 X#define TELIF 13 X#define TPAT 14 /* pattern in case */ X#define TBRACE 15 /* {c-list} */ X#define TASYNC 16 /* c & */ X X/* X * actions determining the environment of a process X */ X#define BIT(i) (1<<(i)) X#define FEXEC BIT(0) /* execute without forking */ X X/* X * flags to control evaluation of words X */ X#define DOSUB 1 /* interpret $, `, and quotes */ X#define DOBLANK 2 /* perform blank interpretation */ X#define DOGLOB 4 /* interpret [?* */ X#define DOKEY 8 /* move words with `=' to 2nd arg. list */ X#define DOTRIM 16 /* trim resulting string */ X X#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) X XExtern char **dolv; XExtern int dolc; XExtern int exstat; XExtern char gflg; XExtern int talking; /* interactive (talking-type wireless) */ XExtern int execflg; XExtern int multiline; /* \n changed to ; */ XExtern struct op *outtree; /* result from parser */ X XExtern xint *failpt; XExtern xint *errpt; X Xstruct brkcon { X jmp_buf brkpt; X struct brkcon *nextlev; X} ; XExtern struct brkcon *brklist; XExtern int isbreak; X X/* X * redirection X */ Xstruct ioword { X short io_unit; /* unit affected */ X short io_flag; /* action (below) */ X char *io_name; /* file name */ X}; X#define IOREAD 1 /* < */ X#define IOHERE 2 /* << (here file) */ X#define IOWRITE 4 /* > */ X#define IOCAT 8 /* >> */ X#define IOXHERE 16 /* ${}, ` in << */ X#define IODUP 32 /* >&digit */ X#define IOCLOSE 64 /* >&- */ X X#define IODEFAULT (-1) /* token for default IO unit */ X XExtern struct wdblock *wdlist; XExtern struct wdblock *iolist; X X/* X * parsing & execution environment X */ Xextern struct env { X char *linep; X struct io *iobase; X struct io *iop; X xint *errpt; X int iofd; X struct env *oenv; X} e; X X/* X * flags: X * -e: quit on error X * -k: look for name=value everywhere on command line X * -n: no execution X * -t: exit after reading and executing one command X * -v: echo as read X * -x: trace X * -u: unset variables net diagnostic X */ Xextern char *flag; X Xextern char *null; /* null value for variable */ Xextern int intr; /* interrupt pending */ X XExtern char *trap[NSIG]; XExtern char ourtrap[NSIG]; XExtern int trapset; /* trap pending */ X Xextern int inword; /* defer traps and interrupts */ X XExtern int yynerrs; /* yacc */ X XExtern char line[LINELIM]; Xextern char *elinep; X X/* X * other functions X */ Xint (*inbuilt())(); /* find builtin command */ Xchar *rexecve(); Xchar *space(); Xchar *getwd(); Xchar *strsave(); Xchar *evalstr(); Xchar *putn(); Xchar *itoa(); Xchar *unquote(); Xstruct var *lookup(); Xstruct wdblock *add2args(); Xstruct wdblock *glob(); Xchar **makenv(); Xstruct ioword *addio(); Xchar **eval(); Xint setstatus(); Xint waitfor(); X Xint onintr(); /* SIGINT handler */ X X/* X * error handling X */ Xvoid leave(); /* abort shell (or fail in subshell) */ Xvoid fail(); /* fail but return to process next command */ Xint sig(); /* default signal handler */ X X/* X * library functions and system calls X */ Xlong lseek(); Xchar *strncpy(); Xint strlen(); Xextern int errno; X X/* -------- var.h -------- */ X Xstruct var { X char *value; X char *name; X struct var *next; X char status; X}; X#define COPYV 1 /* flag to setval, suggesting copy */ X#define RONLY 01 /* variable is read-only */ X#define EXPORT 02 /* variable is to be exported */ X#define GETCELL 04 /* name & value space was got with getcell */ X XExtern struct var *vlist; /* dictionary */ X XExtern struct var *homedir; /* home directory */ XExtern struct var *prompt; /* main prompt */ XExtern struct var *cprompt; /* continuation prompt */ XExtern struct var *path; /* search path for commands */ XExtern struct var *shell; /* shell to interpret command files */ XExtern struct var *ifs; /* field separators */ X Xstruct var *lookup(/* char *s */); Xvoid setval(/* struct var *, char * */); Xvoid nameval(/* struct var *, char *val, *name */); Xvoid export(/* struct var * */); Xvoid ronly(/* struct var * */); Xint isassign(/* char *s */); Xint checkname(/* char *name */); Xint assign(/* char *s, int copyflag */); Xvoid putvlist(/* int key, int fd */); Xint eqname(/* char *n1, char *n2 */); X X/* -------- io.h -------- */ X/* possible arguments to an IO function */ Xstruct ioarg { X char *aword; X char **awordlist; X int afile; /* file descriptor */ X}; X X/* an input generator's state */ Xstruct io { X int (*iofn)(); X struct ioarg arg; X int peekc; X char nlcount; /* for `'s */ X char xchar; /* for `'s */ X char task; /* reason for pushed IO */ X}; XExtern struct io iostack[NPUSH]; X#define XOTHER 0 /* none of the below */ X#define XDOLL 1 /* expanding ${} */ X#define XGRAVE 2 /* expanding `'s */ X#define XIO 3 /* file IO */ X X/* in substitution */ X#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL) X X/* X * input generators for IO structure X */ Xint nlchar(); Xint strchar(); Xint filechar(); Xint herechar(); Xint linechar(); Xint nextchar(); Xint gravechar(); Xint qgravechar(); Xint dolchar(); Xint wdchar(); X X/* X * IO functions X */ Xint getc(); Xint readc(); Xvoid unget(); Xvoid ioecho(); Xvoid prs(); Xvoid putc(); Xvoid prn(); Xvoid closef(); Xvoid closeall(); X X/* X * IO control X */ Xvoid pushio(/* struct ioarg arg, int (*gen)() */); Xint remap(); Xint openpipe(); Xvoid closepipe(); Xstruct io *setbase(/* struct io * */); X XExtern struct ioarg temparg; /* temporary for PUSHIO */ X#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(temparg,(gen))) X#define RUN(what,arg,gen) ((temparg.what = (arg)), run(temparg,(gen))) X X/* -------- word.h -------- */ X#ifndef WORD_H X#define WORD_H 1 Xstruct wdblock { X short w_bsize; X short w_nword; X /* bounds are arbitrary */ X char *w_words[1]; X}; X Xstruct wdblock *addword(); Xstruct wdblock *newword(); Xchar **getwords(); X#endif X X/* -------- area.h -------- */ X X/* X * storage allocation X */ Xchar *getcell(/* unsigned size */); Xvoid garbage(); Xvoid setarea(/* char *obj, int to */); Xint getarea(/* char *obj */); Xvoid freearea(/* int area */); Xvoid freecell(/* char *obj */); X XExtern int areanum; /* current allocation area */ X X#define NEW(type) (type *)getcell(sizeof(type)) X#define DELETE(obj) freecell((char *)obj) X + END-OF-FILE sh.h chmod 'u=rw,g=r,o=r' 'sh.h' set `wc -c 'sh.h'` count=$1 case $count in 7321) :;; *) echo 'Bad character count in ''sh.h' >&2 echo 'Count should be 7321' >&2 esac echo Extracting 'sh1.c' sed 's/^X//' > 'sh1.c' << '+ END-OF-FILE ''sh1.c' X#define Extern extern X#include <signal.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X/* -------- sh.c -------- */ X/* X * shell X */ X X/* #include "sh.h" */ X Xint intr; Xint inparse; Xchar flags['z'-'a'+1]; Xchar *flag = flags-'a'; Xchar *elinep = line+sizeof(line)-5; Xchar *null = ""; Xint inword =1; Xstruct env e ={line, iostack, iostack-1, NULL, FDBASE, NULL}; X Xextern char **environ; /* environment pointer */ X X/* X * default shell, search rules X */ Xchar shellname[] = "/bin/sh"; Xchar search[] = ":/bin:/usr/bin"; X Xint (*qflag)() = SIG_IGN; X Xmain(argc, argv) Xint argc; Xregister char **argv; X{ X register int f; X register char *s; X int cflag; X char *name, **ap; X int (*iof)(); X X initarea(); X if ((ap = environ) != NULL) { X while (*ap) X assign(*ap++, !COPYV); X for (ap = environ; *ap;) X export(lookup(*ap++)); X } X closeall(); X areanum = 1; X X shell = lookup("SHELL"); X if (shell->value == null) X setval(shell, shellname); X export(shell); X X homedir = lookup("HOME"); X if (homedir->value == null) X setval(homedir, "/"); X export(homedir); X X setval(lookup("$"), itoa(getpid(), 5)); X X path = lookup("PATH"); X if (path->value == null) X setval(path, search); X export(path); X X ifs = lookup("IFS"); X if (ifs->value == null) X setval(ifs, " \t\n"); X X prompt = lookup("PS1"); X if (prompt->value == null) X#ifndef UNIXSHELL X setval(prompt, "$ "); X#else X setval(prompt, "% "); X#endif X if (geteuid() == 0) { X setval(prompt, "# "); X prompt->status &= ~EXPORT; X } X cprompt = lookup("PS2"); X if (cprompt->value == null) X setval(cprompt, "> "); X X iof = filechar; X cflag = 0; X name = *argv++; X if (--argc >= 1) { X if(argv[0][0] == '-' && argv[0][1] != '\0') { X for (s = argv[0]+1; *s; s++) X switch (*s) { X case 'c': X prompt->status &= ~EXPORT; X cprompt->status &= ~EXPORT; X setval(prompt, ""); X setval(cprompt, ""); X cflag = 1; X if (--argc > 0) X PUSHIO(aword, *++argv, iof = nlchar); X break; X X case 'q': X qflag = SIG_DFL; X break; X X case 's': X /* standard input */ X break; X X case 't': X prompt->status &= ~EXPORT; X setval(prompt, ""); X iof = linechar; X break; X X case 'i': X talking++; X default: X if (*s>='a' && *s<='z') X flag[*s]++; X } X } else { X argv--; X argc++; X } X if (iof == filechar && --argc > 0) { X setval(prompt, ""); X setval(cprompt, ""); X prompt->status &= ~EXPORT; X cprompt->status &= ~EXPORT; X if (newfile(*++argv)) X exit(1); X } X } X setdash(); X if (e.iop < iostack) { X PUSHIO(afile, 0, iof); X if (isatty(0) && isatty(1) && !cflag) X talking++; X } X signal(SIGQUIT, qflag); X if (name && name[0] == '-') { X talking++; X if ((f = open("/etc/profile", 0)) >= 0) X next(remap(f)); X if ((f = open(".profile", 0)) >= 0) X next(remap(f)); X } X if (talking) { X signal(SIGTERM, sig); X signal(SIGINT, SIG_IGN); X } X dolv = argv; X dolc = argc; X dolv[0] = name; X if (dolc > 1) X for (ap = ++argv; --argc > 0;) X if (assign(*ap = *argv++, !COPYV)) X dolc--; /* keyword */ X else X ap++; X setval(lookup("#"), putn(--dolc)); X X for (;;) { X if (talking && e.iop <= iostack) X prs(prompt->value); X onecommand(); X } X} X Xsetdash() X{ X register char *cp, c; X char m['z'-'a'+1]; X X cp = m; X for (c='a'; c<='z'; c++) X if (flag[c]) X *cp++ = c; X *cp = 0; X setval(lookup("-"), m); X} X Xnewfile(s) Xregister char *s; X{ X register f; X X if (strcmp(s, "-") != 0) { X f = open(s, 0); X if (f < 0) { X prs(s); X err(": cannot open"); X return(1); X } X } else X f = 0; X next(remap(f)); X return(0); X} X Xonecommand() X{ X register i; X jmp_buf m1; X X inword++; X while (e.oenv) X quitenv(); X areanum = 1; X freehere(areanum); X freearea(areanum); X garbage(); X wdlist = 0; X iolist = 0; X e.errpt = 0; X e.linep = line; X yynerrs = 0; X multiline = 0; X inparse = 1; X setjmp(failpt = m1); /* Bruce Evans' fix */ X if (talking) X signal(SIGINT, onintr); X if (setjmp(failpt = m1) || yyparse() || intr) { X while (e.oenv) X quitenv(); X scraphere(); X inparse = 0; X intr = 0; X return; X } X inparse = 0; X inword = 0; X if ((i = trapset) != 0) { X trapset = 0; X runtrap(i); X } X brklist = 0; X intr = 0; X execflg = 0; X if (!flag['n']) { X if (talking) X signal(SIGINT, onintr); X execute(outtree, NOPIPE, NOPIPE, 0); X intr = 0; X if (talking) X signal(SIGINT, SIG_IGN); X } X} X Xvoid Xfail() X{ X longjmp(failpt, 1); X /* NOTREACHED */ X} X Xvoid Xleave() X{ X if (execflg) X fail(); X runtrap(0); X sync(); X exit(exstat); X /* NOTREACHED */ X} X Xwarn(s) Xregister char *s; X{ X if(*s) { X prs(s); X exstat = -1; X } X prs("\n"); X if (flag['e']) X leave(); X} X Xerr(s) Xchar *s; X{ X warn(s); X if (flag['n']) X return; X if (!talking) X leave(); X if (e.errpt) X longjmp(e.errpt, 1); X closeall(); X e.iop = e.iobase = iostack; X} X Xnewenv(f) X{ X register struct env *ep; X X if (f) { X quitenv(); X return(1); X } X ep = (struct env *) space(sizeof(*ep)); X if (ep == NULL) { X while (e.oenv) X quitenv(); X fail(); X } X *ep = e; X e.oenv = ep; X e.errpt = errpt; X return(0); X} X Xquitenv() X{ X register struct env *ep; X register fd; X X if ((ep = e.oenv) != NULL) { X fd = e.iofd; X e = *ep; X /* should close `'d files */ X DELETE(ep); X while (--fd >= e.iofd) X close(fd); X } X} X X/* X * Is any character from s1 in s2? X */ Xint Xanys(s1, s2) Xregister char *s1, *s2; X{ X while (*s1) X if (any(*s1++, s2)) X return(1); X return(0); X} X X/* X * Is character c in s? X */ Xint Xany(c, s) Xregister int c; Xregister char *s; X{ X while (*s) X if (*s++ == c) X return(1); X return(0); X} X Xchar * Xputn(n) Xregister n; X{ X return(itoa(n, -1)); X} X Xchar * Xitoa(u, n) Xregister unsigned u; X{ X register char *cp; X static char s[20]; X int m; X X m = 0; X if (n < 0 && (int) u < 0) { X m++; X u = -u; X } X cp = s+sizeof(s); X *--cp = 0; X do { X *--cp = u%10 + '0'; X u /= 10; X } while (--n > 0 || u); X if (m) X *--cp = '-'; X return(cp); X} X Xnext(f) X{ X PUSHIO(afile, f, nextchar); X} X Xonintr() X{ X signal(SIGINT, SIG_IGN); X if (inparse) { X prs("\n"); X fail(); X } X intr++; X} X Xletter(c) Xregister c; X{ X return(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); X} X Xdigit(c) Xregister c; X{ X return(c >= '0' && c <= '9'); X} X Xletnum(c) Xregister c; X{ X return(letter(c) || digit(c)); X} X Xchar * Xspace(n) Xint n; X{ X register char *cp; X X inword++; X if ((cp = getcell(n)) == 0) X err("out of string space"); X inword--; X return(cp); X} X Xchar * Xstrsave(s, a) Xregister char *s; X{ X register char *cp, *xp; X X if ((cp = space(strlen(s)+1)) != NULL) { X setarea((char *)cp, a); X for (xp = cp; (*xp++ = *s++) != '\0';) X ; X return(cp); X } X return(""); X} X X/* X * if inword is set, traps X * are delayed, avoiding X * having two people allocating X * at once. X */ Xxfree(s) Xregister char *s; X{ X inword++; X DELETE(s); X inword--; X} X X/* X * trap handling X */ Xsig(i) Xregister i; X{ X if (inword == 0) { X signal(i, SIG_IGN); X runtrap(i); X } else X trapset = i; X signal(i, sig); X} X Xruntrap(i) X{ X char *trapstr; X X if ((trapstr = trap[i]) == NULL) X return; X if (i == 0) X trap[i] = 0; X RUN(aword, trapstr, nlchar); X} X X/* -------- var.c -------- */ X/* #include "sh.h" */ X Xstatic char *findeq(); X X/* X * Find the given name in the dictionary X * and return its value. If the name was X * not previously there, enter it now and X * return a null value. X */ Xstruct var * Xlookup(n) Xregister char *n; X{ X register struct var *vp; X register char *cp; X register int c; X static struct var dummy; X X if (digit(*n)) { X dummy.name = n; X for (c = 0; digit(*n) && c < 1000; n++) X c = c*10 + *n-'0'; X dummy.status = RONLY; X dummy.value = c <= dolc? dolv[c]: null; X return(&dummy); X } X for (vp = vlist; vp; vp = vp->next) X if (eqname(vp->name, n)) X return(vp); X cp = findeq(n); X vp = (struct var *)space(sizeof(*vp)); X if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) { X dummy.name = dummy.value = ""; X return(&dummy); X } X for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++) X ; X if (*cp == 0) X *cp = '='; X *++cp = 0; X setarea((char *)vp, 0); X setarea((char *)vp->name, 0); X vp->value = null; X vp->next = vlist; X vp->status = GETCELL; X vlist = vp; X return(vp); X} X X/* X * give variable at `vp' the value `val'. X */ Xvoid Xsetval(vp, val) Xstruct var *vp; Xchar *val; X{ X nameval(vp, val, (char *)NULL); X} X X/* X * if name is not NULL, it must be X * a prefix of the space `val', X * and end with `='. X * this is all so that exporting X * values is reasonably painless. X */ Xvoid Xnameval(vp, val, name) Xregister struct var *vp; Xchar *val, *name; X{ X register char *cp, *xp; X char *nv; X int fl; X X if (vp->status & RONLY) { X for (xp = vp->name; *xp && *xp != '=';) X putc(*xp++); X err(" is read-only"); X return; X } X fl = 0; X if (name == NULL) { X xp = space(strlen(vp->name)+strlen(val)+2); X if (xp == 0) X return; X /* make string: name=value */ X setarea((char *)xp, 0); X name = xp; X for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++) X ; X if (*xp++ == 0) X xp[-1] = '='; X nv = xp; X for (cp = val; (*xp++ = *cp++) != '\0';) X ; X val = nv; X fl = GETCELL; X } X if (vp->status & GETCELL) X xfree(vp->name); /* form new string `name=value' */ X vp->name = name; X vp->value = val; X vp->status |= fl; X} X Xvoid Xexport(vp) Xstruct var *vp; X{ X vp->status |= EXPORT; X} X Xvoid Xronly(vp) Xstruct var *vp; X{ X if (letter(vp->name[0])) /* not an internal symbol ($# etc) */ X vp->status |= RONLY; X} X Xint Xisassign(s) Xregister char *s; X{ X if (!letter(*s)) X return(0); X for (; *s != '='; s++) X if (*s == 0 || !letnum(*s)) X return(0); X return(1); X} X Xint Xassign(s, cf) Xregister char *s; Xint cf; X{ X register char *cp; X struct var *vp; X X if (!letter(*s)) X return(0); X for (cp = s; *cp != '='; cp++) X if (*cp == 0 || !letnum(*cp)) X return(0); X vp = lookup(s); X nameval(vp, ++cp, cf == COPYV? NULL: s); X if (cf != COPYV) X vp->status &= ~GETCELL; X return(1); X} X Xint Xcheckname(cp) Xregister char *cp; X{ X if (!letter(*cp++)) X return(0); X while (*cp) X if (!letnum(*cp++)) X return(0); X return(1); X} X Xvoid Xputvlist(f, out) Xregister int f, out; X{ X register struct var *vp; X X for (vp = vlist; vp; vp = vp->next) X if (vp->status & f && letter(*vp->name)) { X if (vp->status & EXPORT) X write(out, "export ", 7); X if (vp->status & RONLY) X write(out, "readonly ", 9); X write(out, vp->name, (int)(findeq(vp->name) - vp->name)); X write(out, "\n", 1); X } X} X Xint Xeqname(n1, n2) Xregister char *n1, *n2; X{ X for (; *n1 != '=' && *n1 != 0; n1++) X if (*n2++ != *n1) X return(0); X return(*n2 == 0 || *n2 == '='); X} X Xstatic char * Xfindeq(cp) Xregister char *cp; X{ X while (*cp != '\0' && *cp != '=') X cp++; X return(cp); X} X X/* -------- gmatch.c -------- */ X/* X * int gmatch(string, pattern) X * char *string, *pattern; X * X * Match a pattern as in sh(1). X */ X X#define NULL 0 X#define CMASK 0377 X#define QUOTE 0200 X#define QMASK (CMASK&~QUOTE) X#define NOT '!' /* might use ^ */ X Xstatic char *cclass(); X Xint Xgmatch(s, p) Xregister char *s, *p; X{ X register int sc, pc; X X if (s == NULL || p == NULL) X return(0); X while ((pc = *p++ & CMASK) != '\0') { X sc = *s++ & QMASK; X switch (pc) { X case '[': X if ((p = cclass(p, sc)) == NULL) X return(0); X break; X X case '?': X if (sc == 0) X return(0); X break; X X case '*': X s--; X do { X if (*p == '\0' || gmatch(s, p)) X return(1); X } while (*s++ != '\0'); X return(0); X X default: X if (sc != (pc&~QUOTE)) X return(0); X } X } X return(*s == 0); X} X Xstatic char * Xcclass(p, sub) Xregister char *p; Xregister int sub; X{ X register int c, d, not, found; X X if ((not = *p == NOT) != 0) X p++; X found = not; X do { X if (*p == '\0') X return(NULL); X c = *p & CMASK; X if (p[1] == '-' && p[2] != ']') { X d = p[2] & CMASK; X p++; X } else X d = c; X if (c == sub || c <= sub && sub <= d) X found = !not; X } while (*++p != ']'); X return(found? p+1: NULL); X} X X/* -------- area.c -------- */ X#define REGSIZE sizeof(struct region) X#define GROWBY 256 X#undef SHRINKBY 64 X#define FREE 32767 X#define BUSY 0 X#define ALIGN (sizeof(int)-1) X X/* #include "area.h" */ X#define NULL 0 X Xstruct region { X struct region *next; X int area; X}; X X/* X * All memory between (char *)areabot and (char *)(areatop+1) is X * exclusively administered by the area management routines. X * It is assumed that sbrk() and brk() manipulate the high end. X */ Xstatic struct region *areabot; /* bottom of area */ Xstatic struct region *areatop; /* top of area */ Xstatic struct region *areanxt; /* starting point of scan */ Xchar *sbrk(); Xchar *brk(); X Xinitarea() X{ X while ((int)sbrk(0) & ALIGN) X sbrk(1); X areabot = (struct region *)sbrk(REGSIZE); X areabot->next = areabot; X areabot->area = BUSY; X areatop = areabot; X areanxt = areabot; X} X Xchar * Xgetcell(nbytes) Xunsigned nbytes; X{ X register int nregio; X register struct region *p, *q; X register i; X X if (nbytes == 0) X abort(); /* silly and defeats the algorithm */ X /* X * round upwards and add administration area X */ X nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1; X for (p = areanxt;;) { X if (p->area > areanum) { X /* X * merge free cells X */ X while ((q = p->next)->area > areanum) X p->next = q->next; X /* X * exit loop if cell big enough X */ X if (q >= p + nregio) X goto found; X } X p = p->next; X if (p == areanxt) X break; X } X i = nregio >= GROWBY ? nregio : GROWBY; X p = (struct region *)sbrk(i * REGSIZE); X if ((int)p == -1) X return(NULL); X p--; X if (p != areatop) X abort(); /* allocated areas are contiguous */ X q = p + i; X p->next = q; X p->area = FREE; X q->next = areabot; X q->area = BUSY; X areatop = q; Xfound: X /* X * we found a FREE area big enough, pointed to by 'p', and up to 'q' X */ X areanxt = p + nregio; X if (areanxt < q) { X /* X * split into requested area and rest X */ X if (areanxt+1 > q) X abort(); /* insufficient space left for admin */ X areanxt->next = q; X areanxt->area = FREE; X p->next = areanxt; X } X p->area = areanum; X return((char *)(p+1)); X} X Xvoid Xfreecell(cp) Xchar *cp; X{ X register struct region *p; X X if ((p = (struct region *)cp) != NULL) { X p--; X if (p < areanxt) X areanxt = p; X p->area = FREE; X } X} X Xvoid Xfreearea(a) Xregister int a; X{ X register struct region *p, *top; X X top = areatop; X for (p = areabot; p != top; p = p->next) X if (p->area >= a) X p->area = FREE; X} X Xvoid Xsetarea(cp,a) Xchar *cp; Xint a; X{ X register struct region *p; X X if ((p = (struct region *)cp) != NULL) X (p-1)->area = a; X} X Xint Xgetarea(cp) Xchar *cp; X{ X return ((struct region*)cp-1)->area; X} X Xvoid Xgarbage() X{ X register struct region *p, *q, *top; X X top = areatop; X for (p = areabot; p != top; p = p->next) { X if (p->area > areanum) { X while ((q = p->next)->area > areanum) X p->next = q->next; X areanxt = p; X } X } X#ifdef SHRINKBY X if (areatop >= q + SHRINKBY && q->area > areanum) { X brk((char *)(q+1)); X q->next = areabot; X q->area = BUSY; X areatop = q; X } X#endif X} + END-OF-FILE sh1.c chmod 'u=rw,g=r,o=r' 'sh1.c' set `wc -c 'sh1.c'` count=$1 case $count in 14561) :;; *) echo 'Bad character count in ''sh1.c' >&2 echo 'Count should be 14561' >&2 esac echo Extracting 'sh2.c' sed 's/^X//' > 'sh2.c' << '+ END-OF-FILE ''sh2.c' X#define Extern extern X#include <signal.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X X/* -------- csyn.c -------- */ X/* X * shell: syntax (C version) X */ X Xtypedef union { X char *cp; X char **wp; X int i; X struct op *o; X} YYSTYPE; X#define WORD 256 X#define LOGAND 257 X#define LOGOR 258 X#define BREAK 259 X#define IF 260 X#define THEN 261 X#define ELSE 262 X#define ELIF 263 X#define FI 264 X#define CASE 265 X#define ESAC 266 X#define FOR 267 X#define WHILE 268 X#define UNTIL 269 X#define DO 270 X#define DONE 271 X#define IN 272 X#define YYERRCODE 300 X X/* flags to yylex */ X#define CONTIN 01 /* skip new lines to complete command */ X X/* #include "sh.h" */ X#define SYNTAXERR zzerr() Xstatic int startl = 1; Xstatic int peeksym = 0; Xstatic void zzerr(); Xstatic void word(); Xstatic char **copyw(); Xstatic struct op *block(), *namelist(), *list(), *newtp(); Xstatic struct op *pipeline(), *andor(), *command(); Xstatic struct op *nested(), *simple(), *c_list(); Xstatic struct op *dogroup(), *thenpart(), *casepart(), *caselist(); Xstatic struct op *elsepart(); Xstatic char **wordlist(), **pattern(); Xstatic void musthave(); Xstatic int yylex(); Xstatic struct ioword *io(); Xstatic struct ioword **copyio(); Xstatic char *tree(); Xstatic void diag(); Xstatic int nlseen; Xstatic int iounit = IODEFAULT; Xstatic struct op *tp; Xstruct op *newtp(); X Xstatic YYSTYPE yylval; X Xint Xyyparse() X{ X peeksym = 0; X yynerrs = 0; X outtree = c_list(); X musthave('\n', 0); X return(yynerrs!=0); X} X Xstatic struct op * Xpipeline(cf) Xint cf; X{ X register struct op *t, *p; X register int c; X X t = command(cf); X if (t != NULL) { X while ((c = yylex(0)) == '|') { X if ((p = command(CONTIN)) == NULL) X SYNTAXERR; X if (t->type != TPAREN && t->type != TCOM) { X /* shell statement */ X t = block(TPAREN, t, NOBLOCK, NOWORDS); X } X t = block(TPIPE, t, p, NOWORDS); X } X peeksym = c; X } X return(t); X} X Xstatic struct op * Xandor() X{ X register struct op *t, *p; X register int c; X X t = pipeline(0); X if (t != NULL) { X while ((c = yylex(0)) == LOGAND || c == LOGOR) { X if ((p = pipeline(CONTIN)) == NULL) X SYNTAXERR; X t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); X } X peeksym = c; X } X return(t); X} X Xstatic struct op * Xc_list() X{ X register struct op *t, *p; X register int c; X X t = andor(); X if (t != NULL) { X if((peeksym = yylex(0)) == '&') X t = block(TASYNC, t, NOBLOCK, NOWORDS); X while ((c = yylex(0)) == ';' || c == '&' || multiline && c == '\n') { X if ((p = andor()) == NULL) X return(t); X if((peeksym = yylex(0)) == '&') X p = block(TASYNC, p, NOBLOCK, NOWORDS); X t = list(t, p); X } X peeksym = c; X } X return(t); X} X X Xstatic int Xsynio(cf) Xint cf; X{ X register struct ioword *iop; X register int i; X register int c; X X if ((c = yylex(cf)) != '<' && c != '>') { X peeksym = c; X return(0); X } X i = yylval.i; X musthave(WORD, 0); X iop = io(iounit, i, yylval.cp); X iounit = IODEFAULT; X if (i & IOHERE) X markhere(yylval.cp, iop); X} X Xstatic void Xmusthave(c, cf) Xint c, cf; X{ X if ((peeksym = yylex(cf)) != c) X SYNTAXERR; X peeksym = 0; X} X Xstatic struct op * Xsimple() X{ X register struct op *t; X X t = NULL; X for (;;) { X switch (peeksym = yylex(0)) { X case '<': X case '>': X (void) synio(0); X break; X X case WORD: X if (t == NULL) { X t = newtp(); X t->type = TCOM; X } X peeksym = 0; X word(yylval.cp); X break; X X default: X return(t); X } X } X} X Xstatic struct op * Xnested(type, mark) Xint type, mark; X{ X register struct op *t; X X multiline++; X t = c_list(); X musthave(mark, 0); X multiline--; X return(block(type, t, NOBLOCK, NOWORDS)); X} X Xstatic struct op * Xcommand(cf) Xint cf; X{ X register struct ioword *io; X register struct op *t; X struct wdblock *iosave; X register int c; X X iosave = iolist; X iolist = NULL; X if (multiline) X cf |= CONTIN; X while (synio(cf)) X cf = 0; X switch (c = yylex(cf)) { X default: X peeksym = c; X if ((t = simple()) == NULL) { X if (iolist == NULL) X return(NULL); X t = newtp(); X t->type = TCOM; X } X break; X X case '(': X t = nested(TPAREN, ')'); X break; X X case '{': X t = nested(TBRACE, '}'); X break; X X case FOR: X t = newtp(); X t->type = TFOR; X musthave(WORD, 0); X startl = 1; X t->str = yylval.cp; X multiline++; X t->words = wordlist(); X if ((c = yylex(0)) != '\n' && c != ';') X SYNTAXERR; X t->left = dogroup(0); X multiline--; X break; X X case WHILE: X case UNTIL: X multiline++; X t = newtp(); X t->type = c == WHILE? TWHILE: TUNTIL; X t->left = c_list(); X t->right = dogroup(1); X t->words = NULL; X multiline--; X break; X X case CASE: X t = newtp(); X t->type = TCASE; X musthave(WORD, 0); X t->str = yylval.cp; X startl++; X multiline++; X musthave(IN, CONTIN); X startl++; X t->left = caselist(); X musthave(ESAC, 0); X multiline--; X break; X X case IF: X multiline++; X t = newtp(); X t->type = TIF; X t->left = c_list(); X t->right = thenpart(); X musthave(FI, 0); X multiline--; X break; X } X while (synio(0)) X ; X t = namelist(t); X iolist = iosave; X return(t); X} X Xstatic struct op * Xdogroup(onlydone) Xint onlydone; X{ X register int c; X register struct op *list; X X c = yylex(CONTIN); X if (c == DONE && onlydone) X return(NULL); X if (c != DO) X SYNTAXERR; X list = c_list(); X musthave(DONE, 0); X return(list); X} X Xstatic struct op * Xthenpart() X{ X register int c; X register struct op *t; X X if ((c = yylex(0)) != THEN) { X peeksym = c; X return(NULL); X } X t = newtp(); X t->type = 0; X t->left = c_list(); X if (t->left == NULL) X SYNTAXERR; X t->right = elsepart(); X return(t); X} X Xstatic struct op * Xelsepart() X{ X register int c; X register struct op *t; X X switch (c = yylex(0)) { X case ELSE: X if ((t = c_list()) == NULL) X SYNTAXERR; X return(t); X X case ELIF: X t = newtp(); X t->type = TELIF; X t->left = c_list(); X t->right = thenpart(); X return(t); X X default: X peeksym = c; X return(NULL); X } X} X Xstatic struct op * Xcaselist() X{ X register struct op *t; X register int c; X X t = NULL; X while ((peeksym = yylex(CONTIN)) != ESAC) X t = list(t, casepart()); X return(t); X} X Xstatic struct op * Xcasepart() X{ X register struct op *t; X register int c; X X t = newtp(); X t->type = TPAT; X t->words = pattern(); X musthave(')', 0); X t->left = c_list(); X if ((peeksym = yylex(CONTIN)) != ESAC) X musthave(BREAK, CONTIN); X return(t); X} X Xstatic char ** Xpattern() X{ X register int c, cf; X X cf = CONTIN; X do { X musthave(WORD, cf); X word(yylval.cp); X cf = 0; X } while ((c = yylex(0)) == '|'); X peeksym = c; X word(NOWORD); X return(copyw()); X} X Xstatic char ** Xwordlist() X{ X register int c; X X if ((c = yylex(0)) != IN) { X peeksym = c; X return(NULL); X } X startl = 0; X while ((c = yylex(0)) == WORD) X word(yylval.cp); X word(NOWORD); X peeksym = c; X return(copyw()); X} X X/* X * supporting functions X */ Xstatic struct op * Xlist(t1, t2) Xregister struct op *t1, *t2; X{ X if (t1 == NULL) X return(t2); X if (t2 == NULL) X return(t1); X return(block(TLIST, t1, t2, NOWORDS)); X} X Xstatic struct op * Xblock(type, t1, t2, wp) Xstruct op *t1, *t2; Xchar **wp; X{ X register struct op *t; X X t = newtp(); X t->type = type; X t->left = t1; X t->right = t2; X t->words = wp; X return(t); X} X Xstruct res { X char *r_name; X int r_val; X} restab[] = { X "for", FOR, X "case", CASE, X "esac", ESAC, X "while", WHILE, X "do", DO, X "done", DONE, X "if", IF, X "in", IN, X "then", THEN, X "else", ELSE, X "elif", ELIF, X "until", UNTIL, X "fi", FI, X X ";;", BREAK, X "||", LOGOR, X "&&", LOGAND, X "{", '{', X "}", '}', X X 0, X}; X Xrlookup(n) Xregister char *n; X{ X register struct res *rp; X X for (rp = restab; rp->r_name; rp++) X if (strcmp(rp->r_name, n) == 0) X return(rp->r_val); X return(0); X} X Xstatic struct op * Xnewtp() X{ X register struct op *t; X X t = (struct op *)tree(sizeof(*t)); X t->type = 0; X t->words = NULL; X t->ioact = NULL; X t->left = NULL; X t->right = NULL; X t->str = NULL; X return(t); X} X Xstatic struct op * Xnamelist(t) Xregister struct op *t; X{ X if (iolist) { X iolist = addword((char *)NULL, iolist); X t->ioact = copyio(); X } else X t->ioact = NULL; X if (t->type != TCOM) { X if (t->type != TPAREN && t->ioact != NULL) { X t = block(TPAREN, t, NOBLOCK, NOWORDS); X t->ioact = t->left->ioact; X t->left->ioact = NULL; X } X return(t); X } X word(NOWORD); X t->words = copyw(); X return(t); X} X Xstatic char ** Xcopyw() X{ X register char **wd; X X wd = getwords(wdlist); X wdlist = 0; X return(wd); X} X Xstatic void Xword(cp) Xchar *cp; X{ X wdlist = addword(cp, wdlist); X} X Xstatic struct ioword ** Xcopyio() X{ X register struct ioword **iop; X X iop = (struct ioword **) getwords(iolist); X iolist = 0; X return(iop); X} X Xstatic struct ioword * Xio(u, f, cp) Xchar *cp; X{ X register struct ioword *iop; X X iop = (struct ioword *) tree(sizeof(*iop)); X iop->io_unit = u; X iop->io_flag = f; X iop->io_name = cp; X iolist = addword((char *)iop, iolist); X return(iop); X} X Xstatic void Xzzerr() X{ X yyerror("syntax error"); X} X Xyyerror(s) Xchar *s; X{ X yynerrs++; X if (talking) { X if (multiline && nlseen) X unget('\n'); X multiline = 0; X while (yylex(0) != '\n') X ; X } X err(s); X fail(); X} X Xstatic int Xyylex(cf) Xint cf; X{ X register int c, c1; X int atstart; X X if ((c = peeksym) > 0) { X peeksym = 0; X if (c == '\n') X startl = 1; X return(c); X } X nlseen = 0; X e.linep = line; X atstart = startl; X startl = 0; X yylval.i = 0; X Xloop: X while ((c = getc(0)) == ' ' || c == '\t') X ; X switch (c) { X default: X if (any(c, "0123456789")) { X unget(c1 = getc(0)); X if (c1 == '<' || c1 == '>') { X iounit = c - '0'; X goto loop; X } X *e.linep++ = c; X c = c1; X } X break; X X case '#': X while ((c = getc(0)) != 0 && c != '\n') X ; X unget(c); X goto loop; X X case 0: X return(c); X X case '$': X *e.linep++ = c; X if ((c = getc(0)) == '{') { X if ((c = collect(c, '}')) != '\0') X return(c); X goto pack; X } X break; X X case '`': X case '\'': X case '"': X if ((c = collect(c, c)) != '\0') X return(c); X goto pack; X X case '|': X case '&': X case ';': X if ((c1 = dual(c)) != '\0') { X startl = 1; X return(c1); X } X startl = 1; X return(c); X case '^': X startl = 1; X return('|'); X case '>': X case '<': X diag(c); X return(c); X X case '\n': X nlseen++; X gethere(); X startl = 1; X if (multiline || cf & CONTIN) { X if (talking && e.iop <= iostack) X prs(cprompt->value); X if (cf & CONTIN) X goto loop; X } X return(c); X X case '(': X case ')': X startl = 1; X return(c); X } X X unget(c); X Xpack: X while ((c = getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) X if (e.linep >= elinep) X err("word too long"); X else X *e.linep++ = c; X unget(c); X if(any(c, "\"'`$")) X goto loop; X *e.linep++ = '\0'; X if (atstart && (c = rlookup(line))!=0) { X startl = 1; X return(c); X } X yylval.cp = strsave(line, areanum); X return(WORD); X} X Xint Xcollect(c, c1) Xregister c, c1; X{ X char s[2]; X X *e.linep++ = c; X while ((c = getc(c1)) != c1) { X if (c == 0) { X unget(c); X s[0] = c1; X s[1] = 0; X prs("no closing "); yyerror(s); X return(YYERRCODE); X } X if (talking && c == '\n' && e.iop <= iostack) X prs(cprompt->value); X *e.linep++ = c; X } X *e.linep++ = c; X return(0); X} X Xint Xdual(c) Xregister c; X{ X char s[3]; X register char *cp = s; X X *cp++ = c; X *cp++ = getc(0); X *cp = 0; X if ((c = rlookup(s)) == 0) X unget(*--cp); X return(c); X} X Xstatic void Xdiag(ec) Xregister int ec; X{ X register int c; X X c = getc(0); X if (c == '>' || c == '<') { X if (c != ec) X zzerr(); X yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE; X c = getc(0); X } else X yylval.i = ec == '>'? IOWRITE: IOREAD; X if (c != '&' || yylval.i == IOHERE) X unget(c); X else X yylval.i |= IODUP; X} X Xstatic char * Xtree(size) Xunsigned size; X{ X register char *t; X X if ((t = getcell(size)) == NULL) { X prs("command line too complicated\n"); X fail(); X /* NOTREACHED */ X } X return(t); X} X X/* VARARGS1 */ X/* ARGSUSED */ Xprintf(s) /* yyparse calls it */ Xchar *s; X{ X} X + END-OF-FILE sh2.c chmod 'u=rw,g=r,o=r' 'sh2.c' set `wc -c 'sh2.c'` count=$1 case $count in 11571) :;; *) echo 'Bad character count in ''sh2.c' >&2 echo 'Count should be 11571' >&2 esac exit 0