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 * 4. Neither the name of the University nor the names of its contributors 174b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 184b88c807SRodney W. Grimes * without specific prior written permission. 194b88c807SRodney W. Grimes * 204b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 214b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 244b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304b88c807SRodney W. Grimes * SUCH DAMAGE. 314b88c807SRodney W. Grimes */ 324b88c807SRodney W. Grimes 334b88c807SRodney W. Grimes #ifndef lint 343d7b5b93SPhilippe Charnier #if 0 353d7b5b93SPhilippe Charnier static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; 363d7b5b93SPhilippe Charnier #endif 374b88c807SRodney W. Grimes #endif /* not lint */ 382749b141SDavid E. O'Brien #include <sys/cdefs.h> 392749b141SDavid E. O'Brien __FBSDID("$FreeBSD$"); 404b88c807SRodney W. Grimes 41aa9caaf6SPeter Wemm #include <stdlib.h> 42955e9f68SStefan Farfeleder #include <unistd.h> 43aa9caaf6SPeter Wemm 444b88c807SRodney W. Grimes #include "shell.h" 454b88c807SRodney W. Grimes #include "parser.h" 464b88c807SRodney W. Grimes #include "nodes.h" 474b88c807SRodney W. Grimes #include "expand.h" /* defines rmescapes() */ 484b88c807SRodney W. Grimes #include "syntax.h" 494b88c807SRodney W. Grimes #include "options.h" 504b88c807SRodney W. Grimes #include "input.h" 514b88c807SRodney W. Grimes #include "output.h" 524b88c807SRodney W. Grimes #include "var.h" 534b88c807SRodney W. Grimes #include "error.h" 544b88c807SRodney W. Grimes #include "memalloc.h" 554b88c807SRodney W. Grimes #include "mystring.h" 564b88c807SRodney W. Grimes #include "alias.h" 57aa9caaf6SPeter Wemm #include "show.h" 58f01e3d0cSMartin Cracauer #include "eval.h" 59aa9caaf6SPeter Wemm #ifndef NO_HISTORY 604b88c807SRodney W. Grimes #include "myhistedit.h" 61aa9caaf6SPeter Wemm #endif 624b88c807SRodney W. Grimes 634b88c807SRodney W. Grimes /* 644b88c807SRodney W. Grimes * Shell command parser. 654b88c807SRodney W. Grimes */ 664b88c807SRodney W. Grimes 674b88c807SRodney W. Grimes #define EOFMARKLEN 79 68f0c73601SDavid E. O'Brien #define PROMPTLEN 128 694b88c807SRodney W. Grimes 704b88c807SRodney W. Grimes /* values returned by readtoken */ 71aa9caaf6SPeter Wemm #include "token.h" 724b88c807SRodney W. Grimes 734b88c807SRodney W. Grimes 744b88c807SRodney W. Grimes 754b88c807SRodney W. Grimes struct heredoc { 764b88c807SRodney W. Grimes struct heredoc *next; /* next here document in list */ 774b88c807SRodney W. Grimes union node *here; /* redirection node */ 784b88c807SRodney W. Grimes char *eofmark; /* string indicating end of input */ 794b88c807SRodney W. Grimes int striptabs; /* if set, strip leading tabs */ 804b88c807SRodney W. Grimes }; 814b88c807SRodney W. Grimes 824b88c807SRodney W. Grimes 834b88c807SRodney W. Grimes 842ba1b30bSDiomidis Spinellis STATIC struct heredoc *heredoclist; /* list of here documents to read */ 852ba1b30bSDiomidis Spinellis STATIC int parsebackquote; /* nonzero if we are inside backquotes */ 862ba1b30bSDiomidis Spinellis STATIC int doprompt; /* if set, prompt the user */ 872ba1b30bSDiomidis Spinellis STATIC int needprompt; /* true if interactive and at start of line */ 882ba1b30bSDiomidis Spinellis STATIC int lasttoken; /* last token read */ 894b88c807SRodney W. Grimes MKINIT int tokpushback; /* last token pushed back */ 902ba1b30bSDiomidis Spinellis STATIC char *wordtext; /* text of last word returned by readtoken */ 914b88c807SRodney W. Grimes MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 922ba1b30bSDiomidis Spinellis STATIC struct nodelist *backquotelist; 932ba1b30bSDiomidis Spinellis STATIC union node *redirnode; 942ba1b30bSDiomidis Spinellis STATIC struct heredoc *heredoc; 952ba1b30bSDiomidis Spinellis STATIC int quoteflag; /* set if (part of) last token was quoted */ 962ba1b30bSDiomidis Spinellis STATIC int startlinno; /* line # where last token started */ 97b71085aaSStefan Farfeleder STATIC int funclinno; /* line # where the current function started */ 984b88c807SRodney W. Grimes 994417f629SPeter Wemm /* XXX When 'noaliases' is set to one, no alias expansion takes place. */ 1004417f629SPeter Wemm static int noaliases = 0; 1014b88c807SRodney W. Grimes 1024b88c807SRodney W. Grimes 1035134c3f7SWarner Losh STATIC union node *list(int); 1045134c3f7SWarner Losh STATIC union node *andor(void); 1055134c3f7SWarner Losh STATIC union node *pipeline(void); 1065134c3f7SWarner Losh STATIC union node *command(void); 1075134c3f7SWarner Losh STATIC union node *simplecmd(union node **, union node *); 1085134c3f7SWarner Losh STATIC union node *makename(void); 1095134c3f7SWarner Losh STATIC void parsefname(void); 1105134c3f7SWarner Losh STATIC void parseheredoc(void); 1115134c3f7SWarner Losh STATIC int peektoken(void); 1125134c3f7SWarner Losh STATIC int readtoken(void); 1135134c3f7SWarner Losh STATIC int xxreadtoken(void); 1145134c3f7SWarner Losh STATIC int readtoken1(int, char const *, char *, int); 1155134c3f7SWarner Losh STATIC int noexpand(char *); 1165134c3f7SWarner Losh STATIC void synexpect(int); 1175134c3f7SWarner Losh STATIC void synerror(char *); 1185134c3f7SWarner Losh STATIC void setprompt(int); 1194b88c807SRodney W. Grimes 120aa9caaf6SPeter Wemm 1214b88c807SRodney W. Grimes /* 1224b88c807SRodney W. Grimes * Read and parse a command. Returns NEOF on end of file. (NULL is a 1234b88c807SRodney W. Grimes * valid parse tree indicating a blank line.) 1244b88c807SRodney W. Grimes */ 1254b88c807SRodney W. Grimes 1264b88c807SRodney W. Grimes union node * 1275134c3f7SWarner Losh parsecmd(int interact) 128aa9caaf6SPeter Wemm { 1294b88c807SRodney W. Grimes int t; 1304b88c807SRodney W. Grimes 13198e05fd3SMartin Cracauer tokpushback = 0; 1324b88c807SRodney W. Grimes doprompt = interact; 1334b88c807SRodney W. Grimes if (doprompt) 1344b88c807SRodney W. Grimes setprompt(1); 1354b88c807SRodney W. Grimes else 1364b88c807SRodney W. Grimes setprompt(0); 1374b88c807SRodney W. Grimes needprompt = 0; 1384b88c807SRodney W. Grimes t = readtoken(); 1394b88c807SRodney W. Grimes if (t == TEOF) 1404b88c807SRodney W. Grimes return NEOF; 1414b88c807SRodney W. Grimes if (t == TNL) 1424b88c807SRodney W. Grimes return NULL; 1434b88c807SRodney W. Grimes tokpushback++; 1444b88c807SRodney W. Grimes return list(1); 1454b88c807SRodney W. Grimes } 1464b88c807SRodney W. Grimes 1474b88c807SRodney W. Grimes 1484b88c807SRodney W. Grimes STATIC union node * 1495134c3f7SWarner Losh list(int nlflag) 150aa9caaf6SPeter Wemm { 1514b88c807SRodney W. Grimes union node *n1, *n2, *n3; 152aa9caaf6SPeter Wemm int tok; 1534b88c807SRodney W. Grimes 1544b88c807SRodney W. Grimes checkkwd = 2; 1554b88c807SRodney W. Grimes if (nlflag == 0 && tokendlist[peektoken()]) 1564b88c807SRodney W. Grimes return NULL; 157aa9caaf6SPeter Wemm n1 = NULL; 1584b88c807SRodney W. Grimes for (;;) { 1594b88c807SRodney W. Grimes n2 = andor(); 160aa9caaf6SPeter Wemm tok = readtoken(); 161aa9caaf6SPeter Wemm if (tok == TBACKGND) { 162aa9caaf6SPeter Wemm if (n2->type == NCMD || n2->type == NPIPE) { 163aa9caaf6SPeter Wemm n2->ncmd.backgnd = 1; 164aa9caaf6SPeter Wemm } else if (n2->type == NREDIR) { 165aa9caaf6SPeter Wemm n2->type = NBACKGND; 166aa9caaf6SPeter Wemm } else { 167aa9caaf6SPeter Wemm n3 = (union node *)stalloc(sizeof (struct nredir)); 168aa9caaf6SPeter Wemm n3->type = NBACKGND; 169aa9caaf6SPeter Wemm n3->nredir.n = n2; 170aa9caaf6SPeter Wemm n3->nredir.redirect = NULL; 171aa9caaf6SPeter Wemm n2 = n3; 172aa9caaf6SPeter Wemm } 173aa9caaf6SPeter Wemm } 174aa9caaf6SPeter Wemm if (n1 == NULL) { 175aa9caaf6SPeter Wemm n1 = n2; 176aa9caaf6SPeter Wemm } 177aa9caaf6SPeter Wemm else { 1784b88c807SRodney W. Grimes n3 = (union node *)stalloc(sizeof (struct nbinary)); 1794b88c807SRodney W. Grimes n3->type = NSEMI; 1804b88c807SRodney W. Grimes n3->nbinary.ch1 = n1; 1814b88c807SRodney W. Grimes n3->nbinary.ch2 = n2; 1824b88c807SRodney W. Grimes n1 = n3; 183aa9caaf6SPeter Wemm } 184aa9caaf6SPeter Wemm switch (tok) { 185aa9caaf6SPeter Wemm case TBACKGND: 186aa9caaf6SPeter Wemm case TSEMI: 187aa9caaf6SPeter Wemm tok = readtoken(); 1880d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 189aa9caaf6SPeter Wemm case TNL: 190aa9caaf6SPeter Wemm if (tok == TNL) { 191aa9caaf6SPeter Wemm parseheredoc(); 192aa9caaf6SPeter Wemm if (nlflag) 193aa9caaf6SPeter Wemm return n1; 194aa9caaf6SPeter Wemm } else { 195aa9caaf6SPeter Wemm tokpushback++; 196aa9caaf6SPeter Wemm } 197aa9caaf6SPeter Wemm checkkwd = 2; 198aa9caaf6SPeter Wemm if (tokendlist[peektoken()]) 199aa9caaf6SPeter Wemm return n1; 2004b88c807SRodney W. Grimes break; 2014b88c807SRodney W. Grimes case TEOF: 2024b88c807SRodney W. Grimes if (heredoclist) 2034b88c807SRodney W. Grimes parseheredoc(); 2044b88c807SRodney W. Grimes else 2054b88c807SRodney W. Grimes pungetc(); /* push back EOF on input */ 2064b88c807SRodney W. Grimes return n1; 2074b88c807SRodney W. Grimes default: 2084b88c807SRodney W. Grimes if (nlflag) 2094b88c807SRodney W. Grimes synexpect(-1); 2104b88c807SRodney W. Grimes tokpushback++; 2114b88c807SRodney W. Grimes return n1; 2124b88c807SRodney W. Grimes } 2134b88c807SRodney W. Grimes } 2144b88c807SRodney W. Grimes } 2154b88c807SRodney W. Grimes 2164b88c807SRodney W. Grimes 2174b88c807SRodney W. Grimes 2184b88c807SRodney W. Grimes STATIC union node * 2195134c3f7SWarner Losh andor(void) 2205134c3f7SWarner Losh { 2214b88c807SRodney W. Grimes union node *n1, *n2, *n3; 2224b88c807SRodney W. Grimes int t; 2234b88c807SRodney W. Grimes 2244b88c807SRodney W. Grimes n1 = pipeline(); 2254b88c807SRodney W. Grimes for (;;) { 2264b88c807SRodney W. Grimes if ((t = readtoken()) == TAND) { 2274b88c807SRodney W. Grimes t = NAND; 2284b88c807SRodney W. Grimes } else if (t == TOR) { 2294b88c807SRodney W. Grimes t = NOR; 2304b88c807SRodney W. Grimes } else { 2314b88c807SRodney W. Grimes tokpushback++; 2324b88c807SRodney W. Grimes return n1; 2334b88c807SRodney W. Grimes } 2344b88c807SRodney W. Grimes n2 = pipeline(); 2354b88c807SRodney W. Grimes n3 = (union node *)stalloc(sizeof (struct nbinary)); 2364b88c807SRodney W. Grimes n3->type = t; 2374b88c807SRodney W. Grimes n3->nbinary.ch1 = n1; 2384b88c807SRodney W. Grimes n3->nbinary.ch2 = n2; 2394b88c807SRodney W. Grimes n1 = n3; 2404b88c807SRodney W. Grimes } 2414b88c807SRodney W. Grimes } 2424b88c807SRodney W. Grimes 2434b88c807SRodney W. Grimes 2444b88c807SRodney W. Grimes 2454b88c807SRodney W. Grimes STATIC union node * 2465134c3f7SWarner Losh pipeline(void) 2475134c3f7SWarner Losh { 248b785bd7dSBrian Somers union node *n1, *n2, *pipenode; 2494b88c807SRodney W. Grimes struct nodelist *lp, *prev; 250b785bd7dSBrian Somers int negate; 2514b88c807SRodney W. Grimes 252b785bd7dSBrian Somers negate = 0; 2534b88c807SRodney W. Grimes TRACE(("pipeline: entered\n")); 254b785bd7dSBrian Somers while (readtoken() == TNOT) 255b785bd7dSBrian Somers negate = !negate; 256b785bd7dSBrian Somers tokpushback++; 2574b88c807SRodney W. Grimes n1 = command(); 2584b88c807SRodney W. Grimes if (readtoken() == TPIPE) { 2594b88c807SRodney W. Grimes pipenode = (union node *)stalloc(sizeof (struct npipe)); 2604b88c807SRodney W. Grimes pipenode->type = NPIPE; 2614b88c807SRodney W. Grimes pipenode->npipe.backgnd = 0; 2624b88c807SRodney W. Grimes lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 2634b88c807SRodney W. Grimes pipenode->npipe.cmdlist = lp; 2644b88c807SRodney W. Grimes lp->n = n1; 2654b88c807SRodney W. Grimes do { 2664b88c807SRodney W. Grimes prev = lp; 2674b88c807SRodney W. Grimes lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 2684b88c807SRodney W. Grimes lp->n = command(); 2694b88c807SRodney W. Grimes prev->next = lp; 2704b88c807SRodney W. Grimes } while (readtoken() == TPIPE); 2714b88c807SRodney W. Grimes lp->next = NULL; 2724b88c807SRodney W. Grimes n1 = pipenode; 2734b88c807SRodney W. Grimes } 2744b88c807SRodney W. Grimes tokpushback++; 275b785bd7dSBrian Somers if (negate) { 276b785bd7dSBrian Somers n2 = (union node *)stalloc(sizeof (struct nnot)); 277b785bd7dSBrian Somers n2->type = NNOT; 278b785bd7dSBrian Somers n2->nnot.com = n1; 279b785bd7dSBrian Somers return n2; 280b785bd7dSBrian Somers } else 2814b88c807SRodney W. Grimes return n1; 2824b88c807SRodney W. Grimes } 2834b88c807SRodney W. Grimes 2844b88c807SRodney W. Grimes 2854b88c807SRodney W. Grimes 2864b88c807SRodney W. Grimes STATIC union node * 2875134c3f7SWarner Losh command(void) 2885134c3f7SWarner Losh { 2894b88c807SRodney W. Grimes union node *n1, *n2; 2904b88c807SRodney W. Grimes union node *ap, **app; 2914b88c807SRodney W. Grimes union node *cp, **cpp; 2924b88c807SRodney W. Grimes union node *redir, **rpp; 2936c0bde79SBrian Somers int t, negate = 0; 2944b88c807SRodney W. Grimes 2954b88c807SRodney W. Grimes checkkwd = 2; 296aa9caaf6SPeter Wemm redir = NULL; 297aa9caaf6SPeter Wemm n1 = NULL; 2984b88c807SRodney W. Grimes rpp = &redir; 299ab0a2172SSteve Price 3004b88c807SRodney W. Grimes /* Check for redirection which may precede command */ 3014b88c807SRodney W. Grimes while (readtoken() == TREDIR) { 3024b88c807SRodney W. Grimes *rpp = n2 = redirnode; 3034b88c807SRodney W. Grimes rpp = &n2->nfile.next; 3044b88c807SRodney W. Grimes parsefname(); 3054b88c807SRodney W. Grimes } 3064b88c807SRodney W. Grimes tokpushback++; 3074b88c807SRodney W. Grimes 3086c0bde79SBrian Somers while (readtoken() == TNOT) { 3096c0bde79SBrian Somers TRACE(("command: TNOT recognized\n")); 3106c0bde79SBrian Somers negate = !negate; 3116c0bde79SBrian Somers } 3126c0bde79SBrian Somers tokpushback++; 3136c0bde79SBrian Somers 3144b88c807SRodney W. Grimes switch (readtoken()) { 3154b88c807SRodney W. Grimes case TIF: 3164b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nif)); 3174b88c807SRodney W. Grimes n1->type = NIF; 318427748f7STim J. Robbins if ((n1->nif.test = list(0)) == NULL) 319427748f7STim J. Robbins synexpect(-1); 3204b88c807SRodney W. Grimes if (readtoken() != TTHEN) 3214b88c807SRodney W. Grimes synexpect(TTHEN); 3224b88c807SRodney W. Grimes n1->nif.ifpart = list(0); 3234b88c807SRodney W. Grimes n2 = n1; 3244b88c807SRodney W. Grimes while (readtoken() == TELIF) { 3254b88c807SRodney W. Grimes n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 3264b88c807SRodney W. Grimes n2 = n2->nif.elsepart; 3274b88c807SRodney W. Grimes n2->type = NIF; 328427748f7STim J. Robbins if ((n2->nif.test = list(0)) == NULL) 329427748f7STim J. Robbins synexpect(-1); 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; 349427748f7STim J. Robbins if ((n1->nbinary.ch1 = list(0)) == NULL) 350427748f7STim J. Robbins synexpect(-1); 3514b88c807SRodney W. Grimes if ((got=readtoken()) != TDO) { 3524b88c807SRodney W. Grimes TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 3534b88c807SRodney W. Grimes synexpect(TDO); 3544b88c807SRodney W. Grimes } 3554b88c807SRodney W. Grimes n1->nbinary.ch2 = list(0); 3564b88c807SRodney W. Grimes if (readtoken() != TDONE) 3574b88c807SRodney W. Grimes synexpect(TDONE); 3584b88c807SRodney W. Grimes checkkwd = 1; 3594b88c807SRodney W. Grimes break; 3604b88c807SRodney W. Grimes } 3614b88c807SRodney W. Grimes case TFOR: 3624b88c807SRodney W. Grimes if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 3634b88c807SRodney W. Grimes synerror("Bad for loop variable"); 3644b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nfor)); 3654b88c807SRodney W. Grimes n1->type = NFOR; 3664b88c807SRodney W. Grimes n1->nfor.var = wordtext; 3674b88c807SRodney W. Grimes if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 3684b88c807SRodney W. Grimes app = ≈ 3694b88c807SRodney W. Grimes while (readtoken() == TWORD) { 3704b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct narg)); 3714b88c807SRodney W. Grimes n2->type = NARG; 3724b88c807SRodney W. Grimes n2->narg.text = wordtext; 3734b88c807SRodney W. Grimes n2->narg.backquote = backquotelist; 3744b88c807SRodney W. Grimes *app = n2; 3754b88c807SRodney W. Grimes app = &n2->narg.next; 3764b88c807SRodney W. Grimes } 3774b88c807SRodney W. Grimes *app = NULL; 3784b88c807SRodney W. Grimes n1->nfor.args = ap; 3794b88c807SRodney W. Grimes if (lasttoken != TNL && lasttoken != TSEMI) 3804b88c807SRodney W. Grimes synexpect(-1); 3814b88c807SRodney W. Grimes } else { 382811beb4bSStefan Farfeleder static char argvars[5] = { 383811beb4bSStefan Farfeleder CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 384811beb4bSStefan Farfeleder }; 3854b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct narg)); 3864b88c807SRodney W. Grimes n2->type = NARG; 387811beb4bSStefan Farfeleder n2->narg.text = 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(); 426e00e16adSTim J. Robbins while (lasttoken != TESAC) { 4274b88c807SRodney W. Grimes *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 4284b88c807SRodney W. Grimes cp->type = NCLIST; 4294b88c807SRodney W. Grimes app = &cp->nclist.pattern; 430f7a9b7feSTim J. Robbins if (lasttoken == TLP) 431f7a9b7feSTim J. Robbins readtoken(); 4324b88c807SRodney W. Grimes for (;;) { 4334b88c807SRodney W. Grimes *app = ap = (union node *)stalloc(sizeof (struct narg)); 4344b88c807SRodney W. Grimes ap->type = NARG; 4354b88c807SRodney W. Grimes ap->narg.text = wordtext; 4364b88c807SRodney W. Grimes ap->narg.backquote = backquotelist; 437650488feSSean Eric Fagan if (checkkwd = 2, readtoken() != TPIPE) 4384b88c807SRodney W. Grimes break; 4394b88c807SRodney W. Grimes app = &ap->narg.next; 440650488feSSean Eric Fagan readtoken(); 4414b88c807SRodney W. Grimes } 4424b88c807SRodney W. Grimes ap->narg.next = NULL; 4434b88c807SRodney W. Grimes if (lasttoken != TRP) 4444417f629SPeter Wemm noaliases = 0, synexpect(TRP); 4454b88c807SRodney W. Grimes cp->nclist.body = list(0); 446650488feSSean Eric Fagan 447650488feSSean Eric Fagan checkkwd = 2; 448650488feSSean Eric Fagan if ((t = readtoken()) != TESAC) { 449650488feSSean Eric Fagan if (t != TENDCASE) 4504417f629SPeter Wemm noaliases = 0, synexpect(TENDCASE); 451650488feSSean Eric Fagan else 452650488feSSean Eric Fagan checkkwd = 2, readtoken(); 4534b88c807SRodney W. Grimes } 454650488feSSean Eric Fagan cpp = &cp->nclist.next; 455e00e16adSTim J. Robbins } 4564417f629SPeter Wemm noaliases = 0; /* reset alias expansion */ 4574b88c807SRodney W. Grimes *cpp = NULL; 4584b88c807SRodney W. Grimes checkkwd = 1; 4594b88c807SRodney W. Grimes break; 4604b88c807SRodney W. Grimes case TLP: 4614b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nredir)); 4624b88c807SRodney W. Grimes n1->type = NSUBSHELL; 4634b88c807SRodney W. Grimes n1->nredir.n = list(0); 4644b88c807SRodney W. Grimes n1->nredir.redirect = NULL; 4654b88c807SRodney W. Grimes if (readtoken() != TRP) 4664b88c807SRodney W. Grimes synexpect(TRP); 4674b88c807SRodney W. Grimes checkkwd = 1; 4684b88c807SRodney W. Grimes break; 4694b88c807SRodney W. Grimes case TBEGIN: 4704b88c807SRodney W. Grimes n1 = list(0); 4714b88c807SRodney W. Grimes if (readtoken() != TEND) 4724b88c807SRodney W. Grimes synexpect(TEND); 4734b88c807SRodney W. Grimes checkkwd = 1; 4744b88c807SRodney W. Grimes break; 4754b88c807SRodney W. Grimes /* Handle an empty command like other simple commands. */ 476248ffae5SJoerg Wunsch case TSEMI: 477d8d737d7STim J. Robbins case TAND: 478d8d737d7STim J. Robbins case TOR: 479aa9caaf6SPeter Wemm /* 480aa9caaf6SPeter Wemm * An empty command before a ; doesn't make much sense, and 481aa9caaf6SPeter Wemm * should certainly be disallowed in the case of `if ;'. 482aa9caaf6SPeter Wemm */ 483aa9caaf6SPeter Wemm if (!redir) 484aa9caaf6SPeter Wemm synexpect(-1); 485aa9caaf6SPeter Wemm case TNL: 486248ffae5SJoerg Wunsch case TEOF: 4874b88c807SRodney W. Grimes case TWORD: 488aa9caaf6SPeter Wemm case TRP: 4894b88c807SRodney W. Grimes tokpushback++; 4906c0bde79SBrian Somers n1 = simplecmd(rpp, redir); 4916c0bde79SBrian Somers goto checkneg; 4924b88c807SRodney W. Grimes default: 4934b88c807SRodney W. Grimes synexpect(-1); 4944b88c807SRodney W. Grimes } 4954b88c807SRodney W. Grimes 4964b88c807SRodney W. Grimes /* Now check for redirection which may follow command */ 4974b88c807SRodney W. Grimes while (readtoken() == TREDIR) { 4984b88c807SRodney W. Grimes *rpp = n2 = redirnode; 4994b88c807SRodney W. Grimes rpp = &n2->nfile.next; 5004b88c807SRodney W. Grimes parsefname(); 5014b88c807SRodney W. Grimes } 5024b88c807SRodney W. Grimes tokpushback++; 5034b88c807SRodney W. Grimes *rpp = NULL; 5044b88c807SRodney W. Grimes if (redir) { 5054b88c807SRodney W. Grimes if (n1->type != NSUBSHELL) { 5064b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct nredir)); 5074b88c807SRodney W. Grimes n2->type = NREDIR; 5084b88c807SRodney W. Grimes n2->nredir.n = n1; 5094b88c807SRodney W. Grimes n1 = n2; 5104b88c807SRodney W. Grimes } 5114b88c807SRodney W. Grimes n1->nredir.redirect = redir; 5124b88c807SRodney W. Grimes } 5136c0bde79SBrian Somers 5146c0bde79SBrian Somers checkneg: 5156c0bde79SBrian Somers if (negate) { 5166c0bde79SBrian Somers n2 = (union node *)stalloc(sizeof (struct nnot)); 5176c0bde79SBrian Somers n2->type = NNOT; 5186c0bde79SBrian Somers n2->nnot.com = n1; 5196c0bde79SBrian Somers return n2; 5206c0bde79SBrian Somers } 5216c0bde79SBrian Somers else 5224b88c807SRodney W. Grimes return n1; 5234b88c807SRodney W. Grimes } 5244b88c807SRodney W. Grimes 5254b88c807SRodney W. Grimes 5264b88c807SRodney W. Grimes STATIC union node * 5275134c3f7SWarner Losh simplecmd(union node **rpp, union node *redir) 5284b88c807SRodney W. Grimes { 5294b88c807SRodney W. Grimes union node *args, **app; 5304b88c807SRodney W. Grimes union node **orig_rpp = rpp; 5316c0bde79SBrian Somers union node *n = NULL, *n2; 5326c0bde79SBrian Somers int negate = 0; 5334b88c807SRodney W. Grimes 5344b88c807SRodney W. Grimes /* If we don't have any redirections already, then we must reset */ 5354b88c807SRodney W. Grimes /* rpp to be the address of the local redir variable. */ 5364b88c807SRodney W. Grimes if (redir == 0) 5374b88c807SRodney W. Grimes rpp = &redir; 5384b88c807SRodney W. Grimes 5394b88c807SRodney W. Grimes args = NULL; 5404b88c807SRodney W. Grimes app = &args; 5414b88c807SRodney W. Grimes /* 5424b88c807SRodney W. Grimes * We save the incoming value, because we need this for shell 5434b88c807SRodney W. Grimes * functions. There can not be a redirect or an argument between 5444b88c807SRodney W. Grimes * the function name and the open parenthesis. 5454b88c807SRodney W. Grimes */ 5464b88c807SRodney W. Grimes orig_rpp = rpp; 5474b88c807SRodney W. Grimes 5486c0bde79SBrian Somers while (readtoken() == TNOT) { 5496c0bde79SBrian Somers TRACE(("command: TNOT recognized\n")); 5506c0bde79SBrian Somers negate = !negate; 5516c0bde79SBrian Somers } 5526c0bde79SBrian Somers tokpushback++; 5536c0bde79SBrian Somers 5544b88c807SRodney W. Grimes for (;;) { 5554b88c807SRodney W. Grimes if (readtoken() == TWORD) { 5564b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct narg)); 5574b88c807SRodney W. Grimes n->type = NARG; 5584b88c807SRodney W. Grimes n->narg.text = wordtext; 5594b88c807SRodney W. Grimes n->narg.backquote = backquotelist; 5604b88c807SRodney W. Grimes *app = n; 5614b88c807SRodney W. Grimes app = &n->narg.next; 5624b88c807SRodney W. Grimes } else if (lasttoken == TREDIR) { 5634b88c807SRodney W. Grimes *rpp = n = redirnode; 5644b88c807SRodney W. Grimes rpp = &n->nfile.next; 5654b88c807SRodney W. Grimes parsefname(); /* read name of redirection file */ 5664b88c807SRodney W. Grimes } else if (lasttoken == TLP && app == &args->narg.next 5674b88c807SRodney W. Grimes && rpp == orig_rpp) { 5684b88c807SRodney W. Grimes /* We have a function */ 5694b88c807SRodney W. Grimes if (readtoken() != TRP) 5704b88c807SRodney W. Grimes synexpect(TRP); 571b71085aaSStefan Farfeleder funclinno = plinno; 5724b88c807SRodney W. Grimes #ifdef notdef 5734b88c807SRodney W. Grimes if (! goodname(n->narg.text)) 5744b88c807SRodney W. Grimes synerror("Bad function name"); 5754b88c807SRodney W. Grimes #endif 5764b88c807SRodney W. Grimes n->type = NDEFUN; 5774b88c807SRodney W. Grimes n->narg.next = command(); 578b71085aaSStefan Farfeleder funclinno = 0; 5796c0bde79SBrian Somers goto checkneg; 5804b88c807SRodney W. Grimes } else { 5814b88c807SRodney W. Grimes tokpushback++; 5824b88c807SRodney W. Grimes break; 5834b88c807SRodney W. Grimes } 5844b88c807SRodney W. Grimes } 5854b88c807SRodney W. Grimes *app = NULL; 5864b88c807SRodney W. Grimes *rpp = NULL; 5874b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct ncmd)); 5884b88c807SRodney W. Grimes n->type = NCMD; 5894b88c807SRodney W. Grimes n->ncmd.backgnd = 0; 5904b88c807SRodney W. Grimes n->ncmd.args = args; 5914b88c807SRodney W. Grimes n->ncmd.redirect = redir; 5926c0bde79SBrian Somers 5936c0bde79SBrian Somers checkneg: 5946c0bde79SBrian Somers if (negate) { 5956c0bde79SBrian Somers n2 = (union node *)stalloc(sizeof (struct nnot)); 5966c0bde79SBrian Somers n2->type = NNOT; 5976c0bde79SBrian Somers n2->nnot.com = n; 5986c0bde79SBrian Somers return n2; 5996c0bde79SBrian Somers } 6006c0bde79SBrian Somers else 6014b88c807SRodney W. Grimes return n; 6024b88c807SRodney W. Grimes } 6034b88c807SRodney W. Grimes 604aa9caaf6SPeter Wemm STATIC union node * 6055134c3f7SWarner Losh makename(void) 6065134c3f7SWarner Losh { 607aa9caaf6SPeter Wemm union node *n; 608aa9caaf6SPeter Wemm 609aa9caaf6SPeter Wemm n = (union node *)stalloc(sizeof (struct narg)); 610aa9caaf6SPeter Wemm n->type = NARG; 611aa9caaf6SPeter Wemm n->narg.next = NULL; 612aa9caaf6SPeter Wemm n->narg.text = wordtext; 613aa9caaf6SPeter Wemm n->narg.backquote = backquotelist; 614aa9caaf6SPeter Wemm return n; 615aa9caaf6SPeter Wemm } 616aa9caaf6SPeter Wemm 6175134c3f7SWarner Losh void fixredir(union node *n, const char *text, int err) 618aa9caaf6SPeter Wemm { 619aa9caaf6SPeter Wemm TRACE(("Fix redir %s %d\n", text, err)); 620aa9caaf6SPeter Wemm if (!err) 621aa9caaf6SPeter Wemm n->ndup.vname = NULL; 622aa9caaf6SPeter Wemm 623aa9caaf6SPeter Wemm if (is_digit(text[0]) && text[1] == '\0') 624aa9caaf6SPeter Wemm n->ndup.dupfd = digit_val(text[0]); 625aa9caaf6SPeter Wemm else if (text[0] == '-' && text[1] == '\0') 626aa9caaf6SPeter Wemm n->ndup.dupfd = -1; 627aa9caaf6SPeter Wemm else { 628aa9caaf6SPeter Wemm 629aa9caaf6SPeter Wemm if (err) 630aa9caaf6SPeter Wemm synerror("Bad fd number"); 631aa9caaf6SPeter Wemm else 632aa9caaf6SPeter Wemm n->ndup.vname = makename(); 633aa9caaf6SPeter Wemm } 634aa9caaf6SPeter Wemm } 635aa9caaf6SPeter Wemm 6364b88c807SRodney W. Grimes 6374b88c807SRodney W. Grimes STATIC void 6385134c3f7SWarner Losh parsefname(void) 6395134c3f7SWarner Losh { 6404b88c807SRodney W. Grimes union node *n = redirnode; 6414b88c807SRodney W. Grimes 6424b88c807SRodney W. Grimes if (readtoken() != TWORD) 6434b88c807SRodney W. Grimes synexpect(-1); 6444b88c807SRodney W. Grimes if (n->type == NHERE) { 6454b88c807SRodney W. Grimes struct heredoc *here = heredoc; 6464b88c807SRodney W. Grimes struct heredoc *p; 6474b88c807SRodney W. Grimes int i; 6484b88c807SRodney W. Grimes 6494b88c807SRodney W. Grimes if (quoteflag == 0) 6504b88c807SRodney W. Grimes n->type = NXHERE; 6514b88c807SRodney W. Grimes TRACE(("Here document %d\n", n->type)); 6524b88c807SRodney W. Grimes if (here->striptabs) { 6534b88c807SRodney W. Grimes while (*wordtext == '\t') 6544b88c807SRodney W. Grimes wordtext++; 6554b88c807SRodney W. Grimes } 6564b88c807SRodney W. Grimes if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 6574b88c807SRodney W. Grimes synerror("Illegal eof marker for << redirection"); 6584b88c807SRodney W. Grimes rmescapes(wordtext); 6594b88c807SRodney W. Grimes here->eofmark = wordtext; 6604b88c807SRodney W. Grimes here->next = NULL; 6614b88c807SRodney W. Grimes if (heredoclist == NULL) 6624b88c807SRodney W. Grimes heredoclist = here; 6634b88c807SRodney W. Grimes else { 6644b88c807SRodney W. Grimes for (p = heredoclist ; p->next ; p = p->next); 6654b88c807SRodney W. Grimes p->next = here; 6664b88c807SRodney W. Grimes } 6674b88c807SRodney W. Grimes } else if (n->type == NTOFD || n->type == NFROMFD) { 668aa9caaf6SPeter Wemm fixredir(n, wordtext, 0); 6694b88c807SRodney W. Grimes } else { 670aa9caaf6SPeter Wemm n->nfile.fname = makename(); 6714b88c807SRodney W. Grimes } 6724b88c807SRodney W. Grimes } 6734b88c807SRodney W. Grimes 6744b88c807SRodney W. Grimes 6754b88c807SRodney W. Grimes /* 6764b88c807SRodney W. Grimes * Input any here documents. 6774b88c807SRodney W. Grimes */ 6784b88c807SRodney W. Grimes 6794b88c807SRodney W. Grimes STATIC void 6805134c3f7SWarner Losh parseheredoc(void) 6815134c3f7SWarner Losh { 6824b88c807SRodney W. Grimes struct heredoc *here; 6834b88c807SRodney W. Grimes union node *n; 6844b88c807SRodney W. Grimes 6854b88c807SRodney W. Grimes while (heredoclist) { 6864b88c807SRodney W. Grimes here = heredoclist; 6874b88c807SRodney W. Grimes heredoclist = here->next; 6884b88c807SRodney W. Grimes if (needprompt) { 6894b88c807SRodney W. Grimes setprompt(2); 6904b88c807SRodney W. Grimes needprompt = 0; 6914b88c807SRodney W. Grimes } 6924b88c807SRodney W. Grimes readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 6934b88c807SRodney W. Grimes here->eofmark, here->striptabs); 6944b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct narg)); 6954b88c807SRodney W. Grimes n->narg.type = NARG; 6964b88c807SRodney W. Grimes n->narg.next = NULL; 6974b88c807SRodney W. Grimes n->narg.text = wordtext; 6984b88c807SRodney W. Grimes n->narg.backquote = backquotelist; 6994b88c807SRodney W. Grimes here->here->nhere.doc = n; 7004b88c807SRodney W. Grimes } 7014b88c807SRodney W. Grimes } 7024b88c807SRodney W. Grimes 7034b88c807SRodney W. Grimes STATIC int 7045134c3f7SWarner Losh peektoken(void) 7055134c3f7SWarner Losh { 7064b88c807SRodney W. Grimes int t; 7074b88c807SRodney W. Grimes 7084b88c807SRodney W. Grimes t = readtoken(); 7094b88c807SRodney W. Grimes tokpushback++; 7104b88c807SRodney W. Grimes return (t); 7114b88c807SRodney W. Grimes } 7124b88c807SRodney W. Grimes 7134b88c807SRodney W. Grimes STATIC int 7145134c3f7SWarner Losh readtoken(void) 7155134c3f7SWarner Losh { 7164b88c807SRodney W. Grimes int t; 7174b88c807SRodney W. Grimes int savecheckkwd = checkkwd; 7184b88c807SRodney W. Grimes struct alias *ap; 7194b88c807SRodney W. Grimes #ifdef DEBUG 7204b88c807SRodney W. Grimes int alreadyseen = tokpushback; 7214b88c807SRodney W. Grimes #endif 7224b88c807SRodney W. Grimes 7234b88c807SRodney W. Grimes top: 7244b88c807SRodney W. Grimes t = xxreadtoken(); 7254b88c807SRodney W. Grimes 7264b88c807SRodney W. Grimes if (checkkwd) { 7274b88c807SRodney W. Grimes /* 7284b88c807SRodney W. Grimes * eat newlines 7294b88c807SRodney W. Grimes */ 7304b88c807SRodney W. Grimes if (checkkwd == 2) { 7314b88c807SRodney W. Grimes checkkwd = 0; 7324b88c807SRodney W. Grimes while (t == TNL) { 7334b88c807SRodney W. Grimes parseheredoc(); 7344b88c807SRodney W. Grimes t = xxreadtoken(); 7354b88c807SRodney W. Grimes } 7364b88c807SRodney W. Grimes } else 7374b88c807SRodney W. Grimes checkkwd = 0; 7384b88c807SRodney W. Grimes /* 7394b88c807SRodney W. Grimes * check for keywords and aliases 7404b88c807SRodney W. Grimes */ 741aa9caaf6SPeter Wemm if (t == TWORD && !quoteflag) 742aa9caaf6SPeter Wemm { 7438b7808bcSJuli Mallett const char * const *pp; 7444b88c807SRodney W. Grimes 7458b7808bcSJuli Mallett for (pp = parsekwd; *pp; pp++) { 746aa9caaf6SPeter Wemm if (**pp == *wordtext && equal(*pp, wordtext)) 747aa9caaf6SPeter Wemm { 7484b88c807SRodney W. Grimes lasttoken = t = pp - parsekwd + KWDOFFSET; 7494b88c807SRodney W. Grimes TRACE(("keyword %s recognized\n", tokname[t])); 7504b88c807SRodney W. Grimes goto out; 7514b88c807SRodney W. Grimes } 7524b88c807SRodney W. Grimes } 7534417f629SPeter Wemm if (noaliases == 0 && 7544417f629SPeter Wemm (ap = lookupalias(wordtext, 1)) != NULL) { 7554b88c807SRodney W. Grimes pushstring(ap->val, strlen(ap->val), ap); 7564b88c807SRodney W. Grimes checkkwd = savecheckkwd; 7574b88c807SRodney W. Grimes goto top; 7584b88c807SRodney W. Grimes } 7594b88c807SRodney W. Grimes } 7604b88c807SRodney W. Grimes out: 7616c0bde79SBrian Somers checkkwd = (t == TNOT) ? savecheckkwd : 0; 7624b88c807SRodney W. Grimes } 7634b88c807SRodney W. Grimes #ifdef DEBUG 7644b88c807SRodney W. Grimes if (!alreadyseen) 7654b88c807SRodney W. Grimes TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 7664b88c807SRodney W. Grimes else 7674b88c807SRodney W. Grimes TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 7684b88c807SRodney W. Grimes #endif 7694b88c807SRodney W. Grimes return (t); 7704b88c807SRodney W. Grimes } 7714b88c807SRodney W. Grimes 7724b88c807SRodney W. Grimes 7734b88c807SRodney W. Grimes /* 7744b88c807SRodney W. Grimes * Read the next input token. 7754b88c807SRodney W. Grimes * If the token is a word, we set backquotelist to the list of cmds in 7764b88c807SRodney W. Grimes * backquotes. We set quoteflag to true if any part of the word was 7774b88c807SRodney W. Grimes * quoted. 7784b88c807SRodney W. Grimes * If the token is TREDIR, then we set redirnode to a structure containing 7794b88c807SRodney W. Grimes * the redirection. 7804b88c807SRodney W. Grimes * In all cases, the variable startlinno is set to the number of the line 7814b88c807SRodney W. Grimes * on which the token starts. 7824b88c807SRodney W. Grimes * 7834b88c807SRodney W. Grimes * [Change comment: here documents and internal procedures] 7844b88c807SRodney W. Grimes * [Readtoken shouldn't have any arguments. Perhaps we should make the 7854b88c807SRodney W. Grimes * word parsing code into a separate routine. In this case, readtoken 7864b88c807SRodney W. Grimes * doesn't need to have any internal procedures, but parseword does. 7874b88c807SRodney W. Grimes * We could also make parseoperator in essence the main routine, and 7884b88c807SRodney W. Grimes * have parseword (readtoken1?) handle both words and redirection.] 7894b88c807SRodney W. Grimes */ 7904b88c807SRodney W. Grimes 7914b88c807SRodney W. Grimes #define RETURN(token) return lasttoken = token 7924b88c807SRodney W. Grimes 7934b88c807SRodney W. Grimes STATIC int 7945134c3f7SWarner Losh xxreadtoken(void) 7955134c3f7SWarner Losh { 7967920a31dSSteve Price int c; 7974b88c807SRodney W. Grimes 7984b88c807SRodney W. Grimes if (tokpushback) { 7994b88c807SRodney W. Grimes tokpushback = 0; 8004b88c807SRodney W. Grimes return lasttoken; 8014b88c807SRodney W. Grimes } 8024b88c807SRodney W. Grimes if (needprompt) { 8034b88c807SRodney W. Grimes setprompt(2); 8044b88c807SRodney W. Grimes needprompt = 0; 8054b88c807SRodney W. Grimes } 8064b88c807SRodney W. Grimes startlinno = plinno; 8074b88c807SRodney W. Grimes for (;;) { /* until token or start of word found */ 8084b88c807SRodney W. Grimes c = pgetc_macro(); 8094b88c807SRodney W. Grimes if (c == ' ' || c == '\t') 8104b88c807SRodney W. Grimes continue; /* quick check for white space first */ 8114b88c807SRodney W. Grimes switch (c) { 8124b88c807SRodney W. Grimes case ' ': case '\t': 8134b88c807SRodney W. Grimes continue; 8144b88c807SRodney W. Grimes case '#': 8154b88c807SRodney W. Grimes while ((c = pgetc()) != '\n' && c != PEOF); 8164b88c807SRodney W. Grimes pungetc(); 8174b88c807SRodney W. Grimes continue; 8184b88c807SRodney W. Grimes case '\\': 8194b88c807SRodney W. Grimes if (pgetc() == '\n') { 8204b88c807SRodney W. Grimes startlinno = ++plinno; 8214b88c807SRodney W. Grimes if (doprompt) 8224b88c807SRodney W. Grimes setprompt(2); 8234b88c807SRodney W. Grimes else 8244b88c807SRodney W. Grimes setprompt(0); 8254b88c807SRodney W. Grimes continue; 8264b88c807SRodney W. Grimes } 8274b88c807SRodney W. Grimes pungetc(); 8284b88c807SRodney W. Grimes goto breakloop; 8294b88c807SRodney W. Grimes case '\n': 8304b88c807SRodney W. Grimes plinno++; 8314b88c807SRodney W. Grimes needprompt = doprompt; 8324b88c807SRodney W. Grimes RETURN(TNL); 8334b88c807SRodney W. Grimes case PEOF: 8344b88c807SRodney W. Grimes RETURN(TEOF); 8354b88c807SRodney W. Grimes case '&': 8364b88c807SRodney W. Grimes if (pgetc() == '&') 8374b88c807SRodney W. Grimes RETURN(TAND); 8384b88c807SRodney W. Grimes pungetc(); 8394b88c807SRodney W. Grimes RETURN(TBACKGND); 8404b88c807SRodney W. Grimes case '|': 8414b88c807SRodney W. Grimes if (pgetc() == '|') 8424b88c807SRodney W. Grimes RETURN(TOR); 8434b88c807SRodney W. Grimes pungetc(); 8444b88c807SRodney W. Grimes RETURN(TPIPE); 8454b88c807SRodney W. Grimes case ';': 8464b88c807SRodney W. Grimes if (pgetc() == ';') 8474b88c807SRodney W. Grimes RETURN(TENDCASE); 8484b88c807SRodney W. Grimes pungetc(); 8494b88c807SRodney W. Grimes RETURN(TSEMI); 8504b88c807SRodney W. Grimes case '(': 8514b88c807SRodney W. Grimes RETURN(TLP); 8524b88c807SRodney W. Grimes case ')': 8534b88c807SRodney W. Grimes RETURN(TRP); 8544b88c807SRodney W. Grimes default: 8554b88c807SRodney W. Grimes goto breakloop; 8564b88c807SRodney W. Grimes } 8574b88c807SRodney W. Grimes } 8584b88c807SRodney W. Grimes breakloop: 8594b88c807SRodney W. Grimes return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 8604b88c807SRodney W. Grimes #undef RETURN 8614b88c807SRodney W. Grimes } 8624b88c807SRodney W. Grimes 8634b88c807SRodney W. Grimes 8644b88c807SRodney W. Grimes 8654b88c807SRodney W. Grimes /* 8664b88c807SRodney W. Grimes * If eofmark is NULL, read a word or a redirection symbol. If eofmark 8674b88c807SRodney W. Grimes * is not NULL, read a here document. In the latter case, eofmark is the 8684b88c807SRodney W. Grimes * word which marks the end of the document and striptabs is true if 8694b88c807SRodney W. Grimes * leading tabs should be stripped from the document. The argument firstc 8704b88c807SRodney W. Grimes * is the first character of the input token or document. 8714b88c807SRodney W. Grimes * 8724b88c807SRodney W. Grimes * Because C does not have internal subroutines, I have simulated them 8734b88c807SRodney W. Grimes * using goto's to implement the subroutine linkage. The following macros 8744b88c807SRodney W. Grimes * will run code that appears at the end of readtoken1. 8754b88c807SRodney W. Grimes */ 8764b88c807SRodney W. Grimes 8774b88c807SRodney W. Grimes #define CHECKEND() {goto checkend; checkend_return:;} 8784b88c807SRodney W. Grimes #define PARSEREDIR() {goto parseredir; parseredir_return:;} 8794b88c807SRodney W. Grimes #define PARSESUB() {goto parsesub; parsesub_return:;} 8804b88c807SRodney W. Grimes #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 8814b88c807SRodney W. Grimes #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 8824b88c807SRodney W. Grimes #define PARSEARITH() {goto parsearith; parsearith_return:;} 8834b88c807SRodney W. Grimes 8844b88c807SRodney W. Grimes STATIC int 8855134c3f7SWarner Losh readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) 8864b88c807SRodney W. Grimes { 887aa9caaf6SPeter Wemm int c = firstc; 888aa9caaf6SPeter Wemm char *out; 8894b88c807SRodney W. Grimes int len; 8904b88c807SRodney W. Grimes char line[EOFMARKLEN + 1]; 8914b88c807SRodney W. Grimes struct nodelist *bqlist; 8924b88c807SRodney W. Grimes int quotef; 8934b88c807SRodney W. Grimes int dblquote; 8944b88c807SRodney W. Grimes int varnest; /* levels of variables expansion */ 8954b88c807SRodney W. Grimes int arinest; /* levels of arithmetic expansion */ 8964b88c807SRodney W. Grimes int parenlevel; /* levels of parens in arithmetic */ 8974b88c807SRodney W. Grimes int oldstyle; 8984b88c807SRodney W. Grimes char const *prevsyntax; /* syntax before arithmetic */ 8992dde9ce3SMartin Cracauer int synentry; 900aa9caaf6SPeter Wemm #if __GNUC__ 901aa9caaf6SPeter Wemm /* Avoid longjmp clobbering */ 902aa9caaf6SPeter Wemm (void) &out; 903aa9caaf6SPeter Wemm (void) "ef; 904aa9caaf6SPeter Wemm (void) &dblquote; 905aa9caaf6SPeter Wemm (void) &varnest; 906aa9caaf6SPeter Wemm (void) &arinest; 907aa9caaf6SPeter Wemm (void) &parenlevel; 908aa9caaf6SPeter Wemm (void) &oldstyle; 909aa9caaf6SPeter Wemm (void) &prevsyntax; 910aa9caaf6SPeter Wemm (void) &syntax; 9112dde9ce3SMartin Cracauer (void) &synentry; 912aa9caaf6SPeter Wemm #endif 9134b88c807SRodney W. Grimes 9144b88c807SRodney W. Grimes startlinno = plinno; 9154b88c807SRodney W. Grimes dblquote = 0; 9164b88c807SRodney W. Grimes if (syntax == DQSYNTAX) 9174b88c807SRodney W. Grimes dblquote = 1; 9184b88c807SRodney W. Grimes quotef = 0; 9194b88c807SRodney W. Grimes bqlist = NULL; 9204b88c807SRodney W. Grimes varnest = 0; 9214b88c807SRodney W. Grimes arinest = 0; 9224b88c807SRodney W. Grimes parenlevel = 0; 9234b88c807SRodney W. Grimes 9244b88c807SRodney W. Grimes STARTSTACKSTR(out); 9254b88c807SRodney W. Grimes loop: { /* for each line, until end of word */ 9264b88c807SRodney W. Grimes CHECKEND(); /* set c to PEOF if at end of here document */ 9274b88c807SRodney W. Grimes for (;;) { /* until end of line or end of word */ 9284b88c807SRodney W. Grimes CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 9292dde9ce3SMartin Cracauer 9302dde9ce3SMartin Cracauer synentry = syntax[c]; 9312dde9ce3SMartin Cracauer 9322dde9ce3SMartin Cracauer switch(synentry) { 9334b88c807SRodney W. Grimes case CNL: /* '\n' */ 9344b88c807SRodney W. Grimes if (syntax == BASESYNTAX) 9354b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 9364b88c807SRodney W. Grimes USTPUTC(c, out); 9374b88c807SRodney W. Grimes plinno++; 9384b88c807SRodney W. Grimes if (doprompt) 9394b88c807SRodney W. Grimes setprompt(2); 9404b88c807SRodney W. Grimes else 9414b88c807SRodney W. Grimes setprompt(0); 9424b88c807SRodney W. Grimes c = pgetc(); 9434b88c807SRodney W. Grimes goto loop; /* continue outer loop */ 9444b88c807SRodney W. Grimes case CWORD: 9454b88c807SRodney W. Grimes USTPUTC(c, out); 9464b88c807SRodney W. Grimes break; 9474b88c807SRodney W. Grimes case CCTL: 9484b88c807SRodney W. Grimes if (eofmark == NULL || dblquote) 9494b88c807SRodney W. Grimes USTPUTC(CTLESC, out); 9504b88c807SRodney W. Grimes USTPUTC(c, out); 9514b88c807SRodney W. Grimes break; 9524b88c807SRodney W. Grimes case CBACK: /* backslash */ 9534b88c807SRodney W. Grimes c = pgetc(); 9544b88c807SRodney W. Grimes if (c == PEOF) { 9554b88c807SRodney W. Grimes USTPUTC('\\', out); 9564b88c807SRodney W. Grimes pungetc(); 9574b88c807SRodney W. Grimes } else if (c == '\n') { 95862f9f953SYaroslav Tykhiy plinno++; 9594b88c807SRodney W. Grimes if (doprompt) 9604b88c807SRodney W. Grimes setprompt(2); 9614b88c807SRodney W. Grimes else 9624b88c807SRodney W. Grimes setprompt(0); 9634b88c807SRodney W. Grimes } else { 96473f612b5SMartin Cracauer if (dblquote && c != '\\' && 96573f612b5SMartin Cracauer c != '`' && c != '$' && 96673f612b5SMartin Cracauer (c != '"' || eofmark != NULL)) 9674b88c807SRodney W. Grimes USTPUTC('\\', out); 9680c4eeddaSTor Egge if (SQSYNTAX[c] == CCTL) 9694b88c807SRodney W. Grimes USTPUTC(CTLESC, out); 9705557a02aSTor Egge else if (eofmark == NULL) 9716f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9724b88c807SRodney W. Grimes USTPUTC(c, out); 9734b88c807SRodney W. Grimes quotef++; 9744b88c807SRodney W. Grimes } 9754b88c807SRodney W. Grimes break; 9764b88c807SRodney W. Grimes case CSQUOTE: 9775557a02aSTor Egge if (eofmark == NULL) 9786f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9794b88c807SRodney W. Grimes syntax = SQSYNTAX; 9804b88c807SRodney W. Grimes break; 9814b88c807SRodney W. Grimes case CDQUOTE: 9825557a02aSTor Egge if (eofmark == NULL) 9836f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 9844b88c807SRodney W. Grimes syntax = DQSYNTAX; 9854b88c807SRodney W. Grimes dblquote = 1; 9864b88c807SRodney W. Grimes break; 9874b88c807SRodney W. Grimes case CENDQUOTE: 9885557a02aSTor Egge if (eofmark != NULL && arinest == 0 && 9895557a02aSTor Egge varnest == 0) { 9904b88c807SRodney W. Grimes USTPUTC(c, out); 9914b88c807SRodney W. Grimes } else { 9925557a02aSTor Egge if (arinest) { 9934b88c807SRodney W. Grimes syntax = ARISYNTAX; 9944b88c807SRodney W. Grimes dblquote = 0; 9955557a02aSTor Egge } else if (eofmark == NULL) { 9965557a02aSTor Egge syntax = BASESYNTAX; 9975557a02aSTor Egge dblquote = 0; 9985557a02aSTor Egge } 9995557a02aSTor Egge quotef++; 10004b88c807SRodney W. Grimes } 10014b88c807SRodney W. Grimes break; 10024b88c807SRodney W. Grimes case CVAR: /* '$' */ 10034b88c807SRodney W. Grimes PARSESUB(); /* parse substitution */ 10044b88c807SRodney W. Grimes break; 10054b88c807SRodney W. Grimes case CENDVAR: /* '}' */ 10064b88c807SRodney W. Grimes if (varnest > 0) { 10074b88c807SRodney W. Grimes varnest--; 10084b88c807SRodney W. Grimes USTPUTC(CTLENDVAR, out); 10094b88c807SRodney W. Grimes } else { 10104b88c807SRodney W. Grimes USTPUTC(c, out); 10114b88c807SRodney W. Grimes } 10124b88c807SRodney W. Grimes break; 10134b88c807SRodney W. Grimes case CLP: /* '(' in arithmetic */ 10144b88c807SRodney W. Grimes parenlevel++; 10154b88c807SRodney W. Grimes USTPUTC(c, out); 10164b88c807SRodney W. Grimes break; 10174b88c807SRodney W. Grimes case CRP: /* ')' in arithmetic */ 10184b88c807SRodney W. Grimes if (parenlevel > 0) { 10194b88c807SRodney W. Grimes USTPUTC(c, out); 10204b88c807SRodney W. Grimes --parenlevel; 10214b88c807SRodney W. Grimes } else { 10224b88c807SRodney W. Grimes if (pgetc() == ')') { 10234b88c807SRodney W. Grimes if (--arinest == 0) { 10244b88c807SRodney W. Grimes USTPUTC(CTLENDARI, out); 10254b88c807SRodney W. Grimes syntax = prevsyntax; 10265557a02aSTor Egge if (syntax == DQSYNTAX) 10275557a02aSTor Egge dblquote = 1; 10285557a02aSTor Egge else 10295557a02aSTor Egge dblquote = 0; 10304b88c807SRodney W. Grimes } else 10314b88c807SRodney W. Grimes USTPUTC(')', out); 10324b88c807SRodney W. Grimes } else { 10334b88c807SRodney W. Grimes /* 10344b88c807SRodney W. Grimes * unbalanced parens 10354b88c807SRodney W. Grimes * (don't 2nd guess - no error) 10364b88c807SRodney W. Grimes */ 10374b88c807SRodney W. Grimes pungetc(); 10384b88c807SRodney W. Grimes USTPUTC(')', out); 10394b88c807SRodney W. Grimes } 10404b88c807SRodney W. Grimes } 10414b88c807SRodney W. Grimes break; 10424b88c807SRodney W. Grimes case CBQUOTE: /* '`' */ 10434b88c807SRodney W. Grimes PARSEBACKQOLD(); 10444b88c807SRodney W. Grimes break; 10454b88c807SRodney W. Grimes case CEOF: 10464b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 10474b88c807SRodney W. Grimes default: 10484b88c807SRodney W. Grimes if (varnest == 0) 10494b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 10504b88c807SRodney W. Grimes USTPUTC(c, out); 10514b88c807SRodney W. Grimes } 10524b88c807SRodney W. Grimes c = pgetc_macro(); 10534b88c807SRodney W. Grimes } 10544b88c807SRodney W. Grimes } 10554b88c807SRodney W. Grimes endword: 10564b88c807SRodney W. Grimes if (syntax == ARISYNTAX) 10574b88c807SRodney W. Grimes synerror("Missing '))'"); 10584b88c807SRodney W. Grimes if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 10594b88c807SRodney W. Grimes synerror("Unterminated quoted string"); 10604b88c807SRodney W. Grimes if (varnest != 0) { 10614b88c807SRodney W. Grimes startlinno = plinno; 10624b88c807SRodney W. Grimes synerror("Missing '}'"); 10634b88c807SRodney W. Grimes } 10644b88c807SRodney W. Grimes USTPUTC('\0', out); 10654b88c807SRodney W. Grimes len = out - stackblock(); 10664b88c807SRodney W. Grimes out = stackblock(); 10674b88c807SRodney W. Grimes if (eofmark == NULL) { 10684b88c807SRodney W. Grimes if ((c == '>' || c == '<') 10694b88c807SRodney W. Grimes && quotef == 0 10704b88c807SRodney W. Grimes && len <= 2 10714b88c807SRodney W. Grimes && (*out == '\0' || is_digit(*out))) { 10724b88c807SRodney W. Grimes PARSEREDIR(); 10734b88c807SRodney W. Grimes return lasttoken = TREDIR; 10744b88c807SRodney W. Grimes } else { 10754b88c807SRodney W. Grimes pungetc(); 10764b88c807SRodney W. Grimes } 10774b88c807SRodney W. Grimes } 10784b88c807SRodney W. Grimes quoteflag = quotef; 10794b88c807SRodney W. Grimes backquotelist = bqlist; 10804b88c807SRodney W. Grimes grabstackblock(len); 10814b88c807SRodney W. Grimes wordtext = out; 10824b88c807SRodney W. Grimes return lasttoken = TWORD; 10834b88c807SRodney W. Grimes /* end of readtoken routine */ 10844b88c807SRodney W. Grimes 10854b88c807SRodney W. Grimes 10864b88c807SRodney W. Grimes 10874b88c807SRodney W. Grimes /* 10884b88c807SRodney W. Grimes * Check to see whether we are at the end of the here document. When this 10894b88c807SRodney W. Grimes * is called, c is set to the first character of the next input line. If 10904b88c807SRodney W. Grimes * we are at the end of the here document, this routine sets the c to PEOF. 10914b88c807SRodney W. Grimes */ 10924b88c807SRodney W. Grimes 10934b88c807SRodney W. Grimes checkend: { 10944b88c807SRodney W. Grimes if (eofmark) { 10954b88c807SRodney W. Grimes if (striptabs) { 10964b88c807SRodney W. Grimes while (c == '\t') 10974b88c807SRodney W. Grimes c = pgetc(); 10984b88c807SRodney W. Grimes } 10994b88c807SRodney W. Grimes if (c == *eofmark) { 11004b88c807SRodney W. Grimes if (pfgets(line, sizeof line) != NULL) { 11017920a31dSSteve Price char *p, *q; 11024b88c807SRodney W. Grimes 11034b88c807SRodney W. Grimes p = line; 11044b88c807SRodney W. Grimes for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 11054b88c807SRodney W. Grimes if (*p == '\n' && *q == '\0') { 11064b88c807SRodney W. Grimes c = PEOF; 11074b88c807SRodney W. Grimes plinno++; 11084b88c807SRodney W. Grimes needprompt = doprompt; 11094b88c807SRodney W. Grimes } else { 11104b88c807SRodney W. Grimes pushstring(line, strlen(line), NULL); 11114b88c807SRodney W. Grimes } 11124b88c807SRodney W. Grimes } 11134b88c807SRodney W. Grimes } 11144b88c807SRodney W. Grimes } 11154b88c807SRodney W. Grimes goto checkend_return; 11164b88c807SRodney W. Grimes } 11174b88c807SRodney W. Grimes 11184b88c807SRodney W. Grimes 11194b88c807SRodney W. Grimes /* 11204b88c807SRodney W. Grimes * Parse a redirection operator. The variable "out" points to a string 11214b88c807SRodney W. Grimes * specifying the fd to be redirected. The variable "c" contains the 11224b88c807SRodney W. Grimes * first character of the redirection operator. 11234b88c807SRodney W. Grimes */ 11244b88c807SRodney W. Grimes 11254b88c807SRodney W. Grimes parseredir: { 11264b88c807SRodney W. Grimes char fd = *out; 11274b88c807SRodney W. Grimes union node *np; 11284b88c807SRodney W. Grimes 11294b88c807SRodney W. Grimes np = (union node *)stalloc(sizeof (struct nfile)); 11304b88c807SRodney W. Grimes if (c == '>') { 11314b88c807SRodney W. Grimes np->nfile.fd = 1; 11324b88c807SRodney W. Grimes c = pgetc(); 11334b88c807SRodney W. Grimes if (c == '>') 11344b88c807SRodney W. Grimes np->type = NAPPEND; 11354b88c807SRodney W. Grimes else if (c == '&') 11364b88c807SRodney W. Grimes np->type = NTOFD; 11371a958c66STim J. Robbins else if (c == '|') 11381a958c66STim J. Robbins np->type = NCLOBBER; 11394b88c807SRodney W. Grimes else { 11404b88c807SRodney W. Grimes np->type = NTO; 11414b88c807SRodney W. Grimes pungetc(); 11424b88c807SRodney W. Grimes } 11434b88c807SRodney W. Grimes } else { /* c == '<' */ 11444b88c807SRodney W. Grimes np->nfile.fd = 0; 11454b88c807SRodney W. Grimes c = pgetc(); 11464b88c807SRodney W. Grimes if (c == '<') { 11474b88c807SRodney W. Grimes if (sizeof (struct nfile) != sizeof (struct nhere)) { 11484b88c807SRodney W. Grimes np = (union node *)stalloc(sizeof (struct nhere)); 11494b88c807SRodney W. Grimes np->nfile.fd = 0; 11504b88c807SRodney W. Grimes } 11514b88c807SRodney W. Grimes np->type = NHERE; 11524b88c807SRodney W. Grimes heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 11534b88c807SRodney W. Grimes heredoc->here = np; 11544b88c807SRodney W. Grimes if ((c = pgetc()) == '-') { 11554b88c807SRodney W. Grimes heredoc->striptabs = 1; 11564b88c807SRodney W. Grimes } else { 11574b88c807SRodney W. Grimes heredoc->striptabs = 0; 11584b88c807SRodney W. Grimes pungetc(); 11594b88c807SRodney W. Grimes } 11604b88c807SRodney W. Grimes } else if (c == '&') 11614b88c807SRodney W. Grimes np->type = NFROMFD; 11624682f420SBrian Somers else if (c == '>') 11634682f420SBrian Somers np->type = NFROMTO; 11644b88c807SRodney W. Grimes else { 11654b88c807SRodney W. Grimes np->type = NFROM; 11664b88c807SRodney W. Grimes pungetc(); 11674b88c807SRodney W. Grimes } 11684b88c807SRodney W. Grimes } 11694b88c807SRodney W. Grimes if (fd != '\0') 11704b88c807SRodney W. Grimes np->nfile.fd = digit_val(fd); 11714b88c807SRodney W. Grimes redirnode = np; 11724b88c807SRodney W. Grimes goto parseredir_return; 11734b88c807SRodney W. Grimes } 11744b88c807SRodney W. Grimes 11754b88c807SRodney W. Grimes 11764b88c807SRodney W. Grimes /* 11774b88c807SRodney W. Grimes * Parse a substitution. At this point, we have read the dollar sign 11784b88c807SRodney W. Grimes * and nothing else. 11794b88c807SRodney W. Grimes */ 11804b88c807SRodney W. Grimes 11814b88c807SRodney W. Grimes parsesub: { 1182b71085aaSStefan Farfeleder char buf[10]; 11834b88c807SRodney W. Grimes int subtype; 11844b88c807SRodney W. Grimes int typeloc; 11854b88c807SRodney W. Grimes int flags; 11864b88c807SRodney W. Grimes char *p; 11874b88c807SRodney W. Grimes static const char types[] = "}-+?="; 11885c817731SPeter Wemm int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ 1189b71085aaSStefan Farfeleder int i; 1190b71085aaSStefan Farfeleder int linno; 11914f30f299SStefan Farfeleder int length; 11924b88c807SRodney W. Grimes 11934b88c807SRodney W. Grimes c = pgetc(); 1194716b138bSStefan Farfeleder if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) && 1195716b138bSStefan Farfeleder !is_special(c)) { 11964b88c807SRodney W. Grimes USTPUTC('$', out); 11974b88c807SRodney W. Grimes pungetc(); 11984b88c807SRodney W. Grimes } else if (c == '(') { /* $(command) or $((arith)) */ 11994b88c807SRodney W. Grimes if (pgetc() == '(') { 12004b88c807SRodney W. Grimes PARSEARITH(); 12014b88c807SRodney W. Grimes } else { 12024b88c807SRodney W. Grimes pungetc(); 12034b88c807SRodney W. Grimes PARSEBACKQNEW(); 12044b88c807SRodney W. Grimes } 12054b88c807SRodney W. Grimes } else { 12064b88c807SRodney W. Grimes USTPUTC(CTLVAR, out); 12074b88c807SRodney W. Grimes typeloc = out - stackblock(); 12084b88c807SRodney W. Grimes USTPUTC(VSNORMAL, out); 12094b88c807SRodney W. Grimes subtype = VSNORMAL; 1210b71085aaSStefan Farfeleder flags = 0; 12114b88c807SRodney W. Grimes if (c == '{') { 12125c817731SPeter Wemm bracketed_name = 1; 12134b88c807SRodney W. Grimes c = pgetc(); 1214aa9caaf6SPeter Wemm if (c == '#') { 1215aa9caaf6SPeter Wemm if ((c = pgetc()) == '}') 1216aa9caaf6SPeter Wemm c = '#'; 1217aa9caaf6SPeter Wemm else 1218aa9caaf6SPeter Wemm subtype = VSLENGTH; 1219aa9caaf6SPeter Wemm } 1220aa9caaf6SPeter Wemm else 12214b88c807SRodney W. Grimes subtype = 0; 12224b88c807SRodney W. Grimes } 1223716b138bSStefan Farfeleder if (!is_eof(c) && is_name(c)) { 12244f30f299SStefan Farfeleder length = 0; 12254b88c807SRodney W. Grimes do { 12264b88c807SRodney W. Grimes STPUTC(c, out); 12274b88c807SRodney W. Grimes c = pgetc(); 12284f30f299SStefan Farfeleder length++; 1229716b138bSStefan Farfeleder } while (!is_eof(c) && is_in_name(c)); 12304f30f299SStefan Farfeleder if (length == 6 && 12314f30f299SStefan Farfeleder strncmp(out - length, "LINENO", length) == 0) { 1232b71085aaSStefan Farfeleder /* Replace the variable name with the 1233b71085aaSStefan Farfeleder * current line number. */ 1234b71085aaSStefan Farfeleder linno = plinno; 1235b71085aaSStefan Farfeleder if (funclinno != 0) 1236b71085aaSStefan Farfeleder linno -= funclinno - 1; 1237b71085aaSStefan Farfeleder snprintf(buf, sizeof(buf), "%d", linno); 1238b71085aaSStefan Farfeleder STADJUST(-6, out); 1239b71085aaSStefan Farfeleder for (i = 0; buf[i] != '\0'; i++) 1240b71085aaSStefan Farfeleder STPUTC(buf[i], out); 1241b71085aaSStefan Farfeleder flags |= VSLINENO; 1242b71085aaSStefan Farfeleder } 12435c817731SPeter Wemm } else if (is_digit(c)) { 12445c817731SPeter Wemm if (bracketed_name) { 12455c817731SPeter Wemm do { 12465c817731SPeter Wemm STPUTC(c, out); 12475c817731SPeter Wemm c = pgetc(); 12485c817731SPeter Wemm } while (is_digit(c)); 12495c817731SPeter Wemm } else { 12505c817731SPeter Wemm STPUTC(c, out); 12515c817731SPeter Wemm c = pgetc(); 12525c817731SPeter Wemm } 12534b88c807SRodney W. Grimes } else { 125462addaefSStefan Farfeleder if (! is_special(c)) { 125562addaefSStefan Farfeleder subtype = VSERROR; 125662addaefSStefan Farfeleder if (c == '}') 125762addaefSStefan Farfeleder pungetc(); 125862addaefSStefan Farfeleder else 125962addaefSStefan Farfeleder USTPUTC(c, out); 126062addaefSStefan Farfeleder } else { 12614b88c807SRodney W. Grimes USTPUTC(c, out); 12624b88c807SRodney W. Grimes c = pgetc(); 12634b88c807SRodney W. Grimes } 126462addaefSStefan Farfeleder } 12654b88c807SRodney W. Grimes if (subtype == 0) { 1266aa9caaf6SPeter Wemm switch (c) { 1267aa9caaf6SPeter Wemm case ':': 1268b71085aaSStefan Farfeleder flags |= VSNUL; 12694b88c807SRodney W. Grimes c = pgetc(); 1270aa9caaf6SPeter Wemm /*FALLTHROUGH*/ 1271aa9caaf6SPeter Wemm default: 12724b88c807SRodney W. Grimes p = strchr(types, c); 127362addaefSStefan Farfeleder if (p == NULL) { 127462addaefSStefan Farfeleder if (flags == VSNUL) 127562addaefSStefan Farfeleder STPUTC(':', out); 127662addaefSStefan Farfeleder STPUTC(c, out); 127762addaefSStefan Farfeleder subtype = VSERROR; 127862addaefSStefan Farfeleder } else 12794b88c807SRodney W. Grimes subtype = p - types + VSNORMAL; 1280aa9caaf6SPeter Wemm break; 1281aa9caaf6SPeter Wemm case '%': 1282aa9caaf6SPeter Wemm case '#': 1283aa9caaf6SPeter Wemm { 1284aa9caaf6SPeter Wemm int cc = c; 1285aa9caaf6SPeter Wemm subtype = c == '#' ? VSTRIMLEFT : 1286aa9caaf6SPeter Wemm VSTRIMRIGHT; 1287aa9caaf6SPeter Wemm c = pgetc(); 1288aa9caaf6SPeter Wemm if (c == cc) 1289aa9caaf6SPeter Wemm subtype++; 1290aa9caaf6SPeter Wemm else 1291aa9caaf6SPeter Wemm pungetc(); 1292aa9caaf6SPeter Wemm break; 1293aa9caaf6SPeter Wemm } 1294aa9caaf6SPeter Wemm } 129562addaefSStefan Farfeleder } else if (subtype != VSERROR) { 12964b88c807SRodney W. Grimes pungetc(); 12974b88c807SRodney W. Grimes } 129862addaefSStefan Farfeleder STPUTC('=', out); 1299c11e75cfSMartin Cracauer if (subtype != VSLENGTH && (dblquote || arinest)) 13004b88c807SRodney W. Grimes flags |= VSQUOTE; 13014b88c807SRodney W. Grimes *(stackblock() + typeloc) = subtype | flags; 13024b88c807SRodney W. Grimes if (subtype != VSNORMAL) 13034b88c807SRodney W. Grimes varnest++; 13044b88c807SRodney W. Grimes } 13054b88c807SRodney W. Grimes goto parsesub_return; 13064b88c807SRodney W. Grimes } 13074b88c807SRodney W. Grimes 13084b88c807SRodney W. Grimes 13094b88c807SRodney W. Grimes /* 13104b88c807SRodney W. Grimes * Called to parse command substitutions. Newstyle is set if the command 13114b88c807SRodney W. Grimes * is enclosed inside $(...); nlpp is a pointer to the head of the linked 13124b88c807SRodney W. Grimes * list of commands (passed by reference), and savelen is the number of 13134b88c807SRodney W. Grimes * characters on the top of the stack which must be preserved. 13144b88c807SRodney W. Grimes */ 13154b88c807SRodney W. Grimes 13164b88c807SRodney W. Grimes parsebackq: { 13174b88c807SRodney W. Grimes struct nodelist **nlpp; 13184b88c807SRodney W. Grimes int savepbq; 13194b88c807SRodney W. Grimes union node *n; 13204b88c807SRodney W. Grimes char *volatile str; 13214b88c807SRodney W. Grimes struct jmploc jmploc; 13224b88c807SRodney W. Grimes struct jmploc *volatile savehandler; 13234b88c807SRodney W. Grimes int savelen; 1324ab0a2172SSteve Price int saveprompt; 1325ab0a2172SSteve Price #if __GNUC__ 1326ab0a2172SSteve Price /* Avoid longjmp clobbering */ 1327ab0a2172SSteve Price (void) &saveprompt; 1328ab0a2172SSteve Price #endif 13294b88c807SRodney W. Grimes 13304b88c807SRodney W. Grimes savepbq = parsebackquote; 13314b88c807SRodney W. Grimes if (setjmp(jmploc.loc)) { 13324b88c807SRodney W. Grimes if (str) 13334b88c807SRodney W. Grimes ckfree(str); 13344b88c807SRodney W. Grimes parsebackquote = 0; 13354b88c807SRodney W. Grimes handler = savehandler; 13364b88c807SRodney W. Grimes longjmp(handler->loc, 1); 13374b88c807SRodney W. Grimes } 13384b88c807SRodney W. Grimes INTOFF; 13394b88c807SRodney W. Grimes str = NULL; 13404b88c807SRodney W. Grimes savelen = out - stackblock(); 13414b88c807SRodney W. Grimes if (savelen > 0) { 13424b88c807SRodney W. Grimes str = ckmalloc(savelen); 1343aa9caaf6SPeter Wemm memcpy(str, stackblock(), savelen); 13444b88c807SRodney W. Grimes } 13454b88c807SRodney W. Grimes savehandler = handler; 13464b88c807SRodney W. Grimes handler = &jmploc; 13474b88c807SRodney W. Grimes INTON; 13484b88c807SRodney W. Grimes if (oldstyle) { 13494b88c807SRodney W. Grimes /* We must read until the closing backquote, giving special 13504b88c807SRodney W. Grimes treatment to some slashes, and then push the string and 13514b88c807SRodney W. Grimes reread it as input, interpreting it normally. */ 13527920a31dSSteve Price char *out; 13537920a31dSSteve Price int c; 13544b88c807SRodney W. Grimes int savelen; 13554b88c807SRodney W. Grimes char *str; 13564b88c807SRodney W. Grimes 1357ab0a2172SSteve Price 13584b88c807SRodney W. Grimes STARTSTACKSTR(out); 1359ab0a2172SSteve Price for (;;) { 1360ab0a2172SSteve Price if (needprompt) { 1361ab0a2172SSteve Price setprompt(2); 1362ab0a2172SSteve Price needprompt = 0; 136372348d41SJoerg Wunsch } 1364ab0a2172SSteve Price switch (c = pgetc()) { 1365ab0a2172SSteve Price case '`': 1366ab0a2172SSteve Price goto done; 1367ab0a2172SSteve Price 1368ab0a2172SSteve Price case '\\': 1369ab0a2172SSteve Price if ((c = pgetc()) == '\n') { 1370ab0a2172SSteve Price plinno++; 1371ab0a2172SSteve Price if (doprompt) 1372ab0a2172SSteve Price setprompt(2); 1373ab0a2172SSteve Price else 1374ab0a2172SSteve Price setprompt(0); 1375ab0a2172SSteve Price /* 1376ab0a2172SSteve Price * If eating a newline, avoid putting 1377ab0a2172SSteve Price * the newline into the new character 1378ab0a2172SSteve Price * stream (via the STPUTC after the 1379ab0a2172SSteve Price * switch). 1380ab0a2172SSteve Price */ 1381ab0a2172SSteve Price continue; 1382ab0a2172SSteve Price } 13831e95454eSPaul Richards if (c != '\\' && c != '`' && c != '$' 13844b88c807SRodney W. Grimes && (!dblquote || c != '"')) 13854b88c807SRodney W. Grimes STPUTC('\\', out); 1386ab0a2172SSteve Price break; 1387ab0a2172SSteve Price 1388ab0a2172SSteve Price case '\n': 1389ab0a2172SSteve Price plinno++; 1390ab0a2172SSteve Price needprompt = doprompt; 1391ab0a2172SSteve Price break; 1392ab0a2172SSteve Price 1393ab0a2172SSteve Price case PEOF: 1394ab0a2172SSteve Price startlinno = plinno; 1395ab0a2172SSteve Price synerror("EOF in backquote substitution"); 1396ab0a2172SSteve Price break; 1397ab0a2172SSteve Price 1398ab0a2172SSteve Price default: 1399ab0a2172SSteve Price break; 14004b88c807SRodney W. Grimes } 14014b88c807SRodney W. Grimes STPUTC(c, out); 14024b88c807SRodney W. Grimes } 1403ab0a2172SSteve Price done: 14044b88c807SRodney W. Grimes STPUTC('\0', out); 14054b88c807SRodney W. Grimes savelen = out - stackblock(); 14064b88c807SRodney W. Grimes if (savelen > 0) { 14074b88c807SRodney W. Grimes str = ckmalloc(savelen); 1408aa9caaf6SPeter Wemm memcpy(str, stackblock(), savelen); 14094b88c807SRodney W. Grimes setinputstring(str, 1); 14104b88c807SRodney W. Grimes } 1411aa9caaf6SPeter Wemm } 14124b88c807SRodney W. Grimes nlpp = &bqlist; 14134b88c807SRodney W. Grimes while (*nlpp) 14144b88c807SRodney W. Grimes nlpp = &(*nlpp)->next; 14154b88c807SRodney W. Grimes *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 14164b88c807SRodney W. Grimes (*nlpp)->next = NULL; 14174b88c807SRodney W. Grimes parsebackquote = oldstyle; 1418ab0a2172SSteve Price 1419ab0a2172SSteve Price if (oldstyle) { 1420ab0a2172SSteve Price saveprompt = doprompt; 1421ab0a2172SSteve Price doprompt = 0; 1422ab0a2172SSteve Price } 1423ab0a2172SSteve Price 14244b88c807SRodney W. Grimes n = list(0); 1425ab0a2172SSteve Price 14264b88c807SRodney W. Grimes if (oldstyle) 1427ab0a2172SSteve Price doprompt = saveprompt; 1428ab0a2172SSteve Price else { 1429ab0a2172SSteve Price if (readtoken() != TRP) 1430ab0a2172SSteve Price synexpect(TRP); 1431ab0a2172SSteve Price } 1432ab0a2172SSteve Price 1433ab0a2172SSteve Price (*nlpp)->n = n; 1434ab0a2172SSteve Price if (oldstyle) { 1435ab0a2172SSteve Price /* 1436ab0a2172SSteve Price * Start reading from old file again, ignoring any pushed back 1437ab0a2172SSteve Price * tokens left from the backquote parsing 1438ab0a2172SSteve Price */ 14394b88c807SRodney W. Grimes popfile(); 1440ab0a2172SSteve Price tokpushback = 0; 1441ab0a2172SSteve Price } 14424b88c807SRodney W. Grimes while (stackblocksize() <= savelen) 14434b88c807SRodney W. Grimes growstackblock(); 14444b88c807SRodney W. Grimes STARTSTACKSTR(out); 14454b88c807SRodney W. Grimes if (str) { 1446aa9caaf6SPeter Wemm memcpy(out, str, savelen); 14474b88c807SRodney W. Grimes STADJUST(savelen, out); 14484b88c807SRodney W. Grimes INTOFF; 14494b88c807SRodney W. Grimes ckfree(str); 14504b88c807SRodney W. Grimes str = NULL; 14514b88c807SRodney W. Grimes INTON; 14524b88c807SRodney W. Grimes } 14534b88c807SRodney W. Grimes parsebackquote = savepbq; 14544b88c807SRodney W. Grimes handler = savehandler; 14554b88c807SRodney W. Grimes if (arinest || dblquote) 14564b88c807SRodney W. Grimes USTPUTC(CTLBACKQ | CTLQUOTE, out); 14574b88c807SRodney W. Grimes else 14584b88c807SRodney W. Grimes USTPUTC(CTLBACKQ, out); 14594b88c807SRodney W. Grimes if (oldstyle) 14604b88c807SRodney W. Grimes goto parsebackq_oldreturn; 14614b88c807SRodney W. Grimes else 14624b88c807SRodney W. Grimes goto parsebackq_newreturn; 14634b88c807SRodney W. Grimes } 14644b88c807SRodney W. Grimes 14654b88c807SRodney W. Grimes /* 14664b88c807SRodney W. Grimes * Parse an arithmetic expansion (indicate start of one and set state) 14674b88c807SRodney W. Grimes */ 14684b88c807SRodney W. Grimes parsearith: { 14694b88c807SRodney W. Grimes 14704b88c807SRodney W. Grimes if (++arinest == 1) { 14714b88c807SRodney W. Grimes prevsyntax = syntax; 14724b88c807SRodney W. Grimes syntax = ARISYNTAX; 14734b88c807SRodney W. Grimes USTPUTC(CTLARI, out); 14746f47734fSTor Egge if (dblquote) 14756f47734fSTor Egge USTPUTC('"',out); 14766f47734fSTor Egge else 14776f47734fSTor Egge USTPUTC(' ',out); 14784b88c807SRodney W. Grimes } else { 14794b88c807SRodney W. Grimes /* 14804b88c807SRodney W. Grimes * we collapse embedded arithmetic expansion to 14814b88c807SRodney W. Grimes * parenthesis, which should be equivalent 14824b88c807SRodney W. Grimes */ 14834b88c807SRodney W. Grimes USTPUTC('(', out); 14844b88c807SRodney W. Grimes } 14854b88c807SRodney W. Grimes goto parsearith_return; 14864b88c807SRodney W. Grimes } 14874b88c807SRodney W. Grimes 14884b88c807SRodney W. Grimes } /* end of readtoken */ 14894b88c807SRodney W. Grimes 14904b88c807SRodney W. Grimes 14914b88c807SRodney W. Grimes 14924b88c807SRodney W. Grimes #ifdef mkinit 14934b88c807SRodney W. Grimes RESET { 14944b88c807SRodney W. Grimes tokpushback = 0; 14954b88c807SRodney W. Grimes checkkwd = 0; 14964b88c807SRodney W. Grimes } 14974b88c807SRodney W. Grimes #endif 14984b88c807SRodney W. Grimes 14994b88c807SRodney W. Grimes /* 15004b88c807SRodney W. Grimes * Returns true if the text contains nothing to expand (no dollar signs 15014b88c807SRodney W. Grimes * or backquotes). 15024b88c807SRodney W. Grimes */ 15034b88c807SRodney W. Grimes 15044b88c807SRodney W. Grimes STATIC int 15055134c3f7SWarner Losh noexpand(char *text) 15064b88c807SRodney W. Grimes { 15077920a31dSSteve Price char *p; 15087920a31dSSteve Price char c; 15094b88c807SRodney W. Grimes 15104b88c807SRodney W. Grimes p = text; 15114b88c807SRodney W. Grimes while ((c = *p++) != '\0') { 15125557a02aSTor Egge if ( c == CTLQUOTEMARK) 15135557a02aSTor Egge continue; 15144b88c807SRodney W. Grimes if (c == CTLESC) 15154b88c807SRodney W. Grimes p++; 15160c4eeddaSTor Egge else if (BASESYNTAX[(int)c] == CCTL) 15174b88c807SRodney W. Grimes return 0; 15184b88c807SRodney W. Grimes } 15194b88c807SRodney W. Grimes return 1; 15204b88c807SRodney W. Grimes } 15214b88c807SRodney W. Grimes 15224b88c807SRodney W. Grimes 15234b88c807SRodney W. Grimes /* 15244b88c807SRodney W. Grimes * Return true if the argument is a legal variable name (a letter or 15254b88c807SRodney W. Grimes * underscore followed by zero or more letters, underscores, and digits). 15264b88c807SRodney W. Grimes */ 15274b88c807SRodney W. Grimes 15284b88c807SRodney W. Grimes int 15295134c3f7SWarner Losh goodname(char *name) 15304b88c807SRodney W. Grimes { 15317920a31dSSteve Price char *p; 15324b88c807SRodney W. Grimes 15334b88c807SRodney W. Grimes p = name; 15344b88c807SRodney W. Grimes if (! is_name(*p)) 15354b88c807SRodney W. Grimes return 0; 15364b88c807SRodney W. Grimes while (*++p) { 15374b88c807SRodney W. Grimes if (! is_in_name(*p)) 15384b88c807SRodney W. Grimes return 0; 15394b88c807SRodney W. Grimes } 15404b88c807SRodney W. Grimes return 1; 15414b88c807SRodney W. Grimes } 15424b88c807SRodney W. Grimes 15434b88c807SRodney W. Grimes 15444b88c807SRodney W. Grimes /* 15454b88c807SRodney W. Grimes * Called when an unexpected token is read during the parse. The argument 15464b88c807SRodney W. Grimes * is the token that is expected, or -1 if more than one type of token can 15474b88c807SRodney W. Grimes * occur at this point. 15484b88c807SRodney W. Grimes */ 15494b88c807SRodney W. Grimes 15504b88c807SRodney W. Grimes STATIC void 15515134c3f7SWarner Losh synexpect(int token) 1552aa9caaf6SPeter Wemm { 15534b88c807SRodney W. Grimes char msg[64]; 15544b88c807SRodney W. Grimes 15554b88c807SRodney W. Grimes if (token >= 0) { 15564b88c807SRodney W. Grimes fmtstr(msg, 64, "%s unexpected (expecting %s)", 15574b88c807SRodney W. Grimes tokname[lasttoken], tokname[token]); 15584b88c807SRodney W. Grimes } else { 15594b88c807SRodney W. Grimes fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 15604b88c807SRodney W. Grimes } 15614b88c807SRodney W. Grimes synerror(msg); 15624b88c807SRodney W. Grimes } 15634b88c807SRodney W. Grimes 15644b88c807SRodney W. Grimes 15654b88c807SRodney W. Grimes STATIC void 15665134c3f7SWarner Losh synerror(char *msg) 15674b88c807SRodney W. Grimes { 15684b88c807SRodney W. Grimes if (commandname) 15694b88c807SRodney W. Grimes outfmt(&errout, "%s: %d: ", commandname, startlinno); 15704b88c807SRodney W. Grimes outfmt(&errout, "Syntax error: %s\n", msg); 15714b88c807SRodney W. Grimes error((char *)NULL); 15724b88c807SRodney W. Grimes } 15734b88c807SRodney W. Grimes 15744b88c807SRodney W. Grimes STATIC void 15755134c3f7SWarner Losh setprompt(int which) 15764b88c807SRodney W. Grimes { 15774b88c807SRodney W. Grimes whichprompt = which; 15784b88c807SRodney W. Grimes 1579aa9caaf6SPeter Wemm #ifndef NO_HISTORY 15804b88c807SRodney W. Grimes if (!el) 1581aa9caaf6SPeter Wemm #endif 15824b88c807SRodney W. Grimes out2str(getprompt(NULL)); 15834b88c807SRodney W. Grimes } 15844b88c807SRodney W. Grimes 15854b88c807SRodney W. Grimes /* 15864b88c807SRodney W. Grimes * called by editline -- any expansions to the prompt 15874b88c807SRodney W. Grimes * should be added here. 15884b88c807SRodney W. Grimes */ 15894b88c807SRodney W. Grimes char * 15905134c3f7SWarner Losh getprompt(void *unused __unused) 15914b88c807SRodney W. Grimes { 1592f0c73601SDavid E. O'Brien static char ps[PROMPTLEN]; 1593f0c73601SDavid E. O'Brien char *fmt; 1594f0c73601SDavid E. O'Brien int i, j, trim; 1595f0c73601SDavid E. O'Brien 1596f0c73601SDavid E. O'Brien /* 1597f0c73601SDavid E. O'Brien * Select prompt format. 1598f0c73601SDavid E. O'Brien */ 15994b88c807SRodney W. Grimes switch (whichprompt) { 16004b88c807SRodney W. Grimes case 0: 1601f0c73601SDavid E. O'Brien fmt = ""; 1602f0c73601SDavid E. O'Brien break; 16034b88c807SRodney W. Grimes case 1: 1604f0c73601SDavid E. O'Brien fmt = ps1val(); 1605f0c73601SDavid E. O'Brien break; 16064b88c807SRodney W. Grimes case 2: 1607f0c73601SDavid E. O'Brien fmt = ps2val(); 1608f0c73601SDavid E. O'Brien break; 16094b88c807SRodney W. Grimes default: 16104b88c807SRodney W. Grimes return "<internal prompt error>"; 16114b88c807SRodney W. Grimes } 1612f0c73601SDavid E. O'Brien 1613f0c73601SDavid E. O'Brien /* 1614f0c73601SDavid E. O'Brien * Format prompt string. 1615f0c73601SDavid E. O'Brien */ 1616f0c73601SDavid E. O'Brien for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++) 1617f0c73601SDavid E. O'Brien if (*fmt == '\\') 1618f0c73601SDavid E. O'Brien switch (*++fmt) { 1619f0c73601SDavid E. O'Brien 1620f0c73601SDavid E. O'Brien /* 1621f0c73601SDavid E. O'Brien * Hostname. 1622f0c73601SDavid E. O'Brien * 1623f0c73601SDavid E. O'Brien * \h specifies just the local hostname, 1624f0c73601SDavid E. O'Brien * \H specifies fully-qualified hostname. 1625f0c73601SDavid E. O'Brien */ 1626f0c73601SDavid E. O'Brien case 'h': 1627f0c73601SDavid E. O'Brien case 'H': 16288d999570SStefan Farfeleder ps[i] = '\0'; 1629f0c73601SDavid E. O'Brien gethostname(&ps[i], PROMPTLEN - i); 1630f0c73601SDavid E. O'Brien /* Skip to end of hostname. */ 1631f0c73601SDavid E. O'Brien trim = (*fmt == 'h') ? '.' : '\0'; 1632f0c73601SDavid E. O'Brien while ((ps[i+1] != '\0') && (ps[i+1] != trim)) 1633f0c73601SDavid E. O'Brien i++; 1634f0c73601SDavid E. O'Brien break; 1635f0c73601SDavid E. O'Brien 1636f0c73601SDavid E. O'Brien /* 1637f0c73601SDavid E. O'Brien * Working directory. 1638f0c73601SDavid E. O'Brien * 1639f0c73601SDavid E. O'Brien * \W specifies just the final component, 1640f0c73601SDavid E. O'Brien * \w specifies the entire path. 1641f0c73601SDavid E. O'Brien */ 1642f0c73601SDavid E. O'Brien case 'W': 1643f0c73601SDavid E. O'Brien case 'w': 16448d999570SStefan Farfeleder ps[i] = '\0'; 1645f0c73601SDavid E. O'Brien getcwd(&ps[i], PROMPTLEN - i); 1646f0c73601SDavid E. O'Brien if (*fmt == 'W') { 1647f0c73601SDavid E. O'Brien /* Final path component only. */ 1648f0c73601SDavid E. O'Brien trim = 1; 1649f0c73601SDavid E. O'Brien for (j = i; ps[j] != '\0'; j++) 1650f0c73601SDavid E. O'Brien if (ps[j] == '/') 1651f0c73601SDavid E. O'Brien trim = j + 1; 1652f0c73601SDavid E. O'Brien memmove(&ps[i], &ps[trim], 1653f0c73601SDavid E. O'Brien j - trim + 1); 1654f0c73601SDavid E. O'Brien } 1655f0c73601SDavid E. O'Brien /* Skip to end of path. */ 1656f0c73601SDavid E. O'Brien while (ps[i + 1] != '\0') 1657f0c73601SDavid E. O'Brien i++; 1658f0c73601SDavid E. O'Brien break; 1659f0c73601SDavid E. O'Brien 1660f0c73601SDavid E. O'Brien /* 1661f0c73601SDavid E. O'Brien * Superuser status. 1662f0c73601SDavid E. O'Brien * 1663f0c73601SDavid E. O'Brien * '$' for normal users, '#' for root. 1664f0c73601SDavid E. O'Brien */ 1665f0c73601SDavid E. O'Brien case '$': 1666f0c73601SDavid E. O'Brien ps[i] = (geteuid() != 0) ? '$' : '#'; 1667f0c73601SDavid E. O'Brien break; 1668f0c73601SDavid E. O'Brien 1669f0c73601SDavid E. O'Brien /* 1670f0c73601SDavid E. O'Brien * A literal \. 1671f0c73601SDavid E. O'Brien */ 1672f0c73601SDavid E. O'Brien case '\\': 1673f0c73601SDavid E. O'Brien ps[i] = '\\'; 1674f0c73601SDavid E. O'Brien break; 1675f0c73601SDavid E. O'Brien 1676f0c73601SDavid E. O'Brien /* 1677f0c73601SDavid E. O'Brien * Emit unrecognized formats verbatim. 1678f0c73601SDavid E. O'Brien */ 1679f0c73601SDavid E. O'Brien default: 1680f0c73601SDavid E. O'Brien ps[i++] = '\\'; 1681f0c73601SDavid E. O'Brien ps[i] = *fmt; 1682f0c73601SDavid E. O'Brien break; 1683f0c73601SDavid E. O'Brien } 1684f0c73601SDavid E. O'Brien else 1685f0c73601SDavid E. O'Brien ps[i] = *fmt; 1686f0c73601SDavid E. O'Brien ps[i] = '\0'; 1687f0c73601SDavid E. O'Brien return (ps); 16884b88c807SRodney W. Grimes } 1689