-/* $OpenBSD: tree.c,v 1.19 2008/08/11 21:50:35 jaredy Exp $ */
+/* $OpenBSD: tree.c,v 1.20 2012/06/27 07:17:19 otto Exp $ */
/*-
- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ * 2011, 2012, 2013, 2015
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.30 2010/02/25 20:18:19 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.73 2015/04/11 22:03:32 tg Exp $");
-#define INDENT 4
+#define INDENT 8
-#define tputc(c, shf) shf_putchar(c, shf);
static void ptree(struct op *, int, struct shf *);
-static void pioact(struct shf *, int, struct ioword *);
-static void tputC(int, struct shf *);
-static void tputS(char *, struct shf *);
+static void pioact(struct shf *, struct ioword *);
+static const char *wdvarput(struct shf *, const char *, int, int);
static void vfptreef(struct shf *, int, const char *, va_list);
static struct ioword **iocopy(struct ioword **, Area *);
static void iofree(struct ioword **, Area *);
+/* "foo& ; bar" and "foo |& ; bar" are invalid */
+static bool prevent_semicolon;
+
+static const char Telif_pT[] = "elif %T";
+
/*
* print a command tree
*/
const char **w;
struct ioword **ioact;
struct op *t1;
+ int i;
Chain:
if (t == NULL)
return;
switch (t->type) {
case TCOM:
- if (t->vars)
- for (w = (const char **)t->vars; *w != NULL; )
+ prevent_semicolon = false;
+ /*
+ * special-case 'var=<<EOF' (rough; see
+ * exec.c:execute() for full code)
+ */
+ if (
+ /* we have zero arguments, i.e. no programme to run */
+ t->args[0] == NULL &&
+ /* we have exactly one variable assignment */
+ t->vars[0] != NULL && t->vars[1] == NULL &&
+ /* we have exactly one I/O redirection */
+ t->ioact != NULL && t->ioact[0] != NULL &&
+ t->ioact[1] == NULL &&
+ /* of type "here document" (or "here string") */
+ (t->ioact[0]->ioflag & IOTYPE) == IOHERE) {
+ fptreef(shf, indent, "%S", t->vars[0]);
+ break;
+ }
+
+ if (t->vars) {
+ w = (const char **)t->vars;
+ while (*w)
fptreef(shf, indent, "%S ", *w++);
- else
+ } else
shf_puts("#no-vars# ", shf);
- if (t->args)
- for (w = t->args; *w != NULL; )
+ if (t->args) {
+ w = t->args;
+ while (*w)
fptreef(shf, indent, "%S ", *w++);
- else
+ } else
shf_puts("#no-args# ", shf);
break;
case TEXEC:
case TOR:
case TAND:
fptreef(shf, indent, "%T%s %T",
- t->left, (t->type==TOR) ? "||" : "&&", t->right);
+ t->left, (t->type == TOR) ? "||" : "&&", t->right);
break;
case TBANG:
shf_puts("! ", shf);
+ prevent_semicolon = false;
t = t->right;
goto Chain;
- case TDBRACKET: {
- int i;
-
+ case TDBRACKET:
+ w = t->args;
shf_puts("[[", shf);
- for (i = 0; t->args[i]; i++)
- fptreef(shf, indent, " %S", t->args[i]);
+ while (*w)
+ fptreef(shf, indent, " %S", *w++);
shf_puts(" ]] ", shf);
break;
- }
case TSELECT:
- fptreef(shf, indent, "select %s ", t->str);
- /* FALLTHROUGH */
case TFOR:
- if (t->type == TFOR)
- fptreef(shf, indent, "for %s ", t->str);
+ fptreef(shf, indent, "%s %s ",
+ (t->type == TFOR) ? "for" : Tselect, t->str);
if (t->vars != NULL) {
shf_puts("in ", shf);
- for (w = (const char **)t->vars; *w; )
+ w = (const char **)t->vars;
+ while (*w)
fptreef(shf, indent, "%S ", *w++);
fptreef(shf, indent, "%;");
}
fptreef(shf, indent, "case %S in", t->str);
for (t1 = t->left; t1 != NULL; t1 = t1->right) {
fptreef(shf, indent, "%N(");
- for (w = (const char **)t1->vars; *w != NULL; w++)
+ w = (const char **)t1->vars;
+ while (*w) {
fptreef(shf, indent, "%S%c", *w,
(w[1] != NULL) ? '|' : ')');
- fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);
+ ++w;
+ }
+ fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left,
+ t1->u.charflag);
}
fptreef(shf, indent, "%Nesac ");
break;
- case TIF:
+#ifdef DEBUG
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;
+ internal_errorf("TELIF in tree.c:ptree() unexpected");
+ /* FALLTHROUGH */
+#endif
+ case TIF:
+ i = 2;
+ t1 = t;
+ goto process_TIF;
+ do {
+ t1 = t1->right;
+ i = 0;
fptreef(shf, indent, "%;");
+ process_TIF:
/* 5 == strlen("elif ") */
- fptreef(shf, indent + 5, "elif %T", t->left);
- }
- if (t->right != NULL) {
+ fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left);
+ t1 = t1->right;
+ if (t1->left != NULL) {
+ fptreef(shf, indent, "%;");
+ fptreef(shf, indent + INDENT, "%s%N%T",
+ "then", t1->left);
+ }
+ } while (t1->right && t1->right->type == TELIF);
+ if (t1->right != NULL) {
fptreef(shf, indent, "%;");
- fptreef(shf, indent + INDENT, "else%;%T", t->right);
+ fptreef(shf, indent + INDENT, "%s%N%T",
+ "else", t1->right);
}
fptreef(shf, indent, "%;fi ");
break;
case TWHILE:
case TUNTIL:
- /* 6 == strlen("while"/"until") */
+ /* 6 == strlen("while "/"until ") */
fptreef(shf, indent + 6, "%s %T",
- (t->type==TWHILE) ? "while" : "until",
+ (t->type == TWHILE) ? "while" : "until",
t->left);
- fptreef(shf, indent, "%;do");
- fptreef(shf, indent + INDENT, "%;%T", t->right);
+ fptreef(shf, indent, "%;");
+ fptreef(shf, indent + INDENT, "do%N%T", t->right);
fptreef(shf, indent, "%;done ");
break;
case TBRACE:
- fptreef(shf, indent + INDENT, "{%;%T", t->left);
+ fptreef(shf, indent + INDENT, "{%N%T", t->left);
fptreef(shf, indent, "%;} ");
break;
case TCOPROC:
fptreef(shf, indent, "%T|& ", t->left);
+ prevent_semicolon = true;
break;
case TASYNC:
fptreef(shf, indent, "%T& ", t->left);
+ prevent_semicolon = true;
break;
case TFUNCT:
- fptreef(shf, indent,
- t->u.ksh_func ? "function %s %T" : "%s() %T",
- t->str, t->left);
+ fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left);
break;
case TTIME:
- fptreef(shf, indent, "time %T", t->left);
+ fptreef(shf, indent, "%s %T", "time", t->left);
break;
default:
shf_puts("<botch>", shf);
+ prevent_semicolon = false;
break;
}
if ((ioact = t->ioact) != NULL) {
- int need_nl = 0;
+ bool need_nl = false;
while (*ioact != NULL)
- pioact(shf, indent, *ioact++);
+ pioact(shf, *ioact++);
/* Print here documents after everything else... */
- for (ioact = t->ioact; *ioact != NULL; ) {
+ ioact = t->ioact;
+ while (*ioact != NULL) {
struct ioword *iop = *ioact++;
- /* heredoc is 0 when tracing (set -x) */
- if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc &&
- /* iop->delim[1] == '<' means here string */
- (!iop->delim || iop->delim[1] != '<')) {
- tputc('\n', shf);
+ /* heredoc is NULL when tracing (set -x) */
+ if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE &&
+ iop->heredoc) {
+ shf_putc('\n', shf);
shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s",
+ iop->ioflag & IONDELIM ? "<<" :
evalstr(iop->delim, 0));
- need_nl = 1;
+ need_nl = true;
}
}
- /* Last delimiter must be followed by a newline (this often
- * leads to an extra blank line, but its not worth worrying
- * about)
+ /*
+ * Last delimiter must be followed by a newline (this
+ * often leads to an extra blank line, but it's not
+ * worth worrying about)
*/
- if (need_nl)
- tputc('\n', shf);
+ if (need_nl) {
+ shf_putc('\n', shf);
+ prevent_semicolon = true;
+ }
}
}
static void
-pioact(struct shf *shf, int indent, struct ioword *iop)
+pioact(struct shf *shf, struct ioword *iop)
{
- int flag = iop->flag;
- int type = flag & IOTYPE;
- int expected;
+ unsigned short flag = iop->ioflag;
+ unsigned short type = flag & IOTYPE;
+ short 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)
- shf_fprintf(shf, "%d", iop->unit);
+ shf_fprintf(shf, "%d", (int)iop->unit);
switch (type) {
case IOREAD:
- shf_puts("< ", shf);
+ shf_putc('<', shf);
break;
case IOHERE:
- shf_puts(flag & IOSKIP ? "<<-" : "<<", shf);
+ shf_puts("<<", shf);
+ if (flag & IOSKIP)
+ shf_putc('-', shf);
break;
case IOCAT:
- shf_puts(">> ", shf);
+ shf_puts(">>", shf);
break;
case IOWRITE:
- shf_puts(flag & IOCLOB ? ">| " : "> ", shf);
+ shf_putc('>', shf);
+ if (flag & IOCLOB)
+ shf_putc('|', shf);
break;
case IORDWR:
- shf_puts("<> ", shf);
+ shf_puts("<>", shf);
break;
case IODUP:
shf_puts(flag & IORDUP ? "<&" : ">&", shf);
break;
}
- /* name/delim are 0 when printing syntax errors */
+ /* name/delim are NULL when printing syntax errors */
if (type == IOHERE) {
if (iop->delim)
- fptreef(shf, indent, "%s%S ",
- /* here string */ iop->delim[1] == '<' ? "" : " ",
- iop->delim);
+ wdvarput(shf, iop->delim, 0, WDS_TPUTS);
+ if (flag & IOHERESTR)
+ shf_putc(' ', shf);
+ } else if (iop->name) {
+ if (flag & IONAMEXP)
+ print_value_quoted(shf, iop->name);
else
- tputc(' ', shf);
- } 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(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);
+ wdvarput(shf, iop->name, 0, WDS_TPUTS);
+ shf_putc(' ', shf);
+ }
+ prevent_semicolon = false;
}
-static void
-tputS(char *wp, struct shf *shf)
+/* variant of fputs for ptreef and wdstrip */
+static const char *
+wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
{
- int c, quotelevel = 0;
+ int c;
+ const char *cs;
- /* problems:
+ /*-
+ * problems:
* `...` -> $(...)
* 'foo' -> "foo"
+ * x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
+ * x${foo:-'hi'} -> x${foo:-hi} unless WDS_KEEPQ
* could change encoding to:
* OQUOTE ["'] ... CQUOTE ["']
* COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
*/
- while (1)
+ while (/* CONSTCOND */ 1)
switch (*wp++) {
case EOS:
- return;
+ return (--wp);
case ADELIM:
case CHAR:
- tputC(*wp++, shf);
+ c = *wp++;
+ if ((opmode & WDS_MAGIC) &&
+ (ISMAGIC(c) || c == '[' || c == '!' ||
+ c == '-' || c == ']' || c == '*' || c == '?'))
+ shf_putc(MAGIC, shf);
+ shf_putc(c, shf);
break;
- case QCHAR:
+ case QCHAR: {
+ bool doq;
+
c = *wp++;
- if (!quotelevel || (c == '"' || c == '`' || c == '$'))
- tputc('\\', shf);
- tputC(c, shf);
+ doq = (c == '"' || c == '`' || c == '$' || c == '\\');
+ if (opmode & WDS_TPUTS) {
+ if (quotelevel == 0)
+ doq = true;
+ } else {
+ if (!(opmode & WDS_KEEPQ))
+ doq = false;
+ }
+ if (doq)
+ shf_putc('\\', shf);
+ shf_putc(c, shf);
break;
+ }
case COMSUB:
shf_puts("$(", shf);
- while (*wp != 0)
- tputC(*wp++, shf);
- tputc(')', shf);
- wp++;
+ cs = ")";
+ pSUB:
+ while ((c = *wp++) != 0)
+ shf_putc(c, shf);
+ shf_puts(cs, shf);
break;
+ case FUNSUB:
+ c = ' ';
+ if (0)
+ /* FALLTHROUGH */
+ case VALSUB:
+ c = '|';
+ shf_putc('$', shf);
+ shf_putc('{', shf);
+ shf_putc(c, shf);
+ cs = ";}";
+ goto pSUB;
case EXPRSUB:
shf_puts("$((", shf);
- while (*wp != 0)
- tputC(*wp++, shf);
- shf_puts("))", shf);
- wp++;
- break;
+ cs = "))";
+ goto pSUB;
case OQUOTE:
- quotelevel++;
- tputc('"', shf);
+ if (opmode & WDS_TPUTS) {
+ quotelevel++;
+ shf_putc('"', shf);
+ }
break;
case CQUOTE:
- if (quotelevel)
- quotelevel--;
- tputc('"', shf);
+ if (opmode & WDS_TPUTS) {
+ if (quotelevel)
+ quotelevel--;
+ shf_putc('"', shf);
+ }
break;
case OSUBST:
- tputc('$', shf);
+ shf_putc('$', shf);
if (*wp++ == '{')
- tputc('{', shf);
+ shf_putc('{', shf);
while ((c = *wp++) != 0)
- tputC(c, shf);
+ shf_putc(c, shf);
+ wp = wdvarput(shf, wp, 0, opmode);
break;
case CSUBST:
if (*wp++ == '}')
- tputc('}', shf);
- break;
+ shf_putc('}', shf);
+ return (wp);
case OPAT:
- tputc(*wp++, shf);
- tputc('(', shf);
+ if (opmode & WDS_MAGIC) {
+ shf_putc(MAGIC, shf);
+ shf_putchar(*wp++ | 0x80, shf);
+ } else {
+ shf_putchar(*wp++, shf);
+ shf_putc('(', shf);
+ }
break;
case SPAT:
- tputc('|', shf);
- break;
+ c = '|';
+ if (0)
case CPAT:
- tputc(')', shf);
+ c = /*(*/ ')';
+ if (opmode & WDS_MAGIC)
+ shf_putc(MAGIC, shf);
+ shf_putc(c, shf);
break;
}
}
* variable args with an ANSI compiler
*/
/* VARARGS */
-int
+void
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, ...)
+snptreef(char *s, ssize_t n, const char *fmt, ...)
{
va_list va;
struct shf shf;
vfptreef(&shf, 0, fmt, va);
va_end(va);
- return (shf_sclose(&shf)); /* null terminates */
+ /* shf_sclose NUL terminates */
+ return (shf_sclose(&shf));
}
static void
if (c == '%') {
switch ((c = *fmt++)) {
case 'c':
- tputc(va_arg(va, int), shf);
+ /* character (octet, probably) */
+ shf_putchar(va_arg(va, int), shf);
break;
case 's':
+ /* string */
shf_puts(va_arg(va, char *), shf);
break;
- case 'S': /* word */
- tputS(va_arg(va, char *), shf);
+ case 'S':
+ /* word */
+ wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS);
break;
- case 'd': /* decimal */
+ case 'd':
+ /* signed decimal */
shf_fprintf(shf, "%d", va_arg(va, int));
break;
- case 'u': /* decimal */
+ case 'u':
+ /* unsigned decimal */
shf_fprintf(shf, "%u", va_arg(va, unsigned int));
break;
- case 'T': /* format tree */
+ case 'T':
+ /* format tree */
ptree(va_arg(va, struct op *), indent, shf);
- break;
- case ';': /* newline or ; */
- case 'N': /* newline or space */
+ goto dont_trash_prevent_semicolon;
+ case ';':
+ /* newline or ; */
+ case 'N':
+ /* newline or space */
if (shf->flags & SHF_STRING) {
- if (c == ';')
- tputc(';', shf);
- tputc(' ', shf);
+ if (c == ';' && !prevent_semicolon)
+ shf_putc(';', shf);
+ shf_putc(' ', shf);
} else {
int i;
- tputc('\n', shf);
- for (i = indent; i >= 8; i -= 8)
- tputc('\t', shf);
- for (; i > 0; --i)
- tputc(' ', shf);
+ shf_putc('\n', shf);
+ i = indent;
+ while (i >= 8) {
+ shf_putc('\t', shf);
+ i -= 8;
+ }
+ while (i--)
+ shf_putc(' ', shf);
}
break;
case 'R':
- pioact(shf, indent, va_arg(va, struct ioword *));
+ /* I/O redirection */
+ pioact(shf, va_arg(va, struct ioword *));
break;
default:
- tputc(c, shf);
+ shf_putc(c, shf);
break;
}
} else
- tputc(c, shf);
+ shf_putc(c, shf);
+ prevent_semicolon = false;
+ dont_trash_prevent_semicolon:
+ ;
}
}
if (t->vars == NULL)
r->vars = NULL;
else {
- for (tw = (const char **)t->vars; *tw++ != NULL; )
- ;
- rw = r->vars = alloc((tw - (const char **)t->vars + 1) *
+ tw = (const char **)t->vars;
+ while (*tw)
+ ++tw;
+ rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
sizeof(*tw), ap);
- for (tw = (const char **)t->vars; *tw != NULL; )
+ tw = (const char **)t->vars;
+ while (*tw)
*rw++ = wdcopy(*tw++, ap);
*rw = NULL;
}
if (t->args == NULL)
r->args = NULL;
else {
- for (tw = t->args; *tw++ != NULL; )
- ;
- r->args = (const char **)(rw = alloc((tw - t->args + 1) *
+ tw = t->args;
+ while (*tw)
+ ++tw;
+ r->args = (const char **)(rw = alloc2(tw - t->args + 1,
sizeof(*tw), ap));
- for (tw = t->args; *tw != NULL; )
+ tw = t->args;
+ while (*tw)
*rw++ = wdcopy(*tw++, ap);
*rw = NULL;
}
char *
wdcopy(const char *wp, Area *ap)
{
- size_t len = wdscan(wp, EOS) - wp;
+ size_t len;
+
+ len = wdscan(wp, EOS) - wp;
return (memcpy(alloc(len, ap), wp, len));
}
{
int nest = 0;
- while (1)
+ while (/* CONSTCOND */ 1)
switch (*wp++) {
case EOS:
return (wp);
wp++;
break;
case COMSUB:
+ case FUNSUB:
+ case VALSUB:
case EXPRSUB:
while (*wp++ != 0)
;
}
}
-/* return a copy of wp without any of the mark up characters and
- * with quote characters (" ' \) stripped.
- * (string is allocated from ATEMP)
+/*
+ * return a copy of wp without any of the mark up characters and with
+ * quote characters (" ' \) stripped. (string is allocated from ATEMP)
*/
char *
-wdstrip(const char *wp, bool keepq, bool make_magic)
+wdstrip(const char *wp, int opmode)
{
struct shf shf;
- int c;
shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
-
- /* problems:
- * `...` -> $(...)
- * x${foo:-"hi"} -> x${foo:-hi}
- * x${foo:-'hi'} -> x${foo:-hi} unless keepq
- */
- while (1)
- switch (*wp++) {
- case EOS:
- return (shf_sclose(&shf)); /* null terminates */
- case ADELIM:
- case CHAR:
- c = *wp++;
- if (make_magic && (ISMAGIC(c) || c == '[' || c == NOT ||
- c == '-' || c == ']' || c == '*' || c == '?'))
- shf_putchar(MAGIC, &shf);
- shf_putchar(c, &shf);
- break;
- case QCHAR:
- c = *wp++;
- if (keepq && (c == '"' || c == '`' || c == '$' || c == '\\'))
- shf_putchar('\\', &shf);
- shf_putchar(c, &shf);
- break;
- case COMSUB:
- shf_puts("$(", &shf);
- while (*wp != 0)
- shf_putchar(*wp++, &shf);
- shf_putchar(')', &shf);
- break;
- case EXPRSUB:
- shf_puts("$((", &shf);
- while (*wp != 0)
- shf_putchar(*wp++, &shf);
- shf_puts("))", &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;
- case OPAT:
- if (make_magic) {
- shf_putchar(MAGIC, &shf);
- shf_putchar(*wp++ | 0x80, &shf);
- } else {
- shf_putchar(*wp++, &shf);
- shf_putchar('(', &shf);
- }
- break;
- case SPAT:
- if (make_magic)
- shf_putchar(MAGIC, &shf);
- shf_putchar('|', &shf);
- break;
- case CPAT:
- if (make_magic)
- shf_putchar(MAGIC, &shf);
- shf_putchar(')', &shf);
- break;
- }
+ wdvarput(&shf, wp, 0, opmode);
+ /* shf_sclose NUL terminates */
+ return (shf_sclose(&shf));
}
static struct ioword **
struct ioword **ior;
int i;
- for (ior = iow; *ior++ != NULL; )
- ;
- ior = alloc((ior - iow + 1) * sizeof(struct ioword *), ap);
+ ior = iow;
+ while (*ior)
+ ++ior;
+ ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
for (i = 0; iow[i] != NULL; i++) {
struct ioword *p, *q;
}
if (t->args != NULL) {
+ /*XXX we assume the caller is right */
union mksh_ccphack cw;
- /* XXX we assume the caller is right */
+
cw.ro = t->args;
for (w = cw.rw; *w != NULL; w++)
afree(*w, ap);
struct ioword **iop;
struct ioword *p;
- for (iop = iow; (p = *iop++) != NULL; ) {
+ iop = iow;
+ while ((p = *iop++) != NULL) {
if (p->name != NULL)
afree(p->name, ap);
if (p->delim != NULL)
}
afree(iow, ap);
}
+
+void
+fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
+{
+ if (isksh)
+ fptreef(shf, i, "%s %s %T", Tfunction, k, v);
+ else
+ fptreef(shf, i, "%s() %T", k, v);
+}
+
+
+/* for jobs.c */
+void
+vistree(char *dst, size_t sz, struct op *t)
+{
+ unsigned int c;
+ char *cp, *buf;
+ size_t n;
+
+ buf = alloc(sz + 16, ATEMP);
+ snptreef(buf, sz + 16, "%T", t);
+ cp = buf;
+ vist_loop:
+ if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
+ if (c == 0 || n >= sz)
+ /* NUL or not enough free space */
+ goto vist_out;
+ /* copy multibyte char */
+ sz -= n;
+ while (n--)
+ *dst++ = *cp++;
+ goto vist_loop;
+ }
+ if (--sz == 0 || (c = (unsigned char)(*cp++)) == 0)
+ /* NUL or not enough free space */
+ goto vist_out;
+ if (ISCTRL(c & 0x7F)) {
+ /* C0 or C1 control character or DEL */
+ if (--sz == 0)
+ /* not enough free space for two chars */
+ goto vist_out;
+ *dst++ = (c & 0x80) ? '$' : '^';
+ c = UNCTRL(c & 0x7F);
+ } else if (UTFMODE && c > 0x7F) {
+ /* better not try to display broken multibyte chars */
+ /* also go easy on the Unicode: no U+FFFD here */
+ c = '?';
+ }
+ *dst++ = c;
+ goto vist_loop;
+
+ vist_out:
+ *dst = '\0';
+ afree(buf, ATEMP);
+}
+
+#ifdef DEBUG
+void
+dumpchar(struct shf *shf, int c)
+{
+ if (ISCTRL(c & 0x7F)) {
+ /* C0 or C1 control character or DEL */
+ shf_putc((c & 0x80) ? '$' : '^', shf);
+ c = UNCTRL(c & 0x7F);
+ }
+ shf_putc(c, shf);
+}
+
+/* see: wdvarput */
+static const char *
+dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
+{
+ int c;
+
+ while (/* CONSTCOND */ 1) {
+ switch(*wp++) {
+ case EOS:
+ shf_puts("EOS", shf);
+ return (--wp);
+ case ADELIM:
+ shf_puts("ADELIM=", shf);
+ if (0)
+ case CHAR:
+ shf_puts("CHAR=", shf);
+ dumpchar(shf, *wp++);
+ break;
+ case QCHAR:
+ shf_puts("QCHAR<", shf);
+ c = *wp++;
+ if (quotelevel == 0 ||
+ (c == '"' || c == '`' || c == '$' || c == '\\'))
+ shf_putc('\\', shf);
+ dumpchar(shf, c);
+ goto closeandout;
+ case COMSUB:
+ shf_puts("COMSUB<", shf);
+ dumpsub:
+ while ((c = *wp++) != 0)
+ dumpchar(shf, c);
+ closeandout:
+ shf_putc('>', shf);
+ break;
+ case FUNSUB:
+ shf_puts("FUNSUB<", shf);
+ goto dumpsub;
+ case VALSUB:
+ shf_puts("VALSUB<", shf);
+ goto dumpsub;
+ case EXPRSUB:
+ shf_puts("EXPRSUB<", shf);
+ goto dumpsub;
+ case OQUOTE:
+ shf_fprintf(shf, "OQUOTE{%d", ++quotelevel);
+ break;
+ case CQUOTE:
+ shf_fprintf(shf, "%d}CQUOTE", quotelevel);
+ if (quotelevel)
+ quotelevel--;
+ else
+ shf_puts("(err)", shf);
+ break;
+ case OSUBST:
+ shf_puts("OSUBST(", shf);
+ dumpchar(shf, *wp++);
+ shf_puts(")[", shf);
+ while ((c = *wp++) != 0)
+ dumpchar(shf, c);
+ shf_putc('|', shf);
+ wp = dumpwdvar_i(shf, wp, 0);
+ break;
+ case CSUBST:
+ shf_puts("]CSUBST(", shf);
+ dumpchar(shf, *wp++);
+ shf_putc(')', shf);
+ return (wp);
+ case OPAT:
+ shf_puts("OPAT=", shf);
+ dumpchar(shf, *wp++);
+ break;
+ case SPAT:
+ shf_puts("SPAT", shf);
+ break;
+ case CPAT:
+ shf_puts("CPAT", shf);
+ break;
+ default:
+ shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]);
+ break;
+ }
+ shf_putc(' ', shf);
+ }
+}
+void
+dumpwdvar(struct shf *shf, const char *wp)
+{
+ dumpwdvar_i(shf, wp, 0);
+}
+
+void
+dumpioact(struct shf *shf, struct op *t)
+{
+ struct ioword **ioact, *iop;
+
+ if ((ioact = t->ioact) == NULL)
+ return;
+
+ shf_puts("{IOACT", shf);
+ while ((iop = *ioact++) != NULL) {
+ unsigned short type = iop->ioflag & IOTYPE;
+#define DT(x) case x: shf_puts(#x, shf); break;
+#define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
+
+ shf_putc(';', shf);
+ switch (type) {
+ DT(IOREAD)
+ DT(IOWRITE)
+ DT(IORDWR)
+ DT(IOHERE)
+ DT(IOCAT)
+ DT(IODUP)
+ default:
+ shf_fprintf(shf, "unk%d", type);
+ }
+ DB(IOEVAL)
+ DB(IOSKIP)
+ DB(IOCLOB)
+ DB(IORDUP)
+ DB(IONAMEXP)
+ DB(IOBASH)
+ DB(IOHERESTR)
+ DB(IONDELIM)
+ shf_fprintf(shf, ",unit=%d", (int)iop->unit);
+ if (iop->delim) {
+ shf_puts(",delim<", shf);
+ dumpwdvar(shf, iop->delim);
+ shf_putc('>', shf);
+ }
+ if (iop->name) {
+ if (iop->ioflag & IONAMEXP) {
+ shf_puts(",name=", shf);
+ print_value_quoted(shf, iop->name);
+ } else {
+ shf_puts(",name<", shf);
+ dumpwdvar(shf, iop->name);
+ shf_putc('>', shf);
+ }
+ }
+ if (iop->heredoc) {
+ shf_puts(",heredoc=", shf);
+ print_value_quoted(shf, iop->heredoc);
+ }
+#undef DT
+#undef DB
+ }
+ shf_putc('}', shf);
+}
+
+void
+dumptree(struct shf *shf, struct op *t)
+{
+ int i, j;
+ const char **w, *name;
+ struct op *t1;
+ static int nesting;
+
+ for (i = 0; i < nesting; ++i)
+ shf_putc('\t', shf);
+ ++nesting;
+ shf_puts("{tree:" /*}*/, shf);
+ if (t == NULL) {
+ name = "(null)";
+ goto out;
+ }
+ dumpioact(shf, t);
+ switch (t->type) {
+#define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
+
+ OPEN(TCOM)
+ if (t->vars) {
+ i = 0;
+ w = (const char **)t->vars;
+ while (*w) {
+ shf_putc('\n', shf);
+ for (j = 0; j < nesting; ++j)
+ shf_putc('\t', shf);
+ shf_fprintf(shf, " var%d<", i++);
+ dumpwdvar(shf, *w++);
+ shf_putc('>', shf);
+ }
+ } else
+ shf_puts(" #no-vars#", shf);
+ if (t->args) {
+ i = 0;
+ w = t->args;
+ while (*w) {
+ shf_putc('\n', shf);
+ for (j = 0; j < nesting; ++j)
+ shf_putc('\t', shf);
+ shf_fprintf(shf, " arg%d<", i++);
+ dumpwdvar(shf, *w++);
+ shf_putc('>', shf);
+ }
+ } else
+ shf_puts(" #no-args#", shf);
+ break;
+ OPEN(TEXEC)
+ dumpleftandout:
+ t = t->left;
+ dumpandout:
+ shf_putc('\n', shf);
+ dumptree(shf, t);
+ break;
+ OPEN(TPAREN)
+ goto dumpleftandout;
+ OPEN(TPIPE)
+ dumpleftmidrightandout:
+ shf_putc('\n', shf);
+ dumptree(shf, t->left);
+/* middumprightandout: (unused) */
+ shf_fprintf(shf, "/%s:", name);
+ dumprightandout:
+ t = t->right;
+ goto dumpandout;
+ OPEN(TLIST)
+ goto dumpleftmidrightandout;
+ OPEN(TOR)
+ goto dumpleftmidrightandout;
+ OPEN(TAND)
+ goto dumpleftmidrightandout;
+ OPEN(TBANG)
+ goto dumprightandout;
+ OPEN(TDBRACKET)
+ i = 0;
+ w = t->args;
+ while (*w) {
+ shf_putc('\n', shf);
+ for (j = 0; j < nesting; ++j)
+ shf_putc('\t', shf);
+ shf_fprintf(shf, " arg%d<", i++);
+ dumpwdvar(shf, *w++);
+ shf_putc('>', shf);
+ }
+ break;
+ OPEN(TFOR)
+ dumpfor:
+ shf_fprintf(shf, " str<%s>", t->str);
+ if (t->vars != NULL) {
+ i = 0;
+ w = (const char **)t->vars;
+ while (*w) {
+ shf_putc('\n', shf);
+ for (j = 0; j < nesting; ++j)
+ shf_putc('\t', shf);
+ shf_fprintf(shf, " var%d<", i++);
+ dumpwdvar(shf, *w++);
+ shf_putc('>', shf);
+ }
+ }
+ goto dumpleftandout;
+ OPEN(TSELECT)
+ goto dumpfor;
+ OPEN(TCASE)
+ shf_fprintf(shf, " str<%s>", t->str);
+ i = 0;
+ for (t1 = t->left; t1 != NULL; t1 = t1->right) {
+ shf_putc('\n', shf);
+ for (j = 0; j < nesting; ++j)
+ shf_putc('\t', shf);
+ shf_fprintf(shf, " sub%d[(", i);
+ w = (const char **)t1->vars;
+ while (*w) {
+ dumpwdvar(shf, *w);
+ if (w[1] != NULL)
+ shf_putc('|', shf);
+ ++w;
+ }
+ shf_putc(')', shf);
+ dumpioact(shf, t);
+ shf_putc('\n', shf);
+ dumptree(shf, t1->left);
+ shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
+ }
+ break;
+ OPEN(TWHILE)
+ goto dumpleftmidrightandout;
+ OPEN(TUNTIL)
+ goto dumpleftmidrightandout;
+ OPEN(TBRACE)
+ goto dumpleftandout;
+ OPEN(TCOPROC)
+ goto dumpleftandout;
+ OPEN(TASYNC)
+ goto dumpleftandout;
+ OPEN(TFUNCT)
+ shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
+ t->u.ksh_func ? "yes" : "no");
+ goto dumpleftandout;
+ OPEN(TTIME)
+ goto dumpleftandout;
+ OPEN(TIF)
+ dumpif:
+ shf_putc('\n', shf);
+ dumptree(shf, t->left);
+ t = t->right;
+ dumpioact(shf, t);
+ if (t->left != NULL) {
+ shf_puts(" /TTHEN:\n", shf);
+ dumptree(shf, t->left);
+ }
+ if (t->right && t->right->type == TELIF) {
+ shf_puts(" /TELIF:", shf);
+ t = t->right;
+ dumpioact(shf, t);
+ goto dumpif;
+ }
+ if (t->right != NULL) {
+ shf_puts(" /TELSE:\n", shf);
+ dumptree(shf, t->right);
+ }
+ break;
+ OPEN(TEOF)
+ dumpunexpected:
+ shf_puts("unexpected", shf);
+ break;
+ OPEN(TELIF)
+ goto dumpunexpected;
+ OPEN(TPAT)
+ goto dumpunexpected;
+ default:
+ name = "TINVALID";
+ shf_fprintf(shf, "{T<%d>:" /*}*/, t->type);
+ goto dumpunexpected;
+
+#undef OPEN
+ }
+ out:
+ shf_fprintf(shf, /*{*/ " /%s}\n", name);
+ --nesting;
+}
+#endif