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