1 /*- 2 * Copyright (c) 1980 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)ex_put.c 7.13 (Berkeley) 04/17/91"; 10 #endif /* not lint */ 11 12 #include "ex.h" 13 #include "ex_tty.h" 14 #include "ex_vis.h" 15 16 /* 17 * Terminal driving and line formatting routines. 18 * Basic motion optimizations are done here as well 19 * as formatting of lines (printing of control characters, 20 * line numbering and the like). 21 */ 22 23 /* 24 * The routines outchar, putchar and pline are actually 25 * variables, and these variables point at the current definitions 26 * of the routines. See the routine setflav. 27 * We sometimes make outchar be routines which catch the characters 28 * to be printed, e.g. if we want to see how long a line is. 29 * During open/visual, outchar and putchar will be set to 30 * routines in the file ex_vput.c (vputchar, vinschar, etc.). 31 */ 32 int (*Outchar)() = termchar; 33 int (*Put_char)() = normchar; 34 int (*Pline)() = normline; 35 36 int (* 37 setlist(t))() 38 bool t; 39 { 40 register int (*P)(); 41 42 listf = t; 43 P = Put_char; 44 Put_char = t ? listchar : normchar; 45 return (P); 46 } 47 48 int (* 49 setnumb(t))() 50 bool t; 51 { 52 register int (*P)(); 53 54 numberf = t; 55 P = Pline; 56 Pline = t ? numbline : normline; 57 return (P); 58 } 59 60 /* 61 * Format c for list mode; leave things in common 62 * with normal print mode to be done by normchar. 63 */ 64 listchar(c) 65 register short c; 66 { 67 68 c &= (TRIM|QUOTE); 69 switch (c) { 70 71 case '\t': 72 case '\b': 73 outchar('^'); 74 c = ctlof(c); 75 break; 76 77 case '\n': 78 break; 79 80 case '\n' | QUOTE: 81 outchar('$'); 82 break; 83 84 default: 85 if (c & QUOTE) 86 break; 87 if (c < ' ' && c != '\n' || c == DELETE) 88 outchar('^'), c = ctlof(c); 89 break; 90 } 91 normchar(c); 92 } 93 94 /* 95 * Format c for printing. Handle funnies of upper case terminals 96 * and crocky hazeltines which don't have ~. 97 */ 98 normchar(c) 99 register short c; 100 { 101 register char *colp; 102 103 c &= (TRIM|QUOTE); 104 if (c == '~' && HZ) { 105 normchar('\\'); 106 c = '^'; 107 } 108 if (c & QUOTE) 109 switch (c) { 110 111 case ' ' | QUOTE: 112 case '\b' | QUOTE: 113 break; 114 115 case QUOTE: 116 return; 117 118 default: 119 c &= TRIM; 120 } 121 else if (c < ' ' && (c != '\b' || !OS) && c != '\n' && c != '\t' || c == DELETE) 122 ex_putchar('^'), c = ctlof(c); 123 else if (UPPERCASE) 124 if (isupper(c)) { 125 outchar('\\'); 126 c = tolower(c); 127 } else { 128 colp = "({)}!|^~'`"; 129 while (*colp++) 130 if (c == *colp++) { 131 outchar('\\'); 132 c = colp[-2]; 133 break; 134 } 135 } 136 outchar(c); 137 } 138 139 /* 140 * Print a line with a number. 141 */ 142 numbline(i) 143 int i; 144 { 145 146 if (shudclob) 147 slobber(' '); 148 ex_printf("%6d ", i); 149 normline(); 150 } 151 152 /* 153 * Normal line output, no numbering. 154 */ 155 normline() 156 { 157 register char *cp; 158 159 if (shudclob) 160 slobber(linebuf[0]); 161 /* pdp-11 doprnt is not reentrant so can't use "printf" here 162 in case we are tracing */ 163 for (cp = linebuf; *cp;) 164 ex_putchar(*cp++); 165 if (!inopen) 166 ex_putchar('\n' | QUOTE); 167 } 168 169 /* 170 * Given c at the beginning of a line, determine whether 171 * the printing of the line will erase or otherwise obliterate 172 * the prompt which was printed before. If it won't, do it now. 173 */ 174 slobber(c) 175 int c; 176 { 177 178 shudclob = 0; 179 switch (c) { 180 181 case '\t': 182 if (Put_char == listchar) 183 return; 184 break; 185 186 default: 187 return; 188 189 case ' ': 190 case 0: 191 break; 192 } 193 if (OS) 194 return; 195 flush(); 196 putch(' '); 197 if (BC) 198 tputs(BC, 0, putch); 199 else 200 putch('\b'); 201 } 202 203 /* 204 * The output buffer is initialized with a useful error 205 * message so we don't have to keep it in data space. 206 */ 207 static char linb[66]; 208 char *linp = linb; 209 210 /* 211 * Phadnl records when we have already had a complete line ending with \n. 212 * If another line starts without a flush, and the terminal suggests it, 213 * we switch into -nl mode so that we can send lineffeeds to avoid 214 * a lot of spacing. 215 */ 216 static bool phadnl; 217 218 /* 219 * Indirect to current definition of putchar. 220 */ 221 ex_putchar(c) 222 int c; 223 { 224 225 (*Put_char)(c); 226 } 227 228 /* 229 * Termchar routine for command mode. 230 * Watch for possible switching to -nl mode. 231 * Otherwise flush into next level of buffering when 232 * small buffer fills or at a newline. 233 */ 234 termchar(c) 235 int c; 236 { 237 238 if (pfast == 0 && phadnl) 239 pstart(); 240 if (c == '\n') 241 phadnl = 1; 242 else if (linp >= &linb[63]) 243 flush1(); 244 *linp++ = c; 245 if (linp >= &linb[63]) { 246 fgoto(); 247 flush1(); 248 } 249 } 250 251 flush() 252 { 253 254 flush1(); 255 flush2(); 256 } 257 258 /* 259 * Flush from small line buffer into output buffer. 260 * Work here is destroying motion into positions, and then 261 * letting fgoto do the optimized motion. 262 */ 263 flush1() 264 { 265 register char *lp; 266 register short c; 267 268 *linp = 0; 269 lp = linb; 270 while (*lp) 271 switch (c = *lp++) { 272 273 case '\r': 274 destline += destcol / COLUMNS; 275 destcol = 0; 276 continue; 277 278 case '\b': 279 if (destcol) 280 destcol--; 281 continue; 282 283 case ' ': 284 destcol++; 285 continue; 286 287 case '\t': 288 destcol += value(TABSTOP) - destcol % value(TABSTOP); 289 continue; 290 291 case '\n': 292 destline += destcol / COLUMNS + 1; 293 if (destcol != 0 && destcol % COLUMNS == 0) 294 destline--; 295 destcol = 0; 296 continue; 297 298 default: 299 fgoto(); 300 for (;;) { 301 if (AM == 0 && outcol == COLUMNS) 302 fgoto(); 303 c &= TRIM; 304 putch(c); 305 if (c == '\b') { 306 outcol--; 307 destcol--; 308 } else if (c >= ' ' && c != DELETE) { 309 outcol++; 310 destcol++; 311 if (XN && outcol % COLUMNS == 0) 312 putch('\r'), putch('\n'); 313 } 314 c = *lp++; 315 if (c <= ' ') 316 break; 317 } 318 --lp; 319 continue; 320 } 321 linp = linb; 322 } 323 324 flush2() 325 { 326 327 fgoto(); 328 flusho(); 329 pstop(); 330 } 331 332 /* 333 * Sync the position of the output cursor. 334 * Most work here is rounding for terminal boundaries getting the 335 * column position implied by wraparound or the lack thereof and 336 * rolling up the screen to get destline on the screen. 337 */ 338 fgoto() 339 { 340 register int l, c; 341 342 if (destcol > COLUMNS - 1) { 343 destline += destcol / COLUMNS; 344 destcol %= COLUMNS; 345 } 346 if (outcol > COLUMNS - 1) { 347 l = (outcol + 1) / COLUMNS; 348 outline += l; 349 outcol %= COLUMNS; 350 if (AM == 0) { 351 while (l > 0) { 352 if (pfast) 353 if (xCR) 354 tputs(xCR, 0, putch); 355 else 356 putch('\r'); 357 if (xNL) 358 tputs(xNL, 0, putch); 359 else 360 putch('\n'); 361 l--; 362 } 363 outcol = 0; 364 } 365 if (outline > LINES - 1) { 366 destline -= outline - (LINES - 1); 367 outline = LINES - 1; 368 } 369 } 370 if (destline > LINES - 1) { 371 l = destline; 372 destline = LINES - 1; 373 if (outline < LINES - 1) { 374 c = destcol; 375 if (pfast == 0 && (!CA || holdcm)) 376 destcol = 0; 377 fgoto(); 378 destcol = c; 379 } 380 while (l > LINES - 1) { 381 /* 382 * The following linefeed (or simulation thereof) 383 * is supposed to scroll up the screen, since we 384 * are on the bottom line. We make the assumption 385 * that linefeed will scroll. If ns is in the 386 * capability list this won't work. We should 387 * probably have an sc capability but sf will 388 * generally take the place if it works. 389 * 390 * Superbee glitch: in the middle of the screen we 391 * have to use esc B (down) because linefeed screws up 392 * in "Efficient Paging" (what a joke) mode (which is 393 * essential in some SB's because CRLF mode puts garbage 394 * in at end of memory), but you must use linefeed to 395 * scroll since down arrow won't go past memory end. 396 * I turned this off after recieving Paul Eggert's 397 * Superbee description which wins better. 398 */ 399 if (xNL /* && !XB */ && pfast) 400 tputs(xNL, 0, putch); 401 else 402 putch('\n'); 403 l--; 404 if (pfast == 0) 405 outcol = 0; 406 } 407 } 408 if (destline < outline && !(CA && !holdcm || UP != NOSTR)) 409 destline = outline; 410 if (CA && !holdcm) 411 if (plod(costCM) > 0) 412 plod(0); 413 else 414 tputs(tgoto(CM, destcol, destline), 0, putch); 415 else 416 plod(0); 417 outline = destline; 418 outcol = destcol; 419 } 420 421 /* 422 * Tab to column col by flushing and then setting destcol. 423 * Used by "set all". 424 */ 425 tab(col) 426 int col; 427 { 428 429 flush1(); 430 destcol = col; 431 } 432 433 /* 434 * Move (slowly) to destination. 435 * Hard thing here is using home cursor on really deficient terminals. 436 * Otherwise just use cursor motions, hacking use of tabs and overtabbing 437 * and backspace. 438 */ 439 440 static int plodcnt, plodflg; 441 442 plodput(c) 443 { 444 445 if (plodflg) 446 plodcnt--; 447 else 448 putch(c); 449 } 450 451 plod(cnt) 452 { 453 register int i, j, k; 454 register int soutcol, soutline; 455 456 plodcnt = plodflg = cnt; 457 soutcol = outcol; 458 soutline = outline; 459 /* 460 * Consider homing and moving down/right from there, vs moving 461 * directly with local motions to the right spot. 462 */ 463 if (HO) { 464 /* 465 * i is the cost to home and tab/space to the right to 466 * get to the proper column. This assumes ND space costs 467 * 1 char. So i+destcol is cost of motion with home. 468 */ 469 if (GT) 470 i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS)); 471 else 472 i = destcol; 473 /* 474 * j is cost to move locally without homing 475 */ 476 if (destcol >= outcol) { /* if motion is to the right */ 477 j = destcol / value(HARDTABS) - outcol / value(HARDTABS); 478 if (GT && j) 479 j += destcol % value(HARDTABS); 480 else 481 j = destcol - outcol; 482 } else 483 /* leftward motion only works if we can backspace. */ 484 if (outcol - destcol <= i && (BS || BC)) 485 i = j = outcol - destcol; /* cheaper to backspace */ 486 else 487 j = i + 1; /* impossibly expensive */ 488 489 /* k is the absolute value of vertical distance */ 490 k = outline - destline; 491 if (k < 0) 492 k = -k; 493 j += k; 494 495 /* 496 * Decision. We may not have a choice if no UP. 497 */ 498 if (i + destline < j || (!UP && destline < outline)) { 499 /* 500 * Cheaper to home. Do it now and pretend it's a 501 * regular local motion. 502 */ 503 tputs(HO, 0, plodput); 504 outcol = outline = 0; 505 } else if (LL) { 506 /* 507 * Quickly consider homing down and moving from there. 508 * Assume cost of LL is 2. 509 */ 510 k = (LINES - 1) - destline; 511 if (i + k + 2 < j && (k<=0 || UP)) { 512 tputs(LL, 0, plodput); 513 outcol = 0; 514 outline = LINES - 1; 515 } 516 } 517 } else 518 /* 519 * No home and no up means it's impossible, so we return an 520 * incredibly big number to make cursor motion win out. 521 */ 522 if (!UP && destline < outline) 523 return (500); 524 if (GT) 525 i = destcol % value(HARDTABS) 526 + destcol / value(HARDTABS); 527 else 528 i = destcol; 529 /* 530 if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { 531 j *= (k = strlen(BT)); 532 if ((k += (destcol&7)) > 4) 533 j += 8 - (destcol&7); 534 else 535 j += k; 536 } else 537 */ 538 j = outcol - destcol; 539 /* 540 * If we will later need a \n which will turn into a \r\n by 541 * the system or the terminal, then don't bother to try to \r. 542 */ 543 if ((NONL || !pfast) && outline < destline) 544 goto dontcr; 545 /* 546 * If the terminal will do a \r\n and there isn't room for it, 547 * then we can't afford a \r. 548 */ 549 if (NC && outline >= destline) 550 goto dontcr; 551 /* 552 * If it will be cheaper, or if we can't back up, then send 553 * a return preliminarily. 554 */ 555 if (j > i + 1 || outcol > destcol && !BS && !BC) { 556 /* 557 * BUG: this doesn't take the (possibly long) length 558 * of xCR into account. 559 */ 560 if (xCR) 561 tputs(xCR, 0, plodput); 562 else 563 plodput('\r'); 564 if (NC) { 565 if (xNL) 566 tputs(xNL, 0, plodput); 567 else 568 plodput('\n'); 569 outline++; 570 } 571 outcol = 0; 572 } 573 dontcr: 574 /* Move down, if necessary, until we are at the desired line */ 575 while (outline < destline) { 576 j = destline - outline; 577 if (j > costDP && DOWN_PARM) { 578 /* Win big on Tek 4025 */ 579 tputs(tgoto(DOWN_PARM, 0, j), j, plodput); 580 outline += j; 581 } 582 else { 583 outline++; 584 if (xNL && pfast) 585 tputs(xNL, 0, plodput); 586 else 587 plodput('\n'); 588 } 589 if (plodcnt < 0) 590 goto out; 591 if (NONL || pfast == 0) 592 outcol = 0; 593 } 594 if (BT) 595 k = strlen(BT); /* should probably be cost(BT) and moved out */ 596 /* Move left, if necessary, to desired column */ 597 while (outcol > destcol) { 598 if (plodcnt < 0) 599 goto out; 600 if (BT && !insmode && outcol - destcol > 4+k) { 601 tputs(BT, 0, plodput); 602 outcol--; 603 outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */ 604 continue; 605 } 606 j = outcol - destcol; 607 if (j > costLP && LEFT_PARM) { 608 tputs(tgoto(LEFT_PARM, 0, j), j, plodput); 609 outcol -= j; 610 } 611 else { 612 outcol--; 613 if (BC) 614 tputs(BC, 0, plodput); 615 else 616 plodput('\b'); 617 } 618 } 619 /* Move up, if necessary, to desired row */ 620 while (outline > destline) { 621 j = outline - destline; 622 if (UP_PARM && j > 1) { 623 /* Win big on Tek 4025 */ 624 tputs(tgoto(UP_PARM, 0, j), j, plodput); 625 outline -= j; 626 } 627 else { 628 outline--; 629 tputs(UP, 0, plodput); 630 } 631 if (plodcnt < 0) 632 goto out; 633 } 634 /* 635 * Now move to the right, if necessary. We first tab to 636 * as close as we can get. 637 */ 638 if (GT && !insmode && destcol - outcol > 1) { 639 /* tab to right as far as possible without passing col */ 640 for (;;) { 641 i = tabcol(outcol, value(HARDTABS)); 642 if (i > destcol) 643 break; 644 if (TA) 645 tputs(TA, 0, plodput); 646 else 647 plodput('\t'); 648 outcol = i; 649 } 650 /* consider another tab and then some backspaces */ 651 if (destcol - outcol > 4 && i < COLUMNS && (BC || BS)) { 652 if (TA) 653 tputs(TA, 0, plodput); 654 else 655 plodput('\t'); 656 outcol = i; 657 /* 658 * Back up. Don't worry about LEFT_PARM because 659 * it's never more than 4 spaces anyway. 660 */ 661 while (outcol > destcol) { 662 outcol--; 663 if (BC) 664 tputs(BC, 0, plodput); 665 else 666 plodput('\b'); 667 } 668 } 669 } 670 /* 671 * We've tabbed as much as possible. If we still need to go 672 * further (not exact or can't tab) space over. This is a 673 * very common case when moving to the right with space. 674 */ 675 while (outcol < destcol) { 676 j = destcol - outcol; 677 if (j > costRP && RIGHT_PARM) { 678 /* 679 * This probably happens rarely, if at all. 680 * It seems mainly useful for ANSI terminals 681 * with no hardware tabs, and I don't know 682 * of any such terminal at the moment. 683 */ 684 tputs(tgoto(RIGHT_PARM, 0, j), j, plodput); 685 outcol += j; 686 } 687 else { 688 /* 689 * move one char to the right. We don't use ND space 690 * because it's better to just print the char we are 691 * moving over. There are various exceptions, however. 692 * If !inopen, vtube contains garbage. If the char is 693 * a null or a tab we want to print a space. Other 694 * random chars we use space for instead, too. 695 */ 696 if (!inopen || vtube[outline]==NULL || 697 (i=vtube[outline][outcol]) < ' ') 698 i = ' '; 699 if(i & QUOTE) /* mjm: no sign extension on 3B */ 700 i = ' '; 701 if (insmode && ND) 702 tputs(ND, 0, plodput); 703 else 704 plodput(i); 705 outcol++; 706 } 707 if (plodcnt < 0) 708 goto out; 709 } 710 out: 711 if (plodflg) { 712 outcol = soutcol; 713 outline = soutline; 714 } 715 return(plodcnt); 716 } 717 718 /* 719 * An input line arrived. 720 * Calculate new (approximate) screen line position. 721 * Approximate because kill character echoes newline with 722 * no feedback and also because of long input lines. 723 */ 724 noteinp() 725 { 726 727 outline++; 728 if (outline > LINES - 1) 729 outline = LINES - 1; 730 destline = outline; 731 destcol = outcol = 0; 732 } 733 734 /* 735 * Something weird just happened and we 736 * lost track of whats happening out there. 737 * Since we cant, in general, read where we are 738 * we just reset to some known state. 739 * On cursor addressible terminals setting to unknown 740 * will force a cursor address soon. 741 */ 742 termreset() 743 { 744 745 endim(); 746 if (TI) /* otherwise it flushes anyway, and 'set tty=dumb' vomits */ 747 putpad(TI); /*adb change -- emit terminal initial sequence */ 748 destcol = 0; 749 destline = LINES - 1; 750 if (CA) { 751 outcol = UKCOL; 752 outline = UKCOL; 753 } else { 754 outcol = destcol; 755 outline = destline; 756 } 757 } 758 759 /* 760 * Low level buffering, with the ability to drain 761 * buffered output without printing it. 762 */ 763 char *obp = obuf; 764 765 draino() 766 { 767 768 obp = obuf; 769 } 770 771 flusho() 772 { 773 774 if (obp != obuf) { 775 #ifndef vms 776 write(1, obuf, obp - obuf); 777 #else 778 vms_write(1, obuf, obp - obuf); 779 #endif 780 obp = obuf; 781 } 782 } 783 784 putnl() 785 { 786 787 ex_putchar('\n'); 788 } 789 790 ex_putS(cp) 791 char *cp; 792 { 793 794 if (cp == NULL) 795 return; 796 while (*cp) 797 putch(*cp++); 798 } 799 800 801 putch(c) 802 int c; 803 { 804 805 #ifdef OLD3BTTY /* mjm */ 806 if(c == '\n') /* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */ 807 putch('\r'); /* mjm: vi does "stty -icanon" => -onlcr !! */ 808 #endif 809 *obp++ = c & 0177; 810 if (obp >= &obuf[sizeof obuf]) 811 flusho(); 812 } 813 814 /* 815 * Miscellaneous routines related to output. 816 */ 817 818 /* 819 * Put with padding 820 */ 821 putpad(cp) 822 char *cp; 823 { 824 825 flush(); 826 tputs(cp, 0, putch); 827 } 828 829 /* 830 * Set output through normal command mode routine. 831 */ 832 setoutt() 833 { 834 835 Outchar = termchar; 836 } 837 838 /* 839 * Printf (temporarily) in list mode. 840 */ 841 /*VARARGS1*/ 842 lprintf(cp, dp) 843 char *cp, *dp; 844 { 845 register int (*P)(); 846 847 P = setlist(1); 848 ex_printf(cp, dp); 849 Put_char = P; 850 } 851 852 /* 853 * Newline + flush. 854 */ 855 putNFL() 856 { 857 858 putnl(); 859 flush(); 860 } 861 862 /* 863 * Try to start -nl mode. 864 */ 865 pstart() 866 { 867 868 if (NONL) 869 return; 870 if (!value(OPTIMIZE)) 871 return; 872 if (ruptible == 0 || pfast) 873 return; 874 fgoto(); 875 flusho(); 876 pfast = 1; 877 normtty++; 878 #ifndef USG3TTY 879 tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD); 880 #else 881 tty = normf; 882 tty.c_oflag &= ~(ONLCR|TAB3); 883 tty.c_lflag &= ~ECHO; 884 #endif 885 ex_sTTY(1); 886 } 887 888 /* 889 * Stop -nl mode. 890 */ 891 pstop() 892 { 893 894 if (inopen) 895 return; 896 phadnl = 0; 897 linp = linb; 898 draino(); 899 normal(normf); 900 pfast &= ~1; 901 } 902 903 /* 904 * Prep tty for open mode. 905 */ 906 ttymode 907 ostart() 908 { 909 ttymode f; 910 911 if (!intty) 912 error("Open and visual must be used interactively"); 913 ex_gTTY(1); 914 normtty++; 915 #ifndef USG3TTY 916 f = tty.sg_flags; 917 tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) | 918 # ifdef CBREAK 919 CBREAK; 920 # else 921 RAW; 922 # endif 923 # ifdef TIOCGETC 924 ttcharoff(); 925 # endif 926 #else 927 f = tty; 928 tty = normf; 929 tty.c_iflag &= ~ICRNL; 930 tty.c_lflag &= ~(ECHO|ICANON); 931 tty.c_oflag &= ~(TAB3|ONLCR); 932 tty.c_cc[VMIN] = 1; 933 tty.c_cc[VTIME] = 1; 934 ttcharoff(); 935 #endif 936 ex_sTTY(1); 937 tostart(); 938 pfast |= 2; 939 return (f); 940 } 941 942 /* actions associated with putting the terminal in open mode */ 943 tostart() 944 { 945 putpad(VS); 946 putpad(KS); 947 if (!value(MESG)) { 948 if (ttynbuf[0] == 0) { 949 register char *tn; 950 if ((tn=ttyname(2)) == NULL && 951 (tn=ttyname(1)) == NULL && 952 (tn=ttyname(0)) == NULL) 953 ttynbuf[0] = 1; 954 else 955 strcpy(ttynbuf, tn); 956 } 957 if (ttynbuf[0] != 1) { 958 struct stat sbuf; 959 stat(ttynbuf, &sbuf); 960 ttymesg = sbuf.st_mode & 0777; 961 chmod(ttynbuf, 962 #ifdef UCBV7 963 /* 964 * This applies to the UCB V7 Pdp-11 system with the 965 * -u write option only. 966 */ 967 0611 /* 11 = urgent only allowed */ 968 #else 969 0600 970 #endif 971 ); 972 } 973 } 974 } 975 976 /* 977 * Turn off start/stop chars if they aren't the default ^S/^Q. 978 * This is so idiots who make esc their start/stop don't lose. 979 * We always turn off quit since datamedias send ^\ for their 980 * right arrow key. 981 */ 982 #ifdef TIOCGETC 983 ttcharoff() 984 { 985 nttyc.t_quitc = '\377'; 986 if (nttyc.t_startc != CTRL('q')) 987 nttyc.t_startc = '\377'; 988 if (nttyc.t_stopc != CTRL('s')) 989 nttyc.t_stopc = '\377'; 990 # ifdef TIOCLGET 991 nlttyc.t_suspc = '\377'; /* ^Z */ 992 nlttyc.t_dsuspc = '\377'; /* ^Y */ 993 nlttyc.t_flushc = '\377'; /* ^O */ 994 nlttyc.t_lnextc = '\377'; /* ^V */ 995 # endif 996 } 997 #endif 998 999 #ifdef USG3TTY 1000 ttcharoff() 1001 { 1002 tty.c_cc[VQUIT] = '\377'; 1003 # ifdef VSTART 1004 /* 1005 * The following is sample code if USG ever lets people change 1006 * their start/stop chars. As long as they can't we can't get 1007 * into trouble so we just leave them alone. 1008 */ 1009 if (tty.c_cc[VSTART] != CTRL('q')) 1010 tty.c_cc[VSTART] = '\377'; 1011 if (tty.c_cc[VSTOP] != CTRL('s')) 1012 tty.c_cc[VSTOP] = '\377'; 1013 # endif 1014 } 1015 #endif 1016 1017 /* 1018 * Stop open, restoring tty modes. 1019 */ 1020 ostop(f) 1021 ttymode f; 1022 { 1023 1024 #ifndef USG3TTY 1025 pfast = (f & CRMOD) == 0; 1026 #else 1027 pfast = (f.c_oflag & ONLCR) == 0; 1028 #endif 1029 termreset(), fgoto(), flusho(); 1030 normal(f); 1031 tostop(); 1032 } 1033 1034 /* Actions associated with putting the terminal in the right mode. */ 1035 tostop() 1036 { 1037 putpad(VE); 1038 putpad(KE); 1039 if (!value(MESG) && ttynbuf[0]>1) 1040 chmod(ttynbuf, ttymesg); 1041 } 1042 1043 #ifndef CBREAK 1044 /* 1045 * Into cooked mode for interruptibility. 1046 */ 1047 vcook() 1048 { 1049 1050 tty.sg_flags &= ~RAW; 1051 ex_sTTY(1); 1052 } 1053 1054 /* 1055 * Back into raw mode. 1056 */ 1057 vraw() 1058 { 1059 1060 tty.sg_flags |= RAW; 1061 ex_sTTY(1); 1062 } 1063 #endif 1064 1065 /* 1066 * Restore flags to normal state f. 1067 */ 1068 normal(f) 1069 ttymode f; 1070 { 1071 1072 if (normtty > 0) { 1073 ignore(setty(f)); 1074 normtty--; 1075 } 1076 } 1077 1078 /* 1079 * Straight set of flags to state f. 1080 */ 1081 ttymode 1082 setty(f) 1083 ttymode f; 1084 { 1085 #ifndef USG3TTY 1086 register int ot = tty.sg_flags; 1087 #else 1088 ttymode ot; 1089 ot = tty; 1090 #endif 1091 1092 #ifndef USG3TTY 1093 # ifdef TIOCGETC 1094 if (f == normf) { 1095 nttyc = ottyc; 1096 # ifdef TIOCLGET 1097 nlttyc = olttyc; 1098 # endif 1099 } else 1100 ttcharoff(); 1101 # endif 1102 tty.sg_flags = f; 1103 #else 1104 if (tty.c_lflag & ICANON) 1105 ttcharoff(); 1106 tty = f; 1107 #endif 1108 ex_sTTY(1); 1109 return (ot); 1110 } 1111 1112 ex_gTTY(i) 1113 int i; 1114 { 1115 1116 #ifndef USG3TTY 1117 ignore(ioctl(i, TIOCGETP, &tty)); 1118 # ifdef TIOCGETC 1119 ioctl(i, TIOCGETC, (char *) &ottyc); 1120 nttyc = ottyc; 1121 # endif 1122 # ifdef TIOCGLTC 1123 ioctl(i, TIOCGLTC, (char *) &olttyc); 1124 nlttyc = olttyc; 1125 # endif 1126 #else 1127 ioctl(i, TCGETA, (char *) &tty); 1128 #endif 1129 } 1130 1131 /* 1132 * ex_sTTY: set the tty modes on file descriptor i to be what's 1133 * currently in global "tty". (Also use nttyc if needed.) 1134 */ 1135 ex_sTTY(i) 1136 int i; 1137 { 1138 1139 #ifndef USG3TTY 1140 # ifdef USG 1141 /* Bug in USG tty driver, put out a DEL as a patch. */ 1142 if (tty.sg_ospeed >= B1200) 1143 write(1, "\377", 1); 1144 # endif 1145 1146 # ifdef TIOCSETN 1147 /* Don't flush typeahead if we don't have to */ 1148 ioctl(i, TIOCSETN, (char *) &tty); 1149 # else 1150 /* We have to. Too bad. */ 1151 stty(i, &tty); 1152 # endif 1153 1154 # ifdef TIOCGETC 1155 /* Update the other random chars while we're at it. */ 1156 ioctl(i, TIOCSETC, (char *) &nttyc); 1157 # endif 1158 # ifdef TIOCSLTC 1159 ioctl(i, TIOCSLTC, (char *) &nlttyc); 1160 # endif 1161 1162 #else 1163 /* USG 3 very simple: just set everything */ 1164 ioctl(i, TCSETAW, (char *) &tty); 1165 #endif 1166 } 1167 1168 /* 1169 * Print newline, or blank if in open/visual 1170 */ 1171 noonl() 1172 { 1173 1174 ex_putchar(Outchar != termchar ? ' ' : '\n'); 1175 } 1176