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
37static struct ionod *	inout();
38static void	chkword(void);
39static void	chksym(int);
40static struct trenod *	term();
41static struct trenod *	makelist();
42static struct trenod *	list();
43static struct regnod *	syncase();
44static struct trenod *	item();
45static int	skipnl();
46static void	prsym(int);
47static void	synbad(void);
48
49
50/* ======== storage allocation for functions ======== */
51
52unsigned char *
53getstor(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
68struct trenod *
69makefork(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
82static struct trenod *
83makelist(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 */
108struct trenod *
109cmd(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 */
158static struct trenod *
159list(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 */
174static struct trenod *
175term(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
198static struct regnod *
199syncase(esym)
200int	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 */
257static struct trenod *
258item(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
496static int
497skipnl()
498{
499	while ((reserv++, word() == NL))
500		chkpr();
501	return(wdval);
502}
503
504static struct ionod *
505inout(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
563static void
564chkword(void)
565{
566	if (word())
567		synbad();
568}
569
570static void
571chksym(int sym)
572{
573	int	x = sym & wdval;
574
575	if (((x & SYMFLG) ? x : sym) != wdval)
576		synbad();
577}
578
579static void
580prsym(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
603static void
604synbad(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