Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / bin / sh / parser.c
CommitLineData
984263bc
MD
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.
1de703da
MD
35 *
36 * @(#)parser.c 8.7 (Berkeley) 5/16/95
37 * $FreeBSD: src/bin/sh/parser.c,v 1.29.2.9 2002/10/18 11:24:04 tjr Exp $
38 * $DragonFly: src/bin/sh/parser.c,v 1.2 2003/06/17 04:22:50 dillon Exp $
984263bc
MD
39 */
40
984263bc
MD
41#include <stdlib.h>
42
43#include "shell.h"
44#include "parser.h"
45#include "nodes.h"
46#include "expand.h" /* defines rmescapes() */
47#include "redir.h" /* defines copyfd() */
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
69/* values returned by readtoken */
70#include "token.h"
71
72
73
74struct heredoc {
75 struct heredoc *next; /* next here document in list */
76 union node *here; /* redirection node */
77 char *eofmark; /* string indicating end of input */
78 int striptabs; /* if set, strip leading tabs */
79};
80
81
82
83struct heredoc *heredoclist; /* list of here documents to read */
84int parsebackquote; /* nonzero if we are inside backquotes */
85int doprompt; /* if set, prompt the user */
86int needprompt; /* true if interactive and at start of line */
87int lasttoken; /* last token read */
88MKINIT int tokpushback; /* last token pushed back */
89char *wordtext; /* text of last word returned by readtoken */
90MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
91struct nodelist *backquotelist;
92union node *redirnode;
93struct heredoc *heredoc;
94int quoteflag; /* set if (part of) last token was quoted */
95int startlinno; /* line # where last token started */
96
97/* XXX When 'noaliases' is set to one, no alias expansion takes place. */
98static int noaliases = 0;
99
100#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
101#ifdef GDB_HACK
102static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
103static const char types[] = "}-+?=";
104#endif
105
106
107STATIC union node *list(int);
108STATIC union node *andor(void);
109STATIC union node *pipeline(void);
110STATIC union node *command(void);
111STATIC union node *simplecmd(union node **, union node *);
112STATIC union node *makename(void);
113STATIC void parsefname(void);
114STATIC void parseheredoc(void);
115STATIC int peektoken(void);
116STATIC int readtoken(void);
117STATIC int xxreadtoken(void);
118STATIC int readtoken1(int, char const *, char *, int);
119STATIC int noexpand(char *);
120STATIC void synexpect(int);
121STATIC void synerror(char *);
122STATIC void setprompt(int);
123
124
125/*
126 * Read and parse a command. Returns NEOF on end of file. (NULL is a
127 * valid parse tree indicating a blank line.)
128 */
129
130union node *
131parsecmd(int interact)
132{
133 int t;
134
135 tokpushback = 0;
136 doprompt = interact;
137 if (doprompt)
138 setprompt(1);
139 else
140 setprompt(0);
141 needprompt = 0;
142 t = readtoken();
143 if (t == TEOF)
144 return NEOF;
145 if (t == TNL)
146 return NULL;
147 tokpushback++;
148 return list(1);
149}
150
151
152STATIC union node *
153list(int nlflag)
154{
155 union node *n1, *n2, *n3;
156 int tok;
157
158 checkkwd = 2;
159 if (nlflag == 0 && tokendlist[peektoken()])
160 return NULL;
161 n1 = NULL;
162 for (;;) {
163 n2 = andor();
164 tok = readtoken();
165 if (tok == TBACKGND) {
166 if (n2->type == NCMD || n2->type == NPIPE) {
167 n2->ncmd.backgnd = 1;
168 } else if (n2->type == NREDIR) {
169 n2->type = NBACKGND;
170 } else {
171 n3 = (union node *)stalloc(sizeof (struct nredir));
172 n3->type = NBACKGND;
173 n3->nredir.n = n2;
174 n3->nredir.redirect = NULL;
175 n2 = n3;
176 }
177 }
178 if (n1 == NULL) {
179 n1 = n2;
180 }
181 else {
182 n3 = (union node *)stalloc(sizeof (struct nbinary));
183 n3->type = NSEMI;
184 n3->nbinary.ch1 = n1;
185 n3->nbinary.ch2 = n2;
186 n1 = n3;
187 }
188 switch (tok) {
189 case TBACKGND:
190 case TSEMI:
191 tok = readtoken();
192 /* fall through */
193 case TNL:
194 if (tok == TNL) {
195 parseheredoc();
196 if (nlflag)
197 return n1;
198 } else {
199 tokpushback++;
200 }
201 checkkwd = 2;
202 if (tokendlist[peektoken()])
203 return n1;
204 break;
205 case TEOF:
206 if (heredoclist)
207 parseheredoc();
208 else
209 pungetc(); /* push back EOF on input */
210 return n1;
211 default:
212 if (nlflag)
213 synexpect(-1);
214 tokpushback++;
215 return n1;
216 }
217 }
218}
219
220
221
222STATIC union node *
223andor(void)
224{
225 union node *n1, *n2, *n3;
226 int t;
227
228 n1 = pipeline();
229 for (;;) {
230 if ((t = readtoken()) == TAND) {
231 t = NAND;
232 } else if (t == TOR) {
233 t = NOR;
234 } else {
235 tokpushback++;
236 return n1;
237 }
238 n2 = pipeline();
239 n3 = (union node *)stalloc(sizeof (struct nbinary));
240 n3->type = t;
241 n3->nbinary.ch1 = n1;
242 n3->nbinary.ch2 = n2;
243 n1 = n3;
244 }
245}
246
247
248
249STATIC union node *
250pipeline(void)
251{
252 union node *n1, *n2, *pipenode;
253 struct nodelist *lp, *prev;
254 int negate;
255
256 negate = 0;
257 TRACE(("pipeline: entered\n"));
258 while (readtoken() == TNOT)
259 negate = !negate;
260 tokpushback++;
261 n1 = command();
262 if (readtoken() == TPIPE) {
263 pipenode = (union node *)stalloc(sizeof (struct npipe));
264 pipenode->type = NPIPE;
265 pipenode->npipe.backgnd = 0;
266 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
267 pipenode->npipe.cmdlist = lp;
268 lp->n = n1;
269 do {
270 prev = lp;
271 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
272 lp->n = command();
273 prev->next = lp;
274 } while (readtoken() == TPIPE);
275 lp->next = NULL;
276 n1 = pipenode;
277 }
278 tokpushback++;
279 if (negate) {
280 n2 = (union node *)stalloc(sizeof (struct nnot));
281 n2->type = NNOT;
282 n2->nnot.com = n1;
283 return n2;
284 } else
285 return n1;
286}
287
288
289
290STATIC union node *
291command(void)
292{
293 union node *n1, *n2;
294 union node *ap, **app;
295 union node *cp, **cpp;
296 union node *redir, **rpp;
297 int t, negate = 0;
298
299 checkkwd = 2;
300 redir = NULL;
301 n1 = NULL;
302 rpp = &redir;
303
304 /* Check for redirection which may precede command */
305 while (readtoken() == TREDIR) {
306 *rpp = n2 = redirnode;
307 rpp = &n2->nfile.next;
308 parsefname();
309 }
310 tokpushback++;
311
312 while (readtoken() == TNOT) {
313 TRACE(("command: TNOT recognized\n"));
314 negate = !negate;
315 }
316 tokpushback++;
317
318 switch (readtoken()) {
319 case TIF:
320 n1 = (union node *)stalloc(sizeof (struct nif));
321 n1->type = NIF;
322 n1->nif.test = list(0);
323 if (readtoken() != TTHEN)
324 synexpect(TTHEN);
325 n1->nif.ifpart = list(0);
326 n2 = n1;
327 while (readtoken() == TELIF) {
328 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
329 n2 = n2->nif.elsepart;
330 n2->type = NIF;
331 n2->nif.test = list(0);
332 if (readtoken() != TTHEN)
333 synexpect(TTHEN);
334 n2->nif.ifpart = list(0);
335 }
336 if (lasttoken == TELSE)
337 n2->nif.elsepart = list(0);
338 else {
339 n2->nif.elsepart = NULL;
340 tokpushback++;
341 }
342 if (readtoken() != TFI)
343 synexpect(TFI);
344 checkkwd = 1;
345 break;
346 case TWHILE:
347 case TUNTIL: {
348 int got;
349 n1 = (union node *)stalloc(sizeof (struct nbinary));
350 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
351 n1->nbinary.ch1 = list(0);
352 if ((got=readtoken()) != TDO) {
353TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
354 synexpect(TDO);
355 }
356 n1->nbinary.ch2 = list(0);
357 if (readtoken() != TDONE)
358 synexpect(TDONE);
359 checkkwd = 1;
360 break;
361 }
362 case TFOR:
363 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
364 synerror("Bad for loop variable");
365 n1 = (union node *)stalloc(sizeof (struct nfor));
366 n1->type = NFOR;
367 n1->nfor.var = wordtext;
368 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
369 app = &ap;
370 while (readtoken() == TWORD) {
371 n2 = (union node *)stalloc(sizeof (struct narg));
372 n2->type = NARG;
373 n2->narg.text = wordtext;
374 n2->narg.backquote = backquotelist;
375 *app = n2;
376 app = &n2->narg.next;
377 }
378 *app = NULL;
379 n1->nfor.args = ap;
380 if (lasttoken != TNL && lasttoken != TSEMI)
381 synexpect(-1);
382 } else {
383#ifndef GDB_HACK
384 static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
385 '@', '=', '\0'};
386#endif
387 n2 = (union node *)stalloc(sizeof (struct narg));
388 n2->type = NARG;
389 n2->narg.text = (char *)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#ifdef notdef
574 if (! goodname(n->narg.text))
575 synerror("Bad function name");
576#endif
577 n->type = NDEFUN;
578 n->narg.next = command();
579 goto checkneg;
580 } else {
581 tokpushback++;
582 break;
583 }
584 }
585 *app = NULL;
586 *rpp = NULL;
587 n = (union node *)stalloc(sizeof (struct ncmd));
588 n->type = NCMD;
589 n->ncmd.backgnd = 0;
590 n->ncmd.args = args;
591 n->ncmd.redirect = redir;
592
593checkneg:
594 if (negate) {
595 n2 = (union node *)stalloc(sizeof (struct nnot));
596 n2->type = NNOT;
597 n2->nnot.com = n;
598 return n2;
599 }
600 else
601 return n;
602}
603
604STATIC union node *
605makename(void)
606{
607 union node *n;
608
609 n = (union node *)stalloc(sizeof (struct narg));
610 n->type = NARG;
611 n->narg.next = NULL;
612 n->narg.text = wordtext;
613 n->narg.backquote = backquotelist;
614 return n;
615}
616
617void fixredir(union node *n, const char *text, int err)
618{
619 TRACE(("Fix redir %s %d\n", text, err));
620 if (!err)
621 n->ndup.vname = NULL;
622
623 if (is_digit(text[0]) && text[1] == '\0')
624 n->ndup.dupfd = digit_val(text[0]);
625 else if (text[0] == '-' && text[1] == '\0')
626 n->ndup.dupfd = -1;
627 else {
628
629 if (err)
630 synerror("Bad fd number");
631 else
632 n->ndup.vname = makename();
633 }
634}
635
636
637STATIC void
638parsefname(void)
639{
640 union node *n = redirnode;
641
642 if (readtoken() != TWORD)
643 synexpect(-1);
644 if (n->type == NHERE) {
645 struct heredoc *here = heredoc;
646 struct heredoc *p;
647 int i;
648
649 if (quoteflag == 0)
650 n->type = NXHERE;
651 TRACE(("Here document %d\n", n->type));
652 if (here->striptabs) {
653 while (*wordtext == '\t')
654 wordtext++;
655 }
656 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
657 synerror("Illegal eof marker for << redirection");
658 rmescapes(wordtext);
659 here->eofmark = wordtext;
660 here->next = NULL;
661 if (heredoclist == NULL)
662 heredoclist = here;
663 else {
664 for (p = heredoclist ; p->next ; p = p->next);
665 p->next = here;
666 }
667 } else if (n->type == NTOFD || n->type == NFROMFD) {
668 fixredir(n, wordtext, 0);
669 } else {
670 n->nfile.fname = makename();
671 }
672}
673
674
675/*
676 * Input any here documents.
677 */
678
679STATIC void
680parseheredoc(void)
681{
682 struct heredoc *here;
683 union node *n;
684
685 while (heredoclist) {
686 here = heredoclist;
687 heredoclist = here->next;
688 if (needprompt) {
689 setprompt(2);
690 needprompt = 0;
691 }
692 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
693 here->eofmark, here->striptabs);
694 n = (union node *)stalloc(sizeof (struct narg));
695 n->narg.type = NARG;
696 n->narg.next = NULL;
697 n->narg.text = wordtext;
698 n->narg.backquote = backquotelist;
699 here->here->nhere.doc = n;
700 }
701}
702
703STATIC int
704peektoken(void)
705{
706 int t;
707
708 t = readtoken();
709 tokpushback++;
710 return (t);
711}
712
713STATIC int
714readtoken(void)
715{
716 int t;
717 int savecheckkwd = checkkwd;
718 struct alias *ap;
719#ifdef DEBUG
720 int alreadyseen = tokpushback;
721#endif
722
723 top:
724 t = xxreadtoken();
725
726 if (checkkwd) {
727 /*
728 * eat newlines
729 */
730 if (checkkwd == 2) {
731 checkkwd = 0;
732 while (t == TNL) {
733 parseheredoc();
734 t = xxreadtoken();
735 }
736 } else
737 checkkwd = 0;
738 /*
739 * check for keywords and aliases
740 */
741 if (t == TWORD && !quoteflag)
742 {
743 const char * const *pp;
744
745 for (pp = parsekwd; *pp; pp++) {
746 if (**pp == *wordtext && equal(*pp, wordtext))
747 {
748 lasttoken = t = pp - parsekwd + KWDOFFSET;
749 TRACE(("keyword %s recognized\n", tokname[t]));
750 goto out;
751 }
752 }
753 if (noaliases == 0 &&
754 (ap = lookupalias(wordtext, 1)) != NULL) {
755 pushstring(ap->val, strlen(ap->val), ap);
756 checkkwd = savecheckkwd;
757 goto top;
758 }
759 }
760out:
761 checkkwd = (t == TNOT) ? savecheckkwd : 0;
762 }
763#ifdef DEBUG
764 if (!alreadyseen)
765 TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
766 else
767 TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
768#endif
769 return (t);
770}
771
772
773/*
774 * Read the next input token.
775 * If the token is a word, we set backquotelist to the list of cmds in
776 * backquotes. We set quoteflag to true if any part of the word was
777 * quoted.
778 * If the token is TREDIR, then we set redirnode to a structure containing
779 * the redirection.
780 * In all cases, the variable startlinno is set to the number of the line
781 * on which the token starts.
782 *
783 * [Change comment: here documents and internal procedures]
784 * [Readtoken shouldn't have any arguments. Perhaps we should make the
785 * word parsing code into a separate routine. In this case, readtoken
786 * doesn't need to have any internal procedures, but parseword does.
787 * We could also make parseoperator in essence the main routine, and
788 * have parseword (readtoken1?) handle both words and redirection.]
789 */
790
791#define RETURN(token) return lasttoken = token
792
793STATIC int
794xxreadtoken(void)
795{
796 int c;
797
798 if (tokpushback) {
799 tokpushback = 0;
800 return lasttoken;
801 }
802 if (needprompt) {
803 setprompt(2);
804 needprompt = 0;
805 }
806 startlinno = plinno;
807 for (;;) { /* until token or start of word found */
808 c = pgetc_macro();
809 if (c == ' ' || c == '\t')
810 continue; /* quick check for white space first */
811 switch (c) {
812 case ' ': case '\t':
813 continue;
814 case '#':
815 while ((c = pgetc()) != '\n' && c != PEOF);
816 pungetc();
817 continue;
818 case '\\':
819 if (pgetc() == '\n') {
820 startlinno = ++plinno;
821 if (doprompt)
822 setprompt(2);
823 else
824 setprompt(0);
825 continue;
826 }
827 pungetc();
828 goto breakloop;
829 case '\n':
830 plinno++;
831 needprompt = doprompt;
832 RETURN(TNL);
833 case PEOF:
834 RETURN(TEOF);
835 case '&':
836 if (pgetc() == '&')
837 RETURN(TAND);
838 pungetc();
839 RETURN(TBACKGND);
840 case '|':
841 if (pgetc() == '|')
842 RETURN(TOR);
843 pungetc();
844 RETURN(TPIPE);
845 case ';':
846 if (pgetc() == ';')
847 RETURN(TENDCASE);
848 pungetc();
849 RETURN(TSEMI);
850 case '(':
851 RETURN(TLP);
852 case ')':
853 RETURN(TRP);
854 default:
855 goto breakloop;
856 }
857 }
858breakloop:
859 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
860#undef RETURN
861}
862
863
864
865/*
866 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
867 * is not NULL, read a here document. In the latter case, eofmark is the
868 * word which marks the end of the document and striptabs is true if
869 * leading tabs should be stripped from the document. The argument firstc
870 * is the first character of the input token or document.
871 *
872 * Because C does not have internal subroutines, I have simulated them
873 * using goto's to implement the subroutine linkage. The following macros
874 * will run code that appears at the end of readtoken1.
875 */
876
877#define CHECKEND() {goto checkend; checkend_return:;}
878#define PARSEREDIR() {goto parseredir; parseredir_return:;}
879#define PARSESUB() {goto parsesub; parsesub_return:;}
880#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
881#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
882#define PARSEARITH() {goto parsearith; parsearith_return:;}
883
884STATIC int
885readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
886{
887 int c = firstc;
888 char *out;
889 int len;
890 char line[EOFMARKLEN + 1];
891 struct nodelist *bqlist;
892 int quotef;
893 int dblquote;
894 int varnest; /* levels of variables expansion */
895 int arinest; /* levels of arithmetic expansion */
896 int parenlevel; /* levels of parens in arithmetic */
897 int oldstyle;
898 char const *prevsyntax; /* syntax before arithmetic */
899 int synentry;
900#if __GNUC__
901 /* Avoid longjmp clobbering */
902 (void) &out;
903 (void) &quotef;
904 (void) &dblquote;
905 (void) &varnest;
906 (void) &arinest;
907 (void) &parenlevel;
908 (void) &oldstyle;
909 (void) &prevsyntax;
910 (void) &syntax;
911 (void) &synentry;
912#endif
913
914 startlinno = plinno;
915 dblquote = 0;
916 if (syntax == DQSYNTAX)
917 dblquote = 1;
918 quotef = 0;
919 bqlist = NULL;
920 varnest = 0;
921 arinest = 0;
922 parenlevel = 0;
923
924 STARTSTACKSTR(out);
925 loop: { /* for each line, until end of word */
926#if ATTY
927 if (c == '\034' && doprompt
928 && attyset() && ! equal(termval(), "emacs")) {
929 attyline();
930 if (syntax == BASESYNTAX)
931 return readtoken();
932 c = pgetc();
933 goto loop;
934 }
935#endif
936 CHECKEND(); /* set c to PEOF if at end of here document */
937 for (;;) { /* until end of line or end of word */
938 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
939
940 synentry = syntax[c];
941
942 switch(synentry) {
943 case CNL: /* '\n' */
944 if (syntax == BASESYNTAX)
945 goto endword; /* exit outer loop */
946 USTPUTC(c, out);
947 plinno++;
948 if (doprompt)
949 setprompt(2);
950 else
951 setprompt(0);
952 c = pgetc();
953 goto loop; /* continue outer loop */
954 case CWORD:
955 USTPUTC(c, out);
956 break;
957 case CCTL:
958 if (eofmark == NULL || dblquote)
959 USTPUTC(CTLESC, out);
960 USTPUTC(c, out);
961 break;
962 case CBACK: /* backslash */
963 c = pgetc();
964 if (c == PEOF) {
965 USTPUTC('\\', out);
966 pungetc();
967 } else if (c == '\n') {
968 if (doprompt)
969 setprompt(2);
970 else
971 setprompt(0);
972 } else {
973 if (dblquote && c != '\\' &&
974 c != '`' && c != '$' &&
975 (c != '"' || eofmark != NULL))
976 USTPUTC('\\', out);
977 if (SQSYNTAX[c] == CCTL)
978 USTPUTC(CTLESC, out);
979 else if (eofmark == NULL)
980 USTPUTC(CTLQUOTEMARK, out);
981 USTPUTC(c, out);
982 quotef++;
983 }
984 break;
985 case CSQUOTE:
986 if (eofmark == NULL)
987 USTPUTC(CTLQUOTEMARK, out);
988 syntax = SQSYNTAX;
989 break;
990 case CDQUOTE:
991 if (eofmark == NULL)
992 USTPUTC(CTLQUOTEMARK, out);
993 syntax = DQSYNTAX;
994 dblquote = 1;
995 break;
996 case CENDQUOTE:
997 if (eofmark != NULL && arinest == 0 &&
998 varnest == 0) {
999 USTPUTC(c, out);
1000 } else {
1001 if (arinest) {
1002 syntax = ARISYNTAX;
1003 dblquote = 0;
1004 } else if (eofmark == NULL) {
1005 syntax = BASESYNTAX;
1006 dblquote = 0;
1007 }
1008 quotef++;
1009 }
1010 break;
1011 case CVAR: /* '$' */
1012 PARSESUB(); /* parse substitution */
1013 break;
1014 case CENDVAR: /* '}' */
1015 if (varnest > 0) {
1016 varnest--;
1017 USTPUTC(CTLENDVAR, out);
1018 } else {
1019 USTPUTC(c, out);
1020 }
1021 break;
1022 case CLP: /* '(' in arithmetic */
1023 parenlevel++;
1024 USTPUTC(c, out);
1025 break;
1026 case CRP: /* ')' in arithmetic */
1027 if (parenlevel > 0) {
1028 USTPUTC(c, out);
1029 --parenlevel;
1030 } else {
1031 if (pgetc() == ')') {
1032 if (--arinest == 0) {
1033 USTPUTC(CTLENDARI, out);
1034 syntax = prevsyntax;
1035 if (syntax == DQSYNTAX)
1036 dblquote = 1;
1037 else
1038 dblquote = 0;
1039 } else
1040 USTPUTC(')', out);
1041 } else {
1042 /*
1043 * unbalanced parens
1044 * (don't 2nd guess - no error)
1045 */
1046 pungetc();
1047 USTPUTC(')', out);
1048 }
1049 }
1050 break;
1051 case CBQUOTE: /* '`' */
1052 PARSEBACKQOLD();
1053 break;
1054 case CEOF:
1055 goto endword; /* exit outer loop */
1056 default:
1057 if (varnest == 0)
1058 goto endword; /* exit outer loop */
1059 USTPUTC(c, out);
1060 }
1061 c = pgetc_macro();
1062 }
1063 }
1064endword:
1065 if (syntax == ARISYNTAX)
1066 synerror("Missing '))'");
1067 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
1068 synerror("Unterminated quoted string");
1069 if (varnest != 0) {
1070 startlinno = plinno;
1071 synerror("Missing '}'");
1072 }
1073 USTPUTC('\0', out);
1074 len = out - stackblock();
1075 out = stackblock();
1076 if (eofmark == NULL) {
1077 if ((c == '>' || c == '<')
1078 && quotef == 0
1079 && len <= 2
1080 && (*out == '\0' || is_digit(*out))) {
1081 PARSEREDIR();
1082 return lasttoken = TREDIR;
1083 } else {
1084 pungetc();
1085 }
1086 }
1087 quoteflag = quotef;
1088 backquotelist = bqlist;
1089 grabstackblock(len);
1090 wordtext = out;
1091 return lasttoken = TWORD;
1092/* end of readtoken routine */
1093
1094
1095
1096/*
1097 * Check to see whether we are at the end of the here document. When this
1098 * is called, c is set to the first character of the next input line. If
1099 * we are at the end of the here document, this routine sets the c to PEOF.
1100 */
1101
1102checkend: {
1103 if (eofmark) {
1104 if (striptabs) {
1105 while (c == '\t')
1106 c = pgetc();
1107 }
1108 if (c == *eofmark) {
1109 if (pfgets(line, sizeof line) != NULL) {
1110 char *p, *q;
1111
1112 p = line;
1113 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1114 if (*p == '\n' && *q == '\0') {
1115 c = PEOF;
1116 plinno++;
1117 needprompt = doprompt;
1118 } else {
1119 pushstring(line, strlen(line), NULL);
1120 }
1121 }
1122 }
1123 }
1124 goto checkend_return;
1125}
1126
1127
1128/*
1129 * Parse a redirection operator. The variable "out" points to a string
1130 * specifying the fd to be redirected. The variable "c" contains the
1131 * first character of the redirection operator.
1132 */
1133
1134parseredir: {
1135 char fd = *out;
1136 union node *np;
1137
1138 np = (union node *)stalloc(sizeof (struct nfile));
1139 if (c == '>') {
1140 np->nfile.fd = 1;
1141 c = pgetc();
1142 if (c == '>')
1143 np->type = NAPPEND;
1144 else if (c == '&')
1145 np->type = NTOFD;
1146 else if (c == '|')
1147 np->type = NCLOBBER;
1148 else {
1149 np->type = NTO;
1150 pungetc();
1151 }
1152 } else { /* c == '<' */
1153 np->nfile.fd = 0;
1154 c = pgetc();
1155 if (c == '<') {
1156 if (sizeof (struct nfile) != sizeof (struct nhere)) {
1157 np = (union node *)stalloc(sizeof (struct nhere));
1158 np->nfile.fd = 0;
1159 }
1160 np->type = NHERE;
1161 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1162 heredoc->here = np;
1163 if ((c = pgetc()) == '-') {
1164 heredoc->striptabs = 1;
1165 } else {
1166 heredoc->striptabs = 0;
1167 pungetc();
1168 }
1169 } else if (c == '&')
1170 np->type = NFROMFD;
1171 else if (c == '>')
1172 np->type = NFROMTO;
1173 else {
1174 np->type = NFROM;
1175 pungetc();
1176 }
1177 }
1178 if (fd != '\0')
1179 np->nfile.fd = digit_val(fd);
1180 redirnode = np;
1181 goto parseredir_return;
1182}
1183
1184
1185/*
1186 * Parse a substitution. At this point, we have read the dollar sign
1187 * and nothing else.
1188 */
1189
1190parsesub: {
1191 int subtype;
1192 int typeloc;
1193 int flags;
1194 char *p;
1195#ifndef GDB_HACK
1196 static const char types[] = "}-+?=";
1197#endif
1198 int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
1199
1200 c = pgetc();
1201 if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
1202 USTPUTC('$', out);
1203 pungetc();
1204 } else if (c == '(') { /* $(command) or $((arith)) */
1205 if (pgetc() == '(') {
1206 PARSEARITH();
1207 } else {
1208 pungetc();
1209 PARSEBACKQNEW();
1210 }
1211 } else {
1212 USTPUTC(CTLVAR, out);
1213 typeloc = out - stackblock();
1214 USTPUTC(VSNORMAL, out);
1215 subtype = VSNORMAL;
1216 if (c == '{') {
1217 bracketed_name = 1;
1218 c = pgetc();
1219 if (c == '#') {
1220 if ((c = pgetc()) == '}')
1221 c = '#';
1222 else
1223 subtype = VSLENGTH;
1224 }
1225 else
1226 subtype = 0;
1227 }
1228 if (is_name(c)) {
1229 do {
1230 STPUTC(c, out);
1231 c = pgetc();
1232 } while (is_in_name(c));
1233 } else if (is_digit(c)) {
1234 if (bracketed_name) {
1235 do {
1236 STPUTC(c, out);
1237 c = pgetc();
1238 } while (is_digit(c));
1239 } else {
1240 STPUTC(c, out);
1241 c = pgetc();
1242 }
1243 } else {
1244 if (! is_special(c))
1245badsub: synerror("Bad substitution");
1246 USTPUTC(c, out);
1247 c = pgetc();
1248 }
1249 STPUTC('=', out);
1250 flags = 0;
1251 if (subtype == 0) {
1252 switch (c) {
1253 case ':':
1254 flags = VSNUL;
1255 c = pgetc();
1256 /*FALLTHROUGH*/
1257 default:
1258 p = strchr(types, c);
1259 if (p == NULL)
1260 goto badsub;
1261 subtype = p - types + VSNORMAL;
1262 break;
1263 case '%':
1264 case '#':
1265 {
1266 int cc = c;
1267 subtype = c == '#' ? VSTRIMLEFT :
1268 VSTRIMRIGHT;
1269 c = pgetc();
1270 if (c == cc)
1271 subtype++;
1272 else
1273 pungetc();
1274 break;
1275 }
1276 }
1277 } else {
1278 pungetc();
1279 }
1280 if (subtype != VSLENGTH && (dblquote || arinest))
1281 flags |= VSQUOTE;
1282 *(stackblock() + typeloc) = subtype | flags;
1283 if (subtype != VSNORMAL)
1284 varnest++;
1285 }
1286 goto parsesub_return;
1287}
1288
1289
1290/*
1291 * Called to parse command substitutions. Newstyle is set if the command
1292 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1293 * list of commands (passed by reference), and savelen is the number of
1294 * characters on the top of the stack which must be preserved.
1295 */
1296
1297parsebackq: {
1298 struct nodelist **nlpp;
1299 int savepbq;
1300 union node *n;
1301 char *volatile str;
1302 struct jmploc jmploc;
1303 struct jmploc *volatile savehandler;
1304 int savelen;
1305 int saveprompt;
1306#if __GNUC__
1307 /* Avoid longjmp clobbering */
1308 (void) &saveprompt;
1309#endif
1310
1311 savepbq = parsebackquote;
1312 if (setjmp(jmploc.loc)) {
1313 if (str)
1314 ckfree(str);
1315 parsebackquote = 0;
1316 handler = savehandler;
1317 longjmp(handler->loc, 1);
1318 }
1319 INTOFF;
1320 str = NULL;
1321 savelen = out - stackblock();
1322 if (savelen > 0) {
1323 str = ckmalloc(savelen);
1324 memcpy(str, stackblock(), savelen);
1325 }
1326 savehandler = handler;
1327 handler = &jmploc;
1328 INTON;
1329 if (oldstyle) {
1330 /* We must read until the closing backquote, giving special
1331 treatment to some slashes, and then push the string and
1332 reread it as input, interpreting it normally. */
1333 char *out;
1334 int c;
1335 int savelen;
1336 char *str;
1337
1338
1339 STARTSTACKSTR(out);
1340 for (;;) {
1341 if (needprompt) {
1342 setprompt(2);
1343 needprompt = 0;
1344 }
1345 switch (c = pgetc()) {
1346 case '`':
1347 goto done;
1348
1349 case '\\':
1350 if ((c = pgetc()) == '\n') {
1351 plinno++;
1352 if (doprompt)
1353 setprompt(2);
1354 else
1355 setprompt(0);
1356 /*
1357 * If eating a newline, avoid putting
1358 * the newline into the new character
1359 * stream (via the STPUTC after the
1360 * switch).
1361 */
1362 continue;
1363 }
1364 if (c != '\\' && c != '`' && c != '$'
1365 && (!dblquote || c != '"'))
1366 STPUTC('\\', out);
1367 break;
1368
1369 case '\n':
1370 plinno++;
1371 needprompt = doprompt;
1372 break;
1373
1374 case PEOF:
1375 startlinno = plinno;
1376 synerror("EOF in backquote substitution");
1377 break;
1378
1379 default:
1380 break;
1381 }
1382 STPUTC(c, out);
1383 }
1384done:
1385 STPUTC('\0', out);
1386 savelen = out - stackblock();
1387 if (savelen > 0) {
1388 str = ckmalloc(savelen);
1389 memcpy(str, stackblock(), savelen);
1390 setinputstring(str, 1);
1391 }
1392 }
1393 nlpp = &bqlist;
1394 while (*nlpp)
1395 nlpp = &(*nlpp)->next;
1396 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1397 (*nlpp)->next = NULL;
1398 parsebackquote = oldstyle;
1399
1400 if (oldstyle) {
1401 saveprompt = doprompt;
1402 doprompt = 0;
1403 }
1404
1405 n = list(0);
1406
1407 if (oldstyle)
1408 doprompt = saveprompt;
1409 else {
1410 if (readtoken() != TRP)
1411 synexpect(TRP);
1412 }
1413
1414 (*nlpp)->n = n;
1415 if (oldstyle) {
1416 /*
1417 * Start reading from old file again, ignoring any pushed back
1418 * tokens left from the backquote parsing
1419 */
1420 popfile();
1421 tokpushback = 0;
1422 }
1423 while (stackblocksize() <= savelen)
1424 growstackblock();
1425 STARTSTACKSTR(out);
1426 if (str) {
1427 memcpy(out, str, savelen);
1428 STADJUST(savelen, out);
1429 INTOFF;
1430 ckfree(str);
1431 str = NULL;
1432 INTON;
1433 }
1434 parsebackquote = savepbq;
1435 handler = savehandler;
1436 if (arinest || dblquote)
1437 USTPUTC(CTLBACKQ | CTLQUOTE, out);
1438 else
1439 USTPUTC(CTLBACKQ, out);
1440 if (oldstyle)
1441 goto parsebackq_oldreturn;
1442 else
1443 goto parsebackq_newreturn;
1444}
1445
1446/*
1447 * Parse an arithmetic expansion (indicate start of one and set state)
1448 */
1449parsearith: {
1450
1451 if (++arinest == 1) {
1452 prevsyntax = syntax;
1453 syntax = ARISYNTAX;
1454 USTPUTC(CTLARI, out);
1455 if (dblquote)
1456 USTPUTC('"',out);
1457 else
1458 USTPUTC(' ',out);
1459 } else {
1460 /*
1461 * we collapse embedded arithmetic expansion to
1462 * parenthesis, which should be equivalent
1463 */
1464 USTPUTC('(', out);
1465 }
1466 goto parsearith_return;
1467}
1468
1469} /* end of readtoken */
1470
1471
1472
1473#ifdef mkinit
1474RESET {
1475 tokpushback = 0;
1476 checkkwd = 0;
1477}
1478#endif
1479
1480/*
1481 * Returns true if the text contains nothing to expand (no dollar signs
1482 * or backquotes).
1483 */
1484
1485STATIC int
1486noexpand(char *text)
1487{
1488 char *p;
1489 char c;
1490
1491 p = text;
1492 while ((c = *p++) != '\0') {
1493 if ( c == CTLQUOTEMARK)
1494 continue;
1495 if (c == CTLESC)
1496 p++;
1497 else if (BASESYNTAX[(int)c] == CCTL)
1498 return 0;
1499 }
1500 return 1;
1501}
1502
1503
1504/*
1505 * Return true if the argument is a legal variable name (a letter or
1506 * underscore followed by zero or more letters, underscores, and digits).
1507 */
1508
1509int
1510goodname(char *name)
1511{
1512 char *p;
1513
1514 p = name;
1515 if (! is_name(*p))
1516 return 0;
1517 while (*++p) {
1518 if (! is_in_name(*p))
1519 return 0;
1520 }
1521 return 1;
1522}
1523
1524
1525/*
1526 * Called when an unexpected token is read during the parse. The argument
1527 * is the token that is expected, or -1 if more than one type of token can
1528 * occur at this point.
1529 */
1530
1531STATIC void
1532synexpect(int token)
1533{
1534 char msg[64];
1535
1536 if (token >= 0) {
1537 fmtstr(msg, 64, "%s unexpected (expecting %s)",
1538 tokname[lasttoken], tokname[token]);
1539 } else {
1540 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1541 }
1542 synerror(msg);
1543}
1544
1545
1546STATIC void
1547synerror(char *msg)
1548{
1549 if (commandname)
1550 outfmt(&errout, "%s: %d: ", commandname, startlinno);
1551 outfmt(&errout, "Syntax error: %s\n", msg);
1552 error((char *)NULL);
1553}
1554
1555STATIC void
1556setprompt(int which)
1557{
1558 whichprompt = which;
1559
1560#ifndef NO_HISTORY
1561 if (!el)
1562#endif
1563 out2str(getprompt(NULL));
1564}
1565
1566/*
1567 * called by editline -- any expansions to the prompt
1568 * should be added here.
1569 */
1570char *
1571getprompt(void *unused __unused)
1572{
1573 switch (whichprompt) {
1574 case 0:
1575 return "";
1576 case 1:
1577 return ps1val();
1578 case 2:
1579 return ps2val();
1580 default:
1581 return "<internal prompt error>";
1582 }
1583}