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