diff options
author | John Ankarström <john@ankarstrom.se> | 2021-06-07 14:12:11 +0200 |
---|---|---|
committer | John Ankarström <john@ankarstrom.se> | 2021-06-07 14:12:11 +0200 |
commit | e2294b61e15781ca784a611e8ca7dabe132ebc6d (patch) | |
tree | c2a8cc44582534f52a76b1b8e64e6f83ffa501da /tree.c | |
download | ksh-e2294b61e15781ca784a611e8ca7dabe132ebc6d.tar.gz |
First commit (NetBSD 9.1)
Diffstat (limited to 'tree.c')
-rw-r--r-- | tree.c | 750 |
1 files changed, 750 insertions, 0 deletions
@@ -0,0 +1,750 @@ +/* $NetBSD: tree.c,v 1.9 2018/05/08 16:37:59 kamil Exp $ */ + +/* + * command tree climbing + */ +#include <sys/cdefs.h> + +#ifndef lint +__RCSID("$NetBSD: tree.c,v 1.9 2018/05/08 16:37:59 kamil Exp $"); +#endif + + +#include "sh.h" + +#define INDENT 4 + +#define tputc(c, shf) shf_putchar(c, shf); +static void ptree ARGS((struct op *t, int indent, struct shf *f)); +static void pioact ARGS((struct shf *f, int indent, struct ioword *iop)); +static void tputC ARGS((int c, struct shf *shf)); +static void tputS ARGS((char *wp, struct shf *shf)); +static void vfptreef ARGS((struct shf *shf, int indent, const char *fmt, va_list va)); +static struct ioword **iocopy ARGS((struct ioword **iow, Area *ap)); +static void iofree ARGS((struct ioword **iow, Area *ap)); + +/* + * print a command tree + */ + +static void +ptree(t, indent, shf) + struct op *t; + int indent; + struct shf *shf; +{ + char **w; + struct ioword **ioact; + struct op *t1; + + Chain: + if (t == NULL) + return; + switch (t->type) { + case TCOM: + if (t->vars) + for (w = t->vars; *w != NULL; ) + fptreef(shf, indent, "%S ", *w++); + else + fptreef(shf, indent, "#no-vars# "); + if (t->args) + for (w = t->args; *w != NULL; ) + fptreef(shf, indent, "%S ", *w++); + else + fptreef(shf, indent, "#no-args# "); + break; + case TEXEC: +#if 0 /* ?not useful - can't be called? */ + /* Print original vars */ + if (t->left->vars) + for (w = t->left->vars; *w != NULL; ) + fptreef(shf, indent, "%S ", *w++); + else + fptreef(shf, indent, "#no-vars# "); + /* Print expanded vars */ + if (t->args) + for (w = t->args; *w != NULL; ) + fptreef(shf, indent, "%s ", *w++); + else + fptreef(shf, indent, "#no-args# "); + /* Print original io */ + t = t->left; +#else + t = t->left; + goto Chain; +#endif + case TPAREN: + fptreef(shf, indent + 2, "( %T) ", t->left); + break; + case TPIPE: + fptreef(shf, indent, "%T| ", t->left); + t = t->right; + goto Chain; + case TLIST: + fptreef(shf, indent, "%T%;", t->left); + t = t->right; + goto Chain; + case TOR: + case TAND: + fptreef(shf, indent, "%T%s %T", + t->left, (t->type==TOR) ? "||" : "&&", t->right); + break; + case TBANG: + fptreef(shf, indent, "! "); + t = t->right; + goto Chain; + case TDBRACKET: + { + int i; + + fptreef(shf, indent, "[["); + for (i = 0; t->args[i]; i++) + fptreef(shf, indent, " %S", t->args[i]); + fptreef(shf, indent, " ]] "); + break; + } +#ifdef KSH + case TSELECT: + fptreef(shf, indent, "select %s ", t->str); + /* fall through */ +#endif /* KSH */ + case TFOR: + if (t->type == TFOR) + fptreef(shf, indent, "for %s ", t->str); + if (t->vars != NULL) { + fptreef(shf, indent, "in "); + for (w = t->vars; *w; ) + fptreef(shf, indent, "%S ", *w++); + fptreef(shf, indent, "%;"); + } + fptreef(shf, indent + INDENT, "do%N%T", t->left); + fptreef(shf, indent, "%;done "); + break; + case TCASE: + fptreef(shf, indent, "case %S in", t->str); + for (t1 = t->left; t1 != NULL; t1 = t1->right) { + fptreef(shf, indent, "%N("); + for (w = t1->vars; *w != NULL; w++) + fptreef(shf, indent, "%S%c", *w, + (w[1] != NULL) ? '|' : ')'); + fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left); + } + fptreef(shf, indent, "%Nesac "); + break; + case TIF: + case TELIF: + /* 3 == strlen("if ") */ + fptreef(shf, indent + 3, "if %T", t->left); + for (;;) { + t = t->right; + if (t->left != NULL) { + fptreef(shf, indent, "%;"); + fptreef(shf, indent + INDENT, "then%N%T", + t->left); + } + if (t->right == NULL || t->right->type != TELIF) + break; + t = t->right; + fptreef(shf, indent, "%;"); + /* 5 == strlen("elif ") */ + fptreef(shf, indent + 5, "elif %T", t->left); + } + if (t->right != NULL) { + fptreef(shf, indent, "%;"); + fptreef(shf, indent + INDENT, "else%;%T", t->right); + } + fptreef(shf, indent, "%;fi "); + break; + case TWHILE: + case TUNTIL: + /* 6 == strlen("while"/"until") */ + fptreef(shf, indent + 6, "%s %T", + (t->type==TWHILE) ? "while" : "until", + t->left); + fptreef(shf, indent, "%;do"); + fptreef(shf, indent + INDENT, "%;%T", t->right); + fptreef(shf, indent, "%;done "); + break; + case TBRACE: + fptreef(shf, indent + INDENT, "{%;%T", t->left); + fptreef(shf, indent, "%;} "); + break; + case TCOPROC: + fptreef(shf, indent, "%T|& ", t->left); + break; + case TASYNC: + fptreef(shf, indent, "%T& ", t->left); + break; + case TFUNCT: + fptreef(shf, indent, + t->u.ksh_func ? "function %s %T" : "%s() %T", + t->str, t->left); + break; + case TTIME: + fptreef(shf, indent, "time %T", t->left); + break; + default: + fptreef(shf, indent, "<botch>"); + break; + } + if ((ioact = t->ioact) != NULL) { + int need_nl = 0; + + while (*ioact != NULL) + pioact(shf, indent, *ioact++); + /* Print here documents after everything else... */ + for (ioact = t->ioact; *ioact != NULL; ) { + struct ioword *iop = *ioact++; + + /* heredoc is 0 when tracing (set -x) */ + if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) { + tputc('\n', shf); + shf_puts(iop->heredoc, shf); + fptreef(shf, indent, "%s", + evalstr(iop->delim, 0)); + need_nl = 1; + } + } + /* Last delimiter must be followed by a newline (this often + * leads to an extra blank line, but its not worth worrying + * about) + */ + if (need_nl) + tputc('\n', shf); + } +} + +static void +pioact(shf, indent, iop) + struct shf *shf; + int indent; + struct ioword *iop; +{ + int flag = iop->flag; + int type = flag & IOTYPE; + int expected; + + expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 + : (type == IOCAT || type == IOWRITE) ? 1 + : (type == IODUP && (iop->unit == !(flag & IORDUP))) ? + iop->unit + : iop->unit + 1; + if (iop->unit != expected) + tputc('0' + iop->unit, shf); + + switch (type) { + case IOREAD: + fptreef(shf, indent, "< "); + break; + case IOHERE: + if (flag&IOSKIP) + fptreef(shf, indent, "<<- "); + else + fptreef(shf, indent, "<< "); + break; + case IOCAT: + fptreef(shf, indent, ">> "); + break; + case IOWRITE: + if (flag&IOCLOB) + fptreef(shf, indent, ">| "); + else + fptreef(shf, indent, "> "); + break; + case IORDWR: + fptreef(shf, indent, "<> "); + break; + case IODUP: + if (flag & IORDUP) + fptreef(shf, indent, "<&"); + else + fptreef(shf, indent, ">&"); + break; + } + /* name/delim are 0 when printing syntax errors */ + if (type == IOHERE) { + if (iop->delim) + fptreef(shf, indent, "%S ", iop->delim); + } else if (iop->name) + fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ", + iop->name); +} + + +/* + * variants of fputc, fputs for ptreef and snptreef + */ + +static void +tputC(c, shf) + int c; + struct shf *shf; +{ + if ((c&0x60) == 0) { /* C0|C1 */ + tputc((c&0x80) ? '$' : '^', shf); + tputc(((c&0x7F)|0x40), shf); + } else if ((c&0x7F) == 0x7F) { /* DEL */ + tputc((c&0x80) ? '$' : '^', shf); + tputc('?', shf); + } else + tputc(c, shf); +} + +static void +tputS(wp, shf) + char *wp; + struct shf *shf; +{ + int c, quoted=0; + + /* problems: + * `...` -> $(...) + * 'foo' -> "foo" + * could change encoding to: + * OQUOTE ["'] ... CQUOTE ["'] + * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case) + */ + while (1) + switch ((c = *wp++)) { + case EOS: + return; + case CHAR: + tputC(*wp++, shf); + break; + case QCHAR: + c = *wp++; + if (!quoted || (c == '"' || c == '`' || c == '$')) + tputc('\\', shf); + tputC(c, shf); + break; + case COMSUB: + tputc('$', shf); + tputc('(', shf); + while (*wp != 0) + tputC(*wp++, shf); + tputc(')', shf); + wp++; + break; + case EXPRSUB: + tputc('$', shf); + tputc('(', shf); + tputc('(', shf); + while (*wp != 0) + tputC(*wp++, shf); + tputc(')', shf); + tputc(')', shf); + wp++; + break; + case OQUOTE: + quoted = 1; + tputc('"', shf); + break; + case CQUOTE: + quoted = 0; + tputc('"', shf); + break; + case OSUBST: + tputc('$', shf); + if (*wp++ == '{') + tputc('{', shf); + while ((c = *wp++) != 0) + tputC(c, shf); + break; + case CSUBST: + if (*wp++ == '}') + tputc('}', shf); + break; +#ifdef KSH + case OPAT: + tputc(*wp++, shf); + tputc('(', shf); + break; + case SPAT: + tputc('|', shf); + break; + case CPAT: + tputc(')', shf); + break; +#endif /* KSH */ + } +} + +/* + * this is the _only_ way to reliably handle + * variable args with an ANSI compiler + */ +/* VARARGS */ +int +fptreef(struct shf *shf, int indent, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + + vfptreef(shf, indent, fmt, va); + va_end(va); + return 0; +} + +/* VARARGS */ +char * +snptreef(char *s, int n, const char *fmt, ...) +{ + va_list va; + struct shf shf; + + shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf); + + va_start(va, fmt); + vfptreef(&shf, 0, fmt, va); + va_end(va); + + return shf_sclose(&shf); /* null terminates */ +} + +static void +vfptreef(shf, indent, fmt, va) + struct shf *shf; + int indent; + const char *fmt; + va_list va; +{ + int c; + + while ((c = *fmt++)) + if (c == '%') { + long n; + char *p; + int neg; + + switch ((c = *fmt++)) { + case 'c': + tputc(va_arg(va, int), shf); + break; + case 's': + p = va_arg(va, char *); + while (*p) + tputc(*p++, shf); + break; + case 'S': /* word */ + p = va_arg(va, char *); + tputS(p, shf); + break; + case 'd': case 'u': /* decimal */ + n = (c == 'd') ? va_arg(va, int) + : va_arg(va, unsigned int); + neg = c=='d' && n<0; + p = ulton((neg) ? -n : n, 10); + if (neg) + *--p = '-'; + while (*p) + tputc(*p++, shf); + break; + case 'T': /* format tree */ + ptree(va_arg(va, struct op *), indent, shf); + break; + case ';': /* newline or ; */ + case 'N': /* newline or space */ + if (shf->flags & SHF_STRING) { + if (c == ';') + tputc(';', shf); + tputc(' ', shf); + } else { + int i; + + tputc('\n', shf); + for (i = indent; i >= 8; i -= 8) + tputc('\t', shf); + for (; i > 0; --i) + tputc(' ', shf); + } + break; + case 'R': + pioact(shf, indent, va_arg(va, struct ioword *)); + break; + default: + tputc(c, shf); + break; + } + } else + tputc(c, shf); +} + +/* + * copy tree (for function definition) + */ + +struct op * +tcopy(t, ap) + struct op *t; + Area *ap; +{ + struct op *r; + char **tw, **rw; + + if (t == NULL) + return NULL; + + r = (struct op *) alloc(sizeof(struct op), ap); + + r->type = t->type; + r->u.evalflags = t->u.evalflags; + + r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap); + + if (t->vars == NULL) + r->vars = NULL; + else { + for (tw = t->vars; *tw++ != NULL; ) + ; + rw = r->vars = (char **) + alloc((tw - t->vars + 1) * sizeof(*tw), ap); + for (tw = t->vars; *tw != NULL; ) + *rw++ = wdcopy(*tw++, ap); + *rw = NULL; + } + + if (t->args == NULL) + r->args = NULL; + else { + for (tw = t->args; *tw++ != NULL; ) + ; + rw = r->args = (char **) + alloc((tw - t->args + 1) * sizeof(*tw), ap); + for (tw = t->args; *tw != NULL; ) + *rw++ = wdcopy(*tw++, ap); + *rw = NULL; + } + + r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap); + + r->left = tcopy(t->left, ap); + r->right = tcopy(t->right, ap); + r->lineno = t->lineno; + + return r; +} + +char * +wdcopy(wp, ap) + const char *wp; + Area *ap; +{ + size_t len = wdscan(wp, EOS) - wp; + return memcpy(alloc(len, ap), wp, len); +} + +/* return the position of prefix c in wp plus 1 */ +char * +wdscan(wp, c) + const char *wp; + int c; +{ + int nest = 0; + + while (1) + switch (*wp++) { + case EOS: + return (char *) __UNCONST(wp); + case CHAR: + case QCHAR: + wp++; + break; + case COMSUB: + case EXPRSUB: + while (*wp++ != 0) + ; + break; + case OQUOTE: + case CQUOTE: + break; + case OSUBST: + nest++; + while (*wp++ != '\0') + ; + break; + case CSUBST: + wp++; + if (c == CSUBST && nest == 0) + return (char *) __UNCONST(wp); + nest--; + break; +#ifdef KSH + case OPAT: + nest++; + wp++; + break; + case SPAT: + case CPAT: + if (c == wp[-1] && nest == 0) + return (char *) __UNCONST(wp); + if (wp[-1] == CPAT) + nest--; + break; +#endif /* KSH */ + default: + internal_errorf(0, + "wdscan: unknown char 0x%x (carrying on)", + wp[-1]); + } +} + +/* return a copy of wp without any of the mark up characters and + * with quote characters (" ' \) stripped. + * (string is allocated from ATEMP) + */ +char * +wdstrip(wp) + const char *wp; +{ + struct shf shf; + int c; + + shf_sopen((char *) 0, 32, SHF_WR | SHF_DYNAMIC, &shf); + + /* problems: + * `...` -> $(...) + * x${foo:-"hi"} -> x${foo:-hi} + * x${foo:-'hi'} -> x${foo:-hi} + */ + while (1) + switch ((c = *wp++)) { + case EOS: + return shf_sclose(&shf); /* null terminates */ + case CHAR: + case QCHAR: + shf_putchar(*wp++, &shf); + break; + case COMSUB: + shf_putchar('$', &shf); + shf_putchar('(', &shf); + while (*wp != 0) + shf_putchar(*wp++, &shf); + shf_putchar(')', &shf); + break; + case EXPRSUB: + shf_putchar('$', &shf); + shf_putchar('(', &shf); + shf_putchar('(', &shf); + while (*wp != 0) + shf_putchar(*wp++, &shf); + shf_putchar(')', &shf); + shf_putchar(')', &shf); + break; + case OQUOTE: + break; + case CQUOTE: + break; + case OSUBST: + shf_putchar('$', &shf); + if (*wp++ == '{') + shf_putchar('{', &shf); + while ((c = *wp++) != 0) + shf_putchar(c, &shf); + break; + case CSUBST: + if (*wp++ == '}') + shf_putchar('}', &shf); + break; +#ifdef KSH + case OPAT: + shf_putchar(*wp++, &shf); + shf_putchar('(', &shf); + break; + case SPAT: + shf_putchar('|', &shf); + break; + case CPAT: + shf_putchar(')', &shf); + break; +#endif /* KSH */ + } +} + +static struct ioword ** +iocopy(iow, ap) + struct ioword **iow; + Area *ap; +{ + struct ioword **ior; + int i; + + for (ior = iow; *ior++ != NULL; ) + ; + ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap); + + for (i = 0; iow[i] != NULL; i++) { + struct ioword *p, *q; + + p = iow[i]; + q = (struct ioword *) alloc(sizeof(*p), ap); + ior[i] = q; + *q = *p; + if (p->name != (char *) 0) + q->name = wdcopy(p->name, ap); + if (p->delim != (char *) 0) + q->delim = wdcopy(p->delim, ap); + if (p->heredoc != (char *) 0) + q->heredoc = str_save(p->heredoc, ap); + } + ior[i] = NULL; + + return ior; +} + +/* + * free tree (for function definition) + */ + +void +tfree(t, ap) + struct op *t; + Area *ap; +{ + char **w; + + if (t == NULL) + return; + + if (t->str != NULL) + afree((void*)t->str, ap); + + if (t->vars != NULL) { + for (w = t->vars; *w != NULL; w++) + afree((void*)*w, ap); + afree((void*)t->vars, ap); + } + + if (t->args != NULL) { + for (w = t->args; *w != NULL; w++) + afree((void*)*w, ap); + afree((void*)t->args, ap); + } + + if (t->ioact != NULL) + iofree(t->ioact, ap); + + tfree(t->left, ap); + tfree(t->right, ap); + + afree((void*)t, ap); +} + +static void +iofree(iow, ap) + struct ioword **iow; + Area *ap; +{ + struct ioword **iop; + struct ioword *p; + + for (iop = iow; (p = *iop++) != NULL; ) { + if (p->name != NULL) + afree((void*)p->name, ap); + if (p->delim != NULL) + afree((void*)p->delim, ap); + if (p->heredoc != NULL) + afree((void*)p->heredoc, ap); + afree((void*)p, ap); + } +} |