~mirabilos/klibc/master

« back to all changes in this revision

Viewing changes to dash/parser.c

  • Committer: H. Peter Anvin
  • Date: 2006-05-01 00:56:02 UTC
  • Revision ID: git-v1:5dea5e01daaaff0685016f23b5cb46240f28e792
[klibc] Reorganize the standalone klibc tree to match the in-kernel tree

Right now, it's harder than it should to apply and test patches using
the standalone klibc tree.  Reorganize the standalone tree to match
the in-kernel tree.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>

Show diffs side-by-side

added added

removed removed

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