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