parser.c revision 1.4 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.4 dpassage static char rcsid[] = "$Header: /tank/opengrok/rsync2/NetBSD/src/bin/sh/parser.c,v 1.4 1993/04/26 22:07:46 dpassage 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.1 cgd STATIC union node *simplecmd __P((void));
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.1 cgd switch (readtoken()) {
269 1.1 cgd case TIF:
270 1.1 cgd n1 = (union node *)stalloc(sizeof (struct nif));
271 1.1 cgd n1->type = NIF;
272 1.1 cgd n1->nif.test = list(0);
273 1.1 cgd if (readtoken() != TTHEN)
274 1.1 cgd synexpect(TTHEN);
275 1.1 cgd n1->nif.ifpart = list(0);
276 1.1 cgd n2 = n1;
277 1.1 cgd while (readtoken() == TELIF) {
278 1.1 cgd n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
279 1.1 cgd n2 = n2->nif.elsepart;
280 1.1 cgd n2->type = NIF;
281 1.1 cgd n2->nif.test = list(0);
282 1.1 cgd if (readtoken() != TTHEN)
283 1.1 cgd synexpect(TTHEN);
284 1.1 cgd n2->nif.ifpart = list(0);
285 1.1 cgd }
286 1.1 cgd if (lasttoken == TELSE)
287 1.1 cgd n2->nif.elsepart = list(0);
288 1.1 cgd else {
289 1.1 cgd n2->nif.elsepart = NULL;
290 1.1 cgd tokpushback++;
291 1.1 cgd }
292 1.1 cgd if (readtoken() != TFI)
293 1.1 cgd synexpect(TFI);
294 1.1 cgd checkkwd = 1;
295 1.1 cgd break;
296 1.1 cgd case TWHILE:
297 1.1 cgd case TUNTIL: {
298 1.1 cgd int got;
299 1.1 cgd n1 = (union node *)stalloc(sizeof (struct nbinary));
300 1.1 cgd n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
301 1.1 cgd n1->nbinary.ch1 = list(0);
302 1.1 cgd if ((got=readtoken()) != TDO) {
303 1.1 cgd TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
304 1.1 cgd synexpect(TDO);
305 1.1 cgd }
306 1.1 cgd n1->nbinary.ch2 = list(0);
307 1.1 cgd if (readtoken() != TDONE)
308 1.1 cgd synexpect(TDONE);
309 1.1 cgd checkkwd = 1;
310 1.1 cgd break;
311 1.1 cgd }
312 1.1 cgd case TFOR:
313 1.1 cgd if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
314 1.1 cgd synerror("Bad for loop variable");
315 1.1 cgd n1 = (union node *)stalloc(sizeof (struct nfor));
316 1.1 cgd n1->type = NFOR;
317 1.1 cgd n1->nfor.var = wordtext;
318 1.1 cgd if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
319 1.1 cgd app = ≈
320 1.1 cgd while (readtoken() == TWORD) {
321 1.1 cgd n2 = (union node *)stalloc(sizeof (struct narg));
322 1.1 cgd n2->type = NARG;
323 1.1 cgd n2->narg.text = wordtext;
324 1.1 cgd n2->narg.backquote = backquotelist;
325 1.1 cgd *app = n2;
326 1.1 cgd app = &n2->narg.next;
327 1.1 cgd }
328 1.1 cgd *app = NULL;
329 1.1 cgd n1->nfor.args = ap;
330 1.1 cgd } else {
331 1.1 cgd #ifndef GDB_HACK
332 1.1 cgd static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
333 1.1 cgd '@', '=', '\0'};
334 1.1 cgd #endif
335 1.1 cgd n2 = (union node *)stalloc(sizeof (struct narg));
336 1.1 cgd n2->type = NARG;
337 1.1 cgd n2->narg.text = (char *)argvars;
338 1.1 cgd n2->narg.backquote = NULL;
339 1.1 cgd n2->narg.next = NULL;
340 1.1 cgd n1->nfor.args = n2;
341 1.1 cgd }
342 1.1 cgd if (lasttoken != TNL && lasttoken != TSEMI)
343 1.1 cgd synexpect(-1);
344 1.1 cgd checkkwd = 2;
345 1.1 cgd if ((t = readtoken()) == TDO)
346 1.1 cgd t = TDONE;
347 1.1 cgd else if (t == TBEGIN)
348 1.1 cgd t = TEND;
349 1.1 cgd else
350 1.1 cgd synexpect(-1);
351 1.1 cgd n1->nfor.body = list(0);
352 1.1 cgd if (readtoken() != t)
353 1.1 cgd synexpect(t);
354 1.1 cgd checkkwd = 1;
355 1.1 cgd break;
356 1.1 cgd case TCASE:
357 1.1 cgd n1 = (union node *)stalloc(sizeof (struct ncase));
358 1.1 cgd n1->type = NCASE;
359 1.1 cgd if (readtoken() != TWORD)
360 1.1 cgd synexpect(TWORD);
361 1.1 cgd n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
362 1.1 cgd n2->type = NARG;
363 1.1 cgd n2->narg.text = wordtext;
364 1.1 cgd n2->narg.backquote = backquotelist;
365 1.1 cgd n2->narg.next = NULL;
366 1.1 cgd while (readtoken() == TNL);
367 1.1 cgd if (lasttoken != TWORD || ! equal(wordtext, "in"))
368 1.1 cgd synerror("expecting \"in\"");
369 1.1 cgd cpp = &n1->ncase.cases;
370 1.1 cgd while (checkkwd = 2, readtoken() == TWORD) {
371 1.1 cgd *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
372 1.1 cgd cp->type = NCLIST;
373 1.1 cgd app = &cp->nclist.pattern;
374 1.1 cgd for (;;) {
375 1.1 cgd *app = ap = (union node *)stalloc(sizeof (struct narg));
376 1.1 cgd ap->type = NARG;
377 1.1 cgd ap->narg.text = wordtext;
378 1.1 cgd ap->narg.backquote = backquotelist;
379 1.1 cgd if (readtoken() != TPIPE)
380 1.1 cgd break;
381 1.1 cgd app = &ap->narg.next;
382 1.1 cgd if (readtoken() != TWORD)
383 1.1 cgd synexpect(TWORD);
384 1.1 cgd }
385 1.1 cgd ap->narg.next = NULL;
386 1.1 cgd if (lasttoken != TRP)
387 1.1 cgd synexpect(TRP);
388 1.1 cgd cp->nclist.body = list(0);
389 1.1 cgd if ((t = readtoken()) == TESAC)
390 1.1 cgd tokpushback++;
391 1.1 cgd else if (t != TENDCASE)
392 1.1 cgd synexpect(TENDCASE);
393 1.1 cgd cpp = &cp->nclist.next;
394 1.1 cgd }
395 1.1 cgd *cpp = NULL;
396 1.1 cgd if (lasttoken != TESAC)
397 1.1 cgd synexpect(TESAC);
398 1.1 cgd checkkwd = 1;
399 1.1 cgd break;
400 1.1 cgd case TLP:
401 1.1 cgd n1 = (union node *)stalloc(sizeof (struct nredir));
402 1.1 cgd n1->type = NSUBSHELL;
403 1.1 cgd n1->nredir.n = list(0);
404 1.1 cgd n1->nredir.redirect = NULL;
405 1.1 cgd if (readtoken() != TRP)
406 1.1 cgd synexpect(TRP);
407 1.1 cgd checkkwd = 1;
408 1.1 cgd break;
409 1.1 cgd case TBEGIN:
410 1.1 cgd n1 = list(0);
411 1.1 cgd if (readtoken() != TEND)
412 1.1 cgd synexpect(TEND);
413 1.1 cgd checkkwd = 1;
414 1.1 cgd break;
415 1.1 cgd case TWORD:
416 1.1 cgd case TREDIR:
417 1.1 cgd tokpushback++;
418 1.1 cgd return simplecmd();
419 1.1 cgd default:
420 1.1 cgd synexpect(-1);
421 1.1 cgd }
422 1.1 cgd
423 1.1 cgd /* Now check for redirection which may follow command */
424 1.1 cgd rpp = &redir;
425 1.1 cgd while (readtoken() == TREDIR) {
426 1.1 cgd *rpp = n2 = redirnode;
427 1.1 cgd rpp = &n2->nfile.next;
428 1.1 cgd parsefname();
429 1.1 cgd }
430 1.1 cgd tokpushback++;
431 1.1 cgd *rpp = NULL;
432 1.1 cgd if (redir) {
433 1.1 cgd if (n1->type != NSUBSHELL) {
434 1.1 cgd n2 = (union node *)stalloc(sizeof (struct nredir));
435 1.1 cgd n2->type = NREDIR;
436 1.1 cgd n2->nredir.n = n1;
437 1.1 cgd n1 = n2;
438 1.1 cgd }
439 1.1 cgd n1->nredir.redirect = redir;
440 1.1 cgd }
441 1.1 cgd return n1;
442 1.1 cgd }
443 1.1 cgd
444 1.1 cgd
445 1.1 cgd STATIC union node *
446 1.1 cgd simplecmd() {
447 1.1 cgd union node *args, **app;
448 1.1 cgd union node *redir, **rpp;
449 1.1 cgd union node *n;
450 1.1 cgd
451 1.1 cgd args = NULL;
452 1.1 cgd app = &args;
453 1.1 cgd rpp = &redir;
454 1.1 cgd for (;;) {
455 1.1 cgd if (readtoken() == TWORD) {
456 1.1 cgd n = (union node *)stalloc(sizeof (struct narg));
457 1.1 cgd n->type = NARG;
458 1.1 cgd n->narg.text = wordtext;
459 1.1 cgd n->narg.backquote = backquotelist;
460 1.1 cgd *app = n;
461 1.1 cgd app = &n->narg.next;
462 1.1 cgd } else if (lasttoken == TREDIR) {
463 1.1 cgd *rpp = n = redirnode;
464 1.1 cgd rpp = &n->nfile.next;
465 1.1 cgd parsefname(); /* read name of redirection file */
466 1.1 cgd } else if (lasttoken == TLP && app == &args->narg.next
467 1.1 cgd && rpp == &redir) {
468 1.1 cgd /* We have a function */
469 1.1 cgd if (readtoken() != TRP)
470 1.1 cgd synexpect(TRP);
471 1.1 cgd #ifdef notdef
472 1.1 cgd if (! goodname(n->narg.text))
473 1.1 cgd synerror("Bad function name");
474 1.1 cgd #endif
475 1.1 cgd n->type = NDEFUN;
476 1.1 cgd n->narg.next = command();
477 1.1 cgd return n;
478 1.1 cgd } else {
479 1.1 cgd tokpushback++;
480 1.1 cgd break;
481 1.1 cgd }
482 1.1 cgd }
483 1.1 cgd *app = NULL;
484 1.1 cgd *rpp = NULL;
485 1.1 cgd n = (union node *)stalloc(sizeof (struct ncmd));
486 1.1 cgd n->type = NCMD;
487 1.1 cgd n->ncmd.backgnd = 0;
488 1.1 cgd n->ncmd.args = args;
489 1.1 cgd n->ncmd.redirect = redir;
490 1.1 cgd return n;
491 1.1 cgd }
492 1.1 cgd
493 1.1 cgd
494 1.1 cgd STATIC void
495 1.1 cgd parsefname() {
496 1.1 cgd union node *n = redirnode;
497 1.1 cgd
498 1.1 cgd if (readtoken() != TWORD)
499 1.1 cgd synexpect(-1);
500 1.1 cgd if (n->type == NHERE) {
501 1.1 cgd struct heredoc *here = heredoc;
502 1.1 cgd struct heredoc *p;
503 1.1 cgd int i;
504 1.1 cgd
505 1.1 cgd if (quoteflag == 0)
506 1.1 cgd n->type = NXHERE;
507 1.1 cgd TRACE(("Here document %d\n", n->type));
508 1.1 cgd if (here->striptabs) {
509 1.1 cgd while (*wordtext == '\t')
510 1.1 cgd wordtext++;
511 1.1 cgd }
512 1.1 cgd if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
513 1.1 cgd synerror("Illegal eof marker for << redirection");
514 1.1 cgd rmescapes(wordtext);
515 1.1 cgd here->eofmark = wordtext;
516 1.1 cgd here->next = NULL;
517 1.1 cgd if (heredoclist == NULL)
518 1.1 cgd heredoclist = here;
519 1.1 cgd else {
520 1.1 cgd for (p = heredoclist ; p->next ; p = p->next);
521 1.1 cgd p->next = here;
522 1.1 cgd }
523 1.1 cgd } else if (n->type == NTOFD || n->type == NFROMFD) {
524 1.1 cgd if (is_digit(wordtext[0]))
525 1.1 cgd n->ndup.dupfd = digit_val(wordtext[0]);
526 1.1 cgd else if (wordtext[0] == '-')
527 1.1 cgd n->ndup.dupfd = -1;
528 1.1 cgd else
529 1.1 cgd goto bad;
530 1.1 cgd if (wordtext[1] != '\0') {
531 1.1 cgd bad:
532 1.1 cgd synerror("Bad fd number");
533 1.1 cgd }
534 1.1 cgd } else {
535 1.1 cgd n->nfile.fname = (union node *)stalloc(sizeof (struct narg));
536 1.1 cgd n = n->nfile.fname;
537 1.1 cgd n->type = NARG;
538 1.1 cgd n->narg.next = NULL;
539 1.1 cgd n->narg.text = wordtext;
540 1.1 cgd n->narg.backquote = backquotelist;
541 1.1 cgd }
542 1.1 cgd }
543 1.1 cgd
544 1.1 cgd
545 1.1 cgd /*
546 1.1 cgd * Input any here documents.
547 1.1 cgd */
548 1.1 cgd
549 1.1 cgd STATIC void
550 1.1 cgd parseheredoc() {
551 1.1 cgd struct heredoc *here;
552 1.1 cgd union node *n;
553 1.1 cgd
554 1.1 cgd while (heredoclist) {
555 1.1 cgd here = heredoclist;
556 1.1 cgd heredoclist = here->next;
557 1.1 cgd if (needprompt) {
558 1.1 cgd putprompt(ps2val());
559 1.1 cgd needprompt = 0;
560 1.1 cgd }
561 1.1 cgd readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
562 1.1 cgd here->eofmark, here->striptabs);
563 1.1 cgd n = (union node *)stalloc(sizeof (struct narg));
564 1.1 cgd n->narg.type = NARG;
565 1.1 cgd n->narg.next = NULL;
566 1.1 cgd n->narg.text = wordtext;
567 1.1 cgd n->narg.backquote = backquotelist;
568 1.1 cgd here->here->nhere.doc = n;
569 1.1 cgd }
570 1.1 cgd }
571 1.1 cgd
572 1.1 cgd STATIC int
573 1.1 cgd peektoken() {
574 1.1 cgd int t;
575 1.1 cgd
576 1.1 cgd t = readtoken();
577 1.1 cgd tokpushback++;
578 1.1 cgd return (t);
579 1.1 cgd }
580 1.1 cgd
581 1.1 cgd STATIC int xxreadtoken();
582 1.1 cgd
583 1.1 cgd STATIC int
584 1.1 cgd readtoken() {
585 1.1 cgd int t;
586 1.1 cgd #ifdef DEBUG
587 1.1 cgd int alreadyseen = tokpushback;
588 1.1 cgd #endif
589 1.1 cgd
590 1.1 cgd t = xxreadtoken();
591 1.1 cgd
592 1.1 cgd if (checkkwd) {
593 1.1 cgd /*
594 1.1 cgd * eat newlines
595 1.1 cgd */
596 1.1 cgd if (checkkwd == 2) {
597 1.1 cgd checkkwd = 0;
598 1.1 cgd while (t == TNL) {
599 1.1 cgd parseheredoc();
600 1.1 cgd t = xxreadtoken();
601 1.1 cgd }
602 1.1 cgd } else
603 1.1 cgd checkkwd = 0;
604 1.1 cgd /*
605 1.1 cgd * check for keywords
606 1.1 cgd */
607 1.1 cgd if (t == TWORD && !quoteflag) {
608 1.1 cgd register char **pp;
609 1.1 cgd
610 1.1 cgd for (pp = parsekwd; *pp; pp++) {
611 1.1 cgd if (**pp == *wordtext && equal(*pp, wordtext)) {
612 1.1 cgd lasttoken = t = pp - parsekwd + KWDOFFSET;
613 1.1 cgd TRACE(("keyword %s recognized\n", tokname[t]));
614 1.1 cgd break;
615 1.1 cgd }
616 1.1 cgd }
617 1.1 cgd }
618 1.1 cgd }
619 1.1 cgd #ifdef DEBUG
620 1.1 cgd if (!alreadyseen)
621 1.1 cgd TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
622 1.1 cgd else
623 1.1 cgd TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
624 1.1 cgd #endif
625 1.1 cgd return (t);
626 1.1 cgd }
627 1.1 cgd
628 1.1 cgd
629 1.1 cgd /*
630 1.1 cgd * Read the next input token.
631 1.1 cgd * If the token is a word, we set backquotelist to the list of cmds in
632 1.1 cgd * backquotes. We set quoteflag to true if any part of the word was
633 1.1 cgd * quoted.
634 1.1 cgd * If the token is TREDIR, then we set redirnode to a structure containing
635 1.1 cgd * the redirection.
636 1.1 cgd * In all cases, the variable startlinno is set to the number of the line
637 1.1 cgd * on which the token starts.
638 1.1 cgd *
639 1.1 cgd * [Change comment: here documents and internal procedures]
640 1.1 cgd * [Readtoken shouldn't have any arguments. Perhaps we should make the
641 1.1 cgd * word parsing code into a separate routine. In this case, readtoken
642 1.1 cgd * doesn't need to have any internal procedures, but parseword does.
643 1.1 cgd * We could also make parseoperator in essence the main routine, and
644 1.1 cgd * have parseword (readtoken1?) handle both words and redirection.]
645 1.1 cgd */
646 1.1 cgd
647 1.1 cgd #define RETURN(token) return lasttoken = token
648 1.1 cgd
649 1.1 cgd STATIC int
650 1.1 cgd xxreadtoken() {
651 1.1 cgd register c;
652 1.1 cgd
653 1.1 cgd if (tokpushback) {
654 1.1 cgd tokpushback = 0;
655 1.1 cgd return lasttoken;
656 1.1 cgd }
657 1.1 cgd if (needprompt) {
658 1.1 cgd putprompt(ps2val());
659 1.1 cgd needprompt = 0;
660 1.1 cgd }
661 1.1 cgd startlinno = plinno;
662 1.1 cgd for (;;) { /* until token or start of word found */
663 1.1 cgd c = pgetc_macro();
664 1.1 cgd if (c == ' ' || c == '\t')
665 1.1 cgd continue; /* quick check for white space first */
666 1.1 cgd switch (c) {
667 1.1 cgd case ' ': case '\t':
668 1.1 cgd continue;
669 1.1 cgd case '#':
670 1.1 cgd while ((c = pgetc()) != '\n' && c != PEOF);
671 1.1 cgd pungetc();
672 1.1 cgd continue;
673 1.1 cgd case '\\':
674 1.1 cgd if (pgetc() == '\n') {
675 1.1 cgd startlinno = ++plinno;
676 1.1 cgd if (doprompt)
677 1.1 cgd putprompt(ps2val());
678 1.1 cgd continue;
679 1.1 cgd }
680 1.1 cgd pungetc();
681 1.1 cgd goto breakloop;
682 1.1 cgd case '\n':
683 1.1 cgd plinno++;
684 1.1 cgd needprompt = doprompt;
685 1.1 cgd RETURN(TNL);
686 1.1 cgd case PEOF:
687 1.1 cgd RETURN(TEOF);
688 1.1 cgd case '&':
689 1.1 cgd if (pgetc() == '&')
690 1.1 cgd RETURN(TAND);
691 1.1 cgd pungetc();
692 1.1 cgd RETURN(TBACKGND);
693 1.1 cgd case '|':
694 1.1 cgd if (pgetc() == '|')
695 1.1 cgd RETURN(TOR);
696 1.1 cgd pungetc();
697 1.1 cgd RETURN(TPIPE);
698 1.1 cgd case ';':
699 1.1 cgd if (pgetc() == ';')
700 1.1 cgd RETURN(TENDCASE);
701 1.1 cgd pungetc();
702 1.1 cgd RETURN(TSEMI);
703 1.1 cgd case '(':
704 1.1 cgd RETURN(TLP);
705 1.1 cgd case ')':
706 1.1 cgd RETURN(TRP);
707 1.1 cgd default:
708 1.1 cgd goto breakloop;
709 1.1 cgd }
710 1.1 cgd }
711 1.1 cgd breakloop:
712 1.1 cgd return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
713 1.1 cgd #undef RETURN
714 1.1 cgd }
715 1.1 cgd
716 1.1 cgd
717 1.1 cgd
718 1.1 cgd /*
719 1.1 cgd * If eofmark is NULL, read a word or a redirection symbol. If eofmark
720 1.1 cgd * is not NULL, read a here document. In the latter case, eofmark is the
721 1.1 cgd * word which marks the end of the document and striptabs is true if
722 1.1 cgd * leading tabs should be stripped from the document. The argument firstc
723 1.1 cgd * is the first character of the input token or document.
724 1.1 cgd *
725 1.1 cgd * Because C does not have internal subroutines, I have simulated them
726 1.1 cgd * using goto's to implement the subroutine linkage. The following macros
727 1.1 cgd * will run code that appears at the end of readtoken1.
728 1.1 cgd */
729 1.1 cgd
730 1.1 cgd #define CHECKEND() {goto checkend; checkend_return:;}
731 1.1 cgd #define PARSEREDIR() {goto parseredir; parseredir_return:;}
732 1.1 cgd #define PARSESUB() {goto parsesub; parsesub_return:;}
733 1.1 cgd #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
734 1.1 cgd #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
735 1.1 cgd
736 1.1 cgd STATIC int
737 1.1 cgd readtoken1(firstc, syntax, eofmark, striptabs)
738 1.1 cgd int firstc;
739 1.1 cgd char const *syntax;
740 1.1 cgd char *eofmark;
741 1.1 cgd int striptabs;
742 1.1 cgd {
743 1.1 cgd register c = firstc;
744 1.1 cgd register char *out;
745 1.1 cgd int len;
746 1.1 cgd char line[EOFMARKLEN + 1];
747 1.1 cgd struct nodelist *bqlist;
748 1.1 cgd int quotef;
749 1.1 cgd int dblquote;
750 1.1 cgd int varnest;
751 1.1 cgd int oldstyle;
752 1.1 cgd
753 1.1 cgd startlinno = plinno;
754 1.1 cgd dblquote = 0;
755 1.1 cgd if (syntax == DQSYNTAX)
756 1.1 cgd dblquote = 1;
757 1.1 cgd quotef = 0;
758 1.1 cgd bqlist = NULL;
759 1.1 cgd varnest = 0;
760 1.1 cgd STARTSTACKSTR(out);
761 1.1 cgd loop: { /* for each line, until end of word */
762 1.1 cgd #if ATTY
763 1.1 cgd if (c == '\034' && doprompt
764 1.1 cgd && attyset() && ! equal(termval(), "emacs")) {
765 1.1 cgd attyline();
766 1.1 cgd if (syntax == BASESYNTAX)
767 1.1 cgd return readtoken();
768 1.1 cgd c = pgetc();
769 1.1 cgd goto loop;
770 1.1 cgd }
771 1.1 cgd #endif
772 1.1 cgd CHECKEND(); /* set c to PEOF if at end of here document */
773 1.1 cgd for (;;) { /* until end of line or end of word */
774 1.1 cgd CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
775 1.1 cgd switch(syntax[c]) {
776 1.1 cgd case CNL: /* '\n' */
777 1.1 cgd if (syntax == BASESYNTAX)
778 1.1 cgd goto endword; /* exit outer loop */
779 1.1 cgd USTPUTC(c, out);
780 1.1 cgd plinno++;
781 1.1 cgd if (doprompt) {
782 1.1 cgd putprompt(ps2val());
783 1.1 cgd }
784 1.1 cgd c = pgetc();
785 1.1 cgd goto loop; /* continue outer loop */
786 1.1 cgd case CWORD:
787 1.1 cgd USTPUTC(c, out);
788 1.1 cgd break;
789 1.1 cgd case CCTL:
790 1.1 cgd if (eofmark == NULL || dblquote)
791 1.1 cgd USTPUTC(CTLESC, out);
792 1.1 cgd USTPUTC(c, out);
793 1.1 cgd break;
794 1.1 cgd case CBACK: /* backslash */
795 1.1 cgd c = pgetc();
796 1.1 cgd if (c == PEOF) {
797 1.1 cgd USTPUTC('\\', out);
798 1.1 cgd pungetc();
799 1.1 cgd } else if (c == '\n') {
800 1.1 cgd if (doprompt)
801 1.1 cgd putprompt(ps2val());
802 1.1 cgd } else {
803 1.1 cgd if (dblquote && c != '\\' && c != '`' && c != '$'
804 1.1 cgd && (c != '"' || eofmark != NULL))
805 1.1 cgd USTPUTC('\\', out);
806 1.1 cgd if (SQSYNTAX[c] == CCTL)
807 1.1 cgd USTPUTC(CTLESC, out);
808 1.1 cgd USTPUTC(c, out);
809 1.1 cgd quotef++;
810 1.1 cgd }
811 1.1 cgd break;
812 1.1 cgd case CSQUOTE:
813 1.1 cgd syntax = SQSYNTAX;
814 1.1 cgd break;
815 1.1 cgd case CDQUOTE:
816 1.1 cgd syntax = DQSYNTAX;
817 1.1 cgd dblquote = 1;
818 1.1 cgd break;
819 1.1 cgd case CENDQUOTE:
820 1.1 cgd if (eofmark) {
821 1.1 cgd USTPUTC(c, out);
822 1.1 cgd } else {
823 1.1 cgd syntax = BASESYNTAX;
824 1.1 cgd quotef++;
825 1.1 cgd dblquote = 0;
826 1.1 cgd }
827 1.1 cgd break;
828 1.1 cgd case CVAR: /* '$' */
829 1.1 cgd PARSESUB(); /* parse substitution */
830 1.1 cgd break;
831 1.1 cgd case CENDVAR: /* '}' */
832 1.1 cgd if (varnest > 0) {
833 1.1 cgd varnest--;
834 1.1 cgd USTPUTC(CTLENDVAR, out);
835 1.1 cgd } else {
836 1.1 cgd USTPUTC(c, out);
837 1.1 cgd }
838 1.1 cgd break;
839 1.1 cgd case CBQUOTE: /* '`' */
840 1.1 cgd if (parsebackquote && syntax == BASESYNTAX) {
841 1.1 cgd if (out == stackblock())
842 1.1 cgd return lasttoken = TENDBQUOTE;
843 1.1 cgd else
844 1.1 cgd goto endword; /* exit outer loop */
845 1.1 cgd }
846 1.1 cgd PARSEBACKQOLD();
847 1.1 cgd break;
848 1.1 cgd case CEOF:
849 1.1 cgd goto endword; /* exit outer loop */
850 1.1 cgd default:
851 1.1 cgd if (varnest == 0)
852 1.1 cgd goto endword; /* exit outer loop */
853 1.1 cgd USTPUTC(c, out);
854 1.1 cgd }
855 1.1 cgd c = pgetc_macro();
856 1.1 cgd }
857 1.1 cgd }
858 1.1 cgd endword:
859 1.1 cgd if (syntax != BASESYNTAX && eofmark == NULL)
860 1.1 cgd synerror("Unterminated quoted string");
861 1.1 cgd if (varnest != 0) {
862 1.1 cgd startlinno = plinno;
863 1.1 cgd synerror("Missing '}'");
864 1.1 cgd }
865 1.1 cgd USTPUTC('\0', out);
866 1.1 cgd len = out - stackblock();
867 1.1 cgd out = stackblock();
868 1.1 cgd if (eofmark == NULL) {
869 1.1 cgd if ((c == '>' || c == '<')
870 1.1 cgd && quotef == 0
871 1.1 cgd && len <= 2
872 1.1 cgd && (*out == '\0' || is_digit(*out))) {
873 1.1 cgd PARSEREDIR();
874 1.1 cgd return lasttoken = TREDIR;
875 1.1 cgd } else {
876 1.1 cgd pungetc();
877 1.1 cgd }
878 1.1 cgd }
879 1.1 cgd quoteflag = quotef;
880 1.1 cgd backquotelist = bqlist;
881 1.1 cgd grabstackblock(len);
882 1.1 cgd wordtext = out;
883 1.1 cgd return lasttoken = TWORD;
884 1.1 cgd /* end of readtoken routine */
885 1.1 cgd
886 1.1 cgd
887 1.1 cgd
888 1.1 cgd /*
889 1.1 cgd * Check to see whether we are at the end of the here document. When this
890 1.1 cgd * is called, c is set to the first character of the next input line. If
891 1.1 cgd * we are at the end of the here document, this routine sets the c to PEOF.
892 1.1 cgd */
893 1.1 cgd
894 1.1 cgd checkend: {
895 1.1 cgd if (eofmark) {
896 1.1 cgd if (striptabs) {
897 1.1 cgd while (c == '\t')
898 1.1 cgd c = pgetc();
899 1.1 cgd }
900 1.1 cgd if (c == *eofmark) {
901 1.1 cgd if (pfgets(line, sizeof line) != NULL) {
902 1.1 cgd register char *p, *q;
903 1.1 cgd
904 1.1 cgd p = line;
905 1.1 cgd for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
906 1.1 cgd if (*p == '\n' && *q == '\0') {
907 1.1 cgd c = PEOF;
908 1.1 cgd plinno++;
909 1.1 cgd needprompt = doprompt;
910 1.1 cgd } else {
911 1.1 cgd ppushback(line, strlen(line));
912 1.1 cgd }
913 1.1 cgd }
914 1.1 cgd }
915 1.1 cgd }
916 1.1 cgd goto checkend_return;
917 1.1 cgd }
918 1.1 cgd
919 1.1 cgd
920 1.1 cgd /*
921 1.1 cgd * Parse a redirection operator. The variable "out" points to a string
922 1.1 cgd * specifying the fd to be redirected. The variable "c" contains the
923 1.1 cgd * first character of the redirection operator.
924 1.1 cgd */
925 1.1 cgd
926 1.1 cgd parseredir: {
927 1.1 cgd char fd = *out;
928 1.1 cgd union node *np;
929 1.1 cgd
930 1.1 cgd np = (union node *)stalloc(sizeof (struct nfile));
931 1.1 cgd if (c == '>') {
932 1.1 cgd np->nfile.fd = 1;
933 1.1 cgd c = pgetc();
934 1.1 cgd if (c == '>')
935 1.1 cgd np->type = NAPPEND;
936 1.1 cgd else if (c == '&')
937 1.1 cgd np->type = NTOFD;
938 1.1 cgd else {
939 1.1 cgd np->type = NTO;
940 1.1 cgd pungetc();
941 1.1 cgd }
942 1.1 cgd } else { /* c == '<' */
943 1.1 cgd np->nfile.fd = 0;
944 1.1 cgd c = pgetc();
945 1.1 cgd if (c == '<') {
946 1.1 cgd if (sizeof (struct nfile) != sizeof (struct nhere)) {
947 1.1 cgd np = (union node *)stalloc(sizeof (struct nhere));
948 1.1 cgd np->nfile.fd = 0;
949 1.1 cgd }
950 1.1 cgd np->type = NHERE;
951 1.1 cgd heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
952 1.1 cgd heredoc->here = np;
953 1.1 cgd if ((c = pgetc()) == '-') {
954 1.1 cgd heredoc->striptabs = 1;
955 1.1 cgd } else {
956 1.1 cgd heredoc->striptabs = 0;
957 1.1 cgd pungetc();
958 1.1 cgd }
959 1.1 cgd } else if (c == '&')
960 1.1 cgd np->type = NFROMFD;
961 1.1 cgd else {
962 1.1 cgd np->type = NFROM;
963 1.1 cgd pungetc();
964 1.1 cgd }
965 1.1 cgd }
966 1.1 cgd if (fd != '\0')
967 1.1 cgd np->nfile.fd = digit_val(fd);
968 1.1 cgd redirnode = np;
969 1.1 cgd goto parseredir_return;
970 1.1 cgd }
971 1.1 cgd
972 1.1 cgd
973 1.1 cgd /*
974 1.1 cgd * Parse a substitution. At this point, we have read the dollar sign
975 1.1 cgd * and nothing else.
976 1.1 cgd */
977 1.1 cgd
978 1.1 cgd parsesub: {
979 1.1 cgd int subtype;
980 1.1 cgd int typeloc;
981 1.1 cgd int flags;
982 1.1 cgd char *p;
983 1.1 cgd #ifndef GDB_HACK
984 1.1 cgd static const char types[] = "}-+?=";
985 1.1 cgd #endif
986 1.1 cgd
987 1.1 cgd c = pgetc();
988 1.1 cgd if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
989 1.1 cgd USTPUTC('$', out);
990 1.1 cgd pungetc();
991 1.1 cgd } else if (c == '(') { /* $(command) */
992 1.1 cgd PARSEBACKQNEW();
993 1.1 cgd } else {
994 1.1 cgd USTPUTC(CTLVAR, out);
995 1.1 cgd typeloc = out - stackblock();
996 1.1 cgd USTPUTC(VSNORMAL, out);
997 1.1 cgd subtype = VSNORMAL;
998 1.1 cgd if (c == '{') {
999 1.1 cgd c = pgetc();
1000 1.1 cgd subtype = 0;
1001 1.1 cgd }
1002 1.1 cgd if (is_name(c)) {
1003 1.1 cgd do {
1004 1.1 cgd STPUTC(c, out);
1005 1.1 cgd c = pgetc();
1006 1.1 cgd } while (is_in_name(c));
1007 1.1 cgd } else {
1008 1.1 cgd if (! is_special(c))
1009 1.1 cgd badsub: synerror("Bad substitution");
1010 1.1 cgd USTPUTC(c, out);
1011 1.1 cgd c = pgetc();
1012 1.1 cgd }
1013 1.1 cgd STPUTC('=', out);
1014 1.1 cgd flags = 0;
1015 1.1 cgd if (subtype == 0) {
1016 1.1 cgd if (c == ':') {
1017 1.1 cgd flags = VSNUL;
1018 1.1 cgd c = pgetc();
1019 1.1 cgd }
1020 1.1 cgd p = strchr(types, c);
1021 1.1 cgd if (p == NULL)
1022 1.1 cgd goto badsub;
1023 1.1 cgd subtype = p - types + VSNORMAL;
1024 1.1 cgd } else {
1025 1.1 cgd pungetc();
1026 1.1 cgd }
1027 1.1 cgd if (dblquote)
1028 1.1 cgd flags |= VSQUOTE;
1029 1.1 cgd *(stackblock() + typeloc) = subtype | flags;
1030 1.1 cgd if (subtype != VSNORMAL)
1031 1.1 cgd varnest++;
1032 1.1 cgd }
1033 1.1 cgd goto parsesub_return;
1034 1.1 cgd }
1035 1.1 cgd
1036 1.1 cgd
1037 1.1 cgd /*
1038 1.1 cgd * Called to parse command substitutions. Newstyle is set if the command
1039 1.1 cgd * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1040 1.1 cgd * list of commands (passed by reference), and savelen is the number of
1041 1.1 cgd * characters on the top of the stack which must be preserved.
1042 1.1 cgd */
1043 1.1 cgd
1044 1.1 cgd parsebackq: {
1045 1.1 cgd struct nodelist **nlpp;
1046 1.1 cgd int savepbq;
1047 1.1 cgd union node *n;
1048 1.1 cgd char *volatile str;
1049 1.1 cgd struct jmploc jmploc;
1050 1.1 cgd struct jmploc *volatile savehandler;
1051 1.1 cgd int savelen;
1052 1.1 cgd int t;
1053 1.1 cgd
1054 1.1 cgd savepbq = parsebackquote;
1055 1.1 cgd if (setjmp(jmploc.loc)) {
1056 1.1 cgd if (str)
1057 1.1 cgd ckfree(str);
1058 1.1 cgd parsebackquote = 0;
1059 1.1 cgd handler = savehandler;
1060 1.4 dpassage longjmp(handler->loc, 1);
1061 1.1 cgd }
1062 1.1 cgd INTOFF;
1063 1.1 cgd str = NULL;
1064 1.1 cgd savelen = out - stackblock();
1065 1.1 cgd if (savelen > 0) {
1066 1.1 cgd str = ckmalloc(savelen);
1067 1.1 cgd bcopy(stackblock(), str, savelen);
1068 1.1 cgd }
1069 1.1 cgd savehandler = handler;
1070 1.1 cgd handler = &jmploc;
1071 1.1 cgd INTON;
1072 1.1 cgd nlpp = &bqlist;
1073 1.1 cgd while (*nlpp)
1074 1.1 cgd nlpp = &(*nlpp)->next;
1075 1.1 cgd *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1076 1.1 cgd (*nlpp)->next = NULL;
1077 1.1 cgd parsebackquote = oldstyle;
1078 1.1 cgd n = list(0);
1079 1.1 cgd t = oldstyle? TENDBQUOTE : TRP;
1080 1.1 cgd if (readtoken() != t)
1081 1.1 cgd synexpect(t);
1082 1.1 cgd (*nlpp)->n = n;
1083 1.1 cgd while (stackblocksize() <= savelen)
1084 1.1 cgd growstackblock();
1085 1.1 cgd STARTSTACKSTR(out);
1086 1.1 cgd if (str) {
1087 1.1 cgd bcopy(str, out, savelen);
1088 1.1 cgd STADJUST(savelen, out);
1089 1.1 cgd INTOFF;
1090 1.1 cgd ckfree(str);
1091 1.1 cgd str = NULL;
1092 1.1 cgd INTON;
1093 1.1 cgd }
1094 1.1 cgd parsebackquote = savepbq;
1095 1.1 cgd handler = savehandler;
1096 1.1 cgd USTPUTC(CTLBACKQ + dblquote, out);
1097 1.1 cgd if (oldstyle)
1098 1.1 cgd goto parsebackq_oldreturn;
1099 1.1 cgd else
1100 1.1 cgd goto parsebackq_newreturn;
1101 1.1 cgd }
1102 1.1 cgd
1103 1.1 cgd } /* end of readtoken */
1104 1.1 cgd
1105 1.1 cgd
1106 1.1 cgd
1107 1.1 cgd #ifdef mkinit
1108 1.1 cgd RESET {
1109 1.1 cgd tokpushback = 0;
1110 1.1 cgd }
1111 1.1 cgd #endif
1112 1.1 cgd
1113 1.1 cgd
1114 1.1 cgd #if ATTY
1115 1.1 cgd /*
1116 1.1 cgd * Called to process a command generated by atty. We execute the line,
1117 1.1 cgd * and catch any errors that occur so they don't propagate outside of
1118 1.1 cgd * this routine.
1119 1.1 cgd */
1120 1.1 cgd
1121 1.1 cgd STATIC void
1122 1.1 cgd attyline() {
1123 1.1 cgd char line[256];
1124 1.1 cgd struct stackmark smark;
1125 1.1 cgd struct jmploc jmploc;
1126 1.1 cgd struct jmploc *volatile savehandler;
1127 1.1 cgd
1128 1.1 cgd if (pfgets(line, sizeof line) == NULL)
1129 1.1 cgd return; /* "can't happen" */
1130 1.1 cgd if (setjmp(jmploc.loc)) {
1131 1.1 cgd if (exception == EXERROR)
1132 1.1 cgd out2str("\033]D\n");
1133 1.1 cgd handler = savehandler;
1134 1.4 dpassage longjmp(handler->loc, 1);
1135 1.1 cgd }
1136 1.1 cgd savehandler = handler;
1137 1.1 cgd handler = &jmploc;
1138 1.1 cgd setstackmark(&smark);
1139 1.1 cgd evalstring(line);
1140 1.1 cgd popstackmark(&smark);
1141 1.1 cgd handler = savehandler;
1142 1.1 cgd doprompt = 1;
1143 1.1 cgd }
1144 1.1 cgd
1145 1.1 cgd
1146 1.1 cgd /*
1147 1.1 cgd * Output a prompt for atty. We output the prompt as part of the
1148 1.1 cgd * appropriate escape sequence.
1149 1.1 cgd */
1150 1.1 cgd
1151 1.1 cgd STATIC void
1152 1.1 cgd putprompt(s)
1153 1.1 cgd char *s;
1154 1.1 cgd {
1155 1.1 cgd register char *p;
1156 1.1 cgd
1157 1.1 cgd if (attyset() && ! equal(termval(), "emacs")) {
1158 1.1 cgd if (strchr(s, '\7'))
1159 1.1 cgd out2c('\7');
1160 1.1 cgd out2str("\033]P1;");
1161 1.1 cgd for (p = s ; *p ; p++) {
1162 1.1 cgd if ((unsigned)(*p - ' ') <= '~' - ' ')
1163 1.1 cgd out2c(*p);
1164 1.1 cgd }
1165 1.1 cgd out2c('\n');
1166 1.1 cgd } else {
1167 1.1 cgd out2str(s);
1168 1.1 cgd }
1169 1.1 cgd }
1170 1.1 cgd #endif
1171 1.1 cgd
1172 1.1 cgd
1173 1.1 cgd
1174 1.1 cgd /*
1175 1.1 cgd * Returns true if the text contains nothing to expand (no dollar signs
1176 1.1 cgd * or backquotes).
1177 1.1 cgd */
1178 1.1 cgd
1179 1.1 cgd STATIC int
1180 1.1 cgd noexpand(text)
1181 1.1 cgd char *text;
1182 1.1 cgd {
1183 1.1 cgd register char *p;
1184 1.1 cgd register char c;
1185 1.1 cgd
1186 1.1 cgd p = text;
1187 1.1 cgd while ((c = *p++) != '\0') {
1188 1.1 cgd if (c == CTLESC)
1189 1.1 cgd p++;
1190 1.1 cgd else if (BASESYNTAX[c] == CCTL)
1191 1.1 cgd return 0;
1192 1.1 cgd }
1193 1.1 cgd return 1;
1194 1.1 cgd }
1195 1.1 cgd
1196 1.1 cgd
1197 1.1 cgd /*
1198 1.1 cgd * Return true if the argument is a legal variable name (a letter or
1199 1.1 cgd * underscore followed by zero or more letters, underscores, and digits).
1200 1.1 cgd */
1201 1.1 cgd
1202 1.1 cgd int
1203 1.1 cgd goodname(name)
1204 1.1 cgd char *name;
1205 1.1 cgd {
1206 1.1 cgd register char *p;
1207 1.1 cgd
1208 1.1 cgd p = name;
1209 1.1 cgd if (! is_name(*p))
1210 1.1 cgd return 0;
1211 1.1 cgd while (*++p) {
1212 1.1 cgd if (! is_in_name(*p))
1213 1.1 cgd return 0;
1214 1.1 cgd }
1215 1.1 cgd return 1;
1216 1.1 cgd }
1217 1.1 cgd
1218 1.1 cgd
1219 1.1 cgd /*
1220 1.1 cgd * Called when an unexpected token is read during the parse. The argument
1221 1.1 cgd * is the token that is expected, or -1 if more than one type of token can
1222 1.1 cgd * occur at this point.
1223 1.1 cgd */
1224 1.1 cgd
1225 1.1 cgd STATIC void
1226 1.1 cgd synexpect(token) {
1227 1.1 cgd char msg[64];
1228 1.1 cgd
1229 1.1 cgd if (token >= 0) {
1230 1.1 cgd fmtstr(msg, 64, "%s unexpected (expecting %s)",
1231 1.1 cgd tokname[lasttoken], tokname[token]);
1232 1.1 cgd } else {
1233 1.1 cgd fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1234 1.1 cgd }
1235 1.1 cgd synerror(msg);
1236 1.1 cgd }
1237 1.1 cgd
1238 1.1 cgd
1239 1.1 cgd STATIC void
1240 1.1 cgd synerror(msg)
1241 1.1 cgd char *msg;
1242 1.1 cgd {
1243 1.1 cgd if (commandname)
1244 1.1 cgd outfmt(&errout, "%s: %d: ", commandname, startlinno);
1245 1.1 cgd outfmt(&errout, "Syntax error: %s\n", msg);
1246 1.1 cgd error((char *)NULL);
1247 1.1 cgd }
1248