xref: /NextBSD/release/picobsd/tinyware/msh/sh3.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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 
22 static	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 
76 int
execute(t,pin,pout,act)77 execute(t, pin, pout, act)
78 register struct op *t;
79 int *pin, *pout;
80 int 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 
219 broken:
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 
236 static int
forkexec(t,pin,pout,act,wp,pforked)237 forkexec(t, pin, pout, act, wp, pforked)
238 register struct op *t;
239 int *pin, *pout;
240 int act;
241 char **wp;
242 int *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  */
347 static int
parent()348 parent()
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  */
364 int
iosetup(iop,pipein,pipeout)365 iosetup(iop, pipein, pipeout)
366 register struct ioword *iop;
367 int 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 
436 static void
echo(wp)437 echo(wp)
438 register 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 
451 static struct op **
find1case(t,w)452 find1case(t, w)
453 struct op *t;
454 char *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 
474 static struct op *
findcase(t,w)475 findcase(t, w)
476 struct op *t;
477 char *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  */
487 static void
brkset(bc)488 brkset(bc)
489 struct 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  */
502 int
waitfor(lastpid,canintr)503 waitfor(lastpid, canintr)
504 register int lastpid;
505 int 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 
556 int
setstatus(s)557 setstatus(s)
558 register 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  */
570 char *
rexecve(c,v,envp)571 rexecve(c, v, envp)
572 char *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  */
620 int
run(argp,f)621 run(argp, f)
622 struct ioarg *argp;
623 int (*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 
663 int
dolabel()664 dolabel()
665 {
666 	return(0);
667 }
668 
669 int
dochdir(t)670 dochdir(t)
671 register 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 
686 int
doshift(t)687 doshift(t)
688 register 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  */
707 int
dologin(t)708 dologin(t)
709 struct 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 
722 int
doumask(t)723 doumask(t)
724 register 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 
743 int
doexec(t)744 doexec(t)
745 register 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 
765 int
dodot(t)766 dodot(t)
767 struct 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 
795 int
dowait(t)796 dowait(t)
797 struct 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 
812 int
doread(t)813 doread(t)
814 struct 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 
838 int
doeval(t)839 doeval(t)
840 register struct op *t;
841 {
842 	return(RUN(awordlist, t->words+1, wdchar));
843 }
844 
845 int
dotrap(t)846 dotrap(t)
847 register 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 
887 int
getsig(s)888 getsig(s)
889 char *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 
900 void
setsig(n,f)901 setsig(n, f)
902 register 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 
913 int
getn(as)914 getn(as)
915 char *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 
935 int
dobreak(t)936 dobreak(t)
937 struct op *t;
938 {
939 	return(brkcontin(t->words[1], 1));
940 }
941 
942 int
docontinue(t)943 docontinue(t)
944 struct op *t;
945 {
946 	return(brkcontin(t->words[1], 0));
947 }
948 
949 static int
brkcontin(cp,val)950 brkcontin(cp, val)
951 register char *cp;
952 int 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 
974 int
doexit(t)975 doexit(t)
976 struct 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 
987 int
doexport(t)988 doexport(t)
989 struct op *t;
990 {
991 	rdexp(t->words+1, export, EXPORT);
992 	return(0);
993 }
994 
995 int
doreadonly(t)996 doreadonly(t)
997 struct op *t;
998 {
999 	rdexp(t->words+1, ronly, RONLY);
1000 	return(0);
1001 }
1002 
1003 static void
rdexp(wp,f,key)1004 rdexp(wp, f, key)
1005 register char **wp;
1006 void (*f)();
1007 int 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 
1019 static void
badid(s)1020 badid(s)
1021 register char *s;
1022 {
1023 	prs(s);
1024 	err(": bad identifier");
1025 }
1026 
1027 int
doset(t)1028 doset(t)
1029 register 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 
1073 void
varput(s,out)1074 varput(s, out)
1075 register char *s;
1076 int 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 
1088 int
dotimes()1089 dotimes()
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 
1106 struct	builtin {
1107 	char	*command;
1108 	int	(*fn)();
1109 };
1110 static 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 
1133 int (*inbuilt(s))()
1134 register 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