parser.c revision 100483
1232633Smp/*-
259243Sobrien * Copyright (c) 1991, 1993
359243Sobrien *	The Regents of the University of California.  All rights reserved.
459243Sobrien *
559243Sobrien * This code is derived from software contributed to Berkeley by
659243Sobrien * Kenneth Almquist.
759243Sobrien *
859243Sobrien * Redistribution and use in source and binary forms, with or without
959243Sobrien * modification, are permitted provided that the following conditions
1059243Sobrien * are met:
1159243Sobrien * 1. Redistributions of source code must retain the above copyright
1259243Sobrien *    notice, this list of conditions and the following disclaimer.
1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1459243Sobrien *    notice, this list of conditions and the following disclaimer in the
1559243Sobrien *    documentation and/or other materials provided with the distribution.
1659243Sobrien * 3. All advertising materials mentioning features or use of this software
17100616Smp *    must display the following acknowledgement:
1859243Sobrien *	This product includes software developed by the University of
1959243Sobrien *	California, Berkeley and its contributors.
2059243Sobrien * 4. Neither the name of the University nor the names of its contributors
2159243Sobrien *    may be used to endorse or promote products derived from this software
2259243Sobrien *    without specific prior written permission.
2359243Sobrien *
2459243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2559243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2659243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2759243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2859243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2959243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3059243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3159243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3259243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3359243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3459243Sobrien * SUCH DAMAGE.
35232633Smp */
3659243Sobrien
3759243Sobrien#ifndef lint
3859243Sobrien#if 0
3959243Sobrienstatic char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
40167465Smp#endif
41167465Smp#endif /* not lint */
42167465Smp#include <sys/cdefs.h>
43167465Smp__FBSDID("$FreeBSD: head/bin/sh/parser.c 100483 2002-07-22 05:50:12Z tjr $");
44167465Smp
45167465Smp#include <stdlib.h>
46167465Smp
47167465Smp#include "shell.h"
48167465Smp#include "parser.h"
49167465Smp#include "nodes.h"
5059243Sobrien#include "expand.h"	/* defines rmescapes() */
5159243Sobrien#include "redir.h"	/* defines copyfd() */
5259243Sobrien#include "syntax.h"
5359243Sobrien#include "options.h"
5459243Sobrien#include "input.h"
5559243Sobrien#include "output.h"
5659243Sobrien#include "var.h"
5759243Sobrien#include "error.h"
5859243Sobrien#include "memalloc.h"
5959243Sobrien#include "mystring.h"
6059243Sobrien#include "alias.h"
61167465Smp#include "show.h"
6259243Sobrien#include "eval.h"
63167465Smp#ifndef NO_HISTORY
6459243Sobrien#include "myhistedit.h"
6559243Sobrien#endif
6659243Sobrien
67167465Smp/*
68167465Smp * Shell command parser.
69167465Smp */
70167465Smp
7159243Sobrien#define EOFMARKLEN 79
7259243Sobrien
73167465Smp/* values returned by readtoken */
74167465Smp#include "token.h"
7559243Sobrien
76167465Smp
77167465Smp
78167465Smpstruct heredoc {
79167465Smp	struct heredoc *next;	/* next here document in list */
80167465Smp	union node *here;		/* redirection node */
81167465Smp	char *eofmark;		/* string indicating end of input */
8259243Sobrien	int striptabs;		/* if set, strip leading tabs */
8359243Sobrien};
84167465Smp
85167465Smp
8659243Sobrien
87145479Smpstruct heredoc *heredoclist;	/* list of here documents to read */
88145479Smpint parsebackquote;		/* nonzero if we are inside backquotes */
8959243Sobrienint doprompt;			/* if set, prompt the user */
9059243Sobrienint needprompt;			/* true if interactive and at start of line */
9159243Sobrienint lasttoken;			/* last token read */
9259243SobrienMKINIT int tokpushback;		/* last token pushed back */
9359243Sobrienchar *wordtext;			/* text of last word returned by readtoken */
9459243SobrienMKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
9559243Sobrienstruct nodelist *backquotelist;
9659243Sobrienunion node *redirnode;
9759243Sobrienstruct heredoc *heredoc;
9859243Sobrienint quoteflag;			/* set if (part of) last token was quoted */
9959243Sobrienint startlinno;			/* line # where last token started */
10059243Sobrien
10159243Sobrien/* XXX When 'noaliases' is set to one, no alias expansion takes place. */
10259243Sobrienstatic int noaliases = 0;
10359243Sobrien
10459243Sobrien#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
10559243Sobrien#ifdef GDB_HACK
10659243Sobrienstatic const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
10759243Sobrienstatic const char types[] = "}-+?=";
10859243Sobrien#endif
10959243Sobrien
11059243Sobrien
11159243SobrienSTATIC union node *list(int);
11259243SobrienSTATIC union node *andor(void);
11359243SobrienSTATIC union node *pipeline(void);
114167465SmpSTATIC union node *command(void);
115167465SmpSTATIC union node *simplecmd(union node **, union node *);
116167465SmpSTATIC union node *makename(void);
11759243SobrienSTATIC void parsefname(void);
11859243SobrienSTATIC void parseheredoc(void);
11959243SobrienSTATIC int peektoken(void);
12059243SobrienSTATIC int readtoken(void);
12159243SobrienSTATIC int xxreadtoken(void);
122167465SmpSTATIC int readtoken1(int, char const *, char *, int);
123167465SmpSTATIC int noexpand(char *);
12459243SobrienSTATIC void synexpect(int);
12559243SobrienSTATIC void synerror(char *);
12659243SobrienSTATIC void setprompt(int);
127167465Smp
12859243Sobrien
129167465Smp/*
130167465Smp * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
131167465Smp * valid parse tree indicating a blank line.)
132167465Smp */
133167465Smp
134167465Smpunion node *
135167465Smpparsecmd(int interact)
136167465Smp{
137167465Smp	int t;
138145479Smp
13959243Sobrien	tokpushback = 0;
140145479Smp	doprompt = interact;
14159243Sobrien	if (doprompt)
14259243Sobrien		setprompt(1);
143167465Smp	else
14459243Sobrien		setprompt(0);
14559243Sobrien	needprompt = 0;
14659243Sobrien	t = readtoken();
147167465Smp	if (t == TEOF)
14859243Sobrien		return NEOF;
149167465Smp	if (t == TNL)
150167465Smp		return NULL;
15159243Sobrien	tokpushback++;
15259243Sobrien	return list(1);
15359243Sobrien}
154167465Smp
15559243Sobrien
15659243SobrienSTATIC union node *
15759243Sobrienlist(int nlflag)
158167465Smp{
15959243Sobrien	union node *n1, *n2, *n3;
160167465Smp	int tok;
16159243Sobrien
16259243Sobrien	checkkwd = 2;
16359243Sobrien	if (nlflag == 0 && tokendlist[peektoken()])
16459243Sobrien		return NULL;
16559243Sobrien	n1 = NULL;
16659243Sobrien	for (;;) {
16759243Sobrien		n2 = andor();
16859243Sobrien		tok = readtoken();
169167465Smp		if (tok == TBACKGND) {
17059243Sobrien			if (n2->type == NCMD || n2->type == NPIPE) {
17159243Sobrien				n2->ncmd.backgnd = 1;
17259243Sobrien			} else if (n2->type == NREDIR) {
17359243Sobrien				n2->type = NBACKGND;
17459243Sobrien			} else {
17559243Sobrien				n3 = (union node *)stalloc(sizeof (struct nredir));
17659243Sobrien				n3->type = NBACKGND;
177167465Smp				n3->nredir.n = n2;
178167465Smp				n3->nredir.redirect = NULL;
17959243Sobrien				n2 = n3;
180167465Smp			}
18159243Sobrien		}
18259243Sobrien		if (n1 == NULL) {
18359243Sobrien			n1 = n2;
184167465Smp		}
18559243Sobrien		else {
186145479Smp			n3 = (union node *)stalloc(sizeof (struct nbinary));
18759243Sobrien			n3->type = NSEMI;
18859243Sobrien			n3->nbinary.ch1 = n1;
189167465Smp			n3->nbinary.ch2 = n2;
19059243Sobrien			n1 = n3;
191167465Smp		}
19259243Sobrien		switch (tok) {
19359243Sobrien		case TBACKGND:
19459243Sobrien		case TSEMI:
19559243Sobrien			tok = readtoken();
19659243Sobrien			/* fall through */
19759243Sobrien		case TNL:
19859243Sobrien			if (tok == TNL) {
19959243Sobrien				parseheredoc();
20059243Sobrien				if (nlflag)
20159243Sobrien					return n1;
20259243Sobrien			} else {
20359243Sobrien				tokpushback++;
20459243Sobrien			}
20559243Sobrien			checkkwd = 2;
20659243Sobrien			if (tokendlist[peektoken()])
20759243Sobrien				return n1;
20859243Sobrien			break;
209167465Smp		case TEOF:
21059243Sobrien			if (heredoclist)
21159243Sobrien				parseheredoc();
21259243Sobrien			else
21359243Sobrien				pungetc();		/* push back EOF on input */
21459243Sobrien			return n1;
21559243Sobrien		default:
21659243Sobrien			if (nlflag)
21759243Sobrien				synexpect(-1);
21859243Sobrien			tokpushback++;
21959243Sobrien			return n1;
22059243Sobrien		}
22159243Sobrien	}
22259243Sobrien}
22359243Sobrien
22459243Sobrien
22559243Sobrien
226167465SmpSTATIC union node *
22759243Sobrienandor(void)
228167465Smp{
229145479Smp	union node *n1, *n2, *n3;
23059243Sobrien	int t;
23159243Sobrien
23259243Sobrien	n1 = pipeline();
23359243Sobrien	for (;;) {
23459243Sobrien		if ((t = readtoken()) == TAND) {
23559243Sobrien			t = NAND;
23659243Sobrien		} else if (t == TOR) {
23759243Sobrien			t = NOR;
23859243Sobrien		} else {
23959243Sobrien			tokpushback++;
24059243Sobrien			return n1;
24159243Sobrien		}
24259243Sobrien		n2 = pipeline();
24359243Sobrien		n3 = (union node *)stalloc(sizeof (struct nbinary));
24459243Sobrien		n3->type = t;
24559243Sobrien		n3->nbinary.ch1 = n1;
24659243Sobrien		n3->nbinary.ch2 = n2;
24759243Sobrien		n1 = n3;
24859243Sobrien	}
24959243Sobrien}
25059243Sobrien
25159243Sobrien
25259243Sobrien
25359243SobrienSTATIC union node *
25459243Sobrienpipeline(void)
25559243Sobrien{
25659243Sobrien	union node *n1, *n2, *pipenode;
25759243Sobrien	struct nodelist *lp, *prev;
25859243Sobrien	int negate;
25959243Sobrien
26059243Sobrien	negate = 0;
26159243Sobrien	TRACE(("pipeline: entered\n"));
26259243Sobrien	while (readtoken() == TNOT)
26359243Sobrien		negate = !negate;
26459243Sobrien	tokpushback++;
265167465Smp	n1 = command();
26659243Sobrien	if (readtoken() == TPIPE) {
26759243Sobrien		pipenode = (union node *)stalloc(sizeof (struct npipe));
26859243Sobrien		pipenode->type = NPIPE;
26959243Sobrien		pipenode->npipe.backgnd = 0;
27059243Sobrien		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
27159243Sobrien		pipenode->npipe.cmdlist = lp;
27259243Sobrien		lp->n = n1;
273167465Smp		do {
27459243Sobrien			prev = lp;
27559243Sobrien			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
27659243Sobrien			lp->n = command();
27759243Sobrien			prev->next = lp;
27859243Sobrien		} while (readtoken() == TPIPE);
27959243Sobrien		lp->next = NULL;
28059243Sobrien		n1 = pipenode;
28159243Sobrien	}
28259243Sobrien	tokpushback++;
28359243Sobrien	if (negate) {
28459243Sobrien		n2 = (union node *)stalloc(sizeof (struct nnot));
28559243Sobrien		n2->type = NNOT;
28659243Sobrien		n2->nnot.com = n1;
28759243Sobrien		return n2;
28859243Sobrien	} else
28959243Sobrien		return n1;
29059243Sobrien}
29159243Sobrien
29259243Sobrien
29359243Sobrien
294167465SmpSTATIC union node *
29559243Sobriencommand(void)
296167465Smp{
297145479Smp	union node *n1, *n2;
29859243Sobrien	union node *ap, **app;
29959243Sobrien	union node *cp, **cpp;
30059243Sobrien	union node *redir, **rpp;
30159243Sobrien	int t, negate = 0;
30259243Sobrien
30359243Sobrien	checkkwd = 2;
30459243Sobrien	redir = NULL;
30559243Sobrien	n1 = NULL;
30659243Sobrien	rpp = &redir;
30759243Sobrien
30859243Sobrien	/* Check for redirection which may precede command */
30959243Sobrien	while (readtoken() == TREDIR) {
31059243Sobrien		*rpp = n2 = redirnode;
31159243Sobrien		rpp = &n2->nfile.next;
31259243Sobrien		parsefname();
31359243Sobrien	}
31459243Sobrien	tokpushback++;
31559243Sobrien
316167465Smp	while (readtoken() == TNOT) {
31759243Sobrien		TRACE(("command: TNOT recognized\n"));
31859243Sobrien		negate = !negate;
31959243Sobrien	}
32059243Sobrien	tokpushback++;
32159243Sobrien
32259243Sobrien	switch (readtoken()) {
32359243Sobrien	case TIF:
32459243Sobrien		n1 = (union node *)stalloc(sizeof (struct nif));
32559243Sobrien		n1->type = NIF;
32659243Sobrien		n1->nif.test = list(0);
32759243Sobrien		if (readtoken() != TTHEN)
32859243Sobrien			synexpect(TTHEN);
32959243Sobrien		n1->nif.ifpart = list(0);
33059243Sobrien		n2 = n1;
33159243Sobrien		while (readtoken() == TELIF) {
33259243Sobrien			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
33359243Sobrien			n2 = n2->nif.elsepart;
33459243Sobrien			n2->type = NIF;
33559243Sobrien			n2->nif.test = list(0);
336167465Smp			if (readtoken() != TTHEN)
33759243Sobrien				synexpect(TTHEN);
338167465Smp			n2->nif.ifpart = list(0);
339145479Smp		}
340145479Smp		if (lasttoken == TELSE)
34159243Sobrien			n2->nif.elsepart = list(0);
34259243Sobrien		else {
34359243Sobrien			n2->nif.elsepart = NULL;
34459243Sobrien			tokpushback++;
34559243Sobrien		}
34659243Sobrien		if (readtoken() != TFI)
34759243Sobrien			synexpect(TFI);
34859243Sobrien		checkkwd = 1;
34959243Sobrien		break;
35059243Sobrien	case TWHILE:
35159243Sobrien	case TUNTIL: {
35259243Sobrien		int got;
35359243Sobrien		n1 = (union node *)stalloc(sizeof (struct nbinary));
35459243Sobrien		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
35559243Sobrien		n1->nbinary.ch1 = list(0);
35659243Sobrien		if ((got=readtoken()) != TDO) {
357167465SmpTRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
35859243Sobrien			synexpect(TDO);
35959243Sobrien		}
36059243Sobrien		n1->nbinary.ch2 = list(0);
36159243Sobrien		if (readtoken() != TDONE)
36259243Sobrien			synexpect(TDONE);
36359243Sobrien		checkkwd = 1;
36459243Sobrien		break;
36559243Sobrien	}
36659243Sobrien	case TFOR:
36759243Sobrien		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
36859243Sobrien			synerror("Bad for loop variable");
36959243Sobrien		n1 = (union node *)stalloc(sizeof (struct nfor));
37059243Sobrien		n1->type = NFOR;
37159243Sobrien		n1->nfor.var = wordtext;
37259243Sobrien		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
37359243Sobrien			app = &ap;
37459243Sobrien			while (readtoken() == TWORD) {
37559243Sobrien				n2 = (union node *)stalloc(sizeof (struct narg));
37659243Sobrien				n2->type = NARG;
37759243Sobrien				n2->narg.text = wordtext;
378167465Smp				n2->narg.backquote = backquotelist;
37959243Sobrien				*app = n2;
380167465Smp				app = &n2->narg.next;
381145479Smp			}
382145479Smp			*app = NULL;
38359243Sobrien			n1->nfor.args = ap;
38459243Sobrien			if (lasttoken != TNL && lasttoken != TSEMI)
38559243Sobrien				synexpect(-1);
38659243Sobrien		} else {
38759243Sobrien#ifndef GDB_HACK
38859243Sobrien			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
38959243Sobrien								   '@', '=', '\0'};
39059243Sobrien#endif
39159243Sobrien			n2 = (union node *)stalloc(sizeof (struct narg));
39259243Sobrien			n2->type = NARG;
39359243Sobrien			n2->narg.text = (char *)argvars;
39459243Sobrien			n2->narg.backquote = NULL;
39559243Sobrien			n2->narg.next = NULL;
39659243Sobrien			n1->nfor.args = n2;
397167465Smp			/*
39859243Sobrien			 * Newline or semicolon here is optional (but note
39959243Sobrien			 * that the original Bourne shell only allowed NL).
40059243Sobrien			 */
40159243Sobrien			if (lasttoken != TNL && lasttoken != TSEMI)
40259243Sobrien				tokpushback++;
40359243Sobrien		}
40459243Sobrien		checkkwd = 2;
40559243Sobrien		if ((t = readtoken()) == TDO)
40659243Sobrien			t = TDONE;
40759243Sobrien		else if (t == TBEGIN)
40859243Sobrien			t = TEND;
40959243Sobrien		else
41059243Sobrien			synexpect(-1);
41159243Sobrien		n1->nfor.body = list(0);
41259243Sobrien		if (readtoken() != t)
41359243Sobrien			synexpect(t);
41459243Sobrien		checkkwd = 1;
41559243Sobrien		break;
41659243Sobrien	case TCASE:
41759243Sobrien		n1 = (union node *)stalloc(sizeof (struct ncase));
41859243Sobrien		n1->type = NCASE;
419167465Smp		if (readtoken() != TWORD)
42059243Sobrien			synexpect(TWORD);
421167465Smp		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
422145479Smp		n2->type = NARG;
423145479Smp		n2->narg.text = wordtext;
42459243Sobrien		n2->narg.backquote = backquotelist;
42559243Sobrien		n2->narg.next = NULL;
42659243Sobrien		while (readtoken() == TNL);
42759243Sobrien		if (lasttoken != TWORD || ! equal(wordtext, "in"))
42859243Sobrien			synerror("expecting \"in\"");
42959243Sobrien		cpp = &n1->ncase.cases;
43059243Sobrien		noaliases = 1;	/* turn off alias expansion */
43159243Sobrien		checkkwd = 2, readtoken();
43259243Sobrien		do {
43359243Sobrien			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
43459243Sobrien			cp->type = NCLIST;
43559243Sobrien			app = &cp->nclist.pattern;
43659243Sobrien			for (;;) {
43759243Sobrien				*app = ap = (union node *)stalloc(sizeof (struct narg));
43859243Sobrien				ap->type = NARG;
43959243Sobrien				ap->narg.text = wordtext;
440167465Smp				ap->narg.backquote = backquotelist;
44159243Sobrien				if (checkkwd = 2, readtoken() != TPIPE)
44259243Sobrien					break;
44359243Sobrien				app = &ap->narg.next;
44459243Sobrien				readtoken();
44559243Sobrien			}
44659243Sobrien			ap->narg.next = NULL;
44759243Sobrien			if (lasttoken != TRP)
44859243Sobrien				noaliases = 0, synexpect(TRP);
44959243Sobrien			cp->nclist.body = list(0);
45059243Sobrien
45159243Sobrien			checkkwd = 2;
45259243Sobrien			if ((t = readtoken()) != TESAC) {
45359243Sobrien				if (t != TENDCASE)
45459243Sobrien					noaliases = 0, synexpect(TENDCASE);
45559243Sobrien				else
45659243Sobrien					checkkwd = 2, readtoken();
45759243Sobrien			}
45859243Sobrien			cpp = &cp->nclist.next;
45959243Sobrien		} while(lasttoken != TESAC);
460167465Smp		noaliases = 0;	/* reset alias expansion */
46159243Sobrien		*cpp = NULL;
46259243Sobrien		checkkwd = 1;
46359243Sobrien		break;
46459243Sobrien	case TLP:
46559243Sobrien		n1 = (union node *)stalloc(sizeof (struct nredir));
46659243Sobrien		n1->type = NSUBSHELL;
46759243Sobrien		n1->nredir.n = list(0);
46859243Sobrien		n1->nredir.redirect = NULL;
46959243Sobrien		if (readtoken() != TRP)
47059243Sobrien			synexpect(TRP);
471167465Smp		checkkwd = 1;
47259243Sobrien		break;
473167465Smp	case TBEGIN:
474167465Smp		n1 = list(0);
475145479Smp		if (readtoken() != TEND)
476145479Smp			synexpect(TEND);
47759243Sobrien		checkkwd = 1;
47859243Sobrien		break;
479145479Smp	/* Handle an empty command like other simple commands.  */
48059243Sobrien	case TSEMI:
48159243Sobrien		/*
48259243Sobrien		 * An empty command before a ; doesn't make much sense, and
48359243Sobrien		 * should certainly be disallowed in the case of `if ;'.
48459243Sobrien		 */
48559243Sobrien		if (!redir)
48659243Sobrien			synexpect(-1);
48759243Sobrien	case TAND:
48859243Sobrien	case TOR:
48959243Sobrien		synexpect(-1);
49059243Sobrien	case TNL:
49159243Sobrien	case TEOF:
49259243Sobrien	case TWORD:
49359243Sobrien	case TRP:
49459243Sobrien		tokpushback++;
49559243Sobrien		n1 = simplecmd(rpp, redir);
49659243Sobrien		goto checkneg;
49759243Sobrien	default:
49859243Sobrien		synexpect(-1);
49959243Sobrien	}
50059243Sobrien
50159243Sobrien	/* Now check for redirection which may follow command */
50259243Sobrien	while (readtoken() == TREDIR) {
50359243Sobrien		*rpp = n2 = redirnode;
50459243Sobrien		rpp = &n2->nfile.next;
50559243Sobrien		parsefname();
50659243Sobrien	}
50759243Sobrien	tokpushback++;
50859243Sobrien	*rpp = NULL;
50959243Sobrien	if (redir) {
51059243Sobrien		if (n1->type != NSUBSHELL) {
51159243Sobrien			n2 = (union node *)stalloc(sizeof (struct nredir));
51259243Sobrien			n2->type = NREDIR;
51359243Sobrien			n2->nredir.n = n1;
51459243Sobrien			n1 = n2;
51559243Sobrien		}
51659243Sobrien		n1->nredir.redirect = redir;
51759243Sobrien	}
51859243Sobrien
51959243Sobriencheckneg:
52059243Sobrien	if (negate) {
52159243Sobrien		n2 = (union node *)stalloc(sizeof (struct nnot));
52259243Sobrien		n2->type = NNOT;
52359243Sobrien		n2->nnot.com = n1;
52459243Sobrien		return n2;
52559243Sobrien	}
52659243Sobrien	else
52759243Sobrien		return n1;
52859243Sobrien}
52959243Sobrien
53059243Sobrien
53159243SobrienSTATIC union node *
53259243Sobriensimplecmd(union node **rpp, union node *redir)
53359243Sobrien{
53459243Sobrien	union node *args, **app;
53559243Sobrien	union node **orig_rpp = rpp;
53659243Sobrien	union node *n = NULL, *n2;
53759243Sobrien	int negate = 0;
53859243Sobrien
53959243Sobrien	/* If we don't have any redirections already, then we must reset */
54059243Sobrien	/* rpp to be the address of the local redir variable.  */
54159243Sobrien	if (redir == 0)
54259243Sobrien		rpp = &redir;
54359243Sobrien
544167465Smp	args = NULL;
545167465Smp	app = &args;
54659243Sobrien	/*
54759243Sobrien	 * We save the incoming value, because we need this for shell
54859243Sobrien	 * functions.  There can not be a redirect or an argument between
54959243Sobrien	 * the function name and the open parenthesis.
55059243Sobrien	 */
55159243Sobrien	orig_rpp = rpp;
55259243Sobrien
55359243Sobrien	while (readtoken() == TNOT) {
55459243Sobrien		TRACE(("command: TNOT recognized\n"));
55559243Sobrien		negate = !negate;
55659243Sobrien	}
55759243Sobrien	tokpushback++;
55859243Sobrien
55959243Sobrien	for (;;) {
56059243Sobrien		if (readtoken() == TWORD) {
56159243Sobrien			n = (union node *)stalloc(sizeof (struct narg));
56259243Sobrien			n->type = NARG;
56359243Sobrien			n->narg.text = wordtext;
56459243Sobrien			n->narg.backquote = backquotelist;
56559243Sobrien			*app = n;
56659243Sobrien			app = &n->narg.next;
56759243Sobrien		} else if (lasttoken == TREDIR) {
56859243Sobrien			*rpp = n = redirnode;
56959243Sobrien			rpp = &n->nfile.next;
57059243Sobrien			parsefname();	/* read name of redirection file */
57159243Sobrien		} else if (lasttoken == TLP && app == &args->narg.next
57259243Sobrien					    && rpp == orig_rpp) {
57359243Sobrien			/* We have a function */
57459243Sobrien			if (readtoken() != TRP)
57559243Sobrien				synexpect(TRP);
57659243Sobrien#ifdef notdef
57759243Sobrien			if (! goodname(n->narg.text))
57859243Sobrien				synerror("Bad function name");
57959243Sobrien#endif
58059243Sobrien			n->type = NDEFUN;
58159243Sobrien			n->narg.next = command();
58259243Sobrien			goto checkneg;
58359243Sobrien		} else {
58459243Sobrien			tokpushback++;
58559243Sobrien			break;
58659243Sobrien		}
58759243Sobrien	}
58859243Sobrien	*app = NULL;
58959243Sobrien	*rpp = NULL;
59059243Sobrien	n = (union node *)stalloc(sizeof (struct ncmd));
59159243Sobrien	n->type = NCMD;
59259243Sobrien	n->ncmd.backgnd = 0;
59359243Sobrien	n->ncmd.args = args;
59459243Sobrien	n->ncmd.redirect = redir;
59559243Sobrien
59659243Sobriencheckneg:
59759243Sobrien	if (negate) {
59859243Sobrien		n2 = (union node *)stalloc(sizeof (struct nnot));
59959243Sobrien		n2->type = NNOT;
60059243Sobrien		n2->nnot.com = n;
60159243Sobrien		return n2;
60259243Sobrien	}
60359243Sobrien	else
60459243Sobrien		return n;
60559243Sobrien}
60659243Sobrien
60759243SobrienSTATIC union node *
60859243Sobrienmakename(void)
60959243Sobrien{
61059243Sobrien	union node *n;
61159243Sobrien
61259243Sobrien	n = (union node *)stalloc(sizeof (struct narg));
61359243Sobrien	n->type = NARG;
61459243Sobrien	n->narg.next = NULL;
61559243Sobrien	n->narg.text = wordtext;
61659243Sobrien	n->narg.backquote = backquotelist;
61759243Sobrien	return n;
61859243Sobrien}
61959243Sobrien
62059243Sobrienvoid fixredir(union node *n, const char *text, int err)
62159243Sobrien{
62259243Sobrien	TRACE(("Fix redir %s %d\n", text, err));
62359243Sobrien	if (!err)
62459243Sobrien		n->ndup.vname = NULL;
62559243Sobrien
62659243Sobrien	if (is_digit(text[0]) && text[1] == '\0')
62759243Sobrien		n->ndup.dupfd = digit_val(text[0]);
62859243Sobrien	else if (text[0] == '-' && text[1] == '\0')
62959243Sobrien		n->ndup.dupfd = -1;
63059243Sobrien	else {
63159243Sobrien
63259243Sobrien		if (err)
63359243Sobrien			synerror("Bad fd number");
63459243Sobrien		else
63559243Sobrien			n->ndup.vname = makename();
63659243Sobrien	}
63759243Sobrien}
63859243Sobrien
63959243Sobrien
64059243SobrienSTATIC void
64159243Sobrienparsefname(void)
64259243Sobrien{
64359243Sobrien	union node *n = redirnode;
64459243Sobrien
64559243Sobrien	if (readtoken() != TWORD)
64659243Sobrien		synexpect(-1);
64759243Sobrien	if (n->type == NHERE) {
64859243Sobrien		struct heredoc *here = heredoc;
64959243Sobrien		struct heredoc *p;
650167465Smp		int i;
65159243Sobrien
652145479Smp		if (quoteflag == 0)
65359243Sobrien			n->type = NXHERE;
65459243Sobrien		TRACE(("Here document %d\n", n->type));
65559243Sobrien		if (here->striptabs) {
65659243Sobrien			while (*wordtext == '\t')
65759243Sobrien				wordtext++;
65859243Sobrien		}
65959243Sobrien		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
660167465Smp			synerror("Illegal eof marker for << redirection");
661167465Smp		rmescapes(wordtext);
662167465Smp		here->eofmark = wordtext;
663167465Smp		here->next = NULL;
66459243Sobrien		if (heredoclist == NULL)
66559243Sobrien			heredoclist = here;
66659243Sobrien		else {
667167465Smp			for (p = heredoclist ; p->next ; p = p->next);
668167465Smp			p->next = here;
66959243Sobrien		}
67059243Sobrien	} else if (n->type == NTOFD || n->type == NFROMFD) {
67159243Sobrien		fixredir(n, wordtext, 0);
67259243Sobrien	} else {
67359243Sobrien		n->nfile.fname = makename();
67459243Sobrien	}
67559243Sobrien}
67659243Sobrien
67759243Sobrien
67859243Sobrien/*
67959243Sobrien * Input any here documents.
680232633Smp */
681232633Smp
682232633SmpSTATIC void
683167465Smpparseheredoc(void)
68459243Sobrien{
685167465Smp	struct heredoc *here;
686167465Smp	union node *n;
687167465Smp
688167465Smp	while (heredoclist) {
689167465Smp		here = heredoclist;
690167465Smp		heredoclist = here->next;
691167465Smp		if (needprompt) {
692167465Smp			setprompt(2);
693167465Smp			needprompt = 0;
694		}
695		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
696				here->eofmark, here->striptabs);
697		n = (union node *)stalloc(sizeof (struct narg));
698		n->narg.type = NARG;
699		n->narg.next = NULL;
700		n->narg.text = wordtext;
701		n->narg.backquote = backquotelist;
702		here->here->nhere.doc = n;
703	}
704}
705
706STATIC int
707peektoken(void)
708{
709	int t;
710
711	t = readtoken();
712	tokpushback++;
713	return (t);
714}
715
716STATIC int
717readtoken(void)
718{
719	int t;
720	int savecheckkwd = checkkwd;
721	struct alias *ap;
722#ifdef DEBUG
723	int alreadyseen = tokpushback;
724#endif
725
726	top:
727	t = xxreadtoken();
728
729	if (checkkwd) {
730		/*
731		 * eat newlines
732		 */
733		if (checkkwd == 2) {
734			checkkwd = 0;
735			while (t == TNL) {
736				parseheredoc();
737				t = xxreadtoken();
738			}
739		} else
740			checkkwd = 0;
741		/*
742		 * check for keywords and aliases
743		 */
744		if (t == TWORD && !quoteflag)
745		{
746			const char * const *pp;
747
748			for (pp = parsekwd; *pp; pp++) {
749				if (**pp == *wordtext && equal(*pp, wordtext))
750				{
751					lasttoken = t = pp - parsekwd + KWDOFFSET;
752					TRACE(("keyword %s recognized\n", tokname[t]));
753					goto out;
754				}
755			}
756			if (noaliases == 0 &&
757			    (ap = lookupalias(wordtext, 1)) != NULL) {
758				pushstring(ap->val, strlen(ap->val), ap);
759				checkkwd = savecheckkwd;
760				goto top;
761			}
762		}
763out:
764		checkkwd = (t == TNOT) ? savecheckkwd : 0;
765	}
766#ifdef DEBUG
767	if (!alreadyseen)
768	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
769	else
770	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
771#endif
772	return (t);
773}
774
775
776/*
777 * Read the next input token.
778 * If the token is a word, we set backquotelist to the list of cmds in
779 *	backquotes.  We set quoteflag to true if any part of the word was
780 *	quoted.
781 * If the token is TREDIR, then we set redirnode to a structure containing
782 *	the redirection.
783 * In all cases, the variable startlinno is set to the number of the line
784 *	on which the token starts.
785 *
786 * [Change comment:  here documents and internal procedures]
787 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
788 *  word parsing code into a separate routine.  In this case, readtoken
789 *  doesn't need to have any internal procedures, but parseword does.
790 *  We could also make parseoperator in essence the main routine, and
791 *  have parseword (readtoken1?) handle both words and redirection.]
792 */
793
794#define RETURN(token)	return lasttoken = token
795
796STATIC int
797xxreadtoken(void)
798{
799	int c;
800
801	if (tokpushback) {
802		tokpushback = 0;
803		return lasttoken;
804	}
805	if (needprompt) {
806		setprompt(2);
807		needprompt = 0;
808	}
809	startlinno = plinno;
810	for (;;) {	/* until token or start of word found */
811		c = pgetc_macro();
812		if (c == ' ' || c == '\t')
813			continue;		/* quick check for white space first */
814		switch (c) {
815		case ' ': case '\t':
816			continue;
817		case '#':
818			while ((c = pgetc()) != '\n' && c != PEOF);
819			pungetc();
820			continue;
821		case '\\':
822			if (pgetc() == '\n') {
823				startlinno = ++plinno;
824				if (doprompt)
825					setprompt(2);
826				else
827					setprompt(0);
828				continue;
829			}
830			pungetc();
831			goto breakloop;
832		case '\n':
833			plinno++;
834			needprompt = doprompt;
835			RETURN(TNL);
836		case PEOF:
837			RETURN(TEOF);
838		case '&':
839			if (pgetc() == '&')
840				RETURN(TAND);
841			pungetc();
842			RETURN(TBACKGND);
843		case '|':
844			if (pgetc() == '|')
845				RETURN(TOR);
846			pungetc();
847			RETURN(TPIPE);
848		case ';':
849			if (pgetc() == ';')
850				RETURN(TENDCASE);
851			pungetc();
852			RETURN(TSEMI);
853		case '(':
854			RETURN(TLP);
855		case ')':
856			RETURN(TRP);
857		default:
858			goto breakloop;
859		}
860	}
861breakloop:
862	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
863#undef RETURN
864}
865
866
867
868/*
869 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
870 * is not NULL, read a here document.  In the latter case, eofmark is the
871 * word which marks the end of the document and striptabs is true if
872 * leading tabs should be stripped from the document.  The argument firstc
873 * is the first character of the input token or document.
874 *
875 * Because C does not have internal subroutines, I have simulated them
876 * using goto's to implement the subroutine linkage.  The following macros
877 * will run code that appears at the end of readtoken1.
878 */
879
880#define CHECKEND()	{goto checkend; checkend_return:;}
881#define PARSEREDIR()	{goto parseredir; parseredir_return:;}
882#define PARSESUB()	{goto parsesub; parsesub_return:;}
883#define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
884#define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
885#define	PARSEARITH()	{goto parsearith; parsearith_return:;}
886
887STATIC int
888readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
889{
890	int c = firstc;
891	char *out;
892	int len;
893	char line[EOFMARKLEN + 1];
894	struct nodelist *bqlist;
895	int quotef;
896	int dblquote;
897	int varnest;	/* levels of variables expansion */
898	int arinest;	/* levels of arithmetic expansion */
899	int parenlevel;	/* levels of parens in arithmetic */
900	int oldstyle;
901	char const *prevsyntax;	/* syntax before arithmetic */
902	int synentry;
903#if __GNUC__
904	/* Avoid longjmp clobbering */
905	(void) &out;
906	(void) &quotef;
907	(void) &dblquote;
908	(void) &varnest;
909	(void) &arinest;
910	(void) &parenlevel;
911	(void) &oldstyle;
912	(void) &prevsyntax;
913	(void) &syntax;
914	(void) &synentry;
915#endif
916
917	startlinno = plinno;
918	dblquote = 0;
919	if (syntax == DQSYNTAX)
920		dblquote = 1;
921	quotef = 0;
922	bqlist = NULL;
923	varnest = 0;
924	arinest = 0;
925	parenlevel = 0;
926
927	STARTSTACKSTR(out);
928	loop: {	/* for each line, until end of word */
929#if ATTY
930		if (c == '\034' && doprompt
931		 && attyset() && ! equal(termval(), "emacs")) {
932			attyline();
933			if (syntax == BASESYNTAX)
934				return readtoken();
935			c = pgetc();
936			goto loop;
937		}
938#endif
939		CHECKEND();	/* set c to PEOF if at end of here document */
940		for (;;) {	/* until end of line or end of word */
941			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */
942
943			synentry = syntax[c];
944
945			switch(synentry) {
946			case CNL:	/* '\n' */
947				if (syntax == BASESYNTAX)
948					goto endword;	/* exit outer loop */
949				USTPUTC(c, out);
950				plinno++;
951				if (doprompt)
952					setprompt(2);
953				else
954					setprompt(0);
955				c = pgetc();
956				goto loop;		/* continue outer loop */
957			case CWORD:
958				USTPUTC(c, out);
959				break;
960			case CCTL:
961				if (eofmark == NULL || dblquote)
962					USTPUTC(CTLESC, out);
963				USTPUTC(c, out);
964				break;
965			case CBACK:	/* backslash */
966				c = pgetc();
967				if (c == PEOF) {
968					USTPUTC('\\', out);
969					pungetc();
970				} else if (c == '\n') {
971					if (doprompt)
972						setprompt(2);
973					else
974						setprompt(0);
975				} else {
976					if (dblquote && c != '\\' &&
977					    c != '`' && c != '$' &&
978					    (c != '"' || eofmark != NULL))
979						USTPUTC('\\', out);
980					if (SQSYNTAX[c] == CCTL)
981						USTPUTC(CTLESC, out);
982					else if (eofmark == NULL)
983						USTPUTC(CTLQUOTEMARK, out);
984					USTPUTC(c, out);
985					quotef++;
986				}
987				break;
988			case CSQUOTE:
989				if (eofmark == NULL)
990					USTPUTC(CTLQUOTEMARK, out);
991				syntax = SQSYNTAX;
992				break;
993			case CDQUOTE:
994				if (eofmark == NULL)
995					USTPUTC(CTLQUOTEMARK, out);
996				syntax = DQSYNTAX;
997				dblquote = 1;
998				break;
999			case CENDQUOTE:
1000				if (eofmark != NULL && arinest == 0 &&
1001				    varnest == 0) {
1002					USTPUTC(c, out);
1003				} else {
1004					if (arinest) {
1005						syntax = ARISYNTAX;
1006						dblquote = 0;
1007					} else if (eofmark == NULL) {
1008						syntax = BASESYNTAX;
1009						dblquote = 0;
1010					}
1011					quotef++;
1012				}
1013				break;
1014			case CVAR:	/* '$' */
1015				PARSESUB();		/* parse substitution */
1016				break;
1017			case CENDVAR:	/* '}' */
1018				if (varnest > 0) {
1019					varnest--;
1020					USTPUTC(CTLENDVAR, out);
1021				} else {
1022					USTPUTC(c, out);
1023				}
1024				break;
1025			case CLP:	/* '(' in arithmetic */
1026				parenlevel++;
1027				USTPUTC(c, out);
1028				break;
1029			case CRP:	/* ')' in arithmetic */
1030				if (parenlevel > 0) {
1031					USTPUTC(c, out);
1032					--parenlevel;
1033				} else {
1034					if (pgetc() == ')') {
1035						if (--arinest == 0) {
1036							USTPUTC(CTLENDARI, out);
1037							syntax = prevsyntax;
1038							if (syntax == DQSYNTAX)
1039								dblquote = 1;
1040							else
1041								dblquote = 0;
1042						} else
1043							USTPUTC(')', out);
1044					} else {
1045						/*
1046						 * unbalanced parens
1047						 *  (don't 2nd guess - no error)
1048						 */
1049						pungetc();
1050						USTPUTC(')', out);
1051					}
1052				}
1053				break;
1054			case CBQUOTE:	/* '`' */
1055				PARSEBACKQOLD();
1056				break;
1057			case CEOF:
1058				goto endword;		/* exit outer loop */
1059			default:
1060				if (varnest == 0)
1061					goto endword;	/* exit outer loop */
1062				USTPUTC(c, out);
1063			}
1064			c = pgetc_macro();
1065		}
1066	}
1067endword:
1068	if (syntax == ARISYNTAX)
1069		synerror("Missing '))'");
1070	if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
1071		synerror("Unterminated quoted string");
1072	if (varnest != 0) {
1073		startlinno = plinno;
1074		synerror("Missing '}'");
1075	}
1076	USTPUTC('\0', out);
1077	len = out - stackblock();
1078	out = stackblock();
1079	if (eofmark == NULL) {
1080		if ((c == '>' || c == '<')
1081		 && quotef == 0
1082		 && len <= 2
1083		 && (*out == '\0' || is_digit(*out))) {
1084			PARSEREDIR();
1085			return lasttoken = TREDIR;
1086		} else {
1087			pungetc();
1088		}
1089	}
1090	quoteflag = quotef;
1091	backquotelist = bqlist;
1092	grabstackblock(len);
1093	wordtext = out;
1094	return lasttoken = TWORD;
1095/* end of readtoken routine */
1096
1097
1098
1099/*
1100 * Check to see whether we are at the end of the here document.  When this
1101 * is called, c is set to the first character of the next input line.  If
1102 * we are at the end of the here document, this routine sets the c to PEOF.
1103 */
1104
1105checkend: {
1106	if (eofmark) {
1107		if (striptabs) {
1108			while (c == '\t')
1109				c = pgetc();
1110		}
1111		if (c == *eofmark) {
1112			if (pfgets(line, sizeof line) != NULL) {
1113				char *p, *q;
1114
1115				p = line;
1116				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1117				if (*p == '\n' && *q == '\0') {
1118					c = PEOF;
1119					plinno++;
1120					needprompt = doprompt;
1121				} else {
1122					pushstring(line, strlen(line), NULL);
1123				}
1124			}
1125		}
1126	}
1127	goto checkend_return;
1128}
1129
1130
1131/*
1132 * Parse a redirection operator.  The variable "out" points to a string
1133 * specifying the fd to be redirected.  The variable "c" contains the
1134 * first character of the redirection operator.
1135 */
1136
1137parseredir: {
1138	char fd = *out;
1139	union node *np;
1140
1141	np = (union node *)stalloc(sizeof (struct nfile));
1142	if (c == '>') {
1143		np->nfile.fd = 1;
1144		c = pgetc();
1145		if (c == '>')
1146			np->type = NAPPEND;
1147		else if (c == '&')
1148			np->type = NTOFD;
1149		else if (c == '|')
1150			np->type = NCLOBBER;
1151		else {
1152			np->type = NTO;
1153			pungetc();
1154		}
1155	} else {	/* c == '<' */
1156		np->nfile.fd = 0;
1157		c = pgetc();
1158		if (c == '<') {
1159			if (sizeof (struct nfile) != sizeof (struct nhere)) {
1160				np = (union node *)stalloc(sizeof (struct nhere));
1161				np->nfile.fd = 0;
1162			}
1163			np->type = NHERE;
1164			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1165			heredoc->here = np;
1166			if ((c = pgetc()) == '-') {
1167				heredoc->striptabs = 1;
1168			} else {
1169				heredoc->striptabs = 0;
1170				pungetc();
1171			}
1172		} else if (c == '&')
1173			np->type = NFROMFD;
1174		else if (c == '>')
1175			np->type = NFROMTO;
1176		else {
1177			np->type = NFROM;
1178			pungetc();
1179		}
1180	}
1181	if (fd != '\0')
1182		np->nfile.fd = digit_val(fd);
1183	redirnode = np;
1184	goto parseredir_return;
1185}
1186
1187
1188/*
1189 * Parse a substitution.  At this point, we have read the dollar sign
1190 * and nothing else.
1191 */
1192
1193parsesub: {
1194	int subtype;
1195	int typeloc;
1196	int flags;
1197	char *p;
1198#ifndef GDB_HACK
1199	static const char types[] = "}-+?=";
1200#endif
1201       int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
1202
1203	c = pgetc();
1204	if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
1205		USTPUTC('$', out);
1206		pungetc();
1207	} else if (c == '(') {	/* $(command) or $((arith)) */
1208		if (pgetc() == '(') {
1209			PARSEARITH();
1210		} else {
1211			pungetc();
1212			PARSEBACKQNEW();
1213		}
1214	} else {
1215		USTPUTC(CTLVAR, out);
1216		typeloc = out - stackblock();
1217		USTPUTC(VSNORMAL, out);
1218		subtype = VSNORMAL;
1219		if (c == '{') {
1220			bracketed_name = 1;
1221			c = pgetc();
1222			if (c == '#') {
1223				if ((c = pgetc()) == '}')
1224					c = '#';
1225				else
1226					subtype = VSLENGTH;
1227			}
1228			else
1229				subtype = 0;
1230		}
1231		if (is_name(c)) {
1232			do {
1233				STPUTC(c, out);
1234				c = pgetc();
1235			} while (is_in_name(c));
1236		} else if (is_digit(c)) {
1237			if (bracketed_name) {
1238				do {
1239					STPUTC(c, out);
1240					c = pgetc();
1241				} while (is_digit(c));
1242			} else {
1243				STPUTC(c, out);
1244				c = pgetc();
1245			}
1246		} else {
1247			if (! is_special(c))
1248badsub:				synerror("Bad substitution");
1249			USTPUTC(c, out);
1250			c = pgetc();
1251		}
1252		STPUTC('=', out);
1253		flags = 0;
1254		if (subtype == 0) {
1255			switch (c) {
1256			case ':':
1257				flags = VSNUL;
1258				c = pgetc();
1259				/*FALLTHROUGH*/
1260			default:
1261				p = strchr(types, c);
1262				if (p == NULL)
1263					goto badsub;
1264				subtype = p - types + VSNORMAL;
1265				break;
1266			case '%':
1267			case '#':
1268				{
1269					int cc = c;
1270					subtype = c == '#' ? VSTRIMLEFT :
1271							     VSTRIMRIGHT;
1272					c = pgetc();
1273					if (c == cc)
1274						subtype++;
1275					else
1276						pungetc();
1277					break;
1278				}
1279			}
1280		} else {
1281			pungetc();
1282		}
1283		if (subtype != VSLENGTH && (dblquote || arinest))
1284			flags |= VSQUOTE;
1285		*(stackblock() + typeloc) = subtype | flags;
1286		if (subtype != VSNORMAL)
1287			varnest++;
1288	}
1289	goto parsesub_return;
1290}
1291
1292
1293/*
1294 * Called to parse command substitutions.  Newstyle is set if the command
1295 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1296 * list of commands (passed by reference), and savelen is the number of
1297 * characters on the top of the stack which must be preserved.
1298 */
1299
1300parsebackq: {
1301	struct nodelist **nlpp;
1302	int savepbq;
1303	union node *n;
1304	char *volatile str;
1305	struct jmploc jmploc;
1306	struct jmploc *volatile savehandler;
1307	int savelen;
1308	int saveprompt;
1309#if __GNUC__
1310	/* Avoid longjmp clobbering */
1311	(void) &saveprompt;
1312#endif
1313
1314	savepbq = parsebackquote;
1315	if (setjmp(jmploc.loc)) {
1316		if (str)
1317			ckfree(str);
1318		parsebackquote = 0;
1319		handler = savehandler;
1320		longjmp(handler->loc, 1);
1321	}
1322	INTOFF;
1323	str = NULL;
1324	savelen = out - stackblock();
1325	if (savelen > 0) {
1326		str = ckmalloc(savelen);
1327		memcpy(str, stackblock(), savelen);
1328	}
1329	savehandler = handler;
1330	handler = &jmploc;
1331	INTON;
1332        if (oldstyle) {
1333                /* We must read until the closing backquote, giving special
1334                   treatment to some slashes, and then push the string and
1335                   reread it as input, interpreting it normally.  */
1336                char *out;
1337                int c;
1338                int savelen;
1339                char *str;
1340
1341
1342                STARTSTACKSTR(out);
1343		for (;;) {
1344			if (needprompt) {
1345				setprompt(2);
1346				needprompt = 0;
1347			}
1348			switch (c = pgetc()) {
1349			case '`':
1350				goto done;
1351
1352			case '\\':
1353                                if ((c = pgetc()) == '\n') {
1354					plinno++;
1355					if (doprompt)
1356						setprompt(2);
1357					else
1358						setprompt(0);
1359					/*
1360					 * If eating a newline, avoid putting
1361					 * the newline into the new character
1362					 * stream (via the STPUTC after the
1363					 * switch).
1364					 */
1365					continue;
1366				}
1367                                if (c != '\\' && c != '`' && c != '$'
1368                                    && (!dblquote || c != '"'))
1369                                        STPUTC('\\', out);
1370				break;
1371
1372			case '\n':
1373				plinno++;
1374				needprompt = doprompt;
1375				break;
1376
1377			case PEOF:
1378			        startlinno = plinno;
1379				synerror("EOF in backquote substitution");
1380 				break;
1381
1382			default:
1383				break;
1384			}
1385			STPUTC(c, out);
1386                }
1387done:
1388                STPUTC('\0', out);
1389                savelen = out - stackblock();
1390                if (savelen > 0) {
1391                        str = ckmalloc(savelen);
1392                        memcpy(str, stackblock(), savelen);
1393			setinputstring(str, 1);
1394                }
1395        }
1396	nlpp = &bqlist;
1397	while (*nlpp)
1398		nlpp = &(*nlpp)->next;
1399	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1400	(*nlpp)->next = NULL;
1401	parsebackquote = oldstyle;
1402
1403	if (oldstyle) {
1404		saveprompt = doprompt;
1405		doprompt = 0;
1406	}
1407
1408	n = list(0);
1409
1410	if (oldstyle)
1411		doprompt = saveprompt;
1412	else {
1413		if (readtoken() != TRP)
1414			synexpect(TRP);
1415	}
1416
1417	(*nlpp)->n = n;
1418        if (oldstyle) {
1419		/*
1420		 * Start reading from old file again, ignoring any pushed back
1421		 * tokens left from the backquote parsing
1422		 */
1423                popfile();
1424		tokpushback = 0;
1425	}
1426	while (stackblocksize() <= savelen)
1427		growstackblock();
1428	STARTSTACKSTR(out);
1429	if (str) {
1430		memcpy(out, str, savelen);
1431		STADJUST(savelen, out);
1432		INTOFF;
1433		ckfree(str);
1434		str = NULL;
1435		INTON;
1436	}
1437	parsebackquote = savepbq;
1438	handler = savehandler;
1439	if (arinest || dblquote)
1440		USTPUTC(CTLBACKQ | CTLQUOTE, out);
1441	else
1442		USTPUTC(CTLBACKQ, out);
1443	if (oldstyle)
1444		goto parsebackq_oldreturn;
1445	else
1446		goto parsebackq_newreturn;
1447}
1448
1449/*
1450 * Parse an arithmetic expansion (indicate start of one and set state)
1451 */
1452parsearith: {
1453
1454	if (++arinest == 1) {
1455		prevsyntax = syntax;
1456		syntax = ARISYNTAX;
1457		USTPUTC(CTLARI, out);
1458		if (dblquote)
1459			USTPUTC('"',out);
1460		else
1461			USTPUTC(' ',out);
1462	} else {
1463		/*
1464		 * we collapse embedded arithmetic expansion to
1465		 * parenthesis, which should be equivalent
1466		 */
1467		USTPUTC('(', out);
1468	}
1469	goto parsearith_return;
1470}
1471
1472} /* end of readtoken */
1473
1474
1475
1476#ifdef mkinit
1477RESET {
1478	tokpushback = 0;
1479	checkkwd = 0;
1480}
1481#endif
1482
1483/*
1484 * Returns true if the text contains nothing to expand (no dollar signs
1485 * or backquotes).
1486 */
1487
1488STATIC int
1489noexpand(char *text)
1490{
1491	char *p;
1492	char c;
1493
1494	p = text;
1495	while ((c = *p++) != '\0') {
1496		if ( c == CTLQUOTEMARK)
1497			continue;
1498		if (c == CTLESC)
1499			p++;
1500		else if (BASESYNTAX[(int)c] == CCTL)
1501			return 0;
1502	}
1503	return 1;
1504}
1505
1506
1507/*
1508 * Return true if the argument is a legal variable name (a letter or
1509 * underscore followed by zero or more letters, underscores, and digits).
1510 */
1511
1512int
1513goodname(char *name)
1514{
1515	char *p;
1516
1517	p = name;
1518	if (! is_name(*p))
1519		return 0;
1520	while (*++p) {
1521		if (! is_in_name(*p))
1522			return 0;
1523	}
1524	return 1;
1525}
1526
1527
1528/*
1529 * Called when an unexpected token is read during the parse.  The argument
1530 * is the token that is expected, or -1 if more than one type of token can
1531 * occur at this point.
1532 */
1533
1534STATIC void
1535synexpect(int token)
1536{
1537	char msg[64];
1538
1539	if (token >= 0) {
1540		fmtstr(msg, 64, "%s unexpected (expecting %s)",
1541			tokname[lasttoken], tokname[token]);
1542	} else {
1543		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1544	}
1545	synerror(msg);
1546}
1547
1548
1549STATIC void
1550synerror(char *msg)
1551{
1552	if (commandname)
1553		outfmt(&errout, "%s: %d: ", commandname, startlinno);
1554	outfmt(&errout, "Syntax error: %s\n", msg);
1555	error((char *)NULL);
1556}
1557
1558STATIC void
1559setprompt(int which)
1560{
1561	whichprompt = which;
1562
1563#ifndef NO_HISTORY
1564	if (!el)
1565#endif
1566		out2str(getprompt(NULL));
1567}
1568
1569/*
1570 * called by editline -- any expansions to the prompt
1571 *    should be added here.
1572 */
1573char *
1574getprompt(void *unused __unused)
1575{
1576	switch (whichprompt) {
1577	case 0:
1578		return "";
1579	case 1:
1580		return ps1val();
1581	case 2:
1582		return ps2val();
1583	default:
1584		return "<internal prompt error>";
1585	}
1586}
1587