Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/bin/sh/parser.c
101853 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1991, 1993
5
* The Regents of the University of California. 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 <sys/param.h>
36
#include <pwd.h>
37
#include <stdlib.h>
38
#include <unistd.h>
39
#include <stdio.h>
40
#include <time.h>
41
42
#include "shell.h"
43
#include "parser.h"
44
#include "nodes.h"
45
#include "expand.h" /* defines rmescapes() */
46
#include "syntax.h"
47
#include "options.h"
48
#include "input.h"
49
#include "output.h"
50
#include "var.h"
51
#include "error.h"
52
#include "memalloc.h"
53
#include "mystring.h"
54
#include "alias.h"
55
#include "show.h"
56
#include "eval.h"
57
#include "exec.h" /* to check for special builtins */
58
#include "main.h"
59
#include "jobs.h"
60
#ifndef NO_HISTORY
61
#include "myhistedit.h"
62
#endif
63
64
/*
65
* Shell command parser.
66
*/
67
68
#define PROMPTLEN 192
69
70
/* values of checkkwd variable */
71
#define CHKALIAS 0x1
72
#define CHKKWD 0x2
73
#define CHKNL 0x4
74
75
/* values returned by readtoken */
76
#include "token.h"
77
78
79
80
struct heredoc {
81
struct heredoc *next; /* next here document in list */
82
union node *here; /* redirection node */
83
char *eofmark; /* string indicating end of input */
84
int striptabs; /* if set, strip leading tabs */
85
};
86
87
struct parser_temp {
88
struct parser_temp *next;
89
void *data;
90
};
91
92
93
static struct heredoc *heredoclist; /* list of here documents to read */
94
static int doprompt; /* if set, prompt the user */
95
static int needprompt; /* true if interactive and at start of line */
96
static int lasttoken; /* last token read */
97
static int tokpushback; /* last token pushed back */
98
static char *wordtext; /* text of last word returned by readtoken */
99
static int checkkwd;
100
static struct nodelist *backquotelist;
101
static union node *redirnode;
102
static struct heredoc *heredoc;
103
static int quoteflag; /* set if (part of) last token was quoted */
104
static int startlinno; /* line # where last token started */
105
static int funclinno; /* line # where the current function started */
106
static struct parser_temp *parser_temp;
107
108
#define NOEOFMARK ((const char *)&heredoclist)
109
110
111
static union node *list(int);
112
static union node *andor(void);
113
static union node *pipeline(void);
114
static union node *command(void);
115
static union node *simplecmd(union node **, union node *);
116
static union node *makename(void);
117
static union node *makebinary(int type, union node *n1, union node *n2);
118
static void parsefname(void);
119
static void parseheredoc(void);
120
static int peektoken(void);
121
static int readtoken(void);
122
static int xxreadtoken(void);
123
static int readtoken1(int, const char *, const char *, int);
124
static int noexpand(char *);
125
static void consumetoken(int);
126
static void synexpect(int) __dead2;
127
static void synerror(const char *) __dead2;
128
static void setprompt(int);
129
static int pgetc_linecont(void);
130
static void getusername(char *, size_t);
131
132
133
static void *
134
parser_temp_alloc(size_t len)
135
{
136
struct parser_temp *t;
137
138
INTOFF;
139
t = ckmalloc(sizeof(*t));
140
t->data = NULL;
141
t->next = parser_temp;
142
parser_temp = t;
143
t->data = ckmalloc(len);
144
INTON;
145
return t->data;
146
}
147
148
149
static void *
150
parser_temp_realloc(void *ptr, size_t len)
151
{
152
struct parser_temp *t;
153
154
INTOFF;
155
t = parser_temp;
156
if (ptr != t->data)
157
error("bug: parser_temp_realloc misused");
158
t->data = ckrealloc(t->data, len);
159
INTON;
160
return t->data;
161
}
162
163
164
static void
165
parser_temp_free_upto(void *ptr)
166
{
167
struct parser_temp *t;
168
int done = 0;
169
170
INTOFF;
171
while (parser_temp != NULL && !done) {
172
t = parser_temp;
173
parser_temp = t->next;
174
done = t->data == ptr;
175
ckfree(t->data);
176
ckfree(t);
177
}
178
INTON;
179
if (!done)
180
error("bug: parser_temp_free_upto misused");
181
}
182
183
184
static void
185
parser_temp_free_all(void)
186
{
187
struct parser_temp *t;
188
189
INTOFF;
190
while (parser_temp != NULL) {
191
t = parser_temp;
192
parser_temp = t->next;
193
ckfree(t->data);
194
ckfree(t);
195
}
196
INTON;
197
}
198
199
200
/*
201
* Read and parse a command. Returns NEOF on end of file. (NULL is a
202
* valid parse tree indicating a blank line.)
203
*/
204
205
union node *
206
parsecmd(int interact)
207
{
208
int t;
209
210
/* This assumes the parser is not re-entered,
211
* which could happen if we add command substitution on PS1/PS2.
212
*/
213
parser_temp_free_all();
214
heredoclist = NULL;
215
216
tokpushback = 0;
217
checkkwd = 0;
218
doprompt = interact;
219
if (doprompt)
220
setprompt(1);
221
else
222
setprompt(0);
223
needprompt = 0;
224
t = readtoken();
225
if (t == TEOF)
226
return NEOF;
227
if (t == TNL)
228
return NULL;
229
tokpushback++;
230
return list(1);
231
}
232
233
234
/*
235
* Read and parse words for wordexp.
236
* Returns a list of NARG nodes; NULL if there are no words.
237
*/
238
union node *
239
parsewordexp(void)
240
{
241
union node *n, *first = NULL, **pnext;
242
int t;
243
244
/* This assumes the parser is not re-entered,
245
* which could happen if we add command substitution on PS1/PS2.
246
*/
247
parser_temp_free_all();
248
heredoclist = NULL;
249
250
tokpushback = 0;
251
checkkwd = 0;
252
doprompt = 0;
253
setprompt(0);
254
needprompt = 0;
255
pnext = &first;
256
while ((t = readtoken()) != TEOF) {
257
if (t != TWORD)
258
synexpect(TWORD);
259
n = makename();
260
*pnext = n;
261
pnext = &n->narg.next;
262
}
263
return first;
264
}
265
266
267
static union node *
268
list(int nlflag)
269
{
270
union node *ntop, *n1, *n2, *n3;
271
int tok;
272
273
checkkwd = CHKNL | CHKKWD | CHKALIAS;
274
if (!nlflag && tokendlist[peektoken()])
275
return NULL;
276
ntop = n1 = NULL;
277
for (;;) {
278
n2 = andor();
279
tok = readtoken();
280
if (tok == TBACKGND) {
281
if (n2 != NULL && n2->type == NPIPE) {
282
n2->npipe.backgnd = 1;
283
} else if (n2 != NULL && n2->type == NREDIR) {
284
n2->type = NBACKGND;
285
} else {
286
n3 = (union node *)stalloc(sizeof (struct nredir));
287
n3->type = NBACKGND;
288
n3->nredir.n = n2;
289
n3->nredir.redirect = NULL;
290
n2 = n3;
291
}
292
}
293
if (ntop == NULL)
294
ntop = n2;
295
else if (n1 == NULL) {
296
n1 = makebinary(NSEMI, ntop, n2);
297
ntop = n1;
298
}
299
else {
300
n3 = makebinary(NSEMI, n1->nbinary.ch2, n2);
301
n1->nbinary.ch2 = n3;
302
n1 = n3;
303
}
304
switch (tok) {
305
case TBACKGND:
306
case TSEMI:
307
tok = readtoken();
308
/* FALLTHROUGH */
309
case TNL:
310
if (tok == TNL) {
311
parseheredoc();
312
if (nlflag)
313
return ntop;
314
} else if (tok == TEOF && nlflag) {
315
parseheredoc();
316
return ntop;
317
} else {
318
tokpushback++;
319
}
320
checkkwd = CHKNL | CHKKWD | CHKALIAS;
321
if (!nlflag && tokendlist[peektoken()])
322
return ntop;
323
break;
324
case TEOF:
325
if (heredoclist)
326
parseheredoc();
327
else
328
pungetc(); /* push back EOF on input */
329
return ntop;
330
default:
331
if (nlflag)
332
synexpect(-1);
333
tokpushback++;
334
return ntop;
335
}
336
}
337
}
338
339
340
341
static union node *
342
andor(void)
343
{
344
union node *n;
345
int t;
346
347
n = pipeline();
348
for (;;) {
349
if ((t = readtoken()) == TAND) {
350
t = NAND;
351
} else if (t == TOR) {
352
t = NOR;
353
} else {
354
tokpushback++;
355
return n;
356
}
357
n = makebinary(t, n, pipeline());
358
}
359
}
360
361
362
363
static union node *
364
pipeline(void)
365
{
366
union node *n1, *n2, *pipenode;
367
struct nodelist *lp, *prev;
368
int negate, t;
369
370
negate = 0;
371
checkkwd = CHKNL | CHKKWD | CHKALIAS;
372
TRACE(("pipeline: entered\n"));
373
while (readtoken() == TNOT)
374
negate = !negate;
375
tokpushback++;
376
n1 = command();
377
if (readtoken() == TPIPE) {
378
pipenode = (union node *)stalloc(sizeof (struct npipe));
379
pipenode->type = NPIPE;
380
pipenode->npipe.backgnd = 0;
381
lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
382
pipenode->npipe.cmdlist = lp;
383
lp->n = n1;
384
do {
385
prev = lp;
386
lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
387
checkkwd = CHKNL | CHKKWD | CHKALIAS;
388
t = readtoken();
389
tokpushback++;
390
if (t == TNOT)
391
lp->n = pipeline();
392
else
393
lp->n = command();
394
prev->next = lp;
395
} while (readtoken() == TPIPE);
396
lp->next = NULL;
397
n1 = pipenode;
398
}
399
tokpushback++;
400
if (negate) {
401
n2 = (union node *)stalloc(sizeof (struct nnot));
402
n2->type = NNOT;
403
n2->nnot.com = n1;
404
return n2;
405
} else
406
return n1;
407
}
408
409
410
411
static union node *
412
command(void)
413
{
414
union node *n1, *n2;
415
union node *ap, **app;
416
union node *cp, **cpp;
417
union node *redir, **rpp;
418
int t;
419
int is_subshell;
420
421
checkkwd = CHKNL | CHKKWD | CHKALIAS;
422
is_subshell = 0;
423
redir = NULL;
424
n1 = NULL;
425
rpp = &redir;
426
427
/* Check for redirection which may precede command */
428
while (readtoken() == TREDIR) {
429
*rpp = n2 = redirnode;
430
rpp = &n2->nfile.next;
431
parsefname();
432
}
433
tokpushback++;
434
435
switch (readtoken()) {
436
case TIF:
437
n1 = (union node *)stalloc(sizeof (struct nif));
438
n1->type = NIF;
439
if ((n1->nif.test = list(0)) == NULL)
440
synexpect(-1);
441
consumetoken(TTHEN);
442
n1->nif.ifpart = list(0);
443
n2 = n1;
444
while (readtoken() == TELIF) {
445
n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
446
n2 = n2->nif.elsepart;
447
n2->type = NIF;
448
if ((n2->nif.test = list(0)) == NULL)
449
synexpect(-1);
450
consumetoken(TTHEN);
451
n2->nif.ifpart = list(0);
452
}
453
if (lasttoken == TELSE)
454
n2->nif.elsepart = list(0);
455
else {
456
n2->nif.elsepart = NULL;
457
tokpushback++;
458
}
459
consumetoken(TFI);
460
checkkwd = CHKKWD | CHKALIAS;
461
break;
462
case TWHILE:
463
case TUNTIL:
464
t = lasttoken;
465
if ((n1 = list(0)) == NULL)
466
synexpect(-1);
467
consumetoken(TDO);
468
n1 = makebinary((t == TWHILE)? NWHILE : NUNTIL, n1, list(0));
469
consumetoken(TDONE);
470
checkkwd = CHKKWD | CHKALIAS;
471
break;
472
case TFOR:
473
if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
474
synerror("Bad for loop variable");
475
n1 = (union node *)stalloc(sizeof (struct nfor));
476
n1->type = NFOR;
477
n1->nfor.var = wordtext;
478
checkkwd = CHKNL;
479
if (readtoken() == TWORD && !quoteflag &&
480
equal(wordtext, "in")) {
481
app = &ap;
482
while (readtoken() == TWORD) {
483
n2 = makename();
484
*app = n2;
485
app = &n2->narg.next;
486
}
487
*app = NULL;
488
n1->nfor.args = ap;
489
if (lasttoken == TNL)
490
tokpushback++;
491
else if (lasttoken != TSEMI)
492
synexpect(-1);
493
} else {
494
static char argvars[5] = {
495
CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
496
};
497
n2 = (union node *)stalloc(sizeof (struct narg));
498
n2->type = NARG;
499
n2->narg.text = argvars;
500
n2->narg.backquote = NULL;
501
n2->narg.next = NULL;
502
n1->nfor.args = n2;
503
/*
504
* Newline or semicolon here is optional (but note
505
* that the original Bourne shell only allowed NL).
506
*/
507
if (lasttoken != TSEMI)
508
tokpushback++;
509
}
510
checkkwd = CHKNL | CHKKWD | CHKALIAS;
511
if ((t = readtoken()) == TDO)
512
t = TDONE;
513
else if (t == TBEGIN)
514
t = TEND;
515
else
516
synexpect(-1);
517
n1->nfor.body = list(0);
518
consumetoken(t);
519
checkkwd = CHKKWD | CHKALIAS;
520
break;
521
case TCASE:
522
n1 = (union node *)stalloc(sizeof (struct ncase));
523
n1->type = NCASE;
524
consumetoken(TWORD);
525
n1->ncase.expr = makename();
526
checkkwd = CHKNL;
527
if (readtoken() != TWORD || ! equal(wordtext, "in"))
528
synerror("expecting \"in\"");
529
cpp = &n1->ncase.cases;
530
checkkwd = CHKNL | CHKKWD, readtoken();
531
while (lasttoken != TESAC) {
532
*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
533
cp->type = NCLIST;
534
app = &cp->nclist.pattern;
535
if (lasttoken == TLP)
536
readtoken();
537
for (;;) {
538
*app = ap = makename();
539
checkkwd = CHKNL | CHKKWD;
540
if (readtoken() != TPIPE)
541
break;
542
app = &ap->narg.next;
543
readtoken();
544
}
545
ap->narg.next = NULL;
546
if (lasttoken != TRP)
547
synexpect(TRP);
548
cp->nclist.body = list(0);
549
550
checkkwd = CHKNL | CHKKWD | CHKALIAS;
551
if ((t = readtoken()) != TESAC) {
552
if (t == TENDCASE)
553
;
554
else if (t == TFALLTHRU)
555
cp->type = NCLISTFALLTHRU;
556
else
557
synexpect(TENDCASE);
558
checkkwd = CHKNL | CHKKWD, readtoken();
559
}
560
cpp = &cp->nclist.next;
561
}
562
*cpp = NULL;
563
checkkwd = CHKKWD | CHKALIAS;
564
break;
565
case TLP:
566
n1 = (union node *)stalloc(sizeof (struct nredir));
567
n1->type = NSUBSHELL;
568
n1->nredir.n = list(0);
569
n1->nredir.redirect = NULL;
570
consumetoken(TRP);
571
checkkwd = CHKKWD | CHKALIAS;
572
is_subshell = 1;
573
break;
574
case TBEGIN:
575
n1 = list(0);
576
consumetoken(TEND);
577
checkkwd = CHKKWD | CHKALIAS;
578
break;
579
/* A simple command must have at least one redirection or word. */
580
case TBACKGND:
581
case TSEMI:
582
case TAND:
583
case TOR:
584
case TPIPE:
585
case TENDCASE:
586
case TFALLTHRU:
587
case TEOF:
588
case TNL:
589
case TRP:
590
if (!redir)
591
synexpect(-1);
592
case TWORD:
593
tokpushback++;
594
n1 = simplecmd(rpp, redir);
595
return n1;
596
default:
597
synexpect(-1);
598
}
599
600
/* Now check for redirection which may follow command */
601
while (readtoken() == TREDIR) {
602
*rpp = n2 = redirnode;
603
rpp = &n2->nfile.next;
604
parsefname();
605
}
606
tokpushback++;
607
*rpp = NULL;
608
if (redir) {
609
if (!is_subshell) {
610
n2 = (union node *)stalloc(sizeof (struct nredir));
611
n2->type = NREDIR;
612
n2->nredir.n = n1;
613
n1 = n2;
614
}
615
n1->nredir.redirect = redir;
616
}
617
618
return n1;
619
}
620
621
622
static union node *
623
simplecmd(union node **rpp, union node *redir)
624
{
625
union node *args, **app;
626
union node **orig_rpp = rpp;
627
union node *n = NULL;
628
int special;
629
int savecheckkwd;
630
631
/* If we don't have any redirections already, then we must reset */
632
/* rpp to be the address of the local redir variable. */
633
if (redir == NULL)
634
rpp = &redir;
635
636
args = NULL;
637
app = &args;
638
/*
639
* We save the incoming value, because we need this for shell
640
* functions. There can not be a redirect or an argument between
641
* the function name and the open parenthesis.
642
*/
643
orig_rpp = rpp;
644
645
savecheckkwd = CHKALIAS;
646
647
for (;;) {
648
checkkwd = savecheckkwd;
649
if (readtoken() == TWORD) {
650
n = makename();
651
*app = n;
652
app = &n->narg.next;
653
if (savecheckkwd != 0 && !isassignment(wordtext))
654
savecheckkwd = 0;
655
} else if (lasttoken == TREDIR) {
656
*rpp = n = redirnode;
657
rpp = &n->nfile.next;
658
parsefname(); /* read name of redirection file */
659
} else if (lasttoken == TLP && app == &args->narg.next
660
&& rpp == orig_rpp) {
661
/* We have a function */
662
consumetoken(TRP);
663
funclinno = plinno;
664
/*
665
* - Require plain text.
666
* - Functions with '/' cannot be called.
667
* - Reject name=().
668
* - Reject ksh extended glob patterns.
669
*/
670
if (!noexpand(n->narg.text) || quoteflag ||
671
strchr(n->narg.text, '/') ||
672
strchr("!%*+-=?@}~",
673
n->narg.text[strlen(n->narg.text) - 1]))
674
synerror("Bad function name");
675
rmescapes(n->narg.text);
676
if (find_builtin(n->narg.text, &special) >= 0 &&
677
special)
678
synerror("Cannot override a special builtin with a function");
679
n->type = NDEFUN;
680
n->narg.next = command();
681
funclinno = 0;
682
return n;
683
} else {
684
tokpushback++;
685
break;
686
}
687
}
688
*app = NULL;
689
*rpp = NULL;
690
n = (union node *)stalloc(sizeof (struct ncmd));
691
n->type = NCMD;
692
n->ncmd.args = args;
693
n->ncmd.redirect = redir;
694
return n;
695
}
696
697
static union node *
698
makename(void)
699
{
700
union node *n;
701
702
n = (union node *)stalloc(sizeof (struct narg));
703
n->type = NARG;
704
n->narg.next = NULL;
705
n->narg.text = wordtext;
706
n->narg.backquote = backquotelist;
707
return n;
708
}
709
710
static union node *
711
makebinary(int type, union node *n1, union node *n2)
712
{
713
union node *n;
714
715
n = (union node *)stalloc(sizeof (struct nbinary));
716
n->type = type;
717
n->nbinary.ch1 = n1;
718
n->nbinary.ch2 = n2;
719
return (n);
720
}
721
722
void
723
forcealias(void)
724
{
725
checkkwd |= CHKALIAS;
726
}
727
728
void
729
fixredir(union node *n, const char *text, int err)
730
{
731
TRACE(("Fix redir %s %d\n", text, err));
732
if (!err)
733
n->ndup.vname = NULL;
734
735
if (is_digit(text[0]) && text[1] == '\0')
736
n->ndup.dupfd = digit_val(text[0]);
737
else if (text[0] == '-' && text[1] == '\0')
738
n->ndup.dupfd = -1;
739
else {
740
741
if (err)
742
synerror("Bad fd number");
743
else
744
n->ndup.vname = makename();
745
}
746
}
747
748
749
static void
750
parsefname(void)
751
{
752
union node *n = redirnode;
753
754
consumetoken(TWORD);
755
if (n->type == NHERE) {
756
struct heredoc *here = heredoc;
757
struct heredoc *p;
758
759
if (quoteflag == 0)
760
n->type = NXHERE;
761
TRACE(("Here document %d\n", n->type));
762
if (here->striptabs) {
763
while (*wordtext == '\t')
764
wordtext++;
765
}
766
if (! noexpand(wordtext))
767
synerror("Illegal eof marker for << redirection");
768
rmescapes(wordtext);
769
here->eofmark = wordtext;
770
here->next = NULL;
771
if (heredoclist == NULL)
772
heredoclist = here;
773
else {
774
for (p = heredoclist ; p->next ; p = p->next);
775
p->next = here;
776
}
777
} else if (n->type == NTOFD || n->type == NFROMFD) {
778
fixredir(n, wordtext, 0);
779
} else {
780
n->nfile.fname = makename();
781
}
782
}
783
784
785
/*
786
* Input any here documents.
787
*/
788
789
static void
790
parseheredoc(void)
791
{
792
struct heredoc *here;
793
union node *n;
794
795
while (heredoclist) {
796
here = heredoclist;
797
heredoclist = here->next;
798
if (needprompt) {
799
setprompt(2);
800
needprompt = 0;
801
}
802
readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
803
here->eofmark, here->striptabs);
804
n = makename();
805
here->here->nhere.doc = n;
806
}
807
}
808
809
static int
810
peektoken(void)
811
{
812
int t;
813
814
t = readtoken();
815
tokpushback++;
816
return (t);
817
}
818
819
static int
820
readtoken(void)
821
{
822
int t;
823
struct alias *ap;
824
#ifdef DEBUG
825
int alreadyseen = tokpushback;
826
#endif
827
828
top:
829
t = xxreadtoken();
830
831
/*
832
* eat newlines
833
*/
834
if (checkkwd & CHKNL) {
835
while (t == TNL) {
836
parseheredoc();
837
t = xxreadtoken();
838
}
839
}
840
841
/*
842
* check for keywords and aliases
843
*/
844
if (t == TWORD && !quoteflag)
845
{
846
const char * const *pp;
847
848
if (checkkwd & CHKKWD)
849
for (pp = parsekwd; *pp; pp++) {
850
if (**pp == *wordtext && equal(*pp, wordtext))
851
{
852
lasttoken = t = pp - parsekwd + KWDOFFSET;
853
TRACE(("keyword %s recognized\n", tokname[t]));
854
goto out;
855
}
856
}
857
if (checkkwd & CHKALIAS &&
858
(ap = lookupalias(wordtext, 1)) != NULL) {
859
pushstring(ap->val, strlen(ap->val), ap);
860
goto top;
861
}
862
}
863
out:
864
if (t != TNOT)
865
checkkwd = 0;
866
867
#ifdef DEBUG
868
if (!alreadyseen)
869
TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
870
else
871
TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
872
#endif
873
return (t);
874
}
875
876
877
/*
878
* Read the next input token.
879
* If the token is a word, we set backquotelist to the list of cmds in
880
* backquotes. We set quoteflag to true if any part of the word was
881
* quoted.
882
* If the token is TREDIR, then we set redirnode to a structure containing
883
* the redirection.
884
* In all cases, the variable startlinno is set to the number of the line
885
* on which the token starts.
886
*
887
* [Change comment: here documents and internal procedures]
888
* [Readtoken shouldn't have any arguments. Perhaps we should make the
889
* word parsing code into a separate routine. In this case, readtoken
890
* doesn't need to have any internal procedures, but parseword does.
891
* We could also make parseoperator in essence the main routine, and
892
* have parseword (readtoken1?) handle both words and redirection.]
893
*/
894
895
#define RETURN(token) return lasttoken = token
896
897
static int
898
xxreadtoken(void)
899
{
900
int c;
901
902
if (tokpushback) {
903
tokpushback = 0;
904
return lasttoken;
905
}
906
if (needprompt) {
907
setprompt(2);
908
needprompt = 0;
909
}
910
startlinno = plinno;
911
for (;;) { /* until token or start of word found */
912
c = pgetc_macro();
913
switch (c) {
914
case ' ': case '\t':
915
continue;
916
case '#':
917
while ((c = pgetc()) != '\n' && c != PEOF);
918
pungetc();
919
continue;
920
case '\\':
921
if (pgetc() == '\n') {
922
startlinno = ++plinno;
923
if (doprompt)
924
setprompt(2);
925
else
926
setprompt(0);
927
continue;
928
}
929
pungetc();
930
/* FALLTHROUGH */
931
default:
932
return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
933
case '\n':
934
plinno++;
935
needprompt = doprompt;
936
RETURN(TNL);
937
case PEOF:
938
RETURN(TEOF);
939
case '&':
940
if (pgetc_linecont() == '&')
941
RETURN(TAND);
942
pungetc();
943
RETURN(TBACKGND);
944
case '|':
945
if (pgetc_linecont() == '|')
946
RETURN(TOR);
947
pungetc();
948
RETURN(TPIPE);
949
case ';':
950
c = pgetc_linecont();
951
if (c == ';')
952
RETURN(TENDCASE);
953
else if (c == '&')
954
RETURN(TFALLTHRU);
955
pungetc();
956
RETURN(TSEMI);
957
case '(':
958
RETURN(TLP);
959
case ')':
960
RETURN(TRP);
961
}
962
}
963
#undef RETURN
964
}
965
966
967
#define MAXNEST_static 8
968
struct tokenstate
969
{
970
const char *syntax; /* *SYNTAX */
971
int parenlevel; /* levels of parentheses in arithmetic */
972
enum tokenstate_category
973
{
974
TSTATE_TOP,
975
TSTATE_VAR_OLD, /* ${var+-=?}, inherits dquotes */
976
TSTATE_VAR_NEW, /* other ${var...}, own dquote state */
977
TSTATE_ARITH
978
} category;
979
};
980
981
982
/*
983
* Check to see whether we are at the end of the here document. When this
984
* is called, c is set to the first character of the next input line. If
985
* we are at the end of the here document, this routine sets the c to PEOF.
986
* The new value of c is returned.
987
*/
988
989
static int
990
checkend(int c, const char *eofmark, int striptabs)
991
{
992
if (striptabs) {
993
while (c == '\t')
994
c = pgetc();
995
}
996
if (c == *eofmark) {
997
int c2;
998
const char *q;
999
1000
for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++)
1001
;
1002
if ((c2 == PEOF || c2 == '\n') && *q == '\0') {
1003
c = PEOF;
1004
if (c2 == '\n') {
1005
plinno++;
1006
needprompt = doprompt;
1007
}
1008
} else {
1009
pungetc();
1010
pushstring(eofmark + 1, q - (eofmark + 1), NULL);
1011
}
1012
} else if (c == '\n' && *eofmark == '\0') {
1013
c = PEOF;
1014
plinno++;
1015
needprompt = doprompt;
1016
}
1017
return (c);
1018
}
1019
1020
1021
/*
1022
* Parse a redirection operator. The variable "out" points to a string
1023
* specifying the fd to be redirected. The variable "c" contains the
1024
* first character of the redirection operator.
1025
*/
1026
1027
static void
1028
parseredir(char *out, int c)
1029
{
1030
char fd = *out;
1031
union node *np;
1032
1033
np = (union node *)stalloc(sizeof (struct nfile));
1034
if (c == '>') {
1035
np->nfile.fd = 1;
1036
c = pgetc_linecont();
1037
if (c == '>')
1038
np->type = NAPPEND;
1039
else if (c == '&')
1040
np->type = NTOFD;
1041
else if (c == '|')
1042
np->type = NCLOBBER;
1043
else {
1044
np->type = NTO;
1045
pungetc();
1046
}
1047
} else { /* c == '<' */
1048
np->nfile.fd = 0;
1049
c = pgetc_linecont();
1050
if (c == '<') {
1051
if (sizeof (struct nfile) != sizeof (struct nhere)) {
1052
np = (union node *)stalloc(sizeof (struct nhere));
1053
np->nfile.fd = 0;
1054
}
1055
np->type = NHERE;
1056
heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1057
heredoc->here = np;
1058
if ((c = pgetc_linecont()) == '-') {
1059
heredoc->striptabs = 1;
1060
} else {
1061
heredoc->striptabs = 0;
1062
pungetc();
1063
}
1064
} else if (c == '&')
1065
np->type = NFROMFD;
1066
else if (c == '>')
1067
np->type = NFROMTO;
1068
else {
1069
np->type = NFROM;
1070
pungetc();
1071
}
1072
}
1073
if (fd != '\0')
1074
np->nfile.fd = digit_val(fd);
1075
redirnode = np;
1076
}
1077
1078
/*
1079
* Called to parse command substitutions.
1080
*/
1081
1082
static char *
1083
parsebackq(char *out, struct nodelist **pbqlist,
1084
int oldstyle, int dblquote, int quoted)
1085
{
1086
struct nodelist **nlpp;
1087
union node *n;
1088
char *volatile str;
1089
struct jmploc jmploc;
1090
struct jmploc *const savehandler = handler;
1091
size_t savelen;
1092
int saveprompt;
1093
const int bq_startlinno = plinno;
1094
char *volatile ostr = NULL;
1095
struct parsefile *const savetopfile = getcurrentfile();
1096
struct heredoc *const saveheredoclist = heredoclist;
1097
struct heredoc *here;
1098
1099
str = NULL;
1100
if (setjmp(jmploc.loc)) {
1101
popfilesupto(savetopfile);
1102
if (str)
1103
ckfree(str);
1104
if (ostr)
1105
ckfree(ostr);
1106
heredoclist = saveheredoclist;
1107
handler = savehandler;
1108
if (exception == EXERROR) {
1109
startlinno = bq_startlinno;
1110
synerror("Error in command substitution");
1111
}
1112
longjmp(handler->loc, 1);
1113
}
1114
INTOFF;
1115
savelen = out - stackblock();
1116
if (savelen > 0) {
1117
str = ckmalloc(savelen);
1118
memcpy(str, stackblock(), savelen);
1119
}
1120
handler = &jmploc;
1121
heredoclist = NULL;
1122
INTON;
1123
if (oldstyle) {
1124
/* We must read until the closing backquote, giving special
1125
treatment to some slashes, and then push the string and
1126
reread it as input, interpreting it normally. */
1127
char *oout;
1128
int c;
1129
int olen;
1130
1131
1132
STARTSTACKSTR(oout);
1133
for (;;) {
1134
if (needprompt) {
1135
setprompt(2);
1136
needprompt = 0;
1137
}
1138
CHECKSTRSPACE(2, oout);
1139
c = pgetc_linecont();
1140
if (c == '`')
1141
break;
1142
switch (c) {
1143
case '\\':
1144
c = pgetc();
1145
if (c != '\\' && c != '`' && c != '$'
1146
&& (!dblquote || c != '"'))
1147
USTPUTC('\\', oout);
1148
break;
1149
1150
case '\n':
1151
plinno++;
1152
needprompt = doprompt;
1153
break;
1154
1155
case PEOF:
1156
startlinno = plinno;
1157
synerror("EOF in backquote substitution");
1158
break;
1159
1160
default:
1161
break;
1162
}
1163
USTPUTC(c, oout);
1164
}
1165
USTPUTC('\0', oout);
1166
olen = oout - stackblock();
1167
INTOFF;
1168
ostr = ckmalloc(olen);
1169
memcpy(ostr, stackblock(), olen);
1170
setinputstring(ostr, 1);
1171
INTON;
1172
}
1173
nlpp = pbqlist;
1174
while (*nlpp)
1175
nlpp = &(*nlpp)->next;
1176
*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1177
(*nlpp)->next = NULL;
1178
1179
if (oldstyle) {
1180
saveprompt = doprompt;
1181
doprompt = 0;
1182
}
1183
1184
n = list(0);
1185
1186
if (oldstyle) {
1187
if (peektoken() != TEOF)
1188
synexpect(-1);
1189
doprompt = saveprompt;
1190
} else
1191
consumetoken(TRP);
1192
1193
(*nlpp)->n = n;
1194
if (oldstyle) {
1195
/*
1196
* Start reading from old file again, ignoring any pushed back
1197
* tokens left from the backquote parsing
1198
*/
1199
popfile();
1200
tokpushback = 0;
1201
}
1202
STARTSTACKSTR(out);
1203
CHECKSTRSPACE(savelen + 1, out);
1204
INTOFF;
1205
if (str) {
1206
memcpy(out, str, savelen);
1207
STADJUST(savelen, out);
1208
ckfree(str);
1209
str = NULL;
1210
}
1211
if (ostr) {
1212
ckfree(ostr);
1213
ostr = NULL;
1214
}
1215
here = saveheredoclist;
1216
if (here != NULL) {
1217
while (here->next != NULL)
1218
here = here->next;
1219
here->next = heredoclist;
1220
heredoclist = saveheredoclist;
1221
}
1222
handler = savehandler;
1223
INTON;
1224
if (quoted)
1225
USTPUTC(CTLBACKQ | CTLQUOTE, out);
1226
else
1227
USTPUTC(CTLBACKQ, out);
1228
return out;
1229
}
1230
1231
1232
/*
1233
* Called to parse a backslash escape sequence inside $'...'.
1234
* The backslash has already been read.
1235
*/
1236
static char *
1237
readcstyleesc(char *out)
1238
{
1239
int c, vc, i, n;
1240
unsigned int v;
1241
1242
c = pgetc();
1243
switch (c) {
1244
case '\0':
1245
synerror("Unterminated quoted string");
1246
case '\n':
1247
plinno++;
1248
if (doprompt)
1249
setprompt(2);
1250
else
1251
setprompt(0);
1252
return out;
1253
case '\\':
1254
case '\'':
1255
case '"':
1256
v = c;
1257
break;
1258
case 'a': v = '\a'; break;
1259
case 'b': v = '\b'; break;
1260
case 'e': v = '\033'; break;
1261
case 'f': v = '\f'; break;
1262
case 'n': v = '\n'; break;
1263
case 'r': v = '\r'; break;
1264
case 't': v = '\t'; break;
1265
case 'v': v = '\v'; break;
1266
case 'x':
1267
v = 0;
1268
for (;;) {
1269
c = pgetc();
1270
if (c >= '0' && c <= '9')
1271
v = (v << 4) + c - '0';
1272
else if (c >= 'A' && c <= 'F')
1273
v = (v << 4) + c - 'A' + 10;
1274
else if (c >= 'a' && c <= 'f')
1275
v = (v << 4) + c - 'a' + 10;
1276
else
1277
break;
1278
}
1279
pungetc();
1280
break;
1281
case '0': case '1': case '2': case '3':
1282
case '4': case '5': case '6': case '7':
1283
v = c - '0';
1284
c = pgetc();
1285
if (c >= '0' && c <= '7') {
1286
v <<= 3;
1287
v += c - '0';
1288
c = pgetc();
1289
if (c >= '0' && c <= '7') {
1290
v <<= 3;
1291
v += c - '0';
1292
} else
1293
pungetc();
1294
} else
1295
pungetc();
1296
break;
1297
case 'c':
1298
c = pgetc();
1299
if (c < 0x3f || c > 0x7a || c == 0x60)
1300
synerror("Bad escape sequence");
1301
if (c == '\\' && pgetc() != '\\')
1302
synerror("Bad escape sequence");
1303
if (c == '?')
1304
v = 127;
1305
else
1306
v = c & 0x1f;
1307
break;
1308
case 'u':
1309
case 'U':
1310
n = c == 'U' ? 8 : 4;
1311
v = 0;
1312
for (i = 0; i < n; i++) {
1313
c = pgetc();
1314
if (c >= '0' && c <= '9')
1315
v = (v << 4) + c - '0';
1316
else if (c >= 'A' && c <= 'F')
1317
v = (v << 4) + c - 'A' + 10;
1318
else if (c >= 'a' && c <= 'f')
1319
v = (v << 4) + c - 'a' + 10;
1320
else
1321
synerror("Bad escape sequence");
1322
}
1323
if (v == 0 || (v >= 0xd800 && v <= 0xdfff))
1324
synerror("Bad escape sequence");
1325
/* We really need iconv here. */
1326
if (initial_localeisutf8 && v > 127) {
1327
CHECKSTRSPACE(4, out);
1328
/*
1329
* We cannot use wctomb() as the locale may have
1330
* changed.
1331
*/
1332
if (v <= 0x7ff) {
1333
USTPUTC(0xc0 | v >> 6, out);
1334
USTPUTC(0x80 | (v & 0x3f), out);
1335
return out;
1336
} else if (v <= 0xffff) {
1337
USTPUTC(0xe0 | v >> 12, out);
1338
USTPUTC(0x80 | ((v >> 6) & 0x3f), out);
1339
USTPUTC(0x80 | (v & 0x3f), out);
1340
return out;
1341
} else if (v <= 0x10ffff) {
1342
USTPUTC(0xf0 | v >> 18, out);
1343
USTPUTC(0x80 | ((v >> 12) & 0x3f), out);
1344
USTPUTC(0x80 | ((v >> 6) & 0x3f), out);
1345
USTPUTC(0x80 | (v & 0x3f), out);
1346
return out;
1347
}
1348
}
1349
if (v > 127)
1350
v = '?';
1351
break;
1352
default:
1353
synerror("Bad escape sequence");
1354
}
1355
vc = (char)v;
1356
/*
1357
* We can't handle NUL bytes.
1358
* POSIX says we should skip till the closing quote.
1359
*/
1360
if (vc == '\0') {
1361
while ((c = pgetc()) != '\'') {
1362
if (c == '\\')
1363
c = pgetc();
1364
if (c == PEOF)
1365
synerror("Unterminated quoted string");
1366
if (c == '\n') {
1367
plinno++;
1368
if (doprompt)
1369
setprompt(2);
1370
else
1371
setprompt(0);
1372
}
1373
}
1374
pungetc();
1375
return out;
1376
}
1377
if (SQSYNTAX[vc] == CCTL)
1378
USTPUTC(CTLESC, out);
1379
USTPUTC(vc, out);
1380
return out;
1381
}
1382
1383
1384
/*
1385
* If eofmark is NULL, read a word or a redirection symbol. If eofmark
1386
* is not NULL, read a here document. In the latter case, eofmark is the
1387
* word which marks the end of the document and striptabs is true if
1388
* leading tabs should be stripped from the document. The argument firstc
1389
* is the first character of the input token or document.
1390
*
1391
* Because C does not have internal subroutines, I have simulated them
1392
* using goto's to implement the subroutine linkage. The following macros
1393
* will run code that appears at the end of readtoken1.
1394
*/
1395
1396
#define PARSESUB() {goto parsesub; parsesub_return:;}
1397
#define PARSEARITH() {goto parsearith; parsearith_return:;}
1398
1399
static int
1400
readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
1401
int striptabs)
1402
{
1403
int c = firstc;
1404
char *out;
1405
int len;
1406
struct nodelist *bqlist;
1407
int quotef;
1408
int newvarnest;
1409
int level;
1410
int synentry;
1411
struct tokenstate state_static[MAXNEST_static];
1412
int maxnest = MAXNEST_static;
1413
struct tokenstate *state = state_static;
1414
int sqiscstyle = 0;
1415
1416
startlinno = plinno;
1417
quotef = 0;
1418
bqlist = NULL;
1419
newvarnest = 0;
1420
level = 0;
1421
state[level].syntax = initialsyntax;
1422
state[level].parenlevel = 0;
1423
state[level].category = TSTATE_TOP;
1424
1425
STARTSTACKSTR(out);
1426
loop: { /* for each line, until end of word */
1427
if (eofmark && eofmark != NOEOFMARK)
1428
/* set c to PEOF if at end of here document */
1429
c = checkend(c, eofmark, striptabs);
1430
for (;;) { /* until end of line or end of word */
1431
CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
1432
1433
synentry = state[level].syntax[c];
1434
1435
switch(synentry) {
1436
case CNL: /* '\n' */
1437
if (level == 0)
1438
goto endword; /* exit outer loop */
1439
/* FALLTHROUGH */
1440
case CQNL:
1441
USTPUTC(c, out);
1442
plinno++;
1443
if (doprompt)
1444
setprompt(2);
1445
else
1446
setprompt(0);
1447
c = pgetc();
1448
goto loop; /* continue outer loop */
1449
case CSBACK:
1450
if (sqiscstyle) {
1451
out = readcstyleesc(out);
1452
break;
1453
}
1454
/* FALLTHROUGH */
1455
case CWORD:
1456
USTPUTC(c, out);
1457
break;
1458
case CCTL:
1459
if (eofmark == NULL || initialsyntax != SQSYNTAX)
1460
USTPUTC(CTLESC, out);
1461
USTPUTC(c, out);
1462
break;
1463
case CBACK: /* backslash */
1464
c = pgetc();
1465
if (c == PEOF) {
1466
USTPUTC('\\', out);
1467
pungetc();
1468
} else if (c == '\n') {
1469
plinno++;
1470
if (doprompt)
1471
setprompt(2);
1472
else
1473
setprompt(0);
1474
} else {
1475
if (state[level].syntax == DQSYNTAX &&
1476
c != '\\' && c != '`' && c != '$' &&
1477
(c != '"' || (eofmark != NULL &&
1478
newvarnest == 0)) &&
1479
(c != '}' || state[level].category != TSTATE_VAR_OLD))
1480
USTPUTC('\\', out);
1481
if ((eofmark == NULL ||
1482
newvarnest > 0) &&
1483
state[level].syntax == BASESYNTAX)
1484
USTPUTC(CTLQUOTEMARK, out);
1485
if (SQSYNTAX[c] == CCTL)
1486
USTPUTC(CTLESC, out);
1487
USTPUTC(c, out);
1488
if ((eofmark == NULL ||
1489
newvarnest > 0) &&
1490
state[level].syntax == BASESYNTAX &&
1491
state[level].category == TSTATE_VAR_OLD)
1492
USTPUTC(CTLQUOTEEND, out);
1493
quotef++;
1494
}
1495
break;
1496
case CSQUOTE:
1497
USTPUTC(CTLQUOTEMARK, out);
1498
state[level].syntax = SQSYNTAX;
1499
sqiscstyle = 0;
1500
break;
1501
case CDQUOTE:
1502
USTPUTC(CTLQUOTEMARK, out);
1503
state[level].syntax = DQSYNTAX;
1504
break;
1505
case CENDQUOTE:
1506
if (eofmark != NULL && newvarnest == 0)
1507
USTPUTC(c, out);
1508
else {
1509
if (state[level].category == TSTATE_VAR_OLD)
1510
USTPUTC(CTLQUOTEEND, out);
1511
state[level].syntax = BASESYNTAX;
1512
quotef++;
1513
}
1514
break;
1515
case CVAR: /* '$' */
1516
PARSESUB(); /* parse substitution */
1517
break;
1518
case CENDVAR: /* '}' */
1519
if (level > 0 &&
1520
((state[level].category == TSTATE_VAR_OLD &&
1521
state[level].syntax ==
1522
state[level - 1].syntax) ||
1523
(state[level].category == TSTATE_VAR_NEW &&
1524
state[level].syntax == BASESYNTAX))) {
1525
if (state[level].category == TSTATE_VAR_NEW)
1526
newvarnest--;
1527
level--;
1528
USTPUTC(CTLENDVAR, out);
1529
} else {
1530
USTPUTC(c, out);
1531
}
1532
break;
1533
case CLP: /* '(' in arithmetic */
1534
state[level].parenlevel++;
1535
USTPUTC(c, out);
1536
break;
1537
case CRP: /* ')' in arithmetic */
1538
if (state[level].parenlevel > 0) {
1539
USTPUTC(c, out);
1540
--state[level].parenlevel;
1541
} else {
1542
if (pgetc_linecont() == ')') {
1543
if (level > 0 &&
1544
state[level].category == TSTATE_ARITH) {
1545
level--;
1546
USTPUTC(CTLENDARI, out);
1547
} else
1548
USTPUTC(')', out);
1549
} else {
1550
/*
1551
* unbalanced parens
1552
* (don't 2nd guess - no error)
1553
*/
1554
pungetc();
1555
USTPUTC(')', out);
1556
}
1557
}
1558
break;
1559
case CBQUOTE: /* '`' */
1560
out = parsebackq(out, &bqlist, 1,
1561
state[level].syntax == DQSYNTAX &&
1562
(eofmark == NULL || newvarnest > 0),
1563
state[level].syntax == DQSYNTAX || state[level].syntax == ARISYNTAX);
1564
break;
1565
case CEOF:
1566
goto endword; /* exit outer loop */
1567
case CIGN:
1568
break;
1569
default:
1570
if (level == 0)
1571
goto endword; /* exit outer loop */
1572
USTPUTC(c, out);
1573
}
1574
c = pgetc_macro();
1575
}
1576
}
1577
endword:
1578
if (state[level].syntax == ARISYNTAX)
1579
synerror("Missing '))'");
1580
if (state[level].syntax != BASESYNTAX && eofmark == NULL)
1581
synerror("Unterminated quoted string");
1582
if (state[level].category == TSTATE_VAR_OLD ||
1583
state[level].category == TSTATE_VAR_NEW) {
1584
startlinno = plinno;
1585
synerror("Missing '}'");
1586
}
1587
if (state != state_static)
1588
parser_temp_free_upto(state);
1589
USTPUTC('\0', out);
1590
len = out - stackblock();
1591
out = stackblock();
1592
if (eofmark == NULL) {
1593
if ((c == '>' || c == '<')
1594
&& quotef == 0
1595
&& len <= 2
1596
&& (*out == '\0' || is_digit(*out))) {
1597
parseredir(out, c);
1598
return lasttoken = TREDIR;
1599
} else {
1600
pungetc();
1601
}
1602
}
1603
quoteflag = quotef;
1604
backquotelist = bqlist;
1605
grabstackblock(len);
1606
wordtext = out;
1607
return lasttoken = TWORD;
1608
/* end of readtoken routine */
1609
1610
1611
/*
1612
* Parse a substitution. At this point, we have read the dollar sign
1613
* and nothing else.
1614
*/
1615
1616
parsesub: {
1617
int subtype;
1618
int typeloc;
1619
int flags;
1620
char *p;
1621
static const char types[] = "}-+?=";
1622
int linno;
1623
int length;
1624
int c1;
1625
1626
c = pgetc_linecont();
1627
if (c == '(') { /* $(command) or $((arith)) */
1628
if (pgetc_linecont() == '(') {
1629
PARSEARITH();
1630
} else {
1631
pungetc();
1632
out = parsebackq(out, &bqlist, 0,
1633
state[level].syntax == DQSYNTAX &&
1634
(eofmark == NULL || newvarnest > 0),
1635
state[level].syntax == DQSYNTAX ||
1636
state[level].syntax == ARISYNTAX);
1637
}
1638
} else if (c == '{' || is_name(c) || is_special(c)) {
1639
USTPUTC(CTLVAR, out);
1640
typeloc = out - stackblock();
1641
USTPUTC(VSNORMAL, out);
1642
subtype = VSNORMAL;
1643
flags = 0;
1644
if (c == '{') {
1645
c = pgetc_linecont();
1646
subtype = 0;
1647
}
1648
varname:
1649
if (!is_eof(c) && is_name(c)) {
1650
length = 0;
1651
do {
1652
STPUTC(c, out);
1653
c = pgetc_linecont();
1654
length++;
1655
} while (!is_eof(c) && is_in_name(c));
1656
if (length == 6 &&
1657
strncmp(out - length, "LINENO", length) == 0) {
1658
/* Replace the variable name with the
1659
* current line number. */
1660
STADJUST(-6, out);
1661
CHECKSTRSPACE(11, out);
1662
linno = plinno;
1663
if (funclinno != 0)
1664
linno -= funclinno - 1;
1665
length = snprintf(out, 11, "%d", linno);
1666
if (length > 10)
1667
length = 10;
1668
out += length;
1669
flags |= VSLINENO;
1670
}
1671
} else if (is_digit(c)) {
1672
if (subtype != VSNORMAL) {
1673
do {
1674
STPUTC(c, out);
1675
c = pgetc_linecont();
1676
} while (is_digit(c));
1677
} else {
1678
USTPUTC(c, out);
1679
c = pgetc_linecont();
1680
}
1681
} else if (is_special(c)) {
1682
c1 = c;
1683
c = pgetc_linecont();
1684
if (subtype == 0 && c1 == '#') {
1685
subtype = VSLENGTH;
1686
if (strchr(types, c) == NULL && c != ':' &&
1687
c != '#' && c != '%')
1688
goto varname;
1689
c1 = c;
1690
c = pgetc_linecont();
1691
if (c1 != '}' && c == '}') {
1692
pungetc();
1693
c = c1;
1694
goto varname;
1695
}
1696
pungetc();
1697
c = c1;
1698
c1 = '#';
1699
subtype = 0;
1700
}
1701
USTPUTC(c1, out);
1702
} else {
1703
subtype = VSERROR;
1704
if (c == '}')
1705
pungetc();
1706
else if (c == '\n' || c == PEOF)
1707
synerror("Unexpected end of line in substitution");
1708
else if (BASESYNTAX[c] != CCTL)
1709
USTPUTC(c, out);
1710
}
1711
if (subtype == 0) {
1712
switch (c) {
1713
case ':':
1714
flags |= VSNUL;
1715
c = pgetc_linecont();
1716
/*FALLTHROUGH*/
1717
default:
1718
p = strchr(types, c);
1719
if (p == NULL) {
1720
if (c == '\n' || c == PEOF)
1721
synerror("Unexpected end of line in substitution");
1722
if (flags == VSNUL)
1723
STPUTC(':', out);
1724
if (BASESYNTAX[c] != CCTL)
1725
STPUTC(c, out);
1726
subtype = VSERROR;
1727
} else
1728
subtype = p - types + VSNORMAL;
1729
break;
1730
case '%':
1731
case '#':
1732
{
1733
int cc = c;
1734
subtype = c == '#' ? VSTRIMLEFT :
1735
VSTRIMRIGHT;
1736
c = pgetc_linecont();
1737
if (c == cc)
1738
subtype++;
1739
else
1740
pungetc();
1741
break;
1742
}
1743
}
1744
} else if (subtype != VSERROR) {
1745
if (subtype == VSLENGTH && c != '}')
1746
subtype = VSERROR;
1747
pungetc();
1748
}
1749
STPUTC('=', out);
1750
if (state[level].syntax == DQSYNTAX ||
1751
state[level].syntax == ARISYNTAX)
1752
flags |= VSQUOTE;
1753
*(stackblock() + typeloc) = subtype | flags;
1754
if (subtype != VSNORMAL) {
1755
if (level + 1 >= maxnest) {
1756
maxnest *= 2;
1757
if (state == state_static) {
1758
state = parser_temp_alloc(
1759
maxnest * sizeof(*state));
1760
memcpy(state, state_static,
1761
MAXNEST_static * sizeof(*state));
1762
} else
1763
state = parser_temp_realloc(state,
1764
maxnest * sizeof(*state));
1765
}
1766
level++;
1767
state[level].parenlevel = 0;
1768
if (subtype == VSMINUS || subtype == VSPLUS ||
1769
subtype == VSQUESTION || subtype == VSASSIGN) {
1770
/*
1771
* For operators that were in the Bourne shell,
1772
* inherit the double-quote state.
1773
*/
1774
state[level].syntax = state[level - 1].syntax;
1775
state[level].category = TSTATE_VAR_OLD;
1776
} else {
1777
/*
1778
* The other operators take a pattern,
1779
* so go to BASESYNTAX.
1780
* Also, ' and " are now special, even
1781
* in here documents.
1782
*/
1783
state[level].syntax = BASESYNTAX;
1784
state[level].category = TSTATE_VAR_NEW;
1785
newvarnest++;
1786
}
1787
}
1788
} else if (c == '\'' && state[level].syntax == BASESYNTAX) {
1789
/* $'cstylequotes' */
1790
USTPUTC(CTLQUOTEMARK, out);
1791
state[level].syntax = SQSYNTAX;
1792
sqiscstyle = 1;
1793
} else {
1794
USTPUTC('$', out);
1795
pungetc();
1796
}
1797
goto parsesub_return;
1798
}
1799
1800
1801
/*
1802
* Parse an arithmetic expansion (indicate start of one and set state)
1803
*/
1804
parsearith: {
1805
1806
if (level + 1 >= maxnest) {
1807
maxnest *= 2;
1808
if (state == state_static) {
1809
state = parser_temp_alloc(
1810
maxnest * sizeof(*state));
1811
memcpy(state, state_static,
1812
MAXNEST_static * sizeof(*state));
1813
} else
1814
state = parser_temp_realloc(state,
1815
maxnest * sizeof(*state));
1816
}
1817
level++;
1818
state[level].syntax = ARISYNTAX;
1819
state[level].parenlevel = 0;
1820
state[level].category = TSTATE_ARITH;
1821
USTPUTC(CTLARI, out);
1822
if (state[level - 1].syntax == DQSYNTAX)
1823
USTPUTC('"',out);
1824
else
1825
USTPUTC(' ',out);
1826
goto parsearith_return;
1827
}
1828
1829
} /* end of readtoken */
1830
1831
1832
/*
1833
* Returns true if the text contains nothing to expand (no dollar signs
1834
* or backquotes).
1835
*/
1836
1837
static int
1838
noexpand(char *text)
1839
{
1840
char *p;
1841
char c;
1842
1843
p = text;
1844
while ((c = *p++) != '\0') {
1845
if ( c == CTLQUOTEMARK)
1846
continue;
1847
if (c == CTLESC)
1848
p++;
1849
else if (BASESYNTAX[(int)c] == CCTL)
1850
return 0;
1851
}
1852
return 1;
1853
}
1854
1855
1856
/*
1857
* Return true if the argument is a legal variable name (a letter or
1858
* underscore followed by zero or more letters, underscores, and digits).
1859
*/
1860
1861
int
1862
goodname(const char *name)
1863
{
1864
const char *p;
1865
1866
p = name;
1867
if (! is_name(*p))
1868
return 0;
1869
while (*++p) {
1870
if (! is_in_name(*p))
1871
return 0;
1872
}
1873
return 1;
1874
}
1875
1876
1877
int
1878
isassignment(const char *p)
1879
{
1880
if (!is_name(*p))
1881
return 0;
1882
p++;
1883
for (;;) {
1884
if (*p == '=')
1885
return 1;
1886
else if (!is_in_name(*p))
1887
return 0;
1888
p++;
1889
}
1890
}
1891
1892
1893
static void
1894
consumetoken(int token)
1895
{
1896
if (readtoken() != token)
1897
synexpect(token);
1898
}
1899
1900
1901
/*
1902
* Called when an unexpected token is read during the parse. The argument
1903
* is the token that is expected, or -1 if more than one type of token can
1904
* occur at this point.
1905
*/
1906
1907
static void
1908
synexpect(int token)
1909
{
1910
char msg[64];
1911
1912
if (token >= 0) {
1913
fmtstr(msg, 64, "%s unexpected (expecting %s)",
1914
tokname[lasttoken], tokname[token]);
1915
} else {
1916
fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1917
}
1918
synerror(msg);
1919
}
1920
1921
1922
static void
1923
synerror(const char *msg)
1924
{
1925
if (commandname)
1926
outfmt(out2, "%s: %d: ", commandname, startlinno);
1927
else if (arg0)
1928
outfmt(out2, "%s: ", arg0);
1929
outfmt(out2, "Syntax error: %s\n", msg);
1930
error((char *)NULL);
1931
}
1932
1933
static void
1934
setprompt(int which)
1935
{
1936
whichprompt = which;
1937
if (which == 0)
1938
return;
1939
1940
#ifndef NO_HISTORY
1941
if (!el)
1942
#endif
1943
{
1944
out2str(getprompt(NULL));
1945
flushout(out2);
1946
}
1947
}
1948
1949
static int
1950
pgetc_linecont(void)
1951
{
1952
int c;
1953
1954
while ((c = pgetc_macro()) == '\\') {
1955
c = pgetc();
1956
if (c == '\n') {
1957
plinno++;
1958
if (doprompt)
1959
setprompt(2);
1960
else
1961
setprompt(0);
1962
} else {
1963
pungetc();
1964
/* Allow the backslash to be pushed back. */
1965
pushstring("\\", 1, NULL);
1966
return (pgetc());
1967
}
1968
}
1969
return (c);
1970
}
1971
1972
1973
static struct passwd *
1974
getpwlogin(void)
1975
{
1976
const char *login;
1977
1978
login = getlogin();
1979
if (login == NULL)
1980
return (NULL);
1981
1982
return (getpwnam(login));
1983
}
1984
1985
1986
static void
1987
getusername(char *name, size_t namelen)
1988
{
1989
static char cached_name[MAXLOGNAME];
1990
struct passwd *pw;
1991
uid_t euid;
1992
1993
if (cached_name[0] == '\0') {
1994
euid = geteuid();
1995
1996
/*
1997
* Handle the case when there is more than one
1998
* login with the same UID, or when the login
1999
* returned by getlogin(2) does no longer match
2000
* the current UID.
2001
*/
2002
pw = getpwlogin();
2003
if (pw == NULL || pw->pw_uid != euid)
2004
pw = getpwuid(euid);
2005
2006
if (pw != NULL) {
2007
strlcpy(cached_name, pw->pw_name,
2008
sizeof(cached_name));
2009
} else {
2010
snprintf(cached_name, sizeof(cached_name),
2011
"%u", euid);
2012
}
2013
}
2014
2015
strlcpy(name, cached_name, namelen);
2016
}
2017
2018
2019
/*
2020
* called by editline -- any expansions to the prompt
2021
* should be added here.
2022
*/
2023
char *
2024
getprompt(void *unused __unused)
2025
{
2026
static char ps[PROMPTLEN];
2027
const char *fmt;
2028
const char *home;
2029
const char *pwd;
2030
size_t homelen;
2031
int i, trim;
2032
static char internal_error[] = "??";
2033
2034
/*
2035
* Select prompt format.
2036
*/
2037
switch (whichprompt) {
2038
case 0:
2039
fmt = "";
2040
break;
2041
case 1:
2042
fmt = ps1val();
2043
break;
2044
case 2:
2045
fmt = ps2val();
2046
break;
2047
default:
2048
return internal_error;
2049
}
2050
2051
/*
2052
* Format prompt string.
2053
*/
2054
for (i = 0; (i < PROMPTLEN - 1) && (*fmt != '\0'); i++, fmt++) {
2055
if (*fmt == '$') {
2056
const char *varname_start, *varname_end, *value;
2057
char varname[256];
2058
int namelen, braced = 0;
2059
2060
fmt++; /* Skip the '$' */
2061
2062
/* Check for ${VAR} syntax */
2063
if (*fmt == '{') {
2064
braced = 1;
2065
fmt++;
2066
}
2067
2068
varname_start = fmt;
2069
2070
/* Extract variable name */
2071
if (is_digit(*fmt)) {
2072
/* Positional parameter: $0, $1, etc. */
2073
fmt++;
2074
varname_end = fmt;
2075
} else if (is_special(*fmt)) {
2076
/* Special parameter: $?, $!, $$, etc. */
2077
fmt++;
2078
varname_end = fmt;
2079
} else if (is_name(*fmt)) {
2080
/* Regular variable name */
2081
do
2082
fmt++;
2083
while (is_in_name(*fmt));
2084
varname_end = fmt;
2085
} else {
2086
/*
2087
* Not a valid variable reference.
2088
* Output literal '$'.
2089
*/
2090
ps[i] = '$';
2091
if (braced && i < PROMPTLEN - 2)
2092
ps[++i] = '{';
2093
fmt = varname_start - 1;
2094
continue;
2095
}
2096
2097
namelen = varname_end - varname_start;
2098
if (namelen == 0 || namelen >= (int)sizeof(varname)) {
2099
/* Invalid or too long, output literal */
2100
ps[i] = '$';
2101
fmt = varname_start - 1;
2102
continue;
2103
}
2104
2105
/* Copy variable name */
2106
memcpy(varname, varname_start, namelen);
2107
varname[namelen] = '\0';
2108
2109
/* Handle closing brace for ${VAR} */
2110
if (braced) {
2111
if (*fmt == '}') {
2112
fmt++;
2113
} else {
2114
/* Missing closing brace, treat as literal */
2115
ps[i] = '$';
2116
if (i < PROMPTLEN - 2)
2117
ps[++i] = '{';
2118
fmt = varname_start - 1;
2119
continue;
2120
}
2121
}
2122
2123
/* Look up the variable */
2124
if (namelen == 1 && is_digit(*varname)) {
2125
/* Positional parameters - check digits FIRST */
2126
int num = *varname - '0';
2127
if (num == 0)
2128
value = arg0 ? arg0 : "";
2129
else if (num > 0 && num <= shellparam.nparam)
2130
value = shellparam.p[num - 1];
2131
else
2132
value = "";
2133
} else if (namelen == 1 && is_special(*varname)) {
2134
/* Special parameters */
2135
char valbuf[20];
2136
int num;
2137
2138
switch (*varname) {
2139
case '$':
2140
num = rootpid;
2141
break;
2142
case '?':
2143
num = exitstatus;
2144
break;
2145
case '#':
2146
num = shellparam.nparam;
2147
break;
2148
case '!':
2149
num = backgndpidval();
2150
break;
2151
default:
2152
num = 0;
2153
break;
2154
}
2155
snprintf(valbuf, sizeof(valbuf), "%d", num);
2156
value = valbuf;
2157
} else {
2158
/* Regular variables */
2159
value = lookupvar(varname);
2160
if (value == NULL)
2161
value = "";
2162
}
2163
2164
/* Copy value to output, respecting buffer size */
2165
while (*value != '\0' && i < PROMPTLEN - 1) {
2166
ps[i++] = *value++;
2167
}
2168
2169
/*
2170
* Adjust fmt and i for the loop increment.
2171
* fmt will be incremented by the for loop,
2172
* so position it one before where we want.
2173
*/
2174
fmt--;
2175
i--;
2176
continue;
2177
} else if (*fmt != '\\') {
2178
ps[i] = *fmt;
2179
continue;
2180
}
2181
2182
switch (*++fmt) {
2183
2184
/*
2185
* Non-printing sequence begin and end.
2186
*/
2187
case '[':
2188
case ']':
2189
ps[i] = '\001';
2190
break;
2191
2192
/*
2193
* Literal \ and some ASCII characters:
2194
* \a BEL
2195
* \e ESC
2196
* \r CR
2197
*/
2198
case '\\':
2199
case 'a':
2200
case 'e':
2201
case 'r':
2202
if (*fmt == 'a')
2203
ps[i] = '\007';
2204
else if (*fmt == 'e')
2205
ps[i] = '\033';
2206
else if (*fmt == 'r')
2207
ps[i] = '\r';
2208
else
2209
ps[i] = '\\';
2210
break;
2211
2212
/*
2213
* CRLF sequence
2214
*/
2215
case 'n':
2216
if (i < PROMPTLEN - 3) {
2217
ps[i++] = '\r';
2218
ps[i] = '\n';
2219
}
2220
break;
2221
2222
/*
2223
* Print the current time as per provided strftime format.
2224
*/
2225
case 'D': {
2226
char tfmt[128] = "%X"; /* \D{} means %X. */
2227
struct tm *now;
2228
2229
if (fmt[1] != '{') {
2230
/*
2231
* "\D" but not "\D{", so treat the '\'
2232
* literally and rewind fmt to treat 'D'
2233
* literally next iteration.
2234
*/
2235
ps[i] = '\\';
2236
fmt--;
2237
break;
2238
}
2239
fmt += 2; /* Consume "D{". */
2240
if (fmt[0] != '}') {
2241
char *end;
2242
2243
end = memccpy(tfmt, fmt, '}', sizeof(tfmt));
2244
if (end == NULL) {
2245
/*
2246
* Format too long or no '}', so
2247
* ignore "\D{" altogether.
2248
* The loop will do i++, but nothing
2249
* was written to ps, so do i-- here.
2250
* Rewind fmt for similar reason.
2251
*/
2252
i--;
2253
fmt--;
2254
break;
2255
}
2256
*--end = '\0'; /* Ignore the copy of '}'. */
2257
fmt += end - tfmt;
2258
}
2259
now = localtime(&(time_t){time(NULL)});
2260
i += strftime(&ps[i], PROMPTLEN - i - 1, tfmt, now);
2261
i--; /* The loop will do i++. */
2262
break;
2263
}
2264
2265
/*
2266
* Hostname.
2267
*
2268
* \h specifies just the local hostname,
2269
* \H specifies fully-qualified hostname.
2270
*/
2271
case 'h':
2272
case 'H':
2273
ps[i] = '\0';
2274
gethostname(&ps[i], PROMPTLEN - i - 1);
2275
ps[PROMPTLEN - 1] = '\0';
2276
/* Skip to end of hostname. */
2277
trim = (*fmt == 'h') ? '.' : '\0';
2278
while ((ps[i] != '\0') && (ps[i] != trim))
2279
i++;
2280
--i;
2281
break;
2282
2283
/*
2284
* User name.
2285
*/
2286
case 'u':
2287
ps[i] = '\0';
2288
getusername(&ps[i], PROMPTLEN - i);
2289
/* Skip to end of username. */
2290
while (ps[i + 1] != '\0')
2291
i++;
2292
break;
2293
2294
/*
2295
* Working directory.
2296
*
2297
* \W specifies just the final component,
2298
* \w specifies the entire path.
2299
*/
2300
case 'W':
2301
case 'w':
2302
pwd = lookupvar("PWD");
2303
if (pwd == NULL || *pwd == '\0')
2304
pwd = "?";
2305
if (*fmt == 'W' &&
2306
*pwd == '/' && pwd[1] != '\0')
2307
strlcpy(&ps[i], strrchr(pwd, '/') + 1,
2308
PROMPTLEN - i);
2309
else {
2310
home = lookupvar("HOME");
2311
if (home != NULL)
2312
homelen = strlen(home);
2313
if (home != NULL &&
2314
strcmp(home, "/") != 0 &&
2315
strncmp(pwd, home, homelen) == 0 &&
2316
(pwd[homelen] == '/' ||
2317
pwd[homelen] == '\0')) {
2318
strlcpy(&ps[i], "~",
2319
PROMPTLEN - i);
2320
strlcpy(&ps[i + 1],
2321
pwd + homelen,
2322
PROMPTLEN - i - 1);
2323
} else {
2324
strlcpy(&ps[i], pwd, PROMPTLEN - i);
2325
}
2326
}
2327
/* Skip to end of path. */
2328
while (ps[i + 1] != '\0')
2329
i++;
2330
break;
2331
2332
/*
2333
* Superuser status.
2334
*
2335
* '$' for normal users, '#' for root.
2336
*/
2337
case '$':
2338
ps[i] = (geteuid() != 0) ? '$' : '#';
2339
break;
2340
2341
/*
2342
* Emit unrecognized formats verbatim.
2343
*/
2344
default:
2345
ps[i] = '\\';
2346
if (i < PROMPTLEN - 2)
2347
ps[++i] = *fmt;
2348
break;
2349
}
2350
2351
}
2352
ps[i] = '\0';
2353
return (ps);
2354
}
2355
2356
2357
const char *
2358
expandstr(const char *ps)
2359
{
2360
union node n;
2361
struct jmploc jmploc;
2362
struct jmploc *const savehandler = handler;
2363
const int saveprompt = doprompt;
2364
struct parsefile *const savetopfile = getcurrentfile();
2365
struct parser_temp *const saveparser_temp = parser_temp;
2366
const char *result = NULL;
2367
2368
if (!setjmp(jmploc.loc)) {
2369
handler = &jmploc;
2370
parser_temp = NULL;
2371
setinputstring(ps, 1);
2372
doprompt = 0;
2373
readtoken1(pgetc(), DQSYNTAX, NOEOFMARK, 0);
2374
if (backquotelist != NULL)
2375
error("Command substitution not allowed here");
2376
2377
n.narg.type = NARG;
2378
n.narg.next = NULL;
2379
n.narg.text = wordtext;
2380
n.narg.backquote = backquotelist;
2381
2382
expandarg(&n, NULL, 0);
2383
result = stackblock();
2384
INTOFF;
2385
}
2386
handler = savehandler;
2387
doprompt = saveprompt;
2388
popfilesupto(savetopfile);
2389
if (parser_temp != saveparser_temp) {
2390
parser_temp_free_all();
2391
parser_temp = saveparser_temp;
2392
}
2393
if (result != NULL) {
2394
INTON;
2395
} else if (exception == EXINT)
2396
raise(SIGINT);
2397
return result;
2398
}
2399
2400