1 /* $NetBSD: tree.c,v 1.5 2004/07/07 19:20:09 mycroft Exp $ */
4 * command tree climbing
9 __RCSID("$NetBSD: tree.c,v 1.5 2004/07/07 19:20:09 mycroft Exp $");
17 #define tputc(c, shf) shf_putchar(c, shf);
18 static void ptree
ARGS((struct op
*t
, int indent
, struct shf
*f
));
19 static void pioact
ARGS((struct shf
*f
, int indent
, struct ioword
*iop
));
20 static void tputC
ARGS((int c
, struct shf
*shf
));
21 static void tputS
ARGS((char *wp
, struct shf
*shf
));
22 static void vfptreef
ARGS((struct shf
*shf
, int indent
, const char *fmt
, va_list va
));
23 static struct ioword
**iocopy
ARGS((struct ioword
**iow
, Area
*ap
));
24 static void iofree
ARGS((struct ioword
**iow
, Area
*ap
));
27 * print a command tree
32 register struct op
*t
;
34 register struct shf
*shf
;
37 struct ioword
**ioact
;
46 for (w
= t
->vars
; *w
!= NULL
; )
47 fptreef(shf
, indent
, "%S ", *w
++);
49 fptreef(shf
, indent
, "#no-vars# ");
51 for (w
= t
->args
; *w
!= NULL
; )
52 fptreef(shf
, indent
, "%S ", *w
++);
54 fptreef(shf
, indent
, "#no-args# ");
57 #if 0 /* ?not useful - can't be called? */
58 /* Print original vars */
60 for (w
= t
->left
->vars
; *w
!= NULL
; )
61 fptreef(shf
, indent
, "%S ", *w
++);
63 fptreef(shf
, indent
, "#no-vars# ");
64 /* Print expanded vars */
66 for (w
= t
->args
; *w
!= NULL
; )
67 fptreef(shf
, indent
, "%s ", *w
++);
69 fptreef(shf
, indent
, "#no-args# ");
70 /* Print original io */
77 fptreef(shf
, indent
+ 2, "( %T) ", t
->left
);
80 fptreef(shf
, indent
, "%T| ", t
->left
);
84 fptreef(shf
, indent
, "%T%;", t
->left
);
89 fptreef(shf
, indent
, "%T%s %T",
90 t
->left
, (t
->type
==TOR
) ? "||" : "&&", t
->right
);
93 fptreef(shf
, indent
, "! ");
100 fptreef(shf
, indent
, "[[");
101 for (i
= 0; t
->args
[i
]; i
++)
102 fptreef(shf
, indent
, " %S", t
->args
[i
]);
103 fptreef(shf
, indent
, " ]] ");
108 fptreef(shf
, indent
, "select %s ", t
->str
);
113 fptreef(shf
, indent
, "for %s ", t
->str
);
114 if (t
->vars
!= NULL
) {
115 fptreef(shf
, indent
, "in ");
116 for (w
= t
->vars
; *w
; )
117 fptreef(shf
, indent
, "%S ", *w
++);
118 fptreef(shf
, indent
, "%;");
120 fptreef(shf
, indent
+ INDENT
, "do%N%T", t
->left
);
121 fptreef(shf
, indent
, "%;done ");
124 fptreef(shf
, indent
, "case %S in", t
->str
);
125 for (t1
= t
->left
; t1
!= NULL
; t1
= t1
->right
) {
126 fptreef(shf
, indent
, "%N(");
127 for (w
= t1
->vars
; *w
!= NULL
; w
++)
128 fptreef(shf
, indent
, "%S%c", *w
,
129 (w
[1] != NULL
) ? '|' : ')');
130 fptreef(shf
, indent
+ INDENT
, "%;%T%N;;", t1
->left
);
132 fptreef(shf
, indent
, "%Nesac ");
136 /* 3 == strlen("if ") */
137 fptreef(shf
, indent
+ 3, "if %T", t
->left
);
140 if (t
->left
!= NULL
) {
141 fptreef(shf
, indent
, "%;");
142 fptreef(shf
, indent
+ INDENT
, "then%N%T",
145 if (t
->right
== NULL
|| t
->right
->type
!= TELIF
)
148 fptreef(shf
, indent
, "%;");
149 /* 5 == strlen("elif ") */
150 fptreef(shf
, indent
+ 5, "elif %T", t
->left
);
152 if (t
->right
!= NULL
) {
153 fptreef(shf
, indent
, "%;");
154 fptreef(shf
, indent
+ INDENT
, "else%;%T", t
->right
);
156 fptreef(shf
, indent
, "%;fi ");
160 /* 6 == strlen("while"/"until") */
161 fptreef(shf
, indent
+ 6, "%s %T",
162 (t
->type
==TWHILE
) ? "while" : "until",
164 fptreef(shf
, indent
, "%;do");
165 fptreef(shf
, indent
+ INDENT
, "%;%T", t
->right
);
166 fptreef(shf
, indent
, "%;done ");
169 fptreef(shf
, indent
+ INDENT
, "{%;%T", t
->left
);
170 fptreef(shf
, indent
, "%;} ");
173 fptreef(shf
, indent
, "%T|& ", t
->left
);
176 fptreef(shf
, indent
, "%T& ", t
->left
);
180 t
->u
.ksh_func
? "function %s %T" : "%s() %T",
184 fptreef(shf
, indent
, "time %T", t
->left
);
187 fptreef(shf
, indent
, "<botch>");
190 if ((ioact
= t
->ioact
) != NULL
) {
193 while (*ioact
!= NULL
)
194 pioact(shf
, indent
, *ioact
++);
195 /* Print here documents after everything else... */
196 for (ioact
= t
->ioact
; *ioact
!= NULL
; ) {
197 struct ioword
*iop
= *ioact
++;
199 /* heredoc is 0 when tracing (set -x) */
200 if ((iop
->flag
& IOTYPE
) == IOHERE
&& iop
->heredoc
) {
202 shf_puts(iop
->heredoc
, shf
);
203 fptreef(shf
, indent
, "%s",
204 evalstr(iop
->delim
, 0));
208 /* Last delimiter must be followed by a newline (this often
209 * leads to an extra blank line, but its not worth worrying
218 pioact(shf
, indent
, iop
)
219 register struct shf
*shf
;
221 register struct ioword
*iop
;
223 int flag
= iop
->flag
;
224 int type
= flag
& IOTYPE
;
227 expected
= (type
== IOREAD
|| type
== IORDWR
|| type
== IOHERE
) ? 0
228 : (type
== IOCAT
|| type
== IOWRITE
) ? 1
229 : (type
== IODUP
&& (iop
->unit
== !(flag
& IORDUP
))) ?
232 if (iop
->unit
!= expected
)
233 tputc('0' + iop
->unit
, shf
);
237 fptreef(shf
, indent
, "< ");
241 fptreef(shf
, indent
, "<<- ");
243 fptreef(shf
, indent
, "<< ");
246 fptreef(shf
, indent
, ">> ");
250 fptreef(shf
, indent
, ">| ");
252 fptreef(shf
, indent
, "> ");
255 fptreef(shf
, indent
, "<> ");
259 fptreef(shf
, indent
, "<&");
261 fptreef(shf
, indent
, ">&");
264 /* name/delim are 0 when printing syntax errors */
265 if (type
== IOHERE
) {
267 fptreef(shf
, indent
, "%S ", iop
->delim
);
268 } else if (iop
->name
)
269 fptreef(shf
, indent
, (iop
->flag
& IONAMEXP
) ? "%s " : "%S ",
275 * variants of fputc, fputs for ptreef and snptreef
281 register struct shf
*shf
;
283 if ((c
&0x60) == 0) { /* C0|C1 */
284 tputc((c
&0x80) ? '$' : '^', shf
);
285 tputc(((c
&0x7F)|0x40), shf
);
286 } else if ((c
&0x7F) == 0x7F) { /* DEL */
287 tputc((c
&0x80) ? '$' : '^', shf
);
296 register struct shf
*shf
;
298 register int c
, quoted
=0;
303 * could change encoding to:
304 * OQUOTE ["'] ... CQUOTE ["']
305 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
308 switch ((c
= *wp
++)) {
316 if (!quoted
|| (c
== '"' || c
== '`' || c
== '$'))
350 while ((c
= *wp
++) != 0)
373 * this is the _only_ way to reliably handle
374 * variable args with an ANSI compiler
378 #ifdef HAVE_PROTOTYPES
379 fptreef(struct shf
*shf
, int indent
, const char *fmt
, ...)
381 fptreef(shf
, indent
, fmt
, va_alist
)
390 SH_VA_START(va
, fmt
);
392 vfptreef(shf
, indent
, fmt
, va
);
399 #ifdef HAVE_PROTOTYPES
400 snptreef(char *s
, int n
, const char *fmt
, ...)
402 snptreef(s
, n
, fmt
, va_alist
)
412 shf_sopen(s
, n
, SHF_WR
| (s
? 0 : SHF_DYNAMIC
), &shf
);
414 SH_VA_START(va
, fmt
);
415 vfptreef(&shf
, 0, fmt
, va
);
418 return shf_sclose(&shf
); /* null terminates */
422 vfptreef(shf
, indent
, fmt
, va
)
423 register struct shf
*shf
;
436 switch ((c
= *fmt
++)) {
438 tputc(va_arg(va
, int), shf
);
441 p
= va_arg(va
, char *);
446 p
= va_arg(va
, char *);
449 case 'd': case 'u': /* decimal */
450 n
= (c
== 'd') ? va_arg(va
, int)
451 : va_arg(va
, unsigned int);
453 p
= ulton((neg
) ? -n
: n
, 10);
459 case 'T': /* format tree */
460 ptree(va_arg(va
, struct op
*), indent
, shf
);
462 case ';': /* newline or ; */
463 case 'N': /* newline or space */
464 if (shf
->flags
& SHF_STRING
) {
472 for (i
= indent
; i
>= 8; i
-= 8)
479 pioact(shf
, indent
, va_arg(va
, struct ioword
*));
490 * copy tree (for function definition)
495 register struct op
*t
;
498 register struct op
*r
;
499 register char **tw
, **rw
;
504 r
= (struct op
*) alloc(sizeof(struct op
), ap
);
507 r
->u
.evalflags
= t
->u
.evalflags
;
509 r
->str
= t
->type
== TCASE
? wdcopy(t
->str
, ap
) : str_save(t
->str
, ap
);
514 for (tw
= t
->vars
; *tw
++ != NULL
; )
516 rw
= r
->vars
= (char **)
517 alloc((tw
- t
->vars
+ 1) * sizeof(*tw
), ap
);
518 for (tw
= t
->vars
; *tw
!= NULL
; )
519 *rw
++ = wdcopy(*tw
++, ap
);
526 for (tw
= t
->args
; *tw
++ != NULL
; )
528 rw
= r
->args
= (char **)
529 alloc((tw
- t
->args
+ 1) * sizeof(*tw
), ap
);
530 for (tw
= t
->args
; *tw
!= NULL
; )
531 *rw
++ = wdcopy(*tw
++, ap
);
535 r
->ioact
= (t
->ioact
== NULL
) ? NULL
: iocopy(t
->ioact
, ap
);
537 r
->left
= tcopy(t
->left
, ap
);
538 r
->right
= tcopy(t
->right
, ap
);
539 r
->lineno
= t
->lineno
;
549 size_t len
= wdscan(wp
, EOS
) - wp
;
550 return memcpy(alloc(len
, ap
), wp
, len
);
553 /* return the position of prefix c in wp plus 1 */
556 register const char *wp
;
559 register int nest
= 0;
564 return (char *) __UNCONST(wp
);
579 while (*wp
++ != '\0')
584 if (c
== CSUBST
&& nest
== 0)
585 return (char *) __UNCONST(wp
);
595 if (c
== wp
[-1] && nest
== 0)
596 return (char *) __UNCONST(wp
);
603 "wdscan: unknown char 0x%x (carrying on)",
608 /* return a copy of wp without any of the mark up characters and
609 * with quote characters (" ' \) stripped.
610 * (string is allocated from ATEMP)
619 shf_sopen((char *) 0, 32, SHF_WR
| SHF_DYNAMIC
, &shf
);
623 * x${foo:-"hi"} -> x${foo:-hi}
624 * x${foo:-'hi'} -> x${foo:-hi}
627 switch ((c
= *wp
++)) {
629 return shf_sclose(&shf
); /* null terminates */
632 shf_putchar(*wp
++, &shf
);
635 shf_putchar('$', &shf
);
636 shf_putchar('(', &shf
);
638 shf_putchar(*wp
++, &shf
);
639 shf_putchar(')', &shf
);
642 shf_putchar('$', &shf
);
643 shf_putchar('(', &shf
);
644 shf_putchar('(', &shf
);
646 shf_putchar(*wp
++, &shf
);
647 shf_putchar(')', &shf
);
648 shf_putchar(')', &shf
);
655 shf_putchar('$', &shf
);
657 shf_putchar('{', &shf
);
658 while ((c
= *wp
++) != 0)
659 shf_putchar(c
, &shf
);
663 shf_putchar('}', &shf
);
667 shf_putchar(*wp
++, &shf
);
668 shf_putchar('(', &shf
);
671 shf_putchar('|', &shf
);
674 shf_putchar(')', &shf
);
680 static struct ioword
**
682 register struct ioword
**iow
;
685 register struct ioword
**ior
;
688 for (ior
= iow
; *ior
++ != NULL
; )
690 ior
= (struct ioword
**) alloc((ior
- iow
+ 1) * sizeof(*ior
), ap
);
692 for (i
= 0; iow
[i
] != NULL
; i
++) {
693 register struct ioword
*p
, *q
;
696 q
= (struct ioword
*) alloc(sizeof(*p
), ap
);
699 if (p
->name
!= (char *) 0)
700 q
->name
= wdcopy(p
->name
, ap
);
701 if (p
->delim
!= (char *) 0)
702 q
->delim
= wdcopy(p
->delim
, ap
);
703 if (p
->heredoc
!= (char *) 0)
704 q
->heredoc
= str_save(p
->heredoc
, ap
);
712 * free tree (for function definition)
717 register struct op
*t
;
726 afree((void*)t
->str
, ap
);
728 if (t
->vars
!= NULL
) {
729 for (w
= t
->vars
; *w
!= NULL
; w
++)
730 afree((void*)*w
, ap
);
731 afree((void*)t
->vars
, ap
);
734 if (t
->args
!= NULL
) {
735 for (w
= t
->args
; *w
!= NULL
; w
++)
736 afree((void*)*w
, ap
);
737 afree((void*)t
->args
, ap
);
740 if (t
->ioact
!= NULL
)
741 iofree(t
->ioact
, ap
);
754 register struct ioword
**iop
;
755 register struct ioword
*p
;
757 for (iop
= iow
; (p
= *iop
++) != NULL
; ) {
759 afree((void*)p
->name
, ap
);
760 if (p
->delim
!= NULL
)
761 afree((void*)p
->delim
, ap
);
762 if (p
->heredoc
!= NULL
)
763 afree((void*)p
->heredoc
, ap
);