#
/*
	11/26/75		mod3.30.04
	*/

#define	INTR	2
#define	QUIT	3
#define	LINSIZ	1024
#define	ARGSIZ	50
#define	STKSIZ	10
#define	TRESIZ	128
#define	SCCMODE	0100000
#define	QUOTE	0200

#define	GLOB	"/etc/glob"
#define	GOTO	"/bin/goto"
#define	PWD	"/bin/pwd"
#define	SHELL	"/bin/sh"

/*
 * node types:
 *	TCOM: program	{syntax type 3.2}
 *	TPAR: ( stuff )	{syntax type 3.1}
 *	TFIL: pipe node	{syntax type 2.2, 2.3}
 *	TLST: list node	{syntax type 1.2, 1.3}
 */
#define	TCOM	1
#define	TPAR	2
#define	TFIL	3
#define	TLST	4
/*
 * flags
 *	FCAT:	concatenate to output file.
 *	FECAT:	concatenate to errput file.
 *	FPIN:	input from pipe
 *	FPOU:	output to pipe.
 *	FPAR:	last spinoff from parenthesized expression, don't fork again.
 *	FAND:	no wait for termination of child.
 *	FINT:	clear traps, if set (INTR, QUIT); default input from /dev/null.
 *	FPRS:	print pid of child after forking.
 */
#define	FCAT	1
#define	FECAT	2
#define	FPIN	4
#define	FPOU	8
#define	FPAR	16
#define	FAND	32
#define	FINT	64
#define	FPRS	128
/*
 * node descriptions:
 *	program: DTYP, DFLG, DIN,  DOUT, DERR, DPRG, DCOM, DARG1, DARG2, ...
 *	paren:	 DTYP, DFLG, DIN,  DOUT, DERR, DSPR
 *	pipe:	 DTYP, DFLG, DLEF, DRIT
 *	list:	 DTYP, DFLG, DLEF, DRIT
 */
#define	DTYP	0
#define	DFLG	1
#define	DLEF	2
#define	DIN	2
#define	DRIT	3
#define	DOUT	3
#define	DERR	4
#define	DSPR	5
#define	DPRG	5
#define	DCOM	6
#define	DARG1	7
#define	DARG2	8
struct list {
	int type;
	char flagc;
	char cchar;
	struct list *left;
	struct list *right;
};
struct paren {
	int type;
	int flag;
	char *input;
	char *output;
	char *errput;
	struct list *subpar;
	char	*args[0];
};
struct progm {
	int type;
	int flag;
	char *input;
	char *output;
	char *errput;
	char *program;
	char *pname;
	char *arg1;
	char *arg2;
};
#define	ENOENT	2
#define	E2BIG	7
#define	ENOEXEC	8
#define	ENOMEM	12
#define	EACCES	13
#define	ENOTDIR	20
#define	EDIRECT	13

char	*dolp;
#define	STKP	stk[0]
int	stk[STKSIZ+1];
char	pidp[6];
char	nbuf[6];
int	ldivr;
char	**dolv;
int	dolc;
char	*promp	"% ";
char	*linep;
char	line[LINSIZ];
char	*elinep	line+LINSIZ-30;
char	**argp;
char	*args[ARGSIZ];
char	**eargp	args+ARGSIZ-1;
int	*treep;
int	treecnt;
int	trebuf[TRESIZ];
int	*treeend	trebuf+TRESIZ;
char	peekc;
char	error;
char	uid;
char	setintr;
char	*arginp;
int	acctf;
int	readf;
char	*intrf;
int	prof;
int	onelflg;
int	exitcod;
int	echoflg;
char	*seta[26];
char	tty[] "/dev/lnXX";
char	*qc;
char	qlist[] ": \t;&<>%()|^*?[\"'$\\";
char	*home;
char	*endcore;
char	*endptr;
int	errno;
int	wasintr;
char	*gointr;
char	*goeof;
/*
char	expath[32], *expathp;
*/

