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