parser.c revision 18202
1193323Sed/*- 2193323Sed * Copyright (c) 1991, 1993 3193323Sed * The Regents of the University of California. All rights reserved. 4193323Sed * 5193323Sed * This code is derived from software contributed to Berkeley by 6193323Sed * Kenneth Almquist. 7193323Sed * 8193323Sed * Redistribution and use in source and binary forms, with or without 9193323Sed * modification, are permitted provided that the following conditions 10193323Sed * are met: 11193323Sed * 1. Redistributions of source code must retain the above copyright 12193323Sed * notice, this list of conditions and the following disclaimer. 13193323Sed * 2. Redistributions in binary form must reproduce the above copyright 14193323Sed * notice, this list of conditions and the following disclaimer in the 15193323Sed * documentation and/or other materials provided with the distribution. 16193323Sed * 3. All advertising materials mentioning features or use of this software 17193323Sed * must display the following acknowledgement: 18193323Sed * This product includes software developed by the University of 19193323Sed * California, Berkeley and its contributors. 20193323Sed * 4. Neither the name of the University nor the names of its contributors 21193323Sed * may be used to endorse or promote products derived from this software 22198090Srdivacky * without specific prior written permission. 23193323Sed * 24193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34193323Sed * SUCH DAMAGE. 35193323Sed * 36193323Sed * $Id$ 37198090Srdivacky */ 38193323Sed 39198090Srdivacky#ifndef lint 40193323Sedstatic char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; 41193323Sed#endif /* not lint */ 42193323Sed 43193323Sed#include <stdlib.h> 44193323Sed 45193323Sed#include "shell.h" 46193323Sed#include "parser.h" 47193323Sed#include "nodes.h" 48193323Sed#include "expand.h" /* defines rmescapes() */ 49193323Sed#include "redir.h" /* defines copyfd() */ 50193323Sed#include "syntax.h" 51193323Sed#include "options.h" 52193323Sed#include "input.h" 53193323Sed#include "output.h" 54193323Sed#include "var.h" 55193323Sed#include "error.h" 56193323Sed#include "memalloc.h" 57193323Sed#include "mystring.h" 58193323Sed#include "alias.h" 59193323Sed#include "show.h" 60193323Sed#ifndef NO_HISTORY 61193323Sed#include "myhistedit.h" 62193323Sed#endif 63193323Sed 64193323Sed/* 65193323Sed * Shell command parser. 66193323Sed */ 67193323Sed 68193323Sed#define EOFMARKLEN 79 69193323Sed 70193323Sed/* values returned by readtoken */ 71193323Sed#include "token.h" 72193323Sed 73193323Sed 74193323Sed 75193323Sedstruct heredoc { 76193323Sed struct heredoc *next; /* next here document in list */ 77193323Sed union node *here; /* redirection node */ 78193323Sed char *eofmark; /* string indicating end of input */ 79193323Sed int striptabs; /* if set, strip leading tabs */ 80193323Sed}; 81193323Sed 82193323Sed 83193323Sed 84193323Sedstruct heredoc *heredoclist; /* list of here documents to read */ 85193323Sedint parsebackquote; /* nonzero if we are inside backquotes */ 86193323Sedint doprompt; /* if set, prompt the user */ 87193323Sedint needprompt; /* true if interactive and at start of line */ 88193323Sedint lasttoken; /* last token read */ 89193323SedMKINIT int tokpushback; /* last token pushed back */ 90193323Sedchar *wordtext; /* text of last word returned by readtoken */ 91193323SedMKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 92193323Sedstruct nodelist *backquotelist; 93193323Sedunion node *redirnode; 94193323Sedstruct heredoc *heredoc; 95193323Sedint quoteflag; /* set if (part of) last token was quoted */ 96193323Sedint startlinno; /* line # where last token started */ 97193323Sed 98193323Sed/* XXX When 'noaliases' is set to one, no alias expansion takes place. */ 99193323Sedstatic int noaliases = 0; 100193323Sed 101193323Sed#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ 102193323Sed#ifdef GDB_HACK 103193323Sedstatic const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; 104193323Sedstatic const char types[] = "}-+?="; 105193323Sed#endif 106193323Sed 107193323Sed 108193323SedSTATIC union node *list __P((int)); 109193323SedSTATIC union node *andor __P((void)); 110193323SedSTATIC union node *pipeline __P((void)); 111193323SedSTATIC union node *command __P((void)); 112193323SedSTATIC union node *simplecmd __P((union node **, union node *)); 113193323SedSTATIC union node *makename __P((void)); 114193323SedSTATIC void parsefname __P((void)); 115193323SedSTATIC void parseheredoc __P((void)); 116193323SedSTATIC int peektoken __P((void)); 117193323SedSTATIC int readtoken __P((void)); 118193323SedSTATIC int xxreadtoken __P((void)); 119193323SedSTATIC int readtoken1 __P((int, char const *, char *, int)); 120193323SedSTATIC int noexpand __P((char *)); 121193323SedSTATIC void synexpect __P((int)); 122193323SedSTATIC void synerror __P((char *)); 123193323SedSTATIC void setprompt __P((int)); 124193323Sed 125193323Sed 126193323Sed/* 127193323Sed * Read and parse a command. Returns NEOF on end of file. (NULL is a 128193323Sed * valid parse tree indicating a blank line.) 129193323Sed */ 130193323Sed 131193323Sedunion node * 132193323Sedparsecmd(interact) 133193323Sed int interact; 134193323Sed{ 135193323Sed int t; 136193323Sed 137193323Sed doprompt = interact; 138193323Sed if (doprompt) 139193323Sed setprompt(1); 140193323Sed else 141193323Sed setprompt(0); 142193323Sed needprompt = 0; 143193323Sed t = readtoken(); 144193323Sed if (t == TEOF) 145193323Sed return NEOF; 146193323Sed if (t == TNL) 147193323Sed return NULL; 148193323Sed tokpushback++; 149193323Sed return list(1); 150193323Sed} 151193323Sed 152193323Sed 153193323SedSTATIC union node * 154193323Sedlist(nlflag) 155193323Sed int nlflag; 156193323Sed{ 157193323Sed union node *n1, *n2, *n3; 158193323Sed int tok; 159193323Sed 160193323Sed checkkwd = 2; 161193323Sed if (nlflag == 0 && tokendlist[peektoken()]) 162193323Sed return NULL; 163193323Sed n1 = NULL; 164193323Sed for (;;) { 165193323Sed n2 = andor(); 166193323Sed tok = readtoken(); 167193323Sed if (tok == TBACKGND) { 168193323Sed if (n2->type == NCMD || n2->type == NPIPE) { 169193323Sed n2->ncmd.backgnd = 1; 170193323Sed } else if (n2->type == NREDIR) { 171193323Sed n2->type = NBACKGND; 172193323Sed } else { 173193323Sed n3 = (union node *)stalloc(sizeof (struct nredir)); 174193323Sed n3->type = NBACKGND; 175193323Sed n3->nredir.n = n2; 176193323Sed n3->nredir.redirect = NULL; 177193323Sed n2 = n3; 178193323Sed } 179193323Sed } 180193323Sed if (n1 == NULL) { 181193323Sed n1 = n2; 182193323Sed } 183193323Sed else { 184193323Sed n3 = (union node *)stalloc(sizeof (struct nbinary)); 185193323Sed n3->type = NSEMI; 186193323Sed n3->nbinary.ch1 = n1; 187193323Sed n3->nbinary.ch2 = n2; 188193323Sed n1 = n3; 189193323Sed } 190193323Sed switch (tok) { 191193323Sed case TBACKGND: 192193323Sed case TSEMI: 193193323Sed tok = readtoken(); 194193323Sed /* fall through */ 195193323Sed case TNL: 196193323Sed if (tok == TNL) { 197193323Sed parseheredoc(); 198193323Sed if (nlflag) 199193323Sed return n1; 200193323Sed } else { 201193323Sed tokpushback++; 202193323Sed } 203193323Sed checkkwd = 2; 204193323Sed if (tokendlist[peektoken()]) 205193323Sed return n1; 206193323Sed break; 207193323Sed case TEOF: 208193323Sed if (heredoclist) 209193323Sed parseheredoc(); 210193323Sed else 211193323Sed pungetc(); /* push back EOF on input */ 212193323Sed return n1; 213193323Sed default: 214193323Sed if (nlflag) 215193323Sed synexpect(-1); 216193323Sed tokpushback++; 217193323Sed return n1; 218193323Sed } 219198090Srdivacky } 220193323Sed} 221193323Sed 222193323Sed 223198090Srdivacky 224198090SrdivackySTATIC union node * 225193323Sedandor() { 226193323Sed union node *n1, *n2, *n3; 227193323Sed int t; 228193323Sed 229193323Sed n1 = pipeline(); 230193323Sed for (;;) { 231193323Sed if ((t = readtoken()) == TAND) { 232193323Sed t = NAND; 233193323Sed } else if (t == TOR) { 234193323Sed t = NOR; 235193323Sed } else { 236193323Sed tokpushback++; 237193323Sed return n1; 238193323Sed } 239193323Sed n2 = pipeline(); 240193323Sed n3 = (union node *)stalloc(sizeof (struct nbinary)); 241193323Sed n3->type = t; 242198090Srdivacky n3->nbinary.ch1 = n1; 243193323Sed n3->nbinary.ch2 = n2; 244198090Srdivacky n1 = n3; 245198090Srdivacky } 246193323Sed} 247193323Sed 248193323Sed 249193323Sed 250193323SedSTATIC union node * 251198090Srdivackypipeline() { 252198090Srdivacky union node *n1, *pipenode, *notnode; 253193323Sed struct nodelist *lp, *prev; 254193323Sed int negate = 0; 255193323Sed 256193323Sed TRACE(("pipeline: entered\n")); 257193323Sed while (readtoken() == TNOT) { 258193323Sed TRACE(("pipeline: TNOT recognized\n")); 259193323Sed negate = !negate; 260198090Srdivacky } 261193323Sed tokpushback++; 262193323Sed n1 = command(); 263193323Sed if (readtoken() == TPIPE) { 264193323Sed pipenode = (union node *)stalloc(sizeof (struct npipe)); 265193323Sed pipenode->type = NPIPE; 266193323Sed pipenode->npipe.backgnd = 0; 267193323Sed lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 268193323Sed pipenode->npipe.cmdlist = lp; 269193323Sed lp->n = n1; 270193323Sed do { 271193323Sed prev = lp; 272193323Sed lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 273193323Sed lp->n = command(); 274193323Sed prev->next = lp; 275193323Sed } while (readtoken() == TPIPE); 276193323Sed lp->next = NULL; 277193323Sed n1 = pipenode; 278193323Sed } 279193323Sed tokpushback++; 280193323Sed if (negate) { 281193323Sed notnode = (union node *)stalloc(sizeof (struct nnot)); 282193323Sed notnode->type = NNOT; 283193323Sed notnode->nnot.com = n1; 284193323Sed n1 = notnode; 285193323Sed } 286193323Sed return n1; 287193323Sed} 288193323Sed 289193323Sed 290193323Sed 291193323SedSTATIC union node * 292193323Sedcommand() { 293193323Sed union node *n1, *n2; 294193323Sed union node *ap, **app; 295193323Sed union node *cp, **cpp; 296193323Sed union node *redir, **rpp; 297193323Sed int t; 298193323Sed 299193323Sed checkkwd = 2; 300193323Sed redir = NULL; 301193323Sed n1 = NULL; 302193323Sed rpp = &redir; 303193323Sed /* Check for redirection which may precede command */ 304193323Sed while (readtoken() == TREDIR) { 305193323Sed *rpp = n2 = redirnode; 306193323Sed rpp = &n2->nfile.next; 307193323Sed parsefname(); 308193323Sed } 309193323Sed tokpushback++; 310193323Sed 311193323Sed switch (readtoken()) { 312193323Sed case TIF: 313193323Sed n1 = (union node *)stalloc(sizeof (struct nif)); 314193323Sed n1->type = NIF; 315193323Sed n1->nif.test = list(0); 316193323Sed if (readtoken() != TTHEN) 317193323Sed synexpect(TTHEN); 318193323Sed n1->nif.ifpart = list(0); 319193323Sed n2 = n1; 320193323Sed while (readtoken() == TELIF) { 321193323Sed n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 322193323Sed n2 = n2->nif.elsepart; 323193323Sed n2->type = NIF; 324193323Sed n2->nif.test = list(0); 325193323Sed if (readtoken() != TTHEN) 326193323Sed synexpect(TTHEN); 327193323Sed n2->nif.ifpart = list(0); 328193323Sed } 329193323Sed if (lasttoken == TELSE) 330193323Sed n2->nif.elsepart = list(0); 331193323Sed else { 332193323Sed n2->nif.elsepart = NULL; 333193323Sed tokpushback++; 334193323Sed } 335193323Sed if (readtoken() != TFI) 336193323Sed synexpect(TFI); 337193323Sed checkkwd = 1; 338193323Sed break; 339193323Sed case TWHILE: 340193323Sed case TUNTIL: { 341193323Sed int got; 342193323Sed n1 = (union node *)stalloc(sizeof (struct nbinary)); 343193323Sed n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 344193323Sed n1->nbinary.ch1 = list(0); 345193323Sed if ((got=readtoken()) != TDO) { 346193323SedTRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 347193323Sed synexpect(TDO); 348193323Sed } 349193323Sed n1->nbinary.ch2 = list(0); 350193323Sed if (readtoken() != TDONE) 351193323Sed synexpect(TDONE); 352193323Sed checkkwd = 1; 353193323Sed break; 354193323Sed } 355193323Sed case TFOR: 356193323Sed if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 357193323Sed synerror("Bad for loop variable"); 358193323Sed n1 = (union node *)stalloc(sizeof (struct nfor)); 359193323Sed n1->type = NFOR; 360193323Sed n1->nfor.var = wordtext; 361193323Sed if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 362193323Sed app = ≈ 363193323Sed while (readtoken() == TWORD) { 364193323Sed n2 = (union node *)stalloc(sizeof (struct narg)); 365193323Sed n2->type = NARG; 366193323Sed n2->narg.text = wordtext; 367193323Sed n2->narg.backquote = backquotelist; 368193323Sed *app = n2; 369193323Sed app = &n2->narg.next; 370193323Sed } 371193323Sed *app = NULL; 372193323Sed n1->nfor.args = ap; 373193323Sed if (lasttoken != TNL && lasttoken != TSEMI) 374193323Sed synexpect(-1); 375193323Sed } else { 376193323Sed#ifndef GDB_HACK 377193323Sed static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 378193323Sed '@', '=', '\0'}; 379193323Sed#endif 380193323Sed n2 = (union node *)stalloc(sizeof (struct narg)); 381193323Sed n2->type = NARG; 382193323Sed n2->narg.text = (char *)argvars; 383193323Sed n2->narg.backquote = NULL; 384193323Sed n2->narg.next = NULL; 385193323Sed n1->nfor.args = n2; 386193323Sed /* 387193323Sed * Newline or semicolon here is optional (but note 388193323Sed * that the original Bourne shell only allowed NL). 389193323Sed */ 390193323Sed if (lasttoken != TNL && lasttoken != TSEMI) 391193323Sed tokpushback++; 392193323Sed } 393193323Sed checkkwd = 2; 394193323Sed if ((t = readtoken()) == TDO) 395193323Sed t = TDONE; 396193323Sed else if (t == TBEGIN) 397193323Sed t = TEND; 398193323Sed else 399193323Sed synexpect(-1); 400193323Sed n1->nfor.body = list(0); 401198090Srdivacky if (readtoken() != t) 402193323Sed synexpect(t); 403193323Sed checkkwd = 1; 404193323Sed break; 405193323Sed case TCASE: 406193323Sed n1 = (union node *)stalloc(sizeof (struct ncase)); 407193323Sed n1->type = NCASE; 408193323Sed if (readtoken() != TWORD) 409193323Sed synexpect(TWORD); 410193323Sed n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 411193323Sed n2->type = NARG; 412193323Sed n2->narg.text = wordtext; 413193323Sed n2->narg.backquote = backquotelist; 414193323Sed n2->narg.next = NULL; 415193323Sed while (readtoken() == TNL); 416193323Sed if (lasttoken != TWORD || ! equal(wordtext, "in")) 417193323Sed synerror("expecting \"in\""); 418193323Sed cpp = &n1->ncase.cases; 419193323Sed noaliases = 1; /* turn off alias expansion */ 420193323Sed checkkwd = 2, readtoken(); 421193323Sed do { 422193323Sed *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 423193323Sed cp->type = NCLIST; 424193323Sed app = &cp->nclist.pattern; 425193323Sed for (;;) { 426193323Sed *app = ap = (union node *)stalloc(sizeof (struct narg)); 427193323Sed ap->type = NARG; 428193323Sed ap->narg.text = wordtext; 429193323Sed ap->narg.backquote = backquotelist; 430193323Sed if (checkkwd = 2, readtoken() != TPIPE) 431193323Sed break; 432193323Sed app = &ap->narg.next; 433193323Sed readtoken(); 434193323Sed } 435193323Sed ap->narg.next = NULL; 436193323Sed if (lasttoken != TRP) 437193323Sed noaliases = 0, synexpect(TRP); 438193323Sed cp->nclist.body = list(0); 439193323Sed 440193323Sed checkkwd = 2; 441193323Sed if ((t = readtoken()) != TESAC) { 442193323Sed if (t != TENDCASE) 443193323Sed noaliases = 0, synexpect(TENDCASE); 444193323Sed else 445193323Sed checkkwd = 2, readtoken(); 446193323Sed } 447193323Sed cpp = &cp->nclist.next; 448193323Sed } while(lasttoken != TESAC); 449193323Sed noaliases = 0; /* reset alias expansion */ 450193323Sed *cpp = NULL; 451193323Sed checkkwd = 1; 452193323Sed break; 453193323Sed case TLP: 454193323Sed n1 = (union node *)stalloc(sizeof (struct nredir)); 455193323Sed n1->type = NSUBSHELL; 456193323Sed n1->nredir.n = list(0); 457193323Sed n1->nredir.redirect = NULL; 458193323Sed if (readtoken() != TRP) 459193323Sed synexpect(TRP); 460193323Sed checkkwd = 1; 461193323Sed break; 462193323Sed case TBEGIN: 463193323Sed n1 = list(0); 464193323Sed if (readtoken() != TEND) 465193323Sed synexpect(TEND); 466193323Sed checkkwd = 1; 467193323Sed break; 468193323Sed /* Handle an empty command like other simple commands. */ 469193323Sed case TSEMI: 470193323Sed /* 471193323Sed * An empty command before a ; doesn't make much sense, and 472193323Sed * should certainly be disallowed in the case of `if ;'. 473193323Sed */ 474193323Sed if (!redir) 475193323Sed synexpect(-1); 476193323Sed case TAND: /* XXX merge query! */ 477193323Sed case TOR: /* XXX merge query! */ 478193323Sed case TNL: 479193323Sed case TEOF: 480193323Sed case TWORD: 481193323Sed case TRP: 482193323Sed tokpushback++; 483193323Sed return simplecmd(rpp, redir); 484193323Sed default: 485193323Sed synexpect(-1); 486193323Sed } 487193323Sed 488193323Sed /* Now check for redirection which may follow command */ 489193323Sed while (readtoken() == TREDIR) { 490193323Sed *rpp = n2 = redirnode; 491193323Sed rpp = &n2->nfile.next; 492193323Sed parsefname(); 493193323Sed } 494193323Sed tokpushback++; 495193323Sed *rpp = NULL; 496193323Sed if (redir) { 497193323Sed if (n1->type != NSUBSHELL) { 498193323Sed n2 = (union node *)stalloc(sizeof (struct nredir)); 499193323Sed n2->type = NREDIR; 500193323Sed n2->nredir.n = n1; 501193323Sed n1 = n2; 502193323Sed } 503193323Sed n1->nredir.redirect = redir; 504198090Srdivacky } 505193323Sed return n1; 506193323Sed} 507193323Sed 508193323Sed 509193323SedSTATIC union node * 510193323Sedsimplecmd(rpp, redir) 511193323Sed union node **rpp, *redir; 512193323Sed { 513193323Sed union node *args, **app; 514193323Sed union node **orig_rpp = rpp; 515193323Sed union node *n = NULL; 516193323Sed 517193323Sed /* If we don't have any redirections already, then we must reset */ 518193323Sed /* rpp to be the address of the local redir variable. */ 519193323Sed if (redir == 0) 520193323Sed rpp = &redir; 521193323Sed 522193323Sed args = NULL; 523193323Sed app = &args; 524193323Sed /* 525193323Sed * We save the incoming value, because we need this for shell 526193323Sed * functions. There can not be a redirect or an argument between 527193323Sed * the function name and the open parenthesis. 528193323Sed */ 529193323Sed orig_rpp = rpp; 530193323Sed 531193323Sed for (;;) { 532193323Sed if (readtoken() == TWORD) { 533193323Sed n = (union node *)stalloc(sizeof (struct narg)); 534193323Sed n->type = NARG; 535193323Sed n->narg.text = wordtext; 536193323Sed n->narg.backquote = backquotelist; 537193323Sed *app = n; 538193323Sed app = &n->narg.next; 539193323Sed } else if (lasttoken == TREDIR) { 540193323Sed *rpp = n = redirnode; 541193323Sed rpp = &n->nfile.next; 542193323Sed parsefname(); /* read name of redirection file */ 543193323Sed } else if (lasttoken == TLP && app == &args->narg.next 544193323Sed && rpp == orig_rpp) { 545193323Sed /* We have a function */ 546198090Srdivacky if (readtoken() != TRP) 547198090Srdivacky synexpect(TRP); 548198090Srdivacky#ifdef notdef 549198090Srdivacky if (! goodname(n->narg.text)) 550198090Srdivacky synerror("Bad function name"); 551198090Srdivacky#endif 552193323Sed n->type = NDEFUN; 553193323Sed n->narg.next = command(); 554193323Sed return n; 555193323Sed } else { 556193323Sed tokpushback++; 557193323Sed break; 558193323Sed } 559193323Sed } 560193323Sed *app = NULL; 561193323Sed *rpp = NULL; 562193323Sed n = (union node *)stalloc(sizeof (struct ncmd)); 563193323Sed n->type = NCMD; 564193323Sed n->ncmd.backgnd = 0; 565193323Sed n->ncmd.args = args; 566193323Sed n->ncmd.redirect = redir; 567193323Sed return n; 568193323Sed} 569193323Sed 570193323SedSTATIC union node * 571193323Sedmakename() { 572193323Sed union node *n; 573193323Sed 574193323Sed n = (union node *)stalloc(sizeof (struct narg)); 575193323Sed n->type = NARG; 576193323Sed n->narg.next = NULL; 577193323Sed n->narg.text = wordtext; 578193323Sed n->narg.backquote = backquotelist; 579193323Sed return n; 580193323Sed} 581193323Sed 582193323Sedvoid fixredir(n, text, err) 583193323Sed union node *n; 584193323Sed const char *text; 585193323Sed int err; 586193323Sed { 587193323Sed TRACE(("Fix redir %s %d\n", text, err)); 588193323Sed if (!err) 589193323Sed n->ndup.vname = NULL; 590193323Sed 591193323Sed if (is_digit(text[0]) && text[1] == '\0') 592193323Sed n->ndup.dupfd = digit_val(text[0]); 593193323Sed else if (text[0] == '-' && text[1] == '\0') 594193323Sed n->ndup.dupfd = -1; 595193323Sed else { 596193323Sed 597193323Sed if (err) 598193323Sed synerror("Bad fd number"); 599193323Sed else 600193323Sed n->ndup.vname = makename(); 601193323Sed } 602193323Sed} 603193323Sed 604193323Sed 605193323SedSTATIC void 606193323Sedparsefname() { 607193323Sed union node *n = redirnode; 608193323Sed 609193323Sed if (readtoken() != TWORD) 610193323Sed synexpect(-1); 611193323Sed if (n->type == NHERE) { 612193323Sed struct heredoc *here = heredoc; 613193323Sed struct heredoc *p; 614193323Sed int i; 615193323Sed 616193323Sed if (quoteflag == 0) 617193323Sed n->type = NXHERE; 618193323Sed TRACE(("Here document %d\n", n->type)); 619193323Sed if (here->striptabs) { 620193323Sed while (*wordtext == '\t') 621193323Sed wordtext++; 622193323Sed } 623198090Srdivacky if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 624198090Srdivacky synerror("Illegal eof marker for << redirection"); 625198090Srdivacky rmescapes(wordtext); 626198090Srdivacky here->eofmark = wordtext; 627198090Srdivacky here->next = NULL; 628193323Sed if (heredoclist == NULL) 629193323Sed heredoclist = here; 630193323Sed else { 631193323Sed for (p = heredoclist ; p->next ; p = p->next); 632193323Sed p->next = here; 633193323Sed } 634193323Sed } else if (n->type == NTOFD || n->type == NFROMFD) { 635193323Sed fixredir(n, wordtext, 0); 636193323Sed } else { 637193323Sed n->nfile.fname = makename(); 638193323Sed } 639193323Sed} 640193323Sed 641193323Sed 642193323Sed/* 643193323Sed * Input any here documents. 644193323Sed */ 645193323Sed 646193323SedSTATIC void 647193323Sedparseheredoc() { 648193323Sed struct heredoc *here; 649193323Sed union node *n; 650193323Sed 651193323Sed while (heredoclist) { 652193323Sed here = heredoclist; 653193323Sed heredoclist = here->next; 654193323Sed if (needprompt) { 655193323Sed setprompt(2); 656193323Sed needprompt = 0; 657193323Sed } 658193323Sed readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 659193323Sed here->eofmark, here->striptabs); 660193323Sed n = (union node *)stalloc(sizeof (struct narg)); 661193323Sed n->narg.type = NARG; 662193323Sed n->narg.next = NULL; 663193323Sed n->narg.text = wordtext; 664193323Sed n->narg.backquote = backquotelist; 665193323Sed here->here->nhere.doc = n; 666193323Sed } 667193323Sed} 668193323Sed 669193323SedSTATIC int 670193323Sedpeektoken() { 671193323Sed int t; 672193323Sed 673193323Sed t = readtoken(); 674193323Sed tokpushback++; 675193323Sed return (t); 676193323Sed} 677193323Sed 678193323SedSTATIC int xxreadtoken(); 679193323Sed 680193323SedSTATIC int 681193323Sedreadtoken() { 682193323Sed int t; 683193323Sed int savecheckkwd = checkkwd; 684193323Sed struct alias *ap; 685193323Sed#ifdef DEBUG 686193323Sed int alreadyseen = tokpushback; 687193323Sed#endif 688193323Sed 689193323Sed top: 690193323Sed t = xxreadtoken(); 691193323Sed 692193323Sed if (checkkwd) { 693198090Srdivacky /* 694198090Srdivacky * eat newlines 695198090Srdivacky */ 696198090Srdivacky if (checkkwd == 2) { 697198090Srdivacky checkkwd = 0; 698193323Sed while (t == TNL) { 699193323Sed parseheredoc(); 700193323Sed t = xxreadtoken(); 701193323Sed } 702193323Sed } else 703193323Sed checkkwd = 0; 704193323Sed /* 705193323Sed * check for keywords and aliases 706193323Sed */ 707193323Sed if (t == TWORD && !quoteflag) 708193323Sed { 709193323Sed register char * const *pp; 710193323Sed 711193323Sed for (pp = (char **)parsekwd; *pp; pp++) { 712193323Sed if (**pp == *wordtext && equal(*pp, wordtext)) 713193323Sed { 714193323Sed lasttoken = t = pp - parsekwd + KWDOFFSET; 715193323Sed TRACE(("keyword %s recognized\n", tokname[t])); 716193323Sed goto out; 717193323Sed } 718193323Sed } 719193323Sed if (noaliases == 0 && 720193323Sed (ap = lookupalias(wordtext, 1)) != NULL) { 721193323Sed pushstring(ap->val, strlen(ap->val), ap); 722193323Sed checkkwd = savecheckkwd; 723193323Sed goto top; 724193323Sed } 725193323Sed } 726193323Sedout: 727193323Sed checkkwd = 0; 728193323Sed } 729193323Sed#ifdef DEBUG 730193323Sed if (!alreadyseen) 731193323Sed TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 732193323Sed else 733193323Sed TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 734193323Sed#endif 735193323Sed return (t); 736193323Sed} 737193323Sed 738193323Sed 739193323Sed/* 740193323Sed * Read the next input token. 741193323Sed * If the token is a word, we set backquotelist to the list of cmds in 742193323Sed * backquotes. We set quoteflag to true if any part of the word was 743193323Sed * quoted. 744193323Sed * If the token is TREDIR, then we set redirnode to a structure containing 745193323Sed * the redirection. 746193323Sed * In all cases, the variable startlinno is set to the number of the line 747193323Sed * on which the token starts. 748193323Sed * 749193323Sed * [Change comment: here documents and internal procedures] 750193323Sed * [Readtoken shouldn't have any arguments. Perhaps we should make the 751193323Sed * word parsing code into a separate routine. In this case, readtoken 752193323Sed * doesn't need to have any internal procedures, but parseword does. 753193323Sed * We could also make parseoperator in essence the main routine, and 754193323Sed * have parseword (readtoken1?) handle both words and redirection.] 755193323Sed */ 756193323Sed 757193323Sed#define RETURN(token) return lasttoken = token 758193323Sed 759193323SedSTATIC int 760193323Sedxxreadtoken() { 761193323Sed register c; 762193323Sed 763193323Sed if (tokpushback) { 764193323Sed tokpushback = 0; 765193323Sed return lasttoken; 766193323Sed } 767193323Sed if (needprompt) { 768193323Sed setprompt(2); 769193323Sed needprompt = 0; 770193323Sed } 771193323Sed startlinno = plinno; 772193323Sed for (;;) { /* until token or start of word found */ 773193323Sed c = pgetc_macro(); 774193323Sed if (c == ' ' || c == '\t') 775193323Sed continue; /* quick check for white space first */ 776193323Sed switch (c) { 777193323Sed case ' ': case '\t': 778193323Sed continue; 779193323Sed case '#': 780193323Sed while ((c = pgetc()) != '\n' && c != PEOF); 781193323Sed pungetc(); 782193323Sed continue; 783193323Sed case '\\': 784193323Sed if (pgetc() == '\n') { 785193323Sed startlinno = ++plinno; 786193323Sed if (doprompt) 787193323Sed setprompt(2); 788193323Sed else 789193323Sed setprompt(0); 790193323Sed continue; 791193323Sed } 792193323Sed pungetc(); 793193323Sed goto breakloop; 794193323Sed case '\n': 795193323Sed plinno++; 796193323Sed needprompt = doprompt; 797193323Sed RETURN(TNL); 798193323Sed case PEOF: 799193323Sed RETURN(TEOF); 800193323Sed case '&': 801193323Sed if (pgetc() == '&') 802193323Sed RETURN(TAND); 803193323Sed pungetc(); 804193323Sed RETURN(TBACKGND); 805193323Sed case '|': 806193323Sed if (pgetc() == '|') 807193323Sed RETURN(TOR); 808193323Sed pungetc(); 809193323Sed RETURN(TPIPE); 810193323Sed case ';': 811193323Sed if (pgetc() == ';') 812193323Sed RETURN(TENDCASE); 813193323Sed pungetc(); 814193323Sed RETURN(TSEMI); 815198090Srdivacky case '(': 816193323Sed RETURN(TLP); 817193323Sed case ')': 818193323Sed RETURN(TRP); 819193323Sed default: 820193323Sed goto breakloop; 821193323Sed } 822193323Sed } 823193323Sedbreakloop: 824193323Sed return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 825193323Sed#undef RETURN 826193323Sed} 827193323Sed 828193323Sed 829193323Sed 830193323Sed/* 831193323Sed * If eofmark is NULL, read a word or a redirection symbol. If eofmark 832193323Sed * is not NULL, read a here document. In the latter case, eofmark is the 833193323Sed * word which marks the end of the document and striptabs is true if 834193323Sed * leading tabs should be stripped from the document. The argument firstc 835193323Sed * is the first character of the input token or document. 836193323Sed * 837193323Sed * Because C does not have internal subroutines, I have simulated them 838193323Sed * using goto's to implement the subroutine linkage. The following macros 839193323Sed * will run code that appears at the end of readtoken1. 840193323Sed */ 841193323Sed 842193323Sed#define CHECKEND() {goto checkend; checkend_return:;} 843193323Sed#define PARSEREDIR() {goto parseredir; parseredir_return:;} 844193323Sed#define PARSESUB() {goto parsesub; parsesub_return:;} 845193323Sed#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 846193323Sed#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 847193323Sed#define PARSEARITH() {goto parsearith; parsearith_return:;} 848193323Sed 849193323SedSTATIC int 850193323Sedreadtoken1(firstc, syntax, eofmark, striptabs) 851193323Sed int firstc; 852193323Sed char const *syntax; 853193323Sed char *eofmark; 854193323Sed int striptabs; 855193323Sed { 856193323Sed int c = firstc; 857193323Sed char *out; 858193323Sed int len; 859193323Sed char line[EOFMARKLEN + 1]; 860193323Sed struct nodelist *bqlist; 861193323Sed int quotef; 862193323Sed int dblquote; 863193323Sed int varnest; /* levels of variables expansion */ 864193323Sed int arinest; /* levels of arithmetic expansion */ 865193323Sed int parenlevel; /* levels of parens in arithmetic */ 866193323Sed int oldstyle; 867193323Sed char const *prevsyntax; /* syntax before arithmetic */ 868193323Sed#if __GNUC__ 869193323Sed /* Avoid longjmp clobbering */ 870193323Sed (void) &out; 871193323Sed (void) "ef; 872193323Sed (void) &dblquote; 873193323Sed (void) &varnest; 874193323Sed (void) &arinest; 875193323Sed (void) &parenlevel; 876193323Sed (void) &oldstyle; 877193323Sed (void) &prevsyntax; 878193323Sed (void) &syntax; 879193323Sed#endif 880193323Sed 881193323Sed startlinno = plinno; 882193323Sed dblquote = 0; 883193323Sed if (syntax == DQSYNTAX) 884193323Sed dblquote = 1; 885193323Sed quotef = 0; 886193323Sed bqlist = NULL; 887193323Sed varnest = 0; 888193323Sed arinest = 0; 889193323Sed parenlevel = 0; 890193323Sed 891193323Sed STARTSTACKSTR(out); 892198090Srdivacky loop: { /* for each line, until end of word */ 893193323Sed#if ATTY 894193323Sed if (c == '\034' && doprompt 895193323Sed && attyset() && ! equal(termval(), "emacs")) { 896193323Sed attyline(); 897193323Sed if (syntax == BASESYNTAX) 898193323Sed return readtoken(); 899193323Sed c = pgetc(); 900193323Sed goto loop; 901193323Sed } 902193323Sed#endif 903193323Sed CHECKEND(); /* set c to PEOF if at end of here document */ 904193323Sed for (;;) { /* until end of line or end of word */ 905193323Sed CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 906193323Sed switch(syntax[c]) { 907193323Sed case CNL: /* '\n' */ 908193323Sed if (syntax == BASESYNTAX) 909193323Sed goto endword; /* exit outer loop */ 910193323Sed USTPUTC(c, out); 911193323Sed plinno++; 912193323Sed if (doprompt) 913198090Srdivacky setprompt(2); 914193323Sed else 915193323Sed setprompt(0); 916193323Sed c = pgetc(); 917193323Sed goto loop; /* continue outer loop */ 918193323Sed case CWORD: 919193323Sed USTPUTC(c, out); 920193323Sed break; 921193323Sed case CCTL: 922193323Sed if (eofmark == NULL || dblquote) 923193323Sed USTPUTC(CTLESC, out); 924193323Sed USTPUTC(c, out); 925193323Sed break; 926193323Sed case CBACK: /* backslash */ 927193323Sed c = pgetc(); 928193323Sed if (c == PEOF) { 929193323Sed USTPUTC('\\', out); 930193323Sed pungetc(); 931193323Sed } else if (c == '\n') { 932193323Sed if (doprompt) 933193323Sed setprompt(2); 934193323Sed else 935193323Sed setprompt(0); 936193323Sed } else { 937198090Srdivacky if (dblquote && c != '\\' && c != '`' && c != '$' 938198090Srdivacky && (c != '"' || eofmark != NULL)) 939198090Srdivacky USTPUTC('\\', out); 940198090Srdivacky if (SQSYNTAX[c] == CCTL) 941198090Srdivacky USTPUTC(CTLESC, out); 942198090Srdivacky USTPUTC(c, out); 943198090Srdivacky quotef++; 944198090Srdivacky } 945193323Sed break; 946193323Sed case CSQUOTE: 947193323Sed syntax = SQSYNTAX; 948193323Sed break; 949193323Sed case CDQUOTE: 950193323Sed syntax = DQSYNTAX; 951193323Sed dblquote = 1; 952193323Sed break; 953198090Srdivacky case CENDQUOTE: 954193323Sed if (eofmark) { 955193323Sed USTPUTC(c, out); 956193323Sed } else { 957193323Sed if (arinest) 958193323Sed syntax = ARISYNTAX; 959193323Sed else 960193323Sed syntax = BASESYNTAX; 961193323Sed quotef++; 962193323Sed dblquote = 0; 963193323Sed } 964193323Sed break; 965193323Sed case CVAR: /* '$' */ 966193323Sed PARSESUB(); /* parse substitution */ 967193323Sed break; 968193323Sed case CENDVAR: /* '}' */ 969193323Sed if (varnest > 0) { 970193323Sed varnest--; 971193323Sed USTPUTC(CTLENDVAR, out); 972193323Sed } else { 973193323Sed USTPUTC(c, out); 974193323Sed } 975193323Sed break; 976193323Sed case CLP: /* '(' in arithmetic */ 977198090Srdivacky parenlevel++; 978193323Sed USTPUTC(c, out); 979193323Sed break; 980193323Sed case CRP: /* ')' in arithmetic */ 981193323Sed if (parenlevel > 0) { 982193323Sed USTPUTC(c, out); 983193323Sed --parenlevel; 984193323Sed } else { 985193323Sed if (pgetc() == ')') { 986193323Sed if (--arinest == 0) { 987193323Sed USTPUTC(CTLENDARI, out); 988193323Sed syntax = prevsyntax; 989193323Sed } else 990193323Sed USTPUTC(')', out); 991193323Sed } else { 992193323Sed /* 993193323Sed * unbalanced parens 994193323Sed * (don't 2nd guess - no error) 995193323Sed */ 996193323Sed pungetc(); 997193323Sed USTPUTC(')', out); 998193323Sed } 999193323Sed } 1000193323Sed break; 1001193323Sed case CBQUOTE: /* '`' */ 1002193323Sed PARSEBACKQOLD(); 1003193323Sed break; 1004193323Sed case CEOF: 1005193323Sed goto endword; /* exit outer loop */ 1006193323Sed default: 1007193323Sed if (varnest == 0) 1008193323Sed goto endword; /* exit outer loop */ 1009193323Sed USTPUTC(c, out); 1010193323Sed } 1011193323Sed c = pgetc_macro(); 1012193323Sed } 1013193323Sed } 1014193323Sedendword: 1015193323Sed if (syntax == ARISYNTAX) 1016193323Sed synerror("Missing '))'"); 1017193323Sed if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 1018193323Sed synerror("Unterminated quoted string"); 1019193323Sed if (varnest != 0) { 1020193323Sed startlinno = plinno; 1021193323Sed synerror("Missing '}'"); 1022193323Sed } 1023193323Sed USTPUTC('\0', out); 1024193323Sed len = out - stackblock(); 1025193323Sed out = stackblock(); 1026193323Sed if (eofmark == NULL) { 1027193323Sed if ((c == '>' || c == '<') 1028193323Sed && quotef == 0 1029193323Sed && len <= 2 1030193323Sed && (*out == '\0' || is_digit(*out))) { 1031193323Sed PARSEREDIR(); 1032193323Sed return lasttoken = TREDIR; 1033193323Sed } else { 1034193323Sed pungetc(); 1035193323Sed } 1036193323Sed } 1037193323Sed quoteflag = quotef; 1038193323Sed backquotelist = bqlist; 1039193323Sed grabstackblock(len); 1040193323Sed wordtext = out; 1041193323Sed return lasttoken = TWORD; 1042193323Sed/* end of readtoken routine */ 1043193323Sed 1044193323Sed 1045193323Sed 1046193323Sed/* 1047193323Sed * Check to see whether we are at the end of the here document. When this 1048193323Sed * is called, c is set to the first character of the next input line. If 1049193323Sed * we are at the end of the here document, this routine sets the c to PEOF. 1050193323Sed */ 1051193323Sed 1052193323Sedcheckend: { 1053193323Sed if (eofmark) { 1054193323Sed if (striptabs) { 1055193323Sed while (c == '\t') 1056193323Sed c = pgetc(); 1057193323Sed } 1058193323Sed if (c == *eofmark) { 1059193323Sed if (pfgets(line, sizeof line) != NULL) { 1060193323Sed register char *p, *q; 1061193323Sed 1062193323Sed p = line; 1063193323Sed for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 1064193323Sed if (*p == '\n' && *q == '\0') { 1065193323Sed c = PEOF; 1066193323Sed plinno++; 1067193323Sed needprompt = doprompt; 1068193323Sed } else { 1069193323Sed pushstring(line, strlen(line), NULL); 1070193323Sed } 1071193323Sed } 1072193323Sed } 1073193323Sed } 1074193323Sed goto checkend_return; 1075193323Sed} 1076193323Sed 1077193323Sed 1078193323Sed/* 1079193323Sed * Parse a redirection operator. The variable "out" points to a string 1080193323Sed * specifying the fd to be redirected. The variable "c" contains the 1081193323Sed * first character of the redirection operator. 1082193323Sed */ 1083193323Sed 1084193323Sedparseredir: { 1085193323Sed char fd = *out; 1086193323Sed union node *np; 1087193323Sed 1088193323Sed np = (union node *)stalloc(sizeof (struct nfile)); 1089193323Sed if (c == '>') { 1090193323Sed np->nfile.fd = 1; 1091193323Sed c = pgetc(); 1092193323Sed if (c == '>') 1093193323Sed np->type = NAPPEND; 1094193323Sed else if (c == '&') 1095193323Sed np->type = NTOFD; 1096193323Sed else { 1097193323Sed np->type = NTO; 1098193323Sed pungetc(); 1099193323Sed } 1100198090Srdivacky } else { /* c == '<' */ 1101193323Sed np->nfile.fd = 0; 1102193323Sed c = pgetc(); 1103193323Sed if (c == '<') { 1104193323Sed if (sizeof (struct nfile) != sizeof (struct nhere)) { 1105193323Sed np = (union node *)stalloc(sizeof (struct nhere)); 1106193323Sed np->nfile.fd = 0; 1107193323Sed } 1108193323Sed np->type = NHERE; 1109193323Sed heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 1110193323Sed heredoc->here = np; 1111193323Sed if ((c = pgetc()) == '-') { 1112193323Sed heredoc->striptabs = 1; 1113193323Sed } else { 1114193323Sed heredoc->striptabs = 0; 1115193323Sed pungetc(); 1116193323Sed } 1117193323Sed } else if (c == '&') 1118193323Sed np->type = NFROMFD; 1119193323Sed else { 1120193323Sed np->type = NFROM; 1121193323Sed pungetc(); 1122193323Sed } 1123193323Sed } 1124193323Sed if (fd != '\0') 1125193323Sed np->nfile.fd = digit_val(fd); 1126193323Sed redirnode = np; 1127193323Sed goto parseredir_return; 1128193323Sed} 1129193323Sed 1130193323Sed 1131193323Sed/* 1132193323Sed * Parse a substitution. At this point, we have read the dollar sign 1133193323Sed * and nothing else. 1134193323Sed */ 1135193323Sed 1136193323Sedparsesub: { 1137193323Sed int subtype; 1138193323Sed int typeloc; 1139193323Sed int flags; 1140193323Sed char *p; 1141193323Sed#ifndef GDB_HACK 1142193323Sed static const char types[] = "}-+?="; 1143193323Sed#endif 1144193323Sed int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ 1145193323Sed 1146193323Sed c = pgetc(); 1147193323Sed if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 1148193323Sed USTPUTC('$', out); 1149193323Sed pungetc(); 1150193323Sed } else if (c == '(') { /* $(command) or $((arith)) */ 1151193323Sed if (pgetc() == '(') { 1152193323Sed PARSEARITH(); 1153193323Sed } else { 1154193323Sed pungetc(); 1155193323Sed PARSEBACKQNEW(); 1156193323Sed } 1157193323Sed } else { 1158193323Sed USTPUTC(CTLVAR, out); 1159193323Sed typeloc = out - stackblock(); 1160193323Sed USTPUTC(VSNORMAL, out); 1161193323Sed subtype = VSNORMAL; 1162198090Srdivacky if (c == '{') { 1163193323Sed bracketed_name = 1; 1164193323Sed c = pgetc(); 1165193323Sed if (c == '#') { 1166193323Sed if ((c = pgetc()) == '}') 1167193323Sed c = '#'; 1168193323Sed else 1169193323Sed subtype = VSLENGTH; 1170193323Sed } 1171193323Sed else 1172193323Sed subtype = 0; 1173193323Sed } 1174193323Sed if (is_name(c)) { 1175193323Sed do { 1176193323Sed STPUTC(c, out); 1177193323Sed c = pgetc(); 1178193323Sed } while (is_in_name(c)); 1179193323Sed } else if (is_digit(c)) { 1180193323Sed if (bracketed_name) { 1181193323Sed do { 1182193323Sed STPUTC(c, out); 1183193323Sed c = pgetc(); 1184193323Sed } while (is_digit(c)); 1185193323Sed } else { 1186193323Sed STPUTC(c, out); 1187193323Sed c = pgetc(); 1188193323Sed } 1189193323Sed } else { 1190193323Sed if (! is_special(c)) 1191193323Sedbadsub: synerror("Bad substitution"); 1192193323Sed USTPUTC(c, out); 1193193323Sed c = pgetc(); 1194193323Sed } 1195193323Sed STPUTC('=', out); 1196193323Sed flags = 0; 1197193323Sed if (subtype == 0) { 1198193323Sed switch (c) { 1199193323Sed case ':': 1200193323Sed flags = VSNUL; 1201193323Sed c = pgetc(); 1202193323Sed /*FALLTHROUGH*/ 1203193323Sed default: 1204193323Sed p = strchr(types, c); 1205193323Sed if (p == NULL) 1206193323Sed goto badsub; 1207193323Sed subtype = p - types + VSNORMAL; 1208193323Sed break; 1209193323Sed case '%': 1210193323Sed case '#': 1211193323Sed { 1212193323Sed int cc = c; 1213193323Sed subtype = c == '#' ? VSTRIMLEFT : 1214193323Sed VSTRIMRIGHT; 1215193323Sed c = pgetc(); 1216193323Sed if (c == cc) 1217193323Sed subtype++; 1218193323Sed else 1219193323Sed pungetc(); 1220193323Sed break; 1221193323Sed } 1222193323Sed } 1223193323Sed } else { 1224193323Sed pungetc(); 1225193323Sed } 1226193323Sed if (dblquote || arinest) 1227193323Sed flags |= VSQUOTE; 1228193323Sed *(stackblock() + typeloc) = subtype | flags; 1229193323Sed if (subtype != VSNORMAL) 1230193323Sed varnest++; 1231193323Sed } 1232193323Sed goto parsesub_return; 1233193323Sed} 1234193323Sed 1235198090Srdivacky 1236193323Sed/* 1237193323Sed * Called to parse command substitutions. Newstyle is set if the command 1238193323Sed * is enclosed inside $(...); nlpp is a pointer to the head of the linked 1239193323Sed * list of commands (passed by reference), and savelen is the number of 1240193323Sed * characters on the top of the stack which must be preserved. 1241193323Sed */ 1242193323Sed 1243193323Sedparsebackq: { 1244193323Sed struct nodelist **nlpp; 1245193323Sed int savepbq; 1246193323Sed union node *n; 1247193323Sed char *volatile str; 1248193323Sed struct jmploc jmploc; 1249193323Sed struct jmploc *volatile savehandler; 1250193323Sed int savelen; 1251193323Sed 1252193323Sed savepbq = parsebackquote; 1253193323Sed if (setjmp(jmploc.loc)) { 1254193323Sed if (str) 1255193323Sed ckfree(str); 1256193323Sed parsebackquote = 0; 1257193323Sed handler = savehandler; 1258193323Sed longjmp(handler->loc, 1); 1259193323Sed } 1260193323Sed INTOFF; 1261193323Sed str = NULL; 1262193323Sed savelen = out - stackblock(); 1263193323Sed if (savelen > 0) { 1264193323Sed str = ckmalloc(savelen); 1265193323Sed memcpy(str, stackblock(), savelen); 1266193323Sed } 1267193323Sed savehandler = handler; 1268193323Sed handler = &jmploc; 1269193323Sed INTON; 1270193323Sed if (oldstyle) { 1271193323Sed /* We must read until the closing backquote, giving special 1272193323Sed treatment to some slashes, and then push the string and 1273193323Sed reread it as input, interpreting it normally. */ 1274193323Sed register char *out; 1275193323Sed register c; 1276193323Sed int savelen; 1277193323Sed char *str; 1278193323Sed 1279193323Sed STARTSTACKSTR(out); 1280193323Sed while ((c = pgetc ()) != '`') { 1281193323Sed if (c == PEOF) { 1282193323Sed startlinno = plinno; 1283193323Sed synerror("EOF in backquote substitution"); 1284193323Sed } 1285193323Sed if (c == '\\') { 1286193323Sed c = pgetc (); 1287193323Sed if (c != '\\' && c != '`' && c != '$' 1288193323Sed && (!dblquote || c != '"')) 1289193323Sed STPUTC('\\', out); 1290193323Sed } 1291193323Sed STPUTC(c, out); 1292193323Sed } 1293193323Sed STPUTC('\0', out); 1294193323Sed savelen = out - stackblock(); 1295193323Sed if (savelen > 0) { 1296193323Sed str = ckmalloc(savelen); 1297193323Sed memcpy(str, stackblock(), savelen); 1298193323Sed setinputstring(str, 1); 1299193323Sed } 1300193323Sed } 1301193323Sed nlpp = &bqlist; 1302193323Sed while (*nlpp) 1303193323Sed nlpp = &(*nlpp)->next; 1304193323Sed *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 1305193323Sed (*nlpp)->next = NULL; 1306193323Sed parsebackquote = oldstyle; 1307193323Sed n = list(0); 1308193323Sed if (!oldstyle && (readtoken() != TRP)) 1309193323Sed synexpect(TRP); 1310193323Sed (*nlpp)->n = n; 1311193323Sed /* Start reading from old file again. */ 1312193323Sed if (oldstyle) 1313193323Sed popfile(); 1314193323Sed while (stackblocksize() <= savelen) 1315193323Sed growstackblock(); 1316193323Sed STARTSTACKSTR(out); 1317193323Sed if (str) { 1318193323Sed memcpy(out, str, savelen); 1319193323Sed STADJUST(savelen, out); 1320193323Sed INTOFF; 1321193323Sed ckfree(str); 1322193323Sed str = NULL; 1323193323Sed INTON; 1324193323Sed } 1325193323Sed parsebackquote = savepbq; 1326193323Sed handler = savehandler; 1327193323Sed if (arinest || dblquote) 1328198090Srdivacky USTPUTC(CTLBACKQ | CTLQUOTE, out); 1329193323Sed else 1330193323Sed USTPUTC(CTLBACKQ, out); 1331193323Sed if (oldstyle) 1332193323Sed goto parsebackq_oldreturn; 1333193323Sed else 1334193323Sed goto parsebackq_newreturn; 1335193323Sed} 1336193323Sed 1337193323Sed/* 1338193323Sed * Parse an arithmetic expansion (indicate start of one and set state) 1339193323Sed */ 1340193323Sedparsearith: { 1341193323Sed 1342193323Sed if (++arinest == 1) { 1343193323Sed prevsyntax = syntax; 1344193323Sed syntax = ARISYNTAX; 1345193323Sed USTPUTC(CTLARI, out); 1346193323Sed } else { 1347193323Sed /* 1348193323Sed * we collapse embedded arithmetic expansion to 1349193323Sed * parenthesis, which should be equivalent 1350193323Sed */ 1351193323Sed USTPUTC('(', out); 1352193323Sed } 1353193323Sed goto parsearith_return; 1354193323Sed} 1355193323Sed 1356193323Sed} /* end of readtoken */ 1357193323Sed 1358193323Sed 1359193323Sed 1360193323Sed#ifdef mkinit 1361193323SedRESET { 1362193323Sed tokpushback = 0; 1363193323Sed checkkwd = 0; 1364193323Sed} 1365193323Sed#endif 1366193323Sed 1367193323Sed/* 1368193323Sed * Returns true if the text contains nothing to expand (no dollar signs 1369193323Sed * or backquotes). 1370193323Sed */ 1371193323Sed 1372193323SedSTATIC int 1373193323Sednoexpand(text) 1374193323Sed char *text; 1375193323Sed { 1376193323Sed register char *p; 1377193323Sed register char c; 1378193323Sed 1379193323Sed p = text; 1380193323Sed while ((c = *p++) != '\0') { 1381193323Sed if (c == CTLESC) 1382193323Sed p++; 1383193323Sed else if (BASESYNTAX[c] == CCTL) 1384193323Sed return 0; 1385193323Sed } 1386193323Sed return 1; 1387193323Sed} 1388193323Sed 1389193323Sed 1390193323Sed/* 1391193323Sed * Return true if the argument is a legal variable name (a letter or 1392193323Sed * underscore followed by zero or more letters, underscores, and digits). 1393193323Sed */ 1394193323Sed 1395193323Sedint 1396193323Sedgoodname(name) 1397193323Sed char *name; 1398193323Sed { 1399193323Sed register char *p; 1400193323Sed 1401193323Sed p = name; 1402193323Sed if (! is_name(*p)) 1403193323Sed return 0; 1404193323Sed while (*++p) { 1405193323Sed if (! is_in_name(*p)) 1406193323Sed return 0; 1407193323Sed } 1408193323Sed return 1; 1409193323Sed} 1410193323Sed 1411193323Sed 1412193323Sed/* 1413193323Sed * Called when an unexpected token is read during the parse. The argument 1414193323Sed * is the token that is expected, or -1 if more than one type of token can 1415198090Srdivacky * occur at this point. 1416193323Sed */ 1417193323Sed 1418193323SedSTATIC void 1419193323Sedsynexpect(token) 1420193323Sed int token; 1421193323Sed{ 1422193323Sed char msg[64]; 1423193323Sed 1424193323Sed if (token >= 0) { 1425193323Sed fmtstr(msg, 64, "%s unexpected (expecting %s)", 1426193323Sed tokname[lasttoken], tokname[token]); 1427193323Sed } else { 1428193323Sed fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 1429193323Sed } 1430193323Sed synerror(msg); 1431193323Sed} 1432193323Sed 1433193323Sed 1434193323SedSTATIC void 1435198090Srdivackysynerror(msg) 1436193323Sed char *msg; 1437193323Sed { 1438193323Sed if (commandname) 1439193323Sed outfmt(&errout, "%s: %d: ", commandname, startlinno); 1440193323Sed outfmt(&errout, "Syntax error: %s\n", msg); 1441193323Sed error((char *)NULL); 1442193323Sed} 1443193323Sed 1444193323SedSTATIC void 1445193323Sedsetprompt(which) 1446193323Sed int which; 1447193323Sed { 1448193323Sed whichprompt = which; 1449193323Sed 1450193323Sed#ifndef NO_HISTORY 1451193323Sed if (!el) 1452193323Sed#endif 1453193323Sed out2str(getprompt(NULL)); 1454193323Sed} 1455193323Sed 1456193323Sed/* 1457193323Sed * called by editline -- any expansions to the prompt 1458193323Sed * should be added here. 1459193323Sed */ 1460193323Sedchar * 1461193323Sedgetprompt(unused) 1462193323Sed void *unused; 1463193323Sed { 1464193323Sed switch (whichprompt) { 1465193323Sed case 0: 1466193323Sed return ""; 1467198090Srdivacky case 1: 1468193323Sed return ps1val(); 1469193323Sed case 2: 1470193323Sed return ps2val(); 1471193323Sed default: 1472193323Sed return "<internal prompt error>"; 1473193323Sed } 1474193323Sed} 1475193323Sed