char	*mesg[]	{
	0,
	"Hangup",
	0,
	"Quit",
	"Illegal instruction",
	"Trace/BPT trap",
	"IOT trap",
	"EMT trap",
	"Floating exception",
	"Killed",
	"Bus error",
	"Memory fault",
	"Bad system call",
	"Broken pipe",
	"Alarm timeout",
	"Software kill",
	"Sig 16",
	"Sig 17",
	"Sig 18",
	"Sig 19",
};

char *acct_name "/usr/adm/sh_acct";
struct stime {
	long uproct;
	long sproct;
	long cputim;
	long systim;
} timeb;


main(c, av)
int c;
char **av;
{
	register *f;
	register char *cptr, **v;
	int pv[2];
	int stopprof();
	int ln;
	int pwdstat;
	struct{
		char	lobyte;
		char	hibyte;
	};

	endptr = endcore = sbrk(0);
	dup(1);	/* if error output (2) not open, open it. */
	for(cptr=3; cptr<15; close(cptr++));

	if(pipe(f=pv)!= -1) {
		if(!fork()) {
			close(*f++);
			close(1);
			dup(*f);
			close(*f);
			write(1, "/", 1);
			execl(PWD, PWD+5, 0);
			exit(9);
		}
		close(f[1]);
		wait(&pwdstat);
		home = rdval(*f, 0, 0);
		close(*f);
	}

	ln = lnxx(0);
	if(ln.lobyte == 'x' && ln.hibyte == 'x'){
		ln = lnxx(1);
		if(ln.lobyte == 'x' && ln.hibyte == 'x')
			ln = lnxx(2);
	}
	tty[7] = ln;
	tty[8] = ln>>8;

	btoa(getpid(), pidp+5);
	f = pidp;
	*f++ =| '00';
	*f =| '00';
	v = av;
	cptr = acct_name;
	promp = "% ";
	if(((uid = getuid())&0377) == 0) {
		promp = "# ";
		acct_name[10] = 'u';
	}
	acctf = open(cptr, 1);

	f = *v++;
	if(c == 1 && *f == '-')
		if((prof = open("profile.sh", 0)) == -1)
			prof = 0;

	while(--c > 0 && promp) {
		cptr = *v++;
		if(*cptr++ == '-') {
			switch(*cptr) {

			default:
				prs("Bad arg: ");
				err(--cptr);

			case 'c':
				if(--c <= 0)
					exit(4);
				arginp = *v;
			case '\0':
				break;

			case 'e':
			case 'v':
				echoflg = 1;
				continue;

			case 'i':
				*f = '-';
				continue;

			case 't':
				onelflg = 2;
				*--v =+ 2;
			}
		*f = '-';
		} else {
			readf = dup(0);
			close(0);
			openi(*--v);
			intrf = *v;
		}
		promp = 0;
	}
	dolv = v;
	dolc = c;
	*--v = f;

	if(*f == '-') {
		setintr++;
		signal(QUIT, 1);
		signal(INTR, 1);
		if(prof)setintr = -1;
	}

	setexit();
	for(;;) {
		if(wasintr == 1)
			wasintr = 0;
		if(wasintr > 0) {
			wasintr = -1;
			if(intrf)
				if((prof = open(intrf, 0)) == -1)
					prof = 0;
			if(xgoto(gointr)) {
				if(prof)
					close(prof);
				prof = 0;
				signal(INTR, 0);
				wasintr = 0;
			}
		}
		if(promp && !prof)
			prs(promp);
		echoflg =<<2;
		qc = qlist;
		if((peekc = getc()) == ':')
			while(getc() != '\n');
		else {
			qc++;
			main1();
		if(setintr<0) {
			signal(INTR, stopprof);
			setintr = 1;
		}
		}
	}
}

main1()
{
	register char c, *cp;
	register *t;

	argp = args;
	linep = line;
	error = 0;
	do {
		cp = linep;
		if(argp == eargp) {
			while(getc() != '\n');
			err("Too many tokens");
			reset();
		}
		word();
	} while(*cp != '\n');
	treep = trebuf;
	treecnt = 0;
	if(error == 0)
		t = syntax(args, argp);
	if(error != 0)
		err("syntax error");
	else
		execute(t);
}

