Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 1 | /* $OpenBSD: tree.c,v 1.21 2015/09/01 13:12:31 tedu Exp $ */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 2 | |
| 3 | /*- |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 4 | * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 5 | * 2011, 2012, 2013, 2015, 2016, 2017 |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 6 | * mirabilos <m@mirbsd.org> |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 7 | * |
| 8 | * Provided that these terms and disclaimer and all copyright notices |
| 9 | * are retained or reproduced in an accompanying document, permission |
| 10 | * is granted to deal in this work without restriction, including un- |
| 11 | * limited rights to use, publicly perform, distribute, sell, modify, |
| 12 | * merge, give away, or sublicence. |
| 13 | * |
| 14 | * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to |
| 15 | * the utmost extent permitted by applicable law, neither express nor |
| 16 | * implied; without malicious intent or gross negligence. In no event |
| 17 | * may a licensor, author or contributor be held liable for indirect, |
| 18 | * direct, other damage, loss, or other issues arising in any way out |
| 19 | * of dealing in the work, even if advised of the possibility of such |
| 20 | * damage or existence of a defect, except proven that it results out |
| 21 | * of said person's immediate fault when using the work as intended. |
| 22 | */ |
| 23 | |
| 24 | #include "sh.h" |
| 25 | |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 26 | __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.89 2017/04/12 16:46:23 tg Exp $"); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 27 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 28 | #define INDENT 8 |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 29 | |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 30 | static void ptree(struct op *, int, struct shf *); |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 31 | static void pioact(struct shf *, struct ioword *); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 32 | static const char *wdvarput(struct shf *, const char *, int, int); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 33 | static void vfptreef(struct shf *, int, const char *, va_list); |
| 34 | static struct ioword **iocopy(struct ioword **, Area *); |
| 35 | static void iofree(struct ioword **, Area *); |
| 36 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 37 | /* "foo& ; bar" and "foo |& ; bar" are invalid */ |
| 38 | static bool prevent_semicolon; |
| 39 | |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 40 | static const char Telif_pT[] = "elif %T"; |
| 41 | |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 42 | /* |
| 43 | * print a command tree |
| 44 | */ |
| 45 | static void |
| 46 | ptree(struct op *t, int indent, struct shf *shf) |
| 47 | { |
| 48 | const char **w; |
| 49 | struct ioword **ioact; |
| 50 | struct op *t1; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 51 | int i; |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 52 | const char *ccp; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 53 | |
| 54 | Chain: |
| 55 | if (t == NULL) |
| 56 | return; |
| 57 | switch (t->type) { |
| 58 | case TCOM: |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 59 | prevent_semicolon = false; |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 60 | /* special-case 'var=<<EOF' (cf. exec.c:execute) */ |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 61 | if (t->args && |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 62 | /* we have zero arguments, i.e. no program to run */ |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 63 | t->args[0] == NULL && |
| 64 | /* we have exactly one variable assignment */ |
| 65 | t->vars[0] != NULL && t->vars[1] == NULL && |
| 66 | /* we have exactly one I/O redirection */ |
| 67 | t->ioact != NULL && t->ioact[0] != NULL && |
| 68 | t->ioact[1] == NULL && |
| 69 | /* of type "here document" (or "here string") */ |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 70 | (t->ioact[0]->ioflag & IOTYPE) == IOHERE && |
| 71 | /* the variable assignment begins with a valid varname */ |
| 72 | (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] && |
| 73 | /* and has no right-hand side (i.e. "varname=") */ |
| 74 | ccp[0] == CHAR && ((ccp[1] == '=' && ccp[2] == EOS) || |
| 75 | /* or "varname+=" */ (ccp[1] == '+' && ccp[2] == CHAR && |
| 76 | ccp[3] == '=' && ccp[4] == EOS))) { |
| 77 | fptreef(shf, indent, Tf_S, t->vars[0]); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 78 | break; |
| 79 | } |
| 80 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 81 | if (t->vars) { |
| 82 | w = (const char **)t->vars; |
| 83 | while (*w) |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 84 | fptreef(shf, indent, Tf_S_, *w++); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 85 | } else |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 86 | shf_puts("#no-vars# ", shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 87 | if (t->args) { |
| 88 | w = t->args; |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 89 | if (*w && **w == CHAR) { |
| 90 | char *cp = wdstrip(*w++, WDS_TPUTS); |
| 91 | |
| 92 | if (valid_alias_name(cp)) |
| 93 | shf_putc('\\', shf); |
| 94 | shf_puts(cp, shf); |
| 95 | shf_putc(' ', shf); |
| 96 | afree(cp, ATEMP); |
| 97 | } |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 98 | while (*w) |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 99 | fptreef(shf, indent, Tf_S_, *w++); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 100 | } else |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 101 | shf_puts("#no-args# ", shf); |
| 102 | break; |
| 103 | case TEXEC: |
| 104 | t = t->left; |
| 105 | goto Chain; |
| 106 | case TPAREN: |
| 107 | fptreef(shf, indent + 2, "( %T) ", t->left); |
| 108 | break; |
| 109 | case TPIPE: |
| 110 | fptreef(shf, indent, "%T| ", t->left); |
| 111 | t = t->right; |
| 112 | goto Chain; |
| 113 | case TLIST: |
| 114 | fptreef(shf, indent, "%T%;", t->left); |
| 115 | t = t->right; |
| 116 | goto Chain; |
| 117 | case TOR: |
| 118 | case TAND: |
| 119 | fptreef(shf, indent, "%T%s %T", |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 120 | t->left, (t->type == TOR) ? "||" : "&&", t->right); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 121 | break; |
| 122 | case TBANG: |
| 123 | shf_puts("! ", shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 124 | prevent_semicolon = false; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 125 | t = t->right; |
| 126 | goto Chain; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 127 | case TDBRACKET: |
| 128 | w = t->args; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 129 | shf_puts("[[", shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 130 | while (*w) |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 131 | fptreef(shf, indent, Tf__S, *w++); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 132 | shf_puts(" ]] ", shf); |
| 133 | break; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 134 | case TSELECT: |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 135 | case TFOR: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 136 | fptreef(shf, indent, "%s %s ", |
| 137 | (t->type == TFOR) ? "for" : Tselect, t->str); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 138 | if (t->vars != NULL) { |
| 139 | shf_puts("in ", shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 140 | w = (const char **)t->vars; |
| 141 | while (*w) |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 142 | fptreef(shf, indent, Tf_S_, *w++); |
| 143 | fptreef(shf, indent, Tft_end); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 144 | } |
| 145 | fptreef(shf, indent + INDENT, "do%N%T", t->left); |
| 146 | fptreef(shf, indent, "%;done "); |
| 147 | break; |
| 148 | case TCASE: |
| 149 | fptreef(shf, indent, "case %S in", t->str); |
| 150 | for (t1 = t->left; t1 != NULL; t1 = t1->right) { |
| 151 | fptreef(shf, indent, "%N("); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 152 | w = (const char **)t1->vars; |
| 153 | while (*w) { |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 154 | fptreef(shf, indent, "%S%c", *w, |
| 155 | (w[1] != NULL) ? '|' : ')'); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 156 | ++w; |
| 157 | } |
| 158 | fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left, |
| 159 | t1->u.charflag); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 160 | } |
| 161 | fptreef(shf, indent, "%Nesac "); |
| 162 | break; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 163 | case TELIF: |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 164 | internal_errorf(TELIF_unexpected); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 165 | /* FALLTHROUGH */ |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 166 | case TIF: |
| 167 | i = 2; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 168 | t1 = t; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 169 | goto process_TIF; |
| 170 | do { |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 171 | t1 = t1->right; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 172 | i = 0; |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 173 | fptreef(shf, indent, Tft_end); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 174 | process_TIF: |
| 175 | /* 5 == strlen("elif ") */ |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 176 | fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left); |
| 177 | t1 = t1->right; |
| 178 | if (t1->left != NULL) { |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 179 | fptreef(shf, indent, Tft_end); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 180 | fptreef(shf, indent + INDENT, "%s%N%T", |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 181 | "then", t1->left); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 182 | } |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 183 | } while (t1->right && t1->right->type == TELIF); |
| 184 | if (t1->right != NULL) { |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 185 | fptreef(shf, indent, Tft_end); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 186 | fptreef(shf, indent + INDENT, "%s%N%T", |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 187 | "else", t1->right); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 188 | } |
| 189 | fptreef(shf, indent, "%;fi "); |
| 190 | break; |
| 191 | case TWHILE: |
| 192 | case TUNTIL: |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 193 | /* 6 == strlen("while "/"until ") */ |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 194 | fptreef(shf, indent + 6, Tf_s_T, |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 195 | (t->type == TWHILE) ? "while" : "until", |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 196 | t->left); |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 197 | fptreef(shf, indent, Tft_end); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 198 | fptreef(shf, indent + INDENT, "do%N%T", t->right); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 199 | fptreef(shf, indent, "%;done "); |
| 200 | break; |
| 201 | case TBRACE: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 202 | fptreef(shf, indent + INDENT, "{%N%T", t->left); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 203 | fptreef(shf, indent, "%;} "); |
| 204 | break; |
| 205 | case TCOPROC: |
| 206 | fptreef(shf, indent, "%T|& ", t->left); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 207 | prevent_semicolon = true; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 208 | break; |
| 209 | case TASYNC: |
| 210 | fptreef(shf, indent, "%T& ", t->left); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 211 | prevent_semicolon = true; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 212 | break; |
| 213 | case TFUNCT: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 214 | fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 215 | break; |
| 216 | case TTIME: |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 217 | fptreef(shf, indent, Tf_s_T, Ttime, t->left); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 218 | break; |
| 219 | default: |
| 220 | shf_puts("<botch>", shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 221 | prevent_semicolon = false; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 222 | break; |
| 223 | } |
| 224 | if ((ioact = t->ioact) != NULL) { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 225 | bool need_nl = false; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 226 | |
| 227 | while (*ioact != NULL) |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 228 | pioact(shf, *ioact++); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 229 | /* Print here documents after everything else... */ |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 230 | ioact = t->ioact; |
| 231 | while (*ioact != NULL) { |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 232 | struct ioword *iop = *ioact++; |
| 233 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 234 | /* heredoc is NULL when tracing (set -x) */ |
Elliott Hughes | b27ce95 | 2015-04-21 13:39:18 -0700 | [diff] [blame] | 235 | if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE && |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 236 | iop->heredoc) { |
| 237 | shf_putc('\n', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 238 | shf_puts(iop->heredoc, shf); |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 239 | fptreef(shf, indent, Tf_s, |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 240 | evalstr(iop->delim, 0)); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 241 | need_nl = true; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 242 | } |
| 243 | } |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 244 | /* |
| 245 | * Last delimiter must be followed by a newline (this |
| 246 | * often leads to an extra blank line, but it's not |
| 247 | * worth worrying about) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 248 | */ |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 249 | if (need_nl) { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 250 | shf_putc('\n', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 251 | prevent_semicolon = true; |
| 252 | } |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 253 | } |
| 254 | } |
| 255 | |
| 256 | static void |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 257 | pioact(struct shf *shf, struct ioword *iop) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 258 | { |
Elliott Hughes | b27ce95 | 2015-04-21 13:39:18 -0700 | [diff] [blame] | 259 | unsigned short flag = iop->ioflag; |
| 260 | unsigned short type = flag & IOTYPE; |
| 261 | short expected; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 262 | |
| 263 | expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 : |
| 264 | (type == IOCAT || type == IOWRITE) ? 1 : |
| 265 | (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit : |
| 266 | iop->unit + 1; |
| 267 | if (iop->unit != expected) |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 268 | shf_fprintf(shf, Tf_d, (int)iop->unit); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 269 | |
| 270 | switch (type) { |
| 271 | case IOREAD: |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 272 | shf_putc('<', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 273 | break; |
| 274 | case IOHERE: |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 275 | shf_puts("<<", shf); |
| 276 | if (flag & IOSKIP) |
| 277 | shf_putc('-', shf); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 278 | else if (flag & IOHERESTR) |
| 279 | shf_putc('<', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 280 | break; |
| 281 | case IOCAT: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 282 | shf_puts(">>", shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 283 | break; |
| 284 | case IOWRITE: |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 285 | shf_putc('>', shf); |
| 286 | if (flag & IOCLOB) |
| 287 | shf_putc('|', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 288 | break; |
| 289 | case IORDWR: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 290 | shf_puts("<>", shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 291 | break; |
| 292 | case IODUP: |
| 293 | shf_puts(flag & IORDUP ? "<&" : ">&", shf); |
| 294 | break; |
| 295 | } |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 296 | /* name/delim are NULL when printing syntax errors */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 297 | if (type == IOHERE) { |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 298 | if (iop->delim && !(iop->ioflag & IONDELIM)) |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 299 | wdvarput(shf, iop->delim, 0, WDS_TPUTS); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 300 | } else if (iop->ioname) { |
Elliott Hughes | b27ce95 | 2015-04-21 13:39:18 -0700 | [diff] [blame] | 301 | if (flag & IONAMEXP) |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 302 | print_value_quoted(shf, iop->ioname); |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 303 | else |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 304 | wdvarput(shf, iop->ioname, 0, WDS_TPUTS); |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 305 | } |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 306 | shf_putc(' ', shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 307 | prevent_semicolon = false; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 308 | } |
| 309 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 310 | /* variant of fputs for ptreef and wdstrip */ |
| 311 | static const char * |
| 312 | wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 313 | { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 314 | int c; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 315 | const char *cs; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 316 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 317 | /*- |
| 318 | * problems: |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 319 | * `...` -> $(...) |
| 320 | * 'foo' -> "foo" |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 321 | * x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 322 | * x${foo:-'hi'} -> x${foo:-hi} |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 323 | * could change encoding to: |
| 324 | * OQUOTE ["'] ... CQUOTE ["'] |
| 325 | * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case) |
| 326 | */ |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 327 | while (/* CONSTCOND */ 1) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 328 | switch (*wp++) { |
| 329 | case EOS: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 330 | return (--wp); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 331 | case ADELIM: |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 332 | if (*wp == /*{*/'}') { |
| 333 | ++wp; |
| 334 | goto wdvarput_csubst; |
| 335 | } |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 336 | /* FALLTHROUGH */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 337 | case CHAR: |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 338 | c = *wp++; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 339 | shf_putc(c, shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 340 | break; |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 341 | case QCHAR: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 342 | c = *wp++; |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 343 | if (opmode & WDS_TPUTS) |
| 344 | switch (c) { |
| 345 | case '\n': |
| 346 | if (quotelevel == 0) { |
| 347 | c = '\''; |
| 348 | shf_putc(c, shf); |
| 349 | shf_putc('\n', shf); |
| 350 | } |
| 351 | break; |
| 352 | default: |
| 353 | if (quotelevel == 0) |
| 354 | /* FALLTHROUGH */ |
| 355 | case '"': |
| 356 | case '`': |
| 357 | case '$': |
| 358 | case '\\': |
| 359 | shf_putc('\\', shf); |
| 360 | break; |
| 361 | } |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 362 | shf_putc(c, shf); |
| 363 | break; |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 364 | case COMASUB: |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 365 | case COMSUB: |
| 366 | shf_puts("$(", shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 367 | cs = ")"; |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 368 | if (*wp == '(' /*)*/) |
| 369 | shf_putc(' ', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 370 | pSUB: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 371 | while ((c = *wp++) != 0) |
| 372 | shf_putc(c, shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 373 | shf_puts(cs, shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 374 | break; |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 375 | case FUNASUB: |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 376 | case FUNSUB: |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 377 | c = ' '; |
| 378 | if (0) |
| 379 | /* FALLTHROUGH */ |
| 380 | case VALSUB: |
| 381 | c = '|'; |
| 382 | shf_putc('$', shf); |
| 383 | shf_putc('{', shf); |
| 384 | shf_putc(c, shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 385 | cs = ";}"; |
| 386 | goto pSUB; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 387 | case EXPRSUB: |
| 388 | shf_puts("$((", shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 389 | cs = "))"; |
| 390 | goto pSUB; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 391 | case OQUOTE: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 392 | if (opmode & WDS_TPUTS) { |
| 393 | quotelevel++; |
| 394 | shf_putc('"', shf); |
| 395 | } |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 396 | break; |
| 397 | case CQUOTE: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 398 | if (opmode & WDS_TPUTS) { |
| 399 | if (quotelevel) |
| 400 | quotelevel--; |
| 401 | shf_putc('"', shf); |
| 402 | } |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 403 | break; |
| 404 | case OSUBST: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 405 | shf_putc('$', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 406 | if (*wp++ == '{') |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 407 | shf_putc('{', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 408 | while ((c = *wp++) != 0) |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 409 | shf_putc(c, shf); |
| 410 | wp = wdvarput(shf, wp, 0, opmode); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 411 | break; |
| 412 | case CSUBST: |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 413 | if (*wp++ == '}') { |
| 414 | wdvarput_csubst: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 415 | shf_putc('}', shf); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 416 | } |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 417 | return (wp); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 418 | case OPAT: |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 419 | shf_putchar(*wp++, shf); |
| 420 | shf_putc('(', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 421 | break; |
| 422 | case SPAT: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 423 | c = '|'; |
| 424 | if (0) |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 425 | /* FALLTHROUGH */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 426 | case CPAT: |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 427 | c = /*(*/ ')'; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 428 | shf_putc(c, shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 429 | break; |
| 430 | } |
| 431 | } |
| 432 | |
| 433 | /* |
| 434 | * this is the _only_ way to reliably handle |
| 435 | * variable args with an ANSI compiler |
| 436 | */ |
| 437 | /* VARARGS */ |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 438 | void |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 439 | fptreef(struct shf *shf, int indent, const char *fmt, ...) |
| 440 | { |
| 441 | va_list va; |
| 442 | |
| 443 | va_start(va, fmt); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 444 | vfptreef(shf, indent, fmt, va); |
| 445 | va_end(va); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 446 | } |
| 447 | |
| 448 | /* VARARGS */ |
| 449 | char * |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 450 | snptreef(char *s, ssize_t n, const char *fmt, ...) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 451 | { |
| 452 | va_list va; |
| 453 | struct shf shf; |
| 454 | |
| 455 | shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf); |
| 456 | |
| 457 | va_start(va, fmt); |
| 458 | vfptreef(&shf, 0, fmt, va); |
| 459 | va_end(va); |
| 460 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 461 | /* shf_sclose NUL terminates */ |
| 462 | return (shf_sclose(&shf)); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 463 | } |
| 464 | |
| 465 | static void |
| 466 | vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) |
| 467 | { |
| 468 | int c; |
| 469 | |
| 470 | while ((c = *fmt++)) { |
| 471 | if (c == '%') { |
| 472 | switch ((c = *fmt++)) { |
| 473 | case 'c': |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 474 | /* character (octet, probably) */ |
| 475 | shf_putchar(va_arg(va, int), shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 476 | break; |
| 477 | case 's': |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 478 | /* string */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 479 | shf_puts(va_arg(va, char *), shf); |
| 480 | break; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 481 | case 'S': |
| 482 | /* word */ |
| 483 | wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 484 | break; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 485 | case 'd': |
| 486 | /* signed decimal */ |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 487 | shf_fprintf(shf, Tf_d, va_arg(va, int)); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 488 | break; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 489 | case 'u': |
| 490 | /* unsigned decimal */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 491 | shf_fprintf(shf, "%u", va_arg(va, unsigned int)); |
| 492 | break; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 493 | case 'T': |
| 494 | /* format tree */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 495 | ptree(va_arg(va, struct op *), indent, shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 496 | goto dont_trash_prevent_semicolon; |
| 497 | case ';': |
| 498 | /* newline or ; */ |
| 499 | case 'N': |
| 500 | /* newline or space */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 501 | if (shf->flags & SHF_STRING) { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 502 | if (c == ';' && !prevent_semicolon) |
| 503 | shf_putc(';', shf); |
| 504 | shf_putc(' ', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 505 | } else { |
| 506 | int i; |
| 507 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 508 | shf_putc('\n', shf); |
| 509 | i = indent; |
| 510 | while (i >= 8) { |
| 511 | shf_putc('\t', shf); |
| 512 | i -= 8; |
| 513 | } |
| 514 | while (i--) |
| 515 | shf_putc(' ', shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 516 | } |
| 517 | break; |
| 518 | case 'R': |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 519 | /* I/O redirection */ |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 520 | pioact(shf, va_arg(va, struct ioword *)); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 521 | break; |
| 522 | default: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 523 | shf_putc(c, shf); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 524 | break; |
| 525 | } |
| 526 | } else |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 527 | shf_putc(c, shf); |
| 528 | prevent_semicolon = false; |
| 529 | dont_trash_prevent_semicolon: |
| 530 | ; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 531 | } |
| 532 | } |
| 533 | |
| 534 | /* |
| 535 | * copy tree (for function definition) |
| 536 | */ |
| 537 | struct op * |
| 538 | tcopy(struct op *t, Area *ap) |
| 539 | { |
| 540 | struct op *r; |
| 541 | const char **tw; |
| 542 | char **rw; |
| 543 | |
| 544 | if (t == NULL) |
| 545 | return (NULL); |
| 546 | |
| 547 | r = alloc(sizeof(struct op), ap); |
| 548 | |
| 549 | r->type = t->type; |
| 550 | r->u.evalflags = t->u.evalflags; |
| 551 | |
| 552 | if (t->type == TCASE) |
| 553 | r->str = wdcopy(t->str, ap); |
| 554 | else |
| 555 | strdupx(r->str, t->str, ap); |
| 556 | |
| 557 | if (t->vars == NULL) |
| 558 | r->vars = NULL; |
| 559 | else { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 560 | tw = (const char **)t->vars; |
| 561 | while (*tw) |
| 562 | ++tw; |
| 563 | rw = r->vars = alloc2(tw - (const char **)t->vars + 1, |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 564 | sizeof(*tw), ap); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 565 | tw = (const char **)t->vars; |
| 566 | while (*tw) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 567 | *rw++ = wdcopy(*tw++, ap); |
| 568 | *rw = NULL; |
| 569 | } |
| 570 | |
| 571 | if (t->args == NULL) |
| 572 | r->args = NULL; |
| 573 | else { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 574 | tw = t->args; |
| 575 | while (*tw) |
| 576 | ++tw; |
| 577 | r->args = (const char **)(rw = alloc2(tw - t->args + 1, |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 578 | sizeof(*tw), ap)); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 579 | tw = t->args; |
| 580 | while (*tw) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 581 | *rw++ = wdcopy(*tw++, ap); |
| 582 | *rw = NULL; |
| 583 | } |
| 584 | |
| 585 | r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap); |
| 586 | |
| 587 | r->left = tcopy(t->left, ap); |
| 588 | r->right = tcopy(t->right, ap); |
| 589 | r->lineno = t->lineno; |
| 590 | |
| 591 | return (r); |
| 592 | } |
| 593 | |
| 594 | char * |
| 595 | wdcopy(const char *wp, Area *ap) |
| 596 | { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 597 | size_t len; |
| 598 | |
| 599 | len = wdscan(wp, EOS) - wp; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 600 | return (memcpy(alloc(len, ap), wp, len)); |
| 601 | } |
| 602 | |
| 603 | /* return the position of prefix c in wp plus 1 */ |
| 604 | const char * |
| 605 | wdscan(const char *wp, int c) |
| 606 | { |
| 607 | int nest = 0; |
| 608 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 609 | while (/* CONSTCOND */ 1) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 610 | switch (*wp++) { |
| 611 | case EOS: |
| 612 | return (wp); |
| 613 | case ADELIM: |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 614 | if (c == ADELIM && nest == 0) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 615 | return (wp + 1); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 616 | if (*wp == /*{*/'}') |
| 617 | goto wdscan_csubst; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 618 | /* FALLTHROUGH */ |
| 619 | case CHAR: |
| 620 | case QCHAR: |
| 621 | wp++; |
| 622 | break; |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 623 | case COMASUB: |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 624 | case COMSUB: |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 625 | case FUNASUB: |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 626 | case FUNSUB: |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 627 | case VALSUB: |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 628 | case EXPRSUB: |
| 629 | while (*wp++ != 0) |
| 630 | ; |
| 631 | break; |
| 632 | case OQUOTE: |
| 633 | case CQUOTE: |
| 634 | break; |
| 635 | case OSUBST: |
| 636 | nest++; |
| 637 | while (*wp++ != '\0') |
| 638 | ; |
| 639 | break; |
| 640 | case CSUBST: |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 641 | wdscan_csubst: |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 642 | wp++; |
| 643 | if (c == CSUBST && nest == 0) |
| 644 | return (wp); |
| 645 | nest--; |
| 646 | break; |
| 647 | case OPAT: |
| 648 | nest++; |
| 649 | wp++; |
| 650 | break; |
| 651 | case SPAT: |
| 652 | case CPAT: |
| 653 | if (c == wp[-1] && nest == 0) |
| 654 | return (wp); |
| 655 | if (wp[-1] == CPAT) |
| 656 | nest--; |
| 657 | break; |
| 658 | default: |
| 659 | internal_warningf( |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 660 | "wdscan: unknown char 0x%X (carrying on)", |
| 661 | (unsigned char)wp[-1]); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 662 | } |
| 663 | } |
| 664 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 665 | /* |
| 666 | * return a copy of wp without any of the mark up characters and with |
| 667 | * quote characters (" ' \) stripped. (string is allocated from ATEMP) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 668 | */ |
| 669 | char * |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 670 | wdstrip(const char *wp, int opmode) |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 671 | { |
| 672 | struct shf shf; |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 673 | |
| 674 | shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 675 | wdvarput(&shf, wp, 0, opmode); |
| 676 | /* shf_sclose NUL terminates */ |
| 677 | return (shf_sclose(&shf)); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 678 | } |
| 679 | |
| 680 | static struct ioword ** |
| 681 | iocopy(struct ioword **iow, Area *ap) |
| 682 | { |
| 683 | struct ioword **ior; |
| 684 | int i; |
| 685 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 686 | ior = iow; |
| 687 | while (*ior) |
| 688 | ++ior; |
| 689 | ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 690 | |
| 691 | for (i = 0; iow[i] != NULL; i++) { |
| 692 | struct ioword *p, *q; |
| 693 | |
| 694 | p = iow[i]; |
| 695 | q = alloc(sizeof(struct ioword), ap); |
| 696 | ior[i] = q; |
| 697 | *q = *p; |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 698 | if (p->ioname != NULL) |
| 699 | q->ioname = wdcopy(p->ioname, ap); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 700 | if (p->delim != NULL) |
| 701 | q->delim = wdcopy(p->delim, ap); |
| 702 | if (p->heredoc != NULL) |
| 703 | strdupx(q->heredoc, p->heredoc, ap); |
| 704 | } |
| 705 | ior[i] = NULL; |
| 706 | |
| 707 | return (ior); |
| 708 | } |
| 709 | |
| 710 | /* |
| 711 | * free tree (for function definition) |
| 712 | */ |
| 713 | void |
| 714 | tfree(struct op *t, Area *ap) |
| 715 | { |
| 716 | char **w; |
| 717 | |
| 718 | if (t == NULL) |
| 719 | return; |
| 720 | |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 721 | afree(t->str, ap); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 722 | |
| 723 | if (t->vars != NULL) { |
| 724 | for (w = t->vars; *w != NULL; w++) |
| 725 | afree(*w, ap); |
| 726 | afree(t->vars, ap); |
| 727 | } |
| 728 | |
| 729 | if (t->args != NULL) { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 730 | /*XXX we assume the caller is right */ |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 731 | union mksh_ccphack cw; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 732 | |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 733 | cw.ro = t->args; |
| 734 | for (w = cw.rw; *w != NULL; w++) |
| 735 | afree(*w, ap); |
| 736 | afree(t->args, ap); |
| 737 | } |
| 738 | |
| 739 | if (t->ioact != NULL) |
| 740 | iofree(t->ioact, ap); |
| 741 | |
| 742 | tfree(t->left, ap); |
| 743 | tfree(t->right, ap); |
| 744 | |
| 745 | afree(t, ap); |
| 746 | } |
| 747 | |
| 748 | static void |
| 749 | iofree(struct ioword **iow, Area *ap) |
| 750 | { |
| 751 | struct ioword **iop; |
| 752 | struct ioword *p; |
| 753 | |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 754 | iop = iow; |
| 755 | while ((p = *iop++) != NULL) { |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 756 | afree(p->ioname, ap); |
| 757 | afree(p->delim, ap); |
| 758 | afree(p->heredoc, ap); |
Jean-Baptiste Queru | 5155f1c | 2011-06-16 10:05:28 -0700 | [diff] [blame] | 759 | afree(p, ap); |
| 760 | } |
| 761 | afree(iow, ap); |
| 762 | } |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 763 | |
| 764 | void |
| 765 | fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v) |
| 766 | { |
| 767 | if (isksh) |
| 768 | fptreef(shf, i, "%s %s %T", Tfunction, k, v); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 769 | else if (ktsearch(&keywords, k, hash(k))) |
| 770 | fptreef(shf, i, "%s %s() %T", Tfunction, k, v); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 771 | else |
| 772 | fptreef(shf, i, "%s() %T", k, v); |
| 773 | } |
| 774 | |
| 775 | |
| 776 | /* for jobs.c */ |
| 777 | void |
| 778 | vistree(char *dst, size_t sz, struct op *t) |
| 779 | { |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 780 | unsigned int c; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 781 | char *cp, *buf; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 782 | size_t n; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 783 | |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 784 | buf = alloc(sz + 16, ATEMP); |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 785 | snptreef(buf, sz + 16, Tf_T, t); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 786 | cp = buf; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 787 | vist_loop: |
| 788 | if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) { |
| 789 | if (c == 0 || n >= sz) |
| 790 | /* NUL or not enough free space */ |
| 791 | goto vist_out; |
| 792 | /* copy multibyte char */ |
| 793 | sz -= n; |
| 794 | while (n--) |
| 795 | *dst++ = *cp++; |
| 796 | goto vist_loop; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 797 | } |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 798 | if (--sz == 0 || (c = (unsigned char)(*cp++)) == 0) |
| 799 | /* NUL or not enough free space */ |
| 800 | goto vist_out; |
Elliott Hughes | 737fdce | 2014-08-07 12:59:26 -0700 | [diff] [blame] | 801 | if (ISCTRL(c & 0x7F)) { |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 802 | /* C0 or C1 control character or DEL */ |
| 803 | if (--sz == 0) |
| 804 | /* not enough free space for two chars */ |
| 805 | goto vist_out; |
| 806 | *dst++ = (c & 0x80) ? '$' : '^'; |
Elliott Hughes | 737fdce | 2014-08-07 12:59:26 -0700 | [diff] [blame] | 807 | c = UNCTRL(c & 0x7F); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 808 | } else if (UTFMODE && c > 0x7F) { |
| 809 | /* better not try to display broken multibyte chars */ |
Elliott Hughes | 737fdce | 2014-08-07 12:59:26 -0700 | [diff] [blame] | 810 | /* also go easy on the Unicode: no U+FFFD here */ |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 811 | c = '?'; |
| 812 | } |
| 813 | *dst++ = c; |
| 814 | goto vist_loop; |
| 815 | |
| 816 | vist_out: |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 817 | *dst = '\0'; |
| 818 | afree(buf, ATEMP); |
| 819 | } |
| 820 | |
| 821 | #ifdef DEBUG |
| 822 | void |
| 823 | dumpchar(struct shf *shf, int c) |
| 824 | { |
Elliott Hughes | 737fdce | 2014-08-07 12:59:26 -0700 | [diff] [blame] | 825 | if (ISCTRL(c & 0x7F)) { |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 826 | /* C0 or C1 control character or DEL */ |
| 827 | shf_putc((c & 0x80) ? '$' : '^', shf); |
Elliott Hughes | 737fdce | 2014-08-07 12:59:26 -0700 | [diff] [blame] | 828 | c = UNCTRL(c & 0x7F); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 829 | } |
| 830 | shf_putc(c, shf); |
| 831 | } |
| 832 | |
| 833 | /* see: wdvarput */ |
| 834 | static const char * |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 835 | dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel) |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 836 | { |
| 837 | int c; |
| 838 | |
| 839 | while (/* CONSTCOND */ 1) { |
| 840 | switch(*wp++) { |
| 841 | case EOS: |
| 842 | shf_puts("EOS", shf); |
| 843 | return (--wp); |
| 844 | case ADELIM: |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 845 | if (*wp == /*{*/'}') { |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 846 | shf_puts(/*{*/ "]ADELIM(})", shf); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 847 | return (wp + 1); |
| 848 | } |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 849 | shf_puts("ADELIM=", shf); |
| 850 | if (0) |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 851 | /* FALLTHROUGH */ |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 852 | case CHAR: |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 853 | shf_puts("CHAR=", shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 854 | dumpchar(shf, *wp++); |
| 855 | break; |
| 856 | case QCHAR: |
| 857 | shf_puts("QCHAR<", shf); |
| 858 | c = *wp++; |
| 859 | if (quotelevel == 0 || |
| 860 | (c == '"' || c == '`' || c == '$' || c == '\\')) |
| 861 | shf_putc('\\', shf); |
| 862 | dumpchar(shf, c); |
| 863 | goto closeandout; |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 864 | case COMASUB: |
| 865 | shf_puts("COMASUB<", shf); |
| 866 | goto dumpsub; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 867 | case COMSUB: |
| 868 | shf_puts("COMSUB<", shf); |
| 869 | dumpsub: |
| 870 | while ((c = *wp++) != 0) |
| 871 | dumpchar(shf, c); |
| 872 | closeandout: |
| 873 | shf_putc('>', shf); |
| 874 | break; |
Elliott Hughes | a3c3f96 | 2017-04-12 16:52:30 -0700 | [diff] [blame] | 875 | case FUNASUB: |
| 876 | shf_puts("FUNASUB<", shf); |
| 877 | goto dumpsub; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 878 | case FUNSUB: |
| 879 | shf_puts("FUNSUB<", shf); |
| 880 | goto dumpsub; |
Thorsten Glaser | 811a575 | 2013-07-25 14:24:45 +0000 | [diff] [blame] | 881 | case VALSUB: |
| 882 | shf_puts("VALSUB<", shf); |
| 883 | goto dumpsub; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 884 | case EXPRSUB: |
| 885 | shf_puts("EXPRSUB<", shf); |
| 886 | goto dumpsub; |
| 887 | case OQUOTE: |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 888 | shf_fprintf(shf, "OQUOTE{%d" /*}*/, ++quotelevel); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 889 | break; |
| 890 | case CQUOTE: |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 891 | shf_fprintf(shf, /*{*/ "%d}CQUOTE", quotelevel); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 892 | if (quotelevel) |
| 893 | quotelevel--; |
| 894 | else |
| 895 | shf_puts("(err)", shf); |
| 896 | break; |
| 897 | case OSUBST: |
| 898 | shf_puts("OSUBST(", shf); |
| 899 | dumpchar(shf, *wp++); |
| 900 | shf_puts(")[", shf); |
| 901 | while ((c = *wp++) != 0) |
| 902 | dumpchar(shf, c); |
| 903 | shf_putc('|', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 904 | wp = dumpwdvar_i(shf, wp, 0); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 905 | break; |
| 906 | case CSUBST: |
| 907 | shf_puts("]CSUBST(", shf); |
| 908 | dumpchar(shf, *wp++); |
| 909 | shf_putc(')', shf); |
| 910 | return (wp); |
| 911 | case OPAT: |
| 912 | shf_puts("OPAT=", shf); |
| 913 | dumpchar(shf, *wp++); |
| 914 | break; |
| 915 | case SPAT: |
| 916 | shf_puts("SPAT", shf); |
| 917 | break; |
| 918 | case CPAT: |
| 919 | shf_puts("CPAT", shf); |
| 920 | break; |
| 921 | default: |
| 922 | shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]); |
| 923 | break; |
| 924 | } |
| 925 | shf_putc(' ', shf); |
| 926 | } |
| 927 | } |
| 928 | void |
| 929 | dumpwdvar(struct shf *shf, const char *wp) |
| 930 | { |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 931 | dumpwdvar_i(shf, wp, 0); |
| 932 | } |
| 933 | |
| 934 | void |
| 935 | dumpioact(struct shf *shf, struct op *t) |
| 936 | { |
| 937 | struct ioword **ioact, *iop; |
| 938 | |
| 939 | if ((ioact = t->ioact) == NULL) |
| 940 | return; |
| 941 | |
| 942 | shf_puts("{IOACT", shf); |
| 943 | while ((iop = *ioact++) != NULL) { |
Elliott Hughes | b27ce95 | 2015-04-21 13:39:18 -0700 | [diff] [blame] | 944 | unsigned short type = iop->ioflag & IOTYPE; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 945 | #define DT(x) case x: shf_puts(#x, shf); break; |
Elliott Hughes | b27ce95 | 2015-04-21 13:39:18 -0700 | [diff] [blame] | 946 | #define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 947 | |
| 948 | shf_putc(';', shf); |
| 949 | switch (type) { |
| 950 | DT(IOREAD) |
| 951 | DT(IOWRITE) |
| 952 | DT(IORDWR) |
| 953 | DT(IOHERE) |
| 954 | DT(IOCAT) |
| 955 | DT(IODUP) |
| 956 | default: |
| 957 | shf_fprintf(shf, "unk%d", type); |
| 958 | } |
| 959 | DB(IOEVAL) |
| 960 | DB(IOSKIP) |
| 961 | DB(IOCLOB) |
| 962 | DB(IORDUP) |
| 963 | DB(IONAMEXP) |
| 964 | DB(IOBASH) |
| 965 | DB(IOHERESTR) |
| 966 | DB(IONDELIM) |
Elliott Hughes | b27ce95 | 2015-04-21 13:39:18 -0700 | [diff] [blame] | 967 | shf_fprintf(shf, ",unit=%d", (int)iop->unit); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 968 | if (iop->delim && !(iop->ioflag & IONDELIM)) { |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 969 | shf_puts(",delim<", shf); |
| 970 | dumpwdvar(shf, iop->delim); |
| 971 | shf_putc('>', shf); |
| 972 | } |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 973 | if (iop->ioname) { |
Elliott Hughes | b27ce95 | 2015-04-21 13:39:18 -0700 | [diff] [blame] | 974 | if (iop->ioflag & IONAMEXP) { |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 975 | shf_puts(",name=", shf); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 976 | print_value_quoted(shf, iop->ioname); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 977 | } else { |
| 978 | shf_puts(",name<", shf); |
Elliott Hughes | fc0307d | 2016-02-02 15:26:47 -0800 | [diff] [blame] | 979 | dumpwdvar(shf, iop->ioname); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 980 | shf_putc('>', shf); |
| 981 | } |
| 982 | } |
| 983 | if (iop->heredoc) { |
| 984 | shf_puts(",heredoc=", shf); |
| 985 | print_value_quoted(shf, iop->heredoc); |
| 986 | } |
| 987 | #undef DT |
| 988 | #undef DB |
| 989 | } |
| 990 | shf_putc('}', shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 991 | } |
| 992 | |
| 993 | void |
| 994 | dumptree(struct shf *shf, struct op *t) |
| 995 | { |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 996 | int i, j; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 997 | const char **w, *name; |
| 998 | struct op *t1; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 999 | static int nesting; |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1000 | |
| 1001 | for (i = 0; i < nesting; ++i) |
| 1002 | shf_putc('\t', shf); |
| 1003 | ++nesting; |
| 1004 | shf_puts("{tree:" /*}*/, shf); |
| 1005 | if (t == NULL) { |
| 1006 | name = "(null)"; |
| 1007 | goto out; |
| 1008 | } |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1009 | dumpioact(shf, t); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1010 | switch (t->type) { |
| 1011 | #define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/ |
| 1012 | |
| 1013 | OPEN(TCOM) |
| 1014 | if (t->vars) { |
| 1015 | i = 0; |
| 1016 | w = (const char **)t->vars; |
| 1017 | while (*w) { |
| 1018 | shf_putc('\n', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1019 | for (j = 0; j < nesting; ++j) |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1020 | shf_putc('\t', shf); |
| 1021 | shf_fprintf(shf, " var%d<", i++); |
| 1022 | dumpwdvar(shf, *w++); |
| 1023 | shf_putc('>', shf); |
| 1024 | } |
| 1025 | } else |
| 1026 | shf_puts(" #no-vars#", shf); |
| 1027 | if (t->args) { |
| 1028 | i = 0; |
| 1029 | w = t->args; |
| 1030 | while (*w) { |
| 1031 | shf_putc('\n', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1032 | for (j = 0; j < nesting; ++j) |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1033 | shf_putc('\t', shf); |
| 1034 | shf_fprintf(shf, " arg%d<", i++); |
| 1035 | dumpwdvar(shf, *w++); |
| 1036 | shf_putc('>', shf); |
| 1037 | } |
| 1038 | } else |
| 1039 | shf_puts(" #no-args#", shf); |
| 1040 | break; |
| 1041 | OPEN(TEXEC) |
| 1042 | dumpleftandout: |
| 1043 | t = t->left; |
| 1044 | dumpandout: |
| 1045 | shf_putc('\n', shf); |
| 1046 | dumptree(shf, t); |
| 1047 | break; |
| 1048 | OPEN(TPAREN) |
| 1049 | goto dumpleftandout; |
| 1050 | OPEN(TPIPE) |
| 1051 | dumpleftmidrightandout: |
| 1052 | shf_putc('\n', shf); |
| 1053 | dumptree(shf, t->left); |
| 1054 | /* middumprightandout: (unused) */ |
| 1055 | shf_fprintf(shf, "/%s:", name); |
| 1056 | dumprightandout: |
| 1057 | t = t->right; |
| 1058 | goto dumpandout; |
| 1059 | OPEN(TLIST) |
| 1060 | goto dumpleftmidrightandout; |
| 1061 | OPEN(TOR) |
| 1062 | goto dumpleftmidrightandout; |
| 1063 | OPEN(TAND) |
| 1064 | goto dumpleftmidrightandout; |
| 1065 | OPEN(TBANG) |
| 1066 | goto dumprightandout; |
| 1067 | OPEN(TDBRACKET) |
| 1068 | i = 0; |
| 1069 | w = t->args; |
| 1070 | while (*w) { |
| 1071 | shf_putc('\n', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1072 | for (j = 0; j < nesting; ++j) |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1073 | shf_putc('\t', shf); |
| 1074 | shf_fprintf(shf, " arg%d<", i++); |
| 1075 | dumpwdvar(shf, *w++); |
| 1076 | shf_putc('>', shf); |
| 1077 | } |
| 1078 | break; |
| 1079 | OPEN(TFOR) |
| 1080 | dumpfor: |
| 1081 | shf_fprintf(shf, " str<%s>", t->str); |
| 1082 | if (t->vars != NULL) { |
| 1083 | i = 0; |
| 1084 | w = (const char **)t->vars; |
| 1085 | while (*w) { |
| 1086 | shf_putc('\n', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1087 | for (j = 0; j < nesting; ++j) |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1088 | shf_putc('\t', shf); |
| 1089 | shf_fprintf(shf, " var%d<", i++); |
| 1090 | dumpwdvar(shf, *w++); |
| 1091 | shf_putc('>', shf); |
| 1092 | } |
| 1093 | } |
| 1094 | goto dumpleftandout; |
| 1095 | OPEN(TSELECT) |
| 1096 | goto dumpfor; |
| 1097 | OPEN(TCASE) |
| 1098 | shf_fprintf(shf, " str<%s>", t->str); |
| 1099 | i = 0; |
| 1100 | for (t1 = t->left; t1 != NULL; t1 = t1->right) { |
| 1101 | shf_putc('\n', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1102 | for (j = 0; j < nesting; ++j) |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1103 | shf_putc('\t', shf); |
| 1104 | shf_fprintf(shf, " sub%d[(", i); |
| 1105 | w = (const char **)t1->vars; |
| 1106 | while (*w) { |
| 1107 | dumpwdvar(shf, *w); |
| 1108 | if (w[1] != NULL) |
| 1109 | shf_putc('|', shf); |
| 1110 | ++w; |
| 1111 | } |
| 1112 | shf_putc(')', shf); |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1113 | dumpioact(shf, t); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1114 | shf_putc('\n', shf); |
| 1115 | dumptree(shf, t1->left); |
| 1116 | shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++); |
| 1117 | } |
| 1118 | break; |
| 1119 | OPEN(TWHILE) |
| 1120 | goto dumpleftmidrightandout; |
| 1121 | OPEN(TUNTIL) |
| 1122 | goto dumpleftmidrightandout; |
| 1123 | OPEN(TBRACE) |
| 1124 | goto dumpleftandout; |
| 1125 | OPEN(TCOPROC) |
| 1126 | goto dumpleftandout; |
| 1127 | OPEN(TASYNC) |
| 1128 | goto dumpleftandout; |
| 1129 | OPEN(TFUNCT) |
| 1130 | shf_fprintf(shf, " str<%s> ksh<%s>", t->str, |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 1131 | t->u.ksh_func ? Ttrue : Tfalse); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1132 | goto dumpleftandout; |
| 1133 | OPEN(TTIME) |
| 1134 | goto dumpleftandout; |
| 1135 | OPEN(TIF) |
| 1136 | dumpif: |
| 1137 | shf_putc('\n', shf); |
| 1138 | dumptree(shf, t->left); |
| 1139 | t = t->right; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1140 | dumpioact(shf, t); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1141 | if (t->left != NULL) { |
| 1142 | shf_puts(" /TTHEN:\n", shf); |
| 1143 | dumptree(shf, t->left); |
| 1144 | } |
| 1145 | if (t->right && t->right->type == TELIF) { |
| 1146 | shf_puts(" /TELIF:", shf); |
| 1147 | t = t->right; |
Thorsten Glaser | c2dc5de | 2013-02-18 23:02:51 +0000 | [diff] [blame] | 1148 | dumpioact(shf, t); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1149 | goto dumpif; |
| 1150 | } |
| 1151 | if (t->right != NULL) { |
| 1152 | shf_puts(" /TELSE:\n", shf); |
| 1153 | dumptree(shf, t->right); |
| 1154 | } |
| 1155 | break; |
| 1156 | OPEN(TEOF) |
| 1157 | dumpunexpected: |
Elliott Hughes | 77740fc | 2016-08-12 15:06:53 -0700 | [diff] [blame] | 1158 | shf_puts(Tunexpected, shf); |
Geremy Condra | 03ebf06 | 2011-10-12 18:17:24 -0700 | [diff] [blame] | 1159 | break; |
| 1160 | OPEN(TELIF) |
| 1161 | goto dumpunexpected; |
| 1162 | OPEN(TPAT) |
| 1163 | goto dumpunexpected; |
| 1164 | default: |
| 1165 | name = "TINVALID"; |
| 1166 | shf_fprintf(shf, "{T<%d>:" /*}*/, t->type); |
| 1167 | goto dumpunexpected; |
| 1168 | |
| 1169 | #undef OPEN |
| 1170 | } |
| 1171 | out: |
| 1172 | shf_fprintf(shf, /*{*/ " /%s}\n", name); |
| 1173 | --nesting; |
| 1174 | } |
| 1175 | #endif |