xref: /illumos-gate/usr/src/cmd/csh/sh.parse.c (revision 258f91c6020f3614878f3dcd49df02d9e004de2c)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved  	*/
8 
9 /*
10  * Copyright (c) 1980 Regents of the University of California.
11  * All rights reserved. The Berkeley Software License Agreement
12  * specifies the terms and conditions for redistribution.
13  */
14 
15 #include "sh.h"
16 #include "sh.tconst.h"
17 
18 /*
19  * C shell
20  */
21 
22 void	asyntax(struct wordent *, struct wordent *);
23 void	asyn0(struct wordent *, struct wordent *);
24 void	asyn3(struct wordent *, struct wordent *);
25 void	chr_blkfree(char **);
26 struct command	*syn0(struct wordent *, struct wordent *, int);
27 struct command	*syn1(struct wordent *, struct wordent *, int);
28 struct command	*syn1a(struct wordent *, struct wordent *, int);
29 struct command	*syn1b(struct wordent *, struct wordent *, int);
30 struct command	*syn2(struct wordent *, struct wordent *, int);
31 struct command	*syn3(struct wordent *, struct wordent *, int);
32 struct wordent	*freenod(struct wordent *, struct wordent *);
33 
34 /*
35  * Perform aliasing on the word list lex
36  * Do a (very rudimentary) parse to separate into commands.
37  * If word 0 of a command has an alias, do it.
38  * Repeat a maximum of 20 times.
39  */
40 void
alias(struct wordent * lex)41 alias(struct wordent *lex)
42 {
43 	int aleft = 21;
44 	jmp_buf osetexit;
45 
46 #ifdef TRACE
47 	tprintf("TRACE- alias()\n");
48 #endif
49 	getexit(osetexit);
50 	setexit();
51 	if (haderr) {
52 		resexit(osetexit);
53 		reset();
54 	}
55 	if (--aleft == 0)
56 		error("Alias loop");
57 	asyntax(lex->next, lex);
58 	resexit(osetexit);
59 }
60 
61 void
asyntax(struct wordent * p1,struct wordent * p2)62 asyntax(struct wordent *p1, struct wordent *p2)
63 {
64 #ifdef TRACE
65 	tprintf("TRACE- asyntax()\n");
66 #endif
67 
68 	while (p1 != p2)
69 		/* if (any(p1->word[0], ";&\n")) */  /* For char -> tchar */
70 		if (p1->word[0] == ';' ||
71 		    p1->word[0] == '&' ||
72 		    p1->word[0] == '\n')
73 			p1 = p1->next;
74 		else {
75 			asyn0(p1, p2);
76 			return;
77 		}
78 }
79 
80 void
asyn0(struct wordent * p1,struct wordent * p2)81 asyn0(struct wordent *p1, struct wordent *p2)
82 {
83 	struct wordent *p;
84 	int l = 0;
85 
86 #ifdef TRACE
87 	tprintf("TRACE- asyn0()\n");
88 #endif
89 	for (p = p1; p != p2; p = p->next)
90 		switch (p->word[0]) {
91 
92 		case '(':
93 			l++;
94 			continue;
95 
96 		case ')':
97 			l--;
98 			if (l < 0)
99 				error("Too many )'s");
100 			continue;
101 
102 		case '>':
103 			if (p->next != p2 && eq(p->next->word, S_AND /* "&"*/))
104 				p = p->next;
105 			continue;
106 
107 		case '&':
108 		case '|':
109 		case ';':
110 		case '\n':
111 			if (l != 0)
112 				continue;
113 			asyn3(p1, p);
114 			asyntax(p->next, p2);
115 			return;
116 		}
117 	if (l == 0)
118 		asyn3(p1, p2);
119 }
120 
121 void
asyn3(struct wordent * p1,struct wordent * p2)122 asyn3(struct wordent *p1, struct wordent *p2)
123 {
124 	struct varent *ap;
125 	struct wordent alout;
126 	bool redid;
127 
128 #ifdef TRACE
129 	tprintf("TRACE- asyn3()\n");
130 #endif
131 	if (p1 == p2)
132 		return;
133 	if (p1->word[0] == '(') {
134 		for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
135 			if (p2 == p1)
136 				return;
137 		if (p2 == p1->next)
138 			return;
139 		asyn0(p1->next, p2);
140 		return;
141 	}
142 	ap = adrof1(p1->word, &aliases);
143 	if (ap == 0)
144 		return;
145 	alhistp = p1->prev;
146 	alhistt = p2;
147 	alvec = ap->vec;
148 	redid = lex(&alout);
149 	alhistp = alhistt = 0;
150 	alvec = 0;
151 	if (err_msg) {
152 		freelex(&alout);
153 		error("%s", gettext(err_msg));
154 	}
155 	if (p1->word[0] && eq(p1->word, alout.next->word)) {
156 		tchar *cp = alout.next->word;
157 
158 		alout.next->word = strspl(S_TOPBIT /* "\200" */, cp);
159 		xfree(cp);
160 	}
161 	p1 = freenod(p1, redid ? p2 : p1->next);
162 	if (alout.next != &alout) {
163 		p1->next->prev = alout.prev->prev;
164 		alout.prev->prev->next = p1->next;
165 		alout.next->prev = p1;
166 		p1->next = alout.next;
167 		xfree(alout.prev->word);
168 		xfree(alout.prev);
169 	}
170 	reset();		/* throw! */
171 }
172 
173 struct wordent *
freenod(struct wordent * p1,struct wordent * p2)174 freenod(struct wordent *p1, struct wordent *p2)
175 {
176 	struct wordent *retp = p1->prev;
177 
178 #ifdef TRACE
179 	tprintf("TRACE- freenod()\n");
180 #endif
181 	while (p1 != p2) {
182 		xfree(p1->word);
183 		p1 = p1->next;
184 		xfree(p1->prev);
185 	}
186 	retp->next = p2;
187 	p2->prev = retp;
188 	return (retp);
189 }
190 
191 #define	PHERE	1
192 #define	PIN	2
193 #define	POUT	4
194 #define	PDIAG	8
195 
196 /*
197  * syntax
198  *	empty
199  *	syn0
200  */
201 struct command *
syntax(struct wordent * p1,struct wordent * p2,int flags)202 syntax(struct wordent *p1, struct wordent *p2, int flags)
203 {
204 #ifdef TRACE
205 	tprintf("TRACE- syntax()\n");
206 #endif
207 
208 	while (p1 != p2)
209 		/* if (any(p1->word[0], ";&\n")) */ /* for char -> tchar */
210 		if (p1->word[0] == ';' ||
211 		    p1->word[0] == '&' ||
212 		    p1->word[0] == '\n')
213 			p1 = p1->next;
214 		else
215 			return (syn0(p1, p2, flags));
216 	return (0);
217 }
218 
219 /*
220  * syn0
221  *	syn1
222  *	syn1 & syntax
223  */
224 struct command *
syn0(struct wordent * p1,struct wordent * p2,int flags)225 syn0(struct wordent *p1, struct wordent *p2, int flags)
226 {
227 	struct wordent *p;
228 	struct command *t, *t1;
229 	int l;
230 
231 #ifdef TRACE
232 	tprintf("TRACE- syn0()\n");
233 #endif
234 	l = 0;
235 	for (p = p1; p != p2; p = p->next)
236 		switch (p->word[0]) {
237 
238 		case '(':
239 			l++;
240 			continue;
241 
242 		case ')':
243 			l--;
244 			if (l < 0)
245 				seterr("Too many )'s");
246 			continue;
247 
248 		case '|':
249 			if (p->word[1] == '|')
250 				continue;
251 			/* fall into ... */
252 
253 		case '>':
254 			if (p->next != p2 && eq(p->next->word, S_AND /* "&" */))
255 				p = p->next;
256 			continue;
257 
258 		case '&':
259 			if (l != 0)
260 				break;
261 			if (p->word[1] == '&')
262 				continue;
263 			t1 = syn1(p1, p, flags);
264 			if (t1->t_dtyp == TLST ||
265 			    t1->t_dtyp == TAND ||
266 			    t1->t_dtyp == TOR) {
267 				t = (struct command *)xcalloc(1, sizeof (*t));
268 				t->t_dtyp = TPAR;
269 				t->t_dflg = FAND|FINT;
270 				t->t_dspr = t1;
271 				t1 = t;
272 			} else
273 				t1->t_dflg |= FAND|FINT;
274 			t = (struct command *)xcalloc(1, sizeof (*t));
275 			t->t_dtyp = TLST;
276 			t->t_dflg = 0;
277 			t->t_dcar = t1;
278 			t->t_dcdr = syntax(p, p2, flags);
279 			return (t);
280 		}
281 	if (l == 0)
282 		return (syn1(p1, p2, flags));
283 	seterr("Too many ('s");
284 	return (0);
285 }
286 
287 /*
288  * syn1
289  *	syn1a
290  *	syn1a ; syntax
291  */
292 struct command *
syn1(struct wordent * p1,struct wordent * p2,int flags)293 syn1(struct wordent *p1, struct wordent *p2, int flags)
294 {
295 	struct wordent *p;
296 	struct command *t;
297 	int l;
298 
299 #ifdef TRACE
300 	tprintf("TRACE- syn1()\n");
301 #endif
302 	l = 0;
303 	for (p = p1; p != p2; p = p->next)
304 		switch (p->word[0]) {
305 
306 		case '(':
307 			l++;
308 			continue;
309 
310 		case ')':
311 			l--;
312 			continue;
313 
314 		case ';':
315 		case '\n':
316 			if (l != 0)
317 				break;
318 			t = (struct command *)xcalloc(1, sizeof (*t));
319 			t->t_dtyp = TLST;
320 			t->t_dcar = syn1a(p1, p, flags);
321 			t->t_dcdr = syntax(p->next, p2, flags);
322 			if (t->t_dcdr == 0)
323 				t->t_dcdr = t->t_dcar, t->t_dcar = 0;
324 			return (t);
325 		}
326 	return (syn1a(p1, p2, flags));
327 }
328 
329 /*
330  * syn1a
331  *	syn1b
332  *	syn1b || syn1a
333  */
334 struct command *
syn1a(struct wordent * p1,struct wordent * p2,int flags)335 syn1a(struct wordent *p1, struct wordent *p2, int flags)
336 {
337 	struct wordent *p;
338 	struct command *t;
339 	int l = 0;
340 
341 #ifdef TRACE
342 	tprintf("TRACE- syn1a()\n");
343 #endif
344 	for (p = p1; p != p2; p = p->next)
345 		switch (p->word[0]) {
346 
347 		case '(':
348 			l++;
349 			continue;
350 
351 		case ')':
352 			l--;
353 			continue;
354 
355 		case '|':
356 			if (p->word[1] != '|')
357 				continue;
358 			if (l == 0) {
359 				t = (struct command *)xcalloc(1, sizeof (*t));
360 				t->t_dtyp = TOR;
361 				t->t_dcar = syn1b(p1, p, flags);
362 				t->t_dcdr = syn1a(p->next, p2, flags);
363 				t->t_dflg = 0;
364 				return (t);
365 			}
366 			continue;
367 		}
368 	return (syn1b(p1, p2, flags));
369 }
370 
371 /*
372  * syn1b
373  *	syn2
374  *	syn2 && syn1b
375  */
376 struct command *
syn1b(struct wordent * p1,struct wordent * p2,int flags)377 syn1b(struct wordent *p1, struct wordent *p2, int flags)
378 {
379 	struct wordent *p;
380 	struct command *t;
381 	int l = 0;
382 
383 #ifdef TRACE
384 	tprintf("TRACE- syn1b()\n");
385 #endif
386 	l = 0;
387 	for (p = p1; p != p2; p = p->next)
388 		switch (p->word[0]) {
389 
390 		case '(':
391 			l++;
392 			continue;
393 
394 		case ')':
395 			l--;
396 			continue;
397 
398 		case '&':
399 			if (p->word[1] == '&' && l == 0) {
400 				t = (struct command *)xcalloc(1, sizeof (*t));
401 				t->t_dtyp = TAND;
402 				t->t_dcar = syn2(p1, p, flags);
403 				t->t_dcdr = syn1b(p->next, p2, flags);
404 				t->t_dflg = 0;
405 				return (t);
406 			}
407 			continue;
408 		}
409 	return (syn2(p1, p2, flags));
410 }
411 
412 /*
413  * syn2
414  *	syn3
415  *	syn3 | syn2
416  *	syn3 |& syn2
417  */
418 struct command *
syn2(struct wordent * p1,struct wordent * p2,int flags)419 syn2(struct wordent *p1, struct wordent *p2, int flags)
420 {
421 	struct wordent *p, *pn;
422 	struct command *t;
423 	int l = 0;
424 	int f;
425 
426 #ifdef TRACE
427 	tprintf("TRACE- syn2()\n");
428 #endif
429 	for (p = p1; p != p2; p = p->next)
430 		switch (p->word[0]) {
431 
432 		case '(':
433 			l++;
434 			continue;
435 
436 		case ')':
437 			l--;
438 			continue;
439 
440 		case '|':
441 			if (l != 0)
442 				continue;
443 			t = (struct command *)xcalloc(1, sizeof (*t));
444 			f = flags | POUT;
445 			pn = p->next;
446 			if (pn != p2 && pn->word[0] == '&') {
447 				f |= PDIAG;
448 				t->t_dflg |= FDIAG;
449 			}
450 			t->t_dtyp = TFIL;
451 			t->t_dcar = syn3(p1, p, f);
452 			if (pn != p2 && pn->word[0] == '&')
453 				p = pn;
454 			t->t_dcdr = syn2(p->next, p2, flags | PIN);
455 			return (t);
456 		}
457 	return (syn3(p1, p2, flags));
458 }
459 
460 tchar 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 struct command *
syn3(struct wordent * p1,struct wordent * p2,int flags)471 syn3(struct wordent *p1, struct wordent *p2, int flags)
472 {
473 	struct wordent *p;
474 	struct wordent *lp, *rp;
475 	struct command *t;
476 	int l;
477 	tchar **av;
478 	int n, c;
479 	bool specp = 0;
480 
481 #ifdef TRACE
482 	tprintf("TRACE- syn3()\n");
483 #endif
484 	if (p1 != p2) {
485 		p = p1;
486 again:
487 		switch (srchx(p->word)) {
488 
489 		case ZELSE:
490 			p = p->next;
491 			if (p != p2)
492 				goto again;
493 			break;
494 
495 		case ZEXIT:
496 		case ZFOREACH:
497 		case ZIF:
498 		case ZLET:
499 		case ZSET:
500 		case ZSWITCH:
501 		case ZWHILE:
502 			specp = 1;
503 			break;
504 		}
505 	}
506 	n = 0;
507 	l = 0;
508 	for (p = p1; p != p2; p = p->next)
509 		switch (p->word[0]) {
510 
511 		case '(':
512 			if (specp)
513 				n++;
514 			l++;
515 			continue;
516 
517 		case ')':
518 			if (specp)
519 				n++;
520 			l--;
521 			continue;
522 
523 		case '>':
524 		case '<':
525 			if (l != 0) {
526 				if (specp)
527 					n++;
528 				continue;
529 			}
530 			if (p->next == p2)
531 				continue;
532 			if (any(p->next->word[0], RELPAR))
533 				continue;
534 			n--;
535 			continue;
536 
537 		default:
538 			if (!specp && l != 0)
539 				continue;
540 			n++;
541 			continue;
542 		}
543 	if (n < 0)
544 		n = 0;
545 	t = (struct command *)xcalloc(1, sizeof (*t));
546 	av =  (tchar **)xcalloc((unsigned)(n + 1), sizeof (tchar **));
547 	t->t_dcom = av;
548 	n = 0;
549 	if (p2->word[0] == ')')
550 		t->t_dflg = FPAR;
551 	lp = 0;
552 	rp = 0;
553 	l = 0;
554 	for (p = p1; p != p2; p = p->next) {
555 		c = p->word[0];
556 		switch (c) {
557 
558 		case '(':
559 			if (l == 0) {
560 				if (lp != 0 && !specp)
561 					seterr("Badly placed (");
562 				lp = p->next;
563 			}
564 			l++;
565 			goto savep;
566 
567 		case ')':
568 			l--;
569 			if (l == 0)
570 				rp = p;
571 			goto savep;
572 
573 		case '>':
574 			if (l != 0)
575 				goto savep;
576 			if (p->word[1] == '>')
577 				t->t_dflg |= FCAT;
578 			if (p->next != p2 && eq(p->next->word, S_AND /* "&" */)) {
579 				t->t_dflg |= FDIAG, p = p->next;
580 				if (flags & (POUT|PDIAG))
581 					goto badout;
582 			}
583 			if (p->next != p2 && eq(p->next->word, S_EXAS /* "!" */))
584 				t->t_dflg |= FANY, p = p->next;
585 			if (p->next == p2) {
586 missfile:
587 				seterr("Missing name for redirect");
588 				continue;
589 			}
590 			p = p->next;
591 			if (any(p->word[0], RELPAR))
592 				goto missfile;
593 			if ((flags & POUT) && (flags & PDIAG) == 0 || t->t_drit)
594 badout:
595 				seterr("Ambiguous output redirect");
596 			else
597 				t->t_drit = savestr(p->word);
598 			continue;
599 
600 		case '<':
601 			if (l != 0)
602 				goto savep;
603 			if (p->word[1] == '<')
604 				t->t_dflg |= FHERE;
605 			if (p->next == p2)
606 				goto missfile;
607 			p = p->next;
608 			if (any(p->word[0], RELPAR))
609 				goto missfile;
610 			if ((flags & PHERE) && (t->t_dflg & FHERE))
611 				seterr("Can't << within ()'s");
612 			else if ((flags & PIN) || t->t_dlef)
613 				seterr("Ambiguous input redirect");
614 			else
615 				t->t_dlef = savestr(p->word);
616 			continue;
617 
618 savep:
619 			if (!specp)
620 				continue;
621 		default:
622 			if (l != 0 && !specp)
623 				continue;
624 			if (err_msg == NULL)
625 				av[n] = savestr(p->word);
626 			n++;
627 			continue;
628 		}
629 	}
630 	if (lp != 0 && !specp) {
631 		if (n != 0)
632 			seterr("Badly placed ()'s");
633 		t->t_dtyp = TPAR;
634 		t->t_dspr = syn0(lp, rp, PHERE);
635 	} else {
636 		if (n == 0)
637 			seterr("Invalid null command");
638 		t->t_dtyp = TCOM;
639 	}
640 	return (t);
641 }
642 
643 void
freesyn(struct command * t)644 freesyn(struct command *t)
645 {
646 #ifdef TRACE
647 	tprintf("TRACE- freesyn()\n");
648 #endif
649 	if (t == 0)
650 		return;
651 	switch (t->t_dtyp) {
652 
653 	case TCOM:
654 		blkfree(t->t_dcom);
655 		if (t->cfname)
656 			xfree(t->cfname);
657 		if (t->cargs)
658 			chr_blkfree(t->cargs);
659 		goto lr;
660 
661 	case TPAR:
662 		freesyn(t->t_dspr);
663 		/* fall into ... */
664 
665 lr:
666 		xfree(t->t_dlef);
667 		xfree(t->t_drit);
668 		break;
669 
670 	case TAND:
671 	case TOR:
672 	case TFIL:
673 	case TLST:
674 		freesyn(t->t_dcar), freesyn(t->t_dcdr);
675 		break;
676 	}
677 	xfree(t);
678 }
679 
680 
681 void
chr_blkfree(char ** vec)682 chr_blkfree(char **vec)
683 {
684 	char **av;
685 
686 	for (av = vec; *av; av++)
687 		xfree(*av);
688 	xfree(vec);
689 }
690