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