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