parser.c revision 20425
1121934Sharti/*- 2121934Sharti * Copyright (c) 1991, 1993 3121934Sharti * The Regents of the University of California. All rights reserved. 4121934Sharti * 5121934Sharti * This code is derived from software contributed to Berkeley by 6131826Sharti * Kenneth Almquist. 7131826Sharti * 8121934Sharti * Redistribution and use in source and binary forms, with or without 9121934Sharti * modification, are permitted provided that the following conditions 10121934Sharti * are met: 11121934Sharti * 1. Redistributions of source code must retain the above copyright 12121934Sharti * notice, this list of conditions and the following disclaimer. 13121934Sharti * 2. Redistributions in binary form must reproduce the above copyright 14121934Sharti * notice, this list of conditions and the following disclaimer in the 15121934Sharti * documentation and/or other materials provided with the distribution. 16121934Sharti * 3. All advertising materials mentioning features or use of this software 17121934Sharti * must display the following acknowledgement: 18121934Sharti * This product includes software developed by the University of 19121934Sharti * California, Berkeley and its contributors. 20121934Sharti * 4. Neither the name of the University nor the names of its contributors 21121934Sharti * may be used to endorse or promote products derived from this software 22121934Sharti * without specific prior written permission. 23121934Sharti * 24121934Sharti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25121934Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26121934Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27121934Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28121934Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29133492Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30121934Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31121934Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32121934Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33121934Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34121934Sharti * SUCH DAMAGE. 35121934Sharti * 36121934Sharti * $Id: parser.c,v 1.16 1996/09/10 02:42:33 peter Exp $ 37121934Sharti */ 38121934Sharti 39121934Sharti#ifndef lint 40121934Shartistatic char const sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; 41121934Sharti#endif /* not lint */ 42121934Sharti 43121934Sharti#include <stdlib.h> 44121934Sharti 45121934Sharti#include "shell.h" 46121934Sharti#include "parser.h" 47121934Sharti#include "nodes.h" 48121934Sharti#include "expand.h" /* defines rmescapes() */ 49121934Sharti#include "redir.h" /* defines copyfd() */ 50121934Sharti#include "syntax.h" 51121934Sharti#include "options.h" 52121934Sharti#include "input.h" 53121934Sharti#include "output.h" 54121934Sharti#include "var.h" 55121934Sharti#include "error.h" 56121934Sharti#include "memalloc.h" 57121934Sharti#include "mystring.h" 58121934Sharti#include "alias.h" 59121934Sharti#include "show.h" 60121934Sharti#ifndef NO_HISTORY 61121934Sharti#include "myhistedit.h" 62121934Sharti#endif 63121934Sharti 64121934Sharti/* 65121934Sharti * Shell command parser. 66121934Sharti */ 67121934Sharti 68121934Sharti#define EOFMARKLEN 79 69121934Sharti 70121934Sharti/* values returned by readtoken */ 71121934Sharti#include "token.h" 72121934Sharti 73121934Sharti 74121934Sharti 75121934Shartistruct heredoc { 76121934Sharti struct heredoc *next; /* next here document in list */ 77121934Sharti union node *here; /* redirection node */ 78121934Sharti char *eofmark; /* string indicating end of input */ 79121934Sharti int striptabs; /* if set, strip leading tabs */ 80121934Sharti}; 81121934Sharti 82121934Sharti 83121934Sharti 84121934Shartistruct heredoc *heredoclist; /* list of here documents to read */ 85121934Shartiint parsebackquote; /* nonzero if we are inside backquotes */ 86121934Shartiint doprompt; /* if set, prompt the user */ 87121934Shartiint needprompt; /* true if interactive and at start of line */ 88121934Shartiint lasttoken; /* last token read */ 89121934ShartiMKINIT int tokpushback; /* last token pushed back */ 90121934Shartichar *wordtext; /* text of last word returned by readtoken */ 91121934ShartiMKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 92121934Shartistruct nodelist *backquotelist; 93121934Shartiunion node *redirnode; 94121934Shartistruct heredoc *heredoc; 95121934Shartiint quoteflag; /* set if (part of) last token was quoted */ 96121934Shartiint startlinno; /* line # where last token started */ 97121934Sharti 98121934Sharti/* XXX When 'noaliases' is set to one, no alias expansion takes place. */ 99121934Shartistatic int noaliases = 0; 100121934Sharti 101121934Sharti#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ 102121934Sharti#ifdef GDB_HACK 103121934Shartistatic const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; 104121934Shartistatic const char types[] = "}-+?="; 105121934Sharti#endif 106121934Sharti 107121934Sharti 108121934ShartiSTATIC union node *list __P((int)); 109121934ShartiSTATIC union node *andor __P((void)); 110121934ShartiSTATIC union node *pipeline __P((void)); 111121934ShartiSTATIC union node *command __P((void)); 112121934ShartiSTATIC union node *simplecmd __P((union node **, union node *)); 113121934ShartiSTATIC union node *makename __P((void)); 114121934ShartiSTATIC void parsefname __P((void)); 115121934ShartiSTATIC void parseheredoc __P((void)); 116121934ShartiSTATIC int peektoken __P((void)); 117121934ShartiSTATIC int readtoken __P((void)); 118121934ShartiSTATIC int xxreadtoken __P((void)); 119121934ShartiSTATIC int readtoken1 __P((int, char const *, char *, int)); 120121934ShartiSTATIC int noexpand __P((char *)); 121121934ShartiSTATIC void synexpect __P((int)); 122121934ShartiSTATIC void synerror __P((char *)); 123121934ShartiSTATIC void setprompt __P((int)); 124121934Sharti 125121934Sharti 126121934Sharti/* 127121934Sharti * Read and parse a command. Returns NEOF on end of file. (NULL is a 128121934Sharti * valid parse tree indicating a blank line.) 129121934Sharti */ 130121934Sharti 131121934Shartiunion node * 132121934Shartiparsecmd(interact) 133121934Sharti int interact; 134121934Sharti{ 135121934Sharti int t; 136121934Sharti 137121934Sharti doprompt = interact; 138121934Sharti if (doprompt) 139121934Sharti setprompt(1); 140121934Sharti else 141121934Sharti setprompt(0); 142121934Sharti needprompt = 0; 143121934Sharti t = readtoken(); 144121934Sharti if (t == TEOF) 145121934Sharti return NEOF; 146121934Sharti if (t == TNL) 147121934Sharti return NULL; 148121934Sharti tokpushback++; 149121934Sharti return list(1); 150121934Sharti} 151121934Sharti 152121934Sharti 153121934ShartiSTATIC union node * 154121934Shartilist(nlflag) 155121934Sharti int nlflag; 156121934Sharti{ 157121934Sharti union node *n1, *n2, *n3; 158121934Sharti int tok; 159121934Sharti 160121934Sharti checkkwd = 2; 161121934Sharti if (nlflag == 0 && tokendlist[peektoken()]) 162121934Sharti return NULL; 163121934Sharti n1 = NULL; 164121934Sharti for (;;) { 165121934Sharti n2 = andor(); 166121934Sharti tok = readtoken(); 167121934Sharti if (tok == TBACKGND) { 168121934Sharti if (n2->type == NCMD || n2->type == NPIPE) { 169121934Sharti n2->ncmd.backgnd = 1; 170121934Sharti } else if (n2->type == NREDIR) { 171121934Sharti n2->type = NBACKGND; 172121934Sharti } else { 173121934Sharti n3 = (union node *)stalloc(sizeof (struct nredir)); 174121934Sharti n3->type = NBACKGND; 175121934Sharti n3->nredir.n = n2; 176121934Sharti n3->nredir.redirect = NULL; 177121934Sharti n2 = n3; 178121934Sharti } 179121934Sharti } 180121934Sharti if (n1 == NULL) { 181121934Sharti n1 = n2; 182121934Sharti } 183121934Sharti else { 184121934Sharti n3 = (union node *)stalloc(sizeof (struct nbinary)); 185121934Sharti n3->type = NSEMI; 186121934Sharti n3->nbinary.ch1 = n1; 187121934Sharti n3->nbinary.ch2 = n2; 188121934Sharti n1 = n3; 189121934Sharti } 190121934Sharti switch (tok) { 191121934Sharti case TBACKGND: 192121934Sharti case TSEMI: 193121934Sharti tok = readtoken(); 194121934Sharti /* fall through */ 195121934Sharti case TNL: 196121934Sharti if (tok == TNL) { 197121934Sharti parseheredoc(); 198121934Sharti if (nlflag) 199121934Sharti return n1; 200121934Sharti } else { 201121934Sharti tokpushback++; 202121934Sharti } 203121934Sharti checkkwd = 2; 204121934Sharti if (tokendlist[peektoken()]) 205121934Sharti return n1; 206121934Sharti break; 207121934Sharti case TEOF: 208121934Sharti if (heredoclist) 209133492Sharti parseheredoc(); 210121934Sharti else 211133492Sharti pungetc(); /* push back EOF on input */ 212133492Sharti return n1; 213133492Sharti default: 214121934Sharti if (nlflag) 215121934Sharti synexpect(-1); 216121934Sharti tokpushback++; 217121934Sharti return n1; 218121934Sharti } 219121934Sharti } 220121934Sharti} 221121934Sharti 222121934Sharti 223121934Sharti 224121934ShartiSTATIC union node * 225121934Shartiandor() { 226121934Sharti union node *n1, *n2, *n3; 227121934Sharti int t; 228121934Sharti 229121934Sharti n1 = pipeline(); 230121934Sharti for (;;) { 231121934Sharti if ((t = readtoken()) == TAND) { 232121934Sharti t = NAND; 233121934Sharti } else if (t == TOR) { 234121934Sharti t = NOR; 235121934Sharti } else { 236121934Sharti tokpushback++; 237121934Sharti return n1; 238121934Sharti } 239121934Sharti n2 = pipeline(); 240121934Sharti n3 = (union node *)stalloc(sizeof (struct nbinary)); 241121934Sharti n3->type = t; 242121934Sharti n3->nbinary.ch1 = n1; 243121934Sharti n3->nbinary.ch2 = n2; 244121934Sharti n1 = n3; 245121934Sharti } 246121934Sharti} 247121934Sharti 248121934Sharti 249121934Sharti 250121934ShartiSTATIC union node * 251121934Shartipipeline() { 252121934Sharti union node *n1, *pipenode; 253121934Sharti struct nodelist *lp, *prev; 254121934Sharti 255121934Sharti TRACE(("pipeline: entered\n")); 256121934Sharti n1 = command(); 257121934Sharti if (readtoken() == TPIPE) { 258121934Sharti pipenode = (union node *)stalloc(sizeof (struct npipe)); 259121934Sharti pipenode->type = NPIPE; 260121934Sharti pipenode->npipe.backgnd = 0; 261121934Sharti lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 262121934Sharti pipenode->npipe.cmdlist = lp; 263121934Sharti lp->n = n1; 264121934Sharti do { 265121934Sharti prev = lp; 266121934Sharti lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 267121934Sharti lp->n = command(); 268121934Sharti prev->next = lp; 269121934Sharti } while (readtoken() == TPIPE); 270121934Sharti lp->next = NULL; 271121934Sharti n1 = pipenode; 272121934Sharti } 273121934Sharti tokpushback++; 274121934Sharti return n1; 275121934Sharti} 276121934Sharti 277121934Sharti 278121934Sharti 279121934ShartiSTATIC union node * 280121934Sharticommand() { 281121934Sharti union node *n1, *n2; 282121934Sharti union node *ap, **app; 283121934Sharti union node *cp, **cpp; 284121934Sharti union node *redir, **rpp; 285121934Sharti int t, negate = 0; 286121934Sharti 287121934Sharti checkkwd = 2; 288121934Sharti redir = NULL; 289121934Sharti n1 = NULL; 290121934Sharti rpp = &redir; 291121934Sharti 292121934Sharti /* Check for redirection which may precede command */ 293121934Sharti while (readtoken() == TREDIR) { 294121934Sharti *rpp = n2 = redirnode; 295121934Sharti rpp = &n2->nfile.next; 296121934Sharti parsefname(); 297121934Sharti } 298121934Sharti tokpushback++; 299121934Sharti 300121934Sharti while (readtoken() == TNOT) { 301121934Sharti TRACE(("command: TNOT recognized\n")); 302121934Sharti negate = !negate; 303121934Sharti } 304121934Sharti tokpushback++; 305121934Sharti 306121934Sharti switch (readtoken()) { 307121934Sharti case TIF: 308121934Sharti n1 = (union node *)stalloc(sizeof (struct nif)); 309121934Sharti n1->type = NIF; 310121934Sharti n1->nif.test = list(0); 311121934Sharti if (readtoken() != TTHEN) 312121934Sharti synexpect(TTHEN); 313121934Sharti n1->nif.ifpart = list(0); 314121934Sharti n2 = n1; 315121934Sharti while (readtoken() == TELIF) { 316121934Sharti n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 317121934Sharti n2 = n2->nif.elsepart; 318121934Sharti n2->type = NIF; 319121934Sharti n2->nif.test = list(0); 320121934Sharti if (readtoken() != TTHEN) 321121934Sharti synexpect(TTHEN); 322121934Sharti n2->nif.ifpart = list(0); 323121934Sharti } 324121934Sharti if (lasttoken == TELSE) 325121934Sharti n2->nif.elsepart = list(0); 326121934Sharti else { 327121934Sharti n2->nif.elsepart = NULL; 328121934Sharti tokpushback++; 329121934Sharti } 330121934Sharti if (readtoken() != TFI) 331121934Sharti synexpect(TFI); 332121934Sharti checkkwd = 1; 333121934Sharti break; 334121934Sharti case TWHILE: 335121934Sharti case TUNTIL: { 336121934Sharti int got; 337121934Sharti n1 = (union node *)stalloc(sizeof (struct nbinary)); 338121934Sharti n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 339121934Sharti n1->nbinary.ch1 = list(0); 340121934Sharti if ((got=readtoken()) != TDO) { 341121934ShartiTRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 342121934Sharti synexpect(TDO); 343121934Sharti } 344121934Sharti n1->nbinary.ch2 = list(0); 345121934Sharti if (readtoken() != TDONE) 346121934Sharti synexpect(TDONE); 347121934Sharti checkkwd = 1; 348121934Sharti break; 349121934Sharti } 350121934Sharti case TFOR: 351121934Sharti if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 352121934Sharti synerror("Bad for loop variable"); 353121934Sharti n1 = (union node *)stalloc(sizeof (struct nfor)); 354121934Sharti n1->type = NFOR; 355121934Sharti n1->nfor.var = wordtext; 356121934Sharti if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 357121934Sharti app = ≈ 358121934Sharti while (readtoken() == TWORD) { 359121934Sharti n2 = (union node *)stalloc(sizeof (struct narg)); 360121934Sharti n2->type = NARG; 361121934Sharti n2->narg.text = wordtext; 362121934Sharti n2->narg.backquote = backquotelist; 363121934Sharti *app = n2; 364121934Sharti app = &n2->narg.next; 365121934Sharti } 366121934Sharti *app = NULL; 367121934Sharti n1->nfor.args = ap; 368121934Sharti if (lasttoken != TNL && lasttoken != TSEMI) 369121934Sharti synexpect(-1); 370121934Sharti } else { 371121934Sharti#ifndef GDB_HACK 372121934Sharti static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 373121934Sharti '@', '=', '\0'}; 374121934Sharti#endif 375121934Sharti n2 = (union node *)stalloc(sizeof (struct narg)); 376121934Sharti n2->type = NARG; 377121934Sharti n2->narg.text = (char *)argvars; 378121934Sharti n2->narg.backquote = NULL; 379121934Sharti n2->narg.next = NULL; 380121934Sharti n1->nfor.args = n2; 381121934Sharti /* 382121934Sharti * Newline or semicolon here is optional (but note 383121934Sharti * that the original Bourne shell only allowed NL). 384121934Sharti */ 385121934Sharti if (lasttoken != TNL && lasttoken != TSEMI) 386121934Sharti tokpushback++; 387121934Sharti } 388121934Sharti checkkwd = 2; 389121934Sharti if ((t = readtoken()) == TDO) 390121934Sharti t = TDONE; 391121934Sharti else if (t == TBEGIN) 392121934Sharti t = TEND; 393121934Sharti else 394121934Sharti synexpect(-1); 395121934Sharti n1->nfor.body = list(0); 396121934Sharti if (readtoken() != t) 397121934Sharti synexpect(t); 398121934Sharti checkkwd = 1; 399121934Sharti break; 400121934Sharti case TCASE: 401121934Sharti n1 = (union node *)stalloc(sizeof (struct ncase)); 402121934Sharti n1->type = NCASE; 403121934Sharti if (readtoken() != TWORD) 404121934Sharti synexpect(TWORD); 405121934Sharti n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 406121934Sharti n2->type = NARG; 407121934Sharti n2->narg.text = wordtext; 408121934Sharti n2->narg.backquote = backquotelist; 409121934Sharti n2->narg.next = NULL; 410121934Sharti while (readtoken() == TNL); 411121934Sharti if (lasttoken != TWORD || ! equal(wordtext, "in")) 412121934Sharti synerror("expecting \"in\""); 413121934Sharti cpp = &n1->ncase.cases; 414121934Sharti noaliases = 1; /* turn off alias expansion */ 415121934Sharti checkkwd = 2, readtoken(); 416121934Sharti do { 417121934Sharti *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 418121934Sharti cp->type = NCLIST; 419121934Sharti app = &cp->nclist.pattern; 420121934Sharti for (;;) { 421121934Sharti *app = ap = (union node *)stalloc(sizeof (struct narg)); 422121934Sharti ap->type = NARG; 423121934Sharti ap->narg.text = wordtext; 424121934Sharti ap->narg.backquote = backquotelist; 425121934Sharti if (checkkwd = 2, readtoken() != TPIPE) 426121934Sharti break; 427121934Sharti app = &ap->narg.next; 428121934Sharti readtoken(); 429121934Sharti } 430121934Sharti ap->narg.next = NULL; 431121934Sharti if (lasttoken != TRP) 432121934Sharti noaliases = 0, synexpect(TRP); 433121934Sharti cp->nclist.body = list(0); 434121934Sharti 435121934Sharti checkkwd = 2; 436121934Sharti if ((t = readtoken()) != TESAC) { 437121934Sharti if (t != TENDCASE) 438121934Sharti noaliases = 0, synexpect(TENDCASE); 439121934Sharti else 440121934Sharti checkkwd = 2, readtoken(); 441121934Sharti } 442121934Sharti cpp = &cp->nclist.next; 443121934Sharti } while(lasttoken != TESAC); 444121934Sharti noaliases = 0; /* reset alias expansion */ 445121934Sharti *cpp = NULL; 446121934Sharti checkkwd = 1; 447121934Sharti break; 448121934Sharti case TLP: 449121934Sharti n1 = (union node *)stalloc(sizeof (struct nredir)); 450121934Sharti n1->type = NSUBSHELL; 451121934Sharti n1->nredir.n = list(0); 452121934Sharti n1->nredir.redirect = NULL; 453121934Sharti if (readtoken() != TRP) 454121934Sharti synexpect(TRP); 455121934Sharti checkkwd = 1; 456121934Sharti break; 457121934Sharti case TBEGIN: 458121934Sharti n1 = list(0); 459121934Sharti if (readtoken() != TEND) 460121934Sharti synexpect(TEND); 461121934Sharti checkkwd = 1; 462121934Sharti break; 463121934Sharti /* Handle an empty command like other simple commands. */ 464121934Sharti case TSEMI: 465121934Sharti /* 466121934Sharti * An empty command before a ; doesn't make much sense, and 467121934Sharti * should certainly be disallowed in the case of `if ;'. 468121934Sharti */ 469121934Sharti if (!redir) 470121934Sharti synexpect(-1); 471121934Sharti case TAND: 472121934Sharti case TOR: 473121934Sharti case TNL: 474121934Sharti case TEOF: 475121934Sharti case TWORD: 476121934Sharti case TRP: 477121934Sharti tokpushback++; 478121934Sharti n1 = simplecmd(rpp, redir); 479121934Sharti goto checkneg; 480121934Sharti default: 481121934Sharti synexpect(-1); 482121934Sharti } 483121934Sharti 484121934Sharti /* Now check for redirection which may follow command */ 485121934Sharti while (readtoken() == TREDIR) { 486121934Sharti *rpp = n2 = redirnode; 487121934Sharti rpp = &n2->nfile.next; 488121934Sharti parsefname(); 489121934Sharti } 490121934Sharti tokpushback++; 491121934Sharti *rpp = NULL; 492121934Sharti if (redir) { 493121934Sharti if (n1->type != NSUBSHELL) { 494121934Sharti n2 = (union node *)stalloc(sizeof (struct nredir)); 495121934Sharti n2->type = NREDIR; 496121934Sharti n2->nredir.n = n1; 497121934Sharti n1 = n2; 498121934Sharti } 499121934Sharti n1->nredir.redirect = redir; 500121934Sharti } 501121934Sharti 502121934Sharticheckneg: 503121934Sharti if (negate) { 504121934Sharti n2 = (union node *)stalloc(sizeof (struct nnot)); 505121934Sharti n2->type = NNOT; 506121934Sharti n2->nnot.com = n1; 507121934Sharti return n2; 508121934Sharti } 509121934Sharti else 510121934Sharti return n1; 511121934Sharti} 512121934Sharti 513121934Sharti 514121934ShartiSTATIC union node * 515121934Shartisimplecmd(rpp, redir) 516121934Sharti union node **rpp, *redir; 517121934Sharti { 518121934Sharti union node *args, **app; 519121934Sharti union node **orig_rpp = rpp; 520121934Sharti union node *n = NULL, *n2; 521121934Sharti int negate = 0; 522121934Sharti 523121934Sharti /* If we don't have any redirections already, then we must reset */ 524121934Sharti /* rpp to be the address of the local redir variable. */ 525121934Sharti if (redir == 0) 526121934Sharti rpp = &redir; 527121934Sharti 528121934Sharti args = NULL; 529121934Sharti app = &args; 530121934Sharti /* 531121934Sharti * We save the incoming value, because we need this for shell 532121934Sharti * functions. There can not be a redirect or an argument between 533121934Sharti * the function name and the open parenthesis. 534121934Sharti */ 535121934Sharti orig_rpp = rpp; 536121934Sharti 537121934Sharti while (readtoken() == TNOT) { 538121934Sharti TRACE(("command: TNOT recognized\n")); 539121934Sharti negate = !negate; 540121934Sharti } 541121934Sharti tokpushback++; 542121934Sharti 543121934Sharti for (;;) { 544121934Sharti if (readtoken() == TWORD) { 545121934Sharti n = (union node *)stalloc(sizeof (struct narg)); 546121934Sharti n->type = NARG; 547121934Sharti n->narg.text = wordtext; 548121934Sharti n->narg.backquote = backquotelist; 549121934Sharti *app = n; 550121934Sharti app = &n->narg.next; 551121934Sharti } else if (lasttoken == TREDIR) { 552121934Sharti *rpp = n = redirnode; 553121934Sharti rpp = &n->nfile.next; 554121934Sharti parsefname(); /* read name of redirection file */ 555121934Sharti } else if (lasttoken == TLP && app == &args->narg.next 556121934Sharti && rpp == orig_rpp) { 557121934Sharti /* We have a function */ 558121934Sharti if (readtoken() != TRP) 559121934Sharti synexpect(TRP); 560121934Sharti#ifdef notdef 561121934Sharti if (! goodname(n->narg.text)) 562121934Sharti synerror("Bad function name"); 563121934Sharti#endif 564121934Sharti n->type = NDEFUN; 565121934Sharti n->narg.next = command(); 566121934Sharti goto checkneg; 567121934Sharti } else { 568121934Sharti tokpushback++; 569121934Sharti break; 570121934Sharti } 571121934Sharti } 572121934Sharti *app = NULL; 573121934Sharti *rpp = NULL; 574121934Sharti n = (union node *)stalloc(sizeof (struct ncmd)); 575121934Sharti n->type = NCMD; 576121934Sharti n->ncmd.backgnd = 0; 577121934Sharti n->ncmd.args = args; 578121934Sharti n->ncmd.redirect = redir; 579121934Sharti 580121934Sharticheckneg: 581121934Sharti if (negate) { 582121934Sharti n2 = (union node *)stalloc(sizeof (struct nnot)); 583121934Sharti n2->type = NNOT; 584121934Sharti n2->nnot.com = n; 585121934Sharti return n2; 586121934Sharti } 587121934Sharti else 588121934Sharti return n; 589121934Sharti} 590121934Sharti 591121934ShartiSTATIC union node * 592121934Shartimakename() { 593121934Sharti union node *n; 594121934Sharti 595121934Sharti n = (union node *)stalloc(sizeof (struct narg)); 596121934Sharti n->type = NARG; 597121934Sharti n->narg.next = NULL; 598121934Sharti n->narg.text = wordtext; 599121934Sharti n->narg.backquote = backquotelist; 600121934Sharti return n; 601121934Sharti} 602121934Sharti 603121934Shartivoid fixredir(n, text, err) 604121934Sharti union node *n; 605121934Sharti const char *text; 606121934Sharti int err; 607121934Sharti { 608121934Sharti TRACE(("Fix redir %s %d\n", text, err)); 609121934Sharti if (!err) 610121934Sharti n->ndup.vname = NULL; 611121934Sharti 612121934Sharti if (is_digit(text[0]) && text[1] == '\0') 613121934Sharti n->ndup.dupfd = digit_val(text[0]); 614121934Sharti else if (text[0] == '-' && text[1] == '\0') 615121934Sharti n->ndup.dupfd = -1; 616121934Sharti else { 617121934Sharti 618121934Sharti if (err) 619121934Sharti synerror("Bad fd number"); 620121934Sharti else 621121934Sharti n->ndup.vname = makename(); 622121934Sharti } 623121934Sharti} 624121934Sharti 625121934Sharti 626121934ShartiSTATIC void 627121934Shartiparsefname() { 628121934Sharti union node *n = redirnode; 629121934Sharti 630121934Sharti if (readtoken() != TWORD) 631121934Sharti synexpect(-1); 632121934Sharti if (n->type == NHERE) { 633121934Sharti struct heredoc *here = heredoc; 634121934Sharti struct heredoc *p; 635121934Sharti int i; 636121934Sharti 637121934Sharti if (quoteflag == 0) 638121934Sharti n->type = NXHERE; 639121934Sharti TRACE(("Here document %d\n", n->type)); 640121934Sharti if (here->striptabs) { 641121934Sharti while (*wordtext == '\t') 642121934Sharti wordtext++; 643121934Sharti } 644121934Sharti if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 645121934Sharti synerror("Illegal eof marker for << redirection"); 646121934Sharti rmescapes(wordtext); 647121934Sharti here->eofmark = wordtext; 648121934Sharti here->next = NULL; 649121934Sharti if (heredoclist == NULL) 650121934Sharti heredoclist = here; 651121934Sharti else { 652121934Sharti for (p = heredoclist ; p->next ; p = p->next); 653121934Sharti p->next = here; 654121934Sharti } 655121934Sharti } else if (n->type == NTOFD || n->type == NFROMFD) { 656121934Sharti fixredir(n, wordtext, 0); 657121934Sharti } else { 658121934Sharti n->nfile.fname = makename(); 659121934Sharti } 660121934Sharti} 661121934Sharti 662121934Sharti 663121934Sharti/* 664121934Sharti * Input any here documents. 665121934Sharti */ 666121934Sharti 667121934ShartiSTATIC void 668121934Shartiparseheredoc() { 669121934Sharti struct heredoc *here; 670121934Sharti union node *n; 671121934Sharti 672121934Sharti while (heredoclist) { 673121934Sharti here = heredoclist; 674121934Sharti heredoclist = here->next; 675121934Sharti if (needprompt) { 676121934Sharti setprompt(2); 677121934Sharti needprompt = 0; 678121934Sharti } 679121934Sharti readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 680121934Sharti here->eofmark, here->striptabs); 681121934Sharti n = (union node *)stalloc(sizeof (struct narg)); 682121934Sharti n->narg.type = NARG; 683121934Sharti n->narg.next = NULL; 684121934Sharti n->narg.text = wordtext; 685121934Sharti n->narg.backquote = backquotelist; 686121934Sharti here->here->nhere.doc = n; 687121934Sharti } 688121934Sharti} 689121934Sharti 690121934ShartiSTATIC int 691121934Shartipeektoken() { 692121934Sharti int t; 693121934Sharti 694121934Sharti t = readtoken(); 695121934Sharti tokpushback++; 696121934Sharti return (t); 697121934Sharti} 698121934Sharti 699121934ShartiSTATIC int xxreadtoken(); 700121934Sharti 701121934ShartiSTATIC int 702121934Shartireadtoken() { 703121934Sharti int t; 704121934Sharti int savecheckkwd = checkkwd; 705121934Sharti struct alias *ap; 706121934Sharti#ifdef DEBUG 707121934Sharti int alreadyseen = tokpushback; 708121934Sharti#endif 709121934Sharti 710121934Sharti top: 711121934Sharti t = xxreadtoken(); 712121934Sharti 713121934Sharti if (checkkwd) { 714121934Sharti /* 715121934Sharti * eat newlines 716121934Sharti */ 717121934Sharti if (checkkwd == 2) { 718121934Sharti checkkwd = 0; 719121934Sharti while (t == TNL) { 720121934Sharti parseheredoc(); 721121934Sharti t = xxreadtoken(); 722121934Sharti } 723121934Sharti } else 724121934Sharti checkkwd = 0; 725121934Sharti /* 726121934Sharti * check for keywords and aliases 727121934Sharti */ 728121934Sharti if (t == TWORD && !quoteflag) 729121934Sharti { 730121934Sharti register char * const *pp; 731121934Sharti 732121934Sharti for (pp = (char **)parsekwd; *pp; pp++) { 733121934Sharti if (**pp == *wordtext && equal(*pp, wordtext)) 734121934Sharti { 735121934Sharti lasttoken = t = pp - parsekwd + KWDOFFSET; 736121934Sharti TRACE(("keyword %s recognized\n", tokname[t])); 737121934Sharti goto out; 738121934Sharti } 739121934Sharti } 740121934Sharti if (noaliases == 0 && 741121934Sharti (ap = lookupalias(wordtext, 1)) != NULL) { 742121934Sharti pushstring(ap->val, strlen(ap->val), ap); 743121934Sharti checkkwd = savecheckkwd; 744121934Sharti goto top; 745121934Sharti } 746121934Sharti } 747121934Shartiout: 748121934Sharti checkkwd = (t == TNOT) ? savecheckkwd : 0; 749121934Sharti } 750121934Sharti#ifdef DEBUG 751121934Sharti if (!alreadyseen) 752121934Sharti TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 753121934Sharti else 754121934Sharti TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 755121934Sharti#endif 756121934Sharti return (t); 757121934Sharti} 758121934Sharti 759121934Sharti 760121934Sharti/* 761121934Sharti * Read the next input token. 762121934Sharti * If the token is a word, we set backquotelist to the list of cmds in 763121934Sharti * backquotes. We set quoteflag to true if any part of the word was 764121934Sharti * quoted. 765121934Sharti * If the token is TREDIR, then we set redirnode to a structure containing 766121934Sharti * the redirection. 767121934Sharti * In all cases, the variable startlinno is set to the number of the line 768121934Sharti * on which the token starts. 769121934Sharti * 770121934Sharti * [Change comment: here documents and internal procedures] 771121934Sharti * [Readtoken shouldn't have any arguments. Perhaps we should make the 772121934Sharti * word parsing code into a separate routine. In this case, readtoken 773121934Sharti * doesn't need to have any internal procedures, but parseword does. 774121934Sharti * We could also make parseoperator in essence the main routine, and 775121934Sharti * have parseword (readtoken1?) handle both words and redirection.] 776121934Sharti */ 777121934Sharti 778121934Sharti#define RETURN(token) return lasttoken = token 779121934Sharti 780121934ShartiSTATIC int 781121934Shartixxreadtoken() { 782121934Sharti register c; 783121934Sharti 784121934Sharti if (tokpushback) { 785121934Sharti tokpushback = 0; 786121934Sharti return lasttoken; 787121934Sharti } 788121934Sharti if (needprompt) { 789121934Sharti setprompt(2); 790121934Sharti needprompt = 0; 791121934Sharti } 792121934Sharti startlinno = plinno; 793121934Sharti for (;;) { /* until token or start of word found */ 794121934Sharti c = pgetc_macro(); 795121934Sharti if (c == ' ' || c == '\t') 796121934Sharti continue; /* quick check for white space first */ 797121934Sharti switch (c) { 798121934Sharti case ' ': case '\t': 799121934Sharti continue; 800121934Sharti case '#': 801121934Sharti while ((c = pgetc()) != '\n' && c != PEOF); 802121934Sharti pungetc(); 803121934Sharti continue; 804121934Sharti case '\\': 805121934Sharti if (pgetc() == '\n') { 806121934Sharti startlinno = ++plinno; 807121934Sharti if (doprompt) 808121934Sharti setprompt(2); 809121934Sharti else 810121934Sharti setprompt(0); 811121934Sharti continue; 812121934Sharti } 813121934Sharti pungetc(); 814121934Sharti goto breakloop; 815121934Sharti case '\n': 816121934Sharti plinno++; 817121934Sharti needprompt = doprompt; 818121934Sharti RETURN(TNL); 819121934Sharti case PEOF: 820121934Sharti RETURN(TEOF); 821121934Sharti case '&': 822121934Sharti if (pgetc() == '&') 823121934Sharti RETURN(TAND); 824121934Sharti pungetc(); 825121934Sharti RETURN(TBACKGND); 826121934Sharti case '|': 827121934Sharti if (pgetc() == '|') 828121934Sharti RETURN(TOR); 829121934Sharti pungetc(); 830121934Sharti RETURN(TPIPE); 831121934Sharti case ';': 832121934Sharti if (pgetc() == ';') 833121934Sharti RETURN(TENDCASE); 834121934Sharti pungetc(); 835121934Sharti RETURN(TSEMI); 836121934Sharti case '(': 837121934Sharti RETURN(TLP); 838121934Sharti case ')': 839121934Sharti RETURN(TRP); 840121934Sharti default: 841121934Sharti goto breakloop; 842121934Sharti } 843121934Sharti } 844121934Shartibreakloop: 845121934Sharti return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 846121934Sharti#undef RETURN 847121934Sharti} 848121934Sharti 849121934Sharti 850121934Sharti 851121934Sharti/* 852121934Sharti * If eofmark is NULL, read a word or a redirection symbol. If eofmark 853121934Sharti * is not NULL, read a here document. In the latter case, eofmark is the 854121934Sharti * word which marks the end of the document and striptabs is true if 855121934Sharti * leading tabs should be stripped from the document. The argument firstc 856121934Sharti * is the first character of the input token or document. 857121934Sharti * 858121934Sharti * Because C does not have internal subroutines, I have simulated them 859121934Sharti * using goto's to implement the subroutine linkage. The following macros 860121934Sharti * will run code that appears at the end of readtoken1. 861121934Sharti */ 862121934Sharti 863121934Sharti#define CHECKEND() {goto checkend; checkend_return:;} 864121934Sharti#define PARSEREDIR() {goto parseredir; parseredir_return:;} 865121934Sharti#define PARSESUB() {goto parsesub; parsesub_return:;} 866121934Sharti#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 867121934Sharti#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 868121934Sharti#define PARSEARITH() {goto parsearith; parsearith_return:;} 869121934Sharti 870121934ShartiSTATIC int 871121934Shartireadtoken1(firstc, syntax, eofmark, striptabs) 872121934Sharti int firstc; 873121934Sharti char const *syntax; 874121934Sharti char *eofmark; 875121934Sharti int striptabs; 876121934Sharti { 877121934Sharti int c = firstc; 878121934Sharti char *out; 879121934Sharti int len; 880121934Sharti char line[EOFMARKLEN + 1]; 881121934Sharti struct nodelist *bqlist; 882121934Sharti int quotef; 883121934Sharti int dblquote; 884121934Sharti int varnest; /* levels of variables expansion */ 885121934Sharti int arinest; /* levels of arithmetic expansion */ 886121934Sharti int parenlevel; /* levels of parens in arithmetic */ 887121934Sharti int oldstyle; 888121934Sharti char const *prevsyntax; /* syntax before arithmetic */ 889121934Sharti#if __GNUC__ 890121934Sharti /* Avoid longjmp clobbering */ 891121934Sharti (void) &out; 892121934Sharti (void) "ef; 893121934Sharti (void) &dblquote; 894121934Sharti (void) &varnest; 895121934Sharti (void) &arinest; 896121934Sharti (void) &parenlevel; 897121934Sharti (void) &oldstyle; 898121934Sharti (void) &prevsyntax; 899121934Sharti (void) &syntax; 900121934Sharti#endif 901121934Sharti 902121934Sharti startlinno = plinno; 903121934Sharti dblquote = 0; 904121934Sharti if (syntax == DQSYNTAX) 905121934Sharti dblquote = 1; 906121934Sharti quotef = 0; 907121934Sharti bqlist = NULL; 908121934Sharti varnest = 0; 909121934Sharti arinest = 0; 910121934Sharti parenlevel = 0; 911121934Sharti 912121934Sharti STARTSTACKSTR(out); 913121934Sharti loop: { /* for each line, until end of word */ 914121934Sharti#if ATTY 915121934Sharti if (c == '\034' && doprompt 916121934Sharti && attyset() && ! equal(termval(), "emacs")) { 917121934Sharti attyline(); 918121934Sharti if (syntax == BASESYNTAX) 919121934Sharti return readtoken(); 920121934Sharti c = pgetc(); 921121934Sharti goto loop; 922121934Sharti } 923121934Sharti#endif 924121934Sharti CHECKEND(); /* set c to PEOF if at end of here document */ 925121934Sharti for (;;) { /* until end of line or end of word */ 926121934Sharti CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 927121934Sharti switch(syntax[c]) { 928121934Sharti case CNL: /* '\n' */ 929121934Sharti if (syntax == BASESYNTAX) 930121934Sharti goto endword; /* exit outer loop */ 931121934Sharti USTPUTC(c, out); 932121934Sharti plinno++; 933121934Sharti if (doprompt) 934121934Sharti setprompt(2); 935121934Sharti else 936121934Sharti setprompt(0); 937121934Sharti c = pgetc(); 938121934Sharti goto loop; /* continue outer loop */ 939121934Sharti case CWORD: 940121934Sharti USTPUTC(c, out); 941121934Sharti break; 942121934Sharti case CCTL: 943121934Sharti if (eofmark == NULL || dblquote) 944121934Sharti USTPUTC(CTLESC, out); 945121934Sharti USTPUTC(c, out); 946121934Sharti break; 947121934Sharti case CBACK: /* backslash */ 948121934Sharti c = pgetc(); 949121934Sharti if (c == PEOF) { 950121934Sharti USTPUTC('\\', out); 951121934Sharti pungetc(); 952121934Sharti } else if (c == '\n') { 953121934Sharti if (doprompt) 954121934Sharti setprompt(2); 955121934Sharti else 956121934Sharti setprompt(0); 957121934Sharti } else { 958121934Sharti if (dblquote && c != '\\' && c != '`' && c != '$' 959121934Sharti && (c != '"' || eofmark != NULL)) 960121934Sharti USTPUTC('\\', out); 961121934Sharti if (SQSYNTAX[c] == CCTL) 962121934Sharti USTPUTC(CTLESC, out); 963121934Sharti USTPUTC(c, out); 964121934Sharti quotef++; 965121934Sharti } 966121934Sharti break; 967121934Sharti case CSQUOTE: 968121934Sharti syntax = SQSYNTAX; 969121934Sharti break; 970121934Sharti case CDQUOTE: 971121934Sharti syntax = DQSYNTAX; 972121934Sharti dblquote = 1; 973121934Sharti break; 974121934Sharti case CENDQUOTE: 975121934Sharti if (eofmark) { 976121934Sharti USTPUTC(c, out); 977121934Sharti } else { 978121934Sharti if (arinest) 979121934Sharti syntax = ARISYNTAX; 980121934Sharti else 981121934Sharti syntax = BASESYNTAX; 982121934Sharti quotef++; 983121934Sharti dblquote = 0; 984121934Sharti } 985121934Sharti break; 986121934Sharti case CVAR: /* '$' */ 987121934Sharti PARSESUB(); /* parse substitution */ 988121934Sharti break; 989121934Sharti case CENDVAR: /* '}' */ 990121934Sharti if (varnest > 0) { 991121934Sharti varnest--; 992121934Sharti USTPUTC(CTLENDVAR, out); 993121934Sharti } else { 994121934Sharti USTPUTC(c, out); 995121934Sharti } 996121934Sharti break; 997121934Sharti case CLP: /* '(' in arithmetic */ 998121934Sharti parenlevel++; 999121934Sharti USTPUTC(c, out); 1000121934Sharti break; 1001121934Sharti case CRP: /* ')' in arithmetic */ 1002121934Sharti if (parenlevel > 0) { 1003121934Sharti USTPUTC(c, out); 1004121934Sharti --parenlevel; 1005121934Sharti } else { 1006121934Sharti if (pgetc() == ')') { 1007121934Sharti if (--arinest == 0) { 1008121934Sharti USTPUTC(CTLENDARI, out); 1009121934Sharti syntax = prevsyntax; 1010121934Sharti } else 1011121934Sharti USTPUTC(')', out); 1012121934Sharti } else { 1013121934Sharti /* 1014121934Sharti * unbalanced parens 1015121934Sharti * (don't 2nd guess - no error) 1016121934Sharti */ 1017121934Sharti pungetc(); 1018121934Sharti USTPUTC(')', out); 1019121934Sharti } 1020121934Sharti } 1021121934Sharti break; 1022121934Sharti case CBQUOTE: /* '`' */ 1023121934Sharti PARSEBACKQOLD(); 1024121934Sharti break; 1025121934Sharti case CEOF: 1026121934Sharti goto endword; /* exit outer loop */ 1027121934Sharti default: 1028121934Sharti if (varnest == 0) 1029121934Sharti goto endword; /* exit outer loop */ 1030121934Sharti USTPUTC(c, out); 1031121934Sharti } 1032121934Sharti c = pgetc_macro(); 1033121934Sharti } 1034121934Sharti } 1035121934Shartiendword: 1036121934Sharti if (syntax == ARISYNTAX) 1037121934Sharti synerror("Missing '))'"); 1038121934Sharti if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 1039121934Sharti synerror("Unterminated quoted string"); 1040121934Sharti if (varnest != 0) { 1041121934Sharti startlinno = plinno; 1042121934Sharti synerror("Missing '}'"); 1043121934Sharti } 1044121934Sharti USTPUTC('\0', out); 1045121934Sharti len = out - stackblock(); 1046121934Sharti out = stackblock(); 1047121934Sharti if (eofmark == NULL) { 1048121934Sharti if ((c == '>' || c == '<') 1049121934Sharti && quotef == 0 1050121934Sharti && len <= 2 1051121934Sharti && (*out == '\0' || is_digit(*out))) { 1052121934Sharti PARSEREDIR(); 1053121934Sharti return lasttoken = TREDIR; 1054121934Sharti } else { 1055121934Sharti pungetc(); 1056121934Sharti } 1057121934Sharti } 1058121934Sharti quoteflag = quotef; 1059121934Sharti backquotelist = bqlist; 1060121934Sharti grabstackblock(len); 1061121934Sharti wordtext = out; 1062121934Sharti return lasttoken = TWORD; 1063121934Sharti/* end of readtoken routine */ 1064121934Sharti 1065121934Sharti 1066121934Sharti 1067121934Sharti/* 1068121934Sharti * Check to see whether we are at the end of the here document. When this 1069121934Sharti * is called, c is set to the first character of the next input line. If 1070121934Sharti * we are at the end of the here document, this routine sets the c to PEOF. 1071121934Sharti */ 1072121934Sharti 1073121934Sharticheckend: { 1074121934Sharti if (eofmark) { 1075121934Sharti if (striptabs) { 1076121934Sharti while (c == '\t') 1077121934Sharti c = pgetc(); 1078121934Sharti } 1079121934Sharti if (c == *eofmark) { 1080121934Sharti if (pfgets(line, sizeof line) != NULL) { 1081121934Sharti register char *p, *q; 1082121934Sharti 1083121934Sharti p = line; 1084121934Sharti for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 1085121934Sharti if (*p == '\n' && *q == '\0') { 1086121934Sharti c = PEOF; 1087121934Sharti plinno++; 1088121934Sharti needprompt = doprompt; 1089121934Sharti } else { 1090121934Sharti pushstring(line, strlen(line), NULL); 1091121934Sharti } 1092121934Sharti } 1093121934Sharti } 1094121934Sharti } 1095121934Sharti goto checkend_return; 1096121934Sharti} 1097121934Sharti 1098121934Sharti 1099121934Sharti/* 1100121934Sharti * Parse a redirection operator. The variable "out" points to a string 1101121934Sharti * specifying the fd to be redirected. The variable "c" contains the 1102121934Sharti * first character of the redirection operator. 1103121934Sharti */ 1104121934Sharti 1105121934Shartiparseredir: { 1106121934Sharti char fd = *out; 1107121934Sharti union node *np; 1108121934Sharti 1109121934Sharti np = (union node *)stalloc(sizeof (struct nfile)); 1110121934Sharti if (c == '>') { 1111121934Sharti np->nfile.fd = 1; 1112121934Sharti c = pgetc(); 1113121934Sharti if (c == '>') 1114121934Sharti np->type = NAPPEND; 1115121934Sharti else if (c == '&') 1116121934Sharti np->type = NTOFD; 1117121934Sharti else { 1118121934Sharti np->type = NTO; 1119121934Sharti pungetc(); 1120121934Sharti } 1121121934Sharti } else { /* c == '<' */ 1122121934Sharti np->nfile.fd = 0; 1123121934Sharti c = pgetc(); 1124121934Sharti if (c == '<') { 1125121934Sharti if (sizeof (struct nfile) != sizeof (struct nhere)) { 1126121934Sharti np = (union node *)stalloc(sizeof (struct nhere)); 1127121934Sharti np->nfile.fd = 0; 1128121934Sharti } 1129121934Sharti np->type = NHERE; 1130121934Sharti heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 1131121934Sharti heredoc->here = np; 1132121934Sharti if ((c = pgetc()) == '-') { 1133121934Sharti heredoc->striptabs = 1; 1134121934Sharti } else { 1135121934Sharti heredoc->striptabs = 0; 1136121934Sharti pungetc(); 1137121934Sharti } 1138121934Sharti } else if (c == '&') 1139121934Sharti np->type = NFROMFD; 1140121934Sharti else { 1141121934Sharti np->type = NFROM; 1142121934Sharti pungetc(); 1143121934Sharti } 1144121934Sharti } 1145121934Sharti if (fd != '\0') 1146121934Sharti np->nfile.fd = digit_val(fd); 1147121934Sharti redirnode = np; 1148121934Sharti goto parseredir_return; 1149121934Sharti} 1150121934Sharti 1151121934Sharti 1152121934Sharti/* 1153121934Sharti * Parse a substitution. At this point, we have read the dollar sign 1154121934Sharti * and nothing else. 1155121934Sharti */ 1156121934Sharti 1157121934Shartiparsesub: { 1158121934Sharti int subtype; 1159121934Sharti int typeloc; 1160121934Sharti int flags; 1161121934Sharti char *p; 1162121934Sharti#ifndef GDB_HACK 1163121934Sharti static const char types[] = "}-+?="; 1164121934Sharti#endif 1165121934Sharti int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ 1166121934Sharti 1167121934Sharti c = pgetc(); 1168121934Sharti if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 1169121934Sharti USTPUTC('$', out); 1170121934Sharti pungetc(); 1171121934Sharti } else if (c == '(') { /* $(command) or $((arith)) */ 1172121934Sharti if (pgetc() == '(') { 1173121934Sharti PARSEARITH(); 1174121934Sharti } else { 1175121934Sharti pungetc(); 1176121934Sharti PARSEBACKQNEW(); 1177121934Sharti } 1178121934Sharti } else { 1179121934Sharti USTPUTC(CTLVAR, out); 1180121934Sharti typeloc = out - stackblock(); 1181121934Sharti USTPUTC(VSNORMAL, out); 1182121934Sharti subtype = VSNORMAL; 1183121934Sharti if (c == '{') { 1184121934Sharti bracketed_name = 1; 1185121934Sharti c = pgetc(); 1186121934Sharti if (c == '#') { 1187121934Sharti if ((c = pgetc()) == '}') 1188121934Sharti c = '#'; 1189121934Sharti else 1190121934Sharti subtype = VSLENGTH; 1191121934Sharti } 1192121934Sharti else 1193121934Sharti subtype = 0; 1194121934Sharti } 1195121934Sharti if (is_name(c)) { 1196121934Sharti do { 1197121934Sharti STPUTC(c, out); 1198121934Sharti c = pgetc(); 1199121934Sharti } while (is_in_name(c)); 1200121934Sharti } else if (is_digit(c)) { 1201121934Sharti if (bracketed_name) { 1202121934Sharti do { 1203121934Sharti STPUTC(c, out); 1204121934Sharti c = pgetc(); 1205121934Sharti } while (is_digit(c)); 1206121934Sharti } else { 1207121934Sharti STPUTC(c, out); 1208121934Sharti c = pgetc(); 1209121934Sharti } 1210121934Sharti } else { 1211121934Sharti if (! is_special(c)) 1212121934Shartibadsub: synerror("Bad substitution"); 1213121934Sharti USTPUTC(c, out); 1214121934Sharti c = pgetc(); 1215121934Sharti } 1216121934Sharti STPUTC('=', out); 1217121934Sharti flags = 0; 1218121934Sharti if (subtype == 0) { 1219121934Sharti switch (c) { 1220121934Sharti case ':': 1221121934Sharti flags = VSNUL; 1222121934Sharti c = pgetc(); 1223121934Sharti /*FALLTHROUGH*/ 1224121934Sharti default: 1225121934Sharti p = strchr(types, c); 1226121934Sharti if (p == NULL) 1227121934Sharti goto badsub; 1228121934Sharti subtype = p - types + VSNORMAL; 1229121934Sharti break; 1230121934Sharti case '%': 1231121934Sharti case '#': 1232121934Sharti { 1233121934Sharti int cc = c; 1234121934Sharti subtype = c == '#' ? VSTRIMLEFT : 1235121934Sharti VSTRIMRIGHT; 1236121934Sharti c = pgetc(); 1237121934Sharti if (c == cc) 1238121934Sharti subtype++; 1239121934Sharti else 1240121934Sharti pungetc(); 1241121934Sharti break; 1242121934Sharti } 1243121934Sharti } 1244121934Sharti } else { 1245121934Sharti pungetc(); 1246121934Sharti } 1247121934Sharti if (dblquote || arinest) 1248121934Sharti flags |= VSQUOTE; 1249121934Sharti *(stackblock() + typeloc) = subtype | flags; 1250121934Sharti if (subtype != VSNORMAL) 1251121934Sharti varnest++; 1252121934Sharti } 1253121934Sharti goto parsesub_return; 1254121934Sharti} 1255121934Sharti 1256121934Sharti 1257121934Sharti/* 1258121934Sharti * Called to parse command substitutions. Newstyle is set if the command 1259121934Sharti * is enclosed inside $(...); nlpp is a pointer to the head of the linked 1260121934Sharti * list of commands (passed by reference), and savelen is the number of 1261121934Sharti * characters on the top of the stack which must be preserved. 1262121934Sharti */ 1263121934Sharti 1264121934Shartiparsebackq: { 1265121934Sharti struct nodelist **nlpp; 1266121934Sharti int savepbq; 1267121934Sharti union node *n; 1268121934Sharti char *volatile str; 1269121934Sharti struct jmploc jmploc; 1270121934Sharti struct jmploc *volatile savehandler; 1271121934Sharti int savelen; 1272121934Sharti int saveprompt; 1273121934Sharti#if __GNUC__ 1274121934Sharti /* Avoid longjmp clobbering */ 1275121934Sharti (void) &saveprompt; 1276121934Sharti#endif 1277121934Sharti 1278121934Sharti savepbq = parsebackquote; 1279121934Sharti if (setjmp(jmploc.loc)) { 1280121934Sharti if (str) 1281121934Sharti ckfree(str); 1282121934Sharti parsebackquote = 0; 1283121934Sharti handler = savehandler; 1284121934Sharti longjmp(handler->loc, 1); 1285121934Sharti } 1286121934Sharti INTOFF; 1287121934Sharti str = NULL; 1288121934Sharti savelen = out - stackblock(); 1289121934Sharti if (savelen > 0) { 1290121934Sharti str = ckmalloc(savelen); 1291121934Sharti memcpy(str, stackblock(), savelen); 1292121934Sharti } 1293121934Sharti savehandler = handler; 1294121934Sharti handler = &jmploc; 1295121934Sharti INTON; 1296121934Sharti if (oldstyle) { 1297121934Sharti /* We must read until the closing backquote, giving special 1298121934Sharti treatment to some slashes, and then push the string and 1299121934Sharti reread it as input, interpreting it normally. */ 1300121934Sharti register char *out; 1301121934Sharti register c; 1302121934Sharti int savelen; 1303121934Sharti char *str; 1304121934Sharti 1305121934Sharti 1306121934Sharti STARTSTACKSTR(out); 1307121934Sharti for (;;) { 1308121934Sharti if (needprompt) { 1309121934Sharti setprompt(2); 1310121934Sharti needprompt = 0; 1311121934Sharti } 1312121934Sharti switch (c = pgetc()) { 1313121934Sharti case '`': 1314121934Sharti goto done; 1315121934Sharti 1316121934Sharti case '\\': 1317121934Sharti if ((c = pgetc()) == '\n') { 1318121934Sharti plinno++; 1319121934Sharti if (doprompt) 1320121934Sharti setprompt(2); 1321121934Sharti else 1322121934Sharti setprompt(0); 1323121934Sharti /* 1324121934Sharti * If eating a newline, avoid putting 1325121934Sharti * the newline into the new character 1326121934Sharti * stream (via the STPUTC after the 1327121934Sharti * switch). 1328121934Sharti */ 1329121934Sharti continue; 1330121934Sharti } 1331121934Sharti if (c != '\\' && c != '`' && c != '$' 1332121934Sharti && (!dblquote || c != '"')) 1333121934Sharti STPUTC('\\', out); 1334121934Sharti break; 1335121934Sharti 1336121934Sharti case '\n': 1337121934Sharti plinno++; 1338121934Sharti needprompt = doprompt; 1339121934Sharti break; 1340121934Sharti 1341121934Sharti case PEOF: 1342121934Sharti startlinno = plinno; 1343121934Sharti synerror("EOF in backquote substitution"); 1344121934Sharti break; 1345121934Sharti 1346121934Sharti default: 1347121934Sharti break; 1348121934Sharti } 1349121934Sharti STPUTC(c, out); 1350121934Sharti } 1351121934Shartidone: 1352121934Sharti STPUTC('\0', out); 1353121934Sharti savelen = out - stackblock(); 1354121934Sharti if (savelen > 0) { 1355121934Sharti str = ckmalloc(savelen); 1356121934Sharti memcpy(str, stackblock(), savelen); 1357121934Sharti setinputstring(str, 1); 1358121934Sharti } 1359121934Sharti } 1360121934Sharti nlpp = &bqlist; 1361121934Sharti while (*nlpp) 1362121934Sharti nlpp = &(*nlpp)->next; 1363121934Sharti *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 1364121934Sharti (*nlpp)->next = NULL; 1365121934Sharti parsebackquote = oldstyle; 1366121934Sharti 1367121934Sharti if (oldstyle) { 1368121934Sharti saveprompt = doprompt; 1369121934Sharti doprompt = 0; 1370121934Sharti } 1371121934Sharti 1372 n = list(0); 1373 1374 if (oldstyle) 1375 doprompt = saveprompt; 1376 else { 1377 if (readtoken() != TRP) 1378 synexpect(TRP); 1379 } 1380 1381 (*nlpp)->n = n; 1382 if (oldstyle) { 1383 /* 1384 * Start reading from old file again, ignoring any pushed back 1385 * tokens left from the backquote parsing 1386 */ 1387 popfile(); 1388 tokpushback = 0; 1389 } 1390 while (stackblocksize() <= savelen) 1391 growstackblock(); 1392 STARTSTACKSTR(out); 1393 if (str) { 1394 memcpy(out, str, savelen); 1395 STADJUST(savelen, out); 1396 INTOFF; 1397 ckfree(str); 1398 str = NULL; 1399 INTON; 1400 } 1401 parsebackquote = savepbq; 1402 handler = savehandler; 1403 if (arinest || dblquote) 1404 USTPUTC(CTLBACKQ | CTLQUOTE, out); 1405 else 1406 USTPUTC(CTLBACKQ, out); 1407 if (oldstyle) 1408 goto parsebackq_oldreturn; 1409 else 1410 goto parsebackq_newreturn; 1411} 1412 1413/* 1414 * Parse an arithmetic expansion (indicate start of one and set state) 1415 */ 1416parsearith: { 1417 1418 if (++arinest == 1) { 1419 prevsyntax = syntax; 1420 syntax = ARISYNTAX; 1421 USTPUTC(CTLARI, out); 1422 } else { 1423 /* 1424 * we collapse embedded arithmetic expansion to 1425 * parenthesis, which should be equivalent 1426 */ 1427 USTPUTC('(', out); 1428 } 1429 goto parsearith_return; 1430} 1431 1432} /* end of readtoken */ 1433 1434 1435 1436#ifdef mkinit 1437RESET { 1438 tokpushback = 0; 1439 checkkwd = 0; 1440} 1441#endif 1442 1443/* 1444 * Returns true if the text contains nothing to expand (no dollar signs 1445 * or backquotes). 1446 */ 1447 1448STATIC int 1449noexpand(text) 1450 char *text; 1451 { 1452 register char *p; 1453 register char c; 1454 1455 p = text; 1456 while ((c = *p++) != '\0') { 1457 if (c == CTLESC) 1458 p++; 1459 else if (BASESYNTAX[c] == CCTL) 1460 return 0; 1461 } 1462 return 1; 1463} 1464 1465 1466/* 1467 * Return true if the argument is a legal variable name (a letter or 1468 * underscore followed by zero or more letters, underscores, and digits). 1469 */ 1470 1471int 1472goodname(name) 1473 char *name; 1474 { 1475 register char *p; 1476 1477 p = name; 1478 if (! is_name(*p)) 1479 return 0; 1480 while (*++p) { 1481 if (! is_in_name(*p)) 1482 return 0; 1483 } 1484 return 1; 1485} 1486 1487 1488/* 1489 * Called when an unexpected token is read during the parse. The argument 1490 * is the token that is expected, or -1 if more than one type of token can 1491 * occur at this point. 1492 */ 1493 1494STATIC void 1495synexpect(token) 1496 int token; 1497{ 1498 char msg[64]; 1499 1500 if (token >= 0) { 1501 fmtstr(msg, 64, "%s unexpected (expecting %s)", 1502 tokname[lasttoken], tokname[token]); 1503 } else { 1504 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 1505 } 1506 synerror(msg); 1507} 1508 1509 1510STATIC void 1511synerror(msg) 1512 char *msg; 1513 { 1514 if (commandname) 1515 outfmt(&errout, "%s: %d: ", commandname, startlinno); 1516 outfmt(&errout, "Syntax error: %s\n", msg); 1517 error((char *)NULL); 1518} 1519 1520STATIC void 1521setprompt(which) 1522 int which; 1523 { 1524 whichprompt = which; 1525 1526#ifndef NO_HISTORY 1527 if (!el) 1528#endif 1529 out2str(getprompt(NULL)); 1530} 1531 1532/* 1533 * called by editline -- any expansions to the prompt 1534 * should be added here. 1535 */ 1536char * 1537getprompt(unused) 1538 void *unused; 1539 { 1540 switch (whichprompt) { 1541 case 0: 1542 return ""; 1543 case 1: 1544 return ps1val(); 1545 case 2: 1546 return ps2val(); 1547 default: 1548 return "<internal prompt error>"; 1549 } 1550} 1551