word()
{
	register char c, c1;
	register (*qf)();
	extern getc(), reade();

	*argp++ = linep;

loop:
	switch(c = getc()) {

	case ' ':
	case '\t':
		goto loop;

	case '\'':
	case '"':
		c1 = c;
		qc = qlist+16;
		qf = (c1 == '"')? reade: getc;
		while((c=(*qf)()) != c1) {
			if(c == '\n') {
				error++;
				peekc = c;
				return;
			}
			*linep++ = c|QUOTE;
		}
		qc = qlist+1;
		goto pack;


	case '&':
	case ';':
	case '%':
	case '<':
	case '>':
	case '(':
	case ')':
	case '|':
	case '^':
	case '\n':
		*linep++ = c;
		*linep++ = '\0';
		return;

	default:
		peekc = c;
	}

pack:
	for(;;) {
		c = getc();
		if(any(c, " '\"\t;&%<>()|^\n")) {
			peekc = c;
			if(any(c, "\"'"))
				goto loop;
			*linep++ = '\0';
			return;
		}
		*linep++ = c;
	}
}

tree(n)
int n;
{
	register *t;

	t = treep;
	treep =+ n;
	treecnt++;
	if (treep>treeend) {
		prs("Command table overflow\n");
		error++;
		reset();
	}
	return(t);
}

reade() {
	return(echo(readc()));
}

echo(c) {
	switch(echoflg) {

	case 0:
		return(c);

	case 1<<10: /* (1<<2)<<8 only. */
	case 1<<2:
		write(2, "* ", 2);
	case 1<<8:
		if(echoflg != 1<<2)
			write(2, "\\\n", 1);
		c =& 0177;
	case 1:
		write(2, &c, 1);
		break;

	case 1<<4:
		write(2, "\\\n", 2);
	}
	echoflg = 1;
	return(c);
}

getc()
{
	register char c, n, *temp;

	if(peekc) {
		c = peekc;
		peekc = 0;
		return(c);
	}
	for(;;) {
		c = readc();
		if(c == '$') {
			c = readc();
			temp = "\\$X";
			temp[2] = c;
			if((n = c-'0')>=0 && c<='9') {
				if(n > dolc)
					continue;
				else	temp = dolv[n];
			} else if((n = c-'a')>=0 && c<='z') {
				if((temp = seta[n]) == 0)
					continue;
			} else if(c == '$')
				temp = pidp;
			else if(c == '.')
				temp = home;
			else if(c == 'T' || c == '_')
				temp = tty;
			else if(c == 'E') {
				temp = nbuf;
				temp[3] = 0;
				temp[2] = (exitcod & 7) + '0';
				temp[1] = (exitcod>>3 & 7) + '0';
				temp[0] = (exitcod>>6 & 3) + '0';
			} else if(c == 'N')
				temp = btoa(dolc, nbuf+5);
			else if(c == 'R')
				temp = btoa(exitcod, nbuf+5);
			else if(c == 'P')
				temp = btoa(prof, nbuf+5);
			else if(c == 'F')
				temp = btoa(readf, nbuf+5);
			else if(c == 'V') {
				if(echoflg)
					temp = "-v";
				else	continue;
			} else if(c == 'I')
				temp = btoa(setintr, nbuf+5);
			else if(c=='Z')
				temp = btoa(endptr);
			if(STKP >= STKSIZ)
				err("'$' nesting error");
			else {
				stk[STKP] = dolp;
				STKP++;
				dolp = temp;
			}
			continue;
		}

		if(c=='\\') {
			c=readc();
			if(c=='\n') {
				echoflg =<<4;
				c = ' ';
			} else if(any(c, qc)) {
				c =| QUOTE;
				echoflg =<<8;
			} else {
				peekc = c;
				c = '\\';
			}
		}
		break;
	}
	echo(c);
	if(linep == elinep) {
		linep--;
		while(getc() != '\n');
		linep++;
		err("Too many characters");
		reset();
	}
	return(c);
}

