Sun Mar 27 14:36:29 2016 UTC ()
Cease "support" for <redirect> fn() { ...
Any redirect (or redirects) before a function definition were
allowed by the parser, but otherwise totally ignored.  The standard
syntax does not permit redirects there, now, neither do we. (from kre@)


(christos)
diff -r1.109 -r1.110 src/bin/sh/parser.c

cvs diff -r1.109 -r1.110 src/bin/sh/parser.c (switch to unified diff)

--- src/bin/sh/parser.c 2016/03/27 14:35:30 1.109
+++ src/bin/sh/parser.c 2016/03/27 14:36:29 1.110
@@ -1,1599 +1,1592 @@ @@ -1,1599 +1,1592 @@
1/* $NetBSD: parser.c,v 1.109 2016/03/27 14:35:30 christos Exp $ */ 1/* $NetBSD: parser.c,v 1.110 2016/03/27 14:36:29 christos Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1991, 1993 4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist. 8 * Kenneth Almquist.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36#ifndef lint 36#ifndef lint
37#if 0 37#if 0
38static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; 38static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
39#else 39#else
40__RCSID("$NetBSD: parser.c,v 1.109 2016/03/27 14:35:30 christos Exp $"); 40__RCSID("$NetBSD: parser.c,v 1.110 2016/03/27 14:36:29 christos Exp $");
41#endif 41#endif
42#endif /* not lint */ 42#endif /* not lint */
43 43
44#include <stdio.h> 44#include <stdio.h>
45#include <stdlib.h> 45#include <stdlib.h>
46#include <limits.h> 46#include <limits.h>
47 47
48#include "shell.h" 48#include "shell.h"
49#include "parser.h" 49#include "parser.h"
50#include "nodes.h" 50#include "nodes.h"
51#include "expand.h" /* defines rmescapes() */ 51#include "expand.h" /* defines rmescapes() */
52#include "eval.h" /* defines commandname */ 52#include "eval.h" /* defines commandname */
53#include "redir.h" /* defines copyfd() */ 53#include "redir.h" /* defines copyfd() */
54#include "syntax.h" 54#include "syntax.h"
55#include "options.h" 55#include "options.h"
56#include "input.h" 56#include "input.h"
57#include "output.h" 57#include "output.h"
58#include "var.h" 58#include "var.h"
59#include "error.h" 59#include "error.h"
60#include "memalloc.h" 60#include "memalloc.h"
61#include "mystring.h" 61#include "mystring.h"
62#include "alias.h" 62#include "alias.h"
63#include "show.h" 63#include "show.h"
64#ifndef SMALL 64#ifndef SMALL
65#include "myhistedit.h" 65#include "myhistedit.h"
66#endif 66#endif
67 67
68/* 68/*
69 * Shell command parser. 69 * Shell command parser.
70 */ 70 */
71 71
72#define EOFMARKLEN 79 72#define EOFMARKLEN 79
73 73
74/* values returned by readtoken */ 74/* values returned by readtoken */
75#include "token.h" 75#include "token.h"
76 76
77#define OPENBRACE '{' 77#define OPENBRACE '{'
78#define CLOSEBRACE '}' 78#define CLOSEBRACE '}'
79 79
80 80
81struct heredoc { 81struct heredoc {
82 struct heredoc *next; /* next here document in list */ 82 struct heredoc *next; /* next here document in list */
83 union node *here; /* redirection node */ 83 union node *here; /* redirection node */
84 char *eofmark; /* string indicating end of input */ 84 char *eofmark; /* string indicating end of input */
85 int striptabs; /* if set, strip leading tabs */ 85 int striptabs; /* if set, strip leading tabs */
86}; 86};
87 87
88 88
89 89
90static int noalias = 0; /* when set, don't handle aliases */ 90static int noalias = 0; /* when set, don't handle aliases */
91struct heredoc *heredoclist; /* list of here documents to read */ 91struct heredoc *heredoclist; /* list of here documents to read */
92int parsebackquote; /* nonzero if we are inside backquotes */ 92int parsebackquote; /* nonzero if we are inside backquotes */
93int doprompt; /* if set, prompt the user */ 93int doprompt; /* if set, prompt the user */
94int needprompt; /* true if interactive and at start of line */ 94int needprompt; /* true if interactive and at start of line */
95int lasttoken; /* last token read */ 95int lasttoken; /* last token read */
96MKINIT int tokpushback; /* last token pushed back */ 96MKINIT int tokpushback; /* last token pushed back */
97char *wordtext; /* text of last word returned by readtoken */ 97char *wordtext; /* text of last word returned by readtoken */
98MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 98MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
99struct nodelist *backquotelist; 99struct nodelist *backquotelist;
100union node *redirnode; 100union node *redirnode;
101struct heredoc *heredoc; 101struct heredoc *heredoc;
102int quoteflag; /* set if (part of) last token was quoted */ 102int quoteflag; /* set if (part of) last token was quoted */
103int startlinno; /* line # where last token started */ 103int startlinno; /* line # where last token started */
104int funclinno; /* line # where the current function started */ 104int funclinno; /* line # where the current function started */
105 105
106 106
107STATIC union node *list(int, int); 107STATIC union node *list(int, int);
108STATIC union node *andor(void); 108STATIC union node *andor(void);
109STATIC union node *pipeline(void); 109STATIC union node *pipeline(void);
110STATIC union node *command(void); 110STATIC union node *command(void);
111STATIC union node *simplecmd(union node **, union node *); 111STATIC union node *simplecmd(union node **, union node *);
112STATIC union node *makename(void); 112STATIC union node *makename(void);
113STATIC void parsefname(void); 113STATIC void parsefname(void);
114STATIC void parseheredoc(void); 114STATIC void parseheredoc(void);
115STATIC int peektoken(void); 115STATIC int peektoken(void);
116STATIC int readtoken(void); 116STATIC int readtoken(void);
117STATIC int xxreadtoken(void); 117STATIC int xxreadtoken(void);
118STATIC int readtoken1(int, char const *, char *, int); 118STATIC int readtoken1(int, char const *, char *, int);
119STATIC int noexpand(char *); 119STATIC int noexpand(char *);
120STATIC void synexpect(int, const char *) __dead; 120STATIC void synexpect(int, const char *) __dead;
121STATIC void synerror(const char *) __dead; 121STATIC void synerror(const char *) __dead;
122STATIC void setprompt(int); 122STATIC void setprompt(int);
123 123
124 124
125static const char EOFhere[] = "EOF reading here (<<) document"; 125static const char EOFhere[] = "EOF reading here (<<) document";
126 126
127 127
128/* 128/*
129 * Read and parse a command. Returns NEOF on end of file. (NULL is a 129 * Read and parse a command. Returns NEOF on end of file. (NULL is a
130 * valid parse tree indicating a blank line.) 130 * valid parse tree indicating a blank line.)
131 */ 131 */
132 132
133union node * 133union node *
134parsecmd(int interact) 134parsecmd(int interact)
135{ 135{
136 int t; 136 int t;
137 137
138 tokpushback = 0; 138 tokpushback = 0;
139 doprompt = interact; 139 doprompt = interact;
140 if (doprompt) 140 if (doprompt)
141 setprompt(1); 141 setprompt(1);
142 else 142 else
143 setprompt(0); 143 setprompt(0);
144 needprompt = 0; 144 needprompt = 0;
145 t = readtoken(); 145 t = readtoken();
146 if (t == TEOF) 146 if (t == TEOF)
147 return NEOF; 147 return NEOF;
148 if (t == TNL) 148 if (t == TNL)
149 return NULL; 149 return NULL;
150 tokpushback++; 150 tokpushback++;
151 return list(1, 0); 151 return list(1, 0);
152} 152}
153 153
154 154
155STATIC union node * 155STATIC union node *
156list(int nlflag, int erflag) 156list(int nlflag, int erflag)
157{ 157{
158 union node *n1, *n2, *n3; 158 union node *n1, *n2, *n3;
159 int tok; 159 int tok;
160 TRACE(("list(%d,%d): entered\n", nlflag, erflag)); 160 TRACE(("list(%d,%d): entered\n", nlflag, erflag));
161 161
162 checkkwd = 2; 162 checkkwd = 2;
163 if (nlflag == 0 && tokendlist[peektoken()]) 163 if (nlflag == 0 && tokendlist[peektoken()])
164 return NULL; 164 return NULL;
165 n1 = NULL; 165 n1 = NULL;
166 for (;;) { 166 for (;;) {
167 n2 = andor(); 167 n2 = andor();
168 tok = readtoken(); 168 tok = readtoken();
169 if (tok == TBACKGND) { 169 if (tok == TBACKGND) {
170 if (n2->type == NCMD || n2->type == NPIPE) { 170 if (n2->type == NCMD || n2->type == NPIPE) {
171 n2->ncmd.backgnd = 1; 171 n2->ncmd.backgnd = 1;
172 } else if (n2->type == NREDIR) { 172 } else if (n2->type == NREDIR) {
173 n2->type = NBACKGND; 173 n2->type = NBACKGND;
174 } else { 174 } else {
175 n3 = stalloc(sizeof(struct nredir)); 175 n3 = stalloc(sizeof(struct nredir));
176 n3->type = NBACKGND; 176 n3->type = NBACKGND;
177 n3->nredir.n = n2; 177 n3->nredir.n = n2;
178 n3->nredir.redirect = NULL; 178 n3->nredir.redirect = NULL;
179 n2 = n3; 179 n2 = n3;
180 } 180 }
181 } 181 }
182 if (n1 == NULL) { 182 if (n1 == NULL) {
183 n1 = n2; 183 n1 = n2;
184 } 184 }
185 else { 185 else {
186 n3 = stalloc(sizeof(struct nbinary)); 186 n3 = stalloc(sizeof(struct nbinary));
187 n3->type = NSEMI; 187 n3->type = NSEMI;
188 n3->nbinary.ch1 = n1; 188 n3->nbinary.ch1 = n1;
189 n3->nbinary.ch2 = n2; 189 n3->nbinary.ch2 = n2;
190 n1 = n3; 190 n1 = n3;
191 } 191 }
192 switch (tok) { 192 switch (tok) {
193 case TBACKGND: 193 case TBACKGND:
194 case TSEMI: 194 case TSEMI:
195 tok = readtoken(); 195 tok = readtoken();
196 /* FALLTHROUGH */ 196 /* FALLTHROUGH */
197 case TNL: 197 case TNL:
198 if (tok == TNL) { 198 if (tok == TNL) {
199 parseheredoc(); 199 parseheredoc();
200 if (nlflag) 200 if (nlflag)
201 return n1; 201 return n1;
202 } else { 202 } else {
203 tokpushback++; 203 tokpushback++;
204 } 204 }
205 checkkwd = 2; 205 checkkwd = 2;
206 if (tokendlist[peektoken()]) 206 if (tokendlist[peektoken()])
207 return n1; 207 return n1;
208 break; 208 break;
209 case TEOF: 209 case TEOF:
210 if (heredoclist) 210 if (heredoclist)
211 parseheredoc(); 211 parseheredoc();
212 else 212 else
213 pungetc(); /* push back EOF on input */ 213 pungetc(); /* push back EOF on input */
214 return n1; 214 return n1;
215 default: 215 default:
216 if (nlflag || erflag) 216 if (nlflag || erflag)
217 synexpect(-1, 0); 217 synexpect(-1, 0);
218 tokpushback++; 218 tokpushback++;
219 return n1; 219 return n1;
220 } 220 }
221 } 221 }
222} 222}
223 223
224STATIC union node * 224STATIC union node *
225andor(void) 225andor(void)
226{ 226{
227 union node *n1, *n2, *n3; 227 union node *n1, *n2, *n3;
228 int t; 228 int t;
229 229
230 TRACE(("andor: entered\n")); 230 TRACE(("andor: entered\n"));
231 n1 = pipeline(); 231 n1 = pipeline();
232 for (;;) { 232 for (;;) {
233 if ((t = readtoken()) == TAND) { 233 if ((t = readtoken()) == TAND) {
234 t = NAND; 234 t = NAND;
235 } else if (t == TOR) { 235 } else if (t == TOR) {
236 t = NOR; 236 t = NOR;
237 } else { 237 } else {
238 tokpushback++; 238 tokpushback++;
239 return n1; 239 return n1;
240 } 240 }
241 n2 = pipeline(); 241 n2 = pipeline();
242 n3 = stalloc(sizeof(struct nbinary)); 242 n3 = stalloc(sizeof(struct nbinary));
243 n3->type = t; 243 n3->type = t;
244 n3->nbinary.ch1 = n1; 244 n3->nbinary.ch1 = n1;
245 n3->nbinary.ch2 = n2; 245 n3->nbinary.ch2 = n2;
246 n1 = n3; 246 n1 = n3;
247 } 247 }
248} 248}
249 249
250STATIC union node * 250STATIC union node *
251pipeline(void) 251pipeline(void)
252{ 252{
253 union node *n1, *n2, *pipenode; 253 union node *n1, *n2, *pipenode;
254 struct nodelist *lp, *prev; 254 struct nodelist *lp, *prev;
255 int negate; 255 int negate;
256 256
257 TRACE(("pipeline: entered\n")); 257 TRACE(("pipeline: entered\n"));
258 258
259 negate = 0; 259 negate = 0;
260 checkkwd = 2; 260 checkkwd = 2;
261 while (readtoken() == TNOT) { 261 while (readtoken() == TNOT) {
262 TRACE(("pipeline: TNOT recognized\n")); 262 TRACE(("pipeline: TNOT recognized\n"));
263 negate = !negate; 263 negate = !negate;
264 } 264 }
265 tokpushback++; 265 tokpushback++;
266 n1 = command(); 266 n1 = command();
267 if (readtoken() == TPIPE) { 267 if (readtoken() == TPIPE) {
268 pipenode = stalloc(sizeof(struct npipe)); 268 pipenode = stalloc(sizeof(struct npipe));
269 pipenode->type = NPIPE; 269 pipenode->type = NPIPE;
270 pipenode->npipe.backgnd = 0; 270 pipenode->npipe.backgnd = 0;
271 lp = stalloc(sizeof(struct nodelist)); 271 lp = stalloc(sizeof(struct nodelist));
272 pipenode->npipe.cmdlist = lp; 272 pipenode->npipe.cmdlist = lp;
273 lp->n = n1; 273 lp->n = n1;
274 do { 274 do {
275 prev = lp; 275 prev = lp;
276 lp = stalloc(sizeof(struct nodelist)); 276 lp = stalloc(sizeof(struct nodelist));
277 lp->n = command(); 277 lp->n = command();
278 prev->next = lp; 278 prev->next = lp;
279 } while (readtoken() == TPIPE); 279 } while (readtoken() == TPIPE);
280 lp->next = NULL; 280 lp->next = NULL;
281 n1 = pipenode; 281 n1 = pipenode;
282 } 282 }
283 tokpushback++; 283 tokpushback++;
284 if (negate) { 284 if (negate) {
285 TRACE(("negate pipeline\n")); 285 TRACE(("negate pipeline\n"));
286 n2 = stalloc(sizeof(struct nnot)); 286 n2 = stalloc(sizeof(struct nnot));
287 n2->type = NNOT; 287 n2->type = NNOT;
288 n2->nnot.com = n1; 288 n2->nnot.com = n1;
289 return n2; 289 return n2;
290 } else 290 } else
291 return n1; 291 return n1;
292} 292}
293 293
294 294
295 295
296STATIC union node * 296STATIC union node *
297command(void) 297command(void)
298{ 298{
299 union node *n1, *n2; 299 union node *n1, *n2;
300 union node *ap, **app; 300 union node *ap, **app;
301 union node *cp, **cpp; 301 union node *cp, **cpp;
302 union node *redir, **rpp; 302 union node *redir, **rpp;
303 int t, negate = 0; 303 int t, negate = 0;
304 304
305 TRACE(("command: entered\n")); 305 TRACE(("command: entered\n"));
306 306
307 checkkwd = 2; 307 checkkwd = 2;
308 redir = NULL; 308 redir = NULL;
309 n1 = NULL; 309 n1 = NULL;
310 rpp = &redir; 310 rpp = &redir;
311 311
312 /* Check for redirection which may precede command */ 312 /* Check for redirection which may precede command */
313 while (readtoken() == TREDIR) { 313 while (readtoken() == TREDIR) {
314 *rpp = n2 = redirnode; 314 *rpp = n2 = redirnode;
315 rpp = &n2->nfile.next; 315 rpp = &n2->nfile.next;
316 parsefname(); 316 parsefname();
317 } 317 }
318 tokpushback++; 318 tokpushback++;
319 319
320 while (readtoken() == TNOT) { 320 while (readtoken() == TNOT) {
321 TRACE(("command: TNOT recognized\n")); 321 TRACE(("command: TNOT recognized\n"));
322 negate = !negate; 322 negate = !negate;
323 } 323 }
324 tokpushback++; 324 tokpushback++;
325 325
326 switch (readtoken()) { 326 switch (readtoken()) {
327 case TIF: 327 case TIF:
328 n1 = stalloc(sizeof(struct nif)); 328 n1 = stalloc(sizeof(struct nif));
329 n1->type = NIF; 329 n1->type = NIF;
330 n1->nif.test = list(0, 0); 330 n1->nif.test = list(0, 0);
331 if (readtoken() != TTHEN) 331 if (readtoken() != TTHEN)
332 synexpect(TTHEN, 0); 332 synexpect(TTHEN, 0);
333 n1->nif.ifpart = list(0, 0); 333 n1->nif.ifpart = list(0, 0);
334 n2 = n1; 334 n2 = n1;
335 while (readtoken() == TELIF) { 335 while (readtoken() == TELIF) {
336 n2->nif.elsepart = stalloc(sizeof(struct nif)); 336 n2->nif.elsepart = stalloc(sizeof(struct nif));
337 n2 = n2->nif.elsepart; 337 n2 = n2->nif.elsepart;
338 n2->type = NIF; 338 n2->type = NIF;
339 n2->nif.test = list(0, 0); 339 n2->nif.test = list(0, 0);
340 if (readtoken() != TTHEN) 340 if (readtoken() != TTHEN)
341 synexpect(TTHEN, 0); 341 synexpect(TTHEN, 0);
342 n2->nif.ifpart = list(0, 0); 342 n2->nif.ifpart = list(0, 0);
343 } 343 }
344 if (lasttoken == TELSE) 344 if (lasttoken == TELSE)
345 n2->nif.elsepart = list(0, 0); 345 n2->nif.elsepart = list(0, 0);
346 else { 346 else {
347 n2->nif.elsepart = NULL; 347 n2->nif.elsepart = NULL;
348 tokpushback++; 348 tokpushback++;
349 } 349 }
350 if (readtoken() != TFI) 350 if (readtoken() != TFI)
351 synexpect(TFI, 0); 351 synexpect(TFI, 0);
352 checkkwd = 1; 352 checkkwd = 1;
353 break; 353 break;
354 case TWHILE: 354 case TWHILE:
355 case TUNTIL: { 355 case TUNTIL: {
356 int got; 356 int got;
357 n1 = stalloc(sizeof(struct nbinary)); 357 n1 = stalloc(sizeof(struct nbinary));
358 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 358 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
359 n1->nbinary.ch1 = list(0, 0); 359 n1->nbinary.ch1 = list(0, 0);
360 if ((got=readtoken()) != TDO) { 360 if ((got=readtoken()) != TDO) {
361TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 361TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
362 synexpect(TDO, 0); 362 synexpect(TDO, 0);
363 } 363 }
364 n1->nbinary.ch2 = list(0, 0); 364 n1->nbinary.ch2 = list(0, 0);
365 if (readtoken() != TDONE) 365 if (readtoken() != TDONE)
366 synexpect(TDONE, 0); 366 synexpect(TDONE, 0);
367 checkkwd = 1; 367 checkkwd = 1;
368 break; 368 break;
369 } 369 }
370 case TFOR: 370 case TFOR:
371 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 371 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
372 synerror("Bad for loop variable"); 372 synerror("Bad for loop variable");
373 n1 = stalloc(sizeof(struct nfor)); 373 n1 = stalloc(sizeof(struct nfor));
374 n1->type = NFOR; 374 n1->type = NFOR;
375 n1->nfor.var = wordtext; 375 n1->nfor.var = wordtext;
376 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 376 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
377 app = &ap; 377 app = &ap;
378 while (readtoken() == TWORD) { 378 while (readtoken() == TWORD) {
379 n2 = stalloc(sizeof(struct narg)); 379 n2 = stalloc(sizeof(struct narg));
380 n2->type = NARG; 380 n2->type = NARG;
381 n2->narg.text = wordtext; 381 n2->narg.text = wordtext;
382 n2->narg.backquote = backquotelist; 382 n2->narg.backquote = backquotelist;
383 *app = n2; 383 *app = n2;
384 app = &n2->narg.next; 384 app = &n2->narg.next;
385 } 385 }
386 *app = NULL; 386 *app = NULL;
387 n1->nfor.args = ap; 387 n1->nfor.args = ap;
388 if (lasttoken != TNL && lasttoken != TSEMI) 388 if (lasttoken != TNL && lasttoken != TSEMI)
389 synexpect(-1, 0); 389 synexpect(-1, 0);
390 } else { 390 } else {
391 static char argvars[5] = { 391 static char argvars[5] = {
392 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 392 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
393 }; 393 };
394 n2 = stalloc(sizeof(struct narg)); 394 n2 = stalloc(sizeof(struct narg));
395 n2->type = NARG; 395 n2->type = NARG;
396 n2->narg.text = argvars; 396 n2->narg.text = argvars;
397 n2->narg.backquote = NULL; 397 n2->narg.backquote = NULL;
398 n2->narg.next = NULL; 398 n2->narg.next = NULL;
399 n1->nfor.args = n2; 399 n1->nfor.args = n2;
400 /* 400 /*
401 * Newline or semicolon here is optional (but note 401 * Newline or semicolon here is optional (but note
402 * that the original Bourne shell only allowed NL). 402 * that the original Bourne shell only allowed NL).
403 */ 403 */
404 if (lasttoken != TNL && lasttoken != TSEMI) 404 if (lasttoken != TNL && lasttoken != TSEMI)
405 tokpushback++; 405 tokpushback++;
406 } 406 }
407 checkkwd = 2; 407 checkkwd = 2;
408 if ((t = readtoken()) == TDO) 408 if ((t = readtoken()) == TDO)
409 t = TDONE; 409 t = TDONE;
410 else if (t == TBEGIN) 410 else if (t == TBEGIN)
411 t = TEND; 411 t = TEND;
412 else 412 else
413 synexpect(-1, 0); 413 synexpect(-1, 0);
414 n1->nfor.body = list(0, 0); 414 n1->nfor.body = list(0, 0);
415 if (readtoken() != t) 415 if (readtoken() != t)
416 synexpect(t, 0); 416 synexpect(t, 0);
417 checkkwd = 1; 417 checkkwd = 1;
418 break; 418 break;
419 case TCASE: 419 case TCASE:
420 n1 = stalloc(sizeof(struct ncase)); 420 n1 = stalloc(sizeof(struct ncase));
421 n1->type = NCASE; 421 n1->type = NCASE;
422 if (readtoken() != TWORD) 422 if (readtoken() != TWORD)
423 synexpect(TWORD, 0); 423 synexpect(TWORD, 0);
424 n1->ncase.expr = n2 = stalloc(sizeof(struct narg)); 424 n1->ncase.expr = n2 = stalloc(sizeof(struct narg));
425 n2->type = NARG; 425 n2->type = NARG;
426 n2->narg.text = wordtext; 426 n2->narg.text = wordtext;
427 n2->narg.backquote = backquotelist; 427 n2->narg.backquote = backquotelist;
428 n2->narg.next = NULL; 428 n2->narg.next = NULL;
429 while (readtoken() == TNL); 429 while (readtoken() == TNL);
430 if (lasttoken != TWORD || ! equal(wordtext, "in")) 430 if (lasttoken != TWORD || ! equal(wordtext, "in"))
431 synexpect(-1, "in"); 431 synexpect(-1, "in");
432 cpp = &n1->ncase.cases; 432 cpp = &n1->ncase.cases;
433 noalias = 1; 433 noalias = 1;
434 checkkwd = 2, readtoken(); 434 checkkwd = 2, readtoken();
435 /* 435 /*
436 * Both ksh and bash accept 'case x in esac' 436 * Both ksh and bash accept 'case x in esac'
437 * so configure scripts started taking advantage of this. 437 * so configure scripts started taking advantage of this.
438 * The page: http://pubs.opengroup.org/onlinepubs/\ 438 * The page: http://pubs.opengroup.org/onlinepubs/\
439 * 009695399/utilities/xcu_chap02.html contradicts itself, 439 * 009695399/utilities/xcu_chap02.html contradicts itself,
440 * as to if this is legal; the "Case Conditional Format" 440 * as to if this is legal; the "Case Conditional Format"
441 * paragraph shows one case is required, but the "Grammar" 441 * paragraph shows one case is required, but the "Grammar"
442 * section shows a grammar that explicitly allows the no 442 * section shows a grammar that explicitly allows the no
443 * case option. 443 * case option.
444 */ 444 */
445 while (lasttoken != TESAC) { 445 while (lasttoken != TESAC) {
446 *cpp = cp = stalloc(sizeof(struct nclist)); 446 *cpp = cp = stalloc(sizeof(struct nclist));
447 if (lasttoken == TLP) 447 if (lasttoken == TLP)
448 readtoken(); 448 readtoken();
449 cp->type = NCLIST; 449 cp->type = NCLIST;
450 app = &cp->nclist.pattern; 450 app = &cp->nclist.pattern;
451 for (;;) { 451 for (;;) {
452 *app = ap = stalloc(sizeof(struct narg)); 452 *app = ap = stalloc(sizeof(struct narg));
453 ap->type = NARG; 453 ap->type = NARG;
454 ap->narg.text = wordtext; 454 ap->narg.text = wordtext;
455 ap->narg.backquote = backquotelist; 455 ap->narg.backquote = backquotelist;
456 if (checkkwd = 2, readtoken() != TPIPE) 456 if (checkkwd = 2, readtoken() != TPIPE)
457 break; 457 break;
458 app = &ap->narg.next; 458 app = &ap->narg.next;
459 readtoken(); 459 readtoken();
460 } 460 }
461 ap->narg.next = NULL; 461 ap->narg.next = NULL;
462 noalias = 0; 462 noalias = 0;
463 if (lasttoken != TRP) { 463 if (lasttoken != TRP) {
464 synexpect(TRP, 0); 464 synexpect(TRP, 0);
465 } 465 }
466 cp->nclist.body = list(0, 0); 466 cp->nclist.body = list(0, 0);
467 467
468 checkkwd = 2; 468 checkkwd = 2;
469 if ((t = readtoken()) != TESAC) { 469 if ((t = readtoken()) != TESAC) {
470 if (t != TENDCASE) { 470 if (t != TENDCASE) {
471 noalias = 0; 471 noalias = 0;
472 synexpect(TENDCASE, 0); 472 synexpect(TENDCASE, 0);
473 } else { 473 } else {
474 noalias = 1; 474 noalias = 1;
475 checkkwd = 2; 475 checkkwd = 2;
476 readtoken(); 476 readtoken();
477 } 477 }
478 } 478 }
479 cpp = &cp->nclist.next; 479 cpp = &cp->nclist.next;
480 } 480 }
481 noalias = 0; 481 noalias = 0;
482 *cpp = NULL; 482 *cpp = NULL;
483 checkkwd = 1; 483 checkkwd = 1;
484 break; 484 break;
485 case TLP: 485 case TLP:
486 n1 = stalloc(sizeof(struct nredir)); 486 n1 = stalloc(sizeof(struct nredir));
487 n1->type = NSUBSHELL; 487 n1->type = NSUBSHELL;
488 n1->nredir.n = list(0, 0); 488 n1->nredir.n = list(0, 0);
489 n1->nredir.redirect = NULL; 489 n1->nredir.redirect = NULL;
490 if (readtoken() != TRP) 490 if (readtoken() != TRP)
491 synexpect(TRP, 0); 491 synexpect(TRP, 0);
492 checkkwd = 1; 492 checkkwd = 1;
493 break; 493 break;
494 case TBEGIN: 494 case TBEGIN:
495 n1 = list(0, 0); 495 n1 = list(0, 0);
496 if (readtoken() != TEND) 496 if (readtoken() != TEND)
497 synexpect(TEND, 0); 497 synexpect(TEND, 0);
498 checkkwd = 1; 498 checkkwd = 1;
499 break; 499 break;
500 /* Handle an empty command like other simple commands. */ 500 /* Handle an empty command like other simple commands. */
501 case TSEMI: 501 case TSEMI:
502 /* 502 /*
503 * An empty command before a ; doesn't make much sense, and 503 * An empty command before a ; doesn't make much sense, and
504 * should certainly be disallowed in the case of `if ;'. 504 * should certainly be disallowed in the case of `if ;'.
505 */ 505 */
506 if (!redir) 506 if (!redir)
507 synexpect(-1, 0); 507 synexpect(-1, 0);
508 case TAND: 508 case TAND:
509 case TOR: 509 case TOR:
510 case TNL: 510 case TNL:
511 case TEOF: 511 case TEOF:
512 case TWORD: 512 case TWORD:
513 case TRP: 513 case TRP:
514 tokpushback++; 514 tokpushback++;
515 n1 = simplecmd(rpp, redir); 515 n1 = simplecmd(rpp, redir);
516 goto checkneg; 516 goto checkneg;
517 case TENDCASE: 517 case TENDCASE:
518 if (redir) { 518 if (redir) {
519 tokpushback++; 519 tokpushback++;
520 goto checkneg; 520 goto checkneg;
521 } 521 }
522 /* FALLTHROUGH */ 522 /* FALLTHROUGH */
523 default: 523 default:
524 synexpect(-1, 0); 524 synexpect(-1, 0);
525 /* NOTREACHED */ 525 /* NOTREACHED */
526 } 526 }
527 527
528 /* Now check for redirection which may follow command */ 528 /* Now check for redirection which may follow command */
529 while (readtoken() == TREDIR) { 529 while (readtoken() == TREDIR) {
530 *rpp = n2 = redirnode; 530 *rpp = n2 = redirnode;
531 rpp = &n2->nfile.next; 531 rpp = &n2->nfile.next;
532 parsefname(); 532 parsefname();
533 } 533 }
534 tokpushback++; 534 tokpushback++;
535 *rpp = NULL; 535 *rpp = NULL;
536 if (redir) { 536 if (redir) {
537 if (n1->type != NSUBSHELL) { 537 if (n1->type != NSUBSHELL) {
538 n2 = stalloc(sizeof(struct nredir)); 538 n2 = stalloc(sizeof(struct nredir));
539 n2->type = NREDIR; 539 n2->type = NREDIR;
540 n2->nredir.n = n1; 540 n2->nredir.n = n1;
541 n1 = n2; 541 n1 = n2;
542 } 542 }
543 n1->nredir.redirect = redir; 543 n1->nredir.redirect = redir;
544 } 544 }
545 545
546checkneg: 546checkneg:
547 if (negate) { 547 if (negate) {
548 TRACE(("negate command\n")); 548 TRACE(("negate command\n"));
549 n2 = stalloc(sizeof(struct nnot)); 549 n2 = stalloc(sizeof(struct nnot));
550 n2->type = NNOT; 550 n2->type = NNOT;
551 n2->nnot.com = n1; 551 n2->nnot.com = n1;
552 return n2; 552 return n2;
553 } 553 }
554 else 554 else
555 return n1; 555 return n1;
556} 556}
557 557
558 558
559STATIC union node * 559STATIC union node *
560simplecmd(union node **rpp, union node *redir) 560simplecmd(union node **rpp, union node *redir)
561{ 561{
562 union node *args, **app; 562 union node *args, **app;
563 union node **orig_rpp = rpp; 
564 union node *n = NULL, *n2; 563 union node *n = NULL, *n2;
565 int negate = 0; 564 int negate = 0;
566 565
567 /* If we don't have any redirections already, then we must reset */ 566 /* If we don't have any redirections already, then we must reset */
568 /* rpp to be the address of the local redir variable. */ 567 /* rpp to be the address of the local redir variable. */
569 if (redir == 0) 568 if (redir == 0)
570 rpp = &redir; 569 rpp = &redir;
571 570
572 args = NULL; 571 args = NULL;
573 app = &args; 572 app = &args;
574 /* 
575 * We save the incoming value, because we need this for shell 
576 * functions. There can not be a redirect or an argument between 
577 * the function name and the open parenthesis. 
578 */ 
579 orig_rpp = rpp; 
580 573
581 while (readtoken() == TNOT) { 574 while (readtoken() == TNOT) {
582 TRACE(("simplcmd: TNOT recognized\n")); 575 TRACE(("simplcmd: TNOT recognized\n"));
583 negate = !negate; 576 negate = !negate;
584 } 577 }
585 tokpushback++; 578 tokpushback++;
586 579
587 for (;;) { 580 for (;;) {
588 if (readtoken() == TWORD) { 581 if (readtoken() == TWORD) {
589 n = stalloc(sizeof(struct narg)); 582 n = stalloc(sizeof(struct narg));
590 n->type = NARG; 583 n->type = NARG;
591 n->narg.text = wordtext; 584 n->narg.text = wordtext;
592 n->narg.backquote = backquotelist; 585 n->narg.backquote = backquotelist;
593 *app = n; 586 *app = n;
594 app = &n->narg.next; 587 app = &n->narg.next;
595 } else if (lasttoken == TREDIR) { 588 } else if (lasttoken == TREDIR) {
596 *rpp = n = redirnode; 589 *rpp = n = redirnode;
597 rpp = &n->nfile.next; 590 rpp = &n->nfile.next;
598 parsefname(); /* read name of redirection file */ 591 parsefname(); /* read name of redirection file */
599 } else if (lasttoken == TLP && app == &args->narg.next 592 } else if (lasttoken == TLP && app == &args->narg.next
600 && rpp == orig_rpp) { 593 && redir == 0) {
601 /* We have a function */ 594 /* We have a function */
602 if (readtoken() != TRP) 595 if (readtoken() != TRP)
603 synexpect(TRP, 0); 596 synexpect(TRP, 0);
604 funclinno = plinno; 597 funclinno = plinno;
605 rmescapes(n->narg.text); 598 rmescapes(n->narg.text);
606 if (!goodname(n->narg.text)) 599 if (!goodname(n->narg.text))
607 synerror("Bad function name"); 600 synerror("Bad function name");
608 n->type = NDEFUN; 601 n->type = NDEFUN;
609 n->narg.next = command(); 602 n->narg.next = command();
610 funclinno = 0; 603 funclinno = 0;
611 goto checkneg; 604 goto checkneg;
612 } else { 605 } else {
613 tokpushback++; 606 tokpushback++;
614 break; 607 break;
615 } 608 }
616 } 609 }
617 *app = NULL; 610 *app = NULL;
618 *rpp = NULL; 611 *rpp = NULL;
619 n = stalloc(sizeof(struct ncmd)); 612 n = stalloc(sizeof(struct ncmd));
620 n->type = NCMD; 613 n->type = NCMD;
621 n->ncmd.backgnd = 0; 614 n->ncmd.backgnd = 0;
622 n->ncmd.args = args; 615 n->ncmd.args = args;
623 n->ncmd.redirect = redir; 616 n->ncmd.redirect = redir;
624 617
625checkneg: 618checkneg:
626 if (negate) { 619 if (negate) {
627 TRACE(("negate simplecmd\n")); 620 TRACE(("negate simplecmd\n"));
628 n2 = stalloc(sizeof(struct nnot)); 621 n2 = stalloc(sizeof(struct nnot));
629 n2->type = NNOT; 622 n2->type = NNOT;
630 n2->nnot.com = n; 623 n2->nnot.com = n;
631 return n2; 624 return n2;
632 } 625 }
633 else 626 else
634 return n; 627 return n;
635} 628}
636 629
637STATIC union node * 630STATIC union node *
638makename(void) 631makename(void)
639{ 632{
640 union node *n; 633 union node *n;
641 634
642 n = stalloc(sizeof(struct narg)); 635 n = stalloc(sizeof(struct narg));
643 n->type = NARG; 636 n->type = NARG;
644 n->narg.next = NULL; 637 n->narg.next = NULL;
645 n->narg.text = wordtext; 638 n->narg.text = wordtext;
646 n->narg.backquote = backquotelist; 639 n->narg.backquote = backquotelist;
647 return n; 640 return n;
648} 641}
649 642
650void 643void
651fixredir(union node *n, const char *text, int err) 644fixredir(union node *n, const char *text, int err)
652{ 645{
653 TRACE(("Fix redir %s %d\n", text, err)); 646 TRACE(("Fix redir %s %d\n", text, err));
654 if (!err) 647 if (!err)
655 n->ndup.vname = NULL; 648 n->ndup.vname = NULL;
656 649
657 if (is_number(text)) 650 if (is_number(text))
658 n->ndup.dupfd = number(text); 651 n->ndup.dupfd = number(text);
659 else if (text[0] == '-' && text[1] == '\0') 652 else if (text[0] == '-' && text[1] == '\0')
660 n->ndup.dupfd = -1; 653 n->ndup.dupfd = -1;
661 else { 654 else {
662 655
663 if (err) 656 if (err)
664 synerror("Bad fd number"); 657 synerror("Bad fd number");
665 else 658 else
666 n->ndup.vname = makename(); 659 n->ndup.vname = makename();
667 } 660 }
668} 661}
669 662
670 663
671STATIC void 664STATIC void
672parsefname(void) 665parsefname(void)
673{ 666{
674 union node *n = redirnode; 667 union node *n = redirnode;
675 668
676 if (readtoken() != TWORD) 669 if (readtoken() != TWORD)
677 synexpect(-1, 0); 670 synexpect(-1, 0);
678 if (n->type == NHERE) { 671 if (n->type == NHERE) {
679 struct heredoc *here = heredoc; 672 struct heredoc *here = heredoc;
680 struct heredoc *p; 673 struct heredoc *p;
681 int i; 674 int i;
682 675
683 if (quoteflag == 0) 676 if (quoteflag == 0)
684 n->type = NXHERE; 677 n->type = NXHERE;
685 TRACE(("Here document %d\n", n->type)); 678 TRACE(("Here document %d\n", n->type));
686 if (here->striptabs) { 679 if (here->striptabs) {
687 while (*wordtext == '\t') 680 while (*wordtext == '\t')
688 wordtext++; 681 wordtext++;
689 } 682 }
690 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 683 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
691 synerror("Illegal eof marker for << redirection"); 684 synerror("Illegal eof marker for << redirection");
692 rmescapes(wordtext); 685 rmescapes(wordtext);
693 here->eofmark = wordtext; 686 here->eofmark = wordtext;
694 here->next = NULL; 687 here->next = NULL;
695 if (heredoclist == NULL) 688 if (heredoclist == NULL)
696 heredoclist = here; 689 heredoclist = here;
697 else { 690 else {
698 for (p = heredoclist ; p->next ; p = p->next) 691 for (p = heredoclist ; p->next ; p = p->next)
699 continue; 692 continue;
700 p->next = here; 693 p->next = here;
701 } 694 }
702 } else if (n->type == NTOFD || n->type == NFROMFD) { 695 } else if (n->type == NTOFD || n->type == NFROMFD) {
703 fixredir(n, wordtext, 0); 696 fixredir(n, wordtext, 0);
704 } else { 697 } else {
705 n->nfile.fname = makename(); 698 n->nfile.fname = makename();
706 } 699 }
707} 700}
708 701
709 702
710/* 703/*
711 * Input any here documents. 704 * Input any here documents.
712 */ 705 */
713 706
714STATIC void 707STATIC void
715parseheredoc(void) 708parseheredoc(void)
716{ 709{
717 struct heredoc *here; 710 struct heredoc *here;
718 union node *n; 711 union node *n;
719 712
720 while (heredoclist) { 713 while (heredoclist) {
721 int c; 714 int c;
722 715
723 here = heredoclist; 716 here = heredoclist;
724 heredoclist = here->next; 717 heredoclist = here->next;
725 if (needprompt) { 718 if (needprompt) {
726 setprompt(2); 719 setprompt(2);
727 needprompt = 0; 720 needprompt = 0;
728 } 721 }
729 if ((c = pgetc()) == PEOF) { 722 if ((c = pgetc()) == PEOF) {
730 synerror(EOFhere); 723 synerror(EOFhere);
731 /* NOTREACHED */ 724 /* NOTREACHED */
732 } 725 }
733 readtoken1(c, here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 726 readtoken1(c, here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
734 here->eofmark, here->striptabs); 727 here->eofmark, here->striptabs);
735 n = stalloc(sizeof(struct narg)); 728 n = stalloc(sizeof(struct narg));
736 n->narg.type = NARG; 729 n->narg.type = NARG;
737 n->narg.next = NULL; 730 n->narg.next = NULL;
738 n->narg.text = wordtext; 731 n->narg.text = wordtext;
739 n->narg.backquote = backquotelist; 732 n->narg.backquote = backquotelist;
740 here->here->nhere.doc = n; 733 here->here->nhere.doc = n;
741 } 734 }
742} 735}
743 736
744STATIC int 737STATIC int
745peektoken(void) 738peektoken(void)
746{ 739{
747 int t; 740 int t;
748 741
749 t = readtoken(); 742 t = readtoken();
750 tokpushback++; 743 tokpushback++;
751 return (t); 744 return (t);
752} 745}
753 746
754STATIC int 747STATIC int
755readtoken(void) 748readtoken(void)
756{ 749{
757 int t; 750 int t;
758 int savecheckkwd = checkkwd; 751 int savecheckkwd = checkkwd;
759#ifdef DEBUG 752#ifdef DEBUG
760 int alreadyseen = tokpushback; 753 int alreadyseen = tokpushback;
761#endif 754#endif
762 struct alias *ap; 755 struct alias *ap;
763 756
764 top: 757 top:
765 t = xxreadtoken(); 758 t = xxreadtoken();
766 759
767 if (checkkwd) { 760 if (checkkwd) {
768 /* 761 /*
769 * eat newlines 762 * eat newlines
770 */ 763 */
771 if (checkkwd == 2) { 764 if (checkkwd == 2) {
772 checkkwd = 0; 765 checkkwd = 0;
773 while (t == TNL) { 766 while (t == TNL) {
774 parseheredoc(); 767 parseheredoc();
775 t = xxreadtoken(); 768 t = xxreadtoken();
776 } 769 }
777 } else 770 } else
778 checkkwd = 0; 771 checkkwd = 0;
779 /* 772 /*
780 * check for keywords and aliases 773 * check for keywords and aliases
781 */ 774 */
782 if (t == TWORD && !quoteflag) { 775 if (t == TWORD && !quoteflag) {
783 const char *const *pp; 776 const char *const *pp;
784 777
785 for (pp = parsekwd; *pp; pp++) { 778 for (pp = parsekwd; *pp; pp++) {
786 if (**pp == *wordtext && equal(*pp, wordtext)) { 779 if (**pp == *wordtext && equal(*pp, wordtext)) {
787 lasttoken = t = pp - 780 lasttoken = t = pp -
788 parsekwd + KWDOFFSET; 781 parsekwd + KWDOFFSET;
789 TRACE(("keyword %s recognized\n", tokname[t])); 782 TRACE(("keyword %s recognized\n", tokname[t]));
790 goto out; 783 goto out;
791 } 784 }
792 } 785 }
793 if (!noalias && 786 if (!noalias &&
794 (ap = lookupalias(wordtext, 1)) != NULL) { 787 (ap = lookupalias(wordtext, 1)) != NULL) {
795 pushstring(ap->val, strlen(ap->val), ap); 788 pushstring(ap->val, strlen(ap->val), ap);
796 checkkwd = savecheckkwd; 789 checkkwd = savecheckkwd;
797 goto top; 790 goto top;
798 } 791 }
799 } 792 }
800out: 793out:
801 checkkwd = (t == TNOT) ? savecheckkwd : 0; 794 checkkwd = (t == TNOT) ? savecheckkwd : 0;
802 } 795 }
803 TRACE(("%stoken %s %s\n", alreadyseen ? "reread " : "", tokname[t], t == TWORD ? wordtext : "")); 796 TRACE(("%stoken %s %s\n", alreadyseen ? "reread " : "", tokname[t], t == TWORD ? wordtext : ""));
804 return (t); 797 return (t);
805} 798}
806 799
807 800
808/* 801/*
809 * Read the next input token. 802 * Read the next input token.
810 * If the token is a word, we set backquotelist to the list of cmds in 803 * If the token is a word, we set backquotelist to the list of cmds in
811 * backquotes. We set quoteflag to true if any part of the word was 804 * backquotes. We set quoteflag to true if any part of the word was
812 * quoted. 805 * quoted.
813 * If the token is TREDIR, then we set redirnode to a structure containing 806 * If the token is TREDIR, then we set redirnode to a structure containing
814 * the redirection. 807 * the redirection.
815 * In all cases, the variable startlinno is set to the number of the line 808 * In all cases, the variable startlinno is set to the number of the line
816 * on which the token starts. 809 * on which the token starts.
817 * 810 *
818 * [Change comment: here documents and internal procedures] 811 * [Change comment: here documents and internal procedures]
819 * [Readtoken shouldn't have any arguments. Perhaps we should make the 812 * [Readtoken shouldn't have any arguments. Perhaps we should make the
820 * word parsing code into a separate routine. In this case, readtoken 813 * word parsing code into a separate routine. In this case, readtoken
821 * doesn't need to have any internal procedures, but parseword does. 814 * doesn't need to have any internal procedures, but parseword does.
822 * We could also make parseoperator in essence the main routine, and 815 * We could also make parseoperator in essence the main routine, and
823 * have parseword (readtoken1?) handle both words and redirection.] 816 * have parseword (readtoken1?) handle both words and redirection.]
824 */ 817 */
825 818
826#define RETURN(token) return lasttoken = token 819#define RETURN(token) return lasttoken = token
827 820
828STATIC int 821STATIC int
829xxreadtoken(void) 822xxreadtoken(void)
830{ 823{
831 int c; 824 int c;
832 825
833 if (tokpushback) { 826 if (tokpushback) {
834 tokpushback = 0; 827 tokpushback = 0;
835 return lasttoken; 828 return lasttoken;
836 } 829 }
837 if (needprompt) { 830 if (needprompt) {
838 setprompt(2); 831 setprompt(2);
839 needprompt = 0; 832 needprompt = 0;
840 } 833 }
841 startlinno = plinno; 834 startlinno = plinno;
842 for (;;) { /* until token or start of word found */ 835 for (;;) { /* until token or start of word found */
843 c = pgetc_macro(); 836 c = pgetc_macro();
844 switch (c) { 837 switch (c) {
845 case ' ': case '\t': 838 case ' ': case '\t':
846 continue; 839 continue;
847 case '#': 840 case '#':
848 while ((c = pgetc()) != '\n' && c != PEOF) 841 while ((c = pgetc()) != '\n' && c != PEOF)
849 continue; 842 continue;
850 pungetc(); 843 pungetc();
851 continue; 844 continue;
852 845
853 case '\n': 846 case '\n':
854 plinno++; 847 plinno++;
855 needprompt = doprompt; 848 needprompt = doprompt;
856 RETURN(TNL); 849 RETURN(TNL);
857 case PEOF: 850 case PEOF:
858 RETURN(TEOF); 851 RETURN(TEOF);
859 852
860 case '&': 853 case '&':
861 if (pgetc() == '&') 854 if (pgetc() == '&')
862 RETURN(TAND); 855 RETURN(TAND);
863 pungetc(); 856 pungetc();
864 RETURN(TBACKGND); 857 RETURN(TBACKGND);
865 case '|': 858 case '|':
866 if (pgetc() == '|') 859 if (pgetc() == '|')
867 RETURN(TOR); 860 RETURN(TOR);
868 pungetc(); 861 pungetc();
869 RETURN(TPIPE); 862 RETURN(TPIPE);
870 case ';': 863 case ';':
871 if (pgetc() == ';') 864 if (pgetc() == ';')
872 RETURN(TENDCASE); 865 RETURN(TENDCASE);
873 pungetc(); 866 pungetc();
874 RETURN(TSEMI); 867 RETURN(TSEMI);
875 case '(': 868 case '(':
876 RETURN(TLP); 869 RETURN(TLP);
877 case ')': 870 case ')':
878 RETURN(TRP); 871 RETURN(TRP);
879 872
880 case '\\': 873 case '\\':
881 switch (pgetc()) { 874 switch (pgetc()) {
882 case '\n': 875 case '\n':
883 startlinno = ++plinno; 876 startlinno = ++plinno;
884 if (doprompt) 877 if (doprompt)
885 setprompt(2); 878 setprompt(2);
886 else 879 else
887 setprompt(0); 880 setprompt(0);
888 continue; 881 continue;
889 case PEOF: 882 case PEOF:
890 RETURN(TEOF); 883 RETURN(TEOF);
891 default: 884 default:
892 pungetc(); 885 pungetc();
893 break; 886 break;
894 } 887 }
895 /* FALLTHROUGH */ 888 /* FALLTHROUGH */
896 default: 889 default:
897 return readtoken1(c, BASESYNTAX, NULL, 0); 890 return readtoken1(c, BASESYNTAX, NULL, 0);
898 } 891 }
899 } 892 }
900#undef RETURN 893#undef RETURN
901} 894}
902 895
903 896
904 897
905/* 898/*
906 * If eofmark is NULL, read a word or a redirection symbol. If eofmark 899 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
907 * is not NULL, read a here document. In the latter case, eofmark is the 900 * is not NULL, read a here document. In the latter case, eofmark is the
908 * word which marks the end of the document and striptabs is true if 901 * word which marks the end of the document and striptabs is true if
909 * leading tabs should be stripped from the document. The argument firstc 902 * leading tabs should be stripped from the document. The argument firstc
910 * is the first character of the input token or document. 903 * is the first character of the input token or document.
911 * 904 *
912 * Because C does not have internal subroutines, I have simulated them 905 * Because C does not have internal subroutines, I have simulated them
913 * using goto's to implement the subroutine linkage. The following macros 906 * using goto's to implement the subroutine linkage. The following macros
914 * will run code that appears at the end of readtoken1. 907 * will run code that appears at the end of readtoken1.
915 */ 908 */
916 909
917/* 910/*
918 * We used to remember only the current syntax, variable nesting level, 911 * We used to remember only the current syntax, variable nesting level,
919 * double quote state for each var nesting level, and arith nesting 912 * double quote state for each var nesting level, and arith nesting
920 * level (unrelated to var nesting) and one prev syntax when in arith 913 * level (unrelated to var nesting) and one prev syntax when in arith
921 * syntax. This worked for simple cases, but can't handle arith inside 914 * syntax. This worked for simple cases, but can't handle arith inside
922 * var expansion inside arith inside var with some quoted and some not. 915 * var expansion inside arith inside var with some quoted and some not.
923 * 916 *
924 * Inspired by FreeBSD's implementation (though it was the obvious way) 917 * Inspired by FreeBSD's implementation (though it was the obvious way)
925 * though implemented differently, we now have a stack that keeps track 918 * though implemented differently, we now have a stack that keeps track
926 * of what we are doing now, and what we were doing previously. 919 * of what we are doing now, and what we were doing previously.
927 * Every time something changes, which will eventually end and should 920 * Every time something changes, which will eventually end and should
928 * revert to the previous state, we push this stack, and then pop it 921 * revert to the previous state, we push this stack, and then pop it
929 * again later (that is every ${} with an operator (to parse the word 922 * again later (that is every ${} with an operator (to parse the word
930 * or pattern that follows) ${x} and $x are too simple to need it) 923 * or pattern that follows) ${x} and $x are too simple to need it)
931 * $(( )) $( ) and "...". Always. Really, always! 924 * $(( )) $( ) and "...". Always. Really, always!
932 * 925 *
933 * The stack is implemented as one static (on the C stack) base block 926 * The stack is implemented as one static (on the C stack) base block
934 * containing LEVELS_PER_BLOCK (8) stack entries, which should be 927 * containing LEVELS_PER_BLOCK (8) stack entries, which should be
935 * enough for the vast majority of cases. For torture tests, we 928 * enough for the vast majority of cases. For torture tests, we
936 * malloc more blocks as needed. All accesses through the inline 929 * malloc more blocks as needed. All accesses through the inline
937 * functions below. 930 * functions below.
938 */ 931 */
939 932
940/* 933/*
941 * varnest & arinest will typically be 0 or 1 934 * varnest & arinest will typically be 0 or 1
942 * (varnest can increment in usages like ${x=${y}} but probably 935 * (varnest can increment in usages like ${x=${y}} but probably
943 * does not really need to) 936 * does not really need to)
944 * parenlevel allows balancing parens inside a $(( )), it is reset 937 * parenlevel allows balancing parens inside a $(( )), it is reset
945 * at each new nesting level ( $(( ( x + 3 ${unset-)} )) does not work. 938 * at each new nesting level ( $(( ( x + 3 ${unset-)} )) does not work.
946 * quoted is special - we need to know 2 things ... are we inside "..." 939 * quoted is special - we need to know 2 things ... are we inside "..."
947 * (even if inherited from some previous nesting level) and was there 940 * (even if inherited from some previous nesting level) and was there
948 * an opening '"' at this level (so the next will be closing). 941 * an opening '"' at this level (so the next will be closing).
949 * "..." can span nesting levels, but cannot be opened in one and 942 * "..." can span nesting levels, but cannot be opened in one and
950 * closed in a different one. 943 * closed in a different one.
951 * To handle this, "quoted" has two fields, the bottom 4 (really 2) 944 * To handle this, "quoted" has two fields, the bottom 4 (really 2)
952 * bits are 0, 1, or 2, for un, single, and double quoted (single quoted 945 * bits are 0, 1, or 2, for un, single, and double quoted (single quoted
953 * is really so special that this setting is not very important) 946 * is really so special that this setting is not very important)
954 * and 0x10 that indicates that an opening quote has been seen. 947 * and 0x10 that indicates that an opening quote has been seen.
955 * The bottom 4 bits are inherited, the 0x10 bit is not. 948 * The bottom 4 bits are inherited, the 0x10 bit is not.
956 */ 949 */
957struct tokenstate { 950struct tokenstate {
958 const char *ts_syntax; 951 const char *ts_syntax;
959 unsigned short ts_parenlevel; /* counters */ 952 unsigned short ts_parenlevel; /* counters */
960 unsigned short ts_varnest; /* 64000 levels should be enough! */ 953 unsigned short ts_varnest; /* 64000 levels should be enough! */
961 unsigned short ts_arinest; 954 unsigned short ts_arinest;
962 unsigned short ts_quoted; /* 1 -> single, 2 -> double */ 955 unsigned short ts_quoted; /* 1 -> single, 2 -> double */
963}; 956};
964 957
965#define NQ 0x00 /* Unquoted */ 958#define NQ 0x00 /* Unquoted */
966#define SQ 0x01 /* Single Quotes */ 959#define SQ 0x01 /* Single Quotes */
967#define DQ 0x02 /* Double Quotes (or equivalent) */ 960#define DQ 0x02 /* Double Quotes (or equivalent) */
968#define QF 0x0F /* Mask to extract previous values */ 961#define QF 0x0F /* Mask to extract previous values */
969#define QS 0x10 /* Quoting started at this level in stack */ 962#define QS 0x10 /* Quoting started at this level in stack */
970 963
971#define LEVELS_PER_BLOCK 8 964#define LEVELS_PER_BLOCK 8
972#define VSS struct statestack 965#define VSS struct statestack
973 966
974struct statestack { 967struct statestack {
975 VSS *prev; /* previous block in list */ 968 VSS *prev; /* previous block in list */
976 int cur; /* which of our tokenstates is current */ 969 int cur; /* which of our tokenstates is current */
977 struct tokenstate tokenstate[LEVELS_PER_BLOCK]; 970 struct tokenstate tokenstate[LEVELS_PER_BLOCK];
978}; 971};
979 972
980static inline struct tokenstate * 973static inline struct tokenstate *
981currentstate(VSS *stack) 974currentstate(VSS *stack)
982{ 975{
983 return &stack->tokenstate[stack->cur]; 976 return &stack->tokenstate[stack->cur];
984} 977}
985 978
986static inline struct tokenstate * 979static inline struct tokenstate *
987prevstate(VSS *stack) 980prevstate(VSS *stack)
988{ 981{
989 if (stack->cur != 0) 982 if (stack->cur != 0)
990 return &stack->tokenstate[stack->cur - 1]; 983 return &stack->tokenstate[stack->cur - 1];
991 if (stack->prev == NULL) /* cannot drop below base */ 984 if (stack->prev == NULL) /* cannot drop below base */
992 return &stack->tokenstate[0]; 985 return &stack->tokenstate[0];
993 return &stack->prev->tokenstate[LEVELS_PER_BLOCK - 1]; 986 return &stack->prev->tokenstate[LEVELS_PER_BLOCK - 1];
994} 987}
995 988
996static inline VSS * 989static inline VSS *
997bump_state_level(VSS *stack) 990bump_state_level(VSS *stack)
998{ 991{
999 struct tokenstate *os, *ts; 992 struct tokenstate *os, *ts;
1000 993
1001 os = currentstate(stack); 994 os = currentstate(stack);
1002 995
1003 if (++stack->cur >= LEVELS_PER_BLOCK) { 996 if (++stack->cur >= LEVELS_PER_BLOCK) {
1004 VSS *ss; 997 VSS *ss;
1005 998
1006 ss = (VSS *)ckmalloc(sizeof (struct statestack)); 999 ss = (VSS *)ckmalloc(sizeof (struct statestack));
1007 ss->cur = 0; 1000 ss->cur = 0;
1008 ss->prev = stack; 1001 ss->prev = stack;
1009 stack = ss; 1002 stack = ss;
1010 } 1003 }
1011 1004
1012 ts = currentstate(stack); 1005 ts = currentstate(stack);
1013 1006
1014 ts->ts_parenlevel = 0; /* parens inside never match outside */ 1007 ts->ts_parenlevel = 0; /* parens inside never match outside */
1015 1008
1016 ts->ts_quoted = os->ts_quoted & QF; /* these are default settings */ 1009 ts->ts_quoted = os->ts_quoted & QF; /* these are default settings */
1017 ts->ts_varnest = os->ts_varnest; 1010 ts->ts_varnest = os->ts_varnest;
1018 ts->ts_arinest = os->ts_arinest; /* when appropriate */ 1011 ts->ts_arinest = os->ts_arinest; /* when appropriate */
1019 ts->ts_syntax = os->ts_syntax; /* they will be altered */ 1012 ts->ts_syntax = os->ts_syntax; /* they will be altered */
1020 1013
1021 return stack; 1014 return stack;
1022} 1015}
1023 1016
1024static inline VSS * 1017static inline VSS *
1025drop_state_level(VSS *stack) 1018drop_state_level(VSS *stack)
1026{ 1019{
1027 if (stack->cur == 0) { 1020 if (stack->cur == 0) {
1028 VSS *ss; 1021 VSS *ss;
1029 1022
1030 ss = stack; 1023 ss = stack;
1031 stack = ss->prev; 1024 stack = ss->prev;
1032 if (stack == NULL) 1025 if (stack == NULL)
1033 return ss; 1026 return ss;
1034 ckfree(ss); 1027 ckfree(ss);
1035 } 1028 }
1036 --stack->cur; 1029 --stack->cur;
1037 return stack; 1030 return stack;
1038} 1031}
1039 1032
1040static inline void 1033static inline void
1041cleanup_state_stack(VSS *stack) 1034cleanup_state_stack(VSS *stack)
1042{ 1035{
1043 while (stack->prev != NULL) { 1036 while (stack->prev != NULL) {
1044 stack->cur = 0; 1037 stack->cur = 0;
1045 stack = drop_state_level(stack); 1038 stack = drop_state_level(stack);
1046 } 1039 }
1047} 1040}
1048 1041
1049#define CHECKEND() {goto checkend; checkend_return:;} 1042#define CHECKEND() {goto checkend; checkend_return:;}
1050#define PARSEREDIR() {goto parseredir; parseredir_return:;} 1043#define PARSEREDIR() {goto parseredir; parseredir_return:;}
1051#define PARSESUB() {goto parsesub; parsesub_return:;} 1044#define PARSESUB() {goto parsesub; parsesub_return:;}
1052#define PARSEARITH() {goto parsearith; parsearith_return:;} 1045#define PARSEARITH() {goto parsearith; parsearith_return:;}
1053 1046
1054/* 1047/*
1055 * The following macros all assume the existance of a local var "stack" 1048 * The following macros all assume the existance of a local var "stack"
1056 * which contains a pointer to the current struct stackstate 1049 * which contains a pointer to the current struct stackstate
1057 */ 1050 */
1058 1051
1059/* 1052/*
1060 * These are macros rather than inline funcs to avoid code churn as much 1053 * These are macros rather than inline funcs to avoid code churn as much
1061 * as possible - they replace macros of the same name used previously. 1054 * as possible - they replace macros of the same name used previously.
1062 */ 1055 */
1063#define ISDBLQUOTE() (currentstate(stack)->ts_quoted & QS) 1056#define ISDBLQUOTE() (currentstate(stack)->ts_quoted & QS)
1064#define SETDBLQUOTE() (currentstate(stack)->ts_quoted = QS | DQ) 1057#define SETDBLQUOTE() (currentstate(stack)->ts_quoted = QS | DQ)
1065#define CLRDBLQUOTE() (currentstate(stack)->ts_quoted = \ 1058#define CLRDBLQUOTE() (currentstate(stack)->ts_quoted = \
1066 stack->cur != 0 || stack->prev ? \ 1059 stack->cur != 0 || stack->prev ? \
1067 prevstate(stack)->ts_quoted & QF : 0) 1060 prevstate(stack)->ts_quoted & QF : 0)
1068 1061
1069/* 1062/*
1070 * This set are just to avoid excess typing and line lengths... 1063 * This set are just to avoid excess typing and line lengths...
1071 * The ones that "look like" var names must be implemented to be lvalues 1064 * The ones that "look like" var names must be implemented to be lvalues
1072 */ 1065 */
1073#define syntax (currentstate(stack)->ts_syntax) 1066#define syntax (currentstate(stack)->ts_syntax)
1074#define parenlevel (currentstate(stack)->ts_parenlevel) 1067#define parenlevel (currentstate(stack)->ts_parenlevel)
1075#define varnest (currentstate(stack)->ts_varnest) 1068#define varnest (currentstate(stack)->ts_varnest)
1076#define arinest (currentstate(stack)->ts_arinest) 1069#define arinest (currentstate(stack)->ts_arinest)
1077#define quoted (currentstate(stack)->ts_quoted) 1070#define quoted (currentstate(stack)->ts_quoted)
1078#define TS_PUSH() (stack = bump_state_level(stack)) 1071#define TS_PUSH() (stack = bump_state_level(stack))
1079#define TS_POP() (stack = drop_state_level(stack)) 1072#define TS_POP() (stack = drop_state_level(stack))
1080 1073
1081/* 1074/*
1082 * Called to parse command substitutions. oldstyle is true if the command 1075 * Called to parse command substitutions. oldstyle is true if the command
1083 * is enclosed inside `` (otherwise it was enclosed in "$( )") 1076 * is enclosed inside `` (otherwise it was enclosed in "$( )")
1084 * 1077 *
1085 * Internally nlpp is a pointer to the head of the linked 1078 * Internally nlpp is a pointer to the head of the linked
1086 * list of commands (passed by reference), and savelen is the number of 1079 * list of commands (passed by reference), and savelen is the number of
1087 * characters on the top of the stack which must be preserved. 1080 * characters on the top of the stack which must be preserved.
1088 */ 1081 */
1089static char * 1082static char *
1090parsebackq(VSS *const stack, char * const in, 1083parsebackq(VSS *const stack, char * const in,
1091 struct nodelist **const pbqlist, const int oldstyle) 1084 struct nodelist **const pbqlist, const int oldstyle)
1092{ 1085{
1093 struct nodelist **nlpp; 1086 struct nodelist **nlpp;
1094 const int savepbq = parsebackquote; 1087 const int savepbq = parsebackquote;
1095 union node *n; 1088 union node *n;
1096 char *out; 1089 char *out;
1097 char *str = NULL; 1090 char *str = NULL;
1098 char *volatile sstr = str; 1091 char *volatile sstr = str;
1099 struct jmploc jmploc; 1092 struct jmploc jmploc;
1100 struct jmploc *const savehandler = handler; 1093 struct jmploc *const savehandler = handler;
1101 const int savelen = in - stackblock(); 1094 const int savelen = in - stackblock();
1102 int saveprompt; 1095 int saveprompt;
1103 1096
1104 if (setjmp(jmploc.loc)) { 1097 if (setjmp(jmploc.loc)) {
1105 if (sstr) 1098 if (sstr)
1106 ckfree(__UNVOLATILE(sstr)); 1099 ckfree(__UNVOLATILE(sstr));
1107 cleanup_state_stack(stack); 1100 cleanup_state_stack(stack);
1108 parsebackquote = 0; 1101 parsebackquote = 0;
1109 handler = savehandler; 1102 handler = savehandler;
1110 longjmp(handler->loc, 1); 1103 longjmp(handler->loc, 1);
1111 } 1104 }
1112 INTOFF; 1105 INTOFF;
1113 sstr = str = NULL; 1106 sstr = str = NULL;
1114 if (savelen > 0) { 1107 if (savelen > 0) {
1115 sstr = str = ckmalloc(savelen); 1108 sstr = str = ckmalloc(savelen);
1116 memcpy(str, stackblock(), savelen); 1109 memcpy(str, stackblock(), savelen);
1117 } 1110 }
1118 handler = &jmploc; 1111 handler = &jmploc;
1119 INTON; 1112 INTON;
1120 if (oldstyle) { 1113 if (oldstyle) {
1121 /* We must read until the closing backquote, giving special 1114 /* We must read until the closing backquote, giving special
1122 treatment to some slashes, and then push the string and 1115 treatment to some slashes, and then push the string and
1123 reread it as input, interpreting it normally. */ 1116 reread it as input, interpreting it normally. */
1124 int pc; 1117 int pc;
1125 int psavelen; 1118 int psavelen;
1126 char *pstr; 1119 char *pstr;
1127 1120
1128 /* 1121 /*
1129 * Because the entire `...` is read here, we don't 1122 * Because the entire `...` is read here, we don't
1130 * need to bother the state stack. That will be used 1123 * need to bother the state stack. That will be used
1131 * (as appropriate) when the processed string is re-read. 1124 * (as appropriate) when the processed string is re-read.
1132 */ 1125 */
1133 STARTSTACKSTR(out); 1126 STARTSTACKSTR(out);
1134 for (;;) { 1127 for (;;) {
1135 if (needprompt) { 1128 if (needprompt) {
1136 setprompt(2); 1129 setprompt(2);
1137 needprompt = 0; 1130 needprompt = 0;
1138 } 1131 }
1139 switch (pc = pgetc()) { 1132 switch (pc = pgetc()) {
1140 case '`': 1133 case '`':
1141 goto done; 1134 goto done;
1142 1135
1143 case '\\': 1136 case '\\':
1144 if ((pc = pgetc()) == '\n') { 1137 if ((pc = pgetc()) == '\n') {
1145 plinno++; 1138 plinno++;
1146 if (doprompt) 1139 if (doprompt)
1147 setprompt(2); 1140 setprompt(2);
1148 else 1141 else
1149 setprompt(0); 1142 setprompt(0);
1150 /* 1143 /*
1151 * If eating a newline, avoid putting 1144 * If eating a newline, avoid putting
1152 * the newline into the new character 1145 * the newline into the new character
1153 * stream (via the STPUTC after the 1146 * stream (via the STPUTC after the
1154 * switch). 1147 * switch).
1155 */ 1148 */
1156 continue; 1149 continue;
1157 } 1150 }
1158 if (pc != '\\' && pc != '`' && pc != '$' 1151 if (pc != '\\' && pc != '`' && pc != '$'
1159 && (!ISDBLQUOTE() || pc != '"')) 1152 && (!ISDBLQUOTE() || pc != '"'))
1160 STPUTC('\\', out); 1153 STPUTC('\\', out);
1161 break; 1154 break;
1162 1155
1163 case '\n': 1156 case '\n':
1164 plinno++; 1157 plinno++;
1165 needprompt = doprompt; 1158 needprompt = doprompt;
1166 break; 1159 break;
1167 1160
1168 case PEOF: 1161 case PEOF:
1169 startlinno = plinno; 1162 startlinno = plinno;
1170 synerror("EOF in backquote substitution"); 1163 synerror("EOF in backquote substitution");
1171 break; 1164 break;
1172 1165
1173 default: 1166 default:
1174 break; 1167 break;
1175 } 1168 }
1176 STPUTC(pc, out); 1169 STPUTC(pc, out);
1177 } 1170 }
1178done: 1171done:
1179 STPUTC('\0', out); 1172 STPUTC('\0', out);
1180 psavelen = out - stackblock(); 1173 psavelen = out - stackblock();
1181 if (psavelen > 0) { 1174 if (psavelen > 0) {
1182 pstr = grabstackstr(out); 1175 pstr = grabstackstr(out);
1183 setinputstring(pstr, 1); 1176 setinputstring(pstr, 1);
1184 } 1177 }
1185 } 1178 }
1186 nlpp = pbqlist; 1179 nlpp = pbqlist;
1187 while (*nlpp) 1180 while (*nlpp)
1188 nlpp = &(*nlpp)->next; 1181 nlpp = &(*nlpp)->next;
1189 *nlpp = stalloc(sizeof(struct nodelist)); 1182 *nlpp = stalloc(sizeof(struct nodelist));
1190 (*nlpp)->next = NULL; 1183 (*nlpp)->next = NULL;
1191 parsebackquote = oldstyle; 1184 parsebackquote = oldstyle;
1192 1185
1193 if (oldstyle) { 1186 if (oldstyle) {
1194 saveprompt = doprompt; 1187 saveprompt = doprompt;
1195 doprompt = 0; 1188 doprompt = 0;
1196 } else 1189 } else
1197 saveprompt = 0; 1190 saveprompt = 0;
1198 1191
1199 n = list(0, oldstyle); 1192 n = list(0, oldstyle);
1200 1193
1201 if (oldstyle) 1194 if (oldstyle)
1202 doprompt = saveprompt; 1195 doprompt = saveprompt;
1203 else { 1196 else {
1204 if (readtoken() != TRP) { 1197 if (readtoken() != TRP) {
1205 cleanup_state_stack(stack); 1198 cleanup_state_stack(stack);
1206 synexpect(TRP, 0); 1199 synexpect(TRP, 0);
1207 } 1200 }
1208 } 1201 }
1209 1202
1210 (*nlpp)->n = n; 1203 (*nlpp)->n = n;
1211 if (oldstyle) { 1204 if (oldstyle) {
1212 /* 1205 /*
1213 * Start reading from old file again, ignoring any pushed back 1206 * Start reading from old file again, ignoring any pushed back
1214 * tokens left from the backquote parsing 1207 * tokens left from the backquote parsing
1215 */ 1208 */
1216 popfile(); 1209 popfile();
1217 tokpushback = 0; 1210 tokpushback = 0;
1218 } 1211 }
1219 1212
1220 while (stackblocksize() <= savelen) 1213 while (stackblocksize() <= savelen)
1221 growstackblock(); 1214 growstackblock();
1222 STARTSTACKSTR(out); 1215 STARTSTACKSTR(out);
1223 if (str) { 1216 if (str) {
1224 memcpy(out, str, savelen); 1217 memcpy(out, str, savelen);
1225 STADJUST(savelen, out); 1218 STADJUST(savelen, out);
1226 INTOFF; 1219 INTOFF;
1227 ckfree(str); 1220 ckfree(str);
1228 sstr = str = NULL; 1221 sstr = str = NULL;
1229 INTON; 1222 INTON;
1230 } 1223 }
1231 parsebackquote = savepbq; 1224 parsebackquote = savepbq;
1232 handler = savehandler; 1225 handler = savehandler;
1233 if (arinest || ISDBLQUOTE()) 1226 if (arinest || ISDBLQUOTE())
1234 USTPUTC(CTLBACKQ | CTLQUOTE, out); 1227 USTPUTC(CTLBACKQ | CTLQUOTE, out);
1235 else 1228 else
1236 USTPUTC(CTLBACKQ, out); 1229 USTPUTC(CTLBACKQ, out);
1237 1230
1238 return out; 1231 return out;
1239} 1232}
1240 1233
1241STATIC int 1234STATIC int
1242readtoken1(int firstc, char const *syn, char *eofmark, int striptabs) 1235readtoken1(int firstc, char const *syn, char *eofmark, int striptabs)
1243{ 1236{
1244 int c = firstc; 1237 int c = firstc;
1245 char * out; 1238 char * out;
1246 int len; 1239 int len;
1247 char line[EOFMARKLEN + 1]; 1240 char line[EOFMARKLEN + 1];
1248 struct nodelist *bqlist; 1241 struct nodelist *bqlist;
1249 int quotef; 1242 int quotef;
1250 VSS static_stack; 1243 VSS static_stack;
1251 VSS *stack = &static_stack; 1244 VSS *stack = &static_stack;
1252 1245
1253 stack->prev = NULL; 1246 stack->prev = NULL;
1254 stack->cur = 0; 1247 stack->cur = 0;
1255 1248
1256 syntax = syn; 1249 syntax = syn;
1257 1250
1258 startlinno = plinno; 1251 startlinno = plinno;
1259 varnest = 0; 1252 varnest = 0;
1260 quoted = 0; 1253 quoted = 0;
1261 if (syntax == DQSYNTAX) 1254 if (syntax == DQSYNTAX)
1262 SETDBLQUOTE(); 1255 SETDBLQUOTE();
1263 quotef = 0; 1256 quotef = 0;
1264 bqlist = NULL; 1257 bqlist = NULL;
1265 arinest = 0; 1258 arinest = 0;
1266 parenlevel = 0; 1259 parenlevel = 0;
1267 1260
1268 STARTSTACKSTR(out); 1261 STARTSTACKSTR(out);
1269 loop: { /* for each line, until end of word */ 1262 loop: { /* for each line, until end of word */
1270 CHECKEND(); /* set c to PEOF if at end of here document */ 1263 CHECKEND(); /* set c to PEOF if at end of here document */
1271 for (;;) { /* until end of line or end of word */ 1264 for (;;) { /* until end of line or end of word */
1272 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 1265 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
1273 switch(syntax[c]) { 1266 switch(syntax[c]) {
1274 case CNL: /* '\n' */ 1267 case CNL: /* '\n' */
1275 if (syntax == BASESYNTAX) 1268 if (syntax == BASESYNTAX)
1276 goto endword; /* exit outer loop */ 1269 goto endword; /* exit outer loop */
1277 USTPUTC(c, out); 1270 USTPUTC(c, out);
1278 plinno++; 1271 plinno++;
1279 if (doprompt) 1272 if (doprompt)
1280 setprompt(2); 1273 setprompt(2);
1281 else 1274 else
1282 setprompt(0); 1275 setprompt(0);
1283 c = pgetc(); 1276 c = pgetc();
1284 goto loop; /* continue outer loop */ 1277 goto loop; /* continue outer loop */
1285 case CWORD: 1278 case CWORD:
1286 USTPUTC(c, out); 1279 USTPUTC(c, out);
1287 break; 1280 break;
1288 case CCTL: 1281 case CCTL:
1289 if (eofmark == NULL || ISDBLQUOTE()) 1282 if (eofmark == NULL || ISDBLQUOTE())
1290 USTPUTC(CTLESC, out); 1283 USTPUTC(CTLESC, out);
1291 USTPUTC(c, out); 1284 USTPUTC(c, out);
1292 break; 1285 break;
1293 case CBACK: /* backslash */ 1286 case CBACK: /* backslash */
1294 c = pgetc(); 1287 c = pgetc();
1295 if (c == PEOF) { 1288 if (c == PEOF) {
1296 USTPUTC('\\', out); 1289 USTPUTC('\\', out);
1297 pungetc(); 1290 pungetc();
1298 break; 1291 break;
1299 } 1292 }
1300 if (c == '\n') { 1293 if (c == '\n') {
1301 plinno++; 1294 plinno++;
1302 if (doprompt) 1295 if (doprompt)
1303 setprompt(2); 1296 setprompt(2);
1304 else 1297 else
1305 setprompt(0); 1298 setprompt(0);
1306 break; 1299 break;
1307 } 1300 }
1308 quotef = 1; 1301 quotef = 1;
1309 if (ISDBLQUOTE() && c != '\\' && 1302 if (ISDBLQUOTE() && c != '\\' &&
1310 c != '`' && c != '$' && 1303 c != '`' && c != '$' &&
1311 (c != '"' || eofmark != NULL)) 1304 (c != '"' || eofmark != NULL))
1312 USTPUTC('\\', out); 1305 USTPUTC('\\', out);
1313 if (SQSYNTAX[c] == CCTL) 1306 if (SQSYNTAX[c] == CCTL)
1314 USTPUTC(CTLESC, out); 1307 USTPUTC(CTLESC, out);
1315 else if (eofmark == NULL) { 1308 else if (eofmark == NULL) {
1316 USTPUTC(CTLQUOTEMARK, out); 1309 USTPUTC(CTLQUOTEMARK, out);
1317 USTPUTC(c, out); 1310 USTPUTC(c, out);
1318 if (varnest != 0) 1311 if (varnest != 0)
1319 USTPUTC(CTLQUOTEEND, out); 1312 USTPUTC(CTLQUOTEEND, out);
1320 break; 1313 break;
1321 } 1314 }
1322 USTPUTC(c, out); 1315 USTPUTC(c, out);
1323 break; 1316 break;
1324 case CSQUOTE: 1317 case CSQUOTE:
1325 if (syntax != SQSYNTAX) { 1318 if (syntax != SQSYNTAX) {
1326 if (eofmark == NULL) 1319 if (eofmark == NULL)
1327 USTPUTC(CTLQUOTEMARK, out); 1320 USTPUTC(CTLQUOTEMARK, out);
1328 quotef = 1; 1321 quotef = 1;
1329 TS_PUSH(); 1322 TS_PUSH();
1330 syntax = SQSYNTAX; 1323 syntax = SQSYNTAX;
1331 quoted = SQ; 1324 quoted = SQ;
1332 break; 1325 break;
1333 } 1326 }
1334 if (eofmark != NULL && arinest == 0 && 1327 if (eofmark != NULL && arinest == 0 &&
1335 varnest == 0) { 1328 varnest == 0) {
1336 /* Ignore inside quoted here document */ 1329 /* Ignore inside quoted here document */
1337 USTPUTC(c, out); 1330 USTPUTC(c, out);
1338 break; 1331 break;
1339 } 1332 }
1340 /* End of single quotes... */ 1333 /* End of single quotes... */
1341 TS_POP(); 1334 TS_POP();
1342 if (syntax == BASESYNTAX && varnest != 0) 1335 if (syntax == BASESYNTAX && varnest != 0)
1343 USTPUTC(CTLQUOTEEND, out); 1336 USTPUTC(CTLQUOTEEND, out);
1344 break; 1337 break;
1345 case CDQUOTE: 1338 case CDQUOTE:
1346 if (eofmark != NULL && arinest == 0 && 1339 if (eofmark != NULL && arinest == 0 &&
1347 varnest == 0) { 1340 varnest == 0) {
1348 /* Ignore inside here document */ 1341 /* Ignore inside here document */
1349 USTPUTC(c, out); 1342 USTPUTC(c, out);
1350 break; 1343 break;
1351 } 1344 }
1352 quotef = 1; 1345 quotef = 1;
1353 if (arinest) { 1346 if (arinest) {
1354 if (ISDBLQUOTE()) { 1347 if (ISDBLQUOTE()) {
1355 TS_POP(); 1348 TS_POP();
1356 } else { 1349 } else {
1357 TS_PUSH(); 1350 TS_PUSH();
1358 syntax = DQSYNTAX; 1351 syntax = DQSYNTAX;
1359 SETDBLQUOTE(); 1352 SETDBLQUOTE();
1360 USTPUTC(CTLQUOTEMARK, out); 1353 USTPUTC(CTLQUOTEMARK, out);
1361 } 1354 }
1362 break; 1355 break;
1363 } 1356 }
1364 if (eofmark != NULL) 1357 if (eofmark != NULL)
1365 break; 1358 break;
1366 if (ISDBLQUOTE()) { 1359 if (ISDBLQUOTE()) {
1367 TS_POP(); 1360 TS_POP();
1368 if (varnest != 0) 1361 if (varnest != 0)
1369 USTPUTC(CTLQUOTEEND, out); 1362 USTPUTC(CTLQUOTEEND, out);
1370 } else { 1363 } else {
1371 TS_PUSH(); 1364 TS_PUSH();
1372 syntax = DQSYNTAX; 1365 syntax = DQSYNTAX;
1373 SETDBLQUOTE(); 1366 SETDBLQUOTE();
1374 USTPUTC(CTLQUOTEMARK, out); 1367 USTPUTC(CTLQUOTEMARK, out);
1375 } 1368 }
1376 break; 1369 break;
1377 case CVAR: /* '$' */ 1370 case CVAR: /* '$' */
1378 PARSESUB(); /* parse substitution */ 1371 PARSESUB(); /* parse substitution */
1379 break; 1372 break;
1380 case CENDVAR: /* CLOSEBRACE */ 1373 case CENDVAR: /* CLOSEBRACE */
1381 if (varnest > 0 && !ISDBLQUOTE()) { 1374 if (varnest > 0 && !ISDBLQUOTE()) {
1382 TS_POP(); 1375 TS_POP();
1383 USTPUTC(CTLENDVAR, out); 1376 USTPUTC(CTLENDVAR, out);
1384 } else { 1377 } else {
1385 USTPUTC(c, out); 1378 USTPUTC(c, out);
1386 } 1379 }
1387 break; 1380 break;
1388 case CLP: /* '(' in arithmetic */ 1381 case CLP: /* '(' in arithmetic */
1389 parenlevel++; 1382 parenlevel++;
1390 USTPUTC(c, out); 1383 USTPUTC(c, out);
1391 break; 1384 break;
1392 case CRP: /* ')' in arithmetic */ 1385 case CRP: /* ')' in arithmetic */
1393 if (parenlevel > 0) { 1386 if (parenlevel > 0) {
1394 USTPUTC(c, out); 1387 USTPUTC(c, out);
1395 --parenlevel; 1388 --parenlevel;
1396 } else { 1389 } else {
1397 if (pgetc() == ')') { 1390 if (pgetc() == ')') {
1398 if (--arinest == 0) { 1391 if (--arinest == 0) {
1399 TS_POP(); 1392 TS_POP();
1400 USTPUTC(CTLENDARI, out); 1393 USTPUTC(CTLENDARI, out);
1401 } else 1394 } else
1402 USTPUTC(')', out); 1395 USTPUTC(')', out);
1403 } else { 1396 } else {
1404 /* 1397 /*
1405 * unbalanced parens 1398 * unbalanced parens
1406 * (don't 2nd guess - no error) 1399 * (don't 2nd guess - no error)
1407 */ 1400 */
1408 pungetc(); 1401 pungetc();
1409 USTPUTC(')', out); 1402 USTPUTC(')', out);
1410 } 1403 }
1411 } 1404 }
1412 break; 1405 break;
1413 case CBQUOTE: /* '`' */ 1406 case CBQUOTE: /* '`' */
1414 out = parsebackq(stack, out, &bqlist, 1); 1407 out = parsebackq(stack, out, &bqlist, 1);
1415 break; 1408 break;
1416 case CEOF: 1409 case CEOF:
1417 goto endword; /* exit outer loop */ 1410 goto endword; /* exit outer loop */
1418 default: 1411 default:
1419 if (varnest == 0 && !ISDBLQUOTE()) 1412 if (varnest == 0 && !ISDBLQUOTE())
1420 goto endword; /* exit outer loop */ 1413 goto endword; /* exit outer loop */
1421 USTPUTC(c, out); 1414 USTPUTC(c, out);
1422 } 1415 }
1423 c = pgetc_macro(); 1416 c = pgetc_macro();
1424 } 1417 }
1425 } 1418 }
1426endword: 1419endword:
1427 if (syntax == ARISYNTAX) { 1420 if (syntax == ARISYNTAX) {
1428 cleanup_state_stack(stack); 1421 cleanup_state_stack(stack);
1429 synerror("Missing '))'"); 1422 synerror("Missing '))'");
1430 } 1423 }
1431 if (syntax != BASESYNTAX && /* ! parsebackquote && */ eofmark == NULL) { 1424 if (syntax != BASESYNTAX && /* ! parsebackquote && */ eofmark == NULL) {
1432 cleanup_state_stack(stack); 1425 cleanup_state_stack(stack);
1433 synerror("Unterminated quoted string"); 1426 synerror("Unterminated quoted string");
1434 } 1427 }
1435 if (varnest != 0) { 1428 if (varnest != 0) {
1436 cleanup_state_stack(stack); 1429 cleanup_state_stack(stack);
1437 startlinno = plinno; 1430 startlinno = plinno;
1438 /* { */ 1431 /* { */
1439 synerror("Missing '}'"); 1432 synerror("Missing '}'");
1440 } 1433 }
1441 USTPUTC('\0', out); 1434 USTPUTC('\0', out);
1442 len = out - stackblock(); 1435 len = out - stackblock();
1443 out = stackblock(); 1436 out = stackblock();
1444 if (eofmark == NULL) { 1437 if (eofmark == NULL) {
1445 if ((c == '>' || c == '<') 1438 if ((c == '>' || c == '<')
1446 && quotef == 0 1439 && quotef == 0
1447 && (*out == '\0' || is_number(out))) { 1440 && (*out == '\0' || is_number(out))) {
1448 PARSEREDIR(); 1441 PARSEREDIR();
1449 cleanup_state_stack(stack); 1442 cleanup_state_stack(stack);
1450 return lasttoken = TREDIR; 1443 return lasttoken = TREDIR;
1451 } else { 1444 } else {
1452 pungetc(); 1445 pungetc();
1453 } 1446 }
1454 } 1447 }
1455 quoteflag = quotef; 1448 quoteflag = quotef;
1456 backquotelist = bqlist; 1449 backquotelist = bqlist;
1457 grabstackblock(len); 1450 grabstackblock(len);
1458 wordtext = out; 1451 wordtext = out;
1459 cleanup_state_stack(stack); 1452 cleanup_state_stack(stack);
1460 return lasttoken = TWORD; 1453 return lasttoken = TWORD;
1461/* end of readtoken routine */ 1454/* end of readtoken routine */
1462 1455
1463 1456
1464 1457
1465/* 1458/*
1466 * Check to see whether we are at the end of the here document. When this 1459 * Check to see whether we are at the end of the here document. When this
1467 * is called, c is set to the first character of the next input line. If 1460 * is called, c is set to the first character of the next input line. If
1468 * we are at the end of the here document, this routine sets the c to PEOF. 1461 * we are at the end of the here document, this routine sets the c to PEOF.
1469 */ 1462 */
1470 1463
1471checkend: { 1464checkend: {
1472 if (eofmark) { 1465 if (eofmark) {
1473 if (c == PEOF) 1466 if (c == PEOF)
1474 synerror(EOFhere); 1467 synerror(EOFhere);
1475 if (striptabs) { 1468 if (striptabs) {
1476 while (c == '\t') 1469 while (c == '\t')
1477 c = pgetc(); 1470 c = pgetc();
1478 } 1471 }
1479 if (c == *eofmark) { 1472 if (c == *eofmark) {
1480 if (pfgets(line, sizeof line) != NULL) { 1473 if (pfgets(line, sizeof line) != NULL) {
1481 char *p, *q; 1474 char *p, *q;
1482 1475
1483 p = line; 1476 p = line;
1484 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++) 1477 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++)
1485 continue; 1478 continue;
1486 if ((*p == '\0' || *p == '\n') && *q == '\0') { 1479 if ((*p == '\0' || *p == '\n') && *q == '\0') {
1487 c = PEOF; 1480 c = PEOF;
1488 plinno++; 1481 plinno++;
1489 needprompt = doprompt; 1482 needprompt = doprompt;
1490 } else { 1483 } else {
1491 pushstring(line, strlen(line), NULL); 1484 pushstring(line, strlen(line), NULL);
1492 } 1485 }
1493 } else 1486 } else
1494 synerror(EOFhere); 1487 synerror(EOFhere);
1495 } 1488 }
1496 } 1489 }
1497 goto checkend_return; 1490 goto checkend_return;
1498} 1491}
1499 1492
1500 1493
1501/* 1494/*
1502 * Parse a redirection operator. The variable "out" points to a string 1495 * Parse a redirection operator. The variable "out" points to a string
1503 * specifying the fd to be redirected. The variable "c" contains the 1496 * specifying the fd to be redirected. The variable "c" contains the
1504 * first character of the redirection operator. 1497 * first character of the redirection operator.
1505 */ 1498 */
1506 1499
1507parseredir: { 1500parseredir: {
1508 char fd[64]; 1501 char fd[64];
1509 union node *np; 1502 union node *np;
1510 strlcpy(fd, out, sizeof(fd)); 1503 strlcpy(fd, out, sizeof(fd));
1511 1504
1512 np = stalloc(sizeof(struct nfile)); 1505 np = stalloc(sizeof(struct nfile));
1513 if (c == '>') { 1506 if (c == '>') {
1514 np->nfile.fd = 1; 1507 np->nfile.fd = 1;
1515 c = pgetc(); 1508 c = pgetc();
1516 if (c == '>') 1509 if (c == '>')
1517 np->type = NAPPEND; 1510 np->type = NAPPEND;
1518 else if (c == '|') 1511 else if (c == '|')
1519 np->type = NCLOBBER; 1512 np->type = NCLOBBER;
1520 else if (c == '&') 1513 else if (c == '&')
1521 np->type = NTOFD; 1514 np->type = NTOFD;
1522 else { 1515 else {
1523 np->type = NTO; 1516 np->type = NTO;
1524 pungetc(); 1517 pungetc();
1525 } 1518 }
1526 } else { /* c == '<' */ 1519 } else { /* c == '<' */
1527 np->nfile.fd = 0; 1520 np->nfile.fd = 0;
1528 switch (c = pgetc()) { 1521 switch (c = pgetc()) {
1529 case '<': 1522 case '<':
1530 if (sizeof (struct nfile) != sizeof (struct nhere)) { 1523 if (sizeof (struct nfile) != sizeof (struct nhere)) {
1531 np = stalloc(sizeof(struct nhere)); 1524 np = stalloc(sizeof(struct nhere));
1532 np->nfile.fd = 0; 1525 np->nfile.fd = 0;
1533 } 1526 }
1534 np->type = NHERE; 1527 np->type = NHERE;
1535 heredoc = stalloc(sizeof(struct heredoc)); 1528 heredoc = stalloc(sizeof(struct heredoc));
1536 heredoc->here = np; 1529 heredoc->here = np;
1537 if ((c = pgetc()) == '-') { 1530 if ((c = pgetc()) == '-') {
1538 heredoc->striptabs = 1; 1531 heredoc->striptabs = 1;
1539 } else { 1532 } else {
1540 heredoc->striptabs = 0; 1533 heredoc->striptabs = 0;
1541 pungetc(); 1534 pungetc();
1542 } 1535 }
1543 break; 1536 break;
1544 1537
1545 case '&': 1538 case '&':
1546 np->type = NFROMFD; 1539 np->type = NFROMFD;
1547 break; 1540 break;
1548 1541
1549 case '>': 1542 case '>':
1550 np->type = NFROMTO; 1543 np->type = NFROMTO;
1551 break; 1544 break;
1552 1545
1553 default: 1546 default:
1554 np->type = NFROM; 1547 np->type = NFROM;
1555 pungetc(); 1548 pungetc();
1556 break; 1549 break;
1557 } 1550 }
1558 } 1551 }
1559 if (*fd != '\0') 1552 if (*fd != '\0')
1560 np->nfile.fd = number(fd); 1553 np->nfile.fd = number(fd);
1561 redirnode = np; 1554 redirnode = np;
1562 goto parseredir_return; 1555 goto parseredir_return;
1563} 1556}
1564 1557
1565 1558
1566/* 1559/*
1567 * Parse a substitution. At this point, we have read the dollar sign 1560 * Parse a substitution. At this point, we have read the dollar sign
1568 * and nothing else. 1561 * and nothing else.
1569 */ 1562 */
1570 1563
1571parsesub: { 1564parsesub: {
1572 char buf[10]; 1565 char buf[10];
1573 int subtype; 1566 int subtype;
1574 int typeloc; 1567 int typeloc;
1575 int flags; 1568 int flags;
1576 char *p; 1569 char *p;
1577 static const char types[] = "}-+?="; 1570 static const char types[] = "}-+?=";
1578 int i; 1571 int i;
1579 int linno; 1572 int linno;
1580 1573
1581 c = pgetc(); 1574 c = pgetc();
1582 if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) { 1575 if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
1583 USTPUTC('$', out); 1576 USTPUTC('$', out);
1584 pungetc(); 1577 pungetc();
1585 } else if (c == '(') { /* $(command) or $((arith)) */ 1578 } else if (c == '(') { /* $(command) or $((arith)) */
1586 if (pgetc() == '(') { 1579 if (pgetc() == '(') {
1587 PARSEARITH(); 1580 PARSEARITH();
1588 } else { 1581 } else {
1589 pungetc(); 1582 pungetc();
1590 out = parsebackq(stack, out, &bqlist, 0); 1583 out = parsebackq(stack, out, &bqlist, 0);
1591 } 1584 }
1592 } else { 1585 } else {
1593 USTPUTC(CTLVAR, out); 1586 USTPUTC(CTLVAR, out);
1594 typeloc = out - stackblock(); 1587 typeloc = out - stackblock();
1595 USTPUTC(VSNORMAL, out); 1588 USTPUTC(VSNORMAL, out);
1596 subtype = VSNORMAL; 1589 subtype = VSNORMAL;
1597 flags = 0; 1590 flags = 0;
1598 if (c == OPENBRACE) { 1591 if (c == OPENBRACE) {
1599 c = pgetc(); 1592 c = pgetc();