xref: /freebsd/bin/sh/parser.c (revision 427748f7df4c95b955328061873a0716a0643b0b)
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
414b88c807SRodney W. Grimes #endif /* not lint */
422749b141SDavid E. O'Brien #include <sys/cdefs.h>
432749b141SDavid E. O'Brien __FBSDID("$FreeBSD$");
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 
1115134c3f7SWarner Losh STATIC union node *list(int);
1125134c3f7SWarner Losh STATIC union node *andor(void);
1135134c3f7SWarner Losh STATIC union node *pipeline(void);
1145134c3f7SWarner Losh STATIC union node *command(void);
1155134c3f7SWarner Losh STATIC union node *simplecmd(union node **, union node *);
1165134c3f7SWarner Losh STATIC union node *makename(void);
1175134c3f7SWarner Losh STATIC void parsefname(void);
1185134c3f7SWarner Losh STATIC void parseheredoc(void);
1195134c3f7SWarner Losh STATIC int peektoken(void);
1205134c3f7SWarner Losh STATIC int readtoken(void);
1215134c3f7SWarner Losh STATIC int xxreadtoken(void);
1225134c3f7SWarner Losh STATIC int readtoken1(int, char const *, char *, int);
1235134c3f7SWarner Losh STATIC int noexpand(char *);
1245134c3f7SWarner Losh STATIC void synexpect(int);
1255134c3f7SWarner Losh STATIC void synerror(char *);
1265134c3f7SWarner Losh STATIC void setprompt(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 *
1355134c3f7SWarner Losh parsecmd(int interact)
136aa9caaf6SPeter Wemm {
1374b88c807SRodney W. Grimes 	int t;
1384b88c807SRodney W. Grimes 
13998e05fd3SMartin Cracauer 	tokpushback = 0;
1404b88c807SRodney W. Grimes 	doprompt = interact;
1414b88c807SRodney W. Grimes 	if (doprompt)
1424b88c807SRodney W. Grimes 		setprompt(1);
1434b88c807SRodney W. Grimes 	else
1444b88c807SRodney W. Grimes 		setprompt(0);
1454b88c807SRodney W. Grimes 	needprompt = 0;
1464b88c807SRodney W. Grimes 	t = readtoken();
1474b88c807SRodney W. Grimes 	if (t == TEOF)
1484b88c807SRodney W. Grimes 		return NEOF;
1494b88c807SRodney W. Grimes 	if (t == TNL)
1504b88c807SRodney W. Grimes 		return NULL;
1514b88c807SRodney W. Grimes 	tokpushback++;
1524b88c807SRodney W. Grimes 	return list(1);
1534b88c807SRodney W. Grimes }
1544b88c807SRodney W. Grimes 
1554b88c807SRodney W. Grimes 
1564b88c807SRodney W. Grimes STATIC union node *
1575134c3f7SWarner Losh list(int nlflag)
158aa9caaf6SPeter Wemm {
1594b88c807SRodney W. Grimes 	union node *n1, *n2, *n3;
160aa9caaf6SPeter Wemm 	int tok;
1614b88c807SRodney W. Grimes 
1624b88c807SRodney W. Grimes 	checkkwd = 2;
1634b88c807SRodney W. Grimes 	if (nlflag == 0 && tokendlist[peektoken()])
1644b88c807SRodney W. Grimes 		return NULL;
165aa9caaf6SPeter Wemm 	n1 = NULL;
1664b88c807SRodney W. Grimes 	for (;;) {
1674b88c807SRodney W. Grimes 		n2 = andor();
168aa9caaf6SPeter Wemm 		tok = readtoken();
169aa9caaf6SPeter Wemm 		if (tok == TBACKGND) {
170aa9caaf6SPeter Wemm 			if (n2->type == NCMD || n2->type == NPIPE) {
171aa9caaf6SPeter Wemm 				n2->ncmd.backgnd = 1;
172aa9caaf6SPeter Wemm 			} else if (n2->type == NREDIR) {
173aa9caaf6SPeter Wemm 				n2->type = NBACKGND;
174aa9caaf6SPeter Wemm 			} else {
175aa9caaf6SPeter Wemm 				n3 = (union node *)stalloc(sizeof (struct nredir));
176aa9caaf6SPeter Wemm 				n3->type = NBACKGND;
177aa9caaf6SPeter Wemm 				n3->nredir.n = n2;
178aa9caaf6SPeter Wemm 				n3->nredir.redirect = NULL;
179aa9caaf6SPeter Wemm 				n2 = n3;
180aa9caaf6SPeter Wemm 			}
181aa9caaf6SPeter Wemm 		}
182aa9caaf6SPeter Wemm 		if (n1 == NULL) {
183aa9caaf6SPeter Wemm 			n1 = n2;
184aa9caaf6SPeter Wemm 		}
185aa9caaf6SPeter Wemm 		else {
1864b88c807SRodney W. Grimes 			n3 = (union node *)stalloc(sizeof (struct nbinary));
1874b88c807SRodney W. Grimes 			n3->type = NSEMI;
1884b88c807SRodney W. Grimes 			n3->nbinary.ch1 = n1;
1894b88c807SRodney W. Grimes 			n3->nbinary.ch2 = n2;
1904b88c807SRodney W. Grimes 			n1 = n3;
191aa9caaf6SPeter Wemm 		}
192aa9caaf6SPeter Wemm 		switch (tok) {
193aa9caaf6SPeter Wemm 		case TBACKGND:
194aa9caaf6SPeter Wemm 		case TSEMI:
195aa9caaf6SPeter Wemm 			tok = readtoken();
1960d9f1a69SPhilippe Charnier 			/* FALLTHROUGH */
197aa9caaf6SPeter Wemm 		case TNL:
198aa9caaf6SPeter Wemm 			if (tok == TNL) {
199aa9caaf6SPeter Wemm 				parseheredoc();
200aa9caaf6SPeter Wemm 				if (nlflag)
201aa9caaf6SPeter Wemm 					return n1;
202aa9caaf6SPeter Wemm 			} else {
203aa9caaf6SPeter Wemm 				tokpushback++;
204aa9caaf6SPeter Wemm 			}
205aa9caaf6SPeter Wemm 			checkkwd = 2;
206aa9caaf6SPeter Wemm 			if (tokendlist[peektoken()])
207aa9caaf6SPeter Wemm 				return n1;
2084b88c807SRodney W. Grimes 			break;
2094b88c807SRodney W. Grimes 		case TEOF:
2104b88c807SRodney W. Grimes 			if (heredoclist)
2114b88c807SRodney W. Grimes 				parseheredoc();
2124b88c807SRodney W. Grimes 			else
2134b88c807SRodney W. Grimes 				pungetc();		/* push back EOF on input */
2144b88c807SRodney W. Grimes 			return n1;
2154b88c807SRodney W. Grimes 		default:
2164b88c807SRodney W. Grimes 			if (nlflag)
2174b88c807SRodney W. Grimes 				synexpect(-1);
2184b88c807SRodney W. Grimes 			tokpushback++;
2194b88c807SRodney W. Grimes 			return n1;
2204b88c807SRodney W. Grimes 		}
2214b88c807SRodney W. Grimes 	}
2224b88c807SRodney W. Grimes }
2234b88c807SRodney W. Grimes 
2244b88c807SRodney W. Grimes 
2254b88c807SRodney W. Grimes 
2264b88c807SRodney W. Grimes STATIC union node *
2275134c3f7SWarner Losh andor(void)
2285134c3f7SWarner Losh {
2294b88c807SRodney W. Grimes 	union node *n1, *n2, *n3;
2304b88c807SRodney W. Grimes 	int t;
2314b88c807SRodney W. Grimes 
2324b88c807SRodney W. Grimes 	n1 = pipeline();
2334b88c807SRodney W. Grimes 	for (;;) {
2344b88c807SRodney W. Grimes 		if ((t = readtoken()) == TAND) {
2354b88c807SRodney W. Grimes 			t = NAND;
2364b88c807SRodney W. Grimes 		} else if (t == TOR) {
2374b88c807SRodney W. Grimes 			t = NOR;
2384b88c807SRodney W. Grimes 		} else {
2394b88c807SRodney W. Grimes 			tokpushback++;
2404b88c807SRodney W. Grimes 			return n1;
2414b88c807SRodney W. Grimes 		}
2424b88c807SRodney W. Grimes 		n2 = pipeline();
2434b88c807SRodney W. Grimes 		n3 = (union node *)stalloc(sizeof (struct nbinary));
2444b88c807SRodney W. Grimes 		n3->type = t;
2454b88c807SRodney W. Grimes 		n3->nbinary.ch1 = n1;
2464b88c807SRodney W. Grimes 		n3->nbinary.ch2 = n2;
2474b88c807SRodney W. Grimes 		n1 = n3;
2484b88c807SRodney W. Grimes 	}
2494b88c807SRodney W. Grimes }
2504b88c807SRodney W. Grimes 
2514b88c807SRodney W. Grimes 
2524b88c807SRodney W. Grimes 
2534b88c807SRodney W. Grimes STATIC union node *
2545134c3f7SWarner Losh pipeline(void)
2555134c3f7SWarner Losh {
256b785bd7dSBrian Somers 	union node *n1, *n2, *pipenode;
2574b88c807SRodney W. Grimes 	struct nodelist *lp, *prev;
258b785bd7dSBrian Somers 	int negate;
2594b88c807SRodney W. Grimes 
260b785bd7dSBrian Somers 	negate = 0;
2614b88c807SRodney W. Grimes 	TRACE(("pipeline: entered\n"));
262b785bd7dSBrian Somers 	while (readtoken() == TNOT)
263b785bd7dSBrian Somers 		negate = !negate;
264b785bd7dSBrian Somers 	tokpushback++;
2654b88c807SRodney W. Grimes 	n1 = command();
2664b88c807SRodney W. Grimes 	if (readtoken() == TPIPE) {
2674b88c807SRodney W. Grimes 		pipenode = (union node *)stalloc(sizeof (struct npipe));
2684b88c807SRodney W. Grimes 		pipenode->type = NPIPE;
2694b88c807SRodney W. Grimes 		pipenode->npipe.backgnd = 0;
2704b88c807SRodney W. Grimes 		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
2714b88c807SRodney W. Grimes 		pipenode->npipe.cmdlist = lp;
2724b88c807SRodney W. Grimes 		lp->n = n1;
2734b88c807SRodney W. Grimes 		do {
2744b88c807SRodney W. Grimes 			prev = lp;
2754b88c807SRodney W. Grimes 			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
2764b88c807SRodney W. Grimes 			lp->n = command();
2774b88c807SRodney W. Grimes 			prev->next = lp;
2784b88c807SRodney W. Grimes 		} while (readtoken() == TPIPE);
2794b88c807SRodney W. Grimes 		lp->next = NULL;
2804b88c807SRodney W. Grimes 		n1 = pipenode;
2814b88c807SRodney W. Grimes 	}
2824b88c807SRodney W. Grimes 	tokpushback++;
283b785bd7dSBrian Somers 	if (negate) {
284b785bd7dSBrian Somers 		n2 = (union node *)stalloc(sizeof (struct nnot));
285b785bd7dSBrian Somers 		n2->type = NNOT;
286b785bd7dSBrian Somers 		n2->nnot.com = n1;
287b785bd7dSBrian Somers 		return n2;
288b785bd7dSBrian Somers 	} else
2894b88c807SRodney W. Grimes 		return n1;
2904b88c807SRodney W. Grimes }
2914b88c807SRodney W. Grimes 
2924b88c807SRodney W. Grimes 
2934b88c807SRodney W. Grimes 
2944b88c807SRodney W. Grimes STATIC union node *
2955134c3f7SWarner Losh command(void)
2965134c3f7SWarner Losh {
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;
3016c0bde79SBrian Somers 	int t, negate = 0;
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 
3166c0bde79SBrian Somers 	while (readtoken() == TNOT) {
3176c0bde79SBrian Somers 		TRACE(("command: TNOT recognized\n"));
3186c0bde79SBrian Somers 		negate = !negate;
3196c0bde79SBrian Somers 	}
3206c0bde79SBrian Somers 	tokpushback++;
3216c0bde79SBrian Somers 
3224b88c807SRodney W. Grimes 	switch (readtoken()) {
3234b88c807SRodney W. Grimes 	case TIF:
3244b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nif));
3254b88c807SRodney W. Grimes 		n1->type = NIF;
326427748f7STim J. Robbins 		if ((n1->nif.test = list(0)) == NULL)
327427748f7STim J. Robbins 			synexpect(-1);
3284b88c807SRodney W. Grimes 		if (readtoken() != TTHEN)
3294b88c807SRodney W. Grimes 			synexpect(TTHEN);
3304b88c807SRodney W. Grimes 		n1->nif.ifpart = list(0);
3314b88c807SRodney W. Grimes 		n2 = n1;
3324b88c807SRodney W. Grimes 		while (readtoken() == TELIF) {
3334b88c807SRodney W. Grimes 			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
3344b88c807SRodney W. Grimes 			n2 = n2->nif.elsepart;
3354b88c807SRodney W. Grimes 			n2->type = NIF;
336427748f7STim J. Robbins 			if ((n2->nif.test = list(0)) == NULL)
337427748f7STim J. Robbins 				synexpect(-1);
3384b88c807SRodney W. Grimes 			if (readtoken() != TTHEN)
3394b88c807SRodney W. Grimes 				synexpect(TTHEN);
3404b88c807SRodney W. Grimes 			n2->nif.ifpart = list(0);
3414b88c807SRodney W. Grimes 		}
3424b88c807SRodney W. Grimes 		if (lasttoken == TELSE)
3434b88c807SRodney W. Grimes 			n2->nif.elsepart = list(0);
3444b88c807SRodney W. Grimes 		else {
3454b88c807SRodney W. Grimes 			n2->nif.elsepart = NULL;
3464b88c807SRodney W. Grimes 			tokpushback++;
3474b88c807SRodney W. Grimes 		}
3484b88c807SRodney W. Grimes 		if (readtoken() != TFI)
3494b88c807SRodney W. Grimes 			synexpect(TFI);
3504b88c807SRodney W. Grimes 		checkkwd = 1;
3514b88c807SRodney W. Grimes 		break;
3524b88c807SRodney W. Grimes 	case TWHILE:
3534b88c807SRodney W. Grimes 	case TUNTIL: {
3544b88c807SRodney W. Grimes 		int got;
3554b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nbinary));
3564b88c807SRodney W. Grimes 		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
357427748f7STim J. Robbins 		if ((n1->nbinary.ch1 = list(0)) == NULL)
358427748f7STim J. Robbins 			synexpect(-1);
3594b88c807SRodney W. Grimes 		if ((got=readtoken()) != TDO) {
3604b88c807SRodney W. Grimes TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
3614b88c807SRodney W. Grimes 			synexpect(TDO);
3624b88c807SRodney W. Grimes 		}
3634b88c807SRodney W. Grimes 		n1->nbinary.ch2 = list(0);
3644b88c807SRodney W. Grimes 		if (readtoken() != TDONE)
3654b88c807SRodney W. Grimes 			synexpect(TDONE);
3664b88c807SRodney W. Grimes 		checkkwd = 1;
3674b88c807SRodney W. Grimes 		break;
3684b88c807SRodney W. Grimes 	}
3694b88c807SRodney W. Grimes 	case TFOR:
3704b88c807SRodney W. Grimes 		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
3714b88c807SRodney W. Grimes 			synerror("Bad for loop variable");
3724b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nfor));
3734b88c807SRodney W. Grimes 		n1->type = NFOR;
3744b88c807SRodney W. Grimes 		n1->nfor.var = wordtext;
3754b88c807SRodney W. Grimes 		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
3764b88c807SRodney W. Grimes 			app = &ap;
3774b88c807SRodney W. Grimes 			while (readtoken() == TWORD) {
3784b88c807SRodney W. Grimes 				n2 = (union node *)stalloc(sizeof (struct narg));
3794b88c807SRodney W. Grimes 				n2->type = NARG;
3804b88c807SRodney W. Grimes 				n2->narg.text = wordtext;
3814b88c807SRodney W. Grimes 				n2->narg.backquote = backquotelist;
3824b88c807SRodney W. Grimes 				*app = n2;
3834b88c807SRodney W. Grimes 				app = &n2->narg.next;
3844b88c807SRodney W. Grimes 			}
3854b88c807SRodney W. Grimes 			*app = NULL;
3864b88c807SRodney W. Grimes 			n1->nfor.args = ap;
3874b88c807SRodney W. Grimes 			if (lasttoken != TNL && lasttoken != TSEMI)
3884b88c807SRodney W. Grimes 				synexpect(-1);
3894b88c807SRodney W. Grimes 		} else {
3904b88c807SRodney W. Grimes #ifndef GDB_HACK
3914b88c807SRodney W. Grimes 			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
3924b88c807SRodney W. Grimes 								   '@', '=', '\0'};
3934b88c807SRodney W. Grimes #endif
3944b88c807SRodney W. Grimes 			n2 = (union node *)stalloc(sizeof (struct narg));
3954b88c807SRodney W. Grimes 			n2->type = NARG;
3964b88c807SRodney W. Grimes 			n2->narg.text = (char *)argvars;
3974b88c807SRodney W. Grimes 			n2->narg.backquote = NULL;
3984b88c807SRodney W. Grimes 			n2->narg.next = NULL;
3994b88c807SRodney W. Grimes 			n1->nfor.args = n2;
4004b88c807SRodney W. Grimes 			/*
4014b88c807SRodney W. Grimes 			 * Newline or semicolon here is optional (but note
4024b88c807SRodney W. Grimes 			 * that the original Bourne shell only allowed NL).
4034b88c807SRodney W. Grimes 			 */
4044b88c807SRodney W. Grimes 			if (lasttoken != TNL && lasttoken != TSEMI)
4054b88c807SRodney W. Grimes 				tokpushback++;
4064b88c807SRodney W. Grimes 		}
4074b88c807SRodney W. Grimes 		checkkwd = 2;
4084b88c807SRodney W. Grimes 		if ((t = readtoken()) == TDO)
4094b88c807SRodney W. Grimes 			t = TDONE;
4104b88c807SRodney W. Grimes 		else if (t == TBEGIN)
4114b88c807SRodney W. Grimes 			t = TEND;
4124b88c807SRodney W. Grimes 		else
4134b88c807SRodney W. Grimes 			synexpect(-1);
4144b88c807SRodney W. Grimes 		n1->nfor.body = list(0);
4154b88c807SRodney W. Grimes 		if (readtoken() != t)
4164b88c807SRodney W. Grimes 			synexpect(t);
4174b88c807SRodney W. Grimes 		checkkwd = 1;
4184b88c807SRodney W. Grimes 		break;
4194b88c807SRodney W. Grimes 	case TCASE:
4204b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct ncase));
4214b88c807SRodney W. Grimes 		n1->type = NCASE;
4224b88c807SRodney W. Grimes 		if (readtoken() != TWORD)
4234b88c807SRodney W. Grimes 			synexpect(TWORD);
4244b88c807SRodney W. Grimes 		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
4254b88c807SRodney W. Grimes 		n2->type = NARG;
4264b88c807SRodney W. Grimes 		n2->narg.text = wordtext;
4274b88c807SRodney W. Grimes 		n2->narg.backquote = backquotelist;
4284b88c807SRodney W. Grimes 		n2->narg.next = NULL;
4294b88c807SRodney W. Grimes 		while (readtoken() == TNL);
4304b88c807SRodney W. Grimes 		if (lasttoken != TWORD || ! equal(wordtext, "in"))
4314b88c807SRodney W. Grimes 			synerror("expecting \"in\"");
4324b88c807SRodney W. Grimes 		cpp = &n1->ncase.cases;
4334417f629SPeter Wemm 		noaliases = 1;	/* turn off alias expansion */
434650488feSSean Eric Fagan 		checkkwd = 2, readtoken();
435e00e16adSTim J. Robbins 		while (lasttoken != TESAC) {
4364b88c807SRodney W. Grimes 			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
4374b88c807SRodney W. Grimes 			cp->type = NCLIST;
4384b88c807SRodney W. Grimes 			app = &cp->nclist.pattern;
439f7a9b7feSTim J. Robbins 			if (lasttoken == TLP)
440f7a9b7feSTim J. Robbins 				readtoken();
4414b88c807SRodney W. Grimes 			for (;;) {
4424b88c807SRodney W. Grimes 				*app = ap = (union node *)stalloc(sizeof (struct narg));
4434b88c807SRodney W. Grimes 				ap->type = NARG;
4444b88c807SRodney W. Grimes 				ap->narg.text = wordtext;
4454b88c807SRodney W. Grimes 				ap->narg.backquote = backquotelist;
446650488feSSean Eric Fagan 				if (checkkwd = 2, readtoken() != TPIPE)
4474b88c807SRodney W. Grimes 					break;
4484b88c807SRodney W. Grimes 				app = &ap->narg.next;
449650488feSSean Eric Fagan 				readtoken();
4504b88c807SRodney W. Grimes 			}
4514b88c807SRodney W. Grimes 			ap->narg.next = NULL;
4524b88c807SRodney W. Grimes 			if (lasttoken != TRP)
4534417f629SPeter Wemm 				noaliases = 0, synexpect(TRP);
4544b88c807SRodney W. Grimes 			cp->nclist.body = list(0);
455650488feSSean Eric Fagan 
456650488feSSean Eric Fagan 			checkkwd = 2;
457650488feSSean Eric Fagan 			if ((t = readtoken()) != TESAC) {
458650488feSSean Eric Fagan 				if (t != TENDCASE)
4594417f629SPeter Wemm 					noaliases = 0, synexpect(TENDCASE);
460650488feSSean Eric Fagan 				else
461650488feSSean Eric Fagan 					checkkwd = 2, readtoken();
4624b88c807SRodney W. Grimes 			}
463650488feSSean Eric Fagan 			cpp = &cp->nclist.next;
464e00e16adSTim J. Robbins 		}
4654417f629SPeter Wemm 		noaliases = 0;	/* reset alias expansion */
4664b88c807SRodney W. Grimes 		*cpp = NULL;
4674b88c807SRodney W. Grimes 		checkkwd = 1;
4684b88c807SRodney W. Grimes 		break;
4694b88c807SRodney W. Grimes 	case TLP:
4704b88c807SRodney W. Grimes 		n1 = (union node *)stalloc(sizeof (struct nredir));
4714b88c807SRodney W. Grimes 		n1->type = NSUBSHELL;
4724b88c807SRodney W. Grimes 		n1->nredir.n = list(0);
4734b88c807SRodney W. Grimes 		n1->nredir.redirect = NULL;
4744b88c807SRodney W. Grimes 		if (readtoken() != TRP)
4754b88c807SRodney W. Grimes 			synexpect(TRP);
4764b88c807SRodney W. Grimes 		checkkwd = 1;
4774b88c807SRodney W. Grimes 		break;
4784b88c807SRodney W. Grimes 	case TBEGIN:
4794b88c807SRodney W. Grimes 		n1 = list(0);
4804b88c807SRodney W. Grimes 		if (readtoken() != TEND)
4814b88c807SRodney W. Grimes 			synexpect(TEND);
4824b88c807SRodney W. Grimes 		checkkwd = 1;
4834b88c807SRodney W. Grimes 		break;
4844b88c807SRodney W. Grimes 	/* Handle an empty command like other simple commands.  */
485248ffae5SJoerg Wunsch 	case TSEMI:
486d8d737d7STim J. Robbins 	case TAND:
487d8d737d7STim J. Robbins 	case TOR:
488aa9caaf6SPeter Wemm 		/*
489aa9caaf6SPeter Wemm 		 * An empty command before a ; doesn't make much sense, and
490aa9caaf6SPeter Wemm 		 * should certainly be disallowed in the case of `if ;'.
491aa9caaf6SPeter Wemm 		 */
492aa9caaf6SPeter Wemm 		if (!redir)
493aa9caaf6SPeter Wemm 			synexpect(-1);
494aa9caaf6SPeter Wemm 	case TNL:
495248ffae5SJoerg Wunsch 	case TEOF:
4964b88c807SRodney W. Grimes 	case TWORD:
497aa9caaf6SPeter Wemm 	case TRP:
4984b88c807SRodney W. Grimes 		tokpushback++;
4996c0bde79SBrian Somers 		n1 = simplecmd(rpp, redir);
5006c0bde79SBrian Somers 		goto checkneg;
5014b88c807SRodney W. Grimes 	default:
5024b88c807SRodney W. Grimes 		synexpect(-1);
5034b88c807SRodney W. Grimes 	}
5044b88c807SRodney W. Grimes 
5054b88c807SRodney W. Grimes 	/* Now check for redirection which may follow command */
5064b88c807SRodney W. Grimes 	while (readtoken() == TREDIR) {
5074b88c807SRodney W. Grimes 		*rpp = n2 = redirnode;
5084b88c807SRodney W. Grimes 		rpp = &n2->nfile.next;
5094b88c807SRodney W. Grimes 		parsefname();
5104b88c807SRodney W. Grimes 	}
5114b88c807SRodney W. Grimes 	tokpushback++;
5124b88c807SRodney W. Grimes 	*rpp = NULL;
5134b88c807SRodney W. Grimes 	if (redir) {
5144b88c807SRodney W. Grimes 		if (n1->type != NSUBSHELL) {
5154b88c807SRodney W. Grimes 			n2 = (union node *)stalloc(sizeof (struct nredir));
5164b88c807SRodney W. Grimes 			n2->type = NREDIR;
5174b88c807SRodney W. Grimes 			n2->nredir.n = n1;
5184b88c807SRodney W. Grimes 			n1 = n2;
5194b88c807SRodney W. Grimes 		}
5204b88c807SRodney W. Grimes 		n1->nredir.redirect = redir;
5214b88c807SRodney W. Grimes 	}
5226c0bde79SBrian Somers 
5236c0bde79SBrian Somers checkneg:
5246c0bde79SBrian Somers 	if (negate) {
5256c0bde79SBrian Somers 		n2 = (union node *)stalloc(sizeof (struct nnot));
5266c0bde79SBrian Somers 		n2->type = NNOT;
5276c0bde79SBrian Somers 		n2->nnot.com = n1;
5286c0bde79SBrian Somers 		return n2;
5296c0bde79SBrian Somers 	}
5306c0bde79SBrian Somers 	else
5314b88c807SRodney W. Grimes 		return n1;
5324b88c807SRodney W. Grimes }
5334b88c807SRodney W. Grimes 
5344b88c807SRodney W. Grimes 
5354b88c807SRodney W. Grimes STATIC union node *
5365134c3f7SWarner Losh simplecmd(union node **rpp, union node *redir)
5374b88c807SRodney W. Grimes {
5384b88c807SRodney W. Grimes 	union node *args, **app;
5394b88c807SRodney W. Grimes 	union node **orig_rpp = rpp;
5406c0bde79SBrian Somers 	union node *n = NULL, *n2;
5416c0bde79SBrian Somers 	int negate = 0;
5424b88c807SRodney W. Grimes 
5434b88c807SRodney W. Grimes 	/* If we don't have any redirections already, then we must reset */
5444b88c807SRodney W. Grimes 	/* rpp to be the address of the local redir variable.  */
5454b88c807SRodney W. Grimes 	if (redir == 0)
5464b88c807SRodney W. Grimes 		rpp = &redir;
5474b88c807SRodney W. Grimes 
5484b88c807SRodney W. Grimes 	args = NULL;
5494b88c807SRodney W. Grimes 	app = &args;
5504b88c807SRodney W. Grimes 	/*
5514b88c807SRodney W. Grimes 	 * We save the incoming value, because we need this for shell
5524b88c807SRodney W. Grimes 	 * functions.  There can not be a redirect or an argument between
5534b88c807SRodney W. Grimes 	 * the function name and the open parenthesis.
5544b88c807SRodney W. Grimes 	 */
5554b88c807SRodney W. Grimes 	orig_rpp = rpp;
5564b88c807SRodney W. Grimes 
5576c0bde79SBrian Somers 	while (readtoken() == TNOT) {
5586c0bde79SBrian Somers 		TRACE(("command: TNOT recognized\n"));
5596c0bde79SBrian Somers 		negate = !negate;
5606c0bde79SBrian Somers 	}
5616c0bde79SBrian Somers 	tokpushback++;
5626c0bde79SBrian Somers 
5634b88c807SRodney W. Grimes 	for (;;) {
5644b88c807SRodney W. Grimes 		if (readtoken() == TWORD) {
5654b88c807SRodney W. Grimes 			n = (union node *)stalloc(sizeof (struct narg));
5664b88c807SRodney W. Grimes 			n->type = NARG;
5674b88c807SRodney W. Grimes 			n->narg.text = wordtext;
5684b88c807SRodney W. Grimes 			n->narg.backquote = backquotelist;
5694b88c807SRodney W. Grimes 			*app = n;
5704b88c807SRodney W. Grimes 			app = &n->narg.next;
5714b88c807SRodney W. Grimes 		} else if (lasttoken == TREDIR) {
5724b88c807SRodney W. Grimes 			*rpp = n = redirnode;
5734b88c807SRodney W. Grimes 			rpp = &n->nfile.next;
5744b88c807SRodney W. Grimes 			parsefname();	/* read name of redirection file */
5754b88c807SRodney W. Grimes 		} else if (lasttoken == TLP && app == &args->narg.next
5764b88c807SRodney W. Grimes 					    && rpp == orig_rpp) {
5774b88c807SRodney W. Grimes 			/* We have a function */
5784b88c807SRodney W. Grimes 			if (readtoken() != TRP)
5794b88c807SRodney W. Grimes 				synexpect(TRP);
5804b88c807SRodney W. Grimes #ifdef notdef
5814b88c807SRodney W. Grimes 			if (! goodname(n->narg.text))
5824b88c807SRodney W. Grimes 				synerror("Bad function name");
5834b88c807SRodney W. Grimes #endif
5844b88c807SRodney W. Grimes 			n->type = NDEFUN;
5854b88c807SRodney W. Grimes 			n->narg.next = command();
5866c0bde79SBrian Somers 			goto checkneg;
5874b88c807SRodney W. Grimes 		} else {
5884b88c807SRodney W. Grimes 			tokpushback++;
5894b88c807SRodney W. Grimes 			break;
5904b88c807SRodney W. Grimes 		}
5914b88c807SRodney W. Grimes 	}
5924b88c807SRodney W. Grimes 	*app = NULL;
5934b88c807SRodney W. Grimes 	*rpp = NULL;
5944b88c807SRodney W. Grimes 	n = (union node *)stalloc(sizeof (struct ncmd));
5954b88c807SRodney W. Grimes 	n->type = NCMD;
5964b88c807SRodney W. Grimes 	n->ncmd.backgnd = 0;
5974b88c807SRodney W. Grimes 	n->ncmd.args = args;
5984b88c807SRodney W. Grimes 	n->ncmd.redirect = redir;
5996c0bde79SBrian Somers 
6006c0bde79SBrian Somers checkneg:
6016c0bde79SBrian Somers 	if (negate) {
6026c0bde79SBrian Somers 		n2 = (union node *)stalloc(sizeof (struct nnot));
6036c0bde79SBrian Somers 		n2->type = NNOT;
6046c0bde79SBrian Somers 		n2->nnot.com = n;
6056c0bde79SBrian Somers 		return n2;
6066c0bde79SBrian Somers 	}
6076c0bde79SBrian Somers 	else
6084b88c807SRodney W. Grimes 		return n;
6094b88c807SRodney W. Grimes }
6104b88c807SRodney W. Grimes 
611aa9caaf6SPeter Wemm STATIC union node *
6125134c3f7SWarner Losh makename(void)
6135134c3f7SWarner Losh {
614aa9caaf6SPeter Wemm 	union node *n;
615aa9caaf6SPeter Wemm 
616aa9caaf6SPeter Wemm 	n = (union node *)stalloc(sizeof (struct narg));
617aa9caaf6SPeter Wemm 	n->type = NARG;
618aa9caaf6SPeter Wemm 	n->narg.next = NULL;
619aa9caaf6SPeter Wemm 	n->narg.text = wordtext;
620aa9caaf6SPeter Wemm 	n->narg.backquote = backquotelist;
621aa9caaf6SPeter Wemm 	return n;
622aa9caaf6SPeter Wemm }
623aa9caaf6SPeter Wemm 
6245134c3f7SWarner Losh void fixredir(union node *n, const char *text, int err)
625aa9caaf6SPeter Wemm {
626aa9caaf6SPeter Wemm 	TRACE(("Fix redir %s %d\n", text, err));
627aa9caaf6SPeter Wemm 	if (!err)
628aa9caaf6SPeter Wemm 		n->ndup.vname = NULL;
629aa9caaf6SPeter Wemm 
630aa9caaf6SPeter Wemm 	if (is_digit(text[0]) && text[1] == '\0')
631aa9caaf6SPeter Wemm 		n->ndup.dupfd = digit_val(text[0]);
632aa9caaf6SPeter Wemm 	else if (text[0] == '-' && text[1] == '\0')
633aa9caaf6SPeter Wemm 		n->ndup.dupfd = -1;
634aa9caaf6SPeter Wemm 	else {
635aa9caaf6SPeter Wemm 
636aa9caaf6SPeter Wemm 		if (err)
637aa9caaf6SPeter Wemm 			synerror("Bad fd number");
638aa9caaf6SPeter Wemm 		else
639aa9caaf6SPeter Wemm 			n->ndup.vname = makename();
640aa9caaf6SPeter Wemm 	}
641aa9caaf6SPeter Wemm }
642aa9caaf6SPeter Wemm 
6434b88c807SRodney W. Grimes 
6444b88c807SRodney W. Grimes STATIC void
6455134c3f7SWarner Losh parsefname(void)
6465134c3f7SWarner Losh {
6474b88c807SRodney W. Grimes 	union node *n = redirnode;
6484b88c807SRodney W. Grimes 
6494b88c807SRodney W. Grimes 	if (readtoken() != TWORD)
6504b88c807SRodney W. Grimes 		synexpect(-1);
6514b88c807SRodney W. Grimes 	if (n->type == NHERE) {
6524b88c807SRodney W. Grimes 		struct heredoc *here = heredoc;
6534b88c807SRodney W. Grimes 		struct heredoc *p;
6544b88c807SRodney W. Grimes 		int i;
6554b88c807SRodney W. Grimes 
6564b88c807SRodney W. Grimes 		if (quoteflag == 0)
6574b88c807SRodney W. Grimes 			n->type = NXHERE;
6584b88c807SRodney W. Grimes 		TRACE(("Here document %d\n", n->type));
6594b88c807SRodney W. Grimes 		if (here->striptabs) {
6604b88c807SRodney W. Grimes 			while (*wordtext == '\t')
6614b88c807SRodney W. Grimes 				wordtext++;
6624b88c807SRodney W. Grimes 		}
6634b88c807SRodney W. Grimes 		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
6644b88c807SRodney W. Grimes 			synerror("Illegal eof marker for << redirection");
6654b88c807SRodney W. Grimes 		rmescapes(wordtext);
6664b88c807SRodney W. Grimes 		here->eofmark = wordtext;
6674b88c807SRodney W. Grimes 		here->next = NULL;
6684b88c807SRodney W. Grimes 		if (heredoclist == NULL)
6694b88c807SRodney W. Grimes 			heredoclist = here;
6704b88c807SRodney W. Grimes 		else {
6714b88c807SRodney W. Grimes 			for (p = heredoclist ; p->next ; p = p->next);
6724b88c807SRodney W. Grimes 			p->next = here;
6734b88c807SRodney W. Grimes 		}
6744b88c807SRodney W. Grimes 	} else if (n->type == NTOFD || n->type == NFROMFD) {
675aa9caaf6SPeter Wemm 		fixredir(n, wordtext, 0);
6764b88c807SRodney W. Grimes 	} else {
677aa9caaf6SPeter Wemm 		n->nfile.fname = makename();
6784b88c807SRodney W. Grimes 	}
6794b88c807SRodney W. Grimes }
6804b88c807SRodney W. Grimes 
6814b88c807SRodney W. Grimes 
6824b88c807SRodney W. Grimes /*
6834b88c807SRodney W. Grimes  * Input any here documents.
6844b88c807SRodney W. Grimes  */
6854b88c807SRodney W. Grimes 
6864b88c807SRodney W. Grimes STATIC void
6875134c3f7SWarner Losh parseheredoc(void)
6885134c3f7SWarner Losh {
6894b88c807SRodney W. Grimes 	struct heredoc *here;
6904b88c807SRodney W. Grimes 	union node *n;
6914b88c807SRodney W. Grimes 
6924b88c807SRodney W. Grimes 	while (heredoclist) {
6934b88c807SRodney W. Grimes 		here = heredoclist;
6944b88c807SRodney W. Grimes 		heredoclist = here->next;
6954b88c807SRodney W. Grimes 		if (needprompt) {
6964b88c807SRodney W. Grimes 			setprompt(2);
6974b88c807SRodney W. Grimes 			needprompt = 0;
6984b88c807SRodney W. Grimes 		}
6994b88c807SRodney W. Grimes 		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
7004b88c807SRodney W. Grimes 				here->eofmark, here->striptabs);
7014b88c807SRodney W. Grimes 		n = (union node *)stalloc(sizeof (struct narg));
7024b88c807SRodney W. Grimes 		n->narg.type = NARG;
7034b88c807SRodney W. Grimes 		n->narg.next = NULL;
7044b88c807SRodney W. Grimes 		n->narg.text = wordtext;
7054b88c807SRodney W. Grimes 		n->narg.backquote = backquotelist;
7064b88c807SRodney W. Grimes 		here->here->nhere.doc = n;
7074b88c807SRodney W. Grimes 	}
7084b88c807SRodney W. Grimes }
7094b88c807SRodney W. Grimes 
7104b88c807SRodney W. Grimes STATIC int
7115134c3f7SWarner Losh peektoken(void)
7125134c3f7SWarner Losh {
7134b88c807SRodney W. Grimes 	int t;
7144b88c807SRodney W. Grimes 
7154b88c807SRodney W. Grimes 	t = readtoken();
7164b88c807SRodney W. Grimes 	tokpushback++;
7174b88c807SRodney W. Grimes 	return (t);
7184b88c807SRodney W. Grimes }
7194b88c807SRodney W. Grimes 
7204b88c807SRodney W. Grimes STATIC int
7215134c3f7SWarner Losh readtoken(void)
7225134c3f7SWarner Losh {
7234b88c807SRodney W. Grimes 	int t;
7244b88c807SRodney W. Grimes 	int savecheckkwd = checkkwd;
7254b88c807SRodney W. Grimes 	struct alias *ap;
7264b88c807SRodney W. Grimes #ifdef DEBUG
7274b88c807SRodney W. Grimes 	int alreadyseen = tokpushback;
7284b88c807SRodney W. Grimes #endif
7294b88c807SRodney W. Grimes 
7304b88c807SRodney W. Grimes 	top:
7314b88c807SRodney W. Grimes 	t = xxreadtoken();
7324b88c807SRodney W. Grimes 
7334b88c807SRodney W. Grimes 	if (checkkwd) {
7344b88c807SRodney W. Grimes 		/*
7354b88c807SRodney W. Grimes 		 * eat newlines
7364b88c807SRodney W. Grimes 		 */
7374b88c807SRodney W. Grimes 		if (checkkwd == 2) {
7384b88c807SRodney W. Grimes 			checkkwd = 0;
7394b88c807SRodney W. Grimes 			while (t == TNL) {
7404b88c807SRodney W. Grimes 				parseheredoc();
7414b88c807SRodney W. Grimes 				t = xxreadtoken();
7424b88c807SRodney W. Grimes 			}
7434b88c807SRodney W. Grimes 		} else
7444b88c807SRodney W. Grimes 			checkkwd = 0;
7454b88c807SRodney W. Grimes 		/*
7464b88c807SRodney W. Grimes 		 * check for keywords and aliases
7474b88c807SRodney W. Grimes 		 */
748aa9caaf6SPeter Wemm 		if (t == TWORD && !quoteflag)
749aa9caaf6SPeter Wemm 		{
7508b7808bcSJuli Mallett 			const char * const *pp;
7514b88c807SRodney W. Grimes 
7528b7808bcSJuli Mallett 			for (pp = parsekwd; *pp; pp++) {
753aa9caaf6SPeter Wemm 				if (**pp == *wordtext && equal(*pp, wordtext))
754aa9caaf6SPeter Wemm 				{
7554b88c807SRodney W. Grimes 					lasttoken = t = pp - parsekwd + KWDOFFSET;
7564b88c807SRodney W. Grimes 					TRACE(("keyword %s recognized\n", tokname[t]));
7574b88c807SRodney W. Grimes 					goto out;
7584b88c807SRodney W. Grimes 				}
7594b88c807SRodney W. Grimes 			}
7604417f629SPeter Wemm 			if (noaliases == 0 &&
7614417f629SPeter Wemm 			    (ap = lookupalias(wordtext, 1)) != NULL) {
7624b88c807SRodney W. Grimes 				pushstring(ap->val, strlen(ap->val), ap);
7634b88c807SRodney W. Grimes 				checkkwd = savecheckkwd;
7644b88c807SRodney W. Grimes 				goto top;
7654b88c807SRodney W. Grimes 			}
7664b88c807SRodney W. Grimes 		}
7674b88c807SRodney W. Grimes out:
7686c0bde79SBrian Somers 		checkkwd = (t == TNOT) ? savecheckkwd : 0;
7694b88c807SRodney W. Grimes 	}
7704b88c807SRodney W. Grimes #ifdef DEBUG
7714b88c807SRodney W. Grimes 	if (!alreadyseen)
7724b88c807SRodney W. Grimes 	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
7734b88c807SRodney W. Grimes 	else
7744b88c807SRodney W. Grimes 	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
7754b88c807SRodney W. Grimes #endif
7764b88c807SRodney W. Grimes 	return (t);
7774b88c807SRodney W. Grimes }
7784b88c807SRodney W. Grimes 
7794b88c807SRodney W. Grimes 
7804b88c807SRodney W. Grimes /*
7814b88c807SRodney W. Grimes  * Read the next input token.
7824b88c807SRodney W. Grimes  * If the token is a word, we set backquotelist to the list of cmds in
7834b88c807SRodney W. Grimes  *	backquotes.  We set quoteflag to true if any part of the word was
7844b88c807SRodney W. Grimes  *	quoted.
7854b88c807SRodney W. Grimes  * If the token is TREDIR, then we set redirnode to a structure containing
7864b88c807SRodney W. Grimes  *	the redirection.
7874b88c807SRodney W. Grimes  * In all cases, the variable startlinno is set to the number of the line
7884b88c807SRodney W. Grimes  *	on which the token starts.
7894b88c807SRodney W. Grimes  *
7904b88c807SRodney W. Grimes  * [Change comment:  here documents and internal procedures]
7914b88c807SRodney W. Grimes  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
7924b88c807SRodney W. Grimes  *  word parsing code into a separate routine.  In this case, readtoken
7934b88c807SRodney W. Grimes  *  doesn't need to have any internal procedures, but parseword does.
7944b88c807SRodney W. Grimes  *  We could also make parseoperator in essence the main routine, and
7954b88c807SRodney W. Grimes  *  have parseword (readtoken1?) handle both words and redirection.]
7964b88c807SRodney W. Grimes  */
7974b88c807SRodney W. Grimes 
7984b88c807SRodney W. Grimes #define RETURN(token)	return lasttoken = token
7994b88c807SRodney W. Grimes 
8004b88c807SRodney W. Grimes STATIC int
8015134c3f7SWarner Losh xxreadtoken(void)
8025134c3f7SWarner Losh {
8037920a31dSSteve Price 	int c;
8044b88c807SRodney W. Grimes 
8054b88c807SRodney W. Grimes 	if (tokpushback) {
8064b88c807SRodney W. Grimes 		tokpushback = 0;
8074b88c807SRodney W. Grimes 		return lasttoken;
8084b88c807SRodney W. Grimes 	}
8094b88c807SRodney W. Grimes 	if (needprompt) {
8104b88c807SRodney W. Grimes 		setprompt(2);
8114b88c807SRodney W. Grimes 		needprompt = 0;
8124b88c807SRodney W. Grimes 	}
8134b88c807SRodney W. Grimes 	startlinno = plinno;
8144b88c807SRodney W. Grimes 	for (;;) {	/* until token or start of word found */
8154b88c807SRodney W. Grimes 		c = pgetc_macro();
8164b88c807SRodney W. Grimes 		if (c == ' ' || c == '\t')
8174b88c807SRodney W. Grimes 			continue;		/* quick check for white space first */
8184b88c807SRodney W. Grimes 		switch (c) {
8194b88c807SRodney W. Grimes 		case ' ': case '\t':
8204b88c807SRodney W. Grimes 			continue;
8214b88c807SRodney W. Grimes 		case '#':
8224b88c807SRodney W. Grimes 			while ((c = pgetc()) != '\n' && c != PEOF);
8234b88c807SRodney W. Grimes 			pungetc();
8244b88c807SRodney W. Grimes 			continue;
8254b88c807SRodney W. Grimes 		case '\\':
8264b88c807SRodney W. Grimes 			if (pgetc() == '\n') {
8274b88c807SRodney W. Grimes 				startlinno = ++plinno;
8284b88c807SRodney W. Grimes 				if (doprompt)
8294b88c807SRodney W. Grimes 					setprompt(2);
8304b88c807SRodney W. Grimes 				else
8314b88c807SRodney W. Grimes 					setprompt(0);
8324b88c807SRodney W. Grimes 				continue;
8334b88c807SRodney W. Grimes 			}
8344b88c807SRodney W. Grimes 			pungetc();
8354b88c807SRodney W. Grimes 			goto breakloop;
8364b88c807SRodney W. Grimes 		case '\n':
8374b88c807SRodney W. Grimes 			plinno++;
8384b88c807SRodney W. Grimes 			needprompt = doprompt;
8394b88c807SRodney W. Grimes 			RETURN(TNL);
8404b88c807SRodney W. Grimes 		case PEOF:
8414b88c807SRodney W. Grimes 			RETURN(TEOF);
8424b88c807SRodney W. Grimes 		case '&':
8434b88c807SRodney W. Grimes 			if (pgetc() == '&')
8444b88c807SRodney W. Grimes 				RETURN(TAND);
8454b88c807SRodney W. Grimes 			pungetc();
8464b88c807SRodney W. Grimes 			RETURN(TBACKGND);
8474b88c807SRodney W. Grimes 		case '|':
8484b88c807SRodney W. Grimes 			if (pgetc() == '|')
8494b88c807SRodney W. Grimes 				RETURN(TOR);
8504b88c807SRodney W. Grimes 			pungetc();
8514b88c807SRodney W. Grimes 			RETURN(TPIPE);
8524b88c807SRodney W. Grimes 		case ';':
8534b88c807SRodney W. Grimes 			if (pgetc() == ';')
8544b88c807SRodney W. Grimes 				RETURN(TENDCASE);
8554b88c807SRodney W. Grimes 			pungetc();
8564b88c807SRodney W. Grimes 			RETURN(TSEMI);
8574b88c807SRodney W. Grimes 		case '(':
8584b88c807SRodney W. Grimes 			RETURN(TLP);
8594b88c807SRodney W. Grimes 		case ')':
8604b88c807SRodney W. Grimes 			RETURN(TRP);
8614b88c807SRodney W. Grimes 		default:
8624b88c807SRodney W. Grimes 			goto breakloop;
8634b88c807SRodney W. Grimes 		}
8644b88c807SRodney W. Grimes 	}
8654b88c807SRodney W. Grimes breakloop:
8664b88c807SRodney W. Grimes 	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
8674b88c807SRodney W. Grimes #undef RETURN
8684b88c807SRodney W. Grimes }
8694b88c807SRodney W. Grimes 
8704b88c807SRodney W. Grimes 
8714b88c807SRodney W. Grimes 
8724b88c807SRodney W. Grimes /*
8734b88c807SRodney W. Grimes  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
8744b88c807SRodney W. Grimes  * is not NULL, read a here document.  In the latter case, eofmark is the
8754b88c807SRodney W. Grimes  * word which marks the end of the document and striptabs is true if
8764b88c807SRodney W. Grimes  * leading tabs should be stripped from the document.  The argument firstc
8774b88c807SRodney W. Grimes  * is the first character of the input token or document.
8784b88c807SRodney W. Grimes  *
8794b88c807SRodney W. Grimes  * Because C does not have internal subroutines, I have simulated them
8804b88c807SRodney W. Grimes  * using goto's to implement the subroutine linkage.  The following macros
8814b88c807SRodney W. Grimes  * will run code that appears at the end of readtoken1.
8824b88c807SRodney W. Grimes  */
8834b88c807SRodney W. Grimes 
8844b88c807SRodney W. Grimes #define CHECKEND()	{goto checkend; checkend_return:;}
8854b88c807SRodney W. Grimes #define PARSEREDIR()	{goto parseredir; parseredir_return:;}
8864b88c807SRodney W. Grimes #define PARSESUB()	{goto parsesub; parsesub_return:;}
8874b88c807SRodney W. Grimes #define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
8884b88c807SRodney W. Grimes #define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
8894b88c807SRodney W. Grimes #define	PARSEARITH()	{goto parsearith; parsearith_return:;}
8904b88c807SRodney W. Grimes 
8914b88c807SRodney W. Grimes STATIC int
8925134c3f7SWarner Losh readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
8934b88c807SRodney W. Grimes {
894aa9caaf6SPeter Wemm 	int c = firstc;
895aa9caaf6SPeter Wemm 	char *out;
8964b88c807SRodney W. Grimes 	int len;
8974b88c807SRodney W. Grimes 	char line[EOFMARKLEN + 1];
8984b88c807SRodney W. Grimes 	struct nodelist *bqlist;
8994b88c807SRodney W. Grimes 	int quotef;
9004b88c807SRodney W. Grimes 	int dblquote;
9014b88c807SRodney W. Grimes 	int varnest;	/* levels of variables expansion */
9024b88c807SRodney W. Grimes 	int arinest;	/* levels of arithmetic expansion */
9034b88c807SRodney W. Grimes 	int parenlevel;	/* levels of parens in arithmetic */
9044b88c807SRodney W. Grimes 	int oldstyle;
9054b88c807SRodney W. Grimes 	char const *prevsyntax;	/* syntax before arithmetic */
9062dde9ce3SMartin Cracauer 	int synentry;
907aa9caaf6SPeter Wemm #if __GNUC__
908aa9caaf6SPeter Wemm 	/* Avoid longjmp clobbering */
909aa9caaf6SPeter Wemm 	(void) &out;
910aa9caaf6SPeter Wemm 	(void) &quotef;
911aa9caaf6SPeter Wemm 	(void) &dblquote;
912aa9caaf6SPeter Wemm 	(void) &varnest;
913aa9caaf6SPeter Wemm 	(void) &arinest;
914aa9caaf6SPeter Wemm 	(void) &parenlevel;
915aa9caaf6SPeter Wemm 	(void) &oldstyle;
916aa9caaf6SPeter Wemm 	(void) &prevsyntax;
917aa9caaf6SPeter Wemm 	(void) &syntax;
9182dde9ce3SMartin Cracauer 	(void) &synentry;
919aa9caaf6SPeter Wemm #endif
9204b88c807SRodney W. Grimes 
9214b88c807SRodney W. Grimes 	startlinno = plinno;
9224b88c807SRodney W. Grimes 	dblquote = 0;
9234b88c807SRodney W. Grimes 	if (syntax == DQSYNTAX)
9244b88c807SRodney W. Grimes 		dblquote = 1;
9254b88c807SRodney W. Grimes 	quotef = 0;
9264b88c807SRodney W. Grimes 	bqlist = NULL;
9274b88c807SRodney W. Grimes 	varnest = 0;
9284b88c807SRodney W. Grimes 	arinest = 0;
9294b88c807SRodney W. Grimes 	parenlevel = 0;
9304b88c807SRodney W. Grimes 
9314b88c807SRodney W. Grimes 	STARTSTACKSTR(out);
9324b88c807SRodney W. Grimes 	loop: {	/* for each line, until end of word */
9334b88c807SRodney W. Grimes 		CHECKEND();	/* set c to PEOF if at end of here document */
9344b88c807SRodney W. Grimes 		for (;;) {	/* until end of line or end of word */
9354b88c807SRodney W. Grimes 			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */
9362dde9ce3SMartin Cracauer 
9372dde9ce3SMartin Cracauer 			synentry = syntax[c];
9382dde9ce3SMartin Cracauer 
9392dde9ce3SMartin Cracauer 			switch(synentry) {
9404b88c807SRodney W. Grimes 			case CNL:	/* '\n' */
9414b88c807SRodney W. Grimes 				if (syntax == BASESYNTAX)
9424b88c807SRodney W. Grimes 					goto endword;	/* exit outer loop */
9434b88c807SRodney W. Grimes 				USTPUTC(c, out);
9444b88c807SRodney W. Grimes 				plinno++;
9454b88c807SRodney W. Grimes 				if (doprompt)
9464b88c807SRodney W. Grimes 					setprompt(2);
9474b88c807SRodney W. Grimes 				else
9484b88c807SRodney W. Grimes 					setprompt(0);
9494b88c807SRodney W. Grimes 				c = pgetc();
9504b88c807SRodney W. Grimes 				goto loop;		/* continue outer loop */
9514b88c807SRodney W. Grimes 			case CWORD:
9524b88c807SRodney W. Grimes 				USTPUTC(c, out);
9534b88c807SRodney W. Grimes 				break;
9544b88c807SRodney W. Grimes 			case CCTL:
9554b88c807SRodney W. Grimes 				if (eofmark == NULL || dblquote)
9564b88c807SRodney W. Grimes 					USTPUTC(CTLESC, out);
9574b88c807SRodney W. Grimes 				USTPUTC(c, out);
9584b88c807SRodney W. Grimes 				break;
9594b88c807SRodney W. Grimes 			case CBACK:	/* backslash */
9604b88c807SRodney W. Grimes 				c = pgetc();
9614b88c807SRodney W. Grimes 				if (c == PEOF) {
9624b88c807SRodney W. Grimes 					USTPUTC('\\', out);
9634b88c807SRodney W. Grimes 					pungetc();
9644b88c807SRodney W. Grimes 				} else if (c == '\n') {
9654b88c807SRodney W. Grimes 					if (doprompt)
9664b88c807SRodney W. Grimes 						setprompt(2);
9674b88c807SRodney W. Grimes 					else
9684b88c807SRodney W. Grimes 						setprompt(0);
9694b88c807SRodney W. Grimes 				} else {
97073f612b5SMartin Cracauer 					if (dblquote && c != '\\' &&
97173f612b5SMartin Cracauer 					    c != '`' && c != '$' &&
97273f612b5SMartin Cracauer 					    (c != '"' || eofmark != NULL))
9734b88c807SRodney W. Grimes 						USTPUTC('\\', out);
9740c4eeddaSTor Egge 					if (SQSYNTAX[c] == CCTL)
9754b88c807SRodney W. Grimes 						USTPUTC(CTLESC, out);
9765557a02aSTor Egge 					else if (eofmark == NULL)
9776f47734fSTor Egge 						USTPUTC(CTLQUOTEMARK, out);
9784b88c807SRodney W. Grimes 					USTPUTC(c, out);
9794b88c807SRodney W. Grimes 					quotef++;
9804b88c807SRodney W. Grimes 				}
9814b88c807SRodney W. Grimes 				break;
9824b88c807SRodney W. Grimes 			case CSQUOTE:
9835557a02aSTor Egge 				if (eofmark == NULL)
9846f47734fSTor Egge 					USTPUTC(CTLQUOTEMARK, out);
9854b88c807SRodney W. Grimes 				syntax = SQSYNTAX;
9864b88c807SRodney W. Grimes 				break;
9874b88c807SRodney W. Grimes 			case CDQUOTE:
9885557a02aSTor Egge 				if (eofmark == NULL)
9896f47734fSTor Egge 					USTPUTC(CTLQUOTEMARK, out);
9904b88c807SRodney W. Grimes 				syntax = DQSYNTAX;
9914b88c807SRodney W. Grimes 				dblquote = 1;
9924b88c807SRodney W. Grimes 				break;
9934b88c807SRodney W. Grimes 			case CENDQUOTE:
9945557a02aSTor Egge 				if (eofmark != NULL && arinest == 0 &&
9955557a02aSTor Egge 				    varnest == 0) {
9964b88c807SRodney W. Grimes 					USTPUTC(c, out);
9974b88c807SRodney W. Grimes 				} else {
9985557a02aSTor Egge 					if (arinest) {
9994b88c807SRodney W. Grimes 						syntax = ARISYNTAX;
10004b88c807SRodney W. Grimes 						dblquote = 0;
10015557a02aSTor Egge 					} else if (eofmark == NULL) {
10025557a02aSTor Egge 						syntax = BASESYNTAX;
10035557a02aSTor Egge 						dblquote = 0;
10045557a02aSTor Egge 					}
10055557a02aSTor Egge 					quotef++;
10064b88c807SRodney W. Grimes 				}
10074b88c807SRodney W. Grimes 				break;
10084b88c807SRodney W. Grimes 			case CVAR:	/* '$' */
10094b88c807SRodney W. Grimes 				PARSESUB();		/* parse substitution */
10104b88c807SRodney W. Grimes 				break;
10114b88c807SRodney W. Grimes 			case CENDVAR:	/* '}' */
10124b88c807SRodney W. Grimes 				if (varnest > 0) {
10134b88c807SRodney W. Grimes 					varnest--;
10144b88c807SRodney W. Grimes 					USTPUTC(CTLENDVAR, out);
10154b88c807SRodney W. Grimes 				} else {
10164b88c807SRodney W. Grimes 					USTPUTC(c, out);
10174b88c807SRodney W. Grimes 				}
10184b88c807SRodney W. Grimes 				break;
10194b88c807SRodney W. Grimes 			case CLP:	/* '(' in arithmetic */
10204b88c807SRodney W. Grimes 				parenlevel++;
10214b88c807SRodney W. Grimes 				USTPUTC(c, out);
10224b88c807SRodney W. Grimes 				break;
10234b88c807SRodney W. Grimes 			case CRP:	/* ')' in arithmetic */
10244b88c807SRodney W. Grimes 				if (parenlevel > 0) {
10254b88c807SRodney W. Grimes 					USTPUTC(c, out);
10264b88c807SRodney W. Grimes 					--parenlevel;
10274b88c807SRodney W. Grimes 				} else {
10284b88c807SRodney W. Grimes 					if (pgetc() == ')') {
10294b88c807SRodney W. Grimes 						if (--arinest == 0) {
10304b88c807SRodney W. Grimes 							USTPUTC(CTLENDARI, out);
10314b88c807SRodney W. Grimes 							syntax = prevsyntax;
10325557a02aSTor Egge 							if (syntax == DQSYNTAX)
10335557a02aSTor Egge 								dblquote = 1;
10345557a02aSTor Egge 							else
10355557a02aSTor Egge 								dblquote = 0;
10364b88c807SRodney W. Grimes 						} else
10374b88c807SRodney W. Grimes 							USTPUTC(')', out);
10384b88c807SRodney W. Grimes 					} else {
10394b88c807SRodney W. Grimes 						/*
10404b88c807SRodney W. Grimes 						 * unbalanced parens
10414b88c807SRodney W. Grimes 						 *  (don't 2nd guess - no error)
10424b88c807SRodney W. Grimes 						 */
10434b88c807SRodney W. Grimes 						pungetc();
10444b88c807SRodney W. Grimes 						USTPUTC(')', out);
10454b88c807SRodney W. Grimes 					}
10464b88c807SRodney W. Grimes 				}
10474b88c807SRodney W. Grimes 				break;
10484b88c807SRodney W. Grimes 			case CBQUOTE:	/* '`' */
10494b88c807SRodney W. Grimes 				PARSEBACKQOLD();
10504b88c807SRodney W. Grimes 				break;
10514b88c807SRodney W. Grimes 			case CEOF:
10524b88c807SRodney W. Grimes 				goto endword;		/* exit outer loop */
10534b88c807SRodney W. Grimes 			default:
10544b88c807SRodney W. Grimes 				if (varnest == 0)
10554b88c807SRodney W. Grimes 					goto endword;	/* exit outer loop */
10564b88c807SRodney W. Grimes 				USTPUTC(c, out);
10574b88c807SRodney W. Grimes 			}
10584b88c807SRodney W. Grimes 			c = pgetc_macro();
10594b88c807SRodney W. Grimes 		}
10604b88c807SRodney W. Grimes 	}
10614b88c807SRodney W. Grimes endword:
10624b88c807SRodney W. Grimes 	if (syntax == ARISYNTAX)
10634b88c807SRodney W. Grimes 		synerror("Missing '))'");
10644b88c807SRodney W. Grimes 	if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10654b88c807SRodney W. Grimes 		synerror("Unterminated quoted string");
10664b88c807SRodney W. Grimes 	if (varnest != 0) {
10674b88c807SRodney W. Grimes 		startlinno = plinno;
10684b88c807SRodney W. Grimes 		synerror("Missing '}'");
10694b88c807SRodney W. Grimes 	}
10704b88c807SRodney W. Grimes 	USTPUTC('\0', out);
10714b88c807SRodney W. Grimes 	len = out - stackblock();
10724b88c807SRodney W. Grimes 	out = stackblock();
10734b88c807SRodney W. Grimes 	if (eofmark == NULL) {
10744b88c807SRodney W. Grimes 		if ((c == '>' || c == '<')
10754b88c807SRodney W. Grimes 		 && quotef == 0
10764b88c807SRodney W. Grimes 		 && len <= 2
10774b88c807SRodney W. Grimes 		 && (*out == '\0' || is_digit(*out))) {
10784b88c807SRodney W. Grimes 			PARSEREDIR();
10794b88c807SRodney W. Grimes 			return lasttoken = TREDIR;
10804b88c807SRodney W. Grimes 		} else {
10814b88c807SRodney W. Grimes 			pungetc();
10824b88c807SRodney W. Grimes 		}
10834b88c807SRodney W. Grimes 	}
10844b88c807SRodney W. Grimes 	quoteflag = quotef;
10854b88c807SRodney W. Grimes 	backquotelist = bqlist;
10864b88c807SRodney W. Grimes 	grabstackblock(len);
10874b88c807SRodney W. Grimes 	wordtext = out;
10884b88c807SRodney W. Grimes 	return lasttoken = TWORD;
10894b88c807SRodney W. Grimes /* end of readtoken routine */
10904b88c807SRodney W. Grimes 
10914b88c807SRodney W. Grimes 
10924b88c807SRodney W. Grimes 
10934b88c807SRodney W. Grimes /*
10944b88c807SRodney W. Grimes  * Check to see whether we are at the end of the here document.  When this
10954b88c807SRodney W. Grimes  * is called, c is set to the first character of the next input line.  If
10964b88c807SRodney W. Grimes  * we are at the end of the here document, this routine sets the c to PEOF.
10974b88c807SRodney W. Grimes  */
10984b88c807SRodney W. Grimes 
10994b88c807SRodney W. Grimes checkend: {
11004b88c807SRodney W. Grimes 	if (eofmark) {
11014b88c807SRodney W. Grimes 		if (striptabs) {
11024b88c807SRodney W. Grimes 			while (c == '\t')
11034b88c807SRodney W. Grimes 				c = pgetc();
11044b88c807SRodney W. Grimes 		}
11054b88c807SRodney W. Grimes 		if (c == *eofmark) {
11064b88c807SRodney W. Grimes 			if (pfgets(line, sizeof line) != NULL) {
11077920a31dSSteve Price 				char *p, *q;
11084b88c807SRodney W. Grimes 
11094b88c807SRodney W. Grimes 				p = line;
11104b88c807SRodney W. Grimes 				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
11114b88c807SRodney W. Grimes 				if (*p == '\n' && *q == '\0') {
11124b88c807SRodney W. Grimes 					c = PEOF;
11134b88c807SRodney W. Grimes 					plinno++;
11144b88c807SRodney W. Grimes 					needprompt = doprompt;
11154b88c807SRodney W. Grimes 				} else {
11164b88c807SRodney W. Grimes 					pushstring(line, strlen(line), NULL);
11174b88c807SRodney W. Grimes 				}
11184b88c807SRodney W. Grimes 			}
11194b88c807SRodney W. Grimes 		}
11204b88c807SRodney W. Grimes 	}
11214b88c807SRodney W. Grimes 	goto checkend_return;
11224b88c807SRodney W. Grimes }
11234b88c807SRodney W. Grimes 
11244b88c807SRodney W. Grimes 
11254b88c807SRodney W. Grimes /*
11264b88c807SRodney W. Grimes  * Parse a redirection operator.  The variable "out" points to a string
11274b88c807SRodney W. Grimes  * specifying the fd to be redirected.  The variable "c" contains the
11284b88c807SRodney W. Grimes  * first character of the redirection operator.
11294b88c807SRodney W. Grimes  */
11304b88c807SRodney W. Grimes 
11314b88c807SRodney W. Grimes parseredir: {
11324b88c807SRodney W. Grimes 	char fd = *out;
11334b88c807SRodney W. Grimes 	union node *np;
11344b88c807SRodney W. Grimes 
11354b88c807SRodney W. Grimes 	np = (union node *)stalloc(sizeof (struct nfile));
11364b88c807SRodney W. Grimes 	if (c == '>') {
11374b88c807SRodney W. Grimes 		np->nfile.fd = 1;
11384b88c807SRodney W. Grimes 		c = pgetc();
11394b88c807SRodney W. Grimes 		if (c == '>')
11404b88c807SRodney W. Grimes 			np->type = NAPPEND;
11414b88c807SRodney W. Grimes 		else if (c == '&')
11424b88c807SRodney W. Grimes 			np->type = NTOFD;
11431a958c66STim J. Robbins 		else if (c == '|')
11441a958c66STim J. Robbins 			np->type = NCLOBBER;
11454b88c807SRodney W. Grimes 		else {
11464b88c807SRodney W. Grimes 			np->type = NTO;
11474b88c807SRodney W. Grimes 			pungetc();
11484b88c807SRodney W. Grimes 		}
11494b88c807SRodney W. Grimes 	} else {	/* c == '<' */
11504b88c807SRodney W. Grimes 		np->nfile.fd = 0;
11514b88c807SRodney W. Grimes 		c = pgetc();
11524b88c807SRodney W. Grimes 		if (c == '<') {
11534b88c807SRodney W. Grimes 			if (sizeof (struct nfile) != sizeof (struct nhere)) {
11544b88c807SRodney W. Grimes 				np = (union node *)stalloc(sizeof (struct nhere));
11554b88c807SRodney W. Grimes 				np->nfile.fd = 0;
11564b88c807SRodney W. Grimes 			}
11574b88c807SRodney W. Grimes 			np->type = NHERE;
11584b88c807SRodney W. Grimes 			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
11594b88c807SRodney W. Grimes 			heredoc->here = np;
11604b88c807SRodney W. Grimes 			if ((c = pgetc()) == '-') {
11614b88c807SRodney W. Grimes 				heredoc->striptabs = 1;
11624b88c807SRodney W. Grimes 			} else {
11634b88c807SRodney W. Grimes 				heredoc->striptabs = 0;
11644b88c807SRodney W. Grimes 				pungetc();
11654b88c807SRodney W. Grimes 			}
11664b88c807SRodney W. Grimes 		} else if (c == '&')
11674b88c807SRodney W. Grimes 			np->type = NFROMFD;
11684682f420SBrian Somers 		else if (c == '>')
11694682f420SBrian Somers 			np->type = NFROMTO;
11704b88c807SRodney W. Grimes 		else {
11714b88c807SRodney W. Grimes 			np->type = NFROM;
11724b88c807SRodney W. Grimes 			pungetc();
11734b88c807SRodney W. Grimes 		}
11744b88c807SRodney W. Grimes 	}
11754b88c807SRodney W. Grimes 	if (fd != '\0')
11764b88c807SRodney W. Grimes 		np->nfile.fd = digit_val(fd);
11774b88c807SRodney W. Grimes 	redirnode = np;
11784b88c807SRodney W. Grimes 	goto parseredir_return;
11794b88c807SRodney W. Grimes }
11804b88c807SRodney W. Grimes 
11814b88c807SRodney W. Grimes 
11824b88c807SRodney W. Grimes /*
11834b88c807SRodney W. Grimes  * Parse a substitution.  At this point, we have read the dollar sign
11844b88c807SRodney W. Grimes  * and nothing else.
11854b88c807SRodney W. Grimes  */
11864b88c807SRodney W. Grimes 
11874b88c807SRodney W. Grimes parsesub: {
11884b88c807SRodney W. Grimes 	int subtype;
11894b88c807SRodney W. Grimes 	int typeloc;
11904b88c807SRodney W. Grimes 	int flags;
11914b88c807SRodney W. Grimes 	char *p;
11924b88c807SRodney W. Grimes #ifndef GDB_HACK
11934b88c807SRodney W. Grimes 	static const char types[] = "}-+?=";
11944b88c807SRodney W. Grimes #endif
11955c817731SPeter Wemm        int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
11964b88c807SRodney W. Grimes 
11974b88c807SRodney W. Grimes 	c = pgetc();
11984b88c807SRodney W. Grimes 	if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
11994b88c807SRodney W. Grimes 		USTPUTC('$', out);
12004b88c807SRodney W. Grimes 		pungetc();
12014b88c807SRodney W. Grimes 	} else if (c == '(') {	/* $(command) or $((arith)) */
12024b88c807SRodney W. Grimes 		if (pgetc() == '(') {
12034b88c807SRodney W. Grimes 			PARSEARITH();
12044b88c807SRodney W. Grimes 		} else {
12054b88c807SRodney W. Grimes 			pungetc();
12064b88c807SRodney W. Grimes 			PARSEBACKQNEW();
12074b88c807SRodney W. Grimes 		}
12084b88c807SRodney W. Grimes 	} else {
12094b88c807SRodney W. Grimes 		USTPUTC(CTLVAR, out);
12104b88c807SRodney W. Grimes 		typeloc = out - stackblock();
12114b88c807SRodney W. Grimes 		USTPUTC(VSNORMAL, out);
12124b88c807SRodney W. Grimes 		subtype = VSNORMAL;
12134b88c807SRodney W. Grimes 		if (c == '{') {
12145c817731SPeter Wemm 			bracketed_name = 1;
12154b88c807SRodney W. Grimes 			c = pgetc();
1216aa9caaf6SPeter Wemm 			if (c == '#') {
1217aa9caaf6SPeter Wemm 				if ((c = pgetc()) == '}')
1218aa9caaf6SPeter Wemm 					c = '#';
1219aa9caaf6SPeter Wemm 				else
1220aa9caaf6SPeter Wemm 					subtype = VSLENGTH;
1221aa9caaf6SPeter Wemm 			}
1222aa9caaf6SPeter Wemm 			else
12234b88c807SRodney W. Grimes 				subtype = 0;
12244b88c807SRodney W. Grimes 		}
12254b88c807SRodney W. Grimes 		if (is_name(c)) {
12264b88c807SRodney W. Grimes 			do {
12274b88c807SRodney W. Grimes 				STPUTC(c, out);
12284b88c807SRodney W. Grimes 				c = pgetc();
12294b88c807SRodney W. Grimes 			} while (is_in_name(c));
12305c817731SPeter Wemm 		} else if (is_digit(c)) {
12315c817731SPeter Wemm 			if (bracketed_name) {
12325c817731SPeter Wemm 				do {
12335c817731SPeter Wemm 					STPUTC(c, out);
12345c817731SPeter Wemm 					c = pgetc();
12355c817731SPeter Wemm 				} while (is_digit(c));
12365c817731SPeter Wemm 			} else {
12375c817731SPeter Wemm 				STPUTC(c, out);
12385c817731SPeter Wemm 				c = pgetc();
12395c817731SPeter Wemm 			}
12404b88c807SRodney W. Grimes 		} else {
12414b88c807SRodney W. Grimes 			if (! is_special(c))
12424b88c807SRodney W. Grimes badsub:				synerror("Bad substitution");
12434b88c807SRodney W. Grimes 			USTPUTC(c, out);
12444b88c807SRodney W. Grimes 			c = pgetc();
12454b88c807SRodney W. Grimes 		}
12464b88c807SRodney W. Grimes 		STPUTC('=', out);
12474b88c807SRodney W. Grimes 		flags = 0;
12484b88c807SRodney W. Grimes 		if (subtype == 0) {
1249aa9caaf6SPeter Wemm 			switch (c) {
1250aa9caaf6SPeter Wemm 			case ':':
12514b88c807SRodney W. Grimes 				flags = VSNUL;
12524b88c807SRodney W. Grimes 				c = pgetc();
1253aa9caaf6SPeter Wemm 				/*FALLTHROUGH*/
1254aa9caaf6SPeter Wemm 			default:
12554b88c807SRodney W. Grimes 				p = strchr(types, c);
12564b88c807SRodney W. Grimes 				if (p == NULL)
12574b88c807SRodney W. Grimes 					goto badsub;
12584b88c807SRodney W. Grimes 				subtype = p - types + VSNORMAL;
1259aa9caaf6SPeter Wemm 				break;
1260aa9caaf6SPeter Wemm 			case '%':
1261aa9caaf6SPeter Wemm 			case '#':
1262aa9caaf6SPeter Wemm 				{
1263aa9caaf6SPeter Wemm 					int cc = c;
1264aa9caaf6SPeter Wemm 					subtype = c == '#' ? VSTRIMLEFT :
1265aa9caaf6SPeter Wemm 							     VSTRIMRIGHT;
1266aa9caaf6SPeter Wemm 					c = pgetc();
1267aa9caaf6SPeter Wemm 					if (c == cc)
1268aa9caaf6SPeter Wemm 						subtype++;
1269aa9caaf6SPeter Wemm 					else
1270aa9caaf6SPeter Wemm 						pungetc();
1271aa9caaf6SPeter Wemm 					break;
1272aa9caaf6SPeter Wemm 				}
1273aa9caaf6SPeter Wemm 			}
12744b88c807SRodney W. Grimes 		} else {
12754b88c807SRodney W. Grimes 			pungetc();
12764b88c807SRodney W. Grimes 		}
1277c11e75cfSMartin Cracauer 		if (subtype != VSLENGTH && (dblquote || arinest))
12784b88c807SRodney W. Grimes 			flags |= VSQUOTE;
12794b88c807SRodney W. Grimes 		*(stackblock() + typeloc) = subtype | flags;
12804b88c807SRodney W. Grimes 		if (subtype != VSNORMAL)
12814b88c807SRodney W. Grimes 			varnest++;
12824b88c807SRodney W. Grimes 	}
12834b88c807SRodney W. Grimes 	goto parsesub_return;
12844b88c807SRodney W. Grimes }
12854b88c807SRodney W. Grimes 
12864b88c807SRodney W. Grimes 
12874b88c807SRodney W. Grimes /*
12884b88c807SRodney W. Grimes  * Called to parse command substitutions.  Newstyle is set if the command
12894b88c807SRodney W. Grimes  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12904b88c807SRodney W. Grimes  * list of commands (passed by reference), and savelen is the number of
12914b88c807SRodney W. Grimes  * characters on the top of the stack which must be preserved.
12924b88c807SRodney W. Grimes  */
12934b88c807SRodney W. Grimes 
12944b88c807SRodney W. Grimes parsebackq: {
12954b88c807SRodney W. Grimes 	struct nodelist **nlpp;
12964b88c807SRodney W. Grimes 	int savepbq;
12974b88c807SRodney W. Grimes 	union node *n;
12984b88c807SRodney W. Grimes 	char *volatile str;
12994b88c807SRodney W. Grimes 	struct jmploc jmploc;
13004b88c807SRodney W. Grimes 	struct jmploc *volatile savehandler;
13014b88c807SRodney W. Grimes 	int savelen;
1302ab0a2172SSteve Price 	int saveprompt;
1303ab0a2172SSteve Price #if __GNUC__
1304ab0a2172SSteve Price 	/* Avoid longjmp clobbering */
1305ab0a2172SSteve Price 	(void) &saveprompt;
1306ab0a2172SSteve Price #endif
13074b88c807SRodney W. Grimes 
13084b88c807SRodney W. Grimes 	savepbq = parsebackquote;
13094b88c807SRodney W. Grimes 	if (setjmp(jmploc.loc)) {
13104b88c807SRodney W. Grimes 		if (str)
13114b88c807SRodney W. Grimes 			ckfree(str);
13124b88c807SRodney W. Grimes 		parsebackquote = 0;
13134b88c807SRodney W. Grimes 		handler = savehandler;
13144b88c807SRodney W. Grimes 		longjmp(handler->loc, 1);
13154b88c807SRodney W. Grimes 	}
13164b88c807SRodney W. Grimes 	INTOFF;
13174b88c807SRodney W. Grimes 	str = NULL;
13184b88c807SRodney W. Grimes 	savelen = out - stackblock();
13194b88c807SRodney W. Grimes 	if (savelen > 0) {
13204b88c807SRodney W. Grimes 		str = ckmalloc(savelen);
1321aa9caaf6SPeter Wemm 		memcpy(str, stackblock(), savelen);
13224b88c807SRodney W. Grimes 	}
13234b88c807SRodney W. Grimes 	savehandler = handler;
13244b88c807SRodney W. Grimes 	handler = &jmploc;
13254b88c807SRodney W. Grimes 	INTON;
13264b88c807SRodney W. Grimes         if (oldstyle) {
13274b88c807SRodney W. Grimes                 /* We must read until the closing backquote, giving special
13284b88c807SRodney W. Grimes                    treatment to some slashes, and then push the string and
13294b88c807SRodney W. Grimes                    reread it as input, interpreting it normally.  */
13307920a31dSSteve Price                 char *out;
13317920a31dSSteve Price                 int c;
13324b88c807SRodney W. Grimes                 int savelen;
13334b88c807SRodney W. Grimes                 char *str;
13344b88c807SRodney W. Grimes 
1335ab0a2172SSteve Price 
13364b88c807SRodney W. Grimes                 STARTSTACKSTR(out);
1337ab0a2172SSteve Price 		for (;;) {
1338ab0a2172SSteve Price 			if (needprompt) {
1339ab0a2172SSteve Price 				setprompt(2);
1340ab0a2172SSteve Price 				needprompt = 0;
134172348d41SJoerg Wunsch 			}
1342ab0a2172SSteve Price 			switch (c = pgetc()) {
1343ab0a2172SSteve Price 			case '`':
1344ab0a2172SSteve Price 				goto done;
1345ab0a2172SSteve Price 
1346ab0a2172SSteve Price 			case '\\':
1347ab0a2172SSteve Price                                 if ((c = pgetc()) == '\n') {
1348ab0a2172SSteve Price 					plinno++;
1349ab0a2172SSteve Price 					if (doprompt)
1350ab0a2172SSteve Price 						setprompt(2);
1351ab0a2172SSteve Price 					else
1352ab0a2172SSteve Price 						setprompt(0);
1353ab0a2172SSteve Price 					/*
1354ab0a2172SSteve Price 					 * If eating a newline, avoid putting
1355ab0a2172SSteve Price 					 * the newline into the new character
1356ab0a2172SSteve Price 					 * stream (via the STPUTC after the
1357ab0a2172SSteve Price 					 * switch).
1358ab0a2172SSteve Price 					 */
1359ab0a2172SSteve Price 					continue;
1360ab0a2172SSteve Price 				}
13611e95454eSPaul Richards                                 if (c != '\\' && c != '`' && c != '$'
13624b88c807SRodney W. Grimes                                     && (!dblquote || c != '"'))
13634b88c807SRodney W. Grimes                                         STPUTC('\\', out);
1364ab0a2172SSteve Price 				break;
1365ab0a2172SSteve Price 
1366ab0a2172SSteve Price 			case '\n':
1367ab0a2172SSteve Price 				plinno++;
1368ab0a2172SSteve Price 				needprompt = doprompt;
1369ab0a2172SSteve Price 				break;
1370ab0a2172SSteve Price 
1371ab0a2172SSteve Price 			case PEOF:
1372ab0a2172SSteve Price 			        startlinno = plinno;
1373ab0a2172SSteve Price 				synerror("EOF in backquote substitution");
1374ab0a2172SSteve Price  				break;
1375ab0a2172SSteve Price 
1376ab0a2172SSteve Price 			default:
1377ab0a2172SSteve Price 				break;
13784b88c807SRodney W. Grimes 			}
13794b88c807SRodney W. Grimes 			STPUTC(c, out);
13804b88c807SRodney W. Grimes                 }
1381ab0a2172SSteve Price done:
13824b88c807SRodney W. Grimes                 STPUTC('\0', out);
13834b88c807SRodney W. Grimes                 savelen = out - stackblock();
13844b88c807SRodney W. Grimes                 if (savelen > 0) {
13854b88c807SRodney W. Grimes                         str = ckmalloc(savelen);
1386aa9caaf6SPeter Wemm                         memcpy(str, stackblock(), savelen);
13874b88c807SRodney W. Grimes 			setinputstring(str, 1);
13884b88c807SRodney W. Grimes                 }
1389aa9caaf6SPeter Wemm         }
13904b88c807SRodney W. Grimes 	nlpp = &bqlist;
13914b88c807SRodney W. Grimes 	while (*nlpp)
13924b88c807SRodney W. Grimes 		nlpp = &(*nlpp)->next;
13934b88c807SRodney W. Grimes 	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
13944b88c807SRodney W. Grimes 	(*nlpp)->next = NULL;
13954b88c807SRodney W. Grimes 	parsebackquote = oldstyle;
1396ab0a2172SSteve Price 
1397ab0a2172SSteve Price 	if (oldstyle) {
1398ab0a2172SSteve Price 		saveprompt = doprompt;
1399ab0a2172SSteve Price 		doprompt = 0;
1400ab0a2172SSteve Price 	}
1401ab0a2172SSteve Price 
14024b88c807SRodney W. Grimes 	n = list(0);
1403ab0a2172SSteve Price 
14044b88c807SRodney W. Grimes 	if (oldstyle)
1405ab0a2172SSteve Price 		doprompt = saveprompt;
1406ab0a2172SSteve Price 	else {
1407ab0a2172SSteve Price 		if (readtoken() != TRP)
1408ab0a2172SSteve Price 			synexpect(TRP);
1409ab0a2172SSteve Price 	}
1410ab0a2172SSteve Price 
1411ab0a2172SSteve Price 	(*nlpp)->n = n;
1412ab0a2172SSteve Price         if (oldstyle) {
1413ab0a2172SSteve Price 		/*
1414ab0a2172SSteve Price 		 * Start reading from old file again, ignoring any pushed back
1415ab0a2172SSteve Price 		 * tokens left from the backquote parsing
1416ab0a2172SSteve Price 		 */
14174b88c807SRodney W. Grimes                 popfile();
1418ab0a2172SSteve Price 		tokpushback = 0;
1419ab0a2172SSteve Price 	}
14204b88c807SRodney W. Grimes 	while (stackblocksize() <= savelen)
14214b88c807SRodney W. Grimes 		growstackblock();
14224b88c807SRodney W. Grimes 	STARTSTACKSTR(out);
14234b88c807SRodney W. Grimes 	if (str) {
1424aa9caaf6SPeter Wemm 		memcpy(out, str, savelen);
14254b88c807SRodney W. Grimes 		STADJUST(savelen, out);
14264b88c807SRodney W. Grimes 		INTOFF;
14274b88c807SRodney W. Grimes 		ckfree(str);
14284b88c807SRodney W. Grimes 		str = NULL;
14294b88c807SRodney W. Grimes 		INTON;
14304b88c807SRodney W. Grimes 	}
14314b88c807SRodney W. Grimes 	parsebackquote = savepbq;
14324b88c807SRodney W. Grimes 	handler = savehandler;
14334b88c807SRodney W. Grimes 	if (arinest || dblquote)
14344b88c807SRodney W. Grimes 		USTPUTC(CTLBACKQ | CTLQUOTE, out);
14354b88c807SRodney W. Grimes 	else
14364b88c807SRodney W. Grimes 		USTPUTC(CTLBACKQ, out);
14374b88c807SRodney W. Grimes 	if (oldstyle)
14384b88c807SRodney W. Grimes 		goto parsebackq_oldreturn;
14394b88c807SRodney W. Grimes 	else
14404b88c807SRodney W. Grimes 		goto parsebackq_newreturn;
14414b88c807SRodney W. Grimes }
14424b88c807SRodney W. Grimes 
14434b88c807SRodney W. Grimes /*
14444b88c807SRodney W. Grimes  * Parse an arithmetic expansion (indicate start of one and set state)
14454b88c807SRodney W. Grimes  */
14464b88c807SRodney W. Grimes parsearith: {
14474b88c807SRodney W. Grimes 
14484b88c807SRodney W. Grimes 	if (++arinest == 1) {
14494b88c807SRodney W. Grimes 		prevsyntax = syntax;
14504b88c807SRodney W. Grimes 		syntax = ARISYNTAX;
14514b88c807SRodney W. Grimes 		USTPUTC(CTLARI, out);
14526f47734fSTor Egge 		if (dblquote)
14536f47734fSTor Egge 			USTPUTC('"',out);
14546f47734fSTor Egge 		else
14556f47734fSTor Egge 			USTPUTC(' ',out);
14564b88c807SRodney W. Grimes 	} else {
14574b88c807SRodney W. Grimes 		/*
14584b88c807SRodney W. Grimes 		 * we collapse embedded arithmetic expansion to
14594b88c807SRodney W. Grimes 		 * parenthesis, which should be equivalent
14604b88c807SRodney W. Grimes 		 */
14614b88c807SRodney W. Grimes 		USTPUTC('(', out);
14624b88c807SRodney W. Grimes 	}
14634b88c807SRodney W. Grimes 	goto parsearith_return;
14644b88c807SRodney W. Grimes }
14654b88c807SRodney W. Grimes 
14664b88c807SRodney W. Grimes } /* end of readtoken */
14674b88c807SRodney W. Grimes 
14684b88c807SRodney W. Grimes 
14694b88c807SRodney W. Grimes 
14704b88c807SRodney W. Grimes #ifdef mkinit
14714b88c807SRodney W. Grimes RESET {
14724b88c807SRodney W. Grimes 	tokpushback = 0;
14734b88c807SRodney W. Grimes 	checkkwd = 0;
14744b88c807SRodney W. Grimes }
14754b88c807SRodney W. Grimes #endif
14764b88c807SRodney W. Grimes 
14774b88c807SRodney W. Grimes /*
14784b88c807SRodney W. Grimes  * Returns true if the text contains nothing to expand (no dollar signs
14794b88c807SRodney W. Grimes  * or backquotes).
14804b88c807SRodney W. Grimes  */
14814b88c807SRodney W. Grimes 
14824b88c807SRodney W. Grimes STATIC int
14835134c3f7SWarner Losh noexpand(char *text)
14844b88c807SRodney W. Grimes {
14857920a31dSSteve Price 	char *p;
14867920a31dSSteve Price 	char c;
14874b88c807SRodney W. Grimes 
14884b88c807SRodney W. Grimes 	p = text;
14894b88c807SRodney W. Grimes 	while ((c = *p++) != '\0') {
14905557a02aSTor Egge 		if ( c == CTLQUOTEMARK)
14915557a02aSTor Egge 			continue;
14924b88c807SRodney W. Grimes 		if (c == CTLESC)
14934b88c807SRodney W. Grimes 			p++;
14940c4eeddaSTor Egge 		else if (BASESYNTAX[(int)c] == CCTL)
14954b88c807SRodney W. Grimes 			return 0;
14964b88c807SRodney W. Grimes 	}
14974b88c807SRodney W. Grimes 	return 1;
14984b88c807SRodney W. Grimes }
14994b88c807SRodney W. Grimes 
15004b88c807SRodney W. Grimes 
15014b88c807SRodney W. Grimes /*
15024b88c807SRodney W. Grimes  * Return true if the argument is a legal variable name (a letter or
15034b88c807SRodney W. Grimes  * underscore followed by zero or more letters, underscores, and digits).
15044b88c807SRodney W. Grimes  */
15054b88c807SRodney W. Grimes 
15064b88c807SRodney W. Grimes int
15075134c3f7SWarner Losh goodname(char *name)
15084b88c807SRodney W. Grimes {
15097920a31dSSteve Price 	char *p;
15104b88c807SRodney W. Grimes 
15114b88c807SRodney W. Grimes 	p = name;
15124b88c807SRodney W. Grimes 	if (! is_name(*p))
15134b88c807SRodney W. Grimes 		return 0;
15144b88c807SRodney W. Grimes 	while (*++p) {
15154b88c807SRodney W. Grimes 		if (! is_in_name(*p))
15164b88c807SRodney W. Grimes 			return 0;
15174b88c807SRodney W. Grimes 	}
15184b88c807SRodney W. Grimes 	return 1;
15194b88c807SRodney W. Grimes }
15204b88c807SRodney W. Grimes 
15214b88c807SRodney W. Grimes 
15224b88c807SRodney W. Grimes /*
15234b88c807SRodney W. Grimes  * Called when an unexpected token is read during the parse.  The argument
15244b88c807SRodney W. Grimes  * is the token that is expected, or -1 if more than one type of token can
15254b88c807SRodney W. Grimes  * occur at this point.
15264b88c807SRodney W. Grimes  */
15274b88c807SRodney W. Grimes 
15284b88c807SRodney W. Grimes STATIC void
15295134c3f7SWarner Losh synexpect(int token)
1530aa9caaf6SPeter Wemm {
15314b88c807SRodney W. Grimes 	char msg[64];
15324b88c807SRodney W. Grimes 
15334b88c807SRodney W. Grimes 	if (token >= 0) {
15344b88c807SRodney W. Grimes 		fmtstr(msg, 64, "%s unexpected (expecting %s)",
15354b88c807SRodney W. Grimes 			tokname[lasttoken], tokname[token]);
15364b88c807SRodney W. Grimes 	} else {
15374b88c807SRodney W. Grimes 		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
15384b88c807SRodney W. Grimes 	}
15394b88c807SRodney W. Grimes 	synerror(msg);
15404b88c807SRodney W. Grimes }
15414b88c807SRodney W. Grimes 
15424b88c807SRodney W. Grimes 
15434b88c807SRodney W. Grimes STATIC void
15445134c3f7SWarner Losh synerror(char *msg)
15454b88c807SRodney W. Grimes {
15464b88c807SRodney W. Grimes 	if (commandname)
15474b88c807SRodney W. Grimes 		outfmt(&errout, "%s: %d: ", commandname, startlinno);
15484b88c807SRodney W. Grimes 	outfmt(&errout, "Syntax error: %s\n", msg);
15494b88c807SRodney W. Grimes 	error((char *)NULL);
15504b88c807SRodney W. Grimes }
15514b88c807SRodney W. Grimes 
15524b88c807SRodney W. Grimes STATIC void
15535134c3f7SWarner Losh setprompt(int which)
15544b88c807SRodney W. Grimes {
15554b88c807SRodney W. Grimes 	whichprompt = which;
15564b88c807SRodney W. Grimes 
1557aa9caaf6SPeter Wemm #ifndef NO_HISTORY
15584b88c807SRodney W. Grimes 	if (!el)
1559aa9caaf6SPeter Wemm #endif
15604b88c807SRodney W. Grimes 		out2str(getprompt(NULL));
15614b88c807SRodney W. Grimes }
15624b88c807SRodney W. Grimes 
15634b88c807SRodney W. Grimes /*
15644b88c807SRodney W. Grimes  * called by editline -- any expansions to the prompt
15654b88c807SRodney W. Grimes  *    should be added here.
15664b88c807SRodney W. Grimes  */
15674b88c807SRodney W. Grimes char *
15685134c3f7SWarner Losh getprompt(void *unused __unused)
15694b88c807SRodney W. Grimes {
15704b88c807SRodney W. Grimes 	switch (whichprompt) {
15714b88c807SRodney W. Grimes 	case 0:
15724b88c807SRodney W. Grimes 		return "";
15734b88c807SRodney W. Grimes 	case 1:
15744b88c807SRodney W. Grimes 		return ps1val();
15754b88c807SRodney W. Grimes 	case 2:
15764b88c807SRodney W. Grimes 		return ps2val();
15774b88c807SRodney W. Grimes 	default:
15784b88c807SRodney W. Grimes 		return "<internal prompt error>";
15794b88c807SRodney W. Grimes 	}
15804b88c807SRodney W. Grimes }
1581