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