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