xref: /freebsd/bin/sh/parser.c (revision 4682f420f256110392b573eba39d7546a3c94b86)
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  * 3. All advertising materials mentioning features or use of this software
174b88c807SRodney W. Grimes  *    must display the following acknowledgement:
184b88c807SRodney W. Grimes  *	This product includes software developed by the University of
194b88c807SRodney W. Grimes  *	California, Berkeley and its contributors.
204b88c807SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
214b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
224b88c807SRodney W. Grimes  *    without specific prior written permission.
234b88c807SRodney W. Grimes  *
244b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
254b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
264b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
274b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
284b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
294b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
304b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
314b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
324b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
334b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
344b88c807SRodney W. Grimes  * SUCH DAMAGE.
354b88c807SRodney W. Grimes  */
364b88c807SRodney W. Grimes 
374b88c807SRodney W. Grimes #ifndef lint
383d7b5b93SPhilippe Charnier #if 0
393d7b5b93SPhilippe Charnier static char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
403d7b5b93SPhilippe Charnier #endif
413d7b5b93SPhilippe Charnier static const char rcsid[] =
422a456239SPeter Wemm   "$FreeBSD$";
434b88c807SRodney W. Grimes #endif /* not lint */
444b88c807SRodney W. Grimes 
45aa9caaf6SPeter Wemm #include <stdlib.h>
46aa9caaf6SPeter Wemm 
474b88c807SRodney W. Grimes #include "shell.h"
484b88c807SRodney W. Grimes #include "parser.h"
494b88c807SRodney W. Grimes #include "nodes.h"
504b88c807SRodney W. Grimes #include "expand.h"	/* defines rmescapes() */
514b88c807SRodney W. Grimes #include "redir.h"	/* defines copyfd() */
524b88c807SRodney W. Grimes #include "syntax.h"
534b88c807SRodney W. Grimes #include "options.h"
544b88c807SRodney W. Grimes #include "input.h"
554b88c807SRodney W. Grimes #include "output.h"
564b88c807SRodney W. Grimes #include "var.h"
574b88c807SRodney W. Grimes #include "error.h"
584b88c807SRodney W. Grimes #include "memalloc.h"
594b88c807SRodney W. Grimes #include "mystring.h"
604b88c807SRodney W. Grimes #include "alias.h"
61aa9caaf6SPeter Wemm #include "show.h"
62f01e3d0cSMartin Cracauer #include "eval.h"
63aa9caaf6SPeter Wemm #ifndef NO_HISTORY
644b88c807SRodney W. Grimes #include "myhistedit.h"
65aa9caaf6SPeter Wemm #endif
664b88c807SRodney W. Grimes 
674b88c807SRodney W. Grimes /*
684b88c807SRodney W. Grimes  * Shell command parser.
694b88c807SRodney W. Grimes  */
704b88c807SRodney W. Grimes 
714b88c807SRodney W. Grimes #define EOFMARKLEN 79
724b88c807SRodney W. Grimes 
734b88c807SRodney W. Grimes /* values returned by readtoken */
74aa9caaf6SPeter Wemm #include "token.h"
754b88c807SRodney W. Grimes 
764b88c807SRodney W. Grimes 
774b88c807SRodney W. Grimes 
784b88c807SRodney W. Grimes struct heredoc {
794b88c807SRodney W. Grimes 	struct heredoc *next;	/* next here document in list */
804b88c807SRodney W. Grimes 	union node *here;		/* redirection node */
814b88c807SRodney W. Grimes 	char *eofmark;		/* string indicating end of input */
824b88c807SRodney W. Grimes 	int striptabs;		/* if set, strip leading tabs */
834b88c807SRodney W. Grimes };
844b88c807SRodney W. Grimes 
854b88c807SRodney W. Grimes 
864b88c807SRodney W. Grimes 
874b88c807SRodney W. Grimes struct heredoc *heredoclist;	/* list of here documents to read */
884b88c807SRodney W. Grimes int parsebackquote;		/* nonzero if we are inside backquotes */
894b88c807SRodney W. Grimes int doprompt;			/* if set, prompt the user */
904b88c807SRodney W. Grimes int needprompt;			/* true if interactive and at start of line */
914b88c807SRodney W. Grimes int lasttoken;			/* last token read */
924b88c807SRodney W. Grimes MKINIT int tokpushback;		/* last token pushed back */
934b88c807SRodney W. Grimes char *wordtext;			/* text of last word returned by readtoken */
944b88c807SRodney W. Grimes MKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
954b88c807SRodney W. Grimes struct nodelist *backquotelist;
964b88c807SRodney W. Grimes union node *redirnode;
974b88c807SRodney W. Grimes struct heredoc *heredoc;
984b88c807SRodney W. Grimes int quoteflag;			/* set if (part of) last token was quoted */
994b88c807SRodney W. Grimes int startlinno;			/* line # where last token started */
1004b88c807SRodney W. Grimes 
1014417f629SPeter Wemm /* XXX When 'noaliases' is set to one, no alias expansion takes place. */
1024417f629SPeter Wemm static int noaliases = 0;
1034b88c807SRodney W. Grimes 
1044b88c807SRodney W. Grimes #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
1054b88c807SRodney W. Grimes #ifdef GDB_HACK
1064b88c807SRodney W. Grimes static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
1074b88c807SRodney W. Grimes static const char types[] = "}-+?=";
1084b88c807SRodney W. Grimes #endif
1094b88c807SRodney W. Grimes 
1104b88c807SRodney W. Grimes 
1114b88c807SRodney W. Grimes STATIC union node *list __P((int));
1124b88c807SRodney W. Grimes STATIC union node *andor __P((void));
1134b88c807SRodney W. Grimes STATIC union node *pipeline __P((void));
1144b88c807SRodney W. Grimes STATIC union node *command __P((void));
1154b88c807SRodney W. Grimes STATIC union node *simplecmd __P((union node **, union node *));
116aa9caaf6SPeter Wemm STATIC union node *makename __P((void));
1174b88c807SRodney W. Grimes STATIC void parsefname __P((void));
1184b88c807SRodney W. Grimes STATIC void parseheredoc __P((void));
119aa9caaf6SPeter Wemm STATIC int peektoken __P((void));
1204b88c807SRodney W. Grimes STATIC int readtoken __P((void));
121aa9caaf6SPeter Wemm STATIC int xxreadtoken __P((void));
1224b88c807SRodney W. Grimes STATIC int readtoken1 __P((int, char const *, char *, int));
1234b88c807SRodney W. Grimes STATIC int noexpand __P((char *));
1244b88c807SRodney W. Grimes STATIC void synexpect __P((int));
1254b88c807SRodney W. Grimes STATIC void synerror __P((char *));
1264b88c807SRodney W. Grimes STATIC void setprompt __P((int));
1274b88c807SRodney W. Grimes 
128aa9caaf6SPeter Wemm 
1294b88c807SRodney W. Grimes /*
1304b88c807SRodney W. Grimes  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
1314b88c807SRodney W. Grimes  * valid parse tree indicating a blank line.)
1324b88c807SRodney W. Grimes  */
1334b88c807SRodney W. Grimes 
1344b88c807SRodney W. Grimes union node *
135aa9caaf6SPeter Wemm parsecmd(interact)
136aa9caaf6SPeter Wemm 	int interact;
137aa9caaf6SPeter Wemm {
1384b88c807SRodney W. Grimes 	int t;
1394b88c807SRodney W. Grimes 
14098e05fd3SMartin Cracauer 	tokpushback = 0;
1414b88c807SRodney W. Grimes 	doprompt = interact;
1424b88c807SRodney W. Grimes 	if (doprompt)
1434b88c807SRodney W. Grimes 		setprompt(1);
1444b88c807SRodney W. Grimes 	else
1454b88c807SRodney W. Grimes 		setprompt(0);
1464b88c807SRodney W. Grimes 	needprompt = 0;
1474b88c807SRodney W. Grimes 	t = readtoken();
1484b88c807SRodney W. Grimes 	if (t == TEOF)
1494b88c807SRodney W. Grimes 		return NEOF;
1504b88c807SRodney W. Grimes 	if (t == TNL)
1514b88c807SRodney W. Grimes 		return NULL;
1524b88c807SRodney W. Grimes 	tokpushback++;
1534b88c807SRodney W. Grimes 	return list(1);
1544b88c807SRodney W. Grimes }
1554b88c807SRodney W. Grimes 
1564b88c807SRodney W. Grimes 
1574b88c807SRodney W. Grimes STATIC union node *
158aa9caaf6SPeter Wemm list(nlflag)
159aa9caaf6SPeter Wemm 	int nlflag;
160aa9caaf6SPeter Wemm {
1614b88c807SRodney W. Grimes 	union node *n1, *n2, *n3;
162aa9caaf6SPeter Wemm 	int tok;
1634b88c807SRodney W. Grimes 
1644b88c807SRodney W. Grimes 	checkkwd = 2;
1654b88c807SRodney W. Grimes 	if (nlflag == 0 && tokendlist[peektoken()])
1664b88c807SRodney W. Grimes 		return NULL;
167aa9caaf6SPeter Wemm 	n1 = NULL;
1684b88c807SRodney W. Grimes 	for (;;) {
1694b88c807SRodney W. Grimes 		n2 = andor();
170aa9caaf6SPeter Wemm 		tok = readtoken();
171aa9caaf6SPeter Wemm 		if (tok == TBACKGND) {
172aa9caaf6SPeter Wemm 			if (n2->type == NCMD || n2->type == NPIPE) {
173aa9caaf6SPeter Wemm 				n2->ncmd.backgnd = 1;
174aa9caaf6SPeter Wemm 			} else if (n2->type == NREDIR) {
175aa9caaf6SPeter Wemm 				n2->type = NBACKGND;
176aa9caaf6SPeter Wemm 			} else {
177aa9caaf6SPeter Wemm 				n3 = (union node *)stalloc(sizeof (struct nredir));
178aa9caaf6SPeter Wemm 				n3->type = NBACKGND;
179aa9caaf6SPeter Wemm 				n3->nredir.n = n2;
180aa9caaf6SPeter Wemm 				n3->nredir.redirect = NULL;
181aa9caaf6SPeter Wemm 				n2 = n3;
182aa9caaf6SPeter Wemm 			}
183aa9caaf6SPeter Wemm 		}
184aa9caaf6SPeter Wemm 		if (n1 == NULL) {
185aa9caaf6SPeter Wemm 			n1 = n2;
186aa9caaf6SPeter Wemm 		}
187aa9caaf6SPeter Wemm 		else {
1884b88c807SRodney W. Grimes 			n3 = (union node *)stalloc(sizeof (struct nbinary));
1894b88c807SRodney W. Grimes 			n3->type = NSEMI;
1904b88c807SRodney W. Grimes 			n3->nbinary.ch1 = n1;
1914b88c807SRodney W. Grimes 			n3->nbinary.ch2 = n2;
1924b88c807SRodney W. Grimes 			n1 = n3;
193aa9caaf6SPeter Wemm 		}
194aa9caaf6SPeter Wemm 		switch (tok) {
195aa9caaf6SPeter Wemm 		case TBACKGND:
196aa9caaf6SPeter Wemm 		case TSEMI:
197aa9caaf6SPeter Wemm 			tok = readtoken();
198aa9caaf6SPeter Wemm 			/* fall through */
199aa9caaf6SPeter Wemm 		case TNL:
200aa9caaf6SPeter Wemm 			if (tok == TNL) {
201aa9caaf6SPeter Wemm 				parseheredoc();
202aa9caaf6SPeter Wemm 				if (nlflag)
203aa9caaf6SPeter Wemm 					return n1;
204aa9caaf6SPeter Wemm 			} else {
205aa9caaf6SPeter Wemm 				tokpushback++;
206aa9caaf6SPeter Wemm 			}
207aa9caaf6SPeter Wemm 			checkkwd = 2;
208aa9caaf6SPeter Wemm 			if (tokendlist[peektoken()])
209aa9caaf6SPeter Wemm 				return n1;
2104b88c807SRodney W. Grimes 			break;
2114b88c807SRodney W. Grimes 		case TEOF:
2124b88c807SRodney W. Grimes 			if (heredoclist)
2134b88c807SRodney W. Grimes 				parseheredoc();
2144b88c807SRodney W. Grimes 			else
2154b88c807SRodney W. Grimes 				pungetc();		/* push back EOF on input */
2164b88c807SRodney W. Grimes 			return n1;
2174b88c807SRodney W. Grimes 		default:
2184b88c807SRodney W. Grimes 			if (nlflag)
2194b88c807SRodney W. Grimes 				synexpect(-1);
2204b88c807SRodney W. Grimes 			tokpushback++;
2214b88c807SRodney W. Grimes 			return n1;
2224b88c807SRodney W. Grimes 		}
2234b88c807SRodney W. Grimes 	}
2244b88c807SRodney W. Grimes }
2254b88c807SRodney W. Grimes 
2264b88c807SRodney W. Grimes 
2274b88c807SRodney W. Grimes 
2284b88c807SRodney W. Grimes STATIC union node *
2294b88c807SRodney W. Grimes andor() {
2304b88c807SRodney W. Grimes 	union node *n1, *n2, *n3;
2314b88c807SRodney W. Grimes 	int t;
2324b88c807SRodney W. Grimes 
2334b88c807SRodney W. Grimes 	n1 = pipeline();
2344b88c807SRodney W. Grimes 	for (;;) {
2354b88c807SRodney W. Grimes 		if ((t = readtoken()) == TAND) {
2364b88c807SRodney W. Grimes 			t = NAND;
2374b88c807SRodney W. Grimes 		} else if (t == TOR) {
2384b88c807SRodney W. Grimes 			t = NOR;
2394b88c807SRodney W. Grimes 		} else {
2404b88c807SRodney W. Grimes 			tokpushback++;
2414b88c807SRodney W. Grimes 			return n1;
2424b88c807SRodney W. Grimes 		}
2434b88c807SRodney W. Grimes 		n2 = pipeline();
2444b88c807SRodney W. Grimes 		n3 = (union node *)stalloc(sizeof (struct nbinary));
2454b88c807SRodney W. Grimes 		n3->type = t;
2464b88c807SRodney W. Grimes 		n3->nbinary.ch1 = n1;
2474b88c807SRodney W. Grimes 		n3->nbinary.ch2 = n2;
2484b88c807SRodney W. Grimes 		n1 = n3;
2494b88c807SRodney W. Grimes 	}
2504b88c807SRodney W. Grimes }
2514b88c807SRodney W. Grimes 
2524b88c807SRodney W. Grimes 
2534b88c807SRodney W. Grimes 
2544b88c807SRodney W. Grimes STATIC union node *
2554b88c807SRodney W. Grimes pipeline() {
2567920a31dSSteve Price 	union node *n1, *pipenode, *notnode;
2574b88c807SRodney W. Grimes 	struct nodelist *lp, *prev;
2587920a31dSSteve Price 	int negate = 0;
2594b88c807SRodney W. Grimes 
2604b88c807SRodney W. Grimes 	TRACE(("pipeline: entered\n"));
2617920a31dSSteve Price 	while (readtoken() == TNOT) {
2627920a31dSSteve Price 		TRACE(("pipeline: TNOT recognized\n"));
2637920a31dSSteve Price 		negate = !negate;
2647920a31dSSteve Price 	}
2657920a31dSSteve Price 	tokpushback++;
2664b88c807SRodney W. Grimes 	n1 = command();
2674b88c807SRodney W. Grimes 	if (readtoken() == TPIPE) {
2684b88c807SRodney W. Grimes 		pipenode = (union node *)stalloc(sizeof (struct npipe));
2694b88c807SRodney W. Grimes 		pipenode->type = NPIPE;
2704b88c807SRodney W. Grimes 		pipenode->npipe.backgnd = 0;
2714b88c807SRodney W. Grimes 		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
2724b88c807SRodney W. Grimes 		pipenode->npipe.cmdlist = lp;
2734b88c807SRodney W. Grimes 		lp->n = n1;
2744b88c807SRodney W. Grimes 		do {
2754b88c807SRodney W. Grimes 			prev = lp;
2764b88c807SRodney W. Grimes 			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
2774b88c807SRodney W. Grimes 			lp->n = command();
2784b88c807SRodney W. Grimes 			prev->next = lp;
2794b88c807SRodney W. Grimes 		} while (readtoken() == TPIPE);
2804b88c807SRodney W. Grimes 		lp->next = NULL;
2814b88c807SRodney W. Grimes 		n1 = pipenode;
2824b88c807SRodney W. Grimes 	}
2834b88c807SRodney W. Grimes 	tokpushback++;
2847920a31dSSteve Price 	if (negate) {
2857920a31dSSteve Price 		notnode = (union node *)stalloc(sizeof(struct nnot));
2867920a31dSSteve Price 		notnode->type = NNOT;
2877920a31dSSteve Price 		notnode->nnot.com = n1;
2887920a31dSSteve Price 		n1 = notnode;
2897920a31dSSteve Price 	}
2904b88c807SRodney W. Grimes 	return n1;
2914b88c807SRodney W. Grimes }
2924b88c807SRodney W. Grimes 
2934b88c807SRodney W. Grimes 
2944b88c807SRodney W. Grimes 
2954b88c807SRodney W. Grimes STATIC union node *
2964b88c807SRodney W. Grimes command() {
2974b88c807SRodney W. Grimes 	union node *n1, *n2;
2984b88c807SRodney W. Grimes 	union node *ap, **app;
2994b88c807SRodney W. Grimes 	union node *cp, **cpp;
3004b88c807SRodney W. Grimes 	union node *redir, **rpp;
3017920a31dSSteve Price 	int t;
3024b88c807SRodney W. Grimes 
3034b88c807SRodney W. Grimes 	checkkwd = 2;
304aa9caaf6SPeter Wemm 	redir = NULL;
305aa9caaf6SPeter Wemm 	n1 = NULL;
3064b88c807SRodney W. Grimes 	rpp = &redir;
307ab0a2172SSteve Price 
3084b88c807SRodney W. Grimes 	/* Check for redirection which may precede command */
3094b88c807SRodney W. Grimes 	while (readtoken() == TREDIR) {
3104b88c807SRodney W. Grimes 		*rpp = n2 = redirnode;
3114b88c807SRodney W. Grimes 		rpp = &n2->nfile.next;
3124b88c807SRodney W. Grimes 		parsefname();
3134b88c807SRodney W. Grimes 	}
3144b88c807SRodney W. Grimes 	tokpushback++;
3154b88c807SRodney W. Grimes 
3164b88c807SRodney W. Grimes 	switch (readtoken()) {
3174b88c807SRodney W. Grimes 	case TIF:
3184b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nif));
3194b88c807SRodney W. Grimes 		n1->type = NIF;
3204b88c807SRodney W. Grimes 		n1->nif.test = list(0);
3214b88c807SRodney W. Grimes 		if (readtoken() != TTHEN)
3224b88c807SRodney W. Grimes 			synexpect(TTHEN);
3234b88c807SRodney W. Grimes 		n1->nif.ifpart = list(0);
3244b88c807SRodney W. Grimes 		n2 = n1;
3254b88c807SRodney W. Grimes 		while (readtoken() == TELIF) {
3264b88c807SRodney W. Grimes 			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
3274b88c807SRodney W. Grimes 			n2 = n2->nif.elsepart;
3284b88c807SRodney W. Grimes 			n2->type = NIF;
3294b88c807SRodney W. Grimes 			n2->nif.test = list(0);
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;
3494b88c807SRodney W. Grimes 		n1->nbinary.ch1 = list(0);
3504b88c807SRodney W. Grimes 		if ((got=readtoken()) != TDO) {
3514b88c807SRodney W. Grimes TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
3524b88c807SRodney W. Grimes 			synexpect(TDO);
3534b88c807SRodney W. Grimes 		}
3544b88c807SRodney W. Grimes 		n1->nbinary.ch2 = list(0);
3554b88c807SRodney W. Grimes 		if (readtoken() != TDONE)
3564b88c807SRodney W. Grimes 			synexpect(TDONE);
3574b88c807SRodney W. Grimes 		checkkwd = 1;
3584b88c807SRodney W. Grimes 		break;
3594b88c807SRodney W. Grimes 	}
3604b88c807SRodney W. Grimes 	case TFOR:
3614b88c807SRodney W. Grimes 		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
3624b88c807SRodney W. Grimes 			synerror("Bad for loop variable");
3634b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nfor));
3644b88c807SRodney W. Grimes 		n1->type = NFOR;
3654b88c807SRodney W. Grimes 		n1->nfor.var = wordtext;
3664b88c807SRodney W. Grimes 		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
3674b88c807SRodney W. Grimes 			app = &ap;
3684b88c807SRodney W. Grimes 			while (readtoken() == TWORD) {
3694b88c807SRodney W. Grimes 				n2 = (union node *)stalloc(sizeof (struct narg));
3704b88c807SRodney W. Grimes 				n2->type = NARG;
3714b88c807SRodney W. Grimes 				n2->narg.text = wordtext;
3724b88c807SRodney W. Grimes 				n2->narg.backquote = backquotelist;
3734b88c807SRodney W. Grimes 				*app = n2;
3744b88c807SRodney W. Grimes 				app = &n2->narg.next;
3754b88c807SRodney W. Grimes 			}
3764b88c807SRodney W. Grimes 			*app = NULL;
3774b88c807SRodney W. Grimes 			n1->nfor.args = ap;
3784b88c807SRodney W. Grimes 			if (lasttoken != TNL && lasttoken != TSEMI)
3794b88c807SRodney W. Grimes 				synexpect(-1);
3804b88c807SRodney W. Grimes 		} else {
3814b88c807SRodney W. Grimes #ifndef GDB_HACK
3824b88c807SRodney W. Grimes 			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
3834b88c807SRodney W. Grimes 								   '@', '=', '\0'};
3844b88c807SRodney W. Grimes #endif
3854b88c807SRodney W. Grimes 			n2 = (union node *)stalloc(sizeof (struct narg));
3864b88c807SRodney W. Grimes 			n2->type = NARG;
3874b88c807SRodney W. Grimes 			n2->narg.text = (char *)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();
426650488feSSean Eric Fagan 		do {
4274b88c807SRodney W. Grimes 			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
4284b88c807SRodney W. Grimes 			cp->type = NCLIST;
4294b88c807SRodney W. Grimes 			app = &cp->nclist.pattern;
4304b88c807SRodney W. Grimes 			for (;;) {
4314b88c807SRodney W. Grimes 				*app = ap = (union node *)stalloc(sizeof (struct narg));
4324b88c807SRodney W. Grimes 				ap->type = NARG;
4334b88c807SRodney W. Grimes 				ap->narg.text = wordtext;
4344b88c807SRodney W. Grimes 				ap->narg.backquote = backquotelist;
435650488feSSean Eric Fagan 				if (checkkwd = 2, readtoken() != TPIPE)
4364b88c807SRodney W. Grimes 					break;
4374b88c807SRodney W. Grimes 				app = &ap->narg.next;
438650488feSSean Eric Fagan 				readtoken();
4394b88c807SRodney W. Grimes 			}
4404b88c807SRodney W. Grimes 			ap->narg.next = NULL;
4414b88c807SRodney W. Grimes 			if (lasttoken != TRP)
4424417f629SPeter Wemm 				noaliases = 0, synexpect(TRP);
4434b88c807SRodney W. Grimes 			cp->nclist.body = list(0);
444650488feSSean Eric Fagan 
445650488feSSean Eric Fagan 			checkkwd = 2;
446650488feSSean Eric Fagan 			if ((t = readtoken()) != TESAC) {
447650488feSSean Eric Fagan 				if (t != TENDCASE)
4484417f629SPeter Wemm 					noaliases = 0, synexpect(TENDCASE);
449650488feSSean Eric Fagan 				else
450650488feSSean Eric Fagan 					checkkwd = 2, readtoken();
4514b88c807SRodney W. Grimes 			}
452650488feSSean Eric Fagan 			cpp = &cp->nclist.next;
453650488feSSean Eric Fagan 		} while(lasttoken != TESAC);
4544417f629SPeter Wemm 		noaliases = 0;	/* reset alias expansion */
4554b88c807SRodney W. Grimes 		*cpp = NULL;
4564b88c807SRodney W. Grimes 		checkkwd = 1;
4574b88c807SRodney W. Grimes 		break;
4584b88c807SRodney W. Grimes 	case TLP:
4594b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nredir));
4604b88c807SRodney W. Grimes 		n1->type = NSUBSHELL;
4614b88c807SRodney W. Grimes 		n1->nredir.n = list(0);
4624b88c807SRodney W. Grimes 		n1->nredir.redirect = NULL;
4634b88c807SRodney W. Grimes 		if (readtoken() != TRP)
4644b88c807SRodney W. Grimes 			synexpect(TRP);
4654b88c807SRodney W. Grimes 		checkkwd = 1;
4664b88c807SRodney W. Grimes 		break;
4674b88c807SRodney W. Grimes 	case TBEGIN:
4684b88c807SRodney W. Grimes 		n1 = list(0);
4694b88c807SRodney W. Grimes 		if (readtoken() != TEND)
4704b88c807SRodney W. Grimes 			synexpect(TEND);
4714b88c807SRodney W. Grimes 		checkkwd = 1;
4724b88c807SRodney W. Grimes 		break;
4734b88c807SRodney W. Grimes 	/* Handle an empty command like other simple commands.  */
474248ffae5SJoerg Wunsch 	case TSEMI:
475aa9caaf6SPeter Wemm 		/*
476aa9caaf6SPeter Wemm 		 * An empty command before a ; doesn't make much sense, and
477aa9caaf6SPeter Wemm 		 * should certainly be disallowed in the case of `if ;'.
478aa9caaf6SPeter Wemm 		 */
479aa9caaf6SPeter Wemm 		if (!redir)
480aa9caaf6SPeter Wemm 			synexpect(-1);
481ab0a2172SSteve Price 	case TAND:
482ab0a2172SSteve Price 	case TOR:
483aa9caaf6SPeter Wemm 	case TNL:
484248ffae5SJoerg Wunsch 	case TEOF:
4854b88c807SRodney W. Grimes 	case TWORD:
486aa9caaf6SPeter Wemm 	case TRP:
4874b88c807SRodney W. Grimes 		tokpushback++;
4887920a31dSSteve Price 		return simplecmd(rpp, redir);
4894b88c807SRodney W. Grimes 	default:
4904b88c807SRodney W. Grimes 		synexpect(-1);
4914b88c807SRodney W. Grimes 	}
4924b88c807SRodney W. Grimes 
4934b88c807SRodney W. Grimes 	/* Now check for redirection which may follow command */
4944b88c807SRodney W. Grimes 	while (readtoken() == TREDIR) {
4954b88c807SRodney W. Grimes 		*rpp = n2 = redirnode;
4964b88c807SRodney W. Grimes 		rpp = &n2->nfile.next;
4974b88c807SRodney W. Grimes 		parsefname();
4984b88c807SRodney W. Grimes 	}
4994b88c807SRodney W. Grimes 	tokpushback++;
5004b88c807SRodney W. Grimes 	*rpp = NULL;
5014b88c807SRodney W. Grimes 	if (redir) {
5024b88c807SRodney W. Grimes 		if (n1->type != NSUBSHELL) {
5034b88c807SRodney W. Grimes 			n2 = (union node *)stalloc(sizeof (struct nredir));
5044b88c807SRodney W. Grimes 			n2->type = NREDIR;
5054b88c807SRodney W. Grimes 			n2->nredir.n = n1;
5064b88c807SRodney W. Grimes 			n1 = n2;
5074b88c807SRodney W. Grimes 		}
5084b88c807SRodney W. Grimes 		n1->nredir.redirect = redir;
5094b88c807SRodney W. Grimes 	}
5104b88c807SRodney W. Grimes 	return n1;
5114b88c807SRodney W. Grimes }
5124b88c807SRodney W. Grimes 
5134b88c807SRodney W. Grimes 
5144b88c807SRodney W. Grimes STATIC union node *
5154b88c807SRodney W. Grimes simplecmd(rpp, redir)
5164b88c807SRodney W. Grimes 	union node **rpp, *redir;
5174b88c807SRodney W. Grimes 	{
5184b88c807SRodney W. Grimes 	union node *args, **app;
5194b88c807SRodney W. Grimes 	union node **orig_rpp = rpp;
5207920a31dSSteve Price 	union node *n = NULL;
5214b88c807SRodney W. Grimes 
5224b88c807SRodney W. Grimes 	/* If we don't have any redirections already, then we must reset */
5234b88c807SRodney W. Grimes 	/* rpp to be the address of the local redir variable.  */
5244b88c807SRodney W. Grimes 	if (redir == 0)
5254b88c807SRodney W. Grimes 		rpp = &redir;
5264b88c807SRodney W. Grimes 
5274b88c807SRodney W. Grimes 	args = NULL;
5284b88c807SRodney W. Grimes 	app = &args;
5294b88c807SRodney W. Grimes 	/*
5304b88c807SRodney W. Grimes 	 * We save the incoming value, because we need this for shell
5314b88c807SRodney W. Grimes 	 * functions.  There can not be a redirect or an argument between
5324b88c807SRodney W. Grimes 	 * the function name and the open parenthesis.
5334b88c807SRodney W. Grimes 	 */
5344b88c807SRodney W. Grimes 	orig_rpp = rpp;
5354b88c807SRodney W. Grimes 
5364b88c807SRodney W. Grimes 	for (;;) {
5374b88c807SRodney W. Grimes 		if (readtoken() == TWORD) {
5384b88c807SRodney W. Grimes 			n = (union node *)stalloc(sizeof (struct narg));
5394b88c807SRodney W. Grimes 			n->type = NARG;
5404b88c807SRodney W. Grimes 			n->narg.text = wordtext;
5414b88c807SRodney W. Grimes 			n->narg.backquote = backquotelist;
5424b88c807SRodney W. Grimes 			*app = n;
5434b88c807SRodney W. Grimes 			app = &n->narg.next;
5444b88c807SRodney W. Grimes 		} else if (lasttoken == TREDIR) {
5454b88c807SRodney W. Grimes 			*rpp = n = redirnode;
5464b88c807SRodney W. Grimes 			rpp = &n->nfile.next;
5474b88c807SRodney W. Grimes 			parsefname();	/* read name of redirection file */
5484b88c807SRodney W. Grimes 		} else if (lasttoken == TLP && app == &args->narg.next
5494b88c807SRodney W. Grimes 					    && rpp == orig_rpp) {
5504b88c807SRodney W. Grimes 			/* We have a function */
5514b88c807SRodney W. Grimes 			if (readtoken() != TRP)
5524b88c807SRodney W. Grimes 				synexpect(TRP);
5534b88c807SRodney W. Grimes #ifdef notdef
5544b88c807SRodney W. Grimes 			if (! goodname(n->narg.text))
5554b88c807SRodney W. Grimes 				synerror("Bad function name");
5564b88c807SRodney W. Grimes #endif
5574b88c807SRodney W. Grimes 			n->type = NDEFUN;
5584b88c807SRodney W. Grimes 			n->narg.next = command();
5597920a31dSSteve Price 			return n;
5604b88c807SRodney W. Grimes 		} else {
5614b88c807SRodney W. Grimes 			tokpushback++;
5624b88c807SRodney W. Grimes 			break;
5634b88c807SRodney W. Grimes 		}
5644b88c807SRodney W. Grimes 	}
5654b88c807SRodney W. Grimes 	*app = NULL;
5664b88c807SRodney W. Grimes 	*rpp = NULL;
5674b88c807SRodney W. Grimes 	n = (union node *)stalloc(sizeof (struct ncmd));
5684b88c807SRodney W. Grimes 	n->type = NCMD;
5694b88c807SRodney W. Grimes 	n->ncmd.backgnd = 0;
5704b88c807SRodney W. Grimes 	n->ncmd.args = args;
5714b88c807SRodney W. Grimes 	n->ncmd.redirect = redir;
5724b88c807SRodney W. Grimes 	return n;
5734b88c807SRodney W. Grimes }
5744b88c807SRodney W. Grimes 
575aa9caaf6SPeter Wemm STATIC union node *
576aa9caaf6SPeter Wemm makename() {
577aa9caaf6SPeter Wemm 	union node *n;
578aa9caaf6SPeter Wemm 
579aa9caaf6SPeter Wemm 	n = (union node *)stalloc(sizeof (struct narg));
580aa9caaf6SPeter Wemm 	n->type = NARG;
581aa9caaf6SPeter Wemm 	n->narg.next = NULL;
582aa9caaf6SPeter Wemm 	n->narg.text = wordtext;
583aa9caaf6SPeter Wemm 	n->narg.backquote = backquotelist;
584aa9caaf6SPeter Wemm 	return n;
585aa9caaf6SPeter Wemm }
586aa9caaf6SPeter Wemm 
587aa9caaf6SPeter Wemm void fixredir(n, text, err)
588aa9caaf6SPeter Wemm 	union node *n;
589aa9caaf6SPeter Wemm 	const char *text;
590aa9caaf6SPeter Wemm 	int err;
591aa9caaf6SPeter Wemm 	{
592aa9caaf6SPeter Wemm 	TRACE(("Fix redir %s %d\n", text, err));
593aa9caaf6SPeter Wemm 	if (!err)
594aa9caaf6SPeter Wemm 		n->ndup.vname = NULL;
595aa9caaf6SPeter Wemm 
596aa9caaf6SPeter Wemm 	if (is_digit(text[0]) && text[1] == '\0')
597aa9caaf6SPeter Wemm 		n->ndup.dupfd = digit_val(text[0]);
598aa9caaf6SPeter Wemm 	else if (text[0] == '-' && text[1] == '\0')
599aa9caaf6SPeter Wemm 		n->ndup.dupfd = -1;
600aa9caaf6SPeter Wemm 	else {
601aa9caaf6SPeter Wemm 
602aa9caaf6SPeter Wemm 		if (err)
603aa9caaf6SPeter Wemm 			synerror("Bad fd number");
604aa9caaf6SPeter Wemm 		else
605aa9caaf6SPeter Wemm 			n->ndup.vname = makename();
606aa9caaf6SPeter Wemm 	}
607aa9caaf6SPeter Wemm }
608aa9caaf6SPeter Wemm 
6094b88c807SRodney W. Grimes 
6104b88c807SRodney W. Grimes STATIC void
6114b88c807SRodney W. Grimes parsefname() {
6124b88c807SRodney W. Grimes 	union node *n = redirnode;
6134b88c807SRodney W. Grimes 
6144b88c807SRodney W. Grimes 	if (readtoken() != TWORD)
6154b88c807SRodney W. Grimes 		synexpect(-1);
6164b88c807SRodney W. Grimes 	if (n->type == NHERE) {
6174b88c807SRodney W. Grimes 		struct heredoc *here = heredoc;
6184b88c807SRodney W. Grimes 		struct heredoc *p;
6194b88c807SRodney W. Grimes 		int i;
6204b88c807SRodney W. Grimes 
6214b88c807SRodney W. Grimes 		if (quoteflag == 0)
6224b88c807SRodney W. Grimes 			n->type = NXHERE;
6234b88c807SRodney W. Grimes 		TRACE(("Here document %d\n", n->type));
6244b88c807SRodney W. Grimes 		if (here->striptabs) {
6254b88c807SRodney W. Grimes 			while (*wordtext == '\t')
6264b88c807SRodney W. Grimes 				wordtext++;
6274b88c807SRodney W. Grimes 		}
6284b88c807SRodney W. Grimes 		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
6294b88c807SRodney W. Grimes 			synerror("Illegal eof marker for << redirection");
6304b88c807SRodney W. Grimes 		rmescapes(wordtext);
6314b88c807SRodney W. Grimes 		here->eofmark = wordtext;
6324b88c807SRodney W. Grimes 		here->next = NULL;
6334b88c807SRodney W. Grimes 		if (heredoclist == NULL)
6344b88c807SRodney W. Grimes 			heredoclist = here;
6354b88c807SRodney W. Grimes 		else {
6364b88c807SRodney W. Grimes 			for (p = heredoclist ; p->next ; p = p->next);
6374b88c807SRodney W. Grimes 			p->next = here;
6384b88c807SRodney W. Grimes 		}
6394b88c807SRodney W. Grimes 	} else if (n->type == NTOFD || n->type == NFROMFD) {
640aa9caaf6SPeter Wemm 		fixredir(n, wordtext, 0);
6414b88c807SRodney W. Grimes 	} else {
642aa9caaf6SPeter Wemm 		n->nfile.fname = makename();
6434b88c807SRodney W. Grimes 	}
6444b88c807SRodney W. Grimes }
6454b88c807SRodney W. Grimes 
6464b88c807SRodney W. Grimes 
6474b88c807SRodney W. Grimes /*
6484b88c807SRodney W. Grimes  * Input any here documents.
6494b88c807SRodney W. Grimes  */
6504b88c807SRodney W. Grimes 
6514b88c807SRodney W. Grimes STATIC void
6524b88c807SRodney W. Grimes parseheredoc() {
6534b88c807SRodney W. Grimes 	struct heredoc *here;
6544b88c807SRodney W. Grimes 	union node *n;
6554b88c807SRodney W. Grimes 
6564b88c807SRodney W. Grimes 	while (heredoclist) {
6574b88c807SRodney W. Grimes 		here = heredoclist;
6584b88c807SRodney W. Grimes 		heredoclist = here->next;
6594b88c807SRodney W. Grimes 		if (needprompt) {
6604b88c807SRodney W. Grimes 			setprompt(2);
6614b88c807SRodney W. Grimes 			needprompt = 0;
6624b88c807SRodney W. Grimes 		}
6634b88c807SRodney W. Grimes 		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
6644b88c807SRodney W. Grimes 				here->eofmark, here->striptabs);
6654b88c807SRodney W. Grimes 		n = (union node *)stalloc(sizeof (struct narg));
6664b88c807SRodney W. Grimes 		n->narg.type = NARG;
6674b88c807SRodney W. Grimes 		n->narg.next = NULL;
6684b88c807SRodney W. Grimes 		n->narg.text = wordtext;
6694b88c807SRodney W. Grimes 		n->narg.backquote = backquotelist;
6704b88c807SRodney W. Grimes 		here->here->nhere.doc = n;
6714b88c807SRodney W. Grimes 	}
6724b88c807SRodney W. Grimes }
6734b88c807SRodney W. Grimes 
6744b88c807SRodney W. Grimes STATIC int
6754b88c807SRodney W. Grimes peektoken() {
6764b88c807SRodney W. Grimes 	int t;
6774b88c807SRodney W. Grimes 
6784b88c807SRodney W. Grimes 	t = readtoken();
6794b88c807SRodney W. Grimes 	tokpushback++;
6804b88c807SRodney W. Grimes 	return (t);
6814b88c807SRodney W. Grimes }
6824b88c807SRodney W. Grimes 
6834b88c807SRodney W. Grimes STATIC int
6844b88c807SRodney W. Grimes readtoken() {
6854b88c807SRodney W. Grimes 	int t;
6864b88c807SRodney W. Grimes 	int savecheckkwd = checkkwd;
6874b88c807SRodney W. Grimes 	struct alias *ap;
6884b88c807SRodney W. Grimes #ifdef DEBUG
6894b88c807SRodney W. Grimes 	int alreadyseen = tokpushback;
6904b88c807SRodney W. Grimes #endif
6914b88c807SRodney W. Grimes 
6924b88c807SRodney W. Grimes 	top:
6934b88c807SRodney W. Grimes 	t = xxreadtoken();
6944b88c807SRodney W. Grimes 
6954b88c807SRodney W. Grimes 	if (checkkwd) {
6964b88c807SRodney W. Grimes 		/*
6974b88c807SRodney W. Grimes 		 * eat newlines
6984b88c807SRodney W. Grimes 		 */
6994b88c807SRodney W. Grimes 		if (checkkwd == 2) {
7004b88c807SRodney W. Grimes 			checkkwd = 0;
7014b88c807SRodney W. Grimes 			while (t == TNL) {
7024b88c807SRodney W. Grimes 				parseheredoc();
7034b88c807SRodney W. Grimes 				t = xxreadtoken();
7044b88c807SRodney W. Grimes 			}
7054b88c807SRodney W. Grimes 		} else
7064b88c807SRodney W. Grimes 			checkkwd = 0;
7074b88c807SRodney W. Grimes 		/*
7084b88c807SRodney W. Grimes 		 * check for keywords and aliases
7094b88c807SRodney W. Grimes 		 */
710aa9caaf6SPeter Wemm 		if (t == TWORD && !quoteflag)
711aa9caaf6SPeter Wemm 		{
7127920a31dSSteve Price 			char * const *pp;
7134b88c807SRodney W. Grimes 
7144b88c807SRodney W. Grimes 			for (pp = (char **)parsekwd; *pp; pp++) {
715aa9caaf6SPeter Wemm 				if (**pp == *wordtext && equal(*pp, wordtext))
716aa9caaf6SPeter Wemm 				{
7174b88c807SRodney W. Grimes 					lasttoken = t = pp - parsekwd + KWDOFFSET;
7184b88c807SRodney W. Grimes 					TRACE(("keyword %s recognized\n", tokname[t]));
7194b88c807SRodney W. Grimes 					goto out;
7204b88c807SRodney W. Grimes 				}
7214b88c807SRodney W. Grimes 			}
7224417f629SPeter Wemm 			if (noaliases == 0 &&
7234417f629SPeter Wemm 			    (ap = lookupalias(wordtext, 1)) != NULL) {
7244b88c807SRodney W. Grimes 				pushstring(ap->val, strlen(ap->val), ap);
7254b88c807SRodney W. Grimes 				checkkwd = savecheckkwd;
7264b88c807SRodney W. Grimes 				goto top;
7274b88c807SRodney W. Grimes 			}
7284b88c807SRodney W. Grimes 		}
7294b88c807SRodney W. Grimes out:
7307920a31dSSteve Price 		checkkwd = 0;
7314b88c807SRodney W. Grimes 	}
7324b88c807SRodney W. Grimes #ifdef DEBUG
7334b88c807SRodney W. Grimes 	if (!alreadyseen)
7344b88c807SRodney W. Grimes 	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
7354b88c807SRodney W. Grimes 	else
7364b88c807SRodney W. Grimes 	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
7374b88c807SRodney W. Grimes #endif
7384b88c807SRodney W. Grimes 	return (t);
7394b88c807SRodney W. Grimes }
7404b88c807SRodney W. Grimes 
7414b88c807SRodney W. Grimes 
7424b88c807SRodney W. Grimes /*
7434b88c807SRodney W. Grimes  * Read the next input token.
7444b88c807SRodney W. Grimes  * If the token is a word, we set backquotelist to the list of cmds in
7454b88c807SRodney W. Grimes  *	backquotes.  We set quoteflag to true if any part of the word was
7464b88c807SRodney W. Grimes  *	quoted.
7474b88c807SRodney W. Grimes  * If the token is TREDIR, then we set redirnode to a structure containing
7484b88c807SRodney W. Grimes  *	the redirection.
7494b88c807SRodney W. Grimes  * In all cases, the variable startlinno is set to the number of the line
7504b88c807SRodney W. Grimes  *	on which the token starts.
7514b88c807SRodney W. Grimes  *
7524b88c807SRodney W. Grimes  * [Change comment:  here documents and internal procedures]
7534b88c807SRodney W. Grimes  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
7544b88c807SRodney W. Grimes  *  word parsing code into a separate routine.  In this case, readtoken
7554b88c807SRodney W. Grimes  *  doesn't need to have any internal procedures, but parseword does.
7564b88c807SRodney W. Grimes  *  We could also make parseoperator in essence the main routine, and
7574b88c807SRodney W. Grimes  *  have parseword (readtoken1?) handle both words and redirection.]
7584b88c807SRodney W. Grimes  */
7594b88c807SRodney W. Grimes 
7604b88c807SRodney W. Grimes #define RETURN(token)	return lasttoken = token
7614b88c807SRodney W. Grimes 
7624b88c807SRodney W. Grimes STATIC int
7634b88c807SRodney W. Grimes xxreadtoken() {
7647920a31dSSteve Price 	int c;
7654b88c807SRodney W. Grimes 
7664b88c807SRodney W. Grimes 	if (tokpushback) {
7674b88c807SRodney W. Grimes 		tokpushback = 0;
7684b88c807SRodney W. Grimes 		return lasttoken;
7694b88c807SRodney W. Grimes 	}
7704b88c807SRodney W. Grimes 	if (needprompt) {
7714b88c807SRodney W. Grimes 		setprompt(2);
7724b88c807SRodney W. Grimes 		needprompt = 0;
7734b88c807SRodney W. Grimes 	}
7744b88c807SRodney W. Grimes 	startlinno = plinno;
7754b88c807SRodney W. Grimes 	for (;;) {	/* until token or start of word found */
7764b88c807SRodney W. Grimes 		c = pgetc_macro();
7774b88c807SRodney W. Grimes 		if (c == ' ' || c == '\t')
7784b88c807SRodney W. Grimes 			continue;		/* quick check for white space first */
7794b88c807SRodney W. Grimes 		switch (c) {
7804b88c807SRodney W. Grimes 		case ' ': case '\t':
7814b88c807SRodney W. Grimes 			continue;
7824b88c807SRodney W. Grimes 		case '#':
7834b88c807SRodney W. Grimes 			while ((c = pgetc()) != '\n' && c != PEOF);
7844b88c807SRodney W. Grimes 			pungetc();
7854b88c807SRodney W. Grimes 			continue;
7864b88c807SRodney W. Grimes 		case '\\':
7874b88c807SRodney W. Grimes 			if (pgetc() == '\n') {
7884b88c807SRodney W. Grimes 				startlinno = ++plinno;
7894b88c807SRodney W. Grimes 				if (doprompt)
7904b88c807SRodney W. Grimes 					setprompt(2);
7914b88c807SRodney W. Grimes 				else
7924b88c807SRodney W. Grimes 					setprompt(0);
7934b88c807SRodney W. Grimes 				continue;
7944b88c807SRodney W. Grimes 			}
7954b88c807SRodney W. Grimes 			pungetc();
7964b88c807SRodney W. Grimes 			goto breakloop;
7974b88c807SRodney W. Grimes 		case '\n':
7984b88c807SRodney W. Grimes 			plinno++;
7994b88c807SRodney W. Grimes 			needprompt = doprompt;
8004b88c807SRodney W. Grimes 			RETURN(TNL);
8014b88c807SRodney W. Grimes 		case PEOF:
8024b88c807SRodney W. Grimes 			RETURN(TEOF);
8034b88c807SRodney W. Grimes 		case '&':
8044b88c807SRodney W. Grimes 			if (pgetc() == '&')
8054b88c807SRodney W. Grimes 				RETURN(TAND);
8064b88c807SRodney W. Grimes 			pungetc();
8074b88c807SRodney W. Grimes 			RETURN(TBACKGND);
8084b88c807SRodney W. Grimes 		case '|':
8094b88c807SRodney W. Grimes 			if (pgetc() == '|')
8104b88c807SRodney W. Grimes 				RETURN(TOR);
8114b88c807SRodney W. Grimes 			pungetc();
8124b88c807SRodney W. Grimes 			RETURN(TPIPE);
8134b88c807SRodney W. Grimes 		case ';':
8144b88c807SRodney W. Grimes 			if (pgetc() == ';')
8154b88c807SRodney W. Grimes 				RETURN(TENDCASE);
8164b88c807SRodney W. Grimes 			pungetc();
8174b88c807SRodney W. Grimes 			RETURN(TSEMI);
8184b88c807SRodney W. Grimes 		case '(':
8194b88c807SRodney W. Grimes 			RETURN(TLP);
8204b88c807SRodney W. Grimes 		case ')':
8214b88c807SRodney W. Grimes 			RETURN(TRP);
8224b88c807SRodney W. Grimes 		default:
8234b88c807SRodney W. Grimes 			goto breakloop;
8244b88c807SRodney W. Grimes 		}
8254b88c807SRodney W. Grimes 	}
8264b88c807SRodney W. Grimes breakloop:
8274b88c807SRodney W. Grimes 	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
8284b88c807SRodney W. Grimes #undef RETURN
8294b88c807SRodney W. Grimes }
8304b88c807SRodney W. Grimes 
8314b88c807SRodney W. Grimes 
8324b88c807SRodney W. Grimes 
8334b88c807SRodney W. Grimes /*
8344b88c807SRodney W. Grimes  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
8354b88c807SRodney W. Grimes  * is not NULL, read a here document.  In the latter case, eofmark is the
8364b88c807SRodney W. Grimes  * word which marks the end of the document and striptabs is true if
8374b88c807SRodney W. Grimes  * leading tabs should be stripped from the document.  The argument firstc
8384b88c807SRodney W. Grimes  * is the first character of the input token or document.
8394b88c807SRodney W. Grimes  *
8404b88c807SRodney W. Grimes  * Because C does not have internal subroutines, I have simulated them
8414b88c807SRodney W. Grimes  * using goto's to implement the subroutine linkage.  The following macros
8424b88c807SRodney W. Grimes  * will run code that appears at the end of readtoken1.
8434b88c807SRodney W. Grimes  */
8444b88c807SRodney W. Grimes 
8454b88c807SRodney W. Grimes #define CHECKEND()	{goto checkend; checkend_return:;}
8464b88c807SRodney W. Grimes #define PARSEREDIR()	{goto parseredir; parseredir_return:;}
8474b88c807SRodney W. Grimes #define PARSESUB()	{goto parsesub; parsesub_return:;}
8484b88c807SRodney W. Grimes #define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
8494b88c807SRodney W. Grimes #define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
8504b88c807SRodney W. Grimes #define	PARSEARITH()	{goto parsearith; parsearith_return:;}
8514b88c807SRodney W. Grimes 
8524b88c807SRodney W. Grimes STATIC int
8534b88c807SRodney W. Grimes readtoken1(firstc, syntax, eofmark, striptabs)
8544b88c807SRodney W. Grimes 	int firstc;
8554b88c807SRodney W. Grimes 	char const *syntax;
8564b88c807SRodney W. Grimes 	char *eofmark;
8574b88c807SRodney W. Grimes 	int striptabs;
8584b88c807SRodney W. Grimes 	{
859aa9caaf6SPeter Wemm 	int c = firstc;
860aa9caaf6SPeter Wemm 	char *out;
8614b88c807SRodney W. Grimes 	int len;
8624b88c807SRodney W. Grimes 	char line[EOFMARKLEN + 1];
8634b88c807SRodney W. Grimes 	struct nodelist *bqlist;
8644b88c807SRodney W. Grimes 	int quotef;
8654b88c807SRodney W. Grimes 	int dblquote;
8664b88c807SRodney W. Grimes 	int varnest;	/* levels of variables expansion */
8674b88c807SRodney W. Grimes 	int arinest;	/* levels of arithmetic expansion */
8684b88c807SRodney W. Grimes 	int parenlevel;	/* levels of parens in arithmetic */
8694b88c807SRodney W. Grimes 	int oldstyle;
8704b88c807SRodney W. Grimes 	char const *prevsyntax;	/* syntax before arithmetic */
8712dde9ce3SMartin Cracauer 	int synentry;
872aa9caaf6SPeter Wemm #if __GNUC__
873aa9caaf6SPeter Wemm 	/* Avoid longjmp clobbering */
874aa9caaf6SPeter Wemm 	(void) &out;
875aa9caaf6SPeter Wemm 	(void) &quotef;
876aa9caaf6SPeter Wemm 	(void) &dblquote;
877aa9caaf6SPeter Wemm 	(void) &varnest;
878aa9caaf6SPeter Wemm 	(void) &arinest;
879aa9caaf6SPeter Wemm 	(void) &parenlevel;
880aa9caaf6SPeter Wemm 	(void) &oldstyle;
881aa9caaf6SPeter Wemm 	(void) &prevsyntax;
882aa9caaf6SPeter Wemm 	(void) &syntax;
8832dde9ce3SMartin Cracauer 	(void) &synentry;
884aa9caaf6SPeter Wemm #endif
8854b88c807SRodney W. Grimes 
8864b88c807SRodney W. Grimes 	startlinno = plinno;
8874b88c807SRodney W. Grimes 	dblquote = 0;
8884b88c807SRodney W. Grimes 	if (syntax == DQSYNTAX)
8894b88c807SRodney W. Grimes 		dblquote = 1;
8904b88c807SRodney W. Grimes 	quotef = 0;
8914b88c807SRodney W. Grimes 	bqlist = NULL;
8924b88c807SRodney W. Grimes 	varnest = 0;
8934b88c807SRodney W. Grimes 	arinest = 0;
8944b88c807SRodney W. Grimes 	parenlevel = 0;
8954b88c807SRodney W. Grimes 
8964b88c807SRodney W. Grimes 	STARTSTACKSTR(out);
8974b88c807SRodney W. Grimes 	loop: {	/* for each line, until end of word */
8984b88c807SRodney W. Grimes #if ATTY
8994b88c807SRodney W. Grimes 		if (c == '\034' && doprompt
9004b88c807SRodney W. Grimes 		 && attyset() && ! equal(termval(), "emacs")) {
9014b88c807SRodney W. Grimes 			attyline();
9024b88c807SRodney W. Grimes 			if (syntax == BASESYNTAX)
9034b88c807SRodney W. Grimes 				return readtoken();
9044b88c807SRodney W. Grimes 			c = pgetc();
9054b88c807SRodney W. Grimes 			goto loop;
9064b88c807SRodney W. Grimes 		}
9074b88c807SRodney W. Grimes #endif
9084b88c807SRodney W. Grimes 		CHECKEND();	/* set c to PEOF if at end of here document */
9094b88c807SRodney W. Grimes 		for (;;) {	/* until end of line or end of word */
9104b88c807SRodney W. Grimes 			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */
9112dde9ce3SMartin Cracauer 
9122dde9ce3SMartin Cracauer 			synentry = syntax[c];
9132dde9ce3SMartin Cracauer 
9142dde9ce3SMartin Cracauer 			switch(synentry) {
9154b88c807SRodney W. Grimes 			case CNL:	/* '\n' */
9164b88c807SRodney W. Grimes 				if (syntax == BASESYNTAX)
9174b88c807SRodney W. Grimes 					goto endword;	/* exit outer loop */
9184b88c807SRodney W. Grimes 				USTPUTC(c, out);
9194b88c807SRodney W. Grimes 				plinno++;
9204b88c807SRodney W. Grimes 				if (doprompt)
9214b88c807SRodney W. Grimes 					setprompt(2);
9224b88c807SRodney W. Grimes 				else
9234b88c807SRodney W. Grimes 					setprompt(0);
9244b88c807SRodney W. Grimes 				c = pgetc();
9254b88c807SRodney W. Grimes 				goto loop;		/* continue outer loop */
9264b88c807SRodney W. Grimes 			case CWORD:
9274b88c807SRodney W. Grimes 				USTPUTC(c, out);
9284b88c807SRodney W. Grimes 				break;
9294b88c807SRodney W. Grimes 			case CCTL:
9304b88c807SRodney W. Grimes 				if (eofmark == NULL || dblquote)
9314b88c807SRodney W. Grimes 					USTPUTC(CTLESC, out);
9324b88c807SRodney W. Grimes 				USTPUTC(c, out);
9334b88c807SRodney W. Grimes 				break;
9344b88c807SRodney W. Grimes 			case CBACK:	/* backslash */
9354b88c807SRodney W. Grimes 				c = pgetc();
9364b88c807SRodney W. Grimes 				if (c == PEOF) {
9374b88c807SRodney W. Grimes 					USTPUTC('\\', out);
9384b88c807SRodney W. Grimes 					pungetc();
9394b88c807SRodney W. Grimes 				} else if (c == '\n') {
9404b88c807SRodney W. Grimes 					if (doprompt)
9414b88c807SRodney W. Grimes 						setprompt(2);
9424b88c807SRodney W. Grimes 					else
9434b88c807SRodney W. Grimes 						setprompt(0);
9444b88c807SRodney W. Grimes 				} else {
94573f612b5SMartin Cracauer 					if (dblquote && c != '\\' &&
94673f612b5SMartin Cracauer 					    c != '`' && c != '$' &&
94773f612b5SMartin Cracauer 					    (c != '"' || eofmark != NULL))
9484b88c807SRodney W. Grimes 						USTPUTC('\\', out);
94973f612b5SMartin Cracauer 					if (c >= 0 && SQSYNTAX[c] == CCTL)
9504b88c807SRodney W. Grimes 						USTPUTC(CTLESC, out);
9515557a02aSTor Egge 					else if (eofmark == NULL)
9526f47734fSTor Egge 						USTPUTC(CTLQUOTEMARK, out);
9534b88c807SRodney W. Grimes 					USTPUTC(c, out);
9544b88c807SRodney W. Grimes 					quotef++;
9554b88c807SRodney W. Grimes 				}
9564b88c807SRodney W. Grimes 				break;
9574b88c807SRodney W. Grimes 			case CSQUOTE:
9585557a02aSTor Egge 				if (eofmark == NULL)
9596f47734fSTor Egge 					USTPUTC(CTLQUOTEMARK, out);
9604b88c807SRodney W. Grimes 				syntax = SQSYNTAX;
9614b88c807SRodney W. Grimes 				break;
9624b88c807SRodney W. Grimes 			case CDQUOTE:
9635557a02aSTor Egge 				if (eofmark == NULL)
9646f47734fSTor Egge 					USTPUTC(CTLQUOTEMARK, out);
9654b88c807SRodney W. Grimes 				syntax = DQSYNTAX;
9664b88c807SRodney W. Grimes 				dblquote = 1;
9674b88c807SRodney W. Grimes 				break;
9684b88c807SRodney W. Grimes 			case CENDQUOTE:
9695557a02aSTor Egge 				if (eofmark != NULL && arinest == 0 &&
9705557a02aSTor Egge 				    varnest == 0) {
9714b88c807SRodney W. Grimes 					USTPUTC(c, out);
9724b88c807SRodney W. Grimes 				} else {
9735557a02aSTor Egge 					if (arinest) {
9744b88c807SRodney W. Grimes 						syntax = ARISYNTAX;
9754b88c807SRodney W. Grimes 						dblquote = 0;
9765557a02aSTor Egge 					} else if (eofmark == NULL) {
9775557a02aSTor Egge 						syntax = BASESYNTAX;
9785557a02aSTor Egge 						dblquote = 0;
9795557a02aSTor Egge 					}
9805557a02aSTor Egge 					quotef++;
9814b88c807SRodney W. Grimes 				}
9824b88c807SRodney W. Grimes 				break;
9834b88c807SRodney W. Grimes 			case CVAR:	/* '$' */
9844b88c807SRodney W. Grimes 				PARSESUB();		/* parse substitution */
9854b88c807SRodney W. Grimes 				break;
9864b88c807SRodney W. Grimes 			case CENDVAR:	/* '}' */
9874b88c807SRodney W. Grimes 				if (varnest > 0) {
9884b88c807SRodney W. Grimes 					varnest--;
9894b88c807SRodney W. Grimes 					USTPUTC(CTLENDVAR, out);
9904b88c807SRodney W. Grimes 				} else {
9914b88c807SRodney W. Grimes 					USTPUTC(c, out);
9924b88c807SRodney W. Grimes 				}
9934b88c807SRodney W. Grimes 				break;
9944b88c807SRodney W. Grimes 			case CLP:	/* '(' in arithmetic */
9954b88c807SRodney W. Grimes 				parenlevel++;
9964b88c807SRodney W. Grimes 				USTPUTC(c, out);
9974b88c807SRodney W. Grimes 				break;
9984b88c807SRodney W. Grimes 			case CRP:	/* ')' in arithmetic */
9994b88c807SRodney W. Grimes 				if (parenlevel > 0) {
10004b88c807SRodney W. Grimes 					USTPUTC(c, out);
10014b88c807SRodney W. Grimes 					--parenlevel;
10024b88c807SRodney W. Grimes 				} else {
10034b88c807SRodney W. Grimes 					if (pgetc() == ')') {
10044b88c807SRodney W. Grimes 						if (--arinest == 0) {
10054b88c807SRodney W. Grimes 							USTPUTC(CTLENDARI, out);
10064b88c807SRodney W. Grimes 							syntax = prevsyntax;
10075557a02aSTor Egge 							if (syntax == DQSYNTAX)
10085557a02aSTor Egge 								dblquote = 1;
10095557a02aSTor Egge 							else
10105557a02aSTor Egge 								dblquote = 0;
10114b88c807SRodney W. Grimes 						} else
10124b88c807SRodney W. Grimes 							USTPUTC(')', out);
10134b88c807SRodney W. Grimes 					} else {
10144b88c807SRodney W. Grimes 						/*
10154b88c807SRodney W. Grimes 						 * unbalanced parens
10164b88c807SRodney W. Grimes 						 *  (don't 2nd guess - no error)
10174b88c807SRodney W. Grimes 						 */
10184b88c807SRodney W. Grimes 						pungetc();
10194b88c807SRodney W. Grimes 						USTPUTC(')', out);
10204b88c807SRodney W. Grimes 					}
10214b88c807SRodney W. Grimes 				}
10224b88c807SRodney W. Grimes 				break;
10234b88c807SRodney W. Grimes 			case CBQUOTE:	/* '`' */
10244b88c807SRodney W. Grimes 				PARSEBACKQOLD();
10254b88c807SRodney W. Grimes 				break;
10264b88c807SRodney W. Grimes 			case CEOF:
10274b88c807SRodney W. Grimes 				goto endword;		/* exit outer loop */
10284b88c807SRodney W. Grimes 			default:
10294b88c807SRodney W. Grimes 				if (varnest == 0)
10304b88c807SRodney W. Grimes 					goto endword;	/* exit outer loop */
10314b88c807SRodney W. Grimes 				USTPUTC(c, out);
10324b88c807SRodney W. Grimes 			}
10334b88c807SRodney W. Grimes 			c = pgetc_macro();
10344b88c807SRodney W. Grimes 		}
10354b88c807SRodney W. Grimes 	}
10364b88c807SRodney W. Grimes endword:
10374b88c807SRodney W. Grimes 	if (syntax == ARISYNTAX)
10384b88c807SRodney W. Grimes 		synerror("Missing '))'");
10394b88c807SRodney W. Grimes 	if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10404b88c807SRodney W. Grimes 		synerror("Unterminated quoted string");
10414b88c807SRodney W. Grimes 	if (varnest != 0) {
10424b88c807SRodney W. Grimes 		startlinno = plinno;
10434b88c807SRodney W. Grimes 		synerror("Missing '}'");
10444b88c807SRodney W. Grimes 	}
10454b88c807SRodney W. Grimes 	USTPUTC('\0', out);
10464b88c807SRodney W. Grimes 	len = out - stackblock();
10474b88c807SRodney W. Grimes 	out = stackblock();
10484b88c807SRodney W. Grimes 	if (eofmark == NULL) {
10494b88c807SRodney W. Grimes 		if ((c == '>' || c == '<')
10504b88c807SRodney W. Grimes 		 && quotef == 0
10514b88c807SRodney W. Grimes 		 && len <= 2
10524b88c807SRodney W. Grimes 		 && (*out == '\0' || is_digit(*out))) {
10534b88c807SRodney W. Grimes 			PARSEREDIR();
10544b88c807SRodney W. Grimes 			return lasttoken = TREDIR;
10554b88c807SRodney W. Grimes 		} else {
10564b88c807SRodney W. Grimes 			pungetc();
10574b88c807SRodney W. Grimes 		}
10584b88c807SRodney W. Grimes 	}
10594b88c807SRodney W. Grimes 	quoteflag = quotef;
10604b88c807SRodney W. Grimes 	backquotelist = bqlist;
10614b88c807SRodney W. Grimes 	grabstackblock(len);
10624b88c807SRodney W. Grimes 	wordtext = out;
10634b88c807SRodney W. Grimes 	return lasttoken = TWORD;
10644b88c807SRodney W. Grimes /* end of readtoken routine */
10654b88c807SRodney W. Grimes 
10664b88c807SRodney W. Grimes 
10674b88c807SRodney W. Grimes 
10684b88c807SRodney W. Grimes /*
10694b88c807SRodney W. Grimes  * Check to see whether we are at the end of the here document.  When this
10704b88c807SRodney W. Grimes  * is called, c is set to the first character of the next input line.  If
10714b88c807SRodney W. Grimes  * we are at the end of the here document, this routine sets the c to PEOF.
10724b88c807SRodney W. Grimes  */
10734b88c807SRodney W. Grimes 
10744b88c807SRodney W. Grimes checkend: {
10754b88c807SRodney W. Grimes 	if (eofmark) {
10764b88c807SRodney W. Grimes 		if (striptabs) {
10774b88c807SRodney W. Grimes 			while (c == '\t')
10784b88c807SRodney W. Grimes 				c = pgetc();
10794b88c807SRodney W. Grimes 		}
10804b88c807SRodney W. Grimes 		if (c == *eofmark) {
10814b88c807SRodney W. Grimes 			if (pfgets(line, sizeof line) != NULL) {
10827920a31dSSteve Price 				char *p, *q;
10834b88c807SRodney W. Grimes 
10844b88c807SRodney W. Grimes 				p = line;
10854b88c807SRodney W. Grimes 				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10864b88c807SRodney W. Grimes 				if (*p == '\n' && *q == '\0') {
10874b88c807SRodney W. Grimes 					c = PEOF;
10884b88c807SRodney W. Grimes 					plinno++;
10894b88c807SRodney W. Grimes 					needprompt = doprompt;
10904b88c807SRodney W. Grimes 				} else {
10914b88c807SRodney W. Grimes 					pushstring(line, strlen(line), NULL);
10924b88c807SRodney W. Grimes 				}
10934b88c807SRodney W. Grimes 			}
10944b88c807SRodney W. Grimes 		}
10954b88c807SRodney W. Grimes 	}
10964b88c807SRodney W. Grimes 	goto checkend_return;
10974b88c807SRodney W. Grimes }
10984b88c807SRodney W. Grimes 
10994b88c807SRodney W. Grimes 
11004b88c807SRodney W. Grimes /*
11014b88c807SRodney W. Grimes  * Parse a redirection operator.  The variable "out" points to a string
11024b88c807SRodney W. Grimes  * specifying the fd to be redirected.  The variable "c" contains the
11034b88c807SRodney W. Grimes  * first character of the redirection operator.
11044b88c807SRodney W. Grimes  */
11054b88c807SRodney W. Grimes 
11064b88c807SRodney W. Grimes parseredir: {
11074b88c807SRodney W. Grimes 	char fd = *out;
11084b88c807SRodney W. Grimes 	union node *np;
11094b88c807SRodney W. Grimes 
11104b88c807SRodney W. Grimes 	np = (union node *)stalloc(sizeof (struct nfile));
11114b88c807SRodney W. Grimes 	if (c == '>') {
11124b88c807SRodney W. Grimes 		np->nfile.fd = 1;
11134b88c807SRodney W. Grimes 		c = pgetc();
11144b88c807SRodney W. Grimes 		if (c == '>')
11154b88c807SRodney W. Grimes 			np->type = NAPPEND;
11164b88c807SRodney W. Grimes 		else if (c == '&')
11174b88c807SRodney W. Grimes 			np->type = NTOFD;
11184b88c807SRodney W. Grimes 		else {
11194b88c807SRodney W. Grimes 			np->type = NTO;
11204b88c807SRodney W. Grimes 			pungetc();
11214b88c807SRodney W. Grimes 		}
11224b88c807SRodney W. Grimes 	} else {	/* c == '<' */
11234b88c807SRodney W. Grimes 		np->nfile.fd = 0;
11244b88c807SRodney W. Grimes 		c = pgetc();
11254b88c807SRodney W. Grimes 		if (c == '<') {
11264b88c807SRodney W. Grimes 			if (sizeof (struct nfile) != sizeof (struct nhere)) {
11274b88c807SRodney W. Grimes 				np = (union node *)stalloc(sizeof (struct nhere));
11284b88c807SRodney W. Grimes 				np->nfile.fd = 0;
11294b88c807SRodney W. Grimes 			}
11304b88c807SRodney W. Grimes 			np->type = NHERE;
11314b88c807SRodney W. Grimes 			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
11324b88c807SRodney W. Grimes 			heredoc->here = np;
11334b88c807SRodney W. Grimes 			if ((c = pgetc()) == '-') {
11344b88c807SRodney W. Grimes 				heredoc->striptabs = 1;
11354b88c807SRodney W. Grimes 			} else {
11364b88c807SRodney W. Grimes 				heredoc->striptabs = 0;
11374b88c807SRodney W. Grimes 				pungetc();
11384b88c807SRodney W. Grimes 			}
11394b88c807SRodney W. Grimes 		} else if (c == '&')
11404b88c807SRodney W. Grimes 			np->type = NFROMFD;
11414682f420SBrian Somers 		else if (c == '>')
11424682f420SBrian Somers 			np->type = NFROMTO;
11434b88c807SRodney W. Grimes 		else {
11444b88c807SRodney W. Grimes 			np->type = NFROM;
11454b88c807SRodney W. Grimes 			pungetc();
11464b88c807SRodney W. Grimes 		}
11474b88c807SRodney W. Grimes 	}
11484b88c807SRodney W. Grimes 	if (fd != '\0')
11494b88c807SRodney W. Grimes 		np->nfile.fd = digit_val(fd);
11504b88c807SRodney W. Grimes 	redirnode = np;
11514b88c807SRodney W. Grimes 	goto parseredir_return;
11524b88c807SRodney W. Grimes }
11534b88c807SRodney W. Grimes 
11544b88c807SRodney W. Grimes 
11554b88c807SRodney W. Grimes /*
11564b88c807SRodney W. Grimes  * Parse a substitution.  At this point, we have read the dollar sign
11574b88c807SRodney W. Grimes  * and nothing else.
11584b88c807SRodney W. Grimes  */
11594b88c807SRodney W. Grimes 
11604b88c807SRodney W. Grimes parsesub: {
11614b88c807SRodney W. Grimes 	int subtype;
11624b88c807SRodney W. Grimes 	int typeloc;
11634b88c807SRodney W. Grimes 	int flags;
11644b88c807SRodney W. Grimes 	char *p;
11654b88c807SRodney W. Grimes #ifndef GDB_HACK
11664b88c807SRodney W. Grimes 	static const char types[] = "}-+?=";
11674b88c807SRodney W. Grimes #endif
11685c817731SPeter Wemm        int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
11694b88c807SRodney W. Grimes 
11704b88c807SRodney W. Grimes 	c = pgetc();
11714b88c807SRodney W. Grimes 	if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
11724b88c807SRodney W. Grimes 		USTPUTC('$', out);
11734b88c807SRodney W. Grimes 		pungetc();
11744b88c807SRodney W. Grimes 	} else if (c == '(') {	/* $(command) or $((arith)) */
11754b88c807SRodney W. Grimes 		if (pgetc() == '(') {
11764b88c807SRodney W. Grimes 			PARSEARITH();
11774b88c807SRodney W. Grimes 		} else {
11784b88c807SRodney W. Grimes 			pungetc();
11794b88c807SRodney W. Grimes 			PARSEBACKQNEW();
11804b88c807SRodney W. Grimes 		}
11814b88c807SRodney W. Grimes 	} else {
11824b88c807SRodney W. Grimes 		USTPUTC(CTLVAR, out);
11834b88c807SRodney W. Grimes 		typeloc = out - stackblock();
11844b88c807SRodney W. Grimes 		USTPUTC(VSNORMAL, out);
11854b88c807SRodney W. Grimes 		subtype = VSNORMAL;
11864b88c807SRodney W. Grimes 		if (c == '{') {
11875c817731SPeter Wemm 			bracketed_name = 1;
11884b88c807SRodney W. Grimes 			c = pgetc();
1189aa9caaf6SPeter Wemm 			if (c == '#') {
1190aa9caaf6SPeter Wemm 				if ((c = pgetc()) == '}')
1191aa9caaf6SPeter Wemm 					c = '#';
1192aa9caaf6SPeter Wemm 				else
1193aa9caaf6SPeter Wemm 					subtype = VSLENGTH;
1194aa9caaf6SPeter Wemm 			}
1195aa9caaf6SPeter Wemm 			else
11964b88c807SRodney W. Grimes 				subtype = 0;
11974b88c807SRodney W. Grimes 		}
11984b88c807SRodney W. Grimes 		if (is_name(c)) {
11994b88c807SRodney W. Grimes 			do {
12004b88c807SRodney W. Grimes 				STPUTC(c, out);
12014b88c807SRodney W. Grimes 				c = pgetc();
12024b88c807SRodney W. Grimes 			} while (is_in_name(c));
12035c817731SPeter Wemm 		} else if (is_digit(c)) {
12045c817731SPeter Wemm 			if (bracketed_name) {
12055c817731SPeter Wemm 				do {
12065c817731SPeter Wemm 					STPUTC(c, out);
12075c817731SPeter Wemm 					c = pgetc();
12085c817731SPeter Wemm 				} while (is_digit(c));
12095c817731SPeter Wemm 			} else {
12105c817731SPeter Wemm 				STPUTC(c, out);
12115c817731SPeter Wemm 				c = pgetc();
12125c817731SPeter Wemm 			}
12134b88c807SRodney W. Grimes 		} else {
12144b88c807SRodney W. Grimes 			if (! is_special(c))
12154b88c807SRodney W. Grimes badsub:				synerror("Bad substitution");
12164b88c807SRodney W. Grimes 			USTPUTC(c, out);
12174b88c807SRodney W. Grimes 			c = pgetc();
12184b88c807SRodney W. Grimes 		}
12194b88c807SRodney W. Grimes 		STPUTC('=', out);
12204b88c807SRodney W. Grimes 		flags = 0;
12214b88c807SRodney W. Grimes 		if (subtype == 0) {
1222aa9caaf6SPeter Wemm 			switch (c) {
1223aa9caaf6SPeter Wemm 			case ':':
12244b88c807SRodney W. Grimes 				flags = VSNUL;
12254b88c807SRodney W. Grimes 				c = pgetc();
1226aa9caaf6SPeter Wemm 				/*FALLTHROUGH*/
1227aa9caaf6SPeter Wemm 			default:
12284b88c807SRodney W. Grimes 				p = strchr(types, c);
12294b88c807SRodney W. Grimes 				if (p == NULL)
12304b88c807SRodney W. Grimes 					goto badsub;
12314b88c807SRodney W. Grimes 				subtype = p - types + VSNORMAL;
1232aa9caaf6SPeter Wemm 				break;
1233aa9caaf6SPeter Wemm 			case '%':
1234aa9caaf6SPeter Wemm 			case '#':
1235aa9caaf6SPeter Wemm 				{
1236aa9caaf6SPeter Wemm 					int cc = c;
1237aa9caaf6SPeter Wemm 					subtype = c == '#' ? VSTRIMLEFT :
1238aa9caaf6SPeter Wemm 							     VSTRIMRIGHT;
1239aa9caaf6SPeter Wemm 					c = pgetc();
1240aa9caaf6SPeter Wemm 					if (c == cc)
1241aa9caaf6SPeter Wemm 						subtype++;
1242aa9caaf6SPeter Wemm 					else
1243aa9caaf6SPeter Wemm 						pungetc();
1244aa9caaf6SPeter Wemm 					break;
1245aa9caaf6SPeter Wemm 				}
1246aa9caaf6SPeter Wemm 			}
12474b88c807SRodney W. Grimes 		} else {
12484b88c807SRodney W. Grimes 			pungetc();
12494b88c807SRodney W. Grimes 		}
1250c11e75cfSMartin Cracauer 		if (subtype != VSLENGTH && (dblquote || arinest))
12514b88c807SRodney W. Grimes 			flags |= VSQUOTE;
12524b88c807SRodney W. Grimes 		*(stackblock() + typeloc) = subtype | flags;
12534b88c807SRodney W. Grimes 		if (subtype != VSNORMAL)
12544b88c807SRodney W. Grimes 			varnest++;
12554b88c807SRodney W. Grimes 	}
12564b88c807SRodney W. Grimes 	goto parsesub_return;
12574b88c807SRodney W. Grimes }
12584b88c807SRodney W. Grimes 
12594b88c807SRodney W. Grimes 
12604b88c807SRodney W. Grimes /*
12614b88c807SRodney W. Grimes  * Called to parse command substitutions.  Newstyle is set if the command
12624b88c807SRodney W. Grimes  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12634b88c807SRodney W. Grimes  * list of commands (passed by reference), and savelen is the number of
12644b88c807SRodney W. Grimes  * characters on the top of the stack which must be preserved.
12654b88c807SRodney W. Grimes  */
12664b88c807SRodney W. Grimes 
12674b88c807SRodney W. Grimes parsebackq: {
12684b88c807SRodney W. Grimes 	struct nodelist **nlpp;
12694b88c807SRodney W. Grimes 	int savepbq;
12704b88c807SRodney W. Grimes 	union node *n;
12714b88c807SRodney W. Grimes 	char *volatile str;
12724b88c807SRodney W. Grimes 	struct jmploc jmploc;
12734b88c807SRodney W. Grimes 	struct jmploc *volatile savehandler;
12744b88c807SRodney W. Grimes 	int savelen;
1275ab0a2172SSteve Price 	int saveprompt;
1276ab0a2172SSteve Price #if __GNUC__
1277ab0a2172SSteve Price 	/* Avoid longjmp clobbering */
1278ab0a2172SSteve Price 	(void) &saveprompt;
1279ab0a2172SSteve Price #endif
12804b88c807SRodney W. Grimes 
12814b88c807SRodney W. Grimes 	savepbq = parsebackquote;
12824b88c807SRodney W. Grimes 	if (setjmp(jmploc.loc)) {
12834b88c807SRodney W. Grimes 		if (str)
12844b88c807SRodney W. Grimes 			ckfree(str);
12854b88c807SRodney W. Grimes 		parsebackquote = 0;
12864b88c807SRodney W. Grimes 		handler = savehandler;
12874b88c807SRodney W. Grimes 		longjmp(handler->loc, 1);
12884b88c807SRodney W. Grimes 	}
12894b88c807SRodney W. Grimes 	INTOFF;
12904b88c807SRodney W. Grimes 	str = NULL;
12914b88c807SRodney W. Grimes 	savelen = out - stackblock();
12924b88c807SRodney W. Grimes 	if (savelen > 0) {
12934b88c807SRodney W. Grimes 		str = ckmalloc(savelen);
1294aa9caaf6SPeter Wemm 		memcpy(str, stackblock(), savelen);
12954b88c807SRodney W. Grimes 	}
12964b88c807SRodney W. Grimes 	savehandler = handler;
12974b88c807SRodney W. Grimes 	handler = &jmploc;
12984b88c807SRodney W. Grimes 	INTON;
12994b88c807SRodney W. Grimes         if (oldstyle) {
13004b88c807SRodney W. Grimes                 /* We must read until the closing backquote, giving special
13014b88c807SRodney W. Grimes                    treatment to some slashes, and then push the string and
13024b88c807SRodney W. Grimes                    reread it as input, interpreting it normally.  */
13037920a31dSSteve Price                 char *out;
13047920a31dSSteve Price                 int c;
13054b88c807SRodney W. Grimes                 int savelen;
13064b88c807SRodney W. Grimes                 char *str;
13074b88c807SRodney W. Grimes 
1308ab0a2172SSteve Price 
13094b88c807SRodney W. Grimes                 STARTSTACKSTR(out);
1310ab0a2172SSteve Price 		for (;;) {
1311ab0a2172SSteve Price 			if (needprompt) {
1312ab0a2172SSteve Price 				setprompt(2);
1313ab0a2172SSteve Price 				needprompt = 0;
131472348d41SJoerg Wunsch 			}
1315ab0a2172SSteve Price 			switch (c = pgetc()) {
1316ab0a2172SSteve Price 			case '`':
1317ab0a2172SSteve Price 				goto done;
1318ab0a2172SSteve Price 
1319ab0a2172SSteve Price 			case '\\':
1320ab0a2172SSteve Price                                 if ((c = pgetc()) == '\n') {
1321ab0a2172SSteve Price 					plinno++;
1322ab0a2172SSteve Price 					if (doprompt)
1323ab0a2172SSteve Price 						setprompt(2);
1324ab0a2172SSteve Price 					else
1325ab0a2172SSteve Price 						setprompt(0);
1326ab0a2172SSteve Price 					/*
1327ab0a2172SSteve Price 					 * If eating a newline, avoid putting
1328ab0a2172SSteve Price 					 * the newline into the new character
1329ab0a2172SSteve Price 					 * stream (via the STPUTC after the
1330ab0a2172SSteve Price 					 * switch).
1331ab0a2172SSteve Price 					 */
1332ab0a2172SSteve Price 					continue;
1333ab0a2172SSteve Price 				}
13341e95454eSPaul Richards                                 if (c != '\\' && c != '`' && c != '$'
13354b88c807SRodney W. Grimes                                     && (!dblquote || c != '"'))
13364b88c807SRodney W. Grimes                                         STPUTC('\\', out);
1337ab0a2172SSteve Price 				break;
1338ab0a2172SSteve Price 
1339ab0a2172SSteve Price 			case '\n':
1340ab0a2172SSteve Price 				plinno++;
1341ab0a2172SSteve Price 				needprompt = doprompt;
1342ab0a2172SSteve Price 				break;
1343ab0a2172SSteve Price 
1344ab0a2172SSteve Price 			case PEOF:
1345ab0a2172SSteve Price 			        startlinno = plinno;
1346ab0a2172SSteve Price 				synerror("EOF in backquote substitution");
1347ab0a2172SSteve Price  				break;
1348ab0a2172SSteve Price 
1349ab0a2172SSteve Price 			default:
1350ab0a2172SSteve Price 				break;
13514b88c807SRodney W. Grimes 			}
13524b88c807SRodney W. Grimes 			STPUTC(c, out);
13534b88c807SRodney W. Grimes                 }
1354ab0a2172SSteve Price done:
13554b88c807SRodney W. Grimes                 STPUTC('\0', out);
13564b88c807SRodney W. Grimes                 savelen = out - stackblock();
13574b88c807SRodney W. Grimes                 if (savelen > 0) {
13584b88c807SRodney W. Grimes                         str = ckmalloc(savelen);
1359aa9caaf6SPeter Wemm                         memcpy(str, stackblock(), savelen);
13604b88c807SRodney W. Grimes 			setinputstring(str, 1);
13614b88c807SRodney W. Grimes                 }
1362aa9caaf6SPeter Wemm         }
13634b88c807SRodney W. Grimes 	nlpp = &bqlist;
13644b88c807SRodney W. Grimes 	while (*nlpp)
13654b88c807SRodney W. Grimes 		nlpp = &(*nlpp)->next;
13664b88c807SRodney W. Grimes 	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
13674b88c807SRodney W. Grimes 	(*nlpp)->next = NULL;
13684b88c807SRodney W. Grimes 	parsebackquote = oldstyle;
1369ab0a2172SSteve Price 
1370ab0a2172SSteve Price 	if (oldstyle) {
1371ab0a2172SSteve Price 		saveprompt = doprompt;
1372ab0a2172SSteve Price 		doprompt = 0;
1373ab0a2172SSteve Price 	}
1374ab0a2172SSteve Price 
13754b88c807SRodney W. Grimes 	n = list(0);
1376ab0a2172SSteve Price 
13774b88c807SRodney W. Grimes 	if (oldstyle)
1378ab0a2172SSteve Price 		doprompt = saveprompt;
1379ab0a2172SSteve Price 	else {
1380ab0a2172SSteve Price 		if (readtoken() != TRP)
1381ab0a2172SSteve Price 			synexpect(TRP);
1382ab0a2172SSteve Price 	}
1383ab0a2172SSteve Price 
1384ab0a2172SSteve Price 	(*nlpp)->n = n;
1385ab0a2172SSteve Price         if (oldstyle) {
1386ab0a2172SSteve Price 		/*
1387ab0a2172SSteve Price 		 * Start reading from old file again, ignoring any pushed back
1388ab0a2172SSteve Price 		 * tokens left from the backquote parsing
1389ab0a2172SSteve Price 		 */
13904b88c807SRodney W. Grimes                 popfile();
1391ab0a2172SSteve Price 		tokpushback = 0;
1392ab0a2172SSteve Price 	}
13934b88c807SRodney W. Grimes 	while (stackblocksize() <= savelen)
13944b88c807SRodney W. Grimes 		growstackblock();
13954b88c807SRodney W. Grimes 	STARTSTACKSTR(out);
13964b88c807SRodney W. Grimes 	if (str) {
1397aa9caaf6SPeter Wemm 		memcpy(out, str, savelen);
13984b88c807SRodney W. Grimes 		STADJUST(savelen, out);
13994b88c807SRodney W. Grimes 		INTOFF;
14004b88c807SRodney W. Grimes 		ckfree(str);
14014b88c807SRodney W. Grimes 		str = NULL;
14024b88c807SRodney W. Grimes 		INTON;
14034b88c807SRodney W. Grimes 	}
14044b88c807SRodney W. Grimes 	parsebackquote = savepbq;
14054b88c807SRodney W. Grimes 	handler = savehandler;
14064b88c807SRodney W. Grimes 	if (arinest || dblquote)
14074b88c807SRodney W. Grimes 		USTPUTC(CTLBACKQ | CTLQUOTE, out);
14084b88c807SRodney W. Grimes 	else
14094b88c807SRodney W. Grimes 		USTPUTC(CTLBACKQ, out);
14104b88c807SRodney W. Grimes 	if (oldstyle)
14114b88c807SRodney W. Grimes 		goto parsebackq_oldreturn;
14124b88c807SRodney W. Grimes 	else
14134b88c807SRodney W. Grimes 		goto parsebackq_newreturn;
14144b88c807SRodney W. Grimes }
14154b88c807SRodney W. Grimes 
14164b88c807SRodney W. Grimes /*
14174b88c807SRodney W. Grimes  * Parse an arithmetic expansion (indicate start of one and set state)
14184b88c807SRodney W. Grimes  */
14194b88c807SRodney W. Grimes parsearith: {
14204b88c807SRodney W. Grimes 
14214b88c807SRodney W. Grimes 	if (++arinest == 1) {
14224b88c807SRodney W. Grimes 		prevsyntax = syntax;
14234b88c807SRodney W. Grimes 		syntax = ARISYNTAX;
14244b88c807SRodney W. Grimes 		USTPUTC(CTLARI, out);
14256f47734fSTor Egge 		if (dblquote)
14266f47734fSTor Egge 			USTPUTC('"',out);
14276f47734fSTor Egge 		else
14286f47734fSTor Egge 			USTPUTC(' ',out);
14294b88c807SRodney W. Grimes 	} else {
14304b88c807SRodney W. Grimes 		/*
14314b88c807SRodney W. Grimes 		 * we collapse embedded arithmetic expansion to
14324b88c807SRodney W. Grimes 		 * parenthesis, which should be equivalent
14334b88c807SRodney W. Grimes 		 */
14344b88c807SRodney W. Grimes 		USTPUTC('(', out);
14354b88c807SRodney W. Grimes 	}
14364b88c807SRodney W. Grimes 	goto parsearith_return;
14374b88c807SRodney W. Grimes }
14384b88c807SRodney W. Grimes 
14394b88c807SRodney W. Grimes } /* end of readtoken */
14404b88c807SRodney W. Grimes 
14414b88c807SRodney W. Grimes 
14424b88c807SRodney W. Grimes 
14434b88c807SRodney W. Grimes #ifdef mkinit
14444b88c807SRodney W. Grimes RESET {
14454b88c807SRodney W. Grimes 	tokpushback = 0;
14464b88c807SRodney W. Grimes 	checkkwd = 0;
14474b88c807SRodney W. Grimes }
14484b88c807SRodney W. Grimes #endif
14494b88c807SRodney W. Grimes 
14504b88c807SRodney W. Grimes /*
14514b88c807SRodney W. Grimes  * Returns true if the text contains nothing to expand (no dollar signs
14524b88c807SRodney W. Grimes  * or backquotes).
14534b88c807SRodney W. Grimes  */
14544b88c807SRodney W. Grimes 
14554b88c807SRodney W. Grimes STATIC int
14564b88c807SRodney W. Grimes noexpand(text)
14574b88c807SRodney W. Grimes 	char *text;
14584b88c807SRodney W. Grimes 	{
14597920a31dSSteve Price 	char *p;
14607920a31dSSteve Price 	char c;
14614b88c807SRodney W. Grimes 
14624b88c807SRodney W. Grimes 	p = text;
14634b88c807SRodney W. Grimes 	while ((c = *p++) != '\0') {
14645557a02aSTor Egge 		if ( c == CTLQUOTEMARK)
14655557a02aSTor Egge 			continue;
14664b88c807SRodney W. Grimes 		if (c == CTLESC)
14674b88c807SRodney W. Grimes 			p++;
146873f612b5SMartin Cracauer 		else if (c >= 0 && BASESYNTAX[(int)c] == CCTL)
14694b88c807SRodney W. Grimes 			return 0;
14704b88c807SRodney W. Grimes 	}
14714b88c807SRodney W. Grimes 	return 1;
14724b88c807SRodney W. Grimes }
14734b88c807SRodney W. Grimes 
14744b88c807SRodney W. Grimes 
14754b88c807SRodney W. Grimes /*
14764b88c807SRodney W. Grimes  * Return true if the argument is a legal variable name (a letter or
14774b88c807SRodney W. Grimes  * underscore followed by zero or more letters, underscores, and digits).
14784b88c807SRodney W. Grimes  */
14794b88c807SRodney W. Grimes 
14804b88c807SRodney W. Grimes int
14814b88c807SRodney W. Grimes goodname(name)
14824b88c807SRodney W. Grimes 	char *name;
14834b88c807SRodney W. Grimes 	{
14847920a31dSSteve Price 	char *p;
14854b88c807SRodney W. Grimes 
14864b88c807SRodney W. Grimes 	p = name;
14874b88c807SRodney W. Grimes 	if (! is_name(*p))
14884b88c807SRodney W. Grimes 		return 0;
14894b88c807SRodney W. Grimes 	while (*++p) {
14904b88c807SRodney W. Grimes 		if (! is_in_name(*p))
14914b88c807SRodney W. Grimes 			return 0;
14924b88c807SRodney W. Grimes 	}
14934b88c807SRodney W. Grimes 	return 1;
14944b88c807SRodney W. Grimes }
14954b88c807SRodney W. Grimes 
14964b88c807SRodney W. Grimes 
14974b88c807SRodney W. Grimes /*
14984b88c807SRodney W. Grimes  * Called when an unexpected token is read during the parse.  The argument
14994b88c807SRodney W. Grimes  * is the token that is expected, or -1 if more than one type of token can
15004b88c807SRodney W. Grimes  * occur at this point.
15014b88c807SRodney W. Grimes  */
15024b88c807SRodney W. Grimes 
15034b88c807SRodney W. Grimes STATIC void
1504aa9caaf6SPeter Wemm synexpect(token)
1505aa9caaf6SPeter Wemm 	int token;
1506aa9caaf6SPeter Wemm {
15074b88c807SRodney W. Grimes 	char msg[64];
15084b88c807SRodney W. Grimes 
15094b88c807SRodney W. Grimes 	if (token >= 0) {
15104b88c807SRodney W. Grimes 		fmtstr(msg, 64, "%s unexpected (expecting %s)",
15114b88c807SRodney W. Grimes 			tokname[lasttoken], tokname[token]);
15124b88c807SRodney W. Grimes 	} else {
15134b88c807SRodney W. Grimes 		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
15144b88c807SRodney W. Grimes 	}
15154b88c807SRodney W. Grimes 	synerror(msg);
15164b88c807SRodney W. Grimes }
15174b88c807SRodney W. Grimes 
15184b88c807SRodney W. Grimes 
15194b88c807SRodney W. Grimes STATIC void
15204b88c807SRodney W. Grimes synerror(msg)
15214b88c807SRodney W. Grimes 	char *msg;
15224b88c807SRodney W. Grimes 	{
15234b88c807SRodney W. Grimes 	if (commandname)
15244b88c807SRodney W. Grimes 		outfmt(&errout, "%s: %d: ", commandname, startlinno);
15254b88c807SRodney W. Grimes 	outfmt(&errout, "Syntax error: %s\n", msg);
15264b88c807SRodney W. Grimes 	error((char *)NULL);
15274b88c807SRodney W. Grimes }
15284b88c807SRodney W. Grimes 
15294b88c807SRodney W. Grimes STATIC void
15304b88c807SRodney W. Grimes setprompt(which)
15314b88c807SRodney W. Grimes 	int which;
15324b88c807SRodney W. Grimes 	{
15334b88c807SRodney W. Grimes 	whichprompt = which;
15344b88c807SRodney W. Grimes 
1535aa9caaf6SPeter Wemm #ifndef NO_HISTORY
15364b88c807SRodney W. Grimes 	if (!el)
1537aa9caaf6SPeter Wemm #endif
15384b88c807SRodney W. Grimes 		out2str(getprompt(NULL));
15394b88c807SRodney W. Grimes }
15404b88c807SRodney W. Grimes 
15414b88c807SRodney W. Grimes /*
15424b88c807SRodney W. Grimes  * called by editline -- any expansions to the prompt
15434b88c807SRodney W. Grimes  *    should be added here.
15444b88c807SRodney W. Grimes  */
15454b88c807SRodney W. Grimes char *
15464b88c807SRodney W. Grimes getprompt(unused)
1547e7a0b024SSteve Price 	void *unused __unused;
15484b88c807SRodney W. Grimes {
15494b88c807SRodney W. Grimes 	switch (whichprompt) {
15504b88c807SRodney W. Grimes 	case 0:
15514b88c807SRodney W. Grimes 		return "";
15524b88c807SRodney W. Grimes 	case 1:
15534b88c807SRodney W. Grimes 		return ps1val();
15544b88c807SRodney W. Grimes 	case 2:
15554b88c807SRodney W. Grimes 		return ps2val();
15564b88c807SRodney W. Grimes 	default:
15574b88c807SRodney W. Grimes 		return "<internal prompt error>";
15584b88c807SRodney W. Grimes 	}
15594b88c807SRodney W. Grimes }
1560