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

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

kash: parser.c,memalloc.c/.h,expand.c: Prepared the parser for using a separate allocator.

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