parser.c revision 20425
1121934Sharti/*-
2121934Sharti * Copyright (c) 1991, 1993
3121934Sharti *	The Regents of the University of California.  All rights reserved.
4121934Sharti *
5121934Sharti * This code is derived from software contributed to Berkeley by
6131826Sharti * Kenneth Almquist.
7131826Sharti *
8121934Sharti * Redistribution and use in source and binary forms, with or without
9121934Sharti * modification, are permitted provided that the following conditions
10121934Sharti * are met:
11121934Sharti * 1. Redistributions of source code must retain the above copyright
12121934Sharti *    notice, this list of conditions and the following disclaimer.
13121934Sharti * 2. Redistributions in binary form must reproduce the above copyright
14121934Sharti *    notice, this list of conditions and the following disclaimer in the
15121934Sharti *    documentation and/or other materials provided with the distribution.
16121934Sharti * 3. All advertising materials mentioning features or use of this software
17121934Sharti *    must display the following acknowledgement:
18121934Sharti *	This product includes software developed by the University of
19121934Sharti *	California, Berkeley and its contributors.
20121934Sharti * 4. Neither the name of the University nor the names of its contributors
21121934Sharti *    may be used to endorse or promote products derived from this software
22121934Sharti *    without specific prior written permission.
23121934Sharti *
24121934Sharti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25121934Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26121934Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27121934Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28121934Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29133492Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30121934Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31121934Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32121934Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33121934Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34121934Sharti * SUCH DAMAGE.
35121934Sharti *
36121934Sharti *	$Id: parser.c,v 1.16 1996/09/10 02:42:33 peter Exp $
37121934Sharti */
38121934Sharti
39121934Sharti#ifndef lint
40121934Shartistatic char const sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
41121934Sharti#endif /* not lint */
42121934Sharti
43121934Sharti#include <stdlib.h>
44121934Sharti
45121934Sharti#include "shell.h"
46121934Sharti#include "parser.h"
47121934Sharti#include "nodes.h"
48121934Sharti#include "expand.h"	/* defines rmescapes() */
49121934Sharti#include "redir.h"	/* defines copyfd() */
50121934Sharti#include "syntax.h"
51121934Sharti#include "options.h"
52121934Sharti#include "input.h"
53121934Sharti#include "output.h"
54121934Sharti#include "var.h"
55121934Sharti#include "error.h"
56121934Sharti#include "memalloc.h"
57121934Sharti#include "mystring.h"
58121934Sharti#include "alias.h"
59121934Sharti#include "show.h"
60121934Sharti#ifndef NO_HISTORY
61121934Sharti#include "myhistedit.h"
62121934Sharti#endif
63121934Sharti
64121934Sharti/*
65121934Sharti * Shell command parser.
66121934Sharti */
67121934Sharti
68121934Sharti#define EOFMARKLEN 79
69121934Sharti
70121934Sharti/* values returned by readtoken */
71121934Sharti#include "token.h"
72121934Sharti
73121934Sharti
74121934Sharti
75121934Shartistruct heredoc {
76121934Sharti	struct heredoc *next;	/* next here document in list */
77121934Sharti	union node *here;		/* redirection node */
78121934Sharti	char *eofmark;		/* string indicating end of input */
79121934Sharti	int striptabs;		/* if set, strip leading tabs */
80121934Sharti};
81121934Sharti
82121934Sharti
83121934Sharti
84121934Shartistruct heredoc *heredoclist;	/* list of here documents to read */
85121934Shartiint parsebackquote;		/* nonzero if we are inside backquotes */
86121934Shartiint doprompt;			/* if set, prompt the user */
87121934Shartiint needprompt;			/* true if interactive and at start of line */
88121934Shartiint lasttoken;			/* last token read */
89121934ShartiMKINIT int tokpushback;		/* last token pushed back */
90121934Shartichar *wordtext;			/* text of last word returned by readtoken */
91121934ShartiMKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
92121934Shartistruct nodelist *backquotelist;
93121934Shartiunion node *redirnode;
94121934Shartistruct heredoc *heredoc;
95121934Shartiint quoteflag;			/* set if (part of) last token was quoted */
96121934Shartiint startlinno;			/* line # where last token started */
97121934Sharti
98121934Sharti/* XXX When 'noaliases' is set to one, no alias expansion takes place. */
99121934Shartistatic int noaliases = 0;
100121934Sharti
101121934Sharti#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
102121934Sharti#ifdef GDB_HACK
103121934Shartistatic const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
104121934Shartistatic const char types[] = "}-+?=";
105121934Sharti#endif
106121934Sharti
107121934Sharti
108121934ShartiSTATIC union node *list __P((int));
109121934ShartiSTATIC union node *andor __P((void));
110121934ShartiSTATIC union node *pipeline __P((void));
111121934ShartiSTATIC union node *command __P((void));
112121934ShartiSTATIC union node *simplecmd __P((union node **, union node *));
113121934ShartiSTATIC union node *makename __P((void));
114121934ShartiSTATIC void parsefname __P((void));
115121934ShartiSTATIC void parseheredoc __P((void));
116121934ShartiSTATIC int peektoken __P((void));
117121934ShartiSTATIC int readtoken __P((void));
118121934ShartiSTATIC int xxreadtoken __P((void));
119121934ShartiSTATIC int readtoken1 __P((int, char const *, char *, int));
120121934ShartiSTATIC int noexpand __P((char *));
121121934ShartiSTATIC void synexpect __P((int));
122121934ShartiSTATIC void synerror __P((char *));
123121934ShartiSTATIC void setprompt __P((int));
124121934Sharti
125121934Sharti
126121934Sharti/*
127121934Sharti * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
128121934Sharti * valid parse tree indicating a blank line.)
129121934Sharti */
130121934Sharti
131121934Shartiunion node *
132121934Shartiparsecmd(interact)
133121934Sharti	int interact;
134121934Sharti{
135121934Sharti	int t;
136121934Sharti
137121934Sharti	doprompt = interact;
138121934Sharti	if (doprompt)
139121934Sharti		setprompt(1);
140121934Sharti	else
141121934Sharti		setprompt(0);
142121934Sharti	needprompt = 0;
143121934Sharti	t = readtoken();
144121934Sharti	if (t == TEOF)
145121934Sharti		return NEOF;
146121934Sharti	if (t == TNL)
147121934Sharti		return NULL;
148121934Sharti	tokpushback++;
149121934Sharti	return list(1);
150121934Sharti}
151121934Sharti
152121934Sharti
153121934ShartiSTATIC union node *
154121934Shartilist(nlflag)
155121934Sharti	int nlflag;
156121934Sharti{
157121934Sharti	union node *n1, *n2, *n3;
158121934Sharti	int tok;
159121934Sharti
160121934Sharti	checkkwd = 2;
161121934Sharti	if (nlflag == 0 && tokendlist[peektoken()])
162121934Sharti		return NULL;
163121934Sharti	n1 = NULL;
164121934Sharti	for (;;) {
165121934Sharti		n2 = andor();
166121934Sharti		tok = readtoken();
167121934Sharti		if (tok == TBACKGND) {
168121934Sharti			if (n2->type == NCMD || n2->type == NPIPE) {
169121934Sharti				n2->ncmd.backgnd = 1;
170121934Sharti			} else if (n2->type == NREDIR) {
171121934Sharti				n2->type = NBACKGND;
172121934Sharti			} else {
173121934Sharti				n3 = (union node *)stalloc(sizeof (struct nredir));
174121934Sharti				n3->type = NBACKGND;
175121934Sharti				n3->nredir.n = n2;
176121934Sharti				n3->nredir.redirect = NULL;
177121934Sharti				n2 = n3;
178121934Sharti			}
179121934Sharti		}
180121934Sharti		if (n1 == NULL) {
181121934Sharti			n1 = n2;
182121934Sharti		}
183121934Sharti		else {
184121934Sharti			n3 = (union node *)stalloc(sizeof (struct nbinary));
185121934Sharti			n3->type = NSEMI;
186121934Sharti			n3->nbinary.ch1 = n1;
187121934Sharti			n3->nbinary.ch2 = n2;
188121934Sharti			n1 = n3;
189121934Sharti		}
190121934Sharti		switch (tok) {
191121934Sharti		case TBACKGND:
192121934Sharti		case TSEMI:
193121934Sharti			tok = readtoken();
194121934Sharti			/* fall through */
195121934Sharti		case TNL:
196121934Sharti			if (tok == TNL) {
197121934Sharti				parseheredoc();
198121934Sharti				if (nlflag)
199121934Sharti					return n1;
200121934Sharti			} else {
201121934Sharti				tokpushback++;
202121934Sharti			}
203121934Sharti			checkkwd = 2;
204121934Sharti			if (tokendlist[peektoken()])
205121934Sharti				return n1;
206121934Sharti			break;
207121934Sharti		case TEOF:
208121934Sharti			if (heredoclist)
209133492Sharti				parseheredoc();
210121934Sharti			else
211133492Sharti				pungetc();		/* push back EOF on input */
212133492Sharti			return n1;
213133492Sharti		default:
214121934Sharti			if (nlflag)
215121934Sharti				synexpect(-1);
216121934Sharti			tokpushback++;
217121934Sharti			return n1;
218121934Sharti		}
219121934Sharti	}
220121934Sharti}
221121934Sharti
222121934Sharti
223121934Sharti
224121934ShartiSTATIC union node *
225121934Shartiandor() {
226121934Sharti	union node *n1, *n2, *n3;
227121934Sharti	int t;
228121934Sharti
229121934Sharti	n1 = pipeline();
230121934Sharti	for (;;) {
231121934Sharti		if ((t = readtoken()) == TAND) {
232121934Sharti			t = NAND;
233121934Sharti		} else if (t == TOR) {
234121934Sharti			t = NOR;
235121934Sharti		} else {
236121934Sharti			tokpushback++;
237121934Sharti			return n1;
238121934Sharti		}
239121934Sharti		n2 = pipeline();
240121934Sharti		n3 = (union node *)stalloc(sizeof (struct nbinary));
241121934Sharti		n3->type = t;
242121934Sharti		n3->nbinary.ch1 = n1;
243121934Sharti		n3->nbinary.ch2 = n2;
244121934Sharti		n1 = n3;
245121934Sharti	}
246121934Sharti}
247121934Sharti
248121934Sharti
249121934Sharti
250121934ShartiSTATIC union node *
251121934Shartipipeline() {
252121934Sharti	union node *n1, *pipenode;
253121934Sharti	struct nodelist *lp, *prev;
254121934Sharti
255121934Sharti	TRACE(("pipeline: entered\n"));
256121934Sharti	n1 = command();
257121934Sharti	if (readtoken() == TPIPE) {
258121934Sharti		pipenode = (union node *)stalloc(sizeof (struct npipe));
259121934Sharti		pipenode->type = NPIPE;
260121934Sharti		pipenode->npipe.backgnd = 0;
261121934Sharti		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
262121934Sharti		pipenode->npipe.cmdlist = lp;
263121934Sharti		lp->n = n1;
264121934Sharti		do {
265121934Sharti			prev = lp;
266121934Sharti			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
267121934Sharti			lp->n = command();
268121934Sharti			prev->next = lp;
269121934Sharti		} while (readtoken() == TPIPE);
270121934Sharti		lp->next = NULL;
271121934Sharti		n1 = pipenode;
272121934Sharti	}
273121934Sharti	tokpushback++;
274121934Sharti	return n1;
275121934Sharti}
276121934Sharti
277121934Sharti
278121934Sharti
279121934ShartiSTATIC union node *
280121934Sharticommand() {
281121934Sharti	union node *n1, *n2;
282121934Sharti	union node *ap, **app;
283121934Sharti	union node *cp, **cpp;
284121934Sharti	union node *redir, **rpp;
285121934Sharti	int t, negate = 0;
286121934Sharti
287121934Sharti	checkkwd = 2;
288121934Sharti	redir = NULL;
289121934Sharti	n1 = NULL;
290121934Sharti	rpp = &redir;
291121934Sharti
292121934Sharti	/* Check for redirection which may precede command */
293121934Sharti	while (readtoken() == TREDIR) {
294121934Sharti		*rpp = n2 = redirnode;
295121934Sharti		rpp = &n2->nfile.next;
296121934Sharti		parsefname();
297121934Sharti	}
298121934Sharti	tokpushback++;
299121934Sharti
300121934Sharti	while (readtoken() == TNOT) {
301121934Sharti		TRACE(("command: TNOT recognized\n"));
302121934Sharti		negate = !negate;
303121934Sharti	}
304121934Sharti	tokpushback++;
305121934Sharti
306121934Sharti	switch (readtoken()) {
307121934Sharti	case TIF:
308121934Sharti		n1 = (union node *)stalloc(sizeof (struct nif));
309121934Sharti		n1->type = NIF;
310121934Sharti		n1->nif.test = list(0);
311121934Sharti		if (readtoken() != TTHEN)
312121934Sharti			synexpect(TTHEN);
313121934Sharti		n1->nif.ifpart = list(0);
314121934Sharti		n2 = n1;
315121934Sharti		while (readtoken() == TELIF) {
316121934Sharti			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
317121934Sharti			n2 = n2->nif.elsepart;
318121934Sharti			n2->type = NIF;
319121934Sharti			n2->nif.test = list(0);
320121934Sharti			if (readtoken() != TTHEN)
321121934Sharti				synexpect(TTHEN);
322121934Sharti			n2->nif.ifpart = list(0);
323121934Sharti		}
324121934Sharti		if (lasttoken == TELSE)
325121934Sharti			n2->nif.elsepart = list(0);
326121934Sharti		else {
327121934Sharti			n2->nif.elsepart = NULL;
328121934Sharti			tokpushback++;
329121934Sharti		}
330121934Sharti		if (readtoken() != TFI)
331121934Sharti			synexpect(TFI);
332121934Sharti		checkkwd = 1;
333121934Sharti		break;
334121934Sharti	case TWHILE:
335121934Sharti	case TUNTIL: {
336121934Sharti		int got;
337121934Sharti		n1 = (union node *)stalloc(sizeof (struct nbinary));
338121934Sharti		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
339121934Sharti		n1->nbinary.ch1 = list(0);
340121934Sharti		if ((got=readtoken()) != TDO) {
341121934ShartiTRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
342121934Sharti			synexpect(TDO);
343121934Sharti		}
344121934Sharti		n1->nbinary.ch2 = list(0);
345121934Sharti		if (readtoken() != TDONE)
346121934Sharti			synexpect(TDONE);
347121934Sharti		checkkwd = 1;
348121934Sharti		break;
349121934Sharti	}
350121934Sharti	case TFOR:
351121934Sharti		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
352121934Sharti			synerror("Bad for loop variable");
353121934Sharti		n1 = (union node *)stalloc(sizeof (struct nfor));
354121934Sharti		n1->type = NFOR;
355121934Sharti		n1->nfor.var = wordtext;
356121934Sharti		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
357121934Sharti			app = &ap;
358121934Sharti			while (readtoken() == TWORD) {
359121934Sharti				n2 = (union node *)stalloc(sizeof (struct narg));
360121934Sharti				n2->type = NARG;
361121934Sharti				n2->narg.text = wordtext;
362121934Sharti				n2->narg.backquote = backquotelist;
363121934Sharti				*app = n2;
364121934Sharti				app = &n2->narg.next;
365121934Sharti			}
366121934Sharti			*app = NULL;
367121934Sharti			n1->nfor.args = ap;
368121934Sharti			if (lasttoken != TNL && lasttoken != TSEMI)
369121934Sharti				synexpect(-1);
370121934Sharti		} else {
371121934Sharti#ifndef GDB_HACK
372121934Sharti			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
373121934Sharti								   '@', '=', '\0'};
374121934Sharti#endif
375121934Sharti			n2 = (union node *)stalloc(sizeof (struct narg));
376121934Sharti			n2->type = NARG;
377121934Sharti			n2->narg.text = (char *)argvars;
378121934Sharti			n2->narg.backquote = NULL;
379121934Sharti			n2->narg.next = NULL;
380121934Sharti			n1->nfor.args = n2;
381121934Sharti			/*
382121934Sharti			 * Newline or semicolon here is optional (but note
383121934Sharti			 * that the original Bourne shell only allowed NL).
384121934Sharti			 */
385121934Sharti			if (lasttoken != TNL && lasttoken != TSEMI)
386121934Sharti				tokpushback++;
387121934Sharti		}
388121934Sharti		checkkwd = 2;
389121934Sharti		if ((t = readtoken()) == TDO)
390121934Sharti			t = TDONE;
391121934Sharti		else if (t == TBEGIN)
392121934Sharti			t = TEND;
393121934Sharti		else
394121934Sharti			synexpect(-1);
395121934Sharti		n1->nfor.body = list(0);
396121934Sharti		if (readtoken() != t)
397121934Sharti			synexpect(t);
398121934Sharti		checkkwd = 1;
399121934Sharti		break;
400121934Sharti	case TCASE:
401121934Sharti		n1 = (union node *)stalloc(sizeof (struct ncase));
402121934Sharti		n1->type = NCASE;
403121934Sharti		if (readtoken() != TWORD)
404121934Sharti			synexpect(TWORD);
405121934Sharti		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
406121934Sharti		n2->type = NARG;
407121934Sharti		n2->narg.text = wordtext;
408121934Sharti		n2->narg.backquote = backquotelist;
409121934Sharti		n2->narg.next = NULL;
410121934Sharti		while (readtoken() == TNL);
411121934Sharti		if (lasttoken != TWORD || ! equal(wordtext, "in"))
412121934Sharti			synerror("expecting \"in\"");
413121934Sharti		cpp = &n1->ncase.cases;
414121934Sharti		noaliases = 1;	/* turn off alias expansion */
415121934Sharti		checkkwd = 2, readtoken();
416121934Sharti		do {
417121934Sharti			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
418121934Sharti			cp->type = NCLIST;
419121934Sharti			app = &cp->nclist.pattern;
420121934Sharti			for (;;) {
421121934Sharti				*app = ap = (union node *)stalloc(sizeof (struct narg));
422121934Sharti				ap->type = NARG;
423121934Sharti				ap->narg.text = wordtext;
424121934Sharti				ap->narg.backquote = backquotelist;
425121934Sharti				if (checkkwd = 2, readtoken() != TPIPE)
426121934Sharti					break;
427121934Sharti				app = &ap->narg.next;
428121934Sharti				readtoken();
429121934Sharti			}
430121934Sharti			ap->narg.next = NULL;
431121934Sharti			if (lasttoken != TRP)
432121934Sharti				noaliases = 0, synexpect(TRP);
433121934Sharti			cp->nclist.body = list(0);
434121934Sharti
435121934Sharti			checkkwd = 2;
436121934Sharti			if ((t = readtoken()) != TESAC) {
437121934Sharti				if (t != TENDCASE)
438121934Sharti					noaliases = 0, synexpect(TENDCASE);
439121934Sharti				else
440121934Sharti					checkkwd = 2, readtoken();
441121934Sharti			}
442121934Sharti			cpp = &cp->nclist.next;
443121934Sharti		} while(lasttoken != TESAC);
444121934Sharti		noaliases = 0;	/* reset alias expansion */
445121934Sharti		*cpp = NULL;
446121934Sharti		checkkwd = 1;
447121934Sharti		break;
448121934Sharti	case TLP:
449121934Sharti		n1 = (union node *)stalloc(sizeof (struct nredir));
450121934Sharti		n1->type = NSUBSHELL;
451121934Sharti		n1->nredir.n = list(0);
452121934Sharti		n1->nredir.redirect = NULL;
453121934Sharti		if (readtoken() != TRP)
454121934Sharti			synexpect(TRP);
455121934Sharti		checkkwd = 1;
456121934Sharti		break;
457121934Sharti	case TBEGIN:
458121934Sharti		n1 = list(0);
459121934Sharti		if (readtoken() != TEND)
460121934Sharti			synexpect(TEND);
461121934Sharti		checkkwd = 1;
462121934Sharti		break;
463121934Sharti	/* Handle an empty command like other simple commands.  */
464121934Sharti	case TSEMI:
465121934Sharti		/*
466121934Sharti		 * An empty command before a ; doesn't make much sense, and
467121934Sharti		 * should certainly be disallowed in the case of `if ;'.
468121934Sharti		 */
469121934Sharti		if (!redir)
470121934Sharti			synexpect(-1);
471121934Sharti	case TAND:
472121934Sharti	case TOR:
473121934Sharti	case TNL:
474121934Sharti	case TEOF:
475121934Sharti	case TWORD:
476121934Sharti	case TRP:
477121934Sharti		tokpushback++;
478121934Sharti		n1 = simplecmd(rpp, redir);
479121934Sharti		goto checkneg;
480121934Sharti	default:
481121934Sharti		synexpect(-1);
482121934Sharti	}
483121934Sharti
484121934Sharti	/* Now check for redirection which may follow command */
485121934Sharti	while (readtoken() == TREDIR) {
486121934Sharti		*rpp = n2 = redirnode;
487121934Sharti		rpp = &n2->nfile.next;
488121934Sharti		parsefname();
489121934Sharti	}
490121934Sharti	tokpushback++;
491121934Sharti	*rpp = NULL;
492121934Sharti	if (redir) {
493121934Sharti		if (n1->type != NSUBSHELL) {
494121934Sharti			n2 = (union node *)stalloc(sizeof (struct nredir));
495121934Sharti			n2->type = NREDIR;
496121934Sharti			n2->nredir.n = n1;
497121934Sharti			n1 = n2;
498121934Sharti		}
499121934Sharti		n1->nredir.redirect = redir;
500121934Sharti	}
501121934Sharti
502121934Sharticheckneg:
503121934Sharti	if (negate) {
504121934Sharti		n2 = (union node *)stalloc(sizeof (struct nnot));
505121934Sharti		n2->type = NNOT;
506121934Sharti		n2->nnot.com = n1;
507121934Sharti		return n2;
508121934Sharti	}
509121934Sharti	else
510121934Sharti		return n1;
511121934Sharti}
512121934Sharti
513121934Sharti
514121934ShartiSTATIC union node *
515121934Shartisimplecmd(rpp, redir)
516121934Sharti	union node **rpp, *redir;
517121934Sharti	{
518121934Sharti	union node *args, **app;
519121934Sharti	union node **orig_rpp = rpp;
520121934Sharti	union node *n = NULL, *n2;
521121934Sharti	int negate = 0;
522121934Sharti
523121934Sharti	/* If we don't have any redirections already, then we must reset */
524121934Sharti	/* rpp to be the address of the local redir variable.  */
525121934Sharti	if (redir == 0)
526121934Sharti		rpp = &redir;
527121934Sharti
528121934Sharti	args = NULL;
529121934Sharti	app = &args;
530121934Sharti	/*
531121934Sharti	 * We save the incoming value, because we need this for shell
532121934Sharti	 * functions.  There can not be a redirect or an argument between
533121934Sharti	 * the function name and the open parenthesis.
534121934Sharti	 */
535121934Sharti	orig_rpp = rpp;
536121934Sharti
537121934Sharti	while (readtoken() == TNOT) {
538121934Sharti		TRACE(("command: TNOT recognized\n"));
539121934Sharti		negate = !negate;
540121934Sharti	}
541121934Sharti	tokpushback++;
542121934Sharti
543121934Sharti	for (;;) {
544121934Sharti		if (readtoken() == TWORD) {
545121934Sharti			n = (union node *)stalloc(sizeof (struct narg));
546121934Sharti			n->type = NARG;
547121934Sharti			n->narg.text = wordtext;
548121934Sharti			n->narg.backquote = backquotelist;
549121934Sharti			*app = n;
550121934Sharti			app = &n->narg.next;
551121934Sharti		} else if (lasttoken == TREDIR) {
552121934Sharti			*rpp = n = redirnode;
553121934Sharti			rpp = &n->nfile.next;
554121934Sharti			parsefname();	/* read name of redirection file */
555121934Sharti		} else if (lasttoken == TLP && app == &args->narg.next
556121934Sharti					    && rpp == orig_rpp) {
557121934Sharti			/* We have a function */
558121934Sharti			if (readtoken() != TRP)
559121934Sharti				synexpect(TRP);
560121934Sharti#ifdef notdef
561121934Sharti			if (! goodname(n->narg.text))
562121934Sharti				synerror("Bad function name");
563121934Sharti#endif
564121934Sharti			n->type = NDEFUN;
565121934Sharti			n->narg.next = command();
566121934Sharti			goto checkneg;
567121934Sharti		} else {
568121934Sharti			tokpushback++;
569121934Sharti			break;
570121934Sharti		}
571121934Sharti	}
572121934Sharti	*app = NULL;
573121934Sharti	*rpp = NULL;
574121934Sharti	n = (union node *)stalloc(sizeof (struct ncmd));
575121934Sharti	n->type = NCMD;
576121934Sharti	n->ncmd.backgnd = 0;
577121934Sharti	n->ncmd.args = args;
578121934Sharti	n->ncmd.redirect = redir;
579121934Sharti
580121934Sharticheckneg:
581121934Sharti	if (negate) {
582121934Sharti		n2 = (union node *)stalloc(sizeof (struct nnot));
583121934Sharti		n2->type = NNOT;
584121934Sharti		n2->nnot.com = n;
585121934Sharti		return n2;
586121934Sharti	}
587121934Sharti	else
588121934Sharti		return n;
589121934Sharti}
590121934Sharti
591121934ShartiSTATIC union node *
592121934Shartimakename() {
593121934Sharti	union node *n;
594121934Sharti
595121934Sharti	n = (union node *)stalloc(sizeof (struct narg));
596121934Sharti	n->type = NARG;
597121934Sharti	n->narg.next = NULL;
598121934Sharti	n->narg.text = wordtext;
599121934Sharti	n->narg.backquote = backquotelist;
600121934Sharti	return n;
601121934Sharti}
602121934Sharti
603121934Shartivoid fixredir(n, text, err)
604121934Sharti	union node *n;
605121934Sharti	const char *text;
606121934Sharti	int err;
607121934Sharti	{
608121934Sharti	TRACE(("Fix redir %s %d\n", text, err));
609121934Sharti	if (!err)
610121934Sharti		n->ndup.vname = NULL;
611121934Sharti
612121934Sharti	if (is_digit(text[0]) && text[1] == '\0')
613121934Sharti		n->ndup.dupfd = digit_val(text[0]);
614121934Sharti	else if (text[0] == '-' && text[1] == '\0')
615121934Sharti		n->ndup.dupfd = -1;
616121934Sharti	else {
617121934Sharti
618121934Sharti		if (err)
619121934Sharti			synerror("Bad fd number");
620121934Sharti		else
621121934Sharti			n->ndup.vname = makename();
622121934Sharti	}
623121934Sharti}
624121934Sharti
625121934Sharti
626121934ShartiSTATIC void
627121934Shartiparsefname() {
628121934Sharti	union node *n = redirnode;
629121934Sharti
630121934Sharti	if (readtoken() != TWORD)
631121934Sharti		synexpect(-1);
632121934Sharti	if (n->type == NHERE) {
633121934Sharti		struct heredoc *here = heredoc;
634121934Sharti		struct heredoc *p;
635121934Sharti		int i;
636121934Sharti
637121934Sharti		if (quoteflag == 0)
638121934Sharti			n->type = NXHERE;
639121934Sharti		TRACE(("Here document %d\n", n->type));
640121934Sharti		if (here->striptabs) {
641121934Sharti			while (*wordtext == '\t')
642121934Sharti				wordtext++;
643121934Sharti		}
644121934Sharti		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
645121934Sharti			synerror("Illegal eof marker for << redirection");
646121934Sharti		rmescapes(wordtext);
647121934Sharti		here->eofmark = wordtext;
648121934Sharti		here->next = NULL;
649121934Sharti		if (heredoclist == NULL)
650121934Sharti			heredoclist = here;
651121934Sharti		else {
652121934Sharti			for (p = heredoclist ; p->next ; p = p->next);
653121934Sharti			p->next = here;
654121934Sharti		}
655121934Sharti	} else if (n->type == NTOFD || n->type == NFROMFD) {
656121934Sharti		fixredir(n, wordtext, 0);
657121934Sharti	} else {
658121934Sharti		n->nfile.fname = makename();
659121934Sharti	}
660121934Sharti}
661121934Sharti
662121934Sharti
663121934Sharti/*
664121934Sharti * Input any here documents.
665121934Sharti */
666121934Sharti
667121934ShartiSTATIC void
668121934Shartiparseheredoc() {
669121934Sharti	struct heredoc *here;
670121934Sharti	union node *n;
671121934Sharti
672121934Sharti	while (heredoclist) {
673121934Sharti		here = heredoclist;
674121934Sharti		heredoclist = here->next;
675121934Sharti		if (needprompt) {
676121934Sharti			setprompt(2);
677121934Sharti			needprompt = 0;
678121934Sharti		}
679121934Sharti		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
680121934Sharti				here->eofmark, here->striptabs);
681121934Sharti		n = (union node *)stalloc(sizeof (struct narg));
682121934Sharti		n->narg.type = NARG;
683121934Sharti		n->narg.next = NULL;
684121934Sharti		n->narg.text = wordtext;
685121934Sharti		n->narg.backquote = backquotelist;
686121934Sharti		here->here->nhere.doc = n;
687121934Sharti	}
688121934Sharti}
689121934Sharti
690121934ShartiSTATIC int
691121934Shartipeektoken() {
692121934Sharti	int t;
693121934Sharti
694121934Sharti	t = readtoken();
695121934Sharti	tokpushback++;
696121934Sharti	return (t);
697121934Sharti}
698121934Sharti
699121934ShartiSTATIC int xxreadtoken();
700121934Sharti
701121934ShartiSTATIC int
702121934Shartireadtoken() {
703121934Sharti	int t;
704121934Sharti	int savecheckkwd = checkkwd;
705121934Sharti	struct alias *ap;
706121934Sharti#ifdef DEBUG
707121934Sharti	int alreadyseen = tokpushback;
708121934Sharti#endif
709121934Sharti
710121934Sharti	top:
711121934Sharti	t = xxreadtoken();
712121934Sharti
713121934Sharti	if (checkkwd) {
714121934Sharti		/*
715121934Sharti		 * eat newlines
716121934Sharti		 */
717121934Sharti		if (checkkwd == 2) {
718121934Sharti			checkkwd = 0;
719121934Sharti			while (t == TNL) {
720121934Sharti				parseheredoc();
721121934Sharti				t = xxreadtoken();
722121934Sharti			}
723121934Sharti		} else
724121934Sharti			checkkwd = 0;
725121934Sharti		/*
726121934Sharti		 * check for keywords and aliases
727121934Sharti		 */
728121934Sharti		if (t == TWORD && !quoteflag)
729121934Sharti		{
730121934Sharti			register char * const *pp;
731121934Sharti
732121934Sharti			for (pp = (char **)parsekwd; *pp; pp++) {
733121934Sharti				if (**pp == *wordtext && equal(*pp, wordtext))
734121934Sharti				{
735121934Sharti					lasttoken = t = pp - parsekwd + KWDOFFSET;
736121934Sharti					TRACE(("keyword %s recognized\n", tokname[t]));
737121934Sharti					goto out;
738121934Sharti				}
739121934Sharti			}
740121934Sharti			if (noaliases == 0 &&
741121934Sharti			    (ap = lookupalias(wordtext, 1)) != NULL) {
742121934Sharti				pushstring(ap->val, strlen(ap->val), ap);
743121934Sharti				checkkwd = savecheckkwd;
744121934Sharti				goto top;
745121934Sharti			}
746121934Sharti		}
747121934Shartiout:
748121934Sharti		checkkwd = (t == TNOT) ? savecheckkwd : 0;
749121934Sharti	}
750121934Sharti#ifdef DEBUG
751121934Sharti	if (!alreadyseen)
752121934Sharti	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
753121934Sharti	else
754121934Sharti	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
755121934Sharti#endif
756121934Sharti	return (t);
757121934Sharti}
758121934Sharti
759121934Sharti
760121934Sharti/*
761121934Sharti * Read the next input token.
762121934Sharti * If the token is a word, we set backquotelist to the list of cmds in
763121934Sharti *	backquotes.  We set quoteflag to true if any part of the word was
764121934Sharti *	quoted.
765121934Sharti * If the token is TREDIR, then we set redirnode to a structure containing
766121934Sharti *	the redirection.
767121934Sharti * In all cases, the variable startlinno is set to the number of the line
768121934Sharti *	on which the token starts.
769121934Sharti *
770121934Sharti * [Change comment:  here documents and internal procedures]
771121934Sharti * [Readtoken shouldn't have any arguments.  Perhaps we should make the
772121934Sharti *  word parsing code into a separate routine.  In this case, readtoken
773121934Sharti *  doesn't need to have any internal procedures, but parseword does.
774121934Sharti *  We could also make parseoperator in essence the main routine, and
775121934Sharti *  have parseword (readtoken1?) handle both words and redirection.]
776121934Sharti */
777121934Sharti
778121934Sharti#define RETURN(token)	return lasttoken = token
779121934Sharti
780121934ShartiSTATIC int
781121934Shartixxreadtoken() {
782121934Sharti	register c;
783121934Sharti
784121934Sharti	if (tokpushback) {
785121934Sharti		tokpushback = 0;
786121934Sharti		return lasttoken;
787121934Sharti	}
788121934Sharti	if (needprompt) {
789121934Sharti		setprompt(2);
790121934Sharti		needprompt = 0;
791121934Sharti	}
792121934Sharti	startlinno = plinno;
793121934Sharti	for (;;) {	/* until token or start of word found */
794121934Sharti		c = pgetc_macro();
795121934Sharti		if (c == ' ' || c == '\t')
796121934Sharti			continue;		/* quick check for white space first */
797121934Sharti		switch (c) {
798121934Sharti		case ' ': case '\t':
799121934Sharti			continue;
800121934Sharti		case '#':
801121934Sharti			while ((c = pgetc()) != '\n' && c != PEOF);
802121934Sharti			pungetc();
803121934Sharti			continue;
804121934Sharti		case '\\':
805121934Sharti			if (pgetc() == '\n') {
806121934Sharti				startlinno = ++plinno;
807121934Sharti				if (doprompt)
808121934Sharti					setprompt(2);
809121934Sharti				else
810121934Sharti					setprompt(0);
811121934Sharti				continue;
812121934Sharti			}
813121934Sharti			pungetc();
814121934Sharti			goto breakloop;
815121934Sharti		case '\n':
816121934Sharti			plinno++;
817121934Sharti			needprompt = doprompt;
818121934Sharti			RETURN(TNL);
819121934Sharti		case PEOF:
820121934Sharti			RETURN(TEOF);
821121934Sharti		case '&':
822121934Sharti			if (pgetc() == '&')
823121934Sharti				RETURN(TAND);
824121934Sharti			pungetc();
825121934Sharti			RETURN(TBACKGND);
826121934Sharti		case '|':
827121934Sharti			if (pgetc() == '|')
828121934Sharti				RETURN(TOR);
829121934Sharti			pungetc();
830121934Sharti			RETURN(TPIPE);
831121934Sharti		case ';':
832121934Sharti			if (pgetc() == ';')
833121934Sharti				RETURN(TENDCASE);
834121934Sharti			pungetc();
835121934Sharti			RETURN(TSEMI);
836121934Sharti		case '(':
837121934Sharti			RETURN(TLP);
838121934Sharti		case ')':
839121934Sharti			RETURN(TRP);
840121934Sharti		default:
841121934Sharti			goto breakloop;
842121934Sharti		}
843121934Sharti	}
844121934Shartibreakloop:
845121934Sharti	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
846121934Sharti#undef RETURN
847121934Sharti}
848121934Sharti
849121934Sharti
850121934Sharti
851121934Sharti/*
852121934Sharti * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
853121934Sharti * is not NULL, read a here document.  In the latter case, eofmark is the
854121934Sharti * word which marks the end of the document and striptabs is true if
855121934Sharti * leading tabs should be stripped from the document.  The argument firstc
856121934Sharti * is the first character of the input token or document.
857121934Sharti *
858121934Sharti * Because C does not have internal subroutines, I have simulated them
859121934Sharti * using goto's to implement the subroutine linkage.  The following macros
860121934Sharti * will run code that appears at the end of readtoken1.
861121934Sharti */
862121934Sharti
863121934Sharti#define CHECKEND()	{goto checkend; checkend_return:;}
864121934Sharti#define PARSEREDIR()	{goto parseredir; parseredir_return:;}
865121934Sharti#define PARSESUB()	{goto parsesub; parsesub_return:;}
866121934Sharti#define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
867121934Sharti#define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
868121934Sharti#define	PARSEARITH()	{goto parsearith; parsearith_return:;}
869121934Sharti
870121934ShartiSTATIC int
871121934Shartireadtoken1(firstc, syntax, eofmark, striptabs)
872121934Sharti	int firstc;
873121934Sharti	char const *syntax;
874121934Sharti	char *eofmark;
875121934Sharti	int striptabs;
876121934Sharti	{
877121934Sharti	int c = firstc;
878121934Sharti	char *out;
879121934Sharti	int len;
880121934Sharti	char line[EOFMARKLEN + 1];
881121934Sharti	struct nodelist *bqlist;
882121934Sharti	int quotef;
883121934Sharti	int dblquote;
884121934Sharti	int varnest;	/* levels of variables expansion */
885121934Sharti	int arinest;	/* levels of arithmetic expansion */
886121934Sharti	int parenlevel;	/* levels of parens in arithmetic */
887121934Sharti	int oldstyle;
888121934Sharti	char const *prevsyntax;	/* syntax before arithmetic */
889121934Sharti#if __GNUC__
890121934Sharti	/* Avoid longjmp clobbering */
891121934Sharti	(void) &out;
892121934Sharti	(void) &quotef;
893121934Sharti	(void) &dblquote;
894121934Sharti	(void) &varnest;
895121934Sharti	(void) &arinest;
896121934Sharti	(void) &parenlevel;
897121934Sharti	(void) &oldstyle;
898121934Sharti	(void) &prevsyntax;
899121934Sharti	(void) &syntax;
900121934Sharti#endif
901121934Sharti
902121934Sharti	startlinno = plinno;
903121934Sharti	dblquote = 0;
904121934Sharti	if (syntax == DQSYNTAX)
905121934Sharti		dblquote = 1;
906121934Sharti	quotef = 0;
907121934Sharti	bqlist = NULL;
908121934Sharti	varnest = 0;
909121934Sharti	arinest = 0;
910121934Sharti	parenlevel = 0;
911121934Sharti
912121934Sharti	STARTSTACKSTR(out);
913121934Sharti	loop: {	/* for each line, until end of word */
914121934Sharti#if ATTY
915121934Sharti		if (c == '\034' && doprompt
916121934Sharti		 && attyset() && ! equal(termval(), "emacs")) {
917121934Sharti			attyline();
918121934Sharti			if (syntax == BASESYNTAX)
919121934Sharti				return readtoken();
920121934Sharti			c = pgetc();
921121934Sharti			goto loop;
922121934Sharti		}
923121934Sharti#endif
924121934Sharti		CHECKEND();	/* set c to PEOF if at end of here document */
925121934Sharti		for (;;) {	/* until end of line or end of word */
926121934Sharti			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */
927121934Sharti			switch(syntax[c]) {
928121934Sharti			case CNL:	/* '\n' */
929121934Sharti				if (syntax == BASESYNTAX)
930121934Sharti					goto endword;	/* exit outer loop */
931121934Sharti				USTPUTC(c, out);
932121934Sharti				plinno++;
933121934Sharti				if (doprompt)
934121934Sharti					setprompt(2);
935121934Sharti				else
936121934Sharti					setprompt(0);
937121934Sharti				c = pgetc();
938121934Sharti				goto loop;		/* continue outer loop */
939121934Sharti			case CWORD:
940121934Sharti				USTPUTC(c, out);
941121934Sharti				break;
942121934Sharti			case CCTL:
943121934Sharti				if (eofmark == NULL || dblquote)
944121934Sharti					USTPUTC(CTLESC, out);
945121934Sharti				USTPUTC(c, out);
946121934Sharti				break;
947121934Sharti			case CBACK:	/* backslash */
948121934Sharti				c = pgetc();
949121934Sharti				if (c == PEOF) {
950121934Sharti					USTPUTC('\\', out);
951121934Sharti					pungetc();
952121934Sharti				} else if (c == '\n') {
953121934Sharti					if (doprompt)
954121934Sharti						setprompt(2);
955121934Sharti					else
956121934Sharti						setprompt(0);
957121934Sharti				} else {
958121934Sharti					if (dblquote && c != '\\' && c != '`' && c != '$'
959121934Sharti							 && (c != '"' || eofmark != NULL))
960121934Sharti						USTPUTC('\\', out);
961121934Sharti					if (SQSYNTAX[c] == CCTL)
962121934Sharti						USTPUTC(CTLESC, out);
963121934Sharti					USTPUTC(c, out);
964121934Sharti					quotef++;
965121934Sharti				}
966121934Sharti				break;
967121934Sharti			case CSQUOTE:
968121934Sharti				syntax = SQSYNTAX;
969121934Sharti				break;
970121934Sharti			case CDQUOTE:
971121934Sharti				syntax = DQSYNTAX;
972121934Sharti				dblquote = 1;
973121934Sharti				break;
974121934Sharti			case CENDQUOTE:
975121934Sharti				if (eofmark) {
976121934Sharti					USTPUTC(c, out);
977121934Sharti				} else {
978121934Sharti					if (arinest)
979121934Sharti						syntax = ARISYNTAX;
980121934Sharti					else
981121934Sharti						syntax = BASESYNTAX;
982121934Sharti					quotef++;
983121934Sharti					dblquote = 0;
984121934Sharti				}
985121934Sharti				break;
986121934Sharti			case CVAR:	/* '$' */
987121934Sharti				PARSESUB();		/* parse substitution */
988121934Sharti				break;
989121934Sharti			case CENDVAR:	/* '}' */
990121934Sharti				if (varnest > 0) {
991121934Sharti					varnest--;
992121934Sharti					USTPUTC(CTLENDVAR, out);
993121934Sharti				} else {
994121934Sharti					USTPUTC(c, out);
995121934Sharti				}
996121934Sharti				break;
997121934Sharti			case CLP:	/* '(' in arithmetic */
998121934Sharti				parenlevel++;
999121934Sharti				USTPUTC(c, out);
1000121934Sharti				break;
1001121934Sharti			case CRP:	/* ')' in arithmetic */
1002121934Sharti				if (parenlevel > 0) {
1003121934Sharti					USTPUTC(c, out);
1004121934Sharti					--parenlevel;
1005121934Sharti				} else {
1006121934Sharti					if (pgetc() == ')') {
1007121934Sharti						if (--arinest == 0) {
1008121934Sharti							USTPUTC(CTLENDARI, out);
1009121934Sharti							syntax = prevsyntax;
1010121934Sharti						} else
1011121934Sharti							USTPUTC(')', out);
1012121934Sharti					} else {
1013121934Sharti						/*
1014121934Sharti						 * unbalanced parens
1015121934Sharti						 *  (don't 2nd guess - no error)
1016121934Sharti						 */
1017121934Sharti						pungetc();
1018121934Sharti						USTPUTC(')', out);
1019121934Sharti					}
1020121934Sharti				}
1021121934Sharti				break;
1022121934Sharti			case CBQUOTE:	/* '`' */
1023121934Sharti				PARSEBACKQOLD();
1024121934Sharti				break;
1025121934Sharti			case CEOF:
1026121934Sharti				goto endword;		/* exit outer loop */
1027121934Sharti			default:
1028121934Sharti				if (varnest == 0)
1029121934Sharti					goto endword;	/* exit outer loop */
1030121934Sharti				USTPUTC(c, out);
1031121934Sharti			}
1032121934Sharti			c = pgetc_macro();
1033121934Sharti		}
1034121934Sharti	}
1035121934Shartiendword:
1036121934Sharti	if (syntax == ARISYNTAX)
1037121934Sharti		synerror("Missing '))'");
1038121934Sharti	if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
1039121934Sharti		synerror("Unterminated quoted string");
1040121934Sharti	if (varnest != 0) {
1041121934Sharti		startlinno = plinno;
1042121934Sharti		synerror("Missing '}'");
1043121934Sharti	}
1044121934Sharti	USTPUTC('\0', out);
1045121934Sharti	len = out - stackblock();
1046121934Sharti	out = stackblock();
1047121934Sharti	if (eofmark == NULL) {
1048121934Sharti		if ((c == '>' || c == '<')
1049121934Sharti		 && quotef == 0
1050121934Sharti		 && len <= 2
1051121934Sharti		 && (*out == '\0' || is_digit(*out))) {
1052121934Sharti			PARSEREDIR();
1053121934Sharti			return lasttoken = TREDIR;
1054121934Sharti		} else {
1055121934Sharti			pungetc();
1056121934Sharti		}
1057121934Sharti	}
1058121934Sharti	quoteflag = quotef;
1059121934Sharti	backquotelist = bqlist;
1060121934Sharti	grabstackblock(len);
1061121934Sharti	wordtext = out;
1062121934Sharti	return lasttoken = TWORD;
1063121934Sharti/* end of readtoken routine */
1064121934Sharti
1065121934Sharti
1066121934Sharti
1067121934Sharti/*
1068121934Sharti * Check to see whether we are at the end of the here document.  When this
1069121934Sharti * is called, c is set to the first character of the next input line.  If
1070121934Sharti * we are at the end of the here document, this routine sets the c to PEOF.
1071121934Sharti */
1072121934Sharti
1073121934Sharticheckend: {
1074121934Sharti	if (eofmark) {
1075121934Sharti		if (striptabs) {
1076121934Sharti			while (c == '\t')
1077121934Sharti				c = pgetc();
1078121934Sharti		}
1079121934Sharti		if (c == *eofmark) {
1080121934Sharti			if (pfgets(line, sizeof line) != NULL) {
1081121934Sharti				register char *p, *q;
1082121934Sharti
1083121934Sharti				p = line;
1084121934Sharti				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1085121934Sharti				if (*p == '\n' && *q == '\0') {
1086121934Sharti					c = PEOF;
1087121934Sharti					plinno++;
1088121934Sharti					needprompt = doprompt;
1089121934Sharti				} else {
1090121934Sharti					pushstring(line, strlen(line), NULL);
1091121934Sharti				}
1092121934Sharti			}
1093121934Sharti		}
1094121934Sharti	}
1095121934Sharti	goto checkend_return;
1096121934Sharti}
1097121934Sharti
1098121934Sharti
1099121934Sharti/*
1100121934Sharti * Parse a redirection operator.  The variable "out" points to a string
1101121934Sharti * specifying the fd to be redirected.  The variable "c" contains the
1102121934Sharti * first character of the redirection operator.
1103121934Sharti */
1104121934Sharti
1105121934Shartiparseredir: {
1106121934Sharti	char fd = *out;
1107121934Sharti	union node *np;
1108121934Sharti
1109121934Sharti	np = (union node *)stalloc(sizeof (struct nfile));
1110121934Sharti	if (c == '>') {
1111121934Sharti		np->nfile.fd = 1;
1112121934Sharti		c = pgetc();
1113121934Sharti		if (c == '>')
1114121934Sharti			np->type = NAPPEND;
1115121934Sharti		else if (c == '&')
1116121934Sharti			np->type = NTOFD;
1117121934Sharti		else {
1118121934Sharti			np->type = NTO;
1119121934Sharti			pungetc();
1120121934Sharti		}
1121121934Sharti	} else {	/* c == '<' */
1122121934Sharti		np->nfile.fd = 0;
1123121934Sharti		c = pgetc();
1124121934Sharti		if (c == '<') {
1125121934Sharti			if (sizeof (struct nfile) != sizeof (struct nhere)) {
1126121934Sharti				np = (union node *)stalloc(sizeof (struct nhere));
1127121934Sharti				np->nfile.fd = 0;
1128121934Sharti			}
1129121934Sharti			np->type = NHERE;
1130121934Sharti			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1131121934Sharti			heredoc->here = np;
1132121934Sharti			if ((c = pgetc()) == '-') {
1133121934Sharti				heredoc->striptabs = 1;
1134121934Sharti			} else {
1135121934Sharti				heredoc->striptabs = 0;
1136121934Sharti				pungetc();
1137121934Sharti			}
1138121934Sharti		} else if (c == '&')
1139121934Sharti			np->type = NFROMFD;
1140121934Sharti		else {
1141121934Sharti			np->type = NFROM;
1142121934Sharti			pungetc();
1143121934Sharti		}
1144121934Sharti	}
1145121934Sharti	if (fd != '\0')
1146121934Sharti		np->nfile.fd = digit_val(fd);
1147121934Sharti	redirnode = np;
1148121934Sharti	goto parseredir_return;
1149121934Sharti}
1150121934Sharti
1151121934Sharti
1152121934Sharti/*
1153121934Sharti * Parse a substitution.  At this point, we have read the dollar sign
1154121934Sharti * and nothing else.
1155121934Sharti */
1156121934Sharti
1157121934Shartiparsesub: {
1158121934Sharti	int subtype;
1159121934Sharti	int typeloc;
1160121934Sharti	int flags;
1161121934Sharti	char *p;
1162121934Sharti#ifndef GDB_HACK
1163121934Sharti	static const char types[] = "}-+?=";
1164121934Sharti#endif
1165121934Sharti       int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
1166121934Sharti
1167121934Sharti	c = pgetc();
1168121934Sharti	if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
1169121934Sharti		USTPUTC('$', out);
1170121934Sharti		pungetc();
1171121934Sharti	} else if (c == '(') {	/* $(command) or $((arith)) */
1172121934Sharti		if (pgetc() == '(') {
1173121934Sharti			PARSEARITH();
1174121934Sharti		} else {
1175121934Sharti			pungetc();
1176121934Sharti			PARSEBACKQNEW();
1177121934Sharti		}
1178121934Sharti	} else {
1179121934Sharti		USTPUTC(CTLVAR, out);
1180121934Sharti		typeloc = out - stackblock();
1181121934Sharti		USTPUTC(VSNORMAL, out);
1182121934Sharti		subtype = VSNORMAL;
1183121934Sharti		if (c == '{') {
1184121934Sharti			bracketed_name = 1;
1185121934Sharti			c = pgetc();
1186121934Sharti			if (c == '#') {
1187121934Sharti				if ((c = pgetc()) == '}')
1188121934Sharti					c = '#';
1189121934Sharti				else
1190121934Sharti					subtype = VSLENGTH;
1191121934Sharti			}
1192121934Sharti			else
1193121934Sharti				subtype = 0;
1194121934Sharti		}
1195121934Sharti		if (is_name(c)) {
1196121934Sharti			do {
1197121934Sharti				STPUTC(c, out);
1198121934Sharti				c = pgetc();
1199121934Sharti			} while (is_in_name(c));
1200121934Sharti		} else if (is_digit(c)) {
1201121934Sharti			if (bracketed_name) {
1202121934Sharti				do {
1203121934Sharti					STPUTC(c, out);
1204121934Sharti					c = pgetc();
1205121934Sharti				} while (is_digit(c));
1206121934Sharti			} else {
1207121934Sharti				STPUTC(c, out);
1208121934Sharti				c = pgetc();
1209121934Sharti			}
1210121934Sharti		} else {
1211121934Sharti			if (! is_special(c))
1212121934Shartibadsub:				synerror("Bad substitution");
1213121934Sharti			USTPUTC(c, out);
1214121934Sharti			c = pgetc();
1215121934Sharti		}
1216121934Sharti		STPUTC('=', out);
1217121934Sharti		flags = 0;
1218121934Sharti		if (subtype == 0) {
1219121934Sharti			switch (c) {
1220121934Sharti			case ':':
1221121934Sharti				flags = VSNUL;
1222121934Sharti				c = pgetc();
1223121934Sharti				/*FALLTHROUGH*/
1224121934Sharti			default:
1225121934Sharti				p = strchr(types, c);
1226121934Sharti				if (p == NULL)
1227121934Sharti					goto badsub;
1228121934Sharti				subtype = p - types + VSNORMAL;
1229121934Sharti				break;
1230121934Sharti			case '%':
1231121934Sharti			case '#':
1232121934Sharti				{
1233121934Sharti					int cc = c;
1234121934Sharti					subtype = c == '#' ? VSTRIMLEFT :
1235121934Sharti							     VSTRIMRIGHT;
1236121934Sharti					c = pgetc();
1237121934Sharti					if (c == cc)
1238121934Sharti						subtype++;
1239121934Sharti					else
1240121934Sharti						pungetc();
1241121934Sharti					break;
1242121934Sharti				}
1243121934Sharti			}
1244121934Sharti		} else {
1245121934Sharti			pungetc();
1246121934Sharti		}
1247121934Sharti		if (dblquote || arinest)
1248121934Sharti			flags |= VSQUOTE;
1249121934Sharti		*(stackblock() + typeloc) = subtype | flags;
1250121934Sharti		if (subtype != VSNORMAL)
1251121934Sharti			varnest++;
1252121934Sharti	}
1253121934Sharti	goto parsesub_return;
1254121934Sharti}
1255121934Sharti
1256121934Sharti
1257121934Sharti/*
1258121934Sharti * Called to parse command substitutions.  Newstyle is set if the command
1259121934Sharti * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1260121934Sharti * list of commands (passed by reference), and savelen is the number of
1261121934Sharti * characters on the top of the stack which must be preserved.
1262121934Sharti */
1263121934Sharti
1264121934Shartiparsebackq: {
1265121934Sharti	struct nodelist **nlpp;
1266121934Sharti	int savepbq;
1267121934Sharti	union node *n;
1268121934Sharti	char *volatile str;
1269121934Sharti	struct jmploc jmploc;
1270121934Sharti	struct jmploc *volatile savehandler;
1271121934Sharti	int savelen;
1272121934Sharti	int saveprompt;
1273121934Sharti#if __GNUC__
1274121934Sharti	/* Avoid longjmp clobbering */
1275121934Sharti	(void) &saveprompt;
1276121934Sharti#endif
1277121934Sharti
1278121934Sharti	savepbq = parsebackquote;
1279121934Sharti	if (setjmp(jmploc.loc)) {
1280121934Sharti		if (str)
1281121934Sharti			ckfree(str);
1282121934Sharti		parsebackquote = 0;
1283121934Sharti		handler = savehandler;
1284121934Sharti		longjmp(handler->loc, 1);
1285121934Sharti	}
1286121934Sharti	INTOFF;
1287121934Sharti	str = NULL;
1288121934Sharti	savelen = out - stackblock();
1289121934Sharti	if (savelen > 0) {
1290121934Sharti		str = ckmalloc(savelen);
1291121934Sharti		memcpy(str, stackblock(), savelen);
1292121934Sharti	}
1293121934Sharti	savehandler = handler;
1294121934Sharti	handler = &jmploc;
1295121934Sharti	INTON;
1296121934Sharti        if (oldstyle) {
1297121934Sharti                /* We must read until the closing backquote, giving special
1298121934Sharti                   treatment to some slashes, and then push the string and
1299121934Sharti                   reread it as input, interpreting it normally.  */
1300121934Sharti                register char *out;
1301121934Sharti                register c;
1302121934Sharti                int savelen;
1303121934Sharti                char *str;
1304121934Sharti
1305121934Sharti
1306121934Sharti                STARTSTACKSTR(out);
1307121934Sharti		for (;;) {
1308121934Sharti			if (needprompt) {
1309121934Sharti				setprompt(2);
1310121934Sharti				needprompt = 0;
1311121934Sharti			}
1312121934Sharti			switch (c = pgetc()) {
1313121934Sharti			case '`':
1314121934Sharti				goto done;
1315121934Sharti
1316121934Sharti			case '\\':
1317121934Sharti                                if ((c = pgetc()) == '\n') {
1318121934Sharti					plinno++;
1319121934Sharti					if (doprompt)
1320121934Sharti						setprompt(2);
1321121934Sharti					else
1322121934Sharti						setprompt(0);
1323121934Sharti					/*
1324121934Sharti					 * If eating a newline, avoid putting
1325121934Sharti					 * the newline into the new character
1326121934Sharti					 * stream (via the STPUTC after the
1327121934Sharti					 * switch).
1328121934Sharti					 */
1329121934Sharti					continue;
1330121934Sharti				}
1331121934Sharti                                if (c != '\\' && c != '`' && c != '$'
1332121934Sharti                                    && (!dblquote || c != '"'))
1333121934Sharti                                        STPUTC('\\', out);
1334121934Sharti				break;
1335121934Sharti
1336121934Sharti			case '\n':
1337121934Sharti				plinno++;
1338121934Sharti				needprompt = doprompt;
1339121934Sharti				break;
1340121934Sharti
1341121934Sharti			case PEOF:
1342121934Sharti			        startlinno = plinno;
1343121934Sharti				synerror("EOF in backquote substitution");
1344121934Sharti 				break;
1345121934Sharti
1346121934Sharti			default:
1347121934Sharti				break;
1348121934Sharti			}
1349121934Sharti			STPUTC(c, out);
1350121934Sharti                }
1351121934Shartidone:
1352121934Sharti                STPUTC('\0', out);
1353121934Sharti                savelen = out - stackblock();
1354121934Sharti                if (savelen > 0) {
1355121934Sharti                        str = ckmalloc(savelen);
1356121934Sharti                        memcpy(str, stackblock(), savelen);
1357121934Sharti			setinputstring(str, 1);
1358121934Sharti                }
1359121934Sharti        }
1360121934Sharti	nlpp = &bqlist;
1361121934Sharti	while (*nlpp)
1362121934Sharti		nlpp = &(*nlpp)->next;
1363121934Sharti	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1364121934Sharti	(*nlpp)->next = NULL;
1365121934Sharti	parsebackquote = oldstyle;
1366121934Sharti
1367121934Sharti	if (oldstyle) {
1368121934Sharti		saveprompt = doprompt;
1369121934Sharti		doprompt = 0;
1370121934Sharti	}
1371121934Sharti
1372	n = list(0);
1373
1374	if (oldstyle)
1375		doprompt = saveprompt;
1376	else {
1377		if (readtoken() != TRP)
1378			synexpect(TRP);
1379	}
1380
1381	(*nlpp)->n = n;
1382        if (oldstyle) {
1383		/*
1384		 * Start reading from old file again, ignoring any pushed back
1385		 * tokens left from the backquote parsing
1386		 */
1387                popfile();
1388		tokpushback = 0;
1389	}
1390	while (stackblocksize() <= savelen)
1391		growstackblock();
1392	STARTSTACKSTR(out);
1393	if (str) {
1394		memcpy(out, str, savelen);
1395		STADJUST(savelen, out);
1396		INTOFF;
1397		ckfree(str);
1398		str = NULL;
1399		INTON;
1400	}
1401	parsebackquote = savepbq;
1402	handler = savehandler;
1403	if (arinest || dblquote)
1404		USTPUTC(CTLBACKQ | CTLQUOTE, out);
1405	else
1406		USTPUTC(CTLBACKQ, out);
1407	if (oldstyle)
1408		goto parsebackq_oldreturn;
1409	else
1410		goto parsebackq_newreturn;
1411}
1412
1413/*
1414 * Parse an arithmetic expansion (indicate start of one and set state)
1415 */
1416parsearith: {
1417
1418	if (++arinest == 1) {
1419		prevsyntax = syntax;
1420		syntax = ARISYNTAX;
1421		USTPUTC(CTLARI, out);
1422	} else {
1423		/*
1424		 * we collapse embedded arithmetic expansion to
1425		 * parenthesis, which should be equivalent
1426		 */
1427		USTPUTC('(', out);
1428	}
1429	goto parsearith_return;
1430}
1431
1432} /* end of readtoken */
1433
1434
1435
1436#ifdef mkinit
1437RESET {
1438	tokpushback = 0;
1439	checkkwd = 0;
1440}
1441#endif
1442
1443/*
1444 * Returns true if the text contains nothing to expand (no dollar signs
1445 * or backquotes).
1446 */
1447
1448STATIC int
1449noexpand(text)
1450	char *text;
1451	{
1452	register char *p;
1453	register char c;
1454
1455	p = text;
1456	while ((c = *p++) != '\0') {
1457		if (c == CTLESC)
1458			p++;
1459		else if (BASESYNTAX[c] == CCTL)
1460			return 0;
1461	}
1462	return 1;
1463}
1464
1465
1466/*
1467 * Return true if the argument is a legal variable name (a letter or
1468 * underscore followed by zero or more letters, underscores, and digits).
1469 */
1470
1471int
1472goodname(name)
1473	char *name;
1474	{
1475	register char *p;
1476
1477	p = name;
1478	if (! is_name(*p))
1479		return 0;
1480	while (*++p) {
1481		if (! is_in_name(*p))
1482			return 0;
1483	}
1484	return 1;
1485}
1486
1487
1488/*
1489 * Called when an unexpected token is read during the parse.  The argument
1490 * is the token that is expected, or -1 if more than one type of token can
1491 * occur at this point.
1492 */
1493
1494STATIC void
1495synexpect(token)
1496	int token;
1497{
1498	char msg[64];
1499
1500	if (token >= 0) {
1501		fmtstr(msg, 64, "%s unexpected (expecting %s)",
1502			tokname[lasttoken], tokname[token]);
1503	} else {
1504		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1505	}
1506	synerror(msg);
1507}
1508
1509
1510STATIC void
1511synerror(msg)
1512	char *msg;
1513	{
1514	if (commandname)
1515		outfmt(&errout, "%s: %d: ", commandname, startlinno);
1516	outfmt(&errout, "Syntax error: %s\n", msg);
1517	error((char *)NULL);
1518}
1519
1520STATIC void
1521setprompt(which)
1522	int which;
1523	{
1524	whichprompt = which;
1525
1526#ifndef NO_HISTORY
1527	if (!el)
1528#endif
1529		out2str(getprompt(NULL));
1530}
1531
1532/*
1533 * called by editline -- any expansions to the prompt
1534 *    should be added here.
1535 */
1536char *
1537getprompt(unused)
1538	void *unused;
1539	{
1540	switch (whichprompt) {
1541	case 0:
1542		return "";
1543	case 1:
1544		return ps1val();
1545	case 2:
1546		return ps2val();
1547	default:
1548		return "<internal prompt error>";
1549	}
1550}
1551