File: | src/bin/ksh/tree.c |
Warning: | line 274, column 12 Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: tree.c,v 1.34 2018/04/09 17:53:36 tobias Exp $ */ |
2 | |
3 | /* |
4 | * command tree climbing |
5 | */ |
6 | |
7 | #include <string.h> |
8 | |
9 | #include "sh.h" |
10 | |
11 | #define INDENT4 4 |
12 | |
13 | #define tputc(c, shf)shf_putchar(c, shf); shf_putchar(c, shf); |
14 | static void ptree(struct op *, int, struct shf *); |
15 | static void pioact(struct shf *, int, struct ioword *); |
16 | static void tputC(int, struct shf *); |
17 | static void tputS(char *, struct shf *); |
18 | static void vfptreef(struct shf *, int, const char *, va_list); |
19 | static struct ioword **iocopy(struct ioword **, Area *); |
20 | static void iofree(struct ioword **, Area *); |
21 | |
22 | /* |
23 | * print a command tree |
24 | */ |
25 | |
26 | static void |
27 | ptree(struct op *t, int indent, struct shf *shf) |
28 | { |
29 | char **w; |
30 | struct ioword **ioact; |
31 | struct op *t1; |
32 | |
33 | Chain: |
34 | if (t == NULL((void *)0)) |
35 | return; |
36 | switch (t->type) { |
37 | case TCOM1: |
38 | if (t->vars) |
39 | for (w = t->vars; *w != NULL((void *)0); ) |
40 | fptreef(shf, indent, "%S ", *w++); |
41 | else |
42 | fptreef(shf, indent, "#no-vars# "); |
43 | if (t->args) |
44 | for (w = t->args; *w != NULL((void *)0); ) |
45 | fptreef(shf, indent, "%S ", *w++); |
46 | else |
47 | fptreef(shf, indent, "#no-args# "); |
48 | break; |
49 | case TEXEC21: |
50 | t = t->left; |
51 | goto Chain; |
52 | case TPAREN2: |
53 | fptreef(shf, indent + 2, "( %T) ", t->left); |
54 | break; |
55 | case TPIPE3: |
56 | fptreef(shf, indent, "%T| ", t->left); |
57 | t = t->right; |
58 | goto Chain; |
59 | case TLIST4: |
60 | fptreef(shf, indent, "%T%;", t->left); |
61 | t = t->right; |
62 | goto Chain; |
63 | case TOR5: |
64 | case TAND6: |
65 | fptreef(shf, indent, "%T%s %T", |
66 | t->left, (t->type==TOR5) ? "||" : "&&", t->right); |
67 | break; |
68 | case TBANG7: |
69 | fptreef(shf, indent, "! "); |
70 | t = t->right; |
71 | goto Chain; |
72 | case TDBRACKET8: |
73 | { |
74 | int i; |
75 | |
76 | fptreef(shf, indent, "[["); |
77 | for (i = 0; t->args[i]; i++) |
78 | fptreef(shf, indent, " %S", t->args[i]); |
79 | fptreef(shf, indent, " ]] "); |
80 | break; |
81 | } |
82 | case TSELECT10: |
83 | fptreef(shf, indent, "select %s ", t->str); |
84 | /* FALLTHROUGH */ |
85 | case TFOR9: |
86 | if (t->type == TFOR9) |
87 | fptreef(shf, indent, "for %s ", t->str); |
88 | if (t->vars != NULL((void *)0)) { |
89 | fptreef(shf, indent, "in "); |
90 | for (w = t->vars; *w; ) |
91 | fptreef(shf, indent, "%S ", *w++); |
92 | fptreef(shf, indent, "%;"); |
93 | } |
94 | fptreef(shf, indent + INDENT4, "do%N%T", t->left); |
95 | fptreef(shf, indent, "%;done "); |
96 | break; |
97 | case TCASE11: |
98 | fptreef(shf, indent, "case %S in", t->str); |
99 | for (t1 = t->left; t1 != NULL((void *)0); t1 = t1->right) { |
100 | fptreef(shf, indent, "%N("); |
101 | for (w = t1->vars; *w != NULL((void *)0); w++) |
102 | fptreef(shf, indent, "%S%c", *w, |
103 | (w[1] != NULL((void *)0)) ? '|' : ')'); |
104 | fptreef(shf, indent + INDENT4, "%;%T%N;;", t1->left); |
105 | } |
106 | fptreef(shf, indent, "%Nesac "); |
107 | break; |
108 | case TIF12: |
109 | case TELIF15: |
110 | /* 3 == strlen("if ") */ |
111 | fptreef(shf, indent + 3, "if %T", t->left); |
112 | for (;;) { |
113 | t = t->right; |
114 | if (t->left != NULL((void *)0)) { |
115 | fptreef(shf, indent, "%;"); |
116 | fptreef(shf, indent + INDENT4, "then%N%T", |
117 | t->left); |
118 | } |
119 | if (t->right == NULL((void *)0) || t->right->type != TELIF15) |
120 | break; |
121 | t = t->right; |
122 | fptreef(shf, indent, "%;"); |
123 | /* 5 == strlen("elif ") */ |
124 | fptreef(shf, indent + 5, "elif %T", t->left); |
125 | } |
126 | if (t->right != NULL((void *)0)) { |
127 | fptreef(shf, indent, "%;"); |
128 | fptreef(shf, indent + INDENT4, "else%;%T", t->right); |
129 | } |
130 | fptreef(shf, indent, "%;fi "); |
131 | break; |
132 | case TWHILE13: |
133 | case TUNTIL14: |
134 | /* 6 == strlen("while"/"until") */ |
135 | fptreef(shf, indent + 6, "%s %T", |
136 | (t->type==TWHILE13) ? "while" : "until", |
137 | t->left); |
138 | fptreef(shf, indent, "%;do"); |
139 | fptreef(shf, indent + INDENT4, "%;%T", t->right); |
140 | fptreef(shf, indent, "%;done "); |
141 | break; |
142 | case TBRACE17: |
143 | fptreef(shf, indent + INDENT4, "{%;%T", t->left); |
144 | fptreef(shf, indent, "%;} "); |
145 | break; |
146 | case TCOPROC22: |
147 | fptreef(shf, indent, "%T|& ", t->left); |
148 | break; |
149 | case TASYNC18: |
150 | fptreef(shf, indent, "%T& ", t->left); |
151 | break; |
152 | case TFUNCT19: |
153 | fptreef(shf, indent, |
154 | t->u.ksh_func ? "function %s %T" : "%s() %T", |
155 | t->str, t->left); |
156 | break; |
157 | case TTIME20: |
158 | fptreef(shf, indent, "time %T", t->left); |
159 | break; |
160 | default: |
161 | fptreef(shf, indent, "<botch>"); |
162 | break; |
163 | } |
164 | if ((ioact = t->ioact) != NULL((void *)0)) { |
165 | int need_nl = 0; |
166 | |
167 | while (*ioact != NULL((void *)0)) |
168 | pioact(shf, indent, *ioact++); |
169 | /* Print here documents after everything else... */ |
170 | for (ioact = t->ioact; *ioact != NULL((void *)0); ) { |
171 | struct ioword *iop = *ioact++; |
172 | |
173 | /* heredoc is 0 when tracing (set -x) */ |
174 | if ((iop->flag & IOTYPE0xF) == IOHERE0x4 && iop->heredoc) { |
175 | tputc('\n', shf)shf_putchar('\n', shf);; |
176 | shf_puts(iop->heredoc, shf); |
177 | fptreef(shf, indent, "%s", |
178 | evalstr(iop->delim, 0)); |
179 | need_nl = 1; |
180 | } |
181 | } |
182 | /* Last delimiter must be followed by a newline (this often |
183 | * leads to an extra blank line, but its not worth worrying |
184 | * about) |
185 | */ |
186 | if (need_nl) |
187 | tputc('\n', shf)shf_putchar('\n', shf);; |
188 | } |
189 | } |
190 | |
191 | static void |
192 | pioact(struct shf *shf, int indent, struct ioword *iop) |
193 | { |
194 | int flag = iop->flag; |
195 | int type = flag & IOTYPE0xF; |
196 | int expected; |
197 | |
198 | expected = (type == IOREAD0x1 || type == IORDWR0x3 || type == IOHERE0x4) ? 0 : |
199 | (type == IOCAT0x5 || type == IOWRITE0x2) ? 1 : |
200 | (type == IODUP0x6 && (iop->unit == !(flag & IORDUP(1<<(7))))) ? iop->unit : |
201 | iop->unit + 1; |
202 | if (iop->unit != expected) |
203 | tputc('0' + iop->unit, shf)shf_putchar('0' + iop->unit, shf);; |
204 | |
205 | switch (type) { |
206 | case IOREAD0x1: |
207 | fptreef(shf, indent, "< "); |
208 | break; |
209 | case IOHERE0x4: |
210 | if (flag&IOSKIP(1<<(5))) |
211 | fptreef(shf, indent, "<<- "); |
212 | else |
213 | fptreef(shf, indent, "<< "); |
214 | break; |
215 | case IOCAT0x5: |
216 | fptreef(shf, indent, ">> "); |
217 | break; |
218 | case IOWRITE0x2: |
219 | if (flag&IOCLOB(1<<(6))) |
220 | fptreef(shf, indent, ">| "); |
221 | else |
222 | fptreef(shf, indent, "> "); |
223 | break; |
224 | case IORDWR0x3: |
225 | fptreef(shf, indent, "<> "); |
226 | break; |
227 | case IODUP0x6: |
228 | if (flag & IORDUP(1<<(7))) |
229 | fptreef(shf, indent, "<&"); |
230 | else |
231 | fptreef(shf, indent, ">&"); |
232 | break; |
233 | } |
234 | /* name/delim are 0 when printing syntax errors */ |
235 | if (type == IOHERE0x4) { |
236 | if (iop->delim) |
237 | fptreef(shf, indent, "%S ", iop->delim); |
238 | } else if (iop->name) |
239 | fptreef(shf, indent, (iop->flag & IONAMEXP(1<<(8))) ? "%s " : "%S ", |
240 | iop->name); |
241 | } |
242 | |
243 | |
244 | /* |
245 | * variants of fputc, fputs for ptreef and snptreef |
246 | */ |
247 | |
248 | static void |
249 | tputC(int c, struct shf *shf) |
250 | { |
251 | if ((c&0x60) == 0) { /* C0|C1 */ |
252 | tputc((c&0x80) ? '$' : '^', shf)shf_putchar((c&0x80) ? '$' : '^', shf);; |
253 | tputc(((c&0x7F)|0x40), shf)shf_putchar(((c&0x7F)|0x40), shf);; |
254 | } else if ((c&0x7F) == 0x7F) { /* DEL */ |
255 | tputc((c&0x80) ? '$' : '^', shf)shf_putchar((c&0x80) ? '$' : '^', shf);; |
256 | tputc('?', shf)shf_putchar('?', shf);; |
257 | } else |
258 | tputc(c, shf)shf_putchar(c, shf);; |
259 | } |
260 | |
261 | static void |
262 | tputS(char *wp, struct shf *shf) |
263 | { |
264 | int c, quoted=0; |
265 | |
266 | /* problems: |
267 | * `...` -> $(...) |
268 | * 'foo' -> "foo" |
269 | * could change encoding to: |
270 | * OQUOTE ["'] ... CQUOTE ["'] |
271 | * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case) |
272 | */ |
273 | while (1) |
274 | switch ((c = *wp++)) { |
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c' | |
275 | case EOS0: |
276 | return; |
277 | case CHAR1: |
278 | tputC(*wp++, shf); |
279 | break; |
280 | case QCHAR2: |
281 | c = *wp++; |
282 | if (!quoted || (c == '"' || c == '`' || c == '$')) |
283 | tputc('\\', shf)shf_putchar('\\', shf);; |
284 | tputC(c, shf); |
285 | break; |
286 | case COMSUB3: |
287 | tputc('$', shf)shf_putchar('$', shf);; |
288 | tputc('(', shf)shf_putchar('(', shf);; |
289 | while (*wp != 0) |
290 | tputC(*wp++, shf); |
291 | tputc(')', shf)shf_putchar(')', shf);; |
292 | wp++; |
293 | break; |
294 | case EXPRSUB4: |
295 | tputc('$', shf)shf_putchar('$', shf);; |
296 | tputc('(', shf)shf_putchar('(', shf);; |
297 | tputc('(', shf)shf_putchar('(', shf);; |
298 | while (*wp != 0) |
299 | tputC(*wp++, shf); |
300 | tputc(')', shf)shf_putchar(')', shf);; |
301 | tputc(')', shf)shf_putchar(')', shf);; |
302 | wp++; |
303 | break; |
304 | case OQUOTE5: |
305 | quoted = 1; |
306 | tputc('"', shf)shf_putchar('"', shf);; |
307 | break; |
308 | case CQUOTE6: |
309 | quoted = 0; |
310 | tputc('"', shf)shf_putchar('"', shf);; |
311 | break; |
312 | case OSUBST7: |
313 | tputc('$', shf)shf_putchar('$', shf);; |
314 | if (*wp++ == '{') |
315 | tputc('{', shf)shf_putchar('{', shf);; |
316 | while ((c = *wp++) != 0) |
317 | tputC(c, shf); |
318 | break; |
319 | case CSUBST8: |
320 | if (*wp++ == '}') |
321 | tputc('}', shf)shf_putchar('}', shf);; |
322 | break; |
323 | case OPAT9: |
324 | tputc(*wp++, shf)shf_putchar(*wp++, shf);; |
325 | tputc('(', shf)shf_putchar('(', shf);; |
326 | break; |
327 | case SPAT10: |
328 | tputc('|', shf)shf_putchar('|', shf);; |
329 | break; |
330 | case CPAT11: |
331 | tputc(')', shf)shf_putchar(')', shf);; |
332 | break; |
333 | } |
334 | } |
335 | |
336 | void |
337 | fptreef(struct shf *shf, int indent, const char *fmt, ...) |
338 | { |
339 | va_list va; |
340 | |
341 | va_start(va, fmt)__builtin_va_start((va), fmt); |
342 | vfptreef(shf, indent, fmt, va); |
343 | va_end(va)__builtin_va_end((va)); |
344 | } |
345 | |
346 | char * |
347 | snptreef(char *s, int n, const char *fmt, ...) |
348 | { |
349 | va_list va; |
350 | struct shf shf; |
351 | |
352 | shf_sopen(s, n, SHF_WR0x0002 | (s ? 0 : SHF_DYNAMIC0x0040), &shf); |
353 | |
354 | va_start(va, fmt)__builtin_va_start((va), fmt); |
355 | vfptreef(&shf, 0, fmt, va); |
356 | va_end(va)__builtin_va_end((va)); |
357 | |
358 | return shf_sclose(&shf); /* null terminates */ |
359 | } |
360 | |
361 | static void |
362 | vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) |
363 | { |
364 | int c; |
365 | |
366 | while ((c = *fmt++)) { |
367 | if (c == '%') { |
368 | int64_t n; |
369 | char *p; |
370 | int neg; |
371 | |
372 | switch ((c = *fmt++)) { |
373 | case 'c': |
374 | tputc(va_arg(va, int), shf)shf_putchar(__builtin_va_arg((va), int), shf);; |
375 | break; |
376 | case 'd': /* decimal */ |
377 | n = va_arg(va, int)__builtin_va_arg((va), int); |
378 | neg = n < 0; |
379 | p = u64ton(neg ? -n : n, 10); |
380 | if (neg) |
381 | *--p = '-'; |
382 | while (*p) |
383 | tputc(*p++, shf)shf_putchar(*p++, shf);; |
384 | break; |
385 | case 's': |
386 | p = va_arg(va, char *)__builtin_va_arg((va), char *); |
387 | while (*p) |
388 | tputc(*p++, shf)shf_putchar(*p++, shf);; |
389 | break; |
390 | case 'S': /* word */ |
391 | p = va_arg(va, char *)__builtin_va_arg((va), char *); |
392 | tputS(p, shf); |
393 | break; |
394 | case 'u': /* unsigned decimal */ |
395 | p = u64ton(va_arg(va, unsigned int)__builtin_va_arg((va), unsigned int), 10); |
396 | while (*p) |
397 | tputc(*p++, shf)shf_putchar(*p++, shf);; |
398 | break; |
399 | case 'T': /* format tree */ |
400 | ptree(va_arg(va, struct op *)__builtin_va_arg((va), struct op *), indent, shf); |
401 | break; |
402 | case ';': /* newline or ; */ |
403 | case 'N': /* newline or space */ |
404 | if (shf->flags & SHF_STRING0x0100) { |
405 | if (c == ';') |
406 | tputc(';', shf)shf_putchar(';', shf);; |
407 | tputc(' ', shf)shf_putchar(' ', shf);; |
408 | } else { |
409 | int i; |
410 | |
411 | tputc('\n', shf)shf_putchar('\n', shf);; |
412 | for (i = indent; i >= 8; i -= 8) |
413 | tputc('\t', shf)shf_putchar('\t', shf);; |
414 | for (; i > 0; --i) |
415 | tputc(' ', shf)shf_putchar(' ', shf);; |
416 | } |
417 | break; |
418 | case 'R': |
419 | pioact(shf, indent, va_arg(va, struct ioword *)__builtin_va_arg((va), struct ioword *)); |
420 | break; |
421 | default: |
422 | tputc(c, shf)shf_putchar(c, shf);; |
423 | break; |
424 | } |
425 | } else |
426 | tputc(c, shf)shf_putchar(c, shf);; |
427 | } |
428 | } |
429 | |
430 | /* |
431 | * copy tree (for function definition) |
432 | */ |
433 | |
434 | struct op * |
435 | tcopy(struct op *t, Area *ap) |
436 | { |
437 | struct op *r; |
438 | char **tw, **rw; |
439 | |
440 | if (t == NULL((void *)0)) |
441 | return NULL((void *)0); |
442 | |
443 | r = alloc(sizeof(struct op), ap); |
444 | |
445 | r->type = t->type; |
446 | r->u.evalflags = t->u.evalflags; |
447 | |
448 | r->str = t->type == TCASE11 ? wdcopy(t->str, ap) : str_save(t->str, ap); |
449 | |
450 | if (t->vars == NULL((void *)0)) |
451 | r->vars = NULL((void *)0); |
452 | else { |
453 | for (tw = t->vars; *tw++ != NULL((void *)0); ) |
454 | ; |
455 | rw = r->vars = areallocarray(NULL((void *)0), tw - t->vars + 1, |
456 | sizeof(*tw), ap); |
457 | for (tw = t->vars; *tw != NULL((void *)0); ) |
458 | *rw++ = wdcopy(*tw++, ap); |
459 | *rw = NULL((void *)0); |
460 | } |
461 | |
462 | if (t->args == NULL((void *)0)) |
463 | r->args = NULL((void *)0); |
464 | else { |
465 | for (tw = t->args; *tw++ != NULL((void *)0); ) |
466 | ; |
467 | rw = r->args = areallocarray(NULL((void *)0), tw - t->args + 1, |
468 | sizeof(*tw), ap); |
469 | for (tw = t->args; *tw != NULL((void *)0); ) |
470 | *rw++ = wdcopy(*tw++, ap); |
471 | *rw = NULL((void *)0); |
472 | } |
473 | |
474 | r->ioact = (t->ioact == NULL((void *)0)) ? NULL((void *)0) : iocopy(t->ioact, ap); |
475 | |
476 | r->left = tcopy(t->left, ap); |
477 | r->right = tcopy(t->right, ap); |
478 | r->lineno = t->lineno; |
479 | |
480 | return r; |
481 | } |
482 | |
483 | char * |
484 | wdcopy(const char *wp, Area *ap) |
485 | { |
486 | size_t len = wdscan(wp, EOS0) - wp; |
487 | return memcpy(alloc(len, ap), wp, len); |
488 | } |
489 | |
490 | /* return the position of prefix c in wp plus 1 */ |
491 | char * |
492 | wdscan(const char *wp, int c) |
493 | { |
494 | int nest = 0; |
495 | |
496 | while (1) |
497 | switch (*wp++) { |
498 | case EOS0: |
499 | return (char *) wp; |
500 | case CHAR1: |
501 | case QCHAR2: |
502 | wp++; |
503 | break; |
504 | case COMSUB3: |
505 | case EXPRSUB4: |
506 | while (*wp++ != 0) |
507 | ; |
508 | break; |
509 | case OQUOTE5: |
510 | case CQUOTE6: |
511 | break; |
512 | case OSUBST7: |
513 | nest++; |
514 | while (*wp++ != '\0') |
515 | ; |
516 | break; |
517 | case CSUBST8: |
518 | wp++; |
519 | if (c == CSUBST8 && nest == 0) |
520 | return (char *) wp; |
521 | nest--; |
522 | break; |
523 | case OPAT9: |
524 | nest++; |
525 | wp++; |
526 | break; |
527 | case SPAT10: |
528 | case CPAT11: |
529 | if (c == wp[-1] && nest == 0) |
530 | return (char *) wp; |
531 | if (wp[-1] == CPAT11) |
532 | nest--; |
533 | break; |
534 | default: |
535 | internal_warningf( |
536 | "%s: unknown char 0x%x (carrying on)", |
537 | __func__, wp[-1]); |
538 | } |
539 | } |
540 | |
541 | /* return a copy of wp without any of the mark up characters and |
542 | * with quote characters (" ' \) stripped. |
543 | * (string is allocated from ATEMP) |
544 | */ |
545 | char * |
546 | wdstrip(const char *wp) |
547 | { |
548 | struct shf shf; |
549 | int c; |
550 | |
551 | shf_sopen(NULL((void *)0), 32, SHF_WR0x0002 | SHF_DYNAMIC0x0040, &shf); |
552 | |
553 | /* problems: |
554 | * `...` -> $(...) |
555 | * x${foo:-"hi"} -> x${foo:-hi} |
556 | * x${foo:-'hi'} -> x${foo:-hi} |
557 | */ |
558 | while (1) |
559 | switch ((c = *wp++)) { |
560 | case EOS0: |
561 | return shf_sclose(&shf); /* null terminates */ |
562 | case CHAR1: |
563 | case QCHAR2: |
564 | shf_putchar(*wp++, &shf); |
565 | break; |
566 | case COMSUB3: |
567 | shf_putchar('$', &shf); |
568 | shf_putchar('(', &shf); |
569 | while (*wp != 0) |
570 | shf_putchar(*wp++, &shf); |
571 | shf_putchar(')', &shf); |
572 | break; |
573 | case EXPRSUB4: |
574 | shf_putchar('$', &shf); |
575 | shf_putchar('(', &shf); |
576 | shf_putchar('(', &shf); |
577 | while (*wp != 0) |
578 | shf_putchar(*wp++, &shf); |
579 | shf_putchar(')', &shf); |
580 | shf_putchar(')', &shf); |
581 | break; |
582 | case OQUOTE5: |
583 | break; |
584 | case CQUOTE6: |
585 | break; |
586 | case OSUBST7: |
587 | shf_putchar('$', &shf); |
588 | if (*wp++ == '{') |
589 | shf_putchar('{', &shf); |
590 | while ((c = *wp++) != 0) |
591 | shf_putchar(c, &shf); |
592 | break; |
593 | case CSUBST8: |
594 | if (*wp++ == '}') |
595 | shf_putchar('}', &shf); |
596 | break; |
597 | case OPAT9: |
598 | shf_putchar(*wp++, &shf); |
599 | shf_putchar('(', &shf); |
600 | break; |
601 | case SPAT10: |
602 | shf_putchar('|', &shf); |
603 | break; |
604 | case CPAT11: |
605 | shf_putchar(')', &shf); |
606 | break; |
607 | } |
608 | } |
609 | |
610 | static struct ioword ** |
611 | iocopy(struct ioword **iow, Area *ap) |
612 | { |
613 | struct ioword **ior; |
614 | int i; |
615 | |
616 | for (ior = iow; *ior++ != NULL((void *)0); ) |
617 | ; |
618 | ior = areallocarray(NULL((void *)0), ior - iow + 1, sizeof(*ior), ap); |
619 | |
620 | for (i = 0; iow[i] != NULL((void *)0); i++) { |
621 | struct ioword *p, *q; |
622 | |
623 | p = iow[i]; |
624 | q = alloc(sizeof(*p), ap); |
625 | ior[i] = q; |
626 | *q = *p; |
627 | if (p->name != NULL((void *)0)) |
628 | q->name = wdcopy(p->name, ap); |
629 | if (p->delim != NULL((void *)0)) |
630 | q->delim = wdcopy(p->delim, ap); |
631 | if (p->heredoc != NULL((void *)0)) |
632 | q->heredoc = str_save(p->heredoc, ap); |
633 | } |
634 | ior[i] = NULL((void *)0); |
635 | |
636 | return ior; |
637 | } |
638 | |
639 | /* |
640 | * free tree (for function definition) |
641 | */ |
642 | |
643 | void |
644 | tfree(struct op *t, Area *ap) |
645 | { |
646 | char **w; |
647 | |
648 | if (t == NULL((void *)0)) |
649 | return; |
650 | |
651 | afree(t->str, ap); |
652 | |
653 | if (t->vars != NULL((void *)0)) { |
654 | for (w = t->vars; *w != NULL((void *)0); w++) |
655 | afree(*w, ap); |
656 | afree(t->vars, ap); |
657 | } |
658 | |
659 | if (t->args != NULL((void *)0)) { |
660 | for (w = t->args; *w != NULL((void *)0); w++) |
661 | afree(*w, ap); |
662 | afree(t->args, ap); |
663 | } |
664 | |
665 | if (t->ioact != NULL((void *)0)) |
666 | iofree(t->ioact, ap); |
667 | |
668 | tfree(t->left, ap); |
669 | tfree(t->right, ap); |
670 | |
671 | afree(t, ap); |
672 | } |
673 | |
674 | static void |
675 | iofree(struct ioword **iow, Area *ap) |
676 | { |
677 | struct ioword **iop; |
678 | struct ioword *p; |
679 | |
680 | for (iop = iow; (p = *iop++) != NULL((void *)0); ) { |
681 | afree(p->name, ap); |
682 | afree(p->delim, ap); |
683 | afree(p->heredoc, ap); |
684 | afree(p, ap); |
685 | } |
686 | afree(iow, ap); |
687 | } |