parser.c revision 216404
1239922Sgonzo/*- 2239922Sgonzo * Copyright (c) 1991, 1993 3239922Sgonzo * The Regents of the University of California. All rights reserved. 4239922Sgonzo * 5239922Sgonzo * This code is derived from software contributed to Berkeley by 6239922Sgonzo * Kenneth Almquist. 7239922Sgonzo * 8239922Sgonzo * Redistribution and use in source and binary forms, with or without 9239922Sgonzo * modification, are permitted provided that the following conditions 10239922Sgonzo * are met: 11239922Sgonzo * 1. Redistributions of source code must retain the above copyright 12239922Sgonzo * notice, this list of conditions and the following disclaimer. 13239922Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 14239922Sgonzo * notice, this list of conditions and the following disclaimer in the 15239922Sgonzo * documentation and/or other materials provided with the distribution. 16239922Sgonzo * 4. Neither the name of the University nor the names of its contributors 17239922Sgonzo * may be used to endorse or promote products derived from this software 18239922Sgonzo * without specific prior written permission. 19239922Sgonzo * 20239922Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21239922Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22239922Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23239922Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24239922Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25239922Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26239922Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27239922Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28239922Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29239922Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30239922Sgonzo * SUCH DAMAGE. 31239922Sgonzo */ 32239922Sgonzo 33239922Sgonzo#ifndef lint 34239922Sgonzo#if 0 35239922Sgonzostatic char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; 36239922Sgonzo#endif 37239922Sgonzo#endif /* not lint */ 38239922Sgonzo#include <sys/cdefs.h> 39239922Sgonzo__FBSDID("$FreeBSD: head/bin/sh/parser.c 216404 2010-12-13 10:48:49Z uqs $"); 40239922Sgonzo 41239922Sgonzo#include <stdlib.h> 42239922Sgonzo#include <unistd.h> 43239922Sgonzo#include <stdio.h> 44239922Sgonzo 45239922Sgonzo#include "shell.h" 46239922Sgonzo#include "parser.h" 47239922Sgonzo#include "nodes.h" 48239922Sgonzo#include "expand.h" /* defines rmescapes() */ 49239922Sgonzo#include "syntax.h" 50239922Sgonzo#include "options.h" 51239922Sgonzo#include "input.h" 52239922Sgonzo#include "output.h" 53239922Sgonzo#include "var.h" 54239922Sgonzo#include "error.h" 55239922Sgonzo#include "memalloc.h" 56239922Sgonzo#include "mystring.h" 57239922Sgonzo#include "alias.h" 58239922Sgonzo#include "show.h" 59239922Sgonzo#include "eval.h" 60239922Sgonzo#include "exec.h" /* to check for special builtins */ 61239922Sgonzo#ifndef NO_HISTORY 62239922Sgonzo#include "myhistedit.h" 63239922Sgonzo#endif 64239922Sgonzo 65239922Sgonzo/* 66239922Sgonzo * Shell command parser. 67239922Sgonzo */ 68239922Sgonzo 69239922Sgonzo#define EOFMARKLEN 79 70239922Sgonzo#define PROMPTLEN 128 71243423Sgonzo 72243423Sgonzo/* values of checkkwd variable */ 73243423Sgonzo#define CHKALIAS 0x1 74243423Sgonzo#define CHKKWD 0x2 75243423Sgonzo#define CHKNL 0x4 76243423Sgonzo 77243423Sgonzo/* values returned by readtoken */ 78243423Sgonzo#include "token.h" 79243423Sgonzo 80243423Sgonzo 81243423Sgonzo 82243423Sgonzostruct heredoc { 83243423Sgonzo struct heredoc *next; /* next here document in list */ 84243423Sgonzo union node *here; /* redirection node */ 85243423Sgonzo char *eofmark; /* string indicating end of input */ 86243423Sgonzo int striptabs; /* if set, strip leading tabs */ 87243423Sgonzo}; 88243423Sgonzo 89243423Sgonzostruct parser_temp { 90243423Sgonzo struct parser_temp *next; 91243423Sgonzo void *data; 92243423Sgonzo}; 93243423Sgonzo 94243423Sgonzo 95243423Sgonzostatic struct heredoc *heredoclist; /* list of here documents to read */ 96243423Sgonzostatic int doprompt; /* if set, prompt the user */ 97244762Sgonzostatic int needprompt; /* true if interactive and at start of line */ 98244762Sgonzostatic int lasttoken; /* last token read */ 99244762SgonzoMKINIT int tokpushback; /* last token pushed back */ 100244762Sgonzostatic char *wordtext; /* text of last word returned by readtoken */ 101244762SgonzoMKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 102244762Sgonzostatic struct nodelist *backquotelist; 103239922Sgonzostatic union node *redirnode; 104239922Sgonzostatic struct heredoc *heredoc; 105243423Sgonzostatic int quoteflag; /* set if (part of) last token was quoted */ 106239922Sgonzostatic int startlinno; /* line # where last token started */ 107239922Sgonzostatic int funclinno; /* line # where the current function started */ 108239922Sgonzostatic struct parser_temp *parser_temp; 109239922Sgonzo 110239922Sgonzo 111239922Sgonzostatic union node *list(int, int); 112239922Sgonzostatic union node *andor(void); 113239922Sgonzostatic union node *pipeline(void); 114239922Sgonzostatic union node *command(void); 115239922Sgonzostatic union node *simplecmd(union node **, union node *); 116239922Sgonzostatic union node *makename(void); 117239922Sgonzostatic void parsefname(void); 118239922Sgonzostatic void parseheredoc(void); 119239922Sgonzostatic int peektoken(void); 120239922Sgonzostatic int readtoken(void); 121239922Sgonzostatic int xxreadtoken(void); 122239922Sgonzostatic int readtoken1(int, char const *, char *, int); 123239922Sgonzostatic int noexpand(char *); 124239922Sgonzostatic void synexpect(int) __dead2; 125239922Sgonzostatic void synerror(const char *) __dead2; 126239922Sgonzostatic void setprompt(int); 127239922Sgonzo 128239922Sgonzo 129239922Sgonzostatic void * 130239922Sgonzoparser_temp_alloc(size_t len) 131239922Sgonzo{ 132239922Sgonzo struct parser_temp *t; 133239922Sgonzo 134239922Sgonzo INTOFF; 135239922Sgonzo t = ckmalloc(sizeof(*t)); 136239922Sgonzo t->data = NULL; 137239922Sgonzo t->next = parser_temp; 138239922Sgonzo parser_temp = t; 139239922Sgonzo t->data = ckmalloc(len); 140239922Sgonzo INTON; 141239922Sgonzo return t->data; 142239922Sgonzo} 143243423Sgonzo 144239922Sgonzo 145239922Sgonzostatic void * 146239922Sgonzoparser_temp_realloc(void *ptr, size_t len) 147239922Sgonzo{ 148239922Sgonzo struct parser_temp *t; 149239922Sgonzo 150239922Sgonzo INTOFF; 151239922Sgonzo t = parser_temp; 152239922Sgonzo if (ptr != t->data) 153239922Sgonzo error("bug: parser_temp_realloc misused"); 154239922Sgonzo t->data = ckrealloc(t->data, len); 155239922Sgonzo INTON; 156239922Sgonzo return t->data; 157239922Sgonzo} 158239922Sgonzo 159239922Sgonzo 160239922Sgonzostatic void 161239922Sgonzoparser_temp_free_upto(void *ptr) 162239922Sgonzo{ 163243423Sgonzo struct parser_temp *t; 164243423Sgonzo int done = 0; 165239922Sgonzo 166239922Sgonzo INTOFF; 167239922Sgonzo while (parser_temp != NULL && !done) { 168239922Sgonzo t = parser_temp; 169239922Sgonzo parser_temp = t->next; 170239922Sgonzo done = t->data == ptr; 171239922Sgonzo ckfree(t->data); 172239922Sgonzo ckfree(t); 173243423Sgonzo } 174243423Sgonzo INTON; 175239922Sgonzo if (!done) 176243423Sgonzo error("bug: parser_temp_free_upto misused"); 177243423Sgonzo} 178243423Sgonzo 179243423Sgonzo 180243423Sgonzostatic void 181243423Sgonzoparser_temp_free_all(void) 182243423Sgonzo{ 183243423Sgonzo struct parser_temp *t; 184243423Sgonzo 185243423Sgonzo INTOFF; 186243423Sgonzo while (parser_temp != NULL) { 187243423Sgonzo t = parser_temp; 188243423Sgonzo parser_temp = t->next; 189243423Sgonzo ckfree(t->data); 190243423Sgonzo ckfree(t); 191243423Sgonzo } 192243423Sgonzo INTON; 193243423Sgonzo} 194243423Sgonzo 195243423Sgonzo 196243423Sgonzo/* 197239922Sgonzo * Read and parse a command. Returns NEOF on end of file. (NULL is a 198239922Sgonzo * valid parse tree indicating a blank line.) 199239922Sgonzo */ 200239922Sgonzo 201239922Sgonzounion node * 202239922Sgonzoparsecmd(int interact) 203239922Sgonzo{ 204239922Sgonzo int t; 205239922Sgonzo 206239922Sgonzo /* This assumes the parser is not re-entered, 207239922Sgonzo * which could happen if we add command substitution on PS1/PS2. 208239922Sgonzo */ 209239922Sgonzo parser_temp_free_all(); 210239922Sgonzo heredoclist = NULL; 211239922Sgonzo 212243423Sgonzo tokpushback = 0; 213239922Sgonzo doprompt = interact; 214239922Sgonzo if (doprompt) 215239922Sgonzo setprompt(1); 216239922Sgonzo else 217239922Sgonzo setprompt(0); 218239922Sgonzo needprompt = 0; 219239922Sgonzo t = readtoken(); 220239922Sgonzo if (t == TEOF) 221239922Sgonzo return NEOF; 222239922Sgonzo if (t == TNL) 223239922Sgonzo return NULL; 224243423Sgonzo tokpushback++; 225243423Sgonzo return list(1, 1); 226243423Sgonzo} 227243423Sgonzo 228243423Sgonzo 229243423Sgonzostatic union node * 230243423Sgonzolist(int nlflag, int erflag) 231243423Sgonzo{ 232239922Sgonzo union node *ntop, *n1, *n2, *n3; 233243423Sgonzo int tok; 234239922Sgonzo 235243423Sgonzo checkkwd = CHKNL | CHKKWD | CHKALIAS; 236243423Sgonzo if (!nlflag && !erflag && tokendlist[peektoken()]) 237239922Sgonzo return NULL; 238239922Sgonzo ntop = n1 = NULL; 239239922Sgonzo for (;;) { 240239922Sgonzo n2 = andor(); 241239922Sgonzo tok = readtoken(); 242239922Sgonzo if (tok == TBACKGND) { 243239922Sgonzo if (n2->type == NCMD || n2->type == NPIPE) { 244243423Sgonzo n2->ncmd.backgnd = 1; 245239922Sgonzo } else if (n2->type == NREDIR) { 246239922Sgonzo n2->type = NBACKGND; 247239922Sgonzo } else { 248239922Sgonzo n3 = (union node *)stalloc(sizeof (struct nredir)); 249239922Sgonzo n3->type = NBACKGND; 250239922Sgonzo n3->nredir.n = n2; 251239922Sgonzo n3->nredir.redirect = NULL; 252239922Sgonzo n2 = n3; 253239922Sgonzo } 254239922Sgonzo } 255239922Sgonzo if (ntop == NULL) 256243423Sgonzo ntop = n2; 257239922Sgonzo else if (n1 == NULL) { 258239922Sgonzo n1 = (union node *)stalloc(sizeof (struct nbinary)); 259239922Sgonzo n1->type = NSEMI; 260239922Sgonzo n1->nbinary.ch1 = ntop; 261239922Sgonzo n1->nbinary.ch2 = n2; 262239922Sgonzo ntop = n1; 263239922Sgonzo } 264239922Sgonzo else { 265239922Sgonzo n3 = (union node *)stalloc(sizeof (struct nbinary)); 266239922Sgonzo n3->type = NSEMI; 267239922Sgonzo n3->nbinary.ch1 = n1->nbinary.ch2; 268239922Sgonzo n3->nbinary.ch2 = n2; 269239922Sgonzo n1->nbinary.ch2 = n3; 270239922Sgonzo n1 = n3; 271239922Sgonzo } 272239922Sgonzo switch (tok) { 273239922Sgonzo case TBACKGND: 274239922Sgonzo case TSEMI: 275239922Sgonzo tok = readtoken(); 276239922Sgonzo /* FALLTHROUGH */ 277239922Sgonzo case TNL: 278239922Sgonzo if (tok == TNL) { 279239922Sgonzo parseheredoc(); 280239922Sgonzo if (nlflag) 281239922Sgonzo return ntop; 282239922Sgonzo } else if (tok == TEOF && nlflag) { 283239922Sgonzo parseheredoc(); 284239922Sgonzo return ntop; 285239922Sgonzo } else { 286239922Sgonzo tokpushback++; 287239922Sgonzo } 288239922Sgonzo checkkwd = CHKNL | CHKKWD | CHKALIAS; 289239922Sgonzo if (!nlflag && !erflag && tokendlist[peektoken()]) 290239922Sgonzo return ntop; 291239922Sgonzo break; 292239922Sgonzo case TEOF: 293239922Sgonzo if (heredoclist) 294239922Sgonzo parseheredoc(); 295239922Sgonzo else 296239922Sgonzo pungetc(); /* push back EOF on input */ 297239922Sgonzo return ntop; 298239922Sgonzo default: 299239922Sgonzo if (nlflag || erflag) 300239922Sgonzo synexpect(-1); 301239922Sgonzo tokpushback++; 302239922Sgonzo return ntop; 303239922Sgonzo } 304239922Sgonzo } 305239922Sgonzo} 306239922Sgonzo 307239922Sgonzo 308239922Sgonzo 309239922Sgonzostatic union node * 310239922Sgonzoandor(void) 311239922Sgonzo{ 312239922Sgonzo union node *n1, *n2, *n3; 313239922Sgonzo int t; 314239922Sgonzo 315239922Sgonzo n1 = pipeline(); 316239922Sgonzo for (;;) { 317239922Sgonzo if ((t = readtoken()) == TAND) { 318239922Sgonzo t = NAND; 319239922Sgonzo } else if (t == TOR) { 320239922Sgonzo t = NOR; 321239922Sgonzo } else { 322239922Sgonzo tokpushback++; 323239922Sgonzo return n1; 324239922Sgonzo } 325239922Sgonzo n2 = pipeline(); 326239922Sgonzo n3 = (union node *)stalloc(sizeof (struct nbinary)); 327239922Sgonzo n3->type = t; 328239922Sgonzo n3->nbinary.ch1 = n1; 329239922Sgonzo n3->nbinary.ch2 = n2; 330239922Sgonzo n1 = n3; 331239922Sgonzo } 332239922Sgonzo} 333239922Sgonzo 334239922Sgonzo 335239922Sgonzo 336239922Sgonzostatic union node * 337239922Sgonzopipeline(void) 338239922Sgonzo{ 339239922Sgonzo union node *n1, *n2, *pipenode; 340239922Sgonzo struct nodelist *lp, *prev; 341239922Sgonzo int negate, t; 342239922Sgonzo 343239922Sgonzo negate = 0; 344239922Sgonzo checkkwd = CHKNL | CHKKWD | CHKALIAS; 345239922Sgonzo TRACE(("pipeline: entered\n")); 346239922Sgonzo while (readtoken() == TNOT) 347239922Sgonzo negate = !negate; 348239922Sgonzo tokpushback++; 349239922Sgonzo n1 = command(); 350239922Sgonzo if (readtoken() == TPIPE) { 351239922Sgonzo pipenode = (union node *)stalloc(sizeof (struct npipe)); 352239922Sgonzo pipenode->type = NPIPE; 353239922Sgonzo pipenode->npipe.backgnd = 0; 354239922Sgonzo lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 355239922Sgonzo pipenode->npipe.cmdlist = lp; 356243423Sgonzo lp->n = n1; 357239922Sgonzo do { 358239922Sgonzo prev = lp; 359239922Sgonzo lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 360239922Sgonzo checkkwd = CHKNL | CHKKWD | CHKALIAS; 361239922Sgonzo t = readtoken(); 362239922Sgonzo tokpushback++; 363239922Sgonzo if (t == TNOT) 364239922Sgonzo lp->n = pipeline(); 365239922Sgonzo else 366239922Sgonzo lp->n = command(); 367239922Sgonzo prev->next = lp; 368239922Sgonzo } while (readtoken() == TPIPE); 369239922Sgonzo lp->next = NULL; 370239922Sgonzo n1 = pipenode; 371239922Sgonzo } 372239922Sgonzo tokpushback++; 373239922Sgonzo if (negate) { 374239922Sgonzo n2 = (union node *)stalloc(sizeof (struct nnot)); 375239922Sgonzo n2->type = NNOT; 376239922Sgonzo n2->nnot.com = n1; 377239922Sgonzo return n2; 378239922Sgonzo } else 379239922Sgonzo return n1; 380239922Sgonzo} 381239922Sgonzo 382239922Sgonzo 383239922Sgonzo 384239922Sgonzostatic union node * 385239922Sgonzocommand(void) 386239922Sgonzo{ 387239922Sgonzo union node *n1, *n2; 388239922Sgonzo union node *ap, **app; 389239922Sgonzo union node *cp, **cpp; 390239922Sgonzo union node *redir, **rpp; 391239922Sgonzo int t; 392239922Sgonzo 393239922Sgonzo checkkwd = CHKNL | CHKKWD | CHKALIAS; 394239922Sgonzo redir = NULL; 395239922Sgonzo n1 = NULL; 396239922Sgonzo rpp = &redir; 397239922Sgonzo 398239922Sgonzo /* Check for redirection which may precede command */ 399239922Sgonzo while (readtoken() == TREDIR) { 400239922Sgonzo *rpp = n2 = redirnode; 401239922Sgonzo rpp = &n2->nfile.next; 402239922Sgonzo parsefname(); 403239922Sgonzo } 404239922Sgonzo tokpushback++; 405239922Sgonzo 406239922Sgonzo switch (readtoken()) { 407239922Sgonzo case TIF: 408239922Sgonzo n1 = (union node *)stalloc(sizeof (struct nif)); 409239922Sgonzo n1->type = NIF; 410239922Sgonzo if ((n1->nif.test = list(0, 0)) == NULL) 411239922Sgonzo synexpect(-1); 412239922Sgonzo if (readtoken() != TTHEN) 413239922Sgonzo synexpect(TTHEN); 414239922Sgonzo n1->nif.ifpart = list(0, 0); 415239922Sgonzo n2 = n1; 416239922Sgonzo while (readtoken() == TELIF) { 417239922Sgonzo n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 418239922Sgonzo n2 = n2->nif.elsepart; 419239922Sgonzo n2->type = NIF; 420239922Sgonzo if ((n2->nif.test = list(0, 0)) == NULL) 421239922Sgonzo synexpect(-1); 422239922Sgonzo if (readtoken() != TTHEN) 423239922Sgonzo synexpect(TTHEN); 424239922Sgonzo n2->nif.ifpart = list(0, 0); 425239922Sgonzo } 426239922Sgonzo if (lasttoken == TELSE) 427239922Sgonzo n2->nif.elsepart = list(0, 0); 428239922Sgonzo else { 429244762Sgonzo n2->nif.elsepart = NULL; 430244762Sgonzo tokpushback++; 431244762Sgonzo } 432244762Sgonzo if (readtoken() != TFI) 433244762Sgonzo synexpect(TFI); 434244762Sgonzo checkkwd = CHKKWD | CHKALIAS; 435244762Sgonzo break; 436244762Sgonzo case TWHILE: 437244762Sgonzo case TUNTIL: { 438244762Sgonzo int got; 439244762Sgonzo n1 = (union node *)stalloc(sizeof (struct nbinary)); 440244762Sgonzo n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 441244762Sgonzo if ((n1->nbinary.ch1 = list(0, 0)) == NULL) 442244762Sgonzo synexpect(-1); 443244762Sgonzo if ((got=readtoken()) != TDO) { 444244762SgonzoTRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 445244762Sgonzo synexpect(TDO); 446244762Sgonzo } 447244762Sgonzo n1->nbinary.ch2 = list(0, 0); 448244762Sgonzo if (readtoken() != TDONE) 449244762Sgonzo synexpect(TDONE); 450244762Sgonzo checkkwd = CHKKWD | CHKALIAS; 451244762Sgonzo break; 452244762Sgonzo } 453244762Sgonzo case TFOR: 454244762Sgonzo if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 455244762Sgonzo synerror("Bad for loop variable"); 456239922Sgonzo n1 = (union node *)stalloc(sizeof (struct nfor)); 457239922Sgonzo n1->type = NFOR; 458244762Sgonzo n1->nfor.var = wordtext; 459244762Sgonzo while (readtoken() == TNL) 460244762Sgonzo ; 461244762Sgonzo if (lasttoken == TWORD && ! quoteflag && equal(wordtext, "in")) { 462244762Sgonzo app = ≈ 463244762Sgonzo while (readtoken() == TWORD) { 464244762Sgonzo n2 = (union node *)stalloc(sizeof (struct narg)); 465244762Sgonzo n2->type = NARG; 466244762Sgonzo n2->narg.text = wordtext; 467244762Sgonzo n2->narg.backquote = backquotelist; 468244762Sgonzo *app = n2; 469244762Sgonzo app = &n2->narg.next; 470244762Sgonzo } 471244762Sgonzo *app = NULL; 472244762Sgonzo n1->nfor.args = ap; 473244762Sgonzo if (lasttoken != TNL && lasttoken != TSEMI) 474244762Sgonzo synexpect(-1); 475244762Sgonzo } else { 476244762Sgonzo static char argvars[5] = { 477244762Sgonzo CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 478244762Sgonzo }; 479244762Sgonzo n2 = (union node *)stalloc(sizeof (struct narg)); 480244762Sgonzo n2->type = NARG; 481244762Sgonzo n2->narg.text = argvars; 482244762Sgonzo n2->narg.backquote = NULL; 483244762Sgonzo n2->narg.next = NULL; 484244762Sgonzo n1->nfor.args = n2; 485244762Sgonzo /* 486244762Sgonzo * Newline or semicolon here is optional (but note 487244762Sgonzo * that the original Bourne shell only allowed NL). 488244762Sgonzo */ 489244762Sgonzo if (lasttoken != TNL && lasttoken != TSEMI) 490244762Sgonzo tokpushback++; 491244762Sgonzo } 492244762Sgonzo checkkwd = CHKNL | CHKKWD | CHKALIAS; 493244762Sgonzo if ((t = readtoken()) == TDO) 494244762Sgonzo t = TDONE; 495244762Sgonzo else if (t == TBEGIN) 496244762Sgonzo t = TEND; 497244762Sgonzo else 498244762Sgonzo synexpect(-1); 499244762Sgonzo n1->nfor.body = list(0, 0); 500244762Sgonzo if (readtoken() != t) 501244762Sgonzo synexpect(t); 502244762Sgonzo checkkwd = CHKKWD | CHKALIAS; 503244762Sgonzo break; 504244762Sgonzo case TCASE: 505244762Sgonzo n1 = (union node *)stalloc(sizeof (struct ncase)); 506244762Sgonzo n1->type = NCASE; 507244762Sgonzo if (readtoken() != TWORD) 508244762Sgonzo synexpect(TWORD); 509244762Sgonzo n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 510244762Sgonzo n2->type = NARG; 511244762Sgonzo n2->narg.text = wordtext; 512244762Sgonzo n2->narg.backquote = backquotelist; 513244762Sgonzo n2->narg.next = NULL; 514244762Sgonzo while (readtoken() == TNL); 515244762Sgonzo if (lasttoken != TWORD || ! equal(wordtext, "in")) 516244762Sgonzo synerror("expecting \"in\""); 517244762Sgonzo cpp = &n1->ncase.cases; 518244762Sgonzo checkkwd = CHKNL | CHKKWD, readtoken(); 519244762Sgonzo while (lasttoken != TESAC) { 520244762Sgonzo *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 521244762Sgonzo cp->type = NCLIST; 522244762Sgonzo app = &cp->nclist.pattern; 523244762Sgonzo if (lasttoken == TLP) 524244762Sgonzo readtoken(); 525244762Sgonzo for (;;) { 526244762Sgonzo *app = ap = (union node *)stalloc(sizeof (struct narg)); 527244762Sgonzo ap->type = NARG; 528244762Sgonzo ap->narg.text = wordtext; 529244762Sgonzo ap->narg.backquote = backquotelist; 530244762Sgonzo checkkwd = CHKNL | CHKKWD; 531244762Sgonzo if (readtoken() != TPIPE) 532244762Sgonzo break; 533244762Sgonzo app = &ap->narg.next; 534244762Sgonzo readtoken(); 535244762Sgonzo } 536244762Sgonzo ap->narg.next = NULL; 537244762Sgonzo if (lasttoken != TRP) 538244762Sgonzo synexpect(TRP); 539244762Sgonzo cp->nclist.body = list(0, 0); 540244762Sgonzo 541244762Sgonzo checkkwd = CHKNL | CHKKWD | CHKALIAS; 542244762Sgonzo if ((t = readtoken()) != TESAC) { 543244762Sgonzo if (t != TENDCASE) 544244762Sgonzo synexpect(TENDCASE); 545244762Sgonzo else 546244762Sgonzo checkkwd = CHKNL | CHKKWD, readtoken(); 547244762Sgonzo } 548244762Sgonzo cpp = &cp->nclist.next; 549244762Sgonzo } 550244762Sgonzo *cpp = NULL; 551244762Sgonzo checkkwd = CHKKWD | CHKALIAS; 552244762Sgonzo break; 553244762Sgonzo case TLP: 554244762Sgonzo n1 = (union node *)stalloc(sizeof (struct nredir)); 555244762Sgonzo n1->type = NSUBSHELL; 556244762Sgonzo n1->nredir.n = list(0, 0); 557244762Sgonzo n1->nredir.redirect = NULL; 558244762Sgonzo if (readtoken() != TRP) 559244762Sgonzo synexpect(TRP); 560244762Sgonzo checkkwd = CHKKWD | CHKALIAS; 561244762Sgonzo break; 562244762Sgonzo case TBEGIN: 563244762Sgonzo n1 = list(0, 0); 564239922Sgonzo if (readtoken() != TEND) 565239922Sgonzo synexpect(TEND); 566239922Sgonzo checkkwd = CHKKWD | CHKALIAS; 567243423Sgonzo break; 568243423Sgonzo /* Handle an empty command like other simple commands. */ 569243423Sgonzo case TBACKGND: 570243423Sgonzo case TSEMI: 571243423Sgonzo case TAND: 572243423Sgonzo case TOR: 573243423Sgonzo /* 574243423Sgonzo * An empty command before a ; doesn't make much sense, and 575243423Sgonzo * should certainly be disallowed in the case of `if ;'. 576243423Sgonzo */ 577243423Sgonzo if (!redir) 578243423Sgonzo synexpect(-1); 579243423Sgonzo case TNL: 580243423Sgonzo case TEOF: 581243423Sgonzo case TWORD: 582243423Sgonzo case TRP: 583239922Sgonzo tokpushback++; 584239922Sgonzo n1 = simplecmd(rpp, redir); 585239922Sgonzo return n1; 586243423Sgonzo default: 587239922Sgonzo synexpect(-1); 588243423Sgonzo } 589243423Sgonzo 590243423Sgonzo /* Now check for redirection which may follow command */ 591239922Sgonzo while (readtoken() == TREDIR) { 592243423Sgonzo *rpp = n2 = redirnode; 593243423Sgonzo rpp = &n2->nfile.next; 594239922Sgonzo parsefname(); 595243423Sgonzo } 596243423Sgonzo tokpushback++; 597239922Sgonzo *rpp = NULL; 598243423Sgonzo if (redir) { 599243423Sgonzo if (n1->type != NSUBSHELL) { 600243423Sgonzo n2 = (union node *)stalloc(sizeof (struct nredir)); 601243423Sgonzo n2->type = NREDIR; 602243423Sgonzo n2->nredir.n = n1; 603243423Sgonzo n1 = n2; 604243423Sgonzo } 605243423Sgonzo n1->nredir.redirect = redir; 606243423Sgonzo } 607243423Sgonzo 608243423Sgonzo return n1; 609239922Sgonzo} 610243423Sgonzo 611243423Sgonzo 612243423Sgonzostatic union node * 613243423Sgonzosimplecmd(union node **rpp, union node *redir) 614239922Sgonzo{ 615243423Sgonzo union node *args, **app; 616243423Sgonzo union node **orig_rpp = rpp; 617243423Sgonzo union node *n = NULL; 618243423Sgonzo int special; 619243423Sgonzo 620243423Sgonzo /* If we don't have any redirections already, then we must reset */ 621243423Sgonzo /* rpp to be the address of the local redir variable. */ 622243423Sgonzo if (redir == 0) 623243423Sgonzo rpp = &redir; 624239922Sgonzo 625239922Sgonzo args = NULL; 626239922Sgonzo app = &args; 627239922Sgonzo /* 628239922Sgonzo * We save the incoming value, because we need this for shell 629239922Sgonzo * functions. There can not be a redirect or an argument between 630239922Sgonzo * the function name and the open parenthesis. 631239922Sgonzo */ 632239922Sgonzo orig_rpp = rpp; 633239922Sgonzo 634239922Sgonzo for (;;) { 635239922Sgonzo if (readtoken() == TWORD) { 636239922Sgonzo n = (union node *)stalloc(sizeof (struct narg)); 637239922Sgonzo n->type = NARG; 638239922Sgonzo n->narg.text = wordtext; 639239922Sgonzo n->narg.backquote = backquotelist; 640239922Sgonzo *app = n; 641239922Sgonzo app = &n->narg.next; 642239922Sgonzo } else if (lasttoken == TREDIR) { 643239922Sgonzo *rpp = n = redirnode; 644239922Sgonzo rpp = &n->nfile.next; 645239922Sgonzo parsefname(); /* read name of redirection file */ 646239922Sgonzo } else if (lasttoken == TLP && app == &args->narg.next 647239922Sgonzo && rpp == orig_rpp) { 648243423Sgonzo /* We have a function */ 649239922Sgonzo if (readtoken() != TRP) 650239922Sgonzo synexpect(TRP); 651239922Sgonzo funclinno = plinno; 652239922Sgonzo /* 653239922Sgonzo * - Require plain text. 654239922Sgonzo * - Functions with '/' cannot be called. 655239922Sgonzo * - Reject name=(). 656239922Sgonzo * - Reject ksh extended glob patterns. 657239922Sgonzo */ 658239922Sgonzo if (!noexpand(n->narg.text) || quoteflag || 659239922Sgonzo strchr(n->narg.text, '/') || 660239922Sgonzo strchr("!%*+-=?@}~", 661239922Sgonzo n->narg.text[strlen(n->narg.text) - 1])) 662239922Sgonzo synerror("Bad function name"); 663243423Sgonzo rmescapes(n->narg.text); 664239922Sgonzo if (find_builtin(n->narg.text, &special) >= 0 && 665239922Sgonzo special) 666239922Sgonzo synerror("Cannot override a special builtin with a function"); 667239922Sgonzo n->type = NDEFUN; 668239922Sgonzo n->narg.next = command(); 669239922Sgonzo funclinno = 0; 670239922Sgonzo return n; 671239922Sgonzo } else { 672239922Sgonzo tokpushback++; 673239922Sgonzo break; 674239922Sgonzo } 675239922Sgonzo } 676239922Sgonzo *app = NULL; 677239922Sgonzo *rpp = NULL; 678239922Sgonzo n = (union node *)stalloc(sizeof (struct ncmd)); 679239922Sgonzo n->type = NCMD; 680239922Sgonzo n->ncmd.backgnd = 0; 681239922Sgonzo n->ncmd.args = args; 682239922Sgonzo n->ncmd.redirect = redir; 683239922Sgonzo return n; 684239922Sgonzo} 685239922Sgonzo 686239922Sgonzostatic union node * 687239922Sgonzomakename(void) 688239922Sgonzo{ 689239922Sgonzo union node *n; 690239922Sgonzo 691239922Sgonzo n = (union node *)stalloc(sizeof (struct narg)); 692239922Sgonzo n->type = NARG; 693239922Sgonzo n->narg.next = NULL; 694239922Sgonzo n->narg.text = wordtext; 695239922Sgonzo n->narg.backquote = backquotelist; 696239922Sgonzo return n; 697239922Sgonzo} 698239922Sgonzo 699239922Sgonzovoid 700239922Sgonzofixredir(union node *n, const char *text, int err) 701239922Sgonzo{ 702239922Sgonzo TRACE(("Fix redir %s %d\n", text, err)); 703239922Sgonzo if (!err) 704239922Sgonzo n->ndup.vname = NULL; 705239922Sgonzo 706239922Sgonzo if (is_digit(text[0]) && text[1] == '\0') 707239922Sgonzo n->ndup.dupfd = digit_val(text[0]); 708239922Sgonzo else if (text[0] == '-' && text[1] == '\0') 709239922Sgonzo n->ndup.dupfd = -1; 710239922Sgonzo else { 711239922Sgonzo 712239922Sgonzo if (err) 713239922Sgonzo synerror("Bad fd number"); 714239922Sgonzo else 715239922Sgonzo n->ndup.vname = makename(); 716239922Sgonzo } 717239922Sgonzo} 718239922Sgonzo 719239922Sgonzo 720239922Sgonzostatic void 721239922Sgonzoparsefname(void) 722239922Sgonzo{ 723239922Sgonzo union node *n = redirnode; 724239922Sgonzo 725239922Sgonzo if (readtoken() != TWORD) 726239922Sgonzo synexpect(-1); 727239922Sgonzo if (n->type == NHERE) { 728239922Sgonzo struct heredoc *here = heredoc; 729239922Sgonzo struct heredoc *p; 730239922Sgonzo int i; 731239922Sgonzo 732239922Sgonzo if (quoteflag == 0) 733239922Sgonzo n->type = NXHERE; 734239922Sgonzo TRACE(("Here document %d\n", n->type)); 735239922Sgonzo if (here->striptabs) { 736239922Sgonzo while (*wordtext == '\t') 737239922Sgonzo wordtext++; 738239922Sgonzo } 739239922Sgonzo if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 740239922Sgonzo synerror("Illegal eof marker for << redirection"); 741239922Sgonzo rmescapes(wordtext); 742239922Sgonzo here->eofmark = wordtext; 743239922Sgonzo here->next = NULL; 744239922Sgonzo if (heredoclist == NULL) 745239922Sgonzo heredoclist = here; 746239922Sgonzo else { 747239922Sgonzo for (p = heredoclist ; p->next ; p = p->next); 748239922Sgonzo p->next = here; 749239922Sgonzo } 750239922Sgonzo } else if (n->type == NTOFD || n->type == NFROMFD) { 751239922Sgonzo fixredir(n, wordtext, 0); 752239922Sgonzo } else { 753239922Sgonzo n->nfile.fname = makename(); 754239922Sgonzo } 755239922Sgonzo} 756239922Sgonzo 757239922Sgonzo 758239922Sgonzo/* 759239922Sgonzo * Input any here documents. 760239922Sgonzo */ 761239922Sgonzo 762239922Sgonzostatic void 763239922Sgonzoparseheredoc(void) 764239922Sgonzo{ 765239922Sgonzo struct heredoc *here; 766239922Sgonzo union node *n; 767239922Sgonzo 768239922Sgonzo while (heredoclist) { 769239922Sgonzo here = heredoclist; 770239922Sgonzo heredoclist = here->next; 771239922Sgonzo if (needprompt) { 772239922Sgonzo setprompt(2); 773239922Sgonzo needprompt = 0; 774239922Sgonzo } 775239922Sgonzo readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 776243423Sgonzo here->eofmark, here->striptabs); 777243423Sgonzo n = (union node *)stalloc(sizeof (struct narg)); 778243423Sgonzo n->narg.type = NARG; 779243423Sgonzo n->narg.next = NULL; 780243423Sgonzo n->narg.text = wordtext; 781243423Sgonzo n->narg.backquote = backquotelist; 782239922Sgonzo here->here->nhere.doc = n; 783239922Sgonzo } 784239922Sgonzo} 785239922Sgonzo 786239922Sgonzostatic int 787239922Sgonzopeektoken(void) 788239922Sgonzo{ 789239922Sgonzo int t; 790239922Sgonzo 791239922Sgonzo t = readtoken(); 792239922Sgonzo tokpushback++; 793239922Sgonzo return (t); 794239922Sgonzo} 795239922Sgonzo 796239922Sgonzostatic int 797239922Sgonzoreadtoken(void) 798239922Sgonzo{ 799239922Sgonzo int t; 800239922Sgonzo struct alias *ap; 801239922Sgonzo#ifdef DEBUG 802239922Sgonzo int alreadyseen = tokpushback; 803239922Sgonzo#endif 804239922Sgonzo 805239922Sgonzo top: 806239922Sgonzo t = xxreadtoken(); 807239922Sgonzo 808239922Sgonzo /* 809239922Sgonzo * eat newlines 810239922Sgonzo */ 811239922Sgonzo if (checkkwd & CHKNL) { 812239922Sgonzo while (t == TNL) { 813239922Sgonzo parseheredoc(); 814239922Sgonzo t = xxreadtoken(); 815239922Sgonzo } 816239922Sgonzo } 817239922Sgonzo 818239922Sgonzo /* 819239922Sgonzo * check for keywords and aliases 820239922Sgonzo */ 821239922Sgonzo if (t == TWORD && !quoteflag) 822239922Sgonzo { 823239922Sgonzo const char * const *pp; 824239922Sgonzo 825239922Sgonzo if (checkkwd & CHKKWD) 826239922Sgonzo for (pp = parsekwd; *pp; pp++) { 827239922Sgonzo if (**pp == *wordtext && equal(*pp, wordtext)) 828239922Sgonzo { 829239922Sgonzo lasttoken = t = pp - parsekwd + KWDOFFSET; 830239922Sgonzo TRACE(("keyword %s recognized\n", tokname[t])); 831239922Sgonzo goto out; 832239922Sgonzo } 833239922Sgonzo } 834239922Sgonzo if (checkkwd & CHKALIAS && 835239922Sgonzo (ap = lookupalias(wordtext, 1)) != NULL) { 836239922Sgonzo pushstring(ap->val, strlen(ap->val), ap); 837239922Sgonzo goto top; 838239922Sgonzo } 839239922Sgonzo } 840239922Sgonzoout: 841239922Sgonzo if (t != TNOT) 842239922Sgonzo checkkwd = 0; 843239922Sgonzo 844239922Sgonzo#ifdef DEBUG 845239922Sgonzo if (!alreadyseen) 846239922Sgonzo TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 847239922Sgonzo else 848239922Sgonzo TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 849239922Sgonzo#endif 850239922Sgonzo return (t); 851239922Sgonzo} 852239922Sgonzo 853239922Sgonzo 854239922Sgonzo/* 855239922Sgonzo * Read the next input token. 856239922Sgonzo * If the token is a word, we set backquotelist to the list of cmds in 857239922Sgonzo * backquotes. We set quoteflag to true if any part of the word was 858239922Sgonzo * quoted. 859239922Sgonzo * If the token is TREDIR, then we set redirnode to a structure containing 860239922Sgonzo * the redirection. 861239922Sgonzo * In all cases, the variable startlinno is set to the number of the line 862239922Sgonzo * on which the token starts. 863239922Sgonzo * 864239922Sgonzo * [Change comment: here documents and internal procedures] 865239922Sgonzo * [Readtoken shouldn't have any arguments. Perhaps we should make the 866239922Sgonzo * word parsing code into a separate routine. In this case, readtoken 867239922Sgonzo * doesn't need to have any internal procedures, but parseword does. 868239922Sgonzo * We could also make parseoperator in essence the main routine, and 869239922Sgonzo * have parseword (readtoken1?) handle both words and redirection.] 870239922Sgonzo */ 871239922Sgonzo 872239922Sgonzo#define RETURN(token) return lasttoken = token 873239922Sgonzo 874239922Sgonzostatic int 875239922Sgonzoxxreadtoken(void) 876239922Sgonzo{ 877239922Sgonzo int c; 878239922Sgonzo 879243423Sgonzo if (tokpushback) { 880239922Sgonzo tokpushback = 0; 881239922Sgonzo return lasttoken; 882239922Sgonzo } 883239922Sgonzo if (needprompt) { 884239922Sgonzo setprompt(2); 885239922Sgonzo needprompt = 0; 886239922Sgonzo } 887239922Sgonzo startlinno = plinno; 888239922Sgonzo for (;;) { /* until token or start of word found */ 889239922Sgonzo c = pgetc_macro(); 890239922Sgonzo switch (c) { 891243666Sgonzo case ' ': case '\t': 892239922Sgonzo continue; 893243423Sgonzo case '#': 894245071Sgonzo while ((c = pgetc()) != '\n' && c != PEOF); 895239922Sgonzo pungetc(); 896239922Sgonzo continue; 897239922Sgonzo case '\\': 898239922Sgonzo if (pgetc() == '\n') { 899239922Sgonzo startlinno = ++plinno; 900239922Sgonzo if (doprompt) 901239922Sgonzo setprompt(2); 902239922Sgonzo else 903243423Sgonzo setprompt(0); 904243423Sgonzo continue; 905243423Sgonzo } 906243423Sgonzo pungetc(); 907243423Sgonzo goto breakloop; 908243423Sgonzo case '\n': 909243423Sgonzo plinno++; 910243423Sgonzo needprompt = doprompt; 911243423Sgonzo RETURN(TNL); 912243423Sgonzo case PEOF: 913243423Sgonzo RETURN(TEOF); 914243423Sgonzo case '&': 915243423Sgonzo if (pgetc() == '&') 916243687Sgonzo RETURN(TAND); 917243687Sgonzo pungetc(); 918243423Sgonzo RETURN(TBACKGND); 919243687Sgonzo case '|': 920243687Sgonzo if (pgetc() == '|') 921243423Sgonzo RETURN(TOR); 922243423Sgonzo pungetc(); 923243423Sgonzo RETURN(TPIPE); 924243423Sgonzo case ';': 925239922Sgonzo if (pgetc() == ';') 926239922Sgonzo RETURN(TENDCASE); 927239922Sgonzo pungetc(); 928239922Sgonzo RETURN(TSEMI); 929239922Sgonzo case '(': 930239922Sgonzo RETURN(TLP); 931239922Sgonzo case ')': 932239922Sgonzo RETURN(TRP); 933239922Sgonzo default: 934239922Sgonzo goto breakloop; 935239922Sgonzo } 936239922Sgonzo } 937239922Sgonzobreakloop: 938239922Sgonzo return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 939239922Sgonzo#undef RETURN 940239922Sgonzo} 941239922Sgonzo 942239922Sgonzo 943239922Sgonzo#define MAXNEST_static 8 944239922Sgonzostruct tokenstate 945239922Sgonzo{ 946239922Sgonzo const char *syntax; /* *SYNTAX */ 947239922Sgonzo int parenlevel; /* levels of parentheses in arithmetic */ 948239922Sgonzo enum tokenstate_category 949239922Sgonzo { 950239922Sgonzo TSTATE_TOP, 951239922Sgonzo TSTATE_VAR_OLD, /* ${var+-=?}, inherits dquotes */ 952239922Sgonzo TSTATE_VAR_NEW, /* other ${var...}, own dquote state */ 953239922Sgonzo TSTATE_ARITH 954239922Sgonzo } category; 955239922Sgonzo}; 956239922Sgonzo 957239922Sgonzo 958239922Sgonzo/* 959239922Sgonzo * Called to parse command substitutions. 960239922Sgonzo */ 961239922Sgonzo 962239922Sgonzostatic char * 963239922Sgonzoparsebackq(char *out, struct nodelist **pbqlist, 964239922Sgonzo int oldstyle, int dblquote, int quoted) 965239922Sgonzo{ 966239922Sgonzo struct nodelist **nlpp; 967239922Sgonzo union node *n; 968239922Sgonzo char *volatile str; 969239922Sgonzo struct jmploc jmploc; 970 struct jmploc *const savehandler = handler; 971 int savelen; 972 int saveprompt; 973 const int bq_startlinno = plinno; 974 char *volatile ostr = NULL; 975 struct parsefile *const savetopfile = getcurrentfile(); 976 struct heredoc *const saveheredoclist = heredoclist; 977 struct heredoc *here; 978 979 str = NULL; 980 if (setjmp(jmploc.loc)) { 981 popfilesupto(savetopfile); 982 if (str) 983 ckfree(str); 984 if (ostr) 985 ckfree(ostr); 986 heredoclist = saveheredoclist; 987 handler = savehandler; 988 if (exception == EXERROR) { 989 startlinno = bq_startlinno; 990 synerror("Error in command substitution"); 991 } 992 longjmp(handler->loc, 1); 993 } 994 INTOFF; 995 savelen = out - stackblock(); 996 if (savelen > 0) { 997 str = ckmalloc(savelen); 998 memcpy(str, stackblock(), savelen); 999 } 1000 handler = &jmploc; 1001 heredoclist = NULL; 1002 INTON; 1003 if (oldstyle) { 1004 /* We must read until the closing backquote, giving special 1005 treatment to some slashes, and then push the string and 1006 reread it as input, interpreting it normally. */ 1007 char *oout; 1008 int c; 1009 int olen; 1010 1011 1012 STARTSTACKSTR(oout); 1013 for (;;) { 1014 if (needprompt) { 1015 setprompt(2); 1016 needprompt = 0; 1017 } 1018 CHECKSTRSPACE(2, oout); 1019 switch (c = pgetc()) { 1020 case '`': 1021 goto done; 1022 1023 case '\\': 1024 if ((c = pgetc()) == '\n') { 1025 plinno++; 1026 if (doprompt) 1027 setprompt(2); 1028 else 1029 setprompt(0); 1030 /* 1031 * If eating a newline, avoid putting 1032 * the newline into the new character 1033 * stream (via the USTPUTC after the 1034 * switch). 1035 */ 1036 continue; 1037 } 1038 if (c != '\\' && c != '`' && c != '$' 1039 && (!dblquote || c != '"')) 1040 USTPUTC('\\', oout); 1041 break; 1042 1043 case '\n': 1044 plinno++; 1045 needprompt = doprompt; 1046 break; 1047 1048 case PEOF: 1049 startlinno = plinno; 1050 synerror("EOF in backquote substitution"); 1051 break; 1052 1053 default: 1054 break; 1055 } 1056 USTPUTC(c, oout); 1057 } 1058done: 1059 USTPUTC('\0', oout); 1060 olen = oout - stackblock(); 1061 INTOFF; 1062 ostr = ckmalloc(olen); 1063 memcpy(ostr, stackblock(), olen); 1064 setinputstring(ostr, 1); 1065 INTON; 1066 } 1067 nlpp = pbqlist; 1068 while (*nlpp) 1069 nlpp = &(*nlpp)->next; 1070 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 1071 (*nlpp)->next = NULL; 1072 1073 if (oldstyle) { 1074 saveprompt = doprompt; 1075 doprompt = 0; 1076 } 1077 1078 n = list(0, oldstyle); 1079 1080 if (oldstyle) 1081 doprompt = saveprompt; 1082 else { 1083 if (readtoken() != TRP) 1084 synexpect(TRP); 1085 } 1086 1087 (*nlpp)->n = n; 1088 if (oldstyle) { 1089 /* 1090 * Start reading from old file again, ignoring any pushed back 1091 * tokens left from the backquote parsing 1092 */ 1093 popfile(); 1094 tokpushback = 0; 1095 } 1096 while (stackblocksize() <= savelen) 1097 growstackblock(); 1098 STARTSTACKSTR(out); 1099 INTOFF; 1100 if (str) { 1101 memcpy(out, str, savelen); 1102 STADJUST(savelen, out); 1103 ckfree(str); 1104 str = NULL; 1105 } 1106 if (ostr) { 1107 ckfree(ostr); 1108 ostr = NULL; 1109 } 1110 here = saveheredoclist; 1111 if (here != NULL) { 1112 while (here->next != NULL) 1113 here = here->next; 1114 here->next = heredoclist; 1115 heredoclist = saveheredoclist; 1116 } 1117 handler = savehandler; 1118 INTON; 1119 if (quoted) 1120 USTPUTC(CTLBACKQ | CTLQUOTE, out); 1121 else 1122 USTPUTC(CTLBACKQ, out); 1123 return out; 1124} 1125 1126 1127/* 1128 * If eofmark is NULL, read a word or a redirection symbol. If eofmark 1129 * is not NULL, read a here document. In the latter case, eofmark is the 1130 * word which marks the end of the document and striptabs is true if 1131 * leading tabs should be stripped from the document. The argument firstc 1132 * is the first character of the input token or document. 1133 * 1134 * Because C does not have internal subroutines, I have simulated them 1135 * using goto's to implement the subroutine linkage. The following macros 1136 * will run code that appears at the end of readtoken1. 1137 */ 1138 1139#define CHECKEND() {goto checkend; checkend_return:;} 1140#define PARSEREDIR() {goto parseredir; parseredir_return:;} 1141#define PARSESUB() {goto parsesub; parsesub_return:;} 1142#define PARSEARITH() {goto parsearith; parsearith_return:;} 1143 1144static int 1145readtoken1(int firstc, char const *initialsyntax, char *eofmark, int striptabs) 1146{ 1147 int c = firstc; 1148 char *out; 1149 int len; 1150 char line[EOFMARKLEN + 1]; 1151 struct nodelist *bqlist; 1152 int quotef; 1153 int newvarnest; 1154 int level; 1155 int synentry; 1156 struct tokenstate state_static[MAXNEST_static]; 1157 int maxnest = MAXNEST_static; 1158 struct tokenstate *state = state_static; 1159 1160 startlinno = plinno; 1161 quotef = 0; 1162 bqlist = NULL; 1163 newvarnest = 0; 1164 level = 0; 1165 state[level].syntax = initialsyntax; 1166 state[level].parenlevel = 0; 1167 state[level].category = TSTATE_TOP; 1168 1169 STARTSTACKSTR(out); 1170 loop: { /* for each line, until end of word */ 1171 CHECKEND(); /* set c to PEOF if at end of here document */ 1172 for (;;) { /* until end of line or end of word */ 1173 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 1174 1175 synentry = state[level].syntax[c]; 1176 1177 switch(synentry) { 1178 case CNL: /* '\n' */ 1179 if (state[level].syntax == BASESYNTAX) 1180 goto endword; /* exit outer loop */ 1181 USTPUTC(c, out); 1182 plinno++; 1183 if (doprompt) 1184 setprompt(2); 1185 else 1186 setprompt(0); 1187 c = pgetc(); 1188 goto loop; /* continue outer loop */ 1189 case CWORD: 1190 USTPUTC(c, out); 1191 break; 1192 case CCTL: 1193 if (eofmark == NULL || initialsyntax != SQSYNTAX) 1194 USTPUTC(CTLESC, out); 1195 USTPUTC(c, out); 1196 break; 1197 case CBACK: /* backslash */ 1198 c = pgetc(); 1199 if (c == PEOF) { 1200 USTPUTC('\\', out); 1201 pungetc(); 1202 } else if (c == '\n') { 1203 plinno++; 1204 if (doprompt) 1205 setprompt(2); 1206 else 1207 setprompt(0); 1208 } else { 1209 if (state[level].syntax == DQSYNTAX && 1210 c != '\\' && c != '`' && c != '$' && 1211 (c != '"' || (eofmark != NULL && 1212 newvarnest == 0)) && 1213 (c != '}' || state[level].category != TSTATE_VAR_OLD)) 1214 USTPUTC('\\', out); 1215 if ((eofmark == NULL || 1216 newvarnest > 0) && 1217 state[level].syntax == BASESYNTAX) 1218 USTPUTC(CTLQUOTEMARK, out); 1219 if (SQSYNTAX[c] == CCTL) 1220 USTPUTC(CTLESC, out); 1221 USTPUTC(c, out); 1222 if ((eofmark == NULL || 1223 newvarnest > 0) && 1224 state[level].syntax == BASESYNTAX && 1225 state[level].category == TSTATE_VAR_OLD) 1226 USTPUTC(CTLQUOTEEND, out); 1227 quotef++; 1228 } 1229 break; 1230 case CSQUOTE: 1231 USTPUTC(CTLQUOTEMARK, out); 1232 state[level].syntax = SQSYNTAX; 1233 break; 1234 case CDQUOTE: 1235 USTPUTC(CTLQUOTEMARK, out); 1236 state[level].syntax = DQSYNTAX; 1237 break; 1238 case CENDQUOTE: 1239 if (eofmark != NULL && newvarnest == 0) 1240 USTPUTC(c, out); 1241 else { 1242 if (state[level].category == TSTATE_VAR_OLD) 1243 USTPUTC(CTLQUOTEEND, out); 1244 state[level].syntax = BASESYNTAX; 1245 quotef++; 1246 } 1247 break; 1248 case CVAR: /* '$' */ 1249 PARSESUB(); /* parse substitution */ 1250 break; 1251 case CENDVAR: /* '}' */ 1252 if (level > 0 && 1253 ((state[level].category == TSTATE_VAR_OLD && 1254 state[level].syntax == 1255 state[level - 1].syntax) || 1256 (state[level].category == TSTATE_VAR_NEW && 1257 state[level].syntax == BASESYNTAX))) { 1258 if (state[level].category == TSTATE_VAR_NEW) 1259 newvarnest--; 1260 level--; 1261 USTPUTC(CTLENDVAR, out); 1262 } else { 1263 USTPUTC(c, out); 1264 } 1265 break; 1266 case CLP: /* '(' in arithmetic */ 1267 state[level].parenlevel++; 1268 USTPUTC(c, out); 1269 break; 1270 case CRP: /* ')' in arithmetic */ 1271 if (state[level].parenlevel > 0) { 1272 USTPUTC(c, out); 1273 --state[level].parenlevel; 1274 } else { 1275 if (pgetc() == ')') { 1276 if (level > 0 && 1277 state[level].category == TSTATE_ARITH) { 1278 level--; 1279 USTPUTC(CTLENDARI, out); 1280 } else 1281 USTPUTC(')', out); 1282 } else { 1283 /* 1284 * unbalanced parens 1285 * (don't 2nd guess - no error) 1286 */ 1287 pungetc(); 1288 USTPUTC(')', out); 1289 } 1290 } 1291 break; 1292 case CBQUOTE: /* '`' */ 1293 out = parsebackq(out, &bqlist, 1, 1294 state[level].syntax == DQSYNTAX && 1295 (eofmark == NULL || newvarnest > 0), 1296 state[level].syntax == DQSYNTAX || state[level].syntax == ARISYNTAX); 1297 break; 1298 case CEOF: 1299 goto endword; /* exit outer loop */ 1300 case CIGN: 1301 break; 1302 default: 1303 if (level == 0) 1304 goto endword; /* exit outer loop */ 1305 USTPUTC(c, out); 1306 } 1307 c = pgetc_macro(); 1308 } 1309 } 1310endword: 1311 if (state[level].syntax == ARISYNTAX) 1312 synerror("Missing '))'"); 1313 if (state[level].syntax != BASESYNTAX && eofmark == NULL) 1314 synerror("Unterminated quoted string"); 1315 if (state[level].category == TSTATE_VAR_OLD || 1316 state[level].category == TSTATE_VAR_NEW) { 1317 startlinno = plinno; 1318 synerror("Missing '}'"); 1319 } 1320 if (state != state_static) 1321 parser_temp_free_upto(state); 1322 USTPUTC('\0', out); 1323 len = out - stackblock(); 1324 out = stackblock(); 1325 if (eofmark == NULL) { 1326 if ((c == '>' || c == '<') 1327 && quotef == 0 1328 && len <= 2 1329 && (*out == '\0' || is_digit(*out))) { 1330 PARSEREDIR(); 1331 return lasttoken = TREDIR; 1332 } else { 1333 pungetc(); 1334 } 1335 } 1336 quoteflag = quotef; 1337 backquotelist = bqlist; 1338 grabstackblock(len); 1339 wordtext = out; 1340 return lasttoken = TWORD; 1341/* end of readtoken routine */ 1342 1343 1344/* 1345 * Check to see whether we are at the end of the here document. When this 1346 * is called, c is set to the first character of the next input line. If 1347 * we are at the end of the here document, this routine sets the c to PEOF. 1348 */ 1349 1350checkend: { 1351 if (eofmark) { 1352 if (striptabs) { 1353 while (c == '\t') 1354 c = pgetc(); 1355 } 1356 if (c == *eofmark) { 1357 if (pfgets(line, sizeof line) != NULL) { 1358 char *p, *q; 1359 1360 p = line; 1361 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 1362 if (*p == '\n' && *q == '\0') { 1363 c = PEOF; 1364 plinno++; 1365 needprompt = doprompt; 1366 } else { 1367 pushstring(line, strlen(line), NULL); 1368 } 1369 } 1370 } 1371 } 1372 goto checkend_return; 1373} 1374 1375 1376/* 1377 * Parse a redirection operator. The variable "out" points to a string 1378 * specifying the fd to be redirected. The variable "c" contains the 1379 * first character of the redirection operator. 1380 */ 1381 1382parseredir: { 1383 char fd = *out; 1384 union node *np; 1385 1386 np = (union node *)stalloc(sizeof (struct nfile)); 1387 if (c == '>') { 1388 np->nfile.fd = 1; 1389 c = pgetc(); 1390 if (c == '>') 1391 np->type = NAPPEND; 1392 else if (c == '&') 1393 np->type = NTOFD; 1394 else if (c == '|') 1395 np->type = NCLOBBER; 1396 else { 1397 np->type = NTO; 1398 pungetc(); 1399 } 1400 } else { /* c == '<' */ 1401 np->nfile.fd = 0; 1402 c = pgetc(); 1403 if (c == '<') { 1404 if (sizeof (struct nfile) != sizeof (struct nhere)) { 1405 np = (union node *)stalloc(sizeof (struct nhere)); 1406 np->nfile.fd = 0; 1407 } 1408 np->type = NHERE; 1409 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 1410 heredoc->here = np; 1411 if ((c = pgetc()) == '-') { 1412 heredoc->striptabs = 1; 1413 } else { 1414 heredoc->striptabs = 0; 1415 pungetc(); 1416 } 1417 } else if (c == '&') 1418 np->type = NFROMFD; 1419 else if (c == '>') 1420 np->type = NFROMTO; 1421 else { 1422 np->type = NFROM; 1423 pungetc(); 1424 } 1425 } 1426 if (fd != '\0') 1427 np->nfile.fd = digit_val(fd); 1428 redirnode = np; 1429 goto parseredir_return; 1430} 1431 1432 1433/* 1434 * Parse a substitution. At this point, we have read the dollar sign 1435 * and nothing else. 1436 */ 1437 1438parsesub: { 1439 char buf[10]; 1440 int subtype; 1441 int typeloc; 1442 int flags; 1443 char *p; 1444 static const char types[] = "}-+?="; 1445 int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ 1446 int linno; 1447 int length; 1448 1449 c = pgetc(); 1450 if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) && 1451 !is_special(c)) { 1452 USTPUTC('$', out); 1453 pungetc(); 1454 } else if (c == '(') { /* $(command) or $((arith)) */ 1455 if (pgetc() == '(') { 1456 PARSEARITH(); 1457 } else { 1458 pungetc(); 1459 out = parsebackq(out, &bqlist, 0, 1460 state[level].syntax == DQSYNTAX && 1461 (eofmark == NULL || newvarnest > 0), 1462 state[level].syntax == DQSYNTAX || 1463 state[level].syntax == ARISYNTAX); 1464 } 1465 } else { 1466 USTPUTC(CTLVAR, out); 1467 typeloc = out - stackblock(); 1468 USTPUTC(VSNORMAL, out); 1469 subtype = VSNORMAL; 1470 flags = 0; 1471 if (c == '{') { 1472 bracketed_name = 1; 1473 c = pgetc(); 1474 if (c == '#') { 1475 if ((c = pgetc()) == '}') 1476 c = '#'; 1477 else 1478 subtype = VSLENGTH; 1479 } 1480 else 1481 subtype = 0; 1482 } 1483 if (!is_eof(c) && is_name(c)) { 1484 length = 0; 1485 do { 1486 STPUTC(c, out); 1487 c = pgetc(); 1488 length++; 1489 } while (!is_eof(c) && is_in_name(c)); 1490 if (length == 6 && 1491 strncmp(out - length, "LINENO", length) == 0) { 1492 /* Replace the variable name with the 1493 * current line number. */ 1494 linno = plinno; 1495 if (funclinno != 0) 1496 linno -= funclinno - 1; 1497 snprintf(buf, sizeof(buf), "%d", linno); 1498 STADJUST(-6, out); 1499 STPUTS(buf, out); 1500 flags |= VSLINENO; 1501 } 1502 } else if (is_digit(c)) { 1503 if (bracketed_name) { 1504 do { 1505 STPUTC(c, out); 1506 c = pgetc(); 1507 } while (is_digit(c)); 1508 } else { 1509 STPUTC(c, out); 1510 c = pgetc(); 1511 } 1512 } else { 1513 if (! is_special(c)) { 1514 subtype = VSERROR; 1515 if (c == '}') 1516 pungetc(); 1517 else if (c == '\n' || c == PEOF) 1518 synerror("Unexpected end of line in substitution"); 1519 else 1520 USTPUTC(c, out); 1521 } else { 1522 USTPUTC(c, out); 1523 c = pgetc(); 1524 } 1525 } 1526 if (subtype == 0) { 1527 switch (c) { 1528 case ':': 1529 flags |= VSNUL; 1530 c = pgetc(); 1531 /*FALLTHROUGH*/ 1532 default: 1533 p = strchr(types, c); 1534 if (p == NULL) { 1535 if (c == '\n' || c == PEOF) 1536 synerror("Unexpected end of line in substitution"); 1537 if (flags == VSNUL) 1538 STPUTC(':', out); 1539 STPUTC(c, out); 1540 subtype = VSERROR; 1541 } else 1542 subtype = p - types + VSNORMAL; 1543 break; 1544 case '%': 1545 case '#': 1546 { 1547 int cc = c; 1548 subtype = c == '#' ? VSTRIMLEFT : 1549 VSTRIMRIGHT; 1550 c = pgetc(); 1551 if (c == cc) 1552 subtype++; 1553 else 1554 pungetc(); 1555 break; 1556 } 1557 } 1558 } else if (subtype != VSERROR) { 1559 pungetc(); 1560 } 1561 STPUTC('=', out); 1562 if (subtype != VSLENGTH && (state[level].syntax == DQSYNTAX || 1563 state[level].syntax == ARISYNTAX)) 1564 flags |= VSQUOTE; 1565 *(stackblock() + typeloc) = subtype | flags; 1566 if (subtype != VSNORMAL) { 1567 if (level + 1 >= maxnest) { 1568 maxnest *= 2; 1569 if (state == state_static) { 1570 state = parser_temp_alloc( 1571 maxnest * sizeof(*state)); 1572 memcpy(state, state_static, 1573 MAXNEST_static * sizeof(*state)); 1574 } else 1575 state = parser_temp_realloc(state, 1576 maxnest * sizeof(*state)); 1577 } 1578 level++; 1579 state[level].parenlevel = 0; 1580 if (subtype == VSMINUS || subtype == VSPLUS || 1581 subtype == VSQUESTION || subtype == VSASSIGN) { 1582 /* 1583 * For operators that were in the Bourne shell, 1584 * inherit the double-quote state. 1585 */ 1586 state[level].syntax = state[level - 1].syntax; 1587 state[level].category = TSTATE_VAR_OLD; 1588 } else { 1589 /* 1590 * The other operators take a pattern, 1591 * so go to BASESYNTAX. 1592 * Also, ' and " are now special, even 1593 * in here documents. 1594 */ 1595 state[level].syntax = BASESYNTAX; 1596 state[level].category = TSTATE_VAR_NEW; 1597 newvarnest++; 1598 } 1599 } 1600 } 1601 goto parsesub_return; 1602} 1603 1604 1605/* 1606 * Parse an arithmetic expansion (indicate start of one and set state) 1607 */ 1608parsearith: { 1609 1610 if (level + 1 >= maxnest) { 1611 maxnest *= 2; 1612 if (state == state_static) { 1613 state = parser_temp_alloc( 1614 maxnest * sizeof(*state)); 1615 memcpy(state, state_static, 1616 MAXNEST_static * sizeof(*state)); 1617 } else 1618 state = parser_temp_realloc(state, 1619 maxnest * sizeof(*state)); 1620 } 1621 level++; 1622 state[level].syntax = ARISYNTAX; 1623 state[level].parenlevel = 0; 1624 state[level].category = TSTATE_ARITH; 1625 USTPUTC(CTLARI, out); 1626 if (state[level - 1].syntax == DQSYNTAX) 1627 USTPUTC('"',out); 1628 else 1629 USTPUTC(' ',out); 1630 goto parsearith_return; 1631} 1632 1633} /* end of readtoken */ 1634 1635 1636 1637#ifdef mkinit 1638RESET { 1639 tokpushback = 0; 1640 checkkwd = 0; 1641} 1642#endif 1643 1644/* 1645 * Returns true if the text contains nothing to expand (no dollar signs 1646 * or backquotes). 1647 */ 1648 1649static int 1650noexpand(char *text) 1651{ 1652 char *p; 1653 char c; 1654 1655 p = text; 1656 while ((c = *p++) != '\0') { 1657 if ( c == CTLQUOTEMARK) 1658 continue; 1659 if (c == CTLESC) 1660 p++; 1661 else if (BASESYNTAX[(int)c] == CCTL) 1662 return 0; 1663 } 1664 return 1; 1665} 1666 1667 1668/* 1669 * Return true if the argument is a legal variable name (a letter or 1670 * underscore followed by zero or more letters, underscores, and digits). 1671 */ 1672 1673int 1674goodname(const char *name) 1675{ 1676 const char *p; 1677 1678 p = name; 1679 if (! is_name(*p)) 1680 return 0; 1681 while (*++p) { 1682 if (! is_in_name(*p)) 1683 return 0; 1684 } 1685 return 1; 1686} 1687 1688 1689/* 1690 * Called when an unexpected token is read during the parse. The argument 1691 * is the token that is expected, or -1 if more than one type of token can 1692 * occur at this point. 1693 */ 1694 1695static void 1696synexpect(int token) 1697{ 1698 char msg[64]; 1699 1700 if (token >= 0) { 1701 fmtstr(msg, 64, "%s unexpected (expecting %s)", 1702 tokname[lasttoken], tokname[token]); 1703 } else { 1704 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 1705 } 1706 synerror(msg); 1707} 1708 1709 1710static void 1711synerror(const char *msg) 1712{ 1713 if (commandname) 1714 outfmt(out2, "%s: %d: ", commandname, startlinno); 1715 outfmt(out2, "Syntax error: %s\n", msg); 1716 error((char *)NULL); 1717} 1718 1719static void 1720setprompt(int which) 1721{ 1722 whichprompt = which; 1723 1724#ifndef NO_HISTORY 1725 if (!el) 1726#endif 1727 { 1728 out2str(getprompt(NULL)); 1729 flushout(out2); 1730 } 1731} 1732 1733/* 1734 * called by editline -- any expansions to the prompt 1735 * should be added here. 1736 */ 1737char * 1738getprompt(void *unused __unused) 1739{ 1740 static char ps[PROMPTLEN]; 1741 char *fmt; 1742 const char *pwd; 1743 int i, trim; 1744 static char internal_error[] = "??"; 1745 1746 /* 1747 * Select prompt format. 1748 */ 1749 switch (whichprompt) { 1750 case 0: 1751 fmt = nullstr; 1752 break; 1753 case 1: 1754 fmt = ps1val(); 1755 break; 1756 case 2: 1757 fmt = ps2val(); 1758 break; 1759 default: 1760 return internal_error; 1761 } 1762 1763 /* 1764 * Format prompt string. 1765 */ 1766 for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++) 1767 if (*fmt == '\\') 1768 switch (*++fmt) { 1769 1770 /* 1771 * Hostname. 1772 * 1773 * \h specifies just the local hostname, 1774 * \H specifies fully-qualified hostname. 1775 */ 1776 case 'h': 1777 case 'H': 1778 ps[i] = '\0'; 1779 gethostname(&ps[i], PROMPTLEN - i); 1780 /* Skip to end of hostname. */ 1781 trim = (*fmt == 'h') ? '.' : '\0'; 1782 while ((ps[i+1] != '\0') && (ps[i+1] != trim)) 1783 i++; 1784 break; 1785 1786 /* 1787 * Working directory. 1788 * 1789 * \W specifies just the final component, 1790 * \w specifies the entire path. 1791 */ 1792 case 'W': 1793 case 'w': 1794 pwd = lookupvar("PWD"); 1795 if (pwd == NULL) 1796 pwd = "?"; 1797 if (*fmt == 'W' && 1798 *pwd == '/' && pwd[1] != '\0') 1799 strlcpy(&ps[i], strrchr(pwd, '/') + 1, 1800 PROMPTLEN - i); 1801 else 1802 strlcpy(&ps[i], pwd, PROMPTLEN - i); 1803 /* Skip to end of path. */ 1804 while (ps[i + 1] != '\0') 1805 i++; 1806 break; 1807 1808 /* 1809 * Superuser status. 1810 * 1811 * '$' for normal users, '#' for root. 1812 */ 1813 case '$': 1814 ps[i] = (geteuid() != 0) ? '$' : '#'; 1815 break; 1816 1817 /* 1818 * A literal \. 1819 */ 1820 case '\\': 1821 ps[i] = '\\'; 1822 break; 1823 1824 /* 1825 * Emit unrecognized formats verbatim. 1826 */ 1827 default: 1828 ps[i++] = '\\'; 1829 ps[i] = *fmt; 1830 break; 1831 } 1832 else 1833 ps[i] = *fmt; 1834 ps[i] = '\0'; 1835 return (ps); 1836} 1837