readc()
{
	char cc;
	register c;

	while(dolp) {
		c = *dolp++;
		if(c != '\0')
			return(c =& 0177);
		else
			dolp = stk[--STKP];
	}
	if (arginp) {
		if (arginp == 1)
			exit(exitcod);
		if ((c = *arginp++) == 0) {
			arginp = 1;
			c = '\n';
		}
		return(c);
	}
	if (onelflg==1)
		exit(exitcod);
	if(read1(prof, &cc)) {
		if(!prof || !setintr)
			exit(exitcod);
		close(prof);
		prof = 0;
		if(wasintr<0) {
			wasintr = 0;
			signal(INTR, 0);
		}
		cc = '\n';
	}
	if (cc=='\n' && onelflg)
		onelflg--;
	return(cc);
}

/*
 * syntax
 *	empty
 *	syn1
 */

syntax(p1, p2)
char **p1, **p2;
{

	while(p1 < p2) {
		if(any(**p1, ";&\n"))
			p1++; else
			return(syn1(p1, p2));
	}
	return(0);
}

/*
 * syn1
 *	syn2
 *	syn2 &&C syntax
 *	syn2 & syntax
 *	syn2 ; syntax
 */

syn1(p1, p2)
char **p1, **p2;
{
	register char **p;
	register *t, *t1;
	int l;

	l = 0;
	for(p=p1; p<p2; )
	switch(**p++) {

	case '(':
		l++;
		continue;

	case ')':
		l--;
		if(l < 0)
			error++;
		continue;

	case '&':
	case ';':
	case '\n':
		if(l == 0) {
			l = **--p;
			t = tree(4);
			t[DTYP] = TLST;
			t[DLEF] = syn2(p1, p);
			t[DFLG] = 0;
			p++;
			if(l == '&') {
				t1 = t[DLEF];
				t1[DFLG] =| FAND|FPRS|FINT;
				if(**p == '&' && ++p<p2 &&
				   **p >= 'a' && **p <= 'z' && p[0][1] == 0)
					t1->cchar = **p++;
			}
			t[DRIT] = syntax(p, p2);
			return(t);
		}
	}
	if(l == 0)
		return(syn2(p1, p2));
	error++;
}

/*
 * syn2
 *	syn3
 *	syn3 | syn2
 *	syn3 ^ syn2
 */

syn2(p1, p2)
char **p1, **p2;
{
	register char **p;
	register int l, *t;

	l = 0;
	for(p=p1; p!=p2; )
	switch(**p++) {

	case '(':
		l++;
		continue;

	case ')':
		l--;
		continue;

	case '|':
	case '^':
		if(p1 == p) {
			error++;
			return(0);
		}
		if(l == 0) {
			t = tree(4);
			t[DTYP] = TFIL;
			t[DLEF] = syn3(p1, p-1);
			t[DRIT] = syn2(p, p2);
			t[DFLG] = 0;
			return(t);
		}
	}
	return(syn3(p1, p2));
}

/*
 * syn3
 *	( syn1 ) [ < in  ] [ > [ > ] out ] [ % [ % ] err ]
 *	word word* [ < in ] [ > [ > ] out ] [ % [ % ] err ]
 */

