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