Blame tree.c

Packit Service 95ac19
/*	$OpenBSD: tree.c,v 1.21 2015/09/01 13:12:31 tedu Exp $	*/
Packit Service 95ac19
Packit Service 95ac19
/*-
Packit Service 95ac19
 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
Packit Service 95ac19
 *		 2011, 2012, 2013, 2015, 2016, 2017
Packit Service 95ac19
 *	mirabilos <m@mirbsd.org>
Packit Service 95ac19
 *
Packit Service 95ac19
 * Provided that these terms and disclaimer and all copyright notices
Packit Service 95ac19
 * are retained or reproduced in an accompanying document, permission
Packit Service 95ac19
 * is granted to deal in this work without restriction, including un-
Packit Service 95ac19
 * limited rights to use, publicly perform, distribute, sell, modify,
Packit Service 95ac19
 * merge, give away, or sublicence.
Packit Service 95ac19
 *
Packit Service 95ac19
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
Packit Service 95ac19
 * the utmost extent permitted by applicable law, neither express nor
Packit Service 95ac19
 * implied; without malicious intent or gross negligence. In no event
Packit Service 95ac19
 * may a licensor, author or contributor be held liable for indirect,
Packit Service 95ac19
 * direct, other damage, loss, or other issues arising in any way out
Packit Service 95ac19
 * of dealing in the work, even if advised of the possibility of such
Packit Service 95ac19
 * damage or existence of a defect, except proven that it results out
Packit Service 95ac19
 * of said person's immediate fault when using the work as intended.
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
#include "sh.h"
Packit Service 95ac19
Packit Service 95ac19
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.95 2018/01/14 00:03:05 tg Exp $");
Packit Service 95ac19
Packit Service 95ac19
#define INDENT	8
Packit Service 95ac19
Packit Service 95ac19
static void ptree(struct op *, int, struct shf *);
Packit Service 95ac19
static void pioact(struct shf *, struct ioword *);
Packit Service 95ac19
static const char *wdvarput(struct shf *, const char *, int, int);
Packit Service 95ac19
static void vfptreef(struct shf *, int, const char *, va_list);
Packit Service 95ac19
static struct ioword **iocopy(struct ioword **, Area *);
Packit Service 95ac19
static void iofree(struct ioword **, Area *);
Packit Service 95ac19
Packit Service 95ac19
/* "foo& ; bar" and "foo |& ; bar" are invalid */
Packit Service 95ac19
static bool prevent_semicolon;
Packit Service 95ac19
Packit Service 95ac19
static const char Telif_pT[] = "elif %T";
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * print a command tree
Packit Service 95ac19
 */
