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