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