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 |
094e80ed EW |
8 | static char *sccsid = "@(#)parse.c 5.2 (Berkeley) %G%"; |
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); | |
227 | if (t1->t_dtyp == TLST) { | |
228 | t = (struct command *) calloc(1, sizeof (*t)); | |
229 | t->t_dtyp = TPAR; | |
230 | t->t_dflg = FAND|FINT; | |
231 | t->t_dspr = t1; | |
232 | t1 = t; | |
233 | } else | |
234 | t1->t_dflg |= FAND|FINT; | |
235 | t = (struct command *) calloc(1, sizeof (*t)); | |
236 | t->t_dtyp = TLST; | |
237 | t->t_dflg = 0; | |
238 | t->t_dcar = t1; | |
239 | t->t_dcdr = syntax(p, p2, flags); | |
240 | return(t); | |
241 | } | |
242 | if (l == 0) | |
243 | return (syn1(p1, p2, flags)); | |
244 | seterr("Too many ('s"); | |
245 | return (0); | |
246 | } | |
247 | ||
248 | /* | |
249 | * syn1 | |
250 | * syn1a | |
251 | * syn1a ; syntax | |
252 | */ | |
253 | struct command * | |
254 | syn1(p1, p2, flags) | |
255 | struct wordent *p1, *p2; | |
256 | int flags; | |
257 | { | |
258 | register struct wordent *p; | |
259 | register struct command *t; | |
260 | int l; | |
261 | ||
262 | l = 0; | |
263 | for (p = p1; p != p2; p = p->next) | |
264 | switch (p->word[0]) { | |
265 | ||
266 | case '(': | |
267 | l++; | |
268 | continue; | |
269 | ||
270 | case ')': | |
271 | l--; | |
272 | continue; | |
273 | ||
274 | case ';': | |
275 | case '\n': | |
276 | if (l != 0) | |
277 | break; | |
278 | t = (struct command *) calloc(1, sizeof (*t)); | |
279 | t->t_dtyp = TLST; | |
280 | t->t_dcar = syn1a(p1, p, flags); | |
281 | t->t_dcdr = syntax(p->next, p2, flags); | |
282 | if (t->t_dcdr == 0) | |
283 | t->t_dcdr = t->t_dcar, t->t_dcar = 0; | |
284 | return (t); | |
285 | } | |
286 | return (syn1a(p1, p2, flags)); | |
287 | } | |
288 | ||
289 | /* | |
290 | * syn1a | |
291 | * syn1b | |
292 | * syn1b || syn1a | |
293 | */ | |
294 | struct command * | |
295 | syn1a(p1, p2, flags) | |
296 | struct wordent *p1, *p2; | |
297 | int flags; | |
298 | { | |
299 | register struct wordent *p; | |
300 | register struct command *t; | |
301 | register int l = 0; | |
302 | ||
303 | for (p = p1; p != p2; p = p->next) | |
304 | switch (p->word[0]) { | |
305 | ||
306 | case '(': | |
307 | l++; | |
308 | continue; | |
309 | ||
310 | case ')': | |
311 | l--; | |
312 | continue; | |
313 | ||
314 | case '|': | |
315 | if (p->word[1] != '|') | |
316 | continue; | |
317 | if (l == 0) { | |
318 | t = (struct command *) calloc(1, sizeof (*t)); | |
319 | t->t_dtyp = TOR; | |
320 | t->t_dcar = syn1b(p1, p, flags); | |
321 | t->t_dcdr = syn1a(p->next, p2, flags); | |
322 | t->t_dflg = 0; | |
323 | return (t); | |
324 | } | |
325 | continue; | |
326 | } | |
327 | return (syn1b(p1, p2, flags)); | |
328 | } | |
329 | ||
330 | /* | |
331 | * syn1b | |
332 | * syn2 | |
333 | * syn2 && syn1b | |
334 | */ | |
335 | struct command * | |
336 | syn1b(p1, p2, flags) | |
337 | struct wordent *p1, *p2; | |
338 | int flags; | |
339 | { | |
340 | register struct wordent *p; | |
341 | register struct command *t; | |
342 | register int l = 0; | |
343 | ||
344 | l = 0; | |
345 | for (p = p1; p != p2; p = p->next) | |
346 | switch (p->word[0]) { | |
347 | ||
348 | case '(': | |
349 | l++; | |
350 | continue; | |
351 | ||
352 | case ')': | |
353 | l--; | |
354 | continue; | |
355 | ||
356 | case '&': | |
357 | if (p->word[1] == '&' && l == 0) { | |
358 | t = (struct command *) calloc(1, sizeof (*t)); | |
359 | t->t_dtyp = TAND; | |
360 | t->t_dcar = syn2(p1, p, flags); | |
361 | t->t_dcdr = syn1b(p->next, p2, flags); | |
362 | t->t_dflg = 0; | |
363 | return (t); | |
364 | } | |
365 | continue; | |
366 | } | |
367 | return (syn2(p1, p2, flags)); | |
368 | } | |
369 | ||
370 | /* | |
371 | * syn2 | |
372 | * syn3 | |
373 | * syn3 | syn2 | |
374 | * syn3 |& syn2 | |
375 | */ | |
376 | struct command * | |
377 | syn2(p1, p2, flags) | |
378 | struct wordent *p1, *p2; | |
379 | int flags; | |
380 | { | |
381 | register struct wordent *p, *pn; | |
382 | register struct command *t; | |
383 | register int l = 0; | |
384 | int f; | |
385 | ||
386 | for (p = p1; p != p2; p = p->next) | |
387 | switch (p->word[0]) { | |
388 | ||
389 | case '(': | |
390 | l++; | |
391 | continue; | |
392 | ||
393 | case ')': | |
394 | l--; | |
395 | continue; | |
396 | ||
397 | case '|': | |
398 | if (l != 0) | |
399 | continue; | |
400 | t = (struct command *) calloc(1, sizeof (*t)); | |
401 | f = flags | POUT; | |
402 | pn = p->next; | |
403 | if (pn != p2 && pn->word[0] == '&') { | |
404 | f |= PDIAG; | |
405 | t->t_dflg |= FDIAG; | |
406 | } | |
407 | t->t_dtyp = TFIL; | |
408 | t->t_dcar = syn3(p1, p, f); | |
409 | if (pn != p2 && pn->word[0] == '&') | |
410 | p = pn; | |
411 | t->t_dcdr = syn2(p->next, p2, flags | PIN); | |
412 | return (t); | |
413 | } | |
414 | return (syn3(p1, p2, flags)); | |
415 | } | |
416 | ||
417 | char *RELPAR = "<>()"; | |
418 | ||
419 | /* | |
420 | * syn3 | |
421 | * ( syn0 ) [ < in ] [ > out ] | |
422 | * word word* [ < in ] [ > out ] | |
423 | * KEYWORD ( word* ) word* [ < in ] [ > out ] | |
424 | * | |
425 | * KEYWORD = (@ exit foreach if set switch test while) | |
426 | */ | |
427 | struct command * | |
428 | syn3(p1, p2, flags) | |
429 | struct wordent *p1, *p2; | |
430 | int flags; | |
431 | { | |
432 | register struct wordent *p; | |
433 | struct wordent *lp, *rp; | |
434 | register struct command *t; | |
435 | register int l; | |
436 | char **av; | |
437 | int n, c; | |
438 | bool specp = 0; | |
439 | ||
440 | if (p1 != p2) { | |
441 | p = p1; | |
442 | again: | |
443 | switch (srchx(p->word)) { | |
444 | ||
445 | case ZELSE: | |
446 | p = p->next; | |
447 | if (p != p2) | |
448 | goto again; | |
449 | break; | |
450 | ||
451 | case ZEXIT: | |
452 | case ZFOREACH: | |
453 | case ZIF: | |
454 | case ZLET: | |
455 | case ZSET: | |
456 | case ZSWITCH: | |
457 | case ZWHILE: | |
458 | specp = 1; | |
459 | break; | |
460 | } | |
461 | } | |
462 | n = 0; | |
463 | l = 0; | |
464 | for (p = p1; p != p2; p = p->next) | |
465 | switch (p->word[0]) { | |
466 | ||
467 | case '(': | |
468 | if (specp) | |
469 | n++; | |
470 | l++; | |
471 | continue; | |
472 | ||
473 | case ')': | |
474 | if (specp) | |
475 | n++; | |
476 | l--; | |
477 | continue; | |
478 | ||
479 | case '>': | |
480 | case '<': | |
481 | if (l != 0) { | |
482 | if (specp) | |
483 | n++; | |
484 | continue; | |
485 | } | |
486 | if (p->next == p2) | |
487 | continue; | |
488 | if (any(p->next->word[0], RELPAR)) | |
489 | continue; | |
490 | n--; | |
491 | continue; | |
492 | ||
493 | default: | |
494 | if (!specp && l != 0) | |
495 | continue; | |
496 | n++; | |
497 | continue; | |
498 | } | |
499 | if (n < 0) | |
500 | n = 0; | |
501 | t = (struct command *) calloc(1, sizeof (*t)); | |
35371dec | 502 | av = (char **) calloc((unsigned) (n + 1), sizeof (char **)); |
0d061c44 BJ |
503 | t->t_dcom = av; |
504 | n = 0; | |
505 | if (p2->word[0] == ')') | |
506 | t->t_dflg = FPAR; | |
507 | lp = 0; | |
508 | rp = 0; | |
509 | l = 0; | |
510 | for (p = p1; p != p2; p = p->next) { | |
511 | c = p->word[0]; | |
512 | switch (c) { | |
513 | ||
514 | case '(': | |
515 | if (l == 0) { | |
516 | if (lp != 0 && !specp) | |
517 | seterr("Badly placed ("); | |
518 | lp = p->next; | |
519 | } | |
520 | l++; | |
521 | goto savep; | |
522 | ||
523 | case ')': | |
524 | l--; | |
525 | if (l == 0) | |
526 | rp = p; | |
527 | goto savep; | |
528 | ||
529 | case '>': | |
530 | if (l != 0) | |
531 | goto savep; | |
532 | if (p->word[1] == '>') | |
533 | t->t_dflg |= FCAT; | |
534 | if (p->next != p2 && eq(p->next->word, "&")) { | |
535 | t->t_dflg |= FDIAG, p = p->next; | |
536 | if (flags & (POUT|PDIAG)) | |
537 | goto badout; | |
538 | } | |
539 | if (p->next != p2 && eq(p->next->word, "!")) | |
540 | t->t_dflg |= FANY, p = p->next; | |
541 | if (p->next == p2) { | |
542 | missfile: | |
543 | seterr("Missing name for redirect"); | |
544 | continue; | |
545 | } | |
546 | p = p->next; | |
547 | if (any(p->word[0], RELPAR)) | |
548 | goto missfile; | |
549 | if ((flags & POUT) && (flags & PDIAG) == 0 || t->t_drit) | |
550 | badout: | |
551 | seterr("Ambiguous output redirect"); | |
552 | else | |
553 | t->t_drit = savestr(p->word); | |
554 | continue; | |
555 | ||
556 | case '<': | |
557 | if (l != 0) | |
558 | goto savep; | |
559 | if (p->word[1] == '<') | |
560 | t->t_dflg |= FHERE; | |
561 | if (p->next == p2) | |
562 | goto missfile; | |
563 | p = p->next; | |
564 | if (any(p->word[0], RELPAR)) | |
565 | goto missfile; | |
566 | if ((flags & PHERE) && (t->t_dflg & FHERE)) | |
567 | seterr("Can't << within ()'s"); | |
568 | else if ((flags & PIN) || t->t_dlef) | |
569 | seterr("Ambiguous input redirect"); | |
570 | else | |
571 | t->t_dlef = savestr(p->word); | |
572 | continue; | |
573 | ||
574 | savep: | |
575 | if (!specp) | |
576 | continue; | |
577 | default: | |
578 | if (l != 0 && !specp) | |
579 | continue; | |
580 | if (err == 0) | |
581 | av[n] = savestr(p->word); | |
582 | n++; | |
583 | continue; | |
584 | } | |
585 | } | |
586 | if (lp != 0 && !specp) { | |
587 | if (n != 0) | |
588 | seterr("Badly placed ()'s"); | |
589 | t->t_dtyp = TPAR; | |
590 | t->t_dspr = syn0(lp, rp, PHERE); | |
591 | } else { | |
592 | if (n == 0) | |
593 | seterr("Invalid null command"); | |
594 | t->t_dtyp = TCOM; | |
595 | } | |
596 | return (t); | |
597 | } | |
598 | ||
599 | freesyn(t) | |
600 | register struct command *t; | |
601 | { | |
602 | register char **v; | |
603 | ||
604 | if (t == 0) | |
605 | return; | |
606 | switch (t->t_dtyp) { | |
607 | ||
608 | case TCOM: | |
609 | for (v = t->t_dcom; *v; v++) | |
35371dec EW |
610 | XFREE(*v) |
611 | XFREE((char *)t->t_dcom) | |
0d061c44 BJ |
612 | goto lr; |
613 | ||
614 | case TPAR: | |
615 | freesyn(t->t_dspr); | |
616 | /* fall into ... */ | |
617 | ||
618 | lr: | |
35371dec EW |
619 | XFREE(t->t_dlef) |
620 | XFREE(t->t_drit) | |
0d061c44 BJ |
621 | break; |
622 | ||
623 | case TAND: | |
624 | case TOR: | |
625 | case TFIL: | |
626 | case TLST: | |
627 | freesyn(t->t_dcar), freesyn(t->t_dcdr); | |
628 | break; | |
629 | } | |
35371dec | 630 | XFREE((char *)t) |
0d061c44 | 631 | } |