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