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