source: trunk/src/kash/parser.c@ 3457

Last change on this file since 3457 was 3457, checked in by bird, 5 years ago

kash: New parser allocator for non-forked-mode.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 45.3 KB
Line 
1/* $NetBSD: parser.c,v 1.59 2005/03/21 20:10:29 dsl Exp $ */
2
3/*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#if 0
36#ifndef lint
37static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
38#else
39__RCSID("$NetBSD: parser.c,v 1.59 2005/03/21 20:10:29 dsl Exp $");
40#endif /* not lint */
41#endif
42
43#define SH_MEMALLOC_NO_STACK
44#include <stdlib.h>
45#include <assert.h>
46
47#include "shell.h"
48#include "parser.h"
49#include "nodes.h"
50#include "expand.h" /* defines rmescapes() */
51#include "eval.h" /* defines commandname */
52#include "redir.h" /* defines copyfd() */
53#include "syntax.h"
54#include "options.h"
55#include "input.h"
56#include "output.h"
57#include "var.h"
58#include "error.h"
59#include "memalloc.h"
60#include "mystring.h"
61#include "alias.h"
62#include "show.h"
63#ifndef SMALL
64# include "myhistedit.h"
65#endif
66#include "cd.h"
67#include "shinstance.h"
68
69/*
70 * Shell command parser.
71 */
72
73#define EOFMARKLEN 79
74
75/* values returned by readtoken */
76#include "token.h"
77
78#define OPENBRACE '{'
79#define CLOSEBRACE '}'
80
81
82struct heredoc {
83 struct heredoc *next; /* next here document in list */
84 union node *here; /* redirection node */
85 char *eofmark; /* string indicating end of input */
86 int striptabs; /* if set, strip leading tabs */
87};
88
89
90
91//static int noalias = 0; /* when set, don't handle aliases */
92//struct heredoc *heredoclist; /* list of here documents to read */
93//int parsebackquote; /* nonzero if we are inside backquotes */
94//int doprompt; /* if set, prompt the user */
95//int needprompt; /* true if interactive and at start of line */
96//int lasttoken; /* last token read */
97//MKINIT int tokpushback; /* last token pushed back */
98//char *wordtext; /* text of last word returned by readtoken */
99//MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
100//struct nodelist *backquotelist;
101//union node *redirnode;
102//struct heredoc *heredoc;
103//int quoteflag; /* set if (part of) last token was quoted */
104//int startlinno; /* line # where last token started */
105
106
107STATIC union node *list(shinstance *, int);
108STATIC union node *andor(shinstance *);
109STATIC union node *pipeline(shinstance *);
110STATIC union node *command(shinstance *);
111STATIC union node *simplecmd(shinstance *, union node **, union node *);
112STATIC union node *makename(shinstance *);
113STATIC void parsefname(shinstance *);
114STATIC void parseheredoc(shinstance *);
115STATIC int peektoken(shinstance *);
116STATIC int readtoken(shinstance *);
117STATIC int xxreadtoken(shinstance *);
118STATIC int readtoken1(shinstance *, int, char const *, char *, int);
119STATIC int noexpand(shinstance *, char *);
120SH_NORETURN_1 STATIC void synexpect(shinstance *, int) SH_NORETURN_2;
121SH_NORETURN_1 STATIC void synerror(shinstance *, const char *) SH_NORETURN_2;
122STATIC void setprompt(shinstance *, 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(shinstance *psh, int interact)
132{
133 union node *ret;
134 int t;
135
136 TRACE2((psh, "parsecmd(%d)\n", interact));
137#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
138 pstackpush(psh);
139#endif
140 psh->tokpushback = 0;
141 psh->doprompt = interact;
142 if (psh->doprompt)
143 setprompt(psh, 1);
144 else
145 setprompt(psh, 0);
146 psh->needprompt = 0;
147 t = readtoken(psh);
148 if (t == TEOF)
149 return NEOF;
150 if (t == TNL)
151 return NULL;
152 psh->tokpushback++;
153 ret = list(psh, 1);
154#if 0 /*def DEBUG*/
155 TRACE2((psh, "parsecmd(%d) returns:\n", interact));
156 showtree(psh, ret);
157#endif
158 return ret;
159}
160
161
162STATIC union node *
163list(shinstance *psh, int nlflag)
164{
165 union node *n1, *n2, *n3;
166 int tok;
167
168 psh->checkkwd = 2;
169 if (nlflag == 0 && tokendlist[peektoken(psh)])
170 return NULL;
171 n1 = NULL;
172 for (;;) {
173 n2 = andor(psh);
174 tok = readtoken(psh);
175 if (tok == TBACKGND) {
176 if (n2->type == NCMD || n2->type == NPIPE) {
177 n2->ncmd.backgnd = 1;
178 } else if (n2->type == NREDIR) {
179 n2->type = NBACKGND;
180 } else {
181 n3 = pstallocnode(psh, sizeof (struct nredir));
182 n3->type = NBACKGND;
183 n3->nredir.n = n2;
184 n3->nredir.redirect = NULL;
185 n2 = n3;
186 }
187 }
188 if (n1 == NULL) {
189 n1 = n2;
190 }
191 else {
192 n3 = pstallocnode(psh, sizeof (struct nbinary));
193 n3->type = NSEMI;
194 n3->nbinary.ch1 = n1;
195 n3->nbinary.ch2 = n2;
196 n1 = n3;
197 }
198 switch (tok) {
199 case TBACKGND:
200 case TSEMI:
201 tok = readtoken(psh);
202 /* fall through */
203 case TNL:
204 if (tok == TNL) {
205 parseheredoc(psh);
206 if (nlflag)
207 return n1;
208 } else {
209 psh->tokpushback++;
210 }
211 psh->checkkwd = 2;
212 if (tokendlist[peektoken(psh)])
213 return n1;
214 break;
215 case TEOF:
216 if (psh->heredoclist)
217 parseheredoc(psh);
218 else
219 pungetc(psh); /* push back EOF on input */
220 return n1;
221 default:
222 if (nlflag)
223 synexpect(psh, -1);
224 psh->tokpushback++;
225 return n1;
226 }
227 }
228}
229
230
231
232STATIC union node *
233andor(shinstance *psh)
234{
235 union node *n1, *n2, *n3;
236 int t;
237
238 n1 = pipeline(psh);
239 for (;;) {
240 if ((t = readtoken(psh)) == TAND) {
241 t = NAND;
242 } else if (t == TOR) {
243 t = NOR;
244 } else {
245 psh->tokpushback++;
246 return n1;
247 }
248 n2 = pipeline(psh);
249 n3 = pstallocnode(psh, sizeof (struct nbinary));
250 n3->type = t;
251 n3->nbinary.ch1 = n1;
252 n3->nbinary.ch2 = n2;
253 n1 = n3;
254 }
255}
256
257
258
259STATIC union node *
260pipeline(shinstance *psh)
261{
262 union node *n1, *n2, *pipenode;
263 struct nodelist *lp, *prev;
264 int negate;
265
266 negate = 0;
267 TRACE((psh, "pipeline: entered\n"));
268 while (readtoken(psh) == TNOT)
269 negate = !negate;
270 psh->tokpushback++;
271 n1 = command(psh);
272 if (readtoken(psh) == TPIPE) {
273 pipenode = pstallocnode(psh, sizeof (struct npipe));
274 pipenode->type = NPIPE;
275 pipenode->npipe.backgnd = 0;
276 lp = pstalloclist(psh);
277 pipenode->npipe.cmdlist = lp;
278 lp->n = n1;
279 do {
280 prev = lp;
281 lp = pstalloclist(psh);
282 lp->n = command(psh);
283 prev->next = lp;
284 } while (readtoken(psh) == TPIPE);
285 lp->next = NULL;
286 n1 = pipenode;
287 }
288 psh->tokpushback++;
289 if (negate) {
290 n2 = pstallocnode(psh, sizeof (struct nnot));
291 n2->type = NNOT;
292 n2->nnot.com = n1;
293 return n2;
294 } else
295 return n1;
296}
297
298
299
300STATIC union node *
301command(shinstance *psh)
302{
303 union node *n1, *n2;
304 union node *ap, **app;
305 union node *cp, **cpp;
306 union node *redir, **rpp;
307 int t, negate = 0;
308
309 psh->checkkwd = 2;
310 redir = NULL;
311 n1 = NULL;
312 rpp = &redir;
313
314 /* Check for redirection which may precede command */
315 while (readtoken(psh) == TREDIR) {
316 *rpp = n2 = psh->redirnode;
317 rpp = &n2->nfile.next;
318 parsefname(psh);
319 }
320 psh->tokpushback++;
321
322 while (readtoken(psh) == TNOT) {
323 TRACE((psh, "command: TNOT recognized\n"));
324 negate = !negate;
325 }
326 psh->tokpushback++;
327
328 switch (readtoken(psh)) {
329 case TIF:
330 n1 = pstallocnode(psh, sizeof (struct nif));
331 n1->type = NIF;
332 n1->nif.test = list(psh, 0);
333 if (readtoken(psh) != TTHEN)
334 synexpect(psh, TTHEN);
335 n1->nif.ifpart = list(psh, 0);
336 n2 = n1;
337 while (readtoken(psh) == TELIF) {
338 n2->nif.elsepart = pstallocnode(psh, sizeof (struct nif));
339 n2 = n2->nif.elsepart;
340 n2->type = NIF;
341 n2->nif.test = list(psh, 0);
342 if (readtoken(psh) != TTHEN)
343 synexpect(psh, TTHEN);
344 n2->nif.ifpart = list(psh, 0);
345 }
346 if (psh->lasttoken == TELSE)
347 n2->nif.elsepart = list(psh, 0);
348 else {
349 n2->nif.elsepart = NULL;
350 psh->tokpushback++;
351 }
352 if (readtoken(psh) != TFI)
353 synexpect(psh, TFI);
354 psh->checkkwd = 1;
355 break;
356 case TWHILE:
357 case TUNTIL: {
358 int got;
359 n1 = pstallocnode(psh, sizeof (struct nbinary));
360 n1->type = (psh->lasttoken == TWHILE)? NWHILE : NUNTIL;
361 n1->nbinary.ch1 = list(psh, 0);
362 if ((got=readtoken(psh)) != TDO) {
363TRACE((psh, "expecting DO got %s %s\n", tokname[got], got == TWORD ? psh->wordtext : ""));
364 synexpect(psh, TDO);
365 }
366 n1->nbinary.ch2 = list(psh, 0);
367 if (readtoken(psh) != TDONE)
368 synexpect(psh, TDONE);
369 psh->checkkwd = 1;
370 break;
371 }
372 case TFOR:
373 if (readtoken(psh) != TWORD || psh->quoteflag || ! goodname(psh->wordtext))
374 synerror(psh, "Bad for loop variable");
375 n1 = pstallocnode(psh, sizeof (struct nfor));
376 n1->type = NFOR;
377 n1->nfor.var = psh->wordtext;
378 if (readtoken(psh) == TWORD && ! psh->quoteflag && equal(psh->wordtext, "in")) {
379 app = &ap;
380 while (readtoken(psh) == TWORD) {
381 n2 = pstallocnode(psh, sizeof (struct narg));
382 n2->type = NARG;
383 n2->narg.text = psh->wordtext;
384 n2->narg.backquote = psh->backquotelist;
385 *app = n2;
386 app = &n2->narg.next;
387 }
388 *app = NULL;
389 n1->nfor.args = ap;
390 if (psh->lasttoken != TNL && psh->lasttoken != TSEMI)
391 synexpect(psh, -1);
392 } else {
393 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
394 '@', '=', '\0'};
395 n2 = pstallocnode(psh, sizeof (struct narg));
396 n2->type = NARG;
397 n2->narg.text = argvars;
398 n2->narg.backquote = NULL;
399 n2->narg.next = NULL;
400 n1->nfor.args = n2;
401 /*
402 * Newline or semicolon here is optional (but note
403 * that the original Bourne shell only allowed NL).
404 */
405 if (psh->lasttoken != TNL && psh->lasttoken != TSEMI)
406 psh->tokpushback++;
407 }
408 psh->checkkwd = 2;
409 if ((t = readtoken(psh)) == TDO)
410 t = TDONE;
411 else if (t == TBEGIN)
412 t = TEND;
413 else
414 synexpect(psh, -1);
415 n1->nfor.body = list(psh, 0);
416 if (readtoken(psh) != t)
417 synexpect(psh, t);
418 psh->checkkwd = 1;
419 break;
420 case TCASE:
421 n1 = pstallocnode(psh, sizeof (struct ncase));
422 n1->type = NCASE;
423 if (readtoken(psh) != TWORD)
424 synexpect(psh, TWORD);
425 n1->ncase.expr = n2 = pstallocnode(psh, sizeof (struct narg));
426 n2->type = NARG;
427 n2->narg.text = psh->wordtext;
428 n2->narg.backquote = psh->backquotelist;
429 n2->narg.next = NULL;
430 while (readtoken(psh) == TNL);
431 if (psh->lasttoken != TWORD || ! equal(psh->wordtext, "in"))
432 synerror(psh, "expecting \"in\"");
433 cpp = &n1->ncase.cases;
434 psh->noalias = 1;
435 psh->checkkwd = 2, readtoken(psh);
436 do {
437 *cpp = cp = pstallocnode(psh, sizeof (struct nclist));
438 cp->type = NCLIST;
439 app = &cp->nclist.pattern;
440 for (;;) {
441 *app = ap = pstallocnode(psh, sizeof (struct narg));
442 ap->type = NARG;
443 ap->narg.text = psh->wordtext;
444 ap->narg.backquote = psh->backquotelist;
445 if (psh->checkkwd = 2, readtoken(psh) != TPIPE)
446 break;
447 app = &ap->narg.next;
448 readtoken(psh);
449 }
450 ap->narg.next = NULL;
451 psh->noalias = 0;
452 if (psh->lasttoken != TRP) {
453 synexpect(psh, TRP);
454 }
455 cp->nclist.body = list(psh, 0);
456
457 psh->checkkwd = 2;
458 if ((t = readtoken(psh)) != TESAC) {
459 if (t != TENDCASE) {
460 psh->noalias = 0;
461 synexpect(psh, TENDCASE);
462 } else {
463 psh->noalias = 1;
464 psh->checkkwd = 2;
465 readtoken(psh);
466 }
467 }
468 cpp = &cp->nclist.next;
469 } while(psh->lasttoken != TESAC);
470 psh->noalias = 0;
471 *cpp = NULL;
472 psh->checkkwd = 1;
473 break;
474 case TLP:
475 n1 = pstallocnode(psh, sizeof (struct nredir));
476 n1->type = NSUBSHELL;
477 n1->nredir.n = list(psh, 0);
478 n1->nredir.redirect = NULL;
479 if (readtoken(psh) != TRP)
480 synexpect(psh, TRP);
481 psh->checkkwd = 1;
482 break;
483 case TBEGIN:
484 n1 = list(psh, 0);
485 if (readtoken(psh) != TEND)
486 synexpect(psh, TEND);
487 psh->checkkwd = 1;
488 break;
489 /* Handle an empty command like other simple commands. */
490 case TSEMI:
491 /*
492 * An empty command before a ; doesn't make much sense, and
493 * should certainly be disallowed in the case of `if ;'.
494 */
495 if (!redir)
496 synexpect(psh, -1);
497 case TAND:
498 case TOR:
499 case TNL:
500 case TEOF:
501 case TWORD:
502 case TRP:
503 psh->tokpushback++;
504 n1 = simplecmd(psh, rpp, redir);
505 goto checkneg;
506 default:
507 synexpect(psh, -1);
508 /* NOTREACHED */
509 }
510
511 /* Now check for redirection which may follow command */
512 while (readtoken(psh) == TREDIR) {
513 *rpp = n2 = psh->redirnode;
514 rpp = &n2->nfile.next;
515 parsefname(psh);
516 }
517 psh->tokpushback++;
518 *rpp = NULL;
519 if (redir) {
520 if (n1->type != NSUBSHELL) {
521 n2 = pstallocnode(psh, sizeof (struct nredir));
522 n2->type = NREDIR;
523 n2->nredir.n = n1;
524 n1 = n2;
525 }
526 n1->nredir.redirect = redir;
527 }
528
529checkneg:
530 if (negate) {
531 n2 = pstallocnode(psh, sizeof (struct nnot));
532 n2->type = NNOT;
533 n2->nnot.com = n1;
534 return n2;
535 }
536 else
537 return n1;
538}
539
540
541STATIC union node *
542simplecmd(shinstance *psh, union node **rpp, union node *redir)
543{
544 union node *args, **app;
545 union node **orig_rpp = rpp;
546 union node *n = NULL, *n2;
547 int negate = 0;
548
549 /* If we don't have any redirections already, then we must reset */
550 /* rpp to be the address of the local redir variable. */
551 if (redir == 0)
552 rpp = &redir;
553
554 args = NULL;
555 app = &args;
556 /*
557 * We save the incoming value, because we need this for shell
558 * functions. There can not be a redirect or an argument between
559 * the function name and the open parenthesis.
560 */
561 orig_rpp = rpp;
562
563 while (readtoken(psh) == TNOT) {
564 TRACE((psh, "command: TNOT recognized\n"));
565 negate = !negate;
566 }
567 psh->tokpushback++;
568
569 for (;;) {
570 if (readtoken(psh) == TWORD) {
571 n = pstallocnode(psh, sizeof (struct narg));
572 n->type = NARG;
573 n->narg.text = psh->wordtext;
574 n->narg.backquote = psh->backquotelist;
575 *app = n;
576 app = &n->narg.next;
577 } else if (psh->lasttoken == TREDIR) {
578 *rpp = n = psh->redirnode;
579 rpp = &n->nfile.next;
580 parsefname(psh); /* read name of redirection file */
581 } else if (psh->lasttoken == TLP && app == &args->narg.next
582 && rpp == orig_rpp) {
583 /* We have a function */
584 if (readtoken(psh) != TRP)
585 synexpect(psh, TRP);
586#ifdef notdef
587 if (! goodname(n->narg.text))
588 synerror(psh, "Bad function name");
589#endif
590 n->type = NDEFUN;
591 n->narg.next = command(psh);
592 goto checkneg;
593 } else {
594 psh->tokpushback++;
595 break;
596 }
597 }
598 *app = NULL;
599 *rpp = NULL;
600 n = pstallocnode(psh, sizeof (struct ncmd));
601 n->type = NCMD;
602 n->ncmd.backgnd = 0;
603 n->ncmd.args = args;
604 n->ncmd.redirect = redir;
605
606checkneg:
607 if (negate) {
608 n2 = pstallocnode(psh, sizeof (struct nnot));
609 n2->type = NNOT;
610 n2->nnot.com = n;
611 return n2;
612 }
613 else
614 return n;
615}
616
617STATIC union node *
618makename(shinstance *psh)
619{
620 union node *n;
621
622 n = pstallocnode(psh, sizeof (struct narg));
623 n->type = NARG;
624 n->narg.next = NULL;
625 n->narg.text = psh->wordtext;
626 n->narg.backquote = psh->backquotelist;
627 return n;
628}
629
630void fixredir(shinstance *psh, union node *n, const char *text, int err)
631{
632 TRACE((psh, "Fix redir %s %d\n", text, err));
633 if (!err)
634 n->ndup.vname = NULL;
635
636 if (is_digit(text[0]) && text[1] == '\0')
637 n->ndup.dupfd = digit_val(text[0]);
638 else if (text[0] == '-' && text[1] == '\0')
639 n->ndup.dupfd = -1;
640 else {
641
642 if (err)
643 synerror(psh, "Bad fd number");
644 else
645 n->ndup.vname = makename(psh);
646 }
647}
648
649
650STATIC void
651parsefname(shinstance *psh)
652{
653 union node *n = psh->redirnode;
654
655 if (readtoken(psh) != TWORD)
656 synexpect(psh, -1);
657 if (n->type == NHERE) {
658 struct heredoc *here = psh->heredoc;
659 struct heredoc *p;
660 size_t i;
661
662 if (psh->quoteflag == 0)
663 n->type = NXHERE;
664 TRACE((psh, "Here document %d\n", n->type));
665 if (here->striptabs) {
666 while (*psh->wordtext == '\t')
667 psh->wordtext++;
668 }
669 if (! noexpand(psh, psh->wordtext) || (i = strlen(psh->wordtext)) == 0 || i > EOFMARKLEN)
670 synerror(psh, "Illegal eof marker for << redirection");
671 rmescapes(psh, psh->wordtext);
672 here->eofmark = psh->wordtext;
673 here->next = NULL;
674 if (psh->heredoclist == NULL)
675 psh->heredoclist = here;
676 else {
677 for (p = psh->heredoclist ; p->next ; p = p->next);
678 p->next = here;
679 }
680 } else if (n->type == NTOFD || n->type == NFROMFD) {
681 fixredir(psh, n, psh->wordtext, 0);
682 } else {
683 n->nfile.fname = makename(psh);
684 }
685}
686
687
688/*
689 * Input any here documents.
690 */
691
692STATIC void
693parseheredoc(shinstance *psh)
694{
695 struct heredoc *here;
696 union node *n;
697
698 while (psh->heredoclist) {
699 here = psh->heredoclist;
700 psh->heredoclist = here->next;
701 if (psh->needprompt) {
702 setprompt(psh, 2);
703 psh->needprompt = 0;
704 }
705 readtoken1(psh, pgetc(psh), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
706 here->eofmark, here->striptabs);
707 n = pstallocnode(psh, sizeof (struct narg));
708 n->narg.type = NARG;
709 n->narg.next = NULL;
710 n->narg.text = psh->wordtext;
711 n->narg.backquote = psh->backquotelist;
712 here->here->nhere.doc = n;
713 }
714}
715
716STATIC int
717peektoken(shinstance *psh)
718{
719 int t;
720
721 t = readtoken(psh);
722 psh->tokpushback++;
723 return (t);
724}
725
726STATIC int
727readtoken(shinstance *psh)
728{
729 int t;
730 int savecheckkwd = psh->checkkwd;
731#ifdef DEBUG
732 int alreadyseen = psh->tokpushback;
733#endif
734 struct alias *ap;
735
736 top:
737 t = xxreadtoken(psh);
738
739 if (psh->checkkwd) {
740 /*
741 * eat newlines
742 */
743 if (psh->checkkwd == 2) {
744 psh->checkkwd = 0;
745 while (t == TNL) {
746 parseheredoc(psh);
747 t = xxreadtoken(psh);
748 }
749 } else
750 psh->checkkwd = 0;
751 /*
752 * check for keywords and aliases
753 */
754 if (t == TWORD && !psh->quoteflag)
755 {
756 const char *const *pp;
757
758 for (pp = parsekwd; *pp; pp++) {
759 if (**pp == *psh->wordtext && equal(*pp, psh->wordtext))
760 {
761 psh->lasttoken = t = (int)(pp -
762 parsekwd + KWDOFFSET);
763 TRACE((psh, "keyword %s recognized\n", tokname[t]));
764 goto out;
765 }
766 }
767 if(!psh->noalias &&
768 (ap = lookupalias(psh, psh->wordtext, 1)) != NULL) {
769 pushstring(psh, ap->val, strlen(ap->val), ap);
770 psh->checkkwd = savecheckkwd;
771 goto top;
772 }
773 }
774out:
775 psh->checkkwd = (t == TNOT) ? savecheckkwd : 0;
776 }
777#ifdef DEBUG
778 if (!alreadyseen)
779 TRACE((psh, "token %s %s\n", tokname[t], t == TWORD ? psh->wordtext : ""));
780 else
781 TRACE((psh, "reread token %s \"%s\"\n", tokname[t], t == TWORD ? psh->wordtext : ""));
782#endif
783 return (t);
784}
785
786
787/*
788 * Read the next input token.
789 * If the token is a word, we set psh->backquotelist to the list of cmds in
790 * backquotes. We set psh->quoteflag to true if any part of the word was
791 * quoted.
792 * If the token is TREDIR, then we set psh->redirnode to a structure containing
793 * the redirection.
794 * In all cases, the variable psh->startlinno is set to the number of the line
795 * on which the token starts.
796 *
797 * [Change comment: here documents and internal procedures]
798 * [Readtoken shouldn't have any arguments. Perhaps we should make the
799 * word parsing code into a separate routine. In this case, readtoken
800 * doesn't need to have any internal procedures, but parseword does.
801 * We could also make parseoperator in essence the main routine, and
802 * have parseword (readtoken1?) handle both words and redirection.]
803 */
804
805#define RETURN(token) return psh->lasttoken = token
806
807STATIC int
808xxreadtoken(shinstance *psh)
809{
810 int c;
811
812 if (psh->tokpushback) {
813 psh->tokpushback = 0;
814 return psh->lasttoken;
815 }
816 if (psh->needprompt) {
817 setprompt(psh, 2);
818 psh->needprompt = 0;
819 }
820 psh->startlinno = psh->plinno;
821 for (;;) { /* until token or start of word found */
822 c = pgetc_macro(psh);
823 if (c == ' ' || c == '\t')
824 continue; /* quick check for white space first */
825 switch (c) {
826 case ' ': case '\t':
827 continue;
828 case '#':
829 while ((c = pgetc(psh)) != '\n' && c != PEOF);
830 pungetc(psh);
831 continue;
832 case '\\':
833 if (pgetc(psh) == '\n') {
834 psh->startlinno = ++psh->plinno;
835 if (psh->doprompt)
836 setprompt(psh, 2);
837 else
838 setprompt(psh, 0);
839 continue;
840 }
841 pungetc(psh);
842 goto breakloop;
843 case '\n':
844 psh->plinno++;
845 psh->needprompt = psh->doprompt;
846 RETURN(TNL);
847 case PEOF:
848 RETURN(TEOF);
849 case '&':
850 if (pgetc(psh) == '&')
851 RETURN(TAND);
852 pungetc(psh);
853 RETURN(TBACKGND);
854 case '|':
855 if (pgetc(psh) == '|')
856 RETURN(TOR);
857 pungetc(psh);
858 RETURN(TPIPE);
859 case ';':
860 if (pgetc(psh) == ';')
861 RETURN(TENDCASE);
862 pungetc(psh);
863 RETURN(TSEMI);
864 case '(':
865 RETURN(TLP);
866 case ')':
867 RETURN(TRP);
868 default:
869 goto breakloop;
870 }
871 }
872breakloop:
873 return readtoken1(psh, c, BASESYNTAX, (char *)NULL, 0);
874#undef RETURN
875}
876
877
878
879/*
880 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
881 * is not NULL, read a here document. In the latter case, eofmark is the
882 * word which marks the end of the document and striptabs is true if
883 * leading tabs should be stripped from the document. The argument firstc
884 * is the first character of the input token or document.
885 *
886 * Because C does not have internal subroutines, I have simulated them
887 * using goto's to implement the subroutine linkage. The following macros
888 * will run code that appears at the end of readtoken1.
889 */
890
891#define CHECKEND() {goto checkend; checkend_return:;}
892#define PARSEREDIR() {goto parseredir; parseredir_return:;}
893#define PARSESUB() {goto parsesub; parsesub_return:;}
894#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
895#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
896#define PARSEARITH() {goto parsearith; parsearith_return:;}
897
898/*
899 * Keep track of nested doublequotes in dblquote and doublequotep.
900 * We use dblquote for the first 32 levels, and we expand to a malloc'ed
901 * region for levels above that. Usually we never need to malloc.
902 * This code assumes that an int is 32 bits. We don't use uint32_t,
903 * because the rest of the code does not.
904 */
905#define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \
906 (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32))))
907
908#define SETDBLQUOTE() \
909 if (varnest < 32) \
910 dblquote |= (1 << varnest); \
911 else \
912 dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32))
913
914#define CLRDBLQUOTE() \
915 if (varnest < 32) \
916 dblquote &= ~(1 << varnest); \
917 else \
918 dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32))
919
920STATIC int
921readtoken1(shinstance *psh, int firstc, char const *syntax, char *eofmark, int striptabs)
922{
923 int c = firstc;
924 char *out;
925 char line[EOFMARKLEN + 1];
926 struct nodelist *bqlist;
927 int quotef = 0;
928 int *dblquotep = NULL;
929 size_t maxnest = 32;
930 int dblquote;
931 int varnest; /* levels of variables expansion */
932 int arinest; /* levels of arithmetic expansion */
933 int parenlevel; /* levels of parens in arithmetic */
934 int oldstyle;
935 char const *prevsyntax; /* syntax before arithmetic */
936
937 psh->startlinno = psh->plinno;
938 dblquote = 0;
939 varnest = 0;
940 if (syntax == DQSYNTAX) {
941 SETDBLQUOTE();
942 }
943 quotef = 0;
944 bqlist = NULL;
945 arinest = 0;
946 parenlevel = 0;
947
948#if __GNUC__
949 /* Try avoid longjmp clobbering */
950 (void) &maxnest;
951 (void) &dblquotep;
952 (void) &out;
953 (void) &quotef;
954 (void) &dblquote;
955 (void) &varnest;
956 (void) &arinest;
957 (void) &parenlevel;
958 (void) &oldstyle;
959 (void) &prevsyntax;
960 (void) &syntax;
961#endif
962
963 PSTARTSTACKSTR(psh, out);
964 loop: { /* for each line, until end of word */
965#if ATTY
966 if (c == '\034' && psh->doprompt
967 && attyset() && ! equal(termval(), "emacs")) {
968 attyline();
969 if (syntax == BASESYNTAX)
970 return readtoken(psh);
971 c = pgetc(psh);
972 goto loop;
973 }
974#endif
975 CHECKEND(); /* set c to PEOF if at end of here document */
976 for (;;) { /* until end of line or end of word */
977 PSTCHECKSTRSPACE(psh, 4+1, out); /* permit 4 calls to PSTUPUTC, pluss terminator */
978 switch(syntax[c]) {
979 case CNL: /* '\n' */
980 if (syntax == BASESYNTAX)
981 goto endword; /* exit outer loop */
982 PSTUPUTC(psh, c, out);
983 psh->plinno++;
984 if (psh->doprompt)
985 setprompt(psh, 2);
986 else
987 setprompt(psh, 0);
988 c = pgetc(psh);
989 goto loop; /* continue outer loop */
990 case CWORD:
991 PSTUPUTC(psh, c, out);
992 break;
993 case CCTL:
994 if (eofmark == NULL || ISDBLQUOTE())
995 PSTUPUTC(psh, CTLESC, out);
996 PSTUPUTC(psh, c, out);
997 break;
998 case CBACK: /* backslash */
999 c = pgetc(psh);
1000 if (c == PEOF) {
1001 PSTUPUTC(psh, '\\', out);
1002 pungetc(psh);
1003 break;
1004 }
1005 if (c == '\n') {
1006 if (psh->doprompt)
1007 setprompt(psh, 2);
1008 else
1009 setprompt(psh, 0);
1010 break;
1011 }
1012 quotef = 1;
1013 if (ISDBLQUOTE() && c != '\\' &&
1014 c != '`' && c != '$' &&
1015 (c != '"' || eofmark != NULL))
1016 PSTUPUTC(psh, '\\', out);
1017 if (SQSYNTAX[c] == CCTL)
1018 PSTUPUTC(psh, CTLESC, out);
1019 else if (eofmark == NULL) {
1020 PSTUPUTC(psh, CTLQUOTEMARK, out);
1021 PSTUPUTC(psh, c, out);
1022 if (varnest != 0)
1023 PSTUPUTC(psh, CTLQUOTEEND, out);
1024 break;
1025 }
1026 PSTUPUTC(psh, c, out);
1027 break;
1028 case CSQUOTE:
1029 if (syntax != SQSYNTAX) {
1030 if (eofmark == NULL)
1031 PSTUPUTC(psh, CTLQUOTEMARK, out);
1032 quotef = 1;
1033 syntax = SQSYNTAX;
1034 break;
1035 }
1036 if (eofmark != NULL && arinest == 0 &&
1037 varnest == 0) {
1038 /* Ignore inside quoted here document */
1039 PSTUPUTC(psh, c, out);
1040 break;
1041 }
1042 /* End of single quotes... */
1043 if (arinest)
1044 syntax = ARISYNTAX;
1045 else {
1046 syntax = BASESYNTAX;
1047 if (varnest != 0)
1048 PSTUPUTC(psh, CTLQUOTEEND, out);
1049 }
1050 break;
1051 case CDQUOTE:
1052 if (eofmark != NULL && arinest == 0 &&
1053 varnest == 0) {
1054 /* Ignore inside here document */
1055 PSTUPUTC(psh, c, out);
1056 break;
1057 }
1058 quotef = 1;
1059 if (arinest) {
1060 if (ISDBLQUOTE()) {
1061 syntax = ARISYNTAX;
1062 CLRDBLQUOTE();
1063 } else {
1064 syntax = DQSYNTAX;
1065 SETDBLQUOTE();
1066 PSTUPUTC(psh, CTLQUOTEMARK, out);
1067 }
1068 break;
1069 }
1070 if (eofmark != NULL)
1071 break;
1072 if (ISDBLQUOTE()) {
1073 if (varnest != 0)
1074 PSTUPUTC(psh, CTLQUOTEEND, out);
1075 syntax = BASESYNTAX;
1076 CLRDBLQUOTE();
1077 } else {
1078 syntax = DQSYNTAX;
1079 SETDBLQUOTE();
1080 PSTUPUTC(psh, CTLQUOTEMARK, out);
1081 }
1082 break;
1083 case CVAR: /* '$' */
1084 PARSESUB(); /* parse substitution */
1085 break;
1086 case CENDVAR: /* CLOSEBRACE */
1087 if (varnest > 0 && !ISDBLQUOTE()) {
1088 varnest--;
1089 PSTUPUTC(psh, CTLENDVAR, out);
1090 } else {
1091 PSTUPUTC(psh, c, out);
1092 }
1093 break;
1094 case CLP: /* '(' in arithmetic */
1095 parenlevel++;
1096 PSTUPUTC(psh, c, out);
1097 break;
1098 case CRP: /* ')' in arithmetic */
1099 if (parenlevel > 0) {
1100 PSTUPUTC(psh, c, out);
1101 --parenlevel;
1102 } else {
1103 if (pgetc(psh) == ')') {
1104 if (--arinest == 0) {
1105 PSTUPUTC(psh, CTLENDARI, out);
1106 syntax = prevsyntax;
1107 if (syntax == DQSYNTAX)
1108 SETDBLQUOTE();
1109 else
1110 CLRDBLQUOTE();
1111 } else
1112 PSTUPUTC(psh, ')', out);
1113 } else {
1114 /*
1115 * unbalanced parens
1116 * (don't 2nd guess - no error)
1117 */
1118 pungetc(psh);
1119 PSTUPUTC(psh, ')', out);
1120 }
1121 }
1122 break;
1123 case CBQUOTE: /* '`' */
1124 PARSEBACKQOLD();
1125 break;
1126 case CSHEOF:
1127 goto endword; /* exit outer loop */
1128 default:
1129 if (varnest == 0)
1130 goto endword; /* exit outer loop */
1131 PSTUPUTC(psh, c, out);
1132 }
1133 c = pgetc_macro(psh);
1134 }
1135 }
1136endword:
1137 if (syntax == ARISYNTAX)
1138 synerror(psh, "Missing '))'");
1139 if (syntax != BASESYNTAX && ! psh->parsebackquote && eofmark == NULL)
1140 synerror(psh, "Unterminated quoted string");
1141 if (varnest != 0) {
1142 psh->startlinno = psh->plinno;
1143 /* { */
1144 synerror(psh, "Missing '}'");
1145 }
1146 PSTUPUTC(psh, '\0', out);
1147 if (eofmark == NULL) {
1148 size_t len = (size_t)(out - PSTBLOCK(psh));
1149 char *start = PSTBLOCK(psh);
1150 if ((c == '>' || c == '<')
1151 && quotef == 0
1152 && len <= 2
1153 && (*start == '\0' || is_digit(*start))) {
1154 out = start;
1155 PARSEREDIR();
1156 return psh->lasttoken = TREDIR;
1157 } else {
1158 pungetc(psh);
1159 }
1160 }
1161 psh->quoteflag = quotef;
1162 psh->backquotelist = bqlist;
1163 psh->wordtext = pstgrabstr(psh, out);
1164 if (dblquotep != NULL)
1165 ckfree(psh, dblquotep);
1166 return psh->lasttoken = TWORD;
1167/* end of readtoken routine */
1168
1169
1170
1171/*
1172 * Check to see whether we are at the end of the here document. When this
1173 * is called, c is set to the first character of the next input line. If
1174 * we are at the end of the here document, this routine sets the c to PEOF.
1175 */
1176
1177checkend: {
1178 if (eofmark) {
1179 if (striptabs) {
1180 while (c == '\t')
1181 c = pgetc(psh);
1182 }
1183 if (c == *eofmark) {
1184 if (pfgets(psh, line, sizeof line) != NULL) {
1185 char *p, *q;
1186
1187 p = line;
1188 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1189 if (*p == '\n' && *q == '\0') {
1190 c = PEOF;
1191 psh->plinno++;
1192 psh->needprompt = psh->doprompt;
1193 } else {
1194 pushstring(psh, line, strlen(line), NULL);
1195 }
1196 }
1197 }
1198 }
1199 goto checkend_return;
1200}
1201
1202
1203/*
1204 * Parse a redirection operator. The variable "out" points to a string
1205 * specifying the fd to be redirected. The variable "c" contains the
1206 * first character of the redirection operator.
1207 */
1208
1209parseredir: {
1210 union node *np;
1211 char fd = *out;
1212 char dummy[ sizeof(struct ndup) >= sizeof(struct nfile)
1213 && sizeof(struct ndup) >= sizeof(struct nhere) ? 1 : 0];
1214 (void)dummy;
1215
1216 np = pstallocnode(psh, sizeof (struct ndup));
1217 if (c == '>') {
1218 np->nfile.fd = 1;
1219 c = pgetc(psh);
1220 if (c == '>')
1221 np->type = NAPPEND;
1222 else if (c == '|')
1223 np->type = NCLOBBER;
1224 else if (c == '&')
1225 np->type = NTOFD;
1226 else {
1227 np->type = NTO;
1228 pungetc(psh);
1229 }
1230 } else { /* c == '<' */
1231 np->nfile.fd = 0;
1232 switch (c = pgetc(psh)) {
1233 case '<':
1234 np->type = NHERE;
1235 psh->heredoc = (struct heredoc *)pstalloc(psh, sizeof (struct heredoc));
1236 psh->heredoc->here = np;
1237 if ((c = pgetc(psh)) == '-') {
1238 psh->heredoc->striptabs = 1;
1239 } else {
1240 psh->heredoc->striptabs = 0;
1241 pungetc(psh);
1242 }
1243 break;
1244
1245 case '&':
1246 np->type = NFROMFD;
1247 break;
1248
1249 case '>':
1250 np->type = NFROMTO;
1251 break;
1252
1253 default:
1254 np->type = NFROM;
1255 pungetc(psh);
1256 break;
1257 }
1258 }
1259 if (fd != '\0')
1260 np->nfile.fd = digit_val(fd);
1261 psh->redirnode = np;
1262 goto parseredir_return;
1263}
1264
1265
1266/*
1267 * Parse a substitution. At this point, we have read the dollar sign
1268 * and nothing else.
1269 */
1270
1271parsesub: {
1272 int subtype;
1273 int typeloc;
1274 int flags;
1275 char *p;
1276 static const char types[] = "}-+?=";
1277
1278 c = pgetc(psh);
1279 if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
1280 PSTUPUTC(psh, '$', out);
1281 pungetc(psh);
1282 } else if (c == '(') { /* $(command) or $((arith)) */
1283 if (pgetc(psh) == '(') {
1284 PARSEARITH();
1285 } else {
1286 pungetc(psh);
1287 PARSEBACKQNEW();
1288 }
1289 } else {
1290 PSTUPUTC(psh, CTLVAR, out);
1291 typeloc = (int)(out - PSTBLOCK(psh));
1292 PSTUPUTC(psh, VSNORMAL, out);
1293 subtype = VSNORMAL;
1294 if (c == OPENBRACE) {
1295 c = pgetc(psh);
1296 if (c == '#') {
1297 if ((c = pgetc(psh)) == CLOSEBRACE)
1298 c = '#';
1299 else
1300 subtype = VSLENGTH;
1301 }
1302 else
1303 subtype = 0;
1304 }
1305 if (is_name(c)) {
1306 do {
1307 PSTPUTC(psh, c, out);
1308 c = pgetc(psh);
1309 } while (is_in_name(c));
1310 } else if (is_digit(c)) {
1311 do {
1312 PSTUPUTC(psh, c, out);
1313 c = pgetc(psh);
1314 } while (is_digit(c));
1315 }
1316 else if (is_special(c)) {
1317 PSTUPUTC(psh, c, out);
1318 c = pgetc(psh);
1319 }
1320 else {
1321badsub:
1322 synerror(psh, "Bad substitution");
1323 }
1324
1325 PSTPUTC(psh, '=', out);
1326 flags = 0;
1327 if (subtype == 0) {
1328 switch (c) {
1329 case ':':
1330 flags = VSNUL;
1331 c = pgetc(psh);
1332 /*FALLTHROUGH*/
1333 default:
1334 p = strchr(types, c);
1335 if (p == NULL)
1336 goto badsub;
1337 subtype = (int)(p - types + VSNORMAL);
1338 break;
1339 case '%':
1340 case '#':
1341 {
1342 int cc = c;
1343 subtype = c == '#' ? VSTRIMLEFT :
1344 VSTRIMRIGHT;
1345 c = pgetc(psh);
1346 if (c == cc)
1347 subtype++;
1348 else
1349 pungetc(psh);
1350 break;
1351 }
1352 }
1353 } else {
1354 pungetc(psh);
1355 }
1356 if (ISDBLQUOTE() || arinest)
1357 flags |= VSQUOTE;
1358 *(PSTBLOCK(psh) + typeloc) = subtype | flags;
1359 if (subtype != VSNORMAL) {
1360 varnest++;
1361 if (varnest >= (int)maxnest) {
1362 dblquotep = ckrealloc(psh, dblquotep, maxnest / 8);
1363 dblquotep[(maxnest / 32) - 1] = 0;
1364 maxnest += 32;
1365 }
1366 }
1367 }
1368 goto parsesub_return;
1369}
1370
1371
1372/*
1373 * Called to parse command substitutions. Newstyle is set if the command
1374 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1375 * list of commands (passed by reference), and savelen is the number of
1376 * characters on the top of the stack which must be preserved.
1377 */
1378
1379parsebackq: {
1380 struct nodelist **nlpp;
1381 int savepbq;
1382 union node *n;
1383 char *volatile str;
1384 struct jmploc jmploc;
1385 struct jmploc *volatile savehandler;
1386 int savelen;
1387 int saveprompt;
1388#ifdef __GNUC__
1389 (void) &saveprompt;
1390#endif
1391
1392 savepbq = psh->parsebackquote;
1393 if (setjmp(jmploc.loc)) {
1394 if (str)
1395 ckfree(psh, str);
1396 psh->parsebackquote = 0;
1397 psh->handler = savehandler;
1398 longjmp(psh->handler->loc, 1);
1399 }
1400 INTOFF;
1401 str = NULL;
1402 savelen = (int)(out - PSTBLOCK(psh));
1403 if (savelen > 0) {
1404 str = ckmalloc(psh, savelen);
1405 memcpy(str, PSTBLOCK(psh), savelen);
1406 }
1407 savehandler = psh->handler;
1408 psh->handler = &jmploc;
1409 INTON;
1410 if (oldstyle) {
1411 /* We must read until the closing backquote, giving special
1412 treatment to some slashes, and then push the string and
1413 reread it as input, interpreting it normally. */
1414 char *pout;
1415 int pc;
1416 int psavelen;
1417 char *pstr;
1418
1419
1420 PSTARTSTACKSTR(psh, pout);
1421 for (;;) {
1422 if (psh->needprompt) {
1423 setprompt(psh, 2);
1424 psh->needprompt = 0;
1425 }
1426 switch (pc = pgetc(psh)) {
1427 case '`':
1428 goto done;
1429
1430 case '\\':
1431 if ((pc = pgetc(psh)) == '\n') {
1432 psh->plinno++;
1433 if (psh->doprompt)
1434 setprompt(psh, 2);
1435 else
1436 setprompt(psh, 0);
1437 /*
1438 * If eating a newline, avoid putting
1439 * the newline into the new character
1440 * stream (via the PSTPUTC after the
1441 * switch).
1442 */
1443 continue;
1444 }
1445 if (pc != '\\' && pc != '`' && pc != '$' && (!ISDBLQUOTE() || pc != '"'))
1446 PSTPUTC(psh, '\\', pout);
1447 break;
1448
1449 case '\n':
1450 psh->plinno++;
1451 psh->needprompt = psh->doprompt;
1452 break;
1453
1454 case PEOF:
1455 psh->startlinno = psh->plinno;
1456 synerror(psh, "EOF in backquote substitution");
1457 break;
1458
1459 default:
1460 break;
1461 }
1462 PSTPUTC(psh, pc, pout);
1463 }
1464done:
1465 PSTPUTC(psh, '\0', pout);
1466 psavelen = (int)(pout - PSTBLOCK(psh));
1467 if (psavelen > 0) { /** @todo nonsensical test? */
1468 pstr = pstgrabstr(psh, pout);
1469 setinputstring(psh, pstr, 1 /*push*/);
1470 }
1471 }
1472 nlpp = &bqlist;
1473 while (*nlpp)
1474 nlpp = &(*nlpp)->next;
1475 *nlpp = pstalloclist(psh);
1476 (*nlpp)->next = NULL;
1477 psh->parsebackquote = oldstyle;
1478
1479 if (oldstyle) {
1480 saveprompt = psh->doprompt;
1481 psh->doprompt = 0;
1482 }
1483
1484 n = list(psh, 0);
1485
1486 if (oldstyle)
1487 psh->doprompt = saveprompt;
1488 else {
1489 if (readtoken(psh) != TRP)
1490 synexpect(psh, TRP);
1491 }
1492
1493 (*nlpp)->n = n;
1494 if (oldstyle) {
1495 /*
1496 * Start reading from old file again, ignoring any pushed back
1497 * tokens left from the backquote parsing
1498 */
1499 popfile(psh);
1500 psh->tokpushback = 0;
1501 }
1502 PSTARTSTACKSTR(psh, out);
1503 if (str) {
1504 PSTPUTSTRN(psh, str, savelen, out);
1505 INTOFF;
1506 ckfree(psh, str);
1507 str = NULL;
1508 INTON;
1509 }
1510 psh->parsebackquote = savepbq;
1511 psh->handler = savehandler;
1512 if (arinest || ISDBLQUOTE())
1513 PSTUPUTC(psh, CTLBACKQ | CTLQUOTE, out);
1514 else
1515 PSTUPUTC(psh, CTLBACKQ, out);
1516 if (oldstyle)
1517 goto parsebackq_oldreturn;
1518 else
1519 goto parsebackq_newreturn;
1520}
1521
1522/*
1523 * Parse an arithmetic expansion (indicate start of one and set state)
1524 */
1525parsearith: {
1526
1527 if (++arinest == 1) {
1528 prevsyntax = syntax;
1529 syntax = ARISYNTAX;
1530 PSTUPUTC(psh, CTLARI, out);
1531 if (ISDBLQUOTE())
1532 PSTUPUTC(psh, '"',out);
1533 else
1534 PSTUPUTC(psh, ' ',out);
1535 } else {
1536 /*
1537 * we collapse embedded arithmetic expansion to
1538 * parenthesis, which should be equivalent
1539 */
1540 PSTUPUTC(psh, '(', out);
1541 }
1542 goto parsearith_return;
1543}
1544
1545} /* end of readtoken */
1546
1547
1548
1549#ifdef mkinit
1550RESET {
1551 psh->tokpushback = 0;
1552 psh->checkkwd = 0;
1553}
1554#endif
1555
1556/*
1557 * Returns true if the text contains nothing to expand (no dollar signs
1558 * or backquotes).
1559 */
1560
1561STATIC int
1562noexpand(shinstance *psh, char *text)
1563{
1564 char *p;
1565 char c;
1566
1567 p = text;
1568 while ((c = *p++) != '\0') {
1569 if (c == CTLQUOTEMARK)
1570 continue;
1571 if (c == CTLESC)
1572 p++;
1573 else if (BASESYNTAX[(int)c] == CCTL)
1574 return 0;
1575 }
1576 return 1;
1577}
1578
1579
1580/*
1581 * Return true if the argument is a legal variable name (a letter or
1582 * underscore followed by zero or more letters, underscores, and digits).
1583 */
1584
1585int
1586goodname(const char *name)
1587{
1588 const char *p;
1589
1590 p = name;
1591 if (! is_name(*p))
1592 return 0;
1593 while (*++p) {
1594 if (! is_in_name(*p))
1595 return 0;
1596 }
1597 return 1;
1598}
1599
1600
1601/*
1602 * Called when an unexpected token is read during the parse. The argument
1603 * is the token that is expected, or -1 if more than one type of token can
1604 * occur at this point.
1605 */
1606
1607SH_NORETURN_1 STATIC void
1608synexpect(shinstance *psh, int token)
1609{
1610 char msg[64];
1611
1612 if (token >= 0) {
1613 fmtstr(msg, 64, "%s unexpected (expecting %s)",
1614 tokname[psh->lasttoken], tokname[token]);
1615 } else {
1616 fmtstr(msg, 64, "%s unexpected", tokname[psh->lasttoken]);
1617 }
1618 synerror(psh, msg);
1619 /* NOTREACHED */
1620}
1621
1622
1623SH_NORETURN_1 STATIC void
1624synerror(shinstance *psh, const char *msg)
1625{
1626 if (psh->commandname) {
1627 TRACE((psh, "synerror: %s: %d: Syntax error: %s", psh->commandname, psh->startlinno, msg));
1628 outfmt(&psh->errout, "%s: %d: ", psh->commandname, psh->startlinno);
1629 } else {
1630 TRACE((psh, "synerror: Syntax error: %s\n", msg));
1631 }
1632 outfmt(&psh->errout, "Syntax error: %s\n", msg);
1633 error(psh, (char *)NULL);
1634 /* NOTREACHED */
1635}
1636
1637STATIC const char *
1638my_basename(const char *argv0, unsigned *lenp)
1639{
1640 const char *tmp;
1641
1642 /* skip the path */
1643 for (tmp = strpbrk(argv0, "\\/:"); tmp; tmp = strpbrk(argv0, "\\/:"))
1644 argv0 = tmp + 1;
1645
1646 if (lenp) {
1647 /* find the end, ignoring extenions */
1648 tmp = strrchr(argv0, '.');
1649 if (!tmp)
1650 tmp = strchr(argv0, '\0');
1651 *lenp = (unsigned)(tmp - argv0);
1652 }
1653 return argv0;
1654}
1655
1656
1657STATIC void
1658setprompt(shinstance *psh, int which)
1659{
1660 psh->whichprompt = which;
1661
1662#ifndef SMALL
1663 if (!el)
1664#endif
1665 {
1666 /* deal with bash prompts */
1667 const char *prompt = getprompt(psh, NULL);
1668 if (!strchr(prompt, '\\')) {
1669 out2str(psh, prompt);
1670 } else {
1671 while (*prompt) {
1672 if (*prompt != '\\') {
1673 out2c(psh, *prompt++);
1674 } else {
1675 prompt++;
1676 switch (*prompt++)
1677 {
1678 /* simple */
1679 case '$': out2c(psh, sh_geteuid(psh) ? '$' : '#'); break;
1680 case '\\': out2c(psh, '\\'); break;
1681 case 'a': out2c(psh, '\a'); break;
1682 case 'e': out2c(psh, 033); break;
1683 case 'n': out2c(psh, '\n'); break;
1684 case 'r': out2c(psh, '\r'); break;
1685
1686 /* complicated */
1687 case 's': {
1688 unsigned len;
1689 const char *arg0 = my_basename(psh->arg0, &len);
1690 outfmt(psh->out2, "%.*s", len, arg0);
1691 break;
1692 }
1693 case 'v':
1694 outfmt(psh->out2, "%d.%d", KBUILD_VERSION_MAJOR,
1695 KBUILD_VERSION_MINOR);
1696 break;
1697 case 'V':
1698 outfmt(psh->out2, "%d.%d.%d", KBUILD_VERSION_MAJOR,
1699 KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH);
1700 break;
1701 out2str(psh, getpwd(psh, 1) ? getpwd(psh, 1) : "?");
1702 break;
1703 case 'w':
1704 case 'W': {
1705 const char *cwd = getpwd(psh, 1);
1706 const char *home = bltinlookup(psh, "HOME", 1);
1707 size_t home_len = home ? strlen(home) : 0;
1708 if (!cwd) cwd = "?";
1709 if (!strncmp(cwd, home, home_len)
1710 && ( cwd[home_len] == '\0'
1711 || (cwd[home_len] == '/' && prompt[-1] == 'w'))) {
1712 out2c(psh, '~');
1713 if (prompt[-1] == 'w' && cwd[home_len]) {
1714 out2str(psh, cwd + home_len);
1715 }
1716 } else if (prompt[-1] == 'w') {
1717 out2str(psh, cwd);
1718 } else {
1719 out2str(psh, my_basename(cwd, NULL));
1720 }
1721 break;
1722 }
1723 case '0':
1724 case '1':
1725 case '2':
1726 case '3': {
1727 unsigned int ch = prompt[-1] - '0';
1728 if (isdigit(*prompt)) {
1729 ch *= 8;
1730 ch += *prompt++ - '0';
1731 }
1732 if (isdigit(*prompt)) {
1733 ch *= 8;
1734 ch += *prompt++ - '0';
1735 }
1736 out2c(psh, ch);
1737 break;
1738 }
1739
1740 /* ignore */
1741 break;
1742 case '!':
1743 case '#':
1744 case '@':
1745 case 'A':
1746 case 'h':
1747 case 'H':
1748 case 'j':
1749 case 'l':
1750 case 't':
1751 case 'T':
1752 case 'u':
1753 case '[':
1754 if (strchr(prompt, ']')) {
1755 prompt = strchr(prompt, ']') + 1;
1756 }
1757 break;
1758 case 'D':
1759 if (*prompt == '{' && strchr(prompt, '}')) {
1760 prompt = strchr(prompt, '}') + 1;
1761 }
1762 break;
1763 }
1764
1765 }
1766 }
1767 }
1768 }
1769}
1770
1771/*
1772 * called by editline -- any expansions to the prompt
1773 * should be added here.
1774 */
1775const char *
1776getprompt(shinstance *psh, void *unused)
1777{
1778 switch (psh->whichprompt) {
1779 case 0:
1780 return "";
1781 case 1:
1782 return ps1val(psh);
1783 case 2:
1784 return ps2val(psh);
1785 default:
1786 return "<internal prompt error>";
1787 }
1788}
1789
1790static union node *copyparsetreeint(shinstance *psh, union node *src);
1791
1792/*
1793 * Helper to copyparsetreeint.
1794 */
1795static struct nodelist *
1796copynodelist(shinstance *psh, struct nodelist *src)
1797{
1798 struct nodelist *ret = NULL;
1799 if (src) {
1800 struct nodelist **ppnext = &ret;
1801 while (src) {
1802 struct nodelist *dst = pstalloclist(psh);
1803 dst->next = NULL;
1804 *ppnext = dst;
1805 ppnext = &dst->next;
1806 dst->n = copyparsetreeint(psh, src->n);
1807 src = src->next;
1808 }
1809 }
1810 return ret;
1811}
1812
1813/*
1814 * Duplicates a node tree.
1815 *
1816 * Note! This could probably be generated from nodelist.
1817 */
1818static union node *
1819copyparsetreeint(shinstance *psh, union node *src)
1820{
1821 /** @todo Try avoid recursion for one of the sub-nodes, esp. when there
1822 * is a list like 'next' one. */
1823 union node *ret;
1824 if (src) {
1825 int const type = src->type;
1826 switch (type) {
1827 case NSEMI:
1828 case NAND:
1829 case NOR:
1830 case NWHILE:
1831 case NUNTIL:
1832 ret = pstallocnode(psh, sizeof(src->nbinary));
1833 ret->nbinary.type = type;
1834 ret->nbinary.ch1 = copyparsetreeint(psh, src->nbinary.ch1);
1835 ret->nbinary.ch2 = copyparsetreeint(psh, src->nbinary.ch2);
1836 break;
1837
1838 case NCMD:
1839 ret = pstallocnode(psh, sizeof(src->ncmd));
1840 ret->ncmd.type = NCMD;
1841 ret->ncmd.backgnd = src->ncmd.backgnd;
1842 ret->ncmd.args = copyparsetreeint(psh, src->ncmd.args);
1843 ret->ncmd.redirect = copyparsetreeint(psh, src->ncmd.redirect);
1844 break;
1845
1846 case NPIPE:
1847 ret = pstallocnode(psh, sizeof(src->npipe));
1848 ret->npipe.type = NPIPE;
1849 ret->npipe.backgnd = src->ncmd.backgnd;
1850 ret->npipe.cmdlist = copynodelist(psh, src->npipe.cmdlist);
1851 break;
1852
1853 case NREDIR:
1854 case NBACKGND:
1855 case NSUBSHELL:
1856 ret = pstallocnode(psh, sizeof(src->nredir));
1857 ret->nredir.type = type;
1858 ret->nredir.n = copyparsetreeint(psh, src->nredir.n);
1859 ret->nredir.redirect = copyparsetreeint(psh, src->nredir.redirect);
1860 break;
1861
1862 case NIF:
1863 ret = pstallocnode(psh, sizeof(src->nif));
1864 ret->nif.type = NIF;
1865 ret->nif.test = copyparsetreeint(psh, src->nif.test);
1866 ret->nif.ifpart = copyparsetreeint(psh, src->nif.ifpart);
1867 ret->nif.elsepart = copyparsetreeint(psh, src->nif.elsepart);
1868 break;
1869
1870 case NFOR:
1871 ret = pstallocnode(psh, sizeof(src->nfor));
1872 ret->nfor.type = NFOR;
1873 ret->nfor.args = copyparsetreeint(psh, src->nfor.args);
1874 ret->nfor.body = copyparsetreeint(psh, src->nfor.body);
1875 ret->nfor.var = pstsavestr(psh, src->nfor.var);
1876 break;
1877
1878 case NCASE:
1879 ret = pstallocnode(psh, sizeof(src->ncase));
1880 ret->ncase.type = NCASE;
1881 ret->ncase.expr = copyparsetreeint(psh, src->ncase.expr);
1882 ret->ncase.cases = copyparsetreeint(psh, src->ncase.cases);
1883 break;
1884
1885 case NCLIST:
1886 ret = pstallocnode(psh, sizeof(src->nclist));
1887 ret->nclist.type = NCLIST;
1888 ret->nclist.next = copyparsetreeint(psh, src->nclist.next);
1889 ret->nclist.pattern = copyparsetreeint(psh, src->nclist.pattern);
1890 ret->nclist.body = copyparsetreeint(psh, src->nclist.body);
1891 break;
1892
1893 case NDEFUN:
1894 case NARG:
1895 ret = pstallocnode(psh, sizeof(src->narg));
1896 ret->narg.type = type;
1897 ret->narg.next = copyparsetreeint(psh, src->narg.next);
1898 ret->narg.text = pstsavestr(psh, src->narg.text);
1899 ret->narg.backquote = copynodelist(psh, src->narg.backquote);
1900 break;
1901
1902 case NTO:
1903 case NCLOBBER:
1904 case NFROM:
1905 case NFROMTO:
1906 case NAPPEND:
1907 ret = pstallocnode(psh, sizeof(src->nfile));
1908 ret->nfile.type = type;
1909 ret->nfile.fd = src->nfile.fd;
1910 ret->nfile.next = copyparsetreeint(psh, src->nfile.next);
1911 ret->nfile.fname = copyparsetreeint(psh, src->nfile.fname);
1912 break;
1913
1914 case NTOFD:
1915 case NFROMFD:
1916 ret = pstallocnode(psh, sizeof(src->ndup));
1917 ret->ndup.type = type;
1918 ret->ndup.fd = src->ndup.fd;
1919 ret->ndup.next = copyparsetreeint(psh, src->ndup.next);
1920 ret->ndup.dupfd = src->ndup.dupfd;
1921 ret->ndup.vname = copyparsetreeint(psh, src->ndup.vname);
1922 break;
1923
1924 case NHERE:
1925 case NXHERE:
1926 ret = pstallocnode(psh, sizeof(src->nhere));
1927 ret->nhere.type = type;
1928 ret->nhere.fd = src->nhere.fd;
1929 ret->nhere.next = copyparsetreeint(psh, src->nhere.next);
1930 ret->nhere.doc = copyparsetreeint(psh, src->nhere.doc);
1931 break;
1932
1933 case NNOT:
1934 ret = pstallocnode(psh, sizeof(src->nnot));
1935 ret->nnot.type = NNOT;
1936 ret->nnot.com = copyparsetreeint(psh, src->nnot.com);
1937 break;
1938
1939 default:
1940 error(psh, "Unknown node type: %d (node=%p)", src->type, src);
1941 return NULL;
1942 }
1943 } else {
1944 ret = NULL;
1945 }
1946 return ret;
1947}
1948
1949union node *copyparsetree(shinstance *psh, union node *src)
1950{
1951#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
1952 pstackpush(psh);
1953#endif
1954 return copyparsetreeint(psh, src);
1955}
1956
Note: See TracBrowser for help on using the repository browser.