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