diff options
author | delphij <delphij@FreeBSD.org> | 2009-05-08 23:34:35 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2009-05-08 23:34:35 +0000 |
commit | d069efd47cacc3156036ed37d5532d6a1d4f55c3 (patch) | |
tree | 2526f6b109843b646672c1537476dc51e56c0454 /contrib/less/search.c | |
parent | 6aa3e25391d160482339ee072c010bcd22dfbbd1 (diff) | |
download | FreeBSD-src-d069efd47cacc3156036ed37d5532d6a1d4f55c3.zip FreeBSD-src-d069efd47cacc3156036ed37d5532d6a1d4f55c3.tar.gz |
Flatten all tags of the dist tree of less.
Diffstat (limited to 'contrib/less/search.c')
-rw-r--r-- | contrib/less/search.c | 1551 |
1 files changed, 0 insertions, 1551 deletions
diff --git a/contrib/less/search.c b/contrib/less/search.c deleted file mode 100644 index 3a15380..0000000 --- a/contrib/less/search.c +++ /dev/null @@ -1,1551 +0,0 @@ -/* - * Copyright (C) 1984-2007 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. - * - * For more information about less, or for information on how to - * contact the author, see the README file. - */ - - -/* - * Routines to search a file for a pattern. - */ - -#include "less.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 <regex.h> -#ifdef REG_EXTENDED -#define REGCOMP_FLAG REG_EXTENDED -#else -#define REGCOMP_FLAG 0 -#endif -#endif -#if HAVE_PCRE -#include <pcre.h> -#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; -extern int linenums; -extern int sc_height; -extern int jump_sline; -extern int bs_mode; -extern int ctldisp; -extern int status_col; -extern void * constant ml_search; -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; -extern int utf_mode; -static int hide_hilite; -static int oldbot; -static POSITION prep_startpos; -static POSITION prep_endpos; - -struct hilite -{ - struct hilite *hl_next; - POSITION hl_startpos; - 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; - -#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 */ - -/* - * Get the length of a buffer needed to convert a string. - */ - static int -cvt_length(len, ops) - int len; - int ops; -{ - if (utf_mode) - /* - * Just copying a string in UTF-8 mode can cause it to grow - * in length. - * Six output bytes for one input byte is the worst case - * (and unfortunately is far more than is needed in any - * non-pathological situation, so this is very wasteful). - */ - len *= 6; - return len + 1; -} - -/* - * Convert text. Perform one or more of these transformations: - */ - static void -cvt_text(odst, osrc, lenp, ops) - char *odst; - char *osrc; - int *lenp; - int ops; -{ - char *dst; - char *src; - register char *src_end; - LWCHAR ch; - - if (lenp != NULL) - src_end = osrc + *lenp; - else - src_end = osrc + strlen(osrc); - - for (src = osrc, dst = odst; src < src_end; ) - { - ch = step_char(&src, +1, src_end); - if ((ops & CVT_TO_LC) && IS_UPPER(ch)) - { - /* Convert uppercase to lowercase. */ - put_wchar(&dst, TO_LOWER(ch)); - } else if ((ops & CVT_BS) && ch == '\b' && dst > odst) - { - /* Delete backspace and preceding char. */ - do { - dst--; - } while (dst > odst && - !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst)); - } else if ((ops & CVT_ANSI) && IS_CSI_START(ch)) - { - /* Skip to end of ANSI escape sequence. */ - while (src + 1 != src_end) - if (!is_ansi_middle(*++src)) - break; - } else - /* Just copy. */ - put_wchar(&dst, ch); - } - if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r') - dst--; - *dst = '\0'; - if (lenp != NULL) - *lenp = dst - odst; -} - -/* - * Determine which conversions to perform. - */ - static int -get_cvt_ops() -{ - int ops = 0; - if (is_caseless || bs_mode == BS_SPECIAL) - { - if (is_caseless) - ops |= CVT_TO_LC; - if (bs_mode == BS_SPECIAL) - ops |= CVT_BS; - if (bs_mode != BS_CONTROL) - ops |= CVT_CRLF; - } else if (bs_mode != BS_CONTROL) - { - ops |= CVT_CRLF; - } - if (ctldisp == OPT_ONPLUS) - ops |= CVT_ANSI; - return (ops); -} - -/* - * 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); -} - -/* - * 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 -/* - * Repaint the hilites currently displayed on the screen. - * Repaint each line which contains highlighted text. - * If on==0, force all hilites off. - */ - public void -repaint_hilite(on) - int on; -{ - int slinenum; - POSITION pos; - POSITION epos; - int save_hide_hilite; - - if (squished) - repaint(); - - save_hide_hilite = hide_hilite; - if (!on) - { - if (hide_hilite) - return; - hide_hilite = 1; - } - - if (!can_goto_line) - { - repaint(); - hide_hilite = save_hide_hilite; - return; - } - - for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) - { - pos = position(slinenum); - if (pos == NULL_POSITION) - continue; - epos = position(slinenum+1); -#if 0 - /* - * If any character in the line is highlighted, - * repaint the line. - * - * {{ This doesn't work -- if line is drawn with highlights - * which should be erased (e.g. toggle -i with status column), - * we must redraw the line even if it has no highlights. - * For now, just repaint every line. }} - */ - if (is_hilited(pos, epos, 1, NULL)) -#endif - { - (void) forw_line(pos); - goto_line(slinenum); - put_line(); - } - } - if (!oldbot) - lower_left(); - hide_hilite = save_hide_hilite; -} - -/* - * Clear the attn hilite. - */ - public void -clear_attn() -{ - int slinenum; - POSITION old_start_attnpos; - POSITION old_end_attnpos; - POSITION pos; - POSITION epos; - int moved = 0; - - if (start_attnpos == NULL_POSITION) - return; - old_start_attnpos = start_attnpos; - old_end_attnpos = end_attnpos; - start_attnpos = end_attnpos = NULL_POSITION; - - if (!can_goto_line) - { - repaint(); - return; - } - if (squished) - repaint(); - - for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) - { - pos = position(slinenum); - if (pos == NULL_POSITION) - continue; - epos = position(slinenum+1); - if (pos < old_end_attnpos && - (epos == NULL_POSITION || epos > old_start_attnpos)) - { - (void) forw_line(pos); - goto_line(slinenum); - put_line(); - moved = 1; - } - } - if (moved) - lower_left(); -} -#endif - -/* - * Hide search string highlighting. - */ - public void -undo_search() -{ - if (!prev_pattern()) - { - error("No previous regular expression", NULL_PARG); - return; - } -#if HILITE_SEARCH - hide_hilite = !hide_hilite; - repaint_hilite(1); -#endif -} - -/* - * Compile a search pattern, for future use by match_pattern. - */ - static int -compile_pattern2(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 = (char *) calloc(1, strlen(pattern)+1); - if (last_pattern != NULL) - strcpy(last_pattern, pattern); - - last_search_type = search_type; - return (0); -} - -/* - * Like compile_pattern, but convert the pattern to lowercase if necessary. - */ - static int -compile_pattern(pattern, search_type) - char *pattern; - int search_type; -{ - char *cvt_pattern; - int result; - - if (caseless != OPT_ONPLUS) - cvt_pattern = pattern; - else - { - cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC)); - cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC); - } - result = compile_pattern2(cvt_pattern, search_type); - if (cvt_pattern != pattern) - free(cvt_pattern); - return (result); -} - -/* - * 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, line_len, sp, ep, notbol) - char *line; - int line_len; - char **sp; - char **ep; - int notbol; -{ - int matched; - - if (last_search_type & SRCH_NO_REGEX) - return (match(last_pattern, strlen(last_pattern), line, line_len, 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, line_len, - 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, strlen(last_pattern), line, line_len, 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; -} - -/* - * 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); -} - -/* - * Should any characters in a specified range be highlighted? - * 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 && - (epos == NULL_POSITION || epos > start_attnpos)) - /* - * The attn line overlaps this range. - */ - 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. - */ - return (0); - - if (!nohide && hide_hilite) - /* - * Highlighting is hidden. - */ - return (0); - - return (1); -} - -/* - * Add a new hilite to a hilite list. - */ - static void -add_hilite(anchor, hl) - struct hilite *anchor; - struct hilite *hl; -{ - struct hilite *ihl; - - /* - * Hilites are sorted in the list; find where new one belongs. - * Insert new one after ihl. - */ - for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next) - { - if (ihl->hl_next->hl_startpos > hl->hl_startpos) - break; - } - - /* - * Truncate hilite so it doesn't overlap any existing ones - * above and below it. - */ - if (ihl != anchor) - hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos); - if (ihl->hl_next != NULL) - hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos); - if (hl->hl_startpos >= hl->hl_endpos) - { - /* - * Hilite was truncated out of existence. - */ - free(hl); - return; - } - hl->hl_next = ihl->hl_next; - ihl->hl_next = hl; -} - -/* - * Adjust hl_startpos & hl_endpos to account for processing by cvt_text. - */ - static void -adj_hilite(anchor, linepos, cvt_ops) - struct hilite *anchor; - POSITION linepos; - int cvt_ops; -{ - char *line; - char *oline; - int line_len; - char *line_end; - struct hilite *hl; - int checkstart; - POSITION opos; - POSITION npos; - LWCHAR ch; - int ncwidth; - - /* - * 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 cvt_text modified the line. - * Get the raw line again. Look at each character. - */ - (void) forw_raw_line(linepos, &line, &line_len); - line_end = line + line_len; - 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 == line_end) - break; - - /* Get the next char from the line. */ - oline = line; - ch = step_char(&line, +1, line_end); - ncwidth = line - oline; - npos += ncwidth; - - /* Figure out how this char was processed by cvt_text. */ - if ((cvt_ops & CVT_BS) && ch == '\b') - { - /* Skip the backspace and the following char. */ - oline = line; - ch = step_char(&line, +1, line_end); - ncwidth = line - oline; - npos += ncwidth; - } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch)) - { - /* Converted uppercase to lower. - * Note that this may have changed the number of bytes - * that the character occupies. */ - char dbuf[6]; - char *dst = dbuf; - put_wchar(&dst, TO_LOWER(ch)); - opos += dst - dbuf; - } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch)) - { - /* Skip to end of ANSI escape sequence. */ - while (line < line_end) - { - npos++; - if (!is_ansi_middle(*++line)) - break; - } - } else - { - /* Ordinary unprocessed character. */ - opos += ncwidth; - } - } -} - -/* - * 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, sp, ep, cvt_ops) - POSITION linepos; - char *line; - int line_len; - 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; - /* - * sp and ep delimit the first match in the line. - * Mark the corresponding file positions, then - * look for further matches and mark them. - * {{ This technique, of calling match_pattern on subsequent - * 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; - /* - * 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, - * move to the first char after the string we matched. - * If we matched zero, just move to the next char. - */ - if (ep > searchp) - searchp = ep; - else if (searchp != line_end) - searchp++; - else /* end of line */ - break; - } while (match_pattern(searchp, line_end - 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 - -/* - * Change the caseless-ness of searches. - * Updates the internal search state to reflect a change in the -i flag. - */ - public void -chg_caseless() -{ - if (!is_ucase_pattern) - /* - * Pattern did not have uppercase. - * Just set the search caselessness to the global caselessness. - */ - is_caseless = caseless; - else - /* - * Pattern did have uppercase. - * Discard the pattern; we can't change search caselessness now. - */ - uncompile_pattern(); -} - -#if HILITE_SEARCH -/* - * Find matching text which is currently on screen and highlight it. - */ - static void -hilite_screen() -{ - struct scrpos scrpos; - - get_scrpos(&scrpos); - if (scrpos.pos == NULL_POSITION) - return; - prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); - repaint_hilite(1); -} - -/* - * Change highlighting parameters. - */ - public void -chg_hilite() -{ - /* - * Erase any highlights currently on screen. - */ - clr_hilite(); - hide_hilite = 0; - - if (hilite_search == OPT_ONPLUS) - /* - * Display highlights. - */ - hilite_screen(); -} -#endif - -/* - * Figure out where to start a search. - */ - static POSITION -search_pos(search_type) - int search_type; -{ - POSITION pos; - int linenum; - - if (empty_screen()) - { - /* - * Start at the beginning (or end) of the file. - * The empty_screen() case is mainly for - * command line initiated searches; - * for example, "+/xyz" on the command line. - * Also for multi-file (SRCH_PAST_EOF) searches. - */ - if (search_type & SRCH_FORW) - { - return (ch_zero()); - } else - { - pos = ch_length(); - if (pos == NULL_POSITION) - { - (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, (int *)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); -} - -/* - * Search a subset of the file, specified by start/end position. - */ - static int -search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) - POSITION pos; - POSITION endpos; - int search_type; - int matches; - int maxlines; - POSITION *plinepos; - POSITION *pendpos; -{ - char *line; - char *cline; - int line_len; - LINENUM linenum; - char *sp, *ep; - int line_match; - int cvt_ops; - POSITION linepos, oldpos; - - linenum = find_linenum(pos); - oldpos = pos; - for (;;) - { - /* - * Get lines until we find a matching one or until - * we hit end-of-file (or beginning-of-file if we're - * going backwards), or until we hit the end position. - */ - if (ABORT_SIGS()) - { - /* - * A signal aborts the search. - */ - return (-1); - } - - if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) - { - /* - * Reached end position without a match. - */ - if (pendpos != NULL) - *pendpos = pos; - return (matches); - } - if (maxlines > 0) - maxlines--; - - if (search_type & SRCH_FORW) - { - /* - * Read the next line, and save the - * starting position of that line in linepos. - */ - linepos = pos; - pos = forw_raw_line(pos, &line, &line_len); - if (linenum != 0) - linenum++; - } else - { - /* - * 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--; - } - - if (pos == NULL_POSITION) - { - /* - * Reached EOF/BOF without a match. - */ - if (pendpos != NULL) - *pendpos = oldpos; - return (matches); - } - - /* - * If we're using line numbers, we might as well - * remember the information we have now (the position - * and line number of the current line). - * Don't do it for every line because it slows down - * 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(); - cline = calloc(1, cvt_length(line_len, cvt_ops)); - cvt_text(cline, line, &line_len, 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(cline, line_len, &sp, &ep, 0); - line_match = (!(search_type & SRCH_NO_MATCH) && line_match) || - ((search_type & SRCH_NO_MATCH) && !line_match); - if (!line_match) - { - free(cline); - 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, cline, line_len, sp, ep, cvt_ops); -#endif - free(cline); - } 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(); - if (line_match) - hilite_line(linepos, cline, line_len, sp, ep, cvt_ops); - } -#endif - free(cline); - if (plinepos != NULL) - *plinepos = linepos; - return (0); - } - } -} - - /* - * 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 (compile_pattern(pattern, search_type) < 0) - return (0); - - is_ucase_pattern = is_ucase(pattern); - if (is_ucase_pattern && caseless != OPT_ONPLUS) - is_caseless = 0; - else - is_caseless = caseless; - -#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 - * (that is, n minus the number of matches found). - * Return -1 if the search should be aborted. - * Caller may continue the search in another file - * if less than n matches are found in this file. - */ - public int -search(search_type, pattern, n) - int search_type; - char *pattern; - int n; -{ - POSITION pos; - int result; - - if (pattern == NULL || *pattern == '\0') - { - /* - * A null pattern means use the previously compiled pattern. - */ - if (!prev_pattern() && !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)) - { - error("Please re-enter search pattern", NULL_PARG); - return -1; - } -#if HILITE_SEARCH - if (hilite_search == OPT_ON) - { - /* - * Erase the highlights currently on screen. - * If the search fails, we'll redisplay them later. - */ - repaint_hilite(0); - } - if (hilite_search == OPT_ONPLUS && hide_hilite) - { - /* - * Highlight any matches currently on screen, - * before we actually start the search. - */ - hide_hilite = 0; - hilite_screen(); - } - hide_hilite = 0; -#endif - } else - { - /* - * Compile the pattern. - */ - 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 = is_ucase(pattern); - if (is_ucase_pattern && caseless != OPT_ONPLUS) - is_caseless = 0; - else - is_caseless = caseless; -#if HILITE_SEARCH - if (hilite_search) - { - /* - * Erase the highlights currently on screen. - * Also permanently delete them from the hilite list. - */ - repaint_hilite(0); - hide_hilite = 0; - clr_hilite(); - } - if (hilite_search == OPT_ONPLUS) - { - /* - * Highlight any matches currently on screen, - * before we actually start the search. - */ - hilite_screen(); - } -#endif - } - - /* - * Figure out where to start the search. - */ - pos = search_pos(search_type); - if (pos == NULL_POSITION) - { - /* - * Can't find anyplace to start searching from. - */ - if (search_type & SRCH_PAST_EOF) - return (n); - /* repaint(); -- why was this here? */ - error("Nothing to search", NULL_PARG); - return (-1); - } - - n = search_range(pos, NULL_POSITION, search_type, n, -1, - &pos, (POSITION*)NULL); - if (n != 0) - { - /* - * Search was unsuccessful. - */ -#if HILITE_SEARCH - if (hilite_search == OPT_ON && n > 0) - /* - * Redisplay old hilites. - */ - repaint_hilite(1); -#endif - return (n); - } - - if (!(search_type & SRCH_NO_MOVE)) - { - /* - * Go to the matching line. - */ - jump_loc(pos, jump_sline); - } - -#if HILITE_SEARCH - if (hilite_search == OPT_ON) - /* - * Display new hilites in the matching line. - */ - repaint_hilite(1); -#endif - return (0); -} - - -#if HILITE_SEARCH -/* - * Prepare hilites in a given range of the file. - * - * The pair (prep_startpos,prep_endpos) delimits a contiguous region - * of the file that has been "prepared"; that is, scanned for matches for - * the current search pattern, and hilites have been created for such matches. - * If prep_startpos == NULL_POSITION, the prep region is empty. - * If prep_endpos == NULL_POSITION, the prep region extends to EOF. - * prep_hilite asks that the range (spos,epos) be covered by the prep region. - */ - public void -prep_hilite(spos, epos, maxlines) - POSITION spos; - POSITION epos; - int maxlines; -{ - POSITION nprep_startpos = prep_startpos; - POSITION nprep_endpos = prep_endpos; - POSITION new_epos; - 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; - - /* - * If we're limited to a max number of lines, figure out the - * file position we should stop at. - */ - if (maxlines < 0) - max_epos = NULL_POSITION; - else - { - max_epos = spos; - for (i = 0; i < maxlines; i++) - max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); - } - - /* - * Find two ranges: - * The range that we need to search (spos,epos); and the range that - * the "prep" region will then cover (nprep_startpos,nprep_endpos). - */ - - if (prep_startpos == NULL_POSITION || - (epos != NULL_POSITION && epos < prep_startpos) || - spos > prep_endpos) - { - /* - * New range is not contiguous with old prep region. - * Discard the old prep region and start a new one. - */ - clr_hilite(); - if (epos != NULL_POSITION) - epos += SEARCH_MORE; - nprep_startpos = spos; - } else - { - /* - * New range partially or completely overlaps old prep region. - */ - if (epos == NULL_POSITION) - { - /* - * New range goes to end of file. - */ - ; - } else if (epos > prep_endpos) - { - /* - * New range ends after old prep region. - * Extend prep region to end at end of new range. - */ - epos += SEARCH_MORE; - } else /* (epos <= prep_endpos) */ - { - /* - * New range ends within old prep region. - * Truncate search to end at start of old prep region. - */ - epos = prep_startpos; - } - - if (spos < prep_startpos) - { - /* - * New range starts before old prep region. - * Extend old prep region backwards to start at - * start of new range. - */ - if (spos < SEARCH_MORE) - spos = 0; - else - spos -= SEARCH_MORE; - nprep_startpos = spos; - } else /* (spos >= prep_startpos) */ - { - /* - * New range starts within or after old prep region. - * Trim search to start at end of old prep region. - */ - spos = prep_endpos; - } - } - - if (epos != NULL_POSITION && max_epos != NULL_POSITION && - epos > max_epos) - /* - * Don't go past the max position we're allowed. - */ - epos = max_epos; - - 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; - if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) - nprep_endpos = new_epos; - } - prep_startpos = nprep_startpos; - prep_endpos = nprep_endpos; -} -#endif - -/* - * Simple pattern matching function. - * It supports no metacharacters like *, etc. - */ - static int -match(pattern, pattern_len, buf, buf_len, pfound, pend) - char *pattern; - int pattern_len; - char *buf; - int buf_len; - char **pfound, **pend; -{ - register char *pp, *lp; - register char *pattern_end = pattern + pattern_len; - register char *buf_end = buf + buf_len; - - for ( ; buf < buf_end; buf++) - { - for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) - if (pp == pattern_end || lp == buf_end) - break; - if (pp == pattern_end) - { - if (pfound != NULL) - *pfound = buf; - if (pend != NULL) - *pend = lp; - return (1); - } - } - return (0); -} - -#if HAVE_V8_REGCOMP -/* - * This function is called by the V8 regcomp to report - * errors in regular expressions. - */ - void -regerror(s) - char *s; -{ - PARG parg; - - parg.p_string = s; - error("%s", &parg); -} -#endif - |