Packit Service 95ac19
static void
Packit Service 95ac19
ptree(struct op *t, int indent, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	const char **w;
Packit Service 95ac19
	struct ioword **ioact;
Packit Service 95ac19
	struct op *t1;
Packit Service 95ac19
	int i;
Packit Service 95ac19
	const char *ccp;
Packit Service 95ac19
Packit Service 95ac19
 Chain:
Packit Service 95ac19
	if (t == NULL)
Packit Service 95ac19
		return;
Packit Service 95ac19
	switch (t->type) {
Packit Service 95ac19
	case TCOM:
Packit Service 95ac19
		prevent_semicolon = false;
Packit Service 95ac19
		/* special-case 'var=<
Packit Service 95ac19
		if (t->args &&
Packit Service 95ac19
		    /* we have zero arguments, i.e. no program to run */
Packit Service 95ac19
		    t->args[0] == NULL &&
Packit Service 95ac19
		    /* we have exactly one variable assignment */
Packit Service 95ac19
		    t->vars[0] != NULL && t->vars[1] == NULL &&
Packit Service 95ac19
		    /* we have exactly one I/O redirection */
Packit Service 95ac19
		    t->ioact != NULL && t->ioact[0] != NULL &&
Packit Service 95ac19
		    t->ioact[1] == NULL &&
Packit Service 95ac19
		    /* of type "here document" (or "here string") */
Packit Service 95ac19
		    (t->ioact[0]->ioflag & IOTYPE) == IOHERE &&
Packit Service 95ac19
		    /* the variable assignment begins with a valid varname */
Packit Service 95ac19
		    (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
Packit Service 95ac19
		    /* and has no right-hand side (i.e. "varname=") */
Packit Service 95ac19
		    ccp[0] == CHAR && ((ccp[1] == '=' && ccp[2] == EOS) ||
Packit Service 95ac19
		    /* or "varname+=" */ (ccp[1] == '+' && ccp[2] == CHAR &&
Packit Service 95ac19
		    ccp[3] == '=' && ccp[4] == EOS))) {
Packit Service 95ac19
			fptreef(shf, indent, Tf_S, t->vars[0]);
Packit Service 95ac19
			break;
Packit Service 95ac19
		}
Packit Service 95ac19
Packit Service 95ac19
		if (t->vars) {
Packit Service 95ac19
			w = (const char **)t->vars;
Packit Service 95ac19
			while (*w)
Packit Service 95ac19
				fptreef(shf, indent, Tf_S_, *w++);
Packit Service 95ac19
		} else
Packit Service 95ac19
			shf_puts("#no-vars# ", shf);
Packit Service 95ac19
		if (t->args) {
Packit Service 95ac19
			w = t->args;
Packit Service 95ac19
			if (*w && **w == CHAR) {
Packit Service 95ac19
				char *cp = wdstrip(*w++, WDS_TPUTS);
Packit Service 95ac19
Packit Service 95ac19
				if (valid_alias_name(cp))
Packit Service 95ac19
					shf_putc('\\', shf);
Packit Service 95ac19
				shf_puts(cp, shf);
Packit Service 95ac19
				shf_putc(' ', shf);
Packit Service 95ac19
				afree(cp, ATEMP);
Packit Service 95ac19
			}
Packit Service 95ac19
			while (*w)
Packit Service 95ac19
				fptreef(shf, indent, Tf_S_, *w++);
Packit Service 95ac19
		} else
Packit Service 95ac19
			shf_puts("#no-args# ", shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TEXEC:
Packit Service 95ac19
		t = t->left;
Packit Service 95ac19
		goto Chain;
Packit Service 95ac19
	case TPAREN:
Packit Service 95ac19
		fptreef(shf, indent + 2, "( %T) ", t->left);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TPIPE:
Packit Service 95ac19
		fptreef(shf, indent, "%T| ", t->left);
Packit Service 95ac19
		t = t->right;
Packit Service 95ac19
		goto Chain;
Packit Service 95ac19
	case TLIST:
Packit Service 95ac19
		fptreef(shf, indent, "%T%;", t->left);
Packit Service 95ac19
		t = t->right;
Packit Service 95ac19
		goto Chain;
Packit Service 95ac19
	case TOR:
Packit Service 95ac19
	case TAND:
Packit Service 95ac19
		fptreef(shf, indent, "%T%s %T",
Packit Service 95ac19
		    t->left, (t->type == TOR) ? "||" : "&&", t->right);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TBANG:
Packit Service 95ac19
		shf_puts("! ", shf);
Packit Service 95ac19
		prevent_semicolon = false;
Packit Service 95ac19
		t = t->right;
Packit Service 95ac19
		goto Chain;
Packit Service 95ac19
	case TDBRACKET:
Packit Service 95ac19
		w = t->args;
Packit Service 95ac19
		shf_puts("[[", shf);
Packit Service 95ac19
		while (*w)
Packit Service 95ac19
			fptreef(shf, indent, Tf__S, *w++);
Packit Service 95ac19
		shf_puts(" ]] ", shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TSELECT:
Packit Service 95ac19
	case TFOR:
Packit Service 95ac19
		fptreef(shf, indent, "%s %s ",
Packit Service 95ac19
		    (t->type == TFOR) ? "for" : Tselect, t->str);
Packit Service 95ac19
		if (t->vars != NULL) {
Packit Service 95ac19
			shf_puts("in ", shf);
Packit Service 95ac19
			w = (const char **)t->vars;
Packit Service 95ac19
			while (*w)
Packit Service 95ac19
				fptreef(shf, indent, Tf_S_, *w++);
Packit Service 95ac19
			fptreef(shf, indent, Tft_end);
Packit Service 95ac19
		}
Packit Service 95ac19
		fptreef(shf, indent + INDENT, "do%N%T", t->left);
Packit Service 95ac19
		fptreef(shf, indent, "%;done ");
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TCASE:
Packit Service 95ac19
		fptreef(shf, indent, "case %S in", t->str);
Packit Service 95ac19
		for (t1 = t->left; t1 != NULL; t1 = t1->right) {
Packit Service 95ac19
			fptreef(shf, indent, "%N(");
Packit Service 95ac19
			w = (const char **)t1->vars;
Packit Service 95ac19
			while (*w) {
Packit Service 95ac19
				fptreef(shf, indent, "%S%c", *w,
Packit Service 95ac19
				    (w[1] != NULL) ? '|' : ')');
Packit Service 95ac19
				++w;
Packit Service 95ac19
			}
Packit Service 95ac19
			fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left,
Packit Service 95ac19
			    t1->u.charflag);
Packit Service 95ac19
		}
Packit Service 95ac19
		fptreef(shf, indent, "%Nesac ");
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TELIF:
Packit Service 95ac19
		internal_errorf(TELIF_unexpected);
Packit Service 95ac19
		/* FALLTHROUGH */
Packit Service 95ac19
	case TIF:
Packit Service 95ac19
		i = 2;
Packit Service 95ac19
		t1 = t;
Packit Service 95ac19
		goto process_TIF;
Packit Service 95ac19
		do {
Packit Service 95ac19
			t1 = t1->right;
Packit Service 95ac19
			i = 0;
Packit Service 95ac19
			fptreef(shf, indent, Tft_end);
Packit Service 95ac19
 process_TIF:
Packit Service 95ac19
			/* 5 == strlen("elif ") */
Packit Service 95ac19
			fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left);
Packit Service 95ac19
			t1 = t1->right;
Packit Service 95ac19
			if (t1->left != NULL) {
Packit Service 95ac19
				fptreef(shf, indent, Tft_end);
Packit Service 95ac19
				fptreef(shf, indent + INDENT, "%s%N%T",
Packit Service 95ac19
				    "then", t1->left);
Packit Service 95ac19
			}
Packit Service 95ac19
		} while (t1->right && t1->right->type == TELIF);
Packit Service 95ac19
		if (t1->right != NULL) {
Packit Service 95ac19
			fptreef(shf, indent, Tft_end);
Packit Service 95ac19
			fptreef(shf, indent + INDENT, "%s%N%T",
Packit Service 95ac19
			    "else", t1->right);
Packit Service 95ac19
		}
Packit Service 95ac19
		fptreef(shf, indent, "%;fi ");
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TWHILE:
Packit Service 95ac19
	case TUNTIL:
Packit Service 95ac19
		/* 6 == strlen("while "/"until ") */
Packit Service 95ac19
		fptreef(shf, indent + 6, Tf_s_T,
Packit Service 95ac19
		    (t->type == TWHILE) ? "while" : "until",
Packit Service 95ac19
		    t->left);
Packit Service 95ac19
		fptreef(shf, indent, Tft_end);
Packit Service 95ac19
		fptreef(shf, indent + INDENT, "do%N%T", t->right);
Packit Service 95ac19
		fptreef(shf, indent, "%;done ");
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TBRACE:
Packit Service 95ac19
		fptreef(shf, indent + INDENT, "{%N%T", t->left);
Packit Service 95ac19
		fptreef(shf, indent, "%;} ");
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TCOPROC:
Packit Service 95ac19
		fptreef(shf, indent, "%T|& ", t->left);
Packit Service 95ac19
		prevent_semicolon = true;
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TASYNC:
Packit Service 95ac19
		fptreef(shf, indent, "%T& ", t->left);
Packit Service 95ac19
		prevent_semicolon = true;
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TFUNCT:
Packit Service 95ac19
		fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case TTIME:
Packit Service 95ac19
		fptreef(shf, indent, Tf_s_T, Ttime, t->left);
Packit Service 95ac19
		break;
Packit Service 95ac19
	default:
Packit Service 95ac19
		shf_puts("<botch>", shf);
Packit Service 95ac19
		prevent_semicolon = false;
Packit Service 95ac19
		break;
Packit Service 95ac19
	}
Packit Service 95ac19
	if ((ioact = t->ioact) != NULL) {
Packit Service 95ac19
		bool need_nl = false;
Packit Service 95ac19
Packit Service 95ac19
		while (*ioact != NULL)
Packit Service 95ac19
			pioact(shf, *ioact++);
Packit Service 95ac19
		/* Print here documents after everything else... */
Packit Service 95ac19
		ioact = t->ioact;
Packit Service 95ac19
		while (*ioact != NULL) {
Packit Service 95ac19
			struct ioword *iop = *ioact++;
Packit Service 95ac19
Packit Service 95ac19
			/* heredoc is NULL when tracing (set -x) */
Packit Service 95ac19
			if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE &&
Packit Service 95ac19
			    iop->heredoc) {
Packit Service 95ac19
				shf_putc('\n', shf);
Packit Service 95ac19
				shf_puts(iop->heredoc, shf);
Packit Service 95ac19
				fptreef(shf, indent, Tf_s,
Packit Service 95ac19
				    evalstr(iop->delim, 0));
Packit Service 95ac19
				need_nl = true;
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * Last delimiter must be followed by a newline (this
Packit Service 95ac19
		 * often leads to an extra blank line, but it's not
Packit Service 95ac19
		 * worth worrying about)
Packit Service 95ac19
		 */
Packit Service 95ac19
		if (need_nl) {
Packit Service 95ac19
			shf_putc('\n', shf);
Packit Service 95ac19
			prevent_semicolon = true;
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
pioact(struct shf *shf, struct ioword *iop)
Packit Service 95ac19
{
Packit Service 95ac19
	unsigned short flag = iop->ioflag;
Packit Service 95ac19
	unsigned short type = flag & IOTYPE;
Packit Service 95ac19
	short expected;
Packit Service 95ac19
Packit Service 95ac19
	expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
Packit Service 95ac19
	    (type == IOCAT || type == IOWRITE) ? 1 :
Packit Service 95ac19
	    (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
Packit Service 95ac19
	    iop->unit + 1;
Packit Service 95ac19
	if (iop->unit != expected)
Packit Service 95ac19
		shf_fprintf(shf, Tf_d, (int)iop->unit);
Packit Service 95ac19
Packit Service 95ac19
	switch (type) {
Packit Service 95ac19
	case IOREAD:
Packit Service 95ac19
		shf_putc('<', shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case IOHERE:
Packit Service 95ac19
		shf_puts("<<", shf);
Packit Service 95ac19
		if (flag & IOSKIP)
Packit Service 95ac19
			shf_putc('-', shf);
Packit Service 95ac19
		else if (flag & IOHERESTR)
Packit Service 95ac19
			shf_putc('<', shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case IOCAT:
Packit Service 95ac19
		shf_puts(">>", shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case IOWRITE:
Packit Service 95ac19
		shf_putc('>', shf);
Packit Service 95ac19
		if (flag & IOCLOB)
Packit Service 95ac19
			shf_putc('|', shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case IORDWR:
Packit Service 95ac19
		shf_puts("<>", shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	case IODUP:
Packit Service 95ac19
		shf_puts(flag & IORDUP ? "<&" : ">&", shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	}
Packit Service 95ac19
	/* name/delim are NULL when printing syntax errors */
Packit Service 95ac19
	if (type == IOHERE) {
Packit Service 95ac19
		if (iop->delim && !(iop->ioflag & IONDELIM))
Packit Service 95ac19
			wdvarput(shf, iop->delim, 0, WDS_TPUTS);
Packit Service 95ac19
	} else if (iop->ioname) {
Packit Service 95ac19
		if (flag & IONAMEXP)
Packit Service 95ac19
			print_value_quoted(shf, iop->ioname);
Packit Service 95ac19
		else
Packit Service 95ac19
			wdvarput(shf, iop->ioname, 0, WDS_TPUTS);
Packit Service 95ac19
	}
Packit Service 95ac19
	shf_putc(' ', shf);
Packit Service 95ac19
	prevent_semicolon = false;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* variant of fputs for ptreef and wdstrip */
Packit Service 95ac19
static const char *
Packit Service 95ac19
wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
Packit Service 95ac19
{
Packit Service 95ac19
	int c;
Packit Service 95ac19
	const char *cs;
Packit Service 95ac19
Packit Service 95ac19
	/*-
Packit Service 95ac19
	 * problems:
Packit Service 95ac19
	 *	`...` -> $(...)
Packit Service 95ac19
	 *	'foo' -> "foo"
Packit Service 95ac19
	 *	x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
Packit Service 95ac19
	 *	x${foo:-'hi'} -> x${foo:-hi}
Packit Service 95ac19
	 * could change encoding to:
Packit Service 95ac19
	 *	OQUOTE ["'] ... CQUOTE ["']
Packit Service 95ac19
	 *	COMSUB [(`] ...\0	(handle $ ` \ and maybe " in `...` case)
Packit Service 95ac19
	 */
Packit Service 95ac19
	while (/* CONSTCOND */ 1)
Packit Service 95ac19
		switch (*wp++) {
Packit Service 95ac19
		case EOS:
Packit Service 95ac19
			return (--wp);
Packit Service 95ac19
		case ADELIM:
Packit Service 95ac19
			if (ord(*wp) == ORD(/*{*/ '}')) {
Packit Service 95ac19
				++wp;
Packit Service 95ac19
				goto wdvarput_csubst;
Packit Service 95ac19
			}
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
		case CHAR:
Packit Service 95ac19
			c = ord(*wp++);
Packit Service 95ac19
			shf_putc(c, shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case QCHAR:
Packit Service 95ac19
			c = ord(*wp++);
Packit Service 95ac19
			if (opmode & WDS_TPUTS)
Packit Service 95ac19
				switch (c) {
Packit Service 95ac19
				case ORD('\n'):
Packit Service 95ac19
					if (quotelevel == 0) {
Packit Service 95ac19
						c = ORD('\'');
Packit Service 95ac19
						shf_putc(c, shf);
Packit Service 95ac19
						shf_putc(ORD('\n'), shf);
Packit Service 95ac19
					}
Packit Service 95ac19
					break;
Packit Service 95ac19
				default:
Packit Service 95ac19
					if (quotelevel == 0)
Packit Service 95ac19
						/* FALLTHROUGH */
Packit Service 95ac19
				case ORD('"'):
Packit Service 95ac19
				case ORD('`'):
Packit Service 95ac19
				case ORD('$'):
Packit Service 95ac19
				case ORD('\\'):
Packit Service 95ac19
					  shf_putc(ORD('\\'), shf);
Packit Service 95ac19
					break;
Packit Service 95ac19
				}
Packit Service 95ac19
			shf_putc(c, shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case COMASUB:
Packit Service 95ac19
		case COMSUB:
Packit Service 95ac19
			shf_puts("$(", shf);
Packit Service 95ac19
			cs = ")";
Packit Service 95ac19
			if (ord(*wp) == ORD('(' /*)*/))
Packit Service 95ac19
				shf_putc(' ', shf);
Packit Service 95ac19
 pSUB:
Packit Service 95ac19
			while ((c = *wp++) != 0)
Packit Service 95ac19
				shf_putc(c, shf);
Packit Service 95ac19
			shf_puts(cs, shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case FUNASUB:
Packit Service 95ac19
		case FUNSUB:
Packit Service 95ac19
			c = ORD(' ');
Packit Service 95ac19
			if (0)
Packit Service 95ac19
				/* FALLTHROUGH */
Packit Service 95ac19
		case VALSUB:
Packit Service 95ac19
			  c = ORD('|');
Packit Service 95ac19
			shf_putc('$', shf);
Packit Service 95ac19
			shf_putc('{', shf);
Packit Service 95ac19
			shf_putc(c, shf);
Packit Service 95ac19
			cs = ";}";
Packit Service 95ac19
			goto pSUB;
Packit Service 95ac19
		case EXPRSUB:
Packit Service 95ac19
			shf_puts("$((", shf);
Packit Service 95ac19
			cs = "))";
Packit Service 95ac19
			goto pSUB;
Packit Service 95ac19
		case OQUOTE:
Packit Service 95ac19
			if (opmode & WDS_TPUTS) {
Packit Service 95ac19
				quotelevel++;
Packit Service 95ac19
				shf_putc('"', shf);
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
		case CQUOTE:
Packit Service 95ac19
			if (opmode & WDS_TPUTS) {
Packit Service 95ac19
				if (quotelevel)
Packit Service 95ac19
					quotelevel--;
Packit Service 95ac19
				shf_putc('"', shf);
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
		case OSUBST:
Packit Service 95ac19
			shf_putc('$', shf);
Packit Service 95ac19
			if (ord(*wp++) == ORD('{'))
Packit Service 95ac19
				shf_putc('{', shf);
Packit Service 95ac19
			while ((c = *wp++) != 0)
Packit Service 95ac19
				shf_putc(c, shf);
Packit Service 95ac19
			wp = wdvarput(shf, wp, 0, opmode);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case CSUBST:
Packit Service 95ac19
			if (ord(*wp++) == ORD('}')) {
Packit Service 95ac19
 wdvarput_csubst:
Packit Service 95ac19
				shf_putc('}', shf);
Packit Service 95ac19
			}
Packit Service 95ac19
			return (wp);
Packit Service 95ac19
		case OPAT:
Packit Service 95ac19
			shf_putchar(*wp++, shf);
Packit Service 95ac19
			shf_putc('(', shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case SPAT:
Packit Service 95ac19
			c = ORD('|');
Packit Service 95ac19
			if (0)
Packit Service 95ac19
				/* FALLTHROUGH */
Packit Service 95ac19
		case CPAT:
Packit Service 95ac19
			  c = ORD(/*(*/ ')');
Packit Service 95ac19
			shf_putc(c, shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * this is the _only_ way to reliably handle
Packit Service 95ac19
 * variable args with an ANSI compiler
Packit Service 95ac19
 */
Packit Service 95ac19
/* VARARGS */
Packit Service 95ac19
void
Packit Service 95ac19
fptreef(struct shf *shf, int indent, const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	vfptreef(shf, indent, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* VARARGS */
Packit Service 95ac19
char *
Packit Service 95ac19
snptreef(char *s, ssize_t n, const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
	struct shf shf;
Packit Service 95ac19
Packit Service 95ac19
	shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf;;
Packit Service 95ac19
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	vfptreef(&shf, 0, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
Packit Service 95ac19
	/* shf_sclose NUL terminates */
Packit Service 95ac19
	return (shf_sclose(&shf));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
Packit Service 95ac19
{
Packit Service 95ac19
	int c;
Packit Service 95ac19
Packit Service 95ac19
	while ((c = ord(*fmt++))) {
Packit Service 95ac19
		if (c == '%') {
Packit Service 95ac19
			switch ((c = ord(*fmt++))) {
Packit Service 95ac19
			case ORD('c'):
Packit Service 95ac19
				/* character (octet, probably) */
Packit Service 95ac19
				shf_putchar(va_arg(va, int), shf);
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('s'):
Packit Service 95ac19
				/* string */
Packit Service 95ac19
				shf_puts(va_arg(va, char *), shf);
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('S'):
Packit Service 95ac19
				/* word */
Packit Service 95ac19
				wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS);
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('d'):
Packit Service 95ac19
				/* signed decimal */
Packit Service 95ac19
				shf_fprintf(shf, Tf_d, va_arg(va, int));
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('u'):
Packit Service 95ac19
				/* unsigned decimal */
Packit Service 95ac19
				shf_fprintf(shf, "%u", va_arg(va, unsigned int));
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('T'):
Packit Service 95ac19
				/* format tree */
Packit Service 95ac19
				ptree(va_arg(va, struct op *), indent, shf);
Packit Service 95ac19
				goto dont_trash_prevent_semicolon;
Packit Service 95ac19
			case ORD(';'):
Packit Service 95ac19
				/* newline or ; */
Packit Service 95ac19
			case ORD('N'):
Packit Service 95ac19
				/* newline or space */
Packit Service 95ac19
				if (shf->flags & SHF_STRING) {
Packit Service 95ac19
					if ((unsigned int)c == ORD(';') &&
Packit Service 95ac19
					    !prevent_semicolon)
Packit Service 95ac19
						shf_putc(';', shf);
Packit Service 95ac19
					shf_putc(' ', shf);
Packit Service 95ac19
				} else {
Packit Service 95ac19
					int i;
Packit Service 95ac19
Packit Service 95ac19
					shf_putc('\n', shf);
Packit Service 95ac19
					i = indent;
Packit Service 95ac19
					while (i >= 8) {
Packit Service 95ac19
						shf_putc('\t', shf);
Packit Service 95ac19
						i -= 8;
Packit Service 95ac19
					}
Packit Service 95ac19
					while (i--)
Packit Service 95ac19
						shf_putc(' ', shf);
Packit Service 95ac19
				}
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('R'):
Packit Service 95ac19
				/* I/O redirection */
Packit Service 95ac19
				pioact(shf, va_arg(va, struct ioword *));
Packit Service 95ac19
				break;
Packit Service 95ac19
			default:
Packit Service 95ac19
				shf_putc(c, shf);
Packit Service 95ac19
				break;
Packit Service 95ac19
			}
Packit Service 95ac19
		} else
Packit Service 95ac19
			shf_putc(c, shf);
Packit Service 95ac19
		prevent_semicolon = false;
Packit Service 95ac19
 dont_trash_prevent_semicolon:
Packit Service 95ac19
		;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * copy tree (for function definition)
Packit Service 95ac19
 */
Packit Service 95ac19
struct op *
Packit Service 95ac19
tcopy(struct op *t, Area *ap)
Packit Service 95ac19
{
Packit Service 95ac19
	struct op *r;
Packit Service 95ac19
	const char **tw;
Packit Service 95ac19
	char **rw;
Packit Service 95ac19
Packit Service 95ac19
	if (t == NULL)
Packit Service 95ac19
		return (NULL);
Packit Service 95ac19
Packit Service 95ac19
	r = alloc(sizeof(struct op), ap);
Packit Service 95ac19
Packit Service 95ac19
	r->type = t->type;
Packit Service 95ac19
	r->u.evalflags = t->u.evalflags;
Packit Service 95ac19
Packit Service 95ac19
	if (t->type == TCASE)
Packit Service 95ac19
		r->str = wdcopy(t->str, ap);
Packit Service 95ac19
	else
Packit Service 95ac19
		strdupx(r->str, t->str, ap);
Packit Service 95ac19
Packit Service 95ac19
	if (t->vars == NULL)
Packit Service 95ac19
		r->vars = NULL;
Packit Service 95ac19
	else {
Packit Service 95ac19
		tw = (const char **)t->vars;
Packit Service 95ac19
		while (*tw)
Packit Service 95ac19
			++tw;
Packit Service 95ac19
		rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
Packit Service 95ac19
		    sizeof(*tw), ap);
Packit Service 95ac19
		tw = (const char **)t->vars;
Packit Service 95ac19
		while (*tw)
Packit Service 95ac19
			*rw++ = wdcopy(*tw++, ap);
Packit Service 95ac19
		*rw = NULL;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if (t->args == NULL)
Packit Service 95ac19
		r->args = NULL;
Packit Service 95ac19
	else {
Packit Service 95ac19
		tw = t->args;
Packit Service 95ac19
		while (*tw)
Packit Service 95ac19
			++tw;
Packit Service 95ac19
		r->args = (const char **)(rw = alloc2(tw - t->args + 1,
Packit Service 95ac19
		    sizeof(*tw), ap));
Packit Service 95ac19
		tw = t->args;
Packit Service 95ac19
		while (*tw)
Packit Service 95ac19
			*rw++ = wdcopy(*tw++, ap);
Packit Service 95ac19
		*rw = NULL;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
Packit Service 95ac19
Packit Service 95ac19
	r->left = tcopy(t->left, ap);
Packit Service 95ac19
	r->right = tcopy(t->right, ap);
Packit Service 95ac19
	r->lineno = t->lineno;
Packit Service 95ac19
Packit Service 95ac19
	return (r);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
char *
Packit Service 95ac19
wdcopy(const char *wp, Area *ap)
Packit Service 95ac19
{
Packit Service 95ac19
	size_t len;
Packit Service 95ac19
Packit Service 95ac19
	len = wdscan(wp, EOS) - wp;
Packit Service 95ac19
	return (memcpy(alloc(len, ap), wp, len));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* return the position of prefix c in wp plus 1 */
Packit Service 95ac19
const char *
Packit Service 95ac19
wdscan(const char *wp, int c)
Packit Service 95ac19
{
Packit Service 95ac19
	int nest = 0;
Packit Service 95ac19
Packit Service 95ac19
	while (/* CONSTCOND */ 1)
Packit Service 95ac19
		switch (*wp++) {
Packit Service 95ac19
		case EOS:
Packit Service 95ac19
			return (wp);
Packit Service 95ac19
		case ADELIM:
Packit Service 95ac19
			if (c == ADELIM && nest == 0)
Packit Service 95ac19
				return (wp + 1);
Packit Service 95ac19
			if (ord(*wp) == ORD(/*{*/ '}'))
Packit Service 95ac19
				goto wdscan_csubst;
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
		case CHAR:
Packit Service 95ac19
		case QCHAR:
Packit Service 95ac19
			wp++;
Packit Service 95ac19
			break;
Packit Service 95ac19
		case COMASUB:
Packit Service 95ac19
		case COMSUB:
Packit Service 95ac19
		case FUNASUB:
Packit Service 95ac19
		case FUNSUB:
Packit Service 95ac19
		case VALSUB:
Packit Service 95ac19
		case EXPRSUB:
Packit Service 95ac19
			while (*wp++ != 0)
Packit Service 95ac19
				;
Packit Service 95ac19
			break;
Packit Service 95ac19
		case OQUOTE:
Packit Service 95ac19
		case CQUOTE:
Packit Service 95ac19
			break;
Packit Service 95ac19
		case OSUBST:
Packit Service 95ac19
			nest++;
Packit Service 95ac19
			while (*wp++ != '\0')
Packit Service 95ac19
				;
Packit Service 95ac19
			break;
Packit Service 95ac19
		case CSUBST:
Packit Service 95ac19
 wdscan_csubst:
Packit Service 95ac19
			wp++;
Packit Service 95ac19
			if (c == CSUBST && nest == 0)
Packit Service 95ac19
				return (wp);
Packit Service 95ac19
			nest--;
Packit Service 95ac19
			break;
Packit Service 95ac19
		case OPAT:
Packit Service 95ac19
			nest++;
Packit Service 95ac19
			wp++;
Packit Service 95ac19
			break;
Packit Service 95ac19
		case SPAT:
Packit Service 95ac19
		case CPAT:
Packit Service 95ac19
			if (c == wp[-1] && nest == 0)
Packit Service 95ac19
				return (wp);
Packit Service 95ac19
			if (wp[-1] == CPAT)
Packit Service 95ac19
				nest--;
Packit Service 95ac19
			break;
Packit Service 95ac19
		default:
Packit Service 95ac19
			internal_warningf(
Packit Service 95ac19
			    "wdscan: unknown char 0x%X (carrying on)",
Packit Service 95ac19
			    (unsigned char)wp[-1]);
Packit Service 95ac19
		}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * return a copy of wp without any of the mark up characters and with
Packit Service 95ac19
 * quote characters (" ' \) stripped. (string is allocated from ATEMP)
Packit Service 95ac19
 */
Packit Service 95ac19
char *
Packit Service 95ac19
wdstrip(const char *wp, int opmode)
Packit Service 95ac19
{
Packit Service 95ac19
	struct shf shf;
Packit Service 95ac19
Packit Service 95ac19
	shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf;;
Packit Service 95ac19
	wdvarput(&shf, wp, 0, opmode);
Packit Service 95ac19
	/* shf_sclose NUL terminates */
Packit Service 95ac19
	return (shf_sclose(&shf));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static struct ioword **
Packit Service 95ac19
iocopy(struct ioword **iow, Area *ap)
Packit Service 95ac19
{
Packit Service 95ac19
	struct ioword **ior;
Packit Service 95ac19
	int i;
Packit Service 95ac19
Packit Service 95ac19
	ior = iow;
Packit Service 95ac19
	while (*ior)
Packit Service 95ac19
		++ior;
Packit Service 95ac19
	ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
Packit Service 95ac19
Packit Service 95ac19
	for (i = 0; iow[i] != NULL; i++) {
Packit Service 95ac19
		struct ioword *p, *q;
Packit Service 95ac19
Packit Service 95ac19
		p = iow[i];
Packit Service 95ac19
		q = alloc(sizeof(struct ioword), ap);
Packit Service 95ac19
		ior[i] = q;
Packit Service 95ac19
		*q = *p;
Packit Service 95ac19
		if (p->ioname != NULL)
Packit Service 95ac19
			q->ioname = wdcopy(p->ioname, ap);
Packit Service 95ac19
		if (p->delim != NULL)
Packit Service 95ac19
			q->delim = wdcopy(p->delim, ap);
Packit Service 95ac19
		if (p->heredoc != NULL)
Packit Service 95ac19
			strdupx(q->heredoc, p->heredoc, ap);
Packit Service 95ac19
	}
Packit Service 95ac19
	ior[i] = NULL;
Packit Service 95ac19
Packit Service 95ac19
	return (ior);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * free tree (for function definition)
Packit Service 95ac19
 */
Packit Service 95ac19
void
Packit Service 95ac19
tfree(struct op *t, Area *ap)
Packit Service 95ac19
{
Packit Service 95ac19
	char **w;
Packit Service 95ac19
Packit Service 95ac19
	if (t == NULL)
Packit Service 95ac19
		return;
Packit Service 95ac19
Packit Service 95ac19
	afree(t->str, ap);
Packit Service 95ac19
Packit Service 95ac19
	if (t->vars != NULL) {
Packit Service 95ac19
		for (w = t->vars; *w != NULL; w++)
Packit Service 95ac19
			afree(*w, ap);
Packit Service 95ac19
		afree(t->vars, ap);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if (t->args != NULL) {
Packit Service 95ac19
		/*XXX we assume the caller is right */
Packit Service 95ac19
		union mksh_ccphack cw;
Packit Service 95ac19
Packit Service 95ac19
		cw.ro = t->args;
Packit Service 95ac19
		for (w = cw.rw; *w != NULL; w++)
Packit Service 95ac19
			afree(*w, ap);
Packit Service 95ac19
		afree(t->args, ap);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if (t->ioact != NULL)
Packit Service 95ac19
		iofree(t->ioact, ap);
Packit Service 95ac19
Packit Service 95ac19
	tfree(t->left, ap);
Packit Service 95ac19
	tfree(t->right, ap);
Packit Service 95ac19
Packit Service 95ac19
	afree(t, ap);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
iofree(struct ioword **iow, Area *ap)
Packit Service 95ac19
{
Packit Service 95ac19
	struct ioword **iop;
Packit Service 95ac19
	struct ioword *p;
Packit Service 95ac19
Packit Service 95ac19
	iop = iow;
Packit Service 95ac19
	while ((p = *iop++) != NULL) {
Packit Service 95ac19
		afree(p->ioname, ap);
Packit Service 95ac19
		afree(p->delim, ap);
Packit Service 95ac19
		afree(p->heredoc, ap);
Packit Service 95ac19
		afree(p, ap);
Packit Service 95ac19
	}
Packit Service 95ac19
	afree(iow, ap);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
Packit Service 95ac19
{
Packit Service 95ac19
	if (isksh)
Packit Service 95ac19
		fptreef(shf, i, "%s %s %T", Tfunction, k, v);
Packit Service 95ac19
	else if (ktsearch(&keywords, k, hash(k)))
Packit Service 95ac19
		fptreef(shf, i, "%s %s() %T", Tfunction, k, v);
Packit Service 95ac19
	else
Packit Service 95ac19
		fptreef(shf, i, "%s() %T", k, v);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
Packit Service 95ac19
/* for jobs.c */
Packit Service 95ac19
void
Packit Service 95ac19
vistree(char *dst, size_t sz, struct op *t)
Packit Service 95ac19
{
Packit Service 95ac19
	unsigned int c;
Packit Service 95ac19
	char *cp, *buf;
Packit Service 95ac19
	size_t n;
Packit Service 95ac19
Packit Service 95ac19
	buf = alloc(sz + 16, ATEMP);
Packit Service 95ac19
	snptreef(buf, sz + 16, Tf_T, t);
Packit Service 95ac19
	cp = buf;
Packit Service 95ac19
 vist_loop:
Packit Service 95ac19
	if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
Packit Service 95ac19
		if (c == 0 || n >= sz)
Packit Service 95ac19
			/* NUL or not enough free space */
Packit Service 95ac19
			goto vist_out;
Packit Service 95ac19
		/* copy multibyte char */
Packit Service 95ac19
		sz -= n;
Packit Service 95ac19
		while (n--)
Packit Service 95ac19
			*dst++ = *cp++;
Packit Service 95ac19
		goto vist_loop;
Packit Service 95ac19
	}
Packit Service 95ac19
	if (--sz == 0 || (c = ord(*cp++)) == 0)
Packit Service 95ac19
		/* NUL or not enough free space */
Packit Service 95ac19
		goto vist_out;
Packit Service 95ac19
	if (ksh_isctrl(c)) {
Packit Service 95ac19
		/* C0 or C1 control character or DEL */
Packit Service 95ac19
		if (--sz == 0)
Packit Service 95ac19
			/* not enough free space for two chars */
Packit Service 95ac19
			goto vist_out;
Packit Service 95ac19
		*dst++ = '^';
Packit Service 95ac19
		c = ksh_unctrl(c);
Packit Service 95ac19
	} else if (UTFMODE && rtt2asc(c) > 0x7F) {
Packit Service 95ac19
		/* better not try to display broken multibyte chars */
Packit Service 95ac19
		/* also go easy on the Unicode: no U+FFFD here */
Packit Service 95ac19
		c = ORD('?');
Packit Service 95ac19
	}
Packit Service 95ac19
	*dst++ = c;
Packit Service 95ac19
	goto vist_loop;
Packit Service 95ac19
Packit Service 95ac19
 vist_out:
Packit Service 95ac19
	*dst = '\0';
Packit Service 95ac19
	afree(buf, ATEMP);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#ifdef DEBUG
Packit Service 95ac19
void
Packit Service 95ac19
dumpchar(struct shf *shf, int c)
Packit Service 95ac19
{
Packit Service 95ac19
	if (ksh_isctrl(c)) {
Packit Service 95ac19
		/* C0 or C1 control character or DEL */
Packit Service 95ac19
		shf_putc('^', shf);
Packit Service 95ac19
		c = ksh_unctrl(c);
Packit Service 95ac19
	}
Packit Service 95ac19
	shf_putc(c, shf);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* see: wdvarput */
Packit Service 95ac19
static const char *
Packit Service 95ac19
dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
Packit Service 95ac19
{
Packit Service 95ac19
	int c;
Packit Service 95ac19
Packit Service 95ac19
	while (/* CONSTCOND */ 1) {
Packit Service 95ac19
		switch(*wp++) {
Packit Service 95ac19
		case EOS:
Packit Service 95ac19
			shf_puts("EOS", shf);
Packit Service 95ac19
			return (--wp);
Packit Service 95ac19
		case ADELIM:
Packit Service 95ac19
			if (ord(*wp) == ORD(/*{*/ '}')) {
Packit Service 95ac19
				shf_puts(/*{*/ "]ADELIM(})", shf);
Packit Service 95ac19
				return (wp + 1);
Packit Service 95ac19
			}
Packit Service 95ac19
			shf_puts("ADELIM=", shf);
Packit Service 95ac19
			if (0)
Packit Service 95ac19
				/* FALLTHROUGH */
Packit Service 95ac19
		case CHAR:
Packit Service 95ac19
			  shf_puts("CHAR=", shf);
Packit Service 95ac19
			dumpchar(shf, *wp++);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case QCHAR:
Packit Service 95ac19
			shf_puts("QCHAR<", shf);
Packit Service 95ac19
			c = ord(*wp++);
Packit Service 95ac19
			if (quotelevel == 0 || c == ORD('"') ||
Packit Service 95ac19
			    c == ORD('\\') || ctype(c, C_DOLAR | C_GRAVE))
Packit Service 95ac19
				shf_putc('\\', shf);
Packit Service 95ac19
			dumpchar(shf, c);
Packit Service 95ac19
			goto closeandout;
Packit Service 95ac19
		case COMASUB:
Packit Service 95ac19
			shf_puts("COMASUB<", shf);
Packit Service 95ac19
			goto dumpsub;
Packit Service 95ac19
		case COMSUB:
Packit Service 95ac19
			shf_puts("COMSUB<", shf);
Packit Service 95ac19
 dumpsub:
Packit Service 95ac19
			while ((c = *wp++) != 0)
Packit Service 95ac19
				dumpchar(shf, c);
Packit Service 95ac19
 closeandout:
Packit Service 95ac19
			shf_putc('>', shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case FUNASUB:
Packit Service 95ac19
			shf_puts("FUNASUB<", shf);
Packit Service 95ac19
			goto dumpsub;
Packit Service 95ac19
		case FUNSUB:
Packit Service 95ac19
			shf_puts("FUNSUB<", shf);
Packit Service 95ac19
			goto dumpsub;
Packit Service 95ac19
		case VALSUB:
Packit Service 95ac19
			shf_puts("VALSUB<", shf);
Packit Service 95ac19
			goto dumpsub;
Packit Service 95ac19
		case EXPRSUB:
Packit Service 95ac19
			shf_puts("EXPRSUB<", shf);
Packit Service 95ac19
			goto dumpsub;
Packit Service 95ac19
		case OQUOTE:
Packit Service 95ac19
			shf_fprintf(shf, "OQUOTE{%d" /*}*/, ++quotelevel);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case CQUOTE:
Packit Service 95ac19
			shf_fprintf(shf, /*{*/ "%d}CQUOTE", quotelevel);
Packit Service 95ac19
			if (quotelevel)
Packit Service 95ac19
				quotelevel--;
Packit Service 95ac19
			else
Packit Service 95ac19
				shf_puts("(err)", shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case OSUBST:
Packit Service 95ac19
			shf_puts("OSUBST(", shf);
Packit Service 95ac19
			dumpchar(shf, *wp++);
Packit Service 95ac19
			shf_puts(")[", shf);
Packit Service 95ac19
			while ((c = *wp++) != 0)
Packit Service 95ac19
				dumpchar(shf, c);
Packit Service 95ac19
			shf_putc('|', shf);
Packit Service 95ac19
			wp = dumpwdvar_i(shf, wp, 0);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case CSUBST:
Packit Service 95ac19
			shf_puts("]CSUBST(", shf);
Packit Service 95ac19
			dumpchar(shf, *wp++);
Packit Service 95ac19
			shf_putc(')', shf);
Packit Service 95ac19
			return (wp);
Packit Service 95ac19
		case OPAT:
Packit Service 95ac19
			shf_puts("OPAT=", shf);
Packit Service 95ac19
			dumpchar(shf, *wp++);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case SPAT:
Packit Service 95ac19
			shf_puts("SPAT", shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		case CPAT:
Packit Service 95ac19
			shf_puts("CPAT", shf);
Packit Service 95ac19
			break;
Packit Service 95ac19
		default:
Packit Service 95ac19
			shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]);
Packit Service 95ac19
			break;
Packit Service 95ac19
		}
Packit Service 95ac19
		shf_putc(' ', shf);
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
void
Packit Service 95ac19
dumpwdvar(struct shf *shf, const char *wp)
Packit Service 95ac19
{
Packit Service 95ac19
	dumpwdvar_i(shf, wp, 0);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
dumpioact(struct shf *shf, struct op *t)
Packit Service 95ac19
{
Packit Service 95ac19
	struct ioword **ioact, *iop;
Packit Service 95ac19
Packit Service 95ac19
	if ((ioact = t->ioact) == NULL)
Packit Service 95ac19
		return;
Packit Service 95ac19
Packit Service 95ac19
	shf_puts("{IOACT", shf);
Packit Service 95ac19
	while ((iop = *ioact++) != NULL) {
Packit Service 95ac19
		unsigned short type = iop->ioflag & IOTYPE;
Packit Service 95ac19
#define DT(x) case x: shf_puts(#x, shf); break;
Packit Service 95ac19
#define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
Packit Service 95ac19
Packit Service 95ac19
		shf_putc(';', shf);
Packit Service 95ac19
		switch (type) {
Packit Service 95ac19
		DT(IOREAD)
Packit Service 95ac19
		DT(IOWRITE)
Packit Service 95ac19
		DT(IORDWR)
Packit Service 95ac19
		DT(IOHERE)
Packit Service 95ac19
		DT(IOCAT)
Packit Service 95ac19
		DT(IODUP)
Packit Service 95ac19
		default:
Packit Service 95ac19
			shf_fprintf(shf, "unk%d", type);
Packit Service 95ac19
		}
Packit Service 95ac19
		DB(IOEVAL)
Packit Service 95ac19
		DB(IOSKIP)
Packit Service 95ac19
		DB(IOCLOB)
Packit Service 95ac19
		DB(IORDUP)
Packit Service 95ac19
		DB(IONAMEXP)
Packit Service 95ac19
		DB(IOBASH)
Packit Service 95ac19
		DB(IOHERESTR)
Packit Service 95ac19
		DB(IONDELIM)
Packit Service 95ac19
		shf_fprintf(shf, ",unit=%d", (int)iop->unit);
Packit Service 95ac19
		if (iop->delim && !(iop->ioflag & IONDELIM)) {
Packit Service 95ac19
			shf_puts(",delim<", shf);
Packit Service 95ac19
			dumpwdvar(shf, iop->delim);
Packit Service 95ac19
			shf_putc('>', shf);
Packit Service 95ac19
		}
Packit Service 95ac19
		if (iop->ioname) {
Packit Service 95ac19
			if (iop->ioflag & IONAMEXP) {
Packit Service 95ac19
				shf_puts(",name=", shf);
Packit Service 95ac19
				print_value_quoted(shf, iop->ioname);
Packit Service 95ac19
			} else {
Packit Service 95ac19
				shf_puts(",name<", shf);
Packit Service 95ac19
				dumpwdvar(shf, iop->ioname);
Packit Service 95ac19
				shf_putc('>', shf);
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
		if (iop->heredoc) {
Packit Service 95ac19
			shf_puts(",heredoc=", shf);
Packit Service 95ac19
			print_value_quoted(shf, iop->heredoc);
Packit Service 95ac19
		}
Packit Service 95ac19
#undef DT
Packit Service 95ac19
#undef DB
Packit Service 95ac19
	}
Packit Service 95ac19
	shf_putc('}', shf);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
dumptree(struct shf *shf, struct op *t)
Packit Service 95ac19
{
Packit Service 95ac19
	int i, j;
Packit Service 95ac19
	const char **w, *name;
Packit Service 95ac19
	struct op *t1;
Packit Service 95ac19
	static int nesting;
Packit Service 95ac19
Packit Service 95ac19
	for (i = 0; i < nesting; ++i)
Packit Service 95ac19
		shf_putc('\t', shf);
Packit Service 95ac19
	++nesting;
Packit Service 95ac19
	shf_puts("{tree:" /*}*/, shf);
Packit Service 95ac19
	if (t == NULL) {
Packit Service 95ac19
		name = "(null)";
Packit Service 95ac19
		goto out;
Packit Service 95ac19
	}
Packit Service 95ac19
	dumpioact(shf, t);
Packit Service 95ac19
	switch (t->type) {
Packit Service 95ac19
#define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
Packit Service 95ac19
Packit Service 95ac19
	OPEN(TCOM)
Packit Service 95ac19
		if (t->vars) {
Packit Service 95ac19
			i = 0;
Packit Service 95ac19
			w = (const char **)t->vars;
Packit Service 95ac19
			while (*w) {
Packit Service 95ac19
				shf_putc('\n', shf);
Packit Service 95ac19
				for (j = 0; j < nesting; ++j)
Packit Service 95ac19
					shf_putc('\t', shf);
Packit Service 95ac19
				shf_fprintf(shf, " var%d<", i++);
Packit Service 95ac19
				dumpwdvar(shf, *w++);
Packit Service 95ac19
				shf_putc('>', shf);
Packit Service 95ac19
			}
Packit Service 95ac19
		} else
Packit Service 95ac19
			shf_puts(" #no-vars#", shf);
Packit Service 95ac19
		if (t->args) {
Packit Service 95ac19
			i = 0;
Packit Service 95ac19
			w = t->args;
Packit Service 95ac19
			while (*w) {
Packit Service 95ac19
				shf_putc('\n', shf);
Packit Service 95ac19
				for (j = 0; j < nesting; ++j)
Packit Service 95ac19
					shf_putc('\t', shf);
Packit Service 95ac19
				shf_fprintf(shf, " arg%d<", i++);
Packit Service 95ac19
				dumpwdvar(shf, *w++);
Packit Service 95ac19
				shf_putc('>', shf);
Packit Service 95ac19
			}
Packit Service 95ac19
		} else
Packit Service 95ac19
			shf_puts(" #no-args#", shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	OPEN(TEXEC)
Packit Service 95ac19
 dumpleftandout:
Packit Service 95ac19
		t = t->left;
Packit Service 95ac19
 dumpandout:
Packit Service 95ac19
		shf_putc('\n', shf);
Packit Service 95ac19
		dumptree(shf, t);
Packit Service 95ac19
		break;
Packit Service 95ac19
	OPEN(TPAREN)
Packit Service 95ac19
		goto dumpleftandout;
Packit Service 95ac19
	OPEN(TPIPE)
Packit Service 95ac19
 dumpleftmidrightandout:
Packit Service 95ac19
		shf_putc('\n', shf);
Packit Service 95ac19
		dumptree(shf, t->left);
Packit Service 95ac19
/* middumprightandout: (unused) */
Packit Service 95ac19
		shf_fprintf(shf, "/%s:", name);
Packit Service 95ac19
 dumprightandout:
Packit Service 95ac19
		t = t->right;
Packit Service 95ac19
		goto dumpandout;
Packit Service 95ac19
	OPEN(TLIST)
Packit Service 95ac19
		goto dumpleftmidrightandout;
Packit Service 95ac19
	OPEN(TOR)
Packit Service 95ac19
		goto dumpleftmidrightandout;
Packit Service 95ac19
	OPEN(TAND)
Packit Service 95ac19
		goto dumpleftmidrightandout;
Packit Service 95ac19
	OPEN(TBANG)
Packit Service 95ac19
		goto dumprightandout;
Packit Service 95ac19
	OPEN(TDBRACKET)
Packit Service 95ac19
		i = 0;
Packit Service 95ac19
		w = t->args;
Packit Service 95ac19
		while (*w) {
Packit Service 95ac19
			shf_putc('\n', shf);
Packit Service 95ac19
			for (j = 0; j < nesting; ++j)
Packit Service 95ac19
				shf_putc('\t', shf);
Packit Service 95ac19
			shf_fprintf(shf, " arg%d<", i++);
Packit Service 95ac19
			dumpwdvar(shf, *w++);
Packit Service 95ac19
			shf_putc('>', shf);
Packit Service 95ac19
		}
Packit Service 95ac19
		break;
Packit Service 95ac19
	OPEN(TFOR)
Packit Service 95ac19
 dumpfor:
Packit Service 95ac19
		shf_fprintf(shf, " str<%s>", t->str);
Packit Service 95ac19
		if (t->vars != NULL) {
Packit Service 95ac19
			i = 0;
Packit Service 95ac19
			w = (const char **)t->vars;
Packit Service 95ac19
			while (*w) {
Packit Service 95ac19
				shf_putc('\n', shf);
Packit Service 95ac19
				for (j = 0; j < nesting; ++j)
Packit Service 95ac19
					shf_putc('\t', shf);
Packit Service 95ac19
				shf_fprintf(shf, " var%d<", i++);
Packit Service 95ac19
				dumpwdvar(shf, *w++);
Packit Service 95ac19
				shf_putc('>', shf);
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
		goto dumpleftandout;
Packit Service 95ac19
	OPEN(TSELECT)
Packit Service 95ac19
		goto dumpfor;
Packit Service 95ac19
	OPEN(TCASE)
Packit Service 95ac19
		shf_fprintf(shf, " str<%s>", t->str);
Packit Service 95ac19
		i = 0;
Packit Service 95ac19
		for (t1 = t->left; t1 != NULL; t1 = t1->right) {
Packit Service 95ac19
			shf_putc('\n', shf);
Packit Service 95ac19
			for (j = 0; j < nesting; ++j)
Packit Service 95ac19
				shf_putc('\t', shf);
Packit Service 95ac19
			shf_fprintf(shf, " sub%d[(", i);
Packit Service 95ac19
			w = (const char **)t1->vars;
Packit Service 95ac19
			while (*w) {
Packit Service 95ac19
				dumpwdvar(shf, *w);
Packit Service 95ac19
				if (w[1] != NULL)
Packit Service 95ac19
					shf_putc('|', shf);
Packit Service 95ac19
				++w;
Packit Service 95ac19
			}
Packit Service 95ac19
			shf_putc(')', shf);
Packit Service 95ac19
			dumpioact(shf, t);
Packit Service 95ac19
			shf_putc('\n', shf);
Packit Service 95ac19
			dumptree(shf, t1->left);
Packit Service 95ac19
			shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
Packit Service 95ac19
		}
Packit Service 95ac19
		break;
Packit Service 95ac19
	OPEN(TWHILE)
Packit Service 95ac19
		goto dumpleftmidrightandout;
Packit Service 95ac19
	OPEN(TUNTIL)
Packit Service 95ac19
		goto dumpleftmidrightandout;
Packit Service 95ac19
	OPEN(TBRACE)
Packit Service 95ac19
		goto dumpleftandout;
Packit Service 95ac19
	OPEN(TCOPROC)
Packit Service 95ac19
		goto dumpleftandout;
Packit Service 95ac19
	OPEN(TASYNC)
Packit Service 95ac19
		goto dumpleftandout;
Packit Service 95ac19
	OPEN(TFUNCT)
Packit Service 95ac19
		shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
Packit Service 95ac19
		    t->u.ksh_func ? Ttrue : Tfalse);
Packit Service 95ac19
		goto dumpleftandout;
Packit Service 95ac19
	OPEN(TTIME)
Packit Service 95ac19
		goto dumpleftandout;
Packit Service 95ac19
	OPEN(TIF)
Packit Service 95ac19
 dumpif:
Packit Service 95ac19
		shf_putc('\n', shf);
Packit Service 95ac19
		dumptree(shf, t->left);
Packit Service 95ac19
		t = t->right;
Packit Service 95ac19
		dumpioact(shf, t);
Packit Service 95ac19
		if (t->left != NULL) {
Packit Service 95ac19
			shf_puts(" /TTHEN:\n", shf);
Packit Service 95ac19
			dumptree(shf, t->left);
Packit Service 95ac19
		}
Packit Service 95ac19
		if (t->right && t->right->type == TELIF) {
Packit Service 95ac19
			shf_puts(" /TELIF:", shf);
Packit Service 95ac19
			t = t->right;
Packit Service 95ac19
			dumpioact(shf, t);
Packit Service 95ac19
			goto dumpif;
Packit Service 95ac19
		}
Packit Service 95ac19
		if (t->right != NULL) {
Packit Service 95ac19
			shf_puts(" /TELSE:\n", shf);
Packit Service 95ac19
			dumptree(shf, t->right);
Packit Service 95ac19
		}
Packit Service 95ac19
		break;
Packit Service 95ac19
	OPEN(TEOF)
Packit Service 95ac19
 dumpunexpected:
Packit Service 95ac19
		shf_puts(Tunexpected, shf);
Packit Service 95ac19
		break;
Packit Service 95ac19
	OPEN(TELIF)
Packit Service 95ac19
		goto dumpunexpected;
Packit Service 95ac19
	OPEN(TPAT)
Packit Service 95ac19
		goto dumpunexpected;
Packit Service 95ac19
	default:
Packit Service 95ac19
		name = "TINVALID";
Packit Service 95ac19
		shf_fprintf(shf, "{T<%d>:" /*}*/, t->type);
Packit Service 95ac19
		goto dumpunexpected;
Packit Service 95ac19
Packit Service 95ac19
#undef OPEN
Packit Service 95ac19
	}
Packit Service 95ac19
 out:
Packit Service 95ac19
	shf_fprintf(shf, /*{*/ " /%s}\n", name);
Packit Service 95ac19
	--nesting;
Packit Service 95ac19
}
Packit Service 95ac19
#endif