14b88c807SRodney W. Grimes /*- 24b88c807SRodney W. Grimes * Copyright (c) 1991, 1993 34b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 44b88c807SRodney W. Grimes * 54b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 64b88c807SRodney W. Grimes * Kenneth Almquist. 74b88c807SRodney W. Grimes * 84b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 94b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 104b88c807SRodney W. Grimes * are met: 114b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 124b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 134b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 144b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 154b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 164b88c807SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 174b88c807SRodney W. Grimes * must display the following acknowledgement: 184b88c807SRodney W. Grimes * This product includes software developed by the University of 194b88c807SRodney W. Grimes * California, Berkeley and its contributors. 204b88c807SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 214b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 224b88c807SRodney W. Grimes * without specific prior written permission. 234b88c807SRodney W. Grimes * 244b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 254b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 264b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 274b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 284b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 294b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 304b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 314b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 324b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 334b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 344b88c807SRodney W. Grimes * SUCH DAMAGE. 354b88c807SRodney W. Grimes */ 364b88c807SRodney W. Grimes 374b88c807SRodney W. Grimes #ifndef lint 383d7b5b93SPhilippe Charnier #if 0 393d7b5b93SPhilippe Charnier static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; 403d7b5b93SPhilippe Charnier #endif 413d7b5b93SPhilippe Charnier static const char rcsid[] = 422a456239SPeter Wemm "$FreeBSD$"; 434b88c807SRodney W. Grimes #endif /* not lint */ 444b88c807SRodney W. Grimes 45aa9caaf6SPeter Wemm #include <stdlib.h> 46aa9caaf6SPeter Wemm 474b88c807SRodney W. Grimes #include "shell.h" 484b88c807SRodney W. Grimes #include "parser.h" 494b88c807SRodney W. Grimes #include "nodes.h" 504b88c807SRodney W. Grimes #include "expand.h" /* defines rmescapes() */ 514b88c807SRodney W. Grimes #include "redir.h" /* defines copyfd() */ 524b88c807SRodney W. Grimes #include "syntax.h" 534b88c807SRodney W. Grimes #include "options.h" 544b88c807SRodney W. Grimes #include "input.h" 554b88c807SRodney W. Grimes #include "output.h" 564b88c807SRodney W. Grimes #include "var.h" 574b88c807SRodney W. Grimes #include "error.h" 584b88c807SRodney W. Grimes #include "memalloc.h" 594b88c807SRodney W. Grimes #include "mystring.h" 604b88c807SRodney W. Grimes #include "alias.h" 61aa9caaf6SPeter Wemm #include "show.h" 62f01e3d0cSMartin Cracauer #include "eval.h" 63aa9caaf6SPeter Wemm #ifndef NO_HISTORY 644b88c807SRodney W. Grimes #include "myhistedit.h" 65aa9caaf6SPeter Wemm #endif 664b88c807SRodney W. Grimes 674b88c807SRodney W. Grimes /* 684b88c807SRodney W. Grimes * Shell command parser. 694b88c807SRodney W. Grimes */ 704b88c807SRodney W. Grimes 714b88c807SRodney W. Grimes #define EOFMARKLEN 79 724b88c807SRodney W. Grimes 734b88c807SRodney W. Grimes /* values returned by readtoken */ 74aa9caaf6SPeter Wemm #include "token.h" 754b88c807SRodney W. Grimes 764b88c807SRodney W. Grimes 774b88c807SRodney W. Grimes 784b88c807SRodney W. Grimes struct heredoc { 794b88c807SRodney W. Grimes struct heredoc *next; /* next here document in list */ 804b88c807SRodney W. Grimes union node *here; /* redirection node */ 814b88c807SRodney W. Grimes char *eofmark; /* string indicating end of input */ 824b88c807SRodney W. Grimes int striptabs; /* if set, strip leading tabs */ 834b88c807SRodney W. Grimes }; 844b88c807SRodney W. Grimes 854b88c807SRodney W. Grimes 864b88c807SRodney W. Grimes 874b88c807SRodney W. Grimes struct heredoc *heredoclist; /* list of here documents to read */ 884b88c807SRodney W. Grimes int parsebackquote; /* nonzero if we are inside backquotes */ 894b88c807SRodney W. Grimes int doprompt; /* if set, prompt the user */ 904b88c807SRodney W. Grimes int needprompt; /* true if interactive and at start of line */ 914b88c807SRodney W. Grimes int lasttoken; /* last token read */ 924b88c807SRodney W. Grimes MKINIT int tokpushback; /* last token pushed back */ 934b88c807SRodney W. Grimes char *wordtext; /* text of last word returned by readtoken */ 944b88c807SRodney W. Grimes MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 954b88c807SRodney W. Grimes struct nodelist *backquotelist; 964b88c807SRodney W. Grimes union node *redirnode; 974b88c807SRodney W. Grimes struct heredoc *heredoc; 984b88c807SRodney W. Grimes int quoteflag; /* set if (part of) last token was quoted */ 994b88c807SRodney W. Grimes int startlinno; /* line # where last token started */ 1004b88c807SRodney W. Grimes 1014417f629SPeter Wemm /* XXX When 'noaliases' is set to one, no alias expansion takes place. */ 1024417f629SPeter Wemm static int noaliases = 0; 1034b88c807SRodney W. Grimes 1044b88c807SRodney W. Grimes #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ 1054b88c807SRodney W. Grimes #ifdef GDB_HACK 1064b88c807SRodney W. Grimes static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; 1074b88c807SRodney W. Grimes static const char types[] = "}-+?="; 1084b88c807SRodney W. Grimes #endif 1094b88c807SRodney W. Grimes 1104b88c807SRodney W. Grimes 1114b88c807SRodney W. Grimes STATIC union node *list __P((int)); 1124b88c807SRodney W. Grimes STATIC union node *andor __P((void)); 1134b88c807SRodney W. Grimes STATIC union node *pipeline __P((void)); 1144b88c807SRodney W. Grimes STATIC union node *command __P((void)); 1154b88c807SRodney W. Grimes STATIC union node *simplecmd __P((union node **, union node *)); 116aa9caaf6SPeter Wemm STATIC union node *makename __P((void)); 1174b88c807SRodney W. Grimes STATIC void parsefname __P((void)); 1184b88c807SRodney W. Grimes STATIC void parseheredoc __P((void)); 119aa9caaf6SPeter Wemm STATIC int peektoken __P((void)); 1204b88c807SRodney W. Grimes STATIC int readtoken __P((void)); 121aa9caaf6SPeter Wemm STATIC int xxreadtoken __P((void)); 1224b88c807SRodney W. Grimes STATIC int readtoken1 __P((int, char const *, char *, int)); 1234b88c807SRodney W. Grimes STATIC int noexpand __P((char *)); 1244b88c807SRodney W. Grimes STATIC void synexpect __P((int)); 1254b88c807SRodney W. Grimes STATIC void synerror __P((char *)); 1264b88c807SRodney W. Grimes STATIC void setprompt __P((int)); 1274b88c807SRodney W. Grimes 128aa9caaf6SPeter Wemm 1294b88c807SRodney W. Grimes /* 1304b88c807SRodney W. Grimes * Read and parse a command. Returns NEOF on end of file. (NULL is a 1314b88c807SRodney W. Grimes * valid parse tree indicating a blank line.) 1324b88c807SRodney W. Grimes */ 1334b88c807SRodney W. Grimes 1344b88c807SRodney W. Grimes union node * 135aa9caaf6SPeter Wemm parsecmd(interact) 136aa9caaf6SPeter Wemm int interact; 137aa9caaf6SPeter Wemm { 1384b88c807SRodney W. Grimes int t; 1394b88c807SRodney W. Grimes 14098e05fd3SMartin Cracauer tokpushback = 0; 1414b88c807SRodney W. Grimes doprompt = interact; 1424b88c807SRodney W. Grimes if (doprompt) 1434b88c807SRodney W. Grimes setprompt(1); 1444b88c807SRodney W. Grimes else 1454b88c807SRodney W. Grimes setprompt(0); 1464b88c807SRodney W. Grimes needprompt = 0; 1474b88c807SRodney W. Grimes t = readtoken(); 1484b88c807SRodney W. Grimes if (t == TEOF) 1494b88c807SRodney W. Grimes return NEOF; 1504b88c807SRodney W. Grimes if (t == TNL) 1514b88c807SRodney W. Grimes return NULL; 1524b88c807SRodney W. Grimes tokpushback++; 1534b88c807SRodney W. Grimes return list(1); 1544b88c807SRodney W. Grimes } 1554b88c807SRodney W. Grimes 1564b88c807SRodney W. Grimes 1574b88c807SRodney W. Grimes STATIC union node * 158aa9caaf6SPeter Wemm list(nlflag) 159aa9caaf6SPeter Wemm int nlflag; 160aa9caaf6SPeter Wemm { 1614b88c807SRodney W. Grimes union node *n1, *n2, *n3; 162aa9caaf6SPeter Wemm int tok; 1634b88c807SRodney W. Grimes 1644b88c807SRodney W. Grimes checkkwd = 2; 1654b88c807SRodney W. Grimes if (nlflag == 0 && tokendlist[peektoken()]) 1664b88c807SRodney W. Grimes return NULL; 167aa9caaf6SPeter Wemm n1 = NULL; 1684b88c807SRodney W. Grimes for (;;) { 1694b88c807SRodney W. Grimes n2 = andor(); 170aa9caaf6SPeter Wemm tok = readtoken(); 171aa9caaf6SPeter Wemm if (tok == TBACKGND) { 172aa9caaf6SPeter Wemm if (n2->type == NCMD || n2->type == NPIPE) { 173aa9caaf6SPeter Wemm n2->ncmd.backgnd = 1; 174aa9caaf6SPeter Wemm } else if (n2->type == NREDIR) { 175aa9caaf6SPeter Wemm n2->type = NBACKGND; 176aa9caaf6SPeter Wemm } else { 177aa9caaf6SPeter Wemm n3 = (union node *)stalloc(sizeof (struct nredir)); 178aa9caaf6SPeter Wemm n3->type = NBACKGND; 179aa9caaf6SPeter Wemm n3->nredir.n = n2; 180aa9caaf6SPeter Wemm n3->nredir.redirect = NULL; 181aa9caaf6SPeter Wemm n2 = n3; 182aa9caaf6SPeter Wemm } 183aa9caaf6SPeter Wemm } 184aa9caaf6SPeter Wemm if (n1 == NULL) { 185aa9caaf6SPeter Wemm n1 = n2; 186aa9caaf6SPeter Wemm } 187aa9caaf6SPeter Wemm else { 1884b88c807SRodney W. Grimes n3 = (union node *)stalloc(sizeof (struct nbinary)); 1894b88c807SRodney W. Grimes n3->type = NSEMI; 1904b88c807SRodney W. Grimes n3->nbinary.ch1 = n1; 1914b88c807SRodney W. Grimes n3->nbinary.ch2 = n2; 1924b88c807SRodney W. Grimes n1 = n3; 193aa9caaf6SPeter Wemm } 194aa9caaf6SPeter Wemm switch (tok) { 195aa9caaf6SPeter Wemm case TBACKGND: 196aa9caaf6SPeter Wemm case TSEMI: 197aa9caaf6SPeter Wemm tok = readtoken(); 198aa9caaf6SPeter Wemm /* fall through */ 199aa9caaf6SPeter Wemm case TNL: 200aa9caaf6SPeter Wemm if (tok == TNL) { 201aa9caaf6SPeter Wemm parseheredoc(); 202aa9caaf6SPeter Wemm if (nlflag) 203aa9caaf6SPeter Wemm return n1; 204aa9caaf6SPeter Wemm } else { 205aa9caaf6SPeter Wemm tokpushback++; 206aa9caaf6SPeter Wemm } 207aa9caaf6SPeter Wemm checkkwd = 2; 208aa9caaf6SPeter Wemm if (tokendlist[peektoken()]) 209aa9caaf6SPeter Wemm return n1; 2104b88c807SRodney W. Grimes break; 2114b88c807SRodney W. Grimes case TEOF: 2124b88c807SRodney W. Grimes if (heredoclist) 2134b88c807SRodney W. Grimes parseheredoc(); 2144b88c807SRodney W. Grimes else 2154b88c807SRodney W. Grimes pungetc(); /* push back EOF on input */ 2164b88c807SRodney W. Grimes return n1; 2174b88c807SRodney W. Grimes default: 2184b88c807SRodney W. Grimes if (nlflag) 2194b88c807SRodney W. Grimes synexpect(-1); 2204b88c807SRodney W. Grimes tokpushback++; 2214b88c807SRodney W. Grimes return n1; 2224b88c807SRodney W. Grimes } 2234b88c807SRodney W. Grimes } 2244b88c807SRodney W. Grimes } 2254b88c807SRodney W. Grimes 2264b88c807SRodney W. Grimes 2274b88c807SRodney W. Grimes 2284b88c807SRodney W. Grimes STATIC union node * 2294b88c807SRodney W. Grimes andor() { 2304b88c807SRodney W. Grimes union node *n1, *n2, *n3; 2314b88c807SRodney W. Grimes int t; 2324b88c807SRodney W. Grimes 2334b88c807SRodney W. Grimes n1 = pipeline(); 2344b88c807SRodney W. Grimes for (;;) { 2354b88c807SRodney W. Grimes if ((t = readtoken()) == TAND) { 2364b88c807SRodney W. Grimes t = NAND; 2374b88c807SRodney W. Grimes } else if (t == TOR) { 2384b88c807SRodney W. Grimes t = NOR; 2394b88c807SRodney W. Grimes } else { 2404b88c807SRodney W. Grimes tokpushback++; 2414b88c807SRodney W. Grimes return n1; 2424b88c807SRodney W. Grimes } 2434b88c807SRodney W. Grimes n2 = pipeline(); 2444b88c807SRodney W. Grimes n3 = (union node *)stalloc(sizeof (struct nbinary)); 2454b88c807SRodney W. Grimes n3->type = t; 2464b88c807SRodney W. Grimes n3->nbinary.ch1 = n1; 2474b88c807SRodney W. Grimes n3->nbinary.ch2 = n2; 2484b88c807SRodney W. Grimes n1 = n3; 2494b88c807SRodney W. Grimes } 2504b88c807SRodney W. Grimes } 2514b88c807SRodney W. Grimes 2524b88c807SRodney W. Grimes 2534b88c807SRodney W. Grimes 2544b88c807SRodney W. Grimes STATIC union node * 2554b88c807SRodney W. Grimes pipeline() { 2567920a31dSSteve Price union node *n1, *pipenode, *notnode; 2574b88c807SRodney W. Grimes struct nodelist *lp, *prev; 2587920a31dSSteve Price int negate = 0; 2594b88c807SRodney W. Grimes 2604b88c807SRodney W. Grimes TRACE(("pipeline: entered\n")); 2617920a31dSSteve Price while (readtoken() == TNOT) { 2627920a31dSSteve Price TRACE(("pipeline: TNOT recognized\n")); 2637920a31dSSteve Price negate = !negate; 2647920a31dSSteve Price } 2657920a31dSSteve Price tokpushback++; 2664b88c807SRodney W. Grimes n1 = command(); 2674b88c807SRodney W. Grimes if (readtoken() == TPIPE) { 2684b88c807SRodney W. Grimes pipenode = (union node *)stalloc(sizeof (struct npipe)); 2694b88c807SRodney W. Grimes pipenode->type = NPIPE; 2704b88c807SRodney W. Grimes pipenode->npipe.backgnd = 0; 2714b88c807SRodney W. Grimes lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 2724b88c807SRodney W. Grimes pipenode->npipe.cmdlist = lp; 2734b88c807SRodney W. Grimes lp->n = n1; 2744b88c807SRodney W. Grimes do { 2754b88c807SRodney W. Grimes prev = lp; 2764b88c807SRodney W. Grimes lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 2774b88c807SRodney W. Grimes lp->n = command(); 2784b88c807SRodney W. Grimes prev->next = lp; 2794b88c807SRodney W. Grimes } while (readtoken() == TPIPE); 2804b88c807SRodney W. Grimes lp->next = NULL; 2814b88c807SRodney W. Grimes n1 = pipenode; 2824b88c807SRodney W. Grimes } 2834b88c807SRodney W. Grimes tokpushback++; 2847920a31dSSteve Price if (negate) { 2857920a31dSSteve Price notnode = (union node *)stalloc(sizeof(struct nnot)); 2867920a31dSSteve Price notnode->type = NNOT; 2877920a31dSSteve Price notnode->nnot.com = n1; 2887920a31dSSteve Price n1 = notnode; 2897920a31dSSteve Price } 2904b88c807SRodney W. Grimes return n1; 2914b88c807SRodney W. Grimes } 2924b88c807SRodney W. Grimes 2934b88c807SRodney W. Grimes 2944b88c807SRodney W. Grimes 2954b88c807SRodney W. Grimes STATIC union node * 2964b88c807SRodney W. Grimes command() { 2974b88c807SRodney W. Grimes union node *n1, *n2; 2984b88c807SRodney W. Grimes union node *ap, **app; 2994b88c807SRodney W. Grimes union node *cp, **cpp; 3004b88c807SRodney W. Grimes union node *redir, **rpp; 3017920a31dSSteve Price int t; 3024b88c807SRodney W. Grimes 3034b88c807SRodney W. Grimes checkkwd = 2; 304aa9caaf6SPeter Wemm redir = NULL; 305aa9caaf6SPeter Wemm n1 = NULL; 3064b88c807SRodney W. Grimes rpp = &redir; 307ab0a2172SSteve Price 3084b88c807SRodney W. Grimes /* Check for redirection which may precede command */ 3094b88c807SRodney W. Grimes while (readtoken() == TREDIR) { 3104b88c807SRodney W. Grimes *rpp = n2 = redirnode; 3114b88c807SRodney W. Grimes rpp = &n2->nfile.next; 3124b88c807SRodney W. Grimes parsefname(); 3134b88c807SRodney W. Grimes } 3144b88c807SRodney W. Grimes tokpushback++; 3154b88c807SRodney W. Grimes 3164b88c807SRodney W. Grimes switch (readtoken()) { 3174b88c807SRodney W. Grimes case TIF: 3184b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nif)); 3194b88c807SRodney W. Grimes n1->type = NIF; 3204b88c807SRodney W. Grimes n1->nif.test = list(0); 3214b88c807SRodney W. Grimes if (readtoken() != TTHEN) 3224b88c807SRodney W. Grimes synexpect(TTHEN); 3234b88c807SRodney W. Grimes n1->nif.ifpart = list(0); 3244b88c807SRodney W. Grimes n2 = n1; 3254b88c807SRodney W. Grimes while (readtoken() == TELIF) { 3264b88c807SRodney W. Grimes n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 3274b88c807SRodney W. Grimes n2 = n2->nif.elsepart; 3284b88c807SRodney W. Grimes n2->type = NIF; 3294b88c807SRodney W. Grimes n2->nif.test = list(0); 3304b88c807SRodney W. Grimes if (readtoken() != TTHEN) 3314b88c807SRodney W. Grimes synexpect(TTHEN); 3324b88c807SRodney W. Grimes n2->nif.ifpart = list(0); 3334b88c807SRodney W. Grimes } 3344b88c807SRodney W. Grimes if (lasttoken == TELSE) 3354b88c807SRodney W. Grimes n2->nif.elsepart = list(0); 3364b88c807SRodney W. Grimes else { 3374b88c807SRodney W. Grimes n2->nif.elsepart = NULL; 3384b88c807SRodney W. Grimes tokpushback++; 3394b88c807SRodney W. Grimes } 3404b88c807SRodney W. Grimes if (readtoken() != TFI) 3414b88c807SRodney W. Grimes synexpect(TFI); 3424b88c807SRodney W. Grimes checkkwd = 1; 3434b88c807SRodney W. Grimes break; 3444b88c807SRodney W. Grimes case TWHILE: 3454b88c807SRodney W. Grimes case TUNTIL: { 3464b88c807SRodney W. Grimes int got; 3474b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nbinary)); 3484b88c807SRodney W. Grimes n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 3494b88c807SRodney W. Grimes n1->nbinary.ch1 = list(0); 3504b88c807SRodney W. Grimes if ((got=readtoken()) != TDO) { 3514b88c807SRodney W. Grimes TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 3524b88c807SRodney W. Grimes synexpect(TDO); 3534b88c807SRodney W. Grimes } 3544b88c807SRodney W. Grimes n1->nbinary.ch2 = list(0); 3554b88c807SRodney W. Grimes if (readtoken() != TDONE) 3564b88c807SRodney W. Grimes synexpect(TDONE); 3574b88c807SRodney W. Grimes checkkwd = 1; 3584b88c807SRodney W. Grimes break; 3594b88c807SRodney W. Grimes } 3604b88c807SRodney W. Grimes case TFOR: 3614b88c807SRodney W. Grimes if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 3624b88c807SRodney W. Grimes synerror("Bad for loop variable"); 3634b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nfor)); 3644b88c807SRodney W. Grimes n1->type = NFOR; 3654b88c807SRodney W. Grimes n1->nfor.var = wordtext; 3664b88c807SRodney W. Grimes if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 3674b88c807SRodney W. Grimes app = ≈ 3684b88c807SRodney W. Grimes while (readtoken() == TWORD) { 3694b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct narg)); 3704b88c807SRodney W. Grimes n2->type = NARG; 3714b88c807SRodney W. Grimes n2->narg.text = wordtext; 3724b88c807SRodney W. Grimes n2->narg.backquote = backquotelist; 3734b88c807SRodney W. Grimes *app = n2; 3744b88c807SRodney W. Grimes app = &n2->narg.next; 3754b88c807SRodney W. Grimes } 3764b88c807SRodney W. Grimes *app = NULL; 3774b88c807SRodney W. Grimes n1->nfor.args = ap; 3784b88c807SRodney W. Grimes if (lasttoken != TNL && lasttoken != TSEMI) 3794b88c807SRodney W. Grimes synexpect(-1); 3804b88c807SRodney W. Grimes } else { 3814b88c807SRodney W. Grimes #ifndef GDB_HACK 3824b88c807SRodney W. Grimes static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 3834b88c807SRodney W. Grimes '@', '=', '\0'}; 3844b88c807SRodney W. Grimes #endif 3854b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct narg)); 3864b88c807SRodney W. Grimes n2->type = NARG; 3874b88c807SRodney W. Grimes n2->narg.text = (char *)argvars; 3884b88c807SRodney W. Grimes n2->narg.backquote = NULL; 3894b88c807SRodney W. Grimes n2->narg.next = NULL; 3904b88c807SRodney W. Grimes n1->nfor.args = n2; 3914b88c807SRodney W. Grimes /* 3924b88c807SRodney W. Grimes * Newline or semicolon here is optional (but note 3934b88c807SRodney W. Grimes * that the original Bourne shell only allowed NL). 3944b88c807SRodney W. Grimes */ 3954b88c807SRodney W. Grimes if (lasttoken != TNL && lasttoken != TSEMI) 3964b88c807SRodney W. Grimes tokpushback++; 3974b88c807SRodney W. Grimes } 3984b88c807SRodney W. Grimes checkkwd = 2; 3994b88c807SRodney W. Grimes if ((t = readtoken()) == TDO) 4004b88c807SRodney W. Grimes t = TDONE; 4014b88c807SRodney W. Grimes else if (t == TBEGIN) 4024b88c807SRodney W. Grimes t = TEND; 4034b88c807SRodney W. Grimes else 4044b88c807SRodney W. Grimes synexpect(-1); 4054b88c807SRodney W. Grimes n1->nfor.body = list(0); 4064b88c807SRodney W. Grimes if (readtoken() != t) 4074b88c807SRodney W. Grimes synexpect(t); 4084b88c807SRodney W. Grimes checkkwd = 1; 4094b88c807SRodney W. Grimes break; 4104b88c807SRodney W. Grimes case TCASE: 4114b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct ncase)); 4124b88c807SRodney W. Grimes n1->type = NCASE; 4134b88c807SRodney W. Grimes if (readtoken() != TWORD) 4144b88c807SRodney W. Grimes synexpect(TWORD); 4154b88c807SRodney W. Grimes n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 4164b88c807SRodney W. Grimes n2->type = NARG; 4174b88c807SRodney W. Grimes n2->narg.text = wordtext; 4184b88c807SRodney W. Grimes n2->narg.backquote = backquotelist; 4194b88c807SRodney W. Grimes n2->narg.next = NULL; 4204b88c807SRodney W. Grimes while (readtoken() == TNL); 4214b88c807SRodney W. Grimes if (lasttoken != TWORD || ! equal(wordtext, "in")) 4224b88c807SRodney W. Grimes synerror("expecting \"in\""); 4234b88c807SRodney W. Grimes cpp = &n1->ncase.cases; 4244417f629SPeter Wemm noaliases = 1; /* turn off alias expansion */ 425650488feSSean Eric Fagan checkkwd = 2, readtoken(); 426650488feSSean Eric Fagan do { 4274b88c807SRodney W. Grimes *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 4284b88c807SRodney W. Grimes cp->type = NCLIST; 4294b88c807SRodney W. Grimes app = &cp->nclist.pattern; 4304b88c807SRodney W. Grimes for (;;) { 4314b88c807SRodney W. Grimes *app = ap = (union node *)stalloc(sizeof (struct narg)); 4324b88c807SRodney W. Grimes ap->type = NARG; 4334b88c807SRodney W. Grimes ap->narg.text = wordtext; 4344b88c807SRodney W. Grimes ap->narg.backquote = backquotelist; 435650488feSSean Eric Fagan if (checkkwd = 2, readtoken() != TPIPE) 4364b88c807SRodney W. Grimes break; 4374b88c807SRodney W. Grimes app = &ap->narg.next; 438650488feSSean Eric Fagan readtoken(); 4394b88c807SRodney W. Grimes } 4404b88c807SRodney W. Grimes ap->narg.next = NULL; 4414b88c807SRodney W. Grimes if (lasttoken != TRP) 4424417f629SPeter Wemm noaliases = 0, synexpect(TRP); 4434b88c807SRodney W. Grimes cp->nclist.body = list(0); 444650488feSSean Eric Fagan 445650488feSSean Eric Fagan checkkwd = 2; 446650488feSSean Eric Fagan if ((t = readtoken()) != TESAC) { 447650488feSSean Eric Fagan if (t != TENDCASE) 4484417f629SPeter Wemm noaliases = 0, synexpect(TENDCASE); 449650488feSSean Eric Fagan else 450650488feSSean Eric Fagan checkkwd = 2, readtoken(); 4514b88c807SRodney W. Grimes } 452650488feSSean Eric Fagan cpp = &cp->nclist.next; 453650488feSSean Eric Fagan } while(lasttoken != TESAC); 4544417f629SPeter Wemm noaliases = 0; /* reset alias expansion */ 4554b88c807SRodney W. Grimes *cpp = NULL; 4564b88c807SRodney W. Grimes checkkwd = 1; 4574b88c807SRodney W. Grimes break; 4584b88c807SRodney W. Grimes case TLP: 4594b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nredir)); 4604b88c807SRodney W. Grimes n1->type = NSUBSHELL; 4614b88c807SRodney W. Grimes n1->nredir.n = list(0); 4624b88c807SRodney W. Grimes n1->nredir.redirect = NULL; 4634b88c807SRodney W. Grimes if (readtoken() != TRP) 4644b88c807SRodney W. Grimes synexpect(TRP); 4654b88c807SRodney W. Grimes checkkwd = 1; 4664b88c807SRodney W. Grimes break; 4674b88c807SRodney W. Grimes case TBEGIN: 4684b88c807SRodney W. Grimes n1 = list(0); 4694b88c807SRodney W. Grimes if (readtoken() != TEND) 4704b88c807SRodney W. Grimes synexpect(TEND); 4714b88c807SRodney W. Grimes checkkwd = 1; 4724b88c807SRodney W. Grimes break; 4734b88c807SRodney W. Grimes /* Handle an empty command like other simple commands. */ 474248ffae5SJoerg Wunsch case TSEMI: 475aa9caaf6SPeter Wemm /* 476aa9caaf6SPeter Wemm * An empty command before a ; doesn't make much sense, and 477aa9caaf6SPeter Wemm * should certainly be disallowed in the case of `if ;'. 478aa9caaf6SPeter Wemm */ 479aa9caaf6SPeter Wemm if (!redir) 480aa9caaf6SPeter Wemm synexpect(-1); 481ab0a2172SSteve Price case TAND: 482ab0a2172SSteve Price case TOR: 483aa9caaf6SPeter Wemm case TNL: 484248ffae5SJoerg Wunsch case TEOF: 4854b88c807SRodney W. Grimes case TWORD: 486aa9caaf6SPeter Wemm case TRP: 4874b88c807SRodney W. Grimes tokpushback++; 4887920a31dSSteve Price return simplecmd(rpp, redir); 4894b88c807SRodney W. Grimes default: 4904b88c807SRodney W. Grimes synexpect(-1); 4914b88c807SRodney W. Grimes } 4924b88c807SRodney W. Grimes 4934b88c807SRodney W. Grimes /* Now check for redirection which may follow command */ 4944b88c807SRodney W. Grimes while (readtoken() == TREDIR) { 4954b88c807SRodney W. Grimes *rpp = n2 = redirnode; 4964b88c807SRodney W. Grimes rpp = &n2->nfile.next; 4974b88c807SRodney W. Grimes parsefname(); 4984b88c807SRodney W. Grimes } 4994b88c807SRodney W. Grimes tokpushback++; 5004b88c807SRodney W. Grimes *rpp = NULL; 5014b88c807SRodney W. Grimes if (redir) { 5024b88c807SRodney W. Grimes if (n1->type != NSUBSHELL) { 5034b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct nredir)); 5044b88c807SRodney W. Grimes n2->type = NREDIR; 5054b88c807SRodney W. Grimes n2->nredir.n = n1; 5064b88c807SRodney W. Grimes n1 = n2; 5074b88c807SRodney W. Grimes } 5084b88c807SRodney W. Grimes n1->nredir.redirect = redir; 5094b88c807SRodney W. Grimes } 5104b88c807SRodney W. Grimes return n1; 5114b88c807SRodney W. Grimes } 5124b88c807SRodney W. Grimes 5134b88c807SRodney W. Grimes 5144b88c807SRodney W. Grimes STATIC union node * 5154b88c807SRodney W. Grimes simplecmd(rpp, redir) 5164b88c807SRodney W. Grimes union node **rpp, *redir; 5174b88c807SRodney W. Grimes { 5184b88c807SRodney W. Grimes union node *args, **app; 5194b88c807SRodney W. Grimes union node **orig_rpp = rpp; 5207920a31dSSteve Price union node *n = NULL; 5214b88c807SRodney W. Grimes 5224b88c807SRodney W. Grimes /* If we don't have any redirections already, then we must reset */ 5234b88c807SRodney W. Grimes /* rpp to be the address of the local redir variable. */ 5244b88c807SRodney W. Grimes if (redir == 0) 5254b88c807SRodney W. Grimes rpp = &redir; 5264b88c807SRodney W. Grimes 5274b88c807SRodney W. Grimes args = NULL; 5284b88c807SRodney W. Grimes app = &args; 5294b88c807SRodney W. Grimes /* 5304b88c807SRodney W. Grimes * We save the incoming value, because we need this for shell 5314b88c807SRodney W. Grimes * functions. There can not be a redirect or an argument between 5324b88c807SRodney W. Grimes * the function name and the open parenthesis. 5334b88c807SRodney W. Grimes */ 5344b88c807SRodney W. Grimes orig_rpp = rpp; 5354b88c807SRodney W. Grimes 5364b88c807SRodney W. Grimes for (;;) { 5374b88c807SRodney W. Grimes if (readtoken() == TWORD) { 5384b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct narg)); 5394b88c807SRodney W. Grimes n->type = NARG; 5404b88c807SRodney W. Grimes n->narg.text = wordtext; 5414b88c807SRodney W. Grimes n->narg.backquote = backquotelist; 5424b88c807SRodney W. Grimes *app = n; 5434b88c807SRodney W. Grimes app = &n->narg.next; 5444b88c807SRodney W. Grimes } else if (lasttoken == TREDIR) { 5454b88c807SRodney W. Grimes *rpp = n = redirnode; 5464b88c807SRodney W. Grimes rpp = &n->nfile.next; 5474b88c807SRodney W. Grimes parsefname(); /* read name of redirection file */ 5484b88c807SRodney W. Grimes } else if (lasttoken == TLP && app == &args->narg.next 5494b88c807SRodney W. Grimes && rpp == orig_rpp) { 5504b88c807SRodney W. Grimes /* We have a function */ 5514b88c807SRodney W. Grimes if (readtoken() != TRP) 5524b88c807SRodney W. Grimes synexpect(TRP); 5534b88c807SRodney W. Grimes #ifdef notdef 5544b88c807SRodney W. Grimes if (! goodname(n->narg.text)) 5554b88c807SRodney W. Grimes synerror("Bad function name"); 5564b88c807SRodney W. Grimes #endif 5574b88c807SRodney W. Grimes n->type = NDEFUN; 5584b88c807SRodney W. Grimes n->narg.next = command(); 5597920a31dSSteve Price return n; 5604b88c807SRodney W. Grimes } else { 5614b88c807SRodney W. Grimes tokpushback++; 5624b88c807SRodney W. Grimes break; 5634b88c807SRodney W. Grimes } 5644b88c807SRodney W. Grimes } 5654b88c807SRodney W. Grimes *app = NULL; 5664b88c807SRodney W. Grimes *rpp = NULL; 5674b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct ncmd)); 5684b88c807SRodney W. Grimes n->type = NCMD; 5694b88c807SRodney W. Grimes n->ncmd.backgnd = 0; 5704b88c807SRodney W. Grimes n->ncmd.args = args; 5714b88c807SRodney W. Grimes n->ncmd.redirect = redir; 5724b88c807SRodney W. Grimes return n; 5734b88c807SRodney W. Grimes } 5744b88c807SRodney W. Grimes 575aa9caaf6SPeter Wemm STATIC union node * 576aa9caaf6SPeter Wemm makename() { 577aa9caaf6SPeter Wemm union node *n; 578aa9caaf6SPeter Wemm 579aa9caaf6SPeter Wemm n = (union node *)stalloc(sizeof (struct narg)); 580aa9caaf6SPeter Wemm n->type = NARG; 581aa9caaf6SPeter Wemm n->narg.next = NULL; 582aa9caaf6SPeter Wemm n->narg.text = wordtext; 583aa9caaf6SPeter Wemm n->narg.backquote = backquotelist; 584aa9caaf6SPeter Wemm return n; 585aa9caaf6SPeter Wemm } 586aa9caaf6SPeter Wemm 587aa9caaf6SPeter Wemm void fixredir(n, text, err) 588aa9caaf6SPeter Wemm union node *n; 589aa9caaf6SPeter Wemm const char *text; 590aa9caaf6SPeter Wemm int err; 591aa9caaf6SPeter Wemm { 592aa9caaf6SPeter Wemm TRACE(("Fix redir %s %d\n", text, err)); 593aa9caaf6SPeter Wemm if (!err) 594aa9caaf6SPeter Wemm n->ndup.vname = NULL; 595aa9caaf6SPeter Wemm 596aa9caaf6SPeter Wemm if (is_digit(text[0]) && text[1] == '\0') 597aa9caaf6SPeter Wemm n->ndup.dupfd = digit_val(text[0]); 598aa9caaf6SPeter Wemm else if (text[0] == '-' && text[1] == '\0') 599aa9caaf6SPeter Wemm n->ndup.dupfd = -1; 600aa9caaf6SPeter Wemm else { 601aa9caaf6SPeter Wemm 602aa9caaf6SPeter Wemm if (err) 603aa9caaf6SPeter Wemm synerror("Bad fd number"); 604aa9caaf6SPeter Wemm else 605aa9caaf6SPeter Wemm n->ndup.vname = makename(); 606aa9caaf6SPeter Wemm } 607aa9caaf6SPeter Wemm } 608aa9caaf6SPeter Wemm 6094b88c807SRodney W. Grimes 6104b88c807SRodney W. Grimes STATIC void 6114b88c807SRodney W. Grimes parsefname() { 6124b88c807SRodney W. Grimes union node *n = redirnode; 6134b88c807SRodney W. Grimes 6144b88c807SRodney W. Grimes if (readtoken() != TWORD) 6154b88c807SRodney W. Grimes synexpect(-1); 6164b88c807SRodney W. Grimes if (n->type == NHERE) { 6174b88c807SRodney W. Grimes struct heredoc *here = heredoc; 6184b88c807SRodney W. Grimes struct heredoc *p; 6194b88c807SRodney W. Grimes int i; 6204b88c807SRodney W. Grimes 6214b88c807SRodney W. Grimes if (quoteflag == 0) 6224b88c807SRodney W. Grimes n->type = NXHERE; 6234b88c807SRodney W. Grimes TRACE(("Here document %d\n", n->type)); 6244b88c807SRodney W. Grimes if (here->striptabs) { 6254b88c807SRodney W. Grimes while (*wordtext == '\t') 6264b88c807SRodney W. Grimes wordtext++; 6274b88c807SRodney W. Grimes } 6284b88c807SRodney W. Grimes if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 6294b88c807SRodney W. Grimes synerror("Illegal eof marker for << redirection"); 6304b88c807SRodney W. Grimes rmescapes(wordtext); 6314b88c807SRodney W. Grimes here->eofmark = wordtext; 6324b88c807SRodney W. Grimes here->next = NULL; 6334b88c807SRodney W. Grimes if (heredoclist == NULL) 6344b88c807SRodney W. Grimes heredoclist = here; 6354b88c807SRodney W. Grimes else { 6364b88c807SRodney W. Grimes for (p = heredoclist ; p->next ; p = p->next); 6374b88c807SRodney W. Grimes p->next = here; 6384b88c807SRodney W. Grimes } 6394b88c807SRodney W. Grimes } else if (n->type == NTOFD || n->type == NFROMFD) { 640aa9caaf6SPeter Wemm fixredir(n, wordtext, 0); 6414b88c807SRodney W. Grimes } else { 642aa9caaf6SPeter Wemm n->nfile.fname = makename(); 6434b88c807SRodney W. Grimes } 6444b88c807SRodney W. Grimes } 6454b88c807SRodney W. Grimes 6464b88c807SRodney W. Grimes 6474b88c807SRodney W. Grimes /* 6484b88c807SRodney W. Grimes * Input any here documents. 6494b88c807SRodney W. Grimes */ 6504b88c807SRodney W. Grimes 6514b88c807SRodney W. Grimes STATIC void 6524b88c807SRodney W. Grimes parseheredoc() { 6534b88c807SRodney W. Grimes struct heredoc *here; 6544b88c807SRodney W. Grimes union node *n; 6554b88c807SRodney W. Grimes 6564b88c807SRodney W. Grimes while (heredoclist) { 6574b88c807SRodney W. Grimes here = heredoclist; 6584b88c807SRodney W. Grimes heredoclist = here->next; 6594b88c807SRodney W. Grimes if (needprompt) { 6604b88c807SRodney W. Grimes setprompt(2); 6614b88c807SRodney W. Grimes needprompt = 0; 6624b88c807SRodney W. Grimes } 6634b88c807SRodney W. Grimes readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 6644b88c807SRodney W. Grimes here->eofmark, here->striptabs); 6654b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct narg)); 6664b88c807SRodney W. Grimes n->narg.type = NARG; 6674b88c807SRodney W. Grimes n->narg.next = NULL; 6684b88c807SRodney W. Grimes n->narg.text = wordtext; 6694b88c807SRodney W. Grimes n->narg.backquote = backquotelist; 6704b88c807SRodney W. Grimes here->here->nhere.doc = n; 6714b88c807SRodney W. Grimes } 6724b88c807SRodney W. Grimes } 6734b88c807SRodney W. Grimes 6744b88c807SRodney W. Grimes STATIC int 6754b88c807SRodney W. Grimes peektoken() { 6764b88c807SRodney W. Grimes int t; 6774b88c807SRodney W. Grimes 6784b88c807SRodney W. Grimes t = readtoken(); 6794b88c807SRodney W. Grimes tokpushback++; 6804b88c807SRodney W. Grimes return (t); 6814b88c807SRodney W. Grimes } 6824b88c807SRodney W. Grimes 6834b88c807SRodney W. Grimes STATIC int 6844b88c807SRodney W. Grimes readtoken() { 6854b88c807SRodney W. Grimes int t; 6864b88c807SRodney W. Grimes int savecheckkwd = checkkwd; 6874b88c807SRodney W. Grimes struct alias *ap; 6884b88c807SRodney W. Grimes #ifdef DEBUG 6894b88c807SRodney W. Grimes int alreadyseen = tokpushback; 6904b88c807SRodney W. Grimes #endif 6914b88c807SRodney W. Grimes 6924b88c807SRodney W. Grimes top: 6934b88c807SRodney W. Grimes t = xxreadtoken(); 6944b88c807SRodney W. Grimes 6954b88c807SRodney W. Grimes if (checkkwd) { 6964b88c807SRodney W. Grimes /* 6974b88c807SRodney W. Grimes * eat newlines 6984b88c807SRodney W. Grimes */ 6994b88c807SRodney W. Grimes if (checkkwd == 2) { 7004b88c807SRodney W. Grimes checkkwd = 0; 7014b88c807SRodney W. Grimes while (t == TNL) { 7024b88c807SRodney W. Grimes parseheredoc(); 7034b88c807SRodney W. Grimes t = xxreadtoken(); 7044b88c807SRodney W. Grimes } 7054b88c807SRodney W. Grimes } else 7064b88c807SRodney W. Grimes checkkwd = 0; 7074b88c807SRodney W. Grimes /* 7084b88c807SRodney W. Grimes * check for keywords and aliases 7094b88c807SRodney W. Grimes */ 710aa9caaf6SPeter Wemm if (t == TWORD && !quoteflag) 711aa9caaf6SPeter Wemm { 7127920a31dSSteve Price char * const *pp; 7134b88c807SRodney W. Grimes 7144b88c807SRodney W. Grimes for (pp = (char **)parsekwd; *pp; pp++) { 715aa9caaf6SPeter Wemm if (**pp == *wordtext && equal(*pp, wordtext)) 716aa9caaf6SPeter Wemm { 7174b88c807SRodney W. Grimes lasttoken = t = pp - parsekwd + KWDOFFSET; 7184b88c807SRodney W. Grimes TRACE(("keyword %s recognized\n", tokname[t])); 7194b88c807SRodney W. Grimes goto out; 7204b88c807SRodney W. Grimes } 7214b88c807SRodney W. Grimes } 7224417f629SPeter Wemm if (noaliases == 0 && 7234417f629SPeter Wemm (ap = lookupalias(wordtext, 1)) != NULL) { 7244b88c807SRodney W. Grimes pushstring(ap->val, strlen(ap->val), ap); 7254b88c807SRodney W. Grimes checkkwd = savecheckkwd; 7264b88c807SRodney W. Grimes goto top; 7274b88c807SRodney W. Grimes } 7284b88c807SRodney W. Grimes } 7294b88c807SRodney W. Grimes out: 7307920a31dSSteve Price checkkwd = 0; 7314b88c807SRodney W. Grimes } 7324b88c807SRodney W. Grimes #ifdef DEBUG 7334b88c807SRodney W. Grimes if (!alreadyseen) 7344b88c807SRodney W. Grimes TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 7354b88c807SRodney W. Grimes else 7364b88c807SRodney W. Grimes TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 7374b88c807SRodney W. Grimes #endif 7384b88c807SRodney W. Grimes return (t); 7394b88c807SRodney W. Grimes } 7404b88c807SRodney W. Grimes 7414b88c807SRodney W. Grimes 7424b88c807SRodney W. Grimes /* 7434b88c807SRodney W. Grimes * Read the next input token. 7444b88c807SRodney W. Grimes * If the token is a word, we set backquotelist to the list of cmds in 7454b88c807SRodney W. Grimes * backquotes. We set quoteflag to true if any part of the word was 7464b88c807SRodney W. Grimes * quoted. 7474b88c807SRodney W. Grimes * If the token is TREDIR, then we set redirnode to a structure containing 7484b88c807SRodney W. Grimes * the redirection. 7494b88c807SRodney W. Grimes * In all cases, the variable startlinno is set to the number of the line 7504b88c807SRodney W. Grimes * on which the token starts. 7514b88c807SRodney W. Grimes * 7524b88c807SRodney W. Grimes * [Change comment: here documents and internal procedures] 7534b88c807SRodney W. Grimes * [Readtoken shouldn't have any arguments. Perhaps we should make the 7544b88c807SRodney W. Grimes * word parsing code into a separate routine. In this case, readtoken 7554b88c807SRodney W. Grimes * doesn't need to have any internal procedures, but parseword does. 7564b88c807SRodney W. Grimes * We could also make parseoperator in essence the main routine, and 7574b88c807SRodney W. Grimes * have parseword (readtoken1?) handle both words and redirection.] 7584b88c807SRodney W. Grimes */ 7594b88c807SRodney W. Grimes 7604b88c807SRodney W. Grimes #define RETURN(token) return lasttoken = token 7614b88c807SRodney W. Grimes 7624b88c807SRodney W. Grimes STATIC int 7634b88c807SRodney W. Grimes xxreadtoken() { 7647920a31dSSteve Price int c; 7654b88c807SRodney W. Grimes 7664b88c807SRodney W. Grimes if (tokpushback) { 7674b88c807SRodney W. Grimes tokpushback = 0; 7684b88c807SRodney W. Grimes return lasttoken; 7694b88c807SRodney W. Grimes } 7704b88c807SRodney W. Grimes if (needprompt) { 7714b88c807SRodney W. Grimes setprompt(2); 7724b88c807SRodney W. Grimes needprompt = 0; 7734b88c807SRodney W. Grimes } 7744b88c807SRodney W. Grimes startlinno = plinno; 7754b88c807SRodney W. Grimes for (;;) { /* until token or start of word found */ 7764b88c807SRodney W. Grimes c = pgetc_macro(); 7774b88c807SRodney W. Grimes if (c == ' ' || c == '\t') 7784b88c807SRodney W. Grimes continue; /* quick check for white space first */ 7794b88c807SRodney W. Grimes switch (c) { 7804b88c807SRodney W. Grimes case ' ': case '\t': 7814b88c807SRodney W. Grimes continue; 7824b88c807SRodney W. Grimes case '#': 7834b88c807SRodney W. Grimes while ((c = pgetc()) != '\n' && c != PEOF); 7844b88c807SRodney W. Grimes pungetc(); 7854b88c807SRodney W. Grimes continue; 7864b88c807SRodney W. Grimes case '\\': 7874b88c807SRodney W. Grimes if (pgetc() == '\n') { 7884b88c807SRodney W. Grimes startlinno = ++plinno; 7894b88c807SRodney W. Grimes if (doprompt) 7904b88c807SRodney W. Grimes setprompt(2); 7914b88c807SRodney W. Grimes else 7924b88c807SRodney W. Grimes setprompt(0); 7934b88c807SRodney W. Grimes continue; 7944b88c807SRodney W. Grimes } 7954b88c807SRodney W. Grimes pungetc(); 7964b88c807SRodney W. Grimes goto breakloop; 7974b88c807SRodney W. Grimes case '\n': 7984b88c807SRodney W. Grimes plinno++; 7994b88c807SRodney W. Grimes needprompt = doprompt; 8004b88c807SRodney W. Grimes RETURN(TNL); 8014b88c807SRodney W. Grimes case PEOF: 8024b88c807SRodney W. Grimes RETURN(TEOF); 8034b88c807SRodney W. Grimes case '&': 8044b88c807SRodney W. Grimes if (pgetc() == '&') 8054b88c807SRodney W. Grimes RETURN(TAND); 8064b88c807SRodney W. Grimes pungetc(); 8074b88c807SRodney W. Grimes RETURN(TBACKGND); 8084b88c807SRodney W. Grimes case '|': 8094b88c807SRodney W. Grimes if (pgetc() == '|') 8104b88c807SRodney W. Grimes RETURN(TOR); 8114b88c807SRodney W. Grimes pungetc(); 8124b88c807SRodney W. Grimes RETURN(TPIPE); 8134b88c807SRodney W. Grimes case ';': 8144b88c807SRodney W. Grimes if (pgetc() == ';') 8154b88c807SRodney W. Grimes RETURN(TENDCASE); 8164b88c807SRodney W. Grimes pungetc(); 8174b88c807SRodney W. Grimes RETURN(TSEMI); 8184b88c807SRodney W. Grimes case '(': 8194b88c807SRodney W. Grimes RETURN(TLP); 8204b88c807SRodney W. Grimes case ')': 8214b88c807SRodney W. Grimes RETURN(TRP); 8224b88c807SRodney W. Grimes default: 8234b88c807SRodney W. Grimes goto breakloop; 8244b88c807SRodney W. Grimes } 8254b88c807SRodney W. Grimes } 8264b88c807SRodney W. Grimes breakloop: 8274b88c807SRodney W. Grimes return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 8284b88c807SRodney W. Grimes #undef RETURN 8294b88c807SRodney W. Grimes } 8304b88c807SRodney W. Grimes 8314b88c807SRodney W. Grimes 8324b88c807SRodney W. Grimes 8334b88c807SRodney W. Grimes /* 8344b88c807SRodney W. Grimes * If eofmark is NULL, read a word or a redirection symbol. If eofmark 8354b88c807SRodney W. Grimes * is not NULL, read a here document. In the latter case, eofmark is the 8364b88c807SRodney W. Grimes * word which marks the end of the document and striptabs is true if 8374b88c807SRodney W. Grimes * leading tabs should be stripped from the document. The argument firstc 8384b88c807SRodney W. Grimes * is the first character of the input token or document. 8394b88c807SRodney W. Grimes * 8404b88c807SRodney W. Grimes * Because C does not have internal subroutines, I have simulated them 8414b88c807SRodney W. Grimes * using goto's to implement the subroutine linkage. The following macros 8424b88c807SRodney W. Grimes * will run code that appears at the end of readtoken1. 8434b88c807SRodney W. Grimes */ 8444b88c807SRodney W. Grimes 8454b88c807SRodney W. Grimes #define CHECKEND() {goto checkend; checkend_return:;} 8464b88c807SRodney W. Grimes #define PARSEREDIR() {goto parseredir; parseredir_return:;} 8474b88c807SRodney W. Grimes #define PARSESUB() {goto parsesub; parsesub_return:;} 8484b88c807SRodney W. Grimes #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 8494b88c807SRodney W. Grimes #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 8504b88c807SRodney W. Grimes #define PARSEARITH() {goto parsearith; parsearith_return:;} 8514b88c807SRodney W. Grimes 8524b88c807SRodney W. Grimes STATIC int 8534b88c807SRodney W. Grimes readtoken1(firstc, syntax, eofmark, striptabs) 8544b88c807SRodney W. Grimes int firstc; 8554b88c807SRodney W. Grimes char const *syntax; 8564b88c807SRodney W. Grimes char *eofmark; 8574b88c807SRodney W. Grimes int striptabs; 8584b88c807SRodney W. Grimes { 859aa9caaf6SPeter Wemm int c = firstc; 860aa9caaf6SPeter Wemm char *out; 8614b88c807SRodney W. Grimes int len; 8624b88c807SRodney W. Grimes char line[EOFMARKLEN + 1]; 8634b88c807SRodney W. Grimes struct nodelist *bqlist; 8644b88c807SRodney W. Grimes int quotef; 8654b88c807SRodney W. Grimes int dblquote; 8664b88c807SRodney W. Grimes int varnest; /* levels of variables expansion */ 8674b88c807SRodney W. Grimes int arinest; /* levels of arithmetic expansion */ 8684b88c807SRodney W. Grimes int parenlevel; /* levels of parens in arithmetic */ 8694b88c807SRodney W. Grimes int oldstyle; 8704b88c807SRodney W. Grimes char const *prevsyntax; /* syntax before arithmetic */ 8712dde9ce3SMartin Cracauer int synentry; 872aa9caaf6SPeter Wemm #if __GNUC__ 873aa9caaf6SPeter Wemm /* Avoid longjmp clobbering */ 874aa9caaf6SPeter Wemm (void) &out; 875aa9caaf6SPeter Wemm (void) "ef; 876aa9caaf6SPeter Wemm (void) &dblquote; 877aa9caaf6SPeter Wemm (void) &varnest; 878aa9caaf6SPeter Wemm (void) &arinest; 879aa9caaf6SPeter Wemm (void) &parenlevel; 880aa9caaf6SPeter Wemm (void) &oldstyle; 881aa9caaf6SPeter Wemm (void) &prevsyntax; 882aa9caaf6SPeter Wemm (void) &syntax; 8832dde9ce3SMartin Cracauer (void) &synentry; 884aa9caaf6SPeter Wemm #endif 8854b88c807SRodney W. Grimes 8864b88c807SRodney W. Grimes startlinno = plinno; 8874b88c807SRodney W. Grimes dblquote = 0; 8884b88c807SRodney W. Grimes if (syntax == DQSYNTAX) 8894b88c807SRodney W. Grimes dblquote = 1; 8904b88c807SRodney W. Grimes quotef = 0; 8914b88c807SRodney W. Grimes bqlist = NULL; 8924b88c807SRodney W. Grimes varnest = 0; 8934b88c807SRodney W. Grimes arinest = 0; 8944b88c807SRodney W. Grimes parenlevel = 0; 8954b88c807SRodney W. Grimes 8964b88c807SRodney W. Grimes STARTSTACKSTR(out); 8974b88c807SRodney W. Grimes loop: { /* for each line, until end of word */ 8984b88c807SRodney W. Grimes #if ATTY 8994b88c807SRodney W. Grimes if (c == '\034' && doprompt 9004b88c807SRodney W. Grimes && attyset() && ! equal(termval(), "emacs")) { 9014b88c807SRodney W. Grimes attyline(); 9024b88c807SRodney W. Grimes if (syntax == BASESYNTAX) 9034b88c807SRodney W. Grimes return readtoken(); 9044b88c807SRodney W. Grimes c = pgetc(); 9054b88c807SRodney W. Grimes goto loop; 9064b88c807SRodney W. Grimes } 9074b88c807SRodney W. Grimes #endif 9084b88c807SRodney W. Grimes CHECKEND(); /* set c to PEOF if at end of here document */ 9094b88c807SRodney W. Grimes for (;;) { /* until end of line or end of word */ 9104b88c807SRodney W. Grimes CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 9112dde9ce3SMartin Cracauer 9122dde9ce3SMartin Cracauer synentry = syntax[c]; 9132dde9ce3SMartin Cracauer 9142dde9ce3SMartin Cracauer switch(synentry) { 9154b88c807SRodney W. Grimes case CNL: /* '\n' */ 9164b88c807SRodney W. Grimes if (syntax == BASESYNTAX) 9174b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 9184b88c807SRodney W. Grimes USTPUTC(c, out); 9194b88c807SRodney W. Grimes plinno++; 9204b88c807SRodney W. Grimes if (doprompt) 9214b88c807SRodney W. Grimes setprompt(2); 9224b88c807SRodney W. Grimes else 9234b88c807SRodney W. Grimes setprompt(0); 9244b88c807SRodney W. Grimes c = pgetc(); 9254b88c807SRodney W. Grimes goto loop; /* continue outer loop */ 9264b88c807SRodney W. Grimes case CWORD: 9274b88c807SRodney W. Grimes USTPUTC(c, out); 9284b88c807SRodney W. Grimes break; 9294b88c807SRodney W. Grimes case CCTL: 9304b88c807SRodney W. Grimes if (eofmark == NULL || dblquote) 9314b88c807SRodney W. Grimes USTPUTC(CTLESC, out); 9324b88c807SRodney W. Grimes USTPUTC(c, out); 9334b88c807SRodney W. Grimes break; 9344b88c807SRodney W. Grimes case CBACK: /* backslash */ 9354b88c807SRodney W. Grimes c = pgetc(); 9364b88c807SRodney W. Grimes if (c == PEOF) { 9374b88c807SRodney W. Grimes USTPUTC('\\', out); 9384b88c807SRodney W. Grimes pungetc(); 9394b88c807SRodney W. Grimes } else if (c == '\n') { 9404b88c807SRodney W. Grimes if (doprompt) 9414b88c807SRodney W. Grimes setprompt(2); 9424b88c807SRodney W. Grimes else 9434b88c807SRodney W. Grimes setprompt(0); 9444b88c807SRodney W. Grimes } else { 94573f612b5SMartin Cracauer if (dblquote && c != '\\' && 94673f612b5SMartin Cracauer c != '`' && c != '$' && 94773f612b5SMartin Cracauer (c != '"' || eofmark != NULL)) 9484b88c807SRodney W. Grimes USTPUTC('\\', out); 94973f612b5SMartin Cracauer if (c >= 0 && SQSYNTAX[c] == CCTL) 9504b88c807SRodney W. Grimes USTPUTC(CTLESC, out); 9515557a02aSTor Egge else if (eofmark == NULL) 9526f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9534b88c807SRodney W. Grimes USTPUTC(c, out); 9544b88c807SRodney W. Grimes quotef++; 9554b88c807SRodney W. Grimes } 9564b88c807SRodney W. Grimes break; 9574b88c807SRodney W. Grimes case CSQUOTE: 9585557a02aSTor Egge if (eofmark == NULL) 9596f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9604b88c807SRodney W. Grimes syntax = SQSYNTAX; 9614b88c807SRodney W. Grimes break; 9624b88c807SRodney W. Grimes case CDQUOTE: 9635557a02aSTor Egge if (eofmark == NULL) 9646f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9654b88c807SRodney W. Grimes syntax = DQSYNTAX; 9664b88c807SRodney W. Grimes dblquote = 1; 9674b88c807SRodney W. Grimes break; 9684b88c807SRodney W. Grimes case CENDQUOTE: 9695557a02aSTor Egge if (eofmark != NULL && arinest == 0 && 9705557a02aSTor Egge varnest == 0) { 9714b88c807SRodney W. Grimes USTPUTC(c, out); 9724b88c807SRodney W. Grimes } else { 9735557a02aSTor Egge if (arinest) { 9744b88c807SRodney W. Grimes syntax = ARISYNTAX; 9754b88c807SRodney W. Grimes dblquote = 0; 9765557a02aSTor Egge } else if (eofmark == NULL) { 9775557a02aSTor Egge syntax = BASESYNTAX; 9785557a02aSTor Egge dblquote = 0; 9795557a02aSTor Egge } 9805557a02aSTor Egge quotef++; 9814b88c807SRodney W. Grimes } 9824b88c807SRodney W. Grimes break; 9834b88c807SRodney W. Grimes case CVAR: /* '$' */ 9844b88c807SRodney W. Grimes PARSESUB(); /* parse substitution */ 9854b88c807SRodney W. Grimes break; 9864b88c807SRodney W. Grimes case CENDVAR: /* '}' */ 9874b88c807SRodney W. Grimes if (varnest > 0) { 9884b88c807SRodney W. Grimes varnest--; 9894b88c807SRodney W. Grimes USTPUTC(CTLENDVAR, out); 9904b88c807SRodney W. Grimes } else { 9914b88c807SRodney W. Grimes USTPUTC(c, out); 9924b88c807SRodney W. Grimes } 9934b88c807SRodney W. Grimes break; 9944b88c807SRodney W. Grimes case CLP: /* '(' in arithmetic */ 9954b88c807SRodney W. Grimes parenlevel++; 9964b88c807SRodney W. Grimes USTPUTC(c, out); 9974b88c807SRodney W. Grimes break; 9984b88c807SRodney W. Grimes case CRP: /* ')' in arithmetic */ 9994b88c807SRodney W. Grimes if (parenlevel > 0) { 10004b88c807SRodney W. Grimes USTPUTC(c, out); 10014b88c807SRodney W. Grimes --parenlevel; 10024b88c807SRodney W. Grimes } else { 10034b88c807SRodney W. Grimes if (pgetc() == ')') { 10044b88c807SRodney W. Grimes if (--arinest == 0) { 10054b88c807SRodney W. Grimes USTPUTC(CTLENDARI, out); 10064b88c807SRodney W. Grimes syntax = prevsyntax; 10075557a02aSTor Egge if (syntax == DQSYNTAX) 10085557a02aSTor Egge dblquote = 1; 10095557a02aSTor Egge else 10105557a02aSTor Egge dblquote = 0; 10114b88c807SRodney W. Grimes } else 10124b88c807SRodney W. Grimes USTPUTC(')', out); 10134b88c807SRodney W. Grimes } else { 10144b88c807SRodney W. Grimes /* 10154b88c807SRodney W. Grimes * unbalanced parens 10164b88c807SRodney W. Grimes * (don't 2nd guess - no error) 10174b88c807SRodney W. Grimes */ 10184b88c807SRodney W. Grimes pungetc(); 10194b88c807SRodney W. Grimes USTPUTC(')', out); 10204b88c807SRodney W. Grimes } 10214b88c807SRodney W. Grimes } 10224b88c807SRodney W. Grimes break; 10234b88c807SRodney W. Grimes case CBQUOTE: /* '`' */ 10244b88c807SRodney W. Grimes PARSEBACKQOLD(); 10254b88c807SRodney W. Grimes break; 10264b88c807SRodney W. Grimes case CEOF: 10274b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 10284b88c807SRodney W. Grimes default: 10294b88c807SRodney W. Grimes if (varnest == 0) 10304b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 10314b88c807SRodney W. Grimes USTPUTC(c, out); 10324b88c807SRodney W. Grimes } 10334b88c807SRodney W. Grimes c = pgetc_macro(); 10344b88c807SRodney W. Grimes } 10354b88c807SRodney W. Grimes } 10364b88c807SRodney W. Grimes endword: 10374b88c807SRodney W. Grimes if (syntax == ARISYNTAX) 10384b88c807SRodney W. Grimes synerror("Missing '))'"); 10394b88c807SRodney W. Grimes if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 10404b88c807SRodney W. Grimes synerror("Unterminated quoted string"); 10414b88c807SRodney W. Grimes if (varnest != 0) { 10424b88c807SRodney W. Grimes startlinno = plinno; 10434b88c807SRodney W. Grimes synerror("Missing '}'"); 10444b88c807SRodney W. Grimes } 10454b88c807SRodney W. Grimes USTPUTC('\0', out); 10464b88c807SRodney W. Grimes len = out - stackblock(); 10474b88c807SRodney W. Grimes out = stackblock(); 10484b88c807SRodney W. Grimes if (eofmark == NULL) { 10494b88c807SRodney W. Grimes if ((c == '>' || c == '<') 10504b88c807SRodney W. Grimes && quotef == 0 10514b88c807SRodney W. Grimes && len <= 2 10524b88c807SRodney W. Grimes && (*out == '\0' || is_digit(*out))) { 10534b88c807SRodney W. Grimes PARSEREDIR(); 10544b88c807SRodney W. Grimes return lasttoken = TREDIR; 10554b88c807SRodney W. Grimes } else { 10564b88c807SRodney W. Grimes pungetc(); 10574b88c807SRodney W. Grimes } 10584b88c807SRodney W. Grimes } 10594b88c807SRodney W. Grimes quoteflag = quotef; 10604b88c807SRodney W. Grimes backquotelist = bqlist; 10614b88c807SRodney W. Grimes grabstackblock(len); 10624b88c807SRodney W. Grimes wordtext = out; 10634b88c807SRodney W. Grimes return lasttoken = TWORD; 10644b88c807SRodney W. Grimes /* end of readtoken routine */ 10654b88c807SRodney W. Grimes 10664b88c807SRodney W. Grimes 10674b88c807SRodney W. Grimes 10684b88c807SRodney W. Grimes /* 10694b88c807SRodney W. Grimes * Check to see whether we are at the end of the here document. When this 10704b88c807SRodney W. Grimes * is called, c is set to the first character of the next input line. If 10714b88c807SRodney W. Grimes * we are at the end of the here document, this routine sets the c to PEOF. 10724b88c807SRodney W. Grimes */ 10734b88c807SRodney W. Grimes 10744b88c807SRodney W. Grimes checkend: { 10754b88c807SRodney W. Grimes if (eofmark) { 10764b88c807SRodney W. Grimes if (striptabs) { 10774b88c807SRodney W. Grimes while (c == '\t') 10784b88c807SRodney W. Grimes c = pgetc(); 10794b88c807SRodney W. Grimes } 10804b88c807SRodney W. Grimes if (c == *eofmark) { 10814b88c807SRodney W. Grimes if (pfgets(line, sizeof line) != NULL) { 10827920a31dSSteve Price char *p, *q; 10834b88c807SRodney W. Grimes 10844b88c807SRodney W. Grimes p = line; 10854b88c807SRodney W. Grimes for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 10864b88c807SRodney W. Grimes if (*p == '\n' && *q == '\0') { 10874b88c807SRodney W. Grimes c = PEOF; 10884b88c807SRodney W. Grimes plinno++; 10894b88c807SRodney W. Grimes needprompt = doprompt; 10904b88c807SRodney W. Grimes } else { 10914b88c807SRodney W. Grimes pushstring(line, strlen(line), NULL); 10924b88c807SRodney W. Grimes } 10934b88c807SRodney W. Grimes } 10944b88c807SRodney W. Grimes } 10954b88c807SRodney W. Grimes } 10964b88c807SRodney W. Grimes goto checkend_return; 10974b88c807SRodney W. Grimes } 10984b88c807SRodney W. Grimes 10994b88c807SRodney W. Grimes 11004b88c807SRodney W. Grimes /* 11014b88c807SRodney W. Grimes * Parse a redirection operator. The variable "out" points to a string 11024b88c807SRodney W. Grimes * specifying the fd to be redirected. The variable "c" contains the 11034b88c807SRodney W. Grimes * first character of the redirection operator. 11044b88c807SRodney W. Grimes */ 11054b88c807SRodney W. Grimes 11064b88c807SRodney W. Grimes parseredir: { 11074b88c807SRodney W. Grimes char fd = *out; 11084b88c807SRodney W. Grimes union node *np; 11094b88c807SRodney W. Grimes 11104b88c807SRodney W. Grimes np = (union node *)stalloc(sizeof (struct nfile)); 11114b88c807SRodney W. Grimes if (c == '>') { 11124b88c807SRodney W. Grimes np->nfile.fd = 1; 11134b88c807SRodney W. Grimes c = pgetc(); 11144b88c807SRodney W. Grimes if (c == '>') 11154b88c807SRodney W. Grimes np->type = NAPPEND; 11164b88c807SRodney W. Grimes else if (c == '&') 11174b88c807SRodney W. Grimes np->type = NTOFD; 11184b88c807SRodney W. Grimes else { 11194b88c807SRodney W. Grimes np->type = NTO; 11204b88c807SRodney W. Grimes pungetc(); 11214b88c807SRodney W. Grimes } 11224b88c807SRodney W. Grimes } else { /* c == '<' */ 11234b88c807SRodney W. Grimes np->nfile.fd = 0; 11244b88c807SRodney W. Grimes c = pgetc(); 11254b88c807SRodney W. Grimes if (c == '<') { 11264b88c807SRodney W. Grimes if (sizeof (struct nfile) != sizeof (struct nhere)) { 11274b88c807SRodney W. Grimes np = (union node *)stalloc(sizeof (struct nhere)); 11284b88c807SRodney W. Grimes np->nfile.fd = 0; 11294b88c807SRodney W. Grimes } 11304b88c807SRodney W. Grimes np->type = NHERE; 11314b88c807SRodney W. Grimes heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 11324b88c807SRodney W. Grimes heredoc->here = np; 11334b88c807SRodney W. Grimes if ((c = pgetc()) == '-') { 11344b88c807SRodney W. Grimes heredoc->striptabs = 1; 11354b88c807SRodney W. Grimes } else { 11364b88c807SRodney W. Grimes heredoc->striptabs = 0; 11374b88c807SRodney W. Grimes pungetc(); 11384b88c807SRodney W. Grimes } 11394b88c807SRodney W. Grimes } else if (c == '&') 11404b88c807SRodney W. Grimes np->type = NFROMFD; 11414682f420SBrian Somers else if (c == '>') 11424682f420SBrian Somers np->type = NFROMTO; 11434b88c807SRodney W. Grimes else { 11444b88c807SRodney W. Grimes np->type = NFROM; 11454b88c807SRodney W. Grimes pungetc(); 11464b88c807SRodney W. Grimes } 11474b88c807SRodney W. Grimes } 11484b88c807SRodney W. Grimes if (fd != '\0') 11494b88c807SRodney W. Grimes np->nfile.fd = digit_val(fd); 11504b88c807SRodney W. Grimes redirnode = np; 11514b88c807SRodney W. Grimes goto parseredir_return; 11524b88c807SRodney W. Grimes } 11534b88c807SRodney W. Grimes 11544b88c807SRodney W. Grimes 11554b88c807SRodney W. Grimes /* 11564b88c807SRodney W. Grimes * Parse a substitution. At this point, we have read the dollar sign 11574b88c807SRodney W. Grimes * and nothing else. 11584b88c807SRodney W. Grimes */ 11594b88c807SRodney W. Grimes 11604b88c807SRodney W. Grimes parsesub: { 11614b88c807SRodney W. Grimes int subtype; 11624b88c807SRodney W. Grimes int typeloc; 11634b88c807SRodney W. Grimes int flags; 11644b88c807SRodney W. Grimes char *p; 11654b88c807SRodney W. Grimes #ifndef GDB_HACK 11664b88c807SRodney W. Grimes static const char types[] = "}-+?="; 11674b88c807SRodney W. Grimes #endif 11685c817731SPeter Wemm int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ 11694b88c807SRodney W. Grimes 11704b88c807SRodney W. Grimes c = pgetc(); 11714b88c807SRodney W. Grimes if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 11724b88c807SRodney W. Grimes USTPUTC('$', out); 11734b88c807SRodney W. Grimes pungetc(); 11744b88c807SRodney W. Grimes } else if (c == '(') { /* $(command) or $((arith)) */ 11754b88c807SRodney W. Grimes if (pgetc() == '(') { 11764b88c807SRodney W. Grimes PARSEARITH(); 11774b88c807SRodney W. Grimes } else { 11784b88c807SRodney W. Grimes pungetc(); 11794b88c807SRodney W. Grimes PARSEBACKQNEW(); 11804b88c807SRodney W. Grimes } 11814b88c807SRodney W. Grimes } else { 11824b88c807SRodney W. Grimes USTPUTC(CTLVAR, out); 11834b88c807SRodney W. Grimes typeloc = out - stackblock(); 11844b88c807SRodney W. Grimes USTPUTC(VSNORMAL, out); 11854b88c807SRodney W. Grimes subtype = VSNORMAL; 11864b88c807SRodney W. Grimes if (c == '{') { 11875c817731SPeter Wemm bracketed_name = 1; 11884b88c807SRodney W. Grimes c = pgetc(); 1189aa9caaf6SPeter Wemm if (c == '#') { 1190aa9caaf6SPeter Wemm if ((c = pgetc()) == '}') 1191aa9caaf6SPeter Wemm c = '#'; 1192aa9caaf6SPeter Wemm else 1193aa9caaf6SPeter Wemm subtype = VSLENGTH; 1194aa9caaf6SPeter Wemm } 1195aa9caaf6SPeter Wemm else 11964b88c807SRodney W. Grimes subtype = 0; 11974b88c807SRodney W. Grimes } 11984b88c807SRodney W. Grimes if (is_name(c)) { 11994b88c807SRodney W. Grimes do { 12004b88c807SRodney W. Grimes STPUTC(c, out); 12014b88c807SRodney W. Grimes c = pgetc(); 12024b88c807SRodney W. Grimes } while (is_in_name(c)); 12035c817731SPeter Wemm } else if (is_digit(c)) { 12045c817731SPeter Wemm if (bracketed_name) { 12055c817731SPeter Wemm do { 12065c817731SPeter Wemm STPUTC(c, out); 12075c817731SPeter Wemm c = pgetc(); 12085c817731SPeter Wemm } while (is_digit(c)); 12095c817731SPeter Wemm } else { 12105c817731SPeter Wemm STPUTC(c, out); 12115c817731SPeter Wemm c = pgetc(); 12125c817731SPeter Wemm } 12134b88c807SRodney W. Grimes } else { 12144b88c807SRodney W. Grimes if (! is_special(c)) 12154b88c807SRodney W. Grimes badsub: synerror("Bad substitution"); 12164b88c807SRodney W. Grimes USTPUTC(c, out); 12174b88c807SRodney W. Grimes c = pgetc(); 12184b88c807SRodney W. Grimes } 12194b88c807SRodney W. Grimes STPUTC('=', out); 12204b88c807SRodney W. Grimes flags = 0; 12214b88c807SRodney W. Grimes if (subtype == 0) { 1222aa9caaf6SPeter Wemm switch (c) { 1223aa9caaf6SPeter Wemm case ':': 12244b88c807SRodney W. Grimes flags = VSNUL; 12254b88c807SRodney W. Grimes c = pgetc(); 1226aa9caaf6SPeter Wemm /*FALLTHROUGH*/ 1227aa9caaf6SPeter Wemm default: 12284b88c807SRodney W. Grimes p = strchr(types, c); 12294b88c807SRodney W. Grimes if (p == NULL) 12304b88c807SRodney W. Grimes goto badsub; 12314b88c807SRodney W. Grimes subtype = p - types + VSNORMAL; 1232aa9caaf6SPeter Wemm break; 1233aa9caaf6SPeter Wemm case '%': 1234aa9caaf6SPeter Wemm case '#': 1235aa9caaf6SPeter Wemm { 1236aa9caaf6SPeter Wemm int cc = c; 1237aa9caaf6SPeter Wemm subtype = c == '#' ? VSTRIMLEFT : 1238aa9caaf6SPeter Wemm VSTRIMRIGHT; 1239aa9caaf6SPeter Wemm c = pgetc(); 1240aa9caaf6SPeter Wemm if (c == cc) 1241aa9caaf6SPeter Wemm subtype++; 1242aa9caaf6SPeter Wemm else 1243aa9caaf6SPeter Wemm pungetc(); 1244aa9caaf6SPeter Wemm break; 1245aa9caaf6SPeter Wemm } 1246aa9caaf6SPeter Wemm } 12474b88c807SRodney W. Grimes } else { 12484b88c807SRodney W. Grimes pungetc(); 12494b88c807SRodney W. Grimes } 1250c11e75cfSMartin Cracauer if (subtype != VSLENGTH && (dblquote || arinest)) 12514b88c807SRodney W. Grimes flags |= VSQUOTE; 12524b88c807SRodney W. Grimes *(stackblock() + typeloc) = subtype | flags; 12534b88c807SRodney W. Grimes if (subtype != VSNORMAL) 12544b88c807SRodney W. Grimes varnest++; 12554b88c807SRodney W. Grimes } 12564b88c807SRodney W. Grimes goto parsesub_return; 12574b88c807SRodney W. Grimes } 12584b88c807SRodney W. Grimes 12594b88c807SRodney W. Grimes 12604b88c807SRodney W. Grimes /* 12614b88c807SRodney W. Grimes * Called to parse command substitutions. Newstyle is set if the command 12624b88c807SRodney W. Grimes * is enclosed inside $(...); nlpp is a pointer to the head of the linked 12634b88c807SRodney W. Grimes * list of commands (passed by reference), and savelen is the number of 12644b88c807SRodney W. Grimes * characters on the top of the stack which must be preserved. 12654b88c807SRodney W. Grimes */ 12664b88c807SRodney W. Grimes 12674b88c807SRodney W. Grimes parsebackq: { 12684b88c807SRodney W. Grimes struct nodelist **nlpp; 12694b88c807SRodney W. Grimes int savepbq; 12704b88c807SRodney W. Grimes union node *n; 12714b88c807SRodney W. Grimes char *volatile str; 12724b88c807SRodney W. Grimes struct jmploc jmploc; 12734b88c807SRodney W. Grimes struct jmploc *volatile savehandler; 12744b88c807SRodney W. Grimes int savelen; 1275ab0a2172SSteve Price int saveprompt; 1276ab0a2172SSteve Price #if __GNUC__ 1277ab0a2172SSteve Price /* Avoid longjmp clobbering */ 1278ab0a2172SSteve Price (void) &saveprompt; 1279ab0a2172SSteve Price #endif 12804b88c807SRodney W. Grimes 12814b88c807SRodney W. Grimes savepbq = parsebackquote; 12824b88c807SRodney W. Grimes if (setjmp(jmploc.loc)) { 12834b88c807SRodney W. Grimes if (str) 12844b88c807SRodney W. Grimes ckfree(str); 12854b88c807SRodney W. Grimes parsebackquote = 0; 12864b88c807SRodney W. Grimes handler = savehandler; 12874b88c807SRodney W. Grimes longjmp(handler->loc, 1); 12884b88c807SRodney W. Grimes } 12894b88c807SRodney W. Grimes INTOFF; 12904b88c807SRodney W. Grimes str = NULL; 12914b88c807SRodney W. Grimes savelen = out - stackblock(); 12924b88c807SRodney W. Grimes if (savelen > 0) { 12934b88c807SRodney W. Grimes str = ckmalloc(savelen); 1294aa9caaf6SPeter Wemm memcpy(str, stackblock(), savelen); 12954b88c807SRodney W. Grimes } 12964b88c807SRodney W. Grimes savehandler = handler; 12974b88c807SRodney W. Grimes handler = &jmploc; 12984b88c807SRodney W. Grimes INTON; 12994b88c807SRodney W. Grimes if (oldstyle) { 13004b88c807SRodney W. Grimes /* We must read until the closing backquote, giving special 13014b88c807SRodney W. Grimes treatment to some slashes, and then push the string and 13024b88c807SRodney W. Grimes reread it as input, interpreting it normally. */ 13037920a31dSSteve Price char *out; 13047920a31dSSteve Price int c; 13054b88c807SRodney W. Grimes int savelen; 13064b88c807SRodney W. Grimes char *str; 13074b88c807SRodney W. Grimes 1308ab0a2172SSteve Price 13094b88c807SRodney W. Grimes STARTSTACKSTR(out); 1310ab0a2172SSteve Price for (;;) { 1311ab0a2172SSteve Price if (needprompt) { 1312ab0a2172SSteve Price setprompt(2); 1313ab0a2172SSteve Price needprompt = 0; 131472348d41SJoerg Wunsch } 1315ab0a2172SSteve Price switch (c = pgetc()) { 1316ab0a2172SSteve Price case '`': 1317ab0a2172SSteve Price goto done; 1318ab0a2172SSteve Price 1319ab0a2172SSteve Price case '\\': 1320ab0a2172SSteve Price if ((c = pgetc()) == '\n') { 1321ab0a2172SSteve Price plinno++; 1322ab0a2172SSteve Price if (doprompt) 1323ab0a2172SSteve Price setprompt(2); 1324ab0a2172SSteve Price else 1325ab0a2172SSteve Price setprompt(0); 1326ab0a2172SSteve Price /* 1327ab0a2172SSteve Price * If eating a newline, avoid putting 1328ab0a2172SSteve Price * the newline into the new character 1329ab0a2172SSteve Price * stream (via the STPUTC after the 1330ab0a2172SSteve Price * switch). 1331ab0a2172SSteve Price */ 1332ab0a2172SSteve Price continue; 1333ab0a2172SSteve Price } 13341e95454eSPaul Richards if (c != '\\' && c != '`' && c != '$' 13354b88c807SRodney W. Grimes && (!dblquote || c != '"')) 13364b88c807SRodney W. Grimes STPUTC('\\', out); 1337ab0a2172SSteve Price break; 1338ab0a2172SSteve Price 1339ab0a2172SSteve Price case '\n': 1340ab0a2172SSteve Price plinno++; 1341ab0a2172SSteve Price needprompt = doprompt; 1342ab0a2172SSteve Price break; 1343ab0a2172SSteve Price 1344ab0a2172SSteve Price case PEOF: 1345ab0a2172SSteve Price startlinno = plinno; 1346ab0a2172SSteve Price synerror("EOF in backquote substitution"); 1347ab0a2172SSteve Price break; 1348ab0a2172SSteve Price 1349ab0a2172SSteve Price default: 1350ab0a2172SSteve Price break; 13514b88c807SRodney W. Grimes } 13524b88c807SRodney W. Grimes STPUTC(c, out); 13534b88c807SRodney W. Grimes } 1354ab0a2172SSteve Price done: 13554b88c807SRodney W. Grimes STPUTC('\0', out); 13564b88c807SRodney W. Grimes savelen = out - stackblock(); 13574b88c807SRodney W. Grimes if (savelen > 0) { 13584b88c807SRodney W. Grimes str = ckmalloc(savelen); 1359aa9caaf6SPeter Wemm memcpy(str, stackblock(), savelen); 13604b88c807SRodney W. Grimes setinputstring(str, 1); 13614b88c807SRodney W. Grimes } 1362aa9caaf6SPeter Wemm } 13634b88c807SRodney W. Grimes nlpp = &bqlist; 13644b88c807SRodney W. Grimes while (*nlpp) 13654b88c807SRodney W. Grimes nlpp = &(*nlpp)->next; 13664b88c807SRodney W. Grimes *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 13674b88c807SRodney W. Grimes (*nlpp)->next = NULL; 13684b88c807SRodney W. Grimes parsebackquote = oldstyle; 1369ab0a2172SSteve Price 1370ab0a2172SSteve Price if (oldstyle) { 1371ab0a2172SSteve Price saveprompt = doprompt; 1372ab0a2172SSteve Price doprompt = 0; 1373ab0a2172SSteve Price } 1374ab0a2172SSteve Price 13754b88c807SRodney W. Grimes n = list(0); 1376ab0a2172SSteve Price 13774b88c807SRodney W. Grimes if (oldstyle) 1378ab0a2172SSteve Price doprompt = saveprompt; 1379ab0a2172SSteve Price else { 1380ab0a2172SSteve Price if (readtoken() != TRP) 1381ab0a2172SSteve Price synexpect(TRP); 1382ab0a2172SSteve Price } 1383ab0a2172SSteve Price 1384ab0a2172SSteve Price (*nlpp)->n = n; 1385ab0a2172SSteve Price if (oldstyle) { 1386ab0a2172SSteve Price /* 1387ab0a2172SSteve Price * Start reading from old file again, ignoring any pushed back 1388ab0a2172SSteve Price * tokens left from the backquote parsing 1389ab0a2172SSteve Price */ 13904b88c807SRodney W. Grimes popfile(); 1391ab0a2172SSteve Price tokpushback = 0; 1392ab0a2172SSteve Price } 13934b88c807SRodney W. Grimes while (stackblocksize() <= savelen) 13944b88c807SRodney W. Grimes growstackblock(); 13954b88c807SRodney W. Grimes STARTSTACKSTR(out); 13964b88c807SRodney W. Grimes if (str) { 1397aa9caaf6SPeter Wemm memcpy(out, str, savelen); 13984b88c807SRodney W. Grimes STADJUST(savelen, out); 13994b88c807SRodney W. Grimes INTOFF; 14004b88c807SRodney W. Grimes ckfree(str); 14014b88c807SRodney W. Grimes str = NULL; 14024b88c807SRodney W. Grimes INTON; 14034b88c807SRodney W. Grimes } 14044b88c807SRodney W. Grimes parsebackquote = savepbq; 14054b88c807SRodney W. Grimes handler = savehandler; 14064b88c807SRodney W. Grimes if (arinest || dblquote) 14074b88c807SRodney W. Grimes USTPUTC(CTLBACKQ | CTLQUOTE, out); 14084b88c807SRodney W. Grimes else 14094b88c807SRodney W. Grimes USTPUTC(CTLBACKQ, out); 14104b88c807SRodney W. Grimes if (oldstyle) 14114b88c807SRodney W. Grimes goto parsebackq_oldreturn; 14124b88c807SRodney W. Grimes else 14134b88c807SRodney W. Grimes goto parsebackq_newreturn; 14144b88c807SRodney W. Grimes } 14154b88c807SRodney W. Grimes 14164b88c807SRodney W. Grimes /* 14174b88c807SRodney W. Grimes * Parse an arithmetic expansion (indicate start of one and set state) 14184b88c807SRodney W. Grimes */ 14194b88c807SRodney W. Grimes parsearith: { 14204b88c807SRodney W. Grimes 14214b88c807SRodney W. Grimes if (++arinest == 1) { 14224b88c807SRodney W. Grimes prevsyntax = syntax; 14234b88c807SRodney W. Grimes syntax = ARISYNTAX; 14244b88c807SRodney W. Grimes USTPUTC(CTLARI, out); 14256f47734fSTor Egge if (dblquote) 14266f47734fSTor Egge USTPUTC('"',out); 14276f47734fSTor Egge else 14286f47734fSTor Egge USTPUTC(' ',out); 14294b88c807SRodney W. Grimes } else { 14304b88c807SRodney W. Grimes /* 14314b88c807SRodney W. Grimes * we collapse embedded arithmetic expansion to 14324b88c807SRodney W. Grimes * parenthesis, which should be equivalent 14334b88c807SRodney W. Grimes */ 14344b88c807SRodney W. Grimes USTPUTC('(', out); 14354b88c807SRodney W. Grimes } 14364b88c807SRodney W. Grimes goto parsearith_return; 14374b88c807SRodney W. Grimes } 14384b88c807SRodney W. Grimes 14394b88c807SRodney W. Grimes } /* end of readtoken */ 14404b88c807SRodney W. Grimes 14414b88c807SRodney W. Grimes 14424b88c807SRodney W. Grimes 14434b88c807SRodney W. Grimes #ifdef mkinit 14444b88c807SRodney W. Grimes RESET { 14454b88c807SRodney W. Grimes tokpushback = 0; 14464b88c807SRodney W. Grimes checkkwd = 0; 14474b88c807SRodney W. Grimes } 14484b88c807SRodney W. Grimes #endif 14494b88c807SRodney W. Grimes 14504b88c807SRodney W. Grimes /* 14514b88c807SRodney W. Grimes * Returns true if the text contains nothing to expand (no dollar signs 14524b88c807SRodney W. Grimes * or backquotes). 14534b88c807SRodney W. Grimes */ 14544b88c807SRodney W. Grimes 14554b88c807SRodney W. Grimes STATIC int 14564b88c807SRodney W. Grimes noexpand(text) 14574b88c807SRodney W. Grimes char *text; 14584b88c807SRodney W. Grimes { 14597920a31dSSteve Price char *p; 14607920a31dSSteve Price char c; 14614b88c807SRodney W. Grimes 14624b88c807SRodney W. Grimes p = text; 14634b88c807SRodney W. Grimes while ((c = *p++) != '\0') { 14645557a02aSTor Egge if ( c == CTLQUOTEMARK) 14655557a02aSTor Egge continue; 14664b88c807SRodney W. Grimes if (c == CTLESC) 14674b88c807SRodney W. Grimes p++; 146873f612b5SMartin Cracauer else if (c >= 0 && BASESYNTAX[(int)c] == CCTL) 14694b88c807SRodney W. Grimes return 0; 14704b88c807SRodney W. Grimes } 14714b88c807SRodney W. Grimes return 1; 14724b88c807SRodney W. Grimes } 14734b88c807SRodney W. Grimes 14744b88c807SRodney W. Grimes 14754b88c807SRodney W. Grimes /* 14764b88c807SRodney W. Grimes * Return true if the argument is a legal variable name (a letter or 14774b88c807SRodney W. Grimes * underscore followed by zero or more letters, underscores, and digits). 14784b88c807SRodney W. Grimes */ 14794b88c807SRodney W. Grimes 14804b88c807SRodney W. Grimes int 14814b88c807SRodney W. Grimes goodname(name) 14824b88c807SRodney W. Grimes char *name; 14834b88c807SRodney W. Grimes { 14847920a31dSSteve Price char *p; 14854b88c807SRodney W. Grimes 14864b88c807SRodney W. Grimes p = name; 14874b88c807SRodney W. Grimes if (! is_name(*p)) 14884b88c807SRodney W. Grimes return 0; 14894b88c807SRodney W. Grimes while (*++p) { 14904b88c807SRodney W. Grimes if (! is_in_name(*p)) 14914b88c807SRodney W. Grimes return 0; 14924b88c807SRodney W. Grimes } 14934b88c807SRodney W. Grimes return 1; 14944b88c807SRodney W. Grimes } 14954b88c807SRodney W. Grimes 14964b88c807SRodney W. Grimes 14974b88c807SRodney W. Grimes /* 14984b88c807SRodney W. Grimes * Called when an unexpected token is read during the parse. The argument 14994b88c807SRodney W. Grimes * is the token that is expected, or -1 if more than one type of token can 15004b88c807SRodney W. Grimes * occur at this point. 15014b88c807SRodney W. Grimes */ 15024b88c807SRodney W. Grimes 15034b88c807SRodney W. Grimes STATIC void 1504aa9caaf6SPeter Wemm synexpect(token) 1505aa9caaf6SPeter Wemm int token; 1506aa9caaf6SPeter Wemm { 15074b88c807SRodney W. Grimes char msg[64]; 15084b88c807SRodney W. Grimes 15094b88c807SRodney W. Grimes if (token >= 0) { 15104b88c807SRodney W. Grimes fmtstr(msg, 64, "%s unexpected (expecting %s)", 15114b88c807SRodney W. Grimes tokname[lasttoken], tokname[token]); 15124b88c807SRodney W. Grimes } else { 15134b88c807SRodney W. Grimes fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 15144b88c807SRodney W. Grimes } 15154b88c807SRodney W. Grimes synerror(msg); 15164b88c807SRodney W. Grimes } 15174b88c807SRodney W. Grimes 15184b88c807SRodney W. Grimes 15194b88c807SRodney W. Grimes STATIC void 15204b88c807SRodney W. Grimes synerror(msg) 15214b88c807SRodney W. Grimes char *msg; 15224b88c807SRodney W. Grimes { 15234b88c807SRodney W. Grimes if (commandname) 15244b88c807SRodney W. Grimes outfmt(&errout, "%s: %d: ", commandname, startlinno); 15254b88c807SRodney W. Grimes outfmt(&errout, "Syntax error: %s\n", msg); 15264b88c807SRodney W. Grimes error((char *)NULL); 15274b88c807SRodney W. Grimes } 15284b88c807SRodney W. Grimes 15294b88c807SRodney W. Grimes STATIC void 15304b88c807SRodney W. Grimes setprompt(which) 15314b88c807SRodney W. Grimes int which; 15324b88c807SRodney W. Grimes { 15334b88c807SRodney W. Grimes whichprompt = which; 15344b88c807SRodney W. Grimes 1535aa9caaf6SPeter Wemm #ifndef NO_HISTORY 15364b88c807SRodney W. Grimes if (!el) 1537aa9caaf6SPeter Wemm #endif 15384b88c807SRodney W. Grimes out2str(getprompt(NULL)); 15394b88c807SRodney W. Grimes } 15404b88c807SRodney W. Grimes 15414b88c807SRodney W. Grimes /* 15424b88c807SRodney W. Grimes * called by editline -- any expansions to the prompt 15434b88c807SRodney W. Grimes * should be added here. 15444b88c807SRodney W. Grimes */ 15454b88c807SRodney W. Grimes char * 15464b88c807SRodney W. Grimes getprompt(unused) 1547e7a0b024SSteve Price void *unused __unused; 15484b88c807SRodney W. Grimes { 15494b88c807SRodney W. Grimes switch (whichprompt) { 15504b88c807SRodney W. Grimes case 0: 15514b88c807SRodney W. Grimes return ""; 15524b88c807SRodney W. Grimes case 1: 15534b88c807SRodney W. Grimes return ps1val(); 15544b88c807SRodney W. Grimes case 2: 15554b88c807SRodney W. Grimes return ps2val(); 15564b88c807SRodney W. Grimes default: 15574b88c807SRodney W. Grimes return "<internal prompt error>"; 15584b88c807SRodney W. Grimes } 15594b88c807SRodney W. Grimes } 1560