147139Sbostic /*- 247139Sbostic * Copyright (c) 1991 The Regents of the University of California. 347139Sbostic * 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*47981Smarc static char sccsid[] = "@(#)parser.c 5.3 (Berkeley) 04/12/91"; 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" 2847139Sbostic 2947139Sbostic 3047139Sbostic /* 3147139Sbostic * Shell command parser. 3247139Sbostic */ 3347139Sbostic 3447139Sbostic #define EOFMARKLEN 79 3547139Sbostic 3647139Sbostic /* values returned by readtoken */ 3747139Sbostic #include "token.def" 3847139Sbostic 3947139Sbostic 4047139Sbostic 4147139Sbostic struct heredoc { 4247139Sbostic struct heredoc *next; /* next here document in list */ 4347139Sbostic union node *here; /* redirection node */ 4447139Sbostic char *eofmark; /* string indicating end of input */ 4547139Sbostic int striptabs; /* if set, strip leading tabs */ 4647139Sbostic }; 4747139Sbostic 4847139Sbostic 4947139Sbostic 5047139Sbostic struct heredoc *heredoclist; /* list of here documents to read */ 5147139Sbostic int parsebackquote; /* nonzero if we are inside backquotes */ 5247139Sbostic int doprompt; /* if set, prompt the user */ 5347139Sbostic int needprompt; /* true if interactive and at start of line */ 5447139Sbostic int lasttoken; /* last token read */ 5547139Sbostic MKINIT int tokpushback; /* last token pushed back */ 5647139Sbostic char *wordtext; /* text of last word returned by readtoken */ 57*47981Smarc int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 5847139Sbostic struct nodelist *backquotelist; 5947139Sbostic union node *redirnode; 6047139Sbostic struct heredoc *heredoc; 6147139Sbostic int quoteflag; /* set if (part of) last token was quoted */ 6247139Sbostic int startlinno; /* line # where last token started */ 6347139Sbostic 6447139Sbostic 6547139Sbostic #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ 6647139Sbostic #ifdef GDB_HACK 6747139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; 6847139Sbostic static const char types[] = "}-+?="; 6947139Sbostic #endif 7047139Sbostic 7147139Sbostic 72*47981Smarc STATIC union node *list __P((int)); 73*47981Smarc STATIC union node *andor __P((void)); 74*47981Smarc STATIC union node *pipeline __P((void)); 75*47981Smarc STATIC union node *command __P((void)); 76*47981Smarc STATIC union node *simplecmd __P((void)); 77*47981Smarc STATIC void parsefname __P((void)); 78*47981Smarc STATIC void parseheredoc __P((void)); 79*47981Smarc STATIC int readtoken __P((void)); 80*47981Smarc STATIC int readtoken1 __P((int, char const *, char *, int)); 81*47981Smarc STATIC void attyline __P((void)); 82*47981Smarc STATIC int noexpand __P((char *)); 83*47981Smarc STATIC void synexpect __P((int)); 84*47981Smarc STATIC void synerror __P((char *)); 8547139Sbostic 8647139Sbostic #if ATTY 87*47981Smarc STATIC void putprompt __P((char *)); 8847139Sbostic #else /* not ATTY */ 8947139Sbostic #define putprompt(s) out2str(s) 9047139Sbostic #endif 9147139Sbostic 9247139Sbostic 9347139Sbostic 9447139Sbostic 9547139Sbostic /* 9647139Sbostic * Read and parse a command. Returns NEOF on end of file. (NULL is a 9747139Sbostic * valid parse tree indicating a blank line.) 9847139Sbostic */ 9947139Sbostic 10047139Sbostic union node * 10147139Sbostic parsecmd(interact) { 10247139Sbostic int t; 10347139Sbostic 10447139Sbostic doprompt = interact; 10547139Sbostic if (doprompt) 10647139Sbostic putprompt(ps1val()); 10747139Sbostic needprompt = 0; 10847139Sbostic if ((t = readtoken()) == TEOF) 10947139Sbostic return NEOF; 11047139Sbostic if (t == TNL) 11147139Sbostic return NULL; 11247139Sbostic tokpushback++; 11347139Sbostic return list(1); 11447139Sbostic } 11547139Sbostic 11647139Sbostic 11747139Sbostic STATIC union node * 11847139Sbostic list(nlflag) { 11947139Sbostic union node *n1, *n2, *n3; 12047139Sbostic 121*47981Smarc checkkwd = 2; 122*47981Smarc if (nlflag == 0 && tokendlist[peektoken()]) 12347139Sbostic return NULL; 12447139Sbostic n1 = andor(); 12547139Sbostic for (;;) { 12647139Sbostic switch (readtoken()) { 12747139Sbostic case TBACKGND: 12847139Sbostic if (n1->type == NCMD || n1->type == NPIPE) { 12947139Sbostic n1->ncmd.backgnd = 1; 13047139Sbostic } else if (n1->type == NREDIR) { 13147139Sbostic n1->type = NBACKGND; 13247139Sbostic } else { 13347139Sbostic n3 = (union node *)stalloc(sizeof (struct nredir)); 13447139Sbostic n3->type = NBACKGND; 13547139Sbostic n3->nredir.n = n1; 13647139Sbostic n3->nredir.redirect = NULL; 13747139Sbostic n1 = n3; 13847139Sbostic } 13947139Sbostic goto tsemi; 14047139Sbostic case TNL: 14147139Sbostic tokpushback++; 14247139Sbostic /* fall through */ 14347139Sbostic tsemi: case TSEMI: 14447139Sbostic if (readtoken() == TNL) { 14547139Sbostic parseheredoc(); 14647139Sbostic if (nlflag) 14747139Sbostic return n1; 14847139Sbostic } else { 14947139Sbostic tokpushback++; 15047139Sbostic } 151*47981Smarc checkkwd = 2; 152*47981Smarc if (tokendlist[peektoken()]) 15347139Sbostic return n1; 15447139Sbostic n2 = andor(); 15547139Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 15647139Sbostic n3->type = NSEMI; 15747139Sbostic n3->nbinary.ch1 = n1; 15847139Sbostic n3->nbinary.ch2 = n2; 15947139Sbostic n1 = n3; 16047139Sbostic break; 16147139Sbostic case TEOF: 16247139Sbostic if (heredoclist) 16347139Sbostic parseheredoc(); 16447139Sbostic else 16547139Sbostic pungetc(); /* push back EOF on input */ 16647139Sbostic return n1; 16747139Sbostic default: 16847139Sbostic if (nlflag) 16947139Sbostic synexpect(-1); 17047139Sbostic tokpushback++; 17147139Sbostic return n1; 17247139Sbostic } 17347139Sbostic } 17447139Sbostic } 17547139Sbostic 17647139Sbostic 17747139Sbostic 17847139Sbostic STATIC union node * 17947139Sbostic andor() { 18047139Sbostic union node *n1, *n2, *n3; 18147139Sbostic int t; 18247139Sbostic 18347139Sbostic n1 = pipeline(); 18447139Sbostic for (;;) { 18547139Sbostic if ((t = readtoken()) == TAND) { 18647139Sbostic t = NAND; 18747139Sbostic } else if (t == TOR) { 18847139Sbostic t = NOR; 18947139Sbostic } else { 19047139Sbostic tokpushback++; 19147139Sbostic return n1; 19247139Sbostic } 19347139Sbostic n2 = pipeline(); 19447139Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 19547139Sbostic n3->type = t; 19647139Sbostic n3->nbinary.ch1 = n1; 19747139Sbostic n3->nbinary.ch2 = n2; 19847139Sbostic n1 = n3; 19947139Sbostic } 20047139Sbostic } 20147139Sbostic 20247139Sbostic 20347139Sbostic 20447139Sbostic STATIC union node * 20547139Sbostic pipeline() { 20647139Sbostic union node *n1, *pipenode; 20747139Sbostic struct nodelist *lp, *prev; 20847139Sbostic 20947139Sbostic n1 = command(); 21047139Sbostic if (readtoken() == TPIPE) { 21147139Sbostic pipenode = (union node *)stalloc(sizeof (struct npipe)); 21247139Sbostic pipenode->type = NPIPE; 21347139Sbostic pipenode->npipe.backgnd = 0; 21447139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 21547139Sbostic pipenode->npipe.cmdlist = lp; 21647139Sbostic lp->n = n1; 21747139Sbostic do { 21847139Sbostic prev = lp; 21947139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 22047139Sbostic lp->n = command(); 22147139Sbostic prev->next = lp; 22247139Sbostic } while (readtoken() == TPIPE); 22347139Sbostic lp->next = NULL; 22447139Sbostic n1 = pipenode; 22547139Sbostic } 22647139Sbostic tokpushback++; 22747139Sbostic return n1; 22847139Sbostic } 22947139Sbostic 23047139Sbostic 23147139Sbostic 23247139Sbostic STATIC union node * 23347139Sbostic command() { 23447139Sbostic union node *n1, *n2; 23547139Sbostic union node *ap, **app; 23647139Sbostic union node *cp, **cpp; 23747139Sbostic union node *redir, **rpp; 23847139Sbostic int t; 23947139Sbostic 240*47981Smarc checkkwd = 2; 24147139Sbostic switch (readtoken()) { 24247139Sbostic case TIF: 24347139Sbostic n1 = (union node *)stalloc(sizeof (struct nif)); 24447139Sbostic n1->type = NIF; 24547139Sbostic n1->nif.test = list(0); 24647139Sbostic if (readtoken() != TTHEN) 24747139Sbostic synexpect(TTHEN); 24847139Sbostic n1->nif.ifpart = list(0); 24947139Sbostic n2 = n1; 25047139Sbostic while (readtoken() == TELIF) { 25147139Sbostic n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 25247139Sbostic n2 = n2->nif.elsepart; 25347139Sbostic n2->type = NIF; 25447139Sbostic n2->nif.test = list(0); 25547139Sbostic if (readtoken() != TTHEN) 25647139Sbostic synexpect(TTHEN); 25747139Sbostic n2->nif.ifpart = list(0); 25847139Sbostic } 25947139Sbostic if (lasttoken == TELSE) 26047139Sbostic n2->nif.elsepart = list(0); 26147139Sbostic else { 26247139Sbostic n2->nif.elsepart = NULL; 26347139Sbostic tokpushback++; 26447139Sbostic } 26547139Sbostic if (readtoken() != TFI) 26647139Sbostic synexpect(TFI); 267*47981Smarc checkkwd = 1; 26847139Sbostic break; 26947139Sbostic case TWHILE: 270*47981Smarc case TUNTIL: { 271*47981Smarc int got; 27247139Sbostic n1 = (union node *)stalloc(sizeof (struct nbinary)); 27347139Sbostic n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 27447139Sbostic n1->nbinary.ch1 = list(0); 275*47981Smarc if ((got=readtoken()) != TDO) { 276*47981Smarc TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 27747139Sbostic synexpect(TDO); 278*47981Smarc } 27947139Sbostic n1->nbinary.ch2 = list(0); 28047139Sbostic if (readtoken() != TDONE) 28147139Sbostic synexpect(TDONE); 282*47981Smarc checkkwd = 1; 28347139Sbostic break; 284*47981Smarc } 28547139Sbostic case TFOR: 28647139Sbostic if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 28747139Sbostic synerror("Bad for loop variable"); 28847139Sbostic n1 = (union node *)stalloc(sizeof (struct nfor)); 28947139Sbostic n1->type = NFOR; 29047139Sbostic n1->nfor.var = wordtext; 29147139Sbostic if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 29247139Sbostic app = ≈ 29347139Sbostic while (readtoken() == TWORD) { 29447139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 29547139Sbostic n2->type = NARG; 29647139Sbostic n2->narg.text = wordtext; 29747139Sbostic n2->narg.backquote = backquotelist; 29847139Sbostic *app = n2; 29947139Sbostic app = &n2->narg.next; 30047139Sbostic } 30147139Sbostic *app = NULL; 30247139Sbostic n1->nfor.args = ap; 30347139Sbostic } else { 30447139Sbostic #ifndef GDB_HACK 30547139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 30647139Sbostic '@', '=', '\0'}; 30747139Sbostic #endif 30847139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 30947139Sbostic n2->type = NARG; 31047139Sbostic n2->narg.text = (char *)argvars; 31147139Sbostic n2->narg.backquote = NULL; 31247139Sbostic n2->narg.next = NULL; 31347139Sbostic n1->nfor.args = n2; 31447139Sbostic } 31547139Sbostic if (lasttoken != TNL && lasttoken != TSEMI) 31647139Sbostic synexpect(-1); 317*47981Smarc checkkwd = 2; 31847139Sbostic if ((t = readtoken()) == TDO) 31947139Sbostic t = TDONE; 32047139Sbostic else if (t == TBEGIN) 32147139Sbostic t = TEND; 32247139Sbostic else 32347139Sbostic synexpect(-1); 32447139Sbostic n1->nfor.body = list(0); 32547139Sbostic if (readtoken() != t) 32647139Sbostic synexpect(t); 327*47981Smarc checkkwd = 1; 32847139Sbostic break; 32947139Sbostic case TCASE: 33047139Sbostic n1 = (union node *)stalloc(sizeof (struct ncase)); 33147139Sbostic n1->type = NCASE; 33247139Sbostic if (readtoken() != TWORD) 33347139Sbostic synexpect(TWORD); 33447139Sbostic n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 33547139Sbostic n2->type = NARG; 33647139Sbostic n2->narg.text = wordtext; 33747139Sbostic n2->narg.backquote = backquotelist; 33847139Sbostic n2->narg.next = NULL; 33947139Sbostic while (readtoken() == TNL); 34047139Sbostic if (lasttoken != TWORD || ! equal(wordtext, "in")) 34147139Sbostic synerror("expecting \"in\""); 34247139Sbostic cpp = &n1->ncase.cases; 343*47981Smarc while (checkkwd = 2, readtoken() == TWORD) { 34447139Sbostic *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 34547139Sbostic cp->type = NCLIST; 34647139Sbostic app = &cp->nclist.pattern; 34747139Sbostic for (;;) { 34847139Sbostic *app = ap = (union node *)stalloc(sizeof (struct narg)); 34947139Sbostic ap->type = NARG; 35047139Sbostic ap->narg.text = wordtext; 35147139Sbostic ap->narg.backquote = backquotelist; 35247139Sbostic if (readtoken() != TPIPE) 35347139Sbostic break; 35447139Sbostic app = &ap->narg.next; 35547139Sbostic if (readtoken() != TWORD) 35647139Sbostic synexpect(TWORD); 35747139Sbostic } 35847139Sbostic ap->narg.next = NULL; 35947139Sbostic if (lasttoken != TRP) 36047139Sbostic synexpect(TRP); 36147139Sbostic cp->nclist.body = list(0); 36247139Sbostic if ((t = readtoken()) == TESAC) 36347139Sbostic tokpushback++; 36447139Sbostic else if (t != TENDCASE) 36547139Sbostic synexpect(TENDCASE); 36647139Sbostic cpp = &cp->nclist.next; 36747139Sbostic } 36847139Sbostic *cpp = NULL; 36947139Sbostic if (lasttoken != TESAC) 37047139Sbostic synexpect(TESAC); 371*47981Smarc checkkwd = 1; 37247139Sbostic break; 37347139Sbostic case TLP: 37447139Sbostic n1 = (union node *)stalloc(sizeof (struct nredir)); 37547139Sbostic n1->type = NSUBSHELL; 37647139Sbostic n1->nredir.n = list(0); 37747139Sbostic n1->nredir.redirect = NULL; 37847139Sbostic if (readtoken() != TRP) 37947139Sbostic synexpect(TRP); 380*47981Smarc checkkwd = 1; 38147139Sbostic break; 38247139Sbostic case TBEGIN: 38347139Sbostic n1 = list(0); 38447139Sbostic if (readtoken() != TEND) 38547139Sbostic synexpect(TEND); 386*47981Smarc checkkwd = 1; 38747139Sbostic break; 38847139Sbostic case TWORD: 38947139Sbostic case TREDIR: 39047139Sbostic tokpushback++; 39147139Sbostic return simplecmd(); 39247139Sbostic default: 39347139Sbostic synexpect(-1); 39447139Sbostic } 39547139Sbostic 39647139Sbostic /* Now check for redirection which may follow command */ 39747139Sbostic rpp = &redir; 39847139Sbostic while (readtoken() == TREDIR) { 39947139Sbostic *rpp = n2 = redirnode; 40047139Sbostic rpp = &n2->nfile.next; 40147139Sbostic parsefname(); 40247139Sbostic } 40347139Sbostic tokpushback++; 40447139Sbostic *rpp = NULL; 40547139Sbostic if (redir) { 40647139Sbostic if (n1->type != NSUBSHELL) { 40747139Sbostic n2 = (union node *)stalloc(sizeof (struct nredir)); 40847139Sbostic n2->type = NREDIR; 40947139Sbostic n2->nredir.n = n1; 41047139Sbostic n1 = n2; 41147139Sbostic } 41247139Sbostic n1->nredir.redirect = redir; 41347139Sbostic } 41447139Sbostic return n1; 41547139Sbostic } 41647139Sbostic 41747139Sbostic 41847139Sbostic STATIC union node * 41947139Sbostic simplecmd() { 42047139Sbostic union node *args, **app; 42147139Sbostic union node *redir, **rpp; 42247139Sbostic union node *n; 42347139Sbostic 42447139Sbostic args = NULL; 42547139Sbostic app = &args; 42647139Sbostic rpp = &redir; 42747139Sbostic for (;;) { 42847139Sbostic if (readtoken() == TWORD) { 42947139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 43047139Sbostic n->type = NARG; 43147139Sbostic n->narg.text = wordtext; 43247139Sbostic n->narg.backquote = backquotelist; 43347139Sbostic *app = n; 43447139Sbostic app = &n->narg.next; 43547139Sbostic } else if (lasttoken == TREDIR) { 43647139Sbostic *rpp = n = redirnode; 43747139Sbostic rpp = &n->nfile.next; 43847139Sbostic parsefname(); /* read name of redirection file */ 43947139Sbostic } else if (lasttoken == TLP && app == &args->narg.next 44047139Sbostic && rpp == &redir) { 44147139Sbostic /* We have a function */ 44247139Sbostic if (readtoken() != TRP) 44347139Sbostic synexpect(TRP); 44447300Smarc #ifdef notdef 44547139Sbostic if (! goodname(n->narg.text)) 44647139Sbostic synerror("Bad function name"); 44747300Smarc #endif 44847139Sbostic n->type = NDEFUN; 44947139Sbostic n->narg.next = command(); 45047139Sbostic return n; 45147139Sbostic } else { 45247139Sbostic tokpushback++; 45347139Sbostic break; 45447139Sbostic } 45547139Sbostic } 45647139Sbostic *app = NULL; 45747139Sbostic *rpp = NULL; 45847139Sbostic n = (union node *)stalloc(sizeof (struct ncmd)); 45947139Sbostic n->type = NCMD; 46047139Sbostic n->ncmd.backgnd = 0; 46147139Sbostic n->ncmd.args = args; 46247139Sbostic n->ncmd.redirect = redir; 46347139Sbostic return n; 46447139Sbostic } 46547139Sbostic 46647139Sbostic 46747139Sbostic STATIC void 46847139Sbostic parsefname() { 46947139Sbostic union node *n = redirnode; 47047139Sbostic 47147139Sbostic if (readtoken() != TWORD) 47247139Sbostic synexpect(-1); 47347139Sbostic if (n->type == NHERE) { 47447139Sbostic struct heredoc *here = heredoc; 47547139Sbostic struct heredoc *p; 47647139Sbostic int i; 47747139Sbostic 47847139Sbostic if (quoteflag == 0) 47947139Sbostic n->type = NXHERE; 48047139Sbostic TRACE(("Here document %d\n", n->type)); 48147139Sbostic if (here->striptabs) { 48247139Sbostic while (*wordtext == '\t') 48347139Sbostic wordtext++; 48447139Sbostic } 48547139Sbostic if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 48647139Sbostic synerror("Illegal eof marker for << redirection"); 48747139Sbostic rmescapes(wordtext); 48847139Sbostic here->eofmark = wordtext; 48947139Sbostic here->next = NULL; 49047139Sbostic if (heredoclist == NULL) 49147139Sbostic heredoclist = here; 49247139Sbostic else { 49347139Sbostic for (p = heredoclist ; p->next ; p = p->next); 49447139Sbostic p->next = here; 49547139Sbostic } 49647139Sbostic } else if (n->type == NTOFD || n->type == NFROMFD) { 49747139Sbostic if (is_digit(wordtext[0])) 49847139Sbostic n->ndup.dupfd = digit_val(wordtext[0]); 49947139Sbostic else if (wordtext[0] == '-') 50047139Sbostic n->ndup.dupfd = -1; 50147139Sbostic else 50247139Sbostic goto bad; 50347139Sbostic if (wordtext[1] != '\0') { 50447139Sbostic bad: 50547139Sbostic synerror("Bad fd number"); 50647139Sbostic } 50747139Sbostic } else { 50847139Sbostic n->nfile.fname = (union node *)stalloc(sizeof (struct narg)); 50947139Sbostic n = n->nfile.fname; 51047139Sbostic n->type = NARG; 51147139Sbostic n->narg.next = NULL; 51247139Sbostic n->narg.text = wordtext; 51347139Sbostic n->narg.backquote = backquotelist; 51447139Sbostic } 51547139Sbostic } 51647139Sbostic 51747139Sbostic 51847139Sbostic /* 51947139Sbostic * Input any here documents. 52047139Sbostic */ 52147139Sbostic 52247139Sbostic STATIC void 52347139Sbostic parseheredoc() { 52447139Sbostic struct heredoc *here; 52547139Sbostic union node *n; 52647139Sbostic 52747139Sbostic while (heredoclist) { 52847139Sbostic here = heredoclist; 52947139Sbostic heredoclist = here->next; 53047139Sbostic if (needprompt) { 53147139Sbostic putprompt(ps2val()); 53247139Sbostic needprompt = 0; 53347139Sbostic } 53447139Sbostic readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 53547139Sbostic here->eofmark, here->striptabs); 53647139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 53747139Sbostic n->narg.type = NARG; 53847139Sbostic n->narg.next = NULL; 53947139Sbostic n->narg.text = wordtext; 54047139Sbostic n->narg.backquote = backquotelist; 54147139Sbostic here->here->nhere.doc = n; 54247139Sbostic } 54347139Sbostic } 54447139Sbostic 545*47981Smarc STATIC int 546*47981Smarc peektoken() { 54747139Sbostic int t; 54847139Sbostic 549*47981Smarc t = readtoken(); 55047139Sbostic tokpushback++; 551*47981Smarc return (t); 55247139Sbostic } 55347139Sbostic 55447139Sbostic STATIC int xxreadtoken(); 55547139Sbostic 55647139Sbostic STATIC int 55747139Sbostic readtoken() { 55847139Sbostic int t; 559*47981Smarc #ifdef DEBUG 560*47981Smarc int alreadyseen = tokpushback; 561*47981Smarc #endif 562*47981Smarc 563*47981Smarc t = xxreadtoken(); 56447139Sbostic 565*47981Smarc if (checkkwd) { 566*47981Smarc /* 567*47981Smarc * eat newlines 568*47981Smarc */ 569*47981Smarc if (checkkwd == 2) { 570*47981Smarc checkkwd = 0; 571*47981Smarc while (t == TNL) { 572*47981Smarc parseheredoc(); 573*47981Smarc t = xxreadtoken(); 574*47981Smarc } 575*47981Smarc } else 576*47981Smarc checkkwd = 0; 577*47981Smarc /* 578*47981Smarc * check for keywords 579*47981Smarc */ 580*47981Smarc if (t == TWORD && !quoteflag) { 581*47981Smarc register char **pp; 582*47981Smarc 583*47981Smarc for (pp = parsekwd; *pp; pp++) { 584*47981Smarc if (**pp == *wordtext && equal(*pp, wordtext)) { 585*47981Smarc lasttoken = t = pp - parsekwd + KWDOFFSET; 586*47981Smarc TRACE(("keyword %s recognized\n", tokname[t])); 587*47981Smarc break; 588*47981Smarc } 589*47981Smarc } 590*47981Smarc } 59147139Sbostic } 592*47981Smarc #ifdef DEBUG 593*47981Smarc if (!alreadyseen) 594*47981Smarc TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 595*47981Smarc else 596*47981Smarc TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 597*47981Smarc #endif 598*47981Smarc return (t); 59947139Sbostic } 60047139Sbostic 60147139Sbostic 60247139Sbostic /* 60347139Sbostic * Read the next input token. 60447139Sbostic * If the token is a word, we set backquotelist to the list of cmds in 60547139Sbostic * backquotes. We set quoteflag to true if any part of the word was 60647139Sbostic * quoted. 60747139Sbostic * If the token is TREDIR, then we set redirnode to a structure containing 60847139Sbostic * the redirection. 60947139Sbostic * In all cases, the variable startlinno is set to the number of the line 61047139Sbostic * on which the token starts. 61147139Sbostic * 61247139Sbostic * [Change comment: here documents and internal procedures] 61347139Sbostic * [Readtoken shouldn't have any arguments. Perhaps we should make the 61447139Sbostic * word parsing code into a separate routine. In this case, readtoken 61547139Sbostic * doesn't need to have any internal procedures, but parseword does. 61647139Sbostic * We could also make parseoperator in essence the main routine, and 61747139Sbostic * have parseword (readtoken1?) handle both words and redirection.] 61847139Sbostic */ 61947139Sbostic 62047139Sbostic #define RETURN(token) return lasttoken = token 62147139Sbostic 62247139Sbostic STATIC int 62347139Sbostic xxreadtoken() { 62447139Sbostic register c; 62547139Sbostic 62647139Sbostic if (tokpushback) { 62747139Sbostic tokpushback = 0; 62847139Sbostic return lasttoken; 62947139Sbostic } 63047139Sbostic if (needprompt) { 63147139Sbostic putprompt(ps2val()); 63247139Sbostic needprompt = 0; 63347139Sbostic } 63447139Sbostic startlinno = plinno; 63547139Sbostic for (;;) { /* until token or start of word found */ 63647139Sbostic c = pgetc_macro(); 63747139Sbostic if (c == ' ' || c == '\t') 63847139Sbostic continue; /* quick check for white space first */ 63947139Sbostic switch (c) { 64047139Sbostic case ' ': case '\t': 64147139Sbostic continue; 64247139Sbostic case '#': 64347139Sbostic while ((c = pgetc()) != '\n' && c != PEOF); 64447139Sbostic pungetc(); 64547139Sbostic continue; 64647139Sbostic case '\\': 64747139Sbostic if (pgetc() == '\n') { 64847139Sbostic startlinno = ++plinno; 64947139Sbostic if (doprompt) 65047139Sbostic putprompt(ps2val()); 65147139Sbostic continue; 65247139Sbostic } 65347139Sbostic pungetc(); 65447139Sbostic goto breakloop; 65547139Sbostic case '\n': 65647139Sbostic plinno++; 65747139Sbostic needprompt = doprompt; 65847139Sbostic RETURN(TNL); 65947139Sbostic case PEOF: 66047139Sbostic RETURN(TEOF); 66147139Sbostic case '&': 66247139Sbostic if (pgetc() == '&') 66347139Sbostic RETURN(TAND); 66447139Sbostic pungetc(); 66547139Sbostic RETURN(TBACKGND); 66647139Sbostic case '|': 66747139Sbostic if (pgetc() == '|') 66847139Sbostic RETURN(TOR); 66947139Sbostic pungetc(); 67047139Sbostic RETURN(TPIPE); 67147139Sbostic case ';': 67247139Sbostic if (pgetc() == ';') 67347139Sbostic RETURN(TENDCASE); 67447139Sbostic pungetc(); 67547139Sbostic RETURN(TSEMI); 67647139Sbostic case '(': 67747139Sbostic RETURN(TLP); 67847139Sbostic case ')': 67947139Sbostic RETURN(TRP); 68047139Sbostic default: 68147139Sbostic goto breakloop; 68247139Sbostic } 68347139Sbostic } 68447139Sbostic breakloop: 68547139Sbostic return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 68647139Sbostic #undef RETURN 68747139Sbostic } 68847139Sbostic 68947139Sbostic 69047139Sbostic 69147139Sbostic /* 69247139Sbostic * If eofmark is NULL, read a word or a redirection symbol. If eofmark 69347139Sbostic * is not NULL, read a here document. In the latter case, eofmark is the 69447139Sbostic * word which marks the end of the document and striptabs is true if 69547139Sbostic * leading tabs should be stripped from the document. The argument firstc 69647139Sbostic * is the first character of the input token or document. 69747139Sbostic * 69847139Sbostic * Because C does not have internal subroutines, I have simulated them 69947139Sbostic * using goto's to implement the subroutine linkage. The following macros 70047139Sbostic * will run code that appears at the end of readtoken1. 70147139Sbostic */ 70247139Sbostic 70347139Sbostic #define CHECKEND() {goto checkend; checkend_return:;} 70447139Sbostic #define PARSEREDIR() {goto parseredir; parseredir_return:;} 70547139Sbostic #define PARSESUB() {goto parsesub; parsesub_return:;} 70647139Sbostic #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 70747139Sbostic #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 70847139Sbostic 70947139Sbostic STATIC int 71047139Sbostic readtoken1(firstc, syntax, eofmark, striptabs) 71147139Sbostic int firstc; 71247139Sbostic char const *syntax; 71347139Sbostic char *eofmark; 71447139Sbostic int striptabs; 71547139Sbostic { 71647139Sbostic register c = firstc; 71747139Sbostic register char *out; 71847139Sbostic int len; 71947139Sbostic char line[EOFMARKLEN + 1]; 72047139Sbostic struct nodelist *bqlist; 72147139Sbostic int quotef; 72247139Sbostic int dblquote; 72347139Sbostic int varnest; 72447139Sbostic int oldstyle; 72547139Sbostic 72647139Sbostic startlinno = plinno; 72747139Sbostic dblquote = 0; 72847139Sbostic if (syntax == DQSYNTAX) 72947139Sbostic dblquote = 1; 73047139Sbostic quotef = 0; 73147139Sbostic bqlist = NULL; 73247139Sbostic varnest = 0; 73347139Sbostic STARTSTACKSTR(out); 73447139Sbostic loop: { /* for each line, until end of word */ 73547139Sbostic #if ATTY 73647139Sbostic if (c == '\034' && doprompt 73747139Sbostic && attyset() && ! equal(termval(), "emacs")) { 73847139Sbostic attyline(); 73947139Sbostic if (syntax == BASESYNTAX) 74047139Sbostic return readtoken(); 74147139Sbostic c = pgetc(); 74247139Sbostic goto loop; 74347139Sbostic } 74447139Sbostic #endif 74547139Sbostic CHECKEND(); /* set c to PEOF if at end of here document */ 74647139Sbostic for (;;) { /* until end of line or end of word */ 74747139Sbostic CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 74847139Sbostic switch(syntax[c]) { 74947139Sbostic case CNL: /* '\n' */ 75047139Sbostic if (syntax == BASESYNTAX) 75147139Sbostic goto endword; /* exit outer loop */ 75247139Sbostic USTPUTC(c, out); 75347139Sbostic plinno++; 75447139Sbostic if (doprompt) { 75547139Sbostic putprompt(ps2val()); 75647139Sbostic } 75747139Sbostic c = pgetc(); 75847139Sbostic goto loop; /* continue outer loop */ 75947139Sbostic case CWORD: 76047139Sbostic USTPUTC(c, out); 76147139Sbostic break; 76247139Sbostic case CCTL: 76347139Sbostic if (eofmark == NULL || dblquote) 76447139Sbostic USTPUTC(CTLESC, out); 76547139Sbostic USTPUTC(c, out); 76647139Sbostic break; 76747139Sbostic case CBACK: /* backslash */ 76847139Sbostic c = pgetc(); 76947139Sbostic if (c == PEOF) { 77047139Sbostic USTPUTC('\\', out); 77147139Sbostic pungetc(); 77247139Sbostic } else if (c == '\n') { 77347139Sbostic if (doprompt) 77447139Sbostic putprompt(ps2val()); 77547139Sbostic } else { 77647139Sbostic if (dblquote && c != '\\' && c != '`' && c != '$' 77747139Sbostic && (c != '"' || eofmark != NULL)) 77847139Sbostic USTPUTC('\\', out); 77947139Sbostic if (SQSYNTAX[c] == CCTL) 78047139Sbostic USTPUTC(CTLESC, out); 78147139Sbostic USTPUTC(c, out); 78247139Sbostic quotef++; 78347139Sbostic } 78447139Sbostic break; 78547139Sbostic case CSQUOTE: 78647139Sbostic syntax = SQSYNTAX; 78747139Sbostic break; 78847139Sbostic case CDQUOTE: 78947139Sbostic syntax = DQSYNTAX; 79047139Sbostic dblquote = 1; 79147139Sbostic break; 79247139Sbostic case CENDQUOTE: 79347139Sbostic if (eofmark) { 79447139Sbostic USTPUTC(c, out); 79547139Sbostic } else { 79647139Sbostic syntax = BASESYNTAX; 79747139Sbostic quotef++; 79847139Sbostic dblquote = 0; 79947139Sbostic } 80047139Sbostic break; 80147139Sbostic case CVAR: /* '$' */ 80247139Sbostic PARSESUB(); /* parse substitution */ 80347139Sbostic break; 80447139Sbostic case CENDVAR: /* '}' */ 80547139Sbostic if (varnest > 0) { 80647139Sbostic varnest--; 80747139Sbostic USTPUTC(CTLENDVAR, out); 80847139Sbostic } else { 80947139Sbostic USTPUTC(c, out); 81047139Sbostic } 81147139Sbostic break; 81247139Sbostic case CBQUOTE: /* '`' */ 81347139Sbostic if (parsebackquote && syntax == BASESYNTAX) { 81447139Sbostic if (out == stackblock()) 81547139Sbostic return lasttoken = TENDBQUOTE; 81647139Sbostic else 81747139Sbostic goto endword; /* exit outer loop */ 81847139Sbostic } 81947139Sbostic PARSEBACKQOLD(); 82047139Sbostic break; 82147139Sbostic case CEOF: 82247139Sbostic goto endword; /* exit outer loop */ 82347139Sbostic default: 82447139Sbostic if (varnest == 0) 82547139Sbostic goto endword; /* exit outer loop */ 82647139Sbostic USTPUTC(c, out); 82747139Sbostic } 82847139Sbostic c = pgetc_macro(); 82947139Sbostic } 83047139Sbostic } 83147139Sbostic endword: 83247139Sbostic if (syntax != BASESYNTAX && eofmark == NULL) 83347139Sbostic synerror("Unterminated quoted string"); 83447139Sbostic if (varnest != 0) { 83547139Sbostic startlinno = plinno; 83647139Sbostic synerror("Missing '}'"); 83747139Sbostic } 83847139Sbostic USTPUTC('\0', out); 83947139Sbostic len = out - stackblock(); 84047139Sbostic out = stackblock(); 84147139Sbostic if (eofmark == NULL) { 84247139Sbostic if ((c == '>' || c == '<') 84347139Sbostic && quotef == 0 84447139Sbostic && len <= 2 84547139Sbostic && (*out == '\0' || is_digit(*out))) { 84647139Sbostic PARSEREDIR(); 84747139Sbostic return lasttoken = TREDIR; 84847139Sbostic } else { 84947139Sbostic pungetc(); 85047139Sbostic } 85147139Sbostic } 85247139Sbostic quoteflag = quotef; 85347139Sbostic backquotelist = bqlist; 85447139Sbostic grabstackblock(len); 85547139Sbostic wordtext = out; 85647139Sbostic return lasttoken = TWORD; 85747139Sbostic /* end of readtoken routine */ 85847139Sbostic 85947139Sbostic 86047139Sbostic 86147139Sbostic /* 86247139Sbostic * Check to see whether we are at the end of the here document. When this 86347139Sbostic * is called, c is set to the first character of the next input line. If 86447139Sbostic * we are at the end of the here document, this routine sets the c to PEOF. 86547139Sbostic */ 86647139Sbostic 86747139Sbostic checkend: { 86847139Sbostic if (eofmark) { 86947139Sbostic if (striptabs) { 87047139Sbostic while (c == '\t') 87147139Sbostic c = pgetc(); 87247139Sbostic } 87347139Sbostic if (c == *eofmark) { 87447139Sbostic if (pfgets(line, sizeof line) != NULL) { 87547139Sbostic register char *p, *q; 87647139Sbostic 87747139Sbostic p = line; 87847139Sbostic for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 87947139Sbostic if (*p == '\n' && *q == '\0') { 88047139Sbostic c = PEOF; 88147139Sbostic plinno++; 88247139Sbostic needprompt = doprompt; 88347139Sbostic } else { 88447139Sbostic ppushback(line, strlen(line)); 88547139Sbostic } 88647139Sbostic } 88747139Sbostic } 88847139Sbostic } 88947139Sbostic goto checkend_return; 89047139Sbostic } 89147139Sbostic 89247139Sbostic 89347139Sbostic /* 89447139Sbostic * Parse a redirection operator. The variable "out" points to a string 89547139Sbostic * specifying the fd to be redirected. The variable "c" contains the 89647139Sbostic * first character of the redirection operator. 89747139Sbostic */ 89847139Sbostic 89947139Sbostic parseredir: { 90047139Sbostic char fd = *out; 90147139Sbostic union node *np; 90247139Sbostic 90347139Sbostic np = (union node *)stalloc(sizeof (struct nfile)); 90447139Sbostic if (c == '>') { 90547139Sbostic np->nfile.fd = 1; 90647139Sbostic c = pgetc(); 90747139Sbostic if (c == '>') 90847139Sbostic np->type = NAPPEND; 90947139Sbostic else if (c == '&') 91047139Sbostic np->type = NTOFD; 91147139Sbostic else { 91247139Sbostic np->type = NTO; 91347139Sbostic pungetc(); 91447139Sbostic } 91547139Sbostic } else { /* c == '<' */ 91647139Sbostic np->nfile.fd = 0; 91747139Sbostic c = pgetc(); 91847139Sbostic if (c == '<') { 91947139Sbostic if (sizeof (struct nfile) != sizeof (struct nhere)) { 92047139Sbostic np = (union node *)stalloc(sizeof (struct nhere)); 92147139Sbostic np->nfile.fd = 0; 92247139Sbostic } 92347139Sbostic np->type = NHERE; 92447139Sbostic heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 92547139Sbostic heredoc->here = np; 92647139Sbostic if ((c = pgetc()) == '-') { 92747139Sbostic heredoc->striptabs = 1; 92847139Sbostic } else { 92947139Sbostic heredoc->striptabs = 0; 93047139Sbostic pungetc(); 93147139Sbostic } 93247139Sbostic } else if (c == '&') 93347139Sbostic np->type = NFROMFD; 93447139Sbostic else { 93547139Sbostic np->type = NFROM; 93647139Sbostic pungetc(); 93747139Sbostic } 93847139Sbostic } 93947139Sbostic if (fd != '\0') 94047139Sbostic np->nfile.fd = digit_val(fd); 94147139Sbostic redirnode = np; 94247139Sbostic goto parseredir_return; 94347139Sbostic } 94447139Sbostic 94547139Sbostic 94647139Sbostic /* 94747139Sbostic * Parse a substitution. At this point, we have read the dollar sign 94847139Sbostic * and nothing else. 94947139Sbostic */ 95047139Sbostic 95147139Sbostic parsesub: { 95247139Sbostic int subtype; 95347139Sbostic int typeloc; 95447139Sbostic int flags; 95547139Sbostic char *p; 95647139Sbostic #ifndef GDB_HACK 95747139Sbostic static const char types[] = "}-+?="; 95847139Sbostic #endif 95947139Sbostic 96047139Sbostic c = pgetc(); 96147300Smarc if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 96247139Sbostic USTPUTC('$', out); 96347139Sbostic pungetc(); 96447139Sbostic } else if (c == '(') { /* $(command) */ 96547139Sbostic PARSEBACKQNEW(); 96647139Sbostic } else { 96747139Sbostic USTPUTC(CTLVAR, out); 96847139Sbostic typeloc = out - stackblock(); 96947139Sbostic USTPUTC(VSNORMAL, out); 97047139Sbostic subtype = VSNORMAL; 97147139Sbostic if (c == '{') { 97247139Sbostic c = pgetc(); 97347139Sbostic subtype = 0; 97447139Sbostic } 97547139Sbostic if (is_name(c)) { 97647139Sbostic do { 97747139Sbostic STPUTC(c, out); 97847139Sbostic c = pgetc(); 97947139Sbostic } while (is_in_name(c)); 98047139Sbostic } else { 98147139Sbostic if (! is_special(c)) 98247300Smarc badsub: synerror("Bad substitution"); 98347139Sbostic USTPUTC(c, out); 98447139Sbostic c = pgetc(); 98547139Sbostic } 98647139Sbostic STPUTC('=', out); 98747139Sbostic flags = 0; 98847139Sbostic if (subtype == 0) { 98947139Sbostic if (c == ':') { 99047139Sbostic flags = VSNUL; 99147139Sbostic c = pgetc(); 99247139Sbostic } 99347139Sbostic p = strchr(types, c); 99447139Sbostic if (p == NULL) 99547139Sbostic goto badsub; 99647139Sbostic subtype = p - types + VSNORMAL; 99747139Sbostic } else { 99847139Sbostic pungetc(); 99947139Sbostic } 100047139Sbostic if (dblquote) 100147139Sbostic flags |= VSQUOTE; 100247139Sbostic *(stackblock() + typeloc) = subtype | flags; 100347139Sbostic if (subtype != VSNORMAL) 100447139Sbostic varnest++; 100547139Sbostic } 100647139Sbostic goto parsesub_return; 100747139Sbostic } 100847139Sbostic 100947139Sbostic 101047139Sbostic /* 101147139Sbostic * Called to parse command substitutions. Newstyle is set if the command 101247139Sbostic * is enclosed inside $(...); nlpp is a pointer to the head of the linked 101347139Sbostic * list of commands (passed by reference), and savelen is the number of 101447139Sbostic * characters on the top of the stack which must be preserved. 101547139Sbostic */ 101647139Sbostic 101747139Sbostic parsebackq: { 101847139Sbostic struct nodelist **nlpp; 101947139Sbostic int savepbq; 102047139Sbostic union node *n; 102147139Sbostic char *volatile str; 102247139Sbostic struct jmploc jmploc; 102347139Sbostic struct jmploc *volatile savehandler; 102447139Sbostic int savelen; 102547139Sbostic int t; 102647139Sbostic 102747139Sbostic savepbq = parsebackquote; 102847139Sbostic if (setjmp(jmploc.loc)) { 102947139Sbostic if (str) 103047139Sbostic ckfree(str); 103147139Sbostic parsebackquote = 0; 103247139Sbostic handler = savehandler; 103347139Sbostic longjmp(handler, 1); 103447139Sbostic } 103547139Sbostic INTOFF; 103647139Sbostic str = NULL; 103747139Sbostic savelen = out - stackblock(); 103847139Sbostic if (savelen > 0) { 103947139Sbostic str = ckmalloc(savelen); 104047139Sbostic bcopy(stackblock(), str, savelen); 104147139Sbostic } 104247139Sbostic savehandler = handler; 104347139Sbostic handler = &jmploc; 104447139Sbostic INTON; 104547139Sbostic nlpp = &bqlist; 104647139Sbostic while (*nlpp) 104747139Sbostic nlpp = &(*nlpp)->next; 104847139Sbostic *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 104947139Sbostic (*nlpp)->next = NULL; 105047139Sbostic parsebackquote = oldstyle; 105147139Sbostic n = list(0); 105247139Sbostic t = oldstyle? TENDBQUOTE : TRP; 105347139Sbostic if (readtoken() != t) 105447139Sbostic synexpect(t); 105547139Sbostic (*nlpp)->n = n; 105647139Sbostic while (stackblocksize() <= savelen) 105747139Sbostic growstackblock(); 105847139Sbostic STARTSTACKSTR(out); 105947139Sbostic if (str) { 106047139Sbostic bcopy(str, out, savelen); 106147139Sbostic STADJUST(savelen, out); 106247139Sbostic INTOFF; 106347139Sbostic ckfree(str); 106447139Sbostic str = NULL; 106547139Sbostic INTON; 106647139Sbostic } 106747139Sbostic parsebackquote = savepbq; 106847139Sbostic handler = savehandler; 106947139Sbostic USTPUTC(CTLBACKQ + dblquote, out); 107047139Sbostic if (oldstyle) 107147139Sbostic goto parsebackq_oldreturn; 107247139Sbostic else 107347139Sbostic goto parsebackq_newreturn; 107447139Sbostic } 107547139Sbostic 107647139Sbostic } /* end of readtoken */ 107747139Sbostic 107847139Sbostic 107947139Sbostic 108047139Sbostic #ifdef mkinit 108147139Sbostic RESET { 108247139Sbostic tokpushback = 0; 108347139Sbostic } 108447139Sbostic #endif 108547139Sbostic 108647139Sbostic 108747139Sbostic #if ATTY 108847139Sbostic /* 108947139Sbostic * Called to process a command generated by atty. We execute the line, 109047139Sbostic * and catch any errors that occur so they don't propagate outside of 109147139Sbostic * this routine. 109247139Sbostic */ 109347139Sbostic 109447139Sbostic STATIC void 109547139Sbostic attyline() { 109647139Sbostic char line[256]; 109747139Sbostic struct stackmark smark; 109847139Sbostic struct jmploc jmploc; 109947139Sbostic struct jmploc *volatile savehandler; 110047139Sbostic 110147139Sbostic if (pfgets(line, sizeof line) == NULL) 110247139Sbostic return; /* "can't happen" */ 110347139Sbostic if (setjmp(jmploc.loc)) { 110447139Sbostic if (exception == EXERROR) 110547139Sbostic out2str("\033]D\n"); 110647139Sbostic handler = savehandler; 110747139Sbostic longjmp(handler, 1); 110847139Sbostic } 110947139Sbostic savehandler = handler; 111047139Sbostic handler = &jmploc; 111147139Sbostic setstackmark(&smark); 111247139Sbostic evalstring(line); 111347139Sbostic popstackmark(&smark); 111447139Sbostic handler = savehandler; 111547139Sbostic doprompt = 1; 111647139Sbostic } 111747139Sbostic 111847139Sbostic 111947139Sbostic /* 112047139Sbostic * Output a prompt for atty. We output the prompt as part of the 112147139Sbostic * appropriate escape sequence. 112247139Sbostic */ 112347139Sbostic 112447139Sbostic STATIC void 112547139Sbostic putprompt(s) 112647139Sbostic char *s; 112747139Sbostic { 112847139Sbostic register char *p; 112947139Sbostic 113047139Sbostic if (attyset() && ! equal(termval(), "emacs")) { 113147139Sbostic if (strchr(s, '\7')) 113247139Sbostic out2c('\7'); 113347139Sbostic out2str("\033]P1;"); 113447139Sbostic for (p = s ; *p ; p++) { 113547139Sbostic if ((unsigned)(*p - ' ') <= '~' - ' ') 113647139Sbostic out2c(*p); 113747139Sbostic } 113847139Sbostic out2c('\n'); 113947139Sbostic } else { 114047139Sbostic out2str(s); 114147139Sbostic } 114247139Sbostic } 114347139Sbostic #endif 114447139Sbostic 114547139Sbostic 114647139Sbostic 114747139Sbostic /* 114847139Sbostic * Returns true if the text contains nothing to expand (no dollar signs 114947139Sbostic * or backquotes). 115047139Sbostic */ 115147139Sbostic 115247139Sbostic STATIC int 115347139Sbostic noexpand(text) 115447139Sbostic char *text; 115547139Sbostic { 115647139Sbostic register char *p; 115747139Sbostic register char c; 115847139Sbostic 115947139Sbostic p = text; 116047139Sbostic while ((c = *p++) != '\0') { 116147139Sbostic if (c == CTLESC) 116247139Sbostic p++; 116347139Sbostic else if (BASESYNTAX[c] == CCTL) 116447139Sbostic return 0; 116547139Sbostic } 116647139Sbostic return 1; 116747139Sbostic } 116847139Sbostic 116947139Sbostic 117047139Sbostic /* 117147139Sbostic * Return true if the argument is a legal variable name (a letter or 117247139Sbostic * underscore followed by zero or more letters, underscores, and digits). 117347139Sbostic */ 117447139Sbostic 117547139Sbostic int 117647139Sbostic goodname(name) 117747139Sbostic char *name; 117847139Sbostic { 117947139Sbostic register char *p; 118047139Sbostic 118147139Sbostic p = name; 118247139Sbostic if (! is_name(*p)) 118347139Sbostic return 0; 118447139Sbostic while (*++p) { 118547139Sbostic if (! is_in_name(*p)) 118647139Sbostic return 0; 118747139Sbostic } 118847139Sbostic return 1; 118947139Sbostic } 119047139Sbostic 119147139Sbostic 119247139Sbostic /* 119347139Sbostic * Called when an unexpected token is read during the parse. The argument 119447139Sbostic * is the token that is expected, or -1 if more than one type of token can 119547139Sbostic * occur at this point. 119647139Sbostic */ 119747139Sbostic 119847139Sbostic STATIC void 119947139Sbostic synexpect(token) { 120047139Sbostic char msg[64]; 120147139Sbostic 120247139Sbostic if (token >= 0) { 120347139Sbostic fmtstr(msg, 64, "%s unexpected (expecting %s)", 120447139Sbostic tokname[lasttoken], tokname[token]); 120547139Sbostic } else { 120647139Sbostic fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 120747139Sbostic } 120847139Sbostic synerror(msg); 120947139Sbostic } 121047139Sbostic 121147139Sbostic 121247139Sbostic STATIC void 121347139Sbostic synerror(msg) 121447139Sbostic char *msg; 121547139Sbostic { 121647139Sbostic if (commandname) 121747139Sbostic outfmt(&errout, "%s: %d: ", commandname, startlinno); 121847139Sbostic outfmt(&errout, "Syntax error: %s\n", msg); 121947139Sbostic error((char *)NULL); 122047139Sbostic } 1221