xref: /dragonfly/contrib/tcsh-6/sh.parse.c (revision b97fef05)
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.
7  *
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.
19  *
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.
31  */
32 #include "sh.h"
33 
34 /*
35  * C shell
36  */
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);
47 
48 #define ALEFT	51		/* max of 50 alias expansions	 */
49 #define HLEFT	11		/* max of 10 history expansions */
50 /*
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.
55  */
56 extern int hleft;
57 void
58 alias(struct wordent *lexp)
59 {
60     int aleft;
61 
62     aleft = ALEFT;
63     hleft = HLEFT;
64     do {
65 	if (--aleft == 0)
66 	    stderror(ERR_ALIASLOOP);
67     } while (asyntax(lexp->next, lexp) != 0);
68 }
69 
70 static int
71 asyntax(struct wordent *p1, struct wordent *p2)
72 {
73     while (p1 != p2) {
74 	if (!any(";&\n", p1->word[0]))
75 	    return asyn0(p1, p2);
76 	p1 = p1->next;
77     }
78     return 0;
79 }
80 
81 static int
82 asyn0(struct wordent *p1, struct wordent *p2)
83 {
84     struct wordent *p;
85     int l = 0;
86 
87     for (p = p1; p != p2; p = p->next)
88 	switch (p->word[0]) {
89 
90 	case '(':
91 	    l++;
92 	    continue;
93 
94 	case ')':
95 	    l--;
96 	    if (l < 0)
97 		stderror(ERR_TOOMANYRP);
98 	    continue;
99 
100 	case '>':
101 	    if (p->next != p2 && eq(p->next->word, STRand))
102 		p = p->next;
103 	    continue;
104 
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);
114 
115 	default:
116 	    break;
117 	}
118     if (l == 0)
119 	return asyn3(p1, p2);
120     return 0;
121 }
122 
123 static void
124 alvec_cleanup(void *dummy)
125 {
126     USE(dummy);
127     alhistp = NULL;
128     alhistt = NULL;
129     alvec = NULL;
130 }
131 
132 static int
133 asyn3(struct wordent *p1, struct wordent *p2)
134 {
135     struct varent *ap;
136     struct wordent alout;
137     int redid;
138 
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);
148     }
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);
161     }
162     if (p1->word[0] && eq(p1->word, alout.next->word)) {
163 	Char   *cp = alout.next->word;
164 
165 	alout.next->word = Strspl(STRQNULL, cp);
166 	xfree(cp);
167     }
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);
176     }
177     return 1;
178 }
179 
180 static struct wordent *
181 freenod(struct wordent *p1, struct wordent *p2)
182 {
183     struct wordent *retp = p1->prev;
184 
185     while (p1 != p2) {
186 	xfree(p1->word);
187 	p1 = p1->next;
188 	xfree(p1->prev);
189     }
190     retp->next = p2;
191     p2->prev = retp;
192     return (retp);
193 }
194 
195 #define	P_HERE	1
196 #define	P_IN	2
197 #define	P_OUT	4
198 #define	P_DIAG	8
199 
200 /*
201  * syntax
202  *	empty
203  *	syn0
204  */
205 struct command *
206 syntax(const struct wordent *p1, const struct wordent *p2, int flags)
207 {
208 
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);
215 }
216 
217 /*
218  * syn0
219  *	syn1
220  *	syn1 & syntax
221  */
222 static struct command *
223 syn0(const struct wordent *p1, const struct wordent *p2, int flags)
224 {
225     const struct wordent *p;
226     struct command *t, *t1;
227     int     l;
228 
229     l = 0;
230     for (p = p1; p != p2; p = p->next)
231 	switch (p->word[0]) {
232 
233 	case '(':
234 	    l++;
235 	    continue;
236 
237 	case ')':
238 	    l--;
239 	    if (l < 0)
240 		seterror(ERR_TOOMANYRP);
241 	    continue;
242 
243 	case '|':
244 	    if (p->word[1] == '|')
245 		continue;
246 	    /*FALLTHROUGH*/
247 
248 	case '>':
249 	    if (p->next != p2 && eq(p->next->word, STRand))
250 		p = p->next;
251 	    continue;
252 
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;
267 	    }
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;
278 	}
279     if (l == 0)
280 	return (syn1(p1, p2, flags));
281     seterror(ERR_TOOMANYLP);
282     return (0);
283 }
284 
285 /*
286  * syn1
287  *	syn1a
288  *	syn1a ; syntax
289  */
290 static struct command *
291 syn1(const struct wordent *p1, const struct wordent *p2, int flags)
292 {
293     const struct wordent *p;
294     struct command *t;
295     int     l;
296 
297     l = 0;
298     for (p = p1; p != p2; p = p->next)
299 	switch (p->word[0]) {
300 
301 	case '(':
302 	    l++;
303 	    continue;
304 
305 	case ')':
306 	    l--;
307 	    continue;
308 
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);
320 
321 	default:
322 	    break;
323 	}
324     return (syn1a(p1, p2, flags));
325 }
326 
327 /*
328  * syn1a
329  *	syn1b
330  *	syn1b || syn1a
331  */
332 static struct command *
333 syn1a(const struct wordent *p1, const struct wordent *p2, int flags)
334 {
335     const struct wordent *p;
336     struct command *t;
337     int l = 0;
338 
339     for (p = p1; p != p2; p = p->next)
340 	switch (p->word[0]) {
341 
342 	case '(':
343 	    l++;
344 	    continue;
345 
346 	case ')':
347 	    l--;
348 	    continue;
349 
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);
360 	    }
361 	    continue;
362 
363 	default:
364 	    break;
365 	}
366     return (syn1b(p1, p2, flags));
367 }
368 
369 /*
370  * syn1b
371  *	syn2
372  *	syn2 && syn1b
373  */
374 static struct command *
375 syn1b(const struct wordent *p1, const struct wordent *p2, int flags)
376 {
377     const struct wordent *p;
378     struct command *t;
379     int l = 0;
380 
381     for (p = p1; p != p2; p = p->next)
382 	switch (p->word[0]) {
383 
384 	case '(':
385 	    l++;
386 	    continue;
387 
388 	case ')':
389 	    l--;
390 	    continue;
391 
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);
400 	    }
401 	    continue;
402 
403 	default:
404 	    break;
405 	}
406     return (syn2(p1, p2, flags));
407 }
408 
409 /*
410  * syn2
411  *	syn3
412  *	syn3 | syn2
413  *	syn3 |& syn2
414  */
415 static struct command *
416 syn2(const struct wordent *p1, const struct wordent *p2, int flags)
417 {
418     const struct wordent *p, *pn;
419     struct command *t;
420     int l = 0;
421     int     f;
422 
423     for (p = p1; p != p2; p = p->next)
424 	switch (p->word[0]) {
425 
426 	case '(':
427 	    l++;
428 	    continue;
429 
430 	case ')':
431 	    l--;
432 	    continue;
433 
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;
443 	    }
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);
450 
451 	default:
452 	    break;
453 	}
454     return (syn3(p1, p2, flags));
455 }
456 
457 static const char RELPAR[] = {'<', '>', '(', ')', '\0'};
458 
459 /*
460  * syn3
461  *	( syn0 ) [ < in  ] [ > out ]
462  *	word word* [ < in ] [ > out ]
463  *	KEYWORD ( word* ) word* [ < in ] [ > out ]
464  *
465  *	KEYWORD = (@ exit foreach if set switch test while)
466  */
467 static struct command *
468 syn3(const struct wordent *p1, const struct wordent *p2, int flags)
469 {
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;
477 
478     if (p1 != p2) {
479 	p = p1;
480 again:
481 	switch (srchx(p->word)) {
482 
483 	case TC_ELSE:
484 	    p = p->next;
485 	    if (p != p2)
486 		goto again;
487 	    break;
488 
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;
500 	}
501     }
502     n = 0;
503     l = 0;
504     for (p = p1; p != p2; p = p->next)
505 	switch (p->word[0]) {
506 
507 	case '(':
508 	    if (specp)
509 		n++;
510 	    l++;
511 	    continue;
512 
513 	case ')':
514 	    if (specp)
515 		n++;
516 	    l--;
517 	    continue;
518 
519 	case '>':
520 	case '<':
521 	    if (l != 0) {
522 		if (specp)
523 		    n++;
524 		continue;
525 	    }
526 	    if (p->next == p2)
527 		continue;
528 	    if (any(RELPAR, p->next->word[0]))
529 		continue;
530 	    n--;
531 	    continue;
532 
533 	default:
534 	    if (!specp && l != 0)
535 		continue;
536 	    n++;
537 	    continue;
538 	}
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) {
553 
554 	case '(':
555 	    if (l == 0) {
556 		if (lp != 0 && !specp)
557 		    seterror(ERR_BADPLP);
558 		lp = p->next;
559 	    }
560 	    l++;
561 	    goto savep;
562 
563 	case ')':
564 	    l--;
565 	    if (l == 0)
566 		rp = p;
567 	    goto savep;
568 
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;
579 		}
580 	    }
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;
586 	    }
587 	    p = p->next;
588 	    if (any(RELPAR, p->word[0])) {
589 		seterror(ERR_MISRED);
590 		continue;
591 	    }
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;
597 
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;
606 	    }
607 	    p = p->next;
608 	    if (any(RELPAR, p->word[0])) {
609 		seterror(ERR_MISRED);
610 		continue;
611 	    }
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;
619 
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;
631 	}
632     }
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);
638     }
639     else {
640 	if (n == 0)
641 	    seterror(ERR_NULLCOM);
642 	t->t_dtyp = NODE_COMMAND;
643     }
644     return (t);
645 }
646 
647 void
648 freesyn(struct command *t)
649 {
650     Char **v;
651 
652     if (t == 0)
653 	return;
654     switch (t->t_dtyp) {
655 
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;
668 
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;
677     }
678 #ifdef DEBUG
679     memset(t, 0, sizeof(*t));
680 #endif
681     xfree(t);
682 }
683 
684 void
685 syntax_cleanup(void *xt)
686 {
687     struct command *t;
688 
689     t = xt;
690     freesyn(t);
691 }
692