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