1 /* $FreeBSD$ */ 2 /* 3 * Copyright (C) 1984-2011 Mark Nudelman 4 * 5 * You may distribute under the terms of either the GNU General Public 6 * License or the Less License, as specified in the README file. 7 * 8 * For more information about less, or for information on how to 9 * contact the author, see the README file. 10 */ 11 12 13 /* 14 * Routines to search a file for a pattern. 15 */ 16 17 #include "less.h" 18 #include "pattern.h" 19 #include "position.h" 20 #include "charset.h" 21 22 #define MINPOS(a,b) (((a) < (b)) ? (a) : (b)) 23 #define MAXPOS(a,b) (((a) > (b)) ? (a) : (b)) 24 25 extern int sigs; 26 extern int how_search; 27 extern int caseless; 28 extern int linenums; 29 extern int sc_height; 30 extern int jump_sline; 31 extern int bs_mode; 32 extern int less_is_more; 33 extern int ctldisp; 34 extern int status_col; 35 extern void * constant ml_search; 36 extern POSITION start_attnpos; 37 extern POSITION end_attnpos; 38 extern int utf_mode; 39 extern int screen_trashed; 40 #if HILITE_SEARCH 41 extern int hilite_search; 42 extern int size_linebuf; 43 extern int squished; 44 extern int can_goto_line; 45 static int hide_hilite; 46 static POSITION prep_startpos; 47 static POSITION prep_endpos; 48 static int is_caseless; 49 static int is_ucase_pattern; 50 51 struct hilite 52 { 53 struct hilite *hl_next; 54 POSITION hl_startpos; 55 POSITION hl_endpos; 56 }; 57 static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 58 static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 59 #define hl_first hl_next 60 #endif 61 62 /* 63 * These are the static variables that represent the "remembered" 64 * search pattern and filter pattern. 65 */ 66 struct pattern_info { 67 DEFINE_PATTERN(compiled); 68 char* text; 69 int search_type; 70 }; 71 72 static struct pattern_info search_info; 73 static struct pattern_info filter_info; 74 75 /* 76 * Are there any uppercase letters in this string? 77 */ 78 static int 79 is_ucase(str) 80 char *str; 81 { 82 char *str_end = str + strlen(str); 83 LWCHAR ch; 84 85 while (str < str_end) 86 { 87 ch = step_char(&str, +1, str_end); 88 if (IS_UPPER(ch)) 89 return (1); 90 } 91 return (0); 92 } 93 94 /* 95 * Compile and save a search pattern. 96 */ 97 static int 98 set_pattern(info, pattern, search_type) 99 struct pattern_info *info; 100 char *pattern; 101 int search_type; 102 { 103 if (pattern == NULL) 104 CLEAR_PATTERN(search_info.compiled); 105 else if (compile_pattern(pattern, search_type, &info->compiled) < 0) 106 return -1; 107 /* Pattern compiled successfully; save the text too. */ 108 if (info->text != NULL) 109 free(info->text); 110 info->text = NULL; 111 if (pattern != NULL) 112 { 113 info->text = (char *) ecalloc(1, strlen(pattern)+1); 114 strcpy(info->text, pattern); 115 } 116 info->search_type = search_type; 117 118 /* 119 * Ignore case if -I is set OR 120 * -i is set AND the pattern is all lowercase. 121 */ 122 is_ucase_pattern = is_ucase(pattern); 123 if (is_ucase_pattern && caseless != OPT_ONPLUS) 124 is_caseless = 0; 125 else 126 is_caseless = caseless; 127 return 0; 128 } 129 130 /* 131 * Discard a saved pattern. 132 */ 133 static void 134 clear_pattern(info) 135 struct pattern_info *info; 136 { 137 if (info->text != NULL) 138 free(info->text); 139 info->text = NULL; 140 uncompile_pattern(&info->compiled); 141 } 142 143 /* 144 * Initialize saved pattern to nothing. 145 */ 146 static void 147 init_pattern(info) 148 struct pattern_info *info; 149 { 150 CLEAR_PATTERN(info->compiled); 151 info->text = NULL; 152 info->search_type = 0; 153 } 154 155 /* 156 * Initialize search variables. 157 */ 158 public void 159 init_search() 160 { 161 init_pattern(&search_info); 162 init_pattern(&filter_info); 163 } 164 165 /* 166 * Determine which text conversions to perform before pattern matching. 167 */ 168 static int 169 get_cvt_ops() 170 { 171 int ops = 0; 172 if (is_caseless || bs_mode == BS_SPECIAL) 173 { 174 if (is_caseless) 175 ops |= CVT_TO_LC; 176 if (bs_mode == BS_SPECIAL) 177 ops |= CVT_BS; 178 if (bs_mode != BS_CONTROL) 179 ops |= CVT_CRLF; 180 } else if (bs_mode != BS_CONTROL) 181 { 182 ops |= CVT_CRLF; 183 } 184 if (ctldisp == OPT_ONPLUS) 185 ops |= CVT_ANSI; 186 return (ops); 187 } 188 189 /* 190 * Is there a previous (remembered) search pattern? 191 */ 192 static int 193 prev_pattern(info) 194 struct pattern_info *info; 195 { 196 if (info->search_type & SRCH_NO_REGEX) 197 return (info->text != NULL); 198 return (!is_null_pattern(info->compiled)); 199 } 200 201 #if HILITE_SEARCH 202 /* 203 * Repaint the hilites currently displayed on the screen. 204 * Repaint each line which contains highlighted text. 205 * If on==0, force all hilites off. 206 */ 207 public void 208 repaint_hilite(on) 209 int on; 210 { 211 int slinenum; 212 POSITION pos; 213 POSITION epos; 214 int save_hide_hilite; 215 216 if (squished) 217 repaint(); 218 219 save_hide_hilite = hide_hilite; 220 if (!on) 221 { 222 if (hide_hilite) 223 return; 224 hide_hilite = 1; 225 } 226 227 if (!can_goto_line) 228 { 229 repaint(); 230 hide_hilite = save_hide_hilite; 231 return; 232 } 233 234 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 235 { 236 pos = position(slinenum); 237 if (pos == NULL_POSITION) 238 continue; 239 epos = position(slinenum+1); 240 (void) forw_line(pos); 241 goto_line(slinenum); 242 put_line(); 243 } 244 lower_left(); 245 hide_hilite = save_hide_hilite; 246 } 247 248 /* 249 * Clear the attn hilite. 250 */ 251 public void 252 clear_attn() 253 { 254 int slinenum; 255 POSITION old_start_attnpos; 256 POSITION old_end_attnpos; 257 POSITION pos; 258 POSITION epos; 259 int moved = 0; 260 261 if (start_attnpos == NULL_POSITION) 262 return; 263 old_start_attnpos = start_attnpos; 264 old_end_attnpos = end_attnpos; 265 start_attnpos = end_attnpos = NULL_POSITION; 266 267 if (!can_goto_line) 268 { 269 repaint(); 270 return; 271 } 272 if (squished) 273 repaint(); 274 275 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 276 { 277 pos = position(slinenum); 278 if (pos == NULL_POSITION) 279 continue; 280 epos = position(slinenum+1); 281 if (pos < old_end_attnpos && 282 (epos == NULL_POSITION || epos > old_start_attnpos)) 283 { 284 (void) forw_line(pos); 285 goto_line(slinenum); 286 put_line(); 287 moved = 1; 288 } 289 } 290 if (moved) 291 lower_left(); 292 } 293 #endif 294 295 /* 296 * Hide search string highlighting. 297 */ 298 public void 299 undo_search() 300 { 301 if (!prev_pattern(&search_info)) 302 { 303 error("No previous regular expression", NULL_PARG); 304 return; 305 } 306 #if HILITE_SEARCH 307 hide_hilite = !hide_hilite; 308 repaint_hilite(1); 309 #endif 310 } 311 312 #if HILITE_SEARCH 313 /* 314 * Clear the hilite list. 315 */ 316 public void 317 clr_hlist(anchor) 318 struct hilite *anchor; 319 { 320 struct hilite *hl; 321 struct hilite *nexthl; 322 323 for (hl = anchor->hl_first; hl != NULL; hl = nexthl) 324 { 325 nexthl = hl->hl_next; 326 free((void*)hl); 327 } 328 anchor->hl_first = NULL; 329 prep_startpos = prep_endpos = NULL_POSITION; 330 } 331 332 public void 333 clr_hilite() 334 { 335 clr_hlist(&hilite_anchor); 336 } 337 338 public void 339 clr_filter() 340 { 341 clr_hlist(&filter_anchor); 342 } 343 344 /* 345 * Should any characters in a specified range be highlighted? 346 */ 347 static int 348 is_hilited_range(pos, epos) 349 POSITION pos; 350 POSITION epos; 351 { 352 struct hilite *hl; 353 354 /* 355 * Look at each highlight and see if any part of it falls in the range. 356 */ 357 for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) 358 { 359 if (hl->hl_endpos > pos && 360 (epos == NULL_POSITION || epos > hl->hl_startpos)) 361 return (1); 362 } 363 return (0); 364 } 365 366 /* 367 * Is a line "filtered" -- that is, should it be hidden? 368 */ 369 public int 370 is_filtered(pos) 371 POSITION pos; 372 { 373 struct hilite *hl; 374 375 if (ch_getflags() & CH_HELPFILE) 376 return (0); 377 378 /* 379 * Look at each filter and see if the start position 380 * equals the start position of the line. 381 */ 382 for (hl = filter_anchor.hl_first; hl != NULL; hl = hl->hl_next) 383 { 384 if (hl->hl_startpos == pos) 385 return (1); 386 } 387 return (0); 388 } 389 390 /* 391 * Should any characters in a specified range be highlighted? 392 * If nohide is nonzero, don't consider hide_hilite. 393 */ 394 public int 395 is_hilited(pos, epos, nohide, p_matches) 396 POSITION pos; 397 POSITION epos; 398 int nohide; 399 int *p_matches; 400 { 401 int match; 402 403 if (p_matches != NULL) 404 *p_matches = 0; 405 406 if (!status_col && 407 start_attnpos != NULL_POSITION && 408 pos < end_attnpos && 409 (epos == NULL_POSITION || epos > start_attnpos)) 410 /* 411 * The attn line overlaps this range. 412 */ 413 return (1); 414 415 match = is_hilited_range(pos, epos); 416 if (!match) 417 return (0); 418 419 if (p_matches != NULL) 420 /* 421 * Report matches, even if we're hiding highlights. 422 */ 423 *p_matches = 1; 424 425 if (hilite_search == 0) 426 /* 427 * Not doing highlighting. 428 */ 429 return (0); 430 431 if (!nohide && hide_hilite) 432 /* 433 * Highlighting is hidden. 434 */ 435 return (0); 436 437 return (1); 438 } 439 440 /* 441 * Add a new hilite to a hilite list. 442 */ 443 static void 444 add_hilite(anchor, hl) 445 struct hilite *anchor; 446 struct hilite *hl; 447 { 448 struct hilite *ihl; 449 450 /* 451 * Hilites are sorted in the list; find where new one belongs. 452 * Insert new one after ihl. 453 */ 454 for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next) 455 { 456 if (ihl->hl_next->hl_startpos > hl->hl_startpos) 457 break; 458 } 459 460 /* 461 * Truncate hilite so it doesn't overlap any existing ones 462 * above and below it. 463 */ 464 if (ihl != anchor) 465 hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos); 466 if (ihl->hl_next != NULL) 467 hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos); 468 if (hl->hl_startpos >= hl->hl_endpos) 469 { 470 /* 471 * Hilite was truncated out of existence. 472 */ 473 free(hl); 474 return; 475 } 476 hl->hl_next = ihl->hl_next; 477 ihl->hl_next = hl; 478 } 479 480 /* 481 * Make a hilite for each string in a physical line which matches 482 * the current pattern. 483 * sp,ep delimit the first match already found. 484 */ 485 static void 486 hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops) 487 POSITION linepos; 488 char *line; 489 int line_len; 490 int *chpos; 491 char *sp; 492 char *ep; 493 int cvt_ops; 494 { 495 char *searchp; 496 char *line_end = line + line_len; 497 struct hilite *hl; 498 499 if (sp == NULL || ep == NULL) 500 return; 501 /* 502 * sp and ep delimit the first match in the line. 503 * Mark the corresponding file positions, then 504 * look for further matches and mark them. 505 * {{ This technique, of calling match_pattern on subsequent 506 * substrings of the line, may mark more than is correct 507 * if the pattern starts with "^". This bug is fixed 508 * for those regex functions that accept a notbol parameter 509 * (currently POSIX, PCRE and V8-with-regexec2). }} 510 */ 511 searchp = line; 512 do { 513 if (ep > sp) 514 { 515 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); 516 hl->hl_startpos = linepos + chpos[sp-line]; 517 hl->hl_endpos = linepos + chpos[ep-line]; 518 add_hilite(&hilite_anchor, hl); 519 } 520 /* 521 * If we matched more than zero characters, 522 * move to the first char after the string we matched. 523 * If we matched zero, just move to the next char. 524 */ 525 if (ep > searchp) 526 searchp = ep; 527 else if (searchp != line_end) 528 searchp++; 529 else /* end of line */ 530 break; 531 } while (match_pattern(search_info.compiled, search_info.text, 532 searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type)); 533 } 534 #endif 535 536 /* 537 * Change the caseless-ness of searches. 538 * Updates the internal search state to reflect a change in the -i flag. 539 */ 540 public void 541 chg_caseless() 542 { 543 if (!is_ucase_pattern) 544 /* 545 * Pattern did not have uppercase. 546 * Just set the search caselessness to the global caselessness. 547 */ 548 is_caseless = caseless; 549 else 550 /* 551 * Pattern did have uppercase. 552 * Discard the pattern; we can't change search caselessness now. 553 */ 554 clear_pattern(&search_info); 555 } 556 557 #if HILITE_SEARCH 558 /* 559 * Find matching text which is currently on screen and highlight it. 560 */ 561 static void 562 hilite_screen() 563 { 564 struct scrpos scrpos; 565 566 get_scrpos(&scrpos); 567 if (scrpos.pos == NULL_POSITION) 568 return; 569 prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); 570 repaint_hilite(1); 571 } 572 573 /* 574 * Change highlighting parameters. 575 */ 576 public void 577 chg_hilite() 578 { 579 /* 580 * Erase any highlights currently on screen. 581 */ 582 clr_hilite(); 583 hide_hilite = 0; 584 585 if (hilite_search == OPT_ONPLUS) 586 /* 587 * Display highlights. 588 */ 589 hilite_screen(); 590 } 591 #endif 592 593 /* 594 * Figure out where to start a search. 595 */ 596 static POSITION 597 search_pos(search_type) 598 int search_type; 599 { 600 POSITION pos; 601 int linenum; 602 603 if (empty_screen()) 604 { 605 /* 606 * Start at the beginning (or end) of the file. 607 * The empty_screen() case is mainly for 608 * command line initiated searches; 609 * for example, "+/xyz" on the command line. 610 * Also for multi-file (SRCH_PAST_EOF) searches. 611 */ 612 if (search_type & SRCH_FORW) 613 { 614 pos = ch_zero(); 615 } else 616 { 617 pos = ch_length(); 618 if (pos == NULL_POSITION) 619 { 620 (void) ch_end_seek(); 621 pos = ch_length(); 622 } 623 } 624 linenum = 0; 625 } else 626 { 627 int add_one = 0; 628 629 if (how_search == OPT_ON) 630 { 631 /* 632 * Search does not include current screen. 633 */ 634 if (search_type & SRCH_FORW) 635 linenum = BOTTOM_PLUS_ONE; 636 else 637 linenum = TOP; 638 } else if (how_search == OPT_ONPLUS && !(search_type & SRCH_AFTER_TARGET)) 639 { 640 /* 641 * Search includes all of displayed screen. 642 */ 643 if (search_type & SRCH_FORW) 644 linenum = TOP; 645 else 646 linenum = BOTTOM_PLUS_ONE; 647 } else 648 { 649 /* 650 * Search includes the part of current screen beyond the jump target. 651 * It starts at the jump target (if searching backwards), 652 * or at the jump target plus one (if forwards). 653 */ 654 linenum = jump_sline; 655 if (search_type & SRCH_FORW) 656 add_one = 1; 657 } 658 linenum = adjsline(linenum); 659 pos = position(linenum); 660 if (add_one) 661 pos = forw_raw_line(pos, (char **)NULL, (int *)NULL); 662 } 663 664 /* 665 * If the line is empty, look around for a plausible starting place. 666 */ 667 if (search_type & SRCH_FORW) 668 { 669 while (pos == NULL_POSITION) 670 { 671 if (++linenum >= sc_height) 672 break; 673 pos = position(linenum); 674 } 675 } else 676 { 677 while (pos == NULL_POSITION) 678 { 679 if (--linenum < 0) 680 break; 681 pos = position(linenum); 682 } 683 } 684 return (pos); 685 } 686 687 /* 688 * Search a subset of the file, specified by start/end position. 689 */ 690 static int 691 search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) 692 POSITION pos; 693 POSITION endpos; 694 int search_type; 695 int matches; 696 int maxlines; 697 POSITION *plinepos; 698 POSITION *pendpos; 699 { 700 char *line; 701 char *cline; 702 int line_len; 703 LINENUM linenum; 704 char *sp, *ep; 705 int line_match; 706 int cvt_ops; 707 int cvt_len; 708 int *chpos; 709 POSITION linepos, oldpos; 710 711 linenum = find_linenum(pos); 712 oldpos = pos; 713 for (;;) 714 { 715 /* 716 * Get lines until we find a matching one or until 717 * we hit end-of-file (or beginning-of-file if we're 718 * going backwards), or until we hit the end position. 719 */ 720 if (ABORT_SIGS()) 721 { 722 /* 723 * A signal aborts the search. 724 */ 725 return (-1); 726 } 727 728 if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) 729 { 730 /* 731 * Reached end position without a match. 732 */ 733 if (pendpos != NULL) 734 *pendpos = pos; 735 return (matches); 736 } 737 if (maxlines > 0) 738 maxlines--; 739 740 if (search_type & SRCH_FORW) 741 { 742 /* 743 * Read the next line, and save the 744 * starting position of that line in linepos. 745 */ 746 linepos = pos; 747 pos = forw_raw_line(pos, &line, &line_len); 748 if (linenum != 0) 749 linenum++; 750 } else 751 { 752 /* 753 * Read the previous line and save the 754 * starting position of that line in linepos. 755 */ 756 pos = back_raw_line(pos, &line, &line_len); 757 linepos = pos; 758 if (linenum != 0) 759 linenum--; 760 } 761 762 if (pos == NULL_POSITION) 763 { 764 /* 765 * Reached EOF/BOF without a match. 766 */ 767 if (pendpos != NULL) 768 *pendpos = oldpos; 769 return (matches); 770 } 771 772 /* 773 * If we're using line numbers, we might as well 774 * remember the information we have now (the position 775 * and line number of the current line). 776 * Don't do it for every line because it slows down 777 * the search. Remember the line number only if 778 * we're "far" from the last place we remembered it. 779 */ 780 if (linenums && abs((int)(pos - oldpos)) > 2048) 781 add_lnum(linenum, pos); 782 oldpos = pos; 783 784 if (is_filtered(linepos)) 785 continue; 786 787 /* 788 * If it's a caseless search, convert the line to lowercase. 789 * If we're doing backspace processing, delete backspaces. 790 */ 791 cvt_ops = get_cvt_ops(); 792 cvt_len = cvt_length(line_len, cvt_ops); 793 cline = (char *) ecalloc(1, cvt_len); 794 chpos = cvt_alloc_chpos(cvt_len); 795 cvt_text(cline, line, chpos, &line_len, cvt_ops); 796 797 #if HILITE_SEARCH 798 /* 799 * Check to see if the line matches the filter pattern. 800 * If so, add an entry to the filter list. 801 */ 802 if ((search_type & SRCH_FIND_ALL) && prev_pattern(&filter_info)) { 803 int line_filter = match_pattern(filter_info.compiled, filter_info.text, 804 cline, line_len, &sp, &ep, 0, filter_info.search_type); 805 if (line_filter) 806 { 807 struct hilite *hl = (struct hilite *) 808 ecalloc(1, sizeof(struct hilite)); 809 hl->hl_startpos = linepos; 810 hl->hl_endpos = pos; 811 add_hilite(&filter_anchor, hl); 812 } 813 } 814 #endif 815 816 /* 817 * Test the next line to see if we have a match. 818 * We are successful if we either want a match and got one, 819 * or if we want a non-match and got one. 820 */ 821 if (prev_pattern(&search_info)) 822 { 823 line_match = match_pattern(search_info.compiled, search_info.text, 824 cline, line_len, &sp, &ep, 0, search_type); 825 if (line_match) 826 { 827 /* 828 * Got a match. 829 */ 830 if (search_type & SRCH_FIND_ALL) 831 { 832 #if HILITE_SEARCH 833 /* 834 * We are supposed to find all matches in the range. 835 * Just add the matches in this line to the 836 * hilite list and keep searching. 837 */ 838 hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops); 839 #endif 840 } else if (--matches <= 0) 841 { 842 /* 843 * Found the one match we're looking for. 844 * Return it. 845 */ 846 #if HILITE_SEARCH 847 if (hilite_search == OPT_ON) 848 { 849 /* 850 * Clear the hilite list and add only 851 * the matches in this one line. 852 */ 853 clr_hilite(); 854 hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops); 855 } 856 #endif 857 free(cline); 858 free(chpos); 859 if (plinepos != NULL) 860 *plinepos = linepos; 861 return (0); 862 } 863 } 864 } 865 free(cline); 866 free(chpos); 867 } 868 } 869 870 /* 871 * search for a pattern in history. If found, compile that pattern. 872 */ 873 static int 874 hist_pattern(search_type) 875 int search_type; 876 { 877 #if CMD_HISTORY 878 char *pattern; 879 880 set_mlist(ml_search, 0); 881 pattern = cmd_lastpattern(); 882 if (pattern == NULL) 883 return (0); 884 885 if (set_pattern(&search_info, pattern, search_type) < 0) 886 return (0); 887 888 #if HILITE_SEARCH 889 if (hilite_search == OPT_ONPLUS && !hide_hilite) 890 hilite_screen(); 891 #endif 892 893 return (1); 894 #else /* CMD_HISTORY */ 895 return (0); 896 #endif /* CMD_HISTORY */ 897 } 898 899 /* 900 * Search for the n-th occurrence of a specified pattern, 901 * either forward or backward. 902 * Return the number of matches not yet found in this file 903 * (that is, n minus the number of matches found). 904 * Return -1 if the search should be aborted. 905 * Caller may continue the search in another file 906 * if less than n matches are found in this file. 907 */ 908 public int 909 search(search_type, pattern, n) 910 int search_type; 911 char *pattern; 912 int n; 913 { 914 POSITION pos; 915 916 if (pattern == NULL || *pattern == '\0') 917 { 918 /* 919 * A null pattern means use the previously compiled pattern. 920 */ 921 search_type |= SRCH_AFTER_TARGET; 922 if (!prev_pattern(&search_info) && !hist_pattern(search_type)) 923 { 924 error("No previous regular expression", NULL_PARG); 925 return (-1); 926 } 927 if ((search_type & SRCH_NO_REGEX) != 928 (search_info.search_type & SRCH_NO_REGEX)) 929 { 930 error("Please re-enter search pattern", NULL_PARG); 931 return -1; 932 } 933 #if HILITE_SEARCH 934 if (hilite_search == OPT_ON) 935 { 936 /* 937 * Erase the highlights currently on screen. 938 * If the search fails, we'll redisplay them later. 939 */ 940 repaint_hilite(0); 941 } 942 if (hilite_search == OPT_ONPLUS && hide_hilite) 943 { 944 /* 945 * Highlight any matches currently on screen, 946 * before we actually start the search. 947 */ 948 hide_hilite = 0; 949 hilite_screen(); 950 } 951 hide_hilite = 0; 952 #endif 953 } else 954 { 955 /* 956 * Compile the pattern. 957 */ 958 if (set_pattern(&search_info, pattern, search_type) < 0) 959 return (-1); 960 #if HILITE_SEARCH 961 if (hilite_search) 962 { 963 /* 964 * Erase the highlights currently on screen. 965 * Also permanently delete them from the hilite list. 966 */ 967 repaint_hilite(0); 968 hide_hilite = 0; 969 clr_hilite(); 970 } 971 if (hilite_search == OPT_ONPLUS) 972 { 973 /* 974 * Highlight any matches currently on screen, 975 * before we actually start the search. 976 */ 977 hilite_screen(); 978 } 979 #endif 980 } 981 982 /* 983 * Figure out where to start the search. 984 */ 985 pos = search_pos(search_type); 986 if (pos == NULL_POSITION) 987 { 988 /* 989 * Can't find anyplace to start searching from. 990 */ 991 if (search_type & SRCH_PAST_EOF) 992 return (n); 993 /* repaint(); -- why was this here? */ 994 error("Nothing to search", NULL_PARG); 995 return (-1); 996 } 997 998 n = search_range(pos, NULL_POSITION, search_type, n, -1, 999 &pos, (POSITION*)NULL); 1000 if (n != 0) 1001 { 1002 /* 1003 * Search was unsuccessful. 1004 */ 1005 #if HILITE_SEARCH 1006 if (hilite_search == OPT_ON && n > 0) 1007 /* 1008 * Redisplay old hilites. 1009 */ 1010 repaint_hilite(1); 1011 #endif 1012 return (n); 1013 } 1014 1015 if (!(search_type & SRCH_NO_MOVE)) 1016 { 1017 /* 1018 * Go to the matching line. 1019 */ 1020 jump_loc(pos, jump_sline); 1021 } 1022 1023 #if HILITE_SEARCH 1024 if (hilite_search == OPT_ON) 1025 /* 1026 * Display new hilites in the matching line. 1027 */ 1028 repaint_hilite(1); 1029 #endif 1030 return (0); 1031 } 1032 1033 1034 #if HILITE_SEARCH 1035 /* 1036 * Prepare hilites in a given range of the file. 1037 * 1038 * The pair (prep_startpos,prep_endpos) delimits a contiguous region 1039 * of the file that has been "prepared"; that is, scanned for matches for 1040 * the current search pattern, and hilites have been created for such matches. 1041 * If prep_startpos == NULL_POSITION, the prep region is empty. 1042 * If prep_endpos == NULL_POSITION, the prep region extends to EOF. 1043 * prep_hilite asks that the range (spos,epos) be covered by the prep region. 1044 */ 1045 public void 1046 prep_hilite(spos, epos, maxlines) 1047 POSITION spos; 1048 POSITION epos; 1049 int maxlines; 1050 { 1051 POSITION nprep_startpos = prep_startpos; 1052 POSITION nprep_endpos = prep_endpos; 1053 POSITION new_epos; 1054 POSITION max_epos; 1055 int result; 1056 int i; 1057 1058 /* 1059 * Search beyond where we're asked to search, so the prep region covers 1060 * more than we need. Do one big search instead of a bunch of small ones. 1061 */ 1062 #define SEARCH_MORE (3*size_linebuf) 1063 1064 if (!prev_pattern(&search_info) && !is_filtering()) 1065 return; 1066 1067 /* 1068 * If we're limited to a max number of lines, figure out the 1069 * file position we should stop at. 1070 */ 1071 if (maxlines < 0) 1072 max_epos = NULL_POSITION; 1073 else 1074 { 1075 max_epos = spos; 1076 for (i = 0; i < maxlines; i++) 1077 max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); 1078 } 1079 1080 /* 1081 * Find two ranges: 1082 * The range that we need to search (spos,epos); and the range that 1083 * the "prep" region will then cover (nprep_startpos,nprep_endpos). 1084 */ 1085 1086 if (prep_startpos == NULL_POSITION || 1087 (epos != NULL_POSITION && epos < prep_startpos) || 1088 spos > prep_endpos) 1089 { 1090 /* 1091 * New range is not contiguous with old prep region. 1092 * Discard the old prep region and start a new one. 1093 */ 1094 clr_hilite(); 1095 clr_filter(); 1096 if (epos != NULL_POSITION) 1097 epos += SEARCH_MORE; 1098 nprep_startpos = spos; 1099 } else 1100 { 1101 /* 1102 * New range partially or completely overlaps old prep region. 1103 */ 1104 if (epos == NULL_POSITION) 1105 { 1106 /* 1107 * New range goes to end of file. 1108 */ 1109 ; 1110 } else if (epos > prep_endpos) 1111 { 1112 /* 1113 * New range ends after old prep region. 1114 * Extend prep region to end at end of new range. 1115 */ 1116 epos += SEARCH_MORE; 1117 } else /* (epos <= prep_endpos) */ 1118 { 1119 /* 1120 * New range ends within old prep region. 1121 * Truncate search to end at start of old prep region. 1122 */ 1123 epos = prep_startpos; 1124 } 1125 1126 if (spos < prep_startpos) 1127 { 1128 /* 1129 * New range starts before old prep region. 1130 * Extend old prep region backwards to start at 1131 * start of new range. 1132 */ 1133 if (spos < SEARCH_MORE) 1134 spos = 0; 1135 else 1136 spos -= SEARCH_MORE; 1137 nprep_startpos = spos; 1138 } else /* (spos >= prep_startpos) */ 1139 { 1140 /* 1141 * New range starts within or after old prep region. 1142 * Trim search to start at end of old prep region. 1143 */ 1144 spos = prep_endpos; 1145 } 1146 } 1147 1148 if (epos != NULL_POSITION && max_epos != NULL_POSITION && 1149 epos > max_epos) 1150 /* 1151 * Don't go past the max position we're allowed. 1152 */ 1153 epos = max_epos; 1154 1155 if (epos == NULL_POSITION || epos > spos) 1156 { 1157 int search_type = SRCH_FORW | SRCH_FIND_ALL; 1158 search_type |= (search_info.search_type & SRCH_NO_REGEX); 1159 result = search_range(spos, epos, search_type, 0, 1160 maxlines, (POSITION*)NULL, &new_epos); 1161 if (result < 0) 1162 return; 1163 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 1164 nprep_endpos = new_epos; 1165 } 1166 prep_startpos = nprep_startpos; 1167 prep_endpos = nprep_endpos; 1168 } 1169 1170 /* 1171 * Set the pattern to be used for line filtering. 1172 */ 1173 public void 1174 set_filter_pattern(pattern, search_type) 1175 char *pattern; 1176 int search_type; 1177 { 1178 clr_filter(); 1179 if (pattern == NULL || *pattern == '\0') 1180 clear_pattern(&filter_info); 1181 else 1182 set_pattern(&filter_info, pattern, search_type); 1183 screen_trashed = 1; 1184 } 1185 1186 /* 1187 * Is there a line filter in effect? 1188 */ 1189 public int 1190 is_filtering() 1191 { 1192 if (ch_getflags() & CH_HELPFILE) 1193 return (0); 1194 return prev_pattern(&filter_info); 1195 } 1196 #endif 1197 1198 #if HAVE_V8_REGCOMP 1199 /* 1200 * This function is called by the V8 regcomp to report 1201 * errors in regular expressions. 1202 */ 1203 void 1204 regerror(s) 1205 char *s; 1206 { 1207 PARG parg; 1208 1209 parg.p_string = s; 1210 error("%s", &parg); 1211 } 1212 #endif 1213 1214