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*68927Sbostic static char sccsid[] = "@(#)parser.c 8.2 (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; 117*68927Sbostic int tok; 11847139Sbostic 11947981Smarc checkkwd = 2; 12047981Smarc if (nlflag == 0 && tokendlist[peektoken()]) 12147139Sbostic return NULL; 122*68927Sbostic n1 = NULL; 12347139Sbostic for (;;) { 124*68927Sbostic n2 = andor(); 125*68927Sbostic tok = readtoken(); 126*68927Sbostic if (tok == TBACKGND) { 127*68927Sbostic if (n2->type == NCMD || n2->type == NPIPE) { 128*68927Sbostic n2->ncmd.backgnd = 1; 129*68927Sbostic } else if (n2->type == NREDIR) { 130*68927Sbostic n2->type = NBACKGND; 13147139Sbostic } else { 13247139Sbostic n3 = (union node *)stalloc(sizeof (struct nredir)); 13347139Sbostic n3->type = NBACKGND; 134*68927Sbostic n3->nredir.n = n2; 13547139Sbostic n3->nredir.redirect = NULL; 136*68927Sbostic n2 = n3; 13747139Sbostic } 138*68927Sbostic } 139*68927Sbostic if (n1 == NULL) { 140*68927Sbostic n1 = n2; 141*68927Sbostic } 142*68927Sbostic else { 143*68927Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 144*68927Sbostic n3->type = NSEMI; 145*68927Sbostic n3->nbinary.ch1 = n1; 146*68927Sbostic n3->nbinary.ch2 = n2; 147*68927Sbostic n1 = n3; 148*68927Sbostic } 149*68927Sbostic switch (tok) { 150*68927Sbostic case TBACKGND: 151*68927Sbostic case TSEMI: 152*68927Sbostic tok = readtoken(); 153*68927Sbostic /* fall through */ 15447139Sbostic case TNL: 155*68927Sbostic 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. */ 42360296Smarc case TNL: 42447139Sbostic case TWORD: 42547139Sbostic tokpushback++; 42660296Smarc return simplecmd(rpp, redir); 42747139Sbostic default: 42847139Sbostic synexpect(-1); 42947139Sbostic } 43047139Sbostic 43147139Sbostic /* Now check for redirection which may follow command */ 43247139Sbostic while (readtoken() == TREDIR) { 43347139Sbostic *rpp = n2 = redirnode; 43447139Sbostic rpp = &n2->nfile.next; 43547139Sbostic parsefname(); 43647139Sbostic } 43747139Sbostic tokpushback++; 43847139Sbostic *rpp = NULL; 43947139Sbostic if (redir) { 44047139Sbostic if (n1->type != NSUBSHELL) { 44147139Sbostic n2 = (union node *)stalloc(sizeof (struct nredir)); 44247139Sbostic n2->type = NREDIR; 44347139Sbostic n2->nredir.n = n1; 44447139Sbostic n1 = n2; 44547139Sbostic } 44647139Sbostic n1->nredir.redirect = redir; 44747139Sbostic } 44847139Sbostic return n1; 44947139Sbostic } 45047139Sbostic 45147139Sbostic 45247139Sbostic STATIC union node * 45360296Smarc simplecmd(rpp, redir) 45460296Smarc union node **rpp, *redir; 45560296Smarc { 45647139Sbostic union node *args, **app; 45760296Smarc union node **orig_rpp = rpp; 45847139Sbostic union node *n; 45947139Sbostic 46060296Smarc /* If we don't have any redirections already, then we must reset */ 46160296Smarc /* rpp to be the address of the local redir variable. */ 46260296Smarc if (redir == 0) 46360296Smarc rpp = &redir; 46460296Smarc 46547139Sbostic args = NULL; 46647139Sbostic app = &args; 46760296Smarc /* 46860296Smarc * We save the incoming value, because we need this for shell 46960296Smarc * functions. There can not be a redirect or an argument between 47060296Smarc * the function name and the open parenthesis. 47160296Smarc */ 47260296Smarc orig_rpp = rpp; 47360296Smarc 47447139Sbostic for (;;) { 47547139Sbostic if (readtoken() == TWORD) { 47647139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 47747139Sbostic n->type = NARG; 47847139Sbostic n->narg.text = wordtext; 47947139Sbostic n->narg.backquote = backquotelist; 48047139Sbostic *app = n; 48147139Sbostic app = &n->narg.next; 48247139Sbostic } else if (lasttoken == TREDIR) { 48347139Sbostic *rpp = n = redirnode; 48447139Sbostic rpp = &n->nfile.next; 48547139Sbostic parsefname(); /* read name of redirection file */ 48647139Sbostic } else if (lasttoken == TLP && app == &args->narg.next 48760296Smarc && rpp == orig_rpp) { 48847139Sbostic /* We have a function */ 48947139Sbostic if (readtoken() != TRP) 49047139Sbostic synexpect(TRP); 49147300Smarc #ifdef notdef 49247139Sbostic if (! goodname(n->narg.text)) 49347139Sbostic synerror("Bad function name"); 49447300Smarc #endif 49547139Sbostic n->type = NDEFUN; 49647139Sbostic n->narg.next = command(); 49747139Sbostic return n; 49847139Sbostic } else { 49947139Sbostic tokpushback++; 50047139Sbostic break; 50147139Sbostic } 50247139Sbostic } 50347139Sbostic *app = NULL; 50447139Sbostic *rpp = NULL; 50547139Sbostic n = (union node *)stalloc(sizeof (struct ncmd)); 50647139Sbostic n->type = NCMD; 50747139Sbostic n->ncmd.backgnd = 0; 50847139Sbostic n->ncmd.args = args; 50947139Sbostic n->ncmd.redirect = redir; 51047139Sbostic return n; 51147139Sbostic } 51247139Sbostic 51347139Sbostic 51447139Sbostic STATIC void 51547139Sbostic parsefname() { 51647139Sbostic union node *n = redirnode; 51747139Sbostic 51847139Sbostic if (readtoken() != TWORD) 51947139Sbostic synexpect(-1); 52047139Sbostic if (n->type == NHERE) { 52147139Sbostic struct heredoc *here = heredoc; 52247139Sbostic struct heredoc *p; 52347139Sbostic int i; 52447139Sbostic 52547139Sbostic if (quoteflag == 0) 52647139Sbostic n->type = NXHERE; 52747139Sbostic TRACE(("Here document %d\n", n->type)); 52847139Sbostic if (here->striptabs) { 52947139Sbostic while (*wordtext == '\t') 53047139Sbostic wordtext++; 53147139Sbostic } 53247139Sbostic if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 53347139Sbostic synerror("Illegal eof marker for << redirection"); 53447139Sbostic rmescapes(wordtext); 53547139Sbostic here->eofmark = wordtext; 53647139Sbostic here->next = NULL; 53747139Sbostic if (heredoclist == NULL) 53847139Sbostic heredoclist = here; 53947139Sbostic else { 54047139Sbostic for (p = heredoclist ; p->next ; p = p->next); 54147139Sbostic p->next = here; 54247139Sbostic } 54347139Sbostic } else if (n->type == NTOFD || n->type == NFROMFD) { 54447139Sbostic if (is_digit(wordtext[0])) 54547139Sbostic n->ndup.dupfd = digit_val(wordtext[0]); 54647139Sbostic else if (wordtext[0] == '-') 54747139Sbostic n->ndup.dupfd = -1; 54847139Sbostic else 54947139Sbostic goto bad; 55047139Sbostic if (wordtext[1] != '\0') { 55147139Sbostic bad: 55247139Sbostic synerror("Bad fd number"); 55347139Sbostic } 55447139Sbostic } else { 55547139Sbostic n->nfile.fname = (union node *)stalloc(sizeof (struct narg)); 55647139Sbostic n = n->nfile.fname; 55747139Sbostic n->type = NARG; 55847139Sbostic n->narg.next = NULL; 55947139Sbostic n->narg.text = wordtext; 56047139Sbostic n->narg.backquote = backquotelist; 56147139Sbostic } 56247139Sbostic } 56347139Sbostic 56447139Sbostic 56547139Sbostic /* 56647139Sbostic * Input any here documents. 56747139Sbostic */ 56847139Sbostic 56947139Sbostic STATIC void 57047139Sbostic parseheredoc() { 57147139Sbostic struct heredoc *here; 57247139Sbostic union node *n; 57347139Sbostic 57447139Sbostic while (heredoclist) { 57547139Sbostic here = heredoclist; 57647139Sbostic heredoclist = here->next; 57747139Sbostic if (needprompt) { 57854322Smarc setprompt(2); 57947139Sbostic needprompt = 0; 58047139Sbostic } 58147139Sbostic readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 58247139Sbostic here->eofmark, here->striptabs); 58347139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 58447139Sbostic n->narg.type = NARG; 58547139Sbostic n->narg.next = NULL; 58647139Sbostic n->narg.text = wordtext; 58747139Sbostic n->narg.backquote = backquotelist; 58847139Sbostic here->here->nhere.doc = n; 58947139Sbostic } 59047139Sbostic } 59147139Sbostic 59247981Smarc STATIC int 59347981Smarc peektoken() { 59447139Sbostic int t; 59547139Sbostic 59647981Smarc t = readtoken(); 59747139Sbostic tokpushback++; 59847981Smarc return (t); 59947139Sbostic } 60047139Sbostic 60147139Sbostic STATIC int xxreadtoken(); 60247139Sbostic 60347139Sbostic STATIC int 60447139Sbostic readtoken() { 60547139Sbostic int t; 60654322Smarc int savecheckkwd = checkkwd; 60754322Smarc struct alias *ap; 60847981Smarc #ifdef DEBUG 60947981Smarc int alreadyseen = tokpushback; 61047981Smarc #endif 61147981Smarc 61254322Smarc top: 61347981Smarc t = xxreadtoken(); 61447139Sbostic 61547981Smarc if (checkkwd) { 61647981Smarc /* 61747981Smarc * eat newlines 61847981Smarc */ 61947981Smarc if (checkkwd == 2) { 62047981Smarc checkkwd = 0; 62147981Smarc while (t == TNL) { 62247981Smarc parseheredoc(); 62347981Smarc t = xxreadtoken(); 62447981Smarc } 62547981Smarc } else 62647981Smarc checkkwd = 0; 62747981Smarc /* 62854322Smarc * check for keywords and aliases 62947981Smarc */ 63047981Smarc if (t == TWORD && !quoteflag) { 63154322Smarc register char * const *pp, *s; 63247981Smarc 63360296Smarc for (pp = (char **)parsekwd; *pp; pp++) { 63447981Smarc if (**pp == *wordtext && equal(*pp, wordtext)) { 63547981Smarc lasttoken = t = pp - parsekwd + KWDOFFSET; 63647981Smarc TRACE(("keyword %s recognized\n", tokname[t])); 63754322Smarc goto out; 63847981Smarc } 63947981Smarc } 64054322Smarc if (ap = lookupalias(wordtext, 1)) { 64154322Smarc pushstring(ap->val, strlen(ap->val), ap); 64254322Smarc checkkwd = savecheckkwd; 64354322Smarc goto top; 64454322Smarc } 64547981Smarc } 64654322Smarc out: 64754322Smarc checkkwd = 0; 64847139Sbostic } 64947981Smarc #ifdef DEBUG 65047981Smarc if (!alreadyseen) 65147981Smarc TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 65247981Smarc else 65347981Smarc TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 65447981Smarc #endif 65547981Smarc return (t); 65647139Sbostic } 65747139Sbostic 65847139Sbostic 65947139Sbostic /* 66047139Sbostic * Read the next input token. 66147139Sbostic * If the token is a word, we set backquotelist to the list of cmds in 66247139Sbostic * backquotes. We set quoteflag to true if any part of the word was 66347139Sbostic * quoted. 66447139Sbostic * If the token is TREDIR, then we set redirnode to a structure containing 66547139Sbostic * the redirection. 66647139Sbostic * In all cases, the variable startlinno is set to the number of the line 66747139Sbostic * on which the token starts. 66847139Sbostic * 66947139Sbostic * [Change comment: here documents and internal procedures] 67047139Sbostic * [Readtoken shouldn't have any arguments. Perhaps we should make the 67147139Sbostic * word parsing code into a separate routine. In this case, readtoken 67247139Sbostic * doesn't need to have any internal procedures, but parseword does. 67347139Sbostic * We could also make parseoperator in essence the main routine, and 67447139Sbostic * have parseword (readtoken1?) handle both words and redirection.] 67547139Sbostic */ 67647139Sbostic 67747139Sbostic #define RETURN(token) return lasttoken = token 67847139Sbostic 67947139Sbostic STATIC int 68047139Sbostic xxreadtoken() { 68147139Sbostic register c; 68247139Sbostic 68347139Sbostic if (tokpushback) { 68447139Sbostic tokpushback = 0; 68547139Sbostic return lasttoken; 68647139Sbostic } 68747139Sbostic if (needprompt) { 68854322Smarc setprompt(2); 68947139Sbostic needprompt = 0; 69047139Sbostic } 69147139Sbostic startlinno = plinno; 69247139Sbostic for (;;) { /* until token or start of word found */ 69347139Sbostic c = pgetc_macro(); 69447139Sbostic if (c == ' ' || c == '\t') 69547139Sbostic continue; /* quick check for white space first */ 69647139Sbostic switch (c) { 69747139Sbostic case ' ': case '\t': 69847139Sbostic continue; 69947139Sbostic case '#': 70047139Sbostic while ((c = pgetc()) != '\n' && c != PEOF); 70147139Sbostic pungetc(); 70247139Sbostic continue; 70347139Sbostic case '\\': 70447139Sbostic if (pgetc() == '\n') { 70547139Sbostic startlinno = ++plinno; 70647139Sbostic if (doprompt) 70754322Smarc setprompt(2); 70854322Smarc else 70954322Smarc setprompt(0); 71047139Sbostic continue; 71147139Sbostic } 71247139Sbostic pungetc(); 71347139Sbostic goto breakloop; 71447139Sbostic case '\n': 71547139Sbostic plinno++; 71647139Sbostic needprompt = doprompt; 71747139Sbostic RETURN(TNL); 71847139Sbostic case PEOF: 71947139Sbostic RETURN(TEOF); 72047139Sbostic case '&': 72147139Sbostic if (pgetc() == '&') 72247139Sbostic RETURN(TAND); 72347139Sbostic pungetc(); 72447139Sbostic RETURN(TBACKGND); 72547139Sbostic case '|': 72647139Sbostic if (pgetc() == '|') 72747139Sbostic RETURN(TOR); 72847139Sbostic pungetc(); 72947139Sbostic RETURN(TPIPE); 73047139Sbostic case ';': 73147139Sbostic if (pgetc() == ';') 73247139Sbostic RETURN(TENDCASE); 73347139Sbostic pungetc(); 73447139Sbostic RETURN(TSEMI); 73547139Sbostic case '(': 73647139Sbostic RETURN(TLP); 73747139Sbostic case ')': 73847139Sbostic RETURN(TRP); 73947139Sbostic default: 74047139Sbostic goto breakloop; 74147139Sbostic } 74247139Sbostic } 74347139Sbostic breakloop: 74447139Sbostic return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 74547139Sbostic #undef RETURN 74647139Sbostic } 74747139Sbostic 74847139Sbostic 74947139Sbostic 75047139Sbostic /* 75147139Sbostic * If eofmark is NULL, read a word or a redirection symbol. If eofmark 75247139Sbostic * is not NULL, read a here document. In the latter case, eofmark is the 75347139Sbostic * word which marks the end of the document and striptabs is true if 75447139Sbostic * leading tabs should be stripped from the document. The argument firstc 75547139Sbostic * is the first character of the input token or document. 75647139Sbostic * 75747139Sbostic * Because C does not have internal subroutines, I have simulated them 75847139Sbostic * using goto's to implement the subroutine linkage. The following macros 75947139Sbostic * will run code that appears at the end of readtoken1. 76047139Sbostic */ 76147139Sbostic 76247139Sbostic #define CHECKEND() {goto checkend; checkend_return:;} 76347139Sbostic #define PARSEREDIR() {goto parseredir; parseredir_return:;} 76447139Sbostic #define PARSESUB() {goto parsesub; parsesub_return:;} 76547139Sbostic #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 76647139Sbostic #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 76753302Smarc #define PARSEARITH() {goto parsearith; parsearith_return:;} 76847139Sbostic 76947139Sbostic STATIC int 77047139Sbostic readtoken1(firstc, syntax, eofmark, striptabs) 77147139Sbostic int firstc; 77247139Sbostic char const *syntax; 77347139Sbostic char *eofmark; 77447139Sbostic int striptabs; 77547139Sbostic { 77647139Sbostic register c = firstc; 77747139Sbostic register char *out; 77847139Sbostic int len; 77947139Sbostic char line[EOFMARKLEN + 1]; 78047139Sbostic struct nodelist *bqlist; 78147139Sbostic int quotef; 78247139Sbostic int dblquote; 78353302Smarc int varnest; /* levels of variables expansion */ 78453302Smarc int arinest; /* levels of arithmetic expansion */ 78553302Smarc int parenlevel; /* levels of parens in arithmetic */ 78647139Sbostic int oldstyle; 78753302Smarc char const *prevsyntax; /* syntax before arithmetic */ 78847139Sbostic 78947139Sbostic startlinno = plinno; 79047139Sbostic dblquote = 0; 79147139Sbostic if (syntax == DQSYNTAX) 79247139Sbostic dblquote = 1; 79347139Sbostic quotef = 0; 79447139Sbostic bqlist = NULL; 79547139Sbostic varnest = 0; 79653302Smarc arinest = 0; 79753302Smarc parenlevel = 0; 79853302Smarc 79947139Sbostic STARTSTACKSTR(out); 80047139Sbostic loop: { /* for each line, until end of word */ 80147139Sbostic #if ATTY 80247139Sbostic if (c == '\034' && doprompt 80347139Sbostic && attyset() && ! equal(termval(), "emacs")) { 80447139Sbostic attyline(); 80547139Sbostic if (syntax == BASESYNTAX) 80647139Sbostic return readtoken(); 80747139Sbostic c = pgetc(); 80847139Sbostic goto loop; 80947139Sbostic } 81047139Sbostic #endif 81147139Sbostic CHECKEND(); /* set c to PEOF if at end of here document */ 81247139Sbostic for (;;) { /* until end of line or end of word */ 81347139Sbostic CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 81459177Smarc if (parsebackquote && c == '\\') { 81558381Smarc c = pgetc(); /* XXX - compat with old /bin/sh */ 81659177Smarc if (c != '\\' && c != '`' && c != '$') { 81759177Smarc pungetc(); 81859177Smarc c = '\\'; 81959177Smarc } 82059177Smarc } 82147139Sbostic switch(syntax[c]) { 82247139Sbostic case CNL: /* '\n' */ 82347139Sbostic if (syntax == BASESYNTAX) 82447139Sbostic goto endword; /* exit outer loop */ 82547139Sbostic USTPUTC(c, out); 82647139Sbostic plinno++; 82754322Smarc if (doprompt) 82854322Smarc setprompt(2); 82954322Smarc else 83054322Smarc setprompt(0); 83147139Sbostic c = pgetc(); 83247139Sbostic goto loop; /* continue outer loop */ 83347139Sbostic case CWORD: 83447139Sbostic USTPUTC(c, out); 83547139Sbostic break; 83647139Sbostic case CCTL: 83747139Sbostic if (eofmark == NULL || dblquote) 83847139Sbostic USTPUTC(CTLESC, out); 83947139Sbostic USTPUTC(c, out); 84047139Sbostic break; 84147139Sbostic case CBACK: /* backslash */ 84247139Sbostic c = pgetc(); 84347139Sbostic if (c == PEOF) { 84447139Sbostic USTPUTC('\\', out); 84547139Sbostic pungetc(); 84647139Sbostic } else if (c == '\n') { 84747139Sbostic if (doprompt) 84854322Smarc setprompt(2); 84954322Smarc else 85054322Smarc setprompt(0); 85147139Sbostic } else { 85247139Sbostic if (dblquote && c != '\\' && c != '`' && c != '$' 85347139Sbostic && (c != '"' || eofmark != NULL)) 85447139Sbostic USTPUTC('\\', out); 85547139Sbostic if (SQSYNTAX[c] == CCTL) 85647139Sbostic USTPUTC(CTLESC, out); 85747139Sbostic USTPUTC(c, out); 85847139Sbostic quotef++; 85947139Sbostic } 86047139Sbostic break; 86147139Sbostic case CSQUOTE: 86247139Sbostic syntax = SQSYNTAX; 86347139Sbostic break; 86447139Sbostic case CDQUOTE: 86547139Sbostic syntax = DQSYNTAX; 86647139Sbostic dblquote = 1; 86747139Sbostic break; 86847139Sbostic case CENDQUOTE: 86947139Sbostic if (eofmark) { 87047139Sbostic USTPUTC(c, out); 87147139Sbostic } else { 87253302Smarc if (arinest) 87353302Smarc syntax = ARISYNTAX; 87453302Smarc else 87553302Smarc syntax = BASESYNTAX; 87647139Sbostic quotef++; 87747139Sbostic dblquote = 0; 87847139Sbostic } 87947139Sbostic break; 88047139Sbostic case CVAR: /* '$' */ 88147139Sbostic PARSESUB(); /* parse substitution */ 88247139Sbostic break; 88347139Sbostic case CENDVAR: /* '}' */ 88447139Sbostic if (varnest > 0) { 88547139Sbostic varnest--; 88647139Sbostic USTPUTC(CTLENDVAR, out); 88747139Sbostic } else { 88847139Sbostic USTPUTC(c, out); 88947139Sbostic } 89047139Sbostic break; 89153302Smarc case CLP: /* '(' in arithmetic */ 89253302Smarc parenlevel++; 89353302Smarc USTPUTC(c, out); 89453302Smarc break; 89553302Smarc case CRP: /* ')' in arithmetic */ 89653302Smarc if (parenlevel > 0) { 89753302Smarc USTPUTC(c, out); 89853302Smarc --parenlevel; 89953302Smarc } else { 90053302Smarc if (pgetc() == ')') { 90153302Smarc if (--arinest == 0) { 90253302Smarc USTPUTC(CTLENDARI, out); 90353302Smarc syntax = prevsyntax; 90453302Smarc } else 90553302Smarc USTPUTC(')', out); 90653302Smarc } else { 90753302Smarc /* 90853302Smarc * unbalanced parens 90953302Smarc * (don't 2nd guess - no error) 91053302Smarc */ 91153302Smarc pungetc(); 91253302Smarc USTPUTC(')', out); 91353302Smarc } 91453302Smarc } 91553302Smarc break; 91647139Sbostic case CBQUOTE: /* '`' */ 91747139Sbostic PARSEBACKQOLD(); 91847139Sbostic break; 91947139Sbostic case CEOF: 92047139Sbostic goto endword; /* exit outer loop */ 92147139Sbostic default: 92247139Sbostic if (varnest == 0) 92347139Sbostic goto endword; /* exit outer loop */ 92447139Sbostic USTPUTC(c, out); 92547139Sbostic } 92647139Sbostic c = pgetc_macro(); 92747139Sbostic } 92847139Sbostic } 92947139Sbostic endword: 93053302Smarc if (syntax == ARISYNTAX) 93153302Smarc synerror("Missing '))'"); 93260296Smarc if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 93347139Sbostic synerror("Unterminated quoted string"); 93447139Sbostic if (varnest != 0) { 93547139Sbostic startlinno = plinno; 93647139Sbostic synerror("Missing '}'"); 93747139Sbostic } 93847139Sbostic USTPUTC('\0', out); 93947139Sbostic len = out - stackblock(); 94047139Sbostic out = stackblock(); 94147139Sbostic if (eofmark == NULL) { 94247139Sbostic if ((c == '>' || c == '<') 94347139Sbostic && quotef == 0 94447139Sbostic && len <= 2 94547139Sbostic && (*out == '\0' || is_digit(*out))) { 94647139Sbostic PARSEREDIR(); 94747139Sbostic return lasttoken = TREDIR; 94847139Sbostic } else { 94947139Sbostic pungetc(); 95047139Sbostic } 95147139Sbostic } 95247139Sbostic quoteflag = quotef; 95347139Sbostic backquotelist = bqlist; 95447139Sbostic grabstackblock(len); 95547139Sbostic wordtext = out; 95647139Sbostic return lasttoken = TWORD; 95747139Sbostic /* end of readtoken routine */ 95847139Sbostic 95947139Sbostic 96047139Sbostic 96147139Sbostic /* 96247139Sbostic * Check to see whether we are at the end of the here document. When this 96347139Sbostic * is called, c is set to the first character of the next input line. If 96447139Sbostic * we are at the end of the here document, this routine sets the c to PEOF. 96547139Sbostic */ 96647139Sbostic 96747139Sbostic checkend: { 96847139Sbostic if (eofmark) { 96947139Sbostic if (striptabs) { 97047139Sbostic while (c == '\t') 97147139Sbostic c = pgetc(); 97247139Sbostic } 97347139Sbostic if (c == *eofmark) { 97447139Sbostic if (pfgets(line, sizeof line) != NULL) { 97547139Sbostic register char *p, *q; 97647139Sbostic 97747139Sbostic p = line; 97847139Sbostic for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 97947139Sbostic if (*p == '\n' && *q == '\0') { 98047139Sbostic c = PEOF; 98147139Sbostic plinno++; 98247139Sbostic needprompt = doprompt; 98347139Sbostic } else { 98454322Smarc pushstring(line, strlen(line), NULL); 98547139Sbostic } 98647139Sbostic } 98747139Sbostic } 98847139Sbostic } 98947139Sbostic goto checkend_return; 99047139Sbostic } 99147139Sbostic 99247139Sbostic 99347139Sbostic /* 99447139Sbostic * Parse a redirection operator. The variable "out" points to a string 99547139Sbostic * specifying the fd to be redirected. The variable "c" contains the 99647139Sbostic * first character of the redirection operator. 99747139Sbostic */ 99847139Sbostic 99947139Sbostic parseredir: { 100047139Sbostic char fd = *out; 100147139Sbostic union node *np; 100247139Sbostic 100347139Sbostic np = (union node *)stalloc(sizeof (struct nfile)); 100447139Sbostic if (c == '>') { 100547139Sbostic np->nfile.fd = 1; 100647139Sbostic c = pgetc(); 100747139Sbostic if (c == '>') 100847139Sbostic np->type = NAPPEND; 100947139Sbostic else if (c == '&') 101047139Sbostic np->type = NTOFD; 101147139Sbostic else { 101247139Sbostic np->type = NTO; 101347139Sbostic pungetc(); 101447139Sbostic } 101547139Sbostic } else { /* c == '<' */ 101647139Sbostic np->nfile.fd = 0; 101747139Sbostic c = pgetc(); 101847139Sbostic if (c == '<') { 101947139Sbostic if (sizeof (struct nfile) != sizeof (struct nhere)) { 102047139Sbostic np = (union node *)stalloc(sizeof (struct nhere)); 102147139Sbostic np->nfile.fd = 0; 102247139Sbostic } 102347139Sbostic np->type = NHERE; 102447139Sbostic heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 102547139Sbostic heredoc->here = np; 102647139Sbostic if ((c = pgetc()) == '-') { 102747139Sbostic heredoc->striptabs = 1; 102847139Sbostic } else { 102947139Sbostic heredoc->striptabs = 0; 103047139Sbostic pungetc(); 103147139Sbostic } 103247139Sbostic } else if (c == '&') 103347139Sbostic np->type = NFROMFD; 103447139Sbostic else { 103547139Sbostic np->type = NFROM; 103647139Sbostic pungetc(); 103747139Sbostic } 103847139Sbostic } 103947139Sbostic if (fd != '\0') 104047139Sbostic np->nfile.fd = digit_val(fd); 104147139Sbostic redirnode = np; 104247139Sbostic goto parseredir_return; 104347139Sbostic } 104447139Sbostic 104547139Sbostic 104647139Sbostic /* 104747139Sbostic * Parse a substitution. At this point, we have read the dollar sign 104847139Sbostic * and nothing else. 104947139Sbostic */ 105047139Sbostic 105147139Sbostic parsesub: { 105247139Sbostic int subtype; 105347139Sbostic int typeloc; 105447139Sbostic int flags; 105547139Sbostic char *p; 105647139Sbostic #ifndef GDB_HACK 105747139Sbostic static const char types[] = "}-+?="; 105847139Sbostic #endif 105947139Sbostic 106047139Sbostic c = pgetc(); 106147300Smarc if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 106247139Sbostic USTPUTC('$', out); 106347139Sbostic pungetc(); 106453302Smarc } else if (c == '(') { /* $(command) or $((arith)) */ 106553302Smarc if (pgetc() == '(') { 106653302Smarc PARSEARITH(); 106753302Smarc } else { 106853302Smarc pungetc(); 106953302Smarc PARSEBACKQNEW(); 107053302Smarc } 107147139Sbostic } else { 107247139Sbostic USTPUTC(CTLVAR, out); 107347139Sbostic typeloc = out - stackblock(); 107447139Sbostic USTPUTC(VSNORMAL, out); 107547139Sbostic subtype = VSNORMAL; 107647139Sbostic if (c == '{') { 107747139Sbostic c = pgetc(); 107847139Sbostic subtype = 0; 107947139Sbostic } 108047139Sbostic if (is_name(c)) { 108147139Sbostic do { 108247139Sbostic STPUTC(c, out); 108347139Sbostic c = pgetc(); 108447139Sbostic } while (is_in_name(c)); 108547139Sbostic } else { 108647139Sbostic if (! is_special(c)) 108747300Smarc badsub: synerror("Bad substitution"); 108847139Sbostic USTPUTC(c, out); 108947139Sbostic c = pgetc(); 109047139Sbostic } 109147139Sbostic STPUTC('=', out); 109247139Sbostic flags = 0; 109347139Sbostic if (subtype == 0) { 109447139Sbostic if (c == ':') { 109547139Sbostic flags = VSNUL; 109647139Sbostic c = pgetc(); 109747139Sbostic } 109847139Sbostic p = strchr(types, c); 109947139Sbostic if (p == NULL) 110047139Sbostic goto badsub; 110147139Sbostic subtype = p - types + VSNORMAL; 110247139Sbostic } else { 110347139Sbostic pungetc(); 110447139Sbostic } 110553302Smarc if (dblquote || arinest) 110647139Sbostic flags |= VSQUOTE; 110747139Sbostic *(stackblock() + typeloc) = subtype | flags; 110847139Sbostic if (subtype != VSNORMAL) 110947139Sbostic varnest++; 111047139Sbostic } 111147139Sbostic goto parsesub_return; 111247139Sbostic } 111347139Sbostic 111447139Sbostic 111547139Sbostic /* 111647139Sbostic * Called to parse command substitutions. Newstyle is set if the command 111747139Sbostic * is enclosed inside $(...); nlpp is a pointer to the head of the linked 111847139Sbostic * list of commands (passed by reference), and savelen is the number of 111947139Sbostic * characters on the top of the stack which must be preserved. 112047139Sbostic */ 112147139Sbostic 112247139Sbostic parsebackq: { 112347139Sbostic struct nodelist **nlpp; 112447139Sbostic int savepbq; 112547139Sbostic union node *n; 112647139Sbostic char *volatile str; 112747139Sbostic struct jmploc jmploc; 112847139Sbostic struct jmploc *volatile savehandler; 112947139Sbostic int savelen; 113047139Sbostic 113147139Sbostic savepbq = parsebackquote; 113247139Sbostic if (setjmp(jmploc.loc)) { 113347139Sbostic if (str) 113447139Sbostic ckfree(str); 113547139Sbostic parsebackquote = 0; 113647139Sbostic handler = savehandler; 113754322Smarc longjmp(handler->loc, 1); 113847139Sbostic } 113947139Sbostic INTOFF; 114047139Sbostic str = NULL; 114147139Sbostic savelen = out - stackblock(); 114247139Sbostic if (savelen > 0) { 114347139Sbostic str = ckmalloc(savelen); 114447139Sbostic bcopy(stackblock(), str, savelen); 114547139Sbostic } 114647139Sbostic savehandler = handler; 114747139Sbostic handler = &jmploc; 114847139Sbostic INTON; 114960296Smarc if (oldstyle) { 115060296Smarc /* We must read until the closing backquote, giving special 115160296Smarc treatment to some slashes, and then push the string and 115260296Smarc reread it as input, interpreting it normally. */ 115360296Smarc register char *out; 115460296Smarc register c; 115560296Smarc int savelen; 115660296Smarc char *str; 115760296Smarc 115860296Smarc STARTSTACKSTR(out); 115960296Smarc while ((c = pgetc ()) != '`') { 116060296Smarc if (c == '\\') { 116160296Smarc c = pgetc (); 116260296Smarc if (c != '\\' && c != '`' && c != '$' 116360296Smarc && (!dblquote || c != '"')) 116460296Smarc STPUTC('\\', out); 116560296Smarc } 116660296Smarc STPUTC(c, out); 116760296Smarc } 116860296Smarc STPUTC('\0', out); 116960296Smarc savelen = out - stackblock(); 117060296Smarc if (savelen > 0) { 117160296Smarc str = ckmalloc(savelen); 117260296Smarc bcopy(stackblock(), str, savelen); 117360296Smarc } 117460296Smarc setinputstring(str, 1); 117560296Smarc } 117647139Sbostic nlpp = &bqlist; 117747139Sbostic while (*nlpp) 117847139Sbostic nlpp = &(*nlpp)->next; 117947139Sbostic *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 118047139Sbostic (*nlpp)->next = NULL; 118147139Sbostic parsebackquote = oldstyle; 118247139Sbostic n = list(0); 118360296Smarc if (!oldstyle && (readtoken() != TRP)) 118460296Smarc synexpect(TRP); 118547139Sbostic (*nlpp)->n = n; 118660296Smarc /* Start reading from old file again. */ 118760296Smarc if (oldstyle) 118860296Smarc popfile(); 118947139Sbostic while (stackblocksize() <= savelen) 119047139Sbostic growstackblock(); 119147139Sbostic STARTSTACKSTR(out); 119247139Sbostic if (str) { 119347139Sbostic bcopy(str, out, savelen); 119447139Sbostic STADJUST(savelen, out); 119547139Sbostic INTOFF; 119647139Sbostic ckfree(str); 119747139Sbostic str = NULL; 119847139Sbostic INTON; 119947139Sbostic } 120047139Sbostic parsebackquote = savepbq; 120147139Sbostic handler = savehandler; 120253302Smarc if (arinest || dblquote) 120353302Smarc USTPUTC(CTLBACKQ | CTLQUOTE, out); 120453302Smarc else 120553302Smarc USTPUTC(CTLBACKQ, out); 120647139Sbostic if (oldstyle) 120747139Sbostic goto parsebackq_oldreturn; 120847139Sbostic else 120947139Sbostic goto parsebackq_newreturn; 121047139Sbostic } 121147139Sbostic 121253302Smarc /* 121353302Smarc * Parse an arithmetic expansion (indicate start of one and set state) 121453302Smarc */ 121553302Smarc parsearith: { 121653302Smarc 121753302Smarc if (++arinest == 1) { 121853302Smarc prevsyntax = syntax; 121953302Smarc syntax = ARISYNTAX; 122053302Smarc USTPUTC(CTLARI, out); 122153302Smarc } else { 122253302Smarc /* 122353302Smarc * we collapse embedded arithmetic expansion to 122453302Smarc * parenthesis, which should be equivalent 122553302Smarc */ 122653302Smarc USTPUTC('(', out); 122753302Smarc } 122853302Smarc goto parsearith_return; 122953302Smarc } 123053302Smarc 123147139Sbostic } /* end of readtoken */ 123247139Sbostic 123347139Sbostic 123447139Sbostic 123547139Sbostic #ifdef mkinit 123647139Sbostic RESET { 123747139Sbostic tokpushback = 0; 123854322Smarc checkkwd = 0; 123947139Sbostic } 124047139Sbostic #endif 124147139Sbostic 124247139Sbostic /* 124347139Sbostic * Returns true if the text contains nothing to expand (no dollar signs 124447139Sbostic * or backquotes). 124547139Sbostic */ 124647139Sbostic 124747139Sbostic STATIC int 124847139Sbostic noexpand(text) 124947139Sbostic char *text; 125047139Sbostic { 125147139Sbostic register char *p; 125247139Sbostic register char c; 125347139Sbostic 125447139Sbostic p = text; 125547139Sbostic while ((c = *p++) != '\0') { 125647139Sbostic if (c == CTLESC) 125747139Sbostic p++; 125847139Sbostic else if (BASESYNTAX[c] == CCTL) 125947139Sbostic return 0; 126047139Sbostic } 126147139Sbostic return 1; 126247139Sbostic } 126347139Sbostic 126447139Sbostic 126547139Sbostic /* 126647139Sbostic * Return true if the argument is a legal variable name (a letter or 126747139Sbostic * underscore followed by zero or more letters, underscores, and digits). 126847139Sbostic */ 126947139Sbostic 127047139Sbostic int 127147139Sbostic goodname(name) 127247139Sbostic char *name; 127347139Sbostic { 127447139Sbostic register char *p; 127547139Sbostic 127647139Sbostic p = name; 127747139Sbostic if (! is_name(*p)) 127847139Sbostic return 0; 127947139Sbostic while (*++p) { 128047139Sbostic if (! is_in_name(*p)) 128147139Sbostic return 0; 128247139Sbostic } 128347139Sbostic return 1; 128447139Sbostic } 128547139Sbostic 128647139Sbostic 128747139Sbostic /* 128847139Sbostic * Called when an unexpected token is read during the parse. The argument 128947139Sbostic * is the token that is expected, or -1 if more than one type of token can 129047139Sbostic * occur at this point. 129147139Sbostic */ 129247139Sbostic 129347139Sbostic STATIC void 129447139Sbostic synexpect(token) { 129547139Sbostic char msg[64]; 129647139Sbostic 129747139Sbostic if (token >= 0) { 129847139Sbostic fmtstr(msg, 64, "%s unexpected (expecting %s)", 129947139Sbostic tokname[lasttoken], tokname[token]); 130047139Sbostic } else { 130147139Sbostic fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 130247139Sbostic } 130347139Sbostic synerror(msg); 130447139Sbostic } 130547139Sbostic 130647139Sbostic 130747139Sbostic STATIC void 130847139Sbostic synerror(msg) 130947139Sbostic char *msg; 131047139Sbostic { 131147139Sbostic if (commandname) 131247139Sbostic outfmt(&errout, "%s: %d: ", commandname, startlinno); 131347139Sbostic outfmt(&errout, "Syntax error: %s\n", msg); 131447139Sbostic error((char *)NULL); 131547139Sbostic } 131654322Smarc 131754322Smarc STATIC void 131854322Smarc setprompt(which) 131954322Smarc int which; 132054322Smarc { 132154322Smarc whichprompt = which; 132254322Smarc 132354322Smarc if (!el) 132454322Smarc out2str(getprompt(NULL)); 132554322Smarc } 132654322Smarc 132754322Smarc /* 132854322Smarc * called by editline -- any expansions to the prompt 132954322Smarc * should be added here. 133054322Smarc */ 133154322Smarc char * 133254322Smarc getprompt(unused) 133354322Smarc void *unused; 133454322Smarc { 133554322Smarc switch (whichprompt) { 133654322Smarc case 0: 133754322Smarc return ""; 133854322Smarc case 1: 133954322Smarc return ps1val(); 134054322Smarc case 2: 134154322Smarc return ps2val(); 134254322Smarc default: 134354322Smarc return "<internal prompt error>"; 134454322Smarc } 134554322Smarc } 1346