usr.sbin/makefs: Add -o c|C option to specify comp|check type
[dragonfly.git] / contrib / tcsh-6 / sh.parse.c
blob211a1012b9a8cfc519bb623018464b75127a3e96
1 /*
2 * sh.parse.c: Interpret a list of tokens
3 */
4 /*-
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 #include "sh.h"
35 * C shell
37 static int asyntax (struct wordent *, struct wordent *);
38 static int asyn0 (struct wordent *, struct wordent *);
39 static int asyn3 (struct wordent *, struct wordent *);
40 static struct wordent *freenod (struct wordent *, struct wordent *);
41 static struct command *syn0 (const struct wordent *, const struct wordent *, int);
42 static struct command *syn1 (const struct wordent *, const struct wordent *, int);
43 static struct command *syn1a (const struct wordent *, const struct wordent *, int);
44 static struct command *syn1b (const struct wordent *, const struct wordent *, int);
45 static struct command *syn2 (const struct wordent *, const struct wordent *, int);
46 static struct command *syn3 (const struct wordent *, const struct wordent *, int);
48 #define ALEFT 51 /* max of 50 alias expansions */
49 #define HLEFT 11 /* max of 10 history expansions */
51 * Perform aliasing on the word list lexp
52 * Do a (very rudimentary) parse to separate into commands.
53 * If word 0 of a command has an alias, do it.
54 * Repeat a maximum of 50 times.
56 extern int hleft;
57 void
58 alias(struct wordent *lexp)
60 int aleft;
62 aleft = ALEFT;
63 hleft = HLEFT;
64 do {
65 if (--aleft == 0)
66 stderror(ERR_ALIASLOOP);
67 } while (asyntax(lexp->next, lexp) != 0);
70 static int
71 asyntax(struct wordent *p1, struct wordent *p2)
73 while (p1 != p2) {
74 if (!any(";&\n", p1->word[0]))
75 return asyn0(p1, p2);
76 p1 = p1->next;
78 return 0;
81 static int
82 asyn0(struct wordent *p1, struct wordent *p2)
84 struct wordent *p;
85 int l = 0;
87 for (p = p1; p != p2; p = p->next)
88 switch (p->word[0]) {
90 case '(':
91 l++;
92 continue;
94 case ')':
95 l--;
96 if (l < 0)
97 stderror(ERR_TOOMANYRP);
98 continue;
100 case '>':
101 if (p->next != p2 && eq(p->next->word, STRand))
102 p = p->next;
103 continue;
105 case '&':
106 case '|':
107 case ';':
108 case '\n':
109 if (l != 0)
110 continue;
111 if (asyn3(p1, p) != 0)
112 return 1;
113 return asyntax(p->next, p2);
115 default:
116 break;
118 if (l == 0)
119 return asyn3(p1, p2);
120 return 0;
123 static void
124 alvec_cleanup(void *dummy)
126 USE(dummy);
127 alhistp = NULL;
128 alhistt = NULL;
129 alvec = NULL;
132 static int
133 asyn3(struct wordent *p1, struct wordent *p2)
135 struct varent *ap;
136 struct wordent alout;
137 int redid;
139 if (p1 == p2)
140 return 0;
141 if (p1->word[0] == '(') {
142 for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
143 if (p2 == p1)
144 return 0;
145 if (p2 == p1->next)
146 return 0;
147 return asyn0(p1->next, p2);
149 ap = adrof1(p1->word, &aliases);
150 if (ap == 0)
151 return 0;
152 alhistp = p1->prev;
153 alhistt = p2;
154 alvec = ap->vec;
155 cleanup_push(&alvec, alvec_cleanup);
156 redid = lex(&alout);
157 cleanup_until(&alvec);
158 if (seterr) {
159 freelex(&alout);
160 stderror(ERR_OLD);
162 if (p1->word[0] && eq(p1->word, alout.next->word)) {
163 Char *cp = alout.next->word;
165 alout.next->word = Strspl(STRQNULL, cp);
166 xfree(cp);
168 p1 = freenod(p1, redid ? p2 : p1->next);
169 if (alout.next != &alout) {
170 p1->next->prev = alout.prev->prev;
171 alout.prev->prev->next = p1->next;
172 alout.next->prev = p1;
173 p1->next = alout.next;
174 xfree(alout.prev->word);
175 xfree(alout.prev);
177 return 1;
180 static struct wordent *
181 freenod(struct wordent *p1, struct wordent *p2)
183 struct wordent *retp = p1->prev;
185 while (p1 != p2) {
186 xfree(p1->word);
187 p1 = p1->next;
188 xfree(p1->prev);
190 retp->next = p2;
191 p2->prev = retp;
192 return (retp);
195 #define P_HERE 1
196 #define P_IN 2
197 #define P_OUT 4
198 #define P_DIAG 8
201 * syntax
202 * empty
203 * syn0
205 struct command *
206 syntax(const struct wordent *p1, const struct wordent *p2, int flags)
209 while (p1 != p2)
210 if (any(";&\n", p1->word[0]))
211 p1 = p1->next;
212 else
213 return (syn0(p1, p2, flags));
214 return (0);
218 * syn0
219 * syn1
220 * syn1 & syntax
222 static struct command *
223 syn0(const struct wordent *p1, const struct wordent *p2, int flags)
225 const struct wordent *p;
226 struct command *t, *t1;
227 int l;
229 l = 0;
230 for (p = p1; p != p2; p = p->next)
231 switch (p->word[0]) {
233 case '(':
234 l++;
235 continue;
237 case ')':
238 l--;
239 if (l < 0)
240 seterror(ERR_TOOMANYRP);
241 continue;
243 case '|':
244 if (p->word[1] == '|')
245 continue;
246 /*FALLTHROUGH*/
248 case '>':
249 if (p->next != p2 && eq(p->next->word, STRand))
250 p = p->next;
251 continue;
253 case '&':
254 if (l != 0)
255 break;
256 if (p->word[1] == '&')
257 continue;
258 t1 = syn1(p1, p, flags);
259 if (t1->t_dtyp == NODE_LIST ||
260 t1->t_dtyp == NODE_AND ||
261 t1->t_dtyp == NODE_OR) {
262 t = xcalloc(1, sizeof(*t));
263 t->t_dtyp = NODE_PAREN;
264 t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
265 t->t_dspr = t1;
266 t1 = t;
268 else
269 t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
270 t = xcalloc(1, sizeof(*t));
271 t->t_dtyp = NODE_LIST;
272 t->t_dflg = 0;
273 t->t_dcar = t1;
274 t->t_dcdr = syntax(p, p2, flags);
275 return (t);
276 default:
277 break;
279 if (l == 0)
280 return (syn1(p1, p2, flags));
281 seterror(ERR_TOOMANYLP);
282 return (0);
286 * syn1
287 * syn1a
288 * syn1a ; syntax
290 static struct command *
291 syn1(const struct wordent *p1, const struct wordent *p2, int flags)
293 const struct wordent *p;
294 struct command *t;
295 int l;
297 l = 0;
298 for (p = p1; p != p2; p = p->next)
299 switch (p->word[0]) {
301 case '(':
302 l++;
303 continue;
305 case ')':
306 l--;
307 continue;
309 case ';':
310 case '\n':
311 if (l != 0)
312 break;
313 t = xcalloc(1, sizeof(*t));
314 t->t_dtyp = NODE_LIST;
315 t->t_dcar = syn1a(p1, p, flags);
316 t->t_dcdr = syntax(p->next, p2, flags);
317 if (t->t_dcdr == 0)
318 t->t_dcdr = t->t_dcar, t->t_dcar = 0;
319 return (t);
321 default:
322 break;
324 return (syn1a(p1, p2, flags));
328 * syn1a
329 * syn1b
330 * syn1b || syn1a
332 static struct command *
333 syn1a(const struct wordent *p1, const struct wordent *p2, int flags)
335 const struct wordent *p;
336 struct command *t;
337 int l = 0;
339 for (p = p1; p != p2; p = p->next)
340 switch (p->word[0]) {
342 case '(':
343 l++;
344 continue;
346 case ')':
347 l--;
348 continue;
350 case '|':
351 if (p->word[1] != '|')
352 continue;
353 if (l == 0) {
354 t = xcalloc(1, sizeof(*t));
355 t->t_dtyp = NODE_OR;
356 t->t_dcar = syn1b(p1, p, flags);
357 t->t_dcdr = syn1a(p->next, p2, flags);
358 t->t_dflg = 0;
359 return (t);
361 continue;
363 default:
364 break;
366 return (syn1b(p1, p2, flags));
370 * syn1b
371 * syn2
372 * syn2 && syn1b
374 static struct command *
375 syn1b(const struct wordent *p1, const struct wordent *p2, int flags)
377 const struct wordent *p;
378 struct command *t;
379 int l = 0;
381 for (p = p1; p != p2; p = p->next)
382 switch (p->word[0]) {
384 case '(':
385 l++;
386 continue;
388 case ')':
389 l--;
390 continue;
392 case '&':
393 if (p->word[1] == '&' && l == 0) {
394 t = xcalloc(1, sizeof(*t));
395 t->t_dtyp = NODE_AND;
396 t->t_dcar = syn2(p1, p, flags);
397 t->t_dcdr = syn1b(p->next, p2, flags);
398 t->t_dflg = 0;
399 return (t);
401 continue;
403 default:
404 break;
406 return (syn2(p1, p2, flags));
410 * syn2
411 * syn3
412 * syn3 | syn2
413 * syn3 |& syn2
415 static struct command *
416 syn2(const struct wordent *p1, const struct wordent *p2, int flags)
418 const struct wordent *p, *pn;
419 struct command *t;
420 int l = 0;
421 int f;
423 for (p = p1; p != p2; p = p->next)
424 switch (p->word[0]) {
426 case '(':
427 l++;
428 continue;
430 case ')':
431 l--;
432 continue;
434 case '|':
435 if (l != 0)
436 continue;
437 t = xcalloc(1, sizeof(*t));
438 f = flags | P_OUT;
439 pn = p->next;
440 if (pn != p2 && pn->word[0] == '&') {
441 f |= P_DIAG;
442 t->t_dflg |= F_STDERR;
444 t->t_dtyp = NODE_PIPE;
445 t->t_dcar = syn3(p1, p, f);
446 if (pn != p2 && pn->word[0] == '&')
447 p = pn;
448 t->t_dcdr = syn2(p->next, p2, flags | P_IN);
449 return (t);
451 default:
452 break;
454 return (syn3(p1, p2, flags));
457 static const char RELPAR[] = {'<', '>', '(', ')', '\0'};
460 * syn3
461 * ( syn0 ) [ < in ] [ > out ]
462 * word word* [ < in ] [ > out ]
463 * KEYWORD ( word* ) word* [ < in ] [ > out ]
465 * KEYWORD = (@ exit foreach if set switch test while)
467 static struct command *
468 syn3(const struct wordent *p1, const struct wordent *p2, int flags)
470 const struct wordent *p;
471 const struct wordent *lp, *rp;
472 struct command *t;
473 int l;
474 Char **av;
475 int n, c;
476 int specp = 0;
478 if (p1 != p2) {
479 p = p1;
480 again:
481 switch (srchx(p->word)) {
483 case TC_ELSE:
484 p = p->next;
485 if (p != p2)
486 goto again;
487 break;
489 case TC_EXIT:
490 case TC_FOREACH:
491 case TC_IF:
492 case TC_LET:
493 case TC_SET:
494 case TC_SWITCH:
495 case TC_WHILE:
496 specp = 1;
497 break;
498 default:
499 break;
502 n = 0;
503 l = 0;
504 for (p = p1; p != p2; p = p->next)
505 switch (p->word[0]) {
507 case '(':
508 if (specp)
509 n++;
510 l++;
511 continue;
513 case ')':
514 if (specp)
515 n++;
516 l--;
517 continue;
519 case '>':
520 case '<':
521 if (l != 0) {
522 if (specp)
523 n++;
524 continue;
526 if (p->next == p2)
527 continue;
528 if (any(RELPAR, p->next->word[0]))
529 continue;
530 n--;
531 continue;
533 default:
534 if (!specp && l != 0)
535 continue;
536 n++;
537 continue;
539 if (n < 0)
540 n = 0;
541 t = xcalloc(1, sizeof(*t));
542 av = xcalloc(n + 1, sizeof(Char **));
543 t->t_dcom = av;
544 n = 0;
545 if (p2->word[0] == ')')
546 t->t_dflg = F_NOFORK;
547 lp = 0;
548 rp = 0;
549 l = 0;
550 for (p = p1; p != p2; p = p->next) {
551 c = p->word[0];
552 switch (c) {
554 case '(':
555 if (l == 0) {
556 if (lp != 0 && !specp)
557 seterror(ERR_BADPLP);
558 lp = p->next;
560 l++;
561 goto savep;
563 case ')':
564 l--;
565 if (l == 0)
566 rp = p;
567 goto savep;
569 case '>':
570 if (l != 0)
571 goto savep;
572 if (p->word[1] == '>')
573 t->t_dflg |= F_APPEND;
574 if (p->next != p2 && eq(p->next->word, STRand)) {
575 t->t_dflg |= F_STDERR, p = p->next;
576 if (flags & (P_OUT | P_DIAG)) {
577 seterror(ERR_OUTRED);
578 continue;
581 if (p->next != p2 && eq(p->next->word, STRbang))
582 t->t_dflg |= F_OVERWRITE, p = p->next;
583 if (p->next == p2) {
584 seterror(ERR_MISRED);
585 continue;
587 p = p->next;
588 if (any(RELPAR, p->word[0])) {
589 seterror(ERR_MISRED);
590 continue;
592 if (((flags & P_OUT) && (flags & P_DIAG) == 0) || t->t_drit)
593 seterror(ERR_OUTRED);
594 else
595 t->t_drit = Strsave(p->word);
596 continue;
598 case '<':
599 if (l != 0)
600 goto savep;
601 if (p->word[1] == '<')
602 t->t_dflg |= F_READ;
603 if (p->next == p2) {
604 seterror(ERR_MISRED);
605 continue;
607 p = p->next;
608 if (any(RELPAR, p->word[0])) {
609 seterror(ERR_MISRED);
610 continue;
612 if ((flags & P_HERE) && (t->t_dflg & F_READ))
613 seterror(ERR_REDPAR);
614 else if ((flags & P_IN) || t->t_dlef)
615 seterror(ERR_INRED);
616 else
617 t->t_dlef = Strsave(p->word);
618 continue;
620 savep:
621 if (!specp)
622 continue;
623 /* FALLTHROUGH */
624 default:
625 if (l != 0 && !specp)
626 continue;
627 if (seterr == 0)
628 av[n] = Strsave(p->word);
629 n++;
630 continue;
633 if (lp != 0 && !specp) {
634 if (n != 0)
635 seterror(ERR_BADPLPS);
636 t->t_dtyp = NODE_PAREN;
637 t->t_dspr = syn0(lp, rp, P_HERE);
639 else {
640 if (n == 0)
641 seterror(ERR_NULLCOM);
642 t->t_dtyp = NODE_COMMAND;
644 return (t);
647 void
648 freesyn(struct command *t)
650 Char **v;
652 if (t == 0)
653 return;
654 switch (t->t_dtyp) {
656 case NODE_COMMAND:
657 for (v = t->t_dcom; *v; v++)
658 xfree(*v);
659 xfree(t->t_dcom);
660 xfree(t->t_dlef);
661 xfree(t->t_drit);
662 break;
663 case NODE_PAREN:
664 freesyn(t->t_dspr);
665 xfree(t->t_dlef);
666 xfree(t->t_drit);
667 break;
669 case NODE_AND:
670 case NODE_OR:
671 case NODE_PIPE:
672 case NODE_LIST:
673 freesyn(t->t_dcar), freesyn(t->t_dcdr);
674 break;
675 default:
676 break;
678 #ifdef DEBUG
679 memset(t, 0, sizeof(*t));
680 #endif
681 xfree(t);
684 void
685 syntax_cleanup(void *xt)
687 struct command *t;
689 t = xt;
690 freesyn(t);