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