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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 30 /* 31 * Copyright (c) 1981 Regents of the University of California 32 */ 33 34 #include "ex.h" 35 #include "ex_tty.h" 36 #include "ex_vis.h" 37 #include <regexpr.h> 38 #ifndef PRESUNEUC 39 #include <wctype.h> 40 /* Undef putchar/getchar if they're defined. */ 41 #ifdef putchar 42 #undef putchar 43 #endif 44 #ifdef getchar 45 #undef getchar 46 #endif 47 #endif /* PRESUNEUC */ 48 49 #ifdef PRESUNEUC 50 #define blank() isspace(wcursor[0]) 51 #endif /* PRESUNEUC */ 52 #define forbid(a) if (a) goto errlab; 53 54 unsigned char vscandir[2] = { '/', 0 }; 55 56 static int get_addr(); 57 58 /* 59 * Decode an operator/operand type command. 60 * Eventually we switch to an operator subroutine in ex_vops.c. 61 * The work here is setting up a function variable to point 62 * to the routine we want, and manipulation of the variables 63 * wcursor and wdot, which mark the other end of the affected 64 * area. If wdot is zero, then the current line is the other end, 65 * and if wcursor is zero, then the first non-blank location of the 66 * other line is implied. 67 */ 68 void 69 operate(int c, int cnt) 70 { 71 wchar_t i; 72 int (*moveop)(), (*deleteop)(); 73 int (*opf)(); 74 bool subop = 0; 75 unsigned char *oglobp, *ocurs; 76 line *addr; 77 line *odot; 78 int oc; 79 static unsigned char lastFKND; 80 static wchar_t lastFCHR; 81 short d; 82 /* #ifdef PTR_ADDRESSES */ 83 int mouse_x; 84 int mouse_y; 85 int oline; 86 /* #endif PTR_ADDRESSES */ 87 88 moveop = vmove, deleteop = (int (*)())vdelete; 89 wcursor = cursor; 90 wdot = NOLINE; 91 notecnt = 0; 92 dir = 1; 93 switch (c) { 94 95 /* 96 * d delete operator. 97 */ 98 case 'd': 99 moveop = (int (*)())vdelete; 100 deleteop = beep; 101 break; 102 103 /* 104 * s substitute characters, like c\040, i.e. change space. 105 */ 106 case 's': 107 ungetkey(' '); 108 subop++; 109 /* FALLTHROUGH */ 110 111 /* 112 * c Change operator. 113 */ 114 case 'c': 115 if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S') 116 subop++; 117 moveop = (int (*)())vchange; 118 deleteop = beep; 119 break; 120 121 /* 122 * ! Filter through a UNIX command. 123 */ 124 case '!': 125 moveop = vfilter; 126 deleteop = beep; 127 break; 128 129 /* 130 * y Yank operator. Place specified text so that it 131 * can be put back with p/P. Also yanks to named buffers. 132 */ 133 case 'y': 134 moveop = vyankit; 135 deleteop = beep; 136 break; 137 138 /* 139 * = Reformat operator (for LISP). 140 */ 141 case '=': 142 forbid(!value(vi_LISP)); 143 /* FALLTHROUGH */ 144 145 /* 146 * > Right shift operator. 147 * < Left shift operator. 148 */ 149 case '<': 150 case '>': 151 moveop = vshftop; 152 deleteop = beep; 153 break; 154 155 /* 156 * r Replace character under cursor with single following 157 * character. 158 */ 159 case 'r': 160 vmacchng(1); 161 vrep(cnt); 162 return; 163 164 default: 165 goto nocount; 166 } 167 vmacchng(1); 168 /* 169 * Had an operator, so accept another count. 170 * Multiply counts together. 171 */ 172 if (isdigit(peekkey()) && peekkey() != '0') { 173 cnt *= vgetcnt(); 174 Xcnt = cnt; 175 forbid(cnt <= 0); 176 } 177 178 /* 179 * Get next character, mapping it and saving as 180 * part of command for repeat. 181 */ 182 c = map(getesc(), arrows, 0); 183 if (c == 0) 184 return; 185 if (!subop) 186 *lastcp++ = c; 187 nocount: 188 opf = moveop; 189 switch (c) { 190 191 /* #ifdef PTR_ADDRESSES */ 192 /* 193 * ^X^_ Netty Mouse positioning hack 194 * ^X^] 195 */ 196 case CTRL('X'): 197 /* 198 * Read in mouse stuff 199 */ 200 c = getkey(); /* ^_ or ^] */ 201 if ((c != CTRL('_')) && (c != (CTRL(']')))) 202 break; 203 getkey(); /* mouse button */ 204 mouse_x = get_addr() + 1; 205 mouse_y = get_addr() + 1; 206 if (mouse_y < WTOP) 207 break; 208 if (Pline == numbline) 209 mouse_x -= 8; 210 if (mouse_x < 0) 211 mouse_x = 0; 212 if (mouse_x > WCOLS) 213 break; 214 /* 215 * Find the line on the screen 216 */ 217 for (i = 0; i <= WECHO; i++) { 218 if (vlinfo[i].vliny >= mouse_y) 219 break; 220 } 221 if (i > WECHO) 222 break; 223 /* 224 * Look for lines longer than one line - note odd case at zero 225 */ 226 if (i) { 227 if (vlinfo[i - 1].vdepth > 1) { 228 mouse_x += WCOLS * (mouse_y - 229 (vlinfo[i].vliny - 230 (vlinfo[i - 1].vdepth - 1))); 231 } 232 } 233 else 234 { 235 mouse_x += WCOLS * (mouse_y - 1); 236 } 237 /* 238 * Set the line 239 */ 240 vsave(); 241 ocurs = cursor; 242 odot = dot; 243 oline = vcline; 244 operate('H', i); 245 /* 246 * Set the column 247 */ 248 getDOT(); 249 if (Pline == numbline) 250 mouse_x += 8; 251 vmovcol = mouse_x; 252 vmoving = 1; 253 wcursor = vfindcol(mouse_x); 254 /* 255 * Reset everything so that stuff like delete and change work 256 */ 257 wdot = (odot - oline) + i - 1; 258 cursor = ocurs; 259 vcline = oline; 260 dot = odot; 261 getDOT(); 262 break; 263 /* #endif PTR_ADDRESSES */ 264 265 /* 266 * b Back up a word. 267 * B Back up a word, liberal definition. 268 */ 269 case 'b': 270 case 'B': 271 dir = -1; 272 /* FALLTHROUGH */ 273 274 /* 275 * w Forward a word. 276 * W Forward a word, liberal definition. 277 */ 278 case 'W': 279 case 'w': 280 wdkind = c & ' '; 281 forbid(lfind(2, cnt, opf, (line *)0) < 0); 282 vmoving = 0; 283 break; 284 285 /* 286 * E to end of following blank/nonblank word 287 */ 288 case 'E': 289 wdkind = 0; 290 goto ein; 291 292 /* 293 * e To end of following word. 294 */ 295 case 'e': 296 wdkind = 1; 297 ein: 298 forbid(lfind(3, cnt - 1, opf, (line *)0) < 0); 299 vmoving = 0; 300 break; 301 302 /* 303 * ( Back an s-expression. 304 */ 305 case '(': 306 dir = -1; 307 /* FALLTHROUGH */ 308 309 /* 310 * ) Forward an s-expression. 311 */ 312 case ')': 313 forbid(lfind(0, cnt, opf, (line *) 0) < 0); 314 markDOT(); 315 break; 316 317 /* 318 * { Back an s-expression, but don't stop on atoms. 319 * In text mode, a paragraph. For C, a balanced set 320 * of {}'s. 321 */ 322 case '{': 323 dir = -1; 324 /* FALLTHROUGH */ 325 326 /* 327 * } Forward an s-expression, but don't stop on atoms. 328 * In text mode, back paragraph. For C, back a balanced 329 * set of {}'s. 330 */ 331 case '}': 332 forbid(lfind(1, cnt, opf, (line *) 0) < 0); 333 markDOT(); 334 break; 335 336 /* 337 * % To matching () or {}. If not at ( or { scan for 338 * first such after cursor on this line. 339 */ 340 case '%': 341 vsave(); 342 ocurs = cursor; 343 odot = wdot = dot; 344 oglobp = globp; 345 CATCH 346 i = lmatchp((line *) 0); 347 ONERR 348 globp = oglobp; 349 dot = wdot = odot; 350 cursor = ocurs; 351 splitw = 0; 352 vclean(); 353 vjumpto(dot, ocurs, 0); 354 return; 355 ENDCATCH 356 #ifdef TRACE 357 if (trace) 358 fprintf(trace, "after lmatchp in %, dot=%d, wdot=%d, " 359 "dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); 360 #endif 361 getDOT(); 362 forbid(!i); 363 if (opf != vmove) 364 if (dir > 0) 365 wcursor++; 366 else 367 cursor++; 368 else 369 markDOT(); 370 vmoving = 0; 371 break; 372 373 /* 374 * [ Back to beginning of defun, i.e. an ( in column 1. 375 * For text, back to a section macro. 376 * For C, back to a { in column 1 (~~ beg of function.) 377 */ 378 case '[': 379 dir = -1; 380 /* FALLTHROUGH */ 381 382 /* 383 * ] Forward to next defun, i.e. a ( in column 1. 384 * For text, forward section. 385 * For C, forward to a } in column 1 (if delete or such) 386 * or if a move to a { in column 1. 387 */ 388 case ']': 389 if (!vglobp) 390 forbid(getkey() != c); 391 #ifndef XPG4 392 forbid(Xhadcnt); 393 #endif 394 vsave(); 395 #ifdef XPG4 396 if (cnt > 1) { 397 while (cnt-- > 1) { 398 i = lbrack(c, opf); 399 getDOT(); 400 forbid(!i); 401 markDOT(); 402 if (ospeed > B300) 403 hold |= HOLDWIG; 404 (*opf)(c); 405 } 406 } 407 #endif /* XPG4 */ 408 i = lbrack(c, opf); 409 getDOT(); 410 forbid(!i); 411 markDOT(); 412 if (ospeed > B300) 413 hold |= HOLDWIG; 414 break; 415 416 /* 417 * , Invert last find with f F t or T, like inverse 418 * of ;. 419 */ 420 case ',': 421 forbid(lastFKND == 0); 422 c = isupper(lastFKND) ? tolower(lastFKND) : toupper(lastFKND); 423 i = lastFCHR; 424 if (vglobp == 0) 425 vglobp = (unsigned char *)""; 426 subop++; 427 goto nocount; 428 429 /* 430 * 0 To beginning of real line. 431 */ 432 case '0': 433 wcursor = linebuf; 434 vmoving = 0; 435 break; 436 437 /* 438 * ; Repeat last find with f F t or T. 439 */ 440 case ';': 441 forbid(lastFKND == 0); 442 c = lastFKND; 443 i = lastFCHR; 444 subop++; 445 goto nocount; 446 447 /* 448 * F Find single character before cursor in current line. 449 * T Like F, but stops before character. 450 */ 451 case 'F': /* inverted find */ 452 case 'T': 453 dir = -1; 454 /* FALLTHROUGH */ 455 456 /* 457 * f Find single character following cursor in current line. 458 * t Like f, but stope before character. 459 */ 460 case 'f': /* find */ 461 case 't': 462 if (!subop) { 463 int length; 464 wchar_t wchar; 465 length = _mbftowc(lastcp, &wchar, getesc, &Peekkey); 466 if (length <= 0 || wchar == 0) { 467 (void) beep(); 468 return; 469 } 470 i = wchar; 471 lastcp += length; 472 } 473 if (vglobp == 0) 474 lastFKND = c, lastFCHR = i; 475 for (; cnt > 0; cnt--) 476 forbid(find(i) == 0); 477 vmoving = 0; 478 switch (c) { 479 480 case 'T': 481 wcursor = nextchr(wcursor); 482 break; 483 484 case 't': 485 wcursor = lastchr(linebuf, wcursor); 486 /* FALLTHROUGH */ 487 case 'f': 488 fixup: 489 if (moveop != vmove) 490 wcursor = nextchr(wcursor); 491 break; 492 } 493 break; 494 495 /* 496 * | Find specified print column in current line. 497 */ 498 case '|': 499 if (Pline == numbline) 500 cnt += 8; 501 vmovcol = cnt; 502 vmoving = 1; 503 wcursor = vfindcol(cnt); 504 break; 505 506 /* 507 * ^ To beginning of non-white space on line. 508 */ 509 case '^': 510 wcursor = vskipwh(linebuf); 511 vmoving = 0; 512 break; 513 514 /* 515 * $ To end of line. 516 */ 517 case '$': 518 if (opf == vmove) { 519 vmoving = 1; 520 vmovcol = 20000; 521 } else 522 vmoving = 0; 523 if (cnt > 1) { 524 if (opf == vmove) { 525 wcursor = 0; 526 cnt--; 527 } else 528 wcursor = linebuf; 529 /* This is wrong at EOF */ 530 wdot = dot + cnt; 531 break; 532 } 533 if (linebuf[0]) { 534 wcursor = strend(linebuf); 535 wcursor = lastchr(linebuf, wcursor); 536 goto fixup; 537 } 538 wcursor = linebuf; 539 break; 540 541 /* 542 * h Back a character. 543 * ^H Back a character. 544 */ 545 case 'h': 546 case CTRL('h'): 547 dir = -1; 548 /* FALLTHROUGH */ 549 550 /* 551 * space Forward a character. 552 */ 553 case 'l': 554 case ' ': 555 forbid(margin() || opf == vmove && edge()); 556 while (cnt > 0 && !margin()) { 557 if (dir == 1) 558 wcursor = nextchr(wcursor); 559 else 560 wcursor = lastchr(linebuf, wcursor); 561 cnt--; 562 } 563 if (margin() && opf == vmove || wcursor < linebuf) { 564 if (dir == 1) 565 wcursor = lastchr(linebuf, wcursor); 566 else 567 wcursor = linebuf; 568 } 569 vmoving = 0; 570 break; 571 572 /* 573 * D Delete to end of line, short for d$. 574 */ 575 case 'D': 576 cnt = INF; 577 goto deleteit; 578 579 /* 580 * X Delete character before cursor. 581 */ 582 case 'X': 583 dir = -1; 584 /* FALLTHROUGH */ 585 deleteit: 586 /* 587 * x Delete character at cursor, leaving cursor where it is. 588 */ 589 case 'x': 590 if (margin()) 591 goto errlab; 592 vmacchng(1); 593 while (cnt > 0 && !margin()) { 594 if (dir == 1) 595 wcursor = nextchr(wcursor); 596 else 597 wcursor = lastchr(linebuf, wcursor); 598 cnt--; 599 } 600 opf = deleteop; 601 vmoving = 0; 602 break; 603 604 default: 605 /* 606 * Stuttered operators are equivalent to the operator on 607 * a line, thus turn dd into d_. 608 */ 609 if (opf == vmove || c != workcmd[0]) { 610 errlab: 611 (void) beep(); 612 vmacp = 0; 613 return; 614 } 615 /* FALLTHROUGH */ 616 617 /* 618 * _ Target for a line or group of lines. 619 * Stuttering is more convenient; this is mostly 620 * for aesthetics. 621 */ 622 case '_': 623 wdot = dot + cnt - 1; 624 vmoving = 0; 625 wcursor = 0; 626 break; 627 628 /* 629 * H To first, home line on screen. 630 * Count is for count'th line rather than first. 631 */ 632 case 'H': 633 wdot = (dot - vcline) + cnt - 1; 634 if (opf == vmove) 635 markit(wdot); 636 vmoving = 0; 637 wcursor = 0; 638 break; 639 640 /* 641 * - Backwards lines, to first non-white character. 642 */ 643 case '-': 644 wdot = dot - cnt; 645 vmoving = 0; 646 wcursor = 0; 647 break; 648 649 /* 650 * ^P To previous line same column. Ridiculous on the 651 * console of the VAX since it puts console in LSI mode. 652 */ 653 case 'k': 654 case CTRL('p'): 655 wdot = dot - cnt; 656 if (vmoving == 0) 657 vmoving = 1, vmovcol = column(cursor); 658 wcursor = 0; 659 break; 660 661 /* 662 * L To last line on screen, or count'th line from the 663 * bottom. 664 */ 665 case 'L': 666 wdot = dot + vcnt - vcline - cnt; 667 if (opf == vmove) 668 markit(wdot); 669 vmoving = 0; 670 wcursor = 0; 671 break; 672 673 /* 674 * M To the middle of the screen. 675 */ 676 case 'M': 677 wdot = dot + ((vcnt + 1) / 2) - vcline - 1; 678 if (opf == vmove) 679 markit(wdot); 680 vmoving = 0; 681 wcursor = 0; 682 break; 683 684 /* 685 * + Forward line, to first non-white. 686 * 687 * CR Convenient synonym for +. 688 */ 689 case '+': 690 case CR: 691 wdot = dot + cnt; 692 vmoving = 0; 693 wcursor = 0; 694 break; 695 696 /* 697 * ^N To next line, same column if possible. 698 * 699 * LF Linefeed is a convenient synonym for ^N. 700 */ 701 case CTRL('n'): 702 case 'j': 703 case NL: 704 wdot = dot + cnt; 705 if (vmoving == 0) 706 vmoving = 1, vmovcol = column(cursor); 707 wcursor = 0; 708 break; 709 710 /* 711 * n Search to next match of current pattern. 712 */ 713 case 'n': 714 vglobp = vscandir; 715 c = *vglobp++; 716 goto nocount; 717 718 /* 719 * N Like n but in reverse direction. 720 */ 721 case 'N': 722 vglobp = vscandir[0] == '/' ? (unsigned char *)"?" : 723 (unsigned char *)"/"; 724 c = *vglobp++; 725 goto nocount; 726 727 /* 728 * ' Return to line specified by following mark, 729 * first white position on line. 730 * 731 * ` Return to marked line at remembered column. 732 */ 733 case '\'': 734 case '`': 735 d = c; 736 c = getesc(); 737 if (c == 0) 738 return; 739 c = markreg(c); 740 forbid(c == 0); 741 wdot = getmark(c); 742 forbid(wdot == NOLINE); 743 forbid(Xhadcnt); 744 vmoving = 0; 745 wcursor = d == '`' ? ncols[c - 'a'] : 0; 746 if (opf == vmove && (wdot != dot || 747 (d == '`' && wcursor != cursor))) 748 markDOT(); 749 if (wcursor) { 750 vsave(); 751 getaline(*wdot); 752 if (wcursor > strend(linebuf)) 753 wcursor = 0; 754 else { 755 cnt = wcursor - linebuf; 756 /*CSTYLED*/ 757 for (wcursor = linebuf; wcursor - linebuf < cnt; ) 758 wcursor = nextchr(wcursor); 759 if (wcursor - linebuf > cnt) 760 wcursor = lastchr(linebuf, wcursor); 761 } 762 getDOT(); 763 } 764 if (ospeed > B300) 765 hold |= HOLDWIG; 766 break; 767 768 /* 769 * G Goto count'th line, or last line if no count 770 * given. 771 */ 772 case 'G': 773 if (!Xhadcnt) 774 cnt = lineDOL(); 775 wdot = zero + cnt; 776 forbid(wdot < one || wdot > dol); 777 if (opf == vmove) 778 markit(wdot); 779 vmoving = 0; 780 wcursor = 0; 781 break; 782 783 /* 784 * / Scan forward for following re. 785 * ? Scan backward for following re. 786 */ 787 case '/': 788 case '?': 789 forbid(Xhadcnt); 790 vsave(); 791 oc = c; 792 ocurs = cursor; 793 odot = dot; 794 wcursor = 0; 795 if (readecho(c)) 796 return; 797 if (!vglobp) 798 vscandir[0] = genbuf[0]; 799 oglobp = globp; CP(vutmp, genbuf); globp = vutmp; 800 d = peekc; 801 fromsemi: 802 ungetchar(0); 803 fixech(); 804 CATCH 805 #ifndef CBREAK 806 /* 807 * Lose typeahead (ick). 808 */ 809 vcook(); 810 #endif 811 addr = address(cursor); 812 #ifndef CBREAK 813 vraw(); 814 #endif 815 ONERR 816 #ifndef CBREAK 817 vraw(); 818 #endif 819 slerr: 820 globp = oglobp; 821 dot = odot; 822 cursor = ocurs; 823 ungetchar(d); 824 splitw = 0; 825 vclean(); 826 vjumpto(dot, ocurs, 0); 827 return; 828 ENDCATCH 829 if (globp == 0) 830 globp = (unsigned char *)""; 831 else if (peekc) 832 --globp; 833 if (*globp == ';') { 834 /* /foo/;/bar/ */ 835 globp++; 836 dot = addr; 837 cursor = (unsigned char *)loc1; 838 goto fromsemi; 839 } 840 dot = odot; 841 ungetchar(d); 842 c = 0; 843 if (*globp == 'z') 844 globp++, c = '\n'; 845 if (any(*globp, "^+-.")) 846 c = *globp++; 847 i = 0; 848 while (isdigit(*globp)) 849 i = i * 10 + *globp++ - '0'; 850 if (any(*globp, "^+-.")) 851 c = *globp++; 852 if (*globp) { 853 /* random junk after the pattern */ 854 (void) beep(); 855 goto slerr; 856 } 857 globp = oglobp; 858 splitw = 0; 859 vmoving = 0; 860 wcursor = (unsigned char *)loc1; 861 if (i != 0) 862 vsetsiz(i); 863 if (opf == vmove) { 864 if (state == ONEOPEN || state == HARDOPEN) 865 outline = destline = WBOT; 866 if (addr != dot || (unsigned char *)loc1 != cursor) 867 markDOT(); 868 if (loc1 > (char *)linebuf && *loc1 == 0) 869 loc1 = (char *)lastchr(linebuf, loc1); 870 if (c) 871 vjumpto(addr, (unsigned char *)loc1, c); 872 else { 873 vmoving = 0; 874 if (loc1) { 875 vmoving++; 876 vmovcol = column(loc1); 877 } 878 getDOT(); 879 if (state == CRTOPEN && addr != dot) 880 vup1(); 881 vupdown(addr - dot, NOSTR); 882 } 883 if (oc == '/') { /* forward search */ 884 if (dot < odot || 885 (dot == odot && cursor <= ocurs)) 886 warnf(value(vi_TERSE) ? 887 gettext("Search wrapped BOTTOM") : 888 gettext("Search wrapped around BOTTOM of buffer")); 889 } else { /* backward search */ 890 if (dot > odot || 891 (dot == odot && cursor >= ocurs)) 892 warnf(value(vi_TERSE) ? 893 gettext("Search wrapped TOP") : 894 gettext("Search wrapped around TOP of buffer")); 895 } 896 return; 897 } 898 lastcp[-1] = 'n'; 899 getDOT(); 900 wdot = addr; 901 break; 902 } 903 /* 904 * Apply. 905 */ 906 if (vreg && wdot == 0) 907 wdot = dot; 908 (*opf)(c); 909 wdot = NOLINE; 910 } 911 912 static void 913 lfixol() 914 { 915 unsigned char *savevglobp; 916 int savesplit; 917 918 if (Outchar == vputchar) 919 return; 920 921 /* Show messages */ 922 putnl(); 923 if (inopen > 0 && clr_eol) 924 vclreol(); 925 if (enter_standout_mode && exit_bold) 926 putpad((unsigned char *)enter_standout_mode); 927 lprintf(gettext("[Hit return to continue] "), 0); 928 if (enter_standout_mode && exit_bold) 929 putpad((unsigned char *)exit_bold); 930 931 /* Get key input for confirmation */ 932 savevglobp = vglobp; 933 vglobp = 0; /* force typed input */ 934 getkey(); 935 vglobp = savevglobp; 936 937 /* reset output function */ 938 Outchar = vputchar; 939 940 /* Clean up screen */ 941 savesplit = splitw; 942 splitw = 0; 943 vclear(); 944 vdirty(0, WLINES); 945 vredraw(WTOP); 946 splitw = savesplit; 947 } 948 949 void 950 warnf(char *str, char *cp) 951 { 952 int saveline, savecol, savesplit; 953 954 saveline = outline; 955 savecol = outcol; 956 savesplit = splitw; 957 splitw = 1; 958 vgoto(WECHO, 0); 959 if (!enter_standout_mode || !exit_bold) 960 dingdong(); 961 if (clr_eol) 962 vclreol(); 963 if (enter_standout_mode && exit_bold) 964 putpad((unsigned char *)enter_standout_mode); 965 lprintf(str, cp); 966 if (enter_standout_mode && exit_bold) 967 putpad((unsigned char *)exit_bold); 968 lfixol(); 969 vgoto(saveline, savecol); 970 splitw = savesplit; 971 } 972 973 /* #ifdef PTR_ADDRESSES */ 974 /* 975 * read in a row or column address 976 * 977 */ 978 static int 979 get_addr() 980 { 981 short c; 982 short next; 983 984 c = getkey(); 985 next = 0; 986 switch (c) { 987 case CTRL('A'): 988 next = 96; 989 c = getkey(); 990 break; 991 992 case CTRL('B'): 993 next = 192; 994 c = getkey(); 995 break; 996 } 997 if (c < ' ') 998 return (-1); 999 return (next + c - ' '); 1000 } 1001 /* #endif PTR_ADDRESSES */ 1002 1003 /* 1004 * Find single character c, in direction dir from cursor. 1005 */ 1006 int 1007 find(wchar_t c) 1008 { 1009 1010 wchar_t wchar; 1011 int length; 1012 for (;;) { 1013 if (edge()) 1014 return (0); 1015 if (dir == 1) 1016 wcursor = nextchr(wcursor); 1017 else 1018 wcursor = lastchr(linebuf, wcursor); 1019 if ((length = mbtowc(&wchar, (char *)wcursor, 1020 MULTI_BYTE_MAX)) > 0 && wchar == c) 1021 return (1); 1022 } 1023 } 1024 1025 /* 1026 * Do a word motion with operator op, and cnt more words 1027 * to go after this. 1028 */ 1029 int 1030 word(int (*op)(), int cnt) 1031 { 1032 int which; 1033 unsigned char *iwc; 1034 line *iwdot = wdot; 1035 wchar_t wchar; 1036 int length; 1037 1038 if (dir == 1) { 1039 iwc = wcursor; 1040 which = wordch(wcursor); 1041 while (wordof(which, wcursor)) { 1042 length = mbtowc(&wchar, (char *)wcursor, 1043 MULTI_BYTE_MAX); 1044 if (length <= 0) 1045 length = 1; 1046 if (cnt == 1 && op != vmove && wcursor[length] == 0) { 1047 wcursor += length; 1048 break; 1049 } 1050 if (!lnext()) 1051 return (0); 1052 if (wcursor == linebuf) 1053 break; 1054 } 1055 /* Unless last segment of a change skip blanks */ 1056 if (op != (int (*)())vchange || cnt > 1) 1057 while (!margin() && blank()) { 1058 if (!lnext()) 1059 return (0); 1060 } 1061 else 1062 if (wcursor == iwc && iwdot == wdot && *iwc) 1063 wcursor = nextchr(wcursor); 1064 if (op == vmove && margin()) { 1065 wcursor = lastchr(linebuf, wcursor); 1066 #ifdef XPG4 1067 if (wcursor < linebuf) { 1068 wcursor = linebuf; 1069 } 1070 #endif /* XPG4 */ 1071 } 1072 } else { 1073 if (!lnext()) 1074 return (0); 1075 while (blank()) 1076 if (!lnext()) 1077 return (0); 1078 if (!margin()) { 1079 which = wordch(wcursor); 1080 while (!margin() && wordof(which, wcursor)) 1081 wcursor = lastchr(linebuf, wcursor); 1082 } 1083 #ifdef PRESUNEUC 1084 if (wcursor < linebuf || !wordof(which, wcursor)) 1085 wcursor = nextchr(wcursor); 1086 #else 1087 if (wcursor < linebuf) 1088 wcursor++; 1089 else if (!wordof(which, wcursor)) 1090 wcursor = nextchr(wcursor); 1091 #endif /* PRESUNEUC */ 1092 } 1093 return (1); 1094 } 1095 1096 /* 1097 * To end of word, with operator op and cnt more motions 1098 * remaining after this. 1099 */ 1100 int 1101 eend(int (*op)()) 1102 { 1103 int which; 1104 1105 if (!lnext()) 1106 return (0); 1107 while (blank()) 1108 if (!lnext()) 1109 return (0); 1110 which = wordch(wcursor); 1111 while (wordof(which, wcursor)) { 1112 if (wcursor[1] == 0) { 1113 wcursor = nextchr(wcursor); 1114 break; 1115 } 1116 if (!lnext()) 1117 return (0); 1118 } 1119 if (op == vyankit) 1120 wcursor = lastchr(linebuf, wcursor) + 1; 1121 else if (op != (int (*)())vchange && op != (int (*)())vdelete && 1122 wcursor > linebuf) 1123 wcursor = lastchr(linebuf, wcursor); 1124 return (1); 1125 } 1126 1127 /* 1128 * Wordof tells whether the character at *wc is in a word of 1129 * kind which (blank/nonblank words are 0, conservative words 1). 1130 */ 1131 int 1132 wordof(unsigned char which, unsigned char *wc) 1133 { 1134 #ifdef PRESUNEUC 1135 1136 if (isspace(*wc)) 1137 #else 1138 wchar_t z; 1139 1140 (void) mbtowc(&z, (char *)wc, MB_LEN_MAX); 1141 if (iswspace(z)) 1142 #endif /* PRESUNEUC */ 1143 return (0); 1144 return (!wdkind || wordch(wc) == which); 1145 } 1146 1147 /* 1148 * Wordch tells whether character at *wc is a word character 1149 * i.e. an alfa, digit, or underscore. 1150 */ 1151 #ifdef PRESUNEUC 1152 #define SS2 0216 1153 #define SS3 0217 1154 #endif /* PRESUNEUC */ 1155 1156 int 1157 wordch(unsigned char *wc) 1158 { 1159 int length; 1160 wchar_t c; 1161 1162 length = mbtowc(&c, (char *)wc, MULTI_BYTE_MAX); 1163 if (length <= 0) 1164 return (0); 1165 if (length > 1) 1166 #ifndef PRESUNEUC 1167 if (wdwc) 1168 return (*wdwc)(c); 1169 else 1170 #endif /* PRESUNEUC */ 1171 return (length); 1172 #ifndef PRESUNEUC 1173 return (isalpha(*wc) || isdigit(*wc) || *wc == '_'); 1174 #else 1175 return (isalpha(c) || isdigit(c) || c == '_'); 1176 #endif /* PRESUNEUC */ 1177 } 1178 1179 /* 1180 * Edge tells when we hit the last character in the current line. 1181 */ 1182 int 1183 edge(void) 1184 { 1185 1186 if (linebuf[0] == 0) 1187 return (1); 1188 if (dir == 1) 1189 return (*(nextchr(wcursor)) == 0); 1190 else 1191 return (wcursor == linebuf); 1192 } 1193 1194 /* 1195 * Margin tells us when we have fallen off the end of the line. 1196 */ 1197 int 1198 margin(void) 1199 { 1200 1201 return (wcursor < linebuf || wcursor[0] == 0); 1202 } 1203 #ifndef PRESUNEUC 1204 1205 /* 1206 * Blank tells if the cursor is currently on a TAB, RETURN, 1207 * NEWLINE, FORMFEED, bertical tab, or SPACE character from EUC 1208 * primary and supplementary codesets. 1209 */ 1210 int 1211 blank(void) 1212 { 1213 wchar_t z; 1214 1215 (void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX); 1216 return (iswspace((int)z)); 1217 } 1218 #endif /* PRESUNEUC */ 1219