parser.c revision 216404
1239922Sgonzo/*-
2239922Sgonzo * Copyright (c) 1991, 1993
3239922Sgonzo *	The Regents of the University of California.  All rights reserved.
4239922Sgonzo *
5239922Sgonzo * This code is derived from software contributed to Berkeley by
6239922Sgonzo * Kenneth Almquist.
7239922Sgonzo *
8239922Sgonzo * Redistribution and use in source and binary forms, with or without
9239922Sgonzo * modification, are permitted provided that the following conditions
10239922Sgonzo * are met:
11239922Sgonzo * 1. Redistributions of source code must retain the above copyright
12239922Sgonzo *    notice, this list of conditions and the following disclaimer.
13239922Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
14239922Sgonzo *    notice, this list of conditions and the following disclaimer in the
15239922Sgonzo *    documentation and/or other materials provided with the distribution.
16239922Sgonzo * 4. Neither the name of the University nor the names of its contributors
17239922Sgonzo *    may be used to endorse or promote products derived from this software
18239922Sgonzo *    without specific prior written permission.
19239922Sgonzo *
20239922Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21239922Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22239922Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23239922Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24239922Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25239922Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26239922Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27239922Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28239922Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29239922Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30239922Sgonzo * SUCH DAMAGE.
31239922Sgonzo */
32239922Sgonzo
33239922Sgonzo#ifndef lint
34239922Sgonzo#if 0
35239922Sgonzostatic char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
36239922Sgonzo#endif
37239922Sgonzo#endif /* not lint */
38239922Sgonzo#include <sys/cdefs.h>
39239922Sgonzo__FBSDID("$FreeBSD: head/bin/sh/parser.c 216404 2010-12-13 10:48:49Z uqs $");
40239922Sgonzo
41239922Sgonzo#include <stdlib.h>
42239922Sgonzo#include <unistd.h>
43239922Sgonzo#include <stdio.h>
44239922Sgonzo
45239922Sgonzo#include "shell.h"
46239922Sgonzo#include "parser.h"
47239922Sgonzo#include "nodes.h"
48239922Sgonzo#include "expand.h"	/* defines rmescapes() */
49239922Sgonzo#include "syntax.h"
50239922Sgonzo#include "options.h"
51239922Sgonzo#include "input.h"
52239922Sgonzo#include "output.h"
53239922Sgonzo#include "var.h"
54239922Sgonzo#include "error.h"
55239922Sgonzo#include "memalloc.h"
56239922Sgonzo#include "mystring.h"
57239922Sgonzo#include "alias.h"
58239922Sgonzo#include "show.h"
59239922Sgonzo#include "eval.h"
60239922Sgonzo#include "exec.h"	/* to check for special builtins */
61239922Sgonzo#ifndef NO_HISTORY
62239922Sgonzo#include "myhistedit.h"
63239922Sgonzo#endif
64239922Sgonzo
65239922Sgonzo/*
66239922Sgonzo * Shell command parser.
67239922Sgonzo */
68239922Sgonzo
69239922Sgonzo#define	EOFMARKLEN	79
70239922Sgonzo#define	PROMPTLEN	128
71243423Sgonzo
72243423Sgonzo/* values of checkkwd variable */
73243423Sgonzo#define CHKALIAS	0x1
74243423Sgonzo#define CHKKWD		0x2
75243423Sgonzo#define CHKNL		0x4
76243423Sgonzo
77243423Sgonzo/* values returned by readtoken */
78243423Sgonzo#include "token.h"
79243423Sgonzo
80243423Sgonzo
81243423Sgonzo
82243423Sgonzostruct heredoc {
83243423Sgonzo	struct heredoc *next;	/* next here document in list */
84243423Sgonzo	union node *here;		/* redirection node */
85243423Sgonzo	char *eofmark;		/* string indicating end of input */
86243423Sgonzo	int striptabs;		/* if set, strip leading tabs */
87243423Sgonzo};
88243423Sgonzo
89243423Sgonzostruct parser_temp {
90243423Sgonzo	struct parser_temp *next;
91243423Sgonzo	void *data;
92243423Sgonzo};
93243423Sgonzo
94243423Sgonzo
95243423Sgonzostatic struct heredoc *heredoclist;	/* list of here documents to read */
96243423Sgonzostatic int doprompt;		/* if set, prompt the user */
97244762Sgonzostatic int needprompt;		/* true if interactive and at start of line */
98244762Sgonzostatic int lasttoken;		/* last token read */
99244762SgonzoMKINIT int tokpushback;		/* last token pushed back */
100244762Sgonzostatic char *wordtext;		/* text of last word returned by readtoken */
101244762SgonzoMKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
102244762Sgonzostatic struct nodelist *backquotelist;
103239922Sgonzostatic union node *redirnode;
104239922Sgonzostatic struct heredoc *heredoc;
105243423Sgonzostatic int quoteflag;		/* set if (part of) last token was quoted */
106239922Sgonzostatic int startlinno;		/* line # where last token started */
107239922Sgonzostatic int funclinno;		/* line # where the current function started */
108239922Sgonzostatic struct parser_temp *parser_temp;
109239922Sgonzo
110239922Sgonzo
111239922Sgonzostatic union node *list(int, int);
112239922Sgonzostatic union node *andor(void);
113239922Sgonzostatic union node *pipeline(void);
114239922Sgonzostatic union node *command(void);
115239922Sgonzostatic union node *simplecmd(union node **, union node *);
116239922Sgonzostatic union node *makename(void);
117239922Sgonzostatic void parsefname(void);
118239922Sgonzostatic void parseheredoc(void);
119239922Sgonzostatic int peektoken(void);
120239922Sgonzostatic int readtoken(void);
121239922Sgonzostatic int xxreadtoken(void);
122239922Sgonzostatic int readtoken1(int, char const *, char *, int);
123239922Sgonzostatic int noexpand(char *);
124239922Sgonzostatic void synexpect(int) __dead2;
125239922Sgonzostatic void synerror(const char *) __dead2;
126239922Sgonzostatic void setprompt(int);
127239922Sgonzo
128239922Sgonzo
129239922Sgonzostatic void *
130239922Sgonzoparser_temp_alloc(size_t len)
131239922Sgonzo{
132239922Sgonzo	struct parser_temp *t;
133239922Sgonzo
134239922Sgonzo	INTOFF;
135239922Sgonzo	t = ckmalloc(sizeof(*t));
136239922Sgonzo	t->data = NULL;
137239922Sgonzo	t->next = parser_temp;
138239922Sgonzo	parser_temp = t;
139239922Sgonzo	t->data = ckmalloc(len);
140239922Sgonzo	INTON;
141239922Sgonzo	return t->data;
142239922Sgonzo}
143243423Sgonzo
144239922Sgonzo
145239922Sgonzostatic void *
146239922Sgonzoparser_temp_realloc(void *ptr, size_t len)
147239922Sgonzo{
148239922Sgonzo	struct parser_temp *t;
149239922Sgonzo
150239922Sgonzo	INTOFF;
151239922Sgonzo	t = parser_temp;
152239922Sgonzo	if (ptr != t->data)
153239922Sgonzo		error("bug: parser_temp_realloc misused");
154239922Sgonzo	t->data = ckrealloc(t->data, len);
155239922Sgonzo	INTON;
156239922Sgonzo	return t->data;
157239922Sgonzo}
158239922Sgonzo
159239922Sgonzo
160239922Sgonzostatic void
161239922Sgonzoparser_temp_free_upto(void *ptr)
162239922Sgonzo{
163243423Sgonzo	struct parser_temp *t;
164243423Sgonzo	int done = 0;
165239922Sgonzo
166239922Sgonzo	INTOFF;
167239922Sgonzo	while (parser_temp != NULL && !done) {
168239922Sgonzo		t = parser_temp;
169239922Sgonzo		parser_temp = t->next;
170239922Sgonzo		done = t->data == ptr;
171239922Sgonzo		ckfree(t->data);
172239922Sgonzo		ckfree(t);
173243423Sgonzo	}
174243423Sgonzo	INTON;
175239922Sgonzo	if (!done)
176243423Sgonzo		error("bug: parser_temp_free_upto misused");
177243423Sgonzo}
178243423Sgonzo
179243423Sgonzo
180243423Sgonzostatic void
181243423Sgonzoparser_temp_free_all(void)
182243423Sgonzo{
183243423Sgonzo	struct parser_temp *t;
184243423Sgonzo
185243423Sgonzo	INTOFF;
186243423Sgonzo	while (parser_temp != NULL) {
187243423Sgonzo		t = parser_temp;
188243423Sgonzo		parser_temp = t->next;
189243423Sgonzo		ckfree(t->data);
190243423Sgonzo		ckfree(t);
191243423Sgonzo	}
192243423Sgonzo	INTON;
193243423Sgonzo}
194243423Sgonzo
195243423Sgonzo
196243423Sgonzo/*
197239922Sgonzo * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
198239922Sgonzo * valid parse tree indicating a blank line.)
199239922Sgonzo */
200239922Sgonzo
201239922Sgonzounion node *
202239922Sgonzoparsecmd(int interact)
203239922Sgonzo{
204239922Sgonzo	int t;
205239922Sgonzo
206239922Sgonzo	/* This assumes the parser is not re-entered,
207239922Sgonzo	 * which could happen if we add command substitution on PS1/PS2.
208239922Sgonzo	 */
209239922Sgonzo	parser_temp_free_all();
210239922Sgonzo	heredoclist = NULL;
211239922Sgonzo
212243423Sgonzo	tokpushback = 0;
213239922Sgonzo	doprompt = interact;
214239922Sgonzo	if (doprompt)
215239922Sgonzo		setprompt(1);
216239922Sgonzo	else
217239922Sgonzo		setprompt(0);
218239922Sgonzo	needprompt = 0;
219239922Sgonzo	t = readtoken();
220239922Sgonzo	if (t == TEOF)
221239922Sgonzo		return NEOF;
222239922Sgonzo	if (t == TNL)
223239922Sgonzo		return NULL;
224243423Sgonzo	tokpushback++;
225243423Sgonzo	return list(1, 1);
226243423Sgonzo}
227243423Sgonzo
228243423Sgonzo
229243423Sgonzostatic union node *
230243423Sgonzolist(int nlflag, int erflag)
231243423Sgonzo{
232239922Sgonzo	union node *ntop, *n1, *n2, *n3;
233243423Sgonzo	int tok;
234239922Sgonzo
235243423Sgonzo	checkkwd = CHKNL | CHKKWD | CHKALIAS;
236243423Sgonzo	if (!nlflag && !erflag && tokendlist[peektoken()])
237239922Sgonzo		return NULL;
238239922Sgonzo	ntop = n1 = NULL;
239239922Sgonzo	for (;;) {
240239922Sgonzo		n2 = andor();
241239922Sgonzo		tok = readtoken();
242239922Sgonzo		if (tok == TBACKGND) {
243239922Sgonzo			if (n2->type == NCMD || n2->type == NPIPE) {
244243423Sgonzo				n2->ncmd.backgnd = 1;
245239922Sgonzo			} else if (n2->type == NREDIR) {
246239922Sgonzo				n2->type = NBACKGND;
247239922Sgonzo			} else {
248239922Sgonzo				n3 = (union node *)stalloc(sizeof (struct nredir));
249239922Sgonzo				n3->type = NBACKGND;
250239922Sgonzo				n3->nredir.n = n2;
251239922Sgonzo				n3->nredir.redirect = NULL;
252239922Sgonzo				n2 = n3;
253239922Sgonzo			}
254239922Sgonzo		}
255239922Sgonzo		if (ntop == NULL)
256243423Sgonzo			ntop = n2;
257239922Sgonzo		else if (n1 == NULL) {
258239922Sgonzo			n1 = (union node *)stalloc(sizeof (struct nbinary));
259239922Sgonzo			n1->type = NSEMI;
260239922Sgonzo			n1->nbinary.ch1 = ntop;
261239922Sgonzo			n1->nbinary.ch2 = n2;
262239922Sgonzo			ntop = n1;
263239922Sgonzo		}
264239922Sgonzo		else {
265239922Sgonzo			n3 = (union node *)stalloc(sizeof (struct nbinary));
266239922Sgonzo			n3->type = NSEMI;
267239922Sgonzo			n3->nbinary.ch1 = n1->nbinary.ch2;
268239922Sgonzo			n3->nbinary.ch2 = n2;
269239922Sgonzo			n1->nbinary.ch2 = n3;
270239922Sgonzo			n1 = n3;
271239922Sgonzo		}
272239922Sgonzo		switch (tok) {
273239922Sgonzo		case TBACKGND:
274239922Sgonzo		case TSEMI:
275239922Sgonzo			tok = readtoken();
276239922Sgonzo			/* FALLTHROUGH */
277239922Sgonzo		case TNL:
278239922Sgonzo			if (tok == TNL) {
279239922Sgonzo				parseheredoc();
280239922Sgonzo				if (nlflag)
281239922Sgonzo					return ntop;
282239922Sgonzo			} else if (tok == TEOF && nlflag) {
283239922Sgonzo				parseheredoc();
284239922Sgonzo				return ntop;
285239922Sgonzo			} else {
286239922Sgonzo				tokpushback++;
287239922Sgonzo			}
288239922Sgonzo			checkkwd = CHKNL | CHKKWD | CHKALIAS;
289239922Sgonzo			if (!nlflag && !erflag && tokendlist[peektoken()])
290239922Sgonzo				return ntop;
291239922Sgonzo			break;
292239922Sgonzo		case TEOF:
293239922Sgonzo			if (heredoclist)
294239922Sgonzo				parseheredoc();
295239922Sgonzo			else
296239922Sgonzo				pungetc();		/* push back EOF on input */
297239922Sgonzo			return ntop;
298239922Sgonzo		default:
299239922Sgonzo			if (nlflag || erflag)
300239922Sgonzo				synexpect(-1);
301239922Sgonzo			tokpushback++;
302239922Sgonzo			return ntop;
303239922Sgonzo		}
304239922Sgonzo	}
305239922Sgonzo}
306239922Sgonzo
307239922Sgonzo
308239922Sgonzo
309239922Sgonzostatic union node *
310239922Sgonzoandor(void)
311239922Sgonzo{
312239922Sgonzo	union node *n1, *n2, *n3;
313239922Sgonzo	int t;
314239922Sgonzo
315239922Sgonzo	n1 = pipeline();
316239922Sgonzo	for (;;) {
317239922Sgonzo		if ((t = readtoken()) == TAND) {
318239922Sgonzo			t = NAND;
319239922Sgonzo		} else if (t == TOR) {
320239922Sgonzo			t = NOR;
321239922Sgonzo		} else {
322239922Sgonzo			tokpushback++;
323239922Sgonzo			return n1;
324239922Sgonzo		}
325239922Sgonzo		n2 = pipeline();
326239922Sgonzo		n3 = (union node *)stalloc(sizeof (struct nbinary));
327239922Sgonzo		n3->type = t;
328239922Sgonzo		n3->nbinary.ch1 = n1;
329239922Sgonzo		n3->nbinary.ch2 = n2;
330239922Sgonzo		n1 = n3;
331239922Sgonzo	}
332239922Sgonzo}
333239922Sgonzo
334239922Sgonzo
335239922Sgonzo
336239922Sgonzostatic union node *
337239922Sgonzopipeline(void)
338239922Sgonzo{
339239922Sgonzo	union node *n1, *n2, *pipenode;
340239922Sgonzo	struct nodelist *lp, *prev;
341239922Sgonzo	int negate, t;
342239922Sgonzo
343239922Sgonzo	negate = 0;
344239922Sgonzo	checkkwd = CHKNL | CHKKWD | CHKALIAS;
345239922Sgonzo	TRACE(("pipeline: entered\n"));
346239922Sgonzo	while (readtoken() == TNOT)
347239922Sgonzo		negate = !negate;
348239922Sgonzo	tokpushback++;
349239922Sgonzo	n1 = command();
350239922Sgonzo	if (readtoken() == TPIPE) {
351239922Sgonzo		pipenode = (union node *)stalloc(sizeof (struct npipe));
352239922Sgonzo		pipenode->type = NPIPE;
353239922Sgonzo		pipenode->npipe.backgnd = 0;
354239922Sgonzo		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
355239922Sgonzo		pipenode->npipe.cmdlist = lp;
356243423Sgonzo		lp->n = n1;
357239922Sgonzo		do {
358239922Sgonzo			prev = lp;
359239922Sgonzo			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
360239922Sgonzo			checkkwd = CHKNL | CHKKWD | CHKALIAS;
361239922Sgonzo			t = readtoken();
362239922Sgonzo			tokpushback++;
363239922Sgonzo			if (t == TNOT)
364239922Sgonzo				lp->n = pipeline();
365239922Sgonzo			else
366239922Sgonzo				lp->n = command();
367239922Sgonzo			prev->next = lp;
368239922Sgonzo		} while (readtoken() == TPIPE);
369239922Sgonzo		lp->next = NULL;
370239922Sgonzo		n1 = pipenode;
371239922Sgonzo	}
372239922Sgonzo	tokpushback++;
373239922Sgonzo	if (negate) {
374239922Sgonzo		n2 = (union node *)stalloc(sizeof (struct nnot));
375239922Sgonzo		n2->type = NNOT;
376239922Sgonzo		n2->nnot.com = n1;
377239922Sgonzo		return n2;
378239922Sgonzo	} else
379239922Sgonzo		return n1;
380239922Sgonzo}
381239922Sgonzo
382239922Sgonzo
383239922Sgonzo
384239922Sgonzostatic union node *
385239922Sgonzocommand(void)
386239922Sgonzo{
387239922Sgonzo	union node *n1, *n2;
388239922Sgonzo	union node *ap, **app;
389239922Sgonzo	union node *cp, **cpp;
390239922Sgonzo	union node *redir, **rpp;
391239922Sgonzo	int t;
392239922Sgonzo
393239922Sgonzo	checkkwd = CHKNL | CHKKWD | CHKALIAS;
394239922Sgonzo	redir = NULL;
395239922Sgonzo	n1 = NULL;
396239922Sgonzo	rpp = &redir;
397239922Sgonzo
398239922Sgonzo	/* Check for redirection which may precede command */
399239922Sgonzo	while (readtoken() == TREDIR) {
400239922Sgonzo		*rpp = n2 = redirnode;
401239922Sgonzo		rpp = &n2->nfile.next;
402239922Sgonzo		parsefname();
403239922Sgonzo	}
404239922Sgonzo	tokpushback++;
405239922Sgonzo
406239922Sgonzo	switch (readtoken()) {
407239922Sgonzo	case TIF:
408239922Sgonzo		n1 = (union node *)stalloc(sizeof (struct nif));
409239922Sgonzo		n1->type = NIF;
410239922Sgonzo		if ((n1->nif.test = list(0, 0)) == NULL)
411239922Sgonzo			synexpect(-1);
412239922Sgonzo		if (readtoken() != TTHEN)
413239922Sgonzo			synexpect(TTHEN);
414239922Sgonzo		n1->nif.ifpart = list(0, 0);
415239922Sgonzo		n2 = n1;
416239922Sgonzo		while (readtoken() == TELIF) {
417239922Sgonzo			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
418239922Sgonzo			n2 = n2->nif.elsepart;
419239922Sgonzo			n2->type = NIF;
420239922Sgonzo			if ((n2->nif.test = list(0, 0)) == NULL)
421239922Sgonzo				synexpect(-1);
422239922Sgonzo			if (readtoken() != TTHEN)
423239922Sgonzo				synexpect(TTHEN);
424239922Sgonzo			n2->nif.ifpart = list(0, 0);
425239922Sgonzo		}
426239922Sgonzo		if (lasttoken == TELSE)
427239922Sgonzo			n2->nif.elsepart = list(0, 0);
428239922Sgonzo		else {
429244762Sgonzo			n2->nif.elsepart = NULL;
430244762Sgonzo			tokpushback++;
431244762Sgonzo		}
432244762Sgonzo		if (readtoken() != TFI)
433244762Sgonzo			synexpect(TFI);
434244762Sgonzo		checkkwd = CHKKWD | CHKALIAS;
435244762Sgonzo		break;
436244762Sgonzo	case TWHILE:
437244762Sgonzo	case TUNTIL: {
438244762Sgonzo		int got;
439244762Sgonzo		n1 = (union node *)stalloc(sizeof (struct nbinary));
440244762Sgonzo		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
441244762Sgonzo		if ((n1->nbinary.ch1 = list(0, 0)) == NULL)
442244762Sgonzo			synexpect(-1);
443244762Sgonzo		if ((got=readtoken()) != TDO) {
444244762SgonzoTRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
445244762Sgonzo			synexpect(TDO);
446244762Sgonzo		}
447244762Sgonzo		n1->nbinary.ch2 = list(0, 0);
448244762Sgonzo		if (readtoken() != TDONE)
449244762Sgonzo			synexpect(TDONE);
450244762Sgonzo		checkkwd = CHKKWD | CHKALIAS;
451244762Sgonzo		break;
452244762Sgonzo	}
453244762Sgonzo	case TFOR:
454244762Sgonzo		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
455244762Sgonzo			synerror("Bad for loop variable");
456239922Sgonzo		n1 = (union node *)stalloc(sizeof (struct nfor));
457239922Sgonzo		n1->type = NFOR;
458244762Sgonzo		n1->nfor.var = wordtext;
459244762Sgonzo		while (readtoken() == TNL)
460244762Sgonzo			;
461244762Sgonzo		if (lasttoken == TWORD && ! quoteflag && equal(wordtext, "in")) {
462244762Sgonzo			app = &ap;
463244762Sgonzo			while (readtoken() == TWORD) {
464244762Sgonzo				n2 = (union node *)stalloc(sizeof (struct narg));
465244762Sgonzo				n2->type = NARG;
466244762Sgonzo				n2->narg.text = wordtext;
467244762Sgonzo				n2->narg.backquote = backquotelist;
468244762Sgonzo				*app = n2;
469244762Sgonzo				app = &n2->narg.next;
470244762Sgonzo			}
471244762Sgonzo			*app = NULL;
472244762Sgonzo			n1->nfor.args = ap;
473244762Sgonzo			if (lasttoken != TNL && lasttoken != TSEMI)
474244762Sgonzo				synexpect(-1);
475244762Sgonzo		} else {
476244762Sgonzo			static char argvars[5] = {
477244762Sgonzo				CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
478244762Sgonzo			};
479244762Sgonzo			n2 = (union node *)stalloc(sizeof (struct narg));
480244762Sgonzo			n2->type = NARG;
481244762Sgonzo			n2->narg.text = argvars;
482244762Sgonzo			n2->narg.backquote = NULL;
483244762Sgonzo			n2->narg.next = NULL;
484244762Sgonzo			n1->nfor.args = n2;
485244762Sgonzo			/*
486244762Sgonzo			 * Newline or semicolon here is optional (but note
487244762Sgonzo			 * that the original Bourne shell only allowed NL).
488244762Sgonzo			 */
489244762Sgonzo			if (lasttoken != TNL && lasttoken != TSEMI)
490244762Sgonzo				tokpushback++;
491244762Sgonzo		}
492244762Sgonzo		checkkwd = CHKNL | CHKKWD | CHKALIAS;
493244762Sgonzo		if ((t = readtoken()) == TDO)
494244762Sgonzo			t = TDONE;
495244762Sgonzo		else if (t == TBEGIN)
496244762Sgonzo			t = TEND;
497244762Sgonzo		else
498244762Sgonzo			synexpect(-1);
499244762Sgonzo		n1->nfor.body = list(0, 0);
500244762Sgonzo		if (readtoken() != t)
501244762Sgonzo			synexpect(t);
502244762Sgonzo		checkkwd = CHKKWD | CHKALIAS;
503244762Sgonzo		break;
504244762Sgonzo	case TCASE:
505244762Sgonzo		n1 = (union node *)stalloc(sizeof (struct ncase));
506244762Sgonzo		n1->type = NCASE;
507244762Sgonzo		if (readtoken() != TWORD)
508244762Sgonzo			synexpect(TWORD);
509244762Sgonzo		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
510244762Sgonzo		n2->type = NARG;
511244762Sgonzo		n2->narg.text = wordtext;
512244762Sgonzo		n2->narg.backquote = backquotelist;
513244762Sgonzo		n2->narg.next = NULL;
514244762Sgonzo		while (readtoken() == TNL);
515244762Sgonzo		if (lasttoken != TWORD || ! equal(wordtext, "in"))
516244762Sgonzo			synerror("expecting \"in\"");
517244762Sgonzo		cpp = &n1->ncase.cases;
518244762Sgonzo		checkkwd = CHKNL | CHKKWD, readtoken();
519244762Sgonzo		while (lasttoken != TESAC) {
520244762Sgonzo			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
521244762Sgonzo			cp->type = NCLIST;
522244762Sgonzo			app = &cp->nclist.pattern;
523244762Sgonzo			if (lasttoken == TLP)
524244762Sgonzo				readtoken();
525244762Sgonzo			for (;;) {
526244762Sgonzo				*app = ap = (union node *)stalloc(sizeof (struct narg));
527244762Sgonzo				ap->type = NARG;
528244762Sgonzo				ap->narg.text = wordtext;
529244762Sgonzo				ap->narg.backquote = backquotelist;
530244762Sgonzo				checkkwd = CHKNL | CHKKWD;
531244762Sgonzo				if (readtoken() != TPIPE)
532244762Sgonzo					break;
533244762Sgonzo				app = &ap->narg.next;
534244762Sgonzo				readtoken();
535244762Sgonzo			}
536244762Sgonzo			ap->narg.next = NULL;
537244762Sgonzo			if (lasttoken != TRP)
538244762Sgonzo				synexpect(TRP);
539244762Sgonzo			cp->nclist.body = list(0, 0);
540244762Sgonzo
541244762Sgonzo			checkkwd = CHKNL | CHKKWD | CHKALIAS;
542244762Sgonzo			if ((t = readtoken()) != TESAC) {
543244762Sgonzo				if (t != TENDCASE)
544244762Sgonzo					synexpect(TENDCASE);
545244762Sgonzo				else
546244762Sgonzo					checkkwd = CHKNL | CHKKWD, readtoken();
547244762Sgonzo			}
548244762Sgonzo			cpp = &cp->nclist.next;
549244762Sgonzo		}
550244762Sgonzo		*cpp = NULL;
551244762Sgonzo		checkkwd = CHKKWD | CHKALIAS;
552244762Sgonzo		break;
553244762Sgonzo	case TLP:
554244762Sgonzo		n1 = (union node *)stalloc(sizeof (struct nredir));
555244762Sgonzo		n1->type = NSUBSHELL;
556244762Sgonzo		n1->nredir.n = list(0, 0);
557244762Sgonzo		n1->nredir.redirect = NULL;
558244762Sgonzo		if (readtoken() != TRP)
559244762Sgonzo			synexpect(TRP);
560244762Sgonzo		checkkwd = CHKKWD | CHKALIAS;
561244762Sgonzo		break;
562244762Sgonzo	case TBEGIN:
563244762Sgonzo		n1 = list(0, 0);
564239922Sgonzo		if (readtoken() != TEND)
565239922Sgonzo			synexpect(TEND);
566239922Sgonzo		checkkwd = CHKKWD | CHKALIAS;
567243423Sgonzo		break;
568243423Sgonzo	/* Handle an empty command like other simple commands.  */
569243423Sgonzo	case TBACKGND:
570243423Sgonzo	case TSEMI:
571243423Sgonzo	case TAND:
572243423Sgonzo	case TOR:
573243423Sgonzo		/*
574243423Sgonzo		 * An empty command before a ; doesn't make much sense, and
575243423Sgonzo		 * should certainly be disallowed in the case of `if ;'.
576243423Sgonzo		 */
577243423Sgonzo		if (!redir)
578243423Sgonzo			synexpect(-1);
579243423Sgonzo	case TNL:
580243423Sgonzo	case TEOF:
581243423Sgonzo	case TWORD:
582243423Sgonzo	case TRP:
583239922Sgonzo		tokpushback++;
584239922Sgonzo		n1 = simplecmd(rpp, redir);
585239922Sgonzo		return n1;
586243423Sgonzo	default:
587239922Sgonzo		synexpect(-1);
588243423Sgonzo	}
589243423Sgonzo
590243423Sgonzo	/* Now check for redirection which may follow command */
591239922Sgonzo	while (readtoken() == TREDIR) {
592243423Sgonzo		*rpp = n2 = redirnode;
593243423Sgonzo		rpp = &n2->nfile.next;
594239922Sgonzo		parsefname();
595243423Sgonzo	}
596243423Sgonzo	tokpushback++;
597239922Sgonzo	*rpp = NULL;
598243423Sgonzo	if (redir) {
599243423Sgonzo		if (n1->type != NSUBSHELL) {
600243423Sgonzo			n2 = (union node *)stalloc(sizeof (struct nredir));
601243423Sgonzo			n2->type = NREDIR;
602243423Sgonzo			n2->nredir.n = n1;
603243423Sgonzo			n1 = n2;
604243423Sgonzo		}
605243423Sgonzo		n1->nredir.redirect = redir;
606243423Sgonzo	}
607243423Sgonzo
608243423Sgonzo	return n1;
609239922Sgonzo}
610243423Sgonzo
611243423Sgonzo
612243423Sgonzostatic union node *
613243423Sgonzosimplecmd(union node **rpp, union node *redir)
614239922Sgonzo{
615243423Sgonzo	union node *args, **app;
616243423Sgonzo	union node **orig_rpp = rpp;
617243423Sgonzo	union node *n = NULL;
618243423Sgonzo	int special;
619243423Sgonzo
620243423Sgonzo	/* If we don't have any redirections already, then we must reset */
621243423Sgonzo	/* rpp to be the address of the local redir variable.  */
622243423Sgonzo	if (redir == 0)
623243423Sgonzo		rpp = &redir;
624239922Sgonzo
625239922Sgonzo	args = NULL;
626239922Sgonzo	app = &args;
627239922Sgonzo	/*
628239922Sgonzo	 * We save the incoming value, because we need this for shell
629239922Sgonzo	 * functions.  There can not be a redirect or an argument between
630239922Sgonzo	 * the function name and the open parenthesis.
631239922Sgonzo	 */
632239922Sgonzo	orig_rpp = rpp;
633239922Sgonzo
634239922Sgonzo	for (;;) {
635239922Sgonzo		if (readtoken() == TWORD) {
636239922Sgonzo			n = (union node *)stalloc(sizeof (struct narg));
637239922Sgonzo			n->type = NARG;
638239922Sgonzo			n->narg.text = wordtext;
639239922Sgonzo			n->narg.backquote = backquotelist;
640239922Sgonzo			*app = n;
641239922Sgonzo			app = &n->narg.next;
642239922Sgonzo		} else if (lasttoken == TREDIR) {
643239922Sgonzo			*rpp = n = redirnode;
644239922Sgonzo			rpp = &n->nfile.next;
645239922Sgonzo			parsefname();	/* read name of redirection file */
646239922Sgonzo		} else if (lasttoken == TLP && app == &args->narg.next
647239922Sgonzo					    && rpp == orig_rpp) {
648243423Sgonzo			/* We have a function */
649239922Sgonzo			if (readtoken() != TRP)
650239922Sgonzo				synexpect(TRP);
651239922Sgonzo			funclinno = plinno;
652239922Sgonzo			/*
653239922Sgonzo			 * - Require plain text.
654239922Sgonzo			 * - Functions with '/' cannot be called.
655239922Sgonzo			 * - Reject name=().
656239922Sgonzo			 * - Reject ksh extended glob patterns.
657239922Sgonzo			 */
658239922Sgonzo			if (!noexpand(n->narg.text) || quoteflag ||
659239922Sgonzo			    strchr(n->narg.text, '/') ||
660239922Sgonzo			    strchr("!%*+-=?@}~",
661239922Sgonzo				n->narg.text[strlen(n->narg.text) - 1]))
662239922Sgonzo				synerror("Bad function name");
663243423Sgonzo			rmescapes(n->narg.text);
664239922Sgonzo			if (find_builtin(n->narg.text, &special) >= 0 &&
665239922Sgonzo			    special)
666239922Sgonzo				synerror("Cannot override a special builtin with a function");
667239922Sgonzo			n->type = NDEFUN;
668239922Sgonzo			n->narg.next = command();
669239922Sgonzo			funclinno = 0;
670239922Sgonzo			return n;
671239922Sgonzo		} else {
672239922Sgonzo			tokpushback++;
673239922Sgonzo			break;
674239922Sgonzo		}
675239922Sgonzo	}
676239922Sgonzo	*app = NULL;
677239922Sgonzo	*rpp = NULL;
678239922Sgonzo	n = (union node *)stalloc(sizeof (struct ncmd));
679239922Sgonzo	n->type = NCMD;
680239922Sgonzo	n->ncmd.backgnd = 0;
681239922Sgonzo	n->ncmd.args = args;
682239922Sgonzo	n->ncmd.redirect = redir;
683239922Sgonzo	return n;
684239922Sgonzo}
685239922Sgonzo
686239922Sgonzostatic union node *
687239922Sgonzomakename(void)
688239922Sgonzo{
689239922Sgonzo	union node *n;
690239922Sgonzo
691239922Sgonzo	n = (union node *)stalloc(sizeof (struct narg));
692239922Sgonzo	n->type = NARG;
693239922Sgonzo	n->narg.next = NULL;
694239922Sgonzo	n->narg.text = wordtext;
695239922Sgonzo	n->narg.backquote = backquotelist;
696239922Sgonzo	return n;
697239922Sgonzo}
698239922Sgonzo
699239922Sgonzovoid
700239922Sgonzofixredir(union node *n, const char *text, int err)
701239922Sgonzo{
702239922Sgonzo	TRACE(("Fix redir %s %d\n", text, err));
703239922Sgonzo	if (!err)
704239922Sgonzo		n->ndup.vname = NULL;
705239922Sgonzo
706239922Sgonzo	if (is_digit(text[0]) && text[1] == '\0')
707239922Sgonzo		n->ndup.dupfd = digit_val(text[0]);
708239922Sgonzo	else if (text[0] == '-' && text[1] == '\0')
709239922Sgonzo		n->ndup.dupfd = -1;
710239922Sgonzo	else {
711239922Sgonzo
712239922Sgonzo		if (err)
713239922Sgonzo			synerror("Bad fd number");
714239922Sgonzo		else
715239922Sgonzo			n->ndup.vname = makename();
716239922Sgonzo	}
717239922Sgonzo}
718239922Sgonzo
719239922Sgonzo
720239922Sgonzostatic void
721239922Sgonzoparsefname(void)
722239922Sgonzo{
723239922Sgonzo	union node *n = redirnode;
724239922Sgonzo
725239922Sgonzo	if (readtoken() != TWORD)
726239922Sgonzo		synexpect(-1);
727239922Sgonzo	if (n->type == NHERE) {
728239922Sgonzo		struct heredoc *here = heredoc;
729239922Sgonzo		struct heredoc *p;
730239922Sgonzo		int i;
731239922Sgonzo
732239922Sgonzo		if (quoteflag == 0)
733239922Sgonzo			n->type = NXHERE;
734239922Sgonzo		TRACE(("Here document %d\n", n->type));
735239922Sgonzo		if (here->striptabs) {
736239922Sgonzo			while (*wordtext == '\t')
737239922Sgonzo				wordtext++;
738239922Sgonzo		}
739239922Sgonzo		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
740239922Sgonzo			synerror("Illegal eof marker for << redirection");
741239922Sgonzo		rmescapes(wordtext);
742239922Sgonzo		here->eofmark = wordtext;
743239922Sgonzo		here->next = NULL;
744239922Sgonzo		if (heredoclist == NULL)
745239922Sgonzo			heredoclist = here;
746239922Sgonzo		else {
747239922Sgonzo			for (p = heredoclist ; p->next ; p = p->next);
748239922Sgonzo			p->next = here;
749239922Sgonzo		}
750239922Sgonzo	} else if (n->type == NTOFD || n->type == NFROMFD) {
751239922Sgonzo		fixredir(n, wordtext, 0);
752239922Sgonzo	} else {
753239922Sgonzo		n->nfile.fname = makename();
754239922Sgonzo	}
755239922Sgonzo}
756239922Sgonzo
757239922Sgonzo
758239922Sgonzo/*
759239922Sgonzo * Input any here documents.
760239922Sgonzo */
761239922Sgonzo
762239922Sgonzostatic void
763239922Sgonzoparseheredoc(void)
764239922Sgonzo{
765239922Sgonzo	struct heredoc *here;
766239922Sgonzo	union node *n;
767239922Sgonzo
768239922Sgonzo	while (heredoclist) {
769239922Sgonzo		here = heredoclist;
770239922Sgonzo		heredoclist = here->next;
771239922Sgonzo		if (needprompt) {
772239922Sgonzo			setprompt(2);
773239922Sgonzo			needprompt = 0;
774239922Sgonzo		}
775239922Sgonzo		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
776243423Sgonzo				here->eofmark, here->striptabs);
777243423Sgonzo		n = (union node *)stalloc(sizeof (struct narg));
778243423Sgonzo		n->narg.type = NARG;
779243423Sgonzo		n->narg.next = NULL;
780243423Sgonzo		n->narg.text = wordtext;
781243423Sgonzo		n->narg.backquote = backquotelist;
782239922Sgonzo		here->here->nhere.doc = n;
783239922Sgonzo	}
784239922Sgonzo}
785239922Sgonzo
786239922Sgonzostatic int
787239922Sgonzopeektoken(void)
788239922Sgonzo{
789239922Sgonzo	int t;
790239922Sgonzo
791239922Sgonzo	t = readtoken();
792239922Sgonzo	tokpushback++;
793239922Sgonzo	return (t);
794239922Sgonzo}
795239922Sgonzo
796239922Sgonzostatic int
797239922Sgonzoreadtoken(void)
798239922Sgonzo{
799239922Sgonzo	int t;
800239922Sgonzo	struct alias *ap;
801239922Sgonzo#ifdef DEBUG
802239922Sgonzo	int alreadyseen = tokpushback;
803239922Sgonzo#endif
804239922Sgonzo
805239922Sgonzo	top:
806239922Sgonzo	t = xxreadtoken();
807239922Sgonzo
808239922Sgonzo	/*
809239922Sgonzo	 * eat newlines
810239922Sgonzo	 */
811239922Sgonzo	if (checkkwd & CHKNL) {
812239922Sgonzo		while (t == TNL) {
813239922Sgonzo			parseheredoc();
814239922Sgonzo			t = xxreadtoken();
815239922Sgonzo		}
816239922Sgonzo	}
817239922Sgonzo
818239922Sgonzo	/*
819239922Sgonzo	 * check for keywords and aliases
820239922Sgonzo	 */
821239922Sgonzo	if (t == TWORD && !quoteflag)
822239922Sgonzo	{
823239922Sgonzo		const char * const *pp;
824239922Sgonzo
825239922Sgonzo		if (checkkwd & CHKKWD)
826239922Sgonzo			for (pp = parsekwd; *pp; pp++) {
827239922Sgonzo				if (**pp == *wordtext && equal(*pp, wordtext))
828239922Sgonzo				{
829239922Sgonzo					lasttoken = t = pp - parsekwd + KWDOFFSET;
830239922Sgonzo					TRACE(("keyword %s recognized\n", tokname[t]));
831239922Sgonzo					goto out;
832239922Sgonzo				}
833239922Sgonzo			}
834239922Sgonzo		if (checkkwd & CHKALIAS &&
835239922Sgonzo		    (ap = lookupalias(wordtext, 1)) != NULL) {
836239922Sgonzo			pushstring(ap->val, strlen(ap->val), ap);
837239922Sgonzo			goto top;
838239922Sgonzo		}
839239922Sgonzo	}
840239922Sgonzoout:
841239922Sgonzo	if (t != TNOT)
842239922Sgonzo		checkkwd = 0;
843239922Sgonzo
844239922Sgonzo#ifdef DEBUG
845239922Sgonzo	if (!alreadyseen)
846239922Sgonzo	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
847239922Sgonzo	else
848239922Sgonzo	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
849239922Sgonzo#endif
850239922Sgonzo	return (t);
851239922Sgonzo}
852239922Sgonzo
853239922Sgonzo
854239922Sgonzo/*
855239922Sgonzo * Read the next input token.
856239922Sgonzo * If the token is a word, we set backquotelist to the list of cmds in
857239922Sgonzo *	backquotes.  We set quoteflag to true if any part of the word was
858239922Sgonzo *	quoted.
859239922Sgonzo * If the token is TREDIR, then we set redirnode to a structure containing
860239922Sgonzo *	the redirection.
861239922Sgonzo * In all cases, the variable startlinno is set to the number of the line
862239922Sgonzo *	on which the token starts.
863239922Sgonzo *
864239922Sgonzo * [Change comment:  here documents and internal procedures]
865239922Sgonzo * [Readtoken shouldn't have any arguments.  Perhaps we should make the
866239922Sgonzo *  word parsing code into a separate routine.  In this case, readtoken
867239922Sgonzo *  doesn't need to have any internal procedures, but parseword does.
868239922Sgonzo *  We could also make parseoperator in essence the main routine, and
869239922Sgonzo *  have parseword (readtoken1?) handle both words and redirection.]
870239922Sgonzo */
871239922Sgonzo
872239922Sgonzo#define RETURN(token)	return lasttoken = token
873239922Sgonzo
874239922Sgonzostatic int
875239922Sgonzoxxreadtoken(void)
876239922Sgonzo{
877239922Sgonzo	int c;
878239922Sgonzo
879243423Sgonzo	if (tokpushback) {
880239922Sgonzo		tokpushback = 0;
881239922Sgonzo		return lasttoken;
882239922Sgonzo	}
883239922Sgonzo	if (needprompt) {
884239922Sgonzo		setprompt(2);
885239922Sgonzo		needprompt = 0;
886239922Sgonzo	}
887239922Sgonzo	startlinno = plinno;
888239922Sgonzo	for (;;) {	/* until token or start of word found */
889239922Sgonzo		c = pgetc_macro();
890239922Sgonzo		switch (c) {
891243666Sgonzo		case ' ': case '\t':
892239922Sgonzo			continue;
893243423Sgonzo		case '#':
894245071Sgonzo			while ((c = pgetc()) != '\n' && c != PEOF);
895239922Sgonzo			pungetc();
896239922Sgonzo			continue;
897239922Sgonzo		case '\\':
898239922Sgonzo			if (pgetc() == '\n') {
899239922Sgonzo				startlinno = ++plinno;
900239922Sgonzo				if (doprompt)
901239922Sgonzo					setprompt(2);
902239922Sgonzo				else
903243423Sgonzo					setprompt(0);
904243423Sgonzo				continue;
905243423Sgonzo			}
906243423Sgonzo			pungetc();
907243423Sgonzo			goto breakloop;
908243423Sgonzo		case '\n':
909243423Sgonzo			plinno++;
910243423Sgonzo			needprompt = doprompt;
911243423Sgonzo			RETURN(TNL);
912243423Sgonzo		case PEOF:
913243423Sgonzo			RETURN(TEOF);
914243423Sgonzo		case '&':
915243423Sgonzo			if (pgetc() == '&')
916243687Sgonzo				RETURN(TAND);
917243687Sgonzo			pungetc();
918243423Sgonzo			RETURN(TBACKGND);
919243687Sgonzo		case '|':
920243687Sgonzo			if (pgetc() == '|')
921243423Sgonzo				RETURN(TOR);
922243423Sgonzo			pungetc();
923243423Sgonzo			RETURN(TPIPE);
924243423Sgonzo		case ';':
925239922Sgonzo			if (pgetc() == ';')
926239922Sgonzo				RETURN(TENDCASE);
927239922Sgonzo			pungetc();
928239922Sgonzo			RETURN(TSEMI);
929239922Sgonzo		case '(':
930239922Sgonzo			RETURN(TLP);
931239922Sgonzo		case ')':
932239922Sgonzo			RETURN(TRP);
933239922Sgonzo		default:
934239922Sgonzo			goto breakloop;
935239922Sgonzo		}
936239922Sgonzo	}
937239922Sgonzobreakloop:
938239922Sgonzo	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
939239922Sgonzo#undef RETURN
940239922Sgonzo}
941239922Sgonzo
942239922Sgonzo
943239922Sgonzo#define MAXNEST_static 8
944239922Sgonzostruct tokenstate
945239922Sgonzo{
946239922Sgonzo	const char *syntax; /* *SYNTAX */
947239922Sgonzo	int parenlevel; /* levels of parentheses in arithmetic */
948239922Sgonzo	enum tokenstate_category
949239922Sgonzo	{
950239922Sgonzo		TSTATE_TOP,
951239922Sgonzo		TSTATE_VAR_OLD, /* ${var+-=?}, inherits dquotes */
952239922Sgonzo		TSTATE_VAR_NEW, /* other ${var...}, own dquote state */
953239922Sgonzo		TSTATE_ARITH
954239922Sgonzo	} category;
955239922Sgonzo};
956239922Sgonzo
957239922Sgonzo
958239922Sgonzo/*
959239922Sgonzo * Called to parse command substitutions.
960239922Sgonzo */
961239922Sgonzo
962239922Sgonzostatic char *
963239922Sgonzoparsebackq(char *out, struct nodelist **pbqlist,
964239922Sgonzo		int oldstyle, int dblquote, int quoted)
965239922Sgonzo{
966239922Sgonzo	struct nodelist **nlpp;
967239922Sgonzo	union node *n;
968239922Sgonzo	char *volatile str;
969239922Sgonzo	struct jmploc jmploc;
970	struct jmploc *const savehandler = handler;
971	int savelen;
972	int saveprompt;
973	const int bq_startlinno = plinno;
974	char *volatile ostr = NULL;
975	struct parsefile *const savetopfile = getcurrentfile();
976	struct heredoc *const saveheredoclist = heredoclist;
977	struct heredoc *here;
978
979	str = NULL;
980	if (setjmp(jmploc.loc)) {
981		popfilesupto(savetopfile);
982		if (str)
983			ckfree(str);
984		if (ostr)
985			ckfree(ostr);
986		heredoclist = saveheredoclist;
987		handler = savehandler;
988		if (exception == EXERROR) {
989			startlinno = bq_startlinno;
990			synerror("Error in command substitution");
991		}
992		longjmp(handler->loc, 1);
993	}
994	INTOFF;
995	savelen = out - stackblock();
996	if (savelen > 0) {
997		str = ckmalloc(savelen);
998		memcpy(str, stackblock(), savelen);
999	}
1000	handler = &jmploc;
1001	heredoclist = NULL;
1002	INTON;
1003        if (oldstyle) {
1004                /* We must read until the closing backquote, giving special
1005                   treatment to some slashes, and then push the string and
1006                   reread it as input, interpreting it normally.  */
1007                char *oout;
1008                int c;
1009                int olen;
1010
1011
1012                STARTSTACKSTR(oout);
1013		for (;;) {
1014			if (needprompt) {
1015				setprompt(2);
1016				needprompt = 0;
1017			}
1018			CHECKSTRSPACE(2, oout);
1019			switch (c = pgetc()) {
1020			case '`':
1021				goto done;
1022
1023			case '\\':
1024                                if ((c = pgetc()) == '\n') {
1025					plinno++;
1026					if (doprompt)
1027						setprompt(2);
1028					else
1029						setprompt(0);
1030					/*
1031					 * If eating a newline, avoid putting
1032					 * the newline into the new character
1033					 * stream (via the USTPUTC after the
1034					 * switch).
1035					 */
1036					continue;
1037				}
1038                                if (c != '\\' && c != '`' && c != '$'
1039                                    && (!dblquote || c != '"'))
1040                                        USTPUTC('\\', oout);
1041				break;
1042
1043			case '\n':
1044				plinno++;
1045				needprompt = doprompt;
1046				break;
1047
1048			case PEOF:
1049			        startlinno = plinno;
1050				synerror("EOF in backquote substitution");
1051 				break;
1052
1053			default:
1054				break;
1055			}
1056			USTPUTC(c, oout);
1057                }
1058done:
1059                USTPUTC('\0', oout);
1060                olen = oout - stackblock();
1061		INTOFF;
1062		ostr = ckmalloc(olen);
1063		memcpy(ostr, stackblock(), olen);
1064		setinputstring(ostr, 1);
1065		INTON;
1066        }
1067	nlpp = pbqlist;
1068	while (*nlpp)
1069		nlpp = &(*nlpp)->next;
1070	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1071	(*nlpp)->next = NULL;
1072
1073	if (oldstyle) {
1074		saveprompt = doprompt;
1075		doprompt = 0;
1076	}
1077
1078	n = list(0, oldstyle);
1079
1080	if (oldstyle)
1081		doprompt = saveprompt;
1082	else {
1083		if (readtoken() != TRP)
1084			synexpect(TRP);
1085	}
1086
1087	(*nlpp)->n = n;
1088        if (oldstyle) {
1089		/*
1090		 * Start reading from old file again, ignoring any pushed back
1091		 * tokens left from the backquote parsing
1092		 */
1093                popfile();
1094		tokpushback = 0;
1095	}
1096	while (stackblocksize() <= savelen)
1097		growstackblock();
1098	STARTSTACKSTR(out);
1099	INTOFF;
1100	if (str) {
1101		memcpy(out, str, savelen);
1102		STADJUST(savelen, out);
1103		ckfree(str);
1104		str = NULL;
1105	}
1106	if (ostr) {
1107		ckfree(ostr);
1108		ostr = NULL;
1109	}
1110	here = saveheredoclist;
1111	if (here != NULL) {
1112		while (here->next != NULL)
1113			here = here->next;
1114		here->next = heredoclist;
1115		heredoclist = saveheredoclist;
1116	}
1117	handler = savehandler;
1118	INTON;
1119	if (quoted)
1120		USTPUTC(CTLBACKQ | CTLQUOTE, out);
1121	else
1122		USTPUTC(CTLBACKQ, out);
1123	return out;
1124}
1125
1126
1127/*
1128 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
1129 * is not NULL, read a here document.  In the latter case, eofmark is the
1130 * word which marks the end of the document and striptabs is true if
1131 * leading tabs should be stripped from the document.  The argument firstc
1132 * is the first character of the input token or document.
1133 *
1134 * Because C does not have internal subroutines, I have simulated them
1135 * using goto's to implement the subroutine linkage.  The following macros
1136 * will run code that appears at the end of readtoken1.
1137 */
1138
1139#define CHECKEND()	{goto checkend; checkend_return:;}
1140#define PARSEREDIR()	{goto parseredir; parseredir_return:;}
1141#define PARSESUB()	{goto parsesub; parsesub_return:;}
1142#define	PARSEARITH()	{goto parsearith; parsearith_return:;}
1143
1144static int
1145readtoken1(int firstc, char const *initialsyntax, char *eofmark, int striptabs)
1146{
1147	int c = firstc;
1148	char *out;
1149	int len;
1150	char line[EOFMARKLEN + 1];
1151	struct nodelist *bqlist;
1152	int quotef;
1153	int newvarnest;
1154	int level;
1155	int synentry;
1156	struct tokenstate state_static[MAXNEST_static];
1157	int maxnest = MAXNEST_static;
1158	struct tokenstate *state = state_static;
1159
1160	startlinno = plinno;
1161	quotef = 0;
1162	bqlist = NULL;
1163	newvarnest = 0;
1164	level = 0;
1165	state[level].syntax = initialsyntax;
1166	state[level].parenlevel = 0;
1167	state[level].category = TSTATE_TOP;
1168
1169	STARTSTACKSTR(out);
1170	loop: {	/* for each line, until end of word */
1171		CHECKEND();	/* set c to PEOF if at end of here document */
1172		for (;;) {	/* until end of line or end of word */
1173			CHECKSTRSPACE(4, out);	/* permit 4 calls to USTPUTC */
1174
1175			synentry = state[level].syntax[c];
1176
1177			switch(synentry) {
1178			case CNL:	/* '\n' */
1179				if (state[level].syntax == BASESYNTAX)
1180					goto endword;	/* exit outer loop */
1181				USTPUTC(c, out);
1182				plinno++;
1183				if (doprompt)
1184					setprompt(2);
1185				else
1186					setprompt(0);
1187				c = pgetc();
1188				goto loop;		/* continue outer loop */
1189			case CWORD:
1190				USTPUTC(c, out);
1191				break;
1192			case CCTL:
1193				if (eofmark == NULL || initialsyntax != SQSYNTAX)
1194					USTPUTC(CTLESC, out);
1195				USTPUTC(c, out);
1196				break;
1197			case CBACK:	/* backslash */
1198				c = pgetc();
1199				if (c == PEOF) {
1200					USTPUTC('\\', out);
1201					pungetc();
1202				} else if (c == '\n') {
1203					plinno++;
1204					if (doprompt)
1205						setprompt(2);
1206					else
1207						setprompt(0);
1208				} else {
1209					if (state[level].syntax == DQSYNTAX &&
1210					    c != '\\' && c != '`' && c != '$' &&
1211					    (c != '"' || (eofmark != NULL &&
1212						newvarnest == 0)) &&
1213					    (c != '}' || state[level].category != TSTATE_VAR_OLD))
1214						USTPUTC('\\', out);
1215					if ((eofmark == NULL ||
1216					    newvarnest > 0) &&
1217					    state[level].syntax == BASESYNTAX)
1218						USTPUTC(CTLQUOTEMARK, out);
1219					if (SQSYNTAX[c] == CCTL)
1220						USTPUTC(CTLESC, out);
1221					USTPUTC(c, out);
1222					if ((eofmark == NULL ||
1223					    newvarnest > 0) &&
1224					    state[level].syntax == BASESYNTAX &&
1225					    state[level].category == TSTATE_VAR_OLD)
1226						USTPUTC(CTLQUOTEEND, out);
1227					quotef++;
1228				}
1229				break;
1230			case CSQUOTE:
1231				USTPUTC(CTLQUOTEMARK, out);
1232				state[level].syntax = SQSYNTAX;
1233				break;
1234			case CDQUOTE:
1235				USTPUTC(CTLQUOTEMARK, out);
1236				state[level].syntax = DQSYNTAX;
1237				break;
1238			case CENDQUOTE:
1239				if (eofmark != NULL && newvarnest == 0)
1240					USTPUTC(c, out);
1241				else {
1242					if (state[level].category == TSTATE_VAR_OLD)
1243						USTPUTC(CTLQUOTEEND, out);
1244					state[level].syntax = BASESYNTAX;
1245					quotef++;
1246				}
1247				break;
1248			case CVAR:	/* '$' */
1249				PARSESUB();		/* parse substitution */
1250				break;
1251			case CENDVAR:	/* '}' */
1252				if (level > 0 &&
1253				    ((state[level].category == TSTATE_VAR_OLD &&
1254				      state[level].syntax ==
1255				      state[level - 1].syntax) ||
1256				    (state[level].category == TSTATE_VAR_NEW &&
1257				     state[level].syntax == BASESYNTAX))) {
1258					if (state[level].category == TSTATE_VAR_NEW)
1259						newvarnest--;
1260					level--;
1261					USTPUTC(CTLENDVAR, out);
1262				} else {
1263					USTPUTC(c, out);
1264				}
1265				break;
1266			case CLP:	/* '(' in arithmetic */
1267				state[level].parenlevel++;
1268				USTPUTC(c, out);
1269				break;
1270			case CRP:	/* ')' in arithmetic */
1271				if (state[level].parenlevel > 0) {
1272					USTPUTC(c, out);
1273					--state[level].parenlevel;
1274				} else {
1275					if (pgetc() == ')') {
1276						if (level > 0 &&
1277						    state[level].category == TSTATE_ARITH) {
1278							level--;
1279							USTPUTC(CTLENDARI, out);
1280						} else
1281							USTPUTC(')', out);
1282					} else {
1283						/*
1284						 * unbalanced parens
1285						 *  (don't 2nd guess - no error)
1286						 */
1287						pungetc();
1288						USTPUTC(')', out);
1289					}
1290				}
1291				break;
1292			case CBQUOTE:	/* '`' */
1293				out = parsebackq(out, &bqlist, 1,
1294				    state[level].syntax == DQSYNTAX &&
1295				    (eofmark == NULL || newvarnest > 0),
1296				    state[level].syntax == DQSYNTAX || state[level].syntax == ARISYNTAX);
1297				break;
1298			case CEOF:
1299				goto endword;		/* exit outer loop */
1300			case CIGN:
1301				break;
1302			default:
1303				if (level == 0)
1304					goto endword;	/* exit outer loop */
1305				USTPUTC(c, out);
1306			}
1307			c = pgetc_macro();
1308		}
1309	}
1310endword:
1311	if (state[level].syntax == ARISYNTAX)
1312		synerror("Missing '))'");
1313	if (state[level].syntax != BASESYNTAX && eofmark == NULL)
1314		synerror("Unterminated quoted string");
1315	if (state[level].category == TSTATE_VAR_OLD ||
1316	    state[level].category == TSTATE_VAR_NEW) {
1317		startlinno = plinno;
1318		synerror("Missing '}'");
1319	}
1320	if (state != state_static)
1321		parser_temp_free_upto(state);
1322	USTPUTC('\0', out);
1323	len = out - stackblock();
1324	out = stackblock();
1325	if (eofmark == NULL) {
1326		if ((c == '>' || c == '<')
1327		 && quotef == 0
1328		 && len <= 2
1329		 && (*out == '\0' || is_digit(*out))) {
1330			PARSEREDIR();
1331			return lasttoken = TREDIR;
1332		} else {
1333			pungetc();
1334		}
1335	}
1336	quoteflag = quotef;
1337	backquotelist = bqlist;
1338	grabstackblock(len);
1339	wordtext = out;
1340	return lasttoken = TWORD;
1341/* end of readtoken routine */
1342
1343
1344/*
1345 * Check to see whether we are at the end of the here document.  When this
1346 * is called, c is set to the first character of the next input line.  If
1347 * we are at the end of the here document, this routine sets the c to PEOF.
1348 */
1349
1350checkend: {
1351	if (eofmark) {
1352		if (striptabs) {
1353			while (c == '\t')
1354				c = pgetc();
1355		}
1356		if (c == *eofmark) {
1357			if (pfgets(line, sizeof line) != NULL) {
1358				char *p, *q;
1359
1360				p = line;
1361				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1362				if (*p == '\n' && *q == '\0') {
1363					c = PEOF;
1364					plinno++;
1365					needprompt = doprompt;
1366				} else {
1367					pushstring(line, strlen(line), NULL);
1368				}
1369			}
1370		}
1371	}
1372	goto checkend_return;
1373}
1374
1375
1376/*
1377 * Parse a redirection operator.  The variable "out" points to a string
1378 * specifying the fd to be redirected.  The variable "c" contains the
1379 * first character of the redirection operator.
1380 */
1381
1382parseredir: {
1383	char fd = *out;
1384	union node *np;
1385
1386	np = (union node *)stalloc(sizeof (struct nfile));
1387	if (c == '>') {
1388		np->nfile.fd = 1;
1389		c = pgetc();
1390		if (c == '>')
1391			np->type = NAPPEND;
1392		else if (c == '&')
1393			np->type = NTOFD;
1394		else if (c == '|')
1395			np->type = NCLOBBER;
1396		else {
1397			np->type = NTO;
1398			pungetc();
1399		}
1400	} else {	/* c == '<' */
1401		np->nfile.fd = 0;
1402		c = pgetc();
1403		if (c == '<') {
1404			if (sizeof (struct nfile) != sizeof (struct nhere)) {
1405				np = (union node *)stalloc(sizeof (struct nhere));
1406				np->nfile.fd = 0;
1407			}
1408			np->type = NHERE;
1409			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1410			heredoc->here = np;
1411			if ((c = pgetc()) == '-') {
1412				heredoc->striptabs = 1;
1413			} else {
1414				heredoc->striptabs = 0;
1415				pungetc();
1416			}
1417		} else if (c == '&')
1418			np->type = NFROMFD;
1419		else if (c == '>')
1420			np->type = NFROMTO;
1421		else {
1422			np->type = NFROM;
1423			pungetc();
1424		}
1425	}
1426	if (fd != '\0')
1427		np->nfile.fd = digit_val(fd);
1428	redirnode = np;
1429	goto parseredir_return;
1430}
1431
1432
1433/*
1434 * Parse a substitution.  At this point, we have read the dollar sign
1435 * and nothing else.
1436 */
1437
1438parsesub: {
1439	char buf[10];
1440	int subtype;
1441	int typeloc;
1442	int flags;
1443	char *p;
1444	static const char types[] = "}-+?=";
1445	int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
1446	int linno;
1447	int length;
1448
1449	c = pgetc();
1450	if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) &&
1451	    !is_special(c)) {
1452		USTPUTC('$', out);
1453		pungetc();
1454	} else if (c == '(') {	/* $(command) or $((arith)) */
1455		if (pgetc() == '(') {
1456			PARSEARITH();
1457		} else {
1458			pungetc();
1459			out = parsebackq(out, &bqlist, 0,
1460			    state[level].syntax == DQSYNTAX &&
1461			    (eofmark == NULL || newvarnest > 0),
1462			    state[level].syntax == DQSYNTAX ||
1463			    state[level].syntax == ARISYNTAX);
1464		}
1465	} else {
1466		USTPUTC(CTLVAR, out);
1467		typeloc = out - stackblock();
1468		USTPUTC(VSNORMAL, out);
1469		subtype = VSNORMAL;
1470		flags = 0;
1471		if (c == '{') {
1472			bracketed_name = 1;
1473			c = pgetc();
1474			if (c == '#') {
1475				if ((c = pgetc()) == '}')
1476					c = '#';
1477				else
1478					subtype = VSLENGTH;
1479			}
1480			else
1481				subtype = 0;
1482		}
1483		if (!is_eof(c) && is_name(c)) {
1484			length = 0;
1485			do {
1486				STPUTC(c, out);
1487				c = pgetc();
1488				length++;
1489			} while (!is_eof(c) && is_in_name(c));
1490			if (length == 6 &&
1491			    strncmp(out - length, "LINENO", length) == 0) {
1492				/* Replace the variable name with the
1493				 * current line number. */
1494				linno = plinno;
1495				if (funclinno != 0)
1496					linno -= funclinno - 1;
1497				snprintf(buf, sizeof(buf), "%d", linno);
1498				STADJUST(-6, out);
1499				STPUTS(buf, out);
1500				flags |= VSLINENO;
1501			}
1502		} else if (is_digit(c)) {
1503			if (bracketed_name) {
1504				do {
1505					STPUTC(c, out);
1506					c = pgetc();
1507				} while (is_digit(c));
1508			} else {
1509				STPUTC(c, out);
1510				c = pgetc();
1511			}
1512		} else {
1513			if (! is_special(c)) {
1514				subtype = VSERROR;
1515				if (c == '}')
1516					pungetc();
1517				else if (c == '\n' || c == PEOF)
1518					synerror("Unexpected end of line in substitution");
1519				else
1520					USTPUTC(c, out);
1521			} else {
1522				USTPUTC(c, out);
1523				c = pgetc();
1524			}
1525		}
1526		if (subtype == 0) {
1527			switch (c) {
1528			case ':':
1529				flags |= VSNUL;
1530				c = pgetc();
1531				/*FALLTHROUGH*/
1532			default:
1533				p = strchr(types, c);
1534				if (p == NULL) {
1535					if (c == '\n' || c == PEOF)
1536						synerror("Unexpected end of line in substitution");
1537					if (flags == VSNUL)
1538						STPUTC(':', out);
1539					STPUTC(c, out);
1540					subtype = VSERROR;
1541				} else
1542					subtype = p - types + VSNORMAL;
1543				break;
1544			case '%':
1545			case '#':
1546				{
1547					int cc = c;
1548					subtype = c == '#' ? VSTRIMLEFT :
1549							     VSTRIMRIGHT;
1550					c = pgetc();
1551					if (c == cc)
1552						subtype++;
1553					else
1554						pungetc();
1555					break;
1556				}
1557			}
1558		} else if (subtype != VSERROR) {
1559			pungetc();
1560		}
1561		STPUTC('=', out);
1562		if (subtype != VSLENGTH && (state[level].syntax == DQSYNTAX ||
1563		    state[level].syntax == ARISYNTAX))
1564			flags |= VSQUOTE;
1565		*(stackblock() + typeloc) = subtype | flags;
1566		if (subtype != VSNORMAL) {
1567			if (level + 1 >= maxnest) {
1568				maxnest *= 2;
1569				if (state == state_static) {
1570					state = parser_temp_alloc(
1571					    maxnest * sizeof(*state));
1572					memcpy(state, state_static,
1573					    MAXNEST_static * sizeof(*state));
1574				} else
1575					state = parser_temp_realloc(state,
1576					    maxnest * sizeof(*state));
1577			}
1578			level++;
1579			state[level].parenlevel = 0;
1580			if (subtype == VSMINUS || subtype == VSPLUS ||
1581			    subtype == VSQUESTION || subtype == VSASSIGN) {
1582				/*
1583				 * For operators that were in the Bourne shell,
1584				 * inherit the double-quote state.
1585				 */
1586				state[level].syntax = state[level - 1].syntax;
1587				state[level].category = TSTATE_VAR_OLD;
1588			} else {
1589				/*
1590				 * The other operators take a pattern,
1591				 * so go to BASESYNTAX.
1592				 * Also, ' and " are now special, even
1593				 * in here documents.
1594				 */
1595				state[level].syntax = BASESYNTAX;
1596				state[level].category = TSTATE_VAR_NEW;
1597				newvarnest++;
1598			}
1599		}
1600	}
1601	goto parsesub_return;
1602}
1603
1604
1605/*
1606 * Parse an arithmetic expansion (indicate start of one and set state)
1607 */
1608parsearith: {
1609
1610	if (level + 1 >= maxnest) {
1611		maxnest *= 2;
1612		if (state == state_static) {
1613			state = parser_temp_alloc(
1614			    maxnest * sizeof(*state));
1615			memcpy(state, state_static,
1616			    MAXNEST_static * sizeof(*state));
1617		} else
1618			state = parser_temp_realloc(state,
1619			    maxnest * sizeof(*state));
1620	}
1621	level++;
1622	state[level].syntax = ARISYNTAX;
1623	state[level].parenlevel = 0;
1624	state[level].category = TSTATE_ARITH;
1625	USTPUTC(CTLARI, out);
1626	if (state[level - 1].syntax == DQSYNTAX)
1627		USTPUTC('"',out);
1628	else
1629		USTPUTC(' ',out);
1630	goto parsearith_return;
1631}
1632
1633} /* end of readtoken */
1634
1635
1636
1637#ifdef mkinit
1638RESET {
1639	tokpushback = 0;
1640	checkkwd = 0;
1641}
1642#endif
1643
1644/*
1645 * Returns true if the text contains nothing to expand (no dollar signs
1646 * or backquotes).
1647 */
1648
1649static int
1650noexpand(char *text)
1651{
1652	char *p;
1653	char c;
1654
1655	p = text;
1656	while ((c = *p++) != '\0') {
1657		if ( c == CTLQUOTEMARK)
1658			continue;
1659		if (c == CTLESC)
1660			p++;
1661		else if (BASESYNTAX[(int)c] == CCTL)
1662			return 0;
1663	}
1664	return 1;
1665}
1666
1667
1668/*
1669 * Return true if the argument is a legal variable name (a letter or
1670 * underscore followed by zero or more letters, underscores, and digits).
1671 */
1672
1673int
1674goodname(const char *name)
1675{
1676	const char *p;
1677
1678	p = name;
1679	if (! is_name(*p))
1680		return 0;
1681	while (*++p) {
1682		if (! is_in_name(*p))
1683			return 0;
1684	}
1685	return 1;
1686}
1687
1688
1689/*
1690 * Called when an unexpected token is read during the parse.  The argument
1691 * is the token that is expected, or -1 if more than one type of token can
1692 * occur at this point.
1693 */
1694
1695static void
1696synexpect(int token)
1697{
1698	char msg[64];
1699
1700	if (token >= 0) {
1701		fmtstr(msg, 64, "%s unexpected (expecting %s)",
1702			tokname[lasttoken], tokname[token]);
1703	} else {
1704		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1705	}
1706	synerror(msg);
1707}
1708
1709
1710static void
1711synerror(const char *msg)
1712{
1713	if (commandname)
1714		outfmt(out2, "%s: %d: ", commandname, startlinno);
1715	outfmt(out2, "Syntax error: %s\n", msg);
1716	error((char *)NULL);
1717}
1718
1719static void
1720setprompt(int which)
1721{
1722	whichprompt = which;
1723
1724#ifndef NO_HISTORY
1725	if (!el)
1726#endif
1727	{
1728		out2str(getprompt(NULL));
1729		flushout(out2);
1730	}
1731}
1732
1733/*
1734 * called by editline -- any expansions to the prompt
1735 *    should be added here.
1736 */
1737char *
1738getprompt(void *unused __unused)
1739{
1740	static char ps[PROMPTLEN];
1741	char *fmt;
1742	const char *pwd;
1743	int i, trim;
1744	static char internal_error[] = "??";
1745
1746	/*
1747	 * Select prompt format.
1748	 */
1749	switch (whichprompt) {
1750	case 0:
1751		fmt = nullstr;
1752		break;
1753	case 1:
1754		fmt = ps1val();
1755		break;
1756	case 2:
1757		fmt = ps2val();
1758		break;
1759	default:
1760		return internal_error;
1761	}
1762
1763	/*
1764	 * Format prompt string.
1765	 */
1766	for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++)
1767		if (*fmt == '\\')
1768			switch (*++fmt) {
1769
1770				/*
1771				 * Hostname.
1772				 *
1773				 * \h specifies just the local hostname,
1774				 * \H specifies fully-qualified hostname.
1775				 */
1776			case 'h':
1777			case 'H':
1778				ps[i] = '\0';
1779				gethostname(&ps[i], PROMPTLEN - i);
1780				/* Skip to end of hostname. */
1781				trim = (*fmt == 'h') ? '.' : '\0';
1782				while ((ps[i+1] != '\0') && (ps[i+1] != trim))
1783					i++;
1784				break;
1785
1786				/*
1787				 * Working directory.
1788				 *
1789				 * \W specifies just the final component,
1790				 * \w specifies the entire path.
1791				 */
1792			case 'W':
1793			case 'w':
1794				pwd = lookupvar("PWD");
1795				if (pwd == NULL)
1796					pwd = "?";
1797				if (*fmt == 'W' &&
1798				    *pwd == '/' && pwd[1] != '\0')
1799					strlcpy(&ps[i], strrchr(pwd, '/') + 1,
1800					    PROMPTLEN - i);
1801				else
1802					strlcpy(&ps[i], pwd, PROMPTLEN - i);
1803				/* Skip to end of path. */
1804				while (ps[i + 1] != '\0')
1805					i++;
1806				break;
1807
1808				/*
1809				 * Superuser status.
1810				 *
1811				 * '$' for normal users, '#' for root.
1812				 */
1813			case '$':
1814				ps[i] = (geteuid() != 0) ? '$' : '#';
1815				break;
1816
1817				/*
1818				 * A literal \.
1819				 */
1820			case '\\':
1821				ps[i] = '\\';
1822				break;
1823
1824				/*
1825				 * Emit unrecognized formats verbatim.
1826				 */
1827			default:
1828				ps[i++] = '\\';
1829				ps[i] = *fmt;
1830				break;
1831			}
1832		else
1833			ps[i] = *fmt;
1834	ps[i] = '\0';
1835	return (ps);
1836}
1837