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