--- /dev/null
+PLATFORM = 6809
+CC = m6809-unknown-gcc
+# These are wrappers for lwasm and lwar
+ASM = m6809-unknown-as
+AR = m6809-unknown-ar
+LINKER = lwlink
+CFLAGS = -I../../../../Library/include -I../../../../Library/include/6502
+COPT = -Os
+LINKER_OPT = --format=raw -L../../../../Library/libs -lc6809
+LIBGCCDIR = $(dir $(shell $(CC) -print-libgcc-file-name))
+LINKER_OPT += -L$(LIBGCCDIR) -lgcc
+LINKER_OPT += --script=../../../util/$(TARGET).link
+ASM_OPT = -o
+CRT0 = ../../../../Library/libs/crt0_6809.o
+
+.SUFFIXES: .c .o
+
+
+SRCS = args.c blok.c builtin.c cmd.c ctype.c error.c expand.c fault.c io.c \
+ macro.c main.c msg.c name.c print.c service.c setbrk.c stak.c \
+ string.c xec.c glob.c
+
+# Workaround for gcc 6809
+SRCS_HARD = word.c
+
+
+OBJS = $(SRCS:.c=.o)
+OBJS_HARD = $(SRCS_HARD:.c=.o)
+
+all: sh
+
+$(OBJS): $(SRCS) $(CRT0)
+
+$(OBJS): %.o : %.c
+ $(CC) -c $(CFLAGS) $(COPT) $<
+
+$(OBJS_HARD): $(SRCS_HARD)
+
+sh: $(OBJS) $(OBJS_HARD)
+ $(LINKER) -o $@ $(LINKER_OPT) $(CRT0) $(OBJS) $(OBJS_HARD)
+
+clean:
+ rm -f $(OBJS) sh $(SRCS:.c=) core *~
+
+rmbak:
+ rm -f *~ core
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include <stdlib.h>
+#include "defs.h"
+
+LOCAL STRING *copyargs();
+LOCAL DOLPTR dolh;
+
+CHAR flagadr[10];
+
+CHAR flagchar[] = {
+ 'x', 'n', 'v', 't', 's', 'i', 'e', 'r', 'k', 'u', 0
+};
+INT flagval[] = {
+ execpr, noexec, readpr, oneflg, stdflg, intflg, errflg, rshflg, keyflg, setflg, 0
+};
+
+/* ======== option handling ======== */
+
+
+INT options(argc,argv)
+ STRING *argv;
+ INT argc;
+{
+ REG STRING cp;
+ REG STRING *argp=argv;
+ REG STRING flagc;
+ STRING flagp;
+
+ IF argc>1 ANDF *argp[1]=='-'
+ THEN cp=argp[1];
+ flags &= ~(execpr|readpr);
+ WHILE *++cp
+ DO flagc=flagchar;
+
+ WHILE *flagc ANDF *flagc != *cp DO flagc++ OD
+ IF *cp == *flagc
+ THEN flags |= flagval[flagc-flagchar];
+ ELIF *cp=='c' ANDF argc>2 ANDF comdiv==0
+ THEN comdiv=argp[2];
+ argp[1]=argp[0]; argp++; argc--;
+ ELSE failed(argv[1],badopt);
+ FI
+ OD
+ argp[1]=argp[0]; argc--;
+ FI
+
+ /* set up $- */
+ flagc=flagchar;
+ flagp=flagadr;
+ WHILE *flagc
+ DO IF flags&flagval[flagc-flagchar]
+ THEN *flagp++ = *flagc;
+ FI
+ flagc++;
+ OD
+ *flagp++=0;
+
+ return(argc);
+}
+
+void setargs(argi)
+ STRING argi[];
+{
+ /* count args */
+ REG STRING *argp=argi;
+ REG INT argn=0;
+
+ WHILE Rcheat(*argp++)!=ENDARGS DO argn++ OD
+
+ /* free old ones unless on for loop chain */
+ freeargs(dolh);
+ dolh=(DOLPTR)copyargs(argi,argn); /* sets dolv */
+ assnum(&dolladr,dolc=argn-1);
+}
+
+DOLPTR
+freeargs(blk)
+ DOLPTR blk;
+{
+ REG STRING *argp;
+ REG DOLPTR argr=0;
+ REG DOLPTR argblk;
+
+ IF argblk=blk
+ THEN argr = argblk->dolnxt;
+ IF (--argblk->doluse)==0
+ THEN FOR argp=(STRING *)argblk->dolarg; Rcheat(*argp)!=ENDARGS; argp++
+ DO free(*argp) OD
+ free(argblk);
+ FI
+ FI
+ return(argr);
+}
+
+LOCAL STRING * copyargs(from, n)
+ STRING from[];
+{
+ REG STRING * np=(STRING *)alloc(sizeof(STRING*)*n+3*BYTESPERWORD);
+ REG STRING * fp=from;
+ REG STRING * pp=np;
+
+ ((DOLPTR)np)->doluse=1; /* use count */
+ np=(STRING *)((DOLPTR)np)->dolarg;
+ dolv=np;
+
+ WHILE n--
+ DO *np++ = make(*fp++) OD
+ *np++ = ENDARGS;
+ return(pp);
+}
+
+clearup()
+{
+ /* force `for' $* lists to go away */
+ WHILE argfor=freeargs(argfor) DONE
+
+ /* clean up io files */
+ WHILE pop() DONE
+}
+
+DOLPTR useargs()
+{
+ IF dolh
+ THEN dolh->doluse++;
+ dolh->dolnxt=argfor;
+ return(argfor=dolh);
+ ELSE return(0);
+ FI
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+
+/*
+ * storage allocator
+ * (circular first fit strategy)
+ */
+
+#define BUSY 01
+#define busy(x) (Rcheat((x)->word)&BUSY)
+
+POS brkincr=BRKINCR;
+BLKPTR blokp; /*current search pointer*/
+BLKPTR bloktop=BLK(end); /*top of arena (last blok)*/
+
+
+
+ADDRESS alloc(nbytes)
+ POS nbytes;
+{
+ REG POS rbytes = round(nbytes+BYTESPERWORD,BYTESPERWORD);
+
+ LOOP INT c=0;
+ REG BLKPTR p = blokp;
+ REG BLKPTR q;
+ REP IF !busy(p)
+ THEN WHILE !busy(q = p->word) DO p->word = q->word OD
+ IF ADR(q)-ADR(p) >= rbytes
+ THEN blokp = BLK(ADR(p)+rbytes);
+ IF q > blokp
+ THEN blokp->word = p->word;
+ FI
+ p->word=BLK(Rcheat(blokp)|BUSY);
+ return(ADR(p+1));
+ FI
+ FI
+ q = p; p = BLK(Rcheat(p->word)&~BUSY);
+ PER p>q ORF (c++)==0 DONE
+ addblok(rbytes);
+ POOL
+}
+
+void addblok(reqd)
+ POS reqd;
+{
+ IF stakbas!=staktop
+ THEN REG STKPTR rndstak;
+ REG BLKPTR blokstak;
+
+ pushstak(0);
+ rndstak=(STKPTR)round(staktop,BYTESPERWORD);
+ blokstak=BLK(stakbas)-1;
+ blokstak->word=stakbsy; stakbsy=blokstak;
+ bloktop->word=BLK(Rcheat(rndstak)|BUSY);
+ bloktop=BLK(rndstak);
+ FI
+ reqd += brkincr; reqd &= ~(brkincr-1);
+ blokp=bloktop;
+ bloktop=bloktop->word=BLK(Rcheat(bloktop)+reqd);
+ bloktop->word=BLK(ADR(end)+1);
+ BEGIN
+ REG STKPTR stakadr=STK(bloktop+2);
+ staktop=movstr(stakbot,stakadr);
+ stakbas=stakbot=stakadr;
+ END
+}
+
+void free(void *ap)
+{
+ BLKPTR p;
+
+ IF (p=ap) ANDF p<bloktop
+ THEN Lcheat((--p)->word) &= ~BUSY;
+ FI
+}
+
+#ifdef DEBUG
+chkbptr(ptr)
+ BLKPTR ptr;
+{
+ INT exf=0;
+ REG BLKPTR p = end;
+ REG BLKPTR q;
+ INT us=0, un=0;
+
+ LOOP
+ q = Rcheat(p->word)&~BUSY;
+ IF p==ptr THEN exf++ FI
+ IF q<end ORF q>bloktop THEN abort(3) FI
+ IF p==bloktop THEN break FI
+ IF busy(p)
+ THEN us += q-p;
+ ELSE un += q-p;
+ FI
+ IF p>=q THEN abort(4) FI
+ p=q;
+ POOL
+ IF exf==0 THEN abort(1) FI
+ prn(un); prc(SP); prn(us); prc(NL);
+}
+#endif
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#define BRKINCR 01000
+#define BRKMAX 04000
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+builtin()
+{return(0);}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+#include "sym.h"
+
+LOCAL IOPTR inout();
+LOCAL void chkword();
+LOCAL void chksym();
+LOCAL TREPTR term();
+LOCAL TREPTR makelist();
+LOCAL TREPTR list();
+LOCAL REGPTR syncase();
+LOCAL TREPTR item();
+LOCAL int skipnl();
+LOCAL void prsym();
+LOCAL void synbad();
+
+
+/* ======== command line decoding ========*/
+
+
+
+
+TREPTR makefork(flgs, i)
+ INT flgs;
+ TREPTR i;
+{
+ REG FORKPTR t;
+
+ t=(FORKPTR)getstak(FORKTYPE);
+ t->forktyp=flgs|TFORK;
+ t->forktre=i;
+ t->forkio=0;
+ return(TREPTR)(t);
+}
+
+LOCAL TREPTR makelist(type,i,r)
+ INT type;
+ TREPTR i, r;
+{
+ REG LSTPTR t;
+
+ IF i==0 ORF r==0
+ THEN synbad();
+ ELSE t = (LSTPTR)getstak(LSTTYPE);
+ t->lsttyp = type;
+ t->lstlef = i; t->lstrit = r;
+ FI
+ return(TREPTR)(t);
+}
+
+/*
+ * cmd
+ * empty
+ * list
+ * list & [ cmd ]
+ * list [ ; cmd ]
+ */
+
+TREPTR cmd(sym,flg)
+ REG INT sym;
+ INT flg;
+{
+ REG TREPTR i, e;
+
+ i = list(flg);
+
+ IF wdval==NL
+ THEN IF flg&NLFLG
+ THEN wdval=';'; chkpr(NL);
+ FI
+ ELIF i==0 ANDF (flg&MTFLG)==0
+ THEN synbad();
+ FI
+
+ SWITCH wdval IN
+
+ case '&':
+ IF i
+ THEN i = makefork(FINT|FPRS|FAMP, i);
+ ELSE synbad();
+ FI
+
+ case ';':
+ IF e=cmd(sym,flg|MTFLG)
+ THEN i=makelist(TLST, i, e);
+ FI
+ break;
+
+ case EOFSYM:
+ IF sym==NL
+ THEN break;
+ FI
+
+ default:
+ IF sym
+ THEN chksym(sym);
+ FI
+
+ ENDSW
+ return(i);
+}
+
+/*
+ * list
+ * term
+ * list && term
+ * list || term
+ */
+
+LOCAL TREPTR list(flg)
+{
+ REG TREPTR r;
+ REG INT b;
+
+ r = term(flg);
+ WHILE r ANDF ((b=(wdval==ANDFSYM)) ORF wdval==ORFSYM)
+ DO r = makelist((b ? TAND : TORF), r, term(NLFLG));
+ OD
+ return(r);
+}
+
+/*
+ * term
+ * item
+ * item |^ term
+ */
+
+LOCAL TREPTR term(flg)
+{
+ REG TREPTR t;
+
+ reserv++;
+ IF flg&NLFLG
+ THEN skipnl();
+ ELSE word();
+ FI
+
+ IF (t=item(TRUE)) ANDF (wdval=='^' ORF wdval=='|')
+ THEN return(makelist(TFIL, makefork(FPOU,t), makefork(FPIN|FPCL,term(NLFLG))));
+ ELSE return(t);
+ FI
+}
+
+LOCAL REGPTR syncase(esym)
+ REG INT esym;
+{
+ skipnl();
+ IF wdval==esym
+ THEN return(0);
+ ELSE REG REGPTR r=(REGPTR)getstak(REGTYPE);
+ r->regptr=0;
+ LOOP wdarg->argnxt=r->regptr;
+ r->regptr=wdarg;
+ IF wdval ORF ( word()!=')' ANDF wdval!='|' )
+ THEN synbad();
+ FI
+ IF wdval=='|'
+ THEN word();
+ ELSE break;
+ FI
+ POOL
+ r->regcom=cmd(0,NLFLG|MTFLG);
+ IF wdval==ECSYM
+ THEN r->regnxt=syncase(esym);
+ ELSE chksym(esym);
+ r->regnxt=0;
+ FI
+ return(r);
+ FI
+}
+
+/*
+ * item
+ *
+ * ( cmd ) [ < in ] [ > out ]
+ * word word* [ < in ] [ > out ]
+ * if ... then ... else ... fi
+ * for ... while ... do ... done
+ * case ... in ... esac
+ * begin ... end
+ */
+
+LOCAL TREPTR item(flag)
+ BOOL flag;
+{
+ REG TREPTR t;
+ REG IOPTR io;
+
+ IF flag
+ THEN io=inout((IOPTR)0);
+ ELSE io=0;
+ FI
+
+ SWITCH wdval IN
+
+ case CASYM:
+ BEGIN
+ t=(TREPTR)getstak(SWTYPE);
+ chkword();
+ ((SWPTR)t)->swarg=wdarg->argval;
+ skipnl(); chksym(INSYM|BRSYM);
+ ((SWPTR)t)->swlst=syncase(wdval==INSYM?ESSYM:KTSYM);
+ ((SWPTR)t)->swtyp=TSW;
+ break;
+ END
+
+ case IFSYM:
+ BEGIN
+ REG INT w;
+ t=(TREPTR)getstak(IFTYPE);
+ ((IFPTR)t)->iftyp=TIF;
+ ((IFPTR)t)->iftre=cmd(THSYM,NLFLG);
+ ((IFPTR)t)->thtre=cmd(ELSYM|FISYM|EFSYM,NLFLG);
+ ((IFPTR)t)->eltre=((w=wdval)==ELSYM ? cmd(FISYM,NLFLG) : (w==EFSYM ? (wdval=IFSYM, item(0)) : 0));
+ IF w==EFSYM THEN return(t) FI
+ break;
+ END
+
+ case FORSYM:
+ BEGIN
+ t=(TREPTR)getstak(FORTYPE);
+ ((FORPTR)t)->fortyp=TFOR;
+ ((FORPTR)t)->forlst=0;
+ chkword();
+ ((FORPTR)t)->fornam=wdarg->argval;
+ IF skipnl()==INSYM
+ THEN chkword();
+ ((FORPTR)t)->forlst=(COMPTR)item(0);
+ IF wdval!=NL ANDF wdval!=';'
+ THEN synbad();
+ FI
+ chkpr(wdval); skipnl();
+ FI
+ chksym(DOSYM|BRSYM);
+ ((FORPTR)t)->fortre=cmd(wdval==DOSYM?ODSYM:KTSYM,NLFLG);
+ break;
+ END
+
+ case WHSYM:
+ case UNSYM:
+ BEGIN
+ t=(TREPTR)getstak(WHTYPE);
+ ((WHPTR)t)->whtyp=(wdval==WHSYM ? TWH : TUN);
+ ((WHPTR)t)->whtre = cmd(DOSYM,NLFLG);
+ ((WHPTR)t)->dotre = cmd(ODSYM,NLFLG);
+ break;
+ END
+
+ case BRSYM:
+ t=cmd(KTSYM,NLFLG);
+ break;
+
+ case '(':
+ BEGIN
+ REG PARPTR p;
+ p=(PARPTR)getstak(PARTYPE);
+ p->partre=cmd(')',NLFLG);
+ p->partyp=TPAR;
+ t=makefork(0,p);
+ break;
+ END
+
+ default:
+ IF io==0
+ THEN return(0);
+ FI
+
+ case 0:
+ BEGIN
+ REG ARGPTR argp;
+ REG ARGPTR *argtail;
+ REG ARGPTR *argset=0;
+ INT keywd=1;
+ t=(TREPTR)getstak(COMTYPE);
+ ((COMPTR)t)->comio=io; /*initial io chain*/
+ argtail = &(((COMPTR)t)->comarg);
+ WHILE wdval==0
+ DO argp = wdarg;
+ IF wdset ANDF keywd
+ THEN argp->argnxt=(ARGPTR)argset;
+ argset=(ARGPTR *)argp;
+ ELSE *argtail=argp; argtail = &(argp->argnxt); keywd=flags&keyflg;
+ FI
+ word();
+ IF flag
+ THEN ((COMPTR)t)->comio=inout(((COMPTR)t)->comio);
+ FI
+ OD
+
+ ((COMPTR)t)->comtyp=TCOM;
+ ((COMPTR)t)->comset=(ARGPTR)argset;
+ *argtail=0;
+ return(t);
+ END
+
+ ENDSW
+ reserv++; word();
+ IF io=inout(io)
+ THEN t=makefork(0,t); t->treio=io;
+ FI
+ return(t);
+}
+
+
+LOCAL int skipnl()
+{
+ WHILE (reserv++, word()==NL) DO chkpr(NL) OD
+ return(wdval);
+}
+
+LOCAL IOPTR inout(lastio)
+ IOPTR lastio;
+{
+ REG INT iof;
+ REG IOPTR iop;
+ REG CHAR c;
+
+ iof=wdnum;
+
+ SWITCH wdval IN
+
+ case DOCSYM:
+ iof |= IODOC; break;
+
+ case APPSYM:
+ case '>':
+ IF wdnum==0 THEN iof |= 1 FI
+ iof |= IOPUT;
+ IF wdval==APPSYM
+ THEN iof |= IOAPP; break;
+ FI
+
+ case '<':
+ IF (c=nextc(0))=='&'
+ THEN iof |= IOMOV;
+ ELIF c=='>'
+ THEN iof |= IORDW;
+ ELSE peekc=c|MARK;
+ FI
+ break;
+
+ default:
+ return(lastio);
+ ENDSW
+
+ chkword();
+ iop=(IOPTR)getstak(IOTYPE);
+ iop->ioname=wdarg->argval;
+ iop->iofile=iof;
+ IF iof&IODOC
+ THEN iop->iolst=iopend; iopend=iop;
+ FI
+ word(); iop->ionxt=inout(lastio);
+ return(iop);
+}
+
+LOCAL void chkword()
+{
+ IF word()
+ THEN synbad();
+ FI
+}
+
+LOCAL void chksym(sym)
+{
+ REG INT x = sym&wdval;
+ IF ((x&SYMFLG) ? x : sym) != wdval
+ THEN synbad();
+ FI
+}
+
+LOCAL void prsym(sym)
+{
+ IF sym&SYMFLG
+ THEN REG SYSPTR sp=reserved;
+ WHILE sp->sysval
+ ANDF sp->sysval!=sym
+ DO sp++ OD
+ prs(sp->sysnam);
+ ELIF sym==EOFSYM
+ THEN prs(endoffile);
+ ELSE IF sym&SYMREP THEN prc(sym) FI
+ IF sym==NL
+ THEN prs("newline");
+ ELSE prc(sym);
+ FI
+ FI
+}
+
+LOCAL void synbad()
+{
+ prp(); prs(synmsg);
+ IF (flags&ttyflg)==0
+ THEN prs(atline); prn(standin->flin);
+ FI
+ prs(colon);
+ prc(LQ);
+ IF wdval
+ THEN prsym(wdval);
+ ELSE prs(wdarg->argval);
+ FI
+ prc(RQ); prs(unexpected);
+ newline();
+ exitsh(SYNBAD);
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+char _ctype1[] = {
+/* 000 001 002 003 004 005 006 007 */
+ _EOF, 0, 0, 0, 0, 0, 0, 0,
+
+/* bs ht nl vt np cr so si */
+ 0, _TAB, _EOR, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* sp ! " # $ % & ' */
+ _SPC, 0, _DQU, 0, _DOL1, 0, _AMP, 0,
+
+/* ( ) * + , - . / */
+ _BRA, _KET, 0, 0, 0, 0, 0, 0,
+
+/* 0 1 2 3 4 5 6 7 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* 8 9 : ; < = > ? */
+ 0, 0, 0, _SEM, _LT, 0, _GT, 0,
+
+/* @ A B C D E F G */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* H I J K L M N O */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* P Q R S T U V W */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* X Y Z [ \ ] ^ _ */
+ 0, 0, 0, 0, _BSL, 0, _HAT, 0,
+
+/* ` a b c d e f g */
+ _LQU, 0, 0, 0, 0, 0, 0, 0,
+
+/* h i j k l m n o */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* p q r s t u v w */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* x y z { | } ~ del */
+ 0, 0, 0, 0, _BAR, 0, 0, 0
+};
+
+
+char _ctype2[] = {
+/* 000 001 002 003 004 005 006 007 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* bs ht nl vt np cr so si */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* sp ! " # $ % & ' */
+ 0, _PCS, 0, _NUM, _DOL2, 0, 0, 0,
+
+/* ( ) * + , - . / */
+ 0, 0, _AST, _PLS, 0, _MIN, 0, 0,
+
+/* 0 1 2 3 4 5 6 7 */
+ _DIG, _DIG, _DIG, _DIG, _DIG, _DIG, _DIG, _DIG,
+
+/* 8 9 : ; < = > ? */
+ _DIG, _DIG, 0, 0, 0, _EQ, 0, _QU,
+
+/* @ A B C D E F G */
+ _AT, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC,
+
+/* H I J K L M N O */
+ _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC,
+
+/* P Q R S T U V W */
+ _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC,
+
+/* X Y Z [ \ ] ^ _ */
+ _UPC, _UPC, _UPC, _SQB, 0, 0, 0, _UPC,
+
+/* ` a b c d e f g */
+ 0, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC,
+
+/* h i j k l m n o */
+ _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC,
+
+/* p q r s t u v w */
+ _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC,
+
+/* x y z { | } ~ del */
+ _LPC, _LPC, _LPC, _CBR, 0, _CKT, 0, 0
+};
+
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+
+/* table 1 */
+#define T_SUB 01
+#define T_MET 02
+#define T_SPC 04
+#define T_DIP 010
+#define T_EOF 020
+#define T_EOR 040
+#define T_QOT 0100
+#define T_ESC 0200
+
+/* table 2 */
+#define T_BRC 01
+#define T_DEF 02
+#define T_AST 04
+#define T_DIG 010
+#define T_FNG 020
+#define T_SHN 040
+#define T_IDC 0100
+#define T_SET 0200
+
+/* for single chars */
+#define _TAB (T_SPC)
+#define _SPC (T_SPC)
+#define _UPC (T_IDC)
+#define _LPC (T_IDC)
+#define _DIG (T_DIG)
+#define _EOF (T_EOF)
+#define _EOR (T_EOR)
+#define _BAR (T_DIP)
+#define _HAT (T_MET)
+#define _BRA (T_MET)
+#define _KET (T_MET)
+#define _SQB (T_FNG)
+#define _AMP (T_DIP)
+#define _SEM (T_DIP)
+#define _LT (T_DIP)
+#define _GT (T_DIP)
+#define _LQU (T_QOT|T_ESC)
+#define _BSL (T_ESC)
+#define _DQU (T_QOT)
+#define _DOL1 (T_SUB|T_ESC)
+
+#define _CBR T_BRC
+#define _CKT T_DEF
+#define _AST (T_AST|T_FNG)
+#define _EQ (T_DEF)
+#define _MIN (T_DEF|T_SHN)
+#define _PCS (T_SHN)
+#define _NUM (T_SHN)
+#define _DOL2 (T_SHN)
+#define _PLS (T_DEF|T_SET)
+#define _AT (T_AST)
+#define _QU (T_DEF|T_FNG|T_SHN)
+
+/* abbreviations for tests */
+#define _IDCH (T_IDC|T_DIG)
+#define _META (T_SPC|T_DIP|T_MET|T_EOR)
+
+extern char _ctype1[];
+
+/* nb these args are not call by value !!!! */
+#define space(c) (((c)"E)==0 ANDF _ctype1[c]&(T_SPC))
+#define eofmeta(c) (((c)"E)==0 ANDF _ctype1[c]&(_META|T_EOF))
+#define qotchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_QOT))
+#define eolchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_EOR|T_EOF))
+#define dipchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_DIP))
+#define subchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_SUB|T_QOT))
+#define escchar(c) (((c)"E)==0 ANDF _ctype1[c]&(T_ESC))
+
+extern char _ctype2[];
+
+#define digit(c) (((c)"E)==0 ANDF _ctype2[c]&(T_DIG))
+#define fngchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_FNG))
+#define dolchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN))
+#define defchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_DEF))
+#define setchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_SET))
+#define digchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_AST|T_DIG))
+#define letter(c) (((c)"E)==0 ANDF _ctype2[c]&(T_IDC))
+#define alphanum(c) (((c)"E)==0 ANDF _ctype2[c]&(_IDCH))
+#define astchar(c) (((c)"E)==0 ANDF _ctype2[c]&(T_AST))
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+//#include <stdint.h>
+#include <stddef.h>
+#include <unistd.h>
+
+/*
+ * UNIX shell
+ */
+
+/* error exits from various parts of shell */
+#define ERROR 1
+#define SYNBAD 2
+#define SIGFAIL 3
+#define SIGFLG 0200
+
+/* command tree */
+#define FPRS 020
+#define FINT 040
+#define FAMP 0100
+#define FPIN 0400
+#define FPOU 01000
+#define FPCL 02000
+#define FCMD 04000
+#define COMMSK 017
+
+#define TCOM 0
+#define TPAR 1
+#define TFIL 2
+#define TLST 3
+#define TIF 4
+#define TWH 5
+#define TUN 6
+#define TSW 7
+#define TAND 8
+#define TORF 9
+#define TFORK 10
+#define TFOR 11
+
+/* execute table */
+#define SYSSET 1
+#define SYSCD 2
+#define SYSEXEC 3
+#define SYSLOGIN 4
+#define SYSTRAP 5
+#define SYSEXIT 6
+#define SYSSHFT 7
+#define SYSWAIT 8
+#define SYSCONT 9
+#define SYSBREAK 10
+#define SYSEVAL 11
+#define SYSDOT 12
+#define SYSRDONLY 13
+#define SYSTIMES 14
+#define SYSXPORT 15
+#define SYSNULL 16
+#define SYSREAD 17
+#define SYSTST 18
+#define SYSUMASK 19
+
+/* used for input and output of shell */
+#define INIO 10
+#define OTIO 11
+
+/*io nodes*/
+#define USERIO 10
+#define IOUFD 15
+#define IODOC 16
+#define IOPUT 32
+#define IOAPP 64
+#define IOMOV 128
+#define IORDW 256
+#define INPIPE 0
+#define OTPIPE 1
+
+/* arg list terminator */
+#define ENDARGS 0
+
+#include "mac.h"
+#include "mode.h"
+#include "name.h"
+
+
+/* result type declarations */
+extern void *setbrk(intptr_t);
+extern void sh_getenv(void);
+extern STRING *sh_setenv(void);
+
+
+#define alloc malloc
+ADDRESS alloc();
+void addblok();
+STRING make();
+STRING movstr();
+TREPTR cmd();
+TREPTR makefork();
+NAMPTR lookup();
+void setname();
+void setargs();
+DOLPTR useargs();
+DOLPTR freeargs();
+REAL expr();
+STRING catpath();
+STRING getpath();
+STRING *scan();
+STRING mactrim();
+STRING macro();
+void await();
+void post();
+void exname();
+void printnam();
+void printflg();
+void prs();
+void prc();
+
+#define attrib(n,f) (n->namflg |= f)
+#define round(a,b) (((int)((ADR(a)+b)-1))&~((b)-1))
+#define closepipe(x) (close(x[INPIPE]), close(x[OTPIPE]))
+#define eq(a,b) (cf(a,b)==0)
+#define max(a,b) ((a)>(b)?(a):(b))
+#define assert(x) ;
+
+/* temp files and io */
+extern UFD output;
+extern INT ioset;
+extern IOPTR iotemp; /* files to be deleted sometime */
+extern IOPTR iopend; /* documents waiting to be read at NL */
+
+/* substitution */
+extern INT dolc;
+extern STRING *dolv;
+extern DOLPTR argfor;
+extern ARGPTR gchain;
+
+/* stack */
+#define BLK(x) ((BLKPTR)(x))
+#define BYT(x) ((BYTPTR)(x))
+#define STK(x) ((STKPTR)(x))
+#define ADR(x) ((char*)(x))
+
+/* stak stuff */
+#include "stak.h"
+
+/* string constants */
+extern const char atline[];
+extern const char readmsg[];
+extern const char colon[];
+extern const char minus[];
+extern const char nullstr[];
+extern const char sptbnl[];
+extern const char unexpected[];
+extern const char endoffile[];
+extern const char synmsg[];
+
+/* name tree and words */
+extern SYSTAB reserved;
+extern INT wdval;
+extern INT wdnum;
+extern ARGPTR wdarg;
+extern INT wdset;
+extern BOOL reserv;
+
+/* prompting */
+extern const char stdprompt[];
+extern const char supprompt[];
+extern const char profile[];
+
+/* built in names */
+extern NAMNOD fngnod;
+extern NAMNOD ifsnod;
+extern NAMNOD homenod;
+extern NAMNOD mailnod;
+extern NAMNOD pathnod;
+extern NAMNOD ps1nod;
+extern NAMNOD ps2nod;
+
+/* special names */
+extern char flagadr[10];
+extern STRING cmdadr;
+extern STRING exitadr;
+extern STRING dolladr;
+extern STRING pcsadr;
+extern STRING pidadr;
+
+extern const char defpath[];
+
+/* names always present */
+extern const char mailname[];
+extern const char homename[];
+extern const char pathname[];
+extern const char fngname[];
+extern const char ifsname[];
+extern const char ps1name[];
+extern const char ps2name[];
+
+/* transput */
+extern CHAR tmpout[];
+extern STRING tmpnam;
+extern INT serial;
+#define TMPNAM 7
+extern FILE standin;
+#define input (standin->fdes)
+#define eof (standin->feof)
+extern INT peekc;
+extern STRING comdiv;
+extern const char devnull[];
+
+/* flags */
+#define noexec 01
+#define intflg 02
+#define prompt 04
+#define setflg 010
+#define errflg 020
+#define ttyflg 040
+#define forked 0100
+#define oneflg 0200
+#define rshflg 0400
+#define waiting 01000
+#define stdflg 02000
+#define execpr 04000
+#define readpr 010000
+#define keyflg 020000
+extern INT flags;
+
+/* error exits from various parts of shell */
+#include <setjmp.h>
+extern jmp_buf subshell;
+extern jmp_buf errshell;
+
+/* fault handling */
+#include "brkincr.h"
+extern POS brkincr;
+
+#define MINTRAP 0
+#define MAXTRAP 17
+
+#define INTR 2
+#define QUIT 3
+#define MEMF 11
+#define ALARM 14
+#define KILL 15
+#define TRAPSET 2
+#define SIGSET 4
+#define SIGMOD 8
+
+void fault();
+extern BOOL trapnote;
+extern STRING trapcom[];
+extern BOOL trapflg[];
+
+/* name tree and words */
+extern STRING *environ;
+extern CHAR numbuf[];
+extern const char export[];
+extern const char readonly[];
+
+/* execflgs */
+extern INT exitval;
+extern BOOL execbrk;
+extern INT loopcnt;
+extern INT breakcnt;
+
+/* messages */
+extern const char mailmsg[];
+extern const char coredump[];
+extern const char badopt[];
+extern const char badparam[];
+extern const char badsub[];
+extern const char nospace[];
+extern const char notfound[];
+extern const char badtrap[];
+extern const char baddir[];
+extern const char badshift[];
+extern const char illegal[];
+extern const char restricted[];
+extern const char execpmsg[];
+extern const char notid[];
+extern const char wtfailed[];
+extern const char badcreate[];
+extern const char piperr[];
+extern const char badopen[];
+extern const char badnum[];
+extern const char arglist[];
+extern const char txtbsy[];
+extern const char toobig[];
+extern const char badexec[];
+extern const char notfound[];
+extern const char badfile[];
+
+extern address end[];
+
+#include "ctype.h"
+
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#define DUPFLG 0100
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+
+/* ======== error handling ======== */
+
+exitset()
+{
+ assnum(&exitadr,exitval);
+}
+
+sigchk()
+{
+ /* Find out if it is time to go away.
+ * `trapnote' is set to SIGSET when fault is seen and
+ * no trap has been set.
+ */
+ IF trapnote&SIGSET
+ THEN exitsh(SIGFAIL);
+ FI
+}
+
+failed(s1,s2)
+ STRING s1, s2;
+{
+ prp(); prs(s1);
+ IF s2
+ THEN prs(colon); prs(s2);
+ FI
+ newline(); exitsh(ERROR);
+}
+
+error(s)
+ STRING s;
+{
+ failed(s,NIL);
+}
+
+exitsh(xno)
+ INT xno;
+{
+ /* Arrive here from `FATAL' errors
+ * a) exit command,
+ * b) default trap,
+ * c) fault with no trap set.
+ *
+ * Action is to return to command level or exit.
+ */
+ exitval=xno;
+ IF (flags & (forked|errflg|ttyflg)) != ttyflg
+ THEN done();
+ ELSE clearup();
+ longjmp(errshell,1);
+ FI
+}
+
+done()
+{
+ REG STRING t;
+ IF t=trapcom[0]
+ THEN trapcom[0]=0; /*should free but not long */
+ execexp(t,0);
+ FI
+ rmtemp(0);
+ exit(exitval);
+}
+
+rmtemp(base)
+ IOPTR base;
+{
+ WHILE iotemp>base
+ DO unlink(iotemp->ioname);
+ iotemp=iotemp->iolst;
+ OD
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include <dirent.h>
+#include <sys/types.h>
+#define DIRSIZ 31
+#include <sys/stat.h>
+#include "defs.h"
+
+
+
+/* globals (file name generation)
+ *
+ * "*" in params matches r.e ".*"
+ * "?" in params matches r.e. "."
+ * "[...]" in params matches character class
+ * "[...a-z...]" in params matches a through z.
+ *
+ */
+
+LOCAL void addg();
+
+
+INT expand(as,rflg)
+ STRING as;
+{
+ INT count, dirf;
+ BOOL dir=0;
+ STRING rescan = 0;
+ REG STRING s, cs;
+ ARGPTR schain = gchain;
+ struct dirent entry;
+ STATBUF statb;
+
+ IF trapnote&SIGSET THEN return(0); FI
+
+ s=cs=as; entry.d_name[DIRSIZ-1]=0; /* to end the string */
+
+ /* check for meta chars */
+ BEGIN
+ REG BOOL slash; slash=0;
+ WHILE !fngchar(*cs)
+ DO IF *cs++==0
+ THEN IF rflg ANDF slash THEN break; ELSE return(0) FI
+ ELIF *cs=='/'
+ THEN slash++;
+ FI
+ OD
+ END
+
+ LOOP IF cs==s
+ THEN s=nullstr;
+ break;
+ ELIF *--cs == '/'
+ THEN *cs=0;
+ IF s==cs THEN s="/" FI
+ break;
+ FI
+ POOL
+ IF stat(s,&statb)>=0
+ ANDF (statb.st_mode&S_IFMT)==S_IFDIR
+ ANDF (dirf=open(s,0))>0
+ THEN dir++;
+ FI
+ count=0;
+ IF *cs==0 THEN *cs++=0200 FI
+ IF dir
+ THEN /* check for rescan */
+ REG STRING rs; rs=cs;
+
+ REP IF *rs=='/' THEN rescan=rs; *rs=0; gchain=0 FI
+ PER *rs++ DONE
+
+ // FIXME: readdir
+ WHILE read(dirf, (void *)&entry, 32) == 32 ANDF (trapnote&SIGSET) == 0
+ DO IF entry.d_ino==0 ORF
+ (*entry.d_name=='.' ANDF *cs!='.')
+ THEN continue;
+ FI
+ IF gmatch(entry.d_name, cs)
+ THEN addg(s,entry.d_name,rescan); count++;
+ FI
+ OD
+ close(dirf);
+
+ IF rescan
+ THEN REG ARGPTR rchain;
+ rchain=gchain; gchain=schain;
+ IF count
+ THEN count=0;
+ WHILE rchain
+ DO count += expand(rchain->argval,1);
+ rchain=rchain->argnxt;
+ OD
+ FI
+ *rescan='/';
+ FI
+ FI
+
+ BEGIN
+ REG CHAR c;
+ s=as;
+ WHILE c = *s
+ DO *s++=(c&STRIP?c:'/') OD
+ END
+ return(count);
+}
+
+gmatch(s, p)
+ REG STRING s, p;
+{
+ REG INT scc;
+ CHAR c;
+
+ IF scc = *s++
+ THEN IF (scc &= STRIP)==0
+ THEN scc=0200;
+ FI
+ FI
+ SWITCH c = *p++ IN
+
+ case '[':
+ {BOOL ok; INT lc;
+ ok=0; lc=077777;
+ WHILE c = *p++
+ DO IF c==']'
+ THEN return(ok?gmatch(s,p):0);
+ ELIF c==MINUS
+ THEN IF lc<=scc ANDF scc<=(*p++) THEN ok++ FI
+ ELSE IF scc==(lc=(c&STRIP)) THEN ok++ FI
+ FI
+ OD
+ return(0);
+ }
+
+ default:
+ IF (c&STRIP)!=scc THEN return(0) FI
+
+ case '?':
+ return(scc?gmatch(s,p):0);
+
+ case '*':
+ IF *p==0 THEN return(1) FI
+ --s;
+ WHILE *s
+ DO IF gmatch(s++,p) THEN return(1) FI OD
+ return(0);
+
+ case 0:
+ return(scc==0);
+ ENDSW
+}
+
+LOCAL void addg(as1,as2,as3)
+ STRING as1, as2, as3;
+{
+ REG STRING s1, s2;
+ REG INT c;
+
+ s2 = locstak()+BYTESPERWORD;
+
+ s1=as1;
+ WHILE c = *s1++
+ DO IF (c &= STRIP)==0
+ THEN *s2++='/';
+ break;
+ FI
+ *s2++=c;
+ OD
+ s1=as2;
+ WHILE *s2 = *s1++ DO s2++ OD
+ IF s1=as3
+ THEN *s2++='/';
+ WHILE *s2++ = *++s1 DONE
+ FI
+ makearg(endstak(s2));
+}
+
+makearg(args)
+ REG STRING args;
+{
+ ((ARGPTR)args)->argnxt=gchain;
+ gchain=(ARGPTR)args;
+}
+
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include <stdlib.h>
+#include "defs.h"
+
+
+STRING trapcom[MAXTRAP];
+BOOL trapflg[MAXTRAP];
+
+/* ======== fault handling routines ======== */
+
+
+void fault(sig)
+ REG INT sig;
+{
+ REG INT flag;
+
+ signal(sig,fault);
+ IF sig==MEMF
+ THEN IF setbrk(brkincr) == -1
+ THEN error(nospace);
+ FI
+ ELIF sig==ALARM
+ THEN IF flags&waiting
+ THEN done();
+ FI
+ ELSE flag = (trapcom[sig] ? TRAPSET : SIGSET);
+ trapnote |= flag;
+ trapflg[sig] |= flag;
+ FI
+}
+
+stdsigs()
+{
+ ignsig(QUIT);
+ getsig(INTR);
+ getsig(MEMF);
+ getsig(ALARM);
+}
+
+ignsig(n)
+{
+ REG INT s, i;
+#if 0
+ // FIXME: need to do proper SIG_IGN checks/handling
+ IF (s=signal(i=n,1)&01)==0
+ THEN trapflg[i] |= SIGMOD;
+ FI
+#endif
+ return(s);
+}
+
+getsig(n)
+{
+ REG INT i;
+
+ IF trapflg[i=n]&SIGMOD ORF ignsig(i)==0
+ THEN signal(i,fault);
+ FI
+}
+
+oldsigs()
+{
+ REG INT i;
+ REG STRING t;
+
+ i=MAXTRAP;
+ WHILE i--
+ DO t=trapcom[i];
+ IF t==0 ORF *t
+ THEN clrsig(i);
+ FI
+ trapflg[i]=0;
+ OD
+ trapnote=0;
+}
+
+clrsig(i)
+ INT i;
+{
+ free(trapcom[i]); trapcom[i]=0;
+ IF trapflg[i]&SIGMOD
+ THEN signal(i,fault);
+ trapflg[i] &= ~SIGMOD;
+ FI
+}
+
+chktrap()
+{
+ /* check for traps */
+ REG INT i=MAXTRAP;
+ REG STRING t;
+
+ trapnote &= ~TRAPSET;
+ WHILE --i
+ DO IF trapflg[i]&TRAPSET
+ THEN trapflg[i] &= ~TRAPSET;
+ IF t=trapcom[i]
+ THEN INT savxit=exitval;
+ execexp(t,0);
+ exitval=savxit; exitset();
+ FI
+ FI
+ OD
+}
--- /dev/null
+int wdval;
+int iopend;
+int flags;
+int peekc;
+char *comdiv;
+int breakcnt;
+int loopcnt;
+int execbrk;
+int exitval;
+int dolc;
+char **dolv;
+/* FIXME */
+void *argfor;
+void *gchain;
+int iotemp;
+int iopend;
+int ioset;
+int output;
+char *pidadr;
+char *dolladr;
+char *pcsadr;
+char *pidadr;
+char *exitadr;
+char *cmdadr;
+int wdset;
+void *wdarg;
+int reserv;
+int wdnum;
+int trapnote;
+int end;
+int serial;
+
+#include <setjmp.h>
+jmp_buf subshell;
+jmp_buf errshell;
+
+/* FIXME */
+
+int setjmp(jmp_buf bar) {}
+void longjmp(jmp_buf bar, int foo) {}
\ No newline at end of file
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+#include "dup.h"
+
+
+/* ======== input output and file copying ======== */
+
+initf(fd)
+ UFD fd;
+{
+ REG FILE f=standin;
+
+ f->fdes=fd; f->fsiz=((flags&(oneflg|ttyflg))==0 ? BUFSIZ : 1);
+ f->fnxt=f->fend=f->fbuf; f->feval=0; f->flin=1;
+ f->feof=FALSE;
+}
+
+estabf(s)
+ REG STRING s;
+{
+ REG FILE f;
+
+ (f=standin)->fdes = -1;
+ f->fend=length(s)+(f->fnxt=s);
+ f->flin=1;
+ return(f->feof=(s==0));
+}
+
+push(af)
+ FILE af;
+{
+ REG FILE f;
+
+ (f=af)->fstak=standin;
+ f->feof=0; f->feval=0;
+ standin=f;
+}
+
+pop()
+{
+ REG FILE f;
+
+ IF (f=standin)->fstak
+ THEN IF f->fdes>=0 THEN close(f->fdes) FI
+ standin=f->fstak;
+ return(TRUE);
+ ELSE return(FALSE);
+ FI
+}
+
+chkpipe(pv)
+ INT *pv;
+{
+ IF pipe(pv)<0 ORF pv[INPIPE]<0 ORF pv[OTPIPE]<0
+ THEN error(piperr);
+ FI
+}
+
+chkopen(idf)
+ STRING idf;
+{
+ REG INT rc;
+
+ IF (rc=open(idf,0))<0
+ THEN failed(idf,badopen);
+ ELSE return(rc);
+ FI
+}
+
+sh_rename(f1,f2)
+ REG INT f1, f2;
+{
+ IF f1!=f2
+ THEN dup2(f1, f2);
+ close(f1);
+ IF f2==0 THEN ioset|=1 FI
+ FI
+}
+
+create(s)
+ STRING s;
+{
+ REG INT rc;
+
+ IF (rc=creat(s,0666))<0
+ THEN failed(s,badcreate);
+ ELSE return(rc);
+ FI
+}
+
+tmpfil()
+{
+ itos(serial++); movstr(numbuf,tmpnam);
+ return(create(tmpout));
+}
+
+/* set by trim */
+BOOL nosubst;
+
+copy(ioparg)
+ IOPTR ioparg;
+{
+ CHAR c, *ends;
+ REG CHAR *cline, *clinep;
+ INT fd;
+ REG IOPTR iop;
+
+ IF iop=ioparg
+ THEN copy(iop->iolst);
+ ends=mactrim(iop->ioname); IF nosubst THEN iop->iofile &= ~IODOC FI
+ fd=tmpfil();
+ iop->ioname=cpystak(tmpout);
+ iop->iolst=iotemp; iotemp=iop;
+ cline=locstak();
+
+ LOOP clinep=cline; chkpr(NL);
+ WHILE (c = (nosubst ? readc() : nextc(*ends)), !eolchar(c)) DO *clinep++ = c OD
+ *clinep=0;
+ IF eof ORF eq(cline,ends) THEN break FI
+ *clinep++=NL;
+ write(fd,cline,clinep-cline);
+ POOL
+ close(fd);
+ FI
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#define LOCAL static
+#define PROC extern
+#define TYPE typedef
+#define STRUCT TYPE struct
+#define UNION TYPE union
+#define REG register
+
+#define IF if(
+#define THEN ){
+#define ELSE } else {
+#define ELIF } else if (
+#define FI ;}
+
+#define BEGIN {
+#define END }
+#define SWITCH switch(
+#define IN ){
+#define ENDSW }
+#define FOR for(
+#define WHILE while(
+#define DO ){
+#define OD ;}
+#define REP do{
+#define PER }while(
+#define DONE );
+#define LOOP for(;;){
+#define POOL }
+
+
+#define SKIP ;
+#define DIV /
+#define REM %
+#define NEQ ^
+#define ANDF &&
+#define ORF ||
+
+#define TRUE (-1)
+#define FALSE 0
+#define LOBYTE 0377
+#define STRIP 0177
+#define QUOTE 0200
+
+#define EOF 0
+#define NL '\n'
+#define SP ' '
+#define LQ '`'
+#define RQ '\''
+#define MINUS '-'
+#define COLON ':'
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+#include "sym.h"
+
+LOCAL CHAR quote; /* used locally */
+LOCAL CHAR quoted; /* used locally */
+
+LOCAL getch();
+LOCAL comsubst();
+LOCAL flush();
+
+
+LOCAL STRING copyto(endch)
+ REG CHAR endch;
+{
+ REG CHAR c;
+
+ WHILE (c=getch(endch))!=endch ANDF c
+ DO pushstak(c|quote) OD
+ zerostak();
+ IF c!=endch THEN error(badsub) FI
+}
+
+LOCAL skipto(endch)
+ REG CHAR endch;
+{
+ /* skip chars up to } */
+ REG CHAR c;
+ WHILE (c=readc()) ANDF c!=endch
+ DO SWITCH c IN
+
+ case SQUOTE: skipto(SQUOTE); break;
+
+ case DQUOTE: skipto(DQUOTE); break;
+
+ case DOLLAR: IF readc()==BRACE
+ THEN skipto('}');
+ FI
+ ENDSW
+ OD
+ IF c!=endch THEN error(badsub) FI
+}
+
+LOCAL getch(endch)
+ CHAR endch;
+{
+ REG CHAR d;
+
+retry:
+ d=readc();
+ IF !subchar(d)
+ THEN return(d);
+ FI
+ IF d==DOLLAR
+ THEN REG INT c;
+ IF (c=readc(), dolchar(c))
+ THEN NAMPTR n=(NAMPTR)NIL;
+ INT dolg=0;
+ BOOL bra;
+ REG STRING argp, v;
+ CHAR idb[2];
+ STRING id=idb;
+
+ IF bra=(c==BRACE) THEN c=readc() FI
+ IF letter(c)
+ THEN argp=(STRING)relstak();
+ WHILE alphanum(c) DO pushstak(c); c=readc() OD
+ zerostak();
+ n=lookup(absstak(argp)); setstak(argp);
+ v = n->namval; id = n->namid;
+ peekc = c|MARK;;
+ ELIF digchar(c)
+ THEN *id=c; idb[1]=0;
+ IF astchar(c)
+ THEN dolg=1; c='1';
+ FI
+ c -= '0';
+ v=((c==0) ? cmdadr : (c<=dolc) ? dolv[c] : (STRING)(dolg=0));
+ ELIF c=='$'
+ THEN v=pidadr;
+ ELIF c=='!'
+ THEN v=pcsadr;
+ ELIF c=='#'
+ THEN v=dolladr;
+ ELIF c=='?'
+ THEN v=exitadr;
+ ELIF c=='-'
+ THEN v=flagadr;
+ ELIF bra THEN error(badsub);
+ ELSE goto retry;
+ FI
+ c = readc();
+ IF !defchar(c) ANDF bra
+ THEN error(badsub);
+ FI
+ argp=0;
+ IF bra
+ THEN IF c!='}'
+ THEN argp=(STRING)relstak();
+ IF (v==0)NEQ(setchar(c))
+ THEN copyto('}');
+ ELSE skipto('}');
+ FI
+ argp=absstak(argp);
+ FI
+ ELSE peekc = c|MARK; c = 0;
+ FI
+ IF v
+ THEN IF c!='+'
+ THEN LOOP WHILE c = *v++
+ DO pushstak(c|quote); OD
+ IF dolg==0 ORF (++dolg>dolc)
+ THEN break;
+ ELSE v=dolv[dolg]; pushstak(SP|(*id=='*' ? quote : 0));
+ FI
+ POOL
+ FI
+ ELIF argp
+ THEN IF c=='?'
+ THEN failed(id,*argp?argp:badparam);
+ ELIF c=='='
+ THEN IF n
+ THEN assign(n,argp);
+ ELSE error(badsub);
+ FI
+ FI
+ ELIF flags&setflg
+ THEN failed(id,badparam);
+ FI
+ goto retry;
+ ELSE peekc=c|MARK;
+ FI
+ ELIF d==endch
+ THEN return(d);
+ ELIF d==SQUOTE
+ THEN comsubst(); goto retry;
+ ELIF d==DQUOTE
+ THEN quoted++; quote^=QUOTE; goto retry;
+ FI
+ return(d);
+}
+
+STRING macro(as)
+ STRING as;
+{
+ /* Strip "" and do $ substitution
+ * Leaves result on top of stack
+ */
+ REG BOOL savqu =quoted;
+ REG CHAR savq = quote;
+ FILEHDR fb;
+
+ push(&fb); estabf(as);
+ usestak();
+ quote=0; quoted=0;
+ copyto(0);
+ pop();
+ IF quoted ANDF (stakbot==staktop) THEN pushstak(QUOTE) FI
+ quote=savq; quoted=savqu;
+ return(fixstak());
+}
+
+LOCAL comsubst()
+{
+ /* command substn */
+ FILEBLK cb;
+ REG CHAR d;
+ REG STKPTR savptr = fixstak();
+
+ usestak();
+ WHILE (d=readc())!=SQUOTE ANDF d
+ DO pushstak(d) OD
+
+ BEGIN
+ REG STRING argc;
+ trim(argc=fixstak());
+ push(&cb); estabf(argc);
+ END
+ BEGIN
+ REG TREPTR t = makefork(FPOU,cmd(EOFSYM,MTFLG|NLFLG));
+ INT pv[2];
+
+ /* this is done like this so that the pipe
+ * is open only when needed
+ */
+ chkpipe(pv);
+ initf(pv[INPIPE]);
+ execute(t, 0, 0, pv);
+ close(pv[OTPIPE]);
+ END
+ tdystak(savptr); staktop=movstr(savptr,stakbot);
+ WHILE d=readc() DO pushstak(d|quote) OD
+ await(0);
+ WHILE stakbot!=staktop
+ DO IF (*--staktop&STRIP)!=NL
+ THEN ++staktop; break;
+ FI
+ OD
+ pop();
+}
+
+#define CPYSIZ 512
+
+subst(in,ot)
+ INT in, ot;
+{
+ REG CHAR c;
+ FILEBLK fb;
+ REG INT count=CPYSIZ;
+
+ push(&fb); initf(in);
+ /* DQUOTE used to stop it from quoting */
+ WHILE c=(getch(DQUOTE)&STRIP)
+ DO pushstak(c);
+ IF --count == 0
+ THEN flush(ot); count=CPYSIZ;
+ FI
+ OD
+ flush(ot);
+ pop();
+}
+
+LOCAL flush(ot)
+{
+ write(ot,stakbot,staktop-stakbot);
+ IF flags&execpr THEN write(output,stakbot,staktop-stakbot) FI
+ staktop=stakbot;
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "defs.h"
+#include "dup.h"
+#include "sym.h"
+#include "timeout.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+UFD output = 2;
+LOCAL BOOL beenhere = FALSE;
+CHAR tmpout[20] = "/tmp/sh-";
+FILEBLK stdfile;
+FILE standin = &stdfile;
+
+LOCAL void exfile();
+
+
+
+
+main(c, v)
+ INT c;
+ STRING v[];
+{
+ REG INT rflag=ttyflg;
+
+ /* initialise storage allocation */
+ stdsigs();
+ setbrk(BRKINCR);
+ addblok((POS)0);
+
+ /* set names from userenv */
+ sh_getenv();
+
+ /* look for restricted */
+/* IF c>0 ANDF any('r', *v) THEN rflag=0 FI */
+
+ /* look for options */
+ dolc=options(c,v);
+ IF dolc<2 THEN flags |= stdflg FI
+ IF (flags&stdflg)==0
+ THEN dolc--;
+ FI
+ dolv=v+c-dolc; dolc--;
+
+ /* return here for shell file execution */
+ setjmp(subshell);
+
+ /* number of positional parameters */
+ assnum(&dolladr,dolc);
+ cmdadr=dolv[0];
+
+ /* set pidname */
+ assnum(&pidadr, getpid());
+
+ /* set up temp file names */
+ settmp();
+
+ /* default ifs */
+ dfault(&ifsnod, sptbnl);
+
+ IF (beenhere++)==FALSE
+ THEN /* ? profile */
+ IF *cmdadr=='-'
+ ANDF (input=pathopen(nullstr, profile))>=0
+ THEN exfile(rflag); flags &= ~ttyflg;
+ FI
+ IF rflag==0 THEN flags |= rshflg FI
+
+ /* open input file if specified */
+ IF comdiv
+ THEN estabf(comdiv); input = -1;
+ ELSE input=((flags&stdflg) ? 0 : chkopen(cmdadr));
+ comdiv--;
+ FI
+// ELSE *execargs=(char *)dolv; /* for `ps' cmd */
+ FI
+
+ exfile(0);
+ done();
+}
+
+LOCAL void exfile(prof)
+BOOL prof;
+{
+ REG L_INT mailtime = 0;
+ REG INT userid;
+ struct stat statb;
+
+ /* move input */
+ IF input>0
+ THEN Ldup(input,INIO);
+ input=INIO;
+ FI
+
+ /* move output to safe place */
+ IF output==2
+ THEN Ldup(dup(2),OTIO);
+ output=OTIO;
+ FI
+
+ userid=getuid();
+
+ /* decide whether interactive */
+ IF (flags&intflg) ORF ((flags&oneflg)==0 ANDF isatty(output) ANDF isatty(input))
+ THEN dfault(&ps1nod, (userid?stdprompt:supprompt));
+ dfault(&ps2nod, readmsg);
+ flags |= ttyflg|prompt; ignsig(KILL);
+ ELSE flags |= prof; flags &= ~prompt;
+ FI
+
+ IF setjmp(errshell) ANDF prof
+ THEN close(input); return;
+ FI
+
+ /* error return here */
+ loopcnt=breakcnt=peekc=0; iopend=0;
+ IF input>=0 THEN initf(input) FI
+
+ /* command loop */
+ LOOP tdystak(0);
+ stakchk(); /* may reduce sbrk */
+ exitset();
+ IF (flags&prompt) ANDF standin->fstak==0 ANDF !eof
+ THEN IF mailnod.namval
+ ANDF stat(mailnod.namval,&statb)>=0 ANDF statb.st_size
+ ANDF (statb.st_mtime != mailtime)
+ ANDF mailtime
+ THEN prs(mailmsg)
+ FI
+ mailtime=statb.st_mtime;
+ prs(ps1nod.namval); alarm(TIMEOUT); flags |= waiting;
+ FI
+
+ trapnote=0; peekc=readc();
+ IF eof
+ THEN return;
+ FI
+ alarm(0); flags &= ~waiting;
+ execute(cmd(NL,MTFLG),0);
+ eof |= (flags&oneflg);
+ POOL
+}
+
+chkpr(eor)
+char eor;
+{
+ IF (flags&prompt) ANDF standin->fstak==0 ANDF eor==NL
+ THEN prs(ps2nod.namval);
+ FI
+}
+
+settmp()
+{
+ itos(getpid()); serial=0;
+ tmpnam=movstr(numbuf,&tmpout[TMPNAM]);
+}
+
+Ldup(fa, fb)
+ REG INT fa, fb;
+{
+ dup2(fa, fb);
+ close(fa);
+ fcntl(fb, F_SETFD, FD_CLOEXEC);
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ */
+
+
+#define BYTESPERWORD (sizeof(char *))
+
+TYPE char CHAR;
+TYPE char BOOL;
+TYPE int UFD;
+TYPE int INT;
+TYPE float REAL;
+TYPE void *ADDRESS;
+TYPE long int L_INT;
+TYPE unsigned POS;
+TYPE char *STRING;
+TYPE int PIPE[];
+TYPE char *STKPTR;
+TYPE char *BYTPTR;
+
+STRUCT stat STATBUF; /* defined in /usr/sys/stat.h */
+STRUCT blk *BLKPTR;
+STRUCT fileblk FILEBLK;
+STRUCT filehdr FILEHDR;
+STRUCT fileblk *FILE;
+STRUCT trenod *TREPTR;
+STRUCT forknod *FORKPTR;
+STRUCT comnod *COMPTR;
+STRUCT swnod *SWPTR;
+STRUCT regnod *REGPTR;
+STRUCT parnod *PARPTR;
+STRUCT ifnod *IFPTR;
+STRUCT whnod *WHPTR;
+STRUCT fornod *FORPTR;
+STRUCT lstnod *LSTPTR;
+STRUCT argnod *ARGPTR;
+STRUCT dolnod *DOLPTR;
+STRUCT ionod *IOPTR;
+STRUCT namnod NAMNOD;
+STRUCT namnod *NAMPTR;
+#define NIL ((char*)0)
+
+
+/* the following nonsense is required
+ * because casts turn an Lvalue
+ * into an Rvalue so two cheats
+ * are necessary, one for each context.
+ */
+#define Lcheat(a) (*(int *)&(a))
+#define Rcheat(a) ((int)(a))
+
+
+/* address puns for storage allocation */
+UNION {
+ FORKPTR _forkptr;
+ COMPTR _comptr;
+ PARPTR _parptr;
+ IFPTR _ifptr;
+ WHPTR _whptr;
+ FORPTR _forptr;
+ LSTPTR _lstptr;
+ BLKPTR _blkptr;
+ NAMPTR _namptr;
+ BYTPTR _bytptr;
+ } address;
+
+
+/* heap storage */
+struct blk {
+ BLKPTR word;
+};
+
+#define BUFSIZ 64
+struct fileblk {
+ UFD fdes;
+ POS flin;
+ BOOL feof;
+ CHAR fsiz;
+ STRING fnxt;
+ STRING fend;
+ STRING *feval;
+ FILE fstak;
+ CHAR fbuf[BUFSIZ];
+};
+
+/* for files not used with file descriptors */
+struct filehdr {
+ UFD fdes;
+ POS flin;
+ BOOL feof;
+ CHAR fsiz;
+ STRING fnxt;
+ STRING fend;
+ STRING *feval;
+ FILE fstak;
+ CHAR _fbuf[1];
+};
+
+struct sysnod {
+ STRING sysnam;
+ INT sysval;
+};
+
+STRUCT sysnod SYSNOD;
+STRUCT sysnod *SYSPTR;
+STRUCT sysnod SYSTAB[];
+
+/* this node is a proforma for those that follow */
+struct trenod {
+ INT tretyp;
+ IOPTR treio;
+};
+
+/* dummy for access only */
+struct argnod {
+ ARGPTR argnxt;
+ CHAR argval[1];
+};
+
+struct dolnod {
+ DOLPTR dolnxt;
+ INT doluse;
+ CHAR dolarg[1];
+};
+
+struct forknod {
+ INT forktyp;
+ IOPTR forkio;
+ TREPTR forktre;
+};
+
+struct comnod {
+ INT comtyp;
+ IOPTR comio;
+ ARGPTR comarg;
+ ARGPTR comset;
+};
+
+struct ifnod {
+ INT iftyp;
+ TREPTR iftre;
+ TREPTR thtre;
+ TREPTR eltre;
+};
+
+struct whnod {
+ INT whtyp;
+ TREPTR whtre;
+ TREPTR dotre;
+};
+
+struct fornod {
+ INT fortyp;
+ TREPTR fortre;
+ STRING fornam;
+ COMPTR forlst;
+};
+
+struct swnod {
+ INT swtyp;
+ STRING swarg;
+ REGPTR swlst;
+};
+
+struct regnod {
+ ARGPTR regptr;
+ TREPTR regcom;
+ REGPTR regnxt;
+};
+
+struct parnod {
+ INT partyp;
+ TREPTR partre;
+};
+
+struct lstnod {
+ INT lsttyp;
+ TREPTR lstlef;
+ TREPTR lstrit;
+};
+
+struct ionod {
+ INT iofile;
+ STRING ioname;
+ IOPTR ionxt;
+ IOPTR iolst;
+};
+
+#define FORKTYPE (sizeof(struct forknod))
+#define COMTYPE (sizeof(struct comnod))
+#define IFTYPE (sizeof(struct ifnod))
+#define WHTYPE (sizeof(struct whnod))
+#define FORTYPE (sizeof(struct fornod))
+#define SWTYPE (sizeof(struct swnod))
+#define REGTYPE (sizeof(struct regnod))
+#define PARTYPE (sizeof(struct parnod))
+#define LSTTYPE (sizeof(struct lstnod))
+#define IOTYPE (sizeof(struct ionod))
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+
+#include "defs.h"
+#include "sym.h"
+
+const char version[] = "\nVERSION sys137 DATE 1978 Nov 6 14:29:22\n";
+
+/* error messages */
+const char badopt[] = "bad option(s)";
+const char mailmsg[] = "you have mail\n";
+const char nospace[] = "no space";
+const char synmsg[] = "syntax error";
+
+const char badnum[] = "bad number";
+const char badparam[] = "parameter not set";
+const char badsub[] = "bad substitution";
+const char badcreate[] = "cannot create";
+const char illegal[] = "illegal io";
+const char restricted[] = "restricted";
+const char piperr[] = "cannot make pipe";
+const char badopen[] = "cannot open";
+const char coredump[] = " - core dumped";
+const char arglist[] = "arg list too long";
+const char txtbsy[] = "text busy";
+const char toobig[] = "too big";
+const char badexec[] = "cannot execute";
+const char notfound[] = "not found";
+const char badfile[] = "bad file number";
+const char badshift[] = "cannot shift";
+const char baddir[] = "bad directory";
+const char badtrap[] = "bad trap";
+const char wtfailed[] = "is read only";
+const char notid[] = "is not an identifier";
+
+/* built in names */
+const char pathname[] = "PATH";
+const char homename[] = "HOME";
+const char mailname[] = "MAIL";
+const char fngname[] = "FILEMATCH";
+const char ifsname[] = "IFS";
+const char ps1name[] = "PS1";
+const char ps2name[] = "PS2";
+
+/* string constants */
+const char nullstr[] = "";
+const char sptbnl[] = " \t\n";
+const char defpath[] = ":/bin:/usr/bin";
+const char colon[] = ": ";
+const char minus[] = "-";
+const char endoffile[] = "end of file";
+const char unexpected[] = " unexpected";
+const char atline[] = " at line ";
+const char devnull[] = "/dev/null";
+const char execpmsg[] = "+ ";
+const char readmsg[] = "> ";
+const char stdprompt[] = "$ ";
+const char supprompt[] = "# ";
+const char profile[] = ".profile";
+
+
+/* tables */
+SYSTAB reserved = {
+ {"in", INSYM},
+ {"esac", ESSYM},
+ {"case", CASYM},
+ {"for", FORSYM},
+ {"done", ODSYM},
+ {"if", IFSYM},
+ {"while", WHSYM},
+ {"do", DOSYM},
+ {"then", THSYM},
+ {"else", ELSYM},
+ {"elif", EFSYM},
+ {"fi", FISYM},
+ {"until", UNSYM},
+ { "{", BRSYM},
+ { "}", KTSYM},
+ {0, 0},
+};
+
+STRING sysmsg[] = {
+ 0,
+ "Hangup",
+ 0, /* Interrupt */
+ "Quit",
+ "Illegal instruction",
+ "Trace/BPT trap",
+ "IOT trap",
+ "EMT trap",
+ "Floating exception",
+ "Killed",
+ "Bus error",
+ "Memory fault",
+ "Bad system call",
+ 0, /* Broken pipe */
+ "Alarm call",
+ "Terminated",
+ "Signal 16",
+};
+
+const char export[] = "export";
+const char readonly[] = "readonly";
+SYSTAB commands = {
+ {"cd", SYSCD},
+ {"read", SYSREAD},
+/*
+ {"[", SYSTST},
+*/
+ {"set", SYSSET},
+ {":", SYSNULL},
+ {"trap", SYSTRAP},
+ {"login", SYSLOGIN},
+ {"wait", SYSWAIT},
+ {"eval", SYSEVAL},
+ {".", SYSDOT},
+ {"newgrp", SYSLOGIN},
+ {readonly, SYSRDONLY},
+ {export, SYSXPORT},
+ {"chdir", SYSCD},
+ {"break", SYSBREAK},
+ {"continue", SYSCONT},
+ {"shift", SYSSHFT},
+ {"exit", SYSEXIT},
+ {"exec", SYSEXEC},
+ {"times", SYSTIMES},
+ {"umask", SYSUMASK},
+ {0, 0},
+};
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+LOCAL BOOL chkid();
+LOCAL void namwalk();
+
+
+NAMNOD ps2nod = {(NAMPTR)NIL, (NAMPTR)NIL, ps2name},
+ fngnod = {(NAMPTR)NIL, (NAMPTR)NIL, fngname},
+ pathnod = {(NAMPTR)NIL, (NAMPTR)NIL, pathname},
+ ifsnod = {(NAMPTR)NIL, (NAMPTR)NIL, ifsname},
+ ps1nod = {&pathnod, &ps2nod, ps1name},
+ homenod = {&fngnod, &ifsnod, homename},
+ mailnod = {&homenod, &ps1nod, mailname};
+
+NAMPTR namep = &mailnod;
+
+
+/* ======== variable and string handling ======== */
+
+syslook(w,syswds)
+ STRING w;
+ SYSTAB syswds;
+{
+ REG CHAR first;
+ REG STRING s;
+ REG SYSPTR syscan;
+
+ syscan=syswds; first = *w;
+
+ WHILE s=syscan->sysnam
+ DO IF first == *s
+ ANDF eq(w,s)
+ THEN return(syscan->sysval);
+ FI
+ syscan++;
+ OD
+ return(0);
+}
+
+setlist(arg,xp)
+ REG ARGPTR arg;
+ INT xp;
+{
+ WHILE arg
+ DO REG STRING s=mactrim(arg->argval);
+ setname(s, xp);
+ arg=arg->argnxt;
+ IF flags&execpr
+ THEN prs(s);
+ IF arg THEN blank(); ELSE newline(); FI
+ FI
+ OD
+}
+
+void setname(argi, xp)
+ STRING argi;
+ INT xp;
+{
+ REG STRING argscan=argi;
+ REG NAMPTR n;
+
+ IF letter(*argscan)
+ THEN WHILE alphanum(*argscan) DO argscan++ OD
+ IF *argscan=='='
+ THEN *argscan = 0;
+ n=lookup(argi);
+ *argscan++ = '=';
+ attrib(n, xp);
+ IF xp&N_ENVNAM
+ THEN n->namenv = n->namval = argscan;
+ ELSE assign(n, argscan);
+ FI
+ return;
+ FI
+ FI
+ failed(argi,notid);
+}
+
+replace(a, v)
+ REG STRING *a;
+ STRING v;
+{
+ free(*a); *a=make(v);
+}
+
+dfault(n,v)
+ NAMPTR n;
+ STRING v;
+{
+ IF n->namval==0
+ THEN assign(n,v)
+ FI
+}
+
+assign(n,v)
+ NAMPTR n;
+ STRING v;
+{
+ IF n->namflg&N_RDONLY
+ THEN failed(n->namid,wtfailed);
+ ELSE replace(&n->namval,v);
+ FI
+}
+
+INT readvar(names)
+ STRING *names;
+{
+ FILEBLK fb;
+ REG FILE f = &fb;
+ REG CHAR c;
+ REG INT rc=0;
+ NAMPTR n=lookup(*names++); /* done now to avoid storage mess */
+ STKPTR rel=(STKPTR)relstak();
+
+ push(f); initf(dup(0));
+ IF lseek(0,0L,1)==-1
+ THEN f->fsiz=1;
+ FI
+
+ LOOP c=nextc(0);
+ IF (*names ANDF any(c, ifsnod.namval)) ORF eolchar(c)
+ THEN zerostak();
+ assign(n,absstak(rel)); setstak(rel);
+ IF *names
+ THEN n=lookup(*names++);
+ ELSE n=0;
+ FI
+ IF eolchar(c)
+ THEN break;
+ FI
+ ELSE pushstak(c);
+ FI
+ POOL
+ WHILE n
+ DO assign(n, nullstr);
+ IF *names THEN n=lookup(*names++); ELSE n=0; FI
+ OD
+
+ IF eof THEN rc=1 FI
+ lseek(0, (long)(f->fnxt-f->fend), 1);
+ pop();
+ return(rc);
+}
+
+assnum(p, i)
+ STRING *p;
+ INT i;
+{
+ itos(i); replace(p,numbuf);
+}
+
+STRING make(v)
+ STRING v;
+{
+ REG STRING p;
+
+ IF v
+ THEN movstr(v,p=alloc(length(v)));
+ return(p);
+ ELSE return(0);
+ FI
+}
+
+
+NAMPTR lookup(nam)
+ REG STRING nam;
+{
+ REG NAMPTR nscan=namep;
+ REG NAMPTR *prev;
+ INT LR;
+
+ IF !chkid(nam)
+ THEN failed(nam,notid);
+ FI
+ WHILE nscan
+ DO IF (LR=cf(nam,nscan->namid))==0
+ THEN return(nscan);
+ ELIF LR<0
+ THEN prev = &(nscan->namlft);
+ ELSE prev = &(nscan->namrgt);
+ FI
+ nscan = *prev;
+ OD
+
+ /* add name node */
+ nscan=(NAMPTR)alloc(sizeof *nscan);
+ nscan->namlft=nscan->namrgt=(NAMPTR)NIL;
+ nscan->namid=make(nam);
+ nscan->namval=0; nscan->namflg=N_DEFAULT; nscan->namenv=0;
+ return(*prev = nscan);
+}
+
+LOCAL BOOL chkid(nam)
+ STRING nam;
+{
+ REG CHAR * cp=nam;
+
+ IF !letter(*cp)
+ THEN return(FALSE);
+ ELSE WHILE *++cp
+ DO IF !alphanum(*cp)
+ THEN return(FALSE);
+ FI
+ OD
+ FI
+ return(TRUE);
+}
+
+LOCAL void (*namfn)();
+namscan(fn)
+ void (*fn)();
+{
+ namfn=fn;
+ namwalk(namep);
+}
+
+LOCAL void namwalk(np)
+ REG NAMPTR np;
+{
+ IF np
+ THEN namwalk(np->namlft);
+ (*namfn)(np);
+ namwalk(np->namrgt);
+ FI
+}
+
+void printnam(n)
+ NAMPTR n;
+{
+ REG STRING s;
+
+ sigchk();
+ IF s=n->namval
+ THEN prs(n->namid);
+ prc('='); prs(s);
+ newline();
+ FI
+}
+
+LOCAL STRING staknam(n)
+ REG NAMPTR n;
+{
+ REG STRING p;
+
+ p=movstr(n->namid,staktop);
+ p=movstr("=",p);
+ p=movstr(n->namval,p);
+ return(getstak(p+1-ADR(stakbot)));
+}
+
+void exname(n)
+ REG NAMPTR n;
+{
+ IF n->namflg&N_EXPORT
+ THEN free(n->namenv);
+ n->namenv = make(n->namval);
+ ELSE free(n->namval);
+ n->namval = make(n->namenv);
+ FI
+}
+
+void printflg(n)
+ REG NAMPTR n;
+{
+ IF n->namflg&N_EXPORT
+ THEN prs(export); blank();
+ FI
+ IF n->namflg&N_RDONLY
+ THEN prs(readonly); blank();
+ FI
+ IF n->namflg&(N_EXPORT|N_RDONLY)
+ THEN prs(n->namid); newline();
+ FI
+}
+
+void sh_getenv(void)
+{
+ REG STRING *e=environ;
+
+ WHILE *e
+ DO setname(*e++, N_ENVNAM) OD
+}
+
+LOCAL INT namec;
+
+void countnam(n)
+ NAMPTR n;
+{
+ namec++;
+}
+
+LOCAL STRING *argnam;
+
+void pushnam(n)
+ NAMPTR n;
+{
+ IF n->namval
+ THEN *argnam++ = staknam(n);
+ FI
+}
+
+STRING *sh_setenv(void)
+{
+ REG STRING *er;
+
+ namec=0;
+ namscan(countnam);
+ argnam = er = (STRING *)getstak(namec*BYTESPERWORD+BYTESPERWORD);
+ namscan(pushnam);
+ *argnam++ = 0;
+ return(er);
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+
+#define N_RDONLY 0100000
+#define N_EXPORT 0040000
+#define N_ENVNAM 0020000
+#define N_ENVPOS 0007777
+
+#define N_DEFAULT 0
+
+struct namnod {
+ NAMPTR namlft;
+ NAMPTR namrgt;
+ STRING namid;
+ STRING namval;
+ STRING namenv;
+ INT namflg;
+};
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+CHAR numbuf[6];
+
+
+/* printing and io conversion */
+
+newline()
+{ prc(NL);
+}
+
+blank()
+{ prc(SP);
+}
+
+prp()
+{
+ IF (flags&prompt)==0 ANDF cmdadr
+ THEN prs(cmdadr); prs(colon);
+ FI
+}
+
+void prs(as)
+ STRING as;
+{
+ REG STRING s;
+
+ IF s=as
+ THEN write(output,s,length(s)-1);
+ FI
+}
+
+void prc(c)
+ CHAR c;
+{
+ IF c
+ THEN write(output,&c,1);
+ FI
+}
+
+prt(t)
+ L_INT t;
+{
+ REG INT hr, min, sec;
+
+ t += 30; t /= 60;
+ sec=t%60; t /= 60;
+ min=t%60;
+ IF hr=t/60
+ THEN prn(hr); prc('h');
+ FI
+ prn(min); prc('m');
+ prn(sec); prc('s');
+}
+
+prn(n)
+ INT n;
+{
+ itos(n); prs(numbuf);
+}
+
+itos(n)
+{
+ REG char *abuf; REG POS a, i; INT pr, d;
+ abuf=numbuf; pr=FALSE; a=n;
+ FOR i=10000; i!=1; i/=10
+ DO IF (pr |= (d=a/i)) THEN *abuf++=d+'0' FI
+ a %= i;
+ OD
+ *abuf++=a+'0';
+ *abuf++=0;
+}
+
+stoi(icp)
+STRING icp;
+{
+ REG CHAR *cp = icp;
+ REG INT r = 0;
+ REG CHAR c;
+
+ WHILE (c = *cp, digit(c)) ANDF c ANDF r>=0
+ DO r = r*10 + c - '0'; cp++ OD
+ IF r<0 ORF cp==icp
+ THEN failed(icp,badnum);
+ ELSE return(r);
+ FI
+}
+
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+
+LOCAL STRING execs();
+LOCAL void gsort();
+LOCAL INT split();
+
+#define ARGMK 01
+
+INT errno;
+STRING sysmsg[];
+
+/* fault handling */
+#define ENOMEM 12
+#define ENOEXEC 8
+#define E2BIG 7
+#define ENOENT 2
+#define ETXTBSY 26
+
+
+
+/* service routines for `execute' */
+
+void initio(iop)
+ IOPTR iop;
+{
+ REG STRING ion;
+ REG INT iof, fd;
+
+ IF iop
+ THEN iof=iop->iofile;
+ ion=mactrim(iop->ioname);
+ IF *ion ANDF (flags&noexec)==0
+ THEN IF iof&IODOC
+ THEN subst(chkopen(ion),(fd=tmpfil()));
+ close(fd); fd=chkopen(tmpout); unlink(tmpout);
+ ELIF iof&IOMOV
+ THEN IF eq(minus,ion)
+ THEN fd = -1;
+ close(iof&IOUFD);
+ ELIF (fd=stoi(ion))>=USERIO
+ THEN failed(ion,badfile);
+ ELSE fd=dup(fd);
+ FI
+ ELIF (iof&IOPUT)==0
+ THEN fd=chkopen(ion);
+ ELIF flags&rshflg
+ THEN failed(ion,restricted);
+ ELIF iof&IOAPP ANDF (fd=open(ion,1))>=0
+ THEN lseek(fd, 0L, 2);
+ ELSE fd=create(ion);
+ FI
+ IF fd>=0
+ THEN sh_rename(fd,iof&IOUFD);
+ FI
+ FI
+ initio(iop->ionxt);
+ FI
+}
+
+STRING getpath(s)
+ STRING s;
+{
+ REG STRING path;
+ IF any('/',s)
+ THEN IF flags&rshflg
+ THEN failed(s, restricted);
+ ELSE return(nullstr);
+ FI
+ ELIF (path = pathnod.namval)==0
+ THEN return(defpath);
+ ELSE return(cpystak(path));
+ FI
+}
+
+INT pathopen(path, name)
+ REG STRING path, name;
+{
+ REG UFD f;
+
+ REP path=catpath(path,name);
+ PER (f=open(curstak(),0))<0 ANDF path DONE
+ return(f);
+}
+
+STRING catpath(path,name)
+ REG STRING path;
+ STRING name;
+{
+ /* leaves result on top of stack */
+ REG STRING scanp = path,
+ argp = locstak();
+
+ WHILE *scanp ANDF *scanp!=COLON DO *argp++ = *scanp++ OD
+ IF scanp!=path THEN *argp++='/' FI
+ IF *scanp==COLON THEN scanp++ FI
+ path=(*scanp ? scanp : 0); scanp=name;
+ WHILE (*argp++ = *scanp++) DONE
+ return(path);
+}
+
+LOCAL STRING xecmsg;
+LOCAL STRING *xecenv;
+
+void execa(at)
+ STRING at[];
+{
+ REG STRING path;
+ REG STRING *t = at;
+
+ IF (flags&noexec)==0
+ THEN xecmsg=notfound; path=getpath(*t);
+ namscan(exname);
+ xecenv=sh_setenv();
+ WHILE path=execs(path,t) DONE
+ failed(*t,xecmsg);
+ FI
+}
+
+LOCAL STRING execs(ap,t)
+ STRING ap;
+ REG STRING t[];
+{
+ REG STRING p, prefix;
+
+ prefix=catpath(ap,t[0]);
+ trim(p=curstak());
+
+ sigchk();
+ execve(p, &t[0] ,xecenv);
+ SWITCH errno IN
+
+ case ENOEXEC:
+ flags=0;
+ comdiv=0; ioset=0;
+ clearup(); /* remove open files and for loop junk */
+ IF input THEN close(input) FI
+ close(output); output=2;
+ input=chkopen(p);
+
+ /* set up new args */
+ setargs(t);
+ longjmp(subshell,1);
+
+ case ENOMEM:
+ failed(p,toobig);
+
+ case E2BIG:
+ failed(p,arglist);
+
+ case ETXTBSY:
+ failed(p,txtbsy);
+
+ default:
+ xecmsg=badexec;
+ case ENOENT:
+ return(prefix);
+ ENDSW
+}
+
+/* for processes to be waited for */
+#define MAXP 20
+LOCAL INT pwlist[MAXP];
+LOCAL INT pwc;
+
+postclr()
+{
+ REG INT *pw = pwlist;
+
+ WHILE pw <= &pwlist[pwc]
+ DO *pw++ = 0 OD
+ pwc=0;
+}
+
+void post(pcsid)
+ INT pcsid;
+{
+ REG INT *pw = pwlist;
+
+ IF pcsid
+ THEN WHILE *pw DO pw++ OD
+ IF pwc >= MAXP-1
+ THEN pw--;
+ ELSE pwc++;
+ FI
+ *pw = pcsid;
+ FI
+}
+
+void await(i)
+ INT i;
+{
+ INT rc=0, wx=0;
+ INT w;
+ INT ipwc = pwc;
+
+ post(i);
+ WHILE pwc
+ DO REG INT p;
+ REG INT sig;
+ INT w_hi;
+
+ BEGIN
+ REG INT *pw=pwlist;
+ p=wait(&w);
+ WHILE pw <= &pwlist[ipwc]
+ DO IF *pw==p
+ THEN *pw=0; pwc--;
+ ELSE pw++;
+ FI
+ OD
+ END
+
+ IF p == -1 THEN continue FI
+
+ w_hi = (w>>8)&LOBYTE;
+
+ IF sig = w&0177
+ THEN IF sig == 0177 /* ptrace! return */
+ THEN prs("ptrace: ");
+ sig = w_hi;
+ FI
+ IF sysmsg[sig]
+ THEN IF i!=p ORF (flags&prompt)==0 THEN prp(); prn(p); blank() FI
+ prs(sysmsg[sig]);
+ IF w&0200 THEN prs(coredump) FI
+ FI
+ newline();
+ FI
+
+ IF rc==0
+ THEN rc = (sig ? sig|SIGFLG : w_hi);
+ FI
+ wx |= w;
+ OD
+
+ IF wx ANDF flags&errflg
+ THEN exitsh(rc);
+ FI
+ exitval=rc; exitset();
+}
+
+BOOL nosubst;
+
+trim(at)
+ STRING at;
+{
+ REG STRING p;
+ REG CHAR c;
+ REG CHAR q=0;
+
+ IF p=at
+ THEN WHILE c = *p
+ DO *p++=c&STRIP; q |= c OD
+ FI
+ nosubst=q"E;
+}
+
+STRING mactrim(s)
+ STRING s;
+{
+ REG STRING t=macro(s);
+ trim(t);
+ return(t);
+}
+
+STRING *scan(argn)
+ INT argn;
+{
+ REG ARGPTR argp = (ARGPTR)(Rcheat(gchain)&~ARGMK);
+ REG STRING *comargn, *comargm;
+
+ comargn=(STRING *)getstak(BYTESPERWORD*argn+BYTESPERWORD); comargm = comargn += argn; *comargn = ENDARGS;
+
+ WHILE argp
+ DO *--comargn = argp->argval;
+ IF argp = argp->argnxt
+ THEN trim(*comargn);
+ FI
+ IF argp==0 ORF Rcheat(argp)&ARGMK
+ THEN gsort(comargn,comargm);
+ comargm = comargn;
+ FI
+ /* Lcheat(argp) &= ~ARGMK; */
+ argp = (ARGPTR)(Rcheat(argp)&~ARGMK);
+ OD
+ return(comargn);
+}
+
+LOCAL void gsort(from,to)
+ STRING from[], to[];
+{
+ INT k, m, n;
+ REG INT i, j;
+
+ IF (n=to-from)<=1 THEN return FI
+
+ FOR j=1; j<=n; j*=2 DONE
+
+ FOR m=2*j-1; m/=2;
+ DO k=n-m;
+ FOR j=0; j<k; j++
+ DO FOR i=j; i>=0; i-=m
+ DO REG STRING *fromi; fromi = &from[i];
+ IF cf(fromi[m],fromi[0])>0
+ THEN break;
+ ELSE STRING s; s=fromi[m]; fromi[m]=fromi[0]; fromi[0]=s;
+ FI
+ OD
+ OD
+ OD
+}
+
+/* Argument list generation */
+
+INT getarg(ac)
+ COMPTR ac;
+{
+ REG ARGPTR argp;
+ REG INT count=0;
+ REG COMPTR c;
+
+ IF c=ac
+ THEN argp=c->comarg;
+ WHILE argp
+ DO count += split(macro(argp->argval));
+ argp=argp->argnxt;
+ OD
+ FI
+ return(count);
+}
+
+LOCAL INT split(s)
+ REG STRING s;
+{
+ REG STRING argp;
+ REG INT c;
+ INT count=0;
+
+ LOOP sigchk(); argp=locstak()+BYTESPERWORD;
+ WHILE (c = *s++, !any(c,ifsnod.namval) && c)
+ DO *argp++ = c OD
+ IF argp==staktop+BYTESPERWORD
+ THEN IF c
+ THEN continue;
+ ELSE return(count);
+ FI
+ ELIF c==0
+ THEN s--;
+ FI
+ IF c=expand(((ARGPTR)(argp=endstak(argp)))->argval,0)
+ THEN count += c;
+ ELSE /* assign(&fngnod, argp->argval); */
+ makearg(argp); count++;
+ FI
+ Lcheat(gchain) |= ARGMK;
+ POOL
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+void *setbrk(intptr_t incr)
+{
+ uint8_t *a = sbrk(incr);
+ brkend = a + incr;
+ return a;
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+STKPTR stakbot=nullstr;
+
+
+
+/* ======== storage allocation ======== */
+
+STKPTR getstak(asize)
+ INT asize;
+{ /* allocate requested stack */
+ REG STKPTR oldstak;
+ REG INT size;
+
+ size=round(asize,BYTESPERWORD);
+ oldstak=stakbot;
+ staktop = stakbot += size;
+ return(oldstak);
+}
+
+STKPTR locstak()
+{ /* set up stack for local use
+ * should be followed by `endstak'
+ */
+ IF brkend-stakbot<BRKINCR
+ THEN setbrk(brkincr);
+ IF brkincr < BRKMAX
+ THEN brkincr += 256;
+ FI
+ FI
+ return(stakbot);
+}
+
+STKPTR savstak()
+{
+ assert(staktop==stakbot);
+ return(stakbot);
+}
+
+STKPTR endstak(argp)
+ REG STRING argp;
+{ /* tidy up after `locstak' */
+ REG STKPTR oldstak;
+ *argp++=0;
+ oldstak=stakbot; stakbot=staktop=(STKPTR)round(argp,BYTESPERWORD);
+ return(oldstak);
+}
+
+void tdystak(x)
+ REG STKPTR x;
+{
+ /* try to bring stack back to x */
+ WHILE ADR(stakbsy)>ADR(x)
+ DO free(stakbsy);
+ stakbsy = stakbsy->word;
+ OD
+ staktop=stakbot=max(ADR(x),ADR(stakbas));
+ rmtemp(x);
+}
+
+stakchk()
+{
+ IF (brkend-stakbas)>BRKINCR+BRKINCR
+ THEN setbrk(-BRKINCR);
+ FI
+}
+
+STKPTR cpystak(x)
+ STKPTR x;
+{
+ return(endstak(movstr(x,locstak())));
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+/* To use stack as temporary workspace across
+ * possible storage allocation (eg name lookup)
+ * a) get ptr from `relstak'
+ * b) can now use `pushstak'
+ * c) then reset with `setstak'
+ * d) `absstak' gives real address if needed
+ */
+#define relstak() (staktop-stakbot)
+#define absstak(x) (stakbot+Rcheat(x))
+#define setstak(x) (staktop=absstak(x))
+#define pushstak(c) (*staktop++=(c))
+#define zerostak() (*staktop=0)
+
+/* Used to address an item left on the top of
+ * the stack (very temporary)
+ */
+#define curstak() (staktop)
+
+/* `usestak' before `pushstak' then `fixstak'
+ * These routines are safe against heap
+ * being allocated.
+ */
+#define usestak() {locstak();}
+
+/* for local use only since it hands
+ * out a real address for the stack top
+ */
+STKPTR locstak();
+
+/* Will allocate the item being used and return its
+ * address (safe now).
+ */
+#define fixstak() endstak(staktop)
+
+/* For use after `locstak' to hand back
+ * new stack top and then allocate item
+ */
+STKPTR endstak();
+
+/* Copy a string onto the stack and
+ * allocate the space.
+ */
+STKPTR cpystak();
+
+/* Allocate given ammount of stack space */
+STKPTR getstak();
+
+/* A chain of ptrs of stack blocks that
+ * have become covered by heap allocation.
+ * `tdystak' will return them to the heap.
+ */
+BLKPTR stakbsy;
+
+/* Base of the entire stack */
+STKPTR stakbas;
+
+/* Top of entire stack */
+STKPTR brkend;
+
+/* Base of current item */
+STKPTR stakbot;
+
+/* Top of current item */
+STKPTR staktop;
+
+/* Used with tdystak */
+STKPTR savstak();
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+
+
+/* ======== general purpose string handling ======== */
+
+
+STRING movstr(a,b)
+ REG STRING a, b;
+{
+ WHILE *b++ = *a++ DONE
+ return(--b);
+}
+
+INT any(c,s)
+ REG CHAR c;
+ STRING s;
+{
+ REG CHAR d;
+
+ WHILE d = *s++
+ DO IF d==c
+ THEN return(TRUE);
+ FI
+ OD
+ return(FALSE);
+}
+
+INT cf(s1, s2)
+ REG STRING s1, s2;
+{
+ WHILE *s1++ == *s2
+ DO IF *s2++==0
+ THEN return(0);
+ FI
+ OD
+ return(*--s1 - *s2);
+}
+
+INT length(as)
+ STRING as;
+{
+ REG STRING s;
+
+ IF s=as THEN WHILE *s++ DONE FI
+ return(s-as);
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ */
+
+
+/* symbols for parsing */
+#define DOSYM 0405
+#define FISYM 0420
+#define EFSYM 0422
+#define ELSYM 0421
+#define INSYM 0412
+#define BRSYM 0406
+#define KTSYM 0450
+#define THSYM 0444
+#define ODSYM 0441
+#define ESSYM 0442
+#define IFSYM 0436
+#define FORSYM 0435
+#define WHSYM 0433
+#define UNSYM 0427
+#define CASYM 0417
+
+#define SYMREP 04000
+#define ECSYM (SYMREP|';')
+#define ANDFSYM (SYMREP|'&')
+#define ORFSYM (SYMREP|'|')
+#define APPSYM (SYMREP|'>')
+#define DOCSYM (SYMREP|'<')
+#define EOFSYM 02000
+#define SYMFLG 0400
+
+/* arg to `cmd' */
+#define NLFLG 1
+#define MTFLG 2
+
+/* for peekc */
+#define MARK 0100000
+
+/* odd chars */
+#define DQUOTE '"'
+#define SQUOTE '`'
+#define LITERAL '\''
+#define DOLLAR '$'
+#define ESCAPE '\\'
+#define BRACE '{'
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#define TIMEOUT 0
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+#include "sym.h"
+
+LOCAL readb();
+
+
+/* ======== character handling for command lines ========*/
+
+
+word()
+{
+ REG CHAR c, d;
+ REG CHAR *argp=locstak()+BYTESPERWORD;
+ INT alpha=1;
+
+ wdnum=0; wdset=0;
+
+ WHILE (c=nextc(0), space(c)) DONE
+ IF !eofmeta(c)
+ THEN REP IF c==LITERAL
+ THEN *argp++=(DQUOTE);
+ WHILE (c=readc()) ANDF c!=LITERAL
+ DO *argp++=(c|QUOTE); chkpr(c) OD
+ *argp++=(DQUOTE);
+ ELSE *argp++=(c);
+ IF c=='=' THEN wdset |= alpha FI
+ IF !alphanum(c) THEN alpha=0 FI
+ IF qotchar(c)
+ THEN d=c;
+ WHILE (*argp++=(c=nextc(d))) ANDF c!=d
+ DO chkpr(c) OD
+ FI
+ FI
+ PER (c=nextc(0), !eofmeta(c)) DONE
+ argp=endstak(argp);
+ IF !letter(((ARGPTR)argp)->argval[0]) THEN wdset=0 FI
+
+ peekc=c|MARK;
+ IF ((ARGPTR)argp)->argval[1]==0 ANDF (d=((ARGPTR)argp)->argval[0], digit(d)) ANDF (c=='>' ORF c=='<')
+ THEN word(); wdnum=d-'0';
+ ELSE /*check for reserved words*/
+ IF reserv==FALSE ORF (wdval=syslook(((ARGPTR)argp)->argval,reserved))==0
+ THEN wdarg=(ARGPTR)argp; wdval=0;
+ FI
+ FI
+
+ ELIF dipchar(c)
+ THEN IF (d=nextc(0))==c
+ THEN wdval = c|SYMREP;
+ ELSE peekc = d|MARK; wdval = c;
+ FI
+ ELSE IF (wdval=c)==EOF
+ THEN wdval=EOFSYM;
+ FI
+ IF iopend ANDF eolchar(c)
+ THEN copy(iopend); iopend=0;
+ FI
+ FI
+ reserv=FALSE;
+ return(wdval);
+}
+
+nextc(quote)
+ CHAR quote;
+{
+ REG CHAR c, d;
+ IF (d=readc())==ESCAPE
+ THEN IF (c=readc())==NL
+ THEN chkpr(NL); d=nextc(quote);
+ ELIF quote ANDF c!=quote ANDF !escchar(c)
+ THEN peekc=c|MARK;
+ ELSE d = c|QUOTE;
+ FI
+ FI
+ return(d);
+}
+
+readc()
+{
+ REG CHAR c;
+ REG INT len;
+ REG FILE f;
+
+retry:
+ IF peekc
+ THEN c=peekc; peekc=0;
+ ELIF (f=standin, f->fnxt!=f->fend)
+ THEN IF (c = *f->fnxt++)==0
+ THEN IF f->feval
+ THEN IF estabf(*f->feval++)
+ THEN c=EOF;
+ ELSE c=SP;
+ FI
+ ELSE goto retry; /* = c=readc(); */
+ FI
+ FI
+ IF flags&readpr ANDF standin->fstak==0 THEN prc(c) FI
+ IF c==NL THEN f->flin++ FI
+ ELIF f->feof ORF f->fdes<0
+ THEN c=EOF; f->feof++;
+ ELIF (len=readb())<=0
+ THEN close(f->fdes); f->fdes = -1; c=EOF; f->feof++;
+ ELSE f->fend = (f->fnxt = f->fbuf)+len;
+ goto retry;
+ FI
+ return(c);
+}
+
+LOCAL readb()
+{
+ REG FILE f=standin;
+ REG INT len;
+
+ REP IF trapnote&SIGSET THEN newline(); sigchk() FI
+ PER (len=read(f->fdes,f->fbuf,f->fsiz))<0 ANDF trapnote DONE
+ return(len);
+}
--- /dev/null
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+/* Changes: Copyright (c) 1999 Robert Nordier. All rights reserved. */
+
+#
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Bell Telephone Laboratories
+ *
+ */
+
+#include "defs.h"
+#include "sym.h"
+
+LOCAL INT parent;
+
+SYSTAB commands;
+
+
+
+/* ======== command execution ========*/
+
+
+execute(argt, execflg, pf1, pf2)
+ TREPTR argt;
+ INT *pf1, *pf2;
+{
+ /* `stakbot' is preserved by this routine */
+ REG TREPTR t;
+ STKPTR sav=savstak();
+
+ sigchk();
+
+ IF (t=argt) ANDF execbrk==0
+ THEN REG INT treeflgs;
+ INT oldexit, type;
+ REG STRING *com;
+
+ treeflgs = t->tretyp; type = treeflgs&COMMSK;
+ oldexit=exitval; exitval=0;
+
+ SWITCH type IN
+
+ case TCOM:
+ BEGIN
+ STRING a1;
+ INT argn, internal;
+ ARGPTR schain=gchain;
+ IOPTR io=t->treio;
+ gchain=0;
+ argn = getarg(t);
+ com=scan(argn);
+ a1=com[1]; gchain=schain;
+
+ IF (internal=syslook(com[0],commands)) ORF argn==0
+ THEN setlist(((COMPTR)t)->comset, 0);
+ FI
+
+ IF argn ANDF (flags&noexec)==0
+ THEN /* print command if execpr */
+ IF flags&execpr
+ THEN argn=0; prs(execpmsg);
+ WHILE com[argn]!=ENDARGS
+ DO prs(com[argn++]); blank() OD
+ newline();
+ FI
+
+ SWITCH internal IN
+
+ case SYSDOT:
+ IF a1
+ THEN REG INT f;
+
+ IF (f=pathopen(getpath(a1), a1)) < 0
+ THEN failed(a1,notfound);
+ ELSE execexp(0,f);
+ FI
+ FI
+ break;
+
+ case SYSTIMES:
+ {
+ L_INT t[4]; times(t);
+ prt(t[2]); blank(); prt(t[3]); newline();
+ }
+ break;
+
+ case SYSEXIT:
+ exitsh(a1?stoi(a1):oldexit);
+
+ case SYSNULL:
+ io=0;
+ break;
+
+ case SYSCONT:
+ execbrk = -loopcnt; break;
+
+ case SYSBREAK:
+ IF (execbrk=loopcnt) ANDF a1
+ THEN breakcnt=stoi(a1);
+ FI
+ break;
+
+ case SYSTRAP:
+ IF a1
+ THEN BOOL clear;
+ IF (clear=digit(*a1))==0
+ THEN ++com;
+ FI
+ WHILE *++com
+ DO INT i;
+ IF (i=stoi(*com))>=MAXTRAP ORF i<MINTRAP
+ THEN failed(*com,badtrap);
+ ELIF clear
+ THEN clrsig(i);
+ ELSE replace(&trapcom[i],a1);
+ IF *a1
+ THEN getsig(i);
+ ELSE ignsig(i);
+ FI
+ FI
+ OD
+ ELSE /* print out current traps */
+ INT i;
+
+ FOR i=0; i<MAXTRAP; i++
+ DO IF trapcom[i]
+ THEN prn(i); prs(colon); prs(trapcom[i]); newline();
+ FI
+ OD
+ FI
+ break;
+
+ case SYSEXEC:
+ com++;
+ initio(io); ioset=0; io=0;
+ IF a1==0 THEN break FI
+
+ case SYSLOGIN:
+ flags |= forked;
+ oldsigs(); execa(com); done();
+
+ case SYSCD:
+ IF flags&rshflg
+ THEN failed(com[0],restricted);
+ ELIF (a1==0 ANDF (a1=homenod.namval)==0) ORF chdir(a1)<0
+ THEN failed(a1,baddir);
+ FI
+ break;
+
+ case SYSSHFT:
+ IF dolc<1
+ THEN error(badshift);
+ ELSE dolv++; dolc--;
+ FI
+ assnum(&dolladr, dolc);
+ break;
+
+ case SYSWAIT:
+ await(-1);
+ break;
+
+ case SYSREAD:
+ exitval=readvar(&com[1]);
+ break;
+
+/*
+ case SYSTST:
+ exitval=testcmd(com);
+ break;
+*/
+
+ case SYSSET:
+ IF a1
+ THEN INT argc;
+ argc = options(argn,com);
+ IF argc>1
+ THEN setargs(com+argn-argc);
+ FI
+ ELIF ((COMPTR)t)->comset==0
+ THEN /*scan name chain and print*/
+ namscan(printnam);
+ FI
+ break;
+
+ case SYSRDONLY:
+ exitval=N_RDONLY;
+ case SYSXPORT:
+ IF exitval==0 THEN exitval=N_EXPORT; FI
+
+ IF a1
+ THEN WHILE *++com
+ DO attrib(lookup(*com), exitval) OD
+ ELSE namscan(printflg);
+ FI
+ exitval=0;
+ break;
+
+ case SYSEVAL:
+ IF a1
+ THEN execexp(a1,&com[2]);
+ FI
+ break;
+
+ case SYSUMASK:
+ if (a1) {
+ int c, i;
+ i = 0;
+ while ((c = *a1++) >= '0' &&
+ c <= '7')
+ i = (i << 3) + c - '0';
+ umask(i);
+ } else {
+ int i, j;
+ umask(i = umask(0));
+ prc('0');
+ for (j = 6; j >= 0; j -= 3)
+ prc(((i>>j)&07) + '0');
+ newline();
+ }
+ break;
+
+ default:
+ internal=builtin(argn,com);
+
+ ENDSW
+
+ IF internal
+ THEN IF io THEN error(illegal) FI
+ chktrap();
+ break;
+ FI
+ ELIF t->treio==0
+ THEN break;
+ FI
+ END
+
+ case TFORK:
+ IF execflg ANDF (treeflgs&(FAMP|FPOU))==0
+ THEN parent=0;
+ ELSE WHILE (parent=fork()) == -1
+ DO sigchk(); alarm(10); pause() OD
+ FI
+
+ IF parent
+ THEN /* This is the parent branch of fork; */
+ /* it may or may not wait for the child. */
+ IF treeflgs&FPRS ANDF flags&ttyflg
+ THEN prn(parent); newline();
+ FI
+ IF treeflgs&FPCL THEN closepipe(pf1) FI
+ IF (treeflgs&(FAMP|FPOU))==0
+ THEN await(parent);
+ ELIF (treeflgs&FAMP)==0
+ THEN post(parent);
+ ELSE assnum(&pcsadr, parent);
+ FI
+
+ chktrap();
+ break;
+
+
+ ELSE /* this is the forked branch (child) of execute */
+ flags |= forked; iotemp=0;
+ postclr();
+ settmp();
+
+ /* Turn off INTR and QUIT if `FINT' */
+ /* Reset ramaining signals to parent */
+ /* except for those `lost' by trap */
+ oldsigs();
+ IF treeflgs&FINT
+ THEN signal(INTR,1); signal(QUIT,1);
+ FI
+
+ /* pipe in or out */
+ IF treeflgs&FPIN
+ THEN sh_rename(pf1[INPIPE],0);
+ close(pf1[OTPIPE]);
+ FI
+ IF treeflgs&FPOU
+ THEN sh_rename(pf2[OTPIPE],1);
+ close(pf2[INPIPE]);
+ FI
+
+ /* default std input for & */
+ IF treeflgs&FINT ANDF ioset==0
+ THEN sh_rename(chkopen(devnull),0);
+ FI
+
+ /* io redirection */
+ initio(t->treio);
+ IF type!=TCOM
+ THEN execute(((FORKPTR)t)->forktre,1);
+ ELIF com[0]!=ENDARGS
+ THEN setlist(((COMPTR)t)->comset,N_EXPORT);
+ execa(com);
+ FI
+ done();
+ FI
+
+ case TPAR:
+ sh_rename(dup(2),output);
+ execute(((PARPTR)t)->partre,execflg);
+ done();
+
+ case TFIL:
+ BEGIN
+ INT pv[2]; chkpipe(pv);
+ IF execute(((LSTPTR)t)->lstlef, 0, pf1, pv)==0
+ THEN execute(((LSTPTR)t)->lstrit, execflg, pv, pf2);
+ ELSE closepipe(pv);
+ FI
+ END
+ break;
+
+ case TLST:
+ execute(((LSTPTR)t)->lstlef,0);
+ execute(((LSTPTR)t)->lstrit,execflg);
+ break;
+
+ case TAND:
+ IF execute(((LSTPTR)t)->lstlef,0)==0
+ THEN execute(((LSTPTR)t)->lstrit,execflg);
+ FI
+ break;
+
+ case TORF:
+ IF execute(((LSTPTR)t)->lstlef,0)!=0
+ THEN execute(((LSTPTR)t)->lstrit,execflg);
+ FI
+ break;
+
+ case TFOR:
+ BEGIN
+ NAMPTR n = lookup(((FORPTR)t)->fornam);
+ STRING *args;
+ DOLPTR argsav=0;
+
+ IF ((FORPTR)t)->forlst==0
+ THEN args=dolv+1;
+ argsav=useargs();
+ ELSE ARGPTR schain=gchain;
+ gchain=0;
+ trim((args=scan(getarg(((FORPTR)t)->forlst)))[0]);
+ gchain=schain;
+ FI
+ loopcnt++;
+ WHILE *args!=ENDARGS ANDF execbrk==0
+ DO assign(n,*args++);
+ execute(((FORPTR)t)->fortre,0);
+ IF execbrk<0 THEN execbrk=0 FI
+ OD
+ IF breakcnt THEN breakcnt-- FI
+ execbrk=breakcnt; loopcnt--;
+ argfor=freeargs(argsav);
+ END
+ break;
+
+ case TWH:
+ case TUN:
+ BEGIN
+ INT i=0;
+
+ loopcnt++;
+ WHILE execbrk==0 ANDF (execute(((WHPTR)t)->whtre,0)==0)==(type==TWH)
+ DO i=execute(((WHPTR)t)->dotre,0);
+ IF execbrk<0 THEN execbrk=0 FI
+ OD
+ IF breakcnt THEN breakcnt-- FI
+ execbrk=breakcnt; loopcnt--; exitval=i;
+ END
+ break;
+
+ case TIF:
+ IF execute(((IFPTR)t)->iftre,0)==0
+ THEN execute(((IFPTR)t)->thtre,execflg);
+ ELSE execute(((IFPTR)t)->eltre,execflg);
+ FI
+ break;
+
+ case TSW:
+ BEGIN
+ REG STRING r = mactrim(((SWPTR)t)->swarg);
+ t=(TREPTR)((SWPTR)t)->swlst;
+ WHILE t
+ DO ARGPTR rex=((REGPTR)t)->regptr;
+ WHILE rex
+ DO REG STRING s;
+ IF gmatch(r,s=macro(rex->argval)) ORF (trim(s), eq(r,s))
+ THEN execute(((REGPTR)t)->regcom,0);
+ t=0; break;
+ ELSE rex=((ARGPTR)rex)->argnxt;
+ FI
+ OD
+ IF t THEN t=(TREPTR)((REGPTR)t)->regnxt FI
+ OD
+ END
+ break;
+ ENDSW
+ exitset();
+ FI
+
+ sigchk();
+ tdystak(sav);
+ return(exitval);
+}
+
+
+execexp(s,f)
+ STRING s;
+ UFD f;
+{
+ FILEBLK fb;
+ push(&fb);
+ IF s
+ THEN estabf(s); fb.feval=(STRING *)f;
+ ELIF f>=0
+ THEN initf(f);
+ FI
+ execute(cmd(NL, NLFLG|MTFLG),0);
+ pop();
+}