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