1#define Extern extern
2#include <sys/types.h>
3#include <signal.h>
4#define _NSIG NSIG
5#include <errno.h>
6#include <setjmp.h>
7#include <stddef.h>
8#include <time.h>
9#include <sys/times.h>
10#include <sys/stat.h>
11#include <sys/wait.h>
12#undef NULL
13#include "sh.h"
14
15/* -------- exec.c -------- */
16/* #include "sh.h" */
17
18/*
19 * execute tree
20 */
21
22static	char	*signame[] = {
23	"Signal 0",
24	"Hangup",
25	(char *)NULL,	/* interrupt */
26	"Quit",
27	"Illegal instruction",
28	"Trace/BPT trap",
29	"Abort",
30	"EMT trap",
31	"Floating exception",
32	"Killed",
33	"Bus error",
34	"Memory fault",
35	"Bad system call",
36	(char *)NULL,	/* broken pipe */
37	"Alarm clock",
38	"Terminated",
39};
40#define	NSIGNAL (sizeof(signame)/sizeof(signame[0]))
41
42
43_PROTOTYPE(static int forkexec, (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked ));
44_PROTOTYPE(static int parent, (void));
45_PROTOTYPE(int iosetup, (struct ioword *iop, int pipein, int pipeout ));
46_PROTOTYPE(static void echo, (char **wp ));
47_PROTOTYPE(static struct op **find1case, (struct op *t, char *w ));
48_PROTOTYPE(static struct op *findcase, (struct op *t, char *w ));
49_PROTOTYPE(static void brkset, (struct brkcon *bc ));
50_PROTOTYPE(int dolabel, (void));
51_PROTOTYPE(int dochdir, (struct op *t ));
52_PROTOTYPE(int doshift, (struct op *t ));
53_PROTOTYPE(int dologin, (struct op *t ));
54_PROTOTYPE(int doumask, (struct op *t ));
55_PROTOTYPE(int doexec, (struct op *t ));
56_PROTOTYPE(int dodot, (struct op *t ));
57_PROTOTYPE(int dowait, (struct op *t ));
58_PROTOTYPE(int doread, (struct op *t ));
59_PROTOTYPE(int doeval, (struct op *t ));
60_PROTOTYPE(int dotrap, (struct op *t ));
61_PROTOTYPE(int getsig, (char *s ));
62_PROTOTYPE(void setsig, (int n, void (*f)()));
63_PROTOTYPE(int getn, (char *as ));
64_PROTOTYPE(int dobreak, (struct op *t ));
65_PROTOTYPE(int docontinue, (struct op *t ));
66_PROTOTYPE(static int brkcontin, (char *cp, int val ));
67_PROTOTYPE(int doexit, (struct op *t ));
68_PROTOTYPE(int doexport, (struct op *t ));
69_PROTOTYPE(int doreadonly, (struct op *t ));
70_PROTOTYPE(static void rdexp, (char **wp, void (*f)(), int key));
71_PROTOTYPE(static void badid, (char *s ));
72_PROTOTYPE(int doset, (struct op *t ));
73_PROTOTYPE(void varput, (char *s, int out ));
74_PROTOTYPE(int dotimes, (void));
75
76int
77execute(t, pin, pout, act)
78register struct op *t;
79int *pin, *pout;
80int act;
81{
82	register struct op *t1;
83	int i, pv[2], rv, child, a;
84	char *cp, **wp, **wp2;
85	struct var *vp;
86	struct brkcon bc;
87
88	if (t == NULL)
89		return(0);
90	rv = 0;
91	a = areanum++;
92	wp = (wp2 = t->words) != NULL
93	     ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
94	     : NULL;
95
96	switch(t->type) {
97	case TPAREN:
98	case TCOM:
99		rv = forkexec(t, pin, pout, act, wp, &child);
100		if (child) {
101			exstat = rv;
102			leave();
103		}
104		break;
105
106	case TPIPE:
107		if ((rv = openpipe(pv)) < 0)
108			break;
109		pv[0] = remap(pv[0]);
110		pv[1] = remap(pv[1]);
111		(void) execute(t->left, pin, pv, 0);
112		rv = execute(t->right, pv, pout, 0);
113		break;
114
115	case TLIST:
116		(void) execute(t->left, pin, pout, 0);
117		rv = execute(t->right, pin, pout, 0);
118		break;
119
120	case TASYNC:
121		i = parent();
122		if (i != 0) {
123			if (i != -1) {
124				setval(lookup("!"), putn(i));
125				if (pin != NULL)
126					closepipe(pin);
127				if (talking) {
128					prs(putn(i));
129					prs("\n");
130				}
131			} else
132				rv = -1;
133			setstatus(rv);
134		} else {
135			signal(SIGINT, SIG_IGN);
136			signal(SIGQUIT, SIG_IGN);
137			if (talking)
138				signal(SIGTERM, SIG_DFL);
139			talking = 0;
140			if (pin == NULL) {
141				close(0);
142				open("/dev/null", 0);
143			}
144			exit(execute(t->left, pin, pout, FEXEC));
145		}
146		break;
147
148	case TOR:
149	case TAND:
150		rv = execute(t->left, pin, pout, 0);
151		if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND))
152			rv = execute(t1, pin, pout, 0);
153		break;
154
155	case TFOR:
156		if (wp == NULL) {
157			wp = dolv+1;
158			if ((i = dolc) < 0)
159				i = 0;
160		} else {
161			i = -1;
162			while (*wp++ != NULL)
163				;
164		}
165		vp = lookup(t->str);
166		while (setjmp(bc.brkpt))
167			if (isbreak)
168				goto broken;
169		brkset(&bc);
170		for (t1 = t->left; i-- && *wp != NULL;) {
171			setval(vp, *wp++);
172			rv = execute(t1, pin, pout, 0);
173		}
174		brklist = brklist->nextlev;
175		break;
176
177	case TWHILE:
178	case TUNTIL:
179		while (setjmp(bc.brkpt))
180			if (isbreak)
181				goto broken;
182		brkset(&bc);
183		t1 = t->left;
184		while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
185			rv = execute(t->right, pin, pout, 0);
186		brklist = brklist->nextlev;
187		break;
188
189	case TIF:
190	case TELIF:
191	 	if (t->right != NULL) {
192		rv = !execute(t->left, pin, pout, 0) ?
193			execute(t->right->left, pin, pout, 0):
194			execute(t->right->right, pin, pout, 0);
195		}
196		break;
197
198	case TCASE:
199		if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0)
200			cp = "";
201		if ((t1 = findcase(t->left, cp)) != NULL)
202			rv = execute(t1, pin, pout, 0);
203		break;
204
205	case TBRACE:
206/*
207		if (iopp = t->ioact)
208			while (*iopp)
209				if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
210					rv = -1;
211					break;
212				}
213*/
214		if (rv >= 0 && (t1 = t->left))
215			rv = execute(t1, pin, pout, 0);
216		break;
217	}
218
219broken:
220	t->words = wp2;
221	isbreak = 0;
222	freehere(areanum);
223	freearea(areanum);
224	areanum = a;
225	if (talking && intr) {
226		closeall();
227		fail();
228	}
229	if ((i = trapset) != 0) {
230		trapset = 0;
231		runtrap(i);
232	}
233	return(rv);
234}
235
236static int
237forkexec(t, pin, pout, act, wp, pforked)
238register struct op *t;
239int *pin, *pout;
240int act;
241char **wp;
242int *pforked;
243{
244	int i, rv, (*shcom)();
245	register int f;
246	char *cp;
247	struct ioword **iopp;
248	int resetsig;
249	char **owp;
250
251	owp = wp;
252	resetsig = 0;
253	*pforked = 0;
254	shcom = NULL;
255	rv = -1;	/* system-detected error */
256	if (t->type == TCOM) {
257		while ((cp = *wp++) != NULL)
258			;
259		cp = *wp;
260
261		/* strip all initial assignments */
262		/* not correct wrt PATH=yyy command  etc */
263		if (flag['x'])
264			echo (cp ? wp: owp);
265		if (cp == NULL && t->ioact == NULL) {
266			while ((cp = *owp++) != NULL && assign(cp, COPYV))
267				;
268			return(setstatus(0));
269		}
270		else if (cp != NULL)
271			shcom = inbuilt(cp);
272	}
273	t->words = wp;
274	f = act;
275	if (shcom == NULL && (f & FEXEC) == 0) {
276		i = parent();
277		if (i != 0) {
278			if (i == -1)
279				return(rv);
280			if (pin != NULL)
281				closepipe(pin);
282			return(pout==NULL? setstatus(waitfor(i,0)): 0);
283		}
284		if (talking) {
285			signal(SIGINT, SIG_IGN);
286			signal(SIGQUIT, SIG_IGN);
287			resetsig = 1;
288		}
289		talking = 0;
290		intr = 0;
291		(*pforked)++;
292		brklist = 0;
293		execflg = 0;
294	}
295	if (owp != NULL)
296		while ((cp = *owp++) != NULL && assign(cp, COPYV))
297			if (shcom == NULL)
298				export(lookup(cp));
299#ifdef COMPIPE
300	if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
301		err("piping to/from shell builtins not yet done");
302		return(-1);
303	}
304#endif
305	if (pin != NULL) {
306		dup2(pin[0], 0);
307		closepipe(pin);
308	}
309	if (pout != NULL) {
310		dup2(pout[1], 1);
311		closepipe(pout);
312	}
313	if ((iopp = t->ioact) != NULL) {
314		if (shcom != NULL && shcom != doexec) {
315			prs(cp);
316			err(": cannot redirect shell command");
317			return(-1);
318		}
319		while (*iopp)
320			if (iosetup(*iopp++, pin!=NULL, pout!=NULL))
321				return(rv);
322	}
323	if (shcom)
324		return(setstatus((*shcom)(t)));
325	/* should use FIOCEXCL */
326	for (i=FDBASE; i<NOFILE; i++)
327		close(i);
328	if (resetsig) {
329		signal(SIGINT, SIG_DFL);
330		signal(SIGQUIT, SIG_DFL);
331	}
332	if (t->type == TPAREN)
333		exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
334	if (wp[0] == NULL)
335		exit(0);
336	cp = rexecve(wp[0], wp, makenv());
337	prs(wp[0]); prs(": "); warn(cp);
338	if (!execflg)
339		trap[0] = NULL;
340	leave();
341	/* NOTREACHED */
342}
343
344/*
345 * common actions when creating a new child
346 */
347static int
348parent()
349{
350	register int i;
351
352	i = fork();
353	if (i != 0) {
354		if (i == -1)
355			warn("try again");
356	}
357	return(i);
358}
359
360/*
361 * 0< 1> are ignored as required
362 * within pipelines.
363 */
364int
365iosetup(iop, pipein, pipeout)
366register struct ioword *iop;
367int pipein, pipeout;
368{
369	register u;
370	char *cp, *msg;
371
372	if (iop->io_unit == IODEFAULT)	/* take default */
373		iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1;
374	if (pipein && iop->io_unit == 0)
375		return(0);
376	if (pipeout && iop->io_unit == 1)
377		return(0);
378	msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create";
379	if ((iop->io_flag & IOHERE) == 0) {
380		cp = iop->io_name;
381		if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL)
382			return(1);
383	}
384	if (iop->io_flag & IODUP) {
385		if (cp[1] || (!digit(*cp) && *cp != '-')) {
386			prs(cp);
387			err(": illegal >& argument");
388			return(1);
389		}
390		if (*cp == '-')
391			iop->io_flag = IOCLOSE;
392		iop->io_flag &= ~(IOREAD|IOWRITE);
393	}
394	switch (iop->io_flag) {
395	case IOREAD:
396		u = open(cp, 0);
397		break;
398
399	case IOHERE:
400	case IOHERE|IOXHERE:
401		u = herein(iop->io_name, iop->io_flag&IOXHERE);
402		cp = "here file";
403		break;
404
405	case IOWRITE|IOCAT:
406		if ((u = open(cp, 1)) >= 0) {
407			lseek(u, (long)0, 2);
408			break;
409		}
410	case IOWRITE:
411		u = creat(cp, 0666);
412		break;
413
414	case IODUP:
415		u = dup2(*cp-'0', iop->io_unit);
416		break;
417
418	case IOCLOSE:
419		close(iop->io_unit);
420		return(0);
421	}
422	if (u < 0) {
423		prs(cp);
424		prs(": cannot ");
425		warn(msg);
426		return(1);
427	} else {
428		if (u != iop->io_unit) {
429			dup2(u, iop->io_unit);
430			close(u);
431		}
432	}
433	return(0);
434}
435
436static void
437echo(wp)
438register char **wp;
439{
440	register i;
441
442	prs("+");
443	for (i=0; wp[i]; i++) {
444		if (i)
445			prs(" ");
446		prs(wp[i]);
447	}
448	prs("\n");
449}
450
451static struct op **
452find1case(t, w)
453struct op *t;
454char *w;
455{
456	register struct op *t1;
457	struct op **tp;
458	register char **wp, *cp;
459
460	if (t == NULL)
461		return((struct op **)NULL);
462	if (t->type == TLIST) {
463		if ((tp = find1case(t->left, w)) != NULL)
464			return(tp);
465		t1 = t->right;	/* TPAT */
466	} else
467		t1 = t;
468	for (wp = t1->words; *wp;)
469		if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
470			return(&t1->left);
471	return((struct op **)NULL);
472}
473
474static struct op *
475findcase(t, w)
476struct op *t;
477char *w;
478{
479	register struct op **tp;
480
481	return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL);
482}
483
484/*
485 * Enter a new loop level (marked for break/continue).
486 */
487static void
488brkset(bc)
489struct brkcon *bc;
490{
491	bc->nextlev = brklist;
492	brklist = bc;
493}
494
495/*
496 * Wait for the last process created.
497 * Print a message for each process found
498 * that was killed by a signal.
499 * Ignore interrupt signals while waiting
500 * unless `canintr' is true.
501 */
502int
503waitfor(lastpid, canintr)
504register int lastpid;
505int canintr;
506{
507	register int pid, rv;
508	int s;
509	int oheedint = heedint;
510
511	heedint = 0;
512	rv = 0;
513	do {
514		pid = wait(&s);
515		if (pid == -1) {
516			if (errno != EINTR || canintr)
517				break;
518		} else {
519			if ((rv = WAITSIG(s)) != 0) {
520				if (rv < NSIGNAL) {
521					if (signame[rv] != NULL) {
522						if (pid != lastpid) {
523							prn(pid);
524							prs(": ");
525						}
526						prs(signame[rv]);
527					}
528				} else {
529					if (pid != lastpid) {
530						prn(pid);
531						prs(": ");
532					}
533					prs("Signal "); prn(rv); prs(" ");
534				}
535				if (WAITCORE(s))
536					prs(" - core dumped");
537				if (rv >= NSIGNAL || signame[rv])
538					prs("\n");
539				rv = -1;
540			} else
541				rv = WAITVAL(s);
542		}
543	} while (pid != lastpid);
544	heedint = oheedint;
545	if (intr)
546		if (talking) {
547			if (canintr)
548				intr = 0;
549		} else {
550			if (exstat == 0) exstat = rv;
551			onintr(0);
552		}
553	return(rv);
554}
555
556int
557setstatus(s)
558register int s;
559{
560	exstat = s;
561	setval(lookup("?"), putn(s));
562	return(s);
563}
564
565/*
566 * PATH-searching interface to execve.
567 * If getenv("PATH") were kept up-to-date,
568 * execvp might be used.
569 */
570char *
571rexecve(c, v, envp)
572char *c, **v, **envp;
573{
574	register int i;
575	register char *sp, *tp;
576	int eacces = 0, asis = 0;
577
578	sp = any('/', c)? "": path->value;
579	asis = *sp == '\0';
580	while (asis || *sp != '\0') {
581		asis = 0;
582		tp = e.linep;
583		for (; *sp != '\0'; tp++)
584			if ((*tp = *sp++) == ':') {
585				asis = *sp == '\0';
586				break;
587			}
588		if (tp != e.linep)
589			*tp++ = '/';
590		for (i = 0; (*tp++ = c[i++]) != '\0';)
591			;
592		execve(e.linep, v, envp);
593		switch (errno) {
594		case ENOEXEC:
595			*v = e.linep;
596			tp = *--v;
597			*v = e.linep;
598			execve("/bin/sh", v, envp);
599			*v = tp;
600			return("no Shell");
601
602		case ENOMEM:
603			return("program too big");
604
605		case E2BIG:
606			return("argument list too long");
607
608		case EACCES:
609			eacces++;
610			break;
611		}
612	}
613	return(errno==ENOENT ? "not found" : "cannot execute");
614}
615
616/*
617 * Run the command produced by generator `f'
618 * applied to stream `arg'.
619 */
620int
621run(argp, f)
622struct ioarg *argp;
623int (*f)();
624{
625	struct op *otree;
626	struct wdblock *swdlist;
627	struct wdblock *siolist;
628	jmp_buf ev, rt;
629	xint *ofail;
630	int rv;
631
632	areanum++;
633	swdlist = wdlist;
634	siolist = iolist;
635	otree = outtree;
636	ofail = failpt;
637	rv = -1;
638	if (newenv(setjmp(errpt = ev)) == 0) {
639		wdlist = 0;
640		iolist = 0;
641		pushio(argp, f);
642		e.iobase = e.iop;
643		yynerrs = 0;
644		if (setjmp(failpt = rt) == 0 && yyparse() == 0)
645			rv = execute(outtree, NOPIPE, NOPIPE, 0);
646		quitenv();
647	}
648	wdlist = swdlist;
649	iolist = siolist;
650	failpt = ofail;
651	outtree = otree;
652	freearea(areanum--);
653	return(rv);
654}
655
656/* -------- do.c -------- */
657/* #include "sh.h" */
658
659/*
660 * built-in commands: doX
661 */
662
663int
664dolabel()
665{
666	return(0);
667}
668
669int
670dochdir(t)
671register struct op *t;
672{
673	register char *cp, *er;
674
675	if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
676		er = ": no home directory";
677	else if(chdir(cp) < 0)
678		er = ": bad directory";
679	else
680		return(0);
681	prs(cp != NULL? cp: "cd");
682	err(er);
683	return(1);
684}
685
686int
687doshift(t)
688register struct op *t;
689{
690	register n;
691
692	n = t->words[1]? getn(t->words[1]): 1;
693	if(dolc < n) {
694		err("nothing to shift");
695		return(1);
696	}
697	dolv[n] = dolv[0];
698	dolv += n;
699	dolc -= n;
700	setval(lookup("#"), putn(dolc));
701	return(0);
702}
703
704/*
705 * execute login and newgrp directly
706 */
707int
708dologin(t)
709struct op *t;
710{
711	register char *cp;
712
713	if (talking) {
714		signal(SIGINT, SIG_DFL);
715		signal(SIGQUIT, SIG_DFL);
716	}
717	cp = rexecve(t->words[0], t->words, makenv());
718	prs(t->words[0]); prs(": "); err(cp);
719	return(1);
720}
721
722int
723doumask(t)
724register struct op *t;
725{
726	register int i, n;
727	register char *cp;
728
729	if ((cp = t->words[1]) == NULL) {
730		i = umask(0);
731		umask(i);
732		for (n=3*4; (n-=3) >= 0;)
733			putc('0'+((i>>n)&07));
734		putc('\n');
735	} else {
736		for (n=0; *cp>='0' && *cp<='9'; cp++)
737			n = n*8 + (*cp-'0');
738		umask(n);
739	}
740	return(0);
741}
742
743int
744doexec(t)
745register struct op *t;
746{
747	register i;
748	jmp_buf ex;
749	xint *ofail;
750
751	t->ioact = NULL;
752	for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++)
753		;
754	if (i == 0)
755		return(1);
756	execflg = 1;
757	ofail = failpt;
758	if (setjmp(failpt = ex) == 0)
759		execute(t, NOPIPE, NOPIPE, FEXEC);
760	failpt = ofail;
761	execflg = 0;
762	return(1);
763}
764
765int
766dodot(t)
767struct op *t;
768{
769	register i;
770	register char *sp, *tp;
771	char *cp;
772
773	if ((cp = t->words[1]) == NULL)
774		return(0);
775	sp = any('/', cp)? ":": path->value;
776	while (*sp) {
777		tp = e.linep;
778		while (*sp && (*tp = *sp++) != ':')
779			tp++;
780		if (tp != e.linep)
781			*tp++ = '/';
782		for (i = 0; (*tp++ = cp[i++]) != '\0';)
783			;
784		if ((i = open(e.linep, 0)) >= 0) {
785			exstat = 0;
786			next(remap(i));
787			return(exstat);
788		}
789	}
790	prs(cp);
791	err(": not found");
792	return(-1);
793}
794
795int
796dowait(t)
797struct op *t;
798{
799	register i;
800	register char *cp;
801
802	if ((cp = t->words[1]) != NULL) {
803		i = getn(cp);
804		if (i == 0)
805			return(0);
806	} else
807		i = -1;
808	setstatus(waitfor(i, 1));
809	return(0);
810}
811
812int
813doread(t)
814struct op *t;
815{
816	register char *cp, **wp;
817	register nb;
818	register int  nl = 0;
819
820	if (t->words[1] == NULL) {
821		err("usage: read name ...");
822		return(1);
823	}
824	for (wp = t->words+1; *wp; wp++) {
825		for (cp = e.linep; !nl && cp < elinep-1; cp++)
826			if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
827			    (nl = (*cp == '\n')) ||
828			    (wp[1] && any(*cp, ifs->value)))
829				break;
830		*cp = 0;
831		if (nb <= 0)
832			break;
833		setval(lookup(*wp), e.linep);
834	}
835	return(nb <= 0);
836}
837
838int
839doeval(t)
840register struct op *t;
841{
842	return(RUN(awordlist, t->words+1, wdchar));
843}
844
845int
846dotrap(t)
847register struct op *t;
848{
849	register int  n, i;
850	register int  resetsig;
851
852	if (t->words[1] == NULL) {
853		for (i=0; i<=_NSIG; i++)
854			if (trap[i]) {
855				prn(i);
856				prs(": ");
857				prs(trap[i]);
858				prs("\n");
859			}
860		return(0);
861	}
862	resetsig = digit(*t->words[1]);
863	for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
864		n = getsig(t->words[i]);
865		xfree(trap[n]);
866		trap[n] = 0;
867		if (!resetsig) {
868			if (*t->words[1] != '\0') {
869				trap[n] = strsave(t->words[1], 0);
870				setsig(n, sig);
871			} else
872				setsig(n, SIG_IGN);
873		} else {
874			if (talking)
875				if (n == SIGINT)
876					setsig(n, onintr);
877				else
878					setsig(n, n == SIGQUIT ? SIG_IGN
879							       : SIG_DFL);
880			else
881				setsig(n, SIG_DFL);
882		}
883	}
884	return(0);
885}
886
887int
888getsig(s)
889char *s;
890{
891	register int n;
892
893	if ((n = getn(s)) < 0 || n > _NSIG) {
894		err("trap: bad signal number");
895		n = 0;
896	}
897	return(n);
898}
899
900void
901setsig(n, f)
902register n;
903_PROTOTYPE(void (*f), (int));
904{
905	if (n == 0)
906		return;
907	if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
908		ourtrap[n] = 1;
909		signal(n, f);
910	}
911}
912
913int
914getn(as)
915char *as;
916{
917	register char *s;
918	register n, m;
919
920	s = as;
921	m = 1;
922	if (*s == '-') {
923		m = -1;
924		s++;
925	}
926	for (n = 0; digit(*s); s++)
927		n = (n*10) + (*s-'0');
928	if (*s) {
929		prs(as);
930		err(": bad number");
931	}
932	return(n*m);
933}
934
935int
936dobreak(t)
937struct op *t;
938{
939	return(brkcontin(t->words[1], 1));
940}
941
942int
943docontinue(t)
944struct op *t;
945{
946	return(brkcontin(t->words[1], 0));
947}
948
949static int
950brkcontin(cp, val)
951register char *cp;
952int val;
953{
954	register struct brkcon *bc;
955	register nl;
956
957	nl = cp == NULL? 1: getn(cp);
958	if (nl <= 0)
959		nl = 999;
960	do {
961		if ((bc = brklist) == NULL)
962			break;
963		brklist = bc->nextlev;
964	} while (--nl);
965	if (nl) {
966		err("bad break/continue level");
967		return(1);
968	}
969	isbreak = val;
970	longjmp(bc->brkpt, 1);
971	/* NOTREACHED */
972}
973
974int
975doexit(t)
976struct op *t;
977{
978	register char *cp;
979
980	execflg = 0;
981	if ((cp = t->words[1]) != NULL)
982		setstatus(getn(cp));
983	leave();
984	/* NOTREACHED */
985}
986
987int
988doexport(t)
989struct op *t;
990{
991	rdexp(t->words+1, export, EXPORT);
992	return(0);
993}
994
995int
996doreadonly(t)
997struct op *t;
998{
999	rdexp(t->words+1, ronly, RONLY);
1000	return(0);
1001}
1002
1003static void
1004rdexp(wp, f, key)
1005register char **wp;
1006void (*f)();
1007int key;
1008{
1009	if (*wp != NULL) {
1010		for (; *wp != NULL; wp++)
1011			if (checkname(*wp))
1012				(*f)(lookup(*wp));
1013			else
1014				badid(*wp);
1015	} else
1016		putvlist(key, 1);
1017}
1018
1019static void
1020badid(s)
1021register char *s;
1022{
1023	prs(s);
1024	err(": bad identifier");
1025}
1026
1027int
1028doset(t)
1029register struct op *t;
1030{
1031	register struct var *vp;
1032	register char *cp;
1033	register n;
1034
1035	if ((cp = t->words[1]) == NULL) {
1036		for (vp = vlist; vp; vp = vp->next)
1037			varput(vp->name, 1);
1038		return(0);
1039	}
1040	if (*cp == '-') {
1041		/* bad: t->words++; */
1042		for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++)
1043			;
1044		if (*++cp == 0)
1045			flag['x'] = flag['v'] = 0;
1046		else
1047			for (; *cp; cp++)
1048				switch (*cp) {
1049				case 'e':
1050					if (!talking)
1051						flag['e']++;
1052					break;
1053
1054				default:
1055					if (*cp>='a' && *cp<='z')
1056						flag[*cp]++;
1057					break;
1058				}
1059		setdash();
1060	}
1061	if (t->words[1]) {
1062		t->words[0] = dolv[0];
1063		for (n=1; t->words[n]; n++)
1064			setarea((char *)t->words[n], 0);
1065		dolc = n-1;
1066		dolv = t->words;
1067		setval(lookup("#"), putn(dolc));
1068		setarea((char *)(dolv-1), 0);
1069	}
1070	return(0);
1071}
1072
1073void
1074varput(s, out)
1075register char *s;
1076int out;
1077{
1078	if (letnum(*s)) {
1079		write(out, s, strlen(s));
1080		write(out, "\n", 1);
1081	}
1082}
1083
1084
1085#define	SECS	60L
1086#define	MINS	3600L
1087
1088int
1089dotimes()
1090{
1091	struct tms tbuf;
1092
1093	times(&tbuf);
1094
1095	prn((int)(tbuf.tms_cutime / MINS));
1096	prs("m");
1097	prn((int)((tbuf.tms_cutime % MINS) / SECS));
1098	prs("s ");
1099	prn((int)(tbuf.tms_cstime / MINS));
1100	prs("m");
1101	prn((int)((tbuf.tms_cstime % MINS) / SECS));
1102	prs("s\n");
1103	return(0);
1104}
1105
1106struct	builtin {
1107	char	*command;
1108	int	(*fn)();
1109};
1110static struct	builtin	builtin[] = {
1111	":",		dolabel,
1112	"cd",		dochdir,
1113	"shift",	doshift,
1114	"exec",		doexec,
1115	"wait",		dowait,
1116	"read",		doread,
1117	"eval",		doeval,
1118	"trap",		dotrap,
1119	"break",	dobreak,
1120	"continue",	docontinue,
1121	"exit",		doexit,
1122	"export",	doexport,
1123	"readonly",	doreadonly,
1124	"set",		doset,
1125	".",		dodot,
1126	"umask",	doumask,
1127	"login",	dologin,
1128	"newgrp",	dologin,
1129	"times",	dotimes,
1130	0,
1131};
1132
1133int (*inbuilt(s))()
1134register char *s;
1135{
1136	register struct builtin *bp;
1137
1138	for (bp = builtin; bp->command != NULL; bp++)
1139		if (strcmp(bp->command, s) == 0)
1140			return(bp->fn);
1141	return((int(*)())NULL);
1142}
1143
1144