Thu Mar 31 23:11:05 2016 UTC ()
After discussions with Jilles Tjoelker (FreeBSD shell) and
following a suggestion from him, the way the fix to PR bin/50993
was implemented has changed a little.   There are three steps involved
in processing a here document, reading it, parsing it, and then
evaluating it before applying it to the correct file descriptor for
the command to use.  The third of those is not related to this
problem, and has not changed.  The bug was caused by combining the
first two steps into one (and not doing it correctly - which would be
hard that way.)  The fix is to split the first two stages into
separate events.   The original fix moved the 2nd stage (parsing)
to just immediately before the 3rd stage (evaluation.)  Jilles
pointed out some unwanted side effects from doing it that way, and
suggested moving the 2nd stage to immediately after the first.
This commit makes that change.  The effect is to revert the changes
to expand.c and parser.h (which are no longer needed) and simplify
slightly the change to parser.c. (from kre@)


(christos)
diff -r1.114 -r1.115 src/bin/sh/parser.c
diff -r1.20 -r1.21 src/bin/sh/parser.h

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

--- src/bin/sh/parser.c 2016/03/31 16:12:52 1.114
+++ src/bin/sh/parser.c 2016/03/31 23:11:05 1.115
@@ -1,1873 +1,1866 @@ @@ -1,1873 +1,1866 @@
1/* $NetBSD: parser.c,v 1.114 2016/03/31 16:12:52 christos Exp $ */ 1/* $NetBSD: parser.c,v 1.115 2016/03/31 23:11:05 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.114 2016/03/31 16:12:52 christos Exp $"); 40__RCSID("$NetBSD: parser.c,v 1.115 2016/03/31 23:11:05 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/* values returned by readtoken */ 72/* values returned by readtoken */
73#include "token.h" 73#include "token.h"
74 74
75#define OPENBRACE '{' 75#define OPENBRACE '{'
76#define CLOSEBRACE '}' 76#define CLOSEBRACE '}'
77 77
78 78
79struct heredoc { 79struct heredoc {
80 struct heredoc *next; /* next here document in list */ 80 struct heredoc *next; /* next here document in list */
81 union node *here; /* redirection node */ 81 union node *here; /* redirection node */
82 char *eofmark; /* string indicating end of input */ 82 char *eofmark; /* string indicating end of input */
83 int striptabs; /* if set, strip leading tabs */ 83 int striptabs; /* if set, strip leading tabs */
84}; 84};
85 85
86 86
87 87
88static int noalias = 0; /* when set, don't handle aliases */ 88static int noalias = 0; /* when set, don't handle aliases */
89struct heredoc *heredoclist; /* list of here documents to read */ 89struct heredoc *heredoclist; /* list of here documents to read */
90int parsebackquote; /* nonzero if we are inside backquotes */ 90int parsebackquote; /* nonzero if we are inside backquotes */
91int doprompt; /* if set, prompt the user */ 91int doprompt; /* if set, prompt the user */
92int needprompt; /* true if interactive and at start of line */ 92int needprompt; /* true if interactive and at start of line */
93int lasttoken; /* last token read */ 93int lasttoken; /* last token read */
94MKINIT int tokpushback; /* last token pushed back */ 94MKINIT int tokpushback; /* last token pushed back */
95char *wordtext; /* text of last word returned by readtoken */ 95char *wordtext; /* text of last word returned by readtoken */
96MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 96MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
97struct nodelist *backquotelist; 97struct nodelist *backquotelist;
98union node *redirnode; 98union node *redirnode;
99struct heredoc *heredoc; 99struct heredoc *heredoc;
100int quoteflag; /* set if (part of) last token was quoted */ 100int quoteflag; /* set if (part of) last token was quoted */
101int startlinno; /* line # where last token started */ 101int startlinno; /* line # where last token started */
102int funclinno; /* line # where the current function started */ 102int funclinno; /* line # where the current function started */
103 103
104 104
105STATIC union node *list(int, int); 105STATIC union node *list(int, int);
106STATIC union node *andor(void); 106STATIC union node *andor(void);
107STATIC union node *pipeline(void); 107STATIC union node *pipeline(void);
108STATIC union node *command(void); 108STATIC union node *command(void);
109STATIC union node *simplecmd(union node **, union node *); 109STATIC union node *simplecmd(union node **, union node *);
110STATIC union node *makename(void); 110STATIC union node *makename(void);
111STATIC void parsefname(void); 111STATIC void parsefname(void);
112STATIC void slurp_heredoc(char *const, int, int); 112STATIC void slurp_heredoc(char *const, const int, const int);
113STATIC void readheredocs(void); 113STATIC void readheredocs(void);
114STATIC int peektoken(void); 114STATIC int peektoken(void);
115STATIC int readtoken(void); 115STATIC int readtoken(void);
116STATIC int xxreadtoken(void); 116STATIC int xxreadtoken(void);
117STATIC int readtoken1(int, char const *, int); 117STATIC int readtoken1(int, char const *, int);
118STATIC int noexpand(char *); 118STATIC int noexpand(char *);
119STATIC void synexpect(int, const char *) __dead; 119STATIC void synexpect(int, const char *) __dead;
120STATIC void synerror(const char *) __dead; 120STATIC void synerror(const char *) __dead;
121STATIC void setprompt(int); 121STATIC void setprompt(int);
122 122
123 123
124static const char EOFhere[] = "EOF reading here (<<) document"; 124static const char EOFhere[] = "EOF reading here (<<) document";
125 125
126 126
127/* 127/*
128 * Read and parse a command. Returns NEOF on end of file. (NULL is a 128 * Read and parse a command. Returns NEOF on end of file. (NULL is a
129 * valid parse tree indicating a blank line.) 129 * valid parse tree indicating a blank line.)
130 */ 130 */
131 131
132union node * 132union node *
133parsecmd(int interact) 133parsecmd(int interact)
134{ 134{
135 int t; 135 int t;
136 136
137 tokpushback = 0; 137 tokpushback = 0;
138 doprompt = interact; 138 doprompt = interact;
139 if (doprompt) 139 if (doprompt)
140 setprompt(1); 140 setprompt(1);
141 else 141 else
142 setprompt(0); 142 setprompt(0);
143 needprompt = 0; 143 needprompt = 0;
144 t = readtoken(); 144 t = readtoken();
145 if (t == TEOF) 145 if (t == TEOF)
146 return NEOF; 146 return NEOF;
147 if (t == TNL) 147 if (t == TNL)
148 return NULL; 148 return NULL;
149 tokpushback++; 149 tokpushback++;
150 return list(1, 0); 150 return list(1, 0);
151} 151}
152 152
153 153
154STATIC union node * 154STATIC union node *
155list(int nlflag, int erflag) 155list(int nlflag, int erflag)
156{ 156{
157 union node *n1, *n2, *n3; 157 union node *n1, *n2, *n3;
158 int tok; 158 int tok;
159 TRACE(("list(%d,%d): entered\n", nlflag, erflag)); 159 TRACE(("list(%d,%d): entered\n", nlflag, erflag));
160 160
161 checkkwd = 2; 161 checkkwd = 2;
162 if (nlflag == 0 && tokendlist[peektoken()]) 162 if (nlflag == 0 && tokendlist[peektoken()])
163 return NULL; 163 return NULL;
164 n1 = NULL; 164 n1 = NULL;
165 for (;;) { 165 for (;;) {
166 n2 = andor(); 166 n2 = andor();
167 tok = readtoken(); 167 tok = readtoken();
168 if (tok == TBACKGND) { 168 if (tok == TBACKGND) {
169 if (n2->type == NCMD || n2->type == NPIPE) { 169 if (n2->type == NCMD || n2->type == NPIPE) {
170 n2->ncmd.backgnd = 1; 170 n2->ncmd.backgnd = 1;
171 } else if (n2->type == NREDIR) { 171 } else if (n2->type == NREDIR) {
172 n2->type = NBACKGND; 172 n2->type = NBACKGND;
173 } else { 173 } else {
174 n3 = stalloc(sizeof(struct nredir)); 174 n3 = stalloc(sizeof(struct nredir));
175 n3->type = NBACKGND; 175 n3->type = NBACKGND;
176 n3->nredir.n = n2; 176 n3->nredir.n = n2;
177 n3->nredir.redirect = NULL; 177 n3->nredir.redirect = NULL;
178 n2 = n3; 178 n2 = n3;
179 } 179 }
180 } 180 }
181 if (n1 == NULL) { 181 if (n1 == NULL) {
182 n1 = n2; 182 n1 = n2;
183 } 183 }
184 else { 184 else {
185 n3 = stalloc(sizeof(struct nbinary)); 185 n3 = stalloc(sizeof(struct nbinary));
186 n3->type = NSEMI; 186 n3->type = NSEMI;
187 n3->nbinary.ch1 = n1; 187 n3->nbinary.ch1 = n1;
188 n3->nbinary.ch2 = n2; 188 n3->nbinary.ch2 = n2;
189 n1 = n3; 189 n1 = n3;
190 } 190 }
191 switch (tok) { 191 switch (tok) {
192 case TBACKGND: 192 case TBACKGND:
193 case TSEMI: 193 case TSEMI:
194 tok = readtoken(); 194 tok = readtoken();
195 /* FALLTHROUGH */ 195 /* FALLTHROUGH */
196 case TNL: 196 case TNL:
197 if (tok == TNL) { 197 if (tok == TNL) {
198 readheredocs(); 198 readheredocs();
199 if (nlflag) 199 if (nlflag)
200 return n1; 200 return n1;
201 } else { 201 } else {
202 tokpushback++; 202 tokpushback++;
203 } 203 }
204 checkkwd = 2; 204 checkkwd = 2;
205 if (tokendlist[peektoken()]) 205 if (tokendlist[peektoken()])
206 return n1; 206 return n1;
207 break; 207 break;
208 case TEOF: 208 case TEOF:
209 if (heredoclist) 209 if (heredoclist)
210 readheredocs(); 210 readheredocs();
211 else 211 else
212 pungetc(); /* push back EOF on input */ 212 pungetc(); /* push back EOF on input */
213 return n1; 213 return n1;
214 default: 214 default:
215 if (nlflag || erflag) 215 if (nlflag || erflag)
216 synexpect(-1, 0); 216 synexpect(-1, 0);
217 tokpushback++; 217 tokpushback++;
218 return n1; 218 return n1;
219 } 219 }
220 } 220 }
221} 221}
222 222
223STATIC union node * 223STATIC union node *
224andor(void) 224andor(void)
225{ 225{
226 union node *n1, *n2, *n3; 226 union node *n1, *n2, *n3;
227 int t; 227 int t;
228 228
229 TRACE(("andor: entered\n")); 229 TRACE(("andor: entered\n"));
230 n1 = pipeline(); 230 n1 = pipeline();
231 for (;;) { 231 for (;;) {
232 if ((t = readtoken()) == TAND) { 232 if ((t = readtoken()) == TAND) {
233 t = NAND; 233 t = NAND;
234 } else if (t == TOR) { 234 } else if (t == TOR) {
235 t = NOR; 235 t = NOR;
236 } else { 236 } else {
237 tokpushback++; 237 tokpushback++;
238 return n1; 238 return n1;
239 } 239 }
240 n2 = pipeline(); 240 n2 = pipeline();
241 n3 = stalloc(sizeof(struct nbinary)); 241 n3 = stalloc(sizeof(struct nbinary));
242 n3->type = t; 242 n3->type = t;
243 n3->nbinary.ch1 = n1; 243 n3->nbinary.ch1 = n1;
244 n3->nbinary.ch2 = n2; 244 n3->nbinary.ch2 = n2;
245 n1 = n3; 245 n1 = n3;
246 } 246 }
247} 247}
248 248
249STATIC union node * 249STATIC union node *
250pipeline(void) 250pipeline(void)
251{ 251{
252 union node *n1, *n2, *pipenode; 252 union node *n1, *n2, *pipenode;
253 struct nodelist *lp, *prev; 253 struct nodelist *lp, *prev;
254 int negate; 254 int negate;
255 255
256 TRACE(("pipeline: entered\n")); 256 TRACE(("pipeline: entered\n"));
257 257
258 negate = 0; 258 negate = 0;
259 checkkwd = 2; 259 checkkwd = 2;
260 while (readtoken() == TNOT) { 260 while (readtoken() == TNOT) {
261 TRACE(("pipeline: TNOT recognized\n")); 261 TRACE(("pipeline: TNOT recognized\n"));
262 negate = !negate; 262 negate = !negate;
263 } 263 }
264 tokpushback++; 264 tokpushback++;
265 n1 = command(); 265 n1 = command();
266 if (readtoken() == TPIPE) { 266 if (readtoken() == TPIPE) {
267 pipenode = stalloc(sizeof(struct npipe)); 267 pipenode = stalloc(sizeof(struct npipe));
268 pipenode->type = NPIPE; 268 pipenode->type = NPIPE;
269 pipenode->npipe.backgnd = 0; 269 pipenode->npipe.backgnd = 0;
270 lp = stalloc(sizeof(struct nodelist)); 270 lp = stalloc(sizeof(struct nodelist));
271 pipenode->npipe.cmdlist = lp; 271 pipenode->npipe.cmdlist = lp;
272 lp->n = n1; 272 lp->n = n1;
273 do { 273 do {
274 prev = lp; 274 prev = lp;
275 lp = stalloc(sizeof(struct nodelist)); 275 lp = stalloc(sizeof(struct nodelist));
276 lp->n = command(); 276 lp->n = command();
277 prev->next = lp; 277 prev->next = lp;
278 } while (readtoken() == TPIPE); 278 } while (readtoken() == TPIPE);
279 lp->next = NULL; 279 lp->next = NULL;
280 n1 = pipenode; 280 n1 = pipenode;
281 } 281 }
282 tokpushback++; 282 tokpushback++;
283 if (negate) { 283 if (negate) {
284 TRACE(("negate pipeline\n")); 284 TRACE(("negate pipeline\n"));
285 n2 = stalloc(sizeof(struct nnot)); 285 n2 = stalloc(sizeof(struct nnot));
286 n2->type = NNOT; 286 n2->type = NNOT;
287 n2->nnot.com = n1; 287 n2->nnot.com = n1;
288 return n2; 288 return n2;
289 } else 289 } else
290 return n1; 290 return n1;
291} 291}
292 292
293 293
294 294
295STATIC union node * 295STATIC union node *
296command(void) 296command(void)
297{ 297{
298 union node *n1, *n2; 298 union node *n1, *n2;
299 union node *ap, **app; 299 union node *ap, **app;
300 union node *cp, **cpp; 300 union node *cp, **cpp;
301 union node *redir, **rpp; 301 union node *redir, **rpp;
302 int t, negate = 0; 302 int t, negate = 0;
303 303
304 TRACE(("command: entered\n")); 304 TRACE(("command: entered\n"));
305 305
306 checkkwd = 2; 306 checkkwd = 2;
307 redir = NULL; 307 redir = NULL;
308 n1 = NULL; 308 n1 = NULL;
309 rpp = &redir; 309 rpp = &redir;
310 310
311 /* Check for redirection which may precede command */ 311 /* Check for redirection which may precede command */
312 while (readtoken() == TREDIR) { 312 while (readtoken() == TREDIR) {
313 *rpp = n2 = redirnode; 313 *rpp = n2 = redirnode;
314 rpp = &n2->nfile.next; 314 rpp = &n2->nfile.next;
315 parsefname(); 315 parsefname();
316 } 316 }
317 tokpushback++; 317 tokpushback++;
318 318
319 while (readtoken() == TNOT) { 319 while (readtoken() == TNOT) {
320 TRACE(("command: TNOT recognized\n")); 320 TRACE(("command: TNOT recognized\n"));
321 negate = !negate; 321 negate = !negate;
322 } 322 }
323 tokpushback++; 323 tokpushback++;
324 324
325 switch (readtoken()) { 325 switch (readtoken()) {
326 case TIF: 326 case TIF:
327 n1 = stalloc(sizeof(struct nif)); 327 n1 = stalloc(sizeof(struct nif));
328 n1->type = NIF; 328 n1->type = NIF;
329 n1->nif.test = list(0, 0); 329 n1->nif.test = list(0, 0);
330 if (readtoken() != TTHEN) 330 if (readtoken() != TTHEN)
331 synexpect(TTHEN, 0); 331 synexpect(TTHEN, 0);
332 n1->nif.ifpart = list(0, 0); 332 n1->nif.ifpart = list(0, 0);
333 n2 = n1; 333 n2 = n1;
334 while (readtoken() == TELIF) { 334 while (readtoken() == TELIF) {
335 n2->nif.elsepart = stalloc(sizeof(struct nif)); 335 n2->nif.elsepart = stalloc(sizeof(struct nif));
336 n2 = n2->nif.elsepart; 336 n2 = n2->nif.elsepart;
337 n2->type = NIF; 337 n2->type = NIF;
338 n2->nif.test = list(0, 0); 338 n2->nif.test = list(0, 0);
339 if (readtoken() != TTHEN) 339 if (readtoken() != TTHEN)
340 synexpect(TTHEN, 0); 340 synexpect(TTHEN, 0);
341 n2->nif.ifpart = list(0, 0); 341 n2->nif.ifpart = list(0, 0);
342 } 342 }
343 if (lasttoken == TELSE) 343 if (lasttoken == TELSE)
344 n2->nif.elsepart = list(0, 0); 344 n2->nif.elsepart = list(0, 0);
345 else { 345 else {
346 n2->nif.elsepart = NULL; 346 n2->nif.elsepart = NULL;
347 tokpushback++; 347 tokpushback++;
348 } 348 }
349 if (readtoken() != TFI) 349 if (readtoken() != TFI)
350 synexpect(TFI, 0); 350 synexpect(TFI, 0);
351 checkkwd = 1; 351 checkkwd = 1;
352 break; 352 break;
353 case TWHILE: 353 case TWHILE:
354 case TUNTIL: { 354 case TUNTIL: {
355 int got; 355 int got;
356 n1 = stalloc(sizeof(struct nbinary)); 356 n1 = stalloc(sizeof(struct nbinary));
357 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 357 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
358 n1->nbinary.ch1 = list(0, 0); 358 n1->nbinary.ch1 = list(0, 0);
359 if ((got=readtoken()) != TDO) { 359 if ((got=readtoken()) != TDO) {
360TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 360TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
361 synexpect(TDO, 0); 361 synexpect(TDO, 0);
362 } 362 }
363 n1->nbinary.ch2 = list(0, 0); 363 n1->nbinary.ch2 = list(0, 0);
364 if (readtoken() != TDONE) 364 if (readtoken() != TDONE)
365 synexpect(TDONE, 0); 365 synexpect(TDONE, 0);
366 checkkwd = 1; 366 checkkwd = 1;
367 break; 367 break;
368 } 368 }
369 case TFOR: 369 case TFOR:
370 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 370 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
371 synerror("Bad for loop variable"); 371 synerror("Bad for loop variable");
372 n1 = stalloc(sizeof(struct nfor)); 372 n1 = stalloc(sizeof(struct nfor));
373 n1->type = NFOR; 373 n1->type = NFOR;
374 n1->nfor.var = wordtext; 374 n1->nfor.var = wordtext;
375 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 375 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
376 app = &ap; 376 app = &ap;
377 while (readtoken() == TWORD) { 377 while (readtoken() == TWORD) {
378 n2 = stalloc(sizeof(struct narg)); 378 n2 = stalloc(sizeof(struct narg));
379 n2->type = NARG; 379 n2->type = NARG;
380 n2->narg.text = wordtext; 380 n2->narg.text = wordtext;
381 n2->narg.backquote = backquotelist; 381 n2->narg.backquote = backquotelist;
382 *app = n2; 382 *app = n2;
383 app = &n2->narg.next; 383 app = &n2->narg.next;
384 } 384 }
385 *app = NULL; 385 *app = NULL;
386 n1->nfor.args = ap; 386 n1->nfor.args = ap;
387 if (lasttoken != TNL && lasttoken != TSEMI) 387 if (lasttoken != TNL && lasttoken != TSEMI)
388 synexpect(-1, 0); 388 synexpect(-1, 0);
389 } else { 389 } else {
390 static char argvars[5] = { 390 static char argvars[5] = {
391 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 391 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
392 }; 392 };
393 n2 = stalloc(sizeof(struct narg)); 393 n2 = stalloc(sizeof(struct narg));
394 n2->type = NARG; 394 n2->type = NARG;
395 n2->narg.text = argvars; 395 n2->narg.text = argvars;
396 n2->narg.backquote = NULL; 396 n2->narg.backquote = NULL;
397 n2->narg.next = NULL; 397 n2->narg.next = NULL;
398 n1->nfor.args = n2; 398 n1->nfor.args = n2;
399 /* 399 /*
400 * Newline or semicolon here is optional (but note 400 * Newline or semicolon here is optional (but note
401 * that the original Bourne shell only allowed NL). 401 * that the original Bourne shell only allowed NL).
402 */ 402 */
403 if (lasttoken != TNL && lasttoken != TSEMI) 403 if (lasttoken != TNL && lasttoken != TSEMI)
404 tokpushback++; 404 tokpushback++;
405 } 405 }
406 checkkwd = 2; 406 checkkwd = 2;
407 if ((t = readtoken()) == TDO) 407 if ((t = readtoken()) == TDO)
408 t = TDONE; 408 t = TDONE;
409 else if (t == TBEGIN) 409 else if (t == TBEGIN)
410 t = TEND; 410 t = TEND;
411 else 411 else
412 synexpect(-1, 0); 412 synexpect(-1, 0);
413 n1->nfor.body = list(0, 0); 413 n1->nfor.body = list(0, 0);
414 if (readtoken() != t) 414 if (readtoken() != t)
415 synexpect(t, 0); 415 synexpect(t, 0);
416 checkkwd = 1; 416 checkkwd = 1;
417 break; 417 break;
418 case TCASE: 418 case TCASE:
419 n1 = stalloc(sizeof(struct ncase)); 419 n1 = stalloc(sizeof(struct ncase));
420 n1->type = NCASE; 420 n1->type = NCASE;
421 if (readtoken() != TWORD) 421 if (readtoken() != TWORD)
422 synexpect(TWORD, 0); 422 synexpect(TWORD, 0);
423 n1->ncase.expr = n2 = stalloc(sizeof(struct narg)); 423 n1->ncase.expr = n2 = stalloc(sizeof(struct narg));
424 n2->type = NARG; 424 n2->type = NARG;
425 n2->narg.text = wordtext; 425 n2->narg.text = wordtext;
426 n2->narg.backquote = backquotelist; 426 n2->narg.backquote = backquotelist;
427 n2->narg.next = NULL; 427 n2->narg.next = NULL;
428 while (readtoken() == TNL); 428 while (readtoken() == TNL);
429 if (lasttoken != TWORD || ! equal(wordtext, "in")) 429 if (lasttoken != TWORD || ! equal(wordtext, "in"))
430 synexpect(-1, "in"); 430 synexpect(-1, "in");
431 cpp = &n1->ncase.cases; 431 cpp = &n1->ncase.cases;
432 noalias = 1; 432 noalias = 1;
433 checkkwd = 2, readtoken(); 433 checkkwd = 2, readtoken();
434 /* 434 /*
435 * Both ksh and bash accept 'case x in esac' 435 * Both ksh and bash accept 'case x in esac'
436 * so configure scripts started taking advantage of this. 436 * so configure scripts started taking advantage of this.
437 * The page: http://pubs.opengroup.org/onlinepubs/\ 437 * The page: http://pubs.opengroup.org/onlinepubs/\
438 * 009695399/utilities/xcu_chap02.html contradicts itself, 438 * 009695399/utilities/xcu_chap02.html contradicts itself,
439 * as to if this is legal; the "Case Conditional Format" 439 * as to if this is legal; the "Case Conditional Format"
440 * paragraph shows one case is required, but the "Grammar" 440 * paragraph shows one case is required, but the "Grammar"
441 * section shows a grammar that explicitly allows the no 441 * section shows a grammar that explicitly allows the no
442 * case option. 442 * case option.
443 */ 443 */
444 while (lasttoken != TESAC) { 444 while (lasttoken != TESAC) {
445 *cpp = cp = stalloc(sizeof(struct nclist)); 445 *cpp = cp = stalloc(sizeof(struct nclist));
446 if (lasttoken == TLP) 446 if (lasttoken == TLP)
447 readtoken(); 447 readtoken();
448 cp->type = NCLIST; 448 cp->type = NCLIST;
449 app = &cp->nclist.pattern; 449 app = &cp->nclist.pattern;
450 for (;;) { 450 for (;;) {
451 *app = ap = stalloc(sizeof(struct narg)); 451 *app = ap = stalloc(sizeof(struct narg));
452 ap->type = NARG; 452 ap->type = NARG;
453 ap->narg.text = wordtext; 453 ap->narg.text = wordtext;
454 ap->narg.backquote = backquotelist; 454 ap->narg.backquote = backquotelist;
455 if (checkkwd = 2, readtoken() != TPIPE) 455 if (checkkwd = 2, readtoken() != TPIPE)
456 break; 456 break;
457 app = &ap->narg.next; 457 app = &ap->narg.next;
458 readtoken(); 458 readtoken();
459 } 459 }
460 ap->narg.next = NULL; 460 ap->narg.next = NULL;
461 noalias = 0; 461 noalias = 0;
462 if (lasttoken != TRP) { 462 if (lasttoken != TRP) {
463 synexpect(TRP, 0); 463 synexpect(TRP, 0);
464 } 464 }
465 cp->nclist.body = list(0, 0); 465 cp->nclist.body = list(0, 0);
466 466
467 checkkwd = 2; 467 checkkwd = 2;
468 if ((t = readtoken()) != TESAC) { 468 if ((t = readtoken()) != TESAC) {
469 if (t != TENDCASE) { 469 if (t != TENDCASE) {
470 noalias = 0; 470 noalias = 0;
471 synexpect(TENDCASE, 0); 471 synexpect(TENDCASE, 0);
472 } else { 472 } else {
473 noalias = 1; 473 noalias = 1;
474 checkkwd = 2; 474 checkkwd = 2;
475 readtoken(); 475 readtoken();
476 } 476 }
477 } 477 }
478 cpp = &cp->nclist.next; 478 cpp = &cp->nclist.next;
479 } 479 }
480 noalias = 0; 480 noalias = 0;
481 *cpp = NULL; 481 *cpp = NULL;
482 checkkwd = 1; 482 checkkwd = 1;
483 break; 483 break;
484 case TLP: 484 case TLP:
485 n1 = stalloc(sizeof(struct nredir)); 485 n1 = stalloc(sizeof(struct nredir));
486 n1->type = NSUBSHELL; 486 n1->type = NSUBSHELL;
487 n1->nredir.n = list(0, 0); 487 n1->nredir.n = list(0, 0);
488 n1->nredir.redirect = NULL; 488 n1->nredir.redirect = NULL;
489 if (readtoken() != TRP) 489 if (readtoken() != TRP)
490 synexpect(TRP, 0); 490 synexpect(TRP, 0);
491 checkkwd = 1; 491 checkkwd = 1;
492 break; 492 break;
493 case TBEGIN: 493 case TBEGIN:
494 n1 = list(0, 0); 494 n1 = list(0, 0);
495 if (readtoken() != TEND) 495 if (readtoken() != TEND)
496 synexpect(TEND, 0); 496 synexpect(TEND, 0);
497 checkkwd = 1; 497 checkkwd = 1;
498 break; 498 break;
499 /* Handle an empty command like other simple commands. */ 499 /* Handle an empty command like other simple commands. */
500 case TSEMI: 500 case TSEMI:
501 /* 501 /*
502 * An empty command before a ; doesn't make much sense, and 502 * An empty command before a ; doesn't make much sense, and
503 * should certainly be disallowed in the case of `if ;'. 503 * should certainly be disallowed in the case of `if ;'.
504 */ 504 */
505 if (!redir) 505 if (!redir)
506 synexpect(-1, 0); 506 synexpect(-1, 0);
507 case TAND: 507 case TAND:
508 case TOR: 508 case TOR:
509 case TNL: 509 case TNL:
510 case TEOF: 510 case TEOF:
511 case TWORD: 511 case TWORD:
512 case TRP: 512 case TRP:
513 tokpushback++; 513 tokpushback++;
514 n1 = simplecmd(rpp, redir); 514 n1 = simplecmd(rpp, redir);
515 goto checkneg; 515 goto checkneg;
516 case TENDCASE: 516 case TENDCASE:
517 if (redir) { 517 if (redir) {
518 tokpushback++; 518 tokpushback++;
519 goto checkneg; 519 goto checkneg;
520 } 520 }
521 /* FALLTHROUGH */ 521 /* FALLTHROUGH */
522 default: 522 default:
523 synexpect(-1, 0); 523 synexpect(-1, 0);
524 /* NOTREACHED */ 524 /* NOTREACHED */
525 } 525 }
526 526
527 /* Now check for redirection which may follow command */ 527 /* Now check for redirection which may follow command */
528 while (readtoken() == TREDIR) { 528 while (readtoken() == TREDIR) {
529 *rpp = n2 = redirnode; 529 *rpp = n2 = redirnode;
530 rpp = &n2->nfile.next; 530 rpp = &n2->nfile.next;
531 parsefname(); 531 parsefname();
532 } 532 }
533 tokpushback++; 533 tokpushback++;
534 *rpp = NULL; 534 *rpp = NULL;
535 if (redir) { 535 if (redir) {
536 if (n1->type != NSUBSHELL) { 536 if (n1->type != NSUBSHELL) {
537 n2 = stalloc(sizeof(struct nredir)); 537 n2 = stalloc(sizeof(struct nredir));
538 n2->type = NREDIR; 538 n2->type = NREDIR;
539 n2->nredir.n = n1; 539 n2->nredir.n = n1;
540 n1 = n2; 540 n1 = n2;
541 } 541 }
542 n1->nredir.redirect = redir; 542 n1->nredir.redirect = redir;
543 } 543 }
544 544
545checkneg: 545checkneg:
546 if (negate) { 546 if (negate) {
547 TRACE(("negate command\n")); 547 TRACE(("negate command\n"));
548 n2 = stalloc(sizeof(struct nnot)); 548 n2 = stalloc(sizeof(struct nnot));
549 n2->type = NNOT; 549 n2->type = NNOT;
550 n2->nnot.com = n1; 550 n2->nnot.com = n1;
551 return n2; 551 return n2;
552 } 552 }
553 else 553 else
554 return n1; 554 return n1;
555} 555}
556 556
557 557
558STATIC union node * 558STATIC union node *
559simplecmd(union node **rpp, union node *redir) 559simplecmd(union node **rpp, union node *redir)
560{ 560{
561 union node *args, **app; 561 union node *args, **app;
562 union node *n = NULL, *n2; 562 union node *n = NULL, *n2;
563 int negate = 0; 563 int negate = 0;
564 564
565 /* If we don't have any redirections already, then we must reset */ 565 /* If we don't have any redirections already, then we must reset */
566 /* rpp to be the address of the local redir variable. */ 566 /* rpp to be the address of the local redir variable. */
567 if (redir == 0) 567 if (redir == 0)
568 rpp = &redir; 568 rpp = &redir;
569 569
570 args = NULL; 570 args = NULL;
571 app = &args; 571 app = &args;
572 572
573 while (readtoken() == TNOT) { 573 while (readtoken() == TNOT) {
574 TRACE(("simplcmd: TNOT recognized\n")); 574 TRACE(("simplcmd: TNOT recognized\n"));
575 negate = !negate; 575 negate = !negate;
576 } 576 }
577 tokpushback++; 577 tokpushback++;
578 578
579 for (;;) { 579 for (;;) {
580 if (readtoken() == TWORD) { 580 if (readtoken() == TWORD) {
581 n = stalloc(sizeof(struct narg)); 581 n = stalloc(sizeof(struct narg));
582 n->type = NARG; 582 n->type = NARG;
583 n->narg.text = wordtext; 583 n->narg.text = wordtext;
584 n->narg.backquote = backquotelist; 584 n->narg.backquote = backquotelist;
585 *app = n; 585 *app = n;
586 app = &n->narg.next; 586 app = &n->narg.next;
587 } else if (lasttoken == TREDIR) { 587 } else if (lasttoken == TREDIR) {
588 *rpp = n = redirnode; 588 *rpp = n = redirnode;
589 rpp = &n->nfile.next; 589 rpp = &n->nfile.next;
590 parsefname(); /* read name of redirection file */ 590 parsefname(); /* read name of redirection file */
591 } else if (lasttoken == TLP && app == &args->narg.next 591 } else if (lasttoken == TLP && app == &args->narg.next
592 && redir == 0) { 592 && redir == 0) {
593 /* We have a function */ 593 /* We have a function */
594 if (readtoken() != TRP) 594 if (readtoken() != TRP)
595 synexpect(TRP, 0); 595 synexpect(TRP, 0);
596 funclinno = plinno; 596 funclinno = plinno;
597 rmescapes(n->narg.text); 597 rmescapes(n->narg.text);
598 if (!goodname(n->narg.text)) 598 if (!goodname(n->narg.text))
599 synerror("Bad function name"); 599 synerror("Bad function name");
600 n->type = NDEFUN; 600 n->type = NDEFUN;
601 n->narg.next = command(); 601 n->narg.next = command();
602 funclinno = 0; 602 funclinno = 0;
603 goto checkneg; 603 goto checkneg;
604 } else { 604 } else {
605 tokpushback++; 605 tokpushback++;
606 break; 606 break;
607 } 607 }
608 } 608 }
609 *app = NULL; 609 *app = NULL;
610 *rpp = NULL; 610 *rpp = NULL;
611 n = stalloc(sizeof(struct ncmd)); 611 n = stalloc(sizeof(struct ncmd));
612 n->type = NCMD; 612 n->type = NCMD;
613 n->ncmd.backgnd = 0; 613 n->ncmd.backgnd = 0;
614 n->ncmd.args = args; 614 n->ncmd.args = args;
615 n->ncmd.redirect = redir; 615 n->ncmd.redirect = redir;
616 616
617checkneg: 617checkneg:
618 if (negate) { 618 if (negate) {
619 TRACE(("negate simplecmd\n")); 619 TRACE(("negate simplecmd\n"));
620 n2 = stalloc(sizeof(struct nnot)); 620 n2 = stalloc(sizeof(struct nnot));
621 n2->type = NNOT; 621 n2->type = NNOT;
622 n2->nnot.com = n; 622 n2->nnot.com = n;
623 return n2; 623 return n2;
624 } 624 }
625 else 625 else
626 return n; 626 return n;
627} 627}
628 628
629STATIC union node * 629STATIC union node *
630makename(void) 630makename(void)
631{ 631{
632 union node *n; 632 union node *n;
633 633
634 n = stalloc(sizeof(struct narg)); 634 n = stalloc(sizeof(struct narg));
635 n->type = NARG; 635 n->type = NARG;
636 n->narg.next = NULL; 636 n->narg.next = NULL;
637 n->narg.text = wordtext; 637 n->narg.text = wordtext;
638 n->narg.backquote = backquotelist; 638 n->narg.backquote = backquotelist;
639 return n; 639 return n;
640} 640}
641 641
642void 642void
643fixredir(union node *n, const char *text, int err) 643fixredir(union node *n, const char *text, int err)
644{ 644{
645 TRACE(("Fix redir %s %d\n", text, err)); 645 TRACE(("Fix redir %s %d\n", text, err));
646 if (!err) 646 if (!err)
647 n->ndup.vname = NULL; 647 n->ndup.vname = NULL;
648 648
649 if (is_number(text)) 649 if (is_number(text))
650 n->ndup.dupfd = number(text); 650 n->ndup.dupfd = number(text);
651 else if (text[0] == '-' && text[1] == '\0') 651 else if (text[0] == '-' && text[1] == '\0')
652 n->ndup.dupfd = -1; 652 n->ndup.dupfd = -1;
653 else { 653 else {
654 654
655 if (err) 655 if (err)
656 synerror("Bad fd number"); 656 synerror("Bad fd number");
657 else 657 else
658 n->ndup.vname = makename(); 658 n->ndup.vname = makename();
659 } 659 }
660} 660}
661 661
662 662
663STATIC void 663STATIC void
664parsefname(void) 664parsefname(void)
665{ 665{
666 union node *n = redirnode; 666 union node *n = redirnode;
667 667
668 if (readtoken() != TWORD) 668 if (readtoken() != TWORD)
669 synexpect(-1, 0); 669 synexpect(-1, 0);
670 if (n->type == NHERE) { 670 if (n->type == NHERE) {
671 struct heredoc *here = heredoc; 671 struct heredoc *here = heredoc;
672 struct heredoc *p; 672 struct heredoc *p;
673 673
674 if (quoteflag == 0) 674 if (quoteflag == 0)
675 n->type = NXHERE; 675 n->type = NXHERE;
676 TRACE(("Here document %d\n", n->type)); 676 TRACE(("Here document %d\n", n->type));
677 if (here->striptabs) { 677 if (here->striptabs) {
678 while (*wordtext == '\t') 678 while (*wordtext == '\t')
679 wordtext++; 679 wordtext++;
680 } 680 }
681 681
682 /* 682 /*
683 * this test is not really necessary, we are not 683 * this test is not really necessary, we are not
684 * required to expand wordtext, but there's no reason 684 * required to expand wordtext, but there's no reason
685 * it cannot be $$ or something like that - that would 685 * it cannot be $$ or something like that - that would
686 * not mean the pid, but literally two '$' characters. 686 * not mean the pid, but literally two '$' characters.
687 * There is no need for limits on what the word can be. 687 * There is no need for limits on what the word can be.
688 * However, it needs to stay literal as entered, not 688 * However, it needs to stay literal as entered, not
689 * have $ converted to CTLVAR or something, which as 689 * have $ converted to CTLVAR or something, which as
690 * the parser is, at the minute, is impossible to prevent. 690 * the parser is, at the minute, is impossible to prevent.
691 * So, leave it like this until the rest of the parser is fixed. 691 * So, leave it like this until the rest of the parser is fixed.
692 */ 692 */
693 if (! noexpand(wordtext)) 693 if (! noexpand(wordtext))
694 synerror("Illegal eof marker for << redirection"); 694 synerror("Illegal eof marker for << redirection");
695 695
696 rmescapes(wordtext); 696 rmescapes(wordtext);
697 here->eofmark = wordtext; 697 here->eofmark = wordtext;
698 here->next = NULL; 698 here->next = NULL;
699 if (heredoclist == NULL) 699 if (heredoclist == NULL)
700 heredoclist = here; 700 heredoclist = here;
701 else { 701 else {
702 for (p = heredoclist ; p->next ; p = p->next) 702 for (p = heredoclist ; p->next ; p = p->next)
703 continue; 703 continue;
704 p->next = here; 704 p->next = here;
705 } 705 }
706 } else if (n->type == NTOFD || n->type == NFROMFD) { 706 } else if (n->type == NTOFD || n->type == NFROMFD) {
707 fixredir(n, wordtext, 0); 707 fixredir(n, wordtext, 0);
708 } else { 708 } else {
709 n->nfile.fname = makename(); 709 n->nfile.fname = makename();
710 } 710 }
711} 711}
712 712
713/* 713/*
714 * Check to see whether we are at the end of the here document. When this 714 * Check to see whether we are at the end of the here document. When this
715 * is called, c is set to the first character of the next input line. If 715 * is called, c is set to the first character of the next input line. If
716 * we are at the end of the here document, this routine sets the c to PEOF. 716 * we are at the end of the here document, this routine sets the c to PEOF.
717 * The new value of c is returned. 717 * The new value of c is returned.
718 */ 718 */
719 719
720static int 720static int
721checkend(int c, char * const eofmark, const int striptabs) 721checkend(int c, char * const eofmark, const int striptabs)
722{ 722{
723 if (striptabs) { 723 if (striptabs) {
724 while (c == '\t') 724 while (c == '\t')
725 c = pgetc(); 725 c = pgetc();
726 } 726 }
727 if (c == PEOF) { 727 if (c == PEOF) {
728 if (*eofmark == '\0') 728 if (*eofmark == '\0')
729 return (c); 729 return (c);
730 synerror(EOFhere); 730 synerror(EOFhere);
731 } 731 }
732 if (c == *eofmark) { 732 if (c == *eofmark) {
733 int c2; 733 int c2;
734 char *q; 734 char *q;
735 735
736 for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++) 736 for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++)
737 ; 737 ;
738 if ((c2 == PEOF || c2 == '\n') && *q == '\0') { 738 if ((c2 == PEOF || c2 == '\n') && *q == '\0') {
739 c = PEOF; 739 c = PEOF;
740 if (c2 == '\n') { 740 if (c2 == '\n') {
741 plinno++; 741 plinno++;
742 needprompt = doprompt; 742 needprompt = doprompt;
743 } 743 }
744 } else { 744 } else {
745 pungetc(); 745 pungetc();
746 pushstring(eofmark + 1, q - (eofmark + 1), NULL); 746 pushstring(eofmark + 1, q - (eofmark + 1), NULL);
747 } 747 }
748 } else if (c == '\n' && *eofmark == '\0') { 748 } else if (c == '\n' && *eofmark == '\0') {
749 c = PEOF; 749 c = PEOF;
750 plinno++; 750 plinno++;
751 needprompt = doprompt; 751 needprompt = doprompt;
752 } 752 }
753 return (c); 753 return (c);
754} 754}
755 755
756 756
757/* 757/*
758 * Input any here documents. 758 * Input any here documents.
759 */ 759 */
760 760
761STATIC void 761STATIC void
762slurp_heredoc(char *const eofmark, int striptabs, int sq) 762slurp_heredoc(char *const eofmark, const int striptabs, const int sq)
763{ 763{
764 int c; 764 int c;
765 char *out; 765 char *out;
766 766
767 c = pgetc(); 767 c = pgetc();
768 768
769 /* 769 /*
770 * If we hit EOF on the input, and the eofmark is a null string ('') 770 * If we hit EOF on the input, and the eofmark is a null string ('')
771 * we consider this empty line to be the eofmark, and exit without err. 771 * we consider this empty line to be the eofmark, and exit without err.
772 */ 772 */
773 if (c == PEOF && *eofmark != '\0') 773 if (c == PEOF && *eofmark != '\0')
774 synerror(EOFhere); 774 synerror(EOFhere);
775 775
776 STARTSTACKSTR(out); 776 STARTSTACKSTR(out);
777 777
778 while ((c = checkend(c, eofmark, striptabs)) != PEOF) { 778 while ((c = checkend(c, eofmark, striptabs)) != PEOF) {
779 do { 779 do {
780 if (sq) { 780 if (sq) {
781 /* 781 /*
782 * in single quoted mode (eofmark quoted) 782 * in single quoted mode (eofmark quoted)
783 * all we look for is \n so we can check 783 * all we look for is \n so we can check
784 * for the epfmark - everything saved literally. 784 * for the epfmark - everything saved literally.
785 */ 785 */
786 STPUTC(c, out); 786 STPUTC(c, out);
787 if (c == '\n') 787 if (c == '\n')
788 break; 788 break;
789 continue; 789 continue;
790 } 790 }
791 /* 791 /*
792 * In double quoted (non-quoted eofmark) 792 * In double quoted (non-quoted eofmark)
793 * we must handle \ followed by \n here 793 * we must handle \ followed by \n here
794 * otherwise we can mismatch the end mark. 794 * otherwise we can mismatch the end mark.
795 * All other uses of \ will be handled later 795 * All other uses of \ will be handled later
796 * when the here doc is expanded. 796 * when the here doc is expanded.
797 * 797 *
798 * This also makes sure \\ followed by \n does 798 * This also makes sure \\ followed by \n does
799 * not suppress the newline (the \ quotes itself) 799 * not suppress the newline (the \ quotes itself)
800 */ 800 */
801 if (c == '\\') { /* A backslash */ 801 if (c == '\\') { /* A backslash */
802 c = pgetc(); /* followed by */ 802 c = pgetc(); /* followed by */
803 if (c == '\n') /* a newline? */ 803 if (c == '\n') /* a newline? */
804 continue; /* y:drop both */ 804 continue; /* y:drop both */
805 STPUTC('\\', out); /* else keep \ */ 805 STPUTC('\\', out); /* else keep \ */
806 } 806 }
807 STPUTC(c, out); /* keep the char */ 807 STPUTC(c, out); /* keep the char */
808 if (c == '\n') /* at end of line */ 808 if (c == '\n') /* at end of line */
809 break; /* look for eofmark */ 809 break; /* look for eofmark */
810 810
811 } while ((c = pgetc()) != PEOF); 811 } while ((c = pgetc()) != PEOF);
812 812
813 /* 813 /*
814 * If we have read a line, and reached EOF, without 814 * If we have read a line, and reached EOF, without
815 * finding the eofmark, whether the EOF comes before 815 * finding the eofmark, whether the EOF comes before
816 * or immediately after the \n, that is an error. 816 * or immediately after the \n, that is an error.
817 */ 817 */
818 if (c == PEOF || (c = pgetc()) == PEOF) 818 if (c == PEOF || (c = pgetc()) == PEOF)
819 synerror(EOFhere); 819 synerror(EOFhere);
820 } 820 }
821 STPUTC('\0', out); 821 STPUTC('\0', out);
822 822
823 c = out - stackblock(); 823 c = out - stackblock();
824 out = stackblock(); 824 out = stackblock();
825 grabstackblock(c); 825 grabstackblock(c);
826 wordtext = out; 826 wordtext = out;
827 827
828 TRACE(("Slurped a heredoc (to '%s')%s: len %d, \"%.16s\"...\n", 828 TRACE(("Slurped a heredoc (to '%s')%s: len %d, \"%.16s\"...\n",
829 eofmark, striptabs ? " tab stripped" : "", c, wordtext)); 829 eofmark, striptabs ? " tab stripped" : "", c, wordtext));
830} 830}
831 831
832STATIC void 832STATIC void
833readheredocs(void) 833readheredocs(void)
834{ 834{
835 struct heredoc *here; 835 struct heredoc *here;
836 union node *n; 836 union node *n;
837 837
838 while (heredoclist) { 838 while (heredoclist) {
839 here = heredoclist; 839 here = heredoclist;
840 heredoclist = here->next; 840 heredoclist = here->next;
841 if (needprompt) { 841 if (needprompt) {
842 setprompt(2); 842 setprompt(2);
843 needprompt = 0; 843 needprompt = 0;
844 } 844 }
845 845
846 slurp_heredoc(here->eofmark, here->striptabs, 846 slurp_heredoc(here->eofmark, here->striptabs,
847 here->here->nhere.type == NHERE); 847 here->here->nhere.type == NHERE);
848 848
849 n = stalloc(sizeof(struct narg)); 849 n = stalloc(sizeof(struct narg));
850 n->narg.type = NARG; 850 n->narg.type = NARG;
851 n->narg.next = NULL; 851 n->narg.next = NULL;
852 n->narg.text = wordtext; 852 n->narg.text = wordtext;
853 n->narg.backquote = backquotelist; 853 n->narg.backquote = backquotelist;
854 here->here->nhere.doc = n; 854 here->here->nhere.doc = n;
855 } 
856} 
857 
858void 
859parse_heredoc(union node *n) 
860{ 
861 if (n->narg.type != NARG) 
862 abort(); 
863 
864 if (n->narg.text[0] == '\0') /* nothing to do */ 
865 return; 
866 
867 setinputstring(n->narg.text, 1); 
868 
869 readtoken1(pgetc(), DQSYNTAX, 1); 
870 855
871 n->narg.text = wordtext; 856 if (here->here->nhere.type == NHERE)
872 n->narg.backquote = backquotelist; 857 continue;
873 858
874 popfile(); 859 /*
 860 * Now "parse" here docs that have unquoted eofmarkers.
 861 */
 862 setinputstring(wordtext, 1);
 863 readtoken1(pgetc(), DQSYNTAX, 1);
 864 n->narg.text = wordtext;
 865 n->narg.backquote = backquotelist;
 866 popfile();
 867 }
875} 868}
876 869
877STATIC int 870STATIC int
878peektoken(void) 871peektoken(void)
879{ 872{
880 int t; 873 int t;
881 874
882 t = readtoken(); 875 t = readtoken();
883 tokpushback++; 876 tokpushback++;
884 return (t); 877 return (t);
885} 878}
886 879
887STATIC int 880STATIC int
888readtoken(void) 881readtoken(void)
889{ 882{
890 int t; 883 int t;
891 int savecheckkwd = checkkwd; 884 int savecheckkwd = checkkwd;
892#ifdef DEBUG 885#ifdef DEBUG
893 int alreadyseen = tokpushback; 886 int alreadyseen = tokpushback;
894#endif 887#endif
895 struct alias *ap; 888 struct alias *ap;
896 889
897 top: 890 top:
898 t = xxreadtoken(); 891 t = xxreadtoken();
899 892
900 if (checkkwd) { 893 if (checkkwd) {
901 /* 894 /*
902 * eat newlines 895 * eat newlines
903 */ 896 */
904 if (checkkwd == 2) { 897 if (checkkwd == 2) {
905 checkkwd = 0; 898 checkkwd = 0;
906 while (t == TNL) { 899 while (t == TNL) {
907 readheredocs(); 900 readheredocs();
908 t = xxreadtoken(); 901 t = xxreadtoken();
909 } 902 }
910 } else 903 } else
911 checkkwd = 0; 904 checkkwd = 0;
912 /* 905 /*
913 * check for keywords and aliases 906 * check for keywords and aliases
914 */ 907 */
915 if (t == TWORD && !quoteflag) { 908 if (t == TWORD && !quoteflag) {
916 const char *const *pp; 909 const char *const *pp;
917 910
918 for (pp = parsekwd; *pp; pp++) { 911 for (pp = parsekwd; *pp; pp++) {
919 if (**pp == *wordtext && equal(*pp, wordtext)) { 912 if (**pp == *wordtext && equal(*pp, wordtext)) {
920 lasttoken = t = pp - 913 lasttoken = t = pp -
921 parsekwd + KWDOFFSET; 914 parsekwd + KWDOFFSET;
922 TRACE(("keyword %s recognized\n", tokname[t])); 915 TRACE(("keyword %s recognized\n", tokname[t]));
923 goto out; 916 goto out;
924 } 917 }
925 } 918 }
926 if (!noalias && 919 if (!noalias &&
927 (ap = lookupalias(wordtext, 1)) != NULL) { 920 (ap = lookupalias(wordtext, 1)) != NULL) {
928 pushstring(ap->val, strlen(ap->val), ap); 921 pushstring(ap->val, strlen(ap->val), ap);
929 checkkwd = savecheckkwd; 922 checkkwd = savecheckkwd;
930 goto top; 923 goto top;
931 } 924 }
932 } 925 }
933out: 926out:
934 checkkwd = (t == TNOT) ? savecheckkwd : 0; 927 checkkwd = (t == TNOT) ? savecheckkwd : 0;
935 } 928 }
936 TRACE(("%stoken %s %s\n", alreadyseen ? "reread " : "", tokname[t], t == TWORD ? wordtext : "")); 929 TRACE(("%stoken %s %s\n", alreadyseen ? "reread " : "", tokname[t], t == TWORD ? wordtext : ""));
937 return (t); 930 return (t);
938} 931}
939 932
940 933
941/* 934/*
942 * Read the next input token. 935 * Read the next input token.
943 * If the token is a word, we set backquotelist to the list of cmds in 936 * If the token is a word, we set backquotelist to the list of cmds in
944 * backquotes. We set quoteflag to true if any part of the word was 937 * backquotes. We set quoteflag to true if any part of the word was
945 * quoted. 938 * quoted.
946 * If the token is TREDIR, then we set redirnode to a structure containing 939 * If the token is TREDIR, then we set redirnode to a structure containing
947 * the redirection. 940 * the redirection.
948 * In all cases, the variable startlinno is set to the number of the line 941 * In all cases, the variable startlinno is set to the number of the line
949 * on which the token starts. 942 * on which the token starts.
950 * 943 *
951 * [Change comment: here documents and internal procedures] 944 * [Change comment: here documents and internal procedures]
952 * [Readtoken shouldn't have any arguments. Perhaps we should make the 945 * [Readtoken shouldn't have any arguments. Perhaps we should make the
953 * word parsing code into a separate routine. In this case, readtoken 946 * word parsing code into a separate routine. In this case, readtoken
954 * doesn't need to have any internal procedures, but parseword does. 947 * doesn't need to have any internal procedures, but parseword does.
955 * We could also make parseoperator in essence the main routine, and 948 * We could also make parseoperator in essence the main routine, and
956 * have parseword (readtoken1?) handle both words and redirection.] 949 * have parseword (readtoken1?) handle both words and redirection.]
957 */ 950 */
958 951
959#define RETURN(token) return lasttoken = token 952#define RETURN(token) return lasttoken = token
960 953
961STATIC int 954STATIC int
962xxreadtoken(void) 955xxreadtoken(void)
963{ 956{
964 int c; 957 int c;
965 958
966 if (tokpushback) { 959 if (tokpushback) {
967 tokpushback = 0; 960 tokpushback = 0;
968 return lasttoken; 961 return lasttoken;
969 } 962 }
970 if (needprompt) { 963 if (needprompt) {
971 setprompt(2); 964 setprompt(2);
972 needprompt = 0; 965 needprompt = 0;
973 } 966 }
974 startlinno = plinno; 967 startlinno = plinno;
975 for (;;) { /* until token or start of word found */ 968 for (;;) { /* until token or start of word found */
976 c = pgetc_macro(); 969 c = pgetc_macro();
977 switch (c) { 970 switch (c) {
978 case ' ': case '\t': 971 case ' ': case '\t':
979 continue; 972 continue;
980 case '#': 973 case '#':
981 while ((c = pgetc()) != '\n' && c != PEOF) 974 while ((c = pgetc()) != '\n' && c != PEOF)
982 continue; 975 continue;
983 pungetc(); 976 pungetc();
984 continue; 977 continue;
985 978
986 case '\n': 979 case '\n':
987 plinno++; 980 plinno++;
988 needprompt = doprompt; 981 needprompt = doprompt;
989 RETURN(TNL); 982 RETURN(TNL);
990 case PEOF: 983 case PEOF:
991 RETURN(TEOF); 984 RETURN(TEOF);
992 985
993 case '&': 986 case '&':
994 if (pgetc() == '&') 987 if (pgetc() == '&')
995 RETURN(TAND); 988 RETURN(TAND);
996 pungetc(); 989 pungetc();
997 RETURN(TBACKGND); 990 RETURN(TBACKGND);
998 case '|': 991 case '|':
999 if (pgetc() == '|') 992 if (pgetc() == '|')
1000 RETURN(TOR); 993 RETURN(TOR);
1001 pungetc(); 994 pungetc();
1002 RETURN(TPIPE); 995 RETURN(TPIPE);
1003 case ';': 996 case ';':
1004 if (pgetc() == ';') 997 if (pgetc() == ';')
1005 RETURN(TENDCASE); 998 RETURN(TENDCASE);
1006 pungetc(); 999 pungetc();
1007 RETURN(TSEMI); 1000 RETURN(TSEMI);
1008 case '(': 1001 case '(':
1009 RETURN(TLP); 1002 RETURN(TLP);
1010 case ')': 1003 case ')':
1011 RETURN(TRP); 1004 RETURN(TRP);
1012 1005
1013 case '\\': 1006 case '\\':
1014 switch (pgetc()) { 1007 switch (pgetc()) {
1015 case '\n': 1008 case '\n':
1016 startlinno = ++plinno; 1009 startlinno = ++plinno;
1017 if (doprompt) 1010 if (doprompt)
1018 setprompt(2); 1011 setprompt(2);
1019 else 1012 else
1020 setprompt(0); 1013 setprompt(0);
1021 continue; 1014 continue;
1022 case PEOF: 1015 case PEOF:
1023 RETURN(TEOF); 1016 RETURN(TEOF);
1024 default: 1017 default:
1025 pungetc(); 1018 pungetc();
1026 break; 1019 break;
1027 } 1020 }
1028 /* FALLTHROUGH */ 1021 /* FALLTHROUGH */
1029 default: 1022 default:
1030 return readtoken1(c, BASESYNTAX, 0); 1023 return readtoken1(c, BASESYNTAX, 0);
1031 } 1024 }
1032 } 1025 }
1033#undef RETURN 1026#undef RETURN
1034} 1027}
1035 1028
1036 1029
1037 1030
1038/* 1031/*
1039 * If eofmark is NULL, read a word or a redirection symbol. If eofmark 1032 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
1040 * is not NULL, read a here document. In the latter case, eofmark is the 1033 * is not NULL, read a here document. In the latter case, eofmark is the
1041 * word which marks the end of the document and striptabs is true if 1034 * word which marks the end of the document and striptabs is true if
1042 * leading tabs should be stripped from the document. The argument firstc 1035 * leading tabs should be stripped from the document. The argument firstc
1043 * is the first character of the input token or document. 1036 * is the first character of the input token or document.
1044 * 1037 *
1045 * Because C does not have internal subroutines, I have simulated them 1038 * Because C does not have internal subroutines, I have simulated them
1046 * using goto's to implement the subroutine linkage. The following macros 1039 * using goto's to implement the subroutine linkage. The following macros
1047 * will run code that appears at the end of readtoken1. 1040 * will run code that appears at the end of readtoken1.
1048 */ 1041 */
1049 1042
1050/* 1043/*
1051 * We used to remember only the current syntax, variable nesting level, 1044 * We used to remember only the current syntax, variable nesting level,
1052 * double quote state for each var nesting level, and arith nesting 1045 * double quote state for each var nesting level, and arith nesting
1053 * level (unrelated to var nesting) and one prev syntax when in arith 1046 * level (unrelated to var nesting) and one prev syntax when in arith
1054 * syntax. This worked for simple cases, but can't handle arith inside 1047 * syntax. This worked for simple cases, but can't handle arith inside
1055 * var expansion inside arith inside var with some quoted and some not. 1048 * var expansion inside arith inside var with some quoted and some not.
1056 * 1049 *
1057 * Inspired by FreeBSD's implementation (though it was the obvious way) 1050 * Inspired by FreeBSD's implementation (though it was the obvious way)
1058 * though implemented differently, we now have a stack that keeps track 1051 * though implemented differently, we now have a stack that keeps track
1059 * of what we are doing now, and what we were doing previously. 1052 * of what we are doing now, and what we were doing previously.
1060 * Every time something changes, which will eventually end and should 1053 * Every time something changes, which will eventually end and should
1061 * revert to the previous state, we push this stack, and then pop it 1054 * revert to the previous state, we push this stack, and then pop it
1062 * again later (that is every ${} with an operator (to parse the word 1055 * again later (that is every ${} with an operator (to parse the word
1063 * or pattern that follows) ${x} and $x are too simple to need it) 1056 * or pattern that follows) ${x} and $x are too simple to need it)
1064 * $(( )) $( ) and "...". Always. Really, always! 1057 * $(( )) $( ) and "...". Always. Really, always!
1065 * 1058 *
1066 * The stack is implemented as one static (on the C stack) base block 1059 * The stack is implemented as one static (on the C stack) base block
1067 * containing LEVELS_PER_BLOCK (8) stack entries, which should be 1060 * containing LEVELS_PER_BLOCK (8) stack entries, which should be
1068 * enough for the vast majority of cases. For torture tests, we 1061 * enough for the vast majority of cases. For torture tests, we
1069 * malloc more blocks as needed. All accesses through the inline 1062 * malloc more blocks as needed. All accesses through the inline
1070 * functions below. 1063 * functions below.
1071 */ 1064 */
1072 1065
1073/* 1066/*
1074 * varnest & arinest will typically be 0 or 1 1067 * varnest & arinest will typically be 0 or 1
1075 * (varnest can increment in usages like ${x=${y}} but probably 1068 * (varnest can increment in usages like ${x=${y}} but probably
1076 * does not really need to) 1069 * does not really need to)
1077 * parenlevel allows balancing parens inside a $(( )), it is reset 1070 * parenlevel allows balancing parens inside a $(( )), it is reset
1078 * at each new nesting level ( $(( ( x + 3 ${unset-)} )) does not work. 1071 * at each new nesting level ( $(( ( x + 3 ${unset-)} )) does not work.
1079 * quoted is special - we need to know 2 things ... are we inside "..." 1072 * quoted is special - we need to know 2 things ... are we inside "..."
1080 * (even if inherited from some previous nesting level) and was there 1073 * (even if inherited from some previous nesting level) and was there
1081 * an opening '"' at this level (so the next will be closing). 1074 * an opening '"' at this level (so the next will be closing).
1082 * "..." can span nesting levels, but cannot be opened in one and 1075 * "..." can span nesting levels, but cannot be opened in one and
1083 * closed in a different one. 1076 * closed in a different one.
1084 * To handle this, "quoted" has two fields, the bottom 4 (really 2) 1077 * To handle this, "quoted" has two fields, the bottom 4 (really 2)
1085 * bits are 0, 1, or 2, for un, single, and double quoted (single quoted 1078 * bits are 0, 1, or 2, for un, single, and double quoted (single quoted
1086 * is really so special that this setting is not very important) 1079 * is really so special that this setting is not very important)
1087 * and 0x10 that indicates that an opening quote has been seen. 1080 * and 0x10 that indicates that an opening quote has been seen.
1088 * The bottom 4 bits are inherited, the 0x10 bit is not. 1081 * The bottom 4 bits are inherited, the 0x10 bit is not.
1089 */ 1082 */
1090struct tokenstate { 1083struct tokenstate {
1091 const char *ts_syntax; 1084 const char *ts_syntax;
1092 unsigned short ts_parenlevel; /* counters */ 1085 unsigned short ts_parenlevel; /* counters */
1093 unsigned short ts_varnest; /* 64000 levels should be enough! */ 1086 unsigned short ts_varnest; /* 64000 levels should be enough! */
1094 unsigned short ts_arinest; 1087 unsigned short ts_arinest;
1095 unsigned short ts_quoted; /* 1 -> single, 2 -> double */ 1088 unsigned short ts_quoted; /* 1 -> single, 2 -> double */
1096}; 1089};
1097 1090
1098#define NQ 0x00 /* Unquoted */ 1091#define NQ 0x00 /* Unquoted */
1099#define SQ 0x01 /* Single Quotes */ 1092#define SQ 0x01 /* Single Quotes */
1100#define DQ 0x02 /* Double Quotes (or equivalent) */ 1093#define DQ 0x02 /* Double Quotes (or equivalent) */
1101#define QF 0x0F /* Mask to extract previous values */ 1094#define QF 0x0F /* Mask to extract previous values */
1102#define QS 0x10 /* Quoting started at this level in stack */ 1095#define QS 0x10 /* Quoting started at this level in stack */
1103 1096
1104#define LEVELS_PER_BLOCK 8 1097#define LEVELS_PER_BLOCK 8
1105#define VSS struct statestack 1098#define VSS struct statestack
1106 1099
1107struct statestack { 1100struct statestack {
1108 VSS *prev; /* previous block in list */ 1101 VSS *prev; /* previous block in list */
1109 int cur; /* which of our tokenstates is current */ 1102 int cur; /* which of our tokenstates is current */
1110 struct tokenstate tokenstate[LEVELS_PER_BLOCK]; 1103 struct tokenstate tokenstate[LEVELS_PER_BLOCK];
1111}; 1104};
1112 1105
1113static inline struct tokenstate * 1106static inline struct tokenstate *
1114currentstate(VSS *stack) 1107currentstate(VSS *stack)
1115{ 1108{
1116 return &stack->tokenstate[stack->cur]; 1109 return &stack->tokenstate[stack->cur];
1117} 1110}
1118 1111
1119static inline struct tokenstate * 1112static inline struct tokenstate *
1120prevstate(VSS *stack) 1113prevstate(VSS *stack)
1121{ 1114{
1122 if (stack->cur != 0) 1115 if (stack->cur != 0)
1123 return &stack->tokenstate[stack->cur - 1]; 1116 return &stack->tokenstate[stack->cur - 1];
1124 if (stack->prev == NULL) /* cannot drop below base */ 1117 if (stack->prev == NULL) /* cannot drop below base */
1125 return &stack->tokenstate[0]; 1118 return &stack->tokenstate[0];
1126 return &stack->prev->tokenstate[LEVELS_PER_BLOCK - 1]; 1119 return &stack->prev->tokenstate[LEVELS_PER_BLOCK - 1];
1127} 1120}
1128 1121
1129static inline VSS * 1122static inline VSS *
1130bump_state_level(VSS *stack) 1123bump_state_level(VSS *stack)
1131{ 1124{
1132 struct tokenstate *os, *ts; 1125 struct tokenstate *os, *ts;
1133 1126
1134 os = currentstate(stack); 1127 os = currentstate(stack);
1135 1128
1136 if (++stack->cur >= LEVELS_PER_BLOCK) { 1129 if (++stack->cur >= LEVELS_PER_BLOCK) {
1137 VSS *ss; 1130 VSS *ss;
1138 1131
1139 ss = (VSS *)ckmalloc(sizeof (struct statestack)); 1132 ss = (VSS *)ckmalloc(sizeof (struct statestack));
1140 ss->cur = 0; 1133 ss->cur = 0;
1141 ss->prev = stack; 1134 ss->prev = stack;
1142 stack = ss; 1135 stack = ss;
1143 } 1136 }
1144 1137
1145 ts = currentstate(stack); 1138 ts = currentstate(stack);
1146 1139
1147 ts->ts_parenlevel = 0; /* parens inside never match outside */ 1140 ts->ts_parenlevel = 0; /* parens inside never match outside */
1148 1141
1149 ts->ts_quoted = os->ts_quoted & QF; /* these are default settings */ 1142 ts->ts_quoted = os->ts_quoted & QF; /* these are default settings */
1150 ts->ts_varnest = os->ts_varnest; 1143 ts->ts_varnest = os->ts_varnest;
1151 ts->ts_arinest = os->ts_arinest; /* when appropriate */ 1144 ts->ts_arinest = os->ts_arinest; /* when appropriate */
1152 ts->ts_syntax = os->ts_syntax; /* they will be altered */ 1145 ts->ts_syntax = os->ts_syntax; /* they will be altered */
1153 1146
1154 return stack; 1147 return stack;
1155} 1148}
1156 1149
1157static inline VSS * 1150static inline VSS *
1158drop_state_level(VSS *stack) 1151drop_state_level(VSS *stack)
1159{ 1152{
1160 if (stack->cur == 0) { 1153 if (stack->cur == 0) {
1161 VSS *ss; 1154 VSS *ss;
1162 1155
1163 ss = stack; 1156 ss = stack;
1164 stack = ss->prev; 1157 stack = ss->prev;
1165 if (stack == NULL) 1158 if (stack == NULL)
1166 return ss; 1159 return ss;
1167 ckfree(ss); 1160 ckfree(ss);
1168 } 1161 }
1169 --stack->cur; 1162 --stack->cur;
1170 return stack; 1163 return stack;
1171} 1164}
1172 1165
1173static inline void 1166static inline void
1174cleanup_state_stack(VSS *stack) 1167cleanup_state_stack(VSS *stack)
1175{ 1168{
1176 while (stack->prev != NULL) { 1169 while (stack->prev != NULL) {
1177 stack->cur = 0; 1170 stack->cur = 0;
1178 stack = drop_state_level(stack); 1171 stack = drop_state_level(stack);
1179 } 1172 }
1180} 1173}
1181 1174
1182#define PARSESUB() {goto parsesub; parsesub_return:;} 1175#define PARSESUB() {goto parsesub; parsesub_return:;}
1183#define PARSEARITH() {goto parsearith; parsearith_return:;} 1176#define PARSEARITH() {goto parsearith; parsearith_return:;}
1184 1177
1185/* 1178/*
1186 * The following macros all assume the existance of a local var "stack" 1179 * The following macros all assume the existance of a local var "stack"
1187 * which contains a pointer to the current struct stackstate 1180 * which contains a pointer to the current struct stackstate
1188 */ 1181 */
1189 1182
1190/* 1183/*
1191 * These are macros rather than inline funcs to avoid code churn as much 1184 * These are macros rather than inline funcs to avoid code churn as much
1192 * as possible - they replace macros of the same name used previously. 1185 * as possible - they replace macros of the same name used previously.
1193 */ 1186 */
1194#define ISDBLQUOTE() (currentstate(stack)->ts_quoted & QS) 1187#define ISDBLQUOTE() (currentstate(stack)->ts_quoted & QS)
1195#define SETDBLQUOTE() (currentstate(stack)->ts_quoted = QS | DQ) 1188#define SETDBLQUOTE() (currentstate(stack)->ts_quoted = QS | DQ)
1196#define CLRDBLQUOTE() (currentstate(stack)->ts_quoted = \ 1189#define CLRDBLQUOTE() (currentstate(stack)->ts_quoted = \
1197 stack->cur != 0 || stack->prev ? \ 1190 stack->cur != 0 || stack->prev ? \
1198 prevstate(stack)->ts_quoted & QF : 0) 1191 prevstate(stack)->ts_quoted & QF : 0)
1199 1192
1200/* 1193/*
1201 * This set are just to avoid excess typing and line lengths... 1194 * This set are just to avoid excess typing and line lengths...
1202 * The ones that "look like" var names must be implemented to be lvalues 1195 * The ones that "look like" var names must be implemented to be lvalues
1203 */ 1196 */
1204#define syntax (currentstate(stack)->ts_syntax) 1197#define syntax (currentstate(stack)->ts_syntax)
1205#define parenlevel (currentstate(stack)->ts_parenlevel) 1198#define parenlevel (currentstate(stack)->ts_parenlevel)
1206#define varnest (currentstate(stack)->ts_varnest) 1199#define varnest (currentstate(stack)->ts_varnest)
1207#define arinest (currentstate(stack)->ts_arinest) 1200#define arinest (currentstate(stack)->ts_arinest)
1208#define quoted (currentstate(stack)->ts_quoted) 1201#define quoted (currentstate(stack)->ts_quoted)
1209#define TS_PUSH() (stack = bump_state_level(stack)) 1202#define TS_PUSH() (stack = bump_state_level(stack))
1210#define TS_POP() (stack = drop_state_level(stack)) 1203#define TS_POP() (stack = drop_state_level(stack))
1211 1204
1212/* 1205/*
1213 * Called to parse command substitutions. oldstyle is true if the command 1206 * Called to parse command substitutions. oldstyle is true if the command
1214 * is enclosed inside `` (otherwise it was enclosed in "$( )") 1207 * is enclosed inside `` (otherwise it was enclosed in "$( )")
1215 * 1208 *
1216 * Internally nlpp is a pointer to the head of the linked 1209 * Internally nlpp is a pointer to the head of the linked
1217 * list of commands (passed by reference), and savelen is the number of 1210 * list of commands (passed by reference), and savelen is the number of
1218 * characters on the top of the stack which must be preserved. 1211 * characters on the top of the stack which must be preserved.
1219 */ 1212 */
1220static char * 1213static char *
1221parsebackq(VSS *const stack, char * const in, 1214parsebackq(VSS *const stack, char * const in,
1222 struct nodelist **const pbqlist, const int oldstyle) 1215 struct nodelist **const pbqlist, const int oldstyle)
1223{ 1216{
1224 struct nodelist **nlpp; 1217 struct nodelist **nlpp;
1225 const int savepbq = parsebackquote; 1218 const int savepbq = parsebackquote;
1226 union node *n; 1219 union node *n;
1227 char *out; 1220 char *out;
1228 char *str = NULL; 1221 char *str = NULL;
1229 char *volatile sstr = str; 1222 char *volatile sstr = str;
1230 struct jmploc jmploc; 1223 struct jmploc jmploc;
1231 struct jmploc *const savehandler = handler; 1224 struct jmploc *const savehandler = handler;
1232 const int savelen = in - stackblock(); 1225 const int savelen = in - stackblock();
1233 int saveprompt; 1226 int saveprompt;
1234 1227
1235 if (setjmp(jmploc.loc)) { 1228 if (setjmp(jmploc.loc)) {
1236 if (sstr) 1229 if (sstr)
1237 ckfree(__UNVOLATILE(sstr)); 1230 ckfree(__UNVOLATILE(sstr));
1238 cleanup_state_stack(stack); 1231 cleanup_state_stack(stack);
1239 parsebackquote = 0; 1232 parsebackquote = 0;
1240 handler = savehandler; 1233 handler = savehandler;
1241 longjmp(handler->loc, 1); 1234 longjmp(handler->loc, 1);
1242 } 1235 }
1243 INTOFF; 1236 INTOFF;
1244 sstr = str = NULL; 1237 sstr = str = NULL;
1245 if (savelen > 0) { 1238 if (savelen > 0) {
1246 sstr = str = ckmalloc(savelen); 1239 sstr = str = ckmalloc(savelen);
1247 memcpy(str, stackblock(), savelen); 1240 memcpy(str, stackblock(), savelen);
1248 } 1241 }
1249 handler = &jmploc; 1242 handler = &jmploc;
1250 INTON; 1243 INTON;
1251 if (oldstyle) { 1244 if (oldstyle) {
1252 /* We must read until the closing backquote, giving special 1245 /* We must read until the closing backquote, giving special
1253 treatment to some slashes, and then push the string and 1246 treatment to some slashes, and then push the string and
1254 reread it as input, interpreting it normally. */ 1247 reread it as input, interpreting it normally. */
1255 int pc; 1248 int pc;
1256 int psavelen; 1249 int psavelen;
1257 char *pstr; 1250 char *pstr;
1258 1251
1259 /* 1252 /*
1260 * Because the entire `...` is read here, we don't 1253 * Because the entire `...` is read here, we don't
1261 * need to bother the state stack. That will be used 1254 * need to bother the state stack. That will be used
1262 * (as appropriate) when the processed string is re-read. 1255 * (as appropriate) when the processed string is re-read.
1263 */ 1256 */
1264 STARTSTACKSTR(out); 1257 STARTSTACKSTR(out);
1265 for (;;) { 1258 for (;;) {
1266 if (needprompt) { 1259 if (needprompt) {
1267 setprompt(2); 1260 setprompt(2);
1268 needprompt = 0; 1261 needprompt = 0;
1269 } 1262 }
1270 switch (pc = pgetc()) { 1263 switch (pc = pgetc()) {
1271 case '`': 1264 case '`':
1272 goto done; 1265 goto done;
1273 1266
1274 case '\\': 1267 case '\\':
1275 if ((pc = pgetc()) == '\n') { 1268 if ((pc = pgetc()) == '\n') {
1276 plinno++; 1269 plinno++;
1277 if (doprompt) 1270 if (doprompt)
1278 setprompt(2); 1271 setprompt(2);
1279 else 1272 else
1280 setprompt(0); 1273 setprompt(0);
1281 /* 1274 /*
1282 * If eating a newline, avoid putting 1275 * If eating a newline, avoid putting
1283 * the newline into the new character 1276 * the newline into the new character
1284 * stream (via the STPUTC after the 1277 * stream (via the STPUTC after the
1285 * switch). 1278 * switch).
1286 */ 1279 */
1287 continue; 1280 continue;
1288 } 1281 }
1289 if (pc != '\\' && pc != '`' && pc != '$' 1282 if (pc != '\\' && pc != '`' && pc != '$'
1290 && (!ISDBLQUOTE() || pc != '"')) 1283 && (!ISDBLQUOTE() || pc != '"'))
1291 STPUTC('\\', out); 1284 STPUTC('\\', out);
1292 break; 1285 break;
1293 1286
1294 case '\n': 1287 case '\n':
1295 plinno++; 1288 plinno++;
1296 needprompt = doprompt; 1289 needprompt = doprompt;
1297 break; 1290 break;
1298 1291
1299 case PEOF: 1292 case PEOF:
1300 startlinno = plinno; 1293 startlinno = plinno;
1301 synerror("EOF in backquote substitution"); 1294 synerror("EOF in backquote substitution");
1302 break; 1295 break;
1303 1296
1304 default: 1297 default:
1305 break; 1298 break;
1306 } 1299 }
1307 STPUTC(pc, out); 1300 STPUTC(pc, out);
1308 } 1301 }
1309done: 1302done:
1310 STPUTC('\0', out); 1303 STPUTC('\0', out);
1311 psavelen = out - stackblock(); 1304 psavelen = out - stackblock();
1312 if (psavelen > 0) { 1305 if (psavelen > 0) {
1313 pstr = grabstackstr(out); 1306 pstr = grabstackstr(out);
1314 setinputstring(pstr, 1); 1307 setinputstring(pstr, 1);
1315 } 1308 }
1316 } 1309 }
1317 nlpp = pbqlist; 1310 nlpp = pbqlist;
1318 while (*nlpp) 1311 while (*nlpp)
1319 nlpp = &(*nlpp)->next; 1312 nlpp = &(*nlpp)->next;
1320 *nlpp = stalloc(sizeof(struct nodelist)); 1313 *nlpp = stalloc(sizeof(struct nodelist));
1321 (*nlpp)->next = NULL; 1314 (*nlpp)->next = NULL;
1322 parsebackquote = oldstyle; 1315 parsebackquote = oldstyle;
1323 1316
1324 if (oldstyle) { 1317 if (oldstyle) {
1325 saveprompt = doprompt; 1318 saveprompt = doprompt;
1326 doprompt = 0; 1319 doprompt = 0;
1327 } else 1320 } else
1328 saveprompt = 0; 1321 saveprompt = 0;
1329 1322
1330 n = list(0, oldstyle); 1323 n = list(0, oldstyle);
1331 1324
1332 if (oldstyle) 1325 if (oldstyle)
1333 doprompt = saveprompt; 1326 doprompt = saveprompt;
1334 else { 1327 else {
1335 if (readtoken() != TRP) { 1328 if (readtoken() != TRP) {
1336 cleanup_state_stack(stack); 1329 cleanup_state_stack(stack);
1337 synexpect(TRP, 0); 1330 synexpect(TRP, 0);
1338 } 1331 }
1339 } 1332 }
1340 1333
1341 (*nlpp)->n = n; 1334 (*nlpp)->n = n;
1342 if (oldstyle) { 1335 if (oldstyle) {
1343 /* 1336 /*
1344 * Start reading from old file again, ignoring any pushed back 1337 * Start reading from old file again, ignoring any pushed back
1345 * tokens left from the backquote parsing 1338 * tokens left from the backquote parsing
1346 */ 1339 */
1347 popfile(); 1340 popfile();
1348 tokpushback = 0; 1341 tokpushback = 0;
1349 } 1342 }
1350 1343
1351 while (stackblocksize() <= savelen) 1344 while (stackblocksize() <= savelen)
1352 growstackblock(); 1345 growstackblock();
1353 STARTSTACKSTR(out); 1346 STARTSTACKSTR(out);
1354 if (str) { 1347 if (str) {
1355 memcpy(out, str, savelen); 1348 memcpy(out, str, savelen);
1356 STADJUST(savelen, out); 1349 STADJUST(savelen, out);
1357 INTOFF; 1350 INTOFF;
1358 ckfree(str); 1351 ckfree(str);
1359 sstr = str = NULL; 1352 sstr = str = NULL;
1360 INTON; 1353 INTON;
1361 } 1354 }
1362 parsebackquote = savepbq; 1355 parsebackquote = savepbq;
1363 handler = savehandler; 1356 handler = savehandler;
1364 if (arinest || ISDBLQUOTE()) 1357 if (arinest || ISDBLQUOTE())
1365 USTPUTC(CTLBACKQ | CTLQUOTE, out); 1358 USTPUTC(CTLBACKQ | CTLQUOTE, out);
1366 else 1359 else
1367 USTPUTC(CTLBACKQ, out); 1360 USTPUTC(CTLBACKQ, out);
1368 1361
1369 return out; 1362 return out;
1370} 1363}
1371 1364
1372/* 1365/*
1373 * Parse a redirection operator. The parameter "out" points to a string 1366 * Parse a redirection operator. The parameter "out" points to a string
1374 * specifying the fd to be redirected. It is guaranteed to be either "" 1367 * specifying the fd to be redirected. It is guaranteed to be either ""
1375 * or a numeric string (for now anyway). The parameter "c" contains the 1368 * or a numeric string (for now anyway). The parameter "c" contains the
1376 * first character of the redirection operator. 1369 * first character of the redirection operator.
1377 * 1370 *
1378 * Note the string "out" is on the stack, which we are about to clobber, 1371 * Note the string "out" is on the stack, which we are about to clobber,
1379 * so process it first... 1372 * so process it first...
1380 */ 1373 */
1381 1374
1382static void 1375static void
1383parseredir(const char *out, int c) 1376parseredir(const char *out, int c)
1384{ 1377{
1385 union node *np; 1378 union node *np;
1386 int fd; 1379 int fd;
1387 1380
1388 fd = (*out == '\0') ? -1 : atoi(out); 1381 fd = (*out == '\0') ? -1 : atoi(out);
1389 1382
1390 np = stalloc(sizeof(struct nfile)); 1383 np = stalloc(sizeof(struct nfile));
1391 if (c == '>') { 1384 if (c == '>') {
1392 if (fd < 0) 1385 if (fd < 0)
1393 fd = 1; 1386 fd = 1;
1394 c = pgetc(); 1387 c = pgetc();
1395 if (c == '>') 1388 if (c == '>')
1396 np->type = NAPPEND; 1389 np->type = NAPPEND;
1397 else if (c == '|') 1390 else if (c == '|')
1398 np->type = NCLOBBER; 1391 np->type = NCLOBBER;
1399 else if (c == '&') 1392 else if (c == '&')
1400 np->type = NTOFD; 1393 np->type = NTOFD;
1401 else { 1394 else {
1402 np->type = NTO; 1395 np->type = NTO;
1403 pungetc(); 1396 pungetc();
1404 } 1397 }
1405 } else { /* c == '<' */ 1398 } else { /* c == '<' */
1406 if (fd < 0) 1399 if (fd < 0)
1407 fd = 0; 1400 fd = 0;
1408 switch (c = pgetc()) { 1401 switch (c = pgetc()) {
1409 case '<': 1402 case '<':
1410 if (sizeof (struct nfile) != sizeof (struct nhere)) { 1403 if (sizeof (struct nfile) != sizeof (struct nhere)) {
1411 np = stalloc(sizeof(struct nhere)); 1404 np = stalloc(sizeof(struct nhere));
1412 np->nfile.fd = 0; 1405 np->nfile.fd = 0;
1413 } 1406 }
1414 np->type = NHERE; 1407 np->type = NHERE;
1415 heredoc = stalloc(sizeof(struct heredoc)); 1408 heredoc = stalloc(sizeof(struct heredoc));
1416 heredoc->here = np; 1409 heredoc->here = np;
1417 if ((c = pgetc()) == '-') { 1410 if ((c = pgetc()) == '-') {
1418 heredoc->striptabs = 1; 1411 heredoc->striptabs = 1;
1419 } else { 1412 } else {
1420 heredoc->striptabs = 0; 1413 heredoc->striptabs = 0;
1421 pungetc(); 1414 pungetc();
1422 } 1415 }
1423 break; 1416 break;
1424 1417
1425 case '&': 1418 case '&':
1426 np->type = NFROMFD; 1419 np->type = NFROMFD;
1427 break; 1420 break;
1428 1421
1429 case '>': 1422 case '>':
1430 np->type = NFROMTO; 1423 np->type = NFROMTO;
1431 break; 1424 break;
1432 1425
1433 default: 1426 default:
1434 np->type = NFROM; 1427 np->type = NFROM;
1435 pungetc(); 1428 pungetc();
1436 break; 1429 break;
1437 } 1430 }
1438 } 1431 }
1439 np->nfile.fd = fd; 1432 np->nfile.fd = fd;
1440 1433
1441 redirnode = np; /* this is the "value" of TRENODE */ 1434 redirnode = np; /* this is the "value" of TRENODE */
1442} 1435}
1443 1436
1444 1437
1445/* 1438/*
1446 * The lowest level basic tokenizer. 1439 * The lowest level basic tokenizer.
1447 * 1440 *
1448 * The next input byte (character) is in firstc, syn says which 1441 * The next input byte (character) is in firstc, syn says which
1449 * syntax tables we are to use (basic, single or double quoted, or arith) 1442 * syntax tables we are to use (basic, single or double quoted, or arith)
1450 * and magicq (used with sqsyntax and dqsyntax only) indicates that the 1443 * and magicq (used with sqsyntax and dqsyntax only) indicates that the
1451 * quote character itself is not special (used parsing here docs and similar) 1444 * quote character itself is not special (used parsing here docs and similar)
1452 * 1445 *
1453 * The result is the type of the next token (its value, when there is one, 1446 * The result is the type of the next token (its value, when there is one,
1454 * is saved in the relevant global var - must fix that someday!) which is 1447 * is saved in the relevant global var - must fix that someday!) which is
1455 * also saved for re-reading ("lasttoken"). 1448 * also saved for re-reading ("lasttoken").
1456 * 1449 *
1457 * Overall, this routine does far more parsing than it is supposed to. 1450 * Overall, this routine does far more parsing than it is supposed to.
1458 * That will also need fixing, someday... 1451 * That will also need fixing, someday...
1459 */ 1452 */
1460STATIC int 1453STATIC int
1461readtoken1(int firstc, char const *syn, int magicq) 1454readtoken1(int firstc, char const *syn, int magicq)
1462{ 1455{
1463 int c; 1456 int c;
1464 char * out; 1457 char * out;
1465 int len; 1458 int len;
1466 struct nodelist *bqlist; 1459 struct nodelist *bqlist;
1467 int quotef; 1460 int quotef;
1468 VSS static_stack; 1461 VSS static_stack;
1469 VSS *stack = &static_stack; 1462 VSS *stack = &static_stack;
1470 1463
1471 stack->prev = NULL; 1464 stack->prev = NULL;
1472 stack->cur = 0; 1465 stack->cur = 0;
1473 1466
1474 syntax = syn; 1467 syntax = syn;
1475 1468
1476 startlinno = plinno; 1469 startlinno = plinno;
1477 varnest = 0; 1470 varnest = 0;
1478 quoted = 0; 1471 quoted = 0;
1479 if (syntax == DQSYNTAX) 1472 if (syntax == DQSYNTAX)
1480 SETDBLQUOTE(); 1473 SETDBLQUOTE();
1481 quotef = 0; 1474 quotef = 0;
1482 bqlist = NULL; 1475 bqlist = NULL;
1483 arinest = 0; 1476 arinest = 0;
1484 parenlevel = 0; 1477 parenlevel = 0;
1485 1478
1486 STARTSTACKSTR(out); 1479 STARTSTACKSTR(out);
1487 1480
1488 for (c = firstc ;; c = pgetc_macro()) { /* until of token */ 1481 for (c = firstc ;; c = pgetc_macro()) { /* until of token */
1489 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 1482 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
1490 switch (syntax[c]) { 1483 switch (syntax[c]) {
1491 case CNL: /* '\n' */ 1484 case CNL: /* '\n' */
1492 if (syntax == BASESYNTAX) 1485 if (syntax == BASESYNTAX)
1493 break; /* exit loop */ 1486 break; /* exit loop */
1494 USTPUTC(c, out); 1487 USTPUTC(c, out);
1495 plinno++; 1488 plinno++;
1496 if (doprompt) 1489 if (doprompt)
1497 setprompt(2); 1490 setprompt(2);
1498 else 1491 else
1499 setprompt(0); 1492 setprompt(0);
1500 continue; 1493 continue;
1501 1494
1502 case CWORD: 1495 case CWORD:
1503 USTPUTC(c, out); 1496 USTPUTC(c, out);
1504 continue; 1497 continue;
1505 case CCTL: 1498 case CCTL:
1506 if (!magicq || ISDBLQUOTE()) 1499 if (!magicq || ISDBLQUOTE())
1507 USTPUTC(CTLESC, out); 1500 USTPUTC(CTLESC, out);
1508 USTPUTC(c, out); 1501 USTPUTC(c, out);
1509 continue; 1502 continue;
1510 case CBACK: /* backslash */ 1503 case CBACK: /* backslash */
1511 c = pgetc(); 1504 c = pgetc();
1512 if (c == PEOF) { 1505 if (c == PEOF) {
1513 USTPUTC('\\', out); 1506 USTPUTC('\\', out);
1514 pungetc(); 1507 pungetc();
1515 continue; 1508 continue;
1516 } 1509 }
1517 if (c == '\n') { 1510 if (c == '\n') {
1518 plinno++; 1511 plinno++;
1519 if (doprompt) 1512 if (doprompt)
1520 setprompt(2); 1513 setprompt(2);
1521 else 1514 else
1522 setprompt(0); 1515 setprompt(0);
1523 continue; 1516 continue;
1524 } 1517 }
1525 quotef = 1; /* current token is quoted */ 1518 quotef = 1; /* current token is quoted */
1526 if (ISDBLQUOTE() && c != '\\' && c != '`' && 1519 if (ISDBLQUOTE() && c != '\\' && c != '`' &&
1527 c != '$' && (c != '"' || magicq)) 1520 c != '$' && (c != '"' || magicq))
1528 USTPUTC('\\', out); 1521 USTPUTC('\\', out);
1529 if (SQSYNTAX[c] == CCTL) 1522 if (SQSYNTAX[c] == CCTL)
1530 USTPUTC(CTLESC, out); 1523 USTPUTC(CTLESC, out);
1531 else if (!magicq) { 1524 else if (!magicq) {
1532 USTPUTC(CTLQUOTEMARK, out); 1525 USTPUTC(CTLQUOTEMARK, out);
1533 USTPUTC(c, out); 1526 USTPUTC(c, out);
1534 if (varnest != 0) 1527 if (varnest != 0)
1535 USTPUTC(CTLQUOTEEND, out); 1528 USTPUTC(CTLQUOTEEND, out);
1536 continue; 1529 continue;
1537 } 1530 }
1538 USTPUTC(c, out); 1531 USTPUTC(c, out);
1539 continue; 1532 continue;
1540 case CSQUOTE: 1533 case CSQUOTE:
1541 if (syntax != SQSYNTAX) { 1534 if (syntax != SQSYNTAX) {
1542 if (!magicq) 1535 if (!magicq)
1543 USTPUTC(CTLQUOTEMARK, out); 1536 USTPUTC(CTLQUOTEMARK, out);
1544 quotef = 1; 1537 quotef = 1;
1545 TS_PUSH(); 1538 TS_PUSH();
1546 syntax = SQSYNTAX; 1539 syntax = SQSYNTAX;
1547 quoted = SQ; 1540 quoted = SQ;
1548 continue; 1541 continue;
1549 } 1542 }
1550 if (magicq && arinest == 0 && varnest == 0) { 1543 if (magicq && arinest == 0 && varnest == 0) {
1551 /* Ignore inside quoted here document */ 1544 /* Ignore inside quoted here document */
1552 USTPUTC(c, out); 1545 USTPUTC(c, out);
1553 continue; 1546 continue;
1554 } 1547 }
1555 /* End of single quotes... */ 1548 /* End of single quotes... */
1556 TS_POP(); 1549 TS_POP();
1557 if (syntax == BASESYNTAX && varnest != 0) 1550 if (syntax == BASESYNTAX && varnest != 0)
1558 USTPUTC(CTLQUOTEEND, out); 1551 USTPUTC(CTLQUOTEEND, out);
1559 continue; 1552 continue;
1560 case CDQUOTE: 1553 case CDQUOTE:
1561 if (magicq && arinest == 0 && varnest == 0) { 1554 if (magicq && arinest == 0 && varnest == 0) {
1562 /* Ignore inside here document */ 1555 /* Ignore inside here document */
1563 USTPUTC(c, out); 1556 USTPUTC(c, out);
1564 continue; 1557 continue;
1565 } 1558 }
1566 quotef = 1; 1559 quotef = 1;
1567 if (arinest) { 1560 if (arinest) {
1568 if (ISDBLQUOTE()) { 1561 if (ISDBLQUOTE()) {
1569 TS_POP(); 1562 TS_POP();
1570 } else { 1563 } else {
1571 TS_PUSH(); 1564 TS_PUSH();
1572 syntax = DQSYNTAX; 1565 syntax = DQSYNTAX;
1573 SETDBLQUOTE(); 1566 SETDBLQUOTE();
1574 USTPUTC(CTLQUOTEMARK, out); 1567 USTPUTC(CTLQUOTEMARK, out);
1575 } 1568 }
1576 continue; 1569 continue;
1577 } 1570 }
1578 if (magicq) 1571 if (magicq)
1579 continue; 1572 continue;
1580 if (ISDBLQUOTE()) { 1573 if (ISDBLQUOTE()) {
1581 TS_POP(); 1574 TS_POP();
1582 if (varnest != 0) 1575 if (varnest != 0)
1583 USTPUTC(CTLQUOTEEND, out); 1576 USTPUTC(CTLQUOTEEND, out);
1584 } else { 1577 } else {
1585 TS_PUSH(); 1578 TS_PUSH();
1586 syntax = DQSYNTAX; 1579 syntax = DQSYNTAX;
1587 SETDBLQUOTE(); 1580 SETDBLQUOTE();
1588 USTPUTC(CTLQUOTEMARK, out); 1581 USTPUTC(CTLQUOTEMARK, out);
1589 } 1582 }
1590 continue; 1583 continue;
1591 case CVAR: /* '$' */ 1584 case CVAR: /* '$' */
1592 PARSESUB(); /* parse substitution */ 1585 PARSESUB(); /* parse substitution */
1593 continue; 1586 continue;
1594 case CENDVAR: /* CLOSEBRACE */ 1587 case CENDVAR: /* CLOSEBRACE */
1595 if (varnest > 0 && !ISDBLQUOTE()) { 1588 if (varnest > 0 && !ISDBLQUOTE()) {
1596 TS_POP(); 1589 TS_POP();
1597 USTPUTC(CTLENDVAR, out); 1590 USTPUTC(CTLENDVAR, out);
1598 } else { 1591 } else {
1599 USTPUTC(c, out); 1592 USTPUTC(c, out);
1600 } 1593 }
1601 continue; 1594 continue;
1602 case CLP: /* '(' in arithmetic */ 1595 case CLP: /* '(' in arithmetic */
1603 parenlevel++; 1596 parenlevel++;
1604 USTPUTC(c, out); 1597 USTPUTC(c, out);
1605 continue;; 1598 continue;;
1606 case CRP: /* ')' in arithmetic */ 1599 case CRP: /* ')' in arithmetic */
1607 if (parenlevel > 0) { 1600 if (parenlevel > 0) {
1608 USTPUTC(c, out); 1601 USTPUTC(c, out);
1609 --parenlevel; 1602 --parenlevel;
1610 } else { 1603 } else {
1611 if (pgetc() == ')') { 1604 if (pgetc() == ')') {
1612 if (--arinest == 0) { 1605 if (--arinest == 0) {
1613 TS_POP(); 1606 TS_POP();
1614 USTPUTC(CTLENDARI, out); 1607 USTPUTC(CTLENDARI, out);
1615 } else 1608 } else
1616 USTPUTC(')', out); 1609 USTPUTC(')', out);
1617 } else { 1610 } else {
1618 /* 1611 /*
1619 * unbalanced parens 1612 * unbalanced parens
1620 * (don't 2nd guess - no error) 1613 * (don't 2nd guess - no error)
1621 */ 1614 */
1622 pungetc(); 1615 pungetc();
1623 USTPUTC(')', out); 1616 USTPUTC(')', out);
1624 } 1617 }
1625 } 1618 }
1626 continue; 1619 continue;
1627 case CBQUOTE: /* '`' */ 1620 case CBQUOTE: /* '`' */
1628 out = parsebackq(stack, out, &bqlist, 1); 1621 out = parsebackq(stack, out, &bqlist, 1);
1629 continue; 1622 continue;
1630 case CEOF: /* --> c == PEOF */ 1623 case CEOF: /* --> c == PEOF */
1631 break; /* will exit loop */ 1624 break; /* will exit loop */
1632 default: 1625 default:
1633 if (varnest == 0 && !ISDBLQUOTE()) 1626 if (varnest == 0 && !ISDBLQUOTE())
1634 break; /* exit loop */ 1627 break; /* exit loop */
1635 USTPUTC(c, out); 1628 USTPUTC(c, out);
1636 continue; 1629 continue;
1637 } 1630 }
1638 break; /* break from switch -> break from for loop too */ 1631 break; /* break from switch -> break from for loop too */
1639 } 1632 }
1640 1633
1641 if (syntax == ARISYNTAX) { 1634 if (syntax == ARISYNTAX) {
1642 cleanup_state_stack(stack); 1635 cleanup_state_stack(stack);
1643 synerror("Missing '))'"); 1636 synerror("Missing '))'");
1644 } 1637 }
1645 if (syntax != BASESYNTAX && /* ! parsebackquote && */ !magicq) { 1638 if (syntax != BASESYNTAX && /* ! parsebackquote && */ !magicq) {
1646 cleanup_state_stack(stack); 1639 cleanup_state_stack(stack);
1647 synerror("Unterminated quoted string"); 1640 synerror("Unterminated quoted string");
1648 } 1641 }
1649 if (varnest != 0) { 1642 if (varnest != 0) {
1650 cleanup_state_stack(stack); 1643 cleanup_state_stack(stack);
1651 startlinno = plinno; 1644 startlinno = plinno;
1652 /* { */ 1645 /* { */
1653 synerror("Missing '}'"); 1646 synerror("Missing '}'");
1654 } 1647 }
1655 1648
1656 USTPUTC('\0', out); 1649 USTPUTC('\0', out);
1657 len = out - stackblock(); 1650 len = out - stackblock();
1658 out = stackblock(); 1651 out = stackblock();
1659 1652
1660 if (!magicq) { 1653 if (!magicq) {
1661 if ((c == '<' || c == '>') 1654 if ((c == '<' || c == '>')
1662 && quotef == 0 && (*out == '\0' || is_number(out))) { 1655 && quotef == 0 && (*out == '\0' || is_number(out))) {
1663 parseredir(out, c); 1656 parseredir(out, c);
1664 cleanup_state_stack(stack); 1657 cleanup_state_stack(stack);
1665 return lasttoken = TREDIR; 1658 return lasttoken = TREDIR;
1666 } else { 1659 } else {
1667 pungetc(); 1660 pungetc();
1668 } 1661 }
1669 } 1662 }
1670 1663
1671 quoteflag = quotef; 1664 quoteflag = quotef;
1672 backquotelist = bqlist; 1665 backquotelist = bqlist;
1673 grabstackblock(len); 1666 grabstackblock(len);
1674 wordtext = out; 1667 wordtext = out;
1675 cleanup_state_stack(stack); 1668 cleanup_state_stack(stack);
1676 return lasttoken = TWORD; 1669 return lasttoken = TWORD;
1677/* end of readtoken routine */ 1670/* end of readtoken routine */
1678 1671
1679 1672
1680/* 1673/*
1681 * Parse a substitution. At this point, we have read the dollar sign 1674 * Parse a substitution. At this point, we have read the dollar sign
1682 * and nothing else. 1675 * and nothing else.
1683 */ 1676 */
1684 1677
1685parsesub: { 1678parsesub: {
1686 char buf[10]; 1679 char buf[10];
1687 int subtype; 1680 int subtype;
1688 int typeloc; 1681 int typeloc;
1689 int flags; 1682 int flags;
1690 char *p; 1683 char *p;
1691 static const char types[] = "}-+?="; 1684 static const char types[] = "}-+?=";
1692 int i; 1685 int i;
1693 int linno; 1686 int linno;
1694 1687
1695 c = pgetc(); 1688 c = pgetc();
1696 if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) { 1689 if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
1697 USTPUTC('$', out); 1690 USTPUTC('$', out);
1698 pungetc(); 1691 pungetc();
1699 } else if (c == '(') { /* $(command) or $((arith)) */ 1692 } else if (c == '(') { /* $(command) or $((arith)) */
1700 if (pgetc() == '(') { 1693 if (pgetc() == '(') {
1701 PARSEARITH(); 1694 PARSEARITH();
1702 } else { 1695 } else {
1703 pungetc(); 1696 pungetc();
1704 out = parsebackq(stack, out, &bqlist, 0); 1697 out = parsebackq(stack, out, &bqlist, 0);
1705 } 1698 }
1706 } else { 1699 } else {
1707 USTPUTC(CTLVAR, out); 1700 USTPUTC(CTLVAR, out);
1708 typeloc = out - stackblock(); 1701 typeloc = out - stackblock();
1709 USTPUTC(VSNORMAL, out); 1702 USTPUTC(VSNORMAL, out);
1710 subtype = VSNORMAL; 1703 subtype = VSNORMAL;
1711 flags = 0; 1704 flags = 0;
1712 if (c == OPENBRACE) { 1705 if (c == OPENBRACE) {
1713 c = pgetc(); 1706 c = pgetc();
1714 if (c == '#') { 1707 if (c == '#') {
1715 if ((c = pgetc()) == CLOSEBRACE) 1708 if ((c = pgetc()) == CLOSEBRACE)
1716 c = '#'; 1709 c = '#';
1717 else 1710 else
1718 subtype = VSLENGTH; 1711 subtype = VSLENGTH;
1719 } 1712 }
1720 else 1713 else
1721 subtype = 0; 1714 subtype = 0;
1722 } 1715 }
1723 if (is_name(c)) { 1716 if (is_name(c)) {
1724 p = out; 1717 p = out;
1725 do { 1718 do {
1726 STPUTC(c, out); 1719 STPUTC(c, out);
1727 c = pgetc(); 1720 c = pgetc();
1728 } while (is_in_name(c)); 1721 } while (is_in_name(c));
1729 if (out - p == 6 && strncmp(p, "LINENO", 6) == 0) { 1722 if (out - p == 6 && strncmp(p, "LINENO", 6) == 0) {
1730 /* Replace the variable name with the 1723 /* Replace the variable name with the
1731 * current line number. */ 1724 * current line number. */
1732 linno = plinno; 1725 linno = plinno;
1733 if (funclinno != 0) 1726 if (funclinno != 0)
1734 linno -= funclinno - 1; 1727 linno -= funclinno - 1;
1735 snprintf(buf, sizeof(buf), "%d", linno); 1728 snprintf(buf, sizeof(buf), "%d", linno);
1736 STADJUST(-6, out); 1729 STADJUST(-6, out);
1737 for (i = 0; buf[i] != '\0'; i++) 1730 for (i = 0; buf[i] != '\0'; i++)
1738 STPUTC(buf[i], out); 1731 STPUTC(buf[i], out);
1739 flags |= VSLINENO; 1732 flags |= VSLINENO;
1740 } 1733 }
1741 } else if (is_digit(c)) { 1734 } else if (is_digit(c)) {
1742 do { 1735 do {
1743 USTPUTC(c, out); 1736 USTPUTC(c, out);
1744 c = pgetc(); 1737 c = pgetc();
1745 } while (subtype != VSNORMAL && is_digit(c)); 1738 } while (subtype != VSNORMAL && is_digit(c));
1746 } 1739 }
1747 else if (is_special(c)) { 1740 else if (is_special(c)) {
1748 USTPUTC(c, out); 1741 USTPUTC(c, out);
1749 c = pgetc(); 1742 c = pgetc();
1750 } 1743 }
1751 else { 1744 else {
1752badsub: 1745badsub:
1753 cleanup_state_stack(stack); 1746 cleanup_state_stack(stack);
1754 synerror("Bad substitution"); 1747 synerror("Bad substitution");
1755 } 1748 }
1756 1749
1757 STPUTC('=', out); 1750 STPUTC('=', out);
1758 if (subtype == 0) { 1751 if (subtype == 0) {
1759 switch (c) { 1752 switch (c) {
1760 case ':': 1753 case ':':
1761 flags |= VSNUL; 1754 flags |= VSNUL;
1762 c = pgetc(); 1755 c = pgetc();
1763 /*FALLTHROUGH*/ 1756 /*FALLTHROUGH*/
1764 default: 1757 default:
1765 p = strchr(types, c); 1758 p = strchr(types, c);
1766 if (p == NULL) 1759 if (p == NULL)
1767 goto badsub; 1760 goto badsub;
1768 subtype = p - types + VSNORMAL; 1761 subtype = p - types + VSNORMAL;
1769 break; 1762 break;
1770 case '%': 1763 case '%':
1771 case '#': 1764 case '#':
1772 { 1765 {
1773 int cc = c; 1766 int cc = c;
1774 subtype = c == '#' ? VSTRIMLEFT : 1767 subtype = c == '#' ? VSTRIMLEFT :
1775 VSTRIMRIGHT; 1768 VSTRIMRIGHT;
1776 c = pgetc(); 1769 c = pgetc();
1777 if (c == cc) 1770 if (c == cc)
1778 subtype++; 1771 subtype++;
1779 else 1772 else
1780 pungetc(); 1773 pungetc();
1781 break; 1774 break;
1782 } 1775 }
1783 } 1776 }
1784 } else { 1777 } else {
1785 pungetc(); 1778 pungetc();
1786 } 1779 }
1787 if (ISDBLQUOTE() || arinest) 1780 if (ISDBLQUOTE() || arinest)
1788 flags |= VSQUOTE; 1781 flags |= VSQUOTE;
1789 if (subtype >= VSTRIMLEFT && subtype <= VSTRIMRIGHTMAX) 1782 if (subtype >= VSTRIMLEFT && subtype <= VSTRIMRIGHTMAX)
1790 flags |= VSPATQ; 1783 flags |= VSPATQ;
1791 *(stackblock() + typeloc) = subtype | flags; 1784 *(stackblock() + typeloc) = subtype | flags;
1792 if (subtype != VSNORMAL) { 1785 if (subtype != VSNORMAL) {
1793 TS_PUSH(); 1786 TS_PUSH();
1794 varnest++; 1787 varnest++;
1795 arinest = 0; 1788 arinest = 0;
1796 if (subtype > VSASSIGN) { /* # ## % %% */ 1789 if (subtype > VSASSIGN) { /* # ## % %% */
1797 syntax = BASESYNTAX; 1790 syntax = BASESYNTAX;
1798 CLRDBLQUOTE(); 1791 CLRDBLQUOTE();
1799 } 1792 }
1800 } 1793 }
1801 } 1794 }
1802 goto parsesub_return; 1795 goto parsesub_return;
1803} 1796}
1804 1797
1805 1798
1806/* 1799/*
1807 * Parse an arithmetic expansion (indicate start of one and set state) 1800 * Parse an arithmetic expansion (indicate start of one and set state)
1808 */ 1801 */
1809parsearith: { 1802parsearith: {
1810 1803
1811 if (syntax == ARISYNTAX) { 1804 if (syntax == ARISYNTAX) {
1812 /* 1805 /*
1813 * we collapse embedded arithmetic expansion to 1806 * we collapse embedded arithmetic expansion to
1814 * parentheses, which should be equivalent 1807 * parentheses, which should be equivalent
1815 */ 1808 */
1816 USTPUTC('(', out); 1809 USTPUTC('(', out);
1817 USTPUTC('(', out); 1810 USTPUTC('(', out);
1818 /* 1811 /*
1819 * Need 2 of them because there will (should be) 1812 * Need 2 of them because there will (should be)
1820 * two closing ))'s to follow later. 1813 * two closing ))'s to follow later.
1821 */ 1814 */
1822 parenlevel += 2; 1815 parenlevel += 2;
1823 } else { 1816 } else {
1824 TS_PUSH(); 1817 TS_PUSH();
1825 syntax = ARISYNTAX; 1818 syntax = ARISYNTAX;
1826 ++arinest; 1819 ++arinest;
1827 varnest = 0; 1820 varnest = 0;
1828 1821
1829 USTPUTC(CTLARI, out); 1822 USTPUTC(CTLARI, out);
1830 if (ISDBLQUOTE()) 1823 if (ISDBLQUOTE())
1831 USTPUTC('"',out); 1824 USTPUTC('"',out);
1832 else 1825 else
1833 USTPUTC(' ',out); 1826 USTPUTC(' ',out);
1834 } 1827 }
1835 goto parsearith_return; 1828 goto parsearith_return;
1836} 1829}
1837 1830
1838} /* end of readtoken */ 1831} /* end of readtoken */
1839 1832
1840 1833
1841 1834
1842#ifdef mkinit 1835#ifdef mkinit
1843RESET { 1836RESET {
1844 tokpushback = 0; 1837 tokpushback = 0;
1845 checkkwd = 0; 1838 checkkwd = 0;
1846} 1839}
1847#endif 1840#endif
1848 1841
1849/* 1842/*
1850 * Returns true if the text contains nothing to expand (no dollar signs 1843 * Returns true if the text contains nothing to expand (no dollar signs
1851 * or backquotes). 1844 * or backquotes).
1852 */ 1845 */
1853 1846
1854STATIC int 1847STATIC int
1855noexpand(char *text) 1848noexpand(char *text)
1856{ 1849{
1857 char *p; 1850 char *p;
1858 char c; 1851 char c;
1859 1852
1860 p = text; 1853 p = text;
1861 while ((c = *p++) != '\0') { 1854 while ((c = *p++) != '\0') {
1862 if (c == CTLQUOTEMARK) 1855 if (c == CTLQUOTEMARK)
1863 continue; 1856 continue;
1864 if (c == CTLESC) 1857 if (c == CTLESC)
1865 p++; 1858 p++;
1866 else if (BASESYNTAX[(int)c] == CCTL) 1859 else if (BASESYNTAX[(int)c] == CCTL)
1867 return 0; 1860 return 0;
1868 } 1861 }
1869 return 1; 1862 return 1;
1870} 1863}
1871 1864
1872 1865
1873/* 1866/*

cvs diff -r1.20 -r1.21 src/bin/sh/parser.h (switch to unified diff)

--- src/bin/sh/parser.h 2016/03/27 14:39:33 1.20
+++ src/bin/sh/parser.h 2016/03/31 23:11:05 1.21
@@ -1,86 +1,85 @@ @@ -1,86 +1,85 @@
1/* $NetBSD: parser.h,v 1.20 2016/03/27 14:39:33 christos Exp $ */ 1/* $NetBSD: parser.h,v 1.21 2016/03/31 23:11:05 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 * @(#)parser.h 8.3 (Berkeley) 5/4/95 34 * @(#)parser.h 8.3 (Berkeley) 5/4/95
35 */ 35 */
36 36
37/* control characters in argument strings */ 37/* control characters in argument strings */
38#define CTL_FIRST '\201' /* first 'special' character */ 38#define CTL_FIRST '\201' /* first 'special' character */
39#define CTLESC '\201' /* escape next character */ 39#define CTLESC '\201' /* escape next character */
40#define CTLVAR '\202' /* variable defn */ 40#define CTLVAR '\202' /* variable defn */
41#define CTLENDVAR '\203' 41#define CTLENDVAR '\203'
42#define CTLBACKQ '\204' 42#define CTLBACKQ '\204'
43#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ 43#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
44/* CTLBACKQ | CTLQUOTE == '\205' */ 44/* CTLBACKQ | CTLQUOTE == '\205' */
45#define CTLARI '\206' /* arithmetic expression */ 45#define CTLARI '\206' /* arithmetic expression */
46#define CTLENDARI '\207' 46#define CTLENDARI '\207'
47#define CTLQUOTEMARK '\210' 47#define CTLQUOTEMARK '\210'
48#define CTLQUOTEEND '\211' /* only inside ${...} */ 48#define CTLQUOTEEND '\211' /* only inside ${...} */
49#define CTL_LAST '\211' /* last 'special' character */ 49#define CTL_LAST '\211' /* last 'special' character */
50 50
51/* variable substitution byte (follows CTLVAR) */ 51/* variable substitution byte (follows CTLVAR) */
52#define VSTYPE 0x0f /* type of variable substitution */ 52#define VSTYPE 0x0f /* type of variable substitution */
53#define VSNUL 0x10 /* colon--treat the empty string as unset */ 53#define VSNUL 0x10 /* colon--treat the empty string as unset */
54#define VSLINENO 0x20 /* expansion of $LINENO, the line number 54#define VSLINENO 0x20 /* expansion of $LINENO, the line number
55 follows immediately */ 55 follows immediately */
56#define VSPATQ 0x40 /* ensure correct pattern quoting in ${x#pat} */ 56#define VSPATQ 0x40 /* ensure correct pattern quoting in ${x#pat} */
57#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ 57#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
58 58
59/* values of VSTYPE field */ 59/* values of VSTYPE field */
60#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 60#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
61#define VSMINUS 0x2 /* ${var-text} */ 61#define VSMINUS 0x2 /* ${var-text} */
62#define VSPLUS 0x3 /* ${var+text} */ 62#define VSPLUS 0x3 /* ${var+text} */
63#define VSQUESTION 0x4 /* ${var?message} */ 63#define VSQUESTION 0x4 /* ${var?message} */
64#define VSASSIGN 0x5 /* ${var=text} */ 64#define VSASSIGN 0x5 /* ${var=text} */
65#define VSTRIMLEFT 0x6 /* ${var#pattern} */ 65#define VSTRIMLEFT 0x6 /* ${var#pattern} */
66#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ 66#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
67#define VSTRIMRIGHT 0x8 /* ${var%pattern} */ 67#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
68#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ 68#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
69#define VSLENGTH 0xa /* ${#var} */ 69#define VSLENGTH 0xa /* ${#var} */
70 70
71 71
72/* 72/*
73 * NEOF is returned by parsecmd when it encounters an end of file. It 73 * NEOF is returned by parsecmd when it encounters an end of file. It
74 * must be distinct from NULL, so we use the address of a variable that 74 * must be distinct from NULL, so we use the address of a variable that
75 * happens to be handy. 75 * happens to be handy.
76 */ 76 */
77extern int tokpushback; 77extern int tokpushback;
78#define NEOF ((union node *)&tokpushback) 78#define NEOF ((union node *)&tokpushback)
79extern int whichprompt; /* 1 == PS1, 2 == PS2 */ 79extern int whichprompt; /* 1 == PS1, 2 == PS2 */
80 80
81 81
82union node *parsecmd(int); 82union node *parsecmd(int);
83void fixredir(union node *, const char *, int); 83void fixredir(union node *, const char *, int);
84void parse_heredoc(union node *); 
85int goodname(char *); 84int goodname(char *);
86const char *getprompt(void *); 85const char *getprompt(void *);