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