syn3(p1, p2)
char **p1, **p2;
{
	register char **p;
	char **lp, **rp;
	register *t, *ioep;
	int n, l, ioe[3], flg;
	char c;

	flg = 0;
	if(**p2 == ')')
		flg =| FPAR;
	lp = 0;
	rp = 0;
	ioep = ioe+3;
	*--ioep = 0;
	*--ioep = 0;
	*--ioep = 0;
	n = 0;
	l = 0;
	for(p=p1; p!=p2; )
	switch(c = **p++) {

	case '(':
		if(l == 0) {
			if(lp != 0)
				error++;
			lp = p;
		}
		l++;
		continue;

	case ')':
		l--;
		if(l == 0)
			rp = p-1;
		continue;

	case '%':
		ioep++;
	case '>':
		ioep++;
		if(l) {
			ioep = ioe;
			continue;
		}
		if(p != p2) {
			if(**p++ == c)
				flg =| (c == '%') ? FECAT : FCAT;
			else if(**--p == '%')
				**p = 0377;
		}
	case '<':
		if(l) continue;
		if(p == p2 || any(**p, "<>%(") || *ioep) {
			error++;
			continue;
		}
		*ioep = *p++;
		ioep = ioe;
		continue;

	default:
		if(l == 0)
			p1[n++] = p[-1];
	}
	if(lp != 0) {
		if(n != 0)
			error++;
		t = tree(6);
		t[DTYP] = TPAR;
		t[DSPR] = syn1(lp, rp);
		goto out;
	}
	if(n == 0)
		error++;
	p1[n++] = 0;
	t = tree(n+6);
	t[DTYP] = TCOM;
	for(l=0; l<n; l++)
		t[l+DCOM] = p1[l];
out:
	t[DFLG] = flg;
	t[DLEF] = *ioep++;
	t[DRIT] = *ioep++;
	t[DERR] = *ioep;
	return(t);
}

scan(at, f)
int *at;
{
	register char *p, c;
	register *t;

	t = at+DCOM;
	while(p = *t++)
		while(c = *p)
			if(f)
				*p++ =& 0177;
			else
				if(any(*p++,"[?*"))
					return(1);
	return(0);
}

