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