xref: /minix3/bin/sh/parser.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: parser.c,v 1.93 2014/08/29 09:35:19 christos Exp $	*/
2d90bee97SLionel Sambuc 
3d90bee97SLionel Sambuc /*-
4d90bee97SLionel Sambuc  * Copyright (c) 1991, 1993
5d90bee97SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
6d90bee97SLionel Sambuc  *
7d90bee97SLionel Sambuc  * This code is derived from software contributed to Berkeley by
8d90bee97SLionel Sambuc  * Kenneth Almquist.
9d90bee97SLionel Sambuc  *
10d90bee97SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11d90bee97SLionel Sambuc  * modification, are permitted provided that the following conditions
12d90bee97SLionel Sambuc  * are met:
13d90bee97SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14d90bee97SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15d90bee97SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16d90bee97SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17d90bee97SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18d90bee97SLionel Sambuc  * 3. Neither the name of the University nor the names of its contributors
19d90bee97SLionel Sambuc  *    may be used to endorse or promote products derived from this software
20d90bee97SLionel Sambuc  *    without specific prior written permission.
21d90bee97SLionel Sambuc  *
22d90bee97SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23d90bee97SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24d90bee97SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25d90bee97SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26d90bee97SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27d90bee97SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28d90bee97SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29d90bee97SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30d90bee97SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31d90bee97SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32d90bee97SLionel Sambuc  * SUCH DAMAGE.
33d90bee97SLionel Sambuc  */
34d90bee97SLionel Sambuc 
35d90bee97SLionel Sambuc #include <sys/cdefs.h>
36d90bee97SLionel Sambuc #ifndef lint
37d90bee97SLionel Sambuc #if 0
38d90bee97SLionel Sambuc static char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
39d90bee97SLionel Sambuc #else
40*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: parser.c,v 1.93 2014/08/29 09:35:19 christos Exp $");
41d90bee97SLionel Sambuc #endif
42d90bee97SLionel Sambuc #endif /* not lint */
43d90bee97SLionel Sambuc 
44d90bee97SLionel Sambuc #include <stdio.h>
45d90bee97SLionel Sambuc #include <stdlib.h>
46d90bee97SLionel Sambuc #include <limits.h>
47d90bee97SLionel Sambuc 
48d90bee97SLionel Sambuc #include "shell.h"
49d90bee97SLionel Sambuc #include "parser.h"
50d90bee97SLionel Sambuc #include "nodes.h"
51d90bee97SLionel Sambuc #include "expand.h"	/* defines rmescapes() */
52d90bee97SLionel Sambuc #include "eval.h"	/* defines commandname */
53d90bee97SLionel Sambuc #include "redir.h"	/* defines copyfd() */
54d90bee97SLionel Sambuc #include "syntax.h"
55d90bee97SLionel Sambuc #include "options.h"
56d90bee97SLionel Sambuc #include "input.h"
57d90bee97SLionel Sambuc #include "output.h"
58d90bee97SLionel Sambuc #include "var.h"
59d90bee97SLionel Sambuc #include "error.h"
60d90bee97SLionel Sambuc #include "memalloc.h"
61d90bee97SLionel Sambuc #include "mystring.h"
62d90bee97SLionel Sambuc #include "alias.h"
63d90bee97SLionel Sambuc #include "show.h"
64d90bee97SLionel Sambuc #ifndef SMALL
65d90bee97SLionel Sambuc #include "myhistedit.h"
66d90bee97SLionel Sambuc #endif
67d90bee97SLionel Sambuc 
68d90bee97SLionel Sambuc /*
69d90bee97SLionel Sambuc  * Shell command parser.
70d90bee97SLionel Sambuc  */
71d90bee97SLionel Sambuc 
72d90bee97SLionel Sambuc #define EOFMARKLEN 79
73d90bee97SLionel Sambuc 
74d90bee97SLionel Sambuc /* values returned by readtoken */
75d90bee97SLionel Sambuc #include "token.h"
76d90bee97SLionel Sambuc 
77d90bee97SLionel Sambuc #define OPENBRACE '{'
78d90bee97SLionel Sambuc #define CLOSEBRACE '}'
79d90bee97SLionel Sambuc 
80d90bee97SLionel Sambuc 
81d90bee97SLionel Sambuc struct heredoc {
82d90bee97SLionel Sambuc 	struct heredoc *next;	/* next here document in list */
83d90bee97SLionel Sambuc 	union node *here;		/* redirection node */
84d90bee97SLionel Sambuc 	char *eofmark;		/* string indicating end of input */
85d90bee97SLionel Sambuc 	int striptabs;		/* if set, strip leading tabs */
86d90bee97SLionel Sambuc };
87d90bee97SLionel Sambuc 
88d90bee97SLionel Sambuc 
89d90bee97SLionel Sambuc 
90d90bee97SLionel Sambuc static int noalias = 0;		/* when set, don't handle aliases */
91d90bee97SLionel Sambuc struct heredoc *heredoclist;	/* list of here documents to read */
92d90bee97SLionel Sambuc int parsebackquote;		/* nonzero if we are inside backquotes */
93d90bee97SLionel Sambuc int doprompt;			/* if set, prompt the user */
94d90bee97SLionel Sambuc int needprompt;			/* true if interactive and at start of line */
95d90bee97SLionel Sambuc int lasttoken;			/* last token read */
96d90bee97SLionel Sambuc MKINIT int tokpushback;		/* last token pushed back */
97d90bee97SLionel Sambuc char *wordtext;			/* text of last word returned by readtoken */
98d90bee97SLionel Sambuc MKINIT int checkkwd;		/* 1 == check for kwds, 2 == also eat newlines */
99d90bee97SLionel Sambuc struct nodelist *backquotelist;
100d90bee97SLionel Sambuc union node *redirnode;
101d90bee97SLionel Sambuc struct heredoc *heredoc;
102d90bee97SLionel Sambuc int quoteflag;			/* set if (part of) last token was quoted */
103d90bee97SLionel Sambuc int startlinno;			/* line # where last token started */
104d90bee97SLionel Sambuc int funclinno;			/* line # where the current function started */
105d90bee97SLionel Sambuc 
106d90bee97SLionel Sambuc 
107d90bee97SLionel Sambuc STATIC union node *list(int, int);
108d90bee97SLionel Sambuc STATIC union node *andor(void);
109d90bee97SLionel Sambuc STATIC union node *pipeline(void);
110d90bee97SLionel Sambuc STATIC union node *command(void);
111d90bee97SLionel Sambuc STATIC union node *simplecmd(union node **, union node *);
112d90bee97SLionel Sambuc STATIC union node *makename(void);
113d90bee97SLionel Sambuc STATIC void parsefname(void);
114d90bee97SLionel Sambuc STATIC void parseheredoc(void);
115d90bee97SLionel Sambuc STATIC int peektoken(void);
116d90bee97SLionel Sambuc STATIC int readtoken(void);
117d90bee97SLionel Sambuc STATIC int xxreadtoken(void);
118d90bee97SLionel Sambuc STATIC int readtoken1(int, char const *, char *, int);
119d90bee97SLionel Sambuc STATIC int noexpand(char *);
120d90bee97SLionel Sambuc STATIC void synexpect(int) __dead;
121d90bee97SLionel Sambuc STATIC void synerror(const char *) __dead;
122d90bee97SLionel Sambuc STATIC void setprompt(int);
123d90bee97SLionel Sambuc 
124d90bee97SLionel Sambuc 
125d90bee97SLionel Sambuc /*
126d90bee97SLionel Sambuc  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
127d90bee97SLionel Sambuc  * valid parse tree indicating a blank line.)
128d90bee97SLionel Sambuc  */
129d90bee97SLionel Sambuc 
130d90bee97SLionel Sambuc union node *
parsecmd(int interact)131d90bee97SLionel Sambuc parsecmd(int interact)
132d90bee97SLionel Sambuc {
133d90bee97SLionel Sambuc 	int t;
134d90bee97SLionel Sambuc 
135d90bee97SLionel Sambuc 	tokpushback = 0;
136d90bee97SLionel Sambuc 	doprompt = interact;
137d90bee97SLionel Sambuc 	if (doprompt)
138d90bee97SLionel Sambuc 		setprompt(1);
139d90bee97SLionel Sambuc 	else
140d90bee97SLionel Sambuc 		setprompt(0);
141d90bee97SLionel Sambuc 	needprompt = 0;
142d90bee97SLionel Sambuc 	t = readtoken();
143d90bee97SLionel Sambuc 	if (t == TEOF)
144d90bee97SLionel Sambuc 		return NEOF;
145d90bee97SLionel Sambuc 	if (t == TNL)
146d90bee97SLionel Sambuc 		return NULL;
147d90bee97SLionel Sambuc 	tokpushback++;
148d90bee97SLionel Sambuc 	return list(1, 0);
149d90bee97SLionel Sambuc }
150d90bee97SLionel Sambuc 
151d90bee97SLionel Sambuc 
152d90bee97SLionel Sambuc STATIC union node *
list(int nlflag,int erflag)153d90bee97SLionel Sambuc list(int nlflag, int erflag)
154d90bee97SLionel Sambuc {
155d90bee97SLionel Sambuc 	union node *n1, *n2, *n3;
156d90bee97SLionel Sambuc 	int tok;
157d90bee97SLionel Sambuc 	TRACE(("list: entered\n"));
158d90bee97SLionel Sambuc 
159d90bee97SLionel Sambuc 	checkkwd = 2;
160d90bee97SLionel Sambuc 	if (nlflag == 0 && tokendlist[peektoken()])
161d90bee97SLionel Sambuc 		return NULL;
162d90bee97SLionel Sambuc 	n1 = NULL;
163d90bee97SLionel Sambuc 	for (;;) {
164d90bee97SLionel Sambuc 		n2 = andor();
165d90bee97SLionel Sambuc 		tok = readtoken();
166d90bee97SLionel Sambuc 		if (tok == TBACKGND) {
167d90bee97SLionel Sambuc 			if (n2->type == NCMD || n2->type == NPIPE) {
168d90bee97SLionel Sambuc 				n2->ncmd.backgnd = 1;
169d90bee97SLionel Sambuc 			} else if (n2->type == NREDIR) {
170d90bee97SLionel Sambuc 				n2->type = NBACKGND;
171d90bee97SLionel Sambuc 			} else {
172d90bee97SLionel Sambuc 				n3 = (union node *)stalloc(sizeof (struct nredir));
173d90bee97SLionel Sambuc 				n3->type = NBACKGND;
174d90bee97SLionel Sambuc 				n3->nredir.n = n2;
175d90bee97SLionel Sambuc 				n3->nredir.redirect = NULL;
176d90bee97SLionel Sambuc 				n2 = n3;
177d90bee97SLionel Sambuc 			}
178d90bee97SLionel Sambuc 		}
179d90bee97SLionel Sambuc 		if (n1 == NULL) {
180d90bee97SLionel Sambuc 			n1 = n2;
181d90bee97SLionel Sambuc 		}
182d90bee97SLionel Sambuc 		else {
183d90bee97SLionel Sambuc 			n3 = (union node *)stalloc(sizeof (struct nbinary));
184d90bee97SLionel Sambuc 			n3->type = NSEMI;
185d90bee97SLionel Sambuc 			n3->nbinary.ch1 = n1;
186d90bee97SLionel Sambuc 			n3->nbinary.ch2 = n2;
187d90bee97SLionel Sambuc 			n1 = n3;
188d90bee97SLionel Sambuc 		}
189d90bee97SLionel Sambuc 		switch (tok) {
190d90bee97SLionel Sambuc 		case TBACKGND:
191d90bee97SLionel Sambuc 		case TSEMI:
192d90bee97SLionel Sambuc 			tok = readtoken();
193d90bee97SLionel Sambuc 			/* fall through */
194d90bee97SLionel Sambuc 		case TNL:
195d90bee97SLionel Sambuc 			if (tok == TNL) {
196d90bee97SLionel Sambuc 				parseheredoc();
197d90bee97SLionel Sambuc 				if (nlflag)
198d90bee97SLionel Sambuc 					return n1;
199d90bee97SLionel Sambuc 			} else {
200d90bee97SLionel Sambuc 				tokpushback++;
201d90bee97SLionel Sambuc 			}
202d90bee97SLionel Sambuc 			checkkwd = 2;
203d90bee97SLionel Sambuc 			if (tokendlist[peektoken()])
204d90bee97SLionel Sambuc 				return n1;
205d90bee97SLionel Sambuc 			break;
206d90bee97SLionel Sambuc 		case TEOF:
207d90bee97SLionel Sambuc 			if (heredoclist)
208d90bee97SLionel Sambuc 				parseheredoc();
209d90bee97SLionel Sambuc 			else
210d90bee97SLionel Sambuc 				pungetc();		/* push back EOF on input */
211d90bee97SLionel Sambuc 			return n1;
212d90bee97SLionel Sambuc 		default:
213d90bee97SLionel Sambuc 			if (nlflag || erflag)
214d90bee97SLionel Sambuc 				synexpect(-1);
215d90bee97SLionel Sambuc 			tokpushback++;
216d90bee97SLionel Sambuc 			return n1;
217d90bee97SLionel Sambuc 		}
218d90bee97SLionel Sambuc 	}
219d90bee97SLionel Sambuc }
220d90bee97SLionel Sambuc 
221d90bee97SLionel Sambuc 
222d90bee97SLionel Sambuc 
223d90bee97SLionel Sambuc STATIC union node *
andor(void)224d90bee97SLionel Sambuc andor(void)
225d90bee97SLionel Sambuc {
226d90bee97SLionel Sambuc 	union node *n1, *n2, *n3;
227d90bee97SLionel Sambuc 	int t;
228d90bee97SLionel Sambuc 
229d90bee97SLionel Sambuc 	TRACE(("andor: entered\n"));
230d90bee97SLionel Sambuc 	n1 = pipeline();
231d90bee97SLionel Sambuc 	for (;;) {
232d90bee97SLionel Sambuc 		if ((t = readtoken()) == TAND) {
233d90bee97SLionel Sambuc 			t = NAND;
234d90bee97SLionel Sambuc 		} else if (t == TOR) {
235d90bee97SLionel Sambuc 			t = NOR;
236d90bee97SLionel Sambuc 		} else {
237d90bee97SLionel Sambuc 			tokpushback++;
238d90bee97SLionel Sambuc 			return n1;
239d90bee97SLionel Sambuc 		}
240d90bee97SLionel Sambuc 		n2 = pipeline();
241d90bee97SLionel Sambuc 		n3 = (union node *)stalloc(sizeof (struct nbinary));
242d90bee97SLionel Sambuc 		n3->type = t;
243d90bee97SLionel Sambuc 		n3->nbinary.ch1 = n1;
244d90bee97SLionel Sambuc 		n3->nbinary.ch2 = n2;
245d90bee97SLionel Sambuc 		n1 = n3;
246d90bee97SLionel Sambuc 	}
247d90bee97SLionel Sambuc }
248d90bee97SLionel Sambuc 
249d90bee97SLionel Sambuc 
250d90bee97SLionel Sambuc 
251d90bee97SLionel Sambuc STATIC union node *
pipeline(void)252d90bee97SLionel Sambuc pipeline(void)
253d90bee97SLionel Sambuc {
254d90bee97SLionel Sambuc 	union node *n1, *n2, *pipenode;
255d90bee97SLionel Sambuc 	struct nodelist *lp, *prev;
256d90bee97SLionel Sambuc 	int negate;
257d90bee97SLionel Sambuc 
258d90bee97SLionel Sambuc 	TRACE(("pipeline: entered\n"));
259d90bee97SLionel Sambuc 
260d90bee97SLionel Sambuc 	negate = 0;
261d90bee97SLionel Sambuc 	checkkwd = 2;
262d90bee97SLionel Sambuc 	while (readtoken() == TNOT) {
263d90bee97SLionel Sambuc 		TRACE(("pipeline: TNOT recognized\n"));
264d90bee97SLionel Sambuc 		negate = !negate;
265d90bee97SLionel Sambuc 	}
266d90bee97SLionel Sambuc 	tokpushback++;
267d90bee97SLionel Sambuc 	n1 = command();
268d90bee97SLionel Sambuc 	if (readtoken() == TPIPE) {
269d90bee97SLionel Sambuc 		pipenode = (union node *)stalloc(sizeof (struct npipe));
270d90bee97SLionel Sambuc 		pipenode->type = NPIPE;
271d90bee97SLionel Sambuc 		pipenode->npipe.backgnd = 0;
272d90bee97SLionel Sambuc 		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
273d90bee97SLionel Sambuc 		pipenode->npipe.cmdlist = lp;
274d90bee97SLionel Sambuc 		lp->n = n1;
275d90bee97SLionel Sambuc 		do {
276d90bee97SLionel Sambuc 			prev = lp;
277d90bee97SLionel Sambuc 			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
278d90bee97SLionel Sambuc 			lp->n = command();
279d90bee97SLionel Sambuc 			prev->next = lp;
280d90bee97SLionel Sambuc 		} while (readtoken() == TPIPE);
281d90bee97SLionel Sambuc 		lp->next = NULL;
282d90bee97SLionel Sambuc 		n1 = pipenode;
283d90bee97SLionel Sambuc 	}
284d90bee97SLionel Sambuc 	tokpushback++;
285d90bee97SLionel Sambuc 	if (negate) {
286d90bee97SLionel Sambuc 		TRACE(("negate pipeline\n"));
287d90bee97SLionel Sambuc 		n2 = (union node *)stalloc(sizeof (struct nnot));
288d90bee97SLionel Sambuc 		n2->type = NNOT;
289d90bee97SLionel Sambuc 		n2->nnot.com = n1;
290d90bee97SLionel Sambuc 		return n2;
291d90bee97SLionel Sambuc 	} else
292d90bee97SLionel Sambuc 		return n1;
293d90bee97SLionel Sambuc }
294d90bee97SLionel Sambuc 
295d90bee97SLionel Sambuc 
296d90bee97SLionel Sambuc 
297d90bee97SLionel Sambuc STATIC union node *
command(void)298d90bee97SLionel Sambuc command(void)
299d90bee97SLionel Sambuc {
300d90bee97SLionel Sambuc 	union node *n1, *n2;
301d90bee97SLionel Sambuc 	union node *ap, **app;
302d90bee97SLionel Sambuc 	union node *cp, **cpp;
303d90bee97SLionel Sambuc 	union node *redir, **rpp;
304d90bee97SLionel Sambuc 	int t, negate = 0;
305d90bee97SLionel Sambuc 
306d90bee97SLionel Sambuc 	TRACE(("command: entered\n"));
307d90bee97SLionel Sambuc 
308d90bee97SLionel Sambuc 	checkkwd = 2;
309d90bee97SLionel Sambuc 	redir = NULL;
310d90bee97SLionel Sambuc 	n1 = NULL;
311d90bee97SLionel Sambuc 	rpp = &redir;
312d90bee97SLionel Sambuc 
313d90bee97SLionel Sambuc 	/* Check for redirection which may precede command */
314d90bee97SLionel Sambuc 	while (readtoken() == TREDIR) {
315d90bee97SLionel Sambuc 		*rpp = n2 = redirnode;
316d90bee97SLionel Sambuc 		rpp = &n2->nfile.next;
317d90bee97SLionel Sambuc 		parsefname();
318d90bee97SLionel Sambuc 	}
319d90bee97SLionel Sambuc 	tokpushback++;
320d90bee97SLionel Sambuc 
321d90bee97SLionel Sambuc 	while (readtoken() == TNOT) {
322d90bee97SLionel Sambuc 		TRACE(("command: TNOT recognized\n"));
323d90bee97SLionel Sambuc 		negate = !negate;
324d90bee97SLionel Sambuc 	}
325d90bee97SLionel Sambuc 	tokpushback++;
326d90bee97SLionel Sambuc 
327d90bee97SLionel Sambuc 	switch (readtoken()) {
328d90bee97SLionel Sambuc 	case TIF:
329d90bee97SLionel Sambuc 		n1 = (union node *)stalloc(sizeof (struct nif));
330d90bee97SLionel Sambuc 		n1->type = NIF;
331d90bee97SLionel Sambuc 		n1->nif.test = list(0, 0);
332d90bee97SLionel Sambuc 		if (readtoken() != TTHEN)
333d90bee97SLionel Sambuc 			synexpect(TTHEN);
334d90bee97SLionel Sambuc 		n1->nif.ifpart = list(0, 0);
335d90bee97SLionel Sambuc 		n2 = n1;
336d90bee97SLionel Sambuc 		while (readtoken() == TELIF) {
337d90bee97SLionel Sambuc 			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
338d90bee97SLionel Sambuc 			n2 = n2->nif.elsepart;
339d90bee97SLionel Sambuc 			n2->type = NIF;
340d90bee97SLionel Sambuc 			n2->nif.test = list(0, 0);
341d90bee97SLionel Sambuc 			if (readtoken() != TTHEN)
342d90bee97SLionel Sambuc 				synexpect(TTHEN);
343d90bee97SLionel Sambuc 			n2->nif.ifpart = list(0, 0);
344d90bee97SLionel Sambuc 		}
345d90bee97SLionel Sambuc 		if (lasttoken == TELSE)
346d90bee97SLionel Sambuc 			n2->nif.elsepart = list(0, 0);
347d90bee97SLionel Sambuc 		else {
348d90bee97SLionel Sambuc 			n2->nif.elsepart = NULL;
349d90bee97SLionel Sambuc 			tokpushback++;
350d90bee97SLionel Sambuc 		}
351d90bee97SLionel Sambuc 		if (readtoken() != TFI)
352d90bee97SLionel Sambuc 			synexpect(TFI);
353d90bee97SLionel Sambuc 		checkkwd = 1;
354d90bee97SLionel Sambuc 		break;
355d90bee97SLionel Sambuc 	case TWHILE:
356d90bee97SLionel Sambuc 	case TUNTIL: {
357d90bee97SLionel Sambuc 		int got;
358d90bee97SLionel Sambuc 		n1 = (union node *)stalloc(sizeof (struct nbinary));
359d90bee97SLionel Sambuc 		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
360d90bee97SLionel Sambuc 		n1->nbinary.ch1 = list(0, 0);
361d90bee97SLionel Sambuc 		if ((got=readtoken()) != TDO) {
362d90bee97SLionel Sambuc TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
363d90bee97SLionel Sambuc 			synexpect(TDO);
364d90bee97SLionel Sambuc 		}
365d90bee97SLionel Sambuc 		n1->nbinary.ch2 = list(0, 0);
366d90bee97SLionel Sambuc 		if (readtoken() != TDONE)
367d90bee97SLionel Sambuc 			synexpect(TDONE);
368d90bee97SLionel Sambuc 		checkkwd = 1;
369d90bee97SLionel Sambuc 		break;
370d90bee97SLionel Sambuc 	}
371d90bee97SLionel Sambuc 	case TFOR:
372d90bee97SLionel Sambuc 		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
373d90bee97SLionel Sambuc 			synerror("Bad for loop variable");
374d90bee97SLionel Sambuc 		n1 = (union node *)stalloc(sizeof (struct nfor));
375d90bee97SLionel Sambuc 		n1->type = NFOR;
376d90bee97SLionel Sambuc 		n1->nfor.var = wordtext;
377d90bee97SLionel Sambuc 		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
378d90bee97SLionel Sambuc 			app = &ap;
379d90bee97SLionel Sambuc 			while (readtoken() == TWORD) {
380d90bee97SLionel Sambuc 				n2 = (union node *)stalloc(sizeof (struct narg));
381d90bee97SLionel Sambuc 				n2->type = NARG;
382d90bee97SLionel Sambuc 				n2->narg.text = wordtext;
383d90bee97SLionel Sambuc 				n2->narg.backquote = backquotelist;
384d90bee97SLionel Sambuc 				*app = n2;
385d90bee97SLionel Sambuc 				app = &n2->narg.next;
386d90bee97SLionel Sambuc 			}
387d90bee97SLionel Sambuc 			*app = NULL;
388d90bee97SLionel Sambuc 			n1->nfor.args = ap;
389d90bee97SLionel Sambuc 			if (lasttoken != TNL && lasttoken != TSEMI)
390d90bee97SLionel Sambuc 				synexpect(-1);
391d90bee97SLionel Sambuc 		} else {
392d90bee97SLionel Sambuc 			static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
393d90bee97SLionel Sambuc 								   '@', '=', '\0'};
394d90bee97SLionel Sambuc 			n2 = (union node *)stalloc(sizeof (struct narg));
395d90bee97SLionel Sambuc 			n2->type = NARG;
396d90bee97SLionel Sambuc 			n2->narg.text = argvars;
397d90bee97SLionel Sambuc 			n2->narg.backquote = NULL;
398d90bee97SLionel Sambuc 			n2->narg.next = NULL;
399d90bee97SLionel Sambuc 			n1->nfor.args = n2;
400d90bee97SLionel Sambuc 			/*
401d90bee97SLionel Sambuc 			 * Newline or semicolon here is optional (but note
402d90bee97SLionel Sambuc 			 * that the original Bourne shell only allowed NL).
403d90bee97SLionel Sambuc 			 */
404d90bee97SLionel Sambuc 			if (lasttoken != TNL && lasttoken != TSEMI)
405d90bee97SLionel Sambuc 				tokpushback++;
406d90bee97SLionel Sambuc 		}
407d90bee97SLionel Sambuc 		checkkwd = 2;
408d90bee97SLionel Sambuc 		if ((t = readtoken()) == TDO)
409d90bee97SLionel Sambuc 			t = TDONE;
410d90bee97SLionel Sambuc 		else if (t == TBEGIN)
411d90bee97SLionel Sambuc 			t = TEND;
412d90bee97SLionel Sambuc 		else
413d90bee97SLionel Sambuc 			synexpect(-1);
414d90bee97SLionel Sambuc 		n1->nfor.body = list(0, 0);
415d90bee97SLionel Sambuc 		if (readtoken() != t)
416d90bee97SLionel Sambuc 			synexpect(t);
417d90bee97SLionel Sambuc 		checkkwd = 1;
418d90bee97SLionel Sambuc 		break;
419d90bee97SLionel Sambuc 	case TCASE:
420d90bee97SLionel Sambuc 		n1 = (union node *)stalloc(sizeof (struct ncase));
421d90bee97SLionel Sambuc 		n1->type = NCASE;
422d90bee97SLionel Sambuc 		if (readtoken() != TWORD)
423d90bee97SLionel Sambuc 			synexpect(TWORD);
424d90bee97SLionel Sambuc 		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
425d90bee97SLionel Sambuc 		n2->type = NARG;
426d90bee97SLionel Sambuc 		n2->narg.text = wordtext;
427d90bee97SLionel Sambuc 		n2->narg.backquote = backquotelist;
428d90bee97SLionel Sambuc 		n2->narg.next = NULL;
429d90bee97SLionel Sambuc 		while (readtoken() == TNL);
430d90bee97SLionel Sambuc 		if (lasttoken != TWORD || ! equal(wordtext, "in"))
431d90bee97SLionel Sambuc 			synerror("expecting \"in\"");
432d90bee97SLionel Sambuc 		cpp = &n1->ncase.cases;
433d90bee97SLionel Sambuc 		noalias = 1;
434d90bee97SLionel Sambuc 		checkkwd = 2, readtoken();
435*0a6a1f1dSLionel Sambuc 		/*
436*0a6a1f1dSLionel Sambuc 		 * Both ksh and bash accept 'case x in esac'
437*0a6a1f1dSLionel Sambuc 		 * so configure scripts started taking advantage of this.
438*0a6a1f1dSLionel Sambuc 		 * The page: http://pubs.opengroup.org/onlinepubs/\
439*0a6a1f1dSLionel Sambuc 		 * 009695399/utilities/xcu_chap02.html contradicts itself,
440*0a6a1f1dSLionel Sambuc 		 * as to if this is legal; the "Case Conditional Format"
441*0a6a1f1dSLionel Sambuc 		 * paragraph shows one case is required, but the "Grammar"
442*0a6a1f1dSLionel Sambuc 		 * section shows a grammar that explicitly allows the no
443*0a6a1f1dSLionel Sambuc 		 * case option.
444*0a6a1f1dSLionel Sambuc 		 */
445*0a6a1f1dSLionel Sambuc 		while (lasttoken != TESAC) {
446d90bee97SLionel Sambuc 			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
447d90bee97SLionel Sambuc 			if (lasttoken == TLP)
448d90bee97SLionel Sambuc 				readtoken();
449d90bee97SLionel Sambuc 			cp->type = NCLIST;
450d90bee97SLionel Sambuc 			app = &cp->nclist.pattern;
451d90bee97SLionel Sambuc 			for (;;) {
452d90bee97SLionel Sambuc 				*app = ap = (union node *)stalloc(sizeof (struct narg));
453d90bee97SLionel Sambuc 				ap->type = NARG;
454d90bee97SLionel Sambuc 				ap->narg.text = wordtext;
455d90bee97SLionel Sambuc 				ap->narg.backquote = backquotelist;
456d90bee97SLionel Sambuc 				if (checkkwd = 2, readtoken() != TPIPE)
457d90bee97SLionel Sambuc 					break;
458d90bee97SLionel Sambuc 				app = &ap->narg.next;
459d90bee97SLionel Sambuc 				readtoken();
460d90bee97SLionel Sambuc 			}
461d90bee97SLionel Sambuc 			ap->narg.next = NULL;
462d90bee97SLionel Sambuc 			noalias = 0;
463d90bee97SLionel Sambuc 			if (lasttoken != TRP) {
464d90bee97SLionel Sambuc 				synexpect(TRP);
465d90bee97SLionel Sambuc 			}
466d90bee97SLionel Sambuc 			cp->nclist.body = list(0, 0);
467d90bee97SLionel Sambuc 
468d90bee97SLionel Sambuc 			checkkwd = 2;
469d90bee97SLionel Sambuc 			if ((t = readtoken()) != TESAC) {
470d90bee97SLionel Sambuc 				if (t != TENDCASE) {
471d90bee97SLionel Sambuc 					noalias = 0;
472d90bee97SLionel Sambuc 					synexpect(TENDCASE);
473d90bee97SLionel Sambuc 				} else {
474d90bee97SLionel Sambuc 					noalias = 1;
475d90bee97SLionel Sambuc 					checkkwd = 2;
476d90bee97SLionel Sambuc 					readtoken();
477d90bee97SLionel Sambuc 				}
478d90bee97SLionel Sambuc 			}
479d90bee97SLionel Sambuc 			cpp = &cp->nclist.next;
480*0a6a1f1dSLionel Sambuc 		}
481d90bee97SLionel Sambuc 		noalias = 0;
482d90bee97SLionel Sambuc 		*cpp = NULL;
483d90bee97SLionel Sambuc 		checkkwd = 1;
484d90bee97SLionel Sambuc 		break;
485d90bee97SLionel Sambuc 	case TLP:
486d90bee97SLionel Sambuc 		n1 = (union node *)stalloc(sizeof (struct nredir));
487d90bee97SLionel Sambuc 		n1->type = NSUBSHELL;
488d90bee97SLionel Sambuc 		n1->nredir.n = list(0, 0);
489d90bee97SLionel Sambuc 		n1->nredir.redirect = NULL;
490d90bee97SLionel Sambuc 		if (readtoken() != TRP)
491d90bee97SLionel Sambuc 			synexpect(TRP);
492d90bee97SLionel Sambuc 		checkkwd = 1;
493d90bee97SLionel Sambuc 		break;
494d90bee97SLionel Sambuc 	case TBEGIN:
495d90bee97SLionel Sambuc 		n1 = list(0, 0);
496d90bee97SLionel Sambuc 		if (readtoken() != TEND)
497d90bee97SLionel Sambuc 			synexpect(TEND);
498d90bee97SLionel Sambuc 		checkkwd = 1;
499d90bee97SLionel Sambuc 		break;
500d90bee97SLionel Sambuc 	/* Handle an empty command like other simple commands.  */
501d90bee97SLionel Sambuc 	case TSEMI:
502d90bee97SLionel Sambuc 		/*
503d90bee97SLionel Sambuc 		 * An empty command before a ; doesn't make much sense, and
504d90bee97SLionel Sambuc 		 * should certainly be disallowed in the case of `if ;'.
505d90bee97SLionel Sambuc 		 */
506d90bee97SLionel Sambuc 		if (!redir)
507d90bee97SLionel Sambuc 			synexpect(-1);
508d90bee97SLionel Sambuc 	case TAND:
509d90bee97SLionel Sambuc 	case TOR:
510d90bee97SLionel Sambuc 	case TNL:
511d90bee97SLionel Sambuc 	case TEOF:
512d90bee97SLionel Sambuc 	case TWORD:
513d90bee97SLionel Sambuc 	case TRP:
514d90bee97SLionel Sambuc 		tokpushback++;
515d90bee97SLionel Sambuc 		n1 = simplecmd(rpp, redir);
516d90bee97SLionel Sambuc 		goto checkneg;
517d90bee97SLionel Sambuc 	default:
518d90bee97SLionel Sambuc 		synexpect(-1);
519d90bee97SLionel Sambuc 		/* NOTREACHED */
520d90bee97SLionel Sambuc 	}
521d90bee97SLionel Sambuc 
522d90bee97SLionel Sambuc 	/* Now check for redirection which may follow command */
523d90bee97SLionel Sambuc 	while (readtoken() == TREDIR) {
524d90bee97SLionel Sambuc 		*rpp = n2 = redirnode;
525d90bee97SLionel Sambuc 		rpp = &n2->nfile.next;
526d90bee97SLionel Sambuc 		parsefname();
527d90bee97SLionel Sambuc 	}
528d90bee97SLionel Sambuc 	tokpushback++;
529d90bee97SLionel Sambuc 	*rpp = NULL;
530d90bee97SLionel Sambuc 	if (redir) {
531d90bee97SLionel Sambuc 		if (n1->type != NSUBSHELL) {
532d90bee97SLionel Sambuc 			n2 = (union node *)stalloc(sizeof (struct nredir));
533d90bee97SLionel Sambuc 			n2->type = NREDIR;
534d90bee97SLionel Sambuc 			n2->nredir.n = n1;
535d90bee97SLionel Sambuc 			n1 = n2;
536d90bee97SLionel Sambuc 		}
537d90bee97SLionel Sambuc 		n1->nredir.redirect = redir;
538d90bee97SLionel Sambuc 	}
539d90bee97SLionel Sambuc 
540d90bee97SLionel Sambuc checkneg:
541d90bee97SLionel Sambuc 	if (negate) {
542d90bee97SLionel Sambuc 		TRACE(("negate command\n"));
543d90bee97SLionel Sambuc 		n2 = (union node *)stalloc(sizeof (struct nnot));
544d90bee97SLionel Sambuc 		n2->type = NNOT;
545d90bee97SLionel Sambuc 		n2->nnot.com = n1;
546d90bee97SLionel Sambuc 		return n2;
547d90bee97SLionel Sambuc 	}
548d90bee97SLionel Sambuc 	else
549d90bee97SLionel Sambuc 		return n1;
550d90bee97SLionel Sambuc }
551d90bee97SLionel Sambuc 
552d90bee97SLionel Sambuc 
553d90bee97SLionel Sambuc STATIC union node *
simplecmd(union node ** rpp,union node * redir)554d90bee97SLionel Sambuc simplecmd(union node **rpp, union node *redir)
555d90bee97SLionel Sambuc {
556d90bee97SLionel Sambuc 	union node *args, **app;
557d90bee97SLionel Sambuc 	union node **orig_rpp = rpp;
558d90bee97SLionel Sambuc 	union node *n = NULL, *n2;
559d90bee97SLionel Sambuc 	int negate = 0;
560d90bee97SLionel Sambuc 
561d90bee97SLionel Sambuc 	/* If we don't have any redirections already, then we must reset */
562d90bee97SLionel Sambuc 	/* rpp to be the address of the local redir variable.  */
563d90bee97SLionel Sambuc 	if (redir == 0)
564d90bee97SLionel Sambuc 		rpp = &redir;
565d90bee97SLionel Sambuc 
566d90bee97SLionel Sambuc 	args = NULL;
567d90bee97SLionel Sambuc 	app = &args;
568d90bee97SLionel Sambuc 	/*
569d90bee97SLionel Sambuc 	 * We save the incoming value, because we need this for shell
570d90bee97SLionel Sambuc 	 * functions.  There can not be a redirect or an argument between
571d90bee97SLionel Sambuc 	 * the function name and the open parenthesis.
572d90bee97SLionel Sambuc 	 */
573d90bee97SLionel Sambuc 	orig_rpp = rpp;
574d90bee97SLionel Sambuc 
575d90bee97SLionel Sambuc 	while (readtoken() == TNOT) {
576d90bee97SLionel Sambuc 		TRACE(("simplcmd: TNOT recognized\n"));
577d90bee97SLionel Sambuc 		negate = !negate;
578d90bee97SLionel Sambuc 	}
579d90bee97SLionel Sambuc 	tokpushback++;
580d90bee97SLionel Sambuc 
581d90bee97SLionel Sambuc 	for (;;) {
582d90bee97SLionel Sambuc 		if (readtoken() == TWORD) {
583d90bee97SLionel Sambuc 			n = (union node *)stalloc(sizeof (struct narg));
584d90bee97SLionel Sambuc 			n->type = NARG;
585d90bee97SLionel Sambuc 			n->narg.text = wordtext;
586d90bee97SLionel Sambuc 			n->narg.backquote = backquotelist;
587d90bee97SLionel Sambuc 			*app = n;
588d90bee97SLionel Sambuc 			app = &n->narg.next;
589d90bee97SLionel Sambuc 		} else if (lasttoken == TREDIR) {
590d90bee97SLionel Sambuc 			*rpp = n = redirnode;
591d90bee97SLionel Sambuc 			rpp = &n->nfile.next;
592d90bee97SLionel Sambuc 			parsefname();	/* read name of redirection file */
593d90bee97SLionel Sambuc 		} else if (lasttoken == TLP && app == &args->narg.next
594d90bee97SLionel Sambuc 					    && rpp == orig_rpp) {
595d90bee97SLionel Sambuc 			/* We have a function */
596d90bee97SLionel Sambuc 			if (readtoken() != TRP)
597d90bee97SLionel Sambuc 				synexpect(TRP);
598d90bee97SLionel Sambuc 			funclinno = plinno;
599d90bee97SLionel Sambuc 			rmescapes(n->narg.text);
600d90bee97SLionel Sambuc 			if (!goodname(n->narg.text))
601d90bee97SLionel Sambuc 				synerror("Bad function name");
602d90bee97SLionel Sambuc 			n->type = NDEFUN;
603d90bee97SLionel Sambuc 			n->narg.next = command();
604d90bee97SLionel Sambuc 			funclinno = 0;
605d90bee97SLionel Sambuc 			goto checkneg;
606d90bee97SLionel Sambuc 		} else {
607d90bee97SLionel Sambuc 			tokpushback++;
608d90bee97SLionel Sambuc 			break;
609d90bee97SLionel Sambuc 		}
610d90bee97SLionel Sambuc 	}
611d90bee97SLionel Sambuc 	*app = NULL;
612d90bee97SLionel Sambuc 	*rpp = NULL;
613d90bee97SLionel Sambuc 	n = (union node *)stalloc(sizeof (struct ncmd));
614d90bee97SLionel Sambuc 	n->type = NCMD;
615d90bee97SLionel Sambuc 	n->ncmd.backgnd = 0;
616d90bee97SLionel Sambuc 	n->ncmd.args = args;
617d90bee97SLionel Sambuc 	n->ncmd.redirect = redir;
618d90bee97SLionel Sambuc 
619d90bee97SLionel Sambuc checkneg:
620d90bee97SLionel Sambuc 	if (negate) {
621d90bee97SLionel Sambuc 		TRACE(("negate simplecmd\n"));
622d90bee97SLionel Sambuc 		n2 = (union node *)stalloc(sizeof (struct nnot));
623d90bee97SLionel Sambuc 		n2->type = NNOT;
624d90bee97SLionel Sambuc 		n2->nnot.com = n;
625d90bee97SLionel Sambuc 		return n2;
626d90bee97SLionel Sambuc 	}
627d90bee97SLionel Sambuc 	else
628d90bee97SLionel Sambuc 		return n;
629d90bee97SLionel Sambuc }
630d90bee97SLionel Sambuc 
631d90bee97SLionel Sambuc STATIC union node *
makename(void)632d90bee97SLionel Sambuc makename(void)
633d90bee97SLionel Sambuc {
634d90bee97SLionel Sambuc 	union node *n;
635d90bee97SLionel Sambuc 
636d90bee97SLionel Sambuc 	n = (union node *)stalloc(sizeof (struct narg));
637d90bee97SLionel Sambuc 	n->type = NARG;
638d90bee97SLionel Sambuc 	n->narg.next = NULL;
639d90bee97SLionel Sambuc 	n->narg.text = wordtext;
640d90bee97SLionel Sambuc 	n->narg.backquote = backquotelist;
641d90bee97SLionel Sambuc 	return n;
642d90bee97SLionel Sambuc }
643d90bee97SLionel Sambuc 
fixredir(union node * n,const char * text,int err)644d90bee97SLionel Sambuc void fixredir(union node *n, const char *text, int err)
645d90bee97SLionel Sambuc 	{
646d90bee97SLionel Sambuc 	TRACE(("Fix redir %s %d\n", text, err));
647d90bee97SLionel Sambuc 	if (!err)
648d90bee97SLionel Sambuc 		n->ndup.vname = NULL;
649d90bee97SLionel Sambuc 
650*0a6a1f1dSLionel Sambuc 	if (is_number(text))
651*0a6a1f1dSLionel Sambuc 		n->ndup.dupfd = number(text);
652d90bee97SLionel Sambuc 	else if (text[0] == '-' && text[1] == '\0')
653d90bee97SLionel Sambuc 		n->ndup.dupfd = -1;
654d90bee97SLionel Sambuc 	else {
655d90bee97SLionel Sambuc 
656d90bee97SLionel Sambuc 		if (err)
657d90bee97SLionel Sambuc 			synerror("Bad fd number");
658d90bee97SLionel Sambuc 		else
659d90bee97SLionel Sambuc 			n->ndup.vname = makename();
660d90bee97SLionel Sambuc 	}
661d90bee97SLionel Sambuc }
662d90bee97SLionel Sambuc 
663d90bee97SLionel Sambuc 
664d90bee97SLionel Sambuc STATIC void
parsefname(void)665d90bee97SLionel Sambuc parsefname(void)
666d90bee97SLionel Sambuc {
667d90bee97SLionel Sambuc 	union node *n = redirnode;
668d90bee97SLionel Sambuc 
669d90bee97SLionel Sambuc 	if (readtoken() != TWORD)
670d90bee97SLionel Sambuc 		synexpect(-1);
671d90bee97SLionel Sambuc 	if (n->type == NHERE) {
672d90bee97SLionel Sambuc 		struct heredoc *here = heredoc;
673d90bee97SLionel Sambuc 		struct heredoc *p;
674d90bee97SLionel Sambuc 		int i;
675d90bee97SLionel Sambuc 
676d90bee97SLionel Sambuc 		if (quoteflag == 0)
677d90bee97SLionel Sambuc 			n->type = NXHERE;
678d90bee97SLionel Sambuc 		TRACE(("Here document %d\n", n->type));
679d90bee97SLionel Sambuc 		if (here->striptabs) {
680d90bee97SLionel Sambuc 			while (*wordtext == '\t')
681d90bee97SLionel Sambuc 				wordtext++;
682d90bee97SLionel Sambuc 		}
683d90bee97SLionel Sambuc 		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
684d90bee97SLionel Sambuc 			synerror("Illegal eof marker for << redirection");
685d90bee97SLionel Sambuc 		rmescapes(wordtext);
686d90bee97SLionel Sambuc 		here->eofmark = wordtext;
687d90bee97SLionel Sambuc 		here->next = NULL;
688d90bee97SLionel Sambuc 		if (heredoclist == NULL)
689d90bee97SLionel Sambuc 			heredoclist = here;
690d90bee97SLionel Sambuc 		else {
691*0a6a1f1dSLionel Sambuc 			for (p = heredoclist ; p->next ; p = p->next)
692*0a6a1f1dSLionel Sambuc 				continue;
693d90bee97SLionel Sambuc 			p->next = here;
694d90bee97SLionel Sambuc 		}
695d90bee97SLionel Sambuc 	} else if (n->type == NTOFD || n->type == NFROMFD) {
696d90bee97SLionel Sambuc 		fixredir(n, wordtext, 0);
697d90bee97SLionel Sambuc 	} else {
698d90bee97SLionel Sambuc 		n->nfile.fname = makename();
699d90bee97SLionel Sambuc 	}
700d90bee97SLionel Sambuc }
701d90bee97SLionel Sambuc 
702d90bee97SLionel Sambuc 
703d90bee97SLionel Sambuc /*
704d90bee97SLionel Sambuc  * Input any here documents.
705d90bee97SLionel Sambuc  */
706d90bee97SLionel Sambuc 
707d90bee97SLionel Sambuc STATIC void
parseheredoc(void)708d90bee97SLionel Sambuc parseheredoc(void)
709d90bee97SLionel Sambuc {
710d90bee97SLionel Sambuc 	struct heredoc *here;
711d90bee97SLionel Sambuc 	union node *n;
712d90bee97SLionel Sambuc 
713d90bee97SLionel Sambuc 	while (heredoclist) {
714d90bee97SLionel Sambuc 		here = heredoclist;
715d90bee97SLionel Sambuc 		heredoclist = here->next;
716d90bee97SLionel Sambuc 		if (needprompt) {
717d90bee97SLionel Sambuc 			setprompt(2);
718d90bee97SLionel Sambuc 			needprompt = 0;
719d90bee97SLionel Sambuc 		}
720d90bee97SLionel Sambuc 		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
721d90bee97SLionel Sambuc 				here->eofmark, here->striptabs);
722d90bee97SLionel Sambuc 		n = (union node *)stalloc(sizeof (struct narg));
723d90bee97SLionel Sambuc 		n->narg.type = NARG;
724d90bee97SLionel Sambuc 		n->narg.next = NULL;
725d90bee97SLionel Sambuc 		n->narg.text = wordtext;
726d90bee97SLionel Sambuc 		n->narg.backquote = backquotelist;
727d90bee97SLionel Sambuc 		here->here->nhere.doc = n;
728d90bee97SLionel Sambuc 	}
729d90bee97SLionel Sambuc }
730d90bee97SLionel Sambuc 
731d90bee97SLionel Sambuc STATIC int
peektoken(void)732d90bee97SLionel Sambuc peektoken(void)
733d90bee97SLionel Sambuc {
734d90bee97SLionel Sambuc 	int t;
735d90bee97SLionel Sambuc 
736d90bee97SLionel Sambuc 	t = readtoken();
737d90bee97SLionel Sambuc 	tokpushback++;
738d90bee97SLionel Sambuc 	return (t);
739d90bee97SLionel Sambuc }
740d90bee97SLionel Sambuc 
741d90bee97SLionel Sambuc STATIC int
readtoken(void)742d90bee97SLionel Sambuc readtoken(void)
743d90bee97SLionel Sambuc {
744d90bee97SLionel Sambuc 	int t;
745d90bee97SLionel Sambuc 	int savecheckkwd = checkkwd;
746d90bee97SLionel Sambuc #ifdef DEBUG
747d90bee97SLionel Sambuc 	int alreadyseen = tokpushback;
748d90bee97SLionel Sambuc #endif
749d90bee97SLionel Sambuc 	struct alias *ap;
750d90bee97SLionel Sambuc 
751d90bee97SLionel Sambuc 	top:
752d90bee97SLionel Sambuc 	t = xxreadtoken();
753d90bee97SLionel Sambuc 
754d90bee97SLionel Sambuc 	if (checkkwd) {
755d90bee97SLionel Sambuc 		/*
756d90bee97SLionel Sambuc 		 * eat newlines
757d90bee97SLionel Sambuc 		 */
758d90bee97SLionel Sambuc 		if (checkkwd == 2) {
759d90bee97SLionel Sambuc 			checkkwd = 0;
760d90bee97SLionel Sambuc 			while (t == TNL) {
761d90bee97SLionel Sambuc 				parseheredoc();
762d90bee97SLionel Sambuc 				t = xxreadtoken();
763d90bee97SLionel Sambuc 			}
764d90bee97SLionel Sambuc 		} else
765d90bee97SLionel Sambuc 			checkkwd = 0;
766d90bee97SLionel Sambuc 		/*
767d90bee97SLionel Sambuc 		 * check for keywords and aliases
768d90bee97SLionel Sambuc 		 */
769d90bee97SLionel Sambuc 		if (t == TWORD && !quoteflag)
770d90bee97SLionel Sambuc 		{
771d90bee97SLionel Sambuc 			const char *const *pp;
772d90bee97SLionel Sambuc 
773d90bee97SLionel Sambuc 			for (pp = parsekwd; *pp; pp++) {
774d90bee97SLionel Sambuc 				if (**pp == *wordtext && equal(*pp, wordtext))
775d90bee97SLionel Sambuc 				{
776d90bee97SLionel Sambuc 					lasttoken = t = pp -
777d90bee97SLionel Sambuc 					    parsekwd + KWDOFFSET;
778d90bee97SLionel Sambuc 					TRACE(("keyword %s recognized\n", tokname[t]));
779d90bee97SLionel Sambuc 					goto out;
780d90bee97SLionel Sambuc 				}
781d90bee97SLionel Sambuc 			}
782d90bee97SLionel Sambuc 			if (!noalias &&
783d90bee97SLionel Sambuc 			    (ap = lookupalias(wordtext, 1)) != NULL) {
784d90bee97SLionel Sambuc 				pushstring(ap->val, strlen(ap->val), ap);
785d90bee97SLionel Sambuc 				checkkwd = savecheckkwd;
786d90bee97SLionel Sambuc 				goto top;
787d90bee97SLionel Sambuc 			}
788d90bee97SLionel Sambuc 		}
789d90bee97SLionel Sambuc out:
790d90bee97SLionel Sambuc 		checkkwd = (t == TNOT) ? savecheckkwd : 0;
791d90bee97SLionel Sambuc 	}
792d90bee97SLionel Sambuc 	TRACE(("%stoken %s %s\n", alreadyseen ? "reread " : "", tokname[t], t == TWORD ? wordtext : ""));
793d90bee97SLionel Sambuc 	return (t);
794d90bee97SLionel Sambuc }
795d90bee97SLionel Sambuc 
796d90bee97SLionel Sambuc 
797d90bee97SLionel Sambuc /*
798d90bee97SLionel Sambuc  * Read the next input token.
799d90bee97SLionel Sambuc  * If the token is a word, we set backquotelist to the list of cmds in
800d90bee97SLionel Sambuc  *	backquotes.  We set quoteflag to true if any part of the word was
801d90bee97SLionel Sambuc  *	quoted.
802d90bee97SLionel Sambuc  * If the token is TREDIR, then we set redirnode to a structure containing
803d90bee97SLionel Sambuc  *	the redirection.
804d90bee97SLionel Sambuc  * In all cases, the variable startlinno is set to the number of the line
805d90bee97SLionel Sambuc  *	on which the token starts.
806d90bee97SLionel Sambuc  *
807d90bee97SLionel Sambuc  * [Change comment:  here documents and internal procedures]
808d90bee97SLionel Sambuc  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
809d90bee97SLionel Sambuc  *  word parsing code into a separate routine.  In this case, readtoken
810d90bee97SLionel Sambuc  *  doesn't need to have any internal procedures, but parseword does.
811d90bee97SLionel Sambuc  *  We could also make parseoperator in essence the main routine, and
812d90bee97SLionel Sambuc  *  have parseword (readtoken1?) handle both words and redirection.]
813d90bee97SLionel Sambuc  */
814d90bee97SLionel Sambuc 
815d90bee97SLionel Sambuc #define RETURN(token)	return lasttoken = token
816d90bee97SLionel Sambuc 
817d90bee97SLionel Sambuc STATIC int
xxreadtoken(void)818d90bee97SLionel Sambuc xxreadtoken(void)
819d90bee97SLionel Sambuc {
820d90bee97SLionel Sambuc 	int c;
821d90bee97SLionel Sambuc 
822d90bee97SLionel Sambuc 	if (tokpushback) {
823d90bee97SLionel Sambuc 		tokpushback = 0;
824d90bee97SLionel Sambuc 		return lasttoken;
825d90bee97SLionel Sambuc 	}
826d90bee97SLionel Sambuc 	if (needprompt) {
827d90bee97SLionel Sambuc 		setprompt(2);
828d90bee97SLionel Sambuc 		needprompt = 0;
829d90bee97SLionel Sambuc 	}
830d90bee97SLionel Sambuc 	startlinno = plinno;
831d90bee97SLionel Sambuc 	for (;;) {	/* until token or start of word found */
832d90bee97SLionel Sambuc 		c = pgetc_macro();
833d90bee97SLionel Sambuc 		switch (c) {
834d90bee97SLionel Sambuc 		case ' ': case '\t':
835d90bee97SLionel Sambuc 			continue;
836d90bee97SLionel Sambuc 		case '#':
837*0a6a1f1dSLionel Sambuc 			while ((c = pgetc()) != '\n' && c != PEOF)
838*0a6a1f1dSLionel Sambuc 				continue;
839d90bee97SLionel Sambuc 			pungetc();
840d90bee97SLionel Sambuc 			continue;
841d90bee97SLionel Sambuc 		case '\\':
842*0a6a1f1dSLionel Sambuc 			switch (pgetc()) {
843*0a6a1f1dSLionel Sambuc 			case '\n':
844d90bee97SLionel Sambuc 				startlinno = ++plinno;
845d90bee97SLionel Sambuc 				if (doprompt)
846d90bee97SLionel Sambuc 					setprompt(2);
847d90bee97SLionel Sambuc 				else
848d90bee97SLionel Sambuc 					setprompt(0);
849d90bee97SLionel Sambuc 				continue;
850*0a6a1f1dSLionel Sambuc 			case PEOF:
851*0a6a1f1dSLionel Sambuc 				RETURN(TEOF);
852*0a6a1f1dSLionel Sambuc 			default:
853d90bee97SLionel Sambuc 				pungetc();
854*0a6a1f1dSLionel Sambuc 				break;
855*0a6a1f1dSLionel Sambuc 			}
856d90bee97SLionel Sambuc 			goto breakloop;
857d90bee97SLionel Sambuc 		case '\n':
858d90bee97SLionel Sambuc 			plinno++;
859d90bee97SLionel Sambuc 			needprompt = doprompt;
860d90bee97SLionel Sambuc 			RETURN(TNL);
861d90bee97SLionel Sambuc 		case PEOF:
862d90bee97SLionel Sambuc 			RETURN(TEOF);
863d90bee97SLionel Sambuc 		case '&':
864d90bee97SLionel Sambuc 			if (pgetc() == '&')
865d90bee97SLionel Sambuc 				RETURN(TAND);
866d90bee97SLionel Sambuc 			pungetc();
867d90bee97SLionel Sambuc 			RETURN(TBACKGND);
868d90bee97SLionel Sambuc 		case '|':
869d90bee97SLionel Sambuc 			if (pgetc() == '|')
870d90bee97SLionel Sambuc 				RETURN(TOR);
871d90bee97SLionel Sambuc 			pungetc();
872d90bee97SLionel Sambuc 			RETURN(TPIPE);
873d90bee97SLionel Sambuc 		case ';':
874d90bee97SLionel Sambuc 			if (pgetc() == ';')
875d90bee97SLionel Sambuc 				RETURN(TENDCASE);
876d90bee97SLionel Sambuc 			pungetc();
877d90bee97SLionel Sambuc 			RETURN(TSEMI);
878d90bee97SLionel Sambuc 		case '(':
879d90bee97SLionel Sambuc 			RETURN(TLP);
880d90bee97SLionel Sambuc 		case ')':
881d90bee97SLionel Sambuc 			RETURN(TRP);
882d90bee97SLionel Sambuc 		default:
883d90bee97SLionel Sambuc 			goto breakloop;
884d90bee97SLionel Sambuc 		}
885d90bee97SLionel Sambuc 	}
886d90bee97SLionel Sambuc breakloop:
887d90bee97SLionel Sambuc 	return readtoken1(c, BASESYNTAX, NULL, 0);
888d90bee97SLionel Sambuc #undef RETURN
889d90bee97SLionel Sambuc }
890d90bee97SLionel Sambuc 
891d90bee97SLionel Sambuc 
892d90bee97SLionel Sambuc 
893d90bee97SLionel Sambuc /*
894d90bee97SLionel Sambuc  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
895d90bee97SLionel Sambuc  * is not NULL, read a here document.  In the latter case, eofmark is the
896d90bee97SLionel Sambuc  * word which marks the end of the document and striptabs is true if
897d90bee97SLionel Sambuc  * leading tabs should be stripped from the document.  The argument firstc
898d90bee97SLionel Sambuc  * is the first character of the input token or document.
899d90bee97SLionel Sambuc  *
900d90bee97SLionel Sambuc  * Because C does not have internal subroutines, I have simulated them
901d90bee97SLionel Sambuc  * using goto's to implement the subroutine linkage.  The following macros
902d90bee97SLionel Sambuc  * will run code that appears at the end of readtoken1.
903d90bee97SLionel Sambuc  */
904d90bee97SLionel Sambuc 
905d90bee97SLionel Sambuc #define CHECKEND()	{goto checkend; checkend_return:;}
906d90bee97SLionel Sambuc #define PARSEREDIR()	{goto parseredir; parseredir_return:;}
907d90bee97SLionel Sambuc #define PARSESUB()	{goto parsesub; parsesub_return:;}
908d90bee97SLionel Sambuc #define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
909d90bee97SLionel Sambuc #define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
910d90bee97SLionel Sambuc #define	PARSEARITH()	{goto parsearith; parsearith_return:;}
911d90bee97SLionel Sambuc 
912d90bee97SLionel Sambuc /*
913d90bee97SLionel Sambuc  * Keep track of nested doublequotes in dblquote and doublequotep.
914d90bee97SLionel Sambuc  * We use dblquote for the first 32 levels, and we expand to a malloc'ed
915d90bee97SLionel Sambuc  * region for levels above that. Usually we never need to malloc.
916d90bee97SLionel Sambuc  * This code assumes that an int is 32 bits. We don't use uint32_t,
917d90bee97SLionel Sambuc  * because the rest of the code does not.
918d90bee97SLionel Sambuc  */
919d90bee97SLionel Sambuc #define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \
920d90bee97SLionel Sambuc     (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32))))
921d90bee97SLionel Sambuc 
922d90bee97SLionel Sambuc #define SETDBLQUOTE() \
923d90bee97SLionel Sambuc     if (varnest < 32) \
924d90bee97SLionel Sambuc 	dblquote |= (1 << varnest); \
925d90bee97SLionel Sambuc     else \
926d90bee97SLionel Sambuc 	dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32))
927d90bee97SLionel Sambuc 
928d90bee97SLionel Sambuc #define CLRDBLQUOTE() \
929d90bee97SLionel Sambuc     if (varnest < 32) \
930d90bee97SLionel Sambuc 	dblquote &= ~(1 << varnest); \
931d90bee97SLionel Sambuc     else \
932d90bee97SLionel Sambuc 	dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32))
933d90bee97SLionel Sambuc 
934d90bee97SLionel Sambuc STATIC int
readtoken1(int firstc,char const * syn,char * eofmark,int striptabs)935d90bee97SLionel Sambuc readtoken1(int firstc, char const *syn, char *eofmark, int striptabs)
936d90bee97SLionel Sambuc {
937d90bee97SLionel Sambuc 	char const * volatile syntax = syn;
938d90bee97SLionel Sambuc 	int c = firstc;
939d90bee97SLionel Sambuc 	char * volatile out;
940d90bee97SLionel Sambuc 	int len;
941d90bee97SLionel Sambuc 	char line[EOFMARKLEN + 1];
942d90bee97SLionel Sambuc 	struct nodelist *bqlist;
943d90bee97SLionel Sambuc 	volatile int quotef;
944d90bee97SLionel Sambuc 	int * volatile dblquotep = NULL;
945d90bee97SLionel Sambuc 	volatile size_t maxnest = 32;
946d90bee97SLionel Sambuc 	volatile int dblquote;
947d90bee97SLionel Sambuc 	volatile size_t varnest;	/* levels of variables expansion */
948d90bee97SLionel Sambuc 	volatile int arinest;	/* levels of arithmetic expansion */
949d90bee97SLionel Sambuc 	volatile int parenlevel;	/* levels of parens in arithmetic */
950d90bee97SLionel Sambuc 	volatile int oldstyle;
951d90bee97SLionel Sambuc 	char const * volatile prevsyntax;	/* syntax before arithmetic */
952d90bee97SLionel Sambuc #ifdef __GNUC__
953d90bee97SLionel Sambuc 	prevsyntax = NULL;	/* XXX gcc4 */
954d90bee97SLionel Sambuc #endif
955d90bee97SLionel Sambuc 
956d90bee97SLionel Sambuc 	startlinno = plinno;
957d90bee97SLionel Sambuc 	dblquote = 0;
958d90bee97SLionel Sambuc 	varnest = 0;
959d90bee97SLionel Sambuc 	if (syntax == DQSYNTAX) {
960d90bee97SLionel Sambuc 		SETDBLQUOTE();
961d90bee97SLionel Sambuc 	}
962d90bee97SLionel Sambuc 	quotef = 0;
963d90bee97SLionel Sambuc 	bqlist = NULL;
964d90bee97SLionel Sambuc 	arinest = 0;
965d90bee97SLionel Sambuc 	parenlevel = 0;
966d90bee97SLionel Sambuc 
967d90bee97SLionel Sambuc 	STARTSTACKSTR(out);
968d90bee97SLionel Sambuc 	loop: {	/* for each line, until end of word */
969d90bee97SLionel Sambuc #if ATTY
970d90bee97SLionel Sambuc 		if (c == '\034' && doprompt
971d90bee97SLionel Sambuc 		 && attyset() && ! equal(termval(), "emacs")) {
972d90bee97SLionel Sambuc 			attyline();
973d90bee97SLionel Sambuc 			if (syntax == BASESYNTAX)
974d90bee97SLionel Sambuc 				return readtoken();
975d90bee97SLionel Sambuc 			c = pgetc();
976d90bee97SLionel Sambuc 			goto loop;
977d90bee97SLionel Sambuc 		}
978d90bee97SLionel Sambuc #endif
979d90bee97SLionel Sambuc 		CHECKEND();	/* set c to PEOF if at end of here document */
980d90bee97SLionel Sambuc 		for (;;) {	/* until end of line or end of word */
981d90bee97SLionel Sambuc 			CHECKSTRSPACE(4, out);	/* permit 4 calls to USTPUTC */
982d90bee97SLionel Sambuc 			switch(syntax[c]) {
983d90bee97SLionel Sambuc 			case CNL:	/* '\n' */
984d90bee97SLionel Sambuc 				if (syntax == BASESYNTAX)
985d90bee97SLionel Sambuc 					goto endword;	/* exit outer loop */
986d90bee97SLionel Sambuc 				USTPUTC(c, out);
987d90bee97SLionel Sambuc 				plinno++;
988d90bee97SLionel Sambuc 				if (doprompt)
989d90bee97SLionel Sambuc 					setprompt(2);
990d90bee97SLionel Sambuc 				else
991d90bee97SLionel Sambuc 					setprompt(0);
992d90bee97SLionel Sambuc 				c = pgetc();
993d90bee97SLionel Sambuc 				goto loop;		/* continue outer loop */
994d90bee97SLionel Sambuc 			case CWORD:
995d90bee97SLionel Sambuc 				USTPUTC(c, out);
996d90bee97SLionel Sambuc 				break;
997d90bee97SLionel Sambuc 			case CCTL:
998d90bee97SLionel Sambuc 				if (eofmark == NULL || ISDBLQUOTE())
999d90bee97SLionel Sambuc 					USTPUTC(CTLESC, out);
1000d90bee97SLionel Sambuc 				USTPUTC(c, out);
1001d90bee97SLionel Sambuc 				break;
1002d90bee97SLionel Sambuc 			case CBACK:	/* backslash */
1003d90bee97SLionel Sambuc 				c = pgetc();
1004d90bee97SLionel Sambuc 				if (c == PEOF) {
1005d90bee97SLionel Sambuc 					USTPUTC('\\', out);
1006d90bee97SLionel Sambuc 					pungetc();
1007d90bee97SLionel Sambuc 					break;
1008d90bee97SLionel Sambuc 				}
1009d90bee97SLionel Sambuc 				if (c == '\n') {
1010*0a6a1f1dSLionel Sambuc 					plinno++;
1011d90bee97SLionel Sambuc 					if (doprompt)
1012d90bee97SLionel Sambuc 						setprompt(2);
1013d90bee97SLionel Sambuc 					else
1014d90bee97SLionel Sambuc 						setprompt(0);
1015d90bee97SLionel Sambuc 					break;
1016d90bee97SLionel Sambuc 				}
1017d90bee97SLionel Sambuc 				quotef = 1;
1018d90bee97SLionel Sambuc 				if (ISDBLQUOTE() && c != '\\' &&
1019d90bee97SLionel Sambuc 				    c != '`' && c != '$' &&
1020d90bee97SLionel Sambuc 				    (c != '"' || eofmark != NULL))
1021d90bee97SLionel Sambuc 					USTPUTC('\\', out);
1022d90bee97SLionel Sambuc 				if (SQSYNTAX[c] == CCTL)
1023d90bee97SLionel Sambuc 					USTPUTC(CTLESC, out);
1024d90bee97SLionel Sambuc 				else if (eofmark == NULL) {
1025d90bee97SLionel Sambuc 					USTPUTC(CTLQUOTEMARK, out);
1026d90bee97SLionel Sambuc 					USTPUTC(c, out);
1027d90bee97SLionel Sambuc 					if (varnest != 0)
1028d90bee97SLionel Sambuc 						USTPUTC(CTLQUOTEEND, out);
1029d90bee97SLionel Sambuc 					break;
1030d90bee97SLionel Sambuc 				}
1031d90bee97SLionel Sambuc 				USTPUTC(c, out);
1032d90bee97SLionel Sambuc 				break;
1033d90bee97SLionel Sambuc 			case CSQUOTE:
1034d90bee97SLionel Sambuc 				if (syntax != SQSYNTAX) {
1035d90bee97SLionel Sambuc 					if (eofmark == NULL)
1036d90bee97SLionel Sambuc 						USTPUTC(CTLQUOTEMARK, out);
1037d90bee97SLionel Sambuc 					quotef = 1;
1038d90bee97SLionel Sambuc 					syntax = SQSYNTAX;
1039d90bee97SLionel Sambuc 					break;
1040d90bee97SLionel Sambuc 				}
1041d90bee97SLionel Sambuc 				if (eofmark != NULL && arinest == 0 &&
1042d90bee97SLionel Sambuc 				    varnest == 0) {
1043d90bee97SLionel Sambuc 					/* Ignore inside quoted here document */
1044d90bee97SLionel Sambuc 					USTPUTC(c, out);
1045d90bee97SLionel Sambuc 					break;
1046d90bee97SLionel Sambuc 				}
1047d90bee97SLionel Sambuc 				/* End of single quotes... */
1048d90bee97SLionel Sambuc 				if (arinest)
1049d90bee97SLionel Sambuc 					syntax = ARISYNTAX;
1050d90bee97SLionel Sambuc 				else {
1051d90bee97SLionel Sambuc 					syntax = BASESYNTAX;
1052d90bee97SLionel Sambuc 					if (varnest != 0)
1053d90bee97SLionel Sambuc 						USTPUTC(CTLQUOTEEND, out);
1054d90bee97SLionel Sambuc 				}
1055d90bee97SLionel Sambuc 				break;
1056d90bee97SLionel Sambuc 			case CDQUOTE:
1057d90bee97SLionel Sambuc 				if (eofmark != NULL && arinest == 0 &&
1058d90bee97SLionel Sambuc 				    varnest == 0) {
1059d90bee97SLionel Sambuc 					/* Ignore inside here document */
1060d90bee97SLionel Sambuc 					USTPUTC(c, out);
1061d90bee97SLionel Sambuc 					break;
1062d90bee97SLionel Sambuc 				}
1063d90bee97SLionel Sambuc 				quotef = 1;
1064d90bee97SLionel Sambuc 				if (arinest) {
1065d90bee97SLionel Sambuc 					if (ISDBLQUOTE()) {
1066d90bee97SLionel Sambuc 						syntax = ARISYNTAX;
1067d90bee97SLionel Sambuc 						CLRDBLQUOTE();
1068d90bee97SLionel Sambuc 					} else {
1069d90bee97SLionel Sambuc 						syntax = DQSYNTAX;
1070d90bee97SLionel Sambuc 						SETDBLQUOTE();
1071d90bee97SLionel Sambuc 						USTPUTC(CTLQUOTEMARK, out);
1072d90bee97SLionel Sambuc 					}
1073d90bee97SLionel Sambuc 					break;
1074d90bee97SLionel Sambuc 				}
1075d90bee97SLionel Sambuc 				if (eofmark != NULL)
1076d90bee97SLionel Sambuc 					break;
1077d90bee97SLionel Sambuc 				if (ISDBLQUOTE()) {
1078d90bee97SLionel Sambuc 					if (varnest != 0)
1079d90bee97SLionel Sambuc 						USTPUTC(CTLQUOTEEND, out);
1080d90bee97SLionel Sambuc 					syntax = BASESYNTAX;
1081d90bee97SLionel Sambuc 					CLRDBLQUOTE();
1082d90bee97SLionel Sambuc 				} else {
1083d90bee97SLionel Sambuc 					syntax = DQSYNTAX;
1084d90bee97SLionel Sambuc 					SETDBLQUOTE();
1085d90bee97SLionel Sambuc 					USTPUTC(CTLQUOTEMARK, out);
1086d90bee97SLionel Sambuc 				}
1087d90bee97SLionel Sambuc 				break;
1088d90bee97SLionel Sambuc 			case CVAR:	/* '$' */
1089d90bee97SLionel Sambuc 				PARSESUB();		/* parse substitution */
1090d90bee97SLionel Sambuc 				break;
1091d90bee97SLionel Sambuc 			case CENDVAR:	/* CLOSEBRACE */
1092d90bee97SLionel Sambuc 				if (varnest > 0 && !ISDBLQUOTE()) {
1093d90bee97SLionel Sambuc 					varnest--;
1094d90bee97SLionel Sambuc 					USTPUTC(CTLENDVAR, out);
1095d90bee97SLionel Sambuc 				} else {
1096d90bee97SLionel Sambuc 					USTPUTC(c, out);
1097d90bee97SLionel Sambuc 				}
1098d90bee97SLionel Sambuc 				break;
1099d90bee97SLionel Sambuc 			case CLP:	/* '(' in arithmetic */
1100d90bee97SLionel Sambuc 				parenlevel++;
1101d90bee97SLionel Sambuc 				USTPUTC(c, out);
1102d90bee97SLionel Sambuc 				break;
1103d90bee97SLionel Sambuc 			case CRP:	/* ')' in arithmetic */
1104d90bee97SLionel Sambuc 				if (parenlevel > 0) {
1105d90bee97SLionel Sambuc 					USTPUTC(c, out);
1106d90bee97SLionel Sambuc 					--parenlevel;
1107d90bee97SLionel Sambuc 				} else {
1108d90bee97SLionel Sambuc 					if (pgetc() == ')') {
1109d90bee97SLionel Sambuc 						if (--arinest == 0) {
1110d90bee97SLionel Sambuc 							USTPUTC(CTLENDARI, out);
1111d90bee97SLionel Sambuc 							syntax = prevsyntax;
1112d90bee97SLionel Sambuc 							if (syntax == DQSYNTAX)
1113d90bee97SLionel Sambuc 								SETDBLQUOTE();
1114d90bee97SLionel Sambuc 							else
1115d90bee97SLionel Sambuc 								CLRDBLQUOTE();
1116d90bee97SLionel Sambuc 						} else
1117d90bee97SLionel Sambuc 							USTPUTC(')', out);
1118d90bee97SLionel Sambuc 					} else {
1119d90bee97SLionel Sambuc 						/*
1120d90bee97SLionel Sambuc 						 * unbalanced parens
1121d90bee97SLionel Sambuc 						 *  (don't 2nd guess - no error)
1122d90bee97SLionel Sambuc 						 */
1123d90bee97SLionel Sambuc 						pungetc();
1124d90bee97SLionel Sambuc 						USTPUTC(')', out);
1125d90bee97SLionel Sambuc 					}
1126d90bee97SLionel Sambuc 				}
1127d90bee97SLionel Sambuc 				break;
1128d90bee97SLionel Sambuc 			case CBQUOTE:	/* '`' */
1129d90bee97SLionel Sambuc 				PARSEBACKQOLD();
1130d90bee97SLionel Sambuc 				break;
1131d90bee97SLionel Sambuc 			case CEOF:
1132d90bee97SLionel Sambuc 				goto endword;		/* exit outer loop */
1133d90bee97SLionel Sambuc 			default:
1134d90bee97SLionel Sambuc 				if (varnest == 0 && !ISDBLQUOTE())
1135d90bee97SLionel Sambuc 					goto endword;	/* exit outer loop */
1136d90bee97SLionel Sambuc 				USTPUTC(c, out);
1137d90bee97SLionel Sambuc 			}
1138d90bee97SLionel Sambuc 			c = pgetc_macro();
1139d90bee97SLionel Sambuc 		}
1140d90bee97SLionel Sambuc 	}
1141d90bee97SLionel Sambuc endword:
1142d90bee97SLionel Sambuc 	if (syntax == ARISYNTAX)
1143d90bee97SLionel Sambuc 		synerror("Missing '))'");
1144d90bee97SLionel Sambuc 	if (syntax != BASESYNTAX && /* ! parsebackquote && */ eofmark == NULL)
1145d90bee97SLionel Sambuc 		synerror("Unterminated quoted string");
1146d90bee97SLionel Sambuc 	if (varnest != 0) {
1147d90bee97SLionel Sambuc 		startlinno = plinno;
1148d90bee97SLionel Sambuc 		/* { */
1149d90bee97SLionel Sambuc 		synerror("Missing '}'");
1150d90bee97SLionel Sambuc 	}
1151d90bee97SLionel Sambuc 	USTPUTC('\0', out);
1152d90bee97SLionel Sambuc 	len = out - stackblock();
1153d90bee97SLionel Sambuc 	out = stackblock();
1154d90bee97SLionel Sambuc 	if (eofmark == NULL) {
1155d90bee97SLionel Sambuc 		if ((c == '>' || c == '<')
1156d90bee97SLionel Sambuc 		 && quotef == 0
1157*0a6a1f1dSLionel Sambuc 		 && (*out == '\0' || is_number(out))) {
1158d90bee97SLionel Sambuc 			PARSEREDIR();
1159d90bee97SLionel Sambuc 			return lasttoken = TREDIR;
1160d90bee97SLionel Sambuc 		} else {
1161d90bee97SLionel Sambuc 			pungetc();
1162d90bee97SLionel Sambuc 		}
1163d90bee97SLionel Sambuc 	}
1164d90bee97SLionel Sambuc 	quoteflag = quotef;
1165d90bee97SLionel Sambuc 	backquotelist = bqlist;
1166d90bee97SLionel Sambuc 	grabstackblock(len);
1167d90bee97SLionel Sambuc 	wordtext = out;
1168d90bee97SLionel Sambuc 	if (dblquotep != NULL)
1169d90bee97SLionel Sambuc 	    ckfree(dblquotep);
1170d90bee97SLionel Sambuc 	return lasttoken = TWORD;
1171d90bee97SLionel Sambuc /* end of readtoken routine */
1172d90bee97SLionel Sambuc 
1173d90bee97SLionel Sambuc 
1174d90bee97SLionel Sambuc 
1175d90bee97SLionel Sambuc /*
1176d90bee97SLionel Sambuc  * Check to see whether we are at the end of the here document.  When this
1177d90bee97SLionel Sambuc  * is called, c is set to the first character of the next input line.  If
1178d90bee97SLionel Sambuc  * we are at the end of the here document, this routine sets the c to PEOF.
1179d90bee97SLionel Sambuc  */
1180d90bee97SLionel Sambuc 
1181d90bee97SLionel Sambuc checkend: {
1182d90bee97SLionel Sambuc 	if (eofmark) {
1183d90bee97SLionel Sambuc 		if (striptabs) {
1184d90bee97SLionel Sambuc 			while (c == '\t')
1185d90bee97SLionel Sambuc 				c = pgetc();
1186d90bee97SLionel Sambuc 		}
1187d90bee97SLionel Sambuc 		if (c == *eofmark) {
1188d90bee97SLionel Sambuc 			if (pfgets(line, sizeof line) != NULL) {
1189d90bee97SLionel Sambuc 				char *p, *q;
1190d90bee97SLionel Sambuc 
1191d90bee97SLionel Sambuc 				p = line;
1192*0a6a1f1dSLionel Sambuc 				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++)
1193*0a6a1f1dSLionel Sambuc 					continue;
1194d90bee97SLionel Sambuc 				if ((*p == '\0' || *p == '\n') && *q == '\0') {
1195d90bee97SLionel Sambuc 					c = PEOF;
1196d90bee97SLionel Sambuc 					plinno++;
1197d90bee97SLionel Sambuc 					needprompt = doprompt;
1198d90bee97SLionel Sambuc 				} else {
1199d90bee97SLionel Sambuc 					pushstring(line, strlen(line), NULL);
1200d90bee97SLionel Sambuc 				}
1201d90bee97SLionel Sambuc 			}
1202d90bee97SLionel Sambuc 		}
1203d90bee97SLionel Sambuc 	}
1204d90bee97SLionel Sambuc 	goto checkend_return;
1205d90bee97SLionel Sambuc }
1206d90bee97SLionel Sambuc 
1207d90bee97SLionel Sambuc 
1208d90bee97SLionel Sambuc /*
1209d90bee97SLionel Sambuc  * Parse a redirection operator.  The variable "out" points to a string
1210d90bee97SLionel Sambuc  * specifying the fd to be redirected.  The variable "c" contains the
1211d90bee97SLionel Sambuc  * first character of the redirection operator.
1212d90bee97SLionel Sambuc  */
1213d90bee97SLionel Sambuc 
1214d90bee97SLionel Sambuc parseredir: {
1215*0a6a1f1dSLionel Sambuc 	char fd[64];
1216d90bee97SLionel Sambuc 	union node *np;
1217*0a6a1f1dSLionel Sambuc 	strlcpy(fd, out, sizeof(fd));
1218d90bee97SLionel Sambuc 
1219d90bee97SLionel Sambuc 	np = (union node *)stalloc(sizeof (struct nfile));
1220d90bee97SLionel Sambuc 	if (c == '>') {
1221d90bee97SLionel Sambuc 		np->nfile.fd = 1;
1222d90bee97SLionel Sambuc 		c = pgetc();
1223d90bee97SLionel Sambuc 		if (c == '>')
1224d90bee97SLionel Sambuc 			np->type = NAPPEND;
1225d90bee97SLionel Sambuc 		else if (c == '|')
1226d90bee97SLionel Sambuc 			np->type = NCLOBBER;
1227d90bee97SLionel Sambuc 		else if (c == '&')
1228d90bee97SLionel Sambuc 			np->type = NTOFD;
1229d90bee97SLionel Sambuc 		else {
1230d90bee97SLionel Sambuc 			np->type = NTO;
1231d90bee97SLionel Sambuc 			pungetc();
1232d90bee97SLionel Sambuc 		}
1233d90bee97SLionel Sambuc 	} else {	/* c == '<' */
1234d90bee97SLionel Sambuc 		np->nfile.fd = 0;
1235d90bee97SLionel Sambuc 		switch (c = pgetc()) {
1236d90bee97SLionel Sambuc 		case '<':
1237d90bee97SLionel Sambuc 			if (sizeof (struct nfile) != sizeof (struct nhere)) {
1238d90bee97SLionel Sambuc 				np = (union node *)stalloc(sizeof (struct nhere));
1239d90bee97SLionel Sambuc 				np->nfile.fd = 0;
1240d90bee97SLionel Sambuc 			}
1241d90bee97SLionel Sambuc 			np->type = NHERE;
1242d90bee97SLionel Sambuc 			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1243d90bee97SLionel Sambuc 			heredoc->here = np;
1244d90bee97SLionel Sambuc 			if ((c = pgetc()) == '-') {
1245d90bee97SLionel Sambuc 				heredoc->striptabs = 1;
1246d90bee97SLionel Sambuc 			} else {
1247d90bee97SLionel Sambuc 				heredoc->striptabs = 0;
1248d90bee97SLionel Sambuc 				pungetc();
1249d90bee97SLionel Sambuc 			}
1250d90bee97SLionel Sambuc 			break;
1251d90bee97SLionel Sambuc 
1252d90bee97SLionel Sambuc 		case '&':
1253d90bee97SLionel Sambuc 			np->type = NFROMFD;
1254d90bee97SLionel Sambuc 			break;
1255d90bee97SLionel Sambuc 
1256d90bee97SLionel Sambuc 		case '>':
1257d90bee97SLionel Sambuc 			np->type = NFROMTO;
1258d90bee97SLionel Sambuc 			break;
1259d90bee97SLionel Sambuc 
1260d90bee97SLionel Sambuc 		default:
1261d90bee97SLionel Sambuc 			np->type = NFROM;
1262d90bee97SLionel Sambuc 			pungetc();
1263d90bee97SLionel Sambuc 			break;
1264d90bee97SLionel Sambuc 		}
1265d90bee97SLionel Sambuc 	}
1266*0a6a1f1dSLionel Sambuc 	if (*fd != '\0')
1267*0a6a1f1dSLionel Sambuc 		np->nfile.fd = number(fd);
1268d90bee97SLionel Sambuc 	redirnode = np;
1269d90bee97SLionel Sambuc 	goto parseredir_return;
1270d90bee97SLionel Sambuc }
1271d90bee97SLionel Sambuc 
1272d90bee97SLionel Sambuc 
1273d90bee97SLionel Sambuc /*
1274d90bee97SLionel Sambuc  * Parse a substitution.  At this point, we have read the dollar sign
1275d90bee97SLionel Sambuc  * and nothing else.
1276d90bee97SLionel Sambuc  */
1277d90bee97SLionel Sambuc 
1278d90bee97SLionel Sambuc parsesub: {
1279d90bee97SLionel Sambuc 	char buf[10];
1280d90bee97SLionel Sambuc 	int subtype;
1281d90bee97SLionel Sambuc 	int typeloc;
1282d90bee97SLionel Sambuc 	int flags;
1283d90bee97SLionel Sambuc 	char *p;
1284d90bee97SLionel Sambuc 	static const char types[] = "}-+?=";
1285d90bee97SLionel Sambuc 	int i;
1286d90bee97SLionel Sambuc 	int linno;
1287d90bee97SLionel Sambuc 
1288d90bee97SLionel Sambuc 	c = pgetc();
1289d90bee97SLionel Sambuc 	if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
1290d90bee97SLionel Sambuc 		USTPUTC('$', out);
1291d90bee97SLionel Sambuc 		pungetc();
1292d90bee97SLionel Sambuc 	} else if (c == '(') {	/* $(command) or $((arith)) */
1293d90bee97SLionel Sambuc 		if (pgetc() == '(') {
1294d90bee97SLionel Sambuc 			PARSEARITH();
1295d90bee97SLionel Sambuc 		} else {
1296d90bee97SLionel Sambuc 			pungetc();
1297d90bee97SLionel Sambuc 			PARSEBACKQNEW();
1298d90bee97SLionel Sambuc 		}
1299d90bee97SLionel Sambuc 	} else {
1300d90bee97SLionel Sambuc 		USTPUTC(CTLVAR, out);
1301d90bee97SLionel Sambuc 		typeloc = out - stackblock();
1302d90bee97SLionel Sambuc 		USTPUTC(VSNORMAL, out);
1303d90bee97SLionel Sambuc 		subtype = VSNORMAL;
1304d90bee97SLionel Sambuc 		flags = 0;
1305d90bee97SLionel Sambuc 		if (c == OPENBRACE) {
1306d90bee97SLionel Sambuc 			c = pgetc();
1307d90bee97SLionel Sambuc 			if (c == '#') {
1308d90bee97SLionel Sambuc 				if ((c = pgetc()) == CLOSEBRACE)
1309d90bee97SLionel Sambuc 					c = '#';
1310d90bee97SLionel Sambuc 				else
1311d90bee97SLionel Sambuc 					subtype = VSLENGTH;
1312d90bee97SLionel Sambuc 			}
1313d90bee97SLionel Sambuc 			else
1314d90bee97SLionel Sambuc 				subtype = 0;
1315d90bee97SLionel Sambuc 		}
1316d90bee97SLionel Sambuc 		if (is_name(c)) {
1317d90bee97SLionel Sambuc 			p = out;
1318d90bee97SLionel Sambuc 			do {
1319d90bee97SLionel Sambuc 				STPUTC(c, out);
1320d90bee97SLionel Sambuc 				c = pgetc();
1321d90bee97SLionel Sambuc 			} while (is_in_name(c));
1322d90bee97SLionel Sambuc 			if (out - p == 6 && strncmp(p, "LINENO", 6) == 0) {
1323d90bee97SLionel Sambuc 				/* Replace the variable name with the
1324d90bee97SLionel Sambuc 				 * current line number. */
1325d90bee97SLionel Sambuc 				linno = plinno;
1326d90bee97SLionel Sambuc 				if (funclinno != 0)
1327d90bee97SLionel Sambuc 					linno -= funclinno - 1;
1328d90bee97SLionel Sambuc 				snprintf(buf, sizeof(buf), "%d", linno);
1329d90bee97SLionel Sambuc 				STADJUST(-6, out);
1330d90bee97SLionel Sambuc 				for (i = 0; buf[i] != '\0'; i++)
1331d90bee97SLionel Sambuc 					STPUTC(buf[i], out);
1332d90bee97SLionel Sambuc 				flags |= VSLINENO;
1333d90bee97SLionel Sambuc 			}
1334d90bee97SLionel Sambuc 		} else if (is_digit(c)) {
1335d90bee97SLionel Sambuc 			do {
1336d90bee97SLionel Sambuc 				USTPUTC(c, out);
1337d90bee97SLionel Sambuc 				c = pgetc();
1338d90bee97SLionel Sambuc 			} while (is_digit(c));
1339d90bee97SLionel Sambuc 		}
1340d90bee97SLionel Sambuc 		else if (is_special(c)) {
1341d90bee97SLionel Sambuc 			USTPUTC(c, out);
1342d90bee97SLionel Sambuc 			c = pgetc();
1343d90bee97SLionel Sambuc 		}
1344d90bee97SLionel Sambuc 		else
1345d90bee97SLionel Sambuc badsub:			synerror("Bad substitution");
1346d90bee97SLionel Sambuc 
1347d90bee97SLionel Sambuc 		STPUTC('=', out);
1348d90bee97SLionel Sambuc 		if (subtype == 0) {
1349d90bee97SLionel Sambuc 			switch (c) {
1350d90bee97SLionel Sambuc 			case ':':
1351d90bee97SLionel Sambuc 				flags |= VSNUL;
1352d90bee97SLionel Sambuc 				c = pgetc();
1353d90bee97SLionel Sambuc 				/*FALLTHROUGH*/
1354d90bee97SLionel Sambuc 			default:
1355d90bee97SLionel Sambuc 				p = strchr(types, c);
1356d90bee97SLionel Sambuc 				if (p == NULL)
1357d90bee97SLionel Sambuc 					goto badsub;
1358d90bee97SLionel Sambuc 				subtype = p - types + VSNORMAL;
1359d90bee97SLionel Sambuc 				break;
1360d90bee97SLionel Sambuc 			case '%':
1361d90bee97SLionel Sambuc 			case '#':
1362d90bee97SLionel Sambuc 				{
1363d90bee97SLionel Sambuc 					int cc = c;
1364d90bee97SLionel Sambuc 					subtype = c == '#' ? VSTRIMLEFT :
1365d90bee97SLionel Sambuc 							     VSTRIMRIGHT;
1366d90bee97SLionel Sambuc 					c = pgetc();
1367d90bee97SLionel Sambuc 					if (c == cc)
1368d90bee97SLionel Sambuc 						subtype++;
1369d90bee97SLionel Sambuc 					else
1370d90bee97SLionel Sambuc 						pungetc();
1371d90bee97SLionel Sambuc 					break;
1372d90bee97SLionel Sambuc 				}
1373d90bee97SLionel Sambuc 			}
1374d90bee97SLionel Sambuc 		} else {
1375d90bee97SLionel Sambuc 			pungetc();
1376d90bee97SLionel Sambuc 		}
1377d90bee97SLionel Sambuc 		if (ISDBLQUOTE() || arinest)
1378d90bee97SLionel Sambuc 			flags |= VSQUOTE;
1379d90bee97SLionel Sambuc 		*(stackblock() + typeloc) = subtype | flags;
1380d90bee97SLionel Sambuc 		if (subtype != VSNORMAL) {
1381d90bee97SLionel Sambuc 			varnest++;
1382d90bee97SLionel Sambuc 			if (varnest >= maxnest) {
1383d90bee97SLionel Sambuc 				dblquotep = ckrealloc(dblquotep, maxnest / 8);
1384d90bee97SLionel Sambuc 				dblquotep[(maxnest / 32) - 1] = 0;
1385d90bee97SLionel Sambuc 				maxnest += 32;
1386d90bee97SLionel Sambuc 			}
1387d90bee97SLionel Sambuc 		}
1388d90bee97SLionel Sambuc 	}
1389d90bee97SLionel Sambuc 	goto parsesub_return;
1390d90bee97SLionel Sambuc }
1391d90bee97SLionel Sambuc 
1392d90bee97SLionel Sambuc 
1393d90bee97SLionel Sambuc /*
1394d90bee97SLionel Sambuc  * Called to parse command substitutions.  Newstyle is set if the command
1395d90bee97SLionel Sambuc  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1396d90bee97SLionel Sambuc  * list of commands (passed by reference), and savelen is the number of
1397d90bee97SLionel Sambuc  * characters on the top of the stack which must be preserved.
1398d90bee97SLionel Sambuc  */
1399d90bee97SLionel Sambuc 
1400d90bee97SLionel Sambuc parsebackq: {
1401d90bee97SLionel Sambuc 	struct nodelist **nlpp;
1402d90bee97SLionel Sambuc 	int savepbq;
1403d90bee97SLionel Sambuc 	union node *n;
1404d90bee97SLionel Sambuc 	char *volatile str = NULL;
1405d90bee97SLionel Sambuc 	struct jmploc jmploc;
1406d90bee97SLionel Sambuc 	struct jmploc *volatile savehandler = NULL;
1407d90bee97SLionel Sambuc 	int savelen;
1408d90bee97SLionel Sambuc 	int saveprompt;
1409d90bee97SLionel Sambuc 
1410d90bee97SLionel Sambuc 	savepbq = parsebackquote;
1411d90bee97SLionel Sambuc 	if (setjmp(jmploc.loc)) {
1412d90bee97SLionel Sambuc 		if (str)
1413d90bee97SLionel Sambuc 			ckfree(str);
1414d90bee97SLionel Sambuc 		parsebackquote = 0;
1415d90bee97SLionel Sambuc 		handler = savehandler;
1416d90bee97SLionel Sambuc 		longjmp(handler->loc, 1);
1417d90bee97SLionel Sambuc 	}
1418d90bee97SLionel Sambuc 	INTOFF;
1419d90bee97SLionel Sambuc 	str = NULL;
1420d90bee97SLionel Sambuc 	savelen = out - stackblock();
1421d90bee97SLionel Sambuc 	if (savelen > 0) {
1422d90bee97SLionel Sambuc 		str = ckmalloc(savelen);
1423d90bee97SLionel Sambuc 		memcpy(str, stackblock(), savelen);
1424d90bee97SLionel Sambuc 	}
1425d90bee97SLionel Sambuc 	savehandler = handler;
1426d90bee97SLionel Sambuc 	handler = &jmploc;
1427d90bee97SLionel Sambuc 	INTON;
1428d90bee97SLionel Sambuc         if (oldstyle) {
1429d90bee97SLionel Sambuc                 /* We must read until the closing backquote, giving special
1430d90bee97SLionel Sambuc                    treatment to some slashes, and then push the string and
1431d90bee97SLionel Sambuc                    reread it as input, interpreting it normally.  */
1432d90bee97SLionel Sambuc                 char *pout;
1433d90bee97SLionel Sambuc                 int pc;
1434d90bee97SLionel Sambuc                 int psavelen;
1435d90bee97SLionel Sambuc                 char *pstr;
1436d90bee97SLionel Sambuc 
1437d90bee97SLionel Sambuc 
1438d90bee97SLionel Sambuc                 STARTSTACKSTR(pout);
1439d90bee97SLionel Sambuc 		for (;;) {
1440d90bee97SLionel Sambuc 			if (needprompt) {
1441d90bee97SLionel Sambuc 				setprompt(2);
1442d90bee97SLionel Sambuc 				needprompt = 0;
1443d90bee97SLionel Sambuc 			}
1444d90bee97SLionel Sambuc 			switch (pc = pgetc()) {
1445d90bee97SLionel Sambuc 			case '`':
1446d90bee97SLionel Sambuc 				goto done;
1447d90bee97SLionel Sambuc 
1448d90bee97SLionel Sambuc 			case '\\':
1449d90bee97SLionel Sambuc                                 if ((pc = pgetc()) == '\n') {
1450d90bee97SLionel Sambuc 					plinno++;
1451d90bee97SLionel Sambuc 					if (doprompt)
1452d90bee97SLionel Sambuc 						setprompt(2);
1453d90bee97SLionel Sambuc 					else
1454d90bee97SLionel Sambuc 						setprompt(0);
1455d90bee97SLionel Sambuc 					/*
1456d90bee97SLionel Sambuc 					 * If eating a newline, avoid putting
1457d90bee97SLionel Sambuc 					 * the newline into the new character
1458d90bee97SLionel Sambuc 					 * stream (via the STPUTC after the
1459d90bee97SLionel Sambuc 					 * switch).
1460d90bee97SLionel Sambuc 					 */
1461d90bee97SLionel Sambuc 					continue;
1462d90bee97SLionel Sambuc 				}
1463d90bee97SLionel Sambuc                                 if (pc != '\\' && pc != '`' && pc != '$'
1464d90bee97SLionel Sambuc                                     && (!ISDBLQUOTE() || pc != '"'))
1465d90bee97SLionel Sambuc                                         STPUTC('\\', pout);
1466d90bee97SLionel Sambuc 				break;
1467d90bee97SLionel Sambuc 
1468d90bee97SLionel Sambuc 			case '\n':
1469d90bee97SLionel Sambuc 				plinno++;
1470d90bee97SLionel Sambuc 				needprompt = doprompt;
1471d90bee97SLionel Sambuc 				break;
1472d90bee97SLionel Sambuc 
1473d90bee97SLionel Sambuc 			case PEOF:
1474d90bee97SLionel Sambuc 			        startlinno = plinno;
1475d90bee97SLionel Sambuc 				synerror("EOF in backquote substitution");
1476d90bee97SLionel Sambuc  				break;
1477d90bee97SLionel Sambuc 
1478d90bee97SLionel Sambuc 			default:
1479d90bee97SLionel Sambuc 				break;
1480d90bee97SLionel Sambuc 			}
1481d90bee97SLionel Sambuc 			STPUTC(pc, pout);
1482d90bee97SLionel Sambuc                 }
1483d90bee97SLionel Sambuc done:
1484d90bee97SLionel Sambuc                 STPUTC('\0', pout);
1485d90bee97SLionel Sambuc                 psavelen = pout - stackblock();
1486d90bee97SLionel Sambuc                 if (psavelen > 0) {
1487d90bee97SLionel Sambuc 			pstr = grabstackstr(pout);
1488d90bee97SLionel Sambuc 			setinputstring(pstr, 1);
1489d90bee97SLionel Sambuc                 }
1490d90bee97SLionel Sambuc         }
1491d90bee97SLionel Sambuc 	nlpp = &bqlist;
1492d90bee97SLionel Sambuc 	while (*nlpp)
1493d90bee97SLionel Sambuc 		nlpp = &(*nlpp)->next;
1494d90bee97SLionel Sambuc 	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1495d90bee97SLionel Sambuc 	(*nlpp)->next = NULL;
1496d90bee97SLionel Sambuc 	parsebackquote = oldstyle;
1497d90bee97SLionel Sambuc 
1498d90bee97SLionel Sambuc 	if (oldstyle) {
1499d90bee97SLionel Sambuc 		saveprompt = doprompt;
1500d90bee97SLionel Sambuc 		doprompt = 0;
1501d90bee97SLionel Sambuc 	} else
1502d90bee97SLionel Sambuc 		saveprompt = 0;
1503d90bee97SLionel Sambuc 
1504d90bee97SLionel Sambuc 	n = list(0, oldstyle);
1505d90bee97SLionel Sambuc 
1506d90bee97SLionel Sambuc 	if (oldstyle)
1507d90bee97SLionel Sambuc 		doprompt = saveprompt;
1508d90bee97SLionel Sambuc 	else {
1509d90bee97SLionel Sambuc 		if (readtoken() != TRP)
1510d90bee97SLionel Sambuc 			synexpect(TRP);
1511d90bee97SLionel Sambuc 	}
1512d90bee97SLionel Sambuc 
1513d90bee97SLionel Sambuc 	(*nlpp)->n = n;
1514d90bee97SLionel Sambuc         if (oldstyle) {
1515d90bee97SLionel Sambuc 		/*
1516d90bee97SLionel Sambuc 		 * Start reading from old file again, ignoring any pushed back
1517d90bee97SLionel Sambuc 		 * tokens left from the backquote parsing
1518d90bee97SLionel Sambuc 		 */
1519d90bee97SLionel Sambuc                 popfile();
1520d90bee97SLionel Sambuc 		tokpushback = 0;
1521d90bee97SLionel Sambuc 	}
1522d90bee97SLionel Sambuc 	while (stackblocksize() <= savelen)
1523d90bee97SLionel Sambuc 		growstackblock();
1524d90bee97SLionel Sambuc 	STARTSTACKSTR(out);
1525d90bee97SLionel Sambuc 	if (str) {
1526d90bee97SLionel Sambuc 		memcpy(out, str, savelen);
1527d90bee97SLionel Sambuc 		STADJUST(savelen, out);
1528d90bee97SLionel Sambuc 		INTOFF;
1529d90bee97SLionel Sambuc 		ckfree(str);
1530d90bee97SLionel Sambuc 		str = NULL;
1531d90bee97SLionel Sambuc 		INTON;
1532d90bee97SLionel Sambuc 	}
1533d90bee97SLionel Sambuc 	parsebackquote = savepbq;
1534d90bee97SLionel Sambuc 	handler = savehandler;
1535d90bee97SLionel Sambuc 	if (arinest || ISDBLQUOTE())
1536d90bee97SLionel Sambuc 		USTPUTC(CTLBACKQ | CTLQUOTE, out);
1537d90bee97SLionel Sambuc 	else
1538d90bee97SLionel Sambuc 		USTPUTC(CTLBACKQ, out);
1539d90bee97SLionel Sambuc 	if (oldstyle)
1540d90bee97SLionel Sambuc 		goto parsebackq_oldreturn;
1541d90bee97SLionel Sambuc 	else
1542d90bee97SLionel Sambuc 		goto parsebackq_newreturn;
1543d90bee97SLionel Sambuc }
1544d90bee97SLionel Sambuc 
1545d90bee97SLionel Sambuc /*
1546d90bee97SLionel Sambuc  * Parse an arithmetic expansion (indicate start of one and set state)
1547d90bee97SLionel Sambuc  */
1548d90bee97SLionel Sambuc parsearith: {
1549d90bee97SLionel Sambuc 
1550d90bee97SLionel Sambuc 	if (++arinest == 1) {
1551d90bee97SLionel Sambuc 		prevsyntax = syntax;
1552d90bee97SLionel Sambuc 		syntax = ARISYNTAX;
1553d90bee97SLionel Sambuc 		USTPUTC(CTLARI, out);
1554d90bee97SLionel Sambuc 		if (ISDBLQUOTE())
1555d90bee97SLionel Sambuc 			USTPUTC('"',out);
1556d90bee97SLionel Sambuc 		else
1557d90bee97SLionel Sambuc 			USTPUTC(' ',out);
1558d90bee97SLionel Sambuc 	} else {
1559d90bee97SLionel Sambuc 		/*
1560d90bee97SLionel Sambuc 		 * we collapse embedded arithmetic expansion to
1561d90bee97SLionel Sambuc 		 * parenthesis, which should be equivalent
1562d90bee97SLionel Sambuc 		 */
1563d90bee97SLionel Sambuc 		USTPUTC('(', out);
1564d90bee97SLionel Sambuc 	}
1565d90bee97SLionel Sambuc 	goto parsearith_return;
1566d90bee97SLionel Sambuc }
1567d90bee97SLionel Sambuc 
1568d90bee97SLionel Sambuc } /* end of readtoken */
1569d90bee97SLionel Sambuc 
1570d90bee97SLionel Sambuc 
1571d90bee97SLionel Sambuc 
1572d90bee97SLionel Sambuc #ifdef mkinit
1573d90bee97SLionel Sambuc RESET {
1574d90bee97SLionel Sambuc 	tokpushback = 0;
1575d90bee97SLionel Sambuc 	checkkwd = 0;
1576d90bee97SLionel Sambuc }
1577d90bee97SLionel Sambuc #endif
1578d90bee97SLionel Sambuc 
1579d90bee97SLionel Sambuc /*
1580d90bee97SLionel Sambuc  * Returns true if the text contains nothing to expand (no dollar signs
1581d90bee97SLionel Sambuc  * or backquotes).
1582d90bee97SLionel Sambuc  */
1583d90bee97SLionel Sambuc 
1584d90bee97SLionel Sambuc STATIC int
noexpand(char * text)1585d90bee97SLionel Sambuc noexpand(char *text)
1586d90bee97SLionel Sambuc {
1587d90bee97SLionel Sambuc 	char *p;
1588d90bee97SLionel Sambuc 	char c;
1589d90bee97SLionel Sambuc 
1590d90bee97SLionel Sambuc 	p = text;
1591d90bee97SLionel Sambuc 	while ((c = *p++) != '\0') {
1592d90bee97SLionel Sambuc 		if (c == CTLQUOTEMARK)
1593d90bee97SLionel Sambuc 			continue;
1594d90bee97SLionel Sambuc 		if (c == CTLESC)
1595d90bee97SLionel Sambuc 			p++;
1596d90bee97SLionel Sambuc 		else if (BASESYNTAX[(int)c] == CCTL)
1597d90bee97SLionel Sambuc 			return 0;
1598d90bee97SLionel Sambuc 	}
1599d90bee97SLionel Sambuc 	return 1;
1600d90bee97SLionel Sambuc }
1601d90bee97SLionel Sambuc 
1602d90bee97SLionel Sambuc 
1603d90bee97SLionel Sambuc /*
1604d90bee97SLionel Sambuc  * Return true if the argument is a legal variable name (a letter or
1605d90bee97SLionel Sambuc  * underscore followed by zero or more letters, underscores, and digits).
1606d90bee97SLionel Sambuc  */
1607d90bee97SLionel Sambuc 
1608d90bee97SLionel Sambuc int
goodname(char * name)1609d90bee97SLionel Sambuc goodname(char *name)
1610d90bee97SLionel Sambuc 	{
1611d90bee97SLionel Sambuc 	char *p;
1612d90bee97SLionel Sambuc 
1613d90bee97SLionel Sambuc 	p = name;
1614d90bee97SLionel Sambuc 	if (! is_name(*p))
1615d90bee97SLionel Sambuc 		return 0;
1616d90bee97SLionel Sambuc 	while (*++p) {
1617d90bee97SLionel Sambuc 		if (! is_in_name(*p))
1618d90bee97SLionel Sambuc 			return 0;
1619d90bee97SLionel Sambuc 	}
1620d90bee97SLionel Sambuc 	return 1;
1621d90bee97SLionel Sambuc }
1622d90bee97SLionel Sambuc 
1623d90bee97SLionel Sambuc 
1624d90bee97SLionel Sambuc /*
1625d90bee97SLionel Sambuc  * Called when an unexpected token is read during the parse.  The argument
1626d90bee97SLionel Sambuc  * is the token that is expected, or -1 if more than one type of token can
1627d90bee97SLionel Sambuc  * occur at this point.
1628d90bee97SLionel Sambuc  */
1629d90bee97SLionel Sambuc 
1630d90bee97SLionel Sambuc STATIC void
synexpect(int token)1631d90bee97SLionel Sambuc synexpect(int token)
1632d90bee97SLionel Sambuc {
1633d90bee97SLionel Sambuc 	char msg[64];
1634d90bee97SLionel Sambuc 
1635d90bee97SLionel Sambuc 	if (token >= 0) {
1636d90bee97SLionel Sambuc 		fmtstr(msg, 64, "%s unexpected (expecting %s)",
1637d90bee97SLionel Sambuc 			tokname[lasttoken], tokname[token]);
1638d90bee97SLionel Sambuc 	} else {
1639d90bee97SLionel Sambuc 		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1640d90bee97SLionel Sambuc 	}
1641d90bee97SLionel Sambuc 	synerror(msg);
1642d90bee97SLionel Sambuc 	/* NOTREACHED */
1643d90bee97SLionel Sambuc }
1644d90bee97SLionel Sambuc 
1645d90bee97SLionel Sambuc 
1646d90bee97SLionel Sambuc STATIC void
synerror(const char * msg)1647d90bee97SLionel Sambuc synerror(const char *msg)
1648d90bee97SLionel Sambuc {
1649d90bee97SLionel Sambuc 	if (commandname)
1650d90bee97SLionel Sambuc 		outfmt(&errout, "%s: %d: ", commandname, startlinno);
1651d90bee97SLionel Sambuc 	else
1652d90bee97SLionel Sambuc 		outfmt(&errout, "%s: ", getprogname());
1653d90bee97SLionel Sambuc 	outfmt(&errout, "Syntax error: %s\n", msg);
1654d90bee97SLionel Sambuc 	error(NULL);
1655d90bee97SLionel Sambuc 	/* NOTREACHED */
1656d90bee97SLionel Sambuc }
1657d90bee97SLionel Sambuc 
1658d90bee97SLionel Sambuc STATIC void
setprompt(int which)1659d90bee97SLionel Sambuc setprompt(int which)
1660d90bee97SLionel Sambuc {
1661d90bee97SLionel Sambuc 	whichprompt = which;
1662d90bee97SLionel Sambuc 
1663d90bee97SLionel Sambuc #ifndef SMALL
1664d90bee97SLionel Sambuc 	if (!el)
1665d90bee97SLionel Sambuc #endif
1666d90bee97SLionel Sambuc 		out2str(getprompt(NULL));
1667d90bee97SLionel Sambuc }
1668d90bee97SLionel Sambuc 
1669d90bee97SLionel Sambuc /*
1670d90bee97SLionel Sambuc  * called by editline -- any expansions to the prompt
1671d90bee97SLionel Sambuc  *    should be added here.
1672d90bee97SLionel Sambuc  */
1673d90bee97SLionel Sambuc const char *
getprompt(void * unused)1674d90bee97SLionel Sambuc getprompt(void *unused)
1675d90bee97SLionel Sambuc 	{
1676d90bee97SLionel Sambuc 	switch (whichprompt) {
1677d90bee97SLionel Sambuc 	case 0:
1678d90bee97SLionel Sambuc 		return "";
1679d90bee97SLionel Sambuc 	case 1:
1680d90bee97SLionel Sambuc 		return ps1val();
1681d90bee97SLionel Sambuc 	case 2:
1682d90bee97SLionel Sambuc 		return ps2val();
1683d90bee97SLionel Sambuc 	default:
1684d90bee97SLionel Sambuc 		return "<internal prompt error>";
1685d90bee97SLionel Sambuc 	}
1686d90bee97SLionel Sambuc }
1687