execute(t, pf1, pf2)
int *t, pf1, *pf2;
{
	int catchintr();
	int i, f, pv[2], wt;
	register *t1;
	register char *cp1, *cp2;
	char	*copy();

	if((t1 = t) != 0)
	switch(t1[DTYP]) {

	case TCOM:
		exitcod = 0;
		cp1 = t1[DCOM];
		if(equal(cp1, "chdir") || equal(cp1, "cd")) {
			if(t1[DARG1] == 0 || chdir(t1[DARG1]) < 0)
				noex();
			return;
		}
		if(equal(cp1, "shift")) {
			if(dolc < 1) {
				prs("shift: no args\n");
				exitcod = 4;
				return;
			}
			if((cp1 = t1[DARG1])==0) {
				dolv[1] = dolv[0];
				dolv++;
				dolc--;
				return;
			}
			if ((*cp1 =^ '0')>9 || *cp1++ >dolc || *cp1) {
				prs("shift: argument?\n");
				exitcod = 4;
				return;
			}
			t1 = dolv + *--cp1;
			for(cp2 = dolc - *cp1 +1; --cp2; *t1++ = t1[1]);
			dolc--;
			return;
		}
		if(equal(cp1, "login")) {
			if(promp != 0 && prof == 0) {
				close(acctf);
				if(readf) close(readf);
				execv("/bin/login", t1+DCOM);
			}
			noex();
			return;
		}
/* newgrp not implemented.
		if(equal(cp1, "newgrp")) {
			if(promp != 0 && prof == 0) {
				close(acctf);
				if(readf) close(readf);
				execv("/bin/newgrp", t1+DCOM);
			}
			noex();
			return;
		}
*/

/* home -- use chdir $.
		if(equal(cp1, "home")) {
			if(!home || !*home || chdir(home)<0)
				noex();
			return;
		}
*/

		if(equal(cp1, "wait")) {
			if(t1[DARG1])
				cp2 = atob(t1[DARG1]);
			else	cp2 = -1;
			wt = signal(INTR, catchintr);
			pwait(cp2, 0);
			signal(INTR, wt);
			wasintr = 0;
			return;
		}
		if(equal(cp1, ":"))
			return;

		if((cp2=equal(cp1, "return")) || equal(cp1, "exit")) {
			if(t1[DARG1]) exitcod = atob(t1[DARG1]);
			if(cp2 && prof) {
				close(prof);
				prof = 0;
			} else if(promp==0 || prof) {
				seek(0,0,2);
				exit(exitcod);
			}
			return;
		}

		if(equal(cp1, "onintr")) {
			if(setintr) {
				setintr = 1;
				if(t1[DARG1])
					noex();
				else	signal(INTR, 1);
				return;
			}
			if(t1[DARG1]==0) {
				signal(INTR, 0);
				return;
			}
			gointr = rdval(0, 0, t1[DARG1]);
			wasintr = 0;
			signal(INTR, catchintr);
			return;
		}

		if(equal(cp1, "onend")) {
			if(t1[DARG1])
				goeof = rdval(0, 0, t1[DARG1]);
			else
				goeof = 0;
			return;
		}

		if(equal(cp1, "=")) {
			if((cp1 = t1[DARG1]) == 0 ||
			 (*cp1 =- 'a')<0 || *cp1++ > 25 || *cp1 ||
			 (seta[*--cp1] = rdval((t1[DFLG]&FPIN?pf1:0),
			 t1[DLEF], t1[DARG2])) == 0)
					err("'=' error");
			return;
		}

		if(equal(cp1, "open")) {
			if(readf) close(readf);
			if(!t1[DARG1])
				if(t1[DFLG]&FPIN) {
					readf = dup(pf1);
					return;
				} else	t1[DARG1] = tty;
			readf = open(t1[DARG1],0);
			return;
		}

		if(equal(cp1, "read")) {
			cp2 = linep;
			if(t1[DFLG]&FPOU)
				cp1 = pf2[1];
			else if(t1->output) {
				if((cp1=openo(t1->output,t1[DFLG]&FCAT))&0100000)
					return;
			} else	cp1 = 1;
			if(read1(readf, cp2)) {
				if(xgoto(goeof))
					err("read - EOF");
				*cp2 = 0;
			}
			while(*cp2 && *cp2 != '\n') {
				write(cp1, cp2, 1);
				if(read1(readf, cp2))
					break;
			}
			write(cp1, "\n", 1);
			if(!(t1[DFLG]&FPOU) && t1[DRIT])
				close(cp1);
			return;
		}

	case TPAR:
		f = t1[DFLG];
		i = 0;
		if((f&FPAR) == 0)
		for(wt=10; ; wt =+ 10) {
			if ((i=fork()) != -1) break;
			if(promp == 0 && wt<60)
				sleep(wt);
			else {
				err("Cannot fork; try again");
				return;
			}
		}
		if(i != 0) {
			if((f&FPRS) != 0) {
				if(t1->cchar) {
					seta[t1->cchar - 'a'] = rdval(0, 0,
					   btoa(i, nbuf+5));
				} else {
					prn(i);
					prs("\n");
				}
			}
			if((f&FAND) != 0)
				return;
			if((f&FPOU) == 0)
				pwait(i, t);
			return;
		}

		promp = 0;    /* show err this is a child */
		if(prof) {
			close(0);
			dup(prof);
			close(prof);
		}

		if(t1[DERR]) {
			i = openo(t1->errput, f&FECAT);
			close(2);
			dup(i);
			close(i);
		}

		if(t1[DLEF]) {
			close(0);
			openi(t1->input);
		}

		if(t1[DRIT]) {
			close(1);
			if(t1->output[0] == -1)
				dup(2);
			else openo(t1->output, f&FCAT);
		}
		if((f&FPIN) != 0) {
			close(0);
			dup(pf1);
			close(pf1);
		}
		if((f&FPOU) != 0) {
			close(1);
			dup(pf2[1]);
			close(pf2[0]);
			close(pf2[1]);
		}
		if((f&FINT)!=0 && t1[DLEF]==0 && (f&FPIN)==0) {
			close(0);
			open("/dev/null", 0);
		}
		if((f&FINT) == 0 && setintr) {
			signal(INTR, 0);
			signal(QUIT, 0);
		}
		if(t1[DTYP] == TPAR) {
			if(t1 = t1[DSPR])
				t1[DFLG] =| f&FINT;
			execute(t1);
			exit(exitcod);
		}
		close(acctf);
		if(readf) close(readf);
		if(scan(t1, 0)){
			t1[DSPR] = GLOB;
			execv(t1[DSPR], t1+DSPR);
			t1->pname = GLOB;
			noex();
		}
		scan(t1, 1);

		cp1 = *(t1 = t+DCOM);
		cp2 = shexec(cp1, t1);
		copy(*t1, copy("/usr/bin/", linep));
		cp2 =+ shexec(linep+4, t1);
		cp2 =+ shexec(linep, t1);
		prs(*t1);
		err(cp2? ": permission denied!": ": not found");

	case TFIL:
		f = t[DFLG];
		if(pipe(pv)<0)
			err("Cannot create pipe");
		t1 = t[DLEF];
		t1[DFLG] =| FPOU | (f&(FPIN|FINT|FPRS));
		execute(t1, pf1, pv);
		close(pv[1]);
		t1 = t[DRIT];
		t1[DFLG] =| FPIN | (f&(FPOU|FINT|FAND|FPRS));
		execute(t1, *pv, pf2);
		close(pv[0]);
		return;

	case TLST:
		f = t[DFLG]&FINT;
		if(t1 = t[DLEF])
			t1[DFLG] =| f;
		execute(t1);
		if(t1 = t[DRIT])
			t1[DFLG] =| f;
		execute(t1);
		return;

	}
}

