Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (hide 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 niro 532 /*-
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     }