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