AMD64 - Move fdisk and nextboot up one level and remove src/sbin/i386.
[dragonfly.git] / bin / sh / parser.c
blob96d9ff5c4a1291738a9ac53f98ff4a0a06384f79
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.58 2006/11/05 18:36:05 stefanf Exp $
38 * $DragonFly: src/bin/sh/parser.c,v 1.12 2007/01/18 17:03:18 corecode Exp $
41 #include <stdlib.h>
42 #include <unistd.h>
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
64 * Shell command parser.
67 #define EOFMARKLEN 79
68 #define PROMPTLEN 128
70 /* values returned by readtoken */
71 #include "token.h"
75 struct 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 */
84 STATIC struct heredoc *heredoclist; /* list of here documents to read */
85 STATIC int parsebackquote; /* nonzero if we are inside backquotes */
86 STATIC int doprompt; /* if set, prompt the user */
87 STATIC int needprompt; /* true if interactive and at start of line */
88 STATIC int lasttoken; /* last token read */
89 MKINIT int tokpushback; /* last token pushed back */
90 STATIC char *wordtext; /* text of last word returned by readtoken */
92 * 1 == check for kwds
93 * 2 == also eat newlines
94 * 3 == check for TNOT
96 MKINIT int checkkwd;
97 STATIC struct nodelist *backquotelist;
98 STATIC union node *redirnode;
99 STATIC struct heredoc *heredoc;
100 STATIC int quoteflag; /* set if (part of) last token was quoted */
101 STATIC int startlinno; /* line # where last token started */
102 STATIC int funclinno; /* line # where the current function started */
104 /* XXX When 'noaliases' is set to one, no alias expansion takes place. */
105 static int noaliases = 0;
108 STATIC union node *list(int);
109 STATIC union node *andor(void);
110 STATIC union node *pipeline(void);
111 STATIC union node *command(void);
112 STATIC union node *simplecmd(union node **, union node *);
113 STATIC union node *makename(void);
114 STATIC void parsefname(void);
115 STATIC void parseheredoc(void);
116 STATIC int peektoken(void);
117 STATIC int readtoken(void);
118 STATIC int xxreadtoken(void);
119 STATIC int readtoken1(int, char const *, char *, int);
120 STATIC int noexpand(char *);
121 STATIC void synexpect(int);
122 STATIC void synerror(const char *);
123 STATIC void setprompt(int);
127 * Read and parse a command. Returns NEOF on end of file. (NULL is a
128 * valid parse tree indicating a blank line.)
131 union node *
132 parsecmd(int interact)
134 int t;
136 tokpushback = 0;
137 doprompt = interact;
138 if (doprompt)
139 setprompt(1);
140 else
141 setprompt(0);
142 needprompt = 0;
143 t = readtoken();
144 if (t == TEOF)
145 return NEOF;
146 if (t == TNL)
147 return NULL;
148 tokpushback++;
149 return list(1);
153 STATIC union node *
154 list(int nlflag)
156 union node *n1, *n2, *n3;
157 int tok;
159 checkkwd = 2;
160 if (nlflag == 0 && tokendlist[peektoken()])
161 return NULL;
162 n1 = NULL;
163 for (;;) {
164 n2 = andor();
165 tok = readtoken();
166 if (tok == TBACKGND) {
167 if (n2->type == NCMD || n2->type == NPIPE) {
168 n2->ncmd.backgnd = 1;
169 } else if (n2->type == NREDIR) {
170 n2->type = NBACKGND;
171 } else {
172 n3 = (union node *)stalloc(sizeof (struct nredir));
173 n3->type = NBACKGND;
174 n3->nredir.n = n2;
175 n3->nredir.redirect = NULL;
176 n2 = n3;
179 if (n1 == NULL) {
180 n1 = n2;
182 else {
183 n3 = (union node *)stalloc(sizeof (struct nbinary));
184 n3->type = NSEMI;
185 n3->nbinary.ch1 = n1;
186 n3->nbinary.ch2 = n2;
187 n1 = n3;
189 switch (tok) {
190 case TBACKGND:
191 case TSEMI:
192 tok = readtoken();
193 /* FALLTHROUGH */
194 case TNL:
195 if (tok == TNL) {
196 parseheredoc();
197 if (nlflag)
198 return n1;
199 } else {
200 tokpushback++;
202 checkkwd = 2;
203 if (tokendlist[peektoken()])
204 return n1;
205 break;
206 case TEOF:
207 if (heredoclist)
208 parseheredoc();
209 else
210 pungetc(); /* push back EOF on input */
211 return n1;
212 default:
213 if (nlflag)
214 synexpect(-1);
215 tokpushback++;
216 return n1;
223 STATIC union node *
224 andor(void)
226 union node *n1, *n2, *n3;
227 int t;
229 n1 = pipeline();
230 for (;;) {
231 if ((t = readtoken()) == TAND) {
232 t = NAND;
233 } else if (t == TOR) {
234 t = NOR;
235 } else {
236 tokpushback++;
237 return n1;
239 n2 = pipeline();
240 n3 = (union node *)stalloc(sizeof (struct nbinary));
241 n3->type = t;
242 n3->nbinary.ch1 = n1;
243 n3->nbinary.ch2 = n2;
244 n1 = n3;
250 STATIC union node *
251 pipeline(void)
253 union node *n1, *n2, *pipenode;
254 struct nodelist *lp, *prev;
255 int negate;
257 negate = 0;
258 TRACE(("pipeline: entered\n"));
260 checkkwd = 3;
261 while (readtoken() == TNOT)
262 negate = !negate;
263 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 int innernegate = 0;
276 checkkwd = 3;
277 while (readtoken() == TNOT)
278 innernegate = !innernegate;
279 tokpushback++;
281 prev = lp;
282 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
283 lp->n = command();
284 prev->next = lp;
286 if (innernegate) {
287 n2 = (union node *)stalloc(sizeof (struct nnot));
288 n2->type = NNOT;
289 n2->nnot.com = lp->n;
290 lp->n = n2;
292 } while (readtoken() == TPIPE);
293 lp->next = NULL;
294 n1 = pipenode;
296 tokpushback++;
297 if (negate) {
298 n2 = (union node *)stalloc(sizeof (struct nnot));
299 n2->type = NNOT;
300 n2->nnot.com = n1;
301 return n2;
302 } else
303 return n1;
308 STATIC union node *
309 command(void)
311 union node *n1, *n2;
312 union node *ap, **app;
313 union node *cp, **cpp;
314 union node *redir, **rpp;
315 int t;
317 checkkwd = 2;
318 redir = NULL;
319 n1 = NULL;
320 rpp = &redir;
322 /* Check for redirection which may precede command */
323 while (readtoken() == TREDIR) {
324 *rpp = n2 = redirnode;
325 rpp = &n2->nfile.next;
326 parsefname();
328 tokpushback++;
330 switch (readtoken()) {
331 case TIF:
332 n1 = (union node *)stalloc(sizeof (struct nif));
333 n1->type = NIF;
334 if ((n1->nif.test = list(0)) == NULL)
335 synexpect(-1);
336 if (readtoken() != TTHEN)
337 synexpect(TTHEN);
338 n1->nif.ifpart = list(0);
339 n2 = n1;
340 while (readtoken() == TELIF) {
341 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
342 n2 = n2->nif.elsepart;
343 n2->type = NIF;
344 if ((n2->nif.test = list(0)) == NULL)
345 synexpect(-1);
346 if (readtoken() != TTHEN)
347 synexpect(TTHEN);
348 n2->nif.ifpart = list(0);
350 if (lasttoken == TELSE)
351 n2->nif.elsepart = list(0);
352 else {
353 n2->nif.elsepart = NULL;
354 tokpushback++;
356 if (readtoken() != TFI)
357 synexpect(TFI);
358 checkkwd = 1;
359 break;
360 case TWHILE:
361 case TUNTIL: {
362 int got;
363 n1 = (union node *)stalloc(sizeof (struct nbinary));
364 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
365 if ((n1->nbinary.ch1 = list(0)) == NULL)
366 synexpect(-1);
367 if ((got=readtoken()) != TDO) {
368 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
369 synexpect(TDO);
371 n1->nbinary.ch2 = list(0);
372 if (readtoken() != TDONE)
373 synexpect(TDONE);
374 checkkwd = 1;
375 break;
377 case TFOR:
378 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
379 synerror("Bad for loop variable");
380 n1 = (union node *)stalloc(sizeof (struct nfor));
381 n1->type = NFOR;
382 n1->nfor.var = wordtext;
383 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
384 app = &ap;
385 while (readtoken() == TWORD) {
386 n2 = (union node *)stalloc(sizeof (struct narg));
387 n2->type = NARG;
388 n2->narg.text = wordtext;
389 n2->narg.backquote = backquotelist;
390 *app = n2;
391 app = &n2->narg.next;
393 *app = NULL;
394 n1->nfor.args = ap;
395 if (lasttoken != TNL && lasttoken != TSEMI)
396 synexpect(-1);
397 } else {
398 static char argvars[5] = {
399 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
401 n2 = (union node *)stalloc(sizeof (struct narg));
402 n2->type = NARG;
403 n2->narg.text = argvars;
404 n2->narg.backquote = NULL;
405 n2->narg.next = NULL;
406 n1->nfor.args = n2;
408 * Newline or semicolon here is optional (but note
409 * that the original Bourne shell only allowed NL).
411 if (lasttoken != TNL && lasttoken != TSEMI)
412 tokpushback++;
414 checkkwd = 2;
415 if ((t = readtoken()) == TDO)
416 t = TDONE;
417 else if (t == TBEGIN)
418 t = TEND;
419 else
420 synexpect(-1);
421 n1->nfor.body = list(0);
422 if (readtoken() != t)
423 synexpect(t);
424 checkkwd = 1;
425 break;
426 case TCASE:
427 n1 = (union node *)stalloc(sizeof (struct ncase));
428 n1->type = NCASE;
429 if (readtoken() != TWORD)
430 synexpect(TWORD);
431 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
432 n2->type = NARG;
433 n2->narg.text = wordtext;
434 n2->narg.backquote = backquotelist;
435 n2->narg.next = NULL;
436 while (readtoken() == TNL);
437 if (lasttoken != TWORD || ! equal(wordtext, "in"))
438 synerror("expecting \"in\"");
439 cpp = &n1->ncase.cases;
440 noaliases = 1; /* turn off alias expansion */
441 checkkwd = 2, readtoken();
442 while (lasttoken != TESAC) {
443 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
444 cp->type = NCLIST;
445 app = &cp->nclist.pattern;
446 if (lasttoken == TLP)
447 readtoken();
448 for (;;) {
449 *app = ap = (union node *)stalloc(sizeof (struct narg));
450 ap->type = NARG;
451 ap->narg.text = wordtext;
452 ap->narg.backquote = backquotelist;
453 if (checkkwd = 2, readtoken() != TPIPE)
454 break;
455 app = &ap->narg.next;
456 readtoken();
458 ap->narg.next = NULL;
459 if (lasttoken != TRP)
460 noaliases = 0, synexpect(TRP);
461 cp->nclist.body = list(0);
463 checkkwd = 2;
464 if ((t = readtoken()) != TESAC) {
465 if (t != TENDCASE)
466 noaliases = 0, synexpect(TENDCASE);
467 else
468 checkkwd = 2, readtoken();
470 cpp = &cp->nclist.next;
472 noaliases = 0; /* reset alias expansion */
473 *cpp = NULL;
474 checkkwd = 1;
475 break;
476 case TLP:
477 n1 = (union node *)stalloc(sizeof (struct nredir));
478 n1->type = NSUBSHELL;
479 n1->nredir.n = list(0);
480 n1->nredir.redirect = NULL;
481 if (readtoken() != TRP)
482 synexpect(TRP);
483 checkkwd = 1;
484 break;
485 case TBEGIN:
486 n1 = list(0);
487 if (readtoken() != TEND)
488 synexpect(TEND);
489 checkkwd = 1;
490 break;
491 /* Handle an empty command like other simple commands. */
492 case TSEMI:
493 case TAND:
494 case TOR:
496 * An empty command before a ; doesn't make much sense, and
497 * should certainly be disallowed in the case of `if ;'.
499 if (!redir)
500 synexpect(-1);
501 case TNL:
502 case TEOF:
503 case TWORD:
504 case TRP:
505 tokpushback++;
506 return simplecmd(rpp, redir);
507 default:
508 synexpect(-1);
511 /* Now check for redirection which may follow command */
512 while (readtoken() == TREDIR) {
513 *rpp = n2 = redirnode;
514 rpp = &n2->nfile.next;
515 parsefname();
517 tokpushback++;
518 *rpp = NULL;
519 if (redir) {
520 if (n1->type != NSUBSHELL) {
521 n2 = (union node *)stalloc(sizeof (struct nredir));
522 n2->type = NREDIR;
523 n2->nredir.n = n1;
524 n1 = n2;
526 n1->nredir.redirect = redir;
528 return n1;
532 STATIC union node *
533 simplecmd(union node **rpp, union node *redir)
535 union node *args, **app;
536 union node **orig_rpp = rpp;
537 union node *n = NULL;
539 /* If we don't have any redirections already, then we must reset */
540 /* rpp to be the address of the local redir variable. */
541 if (redir == 0)
542 rpp = &redir;
544 args = NULL;
545 app = &args;
547 * We save the incoming value, because we need this for shell
548 * functions. There can not be a redirect or an argument between
549 * the function name and the open parenthesis.
551 orig_rpp = rpp;
553 for (;;) {
554 if (readtoken() == TWORD) {
555 n = (union node *)stalloc(sizeof (struct narg));
556 n->type = NARG;
557 n->narg.text = wordtext;
558 n->narg.backquote = backquotelist;
559 *app = n;
560 app = &n->narg.next;
561 } else if (lasttoken == TREDIR) {
562 *rpp = n = redirnode;
563 rpp = &n->nfile.next;
564 parsefname(); /* read name of redirection file */
565 } else if (lasttoken == TLP && app == &args->narg.next
566 && rpp == orig_rpp) {
567 /* We have a function */
568 if (readtoken() != TRP)
569 synexpect(TRP);
570 funclinno = plinno;
571 #ifdef notdef
572 if (! goodname(n->narg.text))
573 synerror("Bad function name");
574 #endif
575 n->type = NDEFUN;
576 n->narg.next = command();
577 funclinno = 0;
578 return n;
579 } else {
580 tokpushback++;
581 break;
584 *app = NULL;
585 *rpp = NULL;
586 n = (union node *)stalloc(sizeof (struct ncmd));
587 n->type = NCMD;
588 n->ncmd.backgnd = 0;
589 n->ncmd.args = args;
590 n->ncmd.redirect = redir;
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 > 1) {
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 = 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 case '!':
846 if (checkkwd == 3)
847 RETURN(TNOT);
848 /* else FALLTHROUGH */
849 default:
850 goto breakloop;
853 breakloop:
854 return readtoken1(c, BASESYNTAX, NULL, 0);
855 #undef RETURN
861 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
862 * is not NULL, read a here document. In the latter case, eofmark is the
863 * word which marks the end of the document and striptabs is true if
864 * leading tabs should be stripped from the document. The argument firstc
865 * is the first character of the input token or document.
867 * Because C does not have internal subroutines, I have simulated them
868 * using goto's to implement the subroutine linkage. The following macros
869 * will run code that appears at the end of readtoken1.
872 #define CHECKEND() {goto checkend; checkend_return:;}
873 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
874 #define PARSESUB() {goto parsesub; parsesub_return:;}
875 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
876 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
877 #define PARSEARITH() {goto parsearith; parsearith_return:;}
879 STATIC int
880 readtoken1(int firstc, char const *syn, char *eofmark, int striptabs)
882 int c = firstc;
883 char const * volatile syntax = syn;
884 char * volatile out;
885 int len;
886 char line[EOFMARKLEN + 1];
887 struct nodelist *bqlist;
888 volatile int quotef;
889 volatile int dblquote;
890 volatile int varnest; /* levels of variables expansion */
891 volatile int arinest; /* levels of arithmetic expansion */
892 volatile int parenlevel; /* levels of parens in arithmetic */
893 volatile int oldstyle;
894 char const * volatile prevsyntax = NULL; /* syntax before arithmetic */
895 int synentry;
897 startlinno = plinno;
898 dblquote = 0;
899 if (syntax == DQSYNTAX)
900 dblquote = 1;
901 quotef = 0;
902 bqlist = NULL;
903 varnest = 0;
904 arinest = 0;
905 parenlevel = 0;
907 STARTSTACKSTR(out);
908 loop: { /* for each line, until end of word */
909 CHECKEND(); /* set c to PEOF if at end of here document */
910 for (;;) { /* until end of line or end of word */
911 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
913 synentry = syntax[c];
915 switch(synentry) {
916 case CNL: /* '\n' */
917 if (syntax == BASESYNTAX)
918 goto endword; /* exit outer loop */
919 USTPUTC(c, out);
920 plinno++;
921 if (doprompt)
922 setprompt(2);
923 else
924 setprompt(0);
925 c = pgetc();
926 goto loop; /* continue outer loop */
927 case CWORD:
928 USTPUTC(c, out);
929 break;
930 case CCTL:
931 if (eofmark == NULL || dblquote)
932 USTPUTC(CTLESC, out);
933 USTPUTC(c, out);
934 break;
935 case CBACK: /* backslash */
936 c = pgetc();
937 if (c == PEOF) {
938 USTPUTC('\\', out);
939 pungetc();
940 } else if (c == '\n') {
941 plinno++;
942 if (doprompt)
943 setprompt(2);
944 else
945 setprompt(0);
946 } else {
947 if (dblquote && c != '\\' &&
948 c != '`' && c != '$' &&
949 (c != '"' || eofmark != NULL))
950 USTPUTC('\\', out);
951 if (SQSYNTAX[c] == CCTL)
952 USTPUTC(CTLESC, out);
953 else if (eofmark == NULL)
954 USTPUTC(CTLQUOTEMARK, out);
955 USTPUTC(c, out);
956 quotef++;
958 break;
959 case CSQUOTE:
960 if (eofmark == NULL)
961 USTPUTC(CTLQUOTEMARK, out);
962 syntax = SQSYNTAX;
963 break;
964 case CDQUOTE:
965 if (eofmark == NULL)
966 USTPUTC(CTLQUOTEMARK, out);
967 syntax = DQSYNTAX;
968 dblquote = 1;
969 break;
970 case CENDQUOTE:
971 if (eofmark != NULL && arinest == 0 &&
972 varnest == 0) {
973 USTPUTC(c, out);
974 } else {
975 if (arinest) {
976 syntax = ARISYNTAX;
977 dblquote = 0;
978 } else if (eofmark == NULL) {
979 syntax = BASESYNTAX;
980 dblquote = 0;
982 quotef++;
984 break;
985 case CVAR: /* '$' */
986 PARSESUB(); /* parse substitution */
987 break;
988 case CENDVAR: /* '}' */
989 if (varnest > 0) {
990 varnest--;
991 USTPUTC(CTLENDVAR, out);
992 } else {
993 USTPUTC(c, out);
995 break;
996 case CLP: /* '(' in arithmetic */
997 parenlevel++;
998 USTPUTC(c, out);
999 break;
1000 case CRP: /* ')' in arithmetic */
1001 if (parenlevel > 0) {
1002 USTPUTC(c, out);
1003 --parenlevel;
1004 } else {
1005 if (pgetc() == ')') {
1006 if (--arinest == 0) {
1007 USTPUTC(CTLENDARI, out);
1008 syntax = prevsyntax;
1009 if (syntax == DQSYNTAX)
1010 dblquote = 1;
1011 else
1012 dblquote = 0;
1013 } else
1014 USTPUTC(')', out);
1015 } else {
1017 * unbalanced parens
1018 * (don't 2nd guess - no error)
1020 pungetc();
1021 USTPUTC(')', out);
1024 break;
1025 case CBQUOTE: /* '`' */
1026 PARSEBACKQOLD();
1027 break;
1028 case CEOF:
1029 goto endword; /* exit outer loop */
1030 default:
1031 if (varnest == 0)
1032 goto endword; /* exit outer loop */
1033 USTPUTC(c, out);
1035 c = pgetc_macro();
1038 endword:
1039 if (syntax == ARISYNTAX)
1040 synerror("Missing '))'");
1041 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
1042 synerror("Unterminated quoted string");
1043 if (varnest != 0) {
1044 startlinno = plinno;
1045 synerror("Missing '}'");
1047 USTPUTC('\0', out);
1048 len = out - stackblock();
1049 out = stackblock();
1050 if (eofmark == NULL) {
1051 if ((c == '>' || c == '<')
1052 && quotef == 0
1053 && len <= 2
1054 && (*out == '\0' || is_digit(*out))) {
1055 PARSEREDIR();
1056 return lasttoken = TREDIR;
1057 } else {
1058 pungetc();
1061 quoteflag = quotef;
1062 backquotelist = bqlist;
1063 grabstackblock(len);
1064 wordtext = out;
1065 return lasttoken = TWORD;
1066 /* end of readtoken routine */
1071 * Check to see whether we are at the end of the here document. When this
1072 * is called, c is set to the first character of the next input line. If
1073 * we are at the end of the here document, this routine sets the c to PEOF.
1076 checkend: {
1077 if (eofmark) {
1078 if (striptabs) {
1079 while (c == '\t')
1080 c = pgetc();
1082 if (c == *eofmark) {
1083 if (pfgets(line, sizeof line) != NULL) {
1084 char *p, *q;
1086 p = line;
1087 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1088 if (*p == '\n' && *q == '\0') {
1089 c = PEOF;
1090 plinno++;
1091 needprompt = doprompt;
1092 } else {
1093 pushstring(line, strlen(line), NULL);
1098 goto checkend_return;
1103 * Parse a redirection operator. The variable "out" points to a string
1104 * specifying the fd to be redirected. The variable "c" contains the
1105 * first character of the redirection operator.
1108 parseredir: {
1109 char fd = *out;
1110 union node *np;
1112 np = (union node *)stalloc(sizeof (struct nfile));
1113 if (c == '>') {
1114 np->nfile.fd = 1;
1115 c = pgetc();
1116 if (c == '>')
1117 np->type = NAPPEND;
1118 else if (c == '&')
1119 np->type = NTOFD;
1120 else if (c == '|')
1121 np->type = NCLOBBER;
1122 else {
1123 np->type = NTO;
1124 pungetc();
1126 } else { /* c == '<' */
1127 np->nfile.fd = 0;
1128 c = pgetc();
1129 if (c == '<') {
1130 if (sizeof (struct nfile) != sizeof (struct nhere)) {
1131 np = (union node *)stalloc(sizeof (struct nhere));
1132 np->nfile.fd = 0;
1134 np->type = NHERE;
1135 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1136 heredoc->here = np;
1137 if ((c = pgetc()) == '-') {
1138 heredoc->striptabs = 1;
1139 } else {
1140 heredoc->striptabs = 0;
1141 pungetc();
1143 } else if (c == '&')
1144 np->type = NFROMFD;
1145 else if (c == '>')
1146 np->type = NFROMTO;
1147 else {
1148 np->type = NFROM;
1149 pungetc();
1152 if (fd != '\0')
1153 np->nfile.fd = digit_val(fd);
1154 redirnode = np;
1155 goto parseredir_return;
1160 * Parse a substitution. At this point, we have read the dollar sign
1161 * and nothing else.
1164 parsesub: {
1165 char buf[10];
1166 int subtype;
1167 int typeloc;
1168 int flags;
1169 char *p;
1170 static const char types[] = "}-+?=";
1171 int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
1172 int i;
1173 int linno;
1174 int length;
1176 c = pgetc();
1177 if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) &&
1178 !is_special(c)) {
1179 USTPUTC('$', out);
1180 pungetc();
1181 } else if (c == '(') { /* $(command) or $((arith)) */
1182 if (pgetc() == '(') {
1183 PARSEARITH();
1184 } else {
1185 pungetc();
1186 PARSEBACKQNEW();
1188 } else {
1189 USTPUTC(CTLVAR, out);
1190 typeloc = out - stackblock();
1191 USTPUTC(VSNORMAL, out);
1192 subtype = VSNORMAL;
1193 flags = 0;
1194 if (c == '{') {
1195 bracketed_name = 1;
1196 c = pgetc();
1197 if (c == '#') {
1198 if ((c = pgetc()) == '}')
1199 c = '#';
1200 else
1201 subtype = VSLENGTH;
1203 else
1204 subtype = 0;
1206 if (!is_eof(c) && is_name(c)) {
1207 length = 0;
1208 do {
1209 STPUTC(c, out);
1210 c = pgetc();
1211 length++;
1212 } while (!is_eof(c) && is_in_name(c));
1213 if (length == 6 &&
1214 strncmp(out - length, "LINENO", length) == 0) {
1215 /* Replace the variable name with the
1216 * current line number. */
1217 linno = plinno;
1218 if (funclinno != 0)
1219 linno -= funclinno - 1;
1220 snprintf(buf, sizeof(buf), "%d", linno);
1221 STADJUST(-6, out);
1222 for (i = 0; buf[i] != '\0'; i++)
1223 STPUTC(buf[i], out);
1224 flags |= VSLINENO;
1226 } else if (is_digit(c)) {
1227 if (bracketed_name) {
1228 do {
1229 STPUTC(c, out);
1230 c = pgetc();
1231 } while (is_digit(c));
1232 } else {
1233 STPUTC(c, out);
1234 c = pgetc();
1236 } else {
1237 if (! is_special(c)) {
1238 subtype = VSERROR;
1239 if (c == '}')
1240 pungetc();
1241 else
1242 USTPUTC(c, out);
1243 } else {
1244 USTPUTC(c, out);
1245 c = pgetc();
1248 if (subtype == 0) {
1249 switch (c) {
1250 case ':':
1251 flags |= VSNUL;
1252 c = pgetc();
1253 /*FALLTHROUGH*/
1254 default:
1255 p = strchr(types, c);
1256 if (p == NULL) {
1257 if (flags == VSNUL)
1258 STPUTC(':', out);
1259 STPUTC(c, out);
1260 subtype = VSERROR;
1261 } else
1262 subtype = p - types + VSNORMAL;
1263 break;
1264 case '%':
1265 case '#':
1267 int cc = c;
1268 subtype = c == '#' ? VSTRIMLEFT :
1269 VSTRIMRIGHT;
1270 c = pgetc();
1271 if (c == cc)
1272 subtype++;
1273 else
1274 pungetc();
1275 break;
1278 } else if (subtype != VSERROR) {
1279 pungetc();
1281 STPUTC('=', out);
1282 if (subtype != VSLENGTH && (dblquote || arinest))
1283 flags |= VSQUOTE;
1284 *(stackblock() + typeloc) = subtype | flags;
1285 if (subtype != VSNORMAL)
1286 varnest++;
1288 goto parsesub_return;
1293 * Called to parse command substitutions. Newstyle is set if the command
1294 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1295 * list of commands (passed by reference), and savelen is the number of
1296 * characters on the top of the stack which must be preserved.
1299 parsebackq: {
1300 struct nodelist **nlpp;
1301 int savepbq;
1302 union node *n;
1303 char *volatile str;
1304 struct jmploc jmploc;
1305 struct jmploc *volatile savehandler;
1306 int savelen;
1307 volatile int saveprompt;
1309 savepbq = parsebackquote;
1310 if (setjmp(jmploc.loc)) {
1311 if (str)
1312 ckfree(str);
1313 parsebackquote = 0;
1314 handler = savehandler;
1315 longjmp(handler->loc, 1);
1317 INTOFF;
1318 str = NULL;
1319 savelen = out - stackblock();
1320 if (savelen > 0) {
1321 str = ckmalloc(savelen);
1322 memcpy(str, stackblock(), savelen);
1324 savehandler = handler;
1325 handler = &jmploc;
1326 INTON;
1327 if (oldstyle) {
1328 /* We must read until the closing backquote, giving special
1329 treatment to some slashes, and then push the string and
1330 reread it as input, interpreting it normally. */
1331 char *pout;
1332 int pc;
1333 int psavelen;
1334 char *pstr;
1337 STARTSTACKSTR(pout);
1338 for (;;) {
1339 if (needprompt) {
1340 setprompt(2);
1341 needprompt = 0;
1343 switch (pc = pgetc()) {
1344 case '`':
1345 goto done;
1347 case '\\':
1348 if ((pc = pgetc()) == '\n') {
1349 plinno++;
1350 if (doprompt)
1351 setprompt(2);
1352 else
1353 setprompt(0);
1355 * If eating a newline, avoid putting
1356 * the newline into the new character
1357 * stream (via the STPUTC after the
1358 * switch).
1360 continue;
1362 if (pc != '\\' && pc != '`' && pc != '$'
1363 && (!dblquote || pc != '"'))
1364 STPUTC('\\', pout);
1365 break;
1367 case '\n':
1368 plinno++;
1369 needprompt = doprompt;
1370 break;
1372 case PEOF:
1373 startlinno = plinno;
1374 synerror("EOF in backquote substitution");
1375 break;
1377 default:
1378 break;
1380 STPUTC(pc, pout);
1382 done:
1383 STPUTC('\0', pout);
1384 psavelen = pout - stackblock();
1385 if (psavelen > 0) {
1386 pstr = ckmalloc(psavelen);
1387 memcpy(pstr, stackblock(), psavelen);
1388 setinputstring(pstr, 1);
1391 nlpp = &bqlist;
1392 while (*nlpp)
1393 nlpp = &(*nlpp)->next;
1394 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1395 (*nlpp)->next = NULL;
1396 parsebackquote = oldstyle;
1398 if (oldstyle) {
1399 saveprompt = doprompt;
1400 doprompt = 0;
1403 n = list(0);
1405 if (oldstyle)
1406 doprompt = saveprompt;
1407 else {
1408 if (readtoken() != TRP)
1409 synexpect(TRP);
1412 (*nlpp)->n = n;
1413 if (oldstyle) {
1415 * Start reading from old file again, ignoring any pushed back
1416 * tokens left from the backquote parsing
1418 popfile();
1419 tokpushback = 0;
1421 while (stackblocksize() <= savelen)
1422 growstackblock();
1423 STARTSTACKSTR(out);
1424 if (str) {
1425 memcpy(out, str, savelen);
1426 STADJUST(savelen, out);
1427 INTOFF;
1428 ckfree(str);
1429 str = NULL;
1430 INTON;
1432 parsebackquote = savepbq;
1433 handler = savehandler;
1434 if (arinest || dblquote)
1435 USTPUTC(CTLBACKQ | CTLQUOTE, out);
1436 else
1437 USTPUTC(CTLBACKQ, out);
1438 if (oldstyle)
1439 goto parsebackq_oldreturn;
1440 else
1441 goto parsebackq_newreturn;
1445 * Parse an arithmetic expansion (indicate start of one and set state)
1447 parsearith: {
1449 if (++arinest == 1) {
1450 prevsyntax = syntax;
1451 syntax = ARISYNTAX;
1452 USTPUTC(CTLARI, out);
1453 if (dblquote)
1454 USTPUTC('"',out);
1455 else
1456 USTPUTC(' ',out);
1457 } else {
1459 * we collapse embedded arithmetic expansion to
1460 * parenthesis, which should be equivalent
1462 USTPUTC('(', out);
1464 goto parsearith_return;
1467 } /* end of readtoken */
1471 #ifdef mkinit
1472 RESET {
1473 tokpushback = 0;
1474 checkkwd = 0;
1476 #endif
1479 * Returns true if the text contains nothing to expand (no dollar signs
1480 * or backquotes).
1483 STATIC int
1484 noexpand(char *text)
1486 char *p;
1487 char c;
1489 p = text;
1490 while ((c = *p++) != '\0') {
1491 if ( c == CTLQUOTEMARK)
1492 continue;
1493 if (c == CTLESC)
1494 p++;
1495 else if (BASESYNTAX[(int)c] == CCTL)
1496 return 0;
1498 return 1;
1503 * Return true if the argument is a legal variable name (a letter or
1504 * underscore followed by zero or more letters, underscores, and digits).
1508 goodname(char *name)
1510 char *p;
1512 p = name;
1513 if (! is_name(*p))
1514 return 0;
1515 while (*++p) {
1516 if (! is_in_name(*p))
1517 return 0;
1519 return 1;
1524 * Called when an unexpected token is read during the parse. The argument
1525 * is the token that is expected, or -1 if more than one type of token can
1526 * occur at this point.
1529 STATIC void
1530 synexpect(int token)
1532 char msg[64];
1534 if (token >= 0) {
1535 fmtstr(msg, 64, "%s unexpected (expecting %s)",
1536 tokname[lasttoken], tokname[token]);
1537 } else {
1538 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1540 synerror(msg);
1544 STATIC void
1545 synerror(const char *msg)
1547 if (commandname)
1548 outfmt(&errout, "%s: %d: ", commandname, startlinno);
1549 outfmt(&errout, "Syntax error: %s\n", msg);
1550 error(NULL);
1553 STATIC void
1554 setprompt(int which)
1556 whichprompt = which;
1558 #ifndef NO_HISTORY
1559 if (!el)
1560 #endif
1561 out2str(getprompt(NULL));
1565 * called by editline -- any expansions to the prompt
1566 * should be added here.
1568 const char *
1569 getprompt(void *unused __unused)
1571 static char ps[PROMPTLEN];
1572 const char *fmt;
1573 int i, j, trim;
1576 * Select prompt format.
1578 switch (whichprompt) {
1579 case 0:
1580 fmt = "";
1581 break;
1582 case 1:
1583 fmt = ps1val();
1584 break;
1585 case 2:
1586 fmt = ps2val();
1587 break;
1588 default:
1589 return "<internal prompt error>";
1593 * Format prompt string.
1595 for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++)
1596 if (*fmt == '\\')
1597 switch (*++fmt) {
1600 * Hostname.
1602 * \h specifies just the local hostname,
1603 * \H specifies fully-qualified hostname.
1605 case 'h':
1606 case 'H':
1607 ps[i] = '\0';
1608 gethostname(&ps[i], PROMPTLEN - i);
1609 /* Skip to end of hostname. */
1610 trim = (*fmt == 'h') ? '.' : '\0';
1611 while ((ps[i+1] != '\0') && (ps[i+1] != trim))
1612 i++;
1613 break;
1616 * Working directory.
1618 * \W specifies just the final component,
1619 * \w specifies the entire path.
1621 case 'W':
1622 case 'w':
1623 ps[i] = '\0';
1624 getcwd(&ps[i], PROMPTLEN - i);
1625 if (*fmt == 'W') {
1626 /* Final path component only. */
1627 trim = 1;
1628 for (j = i; ps[j] != '\0'; j++)
1629 if (ps[j] == '/')
1630 trim = j + 1;
1631 memmove(&ps[i], &ps[trim],
1632 j - trim + 1);
1634 /* Skip to end of path. */
1635 while (ps[i + 1] != '\0')
1636 i++;
1637 break;
1640 * Superuser status.
1642 * '$' for normal users, '#' for root.
1644 case '$':
1645 ps[i] = (geteuid() != 0) ? '$' : '#';
1646 break;
1649 * A literal \.
1651 case '\\':
1652 ps[i] = '\\';
1653 break;
1656 * Emit unrecognized formats verbatim.
1658 default:
1659 ps[i++] = '\\';
1660 ps[i] = *fmt;
1661 break;
1663 else
1664 ps[i] = *fmt;
1665 ps[i] = '\0';
1666 return (ps);