1 /* $OpenBSD: tree.c,v 1.34 2018/04/09 17:53:36 tobias Exp $ */
4 * command tree climbing
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
27 ptree(struct op
*t
, int indent
, struct shf
*shf
)
30 struct ioword
**ioact
;
39 for (w
= t
->vars
; *w
!= NULL
; )
40 fptreef(shf
, indent
, "%S ", *w
++);
42 fptreef(shf
, indent
, "#no-vars# ");
44 for (w
= t
->args
; *w
!= NULL
; )
45 fptreef(shf
, indent
, "%S ", *w
++);
47 fptreef(shf
, indent
, "#no-args# ");
53 fptreef(shf
, indent
+ 2, "( %T) ", t
->left
);
56 fptreef(shf
, indent
, "%T| ", t
->left
);
60 fptreef(shf
, indent
, "%T%;", t
->left
);
65 fptreef(shf
, indent
, "%T%s %T",
66 t
->left
, (t
->type
==TOR
) ? "||" : "&&", t
->right
);
69 fptreef(shf
, indent
, "! ");
76 fptreef(shf
, indent
, "[[");
77 for (i
= 0; t
->args
[i
]; i
++)
78 fptreef(shf
, indent
, " %S", t
->args
[i
]);
79 fptreef(shf
, indent
, " ]] ");
83 fptreef(shf
, indent
, "select %s ", t
->str
);
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 ");
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 ");
110 /* 3 == strlen("if ") */
111 fptreef(shf
, indent
+ 3, "if %T", t
->left
);
114 if (t
->left
!= NULL
) {
115 fptreef(shf
, indent
, "%;");
116 fptreef(shf
, indent
+ INDENT
, "then%N%T",
119 if (t
->right
== NULL
|| t
->right
->type
!= TELIF
)
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 ");
134 /* 6 == strlen("while"/"until") */
135 fptreef(shf
, indent
+ 6, "%s %T",
136 (t
->type
==TWHILE
) ? "while" : "until",
138 fptreef(shf
, indent
, "%;do");
139 fptreef(shf
, indent
+ INDENT
, "%;%T", t
->right
);
140 fptreef(shf
, indent
, "%;done ");
143 fptreef(shf
, indent
+ INDENT
, "{%;%T", t
->left
);
144 fptreef(shf
, indent
, "%;} ");
147 fptreef(shf
, indent
, "%T|& ", t
->left
);
150 fptreef(shf
, indent
, "%T& ", t
->left
);
154 t
->u
.ksh_func
? "function %s %T" : "%s() %T",
158 fptreef(shf
, indent
, "time %T", t
->left
);
161 fptreef(shf
, indent
, "<botch>");
164 if ((ioact
= t
->ioact
) != NULL
) {
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
) {
176 shf_puts(iop
->heredoc
, shf
);
177 fptreef(shf
, indent
, "%s",
178 evalstr(iop
->delim
, 0));
182 /* Last delimiter must be followed by a newline (this often
183 * leads to an extra blank line, but its not worth worrying
192 pioact(struct shf
*shf
, int indent
, struct ioword
*iop
)
194 int flag
= iop
->flag
;
195 int type
= flag
& IOTYPE
;
198 expected
= (type
== IOREAD
|| type
== IORDWR
|| type
== IOHERE
) ? 0 :
199 (type
== IOCAT
|| type
== IOWRITE
) ? 1 :
200 (type
== IODUP
&& (iop
->unit
== !(flag
& IORDUP
))) ? iop
->unit
:
202 if (iop
->unit
!= expected
)
203 tputc('0' + iop
->unit
, shf
);
207 fptreef(shf
, indent
, "< ");
211 fptreef(shf
, indent
, "<<- ");
213 fptreef(shf
, indent
, "<< ");
216 fptreef(shf
, indent
, ">> ");
220 fptreef(shf
, indent
, ">| ");
222 fptreef(shf
, indent
, "> ");
225 fptreef(shf
, indent
, "<> ");
229 fptreef(shf
, indent
, "<&");
231 fptreef(shf
, indent
, ">&");
234 /* name/delim are 0 when printing syntax errors */
235 if (type
== IOHERE
) {
237 fptreef(shf
, indent
, "%S ", iop
->delim
);
238 } else if (iop
->name
)
239 fptreef(shf
, indent
, (iop
->flag
& IONAMEXP
) ? "%s " : "%S ",
245 * variants of fputc, fputs for ptreef and snptreef
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
);
262 tputS(char *wp
, struct shf
*shf
)
269 * could change encoding to:
270 * OQUOTE ["'] ... CQUOTE ["']
271 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
274 switch ((c
= *wp
++)) {
282 if (!quoted
|| (c
== '"' || c
== '`' || c
== '$'))
316 while ((c
= *wp
++) != 0)
337 fptreef(struct shf
*shf
, int indent
, const char *fmt
, ...)
342 vfptreef(shf
, indent
, fmt
, va
);
347 snptreef(char *s
, int n
, const char *fmt
, ...)
352 shf_sopen(s
, n
, SHF_WR
| (s
? 0 : SHF_DYNAMIC
), &shf
);
355 vfptreef(&shf
, 0, fmt
, va
);
358 return shf_sclose(&shf
); /* null terminates */
362 vfptreef(struct shf
*shf
, int indent
, const char *fmt
, va_list va
)
366 while ((c
= *fmt
++)) {
372 switch ((c
= *fmt
++)) {
374 tputc(va_arg(va
, int), shf
);
376 case 'd': /* decimal */
379 p
= u64ton(neg
? -n
: n
, 10);
386 p
= va_arg(va
, char *);
391 p
= va_arg(va
, char *);
394 case 'u': /* unsigned decimal */
395 p
= u64ton(va_arg(va
, unsigned int), 10);
399 case 'T': /* format tree */
400 ptree(va_arg(va
, struct op
*), indent
, shf
);
402 case ';': /* newline or ; */
403 case 'N': /* newline or space */
404 if (shf
->flags
& SHF_STRING
) {
412 for (i
= indent
; i
>= 8; i
-= 8)
419 pioact(shf
, indent
, va_arg(va
, struct ioword
*));
431 * copy tree (for function definition)
435 tcopy(struct op
*t
, Area
*ap
)
443 r
= alloc(sizeof(struct op
), ap
);
446 r
->u
.evalflags
= t
->u
.evalflags
;
448 r
->str
= t
->type
== TCASE
? wdcopy(t
->str
, ap
) : str_save(t
->str
, ap
);
453 for (tw
= t
->vars
; *tw
++ != NULL
; )
455 rw
= r
->vars
= areallocarray(NULL
, tw
- t
->vars
+ 1,
457 for (tw
= t
->vars
; *tw
!= NULL
; )
458 *rw
++ = wdcopy(*tw
++, ap
);
465 for (tw
= t
->args
; *tw
++ != NULL
; )
467 rw
= r
->args
= areallocarray(NULL
, tw
- t
->args
+ 1,
469 for (tw
= t
->args
; *tw
!= NULL
; )
470 *rw
++ = wdcopy(*tw
++, ap
);
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
;
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 */
492 wdscan(const char *wp
, int c
)
514 while (*wp
++ != '\0')
519 if (c
== CSUBST
&& nest
== 0)
529 if (c
== wp
[-1] && nest
== 0)
536 "%s: unknown char 0x%x (carrying on)",
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)
546 wdstrip(const char *wp
)
551 shf_sopen(NULL
, 32, SHF_WR
| SHF_DYNAMIC
, &shf
);
555 * x${foo:-"hi"} -> x${foo:-hi}
556 * x${foo:-'hi'} -> x${foo:-hi}
559 switch ((c
= *wp
++)) {
561 return shf_sclose(&shf
); /* null terminates */
564 shf_putchar(*wp
++, &shf
);
567 shf_putchar('$', &shf
);
568 shf_putchar('(', &shf
);
570 shf_putchar(*wp
++, &shf
);
571 shf_putchar(')', &shf
);
574 shf_putchar('$', &shf
);
575 shf_putchar('(', &shf
);
576 shf_putchar('(', &shf
);
578 shf_putchar(*wp
++, &shf
);
579 shf_putchar(')', &shf
);
580 shf_putchar(')', &shf
);
587 shf_putchar('$', &shf
);
589 shf_putchar('{', &shf
);
590 while ((c
= *wp
++) != 0)
591 shf_putchar(c
, &shf
);
595 shf_putchar('}', &shf
);
598 shf_putchar(*wp
++, &shf
);
599 shf_putchar('(', &shf
);
602 shf_putchar('|', &shf
);
605 shf_putchar(')', &shf
);
610 static struct ioword
**
611 iocopy(struct ioword
**iow
, Area
*ap
)
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
;
624 q
= alloc(sizeof(*p
), ap
);
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
);
640 * free tree (for function definition)
644 tfree(struct op
*t
, Area
*ap
)
653 if (t
->vars
!= NULL
) {
654 for (w
= t
->vars
; *w
!= NULL
; w
++)
659 if (t
->args
!= NULL
) {
660 for (w
= t
->args
; *w
!= NULL
; w
++)
665 if (t
->ioact
!= NULL
)
666 iofree(t
->ioact
, ap
);
675 iofree(struct ioword
**iow
, Area
*ap
)
680 for (iop
= iow
; (p
= *iop
++) != NULL
; ) {
683 afree(p
->heredoc
, ap
);