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