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