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