Thorsten Glaser | ba2627c | 2010-08-24 18:21:37 +0200 | [diff] [blame] | 1 | /* $OpenBSD: tree.c,v 1.19 2008/08/11 21:50:35 jaredy Exp $ */ |
| 2 | |
| 3 | /*- |
| 4 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
| 5 | * Thorsten Glaser <tg@mirbsd.org> |
| 6 | * |
| 7 | * Provided that these terms and disclaimer and all copyright notices |
| 8 | * are retained or reproduced in an accompanying document, permission |
| 9 | * is granted to deal in this work without restriction, including un- |
| 10 | * limited rights to use, publicly perform, distribute, sell, modify, |
| 11 | * merge, give away, or sublicence. |
| 12 | * |
| 13 | * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to |
| 14 | * the utmost extent permitted by applicable law, neither express nor |
| 15 | * implied; without malicious intent or gross negligence. In no event |
| 16 | * may a licensor, author or contributor be held liable for indirect, |
| 17 | * direct, other damage, loss, or other issues arising in any way out |
| 18 | * of dealing in the work, even if advised of the possibility of such |
| 19 | * damage or existence of a defect, except proven that it results out |
| 20 | * of said person's immediate fault when using the work as intended. |
| 21 | */ |
| 22 | |
| 23 | #include "sh.h" |
| 24 | |
| 25 | __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.30 2010/02/25 20:18:19 tg Exp $"); |
| 26 | |
| 27 | #define INDENT 4 |
| 28 | |
| 29 | #define tputc(c, shf) shf_putchar(c, shf); |
| 30 | static void ptree(struct op *, int, struct shf *); |
| 31 | static void pioact(struct shf *, int, struct ioword *); |
| 32 | static void tputC(int, struct shf *); |
| 33 | static void tputS(char *, struct shf *); |
| 34 | static void vfptreef(struct shf *, int, const char *, va_list); |
| 35 | static struct ioword **iocopy(struct ioword **, Area *); |
| 36 | static void iofree(struct ioword **, Area *); |
| 37 | |
| 38 | /* |
| 39 | * print a command tree |
| 40 | */ |
| 41 | static void |
| 42 | ptree(struct op *t, int indent, struct shf *shf) |
| 43 | { |
| 44 | const char **w; |
| 45 | struct ioword **ioact; |
| 46 | struct op *t1; |
| 47 | |
| 48 | Chain: |
| 49 | if (t == NULL) |
| 50 | return; |
| 51 | switch (t->type) { |
| 52 | case TCOM: |
| 53 | if (t->vars) |
| 54 | for (w = (const char **)t->vars; *w != NULL; ) |
| 55 | fptreef(shf, indent, "%S ", *w++); |
| 56 | else |
| 57 | shf_puts("#no-vars# ", shf); |
| 58 | if (t->args) |
| 59 | for (w = t->args; *w != NULL; ) |
| 60 | fptreef(shf, indent, "%S ", *w++); |
| 61 | else |
| 62 | shf_puts("#no-args# ", shf); |
| 63 | break; |
| 64 | case TEXEC: |
| 65 | t = t->left; |
| 66 | goto Chain; |
| 67 | case TPAREN: |
| 68 | fptreef(shf, indent + 2, "( %T) ", t->left); |
| 69 | break; |
| 70 | case TPIPE: |
| 71 | fptreef(shf, indent, "%T| ", t->left); |
| 72 | t = t->right; |
| 73 | goto Chain; |
| 74 | case TLIST: |
| 75 | fptreef(shf, indent, "%T%;", t->left); |
| 76 | t = t->right; |
| 77 | goto Chain; |
| 78 | case TOR: |
| 79 | case TAND: |
| 80 | fptreef(shf, indent, "%T%s %T", |
| 81 | t->left, (t->type==TOR) ? "||" : "&&", t->right); |
| 82 | break; |
| 83 | case TBANG: |
| 84 | shf_puts("! ", shf); |
| 85 | t = t->right; |
| 86 | goto Chain; |
| 87 | case TDBRACKET: { |
| 88 | int i; |
| 89 | |
| 90 | shf_puts("[[", shf); |
| 91 | for (i = 0; t->args[i]; i++) |
| 92 | fptreef(shf, indent, " %S", t->args[i]); |
| 93 | shf_puts(" ]] ", shf); |
| 94 | break; |
| 95 | } |
| 96 | case TSELECT: |
| 97 | fptreef(shf, indent, "select %s ", t->str); |
| 98 | /* FALLTHROUGH */ |
| 99 | case TFOR: |
| 100 | if (t->type == TFOR) |
| 101 | fptreef(shf, indent, "for %s ", t->str); |
| 102 | if (t->vars != NULL) { |
| 103 | shf_puts("in ", shf); |
| 104 | for (w = (const char **)t->vars; *w; ) |
| 105 | fptreef(shf, indent, "%S ", *w++); |
| 106 | fptreef(shf, indent, "%;"); |
| 107 | } |
| 108 | fptreef(shf, indent + INDENT, "do%N%T", t->left); |
| 109 | fptreef(shf, indent, "%;done "); |
| 110 | break; |
| 111 | case TCASE: |
| 112 | fptreef(shf, indent, "case %S in", t->str); |
| 113 | for (t1 = t->left; t1 != NULL; t1 = t1->right) { |
| 114 | fptreef(shf, indent, "%N("); |
| 115 | for (w = (const char **)t1->vars; *w != NULL; w++) |
| 116 | fptreef(shf, indent, "%S%c", *w, |
| 117 | (w[1] != NULL) ? '|' : ')'); |
| 118 | fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left); |
| 119 | } |
| 120 | fptreef(shf, indent, "%Nesac "); |
| 121 | break; |
| 122 | case TIF: |
| 123 | case TELIF: |
| 124 | /* 3 == strlen("if ") */ |
| 125 | fptreef(shf, indent + 3, "if %T", t->left); |
| 126 | for (;;) { |
| 127 | t = t->right; |
| 128 | if (t->left != NULL) { |
| 129 | fptreef(shf, indent, "%;"); |
| 130 | fptreef(shf, indent + INDENT, "then%N%T", |
| 131 | t->left); |
| 132 | } |
| 133 | if (t->right == NULL || t->right->type != TELIF) |
| 134 | break; |
| 135 | t = t->right; |
| 136 | fptreef(shf, indent, "%;"); |
| 137 | /* 5 == strlen("elif ") */ |
| 138 | fptreef(shf, indent + 5, "elif %T", t->left); |
| 139 | } |
| 140 | if (t->right != NULL) { |
| 141 | fptreef(shf, indent, "%;"); |
| 142 | fptreef(shf, indent + INDENT, "else%;%T", t->right); |
| 143 | } |
| 144 | fptreef(shf, indent, "%;fi "); |
| 145 | break; |
| 146 | case TWHILE: |
| 147 | case TUNTIL: |
| 148 | /* 6 == strlen("while"/"until") */ |
| 149 | fptreef(shf, indent + 6, "%s %T", |
| 150 | (t->type==TWHILE) ? "while" : "until", |
| 151 | t->left); |
| 152 | fptreef(shf, indent, "%;do"); |
| 153 | fptreef(shf, indent + INDENT, "%;%T", t->right); |
| 154 | fptreef(shf, indent, "%;done "); |
| 155 | break; |
| 156 | case TBRACE: |
| 157 | fptreef(shf, indent + INDENT, "{%;%T", t->left); |
| 158 | fptreef(shf, indent, "%;} "); |
| 159 | break; |
| 160 | case TCOPROC: |
| 161 | fptreef(shf, indent, "%T|& ", t->left); |
| 162 | break; |
| 163 | case TASYNC: |
| 164 | fptreef(shf, indent, "%T& ", t->left); |
| 165 | break; |
| 166 | case TFUNCT: |
| 167 | fptreef(shf, indent, |
| 168 | t->u.ksh_func ? "function %s %T" : "%s() %T", |
| 169 | t->str, t->left); |
| 170 | break; |
| 171 | case TTIME: |
| 172 | fptreef(shf, indent, "time %T", t->left); |
| 173 | break; |
| 174 | default: |
| 175 | shf_puts("<botch>", shf); |
| 176 | break; |
| 177 | } |
| 178 | if ((ioact = t->ioact) != NULL) { |
| 179 | int need_nl = 0; |
| 180 | |
| 181 | while (*ioact != NULL) |
| 182 | pioact(shf, indent, *ioact++); |
| 183 | /* Print here documents after everything else... */ |
| 184 | for (ioact = t->ioact; *ioact != NULL; ) { |
| 185 | struct ioword *iop = *ioact++; |
| 186 | |
| 187 | /* heredoc is 0 when tracing (set -x) */ |
| 188 | if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc && |
| 189 | /* iop->delim[1] == '<' means here string */ |
| 190 | (!iop->delim || iop->delim[1] != '<')) { |
| 191 | tputc('\n', shf); |
| 192 | shf_puts(iop->heredoc, shf); |
| 193 | fptreef(shf, indent, "%s", |
| 194 | evalstr(iop->delim, 0)); |
| 195 | need_nl = 1; |
| 196 | } |
| 197 | } |
| 198 | /* Last delimiter must be followed by a newline (this often |
| 199 | * leads to an extra blank line, but its not worth worrying |
| 200 | * about) |
| 201 | */ |
| 202 | if (need_nl) |
| 203 | tputc('\n', shf); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | static void |
| 208 | pioact(struct shf *shf, int indent, struct ioword *iop) |
| 209 | { |
| 210 | int flag = iop->flag; |
| 211 | int type = flag & IOTYPE; |
| 212 | int expected; |
| 213 | |
| 214 | expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 : |
| 215 | (type == IOCAT || type == IOWRITE) ? 1 : |
| 216 | (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit : |
| 217 | iop->unit + 1; |
| 218 | if (iop->unit != expected) |
| 219 | shf_fprintf(shf, "%d", iop->unit); |
| 220 | |
| 221 | switch (type) { |
| 222 | case IOREAD: |
| 223 | shf_puts("< ", shf); |
| 224 | break; |
| 225 | case IOHERE: |
| 226 | shf_puts(flag & IOSKIP ? "<<-" : "<<", shf); |
| 227 | break; |
| 228 | case IOCAT: |
| 229 | shf_puts(">> ", shf); |
| 230 | break; |
| 231 | case IOWRITE: |
| 232 | shf_puts(flag & IOCLOB ? ">| " : "> ", shf); |
| 233 | break; |
| 234 | case IORDWR: |
| 235 | shf_puts("<> ", shf); |
| 236 | break; |
| 237 | case IODUP: |
| 238 | shf_puts(flag & IORDUP ? "<&" : ">&", shf); |
| 239 | break; |
| 240 | } |
| 241 | /* name/delim are 0 when printing syntax errors */ |
| 242 | if (type == IOHERE) { |
| 243 | if (iop->delim) |
| 244 | fptreef(shf, indent, "%s%S ", |
| 245 | /* here string */ iop->delim[1] == '<' ? "" : " ", |
| 246 | iop->delim); |
| 247 | else |
| 248 | tputc(' ', shf); |
| 249 | } else if (iop->name) |
| 250 | fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ", |
| 251 | iop->name); |
| 252 | } |
| 253 | |
| 254 | |
| 255 | /* |
| 256 | * variants of fputc, fputs for ptreef and snptreef |
| 257 | */ |
| 258 | static void |
| 259 | tputC(int c, struct shf *shf) |
| 260 | { |
| 261 | if ((c&0x60) == 0) { /* C0|C1 */ |
| 262 | tputc((c&0x80) ? '$' : '^', shf); |
| 263 | tputc(((c&0x7F)|0x40), shf); |
| 264 | } else if ((c&0x7F) == 0x7F) { /* DEL */ |
| 265 | tputc((c&0x80) ? '$' : '^', shf); |
| 266 | tputc('?', shf); |
| 267 | } else |
| 268 | tputc(c, shf); |
| 269 | } |
| 270 | |
| 271 | static void |
| 272 | tputS(char *wp, struct shf *shf) |
| 273 | { |
| 274 | int c, quotelevel = 0; |
| 275 | |
| 276 | /* problems: |
| 277 | * `...` -> $(...) |
| 278 | * 'foo' -> "foo" |
| 279 | * could change encoding to: |
| 280 | * OQUOTE ["'] ... CQUOTE ["'] |
| 281 | * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case) |
| 282 | */ |
| 283 | while (1) |
| 284 | switch (*wp++) { |
| 285 | case EOS: |
| 286 | return; |
| 287 | case ADELIM: |
| 288 | case CHAR: |
| 289 | tputC(*wp++, shf); |
| 290 | break; |
| 291 | case QCHAR: |
| 292 | c = *wp++; |
| 293 | if (!quotelevel || (c == '"' || c == '`' || c == '$')) |
| 294 | tputc('\\', shf); |
| 295 | tputC(c, shf); |
| 296 | break; |
| 297 | case COMSUB: |
| 298 | shf_puts("$(", shf); |
| 299 | while (*wp != 0) |
| 300 | tputC(*wp++, shf); |
| 301 | tputc(')', shf); |
| 302 | wp++; |
| 303 | break; |
| 304 | case EXPRSUB: |
| 305 | shf_puts("$((", shf); |
| 306 | while (*wp != 0) |
| 307 | tputC(*wp++, shf); |
| 308 | shf_puts("))", shf); |
| 309 | wp++; |
| 310 | break; |
| 311 | case OQUOTE: |
| 312 | quotelevel++; |
| 313 | tputc('"', shf); |
| 314 | break; |
| 315 | case CQUOTE: |
| 316 | if (quotelevel) |
| 317 | quotelevel--; |
| 318 | tputc('"', shf); |
| 319 | break; |
| 320 | case OSUBST: |
| 321 | tputc('$', shf); |
| 322 | if (*wp++ == '{') |
| 323 | tputc('{', shf); |
| 324 | while ((c = *wp++) != 0) |
| 325 | tputC(c, shf); |
| 326 | break; |
| 327 | case CSUBST: |
| 328 | if (*wp++ == '}') |
| 329 | tputc('}', shf); |
| 330 | break; |
| 331 | case OPAT: |
| 332 | tputc(*wp++, shf); |
| 333 | tputc('(', shf); |
| 334 | break; |
| 335 | case SPAT: |
| 336 | tputc('|', shf); |
| 337 | break; |
| 338 | case CPAT: |
| 339 | tputc(')', shf); |
| 340 | break; |
| 341 | } |
| 342 | } |
| 343 | |
| 344 | /* |
| 345 | * this is the _only_ way to reliably handle |
| 346 | * variable args with an ANSI compiler |
| 347 | */ |
| 348 | /* VARARGS */ |
| 349 | int |
| 350 | fptreef(struct shf *shf, int indent, const char *fmt, ...) |
| 351 | { |
| 352 | va_list va; |
| 353 | |
| 354 | va_start(va, fmt); |
| 355 | |
| 356 | vfptreef(shf, indent, fmt, va); |
| 357 | va_end(va); |
| 358 | return (0); |
| 359 | } |
| 360 | |
| 361 | /* VARARGS */ |
| 362 | char * |
| 363 | snptreef(char *s, int n, const char *fmt, ...) |
| 364 | { |
| 365 | va_list va; |
| 366 | struct shf shf; |
| 367 | |
| 368 | shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf); |
| 369 | |
| 370 | va_start(va, fmt); |
| 371 | vfptreef(&shf, 0, fmt, va); |
| 372 | va_end(va); |
| 373 | |
| 374 | return (shf_sclose(&shf)); /* null terminates */ |
| 375 | } |
| 376 | |
| 377 | static void |
| 378 | vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) |
| 379 | { |
| 380 | int c; |
| 381 | |
| 382 | while ((c = *fmt++)) { |
| 383 | if (c == '%') { |
| 384 | switch ((c = *fmt++)) { |
| 385 | case 'c': |
| 386 | tputc(va_arg(va, int), shf); |
| 387 | break; |
| 388 | case 's': |
| 389 | shf_puts(va_arg(va, char *), shf); |
| 390 | break; |
| 391 | case 'S': /* word */ |
| 392 | tputS(va_arg(va, char *), shf); |
| 393 | break; |
| 394 | case 'd': /* decimal */ |
| 395 | shf_fprintf(shf, "%d", va_arg(va, int)); |
| 396 | break; |
| 397 | case 'u': /* decimal */ |
| 398 | shf_fprintf(shf, "%u", va_arg(va, unsigned int)); |
| 399 | break; |
| 400 | case 'T': /* format tree */ |
| 401 | ptree(va_arg(va, struct op *), indent, shf); |
| 402 | break; |
| 403 | case ';': /* newline or ; */ |
| 404 | case 'N': /* newline or space */ |
| 405 | if (shf->flags & SHF_STRING) { |
| 406 | if (c == ';') |
| 407 | tputc(';', shf); |
| 408 | tputc(' ', shf); |
| 409 | } else { |
| 410 | int i; |
| 411 | |
| 412 | tputc('\n', shf); |
| 413 | for (i = indent; i >= 8; i -= 8) |
| 414 | tputc('\t', shf); |
| 415 | for (; i > 0; --i) |
| 416 | tputc(' ', shf); |
| 417 | } |
| 418 | break; |
| 419 | case 'R': |
| 420 | pioact(shf, indent, va_arg(va, struct ioword *)); |
| 421 | break; |
| 422 | default: |
| 423 | tputc(c, shf); |
| 424 | break; |
| 425 | } |
| 426 | } else |
| 427 | tputc(c, shf); |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | /* |
| 432 | * copy tree (for function definition) |
| 433 | */ |
| 434 | struct op * |
| 435 | tcopy(struct op *t, Area *ap) |
| 436 | { |
| 437 | struct op *r; |
| 438 | const char **tw; |
| 439 | char **rw; |
| 440 | |
| 441 | if (t == NULL) |
| 442 | return (NULL); |
| 443 | |
| 444 | r = alloc(sizeof(struct op), ap); |
| 445 | |
| 446 | r->type = t->type; |
| 447 | r->u.evalflags = t->u.evalflags; |
| 448 | |
| 449 | if (t->type == TCASE) |
| 450 | r->str = wdcopy(t->str, ap); |
| 451 | else |
| 452 | strdupx(r->str, t->str, ap); |
| 453 | |
| 454 | if (t->vars == NULL) |
| 455 | r->vars = NULL; |
| 456 | else { |
| 457 | for (tw = (const char **)t->vars; *tw++ != NULL; ) |
| 458 | ; |
| 459 | rw = r->vars = alloc((tw - (const char **)t->vars + 1) * |
| 460 | sizeof(*tw), ap); |
| 461 | for (tw = (const char **)t->vars; *tw != NULL; ) |
| 462 | *rw++ = wdcopy(*tw++, ap); |
| 463 | *rw = NULL; |
| 464 | } |
| 465 | |
| 466 | if (t->args == NULL) |
| 467 | r->args = NULL; |
| 468 | else { |
| 469 | for (tw = t->args; *tw++ != NULL; ) |
| 470 | ; |
| 471 | r->args = (const char **)(rw = alloc((tw - t->args + 1) * |
| 472 | sizeof(*tw), ap)); |
| 473 | for (tw = t->args; *tw != NULL; ) |
| 474 | *rw++ = wdcopy(*tw++, ap); |
| 475 | *rw = NULL; |
| 476 | } |
| 477 | |
| 478 | r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap); |
| 479 | |
| 480 | r->left = tcopy(t->left, ap); |
| 481 | r->right = tcopy(t->right, ap); |
| 482 | r->lineno = t->lineno; |
| 483 | |
| 484 | return (r); |
| 485 | } |
| 486 | |
| 487 | char * |
| 488 | wdcopy(const char *wp, Area *ap) |
| 489 | { |
| 490 | size_t len = wdscan(wp, EOS) - wp; |
| 491 | return (memcpy(alloc(len, ap), wp, len)); |
| 492 | } |
| 493 | |
| 494 | /* return the position of prefix c in wp plus 1 */ |
| 495 | const char * |
| 496 | wdscan(const char *wp, int c) |
| 497 | { |
| 498 | int nest = 0; |
| 499 | |
| 500 | while (1) |
| 501 | switch (*wp++) { |
| 502 | case EOS: |
| 503 | return (wp); |
| 504 | case ADELIM: |
| 505 | if (c == ADELIM) |
| 506 | return (wp + 1); |
| 507 | /* FALLTHROUGH */ |
| 508 | case CHAR: |
| 509 | case QCHAR: |
| 510 | wp++; |
| 511 | break; |
| 512 | case COMSUB: |
| 513 | case EXPRSUB: |
| 514 | while (*wp++ != 0) |
| 515 | ; |
| 516 | break; |
| 517 | case OQUOTE: |
| 518 | case CQUOTE: |
| 519 | break; |
| 520 | case OSUBST: |
| 521 | nest++; |
| 522 | while (*wp++ != '\0') |
| 523 | ; |
| 524 | break; |
| 525 | case CSUBST: |
| 526 | wp++; |
| 527 | if (c == CSUBST && nest == 0) |
| 528 | return (wp); |
| 529 | nest--; |
| 530 | break; |
| 531 | case OPAT: |
| 532 | nest++; |
| 533 | wp++; |
| 534 | break; |
| 535 | case SPAT: |
| 536 | case CPAT: |
| 537 | if (c == wp[-1] && nest == 0) |
| 538 | return (wp); |
| 539 | if (wp[-1] == CPAT) |
| 540 | nest--; |
| 541 | break; |
| 542 | default: |
| 543 | internal_warningf( |
| 544 | "wdscan: unknown char 0x%x (carrying on)", |
| 545 | wp[-1]); |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | /* return a copy of wp without any of the mark up characters and |
| 550 | * with quote characters (" ' \) stripped. |
| 551 | * (string is allocated from ATEMP) |
| 552 | */ |
| 553 | char * |
| 554 | wdstrip(const char *wp, bool keepq, bool make_magic) |
| 555 | { |
| 556 | struct shf shf; |
| 557 | int c; |
| 558 | |
| 559 | shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf); |
| 560 | |
| 561 | /* problems: |
| 562 | * `...` -> $(...) |
| 563 | * x${foo:-"hi"} -> x${foo:-hi} |
| 564 | * x${foo:-'hi'} -> x${foo:-hi} unless keepq |
| 565 | */ |
| 566 | while (1) |
| 567 | switch (*wp++) { |
| 568 | case EOS: |
| 569 | return (shf_sclose(&shf)); /* null terminates */ |
| 570 | case ADELIM: |
| 571 | case CHAR: |
| 572 | c = *wp++; |
| 573 | if (make_magic && (ISMAGIC(c) || c == '[' || c == NOT || |
| 574 | c == '-' || c == ']' || c == '*' || c == '?')) |
| 575 | shf_putchar(MAGIC, &shf); |
| 576 | shf_putchar(c, &shf); |
| 577 | break; |
| 578 | case QCHAR: |
| 579 | c = *wp++; |
| 580 | if (keepq && (c == '"' || c == '`' || c == '$' || c == '\\')) |
| 581 | shf_putchar('\\', &shf); |
| 582 | shf_putchar(c, &shf); |
| 583 | break; |
| 584 | case COMSUB: |
| 585 | shf_puts("$(", &shf); |
| 586 | while (*wp != 0) |
| 587 | shf_putchar(*wp++, &shf); |
| 588 | shf_putchar(')', &shf); |
| 589 | break; |
| 590 | case EXPRSUB: |
| 591 | shf_puts("$((", &shf); |
| 592 | while (*wp != 0) |
| 593 | shf_putchar(*wp++, &shf); |
| 594 | shf_puts("))", &shf); |
| 595 | break; |
| 596 | case OQUOTE: |
| 597 | break; |
| 598 | case CQUOTE: |
| 599 | break; |
| 600 | case OSUBST: |
| 601 | shf_putchar('$', &shf); |
| 602 | if (*wp++ == '{') |
| 603 | shf_putchar('{', &shf); |
| 604 | while ((c = *wp++) != 0) |
| 605 | shf_putchar(c, &shf); |
| 606 | break; |
| 607 | case CSUBST: |
| 608 | if (*wp++ == '}') |
| 609 | shf_putchar('}', &shf); |
| 610 | break; |
| 611 | case OPAT: |
| 612 | if (make_magic) { |
| 613 | shf_putchar(MAGIC, &shf); |
| 614 | shf_putchar(*wp++ | 0x80, &shf); |
| 615 | } else { |
| 616 | shf_putchar(*wp++, &shf); |
| 617 | shf_putchar('(', &shf); |
| 618 | } |
| 619 | break; |
| 620 | case SPAT: |
| 621 | if (make_magic) |
| 622 | shf_putchar(MAGIC, &shf); |
| 623 | shf_putchar('|', &shf); |
| 624 | break; |
| 625 | case CPAT: |
| 626 | if (make_magic) |
| 627 | shf_putchar(MAGIC, &shf); |
| 628 | shf_putchar(')', &shf); |
| 629 | break; |
| 630 | } |
| 631 | } |
| 632 | |
| 633 | static struct ioword ** |
| 634 | iocopy(struct ioword **iow, Area *ap) |
| 635 | { |
| 636 | struct ioword **ior; |
| 637 | int i; |
| 638 | |
| 639 | for (ior = iow; *ior++ != NULL; ) |
| 640 | ; |
| 641 | ior = alloc((ior - iow + 1) * sizeof(struct ioword *), ap); |
| 642 | |
| 643 | for (i = 0; iow[i] != NULL; i++) { |
| 644 | struct ioword *p, *q; |
| 645 | |
| 646 | p = iow[i]; |
| 647 | q = alloc(sizeof(struct ioword), ap); |
| 648 | ior[i] = q; |
| 649 | *q = *p; |
| 650 | if (p->name != NULL) |
| 651 | q->name = wdcopy(p->name, ap); |
| 652 | if (p->delim != NULL) |
| 653 | q->delim = wdcopy(p->delim, ap); |
| 654 | if (p->heredoc != NULL) |
| 655 | strdupx(q->heredoc, p->heredoc, ap); |
| 656 | } |
| 657 | ior[i] = NULL; |
| 658 | |
| 659 | return (ior); |
| 660 | } |
| 661 | |
| 662 | /* |
| 663 | * free tree (for function definition) |
| 664 | */ |
| 665 | void |
| 666 | tfree(struct op *t, Area *ap) |
| 667 | { |
| 668 | char **w; |
| 669 | |
| 670 | if (t == NULL) |
| 671 | return; |
| 672 | |
| 673 | if (t->str != NULL) |
| 674 | afree(t->str, ap); |
| 675 | |
| 676 | if (t->vars != NULL) { |
| 677 | for (w = t->vars; *w != NULL; w++) |
| 678 | afree(*w, ap); |
| 679 | afree(t->vars, ap); |
| 680 | } |
| 681 | |
| 682 | if (t->args != NULL) { |
| 683 | union mksh_ccphack cw; |
| 684 | /* XXX we assume the caller is right */ |
| 685 | cw.ro = t->args; |
| 686 | for (w = cw.rw; *w != NULL; w++) |
| 687 | afree(*w, ap); |
| 688 | afree(t->args, ap); |
| 689 | } |
| 690 | |
| 691 | if (t->ioact != NULL) |
| 692 | iofree(t->ioact, ap); |
| 693 | |
| 694 | tfree(t->left, ap); |
| 695 | tfree(t->right, ap); |
| 696 | |
| 697 | afree(t, ap); |
| 698 | } |
| 699 | |
| 700 | static void |
| 701 | iofree(struct ioword **iow, Area *ap) |
| 702 | { |
| 703 | struct ioword **iop; |
| 704 | struct ioword *p; |
| 705 | |
| 706 | for (iop = iow; (p = *iop++) != NULL; ) { |
| 707 | if (p->name != NULL) |
| 708 | afree(p->name, ap); |
| 709 | if (p->delim != NULL) |
| 710 | afree(p->delim, ap); |
| 711 | if (p->heredoc != NULL) |
| 712 | afree(p->heredoc, ap); |
| 713 | afree(p, ap); |
| 714 | } |
| 715 | afree(iow, ap); |
| 716 | } |