Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/dash/parser.c

Parent Directory Parent Directory | Revision Log Revision Log


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