parser.c revision 1.5 1 1.1 cgd /*-
2 1.1 cgd * Copyright (c) 1991 The Regents of the University of California.
3 1.1 cgd * All rights reserved.
4 1.1 cgd *
5 1.1 cgd * This code is derived from software contributed to Berkeley by
6 1.1 cgd * Kenneth Almquist.
7 1.1 cgd *
8 1.1 cgd * Redistribution and use in source and binary forms, with or without
9 1.1 cgd * modification, are permitted provided that the following conditions
10 1.1 cgd * are met:
11 1.1 cgd * 1. Redistributions of source code must retain the above copyright
12 1.1 cgd * notice, this list of conditions and the following disclaimer.
13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer in the
15 1.1 cgd * documentation and/or other materials provided with the distribution.
16 1.1 cgd * 3. All advertising materials mentioning features or use of this software
17 1.1 cgd * must display the following acknowledgement:
18 1.1 cgd * This product includes software developed by the University of
19 1.1 cgd * California, Berkeley and its contributors.
20 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
21 1.1 cgd * may be used to endorse or promote products derived from this software
22 1.1 cgd * without specific prior written permission.
23 1.1 cgd *
24 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 cgd * SUCH DAMAGE.
35 1.1 cgd */
36 1.1 cgd
37 1.1 cgd #ifndef lint
38 1.1 cgd static char sccsid[] = "@(#)parser.c 5.3 (Berkeley) 4/12/91";
39 1.5 sef static char rcsid[] = "$Header: /tank/opengrok/rsync2/NetBSD/src/bin/sh/parser.c,v 1.5 1993/05/02 01:28:43 sef Exp $";
40 1.1 cgd #endif /* not lint */
41 1.1 cgd
42 1.1 cgd #include "shell.h"
43 1.1 cgd #include "parser.h"
44 1.1 cgd #include "nodes.h"
45 1.1 cgd #include "expand.h" /* defines rmescapes() */
46 1.1 cgd #include "redir.h" /* defines copyfd() */
47 1.1 cgd #include "syntax.h"
48 1.1 cgd #include "options.h"
49 1.1 cgd #include "input.h"
50 1.1 cgd #include "output.h"
51 1.1 cgd #include "var.h"
52 1.1 cgd #include "error.h"
53 1.1 cgd #include "memalloc.h"
54 1.1 cgd #include "mystring.h"
55 1.1 cgd
56 1.1 cgd
57 1.1 cgd /*
58 1.1 cgd * Shell command parser.
59 1.1 cgd */
60 1.1 cgd
61 1.1 cgd #define EOFMARKLEN 79
62 1.1 cgd
63 1.1 cgd /* values returned by readtoken */
64 1.1 cgd #include "token.def"
65 1.1 cgd
66 1.1 cgd
67 1.1 cgd
68 1.1 cgd struct heredoc {
69 1.1 cgd struct heredoc *next; /* next here document in list */
70 1.1 cgd union node *here; /* redirection node */
71 1.1 cgd char *eofmark; /* string indicating end of input */
72 1.1 cgd int striptabs; /* if set, strip leading tabs */
73 1.1 cgd };
74 1.1 cgd
75 1.1 cgd
76 1.1 cgd
77 1.1 cgd struct heredoc *heredoclist; /* list of here documents to read */
78 1.1 cgd int parsebackquote; /* nonzero if we are inside backquotes */
79 1.1 cgd int doprompt; /* if set, prompt the user */
80 1.1 cgd int needprompt; /* true if interactive and at start of line */
81 1.1 cgd int lasttoken; /* last token read */
82 1.1 cgd MKINIT int tokpushback; /* last token pushed back */
83 1.1 cgd char *wordtext; /* text of last word returned by readtoken */
84 1.1 cgd int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
85 1.1 cgd struct nodelist *backquotelist;
86 1.1 cgd union node *redirnode;
87 1.1 cgd struct heredoc *heredoc;
88 1.1 cgd int quoteflag; /* set if (part of) last token was quoted */
89 1.1 cgd int startlinno; /* line # where last token started */
90 1.1 cgd
91 1.1 cgd
92 1.1 cgd #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
93 1.1 cgd #ifdef GDB_HACK
94 1.1 cgd static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
95 1.1 cgd static const char types[] = "}-+?=";
96 1.1 cgd #endif
97 1.1 cgd
98 1.1 cgd
99 1.1 cgd STATIC union node *list __P((int));
100 1.1 cgd STATIC union node *andor __P((void));
101 1.1 cgd STATIC union node *pipeline __P((void));
102 1.1 cgd STATIC union node *command __P((void));
103 1.5 sef STATIC union node *simplecmd __P((union node **, union node *));
104 1.1 cgd STATIC void parsefname __P((void));
105 1.1 cgd STATIC void parseheredoc __P((void));
106 1.1 cgd STATIC int readtoken __P((void));
107 1.1 cgd STATIC int readtoken1 __P((int, char const *, char *, int));
108 1.1 cgd STATIC void attyline __P((void));
109 1.1 cgd STATIC int noexpand __P((char *));
110 1.1 cgd STATIC void synexpect __P((int));
111 1.1 cgd STATIC void synerror __P((char *));
112 1.1 cgd
113 1.1 cgd #if ATTY
114 1.1 cgd STATIC void putprompt __P((char *));
115 1.1 cgd #else /* not ATTY */
116 1.1 cgd #define putprompt(s) out2str(s)
117 1.1 cgd #endif
118 1.1 cgd
119 1.1 cgd
120 1.1 cgd
121 1.1 cgd
122 1.1 cgd /*
123 1.1 cgd * Read and parse a command. Returns NEOF on end of file. (NULL is a
124 1.1 cgd * valid parse tree indicating a blank line.)
125 1.1 cgd */
126 1.1 cgd
127 1.1 cgd union node *
128 1.1 cgd parsecmd(interact) {
129 1.1 cgd int t;
130 1.1 cgd
131 1.1 cgd doprompt = interact;
132 1.1 cgd if (doprompt)
133 1.1 cgd putprompt(ps1val());
134 1.1 cgd needprompt = 0;
135 1.1 cgd if ((t = readtoken()) == TEOF)
136 1.1 cgd return NEOF;
137 1.1 cgd if (t == TNL)
138 1.1 cgd return NULL;
139 1.1 cgd tokpushback++;
140 1.1 cgd return list(1);
141 1.1 cgd }
142 1.1 cgd
143 1.1 cgd
144 1.1 cgd STATIC union node *
145 1.1 cgd list(nlflag) {
146 1.1 cgd union node *n1, *n2, *n3;
147 1.1 cgd
148 1.1 cgd checkkwd = 2;
149 1.1 cgd if (nlflag == 0 && tokendlist[peektoken()])
150 1.1 cgd return NULL;
151 1.1 cgd n1 = andor();
152 1.1 cgd for (;;) {
153 1.1 cgd switch (readtoken()) {
154 1.1 cgd case TBACKGND:
155 1.1 cgd if (n1->type == NCMD || n1->type == NPIPE) {
156 1.1 cgd n1->ncmd.backgnd = 1;
157 1.1 cgd } else if (n1->type == NREDIR) {
158 1.1 cgd n1->type = NBACKGND;
159 1.1 cgd } else {
160 1.1 cgd n3 = (union node *)stalloc(sizeof (struct nredir));
161 1.1 cgd n3->type = NBACKGND;
162 1.1 cgd n3->nredir.n = n1;
163 1.1 cgd n3->nredir.redirect = NULL;
164 1.1 cgd n1 = n3;
165 1.1 cgd }
166 1.1 cgd goto tsemi;
167 1.1 cgd case TNL:
168 1.1 cgd tokpushback++;
169 1.1 cgd /* fall through */
170 1.1 cgd tsemi: case TSEMI:
171 1.1 cgd if (readtoken() == TNL) {
172 1.1 cgd parseheredoc();
173 1.1 cgd if (nlflag)
174 1.1 cgd return n1;
175 1.1 cgd } else {
176 1.1 cgd tokpushback++;
177 1.1 cgd }
178 1.1 cgd checkkwd = 2;
179 1.1 cgd if (tokendlist[peektoken()])
180 1.1 cgd return n1;
181 1.1 cgd n2 = andor();
182 1.1 cgd n3 = (union node *)stalloc(sizeof (struct nbinary));
183 1.1 cgd n3->type = NSEMI;
184 1.1 cgd n3->nbinary.ch1 = n1;
185 1.1 cgd n3->nbinary.ch2 = n2;
186 1.1 cgd n1 = n3;
187 1.1 cgd break;
188 1.1 cgd case TEOF:
189 1.1 cgd if (heredoclist)
190 1.1 cgd parseheredoc();
191 1.1 cgd else
192 1.1 cgd pungetc(); /* push back EOF on input */
193 1.1 cgd return n1;
194 1.1 cgd default:
195 1.1 cgd if (nlflag)
196 1.1 cgd synexpect(-1);
197 1.1 cgd tokpushback++;
198 1.1 cgd return n1;
199 1.1 cgd }
200 1.1 cgd }
201 1.1 cgd }
202 1.1 cgd
203 1.1 cgd
204 1.1 cgd
205 1.1 cgd STATIC union node *
206 1.1 cgd andor() {
207 1.1 cgd union node *n1, *n2, *n3;
208 1.1 cgd int t;
209 1.1 cgd
210 1.1 cgd n1 = pipeline();
211 1.1 cgd for (;;) {
212 1.1 cgd if ((t = readtoken()) == TAND) {
213 1.1 cgd t = NAND;
214 1.1 cgd } else if (t == TOR) {
215 1.1 cgd t = NOR;
216 1.1 cgd } else {
217 1.1 cgd tokpushback++;
218 1.1 cgd return n1;
219 1.1 cgd }
220 1.1 cgd n2 = pipeline();
221 1.1 cgd n3 = (union node *)stalloc(sizeof (struct nbinary));
222 1.1 cgd n3->type = t;
223 1.1 cgd n3->nbinary.ch1 = n1;
224 1.1 cgd n3->nbinary.ch2 = n2;
225 1.1 cgd n1 = n3;
226 1.1 cgd }
227 1.1 cgd }
228 1.1 cgd
229 1.1 cgd
230 1.1 cgd
231 1.1 cgd STATIC union node *
232 1.1 cgd pipeline() {
233 1.1 cgd union node *n1, *pipenode;
234 1.1 cgd struct nodelist *lp, *prev;
235 1.1 cgd
236 1.1 cgd n1 = command();
237 1.1 cgd if (readtoken() == TPIPE) {
238 1.1 cgd pipenode = (union node *)stalloc(sizeof (struct npipe));
239 1.1 cgd pipenode->type = NPIPE;
240 1.1 cgd pipenode->npipe.backgnd = 0;
241 1.1 cgd lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
242 1.1 cgd pipenode->npipe.cmdlist = lp;
243 1.1 cgd lp->n = n1;
244 1.1 cgd do {
245 1.1 cgd prev = lp;
246 1.1 cgd lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
247 1.1 cgd lp->n = command();
248 1.1 cgd prev->next = lp;
249 1.1 cgd } while (readtoken() == TPIPE);
250 1.1 cgd lp->next = NULL;
251 1.1 cgd n1 = pipenode;
252 1.1 cgd }
253 1.1 cgd tokpushback++;
254 1.1 cgd return n1;
255 1.1 cgd }
256 1.1 cgd
257 1.1 cgd
258 1.1 cgd
259 1.1 cgd STATIC union node *
260 1.1 cgd command() {
261 1.1 cgd union node *n1, *n2;
262 1.1 cgd union node *ap, **app;
263 1.1 cgd union node *cp, **cpp;
264 1.1 cgd union node *redir, **rpp;
265 1.1 cgd int t;
266 1.1 cgd
267 1.1 cgd checkkwd = 2;
268 1.5 sef redir = 0;
269 1.5 sef rpp = &redir;
270 1.5 sef /* Check for redirection which may precede command */
271 1.5 sef while (readtoken() == TREDIR) {
272 1.5 sef *rpp = n2 = redirnode;
273 1.5 sef rpp = &n2->nfile.next;
274 1.5 sef parsefname();
275 1.5 sef }
276 1.5 sef tokpushback++;
277 1.5 sef
278 1.1 cgd switch (readtoken()) {
279 1.1 cgd case TIF:
280 1.1 cgd n1 = (union node *)stalloc(sizeof (struct nif));
281 1.1 cgd n1->type = NIF;
282 1.1 cgd n1->nif.test = list(0);
283 1.1 cgd if (readtoken() != TTHEN)
284 1.1 cgd synexpect(TTHEN);
285 1.1 cgd n1->nif.ifpart = list(0);
286 1.1 cgd n2 = n1;
287 1.1 cgd while (readtoken() == TELIF) {
288 1.1 cgd n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
289 1.1 cgd n2 = n2->nif.elsepart;
290 1.1 cgd n2->type = NIF;
291 1.1 cgd n2->nif.test = list(0);
292 1.1 cgd if (readtoken() != TTHEN)
293 1.1 cgd synexpect(TTHEN);
294 1.1 cgd n2->nif.ifpart = list(0);
295 1.1 cgd }
296 1.1 cgd if (lasttoken == TELSE)
297 1.1 cgd n2->nif.elsepart = list(0);
298 1.1 cgd else {
299 1.1 cgd n2->nif.elsepart = NULL;
300 1.1 cgd tokpushback++;
301 1.1 cgd }
302 1.1 cgd if (readtoken() != TFI)
303 1.1 cgd synexpect(TFI);
304 1.1 cgd checkkwd = 1;
305 1.1 cgd break;
306 1.1 cgd case TWHILE:
307 1.1 cgd case TUNTIL: {
308 1.1 cgd int got;
309 1.1 cgd n1 = (union node *)stalloc(sizeof (struct nbinary));
310 1.1 cgd n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
311 1.1 cgd n1->nbinary.ch1 = list(0);
312 1.1 cgd if ((got=readtoken()) != TDO) {
313 1.1 cgd TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
314 1.1 cgd synexpect(TDO);
315 1.1 cgd }
316 1.1 cgd n1->nbinary.ch2 = list(0);
317 1.1 cgd if (readtoken() != TDONE)
318 1.1 cgd synexpect(TDONE);
319 1.1 cgd checkkwd = 1;
320 1.1 cgd break;
321 1.1 cgd }
322 1.1 cgd case TFOR:
323 1.1 cgd if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
324 1.1 cgd synerror("Bad for loop variable");
325 1.1 cgd n1 = (union node *)stalloc(sizeof (struct nfor));
326 1.1 cgd n1->type = NFOR;
327 1.1 cgd n1->nfor.var = wordtext;
328 1.1 cgd if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
329 1.1 cgd app = ≈
330 1.1 cgd while (readtoken() == TWORD) {
331 1.1 cgd n2 = (union node *)stalloc(sizeof (struct narg));
332 1.1 cgd n2->type = NARG;
333 1.1 cgd n2->narg.text = wordtext;
334 1.1 cgd n2->narg.backquote = backquotelist;
335 1.1 cgd *app = n2;
336 1.1 cgd app = &n2->narg.next;
337 1.1 cgd }
338 1.1 cgd *app = NULL;
339 1.1 cgd n1->nfor.args = ap;
340 1.5 sef /* A newline or semicolon is required here to end
341 1.5 sef the list. */
342 1.5 sef if (lasttoken != TNL && lasttoken != TSEMI)
343 1.5 sef synexpect(-1);
344 1.1 cgd } else {
345 1.1 cgd #ifndef GDB_HACK
346 1.1 cgd static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
347 1.1 cgd '@', '=', '\0'};
348 1.1 cgd #endif
349 1.1 cgd n2 = (union node *)stalloc(sizeof (struct narg));
350 1.1 cgd n2->type = NARG;
351 1.1 cgd n2->narg.text = (char *)argvars;
352 1.1 cgd n2->narg.backquote = NULL;
353 1.1 cgd n2->narg.next = NULL;
354 1.1 cgd n1->nfor.args = n2;
355 1.5 sef /* A newline or semicolon is optional here. Anything
356 1.5 sef else gets pushed back so we can read it again. */
357 1.5 sef if (lasttoken != TNL && lasttoken != TSEMI)
358 1.5 sef tokpushback++;
359 1.1 cgd }
360 1.1 cgd checkkwd = 2;
361 1.1 cgd if ((t = readtoken()) == TDO)
362 1.1 cgd t = TDONE;
363 1.1 cgd else if (t == TBEGIN)
364 1.1 cgd t = TEND;
365 1.1 cgd else
366 1.1 cgd synexpect(-1);
367 1.1 cgd n1->nfor.body = list(0);
368 1.1 cgd if (readtoken() != t)
369 1.1 cgd synexpect(t);
370 1.1 cgd checkkwd = 1;
371 1.1 cgd break;
372 1.1 cgd case TCASE:
373 1.1 cgd n1 = (union node *)stalloc(sizeof (struct ncase));
374 1.1 cgd n1->type = NCASE;
375 1.1 cgd if (readtoken() != TWORD)
376 1.1 cgd synexpect(TWORD);
377 1.1 cgd n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
378 1.1 cgd n2->type = NARG;
379 1.1 cgd n2->narg.text = wordtext;
380 1.1 cgd n2->narg.backquote = backquotelist;
381 1.1 cgd n2->narg.next = NULL;
382 1.1 cgd while (readtoken() == TNL);
383 1.1 cgd if (lasttoken != TWORD || ! equal(wordtext, "in"))
384 1.1 cgd synerror("expecting \"in\"");
385 1.1 cgd cpp = &n1->ncase.cases;
386 1.1 cgd while (checkkwd = 2, readtoken() == TWORD) {
387 1.1 cgd *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
388 1.1 cgd cp->type = NCLIST;
389 1.1 cgd app = &cp->nclist.pattern;
390 1.1 cgd for (;;) {
391 1.1 cgd *app = ap = (union node *)stalloc(sizeof (struct narg));
392 1.1 cgd ap->type = NARG;
393 1.1 cgd ap->narg.text = wordtext;
394 1.1 cgd ap->narg.backquote = backquotelist;
395 1.1 cgd if (readtoken() != TPIPE)
396 1.1 cgd break;
397 1.1 cgd app = &ap->narg.next;
398 1.1 cgd if (readtoken() != TWORD)
399 1.1 cgd synexpect(TWORD);
400 1.1 cgd }
401 1.1 cgd ap->narg.next = NULL;
402 1.1 cgd if (lasttoken != TRP)
403 1.1 cgd synexpect(TRP);
404 1.1 cgd cp->nclist.body = list(0);
405 1.1 cgd if ((t = readtoken()) == TESAC)
406 1.1 cgd tokpushback++;
407 1.1 cgd else if (t != TENDCASE)
408 1.1 cgd synexpect(TENDCASE);
409 1.1 cgd cpp = &cp->nclist.next;
410 1.1 cgd }
411 1.1 cgd *cpp = NULL;
412 1.1 cgd if (lasttoken != TESAC)
413 1.1 cgd synexpect(TESAC);
414 1.1 cgd checkkwd = 1;
415 1.1 cgd break;
416 1.1 cgd case TLP:
417 1.1 cgd n1 = (union node *)stalloc(sizeof (struct nredir));
418 1.1 cgd n1->type = NSUBSHELL;
419 1.1 cgd n1->nredir.n = list(0);
420 1.1 cgd n1->nredir.redirect = NULL;
421 1.1 cgd if (readtoken() != TRP)
422 1.1 cgd synexpect(TRP);
423 1.1 cgd checkkwd = 1;
424 1.1 cgd break;
425 1.1 cgd case TBEGIN:
426 1.1 cgd n1 = list(0);
427 1.1 cgd if (readtoken() != TEND)
428 1.1 cgd synexpect(TEND);
429 1.1 cgd checkkwd = 1;
430 1.1 cgd break;
431 1.5 sef /* Handle an empty command like other simple commands. */
432 1.5 sef case TNL:
433 1.1 cgd case TWORD:
434 1.1 cgd tokpushback++;
435 1.5 sef return simplecmd(rpp, redir);
436 1.1 cgd default:
437 1.1 cgd synexpect(-1);
438 1.1 cgd }
439 1.1 cgd
440 1.1 cgd /* Now check for redirection which may follow command */
441 1.1 cgd while (readtoken() == TREDIR) {
442 1.1 cgd *rpp = n2 = redirnode;
443 1.1 cgd rpp = &n2->nfile.next;
444 1.1 cgd parsefname();
445 1.1 cgd }
446 1.1 cgd tokpushback++;
447 1.1 cgd *rpp = NULL;
448 1.1 cgd if (redir) {
449 1.1 cgd if (n1->type != NSUBSHELL) {
450 1.1 cgd n2 = (union node *)stalloc(sizeof (struct nredir));
451 1.1 cgd n2->type = NREDIR;
452 1.1 cgd n2->nredir.n = n1;
453 1.1 cgd n1 = n2;
454 1.1 cgd }
455 1.1 cgd n1->nredir.redirect = redir;
456 1.1 cgd }
457 1.1 cgd return n1;
458 1.1 cgd }
459 1.1 cgd
460 1.1 cgd
461 1.1 cgd STATIC union node *
462 1.5 sef simplecmd(rpp, redir)
463 1.5 sef union node **rpp, *redir;
464 1.5 sef {
465 1.1 cgd union node *args, **app;
466 1.5 sef union node **orig_rpp = rpp;
467 1.1 cgd union node *n;
468 1.1 cgd
469 1.5 sef /* If we don't have any redirections already, then we must reset
470 1.5 sef rpp to be the address of the local redir variable. */
471 1.5 sef if (redir == 0)
472 1.5 sef rpp = &redir;
473 1.5 sef
474 1.1 cgd args = NULL;
475 1.1 cgd app = &args;
476 1.5 sef /* We save the incoming value, because we need this for shell
477 1.5 sef functions. There can not be a redirect or an argument between
478 1.5 sef the function name and the open parenthesis. */
479 1.5 sef orig_rpp = rpp;
480 1.1 cgd for (;;) {
481 1.1 cgd if (readtoken() == TWORD) {
482 1.1 cgd n = (union node *)stalloc(sizeof (struct narg));
483 1.1 cgd n->type = NARG;
484 1.1 cgd n->narg.text = wordtext;
485 1.1 cgd n->narg.backquote = backquotelist;
486 1.1 cgd *app = n;
487 1.1 cgd app = &n->narg.next;
488 1.1 cgd } else if (lasttoken == TREDIR) {
489 1.1 cgd *rpp = n = redirnode;
490 1.1 cgd rpp = &n->nfile.next;
491 1.1 cgd parsefname(); /* read name of redirection file */
492 1.1 cgd } else if (lasttoken == TLP && app == &args->narg.next
493 1.5 sef && rpp == orig_rpp) {
494 1.1 cgd /* We have a function */
495 1.1 cgd if (readtoken() != TRP)
496 1.1 cgd synexpect(TRP);
497 1.1 cgd #ifdef notdef
498 1.1 cgd if (! goodname(n->narg.text))
499 1.1 cgd synerror("Bad function name");
500 1.1 cgd #endif
501 1.1 cgd n->type = NDEFUN;
502 1.1 cgd n->narg.next = command();
503 1.1 cgd return n;
504 1.1 cgd } else {
505 1.1 cgd tokpushback++;
506 1.1 cgd break;
507 1.1 cgd }
508 1.1 cgd }
509 1.1 cgd *app = NULL;
510 1.1 cgd *rpp = NULL;
511 1.1 cgd n = (union node *)stalloc(sizeof (struct ncmd));
512 1.1 cgd n->type = NCMD;
513 1.1 cgd n->ncmd.backgnd = 0;
514 1.1 cgd n->ncmd.args = args;
515 1.1 cgd n->ncmd.redirect = redir;
516 1.1 cgd return n;
517 1.1 cgd }
518 1.1 cgd
519 1.1 cgd
520 1.1 cgd STATIC void
521 1.1 cgd parsefname() {
522 1.1 cgd union node *n = redirnode;
523 1.1 cgd
524 1.1 cgd if (readtoken() != TWORD)
525 1.1 cgd synexpect(-1);
526 1.1 cgd if (n->type == NHERE) {
527 1.1 cgd struct heredoc *here = heredoc;
528 1.1 cgd struct heredoc *p;
529 1.1 cgd int i;
530 1.1 cgd
531 1.1 cgd if (quoteflag == 0)
532 1.1 cgd n->type = NXHERE;
533 1.1 cgd TRACE(("Here document %d\n", n->type));
534 1.1 cgd if (here->striptabs) {
535 1.1 cgd while (*wordtext == '\t')
536 1.1 cgd wordtext++;
537 1.1 cgd }
538 1.1 cgd if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
539 1.1 cgd synerror("Illegal eof marker for << redirection");
540 1.1 cgd rmescapes(wordtext);
541 1.1 cgd here->eofmark = wordtext;
542 1.1 cgd here->next = NULL;
543 1.1 cgd if (heredoclist == NULL)
544 1.1 cgd heredoclist = here;
545 1.1 cgd else {
546 1.1 cgd for (p = heredoclist ; p->next ; p = p->next);
547 1.1 cgd p->next = here;
548 1.1 cgd }
549 1.1 cgd } else if (n->type == NTOFD || n->type == NFROMFD) {
550 1.1 cgd if (is_digit(wordtext[0]))
551 1.1 cgd n->ndup.dupfd = digit_val(wordtext[0]);
552 1.1 cgd else if (wordtext[0] == '-')
553 1.1 cgd n->ndup.dupfd = -1;
554 1.1 cgd else
555 1.1 cgd goto bad;
556 1.1 cgd if (wordtext[1] != '\0') {
557 1.1 cgd bad:
558 1.1 cgd synerror("Bad fd number");
559 1.1 cgd }
560 1.1 cgd } else {
561 1.1 cgd n->nfile.fname = (union node *)stalloc(sizeof (struct narg));
562 1.1 cgd n = n->nfile.fname;
563 1.1 cgd n->type = NARG;
564 1.1 cgd n->narg.next = NULL;
565 1.1 cgd n->narg.text = wordtext;
566 1.1 cgd n->narg.backquote = backquotelist;
567 1.1 cgd }
568 1.1 cgd }
569 1.1 cgd
570 1.1 cgd
571 1.1 cgd /*
572 1.1 cgd * Input any here documents.
573 1.1 cgd */
574 1.1 cgd
575 1.1 cgd STATIC void
576 1.1 cgd parseheredoc() {
577 1.1 cgd struct heredoc *here;
578 1.1 cgd union node *n;
579 1.1 cgd
580 1.1 cgd while (heredoclist) {
581 1.1 cgd here = heredoclist;
582 1.1 cgd heredoclist = here->next;
583 1.1 cgd if (needprompt) {
584 1.1 cgd putprompt(ps2val());
585 1.1 cgd needprompt = 0;
586 1.1 cgd }
587 1.1 cgd readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
588 1.1 cgd here->eofmark, here->striptabs);
589 1.1 cgd n = (union node *)stalloc(sizeof (struct narg));
590 1.1 cgd n->narg.type = NARG;
591 1.1 cgd n->narg.next = NULL;
592 1.1 cgd n->narg.text = wordtext;
593 1.1 cgd n->narg.backquote = backquotelist;
594 1.1 cgd here->here->nhere.doc = n;
595 1.1 cgd }
596 1.1 cgd }
597 1.1 cgd
598 1.1 cgd STATIC int
599 1.1 cgd peektoken() {
600 1.1 cgd int t;
601 1.1 cgd
602 1.1 cgd t = readtoken();
603 1.1 cgd tokpushback++;
604 1.1 cgd return (t);
605 1.1 cgd }
606 1.1 cgd
607 1.1 cgd STATIC int xxreadtoken();
608 1.1 cgd
609 1.1 cgd STATIC int
610 1.1 cgd readtoken() {
611 1.1 cgd int t;
612 1.1 cgd #ifdef DEBUG
613 1.1 cgd int alreadyseen = tokpushback;
614 1.1 cgd #endif
615 1.1 cgd
616 1.1 cgd t = xxreadtoken();
617 1.1 cgd
618 1.1 cgd if (checkkwd) {
619 1.1 cgd /*
620 1.1 cgd * eat newlines
621 1.1 cgd */
622 1.1 cgd if (checkkwd == 2) {
623 1.1 cgd checkkwd = 0;
624 1.1 cgd while (t == TNL) {
625 1.1 cgd parseheredoc();
626 1.1 cgd t = xxreadtoken();
627 1.1 cgd }
628 1.1 cgd } else
629 1.1 cgd checkkwd = 0;
630 1.1 cgd /*
631 1.1 cgd * check for keywords
632 1.1 cgd */
633 1.1 cgd if (t == TWORD && !quoteflag) {
634 1.1 cgd register char **pp;
635 1.1 cgd
636 1.1 cgd for (pp = parsekwd; *pp; pp++) {
637 1.1 cgd if (**pp == *wordtext && equal(*pp, wordtext)) {
638 1.1 cgd lasttoken = t = pp - parsekwd + KWDOFFSET;
639 1.1 cgd TRACE(("keyword %s recognized\n", tokname[t]));
640 1.1 cgd break;
641 1.1 cgd }
642 1.1 cgd }
643 1.1 cgd }
644 1.1 cgd }
645 1.1 cgd #ifdef DEBUG
646 1.1 cgd if (!alreadyseen)
647 1.1 cgd TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
648 1.1 cgd else
649 1.1 cgd TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
650 1.1 cgd #endif
651 1.1 cgd return (t);
652 1.1 cgd }
653 1.1 cgd
654 1.1 cgd
655 1.1 cgd /*
656 1.1 cgd * Read the next input token.
657 1.1 cgd * If the token is a word, we set backquotelist to the list of cmds in
658 1.1 cgd * backquotes. We set quoteflag to true if any part of the word was
659 1.1 cgd * quoted.
660 1.1 cgd * If the token is TREDIR, then we set redirnode to a structure containing
661 1.1 cgd * the redirection.
662 1.1 cgd * In all cases, the variable startlinno is set to the number of the line
663 1.1 cgd * on which the token starts.
664 1.1 cgd *
665 1.1 cgd * [Change comment: here documents and internal procedures]
666 1.1 cgd * [Readtoken shouldn't have any arguments. Perhaps we should make the
667 1.1 cgd * word parsing code into a separate routine. In this case, readtoken
668 1.1 cgd * doesn't need to have any internal procedures, but parseword does.
669 1.1 cgd * We could also make parseoperator in essence the main routine, and
670 1.1 cgd * have parseword (readtoken1?) handle both words and redirection.]
671 1.1 cgd */
672 1.1 cgd
673 1.1 cgd #define RETURN(token) return lasttoken = token
674 1.1 cgd
675 1.1 cgd STATIC int
676 1.1 cgd xxreadtoken() {
677 1.1 cgd register c;
678 1.1 cgd
679 1.1 cgd if (tokpushback) {
680 1.1 cgd tokpushback = 0;
681 1.1 cgd return lasttoken;
682 1.1 cgd }
683 1.1 cgd if (needprompt) {
684 1.1 cgd putprompt(ps2val());
685 1.1 cgd needprompt = 0;
686 1.1 cgd }
687 1.1 cgd startlinno = plinno;
688 1.1 cgd for (;;) { /* until token or start of word found */
689 1.1 cgd c = pgetc_macro();
690 1.1 cgd if (c == ' ' || c == '\t')
691 1.1 cgd continue; /* quick check for white space first */
692 1.1 cgd switch (c) {
693 1.1 cgd case ' ': case '\t':
694 1.1 cgd continue;
695 1.1 cgd case '#':
696 1.1 cgd while ((c = pgetc()) != '\n' && c != PEOF);
697 1.1 cgd pungetc();
698 1.1 cgd continue;
699 1.1 cgd case '\\':
700 1.1 cgd if (pgetc() == '\n') {
701 1.1 cgd startlinno = ++plinno;
702 1.1 cgd if (doprompt)
703 1.1 cgd putprompt(ps2val());
704 1.1 cgd continue;
705 1.1 cgd }
706 1.1 cgd pungetc();
707 1.1 cgd goto breakloop;
708 1.1 cgd case '\n':
709 1.1 cgd plinno++;
710 1.1 cgd needprompt = doprompt;
711 1.1 cgd RETURN(TNL);
712 1.1 cgd case PEOF:
713 1.1 cgd RETURN(TEOF);
714 1.1 cgd case '&':
715 1.1 cgd if (pgetc() == '&')
716 1.1 cgd RETURN(TAND);
717 1.1 cgd pungetc();
718 1.1 cgd RETURN(TBACKGND);
719 1.1 cgd case '|':
720 1.1 cgd if (pgetc() == '|')
721 1.1 cgd RETURN(TOR);
722 1.1 cgd pungetc();
723 1.1 cgd RETURN(TPIPE);
724 1.1 cgd case ';':
725 1.1 cgd if (pgetc() == ';')
726 1.1 cgd RETURN(TENDCASE);
727 1.1 cgd pungetc();
728 1.1 cgd RETURN(TSEMI);
729 1.1 cgd case '(':
730 1.1 cgd RETURN(TLP);
731 1.1 cgd case ')':
732 1.1 cgd RETURN(TRP);
733 1.1 cgd default:
734 1.1 cgd goto breakloop;
735 1.1 cgd }
736 1.1 cgd }
737 1.1 cgd breakloop:
738 1.1 cgd return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
739 1.1 cgd #undef RETURN
740 1.1 cgd }
741 1.1 cgd
742 1.1 cgd
743 1.1 cgd
744 1.1 cgd /*
745 1.1 cgd * If eofmark is NULL, read a word or a redirection symbol. If eofmark
746 1.1 cgd * is not NULL, read a here document. In the latter case, eofmark is the
747 1.1 cgd * word which marks the end of the document and striptabs is true if
748 1.1 cgd * leading tabs should be stripped from the document. The argument firstc
749 1.1 cgd * is the first character of the input token or document.
750 1.1 cgd *
751 1.1 cgd * Because C does not have internal subroutines, I have simulated them
752 1.1 cgd * using goto's to implement the subroutine linkage. The following macros
753 1.1 cgd * will run code that appears at the end of readtoken1.
754 1.1 cgd */
755 1.1 cgd
756 1.1 cgd #define CHECKEND() {goto checkend; checkend_return:;}
757 1.1 cgd #define PARSEREDIR() {goto parseredir; parseredir_return:;}
758 1.1 cgd #define PARSESUB() {goto parsesub; parsesub_return:;}
759 1.1 cgd #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
760 1.1 cgd #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
761 1.1 cgd
762 1.1 cgd STATIC int
763 1.1 cgd readtoken1(firstc, syntax, eofmark, striptabs)
764 1.1 cgd int firstc;
765 1.1 cgd char const *syntax;
766 1.1 cgd char *eofmark;
767 1.1 cgd int striptabs;
768 1.1 cgd {
769 1.1 cgd register c = firstc;
770 1.1 cgd register char *out;
771 1.1 cgd int len;
772 1.1 cgd char line[EOFMARKLEN + 1];
773 1.1 cgd struct nodelist *bqlist;
774 1.1 cgd int quotef;
775 1.1 cgd int dblquote;
776 1.1 cgd int varnest;
777 1.1 cgd int oldstyle;
778 1.1 cgd
779 1.1 cgd startlinno = plinno;
780 1.1 cgd dblquote = 0;
781 1.1 cgd if (syntax == DQSYNTAX)
782 1.1 cgd dblquote = 1;
783 1.1 cgd quotef = 0;
784 1.1 cgd bqlist = NULL;
785 1.1 cgd varnest = 0;
786 1.1 cgd STARTSTACKSTR(out);
787 1.1 cgd loop: { /* for each line, until end of word */
788 1.1 cgd #if ATTY
789 1.1 cgd if (c == '\034' && doprompt
790 1.1 cgd && attyset() && ! equal(termval(), "emacs")) {
791 1.1 cgd attyline();
792 1.1 cgd if (syntax == BASESYNTAX)
793 1.1 cgd return readtoken();
794 1.1 cgd c = pgetc();
795 1.1 cgd goto loop;
796 1.1 cgd }
797 1.1 cgd #endif
798 1.1 cgd CHECKEND(); /* set c to PEOF if at end of here document */
799 1.1 cgd for (;;) { /* until end of line or end of word */
800 1.1 cgd CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
801 1.1 cgd switch(syntax[c]) {
802 1.1 cgd case CNL: /* '\n' */
803 1.1 cgd if (syntax == BASESYNTAX)
804 1.1 cgd goto endword; /* exit outer loop */
805 1.1 cgd USTPUTC(c, out);
806 1.1 cgd plinno++;
807 1.1 cgd if (doprompt) {
808 1.1 cgd putprompt(ps2val());
809 1.1 cgd }
810 1.1 cgd c = pgetc();
811 1.1 cgd goto loop; /* continue outer loop */
812 1.1 cgd case CWORD:
813 1.1 cgd USTPUTC(c, out);
814 1.1 cgd break;
815 1.1 cgd case CCTL:
816 1.1 cgd if (eofmark == NULL || dblquote)
817 1.1 cgd USTPUTC(CTLESC, out);
818 1.1 cgd USTPUTC(c, out);
819 1.1 cgd break;
820 1.1 cgd case CBACK: /* backslash */
821 1.1 cgd c = pgetc();
822 1.1 cgd if (c == PEOF) {
823 1.1 cgd USTPUTC('\\', out);
824 1.1 cgd pungetc();
825 1.1 cgd } else if (c == '\n') {
826 1.1 cgd if (doprompt)
827 1.1 cgd putprompt(ps2val());
828 1.1 cgd } else {
829 1.1 cgd if (dblquote && c != '\\' && c != '`' && c != '$'
830 1.1 cgd && (c != '"' || eofmark != NULL))
831 1.1 cgd USTPUTC('\\', out);
832 1.1 cgd if (SQSYNTAX[c] == CCTL)
833 1.1 cgd USTPUTC(CTLESC, out);
834 1.1 cgd USTPUTC(c, out);
835 1.1 cgd quotef++;
836 1.1 cgd }
837 1.1 cgd break;
838 1.1 cgd case CSQUOTE:
839 1.1 cgd syntax = SQSYNTAX;
840 1.1 cgd break;
841 1.1 cgd case CDQUOTE:
842 1.1 cgd syntax = DQSYNTAX;
843 1.1 cgd dblquote = 1;
844 1.1 cgd break;
845 1.1 cgd case CENDQUOTE:
846 1.1 cgd if (eofmark) {
847 1.1 cgd USTPUTC(c, out);
848 1.1 cgd } else {
849 1.1 cgd syntax = BASESYNTAX;
850 1.1 cgd quotef++;
851 1.1 cgd dblquote = 0;
852 1.1 cgd }
853 1.1 cgd break;
854 1.1 cgd case CVAR: /* '$' */
855 1.1 cgd PARSESUB(); /* parse substitution */
856 1.1 cgd break;
857 1.1 cgd case CENDVAR: /* '}' */
858 1.1 cgd if (varnest > 0) {
859 1.1 cgd varnest--;
860 1.1 cgd USTPUTC(CTLENDVAR, out);
861 1.1 cgd } else {
862 1.1 cgd USTPUTC(c, out);
863 1.1 cgd }
864 1.1 cgd break;
865 1.1 cgd case CBQUOTE: /* '`' */
866 1.1 cgd PARSEBACKQOLD();
867 1.1 cgd break;
868 1.1 cgd case CEOF:
869 1.1 cgd goto endword; /* exit outer loop */
870 1.1 cgd default:
871 1.1 cgd if (varnest == 0)
872 1.1 cgd goto endword; /* exit outer loop */
873 1.1 cgd USTPUTC(c, out);
874 1.1 cgd }
875 1.1 cgd c = pgetc_macro();
876 1.1 cgd }
877 1.1 cgd }
878 1.1 cgd endword:
879 1.5 sef if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
880 1.1 cgd synerror("Unterminated quoted string");
881 1.1 cgd if (varnest != 0) {
882 1.1 cgd startlinno = plinno;
883 1.1 cgd synerror("Missing '}'");
884 1.1 cgd }
885 1.1 cgd USTPUTC('\0', out);
886 1.1 cgd len = out - stackblock();
887 1.1 cgd out = stackblock();
888 1.1 cgd if (eofmark == NULL) {
889 1.1 cgd if ((c == '>' || c == '<')
890 1.1 cgd && quotef == 0
891 1.1 cgd && len <= 2
892 1.1 cgd && (*out == '\0' || is_digit(*out))) {
893 1.1 cgd PARSEREDIR();
894 1.1 cgd return lasttoken = TREDIR;
895 1.1 cgd } else {
896 1.1 cgd pungetc();
897 1.1 cgd }
898 1.1 cgd }
899 1.1 cgd quoteflag = quotef;
900 1.1 cgd backquotelist = bqlist;
901 1.1 cgd grabstackblock(len);
902 1.1 cgd wordtext = out;
903 1.1 cgd return lasttoken = TWORD;
904 1.1 cgd /* end of readtoken routine */
905 1.1 cgd
906 1.1 cgd
907 1.1 cgd
908 1.1 cgd /*
909 1.1 cgd * Check to see whether we are at the end of the here document. When this
910 1.1 cgd * is called, c is set to the first character of the next input line. If
911 1.1 cgd * we are at the end of the here document, this routine sets the c to PEOF.
912 1.1 cgd */
913 1.1 cgd
914 1.1 cgd checkend: {
915 1.1 cgd if (eofmark) {
916 1.1 cgd if (striptabs) {
917 1.1 cgd while (c == '\t')
918 1.1 cgd c = pgetc();
919 1.1 cgd }
920 1.1 cgd if (c == *eofmark) {
921 1.1 cgd if (pfgets(line, sizeof line) != NULL) {
922 1.1 cgd register char *p, *q;
923 1.1 cgd
924 1.1 cgd p = line;
925 1.1 cgd for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
926 1.1 cgd if (*p == '\n' && *q == '\0') {
927 1.1 cgd c = PEOF;
928 1.1 cgd plinno++;
929 1.1 cgd needprompt = doprompt;
930 1.1 cgd } else {
931 1.1 cgd ppushback(line, strlen(line));
932 1.1 cgd }
933 1.1 cgd }
934 1.1 cgd }
935 1.1 cgd }
936 1.1 cgd goto checkend_return;
937 1.1 cgd }
938 1.1 cgd
939 1.1 cgd
940 1.1 cgd /*
941 1.1 cgd * Parse a redirection operator. The variable "out" points to a string
942 1.1 cgd * specifying the fd to be redirected. The variable "c" contains the
943 1.1 cgd * first character of the redirection operator.
944 1.1 cgd */
945 1.1 cgd
946 1.1 cgd parseredir: {
947 1.1 cgd char fd = *out;
948 1.1 cgd union node *np;
949 1.1 cgd
950 1.1 cgd np = (union node *)stalloc(sizeof (struct nfile));
951 1.1 cgd if (c == '>') {
952 1.1 cgd np->nfile.fd = 1;
953 1.1 cgd c = pgetc();
954 1.1 cgd if (c == '>')
955 1.1 cgd np->type = NAPPEND;
956 1.1 cgd else if (c == '&')
957 1.1 cgd np->type = NTOFD;
958 1.1 cgd else {
959 1.1 cgd np->type = NTO;
960 1.1 cgd pungetc();
961 1.1 cgd }
962 1.1 cgd } else { /* c == '<' */
963 1.1 cgd np->nfile.fd = 0;
964 1.1 cgd c = pgetc();
965 1.1 cgd if (c == '<') {
966 1.1 cgd if (sizeof (struct nfile) != sizeof (struct nhere)) {
967 1.1 cgd np = (union node *)stalloc(sizeof (struct nhere));
968 1.1 cgd np->nfile.fd = 0;
969 1.1 cgd }
970 1.1 cgd np->type = NHERE;
971 1.1 cgd heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
972 1.1 cgd heredoc->here = np;
973 1.1 cgd if ((c = pgetc()) == '-') {
974 1.1 cgd heredoc->striptabs = 1;
975 1.1 cgd } else {
976 1.1 cgd heredoc->striptabs = 0;
977 1.1 cgd pungetc();
978 1.1 cgd }
979 1.1 cgd } else if (c == '&')
980 1.1 cgd np->type = NFROMFD;
981 1.1 cgd else {
982 1.1 cgd np->type = NFROM;
983 1.1 cgd pungetc();
984 1.1 cgd }
985 1.1 cgd }
986 1.1 cgd if (fd != '\0')
987 1.1 cgd np->nfile.fd = digit_val(fd);
988 1.1 cgd redirnode = np;
989 1.1 cgd goto parseredir_return;
990 1.1 cgd }
991 1.1 cgd
992 1.1 cgd
993 1.1 cgd /*
994 1.1 cgd * Parse a substitution. At this point, we have read the dollar sign
995 1.1 cgd * and nothing else.
996 1.1 cgd */
997 1.1 cgd
998 1.1 cgd parsesub: {
999 1.1 cgd int subtype;
1000 1.1 cgd int typeloc;
1001 1.1 cgd int flags;
1002 1.1 cgd char *p;
1003 1.1 cgd #ifndef GDB_HACK
1004 1.1 cgd static const char types[] = "}-+?=";
1005 1.1 cgd #endif
1006 1.1 cgd
1007 1.1 cgd c = pgetc();
1008 1.1 cgd if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
1009 1.1 cgd USTPUTC('$', out);
1010 1.1 cgd pungetc();
1011 1.1 cgd } else if (c == '(') { /* $(command) */
1012 1.1 cgd PARSEBACKQNEW();
1013 1.1 cgd } else {
1014 1.1 cgd USTPUTC(CTLVAR, out);
1015 1.1 cgd typeloc = out - stackblock();
1016 1.1 cgd USTPUTC(VSNORMAL, out);
1017 1.1 cgd subtype = VSNORMAL;
1018 1.1 cgd if (c == '{') {
1019 1.1 cgd c = pgetc();
1020 1.1 cgd subtype = 0;
1021 1.1 cgd }
1022 1.1 cgd if (is_name(c)) {
1023 1.1 cgd do {
1024 1.1 cgd STPUTC(c, out);
1025 1.1 cgd c = pgetc();
1026 1.1 cgd } while (is_in_name(c));
1027 1.1 cgd } else {
1028 1.1 cgd if (! is_special(c))
1029 1.1 cgd badsub: synerror("Bad substitution");
1030 1.1 cgd USTPUTC(c, out);
1031 1.1 cgd c = pgetc();
1032 1.1 cgd }
1033 1.1 cgd STPUTC('=', out);
1034 1.1 cgd flags = 0;
1035 1.1 cgd if (subtype == 0) {
1036 1.1 cgd if (c == ':') {
1037 1.1 cgd flags = VSNUL;
1038 1.1 cgd c = pgetc();
1039 1.1 cgd }
1040 1.1 cgd p = strchr(types, c);
1041 1.1 cgd if (p == NULL)
1042 1.1 cgd goto badsub;
1043 1.1 cgd subtype = p - types + VSNORMAL;
1044 1.1 cgd } else {
1045 1.1 cgd pungetc();
1046 1.1 cgd }
1047 1.1 cgd if (dblquote)
1048 1.1 cgd flags |= VSQUOTE;
1049 1.1 cgd *(stackblock() + typeloc) = subtype | flags;
1050 1.1 cgd if (subtype != VSNORMAL)
1051 1.1 cgd varnest++;
1052 1.1 cgd }
1053 1.1 cgd goto parsesub_return;
1054 1.1 cgd }
1055 1.1 cgd
1056 1.1 cgd
1057 1.1 cgd /*
1058 1.1 cgd * Called to parse command substitutions. Newstyle is set if the command
1059 1.1 cgd * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1060 1.1 cgd * list of commands (passed by reference), and savelen is the number of
1061 1.1 cgd * characters on the top of the stack which must be preserved.
1062 1.1 cgd */
1063 1.1 cgd
1064 1.1 cgd parsebackq: {
1065 1.1 cgd struct nodelist **nlpp;
1066 1.1 cgd int savepbq;
1067 1.1 cgd union node *n;
1068 1.1 cgd char *volatile str;
1069 1.1 cgd struct jmploc jmploc;
1070 1.1 cgd struct jmploc *volatile savehandler;
1071 1.1 cgd int savelen;
1072 1.1 cgd
1073 1.1 cgd savepbq = parsebackquote;
1074 1.1 cgd if (setjmp(jmploc.loc)) {
1075 1.1 cgd if (str)
1076 1.1 cgd ckfree(str);
1077 1.1 cgd parsebackquote = 0;
1078 1.1 cgd handler = savehandler;
1079 1.4 dpassage longjmp(handler->loc, 1);
1080 1.1 cgd }
1081 1.1 cgd INTOFF;
1082 1.1 cgd str = NULL;
1083 1.1 cgd savelen = out - stackblock();
1084 1.1 cgd if (savelen > 0) {
1085 1.1 cgd str = ckmalloc(savelen);
1086 1.1 cgd bcopy(stackblock(), str, savelen);
1087 1.1 cgd }
1088 1.1 cgd savehandler = handler;
1089 1.1 cgd handler = &jmploc;
1090 1.1 cgd INTON;
1091 1.5 sef if (oldstyle) {
1092 1.5 sef /* We must read until the closing backquote, giving special
1093 1.5 sef treatment to some slashes, and then push the string and
1094 1.5 sef reread it as input, interpreting it normally. */
1095 1.5 sef register char *out;
1096 1.5 sef register c;
1097 1.5 sef int savelen;
1098 1.5 sef char *str;
1099 1.5 sef
1100 1.5 sef STARTSTACKSTR(out);
1101 1.5 sef while ((c = pgetc ()) != '`') {
1102 1.5 sef if (c == '\\') {
1103 1.5 sef c = pgetc ();
1104 1.5 sef if (c != '\\' && c != '`' && c != '$'
1105 1.5 sef && (!dblquote || c != '"'))
1106 1.5 sef STPUTC('\\', out);
1107 1.5 sef }
1108 1.5 sef STPUTC(c, out);
1109 1.5 sef }
1110 1.5 sef STPUTC('\0', out);
1111 1.5 sef savelen = out - stackblock();
1112 1.5 sef if (savelen > 0) {
1113 1.5 sef str = ckmalloc(savelen);
1114 1.5 sef bcopy(stackblock(), str, savelen);
1115 1.5 sef }
1116 1.5 sef setinputstring(str, 1);
1117 1.5 sef }
1118 1.1 cgd nlpp = &bqlist;
1119 1.1 cgd while (*nlpp)
1120 1.1 cgd nlpp = &(*nlpp)->next;
1121 1.1 cgd *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1122 1.1 cgd (*nlpp)->next = NULL;
1123 1.1 cgd parsebackquote = oldstyle;
1124 1.1 cgd n = list(0);
1125 1.5 sef if (!oldstyle && (readtoken() != TRP))
1126 1.5 sef synexpect(TRP);
1127 1.1 cgd (*nlpp)->n = n;
1128 1.5 sef /* Start reading from old file again. */
1129 1.5 sef if (oldstyle)
1130 1.5 sef popfile();
1131 1.1 cgd while (stackblocksize() <= savelen)
1132 1.1 cgd growstackblock();
1133 1.1 cgd STARTSTACKSTR(out);
1134 1.1 cgd if (str) {
1135 1.1 cgd bcopy(str, out, savelen);
1136 1.1 cgd STADJUST(savelen, out);
1137 1.1 cgd INTOFF;
1138 1.1 cgd ckfree(str);
1139 1.1 cgd str = NULL;
1140 1.1 cgd INTON;
1141 1.1 cgd }
1142 1.1 cgd parsebackquote = savepbq;
1143 1.1 cgd handler = savehandler;
1144 1.1 cgd USTPUTC(CTLBACKQ + dblquote, out);
1145 1.1 cgd if (oldstyle)
1146 1.1 cgd goto parsebackq_oldreturn;
1147 1.1 cgd else
1148 1.1 cgd goto parsebackq_newreturn;
1149 1.1 cgd }
1150 1.1 cgd
1151 1.1 cgd } /* end of readtoken */
1152 1.1 cgd
1153 1.1 cgd
1154 1.1 cgd
1155 1.1 cgd #ifdef mkinit
1156 1.1 cgd RESET {
1157 1.1 cgd tokpushback = 0;
1158 1.1 cgd }
1159 1.1 cgd #endif
1160 1.1 cgd
1161 1.1 cgd
1162 1.1 cgd #if ATTY
1163 1.1 cgd /*
1164 1.1 cgd * Called to process a command generated by atty. We execute the line,
1165 1.1 cgd * and catch any errors that occur so they don't propagate outside of
1166 1.1 cgd * this routine.
1167 1.1 cgd */
1168 1.1 cgd
1169 1.1 cgd STATIC void
1170 1.1 cgd attyline() {
1171 1.1 cgd char line[256];
1172 1.1 cgd struct stackmark smark;
1173 1.1 cgd struct jmploc jmploc;
1174 1.1 cgd struct jmploc *volatile savehandler;
1175 1.1 cgd
1176 1.1 cgd if (pfgets(line, sizeof line) == NULL)
1177 1.1 cgd return; /* "can't happen" */
1178 1.1 cgd if (setjmp(jmploc.loc)) {
1179 1.1 cgd if (exception == EXERROR)
1180 1.1 cgd out2str("\033]D\n");
1181 1.1 cgd handler = savehandler;
1182 1.4 dpassage longjmp(handler->loc, 1);
1183 1.1 cgd }
1184 1.1 cgd savehandler = handler;
1185 1.1 cgd handler = &jmploc;
1186 1.1 cgd setstackmark(&smark);
1187 1.1 cgd evalstring(line);
1188 1.1 cgd popstackmark(&smark);
1189 1.1 cgd handler = savehandler;
1190 1.1 cgd doprompt = 1;
1191 1.1 cgd }
1192 1.1 cgd
1193 1.1 cgd
1194 1.1 cgd /*
1195 1.1 cgd * Output a prompt for atty. We output the prompt as part of the
1196 1.1 cgd * appropriate escape sequence.
1197 1.1 cgd */
1198 1.1 cgd
1199 1.1 cgd STATIC void
1200 1.1 cgd putprompt(s)
1201 1.1 cgd char *s;
1202 1.1 cgd {
1203 1.1 cgd register char *p;
1204 1.1 cgd
1205 1.1 cgd if (attyset() && ! equal(termval(), "emacs")) {
1206 1.1 cgd if (strchr(s, '\7'))
1207 1.1 cgd out2c('\7');
1208 1.1 cgd out2str("\033]P1;");
1209 1.1 cgd for (p = s ; *p ; p++) {
1210 1.1 cgd if ((unsigned)(*p - ' ') <= '~' - ' ')
1211 1.1 cgd out2c(*p);
1212 1.1 cgd }
1213 1.1 cgd out2c('\n');
1214 1.1 cgd } else {
1215 1.1 cgd out2str(s);
1216 1.1 cgd }
1217 1.1 cgd }
1218 1.1 cgd #endif
1219 1.1 cgd
1220 1.1 cgd
1221 1.1 cgd
1222 1.1 cgd /*
1223 1.1 cgd * Returns true if the text contains nothing to expand (no dollar signs
1224 1.1 cgd * or backquotes).
1225 1.1 cgd */
1226 1.1 cgd
1227 1.1 cgd STATIC int
1228 1.1 cgd noexpand(text)
1229 1.1 cgd char *text;
1230 1.1 cgd {
1231 1.1 cgd register char *p;
1232 1.1 cgd register char c;
1233 1.1 cgd
1234 1.1 cgd p = text;
1235 1.1 cgd while ((c = *p++) != '\0') {
1236 1.1 cgd if (c == CTLESC)
1237 1.1 cgd p++;
1238 1.1 cgd else if (BASESYNTAX[c] == CCTL)
1239 1.1 cgd return 0;
1240 1.1 cgd }
1241 1.1 cgd return 1;
1242 1.1 cgd }
1243 1.1 cgd
1244 1.1 cgd
1245 1.1 cgd /*
1246 1.1 cgd * Return true if the argument is a legal variable name (a letter or
1247 1.1 cgd * underscore followed by zero or more letters, underscores, and digits).
1248 1.1 cgd */
1249 1.1 cgd
1250 1.1 cgd int
1251 1.1 cgd goodname(name)
1252 1.1 cgd char *name;
1253 1.1 cgd {
1254 1.1 cgd register char *p;
1255 1.1 cgd
1256 1.1 cgd p = name;
1257 1.1 cgd if (! is_name(*p))
1258 1.1 cgd return 0;
1259 1.1 cgd while (*++p) {
1260 1.1 cgd if (! is_in_name(*p))
1261 1.1 cgd return 0;
1262 1.1 cgd }
1263 1.1 cgd return 1;
1264 1.1 cgd }
1265 1.1 cgd
1266 1.1 cgd
1267 1.1 cgd /*
1268 1.1 cgd * Called when an unexpected token is read during the parse. The argument
1269 1.1 cgd * is the token that is expected, or -1 if more than one type of token can
1270 1.1 cgd * occur at this point.
1271 1.1 cgd */
1272 1.1 cgd
1273 1.1 cgd STATIC void
1274 1.1 cgd synexpect(token) {
1275 1.1 cgd char msg[64];
1276 1.1 cgd
1277 1.1 cgd if (token >= 0) {
1278 1.1 cgd fmtstr(msg, 64, "%s unexpected (expecting %s)",
1279 1.1 cgd tokname[lasttoken], tokname[token]);
1280 1.1 cgd } else {
1281 1.1 cgd fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1282 1.1 cgd }
1283 1.1 cgd synerror(msg);
1284 1.1 cgd }
1285 1.1 cgd
1286 1.1 cgd
1287 1.1 cgd STATIC void
1288 1.1 cgd synerror(msg)
1289 1.1 cgd char *msg;
1290 1.1 cgd {
1291 1.1 cgd if (commandname)
1292 1.1 cgd outfmt(&errout, "%s: %d: ", commandname, startlinno);
1293 1.1 cgd outfmt(&errout, "Syntax error: %s\n", msg);
1294 1.1 cgd error((char *)NULL);
1295 1.1 cgd }
1296