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