Commit | Line | Data |
---|---|---|
b79f4fa9 DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
094e80ed | 3 | * All rights reserved. The Berkeley Software License Agreement |
b79f4fa9 DF |
4 | * specifies the terms and conditions for redistribution. |
5 | */ | |
6 | ||
35371dec | 7 | #ifndef lint |
c741e0c0 | 8 | static char *sccsid = "@(#)parse.c 5.3 (Berkeley) %G%"; |
094e80ed | 9 | #endif |
0d061c44 BJ |
10 | |
11 | #include "sh.h" | |
12 | ||
13 | /* | |
14 | * C shell | |
15 | */ | |
16 | ||
17 | /* | |
18 | * Perform aliasing on the word list lex | |
19 | * Do a (very rudimentary) parse to separate into commands. | |
20 | * If word 0 of a command has an alias, do it. | |
21 | * Repeat a maximum of 20 times. | |
22 | */ | |
23 | alias(lex) | |
24 | register struct wordent *lex; | |
25 | { | |
26 | int aleft = 21; | |
27 | jmp_buf osetexit; | |
28 | ||
29 | getexit(osetexit); | |
30 | setexit(); | |
31 | if (haderr) { | |
32 | resexit(osetexit); | |
33 | reset(); | |
34 | } | |
35 | if (--aleft == 0) | |
36 | error("Alias loop"); | |
37 | asyntax(lex->next, lex); | |
38 | resexit(osetexit); | |
39 | } | |
40 | ||
41 | asyntax(p1, p2) | |
42 | register struct wordent *p1, *p2; | |
43 | { | |
44 | ||
45 | while (p1 != p2) | |
46 | if (any(p1->word[0], ";&\n")) | |
47 | p1 = p1->next; | |
48 | else { | |
49 | asyn0(p1, p2); | |
50 | return; | |
51 | } | |
52 | } | |
53 | ||
54 | asyn0(p1, p2) | |
55 | struct wordent *p1; | |
56 | register struct wordent *p2; | |
57 | { | |
58 | register struct wordent *p; | |
59 | register int l = 0; | |
60 | ||
61 | for (p = p1; p != p2; p = p->next) | |
62 | switch (p->word[0]) { | |
63 | ||
64 | case '(': | |
65 | l++; | |
66 | continue; | |
67 | ||
68 | case ')': | |
69 | l--; | |
70 | if (l < 0) | |
71 | error("Too many )'s"); | |
72 | continue; | |
73 | ||
74 | case '>': | |
75 | if (p->next != p2 && eq(p->next->word, "&")) | |
76 | p = p->next; | |
77 | continue; | |
78 | ||
79 | case '&': | |
80 | case '|': | |
81 | case ';': | |
82 | case '\n': | |
83 | if (l != 0) | |
84 | continue; | |
85 | asyn3(p1, p); | |
86 | asyntax(p->next, p2); | |
87 | return; | |
88 | } | |
89 | if (l == 0) | |
90 | asyn3(p1, p2); | |
91 | } | |
92 | ||
93 | asyn3(p1, p2) | |
94 | struct wordent *p1; | |
95 | register struct wordent *p2; | |
96 | { | |
97 | register struct varent *ap; | |
98 | struct wordent alout; | |
99 | register bool redid; | |
100 | ||
101 | if (p1 == p2) | |
102 | return; | |
103 | if (p1->word[0] == '(') { | |
104 | for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev) | |
105 | if (p2 == p1) | |
106 | return; | |
107 | if (p2 == p1->next) | |
108 | return; | |
109 | asyn0(p1->next, p2); | |
110 | return; | |
111 | } | |
112 | ap = adrof1(p1->word, &aliases); | |
113 | if (ap == 0) | |
114 | return; | |
115 | alhistp = p1->prev; | |
116 | alhistt = p2; | |
117 | alvec = ap->vec; | |
118 | redid = lex(&alout); | |
119 | alhistp = alhistt = 0; | |
120 | alvec = 0; | |
121 | if (err) { | |
122 | freelex(&alout); | |
123 | error(err); | |
124 | } | |
125 | if (p1->word[0] && eq(p1->word, alout.next->word)) { | |
126 | char *cp = alout.next->word; | |
127 | ||
128 | alout.next->word = strspl("\200", cp); | |
35371dec | 129 | XFREE(cp) |
0d061c44 BJ |
130 | } |
131 | p1 = freenod(p1, redid ? p2 : p1->next); | |
132 | if (alout.next != &alout) { | |
133 | p1->next->prev = alout.prev->prev; | |
134 | alout.prev->prev->next = p1->next; | |
135 | alout.next->prev = p1; | |
136 | p1->next = alout.next; | |
35371dec EW |
137 | XFREE(alout.prev->word) |
138 | XFREE((char *)alout.prev) | |
0d061c44 BJ |
139 | } |
140 | reset(); /* throw! */ | |
141 | } | |
142 | ||
143 | struct wordent * | |
144 | freenod(p1, p2) | |
145 | register struct wordent *p1, *p2; | |
146 | { | |
147 | register struct wordent *retp = p1->prev; | |
148 | ||
149 | while (p1 != p2) { | |
35371dec | 150 | XFREE(p1->word) |
0d061c44 | 151 | p1 = p1->next; |
35371dec | 152 | XFREE((char *)p1->prev) |
0d061c44 BJ |
153 | } |
154 | retp->next = p2; | |
155 | p2->prev = retp; | |
156 | return (retp); | |
157 | } | |
158 | ||
159 | #define PHERE 1 | |
160 | #define PIN 2 | |
161 | #define POUT 4 | |
162 | #define PDIAG 8 | |
163 | ||
164 | /* | |
165 | * syntax | |
166 | * empty | |
167 | * syn0 | |
168 | */ | |
169 | struct command * | |
170 | syntax(p1, p2, flags) | |
171 | register struct wordent *p1, *p2; | |
172 | int flags; | |
173 | { | |
174 | ||
175 | while (p1 != p2) | |
176 | if (any(p1->word[0], ";&\n")) | |
177 | p1 = p1->next; | |
178 | else | |
179 | return (syn0(p1, p2, flags)); | |
180 | return (0); | |
181 | } | |
182 | ||
183 | /* | |
184 | * syn0 | |
185 | * syn1 | |
186 | * syn1 & syntax | |
187 | */ | |
188 | struct command * | |
189 | syn0(p1, p2, flags) | |
190 | struct wordent *p1, *p2; | |
191 | int flags; | |
192 | { | |
193 | register struct wordent *p; | |
194 | register struct command *t, *t1; | |
195 | int l; | |
196 | ||
197 | l = 0; | |
198 | for (p = p1; p != p2; p = p->next) | |
199 | switch (p->word[0]) { | |
200 | ||
201 | case '(': | |
202 | l++; | |
203 | continue; | |
204 | ||
205 | case ')': | |
206 | l--; | |
207 | if (l < 0) | |
208 | seterr("Too many )'s"); | |
209 | continue; | |
210 | ||
211 | case '|': | |
212 | if (p->word[1] == '|') | |
213 | continue; | |
214 | /* fall into ... */ | |
215 | ||
216 | case '>': | |
217 | if (p->next != p2 && eq(p->next->word, "&")) | |
218 | p = p->next; | |
219 | continue; | |
220 | ||
221 | case '&': | |
222 | if (l != 0) | |
223 | break; | |
224 | if (p->word[1] == '&') | |
225 | continue; | |
226 | t1 = syn1(p1, p, flags); | |
c741e0c0 JL |
227 | if (t1->t_dtyp == TLST || |
228 | t1->t_dtyp == TAND || | |
229 | t1->t_dtyp == TOR) { | |
0d061c44 BJ |
230 | t = (struct command *) calloc(1, sizeof (*t)); |
231 | t->t_dtyp = TPAR; | |
232 | t->t_dflg = FAND|FINT; | |
233 | t->t_dspr = t1; | |
234 | t1 = t; | |
235 | } else | |
236 | t1->t_dflg |= FAND|FINT; | |
237 | t = (struct command *) calloc(1, sizeof (*t)); | |
238 | t->t_dtyp = TLST; | |
239 | t->t_dflg = 0; | |
240 | t->t_dcar = t1; | |
241 | t->t_dcdr = syntax(p, p2, flags); | |
242 | return(t); | |
243 | } | |
244 | if (l == 0) | |
245 | return (syn1(p1, p2, flags)); | |
246 | seterr("Too many ('s"); | |
247 | return (0); | |
248 | } | |
249 | ||
250 | /* | |
251 | * syn1 | |
252 | * syn1a | |
253 | * syn1a ; syntax | |
254 | */ | |
255 | struct command * | |
256 | syn1(p1, p2, flags) | |
257 | struct wordent *p1, *p2; | |
258 | int flags; | |
259 | { | |
260 | register struct wordent *p; | |
261 | register struct command *t; | |
262 | int l; | |
263 | ||
264 | l = 0; | |
265 | for (p = p1; p != p2; p = p->next) | |
266 | switch (p->word[0]) { | |
267 | ||
268 | case '(': | |
269 | l++; | |
270 | continue; | |
271 | ||
272 | case ')': | |
273 | l--; | |
274 | continue; | |
275 | ||
276 | case ';': | |
277 | case '\n': | |
278 | if (l != 0) | |
279 | break; | |
280 | t = (struct command *) calloc(1, sizeof (*t)); | |
281 | t->t_dtyp = TLST; | |
282 | t->t_dcar = syn1a(p1, p, flags); | |
283 | t->t_dcdr = syntax(p->next, p2, flags); | |
284 | if (t->t_dcdr == 0) | |
285 | t->t_dcdr = t->t_dcar, t->t_dcar = 0; | |
286 | return (t); | |
287 | } | |
288 | return (syn1a(p1, p2, flags)); | |
289 | } | |
290 | ||
291 | /* | |
292 | * syn1a | |
293 | * syn1b | |
294 | * syn1b || syn1a | |
295 | */ | |
296 | struct command * | |
297 | syn1a(p1, p2, flags) | |
298 | struct wordent *p1, *p2; | |
299 | int flags; | |
300 | { | |
301 | register struct wordent *p; | |
302 | register struct command *t; | |
303 | register int l = 0; | |
304 | ||
305 | for (p = p1; p != p2; p = p->next) | |
306 | switch (p->word[0]) { | |
307 | ||
308 | case '(': | |
309 | l++; | |
310 | continue; | |
311 | ||
312 | case ')': | |
313 | l--; | |
314 | continue; | |
315 | ||
316 | case '|': | |
317 | if (p->word[1] != '|') | |
318 | continue; | |
319 | if (l == 0) { | |
320 | t = (struct command *) calloc(1, sizeof (*t)); | |
321 | t->t_dtyp = TOR; | |
322 | t->t_dcar = syn1b(p1, p, flags); | |
323 | t->t_dcdr = syn1a(p->next, p2, flags); | |
324 | t->t_dflg = 0; | |
325 | return (t); | |
326 | } | |
327 | continue; | |
328 | } | |
329 | return (syn1b(p1, p2, flags)); | |
330 | } | |
331 | ||
332 | /* | |
333 | * syn1b | |
334 | * syn2 | |
335 | * syn2 && syn1b | |
336 | */ | |
337 | struct command * | |
338 | syn1b(p1, p2, flags) | |
339 | struct wordent *p1, *p2; | |
340 | int flags; | |
341 | { | |
342 | register struct wordent *p; | |
343 | register struct command *t; | |
344 | register int l = 0; | |
345 | ||
346 | l = 0; | |
347 | for (p = p1; p != p2; p = p->next) | |
348 | switch (p->word[0]) { | |
349 | ||
350 | case '(': | |
351 | l++; | |
352 | continue; | |
353 | ||
354 | case ')': | |
355 | l--; | |
356 | continue; | |
357 | ||
358 | case '&': | |
359 | if (p->word[1] == '&' && l == 0) { | |
360 | t = (struct command *) calloc(1, sizeof (*t)); | |
361 | t->t_dtyp = TAND; | |
362 | t->t_dcar = syn2(p1, p, flags); | |
363 | t->t_dcdr = syn1b(p->next, p2, flags); | |
364 | t->t_dflg = 0; | |
365 | return (t); | |
366 | } | |
367 | continue; | |
368 | } | |
369 | return (syn2(p1, p2, flags)); | |
370 | } | |
371 | ||
372 | /* | |
373 | * syn2 | |
374 | * syn3 | |
375 | * syn3 | syn2 | |
376 | * syn3 |& syn2 | |
377 | */ | |
378 | struct command * | |
379 | syn2(p1, p2, flags) | |
380 | struct wordent *p1, *p2; | |
381 | int flags; | |
382 | { | |
383 | register struct wordent *p, *pn; | |
384 | register struct command *t; | |
385 | register int l = 0; | |
386 | int f; | |
387 | ||
388 | for (p = p1; p != p2; p = p->next) | |
389 | switch (p->word[0]) { | |
390 | ||
391 | case '(': | |
392 | l++; | |
393 | continue; | |
394 | ||
395 | case ')': | |
396 | l--; | |
397 | continue; | |
398 | ||
399 | case '|': | |
400 | if (l != 0) | |
401 | continue; | |
402 | t = (struct command *) calloc(1, sizeof (*t)); | |
403 | f = flags | POUT; | |
404 | pn = p->next; | |
405 | if (pn != p2 && pn->word[0] == '&') { | |
406 | f |= PDIAG; | |
407 | t->t_dflg |= FDIAG; | |
408 | } | |
409 | t->t_dtyp = TFIL; | |
410 | t->t_dcar = syn3(p1, p, f); | |
411 | if (pn != p2 && pn->word[0] == '&') | |
412 | p = pn; | |
413 | t->t_dcdr = syn2(p->next, p2, flags | PIN); | |
414 | return (t); | |
415 | } | |
416 | return (syn3(p1, p2, flags)); | |
417 | } | |
418 | ||
419 | char *RELPAR = "<>()"; | |
420 | ||
421 | /* | |
422 | * syn3 | |
423 | * ( syn0 ) [ < in ] [ > out ] | |
424 | * word word* [ < in ] [ > out ] | |
425 | * KEYWORD ( word* ) word* [ < in ] [ > out ] | |
426 | * | |
427 | * KEYWORD = (@ exit foreach if set switch test while) | |
428 | */ | |
429 | struct command * | |
430 | syn3(p1, p2, flags) | |
431 | struct wordent *p1, *p2; | |
432 | int flags; | |
433 | { | |
434 | register struct wordent *p; | |
435 | struct wordent *lp, *rp; | |
436 | register struct command *t; | |
437 | register int l; | |
438 | char **av; | |
439 | int n, c; | |
440 | bool specp = 0; | |
441 | ||
442 | if (p1 != p2) { | |
443 | p = p1; | |
444 | again: | |
445 | switch (srchx(p->word)) { | |
446 | ||
447 | case ZELSE: | |
448 | p = p->next; | |
449 | if (p != p2) | |
450 | goto again; | |
451 | break; | |
452 | ||
453 | case ZEXIT: | |
454 | case ZFOREACH: | |
455 | case ZIF: | |
456 | case ZLET: | |
457 | case ZSET: | |
458 | case ZSWITCH: | |
459 | case ZWHILE: | |
460 | specp = 1; | |
461 | break; | |
462 | } | |
463 | } | |
464 | n = 0; | |
465 | l = 0; | |
466 | for (p = p1; p != p2; p = p->next) | |
467 | switch (p->word[0]) { | |
468 | ||
469 | case '(': | |
470 | if (specp) | |
471 | n++; | |
472 | l++; | |
473 | continue; | |
474 | ||
475 | case ')': | |
476 | if (specp) | |
477 | n++; | |
478 | l--; | |
479 | continue; | |
480 | ||
481 | case '>': | |
482 | case '<': | |
483 | if (l != 0) { | |
484 | if (specp) | |
485 | n++; | |
486 | continue; | |
487 | } | |
488 | if (p->next == p2) | |
489 | continue; | |
490 | if (any(p->next->word[0], RELPAR)) | |
491 | continue; | |
492 | n--; | |
493 | continue; | |
494 | ||
495 | default: | |
496 | if (!specp && l != 0) | |
497 | continue; | |
498 | n++; | |
499 | continue; | |
500 | } | |
501 | if (n < 0) | |
502 | n = 0; | |
503 | t = (struct command *) calloc(1, sizeof (*t)); | |
35371dec | 504 | av = (char **) calloc((unsigned) (n + 1), sizeof (char **)); |
0d061c44 BJ |
505 | t->t_dcom = av; |
506 | n = 0; | |
507 | if (p2->word[0] == ')') | |
508 | t->t_dflg = FPAR; | |
509 | lp = 0; | |
510 | rp = 0; | |
511 | l = 0; | |
512 | for (p = p1; p != p2; p = p->next) { | |
513 | c = p->word[0]; | |
514 | switch (c) { | |
515 | ||
516 | case '(': | |
517 | if (l == 0) { | |
518 | if (lp != 0 && !specp) | |
519 | seterr("Badly placed ("); | |
520 | lp = p->next; | |
521 | } | |
522 | l++; | |
523 | goto savep; | |
524 | ||
525 | case ')': | |
526 | l--; | |
527 | if (l == 0) | |
528 | rp = p; | |
529 | goto savep; | |
530 | ||
531 | case '>': | |
532 | if (l != 0) | |
533 | goto savep; | |
534 | if (p->word[1] == '>') | |
535 | t->t_dflg |= FCAT; | |
536 | if (p->next != p2 && eq(p->next->word, "&")) { | |
537 | t->t_dflg |= FDIAG, p = p->next; | |
538 | if (flags & (POUT|PDIAG)) | |
539 | goto badout; | |
540 | } | |
541 | if (p->next != p2 && eq(p->next->word, "!")) | |
542 | t->t_dflg |= FANY, p = p->next; | |
543 | if (p->next == p2) { | |
544 | missfile: | |
545 | seterr("Missing name for redirect"); | |
546 | continue; | |
547 | } | |
548 | p = p->next; | |
549 | if (any(p->word[0], RELPAR)) | |
550 | goto missfile; | |
551 | if ((flags & POUT) && (flags & PDIAG) == 0 || t->t_drit) | |
552 | badout: | |
553 | seterr("Ambiguous output redirect"); | |
554 | else | |
555 | t->t_drit = savestr(p->word); | |
556 | continue; | |
557 | ||
558 | case '<': | |
559 | if (l != 0) | |
560 | goto savep; | |
561 | if (p->word[1] == '<') | |
562 | t->t_dflg |= FHERE; | |
563 | if (p->next == p2) | |
564 | goto missfile; | |
565 | p = p->next; | |
566 | if (any(p->word[0], RELPAR)) | |
567 | goto missfile; | |
568 | if ((flags & PHERE) && (t->t_dflg & FHERE)) | |
569 | seterr("Can't << within ()'s"); | |
570 | else if ((flags & PIN) || t->t_dlef) | |
571 | seterr("Ambiguous input redirect"); | |
572 | else | |
573 | t->t_dlef = savestr(p->word); | |
574 | continue; | |
575 | ||
576 | savep: | |
577 | if (!specp) | |
578 | continue; | |
579 | default: | |
580 | if (l != 0 && !specp) | |
581 | continue; | |
582 | if (err == 0) | |
583 | av[n] = savestr(p->word); | |
584 | n++; | |
585 | continue; | |
586 | } | |
587 | } | |
588 | if (lp != 0 && !specp) { | |
589 | if (n != 0) | |
590 | seterr("Badly placed ()'s"); | |
591 | t->t_dtyp = TPAR; | |
592 | t->t_dspr = syn0(lp, rp, PHERE); | |
593 | } else { | |
594 | if (n == 0) | |
595 | seterr("Invalid null command"); | |
596 | t->t_dtyp = TCOM; | |
597 | } | |
598 | return (t); | |
599 | } | |
600 | ||
601 | freesyn(t) | |
602 | register struct command *t; | |
603 | { | |
604 | register char **v; | |
605 | ||
606 | if (t == 0) | |
607 | return; | |
608 | switch (t->t_dtyp) { | |
609 | ||
610 | case TCOM: | |
611 | for (v = t->t_dcom; *v; v++) | |
35371dec EW |
612 | XFREE(*v) |
613 | XFREE((char *)t->t_dcom) | |
0d061c44 BJ |
614 | goto lr; |
615 | ||
616 | case TPAR: | |
617 | freesyn(t->t_dspr); | |
618 | /* fall into ... */ | |
619 | ||
620 | lr: | |
35371dec EW |
621 | XFREE(t->t_dlef) |
622 | XFREE(t->t_drit) | |
0d061c44 BJ |
623 | break; |
624 | ||
625 | case TAND: | |
626 | case TOR: | |
627 | case TFIL: | |
628 | case TLST: | |
629 | freesyn(t->t_dcar), freesyn(t->t_dcdr); | |
630 | break; | |
631 | } | |
35371dec | 632 | XFREE((char *)t) |
0d061c44 | 633 | } |