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