/bin/sh: Minimal changes to get the real Bourne shell building
authorAlan Cox <alan@linux.intel.com>
Sat, 9 May 2015 23:14:15 +0000 (00:14 +0100)
committerAlan Cox <alan@linux.intel.com>
Sat, 9 May 2015 23:14:15 +0000 (00:14 +0100)
There is a *lot* to do here to get this working (including writing setjmp
and longjmp for the 6809 port!). Getting it working on the other compilers
will need full ansification

Also note FIXME pieces for other bodges that will need dealing with before
its useful

Still it weights in at 28K so it should just about fit with some care on a
Dragon-nx-32 !

32 files changed:
Applications/V7/cmd/sh/Makefile.6809 [new file with mode: 0644]
Applications/V7/cmd/sh/args.c [new file with mode: 0644]
Applications/V7/cmd/sh/blok.c [new file with mode: 0644]
Applications/V7/cmd/sh/brkincr.h [new file with mode: 0644]
Applications/V7/cmd/sh/builtin.c [new file with mode: 0644]
Applications/V7/cmd/sh/cmd.c [new file with mode: 0644]
Applications/V7/cmd/sh/ctype.c [new file with mode: 0644]
Applications/V7/cmd/sh/ctype.h [new file with mode: 0644]
Applications/V7/cmd/sh/defs.h [new file with mode: 0644]
Applications/V7/cmd/sh/dup.h [new file with mode: 0644]
Applications/V7/cmd/sh/error.c [new file with mode: 0644]
Applications/V7/cmd/sh/expand.c [new file with mode: 0644]
Applications/V7/cmd/sh/fault.c [new file with mode: 0644]
Applications/V7/cmd/sh/glob.c [new file with mode: 0644]
Applications/V7/cmd/sh/io.c [new file with mode: 0644]
Applications/V7/cmd/sh/mac.h [new file with mode: 0644]
Applications/V7/cmd/sh/macro.c [new file with mode: 0644]
Applications/V7/cmd/sh/main.c [new file with mode: 0644]
Applications/V7/cmd/sh/mode.h [new file with mode: 0644]
Applications/V7/cmd/sh/msg.c [new file with mode: 0644]
Applications/V7/cmd/sh/name.c [new file with mode: 0644]
Applications/V7/cmd/sh/name.h [new file with mode: 0644]
Applications/V7/cmd/sh/print.c [new file with mode: 0644]
Applications/V7/cmd/sh/service.c [new file with mode: 0644]
Applications/V7/cmd/sh/setbrk.c [new file with mode: 0644]
Applications/V7/cmd/sh/stak.c [new file with mode: 0644]
Applications/V7/cmd/sh/stak.h [new file with mode: 0644]
Applications/V7/cmd/sh/string.c [new file with mode: 0644]
Applications/V7/cmd/sh/sym.h [new file with mode: 0644]
Applications/V7/cmd/sh/timeout.h [new file with mode: 0644]
Applications/V7/cmd/sh/word.c [new file with mode: 0644]
Applications/V7/cmd/sh/xec.c [new file with mode: 0644]