noex() {
	register t1;

	prs(t1->pname);
	err(": cannot execute");
}

openi(ifile) {
	register i;

	if((i = open(ifile, 0)) < 0) {
		prs(ifile);
		err(": cannot open");
		i=0;
	}
	return(i);
}

openo(of, flg) {
	register i;

	if(flg && (i = open(of, 1)) > 0)
		seek(i, 0, 2);
	else if((i=creat(of, 0666)) < 0) {
		prs(of);
		err(": cannot create");
	}
	return(i);
}

err(s)
char *s;
{

	prs(s);
	prs("\n");
	if(promp == 0) {
		seek(0, 0, 2);
		exit(8);
	}
	exitcod = 8;
	return;
}

any(c, as)
int c;
char *as;
{
	register char *s;

	s = as;
	while(*s)
		if(*s++ == c)
			return(1);
	return(0);
}

equal(as1, as2)
char *as1, *as2;
{
	register char *s1, *s2;

	s1 = as1;
	s2 = as2;
	while(*s1++ == *s2)
		if(*s2++ == '\0')
			return(1);
	return(0);
}

pwait(i, t)
int i, *t;
{
	register p, e;
	int s;
	int catchintr();

	if(i != 0)
	for(;;) {
		times(&timeb);
		time(&timeb.uproct);
		p = wait(&s);
		if(wasintr > 0) {  /* wait terminated by interrupt */
			if(t == 0) /* wait called by wait command, */
				break; /* stop waiting. */
			p = wait(&s);
		}
		if(p == -1)
			break;
		e = s&0177;
		if(e == 2 && wasintr > 0)  /* process killed by intr */
			e = 0;
		if(mesg[e] != 0) {
			if(p != i) {
				prn(p);
				prs(": ");
			}
			prs(mesg[e]);
			if(s&0200)
				prs(" -- Core dumped");
		}
		exitcod = s>>8;
		if(e != 0)
			err("");
		if(i == p) {
			acct(t);
			break;
		} else
			acct(0);
	}
}

acct(t)
int *t;
{
	if(t == 0)
		enacct("**gok"); else
	if(*t == TPAR)
		enacct("()"); else
	enacct(t[DCOM]);
}

enacct(as)
char *as;
{
	struct stime timbuf;
	struct {
		char cname[14];
		char shf;
		char uid;
		long datet;
		long realt;
		long bcput;
		long bsyst;
	} tbuf;
	register i;
	register char *np, *s;

	if(acctf == -1) return;
	s = as;
	times(&timbuf);
	time(&timbuf.uproct);
	tbuf.realt = timbuf.uproct - timeb.uproct;
	tbuf.bcput = timbuf.cputim - timeb.cputim;
	tbuf.bsyst = timbuf.systim - timeb.cputim;
	for(np = s; i = *s++; )
		if(i=='/')
			np=s;
	for (i=0; i<14; i++) {
		if(tbuf.cname[i] = *np)
			np++;
	}
	tbuf.datet = timbuf.uproct;
	tbuf.uid = uid;
	tbuf.shf = 0;
	if (promp==0)
		tbuf.shf = 1;
	seek(acctf, 0, 2);
	write(acctf, &tbuf, sizeof(tbuf));
}

