1*517d3880Stobias /* $OpenBSD: tree.c,v 1.34 2018/04/09 17:53:36 tobias Exp $ */
27cb960a2Sdownsj
37cb960a2Sdownsj /*
47cb960a2Sdownsj * command tree climbing
57cb960a2Sdownsj */
67cb960a2Sdownsj
756018212Smmcc #include <string.h>
856018212Smmcc
97cb960a2Sdownsj #include "sh.h"
107cb960a2Sdownsj
117cb960a2Sdownsj #define INDENT 4
127cb960a2Sdownsj
137cb960a2Sdownsj #define tputc(c, shf) shf_putchar(c, shf);
14c5d5393cSotto static void ptree(struct op *, int, struct shf *);
15c5d5393cSotto static void pioact(struct shf *, int, struct ioword *);
16c5d5393cSotto static void tputC(int, struct shf *);
17c5d5393cSotto static void tputS(char *, struct shf *);
18c5d5393cSotto static void vfptreef(struct shf *, int, const char *, va_list);
19c5d5393cSotto static struct ioword **iocopy(struct ioword **, Area *);
20c5d5393cSotto static void iofree(struct ioword **, Area *);
217cb960a2Sdownsj
227cb960a2Sdownsj /*
237cb960a2Sdownsj * print a command tree
247cb960a2Sdownsj */
257cb960a2Sdownsj
267cb960a2Sdownsj static void
ptree(struct op * t,int indent,struct shf * shf)27c5d5393cSotto ptree(struct op *t, int indent, struct shf *shf)
287cb960a2Sdownsj {
297894b443Smillert char **w;
307cb960a2Sdownsj struct ioword **ioact;
317cb960a2Sdownsj struct op *t1;
327cb960a2Sdownsj
337cb960a2Sdownsj Chain:
347cb960a2Sdownsj if (t == NULL)
357cb960a2Sdownsj return;
367cb960a2Sdownsj switch (t->type) {
377cb960a2Sdownsj case TCOM:
387cb960a2Sdownsj if (t->vars)
397cb960a2Sdownsj for (w = t->vars; *w != NULL; )
407cb960a2Sdownsj fptreef(shf, indent, "%S ", *w++);
417cb960a2Sdownsj else
427cb960a2Sdownsj fptreef(shf, indent, "#no-vars# ");
437cb960a2Sdownsj if (t->args)
447cb960a2Sdownsj for (w = t->args; *w != NULL; )
457cb960a2Sdownsj fptreef(shf, indent, "%S ", *w++);
467cb960a2Sdownsj else
477cb960a2Sdownsj fptreef(shf, indent, "#no-args# ");
487cb960a2Sdownsj break;
497cb960a2Sdownsj case TEXEC:
507cb960a2Sdownsj t = t->left;
517cb960a2Sdownsj goto Chain;
527cb960a2Sdownsj case TPAREN:
537cb960a2Sdownsj fptreef(shf, indent + 2, "( %T) ", t->left);
547cb960a2Sdownsj break;
557cb960a2Sdownsj case TPIPE:
567cb960a2Sdownsj fptreef(shf, indent, "%T| ", t->left);
577cb960a2Sdownsj t = t->right;
587cb960a2Sdownsj goto Chain;
597cb960a2Sdownsj case TLIST:
607cb960a2Sdownsj fptreef(shf, indent, "%T%;", t->left);
617cb960a2Sdownsj t = t->right;
627cb960a2Sdownsj goto Chain;
637cb960a2Sdownsj case TOR:
647cb960a2Sdownsj case TAND:
657cb960a2Sdownsj fptreef(shf, indent, "%T%s %T",
667cb960a2Sdownsj t->left, (t->type==TOR) ? "||" : "&&", t->right);
677cb960a2Sdownsj break;
687cb960a2Sdownsj case TBANG:
697cb960a2Sdownsj fptreef(shf, indent, "! ");
707cb960a2Sdownsj t = t->right;
717cb960a2Sdownsj goto Chain;
727cb960a2Sdownsj case TDBRACKET:
737cb960a2Sdownsj {
747cb960a2Sdownsj int i;
757cb960a2Sdownsj
767cb960a2Sdownsj fptreef(shf, indent, "[[");
777cb960a2Sdownsj for (i = 0; t->args[i]; i++)
787cb960a2Sdownsj fptreef(shf, indent, " %S", t->args[i]);
797cb960a2Sdownsj fptreef(shf, indent, " ]] ");
807cb960a2Sdownsj break;
817cb960a2Sdownsj }
827cb960a2Sdownsj case TSELECT:
837cb960a2Sdownsj fptreef(shf, indent, "select %s ", t->str);
847eab881bSjaredy /* FALLTHROUGH */
857cb960a2Sdownsj case TFOR:
867cb960a2Sdownsj if (t->type == TFOR)
877cb960a2Sdownsj fptreef(shf, indent, "for %s ", t->str);
887cb960a2Sdownsj if (t->vars != NULL) {
897cb960a2Sdownsj fptreef(shf, indent, "in ");
907cb960a2Sdownsj for (w = t->vars; *w; )
917cb960a2Sdownsj fptreef(shf, indent, "%S ", *w++);
927cb960a2Sdownsj fptreef(shf, indent, "%;");
937cb960a2Sdownsj }
947cb960a2Sdownsj fptreef(shf, indent + INDENT, "do%N%T", t->left);
957cb960a2Sdownsj fptreef(shf, indent, "%;done ");
967cb960a2Sdownsj break;
977cb960a2Sdownsj case TCASE:
987cb960a2Sdownsj fptreef(shf, indent, "case %S in", t->str);
997cb960a2Sdownsj for (t1 = t->left; t1 != NULL; t1 = t1->right) {
1007cb960a2Sdownsj fptreef(shf, indent, "%N(");
1017cb960a2Sdownsj for (w = t1->vars; *w != NULL; w++)
1027cb960a2Sdownsj fptreef(shf, indent, "%S%c", *w,
1037cb960a2Sdownsj (w[1] != NULL) ? '|' : ')');
1047cb960a2Sdownsj fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);
1057cb960a2Sdownsj }
1067cb960a2Sdownsj fptreef(shf, indent, "%Nesac ");
1077cb960a2Sdownsj break;
1087cb960a2Sdownsj case TIF:
1097cb960a2Sdownsj case TELIF:
1107cb960a2Sdownsj /* 3 == strlen("if ") */
1117cb960a2Sdownsj fptreef(shf, indent + 3, "if %T", t->left);
1127cb960a2Sdownsj for (;;) {
1137cb960a2Sdownsj t = t->right;
1147cb960a2Sdownsj if (t->left != NULL) {
1157cb960a2Sdownsj fptreef(shf, indent, "%;");
1167cb960a2Sdownsj fptreef(shf, indent + INDENT, "then%N%T",
1177cb960a2Sdownsj t->left);
1187cb960a2Sdownsj }
1197cb960a2Sdownsj if (t->right == NULL || t->right->type != TELIF)
1207cb960a2Sdownsj break;
1217cb960a2Sdownsj t = t->right;
1227cb960a2Sdownsj fptreef(shf, indent, "%;");
1237cb960a2Sdownsj /* 5 == strlen("elif ") */
1247cb960a2Sdownsj fptreef(shf, indent + 5, "elif %T", t->left);
1257cb960a2Sdownsj }
1267cb960a2Sdownsj if (t->right != NULL) {
1277cb960a2Sdownsj fptreef(shf, indent, "%;");
1287cb960a2Sdownsj fptreef(shf, indent + INDENT, "else%;%T", t->right);
1297cb960a2Sdownsj }
1307cb960a2Sdownsj fptreef(shf, indent, "%;fi ");
1317cb960a2Sdownsj break;
1327cb960a2Sdownsj case TWHILE:
1337cb960a2Sdownsj case TUNTIL:
1347cb960a2Sdownsj /* 6 == strlen("while"/"until") */
1357cb960a2Sdownsj fptreef(shf, indent + 6, "%s %T",
1367cb960a2Sdownsj (t->type==TWHILE) ? "while" : "until",
1377cb960a2Sdownsj t->left);
1387cb960a2Sdownsj fptreef(shf, indent, "%;do");
1397cb960a2Sdownsj fptreef(shf, indent + INDENT, "%;%T", t->right);
1407cb960a2Sdownsj fptreef(shf, indent, "%;done ");
1417cb960a2Sdownsj break;
1427cb960a2Sdownsj case TBRACE:
1437cb960a2Sdownsj fptreef(shf, indent + INDENT, "{%;%T", t->left);
1447cb960a2Sdownsj fptreef(shf, indent, "%;} ");
1457cb960a2Sdownsj break;
1467cb960a2Sdownsj case TCOPROC:
1477cb960a2Sdownsj fptreef(shf, indent, "%T|& ", t->left);
1487cb960a2Sdownsj break;
1497cb960a2Sdownsj case TASYNC:
1507cb960a2Sdownsj fptreef(shf, indent, "%T& ", t->left);
1517cb960a2Sdownsj break;
1527cb960a2Sdownsj case TFUNCT:
1533b015934Smillert fptreef(shf, indent,
1543b015934Smillert t->u.ksh_func ? "function %s %T" : "%s() %T",
1553b015934Smillert t->str, t->left);
1567cb960a2Sdownsj break;
1577cb960a2Sdownsj case TTIME:
1587cb960a2Sdownsj fptreef(shf, indent, "time %T", t->left);
1597cb960a2Sdownsj break;
1607cb960a2Sdownsj default:
1617cb960a2Sdownsj fptreef(shf, indent, "<botch>");
1627cb960a2Sdownsj break;
1637cb960a2Sdownsj }
1647cb960a2Sdownsj if ((ioact = t->ioact) != NULL) {
1657cb960a2Sdownsj int need_nl = 0;
1667cb960a2Sdownsj
1677cb960a2Sdownsj while (*ioact != NULL)
1687cb960a2Sdownsj pioact(shf, indent, *ioact++);
1697cb960a2Sdownsj /* Print here documents after everything else... */
1707cb960a2Sdownsj for (ioact = t->ioact; *ioact != NULL; ) {
1717cb960a2Sdownsj struct ioword *iop = *ioact++;
1727cb960a2Sdownsj
173f00c5086Smillert /* heredoc is 0 when tracing (set -x) */
174f00c5086Smillert if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) {
1757cb960a2Sdownsj tputc('\n', shf);
176f00c5086Smillert shf_puts(iop->heredoc, shf);
177f00c5086Smillert fptreef(shf, indent, "%s",
178f00c5086Smillert evalstr(iop->delim, 0));
1797cb960a2Sdownsj need_nl = 1;
1807cb960a2Sdownsj }
1817cb960a2Sdownsj }
1827cb960a2Sdownsj /* Last delimiter must be followed by a newline (this often
1837cb960a2Sdownsj * leads to an extra blank line, but its not worth worrying
1847cb960a2Sdownsj * about)
1857cb960a2Sdownsj */
1867cb960a2Sdownsj if (need_nl)
1877cb960a2Sdownsj tputc('\n', shf);
1887cb960a2Sdownsj }
1897cb960a2Sdownsj }
1907cb960a2Sdownsj
1917cb960a2Sdownsj static void
pioact(struct shf * shf,int indent,struct ioword * iop)192c5d5393cSotto pioact(struct shf *shf, int indent, struct ioword *iop)
1937cb960a2Sdownsj {
1947cb960a2Sdownsj int flag = iop->flag;
1957cb960a2Sdownsj int type = flag & IOTYPE;
1967cb960a2Sdownsj int expected;
1977cb960a2Sdownsj
1987a8124d8Sderaadt expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
1997a8124d8Sderaadt (type == IOCAT || type == IOWRITE) ? 1 :
2007a8124d8Sderaadt (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
2017a8124d8Sderaadt iop->unit + 1;
2027cb960a2Sdownsj if (iop->unit != expected)
2037cb960a2Sdownsj tputc('0' + iop->unit, shf);
2047cb960a2Sdownsj
2057cb960a2Sdownsj switch (type) {
2067cb960a2Sdownsj case IOREAD:
2077cb960a2Sdownsj fptreef(shf, indent, "< ");
2087cb960a2Sdownsj break;
2097cb960a2Sdownsj case IOHERE:
2107cb960a2Sdownsj if (flag&IOSKIP)
2117cb960a2Sdownsj fptreef(shf, indent, "<<- ");
2127cb960a2Sdownsj else
2137cb960a2Sdownsj fptreef(shf, indent, "<< ");
2147cb960a2Sdownsj break;
2157cb960a2Sdownsj case IOCAT:
2167cb960a2Sdownsj fptreef(shf, indent, ">> ");
2177cb960a2Sdownsj break;
2187cb960a2Sdownsj case IOWRITE:
2197cb960a2Sdownsj if (flag&IOCLOB)
2207cb960a2Sdownsj fptreef(shf, indent, ">| ");
2217cb960a2Sdownsj else
2227cb960a2Sdownsj fptreef(shf, indent, "> ");
2237cb960a2Sdownsj break;
2247cb960a2Sdownsj case IORDWR:
2257cb960a2Sdownsj fptreef(shf, indent, "<> ");
2267cb960a2Sdownsj break;
2277cb960a2Sdownsj case IODUP:
2287cb960a2Sdownsj if (flag & IORDUP)
2297cb960a2Sdownsj fptreef(shf, indent, "<&");
2307cb960a2Sdownsj else
2317cb960a2Sdownsj fptreef(shf, indent, ">&");
2327cb960a2Sdownsj break;
2337cb960a2Sdownsj }
2347cb960a2Sdownsj /* name/delim are 0 when printing syntax errors */
2357cb960a2Sdownsj if (type == IOHERE) {
2367cb960a2Sdownsj if (iop->delim)
2377cb960a2Sdownsj fptreef(shf, indent, "%S ", iop->delim);
2387cb960a2Sdownsj } else if (iop->name)
2397cb960a2Sdownsj fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
2407cb960a2Sdownsj iop->name);
2417cb960a2Sdownsj }
2427cb960a2Sdownsj
2437cb960a2Sdownsj
2447cb960a2Sdownsj /*
2457cb960a2Sdownsj * variants of fputc, fputs for ptreef and snptreef
2467cb960a2Sdownsj */
2477cb960a2Sdownsj
2487cb960a2Sdownsj static void
tputC(int c,struct shf * shf)249c5d5393cSotto tputC(int c, struct shf *shf)
2507cb960a2Sdownsj {
2517cb960a2Sdownsj if ((c&0x60) == 0) { /* C0|C1 */
2527cb960a2Sdownsj tputc((c&0x80) ? '$' : '^', shf);
2537cb960a2Sdownsj tputc(((c&0x7F)|0x40), shf);
2547cb960a2Sdownsj } else if ((c&0x7F) == 0x7F) { /* DEL */
2557cb960a2Sdownsj tputc((c&0x80) ? '$' : '^', shf);
2567cb960a2Sdownsj tputc('?', shf);
2577cb960a2Sdownsj } else
2587cb960a2Sdownsj tputc(c, shf);
2597cb960a2Sdownsj }
2607cb960a2Sdownsj
2617cb960a2Sdownsj static void
tputS(char * wp,struct shf * shf)262c5d5393cSotto tputS(char *wp, struct shf *shf)
2637cb960a2Sdownsj {
2647894b443Smillert int c, quoted=0;
2657cb960a2Sdownsj
2663b015934Smillert /* problems:
2673b015934Smillert * `...` -> $(...)
2683b015934Smillert * 'foo' -> "foo"
2693b015934Smillert * could change encoding to:
2703b015934Smillert * OQUOTE ["'] ... CQUOTE ["']
2713b015934Smillert * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
2723b015934Smillert */
2737cb960a2Sdownsj while (1)
2747cb960a2Sdownsj switch ((c = *wp++)) {
2757cb960a2Sdownsj case EOS:
2767cb960a2Sdownsj return;
2777cb960a2Sdownsj case CHAR:
2787cb960a2Sdownsj tputC(*wp++, shf);
2797cb960a2Sdownsj break;
2807cb960a2Sdownsj case QCHAR:
2817cb960a2Sdownsj c = *wp++;
2827cb960a2Sdownsj if (!quoted || (c == '"' || c == '`' || c == '$'))
2837cb960a2Sdownsj tputc('\\', shf);
2847cb960a2Sdownsj tputC(c, shf);
2857cb960a2Sdownsj break;
2867cb960a2Sdownsj case COMSUB:
2877cb960a2Sdownsj tputc('$', shf);
2887cb960a2Sdownsj tputc('(', shf);
2897cb960a2Sdownsj while (*wp != 0)
2907cb960a2Sdownsj tputC(*wp++, shf);
2917cb960a2Sdownsj tputc(')', shf);
292040161f7Smillert wp++;
2937cb960a2Sdownsj break;
2947cb960a2Sdownsj case EXPRSUB:
2957cb960a2Sdownsj tputc('$', shf);
2967cb960a2Sdownsj tputc('(', shf);
2977cb960a2Sdownsj tputc('(', shf);
2987cb960a2Sdownsj while (*wp != 0)
2997cb960a2Sdownsj tputC(*wp++, shf);
3007cb960a2Sdownsj tputc(')', shf);
3017cb960a2Sdownsj tputc(')', shf);
302040161f7Smillert wp++;
3037cb960a2Sdownsj break;
3047cb960a2Sdownsj case OQUOTE:
3057cb960a2Sdownsj quoted = 1;
3067cb960a2Sdownsj tputc('"', shf);
3077cb960a2Sdownsj break;
3087cb960a2Sdownsj case CQUOTE:
3097cb960a2Sdownsj quoted = 0;
3107cb960a2Sdownsj tputc('"', shf);
3117cb960a2Sdownsj break;
3127cb960a2Sdownsj case OSUBST:
3137cb960a2Sdownsj tputc('$', shf);
3143b015934Smillert if (*wp++ == '{')
3157cb960a2Sdownsj tputc('{', shf);
3167cb960a2Sdownsj while ((c = *wp++) != 0)
3177cb960a2Sdownsj tputC(c, shf);
3187cb960a2Sdownsj break;
3197cb960a2Sdownsj case CSUBST:
3203b015934Smillert if (*wp++ == '}')
3217cb960a2Sdownsj tputc('}', shf);
3227cb960a2Sdownsj break;
3237cb960a2Sdownsj case OPAT:
3247cb960a2Sdownsj tputc(*wp++, shf);
3257cb960a2Sdownsj tputc('(', shf);
3267cb960a2Sdownsj break;
3277cb960a2Sdownsj case SPAT:
3287cb960a2Sdownsj tputc('|', shf);
3297cb960a2Sdownsj break;
3307cb960a2Sdownsj case CPAT:
3317cb960a2Sdownsj tputc(')', shf);
3327cb960a2Sdownsj break;
3337cb960a2Sdownsj }
3347cb960a2Sdownsj }
3357cb960a2Sdownsj
336dde5a284Sotto void
fptreef(struct shf * shf,int indent,const char * fmt,...)3377cb960a2Sdownsj fptreef(struct shf *shf, int indent, const char *fmt, ...)
3387cb960a2Sdownsj {
3397cb960a2Sdownsj va_list va;
3407cb960a2Sdownsj
34169b9f96bSmillert va_start(va, fmt);
3427cb960a2Sdownsj vfptreef(shf, indent, fmt, va);
3437cb960a2Sdownsj va_end(va);
3447cb960a2Sdownsj }
3457cb960a2Sdownsj
3467cb960a2Sdownsj char *
snptreef(char * s,int n,const char * fmt,...)3477cb960a2Sdownsj snptreef(char *s, int n, const char *fmt, ...)
3487cb960a2Sdownsj {
3497cb960a2Sdownsj va_list va;
3507cb960a2Sdownsj struct shf shf;
3517cb960a2Sdownsj
3527cb960a2Sdownsj shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
3537cb960a2Sdownsj
35469b9f96bSmillert va_start(va, fmt);
3557cb960a2Sdownsj vfptreef(&shf, 0, fmt, va);
3567cb960a2Sdownsj va_end(va);
3577cb960a2Sdownsj
3587cb960a2Sdownsj return shf_sclose(&shf); /* null terminates */
3597cb960a2Sdownsj }
3607cb960a2Sdownsj
3617cb960a2Sdownsj static void
vfptreef(struct shf * shf,int indent,const char * fmt,va_list va)362c5d5393cSotto vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
3637cb960a2Sdownsj {
3647894b443Smillert int c;
3657cb960a2Sdownsj
3667a8124d8Sderaadt while ((c = *fmt++)) {
3677cb960a2Sdownsj if (c == '%') {
368*517d3880Stobias int64_t n;
3697894b443Smillert char *p;
3707cb960a2Sdownsj int neg;
3717cb960a2Sdownsj
3727cb960a2Sdownsj switch ((c = *fmt++)) {
3737cb960a2Sdownsj case 'c':
3747cb960a2Sdownsj tputc(va_arg(va, int), shf);
3757cb960a2Sdownsj break;
3764c503bcdSmillert case 'd': /* decimal */
3774c503bcdSmillert n = va_arg(va, int);
3784c503bcdSmillert neg = n < 0;
379*517d3880Stobias p = u64ton(neg ? -n : n, 10);
3804c503bcdSmillert if (neg)
3814c503bcdSmillert *--p = '-';
3824c503bcdSmillert while (*p)
3834c503bcdSmillert tputc(*p++, shf);
3844c503bcdSmillert break;
3857cb960a2Sdownsj case 's':
3867cb960a2Sdownsj p = va_arg(va, char *);
3877cb960a2Sdownsj while (*p)
3887cb960a2Sdownsj tputc(*p++, shf);
3897cb960a2Sdownsj break;
3907cb960a2Sdownsj case 'S': /* word */
3917cb960a2Sdownsj p = va_arg(va, char *);
3927cb960a2Sdownsj tputS(p, shf);
3937cb960a2Sdownsj break;
3944c503bcdSmillert case 'u': /* unsigned decimal */
395*517d3880Stobias p = u64ton(va_arg(va, unsigned int), 10);
3967cb960a2Sdownsj while (*p)
3977cb960a2Sdownsj tputc(*p++, shf);
3987cb960a2Sdownsj break;
3997cb960a2Sdownsj case 'T': /* format tree */
4007cb960a2Sdownsj ptree(va_arg(va, struct op *), indent, shf);
4017cb960a2Sdownsj break;
4027cb960a2Sdownsj case ';': /* newline or ; */
4037cb960a2Sdownsj case 'N': /* newline or space */
4047cb960a2Sdownsj if (shf->flags & SHF_STRING) {
4057cb960a2Sdownsj if (c == ';')
4067cb960a2Sdownsj tputc(';', shf);
4077cb960a2Sdownsj tputc(' ', shf);
4087cb960a2Sdownsj } else {
4097cb960a2Sdownsj int i;
4107cb960a2Sdownsj
4117cb960a2Sdownsj tputc('\n', shf);
4127cb960a2Sdownsj for (i = indent; i >= 8; i -= 8)
4137cb960a2Sdownsj tputc('\t', shf);
4147cb960a2Sdownsj for (; i > 0; --i)
4157cb960a2Sdownsj tputc(' ', shf);
4167cb960a2Sdownsj }
4177cb960a2Sdownsj break;
4187cb960a2Sdownsj case 'R':
4197cb960a2Sdownsj pioact(shf, indent, va_arg(va, struct ioword *));
4207cb960a2Sdownsj break;
4217cb960a2Sdownsj default:
4227cb960a2Sdownsj tputc(c, shf);
4237cb960a2Sdownsj break;
4247cb960a2Sdownsj }
4257cb960a2Sdownsj } else
4267cb960a2Sdownsj tputc(c, shf);
4277cb960a2Sdownsj }
4287a8124d8Sderaadt }
4297cb960a2Sdownsj
4307cb960a2Sdownsj /*
4317cb960a2Sdownsj * copy tree (for function definition)
4327cb960a2Sdownsj */
4337cb960a2Sdownsj
4347cb960a2Sdownsj struct op *
tcopy(struct op * t,Area * ap)435c5d5393cSotto tcopy(struct op *t, Area *ap)
4367cb960a2Sdownsj {
4377894b443Smillert struct op *r;
4387894b443Smillert char **tw, **rw;
4397cb960a2Sdownsj
4407cb960a2Sdownsj if (t == NULL)
4417cb960a2Sdownsj return NULL;
4427cb960a2Sdownsj
4438c046d24Snicm r = alloc(sizeof(struct op), ap);
4447cb960a2Sdownsj
4457cb960a2Sdownsj r->type = t->type;
446dcacb757Sdownsj r->u.evalflags = t->u.evalflags;
4477cb960a2Sdownsj
4487cb960a2Sdownsj r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap);
4497cb960a2Sdownsj
4507cb960a2Sdownsj if (t->vars == NULL)
4517cb960a2Sdownsj r->vars = NULL;
4527cb960a2Sdownsj else {
4537cb960a2Sdownsj for (tw = t->vars; *tw++ != NULL; )
4547cb960a2Sdownsj ;
455d67c3782Smmcc rw = r->vars = areallocarray(NULL, tw - t->vars + 1,
456d67c3782Smmcc sizeof(*tw), ap);
4577cb960a2Sdownsj for (tw = t->vars; *tw != NULL; )
4587cb960a2Sdownsj *rw++ = wdcopy(*tw++, ap);
4597cb960a2Sdownsj *rw = NULL;
4607cb960a2Sdownsj }
4617cb960a2Sdownsj
4627cb960a2Sdownsj if (t->args == NULL)
4637cb960a2Sdownsj r->args = NULL;
4647cb960a2Sdownsj else {
4657cb960a2Sdownsj for (tw = t->args; *tw++ != NULL; )
4667cb960a2Sdownsj ;
467d67c3782Smmcc rw = r->args = areallocarray(NULL, tw - t->args + 1,
468d67c3782Smmcc sizeof(*tw), ap);
4697cb960a2Sdownsj for (tw = t->args; *tw != NULL; )
4707cb960a2Sdownsj *rw++ = wdcopy(*tw++, ap);
4717cb960a2Sdownsj *rw = NULL;
4727cb960a2Sdownsj }
4737cb960a2Sdownsj
4747cb960a2Sdownsj r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
4757cb960a2Sdownsj
4767cb960a2Sdownsj r->left = tcopy(t->left, ap);
4777cb960a2Sdownsj r->right = tcopy(t->right, ap);
478f00c5086Smillert r->lineno = t->lineno;
4797cb960a2Sdownsj
4807cb960a2Sdownsj return r;
4817cb960a2Sdownsj }
4827cb960a2Sdownsj
4837cb960a2Sdownsj char *
wdcopy(const char * wp,Area * ap)484c5d5393cSotto wdcopy(const char *wp, Area *ap)
4857cb960a2Sdownsj {
4867cb960a2Sdownsj size_t len = wdscan(wp, EOS) - wp;
4877cb960a2Sdownsj return memcpy(alloc(len, ap), wp, len);
4887cb960a2Sdownsj }
4897cb960a2Sdownsj
4907cb960a2Sdownsj /* return the position of prefix c in wp plus 1 */
4917cb960a2Sdownsj char *
wdscan(const char * wp,int c)492c5d5393cSotto wdscan(const char *wp, int c)
4937cb960a2Sdownsj {
4947894b443Smillert int nest = 0;
4957cb960a2Sdownsj
4967cb960a2Sdownsj while (1)
4977cb960a2Sdownsj switch (*wp++) {
4987cb960a2Sdownsj case EOS:
4997cb960a2Sdownsj return (char *) wp;
5007cb960a2Sdownsj case CHAR:
5017cb960a2Sdownsj case QCHAR:
5027cb960a2Sdownsj wp++;
5037cb960a2Sdownsj break;
5047cb960a2Sdownsj case COMSUB:
5057cb960a2Sdownsj case EXPRSUB:
5067cb960a2Sdownsj while (*wp++ != 0)
5077cb960a2Sdownsj ;
5087cb960a2Sdownsj break;
5097cb960a2Sdownsj case OQUOTE:
5107cb960a2Sdownsj case CQUOTE:
5117cb960a2Sdownsj break;
5127cb960a2Sdownsj case OSUBST:
5137cb960a2Sdownsj nest++;
5147cb960a2Sdownsj while (*wp++ != '\0')
5157cb960a2Sdownsj ;
5167cb960a2Sdownsj break;
5177cb960a2Sdownsj case CSUBST:
5183b015934Smillert wp++;
5197cb960a2Sdownsj if (c == CSUBST && nest == 0)
5207cb960a2Sdownsj return (char *) wp;
5217cb960a2Sdownsj nest--;
5227cb960a2Sdownsj break;
5237cb960a2Sdownsj case OPAT:
5247cb960a2Sdownsj nest++;
5257cb960a2Sdownsj wp++;
5267cb960a2Sdownsj break;
5277cb960a2Sdownsj case SPAT:
5287cb960a2Sdownsj case CPAT:
5297cb960a2Sdownsj if (c == wp[-1] && nest == 0)
5307cb960a2Sdownsj return (char *) wp;
5317cb960a2Sdownsj if (wp[-1] == CPAT)
5327cb960a2Sdownsj nest--;
5337cb960a2Sdownsj break;
534f00c5086Smillert default:
5356c72b531Sjca internal_warningf(
53697445c82Santon "%s: unknown char 0x%x (carrying on)",
53797445c82Santon __func__, wp[-1]);
5387cb960a2Sdownsj }
5397cb960a2Sdownsj }
5407cb960a2Sdownsj
5413b015934Smillert /* return a copy of wp without any of the mark up characters and
5423b015934Smillert * with quote characters (" ' \) stripped.
5433b015934Smillert * (string is allocated from ATEMP)
5443b015934Smillert */
5453b015934Smillert char *
wdstrip(const char * wp)546c5d5393cSotto wdstrip(const char *wp)
5473b015934Smillert {
5483b015934Smillert struct shf shf;
5493b015934Smillert int c;
5503b015934Smillert
551355ffa75Stedu shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
5523b015934Smillert
5533b015934Smillert /* problems:
5543b015934Smillert * `...` -> $(...)
5553b015934Smillert * x${foo:-"hi"} -> x${foo:-hi}
5563b015934Smillert * x${foo:-'hi'} -> x${foo:-hi}
5573b015934Smillert */
5583b015934Smillert while (1)
5593b015934Smillert switch ((c = *wp++)) {
5603b015934Smillert case EOS:
5613b015934Smillert return shf_sclose(&shf); /* null terminates */
5623b015934Smillert case CHAR:
5633b015934Smillert case QCHAR:
5643b015934Smillert shf_putchar(*wp++, &shf);
5653b015934Smillert break;
5663b015934Smillert case COMSUB:
5673b015934Smillert shf_putchar('$', &shf);
5683b015934Smillert shf_putchar('(', &shf);
5693b015934Smillert while (*wp != 0)
5703b015934Smillert shf_putchar(*wp++, &shf);
5713b015934Smillert shf_putchar(')', &shf);
5723b015934Smillert break;
5733b015934Smillert case EXPRSUB:
5743b015934Smillert shf_putchar('$', &shf);
5753b015934Smillert shf_putchar('(', &shf);
5763b015934Smillert shf_putchar('(', &shf);
5773b015934Smillert while (*wp != 0)
5783b015934Smillert shf_putchar(*wp++, &shf);
5793b015934Smillert shf_putchar(')', &shf);
5803b015934Smillert shf_putchar(')', &shf);
5813b015934Smillert break;
5823b015934Smillert case OQUOTE:
5833b015934Smillert break;
5843b015934Smillert case CQUOTE:
5853b015934Smillert break;
5863b015934Smillert case OSUBST:
5873b015934Smillert shf_putchar('$', &shf);
5883b015934Smillert if (*wp++ == '{')
5893b015934Smillert shf_putchar('{', &shf);
5903b015934Smillert while ((c = *wp++) != 0)
5913b015934Smillert shf_putchar(c, &shf);
5923b015934Smillert break;
5933b015934Smillert case CSUBST:
5943b015934Smillert if (*wp++ == '}')
5953b015934Smillert shf_putchar('}', &shf);
5963b015934Smillert break;
5973b015934Smillert case OPAT:
5983b015934Smillert shf_putchar(*wp++, &shf);
5993b015934Smillert shf_putchar('(', &shf);
6003b015934Smillert break;
6013b015934Smillert case SPAT:
6023b015934Smillert shf_putchar('|', &shf);
6033b015934Smillert break;
6043b015934Smillert case CPAT:
6053b015934Smillert shf_putchar(')', &shf);
6063b015934Smillert break;
6073b015934Smillert }
6083b015934Smillert }
6093b015934Smillert
6107cb960a2Sdownsj static struct ioword **
iocopy(struct ioword ** iow,Area * ap)611c5d5393cSotto iocopy(struct ioword **iow, Area *ap)
6127cb960a2Sdownsj {
6137894b443Smillert struct ioword **ior;
6147894b443Smillert int i;
6157cb960a2Sdownsj
6167cb960a2Sdownsj for (ior = iow; *ior++ != NULL; )
6177cb960a2Sdownsj ;
618d67c3782Smmcc ior = areallocarray(NULL, ior - iow + 1, sizeof(*ior), ap);
6197cb960a2Sdownsj
6207cb960a2Sdownsj for (i = 0; iow[i] != NULL; i++) {
6217894b443Smillert struct ioword *p, *q;
6227cb960a2Sdownsj
6237cb960a2Sdownsj p = iow[i];
6248c046d24Snicm q = alloc(sizeof(*p), ap);
6257cb960a2Sdownsj ior[i] = q;
6267cb960a2Sdownsj *q = *p;
627355ffa75Stedu if (p->name != NULL)
6287cb960a2Sdownsj q->name = wdcopy(p->name, ap);
629355ffa75Stedu if (p->delim != NULL)
6307cb960a2Sdownsj q->delim = wdcopy(p->delim, ap);
631355ffa75Stedu if (p->heredoc != NULL)
632f00c5086Smillert q->heredoc = str_save(p->heredoc, ap);
6337cb960a2Sdownsj }
6347cb960a2Sdownsj ior[i] = NULL;
6357cb960a2Sdownsj
6367cb960a2Sdownsj return ior;
6377cb960a2Sdownsj }
6387cb960a2Sdownsj
6397cb960a2Sdownsj /*
6407cb960a2Sdownsj * free tree (for function definition)
6417cb960a2Sdownsj */
6427cb960a2Sdownsj
6437cb960a2Sdownsj void
tfree(struct op * t,Area * ap)644c5d5393cSotto tfree(struct op *t, Area *ap)
6457cb960a2Sdownsj {
6467894b443Smillert char **w;
6477cb960a2Sdownsj
6487cb960a2Sdownsj if (t == NULL)
6497cb960a2Sdownsj return;
6507cb960a2Sdownsj
651bfd561bcStedu afree(t->str, ap);
6527cb960a2Sdownsj
6537cb960a2Sdownsj if (t->vars != NULL) {
6547cb960a2Sdownsj for (w = t->vars; *w != NULL; w++)
655bfd561bcStedu afree(*w, ap);
656bfd561bcStedu afree(t->vars, ap);
6577cb960a2Sdownsj }
6587cb960a2Sdownsj
6597cb960a2Sdownsj if (t->args != NULL) {
6607cb960a2Sdownsj for (w = t->args; *w != NULL; w++)
661bfd561bcStedu afree(*w, ap);
662bfd561bcStedu afree(t->args, ap);
6637cb960a2Sdownsj }
6647cb960a2Sdownsj
6657cb960a2Sdownsj if (t->ioact != NULL)
6667cb960a2Sdownsj iofree(t->ioact, ap);
6677cb960a2Sdownsj
6687cb960a2Sdownsj tfree(t->left, ap);
6697cb960a2Sdownsj tfree(t->right, ap);
6707cb960a2Sdownsj
671bfd561bcStedu afree(t, ap);
6727cb960a2Sdownsj }
6737cb960a2Sdownsj
6747cb960a2Sdownsj static void
iofree(struct ioword ** iow,Area * ap)675c5d5393cSotto iofree(struct ioword **iow, Area *ap)
6767cb960a2Sdownsj {
6777894b443Smillert struct ioword **iop;
6787894b443Smillert struct ioword *p;
6797cb960a2Sdownsj
6807cb960a2Sdownsj for (iop = iow; (p = *iop++) != NULL; ) {
681bfd561bcStedu afree(p->name, ap);
682bfd561bcStedu afree(p->delim, ap);
683bfd561bcStedu afree(p->heredoc, ap);
684bfd561bcStedu afree(p, ap);
6857cb960a2Sdownsj }
6867b1fe930Sjaredy afree(iow, ap);
6877cb960a2Sdownsj }
688