xref: /original-bsd/local/toolchest/ksh/sh/cmd.c (revision 2565f573)
1*2565f573Smarc /*
2*2565f573Smarc 
3*2565f573Smarc  *      Copyright (c) 1984, 1985, 1986 AT&T
4*2565f573Smarc  *      All Rights Reserved
5*2565f573Smarc 
6*2565f573Smarc  *      THIS IS UNPUBLISHED PROPRIETARY SOURCE
7*2565f573Smarc  *      CODE OF AT&T.
8*2565f573Smarc  *      The copyright notice above does not
9*2565f573Smarc  *      evidence any actual or intended
10*2565f573Smarc  *      publication of such source code.
11*2565f573Smarc 
12*2565f573Smarc  */
13*2565f573Smarc /* @(#)cmd.c	1.1 */
14*2565f573Smarc /*
15*2565f573Smarc  * UNIX shell
16*2565f573Smarc  *
17*2565f573Smarc  * S. R. Bourne
18*2565f573Smarc  * Rewritten by David Korn
19*2565f573Smarc  * AT&T Bell Laboratories
20*2565f573Smarc  *
21*2565f573Smarc  */
22*2565f573Smarc 
23*2565f573Smarc #include	"defs.h"
24*2565f573Smarc #include	"sym.h"
25*2565f573Smarc #include	"flags.h"
26*2565f573Smarc #include	"name.h"
27*2565f573Smarc #include	"io.h"
28*2565f573Smarc #include	"history.h"
29*2565f573Smarc #include	"mode.h"
30*2565f573Smarc #include	"stak.h"
31*2565f573Smarc #include	"shtype.h"
32*2565f573Smarc #include	"brkincr.h"
33*2565f573Smarc #include	"builtins.h"
34*2565f573Smarc 
35*2565f573Smarc 
36*2565f573Smarc /* These routines are defined by this module */
37*2565f573Smarc void	synbad();
38*2565f573Smarc TREPTR	cmd();
39*2565f573Smarc TREPTR	makefork();
40*2565f573Smarc 
41*2565f573Smarc /* These routines are referenced by this module */
42*2565f573Smarc extern void	addblok();
43*2565f573Smarc extern void	chkpr();
44*2565f573Smarc extern void	exitsh();
45*2565f573Smarc extern void	free();
46*2565f573Smarc extern STKPTR	getstak();
47*2565f573Smarc extern void	hist_cancel();
48*2565f573Smarc extern void	hist_flush();
49*2565f573Smarc extern long	hist_position();
50*2565f573Smarc extern char	*malloc();
51*2565f573Smarc extern char	*movstr();
52*2565f573Smarc extern void	p_setout();
53*2565f573Smarc extern void	p_str();
54*2565f573Smarc extern void	p_prp();
55*2565f573Smarc extern void	p_num();
56*2565f573Smarc 
57*2565f573Smarc static TREPTR	makelist();
58*2565f573Smarc static ARGPTR	qscan();
59*2565f573Smarc static IOPTR	inout();
60*2565f573Smarc static void	chkword();
61*2565f573Smarc static void	chkflags();
62*2565f573Smarc static void	chksym();
63*2565f573Smarc static TREPTR	term();
64*2565f573Smarc static TREPTR	list();
65*2565f573Smarc static REGPTR	syncase();
66*2565f573Smarc static TREPTR	item();
67*2565f573Smarc static int	skipnl();
68*2565f573Smarc static void	prsym();
69*2565f573Smarc 
70*2565f573Smarc 
71*2565f573Smarc static int	heredoc;
72*2565f573Smarc 
73*2565f573Smarc /*
74*2565f573Smarc  * ========	command line decoding	========
75*2565f573Smarc  *
76*2565f573Smarc  *  This is the parser for a shell command line
77*2565f573Smarc  */
78*2565f573Smarc 
79*2565f573Smarc 
80*2565f573Smarc 
81*2565f573Smarc 
82*2565f573Smarc /*
83*2565f573Smarc  * Make a node which will cause the shell to fork
84*2565f573Smarc  */
85*2565f573Smarc 
makefork(flgs,i)86*2565f573Smarc TREPTR	makefork(flgs, i)
87*2565f573Smarc int 	flgs;
88*2565f573Smarc TREPTR		i;
89*2565f573Smarc {
90*2565f573Smarc 	register FORKPTR	t;
91*2565f573Smarc 	t=(FORKPTR) getstak(FORKTYPE);
92*2565f573Smarc 	t->forktyp = flgs|TFORK;
93*2565f573Smarc 	t->forktre = i;
94*2565f573Smarc 	t->forkio = 0;
95*2565f573Smarc 	return((TREPTR)t);
96*2565f573Smarc }
97*2565f573Smarc 
98*2565f573Smarc /*
99*2565f573Smarc  *  Make a node corresponding to a command list
100*2565f573Smarc  */
101*2565f573Smarc 
makelist(type,i,r)102*2565f573Smarc static TREPTR	makelist(type,i,r)
103*2565f573Smarc int 	type;
104*2565f573Smarc TREPTR		i, r;
105*2565f573Smarc {
106*2565f573Smarc 	register LSTPTR	t;
107*2565f573Smarc 	if(i==0 || r==0)
108*2565f573Smarc 		synbad();
109*2565f573Smarc 	else
110*2565f573Smarc 	{
111*2565f573Smarc 		t = (LSTPTR) getstak(LSTTYPE);
112*2565f573Smarc 		t->lsttyp = type;
113*2565f573Smarc 		t->lstlef = i;
114*2565f573Smarc 		t->lstrit = r;
115*2565f573Smarc 	}
116*2565f573Smarc 	return((TREPTR)t);
117*2565f573Smarc }
118*2565f573Smarc 
119*2565f573Smarc /*
120*2565f573Smarc  * cmd
121*2565f573Smarc  *	empty
122*2565f573Smarc  *	list
123*2565f573Smarc  *	list & [ cmd ]
124*2565f573Smarc  *	list [ ; cmd ]
125*2565f573Smarc  */
126*2565f573Smarc 
cmd(sym,flg)127*2565f573Smarc TREPTR	cmd(sym,flg)
128*2565f573Smarc register int 	sym;
129*2565f573Smarc int 	flg;
130*2565f573Smarc {
131*2565f573Smarc 	register int flag = FINT|FPRS|FAMP;
132*2565f573Smarc 	register TREPTR	i, e;
133*2565f573Smarc 	IOPTR saviotemp = iotemp;
134*2565f573Smarc 	/* parser output goes on standard error */
135*2565f573Smarc 	p_setout(stderr);
136*2565f573Smarc 	i = list(flg);
137*2565f573Smarc 	if(wdval==NL)
138*2565f573Smarc 	{
139*2565f573Smarc 		if(flg&NLFLG)
140*2565f573Smarc 		{
141*2565f573Smarc 			wdval=';';
142*2565f573Smarc 			chkpr(0);
143*2565f573Smarc 		}
144*2565f573Smarc 	}
145*2565f573Smarc 	else if(i==0 && (flg&MTFLG)==0)
146*2565f573Smarc 		synbad();
147*2565f573Smarc 	switch(wdval)
148*2565f573Smarc 	{
149*2565f573Smarc 		case COOPSYM:		/* set up a cooperating process */
150*2565f573Smarc 			flag |= FPIN|FPOU;
151*2565f573Smarc 		case '&':
152*2565f573Smarc 			if(i)
153*2565f573Smarc 			{
154*2565f573Smarc 				if(saviotemp!=iotemp || heredoc)
155*2565f573Smarc 					flag |= FTMP;
156*2565f573Smarc 				i = (TREPTR)makefork(flag, i);
157*2565f573Smarc 			}
158*2565f573Smarc 			else
159*2565f573Smarc 				 synbad();
160*2565f573Smarc 
161*2565f573Smarc 		case ';':
162*2565f573Smarc 			if(e=cmd(sym,flg|MTFLG))
163*2565f573Smarc 				i=(TREPTR)makelist(TLST, i, e);
164*2565f573Smarc 			break;
165*2565f573Smarc 
166*2565f573Smarc 		case EOFSYM:
167*2565f573Smarc 			if(sym==NL)
168*2565f573Smarc 				break;
169*2565f573Smarc 
170*2565f573Smarc 		default:
171*2565f573Smarc 			if(sym)
172*2565f573Smarc 				chksym(sym);
173*2565f573Smarc 
174*2565f573Smarc 	}
175*2565f573Smarc 	/* restore output stream */
176*2565f573Smarc 	return(i);
177*2565f573Smarc }
178*2565f573Smarc 
179*2565f573Smarc /*
180*2565f573Smarc  * list
181*2565f573Smarc  *	term
182*2565f573Smarc  *	list && term
183*2565f573Smarc  *	list || term
184*2565f573Smarc  */
185*2565f573Smarc 
list(flg)186*2565f573Smarc static TREPTR	list(flg)
187*2565f573Smarc {
188*2565f573Smarc 	register TREPTR	r;
189*2565f573Smarc 	register int 	b;
190*2565f573Smarc 	r = term(flg);
191*2565f573Smarc 	while(r && ((b=(wdval==ANDFSYM)) || wdval==ORFSYM))
192*2565f573Smarc 	{
193*2565f573Smarc 		r = makelist((b ? TAND : TORF), r, term(NLFLG));
194*2565f573Smarc 	}
195*2565f573Smarc 	return(r);
196*2565f573Smarc }
197*2565f573Smarc 
198*2565f573Smarc /*
199*2565f573Smarc  * term
200*2565f573Smarc  *	item
201*2565f573Smarc  *	item |^ term
202*2565f573Smarc  */
203*2565f573Smarc 
term(flg)204*2565f573Smarc static TREPTR	term(flg)
205*2565f573Smarc register int flg;
206*2565f573Smarc {
207*2565f573Smarc 	register TREPTR	t;
208*2565f573Smarc 	register PARPTR	p = NULL;
209*2565f573Smarc 	heredoc = 0;
210*2565f573Smarc 	reserv++;
211*2565f573Smarc 	if(flg&NLFLG)
212*2565f573Smarc 		skipnl();
213*2565f573Smarc 	else
214*2565f573Smarc 		 word();
215*2565f573Smarc 	/* check to see if pipeline is to be timed */
216*2565f573Smarc 	if(wdval==TIMSYM)
217*2565f573Smarc 	{
218*2565f573Smarc 		p=(PARPTR) getstak(PARTYPE);
219*2565f573Smarc 		p->partyp=TTIME;
220*2565f573Smarc 		reserv++;
221*2565f573Smarc 		word();
222*2565f573Smarc 	}
223*2565f573Smarc 	if((t=item(NLFLG|MTFLG)) && wdval=='|')
224*2565f573Smarc 	{
225*2565f573Smarc 		flg = heredoc|FPOU;
226*2565f573Smarc 		t=makelist(TFIL,makefork(flg,t),makefork(FPIN|FPCL,term(NLFLG)));
227*2565f573Smarc 	}
228*2565f573Smarc 	if(p)
229*2565f573Smarc 	{
230*2565f573Smarc 		p->partre= t;
231*2565f573Smarc 		return((TREPTR)p);
232*2565f573Smarc 	}
233*2565f573Smarc 	else
234*2565f573Smarc 		return(t);
235*2565f573Smarc }
236*2565f573Smarc 
237*2565f573Smarc /*
238*2565f573Smarc  * case statement
239*2565f573Smarc  */
240*2565f573Smarc 
syncase(esym)241*2565f573Smarc static REGPTR	syncase(esym)
242*2565f573Smarc register int esym;
243*2565f573Smarc {
244*2565f573Smarc 	wdset |= E_FLAG; 	/* set to avoid aliasing expressions */
245*2565f573Smarc 	skipnl();
246*2565f573Smarc 	if(wdval==esym)
247*2565f573Smarc 	{
248*2565f573Smarc 		wdset &= ~E_FLAG;
249*2565f573Smarc 		return(0);
250*2565f573Smarc 	}
251*2565f573Smarc 	else
252*2565f573Smarc 	{
253*2565f573Smarc 		register REGPTR	r=(REGPTR) getstak(REGTYPE);
254*2565f573Smarc 		r->regptr=0;
255*2565f573Smarc 		while(1)
256*2565f573Smarc 		{
257*2565f573Smarc 			chkflags(wdarg,1);
258*2565f573Smarc 			wdarg->argnxt=r->regptr;
259*2565f573Smarc 			r->regptr=wdarg;
260*2565f573Smarc 			if(wdval==')' || wdval=='|' || ( word()!=')' && wdval!='|' ))
261*2565f573Smarc 				synbad();
262*2565f573Smarc 			if(wdval=='|')
263*2565f573Smarc 				word();
264*2565f573Smarc 			else
265*2565f573Smarc 				break;
266*2565f573Smarc 		}
267*2565f573Smarc 		wdset &= ~E_FLAG;
268*2565f573Smarc 		r->regcom=cmd(0,NLFLG|MTFLG);
269*2565f573Smarc 		if(wdval==ECSYM)
270*2565f573Smarc 			r->regnxt=syncase(esym);
271*2565f573Smarc 		else
272*2565f573Smarc 		{
273*2565f573Smarc 			chksym(esym);
274*2565f573Smarc 			r->regnxt=0;
275*2565f573Smarc 		}
276*2565f573Smarc 		return(r);
277*2565f573Smarc 	}
278*2565f573Smarc }
279*2565f573Smarc 
280*2565f573Smarc /*
281*2565f573Smarc  * item
282*2565f573Smarc  *
283*2565f573Smarc  *	( cmd ) [ < in ] [ > out ]
284*2565f573Smarc  *	word word* [ < in ] [ > out ]
285*2565f573Smarc  *	if ... then ... else ... fi
286*2565f573Smarc  *	for ... while ... do ... done
287*2565f573Smarc  *	case ... in ... esac
288*2565f573Smarc  *	begin ... end
289*2565f573Smarc  */
290*2565f573Smarc 
item(flag)291*2565f573Smarc static TREPTR	item(flag)
292*2565f573Smarc BOOL		flag;
293*2565f573Smarc {
294*2565f573Smarc 	register TREPTR	t;
295*2565f573Smarc 	register IOPTR	io;
296*2565f573Smarc 	if(flag)
297*2565f573Smarc 		io=inout((IOPTR)0,1);
298*2565f573Smarc 	else
299*2565f573Smarc 		io=0;
300*2565f573Smarc 	switch(wdval)
301*2565f573Smarc 	{
302*2565f573Smarc 		/* case statement */
303*2565f573Smarc 		case CASYM:
304*2565f573Smarc 		{
305*2565f573Smarc 			t=(TREPTR) getstak(SWTYPE);
306*2565f573Smarc 			chkword();
307*2565f573Smarc 			((SWPTR) t)->swarg=wdarg->argval;
308*2565f573Smarc 			skipnl();
309*2565f573Smarc 			chksym(INSYM|BRSYM);
310*2565f573Smarc 			((SWPTR) t)->swlst=syncase(wdval==INSYM?ESSYM:KTSYM);
311*2565f573Smarc 			((SWPTR) t)->swtyp=TSW;
312*2565f573Smarc 			break;
313*2565f573Smarc 		}
314*2565f573Smarc 
315*2565f573Smarc 		/* if statement */
316*2565f573Smarc 		case IFSYM:
317*2565f573Smarc 		{
318*2565f573Smarc 			register int w;
319*2565f573Smarc 			t=(TREPTR) getstak(IFTYPE);
320*2565f573Smarc 			((IFPTR) t)->iftyp=TIF;
321*2565f573Smarc 			((IFPTR) t)->iftre=cmd(THSYM,NLFLG);
322*2565f573Smarc 			((IFPTR) t)->thtre=cmd(ELSYM|FISYM|EFSYM,NLFLG);
323*2565f573Smarc 			((IFPTR) t)->eltre=((w=wdval)==ELSYM?cmd(FISYM,NLFLG):
324*2565f573Smarc 				(w==EFSYM?(wdval=IFSYM, item(0)):0));
325*2565f573Smarc 			if(w==EFSYM)
326*2565f573Smarc 				return(t);
327*2565f573Smarc 			break;
328*2565f573Smarc 		}
329*2565f573Smarc 
330*2565f573Smarc 		/* for and select statement */
331*2565f573Smarc 		case FORSYM:
332*2565f573Smarc 		case SELSYM:
333*2565f573Smarc 		{
334*2565f573Smarc 			t=(TREPTR) getstak(FORTYPE);
335*2565f573Smarc 			((FORPTR) t)->fortyp=(wdval==FORSYM?TFOR:TSELECT);
336*2565f573Smarc 			((FORPTR) t)->forlst=0;
337*2565f573Smarc 			chkword();
338*2565f573Smarc 			((FORPTR) t)->fornam=(char*) wdarg->argval;
339*2565f573Smarc 			if(skipnl()==INSYM)
340*2565f573Smarc 			{
341*2565f573Smarc 				chkword();
342*2565f573Smarc 				 ((FORPTR) t)->forlst=(COMPTR) item(0);
343*2565f573Smarc 				if(wdval!=NL && wdval!=';')
344*2565f573Smarc 					synbad();
345*2565f573Smarc 				if(wdval==NL)
346*2565f573Smarc 					chkpr(0);
347*2565f573Smarc 				skipnl();
348*2565f573Smarc 			}
349*2565f573Smarc 			/* 'for i;do cmd' is valid syntax */
350*2565f573Smarc 			else if(wdval==';')
351*2565f573Smarc 			{
352*2565f573Smarc 				reserv = 1;
353*2565f573Smarc 				word();
354*2565f573Smarc 			}
355*2565f573Smarc 			chksym(DOSYM|BRSYM);
356*2565f573Smarc 			((FORPTR) t)->fortre=cmd(wdval==DOSYM?ODSYM:KTSYM,NLFLG);
357*2565f573Smarc 			break;
358*2565f573Smarc 		}
359*2565f573Smarc 
360*2565f573Smarc 		/* This is the code for parsing function definitions */
361*2565f573Smarc 		case PROCSYM:
362*2565f573Smarc 		funct_5_2:
363*2565f573Smarc 		{
364*2565f573Smarc 			TREPTR cmdptr;
365*2565f573Smarc 			BLKPTR blokptr;
366*2565f573Smarc 			int savstates = states;
367*2565f573Smarc 			int saveline = firstline;
368*2565f573Smarc 			register FILE *fd = NULL;
369*2565f573Smarc 			IOPTR saviotemp = iotemp;
370*2565f573Smarc 			t=(TREPTR) getstak(PROCTYPE);
371*2565f573Smarc 			((PROCPTR) t)->proctyp=TPROC;
372*2565f573Smarc 			((PROCPTR) t)->procloc = -1;
373*2565f573Smarc 			firstline = standin->flin;
374*2565f573Smarc 			if(wdval == PROCSYM)
375*2565f573Smarc 				chkword();
376*2565f573Smarc 			((PROCPTR) t)->procnam=(char *) wdarg->argval;
377*2565f573Smarc 			skipnl();
378*2565f573Smarc 			chksym(BRSYM);
379*2565f573Smarc 			/* force a new stak frame to compile the command */
380*2565f573Smarc 			addblok(-1);
381*2565f573Smarc 			if(is_option(INTFLG))
382*2565f573Smarc 			{
383*2565f573Smarc 				/* just in case history file not open yet */
384*2565f573Smarc 				hist_open();
385*2565f573Smarc 				if(fc_fix)
386*2565f573Smarc 				{
387*2565f573Smarc 					fd = fc_fix->fixfd;
388*2565f573Smarc 					states |= FIXFLG;
389*2565f573Smarc 					((PROCPTR)t)->procloc =
390*2565f573Smarc 						hist_position(fc_fix->fixind) +
391*2565f573Smarc 						fd->_ptr - fd->_base;
392*2565f573Smarc 				}
393*2565f573Smarc 			}
394*2565f573Smarc 			cmdptr = cmd(KTSYM,NLFLG);
395*2565f573Smarc 			/* force another stak frame to save the command */
396*2565f573Smarc 			addblok(-1);
397*2565f573Smarc 			blokptr = stakbsy;
398*2565f573Smarc 			stakbsy = stakbsy->word;
399*2565f573Smarc 			/* save the entry point in block */
400*2565f573Smarc 			blokptr->word = BLK(cmdptr);
401*2565f573Smarc 			((PROCPTR) t)->proctre = blokptr;
402*2565f573Smarc 			if(iotemp != saviotemp)
403*2565f573Smarc 			{
404*2565f573Smarc 				iotemp = saviotemp;
405*2565f573Smarc 				states |= RM_TMP;
406*2565f573Smarc 			}
407*2565f573Smarc 			if(fd && (savstates&FIXFLG)==0)
408*2565f573Smarc 			{
409*2565f573Smarc 				hist_flush();
410*2565f573Smarc 				hist_cancel();
411*2565f573Smarc 				states &= ~FIXFLG;
412*2565f573Smarc 			}
413*2565f573Smarc 			firstline = saveline;
414*2565f573Smarc 			break;
415*2565f573Smarc 		}
416*2565f573Smarc 
417*2565f573Smarc 		/* while and until */
418*2565f573Smarc 		case WHSYM:
419*2565f573Smarc 		case UNSYM:
420*2565f573Smarc 		{
421*2565f573Smarc 			t=(TREPTR) getstak(WHTYPE);
422*2565f573Smarc 			((WHPTR) t)->whtyp=(wdval==WHSYM ? TWH : TUN);
423*2565f573Smarc 			((WHPTR) t)->whtre = cmd(DOSYM,NLFLG);
424*2565f573Smarc 			((WHPTR) t)->dotre = cmd(ODSYM,NLFLG);
425*2565f573Smarc 			break;
426*2565f573Smarc 		}
427*2565f573Smarc 
428*2565f573Smarc 		/* command group with { */
429*2565f573Smarc 		case BRSYM:
430*2565f573Smarc 			t=cmd(KTSYM,NLFLG);
431*2565f573Smarc 			break;
432*2565f573Smarc 
433*2565f573Smarc 		case '(':
434*2565f573Smarc 		{
435*2565f573Smarc 			register PARPTR	 p;
436*2565f573Smarc 			p=(PARPTR) getstak(PARTYPE);
437*2565f573Smarc 			p->partre=cmd(')',NLFLG);
438*2565f573Smarc 			p->partyp=TPAR;
439*2565f573Smarc 			t=makefork(0,(TREPTR)p);
440*2565f573Smarc 			break;
441*2565f573Smarc 		}
442*2565f573Smarc 
443*2565f573Smarc 		default:
444*2565f573Smarc 			if(io==0)
445*2565f573Smarc 				return(0);
446*2565f573Smarc 
447*2565f573Smarc 		/* simple command */
448*2565f573Smarc 		case 0:
449*2565f573Smarc 		{
450*2565f573Smarc 			register ARGPTR	argp;
451*2565f573Smarc 			register ARGPTR	*argtail;
452*2565f573Smarc 			register ARGPTR	*argset=0;
453*2565f573Smarc 			int 	keywd=KEYFLG;
454*2565f573Smarc 			int	argno = 0;
455*2565f573Smarc 			int bltin = 0;
456*2565f573Smarc 			t=(TREPTR) getstak(COMTYPE);
457*2565f573Smarc 			((COMPTR)t)->comio=io; /*initial io chain*/
458*2565f573Smarc 			/* set command line number for error messages */
459*2565f573Smarc 			((COMPTR)t)->comline = (exec_flag?cmdline:
460*2565f573Smarc 				standin->flin-firstline-1);
461*2565f573Smarc 			argtail = &(((COMPTR)t)->comarg);
462*2565f573Smarc 			while(wdval==0)
463*2565f573Smarc 			{
464*2565f573Smarc 				argp = wdarg;
465*2565f573Smarc 				argp->argchn = 0;
466*2565f573Smarc 				/* test for keyword argument */
467*2565f573Smarc 				if(wdset&keywd)
468*2565f573Smarc 				{
469*2565f573Smarc 					chkflags(argp,0);
470*2565f573Smarc 					argp->argnxt=(ARGPTR) argset;
471*2565f573Smarc 					argset=(ARGPTR *) argp;
472*2565f573Smarc 					/* alias substitutions allowed */
473*2565f573Smarc 					wdset |= (KEYFLG|S_FLAG);
474*2565f573Smarc 				}
475*2565f573Smarc 				else
476*2565f573Smarc 				{
477*2565f573Smarc 					wdset = 0;	/* don't hunt for aliases*/
478*2565f573Smarc 					chkflags(argp,1);
479*2565f573Smarc 					if((argp->argflag&A_RAW) == 0)
480*2565f573Smarc 						argno = -1;
481*2565f573Smarc 					if(argno>=0 && argno++==0)
482*2565f573Smarc 					{
483*2565f573Smarc 						/* check for builtin command */
484*2565f573Smarc 						bltin=syslook(argp->argval,commands);
485*2565f573Smarc 					}
486*2565f573Smarc 					*argtail = argp;
487*2565f573Smarc 					argtail = &(argp->argnxt);
488*2565f573Smarc 					wdset = keywd=is_option(KEYFLG);
489*2565f573Smarc 				}
490*2565f573Smarc #ifdef DEVFD
491*2565f573Smarc 			retry:
492*2565f573Smarc 				word();
493*2565f573Smarc 				if((wdval&STRIP)=='(')
494*2565f573Smarc 				{
495*2565f573Smarc 					TREPTR t;
496*2565f573Smarc 					int flag = (wdval==OPROC);
497*2565f573Smarc 					t = cmd(')',NLFLG|(argno==1&&wdval=='('?MTFLG:0));
498*2565f573Smarc 					if(t == NULL)
499*2565f573Smarc 					{
500*2565f573Smarc 						wdarg = argp;
501*2565f573Smarc 						goto funct_5_2;
502*2565f573Smarc 					}
503*2565f573Smarc 					argp = (ARGPTR)locstak();
504*2565f573Smarc 					argno = -1;
505*2565f573Smarc 					*argtail = argp;
506*2565f573Smarc 					argtail = &(argp->argnxt);
507*2565f573Smarc 					endstak(movstr(nullstr,argp->argval));
508*2565f573Smarc 					argp->argchn = (ARGPTR)makefork(flag?FPIN|FAMP|FPCL:FPOU,t);
509*2565f573Smarc 					argp->argflag =  (A_EXP|flag);
510*2565f573Smarc 					goto retry;
511*2565f573Smarc 				}
512*2565f573Smarc #else
513*2565f573Smarc 				word();
514*2565f573Smarc 				if(argno==1 && argset==NULL && wdval== '(')
515*2565f573Smarc 				{
516*2565f573Smarc 					/* SVR2 style function */
517*2565f573Smarc 					word();
518*2565f573Smarc 					if(wdval == ')')
519*2565f573Smarc 					{
520*2565f573Smarc 						wdarg = argp;
521*2565f573Smarc 						goto funct_5_2;
522*2565f573Smarc 					}
523*2565f573Smarc 					wdval = '(';
524*2565f573Smarc 				}
525*2565f573Smarc #endif	/* DEVFD */
526*2565f573Smarc 				if(flag)
527*2565f573Smarc 				{
528*2565f573Smarc 					if(io)
529*2565f573Smarc 					{
530*2565f573Smarc 						while(io->ionxt)
531*2565f573Smarc 							io = io->ionxt;
532*2565f573Smarc 						io->ionxt = inout((IOPTR)0,0);
533*2565f573Smarc 					}
534*2565f573Smarc 					else
535*2565f573Smarc 						((COMPTR)t)->comio = io = inout((IOPTR)0,0);
536*2565f573Smarc 				}
537*2565f573Smarc 			}
538*2565f573Smarc 			*argtail = 0;
539*2565f573Smarc 			((COMPTR)t)->comtyp = (TCOM|(bltin<<(COMBITS+1)));
540*2565f573Smarc 			/* expand argument list if possible */
541*2565f573Smarc 			if(argno>0)
542*2565f573Smarc 				((COMPTR)t)->comarg = qscan(t,argno);
543*2565f573Smarc 			else if(((COMPTR)t)->comarg)
544*2565f573Smarc 				((COMPTR)t)->comtyp |= COMSCAN;
545*2565f573Smarc 			((COMPTR)t)->comset=(ARGPTR) argset;
546*2565f573Smarc 			wdset &= ~S_FLAG;
547*2565f573Smarc 			return(t);
548*2565f573Smarc 		}
549*2565f573Smarc 	}
550*2565f573Smarc 	reserv++;
551*2565f573Smarc 	word();
552*2565f573Smarc 	if(io=inout(io,0))
553*2565f573Smarc 	{
554*2565f573Smarc 		int type = t->tretyp&COMMSK;
555*2565f573Smarc 		t=makefork(0,t);
556*2565f573Smarc 		t->treio=io;
557*2565f573Smarc 		if(type != TFORK)
558*2565f573Smarc 			t->tretyp = TSETIO;
559*2565f573Smarc 	}
560*2565f573Smarc 	return(t);
561*2565f573Smarc }
562*2565f573Smarc 
563*2565f573Smarc 
564*2565f573Smarc /*
565*2565f573Smarc  * skip past newlines but issue prompt if interactive
566*2565f573Smarc  */
567*2565f573Smarc 
skipnl()568*2565f573Smarc static int	skipnl()
569*2565f573Smarc {
570*2565f573Smarc 	while((reserv++, word()==NL))
571*2565f573Smarc 		chkpr(0);
572*2565f573Smarc 	return(wdval);
573*2565f573Smarc }
574*2565f573Smarc 
575*2565f573Smarc /*
576*2565f573Smarc  * check for and process and i/o redirections
577*2565f573Smarc  * if flag is set then an alias can be in the next word
578*2565f573Smarc  */
579*2565f573Smarc 
inout(lastio,flag)580*2565f573Smarc static IOPTR	inout(lastio,flag)
581*2565f573Smarc IOPTR		lastio;
582*2565f573Smarc {
583*2565f573Smarc 	register int 	iof;
584*2565f573Smarc 	register IOPTR	iop;
585*2565f573Smarc 	register int c;
586*2565f573Smarc 	iof=wdnum;
587*2565f573Smarc 	switch(wdval)
588*2565f573Smarc 	{
589*2565f573Smarc 		case DOCSYM:	/*	<<	*/
590*2565f573Smarc 			iof |= IODOC;
591*2565f573Smarc 			heredoc = FTMP;
592*2565f573Smarc 			break;
593*2565f573Smarc 
594*2565f573Smarc 		case APPSYM:	/*	>>	*/
595*2565f573Smarc 		case '>':
596*2565f573Smarc 			if(wdnum==0)
597*2565f573Smarc 				iof |= 1;
598*2565f573Smarc 			iof |= IOPUT;
599*2565f573Smarc 			if(wdval==APPSYM)
600*2565f573Smarc 			{
601*2565f573Smarc 				iof |= IOAPP;
602*2565f573Smarc 				break;
603*2565f573Smarc 			}
604*2565f573Smarc 
605*2565f573Smarc 		case '<':
606*2565f573Smarc 			if((c=nextc())=='&')
607*2565f573Smarc 				iof |= IOMOV;
608*2565f573Smarc 			else if(c=='>')
609*2565f573Smarc 			/*	<> is open for read and write	*/
610*2565f573Smarc 			/*	unadvertised feature		*/
611*2565f573Smarc 				iof |= IORDW;
612*2565f573Smarc 			else
613*2565f573Smarc 				 peekn=c|MARK;
614*2565f573Smarc 			break;
615*2565f573Smarc 
616*2565f573Smarc 		default:
617*2565f573Smarc 			return(lastio);
618*2565f573Smarc 	}
619*2565f573Smarc 	chkword();
620*2565f573Smarc 	iop=(IOPTR) getstak(IOTYPE);
621*2565f573Smarc 	iop->ioname=wdarg->argval;
622*2565f573Smarc 	iop->iofile=iof;
623*2565f573Smarc 	if(iof&IODOC)
624*2565f573Smarc 	{
625*2565f573Smarc 		iop->iolst=iopend;
626*2565f573Smarc 		iopend=iop;
627*2565f573Smarc 	}
628*2565f573Smarc 	word();
629*2565f573Smarc 	iop->ionxt=inout(lastio,0);
630*2565f573Smarc 	/* allow alias substitutions */
631*2565f573Smarc 	if(flag)
632*2565f573Smarc 		wdset |= S_FLAG;
633*2565f573Smarc 	return(iop);
634*2565f573Smarc }
635*2565f573Smarc 
636*2565f573Smarc /*
637*2565f573Smarc  * get next token and make sure that it is not a keyword or meta-character
638*2565f573Smarc  */
639*2565f573Smarc 
chkword()640*2565f573Smarc static void	chkword()
641*2565f573Smarc {
642*2565f573Smarc 	if(word())
643*2565f573Smarc 		synbad();
644*2565f573Smarc }
645*2565f573Smarc 
646*2565f573Smarc /*
647*2565f573Smarc  * see if this token is syntactically correct
648*2565f573Smarc  */
649*2565f573Smarc 
chksym(sym)650*2565f573Smarc static void	chksym(sym)
651*2565f573Smarc register int sym;
652*2565f573Smarc {
653*2565f573Smarc 	register int 	x = sym&wdval;
654*2565f573Smarc 	if(((x&SYMFLG) ? x : sym) != wdval)
655*2565f573Smarc 		synbad();
656*2565f573Smarc }
657*2565f573Smarc 
658*2565f573Smarc /*
659*2565f573Smarc  * print the name of a syntactic token
660*2565f573Smarc  */
661*2565f573Smarc 
prsym(sym)662*2565f573Smarc static void	prsym(sym)
663*2565f573Smarc register int sym;
664*2565f573Smarc {
665*2565f573Smarc 	if(sym&SYMFLG)
666*2565f573Smarc 	{
667*2565f573Smarc 		register SYSPTR	sp=reserved;
668*2565f573Smarc 		while(sp->sysval && sp->sysval!=sym)
669*2565f573Smarc 			sp++;
670*2565f573Smarc 		fputs(sp->sysnam,output);
671*2565f573Smarc 	}
672*2565f573Smarc 	else if(sym==EOFSYM)
673*2565f573Smarc 		fputs(endoffile,output);
674*2565f573Smarc 	else
675*2565f573Smarc 	{
676*2565f573Smarc 		if(sym&SYMREP)
677*2565f573Smarc 			putc(sym,output);
678*2565f573Smarc 		if(sym==NL)
679*2565f573Smarc 			fputs("newline or ;",output);
680*2565f573Smarc 		else
681*2565f573Smarc 			putc(sym,output);
682*2565f573Smarc 	}
683*2565f573Smarc 	putc('\'',output);
684*2565f573Smarc }
685*2565f573Smarc 
686*2565f573Smarc /*
687*2565f573Smarc  * print a bad syntax message
688*2565f573Smarc  */
689*2565f573Smarc 
synbad()690*2565f573Smarc void	synbad()
691*2565f573Smarc {
692*2565f573Smarc 	register char *cp = unexpected;
693*2565f573Smarc 	register int w = wdval;
694*2565f573Smarc 	p_setout(stderr);
695*2565f573Smarc 	p_prp(synmsg,0);
696*2565f573Smarc 	if((states&TTYFLG)==0)
697*2565f573Smarc 	{
698*2565f573Smarc 		fputs(atline,output);
699*2565f573Smarc 		p_num((int)standin->flin,SP);
700*2565f573Smarc 	}
701*2565f573Smarc 	p_str(colon,'`');
702*2565f573Smarc 	if(w)
703*2565f573Smarc 		prsym(w);
704*2565f573Smarc 	else
705*2565f573Smarc 		p_str(wdarg->argval,'\'');
706*2565f573Smarc 	if((w&EOFSYM) && w!=EOFSYM)
707*2565f573Smarc 		cp = unmatched;
708*2565f573Smarc 	p_str(cp,NL);
709*2565f573Smarc 	hist_flush();
710*2565f573Smarc 	exitsh(SYNBAD);
711*2565f573Smarc }
712*2565f573Smarc 
713*2565f573Smarc /*
714*2565f573Smarc  * check argument for possible optimizations
715*2565f573Smarc  * in many cases we can skip macro and file name expansion
716*2565f573Smarc  * The fexp flag is set when file expansion is possible
717*2565f573Smarc  */
718*2565f573Smarc 
719*2565f573Smarc #define EXP_MACRO	2	/* macro expansion needed */
720*2565f573Smarc #define EXP_TRIM	4	/* quoted characters in string */
721*2565f573Smarc #define EXP_FILE	8	/* file expansion characters*/
722*2565f573Smarc #define EXP_QUOTE	16	/* string contains " character */
723*2565f573Smarc 
chkflags(argp,fexp)724*2565f573Smarc static void chkflags(argp,fexp)
725*2565f573Smarc register ARGPTR argp;
726*2565f573Smarc {
727*2565f573Smarc 	register int c;
728*2565f573Smarc 	argp->argflag = 0;
729*2565f573Smarc 	{
730*2565f573Smarc 		register int flag = 0;
731*2565f573Smarc 		char nquote = 0;
732*2565f573Smarc 		char *sp=argp->argval;
733*2565f573Smarc 		while(c= *sp++)
734*2565f573Smarc 		{
735*2565f573Smarc 			if(c==ESCAPE)
736*2565f573Smarc 			{
737*2565f573Smarc 				flag |= EXP_TRIM;
738*2565f573Smarc 				sp++;
739*2565f573Smarc 			}
740*2565f573Smarc 			else if(isexp(c))
741*2565f573Smarc 			{
742*2565f573Smarc 				if(c == '$' || c == '`')
743*2565f573Smarc 				{
744*2565f573Smarc 					flag |= EXP_MACRO;
745*2565f573Smarc 					if(c=='`')
746*2565f573Smarc 						subflag++;
747*2565f573Smarc 				}
748*2565f573Smarc 				else if(nquote==0)
749*2565f573Smarc 				{
750*2565f573Smarc 					/* special case of '[' */
751*2565f573Smarc 					if(*sp || c!='[')
752*2565f573Smarc 						flag |= EXP_FILE;
753*2565f573Smarc 				}
754*2565f573Smarc 			}
755*2565f573Smarc 			else if(c == '"')
756*2565f573Smarc 			{
757*2565f573Smarc 				/* toggle the quote count */
758*2565f573Smarc 				nquote = 1 - nquote;
759*2565f573Smarc 				flag |= EXP_QUOTE;
760*2565f573Smarc 			}
761*2565f573Smarc 		}
762*2565f573Smarc 		if(fexp==0)
763*2565f573Smarc 			flag &= ~EXP_FILE;
764*2565f573Smarc 		/* return if no macro expansion, file expansion or trimming required */
765*2565f573Smarc 		if(flag==0)
766*2565f573Smarc 		{
767*2565f573Smarc 			argp->argflag |= A_RAW;
768*2565f573Smarc 			return;
769*2565f573Smarc 		}
770*2565f573Smarc 		/* return if macro or command substitution needed */
771*2565f573Smarc 		if(flag&EXP_MACRO)
772*2565f573Smarc 		{
773*2565f573Smarc 			argp->argflag |= (A_MAC|A_EXP);
774*2565f573Smarc 			return;
775*2565f573Smarc 		}
776*2565f573Smarc 		/* check to see if file expansion is required */
777*2565f573Smarc 		if(flag&EXP_FILE)
778*2565f573Smarc 		{
779*2565f573Smarc 			argp->argflag|= A_EXP;
780*2565f573Smarc 			/* return if no quotes otherwise don't optimize */
781*2565f573Smarc 			if(flag&(EXP_QUOTE|EXP_TRIM))
782*2565f573Smarc 			{
783*2565f573Smarc 				argp->argflag= A_MAC;
784*2565f573Smarc 				return;
785*2565f573Smarc 			}
786*2565f573Smarc 			return;
787*2565f573Smarc 		}
788*2565f573Smarc 		argp->argflag |= A_RAW;
789*2565f573Smarc 	}
790*2565f573Smarc 	/* just get rid of quoting stuff and consider argument as expanded */
791*2565f573Smarc 	{
792*2565f573Smarc 		register char *dp,*sp;
793*2565f573Smarc 		char nquote = 0;	/* set within quoted string */
794*2565f573Smarc 		dp = sp =  argp->argval;
795*2565f573Smarc 		while(c= *sp++)
796*2565f573Smarc 		{
797*2565f573Smarc 			if(c != '"')
798*2565f573Smarc 			{
799*2565f573Smarc 				if(c==ESCAPE)
800*2565f573Smarc 				{
801*2565f573Smarc 					/* strip escchar's in double quotes */
802*2565f573Smarc 					c = *sp++;
803*2565f573Smarc 					if(nquote && !escchar(c) && c!='"')
804*2565f573Smarc 						*dp++ = ESCAPE;
805*2565f573Smarc 				}
806*2565f573Smarc 				*dp++ = c;
807*2565f573Smarc 			}
808*2565f573Smarc 			else	/* toggle quote marker */
809*2565f573Smarc 				nquote = 1-nquote;
810*2565f573Smarc 		}
811*2565f573Smarc 		*dp = 0;
812*2565f573Smarc 	}
813*2565f573Smarc }
814*2565f573Smarc 
815*2565f573Smarc /*
816*2565f573Smarc  * convert argument chain to argument list when no special arguments
817*2565f573Smarc  */
818*2565f573Smarc 
qscan(ac,argn)819*2565f573Smarc static ARGPTR qscan(ac,argn)
820*2565f573Smarc COMPTR	ac;
821*2565f573Smarc int argn;
822*2565f573Smarc {
823*2565f573Smarc 	register char **cp;
824*2565f573Smarc 	register ARGPTR ap;
825*2565f573Smarc 	register DOLPTR dp;
826*2565f573Smarc 	/* leave space for an extra argument at the front */
827*2565f573Smarc 	dp = (DOLPTR)getstak((unsigned)DOLTYPE + sizeof(char*) + argn*sizeof(char*));
828*2565f573Smarc 	cp = dp->dolarg+1;
829*2565f573Smarc 	dp->doluse = argn;
830*2565f573Smarc 	ap = ac->comarg;
831*2565f573Smarc 	while(ap)
832*2565f573Smarc 	{
833*2565f573Smarc 		*cp++ = ap->argval;
834*2565f573Smarc 		ap = ap->argnxt;
835*2565f573Smarc 	}
836*2565f573Smarc 	*cp = NULL;
837*2565f573Smarc 	return((ARGPTR)dp);
838*2565f573Smarc }
839*2565f573Smarc 
840