search.c (191930) | search.c (195941) |
---|---|
1/* $FreeBSD: head/contrib/less/search.c 191930 2009-05-09 01:35:27Z delphij $ */ | 1/* $FreeBSD: head/contrib/less/search.c 195941 2009-07-29 09:20:32Z delphij $ */ |
2/* | 2/* |
3 * Copyright (C) 1984-2008 Mark Nudelman | 3 * Copyright (C) 1984-2009 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" | 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 "pattern.h" |
|
18#include "position.h" 19#include "charset.h" 20 21#define MINPOS(a,b) (((a) < (b)) ? (a) : (b)) 22#define MAXPOS(a,b) (((a) > (b)) ? (a) : (b)) 23 | 19#include "position.h" 20#include "charset.h" 21 22#define MINPOS(a,b) (((a) < (b)) ? (a) : (b)) 23#define MAXPOS(a,b) (((a) > (b)) ? (a) : (b)) 24 |
24#if HAVE_POSIX_REGCOMP 25#include <regex.h> 26#ifdef REG_EXTENDED 27#define REGCOMP_FLAG (less_is_more ? 0 : REG_EXTENDED) 28#else 29#define REGCOMP_FLAG 0 30#endif 31#endif 32#if HAVE_PCRE 33#include <pcre.h> 34#endif 35#if HAVE_RE_COMP 36char *re_comp(); 37int re_exec(); 38#endif 39#if HAVE_REGCMP 40char *regcmp(); 41char *regex(); 42extern char *__loc1; 43#endif 44#if HAVE_V8_REGCOMP 45#include "regexp.h" 46#endif 47 48static int match(); 49 | |
50extern int sigs; 51extern int how_search; 52extern int caseless; 53extern int linenums; 54extern int sc_height; 55extern int jump_sline; 56extern int bs_mode; 57extern int less_is_more; --- 5 unchanged lines hidden (view full) --- 63extern int utf_mode; 64extern int screen_trashed; 65#if HILITE_SEARCH 66extern int hilite_search; 67extern int size_linebuf; 68extern int squished; 69extern int can_goto_line; 70static int hide_hilite; | 25extern int sigs; 26extern int how_search; 27extern int caseless; 28extern int linenums; 29extern int sc_height; 30extern int jump_sline; 31extern int bs_mode; 32extern int less_is_more; --- 5 unchanged lines hidden (view full) --- 38extern int utf_mode; 39extern int screen_trashed; 40#if HILITE_SEARCH 41extern int hilite_search; 42extern int size_linebuf; 43extern int squished; 44extern int can_goto_line; 45static int hide_hilite; |
71static int oldbot; | |
72static POSITION prep_startpos; 73static POSITION prep_endpos; | 46static POSITION prep_startpos; 47static POSITION prep_endpos; |
48static int is_caseless; 49static int is_ucase_pattern; |
|
74 75struct hilite 76{ 77 struct hilite *hl_next; 78 POSITION hl_startpos; 79 POSITION hl_endpos; 80}; 81static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 82static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 83#define hl_first hl_next 84#endif 85 86/* 87 * These are the static variables that represent the "remembered" | 50 51struct hilite 52{ 53 struct hilite *hl_next; 54 POSITION hl_startpos; 55 POSITION hl_endpos; 56}; 57static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 58static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 59#define hl_first hl_next 60#endif 61 62/* 63 * These are the static variables that represent the "remembered" |
88 * search pattern. | 64 * search pattern and filter pattern. |
89 */ | 65 */ |
90#if HAVE_POSIX_REGCOMP 91#define DEFINE_PATTERN(name) static regex_t *name = NULL 92#endif 93#if HAVE_PCRE 94#define DEFINE_PATTERN(name) pcre *name = NULL; 95#endif 96#if HAVE_RE_COMP 97#define DEFINE_PATTERN(name) int name = 0; 98#endif 99#if HAVE_REGCMP 100#define DEFINE_PATTERN(name) static char *name = NULL; 101#endif 102#if HAVE_V8_REGCOMP 103#define DEFINE_PATTERN(name) static struct regexp *name = NULL; 104#endif | 66struct pattern_info { 67 DEFINE_PATTERN(compiled); 68 char* text; 69 int search_type; 70}; 71 72static struct pattern_info search_info; 73static struct pattern_info filter_info; |
105 | 74 |
106DEFINE_PATTERN(search_pattern); 107DEFINE_PATTERN(filter_pattern); 108 109static int is_caseless; 110static int is_ucase_pattern; 111static int last_search_type; 112static int last_filter_type; 113static char *last_pattern = NULL; 114 115#define CVT_TO_LC 01 /* Convert upper-case to lower-case */ 116#define CVT_BS 02 /* Do backspace processing */ 117#define CVT_CRLF 04 /* Remove CR after LF */ 118#define CVT_ANSI 010 /* Remove ANSI escape sequences */ 119 | |
120/* | 75/* |
121 * Get the length of a buffer needed to convert a string. | 76 * Compile and save a search pattern. |
122 */ 123 static int | 77 */ 78 static int |
124cvt_length(len, ops) 125 int len; 126 int ops; | 79set_pattern(info, pattern, search_type) 80 struct pattern_info *info; 81 char *pattern; 82 int search_type; |
127{ | 83{ |
128 if (utf_mode) 129 /* 130 * Just copying a string in UTF-8 mode can cause it to grow 131 * in length. 132 * Six output bytes for one input byte is the worst case 133 * (and unfortunately is far more than is needed in any 134 * non-pathological situation, so this is very wasteful). 135 */ 136 len *= 6; 137 return len + 1; | 84 if (pattern == NULL) 85 CLEAR_PATTERN(search_info.compiled); 86 else if (compile_pattern(pattern, search_type, &info->compiled) < 0) 87 return -1; 88 /* Pattern compiled successfully; save the text too. */ 89 if (info->text != NULL) 90 free(info->text); 91 info->text = NULL; 92 if (pattern != NULL) 93 { 94 info->text = (char *) ecalloc(1, strlen(pattern)+1); 95 strcpy(info->text, pattern); 96 } 97 info->search_type = search_type; 98 return 0; |
138} 139 140/* | 99} 100 101/* |
141 * Convert text. Perform the transformations specified by ops. | 102 * Discard a saved pattern. |
142 */ 143 static void | 103 */ 104 static void |
144cvt_text(odst, osrc, lenp, ops) 145 char *odst; 146 char *osrc; 147 int *lenp; 148 int ops; | 105clear_pattern(info) 106 struct pattern_info *info; |
149{ | 107{ |
150 char *dst; 151 char *src; 152 register char *src_end; 153 LWCHAR ch; | 108 if (info->text != NULL) 109 free(info->text); 110 info->text = NULL; 111 uncompile_pattern(&info->compiled); 112} |
154 | 113 |
155 if (lenp != NULL) 156 src_end = osrc + *lenp; 157 else 158 src_end = osrc + strlen(osrc); | 114/* 115 * Initialize saved pattern to nothing. 116 */ 117 static void 118init_pattern(info) 119 struct pattern_info *info; 120{ 121 CLEAR_PATTERN(info->compiled); 122 info->text = NULL; 123 info->search_type = 0; 124} |
159 | 125 |
160 for (src = osrc, dst = odst; src < src_end; ) 161 { 162 ch = step_char(&src, +1, src_end); 163 if ((ops & CVT_TO_LC) && IS_UPPER(ch)) 164 { 165 /* Convert uppercase to lowercase. */ 166 put_wchar(&dst, TO_LOWER(ch)); 167 } else if ((ops & CVT_BS) && ch == '\b' && dst > odst) 168 { 169 /* Delete backspace and preceding char. */ 170 do { 171 dst--; 172 } while (dst > odst && 173 !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst)); 174 } else if ((ops & CVT_ANSI) && IS_CSI_START(ch)) 175 { 176 /* Skip to end of ANSI escape sequence. */ 177 src++; /* skip the CSI start char */ 178 while (src < src_end) 179 if (!is_ansi_middle(*src++)) 180 break; 181 } else 182 /* Just copy. */ 183 put_wchar(&dst, ch); 184 } 185 if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r') 186 dst--; 187 *dst = '\0'; 188 if (lenp != NULL) 189 *lenp = dst - odst; | 126/* 127 * Initialize search variables. 128 */ 129 public void 130init_search() 131{ 132 init_pattern(&search_info); 133 init_pattern(&filter_info); |
190} 191 192/* | 134} 135 136/* |
193 * Determine which conversions to perform. | 137 * Determine which text conversions to perform before pattern matching. |
194 */ 195 static int 196get_cvt_ops() 197{ 198 int ops = 0; 199 if (is_caseless || bs_mode == BS_SPECIAL) 200 { 201 if (is_caseless) --- 29 unchanged lines hidden (view full) --- 231 } 232 return (0); 233} 234 235/* 236 * Is there a previous (remembered) search pattern? 237 */ 238 static int | 138 */ 139 static int 140get_cvt_ops() 141{ 142 int ops = 0; 143 if (is_caseless || bs_mode == BS_SPECIAL) 144 { 145 if (is_caseless) --- 29 unchanged lines hidden (view full) --- 175 } 176 return (0); 177} 178 179/* 180 * Is there a previous (remembered) search pattern? 181 */ 182 static int |
239prev_pattern() | 183prev_pattern(info) 184 struct pattern_info *info; |
240{ | 185{ |
241 if (last_search_type & SRCH_NO_REGEX) 242 return (last_pattern != NULL); 243#if HAVE_POSIX_REGCOMP 244 return (search_pattern != NULL); 245#endif 246#if HAVE_PCRE 247 return (search_pattern != NULL); 248#endif 249#if HAVE_RE_COMP 250 return (search_pattern != 0); 251#endif 252#if HAVE_REGCMP 253 return (search_pattern != NULL); 254#endif 255#if HAVE_V8_REGCOMP 256 return (search_pattern != NULL); 257#endif 258#if NO_REGEX 259 return (search_pattern != NULL); 260#endif | 186 if (info->search_type & SRCH_NO_REGEX) 187 return (info->text != NULL); 188 return (!is_null_pattern(info->compiled)); |
261} 262 263#if HILITE_SEARCH 264/* 265 * Repaint the hilites currently displayed on the screen. 266 * Repaint each line which contains highlighted text. 267 * If on==0, force all hilites off. 268 */ --- 25 unchanged lines hidden (view full) --- 294 } 295 296 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 297 { 298 pos = position(slinenum); 299 if (pos == NULL_POSITION) 300 continue; 301 epos = position(slinenum+1); | 189} 190 191#if HILITE_SEARCH 192/* 193 * Repaint the hilites currently displayed on the screen. 194 * Repaint each line which contains highlighted text. 195 * If on==0, force all hilites off. 196 */ --- 25 unchanged lines hidden (view full) --- 222 } 223 224 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 225 { 226 pos = position(slinenum); 227 if (pos == NULL_POSITION) 228 continue; 229 epos = position(slinenum+1); |
302#if 0 303 /* 304 * If any character in the line is highlighted, 305 * repaint the line. 306 * 307 * {{ This doesn't work -- if line is drawn with highlights 308 * which should be erased (e.g. toggle -i with status column), 309 * we must redraw the line even if it has no highlights. 310 * For now, just repaint every line. }} 311 */ 312 if (is_hilited(pos, epos, 1, NULL)) 313#endif 314 { 315 (void) forw_line(pos); 316 goto_line(slinenum); 317 put_line(); 318 } | 230 (void) forw_line(pos); 231 goto_line(slinenum); 232 put_line(); |
319 } | 233 } |
320 if (!oldbot) 321 lower_left(); | 234 lower_left(); // if !oldbot |
322 hide_hilite = save_hide_hilite; 323} 324 325/* 326 * Clear the attn hilite. 327 */ 328 public void 329clear_attn() --- 40 unchanged lines hidden (view full) --- 370#endif 371 372/* 373 * Hide search string highlighting. 374 */ 375 public void 376undo_search() 377{ | 235 hide_hilite = save_hide_hilite; 236} 237 238/* 239 * Clear the attn hilite. 240 */ 241 public void 242clear_attn() --- 40 unchanged lines hidden (view full) --- 283#endif 284 285/* 286 * Hide search string highlighting. 287 */ 288 public void 289undo_search() 290{ |
378 if (!prev_pattern()) | 291 if (!prev_pattern(&search_info)) |
379 { 380 error("No previous regular expression", NULL_PARG); 381 return; 382 } 383#if HILITE_SEARCH 384 hide_hilite = !hide_hilite; 385 repaint_hilite(1); 386#endif 387} 388 | 292 { 293 error("No previous regular expression", NULL_PARG); 294 return; 295 } 296#if HILITE_SEARCH 297 hide_hilite = !hide_hilite; 298 repaint_hilite(1); 299#endif 300} 301 |
389/* 390 * Compile a search pattern, for future use by match_pattern. 391 */ 392 static int 393compile_pattern2(pattern, search_type, comp_pattern) 394 char *pattern; 395 int search_type; 396 void **comp_pattern; 397{ 398 if ((search_type & SRCH_NO_REGEX) == 0) 399 { 400#if HAVE_POSIX_REGCOMP 401 regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t)); 402 regex_t **pcomp = (regex_t **) comp_pattern; 403 if (regcomp(comp, pattern, REGCOMP_FLAG)) 404 { 405 free(comp); 406 error("Invalid pattern", NULL_PARG); 407 return (-1); 408 } 409 if (*pcomp != NULL) 410 regfree(*pcomp); 411 *pcomp = comp; 412#endif 413#if HAVE_PCRE 414 pcre *comp; 415 pcre **pcomp = (pcre **) comp_pattern; 416 const char *errstring; 417 int erroffset; 418 PARG parg; 419 comp = pcre_compile(pattern, 0, 420 &errstring, &erroffset, NULL); 421 if (comp == NULL) 422 { 423 parg.p_string = (char *) errstring; 424 error("%s", &parg); 425 return (-1); 426 } 427 *pcomp = comp; 428#endif 429#if HAVE_RE_COMP 430 PARG parg; 431 int *pcomp = (int *) comp_pattern; 432 if ((parg.p_string = re_comp(pattern)) != NULL) 433 { 434 error("%s", &parg); 435 return (-1); 436 } 437 *pcomp = 1; 438#endif 439#if HAVE_REGCMP 440 char *comp; 441 char **pcomp = (char **) comp_pattern; 442 if ((comp = regcmp(pattern, 0)) == NULL) 443 { 444 error("Invalid pattern", NULL_PARG); 445 return (-1); 446 } 447 if (pcomp != NULL) 448 free(*pcomp); 449 *pcomp = comp; 450#endif 451#if HAVE_V8_REGCOMP 452 struct regexp *comp; 453 struct regexp **pcomp = (struct regexp **) comp_pattern; 454 if ((comp = regcomp(pattern)) == NULL) 455 { 456 /* 457 * regcomp has already printed an error message 458 * via regerror(). 459 */ 460 return (-1); 461 } 462 if (*pcomp != NULL) 463 free(*pcomp); 464 *pcomp = comp; 465#endif 466 } 467 468 if (comp_pattern == (void **) &search_pattern) 469 { 470 if (last_pattern != NULL) 471 free(last_pattern); 472 last_pattern = (char *) calloc(1, strlen(pattern)+1); 473 if (last_pattern != NULL) 474 strcpy(last_pattern, pattern); 475 last_search_type = search_type; 476 } else 477 { 478 last_filter_type = search_type; 479 } 480 return (0); 481} 482 483/* 484 * Like compile_pattern2, but convert the pattern to lowercase if necessary. 485 */ 486 static int 487compile_pattern(pattern, search_type, comp_pattern) 488 char *pattern; 489 int search_type; 490 void **comp_pattern; 491{ 492 char *cvt_pattern; 493 int result; 494 495 if (caseless != OPT_ONPLUS) 496 cvt_pattern = pattern; 497 else 498 { 499 cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC)); 500 cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC); 501 } 502 result = compile_pattern2(cvt_pattern, search_type, comp_pattern); 503 if (cvt_pattern != pattern) 504 free(cvt_pattern); 505 return (result); 506} 507 508/* 509 * Forget that we have a compiled pattern. 510 */ 511 static void 512uncompile_pattern(pattern) 513 void **pattern; 514{ 515#if HAVE_POSIX_REGCOMP 516 regex_t **pcomp = (regex_t **) pattern; 517 if (*pcomp != NULL) 518 regfree(*pcomp); 519 *pcomp = NULL; 520#endif 521#if HAVE_PCRE 522 pcre **pcomp = (pcre **) pattern; 523 if (*pcomp != NULL) 524 pcre_free(*pcomp); 525 *pcomp = NULL; 526#endif 527#if HAVE_RE_COMP 528 int *pcomp = (int *) pattern; 529 *pcomp = 0; 530#endif 531#if HAVE_REGCMP 532 char **pcomp = (char **) pattern; 533 if (*pcomp != NULL) 534 free(*pcomp); 535 *pcomp = NULL; 536#endif 537#if HAVE_V8_REGCOMP 538 struct regexp **pcomp = (struct regexp **) pattern; 539 if (*pcomp != NULL) 540 free(*pcomp); 541 *pcomp = NULL; 542#endif 543} 544 545 static void 546uncompile_search_pattern() 547{ 548 uncompile_pattern(&search_pattern); 549 last_pattern = NULL; 550} 551 552 static void 553uncompile_filter_pattern() 554{ 555 uncompile_pattern(&filter_pattern); 556} 557 558/* 559 * Is a compiled pattern null? 560 */ 561 static int 562is_null_pattern(pattern) 563 void *pattern; 564{ 565#if HAVE_POSIX_REGCOMP 566 return (pattern == NULL); 567#endif 568#if HAVE_PCRE 569 return (pattern == NULL); 570#endif 571#if HAVE_RE_COMP 572 return (pattern == 0); 573#endif 574#if HAVE_REGCMP 575 return (pattern == NULL); 576#endif 577#if HAVE_V8_REGCOMP 578 return (pattern == NULL); 579#endif 580} 581 582/* 583 * Perform a pattern match with the previously compiled pattern. 584 * Set sp and ep to the start and end of the matched string. 585 */ 586 static int 587match_pattern(pattern, line, line_len, sp, ep, notbol, search_type) 588 void *pattern; 589 char *line; 590 int line_len; 591 char **sp; 592 char **ep; 593 int notbol; 594 int search_type; 595{ 596 int matched; 597#if HAVE_POSIX_REGCOMP 598 regex_t *spattern = (regex_t *) pattern; 599#endif 600#if HAVE_PCRE 601 pcre *spattern = (pcre *) pattern; 602#endif 603#if HAVE_RE_COMP 604 int spattern = (int) pattern; 605#endif 606#if HAVE_REGCMP 607 char *spattern = (char *) pattern; 608#endif 609#if HAVE_V8_REGCOMP 610 struct regexp *spattern = (struct regexp *) pattern; 611#endif 612 613 if (search_type & SRCH_NO_REGEX) 614 return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep)); 615 616#if HAVE_POSIX_REGCOMP 617 { 618 regmatch_t rm; 619 int flags = (notbol) ? REG_NOTBOL : 0; 620 matched = !regexec(spattern, line, 1, &rm, flags); 621 if (matched) 622 { 623#ifndef __WATCOMC__ 624 *sp = line + rm.rm_so; 625 *ep = line + rm.rm_eo; 626#else 627 *sp = rm.rm_sp; 628 *ep = rm.rm_ep; 629#endif 630 } 631 } 632#endif 633#if HAVE_PCRE 634 { 635 int flags = (notbol) ? PCRE_NOTBOL : 0; 636 int ovector[3]; 637 matched = pcre_exec(spattern, NULL, line, line_len, 638 0, flags, ovector, 3) >= 0; 639 if (matched) 640 { 641 *sp = line + ovector[0]; 642 *ep = line + ovector[1]; 643 } 644 } 645#endif 646#if HAVE_RE_COMP 647 matched = (re_exec(line) == 1); 648 /* 649 * re_exec doesn't seem to provide a way to get the matched string. 650 */ 651 *sp = *ep = NULL; 652#endif 653#if HAVE_REGCMP 654 *ep = regex(spattern, line); 655 matched = (*ep != NULL); 656 if (matched) 657 *sp = __loc1; 658#endif 659#if HAVE_V8_REGCOMP 660#if HAVE_REGEXEC2 661 matched = regexec2(spattern, line, notbol); 662#else 663 matched = regexec(spattern, line); 664#endif 665 if (matched) 666 { 667 *sp = spattern->startp[0]; 668 *ep = spattern->endp[0]; 669 } 670#endif 671#if NO_REGEX 672 matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep); 673#endif 674 matched = (!(search_type & SRCH_NO_MATCH) && matched) || 675 ((search_type & SRCH_NO_MATCH) && !matched); 676 return (matched); 677} 678 | |
679#if HILITE_SEARCH 680/* 681 * Clear the hilite list. 682 */ 683 public void 684clr_hlist(anchor) 685 struct hilite *anchor; 686{ --- 153 unchanged lines hidden (view full) --- 840 free(hl); 841 return; 842 } 843 hl->hl_next = ihl->hl_next; 844 ihl->hl_next = hl; 845} 846 847/* | 302#if HILITE_SEARCH 303/* 304 * Clear the hilite list. 305 */ 306 public void 307clr_hlist(anchor) 308 struct hilite *anchor; 309{ --- 153 unchanged lines hidden (view full) --- 463 free(hl); 464 return; 465 } 466 hl->hl_next = ihl->hl_next; 467 ihl->hl_next = hl; 468} 469 470/* |
848 * Adjust hl_startpos & hl_endpos to account for processing by cvt_text. 849 */ 850 static void 851adj_hilite(anchor, linepos, cvt_ops) 852 struct hilite *anchor; 853 POSITION linepos; 854 int cvt_ops; 855{ 856 char *line; 857 char *oline; 858 int line_len; 859 char *line_end; 860 struct hilite *hl; 861 int checkstart; 862 POSITION opos; 863 POSITION npos; 864 POSITION hl_opos; 865 POSITION hl_npos; 866 LWCHAR ch; 867 int ncwidth; 868 869 /* 870 * The line was already scanned and hilites were added (in hilite_line). 871 * But it was assumed that each char position in the line 872 * correponds to one char position in the file. 873 * This may not be true if cvt_text modified the line. 874 * Get the raw line again. Look at each character. 875 */ 876 (void) forw_raw_line(linepos, &line, &line_len); 877 line_end = line + line_len; 878 opos = npos = linepos; 879 hl = anchor->hl_first; 880 if (hl == NULL) 881 return; 882 hl_opos = hl_npos = hl->hl_startpos; 883 checkstart = TRUE; 884 885 while (hl != NULL && line < line_end) 886 { 887 /* 888 * See if we need to adjust the current hl_startpos or 889 * hl_endpos. After adjusting startpos[i], move to endpos[i]. 890 * After adjusting endpos[i], move to startpos[i+1]. 891 * The hilite list must be sorted thus: 892 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc. 893 */ 894 oline = line; 895 ch = step_char(&line, +1, line_end); 896 ncwidth = line - oline; 897 npos += ncwidth; 898 899 /* Figure out how this char was processed by cvt_text. */ 900 if ((cvt_ops & CVT_BS) && ch == '\b') 901 { 902 /* Skip the backspace and the following char. */ 903 oline = line; 904 ch = step_char(&line, +1, line_end); 905 ncwidth = line - oline; 906 npos += ncwidth; 907 } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch)) 908 { 909 /* Converted uppercase to lower. 910 * Note that this may have changed the number of bytes 911 * that the character occupies. */ 912 char dbuf[6]; 913 char *dst = dbuf; 914 put_wchar(&dst, TO_LOWER(ch)); 915 opos += dst - dbuf; 916 } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch)) 917 { 918 /* Skip to end of ANSI escape sequence. */ 919 line++; /* skip the CSI start char */ 920 npos++; 921 while (line < line_end) 922 { 923 npos++; 924 if (!is_ansi_middle(*line++)) 925 break; 926 } 927 } else 928 { 929 /* Ordinary unprocessed character. */ 930 opos += ncwidth; 931 } 932 933 if (opos == hl_opos) { 934 /* Adjust highlight position. */ 935 hl_npos = npos; 936 } 937 if (opos > hl_opos) 938 { 939 /* 940 * We've moved past the highlight position; store the 941 * adjusted highlight position and move to the next highlight. 942 */ 943 if (checkstart) 944 { 945 hl->hl_startpos = hl_npos; 946 hl_opos = hl->hl_endpos; 947 checkstart = FALSE; 948 } else 949 { 950 hl->hl_endpos = hl_npos; 951 hl = hl->hl_next; 952 if (hl != NULL) 953 hl_opos = hl->hl_startpos; 954 checkstart = TRUE; 955 } 956 hl_npos = npos; 957 } 958 } 959} 960 961/* | |
962 * Make a hilite for each string in a physical line which matches 963 * the current pattern. 964 * sp,ep delimit the first match already found. 965 */ 966 static void | 471 * Make a hilite for each string in a physical line which matches 472 * the current pattern. 473 * sp,ep delimit the first match already found. 474 */ 475 static void |
967hilite_line(linepos, line, line_len, sp, ep, cvt_ops) | 476hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops) |
968 POSITION linepos; 969 char *line; 970 int line_len; | 477 POSITION linepos; 478 char *line; 479 int line_len; |
480 int *chpos; |
|
971 char *sp; 972 char *ep; 973 int cvt_ops; 974{ 975 char *searchp; 976 char *line_end = line + line_len; 977 struct hilite *hl; | 481 char *sp; 482 char *ep; 483 int cvt_ops; 484{ 485 char *searchp; 486 char *line_end = line + line_len; 487 struct hilite *hl; |
978 struct hilite hilites; | |
979 980 if (sp == NULL || ep == NULL) 981 return; 982 /* 983 * sp and ep delimit the first match in the line. 984 * Mark the corresponding file positions, then 985 * look for further matches and mark them. 986 * {{ This technique, of calling match_pattern on subsequent 987 * substrings of the line, may mark more than is correct 988 * if the pattern starts with "^". This bug is fixed 989 * for those regex functions that accept a notbol parameter 990 * (currently POSIX, PCRE and V8-with-regexec2). }} 991 */ 992 searchp = line; | 488 489 if (sp == NULL || ep == NULL) 490 return; 491 /* 492 * sp and ep delimit the first match in the line. 493 * Mark the corresponding file positions, then 494 * look for further matches and mark them. 495 * {{ This technique, of calling match_pattern on subsequent 496 * substrings of the line, may mark more than is correct 497 * if the pattern starts with "^". This bug is fixed 498 * for those regex functions that accept a notbol parameter 499 * (currently POSIX, PCRE and V8-with-regexec2). }} 500 */ 501 searchp = line; |
993 /* 994 * Put the hilites into a temporary list until they're adjusted. 995 */ 996 hilites.hl_first = NULL; | |
997 do { 998 if (ep > sp) 999 { | 502 do { 503 if (ep > sp) 504 { |
1000 /* 1001 * Assume that each char position in the "line" 1002 * buffer corresponds to one char position in the file. 1003 * This is not quite true; we need to adjust later. 1004 */ | |
1005 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); | 505 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); |
1006 hl->hl_startpos = linepos + (sp-line); 1007 hl->hl_endpos = linepos + (ep-line); 1008 add_hilite(&hilites, hl); | 506 hl->hl_startpos = linepos + chpos[sp-line]; 507 hl->hl_endpos = linepos + chpos[ep-line]; 508 add_hilite(&hilite_anchor, hl); |
1009 } 1010 /* 1011 * If we matched more than zero characters, 1012 * move to the first char after the string we matched. 1013 * If we matched zero, just move to the next char. 1014 */ 1015 if (ep > searchp) 1016 searchp = ep; 1017 else if (searchp != line_end) 1018 searchp++; 1019 else /* end of line */ 1020 break; | 509 } 510 /* 511 * If we matched more than zero characters, 512 * move to the first char after the string we matched. 513 * If we matched zero, just move to the next char. 514 */ 515 if (ep > searchp) 516 searchp = ep; 517 else if (searchp != line_end) 518 searchp++; 519 else /* end of line */ 520 break; |
1021 } while (match_pattern(search_pattern, searchp, line_end - searchp, &sp, &ep, 1, last_search_type)); 1022 1023 /* 1024 * If there were backspaces in the original line, they 1025 * were removed, and hl_startpos/hl_endpos are not correct. 1026 * {{ This is very ugly. }} 1027 */ 1028 adj_hilite(&hilites, linepos, cvt_ops); 1029 1030 /* 1031 * Now put the hilites into the real list. 1032 */ 1033 while ((hl = hilites.hl_next) != NULL) 1034 { 1035 hilites.hl_next = hl->hl_next; 1036 add_hilite(&hilite_anchor, hl); 1037 } | 521 } while (match_pattern(search_info.compiled, search_info.text, 522 searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type)); |
1038} 1039#endif 1040 1041/* 1042 * Change the caseless-ness of searches. 1043 * Updates the internal search state to reflect a change in the -i flag. 1044 */ 1045 public void --- 5 unchanged lines hidden (view full) --- 1051 * Just set the search caselessness to the global caselessness. 1052 */ 1053 is_caseless = caseless; 1054 else 1055 /* 1056 * Pattern did have uppercase. 1057 * Discard the pattern; we can't change search caselessness now. 1058 */ | 523} 524#endif 525 526/* 527 * Change the caseless-ness of searches. 528 * Updates the internal search state to reflect a change in the -i flag. 529 */ 530 public void --- 5 unchanged lines hidden (view full) --- 536 * Just set the search caselessness to the global caselessness. 537 */ 538 is_caseless = caseless; 539 else 540 /* 541 * Pattern did have uppercase. 542 * Discard the pattern; we can't change search caselessness now. 543 */ |
1059 uncompile_search_pattern(); | 544 clear_pattern(&search_info); |
1060} 1061 1062#if HILITE_SEARCH 1063/* 1064 * Find matching text which is currently on screen and highlight it. 1065 */ 1066 static void 1067hilite_screen() --- 116 unchanged lines hidden (view full) --- 1184{ 1185 char *line; 1186 char *cline; 1187 int line_len; 1188 LINENUM linenum; 1189 char *sp, *ep; 1190 int line_match; 1191 int cvt_ops; | 545} 546 547#if HILITE_SEARCH 548/* 549 * Find matching text which is currently on screen and highlight it. 550 */ 551 static void 552hilite_screen() --- 116 unchanged lines hidden (view full) --- 669{ 670 char *line; 671 char *cline; 672 int line_len; 673 LINENUM linenum; 674 char *sp, *ep; 675 int line_match; 676 int cvt_ops; |
677 int cvt_len; 678 int *chpos; |
|
1192 POSITION linepos, oldpos; 1193 1194 linenum = find_linenum(pos); 1195 oldpos = pos; 1196 for (;;) 1197 { 1198 /* 1199 * Get lines until we find a matching one or until --- 55 unchanged lines hidden (view full) --- 1255 /* 1256 * If we're using line numbers, we might as well 1257 * remember the information we have now (the position 1258 * and line number of the current line). 1259 * Don't do it for every line because it slows down 1260 * the search. Remember the line number only if 1261 * we're "far" from the last place we remembered it. 1262 */ | 679 POSITION linepos, oldpos; 680 681 linenum = find_linenum(pos); 682 oldpos = pos; 683 for (;;) 684 { 685 /* 686 * Get lines until we find a matching one or until --- 55 unchanged lines hidden (view full) --- 742 /* 743 * If we're using line numbers, we might as well 744 * remember the information we have now (the position 745 * and line number of the current line). 746 * Don't do it for every line because it slows down 747 * the search. Remember the line number only if 748 * we're "far" from the last place we remembered it. 749 */ |
1263 if (linenums && abs((int)(pos - oldpos)) > 1024) | 750 if (linenums && abs((int)(pos - oldpos)) > 2048) |
1264 add_lnum(linenum, pos); 1265 oldpos = pos; 1266 1267 if (is_filtered(linepos)) 1268 continue; 1269 1270 /* 1271 * If it's a caseless search, convert the line to lowercase. 1272 * If we're doing backspace processing, delete backspaces. 1273 */ 1274 cvt_ops = get_cvt_ops(); | 751 add_lnum(linenum, pos); 752 oldpos = pos; 753 754 if (is_filtered(linepos)) 755 continue; 756 757 /* 758 * If it's a caseless search, convert the line to lowercase. 759 * If we're doing backspace processing, delete backspaces. 760 */ 761 cvt_ops = get_cvt_ops(); |
1275 cline = calloc(1, cvt_length(line_len, cvt_ops)); 1276 cvt_text(cline, line, &line_len, cvt_ops); | 762 cvt_len = cvt_length(line_len, cvt_ops); 763 cline = (char *) ecalloc(1, cvt_len); 764 chpos = cvt_alloc_chpos(cvt_len); 765 cvt_text(cline, line, chpos, &line_len, cvt_ops); |
1277 1278#if HILITE_SEARCH 1279 /* 1280 * Check to see if the line matches the filter pattern. 1281 * If so, add an entry to the filter list. 1282 */ | 766 767#if HILITE_SEARCH 768 /* 769 * Check to see if the line matches the filter pattern. 770 * If so, add an entry to the filter list. 771 */ |
1283 if ((search_type & SRCH_FIND_ALL) && 1284 !is_null_pattern(filter_pattern)) 1285 { 1286 int line_filter = match_pattern(filter_pattern, 1287 cline, line_len, &sp, &ep, 0, last_filter_type); | 772 if ((search_type & SRCH_FIND_ALL) && prev_pattern(&filter_info)) { 773 int line_filter = match_pattern(filter_info.compiled, filter_info.text, 774 cline, line_len, &sp, &ep, 0, filter_info.search_type); |
1288 if (line_filter) 1289 { 1290 struct hilite *hl = (struct hilite *) 1291 ecalloc(1, sizeof(struct hilite)); 1292 hl->hl_startpos = linepos; 1293 hl->hl_endpos = pos; 1294 add_hilite(&filter_anchor, hl); 1295 } 1296 } 1297#endif 1298 1299 /* 1300 * Test the next line to see if we have a match. 1301 * We are successful if we either want a match and got one, 1302 * or if we want a non-match and got one. 1303 */ | 775 if (line_filter) 776 { 777 struct hilite *hl = (struct hilite *) 778 ecalloc(1, sizeof(struct hilite)); 779 hl->hl_startpos = linepos; 780 hl->hl_endpos = pos; 781 add_hilite(&filter_anchor, hl); 782 } 783 } 784#endif 785 786 /* 787 * Test the next line to see if we have a match. 788 * We are successful if we either want a match and got one, 789 * or if we want a non-match and got one. 790 */ |
1304 if (!is_null_pattern(search_pattern)) | 791 if (prev_pattern(&search_info)) |
1305 { | 792 { |
1306 line_match = match_pattern(search_pattern, 1307 cline, line_len, &sp, &ep, 0, search_type); | 793 line_match = match_pattern(search_info.compiled, search_info.text, 794 cline, line_len, &sp, &ep, 0, search_type); //FIXME search_info.search_type |
1308 if (line_match) 1309 { 1310 /* 1311 * Got a match. 1312 */ 1313 if (search_type & SRCH_FIND_ALL) 1314 { 1315#if HILITE_SEARCH 1316 /* 1317 * We are supposed to find all matches in the range. 1318 * Just add the matches in this line to the 1319 * hilite list and keep searching. 1320 */ | 795 if (line_match) 796 { 797 /* 798 * Got a match. 799 */ 800 if (search_type & SRCH_FIND_ALL) 801 { 802#if HILITE_SEARCH 803 /* 804 * We are supposed to find all matches in the range. 805 * Just add the matches in this line to the 806 * hilite list and keep searching. 807 */ |
1321 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops); | 808 hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops); |
1322#endif 1323 } else if (--matches <= 0) 1324 { 1325 /* 1326 * Found the one match we're looking for. 1327 * Return it. 1328 */ 1329#if HILITE_SEARCH 1330 if (hilite_search == OPT_ON) 1331 { 1332 /* 1333 * Clear the hilite list and add only 1334 * the matches in this one line. 1335 */ 1336 clr_hilite(); | 809#endif 810 } else if (--matches <= 0) 811 { 812 /* 813 * Found the one match we're looking for. 814 * Return it. 815 */ 816#if HILITE_SEARCH 817 if (hilite_search == OPT_ON) 818 { 819 /* 820 * Clear the hilite list and add only 821 * the matches in this one line. 822 */ 823 clr_hilite(); |
1337 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops); | 824 hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops); |
1338 } 1339#endif 1340 free(cline); | 825 } 826#endif 827 free(cline); |
828 free(chpos); |
|
1341 if (plinepos != NULL) 1342 *plinepos = linepos; 1343 return (0); 1344 } 1345 } 1346 } 1347 free(cline); | 829 if (plinepos != NULL) 830 *plinepos = linepos; 831 return (0); 832 } 833 } 834 } 835 free(cline); |
836 free(chpos); |
|
1348 } 1349} 1350 1351/* 1352 * search for a pattern in history. If found, compile that pattern. 1353 */ 1354 static int 1355hist_pattern(search_type) 1356 int search_type; 1357{ 1358#if CMD_HISTORY 1359 char *pattern; 1360 1361 set_mlist(ml_search, 0); 1362 pattern = cmd_lastpattern(); 1363 if (pattern == NULL) 1364 return (0); 1365 | 837 } 838} 839 840/* 841 * search for a pattern in history. If found, compile that pattern. 842 */ 843 static int 844hist_pattern(search_type) 845 int search_type; 846{ 847#if CMD_HISTORY 848 char *pattern; 849 850 set_mlist(ml_search, 0); 851 pattern = cmd_lastpattern(); 852 if (pattern == NULL) 853 return (0); 854 |
1366 if (compile_pattern(pattern, search_type, &search_pattern) < 0) | 855 if (set_pattern(&search_info, pattern, search_type) < 0) |
1367 return (0); 1368 1369 is_ucase_pattern = is_ucase(pattern); 1370 if (is_ucase_pattern && caseless != OPT_ONPLUS) 1371 is_caseless = 0; 1372 else 1373 is_caseless = caseless; 1374 --- 25 unchanged lines hidden (view full) --- 1400{ 1401 POSITION pos; 1402 1403 if (pattern == NULL || *pattern == '\0') 1404 { 1405 /* 1406 * A null pattern means use the previously compiled pattern. 1407 */ | 856 return (0); 857 858 is_ucase_pattern = is_ucase(pattern); 859 if (is_ucase_pattern && caseless != OPT_ONPLUS) 860 is_caseless = 0; 861 else 862 is_caseless = caseless; 863 --- 25 unchanged lines hidden (view full) --- 889{ 890 POSITION pos; 891 892 if (pattern == NULL || *pattern == '\0') 893 { 894 /* 895 * A null pattern means use the previously compiled pattern. 896 */ |
1408 if (!prev_pattern() && !hist_pattern(search_type)) | 897 if (!prev_pattern(&search_info) && !hist_pattern(search_type)) |
1409 { 1410 error("No previous regular expression", NULL_PARG); 1411 return (-1); 1412 } 1413 if ((search_type & SRCH_NO_REGEX) != | 898 { 899 error("No previous regular expression", NULL_PARG); 900 return (-1); 901 } 902 if ((search_type & SRCH_NO_REGEX) != |
1414 (last_search_type & SRCH_NO_REGEX)) | 903 (search_info.search_type & SRCH_NO_REGEX)) |
1415 { 1416 error("Please re-enter search pattern", NULL_PARG); 1417 return -1; 1418 } 1419#if HILITE_SEARCH 1420 if (hilite_search == OPT_ON) 1421 { 1422 /* --- 13 unchanged lines hidden (view full) --- 1436 } 1437 hide_hilite = 0; 1438#endif 1439 } else 1440 { 1441 /* 1442 * Compile the pattern. 1443 */ | 904 { 905 error("Please re-enter search pattern", NULL_PARG); 906 return -1; 907 } 908#if HILITE_SEARCH 909 if (hilite_search == OPT_ON) 910 { 911 /* --- 13 unchanged lines hidden (view full) --- 925 } 926 hide_hilite = 0; 927#endif 928 } else 929 { 930 /* 931 * Compile the pattern. 932 */ |
1444 if (compile_pattern(pattern, search_type, &search_pattern) < 0) | 933 if (set_pattern(&search_info, pattern, search_type) < 0) |
1445 return (-1); 1446 /* 1447 * Ignore case if -I is set OR 1448 * -i is set AND the pattern is all lowercase. 1449 */ 1450 is_ucase_pattern = is_ucase(pattern); 1451 if (is_ucase_pattern && caseless != OPT_ONPLUS) 1452 is_caseless = 0; --- 91 unchanged lines hidden (view full) --- 1544 int maxlines; 1545{ 1546 POSITION nprep_startpos = prep_startpos; 1547 POSITION nprep_endpos = prep_endpos; 1548 POSITION new_epos; 1549 POSITION max_epos; 1550 int result; 1551 int i; | 934 return (-1); 935 /* 936 * Ignore case if -I is set OR 937 * -i is set AND the pattern is all lowercase. 938 */ 939 is_ucase_pattern = is_ucase(pattern); 940 if (is_ucase_pattern && caseless != OPT_ONPLUS) 941 is_caseless = 0; --- 91 unchanged lines hidden (view full) --- 1033 int maxlines; 1034{ 1035 POSITION nprep_startpos = prep_startpos; 1036 POSITION nprep_endpos = prep_endpos; 1037 POSITION new_epos; 1038 POSITION max_epos; 1039 int result; 1040 int i; |
1041 |
|
1552/* 1553 * Search beyond where we're asked to search, so the prep region covers 1554 * more than we need. Do one big search instead of a bunch of small ones. 1555 */ 1556#define SEARCH_MORE (3*size_linebuf) 1557 | 1042/* 1043 * Search beyond where we're asked to search, so the prep region covers 1044 * more than we need. Do one big search instead of a bunch of small ones. 1045 */ 1046#define SEARCH_MORE (3*size_linebuf) 1047 |
1558 if (!prev_pattern() && !is_filtering()) | 1048 if (!prev_pattern(&search_info) && !is_filtering()) |
1559 return; 1560 1561 /* 1562 * If we're limited to a max number of lines, figure out the 1563 * file position we should stop at. 1564 */ 1565 if (maxlines < 0) 1566 max_epos = NULL_POSITION; --- 76 unchanged lines hidden (view full) --- 1643 epos > max_epos) 1644 /* 1645 * Don't go past the max position we're allowed. 1646 */ 1647 epos = max_epos; 1648 1649 if (epos == NULL_POSITION || epos > spos) 1650 { | 1049 return; 1050 1051 /* 1052 * If we're limited to a max number of lines, figure out the 1053 * file position we should stop at. 1054 */ 1055 if (maxlines < 0) 1056 max_epos = NULL_POSITION; --- 76 unchanged lines hidden (view full) --- 1133 epos > max_epos) 1134 /* 1135 * Don't go past the max position we're allowed. 1136 */ 1137 epos = max_epos; 1138 1139 if (epos == NULL_POSITION || epos > spos) 1140 { |
1651 result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, | 1141 int search_type = SRCH_FORW | SRCH_FIND_ALL; 1142 search_type |= (search_info.search_type & SRCH_NO_REGEX); 1143 result = search_range(spos, epos, search_type, 0, |
1652 maxlines, (POSITION*)NULL, &new_epos); 1653 if (result < 0) 1654 return; 1655 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 1656 nprep_endpos = new_epos; 1657 } 1658 prep_startpos = nprep_startpos; 1659 prep_endpos = nprep_endpos; --- 4 unchanged lines hidden (view full) --- 1664 */ 1665 public void 1666set_filter_pattern(pattern, search_type) 1667 char *pattern; 1668 int search_type; 1669{ 1670 clr_filter(); 1671 if (pattern == NULL || *pattern == '\0') | 1144 maxlines, (POSITION*)NULL, &new_epos); 1145 if (result < 0) 1146 return; 1147 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 1148 nprep_endpos = new_epos; 1149 } 1150 prep_startpos = nprep_startpos; 1151 prep_endpos = nprep_endpos; --- 4 unchanged lines hidden (view full) --- 1156 */ 1157 public void 1158set_filter_pattern(pattern, search_type) 1159 char *pattern; 1160 int search_type; 1161{ 1162 clr_filter(); 1163 if (pattern == NULL || *pattern == '\0') |
1672 uncompile_filter_pattern(); | 1164 clear_pattern(&filter_info); |
1673 else | 1165 else |
1674 compile_pattern(pattern, search_type, &filter_pattern); | 1166 set_pattern(&filter_info, pattern, search_type); |
1675 screen_trashed = 1; 1676} 1677 1678/* 1679 * Is there a line filter in effect? 1680 */ 1681 public int 1682is_filtering() 1683{ 1684 if (ch_getflags() & CH_HELPFILE) 1685 return (0); | 1167 screen_trashed = 1; 1168} 1169 1170/* 1171 * Is there a line filter in effect? 1172 */ 1173 public int 1174is_filtering() 1175{ 1176 if (ch_getflags() & CH_HELPFILE) 1177 return (0); |
1686 return !is_null_pattern(filter_pattern); | 1178 return prev_pattern(&filter_info); |
1687} 1688#endif 1689 | 1179} 1180#endif 1181 |
1690/* 1691 * Simple pattern matching function. 1692 * It supports no metacharacters like *, etc. 1693 */ 1694 static int 1695match(pattern, pattern_len, buf, buf_len, pfound, pend) 1696 char *pattern; 1697 int pattern_len; 1698 char *buf; 1699 int buf_len; 1700 char **pfound, **pend; 1701{ 1702 register char *pp, *lp; 1703 register char *pattern_end = pattern + pattern_len; 1704 register char *buf_end = buf + buf_len; 1705 1706 for ( ; buf < buf_end; buf++) 1707 { 1708 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) 1709 if (pp == pattern_end || lp == buf_end) 1710 break; 1711 if (pp == pattern_end) 1712 { 1713 if (pfound != NULL) 1714 *pfound = buf; 1715 if (pend != NULL) 1716 *pend = lp; 1717 return (1); 1718 } 1719 } 1720 return (0); 1721} 1722 | |
1723#if HAVE_V8_REGCOMP 1724/* 1725 * This function is called by the V8 regcomp to report 1726 * errors in regular expressions. 1727 */ 1728 void 1729regerror(s) 1730 char *s; 1731{ 1732 PARG parg; 1733 1734 parg.p_string = s; 1735 error("%s", &parg); 1736} 1737#endif 1738 | 1182#if HAVE_V8_REGCOMP 1183/* 1184 * This function is called by the V8 regcomp to report 1185 * errors in regular expressions. 1186 */ 1187 void 1188regerror(s) 1189 char *s; 1190{ 1191 PARG parg; 1192 1193 parg.p_string = s; 1194 error("%s", &parg); 1195} 1196#endif 1197 |