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