xref: /illumos-gate/usr/src/cmd/sh/cmd.c (revision cc6c5292fa8a241fe50604cf6a918edfbf7cd7d2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 /*
33  * UNIX shell
34  */
35 
36 #include	"defs.h"
37 #include	"sym.h"
38 
39 static struct ionod *	inout();
40 static void	chkword(void);
41 static void	chksym(int);
42 static struct trenod *	term();
43 static struct trenod *	makelist();
44 static struct trenod *	list();
45 static struct regnod *	syncase();
46 static struct trenod *	item();
47 static int	skipnl();
48 static void	prsym(int);
49 static void	synbad(void);
50 
51 
52 /* ======== storage allocation for functions ======== */
53 
54 unsigned char *
55 getstor(asize)
56 	int asize;
57 {
58 	if (fndef)
59 		return((unsigned char *)alloc(asize));
60 	else
61 		return(getstak(asize));
62 }
63 
64 
65 /* ========	command line decoding	========*/
66 
67 
68 
69 
70 struct trenod *
71 makefork(flgs, i)
72 	int	flgs;
73 	struct trenod *i;
74 {
75 	struct forknod *t;
76 
77 	t = (struct forknod *)getstor(sizeof(struct forknod));
78 	t->forktyp = flgs|TFORK;
79 	t->forktre = i;
80 	t->forkio = 0;
81 	return((struct trenod *)t);
82 }
83 
84 static struct trenod *
85 makelist(type, i, r)
86 	int	type;
87 	struct trenod *i, *r;
88 {
89 	struct lstnod *t;
90 
91 	if (i == 0 || r == 0)
92 		synbad();
93 	else
94 	{
95 		t = (struct lstnod *)getstor(sizeof(struct lstnod));
96 		t->lsttyp = type;
97 		t->lstlef = i;
98 		t->lstrit = r;
99 	}
100 	return((struct trenod *)t);
101 }
102 
103 /*
104  * cmd
105  *	empty
106  *	list
107  *	list & [ cmd ]
108  *	list [ ; cmd ]
109  */
110 struct trenod *
111 cmd(sym, flg)
112 	int	sym;
113 	int		flg;
114 {
115 	struct trenod *i, *e;
116 	i = list(flg);
117 	if (wdval == NL)
118 	{
119 		if (flg & NLFLG)
120 		{
121 			wdval = ';';
122 			chkpr();
123 		}
124 	}
125 	else if (i == 0 && (flg & MTFLG) == 0)
126 		synbad();
127 
128 	switch (wdval)
129 	{
130 	case '&':
131 		if (i)
132 			i = makefork(FAMP, i);
133 		else
134 			synbad();
135 
136 	case ';':
137 		if (e = cmd(sym, flg | MTFLG))
138 			i = makelist(TLST, i, e);
139 		else if (i == 0)
140 			synbad();
141 		break;
142 
143 	case EOFSYM:
144 		if (sym == NL)
145 			break;
146 
147 	default:
148 		if (sym)
149 			chksym(sym);
150 	}
151 	return(i);
152 }
153 
154 /*
155  * list
156  *	term
157  *	list && term
158  *	list || term
159  */
160 static struct trenod *
161 list(flg)
162 {
163 	struct trenod *r;
164 	int		b;
165 	r = term(flg);
166 	while (r && ((b = (wdval == ANDFSYM)) || wdval == ORFSYM))
167 		r = makelist((b ? TAND : TORF), r, term(NLFLG));
168 	return(r);
169 }
170 
171 /*
172  * term
173  *	item
174  *	item |^ term
175  */
176 static struct trenod *
177 term(flg)
178 {
179 	struct trenod *t;
180 
181 	reserv++;
182 	if (flg & NLFLG)
183 		skipnl();
184 	else
185 		word();
186 	if ((t = item(TRUE)) && (wdval == '^' || wdval == '|'))
187 	{
188 		struct trenod	*left;
189 		struct trenod	*right;
190 
191 		left = makefork(FPOU, t);
192 		right = makefork(FPIN, term(NLFLG));
193 		return(makefork(0, makelist(TFIL, left, right)));
194 	}
195 	else
196 		return(t);
197 }
198 
199 
200 static struct regnod *
201 syncase(esym)
202 int	esym;
203 {
204 	skipnl();
205 	if (wdval == esym)
206 		return(0);
207 	else
208 	{
209 		struct regnod *r =
210 		    (struct regnod *)getstor(sizeof (struct regnod));
211 		struct argnod *argp;
212 
213 		r->regptr = 0;
214 		for (;;)
215 		{
216 			if (fndef)
217 			{
218 				argp= wdarg;
219 				wdarg = (struct argnod *)alloc(length(argp->argval) + BYTESPERWORD);
220 				movstr(argp->argval, wdarg->argval);
221 			}
222 
223 			wdarg->argnxt = r->regptr;
224 			r->regptr = wdarg;
225 
226 			/* 'in' is not a reserved word in this case */
227 			if (wdval == INSYM){
228 				wdval = 0;
229 			}
230 			if (wdval || (word() != ')' && wdval != '|'))
231 				synbad();
232 			if (wdval == '|')
233 				word();
234 			else
235 				break;
236 		}
237 		r->regcom = cmd(0, NLFLG | MTFLG);
238 		if (wdval == ECSYM)
239 			r->regnxt = syncase(esym);
240 		else
241 		{
242 			chksym(esym);
243 			r->regnxt = 0;
244 		}
245 		return(r);
246 	}
247 }
248 
249 /*
250  * item
251  *
252  *	( cmd ) [ < in  ] [ > out ]
253  *	word word* [ < in ] [ > out ]
254  *	if ... then ... else ... fi
255  *	for ... while ... do ... done
256  *	case ... in ... esac
257  *	begin ... end
258  */
259 static struct trenod *
260 item(flag)
261 	BOOL	flag;
262 {
263 	struct trenod *r;
264 	struct ionod *io;
265 
266 	if (flag)
267 		io = inout((struct ionod *)0);
268 	else
269 		io = 0;
270 	switch (wdval)
271 	{
272 	case CASYM:
273 		{
274 			struct swnod *t;
275 
276 			t = (struct swnod *)getstor(sizeof(struct swnod));
277 			r = (struct trenod *)t;
278 
279 			chkword();
280 			if (fndef)
281 				t->swarg = make(wdarg->argval);
282 			else
283 				t->swarg = wdarg->argval;
284 			skipnl();
285 			chksym(INSYM | BRSYM);
286 			t->swlst = syncase(wdval == INSYM ? ESSYM : KTSYM);
287 			t->swtyp = TSW;
288 			break;
289 		}
290 
291 	case IFSYM:
292 		{
293 			int	w;
294 			struct ifnod *t;
295 
296 			t = (struct ifnod *)getstor(sizeof(struct ifnod));
297 			r = (struct trenod *)t;
298 
299 			t->iftyp = TIF;
300 			t->iftre = cmd(THSYM, NLFLG);
301 			t->thtre = cmd(ELSYM | FISYM | EFSYM, NLFLG);
302 			t->eltre = ((w = wdval) == ELSYM ? cmd(FISYM, NLFLG) : (w == EFSYM ? (wdval = IFSYM, item(0)) : 0));
303 			if (w == EFSYM)
304 				return(r);
305 			break;
306 		}
307 
308 	case FORSYM:
309 		{
310 			struct fornod *t;
311 
312 			t = (struct fornod *)getstor(sizeof(struct fornod));
313 			r = (struct trenod *)t;
314 
315 			t->fortyp = TFOR;
316 			t->forlst = 0;
317 			chkword();
318 			if (fndef)
319 				t->fornam = make(wdarg->argval);
320 			else
321 				t->fornam = wdarg->argval;
322 			if (skipnl() == INSYM)
323 			{
324 				chkword();
325 
326 				nohash++;
327 				t->forlst = (struct comnod *)item(0);
328 				nohash--;
329 
330 				if (wdval != NL && wdval != ';')
331 					synbad();
332 				if (wdval == NL)
333 					chkpr();
334 				skipnl();
335 			}
336 			chksym(DOSYM | BRSYM);
337 			t->fortre = cmd(wdval == DOSYM ? ODSYM : KTSYM, NLFLG);
338 			break;
339 		}
340 
341 	case WHSYM:
342 	case UNSYM:
343 		{
344 			struct whnod *t;
345 
346 			t = (struct whnod *)getstor(sizeof(struct whnod));
347 			r = (struct trenod *)t;
348 
349 			t->whtyp = (wdval == WHSYM ? TWH : TUN);
350 			t->whtre = cmd(DOSYM, NLFLG);
351 			t->dotre = cmd(ODSYM, NLFLG);
352 			break;
353 		}
354 
355 	case BRSYM:
356 		r = cmd(KTSYM, NLFLG);
357 		break;
358 
359 	case '(':
360 		{
361 			struct parnod *p;
362 
363 			p = (struct parnod *)getstor(sizeof(struct parnod));
364 			p->partre = cmd(')', NLFLG);
365 			p->partyp = TPAR;
366 			r = makefork(0, p);
367 			break;
368 		}
369 
370 	default:
371 		if (io == 0)
372 			return(0);
373 
374 	case 0:
375 		{
376 			struct comnod *t;
377 			struct argnod *argp;
378 			struct argnod **argtail;
379 			struct argnod **argset = 0;
380 			int	keywd = 1;
381 			unsigned char	*com;
382 
383 			if ((wdval != NL) && ((peekn = skipwc()) == '('))
384 			{
385 				struct fndnod *f;
386 				struct ionod  *saveio;
387 
388 				saveio = iotemp;
389 				peekn = 0;
390 				if (skipwc() != ')')
391 					synbad();
392 
393 				f = (struct fndnod *)getstor(sizeof(struct fndnod));
394 				r = (struct trenod *)f;
395 
396 				f->fndtyp = TFND;
397 				if (fndef)
398 					f->fndnam = make(wdarg->argval);
399 				else
400 					f->fndnam = wdarg->argval;
401 				reserv++;
402 				fndef++;
403 				skipnl();
404 				f->fndval = (struct trenod *)item(0);
405 				fndef--;
406 
407 				if (iotemp != saveio)
408 				{
409 					struct ionod 	*ioptr = iotemp;
410 
411 					while (ioptr->iolst != saveio)
412 						ioptr = ioptr->iolst;
413 
414 					ioptr->iolst = fiotemp;
415 					fiotemp = iotemp;
416 					iotemp = saveio;
417 				}
418 				return(r);
419 			}
420 			else
421 			{
422 				t = (struct comnod *)getstor(sizeof(struct comnod));
423 				r = (struct trenod *)t;
424 
425 				t->comio = io; /*initial io chain*/
426 				argtail = &(t->comarg);
427 
428 				while (wdval == 0)
429 				{
430 					if (fndef)
431 					{
432 						argp = wdarg;
433 						wdarg = (struct argnod *)alloc(length(argp->argval) + BYTESPERWORD);
434 						movstr(argp->argval, wdarg->argval);
435 					}
436 
437 					argp = wdarg;
438 					if (wdset && keywd)
439 					{
440 						argp->argnxt = (struct argnod *)argset;
441 						argset = (struct argnod **)argp;
442 					}
443 					else
444 					{
445 						*argtail = argp;
446 						argtail = &(argp->argnxt);
447 						keywd = flags & keyflg;
448 					}
449 					word();
450 					if (flag)
451 					{
452 						if (io)
453 						{
454 							while(io->ionxt)
455 								io = io->ionxt;
456 							io->ionxt = inout((struct ionod *)0);
457 						}
458 						else
459 							t->comio = io = inout((struct ionod *)0);
460  					}
461 				}
462 
463 				t->comtyp = TCOM;
464 				t->comset = (struct argnod *)argset;
465 				*argtail = 0;
466 
467 				if (nohash == 0 && (fndef == 0 || (flags & hashflg)))
468 				{
469 					if (t->comarg)
470 					{
471 						com = t->comarg->argval;
472 						if (*com && *com != DOLLAR)
473 							pathlook(com, 0, t->comset);
474 					}
475 				}
476 
477 				return(r);
478 			}
479 		}
480 
481 	}
482 	reserv++;
483 	word();
484 	if (io = inout(io))
485 	{
486 		r = makefork(0,r);
487 		r->treio = io;
488 	}
489 	return(r);
490 }
491 
492 
493 static int
494 skipnl()
495 {
496 	while ((reserv++, word() == NL))
497 		chkpr();
498 	return(wdval);
499 }
500 
501 static struct ionod *
502 inout(lastio)
503 	struct ionod *lastio;
504 {
505 	int	iof;
506 	struct ionod *iop;
507 	unsigned int	c;
508 
509 	iof = wdnum;
510 	switch (wdval)
511 	{
512 	case DOCSYM:	/*	<<	*/
513 		iof |= IODOC;
514 		break;
515 
516 	case APPSYM:	/*	>>	*/
517 	case '>':
518 		if (wdnum == 0)
519 			iof |= 1;
520 		iof |= IOPUT;
521 		if (wdval == APPSYM)
522 		{
523 			iof |= IOAPP;
524 			break;
525 		}
526 
527 	case '<':
528 		if ((c = nextwc()) == '&')
529 			iof |= IOMOV;
530 		else if (c == '>')
531 			iof |= IORDW;
532 		else
533 			peekn = c | MARK;
534 		break;
535 
536 	default:
537 		return(lastio);
538 	}
539 
540 	chkword();
541 	iop = (struct ionod *)getstor(sizeof(struct ionod));
542 
543 	if (fndef)
544 		iop->ioname = (char *) make(wdarg->argval);
545 	else
546 		iop->ioname = (char *) (wdarg->argval);
547 
548 	iop->iolink = 0;
549 	iop->iofile = iof;
550 	if (iof & IODOC)
551 	{
552 		iop->iolst = iopend;
553 		iopend = iop;
554 	}
555 	word();
556 	iop->ionxt = inout(lastio);
557 	return(iop);
558 }
559 
560 static void
561 chkword(void)
562 {
563 	if (word())
564 		synbad();
565 }
566 
567 static void
568 chksym(int sym)
569 {
570 	int	x = sym & wdval;
571 
572 	if (((x & SYMFLG) ? x : sym) != wdval)
573 		synbad();
574 }
575 
576 static void
577 prsym(int sym)
578 {
579 	if (sym & SYMFLG)
580 	{
581 		const struct sysnod *sp = reserved;
582 
583 		while (sp->sysval && sp->sysval != sym)
584 			sp++;
585 		prs(sp->sysnam);
586 	}
587 	else if (sym == EOFSYM)
588 		prs(endoffile);
589 	else
590 	{
591 		if (sym & SYMREP)
592 			prc(sym);
593 		if (sym == NL)
594 			prs("newline or ;");
595 		else
596 			prc(sym);
597 	}
598 }
599 
600 static void
601 synbad(void)
602 {
603 	prp();
604 	prs(synmsg);
605 	if ((flags & ttyflg) == 0)
606 	{
607 		prs(atline);
608 		prn(standin->flin);
609 	}
610 	prs(colon);
611 	prc(LQ);
612 	if (wdval)
613 		prsym(wdval);
614 	else
615 		prs_cntl(wdarg->argval);
616 	prc(RQ);
617 	prs(unexpected);
618 	newline();
619 	exitsh(SYNBAD);
620 }
621