147139Sbostic /*- 260698Sbostic * Copyright (c) 1991, 1993 360698Sbostic * The Regents of the University of California. All rights reserved. 447139Sbostic * 547139Sbostic * This code is derived from software contributed to Berkeley by 647139Sbostic * Kenneth Almquist. 747139Sbostic * 847139Sbostic * %sccs.include.redist.c% 947139Sbostic */ 1047139Sbostic 1147139Sbostic #ifndef lint 12*69272Schristos static char sccsid[] = "@(#)parser.c 8.6 (Berkeley) 05/04/95"; 1347139Sbostic #endif /* not lint */ 1447139Sbostic 15*69272Schristos #include <stdlib.h> 16*69272Schristos 1747139Sbostic #include "shell.h" 1847139Sbostic #include "parser.h" 1947139Sbostic #include "nodes.h" 2047139Sbostic #include "expand.h" /* defines rmescapes() */ 2147139Sbostic #include "redir.h" /* defines copyfd() */ 2247139Sbostic #include "syntax.h" 2347139Sbostic #include "options.h" 2447139Sbostic #include "input.h" 2547139Sbostic #include "output.h" 2647139Sbostic #include "var.h" 2747139Sbostic #include "error.h" 2847139Sbostic #include "memalloc.h" 2947139Sbostic #include "mystring.h" 3054322Smarc #include "alias.h" 31*69272Schristos #include "show.h" 32*69272Schristos #ifndef NO_HISTORY 3354330Smarc #include "myhistedit.h" 34*69272Schristos #endif 3547139Sbostic 3647139Sbostic /* 3747139Sbostic * Shell command parser. 3847139Sbostic */ 3947139Sbostic 4047139Sbostic #define EOFMARKLEN 79 4147139Sbostic 4247139Sbostic /* values returned by readtoken */ 4347139Sbostic #include "token.def" 4447139Sbostic 4547139Sbostic 4647139Sbostic 4747139Sbostic struct heredoc { 4847139Sbostic struct heredoc *next; /* next here document in list */ 4947139Sbostic union node *here; /* redirection node */ 5047139Sbostic char *eofmark; /* string indicating end of input */ 5147139Sbostic int striptabs; /* if set, strip leading tabs */ 5247139Sbostic }; 5347139Sbostic 5447139Sbostic 5547139Sbostic 5647139Sbostic struct heredoc *heredoclist; /* list of here documents to read */ 5747139Sbostic int parsebackquote; /* nonzero if we are inside backquotes */ 5847139Sbostic int doprompt; /* if set, prompt the user */ 5947139Sbostic int needprompt; /* true if interactive and at start of line */ 6047139Sbostic int lasttoken; /* last token read */ 6147139Sbostic MKINIT int tokpushback; /* last token pushed back */ 6247139Sbostic char *wordtext; /* text of last word returned by readtoken */ 6354322Smarc MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 6447139Sbostic struct nodelist *backquotelist; 6547139Sbostic union node *redirnode; 6647139Sbostic struct heredoc *heredoc; 6747139Sbostic int quoteflag; /* set if (part of) last token was quoted */ 6847139Sbostic int startlinno; /* line # where last token started */ 6947139Sbostic 7047139Sbostic 7147139Sbostic #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ 7247139Sbostic #ifdef GDB_HACK 7347139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; 7447139Sbostic static const char types[] = "}-+?="; 7547139Sbostic #endif 7647139Sbostic 7747139Sbostic 7847981Smarc STATIC union node *list __P((int)); 7947981Smarc STATIC union node *andor __P((void)); 8047981Smarc STATIC union node *pipeline __P((void)); 8147981Smarc STATIC union node *command __P((void)); 8260296Smarc STATIC union node *simplecmd __P((union node **, union node *)); 83*69272Schristos STATIC union node *makename __P((void)); 8447981Smarc STATIC void parsefname __P((void)); 8547981Smarc STATIC void parseheredoc __P((void)); 86*69272Schristos STATIC int peektoken __P((void)); 8747981Smarc STATIC int readtoken __P((void)); 88*69272Schristos STATIC int xxreadtoken __P((void)); 8947981Smarc STATIC int readtoken1 __P((int, char const *, char *, int)); 9047981Smarc STATIC int noexpand __P((char *)); 9147981Smarc STATIC void synexpect __P((int)); 9247981Smarc STATIC void synerror __P((char *)); 93*69272Schristos STATIC void setprompt __P((int)); 9447139Sbostic 95*69272Schristos 9647139Sbostic /* 9747139Sbostic * Read and parse a command. Returns NEOF on end of file. (NULL is a 9847139Sbostic * valid parse tree indicating a blank line.) 9947139Sbostic */ 10047139Sbostic 10147139Sbostic union node * 102*69272Schristos parsecmd(interact) 103*69272Schristos int interact; 104*69272Schristos { 10547139Sbostic int t; 10647139Sbostic 10747139Sbostic doprompt = interact; 10847139Sbostic if (doprompt) 10954322Smarc setprompt(1); 11054322Smarc else 11154322Smarc setprompt(0); 11247139Sbostic needprompt = 0; 11354322Smarc t = readtoken(); 11454322Smarc if (t == TEOF) 11547139Sbostic return NEOF; 11647139Sbostic if (t == TNL) 11747139Sbostic return NULL; 11847139Sbostic tokpushback++; 11947139Sbostic return list(1); 12047139Sbostic } 12147139Sbostic 12247139Sbostic 12347139Sbostic STATIC union node * 124*69272Schristos list(nlflag) 125*69272Schristos int nlflag; 126*69272Schristos { 12747139Sbostic union node *n1, *n2, *n3; 12868927Sbostic int tok; 12947139Sbostic 13047981Smarc checkkwd = 2; 13147981Smarc if (nlflag == 0 && tokendlist[peektoken()]) 13247139Sbostic return NULL; 13368927Sbostic n1 = NULL; 13447139Sbostic for (;;) { 13568927Sbostic n2 = andor(); 13668927Sbostic tok = readtoken(); 13768927Sbostic if (tok == TBACKGND) { 13868927Sbostic if (n2->type == NCMD || n2->type == NPIPE) { 13968927Sbostic n2->ncmd.backgnd = 1; 14068927Sbostic } else if (n2->type == NREDIR) { 14168927Sbostic n2->type = NBACKGND; 14247139Sbostic } else { 14347139Sbostic n3 = (union node *)stalloc(sizeof (struct nredir)); 14447139Sbostic n3->type = NBACKGND; 14568927Sbostic n3->nredir.n = n2; 14647139Sbostic n3->nredir.redirect = NULL; 14768927Sbostic n2 = n3; 14847139Sbostic } 14968927Sbostic } 15068927Sbostic if (n1 == NULL) { 15168927Sbostic n1 = n2; 15268927Sbostic } 15368927Sbostic else { 15468927Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 15568927Sbostic n3->type = NSEMI; 15668927Sbostic n3->nbinary.ch1 = n1; 15768927Sbostic n3->nbinary.ch2 = n2; 15868927Sbostic n1 = n3; 15968927Sbostic } 16068927Sbostic switch (tok) { 16168927Sbostic case TBACKGND: 16268927Sbostic case TSEMI: 16368927Sbostic tok = readtoken(); 16468927Sbostic /* fall through */ 16547139Sbostic case TNL: 16668927Sbostic if (tok == TNL) { 16747139Sbostic parseheredoc(); 16847139Sbostic if (nlflag) 16947139Sbostic return n1; 17047139Sbostic } else { 17147139Sbostic tokpushback++; 17247139Sbostic } 17347981Smarc checkkwd = 2; 17447981Smarc if (tokendlist[peektoken()]) 17547139Sbostic return n1; 17647139Sbostic break; 17747139Sbostic case TEOF: 17847139Sbostic if (heredoclist) 17947139Sbostic parseheredoc(); 18047139Sbostic else 18147139Sbostic pungetc(); /* push back EOF on input */ 18247139Sbostic return n1; 18347139Sbostic default: 18447139Sbostic if (nlflag) 18547139Sbostic synexpect(-1); 18647139Sbostic tokpushback++; 18747139Sbostic return n1; 18847139Sbostic } 18947139Sbostic } 19047139Sbostic } 19147139Sbostic 19247139Sbostic 19347139Sbostic 19447139Sbostic STATIC union node * 19547139Sbostic andor() { 19647139Sbostic union node *n1, *n2, *n3; 19747139Sbostic int t; 19847139Sbostic 19947139Sbostic n1 = pipeline(); 20047139Sbostic for (;;) { 20147139Sbostic if ((t = readtoken()) == TAND) { 20247139Sbostic t = NAND; 20347139Sbostic } else if (t == TOR) { 20447139Sbostic t = NOR; 20547139Sbostic } else { 20647139Sbostic tokpushback++; 20747139Sbostic return n1; 20847139Sbostic } 20947139Sbostic n2 = pipeline(); 21047139Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 21147139Sbostic n3->type = t; 21247139Sbostic n3->nbinary.ch1 = n1; 21347139Sbostic n3->nbinary.ch2 = n2; 21447139Sbostic n1 = n3; 21547139Sbostic } 21647139Sbostic } 21747139Sbostic 21847139Sbostic 21947139Sbostic 22047139Sbostic STATIC union node * 22147139Sbostic pipeline() { 22253178Smarc union node *n1, *pipenode, *notnode; 22347139Sbostic struct nodelist *lp, *prev; 22453178Smarc int negate = 0; 22547139Sbostic 22653178Smarc TRACE(("pipeline: entered\n")); 22753178Smarc while (readtoken() == TNOT) { 22853178Smarc TRACE(("pipeline: TNOT recognized\n")); 22953178Smarc negate = !negate; 23053178Smarc } 23153178Smarc tokpushback++; 23247139Sbostic n1 = command(); 23347139Sbostic if (readtoken() == TPIPE) { 23447139Sbostic pipenode = (union node *)stalloc(sizeof (struct npipe)); 23547139Sbostic pipenode->type = NPIPE; 23647139Sbostic pipenode->npipe.backgnd = 0; 23747139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 23847139Sbostic pipenode->npipe.cmdlist = lp; 23947139Sbostic lp->n = n1; 24047139Sbostic do { 24147139Sbostic prev = lp; 24247139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 24347139Sbostic lp->n = command(); 24447139Sbostic prev->next = lp; 24547139Sbostic } while (readtoken() == TPIPE); 24647139Sbostic lp->next = NULL; 24747139Sbostic n1 = pipenode; 24847139Sbostic } 24947139Sbostic tokpushback++; 25053178Smarc if (negate) { 25153178Smarc notnode = (union node *)stalloc(sizeof (struct nnot)); 25253178Smarc notnode->type = NNOT; 25353178Smarc notnode->nnot.com = n1; 25453178Smarc n1 = notnode; 25553178Smarc } 25647139Sbostic return n1; 25747139Sbostic } 25847139Sbostic 25947139Sbostic 26047139Sbostic 26147139Sbostic STATIC union node * 26247139Sbostic command() { 26347139Sbostic union node *n1, *n2; 26447139Sbostic union node *ap, **app; 26547139Sbostic union node *cp, **cpp; 26647139Sbostic union node *redir, **rpp; 26747139Sbostic int t; 26847139Sbostic 26947981Smarc checkkwd = 2; 270*69272Schristos redir = NULL; 271*69272Schristos n1 = NULL; 27260296Smarc rpp = &redir; 27360296Smarc /* Check for redirection which may precede command */ 27460296Smarc while (readtoken() == TREDIR) { 27560296Smarc *rpp = n2 = redirnode; 27660296Smarc rpp = &n2->nfile.next; 27760296Smarc parsefname(); 27860296Smarc } 27960296Smarc tokpushback++; 28060296Smarc 28147139Sbostic switch (readtoken()) { 28247139Sbostic case TIF: 28347139Sbostic n1 = (union node *)stalloc(sizeof (struct nif)); 28447139Sbostic n1->type = NIF; 28547139Sbostic n1->nif.test = list(0); 28647139Sbostic if (readtoken() != TTHEN) 28747139Sbostic synexpect(TTHEN); 28847139Sbostic n1->nif.ifpart = list(0); 28947139Sbostic n2 = n1; 29047139Sbostic while (readtoken() == TELIF) { 29147139Sbostic n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 29247139Sbostic n2 = n2->nif.elsepart; 29347139Sbostic n2->type = NIF; 29447139Sbostic n2->nif.test = list(0); 29547139Sbostic if (readtoken() != TTHEN) 29647139Sbostic synexpect(TTHEN); 29747139Sbostic n2->nif.ifpart = list(0); 29847139Sbostic } 29947139Sbostic if (lasttoken == TELSE) 30047139Sbostic n2->nif.elsepart = list(0); 30147139Sbostic else { 30247139Sbostic n2->nif.elsepart = NULL; 30347139Sbostic tokpushback++; 30447139Sbostic } 30547139Sbostic if (readtoken() != TFI) 30647139Sbostic synexpect(TFI); 30747981Smarc checkkwd = 1; 30847139Sbostic break; 30947139Sbostic case TWHILE: 31047981Smarc case TUNTIL: { 31147981Smarc int got; 31247139Sbostic n1 = (union node *)stalloc(sizeof (struct nbinary)); 31347139Sbostic n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 31447139Sbostic n1->nbinary.ch1 = list(0); 31547981Smarc if ((got=readtoken()) != TDO) { 31647981Smarc TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 31747139Sbostic synexpect(TDO); 31847981Smarc } 31947139Sbostic n1->nbinary.ch2 = list(0); 32047139Sbostic if (readtoken() != TDONE) 32147139Sbostic synexpect(TDONE); 32247981Smarc checkkwd = 1; 32347139Sbostic break; 32447981Smarc } 32547139Sbostic case TFOR: 32647139Sbostic if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 32747139Sbostic synerror("Bad for loop variable"); 32847139Sbostic n1 = (union node *)stalloc(sizeof (struct nfor)); 32947139Sbostic n1->type = NFOR; 33047139Sbostic n1->nfor.var = wordtext; 33147139Sbostic if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 33247139Sbostic app = ≈ 33347139Sbostic while (readtoken() == TWORD) { 33447139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 33547139Sbostic n2->type = NARG; 33647139Sbostic n2->narg.text = wordtext; 33747139Sbostic n2->narg.backquote = backquotelist; 33847139Sbostic *app = n2; 33947139Sbostic app = &n2->narg.next; 34047139Sbostic } 34147139Sbostic *app = NULL; 34247139Sbostic n1->nfor.args = ap; 34359178Storek if (lasttoken != TNL && lasttoken != TSEMI) 34459178Storek synexpect(-1); 34547139Sbostic } else { 34647139Sbostic #ifndef GDB_HACK 34747139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 34847139Sbostic '@', '=', '\0'}; 34947139Sbostic #endif 35047139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 35147139Sbostic n2->type = NARG; 35247139Sbostic n2->narg.text = (char *)argvars; 35347139Sbostic n2->narg.backquote = NULL; 35447139Sbostic n2->narg.next = NULL; 35547139Sbostic n1->nfor.args = n2; 35659178Storek /* 35759178Storek * Newline or semicolon here is optional (but note 35859178Storek * that the original Bourne shell only allowed NL). 35959178Storek */ 36059178Storek if (lasttoken != TNL && lasttoken != TSEMI) 36159178Storek tokpushback++; 36247139Sbostic } 36347981Smarc checkkwd = 2; 36447139Sbostic if ((t = readtoken()) == TDO) 36547139Sbostic t = TDONE; 36647139Sbostic else if (t == TBEGIN) 36747139Sbostic t = TEND; 36847139Sbostic else 36947139Sbostic synexpect(-1); 37047139Sbostic n1->nfor.body = list(0); 37147139Sbostic if (readtoken() != t) 37247139Sbostic synexpect(t); 37347981Smarc checkkwd = 1; 37447139Sbostic break; 37547139Sbostic case TCASE: 37647139Sbostic n1 = (union node *)stalloc(sizeof (struct ncase)); 37747139Sbostic n1->type = NCASE; 37847139Sbostic if (readtoken() != TWORD) 37947139Sbostic synexpect(TWORD); 38047139Sbostic n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 38147139Sbostic n2->type = NARG; 38247139Sbostic n2->narg.text = wordtext; 38347139Sbostic n2->narg.backquote = backquotelist; 38447139Sbostic n2->narg.next = NULL; 38547139Sbostic while (readtoken() == TNL); 38647139Sbostic if (lasttoken != TWORD || ! equal(wordtext, "in")) 38747139Sbostic synerror("expecting \"in\""); 38847139Sbostic cpp = &n1->ncase.cases; 389*69272Schristos checkkwd = 2, readtoken(); 390*69272Schristos do { 39147139Sbostic *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 39247139Sbostic cp->type = NCLIST; 39347139Sbostic app = &cp->nclist.pattern; 39447139Sbostic for (;;) { 39547139Sbostic *app = ap = (union node *)stalloc(sizeof (struct narg)); 39647139Sbostic ap->type = NARG; 39747139Sbostic ap->narg.text = wordtext; 39847139Sbostic ap->narg.backquote = backquotelist; 399*69272Schristos if (checkkwd = 2, readtoken() != TPIPE) 40047139Sbostic break; 40147139Sbostic app = &ap->narg.next; 402*69272Schristos readtoken(); 40347139Sbostic } 40447139Sbostic ap->narg.next = NULL; 40547139Sbostic if (lasttoken != TRP) 40647139Sbostic synexpect(TRP); 40747139Sbostic cp->nclist.body = list(0); 408*69272Schristos 409*69272Schristos checkkwd = 2; 410*69272Schristos if ((t = readtoken()) != TESAC) { 411*69272Schristos if (t != TENDCASE) 412*69272Schristos synexpect(TENDCASE); 413*69272Schristos else 414*69272Schristos checkkwd = 2, readtoken(); 415*69272Schristos } 41647139Sbostic cpp = &cp->nclist.next; 417*69272Schristos } while(lasttoken != TESAC); 41847139Sbostic *cpp = NULL; 41947981Smarc checkkwd = 1; 42047139Sbostic break; 42147139Sbostic case TLP: 42247139Sbostic n1 = (union node *)stalloc(sizeof (struct nredir)); 42347139Sbostic n1->type = NSUBSHELL; 42447139Sbostic n1->nredir.n = list(0); 42547139Sbostic n1->nredir.redirect = NULL; 42647139Sbostic if (readtoken() != TRP) 42747139Sbostic synexpect(TRP); 42847981Smarc checkkwd = 1; 42947139Sbostic break; 43047139Sbostic case TBEGIN: 43147139Sbostic n1 = list(0); 43247139Sbostic if (readtoken() != TEND) 43347139Sbostic synexpect(TEND); 43447981Smarc checkkwd = 1; 43547139Sbostic break; 43660296Smarc /* Handle an empty command like other simple commands. */ 43768944Sbostic case TSEMI: 43868944Sbostic /* 43968944Sbostic * An empty command before a ; doesn't make much sense, and 44068944Sbostic * should certainly be disallowed in the case of `if ;'. 44168944Sbostic */ 44268944Sbostic if (!redir) 44368944Sbostic synexpect(-1); 44460296Smarc case TNL: 445*69272Schristos case TEOF: 44647139Sbostic case TWORD: 44768944Sbostic case TRP: 44847139Sbostic tokpushback++; 44960296Smarc return simplecmd(rpp, redir); 45047139Sbostic default: 45147139Sbostic synexpect(-1); 45247139Sbostic } 45347139Sbostic 45447139Sbostic /* Now check for redirection which may follow command */ 45547139Sbostic while (readtoken() == TREDIR) { 45647139Sbostic *rpp = n2 = redirnode; 45747139Sbostic rpp = &n2->nfile.next; 45847139Sbostic parsefname(); 45947139Sbostic } 46047139Sbostic tokpushback++; 46147139Sbostic *rpp = NULL; 46247139Sbostic if (redir) { 46347139Sbostic if (n1->type != NSUBSHELL) { 46447139Sbostic n2 = (union node *)stalloc(sizeof (struct nredir)); 46547139Sbostic n2->type = NREDIR; 46647139Sbostic n2->nredir.n = n1; 46747139Sbostic n1 = n2; 46847139Sbostic } 46947139Sbostic n1->nredir.redirect = redir; 47047139Sbostic } 47147139Sbostic return n1; 47247139Sbostic } 47347139Sbostic 47447139Sbostic 47547139Sbostic STATIC union node * 47660296Smarc simplecmd(rpp, redir) 47760296Smarc union node **rpp, *redir; 47860296Smarc { 47947139Sbostic union node *args, **app; 48060296Smarc union node **orig_rpp = rpp; 48147139Sbostic union node *n; 48247139Sbostic 48360296Smarc /* If we don't have any redirections already, then we must reset */ 48460296Smarc /* rpp to be the address of the local redir variable. */ 48560296Smarc if (redir == 0) 48660296Smarc rpp = &redir; 48760296Smarc 48847139Sbostic args = NULL; 48947139Sbostic app = &args; 49060296Smarc /* 49160296Smarc * We save the incoming value, because we need this for shell 49260296Smarc * functions. There can not be a redirect or an argument between 49360296Smarc * the function name and the open parenthesis. 49460296Smarc */ 49560296Smarc orig_rpp = rpp; 49660296Smarc 49747139Sbostic for (;;) { 49847139Sbostic if (readtoken() == TWORD) { 49947139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 50047139Sbostic n->type = NARG; 50147139Sbostic n->narg.text = wordtext; 50247139Sbostic n->narg.backquote = backquotelist; 50347139Sbostic *app = n; 50447139Sbostic app = &n->narg.next; 50547139Sbostic } else if (lasttoken == TREDIR) { 50647139Sbostic *rpp = n = redirnode; 50747139Sbostic rpp = &n->nfile.next; 50847139Sbostic parsefname(); /* read name of redirection file */ 50947139Sbostic } else if (lasttoken == TLP && app == &args->narg.next 51060296Smarc && rpp == orig_rpp) { 51147139Sbostic /* We have a function */ 51247139Sbostic if (readtoken() != TRP) 51347139Sbostic synexpect(TRP); 51447300Smarc #ifdef notdef 51547139Sbostic if (! goodname(n->narg.text)) 51647139Sbostic synerror("Bad function name"); 51747300Smarc #endif 51847139Sbostic n->type = NDEFUN; 51947139Sbostic n->narg.next = command(); 52047139Sbostic return n; 52147139Sbostic } else { 52247139Sbostic tokpushback++; 52347139Sbostic break; 52447139Sbostic } 52547139Sbostic } 52647139Sbostic *app = NULL; 52747139Sbostic *rpp = NULL; 52847139Sbostic n = (union node *)stalloc(sizeof (struct ncmd)); 52947139Sbostic n->type = NCMD; 53047139Sbostic n->ncmd.backgnd = 0; 53147139Sbostic n->ncmd.args = args; 53247139Sbostic n->ncmd.redirect = redir; 53347139Sbostic return n; 53447139Sbostic } 53547139Sbostic 536*69272Schristos STATIC union node * 537*69272Schristos makename() { 538*69272Schristos union node *n; 53947139Sbostic 540*69272Schristos n = (union node *)stalloc(sizeof (struct narg)); 541*69272Schristos n->type = NARG; 542*69272Schristos n->narg.next = NULL; 543*69272Schristos n->narg.text = wordtext; 544*69272Schristos n->narg.backquote = backquotelist; 545*69272Schristos return n; 546*69272Schristos } 547*69272Schristos 548*69272Schristos void fixredir(n, text, err) 549*69272Schristos union node *n; 550*69272Schristos const char *text; 551*69272Schristos int err; 552*69272Schristos { 553*69272Schristos TRACE(("Fix redir %s %d\n", text, err)); 554*69272Schristos if (!err) 555*69272Schristos n->ndup.vname = NULL; 556*69272Schristos 557*69272Schristos if (is_digit(text[0]) && text[1] == '\0') 558*69272Schristos n->ndup.dupfd = digit_val(text[0]); 559*69272Schristos else if (text[0] == '-' && text[1] == '\0') 560*69272Schristos n->ndup.dupfd = -1; 561*69272Schristos else { 562*69272Schristos 563*69272Schristos if (err) 564*69272Schristos synerror("Bad fd number"); 565*69272Schristos else 566*69272Schristos n->ndup.vname = makename(); 567*69272Schristos } 568*69272Schristos } 569*69272Schristos 570*69272Schristos 57147139Sbostic STATIC void 57247139Sbostic parsefname() { 57347139Sbostic union node *n = redirnode; 57447139Sbostic 57547139Sbostic if (readtoken() != TWORD) 57647139Sbostic synexpect(-1); 57747139Sbostic if (n->type == NHERE) { 57847139Sbostic struct heredoc *here = heredoc; 57947139Sbostic struct heredoc *p; 58047139Sbostic int i; 58147139Sbostic 58247139Sbostic if (quoteflag == 0) 58347139Sbostic n->type = NXHERE; 58447139Sbostic TRACE(("Here document %d\n", n->type)); 58547139Sbostic if (here->striptabs) { 58647139Sbostic while (*wordtext == '\t') 58747139Sbostic wordtext++; 58847139Sbostic } 58947139Sbostic if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 59047139Sbostic synerror("Illegal eof marker for << redirection"); 59147139Sbostic rmescapes(wordtext); 59247139Sbostic here->eofmark = wordtext; 59347139Sbostic here->next = NULL; 59447139Sbostic if (heredoclist == NULL) 59547139Sbostic heredoclist = here; 59647139Sbostic else { 59747139Sbostic for (p = heredoclist ; p->next ; p = p->next); 59847139Sbostic p->next = here; 59947139Sbostic } 60047139Sbostic } else if (n->type == NTOFD || n->type == NFROMFD) { 601*69272Schristos fixredir(n, wordtext, 0); 60247139Sbostic } else { 603*69272Schristos n->nfile.fname = makename(); 60447139Sbostic } 60547139Sbostic } 60647139Sbostic 60747139Sbostic 60847139Sbostic /* 60947139Sbostic * Input any here documents. 61047139Sbostic */ 61147139Sbostic 61247139Sbostic STATIC void 61347139Sbostic parseheredoc() { 61447139Sbostic struct heredoc *here; 61547139Sbostic union node *n; 61647139Sbostic 61747139Sbostic while (heredoclist) { 61847139Sbostic here = heredoclist; 61947139Sbostic heredoclist = here->next; 62047139Sbostic if (needprompt) { 62154322Smarc setprompt(2); 62247139Sbostic needprompt = 0; 62347139Sbostic } 62447139Sbostic readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 62547139Sbostic here->eofmark, here->striptabs); 62647139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 62747139Sbostic n->narg.type = NARG; 62847139Sbostic n->narg.next = NULL; 62947139Sbostic n->narg.text = wordtext; 63047139Sbostic n->narg.backquote = backquotelist; 63147139Sbostic here->here->nhere.doc = n; 63247139Sbostic } 63347139Sbostic } 63447139Sbostic 63547981Smarc STATIC int 63647981Smarc peektoken() { 63747139Sbostic int t; 63847139Sbostic 63947981Smarc t = readtoken(); 64047139Sbostic tokpushback++; 64147981Smarc return (t); 64247139Sbostic } 64347139Sbostic 64447139Sbostic STATIC int xxreadtoken(); 64547139Sbostic 64647139Sbostic STATIC int 64747139Sbostic readtoken() { 64847139Sbostic int t; 64954322Smarc int savecheckkwd = checkkwd; 65054322Smarc struct alias *ap; 65147981Smarc #ifdef DEBUG 65247981Smarc int alreadyseen = tokpushback; 65347981Smarc #endif 65447981Smarc 65554322Smarc top: 65647981Smarc t = xxreadtoken(); 65747139Sbostic 65847981Smarc if (checkkwd) { 65947981Smarc /* 66047981Smarc * eat newlines 66147981Smarc */ 66247981Smarc if (checkkwd == 2) { 66347981Smarc checkkwd = 0; 66447981Smarc while (t == TNL) { 66547981Smarc parseheredoc(); 66647981Smarc t = xxreadtoken(); 66747981Smarc } 66847981Smarc } else 66947981Smarc checkkwd = 0; 67047981Smarc /* 67154322Smarc * check for keywords and aliases 67247981Smarc */ 673*69272Schristos if (t == TWORD && !quoteflag) 674*69272Schristos { 675*69272Schristos register char * const *pp; 67647981Smarc 67760296Smarc for (pp = (char **)parsekwd; *pp; pp++) { 678*69272Schristos if (**pp == *wordtext && equal(*pp, wordtext)) 679*69272Schristos { 68047981Smarc lasttoken = t = pp - parsekwd + KWDOFFSET; 68147981Smarc TRACE(("keyword %s recognized\n", tokname[t])); 68254322Smarc goto out; 68347981Smarc } 68447981Smarc } 685*69272Schristos if ((ap = lookupalias(wordtext, 1)) != NULL) { 68654322Smarc pushstring(ap->val, strlen(ap->val), ap); 68754322Smarc checkkwd = savecheckkwd; 68854322Smarc goto top; 68954322Smarc } 69047981Smarc } 69154322Smarc out: 69254322Smarc checkkwd = 0; 69347139Sbostic } 69447981Smarc #ifdef DEBUG 69547981Smarc if (!alreadyseen) 69647981Smarc TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 69747981Smarc else 69847981Smarc TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 69947981Smarc #endif 70047981Smarc return (t); 70147139Sbostic } 70247139Sbostic 70347139Sbostic 70447139Sbostic /* 70547139Sbostic * Read the next input token. 70647139Sbostic * If the token is a word, we set backquotelist to the list of cmds in 70747139Sbostic * backquotes. We set quoteflag to true if any part of the word was 70847139Sbostic * quoted. 70947139Sbostic * If the token is TREDIR, then we set redirnode to a structure containing 71047139Sbostic * the redirection. 71147139Sbostic * In all cases, the variable startlinno is set to the number of the line 71247139Sbostic * on which the token starts. 71347139Sbostic * 71447139Sbostic * [Change comment: here documents and internal procedures] 71547139Sbostic * [Readtoken shouldn't have any arguments. Perhaps we should make the 71647139Sbostic * word parsing code into a separate routine. In this case, readtoken 71747139Sbostic * doesn't need to have any internal procedures, but parseword does. 71847139Sbostic * We could also make parseoperator in essence the main routine, and 71947139Sbostic * have parseword (readtoken1?) handle both words and redirection.] 72047139Sbostic */ 72147139Sbostic 72247139Sbostic #define RETURN(token) return lasttoken = token 72347139Sbostic 72447139Sbostic STATIC int 72547139Sbostic xxreadtoken() { 72647139Sbostic register c; 72747139Sbostic 72847139Sbostic if (tokpushback) { 72947139Sbostic tokpushback = 0; 73047139Sbostic return lasttoken; 73147139Sbostic } 73247139Sbostic if (needprompt) { 73354322Smarc setprompt(2); 73447139Sbostic needprompt = 0; 73547139Sbostic } 73647139Sbostic startlinno = plinno; 73747139Sbostic for (;;) { /* until token or start of word found */ 73847139Sbostic c = pgetc_macro(); 73947139Sbostic if (c == ' ' || c == '\t') 74047139Sbostic continue; /* quick check for white space first */ 74147139Sbostic switch (c) { 74247139Sbostic case ' ': case '\t': 74347139Sbostic continue; 74447139Sbostic case '#': 74547139Sbostic while ((c = pgetc()) != '\n' && c != PEOF); 74647139Sbostic pungetc(); 74747139Sbostic continue; 74847139Sbostic case '\\': 74947139Sbostic if (pgetc() == '\n') { 75047139Sbostic startlinno = ++plinno; 75147139Sbostic if (doprompt) 75254322Smarc setprompt(2); 75354322Smarc else 75454322Smarc setprompt(0); 75547139Sbostic continue; 75647139Sbostic } 75747139Sbostic pungetc(); 75847139Sbostic goto breakloop; 75947139Sbostic case '\n': 76047139Sbostic plinno++; 76147139Sbostic needprompt = doprompt; 76247139Sbostic RETURN(TNL); 76347139Sbostic case PEOF: 76447139Sbostic RETURN(TEOF); 76547139Sbostic case '&': 76647139Sbostic if (pgetc() == '&') 76747139Sbostic RETURN(TAND); 76847139Sbostic pungetc(); 76947139Sbostic RETURN(TBACKGND); 77047139Sbostic case '|': 77147139Sbostic if (pgetc() == '|') 77247139Sbostic RETURN(TOR); 77347139Sbostic pungetc(); 77447139Sbostic RETURN(TPIPE); 77547139Sbostic case ';': 77647139Sbostic if (pgetc() == ';') 77747139Sbostic RETURN(TENDCASE); 77847139Sbostic pungetc(); 77947139Sbostic RETURN(TSEMI); 78047139Sbostic case '(': 78147139Sbostic RETURN(TLP); 78247139Sbostic case ')': 78347139Sbostic RETURN(TRP); 78447139Sbostic default: 78547139Sbostic goto breakloop; 78647139Sbostic } 78747139Sbostic } 78847139Sbostic breakloop: 78947139Sbostic return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 79047139Sbostic #undef RETURN 79147139Sbostic } 79247139Sbostic 79347139Sbostic 79447139Sbostic 79547139Sbostic /* 79647139Sbostic * If eofmark is NULL, read a word or a redirection symbol. If eofmark 79747139Sbostic * is not NULL, read a here document. In the latter case, eofmark is the 79847139Sbostic * word which marks the end of the document and striptabs is true if 79947139Sbostic * leading tabs should be stripped from the document. The argument firstc 80047139Sbostic * is the first character of the input token or document. 80147139Sbostic * 80247139Sbostic * Because C does not have internal subroutines, I have simulated them 80347139Sbostic * using goto's to implement the subroutine linkage. The following macros 80447139Sbostic * will run code that appears at the end of readtoken1. 80547139Sbostic */ 80647139Sbostic 80747139Sbostic #define CHECKEND() {goto checkend; checkend_return:;} 80847139Sbostic #define PARSEREDIR() {goto parseredir; parseredir_return:;} 80947139Sbostic #define PARSESUB() {goto parsesub; parsesub_return:;} 81047139Sbostic #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 81147139Sbostic #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 81253302Smarc #define PARSEARITH() {goto parsearith; parsearith_return:;} 81347139Sbostic 81447139Sbostic STATIC int 81547139Sbostic readtoken1(firstc, syntax, eofmark, striptabs) 81647139Sbostic int firstc; 81747139Sbostic char const *syntax; 81847139Sbostic char *eofmark; 81947139Sbostic int striptabs; 82047139Sbostic { 821*69272Schristos int c = firstc; 822*69272Schristos char *out; 82347139Sbostic int len; 82447139Sbostic char line[EOFMARKLEN + 1]; 82547139Sbostic struct nodelist *bqlist; 82647139Sbostic int quotef; 82747139Sbostic int dblquote; 82853302Smarc int varnest; /* levels of variables expansion */ 82953302Smarc int arinest; /* levels of arithmetic expansion */ 83053302Smarc int parenlevel; /* levels of parens in arithmetic */ 83147139Sbostic int oldstyle; 83253302Smarc char const *prevsyntax; /* syntax before arithmetic */ 833*69272Schristos #if __GNUC__ 834*69272Schristos /* Avoid longjmp clobbering */ 835*69272Schristos (void) &out; 836*69272Schristos (void) "ef; 837*69272Schristos (void) &dblquote; 838*69272Schristos (void) &varnest; 839*69272Schristos (void) &arinest; 840*69272Schristos (void) &parenlevel; 841*69272Schristos (void) &oldstyle; 842*69272Schristos (void) &prevsyntax; 843*69272Schristos (void) &syntax; 844*69272Schristos #endif 84547139Sbostic 84647139Sbostic startlinno = plinno; 84747139Sbostic dblquote = 0; 84847139Sbostic if (syntax == DQSYNTAX) 84947139Sbostic dblquote = 1; 85047139Sbostic quotef = 0; 85147139Sbostic bqlist = NULL; 85247139Sbostic varnest = 0; 85353302Smarc arinest = 0; 85453302Smarc parenlevel = 0; 85553302Smarc 85647139Sbostic STARTSTACKSTR(out); 85747139Sbostic loop: { /* for each line, until end of word */ 85847139Sbostic #if ATTY 85947139Sbostic if (c == '\034' && doprompt 86047139Sbostic && attyset() && ! equal(termval(), "emacs")) { 86147139Sbostic attyline(); 86247139Sbostic if (syntax == BASESYNTAX) 86347139Sbostic return readtoken(); 86447139Sbostic c = pgetc(); 86547139Sbostic goto loop; 86647139Sbostic } 86747139Sbostic #endif 86847139Sbostic CHECKEND(); /* set c to PEOF if at end of here document */ 86947139Sbostic for (;;) { /* until end of line or end of word */ 87047139Sbostic CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 87147139Sbostic switch(syntax[c]) { 87247139Sbostic case CNL: /* '\n' */ 87347139Sbostic if (syntax == BASESYNTAX) 87447139Sbostic goto endword; /* exit outer loop */ 87547139Sbostic USTPUTC(c, out); 87647139Sbostic plinno++; 87754322Smarc if (doprompt) 87854322Smarc setprompt(2); 87954322Smarc else 88054322Smarc setprompt(0); 88147139Sbostic c = pgetc(); 88247139Sbostic goto loop; /* continue outer loop */ 88347139Sbostic case CWORD: 88447139Sbostic USTPUTC(c, out); 88547139Sbostic break; 88647139Sbostic case CCTL: 88747139Sbostic if (eofmark == NULL || dblquote) 88847139Sbostic USTPUTC(CTLESC, out); 88947139Sbostic USTPUTC(c, out); 89047139Sbostic break; 89147139Sbostic case CBACK: /* backslash */ 89247139Sbostic c = pgetc(); 89347139Sbostic if (c == PEOF) { 89447139Sbostic USTPUTC('\\', out); 89547139Sbostic pungetc(); 89647139Sbostic } else if (c == '\n') { 89747139Sbostic if (doprompt) 89854322Smarc setprompt(2); 89954322Smarc else 90054322Smarc setprompt(0); 90147139Sbostic } else { 90247139Sbostic if (dblquote && c != '\\' && c != '`' && c != '$' 90347139Sbostic && (c != '"' || eofmark != NULL)) 90447139Sbostic USTPUTC('\\', out); 90547139Sbostic if (SQSYNTAX[c] == CCTL) 90647139Sbostic USTPUTC(CTLESC, out); 90747139Sbostic USTPUTC(c, out); 90847139Sbostic quotef++; 90947139Sbostic } 91047139Sbostic break; 91147139Sbostic case CSQUOTE: 91247139Sbostic syntax = SQSYNTAX; 91347139Sbostic break; 91447139Sbostic case CDQUOTE: 91547139Sbostic syntax = DQSYNTAX; 91647139Sbostic dblquote = 1; 91747139Sbostic break; 91847139Sbostic case CENDQUOTE: 91947139Sbostic if (eofmark) { 92047139Sbostic USTPUTC(c, out); 92147139Sbostic } else { 92253302Smarc if (arinest) 92353302Smarc syntax = ARISYNTAX; 92453302Smarc else 92553302Smarc syntax = BASESYNTAX; 92647139Sbostic quotef++; 92747139Sbostic dblquote = 0; 92847139Sbostic } 92947139Sbostic break; 93047139Sbostic case CVAR: /* '$' */ 93147139Sbostic PARSESUB(); /* parse substitution */ 93247139Sbostic break; 93347139Sbostic case CENDVAR: /* '}' */ 93447139Sbostic if (varnest > 0) { 93547139Sbostic varnest--; 93647139Sbostic USTPUTC(CTLENDVAR, out); 93747139Sbostic } else { 93847139Sbostic USTPUTC(c, out); 93947139Sbostic } 94047139Sbostic break; 94153302Smarc case CLP: /* '(' in arithmetic */ 94253302Smarc parenlevel++; 94353302Smarc USTPUTC(c, out); 94453302Smarc break; 94553302Smarc case CRP: /* ')' in arithmetic */ 94653302Smarc if (parenlevel > 0) { 94753302Smarc USTPUTC(c, out); 94853302Smarc --parenlevel; 94953302Smarc } else { 95053302Smarc if (pgetc() == ')') { 95153302Smarc if (--arinest == 0) { 95253302Smarc USTPUTC(CTLENDARI, out); 95353302Smarc syntax = prevsyntax; 95453302Smarc } else 95553302Smarc USTPUTC(')', out); 95653302Smarc } else { 95753302Smarc /* 95853302Smarc * unbalanced parens 95953302Smarc * (don't 2nd guess - no error) 96053302Smarc */ 96153302Smarc pungetc(); 96253302Smarc USTPUTC(')', out); 96353302Smarc } 96453302Smarc } 96553302Smarc break; 96647139Sbostic case CBQUOTE: /* '`' */ 96747139Sbostic PARSEBACKQOLD(); 96847139Sbostic break; 96947139Sbostic case CEOF: 97047139Sbostic goto endword; /* exit outer loop */ 97147139Sbostic default: 97247139Sbostic if (varnest == 0) 97347139Sbostic goto endword; /* exit outer loop */ 97447139Sbostic USTPUTC(c, out); 97547139Sbostic } 97647139Sbostic c = pgetc_macro(); 97747139Sbostic } 97847139Sbostic } 97947139Sbostic endword: 98053302Smarc if (syntax == ARISYNTAX) 98153302Smarc synerror("Missing '))'"); 98260296Smarc if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 98347139Sbostic synerror("Unterminated quoted string"); 98447139Sbostic if (varnest != 0) { 98547139Sbostic startlinno = plinno; 98647139Sbostic synerror("Missing '}'"); 98747139Sbostic } 98847139Sbostic USTPUTC('\0', out); 98947139Sbostic len = out - stackblock(); 99047139Sbostic out = stackblock(); 99147139Sbostic if (eofmark == NULL) { 99247139Sbostic if ((c == '>' || c == '<') 99347139Sbostic && quotef == 0 99447139Sbostic && len <= 2 99547139Sbostic && (*out == '\0' || is_digit(*out))) { 99647139Sbostic PARSEREDIR(); 99747139Sbostic return lasttoken = TREDIR; 99847139Sbostic } else { 99947139Sbostic pungetc(); 100047139Sbostic } 100147139Sbostic } 100247139Sbostic quoteflag = quotef; 100347139Sbostic backquotelist = bqlist; 100447139Sbostic grabstackblock(len); 100547139Sbostic wordtext = out; 100647139Sbostic return lasttoken = TWORD; 100747139Sbostic /* end of readtoken routine */ 100847139Sbostic 100947139Sbostic 101047139Sbostic 101147139Sbostic /* 101247139Sbostic * Check to see whether we are at the end of the here document. When this 101347139Sbostic * is called, c is set to the first character of the next input line. If 101447139Sbostic * we are at the end of the here document, this routine sets the c to PEOF. 101547139Sbostic */ 101647139Sbostic 101747139Sbostic checkend: { 101847139Sbostic if (eofmark) { 101947139Sbostic if (striptabs) { 102047139Sbostic while (c == '\t') 102147139Sbostic c = pgetc(); 102247139Sbostic } 102347139Sbostic if (c == *eofmark) { 102447139Sbostic if (pfgets(line, sizeof line) != NULL) { 102547139Sbostic register char *p, *q; 102647139Sbostic 102747139Sbostic p = line; 102847139Sbostic for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 102947139Sbostic if (*p == '\n' && *q == '\0') { 103047139Sbostic c = PEOF; 103147139Sbostic plinno++; 103247139Sbostic needprompt = doprompt; 103347139Sbostic } else { 103454322Smarc pushstring(line, strlen(line), NULL); 103547139Sbostic } 103647139Sbostic } 103747139Sbostic } 103847139Sbostic } 103947139Sbostic goto checkend_return; 104047139Sbostic } 104147139Sbostic 104247139Sbostic 104347139Sbostic /* 104447139Sbostic * Parse a redirection operator. The variable "out" points to a string 104547139Sbostic * specifying the fd to be redirected. The variable "c" contains the 104647139Sbostic * first character of the redirection operator. 104747139Sbostic */ 104847139Sbostic 104947139Sbostic parseredir: { 105047139Sbostic char fd = *out; 105147139Sbostic union node *np; 105247139Sbostic 105347139Sbostic np = (union node *)stalloc(sizeof (struct nfile)); 105447139Sbostic if (c == '>') { 105547139Sbostic np->nfile.fd = 1; 105647139Sbostic c = pgetc(); 105747139Sbostic if (c == '>') 105847139Sbostic np->type = NAPPEND; 105947139Sbostic else if (c == '&') 106047139Sbostic np->type = NTOFD; 106147139Sbostic else { 106247139Sbostic np->type = NTO; 106347139Sbostic pungetc(); 106447139Sbostic } 106547139Sbostic } else { /* c == '<' */ 106647139Sbostic np->nfile.fd = 0; 106747139Sbostic c = pgetc(); 106847139Sbostic if (c == '<') { 106947139Sbostic if (sizeof (struct nfile) != sizeof (struct nhere)) { 107047139Sbostic np = (union node *)stalloc(sizeof (struct nhere)); 107147139Sbostic np->nfile.fd = 0; 107247139Sbostic } 107347139Sbostic np->type = NHERE; 107447139Sbostic heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 107547139Sbostic heredoc->here = np; 107647139Sbostic if ((c = pgetc()) == '-') { 107747139Sbostic heredoc->striptabs = 1; 107847139Sbostic } else { 107947139Sbostic heredoc->striptabs = 0; 108047139Sbostic pungetc(); 108147139Sbostic } 108247139Sbostic } else if (c == '&') 108347139Sbostic np->type = NFROMFD; 108447139Sbostic else { 108547139Sbostic np->type = NFROM; 108647139Sbostic pungetc(); 108747139Sbostic } 108847139Sbostic } 108947139Sbostic if (fd != '\0') 109047139Sbostic np->nfile.fd = digit_val(fd); 109147139Sbostic redirnode = np; 109247139Sbostic goto parseredir_return; 109347139Sbostic } 109447139Sbostic 109547139Sbostic 109647139Sbostic /* 109747139Sbostic * Parse a substitution. At this point, we have read the dollar sign 109847139Sbostic * and nothing else. 109947139Sbostic */ 110047139Sbostic 110147139Sbostic parsesub: { 110247139Sbostic int subtype; 110347139Sbostic int typeloc; 110447139Sbostic int flags; 110547139Sbostic char *p; 110647139Sbostic #ifndef GDB_HACK 110747139Sbostic static const char types[] = "}-+?="; 110847139Sbostic #endif 110947139Sbostic 111047139Sbostic c = pgetc(); 111147300Smarc if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 111247139Sbostic USTPUTC('$', out); 111347139Sbostic pungetc(); 111453302Smarc } else if (c == '(') { /* $(command) or $((arith)) */ 111553302Smarc if (pgetc() == '(') { 111653302Smarc PARSEARITH(); 111753302Smarc } else { 111853302Smarc pungetc(); 111953302Smarc PARSEBACKQNEW(); 112053302Smarc } 112147139Sbostic } else { 112247139Sbostic USTPUTC(CTLVAR, out); 112347139Sbostic typeloc = out - stackblock(); 112447139Sbostic USTPUTC(VSNORMAL, out); 112547139Sbostic subtype = VSNORMAL; 112647139Sbostic if (c == '{') { 112747139Sbostic c = pgetc(); 112869090Sbostic if (c == '#') { 112969090Sbostic subtype = VSLENGTH; 113069090Sbostic c = pgetc(); 113169090Sbostic } 113269090Sbostic else 113369090Sbostic subtype = 0; 113447139Sbostic } 113547139Sbostic if (is_name(c)) { 113647139Sbostic do { 113747139Sbostic STPUTC(c, out); 113847139Sbostic c = pgetc(); 113947139Sbostic } while (is_in_name(c)); 114047139Sbostic } else { 114147139Sbostic if (! is_special(c)) 114247300Smarc badsub: synerror("Bad substitution"); 114347139Sbostic USTPUTC(c, out); 114447139Sbostic c = pgetc(); 114547139Sbostic } 114647139Sbostic STPUTC('=', out); 114747139Sbostic flags = 0; 114847139Sbostic if (subtype == 0) { 114969090Sbostic switch (c) { 115069090Sbostic case ':': 115147139Sbostic flags = VSNUL; 115247139Sbostic c = pgetc(); 115369090Sbostic /*FALLTHROUGH*/ 115469090Sbostic default: 115569090Sbostic p = strchr(types, c); 115669090Sbostic if (p == NULL) 115769090Sbostic goto badsub; 115869090Sbostic subtype = p - types + VSNORMAL; 115969090Sbostic break; 116069090Sbostic case '%': 116169090Sbostic case '#': 116269090Sbostic { 116369090Sbostic int cc = c; 116469090Sbostic subtype = c == '#' ? VSTRIMLEFT : 116569090Sbostic VSTRIMRIGHT; 116669090Sbostic c = pgetc(); 116769090Sbostic if (c == cc) 116869090Sbostic subtype++; 116969090Sbostic else 117069090Sbostic pungetc(); 117169090Sbostic break; 117269090Sbostic } 117347139Sbostic } 117447139Sbostic } else { 117547139Sbostic pungetc(); 117647139Sbostic } 117753302Smarc if (dblquote || arinest) 117847139Sbostic flags |= VSQUOTE; 117947139Sbostic *(stackblock() + typeloc) = subtype | flags; 118047139Sbostic if (subtype != VSNORMAL) 118147139Sbostic varnest++; 118247139Sbostic } 118347139Sbostic goto parsesub_return; 118447139Sbostic } 118547139Sbostic 118647139Sbostic 118747139Sbostic /* 118847139Sbostic * Called to parse command substitutions. Newstyle is set if the command 118947139Sbostic * is enclosed inside $(...); nlpp is a pointer to the head of the linked 119047139Sbostic * list of commands (passed by reference), and savelen is the number of 119147139Sbostic * characters on the top of the stack which must be preserved. 119247139Sbostic */ 119347139Sbostic 119447139Sbostic parsebackq: { 119547139Sbostic struct nodelist **nlpp; 119647139Sbostic int savepbq; 119747139Sbostic union node *n; 119847139Sbostic char *volatile str; 119947139Sbostic struct jmploc jmploc; 120047139Sbostic struct jmploc *volatile savehandler; 120147139Sbostic int savelen; 120247139Sbostic 120347139Sbostic savepbq = parsebackquote; 120447139Sbostic if (setjmp(jmploc.loc)) { 120547139Sbostic if (str) 120647139Sbostic ckfree(str); 120747139Sbostic parsebackquote = 0; 120847139Sbostic handler = savehandler; 120954322Smarc longjmp(handler->loc, 1); 121047139Sbostic } 121147139Sbostic INTOFF; 121247139Sbostic str = NULL; 121347139Sbostic savelen = out - stackblock(); 121447139Sbostic if (savelen > 0) { 121547139Sbostic str = ckmalloc(savelen); 1216*69272Schristos memcpy(str, stackblock(), savelen); 121747139Sbostic } 121847139Sbostic savehandler = handler; 121947139Sbostic handler = &jmploc; 122047139Sbostic INTON; 122160296Smarc if (oldstyle) { 122260296Smarc /* We must read until the closing backquote, giving special 122360296Smarc treatment to some slashes, and then push the string and 122460296Smarc reread it as input, interpreting it normally. */ 122560296Smarc register char *out; 122660296Smarc register c; 122760296Smarc int savelen; 122860296Smarc char *str; 122960296Smarc 123060296Smarc STARTSTACKSTR(out); 123160296Smarc while ((c = pgetc ()) != '`') { 123260296Smarc if (c == '\\') { 123360296Smarc c = pgetc (); 123460296Smarc if (c != '\\' && c != '`' && c != '$' 123560296Smarc && (!dblquote || c != '"')) 123660296Smarc STPUTC('\\', out); 123760296Smarc } 123860296Smarc STPUTC(c, out); 123960296Smarc } 124060296Smarc STPUTC('\0', out); 124160296Smarc savelen = out - stackblock(); 124260296Smarc if (savelen > 0) { 124360296Smarc str = ckmalloc(savelen); 1244*69272Schristos memcpy(str, stackblock(), savelen); 1245*69272Schristos setinputstring(str, 1); 124660296Smarc } 124760296Smarc } 124847139Sbostic nlpp = &bqlist; 124947139Sbostic while (*nlpp) 125047139Sbostic nlpp = &(*nlpp)->next; 125147139Sbostic *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 125247139Sbostic (*nlpp)->next = NULL; 125347139Sbostic parsebackquote = oldstyle; 125447139Sbostic n = list(0); 125560296Smarc if (!oldstyle && (readtoken() != TRP)) 125660296Smarc synexpect(TRP); 125747139Sbostic (*nlpp)->n = n; 125860296Smarc /* Start reading from old file again. */ 125960296Smarc if (oldstyle) 126060296Smarc popfile(); 126147139Sbostic while (stackblocksize() <= savelen) 126247139Sbostic growstackblock(); 126347139Sbostic STARTSTACKSTR(out); 126447139Sbostic if (str) { 1265*69272Schristos memcpy(out, str, savelen); 126647139Sbostic STADJUST(savelen, out); 126747139Sbostic INTOFF; 126847139Sbostic ckfree(str); 126947139Sbostic str = NULL; 127047139Sbostic INTON; 127147139Sbostic } 127247139Sbostic parsebackquote = savepbq; 127347139Sbostic handler = savehandler; 127453302Smarc if (arinest || dblquote) 127553302Smarc USTPUTC(CTLBACKQ | CTLQUOTE, out); 127653302Smarc else 127753302Smarc USTPUTC(CTLBACKQ, out); 127847139Sbostic if (oldstyle) 127947139Sbostic goto parsebackq_oldreturn; 128047139Sbostic else 128147139Sbostic goto parsebackq_newreturn; 128247139Sbostic } 128347139Sbostic 128453302Smarc /* 128553302Smarc * Parse an arithmetic expansion (indicate start of one and set state) 128653302Smarc */ 128753302Smarc parsearith: { 128853302Smarc 128953302Smarc if (++arinest == 1) { 129053302Smarc prevsyntax = syntax; 129153302Smarc syntax = ARISYNTAX; 129253302Smarc USTPUTC(CTLARI, out); 129353302Smarc } else { 129453302Smarc /* 129553302Smarc * we collapse embedded arithmetic expansion to 129653302Smarc * parenthesis, which should be equivalent 129753302Smarc */ 129853302Smarc USTPUTC('(', out); 129953302Smarc } 130053302Smarc goto parsearith_return; 130153302Smarc } 130253302Smarc 130347139Sbostic } /* end of readtoken */ 130447139Sbostic 130547139Sbostic 130647139Sbostic 130747139Sbostic #ifdef mkinit 130847139Sbostic RESET { 130947139Sbostic tokpushback = 0; 131054322Smarc checkkwd = 0; 131147139Sbostic } 131247139Sbostic #endif 131347139Sbostic 131447139Sbostic /* 131547139Sbostic * Returns true if the text contains nothing to expand (no dollar signs 131647139Sbostic * or backquotes). 131747139Sbostic */ 131847139Sbostic 131947139Sbostic STATIC int 132047139Sbostic noexpand(text) 132147139Sbostic char *text; 132247139Sbostic { 132347139Sbostic register char *p; 132447139Sbostic register char c; 132547139Sbostic 132647139Sbostic p = text; 132747139Sbostic while ((c = *p++) != '\0') { 132847139Sbostic if (c == CTLESC) 132947139Sbostic p++; 133047139Sbostic else if (BASESYNTAX[c] == CCTL) 133147139Sbostic return 0; 133247139Sbostic } 133347139Sbostic return 1; 133447139Sbostic } 133547139Sbostic 133647139Sbostic 133747139Sbostic /* 133847139Sbostic * Return true if the argument is a legal variable name (a letter or 133947139Sbostic * underscore followed by zero or more letters, underscores, and digits). 134047139Sbostic */ 134147139Sbostic 134247139Sbostic int 134347139Sbostic goodname(name) 134447139Sbostic char *name; 134547139Sbostic { 134647139Sbostic register char *p; 134747139Sbostic 134847139Sbostic p = name; 134947139Sbostic if (! is_name(*p)) 135047139Sbostic return 0; 135147139Sbostic while (*++p) { 135247139Sbostic if (! is_in_name(*p)) 135347139Sbostic return 0; 135447139Sbostic } 135547139Sbostic return 1; 135647139Sbostic } 135747139Sbostic 135847139Sbostic 135947139Sbostic /* 136047139Sbostic * Called when an unexpected token is read during the parse. The argument 136147139Sbostic * is the token that is expected, or -1 if more than one type of token can 136247139Sbostic * occur at this point. 136347139Sbostic */ 136447139Sbostic 136547139Sbostic STATIC void 1366*69272Schristos synexpect(token) 1367*69272Schristos int token; 1368*69272Schristos { 136947139Sbostic char msg[64]; 137047139Sbostic 137147139Sbostic if (token >= 0) { 137247139Sbostic fmtstr(msg, 64, "%s unexpected (expecting %s)", 137347139Sbostic tokname[lasttoken], tokname[token]); 137447139Sbostic } else { 137547139Sbostic fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 137647139Sbostic } 137747139Sbostic synerror(msg); 137847139Sbostic } 137947139Sbostic 138047139Sbostic 138147139Sbostic STATIC void 138247139Sbostic synerror(msg) 138347139Sbostic char *msg; 138447139Sbostic { 138547139Sbostic if (commandname) 138647139Sbostic outfmt(&errout, "%s: %d: ", commandname, startlinno); 138747139Sbostic outfmt(&errout, "Syntax error: %s\n", msg); 138847139Sbostic error((char *)NULL); 138947139Sbostic } 139054322Smarc 139154322Smarc STATIC void 139254322Smarc setprompt(which) 139354322Smarc int which; 139454322Smarc { 139554322Smarc whichprompt = which; 139654322Smarc 1397*69272Schristos #ifndef NO_HISTORY 139854322Smarc if (!el) 1399*69272Schristos #endif 140054322Smarc out2str(getprompt(NULL)); 140154322Smarc } 140254322Smarc 140354322Smarc /* 140454322Smarc * called by editline -- any expansions to the prompt 140554322Smarc * should be added here. 140654322Smarc */ 140754322Smarc char * 140854322Smarc getprompt(unused) 140954322Smarc void *unused; 141054322Smarc { 141154322Smarc switch (whichprompt) { 141254322Smarc case 0: 141354322Smarc return ""; 141454322Smarc case 1: 141554322Smarc return ps1val(); 141654322Smarc case 2: 141754322Smarc return ps2val(); 141854322Smarc default: 141954322Smarc return "<internal prompt error>"; 142054322Smarc } 142154322Smarc } 1422