Bug Summary

File:src/bin/ksh/syn.c
Warning:line 517, column 12
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name syn.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/bin/ksh/obj -resource-dir /usr/local/lib/clang/13.0.0 -D EMACS -D VI -I . -I /usr/src/bin/ksh -I /usr/src/bin/ksh/../../lib/libc/gen -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/bin/ksh/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/bin/ksh/syn.c
1/* $OpenBSD: syn.c,v 1.40 2021/07/05 13:41:46 millert Exp $ */
2
3/*
4 * shell parser (C version)
5 */
6
7#include <string.h>
8
9#include "sh.h"
10#include "c_test.h"
11
12struct nesting_state {
13 int start_token; /* token than began nesting (eg, FOR) */
14 int start_line; /* line nesting began on */
15};
16
17static void yyparse(void);
18static struct op *pipeline(int);
19static struct op *andor(void);
20static struct op *c_list(int);
21static struct ioword *synio(int);
22static void musthave(int, int);
23static struct op *nested(int, int, int);
24static struct op *get_command(int);
25static struct op *dogroup(void);
26static struct op *thenpart(void);
27static struct op *elsepart(void);
28static struct op *caselist(void);
29static struct op *casepart(int);
30static struct op *function_body(char *, int);
31static char ** wordlist(void);
32static struct op *block(int, struct op *, struct op *, char **);
33static struct op *newtp(int);
34static void syntaxerr(const char *) __attribute__((__noreturn__));
35static void nesting_push(struct nesting_state *, int);
36static void nesting_pop(struct nesting_state *);
37static int assign_command(char *);
38static int inalias(struct source *);
39static int dbtestp_isa(Test_env *, Test_meta);
40static const char *dbtestp_getopnd(Test_env *, Test_op, int);
41static int dbtestp_eval(Test_env *, Test_op, const char *, const char *,
42 int);
43static void dbtestp_error(Test_env *, int, const char *);
44
45static struct op *outtree; /* yyparse output */
46
47static struct nesting_state nesting; /* \n changed to ; */
48
49static int reject; /* token(cf) gets symbol again */
50static int symbol; /* yylex value */
51
52#define token(cf)((reject) ? (reject = 0, symbol) : (symbol = yylex(cf))) \
53 ((reject) ? (reject = false0, symbol) : (symbol = yylex(cf)))
54#define tpeek(cf)((reject) ? (symbol) : (reject = 1, symbol = yylex(cf))) \
55 ((reject) ? (symbol) : (reject = true1, symbol = yylex(cf)))
56
57static void
58yyparse(void)
59{
60 int c;
61
62 reject = false0;
63
64 outtree = c_list(source->type == SSTRING3);
65 c = tpeek(0)((reject) ? (symbol) : (reject = 1, symbol = yylex(0)));
66 if (c == 0 && !outtree)
67 outtree = newtp(TEOF0);
68 else if (c != '\n' && c != 0)
69 syntaxerr(NULL((void*)0));
70}
71
72static struct op *
73pipeline(int cf)
74{
75 struct op *t, *p, *tl = NULL((void*)0);
76
77 t = get_command(cf);
78 if (t != NULL((void*)0)) {
79 while (token(0)((reject) ? (reject = 0, symbol) : (symbol = yylex(0))) == '|') {
80 if ((p = get_command(CONTIN(1<<(0)))) == NULL((void*)0))
81 syntaxerr(NULL((void*)0));
82 if (tl == NULL((void*)0))
83 t = tl = block(TPIPE3, t, p, NULL((void*)0));
84 else
85 tl = tl->right = block(TPIPE3, tl->right, p, NULL((void*)0));
86 }
87 reject = true1;
88 }
89 return (t);
90}
91
92static struct op *
93andor(void)
94{
95 struct op *t, *p;
96 int c;
97
98 t = pipeline(0);
99 if (t != NULL((void*)0)) {
100 while ((c = token(0)((reject) ? (reject = 0, symbol) : (symbol = yylex(0)))) == LOGAND257 || c == LOGOR258) {
101 if ((p = pipeline(CONTIN(1<<(0)))) == NULL((void*)0))
102 syntaxerr(NULL((void*)0));
103 t = block(c == LOGAND257? TAND6: TOR5, t, p, NULL((void*)0));
104 }
105 reject = true1;
106 }
107 return (t);
108}
109
110static struct op *
111c_list(int multi)
112{
113 struct op *t = NULL((void*)0), *p, *tl = NULL((void*)0);
114 int c;
115 int have_sep;
116
117 while (1) {
118 p = andor();
119 /* Token has always been read/rejected at this point, so
120 * we don't worry about what flags to pass token()
121 */
122 c = token(0)((reject) ? (reject = 0, symbol) : (symbol = yylex(0)));
123 have_sep = 1;
124 if (c == '\n' && (multi || inalias(source))) {
125 if (!p) /* ignore blank lines */
126 continue;
127 } else if (!p)
128 break;
129 else if (c == '&' || c == COPROC280)
130 p = block(c == '&' ? TASYNC18 : TCOPROC22,
131 p, NULL((void*)0), NULL((void*)0));
132 else if (c != ';')
133 have_sep = 0;
134 if (!t)
135 t = p;
136 else if (!tl)
137 t = tl = block(TLIST4, t, p, NULL((void*)0));
138 else
139 tl = tl->right = block(TLIST4, tl->right, p, NULL((void*)0));
140 if (!have_sep)
141 break;
142 }
143 reject = true1;
144 return t;
145}
146
147static struct ioword *
148synio(int cf)
149{
150 struct ioword *iop;
151 int ishere;
152
153 if (tpeek(cf)((reject) ? (symbol) : (reject = 1, symbol = yylex(cf))) != REDIR276)
154 return NULL((void*)0);
155 reject = false0;
156 iop = yylval.iop;
157 ishere = (iop->flag&IOTYPE0xF) == IOHERE0x4;
158 musthave(LWORD256, ishere ? HEREDELIM(1<<(9)) : 0);
159 if (ishere) {
160 iop->delim = yylval.cp;
161 if (*ident != 0) /* unquoted */
162 iop->flag |= IOEVAL(1<<(4));
163 if (herep >= &heres[HERES10])
164 yyerror("too many <<'s\n");
165 *herep++ = iop;
166 } else
167 iop->name = yylval.cp;
168 return iop;
169}
170
171static void
172musthave(int c, int cf)
173{
174 if ((token(cf)((reject) ? (reject = 0, symbol) : (symbol = yylex(cf)))) != c)
175 syntaxerr(NULL((void*)0));
176}
177
178static struct op *
179nested(int type, int smark, int emark)
180{
181 struct op *t;
182 struct nesting_state old_nesting;
183
184 nesting_push(&old_nesting, smark);
185 t = c_list(true1);
186 musthave(emark, KEYWORD(1<<(3))|ALIAS(1<<(2)));
187 nesting_pop(&old_nesting);
188 return (block(type, t, NULL((void*)0), NULL((void*)0)));
189}
190
191static struct op *
192get_command(int cf)
193{
194 struct op *t;
195 int c, iopn = 0, syniocf;
196 struct ioword *iop, **iops;
197 XPtrV args, vars;
198 struct nesting_state old_nesting;
199
200 iops = areallocarray(NULL((void*)0), NUFILE32 + 1,
201 sizeof(struct ioword *), ATEMP&genv->area);
202 XPinit(args, 16)do { void **vp__; vp__ = areallocarray(((void*)0), 16, sizeof
(void *), &genv->area); (args).cur = (args).beg = vp__
; (args).end = vp__ + 16; } while (0)
;
203 XPinit(vars, 16)do { void **vp__; vp__ = areallocarray(((void*)0), 16, sizeof
(void *), &genv->area); (vars).cur = (vars).beg = vp__
; (vars).end = vp__ + 16; } while (0)
;
204
205 syniocf = KEYWORD(1<<(3))|ALIAS(1<<(2));
206 switch (c = token(cf|KEYWORD|ALIAS|VARASN)((reject) ? (reject = 0, symbol) : (symbol = yylex(cf|(1<<
(3))|(1<<(2))|(1<<(5)))))
) {
207 default:
208 reject = true1;
209 afree(iops, ATEMP&genv->area);
210 XPfree(args)afree((args).beg, &genv->area);
211 XPfree(vars)afree((vars).beg, &genv->area);
212 return NULL((void*)0); /* empty line */
213
214 case LWORD256:
215 case REDIR276:
216 reject = true1;
217 syniocf &= ~(KEYWORD(1<<(3))|ALIAS(1<<(2)));
218 t = newtp(TCOM1);
219 t->lineno = source->line;
220 while (1) {
221 cf = (t->u.evalflags ? ARRAYVAR(1<<(6)) : 0) |
222 (XPsize(args)((args).cur - (args).beg) == 0 ? ALIAS(1<<(2))|VARASN(1<<(5)) : CMDWORD(1<<(8)));
223 switch (tpeek(cf)((reject) ? (symbol) : (reject = 1, symbol = yylex(cf)))) {
224 case REDIR276:
225 if (iopn >= NUFILE32)
226 yyerror("too many redirections\n");
227 iops[iopn++] = synio(cf);
228 break;
229
230 case LWORD256:
231 reject = false0;
232 /* the iopn == 0 and XPsize(vars) == 0 are
233 * dubious but at&t ksh acts this way
234 */
235 if (iopn == 0 && XPsize(vars)((vars).cur - (vars).beg) == 0 &&
236 XPsize(args)((args).cur - (args).beg) == 0 &&
237 assign_command(ident))
238 t->u.evalflags = DOVACHECK(1<<(9));
239 if ((XPsize(args)((args).cur - (args).beg) == 0 || Flag(FKEYWORD)(shell_flags[(int) (FKEYWORD)])) &&
240 is_wdvarassign(yylval.cp))
241 XPput(vars, yylval.cp)do { if ((vars).cur >= (vars).end) { int n = ((vars).cur -
(vars).beg); (vars).beg = areallocarray((vars).beg, n, 2 * sizeof
(void *), &genv->area); (vars).cur = (vars).beg + n; (
vars).end = (vars).cur + n; } *(vars).cur++ = (yylval.cp); } while
(0)
;
242 else
243 XPput(args, yylval.cp)do { if ((args).cur >= (args).end) { int n = ((args).cur -
(args).beg); (args).beg = areallocarray((args).beg, n, 2 * sizeof
(void *), &genv->area); (args).cur = (args).beg + n; (
args).end = (args).cur + n; } *(args).cur++ = (yylval.cp); } while
(0)
;
244 break;
245
246 case '(':
247 /* Check for "> foo (echo hi)", which at&t ksh
248 * allows (not POSIX, but not disallowed)
249 */
250 afree(t, ATEMP&genv->area);
251 if (XPsize(args)((args).cur - (args).beg) == 0 && XPsize(vars)((vars).cur - (vars).beg) == 0) {
252 reject = false0;
253 goto Subshell;
254 }
255 /* Must be a function */
256 if (iopn != 0 || XPsize(args)((args).cur - (args).beg) != 1 ||
257 XPsize(vars)((vars).cur - (vars).beg) != 0)
258 syntaxerr(NULL((void*)0));
259 reject = false0;
260 /*(*/
261 musthave(')', 0);
262 t = function_body(XPptrv(args)((args).beg)[0], false0);
263 goto Leave;
264
265 default:
266 goto Leave;
267 }
268 }
269 Leave:
270 break;
271
272 Subshell:
273 case '(':
274 t = nested(TPAREN2, '(', ')');
275 break;
276
277 case '{': /*}*/
278 t = nested(TBRACE17, '{', '}');
279 break;
280
281 case MDPAREN277:
282 {
283 static const char let_cmd[] = {
284 CHAR1, 'l', CHAR1, 'e',
285 CHAR1, 't', EOS0
286 };
287 /* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
288 t = newtp(TCOM1);
289 t->lineno = source->line;
290 reject = false0;
291 XPput(args, wdcopy(let_cmd, ATEMP))do { if ((args).cur >= (args).end) { int n = ((args).cur -
(args).beg); (args).beg = areallocarray((args).beg, n, 2 * sizeof
(void *), &genv->area); (args).cur = (args).beg + n; (
args).end = (args).cur + n; } *(args).cur++ = (wdcopy(let_cmd
, &genv->area)); } while (0)
;
292 musthave(LWORD256,LETEXPR(1<<(4)));
293 XPput(args, yylval.cp)do { if ((args).cur >= (args).end) { int n = ((args).cur -
(args).beg); (args).beg = areallocarray((args).beg, n, 2 * sizeof
(void *), &genv->area); (args).cur = (args).beg + n; (
args).end = (args).cur + n; } *(args).cur++ = (yylval.cp); } while
(0)
;
294 break;
295 }
296
297 case DBRACKET279: /* [[ .. ]] */
298 /* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
299 t = newtp(TDBRACKET8);
300 reject = false0;
301 {
302 Test_env te;
303
304 te.flags = TEF_DBRACKET(1<<(1));
305 te.pos.av = &args;
306 te.isa = dbtestp_isa;
307 te.getopnd = dbtestp_getopnd;
308 te.eval = dbtestp_eval;
309 te.error = dbtestp_error;
310
311 test_parse(&te);
312 }
313 break;
314
315 case FOR267:
316 case SELECT268:
317 t = newtp((c == FOR267) ? TFOR9 : TSELECT10);
318 musthave(LWORD256, ARRAYVAR(1<<(6)));
319 if (!is_wdvarname(yylval.cp, true1))
320 yyerror("%s: bad identifier\n",
321 c == FOR267 ? "for" : "select");
322 t->str = str_save(ident, ATEMP&genv->area);
323 nesting_push(&old_nesting, c);
324 t->vars = wordlist();
325 t->left = dogroup();
326 nesting_pop(&old_nesting);
327 break;
328
329 case WHILE269:
330 case UNTIL270:
331 nesting_push(&old_nesting, c);
332 t = newtp((c == WHILE269) ? TWHILE13 : TUNTIL14);
333 t->left = c_list(true1);
334 if (t->left == NULL((void*)0))
335 syntaxerr(NULL((void*)0));
336 t->right = dogroup();
337 nesting_pop(&old_nesting);
338 break;
339
340 case CASE265:
341 t = newtp(TCASE11);
342 musthave(LWORD256, 0);
343 t->str = yylval.cp;
344 nesting_push(&old_nesting, c);
345 t->left = caselist();
346 nesting_pop(&old_nesting);
347 break;
348
349 case IF260:
350 nesting_push(&old_nesting, c);
351 t = newtp(TIF12);
352 t->left = c_list(true1);
353 t->right = thenpart();
354 musthave(FI264, KEYWORD(1<<(3))|ALIAS(1<<(2)));
355 nesting_pop(&old_nesting);
356 break;
357
358 case BANG278:
359 syniocf &= ~(KEYWORD(1<<(3))|ALIAS(1<<(2)));
360 t = pipeline(0);
361 if (t == NULL((void*)0))
362 syntaxerr(NULL((void*)0));
363 t = block(TBANG7, NULL((void*)0), t, NULL((void*)0));
364 break;
365
366 case TIME275:
367 syniocf &= ~(KEYWORD(1<<(3))|ALIAS(1<<(2)));
368 t = pipeline(0);
369 if (t) {
370 if (t->str) {
371 t->str = str_save(t->str, ATEMP&genv->area);
372 } else {
373 t->str = alloc(2, ATEMP&genv->area);
374 t->str[0] = '\0'; /* TF_* flags */
375 t->str[1] = '\0';
376 }
377 }
378 t = block(TTIME20, t, NULL((void*)0), NULL((void*)0));
379 break;
380
381 case FUNCTION274:
382 musthave(LWORD256, 0);
383 t = function_body(yylval.cp, true1);
384 break;
385 }
386
387 while ((iop = synio(syniocf)) != NULL((void*)0)) {
388 if (iopn >= NUFILE32)
389 yyerror("too many redirections\n");
390 iops[iopn++] = iop;
391 }
392
393 if (iopn == 0) {
394 afree(iops, ATEMP&genv->area);
395 t->ioact = NULL((void*)0);
396 } else {
397 iops[iopn++] = NULL((void*)0);
398 iops = areallocarray(iops, iopn,
399 sizeof(struct ioword *), ATEMP&genv->area);
400 t->ioact = iops;
401 }
402
403 if (t->type == TCOM1 || t->type == TDBRACKET8) {
404 XPput(args, NULL)do { if ((args).cur >= (args).end) { int n = ((args).cur -
(args).beg); (args).beg = areallocarray((args).beg, n, 2 * sizeof
(void *), &genv->area); (args).cur = (args).beg + n; (
args).end = (args).cur + n; } *(args).cur++ = (((void*)0)); }
while (0)
;
405 t->args = (char **) XPclose(args)areallocarray((args).beg, ((args).cur - (args).beg), sizeof(void
*), &genv->area)
;
406 XPput(vars, NULL)do { if ((vars).cur >= (vars).end) { int n = ((vars).cur -
(vars).beg); (vars).beg = areallocarray((vars).beg, n, 2 * sizeof
(void *), &genv->area); (vars).cur = (vars).beg + n; (
vars).end = (vars).cur + n; } *(vars).cur++ = (((void*)0)); }
while (0)
;
407 t->vars = (char **) XPclose(vars)areallocarray((vars).beg, ((vars).cur - (vars).beg), sizeof(void
*), &genv->area)
;
408 } else {
409 XPfree(args)afree((args).beg, &genv->area);
410 XPfree(vars)afree((vars).beg, &genv->area);
411 }
412
413 return t;
414}
415
416static struct op *
417dogroup(void)
418{
419 int c;
420 struct op *list;
421
422 c = token(CONTIN|KEYWORD|ALIAS)((reject) ? (reject = 0, symbol) : (symbol = yylex((1<<
(0))|(1<<(3))|(1<<(2)))))
;
423 /* A {...} can be used instead of do...done for for/select loops
424 * but not for while/until loops - we don't need to check if it
425 * is a while loop because it would have been parsed as part of
426 * the conditional command list...
427 */
428 if (c == DO271)
429 c = DONE272;
430 else if (c == '{')
431 c = '}';
432 else
433 syntaxerr(NULL((void*)0));
434 list = c_list(true1);
435 musthave(c, KEYWORD(1<<(3))|ALIAS(1<<(2)));
436 return list;
437}
438
439static struct op *
440thenpart(void)
441{
442 struct op *t;
443
444 musthave(THEN261, KEYWORD(1<<(3))|ALIAS(1<<(2)));
445 t = newtp(0);
446 t->left = c_list(true1);
447 if (t->left == NULL((void*)0))
448 syntaxerr(NULL((void*)0));
449 t->right = elsepart();
450 return (t);
451}
452
453static struct op *
454elsepart(void)
455{
456 struct op *t;
457
458 switch (token(KEYWORD|ALIAS|VARASN)((reject) ? (reject = 0, symbol) : (symbol = yylex((1<<
(3))|(1<<(2))|(1<<(5)))))
) {
459 case ELSE262:
460 if ((t = c_list(true1)) == NULL((void*)0))
461 syntaxerr(NULL((void*)0));
462 return (t);
463
464 case ELIF263:
465 t = newtp(TELIF15);
466 t->left = c_list(true1);
467 t->right = thenpart();
468 return (t);
469
470 default:
471 reject = true1;
472 }
473 return NULL((void*)0);
474}
475
476static struct op *
477caselist(void)
478{
479 struct op *t, *tl;
480 int c;
481
482 c = token(CONTIN|KEYWORD|ALIAS)((reject) ? (reject = 0, symbol) : (symbol = yylex((1<<
(0))|(1<<(3))|(1<<(2)))))
;
483 /* A {...} can be used instead of in...esac for case statements */
484 if (c == IN273)
485 c = ESAC266;
486 else if (c == '{')
487 c = '}';
488 else
489 syntaxerr(NULL((void*)0));
490 t = tl = NULL((void*)0);
491 while ((tpeek(CONTIN|KEYWORD|ESACONLY)((reject) ? (symbol) : (reject = 1, symbol = yylex((1<<
(0))|(1<<(3))|(1<<(7)))))
) != c) { /* no ALIAS here */
492 struct op *tc = casepart(c);
493 if (tl == NULL((void*)0))
494 t = tl = tc, tl->right = NULL((void*)0);
495 else
496 tl->right = tc, tl = tc;
497 }
498 musthave(c, KEYWORD(1<<(3))|ALIAS(1<<(2)));
499 return (t);
500}
501
502static struct op *
503casepart(int endtok)
504{
505 struct op *t;
506 int c;
507 XPtrV ptns;
508
509 XPinit(ptns, 16)do { void **vp__; vp__ = areallocarray(((void*)0), 16, sizeof
(void *), &genv->area); (ptns).cur = (ptns).beg = vp__
; (ptns).end = vp__ + 16; } while (0)
;
510 t = newtp(TPAT16);
511 c = token(CONTIN|KEYWORD)((reject) ? (reject = 0, symbol) : (symbol = yylex((1<<
(0))|(1<<(3)))))
; /* no ALIAS here */
512 if (c != '(')
513 reject = true1;
514 do {
515 musthave(LWORD256, 0);
516 XPput(ptns, yylval.cp)do { if ((ptns).cur >= (ptns).end) { int n = ((ptns).cur -
(ptns).beg); (ptns).beg = areallocarray((ptns).beg, n, 2 * sizeof
(void *), &genv->area); (ptns).cur = (ptns).beg + n; (
ptns).end = (ptns).cur + n; } *(ptns).cur++ = (yylval.cp); } while
(0)
;
517 } while ((c = token(0)((reject) ? (reject = 0, symbol) : (symbol = yylex(0)))) == '|');
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c'
518 reject = true1;
519 XPput(ptns, NULL)do { if ((ptns).cur >= (ptns).end) { int n = ((ptns).cur -
(ptns).beg); (ptns).beg = areallocarray((ptns).beg, n, 2 * sizeof
(void *), &genv->area); (ptns).cur = (ptns).beg + n; (
ptns).end = (ptns).cur + n; } *(ptns).cur++ = (((void*)0)); }
while (0)
;
520 t->vars = (char **) XPclose(ptns)areallocarray((ptns).beg, ((ptns).cur - (ptns).beg), sizeof(void
*), &genv->area)
;
521 musthave(')', 0);
522
523 t->left = c_list(true1);
524 /* Note: Posix requires the ;; */
525 if ((tpeek(CONTIN|KEYWORD|ALIAS)((reject) ? (symbol) : (reject = 1, symbol = yylex((1<<
(0))|(1<<(3))|(1<<(2)))))
) != endtok)
526 musthave(BREAK259, CONTIN(1<<(0))|KEYWORD(1<<(3))|ALIAS(1<<(2)));
527 return (t);
528}
529
530static struct op *
531function_body(char *name,
532 int ksh_func) /* function foo { ... } vs foo() { .. } */
533{
534 char *sname, *p;
535 struct op *t;
536 int old_func_parse;
537
538 sname = wdstrip(name);
539 /* Check for valid characters in name. posix and ksh93 say only
540 * allow [a-zA-Z_0-9] but this allows more as old pdksh's have
541 * allowed more (the following were never allowed:
542 * nul space nl tab $ ' " \ ` ( ) & | ; = < >
543 * C_QUOTE covers all but = and adds # [ ? *)
544 */
545 for (p = sname; *p; p++)
546 if (ctype(*p, C_QUOTE)!!(ctypes[(unsigned char)(*p)]&((1<<(8)))) || *p == '=')
547 yyerror("%s: invalid function name\n", sname);
548
549 t = newtp(TFUNCT19);
550 t->str = sname;
551 t->u.ksh_func = ksh_func;
552 t->lineno = source->line;
553
554 /* Note that POSIX allows only compound statements after foo(), sh and
555 * at&t ksh allow any command, go with the later since it shouldn't
556 * break anything. However, for function foo, at&t ksh only accepts
557 * an open-brace.
558 */
559 if (ksh_func) {
560 musthave('{', CONTIN(1<<(0))|KEYWORD(1<<(3))|ALIAS(1<<(2))); /* } */
561 reject = true1;
562 }
563
564 old_func_parse = genv->flags & EF_FUNC_PARSE(1<<(0));
565 genv->flags |= EF_FUNC_PARSE(1<<(0));
566 if ((t->left = get_command(CONTIN(1<<(0)))) == NULL((void*)0)) {
567 /*
568 * Probably something like foo() followed by eof or ;.
569 * This is accepted by sh and ksh88.
570 * To make "typeset -f foo" work reliably (so its output can
571 * be used as input), we pretend there is a colon here.
572 */
573 t->left = newtp(TCOM1);
574 t->left->args = areallocarray(NULL((void*)0), 2, sizeof(char *), ATEMP&genv->area);
575 t->left->args[0] = alloc(3, ATEMP&genv->area);
576 t->left->args[0][0] = CHAR1;
577 t->left->args[0][1] = ':';
578 t->left->args[0][2] = EOS0;
579 t->left->args[1] = NULL((void*)0);
580 t->left->vars = alloc(sizeof(char *), ATEMP&genv->area);
581 t->left->vars[0] = NULL((void*)0);
582 t->left->lineno = 1;
583 }
584 if (!old_func_parse)
585 genv->flags &= ~EF_FUNC_PARSE(1<<(0));
586
587 return t;
588}
589
590static char **
591wordlist(void)
592{
593 int c;
594 XPtrV args;
595
596 XPinit(args, 16)do { void **vp__; vp__ = areallocarray(((void*)0), 16, sizeof
(void *), &genv->area); (args).cur = (args).beg = vp__
; (args).end = vp__ + 16; } while (0)
;
597 /* Posix does not do alias expansion here... */
598 if ((c = token(CONTIN|KEYWORD|ALIAS)((reject) ? (reject = 0, symbol) : (symbol = yylex((1<<
(0))|(1<<(3))|(1<<(2)))))
) != IN273) {
599 if (c != ';') /* non-POSIX, but at&t ksh accepts a ; here */
600 reject = true1;
601 return NULL((void*)0);
602 }
603 while ((c = token(0)((reject) ? (reject = 0, symbol) : (symbol = yylex(0)))) == LWORD256)
604 XPput(args, yylval.cp)do { if ((args).cur >= (args).end) { int n = ((args).cur -
(args).beg); (args).beg = areallocarray((args).beg, n, 2 * sizeof
(void *), &genv->area); (args).cur = (args).beg + n; (
args).end = (args).cur + n; } *(args).cur++ = (yylval.cp); } while
(0)
;
605 if (c != '\n' && c != ';')
606 syntaxerr(NULL((void*)0));
607 XPput(args, NULL)do { if ((args).cur >= (args).end) { int n = ((args).cur -
(args).beg); (args).beg = areallocarray((args).beg, n, 2 * sizeof
(void *), &genv->area); (args).cur = (args).beg + n; (
args).end = (args).cur + n; } *(args).cur++ = (((void*)0)); }
while (0)
;
608 return (char **) XPclose(args)areallocarray((args).beg, ((args).cur - (args).beg), sizeof(void
*), &genv->area)
;
609}
610
611/*
612 * supporting functions
613 */
614
615static struct op *
616block(int type, struct op *t1, struct op *t2, char **wp)
617{
618 struct op *t;
619
620 t = newtp(type);
621 t->left = t1;
622 t->right = t2;
623 t->vars = wp;
624 return (t);
625}
626
627const struct tokeninfo {
628 const char *name;
629 short val;
630 short reserved;
631} tokentab[] = {
632 /* Reserved words */
633 { "if", IF260, true1 },
634 { "then", THEN261, true1 },
635 { "else", ELSE262, true1 },
636 { "elif", ELIF263, true1 },
637 { "fi", FI264, true1 },
638 { "case", CASE265, true1 },
639 { "esac", ESAC266, true1 },
640 { "for", FOR267, true1 },
641 { "select", SELECT268, true1 },
642 { "while", WHILE269, true1 },
643 { "until", UNTIL270, true1 },
644 { "do", DO271, true1 },
645 { "done", DONE272, true1 },
646 { "in", IN273, true1 },
647 { "function", FUNCTION274, true1 },
648 { "time", TIME275, true1 },
649 { "{", '{', true1 },
650 { "}", '}', true1 },
651 { "!", BANG278, true1 },
652 { "[[", DBRACKET279, true1 },
653 /* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
654 { "&&", LOGAND257, false0 },
655 { "||", LOGOR258, false0 },
656 { ";;", BREAK259, false0 },
657 { "((", MDPAREN277, false0 },
658 { "|&", COPROC280, false0 },
659 /* and some special cases... */
660 { "newline", '\n', false0 },
661 { 0 }
662};
663
664void
665initkeywords(void)
666{
667 struct tokeninfo const *tt;
668 struct tbl *p;
669
670 ktinit(&keywords, APERM&aperm, 32); /* must be 2^n (currently 20 keywords) */
671 for (tt = tokentab; tt->name; tt++) {
672 if (tt->reserved) {
673 p = ktenter(&keywords, tt->name, hash(tt->name));
674 p->flag |= DEFINED(1<<(1))|ISSET(1<<(2));
675 p->type = CKEYWD6;
676 p->val.i = tt->val;
677 }
678 }
679}
680
681static void
682syntaxerr(const char *what)
683{
684 char redir[6]; /* 2<<- is the longest redirection, I think */
685 const char *s;
686 struct tokeninfo const *tt;
687 int c;
688
689 if (!what)
690 what = "unexpected";
691 reject = true1;
692 c = token(0)((reject) ? (reject = 0, symbol) : (symbol = yylex(0)));
693 Again:
694 switch (c) {
695 case 0:
696 if (nesting.start_token) {
697 c = nesting.start_token;
698 source->errline = nesting.start_line;
699 what = "unmatched";
700 goto Again;
701 }
702 /* don't quote the EOF */
703 yyerror("syntax error: unexpected EOF\n");
704 /* NOTREACHED */
705
706 case LWORD256:
707 s = snptreef(NULL((void*)0), 32, "%S", yylval.cp);
708 break;
709
710 case REDIR276:
711 s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
712 break;
713
714 default:
715 for (tt = tokentab; tt->name; tt++)
716 if (tt->val == c)
717 break;
718 if (tt->name)
719 s = tt->name;
720 else {
721 if (c > 0 && c < 256) {
722 redir[0] = c;
723 redir[1] = '\0';
724 } else
725 shf_snprintf(redir, sizeof(redir),
726 "?%d", c);
727 s = redir;
728 }
729 }
730 yyerror("syntax error: `%s' %s\n", s, what);
731}
732
733static void
734nesting_push(struct nesting_state *save, int tok)
735{
736 *save = nesting;
737 nesting.start_token = tok;
738 nesting.start_line = source->line;
739}
740
741static void
742nesting_pop(struct nesting_state *saved)
743{
744 nesting = *saved;
745}
746
747static struct op *
748newtp(int type)
749{
750 struct op *t;
751
752 t = alloc(sizeof(*t), ATEMP&genv->area);
753 t->type = type;
754 t->u.evalflags = 0;
755 t->args = t->vars = NULL((void*)0);
756 t->ioact = NULL((void*)0);
757 t->left = t->right = NULL((void*)0);
758 t->str = NULL((void*)0);
759 return (t);
760}
761
762struct op *
763compile(Source *s)
764{
765 nesting.start_token = 0;
766 nesting.start_line = 0;
767 herep = heres;
768 source = s;
769 yyparse();
770 return outtree;
771}
772
773/* This kludge exists to take care of sh/at&t ksh oddity in which
774 * the arguments of alias/export/readonly/typeset have no field
775 * splitting, file globbing, or (normal) tilde expansion done.
776 * at&t ksh seems to do something similar to this since
777 * $ touch a=a; typeset a=[ab]; echo "$a"
778 * a=[ab]
779 * $ x=typeset; $x a=[ab]; echo "$a"
780 * a=a
781 * $
782 */
783static int
784assign_command(char *s)
785{
786 if (Flag(FPOSIX)(shell_flags[(int) (FPOSIX)]) || !*s)
787 return 0;
788 return (strcmp(s, "alias") == 0) ||
789 (strcmp(s, "export") == 0) ||
790 (strcmp(s, "readonly") == 0) ||
791 (strcmp(s, "typeset") == 0);
792}
793
794/* Check if we are in the middle of reading an alias */
795static int
796inalias(struct source *s)
797{
798 for (; s && s->type == SALIAS7; s = s->next)
799 if (!(s->flags & SF_ALIASEND(1<<(2))))
800 return 1;
801 return 0;
802}
803
804
805/* Order important - indexed by Test_meta values
806 * Note that ||, &&, ( and ) can't appear in as unquoted strings
807 * in normal shell input, so these can be interpreted unambiguously
808 * in the evaluation pass.
809 */
810static const char dbtest_or[] = { CHAR1, '|', CHAR1, '|', EOS0 };
811static const char dbtest_and[] = { CHAR1, '&', CHAR1, '&', EOS0 };
812static const char dbtest_not[] = { CHAR1, '!', EOS0 };
813static const char dbtest_oparen[] = { CHAR1, '(', EOS0 };
814static const char dbtest_cparen[] = { CHAR1, ')', EOS0 };
815const char *const dbtest_tokens[] = {
816 dbtest_or, dbtest_and, dbtest_not,
817 dbtest_oparen, dbtest_cparen
818};
819const char db_close[] = { CHAR1, ']', CHAR1, ']', EOS0 };
820const char db_lthan[] = { CHAR1, '<', EOS0 };
821const char db_gthan[] = { CHAR1, '>', EOS0 };
822
823/* Test if the current token is a whatever. Accepts the current token if
824 * it is. Returns 0 if it is not, non-zero if it is (in the case of
825 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
826 */
827static int
828dbtestp_isa(Test_env *te, Test_meta meta)
829{
830 int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN))((reject) ? (symbol) : (reject = 1, symbol = yylex((1<<
(6)) | (meta == TM_BINOP ? 0 : (1<<(0))))))
;
831 int uqword = 0;
832 char *save = NULL((void*)0);
833 int ret = 0;
834
835 /* unquoted word? */
836 uqword = c == LWORD256 && *ident;
837
838 if (meta == TM_OR)
839 ret = c == LOGOR258;
840 else if (meta == TM_AND)
841 ret = c == LOGAND257;
842 else if (meta == TM_NOT)
843 ret = uqword && strcmp(yylval.cp, dbtest_tokens[(int) TM_NOT]) == 0;
844 else if (meta == TM_OPAREN)
845 ret = c == '(' /*)*/;
846 else if (meta == TM_CPAREN)
847 ret = c == /*(*/ ')';
848 else if (meta == TM_UNOP || meta == TM_BINOP) {
849 if (meta == TM_BINOP && c == REDIR276 &&
850 (yylval.iop->flag == IOREAD0x1 || yylval.iop->flag == IOWRITE0x2)) {
851 ret = 1;
852 save = wdcopy(yylval.iop->flag == IOREAD0x1 ?
853 db_lthan : db_gthan, ATEMP&genv->area);
854 } else if (uqword && (ret = (int) test_isop(te, meta, ident)))
855 save = yylval.cp;
856 } else /* meta == TM_END */
857 ret = uqword && strcmp(yylval.cp, db_close) == 0;
858 if (ret) {
859 reject = false0;
860 if (meta != TM_END) {
861 if (!save)
862 save = wdcopy(dbtest_tokens[(int) meta], ATEMP&genv->area);
863 XPput(*te->pos.av, save)do { if ((*te->pos.av).cur >= (*te->pos.av).end) { int
n = ((*te->pos.av).cur - (*te->pos.av).beg); (*te->
pos.av).beg = areallocarray((*te->pos.av).beg, n, 2 * sizeof
(void *), &genv->area); (*te->pos.av).cur = (*te->
pos.av).beg + n; (*te->pos.av).end = (*te->pos.av).cur +
n; } *(*te->pos.av).cur++ = (save); } while (0)
;
864 }
865 }
866 return ret;
867}
868
869static const char *
870dbtestp_getopnd(Test_env *te, Test_op op, int do_eval)
871{
872 int c = tpeek(ARRAYVAR)((reject) ? (symbol) : (reject = 1, symbol = yylex((1<<
(6)))))
;
873
874 if (c != LWORD256)
875 return NULL((void*)0);
876
877 reject = false0;
878 XPput(*te->pos.av, yylval.cp)do { if ((*te->pos.av).cur >= (*te->pos.av).end) { int
n = ((*te->pos.av).cur - (*te->pos.av).beg); (*te->
pos.av).beg = areallocarray((*te->pos.av).beg, n, 2 * sizeof
(void *), &genv->area); (*te->pos.av).cur = (*te->
pos.av).beg + n; (*te->pos.av).end = (*te->pos.av).cur +
n; } *(*te->pos.av).cur++ = (yylval.cp); } while (0)
;
879
880 return null;
881}
882
883static int
884dbtestp_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
885 int do_eval)
886{
887 return 1;
888}
889
890static void
891dbtestp_error(Test_env *te, int offset, const char *msg)
892{
893 te->flags |= TEF_ERROR(1<<(0));
894
895 if (offset < 0) {
896 reject = true1;
897 /* Kludgy to say the least... */
898 symbol = LWORD256;
899 yylval.cp = *(XPptrv(*te->pos.av)((*te->pos.av).beg) + XPsize(*te->pos.av)((*te->pos.av).cur - (*te->pos.av).beg) +
900 offset);
901 }
902 syntaxerr(msg);
903}