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 /* fall into ... */ 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 /* fall into ... */ 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 /* fall into ... */ 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 /* fall into... */ 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 /* fall into... */ 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 /* fall into ... */ 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 /* fall into ... */ 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 case 'f': 487 fixup: 488 if (moveop != vmove) 489 wcursor = nextchr(wcursor); 490 break; 491 } 492 break; 493 494 /* 495 * | Find specified print column in current line. 496 */ 497 case '|': 498 if (Pline == numbline) 499 cnt += 8; 500 vmovcol = cnt; 501 vmoving = 1; 502 wcursor = vfindcol(cnt); 503 break; 504 505 /* 506 * ^ To beginning of non-white space on line. 507 */ 508 case '^': 509 wcursor = vskipwh(linebuf); 510 vmoving = 0; 511 break; 512 513 /* 514 * $ To end of line. 515 */ 516 case '$': 517 if (opf == vmove) { 518 vmoving = 1; 519 vmovcol = 20000; 520 } else 521 vmoving = 0; 522 if (cnt > 1) { 523 if (opf == vmove) { 524 wcursor = 0; 525 cnt--; 526 } else 527 wcursor = linebuf; 528 /* This is wrong at EOF */ 529 wdot = dot + cnt; 530 break; 531 } 532 if (linebuf[0]) { 533 wcursor = strend(linebuf); 534 wcursor = lastchr(linebuf, wcursor); 535 goto fixup; 536 } 537 wcursor = linebuf; 538 break; 539 540 /* 541 * h Back a character. 542 * ^H Back a character. 543 */ 544 case 'h': 545 case CTRL('h'): 546 dir = -1; 547 /* fall into ... */ 548 549 /* 550 * space Forward a character. 551 */ 552 case 'l': 553 case ' ': 554 forbid(margin() || opf == vmove && edge()); 555 while (cnt > 0 && !margin()) { 556 if (dir == 1) 557 wcursor = nextchr(wcursor); 558 else 559 wcursor = lastchr(linebuf, wcursor); 560 cnt--; 561 } 562 if (margin() && opf == vmove || wcursor < linebuf) { 563 if (dir == 1) 564 wcursor = lastchr(linebuf, wcursor); 565 else 566 wcursor = linebuf; 567 } 568 vmoving = 0; 569 break; 570 571 /* 572 * D Delete to end of line, short for d$. 573 */ 574 case 'D': 575 cnt = INF; 576 goto deleteit; 577 578 /* 579 * X Delete character before cursor. 580 */ 581 case 'X': 582 dir = -1; 583 /* fall into ... */ 584 deleteit: 585 /* 586 * x Delete character at cursor, leaving cursor where it is. 587 */ 588 case 'x': 589 if (margin()) 590 goto errlab; 591 vmacchng(1); 592 while (cnt > 0 && !margin()) { 593 if (dir == 1) 594 wcursor = nextchr(wcursor); 595 else 596 wcursor = lastchr(linebuf, wcursor); 597 cnt--; 598 } 599 opf = deleteop; 600 vmoving = 0; 601 break; 602 603 default: 604 /* 605 * Stuttered operators are equivalent to the operator on 606 * a line, thus turn dd into d_. 607 */ 608 if (opf == vmove || c != workcmd[0]) { 609 errlab: 610 (void) beep(); 611 vmacp = 0; 612 return; 613 } 614 /* fall into ... */ 615 616 /* 617 * _ Target for a line or group of lines. 618 * Stuttering is more convenient; this is mostly 619 * for aesthetics. 620 */ 621 case '_': 622 wdot = dot + cnt - 1; 623 vmoving = 0; 624 wcursor = 0; 625 break; 626 627 /* 628 * H To first, home line on screen. 629 * Count is for count'th line rather than first. 630 */ 631 case 'H': 632 wdot = (dot - vcline) + cnt - 1; 633 if (opf == vmove) 634 markit(wdot); 635 vmoving = 0; 636 wcursor = 0; 637 break; 638 639 /* 640 * - Backwards lines, to first non-white character. 641 */ 642 case '-': 643 wdot = dot - cnt; 644 vmoving = 0; 645 wcursor = 0; 646 break; 647 648 /* 649 * ^P To previous line same column. Ridiculous on the 650 * console of the VAX since it puts console in LSI mode. 651 */ 652 case 'k': 653 case CTRL('p'): 654 wdot = dot - cnt; 655 if (vmoving == 0) 656 vmoving = 1, vmovcol = column(cursor); 657 wcursor = 0; 658 break; 659 660 /* 661 * L To last line on screen, or count'th line from the 662 * bottom. 663 */ 664 case 'L': 665 wdot = dot + vcnt - vcline - cnt; 666 if (opf == vmove) 667 markit(wdot); 668 vmoving = 0; 669 wcursor = 0; 670 break; 671 672 /* 673 * M To the middle of the screen. 674 */ 675 case 'M': 676 wdot = dot + ((vcnt + 1) / 2) - vcline - 1; 677 if (opf == vmove) 678 markit(wdot); 679 vmoving = 0; 680 wcursor = 0; 681 break; 682 683 /* 684 * + Forward line, to first non-white. 685 * 686 * CR Convenient synonym for +. 687 */ 688 case '+': 689 case CR: 690 wdot = dot + cnt; 691 vmoving = 0; 692 wcursor = 0; 693 break; 694 695 /* 696 * ^N To next line, same column if possible. 697 * 698 * LF Linefeed is a convenient synonym for ^N. 699 */ 700 case CTRL('n'): 701 case 'j': 702 case NL: 703 wdot = dot + cnt; 704 if (vmoving == 0) 705 vmoving = 1, vmovcol = column(cursor); 706 wcursor = 0; 707 break; 708 709 /* 710 * n Search to next match of current pattern. 711 */ 712 case 'n': 713 vglobp = vscandir; 714 c = *vglobp++; 715 goto nocount; 716 717 /* 718 * N Like n but in reverse direction. 719 */ 720 case 'N': 721 vglobp = vscandir[0] == '/' ? (unsigned char *)"?" : 722 (unsigned char *)"/"; 723 c = *vglobp++; 724 goto nocount; 725 726 /* 727 * ' Return to line specified by following mark, 728 * first white position on line. 729 * 730 * ` Return to marked line at remembered column. 731 */ 732 case '\'': 733 case '`': 734 d = c; 735 c = getesc(); 736 if (c == 0) 737 return; 738 c = markreg(c); 739 forbid(c == 0); 740 wdot = getmark(c); 741 forbid(wdot == NOLINE); 742 forbid(Xhadcnt); 743 vmoving = 0; 744 wcursor = d == '`' ? ncols[c - 'a'] : 0; 745 if (opf == vmove && (wdot != dot || 746 (d == '`' && wcursor != cursor))) 747 markDOT(); 748 if (wcursor) { 749 vsave(); 750 getaline(*wdot); 751 if (wcursor > strend(linebuf)) 752 wcursor = 0; 753 else { 754 cnt = wcursor - linebuf; 755 /*CSTYLED*/ 756 for (wcursor = linebuf; wcursor - linebuf < cnt; ) 757 wcursor = nextchr(wcursor); 758 if (wcursor - linebuf > cnt) 759 wcursor = lastchr(linebuf, wcursor); 760 } 761 getDOT(); 762 } 763 if (ospeed > B300) 764 hold |= HOLDWIG; 765 break; 766 767 /* 768 * G Goto count'th line, or last line if no count 769 * given. 770 */ 771 case 'G': 772 if (!Xhadcnt) 773 cnt = lineDOL(); 774 wdot = zero + cnt; 775 forbid(wdot < one || wdot > dol); 776 if (opf == vmove) 777 markit(wdot); 778 vmoving = 0; 779 wcursor = 0; 780 break; 781 782 /* 783 * / Scan forward for following re. 784 * ? Scan backward for following re. 785 */ 786 case '/': 787 case '?': 788 forbid(Xhadcnt); 789 vsave(); 790 oc = c; 791 ocurs = cursor; 792 odot = dot; 793 wcursor = 0; 794 if (readecho(c)) 795 return; 796 if (!vglobp) 797 vscandir[0] = genbuf[0]; 798 oglobp = globp; CP(vutmp, genbuf); globp = vutmp; 799 d = peekc; 800 fromsemi: 801 ungetchar(0); 802 fixech(); 803 CATCH 804 #ifndef CBREAK 805 /* 806 * Lose typeahead (ick). 807 */ 808 vcook(); 809 #endif 810 addr = address(cursor); 811 #ifndef CBREAK 812 vraw(); 813 #endif 814 ONERR 815 #ifndef CBREAK 816 vraw(); 817 #endif 818 slerr: 819 globp = oglobp; 820 dot = odot; 821 cursor = ocurs; 822 ungetchar(d); 823 splitw = 0; 824 vclean(); 825 vjumpto(dot, ocurs, 0); 826 return; 827 ENDCATCH 828 if (globp == 0) 829 globp = (unsigned char *)""; 830 else if (peekc) 831 --globp; 832 if (*globp == ';') { 833 /* /foo/;/bar/ */ 834 globp++; 835 dot = addr; 836 cursor = (unsigned char *)loc1; 837 goto fromsemi; 838 } 839 dot = odot; 840 ungetchar(d); 841 c = 0; 842 if (*globp == 'z') 843 globp++, c = '\n'; 844 if (any(*globp, "^+-.")) 845 c = *globp++; 846 i = 0; 847 while (isdigit(*globp)) 848 i = i * 10 + *globp++ - '0'; 849 if (any(*globp, "^+-.")) 850 c = *globp++; 851 if (*globp) { 852 /* random junk after the pattern */ 853 (void) beep(); 854 goto slerr; 855 } 856 globp = oglobp; 857 splitw = 0; 858 vmoving = 0; 859 wcursor = (unsigned char *)loc1; 860 if (i != 0) 861 vsetsiz(i); 862 if (opf == vmove) { 863 if (state == ONEOPEN || state == HARDOPEN) 864 outline = destline = WBOT; 865 if (addr != dot || (unsigned char *)loc1 != cursor) 866 markDOT(); 867 if (loc1 > (char *)linebuf && *loc1 == 0) 868 loc1 = (char *)lastchr(linebuf, loc1); 869 if (c) 870 vjumpto(addr, (unsigned char *)loc1, c); 871 else { 872 vmoving = 0; 873 if (loc1) { 874 vmoving++; 875 vmovcol = column(loc1); 876 } 877 getDOT(); 878 if (state == CRTOPEN && addr != dot) 879 vup1(); 880 vupdown(addr - dot, NOSTR); 881 } 882 if (oc == '/') { /* forward search */ 883 if (dot < odot || 884 (dot == odot && cursor <= ocurs)) 885 warnf(value(vi_TERSE) ? 886 gettext("Search wrapped BOTTOM") : 887 gettext("Search wrapped around BOTTOM of buffer")); 888 } else { /* backward search */ 889 if (dot > odot || 890 (dot == odot && cursor >= ocurs)) 891 warnf(value(vi_TERSE) ? 892 gettext("Search wrapped TOP") : 893 gettext("Search wrapped around TOP of buffer")); 894 } 895 return; 896 } 897 lastcp[-1] = 'n'; 898 getDOT(); 899 wdot = addr; 900 break; 901 } 902 /* 903 * Apply. 904 */ 905 if (vreg && wdot == 0) 906 wdot = dot; 907 (*opf)(c); 908 wdot = NOLINE; 909 } 910 911 static void 912 lfixol() 913 { 914 unsigned char *savevglobp; 915 int savesplit; 916 917 if (Outchar == vputchar) 918 return; 919 920 /* Show messages */ 921 putnl(); 922 if (inopen > 0 && clr_eol) 923 vclreol(); 924 if (enter_standout_mode && exit_bold) 925 putpad((unsigned char *)enter_standout_mode); 926 lprintf(gettext("[Hit return to continue] "), 0); 927 if (enter_standout_mode && exit_bold) 928 putpad((unsigned char *)exit_bold); 929 930 /* Get key input for confirmation */ 931 savevglobp = vglobp; 932 vglobp = 0; /* force typed input */ 933 getkey(); 934 vglobp = savevglobp; 935 936 /* reset output function */ 937 Outchar = vputchar; 938 939 /* Clean up screen */ 940 savesplit = splitw; 941 splitw = 0; 942 vclear(); 943 vdirty(0, WLINES); 944 vredraw(WTOP); 945 splitw = savesplit; 946 } 947 948 void 949 warnf(char *str, char *cp) 950 { 951 int saveline, savecol, savesplit; 952 953 saveline = outline; 954 savecol = outcol; 955 savesplit = splitw; 956 splitw = 1; 957 vgoto(WECHO, 0); 958 if (!enter_standout_mode || !exit_bold) 959 dingdong(); 960 if (clr_eol) 961 vclreol(); 962 if (enter_standout_mode && exit_bold) 963 putpad((unsigned char *)enter_standout_mode); 964 lprintf(str, cp); 965 if (enter_standout_mode && exit_bold) 966 putpad((unsigned char *)exit_bold); 967 lfixol(); 968 vgoto(saveline, savecol); 969 splitw = savesplit; 970 } 971 972 /* #ifdef PTR_ADDRESSES */ 973 /* 974 * read in a row or column address 975 * 976 */ 977 static int 978 get_addr() 979 { 980 short c; 981 short next; 982 983 c = getkey(); 984 next = 0; 985 switch (c) { 986 case CTRL('A'): 987 next = 96; 988 c = getkey(); 989 break; 990 991 case CTRL('B'): 992 next = 192; 993 c = getkey(); 994 break; 995 } 996 if (c < ' ') 997 return (-1); 998 return (next + c - ' '); 999 } 1000 /* #endif PTR_ADDRESSES */ 1001 1002 /* 1003 * Find single character c, in direction dir from cursor. 1004 */ 1005 int 1006 find(wchar_t c) 1007 { 1008 1009 wchar_t wchar; 1010 int length; 1011 for (;;) { 1012 if (edge()) 1013 return (0); 1014 if (dir == 1) 1015 wcursor = nextchr(wcursor); 1016 else 1017 wcursor = lastchr(linebuf, wcursor); 1018 if ((length = mbtowc(&wchar, (char *)wcursor, 1019 MULTI_BYTE_MAX)) > 0 && wchar == c) 1020 return (1); 1021 } 1022 } 1023 1024 /* 1025 * Do a word motion with operator op, and cnt more words 1026 * to go after this. 1027 */ 1028 int 1029 word(int (*op)(), int cnt) 1030 { 1031 int which; 1032 unsigned char *iwc; 1033 line *iwdot = wdot; 1034 wchar_t wchar; 1035 int length; 1036 1037 if (dir == 1) { 1038 iwc = wcursor; 1039 which = wordch(wcursor); 1040 while (wordof(which, wcursor)) { 1041 length = mbtowc(&wchar, (char *)wcursor, 1042 MULTI_BYTE_MAX); 1043 if (length <= 0) 1044 length = 1; 1045 if (cnt == 1 && op != vmove && wcursor[length] == 0) { 1046 wcursor += length; 1047 break; 1048 } 1049 if (!lnext()) 1050 return (0); 1051 if (wcursor == linebuf) 1052 break; 1053 } 1054 /* Unless last segment of a change skip blanks */ 1055 if (op != (int (*)())vchange || cnt > 1) 1056 while (!margin() && blank()) { 1057 if (!lnext()) 1058 return (0); 1059 } 1060 else 1061 if (wcursor == iwc && iwdot == wdot && *iwc) 1062 wcursor = nextchr(wcursor); 1063 if (op == vmove && margin()) { 1064 wcursor = lastchr(linebuf, wcursor); 1065 #ifdef XPG4 1066 if (wcursor < linebuf) { 1067 wcursor = linebuf; 1068 } 1069 #endif /* XPG4 */ 1070 } 1071 } else { 1072 if (!lnext()) 1073 return (0); 1074 while (blank()) 1075 if (!lnext()) 1076 return (0); 1077 if (!margin()) { 1078 which = wordch(wcursor); 1079 while (!margin() && wordof(which, wcursor)) 1080 wcursor = lastchr(linebuf, wcursor); 1081 } 1082 #ifdef PRESUNEUC 1083 if (wcursor < linebuf || !wordof(which, wcursor)) 1084 wcursor = nextchr(wcursor); 1085 #else 1086 if (wcursor < linebuf) 1087 wcursor++; 1088 else if (!wordof(which, wcursor)) 1089 wcursor = nextchr(wcursor); 1090 #endif /* PRESUNEUC */ 1091 } 1092 return (1); 1093 } 1094 1095 /* 1096 * To end of word, with operator op and cnt more motions 1097 * remaining after this. 1098 */ 1099 int 1100 eend(int (*op)()) 1101 { 1102 int which; 1103 1104 if (!lnext()) 1105 return (0); 1106 while (blank()) 1107 if (!lnext()) 1108 return (0); 1109 which = wordch(wcursor); 1110 while (wordof(which, wcursor)) { 1111 if (wcursor[1] == 0) { 1112 wcursor = nextchr(wcursor); 1113 break; 1114 } 1115 if (!lnext()) 1116 return (0); 1117 } 1118 if (op == vyankit) 1119 wcursor = lastchr(linebuf, wcursor) + 1; 1120 else if (op != (int (*)())vchange && op != (int (*)())vdelete && 1121 wcursor > linebuf) 1122 wcursor = lastchr(linebuf, wcursor); 1123 return (1); 1124 } 1125 1126 /* 1127 * Wordof tells whether the character at *wc is in a word of 1128 * kind which (blank/nonblank words are 0, conservative words 1). 1129 */ 1130 int 1131 wordof(unsigned char which, unsigned char *wc) 1132 { 1133 #ifdef PRESUNEUC 1134 1135 if (isspace(*wc)) 1136 #else 1137 wchar_t z; 1138 1139 (void) mbtowc(&z, (char *)wc, MB_LEN_MAX); 1140 if (iswspace(z)) 1141 #endif /* PRESUNEUC */ 1142 return (0); 1143 return (!wdkind || wordch(wc) == which); 1144 } 1145 1146 /* 1147 * Wordch tells whether character at *wc is a word character 1148 * i.e. an alfa, digit, or underscore. 1149 */ 1150 #ifdef PRESUNEUC 1151 #define SS2 0216 1152 #define SS3 0217 1153 #endif /* PRESUNEUC */ 1154 1155 int 1156 wordch(unsigned char *wc) 1157 { 1158 int length; 1159 wchar_t c; 1160 1161 length = mbtowc(&c, (char *)wc, MULTI_BYTE_MAX); 1162 if (length <= 0) 1163 return (0); 1164 if (length > 1) 1165 #ifndef PRESUNEUC 1166 if (wdwc) 1167 return (*wdwc)(c); 1168 else 1169 #endif /* PRESUNEUC */ 1170 return (length); 1171 #ifndef PRESUNEUC 1172 return (isalpha(*wc) || isdigit(*wc) || *wc == '_'); 1173 #else 1174 return (isalpha(c) || isdigit(c) || c == '_'); 1175 #endif /* PRESUNEUC */ 1176 } 1177 1178 /* 1179 * Edge tells when we hit the last character in the current line. 1180 */ 1181 int 1182 edge(void) 1183 { 1184 1185 if (linebuf[0] == 0) 1186 return (1); 1187 if (dir == 1) 1188 return (*(nextchr(wcursor)) == 0); 1189 else 1190 return (wcursor == linebuf); 1191 } 1192 1193 /* 1194 * Margin tells us when we have fallen off the end of the line. 1195 */ 1196 int 1197 margin(void) 1198 { 1199 1200 return (wcursor < linebuf || wcursor[0] == 0); 1201 } 1202 #ifndef PRESUNEUC 1203 1204 /* 1205 * Blank tells if the cursor is currently on a TAB, RETURN, 1206 * NEWLINE, FORMFEED, bertical tab, or SPACE character from EUC 1207 * primary and supplementary codesets. 1208 */ 1209 int 1210 blank(void) 1211 { 1212 wchar_t z; 1213 1214 (void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX); 1215 return (iswspace((int)z)); 1216 } 1217 #endif /* PRESUNEUC */ 1218