=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/less/search.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- src/usr.bin/less/search.c 2003/04/13 18:26:26 1.5 +++ src/usr.bin/less/search.c 2011/09/16 18:12:09 1.6 @@ -1,5 +1,5 @@ /* - * Copyright (C) 1984-2002 Mark Nudelman + * Copyright (C) 1984-2011 Mark Nudelman * * You may distribute under the terms of either the GNU General Public * License or the Less License, as specified in the README file. @@ -14,37 +14,13 @@ */ #include "less.h" +#include "pattern.h" #include "position.h" +#include "charset.h" #define MINPOS(a,b) (((a) < (b)) ? (a) : (b)) #define MAXPOS(a,b) (((a) > (b)) ? (a) : (b)) -#if HAVE_POSIX_REGCOMP -#include -#ifdef REG_EXTENDED -#define REGCOMP_FLAG REG_EXTENDED -#else -#define REGCOMP_FLAG 0 -#endif -#endif -#if HAVE_PCRE -#include -#endif -#if HAVE_RE_COMP -char *re_comp(); -int re_exec(); -#endif -#if HAVE_REGCMP -char *regcmp(); -char *regex(); -extern char *__loc1; -#endif -#if HAVE_V8_REGCOMP -#include "regexp.h" -#endif - -static int match(); - extern int sigs; extern int how_search; extern int caseless; @@ -54,17 +30,21 @@ extern int bs_mode; extern int ctldisp; extern int status_col; +extern void * constant ml_search; extern POSITION start_attnpos; extern POSITION end_attnpos; +extern int utf_mode; +extern int screen_trashed; #if HILITE_SEARCH extern int hilite_search; -extern int screen_trashed; extern int size_linebuf; extern int squished; extern int can_goto_line; static int hide_hilite; static POSITION prep_startpos; static POSITION prep_endpos; +static int is_caseless; +static int is_ucase_pattern; struct hilite { @@ -73,77 +53,113 @@ POSITION hl_endpos; }; static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; +static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION }; #define hl_first hl_next #endif /* * These are the static variables that represent the "remembered" - * search pattern. + * search pattern and filter pattern. */ -#if HAVE_POSIX_REGCOMP -static regex_t *regpattern = NULL; -#endif -#if HAVE_PCRE -pcre *regpattern = NULL; -#endif -#if HAVE_RE_COMP -int re_pattern = 0; -#endif -#if HAVE_REGCMP -static char *cpattern = NULL; -#endif -#if HAVE_V8_REGCOMP -static struct regexp *regpattern = NULL; -#endif +struct pattern_info { + DEFINE_PATTERN(compiled); + char* text; + int search_type; +}; + +static struct pattern_info search_info; +static struct pattern_info filter_info; -static int is_caseless; -static int is_ucase_pattern; -static int last_search_type; -static char *last_pattern = NULL; +/* + * Are there any uppercase letters in this string? + */ + static int +is_ucase(str) + char *str; +{ + char *str_end = str + strlen(str); + LWCHAR ch; + while (str < str_end) + { + ch = step_char(&str, +1, str_end); + if (IS_UPPER(ch)) + return (1); + } + return (0); +} + /* - * Convert text. Perform one or more of these transformations: + * Compile and save a search pattern. */ -#define CVT_TO_LC 01 /* Convert upper-case to lower-case */ -#define CVT_BS 02 /* Do backspace processing */ -#define CVT_CRLF 04 /* Remove CR after LF */ -#define CVT_ANSI 010 /* Remove ANSI escape sequences */ + static int +set_pattern(info, pattern, search_type) + struct pattern_info *info; + char *pattern; + int search_type; +{ + if (pattern == NULL) + CLEAR_PATTERN(search_info.compiled); + else if (compile_pattern(pattern, search_type, &info->compiled) < 0) + return -1; + /* Pattern compiled successfully; save the text too. */ + if (info->text != NULL) + free(info->text); + info->text = NULL; + if (pattern != NULL) + info->text = save(pattern); + info->search_type = search_type; + /* + * Ignore case if -I is set OR + * -i is set AND the pattern is all lowercase. + */ + is_ucase_pattern = is_ucase(pattern); + if (is_ucase_pattern && caseless != OPT_ONPLUS) + is_caseless = 0; + else + is_caseless = caseless; + return 0; +} + +/* + * Discard a saved pattern. + */ static void -cvt_text(odst, osrc, ops) - char *odst; - char *osrc; - int ops; +clear_pattern(info) + struct pattern_info *info; { - register char *dst; - register char *src; + if (info->text != NULL) + free(info->text); + info->text = NULL; + uncompile_pattern(&info->compiled); +} - for (src = osrc, dst = odst; *src != '\0'; src++) - { - if ((ops & CVT_TO_LC) && isupper((unsigned char) *src)) - /* Convert uppercase to lowercase. */ - *dst++ = tolower((unsigned char) *src); - else if ((ops & CVT_BS) && *src == '\b' && dst > odst) - /* Delete BS and preceding char. */ - dst--; - else if ((ops & CVT_ANSI) && *src == ESC) - { - /* Skip to end of ANSI escape sequence. */ - while (src[1] != '\0') - if (is_ansi_end(*++src)) - break; - } else - /* Just copy. */ - *dst++ = *src; - } - if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r') - dst--; - *dst = '\0'; +/* + * Initialize saved pattern to nothing. + */ + static void +init_pattern(info) + struct pattern_info *info; +{ + CLEAR_PATTERN(info->compiled); + info->text = NULL; + info->search_type = 0; } /* - * Determine which conversions to perform. + * Initialize search variables. */ + public void +init_search() +{ + init_pattern(&search_info); + init_pattern(&filter_info); +} + +/* + * Determine which text conversions to perform before pattern matching. + */ static int get_cvt_ops() { @@ -166,46 +182,15 @@ } /* - * Are there any uppercase letters in this string? - */ - static int -is_ucase(s) - char *s; -{ - register char *p; - - for (p = s; *p != '\0'; p++) - if (isupper((unsigned char) *p)) - return (1); - return (0); -} - -/* * Is there a previous (remembered) search pattern? */ static int -prev_pattern() +prev_pattern(info) + struct pattern_info *info; { - if (last_search_type & SRCH_NO_REGEX) - return (last_pattern != NULL); -#if HAVE_POSIX_REGCOMP - return (regpattern != NULL); -#endif -#if HAVE_PCRE - return (regpattern != NULL); -#endif -#if HAVE_RE_COMP - return (re_pattern != 0); -#endif -#if HAVE_REGCMP - return (cpattern != NULL); -#endif -#if HAVE_V8_REGCOMP - return (regpattern != NULL); -#endif -#if NO_REGEX - return (last_pattern != NULL); -#endif + if (info->search_type & SRCH_NO_REGEX) + return (info->text != NULL); + return (!is_null_pattern(info->compiled)); } #if HILITE_SEARCH @@ -247,17 +232,11 @@ if (pos == NULL_POSITION) continue; epos = position(slinenum+1); - /* - * If any character in the line is highlighted, - * repaint the line. - */ - if (is_hilited(pos, epos, 1)) - { - (void) forw_line(pos); - goto_line(slinenum); - put_line(); - } + (void) forw_line(pos); + goto_line(slinenum); + put_line(); } + lower_left(); hide_hilite = save_hide_hilite; } @@ -272,6 +251,7 @@ POSITION old_end_attnpos; POSITION pos; POSITION epos; + int moved = 0; if (start_attnpos == NULL_POSITION) return; @@ -299,8 +279,11 @@ (void) forw_line(pos); goto_line(slinenum); put_line(); + moved = 1; } } + if (moved) + lower_left(); } #endif @@ -310,7 +293,7 @@ public void undo_search() { - if (!prev_pattern()) + if (!prev_pattern(&search_info)) { error("No previous regular expression", NULL_PARG); return; @@ -321,211 +304,82 @@ #endif } +#if HILITE_SEARCH /* - * Compile a search pattern, for future use by match_pattern. + * Clear the hilite list. */ - static int -compile_pattern(pattern, search_type) - char *pattern; - int search_type; + public void +clr_hlist(anchor) + struct hilite *anchor; { - if ((search_type & SRCH_NO_REGEX) == 0) + struct hilite *hl; + struct hilite *nexthl; + + for (hl = anchor->hl_first; hl != NULL; hl = nexthl) { -#if HAVE_POSIX_REGCOMP - regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t)); - if (regcomp(s, pattern, REGCOMP_FLAG)) - { - free(s); - error("Invalid pattern", NULL_PARG); - return (-1); - } - if (regpattern != NULL) - regfree(regpattern); - regpattern = s; -#endif -#if HAVE_PCRE - pcre *comp; - const char *errstring; - int erroffset; - PARG parg; - comp = pcre_compile(pattern, 0, - &errstring, &erroffset, NULL); - if (comp == NULL) - { - parg.p_string = (char *) errstring; - error("%s", &parg); - return (-1); - } - regpattern = comp; -#endif -#if HAVE_RE_COMP - PARG parg; - if ((parg.p_string = re_comp(pattern)) != NULL) - { - error("%s", &parg); - return (-1); - } - re_pattern = 1; -#endif -#if HAVE_REGCMP - char *s; - if ((s = regcmp(pattern, 0)) == NULL) - { - error("Invalid pattern", NULL_PARG); - return (-1); - } - if (cpattern != NULL) - free(cpattern); - cpattern = s; -#endif -#if HAVE_V8_REGCOMP - struct regexp *s; - if ((s = regcomp(pattern)) == NULL) - { - /* - * regcomp has already printed an error message - * via regerror(). - */ - return (-1); - } - if (regpattern != NULL) - free(regpattern); - regpattern = s; -#endif + nexthl = hl->hl_next; + free((void*)hl); } + anchor->hl_first = NULL; + prep_startpos = prep_endpos = NULL_POSITION; +} - if (last_pattern != NULL) - free(last_pattern); - last_pattern = save(pattern); - - last_search_type = search_type; - return (0); + public void +clr_hilite() +{ + clr_hlist(&hilite_anchor); } -/* - * Forget that we have a compiled pattern. - */ - static void -uncompile_pattern() + public void +clr_filter() { -#if HAVE_POSIX_REGCOMP - if (regpattern != NULL) - regfree(regpattern); - regpattern = NULL; -#endif -#if HAVE_PCRE - if (regpattern != NULL) - pcre_free(regpattern); - regpattern = NULL; -#endif -#if HAVE_RE_COMP - re_pattern = 0; -#endif -#if HAVE_REGCMP - if (cpattern != NULL) - free(cpattern); - cpattern = NULL; -#endif -#if HAVE_V8_REGCOMP - if (regpattern != NULL) - free(regpattern); - regpattern = NULL; -#endif - last_pattern = NULL; + clr_hlist(&filter_anchor); } /* - * Perform a pattern match with the previously compiled pattern. - * Set sp and ep to the start and end of the matched string. + * Should any characters in a specified range be highlighted? */ static int -match_pattern(line, sp, ep, notbol) - char *line; - char **sp; - char **ep; - int notbol; +is_hilited_range(pos, epos) + POSITION pos; + POSITION epos; { - int matched; + struct hilite *hl; - if (last_search_type & SRCH_NO_REGEX) - return (match(last_pattern, line, sp, ep)); - -#if HAVE_POSIX_REGCOMP - { - regmatch_t rm; - int flags = (notbol) ? REG_NOTBOL : 0; - matched = !regexec(regpattern, line, 1, &rm, flags); - if (!matched) - return (0); -#ifndef __WATCOMC__ - *sp = line + rm.rm_so; - *ep = line + rm.rm_eo; -#else - *sp = rm.rm_sp; - *ep = rm.rm_ep; -#endif - } -#endif -#if HAVE_PCRE - { - int flags = (notbol) ? PCRE_NOTBOL : 0; - int ovector[3]; - matched = pcre_exec(regpattern, NULL, line, strlen(line), - 0, flags, ovector, 3) >= 0; - if (!matched) - return (0); - *sp = line + ovector[0]; - *ep = line + ovector[1]; - } -#endif -#if HAVE_RE_COMP - matched = (re_exec(line) == 1); /* - * re_exec doesn't seem to provide a way to get the matched string. + * Look at each highlight and see if any part of it falls in the range. */ - *sp = *ep = NULL; -#endif -#if HAVE_REGCMP - *ep = regex(cpattern, line); - matched = (*ep != NULL); - if (!matched) - return (0); - *sp = __loc1; -#endif -#if HAVE_V8_REGCOMP -#if HAVE_REGEXEC2 - matched = regexec2(regpattern, line, notbol); -#else - matched = regexec(regpattern, line); -#endif - if (!matched) - return (0); - *sp = regpattern->startp[0]; - *ep = regpattern->endp[0]; -#endif -#if NO_REGEX - matched = match(last_pattern, line, sp, ep); -#endif - return (matched); + for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) + { + if (hl->hl_endpos > pos && + (epos == NULL_POSITION || epos > hl->hl_startpos)) + return (1); + } + return (0); } -#if HILITE_SEARCH -/* - * Clear the hilite list. +/* + * Is a line "filtered" -- that is, should it be hidden? */ - public void -clr_hilite() + public int +is_filtered(pos) + POSITION pos; { struct hilite *hl; - struct hilite *nexthl; - for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl) + if (ch_getflags() & CH_HELPFILE) + return (0); + + /* + * Look at each filter and see if the start position + * equals the start position of the line. + */ + for (hl = filter_anchor.hl_first; hl != NULL; hl = hl->hl_next) { - nexthl = hl->hl_next; - free((void*)hl); + if (hl->hl_startpos == pos) + return (1); } - hilite_anchor.hl_first = NULL; - prep_startpos = prep_endpos = NULL_POSITION; + return (0); } /* @@ -533,13 +387,17 @@ * If nohide is nonzero, don't consider hide_hilite. */ public int -is_hilited(pos, epos, nohide) +is_hilited(pos, epos, nohide, p_matches) POSITION pos; POSITION epos; int nohide; + int *p_matches; { - struct hilite *hl; + int match; + if (p_matches != NULL) + *p_matches = 0; + if (!status_col && start_attnpos != NULL_POSITION && pos < end_attnpos && @@ -549,6 +407,16 @@ */ return (1); + match = is_hilited_range(pos, epos); + if (!match) + return (0); + + if (p_matches != NULL) + /* + * Report matches, even if we're hiding highlights. + */ + *p_matches = 1; + if (hilite_search == 0) /* * Not doing highlighting. @@ -561,16 +429,7 @@ */ return (0); - /* - * Look at each highlight and see if any part of it falls in the range. - */ - for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) - { - if (hl->hl_endpos > pos && - (epos == NULL_POSITION || epos > hl->hl_startpos)) - return (1); - } - return (0); + return (1); } /* @@ -614,107 +473,23 @@ } /* - * Adjust hl_startpos & hl_endpos to account for backspace processing. - */ - static void -adj_hilite(anchor, linepos, cvt_ops) - struct hilite *anchor; - POSITION linepos; - int cvt_ops; -{ - char *line; - struct hilite *hl; - int checkstart; - POSITION opos; - POSITION npos; - - /* - * The line was already scanned and hilites were added (in hilite_line). - * But it was assumed that each char position in the line - * correponds to one char position in the file. - * This may not be true if there are backspaces in the line. - * Get the raw line again. Look at each character. - */ - (void) forw_raw_line(linepos, &line); - opos = npos = linepos; - hl = anchor->hl_first; - checkstart = TRUE; - while (hl != NULL) - { - /* - * See if we need to adjust the current hl_startpos or - * hl_endpos. After adjusting startpos[i], move to endpos[i]. - * After adjusting endpos[i], move to startpos[i+1]. - * The hilite list must be sorted thus: - * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc. - */ - if (checkstart && hl->hl_startpos == opos) - { - hl->hl_startpos = npos; - checkstart = FALSE; - continue; /* {{ not really necessary }} */ - } else if (!checkstart && hl->hl_endpos == opos) - { - hl->hl_endpos = npos; - checkstart = TRUE; - hl = hl->hl_next; - continue; /* {{ necessary }} */ - } - if (*line == '\0') - break; - if (cvt_ops & CVT_ANSI) - { - while (line[0] == ESC) - { - /* - * Found an ESC. The file position moves - * forward past the entire ANSI escape sequence. - */ - line++; - npos++; - while (*line != '\0') - { - npos++; - if (is_ansi_end(*line++)) - break; - } - } - } - opos++; - npos++; - line++; - if (cvt_ops & CVT_BS) - { - while (line[0] == '\b' && line[1] != '\0') - { - /* - * Found a backspace. The file position moves - * forward by 2 relative to the processed line - * which was searched in hilite_line. - */ - npos += 2; - line += 2; - } - } - } -} - -/* * Make a hilite for each string in a physical line which matches * the current pattern. * sp,ep delimit the first match already found. */ static void -hilite_line(linepos, line, sp, ep, cvt_ops) +hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops) POSITION linepos; char *line; + int line_len; + int *chpos; char *sp; char *ep; int cvt_ops; { char *searchp; + char *line_end = line + line_len; struct hilite *hl; - struct hilite hilites; if (sp == NULL || ep == NULL) return; @@ -726,25 +501,16 @@ * substrings of the line, may mark more than is correct * if the pattern starts with "^". This bug is fixed * for those regex functions that accept a notbol parameter - * (currently POSIX and V8-with-regexec2). }} + * (currently POSIX, PCRE and V8-with-regexec2). }} */ searchp = line; - /* - * Put the hilites into a temporary list until they're adjusted. - */ - hilites.hl_first = NULL; do { if (ep > sp) { - /* - * Assume that each char position in the "line" - * buffer corresponds to one char position in the file. - * This is not quite true; we need to adjust later. - */ hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); - hl->hl_startpos = linepos + (sp-line); - hl->hl_endpos = linepos + (ep-line); - add_hilite(&hilites, hl); + hl->hl_startpos = linepos + chpos[sp-line]; + hl->hl_endpos = linepos + chpos[ep-line]; + add_hilite(&hilite_anchor, hl); } /* * If we matched more than zero characters, @@ -753,27 +519,12 @@ */ if (ep > searchp) searchp = ep; - else if (*searchp != '\0') + else if (searchp != line_end) searchp++; else /* end of line */ break; - } while (match_pattern(searchp, &sp, &ep, 1)); - - /* - * If there were backspaces in the original line, they - * were removed, and hl_startpos/hl_endpos are not correct. - * {{ This is very ugly. }} - */ - adj_hilite(&hilites, linepos, cvt_ops); - - /* - * Now put the hilites into the real list. - */ - while ((hl = hilites.hl_next) != NULL) - { - hilites.hl_next = hl->hl_next; - add_hilite(&hilite_anchor, hl); - } + } while (match_pattern(search_info.compiled, search_info.text, + searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type)); } #endif @@ -795,7 +546,7 @@ * Pattern did have uppercase. * Discard the pattern; we can't change search caselessness now. */ - uncompile_pattern(); + clear_pattern(&search_info); } #if HILITE_SEARCH @@ -855,7 +606,7 @@ */ if (search_type & SRCH_FORW) { - return (ch_zero()); + pos = ch_zero(); } else { pos = ch_length(); @@ -864,47 +615,67 @@ (void) ch_end_seek(); pos = ch_length(); } - return (pos); } - } - if (how_search) + linenum = 0; + } else { - /* - * Search does not include current screen. - */ - if (search_type & SRCH_FORW) - linenum = BOTTOM_PLUS_ONE; - else - linenum = TOP; - pos = position(linenum); - } else - { - /* - * Search includes current screen. - * It starts at the jump target (if searching backwards), - * or at the jump target plus one (if forwards). - */ - linenum = adjsline(jump_sline); - pos = position(linenum); - if (search_type & SRCH_FORW) + int add_one = 0; + + if (how_search == OPT_ON) { - pos = forw_raw_line(pos, (char **)NULL); - while (pos == NULL_POSITION) - { - if (++linenum >= sc_height) - break; - pos = position(linenum); - } + /* + * Search does not include current screen. + */ + if (search_type & SRCH_FORW) + linenum = BOTTOM_PLUS_ONE; + else + linenum = TOP; + } else if (how_search == OPT_ONPLUS && !(search_type & SRCH_AFTER_TARGET)) + { + /* + * Search includes all of displayed screen. + */ + if (search_type & SRCH_FORW) + linenum = TOP; + else + linenum = BOTTOM_PLUS_ONE; } else { - while (pos == NULL_POSITION) - { - if (--linenum < 0) - break; - pos = position(linenum); - } + /* + * Search includes the part of current screen beyond the jump target. + * It starts at the jump target (if searching backwards), + * or at the jump target plus one (if forwards). + */ + linenum = jump_sline; + if (search_type & SRCH_FORW) + add_one = 1; } + linenum = adjsline(linenum); + pos = position(linenum); + if (add_one) + pos = forw_raw_line(pos, (char **)NULL, (int *)NULL); } + + /* + * If the line is empty, look around for a plausible starting place. + */ + if (search_type & SRCH_FORW) + { + while (pos == NULL_POSITION) + { + if (++linenum >= sc_height) + break; + pos = position(linenum); + } + } else + { + while (pos == NULL_POSITION) + { + if (--linenum < 0) + break; + pos = position(linenum); + } + } return (pos); } @@ -922,10 +693,14 @@ POSITION *pendpos; { char *line; + char *cline; + int line_len; LINENUM linenum; char *sp, *ep; int line_match; int cvt_ops; + int cvt_len; + int *chpos; POSITION linepos, oldpos; linenum = find_linenum(pos); @@ -964,7 +739,7 @@ * starting position of that line in linepos. */ linepos = pos; - pos = forw_raw_line(pos, &line); + pos = forw_raw_line(pos, &line, &line_len); if (linenum != 0) linenum++; } else @@ -973,7 +748,7 @@ * Read the previous line and save the * starting position of that line in linepos. */ - pos = back_raw_line(pos, &line); + pos = back_raw_line(pos, &line, &line_len); linepos = pos; if (linenum != 0) linenum--; @@ -997,67 +772,126 @@ * the search. Remember the line number only if * we're "far" from the last place we remembered it. */ - if (linenums && abs((int)(pos - oldpos)) > 1024) + if (linenums && abs((int)(pos - oldpos)) > 2048) add_lnum(linenum, pos); oldpos = pos; + if (is_filtered(linepos)) + continue; + /* * If it's a caseless search, convert the line to lowercase. * If we're doing backspace processing, delete backspaces. */ cvt_ops = get_cvt_ops(); - cvt_text(line, line, cvt_ops); + cvt_len = cvt_length(line_len, cvt_ops); + cline = (char *) ecalloc(1, cvt_len); + chpos = cvt_alloc_chpos(cvt_len); + cvt_text(cline, line, chpos, &line_len, cvt_ops); +#if HILITE_SEARCH /* + * Check to see if the line matches the filter pattern. + * If so, add an entry to the filter list. + */ + if ((search_type & SRCH_FIND_ALL) && prev_pattern(&filter_info)) { + int line_filter = match_pattern(filter_info.compiled, filter_info.text, + cline, line_len, &sp, &ep, 0, filter_info.search_type); + if (line_filter) + { + struct hilite *hl = (struct hilite *) + ecalloc(1, sizeof(struct hilite)); + hl->hl_startpos = linepos; + hl->hl_endpos = pos; + add_hilite(&filter_anchor, hl); + } + } +#endif + + /* * Test the next line to see if we have a match. * We are successful if we either want a match and got one, * or if we want a non-match and got one. */ - line_match = match_pattern(line, &sp, &ep, 0); - line_match = (!(search_type & SRCH_NO_MATCH) && line_match) || - ((search_type & SRCH_NO_MATCH) && !line_match); - if (!line_match) - continue; - /* - * Got a match. - */ - if (search_type & SRCH_FIND_ALL) + if (prev_pattern(&search_info)) { -#if HILITE_SEARCH - /* - * We are supposed to find all matches in the range. - * Just add the matches in this line to the - * hilite list and keep searching. - */ + line_match = match_pattern(search_info.compiled, search_info.text, + cline, line_len, &sp, &ep, 0, search_type); if (line_match) - hilite_line(linepos, line, sp, ep, cvt_ops); -#endif - } else if (--matches <= 0) - { - /* - * Found the one match we're looking for. - * Return it. - */ -#if HILITE_SEARCH - if (hilite_search == 1) { /* - * Clear the hilite list and add only - * the matches in this one line. + * Got a match. */ - clr_hilite(); - if (line_match) - hilite_line(linepos, line, sp, ep, cvt_ops); - } + if (search_type & SRCH_FIND_ALL) + { +#if HILITE_SEARCH + /* + * We are supposed to find all matches in the range. + * Just add the matches in this line to the + * hilite list and keep searching. + */ + hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops); #endif - if (plinepos != NULL) - *plinepos = linepos; - return (0); + } else if (--matches <= 0) + { + /* + * Found the one match we're looking for. + * Return it. + */ +#if HILITE_SEARCH + if (hilite_search == OPT_ON) + { + /* + * Clear the hilite list and add only + * the matches in this one line. + */ + clr_hilite(); + hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops); + } +#endif + free(cline); + free(chpos); + if (plinepos != NULL) + *plinepos = linepos; + return (0); + } + } } + free(cline); + free(chpos); } } /* + * search for a pattern in history. If found, compile that pattern. + */ + static int +hist_pattern(search_type) + int search_type; +{ +#if CMD_HISTORY + char *pattern; + + set_mlist(ml_search, 0); + pattern = cmd_lastpattern(); + if (pattern == NULL) + return (0); + + if (set_pattern(&search_info, pattern, search_type) < 0) + return (0); + +#if HILITE_SEARCH + if (hilite_search == OPT_ONPLUS && !hide_hilite) + hilite_screen(); +#endif + + return (1); +#else /* CMD_HISTORY */ + return (0); +#endif /* CMD_HISTORY */ +} + +/* * Search for the n-th occurrence of a specified pattern, * either forward or backward. * Return the number of matches not yet found in this file @@ -1073,20 +907,20 @@ int n; { POSITION pos; - int ucase; if (pattern == NULL || *pattern == '\0') { /* * A null pattern means use the previously compiled pattern. */ - if (!prev_pattern()) + search_type |= SRCH_AFTER_TARGET; + if (!prev_pattern(&search_info) && !hist_pattern(search_type)) { error("No previous regular expression", NULL_PARG); return (-1); } if ((search_type & SRCH_NO_REGEX) != - (last_search_type & SRCH_NO_REGEX)) + (search_info.search_type & SRCH_NO_REGEX)) { error("Please re-enter search pattern", NULL_PARG); return -1; @@ -1116,20 +950,8 @@ /* * Compile the pattern. */ - ucase = is_ucase(pattern); - if (caseless == OPT_ONPLUS) - cvt_text(pattern, pattern, CVT_TO_LC); - if (compile_pattern(pattern, search_type) < 0) + if (set_pattern(&search_info, pattern, search_type) < 0) return (-1); - /* - * Ignore case if -I is set OR - * -i is set AND the pattern is all lowercase. - */ - is_ucase_pattern = ucase; - if (is_ucase_pattern && caseless != OPT_ONPLUS) - is_caseless = 0; - else - is_caseless = caseless; #if HILITE_SEARCH if (hilite_search) { @@ -1227,13 +1049,14 @@ POSITION max_epos; int result; int i; + /* * Search beyond where we're asked to search, so the prep region covers * more than we need. Do one big search instead of a bunch of small ones. */ #define SEARCH_MORE (3*size_linebuf) - if (!prev_pattern()) + if (!prev_pattern(&search_info) && !is_filtering()) return; /* @@ -1246,7 +1069,7 @@ { max_epos = spos; for (i = 0; i < maxlines; i++) - max_epos = forw_raw_line(max_epos, (char **)NULL); + max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); } /* @@ -1264,6 +1087,7 @@ * Discard the old prep region and start a new one. */ clr_hilite(); + clr_filter(); if (epos != NULL_POSITION) epos += SEARCH_MORE; nprep_startpos = spos; @@ -1325,7 +1149,9 @@ if (epos == NULL_POSITION || epos > spos) { - result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, + int search_type = SRCH_FORW | SRCH_FIND_ALL; + search_type |= (search_info.search_type & SRCH_NO_REGEX); + result = search_range(spos, epos, search_type, 0, maxlines, (POSITION*)NULL, &new_epos); if (result < 0) return; @@ -1335,35 +1161,34 @@ prep_startpos = nprep_startpos; prep_endpos = nprep_endpos; } -#endif /* - * Simple pattern matching function. - * It supports no metacharacters like *, etc. + * Set the pattern to be used for line filtering. */ - static int -match(pattern, buf, pfound, pend) - char *pattern, *buf; - char **pfound, **pend; + public void +set_filter_pattern(pattern, search_type) + char *pattern; + int search_type; { - register char *pp, *lp; + clr_filter(); + if (pattern == NULL || *pattern == '\0') + clear_pattern(&filter_info); + else + set_pattern(&filter_info, pattern, search_type); + screen_trashed = 1; +} - for ( ; *buf != '\0'; buf++) - { - for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) - if (*pp == '\0' || *lp == '\0') - break; - if (*pp == '\0') - { - if (pfound != NULL) - *pfound = buf; - if (pend != NULL) - *pend = lp; - return (1); - } - } - return (0); +/* + * Is there a line filter in effect? + */ + public int +is_filtering() +{ + if (ch_getflags() & CH_HELPFILE) + return (0); + return prev_pattern(&filter_info); } +#endif #if HAVE_V8_REGCOMP /*