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