| 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 | } |