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