Add mksh from CVS 2010/08/24 as system/core/mksh module
Both shells (ash from system/core/sh, and mksh) are built by
default but only the one where $(TARGET_SHELL) is set to is
actually installed (the shell and the mkshrc configuration
file are tagged shell_mksh for this to work).
Signed-off-by: Thorsten Glaser <tg@mirbsd.org>
diff --git a/mksh/src/tree.c b/mksh/src/tree.c
new file mode 100644
index 0000000..aa861db
--- /dev/null
+++ b/mksh/src/tree.c
@@ -0,0 +1,716 @@
+/* $OpenBSD: tree.c,v 1.19 2008/08/11 21:50:35 jaredy Exp $ */
+
+/*-
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ * Thorsten Glaser <tg@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
+#include "sh.h"
+
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.30 2010/02/25 20:18:19 tg Exp $");
+
+#define INDENT 4
+
+#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 vfptreef(struct shf *, int, const char *, va_list);
+static struct ioword **iocopy(struct ioword **, Area *);
+static void iofree(struct ioword **, Area *);
+
+/*
+ * print a command tree
+ */
+static void
+ptree(struct op *t, int indent, struct shf *shf)
+{
+ const char **w;
+ struct ioword **ioact;
+ struct op *t1;
+
+ Chain:
+ if (t == NULL)
+ return;
+ switch (t->type) {
+ case TCOM:
+ if (t->vars)
+ for (w = (const char **)t->vars; *w != NULL; )
+ fptreef(shf, indent, "%S ", *w++);
+ else
+ shf_puts("#no-vars# ", shf);
+ if (t->args)
+ for (w = t->args; *w != NULL; )
+ fptreef(shf, indent, "%S ", *w++);
+ else
+ shf_puts("#no-args# ", shf);
+ break;
+ case TEXEC:
+ t = t->left;
+ goto Chain;
+ 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:
+ shf_puts("! ", shf);
+ t = t->right;
+ goto Chain;
+ case TDBRACKET: {
+ int i;
+
+ shf_puts("[[", shf);
+ for (i = 0; t->args[i]; i++)
+ fptreef(shf, indent, " %S", t->args[i]);
+ 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);
+ if (t->vars != NULL) {
+ shf_puts("in ", shf);
+ for (w = (const char **)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 = (const char **)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:
+ shf_puts("<botch>", shf);
+ 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 &&
+ /* iop->delim[1] == '<' means here string */
+ (!iop->delim || iop->delim[1] != '<')) {
+ 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(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)
+ shf_fprintf(shf, "%d", iop->unit);
+
+ switch (type) {
+ case IOREAD:
+ shf_puts("< ", shf);
+ break;
+ case IOHERE:
+ shf_puts(flag & IOSKIP ? "<<-" : "<<", shf);
+ break;
+ case IOCAT:
+ shf_puts(">> ", shf);
+ break;
+ case IOWRITE:
+ shf_puts(flag & IOCLOB ? ">| " : "> ", shf);
+ break;
+ case IORDWR:
+ shf_puts("<> ", shf);
+ break;
+ case IODUP:
+ shf_puts(flag & IORDUP ? "<&" : ">&", shf);
+ break;
+ }
+ /* name/delim are 0 when printing syntax errors */
+ if (type == IOHERE) {
+ if (iop->delim)
+ fptreef(shf, indent, "%s%S ",
+ /* here string */ iop->delim[1] == '<' ? "" : " ",
+ iop->delim);
+ 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);
+}
+
+static void
+tputS(char *wp, struct shf *shf)
+{
+ int c, quotelevel = 0;
+
+ /* problems:
+ * `...` -> $(...)
+ * 'foo' -> "foo"
+ * could change encoding to:
+ * OQUOTE ["'] ... CQUOTE ["']
+ * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
+ */
+ while (1)
+ switch (*wp++) {
+ case EOS:
+ return;
+ case ADELIM:
+ case CHAR:
+ tputC(*wp++, shf);
+ break;
+ case QCHAR:
+ c = *wp++;
+ if (!quotelevel || (c == '"' || c == '`' || c == '$'))
+ tputc('\\', shf);
+ tputC(c, shf);
+ break;
+ case COMSUB:
+ shf_puts("$(", shf);
+ while (*wp != 0)
+ tputC(*wp++, shf);
+ tputc(')', shf);
+ wp++;
+ break;
+ case EXPRSUB:
+ shf_puts("$((", shf);
+ while (*wp != 0)
+ tputC(*wp++, shf);
+ shf_puts("))", shf);
+ wp++;
+ break;
+ case OQUOTE:
+ quotelevel++;
+ tputc('"', shf);
+ break;
+ case CQUOTE:
+ if (quotelevel)
+ quotelevel--;
+ 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;
+ case OPAT:
+ tputc(*wp++, shf);
+ tputc('(', shf);
+ break;
+ case SPAT:
+ tputc('|', shf);
+ break;
+ case CPAT:
+ tputc(')', shf);
+ break;
+ }
+}
+
+/*
+ * 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(struct shf *shf, int indent, const char *fmt, va_list va)
+{
+ int c;
+
+ while ((c = *fmt++)) {
+ if (c == '%') {
+ switch ((c = *fmt++)) {
+ case 'c':
+ tputc(va_arg(va, int), shf);
+ break;
+ case 's':
+ shf_puts(va_arg(va, char *), shf);
+ break;
+ case 'S': /* word */
+ tputS(va_arg(va, char *), shf);
+ break;
+ case 'd': /* decimal */
+ shf_fprintf(shf, "%d", va_arg(va, int));
+ break;
+ case 'u': /* decimal */
+ shf_fprintf(shf, "%u", va_arg(va, unsigned int));
+ 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(struct op *t, Area *ap)
+{
+ struct op *r;
+ const char **tw;
+ char **rw;
+
+ if (t == NULL)
+ return (NULL);
+
+ r = alloc(sizeof(struct op), ap);
+
+ r->type = t->type;
+ r->u.evalflags = t->u.evalflags;
+
+ if (t->type == TCASE)
+ r->str = wdcopy(t->str, ap);
+ else
+ strdupx(r->str, t->str, ap);
+
+ 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) *
+ sizeof(*tw), ap);
+ for (tw = (const char **)t->vars; *tw != NULL; )
+ *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) *
+ 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(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 */
+const char *
+wdscan(const char *wp, int c)
+{
+ int nest = 0;
+
+ while (1)
+ switch (*wp++) {
+ case EOS:
+ return (wp);
+ case ADELIM:
+ if (c == ADELIM)
+ return (wp + 1);
+ /* FALLTHROUGH */
+ 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 (wp);
+ nest--;
+ break;
+ case OPAT:
+ nest++;
+ wp++;
+ break;
+ case SPAT:
+ case CPAT:
+ if (c == wp[-1] && nest == 0)
+ return (wp);
+ if (wp[-1] == CPAT)
+ nest--;
+ break;
+ default:
+ internal_warningf(
+ "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(const char *wp, bool keepq, bool make_magic)
+{
+ 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;
+ }
+}
+
+static struct ioword **
+iocopy(struct ioword **iow, Area *ap)
+{
+ struct ioword **ior;
+ int i;
+
+ for (ior = iow; *ior++ != NULL; )
+ ;
+ ior = alloc((ior - iow + 1) * sizeof(struct ioword *), ap);
+
+ for (i = 0; iow[i] != NULL; i++) {
+ struct ioword *p, *q;
+
+ p = iow[i];
+ q = alloc(sizeof(struct ioword), ap);
+ ior[i] = q;
+ *q = *p;
+ if (p->name != NULL)
+ q->name = wdcopy(p->name, ap);
+ if (p->delim != NULL)
+ q->delim = wdcopy(p->delim, ap);
+ if (p->heredoc != NULL)
+ strdupx(q->heredoc, p->heredoc, ap);
+ }
+ ior[i] = NULL;
+
+ return (ior);
+}
+
+/*
+ * free tree (for function definition)
+ */
+void
+tfree(struct op *t, Area *ap)
+{
+ char **w;
+
+ if (t == NULL)
+ return;
+
+ if (t->str != NULL)
+ afree(t->str, ap);
+
+ if (t->vars != NULL) {
+ for (w = t->vars; *w != NULL; w++)
+ afree(*w, ap);
+ afree(t->vars, ap);
+ }
+
+ if (t->args != NULL) {
+ 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);
+ afree(t->args, ap);
+ }
+
+ if (t->ioact != NULL)
+ iofree(t->ioact, ap);
+
+ tfree(t->left, ap);
+ tfree(t->right, ap);
+
+ afree(t, ap);
+}
+
+static void
+iofree(struct ioword **iow, Area *ap)
+{
+ struct ioword **iop;
+ struct ioword *p;
+
+ for (iop = iow; (p = *iop++) != NULL; ) {
+ if (p->name != NULL)
+ afree(p->name, ap);
+ if (p->delim != NULL)
+ afree(p->delim, ap);
+ if (p->heredoc != NULL)
+ afree(p->heredoc, ap);
+ afree(p, ap);
+ }
+ afree(iow, ap);
+}