tcsh: fix warning to keep compiling with WARNS=2
[dragonfly.git] / contrib / tcsh-6 / sh.parse.c
blob2ef20c457199ca03f92c36a5b40a7423cb7c6120
1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.parse.c,v 3.18 2006/03/02 18:46:44 christos Exp $ */
2 /*
3 * sh.parse.c: Interpret a list of tokens
4 */
5 /*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 #include "sh.h"
35 RCSID("$tcsh: sh.parse.c,v 3.18 2006/03/02 18:46:44 christos Exp $")
38 * C shell
40 static int asyntax (struct wordent *, struct wordent *);
41 static int asyn0 (struct wordent *, struct wordent *);
42 static int asyn3 (struct wordent *, struct wordent *);
43 static struct wordent *freenod (struct wordent *, struct wordent *);
44 static struct command *syn0 (const struct wordent *, const struct wordent *, int);
45 static struct command *syn1 (const struct wordent *, const struct wordent *, int);
46 static struct command *syn1a (const struct wordent *, const struct wordent *, int);
47 static struct command *syn1b (const struct wordent *, const struct wordent *, int);
48 static struct command *syn2 (const struct wordent *, const struct wordent *, int);
49 static struct command *syn3 (const struct wordent *, const struct wordent *, int);
51 #define ALEFT 51 /* max of 50 alias expansions */
52 #define HLEFT 11 /* max of 10 history expansions */
54 * Perform aliasing on the word list lexp
55 * Do a (very rudimentary) parse to separate into commands.
56 * If word 0 of a command has an alias, do it.
57 * Repeat a maximum of 50 times.
59 extern int hleft;
60 void
61 alias(struct wordent *lexp)
63 int aleft;
65 aleft = ALEFT;
66 hleft = HLEFT;
67 do {
68 if (--aleft == 0)
69 stderror(ERR_ALIASLOOP);
70 } while (asyntax(lexp->next, lexp) != 0);
73 static int
74 asyntax(struct wordent *p1, struct wordent *p2)
76 while (p1 != p2) {
77 if (!any(";&\n", p1->word[0]))
78 return asyn0(p1, p2);
79 p1 = p1->next;
81 return 0;
84 static int
85 asyn0(struct wordent *p1, struct wordent *p2)
87 struct wordent *p;
88 int l = 0;
90 for (p = p1; p != p2; p = p->next)
91 switch (p->word[0]) {
93 case '(':
94 l++;
95 continue;
97 case ')':
98 l--;
99 if (l < 0)
100 stderror(ERR_TOOMANYRP);
101 continue;
103 case '>':
104 if (p->next != p2 && eq(p->next->word, STRand))
105 p = p->next;
106 continue;
108 case '&':
109 case '|':
110 case ';':
111 case '\n':
112 if (l != 0)
113 continue;
114 if (asyn3(p1, p) != 0)
115 return 1;
116 return asyntax(p->next, p2);
118 default:
119 break;
121 if (l == 0)
122 return asyn3(p1, p2);
123 return 0;
126 static void
127 alvec_cleanup(void *dummy)
129 USE(dummy);
130 alhistp = NULL;
131 alhistt = NULL;
132 alvec = NULL;
135 static int
136 asyn3(struct wordent *p1, struct wordent *p2)
138 struct varent *ap;
139 struct wordent alout;
140 int redid;
142 if (p1 == p2)
143 return 0;
144 if (p1->word[0] == '(') {
145 for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
146 if (p2 == p1)
147 return 0;
148 if (p2 == p1->next)
149 return 0;
150 return asyn0(p1->next, p2);
152 ap = adrof1(p1->word, &aliases);
153 if (ap == 0)
154 return 0;
155 alhistp = p1->prev;
156 alhistt = p2;
157 alvec = ap->vec;
158 cleanup_push(&alvec, alvec_cleanup);
159 redid = lex(&alout);
160 cleanup_until(&alvec);
161 if (seterr) {
162 freelex(&alout);
163 stderror(ERR_OLD);
165 if (p1->word[0] && eq(p1->word, alout.next->word)) {
166 Char *cp = alout.next->word;
168 alout.next->word = Strspl(STRQNULL, cp);
169 xfree(cp);
171 p1 = freenod(p1, redid ? p2 : p1->next);
172 if (alout.next != &alout) {
173 p1->next->prev = alout.prev->prev;
174 alout.prev->prev->next = p1->next;
175 alout.next->prev = p1;
176 p1->next = alout.next;
177 xfree(alout.prev->word);
178 xfree(alout.prev);
180 return 1;
183 static struct wordent *
184 freenod(struct wordent *p1, struct wordent *p2)
186 struct wordent *retp = p1->prev;
188 while (p1 != p2) {
189 xfree(p1->word);
190 p1 = p1->next;
191 xfree(p1->prev);
193 retp->next = p2;
194 p2->prev = retp;
195 return (retp);
198 #define P_HERE 1
199 #define P_IN 2
200 #define P_OUT 4
201 #define P_DIAG 8
204 * syntax
205 * empty
206 * syn0
208 struct command *
209 syntax(const struct wordent *p1, const struct wordent *p2, int flags)
212 while (p1 != p2)
213 if (any(";&\n", p1->word[0]))
214 p1 = p1->next;
215 else
216 return (syn0(p1, p2, flags));
217 return (0);
221 * syn0
222 * syn1
223 * syn1 & syntax
225 static struct command *
226 syn0(const struct wordent *p1, const struct wordent *p2, int flags)
228 const struct wordent *p;
229 struct command *t, *t1;
230 int l;
232 l = 0;
233 for (p = p1; p != p2; p = p->next)
234 switch (p->word[0]) {
236 case '(':
237 l++;
238 continue;
240 case ')':
241 l--;
242 if (l < 0)
243 seterror(ERR_TOOMANYRP);
244 continue;
246 case '|':
247 if (p->word[1] == '|')
248 continue;
249 /*FALLTHROUGH*/
251 case '>':
252 if (p->next != p2 && eq(p->next->word, STRand))
253 p = p->next;
254 continue;
256 case '&':
257 if (l != 0)
258 break;
259 if (p->word[1] == '&')
260 continue;
261 t1 = syn1(p1, p, flags);
262 if (t1->t_dtyp == NODE_LIST ||
263 t1->t_dtyp == NODE_AND ||
264 t1->t_dtyp == NODE_OR) {
265 t = xcalloc(1, sizeof(*t));
266 t->t_dtyp = NODE_PAREN;
267 t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
268 t->t_dspr = t1;
269 t1 = t;
271 else
272 t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
273 t = xcalloc(1, sizeof(*t));
274 t->t_dtyp = NODE_LIST;
275 t->t_dflg = 0;
276 t->t_dcar = t1;
277 t->t_dcdr = syntax(p, p2, flags);
278 return (t);
279 default:
280 break;
282 if (l == 0)
283 return (syn1(p1, p2, flags));
284 seterror(ERR_TOOMANYLP);
285 return (0);
289 * syn1
290 * syn1a
291 * syn1a ; syntax
293 static struct command *
294 syn1(const struct wordent *p1, const struct wordent *p2, int flags)
296 const struct wordent *p;
297 struct command *t;
298 int l;
300 l = 0;
301 for (p = p1; p != p2; p = p->next)
302 switch (p->word[0]) {
304 case '(':
305 l++;
306 continue;
308 case ')':
309 l--;
310 continue;
312 case ';':
313 case '\n':
314 if (l != 0)
315 break;
316 t = xcalloc(1, sizeof(*t));
317 t->t_dtyp = NODE_LIST;
318 t->t_dcar = syn1a(p1, p, flags);
319 t->t_dcdr = syntax(p->next, p2, flags);
320 if (t->t_dcdr == 0)
321 t->t_dcdr = t->t_dcar, t->t_dcar = 0;
322 return (t);
324 default:
325 break;
327 return (syn1a(p1, p2, flags));
331 * syn1a
332 * syn1b
333 * syn1b || syn1a
335 static struct command *
336 syn1a(const struct wordent *p1, const struct wordent *p2, int flags)
338 const struct wordent *p;
339 struct command *t;
340 int l = 0;
342 for (p = p1; p != p2; p = p->next)
343 switch (p->word[0]) {
345 case '(':
346 l++;
347 continue;
349 case ')':
350 l--;
351 continue;
353 case '|':
354 if (p->word[1] != '|')
355 continue;
356 if (l == 0) {
357 t = xcalloc(1, sizeof(*t));
358 t->t_dtyp = NODE_OR;
359 t->t_dcar = syn1b(p1, p, flags);
360 t->t_dcdr = syn1a(p->next, p2, flags);
361 t->t_dflg = 0;
362 return (t);
364 continue;
366 default:
367 break;
369 return (syn1b(p1, p2, flags));
373 * syn1b
374 * syn2
375 * syn2 && syn1b
377 static struct command *
378 syn1b(const struct wordent *p1, const struct wordent *p2, int flags)
380 const struct wordent *p;
381 struct command *t;
382 int l = 0;
384 for (p = p1; p != p2; p = p->next)
385 switch (p->word[0]) {
387 case '(':
388 l++;
389 continue;
391 case ')':
392 l--;
393 continue;
395 case '&':
396 if (p->word[1] == '&' && l == 0) {
397 t = xcalloc(1, sizeof(*t));
398 t->t_dtyp = NODE_AND;
399 t->t_dcar = syn2(p1, p, flags);
400 t->t_dcdr = syn1b(p->next, p2, flags);
401 t->t_dflg = 0;
402 return (t);
404 continue;
406 default:
407 break;
409 return (syn2(p1, p2, flags));
413 * syn2
414 * syn3
415 * syn3 | syn2
416 * syn3 |& syn2
418 static struct command *
419 syn2(const struct wordent *p1, const struct wordent *p2, int flags)
421 const struct wordent *p, *pn;
422 struct command *t;
423 int l = 0;
424 int f;
426 for (p = p1; p != p2; p = p->next)
427 switch (p->word[0]) {
429 case '(':
430 l++;
431 continue;
433 case ')':
434 l--;
435 continue;
437 case '|':
438 if (l != 0)
439 continue;
440 t = xcalloc(1, sizeof(*t));
441 f = flags | P_OUT;
442 pn = p->next;
443 if (pn != p2 && pn->word[0] == '&') {
444 f |= P_DIAG;
445 t->t_dflg |= F_STDERR;
447 t->t_dtyp = NODE_PIPE;
448 t->t_dcar = syn3(p1, p, f);
449 if (pn != p2 && pn->word[0] == '&')
450 p = pn;
451 t->t_dcdr = syn2(p->next, p2, flags | P_IN);
452 return (t);
454 default:
455 break;
457 return (syn3(p1, p2, flags));
460 static const char RELPAR[] = {'<', '>', '(', ')', '\0'};
463 * syn3
464 * ( syn0 ) [ < in ] [ > out ]
465 * word word* [ < in ] [ > out ]
466 * KEYWORD ( word* ) word* [ < in ] [ > out ]
468 * KEYWORD = (@ exit foreach if set switch test while)
470 static struct command *
471 syn3(const struct wordent *p1, const struct wordent *p2, int flags)
473 const struct wordent *p;
474 const struct wordent *lp, *rp;
475 struct command *t;
476 int l;
477 Char **av;
478 int n, c;
479 int specp = 0;
481 if (p1 != p2) {
482 p = p1;
483 again:
484 switch (srchx(p->word)) {
486 case TC_ELSE:
487 p = p->next;
488 if (p != p2)
489 goto again;
490 break;
492 case TC_EXIT:
493 case TC_FOREACH:
494 case TC_IF:
495 case TC_LET:
496 case TC_SET:
497 case TC_SWITCH:
498 case TC_WHILE:
499 specp = 1;
500 break;
501 default:
502 break;
505 n = 0;
506 l = 0;
507 for (p = p1; p != p2; p = p->next)
508 switch (p->word[0]) {
510 case '(':
511 if (specp)
512 n++;
513 l++;
514 continue;
516 case ')':
517 if (specp)
518 n++;
519 l--;
520 continue;
522 case '>':
523 case '<':
524 if (l != 0) {
525 if (specp)
526 n++;
527 continue;
529 if (p->next == p2)
530 continue;
531 if (any(RELPAR, p->next->word[0]))
532 continue;
533 n--;
534 continue;
536 default:
537 if (!specp && l != 0)
538 continue;
539 n++;
540 continue;
542 if (n < 0)
543 n = 0;
544 t = xcalloc(1, sizeof(*t));
545 av = xcalloc(n + 1, sizeof(Char **));
546 t->t_dcom = av;
547 n = 0;
548 if (p2->word[0] == ')')
549 t->t_dflg = F_NOFORK;
550 lp = 0;
551 rp = 0;
552 l = 0;
553 for (p = p1; p != p2; p = p->next) {
554 c = p->word[0];
555 switch (c) {
557 case '(':
558 if (l == 0) {
559 if (lp != 0 && !specp)
560 seterror(ERR_BADPLP);
561 lp = p->next;
563 l++;
564 goto savep;
566 case ')':
567 l--;
568 if (l == 0)
569 rp = p;
570 goto savep;
572 case '>':
573 if (l != 0)
574 goto savep;
575 if (p->word[1] == '>')
576 t->t_dflg |= F_APPEND;
577 if (p->next != p2 && eq(p->next->word, STRand)) {
578 t->t_dflg |= F_STDERR, p = p->next;
579 if (flags & (P_OUT | P_DIAG)) {
580 seterror(ERR_OUTRED);
581 continue;
584 if (p->next != p2 && eq(p->next->word, STRbang))
585 t->t_dflg |= F_OVERWRITE, p = p->next;
586 if (p->next == p2) {
587 seterror(ERR_MISRED);
588 continue;
590 p = p->next;
591 if (any(RELPAR, p->word[0])) {
592 seterror(ERR_MISRED);
593 continue;
595 if (((flags & P_OUT) && (flags & P_DIAG) == 0) || t->t_drit)
596 seterror(ERR_OUTRED);
597 else
598 t->t_drit = Strsave(p->word);
599 continue;
601 case '<':
602 if (l != 0)
603 goto savep;
604 if (p->word[1] == '<')
605 t->t_dflg |= F_READ;
606 if (p->next == p2) {
607 seterror(ERR_MISRED);
608 continue;
610 p = p->next;
611 if (any(RELPAR, p->word[0])) {
612 seterror(ERR_MISRED);
613 continue;
615 if ((flags & P_HERE) && (t->t_dflg & F_READ))
616 seterror(ERR_REDPAR);
617 else if ((flags & P_IN) || t->t_dlef)
618 seterror(ERR_INRED);
619 else
620 t->t_dlef = Strsave(p->word);
621 continue;
623 savep:
624 if (!specp)
625 continue;
626 default:
627 if (l != 0 && !specp)
628 continue;
629 if (seterr == 0)
630 av[n] = Strsave(p->word);
631 n++;
632 continue;
635 if (lp != 0 && !specp) {
636 if (n != 0)
637 seterror(ERR_BADPLPS);
638 t->t_dtyp = NODE_PAREN;
639 t->t_dspr = syn0(lp, rp, P_HERE);
641 else {
642 if (n == 0)
643 seterror(ERR_NULLCOM);
644 t->t_dtyp = NODE_COMMAND;
646 return (t);
649 void
650 freesyn(struct command *t)
652 Char **v;
654 if (t == 0)
655 return;
656 switch (t->t_dtyp) {
658 case NODE_COMMAND:
659 for (v = t->t_dcom; *v; v++)
660 xfree(*v);
661 xfree(t->t_dcom);
662 xfree(t->t_dlef);
663 xfree(t->t_drit);
664 break;
665 case NODE_PAREN:
666 freesyn(t->t_dspr);
667 xfree(t->t_dlef);
668 xfree(t->t_drit);
669 break;
671 case NODE_AND:
672 case NODE_OR:
673 case NODE_PIPE:
674 case NODE_LIST:
675 freesyn(t->t_dcar), freesyn(t->t_dcdr);
676 break;
677 default:
678 break;
680 xfree(t);
683 void
684 syntax_cleanup(void *xt)
686 struct command *t;
688 t = xt;
689 freesyn(t);