=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/less/search.c,v retrieving revision 1.5 retrieving revision 1.6 diff -c -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 **** /* ! * Copyright (C) 1984-2002 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. --- 1,5 ---- /* ! * 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,50 **** */ #include "less.h" #include "position.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; --- 14,26 ---- */ #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)) extern int sigs; extern int how_search; extern int caseless; *************** *** 54,70 **** extern int bs_mode; extern int ctldisp; extern int status_col; extern POSITION start_attnpos; extern POSITION end_attnpos; #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; struct hilite { --- 30,50 ---- 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 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,149 **** POSITION hl_endpos; }; static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; #define hl_first hl_next #endif /* * These are the static variables that represent the "remembered" ! * search 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 ! static int is_caseless; ! static int is_ucase_pattern; ! static int last_search_type; ! static char *last_pattern = NULL; /* ! * Convert text. Perform one or more of these transformations: */ ! #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 void ! cvt_text(odst, osrc, ops) ! char *odst; ! char *osrc; ! int ops; { ! register char *dst; ! register char *src; ! 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'; } /* ! * Determine which conversions to perform. */ static int get_cvt_ops() { --- 53,165 ---- 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 and filter pattern. */ ! struct pattern_info { ! DEFINE_PATTERN(compiled); ! char* text; ! int search_type; ! }; ! ! static struct pattern_info search_info; ! static struct pattern_info filter_info; ! /* ! * 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); + } + /* ! * Compile and save a search pattern. */ ! 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 ! clear_pattern(info) ! struct pattern_info *info; { ! if (info->text != NULL) ! free(info->text); ! info->text = NULL; ! uncompile_pattern(&info->compiled); ! } ! /* ! * 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; } /* ! * 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,211 **** } /* - * 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() { ! 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 HILITE_SEARCH --- 182,196 ---- } /* * Is there a previous (remembered) search pattern? */ static int ! prev_pattern(info) ! struct pattern_info *info; { ! if (info->search_type & SRCH_NO_REGEX) ! return (info->text != NULL); ! return (!is_null_pattern(info->compiled)); } #if HILITE_SEARCH *************** *** 247,263 **** 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(); ! } } hide_hilite = save_hide_hilite; } --- 232,242 ---- if (pos == NULL_POSITION) continue; epos = position(slinenum+1); ! (void) forw_line(pos); ! goto_line(slinenum); ! put_line(); } + lower_left(); hide_hilite = save_hide_hilite; } *************** *** 272,277 **** --- 251,257 ---- POSITION old_end_attnpos; POSITION pos; POSITION epos; + int moved = 0; if (start_attnpos == NULL_POSITION) return; *************** *** 299,306 **** --- 279,289 ---- (void) forw_line(pos); goto_line(slinenum); put_line(); + moved = 1; } } + if (moved) + lower_left(); } #endif *************** *** 310,316 **** public void undo_search() { ! if (!prev_pattern()) { error("No previous regular expression", NULL_PARG); return; --- 293,299 ---- public void undo_search() { ! if (!prev_pattern(&search_info)) { error("No previous regular expression", NULL_PARG); return; *************** *** 321,531 **** #endif } /* ! * Compile a search pattern, for future use by match_pattern. */ ! static int ! compile_pattern(pattern, search_type) ! char *pattern; ! int search_type; { ! if ((search_type & SRCH_NO_REGEX) == 0) { ! #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 } ! if (last_pattern != NULL) ! free(last_pattern); ! last_pattern = save(pattern); ! ! last_search_type = search_type; ! return (0); } ! /* ! * Forget that we have a compiled pattern. ! */ ! static void ! uncompile_pattern() { ! #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; } /* ! * Perform a pattern match with the previously compiled pattern. ! * Set sp and ep to the start and end of the matched string. */ static int ! match_pattern(line, sp, ep, notbol) ! char *line; ! char **sp; ! char **ep; ! int notbol; { ! int matched; - 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. */ ! *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); } ! #if HILITE_SEARCH ! /* ! * Clear the hilite list. */ ! public void ! clr_hilite() { struct hilite *hl; - struct hilite *nexthl; ! for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl) { ! nexthl = hl->hl_next; ! free((void*)hl); } ! hilite_anchor.hl_first = NULL; ! prep_startpos = prep_endpos = NULL_POSITION; } /* --- 304,385 ---- #endif } + #if HILITE_SEARCH /* ! * Clear the hilite list. */ ! public void ! clr_hlist(anchor) ! struct hilite *anchor; { ! struct hilite *hl; ! struct hilite *nexthl; ! ! for (hl = anchor->hl_first; hl != NULL; hl = nexthl) { ! nexthl = hl->hl_next; ! free((void*)hl); } + anchor->hl_first = NULL; + prep_startpos = prep_endpos = NULL_POSITION; + } ! public void ! clr_hilite() ! { ! clr_hlist(&hilite_anchor); } ! public void ! clr_filter() { ! clr_hlist(&filter_anchor); } /* ! * Should any characters in a specified range be highlighted? */ static int ! is_hilited_range(pos, epos) ! POSITION pos; ! POSITION epos; { ! struct hilite *hl; /* ! * 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); } ! /* ! * Is a line "filtered" -- that is, should it be hidden? */ ! public int ! is_filtered(pos) ! POSITION pos; { struct hilite *hl; ! 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) { ! if (hl->hl_startpos == pos) ! return (1); } ! return (0); } /* *************** *** 533,545 **** * If nohide is nonzero, don't consider hide_hilite. */ public int ! is_hilited(pos, epos, nohide) POSITION pos; POSITION epos; int nohide; { ! struct hilite *hl; if (!status_col && start_attnpos != NULL_POSITION && pos < end_attnpos && --- 387,403 ---- * If nohide is nonzero, don't consider hide_hilite. */ public int ! is_hilited(pos, epos, nohide, p_matches) POSITION pos; POSITION epos; int nohide; + int *p_matches; { ! int match; + if (p_matches != NULL) + *p_matches = 0; + if (!status_col && start_attnpos != NULL_POSITION && pos < end_attnpos && *************** *** 549,554 **** --- 407,422 ---- */ 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,576 **** */ 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); } /* --- 429,435 ---- */ return (0); ! return (1); } /* *************** *** 614,720 **** } /* - * 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) POSITION linepos; char *line; char *sp; char *ep; int cvt_ops; { char *searchp; struct hilite *hl; - struct hilite hilites; if (sp == NULL || ep == NULL) return; --- 473,495 ---- } /* * 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, 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; if (sp == NULL || ep == NULL) return; *************** *** 726,750 **** * 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). }} */ 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); } /* * If we matched more than zero characters, --- 501,516 ---- * 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, PCRE and V8-with-regexec2). }} */ searchp = line; do { if (ep > sp) { hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); ! 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,779 **** */ if (ep > searchp) searchp = ep; ! else if (*searchp != '\0') 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); ! } } #endif --- 519,530 ---- */ if (ep > searchp) searchp = ep; ! else if (searchp != line_end) searchp++; else /* end of line */ break; ! } while (match_pattern(search_info.compiled, search_info.text, ! searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type)); } #endif *************** *** 795,801 **** * Pattern did have uppercase. * Discard the pattern; we can't change search caselessness now. */ ! uncompile_pattern(); } #if HILITE_SEARCH --- 546,552 ---- * Pattern did have uppercase. * Discard the pattern; we can't change search caselessness now. */ ! clear_pattern(&search_info); } #if HILITE_SEARCH *************** *** 855,861 **** */ if (search_type & SRCH_FORW) { ! return (ch_zero()); } else { pos = ch_length(); --- 606,612 ---- */ if (search_type & SRCH_FORW) { ! pos = ch_zero(); } else { pos = ch_length(); *************** *** 864,910 **** (void) ch_end_seek(); pos = ch_length(); } - return (pos); } ! } ! if (how_search) { ! /* ! * 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) { ! pos = forw_raw_line(pos, (char **)NULL); ! 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); } --- 615,681 ---- (void) ch_end_seek(); pos = ch_length(); } } ! linenum = 0; ! } else { ! int add_one = 0; ! ! if (how_search == OPT_ON) { ! /* ! * 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 { ! /* ! * 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,931 **** --- 693,706 ---- 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,970 **** * starting position of that line in linepos. */ linepos = pos; ! pos = forw_raw_line(pos, &line); if (linenum != 0) linenum++; } else --- 739,745 ---- * starting position of that line in linepos. */ linepos = pos; ! pos = forw_raw_line(pos, &line, &line_len); if (linenum != 0) linenum++; } else *************** *** 973,979 **** * Read the previous line and save the * starting position of that line in linepos. */ ! pos = back_raw_line(pos, &line); linepos = pos; if (linenum != 0) linenum--; --- 748,754 ---- * Read the previous line and save the * starting position of that line in linepos. */ ! pos = back_raw_line(pos, &line, &line_len); linepos = pos; if (linenum != 0) linenum--; *************** *** 997,1063 **** * 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) add_lnum(linenum, pos); oldpos = pos; /* * 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); /* * 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 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. ! */ 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. */ ! clr_hilite(); ! if (line_match) ! hilite_line(linepos, line, sp, ep, cvt_ops); ! } #endif ! if (plinepos != NULL) ! *plinepos = linepos; ! return (0); } } } /* * 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 --- 772,897 ---- * the search. Remember the line number only if * we're "far" from the last place we remembered it. */ ! 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_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. */ ! if (prev_pattern(&search_info)) { ! line_match = match_pattern(search_info.compiled, search_info.text, ! cline, line_len, &sp, &ep, 0, search_type); if (line_match) { /* ! * Got a match. */ ! 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 ! } 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,1092 **** int n; { POSITION pos; - int ucase; if (pattern == NULL || *pattern == '\0') { /* * A null pattern means use the previously compiled pattern. */ ! if (!prev_pattern()) { error("No previous regular expression", NULL_PARG); return (-1); } if ((search_type & SRCH_NO_REGEX) != ! (last_search_type & SRCH_NO_REGEX)) { error("Please re-enter search pattern", NULL_PARG); return -1; --- 907,926 ---- int n; { POSITION pos; if (pattern == NULL || *pattern == '\0') { /* * A null pattern means use the previously compiled 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) != ! (search_info.search_type & SRCH_NO_REGEX)) { error("Please re-enter search pattern", NULL_PARG); return -1; *************** *** 1116,1135 **** /* * 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) 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) { --- 950,957 ---- /* * Compile the pattern. */ ! if (set_pattern(&search_info, pattern, search_type) < 0) return (-1); #if HILITE_SEARCH if (hilite_search) { *************** *** 1227,1239 **** 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()) return; /* --- 1049,1062 ---- 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(&search_info) && !is_filtering()) return; /* *************** *** 1246,1252 **** { max_epos = spos; for (i = 0; i < maxlines; i++) ! max_epos = forw_raw_line(max_epos, (char **)NULL); } /* --- 1069,1075 ---- { max_epos = spos; for (i = 0; i < maxlines; i++) ! max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); } /* *************** *** 1264,1269 **** --- 1087,1093 ---- * 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,1331 **** if (epos == NULL_POSITION || epos > spos) { ! result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, maxlines, (POSITION*)NULL, &new_epos); if (result < 0) return; --- 1149,1157 ---- if (epos == NULL_POSITION || epos > spos) { ! 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,1369 **** prep_startpos = nprep_startpos; prep_endpos = nprep_endpos; } - #endif /* ! * Simple pattern matching function. ! * It supports no metacharacters like *, etc. */ ! static int ! match(pattern, buf, pfound, pend) ! char *pattern, *buf; ! char **pfound, **pend; { ! register char *pp, *lp; ! 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); } #if HAVE_V8_REGCOMP /* --- 1161,1194 ---- prep_startpos = nprep_startpos; prep_endpos = nprep_endpos; } /* ! * Set the pattern to be used for line filtering. */ ! public void ! set_filter_pattern(pattern, search_type) ! char *pattern; ! int search_type; { ! clr_filter(); ! if (pattern == NULL || *pattern == '\0') ! clear_pattern(&filter_info); ! else ! set_pattern(&filter_info, pattern, search_type); ! screen_trashed = 1; ! } ! /* ! * 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 /*