xref: /freebsd/bin/sh/parser.c (revision 4f30f2993f73eb3ec18ed10985aec984d9e7cdc5)
14b88c807SRodney W. Grimes /*-
24b88c807SRodney W. Grimes  * Copyright (c) 1991, 1993
34b88c807SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
44b88c807SRodney W. Grimes  *
54b88c807SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
64b88c807SRodney W. Grimes  * Kenneth Almquist.
74b88c807SRodney W. Grimes  *
84b88c807SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
94b88c807SRodney W. Grimes  * modification, are permitted provided that the following conditions
104b88c807SRodney W. Grimes  * are met:
114b88c807SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
124b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
134b88c807SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
144b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
154b88c807SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
164b88c807SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
174b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
184b88c807SRodney W. Grimes  *    without specific prior written permission.
194b88c807SRodney W. Grimes  *
204b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
214b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
244b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304b88c807SRodney W. Grimes  * SUCH DAMAGE.
314b88c807SRodney W. Grimes  */
324b88c807SRodney W. Grimes 
334b88c807SRodney W. Grimes #ifndef lint
343d7b5b93SPhilippe Charnier #if 0
353d7b5b93SPhilippe Charnier static char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
363d7b5b93SPhilippe Charnier #endif
374b88c807SRodney W. Grimes #endif /* not lint */
382749b141SDavid E. O'Brien #include <sys/cdefs.h>
392749b141SDavid E. O'Brien __FBSDID("$FreeBSD$");
404b88c807SRodney W. Grimes 
41aa9caaf6SPeter Wemm #include <stdlib.h>
42955e9f68SStefan Farfeleder #include <unistd.h>
43aa9caaf6SPeter Wemm 
444b88c807SRodney W. Grimes #include "shell.h"
454b88c807SRodney W. Grimes #include "parser.h"
464b88c807SRodney W. Grimes #include "nodes.h"
474b88c807SRodney W. Grimes #include "expand.h"	/* defines rmescapes() */
484b88c807SRodney W. Grimes #include "syntax.h"
494b88c807SRodney W. Grimes #include "options.h"
504b88c807SRodney W. Grimes #include "input.h"
514b88c807SRodney W. Grimes #include "output.h"
524b88c807SRodney W. Grimes #include "var.h"
534b88c807SRodney W. Grimes #include "error.h"
544b88c807SRodney W. Grimes #include "memalloc.h"
554b88c807SRodney W. Grimes #include "mystring.h"
564b88c807SRodney W. Grimes #include "alias.h"
57aa9caaf6SPeter Wemm #include "show.h"
58f01e3d0cSMartin Cracauer #include "eval.h"
59aa9caaf6SPeter Wemm #ifndef NO_HISTORY
604b88c807SRodney W. Grimes #include "myhistedit.h"
61aa9caaf6SPeter Wemm #endif
624b88c807SRodney W. Grimes 
634b88c807SRodney W. Grimes /*
644b88c807SRodney W. Grimes  * Shell command parser.
654b88c807SRodney W. Grimes  */
664b88c807SRodney W. Grimes 
674b88c807SRodney W. Grimes #define	EOFMARKLEN	79
68f0c73601SDavid E. O'Brien #define	PROMPTLEN	128
694b88c807SRodney W. Grimes 
704b88c807SRodney W. Grimes /* values returned by readtoken */
71aa9caaf6SPeter Wemm #include "token.h"
724b88c807SRodney W. Grimes 
734b88c807SRodney W. Grimes 
744b88c807SRodney W. Grimes 
754b88c807SRodney W. Grimes struct heredoc {
764b88c807SRodney W. Grimes 	struct heredoc *next;	/* next here document in list */
774b88c807SRodney W. Grimes 	union node *here;		/* redirection node */
784b88c807SRodney W. Grimes 	char *eofmark;		/* string indicating end of input */
794b88c807SRodney W. Grimes 	int striptabs;		/* if set, strip leading tabs */
804b88c807SRodney W. Grimes };
814b88c807SRodney W. Grimes 
824b88c807SRodney W. Grimes 
834b88c807SRodney W. Grimes 
842ba1b30bSDiomidis Spinellis STATIC struct heredoc *heredoclist;	/* list of here documents to read */
852ba1b30bSDiomidis Spinellis STATIC int parsebackquote;	/* nonzero if we are inside backquotes */
862ba1b30bSDiomidis Spinellis STATIC int doprompt;		/* if set, prompt the user */
872ba1b30bSDiomidis Spinellis STATIC int needprompt;		/* true if interactive and at start of line */
882ba1b30bSDiomidis Spinellis STATIC int lasttoken;		/* last token read */
894b88c807SRodney W. Grimes MKINIT int tokpushback;		/* last token pushed back */
902ba1b30bSDiomidis Spinellis STATIC char *wordtext;		/* text of last word returned by readtoken */
914b88c807SRodney W. Grimes MKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
922ba1b30bSDiomidis Spinellis STATIC struct nodelist *backquotelist;
932ba1b30bSDiomidis Spinellis STATIC union node *redirnode;
942ba1b30bSDiomidis Spinellis STATIC struct heredoc *heredoc;
952ba1b30bSDiomidis Spinellis STATIC int quoteflag;		/* set if (part of) last token was quoted */
962ba1b30bSDiomidis Spinellis STATIC int startlinno;		/* line # where last token started */
97b71085aaSStefan Farfeleder STATIC int funclinno;		/* line # where the current function started */
984b88c807SRodney W. Grimes 
994417f629SPeter Wemm /* XXX When 'noaliases' is set to one, no alias expansion takes place. */
1004417f629SPeter Wemm static int noaliases = 0;
1014b88c807SRodney W. Grimes 
1024b88c807SRodney W. Grimes 
1035134c3f7SWarner Losh STATIC union node *list(int);
1045134c3f7SWarner Losh STATIC union node *andor(void);
1055134c3f7SWarner Losh STATIC union node *pipeline(void);
1065134c3f7SWarner Losh STATIC union node *command(void);
1075134c3f7SWarner Losh STATIC union node *simplecmd(union node **, union node *);
1085134c3f7SWarner Losh STATIC union node *makename(void);
1095134c3f7SWarner Losh STATIC void parsefname(void);
1105134c3f7SWarner Losh STATIC void parseheredoc(void);
1115134c3f7SWarner Losh STATIC int peektoken(void);
1125134c3f7SWarner Losh STATIC int readtoken(void);
1135134c3f7SWarner Losh STATIC int xxreadtoken(void);
1145134c3f7SWarner Losh STATIC int readtoken1(int, char const *, char *, int);
1155134c3f7SWarner Losh STATIC int noexpand(char *);
1165134c3f7SWarner Losh STATIC void synexpect(int);
1175134c3f7SWarner Losh STATIC void synerror(char *);
1185134c3f7SWarner Losh STATIC void setprompt(int);
1194b88c807SRodney W. Grimes 
120aa9caaf6SPeter Wemm 
1214b88c807SRodney W. Grimes /*
1224b88c807SRodney W. Grimes  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
1234b88c807SRodney W. Grimes  * valid parse tree indicating a blank line.)
1244b88c807SRodney W. Grimes  */
1254b88c807SRodney W. Grimes 
1264b88c807SRodney W. Grimes union node *
1275134c3f7SWarner Losh parsecmd(int interact)
128aa9caaf6SPeter Wemm {
1294b88c807SRodney W. Grimes 	int t;
1304b88c807SRodney W. Grimes 
13198e05fd3SMartin Cracauer 	tokpushback = 0;
1324b88c807SRodney W. Grimes 	doprompt = interact;
1334b88c807SRodney W. Grimes 	if (doprompt)
1344b88c807SRodney W. Grimes 		setprompt(1);
1354b88c807SRodney W. Grimes 	else
1364b88c807SRodney W. Grimes 		setprompt(0);
1374b88c807SRodney W. Grimes 	needprompt = 0;
1384b88c807SRodney W. Grimes 	t = readtoken();
1394b88c807SRodney W. Grimes 	if (t == TEOF)
1404b88c807SRodney W. Grimes 		return NEOF;
1414b88c807SRodney W. Grimes 	if (t == TNL)
1424b88c807SRodney W. Grimes 		return NULL;
1434b88c807SRodney W. Grimes 	tokpushback++;
1444b88c807SRodney W. Grimes 	return list(1);
1454b88c807SRodney W. Grimes }
1464b88c807SRodney W. Grimes 
1474b88c807SRodney W. Grimes 
1484b88c807SRodney W. Grimes STATIC union node *
1495134c3f7SWarner Losh list(int nlflag)
150aa9caaf6SPeter Wemm {
1514b88c807SRodney W. Grimes 	union node *n1, *n2, *n3;
152aa9caaf6SPeter Wemm 	int tok;
1534b88c807SRodney W. Grimes 
1544b88c807SRodney W. Grimes 	checkkwd = 2;
1554b88c807SRodney W. Grimes 	if (nlflag == 0 && tokendlist[peektoken()])
1564b88c807SRodney W. Grimes 		return NULL;
157aa9caaf6SPeter Wemm 	n1 = NULL;
1584b88c807SRodney W. Grimes 	for (;;) {
1594b88c807SRodney W. Grimes 		n2 = andor();
160aa9caaf6SPeter Wemm 		tok = readtoken();
161aa9caaf6SPeter Wemm 		if (tok == TBACKGND) {
162aa9caaf6SPeter Wemm 			if (n2->type == NCMD || n2->type == NPIPE) {
163aa9caaf6SPeter Wemm 				n2->ncmd.backgnd = 1;
164aa9caaf6SPeter Wemm 			} else if (n2->type == NREDIR) {
165aa9caaf6SPeter Wemm 				n2->type = NBACKGND;
166aa9caaf6SPeter Wemm 			} else {
167aa9caaf6SPeter Wemm 				n3 = (union node *)stalloc(sizeof (struct nredir));
168aa9caaf6SPeter Wemm 				n3->type = NBACKGND;
169aa9caaf6SPeter Wemm 				n3->nredir.n = n2;
170aa9caaf6SPeter Wemm 				n3->nredir.redirect = NULL;
171aa9caaf6SPeter Wemm 				n2 = n3;
172aa9caaf6SPeter Wemm 			}
173aa9caaf6SPeter Wemm 		}
174aa9caaf6SPeter Wemm 		if (n1 == NULL) {
175aa9caaf6SPeter Wemm 			n1 = n2;
176aa9caaf6SPeter Wemm 		}
177aa9caaf6SPeter Wemm 		else {
1784b88c807SRodney W. Grimes 			n3 = (union node *)stalloc(sizeof (struct nbinary));
1794b88c807SRodney W. Grimes 			n3->type = NSEMI;
1804b88c807SRodney W. Grimes 			n3->nbinary.ch1 = n1;
1814b88c807SRodney W. Grimes 			n3->nbinary.ch2 = n2;
1824b88c807SRodney W. Grimes 			n1 = n3;
183aa9caaf6SPeter Wemm 		}
184aa9caaf6SPeter Wemm 		switch (tok) {
185aa9caaf6SPeter Wemm 		case TBACKGND:
186aa9caaf6SPeter Wemm 		case TSEMI:
187aa9caaf6SPeter Wemm 			tok = readtoken();
1880d9f1a69SPhilippe Charnier 			/* FALLTHROUGH */
189aa9caaf6SPeter Wemm 		case TNL:
190aa9caaf6SPeter Wemm 			if (tok == TNL) {
191aa9caaf6SPeter Wemm 				parseheredoc();
192aa9caaf6SPeter Wemm 				if (nlflag)
193aa9caaf6SPeter Wemm 					return n1;
194aa9caaf6SPeter Wemm 			} else {
195aa9caaf6SPeter Wemm 				tokpushback++;
196aa9caaf6SPeter Wemm 			}
197aa9caaf6SPeter Wemm 			checkkwd = 2;
198aa9caaf6SPeter Wemm 			if (tokendlist[peektoken()])
199aa9caaf6SPeter Wemm 				return n1;
2004b88c807SRodney W. Grimes 			break;
2014b88c807SRodney W. Grimes 		case TEOF:
2024b88c807SRodney W. Grimes 			if (heredoclist)
2034b88c807SRodney W. Grimes 				parseheredoc();
2044b88c807SRodney W. Grimes 			else
2054b88c807SRodney W. Grimes 				pungetc();		/* push back EOF on input */
2064b88c807SRodney W. Grimes 			return n1;
2074b88c807SRodney W. Grimes 		default:
2084b88c807SRodney W. Grimes 			if (nlflag)
2094b88c807SRodney W. Grimes 				synexpect(-1);
2104b88c807SRodney W. Grimes 			tokpushback++;
2114b88c807SRodney W. Grimes 			return n1;
2124b88c807SRodney W. Grimes 		}
2134b88c807SRodney W. Grimes 	}
2144b88c807SRodney W. Grimes }
2154b88c807SRodney W. Grimes 
2164b88c807SRodney W. Grimes 
2174b88c807SRodney W. Grimes 
2184b88c807SRodney W. Grimes STATIC union node *
2195134c3f7SWarner Losh andor(void)
2205134c3f7SWarner Losh {
2214b88c807SRodney W. Grimes 	union node *n1, *n2, *n3;
2224b88c807SRodney W. Grimes 	int t;
2234b88c807SRodney W. Grimes 
2244b88c807SRodney W. Grimes 	n1 = pipeline();
2254b88c807SRodney W. Grimes 	for (;;) {
2264b88c807SRodney W. Grimes 		if ((t = readtoken()) == TAND) {
2274b88c807SRodney W. Grimes 			t = NAND;
2284b88c807SRodney W. Grimes 		} else if (t == TOR) {
2294b88c807SRodney W. Grimes 			t = NOR;
2304b88c807SRodney W. Grimes 		} else {
2314b88c807SRodney W. Grimes 			tokpushback++;
2324b88c807SRodney W. Grimes 			return n1;
2334b88c807SRodney W. Grimes 		}
2344b88c807SRodney W. Grimes 		n2 = pipeline();
2354b88c807SRodney W. Grimes 		n3 = (union node *)stalloc(sizeof (struct nbinary));
2364b88c807SRodney W. Grimes 		n3->type = t;
2374b88c807SRodney W. Grimes 		n3->nbinary.ch1 = n1;
2384b88c807SRodney W. Grimes 		n3->nbinary.ch2 = n2;
2394b88c807SRodney W. Grimes 		n1 = n3;
2404b88c807SRodney W. Grimes 	}
2414b88c807SRodney W. Grimes }
2424b88c807SRodney W. Grimes 
2434b88c807SRodney W. Grimes 
2444b88c807SRodney W. Grimes 
2454b88c807SRodney W. Grimes STATIC union node *
2465134c3f7SWarner Losh pipeline(void)
2475134c3f7SWarner Losh {
248b785bd7dSBrian Somers 	union node *n1, *n2, *pipenode;
2494b88c807SRodney W. Grimes 	struct nodelist *lp, *prev;
250b785bd7dSBrian Somers 	int negate;
2514b88c807SRodney W. Grimes 
252b785bd7dSBrian Somers 	negate = 0;
2534b88c807SRodney W. Grimes 	TRACE(("pipeline: entered\n"));
254b785bd7dSBrian Somers 	while (readtoken() == TNOT)
255b785bd7dSBrian Somers 		negate = !negate;
256b785bd7dSBrian Somers 	tokpushback++;
2574b88c807SRodney W. Grimes 	n1 = command();
2584b88c807SRodney W. Grimes 	if (readtoken() == TPIPE) {
2594b88c807SRodney W. Grimes 		pipenode = (union node *)stalloc(sizeof (struct npipe));
2604b88c807SRodney W. Grimes 		pipenode->type = NPIPE;
2614b88c807SRodney W. Grimes 		pipenode->npipe.backgnd = 0;
2624b88c807SRodney W. Grimes 		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
2634b88c807SRodney W. Grimes 		pipenode->npipe.cmdlist = lp;
2644b88c807SRodney W. Grimes 		lp->n = n1;
2654b88c807SRodney W. Grimes 		do {
2664b88c807SRodney W. Grimes 			prev = lp;
2674b88c807SRodney W. Grimes 			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
2684b88c807SRodney W. Grimes 			lp->n = command();
2694b88c807SRodney W. Grimes 			prev->next = lp;
2704b88c807SRodney W. Grimes 		} while (readtoken() == TPIPE);
2714b88c807SRodney W. Grimes 		lp->next = NULL;
2724b88c807SRodney W. Grimes 		n1 = pipenode;
2734b88c807SRodney W. Grimes 	}
2744b88c807SRodney W. Grimes 	tokpushback++;
275b785bd7dSBrian Somers 	if (negate) {
276b785bd7dSBrian Somers 		n2 = (union node *)stalloc(sizeof (struct nnot));
277b785bd7dSBrian Somers 		n2->type = NNOT;
278b785bd7dSBrian Somers 		n2->nnot.com = n1;
279b785bd7dSBrian Somers 		return n2;
280b785bd7dSBrian Somers 	} else
2814b88c807SRodney W. Grimes 		return n1;
2824b88c807SRodney W. Grimes }
2834b88c807SRodney W. Grimes 
2844b88c807SRodney W. Grimes 
2854b88c807SRodney W. Grimes 
2864b88c807SRodney W. Grimes STATIC union node *
2875134c3f7SWarner Losh command(void)
2885134c3f7SWarner Losh {
2894b88c807SRodney W. Grimes 	union node *n1, *n2;
2904b88c807SRodney W. Grimes 	union node *ap, **app;
2914b88c807SRodney W. Grimes 	union node *cp, **cpp;
2924b88c807SRodney W. Grimes 	union node *redir, **rpp;
2936c0bde79SBrian Somers 	int t, negate = 0;
2944b88c807SRodney W. Grimes 
2954b88c807SRodney W. Grimes 	checkkwd = 2;
296aa9caaf6SPeter Wemm 	redir = NULL;
297aa9caaf6SPeter Wemm 	n1 = NULL;
2984b88c807SRodney W. Grimes 	rpp = &redir;
299ab0a2172SSteve Price 
3004b88c807SRodney W. Grimes 	/* Check for redirection which may precede command */
3014b88c807SRodney W. Grimes 	while (readtoken() == TREDIR) {
3024b88c807SRodney W. Grimes 		*rpp = n2 = redirnode;
3034b88c807SRodney W. Grimes 		rpp = &n2->nfile.next;
3044b88c807SRodney W. Grimes 		parsefname();
3054b88c807SRodney W. Grimes 	}
3064b88c807SRodney W. Grimes 	tokpushback++;
3074b88c807SRodney W. Grimes 
3086c0bde79SBrian Somers 	while (readtoken() == TNOT) {
3096c0bde79SBrian Somers 		TRACE(("command: TNOT recognized\n"));
3106c0bde79SBrian Somers 		negate = !negate;
3116c0bde79SBrian Somers 	}
3126c0bde79SBrian Somers 	tokpushback++;
3136c0bde79SBrian Somers 
3144b88c807SRodney W. Grimes 	switch (readtoken()) {
3154b88c807SRodney W. Grimes 	case TIF:
3164b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nif));
3174b88c807SRodney W. Grimes 		n1->type = NIF;
318427748f7STim J. Robbins 		if ((n1->nif.test = list(0)) == NULL)
319427748f7STim J. Robbins 			synexpect(-1);
3204b88c807SRodney W. Grimes 		if (readtoken() != TTHEN)
3214b88c807SRodney W. Grimes 			synexpect(TTHEN);
3224b88c807SRodney W. Grimes 		n1->nif.ifpart = list(0);
3234b88c807SRodney W. Grimes 		n2 = n1;
3244b88c807SRodney W. Grimes 		while (readtoken() == TELIF) {
3254b88c807SRodney W. Grimes 			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
3264b88c807SRodney W. Grimes 			n2 = n2->nif.elsepart;
3274b88c807SRodney W. Grimes 			n2->type = NIF;
328427748f7STim J. Robbins 			if ((n2->nif.test = list(0)) == NULL)
329427748f7STim J. Robbins 				synexpect(-1);
3304b88c807SRodney W. Grimes 			if (readtoken() != TTHEN)
3314b88c807SRodney W. Grimes 				synexpect(TTHEN);
3324b88c807SRodney W. Grimes 			n2->nif.ifpart = list(0);
3334b88c807SRodney W. Grimes 		}
3344b88c807SRodney W. Grimes 		if (lasttoken == TELSE)
3354b88c807SRodney W. Grimes 			n2->nif.elsepart = list(0);
3364b88c807SRodney W. Grimes 		else {
3374b88c807SRodney W. Grimes 			n2->nif.elsepart = NULL;
3384b88c807SRodney W. Grimes 			tokpushback++;
3394b88c807SRodney W. Grimes 		}
3404b88c807SRodney W. Grimes 		if (readtoken() != TFI)
3414b88c807SRodney W. Grimes 			synexpect(TFI);
3424b88c807SRodney W. Grimes 		checkkwd = 1;
3434b88c807SRodney W. Grimes 		break;
3444b88c807SRodney W. Grimes 	case TWHILE:
3454b88c807SRodney W. Grimes 	case TUNTIL: {
3464b88c807SRodney W. Grimes 		int got;
3474b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nbinary));
3484b88c807SRodney W. Grimes 		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
349427748f7STim J. Robbins 		if ((n1->nbinary.ch1 = list(0)) == NULL)
350427748f7STim J. Robbins 			synexpect(-1);
3514b88c807SRodney W. Grimes 		if ((got=readtoken()) != TDO) {
3524b88c807SRodney W. Grimes TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
3534b88c807SRodney W. Grimes 			synexpect(TDO);
3544b88c807SRodney W. Grimes 		}
3554b88c807SRodney W. Grimes 		n1->nbinary.ch2 = list(0);
3564b88c807SRodney W. Grimes 		if (readtoken() != TDONE)
3574b88c807SRodney W. Grimes 			synexpect(TDONE);
3584b88c807SRodney W. Grimes 		checkkwd = 1;
3594b88c807SRodney W. Grimes 		break;
3604b88c807SRodney W. Grimes 	}
3614b88c807SRodney W. Grimes 	case TFOR:
3624b88c807SRodney W. Grimes 		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
3634b88c807SRodney W. Grimes 			synerror("Bad for loop variable");
3644b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nfor));
3654b88c807SRodney W. Grimes 		n1->type = NFOR;
3664b88c807SRodney W. Grimes 		n1->nfor.var = wordtext;
3674b88c807SRodney W. Grimes 		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
3684b88c807SRodney W. Grimes 			app = &ap;
3694b88c807SRodney W. Grimes 			while (readtoken() == TWORD) {
3704b88c807SRodney W. Grimes 				n2 = (union node *)stalloc(sizeof (struct narg));
3714b88c807SRodney W. Grimes 				n2->type = NARG;
3724b88c807SRodney W. Grimes 				n2->narg.text = wordtext;
3734b88c807SRodney W. Grimes 				n2->narg.backquote = backquotelist;
3744b88c807SRodney W. Grimes 				*app = n2;
3754b88c807SRodney W. Grimes 				app = &n2->narg.next;
3764b88c807SRodney W. Grimes 			}
3774b88c807SRodney W. Grimes 			*app = NULL;
3784b88c807SRodney W. Grimes 			n1->nfor.args = ap;
3794b88c807SRodney W. Grimes 			if (lasttoken != TNL && lasttoken != TSEMI)
3804b88c807SRodney W. Grimes 				synexpect(-1);
3814b88c807SRodney W. Grimes 		} else {
382811beb4bSStefan Farfeleder 			static char argvars[5] = {
383811beb4bSStefan Farfeleder 				CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
384811beb4bSStefan Farfeleder 			};
3854b88c807SRodney W. Grimes 			n2 = (union node *)stalloc(sizeof (struct narg));
3864b88c807SRodney W. Grimes 			n2->type = NARG;
387811beb4bSStefan Farfeleder 			n2->narg.text = argvars;
3884b88c807SRodney W. Grimes 			n2->narg.backquote = NULL;
3894b88c807SRodney W. Grimes 			n2->narg.next = NULL;
3904b88c807SRodney W. Grimes 			n1->nfor.args = n2;
3914b88c807SRodney W. Grimes 			/*
3924b88c807SRodney W. Grimes 			 * Newline or semicolon here is optional (but note
3934b88c807SRodney W. Grimes 			 * that the original Bourne shell only allowed NL).
3944b88c807SRodney W. Grimes 			 */
3954b88c807SRodney W. Grimes 			if (lasttoken != TNL && lasttoken != TSEMI)
3964b88c807SRodney W. Grimes 				tokpushback++;
3974b88c807SRodney W. Grimes 		}
3984b88c807SRodney W. Grimes 		checkkwd = 2;
3994b88c807SRodney W. Grimes 		if ((t = readtoken()) == TDO)
4004b88c807SRodney W. Grimes 			t = TDONE;
4014b88c807SRodney W. Grimes 		else if (t == TBEGIN)
4024b88c807SRodney W. Grimes 			t = TEND;
4034b88c807SRodney W. Grimes 		else
4044b88c807SRodney W. Grimes 			synexpect(-1);
4054b88c807SRodney W. Grimes 		n1->nfor.body = list(0);
4064b88c807SRodney W. Grimes 		if (readtoken() != t)
4074b88c807SRodney W. Grimes 			synexpect(t);
4084b88c807SRodney W. Grimes 		checkkwd = 1;
4094b88c807SRodney W. Grimes 		break;
4104b88c807SRodney W. Grimes 	case TCASE:
4114b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct ncase));
4124b88c807SRodney W. Grimes 		n1->type = NCASE;
4134b88c807SRodney W. Grimes 		if (readtoken() != TWORD)
4144b88c807SRodney W. Grimes 			synexpect(TWORD);
4154b88c807SRodney W. Grimes 		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
4164b88c807SRodney W. Grimes 		n2->type = NARG;
4174b88c807SRodney W. Grimes 		n2->narg.text = wordtext;
4184b88c807SRodney W. Grimes 		n2->narg.backquote = backquotelist;
4194b88c807SRodney W. Grimes 		n2->narg.next = NULL;
4204b88c807SRodney W. Grimes 		while (readtoken() == TNL);
4214b88c807SRodney W. Grimes 		if (lasttoken != TWORD || ! equal(wordtext, "in"))
4224b88c807SRodney W. Grimes 			synerror("expecting \"in\"");
4234b88c807SRodney W. Grimes 		cpp = &n1->ncase.cases;
4244417f629SPeter Wemm 		noaliases = 1;	/* turn off alias expansion */
425650488feSSean Eric Fagan 		checkkwd = 2, readtoken();
426e00e16adSTim J. Robbins 		while (lasttoken != TESAC) {
4274b88c807SRodney W. Grimes 			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
4284b88c807SRodney W. Grimes 			cp->type = NCLIST;
4294b88c807SRodney W. Grimes 			app = &cp->nclist.pattern;
430f7a9b7feSTim J. Robbins 			if (lasttoken == TLP)
431f7a9b7feSTim J. Robbins 				readtoken();
4324b88c807SRodney W. Grimes 			for (;;) {
4334b88c807SRodney W. Grimes 				*app = ap = (union node *)stalloc(sizeof (struct narg));
4344b88c807SRodney W. Grimes 				ap->type = NARG;
4354b88c807SRodney W. Grimes 				ap->narg.text = wordtext;
4364b88c807SRodney W. Grimes 				ap->narg.backquote = backquotelist;
437650488feSSean Eric Fagan 				if (checkkwd = 2, readtoken() != TPIPE)
4384b88c807SRodney W. Grimes 					break;
4394b88c807SRodney W. Grimes 				app = &ap->narg.next;
440650488feSSean Eric Fagan 				readtoken();
4414b88c807SRodney W. Grimes 			}
4424b88c807SRodney W. Grimes 			ap->narg.next = NULL;
4434b88c807SRodney W. Grimes 			if (lasttoken != TRP)
4444417f629SPeter Wemm 				noaliases = 0, synexpect(TRP);
4454b88c807SRodney W. Grimes 			cp->nclist.body = list(0);
446650488feSSean Eric Fagan 
447650488feSSean Eric Fagan 			checkkwd = 2;
448650488feSSean Eric Fagan 			if ((t = readtoken()) != TESAC) {
449650488feSSean Eric Fagan 				if (t != TENDCASE)
4504417f629SPeter Wemm 					noaliases = 0, synexpect(TENDCASE);
451650488feSSean Eric Fagan 				else
452650488feSSean Eric Fagan 					checkkwd = 2, readtoken();
4534b88c807SRodney W. Grimes 			}
454650488feSSean Eric Fagan 			cpp = &cp->nclist.next;
455e00e16adSTim J. Robbins 		}
4564417f629SPeter Wemm 		noaliases = 0;	/* reset alias expansion */
4574b88c807SRodney W. Grimes 		*cpp = NULL;
4584b88c807SRodney W. Grimes 		checkkwd = 1;
4594b88c807SRodney W. Grimes 		break;
4604b88c807SRodney W. Grimes 	case TLP:
4614b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nredir));
4624b88c807SRodney W. Grimes 		n1->type = NSUBSHELL;
4634b88c807SRodney W. Grimes 		n1->nredir.n = list(0);
4644b88c807SRodney W. Grimes 		n1->nredir.redirect = NULL;
4654b88c807SRodney W. Grimes 		if (readtoken() != TRP)
4664b88c807SRodney W. Grimes 			synexpect(TRP);
4674b88c807SRodney W. Grimes 		checkkwd = 1;
4684b88c807SRodney W. Grimes 		break;
4694b88c807SRodney W. Grimes 	case TBEGIN:
4704b88c807SRodney W. Grimes 		n1 = list(0);
4714b88c807SRodney W. Grimes 		if (readtoken() != TEND)
4724b88c807SRodney W. Grimes 			synexpect(TEND);
4734b88c807SRodney W. Grimes 		checkkwd = 1;
4744b88c807SRodney W. Grimes 		break;
4754b88c807SRodney W. Grimes 	/* Handle an empty command like other simple commands.  */
476248ffae5SJoerg Wunsch 	case TSEMI:
477d8d737d7STim J. Robbins 	case TAND:
478d8d737d7STim J. Robbins 	case TOR:
479aa9caaf6SPeter Wemm 		/*
480aa9caaf6SPeter Wemm 		 * An empty command before a ; doesn't make much sense, and
481aa9caaf6SPeter Wemm 		 * should certainly be disallowed in the case of `if ;'.
482aa9caaf6SPeter Wemm 		 */
483aa9caaf6SPeter Wemm 		if (!redir)
484aa9caaf6SPeter Wemm 			synexpect(-1);
485aa9caaf6SPeter Wemm 	case TNL:
486248ffae5SJoerg Wunsch 	case TEOF:
4874b88c807SRodney W. Grimes 	case TWORD:
488aa9caaf6SPeter Wemm 	case TRP:
4894b88c807SRodney W. Grimes 		tokpushback++;
4906c0bde79SBrian Somers 		n1 = simplecmd(rpp, redir);
4916c0bde79SBrian Somers 		goto checkneg;
4924b88c807SRodney W. Grimes 	default:
4934b88c807SRodney W. Grimes 		synexpect(-1);
4944b88c807SRodney W. Grimes 	}
4954b88c807SRodney W. Grimes 
4964b88c807SRodney W. Grimes 	/* Now check for redirection which may follow command */
4974b88c807SRodney W. Grimes 	while (readtoken() == TREDIR) {
4984b88c807SRodney W. Grimes 		*rpp = n2 = redirnode;
4994b88c807SRodney W. Grimes 		rpp = &n2->nfile.next;
5004b88c807SRodney W. Grimes 		parsefname();
5014b88c807SRodney W. Grimes 	}
5024b88c807SRodney W. Grimes 	tokpushback++;
5034b88c807SRodney W. Grimes 	*rpp = NULL;
5044b88c807SRodney W. Grimes 	if (redir) {
5054b88c807SRodney W. Grimes 		if (n1->type != NSUBSHELL) {
5064b88c807SRodney W. Grimes 			n2 = (union node *)stalloc(sizeof (struct nredir));
5074b88c807SRodney W. Grimes 			n2->type = NREDIR;
5084b88c807SRodney W. Grimes 			n2->nredir.n = n1;
5094b88c807SRodney W. Grimes 			n1 = n2;
5104b88c807SRodney W. Grimes 		}
5114b88c807SRodney W. Grimes 		n1->nredir.redirect = redir;
5124b88c807SRodney W. Grimes 	}
5136c0bde79SBrian Somers 
5146c0bde79SBrian Somers checkneg:
5156c0bde79SBrian Somers 	if (negate) {
5166c0bde79SBrian Somers 		n2 = (union node *)stalloc(sizeof (struct nnot));
5176c0bde79SBrian Somers 		n2->type = NNOT;
5186c0bde79SBrian Somers 		n2->nnot.com = n1;
5196c0bde79SBrian Somers 		return n2;
5206c0bde79SBrian Somers 	}
5216c0bde79SBrian Somers 	else
5224b88c807SRodney W. Grimes 		return n1;
5234b88c807SRodney W. Grimes }
5244b88c807SRodney W. Grimes 
5254b88c807SRodney W. Grimes 
5264b88c807SRodney W. Grimes STATIC union node *
5275134c3f7SWarner Losh simplecmd(union node **rpp, union node *redir)
5284b88c807SRodney W. Grimes {
5294b88c807SRodney W. Grimes 	union node *args, **app;
5304b88c807SRodney W. Grimes 	union node **orig_rpp = rpp;
5316c0bde79SBrian Somers 	union node *n = NULL, *n2;
5326c0bde79SBrian Somers 	int negate = 0;
5334b88c807SRodney W. Grimes 
5344b88c807SRodney W. Grimes 	/* If we don't have any redirections already, then we must reset */
5354b88c807SRodney W. Grimes 	/* rpp to be the address of the local redir variable.  */
5364b88c807SRodney W. Grimes 	if (redir == 0)
5374b88c807SRodney W. Grimes 		rpp = &redir;
5384b88c807SRodney W. Grimes 
5394b88c807SRodney W. Grimes 	args = NULL;
5404b88c807SRodney W. Grimes 	app = &args;
5414b88c807SRodney W. Grimes 	/*
5424b88c807SRodney W. Grimes 	 * We save the incoming value, because we need this for shell
5434b88c807SRodney W. Grimes 	 * functions.  There can not be a redirect or an argument between
5444b88c807SRodney W. Grimes 	 * the function name and the open parenthesis.
5454b88c807SRodney W. Grimes 	 */
5464b88c807SRodney W. Grimes 	orig_rpp = rpp;
5474b88c807SRodney W. Grimes 
5486c0bde79SBrian Somers 	while (readtoken() == TNOT) {
5496c0bde79SBrian Somers 		TRACE(("command: TNOT recognized\n"));
5506c0bde79SBrian Somers 		negate = !negate;
5516c0bde79SBrian Somers 	}
5526c0bde79SBrian Somers 	tokpushback++;
5536c0bde79SBrian Somers 
5544b88c807SRodney W. Grimes 	for (;;) {
5554b88c807SRodney W. Grimes 		if (readtoken() == TWORD) {
5564b88c807SRodney W. Grimes 			n = (union node *)stalloc(sizeof (struct narg));
5574b88c807SRodney W. Grimes 			n->type = NARG;
5584b88c807SRodney W. Grimes 			n->narg.text = wordtext;
5594b88c807SRodney W. Grimes 			n->narg.backquote = backquotelist;
5604b88c807SRodney W. Grimes 			*app = n;
5614b88c807SRodney W. Grimes 			app = &n->narg.next;
5624b88c807SRodney W. Grimes 		} else if (lasttoken == TREDIR) {
5634b88c807SRodney W. Grimes 			*rpp = n = redirnode;
5644b88c807SRodney W. Grimes 			rpp = &n->nfile.next;
5654b88c807SRodney W. Grimes 			parsefname();	/* read name of redirection file */
5664b88c807SRodney W. Grimes 		} else if (lasttoken == TLP && app == &args->narg.next
5674b88c807SRodney W. Grimes 					    && rpp == orig_rpp) {
5684b88c807SRodney W. Grimes 			/* We have a function */
5694b88c807SRodney W. Grimes 			if (readtoken() != TRP)
5704b88c807SRodney W. Grimes 				synexpect(TRP);
571b71085aaSStefan Farfeleder 			funclinno = plinno;
5724b88c807SRodney W. Grimes #ifdef notdef
5734b88c807SRodney W. Grimes 			if (! goodname(n->narg.text))
5744b88c807SRodney W. Grimes 				synerror("Bad function name");
5754b88c807SRodney W. Grimes #endif
5764b88c807SRodney W. Grimes 			n->type = NDEFUN;
5774b88c807SRodney W. Grimes 			n->narg.next = command();
578b71085aaSStefan Farfeleder 			funclinno = 0;
5796c0bde79SBrian Somers 			goto checkneg;
5804b88c807SRodney W. Grimes 		} else {
5814b88c807SRodney W. Grimes 			tokpushback++;
5824b88c807SRodney W. Grimes 			break;
5834b88c807SRodney W. Grimes 		}
5844b88c807SRodney W. Grimes 	}
5854b88c807SRodney W. Grimes 	*app = NULL;
5864b88c807SRodney W. Grimes 	*rpp = NULL;
5874b88c807SRodney W. Grimes 	n = (union node *)stalloc(sizeof (struct ncmd));
5884b88c807SRodney W. Grimes 	n->type = NCMD;
5894b88c807SRodney W. Grimes 	n->ncmd.backgnd = 0;
5904b88c807SRodney W. Grimes 	n->ncmd.args = args;
5914b88c807SRodney W. Grimes 	n->ncmd.redirect = redir;
5926c0bde79SBrian Somers 
5936c0bde79SBrian Somers checkneg:
5946c0bde79SBrian Somers 	if (negate) {
5956c0bde79SBrian Somers 		n2 = (union node *)stalloc(sizeof (struct nnot));
5966c0bde79SBrian Somers 		n2->type = NNOT;
5976c0bde79SBrian Somers 		n2->nnot.com = n;
5986c0bde79SBrian Somers 		return n2;
5996c0bde79SBrian Somers 	}
6006c0bde79SBrian Somers 	else
6014b88c807SRodney W. Grimes 		return n;
6024b88c807SRodney W. Grimes }
6034b88c807SRodney W. Grimes 
604aa9caaf6SPeter Wemm STATIC union node *
6055134c3f7SWarner Losh makename(void)
6065134c3f7SWarner Losh {
607aa9caaf6SPeter Wemm 	union node *n;
608aa9caaf6SPeter Wemm 
609aa9caaf6SPeter Wemm 	n = (union node *)stalloc(sizeof (struct narg));
610aa9caaf6SPeter Wemm 	n->type = NARG;
611aa9caaf6SPeter Wemm 	n->narg.next = NULL;
612aa9caaf6SPeter Wemm 	n->narg.text = wordtext;
613aa9caaf6SPeter Wemm 	n->narg.backquote = backquotelist;
614aa9caaf6SPeter Wemm 	return n;
615aa9caaf6SPeter Wemm }
616aa9caaf6SPeter Wemm 
6175134c3f7SWarner Losh void fixredir(union node *n, const char *text, int err)
618aa9caaf6SPeter Wemm {
619aa9caaf6SPeter Wemm 	TRACE(("Fix redir %s %d\n", text, err));
620aa9caaf6SPeter Wemm 	if (!err)
621aa9caaf6SPeter Wemm 		n->ndup.vname = NULL;
622aa9caaf6SPeter Wemm 
623aa9caaf6SPeter Wemm 	if (is_digit(text[0]) && text[1] == '\0')
624aa9caaf6SPeter Wemm 		n->ndup.dupfd = digit_val(text[0]);
625aa9caaf6SPeter Wemm 	else if (text[0] == '-' && text[1] == '\0')
626aa9caaf6SPeter Wemm 		n->ndup.dupfd = -1;
627aa9caaf6SPeter Wemm 	else {
628aa9caaf6SPeter Wemm 
629aa9caaf6SPeter Wemm 		if (err)
630aa9caaf6SPeter Wemm 			synerror("Bad fd number");
631aa9caaf6SPeter Wemm 		else
632aa9caaf6SPeter Wemm 			n->ndup.vname = makename();
633aa9caaf6SPeter Wemm 	}
634aa9caaf6SPeter Wemm }
635aa9caaf6SPeter Wemm 
6364b88c807SRodney W. Grimes 
6374b88c807SRodney W. Grimes STATIC void
6385134c3f7SWarner Losh parsefname(void)
6395134c3f7SWarner Losh {
6404b88c807SRodney W. Grimes 	union node *n = redirnode;
6414b88c807SRodney W. Grimes 
6424b88c807SRodney W. Grimes 	if (readtoken() != TWORD)
6434b88c807SRodney W. Grimes 		synexpect(-1);
6444b88c807SRodney W. Grimes 	if (n->type == NHERE) {
6454b88c807SRodney W. Grimes 		struct heredoc *here = heredoc;
6464b88c807SRodney W. Grimes 		struct heredoc *p;
6474b88c807SRodney W. Grimes 		int i;
6484b88c807SRodney W. Grimes 
6494b88c807SRodney W. Grimes 		if (quoteflag == 0)
6504b88c807SRodney W. Grimes 			n->type = NXHERE;
6514b88c807SRodney W. Grimes 		TRACE(("Here document %d\n", n->type));
6524b88c807SRodney W. Grimes 		if (here->striptabs) {
6534b88c807SRodney W. Grimes 			while (*wordtext == '\t')
6544b88c807SRodney W. Grimes 				wordtext++;
6554b88c807SRodney W. Grimes 		}
6564b88c807SRodney W. Grimes 		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
6574b88c807SRodney W. Grimes 			synerror("Illegal eof marker for << redirection");
6584b88c807SRodney W. Grimes 		rmescapes(wordtext);
6594b88c807SRodney W. Grimes 		here->eofmark = wordtext;
6604b88c807SRodney W. Grimes 		here->next = NULL;
6614b88c807SRodney W. Grimes 		if (heredoclist == NULL)
6624b88c807SRodney W. Grimes 			heredoclist = here;
6634b88c807SRodney W. Grimes 		else {
6644b88c807SRodney W. Grimes 			for (p = heredoclist ; p->next ; p = p->next);
6654b88c807SRodney W. Grimes 			p->next = here;
6664b88c807SRodney W. Grimes 		}
6674b88c807SRodney W. Grimes 	} else if (n->type == NTOFD || n->type == NFROMFD) {
668aa9caaf6SPeter Wemm 		fixredir(n, wordtext, 0);
6694b88c807SRodney W. Grimes 	} else {
670aa9caaf6SPeter Wemm 		n->nfile.fname = makename();
6714b88c807SRodney W. Grimes 	}
6724b88c807SRodney W. Grimes }
6734b88c807SRodney W. Grimes 
6744b88c807SRodney W. Grimes 
6754b88c807SRodney W. Grimes /*
6764b88c807SRodney W. Grimes  * Input any here documents.
6774b88c807SRodney W. Grimes  */
6784b88c807SRodney W. Grimes 
6794b88c807SRodney W. Grimes STATIC void
6805134c3f7SWarner Losh parseheredoc(void)
6815134c3f7SWarner Losh {
6824b88c807SRodney W. Grimes 	struct heredoc *here;
6834b88c807SRodney W. Grimes 	union node *n;
6844b88c807SRodney W. Grimes 
6854b88c807SRodney W. Grimes 	while (heredoclist) {
6864b88c807SRodney W. Grimes 		here = heredoclist;
6874b88c807SRodney W. Grimes 		heredoclist = here->next;
6884b88c807SRodney W. Grimes 		if (needprompt) {
6894b88c807SRodney W. Grimes 			setprompt(2);
6904b88c807SRodney W. Grimes 			needprompt = 0;
6914b88c807SRodney W. Grimes 		}
6924b88c807SRodney W. Grimes 		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
6934b88c807SRodney W. Grimes 				here->eofmark, here->striptabs);
6944b88c807SRodney W. Grimes 		n = (union node *)stalloc(sizeof (struct narg));
6954b88c807SRodney W. Grimes 		n->narg.type = NARG;
6964b88c807SRodney W. Grimes 		n->narg.next = NULL;
6974b88c807SRodney W. Grimes 		n->narg.text = wordtext;
6984b88c807SRodney W. Grimes 		n->narg.backquote = backquotelist;
6994b88c807SRodney W. Grimes 		here->here->nhere.doc = n;
7004b88c807SRodney W. Grimes 	}
7014b88c807SRodney W. Grimes }
7024b88c807SRodney W. Grimes 
7034b88c807SRodney W. Grimes STATIC int
7045134c3f7SWarner Losh peektoken(void)
7055134c3f7SWarner Losh {
7064b88c807SRodney W. Grimes 	int t;
7074b88c807SRodney W. Grimes 
7084b88c807SRodney W. Grimes 	t = readtoken();
7094b88c807SRodney W. Grimes 	tokpushback++;
7104b88c807SRodney W. Grimes 	return (t);
7114b88c807SRodney W. Grimes }
7124b88c807SRodney W. Grimes 
7134b88c807SRodney W. Grimes STATIC int
7145134c3f7SWarner Losh readtoken(void)
7155134c3f7SWarner Losh {
7164b88c807SRodney W. Grimes 	int t;
7174b88c807SRodney W. Grimes 	int savecheckkwd = checkkwd;
7184b88c807SRodney W. Grimes 	struct alias *ap;
7194b88c807SRodney W. Grimes #ifdef DEBUG
7204b88c807SRodney W. Grimes 	int alreadyseen = tokpushback;
7214b88c807SRodney W. Grimes #endif
7224b88c807SRodney W. Grimes 
7234b88c807SRodney W. Grimes 	top:
7244b88c807SRodney W. Grimes 	t = xxreadtoken();
7254b88c807SRodney W. Grimes 
7264b88c807SRodney W. Grimes 	if (checkkwd) {
7274b88c807SRodney W. Grimes 		/*
7284b88c807SRodney W. Grimes 		 * eat newlines
7294b88c807SRodney W. Grimes 		 */
7304b88c807SRodney W. Grimes 		if (checkkwd == 2) {
7314b88c807SRodney W. Grimes 			checkkwd = 0;
7324b88c807SRodney W. Grimes 			while (t == TNL) {
7334b88c807SRodney W. Grimes 				parseheredoc();
7344b88c807SRodney W. Grimes 				t = xxreadtoken();
7354b88c807SRodney W. Grimes 			}
7364b88c807SRodney W. Grimes 		} else
7374b88c807SRodney W. Grimes 			checkkwd = 0;
7384b88c807SRodney W. Grimes 		/*
7394b88c807SRodney W. Grimes 		 * check for keywords and aliases
7404b88c807SRodney W. Grimes 		 */
741aa9caaf6SPeter Wemm 		if (t == TWORD && !quoteflag)
742aa9caaf6SPeter Wemm 		{
7438b7808bcSJuli Mallett 			const char * const *pp;
7444b88c807SRodney W. Grimes 
7458b7808bcSJuli Mallett 			for (pp = parsekwd; *pp; pp++) {
746aa9caaf6SPeter Wemm 				if (**pp == *wordtext && equal(*pp, wordtext))
747aa9caaf6SPeter Wemm 				{
7484b88c807SRodney W. Grimes 					lasttoken = t = pp - parsekwd + KWDOFFSET;
7494b88c807SRodney W. Grimes 					TRACE(("keyword %s recognized\n", tokname[t]));
7504b88c807SRodney W. Grimes 					goto out;
7514b88c807SRodney W. Grimes 				}
7524b88c807SRodney W. Grimes 			}
7534417f629SPeter Wemm 			if (noaliases == 0 &&
7544417f629SPeter Wemm 			    (ap = lookupalias(wordtext, 1)) != NULL) {
7554b88c807SRodney W. Grimes 				pushstring(ap->val, strlen(ap->val), ap);
7564b88c807SRodney W. Grimes 				checkkwd = savecheckkwd;
7574b88c807SRodney W. Grimes 				goto top;
7584b88c807SRodney W. Grimes 			}
7594b88c807SRodney W. Grimes 		}
7604b88c807SRodney W. Grimes out:
7616c0bde79SBrian Somers 		checkkwd = (t == TNOT) ? savecheckkwd : 0;
7624b88c807SRodney W. Grimes 	}
7634b88c807SRodney W. Grimes #ifdef DEBUG
7644b88c807SRodney W. Grimes 	if (!alreadyseen)
7654b88c807SRodney W. Grimes 	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
7664b88c807SRodney W. Grimes 	else
7674b88c807SRodney W. Grimes 	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
7684b88c807SRodney W. Grimes #endif
7694b88c807SRodney W. Grimes 	return (t);
7704b88c807SRodney W. Grimes }
7714b88c807SRodney W. Grimes 
7724b88c807SRodney W. Grimes 
7734b88c807SRodney W. Grimes /*
7744b88c807SRodney W. Grimes  * Read the next input token.
7754b88c807SRodney W. Grimes  * If the token is a word, we set backquotelist to the list of cmds in
7764b88c807SRodney W. Grimes  *	backquotes.  We set quoteflag to true if any part of the word was
7774b88c807SRodney W. Grimes  *	quoted.
7784b88c807SRodney W. Grimes  * If the token is TREDIR, then we set redirnode to a structure containing
7794b88c807SRodney W. Grimes  *	the redirection.
7804b88c807SRodney W. Grimes  * In all cases, the variable startlinno is set to the number of the line
7814b88c807SRodney W. Grimes  *	on which the token starts.
7824b88c807SRodney W. Grimes  *
7834b88c807SRodney W. Grimes  * [Change comment:  here documents and internal procedures]
7844b88c807SRodney W. Grimes  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
7854b88c807SRodney W. Grimes  *  word parsing code into a separate routine.  In this case, readtoken
7864b88c807SRodney W. Grimes  *  doesn't need to have any internal procedures, but parseword does.
7874b88c807SRodney W. Grimes  *  We could also make parseoperator in essence the main routine, and
7884b88c807SRodney W. Grimes  *  have parseword (readtoken1?) handle both words and redirection.]
7894b88c807SRodney W. Grimes  */
7904b88c807SRodney W. Grimes 
7914b88c807SRodney W. Grimes #define RETURN(token)	return lasttoken = token
7924b88c807SRodney W. Grimes 
7934b88c807SRodney W. Grimes STATIC int
7945134c3f7SWarner Losh xxreadtoken(void)
7955134c3f7SWarner Losh {
7967920a31dSSteve Price 	int c;
7974b88c807SRodney W. Grimes 
7984b88c807SRodney W. Grimes 	if (tokpushback) {
7994b88c807SRodney W. Grimes 		tokpushback = 0;
8004b88c807SRodney W. Grimes 		return lasttoken;
8014b88c807SRodney W. Grimes 	}
8024b88c807SRodney W. Grimes 	if (needprompt) {
8034b88c807SRodney W. Grimes 		setprompt(2);
8044b88c807SRodney W. Grimes 		needprompt = 0;
8054b88c807SRodney W. Grimes 	}
8064b88c807SRodney W. Grimes 	startlinno = plinno;
8074b88c807SRodney W. Grimes 	for (;;) {	/* until token or start of word found */
8084b88c807SRodney W. Grimes 		c = pgetc_macro();
8094b88c807SRodney W. Grimes 		if (c == ' ' || c == '\t')
8104b88c807SRodney W. Grimes 			continue;		/* quick check for white space first */
8114b88c807SRodney W. Grimes 		switch (c) {
8124b88c807SRodney W. Grimes 		case ' ': case '\t':
8134b88c807SRodney W. Grimes 			continue;
8144b88c807SRodney W. Grimes 		case '#':
8154b88c807SRodney W. Grimes 			while ((c = pgetc()) != '\n' && c != PEOF);
8164b88c807SRodney W. Grimes 			pungetc();
8174b88c807SRodney W. Grimes 			continue;
8184b88c807SRodney W. Grimes 		case '\\':
8194b88c807SRodney W. Grimes 			if (pgetc() == '\n') {
8204b88c807SRodney W. Grimes 				startlinno = ++plinno;
8214b88c807SRodney W. Grimes 				if (doprompt)
8224b88c807SRodney W. Grimes 					setprompt(2);
8234b88c807SRodney W. Grimes 				else
8244b88c807SRodney W. Grimes 					setprompt(0);
8254b88c807SRodney W. Grimes 				continue;
8264b88c807SRodney W. Grimes 			}
8274b88c807SRodney W. Grimes 			pungetc();
8284b88c807SRodney W. Grimes 			goto breakloop;
8294b88c807SRodney W. Grimes 		case '\n':
8304b88c807SRodney W. Grimes 			plinno++;
8314b88c807SRodney W. Grimes 			needprompt = doprompt;
8324b88c807SRodney W. Grimes 			RETURN(TNL);
8334b88c807SRodney W. Grimes 		case PEOF:
8344b88c807SRodney W. Grimes 			RETURN(TEOF);
8354b88c807SRodney W. Grimes 		case '&':
8364b88c807SRodney W. Grimes 			if (pgetc() == '&')
8374b88c807SRodney W. Grimes 				RETURN(TAND);
8384b88c807SRodney W. Grimes 			pungetc();
8394b88c807SRodney W. Grimes 			RETURN(TBACKGND);
8404b88c807SRodney W. Grimes 		case '|':
8414b88c807SRodney W. Grimes 			if (pgetc() == '|')
8424b88c807SRodney W. Grimes 				RETURN(TOR);
8434b88c807SRodney W. Grimes 			pungetc();
8444b88c807SRodney W. Grimes 			RETURN(TPIPE);
8454b88c807SRodney W. Grimes 		case ';':
8464b88c807SRodney W. Grimes 			if (pgetc() == ';')
8474b88c807SRodney W. Grimes 				RETURN(TENDCASE);
8484b88c807SRodney W. Grimes 			pungetc();
8494b88c807SRodney W. Grimes 			RETURN(TSEMI);
8504b88c807SRodney W. Grimes 		case '(':
8514b88c807SRodney W. Grimes 			RETURN(TLP);
8524b88c807SRodney W. Grimes 		case ')':
8534b88c807SRodney W. Grimes 			RETURN(TRP);
8544b88c807SRodney W. Grimes 		default:
8554b88c807SRodney W. Grimes 			goto breakloop;
8564b88c807SRodney W. Grimes 		}
8574b88c807SRodney W. Grimes 	}
8584b88c807SRodney W. Grimes breakloop:
8594b88c807SRodney W. Grimes 	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
8604b88c807SRodney W. Grimes #undef RETURN
8614b88c807SRodney W. Grimes }
8624b88c807SRodney W. Grimes 
8634b88c807SRodney W. Grimes 
8644b88c807SRodney W. Grimes 
8654b88c807SRodney W. Grimes /*
8664b88c807SRodney W. Grimes  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
8674b88c807SRodney W. Grimes  * is not NULL, read a here document.  In the latter case, eofmark is the
8684b88c807SRodney W. Grimes  * word which marks the end of the document and striptabs is true if
8694b88c807SRodney W. Grimes  * leading tabs should be stripped from the document.  The argument firstc
8704b88c807SRodney W. Grimes  * is the first character of the input token or document.
8714b88c807SRodney W. Grimes  *
8724b88c807SRodney W. Grimes  * Because C does not have internal subroutines, I have simulated them
8734b88c807SRodney W. Grimes  * using goto's to implement the subroutine linkage.  The following macros
8744b88c807SRodney W. Grimes  * will run code that appears at the end of readtoken1.
8754b88c807SRodney W. Grimes  */
8764b88c807SRodney W. Grimes 
8774b88c807SRodney W. Grimes #define CHECKEND()	{goto checkend; checkend_return:;}
8784b88c807SRodney W. Grimes #define PARSEREDIR()	{goto parseredir; parseredir_return:;}
8794b88c807SRodney W. Grimes #define PARSESUB()	{goto parsesub; parsesub_return:;}
8804b88c807SRodney W. Grimes #define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
8814b88c807SRodney W. Grimes #define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
8824b88c807SRodney W. Grimes #define	PARSEARITH()	{goto parsearith; parsearith_return:;}
8834b88c807SRodney W. Grimes 
8844b88c807SRodney W. Grimes STATIC int
8855134c3f7SWarner Losh readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
8864b88c807SRodney W. Grimes {
887aa9caaf6SPeter Wemm 	int c = firstc;
888aa9caaf6SPeter Wemm 	char *out;
8894b88c807SRodney W. Grimes 	int len;
8904b88c807SRodney W. Grimes 	char line[EOFMARKLEN + 1];
8914b88c807SRodney W. Grimes 	struct nodelist *bqlist;
8924b88c807SRodney W. Grimes 	int quotef;
8934b88c807SRodney W. Grimes 	int dblquote;
8944b88c807SRodney W. Grimes 	int varnest;	/* levels of variables expansion */
8954b88c807SRodney W. Grimes 	int arinest;	/* levels of arithmetic expansion */
8964b88c807SRodney W. Grimes 	int parenlevel;	/* levels of parens in arithmetic */
8974b88c807SRodney W. Grimes 	int oldstyle;
8984b88c807SRodney W. Grimes 	char const *prevsyntax;	/* syntax before arithmetic */
8992dde9ce3SMartin Cracauer 	int synentry;
900aa9caaf6SPeter Wemm #if __GNUC__
901aa9caaf6SPeter Wemm 	/* Avoid longjmp clobbering */
902aa9caaf6SPeter Wemm 	(void) &out;
903aa9caaf6SPeter Wemm 	(void) &quotef;
904aa9caaf6SPeter Wemm 	(void) &dblquote;
905aa9caaf6SPeter Wemm 	(void) &varnest;
906aa9caaf6SPeter Wemm 	(void) &arinest;
907aa9caaf6SPeter Wemm 	(void) &parenlevel;
908aa9caaf6SPeter Wemm 	(void) &oldstyle;
909aa9caaf6SPeter Wemm 	(void) &prevsyntax;
910aa9caaf6SPeter Wemm 	(void) &syntax;
9112dde9ce3SMartin Cracauer 	(void) &synentry;
912aa9caaf6SPeter Wemm #endif
9134b88c807SRodney W. Grimes 
9144b88c807SRodney W. Grimes 	startlinno = plinno;
9154b88c807SRodney W. Grimes 	dblquote = 0;
9164b88c807SRodney W. Grimes 	if (syntax == DQSYNTAX)
9174b88c807SRodney W. Grimes 		dblquote = 1;
9184b88c807SRodney W. Grimes 	quotef = 0;
9194b88c807SRodney W. Grimes 	bqlist = NULL;
9204b88c807SRodney W. Grimes 	varnest = 0;
9214b88c807SRodney W. Grimes 	arinest = 0;
9224b88c807SRodney W. Grimes 	parenlevel = 0;
9234b88c807SRodney W. Grimes 
9244b88c807SRodney W. Grimes 	STARTSTACKSTR(out);
9254b88c807SRodney W. Grimes 	loop: {	/* for each line, until end of word */
9264b88c807SRodney W. Grimes 		CHECKEND();	/* set c to PEOF if at end of here document */
9274b88c807SRodney W. Grimes 		for (;;) {	/* until end of line or end of word */
9284b88c807SRodney W. Grimes 			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */
9292dde9ce3SMartin Cracauer 
9302dde9ce3SMartin Cracauer 			synentry = syntax[c];
9312dde9ce3SMartin Cracauer 
9322dde9ce3SMartin Cracauer 			switch(synentry) {
9334b88c807SRodney W. Grimes 			case CNL:	/* '\n' */
9344b88c807SRodney W. Grimes 				if (syntax == BASESYNTAX)
9354b88c807SRodney W. Grimes 					goto endword;	/* exit outer loop */
9364b88c807SRodney W. Grimes 				USTPUTC(c, out);
9374b88c807SRodney W. Grimes 				plinno++;
9384b88c807SRodney W. Grimes 				if (doprompt)
9394b88c807SRodney W. Grimes 					setprompt(2);
9404b88c807SRodney W. Grimes 				else
9414b88c807SRodney W. Grimes 					setprompt(0);
9424b88c807SRodney W. Grimes 				c = pgetc();
9434b88c807SRodney W. Grimes 				goto loop;		/* continue outer loop */
9444b88c807SRodney W. Grimes 			case CWORD:
9454b88c807SRodney W. Grimes 				USTPUTC(c, out);
9464b88c807SRodney W. Grimes 				break;
9474b88c807SRodney W. Grimes 			case CCTL:
9484b88c807SRodney W. Grimes 				if (eofmark == NULL || dblquote)
9494b88c807SRodney W. Grimes 					USTPUTC(CTLESC, out);
9504b88c807SRodney W. Grimes 				USTPUTC(c, out);
9514b88c807SRodney W. Grimes 				break;
9524b88c807SRodney W. Grimes 			case CBACK:	/* backslash */
9534b88c807SRodney W. Grimes 				c = pgetc();
9544b88c807SRodney W. Grimes 				if (c == PEOF) {
9554b88c807SRodney W. Grimes 					USTPUTC('\\', out);
9564b88c807SRodney W. Grimes 					pungetc();
9574b88c807SRodney W. Grimes 				} else if (c == '\n') {
95862f9f953SYaroslav Tykhiy 					plinno++;
9594b88c807SRodney W. Grimes 					if (doprompt)
9604b88c807SRodney W. Grimes 						setprompt(2);
9614b88c807SRodney W. Grimes 					else
9624b88c807SRodney W. Grimes 						setprompt(0);
9634b88c807SRodney W. Grimes 				} else {
96473f612b5SMartin Cracauer 					if (dblquote && c != '\\' &&
96573f612b5SMartin Cracauer 					    c != '`' && c != '$' &&
96673f612b5SMartin Cracauer 					    (c != '"' || eofmark != NULL))
9674b88c807SRodney W. Grimes 						USTPUTC('\\', out);
9680c4eeddaSTor Egge 					if (SQSYNTAX[c] == CCTL)
9694b88c807SRodney W. Grimes 						USTPUTC(CTLESC, out);
9705557a02aSTor Egge 					else if (eofmark == NULL)
9716f47734fSTor Egge 						USTPUTC(CTLQUOTEMARK, out);
9724b88c807SRodney W. Grimes 					USTPUTC(c, out);
9734b88c807SRodney W. Grimes 					quotef++;
9744b88c807SRodney W. Grimes 				}
9754b88c807SRodney W. Grimes 				break;
9764b88c807SRodney W. Grimes 			case CSQUOTE:
9775557a02aSTor Egge 				if (eofmark == NULL)
9786f47734fSTor Egge 					USTPUTC(CTLQUOTEMARK, out);
9794b88c807SRodney W. Grimes 				syntax = SQSYNTAX;
9804b88c807SRodney W. Grimes 				break;
9814b88c807SRodney W. Grimes 			case CDQUOTE:
9825557a02aSTor Egge 				if (eofmark == NULL)
9836f47734fSTor Egge 					USTPUTC(CTLQUOTEMARK, out);
9844b88c807SRodney W. Grimes 				syntax = DQSYNTAX;
9854b88c807SRodney W. Grimes 				dblquote = 1;
9864b88c807SRodney W. Grimes 				break;
9874b88c807SRodney W. Grimes 			case CENDQUOTE:
9885557a02aSTor Egge 				if (eofmark != NULL && arinest == 0 &&
9895557a02aSTor Egge 				    varnest == 0) {
9904b88c807SRodney W. Grimes 					USTPUTC(c, out);
9914b88c807SRodney W. Grimes 				} else {
9925557a02aSTor Egge 					if (arinest) {
9934b88c807SRodney W. Grimes 						syntax = ARISYNTAX;
9944b88c807SRodney W. Grimes 						dblquote = 0;
9955557a02aSTor Egge 					} else if (eofmark == NULL) {
9965557a02aSTor Egge 						syntax = BASESYNTAX;
9975557a02aSTor Egge 						dblquote = 0;
9985557a02aSTor Egge 					}
9995557a02aSTor Egge 					quotef++;
10004b88c807SRodney W. Grimes 				}
10014b88c807SRodney W. Grimes 				break;
10024b88c807SRodney W. Grimes 			case CVAR:	/* '$' */
10034b88c807SRodney W. Grimes 				PARSESUB();		/* parse substitution */
10044b88c807SRodney W. Grimes 				break;
10054b88c807SRodney W. Grimes 			case CENDVAR:	/* '}' */
10064b88c807SRodney W. Grimes 				if (varnest > 0) {
10074b88c807SRodney W. Grimes 					varnest--;
10084b88c807SRodney W. Grimes 					USTPUTC(CTLENDVAR, out);
10094b88c807SRodney W. Grimes 				} else {
10104b88c807SRodney W. Grimes 					USTPUTC(c, out);
10114b88c807SRodney W. Grimes 				}
10124b88c807SRodney W. Grimes 				break;
10134b88c807SRodney W. Grimes 			case CLP:	/* '(' in arithmetic */
10144b88c807SRodney W. Grimes 				parenlevel++;
10154b88c807SRodney W. Grimes 				USTPUTC(c, out);
10164b88c807SRodney W. Grimes 				break;
10174b88c807SRodney W. Grimes 			case CRP:	/* ')' in arithmetic */
10184b88c807SRodney W. Grimes 				if (parenlevel > 0) {
10194b88c807SRodney W. Grimes 					USTPUTC(c, out);
10204b88c807SRodney W. Grimes 					--parenlevel;
10214b88c807SRodney W. Grimes 				} else {
10224b88c807SRodney W. Grimes 					if (pgetc() == ')') {
10234b88c807SRodney W. Grimes 						if (--arinest == 0) {
10244b88c807SRodney W. Grimes 							USTPUTC(CTLENDARI, out);
10254b88c807SRodney W. Grimes 							syntax = prevsyntax;
10265557a02aSTor Egge 							if (syntax == DQSYNTAX)
10275557a02aSTor Egge 								dblquote = 1;
10285557a02aSTor Egge 							else
10295557a02aSTor Egge 								dblquote = 0;
10304b88c807SRodney W. Grimes 						} else
10314b88c807SRodney W. Grimes 							USTPUTC(')', out);
10324b88c807SRodney W. Grimes 					} else {
10334b88c807SRodney W. Grimes 						/*
10344b88c807SRodney W. Grimes 						 * unbalanced parens
10354b88c807SRodney W. Grimes 						 *  (don't 2nd guess - no error)
10364b88c807SRodney W. Grimes 						 */
10374b88c807SRodney W. Grimes 						pungetc();
10384b88c807SRodney W. Grimes 						USTPUTC(')', out);
10394b88c807SRodney W. Grimes 					}
10404b88c807SRodney W. Grimes 				}
10414b88c807SRodney W. Grimes 				break;
10424b88c807SRodney W. Grimes 			case CBQUOTE:	/* '`' */
10434b88c807SRodney W. Grimes 				PARSEBACKQOLD();
10444b88c807SRodney W. Grimes 				break;
10454b88c807SRodney W. Grimes 			case CEOF:
10464b88c807SRodney W. Grimes 				goto endword;		/* exit outer loop */
10474b88c807SRodney W. Grimes 			default:
10484b88c807SRodney W. Grimes 				if (varnest == 0)
10494b88c807SRodney W. Grimes 					goto endword;	/* exit outer loop */
10504b88c807SRodney W. Grimes 				USTPUTC(c, out);
10514b88c807SRodney W. Grimes 			}
10524b88c807SRodney W. Grimes 			c = pgetc_macro();
10534b88c807SRodney W. Grimes 		}
10544b88c807SRodney W. Grimes 	}
10554b88c807SRodney W. Grimes endword:
10564b88c807SRodney W. Grimes 	if (syntax == ARISYNTAX)
10574b88c807SRodney W. Grimes 		synerror("Missing '))'");
10584b88c807SRodney W. Grimes 	if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10594b88c807SRodney W. Grimes 		synerror("Unterminated quoted string");
10604b88c807SRodney W. Grimes 	if (varnest != 0) {
10614b88c807SRodney W. Grimes 		startlinno = plinno;
10624b88c807SRodney W. Grimes 		synerror("Missing '}'");
10634b88c807SRodney W. Grimes 	}
10644b88c807SRodney W. Grimes 	USTPUTC('\0', out);
10654b88c807SRodney W. Grimes 	len = out - stackblock();
10664b88c807SRodney W. Grimes 	out = stackblock();
10674b88c807SRodney W. Grimes 	if (eofmark == NULL) {
10684b88c807SRodney W. Grimes 		if ((c == '>' || c == '<')
10694b88c807SRodney W. Grimes 		 && quotef == 0
10704b88c807SRodney W. Grimes 		 && len <= 2
10714b88c807SRodney W. Grimes 		 && (*out == '\0' || is_digit(*out))) {
10724b88c807SRodney W. Grimes 			PARSEREDIR();
10734b88c807SRodney W. Grimes 			return lasttoken = TREDIR;
10744b88c807SRodney W. Grimes 		} else {
10754b88c807SRodney W. Grimes 			pungetc();
10764b88c807SRodney W. Grimes 		}
10774b88c807SRodney W. Grimes 	}
10784b88c807SRodney W. Grimes 	quoteflag = quotef;
10794b88c807SRodney W. Grimes 	backquotelist = bqlist;
10804b88c807SRodney W. Grimes 	grabstackblock(len);
10814b88c807SRodney W. Grimes 	wordtext = out;
10824b88c807SRodney W. Grimes 	return lasttoken = TWORD;
10834b88c807SRodney W. Grimes /* end of readtoken routine */
10844b88c807SRodney W. Grimes 
10854b88c807SRodney W. Grimes 
10864b88c807SRodney W. Grimes 
10874b88c807SRodney W. Grimes /*
10884b88c807SRodney W. Grimes  * Check to see whether we are at the end of the here document.  When this
10894b88c807SRodney W. Grimes  * is called, c is set to the first character of the next input line.  If
10904b88c807SRodney W. Grimes  * we are at the end of the here document, this routine sets the c to PEOF.
10914b88c807SRodney W. Grimes  */
10924b88c807SRodney W. Grimes 
10934b88c807SRodney W. Grimes checkend: {
10944b88c807SRodney W. Grimes 	if (eofmark) {
10954b88c807SRodney W. Grimes 		if (striptabs) {
10964b88c807SRodney W. Grimes 			while (c == '\t')
10974b88c807SRodney W. Grimes 				c = pgetc();
10984b88c807SRodney W. Grimes 		}
10994b88c807SRodney W. Grimes 		if (c == *eofmark) {
11004b88c807SRodney W. Grimes 			if (pfgets(line, sizeof line) != NULL) {
11017920a31dSSteve Price 				char *p, *q;
11024b88c807SRodney W. Grimes 
11034b88c807SRodney W. Grimes 				p = line;
11044b88c807SRodney W. Grimes 				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
11054b88c807SRodney W. Grimes 				if (*p == '\n' && *q == '\0') {
11064b88c807SRodney W. Grimes 					c = PEOF;
11074b88c807SRodney W. Grimes 					plinno++;
11084b88c807SRodney W. Grimes 					needprompt = doprompt;
11094b88c807SRodney W. Grimes 				} else {
11104b88c807SRodney W. Grimes 					pushstring(line, strlen(line), NULL);
11114b88c807SRodney W. Grimes 				}
11124b88c807SRodney W. Grimes 			}
11134b88c807SRodney W. Grimes 		}
11144b88c807SRodney W. Grimes 	}
11154b88c807SRodney W. Grimes 	goto checkend_return;
11164b88c807SRodney W. Grimes }
11174b88c807SRodney W. Grimes 
11184b88c807SRodney W. Grimes 
11194b88c807SRodney W. Grimes /*
11204b88c807SRodney W. Grimes  * Parse a redirection operator.  The variable "out" points to a string
11214b88c807SRodney W. Grimes  * specifying the fd to be redirected.  The variable "c" contains the
11224b88c807SRodney W. Grimes  * first character of the redirection operator.
11234b88c807SRodney W. Grimes  */
11244b88c807SRodney W. Grimes 
11254b88c807SRodney W. Grimes parseredir: {
11264b88c807SRodney W. Grimes 	char fd = *out;
11274b88c807SRodney W. Grimes 	union node *np;
11284b88c807SRodney W. Grimes 
11294b88c807SRodney W. Grimes 	np = (union node *)stalloc(sizeof (struct nfile));
11304b88c807SRodney W. Grimes 	if (c == '>') {
11314b88c807SRodney W. Grimes 		np->nfile.fd = 1;
11324b88c807SRodney W. Grimes 		c = pgetc();
11334b88c807SRodney W. Grimes 		if (c == '>')
11344b88c807SRodney W. Grimes 			np->type = NAPPEND;
11354b88c807SRodney W. Grimes 		else if (c == '&')
11364b88c807SRodney W. Grimes 			np->type = NTOFD;
11371a958c66STim J. Robbins 		else if (c == '|')
11381a958c66STim J. Robbins 			np->type = NCLOBBER;
11394b88c807SRodney W. Grimes 		else {
11404b88c807SRodney W. Grimes 			np->type = NTO;
11414b88c807SRodney W. Grimes 			pungetc();
11424b88c807SRodney W. Grimes 		}
11434b88c807SRodney W. Grimes 	} else {	/* c == '<' */
11444b88c807SRodney W. Grimes 		np->nfile.fd = 0;
11454b88c807SRodney W. Grimes 		c = pgetc();
11464b88c807SRodney W. Grimes 		if (c == '<') {
11474b88c807SRodney W. Grimes 			if (sizeof (struct nfile) != sizeof (struct nhere)) {
11484b88c807SRodney W. Grimes 				np = (union node *)stalloc(sizeof (struct nhere));
11494b88c807SRodney W. Grimes 				np->nfile.fd = 0;
11504b88c807SRodney W. Grimes 			}
11514b88c807SRodney W. Grimes 			np->type = NHERE;
11524b88c807SRodney W. Grimes 			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
11534b88c807SRodney W. Grimes 			heredoc->here = np;
11544b88c807SRodney W. Grimes 			if ((c = pgetc()) == '-') {
11554b88c807SRodney W. Grimes 				heredoc->striptabs = 1;
11564b88c807SRodney W. Grimes 			} else {
11574b88c807SRodney W. Grimes 				heredoc->striptabs = 0;
11584b88c807SRodney W. Grimes 				pungetc();
11594b88c807SRodney W. Grimes 			}
11604b88c807SRodney W. Grimes 		} else if (c == '&')
11614b88c807SRodney W. Grimes 			np->type = NFROMFD;
11624682f420SBrian Somers 		else if (c == '>')
11634682f420SBrian Somers 			np->type = NFROMTO;
11644b88c807SRodney W. Grimes 		else {
11654b88c807SRodney W. Grimes 			np->type = NFROM;
11664b88c807SRodney W. Grimes 			pungetc();
11674b88c807SRodney W. Grimes 		}
11684b88c807SRodney W. Grimes 	}
11694b88c807SRodney W. Grimes 	if (fd != '\0')
11704b88c807SRodney W. Grimes 		np->nfile.fd = digit_val(fd);
11714b88c807SRodney W. Grimes 	redirnode = np;
11724b88c807SRodney W. Grimes 	goto parseredir_return;
11734b88c807SRodney W. Grimes }
11744b88c807SRodney W. Grimes 
11754b88c807SRodney W. Grimes 
11764b88c807SRodney W. Grimes /*
11774b88c807SRodney W. Grimes  * Parse a substitution.  At this point, we have read the dollar sign
11784b88c807SRodney W. Grimes  * and nothing else.
11794b88c807SRodney W. Grimes  */
11804b88c807SRodney W. Grimes 
11814b88c807SRodney W. Grimes parsesub: {
1182b71085aaSStefan Farfeleder 	char buf[10];
11834b88c807SRodney W. Grimes 	int subtype;
11844b88c807SRodney W. Grimes 	int typeloc;
11854b88c807SRodney W. Grimes 	int flags;
11864b88c807SRodney W. Grimes 	char *p;
11874b88c807SRodney W. Grimes 	static const char types[] = "}-+?=";
11885c817731SPeter Wemm 	int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
1189b71085aaSStefan Farfeleder 	int i;
1190b71085aaSStefan Farfeleder 	int linno;
11914f30f299SStefan Farfeleder 	int length;
11924b88c807SRodney W. Grimes 
11934b88c807SRodney W. Grimes 	c = pgetc();
1194716b138bSStefan Farfeleder 	if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) &&
1195716b138bSStefan Farfeleder 	    !is_special(c)) {
11964b88c807SRodney W. Grimes 		USTPUTC('$', out);
11974b88c807SRodney W. Grimes 		pungetc();
11984b88c807SRodney W. Grimes 	} else if (c == '(') {	/* $(command) or $((arith)) */
11994b88c807SRodney W. Grimes 		if (pgetc() == '(') {
12004b88c807SRodney W. Grimes 			PARSEARITH();
12014b88c807SRodney W. Grimes 		} else {
12024b88c807SRodney W. Grimes 			pungetc();
12034b88c807SRodney W. Grimes 			PARSEBACKQNEW();
12044b88c807SRodney W. Grimes 		}
12054b88c807SRodney W. Grimes 	} else {
12064b88c807SRodney W. Grimes 		USTPUTC(CTLVAR, out);
12074b88c807SRodney W. Grimes 		typeloc = out - stackblock();
12084b88c807SRodney W. Grimes 		USTPUTC(VSNORMAL, out);
12094b88c807SRodney W. Grimes 		subtype = VSNORMAL;
1210b71085aaSStefan Farfeleder 		flags = 0;
12114b88c807SRodney W. Grimes 		if (c == '{') {
12125c817731SPeter Wemm 			bracketed_name = 1;
12134b88c807SRodney W. Grimes 			c = pgetc();
1214aa9caaf6SPeter Wemm 			if (c == '#') {
1215aa9caaf6SPeter Wemm 				if ((c = pgetc()) == '}')
1216aa9caaf6SPeter Wemm 					c = '#';
1217aa9caaf6SPeter Wemm 				else
1218aa9caaf6SPeter Wemm 					subtype = VSLENGTH;
1219aa9caaf6SPeter Wemm 			}
1220aa9caaf6SPeter Wemm 			else
12214b88c807SRodney W. Grimes 				subtype = 0;
12224b88c807SRodney W. Grimes 		}
1223716b138bSStefan Farfeleder 		if (!is_eof(c) && is_name(c)) {
12244f30f299SStefan Farfeleder 			length = 0;
12254b88c807SRodney W. Grimes 			do {
12264b88c807SRodney W. Grimes 				STPUTC(c, out);
12274b88c807SRodney W. Grimes 				c = pgetc();
12284f30f299SStefan Farfeleder 				length++;
1229716b138bSStefan Farfeleder 			} while (!is_eof(c) && is_in_name(c));
12304f30f299SStefan Farfeleder 			if (length == 6 &&
12314f30f299SStefan Farfeleder 			    strncmp(out - length, "LINENO", length) == 0) {
1232b71085aaSStefan Farfeleder 				/* Replace the variable name with the
1233b71085aaSStefan Farfeleder 				 * current line number. */
1234b71085aaSStefan Farfeleder 				linno = plinno;
1235b71085aaSStefan Farfeleder 				if (funclinno != 0)
1236b71085aaSStefan Farfeleder 					linno -= funclinno - 1;
1237b71085aaSStefan Farfeleder 				snprintf(buf, sizeof(buf), "%d", linno);
1238b71085aaSStefan Farfeleder 				STADJUST(-6, out);
1239b71085aaSStefan Farfeleder 				for (i = 0; buf[i] != '\0'; i++)
1240b71085aaSStefan Farfeleder 					STPUTC(buf[i], out);
1241b71085aaSStefan Farfeleder 				flags |= VSLINENO;
1242b71085aaSStefan Farfeleder 			}
12435c817731SPeter Wemm 		} else if (is_digit(c)) {
12445c817731SPeter Wemm 			if (bracketed_name) {
12455c817731SPeter Wemm 				do {
12465c817731SPeter Wemm 					STPUTC(c, out);
12475c817731SPeter Wemm 					c = pgetc();
12485c817731SPeter Wemm 				} while (is_digit(c));
12495c817731SPeter Wemm 			} else {
12505c817731SPeter Wemm 				STPUTC(c, out);
12515c817731SPeter Wemm 				c = pgetc();
12525c817731SPeter Wemm 			}
12534b88c807SRodney W. Grimes 		} else {
125462addaefSStefan Farfeleder 			if (! is_special(c)) {
125562addaefSStefan Farfeleder 				subtype = VSERROR;
125662addaefSStefan Farfeleder 				if (c == '}')
125762addaefSStefan Farfeleder 					pungetc();
125862addaefSStefan Farfeleder 				else
125962addaefSStefan Farfeleder 					USTPUTC(c, out);
126062addaefSStefan Farfeleder 			} else {
12614b88c807SRodney W. Grimes 				USTPUTC(c, out);
12624b88c807SRodney W. Grimes 				c = pgetc();
12634b88c807SRodney W. Grimes 			}
126462addaefSStefan Farfeleder 		}
12654b88c807SRodney W. Grimes 		if (subtype == 0) {
1266aa9caaf6SPeter Wemm 			switch (c) {
1267aa9caaf6SPeter Wemm 			case ':':
1268b71085aaSStefan Farfeleder 				flags |= VSNUL;
12694b88c807SRodney W. Grimes 				c = pgetc();
1270aa9caaf6SPeter Wemm 				/*FALLTHROUGH*/
1271aa9caaf6SPeter Wemm 			default:
12724b88c807SRodney W. Grimes 				p = strchr(types, c);
127362addaefSStefan Farfeleder 				if (p == NULL) {
127462addaefSStefan Farfeleder 					if (flags == VSNUL)
127562addaefSStefan Farfeleder 						STPUTC(':', out);
127662addaefSStefan Farfeleder 					STPUTC(c, out);
127762addaefSStefan Farfeleder 					subtype = VSERROR;
127862addaefSStefan Farfeleder 				} else
12794b88c807SRodney W. Grimes 					subtype = p - types + VSNORMAL;
1280aa9caaf6SPeter Wemm 				break;
1281aa9caaf6SPeter Wemm 			case '%':
1282aa9caaf6SPeter Wemm 			case '#':
1283aa9caaf6SPeter Wemm 				{
1284aa9caaf6SPeter Wemm 					int cc = c;
1285aa9caaf6SPeter Wemm 					subtype = c == '#' ? VSTRIMLEFT :
1286aa9caaf6SPeter Wemm 							     VSTRIMRIGHT;
1287aa9caaf6SPeter Wemm 					c = pgetc();
1288aa9caaf6SPeter Wemm 					if (c == cc)
1289aa9caaf6SPeter Wemm 						subtype++;
1290aa9caaf6SPeter Wemm 					else
1291aa9caaf6SPeter Wemm 						pungetc();
1292aa9caaf6SPeter Wemm 					break;
1293aa9caaf6SPeter Wemm 				}
1294aa9caaf6SPeter Wemm 			}
129562addaefSStefan Farfeleder 		} else if (subtype != VSERROR) {
12964b88c807SRodney W. Grimes 			pungetc();
12974b88c807SRodney W. Grimes 		}
129862addaefSStefan Farfeleder 		STPUTC('=', out);
1299c11e75cfSMartin Cracauer 		if (subtype != VSLENGTH && (dblquote || arinest))
13004b88c807SRodney W. Grimes 			flags |= VSQUOTE;
13014b88c807SRodney W. Grimes 		*(stackblock() + typeloc) = subtype | flags;
13024b88c807SRodney W. Grimes 		if (subtype != VSNORMAL)
13034b88c807SRodney W. Grimes 			varnest++;
13044b88c807SRodney W. Grimes 	}
13054b88c807SRodney W. Grimes 	goto parsesub_return;
13064b88c807SRodney W. Grimes }
13074b88c807SRodney W. Grimes 
13084b88c807SRodney W. Grimes 
13094b88c807SRodney W. Grimes /*
13104b88c807SRodney W. Grimes  * Called to parse command substitutions.  Newstyle is set if the command
13114b88c807SRodney W. Grimes  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
13124b88c807SRodney W. Grimes  * list of commands (passed by reference), and savelen is the number of
13134b88c807SRodney W. Grimes  * characters on the top of the stack which must be preserved.
13144b88c807SRodney W. Grimes  */
13154b88c807SRodney W. Grimes 
13164b88c807SRodney W. Grimes parsebackq: {
13174b88c807SRodney W. Grimes 	struct nodelist **nlpp;
13184b88c807SRodney W. Grimes 	int savepbq;
13194b88c807SRodney W. Grimes 	union node *n;
13204b88c807SRodney W. Grimes 	char *volatile str;
13214b88c807SRodney W. Grimes 	struct jmploc jmploc;
13224b88c807SRodney W. Grimes 	struct jmploc *volatile savehandler;
13234b88c807SRodney W. Grimes 	int savelen;
1324ab0a2172SSteve Price 	int saveprompt;
1325ab0a2172SSteve Price #if __GNUC__
1326ab0a2172SSteve Price 	/* Avoid longjmp clobbering */
1327ab0a2172SSteve Price 	(void) &saveprompt;
1328ab0a2172SSteve Price #endif
13294b88c807SRodney W. Grimes 
13304b88c807SRodney W. Grimes 	savepbq = parsebackquote;
13314b88c807SRodney W. Grimes 	if (setjmp(jmploc.loc)) {
13324b88c807SRodney W. Grimes 		if (str)
13334b88c807SRodney W. Grimes 			ckfree(str);
13344b88c807SRodney W. Grimes 		parsebackquote = 0;
13354b88c807SRodney W. Grimes 		handler = savehandler;
13364b88c807SRodney W. Grimes 		longjmp(handler->loc, 1);
13374b88c807SRodney W. Grimes 	}
13384b88c807SRodney W. Grimes 	INTOFF;
13394b88c807SRodney W. Grimes 	str = NULL;
13404b88c807SRodney W. Grimes 	savelen = out - stackblock();
13414b88c807SRodney W. Grimes 	if (savelen > 0) {
13424b88c807SRodney W. Grimes 		str = ckmalloc(savelen);
1343aa9caaf6SPeter Wemm 		memcpy(str, stackblock(), savelen);
13444b88c807SRodney W. Grimes 	}
13454b88c807SRodney W. Grimes 	savehandler = handler;
13464b88c807SRodney W. Grimes 	handler = &jmploc;
13474b88c807SRodney W. Grimes 	INTON;
13484b88c807SRodney W. Grimes         if (oldstyle) {
13494b88c807SRodney W. Grimes                 /* We must read until the closing backquote, giving special
13504b88c807SRodney W. Grimes                    treatment to some slashes, and then push the string and
13514b88c807SRodney W. Grimes                    reread it as input, interpreting it normally.  */
13527920a31dSSteve Price                 char *out;
13537920a31dSSteve Price                 int c;
13544b88c807SRodney W. Grimes                 int savelen;
13554b88c807SRodney W. Grimes                 char *str;
13564b88c807SRodney W. Grimes 
1357ab0a2172SSteve Price 
13584b88c807SRodney W. Grimes                 STARTSTACKSTR(out);
1359ab0a2172SSteve Price 		for (;;) {
1360ab0a2172SSteve Price 			if (needprompt) {
1361ab0a2172SSteve Price 				setprompt(2);
1362ab0a2172SSteve Price 				needprompt = 0;
136372348d41SJoerg Wunsch 			}
1364ab0a2172SSteve Price 			switch (c = pgetc()) {
1365ab0a2172SSteve Price 			case '`':
1366ab0a2172SSteve Price 				goto done;
1367ab0a2172SSteve Price 
1368ab0a2172SSteve Price 			case '\\':
1369ab0a2172SSteve Price                                 if ((c = pgetc()) == '\n') {
1370ab0a2172SSteve Price 					plinno++;
1371ab0a2172SSteve Price 					if (doprompt)
1372ab0a2172SSteve Price 						setprompt(2);
1373ab0a2172SSteve Price 					else
1374ab0a2172SSteve Price 						setprompt(0);
1375ab0a2172SSteve Price 					/*
1376ab0a2172SSteve Price 					 * If eating a newline, avoid putting
1377ab0a2172SSteve Price 					 * the newline into the new character
1378ab0a2172SSteve Price 					 * stream (via the STPUTC after the
1379ab0a2172SSteve Price 					 * switch).
1380ab0a2172SSteve Price 					 */
1381ab0a2172SSteve Price 					continue;
1382ab0a2172SSteve Price 				}
13831e95454eSPaul Richards                                 if (c != '\\' && c != '`' && c != '$'
13844b88c807SRodney W. Grimes                                     && (!dblquote || c != '"'))
13854b88c807SRodney W. Grimes                                         STPUTC('\\', out);
1386ab0a2172SSteve Price 				break;
1387ab0a2172SSteve Price 
1388ab0a2172SSteve Price 			case '\n':
1389ab0a2172SSteve Price 				plinno++;
1390ab0a2172SSteve Price 				needprompt = doprompt;
1391ab0a2172SSteve Price 				break;
1392ab0a2172SSteve Price 
1393ab0a2172SSteve Price 			case PEOF:
1394ab0a2172SSteve Price 			        startlinno = plinno;
1395ab0a2172SSteve Price 				synerror("EOF in backquote substitution");
1396ab0a2172SSteve Price  				break;
1397ab0a2172SSteve Price 
1398ab0a2172SSteve Price 			default:
1399ab0a2172SSteve Price 				break;
14004b88c807SRodney W. Grimes 			}
14014b88c807SRodney W. Grimes 			STPUTC(c, out);
14024b88c807SRodney W. Grimes                 }
1403ab0a2172SSteve Price done:
14044b88c807SRodney W. Grimes                 STPUTC('\0', out);
14054b88c807SRodney W. Grimes                 savelen = out - stackblock();
14064b88c807SRodney W. Grimes                 if (savelen > 0) {
14074b88c807SRodney W. Grimes                         str = ckmalloc(savelen);
1408aa9caaf6SPeter Wemm                         memcpy(str, stackblock(), savelen);
14094b88c807SRodney W. Grimes 			setinputstring(str, 1);
14104b88c807SRodney W. Grimes                 }
1411aa9caaf6SPeter Wemm         }
14124b88c807SRodney W. Grimes 	nlpp = &bqlist;
14134b88c807SRodney W. Grimes 	while (*nlpp)
14144b88c807SRodney W. Grimes 		nlpp = &(*nlpp)->next;
14154b88c807SRodney W. Grimes 	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
14164b88c807SRodney W. Grimes 	(*nlpp)->next = NULL;
14174b88c807SRodney W. Grimes 	parsebackquote = oldstyle;
1418ab0a2172SSteve Price 
1419ab0a2172SSteve Price 	if (oldstyle) {
1420ab0a2172SSteve Price 		saveprompt = doprompt;
1421ab0a2172SSteve Price 		doprompt = 0;
1422ab0a2172SSteve Price 	}
1423ab0a2172SSteve Price 
14244b88c807SRodney W. Grimes 	n = list(0);
1425ab0a2172SSteve Price 
14264b88c807SRodney W. Grimes 	if (oldstyle)
1427ab0a2172SSteve Price 		doprompt = saveprompt;
1428ab0a2172SSteve Price 	else {
1429ab0a2172SSteve Price 		if (readtoken() != TRP)
1430ab0a2172SSteve Price 			synexpect(TRP);
1431ab0a2172SSteve Price 	}
1432ab0a2172SSteve Price 
1433ab0a2172SSteve Price 	(*nlpp)->n = n;
1434ab0a2172SSteve Price         if (oldstyle) {
1435ab0a2172SSteve Price 		/*
1436ab0a2172SSteve Price 		 * Start reading from old file again, ignoring any pushed back
1437ab0a2172SSteve Price 		 * tokens left from the backquote parsing
1438ab0a2172SSteve Price 		 */
14394b88c807SRodney W. Grimes                 popfile();
1440ab0a2172SSteve Price 		tokpushback = 0;
1441ab0a2172SSteve Price 	}
14424b88c807SRodney W. Grimes 	while (stackblocksize() <= savelen)
14434b88c807SRodney W. Grimes 		growstackblock();
14444b88c807SRodney W. Grimes 	STARTSTACKSTR(out);
14454b88c807SRodney W. Grimes 	if (str) {
1446aa9caaf6SPeter Wemm 		memcpy(out, str, savelen);
14474b88c807SRodney W. Grimes 		STADJUST(savelen, out);
14484b88c807SRodney W. Grimes 		INTOFF;
14494b88c807SRodney W. Grimes 		ckfree(str);
14504b88c807SRodney W. Grimes 		str = NULL;
14514b88c807SRodney W. Grimes 		INTON;
14524b88c807SRodney W. Grimes 	}
14534b88c807SRodney W. Grimes 	parsebackquote = savepbq;
14544b88c807SRodney W. Grimes 	handler = savehandler;
14554b88c807SRodney W. Grimes 	if (arinest || dblquote)
14564b88c807SRodney W. Grimes 		USTPUTC(CTLBACKQ | CTLQUOTE, out);
14574b88c807SRodney W. Grimes 	else
14584b88c807SRodney W. Grimes 		USTPUTC(CTLBACKQ, out);
14594b88c807SRodney W. Grimes 	if (oldstyle)
14604b88c807SRodney W. Grimes 		goto parsebackq_oldreturn;
14614b88c807SRodney W. Grimes 	else
14624b88c807SRodney W. Grimes 		goto parsebackq_newreturn;
14634b88c807SRodney W. Grimes }
14644b88c807SRodney W. Grimes 
14654b88c807SRodney W. Grimes /*
14664b88c807SRodney W. Grimes  * Parse an arithmetic expansion (indicate start of one and set state)
14674b88c807SRodney W. Grimes  */
14684b88c807SRodney W. Grimes parsearith: {
14694b88c807SRodney W. Grimes 
14704b88c807SRodney W. Grimes 	if (++arinest == 1) {
14714b88c807SRodney W. Grimes 		prevsyntax = syntax;
14724b88c807SRodney W. Grimes 		syntax = ARISYNTAX;
14734b88c807SRodney W. Grimes 		USTPUTC(CTLARI, out);
14746f47734fSTor Egge 		if (dblquote)
14756f47734fSTor Egge 			USTPUTC('"',out);
14766f47734fSTor Egge 		else
14776f47734fSTor Egge 			USTPUTC(' ',out);
14784b88c807SRodney W. Grimes 	} else {
14794b88c807SRodney W. Grimes 		/*
14804b88c807SRodney W. Grimes 		 * we collapse embedded arithmetic expansion to
14814b88c807SRodney W. Grimes 		 * parenthesis, which should be equivalent
14824b88c807SRodney W. Grimes 		 */
14834b88c807SRodney W. Grimes 		USTPUTC('(', out);
14844b88c807SRodney W. Grimes 	}
14854b88c807SRodney W. Grimes 	goto parsearith_return;
14864b88c807SRodney W. Grimes }
14874b88c807SRodney W. Grimes 
14884b88c807SRodney W. Grimes } /* end of readtoken */
14894b88c807SRodney W. Grimes 
14904b88c807SRodney W. Grimes 
14914b88c807SRodney W. Grimes 
14924b88c807SRodney W. Grimes #ifdef mkinit
14934b88c807SRodney W. Grimes RESET {
14944b88c807SRodney W. Grimes 	tokpushback = 0;
14954b88c807SRodney W. Grimes 	checkkwd = 0;
14964b88c807SRodney W. Grimes }
14974b88c807SRodney W. Grimes #endif
14984b88c807SRodney W. Grimes 
14994b88c807SRodney W. Grimes /*
15004b88c807SRodney W. Grimes  * Returns true if the text contains nothing to expand (no dollar signs
15014b88c807SRodney W. Grimes  * or backquotes).
15024b88c807SRodney W. Grimes  */
15034b88c807SRodney W. Grimes 
15044b88c807SRodney W. Grimes STATIC int
15055134c3f7SWarner Losh noexpand(char *text)
15064b88c807SRodney W. Grimes {
15077920a31dSSteve Price 	char *p;
15087920a31dSSteve Price 	char c;
15094b88c807SRodney W. Grimes 
15104b88c807SRodney W. Grimes 	p = text;
15114b88c807SRodney W. Grimes 	while ((c = *p++) != '\0') {
15125557a02aSTor Egge 		if ( c == CTLQUOTEMARK)
15135557a02aSTor Egge 			continue;
15144b88c807SRodney W. Grimes 		if (c == CTLESC)
15154b88c807SRodney W. Grimes 			p++;
15160c4eeddaSTor Egge 		else if (BASESYNTAX[(int)c] == CCTL)
15174b88c807SRodney W. Grimes 			return 0;
15184b88c807SRodney W. Grimes 	}
15194b88c807SRodney W. Grimes 	return 1;
15204b88c807SRodney W. Grimes }
15214b88c807SRodney W. Grimes 
15224b88c807SRodney W. Grimes 
15234b88c807SRodney W. Grimes /*
15244b88c807SRodney W. Grimes  * Return true if the argument is a legal variable name (a letter or
15254b88c807SRodney W. Grimes  * underscore followed by zero or more letters, underscores, and digits).
15264b88c807SRodney W. Grimes  */
15274b88c807SRodney W. Grimes 
15284b88c807SRodney W. Grimes int
15295134c3f7SWarner Losh goodname(char *name)
15304b88c807SRodney W. Grimes {
15317920a31dSSteve Price 	char *p;
15324b88c807SRodney W. Grimes 
15334b88c807SRodney W. Grimes 	p = name;
15344b88c807SRodney W. Grimes 	if (! is_name(*p))
15354b88c807SRodney W. Grimes 		return 0;
15364b88c807SRodney W. Grimes 	while (*++p) {
15374b88c807SRodney W. Grimes 		if (! is_in_name(*p))
15384b88c807SRodney W. Grimes 			return 0;
15394b88c807SRodney W. Grimes 	}
15404b88c807SRodney W. Grimes 	return 1;
15414b88c807SRodney W. Grimes }
15424b88c807SRodney W. Grimes 
15434b88c807SRodney W. Grimes 
15444b88c807SRodney W. Grimes /*
15454b88c807SRodney W. Grimes  * Called when an unexpected token is read during the parse.  The argument
15464b88c807SRodney W. Grimes  * is the token that is expected, or -1 if more than one type of token can
15474b88c807SRodney W. Grimes  * occur at this point.
15484b88c807SRodney W. Grimes  */
15494b88c807SRodney W. Grimes 
15504b88c807SRodney W. Grimes STATIC void
15515134c3f7SWarner Losh synexpect(int token)
1552aa9caaf6SPeter Wemm {
15534b88c807SRodney W. Grimes 	char msg[64];
15544b88c807SRodney W. Grimes 
15554b88c807SRodney W. Grimes 	if (token >= 0) {
15564b88c807SRodney W. Grimes 		fmtstr(msg, 64, "%s unexpected (expecting %s)",
15574b88c807SRodney W. Grimes 			tokname[lasttoken], tokname[token]);
15584b88c807SRodney W. Grimes 	} else {
15594b88c807SRodney W. Grimes 		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
15604b88c807SRodney W. Grimes 	}
15614b88c807SRodney W. Grimes 	synerror(msg);
15624b88c807SRodney W. Grimes }
15634b88c807SRodney W. Grimes 
15644b88c807SRodney W. Grimes 
15654b88c807SRodney W. Grimes STATIC void
15665134c3f7SWarner Losh synerror(char *msg)
15674b88c807SRodney W. Grimes {
15684b88c807SRodney W. Grimes 	if (commandname)
15694b88c807SRodney W. Grimes 		outfmt(&errout, "%s: %d: ", commandname, startlinno);
15704b88c807SRodney W. Grimes 	outfmt(&errout, "Syntax error: %s\n", msg);
15714b88c807SRodney W. Grimes 	error((char *)NULL);
15724b88c807SRodney W. Grimes }
15734b88c807SRodney W. Grimes 
15744b88c807SRodney W. Grimes STATIC void
15755134c3f7SWarner Losh setprompt(int which)
15764b88c807SRodney W. Grimes {
15774b88c807SRodney W. Grimes 	whichprompt = which;
15784b88c807SRodney W. Grimes 
1579aa9caaf6SPeter Wemm #ifndef NO_HISTORY
15804b88c807SRodney W. Grimes 	if (!el)
1581aa9caaf6SPeter Wemm #endif
15824b88c807SRodney W. Grimes 		out2str(getprompt(NULL));
15834b88c807SRodney W. Grimes }
15844b88c807SRodney W. Grimes 
15854b88c807SRodney W. Grimes /*
15864b88c807SRodney W. Grimes  * called by editline -- any expansions to the prompt
15874b88c807SRodney W. Grimes  *    should be added here.
15884b88c807SRodney W. Grimes  */
15894b88c807SRodney W. Grimes char *
15905134c3f7SWarner Losh getprompt(void *unused __unused)
15914b88c807SRodney W. Grimes {
1592f0c73601SDavid E. O'Brien 	static char ps[PROMPTLEN];
1593f0c73601SDavid E. O'Brien 	char *fmt;
1594f0c73601SDavid E. O'Brien 	int i, j, trim;
1595f0c73601SDavid E. O'Brien 
1596f0c73601SDavid E. O'Brien 	/*
1597f0c73601SDavid E. O'Brien 	 * Select prompt format.
1598f0c73601SDavid E. O'Brien 	 */
15994b88c807SRodney W. Grimes 	switch (whichprompt) {
16004b88c807SRodney W. Grimes 	case 0:
1601f0c73601SDavid E. O'Brien 		fmt = "";
1602f0c73601SDavid E. O'Brien 		break;
16034b88c807SRodney W. Grimes 	case 1:
1604f0c73601SDavid E. O'Brien 		fmt = ps1val();
1605f0c73601SDavid E. O'Brien 		break;
16064b88c807SRodney W. Grimes 	case 2:
1607f0c73601SDavid E. O'Brien 		fmt = ps2val();
1608f0c73601SDavid E. O'Brien 		break;
16094b88c807SRodney W. Grimes 	default:
16104b88c807SRodney W. Grimes 		return "<internal prompt error>";
16114b88c807SRodney W. Grimes 	}
1612f0c73601SDavid E. O'Brien 
1613f0c73601SDavid E. O'Brien 	/*
1614f0c73601SDavid E. O'Brien 	 * Format prompt string.
1615f0c73601SDavid E. O'Brien 	 */
1616f0c73601SDavid E. O'Brien 	for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++)
1617f0c73601SDavid E. O'Brien 		if (*fmt == '\\')
1618f0c73601SDavid E. O'Brien 			switch (*++fmt) {
1619f0c73601SDavid E. O'Brien 
1620f0c73601SDavid E. O'Brien 				/*
1621f0c73601SDavid E. O'Brien 				 * Hostname.
1622f0c73601SDavid E. O'Brien 				 *
1623f0c73601SDavid E. O'Brien 				 * \h specifies just the local hostname,
1624f0c73601SDavid E. O'Brien 				 * \H specifies fully-qualified hostname.
1625f0c73601SDavid E. O'Brien 				 */
1626f0c73601SDavid E. O'Brien 			case 'h':
1627f0c73601SDavid E. O'Brien 			case 'H':
16288d999570SStefan Farfeleder 				ps[i] = '\0';
1629f0c73601SDavid E. O'Brien 				gethostname(&ps[i], PROMPTLEN - i);
1630f0c73601SDavid E. O'Brien 				/* Skip to end of hostname. */
1631f0c73601SDavid E. O'Brien 				trim = (*fmt == 'h') ? '.' : '\0';
1632f0c73601SDavid E. O'Brien 				while ((ps[i+1] != '\0') && (ps[i+1] != trim))
1633f0c73601SDavid E. O'Brien 					i++;
1634f0c73601SDavid E. O'Brien 				break;
1635f0c73601SDavid E. O'Brien 
1636f0c73601SDavid E. O'Brien 				/*
1637f0c73601SDavid E. O'Brien 				 * Working directory.
1638f0c73601SDavid E. O'Brien 				 *
1639f0c73601SDavid E. O'Brien 				 * \W specifies just the final component,
1640f0c73601SDavid E. O'Brien 				 * \w specifies the entire path.
1641f0c73601SDavid E. O'Brien 				 */
1642f0c73601SDavid E. O'Brien 			case 'W':
1643f0c73601SDavid E. O'Brien 			case 'w':
16448d999570SStefan Farfeleder 				ps[i] = '\0';
1645f0c73601SDavid E. O'Brien 				getcwd(&ps[i], PROMPTLEN - i);
1646f0c73601SDavid E. O'Brien 				if (*fmt == 'W') {
1647f0c73601SDavid E. O'Brien 					/* Final path component only. */
1648f0c73601SDavid E. O'Brien 					trim = 1;
1649f0c73601SDavid E. O'Brien 					for (j = i; ps[j] != '\0'; j++)
1650f0c73601SDavid E. O'Brien 					  if (ps[j] == '/')
1651f0c73601SDavid E. O'Brien 						trim = j + 1;
1652f0c73601SDavid E. O'Brien 					memmove(&ps[i], &ps[trim],
1653f0c73601SDavid E. O'Brien 					    j - trim + 1);
1654f0c73601SDavid E. O'Brien 				}
1655f0c73601SDavid E. O'Brien 				/* Skip to end of path. */
1656f0c73601SDavid E. O'Brien 				while (ps[i + 1] != '\0')
1657f0c73601SDavid E. O'Brien 					i++;
1658f0c73601SDavid E. O'Brien 				break;
1659f0c73601SDavid E. O'Brien 
1660f0c73601SDavid E. O'Brien 				/*
1661f0c73601SDavid E. O'Brien 				 * Superuser status.
1662f0c73601SDavid E. O'Brien 				 *
1663f0c73601SDavid E. O'Brien 				 * '$' for normal users, '#' for root.
1664f0c73601SDavid E. O'Brien 				 */
1665f0c73601SDavid E. O'Brien 			case '$':
1666f0c73601SDavid E. O'Brien 				ps[i] = (geteuid() != 0) ? '$' : '#';
1667f0c73601SDavid E. O'Brien 				break;
1668f0c73601SDavid E. O'Brien 
1669f0c73601SDavid E. O'Brien 				/*
1670f0c73601SDavid E. O'Brien 				 * A literal \.
1671f0c73601SDavid E. O'Brien 				 */
1672f0c73601SDavid E. O'Brien 			case '\\':
1673f0c73601SDavid E. O'Brien 				ps[i] = '\\';
1674f0c73601SDavid E. O'Brien 				break;
1675f0c73601SDavid E. O'Brien 
1676f0c73601SDavid E. O'Brien 				/*
1677f0c73601SDavid E. O'Brien 				 * Emit unrecognized formats verbatim.
1678f0c73601SDavid E. O'Brien 				 */
1679f0c73601SDavid E. O'Brien 			default:
1680f0c73601SDavid E. O'Brien 				ps[i++] = '\\';
1681f0c73601SDavid E. O'Brien 				ps[i] = *fmt;
1682f0c73601SDavid E. O'Brien 				break;
1683f0c73601SDavid E. O'Brien 			}
1684f0c73601SDavid E. O'Brien 		else
1685f0c73601SDavid E. O'Brien 			ps[i] = *fmt;
1686f0c73601SDavid E. O'Brien 	ps[i] = '\0';
1687f0c73601SDavid E. O'Brien 	return (ps);
16884b88c807SRodney W. Grimes }
1689