1 /* $OpenBSD: tree.c,v 1.20 2012/06/27 07:17:19 otto Exp $ */
4 * command tree climbing
11 #define tputc(c, shf) shf_putchar(c, shf);
12 static void ptree(struct op
*, int, struct shf
*);
13 static void pioact(struct shf
*, int, struct ioword
*);
14 static void tputC(int, struct shf
*);
15 static void tputS(char *, struct shf
*);
16 static void vfptreef(struct shf
*, int, const char *, va_list);
17 static struct ioword
**iocopy(struct ioword
**, Area
*);
18 static void iofree(struct ioword
**, Area
*);
21 * print a command tree
25 ptree(struct op
*t
, int indent
, struct shf
*shf
)
28 struct ioword
**ioact
;
37 for (w
= t
->vars
; *w
!= NULL
; )
38 fptreef(shf
, indent
, "%S ", *w
++);
40 fptreef(shf
, indent
, "#no-vars# ");
42 for (w
= t
->args
; *w
!= NULL
; )
43 fptreef(shf
, indent
, "%S ", *w
++);
45 fptreef(shf
, indent
, "#no-args# ");
48 #if 0 /* ?not useful - can't be called? */
49 /* Print original vars */
51 for (w
= t
->left
->vars
; *w
!= NULL
; )
52 fptreef(shf
, indent
, "%S ", *w
++);
54 fptreef(shf
, indent
, "#no-vars# ");
55 /* Print expanded vars */
57 for (w
= t
->args
; *w
!= NULL
; )
58 fptreef(shf
, indent
, "%s ", *w
++);
60 fptreef(shf
, indent
, "#no-args# ");
61 /* Print original io */
68 fptreef(shf
, indent
+ 2, "( %T) ", t
->left
);
71 fptreef(shf
, indent
, "%T| ", t
->left
);
75 fptreef(shf
, indent
, "%T%;", t
->left
);
80 fptreef(shf
, indent
, "%T%s %T",
81 t
->left
, (t
->type
==TOR
) ? "||" : "&&", t
->right
);
84 fptreef(shf
, indent
, "! ");
91 fptreef(shf
, indent
, "[[");
92 for (i
= 0; t
->args
[i
]; i
++)
93 fptreef(shf
, indent
, " %S", t
->args
[i
]);
94 fptreef(shf
, indent
, " ]] ");
98 fptreef(shf
, indent
, "select %s ", t
->str
);
102 fptreef(shf
, indent
, "for %s ", t
->str
);
103 if (t
->vars
!= NULL
) {
104 fptreef(shf
, indent
, "in ");
105 for (w
= t
->vars
; *w
; )
106 fptreef(shf
, indent
, "%S ", *w
++);
107 fptreef(shf
, indent
, "%;");
109 fptreef(shf
, indent
+ INDENT
, "do%N%T", t
->left
);
110 fptreef(shf
, indent
, "%;done ");
113 fptreef(shf
, indent
, "case %S in", t
->str
);
114 for (t1
= t
->left
; t1
!= NULL
; t1
= t1
->right
) {
115 fptreef(shf
, indent
, "%N(");
116 for (w
= t1
->vars
; *w
!= NULL
; w
++)
117 fptreef(shf
, indent
, "%S%c", *w
,
118 (w
[1] != NULL
) ? '|' : ')');
119 fptreef(shf
, indent
+ INDENT
, "%;%T%N;;", t1
->left
);
121 fptreef(shf
, indent
, "%Nesac ");
125 /* 3 == strlen("if ") */
126 fptreef(shf
, indent
+ 3, "if %T", t
->left
);
129 if (t
->left
!= NULL
) {
130 fptreef(shf
, indent
, "%;");
131 fptreef(shf
, indent
+ INDENT
, "then%N%T",
134 if (t
->right
== NULL
|| t
->right
->type
!= TELIF
)
137 fptreef(shf
, indent
, "%;");
138 /* 5 == strlen("elif ") */
139 fptreef(shf
, indent
+ 5, "elif %T", t
->left
);
141 if (t
->right
!= NULL
) {
142 fptreef(shf
, indent
, "%;");
143 fptreef(shf
, indent
+ INDENT
, "else%;%T", t
->right
);
145 fptreef(shf
, indent
, "%;fi ");
149 /* 6 == strlen("while"/"until") */
150 fptreef(shf
, indent
+ 6, "%s %T",
151 (t
->type
==TWHILE
) ? "while" : "until",
153 fptreef(shf
, indent
, "%;do");
154 fptreef(shf
, indent
+ INDENT
, "%;%T", t
->right
);
155 fptreef(shf
, indent
, "%;done ");
158 fptreef(shf
, indent
+ INDENT
, "{%;%T", t
->left
);
159 fptreef(shf
, indent
, "%;} ");
162 fptreef(shf
, indent
, "%T|& ", t
->left
);
165 fptreef(shf
, indent
, "%T& ", t
->left
);
169 t
->u
.ksh_func
? "function %s %T" : "%s() %T",
173 fptreef(shf
, indent
, "time %T", t
->left
);
176 fptreef(shf
, indent
, "<botch>");
179 if ((ioact
= t
->ioact
) != NULL
) {
182 while (*ioact
!= NULL
)
183 pioact(shf
, indent
, *ioact
++);
184 /* Print here documents after everything else... */
185 for (ioact
= t
->ioact
; *ioact
!= NULL
; ) {
186 struct ioword
*iop
= *ioact
++;
188 /* heredoc is 0 when tracing (set -x) */
189 if ((iop
->flag
& IOTYPE
) == IOHERE
&& iop
->heredoc
) {
191 shf_puts(iop
->heredoc
, shf
);
192 fptreef(shf
, indent
, "%s",
193 evalstr(iop
->delim
, 0));
197 /* Last delimiter must be followed by a newline (this often
198 * leads to an extra blank line, but its not worth worrying
207 pioact(struct shf
*shf
, int indent
, struct ioword
*iop
)
209 int flag
= iop
->flag
;
210 int type
= flag
& IOTYPE
;
213 expected
= (type
== IOREAD
|| type
== IORDWR
|| type
== IOHERE
) ? 0 :
214 (type
== IOCAT
|| type
== IOWRITE
) ? 1 :
215 (type
== IODUP
&& (iop
->unit
== !(flag
& IORDUP
))) ? iop
->unit
:
217 if (iop
->unit
!= expected
)
218 tputc('0' + iop
->unit
, shf
);
222 fptreef(shf
, indent
, "< ");
226 fptreef(shf
, indent
, "<<- ");
228 fptreef(shf
, indent
, "<< ");
231 fptreef(shf
, indent
, ">> ");
235 fptreef(shf
, indent
, ">| ");
237 fptreef(shf
, indent
, "> ");
240 fptreef(shf
, indent
, "<> ");
244 fptreef(shf
, indent
, "<&");
246 fptreef(shf
, indent
, ">&");
249 /* name/delim are 0 when printing syntax errors */
250 if (type
== IOHERE
) {
252 fptreef(shf
, indent
, "%S ", iop
->delim
);
253 } else if (iop
->name
)
254 fptreef(shf
, indent
, (iop
->flag
& IONAMEXP
) ? "%s " : "%S ",
260 * variants of fputc, fputs for ptreef and snptreef
264 tputC(int c
, struct shf
*shf
)
266 if ((c
&0x60) == 0) { /* C0|C1 */
267 tputc((c
&0x80) ? '$' : '^', shf
);
268 tputc(((c
&0x7F)|0x40), shf
);
269 } else if ((c
&0x7F) == 0x7F) { /* DEL */
270 tputc((c
&0x80) ? '$' : '^', shf
);
277 tputS(char *wp
, struct shf
*shf
)
284 * could change encoding to:
285 * OQUOTE ["'] ... CQUOTE ["']
286 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
289 switch ((c
= *wp
++)) {
297 if (!quoted
|| (c
== '"' || c
== '`' || c
== '$'))
331 while ((c
= *wp
++) != 0)
352 * this is the _only_ way to reliably handle
353 * variable args with an ANSI compiler
357 fptreef(struct shf
*shf
, int indent
, const char *fmt
, ...)
362 vfptreef(shf
, indent
, fmt
, va
);
368 snptreef(char *s
, int n
, const char *fmt
, ...)
373 shf_sopen(s
, n
, SHF_WR
| (s
? 0 : SHF_DYNAMIC
), &shf
);
376 vfptreef(&shf
, 0, fmt
, va
);
379 return shf_sclose(&shf
); /* null terminates */
383 vfptreef(struct shf
*shf
, int indent
, const char *fmt
, va_list va
)
387 while ((c
= *fmt
++)) {
393 switch ((c
= *fmt
++)) {
395 tputc(va_arg(va
, int), shf
);
398 p
= va_arg(va
, char *);
403 p
= va_arg(va
, char *);
406 case 'd': case 'u': /* decimal */
407 n
= (c
== 'd') ? va_arg(va
, int) :
408 va_arg(va
, unsigned int);
410 p
= ulton((neg
) ? -n
: n
, 10);
416 case 'T': /* format tree */
417 ptree(va_arg(va
, struct op
*), indent
, shf
);
419 case ';': /* newline or ; */
420 case 'N': /* newline or space */
421 if (shf
->flags
& SHF_STRING
) {
429 for (i
= indent
; i
>= 8; i
-= 8)
436 pioact(shf
, indent
, va_arg(va
, struct ioword
*));
448 * copy tree (for function definition)
452 tcopy(struct op
*t
, Area
*ap
)
460 r
= (struct op
*) alloc(sizeof(struct op
), ap
);
463 r
->u
.evalflags
= t
->u
.evalflags
;
465 r
->str
= t
->type
== TCASE
? wdcopy(t
->str
, ap
) : str_save(t
->str
, ap
);
470 for (tw
= t
->vars
; *tw
++ != NULL
; )
472 rw
= r
->vars
= (char **)
473 alloc((tw
- t
->vars
+ 1) * sizeof(*tw
), ap
);
474 for (tw
= t
->vars
; *tw
!= NULL
; )
475 *rw
++ = wdcopy(*tw
++, ap
);
482 for (tw
= t
->args
; *tw
++ != NULL
; )
484 rw
= r
->args
= (char **)
485 alloc((tw
- t
->args
+ 1) * sizeof(*tw
), ap
);
486 for (tw
= t
->args
; *tw
!= NULL
; )
487 *rw
++ = wdcopy(*tw
++, ap
);
491 r
->ioact
= (t
->ioact
== NULL
) ? NULL
: iocopy(t
->ioact
, ap
);
493 r
->left
= tcopy(t
->left
, ap
);
494 r
->right
= tcopy(t
->right
, ap
);
495 r
->lineno
= t
->lineno
;
501 wdcopy(const char *wp
, Area
*ap
)
503 size_t len
= wdscan(wp
, EOS
) - wp
;
504 return memcpy(alloc(len
, ap
), wp
, len
);
507 /* return the position of prefix c in wp plus 1 */
509 wdscan(const char *wp
, int c
)
531 while (*wp
++ != '\0')
536 if (c
== CSUBST
&& nest
== 0)
546 if (c
== wp
[-1] && nest
== 0)
553 "wdscan: unknown char 0x%x (carrying on)",
558 /* return a copy of wp without any of the mark up characters and
559 * with quote characters (" ' \) stripped.
560 * (string is allocated from ATEMP)
563 wdstrip(const char *wp
)
568 shf_sopen((char *) 0, 32, SHF_WR
| SHF_DYNAMIC
, &shf
);
572 * x${foo:-"hi"} -> x${foo:-hi}
573 * x${foo:-'hi'} -> x${foo:-hi}
576 switch ((c
= *wp
++)) {
578 return shf_sclose(&shf
); /* null terminates */
581 shf_putchar(*wp
++, &shf
);
584 shf_putchar('$', &shf
);
585 shf_putchar('(', &shf
);
587 shf_putchar(*wp
++, &shf
);
588 shf_putchar(')', &shf
);
591 shf_putchar('$', &shf
);
592 shf_putchar('(', &shf
);
593 shf_putchar('(', &shf
);
595 shf_putchar(*wp
++, &shf
);
596 shf_putchar(')', &shf
);
597 shf_putchar(')', &shf
);
604 shf_putchar('$', &shf
);
606 shf_putchar('{', &shf
);
607 while ((c
= *wp
++) != 0)
608 shf_putchar(c
, &shf
);
612 shf_putchar('}', &shf
);
615 shf_putchar(*wp
++, &shf
);
616 shf_putchar('(', &shf
);
619 shf_putchar('|', &shf
);
622 shf_putchar(')', &shf
);
627 static struct ioword
**
628 iocopy(struct ioword
**iow
, Area
*ap
)
633 for (ior
= iow
; *ior
++ != NULL
; )
635 ior
= (struct ioword
**) alloc((ior
- iow
+ 1) * sizeof(*ior
), ap
);
637 for (i
= 0; iow
[i
] != NULL
; i
++) {
638 struct ioword
*p
, *q
;
641 q
= (struct ioword
*) alloc(sizeof(*p
), ap
);
644 if (p
->name
!= (char *) 0)
645 q
->name
= wdcopy(p
->name
, ap
);
646 if (p
->delim
!= (char *) 0)
647 q
->delim
= wdcopy(p
->delim
, ap
);
648 if (p
->heredoc
!= (char *) 0)
649 q
->heredoc
= str_save(p
->heredoc
, ap
);
657 * free tree (for function definition)
661 tfree(struct op
*t
, Area
*ap
)
669 afree((void*)t
->str
, ap
);
671 if (t
->vars
!= NULL
) {
672 for (w
= t
->vars
; *w
!= NULL
; w
++)
673 afree((void*)*w
, ap
);
674 afree((void*)t
->vars
, ap
);
677 if (t
->args
!= NULL
) {
678 for (w
= t
->args
; *w
!= NULL
; w
++)
679 afree((void*)*w
, ap
);
680 afree((void*)t
->args
, ap
);
683 if (t
->ioact
!= NULL
)
684 iofree(t
->ioact
, ap
);
693 iofree(struct ioword
**iow
, Area
*ap
)
698 for (iop
= iow
; (p
= *iop
++) != NULL
; ) {
700 afree((void*)p
->name
, ap
);
701 if (p
->delim
!= NULL
)
702 afree((void*)p
->delim
, ap
);
703 if (p
->heredoc
!= NULL
)
704 afree((void*)p
->heredoc
, ap
);