xref: /freebsd/contrib/tcsh/sh.parse.c (revision b032f27c365b992e9d8e42214183b39acfb8c6ac)
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.
8  *
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.
20  *
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.
32  */
33 #include "sh.h"
34 
35 RCSID("$tcsh: sh.parse.c,v 3.18 2006/03/02 18:46:44 christos Exp $")
36 
37 /*
38  * C shell
39  */
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);
50 
51 #define ALEFT	51		/* max of 50 alias expansions	 */
52 #define HLEFT	11		/* max of 10 history expansions */
53 /*
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.
58  */
59 extern int hleft;
60 void
61 alias(struct wordent *lexp)
62 {
63     int aleft;
64 
65     aleft = ALEFT;
66     hleft = HLEFT;
67     do {
68 	if (--aleft == 0)
69 	    stderror(ERR_ALIASLOOP);
70     } while (asyntax(lexp->next, lexp) != 0);
71 }
72 
73 static int
74 asyntax(struct wordent *p1, struct wordent *p2)
75 {
76     while (p1 != p2) {
77 	if (!any(";&\n", p1->word[0]))
78 	    return asyn0(p1, p2);
79 	p1 = p1->next;
80     }
81     return 0;
82 }
83 
84 static int
85 asyn0(struct wordent *p1, struct wordent *p2)
86 {
87     struct wordent *p;
88     int l = 0;
89 
90     for (p = p1; p != p2; p = p->next)
91 	switch (p->word[0]) {
92 
93 	case '(':
94 	    l++;
95 	    continue;
96 
97 	case ')':
98 	    l--;
99 	    if (l < 0)
100 		stderror(ERR_TOOMANYRP);
101 	    continue;
102 
103 	case '>':
104 	    if (p->next != p2 && eq(p->next->word, STRand))
105 		p = p->next;
106 	    continue;
107 
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);
117 
118 	default:
119 	    break;
120 	}
121     if (l == 0)
122 	return asyn3(p1, p2);
123     return 0;
124 }
125 
126 static void
127 alvec_cleanup(void *dummy)
128 {
129     USE(dummy);
130     alhistp = NULL;
131     alhistt = NULL;
132     alvec = NULL;
133 }
134 
135 static int
136 asyn3(struct wordent *p1, struct wordent *p2)
137 {
138     struct varent *ap;
139     struct wordent alout;
140     int redid;
141 
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);
151     }
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);
164     }
165     if (p1->word[0] && eq(p1->word, alout.next->word)) {
166 	Char   *cp = alout.next->word;
167 
168 	alout.next->word = Strspl(STRQNULL, cp);
169 	xfree(cp);
170     }
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);
179     }
180     return 1;
181 }
182 
183 static struct wordent *
184 freenod(struct wordent *p1, struct wordent *p2)
185 {
186     struct wordent *retp = p1->prev;
187 
188     while (p1 != p2) {
189 	xfree(p1->word);
190 	p1 = p1->next;
191 	xfree(p1->prev);
192     }
193     retp->next = p2;
194     p2->prev = retp;
195     return (retp);
196 }
197 
198 #define	P_HERE	1
199 #define	P_IN	2
200 #define	P_OUT	4
201 #define	P_DIAG	8
202 
203 /*
204  * syntax
205  *	empty
206  *	syn0
207  */
208 struct command *
209 syntax(const struct wordent *p1, const struct wordent *p2, int flags)
210 {
211 
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);
218 }
219 
220 /*
221  * syn0
222  *	syn1
223  *	syn1 & syntax
224  */
225 static struct command *
226 syn0(const struct wordent *p1, const struct wordent *p2, int flags)
227 {
228     const struct wordent *p;
229     struct command *t, *t1;
230     int     l;
231 
232     l = 0;
233     for (p = p1; p != p2; p = p->next)
234 	switch (p->word[0]) {
235 
236 	case '(':
237 	    l++;
238 	    continue;
239 
240 	case ')':
241 	    l--;
242 	    if (l < 0)
243 		seterror(ERR_TOOMANYRP);
244 	    continue;
245 
246 	case '|':
247 	    if (p->word[1] == '|')
248 		continue;
249 	    /*FALLTHROUGH*/
250 
251 	case '>':
252 	    if (p->next != p2 && eq(p->next->word, STRand))
253 		p = p->next;
254 	    continue;
255 
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;
270 	    }
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;
281 	}
282     if (l == 0)
283 	return (syn1(p1, p2, flags));
284     seterror(ERR_TOOMANYLP);
285     return (0);
286 }
287 
288 /*
289  * syn1
290  *	syn1a
291  *	syn1a ; syntax
292  */
293 static struct command *
294 syn1(const struct wordent *p1, const struct wordent *p2, int flags)
295 {
296     const struct wordent *p;
297     struct command *t;
298     int     l;
299 
300     l = 0;
301     for (p = p1; p != p2; p = p->next)
302 	switch (p->word[0]) {
303 
304 	case '(':
305 	    l++;
306 	    continue;
307 
308 	case ')':
309 	    l--;
310 	    continue;
311 
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);
323 
324 	default:
325 	    break;
326 	}
327     return (syn1a(p1, p2, flags));
328 }
329 
330 /*
331  * syn1a
332  *	syn1b
333  *	syn1b || syn1a
334  */
335 static struct command *
336 syn1a(const struct wordent *p1, const struct wordent *p2, int flags)
337 {
338     const struct wordent *p;
339     struct command *t;
340     int l = 0;
341 
342     for (p = p1; p != p2; p = p->next)
343 	switch (p->word[0]) {
344 
345 	case '(':
346 	    l++;
347 	    continue;
348 
349 	case ')':
350 	    l--;
351 	    continue;
352 
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);
363 	    }
364 	    continue;
365 
366 	default:
367 	    break;
368 	}
369     return (syn1b(p1, p2, flags));
370 }
371 
372 /*
373  * syn1b
374  *	syn2
375  *	syn2 && syn1b
376  */
377 static struct command *
378 syn1b(const struct wordent *p1, const struct wordent *p2, int flags)
379 {
380     const struct wordent *p;
381     struct command *t;
382     int l = 0;
383 
384     for (p = p1; p != p2; p = p->next)
385 	switch (p->word[0]) {
386 
387 	case '(':
388 	    l++;
389 	    continue;
390 
391 	case ')':
392 	    l--;
393 	    continue;
394 
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);
403 	    }
404 	    continue;
405 
406 	default:
407 	    break;
408 	}
409     return (syn2(p1, p2, flags));
410 }
411 
412 /*
413  * syn2
414  *	syn3
415  *	syn3 | syn2
416  *	syn3 |& syn2
417  */
418 static struct command *
419 syn2(const struct wordent *p1, const struct wordent *p2, int flags)
420 {
421     const struct wordent *p, *pn;
422     struct command *t;
423     int l = 0;
424     int     f;
425 
426     for (p = p1; p != p2; p = p->next)
427 	switch (p->word[0]) {
428 
429 	case '(':
430 	    l++;
431 	    continue;
432 
433 	case ')':
434 	    l--;
435 	    continue;
436 
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;
446 	    }
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);
453 
454 	default:
455 	    break;
456 	}
457     return (syn3(p1, p2, flags));
458 }
459 
460 static const char RELPAR[] = {'<', '>', '(', ')', '\0'};
461 
462 /*
463  * syn3
464  *	( syn0 ) [ < in  ] [ > out ]
465  *	word word* [ < in ] [ > out ]
466  *	KEYWORD ( word* ) word* [ < in ] [ > out ]
467  *
468  *	KEYWORD = (@ exit foreach if set switch test while)
469  */
470 static struct command *
471 syn3(const struct wordent *p1, const struct wordent *p2, int flags)
472 {
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;
480 
481     if (p1 != p2) {
482 	p = p1;
483 again:
484 	switch (srchx(p->word)) {
485 
486 	case TC_ELSE:
487 	    p = p->next;
488 	    if (p != p2)
489 		goto again;
490 	    break;
491 
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;
503 	}
504     }
505     n = 0;
506     l = 0;
507     for (p = p1; p != p2; p = p->next)
508 	switch (p->word[0]) {
509 
510 	case '(':
511 	    if (specp)
512 		n++;
513 	    l++;
514 	    continue;
515 
516 	case ')':
517 	    if (specp)
518 		n++;
519 	    l--;
520 	    continue;
521 
522 	case '>':
523 	case '<':
524 	    if (l != 0) {
525 		if (specp)
526 		    n++;
527 		continue;
528 	    }
529 	    if (p->next == p2)
530 		continue;
531 	    if (any(RELPAR, p->next->word[0]))
532 		continue;
533 	    n--;
534 	    continue;
535 
536 	default:
537 	    if (!specp && l != 0)
538 		continue;
539 	    n++;
540 	    continue;
541 	}
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) {
556 
557 	case '(':
558 	    if (l == 0) {
559 		if (lp != 0 && !specp)
560 		    seterror(ERR_BADPLP);
561 		lp = p->next;
562 	    }
563 	    l++;
564 	    goto savep;
565 
566 	case ')':
567 	    l--;
568 	    if (l == 0)
569 		rp = p;
570 	    goto savep;
571 
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;
582 		}
583 	    }
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;
589 	    }
590 	    p = p->next;
591 	    if (any(RELPAR, p->word[0])) {
592 		seterror(ERR_MISRED);
593 		continue;
594 	    }
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;
600 
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;
609 	    }
610 	    p = p->next;
611 	    if (any(RELPAR, p->word[0])) {
612 		seterror(ERR_MISRED);
613 		continue;
614 	    }
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;
622 
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;
633 	}
634     }
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);
640     }
641     else {
642 	if (n == 0)
643 	    seterror(ERR_NULLCOM);
644 	t->t_dtyp = NODE_COMMAND;
645     }
646     return (t);
647 }
648 
649 void
650 freesyn(struct command *t)
651 {
652     Char **v;
653 
654     if (t == 0)
655 	return;
656     switch (t->t_dtyp) {
657 
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;
670 
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;
679     }
680     xfree(t);
681 }
682 
683 void
684 syntax_cleanup(void *xt)
685 {
686     struct command *t;
687 
688     t = xt;
689     freesyn(t);
690 }
691