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