1 /*
2 * text.c - textual representations of syntax trees
3 *
4 * This file is part of zsh, the Z shell.
5 *
6 * Copyright (c) 1992-1997 Paul Falstad
7 * All rights reserved.
8 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
14 *
15 * In no event shall Paul Falstad or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Paul Falstad and the Zsh Development Group have been advised of
19 * the possibility of such damage.
20 *
21 * Paul Falstad and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose. The software
24 * provided hereunder is on an "as is" basis, and Paul Falstad and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
27 *
28 */
29
30 #include "zsh.mdh"
31 #include "text.pro"
32
33 /*
34 * If non-zero, expand syntactically significant leading tabs in text
35 * to this number of spaces.
36 *
37 * If negative, don't output leading whitespace at all.
38 */
39
40 /**/
41 int text_expand_tabs;
42
43 /*
44 * Binary operators in conditions.
45 * There order is tied to the order of the definitions COND_STREQ
46 * et seq. in zsh.h.
47 */
48 static const char *cond_binary_ops[] = {
49 "=", "==", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
50 "-ne", "-lt", "-gt", "-le", "-ge", "=~", NULL
51 };
52
53 static char *tptr, *tbuf, *tlim, *tpending;
54 static int tsiz, tindent, tnewlins, tjob;
55
56 /**/
57 int
is_cond_binary_op(const char * str)58 is_cond_binary_op(const char *str)
59 {
60 const char **op;
61 for (op = cond_binary_ops; *op; op++)
62 {
63 if (!strcmp(str, *op))
64 return 1;
65 }
66 return 0;
67 }
68
69 static void
dec_tindent(void)70 dec_tindent(void)
71 {
72 DPUTS(tindent == 0, "attempting to decrement tindent below zero");
73 if (tindent > 0)
74 tindent--;
75 }
76
77 /*
78 * Add a pair of pending strings and a newline.
79 * This is used for here documents. It will be output when
80 * we have a lexically significant newline.
81 *
82 * This isn't that common and a multiple use on the same line is *very*
83 * uncommon; we don't try to optimise it.
84 *
85 * This is not used for job text; there we bear the inaccuracy
86 * of turning this into a here-string.
87 */
88 static void
taddpending(char * str1,char * str2)89 taddpending(char *str1, char *str2)
90 {
91 int len = strlen(str1) + strlen(str2) + 1;
92
93 /*
94 * We don't strip newlines from here-documents converted
95 * to here-strings, so no munging is required except to
96 * add a newline after the here-document terminator.
97 * However, because the job text doesn't automatically
98 * have a newline right at the end, we handle that
99 * specially.
100 */
101 if (tpending) {
102 int oldlen = strlen(tpending);
103 tpending = zrealloc(tpending, len + oldlen + 1);
104 sprintf(tpending + oldlen, "\n%s%s", str1, str2);
105 } else {
106 tpending = (char *)zalloc(len);
107 sprintf(tpending, "%s%s", str1, str2);
108 }
109 }
110
111 /* Output the pending string where appropriate */
112
113 static void
tdopending(void)114 tdopending(void)
115 {
116 if (tpending) {
117 taddchr('\n');
118 taddstr(tpending);
119 zsfree(tpending);
120 tpending = NULL;
121 }
122 }
123
124 /* add a character to the text buffer */
125
126 /**/
127 static void
taddchr(int c)128 taddchr(int c)
129 {
130 *tptr++ = c;
131 if (tptr == tlim) {
132 if (!tbuf) {
133 tptr--;
134 return;
135 }
136 tbuf = zrealloc(tbuf, tsiz *= 2);
137 tlim = tbuf + tsiz;
138 tptr = tbuf + tsiz / 2;
139 }
140 }
141
142 /* add a string to the text buffer */
143
144 /**/
145 static void
taddstr(const char * s)146 taddstr(const char *s)
147 {
148 int sl = strlen(s);
149 char c;
150
151 while (tptr + sl >= tlim) {
152 int x = tptr - tbuf;
153
154 if (!tbuf)
155 return;
156 tbuf = zrealloc(tbuf, tsiz *= 2);
157 tlim = tbuf + tsiz;
158 tptr = tbuf + x;
159 }
160 if (tnewlins) {
161 memcpy(tptr, s, sl);
162 tptr += sl;
163 } else
164 while ((c = *s++))
165 *tptr++ = (c == '\n' ? ' ' : c);
166 }
167
168 /**/
169 static void
taddlist(Estate state,int num)170 taddlist(Estate state, int num)
171 {
172 if (num) {
173 while (num--) {
174 taddstr(ecgetstr(state, EC_NODUP, NULL));
175 taddchr(' ');
176 }
177 tptr--;
178 }
179 }
180
181 /* add an assignment */
182
183 static void
taddassign(wordcode code,Estate state,int typeset)184 taddassign(wordcode code, Estate state, int typeset)
185 {
186 /* name */
187 taddstr(ecgetstr(state, EC_NODUP, NULL));
188 /* value... maybe */
189 if (WC_ASSIGN_TYPE2(code) == WC_ASSIGN_INC) {
190 if (typeset) {
191 /* dummy assignment --- just var name */
192 (void)ecgetstr(state, EC_NODUP, NULL);
193 taddchr(' ');
194 return;
195 }
196 taddchr('+');
197 }
198 taddchr('=');
199 if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) {
200 taddchr('(');
201 taddlist(state, WC_ASSIGN_NUM(code));
202 taddstr(") ");
203 } else {
204 taddstr(ecgetstr(state, EC_NODUP, NULL));
205 taddchr(' ');
206 }
207 }
208
209 /* add a number of assignments from typeset */
210
211 /**/
212 static void
taddassignlist(Estate state,wordcode count)213 taddassignlist(Estate state, wordcode count)
214 {
215 if (count)
216 taddchr(' ');
217 while (count--) {
218 wordcode code = *state->pc++;
219 taddassign(code, state, 1);
220 }
221 }
222
223 /* add a newline, or something equivalent, to the text buffer */
224
225 /**/
226 static void
taddnl(int no_semicolon)227 taddnl(int no_semicolon)
228 {
229 int t0;
230
231 if (tnewlins) {
232 tdopending();
233 taddchr('\n');
234 for (t0 = 0; t0 != tindent; t0++) {
235 if (text_expand_tabs >= 0) {
236 if (text_expand_tabs) {
237 int t1;
238 for (t1 = 0; t1 < text_expand_tabs; t1++)
239 taddchr(' ');
240 } else
241 taddchr('\t');
242 }
243 }
244 } else if (no_semicolon) {
245 taddstr(" ");
246 } else {
247 taddstr("; ");
248 }
249 }
250
251 /*
252 * Output a tab that may be expanded as part of a leading set.
253 * Note this is not part of the text framework; it's for
254 * code that needs to output its own tabs that are to be
255 * consistent with those from getpermtext().
256 *
257 * Note these tabs are only expected to be useful at the
258 * start of the line, so we make no attempt to count columns.
259 */
260
261 /**/
262 void
zoutputtab(FILE * outf)263 zoutputtab(FILE *outf)
264 {
265 if (text_expand_tabs < 0)
266 return;
267 if (text_expand_tabs) {
268 int i;
269 for (i = 0; i < text_expand_tabs; i++)
270 fputc(' ', outf);
271 } else
272 fputc('\t', outf);
273 }
274
275 /* get a permanent textual representation of n */
276
277 /**/
278 mod_export char *
getpermtext(Eprog prog,Wordcode c,int start_indent)279 getpermtext(Eprog prog, Wordcode c, int start_indent)
280 {
281 struct estate s;
282
283 queue_signals();
284
285 if (!c)
286 c = prog->prog;
287
288 useeprog(prog); /* mark as used */
289
290 s.prog = prog;
291 s.pc = c;
292 s.strs = prog->strs;
293
294 tindent = start_indent;
295 tnewlins = 1;
296 tbuf = (char *)zalloc(tsiz = 32);
297 tptr = tbuf;
298 tlim = tbuf + tsiz;
299 tjob = 0;
300 if (prog->len)
301 gettext2(&s);
302 *tptr = '\0';
303 freeeprog(prog); /* mark as unused */
304 untokenize(tbuf);
305
306 unqueue_signals();
307
308 return tbuf;
309 }
310
311 /* get a representation of n in a job text buffer */
312
313 /**/
314 char *
getjobtext(Eprog prog,Wordcode c)315 getjobtext(Eprog prog, Wordcode c)
316 {
317 static char jbuf[JOBTEXTSIZE];
318
319 struct estate s;
320
321 queue_signals();
322
323 if (!c)
324 c = prog->prog;
325
326 useeprog(prog); /* mark as used */
327 s.prog = prog;
328 s.pc = c;
329 s.strs = prog->strs;
330
331 tindent = 0;
332 tnewlins = 0;
333 tbuf = NULL;
334 tptr = jbuf;
335 tlim = tptr + JOBTEXTSIZE - 1;
336 tjob = 1;
337 gettext2(&s);
338 *tptr = '\0';
339 freeeprog(prog); /* mark as unused */
340 untokenize(jbuf);
341
342 unqueue_signals();
343
344 return jbuf;
345 }
346
347 /*
348 * gettext2() shows one way to walk through the word code without
349 * recursion. We start by reading a word code and executing the
350 * action for it. Some codes have sub-structures (like, e.g. WC_FOR)
351 * and require something to be done after the sub-structure has been
352 * handled. For these codes a tstack structure which describes what
353 * has to be done is pushed onto a stack. Codes without sub-structures
354 * arrange for the next structure being taken from the stack so that
355 * the action for it is executed instead of the one for the next
356 * word code. If the stack is empty at this point, we have handled
357 * the whole structure we were called for.
358 */
359
360 typedef struct tstack *Tstack;
361
362 struct tstack {
363 Tstack prev;
364 wordcode code;
365 int pop;
366 union {
367 struct {
368 LinkList list;
369 } _redir;
370 struct {
371 char *strs;
372 Wordcode end;
373 int nargs;
374 } _funcdef;
375 struct {
376 Wordcode end;
377 } _case;
378 struct {
379 int cond;
380 Wordcode end;
381 } _if;
382 struct {
383 int par;
384 } _cond;
385 struct {
386 Wordcode end;
387 } _subsh;
388 } u;
389 };
390
391 static Tstack tstack, tfree;
392
393 static Tstack
tpush(wordcode code,int pop)394 tpush(wordcode code, int pop)
395 {
396 Tstack s;
397
398 if ((s = tfree))
399 tfree = s->prev;
400 else
401 s = (Tstack) zalloc(sizeof(*s));
402
403 s->prev = tstack;
404 tstack = s;
405 s->code = code;
406 s->pop = pop;
407
408 return s;
409 }
410
411 /**/
412 static void
gettext2(Estate state)413 gettext2(Estate state)
414 {
415 Tstack s, n;
416 int stack = 0;
417 wordcode code;
418
419 while (1) {
420 if (stack) {
421 if (!(s = tstack))
422 break;
423 if (s->pop) {
424 tstack = s->prev;
425 s->prev = tfree;
426 tfree = s;
427 }
428 code = s->code;
429 stack = 0;
430 } else {
431 s = NULL;
432 code = *state->pc++;
433 }
434 switch (wc_code(code)) {
435 case WC_LIST:
436 if (!s) {
437 s = tpush(code, (WC_LIST_TYPE(code) & Z_END));
438 stack = 0;
439 } else {
440 if (WC_LIST_TYPE(code) & Z_ASYNC) {
441 taddstr(" &");
442 if (WC_LIST_TYPE(code) & Z_DISOWN)
443 taddstr("|");
444 }
445 if (!(stack = (WC_LIST_TYPE(code) & Z_END))) {
446 if (tnewlins)
447 taddnl(0);
448 else
449 taddstr((WC_LIST_TYPE(code) & Z_ASYNC) ? " " : "; ");
450 s->code = *state->pc++;
451 s->pop = (WC_LIST_TYPE(s->code) & Z_END);
452 }
453 }
454 if (!stack && (WC_LIST_TYPE(s->code) & Z_SIMPLE))
455 state->pc++;
456 break;
457 case WC_SUBLIST:
458 if (!s) {
459 if (!(WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) &&
460 wc_code(*state->pc) != WC_PIPE)
461 stack = -1;
462 if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT)
463 taddstr(stack ? "!" : "! ");
464 if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_COPROC)
465 taddstr(stack ? "coproc" : "coproc ");
466 s = tpush(code, (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END));
467 } else {
468 if (!(stack = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END))) {
469 taddstr((WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) ?
470 " || " : " && ");
471 s->code = *state->pc++;
472 s->pop = (WC_SUBLIST_TYPE(s->code) == WC_SUBLIST_END);
473 if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_NOT) {
474 if (WC_SUBLIST_SKIP(s->code) == 0)
475 stack = 1;
476 taddstr((stack || (!(WC_SUBLIST_FLAGS(s->code) &
477 WC_SUBLIST_SIMPLE) && wc_code(*state->pc) !=
478 WC_PIPE)) ? "!" : "! ");
479 }
480 if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_COPROC)
481 taddstr("coproc ");
482 }
483 }
484 if (stack < 1 && (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_SIMPLE))
485 state->pc++;
486 break;
487 case WC_PIPE:
488 if (!s) {
489 tpush(code, (WC_PIPE_TYPE(code) == WC_PIPE_END));
490 if (WC_PIPE_TYPE(code) == WC_PIPE_MID)
491 state->pc++;
492 } else {
493 if (!(stack = (WC_PIPE_TYPE(code) == WC_PIPE_END))) {
494 taddstr(" | ");
495 s->code = *state->pc++;
496 if (!(s->pop = (WC_PIPE_TYPE(s->code) == WC_PIPE_END)))
497 state->pc++;
498 }
499 }
500 break;
501 case WC_REDIR:
502 if (!s) {
503 state->pc--;
504 n = tpush(code, 1);
505 n->u._redir.list = ecgetredirs(state);
506 } else {
507 getredirs(s->u._redir.list);
508 stack = 1;
509 }
510 break;
511 case WC_ASSIGN:
512 taddassign(code, state, 0);
513 break;
514 case WC_SIMPLE:
515 taddlist(state, WC_SIMPLE_ARGC(code));
516 stack = 1;
517 break;
518 case WC_TYPESET:
519 taddlist(state, WC_TYPESET_ARGC(code));
520 taddassignlist(state, *state->pc++);
521 stack = 1;
522 break;
523 case WC_SUBSH:
524 if (!s) {
525 taddstr("(");
526 tindent++;
527 taddnl(1);
528 n = tpush(code, 1);
529 n->u._subsh.end = state->pc + WC_SUBSH_SKIP(code);
530 /* skip word only use for try/always */
531 state->pc++;
532 } else {
533 state->pc = s->u._subsh.end;
534 dec_tindent();
535 /* semicolon is optional here but more standard */
536 taddnl(0);
537 taddstr(")");
538 stack = 1;
539 }
540 break;
541 case WC_CURSH:
542 if (!s) {
543 taddstr("{");
544 tindent++;
545 taddnl(1);
546 n = tpush(code, 1);
547 n->u._subsh.end = state->pc + WC_CURSH_SKIP(code);
548 /* skip word only use for try/always */
549 state->pc++;
550 } else {
551 state->pc = s->u._subsh.end;
552 dec_tindent();
553 /* semicolon is optional here but more standard */
554 taddnl(0);
555 taddstr("}");
556 stack = 1;
557 }
558 break;
559 case WC_TIMED:
560 if (!s) {
561 taddstr("time");
562 if (WC_TIMED_TYPE(code) == WC_TIMED_PIPE) {
563 taddchr(' ');
564 tindent++;
565 tpush(code, 1);
566 } else
567 stack = 1;
568 } else {
569 dec_tindent();
570 stack = 1;
571 }
572 break;
573 case WC_FUNCDEF:
574 if (!s) {
575 Wordcode p = state->pc;
576 Wordcode end = p + WC_FUNCDEF_SKIP(code);
577 int nargs = *state->pc++;
578
579 taddlist(state, nargs);
580 if (nargs)
581 taddstr(" ");
582 if (tjob) {
583 taddstr("() { ... }");
584 state->pc = end;
585 if (!nargs) {
586 /*
587 * Unnamed function.
588 * We're not going to pull any arguments off
589 * later, so skip them now...
590 */
591 state->pc += *end;
592 }
593 stack = 1;
594 } else {
595 taddstr("() {");
596 tindent++;
597 taddnl(1);
598 n = tpush(code, 1);
599 n->u._funcdef.strs = state->strs;
600 n->u._funcdef.end = end;
601 n->u._funcdef.nargs = nargs;
602 state->strs += *state->pc;
603 state->pc += 3;
604 }
605 } else {
606 state->strs = s->u._funcdef.strs;
607 state->pc = s->u._funcdef.end;
608 dec_tindent();
609 taddnl(0);
610 taddstr("}");
611 if (s->u._funcdef.nargs == 0) {
612 /* Unnamed function with post-arguments */
613 int nargs;
614 s->u._funcdef.end += *state->pc++;
615 nargs = *state->pc++;
616 if (nargs) {
617 taddstr(" ");
618 taddlist(state, nargs);
619 }
620 state->pc = s->u._funcdef.end;
621 }
622 stack = 1;
623 }
624 break;
625 case WC_FOR:
626 if (!s) {
627 taddstr("for ");
628 if (WC_FOR_TYPE(code) == WC_FOR_COND) {
629 taddstr("((");
630 taddstr(ecgetstr(state, EC_NODUP, NULL));
631 taddstr("; ");
632 taddstr(ecgetstr(state, EC_NODUP, NULL));
633 taddstr("; ");
634 taddstr(ecgetstr(state, EC_NODUP, NULL));
635 taddstr(")) do");
636 } else {
637 taddlist(state, *state->pc++);
638 if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
639 taddstr(" in ");
640 taddlist(state, *state->pc++);
641 }
642 taddnl(0);
643 taddstr("do");
644 }
645 tindent++;
646 taddnl(0);
647 tpush(code, 1);
648 } else {
649 dec_tindent();
650 taddnl(0);
651 taddstr("done");
652 stack = 1;
653 }
654 break;
655 case WC_SELECT:
656 if (!s) {
657 taddstr("select ");
658 taddstr(ecgetstr(state, EC_NODUP, NULL));
659 if (WC_SELECT_TYPE(code) == WC_SELECT_LIST) {
660 taddstr(" in ");
661 taddlist(state, *state->pc++);
662 }
663 taddnl(0);
664 taddstr("do");
665 taddnl(0);
666 tindent++;
667 tpush(code, 1);
668 } else {
669 dec_tindent();
670 taddnl(0);
671 taddstr("done");
672 stack = 1;
673 }
674 break;
675 case WC_WHILE:
676 if (!s) {
677 taddstr(WC_WHILE_TYPE(code) == WC_WHILE_UNTIL ?
678 "until " : "while ");
679 tindent++;
680 tpush(code, 0);
681 } else if (!s->pop) {
682 dec_tindent();
683 taddnl(0);
684 taddstr("do");
685 tindent++;
686 taddnl(0);
687 s->pop = 1;
688 } else {
689 dec_tindent();
690 taddnl(0);
691 taddstr("done");
692 stack = 1;
693 }
694 break;
695 case WC_REPEAT:
696 if (!s) {
697 taddstr("repeat ");
698 taddstr(ecgetstr(state, EC_NODUP, NULL));
699 taddnl(0);
700 taddstr("do");
701 tindent++;
702 taddnl(0);
703 tpush(code, 1);
704 } else {
705 dec_tindent();
706 taddnl(0);
707 taddstr("done");
708 stack = 1;
709 }
710 break;
711 case WC_CASE:
712 if (!s) {
713 Wordcode end = state->pc + WC_CASE_SKIP(code);
714 wordcode ialts;
715
716 taddstr("case ");
717 taddstr(ecgetstr(state, EC_NODUP, NULL));
718 taddstr(" in");
719
720 if (state->pc >= end) {
721 if (tnewlins)
722 taddnl(0);
723 else
724 taddchr(' ');
725 taddstr("esac");
726 stack = 1;
727 } else {
728 Wordcode prev_pc;
729 tindent++;
730 if (tnewlins)
731 taddnl(0);
732 else
733 taddchr(' ');
734 taddstr("(");
735 code = *state->pc++;
736 prev_pc = state->pc++;
737 ialts = *prev_pc;
738 while (ialts--) {
739 taddstr(ecgetstr(state, EC_NODUP, NULL));
740 state->pc++;
741 if (ialts)
742 taddstr(" | ");
743 }
744 taddstr(") ");
745 tindent++;
746 n = tpush(code, 0);
747 n->u._case.end = end;
748 n->pop = (prev_pc + WC_CASE_SKIP(code) >= end);
749 }
750 } else if (state->pc < s->u._case.end) {
751 Wordcode prev_pc;
752 wordcode ialts;
753 dec_tindent();
754 switch (WC_CASE_TYPE(code)) {
755 case WC_CASE_OR:
756 taddstr(" ;;");
757 break;
758
759 case WC_CASE_AND:
760 taddstr(" ;&");
761 break;
762
763 default:
764 taddstr(" ;|");
765 break;
766 }
767 if (tnewlins)
768 taddnl(0);
769 else
770 taddchr(' ');
771 taddstr("(");
772 code = *state->pc++;
773 prev_pc = state->pc++;
774 ialts = *prev_pc;
775 while (ialts--) {
776 taddstr(ecgetstr(state, EC_NODUP, NULL));
777 state->pc++;
778 if (ialts)
779 taddstr(" | ");
780 }
781 taddstr(") ");
782 tindent++;
783 s->code = code;
784 s->pop = (prev_pc + WC_CASE_SKIP(code) >=
785 s->u._case.end);
786 } else {
787 dec_tindent();
788 switch (WC_CASE_TYPE(code)) {
789 case WC_CASE_OR:
790 taddstr(" ;;");
791 break;
792
793 case WC_CASE_AND:
794 taddstr(" ;&");
795 break;
796
797 default:
798 taddstr(" ;|");
799 break;
800 }
801 dec_tindent();
802 if (tnewlins)
803 taddnl(0);
804 else
805 taddchr(' ');
806 taddstr("esac");
807 stack = 1;
808 }
809 break;
810 case WC_IF:
811 if (!s) {
812 Wordcode end = state->pc + WC_IF_SKIP(code);
813
814 taddstr("if ");
815 tindent++;
816 state->pc++;
817
818 n = tpush(code, 0);
819 n->u._if.end = end;
820 n->u._if.cond = 1;
821 } else if (s->pop) {
822 stack = 1;
823 } else if (s->u._if.cond) {
824 dec_tindent();
825 taddnl(0);
826 taddstr("then");
827 tindent++;
828 taddnl(0);
829 s->u._if.cond = 0;
830 } else if (state->pc < s->u._if.end) {
831 dec_tindent();
832 taddnl(0);
833 code = *state->pc++;
834 if (WC_IF_TYPE(code) == WC_IF_ELIF) {
835 taddstr("elif ");
836 tindent++;
837 s->u._if.cond = 1;
838 } else {
839 taddstr("else");
840 tindent++;
841 taddnl(0);
842 }
843 } else {
844 s->pop = 1;
845 dec_tindent();
846 taddnl(0);
847 taddstr("fi");
848 stack = 1;
849 }
850 break;
851 case WC_COND:
852 {
853 int ctype;
854
855 if (!s) {
856 taddstr("[[ ");
857 n = tpush(code, 1);
858 n->u._cond.par = 2;
859 } else if (s->u._cond.par == 2) {
860 taddstr(" ]]");
861 stack = 1;
862 break;
863 } else if (s->u._cond.par == 1) {
864 taddstr(" )");
865 stack = 1;
866 break;
867 } else if (WC_COND_TYPE(s->code) == COND_AND) {
868 taddstr(" && ");
869 code = *state->pc++;
870 if (WC_COND_TYPE(code) == COND_OR) {
871 taddstr("( ");
872 n = tpush(code, 1);
873 n->u._cond.par = 1;
874 }
875 } else if (WC_COND_TYPE(s->code) == COND_OR) {
876 taddstr(" || ");
877 code = *state->pc++;
878 if (WC_COND_TYPE(code) == COND_AND) {
879 taddstr("( ");
880 n = tpush(code, 1);
881 n->u._cond.par = 1;
882 }
883 }
884 while (!stack) {
885 switch ((ctype = WC_COND_TYPE(code))) {
886 case COND_NOT:
887 taddstr("! ");
888 code = *state->pc++;
889 if (WC_COND_TYPE(code) <= COND_OR) {
890 taddstr("( ");
891 n = tpush(code, 1);
892 n->u._cond.par = 1;
893 }
894 break;
895 case COND_AND:
896 n = tpush(code, 1);
897 n->u._cond.par = 0;
898 code = *state->pc++;
899 if (WC_COND_TYPE(code) == COND_OR) {
900 taddstr("( ");
901 n = tpush(code, 1);
902 n->u._cond.par = 1;
903 }
904 break;
905 case COND_OR:
906 n = tpush(code, 1);
907 n->u._cond.par = 0;
908 code = *state->pc++;
909 if (WC_COND_TYPE(code) == COND_AND) {
910 taddstr("( ");
911 n = tpush(code, 1);
912 n->u._cond.par = 1;
913 }
914 break;
915 case COND_MOD:
916 taddstr(ecgetstr(state, EC_NODUP, NULL));
917 taddchr(' ');
918 taddlist(state, WC_COND_SKIP(code));
919 stack = 1;
920 break;
921 case COND_MODI:
922 {
923 char *name = ecgetstr(state, EC_NODUP, NULL);
924
925 taddstr(ecgetstr(state, EC_NODUP, NULL));
926 taddchr(' ');
927 taddstr(name);
928 taddchr(' ');
929 taddstr(ecgetstr(state, EC_NODUP, NULL));
930 stack = 1;
931 }
932 break;
933 default:
934 if (ctype < COND_MOD) {
935 /* Binary test: `a = b' etc. */
936 taddstr(ecgetstr(state, EC_NODUP, NULL));
937 taddstr(" ");
938 taddstr(cond_binary_ops[ctype - COND_STREQ]);
939 taddstr(" ");
940 taddstr(ecgetstr(state, EC_NODUP, NULL));
941 if (ctype == COND_STREQ ||
942 ctype == COND_STRDEQ ||
943 ctype == COND_STRNEQ)
944 state->pc++;
945 } else {
946 /* Unary test: `-f foo' etc. */
947 char c2[4];
948
949 c2[0] = '-';
950 c2[1] = ctype;
951 c2[2] = ' ';
952 c2[3] = '\0';
953 taddstr(c2);
954 taddstr(ecgetstr(state, EC_NODUP, NULL));
955 }
956 stack = 1;
957 break;
958 }
959 }
960 }
961 break;
962 case WC_ARITH:
963 taddstr("((");
964 taddstr(ecgetstr(state, EC_NODUP, NULL));
965 taddstr("))");
966 stack = 1;
967 break;
968 case WC_AUTOFN:
969 taddstr("builtin autoload -X");
970 stack = 1;
971 break;
972 case WC_TRY:
973 if (!s) {
974 taddstr("{");
975 tindent++;
976 taddnl(0);
977 n = tpush(code, 0);
978 state->pc++;
979 /* this is the end of the try block alone */
980 n->u._subsh.end = state->pc + WC_CURSH_SKIP(state->pc[-1]);
981 } else if (!s->pop) {
982 state->pc = s->u._subsh.end;
983 dec_tindent();
984 taddnl(0);
985 taddstr("} always {");
986 tindent++;
987 taddnl(0);
988 s->pop = 1;
989 } else {
990 dec_tindent();
991 taddnl(0);
992 taddstr("}");
993 stack = 1;
994 }
995 break;
996 case WC_END:
997 stack = 1;
998 break;
999 default:
1000 DPUTS(1, "unknown word code in gettext2()");
1001 return;
1002 }
1003 }
1004 tdopending();
1005 }
1006
1007 /**/
1008 void
getredirs(LinkList redirs)1009 getredirs(LinkList redirs)
1010 {
1011 LinkNode n;
1012 static char *fstr[] =
1013 {
1014 ">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
1015 "<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
1016 };
1017
1018 queue_signals();
1019
1020 taddchr(' ');
1021 for (n = firstnode(redirs); n; incnode(n)) {
1022 Redir f = (Redir) getdata(n);
1023
1024 switch (f->type) {
1025 case REDIR_WRITE:
1026 case REDIR_WRITENOW:
1027 case REDIR_APP:
1028 case REDIR_APPNOW:
1029 case REDIR_ERRWRITE:
1030 case REDIR_ERRWRITENOW:
1031 case REDIR_ERRAPP:
1032 case REDIR_ERRAPPNOW:
1033 case REDIR_READ:
1034 case REDIR_READWRITE:
1035 case REDIR_HERESTR:
1036 case REDIR_MERGEIN:
1037 case REDIR_MERGEOUT:
1038 case REDIR_INPIPE:
1039 case REDIR_OUTPIPE:
1040 if (f->varid) {
1041 taddchr('{');
1042 taddstr(f->varid);
1043 taddchr('}');
1044 } else if (f->fd1 != (IS_READFD(f->type) ? 0 : 1))
1045 taddchr('0' + f->fd1);
1046 if (f->type == REDIR_HERESTR &&
1047 (f->flags & REDIRF_FROM_HEREDOC)) {
1048 if (tnewlins) {
1049 /*
1050 * Strings that came from here-documents are converted
1051 * to here strings without quotation, so convert them
1052 * back.
1053 */
1054 taddstr(fstr[REDIR_HEREDOC]);
1055 taddstr(f->here_terminator);
1056 taddpending(f->name, f->munged_here_terminator);
1057 } else {
1058 int fnamelen, sav;
1059 taddstr(fstr[REDIR_HERESTR]);
1060 /*
1061 * Just a quick and dirty representation.
1062 * Remove a terminating newline, if any.
1063 */
1064 fnamelen = strlen(f->name);
1065 if (fnamelen > 0 && f->name[fnamelen-1] == '\n') {
1066 sav = 1;
1067 f->name[fnamelen-1] = '\0';
1068 } else
1069 sav = 0;
1070 /*
1071 * Strings that came from here-documents are converted
1072 * to here strings without quotation, so add that
1073 * now. If tokens are present we need to do double quoting.
1074 */
1075 if (!has_token(f->name)) {
1076 taddchr('\'');
1077 taddstr(quotestring(f->name, QT_SINGLE));
1078 taddchr('\'');
1079 } else {
1080 taddchr('"');
1081 taddstr(quotestring(f->name, QT_DOUBLE));
1082 taddchr('"');
1083 }
1084 if (sav)
1085 f->name[fnamelen-1] = '\n';
1086 }
1087 } else {
1088 taddstr(fstr[f->type]);
1089 if (f->type != REDIR_MERGEIN && f->type != REDIR_MERGEOUT)
1090 taddchr(' ');
1091 taddstr(f->name);
1092 }
1093 taddchr(' ');
1094 break;
1095 #ifdef DEBUG
1096 case REDIR_CLOSE:
1097 DPUTS(1, "BUG: CLOSE in getredirs()");
1098 taddchr(f->fd1 + '0');
1099 taddstr(">&- ");
1100 break;
1101 default:
1102 DPUTS(1, "BUG: unknown redirection in getredirs()");
1103 #endif
1104 }
1105 }
1106 tptr--;
1107
1108 unqueue_signals();
1109 }
1110