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