]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - release/picobsd/tinyware/msh/sh3.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / release / picobsd / tinyware / msh / sh3.c
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
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
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
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
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
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 **
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 *
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
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
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
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 *
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
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
664 dolabel()
665 {
666         return(0);
667 }
668
669 int
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
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
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
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
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
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
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
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
839 doeval(t)
840 register struct op *t;
841 {
842         return(RUN(awordlist, t->words+1, wdchar));
843 }
844
845 int
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
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
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
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
936 dobreak(t)
937 struct op *t;
938 {
939         return(brkcontin(t->words[1], 1));
940 }
941
942 int
943 docontinue(t)
944 struct op *t;
945 {
946         return(brkcontin(t->words[1], 0));
947 }
948
949 static int
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
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
988 doexport(t)
989 struct op *t;
990 {
991         rdexp(t->words+1, export, EXPORT);
992         return(0);
993 }
994
995 int
996 doreadonly(t)
997 struct op *t;
998 {
999         rdexp(t->words+1, ronly, RONLY);
1000         return(0);
1001 }
1002
1003 static void
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
1020 badid(s)
1021 register char *s;
1022 {
1023         prs(s);
1024         err(": bad identifier");
1025 }
1026
1027 int
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
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
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