14b88c807SRodney W. Grimes /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 44b88c807SRodney W. Grimes * Copyright (c) 1991, 1993 54b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 64b88c807SRodney W. Grimes * 74b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 84b88c807SRodney W. Grimes * Kenneth Almquist. 94b88c807SRodney W. Grimes * 104b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 114b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 124b88c807SRodney W. Grimes * are met: 134b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 144b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 154b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 164b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 174b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 194b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 204b88c807SRodney W. Grimes * without specific prior written permission. 214b88c807SRodney W. Grimes * 224b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 234b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 244b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 254b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 264b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 274b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 284b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 294b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 304b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 314b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 324b88c807SRodney W. Grimes * SUCH DAMAGE. 334b88c807SRodney W. Grimes */ 344b88c807SRodney W. Grimes 354b88c807SRodney W. Grimes #ifndef lint 363d7b5b93SPhilippe Charnier #if 0 373d7b5b93SPhilippe Charnier static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; 383d7b5b93SPhilippe Charnier #endif 394b88c807SRodney W. Grimes #endif /* not lint */ 402749b141SDavid E. O'Brien #include <sys/cdefs.h> 41d81ca439SEdward Tomasz Napierala #include <sys/param.h> 42d81ca439SEdward Tomasz Napierala #include <pwd.h> 43aa9caaf6SPeter Wemm #include <stdlib.h> 44955e9f68SStefan Farfeleder #include <unistd.h> 4549e10f5eSJilles Tjoelker #include <stdio.h> 46*a675eaecSPiotr Pawel Stefaniak #include <time.h> 47aa9caaf6SPeter Wemm 484b88c807SRodney W. Grimes #include "shell.h" 494b88c807SRodney W. Grimes #include "parser.h" 504b88c807SRodney W. Grimes #include "nodes.h" 514b88c807SRodney W. Grimes #include "expand.h" /* defines rmescapes() */ 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" 6367e109adSJilles Tjoelker #include "exec.h" /* to check for special builtins */ 64aa9caaf6SPeter Wemm #ifndef NO_HISTORY 654b88c807SRodney W. Grimes #include "myhistedit.h" 66aa9caaf6SPeter Wemm #endif 674b88c807SRodney W. Grimes 684b88c807SRodney W. Grimes /* 694b88c807SRodney W. Grimes * Shell command parser. 704b88c807SRodney W. Grimes */ 714b88c807SRodney W. Grimes 723cf65f8aSJuraj Lutter #define PROMPTLEN 192 734b88c807SRodney W. Grimes 74135ff4b5SJilles Tjoelker /* values of checkkwd variable */ 75135ff4b5SJilles Tjoelker #define CHKALIAS 0x1 76135ff4b5SJilles Tjoelker #define CHKKWD 0x2 77135ff4b5SJilles Tjoelker #define CHKNL 0x4 78135ff4b5SJilles Tjoelker 794b88c807SRodney W. Grimes /* values returned by readtoken */ 80aa9caaf6SPeter Wemm #include "token.h" 814b88c807SRodney W. Grimes 824b88c807SRodney W. Grimes 834b88c807SRodney W. Grimes 844b88c807SRodney W. Grimes struct heredoc { 854b88c807SRodney W. Grimes struct heredoc *next; /* next here document in list */ 864b88c807SRodney W. Grimes union node *here; /* redirection node */ 874b88c807SRodney W. Grimes char *eofmark; /* string indicating end of input */ 884b88c807SRodney W. Grimes int striptabs; /* if set, strip leading tabs */ 894b88c807SRodney W. Grimes }; 904b88c807SRodney W. Grimes 918cf06f5eSJilles Tjoelker struct parser_temp { 928cf06f5eSJilles Tjoelker struct parser_temp *next; 938cf06f5eSJilles Tjoelker void *data; 948cf06f5eSJilles Tjoelker }; 954b88c807SRodney W. Grimes 964b88c807SRodney W. Grimes 97aa7b6f82SDavid E. O'Brien static struct heredoc *heredoclist; /* list of here documents to read */ 98aa7b6f82SDavid E. O'Brien static int doprompt; /* if set, prompt the user */ 99aa7b6f82SDavid E. O'Brien static int needprompt; /* true if interactive and at start of line */ 100aa7b6f82SDavid E. O'Brien static int lasttoken; /* last token read */ 101f52924b4SJilles Tjoelker static int tokpushback; /* last token pushed back */ 102aa7b6f82SDavid E. O'Brien static char *wordtext; /* text of last word returned by readtoken */ 103b6dda50aSJilles Tjoelker static int checkkwd; 104aa7b6f82SDavid E. O'Brien static struct nodelist *backquotelist; 105aa7b6f82SDavid E. O'Brien static union node *redirnode; 106aa7b6f82SDavid E. O'Brien static struct heredoc *heredoc; 107aa7b6f82SDavid E. O'Brien static int quoteflag; /* set if (part of) last token was quoted */ 108aa7b6f82SDavid E. O'Brien static int startlinno; /* line # where last token started */ 109aa7b6f82SDavid E. O'Brien static int funclinno; /* line # where the current function started */ 110aa7b6f82SDavid E. O'Brien static struct parser_temp *parser_temp; 1114b88c807SRodney W. Grimes 11292fe71faSJilles Tjoelker #define NOEOFMARK ((const char *)&heredoclist) 11392fe71faSJilles Tjoelker 1144b88c807SRodney W. Grimes 11532187151SJilles Tjoelker static union node *list(int); 11688328642SDavid E. O'Brien static union node *andor(void); 11788328642SDavid E. O'Brien static union node *pipeline(void); 11888328642SDavid E. O'Brien static union node *command(void); 11988328642SDavid E. O'Brien static union node *simplecmd(union node **, union node *); 12088328642SDavid E. O'Brien static union node *makename(void); 121510739ccSJilles Tjoelker static union node *makebinary(int type, union node *n1, union node *n2); 12288328642SDavid E. O'Brien static void parsefname(void); 12388328642SDavid E. O'Brien static void parseheredoc(void); 12488328642SDavid E. O'Brien static int peektoken(void); 12588328642SDavid E. O'Brien static int readtoken(void); 12688328642SDavid E. O'Brien static int xxreadtoken(void); 12746c6b52dSJilles Tjoelker static int readtoken1(int, const char *, const char *, int); 12888328642SDavid E. O'Brien static int noexpand(char *); 1296ab99f87SJilles Tjoelker static void consumetoken(int); 13088328642SDavid E. O'Brien static void synexpect(int) __dead2; 13188328642SDavid E. O'Brien static void synerror(const char *) __dead2; 13288328642SDavid E. O'Brien static void setprompt(int); 1330b4b9c81SJilles Tjoelker static int pgetc_linecont(void); 134d81ca439SEdward Tomasz Napierala static void getusername(char *, size_t); 1354b88c807SRodney W. Grimes 136aa9caaf6SPeter Wemm 13788328642SDavid E. O'Brien static void * 1388cf06f5eSJilles Tjoelker parser_temp_alloc(size_t len) 1398cf06f5eSJilles Tjoelker { 1408cf06f5eSJilles Tjoelker struct parser_temp *t; 1418cf06f5eSJilles Tjoelker 1428cf06f5eSJilles Tjoelker INTOFF; 1438cf06f5eSJilles Tjoelker t = ckmalloc(sizeof(*t)); 1448cf06f5eSJilles Tjoelker t->data = NULL; 1458cf06f5eSJilles Tjoelker t->next = parser_temp; 1468cf06f5eSJilles Tjoelker parser_temp = t; 1478cf06f5eSJilles Tjoelker t->data = ckmalloc(len); 1488cf06f5eSJilles Tjoelker INTON; 1498cf06f5eSJilles Tjoelker return t->data; 1508cf06f5eSJilles Tjoelker } 1518cf06f5eSJilles Tjoelker 1528cf06f5eSJilles Tjoelker 15388328642SDavid E. O'Brien static void * 1548cf06f5eSJilles Tjoelker parser_temp_realloc(void *ptr, size_t len) 1558cf06f5eSJilles Tjoelker { 1568cf06f5eSJilles Tjoelker struct parser_temp *t; 1578cf06f5eSJilles Tjoelker 1588cf06f5eSJilles Tjoelker INTOFF; 1598cf06f5eSJilles Tjoelker t = parser_temp; 1608cf06f5eSJilles Tjoelker if (ptr != t->data) 1618cf06f5eSJilles Tjoelker error("bug: parser_temp_realloc misused"); 1628cf06f5eSJilles Tjoelker t->data = ckrealloc(t->data, len); 1638cf06f5eSJilles Tjoelker INTON; 1648cf06f5eSJilles Tjoelker return t->data; 1658cf06f5eSJilles Tjoelker } 1668cf06f5eSJilles Tjoelker 1678cf06f5eSJilles Tjoelker 16888328642SDavid E. O'Brien static void 1698cf06f5eSJilles Tjoelker parser_temp_free_upto(void *ptr) 1708cf06f5eSJilles Tjoelker { 1718cf06f5eSJilles Tjoelker struct parser_temp *t; 1728cf06f5eSJilles Tjoelker int done = 0; 1738cf06f5eSJilles Tjoelker 1748cf06f5eSJilles Tjoelker INTOFF; 1758cf06f5eSJilles Tjoelker while (parser_temp != NULL && !done) { 1768cf06f5eSJilles Tjoelker t = parser_temp; 1778cf06f5eSJilles Tjoelker parser_temp = t->next; 1788cf06f5eSJilles Tjoelker done = t->data == ptr; 1798cf06f5eSJilles Tjoelker ckfree(t->data); 1808cf06f5eSJilles Tjoelker ckfree(t); 1818cf06f5eSJilles Tjoelker } 1828cf06f5eSJilles Tjoelker INTON; 1838cf06f5eSJilles Tjoelker if (!done) 1848cf06f5eSJilles Tjoelker error("bug: parser_temp_free_upto misused"); 1858cf06f5eSJilles Tjoelker } 1868cf06f5eSJilles Tjoelker 1878cf06f5eSJilles Tjoelker 18888328642SDavid E. O'Brien static void 1898cf06f5eSJilles Tjoelker parser_temp_free_all(void) 1908cf06f5eSJilles Tjoelker { 1918cf06f5eSJilles Tjoelker struct parser_temp *t; 1928cf06f5eSJilles Tjoelker 1938cf06f5eSJilles Tjoelker INTOFF; 1948cf06f5eSJilles Tjoelker while (parser_temp != NULL) { 1958cf06f5eSJilles Tjoelker t = parser_temp; 1968cf06f5eSJilles Tjoelker parser_temp = t->next; 1978cf06f5eSJilles Tjoelker ckfree(t->data); 1988cf06f5eSJilles Tjoelker ckfree(t); 1998cf06f5eSJilles Tjoelker } 2008cf06f5eSJilles Tjoelker INTON; 2018cf06f5eSJilles Tjoelker } 2028cf06f5eSJilles Tjoelker 2038cf06f5eSJilles Tjoelker 2044b88c807SRodney W. Grimes /* 2054b88c807SRodney W. Grimes * Read and parse a command. Returns NEOF on end of file. (NULL is a 2064b88c807SRodney W. Grimes * valid parse tree indicating a blank line.) 2074b88c807SRodney W. Grimes */ 2084b88c807SRodney W. Grimes 2094b88c807SRodney W. Grimes union node * 2105134c3f7SWarner Losh parsecmd(int interact) 211aa9caaf6SPeter Wemm { 2124b88c807SRodney W. Grimes int t; 2134b88c807SRodney W. Grimes 2148cf06f5eSJilles Tjoelker /* This assumes the parser is not re-entered, 2158cf06f5eSJilles Tjoelker * which could happen if we add command substitution on PS1/PS2. 2168cf06f5eSJilles Tjoelker */ 2178cf06f5eSJilles Tjoelker parser_temp_free_all(); 2185d910070SJilles Tjoelker heredoclist = NULL; 2198cf06f5eSJilles Tjoelker 22098e05fd3SMartin Cracauer tokpushback = 0; 2219bb8ccd6SJilles Tjoelker checkkwd = 0; 2224b88c807SRodney W. Grimes doprompt = interact; 2234b88c807SRodney W. Grimes if (doprompt) 2244b88c807SRodney W. Grimes setprompt(1); 2254b88c807SRodney W. Grimes else 2264b88c807SRodney W. Grimes setprompt(0); 2274b88c807SRodney W. Grimes needprompt = 0; 2284b88c807SRodney W. Grimes t = readtoken(); 2294b88c807SRodney W. Grimes if (t == TEOF) 2304b88c807SRodney W. Grimes return NEOF; 2314b88c807SRodney W. Grimes if (t == TNL) 2324b88c807SRodney W. Grimes return NULL; 2334b88c807SRodney W. Grimes tokpushback++; 23432187151SJilles Tjoelker return list(1); 2354b88c807SRodney W. Grimes } 2364b88c807SRodney W. Grimes 2374b88c807SRodney W. Grimes 238d358fa78SJilles Tjoelker /* 239d358fa78SJilles Tjoelker * Read and parse words for wordexp. 240d358fa78SJilles Tjoelker * Returns a list of NARG nodes; NULL if there are no words. 241d358fa78SJilles Tjoelker */ 242d358fa78SJilles Tjoelker union node * 243d358fa78SJilles Tjoelker parsewordexp(void) 244d358fa78SJilles Tjoelker { 245d358fa78SJilles Tjoelker union node *n, *first = NULL, **pnext; 246d358fa78SJilles Tjoelker int t; 247d358fa78SJilles Tjoelker 248d358fa78SJilles Tjoelker /* This assumes the parser is not re-entered, 249d358fa78SJilles Tjoelker * which could happen if we add command substitution on PS1/PS2. 250d358fa78SJilles Tjoelker */ 251d358fa78SJilles Tjoelker parser_temp_free_all(); 252d358fa78SJilles Tjoelker heredoclist = NULL; 253d358fa78SJilles Tjoelker 254d358fa78SJilles Tjoelker tokpushback = 0; 255d358fa78SJilles Tjoelker checkkwd = 0; 256d358fa78SJilles Tjoelker doprompt = 0; 257d358fa78SJilles Tjoelker setprompt(0); 258d358fa78SJilles Tjoelker needprompt = 0; 259d358fa78SJilles Tjoelker pnext = &first; 260d358fa78SJilles Tjoelker while ((t = readtoken()) != TEOF) { 261d358fa78SJilles Tjoelker if (t != TWORD) 262d358fa78SJilles Tjoelker synexpect(TWORD); 263d358fa78SJilles Tjoelker n = makename(); 264d358fa78SJilles Tjoelker *pnext = n; 265d358fa78SJilles Tjoelker pnext = &n->narg.next; 266d358fa78SJilles Tjoelker } 267d358fa78SJilles Tjoelker return first; 268d358fa78SJilles Tjoelker } 269d358fa78SJilles Tjoelker 270d358fa78SJilles Tjoelker 27188328642SDavid E. O'Brien static union node * 27232187151SJilles Tjoelker list(int nlflag) 273aa9caaf6SPeter Wemm { 274dca867f1SJilles Tjoelker union node *ntop, *n1, *n2, *n3; 275aa9caaf6SPeter Wemm int tok; 2764b88c807SRodney W. Grimes 277135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD | CHKALIAS; 27832187151SJilles Tjoelker if (!nlflag && tokendlist[peektoken()]) 2794b88c807SRodney W. Grimes return NULL; 280dca867f1SJilles Tjoelker ntop = n1 = NULL; 2814b88c807SRodney W. Grimes for (;;) { 2824b88c807SRodney W. Grimes n2 = andor(); 283aa9caaf6SPeter Wemm tok = readtoken(); 284aa9caaf6SPeter Wemm if (tok == TBACKGND) { 28531d39658SJilles Tjoelker if (n2 != NULL && n2->type == NPIPE) { 28647e5204eSJilles Tjoelker n2->npipe.backgnd = 1; 28731d39658SJilles Tjoelker } else if (n2 != NULL && n2->type == NREDIR) { 288aa9caaf6SPeter Wemm n2->type = NBACKGND; 289aa9caaf6SPeter Wemm } else { 290aa9caaf6SPeter Wemm n3 = (union node *)stalloc(sizeof (struct nredir)); 291aa9caaf6SPeter Wemm n3->type = NBACKGND; 292aa9caaf6SPeter Wemm n3->nredir.n = n2; 293aa9caaf6SPeter Wemm n3->nredir.redirect = NULL; 294aa9caaf6SPeter Wemm n2 = n3; 295aa9caaf6SPeter Wemm } 296aa9caaf6SPeter Wemm } 297dca867f1SJilles Tjoelker if (ntop == NULL) 298dca867f1SJilles Tjoelker ntop = n2; 299dca867f1SJilles Tjoelker else if (n1 == NULL) { 300510739ccSJilles Tjoelker n1 = makebinary(NSEMI, ntop, n2); 301dca867f1SJilles Tjoelker ntop = n1; 302aa9caaf6SPeter Wemm } 303aa9caaf6SPeter Wemm else { 304510739ccSJilles Tjoelker n3 = makebinary(NSEMI, n1->nbinary.ch2, n2); 305dca867f1SJilles Tjoelker n1->nbinary.ch2 = n3; 3064b88c807SRodney W. Grimes n1 = n3; 307aa9caaf6SPeter Wemm } 308aa9caaf6SPeter Wemm switch (tok) { 309aa9caaf6SPeter Wemm case TBACKGND: 310aa9caaf6SPeter Wemm case TSEMI: 311aa9caaf6SPeter Wemm tok = readtoken(); 3120d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 313aa9caaf6SPeter Wemm case TNL: 314aa9caaf6SPeter Wemm if (tok == TNL) { 315aa9caaf6SPeter Wemm parseheredoc(); 316aa9caaf6SPeter Wemm if (nlflag) 317dca867f1SJilles Tjoelker return ntop; 3186c0c2403SJilles Tjoelker } else if (tok == TEOF && nlflag) { 3196c0c2403SJilles Tjoelker parseheredoc(); 320dca867f1SJilles Tjoelker return ntop; 321aa9caaf6SPeter Wemm } else { 322aa9caaf6SPeter Wemm tokpushback++; 323aa9caaf6SPeter Wemm } 324135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD | CHKALIAS; 32532187151SJilles Tjoelker if (!nlflag && tokendlist[peektoken()]) 326dca867f1SJilles Tjoelker return ntop; 3274b88c807SRodney W. Grimes break; 3284b88c807SRodney W. Grimes case TEOF: 3294b88c807SRodney W. Grimes if (heredoclist) 3304b88c807SRodney W. Grimes parseheredoc(); 3314b88c807SRodney W. Grimes else 3324b88c807SRodney W. Grimes pungetc(); /* push back EOF on input */ 333dca867f1SJilles Tjoelker return ntop; 3344b88c807SRodney W. Grimes default: 33532187151SJilles Tjoelker if (nlflag) 3364b88c807SRodney W. Grimes synexpect(-1); 3374b88c807SRodney W. Grimes tokpushback++; 338dca867f1SJilles Tjoelker return ntop; 3394b88c807SRodney W. Grimes } 3404b88c807SRodney W. Grimes } 3414b88c807SRodney W. Grimes } 3424b88c807SRodney W. Grimes 3434b88c807SRodney W. Grimes 3444b88c807SRodney W. Grimes 34588328642SDavid E. O'Brien static union node * 3465134c3f7SWarner Losh andor(void) 3475134c3f7SWarner Losh { 348510739ccSJilles Tjoelker union node *n; 3494b88c807SRodney W. Grimes int t; 3504b88c807SRodney W. Grimes 351510739ccSJilles Tjoelker n = pipeline(); 3524b88c807SRodney W. Grimes for (;;) { 3534b88c807SRodney W. Grimes if ((t = readtoken()) == TAND) { 3544b88c807SRodney W. Grimes t = NAND; 3554b88c807SRodney W. Grimes } else if (t == TOR) { 3564b88c807SRodney W. Grimes t = NOR; 3574b88c807SRodney W. Grimes } else { 3584b88c807SRodney W. Grimes tokpushback++; 359510739ccSJilles Tjoelker return n; 3604b88c807SRodney W. Grimes } 361510739ccSJilles Tjoelker n = makebinary(t, n, pipeline()); 3624b88c807SRodney W. Grimes } 3634b88c807SRodney W. Grimes } 3644b88c807SRodney W. Grimes 3654b88c807SRodney W. Grimes 3664b88c807SRodney W. Grimes 36788328642SDavid E. O'Brien static union node * 3685134c3f7SWarner Losh pipeline(void) 3695134c3f7SWarner Losh { 370b785bd7dSBrian Somers union node *n1, *n2, *pipenode; 3714b88c807SRodney W. Grimes struct nodelist *lp, *prev; 372ba08f69bSJilles Tjoelker int negate, t; 3734b88c807SRodney W. Grimes 374b785bd7dSBrian Somers negate = 0; 375135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD | CHKALIAS; 3764b88c807SRodney W. Grimes TRACE(("pipeline: entered\n")); 377b785bd7dSBrian Somers while (readtoken() == TNOT) 378b785bd7dSBrian Somers negate = !negate; 379b785bd7dSBrian Somers tokpushback++; 3804b88c807SRodney W. Grimes n1 = command(); 3814b88c807SRodney W. Grimes if (readtoken() == TPIPE) { 3824b88c807SRodney W. Grimes pipenode = (union node *)stalloc(sizeof (struct npipe)); 3834b88c807SRodney W. Grimes pipenode->type = NPIPE; 3844b88c807SRodney W. Grimes pipenode->npipe.backgnd = 0; 3854b88c807SRodney W. Grimes lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 3864b88c807SRodney W. Grimes pipenode->npipe.cmdlist = lp; 3874b88c807SRodney W. Grimes lp->n = n1; 3884b88c807SRodney W. Grimes do { 3894b88c807SRodney W. Grimes prev = lp; 3904b88c807SRodney W. Grimes lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 391135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD | CHKALIAS; 392ba08f69bSJilles Tjoelker t = readtoken(); 393ba08f69bSJilles Tjoelker tokpushback++; 394ba08f69bSJilles Tjoelker if (t == TNOT) 395ba08f69bSJilles Tjoelker lp->n = pipeline(); 396ba08f69bSJilles Tjoelker else 3974b88c807SRodney W. Grimes lp->n = command(); 3984b88c807SRodney W. Grimes prev->next = lp; 3994b88c807SRodney W. Grimes } while (readtoken() == TPIPE); 4004b88c807SRodney W. Grimes lp->next = NULL; 4014b88c807SRodney W. Grimes n1 = pipenode; 4024b88c807SRodney W. Grimes } 4034b88c807SRodney W. Grimes tokpushback++; 404b785bd7dSBrian Somers if (negate) { 405b785bd7dSBrian Somers n2 = (union node *)stalloc(sizeof (struct nnot)); 406b785bd7dSBrian Somers n2->type = NNOT; 407b785bd7dSBrian Somers n2->nnot.com = n1; 408b785bd7dSBrian Somers return n2; 409b785bd7dSBrian Somers } else 4104b88c807SRodney W. Grimes return n1; 4114b88c807SRodney W. Grimes } 4124b88c807SRodney W. Grimes 4134b88c807SRodney W. Grimes 4144b88c807SRodney W. Grimes 41588328642SDavid E. O'Brien static union node * 4165134c3f7SWarner Losh command(void) 4175134c3f7SWarner Losh { 4184b88c807SRodney W. Grimes union node *n1, *n2; 4194b88c807SRodney W. Grimes union node *ap, **app; 4204b88c807SRodney W. Grimes union node *cp, **cpp; 4214b88c807SRodney W. Grimes union node *redir, **rpp; 422ba08f69bSJilles Tjoelker int t; 423b15e9aa3SJilles Tjoelker int is_subshell; 4244b88c807SRodney W. Grimes 425135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD | CHKALIAS; 426b15e9aa3SJilles Tjoelker is_subshell = 0; 427aa9caaf6SPeter Wemm redir = NULL; 428aa9caaf6SPeter Wemm n1 = NULL; 4294b88c807SRodney W. Grimes rpp = &redir; 430ab0a2172SSteve Price 4314b88c807SRodney W. Grimes /* Check for redirection which may precede command */ 4324b88c807SRodney W. Grimes while (readtoken() == TREDIR) { 4334b88c807SRodney W. Grimes *rpp = n2 = redirnode; 4344b88c807SRodney W. Grimes rpp = &n2->nfile.next; 4354b88c807SRodney W. Grimes parsefname(); 4364b88c807SRodney W. Grimes } 4374b88c807SRodney W. Grimes tokpushback++; 4384b88c807SRodney W. Grimes 4394b88c807SRodney W. Grimes switch (readtoken()) { 4404b88c807SRodney W. Grimes case TIF: 4414b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nif)); 4424b88c807SRodney W. Grimes n1->type = NIF; 44332187151SJilles Tjoelker if ((n1->nif.test = list(0)) == NULL) 444427748f7STim J. Robbins synexpect(-1); 4456ab99f87SJilles Tjoelker consumetoken(TTHEN); 44632187151SJilles Tjoelker n1->nif.ifpart = list(0); 4474b88c807SRodney W. Grimes n2 = n1; 4484b88c807SRodney W. Grimes while (readtoken() == TELIF) { 4494b88c807SRodney W. Grimes n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 4504b88c807SRodney W. Grimes n2 = n2->nif.elsepart; 4514b88c807SRodney W. Grimes n2->type = NIF; 45232187151SJilles Tjoelker if ((n2->nif.test = list(0)) == NULL) 453427748f7STim J. Robbins synexpect(-1); 4546ab99f87SJilles Tjoelker consumetoken(TTHEN); 45532187151SJilles Tjoelker n2->nif.ifpart = list(0); 4564b88c807SRodney W. Grimes } 4574b88c807SRodney W. Grimes if (lasttoken == TELSE) 45832187151SJilles Tjoelker n2->nif.elsepart = list(0); 4594b88c807SRodney W. Grimes else { 4604b88c807SRodney W. Grimes n2->nif.elsepart = NULL; 4614b88c807SRodney W. Grimes tokpushback++; 4624b88c807SRodney W. Grimes } 4636ab99f87SJilles Tjoelker consumetoken(TFI); 464135ff4b5SJilles Tjoelker checkkwd = CHKKWD | CHKALIAS; 4654b88c807SRodney W. Grimes break; 4664b88c807SRodney W. Grimes case TWHILE: 4676ab99f87SJilles Tjoelker case TUNTIL: 468510739ccSJilles Tjoelker t = lasttoken; 46932187151SJilles Tjoelker if ((n1 = list(0)) == NULL) 470427748f7STim J. Robbins synexpect(-1); 4716ab99f87SJilles Tjoelker consumetoken(TDO); 47232187151SJilles Tjoelker n1 = makebinary((t == TWHILE)? NWHILE : NUNTIL, n1, list(0)); 4736ab99f87SJilles Tjoelker consumetoken(TDONE); 474135ff4b5SJilles Tjoelker checkkwd = CHKKWD | CHKALIAS; 4754b88c807SRodney W. Grimes break; 4764b88c807SRodney W. Grimes case TFOR: 4774b88c807SRodney W. Grimes if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 4784b88c807SRodney W. Grimes synerror("Bad for loop variable"); 4794b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nfor)); 4804b88c807SRodney W. Grimes n1->type = NFOR; 4814b88c807SRodney W. Grimes n1->nfor.var = wordtext; 48272f750dcSJilles Tjoelker checkkwd = CHKNL; 48372f750dcSJilles Tjoelker if (readtoken() == TWORD && !quoteflag && 48472f750dcSJilles Tjoelker equal(wordtext, "in")) { 4854b88c807SRodney W. Grimes app = ≈ 4864b88c807SRodney W. Grimes while (readtoken() == TWORD) { 48747752ed6SJilles Tjoelker n2 = makename(); 4884b88c807SRodney W. Grimes *app = n2; 4894b88c807SRodney W. Grimes app = &n2->narg.next; 4904b88c807SRodney W. Grimes } 4914b88c807SRodney W. Grimes *app = NULL; 4924b88c807SRodney W. Grimes n1->nfor.args = ap; 49372f750dcSJilles Tjoelker if (lasttoken == TNL) 49472f750dcSJilles Tjoelker tokpushback++; 49572f750dcSJilles Tjoelker else if (lasttoken != TSEMI) 4964b88c807SRodney W. Grimes synexpect(-1); 4974b88c807SRodney W. Grimes } else { 498811beb4bSStefan Farfeleder static char argvars[5] = { 499811beb4bSStefan Farfeleder CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 500811beb4bSStefan Farfeleder }; 5014b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct narg)); 5024b88c807SRodney W. Grimes n2->type = NARG; 503811beb4bSStefan Farfeleder n2->narg.text = argvars; 5044b88c807SRodney W. Grimes n2->narg.backquote = NULL; 5054b88c807SRodney W. Grimes n2->narg.next = NULL; 5064b88c807SRodney W. Grimes n1->nfor.args = n2; 5074b88c807SRodney W. Grimes /* 5084b88c807SRodney W. Grimes * Newline or semicolon here is optional (but note 5094b88c807SRodney W. Grimes * that the original Bourne shell only allowed NL). 5104b88c807SRodney W. Grimes */ 51172f750dcSJilles Tjoelker if (lasttoken != TSEMI) 5124b88c807SRodney W. Grimes tokpushback++; 5134b88c807SRodney W. Grimes } 514135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD | CHKALIAS; 5154b88c807SRodney W. Grimes if ((t = readtoken()) == TDO) 5164b88c807SRodney W. Grimes t = TDONE; 5174b88c807SRodney W. Grimes else if (t == TBEGIN) 5184b88c807SRodney W. Grimes t = TEND; 5194b88c807SRodney W. Grimes else 5204b88c807SRodney W. Grimes synexpect(-1); 52132187151SJilles Tjoelker n1->nfor.body = list(0); 5226ab99f87SJilles Tjoelker consumetoken(t); 523135ff4b5SJilles Tjoelker checkkwd = CHKKWD | CHKALIAS; 5244b88c807SRodney W. Grimes break; 5254b88c807SRodney W. Grimes case TCASE: 5264b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct ncase)); 5274b88c807SRodney W. Grimes n1->type = NCASE; 5286ab99f87SJilles Tjoelker consumetoken(TWORD); 52947752ed6SJilles Tjoelker n1->ncase.expr = makename(); 53072f750dcSJilles Tjoelker checkkwd = CHKNL; 53172f750dcSJilles Tjoelker if (readtoken() != TWORD || ! equal(wordtext, "in")) 5324b88c807SRodney W. Grimes synerror("expecting \"in\""); 5334b88c807SRodney W. Grimes cpp = &n1->ncase.cases; 534135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD, readtoken(); 535e00e16adSTim J. Robbins while (lasttoken != TESAC) { 5364b88c807SRodney W. Grimes *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 5374b88c807SRodney W. Grimes cp->type = NCLIST; 5384b88c807SRodney W. Grimes app = &cp->nclist.pattern; 539f7a9b7feSTim J. Robbins if (lasttoken == TLP) 540f7a9b7feSTim J. Robbins readtoken(); 5414b88c807SRodney W. Grimes for (;;) { 54247752ed6SJilles Tjoelker *app = ap = makename(); 543135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD; 544135ff4b5SJilles Tjoelker if (readtoken() != TPIPE) 5454b88c807SRodney W. Grimes break; 5464b88c807SRodney W. Grimes app = &ap->narg.next; 547650488feSSean Eric Fagan readtoken(); 5484b88c807SRodney W. Grimes } 5494b88c807SRodney W. Grimes ap->narg.next = NULL; 5504b88c807SRodney W. Grimes if (lasttoken != TRP) 551135ff4b5SJilles Tjoelker synexpect(TRP); 55232187151SJilles Tjoelker cp->nclist.body = list(0); 553650488feSSean Eric Fagan 554135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD | CHKALIAS; 555650488feSSean Eric Fagan if ((t = readtoken()) != TESAC) { 556c9afaa63SJilles Tjoelker if (t == TENDCASE) 557c9afaa63SJilles Tjoelker ; 558c9afaa63SJilles Tjoelker else if (t == TFALLTHRU) 559c9afaa63SJilles Tjoelker cp->type = NCLISTFALLTHRU; 560650488feSSean Eric Fagan else 561c9afaa63SJilles Tjoelker synexpect(TENDCASE); 562135ff4b5SJilles Tjoelker checkkwd = CHKNL | CHKKWD, readtoken(); 5634b88c807SRodney W. Grimes } 564650488feSSean Eric Fagan cpp = &cp->nclist.next; 565e00e16adSTim J. Robbins } 5664b88c807SRodney W. Grimes *cpp = NULL; 567135ff4b5SJilles Tjoelker checkkwd = CHKKWD | CHKALIAS; 5684b88c807SRodney W. Grimes break; 5694b88c807SRodney W. Grimes case TLP: 5704b88c807SRodney W. Grimes n1 = (union node *)stalloc(sizeof (struct nredir)); 5714b88c807SRodney W. Grimes n1->type = NSUBSHELL; 57232187151SJilles Tjoelker n1->nredir.n = list(0); 5734b88c807SRodney W. Grimes n1->nredir.redirect = NULL; 5746ab99f87SJilles Tjoelker consumetoken(TRP); 575135ff4b5SJilles Tjoelker checkkwd = CHKKWD | CHKALIAS; 576b15e9aa3SJilles Tjoelker is_subshell = 1; 5774b88c807SRodney W. Grimes break; 5784b88c807SRodney W. Grimes case TBEGIN: 57932187151SJilles Tjoelker n1 = list(0); 5806ab99f87SJilles Tjoelker consumetoken(TEND); 581135ff4b5SJilles Tjoelker checkkwd = CHKKWD | CHKALIAS; 5824b88c807SRodney W. Grimes break; 5833cfb11c4SJilles Tjoelker /* A simple command must have at least one redirection or word. */ 584cac4830cSJilles Tjoelker case TBACKGND: 585248ffae5SJoerg Wunsch case TSEMI: 586d8d737d7STim J. Robbins case TAND: 587d8d737d7STim J. Robbins case TOR: 588adc2e8dfSJilles Tjoelker case TPIPE: 589adc2e8dfSJilles Tjoelker case TENDCASE: 590adc2e8dfSJilles Tjoelker case TFALLTHRU: 5913cfb11c4SJilles Tjoelker case TEOF: 5923cfb11c4SJilles Tjoelker case TNL: 5933cfb11c4SJilles Tjoelker case TRP: 594aa9caaf6SPeter Wemm if (!redir) 595aa9caaf6SPeter Wemm synexpect(-1); 5964b88c807SRodney W. Grimes case TWORD: 5974b88c807SRodney W. Grimes tokpushback++; 5986c0bde79SBrian Somers n1 = simplecmd(rpp, redir); 599ba08f69bSJilles Tjoelker return n1; 6004b88c807SRodney W. Grimes default: 6014b88c807SRodney W. Grimes synexpect(-1); 6024b88c807SRodney W. Grimes } 6034b88c807SRodney W. Grimes 6044b88c807SRodney W. Grimes /* Now check for redirection which may follow command */ 6054b88c807SRodney W. Grimes while (readtoken() == TREDIR) { 6064b88c807SRodney W. Grimes *rpp = n2 = redirnode; 6074b88c807SRodney W. Grimes rpp = &n2->nfile.next; 6084b88c807SRodney W. Grimes parsefname(); 6094b88c807SRodney W. Grimes } 6104b88c807SRodney W. Grimes tokpushback++; 6114b88c807SRodney W. Grimes *rpp = NULL; 6124b88c807SRodney W. Grimes if (redir) { 613b15e9aa3SJilles Tjoelker if (!is_subshell) { 6144b88c807SRodney W. Grimes n2 = (union node *)stalloc(sizeof (struct nredir)); 6154b88c807SRodney W. Grimes n2->type = NREDIR; 6164b88c807SRodney W. Grimes n2->nredir.n = n1; 6174b88c807SRodney W. Grimes n1 = n2; 6184b88c807SRodney W. Grimes } 6194b88c807SRodney W. Grimes n1->nredir.redirect = redir; 6204b88c807SRodney W. Grimes } 6216c0bde79SBrian Somers 6224b88c807SRodney W. Grimes return n1; 6234b88c807SRodney W. Grimes } 6244b88c807SRodney W. Grimes 6254b88c807SRodney W. Grimes 62688328642SDavid E. O'Brien static union node * 6275134c3f7SWarner Losh simplecmd(union node **rpp, union node *redir) 6284b88c807SRodney W. Grimes { 6294b88c807SRodney W. Grimes union node *args, **app; 6304b88c807SRodney W. Grimes union node **orig_rpp = rpp; 631d5af15eaSJilles Tjoelker union node *n = NULL; 63267e109adSJilles Tjoelker int special; 63305a447d0SJilles Tjoelker int savecheckkwd; 6344b88c807SRodney W. Grimes 6354b88c807SRodney W. Grimes /* If we don't have any redirections already, then we must reset */ 6364b88c807SRodney W. Grimes /* rpp to be the address of the local redir variable. */ 63774136dc3SPedro F. Giffuni if (redir == NULL) 6384b88c807SRodney W. Grimes rpp = &redir; 6394b88c807SRodney W. Grimes 6404b88c807SRodney W. Grimes args = NULL; 6414b88c807SRodney W. Grimes app = &args; 6424b88c807SRodney W. Grimes /* 6434b88c807SRodney W. Grimes * We save the incoming value, because we need this for shell 6444b88c807SRodney W. Grimes * functions. There can not be a redirect or an argument between 6454b88c807SRodney W. Grimes * the function name and the open parenthesis. 6464b88c807SRodney W. Grimes */ 6474b88c807SRodney W. Grimes orig_rpp = rpp; 6484b88c807SRodney W. Grimes 64905a447d0SJilles Tjoelker savecheckkwd = CHKALIAS; 65005a447d0SJilles Tjoelker 6514b88c807SRodney W. Grimes for (;;) { 65205a447d0SJilles Tjoelker checkkwd = savecheckkwd; 6534b88c807SRodney W. Grimes if (readtoken() == TWORD) { 65447752ed6SJilles Tjoelker n = makename(); 6554b88c807SRodney W. Grimes *app = n; 6564b88c807SRodney W. Grimes app = &n->narg.next; 65705a447d0SJilles Tjoelker if (savecheckkwd != 0 && !isassignment(wordtext)) 65805a447d0SJilles Tjoelker savecheckkwd = 0; 6594b88c807SRodney W. Grimes } else if (lasttoken == TREDIR) { 6604b88c807SRodney W. Grimes *rpp = n = redirnode; 6614b88c807SRodney W. Grimes rpp = &n->nfile.next; 6624b88c807SRodney W. Grimes parsefname(); /* read name of redirection file */ 6634b88c807SRodney W. Grimes } else if (lasttoken == TLP && app == &args->narg.next 6644b88c807SRodney W. Grimes && rpp == orig_rpp) { 6654b88c807SRodney W. Grimes /* We have a function */ 6666ab99f87SJilles Tjoelker consumetoken(TRP); 667b71085aaSStefan Farfeleder funclinno = plinno; 668074e83b1SJilles Tjoelker /* 669074e83b1SJilles Tjoelker * - Require plain text. 670074e83b1SJilles Tjoelker * - Functions with '/' cannot be called. 671a1251487SJilles Tjoelker * - Reject name=(). 672a1251487SJilles Tjoelker * - Reject ksh extended glob patterns. 673074e83b1SJilles Tjoelker */ 674074e83b1SJilles Tjoelker if (!noexpand(n->narg.text) || quoteflag || 675a1251487SJilles Tjoelker strchr(n->narg.text, '/') || 676a1251487SJilles Tjoelker strchr("!%*+-=?@}~", 677a1251487SJilles Tjoelker n->narg.text[strlen(n->narg.text) - 1])) 6784b88c807SRodney W. Grimes synerror("Bad function name"); 679074e83b1SJilles Tjoelker rmescapes(n->narg.text); 68067e109adSJilles Tjoelker if (find_builtin(n->narg.text, &special) >= 0 && 68167e109adSJilles Tjoelker special) 68267e109adSJilles Tjoelker synerror("Cannot override a special builtin with a function"); 6834b88c807SRodney W. Grimes n->type = NDEFUN; 6844b88c807SRodney W. Grimes n->narg.next = command(); 685b71085aaSStefan Farfeleder funclinno = 0; 686d5af15eaSJilles Tjoelker return n; 6874b88c807SRodney W. Grimes } else { 6884b88c807SRodney W. Grimes tokpushback++; 6894b88c807SRodney W. Grimes break; 6904b88c807SRodney W. Grimes } 6914b88c807SRodney W. Grimes } 6924b88c807SRodney W. Grimes *app = NULL; 6934b88c807SRodney W. Grimes *rpp = NULL; 6944b88c807SRodney W. Grimes n = (union node *)stalloc(sizeof (struct ncmd)); 6954b88c807SRodney W. Grimes n->type = NCMD; 6964b88c807SRodney W. Grimes n->ncmd.args = args; 6974b88c807SRodney W. Grimes n->ncmd.redirect = redir; 6984b88c807SRodney W. Grimes return n; 6994b88c807SRodney W. Grimes } 7004b88c807SRodney W. Grimes 70188328642SDavid E. O'Brien static union node * 7025134c3f7SWarner Losh makename(void) 7035134c3f7SWarner Losh { 704aa9caaf6SPeter Wemm union node *n; 705aa9caaf6SPeter Wemm 706aa9caaf6SPeter Wemm n = (union node *)stalloc(sizeof (struct narg)); 707aa9caaf6SPeter Wemm n->type = NARG; 708aa9caaf6SPeter Wemm n->narg.next = NULL; 709aa9caaf6SPeter Wemm n->narg.text = wordtext; 710aa9caaf6SPeter Wemm n->narg.backquote = backquotelist; 711aa9caaf6SPeter Wemm return n; 712aa9caaf6SPeter Wemm } 713aa9caaf6SPeter Wemm 714510739ccSJilles Tjoelker static union node * 715510739ccSJilles Tjoelker makebinary(int type, union node *n1, union node *n2) 716510739ccSJilles Tjoelker { 717510739ccSJilles Tjoelker union node *n; 718510739ccSJilles Tjoelker 719510739ccSJilles Tjoelker n = (union node *)stalloc(sizeof (struct nbinary)); 720510739ccSJilles Tjoelker n->type = type; 721510739ccSJilles Tjoelker n->nbinary.ch1 = n1; 722510739ccSJilles Tjoelker n->nbinary.ch2 = n2; 723510739ccSJilles Tjoelker return (n); 724510739ccSJilles Tjoelker } 725510739ccSJilles Tjoelker 726aa7b6f82SDavid E. O'Brien void 72748f49aacSJilles Tjoelker forcealias(void) 72848f49aacSJilles Tjoelker { 72948f49aacSJilles Tjoelker checkkwd |= CHKALIAS; 73048f49aacSJilles Tjoelker } 73148f49aacSJilles Tjoelker 73248f49aacSJilles Tjoelker void 733aa7b6f82SDavid E. O'Brien fixredir(union node *n, const char *text, int err) 734aa9caaf6SPeter Wemm { 735aa9caaf6SPeter Wemm TRACE(("Fix redir %s %d\n", text, err)); 736aa9caaf6SPeter Wemm if (!err) 737aa9caaf6SPeter Wemm n->ndup.vname = NULL; 738aa9caaf6SPeter Wemm 739aa9caaf6SPeter Wemm if (is_digit(text[0]) && text[1] == '\0') 740aa9caaf6SPeter Wemm n->ndup.dupfd = digit_val(text[0]); 741aa9caaf6SPeter Wemm else if (text[0] == '-' && text[1] == '\0') 742aa9caaf6SPeter Wemm n->ndup.dupfd = -1; 743aa9caaf6SPeter Wemm else { 744aa9caaf6SPeter Wemm 745aa9caaf6SPeter Wemm if (err) 746aa9caaf6SPeter Wemm synerror("Bad fd number"); 747aa9caaf6SPeter Wemm else 748aa9caaf6SPeter Wemm n->ndup.vname = makename(); 749aa9caaf6SPeter Wemm } 750aa9caaf6SPeter Wemm } 751aa9caaf6SPeter Wemm 7524b88c807SRodney W. Grimes 75388328642SDavid E. O'Brien static void 7545134c3f7SWarner Losh parsefname(void) 7555134c3f7SWarner Losh { 7564b88c807SRodney W. Grimes union node *n = redirnode; 7574b88c807SRodney W. Grimes 7586ab99f87SJilles Tjoelker consumetoken(TWORD); 7594b88c807SRodney W. Grimes if (n->type == NHERE) { 7604b88c807SRodney W. Grimes struct heredoc *here = heredoc; 7614b88c807SRodney W. Grimes struct heredoc *p; 7624b88c807SRodney W. Grimes 7634b88c807SRodney W. Grimes if (quoteflag == 0) 7644b88c807SRodney W. Grimes n->type = NXHERE; 7654b88c807SRodney W. Grimes TRACE(("Here document %d\n", n->type)); 7664b88c807SRodney W. Grimes if (here->striptabs) { 7674b88c807SRodney W. Grimes while (*wordtext == '\t') 7684b88c807SRodney W. Grimes wordtext++; 7694b88c807SRodney W. Grimes } 77072238faaSJilles Tjoelker if (! noexpand(wordtext)) 7714b88c807SRodney W. Grimes synerror("Illegal eof marker for << redirection"); 7724b88c807SRodney W. Grimes rmescapes(wordtext); 7734b88c807SRodney W. Grimes here->eofmark = wordtext; 7744b88c807SRodney W. Grimes here->next = NULL; 7754b88c807SRodney W. Grimes if (heredoclist == NULL) 7764b88c807SRodney W. Grimes heredoclist = here; 7774b88c807SRodney W. Grimes else { 7784b88c807SRodney W. Grimes for (p = heredoclist ; p->next ; p = p->next); 7794b88c807SRodney W. Grimes p->next = here; 7804b88c807SRodney W. Grimes } 7814b88c807SRodney W. Grimes } else if (n->type == NTOFD || n->type == NFROMFD) { 782aa9caaf6SPeter Wemm fixredir(n, wordtext, 0); 7834b88c807SRodney W. Grimes } else { 784aa9caaf6SPeter Wemm n->nfile.fname = makename(); 7854b88c807SRodney W. Grimes } 7864b88c807SRodney W. Grimes } 7874b88c807SRodney W. Grimes 7884b88c807SRodney W. Grimes 7894b88c807SRodney W. Grimes /* 7904b88c807SRodney W. Grimes * Input any here documents. 7914b88c807SRodney W. Grimes */ 7924b88c807SRodney W. Grimes 79388328642SDavid E. O'Brien static void 7945134c3f7SWarner Losh parseheredoc(void) 7955134c3f7SWarner Losh { 7964b88c807SRodney W. Grimes struct heredoc *here; 7974b88c807SRodney W. Grimes union node *n; 7984b88c807SRodney W. Grimes 7994b88c807SRodney W. Grimes while (heredoclist) { 8004b88c807SRodney W. Grimes here = heredoclist; 8014b88c807SRodney W. Grimes heredoclist = here->next; 8024b88c807SRodney W. Grimes if (needprompt) { 8034b88c807SRodney W. Grimes setprompt(2); 8044b88c807SRodney W. Grimes needprompt = 0; 8054b88c807SRodney W. Grimes } 8064b88c807SRodney W. Grimes readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 8074b88c807SRodney W. Grimes here->eofmark, here->striptabs); 80847752ed6SJilles Tjoelker n = makename(); 8094b88c807SRodney W. Grimes here->here->nhere.doc = n; 8104b88c807SRodney W. Grimes } 8114b88c807SRodney W. Grimes } 8124b88c807SRodney W. Grimes 81388328642SDavid E. O'Brien static int 8145134c3f7SWarner Losh peektoken(void) 8155134c3f7SWarner Losh { 8164b88c807SRodney W. Grimes int t; 8174b88c807SRodney W. Grimes 8184b88c807SRodney W. Grimes t = readtoken(); 8194b88c807SRodney W. Grimes tokpushback++; 8204b88c807SRodney W. Grimes return (t); 8214b88c807SRodney W. Grimes } 8224b88c807SRodney W. Grimes 82388328642SDavid E. O'Brien static int 8245134c3f7SWarner Losh readtoken(void) 8255134c3f7SWarner Losh { 8264b88c807SRodney W. Grimes int t; 8274b88c807SRodney W. Grimes struct alias *ap; 8284b88c807SRodney W. Grimes #ifdef DEBUG 8294b88c807SRodney W. Grimes int alreadyseen = tokpushback; 8304b88c807SRodney W. Grimes #endif 8314b88c807SRodney W. Grimes 8324b88c807SRodney W. Grimes top: 8334b88c807SRodney W. Grimes t = xxreadtoken(); 8344b88c807SRodney W. Grimes 8354b88c807SRodney W. Grimes /* 8364b88c807SRodney W. Grimes * eat newlines 8374b88c807SRodney W. Grimes */ 838135ff4b5SJilles Tjoelker if (checkkwd & CHKNL) { 8394b88c807SRodney W. Grimes while (t == TNL) { 8404b88c807SRodney W. Grimes parseheredoc(); 8414b88c807SRodney W. Grimes t = xxreadtoken(); 8424b88c807SRodney W. Grimes } 843135ff4b5SJilles Tjoelker } 844135ff4b5SJilles Tjoelker 8454b88c807SRodney W. Grimes /* 8464b88c807SRodney W. Grimes * check for keywords and aliases 8474b88c807SRodney W. Grimes */ 848aa9caaf6SPeter Wemm if (t == TWORD && !quoteflag) 849aa9caaf6SPeter Wemm { 8508b7808bcSJuli Mallett const char * const *pp; 8514b88c807SRodney W. Grimes 852135ff4b5SJilles Tjoelker if (checkkwd & CHKKWD) 8538b7808bcSJuli Mallett for (pp = parsekwd; *pp; pp++) { 854aa9caaf6SPeter Wemm if (**pp == *wordtext && equal(*pp, wordtext)) 855aa9caaf6SPeter Wemm { 8564b88c807SRodney W. Grimes lasttoken = t = pp - parsekwd + KWDOFFSET; 8574b88c807SRodney W. Grimes TRACE(("keyword %s recognized\n", tokname[t])); 8584b88c807SRodney W. Grimes goto out; 8594b88c807SRodney W. Grimes } 8604b88c807SRodney W. Grimes } 861135ff4b5SJilles Tjoelker if (checkkwd & CHKALIAS && 8624417f629SPeter Wemm (ap = lookupalias(wordtext, 1)) != NULL) { 8634b88c807SRodney W. Grimes pushstring(ap->val, strlen(ap->val), ap); 8644b88c807SRodney W. Grimes goto top; 8654b88c807SRodney W. Grimes } 8664b88c807SRodney W. Grimes } 8674b88c807SRodney W. Grimes out: 868135ff4b5SJilles Tjoelker if (t != TNOT) 869135ff4b5SJilles Tjoelker checkkwd = 0; 870135ff4b5SJilles Tjoelker 8714b88c807SRodney W. Grimes #ifdef DEBUG 8724b88c807SRodney W. Grimes if (!alreadyseen) 8734b88c807SRodney W. Grimes TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 8744b88c807SRodney W. Grimes else 8754b88c807SRodney W. Grimes TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 8764b88c807SRodney W. Grimes #endif 8774b88c807SRodney W. Grimes return (t); 8784b88c807SRodney W. Grimes } 8794b88c807SRodney W. Grimes 8804b88c807SRodney W. Grimes 8814b88c807SRodney W. Grimes /* 8824b88c807SRodney W. Grimes * Read the next input token. 8834b88c807SRodney W. Grimes * If the token is a word, we set backquotelist to the list of cmds in 8844b88c807SRodney W. Grimes * backquotes. We set quoteflag to true if any part of the word was 8854b88c807SRodney W. Grimes * quoted. 8864b88c807SRodney W. Grimes * If the token is TREDIR, then we set redirnode to a structure containing 8874b88c807SRodney W. Grimes * the redirection. 8884b88c807SRodney W. Grimes * In all cases, the variable startlinno is set to the number of the line 8894b88c807SRodney W. Grimes * on which the token starts. 8904b88c807SRodney W. Grimes * 8914b88c807SRodney W. Grimes * [Change comment: here documents and internal procedures] 8924b88c807SRodney W. Grimes * [Readtoken shouldn't have any arguments. Perhaps we should make the 8934b88c807SRodney W. Grimes * word parsing code into a separate routine. In this case, readtoken 8944b88c807SRodney W. Grimes * doesn't need to have any internal procedures, but parseword does. 8954b88c807SRodney W. Grimes * We could also make parseoperator in essence the main routine, and 8964b88c807SRodney W. Grimes * have parseword (readtoken1?) handle both words and redirection.] 8974b88c807SRodney W. Grimes */ 8984b88c807SRodney W. Grimes 8994b88c807SRodney W. Grimes #define RETURN(token) return lasttoken = token 9004b88c807SRodney W. Grimes 90188328642SDavid E. O'Brien static int 9025134c3f7SWarner Losh xxreadtoken(void) 9035134c3f7SWarner Losh { 9047920a31dSSteve Price int c; 9054b88c807SRodney W. Grimes 9064b88c807SRodney W. Grimes if (tokpushback) { 9074b88c807SRodney W. Grimes tokpushback = 0; 9084b88c807SRodney W. Grimes return lasttoken; 9094b88c807SRodney W. Grimes } 9104b88c807SRodney W. Grimes if (needprompt) { 9114b88c807SRodney W. Grimes setprompt(2); 9124b88c807SRodney W. Grimes needprompt = 0; 9134b88c807SRodney W. Grimes } 9144b88c807SRodney W. Grimes startlinno = plinno; 9154b88c807SRodney W. Grimes for (;;) { /* until token or start of word found */ 9164b88c807SRodney W. Grimes c = pgetc_macro(); 9174b88c807SRodney W. Grimes switch (c) { 9184b88c807SRodney W. Grimes case ' ': case '\t': 9194b88c807SRodney W. Grimes continue; 9204b88c807SRodney W. Grimes case '#': 9214b88c807SRodney W. Grimes while ((c = pgetc()) != '\n' && c != PEOF); 9224b88c807SRodney W. Grimes pungetc(); 9234b88c807SRodney W. Grimes continue; 9244b88c807SRodney W. Grimes case '\\': 9254b88c807SRodney W. Grimes if (pgetc() == '\n') { 9264b88c807SRodney W. Grimes startlinno = ++plinno; 9274b88c807SRodney W. Grimes if (doprompt) 9284b88c807SRodney W. Grimes setprompt(2); 9294b88c807SRodney W. Grimes else 9304b88c807SRodney W. Grimes setprompt(0); 9314b88c807SRodney W. Grimes continue; 9324b88c807SRodney W. Grimes } 9334b88c807SRodney W. Grimes pungetc(); 934622fdf32SJilles Tjoelker /* FALLTHROUGH */ 935622fdf32SJilles Tjoelker default: 936622fdf32SJilles Tjoelker return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 9374b88c807SRodney W. Grimes case '\n': 9384b88c807SRodney W. Grimes plinno++; 9394b88c807SRodney W. Grimes needprompt = doprompt; 9404b88c807SRodney W. Grimes RETURN(TNL); 9414b88c807SRodney W. Grimes case PEOF: 9424b88c807SRodney W. Grimes RETURN(TEOF); 9434b88c807SRodney W. Grimes case '&': 9440b4b9c81SJilles Tjoelker if (pgetc_linecont() == '&') 9454b88c807SRodney W. Grimes RETURN(TAND); 9464b88c807SRodney W. Grimes pungetc(); 9474b88c807SRodney W. Grimes RETURN(TBACKGND); 9484b88c807SRodney W. Grimes case '|': 9490b4b9c81SJilles Tjoelker if (pgetc_linecont() == '|') 9504b88c807SRodney W. Grimes RETURN(TOR); 9514b88c807SRodney W. Grimes pungetc(); 9524b88c807SRodney W. Grimes RETURN(TPIPE); 9534b88c807SRodney W. Grimes case ';': 9540b4b9c81SJilles Tjoelker c = pgetc_linecont(); 955c9afaa63SJilles Tjoelker if (c == ';') 9564b88c807SRodney W. Grimes RETURN(TENDCASE); 957c9afaa63SJilles Tjoelker else if (c == '&') 958c9afaa63SJilles Tjoelker RETURN(TFALLTHRU); 9594b88c807SRodney W. Grimes pungetc(); 9604b88c807SRodney W. Grimes RETURN(TSEMI); 9614b88c807SRodney W. Grimes case '(': 9624b88c807SRodney W. Grimes RETURN(TLP); 9634b88c807SRodney W. Grimes case ')': 9644b88c807SRodney W. Grimes RETURN(TRP); 9654b88c807SRodney W. Grimes } 9664b88c807SRodney W. Grimes } 9674b88c807SRodney W. Grimes #undef RETURN 9684b88c807SRodney W. Grimes } 9694b88c807SRodney W. Grimes 9704b88c807SRodney W. Grimes 97188328642SDavid E. O'Brien #define MAXNEST_static 8 9728cf06f5eSJilles Tjoelker struct tokenstate 9738cf06f5eSJilles Tjoelker { 9748cf06f5eSJilles Tjoelker const char *syntax; /* *SYNTAX */ 9758cf06f5eSJilles Tjoelker int parenlevel; /* levels of parentheses in arithmetic */ 9768cf06f5eSJilles Tjoelker enum tokenstate_category 9778cf06f5eSJilles Tjoelker { 9788cf06f5eSJilles Tjoelker TSTATE_TOP, 9798cf06f5eSJilles Tjoelker TSTATE_VAR_OLD, /* ${var+-=?}, inherits dquotes */ 9808cf06f5eSJilles Tjoelker TSTATE_VAR_NEW, /* other ${var...}, own dquote state */ 9818cf06f5eSJilles Tjoelker TSTATE_ARITH 9828cf06f5eSJilles Tjoelker } category; 9838cf06f5eSJilles Tjoelker }; 9848cf06f5eSJilles Tjoelker 9858cf06f5eSJilles Tjoelker 986cab84206SJilles Tjoelker /* 987671a890eSJilles Tjoelker * Check to see whether we are at the end of the here document. When this 988671a890eSJilles Tjoelker * is called, c is set to the first character of the next input line. If 989671a890eSJilles Tjoelker * we are at the end of the here document, this routine sets the c to PEOF. 990671a890eSJilles Tjoelker * The new value of c is returned. 991671a890eSJilles Tjoelker */ 992671a890eSJilles Tjoelker 993671a890eSJilles Tjoelker static int 99472238faaSJilles Tjoelker checkend(int c, const char *eofmark, int striptabs) 995671a890eSJilles Tjoelker { 996671a890eSJilles Tjoelker if (striptabs) { 997671a890eSJilles Tjoelker while (c == '\t') 998671a890eSJilles Tjoelker c = pgetc(); 999671a890eSJilles Tjoelker } 1000671a890eSJilles Tjoelker if (c == *eofmark) { 100172238faaSJilles Tjoelker int c2; 100272238faaSJilles Tjoelker const char *q; 1003671a890eSJilles Tjoelker 100472238faaSJilles Tjoelker for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++) 100572238faaSJilles Tjoelker ; 100672238faaSJilles Tjoelker if ((c2 == PEOF || c2 == '\n') && *q == '\0') { 1007671a890eSJilles Tjoelker c = PEOF; 100872238faaSJilles Tjoelker if (c2 == '\n') { 1009671a890eSJilles Tjoelker plinno++; 1010671a890eSJilles Tjoelker needprompt = doprompt; 1011671a890eSJilles Tjoelker } 1012671a890eSJilles Tjoelker } else { 101372238faaSJilles Tjoelker pungetc(); 101472238faaSJilles Tjoelker pushstring(eofmark + 1, q - (eofmark + 1), NULL); 1015671a890eSJilles Tjoelker } 101692fe71faSJilles Tjoelker } else if (c == '\n' && *eofmark == '\0') { 101792fe71faSJilles Tjoelker c = PEOF; 101892fe71faSJilles Tjoelker plinno++; 101992fe71faSJilles Tjoelker needprompt = doprompt; 1020671a890eSJilles Tjoelker } 1021671a890eSJilles Tjoelker return (c); 1022671a890eSJilles Tjoelker } 1023671a890eSJilles Tjoelker 1024671a890eSJilles Tjoelker 1025671a890eSJilles Tjoelker /* 10263f9b4e9aSJilles Tjoelker * Parse a redirection operator. The variable "out" points to a string 10273f9b4e9aSJilles Tjoelker * specifying the fd to be redirected. The variable "c" contains the 10283f9b4e9aSJilles Tjoelker * first character of the redirection operator. 10293f9b4e9aSJilles Tjoelker */ 10303f9b4e9aSJilles Tjoelker 10313f9b4e9aSJilles Tjoelker static void 10323f9b4e9aSJilles Tjoelker parseredir(char *out, int c) 10333f9b4e9aSJilles Tjoelker { 10343f9b4e9aSJilles Tjoelker char fd = *out; 10353f9b4e9aSJilles Tjoelker union node *np; 10363f9b4e9aSJilles Tjoelker 10373f9b4e9aSJilles Tjoelker np = (union node *)stalloc(sizeof (struct nfile)); 10383f9b4e9aSJilles Tjoelker if (c == '>') { 10393f9b4e9aSJilles Tjoelker np->nfile.fd = 1; 10400b4b9c81SJilles Tjoelker c = pgetc_linecont(); 10413f9b4e9aSJilles Tjoelker if (c == '>') 10423f9b4e9aSJilles Tjoelker np->type = NAPPEND; 10433f9b4e9aSJilles Tjoelker else if (c == '&') 10443f9b4e9aSJilles Tjoelker np->type = NTOFD; 10453f9b4e9aSJilles Tjoelker else if (c == '|') 10463f9b4e9aSJilles Tjoelker np->type = NCLOBBER; 10473f9b4e9aSJilles Tjoelker else { 10483f9b4e9aSJilles Tjoelker np->type = NTO; 10493f9b4e9aSJilles Tjoelker pungetc(); 10503f9b4e9aSJilles Tjoelker } 10513f9b4e9aSJilles Tjoelker } else { /* c == '<' */ 10523f9b4e9aSJilles Tjoelker np->nfile.fd = 0; 10530b4b9c81SJilles Tjoelker c = pgetc_linecont(); 10543f9b4e9aSJilles Tjoelker if (c == '<') { 10553f9b4e9aSJilles Tjoelker if (sizeof (struct nfile) != sizeof (struct nhere)) { 10563f9b4e9aSJilles Tjoelker np = (union node *)stalloc(sizeof (struct nhere)); 10573f9b4e9aSJilles Tjoelker np->nfile.fd = 0; 10583f9b4e9aSJilles Tjoelker } 10593f9b4e9aSJilles Tjoelker np->type = NHERE; 10603f9b4e9aSJilles Tjoelker heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 10613f9b4e9aSJilles Tjoelker heredoc->here = np; 10620b4b9c81SJilles Tjoelker if ((c = pgetc_linecont()) == '-') { 10633f9b4e9aSJilles Tjoelker heredoc->striptabs = 1; 10643f9b4e9aSJilles Tjoelker } else { 10653f9b4e9aSJilles Tjoelker heredoc->striptabs = 0; 10663f9b4e9aSJilles Tjoelker pungetc(); 10673f9b4e9aSJilles Tjoelker } 10683f9b4e9aSJilles Tjoelker } else if (c == '&') 10693f9b4e9aSJilles Tjoelker np->type = NFROMFD; 10703f9b4e9aSJilles Tjoelker else if (c == '>') 10713f9b4e9aSJilles Tjoelker np->type = NFROMTO; 10723f9b4e9aSJilles Tjoelker else { 10733f9b4e9aSJilles Tjoelker np->type = NFROM; 10743f9b4e9aSJilles Tjoelker pungetc(); 10753f9b4e9aSJilles Tjoelker } 10763f9b4e9aSJilles Tjoelker } 10773f9b4e9aSJilles Tjoelker if (fd != '\0') 10783f9b4e9aSJilles Tjoelker np->nfile.fd = digit_val(fd); 10793f9b4e9aSJilles Tjoelker redirnode = np; 10803f9b4e9aSJilles Tjoelker } 10813f9b4e9aSJilles Tjoelker 10823f9b4e9aSJilles Tjoelker /* 1083cab84206SJilles Tjoelker * Called to parse command substitutions. 1084cab84206SJilles Tjoelker */ 1085cab84206SJilles Tjoelker 108688328642SDavid E. O'Brien static char * 1087cab84206SJilles Tjoelker parsebackq(char *out, struct nodelist **pbqlist, 1088cab84206SJilles Tjoelker int oldstyle, int dblquote, int quoted) 1089cab84206SJilles Tjoelker { 1090cab84206SJilles Tjoelker struct nodelist **nlpp; 1091cab84206SJilles Tjoelker union node *n; 1092cab84206SJilles Tjoelker char *volatile str; 1093cab84206SJilles Tjoelker struct jmploc jmploc; 1094cab84206SJilles Tjoelker struct jmploc *const savehandler = handler; 109546c6b52dSJilles Tjoelker size_t savelen; 1096cab84206SJilles Tjoelker int saveprompt; 1097cab84206SJilles Tjoelker const int bq_startlinno = plinno; 1098cab84206SJilles Tjoelker char *volatile ostr = NULL; 1099cab84206SJilles Tjoelker struct parsefile *const savetopfile = getcurrentfile(); 1100ba02a307SJilles Tjoelker struct heredoc *const saveheredoclist = heredoclist; 1101ba02a307SJilles Tjoelker struct heredoc *here; 1102cab84206SJilles Tjoelker 1103cab84206SJilles Tjoelker str = NULL; 1104cab84206SJilles Tjoelker if (setjmp(jmploc.loc)) { 1105cab84206SJilles Tjoelker popfilesupto(savetopfile); 1106cab84206SJilles Tjoelker if (str) 1107cab84206SJilles Tjoelker ckfree(str); 1108cab84206SJilles Tjoelker if (ostr) 1109cab84206SJilles Tjoelker ckfree(ostr); 1110ba02a307SJilles Tjoelker heredoclist = saveheredoclist; 1111cab84206SJilles Tjoelker handler = savehandler; 1112cab84206SJilles Tjoelker if (exception == EXERROR) { 1113cab84206SJilles Tjoelker startlinno = bq_startlinno; 1114cab84206SJilles Tjoelker synerror("Error in command substitution"); 1115cab84206SJilles Tjoelker } 1116cab84206SJilles Tjoelker longjmp(handler->loc, 1); 1117cab84206SJilles Tjoelker } 1118cab84206SJilles Tjoelker INTOFF; 1119cab84206SJilles Tjoelker savelen = out - stackblock(); 1120cab84206SJilles Tjoelker if (savelen > 0) { 1121cab84206SJilles Tjoelker str = ckmalloc(savelen); 1122cab84206SJilles Tjoelker memcpy(str, stackblock(), savelen); 1123cab84206SJilles Tjoelker } 1124cab84206SJilles Tjoelker handler = &jmploc; 1125ba02a307SJilles Tjoelker heredoclist = NULL; 1126cab84206SJilles Tjoelker INTON; 1127cab84206SJilles Tjoelker if (oldstyle) { 1128cab84206SJilles Tjoelker /* We must read until the closing backquote, giving special 1129cab84206SJilles Tjoelker treatment to some slashes, and then push the string and 1130cab84206SJilles Tjoelker reread it as input, interpreting it normally. */ 1131cab84206SJilles Tjoelker char *oout; 1132cab84206SJilles Tjoelker int c; 1133cab84206SJilles Tjoelker int olen; 1134cab84206SJilles Tjoelker 1135cab84206SJilles Tjoelker 1136cab84206SJilles Tjoelker STARTSTACKSTR(oout); 1137cab84206SJilles Tjoelker for (;;) { 1138cab84206SJilles Tjoelker if (needprompt) { 1139cab84206SJilles Tjoelker setprompt(2); 1140cab84206SJilles Tjoelker needprompt = 0; 1141cab84206SJilles Tjoelker } 11429d37e157SJilles Tjoelker CHECKSTRSPACE(2, oout); 11430b4b9c81SJilles Tjoelker c = pgetc_linecont(); 1144622fdf32SJilles Tjoelker if (c == '`') 1145622fdf32SJilles Tjoelker break; 1146622fdf32SJilles Tjoelker switch (c) { 1147cab84206SJilles Tjoelker case '\\': 11480b4b9c81SJilles Tjoelker c = pgetc(); 1149cab84206SJilles Tjoelker if (c != '\\' && c != '`' && c != '$' 1150cab84206SJilles Tjoelker && (!dblquote || c != '"')) 11519d37e157SJilles Tjoelker USTPUTC('\\', oout); 1152cab84206SJilles Tjoelker break; 1153cab84206SJilles Tjoelker 1154cab84206SJilles Tjoelker case '\n': 1155cab84206SJilles Tjoelker plinno++; 1156cab84206SJilles Tjoelker needprompt = doprompt; 1157cab84206SJilles Tjoelker break; 1158cab84206SJilles Tjoelker 1159cab84206SJilles Tjoelker case PEOF: 1160cab84206SJilles Tjoelker startlinno = plinno; 1161cab84206SJilles Tjoelker synerror("EOF in backquote substitution"); 1162cab84206SJilles Tjoelker break; 1163cab84206SJilles Tjoelker 1164cab84206SJilles Tjoelker default: 1165cab84206SJilles Tjoelker break; 1166cab84206SJilles Tjoelker } 11679d37e157SJilles Tjoelker USTPUTC(c, oout); 1168cab84206SJilles Tjoelker } 11699d37e157SJilles Tjoelker USTPUTC('\0', oout); 1170cab84206SJilles Tjoelker olen = oout - stackblock(); 1171cab84206SJilles Tjoelker INTOFF; 1172cab84206SJilles Tjoelker ostr = ckmalloc(olen); 1173cab84206SJilles Tjoelker memcpy(ostr, stackblock(), olen); 1174cab84206SJilles Tjoelker setinputstring(ostr, 1); 1175cab84206SJilles Tjoelker INTON; 1176cab84206SJilles Tjoelker } 1177cab84206SJilles Tjoelker nlpp = pbqlist; 1178cab84206SJilles Tjoelker while (*nlpp) 1179cab84206SJilles Tjoelker nlpp = &(*nlpp)->next; 1180cab84206SJilles Tjoelker *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 1181cab84206SJilles Tjoelker (*nlpp)->next = NULL; 1182cab84206SJilles Tjoelker 1183cab84206SJilles Tjoelker if (oldstyle) { 1184cab84206SJilles Tjoelker saveprompt = doprompt; 1185cab84206SJilles Tjoelker doprompt = 0; 1186cab84206SJilles Tjoelker } 1187cab84206SJilles Tjoelker 118832187151SJilles Tjoelker n = list(0); 1189cab84206SJilles Tjoelker 119032187151SJilles Tjoelker if (oldstyle) { 119132187151SJilles Tjoelker if (peektoken() != TEOF) 119232187151SJilles Tjoelker synexpect(-1); 1193cab84206SJilles Tjoelker doprompt = saveprompt; 119432187151SJilles Tjoelker } else 11956ab99f87SJilles Tjoelker consumetoken(TRP); 1196cab84206SJilles Tjoelker 1197cab84206SJilles Tjoelker (*nlpp)->n = n; 1198cab84206SJilles Tjoelker if (oldstyle) { 1199cab84206SJilles Tjoelker /* 1200cab84206SJilles Tjoelker * Start reading from old file again, ignoring any pushed back 1201cab84206SJilles Tjoelker * tokens left from the backquote parsing 1202cab84206SJilles Tjoelker */ 1203cab84206SJilles Tjoelker popfile(); 1204cab84206SJilles Tjoelker tokpushback = 0; 1205cab84206SJilles Tjoelker } 1206cab84206SJilles Tjoelker STARTSTACKSTR(out); 1207d8f32e72SJilles Tjoelker CHECKSTRSPACE(savelen + 1, out); 1208ba02a307SJilles Tjoelker INTOFF; 1209cab84206SJilles Tjoelker if (str) { 1210cab84206SJilles Tjoelker memcpy(out, str, savelen); 1211cab84206SJilles Tjoelker STADJUST(savelen, out); 1212cab84206SJilles Tjoelker ckfree(str); 1213cab84206SJilles Tjoelker str = NULL; 1214cab84206SJilles Tjoelker } 1215cab84206SJilles Tjoelker if (ostr) { 1216cab84206SJilles Tjoelker ckfree(ostr); 1217cab84206SJilles Tjoelker ostr = NULL; 1218ba02a307SJilles Tjoelker } 1219ba02a307SJilles Tjoelker here = saveheredoclist; 1220ba02a307SJilles Tjoelker if (here != NULL) { 1221ba02a307SJilles Tjoelker while (here->next != NULL) 1222ba02a307SJilles Tjoelker here = here->next; 1223ba02a307SJilles Tjoelker here->next = heredoclist; 1224ba02a307SJilles Tjoelker heredoclist = saveheredoclist; 1225cab84206SJilles Tjoelker } 1226cab84206SJilles Tjoelker handler = savehandler; 1227ba02a307SJilles Tjoelker INTON; 1228cab84206SJilles Tjoelker if (quoted) 1229cab84206SJilles Tjoelker USTPUTC(CTLBACKQ | CTLQUOTE, out); 1230cab84206SJilles Tjoelker else 1231cab84206SJilles Tjoelker USTPUTC(CTLBACKQ, out); 1232cab84206SJilles Tjoelker return out; 1233cab84206SJilles Tjoelker } 1234cab84206SJilles Tjoelker 12354b88c807SRodney W. Grimes 12364b88c807SRodney W. Grimes /* 1237a62ab027SJilles Tjoelker * Called to parse a backslash escape sequence inside $'...'. 1238a62ab027SJilles Tjoelker * The backslash has already been read. 1239a62ab027SJilles Tjoelker */ 1240a62ab027SJilles Tjoelker static char * 1241a62ab027SJilles Tjoelker readcstyleesc(char *out) 1242a62ab027SJilles Tjoelker { 12435e03b81fSJilles Tjoelker int c, vc, i, n; 12445e03b81fSJilles Tjoelker unsigned int v; 1245a62ab027SJilles Tjoelker 1246a62ab027SJilles Tjoelker c = pgetc(); 1247a62ab027SJilles Tjoelker switch (c) { 1248a62ab027SJilles Tjoelker case '\0': 1249a62ab027SJilles Tjoelker synerror("Unterminated quoted string"); 1250a62ab027SJilles Tjoelker case '\n': 1251a62ab027SJilles Tjoelker plinno++; 1252a62ab027SJilles Tjoelker if (doprompt) 1253a62ab027SJilles Tjoelker setprompt(2); 1254a62ab027SJilles Tjoelker else 1255a62ab027SJilles Tjoelker setprompt(0); 1256a62ab027SJilles Tjoelker return out; 1257a62ab027SJilles Tjoelker case '\\': 1258a62ab027SJilles Tjoelker case '\'': 1259a62ab027SJilles Tjoelker case '"': 1260a62ab027SJilles Tjoelker v = c; 1261a62ab027SJilles Tjoelker break; 1262a62ab027SJilles Tjoelker case 'a': v = '\a'; break; 1263a62ab027SJilles Tjoelker case 'b': v = '\b'; break; 1264a62ab027SJilles Tjoelker case 'e': v = '\033'; break; 1265a62ab027SJilles Tjoelker case 'f': v = '\f'; break; 1266a62ab027SJilles Tjoelker case 'n': v = '\n'; break; 1267a62ab027SJilles Tjoelker case 'r': v = '\r'; break; 1268a62ab027SJilles Tjoelker case 't': v = '\t'; break; 1269a62ab027SJilles Tjoelker case 'v': v = '\v'; break; 1270a62ab027SJilles Tjoelker case 'x': 1271a62ab027SJilles Tjoelker v = 0; 1272a62ab027SJilles Tjoelker for (;;) { 1273a62ab027SJilles Tjoelker c = pgetc(); 1274a62ab027SJilles Tjoelker if (c >= '0' && c <= '9') 1275a62ab027SJilles Tjoelker v = (v << 4) + c - '0'; 1276a62ab027SJilles Tjoelker else if (c >= 'A' && c <= 'F') 1277a62ab027SJilles Tjoelker v = (v << 4) + c - 'A' + 10; 1278a62ab027SJilles Tjoelker else if (c >= 'a' && c <= 'f') 1279a62ab027SJilles Tjoelker v = (v << 4) + c - 'a' + 10; 1280a62ab027SJilles Tjoelker else 1281a62ab027SJilles Tjoelker break; 1282a62ab027SJilles Tjoelker } 1283a62ab027SJilles Tjoelker pungetc(); 1284a62ab027SJilles Tjoelker break; 1285a62ab027SJilles Tjoelker case '0': case '1': case '2': case '3': 1286a62ab027SJilles Tjoelker case '4': case '5': case '6': case '7': 1287a62ab027SJilles Tjoelker v = c - '0'; 1288a62ab027SJilles Tjoelker c = pgetc(); 1289a62ab027SJilles Tjoelker if (c >= '0' && c <= '7') { 1290a62ab027SJilles Tjoelker v <<= 3; 1291a62ab027SJilles Tjoelker v += c - '0'; 1292a62ab027SJilles Tjoelker c = pgetc(); 1293a62ab027SJilles Tjoelker if (c >= '0' && c <= '7') { 1294a62ab027SJilles Tjoelker v <<= 3; 1295a62ab027SJilles Tjoelker v += c - '0'; 1296a62ab027SJilles Tjoelker } else 1297a62ab027SJilles Tjoelker pungetc(); 1298a62ab027SJilles Tjoelker } else 1299a62ab027SJilles Tjoelker pungetc(); 1300a62ab027SJilles Tjoelker break; 1301a62ab027SJilles Tjoelker case 'c': 1302a62ab027SJilles Tjoelker c = pgetc(); 1303a62ab027SJilles Tjoelker if (c < 0x3f || c > 0x7a || c == 0x60) 1304a62ab027SJilles Tjoelker synerror("Bad escape sequence"); 1305a62ab027SJilles Tjoelker if (c == '\\' && pgetc() != '\\') 1306a62ab027SJilles Tjoelker synerror("Bad escape sequence"); 1307a62ab027SJilles Tjoelker if (c == '?') 1308a62ab027SJilles Tjoelker v = 127; 1309a62ab027SJilles Tjoelker else 1310a62ab027SJilles Tjoelker v = c & 0x1f; 1311a62ab027SJilles Tjoelker break; 1312a62ab027SJilles Tjoelker case 'u': 1313a62ab027SJilles Tjoelker case 'U': 1314a62ab027SJilles Tjoelker n = c == 'U' ? 8 : 4; 1315a62ab027SJilles Tjoelker v = 0; 1316a62ab027SJilles Tjoelker for (i = 0; i < n; i++) { 1317a62ab027SJilles Tjoelker c = pgetc(); 1318a62ab027SJilles Tjoelker if (c >= '0' && c <= '9') 1319a62ab027SJilles Tjoelker v = (v << 4) + c - '0'; 1320a62ab027SJilles Tjoelker else if (c >= 'A' && c <= 'F') 1321a62ab027SJilles Tjoelker v = (v << 4) + c - 'A' + 10; 1322a62ab027SJilles Tjoelker else if (c >= 'a' && c <= 'f') 1323a62ab027SJilles Tjoelker v = (v << 4) + c - 'a' + 10; 1324a62ab027SJilles Tjoelker else 1325a62ab027SJilles Tjoelker synerror("Bad escape sequence"); 1326a62ab027SJilles Tjoelker } 1327a62ab027SJilles Tjoelker if (v == 0 || (v >= 0xd800 && v <= 0xdfff)) 1328a62ab027SJilles Tjoelker synerror("Bad escape sequence"); 1329a62ab027SJilles Tjoelker /* We really need iconv here. */ 133007eb7033SJilles Tjoelker if (initial_localeisutf8 && v > 127) { 133107eb7033SJilles Tjoelker CHECKSTRSPACE(4, out); 133207eb7033SJilles Tjoelker /* 133307eb7033SJilles Tjoelker * We cannot use wctomb() as the locale may have 133407eb7033SJilles Tjoelker * changed. 133507eb7033SJilles Tjoelker */ 133607eb7033SJilles Tjoelker if (v <= 0x7ff) { 133707eb7033SJilles Tjoelker USTPUTC(0xc0 | v >> 6, out); 133807eb7033SJilles Tjoelker USTPUTC(0x80 | (v & 0x3f), out); 133907eb7033SJilles Tjoelker return out; 134007eb7033SJilles Tjoelker } else if (v <= 0xffff) { 134107eb7033SJilles Tjoelker USTPUTC(0xe0 | v >> 12, out); 134207eb7033SJilles Tjoelker USTPUTC(0x80 | ((v >> 6) & 0x3f), out); 134307eb7033SJilles Tjoelker USTPUTC(0x80 | (v & 0x3f), out); 134407eb7033SJilles Tjoelker return out; 134507eb7033SJilles Tjoelker } else if (v <= 0x10ffff) { 134607eb7033SJilles Tjoelker USTPUTC(0xf0 | v >> 18, out); 134707eb7033SJilles Tjoelker USTPUTC(0x80 | ((v >> 12) & 0x3f), out); 134807eb7033SJilles Tjoelker USTPUTC(0x80 | ((v >> 6) & 0x3f), out); 134907eb7033SJilles Tjoelker USTPUTC(0x80 | (v & 0x3f), out); 135007eb7033SJilles Tjoelker return out; 135107eb7033SJilles Tjoelker } 135207eb7033SJilles Tjoelker } 1353a62ab027SJilles Tjoelker if (v > 127) 1354a62ab027SJilles Tjoelker v = '?'; 1355a62ab027SJilles Tjoelker break; 1356a62ab027SJilles Tjoelker default: 1357a62ab027SJilles Tjoelker synerror("Bad escape sequence"); 1358a62ab027SJilles Tjoelker } 13595e03b81fSJilles Tjoelker vc = (char)v; 1360a62ab027SJilles Tjoelker /* 1361a62ab027SJilles Tjoelker * We can't handle NUL bytes. 1362a62ab027SJilles Tjoelker * POSIX says we should skip till the closing quote. 1363a62ab027SJilles Tjoelker */ 13645e03b81fSJilles Tjoelker if (vc == '\0') { 1365a62ab027SJilles Tjoelker while ((c = pgetc()) != '\'') { 1366a62ab027SJilles Tjoelker if (c == '\\') 1367a62ab027SJilles Tjoelker c = pgetc(); 1368a62ab027SJilles Tjoelker if (c == PEOF) 1369a62ab027SJilles Tjoelker synerror("Unterminated quoted string"); 1370068dfa2dSJilles Tjoelker if (c == '\n') { 1371068dfa2dSJilles Tjoelker plinno++; 1372068dfa2dSJilles Tjoelker if (doprompt) 1373068dfa2dSJilles Tjoelker setprompt(2); 1374068dfa2dSJilles Tjoelker else 1375068dfa2dSJilles Tjoelker setprompt(0); 1376068dfa2dSJilles Tjoelker } 1377a62ab027SJilles Tjoelker } 1378a62ab027SJilles Tjoelker pungetc(); 1379a62ab027SJilles Tjoelker return out; 1380a62ab027SJilles Tjoelker } 13815e03b81fSJilles Tjoelker if (SQSYNTAX[vc] == CCTL) 1382a62ab027SJilles Tjoelker USTPUTC(CTLESC, out); 13835e03b81fSJilles Tjoelker USTPUTC(vc, out); 1384a62ab027SJilles Tjoelker return out; 1385a62ab027SJilles Tjoelker } 1386a62ab027SJilles Tjoelker 1387a62ab027SJilles Tjoelker 1388a62ab027SJilles Tjoelker /* 13894b88c807SRodney W. Grimes * If eofmark is NULL, read a word or a redirection symbol. If eofmark 13904b88c807SRodney W. Grimes * is not NULL, read a here document. In the latter case, eofmark is the 13914b88c807SRodney W. Grimes * word which marks the end of the document and striptabs is true if 13924b88c807SRodney W. Grimes * leading tabs should be stripped from the document. The argument firstc 13934b88c807SRodney W. Grimes * is the first character of the input token or document. 13944b88c807SRodney W. Grimes * 13954b88c807SRodney W. Grimes * Because C does not have internal subroutines, I have simulated them 13964b88c807SRodney W. Grimes * using goto's to implement the subroutine linkage. The following macros 13974b88c807SRodney W. Grimes * will run code that appears at the end of readtoken1. 13984b88c807SRodney W. Grimes */ 13994b88c807SRodney W. Grimes 14004b88c807SRodney W. Grimes #define PARSESUB() {goto parsesub; parsesub_return:;} 14014b88c807SRodney W. Grimes #define PARSEARITH() {goto parsearith; parsearith_return:;} 14024b88c807SRodney W. Grimes 140388328642SDavid E. O'Brien static int 140446c6b52dSJilles Tjoelker readtoken1(int firstc, char const *initialsyntax, const char *eofmark, 140546c6b52dSJilles Tjoelker int striptabs) 14064b88c807SRodney W. Grimes { 1407aa9caaf6SPeter Wemm int c = firstc; 1408aa9caaf6SPeter Wemm char *out; 14094b88c807SRodney W. Grimes int len; 14104b88c807SRodney W. Grimes struct nodelist *bqlist; 14114b88c807SRodney W. Grimes int quotef; 14128cf06f5eSJilles Tjoelker int newvarnest; 14138cf06f5eSJilles Tjoelker int level; 14142dde9ce3SMartin Cracauer int synentry; 141588328642SDavid E. O'Brien struct tokenstate state_static[MAXNEST_static]; 141688328642SDavid E. O'Brien int maxnest = MAXNEST_static; 14178cf06f5eSJilles Tjoelker struct tokenstate *state = state_static; 1418a62ab027SJilles Tjoelker int sqiscstyle = 0; 14194b88c807SRodney W. Grimes 14204b88c807SRodney W. Grimes startlinno = plinno; 14214b88c807SRodney W. Grimes quotef = 0; 14224b88c807SRodney W. Grimes bqlist = NULL; 14238cf06f5eSJilles Tjoelker newvarnest = 0; 14248cf06f5eSJilles Tjoelker level = 0; 14258cf06f5eSJilles Tjoelker state[level].syntax = initialsyntax; 14268cf06f5eSJilles Tjoelker state[level].parenlevel = 0; 14278cf06f5eSJilles Tjoelker state[level].category = TSTATE_TOP; 14284b88c807SRodney W. Grimes 14294b88c807SRodney W. Grimes STARTSTACKSTR(out); 14304b88c807SRodney W. Grimes loop: { /* for each line, until end of word */ 143192fe71faSJilles Tjoelker if (eofmark && eofmark != NOEOFMARK) 1432671a890eSJilles Tjoelker /* set c to PEOF if at end of here document */ 143372238faaSJilles Tjoelker c = checkend(c, eofmark, striptabs); 14344b88c807SRodney W. Grimes for (;;) { /* until end of line or end of word */ 1435048f2667SJilles Tjoelker CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 14362dde9ce3SMartin Cracauer 14378cf06f5eSJilles Tjoelker synentry = state[level].syntax[c]; 14382dde9ce3SMartin Cracauer 14392dde9ce3SMartin Cracauer switch(synentry) { 14404b88c807SRodney W. Grimes case CNL: /* '\n' */ 1441dc0dbd74SJilles Tjoelker if (level == 0) 14424b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 1443dc0dbd74SJilles Tjoelker /* FALLTHROUGH */ 1444dc0dbd74SJilles Tjoelker case CQNL: 14454b88c807SRodney W. Grimes USTPUTC(c, out); 14464b88c807SRodney W. Grimes plinno++; 14474b88c807SRodney W. Grimes if (doprompt) 14484b88c807SRodney W. Grimes setprompt(2); 14494b88c807SRodney W. Grimes else 14504b88c807SRodney W. Grimes setprompt(0); 14514b88c807SRodney W. Grimes c = pgetc(); 14524b88c807SRodney W. Grimes goto loop; /* continue outer loop */ 1453a62ab027SJilles Tjoelker case CSBACK: 1454a62ab027SJilles Tjoelker if (sqiscstyle) { 1455a62ab027SJilles Tjoelker out = readcstyleesc(out); 1456a62ab027SJilles Tjoelker break; 1457a62ab027SJilles Tjoelker } 1458a62ab027SJilles Tjoelker /* FALLTHROUGH */ 14594b88c807SRodney W. Grimes case CWORD: 14604b88c807SRodney W. Grimes USTPUTC(c, out); 14614b88c807SRodney W. Grimes break; 14624b88c807SRodney W. Grimes case CCTL: 14638cf06f5eSJilles Tjoelker if (eofmark == NULL || initialsyntax != SQSYNTAX) 14644b88c807SRodney W. Grimes USTPUTC(CTLESC, out); 14654b88c807SRodney W. Grimes USTPUTC(c, out); 14664b88c807SRodney W. Grimes break; 14674b88c807SRodney W. Grimes case CBACK: /* backslash */ 14684b88c807SRodney W. Grimes c = pgetc(); 14694b88c807SRodney W. Grimes if (c == PEOF) { 14704b88c807SRodney W. Grimes USTPUTC('\\', out); 14714b88c807SRodney W. Grimes pungetc(); 14724b88c807SRodney W. Grimes } else if (c == '\n') { 147362f9f953SYaroslav Tykhiy plinno++; 14744b88c807SRodney W. Grimes if (doprompt) 14754b88c807SRodney W. Grimes setprompt(2); 14764b88c807SRodney W. Grimes else 14774b88c807SRodney W. Grimes setprompt(0); 14784b88c807SRodney W. Grimes } else { 14798cf06f5eSJilles Tjoelker if (state[level].syntax == DQSYNTAX && 14808cf06f5eSJilles Tjoelker c != '\\' && c != '`' && c != '$' && 14818cf06f5eSJilles Tjoelker (c != '"' || (eofmark != NULL && 14828cf06f5eSJilles Tjoelker newvarnest == 0)) && 14838cf06f5eSJilles Tjoelker (c != '}' || state[level].category != TSTATE_VAR_OLD)) 14844b88c807SRodney W. Grimes USTPUTC('\\', out); 1485048f2667SJilles Tjoelker if ((eofmark == NULL || 1486048f2667SJilles Tjoelker newvarnest > 0) && 1487048f2667SJilles Tjoelker state[level].syntax == BASESYNTAX) 1488048f2667SJilles Tjoelker USTPUTC(CTLQUOTEMARK, out); 14890c4eeddaSTor Egge if (SQSYNTAX[c] == CCTL) 14904b88c807SRodney W. Grimes USTPUTC(CTLESC, out); 14914b88c807SRodney W. Grimes USTPUTC(c, out); 1492048f2667SJilles Tjoelker if ((eofmark == NULL || 1493048f2667SJilles Tjoelker newvarnest > 0) && 1494048f2667SJilles Tjoelker state[level].syntax == BASESYNTAX && 1495048f2667SJilles Tjoelker state[level].category == TSTATE_VAR_OLD) 1496048f2667SJilles Tjoelker USTPUTC(CTLQUOTEEND, out); 14974b88c807SRodney W. Grimes quotef++; 14984b88c807SRodney W. Grimes } 14994b88c807SRodney W. Grimes break; 15004b88c807SRodney W. Grimes case CSQUOTE: 15016f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 15028cf06f5eSJilles Tjoelker state[level].syntax = SQSYNTAX; 1503a62ab027SJilles Tjoelker sqiscstyle = 0; 15044b88c807SRodney W. Grimes break; 15054b88c807SRodney W. Grimes case CDQUOTE: 15066f47734fSTor Egge USTPUTC(CTLQUOTEMARK, out); 15078cf06f5eSJilles Tjoelker state[level].syntax = DQSYNTAX; 15084b88c807SRodney W. Grimes break; 15094b88c807SRodney W. Grimes case CENDQUOTE: 15108cf06f5eSJilles Tjoelker if (eofmark != NULL && newvarnest == 0) 15114b88c807SRodney W. Grimes USTPUTC(c, out); 15128cf06f5eSJilles Tjoelker else { 1513048f2667SJilles Tjoelker if (state[level].category == TSTATE_VAR_OLD) 1514048f2667SJilles Tjoelker USTPUTC(CTLQUOTEEND, out); 15158cf06f5eSJilles Tjoelker state[level].syntax = BASESYNTAX; 15165557a02aSTor Egge quotef++; 15174b88c807SRodney W. Grimes } 15184b88c807SRodney W. Grimes break; 15194b88c807SRodney W. Grimes case CVAR: /* '$' */ 15204b88c807SRodney W. Grimes PARSESUB(); /* parse substitution */ 15214b88c807SRodney W. Grimes break; 15224b88c807SRodney W. Grimes case CENDVAR: /* '}' */ 15238cf06f5eSJilles Tjoelker if (level > 0 && 15246c380712SJilles Tjoelker ((state[level].category == TSTATE_VAR_OLD && 15256c380712SJilles Tjoelker state[level].syntax == 15266c380712SJilles Tjoelker state[level - 1].syntax) || 15279cec947fSJilles Tjoelker (state[level].category == TSTATE_VAR_NEW && 15289cec947fSJilles Tjoelker state[level].syntax == BASESYNTAX))) { 15296c380712SJilles Tjoelker if (state[level].category == TSTATE_VAR_NEW) 15308cf06f5eSJilles Tjoelker newvarnest--; 15318cf06f5eSJilles Tjoelker level--; 15324b88c807SRodney W. Grimes USTPUTC(CTLENDVAR, out); 15334b88c807SRodney W. Grimes } else { 15344b88c807SRodney W. Grimes USTPUTC(c, out); 15354b88c807SRodney W. Grimes } 15364b88c807SRodney W. Grimes break; 15374b88c807SRodney W. Grimes case CLP: /* '(' in arithmetic */ 15388cf06f5eSJilles Tjoelker state[level].parenlevel++; 15394b88c807SRodney W. Grimes USTPUTC(c, out); 15404b88c807SRodney W. Grimes break; 15414b88c807SRodney W. Grimes case CRP: /* ')' in arithmetic */ 15428cf06f5eSJilles Tjoelker if (state[level].parenlevel > 0) { 15434b88c807SRodney W. Grimes USTPUTC(c, out); 15448cf06f5eSJilles Tjoelker --state[level].parenlevel; 15454b88c807SRodney W. Grimes } else { 15460b4b9c81SJilles Tjoelker if (pgetc_linecont() == ')') { 15478cf06f5eSJilles Tjoelker if (level > 0 && 15488cf06f5eSJilles Tjoelker state[level].category == TSTATE_ARITH) { 15498cf06f5eSJilles Tjoelker level--; 15504b88c807SRodney W. Grimes USTPUTC(CTLENDARI, out); 15514b88c807SRodney W. Grimes } else 15524b88c807SRodney W. Grimes USTPUTC(')', out); 15534b88c807SRodney W. Grimes } else { 15544b88c807SRodney W. Grimes /* 15554b88c807SRodney W. Grimes * unbalanced parens 15564b88c807SRodney W. Grimes * (don't 2nd guess - no error) 15574b88c807SRodney W. Grimes */ 15584b88c807SRodney W. Grimes pungetc(); 15594b88c807SRodney W. Grimes USTPUTC(')', out); 15604b88c807SRodney W. Grimes } 15614b88c807SRodney W. Grimes } 15624b88c807SRodney W. Grimes break; 15634b88c807SRodney W. Grimes case CBQUOTE: /* '`' */ 15648cf06f5eSJilles Tjoelker out = parsebackq(out, &bqlist, 1, 15658cf06f5eSJilles Tjoelker state[level].syntax == DQSYNTAX && 15668cf06f5eSJilles Tjoelker (eofmark == NULL || newvarnest > 0), 15678cf06f5eSJilles Tjoelker state[level].syntax == DQSYNTAX || state[level].syntax == ARISYNTAX); 15684b88c807SRodney W. Grimes break; 15694b88c807SRodney W. Grimes case CEOF: 15704b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 1571d94c8673SJilles Tjoelker case CIGN: 1572d94c8673SJilles Tjoelker break; 15734b88c807SRodney W. Grimes default: 15748cf06f5eSJilles Tjoelker if (level == 0) 15754b88c807SRodney W. Grimes goto endword; /* exit outer loop */ 15764b88c807SRodney W. Grimes USTPUTC(c, out); 15774b88c807SRodney W. Grimes } 15784b88c807SRodney W. Grimes c = pgetc_macro(); 15794b88c807SRodney W. Grimes } 15804b88c807SRodney W. Grimes } 15814b88c807SRodney W. Grimes endword: 15828cf06f5eSJilles Tjoelker if (state[level].syntax == ARISYNTAX) 15834b88c807SRodney W. Grimes synerror("Missing '))'"); 15848cf06f5eSJilles Tjoelker if (state[level].syntax != BASESYNTAX && eofmark == NULL) 15854b88c807SRodney W. Grimes synerror("Unterminated quoted string"); 15868cf06f5eSJilles Tjoelker if (state[level].category == TSTATE_VAR_OLD || 15878cf06f5eSJilles Tjoelker state[level].category == TSTATE_VAR_NEW) { 15884b88c807SRodney W. Grimes startlinno = plinno; 15894b88c807SRodney W. Grimes synerror("Missing '}'"); 15904b88c807SRodney W. Grimes } 15918cf06f5eSJilles Tjoelker if (state != state_static) 15928cf06f5eSJilles Tjoelker parser_temp_free_upto(state); 15934b88c807SRodney W. Grimes USTPUTC('\0', out); 15944b88c807SRodney W. Grimes len = out - stackblock(); 15954b88c807SRodney W. Grimes out = stackblock(); 15964b88c807SRodney W. Grimes if (eofmark == NULL) { 15974b88c807SRodney W. Grimes if ((c == '>' || c == '<') 15984b88c807SRodney W. Grimes && quotef == 0 15994b88c807SRodney W. Grimes && len <= 2 16004b88c807SRodney W. Grimes && (*out == '\0' || is_digit(*out))) { 16013f9b4e9aSJilles Tjoelker parseredir(out, c); 16024b88c807SRodney W. Grimes return lasttoken = TREDIR; 16034b88c807SRodney W. Grimes } else { 16044b88c807SRodney W. Grimes pungetc(); 16054b88c807SRodney W. Grimes } 16064b88c807SRodney W. Grimes } 16074b88c807SRodney W. Grimes quoteflag = quotef; 16084b88c807SRodney W. Grimes backquotelist = bqlist; 16094b88c807SRodney W. Grimes grabstackblock(len); 16104b88c807SRodney W. Grimes wordtext = out; 16114b88c807SRodney W. Grimes return lasttoken = TWORD; 16124b88c807SRodney W. Grimes /* end of readtoken routine */ 16134b88c807SRodney W. Grimes 16144b88c807SRodney W. Grimes 16154b88c807SRodney W. Grimes /* 16164b88c807SRodney W. Grimes * Parse a substitution. At this point, we have read the dollar sign 16174b88c807SRodney W. Grimes * and nothing else. 16184b88c807SRodney W. Grimes */ 16194b88c807SRodney W. Grimes 16204b88c807SRodney W. Grimes parsesub: { 16214b88c807SRodney W. Grimes int subtype; 16224b88c807SRodney W. Grimes int typeloc; 16234b88c807SRodney W. Grimes int flags; 16244b88c807SRodney W. Grimes char *p; 16254b88c807SRodney W. Grimes static const char types[] = "}-+?="; 1626b71085aaSStefan Farfeleder int linno; 16274f30f299SStefan Farfeleder int length; 162835c641edSJilles Tjoelker int c1; 16294b88c807SRodney W. Grimes 16300b4b9c81SJilles Tjoelker c = pgetc_linecont(); 1631a62ab027SJilles Tjoelker if (c == '(') { /* $(command) or $((arith)) */ 16320b4b9c81SJilles Tjoelker if (pgetc_linecont() == '(') { 16334b88c807SRodney W. Grimes PARSEARITH(); 16344b88c807SRodney W. Grimes } else { 16354b88c807SRodney W. Grimes pungetc(); 16368cf06f5eSJilles Tjoelker out = parsebackq(out, &bqlist, 0, 16378cf06f5eSJilles Tjoelker state[level].syntax == DQSYNTAX && 16388cf06f5eSJilles Tjoelker (eofmark == NULL || newvarnest > 0), 16398cf06f5eSJilles Tjoelker state[level].syntax == DQSYNTAX || 16408cf06f5eSJilles Tjoelker state[level].syntax == ARISYNTAX); 16414b88c807SRodney W. Grimes } 1642a62ab027SJilles Tjoelker } else if (c == '{' || is_name(c) || is_special(c)) { 16434b88c807SRodney W. Grimes USTPUTC(CTLVAR, out); 16444b88c807SRodney W. Grimes typeloc = out - stackblock(); 16454b88c807SRodney W. Grimes USTPUTC(VSNORMAL, out); 16464b88c807SRodney W. Grimes subtype = VSNORMAL; 1647b71085aaSStefan Farfeleder flags = 0; 16484b88c807SRodney W. Grimes if (c == '{') { 16490b4b9c81SJilles Tjoelker c = pgetc_linecont(); 16504b88c807SRodney W. Grimes subtype = 0; 16514b88c807SRodney W. Grimes } 165235c641edSJilles Tjoelker varname: 1653716b138bSStefan Farfeleder if (!is_eof(c) && is_name(c)) { 16544f30f299SStefan Farfeleder length = 0; 16554b88c807SRodney W. Grimes do { 16564b88c807SRodney W. Grimes STPUTC(c, out); 16570b4b9c81SJilles Tjoelker c = pgetc_linecont(); 16584f30f299SStefan Farfeleder length++; 1659716b138bSStefan Farfeleder } while (!is_eof(c) && is_in_name(c)); 16604f30f299SStefan Farfeleder if (length == 6 && 16614f30f299SStefan Farfeleder strncmp(out - length, "LINENO", length) == 0) { 1662b71085aaSStefan Farfeleder /* Replace the variable name with the 1663b71085aaSStefan Farfeleder * current line number. */ 166476963686SJilles Tjoelker STADJUST(-6, out); 166576963686SJilles Tjoelker CHECKSTRSPACE(11, out); 1666b71085aaSStefan Farfeleder linno = plinno; 1667b71085aaSStefan Farfeleder if (funclinno != 0) 1668b71085aaSStefan Farfeleder linno -= funclinno - 1; 166976963686SJilles Tjoelker length = snprintf(out, 11, "%d", linno); 167076963686SJilles Tjoelker if (length > 10) 167176963686SJilles Tjoelker length = 10; 167276963686SJilles Tjoelker out += length; 1673b71085aaSStefan Farfeleder flags |= VSLINENO; 1674b71085aaSStefan Farfeleder } 16755c817731SPeter Wemm } else if (is_digit(c)) { 1676d7250589SJilles Tjoelker if (subtype != VSNORMAL) { 16775c817731SPeter Wemm do { 16785c817731SPeter Wemm STPUTC(c, out); 16790b4b9c81SJilles Tjoelker c = pgetc_linecont(); 16805c817731SPeter Wemm } while (is_digit(c)); 16815c817731SPeter Wemm } else { 16822efd8c0aSJilles Tjoelker USTPUTC(c, out); 16830b4b9c81SJilles Tjoelker c = pgetc_linecont(); 16845c817731SPeter Wemm } 168535c641edSJilles Tjoelker } else if (is_special(c)) { 168635c641edSJilles Tjoelker c1 = c; 16870b4b9c81SJilles Tjoelker c = pgetc_linecont(); 168835c641edSJilles Tjoelker if (subtype == 0 && c1 == '#') { 168935c641edSJilles Tjoelker subtype = VSLENGTH; 169035c641edSJilles Tjoelker if (strchr(types, c) == NULL && c != ':' && 169135c641edSJilles Tjoelker c != '#' && c != '%') 169235c641edSJilles Tjoelker goto varname; 169335c641edSJilles Tjoelker c1 = c; 16940b4b9c81SJilles Tjoelker c = pgetc_linecont(); 169535c641edSJilles Tjoelker if (c1 != '}' && c == '}') { 169635c641edSJilles Tjoelker pungetc(); 169735c641edSJilles Tjoelker c = c1; 169835c641edSJilles Tjoelker goto varname; 169935c641edSJilles Tjoelker } 170035c641edSJilles Tjoelker pungetc(); 170135c641edSJilles Tjoelker c = c1; 170235c641edSJilles Tjoelker c1 = '#'; 170335c641edSJilles Tjoelker subtype = 0; 170435c641edSJilles Tjoelker } 170535c641edSJilles Tjoelker USTPUTC(c1, out); 17064b88c807SRodney W. Grimes } else { 170762addaefSStefan Farfeleder subtype = VSERROR; 170862addaefSStefan Farfeleder if (c == '}') 170962addaefSStefan Farfeleder pungetc(); 1710d323650fSJilles Tjoelker else if (c == '\n' || c == PEOF) 1711d323650fSJilles Tjoelker synerror("Unexpected end of line in substitution"); 1712d0b0ac18SJilles Tjoelker else if (BASESYNTAX[c] != CCTL) 171362addaefSStefan Farfeleder USTPUTC(c, out); 171462addaefSStefan Farfeleder } 17154b88c807SRodney W. Grimes if (subtype == 0) { 1716aa9caaf6SPeter Wemm switch (c) { 1717aa9caaf6SPeter Wemm case ':': 1718b71085aaSStefan Farfeleder flags |= VSNUL; 17190b4b9c81SJilles Tjoelker c = pgetc_linecont(); 1720aa9caaf6SPeter Wemm /*FALLTHROUGH*/ 1721aa9caaf6SPeter Wemm default: 17224b88c807SRodney W. Grimes p = strchr(types, c); 172362addaefSStefan Farfeleder if (p == NULL) { 1724d323650fSJilles Tjoelker if (c == '\n' || c == PEOF) 1725d323650fSJilles Tjoelker synerror("Unexpected end of line in substitution"); 172662addaefSStefan Farfeleder if (flags == VSNUL) 172762addaefSStefan Farfeleder STPUTC(':', out); 1728d0b0ac18SJilles Tjoelker if (BASESYNTAX[c] != CCTL) 172962addaefSStefan Farfeleder STPUTC(c, out); 173062addaefSStefan Farfeleder subtype = VSERROR; 173162addaefSStefan Farfeleder } else 17324b88c807SRodney W. Grimes subtype = p - types + VSNORMAL; 1733aa9caaf6SPeter Wemm break; 1734aa9caaf6SPeter Wemm case '%': 1735aa9caaf6SPeter Wemm case '#': 1736aa9caaf6SPeter Wemm { 1737aa9caaf6SPeter Wemm int cc = c; 1738aa9caaf6SPeter Wemm subtype = c == '#' ? VSTRIMLEFT : 1739aa9caaf6SPeter Wemm VSTRIMRIGHT; 17400b4b9c81SJilles Tjoelker c = pgetc_linecont(); 1741aa9caaf6SPeter Wemm if (c == cc) 1742aa9caaf6SPeter Wemm subtype++; 1743aa9caaf6SPeter Wemm else 1744aa9caaf6SPeter Wemm pungetc(); 1745aa9caaf6SPeter Wemm break; 1746aa9caaf6SPeter Wemm } 1747aa9caaf6SPeter Wemm } 174862addaefSStefan Farfeleder } else if (subtype != VSERROR) { 1749fc0818feSJilles Tjoelker if (subtype == VSLENGTH && c != '}') 1750fc0818feSJilles Tjoelker subtype = VSERROR; 17514b88c807SRodney W. Grimes pungetc(); 17524b88c807SRodney W. Grimes } 175362addaefSStefan Farfeleder STPUTC('=', out); 1754caa7ccdcSJilles Tjoelker if (state[level].syntax == DQSYNTAX || 1755caa7ccdcSJilles Tjoelker state[level].syntax == ARISYNTAX) 17564b88c807SRodney W. Grimes flags |= VSQUOTE; 17574b88c807SRodney W. Grimes *(stackblock() + typeloc) = subtype | flags; 17588cf06f5eSJilles Tjoelker if (subtype != VSNORMAL) { 17598cf06f5eSJilles Tjoelker if (level + 1 >= maxnest) { 17608cf06f5eSJilles Tjoelker maxnest *= 2; 17618cf06f5eSJilles Tjoelker if (state == state_static) { 17628cf06f5eSJilles Tjoelker state = parser_temp_alloc( 17638cf06f5eSJilles Tjoelker maxnest * sizeof(*state)); 17648cf06f5eSJilles Tjoelker memcpy(state, state_static, 176588328642SDavid E. O'Brien MAXNEST_static * sizeof(*state)); 17668cf06f5eSJilles Tjoelker } else 17678cf06f5eSJilles Tjoelker state = parser_temp_realloc(state, 17688cf06f5eSJilles Tjoelker maxnest * sizeof(*state)); 17698cf06f5eSJilles Tjoelker } 17708cf06f5eSJilles Tjoelker level++; 17718cf06f5eSJilles Tjoelker state[level].parenlevel = 0; 17728cf06f5eSJilles Tjoelker if (subtype == VSMINUS || subtype == VSPLUS || 17738cf06f5eSJilles Tjoelker subtype == VSQUESTION || subtype == VSASSIGN) { 17748cf06f5eSJilles Tjoelker /* 17758cf06f5eSJilles Tjoelker * For operators that were in the Bourne shell, 17768cf06f5eSJilles Tjoelker * inherit the double-quote state. 17778cf06f5eSJilles Tjoelker */ 17788cf06f5eSJilles Tjoelker state[level].syntax = state[level - 1].syntax; 17798cf06f5eSJilles Tjoelker state[level].category = TSTATE_VAR_OLD; 17808cf06f5eSJilles Tjoelker } else { 17818cf06f5eSJilles Tjoelker /* 17828cf06f5eSJilles Tjoelker * The other operators take a pattern, 17838cf06f5eSJilles Tjoelker * so go to BASESYNTAX. 17848cf06f5eSJilles Tjoelker * Also, ' and " are now special, even 17858cf06f5eSJilles Tjoelker * in here documents. 17868cf06f5eSJilles Tjoelker */ 17878cf06f5eSJilles Tjoelker state[level].syntax = BASESYNTAX; 17888cf06f5eSJilles Tjoelker state[level].category = TSTATE_VAR_NEW; 17898cf06f5eSJilles Tjoelker newvarnest++; 17908cf06f5eSJilles Tjoelker } 17918cf06f5eSJilles Tjoelker } 1792a62ab027SJilles Tjoelker } else if (c == '\'' && state[level].syntax == BASESYNTAX) { 1793a62ab027SJilles Tjoelker /* $'cstylequotes' */ 1794a62ab027SJilles Tjoelker USTPUTC(CTLQUOTEMARK, out); 1795a62ab027SJilles Tjoelker state[level].syntax = SQSYNTAX; 1796a62ab027SJilles Tjoelker sqiscstyle = 1; 1797a62ab027SJilles Tjoelker } else { 1798a62ab027SJilles Tjoelker USTPUTC('$', out); 1799a62ab027SJilles Tjoelker pungetc(); 18004b88c807SRodney W. Grimes } 18014b88c807SRodney W. Grimes goto parsesub_return; 18024b88c807SRodney W. Grimes } 18034b88c807SRodney W. Grimes 18044b88c807SRodney W. Grimes 18054b88c807SRodney W. Grimes /* 18064b88c807SRodney W. Grimes * Parse an arithmetic expansion (indicate start of one and set state) 18074b88c807SRodney W. Grimes */ 18084b88c807SRodney W. Grimes parsearith: { 18094b88c807SRodney W. Grimes 18108cf06f5eSJilles Tjoelker if (level + 1 >= maxnest) { 18118cf06f5eSJilles Tjoelker maxnest *= 2; 18128cf06f5eSJilles Tjoelker if (state == state_static) { 18138cf06f5eSJilles Tjoelker state = parser_temp_alloc( 18148cf06f5eSJilles Tjoelker maxnest * sizeof(*state)); 18158cf06f5eSJilles Tjoelker memcpy(state, state_static, 181688328642SDavid E. O'Brien MAXNEST_static * sizeof(*state)); 18178cf06f5eSJilles Tjoelker } else 18188cf06f5eSJilles Tjoelker state = parser_temp_realloc(state, 18198cf06f5eSJilles Tjoelker maxnest * sizeof(*state)); 18208cf06f5eSJilles Tjoelker } 18218cf06f5eSJilles Tjoelker level++; 18228cf06f5eSJilles Tjoelker state[level].syntax = ARISYNTAX; 18238cf06f5eSJilles Tjoelker state[level].parenlevel = 0; 18248cf06f5eSJilles Tjoelker state[level].category = TSTATE_ARITH; 18254b88c807SRodney W. Grimes USTPUTC(CTLARI, out); 18268cf06f5eSJilles Tjoelker if (state[level - 1].syntax == DQSYNTAX) 18276f47734fSTor Egge USTPUTC('"',out); 18286f47734fSTor Egge else 18296f47734fSTor Egge USTPUTC(' ',out); 18304b88c807SRodney W. Grimes goto parsearith_return; 18314b88c807SRodney W. Grimes } 18324b88c807SRodney W. Grimes 18334b88c807SRodney W. Grimes } /* end of readtoken */ 18344b88c807SRodney W. Grimes 18354b88c807SRodney W. Grimes 18364b88c807SRodney W. Grimes /* 18374b88c807SRodney W. Grimes * Returns true if the text contains nothing to expand (no dollar signs 18384b88c807SRodney W. Grimes * or backquotes). 18394b88c807SRodney W. Grimes */ 18404b88c807SRodney W. Grimes 184188328642SDavid E. O'Brien static int 18425134c3f7SWarner Losh noexpand(char *text) 18434b88c807SRodney W. Grimes { 18447920a31dSSteve Price char *p; 18457920a31dSSteve Price char c; 18464b88c807SRodney W. Grimes 18474b88c807SRodney W. Grimes p = text; 18484b88c807SRodney W. Grimes while ((c = *p++) != '\0') { 18495557a02aSTor Egge if ( c == CTLQUOTEMARK) 18505557a02aSTor Egge continue; 18514b88c807SRodney W. Grimes if (c == CTLESC) 18524b88c807SRodney W. Grimes p++; 18530c4eeddaSTor Egge else if (BASESYNTAX[(int)c] == CCTL) 18544b88c807SRodney W. Grimes return 0; 18554b88c807SRodney W. Grimes } 18564b88c807SRodney W. Grimes return 1; 18574b88c807SRodney W. Grimes } 18584b88c807SRodney W. Grimes 18594b88c807SRodney W. Grimes 18604b88c807SRodney W. Grimes /* 18614b88c807SRodney W. Grimes * Return true if the argument is a legal variable name (a letter or 18624b88c807SRodney W. Grimes * underscore followed by zero or more letters, underscores, and digits). 18634b88c807SRodney W. Grimes */ 18644b88c807SRodney W. Grimes 18654b88c807SRodney W. Grimes int 18662cac6e36SJilles Tjoelker goodname(const char *name) 18674b88c807SRodney W. Grimes { 18682cac6e36SJilles Tjoelker const char *p; 18694b88c807SRodney W. Grimes 18704b88c807SRodney W. Grimes p = name; 18714b88c807SRodney W. Grimes if (! is_name(*p)) 18724b88c807SRodney W. Grimes return 0; 18734b88c807SRodney W. Grimes while (*++p) { 18744b88c807SRodney W. Grimes if (! is_in_name(*p)) 18754b88c807SRodney W. Grimes return 0; 18764b88c807SRodney W. Grimes } 18774b88c807SRodney W. Grimes return 1; 18784b88c807SRodney W. Grimes } 18794b88c807SRodney W. Grimes 18804b88c807SRodney W. Grimes 188105a447d0SJilles Tjoelker int 188205a447d0SJilles Tjoelker isassignment(const char *p) 188305a447d0SJilles Tjoelker { 188405a447d0SJilles Tjoelker if (!is_name(*p)) 188505a447d0SJilles Tjoelker return 0; 188605a447d0SJilles Tjoelker p++; 188705a447d0SJilles Tjoelker for (;;) { 188805a447d0SJilles Tjoelker if (*p == '=') 188905a447d0SJilles Tjoelker return 1; 189005a447d0SJilles Tjoelker else if (!is_in_name(*p)) 189105a447d0SJilles Tjoelker return 0; 189205a447d0SJilles Tjoelker p++; 189305a447d0SJilles Tjoelker } 189405a447d0SJilles Tjoelker } 189505a447d0SJilles Tjoelker 189605a447d0SJilles Tjoelker 18976ab99f87SJilles Tjoelker static void 18986ab99f87SJilles Tjoelker consumetoken(int token) 18996ab99f87SJilles Tjoelker { 19006ab99f87SJilles Tjoelker if (readtoken() != token) 19016ab99f87SJilles Tjoelker synexpect(token); 19026ab99f87SJilles Tjoelker } 19036ab99f87SJilles Tjoelker 19046ab99f87SJilles Tjoelker 19054b88c807SRodney W. Grimes /* 19064b88c807SRodney W. Grimes * Called when an unexpected token is read during the parse. The argument 19074b88c807SRodney W. Grimes * is the token that is expected, or -1 if more than one type of token can 19084b88c807SRodney W. Grimes * occur at this point. 19094b88c807SRodney W. Grimes */ 19104b88c807SRodney W. Grimes 191188328642SDavid E. O'Brien static void 19125134c3f7SWarner Losh synexpect(int token) 1913aa9caaf6SPeter Wemm { 19144b88c807SRodney W. Grimes char msg[64]; 19154b88c807SRodney W. Grimes 19164b88c807SRodney W. Grimes if (token >= 0) { 19174b88c807SRodney W. Grimes fmtstr(msg, 64, "%s unexpected (expecting %s)", 19184b88c807SRodney W. Grimes tokname[lasttoken], tokname[token]); 19194b88c807SRodney W. Grimes } else { 19204b88c807SRodney W. Grimes fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 19214b88c807SRodney W. Grimes } 19224b88c807SRodney W. Grimes synerror(msg); 19234b88c807SRodney W. Grimes } 19244b88c807SRodney W. Grimes 19254b88c807SRodney W. Grimes 192688328642SDavid E. O'Brien static void 1927384aedabSJilles Tjoelker synerror(const char *msg) 19284b88c807SRodney W. Grimes { 19294b88c807SRodney W. Grimes if (commandname) 1930f7cc73afSJilles Tjoelker outfmt(out2, "%s: %d: ", commandname, startlinno); 1931fafeab43SJilles Tjoelker else if (arg0) 1932fafeab43SJilles Tjoelker outfmt(out2, "%s: ", arg0); 1933f7cc73afSJilles Tjoelker outfmt(out2, "Syntax error: %s\n", msg); 19344b88c807SRodney W. Grimes error((char *)NULL); 19354b88c807SRodney W. Grimes } 19364b88c807SRodney W. Grimes 193788328642SDavid E. O'Brien static void 19385134c3f7SWarner Losh setprompt(int which) 19394b88c807SRodney W. Grimes { 19404b88c807SRodney W. Grimes whichprompt = which; 1941c39f3bacSJilles Tjoelker if (which == 0) 1942c39f3bacSJilles Tjoelker return; 19434b88c807SRodney W. Grimes 1944aa9caaf6SPeter Wemm #ifndef NO_HISTORY 19454b88c807SRodney W. Grimes if (!el) 1946aa9caaf6SPeter Wemm #endif 1947c6204d4aSJilles Tjoelker { 19484b88c807SRodney W. Grimes out2str(getprompt(NULL)); 1949c6204d4aSJilles Tjoelker flushout(out2); 1950c6204d4aSJilles Tjoelker } 19514b88c807SRodney W. Grimes } 19524b88c807SRodney W. Grimes 19530b4b9c81SJilles Tjoelker static int 19540b4b9c81SJilles Tjoelker pgetc_linecont(void) 19550b4b9c81SJilles Tjoelker { 19560b4b9c81SJilles Tjoelker int c; 19570b4b9c81SJilles Tjoelker 19580b4b9c81SJilles Tjoelker while ((c = pgetc_macro()) == '\\') { 19590b4b9c81SJilles Tjoelker c = pgetc(); 19600b4b9c81SJilles Tjoelker if (c == '\n') { 19610b4b9c81SJilles Tjoelker plinno++; 19620b4b9c81SJilles Tjoelker if (doprompt) 19630b4b9c81SJilles Tjoelker setprompt(2); 19640b4b9c81SJilles Tjoelker else 19650b4b9c81SJilles Tjoelker setprompt(0); 19660b4b9c81SJilles Tjoelker } else { 19670b4b9c81SJilles Tjoelker pungetc(); 19680b4b9c81SJilles Tjoelker /* Allow the backslash to be pushed back. */ 19690b4b9c81SJilles Tjoelker pushstring("\\", 1, NULL); 19700b4b9c81SJilles Tjoelker return (pgetc()); 19710b4b9c81SJilles Tjoelker } 19720b4b9c81SJilles Tjoelker } 19730b4b9c81SJilles Tjoelker return (c); 19740b4b9c81SJilles Tjoelker } 19750b4b9c81SJilles Tjoelker 1976d81ca439SEdward Tomasz Napierala 1977d81ca439SEdward Tomasz Napierala static struct passwd * 1978d81ca439SEdward Tomasz Napierala getpwlogin(void) 1979d81ca439SEdward Tomasz Napierala { 1980d81ca439SEdward Tomasz Napierala const char *login; 1981d81ca439SEdward Tomasz Napierala 1982d81ca439SEdward Tomasz Napierala login = getlogin(); 1983d81ca439SEdward Tomasz Napierala if (login == NULL) 1984d81ca439SEdward Tomasz Napierala return (NULL); 1985d81ca439SEdward Tomasz Napierala 1986d81ca439SEdward Tomasz Napierala return (getpwnam(login)); 1987d81ca439SEdward Tomasz Napierala } 1988d81ca439SEdward Tomasz Napierala 1989d81ca439SEdward Tomasz Napierala 1990d81ca439SEdward Tomasz Napierala static void 1991d81ca439SEdward Tomasz Napierala getusername(char *name, size_t namelen) 1992d81ca439SEdward Tomasz Napierala { 1993d81ca439SEdward Tomasz Napierala static char cached_name[MAXLOGNAME]; 1994d81ca439SEdward Tomasz Napierala struct passwd *pw; 1995d81ca439SEdward Tomasz Napierala uid_t euid; 1996d81ca439SEdward Tomasz Napierala 1997d81ca439SEdward Tomasz Napierala if (cached_name[0] == '\0') { 1998d81ca439SEdward Tomasz Napierala euid = geteuid(); 1999d81ca439SEdward Tomasz Napierala 2000d81ca439SEdward Tomasz Napierala /* 2001d81ca439SEdward Tomasz Napierala * Handle the case when there is more than one 2002d81ca439SEdward Tomasz Napierala * login with the same UID, or when the login 2003d81ca439SEdward Tomasz Napierala * returned by getlogin(2) does no longer match 2004d81ca439SEdward Tomasz Napierala * the current UID. 2005d81ca439SEdward Tomasz Napierala */ 2006d81ca439SEdward Tomasz Napierala pw = getpwlogin(); 2007d81ca439SEdward Tomasz Napierala if (pw == NULL || pw->pw_uid != euid) 2008d81ca439SEdward Tomasz Napierala pw = getpwuid(euid); 2009d81ca439SEdward Tomasz Napierala 2010d81ca439SEdward Tomasz Napierala if (pw != NULL) { 2011d81ca439SEdward Tomasz Napierala strlcpy(cached_name, pw->pw_name, 2012d81ca439SEdward Tomasz Napierala sizeof(cached_name)); 2013d81ca439SEdward Tomasz Napierala } else { 2014d81ca439SEdward Tomasz Napierala snprintf(cached_name, sizeof(cached_name), 2015d81ca439SEdward Tomasz Napierala "%u", euid); 2016d81ca439SEdward Tomasz Napierala } 2017d81ca439SEdward Tomasz Napierala } 2018d81ca439SEdward Tomasz Napierala 2019d81ca439SEdward Tomasz Napierala strlcpy(name, cached_name, namelen); 2020d81ca439SEdward Tomasz Napierala } 2021d81ca439SEdward Tomasz Napierala 2022d81ca439SEdward Tomasz Napierala 20234b88c807SRodney W. Grimes /* 20244b88c807SRodney W. Grimes * called by editline -- any expansions to the prompt 20254b88c807SRodney W. Grimes * should be added here. 20264b88c807SRodney W. Grimes */ 20274b88c807SRodney W. Grimes char * 20285134c3f7SWarner Losh getprompt(void *unused __unused) 20294b88c807SRodney W. Grimes { 2030f0c73601SDavid E. O'Brien static char ps[PROMPTLEN]; 20315545faddSJilles Tjoelker const char *fmt; 203220c9381cSEdward Tomasz Napierala const char *home; 2033c9c987cdSJilles Tjoelker const char *pwd; 203420c9381cSEdward Tomasz Napierala size_t homelen; 2035c9c987cdSJilles Tjoelker int i, trim; 2036274110dfSJilles Tjoelker static char internal_error[] = "??"; 2037f0c73601SDavid E. O'Brien 2038f0c73601SDavid E. O'Brien /* 2039f0c73601SDavid E. O'Brien * Select prompt format. 2040f0c73601SDavid E. O'Brien */ 20414b88c807SRodney W. Grimes switch (whichprompt) { 20424b88c807SRodney W. Grimes case 0: 2043781bfb5aSJilles Tjoelker fmt = ""; 2044f0c73601SDavid E. O'Brien break; 20454b88c807SRodney W. Grimes case 1: 2046f0c73601SDavid E. O'Brien fmt = ps1val(); 2047f0c73601SDavid E. O'Brien break; 20484b88c807SRodney W. Grimes case 2: 2049f0c73601SDavid E. O'Brien fmt = ps2val(); 2050f0c73601SDavid E. O'Brien break; 20514b88c807SRodney W. Grimes default: 2052384aedabSJilles Tjoelker return internal_error; 20534b88c807SRodney W. Grimes } 2054f0c73601SDavid E. O'Brien 2055f0c73601SDavid E. O'Brien /* 2056f0c73601SDavid E. O'Brien * Format prompt string. 2057f0c73601SDavid E. O'Brien */ 205863b6e661SPiotr Pawel Stefaniak for (i = 0; (i < PROMPTLEN - 1) && (*fmt != '\0'); i++, fmt++) { 205963b6e661SPiotr Pawel Stefaniak if (*fmt != '\\') { 206063b6e661SPiotr Pawel Stefaniak ps[i] = *fmt; 206163b6e661SPiotr Pawel Stefaniak continue; 206263b6e661SPiotr Pawel Stefaniak } 206363b6e661SPiotr Pawel Stefaniak 2064f0c73601SDavid E. O'Brien switch (*++fmt) { 2065f0c73601SDavid E. O'Brien 2066f0c73601SDavid E. O'Brien /* 20673cf65f8aSJuraj Lutter * Non-printing sequence begin and end. 20683cf65f8aSJuraj Lutter */ 20693cf65f8aSJuraj Lutter case '[': 20703cf65f8aSJuraj Lutter case ']': 20713cf65f8aSJuraj Lutter ps[i] = '\001'; 20723cf65f8aSJuraj Lutter break; 20733cf65f8aSJuraj Lutter 20743cf65f8aSJuraj Lutter /* 20753cf65f8aSJuraj Lutter * Literal \ and some ASCII characters: 20763cf65f8aSJuraj Lutter * \a BEL 20773cf65f8aSJuraj Lutter * \e ESC 20783cf65f8aSJuraj Lutter * \r CR 20793cf65f8aSJuraj Lutter */ 20803cf65f8aSJuraj Lutter case '\\': 20813cf65f8aSJuraj Lutter case 'a': 20823cf65f8aSJuraj Lutter case 'e': 20833cf65f8aSJuraj Lutter case 'r': 20843cf65f8aSJuraj Lutter if (*fmt == 'a') 20853cf65f8aSJuraj Lutter ps[i] = '\007'; 20863cf65f8aSJuraj Lutter else if (*fmt == 'e') 20873cf65f8aSJuraj Lutter ps[i] = '\033'; 20883cf65f8aSJuraj Lutter else if (*fmt == 'r') 20893cf65f8aSJuraj Lutter ps[i] = '\r'; 20903cf65f8aSJuraj Lutter else 20913cf65f8aSJuraj Lutter ps[i] = '\\'; 20923cf65f8aSJuraj Lutter break; 20933cf65f8aSJuraj Lutter 20943cf65f8aSJuraj Lutter /* 20953cf65f8aSJuraj Lutter * CRLF sequence 20963cf65f8aSJuraj Lutter */ 20973cf65f8aSJuraj Lutter case 'n': 20983cf65f8aSJuraj Lutter if (i < PROMPTLEN - 3) { 20993cf65f8aSJuraj Lutter ps[i++] = '\r'; 21003cf65f8aSJuraj Lutter ps[i] = '\n'; 21013cf65f8aSJuraj Lutter } 21023cf65f8aSJuraj Lutter break; 21033cf65f8aSJuraj Lutter 21043cf65f8aSJuraj Lutter /* 2105*a675eaecSPiotr Pawel Stefaniak * Print the current time as per provided strftime format. 2106*a675eaecSPiotr Pawel Stefaniak */ 2107*a675eaecSPiotr Pawel Stefaniak case 'D': { 2108*a675eaecSPiotr Pawel Stefaniak char tfmt[128] = "%X"; /* \D{} means %X. */ 2109*a675eaecSPiotr Pawel Stefaniak struct tm *now; 2110*a675eaecSPiotr Pawel Stefaniak 2111*a675eaecSPiotr Pawel Stefaniak if (fmt[1] != '{') { 2112*a675eaecSPiotr Pawel Stefaniak /* 2113*a675eaecSPiotr Pawel Stefaniak * "\D" but not "\D{", so treat the '\' 2114*a675eaecSPiotr Pawel Stefaniak * literally and rewind fmt to treat 'D' 2115*a675eaecSPiotr Pawel Stefaniak * literally next iteration. 2116*a675eaecSPiotr Pawel Stefaniak */ 2117*a675eaecSPiotr Pawel Stefaniak ps[i] = '\\'; 2118*a675eaecSPiotr Pawel Stefaniak fmt--; 2119*a675eaecSPiotr Pawel Stefaniak break; 2120*a675eaecSPiotr Pawel Stefaniak } 2121*a675eaecSPiotr Pawel Stefaniak fmt += 2; /* Consume "D{". */ 2122*a675eaecSPiotr Pawel Stefaniak if (fmt[0] != '}') { 2123*a675eaecSPiotr Pawel Stefaniak char *end; 2124*a675eaecSPiotr Pawel Stefaniak 2125*a675eaecSPiotr Pawel Stefaniak end = memccpy(tfmt, fmt, '}', sizeof(tfmt)); 2126*a675eaecSPiotr Pawel Stefaniak if (end == NULL) { 2127*a675eaecSPiotr Pawel Stefaniak /* 2128*a675eaecSPiotr Pawel Stefaniak * Format too long or no '}', so 2129*a675eaecSPiotr Pawel Stefaniak * ignore "\D{" altogether. 2130*a675eaecSPiotr Pawel Stefaniak * The loop will do i++, but nothing 2131*a675eaecSPiotr Pawel Stefaniak * was written to ps, so do i-- here. 2132*a675eaecSPiotr Pawel Stefaniak * Rewind fmt for similar reason. 2133*a675eaecSPiotr Pawel Stefaniak */ 2134*a675eaecSPiotr Pawel Stefaniak i--; 2135*a675eaecSPiotr Pawel Stefaniak fmt--; 2136*a675eaecSPiotr Pawel Stefaniak break; 2137*a675eaecSPiotr Pawel Stefaniak } 2138*a675eaecSPiotr Pawel Stefaniak *--end = '\0'; /* Ignore the copy of '}'. */ 2139*a675eaecSPiotr Pawel Stefaniak fmt += end - tfmt; 2140*a675eaecSPiotr Pawel Stefaniak } 2141*a675eaecSPiotr Pawel Stefaniak now = localtime(&(time_t){time(NULL)}); 2142*a675eaecSPiotr Pawel Stefaniak i += strftime(&ps[i], PROMPTLEN - i - 1, tfmt, now); 2143*a675eaecSPiotr Pawel Stefaniak i--; /* The loop will do i++. */ 2144*a675eaecSPiotr Pawel Stefaniak break; 2145*a675eaecSPiotr Pawel Stefaniak } 2146*a675eaecSPiotr Pawel Stefaniak 2147*a675eaecSPiotr Pawel Stefaniak /* 2148f0c73601SDavid E. O'Brien * Hostname. 2149f0c73601SDavid E. O'Brien * 2150f0c73601SDavid E. O'Brien * \h specifies just the local hostname, 2151f0c73601SDavid E. O'Brien * \H specifies fully-qualified hostname. 2152f0c73601SDavid E. O'Brien */ 2153f0c73601SDavid E. O'Brien case 'h': 2154f0c73601SDavid E. O'Brien case 'H': 21558d999570SStefan Farfeleder ps[i] = '\0'; 215663a4675dSDon Lewis gethostname(&ps[i], PROMPTLEN - i - 1); 215763a4675dSDon Lewis ps[PROMPTLEN - 1] = '\0'; 2158f0c73601SDavid E. O'Brien /* Skip to end of hostname. */ 2159f0c73601SDavid E. O'Brien trim = (*fmt == 'h') ? '.' : '\0'; 21608e3543eeSEric van Gyzen while ((ps[i] != '\0') && (ps[i] != trim)) 2161f0c73601SDavid E. O'Brien i++; 21628e3543eeSEric van Gyzen --i; 2163f0c73601SDavid E. O'Brien break; 2164f0c73601SDavid E. O'Brien 2165f0c73601SDavid E. O'Brien /* 2166d81ca439SEdward Tomasz Napierala * User name. 2167d81ca439SEdward Tomasz Napierala */ 2168d81ca439SEdward Tomasz Napierala case 'u': 2169d81ca439SEdward Tomasz Napierala ps[i] = '\0'; 2170d81ca439SEdward Tomasz Napierala getusername(&ps[i], PROMPTLEN - i); 2171d81ca439SEdward Tomasz Napierala /* Skip to end of username. */ 2172d81ca439SEdward Tomasz Napierala while (ps[i + 1] != '\0') 2173d81ca439SEdward Tomasz Napierala i++; 2174d81ca439SEdward Tomasz Napierala break; 2175d81ca439SEdward Tomasz Napierala 2176d81ca439SEdward Tomasz Napierala /* 2177f0c73601SDavid E. O'Brien * Working directory. 2178f0c73601SDavid E. O'Brien * 2179f0c73601SDavid E. O'Brien * \W specifies just the final component, 2180f0c73601SDavid E. O'Brien * \w specifies the entire path. 2181f0c73601SDavid E. O'Brien */ 2182f0c73601SDavid E. O'Brien case 'W': 2183f0c73601SDavid E. O'Brien case 'w': 2184c9c987cdSJilles Tjoelker pwd = lookupvar("PWD"); 21858e3543eeSEric van Gyzen if (pwd == NULL || *pwd == '\0') 2186c9c987cdSJilles Tjoelker pwd = "?"; 2187c9c987cdSJilles Tjoelker if (*fmt == 'W' && 2188c9c987cdSJilles Tjoelker *pwd == '/' && pwd[1] != '\0') 2189c9c987cdSJilles Tjoelker strlcpy(&ps[i], strrchr(pwd, '/') + 1, 2190c9c987cdSJilles Tjoelker PROMPTLEN - i); 219120c9381cSEdward Tomasz Napierala else { 219220c9381cSEdward Tomasz Napierala home = lookupvar("HOME"); 219320c9381cSEdward Tomasz Napierala if (home != NULL) 219420c9381cSEdward Tomasz Napierala homelen = strlen(home); 219520c9381cSEdward Tomasz Napierala if (home != NULL && 219620c9381cSEdward Tomasz Napierala strcmp(home, "/") != 0 && 219720c9381cSEdward Tomasz Napierala strncmp(pwd, home, homelen) == 0 && 219820c9381cSEdward Tomasz Napierala (pwd[homelen] == '/' || 219920c9381cSEdward Tomasz Napierala pwd[homelen] == '\0')) { 220020c9381cSEdward Tomasz Napierala strlcpy(&ps[i], "~", 220120c9381cSEdward Tomasz Napierala PROMPTLEN - i); 220220c9381cSEdward Tomasz Napierala strlcpy(&ps[i + 1], 220320c9381cSEdward Tomasz Napierala pwd + homelen, 220420c9381cSEdward Tomasz Napierala PROMPTLEN - i - 1); 220520c9381cSEdward Tomasz Napierala } else { 2206c9c987cdSJilles Tjoelker strlcpy(&ps[i], pwd, PROMPTLEN - i); 220720c9381cSEdward Tomasz Napierala } 220820c9381cSEdward Tomasz Napierala } 2209f0c73601SDavid E. O'Brien /* Skip to end of path. */ 2210f0c73601SDavid E. O'Brien while (ps[i + 1] != '\0') 2211f0c73601SDavid E. O'Brien i++; 2212f0c73601SDavid E. O'Brien break; 2213f0c73601SDavid E. O'Brien 2214f0c73601SDavid E. O'Brien /* 2215f0c73601SDavid E. O'Brien * Superuser status. 2216f0c73601SDavid E. O'Brien * 2217f0c73601SDavid E. O'Brien * '$' for normal users, '#' for root. 2218f0c73601SDavid E. O'Brien */ 2219f0c73601SDavid E. O'Brien case '$': 2220f0c73601SDavid E. O'Brien ps[i] = (geteuid() != 0) ? '$' : '#'; 2221f0c73601SDavid E. O'Brien break; 2222f0c73601SDavid E. O'Brien 2223f0c73601SDavid E. O'Brien /* 2224f0c73601SDavid E. O'Brien * Emit unrecognized formats verbatim. 2225f0c73601SDavid E. O'Brien */ 2226f0c73601SDavid E. O'Brien default: 222763a4675dSDon Lewis ps[i] = '\\'; 2228eaf2e1e6SDon Lewis if (i < PROMPTLEN - 2) 222963a4675dSDon Lewis ps[++i] = *fmt; 2230f0c73601SDavid E. O'Brien break; 2231f0c73601SDavid E. O'Brien } 223263b6e661SPiotr Pawel Stefaniak 223363b6e661SPiotr Pawel Stefaniak } 2234f0c73601SDavid E. O'Brien ps[i] = '\0'; 2235f0c73601SDavid E. O'Brien return (ps); 22364b88c807SRodney W. Grimes } 2237292e6676SJilles Tjoelker 2238292e6676SJilles Tjoelker 2239292e6676SJilles Tjoelker const char * 224046c6b52dSJilles Tjoelker expandstr(const char *ps) 2241292e6676SJilles Tjoelker { 2242292e6676SJilles Tjoelker union node n; 2243292e6676SJilles Tjoelker struct jmploc jmploc; 2244292e6676SJilles Tjoelker struct jmploc *const savehandler = handler; 2245292e6676SJilles Tjoelker const int saveprompt = doprompt; 2246292e6676SJilles Tjoelker struct parsefile *const savetopfile = getcurrentfile(); 2247292e6676SJilles Tjoelker struct parser_temp *const saveparser_temp = parser_temp; 2248292e6676SJilles Tjoelker const char *result = NULL; 2249292e6676SJilles Tjoelker 2250292e6676SJilles Tjoelker if (!setjmp(jmploc.loc)) { 2251292e6676SJilles Tjoelker handler = &jmploc; 2252292e6676SJilles Tjoelker parser_temp = NULL; 2253292e6676SJilles Tjoelker setinputstring(ps, 1); 2254292e6676SJilles Tjoelker doprompt = 0; 225592fe71faSJilles Tjoelker readtoken1(pgetc(), DQSYNTAX, NOEOFMARK, 0); 2256292e6676SJilles Tjoelker if (backquotelist != NULL) 2257292e6676SJilles Tjoelker error("Command substitution not allowed here"); 2258292e6676SJilles Tjoelker 2259292e6676SJilles Tjoelker n.narg.type = NARG; 2260292e6676SJilles Tjoelker n.narg.next = NULL; 2261292e6676SJilles Tjoelker n.narg.text = wordtext; 2262292e6676SJilles Tjoelker n.narg.backquote = backquotelist; 2263292e6676SJilles Tjoelker 2264292e6676SJilles Tjoelker expandarg(&n, NULL, 0); 2265292e6676SJilles Tjoelker result = stackblock(); 2266292e6676SJilles Tjoelker INTOFF; 2267292e6676SJilles Tjoelker } 2268292e6676SJilles Tjoelker handler = savehandler; 2269292e6676SJilles Tjoelker doprompt = saveprompt; 2270292e6676SJilles Tjoelker popfilesupto(savetopfile); 2271292e6676SJilles Tjoelker if (parser_temp != saveparser_temp) { 2272292e6676SJilles Tjoelker parser_temp_free_all(); 2273292e6676SJilles Tjoelker parser_temp = saveparser_temp; 2274292e6676SJilles Tjoelker } 2275292e6676SJilles Tjoelker if (result != NULL) { 2276292e6676SJilles Tjoelker INTON; 2277292e6676SJilles Tjoelker } else if (exception == EXINT) 2278292e6676SJilles Tjoelker raise(SIGINT); 2279292e6676SJilles Tjoelker return result; 2280292e6676SJilles Tjoelker } 2281