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