xref: /netbsd-src/bin/csh/parse.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: parse.c,v 1.8 1997/07/04 21:24:07 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1980, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)parse.c	8.1 (Berkeley) 5/31/93";
40 #else
41 __RCSID("$NetBSD: parse.c,v 1.8 1997/07/04 21:24:07 christos Exp $");
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/types.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #if __STDC__
49 # include <stdarg.h>
50 #else
51 # include <varargs.h>
52 #endif
53 
54 #include "csh.h"
55 #include "extern.h"
56 
57 static void	 asyntax __P((struct wordent *, struct wordent *));
58 static void	 asyn0 __P((struct wordent *, struct wordent *));
59 static void	 asyn3 __P((struct wordent *, struct wordent *));
60 static struct wordent
61 		*freenod __P((struct wordent *, struct wordent *));
62 static struct command
63 		*syn0 __P((struct wordent *, struct wordent *, int));
64 static struct command
65 		*syn1 __P((struct wordent *, struct wordent *, int));
66 static struct command
67 		*syn1a __P((struct wordent *, struct wordent *, int));
68 static struct command
69 		*syn1b __P((struct wordent *, struct wordent *, int));
70 static struct command
71 		*syn2 __P((struct wordent *, struct wordent *, int));
72 static struct command
73 		*syn3 __P((struct wordent *, struct wordent *, int));
74 
75 #define ALEFT	21		/* max of 20 alias expansions	 */
76 #define HLEFT	11		/* max of 10 history expansions	 */
77 /*
78  * Perform aliasing on the word list lex
79  * Do a (very rudimentary) parse to separate into commands.
80  * If word 0 of a command has an alias, do it.
81  * Repeat a maximum of 20 times.
82  */
83 static int aleft;
84 extern int hleft;
85 void
86 alias(lex)
87     struct wordent *lex;
88 {
89     jmp_buf osetexit;
90 
91     aleft = ALEFT;
92     hleft = HLEFT;
93     getexit(osetexit);
94     (void) setexit();
95     if (haderr) {
96 	resexit(osetexit);
97 	reset();
98     }
99     if (--aleft == 0)
100 	stderror(ERR_ALIASLOOP);
101     asyntax(lex->next, lex);
102     resexit(osetexit);
103 }
104 
105 static void
106 asyntax(p1, p2)
107     struct wordent *p1, *p2;
108 {
109     while (p1 != p2)
110 	if (any(";&\n", p1->word[0]))
111 	    p1 = p1->next;
112 	else {
113 	    asyn0(p1, p2);
114 	    return;
115 	}
116 }
117 
118 static void
119 asyn0(p1, p2)
120     struct wordent *p1;
121     struct wordent *p2;
122 {
123     struct wordent *p;
124     int l = 0;
125 
126     for (p = p1; p != p2; p = p->next)
127 	switch (p->word[0]) {
128 
129 	case '(':
130 	    l++;
131 	    continue;
132 
133 	case ')':
134 	    l--;
135 	    if (l < 0)
136 		stderror(ERR_TOOMANYRP);
137 	    continue;
138 
139 	case '>':
140 	    if (p->next != p2 && eq(p->next->word, STRand))
141 		p = p->next;
142 	    continue;
143 
144 	case '&':
145 	case '|':
146 	case ';':
147 	case '\n':
148 	    if (l != 0)
149 		continue;
150 	    asyn3(p1, p);
151 	    asyntax(p->next, p2);
152 	    return;
153 	}
154     if (l == 0)
155 	asyn3(p1, p2);
156 }
157 
158 static void
159 asyn3(p1, p2)
160     struct wordent *p1;
161     struct wordent *p2;
162 {
163     struct varent *ap;
164     struct wordent alout;
165     bool redid;
166 
167     if (p1 == p2)
168 	return;
169     if (p1->word[0] == '(') {
170 	for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
171 	    if (p2 == p1)
172 		return;
173 	if (p2 == p1->next)
174 	    return;
175 	asyn0(p1->next, p2);
176 	return;
177     }
178     ap = adrof1(p1->word, &aliases);
179     if (ap == 0)
180 	return;
181     alhistp = p1->prev;
182     alhistt = p2;
183     alvec = ap->vec;
184     redid = lex(&alout);
185     alhistp = alhistt = 0;
186     alvec = 0;
187     if (seterr) {
188 	freelex(&alout);
189 	stderror(ERR_OLD);
190     }
191     if (p1->word[0] && eq(p1->word, alout.next->word)) {
192 	Char   *cp = alout.next->word;
193 
194 	alout.next->word = Strspl(STRQNULL, cp);
195 	xfree((ptr_t) cp);
196     }
197     p1 = freenod(p1, redid ? p2 : p1->next);
198     if (alout.next != &alout) {
199 	p1->next->prev = alout.prev->prev;
200 	alout.prev->prev->next = p1->next;
201 	alout.next->prev = p1;
202 	p1->next = alout.next;
203 	xfree((ptr_t) alout.prev->word);
204 	xfree((ptr_t) (alout.prev));
205     }
206     reset();			/* throw! */
207 }
208 
209 static struct wordent *
210 freenod(p1, p2)
211     struct wordent *p1, *p2;
212 {
213     struct wordent *retp = p1->prev;
214 
215     while (p1 != p2) {
216 	xfree((ptr_t) p1->word);
217 	p1 = p1->next;
218 	xfree((ptr_t) (p1->prev));
219     }
220     retp->next = p2;
221     p2->prev = retp;
222     return (retp);
223 }
224 
225 #define	PHERE	1
226 #define	PIN	2
227 #define	POUT	4
228 #define	PERR	8
229 
230 /*
231  * syntax
232  *	empty
233  *	syn0
234  */
235 struct command *
236 syntax(p1, p2, flags)
237     struct wordent *p1, *p2;
238     int     flags;
239 {
240 
241     while (p1 != p2)
242 	if (any(";&\n", p1->word[0]))
243 	    p1 = p1->next;
244 	else
245 	    return (syn0(p1, p2, flags));
246     return (0);
247 }
248 
249 /*
250  * syn0
251  *	syn1
252  *	syn1 & syntax
253  */
254 static struct command *
255 syn0(p1, p2, flags)
256     struct wordent *p1, *p2;
257     int     flags;
258 {
259     struct wordent *p;
260     struct command *t, *t1;
261     int     l;
262 
263     l = 0;
264     for (p = p1; p != p2; p = p->next)
265 	switch (p->word[0]) {
266 
267 	case '(':
268 	    l++;
269 	    continue;
270 
271 	case ')':
272 	    l--;
273 	    if (l < 0)
274 		seterror(ERR_TOOMANYRP);
275 	    continue;
276 
277 	case '|':
278 	    if (p->word[1] == '|')
279 		continue;
280 	    /* fall into ... */
281 
282 	case '>':
283 	    if (p->next != p2 && eq(p->next->word, STRand))
284 		p = p->next;
285 	    continue;
286 
287 	case '&':
288 	    if (l != 0)
289 		break;
290 	    if (p->word[1] == '&')
291 		continue;
292 	    t1 = syn1(p1, p, flags);
293 	    if (t1->t_dtyp == NODE_LIST ||
294 		t1->t_dtyp == NODE_AND ||
295 		t1->t_dtyp == NODE_OR) {
296 		t = (struct command *) xcalloc(1, sizeof(*t));
297 		t->t_dtyp = NODE_PAREN;
298 		t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
299 		t->t_dspr = t1;
300 		t1 = t;
301 	    }
302 	    else
303 		t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
304 	    t = (struct command *) xcalloc(1, sizeof(*t));
305 	    t->t_dtyp = NODE_LIST;
306 	    t->t_dflg = 0;
307 	    t->t_dcar = t1;
308 	    t->t_dcdr = syntax(p, p2, flags);
309 	    return (t);
310 	}
311     if (l == 0)
312 	return (syn1(p1, p2, flags));
313     seterror(ERR_TOOMANYLP);
314     return (0);
315 }
316 
317 /*
318  * syn1
319  *	syn1a
320  *	syn1a ; syntax
321  */
322 static struct command *
323 syn1(p1, p2, flags)
324     struct wordent *p1, *p2;
325     int     flags;
326 {
327     struct wordent *p;
328     struct command *t;
329     int     l;
330 
331     l = 0;
332     for (p = p1; p != p2; p = p->next)
333 	switch (p->word[0]) {
334 
335 	case '(':
336 	    l++;
337 	    continue;
338 
339 	case ')':
340 	    l--;
341 	    continue;
342 
343 	case ';':
344 	case '\n':
345 	    if (l != 0)
346 		break;
347 	    t = (struct command *) xcalloc(1, sizeof(*t));
348 	    t->t_dtyp = NODE_LIST;
349 	    t->t_dcar = syn1a(p1, p, flags);
350 	    t->t_dcdr = syntax(p->next, p2, flags);
351 	    if (t->t_dcdr == 0)
352 		t->t_dcdr = t->t_dcar, t->t_dcar = 0;
353 	    return (t);
354 	}
355     return (syn1a(p1, p2, flags));
356 }
357 
358 /*
359  * syn1a
360  *	syn1b
361  *	syn1b || syn1a
362  */
363 static struct command *
364 syn1a(p1, p2, flags)
365     struct wordent *p1, *p2;
366     int     flags;
367 {
368     struct wordent *p;
369     struct command *t;
370     int l = 0;
371 
372     for (p = p1; p != p2; p = p->next)
373 	switch (p->word[0]) {
374 
375 	case '(':
376 	    l++;
377 	    continue;
378 
379 	case ')':
380 	    l--;
381 	    continue;
382 
383 	case '|':
384 	    if (p->word[1] != '|')
385 		continue;
386 	    if (l == 0) {
387 		t = (struct command *) xcalloc(1, sizeof(*t));
388 		t->t_dtyp = NODE_OR;
389 		t->t_dcar = syn1b(p1, p, flags);
390 		t->t_dcdr = syn1a(p->next, p2, flags);
391 		t->t_dflg = 0;
392 		return (t);
393 	    }
394 	    continue;
395 	}
396     return (syn1b(p1, p2, flags));
397 }
398 
399 /*
400  * syn1b
401  *	syn2
402  *	syn2 && syn1b
403  */
404 static struct command *
405 syn1b(p1, p2, flags)
406     struct wordent *p1, *p2;
407     int     flags;
408 {
409     struct wordent *p;
410     struct command *t;
411     int l = 0;
412 
413     for (p = p1; p != p2; p = p->next)
414 	switch (p->word[0]) {
415 
416 	case '(':
417 	    l++;
418 	    continue;
419 
420 	case ')':
421 	    l--;
422 	    continue;
423 
424 	case '&':
425 	    if (p->word[1] == '&' && l == 0) {
426 		t = (struct command *) xcalloc(1, sizeof(*t));
427 		t->t_dtyp = NODE_AND;
428 		t->t_dcar = syn2(p1, p, flags);
429 		t->t_dcdr = syn1b(p->next, p2, flags);
430 		t->t_dflg = 0;
431 		return (t);
432 	    }
433 	    continue;
434 	}
435     return (syn2(p1, p2, flags));
436 }
437 
438 /*
439  * syn2
440  *	syn3
441  *	syn3 | syn2
442  *	syn3 |& syn2
443  */
444 static struct command *
445 syn2(p1, p2, flags)
446     struct wordent *p1, *p2;
447     int     flags;
448 {
449     struct wordent *p, *pn;
450     struct command *t;
451     int l = 0;
452     int     f;
453 
454     for (p = p1; p != p2; p = p->next)
455 	switch (p->word[0]) {
456 
457 	case '(':
458 	    l++;
459 	    continue;
460 
461 	case ')':
462 	    l--;
463 	    continue;
464 
465 	case '|':
466 	    if (l != 0)
467 		continue;
468 	    t = (struct command *) xcalloc(1, sizeof(*t));
469 	    f = flags | POUT;
470 	    pn = p->next;
471 	    if (pn != p2 && pn->word[0] == '&') {
472 		f |= PERR;
473 		t->t_dflg |= F_STDERR;
474 	    }
475 	    t->t_dtyp = NODE_PIPE;
476 	    t->t_dcar = syn3(p1, p, f);
477 	    if (pn != p2 && pn->word[0] == '&')
478 		p = pn;
479 	    t->t_dcdr = syn2(p->next, p2, flags | PIN);
480 	    return (t);
481 	}
482     return (syn3(p1, p2, flags));
483 }
484 
485 static char RELPAR[] = {'<', '>', '(', ')', '\0'};
486 
487 /*
488  * syn3
489  *	( syn0 ) [ < in  ] [ > out ]
490  *	word word* [ < in ] [ > out ]
491  *	KEYWORD ( word* ) word* [ < in ] [ > out ]
492  *
493  *	KEYWORD = (@ exit foreach if set switch test while)
494  */
495 static struct command *
496 syn3(p1, p2, flags)
497     struct wordent *p1, *p2;
498     int     flags;
499 {
500     struct wordent *p;
501     struct wordent *lp, *rp;
502     struct command *t;
503     int l;
504     Char  **av;
505     int     n, c;
506     bool    specp = 0;
507 
508     if (p1 != p2) {
509 	p = p1;
510 again:
511 	switch (srchx(p->word)) {
512 
513 	case T_ELSE:
514 	    p = p->next;
515 	    if (p != p2)
516 		goto again;
517 	    break;
518 
519 	case T_EXIT:
520 	case T_FOREACH:
521 	case T_IF:
522 	case T_LET:
523 	case T_SET:
524 	case T_SWITCH:
525 	case T_WHILE:
526 	    specp = 1;
527 	    break;
528 	}
529     }
530     n = 0;
531     l = 0;
532     for (p = p1; p != p2; p = p->next)
533 	switch (p->word[0]) {
534 
535 	case '(':
536 	    if (specp)
537 		n++;
538 	    l++;
539 	    continue;
540 
541 	case ')':
542 	    if (specp)
543 		n++;
544 	    l--;
545 	    continue;
546 
547 	case '>':
548 	case '<':
549 	    if (l != 0) {
550 		if (specp)
551 		    n++;
552 		continue;
553 	    }
554 	    if (p->next == p2)
555 		continue;
556 	    if (any(RELPAR, p->next->word[0]))
557 		continue;
558 	    n--;
559 	    continue;
560 
561 	default:
562 	    if (!specp && l != 0)
563 		continue;
564 	    n++;
565 	    continue;
566 	}
567     if (n < 0)
568 	n = 0;
569     t = (struct command *) xcalloc(1, sizeof(*t));
570     av = (Char **) xcalloc((size_t) (n + 1), sizeof(Char **));
571     t->t_dcom = av;
572     n = 0;
573     if (p2->word[0] == ')')
574 	t->t_dflg = F_NOFORK;
575     lp = 0;
576     rp = 0;
577     l = 0;
578     for (p = p1; p != p2; p = p->next) {
579 	c = p->word[0];
580 	switch (c) {
581 
582 	case '(':
583 	    if (l == 0) {
584 		if (lp != 0 && !specp)
585 		    seterror(ERR_BADPLP);
586 		lp = p->next;
587 	    }
588 	    l++;
589 	    goto savep;
590 
591 	case ')':
592 	    l--;
593 	    if (l == 0)
594 		rp = p;
595 	    goto savep;
596 
597 	case '>':
598 	    if (l != 0)
599 		goto savep;
600 	    if (p->word[1] == '>')
601 		t->t_dflg |= F_APPEND;
602 	    if (p->next != p2 && eq(p->next->word, STRand)) {
603 		t->t_dflg |= F_STDERR, p = p->next;
604 		if (flags & (POUT | PERR)) {
605 		    seterror(ERR_OUTRED);
606 		    continue;
607 		}
608 	    }
609 	    if (p->next != p2 && eq(p->next->word, STRbang))
610 		t->t_dflg |= F_OVERWRITE, p = p->next;
611 	    if (p->next == p2) {
612 		seterror(ERR_MISRED);
613 		continue;
614 	    }
615 	    p = p->next;
616 	    if (any(RELPAR, p->word[0])) {
617 		seterror(ERR_MISRED);
618 		continue;
619 	    }
620 	    if ((flags & POUT) && ((flags & PERR) == 0 || t->t_drit))
621 		seterror(ERR_OUTRED);
622 	    else
623 		t->t_drit = Strsave(p->word);
624 	    continue;
625 
626 	case '<':
627 	    if (l != 0)
628 		goto savep;
629 	    if (p->word[1] == '<')
630 		t->t_dflg |= F_READ;
631 	    if (p->next == p2) {
632 		seterror(ERR_MISRED);
633 		continue;
634 	    }
635 	    p = p->next;
636 	    if (any(RELPAR, p->word[0])) {
637 		seterror(ERR_MISRED);
638 		continue;
639 	    }
640 	    if ((flags & PHERE) && (t->t_dflg & F_READ))
641 		seterror(ERR_REDPAR);
642 	    else if ((flags & PIN) || t->t_dlef)
643 		seterror(ERR_INRED);
644 	    else
645 		t->t_dlef = Strsave(p->word);
646 	    continue;
647 
648     savep:
649 	    if (!specp)
650 		continue;
651 	default:
652 	    if (l != 0 && !specp)
653 		continue;
654 	    if (seterr == 0)
655 		av[n] = Strsave(p->word);
656 	    n++;
657 	    continue;
658 	}
659     }
660     if (lp != 0 && !specp) {
661 	if (n != 0)
662 	    seterror(ERR_BADPLPS);
663 	t->t_dtyp = NODE_PAREN;
664 	t->t_dspr = syn0(lp, rp, PHERE);
665     }
666     else {
667 	if (n == 0)
668 	    seterror(ERR_NULLCOM);
669 	t->t_dtyp = NODE_COMMAND;
670     }
671     return (t);
672 }
673 
674 void
675 freesyn(t)
676     struct command *t;
677 {
678     Char **v;
679 
680     if (t == 0)
681 	return;
682     switch (t->t_dtyp) {
683 
684     case NODE_COMMAND:
685 	for (v = t->t_dcom; *v; v++)
686 	    xfree((ptr_t) * v);
687 	xfree((ptr_t) (t->t_dcom));
688 	xfree((ptr_t) t->t_dlef);
689 	xfree((ptr_t) t->t_drit);
690 	break;
691     case NODE_PAREN:
692 	freesyn(t->t_dspr);
693 	xfree((ptr_t) t->t_dlef);
694 	xfree((ptr_t) t->t_drit);
695 	break;
696 
697     case NODE_AND:
698     case NODE_OR:
699     case NODE_PIPE:
700     case NODE_LIST:
701 	freesyn(t->t_dcar), freesyn(t->t_dcdr);
702 	break;
703     }
704     xfree((ptr_t) t);
705 }
706