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