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