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