don't bother resolving onbld python module deps
[unleashed.git] / bin / ksh / tree.c
blobe3ba260ca8ae0eef439ad6d753eb89e48f2be1ec
1 /* $OpenBSD: tree.c,v 1.34 2018/04/09 17:53:36 tobias Exp $ */
3 /*
4 * command tree climbing
5 */
7 #include <string.h>
9 #include "sh.h"
11 #define INDENT 4
13 #define tputc(c, shf) shf_putchar(c, shf);
14 static void ptree(struct op *, int, struct shf *);
15 static void pioact(struct shf *, int, struct ioword *);
16 static void tputC(int, struct shf *);
17 static void tputS(char *, struct shf *);
18 static void vfptreef(struct shf *, int, const char *, va_list);
19 static struct ioword **iocopy(struct ioword **, Area *);
20 static void iofree(struct ioword **, Area *);
23 * print a command tree
26 static void
27 ptree(struct op *t, int indent, struct shf *shf)
29 char **w;
30 struct ioword **ioact;
31 struct op *t1;
33 Chain:
34 if (t == NULL)
35 return;
36 switch (t->type) {
37 case TCOM:
38 if (t->vars)
39 for (w = t->vars; *w != NULL; )
40 fptreef(shf, indent, "%S ", *w++);
41 else
42 fptreef(shf, indent, "#no-vars# ");
43 if (t->args)
44 for (w = t->args; *w != NULL; )
45 fptreef(shf, indent, "%S ", *w++);
46 else
47 fptreef(shf, indent, "#no-args# ");
48 break;
49 case TEXEC:
50 t = t->left;
51 goto Chain;
52 case TPAREN:
53 fptreef(shf, indent + 2, "( %T) ", t->left);
54 break;
55 case TPIPE:
56 fptreef(shf, indent, "%T| ", t->left);
57 t = t->right;
58 goto Chain;
59 case TLIST:
60 fptreef(shf, indent, "%T%;", t->left);
61 t = t->right;
62 goto Chain;
63 case TOR:
64 case TAND:
65 fptreef(shf, indent, "%T%s %T",
66 t->left, (t->type==TOR) ? "||" : "&&", t->right);
67 break;
68 case TBANG:
69 fptreef(shf, indent, "! ");
70 t = t->right;
71 goto Chain;
72 case TDBRACKET:
74 int i;
76 fptreef(shf, indent, "[[");
77 for (i = 0; t->args[i]; i++)
78 fptreef(shf, indent, " %S", t->args[i]);
79 fptreef(shf, indent, " ]] ");
80 break;
82 case TSELECT:
83 fptreef(shf, indent, "select %s ", t->str);
84 /* FALLTHROUGH */
85 case TFOR:
86 if (t->type == TFOR)
87 fptreef(shf, indent, "for %s ", t->str);
88 if (t->vars != NULL) {
89 fptreef(shf, indent, "in ");
90 for (w = t->vars; *w; )
91 fptreef(shf, indent, "%S ", *w++);
92 fptreef(shf, indent, "%;");
94 fptreef(shf, indent + INDENT, "do%N%T", t->left);
95 fptreef(shf, indent, "%;done ");
96 break;
97 case TCASE:
98 fptreef(shf, indent, "case %S in", t->str);
99 for (t1 = t->left; t1 != NULL; t1 = t1->right) {
100 fptreef(shf, indent, "%N(");
101 for (w = t1->vars; *w != NULL; w++)
102 fptreef(shf, indent, "%S%c", *w,
103 (w[1] != NULL) ? '|' : ')');
104 fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);
106 fptreef(shf, indent, "%Nesac ");
107 break;
108 case TIF:
109 case TELIF:
110 /* 3 == strlen("if ") */
111 fptreef(shf, indent + 3, "if %T", t->left);
112 for (;;) {
113 t = t->right;
114 if (t->left != NULL) {
115 fptreef(shf, indent, "%;");
116 fptreef(shf, indent + INDENT, "then%N%T",
117 t->left);
119 if (t->right == NULL || t->right->type != TELIF)
120 break;
121 t = t->right;
122 fptreef(shf, indent, "%;");
123 /* 5 == strlen("elif ") */
124 fptreef(shf, indent + 5, "elif %T", t->left);
126 if (t->right != NULL) {
127 fptreef(shf, indent, "%;");
128 fptreef(shf, indent + INDENT, "else%;%T", t->right);
130 fptreef(shf, indent, "%;fi ");
131 break;
132 case TWHILE:
133 case TUNTIL:
134 /* 6 == strlen("while"/"until") */
135 fptreef(shf, indent + 6, "%s %T",
136 (t->type==TWHILE) ? "while" : "until",
137 t->left);
138 fptreef(shf, indent, "%;do");
139 fptreef(shf, indent + INDENT, "%;%T", t->right);
140 fptreef(shf, indent, "%;done ");
141 break;
142 case TBRACE:
143 fptreef(shf, indent + INDENT, "{%;%T", t->left);
144 fptreef(shf, indent, "%;} ");
145 break;
146 case TCOPROC:
147 fptreef(shf, indent, "%T|& ", t->left);
148 break;
149 case TASYNC:
150 fptreef(shf, indent, "%T& ", t->left);
151 break;
152 case TFUNCT:
153 fptreef(shf, indent,
154 t->u.ksh_func ? "function %s %T" : "%s() %T",
155 t->str, t->left);
156 break;
157 case TTIME:
158 fptreef(shf, indent, "time %T", t->left);
159 break;
160 default:
161 fptreef(shf, indent, "<botch>");
162 break;
164 if ((ioact = t->ioact) != NULL) {
165 int need_nl = 0;
167 while (*ioact != NULL)
168 pioact(shf, indent, *ioact++);
169 /* Print here documents after everything else... */
170 for (ioact = t->ioact; *ioact != NULL; ) {
171 struct ioword *iop = *ioact++;
173 /* heredoc is 0 when tracing (set -x) */
174 if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) {
175 tputc('\n', shf);
176 shf_puts(iop->heredoc, shf);
177 fptreef(shf, indent, "%s",
178 evalstr(iop->delim, 0));
179 need_nl = 1;
182 /* Last delimiter must be followed by a newline (this often
183 * leads to an extra blank line, but its not worth worrying
184 * about)
186 if (need_nl)
187 tputc('\n', shf);
191 static void
192 pioact(struct shf *shf, int indent, struct ioword *iop)
194 int flag = iop->flag;
195 int type = flag & IOTYPE;
196 int expected;
198 expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
199 (type == IOCAT || type == IOWRITE) ? 1 :
200 (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
201 iop->unit + 1;
202 if (iop->unit != expected)
203 tputc('0' + iop->unit, shf);
205 switch (type) {
206 case IOREAD:
207 fptreef(shf, indent, "< ");
208 break;
209 case IOHERE:
210 if (flag&IOSKIP)
211 fptreef(shf, indent, "<<- ");
212 else
213 fptreef(shf, indent, "<< ");
214 break;
215 case IOCAT:
216 fptreef(shf, indent, ">> ");
217 break;
218 case IOWRITE:
219 if (flag&IOCLOB)
220 fptreef(shf, indent, ">| ");
221 else
222 fptreef(shf, indent, "> ");
223 break;
224 case IORDWR:
225 fptreef(shf, indent, "<> ");
226 break;
227 case IODUP:
228 if (flag & IORDUP)
229 fptreef(shf, indent, "<&");
230 else
231 fptreef(shf, indent, ">&");
232 break;
234 /* name/delim are 0 when printing syntax errors */
235 if (type == IOHERE) {
236 if (iop->delim)
237 fptreef(shf, indent, "%S ", iop->delim);
238 } else if (iop->name)
239 fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
240 iop->name);
245 * variants of fputc, fputs for ptreef and snptreef
248 static void
249 tputC(int c, struct shf *shf)
251 if ((c&0x60) == 0) { /* C0|C1 */
252 tputc((c&0x80) ? '$' : '^', shf);
253 tputc(((c&0x7F)|0x40), shf);
254 } else if ((c&0x7F) == 0x7F) { /* DEL */
255 tputc((c&0x80) ? '$' : '^', shf);
256 tputc('?', shf);
257 } else
258 tputc(c, shf);
261 static void
262 tputS(char *wp, struct shf *shf)
264 int c, quoted=0;
266 /* problems:
267 * `...` -> $(...)
268 * 'foo' -> "foo"
269 * could change encoding to:
270 * OQUOTE ["'] ... CQUOTE ["']
271 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
273 while (1)
274 switch ((c = *wp++)) {
275 case EOS:
276 return;
277 case CHAR:
278 tputC(*wp++, shf);
279 break;
280 case QCHAR:
281 c = *wp++;
282 if (!quoted || (c == '"' || c == '`' || c == '$'))
283 tputc('\\', shf);
284 tputC(c, shf);
285 break;
286 case COMSUB:
287 tputc('$', shf);
288 tputc('(', shf);
289 while (*wp != 0)
290 tputC(*wp++, shf);
291 tputc(')', shf);
292 wp++;
293 break;
294 case EXPRSUB:
295 tputc('$', shf);
296 tputc('(', shf);
297 tputc('(', shf);
298 while (*wp != 0)
299 tputC(*wp++, shf);
300 tputc(')', shf);
301 tputc(')', shf);
302 wp++;
303 break;
304 case OQUOTE:
305 quoted = 1;
306 tputc('"', shf);
307 break;
308 case CQUOTE:
309 quoted = 0;
310 tputc('"', shf);
311 break;
312 case OSUBST:
313 tputc('$', shf);
314 if (*wp++ == '{')
315 tputc('{', shf);
316 while ((c = *wp++) != 0)
317 tputC(c, shf);
318 break;
319 case CSUBST:
320 if (*wp++ == '}')
321 tputc('}', shf);
322 break;
323 case OPAT:
324 tputc(*wp++, shf);
325 tputc('(', shf);
326 break;
327 case SPAT:
328 tputc('|', shf);
329 break;
330 case CPAT:
331 tputc(')', shf);
332 break;
336 void
337 fptreef(struct shf *shf, int indent, const char *fmt, ...)
339 va_list va;
341 va_start(va, fmt);
342 vfptreef(shf, indent, fmt, va);
343 va_end(va);
346 char *
347 snptreef(char *s, int n, const char *fmt, ...)
349 va_list va;
350 struct shf shf;
352 shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
354 va_start(va, fmt);
355 vfptreef(&shf, 0, fmt, va);
356 va_end(va);
358 return shf_sclose(&shf); /* null terminates */
361 static void
362 vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
364 int c;
366 while ((c = *fmt++)) {
367 if (c == '%') {
368 int64_t n;
369 char *p;
370 int neg;
372 switch ((c = *fmt++)) {
373 case 'c':
374 tputc(va_arg(va, int), shf);
375 break;
376 case 'd': /* decimal */
377 n = va_arg(va, int);
378 neg = n < 0;
379 p = u64ton(neg ? -n : n, 10);
380 if (neg)
381 *--p = '-';
382 while (*p)
383 tputc(*p++, shf);
384 break;
385 case 's':
386 p = va_arg(va, char *);
387 while (*p)
388 tputc(*p++, shf);
389 break;
390 case 'S': /* word */
391 p = va_arg(va, char *);
392 tputS(p, shf);
393 break;
394 case 'u': /* unsigned decimal */
395 p = u64ton(va_arg(va, unsigned int), 10);
396 while (*p)
397 tputc(*p++, shf);
398 break;
399 case 'T': /* format tree */
400 ptree(va_arg(va, struct op *), indent, shf);
401 break;
402 case ';': /* newline or ; */
403 case 'N': /* newline or space */
404 if (shf->flags & SHF_STRING) {
405 if (c == ';')
406 tputc(';', shf);
407 tputc(' ', shf);
408 } else {
409 int i;
411 tputc('\n', shf);
412 for (i = indent; i >= 8; i -= 8)
413 tputc('\t', shf);
414 for (; i > 0; --i)
415 tputc(' ', shf);
417 break;
418 case 'R':
419 pioact(shf, indent, va_arg(va, struct ioword *));
420 break;
421 default:
422 tputc(c, shf);
423 break;
425 } else
426 tputc(c, shf);
431 * copy tree (for function definition)
434 struct op *
435 tcopy(struct op *t, Area *ap)
437 struct op *r;
438 char **tw, **rw;
440 if (t == NULL)
441 return NULL;
443 r = alloc(sizeof(struct op), ap);
445 r->type = t->type;
446 r->u.evalflags = t->u.evalflags;
448 r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap);
450 if (t->vars == NULL)
451 r->vars = NULL;
452 else {
453 for (tw = t->vars; *tw++ != NULL; )
455 rw = r->vars = areallocarray(NULL, tw - t->vars + 1,
456 sizeof(*tw), ap);
457 for (tw = t->vars; *tw != NULL; )
458 *rw++ = wdcopy(*tw++, ap);
459 *rw = NULL;
462 if (t->args == NULL)
463 r->args = NULL;
464 else {
465 for (tw = t->args; *tw++ != NULL; )
467 rw = r->args = areallocarray(NULL, tw - t->args + 1,
468 sizeof(*tw), ap);
469 for (tw = t->args; *tw != NULL; )
470 *rw++ = wdcopy(*tw++, ap);
471 *rw = NULL;
474 r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
476 r->left = tcopy(t->left, ap);
477 r->right = tcopy(t->right, ap);
478 r->lineno = t->lineno;
480 return r;
483 char *
484 wdcopy(const char *wp, Area *ap)
486 size_t len = wdscan(wp, EOS) - wp;
487 return memcpy(alloc(len, ap), wp, len);
490 /* return the position of prefix c in wp plus 1 */
491 char *
492 wdscan(const char *wp, int c)
494 int nest = 0;
496 while (1)
497 switch (*wp++) {
498 case EOS:
499 return (char *) wp;
500 case CHAR:
501 case QCHAR:
502 wp++;
503 break;
504 case COMSUB:
505 case EXPRSUB:
506 while (*wp++ != 0)
508 break;
509 case OQUOTE:
510 case CQUOTE:
511 break;
512 case OSUBST:
513 nest++;
514 while (*wp++ != '\0')
516 break;
517 case CSUBST:
518 wp++;
519 if (c == CSUBST && nest == 0)
520 return (char *) wp;
521 nest--;
522 break;
523 case OPAT:
524 nest++;
525 wp++;
526 break;
527 case SPAT:
528 case CPAT:
529 if (c == wp[-1] && nest == 0)
530 return (char *) wp;
531 if (wp[-1] == CPAT)
532 nest--;
533 break;
534 default:
535 internal_warningf(
536 "%s: unknown char 0x%x (carrying on)",
537 __func__, wp[-1]);
541 /* return a copy of wp without any of the mark up characters and
542 * with quote characters (" ' \) stripped.
543 * (string is allocated from ATEMP)
545 char *
546 wdstrip(const char *wp)
548 struct shf shf;
549 int c;
551 shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
553 /* problems:
554 * `...` -> $(...)
555 * x${foo:-"hi"} -> x${foo:-hi}
556 * x${foo:-'hi'} -> x${foo:-hi}
558 while (1)
559 switch ((c = *wp++)) {
560 case EOS:
561 return shf_sclose(&shf); /* null terminates */
562 case CHAR:
563 case QCHAR:
564 shf_putchar(*wp++, &shf);
565 break;
566 case COMSUB:
567 shf_putchar('$', &shf);
568 shf_putchar('(', &shf);
569 while (*wp != 0)
570 shf_putchar(*wp++, &shf);
571 shf_putchar(')', &shf);
572 break;
573 case EXPRSUB:
574 shf_putchar('$', &shf);
575 shf_putchar('(', &shf);
576 shf_putchar('(', &shf);
577 while (*wp != 0)
578 shf_putchar(*wp++, &shf);
579 shf_putchar(')', &shf);
580 shf_putchar(')', &shf);
581 break;
582 case OQUOTE:
583 break;
584 case CQUOTE:
585 break;
586 case OSUBST:
587 shf_putchar('$', &shf);
588 if (*wp++ == '{')
589 shf_putchar('{', &shf);
590 while ((c = *wp++) != 0)
591 shf_putchar(c, &shf);
592 break;
593 case CSUBST:
594 if (*wp++ == '}')
595 shf_putchar('}', &shf);
596 break;
597 case OPAT:
598 shf_putchar(*wp++, &shf);
599 shf_putchar('(', &shf);
600 break;
601 case SPAT:
602 shf_putchar('|', &shf);
603 break;
604 case CPAT:
605 shf_putchar(')', &shf);
606 break;
610 static struct ioword **
611 iocopy(struct ioword **iow, Area *ap)
613 struct ioword **ior;
614 int i;
616 for (ior = iow; *ior++ != NULL; )
618 ior = areallocarray(NULL, ior - iow + 1, sizeof(*ior), ap);
620 for (i = 0; iow[i] != NULL; i++) {
621 struct ioword *p, *q;
623 p = iow[i];
624 q = alloc(sizeof(*p), ap);
625 ior[i] = q;
626 *q = *p;
627 if (p->name != NULL)
628 q->name = wdcopy(p->name, ap);
629 if (p->delim != NULL)
630 q->delim = wdcopy(p->delim, ap);
631 if (p->heredoc != NULL)
632 q->heredoc = str_save(p->heredoc, ap);
634 ior[i] = NULL;
636 return ior;
640 * free tree (for function definition)
643 void
644 tfree(struct op *t, Area *ap)
646 char **w;
648 if (t == NULL)
649 return;
651 afree(t->str, ap);
653 if (t->vars != NULL) {
654 for (w = t->vars; *w != NULL; w++)
655 afree(*w, ap);
656 afree(t->vars, ap);
659 if (t->args != NULL) {
660 for (w = t->args; *w != NULL; w++)
661 afree(*w, ap);
662 afree(t->args, ap);
665 if (t->ioact != NULL)
666 iofree(t->ioact, ap);
668 tfree(t->left, ap);
669 tfree(t->right, ap);
671 afree(t, ap);
674 static void
675 iofree(struct ioword **iow, Area *ap)
677 struct ioword **iop;
678 struct ioword *p;
680 for (iop = iow; (p = *iop++) != NULL; ) {
681 afree(p->name, ap);
682 afree(p->delim, ap);
683 afree(p->heredoc, ap);
684 afree(p, ap);
686 afree(iow, ap);