Home | History | Annotate | Download | only in src
      1 /*	$OpenBSD: tree.c,v 1.19 2008/08/11 21:50:35 jaredy Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
      5  *	Thorsten Glaser <tg (at) mirbsd.org>
      6  *
      7  * Provided that these terms and disclaimer and all copyright notices
      8  * are retained or reproduced in an accompanying document, permission
      9  * is granted to deal in this work without restriction, including un-
     10  * limited rights to use, publicly perform, distribute, sell, modify,
     11  * merge, give away, or sublicence.
     12  *
     13  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
     14  * the utmost extent permitted by applicable law, neither express nor
     15  * implied; without malicious intent or gross negligence. In no event
     16  * may a licensor, author or contributor be held liable for indirect,
     17  * direct, other damage, loss, or other issues arising in any way out
     18  * of dealing in the work, even if advised of the possibility of such
     19  * damage or existence of a defect, except proven that it results out
     20  * of said person's immediate fault when using the work as intended.
     21  */
     22 
     23 #include "sh.h"
     24 
     25 __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.30 2010/02/25 20:18:19 tg Exp $");
     26 
     27 #define INDENT	4
     28 
     29 #define tputc(c, shf) shf_putchar(c, shf);
     30 static void ptree(struct op *, int, struct shf *);
     31 static void pioact(struct shf *, int, struct ioword *);
     32 static void tputC(int, struct shf *);
     33 static void tputS(char *, struct shf *);
     34 static void vfptreef(struct shf *, int, const char *, va_list);
     35 static struct ioword **iocopy(struct ioword **, Area *);
     36 static void iofree(struct ioword **, Area *);
     37 
     38 /*
     39  * print a command tree
     40  */
     41 static void
     42 ptree(struct op *t, int indent, struct shf *shf)
     43 {
     44 	const char **w;
     45 	struct ioword **ioact;
     46 	struct op *t1;
     47 
     48  Chain:
     49 	if (t == NULL)
     50 		return;
     51 	switch (t->type) {
     52 	case TCOM:
     53 		if (t->vars)
     54 			for (w = (const char **)t->vars; *w != NULL; )
     55 				fptreef(shf, indent, "%S ", *w++);
     56 		else
     57 			shf_puts("#no-vars# ", shf);
     58 		if (t->args)
     59 			for (w = t->args; *w != NULL; )
     60 				fptreef(shf, indent, "%S ", *w++);
     61 		else
     62 			shf_puts("#no-args# ", shf);
     63 		break;
     64 	case TEXEC:
     65 		t = t->left;
     66 		goto Chain;
     67 	case TPAREN:
     68 		fptreef(shf, indent + 2, "( %T) ", t->left);
     69 		break;
     70 	case TPIPE:
     71 		fptreef(shf, indent, "%T| ", t->left);
     72 		t = t->right;
     73 		goto Chain;
     74 	case TLIST:
     75 		fptreef(shf, indent, "%T%;", t->left);
     76 		t = t->right;
     77 		goto Chain;
     78 	case TOR:
     79 	case TAND:
     80 		fptreef(shf, indent, "%T%s %T",
     81 		    t->left, (t->type==TOR) ? "||" : "&&", t->right);
     82 		break;
     83 	case TBANG:
     84 		shf_puts("! ", shf);
     85 		t = t->right;
     86 		goto Chain;
     87 	case TDBRACKET: {
     88 		int i;
     89 
     90 		shf_puts("[[", shf);
     91 		for (i = 0; t->args[i]; i++)
     92 			fptreef(shf, indent, " %S", t->args[i]);
     93 		shf_puts(" ]] ", shf);
     94 		break;
     95 	}
     96 	case TSELECT:
     97 		fptreef(shf, indent, "select %s ", t->str);
     98 		/* FALLTHROUGH */
     99 	case TFOR:
    100 		if (t->type == TFOR)
    101 			fptreef(shf, indent, "for %s ", t->str);
    102 		if (t->vars != NULL) {
    103 			shf_puts("in ", shf);
    104 			for (w = (const char **)t->vars; *w; )
    105 				fptreef(shf, indent, "%S ", *w++);
    106 			fptreef(shf, indent, "%;");
    107 		}
    108 		fptreef(shf, indent + INDENT, "do%N%T", t->left);
    109 		fptreef(shf, indent, "%;done ");
    110 		break;
    111 	case TCASE:
    112 		fptreef(shf, indent, "case %S in", t->str);
    113 		for (t1 = t->left; t1 != NULL; t1 = t1->right) {
    114 			fptreef(shf, indent, "%N(");
    115 			for (w = (const char **)t1->vars; *w != NULL; w++)
    116 				fptreef(shf, indent, "%S%c", *w,
    117 				    (w[1] != NULL) ? '|' : ')');
    118 			fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);
    119 		}
    120 		fptreef(shf, indent, "%Nesac ");
    121 		break;
    122 	case TIF:
    123 	case TELIF:
    124 		/* 3 == strlen("if ") */
    125 		fptreef(shf, indent + 3, "if %T", t->left);
    126 		for (;;) {
    127 			t = t->right;
    128 			if (t->left != NULL) {
    129 				fptreef(shf, indent, "%;");
    130 				fptreef(shf, indent + INDENT, "then%N%T",
    131 				    t->left);
    132 			}
    133 			if (t->right == NULL || t->right->type != TELIF)
    134 				break;
    135 			t = t->right;
    136 			fptreef(shf, indent, "%;");
    137 			/* 5 == strlen("elif ") */
    138 			fptreef(shf, indent + 5, "elif %T", t->left);
    139 		}
    140 		if (t->right != NULL) {
    141 			fptreef(shf, indent, "%;");
    142 			fptreef(shf, indent + INDENT, "else%;%T", t->right);
    143 		}
    144 		fptreef(shf, indent, "%;fi ");
    145 		break;
    146 	case TWHILE:
    147 	case TUNTIL:
    148 		/* 6 == strlen("while"/"until") */
    149 		fptreef(shf, indent + 6, "%s %T",
    150 		    (t->type==TWHILE) ? "while" : "until",
    151 		    t->left);
    152 		fptreef(shf, indent, "%;do");
    153 		fptreef(shf, indent + INDENT, "%;%T", t->right);
    154 		fptreef(shf, indent, "%;done ");
    155 		break;
    156 	case TBRACE:
    157 		fptreef(shf, indent + INDENT, "{%;%T", t->left);
    158 		fptreef(shf, indent, "%;} ");
    159 		break;
    160 	case TCOPROC:
    161 		fptreef(shf, indent, "%T|& ", t->left);
    162 		break;
    163 	case TASYNC:
    164 		fptreef(shf, indent, "%T& ", t->left);
    165 		break;
    166 	case TFUNCT:
    167 		fptreef(shf, indent,
    168 		    t->u.ksh_func ? "function %s %T" : "%s() %T",
    169 		    t->str, t->left);
    170 		break;
    171 	case TTIME:
    172 		fptreef(shf, indent, "time %T", t->left);
    173 		break;
    174 	default:
    175 		shf_puts("<botch>", shf);
    176 		break;
    177 	}
    178 	if ((ioact = t->ioact) != NULL) {
    179 		int	need_nl = 0;
    180 
    181 		while (*ioact != NULL)
    182 			pioact(shf, indent, *ioact++);
    183 		/* Print here documents after everything else... */
    184 		for (ioact = t->ioact; *ioact != NULL; ) {
    185 			struct ioword *iop = *ioact++;
    186 
    187 			/* heredoc is 0 when tracing (set -x) */
    188 			if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc &&
    189 			    /* iop->delim[1] == '<' means here string */
    190 			    (!iop->delim || iop->delim[1] != '<')) {
    191 				tputc('\n', shf);
    192 				shf_puts(iop->heredoc, shf);
    193 				fptreef(shf, indent, "%s",
    194 				    evalstr(iop->delim, 0));
    195 				need_nl = 1;
    196 			}
    197 		}
    198 		/* Last delimiter must be followed by a newline (this often
    199 		 * leads to an extra blank line, but its not worth worrying
    200 		 * about)
    201 		 */
    202 		if (need_nl)
    203 			tputc('\n', shf);
    204 	}
    205 }
    206 
    207 static void
    208 pioact(struct shf *shf, int indent, struct ioword *iop)
    209 {
    210 	int flag = iop->flag;
    211 	int type = flag & IOTYPE;
    212 	int expected;
    213 
    214 	expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
    215 	    (type == IOCAT || type == IOWRITE) ? 1 :
    216 	    (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
    217 	    iop->unit + 1;
    218 	if (iop->unit != expected)
    219 		shf_fprintf(shf, "%d", iop->unit);
    220 
    221 	switch (type) {
    222 	case IOREAD:
    223 		shf_puts("< ", shf);
    224 		break;
    225 	case IOHERE:
    226 		shf_puts(flag & IOSKIP ? "<<-" : "<<", shf);
    227 		break;
    228 	case IOCAT:
    229 		shf_puts(">> ", shf);
    230 		break;
    231 	case IOWRITE:
    232 		shf_puts(flag & IOCLOB ? ">| " : "> ", shf);
    233 		break;
    234 	case IORDWR:
    235 		shf_puts("<> ", shf);
    236 		break;
    237 	case IODUP:
    238 		shf_puts(flag & IORDUP ? "<&" : ">&", shf);
    239 		break;
    240 	}
    241 	/* name/delim are 0 when printing syntax errors */
    242 	if (type == IOHERE) {
    243 		if (iop->delim)
    244 			fptreef(shf, indent, "%s%S ",
    245 			    /* here string */ iop->delim[1] == '<' ? "" : " ",
    246 			    iop->delim);
    247 		else
    248 			tputc(' ', shf);
    249 	} else if (iop->name)
    250 		fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
    251 		    iop->name);
    252 }
    253 
    254 
    255 /*
    256  * variants of fputc, fputs for ptreef and snptreef
    257  */
    258 static void
    259 tputC(int c, struct shf *shf)
    260 {
    261 	if ((c&0x60) == 0) {		/* C0|C1 */
    262 		tputc((c&0x80) ? '$' : '^', shf);
    263 		tputc(((c&0x7F)|0x40), shf);
    264 	} else if ((c&0x7F) == 0x7F) {	/* DEL */
    265 		tputc((c&0x80) ? '$' : '^', shf);
    266 		tputc('?', shf);
    267 	} else
    268 		tputc(c, shf);
    269 }
    270 
    271 static void
    272 tputS(char *wp, struct shf *shf)
    273 {
    274 	int c, quotelevel = 0;
    275 
    276 	/* problems:
    277 	 *	`...` -> $(...)
    278 	 *	'foo' -> "foo"
    279 	 * could change encoding to:
    280 	 *	OQUOTE ["'] ... CQUOTE ["']
    281 	 *	COMSUB [(`] ...\0	(handle $ ` \ and maybe " in `...` case)
    282 	 */
    283 	while (1)
    284 		switch (*wp++) {
    285 		case EOS:
    286 			return;
    287 		case ADELIM:
    288 		case CHAR:
    289 			tputC(*wp++, shf);
    290 			break;
    291 		case QCHAR:
    292 			c = *wp++;
    293 			if (!quotelevel || (c == '"' || c == '`' || c == '$'))
    294 				tputc('\\', shf);
    295 			tputC(c, shf);
    296 			break;
    297 		case COMSUB:
    298 			shf_puts("$(", shf);
    299 			while (*wp != 0)
    300 				tputC(*wp++, shf);
    301 			tputc(')', shf);
    302 			wp++;
    303 			break;
    304 		case EXPRSUB:
    305 			shf_puts("$((", shf);
    306 			while (*wp != 0)
    307 				tputC(*wp++, shf);
    308 			shf_puts("))", shf);
    309 			wp++;
    310 			break;
    311 		case OQUOTE:
    312 			quotelevel++;
    313 			tputc('"', shf);
    314 			break;
    315 		case CQUOTE:
    316 			if (quotelevel)
    317 				quotelevel--;
    318 			tputc('"', shf);
    319 			break;
    320 		case OSUBST:
    321 			tputc('$', shf);
    322 			if (*wp++ == '{')
    323 				tputc('{', shf);
    324 			while ((c = *wp++) != 0)
    325 				tputC(c, shf);
    326 			break;
    327 		case CSUBST:
    328 			if (*wp++ == '}')
    329 				tputc('}', shf);
    330 			break;
    331 		case OPAT:
    332 			tputc(*wp++, shf);
    333 			tputc('(', shf);
    334 			break;
    335 		case SPAT:
    336 			tputc('|', shf);
    337 			break;
    338 		case CPAT:
    339 			tputc(')', shf);
    340 			break;
    341 		}
    342 }
    343 
    344 /*
    345  * this is the _only_ way to reliably handle
    346  * variable args with an ANSI compiler
    347  */
    348 /* VARARGS */
    349 int
    350 fptreef(struct shf *shf, int indent, const char *fmt, ...)
    351 {
    352 	va_list va;
    353 
    354 	va_start(va, fmt);
    355 
    356 	vfptreef(shf, indent, fmt, va);
    357 	va_end(va);
    358 	return (0);
    359 }
    360 
    361 /* VARARGS */
    362 char *
    363 snptreef(char *s, int n, const char *fmt, ...)
    364 {
    365 	va_list va;
    366 	struct shf shf;
    367 
    368 	shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
    369 
    370 	va_start(va, fmt);
    371 	vfptreef(&shf, 0, fmt, va);
    372 	va_end(va);
    373 
    374 	return (shf_sclose(&shf)); /* null terminates */
    375 }
    376 
    377 static void
    378 vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
    379 {
    380 	int c;
    381 
    382 	while ((c = *fmt++)) {
    383 		if (c == '%') {
    384 			switch ((c = *fmt++)) {
    385 			case 'c':
    386 				tputc(va_arg(va, int), shf);
    387 				break;
    388 			case 's':
    389 				shf_puts(va_arg(va, char *), shf);
    390 				break;
    391 			case 'S':	/* word */
    392 				tputS(va_arg(va, char *), shf);
    393 				break;
    394 			case 'd':	/* decimal */
    395 				shf_fprintf(shf, "%d", va_arg(va, int));
    396 				break;
    397 			case 'u':	/* decimal */
    398 				shf_fprintf(shf, "%u", va_arg(va, unsigned int));
    399 				break;
    400 			case 'T':	/* format tree */
    401 				ptree(va_arg(va, struct op *), indent, shf);
    402 				break;
    403 			case ';':	/* newline or ; */
    404 			case 'N':	/* newline or space */
    405 				if (shf->flags & SHF_STRING) {
    406 					if (c == ';')
    407 						tputc(';', shf);
    408 					tputc(' ', shf);
    409 				} else {
    410 					int i;
    411 
    412 					tputc('\n', shf);
    413 					for (i = indent; i >= 8; i -= 8)
    414 						tputc('\t', shf);
    415 					for (; i > 0; --i)
    416 						tputc(' ', shf);
    417 				}
    418 				break;
    419 			case 'R':
    420 				pioact(shf, indent, va_arg(va, struct ioword *));
    421 				break;
    422 			default:
    423 				tputc(c, shf);
    424 				break;
    425 			}
    426 		} else
    427 			tputc(c, shf);
    428 	}
    429 }
    430 
    431 /*
    432  * copy tree (for function definition)
    433  */
    434 struct op *
    435 tcopy(struct op *t, Area *ap)
    436 {
    437 	struct op *r;
    438 	const char **tw;
    439 	char **rw;
    440 
    441 	if (t == NULL)
    442 		return (NULL);
    443 
    444 	r = alloc(sizeof(struct op), ap);
    445 
    446 	r->type = t->type;
    447 	r->u.evalflags = t->u.evalflags;
    448 
    449 	if (t->type == TCASE)
    450 		r->str = wdcopy(t->str, ap);
    451 	else
    452 		strdupx(r->str, t->str, ap);
    453 
    454 	if (t->vars == NULL)
    455 		r->vars = NULL;
    456 	else {
    457 		for (tw = (const char **)t->vars; *tw++ != NULL; )
    458 			;
    459 		rw = r->vars = alloc((tw - (const char **)t->vars + 1) *
    460 		    sizeof(*tw), ap);
    461 		for (tw = (const char **)t->vars; *tw != NULL; )
    462 			*rw++ = wdcopy(*tw++, ap);
    463 		*rw = NULL;
    464 	}
    465 
    466 	if (t->args == NULL)
    467 		r->args = NULL;
    468 	else {
    469 		for (tw = t->args; *tw++ != NULL; )
    470 			;
    471 		r->args = (const char **)(rw = alloc((tw - t->args + 1) *
    472 		    sizeof(*tw), ap));
    473 		for (tw = t->args; *tw != NULL; )
    474 			*rw++ = wdcopy(*tw++, ap);
    475 		*rw = NULL;
    476 	}
    477 
    478 	r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
    479 
    480 	r->left = tcopy(t->left, ap);
    481 	r->right = tcopy(t->right, ap);
    482 	r->lineno = t->lineno;
    483 
    484 	return (r);
    485 }
    486 
    487 char *
    488 wdcopy(const char *wp, Area *ap)
    489 {
    490 	size_t len = wdscan(wp, EOS) - wp;
    491 	return (memcpy(alloc(len, ap), wp, len));
    492 }
    493 
    494 /* return the position of prefix c in wp plus 1 */
    495 const char *
    496 wdscan(const char *wp, int c)
    497 {
    498 	int nest = 0;
    499 
    500 	while (1)
    501 		switch (*wp++) {
    502 		case EOS:
    503 			return (wp);
    504 		case ADELIM:
    505 			if (c == ADELIM)
    506 				return (wp + 1);
    507 			/* FALLTHROUGH */
    508 		case CHAR:
    509 		case QCHAR:
    510 			wp++;
    511 			break;
    512 		case COMSUB:
    513 		case EXPRSUB:
    514 			while (*wp++ != 0)
    515 				;
    516 			break;
    517 		case OQUOTE:
    518 		case CQUOTE:
    519 			break;
    520 		case OSUBST:
    521 			nest++;
    522 			while (*wp++ != '\0')
    523 				;
    524 			break;
    525 		case CSUBST:
    526 			wp++;
    527 			if (c == CSUBST && nest == 0)
    528 				return (wp);
    529 			nest--;
    530 			break;
    531 		case OPAT:
    532 			nest++;
    533 			wp++;
    534 			break;
    535 		case SPAT:
    536 		case CPAT:
    537 			if (c == wp[-1] && nest == 0)
    538 				return (wp);
    539 			if (wp[-1] == CPAT)
    540 				nest--;
    541 			break;
    542 		default:
    543 			internal_warningf(
    544 			    "wdscan: unknown char 0x%x (carrying on)",
    545 			    wp[-1]);
    546 		}
    547 }
    548 
    549 /* return a copy of wp without any of the mark up characters and
    550  * with quote characters (" ' \) stripped.
    551  * (string is allocated from ATEMP)
    552  */
    553 char *
    554 wdstrip(const char *wp, bool keepq, bool make_magic)
    555 {
    556 	struct shf shf;
    557 	int c;
    558 
    559 	shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
    560 
    561 	/* problems:
    562 	 *	`...` -> $(...)
    563 	 *	x${foo:-"hi"} -> x${foo:-hi}
    564 	 *	x${foo:-'hi'} -> x${foo:-hi} unless keepq
    565 	 */
    566 	while (1)
    567 		switch (*wp++) {
    568 		case EOS:
    569 			return (shf_sclose(&shf)); /* null terminates */
    570 		case ADELIM:
    571 		case CHAR:
    572 			c = *wp++;
    573 			if (make_magic && (ISMAGIC(c) || c == '[' || c == NOT ||
    574 			    c == '-' || c == ']' || c == '*' || c == '?'))
    575 				shf_putchar(MAGIC, &shf);
    576 			shf_putchar(c, &shf);
    577 			break;
    578 		case QCHAR:
    579 			c = *wp++;
    580 			if (keepq && (c == '"' || c == '`' || c == '$' || c == '\\'))
    581 				shf_putchar('\\', &shf);
    582 			shf_putchar(c, &shf);
    583 			break;
    584 		case COMSUB:
    585 			shf_puts("$(", &shf);
    586 			while (*wp != 0)
    587 				shf_putchar(*wp++, &shf);
    588 			shf_putchar(')', &shf);
    589 			break;
    590 		case EXPRSUB:
    591 			shf_puts("$((", &shf);
    592 			while (*wp != 0)
    593 				shf_putchar(*wp++, &shf);
    594 			shf_puts("))", &shf);
    595 			break;
    596 		case OQUOTE:
    597 			break;
    598 		case CQUOTE:
    599 			break;
    600 		case OSUBST:
    601 			shf_putchar('$', &shf);
    602 			if (*wp++ == '{')
    603 			    shf_putchar('{', &shf);
    604 			while ((c = *wp++) != 0)
    605 				shf_putchar(c, &shf);
    606 			break;
    607 		case CSUBST:
    608 			if (*wp++ == '}')
    609 				shf_putchar('}', &shf);
    610 			break;
    611 		case OPAT:
    612 			if (make_magic) {
    613 				shf_putchar(MAGIC, &shf);
    614 				shf_putchar(*wp++ | 0x80, &shf);
    615 			} else {
    616 				shf_putchar(*wp++, &shf);
    617 				shf_putchar('(', &shf);
    618 			}
    619 			break;
    620 		case SPAT:
    621 			if (make_magic)
    622 				shf_putchar(MAGIC, &shf);
    623 			shf_putchar('|', &shf);
    624 			break;
    625 		case CPAT:
    626 			if (make_magic)
    627 				shf_putchar(MAGIC, &shf);
    628 			shf_putchar(')', &shf);
    629 			break;
    630 		}
    631 }
    632 
    633 static struct ioword **
    634 iocopy(struct ioword **iow, Area *ap)
    635 {
    636 	struct ioword **ior;
    637 	int i;
    638 
    639 	for (ior = iow; *ior++ != NULL; )
    640 		;
    641 	ior = alloc((ior - iow + 1) * sizeof(struct ioword *), ap);
    642 
    643 	for (i = 0; iow[i] != NULL; i++) {
    644 		struct ioword *p, *q;
    645 
    646 		p = iow[i];
    647 		q = alloc(sizeof(struct ioword), ap);
    648 		ior[i] = q;
    649 		*q = *p;
    650 		if (p->name != NULL)
    651 			q->name = wdcopy(p->name, ap);
    652 		if (p->delim != NULL)
    653 			q->delim = wdcopy(p->delim, ap);
    654 		if (p->heredoc != NULL)
    655 			strdupx(q->heredoc, p->heredoc, ap);
    656 	}
    657 	ior[i] = NULL;
    658 
    659 	return (ior);
    660 }
    661 
    662 /*
    663  * free tree (for function definition)
    664  */
    665 void
    666 tfree(struct op *t, Area *ap)
    667 {
    668 	char **w;
    669 
    670 	if (t == NULL)
    671 		return;
    672 
    673 	if (t->str != NULL)
    674 		afree(t->str, ap);
    675 
    676 	if (t->vars != NULL) {
    677 		for (w = t->vars; *w != NULL; w++)
    678 			afree(*w, ap);
    679 		afree(t->vars, ap);
    680 	}
    681 
    682 	if (t->args != NULL) {
    683 		union mksh_ccphack cw;
    684 		/* XXX we assume the caller is right */
    685 		cw.ro = t->args;
    686 		for (w = cw.rw; *w != NULL; w++)
    687 			afree(*w, ap);
    688 		afree(t->args, ap);
    689 	}
    690 
    691 	if (t->ioact != NULL)
    692 		iofree(t->ioact, ap);
    693 
    694 	tfree(t->left, ap);
    695 	tfree(t->right, ap);
    696 
    697 	afree(t, ap);
    698 }
    699 
    700 static void
    701 iofree(struct ioword **iow, Area *ap)
    702 {
    703 	struct ioword **iop;
    704 	struct ioword *p;
    705 
    706 	for (iop = iow; (p = *iop++) != NULL; ) {
    707 		if (p->name != NULL)
    708 			afree(p->name, ap);
    709 		if (p->delim != NULL)
    710 			afree(p->delim, ap);
    711 		if (p->heredoc != NULL)
    712 			afree(p->heredoc, ap);
    713 		afree(p, ap);
    714 	}
    715 	afree(iow, ap);
    716 }
    717