xref: /original-bsd/old/sh/cmd.c (revision e59fb703)
1 #ifndef lint
2 static char sccsid[] = "@(#)cmd.c	4.3 04/24/88";
3 #endif
4 
5 #
6 /*
7  * UNIX shell
8  *
9  * S. R. Bourne
10  * Bell Telephone Laboratories
11  *
12  */
13 
14 #include	"defs.h"
15 #include	"sym.h"
16 
17 PROC IOPTR	inout();
18 PROC VOID	chkword();
19 PROC VOID	chksym();
20 PROC TREPTR	term();
21 PROC TREPTR	makelist();
22 PROC TREPTR	list();
23 PROC REGPTR	syncase();
24 PROC TREPTR	item();
25 PROC VOID	skipnl();
26 PROC VOID	prsym();
27 PROC VOID	synbad();
28 
29 
30 /* ========	command line decoding	========*/
31 
32 
33 
34 
35 TREPTR	makefork(flgs, i)
36 	INT		flgs;
37 	TREPTR		i;
38 {
39 	REG TREPTR	t;
40 
41 	t=getstak(FORKTYPE);
42 	t->forknod.forktyp=flgs|TFORK;
43 	t->forknod.forktre=i;
44 	t->forknod.forkio=0;
45 	return(t);
46 }
47 
48 LOCAL TREPTR	makelist(type,i,r)
49 	INT		type;
50 	TREPTR		i, r;
51 {
52 	REG TREPTR	t;
53 
54 	IF i==0 ORF r==0
55 	THEN	synbad();
56 	ELSE	t = getstak(LSTTYPE);
57 		t->lstnod.lsttyp = type;
58 		t->lstnod.lstlef = i;
59 		t->lstnod.lstrit = r;
60 	FI
61 	return(t);
62 }
63 
64 /*
65  * cmd
66  *	empty
67  *	list
68  *	list & [ cmd ]
69  *	list [ ; cmd ]
70  */
71 
72 TREPTR	cmd(sym,flg)
73 	REG INT		sym;
74 	INT		flg;
75 {
76 	REG TREPTR	i, e;
77 
78 	i = list(flg);
79 
80 	IF wdval==NL
81 	THEN	IF flg&NLFLG
82 		THEN	wdval=';'; chkpr(NL);
83 		FI
84 	ELIF i==0 ANDF (flg&MTFLG)==0
85 	THEN	synbad();
86 	FI
87 
88 	SWITCH wdval IN
89 
90 	    case '&':
91 		IF i
92 		THEN	i = makefork(FINT|FPRS|FAMP, i);
93 		ELSE	synbad();
94 		FI
95 
96 	    case ';':
97 		IF e=cmd(sym,flg|MTFLG)
98 		THEN	i=makelist(TLST, i, e);
99 		FI
100 		break;
101 
102 	    case EOFSYM:
103 		IF sym==NL
104 		THEN	break;
105 		FI
106 
107 	    default:
108 		IF sym
109 		THEN	chksym(sym);
110 		FI
111 
112 	ENDSW
113 	return(i);
114 }
115 
116 /*
117  * list
118  *	term
119  *	list && term
120  *	list || term
121  */
122 
123 LOCAL TREPTR	list(flg)
124 {
125 	REG TREPTR	r;
126 	REG INT		b;
127 
128 	r = term(flg);
129 	WHILE r ANDF ((b=(wdval==ANDFSYM)) ORF wdval==ORFSYM)
130 	DO	r = makelist((b ? TAND : TORF), r, term(NLFLG));
131 	OD
132 	return(r);
133 }
134 
135 /*
136  * term
137  *	item
138  *	item |^ term
139  */
140 
141 LOCAL TREPTR	term(flg)
142 {
143 	REG TREPTR	t;
144 
145 	reserv++;
146 	IF flg&NLFLG
147 	THEN	skipnl();
148 	ELSE	word();
149 	FI
150 
151 	IF (t=item(TRUE)) ANDF (wdval=='^' ORF wdval=='|')
152 	THEN	return(makelist(TFIL, makefork(FPOU,t), makefork(FPIN|FPCL,term(NLFLG))));
153 	ELSE	return(t);
154 	FI
155 }
156 
157 LOCAL REGPTR	syncase(esym)
158 	REG INT	esym;
159 {
160 	skipnl();
161 	IF wdval==esym
162 	THEN	return(0);
163 	ELSE	REG REGPTR	r=getstak(REGTYPE);
164 		r->regptr=0;
165 		LOOP wdarg->argnxt=r->regptr;
166 		     r->regptr=wdarg;
167 		     IF wdval ORF ( word()!=')' ANDF wdval!='|' )
168 		     THEN synbad();
169 		     FI
170 		     IF wdval=='|'
171 		     THEN word();
172 		     ELSE break;
173 		     FI
174 		POOL
175 		r->regcom=cmd(0,NLFLG|MTFLG);
176 		IF wdval==ECSYM
177 		THEN	r->regnxt=syncase(esym);
178 		ELSE	chksym(esym);
179 			r->regnxt=0;
180 		FI
181 		return(r);
182 	FI
183 }
184 
185 /*
186  * item
187  *
188  *	( cmd ) [ < in  ] [ > out ]
189  *	word word* [ < in ] [ > out ]
190  *	if ... then ... else ... fi
191  *	for ... while ... do ... done
192  *	case ... in ... esac
193  *	begin ... end
194  */
195 
196 LOCAL TREPTR	item(flag)
197 	BOOL		flag;
198 {
199 	REG TREPTR	t;
200 	REG IOPTR	io;
201 
202 	IF flag
203 	THEN	io=inout((IOPTR)0);
204 	ELSE	io=0;
205 	FI
206 
207 	SWITCH wdval IN
208 
209 	    case CASYM:
210 		BEGIN
211 		   t=getstak(SWTYPE);
212 		   chkword();
213 		   t->swnod.swarg=wdarg->argval;
214 		   skipnl(); chksym(INSYM|BRSYM);
215 		   t->swnod.swlst=syncase(wdval==INSYM?ESSYM:KTSYM);
216 		   t->swnod.swtyp=TSW;
217 		   break;
218 		END
219 
220 	    case IFSYM:
221 		BEGIN
222 		   REG INT	w;
223 		   t=getstak(IFTYPE);
224 		   t->ifnod.iftyp=TIF;
225 		   t->ifnod.iftre=cmd(THSYM,NLFLG);
226 		   t->ifnod.thtre=cmd(ELSYM|FISYM|EFSYM,NLFLG);
227 		   t->ifnod.eltre=((w=wdval)==ELSYM ? cmd(FISYM,NLFLG) : (w==EFSYM ? (wdval=IFSYM, item(0)) : 0));
228 		   IF w==EFSYM THEN return(t) FI
229 		   break;
230 		END
231 
232 	    case FORSYM:
233 		BEGIN
234 		   t=getstak(FORTYPE);
235 		   t->fornod.fortyp=TFOR;
236 		   t->fornod.forlst=0;
237 		   chkword();
238 		   t->fornod.fornam=wdarg->argval;
239 		   IF skipnl()==INSYM
240 		   THEN	chkword();
241 			t->fornod.forlst=item(0);
242 			IF wdval!=NL ANDF wdval!=';'
243 			THEN	synbad();
244 			FI
245 			chkpr(wdval); skipnl();
246 		   FI
247 		   chksym(DOSYM|BRSYM);
248 		   t->fornod.fortre=cmd(wdval==DOSYM?ODSYM:KTSYM,NLFLG);
249 		   break;
250 		END
251 
252 	    case WHSYM:
253 	    case UNSYM:
254 		BEGIN
255 		   t=getstak(WHTYPE);
256 		   t->whnod.whtyp=(wdval==WHSYM ? TWH : TUN);
257 		   t->whnod.whtre = cmd(DOSYM,NLFLG);
258 		   t->whnod.dotre = cmd(ODSYM,NLFLG);
259 		   break;
260 		END
261 
262 	    case BRSYM:
263 		t=cmd(KTSYM,NLFLG);
264 		break;
265 
266 	    case '(':
267 		BEGIN
268 		   REG PARPTR	 p;
269 		   p=getstak(PARTYPE);
270 		   p->partre=cmd(')',NLFLG);
271 		   p->partyp=TPAR;
272 		   t=makefork(0,p);
273 		   break;
274 		END
275 
276 	    default:
277 		IF io==0
278 		THEN	return(0);
279 		FI
280 
281 	    case 0:
282 		BEGIN
283 		   REG ARGPTR	argp;
284 		   REG ARGPTR	*argtail;
285 		   REG ARGPTR	*argset=0;
286 		   INT		keywd=1;
287 		   t=getstak(COMTYPE);
288 		   t->comnod.comio=io; /*initial io chain*/
289 		   argtail = &(t->comnod.comarg);
290 		   WHILE wdval==0
291 		   DO	argp = wdarg;
292 			IF wdset ANDF keywd
293 			THEN	argp->argnxt=argset; argset=argp;
294 			ELSE	*argtail=argp; argtail = &(argp->argnxt); keywd=flags&keyflg;
295 			FI
296 			word();
297 			IF flag
298 			THEN t->comnod.comio=inout(t->comnod.comio);
299 			FI
300 		   OD
301 
302 		   t->comnod.comtyp=TCOM; t->comnod.comset=argset; *argtail=0;
303 		   return(t);
304 		END
305 
306 	ENDSW
307 	reserv++; word();
308 	IF io=inout(io)
309 	THEN	t=makefork(0,t); t->treio.treio=io;
310 	FI
311 	return(t);
312 }
313 
314 
315 LOCAL VOID	skipnl()
316 {
317 	WHILE (reserv++, word()==NL) DO chkpr(NL) OD
318 	return(wdval);
319 }
320 
321 LOCAL IOPTR	inout(lastio)
322 	IOPTR		lastio;
323 {
324 	REG INT		iof;
325 	REG IOPTR	iop;
326 	REG CHAR	c;
327 
328 	iof=wdnum;
329 
330 	SWITCH wdval IN
331 
332 	    case DOCSYM:
333 		iof |= IODOC; break;
334 
335 	    case APPSYM:
336 	    case '>':
337 		IF wdnum==0 THEN iof |= 1 FI
338 		iof |= IOPUT;
339 		IF wdval==APPSYM
340 		THEN	iof |= IOAPP; break;
341 		FI
342 
343 	    case '<':
344 		IF (c=nextc(0))=='&'
345 		THEN	iof |= IOMOV;
346 		ELIF c=='>'
347 		THEN	iof |= IORDW;
348 		ELSE	peekc=c|MARK;
349 		FI
350 		break;
351 
352 	    default:
353 		return(lastio);
354 	ENDSW
355 
356 	chkword();
357 	iop=getstak(IOTYPE); iop->ioname=wdarg->argval; iop->iofile=iof;
358 	IF iof&IODOC
359 	THEN iop->iolst=iopend; iopend=iop;
360 	FI
361 	word(); iop->ionxt=inout(lastio);
362 	return(iop);
363 }
364 
365 LOCAL VOID	chkword()
366 {
367 	IF word()
368 	THEN	synbad();
369 	FI
370 }
371 
372 LOCAL VOID	chksym(sym)
373 {
374 	REG INT		x = sym&wdval;
375 	IF ((x&SYMFLG) ? x : sym) != wdval
376 	THEN	synbad();
377 	FI
378 }
379 
380 LOCAL VOID	prsym(sym)
381 {
382 	IF sym&SYMFLG
383 	THEN	REG SYSPTR	sp=reserved;
384 		WHILE sp->sysval
385 			ANDF sp->sysval!=sym
386 		DO sp++ OD
387 		prs(sp->sysnam);
388 	ELIF sym==EOFSYM
389 	THEN	prs(endoffile);
390 	ELSE	IF sym&SYMREP THEN prc(sym) FI
391 		IF sym==NL
392 		THEN	prs("newline");
393 		ELSE	prc(sym);
394 		FI
395 	FI
396 }
397 
398 LOCAL VOID	synbad()
399 {
400 	prp(); prs(synmsg);
401 	IF (flags&ttyflg)==0
402 	THEN	prs(atline); prn(standin->flin);
403 	FI
404 	prs(colon);
405 	prc(LQ);
406 	IF wdval
407 	THEN	prsym(wdval);
408 	ELSE	prs(wdarg->argval);
409 	FI
410 	prc(RQ); prs(unexpected);
411 	newline();
412 	exitsh(SYNBAD);
413 }
414