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