Commit | Line | Data |
---|---|---|
41c680d7 BJ |
1 | /* Copyright (c) 1979 Regents of the University of California */ |
2 | #include "sh.h" | |
3 | ||
4 | /* | |
5 | * C shell | |
6 | */ | |
7 | ||
8 | struct biltins * | |
9 | isbfunc(cp) | |
10 | register char *cp; | |
11 | { | |
12 | register char *dp; | |
13 | register struct biltins *bp; | |
14 | ||
15 | if (lastchr(cp) == ':') | |
16 | return ((struct biltins *) 1); | |
17 | for (bp = bfunc; dp = bp->bname; bp++) { | |
18 | if (dp[0] == cp[0] && eq(dp, cp)) | |
19 | return (bp); | |
20 | if (dp[0] > cp[0]) | |
21 | break; | |
22 | } | |
23 | return (0); | |
24 | } | |
25 | ||
26 | func(t) | |
27 | register struct command *t; | |
28 | { | |
29 | register struct biltins *bp; | |
30 | int i; | |
31 | ||
32 | bp = bfunc; | |
33 | if (lastchr(t->t_dcom[0]) == ':') { | |
34 | xechoit(t->t_dcom); | |
35 | if (!eq(t->t_dcom[0], ":") && t->t_dcom[1]) | |
36 | error("No args on labels"); | |
37 | return (1); | |
38 | } | |
39 | bp = isbfunc(t->t_dcom[0]); | |
40 | if (bp == 0) | |
41 | return (0); | |
42 | /* timed builtins must go in background if output is pipe, or &'ed */ | |
43 | if (eq(bp->bname, "time")) | |
44 | if ((t->t_dflg & FAND) || (t->t_dflg & FPOU)) | |
45 | return (0); | |
46 | if (eq(bp->bname, "nohup") && t->t_dcom[1]) | |
47 | return (0); | |
48 | xechoit(t->t_dcom); | |
49 | setname(bp->bname); | |
50 | i = blklen(t->t_dcom) - 1; | |
51 | if (i < bp->minargs) | |
52 | bferr("Too few arguments"); | |
53 | if (i > bp->maxargs) | |
54 | bferr("Too many arguments"); | |
55 | i = (*bp->bfunct)(t->t_dcom, t); | |
56 | /* time and nice may not do their deeds, all others guarantee too */ | |
57 | return (eq(bp->bname, "time") || eq(bp->bname, "nice") ? i : 1); | |
58 | } | |
59 | ||
60 | doonintr(v) | |
61 | char **v; | |
62 | { | |
63 | register char *cp; | |
64 | register char *vv = v[1]; | |
65 | ||
66 | if (parintr == SIG_IGN) | |
67 | return; | |
68 | if (setintr && intty) | |
69 | bferr("Can't from terminal"); | |
70 | cp = gointr, gointr = 0, xfree(cp); | |
71 | if (vv == 0) { | |
72 | signal(SIGINT, setintr ? SIG_IGN : SIG_DFL); | |
73 | gointr = 0; | |
74 | } else if (eq((vv = strip(vv)), "-")) { | |
75 | signal(SIGINT, SIG_IGN); | |
76 | gointr = "-"; | |
77 | } else { | |
78 | gointr = savestr(vv); | |
79 | signal(SIGINT, pintr); | |
80 | } | |
81 | } | |
82 | ||
83 | donohup() | |
84 | { | |
85 | ||
86 | if (intty) | |
87 | bferr("Can't from terminal"); | |
88 | if (setintr == 0) { | |
89 | signal(SIGHUP, SIG_IGN); | |
90 | #ifdef CC | |
91 | submit(getpid()); | |
92 | #endif | |
93 | } | |
94 | } | |
95 | ||
96 | dozip() | |
97 | { | |
98 | ||
99 | ; | |
100 | } | |
101 | ||
102 | chngd(vp) | |
103 | register char **vp; | |
104 | { | |
105 | register int i; | |
106 | register char *dp; | |
107 | ||
108 | vp++; | |
109 | dp = *vp; | |
110 | if (dp) | |
111 | dp = globone(dp); | |
112 | else { | |
113 | dp = value("home"); | |
114 | if (*dp == 0) | |
115 | bferr("No home"); | |
116 | } | |
117 | i = chdir(dp); | |
118 | if (*vp) | |
119 | xfree(dp); | |
120 | if (i < 0) | |
121 | Perror(dp); | |
122 | } | |
123 | ||
124 | prvars() | |
125 | { | |
126 | ||
127 | plist(&shvhed); | |
128 | } | |
129 | ||
130 | doalias(v) | |
131 | register char **v; | |
132 | { | |
133 | register struct varent *vp; | |
134 | register char *p; | |
135 | ||
136 | v++; | |
137 | p = *v++; | |
138 | if (p == 0) | |
139 | plist(&aliases); | |
140 | else if (*v == 0) { | |
141 | vp = adrof1(strip(p), &aliases); | |
142 | if (vp) | |
143 | blkpr(vp->vec), printf("\n"); | |
144 | } else { | |
145 | if (eq(p, "alias") || eq(p, "unalias")) { | |
146 | setname(p); | |
147 | bferr("Too dangerous to alias that"); | |
148 | } | |
149 | set1(strip(p), saveblk(v), &aliases); | |
150 | } | |
151 | } | |
152 | ||
153 | unalias(v) | |
154 | char **v; | |
155 | { | |
156 | ||
157 | unset1(v, &aliases); | |
158 | } | |
159 | ||
160 | dologout() | |
161 | { | |
162 | ||
163 | islogin(); | |
164 | goodbye(); | |
165 | } | |
166 | ||
167 | islogin() | |
168 | { | |
169 | ||
170 | if (loginsh) | |
171 | return; | |
172 | error("Not login shell"); | |
173 | } | |
174 | ||
175 | doif(v, kp) | |
176 | char **v; | |
177 | struct command *kp; | |
178 | { | |
179 | register int i; | |
180 | register char **vv; | |
181 | ||
182 | v++; | |
183 | i = exp(&v); | |
184 | vv = v; | |
185 | if (*vv && eq(*vv, "then")) { | |
186 | vv++; | |
187 | if (*vv) | |
188 | bferr("Improper then"); | |
189 | setname("then"); | |
190 | /* | |
191 | * If expression was zero, then scan to else, | |
192 | * otherwise just fall into following code. | |
193 | */ | |
194 | if (!i) | |
195 | search(ZIF, 0); | |
196 | return; | |
197 | } | |
198 | /* | |
199 | * Simple command attached to this if. | |
200 | * Left shift the node in this tree, munging it | |
201 | * so we can reexecute it. | |
202 | */ | |
203 | if (i) { | |
204 | lshift(kp->t_dcom, vv - kp->t_dcom); | |
205 | reexecute(kp); | |
206 | donefds(); | |
207 | } | |
208 | } | |
209 | ||
210 | /* | |
211 | * Reexecute a command, being careful not | |
212 | * to redo i/o redirection, which is already set up. | |
213 | */ | |
214 | reexecute(kp) | |
215 | register struct command *kp; | |
216 | { | |
217 | ||
218 | kp->t_dflg = FREDO; | |
219 | execute(kp); | |
220 | } | |
221 | ||
222 | doelse() | |
223 | { | |
224 | ||
225 | search(ZELSE, 0); | |
226 | } | |
227 | ||
228 | dogoto(v) | |
229 | char **v; | |
230 | { | |
231 | register struct whyle *wp; | |
232 | char *lp; | |
233 | ||
234 | /* | |
235 | * While we still can, locate any unknown ends of existing loops. | |
236 | * This obscure code is the WORST result of the fact that we | |
237 | * don't really parse. | |
238 | */ | |
239 | for (wp = whyles; wp; wp = wp->w_next) | |
240 | if (wp->w_end == 0) | |
241 | wp->w_end = search(ZBREAK, 0); | |
242 | else | |
243 | bseek(wp->w_end); | |
244 | search(ZGOTO, 0, lp = globone(v[1])); | |
245 | xfree(lp); | |
246 | /* | |
247 | * Eliminate loops which were exited. | |
248 | */ | |
249 | wfree(); | |
250 | } | |
251 | ||
252 | doswitch(v) | |
253 | register char **v; | |
254 | { | |
255 | register char *cp, *lp; | |
256 | ||
257 | v++; | |
258 | if (!*v || *(*v++) != '(') | |
259 | goto syntax; | |
260 | cp = **v == ')' ? "" : *v++; | |
261 | if (*(*v++) != ')') | |
262 | v--; | |
263 | if (*v) | |
264 | syntax: | |
265 | error("Syntax error"); | |
266 | search(ZSWITCH, 0, lp = globone(cp)); | |
267 | xfree(lp); | |
268 | } | |
269 | ||
270 | dobreak() | |
271 | { | |
272 | ||
273 | if (whyles) | |
274 | toend(); | |
275 | else | |
276 | bferr("Not in while/foreach"); | |
277 | } | |
278 | ||
279 | doexit(v) | |
280 | char **v; | |
281 | { | |
282 | ||
283 | /* | |
284 | * Don't DEMAND parentheses here either. | |
285 | */ | |
286 | v++; | |
287 | if (*v) { | |
288 | set("status", putn(exp(&v))); | |
289 | if (*v) | |
290 | bferr("Expression syntax"); | |
291 | } | |
292 | btoeof(); | |
293 | if (intty) | |
294 | close(SHIN); | |
295 | } | |
296 | ||
297 | doforeach(v) | |
298 | register char **v; | |
299 | { | |
300 | register char *cp; | |
301 | register struct whyle *nwp; | |
302 | ||
303 | v++; | |
304 | cp = strip(*v); | |
305 | while (*cp && letter(*cp)) | |
306 | cp++; | |
307 | if (*cp || strlen(*v) >= 20) | |
308 | bferr("Invalid variable"); | |
309 | cp = *v++; | |
310 | if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') | |
311 | bferr("Words not ()'ed"); | |
312 | v++; | |
313 | gflag = 0, rscan(v, tglob); | |
314 | v = glob(v); | |
315 | if (v == 0) | |
316 | bferr("No match"); | |
317 | nwp = (struct whyle *) calloc(1, sizeof *nwp); | |
318 | nwp->w_fe = nwp->w_fe0 = v; gargv = 0; | |
319 | nwp->w_start = btell(); | |
320 | nwp->w_fename = savestr(cp); | |
321 | nwp->w_next = whyles; | |
322 | whyles = nwp; | |
323 | /* | |
324 | * Pre-read the loop so as to be more | |
325 | * comprehensible to a terminal user. | |
326 | */ | |
327 | if (intty) | |
328 | preread(); | |
329 | doagain(); | |
330 | } | |
331 | ||
332 | dowhile(v) | |
333 | char **v; | |
334 | { | |
335 | register int status; | |
336 | register bool again = whyles != 0 && whyles->w_start == lineloc; | |
337 | ||
338 | v++; | |
339 | /* | |
340 | * Implement prereading here also, taking care not to | |
341 | * evaluate the expression before the loop has been read up | |
342 | * from a terminal. | |
343 | */ | |
344 | if (intty && !again) | |
345 | status = !exp0(&v, 1); | |
346 | else | |
347 | status = !exp(&v); | |
348 | if (*v) | |
349 | bferr("Expression syntax"); | |
350 | if (!again) { | |
351 | register struct whyle *nwp = (struct whyle *) calloc(1, sizeof (*nwp)); | |
352 | ||
353 | nwp->w_start = lineloc; | |
354 | nwp->w_end = 0; | |
355 | nwp->w_next = whyles; | |
356 | whyles = nwp; | |
357 | if (intty) { | |
358 | /* | |
359 | * The tty preread | |
360 | */ | |
361 | preread(); | |
362 | doagain(); | |
363 | return; | |
364 | } | |
365 | } | |
366 | if (status) | |
367 | /* We ain't gonna loop no more, no more! */ | |
368 | toend(); | |
369 | } | |
370 | ||
371 | preread() | |
372 | { | |
373 | register int (*oldint)(); | |
374 | ||
375 | whyles->w_end = -1; | |
376 | if (setintr) | |
377 | oldint = signal(SIGINT, pintr); | |
378 | search(ZBREAK, 0); | |
379 | if (setintr) | |
380 | signal(SIGINT, oldint); | |
381 | whyles->w_end = btell(); | |
382 | } | |
383 | ||
384 | doend() | |
385 | { | |
386 | ||
387 | if (!whyles) | |
388 | bferr("Not in while/foreach"); | |
389 | whyles->w_end = btell(); | |
390 | doagain(); | |
391 | } | |
392 | ||
393 | docontin() | |
394 | { | |
395 | ||
396 | if (!whyles) | |
397 | bferr("Not in while/foreach"); | |
398 | doagain(); | |
399 | } | |
400 | ||
401 | doagain() | |
402 | { | |
403 | ||
404 | /* Repeating a while is simple */ | |
405 | if (whyles->w_fename == 0) { | |
406 | bseek(whyles->w_start); | |
407 | return; | |
408 | } | |
409 | /* | |
410 | * The foreach variable list actually has a spurious word | |
411 | * ")" at the end of the w_fe list. Thus we are at the | |
412 | * of the list if one word beyond this is 0. | |
413 | */ | |
414 | if (!whyles->w_fe[1]) { | |
415 | dobreak(); | |
416 | return; | |
417 | } | |
418 | set(whyles->w_fename, savestr(*whyles->w_fe++)); | |
419 | bseek(whyles->w_start); | |
420 | } | |
421 | ||
422 | dorepeat(v, kp) | |
423 | char **v; | |
424 | struct command *kp; | |
425 | { | |
426 | register int i; | |
427 | register int (*saveintr)(); | |
428 | ||
429 | i = getn(v[1]); | |
430 | if (setintr) | |
431 | saveintr = signal(SIGINT, SIG_IGN); | |
432 | lshift(v, 2); | |
433 | while (i > 0) { | |
434 | if (setintr) | |
435 | signal(SIGINT, pintr); | |
436 | reexecute(kp); | |
437 | --i; | |
438 | } | |
439 | donefds(); | |
440 | if (setintr) | |
441 | signal(SIGINT, saveintr); | |
442 | } | |
443 | ||
444 | doswbrk() | |
445 | { | |
446 | ||
447 | search(ZBRKSW, 0); | |
448 | } | |
449 | ||
450 | srchx(cp) | |
451 | register char *cp; | |
452 | { | |
453 | register struct srch *sp; | |
454 | ||
455 | for (sp = srchn; sp->s_name; sp++) | |
456 | if (eq(cp, sp->s_name)) | |
457 | return (sp->s_value); | |
458 | return (-1); | |
459 | } | |
460 | ||
461 | char Stype; | |
462 | char *Sgoal; | |
463 | ||
464 | /*VARARGS2*/ | |
465 | search(type, level, goal) | |
466 | int type; | |
467 | register int level; | |
468 | char *goal; | |
469 | { | |
470 | char wordbuf[BUFSIZ]; | |
471 | register char *aword = wordbuf; | |
472 | register char *cp; | |
473 | ||
474 | Stype = type; Sgoal = goal; | |
475 | if (type == ZGOTO) | |
476 | bseek(0l); | |
477 | do { | |
478 | if (intty && fseekp == feobp) | |
479 | printf("? "), flush(); | |
480 | aword[0] = 0, getword(aword); | |
481 | switch (srchx(aword)) { | |
482 | ||
483 | case ZELSE: | |
484 | if (level == 0 && type == ZIF) | |
485 | return; | |
486 | break; | |
487 | ||
488 | case ZIF: | |
489 | while (getword(aword)) | |
490 | continue; | |
491 | if ((type == ZIF || type == ZELSE) && eq(aword, "then")) | |
492 | level++; | |
493 | break; | |
494 | ||
495 | case ZENDIF: | |
496 | if (type == ZIF || type == ZELSE) | |
497 | level--; | |
498 | break; | |
499 | ||
500 | case ZFOREACH: | |
501 | case ZWHILE: | |
502 | if (type == ZBREAK) | |
503 | level++; | |
504 | break; | |
505 | ||
506 | case ZEND: | |
507 | if (type == ZBREAK) | |
508 | level--; | |
509 | break; | |
510 | ||
511 | case ZSWITCH: | |
512 | if (type == ZSWITCH || type == ZBRKSW) | |
513 | level++; | |
514 | break; | |
515 | ||
516 | case ZENDSW: | |
517 | if (type == ZSWITCH || type == ZBRKSW) | |
518 | level--; | |
519 | break; | |
520 | ||
521 | case ZLABEL: | |
522 | if (type == ZGOTO && getword(aword) && eq(aword, goal)) | |
523 | level = -1; | |
524 | break; | |
525 | ||
526 | default: | |
527 | if (type != ZGOTO && (type != ZSWITCH || level != 0)) | |
528 | break; | |
529 | if (lastchr(aword) != ':') | |
530 | break; | |
531 | aword[strlen(aword) - 1] = 0; | |
532 | if (type == ZGOTO && eq(aword, goal) || type == ZSWITCH && eq(aword, "default")) | |
533 | level = -1; | |
534 | break; | |
535 | ||
536 | case ZCASE: | |
537 | if (type != ZSWITCH || level != 0) | |
538 | break; | |
539 | getword(aword); | |
540 | if (lastchr(aword) == ':') | |
541 | aword[strlen(aword) - 1] = 0; | |
542 | cp = strip(Dfix1(aword)); | |
543 | if (Gmatch(goal, cp)) | |
544 | level = -1; | |
545 | xfree(cp); | |
546 | break; | |
547 | ||
548 | case ZDEFAULT: | |
549 | if (type == ZSWITCH && level == 0) | |
550 | level = -1; | |
551 | break; | |
552 | } | |
553 | getword(0); | |
554 | } while (level >= 0); | |
555 | } | |
556 | ||
557 | getword(wp) | |
558 | register char *wp; | |
559 | { | |
560 | register int found = 0; | |
561 | register int c, d; | |
562 | ||
563 | c = readc(1); | |
564 | d = 0; | |
565 | do { | |
566 | while (c == ' ' || c == '\t') | |
567 | c = readc(1); | |
568 | if (c < 0) | |
569 | goto past; | |
570 | if (c == '\n') { | |
571 | if (wp) | |
572 | break; | |
573 | return (0); | |
574 | } | |
575 | unreadc(c); | |
576 | found = 1; | |
577 | do { | |
578 | c = readc(1); | |
579 | if (c == '\\' && (c = readc(1)) == '\n') | |
580 | c = ' '; | |
581 | if (any(c, "'\"")) | |
582 | if (d == 0) | |
583 | d = c; | |
584 | else if (d == c) | |
585 | d = 0; | |
586 | if (c < 0) | |
587 | goto past; | |
588 | if (wp) | |
589 | *wp++ = c; | |
590 | } while ((d || c != ' ' && c != '\t') && c != '\n'); | |
591 | } while (wp == 0); | |
592 | unreadc(c); | |
593 | if (found) | |
594 | *--wp = 0; | |
595 | return (found); | |
596 | ||
597 | past: | |
598 | switch (Stype) { | |
599 | ||
600 | case ZIF: | |
601 | bferr("then/endif not found"); | |
602 | ||
603 | case ZELSE: | |
604 | bferr("endif not found"); | |
605 | ||
606 | case ZBRKSW: | |
607 | case ZSWITCH: | |
608 | bferr("endsw not found"); | |
609 | ||
610 | case ZBREAK: | |
611 | bferr("end not found"); | |
612 | ||
613 | case ZGOTO: | |
614 | setname(Sgoal); | |
615 | bferr("label not found"); | |
616 | } | |
617 | /*NOTREACHED*/ | |
618 | } | |
619 | ||
620 | toend() | |
621 | { | |
622 | ||
623 | if (whyles->w_end == 0) { | |
624 | search(ZBREAK, 0); | |
625 | whyles->w_end = btell() - 1; | |
626 | } else | |
627 | bseek(whyles->w_end); | |
628 | wfree(); | |
629 | } | |
630 | ||
631 | wfree() | |
632 | { | |
633 | long o = btell(); | |
634 | ||
635 | while (whyles) { | |
636 | register struct whyle *wp = whyles; | |
637 | register struct whyle *nwp = wp->w_next; | |
638 | ||
639 | if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) | |
640 | break; | |
641 | if (wp->w_fe0) | |
642 | blkfree(wp->w_fe0); | |
643 | if (wp->w_fename) | |
644 | xfree(wp->w_fename); | |
645 | xfree(wp); | |
646 | whyles = nwp; | |
647 | } | |
648 | } | |
649 | ||
650 | doecho(v) | |
651 | char **v; | |
652 | { | |
653 | ||
654 | echo(' ', v); | |
655 | } | |
656 | ||
657 | doglob(v) | |
658 | char **v; | |
659 | { | |
660 | ||
661 | echo(0, v); | |
662 | flush(); | |
663 | } | |
664 | ||
665 | echo(sep, v) | |
666 | char sep; | |
667 | register char **v; | |
668 | { | |
669 | register char *cp; | |
670 | int (*saveintr)(); | |
671 | if (setintr) | |
672 | saveintr = signal(SIGINT, pintr); | |
673 | ||
674 | v++; | |
675 | if (*v == 0) | |
676 | return; | |
677 | gflag = 0; rscan(v, tglob); | |
678 | if (gflag) { | |
679 | v = glob(v); | |
680 | if (v == 0) | |
681 | bferr("No match"); | |
682 | } else | |
683 | scan(v, trim); | |
684 | while (cp = *v++) { | |
685 | register int c; | |
686 | ||
687 | while (c = *cp++) { | |
688 | if (sep == ' ' && *cp && c == '\\') { | |
689 | c = *cp++; | |
690 | if (c == 'c') { | |
691 | flush(); | |
692 | return; | |
693 | } else if (c == 'n') | |
694 | c = '\n'; | |
695 | else | |
696 | putchar('\\'); | |
697 | } | |
698 | putchar(c | QUOTE); | |
699 | } | |
700 | if (*v) | |
701 | putchar(sep | QUOTE); | |
702 | } | |
703 | if (sep) | |
704 | putchar('\n'); | |
705 | if (setintr) | |
706 | signal(SIGINT, saveintr); | |
707 | if (gargv) | |
708 | blkfree(gargv), gargv = 0; | |
709 | } | |
710 | ||
711 | #ifndef V6 | |
712 | char **environ; | |
713 | ||
714 | dosetenv(v) | |
715 | register char **v; | |
716 | { | |
717 | char *lp = globone(v[2]); | |
718 | ||
719 | setenv(v[1], lp); | |
720 | xfree(lp); | |
721 | } | |
722 | ||
723 | setenv(name, value) | |
724 | char *name, *value; | |
725 | { | |
726 | register char **ep = environ; | |
727 | register char *cp, *dp; | |
728 | char *blk[2], **oep = ep; | |
729 | ||
730 | for (; *ep; ep++) { | |
731 | for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) | |
732 | continue; | |
733 | if (*cp != 0 || *dp != '=') | |
734 | continue; | |
735 | cp = strspl("=", value); | |
736 | xfree(*ep); | |
737 | *ep = strspl(name, cp); | |
738 | xfree(cp); | |
739 | return; | |
740 | } | |
741 | blk[0] = strspl(name, "="); blk[1] = 0; | |
742 | environ = blkspl(environ, blk); | |
743 | xfree(oep); | |
744 | setenv(name, value); | |
745 | } | |
746 | ||
747 | doumask(v) | |
748 | register char **v; | |
749 | { | |
750 | register char *cp = v[1]; | |
751 | register int i; | |
752 | ||
753 | if (cp == 0) { | |
754 | i = umask(0); | |
755 | umask(i); | |
756 | printf("%o\n", i); | |
757 | return; | |
758 | } | |
759 | i = 0; | |
760 | while (digit(*cp) && *cp != '8' && *cp != '9') | |
761 | i = i * 8 + *cp++ - '0'; | |
762 | if (*cp || i < 0 || i > 0777) | |
763 | bferr("Improper mask"); | |
764 | umask(i); | |
765 | } | |
766 | #endif |