read1(file, where) {
	register i;

	while((i = read(file, where, 1)) != 1 && wasintr == 2) wasintr++;
	return(--i != 0);
}

catchintr() {
	wasintr=2;
	signal(INTR, 1);
}

stopprof() {
	signal(INTR, 1);
	seek(prof, 0, 2);
	wasintr=1;
}

char *copy(source,sink) char source[], sink[]; {
	/* copy strings */
	register char *p1, *p2;

	p1 = source;
	p2 = sink;
	while(*p2++ = *p1++);
	return(--p2);
}

rdval(pipef, lef, arg2p) char *arg2p; int *pipef; {
	register char c, *st, *endp;

	endp = st = endptr;

	if(!arg2p && !pipef && lef) {
		if((pipef = open(lef, 0)) < 0)
			return(0);
	} else
		lef = 0;

	do {
		if(endp >= endcore)
			if(sbrk(64)<0)
				return(0);
			else
				endcore =+ 64;
		if(arg2p == 0) {
			if(read1(pipef, endp) || *endp == '\n')
				*endp = '\0';
		} else
			*endp = *arg2p++;
	} while(*endp++);

	endptr = endp;
	if(lef) close(pipef);
	return(st);
}

xgoto(where) char *where; {
	register i;
	int j;

	if(!where || !*where)
		return(1);
	if(!(i = fork())) {
		if(prof) {
			close(0);
			dup(prof);
			close(prof);
		}
		execl(GOTO, GOTO+5, where, 0);
		exit(9);
	}
	if(i == -1)
		return(i);
	pwait(i, 0);
	return(exitcod);
}

atob(ptr)
	char *ptr;
	{
	register char *p;
	register n, base;
	static char base0;

	n = 0;
	p = ptr;
	base = 10;
	if(*p == '-')
		p++;
	if(*p == '0') {
		base = 8;
		p++;
	}
	base0 = base + '0';

	while(*p >= '0' && base0 > *p) {
		n =* base;
		n =+ *p++;
		n =- '0';
	}
	if(*ptr == '-')
		n = -n;
	return(n);
}
#define	ENOENT	2
#define	E2BIG	7
#define	ENOEXEC	8
#define	ENOMEM	12
#define	EACCESS	13
#define	ENOTDIR	20
#define	EDIRECT	13
#define	SHELL	"/bin/sh"

int	ldivr;
char	nbuf[6];
shexec(afile, aargp)
	char *afile, *aargp[];
	{
	register char *file, **rargp;
	extern errno;

	file = afile;
	rargp = aargp;
	execv(file, rargp);
/* temp */	if(!errno || errno & 0177700) errno = EDIRECT;
	if(errno == ENOEXEC) {
		*rargp = file;
		*--rargp = SHELL+5;
		execv(SHELL, rargp);
		if(errno == ENOENT || errno == ENOTDIR)
			err("No Shell!");
	}
	switch (errno) {

	case E2BIG:
		prs(*rargp);
		err(": arg list too long");

	case ENOMEM:
		prs(*rargp);
		err(": not enough core");

	default:
		prs(*rargp);
		prs(": unknown error (errno=");
		prn(errno);
		err(").");

	case EACCESS:
		return(1);

	case ENOENT:
	case ENOTDIR:
		return(0);
	}
}

prs(as)
char *as;
{
	register char *s;

	s = as;
	while(*s)
		write(2, s++, 1);
}

prn(n) {
	prs(btoa(n, nbuf+5));
}

btoa(n, ptr)
	char *ptr;
	{
	register char *p;
	register v;

	p = ptr;
	*p = 0;
	v = n;
	do {
		v = ldiv(0, v, 10);
		*--p = ldivr | '0';
	} while(v);
	return(p);
}
