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 414b88c807SRodney W. Grimes #endif /* not lint */ 422749b141SDavid E. O'Brien #include <sys/cdefs.h> 432749b141SDavid E. O'Brien __FBSDID("$FreeBSD$"); 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 1115134c3f7SWarner Losh STATIC union node *list(int); 1125134c3f7SWarner Losh STATIC union node *andor(void); 1135134c3f7SWarner Losh STATIC union node *pipeline(void); 1145134c3f7SWarner Losh STATIC union node *command(void); 1155134c3f7SWarner Losh STATIC union node *simplecmd(union node **, union node *); 1165134c3f7SWarner Losh STATIC union node *makename(void); 1175134c3f7SWarner Losh STATIC void parsefname(void); 1185134c3f7SWarner Losh STATIC void parseheredoc(void); 1195134c3f7SWarner Losh STATIC int peektoken(void); 1205134c3f7SWarner Losh STATIC int readtoken(void); 1215134c3f7SWarner Losh STATIC int xxreadtoken(void); 1225134c3f7SWarner Losh STATIC int readtoken1(int, char const *, char *, int); 1235134c3f7SWarner Losh STATIC int noexpand(char *); 1245134c3f7SWarner Losh STATIC void synexpect(int); 1255134c3f7SWarner Losh STATIC void synerror(char *); 1265134c3f7SWarner Losh STATIC void setprompt(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 * 1355134c3f7SWarner Losh parsecmd(int interact) 136aa9caaf6SPeter Wemm { 1374b88c807SRodney W. Grimes int t; 1384b88c807SRodney W. Grimes 13998e05fd3SMartin Cracauer tokpushback = 0; 1404b88c807SRodney W. Grimes doprompt = interact; 1414b88c807SRodney W. Grimes if (doprompt) 1424b88c807SRodney W. Grimes setprompt(1); 1434b88c807SRodney W. Grimes else 1444b88c807SRodney W. Grimes setprompt(0); 1454b88c807SRodney W. Grimes needprompt = 0; 1464b88c807SRodney W. Grimes t = readtoken(); 1474b88c807SRodney W. Grimes if (t == TEOF) 1484b88c807SRodney W. Grimes return NEOF; 1494b88c807SRodney W. Grimes if (t == TNL) 1504b88c807SRodney W. Grimes return NULL; 1514b88c807SRodney W. Grimes tokpushback++; 1524b88c807SRodney W. Grimes return list(1); 1534b88c807SRodney W. Grimes } 1544b88c807SRodney W. Grimes 1554b88c807SRodney W. Grimes 1564b88c807SRodney W. Grimes STATIC union node * 1575134c3f7SWarner Losh list(int nlflag) 158aa9caaf6SPeter Wemm { 1594b88c807SRodney W. Grimes union node *n1, *n2, *n3; 160aa9caaf6SPeter Wemm int tok; 1614b88c807SRodney W. Grimes 1624b88c807SRodney W. Grimes checkkwd = 2; 1634b88c807SRodney W. Grimes if (nlflag == 0 && tokendlist[peektoken()]) 1644b88c807SRodney W. Grimes return NULL; 165aa9caaf6SPeter Wemm n1 = NULL; 1664b88c807SRodney W. Grimes for (;;) { 1674b88c807SRodney W. Grimes n2 = andor(); 168aa9caaf6SPeter Wemm tok = readtoken(); 169aa9caaf6SPeter Wemm if (tok == TBACKGND) { 170aa9caaf6SPeter Wemm if (n2->type == NCMD || n2->type == NPIPE) { 171aa9caaf6SPeter Wemm n2->ncmd.backgnd = 1; 172aa9caaf6SPeter Wemm } else if (n2->type == NREDIR) { 173aa9caaf6SPeter Wemm n2->type = NBACKGND; 174aa9caaf6SPeter Wemm } else { 175aa9caaf6SPeter Wemm n3 = (union node *)stalloc(sizeof (struct nredir)); 176aa9caaf6SPeter Wemm n3->type = NBACKGND; 177aa9caaf6SPeter Wemm n3->nredir.n = n2; 178aa9caaf6SPeter Wemm n3->nredir.redirect = NULL; 179aa9caaf6SPeter Wemm n2 = n3; 180aa9caaf6SPeter Wemm } 181aa9caaf6SPeter Wemm } 182aa9caaf6SPeter Wemm if (n1 == NULL) { 183aa9caaf6SPeter Wemm n1 = n2; 184aa9caaf6SPeter Wemm } 185aa9caaf6SPeter Wemm else { 1864b88c807SRodney W. Grimes n3 = (union node *)stalloc(sizeof (struct nbinary)); 1874b88c807SRodney W. Grimes n3->type = NSEMI; 1884b88c807SRodney W. Grimes n3->nbinary.ch1 = n1; 1894b88c807SRodney W. Grimes n3->nbinary.ch2 = n2; 1904b88c807SRodney W. Grimes n1 = n3; 191aa9caaf6SPeter Wemm } 192aa9caaf6SPeter Wemm switch (tok) { 193aa9caaf6SPeter Wemm case TBACKGND: 194aa9caaf6SPeter Wemm case TSEMI: 195aa9caaf6SPeter Wemm tok = readtoken(); 1960d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 197aa9caaf6SPeter Wemm case TNL: 198aa9caaf6SPeter Wemm if (tok == TNL) { 199aa9caaf6SPeter Wemm parseheredoc(); 200aa9caaf6SPeter Wemm if (nlflag) 201aa9caaf6SPeter Wemm return n1; 202aa9caaf6SPeter Wemm } else { 203aa9caaf6SPeter Wemm tokpushback++; 204aa9caaf6SPeter Wemm } 205aa9caaf6SPeter Wemm checkkwd = 2; 206aa9caaf6SPeter Wemm if (tokendlist[peektoken()]) 207aa9caaf6SPeter Wemm return n1; 2084b88c807SRodney W. Grimes break; 2094b88c807SRodney W. Grimes case TEOF: 2104b88c807SRodney W. Grimes if (heredoclist) 2114b88c807SRodney W. Grimes parseheredoc(); 2124b88c807SRodney W. Grimes else 2134b88c807SRodney W. Grimes pungetc(); /* push back EOF on input */ 2144b88c807SRodney W. Grimes return n1; 2154b88c807SRodney W. Grimes default: 2164b88c807SRodney W. Grimes if (nlflag) 2174b88c807SRodney W. Grimes synexpect(-1); 2184b88c807SRodney W. Grimes tokpushback++; 2194b88c807SRodney W. Grimes return n1; 2204b88c807SRodney W. Grimes } 2214b88c807SRodney W. Grimes } 2224b88c807SRodney W. Grimes } 2234b88c807SRodney W. Grimes 2244b88c807SRodney W. Grimes 2254b88c807SRodney W. Grimes 2264b88c807SRodney W. Grimes STATIC union node * 2275134c3f7SWarner Losh andor(void) 2285134c3f7SWarner Losh { 2294b88c807SRodney W. Grimes union node *n1, *n2, *n3; 2304b88c807SRodney W. Grimes int t; 2314b88c807SRodney W. Grimes 2324b88c807SRodney W. Grimes n1 = pipeline(); 2334b88c807SRodney W. Grimes for (;;) { 2344b88c807SRodney W. Grimes if ((t = readtoken()) == TAND) { 2354b88c807SRodney W. Grimes t = NAND; 2364b88c807SRodney W. Grimes } else if (t == TOR) { 2374b88c807SRodney W. Grimes t = NOR; 2384b88c807SRodney W. Grimes } else { 2394b88c807SRodney W. Grimes tokpushback++; 2404b88c807SRodney W. Grimes return n1; 2414b88c807SRodney W. Grimes } 2424b88c807SRodney W. Grimes n2 = pipeline(); 2434b88c807SRodney W. Grimes n3 = (union node *)stalloc(sizeof (struct nbinary)); 2444b88c807SRodney W. Grimes n3->type = t; 2454b88c807SRodney W. Grimes n3->nbinary.ch1 = n1; 2464b88c807SRodney W. Grimes n3->nbinary.ch2 = n2; 2474b88c807SRodney W. Grimes n1 = n3; 2484b88c807SRodney W. Grimes } 2494b88c807SRodney W. Grimes } 2504b88c807SRodney W. Grimes 2514b88c807SRodney W. Grimes 2524b88c807SRodney W. Grimes 2534b88c807SRodney W. Grimes STATIC union node * 2545134c3f7SWarner Losh pipeline(void) 2555134c3f7SWarner Losh { 256b785bd7dSBrian Somers union node *n1, *n2, *pipenode; 2574b88c807SRodney W. Grimes struct nodelist *lp, *prev; 258b785bd7dSBrian Somers int negate; 2594b88c807SRodney W. Grimes 260b785bd7dSBrian Somers negate = 0; 2614b88c807SRodney W. Grimes TRACE(("pipeline: entered\n")); 262b785bd7dSBrian Somers while (readtoken() == TNOT) 263b785bd7dSBrian Somers negate = !negate; 264b785bd7dSBrian Somers tokpushback++; 2654b88c807SRodney W. Grimes n1 = command(); 2664b88c807SRodney W. Grimes if (readtoken() == TPIPE) { 2674b88c807SRodney W. Grimes pipenode = (union node *)stalloc(sizeof (struct npipe)); 2684b88c807SRodney W. Grimes pipenode->type = NPIPE; 2694b88c807SRodney W. Grimes pipenode->npipe.backgnd = 0; 2704b88c807SRodney W. Grimes lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 2714b88c807SRodney W. Grimes pipenode->npipe.cmdlist = lp; 2724b88c807SRodney W. Grimes lp->n = n1; 2734b88c807SRodney W. Grimes do { 2744b88c807SRodney W. Grimes prev = lp; 2754b88c807SRodney W. Grimes lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 2764b88c807SRodney W. Grimes lp->n = command(); 2774b88c807SRodney W. Grimes prev->next = lp; 2784b88c807SRodney W. Grimes } while (readtoken() == TPIPE); 2794b88c807SRodney W. Grimes lp->next = NULL; 2804b88c807SRodney W. Grimes n1 = pipenode; 2814b88c807SRodney W. Grimes } 2824b88c807SRodney W. Grimes tokpushback++; 283b785bd7dSBrian Somers if (negate) { 284b785bd7dSBrian Somers n2 = (union node *)stalloc(sizeof (struct nnot)); 285b785bd7dSBrian Somers n2->type = NNOT; 286b785bd7dSBrian Somers n2->nnot.com = n1; 287b785bd7dSBrian Somers return n2; 288b785bd7dSBrian Somers } else 2894b88c807SRodney W. Grimes return n1; 2904b88c807SRodney W. Grimes } 2914b88c807SRodney W. Grimes 2924b88c807SRodney W. Grimes 2934b88c807SRodney W. Grimes 2944b88c807SRodney W. Grimes STATIC union node * 2955134c3f7SWarner Losh command(void) 2965134c3f7SWarner Losh { 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; 3016c0bde79SBrian Somers int t, negate = 0; 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 3166c0bde79SBrian Somers while (readtoken() == TNOT) { 3176c0bde79SBrian Somers TRACE(("command: TNOT recognized\n")); 3186c0bde79SBrian Somers negate = !negate; 3196c0bde79SBrian Somers } 3206c0bde79SBrian Somers tokpushback++; 3216c0bde79SBrian Somers 3224b88c807SRodney W. Grimes switch (readtoken()) { 3234b88c807SRodney W. Grimes case TIF: 3244b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nif)); 3254b88c807SRodney W. Grimes n1->type = NIF; 326427748f7STim J. Robbins if ((n1->nif.test = list(0)) == NULL) 327427748f7STim J. Robbins synexpect(-1); 3284b88c807SRodney W. Grimes if (readtoken() != TTHEN) 3294b88c807SRodney W. Grimes synexpect(TTHEN); 3304b88c807SRodney W. Grimes n1->nif.ifpart = list(0); 3314b88c807SRodney W. Grimes n2 = n1; 3324b88c807SRodney W. Grimes while (readtoken() == TELIF) { 3334b88c807SRodney W. Grimes n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 3344b88c807SRodney W. Grimes n2 = n2->nif.elsepart; 3354b88c807SRodney W. Grimes n2->type = NIF; 336427748f7STim J. Robbins if ((n2->nif.test = list(0)) == NULL) 337427748f7STim J. Robbins synexpect(-1); 3384b88c807SRodney W. Grimes if (readtoken() != TTHEN) 3394b88c807SRodney W. Grimes synexpect(TTHEN); 3404b88c807SRodney W. Grimes n2->nif.ifpart = list(0); 3414b88c807SRodney W. Grimes } 3424b88c807SRodney W. Grimes if (lasttoken == TELSE) 3434b88c807SRodney W. Grimes n2->nif.elsepart = list(0); 3444b88c807SRodney W. Grimes else { 3454b88c807SRodney W. Grimes n2->nif.elsepart = NULL; 3464b88c807SRodney W. Grimes tokpushback++; 3474b88c807SRodney W. Grimes } 3484b88c807SRodney W. Grimes if (readtoken() != TFI) 3494b88c807SRodney W. Grimes synexpect(TFI); 3504b88c807SRodney W. Grimes checkkwd = 1; 3514b88c807SRodney W. Grimes break; 3524b88c807SRodney W. Grimes case TWHILE: 3534b88c807SRodney W. Grimes case TUNTIL: { 3544b88c807SRodney W. Grimes int got; 3554b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nbinary)); 3564b88c807SRodney W. Grimes n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 357427748f7STim J. Robbins if ((n1->nbinary.ch1 = list(0)) == NULL) 358427748f7STim J. Robbins synexpect(-1); 3594b88c807SRodney W. Grimes if ((got=readtoken()) != TDO) { 3604b88c807SRodney W. Grimes TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 3614b88c807SRodney W. Grimes synexpect(TDO); 3624b88c807SRodney W. Grimes } 3634b88c807SRodney W. Grimes n1->nbinary.ch2 = list(0); 3644b88c807SRodney W. Grimes if (readtoken() != TDONE) 3654b88c807SRodney W. Grimes synexpect(TDONE); 3664b88c807SRodney W. Grimes checkkwd = 1; 3674b88c807SRodney W. Grimes break; 3684b88c807SRodney W. Grimes } 3694b88c807SRodney W. Grimes case TFOR: 3704b88c807SRodney W. Grimes if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 3714b88c807SRodney W. Grimes synerror("Bad for loop variable"); 3724b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nfor)); 3734b88c807SRodney W. Grimes n1->type = NFOR; 3744b88c807SRodney W. Grimes n1->nfor.var = wordtext; 3754b88c807SRodney W. Grimes if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 3764b88c807SRodney W. Grimes app = ≈ 3774b88c807SRodney W. Grimes while (readtoken() == TWORD) { 3784b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct narg)); 3794b88c807SRodney W. Grimes n2->type = NARG; 3804b88c807SRodney W. Grimes n2->narg.text = wordtext; 3814b88c807SRodney W. Grimes n2->narg.backquote = backquotelist; 3824b88c807SRodney W. Grimes *app = n2; 3834b88c807SRodney W. Grimes app = &n2->narg.next; 3844b88c807SRodney W. Grimes } 3854b88c807SRodney W. Grimes *app = NULL; 3864b88c807SRodney W. Grimes n1->nfor.args = ap; 3874b88c807SRodney W. Grimes if (lasttoken != TNL && lasttoken != TSEMI) 3884b88c807SRodney W. Grimes synexpect(-1); 3894b88c807SRodney W. Grimes } else { 3904b88c807SRodney W. Grimes #ifndef GDB_HACK 3914b88c807SRodney W. Grimes static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 3924b88c807SRodney W. Grimes '@', '=', '\0'}; 3934b88c807SRodney W. Grimes #endif 3944b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct narg)); 3954b88c807SRodney W. Grimes n2->type = NARG; 3964b88c807SRodney W. Grimes n2->narg.text = (char *)argvars; 3974b88c807SRodney W. Grimes n2->narg.backquote = NULL; 3984b88c807SRodney W. Grimes n2->narg.next = NULL; 3994b88c807SRodney W. Grimes n1->nfor.args = n2; 4004b88c807SRodney W. Grimes /* 4014b88c807SRodney W. Grimes * Newline or semicolon here is optional (but note 4024b88c807SRodney W. Grimes * that the original Bourne shell only allowed NL). 4034b88c807SRodney W. Grimes */ 4044b88c807SRodney W. Grimes if (lasttoken != TNL && lasttoken != TSEMI) 4054b88c807SRodney W. Grimes tokpushback++; 4064b88c807SRodney W. Grimes } 4074b88c807SRodney W. Grimes checkkwd = 2; 4084b88c807SRodney W. Grimes if ((t = readtoken()) == TDO) 4094b88c807SRodney W. Grimes t = TDONE; 4104b88c807SRodney W. Grimes else if (t == TBEGIN) 4114b88c807SRodney W. Grimes t = TEND; 4124b88c807SRodney W. Grimes else 4134b88c807SRodney W. Grimes synexpect(-1); 4144b88c807SRodney W. Grimes n1->nfor.body = list(0); 4154b88c807SRodney W. Grimes if (readtoken() != t) 4164b88c807SRodney W. Grimes synexpect(t); 4174b88c807SRodney W. Grimes checkkwd = 1; 4184b88c807SRodney W. Grimes break; 4194b88c807SRodney W. Grimes case TCASE: 4204b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct ncase)); 4214b88c807SRodney W. Grimes n1->type = NCASE; 4224b88c807SRodney W. Grimes if (readtoken() != TWORD) 4234b88c807SRodney W. Grimes synexpect(TWORD); 4244b88c807SRodney W. Grimes n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 4254b88c807SRodney W. Grimes n2->type = NARG; 4264b88c807SRodney W. Grimes n2->narg.text = wordtext; 4274b88c807SRodney W. Grimes n2->narg.backquote = backquotelist; 4284b88c807SRodney W. Grimes n2->narg.next = NULL; 4294b88c807SRodney W. Grimes while (readtoken() == TNL); 4304b88c807SRodney W. Grimes if (lasttoken != TWORD || ! equal(wordtext, "in")) 4314b88c807SRodney W. Grimes synerror("expecting \"in\""); 4324b88c807SRodney W. Grimes cpp = &n1->ncase.cases; 4334417f629SPeter Wemm noaliases = 1; /* turn off alias expansion */ 434650488feSSean Eric Fagan checkkwd = 2, readtoken(); 435e00e16adSTim J. Robbins while (lasttoken != TESAC) { 4364b88c807SRodney W. Grimes *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 4374b88c807SRodney W. Grimes cp->type = NCLIST; 4384b88c807SRodney W. Grimes app = &cp->nclist.pattern; 439f7a9b7feSTim J. Robbins if (lasttoken == TLP) 440f7a9b7feSTim J. Robbins readtoken(); 4414b88c807SRodney W. Grimes for (;;) { 4424b88c807SRodney W. Grimes *app = ap = (union node *)stalloc(sizeof (struct narg)); 4434b88c807SRodney W. Grimes ap->type = NARG; 4444b88c807SRodney W. Grimes ap->narg.text = wordtext; 4454b88c807SRodney W. Grimes ap->narg.backquote = backquotelist; 446650488feSSean Eric Fagan if (checkkwd = 2, readtoken() != TPIPE) 4474b88c807SRodney W. Grimes break; 4484b88c807SRodney W. Grimes app = &ap->narg.next; 449650488feSSean Eric Fagan readtoken(); 4504b88c807SRodney W. Grimes } 4514b88c807SRodney W. Grimes ap->narg.next = NULL; 4524b88c807SRodney W. Grimes if (lasttoken != TRP) 4534417f629SPeter Wemm noaliases = 0, synexpect(TRP); 4544b88c807SRodney W. Grimes cp->nclist.body = list(0); 455650488feSSean Eric Fagan 456650488feSSean Eric Fagan checkkwd = 2; 457650488feSSean Eric Fagan if ((t = readtoken()) != TESAC) { 458650488feSSean Eric Fagan if (t != TENDCASE) 4594417f629SPeter Wemm noaliases = 0, synexpect(TENDCASE); 460650488feSSean Eric Fagan else 461650488feSSean Eric Fagan checkkwd = 2, readtoken(); 4624b88c807SRodney W. Grimes } 463650488feSSean Eric Fagan cpp = &cp->nclist.next; 464e00e16adSTim J. Robbins } 4654417f629SPeter Wemm noaliases = 0; /* reset alias expansion */ 4664b88c807SRodney W. Grimes *cpp = NULL; 4674b88c807SRodney W. Grimes checkkwd = 1; 4684b88c807SRodney W. Grimes break; 4694b88c807SRodney W. Grimes case TLP: 4704b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nredir)); 4714b88c807SRodney W. Grimes n1->type = NSUBSHELL; 4724b88c807SRodney W. Grimes n1->nredir.n = list(0); 4734b88c807SRodney W. Grimes n1->nredir.redirect = NULL; 4744b88c807SRodney W. Grimes if (readtoken() != TRP) 4754b88c807SRodney W. Grimes synexpect(TRP); 4764b88c807SRodney W. Grimes checkkwd = 1; 4774b88c807SRodney W. Grimes break; 4784b88c807SRodney W. Grimes case TBEGIN: 4794b88c807SRodney W. Grimes n1 = list(0); 4804b88c807SRodney W. Grimes if (readtoken() != TEND) 4814b88c807SRodney W. Grimes synexpect(TEND); 4824b88c807SRodney W. Grimes checkkwd = 1; 4834b88c807SRodney W. Grimes break; 4844b88c807SRodney W. Grimes /* Handle an empty command like other simple commands. */ 485248ffae5SJoerg Wunsch case TSEMI: 486d8d737d7STim J. Robbins case TAND: 487d8d737d7STim J. Robbins case TOR: 488aa9caaf6SPeter Wemm /* 489aa9caaf6SPeter Wemm * An empty command before a ; doesn't make much sense, and 490aa9caaf6SPeter Wemm * should certainly be disallowed in the case of `if ;'. 491aa9caaf6SPeter Wemm */ 492aa9caaf6SPeter Wemm if (!redir) 493aa9caaf6SPeter Wemm synexpect(-1); 494aa9caaf6SPeter Wemm case TNL: 495248ffae5SJoerg Wunsch case TEOF: 4964b88c807SRodney W. Grimes case TWORD: 497aa9caaf6SPeter Wemm case TRP: 4984b88c807SRodney W. Grimes tokpushback++; 4996c0bde79SBrian Somers n1 = simplecmd(rpp, redir); 5006c0bde79SBrian Somers goto checkneg; 5014b88c807SRodney W. Grimes default: 5024b88c807SRodney W. Grimes synexpect(-1); 5034b88c807SRodney W. Grimes } 5044b88c807SRodney W. Grimes 5054b88c807SRodney W. Grimes /* Now check for redirection which may follow command */ 5064b88c807SRodney W. Grimes while (readtoken() == TREDIR) { 5074b88c807SRodney W. Grimes *rpp = n2 = redirnode; 5084b88c807SRodney W. Grimes rpp = &n2->nfile.next; 5094b88c807SRodney W. Grimes parsefname(); 5104b88c807SRodney W. Grimes } 5114b88c807SRodney W. Grimes tokpushback++; 5124b88c807SRodney W. Grimes *rpp = NULL; 5134b88c807SRodney W. Grimes if (redir) { 5144b88c807SRodney W. Grimes if (n1->type != NSUBSHELL) { 5154b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct nredir)); 5164b88c807SRodney W. Grimes n2->type = NREDIR; 5174b88c807SRodney W. Grimes n2->nredir.n = n1; 5184b88c807SRodney W. Grimes n1 = n2; 5194b88c807SRodney W. Grimes } 5204b88c807SRodney W. Grimes n1->nredir.redirect = redir; 5214b88c807SRodney W. Grimes } 5226c0bde79SBrian Somers 5236c0bde79SBrian Somers checkneg: 5246c0bde79SBrian Somers if (negate) { 5256c0bde79SBrian Somers n2 = (union node *)stalloc(sizeof (struct nnot)); 5266c0bde79SBrian Somers n2->type = NNOT; 5276c0bde79SBrian Somers n2->nnot.com = n1; 5286c0bde79SBrian Somers return n2; 5296c0bde79SBrian Somers } 5306c0bde79SBrian Somers else 5314b88c807SRodney W. Grimes return n1; 5324b88c807SRodney W. Grimes } 5334b88c807SRodney W. Grimes 5344b88c807SRodney W. Grimes 5354b88c807SRodney W. Grimes STATIC union node * 5365134c3f7SWarner Losh simplecmd(union node **rpp, union node *redir) 5374b88c807SRodney W. Grimes { 5384b88c807SRodney W. Grimes union node *args, **app; 5394b88c807SRodney W. Grimes union node **orig_rpp = rpp; 5406c0bde79SBrian Somers union node *n = NULL, *n2; 5416c0bde79SBrian Somers int negate = 0; 5424b88c807SRodney W. Grimes 5434b88c807SRodney W. Grimes /* If we don't have any redirections already, then we must reset */ 5444b88c807SRodney W. Grimes /* rpp to be the address of the local redir variable. */ 5454b88c807SRodney W. Grimes if (redir == 0) 5464b88c807SRodney W. Grimes rpp = &redir; 5474b88c807SRodney W. Grimes 5484b88c807SRodney W. Grimes args = NULL; 5494b88c807SRodney W. Grimes app = &args; 5504b88c807SRodney W. Grimes /* 5514b88c807SRodney W. Grimes * We save the incoming value, because we need this for shell 5524b88c807SRodney W. Grimes * functions. There can not be a redirect or an argument between 5534b88c807SRodney W. Grimes * the function name and the open parenthesis. 5544b88c807SRodney W. Grimes */ 5554b88c807SRodney W. Grimes orig_rpp = rpp; 5564b88c807SRodney W. Grimes 5576c0bde79SBrian Somers while (readtoken() == TNOT) { 5586c0bde79SBrian Somers TRACE(("command: TNOT recognized\n")); 5596c0bde79SBrian Somers negate = !negate; 5606c0bde79SBrian Somers } 5616c0bde79SBrian Somers tokpushback++; 5626c0bde79SBrian Somers 5634b88c807SRodney W. Grimes for (;;) { 5644b88c807SRodney W. Grimes if (readtoken() == TWORD) { 5654b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct narg)); 5664b88c807SRodney W. Grimes n->type = NARG; 5674b88c807SRodney W. Grimes n->narg.text = wordtext; 5684b88c807SRodney W. Grimes n->narg.backquote = backquotelist; 5694b88c807SRodney W. Grimes *app = n; 5704b88c807SRodney W. Grimes app = &n->narg.next; 5714b88c807SRodney W. Grimes } else if (lasttoken == TREDIR) { 5724b88c807SRodney W. Grimes *rpp = n = redirnode; 5734b88c807SRodney W. Grimes rpp = &n->nfile.next; 5744b88c807SRodney W. Grimes parsefname(); /* read name of redirection file */ 5754b88c807SRodney W. Grimes } else if (lasttoken == TLP && app == &args->narg.next 5764b88c807SRodney W. Grimes && rpp == orig_rpp) { 5774b88c807SRodney W. Grimes /* We have a function */ 5784b88c807SRodney W. Grimes if (readtoken() != TRP) 5794b88c807SRodney W. Grimes synexpect(TRP); 5804b88c807SRodney W. Grimes #ifdef notdef 5814b88c807SRodney W. Grimes if (! goodname(n->narg.text)) 5824b88c807SRodney W. Grimes synerror("Bad function name"); 5834b88c807SRodney W. Grimes #endif 5844b88c807SRodney W. Grimes n->type = NDEFUN; 5854b88c807SRodney W. Grimes n->narg.next = command(); 5866c0bde79SBrian Somers goto checkneg; 5874b88c807SRodney W. Grimes } else { 5884b88c807SRodney W. Grimes tokpushback++; 5894b88c807SRodney W. Grimes break; 5904b88c807SRodney W. Grimes } 5914b88c807SRodney W. Grimes } 5924b88c807SRodney W. Grimes *app = NULL; 5934b88c807SRodney W. Grimes *rpp = NULL; 5944b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct ncmd)); 5954b88c807SRodney W. Grimes n->type = NCMD; 5964b88c807SRodney W. Grimes n->ncmd.backgnd = 0; 5974b88c807SRodney W. Grimes n->ncmd.args = args; 5984b88c807SRodney W. Grimes n->ncmd.redirect = redir; 5996c0bde79SBrian Somers 6006c0bde79SBrian Somers checkneg: 6016c0bde79SBrian Somers if (negate) { 6026c0bde79SBrian Somers n2 = (union node *)stalloc(sizeof (struct nnot)); 6036c0bde79SBrian Somers n2->type = NNOT; 6046c0bde79SBrian Somers n2->nnot.com = n; 6056c0bde79SBrian Somers return n2; 6066c0bde79SBrian Somers } 6076c0bde79SBrian Somers else 6084b88c807SRodney W. Grimes return n; 6094b88c807SRodney W. Grimes } 6104b88c807SRodney W. Grimes 611aa9caaf6SPeter Wemm STATIC union node * 6125134c3f7SWarner Losh makename(void) 6135134c3f7SWarner Losh { 614aa9caaf6SPeter Wemm union node *n; 615aa9caaf6SPeter Wemm 616aa9caaf6SPeter Wemm n = (union node *)stalloc(sizeof (struct narg)); 617aa9caaf6SPeter Wemm n->type = NARG; 618aa9caaf6SPeter Wemm n->narg.next = NULL; 619aa9caaf6SPeter Wemm n->narg.text = wordtext; 620aa9caaf6SPeter Wemm n->narg.backquote = backquotelist; 621aa9caaf6SPeter Wemm return n; 622aa9caaf6SPeter Wemm } 623aa9caaf6SPeter Wemm 6245134c3f7SWarner Losh void fixredir(union node *n, const char *text, int err) 625aa9caaf6SPeter Wemm { 626aa9caaf6SPeter Wemm TRACE(("Fix redir %s %d\n", text, err)); 627aa9caaf6SPeter Wemm if (!err) 628aa9caaf6SPeter Wemm n->ndup.vname = NULL; 629aa9caaf6SPeter Wemm 630aa9caaf6SPeter Wemm if (is_digit(text[0]) && text[1] == '\0') 631aa9caaf6SPeter Wemm n->ndup.dupfd = digit_val(text[0]); 632aa9caaf6SPeter Wemm else if (text[0] == '-' && text[1] == '\0') 633aa9caaf6SPeter Wemm n->ndup.dupfd = -1; 634aa9caaf6SPeter Wemm else { 635aa9caaf6SPeter Wemm 636aa9caaf6SPeter Wemm if (err) 637aa9caaf6SPeter Wemm synerror("Bad fd number"); 638aa9caaf6SPeter Wemm else 639aa9caaf6SPeter Wemm n->ndup.vname = makename(); 640aa9caaf6SPeter Wemm } 641aa9caaf6SPeter Wemm } 642aa9caaf6SPeter Wemm 6434b88c807SRodney W. Grimes 6444b88c807SRodney W. Grimes STATIC void 6455134c3f7SWarner Losh parsefname(void) 6465134c3f7SWarner Losh { 6474b88c807SRodney W. Grimes union node *n = redirnode; 6484b88c807SRodney W. Grimes 6494b88c807SRodney W. Grimes if (readtoken() != TWORD) 6504b88c807SRodney W. Grimes synexpect(-1); 6514b88c807SRodney W. Grimes if (n->type == NHERE) { 6524b88c807SRodney W. Grimes struct heredoc *here = heredoc; 6534b88c807SRodney W. Grimes struct heredoc *p; 6544b88c807SRodney W. Grimes int i; 6554b88c807SRodney W. Grimes 6564b88c807SRodney W. Grimes if (quoteflag == 0) 6574b88c807SRodney W. Grimes n->type = NXHERE; 6584b88c807SRodney W. Grimes TRACE(("Here document %d\n", n->type)); 6594b88c807SRodney W. Grimes if (here->striptabs) { 6604b88c807SRodney W. Grimes while (*wordtext == '\t') 6614b88c807SRodney W. Grimes wordtext++; 6624b88c807SRodney W. Grimes } 6634b88c807SRodney W. Grimes if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 6644b88c807SRodney W. Grimes synerror("Illegal eof marker for << redirection"); 6654b88c807SRodney W. Grimes rmescapes(wordtext); 6664b88c807SRodney W. Grimes here->eofmark = wordtext; 6674b88c807SRodney W. Grimes here->next = NULL; 6684b88c807SRodney W. Grimes if (heredoclist == NULL) 6694b88c807SRodney W. Grimes heredoclist = here; 6704b88c807SRodney W. Grimes else { 6714b88c807SRodney W. Grimes for (p = heredoclist ; p->next ; p = p->next); 6724b88c807SRodney W. Grimes p->next = here; 6734b88c807SRodney W. Grimes } 6744b88c807SRodney W. Grimes } else if (n->type == NTOFD || n->type == NFROMFD) { 675aa9caaf6SPeter Wemm fixredir(n, wordtext, 0); 6764b88c807SRodney W. Grimes } else { 677aa9caaf6SPeter Wemm n->nfile.fname = makename(); 6784b88c807SRodney W. Grimes } 6794b88c807SRodney W. Grimes } 6804b88c807SRodney W. Grimes 6814b88c807SRodney W. Grimes 6824b88c807SRodney W. Grimes /* 6834b88c807SRodney W. Grimes * Input any here documents. 6844b88c807SRodney W. Grimes */ 6854b88c807SRodney W. Grimes 6864b88c807SRodney W. Grimes STATIC void 6875134c3f7SWarner Losh parseheredoc(void) 6885134c3f7SWarner Losh { 6894b88c807SRodney W. Grimes struct heredoc *here; 6904b88c807SRodney W. Grimes union node *n; 6914b88c807SRodney W. Grimes 6924b88c807SRodney W. Grimes while (heredoclist) { 6934b88c807SRodney W. Grimes here = heredoclist; 6944b88c807SRodney W. Grimes heredoclist = here->next; 6954b88c807SRodney W. Grimes if (needprompt) { 6964b88c807SRodney W. Grimes setprompt(2); 6974b88c807SRodney W. Grimes needprompt = 0; 6984b88c807SRodney W. Grimes } 6994b88c807SRodney W. Grimes readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 7004b88c807SRodney W. Grimes here->eofmark, here->striptabs); 7014b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct narg)); 7024b88c807SRodney W. Grimes n->narg.type = NARG; 7034b88c807SRodney W. Grimes n->narg.next = NULL; 7044b88c807SRodney W. Grimes n->narg.text = wordtext; 7054b88c807SRodney W. Grimes n->narg.backquote = backquotelist; 7064b88c807SRodney W. Grimes here->here->nhere.doc = n; 7074b88c807SRodney W. Grimes } 7084b88c807SRodney W. Grimes } 7094b88c807SRodney W. Grimes 7104b88c807SRodney W. Grimes STATIC int 7115134c3f7SWarner Losh peektoken(void) 7125134c3f7SWarner Losh { 7134b88c807SRodney W. Grimes int t; 7144b88c807SRodney W. Grimes 7154b88c807SRodney W. Grimes t = readtoken(); 7164b88c807SRodney W. Grimes tokpushback++; 7174b88c807SRodney W. Grimes return (t); 7184b88c807SRodney W. Grimes } 7194b88c807SRodney W. Grimes 7204b88c807SRodney W. Grimes STATIC int 7215134c3f7SWarner Losh readtoken(void) 7225134c3f7SWarner Losh { 7234b88c807SRodney W. Grimes int t; 7244b88c807SRodney W. Grimes int savecheckkwd = checkkwd; 7254b88c807SRodney W. Grimes struct alias *ap; 7264b88c807SRodney W. Grimes #ifdef DEBUG 7274b88c807SRodney W. Grimes int alreadyseen = tokpushback; 7284b88c807SRodney W. Grimes #endif 7294b88c807SRodney W. Grimes 7304b88c807SRodney W. Grimes top: 7314b88c807SRodney W. Grimes t = xxreadtoken(); 7324b88c807SRodney W. Grimes 7334b88c807SRodney W. Grimes if (checkkwd) { 7344b88c807SRodney W. Grimes /* 7354b88c807SRodney W. Grimes * eat newlines 7364b88c807SRodney W. Grimes */ 7374b88c807SRodney W. Grimes if (checkkwd == 2) { 7384b88c807SRodney W. Grimes checkkwd = 0; 7394b88c807SRodney W. Grimes while (t == TNL) { 7404b88c807SRodney W. Grimes parseheredoc(); 7414b88c807SRodney W. Grimes t = xxreadtoken(); 7424b88c807SRodney W. Grimes } 7434b88c807SRodney W. Grimes } else 7444b88c807SRodney W. Grimes checkkwd = 0; 7454b88c807SRodney W. Grimes /* 7464b88c807SRodney W. Grimes * check for keywords and aliases 7474b88c807SRodney W. Grimes */ 748aa9caaf6SPeter Wemm if (t == TWORD && !quoteflag) 749aa9caaf6SPeter Wemm { 7508b7808bcSJuli Mallett const char * const *pp; 7514b88c807SRodney W. Grimes 7528b7808bcSJuli Mallett for (pp = parsekwd; *pp; pp++) { 753aa9caaf6SPeter Wemm if (**pp == *wordtext && equal(*pp, wordtext)) 754aa9caaf6SPeter Wemm { 7554b88c807SRodney W. Grimes lasttoken = t = pp - parsekwd + KWDOFFSET; 7564b88c807SRodney W. Grimes TRACE(("keyword %s recognized\n", tokname[t])); 7574b88c807SRodney W. Grimes goto out; 7584b88c807SRodney W. Grimes } 7594b88c807SRodney W. Grimes } 7604417f629SPeter Wemm if (noaliases == 0 && 7614417f629SPeter Wemm (ap = lookupalias(wordtext, 1)) != NULL) { 7624b88c807SRodney W. Grimes pushstring(ap->val, strlen(ap->val), ap); 7634b88c807SRodney W. Grimes checkkwd = savecheckkwd; 7644b88c807SRodney W. Grimes goto top; 7654b88c807SRodney W. Grimes } 7664b88c807SRodney W. Grimes } 7674b88c807SRodney W. Grimes out: 7686c0bde79SBrian Somers checkkwd = (t == TNOT) ? savecheckkwd : 0; 7694b88c807SRodney W. Grimes } 7704b88c807SRodney W. Grimes #ifdef DEBUG 7714b88c807SRodney W. Grimes if (!alreadyseen) 7724b88c807SRodney W. Grimes TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 7734b88c807SRodney W. Grimes else 7744b88c807SRodney W. Grimes TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 7754b88c807SRodney W. Grimes #endif 7764b88c807SRodney W. Grimes return (t); 7774b88c807SRodney W. Grimes } 7784b88c807SRodney W. Grimes 7794b88c807SRodney W. Grimes 7804b88c807SRodney W. Grimes /* 7814b88c807SRodney W. Grimes * Read the next input token. 7824b88c807SRodney W. Grimes * If the token is a word, we set backquotelist to the list of cmds in 7834b88c807SRodney W. Grimes * backquotes. We set quoteflag to true if any part of the word was 7844b88c807SRodney W. Grimes * quoted. 7854b88c807SRodney W. Grimes * If the token is TREDIR, then we set redirnode to a structure containing 7864b88c807SRodney W. Grimes * the redirection. 7874b88c807SRodney W. Grimes * In all cases, the variable startlinno is set to the number of the line 7884b88c807SRodney W. Grimes * on which the token starts. 7894b88c807SRodney W. Grimes * 7904b88c807SRodney W. Grimes * [Change comment: here documents and internal procedures] 7914b88c807SRodney W. Grimes * [Readtoken shouldn't have any arguments. Perhaps we should make the 7924b88c807SRodney W. Grimes * word parsing code into a separate routine. In this case, readtoken 7934b88c807SRodney W. Grimes * doesn't need to have any internal procedures, but parseword does. 7944b88c807SRodney W. Grimes * We could also make parseoperator in essence the main routine, and 7954b88c807SRodney W. Grimes * have parseword (readtoken1?) handle both words and redirection.] 7964b88c807SRodney W. Grimes */ 7974b88c807SRodney W. Grimes 7984b88c807SRodney W. Grimes #define RETURN(token) return lasttoken = token 7994b88c807SRodney W. Grimes 8004b88c807SRodney W. Grimes STATIC int 8015134c3f7SWarner Losh xxreadtoken(void) 8025134c3f7SWarner Losh { 8037920a31dSSteve Price int c; 8044b88c807SRodney W. Grimes 8054b88c807SRodney W. Grimes if (tokpushback) { 8064b88c807SRodney W. Grimes tokpushback = 0; 8074b88c807SRodney W. Grimes return lasttoken; 8084b88c807SRodney W. Grimes } 8094b88c807SRodney W. Grimes if (needprompt) { 8104b88c807SRodney W. Grimes setprompt(2); 8114b88c807SRodney W. Grimes needprompt = 0; 8124b88c807SRodney W. Grimes } 8134b88c807SRodney W. Grimes startlinno = plinno; 8144b88c807SRodney W. Grimes for (;;) { /* until token or start of word found */ 8154b88c807SRodney W. Grimes c = pgetc_macro(); 8164b88c807SRodney W. Grimes if (c == ' ' || c == '\t') 8174b88c807SRodney W. Grimes continue; /* quick check for white space first */ 8184b88c807SRodney W. Grimes switch (c) { 8194b88c807SRodney W. Grimes case ' ': case '\t': 8204b88c807SRodney W. Grimes continue; 8214b88c807SRodney W. Grimes case '#': 8224b88c807SRodney W. Grimes while ((c = pgetc()) != '\n' && c != PEOF); 8234b88c807SRodney W. Grimes pungetc(); 8244b88c807SRodney W. Grimes continue; 8254b88c807SRodney W. Grimes case '\\': 8264b88c807SRodney W. Grimes if (pgetc() == '\n') { 8274b88c807SRodney W. Grimes startlinno = ++plinno; 8284b88c807SRodney W. Grimes if (doprompt) 8294b88c807SRodney W. Grimes setprompt(2); 8304b88c807SRodney W. Grimes else 8314b88c807SRodney W. Grimes setprompt(0); 8324b88c807SRodney W. Grimes continue; 8334b88c807SRodney W. Grimes } 8344b88c807SRodney W. Grimes pungetc(); 8354b88c807SRodney W. Grimes goto breakloop; 8364b88c807SRodney W. Grimes case '\n': 8374b88c807SRodney W. Grimes plinno++; 8384b88c807SRodney W. Grimes needprompt = doprompt; 8394b88c807SRodney W. Grimes RETURN(TNL); 8404b88c807SRodney W. Grimes case PEOF: 8414b88c807SRodney W. Grimes RETURN(TEOF); 8424b88c807SRodney W. Grimes case '&': 8434b88c807SRodney W. Grimes if (pgetc() == '&') 8444b88c807SRodney W. Grimes RETURN(TAND); 8454b88c807SRodney W. Grimes pungetc(); 8464b88c807SRodney W. Grimes RETURN(TBACKGND); 8474b88c807SRodney W. Grimes case '|': 8484b88c807SRodney W. Grimes if (pgetc() == '|') 8494b88c807SRodney W. Grimes RETURN(TOR); 8504b88c807SRodney W. Grimes pungetc(); 8514b88c807SRodney W. Grimes RETURN(TPIPE); 8524b88c807SRodney W. Grimes case ';': 8534b88c807SRodney W. Grimes if (pgetc() == ';') 8544b88c807SRodney W. Grimes RETURN(TENDCASE); 8554b88c807SRodney W. Grimes pungetc(); 8564b88c807SRodney W. Grimes RETURN(TSEMI); 8574b88c807SRodney W. Grimes case '(': 8584b88c807SRodney W. Grimes RETURN(TLP); 8594b88c807SRodney W. Grimes case ')': 8604b88c807SRodney W. Grimes RETURN(TRP); 8614b88c807SRodney W. Grimes default: 8624b88c807SRodney W. Grimes goto breakloop; 8634b88c807SRodney W. Grimes } 8644b88c807SRodney W. Grimes } 8654b88c807SRodney W. Grimes breakloop: 8664b88c807SRodney W. Grimes return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 8674b88c807SRodney W. Grimes #undef RETURN 8684b88c807SRodney W. Grimes } 8694b88c807SRodney W. Grimes 8704b88c807SRodney W. Grimes 8714b88c807SRodney W. Grimes 8724b88c807SRodney W. Grimes /* 8734b88c807SRodney W. Grimes * If eofmark is NULL, read a word or a redirection symbol. If eofmark 8744b88c807SRodney W. Grimes * is not NULL, read a here document. In the latter case, eofmark is the 8754b88c807SRodney W. Grimes * word which marks the end of the document and striptabs is true if 8764b88c807SRodney W. Grimes * leading tabs should be stripped from the document. The argument firstc 8774b88c807SRodney W. Grimes * is the first character of the input token or document. 8784b88c807SRodney W. Grimes * 8794b88c807SRodney W. Grimes * Because C does not have internal subroutines, I have simulated them 8804b88c807SRodney W. Grimes * using goto's to implement the subroutine linkage. The following macros 8814b88c807SRodney W. Grimes * will run code that appears at the end of readtoken1. 8824b88c807SRodney W. Grimes */ 8834b88c807SRodney W. Grimes 8844b88c807SRodney W. Grimes #define CHECKEND() {goto checkend; checkend_return:;} 8854b88c807SRodney W. Grimes #define PARSEREDIR() {goto parseredir; parseredir_return:;} 8864b88c807SRodney W. Grimes #define PARSESUB() {goto parsesub; parsesub_return:;} 8874b88c807SRodney W. Grimes #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 8884b88c807SRodney W. Grimes #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 8894b88c807SRodney W. Grimes #define PARSEARITH() {goto parsearith; parsearith_return:;} 8904b88c807SRodney W. Grimes 8914b88c807SRodney W. Grimes STATIC int 8925134c3f7SWarner Losh readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) 8934b88c807SRodney W. Grimes { 894aa9caaf6SPeter Wemm int c = firstc; 895aa9caaf6SPeter Wemm char *out; 8964b88c807SRodney W. Grimes int len; 8974b88c807SRodney W. Grimes char line[EOFMARKLEN + 1]; 8984b88c807SRodney W. Grimes struct nodelist *bqlist; 8994b88c807SRodney W. Grimes int quotef; 9004b88c807SRodney W. Grimes int dblquote; 9014b88c807SRodney W. Grimes int varnest; /* levels of variables expansion */ 9024b88c807SRodney W. Grimes int arinest; /* levels of arithmetic expansion */ 9034b88c807SRodney W. Grimes int parenlevel; /* levels of parens in arithmetic */ 9044b88c807SRodney W. Grimes int oldstyle; 9054b88c807SRodney W. Grimes char const *prevsyntax; /* syntax before arithmetic */ 9062dde9ce3SMartin Cracauer int synentry; 907aa9caaf6SPeter Wemm #if __GNUC__ 908aa9caaf6SPeter Wemm /* Avoid longjmp clobbering */ 909aa9caaf6SPeter Wemm (void) &out; 910aa9caaf6SPeter Wemm (void) "ef; 911aa9caaf6SPeter Wemm (void) &dblquote; 912aa9caaf6SPeter Wemm (void) &varnest; 913aa9caaf6SPeter Wemm (void) &arinest; 914aa9caaf6SPeter Wemm (void) &parenlevel; 915aa9caaf6SPeter Wemm (void) &oldstyle; 916aa9caaf6SPeter Wemm (void) &prevsyntax; 917aa9caaf6SPeter Wemm (void) &syntax; 9182dde9ce3SMartin Cracauer (void) &synentry; 919aa9caaf6SPeter Wemm #endif 9204b88c807SRodney W. Grimes 9214b88c807SRodney W. Grimes startlinno = plinno; 9224b88c807SRodney W. Grimes dblquote = 0; 9234b88c807SRodney W. Grimes if (syntax == DQSYNTAX) 9244b88c807SRodney W. Grimes dblquote = 1; 9254b88c807SRodney W. Grimes quotef = 0; 9264b88c807SRodney W. Grimes bqlist = NULL; 9274b88c807SRodney W. Grimes varnest = 0; 9284b88c807SRodney W. Grimes arinest = 0; 9294b88c807SRodney W. Grimes parenlevel = 0; 9304b88c807SRodney W. Grimes 9314b88c807SRodney W. Grimes STARTSTACKSTR(out); 9324b88c807SRodney W. Grimes loop: { /* for each line, until end of word */ 9334b88c807SRodney W. Grimes CHECKEND(); /* set c to PEOF if at end of here document */ 9344b88c807SRodney W. Grimes for (;;) { /* until end of line or end of word */ 9354b88c807SRodney W. Grimes CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 9362dde9ce3SMartin Cracauer 9372dde9ce3SMartin Cracauer synentry = syntax[c]; 9382dde9ce3SMartin Cracauer 9392dde9ce3SMartin Cracauer switch(synentry) { 9404b88c807SRodney W. Grimes case CNL: /* '\n' */ 9414b88c807SRodney W. Grimes if (syntax == BASESYNTAX) 9424b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 9434b88c807SRodney W. Grimes USTPUTC(c, out); 9444b88c807SRodney W. Grimes plinno++; 9454b88c807SRodney W. Grimes if (doprompt) 9464b88c807SRodney W. Grimes setprompt(2); 9474b88c807SRodney W. Grimes else 9484b88c807SRodney W. Grimes setprompt(0); 9494b88c807SRodney W. Grimes c = pgetc(); 9504b88c807SRodney W. Grimes goto loop; /* continue outer loop */ 9514b88c807SRodney W. Grimes case CWORD: 9524b88c807SRodney W. Grimes USTPUTC(c, out); 9534b88c807SRodney W. Grimes break; 9544b88c807SRodney W. Grimes case CCTL: 9554b88c807SRodney W. Grimes if (eofmark == NULL || dblquote) 9564b88c807SRodney W. Grimes USTPUTC(CTLESC, out); 9574b88c807SRodney W. Grimes USTPUTC(c, out); 9584b88c807SRodney W. Grimes break; 9594b88c807SRodney W. Grimes case CBACK: /* backslash */ 9604b88c807SRodney W. Grimes c = pgetc(); 9614b88c807SRodney W. Grimes if (c == PEOF) { 9624b88c807SRodney W. Grimes USTPUTC('\\', out); 9634b88c807SRodney W. Grimes pungetc(); 9644b88c807SRodney W. Grimes } else if (c == '\n') { 9654b88c807SRodney W. Grimes if (doprompt) 9664b88c807SRodney W. Grimes setprompt(2); 9674b88c807SRodney W. Grimes else 9684b88c807SRodney W. Grimes setprompt(0); 9694b88c807SRodney W. Grimes } else { 97073f612b5SMartin Cracauer if (dblquote && c != '\\' && 97173f612b5SMartin Cracauer c != '`' && c != '$' && 97273f612b5SMartin Cracauer (c != '"' || eofmark != NULL)) 9734b88c807SRodney W. Grimes USTPUTC('\\', out); 9740c4eeddaSTor Egge if (SQSYNTAX[c] == CCTL) 9754b88c807SRodney W. Grimes USTPUTC(CTLESC, out); 9765557a02aSTor Egge else if (eofmark == NULL) 9776f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9784b88c807SRodney W. Grimes USTPUTC(c, out); 9794b88c807SRodney W. Grimes quotef++; 9804b88c807SRodney W. Grimes } 9814b88c807SRodney W. Grimes break; 9824b88c807SRodney W. Grimes case CSQUOTE: 9835557a02aSTor Egge if (eofmark == NULL) 9846f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9854b88c807SRodney W. Grimes syntax = SQSYNTAX; 9864b88c807SRodney W. Grimes break; 9874b88c807SRodney W. Grimes case CDQUOTE: 9885557a02aSTor Egge if (eofmark == NULL) 9896f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9904b88c807SRodney W. Grimes syntax = DQSYNTAX; 9914b88c807SRodney W. Grimes dblquote = 1; 9924b88c807SRodney W. Grimes break; 9934b88c807SRodney W. Grimes case CENDQUOTE: 9945557a02aSTor Egge if (eofmark != NULL && arinest == 0 && 9955557a02aSTor Egge varnest == 0) { 9964b88c807SRodney W. Grimes USTPUTC(c, out); 9974b88c807SRodney W. Grimes } else { 9985557a02aSTor Egge if (arinest) { 9994b88c807SRodney W. Grimes syntax = ARISYNTAX; 10004b88c807SRodney W. Grimes dblquote = 0; 10015557a02aSTor Egge } else if (eofmark == NULL) { 10025557a02aSTor Egge syntax = BASESYNTAX; 10035557a02aSTor Egge dblquote = 0; 10045557a02aSTor Egge } 10055557a02aSTor Egge quotef++; 10064b88c807SRodney W. Grimes } 10074b88c807SRodney W. Grimes break; 10084b88c807SRodney W. Grimes case CVAR: /* '$' */ 10094b88c807SRodney W. Grimes PARSESUB(); /* parse substitution */ 10104b88c807SRodney W. Grimes break; 10114b88c807SRodney W. Grimes case CENDVAR: /* '}' */ 10124b88c807SRodney W. Grimes if (varnest > 0) { 10134b88c807SRodney W. Grimes varnest--; 10144b88c807SRodney W. Grimes USTPUTC(CTLENDVAR, out); 10154b88c807SRodney W. Grimes } else { 10164b88c807SRodney W. Grimes USTPUTC(c, out); 10174b88c807SRodney W. Grimes } 10184b88c807SRodney W. Grimes break; 10194b88c807SRodney W. Grimes case CLP: /* '(' in arithmetic */ 10204b88c807SRodney W. Grimes parenlevel++; 10214b88c807SRodney W. Grimes USTPUTC(c, out); 10224b88c807SRodney W. Grimes break; 10234b88c807SRodney W. Grimes case CRP: /* ')' in arithmetic */ 10244b88c807SRodney W. Grimes if (parenlevel > 0) { 10254b88c807SRodney W. Grimes USTPUTC(c, out); 10264b88c807SRodney W. Grimes --parenlevel; 10274b88c807SRodney W. Grimes } else { 10284b88c807SRodney W. Grimes if (pgetc() == ')') { 10294b88c807SRodney W. Grimes if (--arinest == 0) { 10304b88c807SRodney W. Grimes USTPUTC(CTLENDARI, out); 10314b88c807SRodney W. Grimes syntax = prevsyntax; 10325557a02aSTor Egge if (syntax == DQSYNTAX) 10335557a02aSTor Egge dblquote = 1; 10345557a02aSTor Egge else 10355557a02aSTor Egge dblquote = 0; 10364b88c807SRodney W. Grimes } else 10374b88c807SRodney W. Grimes USTPUTC(')', out); 10384b88c807SRodney W. Grimes } else { 10394b88c807SRodney W. Grimes /* 10404b88c807SRodney W. Grimes * unbalanced parens 10414b88c807SRodney W. Grimes * (don't 2nd guess - no error) 10424b88c807SRodney W. Grimes */ 10434b88c807SRodney W. Grimes pungetc(); 10444b88c807SRodney W. Grimes USTPUTC(')', out); 10454b88c807SRodney W. Grimes } 10464b88c807SRodney W. Grimes } 10474b88c807SRodney W. Grimes break; 10484b88c807SRodney W. Grimes case CBQUOTE: /* '`' */ 10494b88c807SRodney W. Grimes PARSEBACKQOLD(); 10504b88c807SRodney W. Grimes break; 10514b88c807SRodney W. Grimes case CEOF: 10524b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 10534b88c807SRodney W. Grimes default: 10544b88c807SRodney W. Grimes if (varnest == 0) 10554b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 10564b88c807SRodney W. Grimes USTPUTC(c, out); 10574b88c807SRodney W. Grimes } 10584b88c807SRodney W. Grimes c = pgetc_macro(); 10594b88c807SRodney W. Grimes } 10604b88c807SRodney W. Grimes } 10614b88c807SRodney W. Grimes endword: 10624b88c807SRodney W. Grimes if (syntax == ARISYNTAX) 10634b88c807SRodney W. Grimes synerror("Missing '))'"); 10644b88c807SRodney W. Grimes if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 10654b88c807SRodney W. Grimes synerror("Unterminated quoted string"); 10664b88c807SRodney W. Grimes if (varnest != 0) { 10674b88c807SRodney W. Grimes startlinno = plinno; 10684b88c807SRodney W. Grimes synerror("Missing '}'"); 10694b88c807SRodney W. Grimes } 10704b88c807SRodney W. Grimes USTPUTC('\0', out); 10714b88c807SRodney W. Grimes len = out - stackblock(); 10724b88c807SRodney W. Grimes out = stackblock(); 10734b88c807SRodney W. Grimes if (eofmark == NULL) { 10744b88c807SRodney W. Grimes if ((c == '>' || c == '<') 10754b88c807SRodney W. Grimes && quotef == 0 10764b88c807SRodney W. Grimes && len <= 2 10774b88c807SRodney W. Grimes && (*out == '\0' || is_digit(*out))) { 10784b88c807SRodney W. Grimes PARSEREDIR(); 10794b88c807SRodney W. Grimes return lasttoken = TREDIR; 10804b88c807SRodney W. Grimes } else { 10814b88c807SRodney W. Grimes pungetc(); 10824b88c807SRodney W. Grimes } 10834b88c807SRodney W. Grimes } 10844b88c807SRodney W. Grimes quoteflag = quotef; 10854b88c807SRodney W. Grimes backquotelist = bqlist; 10864b88c807SRodney W. Grimes grabstackblock(len); 10874b88c807SRodney W. Grimes wordtext = out; 10884b88c807SRodney W. Grimes return lasttoken = TWORD; 10894b88c807SRodney W. Grimes /* end of readtoken routine */ 10904b88c807SRodney W. Grimes 10914b88c807SRodney W. Grimes 10924b88c807SRodney W. Grimes 10934b88c807SRodney W. Grimes /* 10944b88c807SRodney W. Grimes * Check to see whether we are at the end of the here document. When this 10954b88c807SRodney W. Grimes * is called, c is set to the first character of the next input line. If 10964b88c807SRodney W. Grimes * we are at the end of the here document, this routine sets the c to PEOF. 10974b88c807SRodney W. Grimes */ 10984b88c807SRodney W. Grimes 10994b88c807SRodney W. Grimes checkend: { 11004b88c807SRodney W. Grimes if (eofmark) { 11014b88c807SRodney W. Grimes if (striptabs) { 11024b88c807SRodney W. Grimes while (c == '\t') 11034b88c807SRodney W. Grimes c = pgetc(); 11044b88c807SRodney W. Grimes } 11054b88c807SRodney W. Grimes if (c == *eofmark) { 11064b88c807SRodney W. Grimes if (pfgets(line, sizeof line) != NULL) { 11077920a31dSSteve Price char *p, *q; 11084b88c807SRodney W. Grimes 11094b88c807SRodney W. Grimes p = line; 11104b88c807SRodney W. Grimes for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 11114b88c807SRodney W. Grimes if (*p == '\n' && *q == '\0') { 11124b88c807SRodney W. Grimes c = PEOF; 11134b88c807SRodney W. Grimes plinno++; 11144b88c807SRodney W. Grimes needprompt = doprompt; 11154b88c807SRodney W. Grimes } else { 11164b88c807SRodney W. Grimes pushstring(line, strlen(line), NULL); 11174b88c807SRodney W. Grimes } 11184b88c807SRodney W. Grimes } 11194b88c807SRodney W. Grimes } 11204b88c807SRodney W. Grimes } 11214b88c807SRodney W. Grimes goto checkend_return; 11224b88c807SRodney W. Grimes } 11234b88c807SRodney W. Grimes 11244b88c807SRodney W. Grimes 11254b88c807SRodney W. Grimes /* 11264b88c807SRodney W. Grimes * Parse a redirection operator. The variable "out" points to a string 11274b88c807SRodney W. Grimes * specifying the fd to be redirected. The variable "c" contains the 11284b88c807SRodney W. Grimes * first character of the redirection operator. 11294b88c807SRodney W. Grimes */ 11304b88c807SRodney W. Grimes 11314b88c807SRodney W. Grimes parseredir: { 11324b88c807SRodney W. Grimes char fd = *out; 11334b88c807SRodney W. Grimes union node *np; 11344b88c807SRodney W. Grimes 11354b88c807SRodney W. Grimes np = (union node *)stalloc(sizeof (struct nfile)); 11364b88c807SRodney W. Grimes if (c == '>') { 11374b88c807SRodney W. Grimes np->nfile.fd = 1; 11384b88c807SRodney W. Grimes c = pgetc(); 11394b88c807SRodney W. Grimes if (c == '>') 11404b88c807SRodney W. Grimes np->type = NAPPEND; 11414b88c807SRodney W. Grimes else if (c == '&') 11424b88c807SRodney W. Grimes np->type = NTOFD; 11431a958c66STim J. Robbins else if (c == '|') 11441a958c66STim J. Robbins np->type = NCLOBBER; 11454b88c807SRodney W. Grimes else { 11464b88c807SRodney W. Grimes np->type = NTO; 11474b88c807SRodney W. Grimes pungetc(); 11484b88c807SRodney W. Grimes } 11494b88c807SRodney W. Grimes } else { /* c == '<' */ 11504b88c807SRodney W. Grimes np->nfile.fd = 0; 11514b88c807SRodney W. Grimes c = pgetc(); 11524b88c807SRodney W. Grimes if (c == '<') { 11534b88c807SRodney W. Grimes if (sizeof (struct nfile) != sizeof (struct nhere)) { 11544b88c807SRodney W. Grimes np = (union node *)stalloc(sizeof (struct nhere)); 11554b88c807SRodney W. Grimes np->nfile.fd = 0; 11564b88c807SRodney W. Grimes } 11574b88c807SRodney W. Grimes np->type = NHERE; 11584b88c807SRodney W. Grimes heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 11594b88c807SRodney W. Grimes heredoc->here = np; 11604b88c807SRodney W. Grimes if ((c = pgetc()) == '-') { 11614b88c807SRodney W. Grimes heredoc->striptabs = 1; 11624b88c807SRodney W. Grimes } else { 11634b88c807SRodney W. Grimes heredoc->striptabs = 0; 11644b88c807SRodney W. Grimes pungetc(); 11654b88c807SRodney W. Grimes } 11664b88c807SRodney W. Grimes } else if (c == '&') 11674b88c807SRodney W. Grimes np->type = NFROMFD; 11684682f420SBrian Somers else if (c == '>') 11694682f420SBrian Somers np->type = NFROMTO; 11704b88c807SRodney W. Grimes else { 11714b88c807SRodney W. Grimes np->type = NFROM; 11724b88c807SRodney W. Grimes pungetc(); 11734b88c807SRodney W. Grimes } 11744b88c807SRodney W. Grimes } 11754b88c807SRodney W. Grimes if (fd != '\0') 11764b88c807SRodney W. Grimes np->nfile.fd = digit_val(fd); 11774b88c807SRodney W. Grimes redirnode = np; 11784b88c807SRodney W. Grimes goto parseredir_return; 11794b88c807SRodney W. Grimes } 11804b88c807SRodney W. Grimes 11814b88c807SRodney W. Grimes 11824b88c807SRodney W. Grimes /* 11834b88c807SRodney W. Grimes * Parse a substitution. At this point, we have read the dollar sign 11844b88c807SRodney W. Grimes * and nothing else. 11854b88c807SRodney W. Grimes */ 11864b88c807SRodney W. Grimes 11874b88c807SRodney W. Grimes parsesub: { 11884b88c807SRodney W. Grimes int subtype; 11894b88c807SRodney W. Grimes int typeloc; 11904b88c807SRodney W. Grimes int flags; 11914b88c807SRodney W. Grimes char *p; 11924b88c807SRodney W. Grimes #ifndef GDB_HACK 11934b88c807SRodney W. Grimes static const char types[] = "}-+?="; 11944b88c807SRodney W. Grimes #endif 11955c817731SPeter Wemm int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ 11964b88c807SRodney W. Grimes 11974b88c807SRodney W. Grimes c = pgetc(); 11984b88c807SRodney W. Grimes if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 11994b88c807SRodney W. Grimes USTPUTC('$', out); 12004b88c807SRodney W. Grimes pungetc(); 12014b88c807SRodney W. Grimes } else if (c == '(') { /* $(command) or $((arith)) */ 12024b88c807SRodney W. Grimes if (pgetc() == '(') { 12034b88c807SRodney W. Grimes PARSEARITH(); 12044b88c807SRodney W. Grimes } else { 12054b88c807SRodney W. Grimes pungetc(); 12064b88c807SRodney W. Grimes PARSEBACKQNEW(); 12074b88c807SRodney W. Grimes } 12084b88c807SRodney W. Grimes } else { 12094b88c807SRodney W. Grimes USTPUTC(CTLVAR, out); 12104b88c807SRodney W. Grimes typeloc = out - stackblock(); 12114b88c807SRodney W. Grimes USTPUTC(VSNORMAL, out); 12124b88c807SRodney W. Grimes subtype = VSNORMAL; 12134b88c807SRodney W. Grimes if (c == '{') { 12145c817731SPeter Wemm bracketed_name = 1; 12154b88c807SRodney W. Grimes c = pgetc(); 1216aa9caaf6SPeter Wemm if (c == '#') { 1217aa9caaf6SPeter Wemm if ((c = pgetc()) == '}') 1218aa9caaf6SPeter Wemm c = '#'; 1219aa9caaf6SPeter Wemm else 1220aa9caaf6SPeter Wemm subtype = VSLENGTH; 1221aa9caaf6SPeter Wemm } 1222aa9caaf6SPeter Wemm else 12234b88c807SRodney W. Grimes subtype = 0; 12244b88c807SRodney W. Grimes } 12254b88c807SRodney W. Grimes if (is_name(c)) { 12264b88c807SRodney W. Grimes do { 12274b88c807SRodney W. Grimes STPUTC(c, out); 12284b88c807SRodney W. Grimes c = pgetc(); 12294b88c807SRodney W. Grimes } while (is_in_name(c)); 12305c817731SPeter Wemm } else if (is_digit(c)) { 12315c817731SPeter Wemm if (bracketed_name) { 12325c817731SPeter Wemm do { 12335c817731SPeter Wemm STPUTC(c, out); 12345c817731SPeter Wemm c = pgetc(); 12355c817731SPeter Wemm } while (is_digit(c)); 12365c817731SPeter Wemm } else { 12375c817731SPeter Wemm STPUTC(c, out); 12385c817731SPeter Wemm c = pgetc(); 12395c817731SPeter Wemm } 12404b88c807SRodney W. Grimes } else { 12414b88c807SRodney W. Grimes if (! is_special(c)) 12424b88c807SRodney W. Grimes badsub: synerror("Bad substitution"); 12434b88c807SRodney W. Grimes USTPUTC(c, out); 12444b88c807SRodney W. Grimes c = pgetc(); 12454b88c807SRodney W. Grimes } 12464b88c807SRodney W. Grimes STPUTC('=', out); 12474b88c807SRodney W. Grimes flags = 0; 12484b88c807SRodney W. Grimes if (subtype == 0) { 1249aa9caaf6SPeter Wemm switch (c) { 1250aa9caaf6SPeter Wemm case ':': 12514b88c807SRodney W. Grimes flags = VSNUL; 12524b88c807SRodney W. Grimes c = pgetc(); 1253aa9caaf6SPeter Wemm /*FALLTHROUGH*/ 1254aa9caaf6SPeter Wemm default: 12554b88c807SRodney W. Grimes p = strchr(types, c); 12564b88c807SRodney W. Grimes if (p == NULL) 12574b88c807SRodney W. Grimes goto badsub; 12584b88c807SRodney W. Grimes subtype = p - types + VSNORMAL; 1259aa9caaf6SPeter Wemm break; 1260aa9caaf6SPeter Wemm case '%': 1261aa9caaf6SPeter Wemm case '#': 1262aa9caaf6SPeter Wemm { 1263aa9caaf6SPeter Wemm int cc = c; 1264aa9caaf6SPeter Wemm subtype = c == '#' ? VSTRIMLEFT : 1265aa9caaf6SPeter Wemm VSTRIMRIGHT; 1266aa9caaf6SPeter Wemm c = pgetc(); 1267aa9caaf6SPeter Wemm if (c == cc) 1268aa9caaf6SPeter Wemm subtype++; 1269aa9caaf6SPeter Wemm else 1270aa9caaf6SPeter Wemm pungetc(); 1271aa9caaf6SPeter Wemm break; 1272aa9caaf6SPeter Wemm } 1273aa9caaf6SPeter Wemm } 12744b88c807SRodney W. Grimes } else { 12754b88c807SRodney W. Grimes pungetc(); 12764b88c807SRodney W. Grimes } 1277c11e75cfSMartin Cracauer if (subtype != VSLENGTH && (dblquote || arinest)) 12784b88c807SRodney W. Grimes flags |= VSQUOTE; 12794b88c807SRodney W. Grimes *(stackblock() + typeloc) = subtype | flags; 12804b88c807SRodney W. Grimes if (subtype != VSNORMAL) 12814b88c807SRodney W. Grimes varnest++; 12824b88c807SRodney W. Grimes } 12834b88c807SRodney W. Grimes goto parsesub_return; 12844b88c807SRodney W. Grimes } 12854b88c807SRodney W. Grimes 12864b88c807SRodney W. Grimes 12874b88c807SRodney W. Grimes /* 12884b88c807SRodney W. Grimes * Called to parse command substitutions. Newstyle is set if the command 12894b88c807SRodney W. Grimes * is enclosed inside $(...); nlpp is a pointer to the head of the linked 12904b88c807SRodney W. Grimes * list of commands (passed by reference), and savelen is the number of 12914b88c807SRodney W. Grimes * characters on the top of the stack which must be preserved. 12924b88c807SRodney W. Grimes */ 12934b88c807SRodney W. Grimes 12944b88c807SRodney W. Grimes parsebackq: { 12954b88c807SRodney W. Grimes struct nodelist **nlpp; 12964b88c807SRodney W. Grimes int savepbq; 12974b88c807SRodney W. Grimes union node *n; 12984b88c807SRodney W. Grimes char *volatile str; 12994b88c807SRodney W. Grimes struct jmploc jmploc; 13004b88c807SRodney W. Grimes struct jmploc *volatile savehandler; 13014b88c807SRodney W. Grimes int savelen; 1302ab0a2172SSteve Price int saveprompt; 1303ab0a2172SSteve Price #if __GNUC__ 1304ab0a2172SSteve Price /* Avoid longjmp clobbering */ 1305ab0a2172SSteve Price (void) &saveprompt; 1306ab0a2172SSteve Price #endif 13074b88c807SRodney W. Grimes 13084b88c807SRodney W. Grimes savepbq = parsebackquote; 13094b88c807SRodney W. Grimes if (setjmp(jmploc.loc)) { 13104b88c807SRodney W. Grimes if (str) 13114b88c807SRodney W. Grimes ckfree(str); 13124b88c807SRodney W. Grimes parsebackquote = 0; 13134b88c807SRodney W. Grimes handler = savehandler; 13144b88c807SRodney W. Grimes longjmp(handler->loc, 1); 13154b88c807SRodney W. Grimes } 13164b88c807SRodney W. Grimes INTOFF; 13174b88c807SRodney W. Grimes str = NULL; 13184b88c807SRodney W. Grimes savelen = out - stackblock(); 13194b88c807SRodney W. Grimes if (savelen > 0) { 13204b88c807SRodney W. Grimes str = ckmalloc(savelen); 1321aa9caaf6SPeter Wemm memcpy(str, stackblock(), savelen); 13224b88c807SRodney W. Grimes } 13234b88c807SRodney W. Grimes savehandler = handler; 13244b88c807SRodney W. Grimes handler = &jmploc; 13254b88c807SRodney W. Grimes INTON; 13264b88c807SRodney W. Grimes if (oldstyle) { 13274b88c807SRodney W. Grimes /* We must read until the closing backquote, giving special 13284b88c807SRodney W. Grimes treatment to some slashes, and then push the string and 13294b88c807SRodney W. Grimes reread it as input, interpreting it normally. */ 13307920a31dSSteve Price char *out; 13317920a31dSSteve Price int c; 13324b88c807SRodney W. Grimes int savelen; 13334b88c807SRodney W. Grimes char *str; 13344b88c807SRodney W. Grimes 1335ab0a2172SSteve Price 13364b88c807SRodney W. Grimes STARTSTACKSTR(out); 1337ab0a2172SSteve Price for (;;) { 1338ab0a2172SSteve Price if (needprompt) { 1339ab0a2172SSteve Price setprompt(2); 1340ab0a2172SSteve Price needprompt = 0; 134172348d41SJoerg Wunsch } 1342ab0a2172SSteve Price switch (c = pgetc()) { 1343ab0a2172SSteve Price case '`': 1344ab0a2172SSteve Price goto done; 1345ab0a2172SSteve Price 1346ab0a2172SSteve Price case '\\': 1347ab0a2172SSteve Price if ((c = pgetc()) == '\n') { 1348ab0a2172SSteve Price plinno++; 1349ab0a2172SSteve Price if (doprompt) 1350ab0a2172SSteve Price setprompt(2); 1351ab0a2172SSteve Price else 1352ab0a2172SSteve Price setprompt(0); 1353ab0a2172SSteve Price /* 1354ab0a2172SSteve Price * If eating a newline, avoid putting 1355ab0a2172SSteve Price * the newline into the new character 1356ab0a2172SSteve Price * stream (via the STPUTC after the 1357ab0a2172SSteve Price * switch). 1358ab0a2172SSteve Price */ 1359ab0a2172SSteve Price continue; 1360ab0a2172SSteve Price } 13611e95454eSPaul Richards if (c != '\\' && c != '`' && c != '$' 13624b88c807SRodney W. Grimes && (!dblquote || c != '"')) 13634b88c807SRodney W. Grimes STPUTC('\\', out); 1364ab0a2172SSteve Price break; 1365ab0a2172SSteve Price 1366ab0a2172SSteve Price case '\n': 1367ab0a2172SSteve Price plinno++; 1368ab0a2172SSteve Price needprompt = doprompt; 1369ab0a2172SSteve Price break; 1370ab0a2172SSteve Price 1371ab0a2172SSteve Price case PEOF: 1372ab0a2172SSteve Price startlinno = plinno; 1373ab0a2172SSteve Price synerror("EOF in backquote substitution"); 1374ab0a2172SSteve Price break; 1375ab0a2172SSteve Price 1376ab0a2172SSteve Price default: 1377ab0a2172SSteve Price break; 13784b88c807SRodney W. Grimes } 13794b88c807SRodney W. Grimes STPUTC(c, out); 13804b88c807SRodney W. Grimes } 1381ab0a2172SSteve Price done: 13824b88c807SRodney W. Grimes STPUTC('\0', out); 13834b88c807SRodney W. Grimes savelen = out - stackblock(); 13844b88c807SRodney W. Grimes if (savelen > 0) { 13854b88c807SRodney W. Grimes str = ckmalloc(savelen); 1386aa9caaf6SPeter Wemm memcpy(str, stackblock(), savelen); 13874b88c807SRodney W. Grimes setinputstring(str, 1); 13884b88c807SRodney W. Grimes } 1389aa9caaf6SPeter Wemm } 13904b88c807SRodney W. Grimes nlpp = &bqlist; 13914b88c807SRodney W. Grimes while (*nlpp) 13924b88c807SRodney W. Grimes nlpp = &(*nlpp)->next; 13934b88c807SRodney W. Grimes *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 13944b88c807SRodney W. Grimes (*nlpp)->next = NULL; 13954b88c807SRodney W. Grimes parsebackquote = oldstyle; 1396ab0a2172SSteve Price 1397ab0a2172SSteve Price if (oldstyle) { 1398ab0a2172SSteve Price saveprompt = doprompt; 1399ab0a2172SSteve Price doprompt = 0; 1400ab0a2172SSteve Price } 1401ab0a2172SSteve Price 14024b88c807SRodney W. Grimes n = list(0); 1403ab0a2172SSteve Price 14044b88c807SRodney W. Grimes if (oldstyle) 1405ab0a2172SSteve Price doprompt = saveprompt; 1406ab0a2172SSteve Price else { 1407ab0a2172SSteve Price if (readtoken() != TRP) 1408ab0a2172SSteve Price synexpect(TRP); 1409ab0a2172SSteve Price } 1410ab0a2172SSteve Price 1411ab0a2172SSteve Price (*nlpp)->n = n; 1412ab0a2172SSteve Price if (oldstyle) { 1413ab0a2172SSteve Price /* 1414ab0a2172SSteve Price * Start reading from old file again, ignoring any pushed back 1415ab0a2172SSteve Price * tokens left from the backquote parsing 1416ab0a2172SSteve Price */ 14174b88c807SRodney W. Grimes popfile(); 1418ab0a2172SSteve Price tokpushback = 0; 1419ab0a2172SSteve Price } 14204b88c807SRodney W. Grimes while (stackblocksize() <= savelen) 14214b88c807SRodney W. Grimes growstackblock(); 14224b88c807SRodney W. Grimes STARTSTACKSTR(out); 14234b88c807SRodney W. Grimes if (str) { 1424aa9caaf6SPeter Wemm memcpy(out, str, savelen); 14254b88c807SRodney W. Grimes STADJUST(savelen, out); 14264b88c807SRodney W. Grimes INTOFF; 14274b88c807SRodney W. Grimes ckfree(str); 14284b88c807SRodney W. Grimes str = NULL; 14294b88c807SRodney W. Grimes INTON; 14304b88c807SRodney W. Grimes } 14314b88c807SRodney W. Grimes parsebackquote = savepbq; 14324b88c807SRodney W. Grimes handler = savehandler; 14334b88c807SRodney W. Grimes if (arinest || dblquote) 14344b88c807SRodney W. Grimes USTPUTC(CTLBACKQ | CTLQUOTE, out); 14354b88c807SRodney W. Grimes else 14364b88c807SRodney W. Grimes USTPUTC(CTLBACKQ, out); 14374b88c807SRodney W. Grimes if (oldstyle) 14384b88c807SRodney W. Grimes goto parsebackq_oldreturn; 14394b88c807SRodney W. Grimes else 14404b88c807SRodney W. Grimes goto parsebackq_newreturn; 14414b88c807SRodney W. Grimes } 14424b88c807SRodney W. Grimes 14434b88c807SRodney W. Grimes /* 14444b88c807SRodney W. Grimes * Parse an arithmetic expansion (indicate start of one and set state) 14454b88c807SRodney W. Grimes */ 14464b88c807SRodney W. Grimes parsearith: { 14474b88c807SRodney W. Grimes 14484b88c807SRodney W. Grimes if (++arinest == 1) { 14494b88c807SRodney W. Grimes prevsyntax = syntax; 14504b88c807SRodney W. Grimes syntax = ARISYNTAX; 14514b88c807SRodney W. Grimes USTPUTC(CTLARI, out); 14526f47734fSTor Egge if (dblquote) 14536f47734fSTor Egge USTPUTC('"',out); 14546f47734fSTor Egge else 14556f47734fSTor Egge USTPUTC(' ',out); 14564b88c807SRodney W. Grimes } else { 14574b88c807SRodney W. Grimes /* 14584b88c807SRodney W. Grimes * we collapse embedded arithmetic expansion to 14594b88c807SRodney W. Grimes * parenthesis, which should be equivalent 14604b88c807SRodney W. Grimes */ 14614b88c807SRodney W. Grimes USTPUTC('(', out); 14624b88c807SRodney W. Grimes } 14634b88c807SRodney W. Grimes goto parsearith_return; 14644b88c807SRodney W. Grimes } 14654b88c807SRodney W. Grimes 14664b88c807SRodney W. Grimes } /* end of readtoken */ 14674b88c807SRodney W. Grimes 14684b88c807SRodney W. Grimes 14694b88c807SRodney W. Grimes 14704b88c807SRodney W. Grimes #ifdef mkinit 14714b88c807SRodney W. Grimes RESET { 14724b88c807SRodney W. Grimes tokpushback = 0; 14734b88c807SRodney W. Grimes checkkwd = 0; 14744b88c807SRodney W. Grimes } 14754b88c807SRodney W. Grimes #endif 14764b88c807SRodney W. Grimes 14774b88c807SRodney W. Grimes /* 14784b88c807SRodney W. Grimes * Returns true if the text contains nothing to expand (no dollar signs 14794b88c807SRodney W. Grimes * or backquotes). 14804b88c807SRodney W. Grimes */ 14814b88c807SRodney W. Grimes 14824b88c807SRodney W. Grimes STATIC int 14835134c3f7SWarner Losh noexpand(char *text) 14844b88c807SRodney W. Grimes { 14857920a31dSSteve Price char *p; 14867920a31dSSteve Price char c; 14874b88c807SRodney W. Grimes 14884b88c807SRodney W. Grimes p = text; 14894b88c807SRodney W. Grimes while ((c = *p++) != '\0') { 14905557a02aSTor Egge if ( c == CTLQUOTEMARK) 14915557a02aSTor Egge continue; 14924b88c807SRodney W. Grimes if (c == CTLESC) 14934b88c807SRodney W. Grimes p++; 14940c4eeddaSTor Egge else if (BASESYNTAX[(int)c] == CCTL) 14954b88c807SRodney W. Grimes return 0; 14964b88c807SRodney W. Grimes } 14974b88c807SRodney W. Grimes return 1; 14984b88c807SRodney W. Grimes } 14994b88c807SRodney W. Grimes 15004b88c807SRodney W. Grimes 15014b88c807SRodney W. Grimes /* 15024b88c807SRodney W. Grimes * Return true if the argument is a legal variable name (a letter or 15034b88c807SRodney W. Grimes * underscore followed by zero or more letters, underscores, and digits). 15044b88c807SRodney W. Grimes */ 15054b88c807SRodney W. Grimes 15064b88c807SRodney W. Grimes int 15075134c3f7SWarner Losh goodname(char *name) 15084b88c807SRodney W. Grimes { 15097920a31dSSteve Price char *p; 15104b88c807SRodney W. Grimes 15114b88c807SRodney W. Grimes p = name; 15124b88c807SRodney W. Grimes if (! is_name(*p)) 15134b88c807SRodney W. Grimes return 0; 15144b88c807SRodney W. Grimes while (*++p) { 15154b88c807SRodney W. Grimes if (! is_in_name(*p)) 15164b88c807SRodney W. Grimes return 0; 15174b88c807SRodney W. Grimes } 15184b88c807SRodney W. Grimes return 1; 15194b88c807SRodney W. Grimes } 15204b88c807SRodney W. Grimes 15214b88c807SRodney W. Grimes 15224b88c807SRodney W. Grimes /* 15234b88c807SRodney W. Grimes * Called when an unexpected token is read during the parse. The argument 15244b88c807SRodney W. Grimes * is the token that is expected, or -1 if more than one type of token can 15254b88c807SRodney W. Grimes * occur at this point. 15264b88c807SRodney W. Grimes */ 15274b88c807SRodney W. Grimes 15284b88c807SRodney W. Grimes STATIC void 15295134c3f7SWarner Losh synexpect(int token) 1530aa9caaf6SPeter Wemm { 15314b88c807SRodney W. Grimes char msg[64]; 15324b88c807SRodney W. Grimes 15334b88c807SRodney W. Grimes if (token >= 0) { 15344b88c807SRodney W. Grimes fmtstr(msg, 64, "%s unexpected (expecting %s)", 15354b88c807SRodney W. Grimes tokname[lasttoken], tokname[token]); 15364b88c807SRodney W. Grimes } else { 15374b88c807SRodney W. Grimes fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 15384b88c807SRodney W. Grimes } 15394b88c807SRodney W. Grimes synerror(msg); 15404b88c807SRodney W. Grimes } 15414b88c807SRodney W. Grimes 15424b88c807SRodney W. Grimes 15434b88c807SRodney W. Grimes STATIC void 15445134c3f7SWarner Losh synerror(char *msg) 15454b88c807SRodney W. Grimes { 15464b88c807SRodney W. Grimes if (commandname) 15474b88c807SRodney W. Grimes outfmt(&errout, "%s: %d: ", commandname, startlinno); 15484b88c807SRodney W. Grimes outfmt(&errout, "Syntax error: %s\n", msg); 15494b88c807SRodney W. Grimes error((char *)NULL); 15504b88c807SRodney W. Grimes } 15514b88c807SRodney W. Grimes 15524b88c807SRodney W. Grimes STATIC void 15535134c3f7SWarner Losh setprompt(int which) 15544b88c807SRodney W. Grimes { 15554b88c807SRodney W. Grimes whichprompt = which; 15564b88c807SRodney W. Grimes 1557aa9caaf6SPeter Wemm #ifndef NO_HISTORY 15584b88c807SRodney W. Grimes if (!el) 1559aa9caaf6SPeter Wemm #endif 15604b88c807SRodney W. Grimes out2str(getprompt(NULL)); 15614b88c807SRodney W. Grimes } 15624b88c807SRodney W. Grimes 15634b88c807SRodney W. Grimes /* 15644b88c807SRodney W. Grimes * called by editline -- any expansions to the prompt 15654b88c807SRodney W. Grimes * should be added here. 15664b88c807SRodney W. Grimes */ 15674b88c807SRodney W. Grimes char * 15685134c3f7SWarner Losh getprompt(void *unused __unused) 15694b88c807SRodney W. Grimes { 15704b88c807SRodney W. Grimes switch (whichprompt) { 15714b88c807SRodney W. Grimes case 0: 15724b88c807SRodney W. Grimes return ""; 15734b88c807SRodney W. Grimes case 1: 15744b88c807SRodney W. Grimes return ps1val(); 15754b88c807SRodney W. Grimes case 2: 15764b88c807SRodney W. Grimes return ps2val(); 15774b88c807SRodney W. Grimes default: 15784b88c807SRodney W. Grimes return "<internal prompt error>"; 15794b88c807SRodney W. Grimes } 15804b88c807SRodney W. Grimes } 1581