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