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