diff --git a/Applications/V7/cmd/sh/Makefile.6809 b/Applications/V7/cmd/sh/Makefile.6809
new file mode 100644 (file)
index 0000000..e51101e
--- /dev/null
@@ -0,0 +1,46 @@
+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
diff --git a/Applications/V7/cmd/sh/args.c b/Applications/V7/cmd/sh/args.c
new file mode 100644 (file)
index 0000000..c92e551
--- /dev/null
@@ -0,0 +1,140 @@
+/* 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
+}
diff --git a/Applications/V7/cmd/sh/blok.c b/Applications/V7/cmd/sh/blok.c
new file mode 100644 (file)
index 0000000..0a6686d
--- /dev/null
@@ -0,0 +1,113 @@
+/* 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
diff --git a/Applications/V7/cmd/sh/brkincr.h b/Applications/V7/cmd/sh/brkincr.h
new file mode 100644 (file)
index 0000000..9c26e13
--- /dev/null
@@ -0,0 +1,4 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#define BRKINCR 01000
+#define BRKMAX 04000
diff --git a/Applications/V7/cmd/sh/builtin.c b/Applications/V7/cmd/sh/builtin.c
new file mode 100644 (file)
index 0000000..50aca07
--- /dev/null
@@ -0,0 +1,4 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+builtin()
+{return(0);}
diff --git a/Applications/V7/cmd/sh/cmd.c b/Applications/V7/cmd/sh/cmd.c
new file mode 100644 (file)
index 0000000..d539b33
--- /dev/null
@@ -0,0 +1,416 @@
+/* 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);
+}
diff --git a/Applications/V7/cmd/sh/ctype.c b/Applications/V7/cmd/sh/ctype.c
new file mode 100644 (file)
index 0000000..d7eadc8
--- /dev/null
@@ -0,0 +1,111 @@
+/* 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
+};
+
diff --git a/Applications/V7/cmd/sh/ctype.h b/Applications/V7/cmd/sh/ctype.h
new file mode 100644 (file)
index 0000000..e50019a
--- /dev/null
@@ -0,0 +1,92 @@
+/* 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)&QUOTE)==0 ANDF _ctype1[c]&(T_SPC))
+#define eofmeta(c)     (((c)&QUOTE)==0 ANDF _ctype1[c]&(_META|T_EOF))
+#define qotchar(c)     (((c)&QUOTE)==0 ANDF _ctype1[c]&(T_QOT))
+#define eolchar(c)     (((c)&QUOTE)==0 ANDF _ctype1[c]&(T_EOR|T_EOF))
+#define dipchar(c)     (((c)&QUOTE)==0 ANDF _ctype1[c]&(T_DIP))
+#define subchar(c)     (((c)&QUOTE)==0 ANDF _ctype1[c]&(T_SUB|T_QOT))
+#define escchar(c)     (((c)&QUOTE)==0 ANDF _ctype1[c]&(T_ESC))
+
+extern char    _ctype2[];
+
+#define        digit(c)        (((c)&QUOTE)==0 ANDF _ctype2[c]&(T_DIG))
+#define fngchar(c)     (((c)&QUOTE)==0 ANDF _ctype2[c]&(T_FNG))
+#define dolchar(c)     (((c)&QUOTE)==0 ANDF _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN))
+#define defchar(c)     (((c)&QUOTE)==0 ANDF _ctype2[c]&(T_DEF))
+#define setchar(c)     (((c)&QUOTE)==0 ANDF _ctype2[c]&(T_SET))
+#define digchar(c)     (((c)&QUOTE)==0 ANDF _ctype2[c]&(T_AST|T_DIG))
+#define        letter(c)       (((c)&QUOTE)==0 ANDF _ctype2[c]&(T_IDC))
+#define alphanum(c)    (((c)&QUOTE)==0 ANDF _ctype2[c]&(_IDCH))
+#define astchar(c)     (((c)&QUOTE)==0 ANDF _ctype2[c]&(T_AST))
diff --git a/Applications/V7/cmd/sh/defs.h b/Applications/V7/cmd/sh/defs.h
new file mode 100644 (file)
index 0000000..a461953
--- /dev/null
@@ -0,0 +1,294 @@
+/* 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"
+
diff --git a/Applications/V7/cmd/sh/dup.h b/Applications/V7/cmd/sh/dup.h
new file mode 100644 (file)
index 0000000..1818e91
--- /dev/null
@@ -0,0 +1,12 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ *     UNIX shell
+ *
+ *     S. R. Bourne
+ *     Bell Telephone Laboratories
+ *
+ */
+
+#define DUPFLG 0100
diff --git a/Applications/V7/cmd/sh/error.c b/Applications/V7/cmd/sh/error.c
new file mode 100644 (file)
index 0000000..9b6bf2b
--- /dev/null
@@ -0,0 +1,85 @@
+/* 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
+}
diff --git a/Applications/V7/cmd/sh/expand.c b/Applications/V7/cmd/sh/expand.c
new file mode 100644 (file)
index 0000000..97fdcb5
--- /dev/null
@@ -0,0 +1,194 @@
+/* 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;
+}
+
diff --git a/Applications/V7/cmd/sh/fault.c b/Applications/V7/cmd/sh/fault.c
new file mode 100644 (file)
index 0000000..c3a69cd
--- /dev/null
@@ -0,0 +1,114 @@
+/* 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
+}
diff --git a/Applications/V7/cmd/sh/glob.c b/Applications/V7/cmd/sh/glob.c
new file mode 100644 (file)
index 0000000..a9ed719
--- /dev/null
@@ -0,0 +1,40 @@
+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
diff --git a/Applications/V7/cmd/sh/io.c b/Applications/V7/cmd/sh/io.c
new file mode 100644 (file)
index 0000000..4d04a9c
--- /dev/null
@@ -0,0 +1,135 @@
+/* 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
+}
diff --git a/Applications/V7/cmd/sh/mac.h b/Applications/V7/cmd/sh/mac.h
new file mode 100644 (file)
index 0000000..29e5b95
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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))
diff --git a/Applications/V7/cmd/sh/macro.c b/Applications/V7/cmd/sh/macro.c
new file mode 100644 (file)
index 0000000..7f5eccf
--- /dev/null
@@ -0,0 +1,239 @@
+/* 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;
+}
diff --git a/Applications/V7/cmd/sh/main.c b/Applications/V7/cmd/sh/main.c
new file mode 100644 (file)
index 0000000..a1cd5e8
--- /dev/null
@@ -0,0 +1,178 @@
+/* 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);
+}
diff --git a/Applications/V7/cmd/sh/mode.h b/Applications/V7/cmd/sh/mode.h
new file mode 100644 (file)
index 0000000..d02b9a9
--- /dev/null
@@ -0,0 +1,202 @@
+/* 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))
diff --git a/Applications/V7/cmd/sh/msg.c b/Applications/V7/cmd/sh/msg.c
new file mode 100644 (file)
index 0000000..53a1c7e
--- /dev/null
@@ -0,0 +1,139 @@
+/* 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},
+};
diff --git a/Applications/V7/cmd/sh/name.c b/Applications/V7/cmd/sh/name.c
new file mode 100644 (file)
index 0000000..290d568
--- /dev/null
@@ -0,0 +1,324 @@
+/* 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);
+}
diff --git a/Applications/V7/cmd/sh/name.h b/Applications/V7/cmd/sh/name.h
new file mode 100644 (file)
index 0000000..c444fae
--- /dev/null
@@ -0,0 +1,27 @@
+/* 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;
+};
diff --git a/Applications/V7/cmd/sh/print.c b/Applications/V7/cmd/sh/print.c
new file mode 100644 (file)
index 0000000..0821c10
--- /dev/null
@@ -0,0 +1,99 @@
+/* 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
+}
+
diff --git a/Applications/V7/cmd/sh/service.c b/Applications/V7/cmd/sh/service.c
new file mode 100644 (file)
index 0000000..2df4599
--- /dev/null
@@ -0,0 +1,370 @@
+/* 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&QUOTE;
+}
+
+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
+}
diff --git a/Applications/V7/cmd/sh/setbrk.c b/Applications/V7/cmd/sh/setbrk.c
new file mode 100644 (file)
index 0000000..618edf7
--- /dev/null
@@ -0,0 +1,19 @@
+/* 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;
+}
diff --git a/Applications/V7/cmd/sh/stak.c b/Applications/V7/cmd/sh/stak.c
new file mode 100644 (file)
index 0000000..4669e69
--- /dev/null
@@ -0,0 +1,84 @@
+/* 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())));
+}
diff --git a/Applications/V7/cmd/sh/stak.h b/Applications/V7/cmd/sh/stak.h
new file mode 100644 (file)
index 0000000..115b92b
--- /dev/null
@@ -0,0 +1,78 @@
+/* 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();
diff --git a/Applications/V7/cmd/sh/string.c b/Applications/V7/cmd/sh/string.c
new file mode 100644 (file)
index 0000000..1c80d1f
--- /dev/null
@@ -0,0 +1,57 @@
+/* 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);
+}
diff --git a/Applications/V7/cmd/sh/sym.h b/Applications/V7/cmd/sh/sym.h
new file mode 100644 (file)
index 0000000..ac0d78b
--- /dev/null
@@ -0,0 +1,48 @@
+/* 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  '{'
diff --git a/Applications/V7/cmd/sh/timeout.h b/Applications/V7/cmd/sh/timeout.h
new file mode 100644 (file)
index 0000000..83ba182
--- /dev/null
@@ -0,0 +1,12 @@
+/* UNIX V7 source code: see /COPYRIGHT or www.tuhs.org for details. */
+
+#
+/*
+ *     UNIX shell
+ *
+ *     S. R. Bourne
+ *     Bell Telephone Laboratories
+ *
+ */
+
+#define TIMEOUT 0
diff --git a/Applications/V7/cmd/sh/word.c b/Applications/V7/cmd/sh/word.c
new file mode 100644 (file)
index 0000000..294bcaa
--- /dev/null
@@ -0,0 +1,129 @@
+/* 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);
+}
diff --git a/Applications/V7/cmd/sh/xec.c b/Applications/V7/cmd/sh/xec.c
new file mode 100644 (file)
index 0000000..3db942f
--- /dev/null
@@ -0,0 +1,424 @@
+/* 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();
+}