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*68944Sbostic static char sccsid[] = "@(#)parser.c 8.3 (Berkeley) 04/27/95"; 1347139Sbostic #endif /* not lint */ 1447139Sbostic 1547139Sbostic #include "shell.h" 1647139Sbostic #include "parser.h" 1747139Sbostic #include "nodes.h" 1847139Sbostic #include "expand.h" /* defines rmescapes() */ 1947139Sbostic #include "redir.h" /* defines copyfd() */ 2047139Sbostic #include "syntax.h" 2147139Sbostic #include "options.h" 2247139Sbostic #include "input.h" 2347139Sbostic #include "output.h" 2447139Sbostic #include "var.h" 2547139Sbostic #include "error.h" 2647139Sbostic #include "memalloc.h" 2747139Sbostic #include "mystring.h" 2854322Smarc #include "alias.h" 2954330Smarc #include "myhistedit.h" 3047139Sbostic 3147139Sbostic 3247139Sbostic /* 3347139Sbostic * Shell command parser. 3447139Sbostic */ 3547139Sbostic 3647139Sbostic #define EOFMARKLEN 79 3747139Sbostic 3847139Sbostic /* values returned by readtoken */ 3947139Sbostic #include "token.def" 4047139Sbostic 4147139Sbostic 4247139Sbostic 4347139Sbostic struct heredoc { 4447139Sbostic struct heredoc *next; /* next here document in list */ 4547139Sbostic union node *here; /* redirection node */ 4647139Sbostic char *eofmark; /* string indicating end of input */ 4747139Sbostic int striptabs; /* if set, strip leading tabs */ 4847139Sbostic }; 4947139Sbostic 5047139Sbostic 5147139Sbostic 5247139Sbostic struct heredoc *heredoclist; /* list of here documents to read */ 5347139Sbostic int parsebackquote; /* nonzero if we are inside backquotes */ 5447139Sbostic int doprompt; /* if set, prompt the user */ 5547139Sbostic int needprompt; /* true if interactive and at start of line */ 5647139Sbostic int lasttoken; /* last token read */ 5747139Sbostic MKINIT int tokpushback; /* last token pushed back */ 5847139Sbostic char *wordtext; /* text of last word returned by readtoken */ 5954322Smarc MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 6047139Sbostic struct nodelist *backquotelist; 6147139Sbostic union node *redirnode; 6247139Sbostic struct heredoc *heredoc; 6347139Sbostic int quoteflag; /* set if (part of) last token was quoted */ 6447139Sbostic int startlinno; /* line # where last token started */ 6547139Sbostic 6647139Sbostic 6747139Sbostic #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ 6847139Sbostic #ifdef GDB_HACK 6947139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; 7047139Sbostic static const char types[] = "}-+?="; 7147139Sbostic #endif 7247139Sbostic 7347139Sbostic 7447981Smarc STATIC union node *list __P((int)); 7547981Smarc STATIC union node *andor __P((void)); 7647981Smarc STATIC union node *pipeline __P((void)); 7747981Smarc STATIC union node *command __P((void)); 7860296Smarc STATIC union node *simplecmd __P((union node **, union node *)); 7947981Smarc STATIC void parsefname __P((void)); 8047981Smarc STATIC void parseheredoc __P((void)); 8147981Smarc STATIC int readtoken __P((void)); 8247981Smarc STATIC int readtoken1 __P((int, char const *, char *, int)); 8347981Smarc STATIC void attyline __P((void)); 8447981Smarc STATIC int noexpand __P((char *)); 8547981Smarc STATIC void synexpect __P((int)); 8647981Smarc STATIC void synerror __P((char *)); 8754322Smarc STATIC void setprompt __P((int)); 8847139Sbostic 8947139Sbostic /* 9047139Sbostic * Read and parse a command. Returns NEOF on end of file. (NULL is a 9147139Sbostic * valid parse tree indicating a blank line.) 9247139Sbostic */ 9347139Sbostic 9447139Sbostic union node * 9547139Sbostic parsecmd(interact) { 9647139Sbostic int t; 9747139Sbostic 9847139Sbostic doprompt = interact; 9947139Sbostic if (doprompt) 10054322Smarc setprompt(1); 10154322Smarc else 10254322Smarc setprompt(0); 10347139Sbostic needprompt = 0; 10454322Smarc t = readtoken(); 10554322Smarc if (t == TEOF) 10647139Sbostic return NEOF; 10747139Sbostic if (t == TNL) 10847139Sbostic return NULL; 10947139Sbostic tokpushback++; 11047139Sbostic return list(1); 11147139Sbostic } 11247139Sbostic 11347139Sbostic 11447139Sbostic STATIC union node * 11547139Sbostic list(nlflag) { 11647139Sbostic union node *n1, *n2, *n3; 11768927Sbostic int tok; 11847139Sbostic 11947981Smarc checkkwd = 2; 12047981Smarc if (nlflag == 0 && tokendlist[peektoken()]) 12147139Sbostic return NULL; 12268927Sbostic n1 = NULL; 12347139Sbostic for (;;) { 12468927Sbostic n2 = andor(); 12568927Sbostic tok = readtoken(); 12668927Sbostic if (tok == TBACKGND) { 12768927Sbostic if (n2->type == NCMD || n2->type == NPIPE) { 12868927Sbostic n2->ncmd.backgnd = 1; 12968927Sbostic } else if (n2->type == NREDIR) { 13068927Sbostic n2->type = NBACKGND; 13147139Sbostic } else { 13247139Sbostic n3 = (union node *)stalloc(sizeof (struct nredir)); 13347139Sbostic n3->type = NBACKGND; 13468927Sbostic n3->nredir.n = n2; 13547139Sbostic n3->nredir.redirect = NULL; 13668927Sbostic n2 = n3; 13747139Sbostic } 13868927Sbostic } 13968927Sbostic if (n1 == NULL) { 14068927Sbostic n1 = n2; 14168927Sbostic } 14268927Sbostic else { 14368927Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 14468927Sbostic n3->type = NSEMI; 14568927Sbostic n3->nbinary.ch1 = n1; 14668927Sbostic n3->nbinary.ch2 = n2; 14768927Sbostic n1 = n3; 14868927Sbostic } 14968927Sbostic switch (tok) { 15068927Sbostic case TBACKGND: 15168927Sbostic case TSEMI: 15268927Sbostic tok = readtoken(); 15368927Sbostic /* fall through */ 15447139Sbostic case TNL: 15568927Sbostic if (tok == TNL) { 15647139Sbostic parseheredoc(); 15747139Sbostic if (nlflag) 15847139Sbostic return n1; 15947139Sbostic } else { 16047139Sbostic tokpushback++; 16147139Sbostic } 16247981Smarc checkkwd = 2; 16347981Smarc if (tokendlist[peektoken()]) 16447139Sbostic return n1; 16547139Sbostic break; 16647139Sbostic case TEOF: 16747139Sbostic if (heredoclist) 16847139Sbostic parseheredoc(); 16947139Sbostic else 17047139Sbostic pungetc(); /* push back EOF on input */ 17147139Sbostic return n1; 17247139Sbostic default: 17347139Sbostic if (nlflag) 17447139Sbostic synexpect(-1); 17547139Sbostic tokpushback++; 17647139Sbostic return n1; 17747139Sbostic } 17847139Sbostic } 17947139Sbostic } 18047139Sbostic 18147139Sbostic 18247139Sbostic 18347139Sbostic STATIC union node * 18447139Sbostic andor() { 18547139Sbostic union node *n1, *n2, *n3; 18647139Sbostic int t; 18747139Sbostic 18847139Sbostic n1 = pipeline(); 18947139Sbostic for (;;) { 19047139Sbostic if ((t = readtoken()) == TAND) { 19147139Sbostic t = NAND; 19247139Sbostic } else if (t == TOR) { 19347139Sbostic t = NOR; 19447139Sbostic } else { 19547139Sbostic tokpushback++; 19647139Sbostic return n1; 19747139Sbostic } 19847139Sbostic n2 = pipeline(); 19947139Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 20047139Sbostic n3->type = t; 20147139Sbostic n3->nbinary.ch1 = n1; 20247139Sbostic n3->nbinary.ch2 = n2; 20347139Sbostic n1 = n3; 20447139Sbostic } 20547139Sbostic } 20647139Sbostic 20747139Sbostic 20847139Sbostic 20947139Sbostic STATIC union node * 21047139Sbostic pipeline() { 21153178Smarc union node *n1, *pipenode, *notnode; 21247139Sbostic struct nodelist *lp, *prev; 21353178Smarc int negate = 0; 21447139Sbostic 21553178Smarc TRACE(("pipeline: entered\n")); 21653178Smarc while (readtoken() == TNOT) { 21753178Smarc TRACE(("pipeline: TNOT recognized\n")); 21853178Smarc negate = !negate; 21953178Smarc } 22053178Smarc tokpushback++; 22147139Sbostic n1 = command(); 22247139Sbostic if (readtoken() == TPIPE) { 22347139Sbostic pipenode = (union node *)stalloc(sizeof (struct npipe)); 22447139Sbostic pipenode->type = NPIPE; 22547139Sbostic pipenode->npipe.backgnd = 0; 22647139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 22747139Sbostic pipenode->npipe.cmdlist = lp; 22847139Sbostic lp->n = n1; 22947139Sbostic do { 23047139Sbostic prev = lp; 23147139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 23247139Sbostic lp->n = command(); 23347139Sbostic prev->next = lp; 23447139Sbostic } while (readtoken() == TPIPE); 23547139Sbostic lp->next = NULL; 23647139Sbostic n1 = pipenode; 23747139Sbostic } 23847139Sbostic tokpushback++; 23953178Smarc if (negate) { 24053178Smarc notnode = (union node *)stalloc(sizeof (struct nnot)); 24153178Smarc notnode->type = NNOT; 24253178Smarc notnode->nnot.com = n1; 24353178Smarc n1 = notnode; 24453178Smarc } 24547139Sbostic return n1; 24647139Sbostic } 24747139Sbostic 24847139Sbostic 24947139Sbostic 25047139Sbostic STATIC union node * 25147139Sbostic command() { 25247139Sbostic union node *n1, *n2; 25347139Sbostic union node *ap, **app; 25447139Sbostic union node *cp, **cpp; 25547139Sbostic union node *redir, **rpp; 25647139Sbostic int t; 25747139Sbostic 25847981Smarc checkkwd = 2; 25960296Smarc redir = 0; 26060296Smarc rpp = &redir; 26160296Smarc /* Check for redirection which may precede command */ 26260296Smarc while (readtoken() == TREDIR) { 26360296Smarc *rpp = n2 = redirnode; 26460296Smarc rpp = &n2->nfile.next; 26560296Smarc parsefname(); 26660296Smarc } 26760296Smarc tokpushback++; 26860296Smarc 26947139Sbostic switch (readtoken()) { 27047139Sbostic case TIF: 27147139Sbostic n1 = (union node *)stalloc(sizeof (struct nif)); 27247139Sbostic n1->type = NIF; 27347139Sbostic n1->nif.test = list(0); 27447139Sbostic if (readtoken() != TTHEN) 27547139Sbostic synexpect(TTHEN); 27647139Sbostic n1->nif.ifpart = list(0); 27747139Sbostic n2 = n1; 27847139Sbostic while (readtoken() == TELIF) { 27947139Sbostic n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 28047139Sbostic n2 = n2->nif.elsepart; 28147139Sbostic n2->type = NIF; 28247139Sbostic n2->nif.test = list(0); 28347139Sbostic if (readtoken() != TTHEN) 28447139Sbostic synexpect(TTHEN); 28547139Sbostic n2->nif.ifpart = list(0); 28647139Sbostic } 28747139Sbostic if (lasttoken == TELSE) 28847139Sbostic n2->nif.elsepart = list(0); 28947139Sbostic else { 29047139Sbostic n2->nif.elsepart = NULL; 29147139Sbostic tokpushback++; 29247139Sbostic } 29347139Sbostic if (readtoken() != TFI) 29447139Sbostic synexpect(TFI); 29547981Smarc checkkwd = 1; 29647139Sbostic break; 29747139Sbostic case TWHILE: 29847981Smarc case TUNTIL: { 29947981Smarc int got; 30047139Sbostic n1 = (union node *)stalloc(sizeof (struct nbinary)); 30147139Sbostic n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 30247139Sbostic n1->nbinary.ch1 = list(0); 30347981Smarc if ((got=readtoken()) != TDO) { 30447981Smarc TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 30547139Sbostic synexpect(TDO); 30647981Smarc } 30747139Sbostic n1->nbinary.ch2 = list(0); 30847139Sbostic if (readtoken() != TDONE) 30947139Sbostic synexpect(TDONE); 31047981Smarc checkkwd = 1; 31147139Sbostic break; 31247981Smarc } 31347139Sbostic case TFOR: 31447139Sbostic if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 31547139Sbostic synerror("Bad for loop variable"); 31647139Sbostic n1 = (union node *)stalloc(sizeof (struct nfor)); 31747139Sbostic n1->type = NFOR; 31847139Sbostic n1->nfor.var = wordtext; 31947139Sbostic if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 32047139Sbostic app = ≈ 32147139Sbostic while (readtoken() == TWORD) { 32247139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 32347139Sbostic n2->type = NARG; 32447139Sbostic n2->narg.text = wordtext; 32547139Sbostic n2->narg.backquote = backquotelist; 32647139Sbostic *app = n2; 32747139Sbostic app = &n2->narg.next; 32847139Sbostic } 32947139Sbostic *app = NULL; 33047139Sbostic n1->nfor.args = ap; 33159178Storek if (lasttoken != TNL && lasttoken != TSEMI) 33259178Storek synexpect(-1); 33347139Sbostic } else { 33447139Sbostic #ifndef GDB_HACK 33547139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 33647139Sbostic '@', '=', '\0'}; 33747139Sbostic #endif 33847139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 33947139Sbostic n2->type = NARG; 34047139Sbostic n2->narg.text = (char *)argvars; 34147139Sbostic n2->narg.backquote = NULL; 34247139Sbostic n2->narg.next = NULL; 34347139Sbostic n1->nfor.args = n2; 34459178Storek /* 34559178Storek * Newline or semicolon here is optional (but note 34659178Storek * that the original Bourne shell only allowed NL). 34759178Storek */ 34859178Storek if (lasttoken != TNL && lasttoken != TSEMI) 34959178Storek tokpushback++; 35047139Sbostic } 35147981Smarc checkkwd = 2; 35247139Sbostic if ((t = readtoken()) == TDO) 35347139Sbostic t = TDONE; 35447139Sbostic else if (t == TBEGIN) 35547139Sbostic t = TEND; 35647139Sbostic else 35747139Sbostic synexpect(-1); 35847139Sbostic n1->nfor.body = list(0); 35947139Sbostic if (readtoken() != t) 36047139Sbostic synexpect(t); 36147981Smarc checkkwd = 1; 36247139Sbostic break; 36347139Sbostic case TCASE: 36447139Sbostic n1 = (union node *)stalloc(sizeof (struct ncase)); 36547139Sbostic n1->type = NCASE; 36647139Sbostic if (readtoken() != TWORD) 36747139Sbostic synexpect(TWORD); 36847139Sbostic n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 36947139Sbostic n2->type = NARG; 37047139Sbostic n2->narg.text = wordtext; 37147139Sbostic n2->narg.backquote = backquotelist; 37247139Sbostic n2->narg.next = NULL; 37347139Sbostic while (readtoken() == TNL); 37447139Sbostic if (lasttoken != TWORD || ! equal(wordtext, "in")) 37547139Sbostic synerror("expecting \"in\""); 37647139Sbostic cpp = &n1->ncase.cases; 37747981Smarc while (checkkwd = 2, readtoken() == TWORD) { 37847139Sbostic *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 37947139Sbostic cp->type = NCLIST; 38047139Sbostic app = &cp->nclist.pattern; 38147139Sbostic for (;;) { 38247139Sbostic *app = ap = (union node *)stalloc(sizeof (struct narg)); 38347139Sbostic ap->type = NARG; 38447139Sbostic ap->narg.text = wordtext; 38547139Sbostic ap->narg.backquote = backquotelist; 38647139Sbostic if (readtoken() != TPIPE) 38747139Sbostic break; 38847139Sbostic app = &ap->narg.next; 38947139Sbostic if (readtoken() != TWORD) 39047139Sbostic synexpect(TWORD); 39147139Sbostic } 39247139Sbostic ap->narg.next = NULL; 39347139Sbostic if (lasttoken != TRP) 39447139Sbostic synexpect(TRP); 39547139Sbostic cp->nclist.body = list(0); 39647139Sbostic if ((t = readtoken()) == TESAC) 39747139Sbostic tokpushback++; 39847139Sbostic else if (t != TENDCASE) 39947139Sbostic synexpect(TENDCASE); 40047139Sbostic cpp = &cp->nclist.next; 40147139Sbostic } 40247139Sbostic *cpp = NULL; 40347139Sbostic if (lasttoken != TESAC) 40447139Sbostic synexpect(TESAC); 40547981Smarc checkkwd = 1; 40647139Sbostic break; 40747139Sbostic case TLP: 40847139Sbostic n1 = (union node *)stalloc(sizeof (struct nredir)); 40947139Sbostic n1->type = NSUBSHELL; 41047139Sbostic n1->nredir.n = list(0); 41147139Sbostic n1->nredir.redirect = NULL; 41247139Sbostic if (readtoken() != TRP) 41347139Sbostic synexpect(TRP); 41447981Smarc checkkwd = 1; 41547139Sbostic break; 41647139Sbostic case TBEGIN: 41747139Sbostic n1 = list(0); 41847139Sbostic if (readtoken() != TEND) 41947139Sbostic synexpect(TEND); 42047981Smarc checkkwd = 1; 42147139Sbostic break; 42260296Smarc /* Handle an empty command like other simple commands. */ 423*68944Sbostic case TSEMI: 424*68944Sbostic /* 425*68944Sbostic * An empty command before a ; doesn't make much sense, and 426*68944Sbostic * should certainly be disallowed in the case of `if ;'. 427*68944Sbostic */ 428*68944Sbostic if (!redir) 429*68944Sbostic synexpect(-1); 43060296Smarc case TNL: 43147139Sbostic case TWORD: 432*68944Sbostic case TRP: 43347139Sbostic tokpushback++; 43460296Smarc return simplecmd(rpp, redir); 43547139Sbostic default: 43647139Sbostic synexpect(-1); 43747139Sbostic } 43847139Sbostic 43947139Sbostic /* Now check for redirection which may follow command */ 44047139Sbostic while (readtoken() == TREDIR) { 44147139Sbostic *rpp = n2 = redirnode; 44247139Sbostic rpp = &n2->nfile.next; 44347139Sbostic parsefname(); 44447139Sbostic } 44547139Sbostic tokpushback++; 44647139Sbostic *rpp = NULL; 44747139Sbostic if (redir) { 44847139Sbostic if (n1->type != NSUBSHELL) { 44947139Sbostic n2 = (union node *)stalloc(sizeof (struct nredir)); 45047139Sbostic n2->type = NREDIR; 45147139Sbostic n2->nredir.n = n1; 45247139Sbostic n1 = n2; 45347139Sbostic } 45447139Sbostic n1->nredir.redirect = redir; 45547139Sbostic } 45647139Sbostic return n1; 45747139Sbostic } 45847139Sbostic 45947139Sbostic 46047139Sbostic STATIC union node * 46160296Smarc simplecmd(rpp, redir) 46260296Smarc union node **rpp, *redir; 46360296Smarc { 46447139Sbostic union node *args, **app; 46560296Smarc union node **orig_rpp = rpp; 46647139Sbostic union node *n; 46747139Sbostic 46860296Smarc /* If we don't have any redirections already, then we must reset */ 46960296Smarc /* rpp to be the address of the local redir variable. */ 47060296Smarc if (redir == 0) 47160296Smarc rpp = &redir; 47260296Smarc 47347139Sbostic args = NULL; 47447139Sbostic app = &args; 47560296Smarc /* 47660296Smarc * We save the incoming value, because we need this for shell 47760296Smarc * functions. There can not be a redirect or an argument between 47860296Smarc * the function name and the open parenthesis. 47960296Smarc */ 48060296Smarc orig_rpp = rpp; 48160296Smarc 48247139Sbostic for (;;) { 48347139Sbostic if (readtoken() == TWORD) { 48447139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 48547139Sbostic n->type = NARG; 48647139Sbostic n->narg.text = wordtext; 48747139Sbostic n->narg.backquote = backquotelist; 48847139Sbostic *app = n; 48947139Sbostic app = &n->narg.next; 49047139Sbostic } else if (lasttoken == TREDIR) { 49147139Sbostic *rpp = n = redirnode; 49247139Sbostic rpp = &n->nfile.next; 49347139Sbostic parsefname(); /* read name of redirection file */ 49447139Sbostic } else if (lasttoken == TLP && app == &args->narg.next 49560296Smarc && rpp == orig_rpp) { 49647139Sbostic /* We have a function */ 49747139Sbostic if (readtoken() != TRP) 49847139Sbostic synexpect(TRP); 49947300Smarc #ifdef notdef 50047139Sbostic if (! goodname(n->narg.text)) 50147139Sbostic synerror("Bad function name"); 50247300Smarc #endif 50347139Sbostic n->type = NDEFUN; 50447139Sbostic n->narg.next = command(); 50547139Sbostic return n; 50647139Sbostic } else { 50747139Sbostic tokpushback++; 50847139Sbostic break; 50947139Sbostic } 51047139Sbostic } 51147139Sbostic *app = NULL; 51247139Sbostic *rpp = NULL; 51347139Sbostic n = (union node *)stalloc(sizeof (struct ncmd)); 51447139Sbostic n->type = NCMD; 51547139Sbostic n->ncmd.backgnd = 0; 51647139Sbostic n->ncmd.args = args; 51747139Sbostic n->ncmd.redirect = redir; 51847139Sbostic return n; 51947139Sbostic } 52047139Sbostic 52147139Sbostic 52247139Sbostic STATIC void 52347139Sbostic parsefname() { 52447139Sbostic union node *n = redirnode; 52547139Sbostic 52647139Sbostic if (readtoken() != TWORD) 52747139Sbostic synexpect(-1); 52847139Sbostic if (n->type == NHERE) { 52947139Sbostic struct heredoc *here = heredoc; 53047139Sbostic struct heredoc *p; 53147139Sbostic int i; 53247139Sbostic 53347139Sbostic if (quoteflag == 0) 53447139Sbostic n->type = NXHERE; 53547139Sbostic TRACE(("Here document %d\n", n->type)); 53647139Sbostic if (here->striptabs) { 53747139Sbostic while (*wordtext == '\t') 53847139Sbostic wordtext++; 53947139Sbostic } 54047139Sbostic if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 54147139Sbostic synerror("Illegal eof marker for << redirection"); 54247139Sbostic rmescapes(wordtext); 54347139Sbostic here->eofmark = wordtext; 54447139Sbostic here->next = NULL; 54547139Sbostic if (heredoclist == NULL) 54647139Sbostic heredoclist = here; 54747139Sbostic else { 54847139Sbostic for (p = heredoclist ; p->next ; p = p->next); 54947139Sbostic p->next = here; 55047139Sbostic } 55147139Sbostic } else if (n->type == NTOFD || n->type == NFROMFD) { 55247139Sbostic if (is_digit(wordtext[0])) 55347139Sbostic n->ndup.dupfd = digit_val(wordtext[0]); 55447139Sbostic else if (wordtext[0] == '-') 55547139Sbostic n->ndup.dupfd = -1; 55647139Sbostic else 55747139Sbostic goto bad; 55847139Sbostic if (wordtext[1] != '\0') { 55947139Sbostic bad: 56047139Sbostic synerror("Bad fd number"); 56147139Sbostic } 56247139Sbostic } else { 56347139Sbostic n->nfile.fname = (union node *)stalloc(sizeof (struct narg)); 56447139Sbostic n = n->nfile.fname; 56547139Sbostic n->type = NARG; 56647139Sbostic n->narg.next = NULL; 56747139Sbostic n->narg.text = wordtext; 56847139Sbostic n->narg.backquote = backquotelist; 56947139Sbostic } 57047139Sbostic } 57147139Sbostic 57247139Sbostic 57347139Sbostic /* 57447139Sbostic * Input any here documents. 57547139Sbostic */ 57647139Sbostic 57747139Sbostic STATIC void 57847139Sbostic parseheredoc() { 57947139Sbostic struct heredoc *here; 58047139Sbostic union node *n; 58147139Sbostic 58247139Sbostic while (heredoclist) { 58347139Sbostic here = heredoclist; 58447139Sbostic heredoclist = here->next; 58547139Sbostic if (needprompt) { 58654322Smarc setprompt(2); 58747139Sbostic needprompt = 0; 58847139Sbostic } 58947139Sbostic readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 59047139Sbostic here->eofmark, here->striptabs); 59147139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 59247139Sbostic n->narg.type = NARG; 59347139Sbostic n->narg.next = NULL; 59447139Sbostic n->narg.text = wordtext; 59547139Sbostic n->narg.backquote = backquotelist; 59647139Sbostic here->here->nhere.doc = n; 59747139Sbostic } 59847139Sbostic } 59947139Sbostic 60047981Smarc STATIC int 60147981Smarc peektoken() { 60247139Sbostic int t; 60347139Sbostic 60447981Smarc t = readtoken(); 60547139Sbostic tokpushback++; 60647981Smarc return (t); 60747139Sbostic } 60847139Sbostic 60947139Sbostic STATIC int xxreadtoken(); 61047139Sbostic 61147139Sbostic STATIC int 61247139Sbostic readtoken() { 61347139Sbostic int t; 61454322Smarc int savecheckkwd = checkkwd; 61554322Smarc struct alias *ap; 61647981Smarc #ifdef DEBUG 61747981Smarc int alreadyseen = tokpushback; 61847981Smarc #endif 61947981Smarc 62054322Smarc top: 62147981Smarc t = xxreadtoken(); 62247139Sbostic 62347981Smarc if (checkkwd) { 62447981Smarc /* 62547981Smarc * eat newlines 62647981Smarc */ 62747981Smarc if (checkkwd == 2) { 62847981Smarc checkkwd = 0; 62947981Smarc while (t == TNL) { 63047981Smarc parseheredoc(); 63147981Smarc t = xxreadtoken(); 63247981Smarc } 63347981Smarc } else 63447981Smarc checkkwd = 0; 63547981Smarc /* 63654322Smarc * check for keywords and aliases 63747981Smarc */ 63847981Smarc if (t == TWORD && !quoteflag) { 63954322Smarc register char * const *pp, *s; 64047981Smarc 64160296Smarc for (pp = (char **)parsekwd; *pp; pp++) { 64247981Smarc if (**pp == *wordtext && equal(*pp, wordtext)) { 64347981Smarc lasttoken = t = pp - parsekwd + KWDOFFSET; 64447981Smarc TRACE(("keyword %s recognized\n", tokname[t])); 64554322Smarc goto out; 64647981Smarc } 64747981Smarc } 64854322Smarc if (ap = lookupalias(wordtext, 1)) { 64954322Smarc pushstring(ap->val, strlen(ap->val), ap); 65054322Smarc checkkwd = savecheckkwd; 65154322Smarc goto top; 65254322Smarc } 65347981Smarc } 65454322Smarc out: 65554322Smarc checkkwd = 0; 65647139Sbostic } 65747981Smarc #ifdef DEBUG 65847981Smarc if (!alreadyseen) 65947981Smarc TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 66047981Smarc else 66147981Smarc TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 66247981Smarc #endif 66347981Smarc return (t); 66447139Sbostic } 66547139Sbostic 66647139Sbostic 66747139Sbostic /* 66847139Sbostic * Read the next input token. 66947139Sbostic * If the token is a word, we set backquotelist to the list of cmds in 67047139Sbostic * backquotes. We set quoteflag to true if any part of the word was 67147139Sbostic * quoted. 67247139Sbostic * If the token is TREDIR, then we set redirnode to a structure containing 67347139Sbostic * the redirection. 67447139Sbostic * In all cases, the variable startlinno is set to the number of the line 67547139Sbostic * on which the token starts. 67647139Sbostic * 67747139Sbostic * [Change comment: here documents and internal procedures] 67847139Sbostic * [Readtoken shouldn't have any arguments. Perhaps we should make the 67947139Sbostic * word parsing code into a separate routine. In this case, readtoken 68047139Sbostic * doesn't need to have any internal procedures, but parseword does. 68147139Sbostic * We could also make parseoperator in essence the main routine, and 68247139Sbostic * have parseword (readtoken1?) handle both words and redirection.] 68347139Sbostic */ 68447139Sbostic 68547139Sbostic #define RETURN(token) return lasttoken = token 68647139Sbostic 68747139Sbostic STATIC int 68847139Sbostic xxreadtoken() { 68947139Sbostic register c; 69047139Sbostic 69147139Sbostic if (tokpushback) { 69247139Sbostic tokpushback = 0; 69347139Sbostic return lasttoken; 69447139Sbostic } 69547139Sbostic if (needprompt) { 69654322Smarc setprompt(2); 69747139Sbostic needprompt = 0; 69847139Sbostic } 69947139Sbostic startlinno = plinno; 70047139Sbostic for (;;) { /* until token or start of word found */ 70147139Sbostic c = pgetc_macro(); 70247139Sbostic if (c == ' ' || c == '\t') 70347139Sbostic continue; /* quick check for white space first */ 70447139Sbostic switch (c) { 70547139Sbostic case ' ': case '\t': 70647139Sbostic continue; 70747139Sbostic case '#': 70847139Sbostic while ((c = pgetc()) != '\n' && c != PEOF); 70947139Sbostic pungetc(); 71047139Sbostic continue; 71147139Sbostic case '\\': 71247139Sbostic if (pgetc() == '\n') { 71347139Sbostic startlinno = ++plinno; 71447139Sbostic if (doprompt) 71554322Smarc setprompt(2); 71654322Smarc else 71754322Smarc setprompt(0); 71847139Sbostic continue; 71947139Sbostic } 72047139Sbostic pungetc(); 72147139Sbostic goto breakloop; 72247139Sbostic case '\n': 72347139Sbostic plinno++; 72447139Sbostic needprompt = doprompt; 72547139Sbostic RETURN(TNL); 72647139Sbostic case PEOF: 72747139Sbostic RETURN(TEOF); 72847139Sbostic case '&': 72947139Sbostic if (pgetc() == '&') 73047139Sbostic RETURN(TAND); 73147139Sbostic pungetc(); 73247139Sbostic RETURN(TBACKGND); 73347139Sbostic case '|': 73447139Sbostic if (pgetc() == '|') 73547139Sbostic RETURN(TOR); 73647139Sbostic pungetc(); 73747139Sbostic RETURN(TPIPE); 73847139Sbostic case ';': 73947139Sbostic if (pgetc() == ';') 74047139Sbostic RETURN(TENDCASE); 74147139Sbostic pungetc(); 74247139Sbostic RETURN(TSEMI); 74347139Sbostic case '(': 74447139Sbostic RETURN(TLP); 74547139Sbostic case ')': 74647139Sbostic RETURN(TRP); 74747139Sbostic default: 74847139Sbostic goto breakloop; 74947139Sbostic } 75047139Sbostic } 75147139Sbostic breakloop: 75247139Sbostic return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 75347139Sbostic #undef RETURN 75447139Sbostic } 75547139Sbostic 75647139Sbostic 75747139Sbostic 75847139Sbostic /* 75947139Sbostic * If eofmark is NULL, read a word or a redirection symbol. If eofmark 76047139Sbostic * is not NULL, read a here document. In the latter case, eofmark is the 76147139Sbostic * word which marks the end of the document and striptabs is true if 76247139Sbostic * leading tabs should be stripped from the document. The argument firstc 76347139Sbostic * is the first character of the input token or document. 76447139Sbostic * 76547139Sbostic * Because C does not have internal subroutines, I have simulated them 76647139Sbostic * using goto's to implement the subroutine linkage. The following macros 76747139Sbostic * will run code that appears at the end of readtoken1. 76847139Sbostic */ 76947139Sbostic 77047139Sbostic #define CHECKEND() {goto checkend; checkend_return:;} 77147139Sbostic #define PARSEREDIR() {goto parseredir; parseredir_return:;} 77247139Sbostic #define PARSESUB() {goto parsesub; parsesub_return:;} 77347139Sbostic #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 77447139Sbostic #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 77553302Smarc #define PARSEARITH() {goto parsearith; parsearith_return:;} 77647139Sbostic 77747139Sbostic STATIC int 77847139Sbostic readtoken1(firstc, syntax, eofmark, striptabs) 77947139Sbostic int firstc; 78047139Sbostic char const *syntax; 78147139Sbostic char *eofmark; 78247139Sbostic int striptabs; 78347139Sbostic { 78447139Sbostic register c = firstc; 78547139Sbostic register char *out; 78647139Sbostic int len; 78747139Sbostic char line[EOFMARKLEN + 1]; 78847139Sbostic struct nodelist *bqlist; 78947139Sbostic int quotef; 79047139Sbostic int dblquote; 79153302Smarc int varnest; /* levels of variables expansion */ 79253302Smarc int arinest; /* levels of arithmetic expansion */ 79353302Smarc int parenlevel; /* levels of parens in arithmetic */ 79447139Sbostic int oldstyle; 79553302Smarc char const *prevsyntax; /* syntax before arithmetic */ 79647139Sbostic 79747139Sbostic startlinno = plinno; 79847139Sbostic dblquote = 0; 79947139Sbostic if (syntax == DQSYNTAX) 80047139Sbostic dblquote = 1; 80147139Sbostic quotef = 0; 80247139Sbostic bqlist = NULL; 80347139Sbostic varnest = 0; 80453302Smarc arinest = 0; 80553302Smarc parenlevel = 0; 80653302Smarc 80747139Sbostic STARTSTACKSTR(out); 80847139Sbostic loop: { /* for each line, until end of word */ 80947139Sbostic #if ATTY 81047139Sbostic if (c == '\034' && doprompt 81147139Sbostic && attyset() && ! equal(termval(), "emacs")) { 81247139Sbostic attyline(); 81347139Sbostic if (syntax == BASESYNTAX) 81447139Sbostic return readtoken(); 81547139Sbostic c = pgetc(); 81647139Sbostic goto loop; 81747139Sbostic } 81847139Sbostic #endif 81947139Sbostic CHECKEND(); /* set c to PEOF if at end of here document */ 82047139Sbostic for (;;) { /* until end of line or end of word */ 82147139Sbostic CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 82259177Smarc if (parsebackquote && c == '\\') { 82358381Smarc c = pgetc(); /* XXX - compat with old /bin/sh */ 82459177Smarc if (c != '\\' && c != '`' && c != '$') { 82559177Smarc pungetc(); 82659177Smarc c = '\\'; 82759177Smarc } 82859177Smarc } 82947139Sbostic switch(syntax[c]) { 83047139Sbostic case CNL: /* '\n' */ 83147139Sbostic if (syntax == BASESYNTAX) 83247139Sbostic goto endword; /* exit outer loop */ 83347139Sbostic USTPUTC(c, out); 83447139Sbostic plinno++; 83554322Smarc if (doprompt) 83654322Smarc setprompt(2); 83754322Smarc else 83854322Smarc setprompt(0); 83947139Sbostic c = pgetc(); 84047139Sbostic goto loop; /* continue outer loop */ 84147139Sbostic case CWORD: 84247139Sbostic USTPUTC(c, out); 84347139Sbostic break; 84447139Sbostic case CCTL: 84547139Sbostic if (eofmark == NULL || dblquote) 84647139Sbostic USTPUTC(CTLESC, out); 84747139Sbostic USTPUTC(c, out); 84847139Sbostic break; 84947139Sbostic case CBACK: /* backslash */ 85047139Sbostic c = pgetc(); 85147139Sbostic if (c == PEOF) { 85247139Sbostic USTPUTC('\\', out); 85347139Sbostic pungetc(); 85447139Sbostic } else if (c == '\n') { 85547139Sbostic if (doprompt) 85654322Smarc setprompt(2); 85754322Smarc else 85854322Smarc setprompt(0); 85947139Sbostic } else { 86047139Sbostic if (dblquote && c != '\\' && c != '`' && c != '$' 86147139Sbostic && (c != '"' || eofmark != NULL)) 86247139Sbostic USTPUTC('\\', out); 86347139Sbostic if (SQSYNTAX[c] == CCTL) 86447139Sbostic USTPUTC(CTLESC, out); 86547139Sbostic USTPUTC(c, out); 86647139Sbostic quotef++; 86747139Sbostic } 86847139Sbostic break; 86947139Sbostic case CSQUOTE: 87047139Sbostic syntax = SQSYNTAX; 87147139Sbostic break; 87247139Sbostic case CDQUOTE: 87347139Sbostic syntax = DQSYNTAX; 87447139Sbostic dblquote = 1; 87547139Sbostic break; 87647139Sbostic case CENDQUOTE: 87747139Sbostic if (eofmark) { 87847139Sbostic USTPUTC(c, out); 87947139Sbostic } else { 88053302Smarc if (arinest) 88153302Smarc syntax = ARISYNTAX; 88253302Smarc else 88353302Smarc syntax = BASESYNTAX; 88447139Sbostic quotef++; 88547139Sbostic dblquote = 0; 88647139Sbostic } 88747139Sbostic break; 88847139Sbostic case CVAR: /* '$' */ 88947139Sbostic PARSESUB(); /* parse substitution */ 89047139Sbostic break; 89147139Sbostic case CENDVAR: /* '}' */ 89247139Sbostic if (varnest > 0) { 89347139Sbostic varnest--; 89447139Sbostic USTPUTC(CTLENDVAR, out); 89547139Sbostic } else { 89647139Sbostic USTPUTC(c, out); 89747139Sbostic } 89847139Sbostic break; 89953302Smarc case CLP: /* '(' in arithmetic */ 90053302Smarc parenlevel++; 90153302Smarc USTPUTC(c, out); 90253302Smarc break; 90353302Smarc case CRP: /* ')' in arithmetic */ 90453302Smarc if (parenlevel > 0) { 90553302Smarc USTPUTC(c, out); 90653302Smarc --parenlevel; 90753302Smarc } else { 90853302Smarc if (pgetc() == ')') { 90953302Smarc if (--arinest == 0) { 91053302Smarc USTPUTC(CTLENDARI, out); 91153302Smarc syntax = prevsyntax; 91253302Smarc } else 91353302Smarc USTPUTC(')', out); 91453302Smarc } else { 91553302Smarc /* 91653302Smarc * unbalanced parens 91753302Smarc * (don't 2nd guess - no error) 91853302Smarc */ 91953302Smarc pungetc(); 92053302Smarc USTPUTC(')', out); 92153302Smarc } 92253302Smarc } 92353302Smarc break; 92447139Sbostic case CBQUOTE: /* '`' */ 92547139Sbostic PARSEBACKQOLD(); 92647139Sbostic break; 92747139Sbostic case CEOF: 92847139Sbostic goto endword; /* exit outer loop */ 92947139Sbostic default: 93047139Sbostic if (varnest == 0) 93147139Sbostic goto endword; /* exit outer loop */ 93247139Sbostic USTPUTC(c, out); 93347139Sbostic } 93447139Sbostic c = pgetc_macro(); 93547139Sbostic } 93647139Sbostic } 93747139Sbostic endword: 93853302Smarc if (syntax == ARISYNTAX) 93953302Smarc synerror("Missing '))'"); 94060296Smarc if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 94147139Sbostic synerror("Unterminated quoted string"); 94247139Sbostic if (varnest != 0) { 94347139Sbostic startlinno = plinno; 94447139Sbostic synerror("Missing '}'"); 94547139Sbostic } 94647139Sbostic USTPUTC('\0', out); 94747139Sbostic len = out - stackblock(); 94847139Sbostic out = stackblock(); 94947139Sbostic if (eofmark == NULL) { 95047139Sbostic if ((c == '>' || c == '<') 95147139Sbostic && quotef == 0 95247139Sbostic && len <= 2 95347139Sbostic && (*out == '\0' || is_digit(*out))) { 95447139Sbostic PARSEREDIR(); 95547139Sbostic return lasttoken = TREDIR; 95647139Sbostic } else { 95747139Sbostic pungetc(); 95847139Sbostic } 95947139Sbostic } 96047139Sbostic quoteflag = quotef; 96147139Sbostic backquotelist = bqlist; 96247139Sbostic grabstackblock(len); 96347139Sbostic wordtext = out; 96447139Sbostic return lasttoken = TWORD; 96547139Sbostic /* end of readtoken routine */ 96647139Sbostic 96747139Sbostic 96847139Sbostic 96947139Sbostic /* 97047139Sbostic * Check to see whether we are at the end of the here document. When this 97147139Sbostic * is called, c is set to the first character of the next input line. If 97247139Sbostic * we are at the end of the here document, this routine sets the c to PEOF. 97347139Sbostic */ 97447139Sbostic 97547139Sbostic checkend: { 97647139Sbostic if (eofmark) { 97747139Sbostic if (striptabs) { 97847139Sbostic while (c == '\t') 97947139Sbostic c = pgetc(); 98047139Sbostic } 98147139Sbostic if (c == *eofmark) { 98247139Sbostic if (pfgets(line, sizeof line) != NULL) { 98347139Sbostic register char *p, *q; 98447139Sbostic 98547139Sbostic p = line; 98647139Sbostic for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 98747139Sbostic if (*p == '\n' && *q == '\0') { 98847139Sbostic c = PEOF; 98947139Sbostic plinno++; 99047139Sbostic needprompt = doprompt; 99147139Sbostic } else { 99254322Smarc pushstring(line, strlen(line), NULL); 99347139Sbostic } 99447139Sbostic } 99547139Sbostic } 99647139Sbostic } 99747139Sbostic goto checkend_return; 99847139Sbostic } 99947139Sbostic 100047139Sbostic 100147139Sbostic /* 100247139Sbostic * Parse a redirection operator. The variable "out" points to a string 100347139Sbostic * specifying the fd to be redirected. The variable "c" contains the 100447139Sbostic * first character of the redirection operator. 100547139Sbostic */ 100647139Sbostic 100747139Sbostic parseredir: { 100847139Sbostic char fd = *out; 100947139Sbostic union node *np; 101047139Sbostic 101147139Sbostic np = (union node *)stalloc(sizeof (struct nfile)); 101247139Sbostic if (c == '>') { 101347139Sbostic np->nfile.fd = 1; 101447139Sbostic c = pgetc(); 101547139Sbostic if (c == '>') 101647139Sbostic np->type = NAPPEND; 101747139Sbostic else if (c == '&') 101847139Sbostic np->type = NTOFD; 101947139Sbostic else { 102047139Sbostic np->type = NTO; 102147139Sbostic pungetc(); 102247139Sbostic } 102347139Sbostic } else { /* c == '<' */ 102447139Sbostic np->nfile.fd = 0; 102547139Sbostic c = pgetc(); 102647139Sbostic if (c == '<') { 102747139Sbostic if (sizeof (struct nfile) != sizeof (struct nhere)) { 102847139Sbostic np = (union node *)stalloc(sizeof (struct nhere)); 102947139Sbostic np->nfile.fd = 0; 103047139Sbostic } 103147139Sbostic np->type = NHERE; 103247139Sbostic heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 103347139Sbostic heredoc->here = np; 103447139Sbostic if ((c = pgetc()) == '-') { 103547139Sbostic heredoc->striptabs = 1; 103647139Sbostic } else { 103747139Sbostic heredoc->striptabs = 0; 103847139Sbostic pungetc(); 103947139Sbostic } 104047139Sbostic } else if (c == '&') 104147139Sbostic np->type = NFROMFD; 104247139Sbostic else { 104347139Sbostic np->type = NFROM; 104447139Sbostic pungetc(); 104547139Sbostic } 104647139Sbostic } 104747139Sbostic if (fd != '\0') 104847139Sbostic np->nfile.fd = digit_val(fd); 104947139Sbostic redirnode = np; 105047139Sbostic goto parseredir_return; 105147139Sbostic } 105247139Sbostic 105347139Sbostic 105447139Sbostic /* 105547139Sbostic * Parse a substitution. At this point, we have read the dollar sign 105647139Sbostic * and nothing else. 105747139Sbostic */ 105847139Sbostic 105947139Sbostic parsesub: { 106047139Sbostic int subtype; 106147139Sbostic int typeloc; 106247139Sbostic int flags; 106347139Sbostic char *p; 106447139Sbostic #ifndef GDB_HACK 106547139Sbostic static const char types[] = "}-+?="; 106647139Sbostic #endif 106747139Sbostic 106847139Sbostic c = pgetc(); 106947300Smarc if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 107047139Sbostic USTPUTC('$', out); 107147139Sbostic pungetc(); 107253302Smarc } else if (c == '(') { /* $(command) or $((arith)) */ 107353302Smarc if (pgetc() == '(') { 107453302Smarc PARSEARITH(); 107553302Smarc } else { 107653302Smarc pungetc(); 107753302Smarc PARSEBACKQNEW(); 107853302Smarc } 107947139Sbostic } else { 108047139Sbostic USTPUTC(CTLVAR, out); 108147139Sbostic typeloc = out - stackblock(); 108247139Sbostic USTPUTC(VSNORMAL, out); 108347139Sbostic subtype = VSNORMAL; 108447139Sbostic if (c == '{') { 108547139Sbostic c = pgetc(); 108647139Sbostic subtype = 0; 108747139Sbostic } 108847139Sbostic if (is_name(c)) { 108947139Sbostic do { 109047139Sbostic STPUTC(c, out); 109147139Sbostic c = pgetc(); 109247139Sbostic } while (is_in_name(c)); 109347139Sbostic } else { 109447139Sbostic if (! is_special(c)) 109547300Smarc badsub: synerror("Bad substitution"); 109647139Sbostic USTPUTC(c, out); 109747139Sbostic c = pgetc(); 109847139Sbostic } 109947139Sbostic STPUTC('=', out); 110047139Sbostic flags = 0; 110147139Sbostic if (subtype == 0) { 110247139Sbostic if (c == ':') { 110347139Sbostic flags = VSNUL; 110447139Sbostic c = pgetc(); 110547139Sbostic } 110647139Sbostic p = strchr(types, c); 110747139Sbostic if (p == NULL) 110847139Sbostic goto badsub; 110947139Sbostic subtype = p - types + VSNORMAL; 111047139Sbostic } else { 111147139Sbostic pungetc(); 111247139Sbostic } 111353302Smarc if (dblquote || arinest) 111447139Sbostic flags |= VSQUOTE; 111547139Sbostic *(stackblock() + typeloc) = subtype | flags; 111647139Sbostic if (subtype != VSNORMAL) 111747139Sbostic varnest++; 111847139Sbostic } 111947139Sbostic goto parsesub_return; 112047139Sbostic } 112147139Sbostic 112247139Sbostic 112347139Sbostic /* 112447139Sbostic * Called to parse command substitutions. Newstyle is set if the command 112547139Sbostic * is enclosed inside $(...); nlpp is a pointer to the head of the linked 112647139Sbostic * list of commands (passed by reference), and savelen is the number of 112747139Sbostic * characters on the top of the stack which must be preserved. 112847139Sbostic */ 112947139Sbostic 113047139Sbostic parsebackq: { 113147139Sbostic struct nodelist **nlpp; 113247139Sbostic int savepbq; 113347139Sbostic union node *n; 113447139Sbostic char *volatile str; 113547139Sbostic struct jmploc jmploc; 113647139Sbostic struct jmploc *volatile savehandler; 113747139Sbostic int savelen; 113847139Sbostic 113947139Sbostic savepbq = parsebackquote; 114047139Sbostic if (setjmp(jmploc.loc)) { 114147139Sbostic if (str) 114247139Sbostic ckfree(str); 114347139Sbostic parsebackquote = 0; 114447139Sbostic handler = savehandler; 114554322Smarc longjmp(handler->loc, 1); 114647139Sbostic } 114747139Sbostic INTOFF; 114847139Sbostic str = NULL; 114947139Sbostic savelen = out - stackblock(); 115047139Sbostic if (savelen > 0) { 115147139Sbostic str = ckmalloc(savelen); 115247139Sbostic bcopy(stackblock(), str, savelen); 115347139Sbostic } 115447139Sbostic savehandler = handler; 115547139Sbostic handler = &jmploc; 115647139Sbostic INTON; 115760296Smarc if (oldstyle) { 115860296Smarc /* We must read until the closing backquote, giving special 115960296Smarc treatment to some slashes, and then push the string and 116060296Smarc reread it as input, interpreting it normally. */ 116160296Smarc register char *out; 116260296Smarc register c; 116360296Smarc int savelen; 116460296Smarc char *str; 116560296Smarc 116660296Smarc STARTSTACKSTR(out); 116760296Smarc while ((c = pgetc ()) != '`') { 116860296Smarc if (c == '\\') { 116960296Smarc c = pgetc (); 117060296Smarc if (c != '\\' && c != '`' && c != '$' 117160296Smarc && (!dblquote || c != '"')) 117260296Smarc STPUTC('\\', out); 117360296Smarc } 117460296Smarc STPUTC(c, out); 117560296Smarc } 117660296Smarc STPUTC('\0', out); 117760296Smarc savelen = out - stackblock(); 117860296Smarc if (savelen > 0) { 117960296Smarc str = ckmalloc(savelen); 118060296Smarc bcopy(stackblock(), str, savelen); 118160296Smarc } 118260296Smarc setinputstring(str, 1); 118360296Smarc } 118447139Sbostic nlpp = &bqlist; 118547139Sbostic while (*nlpp) 118647139Sbostic nlpp = &(*nlpp)->next; 118747139Sbostic *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 118847139Sbostic (*nlpp)->next = NULL; 118947139Sbostic parsebackquote = oldstyle; 119047139Sbostic n = list(0); 119160296Smarc if (!oldstyle && (readtoken() != TRP)) 119260296Smarc synexpect(TRP); 119347139Sbostic (*nlpp)->n = n; 119460296Smarc /* Start reading from old file again. */ 119560296Smarc if (oldstyle) 119660296Smarc popfile(); 119747139Sbostic while (stackblocksize() <= savelen) 119847139Sbostic growstackblock(); 119947139Sbostic STARTSTACKSTR(out); 120047139Sbostic if (str) { 120147139Sbostic bcopy(str, out, savelen); 120247139Sbostic STADJUST(savelen, out); 120347139Sbostic INTOFF; 120447139Sbostic ckfree(str); 120547139Sbostic str = NULL; 120647139Sbostic INTON; 120747139Sbostic } 120847139Sbostic parsebackquote = savepbq; 120947139Sbostic handler = savehandler; 121053302Smarc if (arinest || dblquote) 121153302Smarc USTPUTC(CTLBACKQ | CTLQUOTE, out); 121253302Smarc else 121353302Smarc USTPUTC(CTLBACKQ, out); 121447139Sbostic if (oldstyle) 121547139Sbostic goto parsebackq_oldreturn; 121647139Sbostic else 121747139Sbostic goto parsebackq_newreturn; 121847139Sbostic } 121947139Sbostic 122053302Smarc /* 122153302Smarc * Parse an arithmetic expansion (indicate start of one and set state) 122253302Smarc */ 122353302Smarc parsearith: { 122453302Smarc 122553302Smarc if (++arinest == 1) { 122653302Smarc prevsyntax = syntax; 122753302Smarc syntax = ARISYNTAX; 122853302Smarc USTPUTC(CTLARI, out); 122953302Smarc } else { 123053302Smarc /* 123153302Smarc * we collapse embedded arithmetic expansion to 123253302Smarc * parenthesis, which should be equivalent 123353302Smarc */ 123453302Smarc USTPUTC('(', out); 123553302Smarc } 123653302Smarc goto parsearith_return; 123753302Smarc } 123853302Smarc 123947139Sbostic } /* end of readtoken */ 124047139Sbostic 124147139Sbostic 124247139Sbostic 124347139Sbostic #ifdef mkinit 124447139Sbostic RESET { 124547139Sbostic tokpushback = 0; 124654322Smarc checkkwd = 0; 124747139Sbostic } 124847139Sbostic #endif 124947139Sbostic 125047139Sbostic /* 125147139Sbostic * Returns true if the text contains nothing to expand (no dollar signs 125247139Sbostic * or backquotes). 125347139Sbostic */ 125447139Sbostic 125547139Sbostic STATIC int 125647139Sbostic noexpand(text) 125747139Sbostic char *text; 125847139Sbostic { 125947139Sbostic register char *p; 126047139Sbostic register char c; 126147139Sbostic 126247139Sbostic p = text; 126347139Sbostic while ((c = *p++) != '\0') { 126447139Sbostic if (c == CTLESC) 126547139Sbostic p++; 126647139Sbostic else if (BASESYNTAX[c] == CCTL) 126747139Sbostic return 0; 126847139Sbostic } 126947139Sbostic return 1; 127047139Sbostic } 127147139Sbostic 127247139Sbostic 127347139Sbostic /* 127447139Sbostic * Return true if the argument is a legal variable name (a letter or 127547139Sbostic * underscore followed by zero or more letters, underscores, and digits). 127647139Sbostic */ 127747139Sbostic 127847139Sbostic int 127947139Sbostic goodname(name) 128047139Sbostic char *name; 128147139Sbostic { 128247139Sbostic register char *p; 128347139Sbostic 128447139Sbostic p = name; 128547139Sbostic if (! is_name(*p)) 128647139Sbostic return 0; 128747139Sbostic while (*++p) { 128847139Sbostic if (! is_in_name(*p)) 128947139Sbostic return 0; 129047139Sbostic } 129147139Sbostic return 1; 129247139Sbostic } 129347139Sbostic 129447139Sbostic 129547139Sbostic /* 129647139Sbostic * Called when an unexpected token is read during the parse. The argument 129747139Sbostic * is the token that is expected, or -1 if more than one type of token can 129847139Sbostic * occur at this point. 129947139Sbostic */ 130047139Sbostic 130147139Sbostic STATIC void 130247139Sbostic synexpect(token) { 130347139Sbostic char msg[64]; 130447139Sbostic 130547139Sbostic if (token >= 0) { 130647139Sbostic fmtstr(msg, 64, "%s unexpected (expecting %s)", 130747139Sbostic tokname[lasttoken], tokname[token]); 130847139Sbostic } else { 130947139Sbostic fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 131047139Sbostic } 131147139Sbostic synerror(msg); 131247139Sbostic } 131347139Sbostic 131447139Sbostic 131547139Sbostic STATIC void 131647139Sbostic synerror(msg) 131747139Sbostic char *msg; 131847139Sbostic { 131947139Sbostic if (commandname) 132047139Sbostic outfmt(&errout, "%s: %d: ", commandname, startlinno); 132147139Sbostic outfmt(&errout, "Syntax error: %s\n", msg); 132247139Sbostic error((char *)NULL); 132347139Sbostic } 132454322Smarc 132554322Smarc STATIC void 132654322Smarc setprompt(which) 132754322Smarc int which; 132854322Smarc { 132954322Smarc whichprompt = which; 133054322Smarc 133154322Smarc if (!el) 133254322Smarc out2str(getprompt(NULL)); 133354322Smarc } 133454322Smarc 133554322Smarc /* 133654322Smarc * called by editline -- any expansions to the prompt 133754322Smarc * should be added here. 133854322Smarc */ 133954322Smarc char * 134054322Smarc getprompt(unused) 134154322Smarc void *unused; 134254322Smarc { 134354322Smarc switch (whichprompt) { 134454322Smarc case 0: 134554322Smarc return ""; 134654322Smarc case 1: 134754322Smarc return ps1val(); 134854322Smarc case 2: 134954322Smarc return ps2val(); 135054322Smarc default: 135154322Smarc return "<internal prompt error>"; 135254322Smarc } 135354322Smarc } 1354