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