search.c revision 128348
160812Sps/* $FreeBSD: head/contrib/less/search.c 128348 2004-04-17 07:24:09Z tjr $ */
260786Sps/*
3128348Stjr * Copyright (C) 1984-2002  Mark Nudelman
460786Sps *
560786Sps * You may distribute under the terms of either the GNU General Public
660786Sps * License or the Less License, as specified in the README file.
760786Sps *
860786Sps * For more information about less, or for information on how to
960786Sps * contact the author, see the README file.
1060786Sps */
1160786Sps
1260786Sps
1360786Sps/*
1460786Sps * Routines to search a file for a pattern.
1560786Sps */
1660786Sps
1760786Sps#include "less.h"
1860786Sps#include "position.h"
1960786Sps
2060786Sps#define	MINPOS(a,b)	(((a) < (b)) ? (a) : (b))
2160786Sps#define	MAXPOS(a,b)	(((a) > (b)) ? (a) : (b))
2260786Sps
2360786Sps#if HAVE_POSIX_REGCOMP
2460786Sps#include <regex.h>
2560786Sps#ifdef REG_EXTENDED
2660812Sps#define	REGCOMP_FLAG	(more_mode ? 0 : REG_EXTENDED)
2760786Sps#else
2860786Sps#define	REGCOMP_FLAG	0
2960786Sps#endif
3060786Sps#endif
3160786Sps#if HAVE_PCRE
3260786Sps#include <pcre.h>
3360786Sps#endif
3460786Sps#if HAVE_RE_COMP
3560786Spschar *re_comp();
3660786Spsint re_exec();
3760786Sps#endif
3860786Sps#if HAVE_REGCMP
3960786Spschar *regcmp();
4060786Spschar *regex();
4160786Spsextern char *__loc1;
4260786Sps#endif
4360786Sps#if HAVE_V8_REGCOMP
4460786Sps#include "regexp.h"
4560786Sps#endif
4660786Sps
4760786Spsstatic int match();
4860786Sps
4960786Spsextern int sigs;
5060786Spsextern int how_search;
5160786Spsextern int caseless;
5260786Spsextern int linenums;
5360786Spsextern int sc_height;
5460786Spsextern int jump_sline;
5560786Spsextern int bs_mode;
5660812Spsextern int more_mode;
57128348Stjrextern int ctldisp;
5863131Spsextern int status_col;
5960786Spsextern POSITION start_attnpos;
6060786Spsextern POSITION end_attnpos;
6160786Sps#if HILITE_SEARCH
6260786Spsextern int hilite_search;
6360786Spsextern int screen_trashed;
6460786Spsextern int size_linebuf;
6560786Spsextern int squished;
6660786Spsextern int can_goto_line;
6760786Spsstatic int hide_hilite;
6860786Spsstatic POSITION prep_startpos;
6960786Spsstatic POSITION prep_endpos;
7060786Sps
7160786Spsstruct hilite
7260786Sps{
7360786Sps	struct hilite *hl_next;
7460786Sps	POSITION hl_startpos;
7560786Sps	POSITION hl_endpos;
7660786Sps};
7760786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
7860786Sps#define	hl_first	hl_next
7960786Sps#endif
8060786Sps
8160786Sps/*
8260786Sps * These are the static variables that represent the "remembered"
8360786Sps * search pattern.
8460786Sps */
8560786Sps#if HAVE_POSIX_REGCOMP
8660786Spsstatic regex_t *regpattern = NULL;
8760786Sps#endif
8860786Sps#if HAVE_PCRE
8960786Spspcre *regpattern = NULL;
9060786Sps#endif
9160786Sps#if HAVE_RE_COMP
9260786Spsint re_pattern = 0;
9360786Sps#endif
9460786Sps#if HAVE_REGCMP
9560786Spsstatic char *cpattern = NULL;
9660786Sps#endif
9760786Sps#if HAVE_V8_REGCOMP
9860786Spsstatic struct regexp *regpattern = NULL;
9960786Sps#endif
10060786Sps
10160786Spsstatic int is_caseless;
10260786Spsstatic int is_ucase_pattern;
10360786Spsstatic int last_search_type;
10460786Spsstatic char *last_pattern = NULL;
10560786Sps
10660786Sps/*
10760786Sps * Convert text.  Perform one or more of these transformations:
10860786Sps */
10960786Sps#define	CVT_TO_LC	01	/* Convert upper-case to lower-case */
11060786Sps#define	CVT_BS		02	/* Do backspace processing */
11160786Sps#define	CVT_CRLF	04	/* Remove CR after LF */
112128348Stjr#define	CVT_ANSI	010	/* Remove ANSI escape sequences */
11360786Sps
11460786Sps	static void
11560786Spscvt_text(odst, osrc, ops)
11660786Sps	char *odst;
11760786Sps	char *osrc;
11860786Sps	int ops;
11960786Sps{
12060786Sps	register char *dst;
12160786Sps	register char *src;
12260786Sps
123128348Stjr	for (src = osrc, dst = odst;  *src != '\0';  src++)
12460786Sps	{
12560786Sps		if ((ops & CVT_TO_LC) && isupper((unsigned char) *src))
12660786Sps			/* Convert uppercase to lowercase. */
127128348Stjr			*dst++ = tolower((unsigned char) *src);
12860786Sps		else if ((ops & CVT_BS) && *src == '\b' && dst > odst)
12960786Sps			/* Delete BS and preceding char. */
130128348Stjr			dst--;
131128348Stjr		else if ((ops & CVT_ANSI) && *src == ESC)
132128348Stjr		{
133128348Stjr			/* Skip to end of ANSI escape sequence. */
134128348Stjr			while (src[1] != '\0')
135128348Stjr				if (is_ansi_end(*++src))
136128348Stjr					break;
137128348Stjr		} else
13860786Sps			/* Just copy. */
139128348Stjr			*dst++ = *src;
14060786Sps	}
14160786Sps	if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
14260786Sps		dst--;
14360786Sps	*dst = '\0';
14460786Sps}
14560786Sps
14660786Sps/*
147128348Stjr * Determine which conversions to perform.
148128348Stjr */
149128348Stjr	static int
150128348Stjrget_cvt_ops()
151128348Stjr{
152128348Stjr	int ops = 0;
153128348Stjr	if (is_caseless || bs_mode == BS_SPECIAL)
154128348Stjr	{
155128348Stjr		if (is_caseless)
156128348Stjr			ops |= CVT_TO_LC;
157128348Stjr		if (bs_mode == BS_SPECIAL)
158128348Stjr			ops |= CVT_BS;
159128348Stjr		if (bs_mode != BS_CONTROL)
160128348Stjr			ops |= CVT_CRLF;
161128348Stjr	} else if (bs_mode != BS_CONTROL)
162128348Stjr	{
163128348Stjr		ops |= CVT_CRLF;
164128348Stjr	}
165128348Stjr	if (ctldisp == OPT_ONPLUS)
166128348Stjr		ops |= CVT_ANSI;
167128348Stjr	return (ops);
168128348Stjr}
169128348Stjr
170128348Stjr/*
17160786Sps * Are there any uppercase letters in this string?
17260786Sps */
17360786Sps	static int
17460786Spsis_ucase(s)
17560786Sps	char *s;
17660786Sps{
17760786Sps	register char *p;
17860786Sps
17960786Sps	for (p = s;  *p != '\0';  p++)
18060786Sps		if (isupper((unsigned char) *p))
18160786Sps			return (1);
18260786Sps	return (0);
18360786Sps}
18460786Sps
18560786Sps/*
18660786Sps * Is there a previous (remembered) search pattern?
18760786Sps */
18860786Sps	static int
18960786Spsprev_pattern()
19060786Sps{
19160786Sps	if (last_search_type & SRCH_NO_REGEX)
19260786Sps		return (last_pattern != NULL);
19360786Sps#if HAVE_POSIX_REGCOMP
19460786Sps	return (regpattern != NULL);
19560786Sps#endif
19660786Sps#if HAVE_PCRE
19760786Sps	return (regpattern != NULL);
19860786Sps#endif
19960786Sps#if HAVE_RE_COMP
20060786Sps	return (re_pattern != 0);
20160786Sps#endif
20260786Sps#if HAVE_REGCMP
20360786Sps	return (cpattern != NULL);
20460786Sps#endif
20560786Sps#if HAVE_V8_REGCOMP
20660786Sps	return (regpattern != NULL);
20760786Sps#endif
20860786Sps#if NO_REGEX
20960786Sps	return (last_pattern != NULL);
21060786Sps#endif
21160786Sps}
21260786Sps
21360786Sps#if HILITE_SEARCH
21460786Sps/*
21560786Sps * Repaint the hilites currently displayed on the screen.
21660786Sps * Repaint each line which contains highlighted text.
21760786Sps * If on==0, force all hilites off.
21860786Sps */
21960786Sps	public void
22060786Spsrepaint_hilite(on)
22160786Sps	int on;
22260786Sps{
22360786Sps	int slinenum;
22460786Sps	POSITION pos;
22560786Sps	POSITION epos;
22660786Sps	int save_hide_hilite;
22760786Sps
22860786Sps	if (squished)
22960786Sps		repaint();
23060786Sps
23160786Sps	save_hide_hilite = hide_hilite;
23260786Sps	if (!on)
23360786Sps	{
23460786Sps		if (hide_hilite)
23560786Sps			return;
23660786Sps		hide_hilite = 1;
23760786Sps	}
23860786Sps
23960786Sps	if (!can_goto_line)
24060786Sps	{
24160786Sps		repaint();
24260786Sps		hide_hilite = save_hide_hilite;
24360786Sps		return;
24460786Sps	}
24560786Sps
24660786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
24760786Sps	{
24860786Sps		pos = position(slinenum);
24960786Sps		if (pos == NULL_POSITION)
25060786Sps			continue;
25160786Sps		epos = position(slinenum+1);
25260786Sps		/*
25360786Sps		 * If any character in the line is highlighted,
25460786Sps		 * repaint the line.
25560786Sps		 */
25660786Sps		if (is_hilited(pos, epos, 1))
25760786Sps		{
25860786Sps			(void) forw_line(pos);
25960786Sps			goto_line(slinenum);
26060786Sps			put_line();
26160786Sps		}
26260786Sps	}
26360786Sps	hide_hilite = save_hide_hilite;
26460786Sps}
26560786Sps
26660786Sps/*
26760786Sps * Clear the attn hilite.
26860786Sps */
26960786Sps	public void
27060786Spsclear_attn()
27160786Sps{
27260786Sps	int slinenum;
27360786Sps	POSITION old_start_attnpos;
27460786Sps	POSITION old_end_attnpos;
27560786Sps	POSITION pos;
27660786Sps	POSITION epos;
27760786Sps
27860786Sps	if (start_attnpos == NULL_POSITION)
27960786Sps		return;
28060786Sps	old_start_attnpos = start_attnpos;
28160786Sps	old_end_attnpos = end_attnpos;
28260786Sps	start_attnpos = end_attnpos = NULL_POSITION;
28360786Sps
28460786Sps	if (!can_goto_line)
28560786Sps	{
28660786Sps		repaint();
28760786Sps		return;
28860786Sps	}
28960786Sps	if (squished)
29060786Sps		repaint();
29160786Sps
29260786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
29360786Sps	{
29460786Sps		pos = position(slinenum);
29560786Sps		if (pos == NULL_POSITION)
29660786Sps			continue;
29760786Sps		epos = position(slinenum+1);
29860786Sps		if (pos < old_end_attnpos &&
29960786Sps		     (epos == NULL_POSITION || epos > old_start_attnpos))
30060786Sps		{
30160786Sps			(void) forw_line(pos);
30260786Sps			goto_line(slinenum);
30360786Sps			put_line();
30460786Sps		}
30560786Sps	}
30660786Sps}
30760786Sps#endif
30860786Sps
30960786Sps/*
31060786Sps * Hide search string highlighting.
31160786Sps */
31260786Sps	public void
31360786Spsundo_search()
31460786Sps{
31560786Sps	if (!prev_pattern())
31660786Sps	{
31760786Sps		error("No previous regular expression", NULL_PARG);
31860786Sps		return;
31960786Sps	}
32060786Sps#if HILITE_SEARCH
32160786Sps	hide_hilite = !hide_hilite;
32260786Sps	repaint_hilite(1);
32360786Sps#endif
32460786Sps}
32560786Sps
32660786Sps/*
32760786Sps * Compile a search pattern, for future use by match_pattern.
32860786Sps */
32960786Sps	static int
33060786Spscompile_pattern(pattern, search_type)
33160786Sps	char *pattern;
33260786Sps	int search_type;
33360786Sps{
33460786Sps	if ((search_type & SRCH_NO_REGEX) == 0)
33560786Sps	{
33660786Sps#if HAVE_POSIX_REGCOMP
33760786Sps		regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
33860786Sps		if (regcomp(s, pattern, REGCOMP_FLAG))
33960786Sps		{
34060786Sps			free(s);
34160786Sps			error("Invalid pattern", NULL_PARG);
34260786Sps			return (-1);
34360786Sps		}
34460786Sps		if (regpattern != NULL)
34560786Sps			regfree(regpattern);
34660786Sps		regpattern = s;
34760786Sps#endif
34860786Sps#if HAVE_PCRE
34960786Sps		pcre *comp;
35060786Sps		const char *errstring;
35160786Sps		int erroffset;
35260786Sps		PARG parg;
35360786Sps		comp = pcre_compile(pattern, 0,
35460786Sps				&errstring, &erroffset, NULL);
35560786Sps		if (comp == NULL)
35660786Sps		{
35760786Sps			parg.p_string = (char *) errstring;
35860786Sps			error("%s", &parg);
35960786Sps			return (-1);
36060786Sps		}
36160786Sps		regpattern = comp;
36260786Sps#endif
36360786Sps#if HAVE_RE_COMP
36460786Sps		PARG parg;
36560786Sps		if ((parg.p_string = re_comp(pattern)) != NULL)
36660786Sps		{
36760786Sps			error("%s", &parg);
36860786Sps			return (-1);
36960786Sps		}
37060786Sps		re_pattern = 1;
37160786Sps#endif
37260786Sps#if HAVE_REGCMP
37360786Sps		char *s;
37460786Sps		if ((s = regcmp(pattern, 0)) == NULL)
37560786Sps		{
37660786Sps			error("Invalid pattern", NULL_PARG);
37760786Sps			return (-1);
37860786Sps		}
37960786Sps		if (cpattern != NULL)
38060786Sps			free(cpattern);
38160786Sps		cpattern = s;
38260786Sps#endif
38360786Sps#if HAVE_V8_REGCOMP
38460786Sps		struct regexp *s;
38560786Sps		if ((s = regcomp(pattern)) == NULL)
38660786Sps		{
38760786Sps			/*
38860786Sps			 * regcomp has already printed an error message
38960786Sps			 * via regerror().
39060786Sps			 */
39160786Sps			return (-1);
39260786Sps		}
39360786Sps		if (regpattern != NULL)
39460786Sps			free(regpattern);
39560786Sps		regpattern = s;
39660786Sps#endif
39760786Sps	}
39860786Sps
39960786Sps	if (last_pattern != NULL)
40060786Sps		free(last_pattern);
40160786Sps	last_pattern = (char *) calloc(1, strlen(pattern)+1);
40260786Sps	if (last_pattern != NULL)
40360786Sps		strcpy(last_pattern, pattern);
40460786Sps
40560786Sps	last_search_type = search_type;
40660786Sps	return (0);
40760786Sps}
40860786Sps
40960786Sps/*
41060786Sps * Forget that we have a compiled pattern.
41160786Sps */
41260786Sps	static void
41360786Spsuncompile_pattern()
41460786Sps{
41560786Sps#if HAVE_POSIX_REGCOMP
41660786Sps	if (regpattern != NULL)
41760786Sps		regfree(regpattern);
41860786Sps	regpattern = NULL;
41960786Sps#endif
42060786Sps#if HAVE_PCRE
42160786Sps	if (regpattern != NULL)
42260786Sps		pcre_free(regpattern);
42360786Sps	regpattern = NULL;
42460786Sps#endif
42560786Sps#if HAVE_RE_COMP
42660786Sps	re_pattern = 0;
42760786Sps#endif
42860786Sps#if HAVE_REGCMP
42960786Sps	if (cpattern != NULL)
43060786Sps		free(cpattern);
43160786Sps	cpattern = NULL;
43260786Sps#endif
43360786Sps#if HAVE_V8_REGCOMP
43460786Sps	if (regpattern != NULL)
43560786Sps		free(regpattern);
43660786Sps	regpattern = NULL;
43760786Sps#endif
43860786Sps	last_pattern = NULL;
43960786Sps}
44060786Sps
44160786Sps/*
44260786Sps * Perform a pattern match with the previously compiled pattern.
44360786Sps * Set sp and ep to the start and end of the matched string.
44460786Sps */
44560786Sps	static int
44660786Spsmatch_pattern(line, sp, ep, notbol)
44760786Sps	char *line;
44860786Sps	char **sp;
44960786Sps	char **ep;
45060786Sps	int notbol;
45160786Sps{
45260786Sps	int matched;
45360786Sps
45460786Sps	if (last_search_type & SRCH_NO_REGEX)
45560786Sps		return (match(last_pattern, line, sp, ep));
45660786Sps
45760786Sps#if HAVE_POSIX_REGCOMP
45860786Sps	{
45960786Sps		regmatch_t rm;
46060786Sps		int flags = (notbol) ? REG_NOTBOL : 0;
46160786Sps		matched = !regexec(regpattern, line, 1, &rm, flags);
46260786Sps		if (!matched)
46360786Sps			return (0);
46460786Sps#ifndef __WATCOMC__
46560786Sps		*sp = line + rm.rm_so;
46660786Sps		*ep = line + rm.rm_eo;
46760786Sps#else
46860786Sps		*sp = rm.rm_sp;
46960786Sps		*ep = rm.rm_ep;
47060786Sps#endif
47160786Sps	}
47260786Sps#endif
47360786Sps#if HAVE_PCRE
47460786Sps	{
47560786Sps		int flags = (notbol) ? PCRE_NOTBOL : 0;
47660786Sps		int ovector[3];
47760786Sps		matched = pcre_exec(regpattern, NULL, line, strlen(line),
47860786Sps			0, flags, ovector, 3) >= 0;
47960786Sps		if (!matched)
48060786Sps			return (0);
48160786Sps		*sp = line + ovector[0];
48260786Sps		*ep = line + ovector[1];
48360786Sps	}
48460786Sps#endif
48560786Sps#if HAVE_RE_COMP
48660786Sps	matched = (re_exec(line) == 1);
48760786Sps	/*
48860786Sps	 * re_exec doesn't seem to provide a way to get the matched string.
48960786Sps	 */
49060786Sps	*sp = *ep = NULL;
49160786Sps#endif
49260786Sps#if HAVE_REGCMP
49360786Sps	*ep = regex(cpattern, line);
49460786Sps	matched = (*ep != NULL);
49560786Sps	if (!matched)
49660786Sps		return (0);
49760786Sps	*sp = __loc1;
49860786Sps#endif
49960786Sps#if HAVE_V8_REGCOMP
50060786Sps#if HAVE_REGEXEC2
50160786Sps	matched = regexec2(regpattern, line, notbol);
50260786Sps#else
50360786Sps	matched = regexec(regpattern, line);
50460786Sps#endif
50560786Sps	if (!matched)
50660786Sps		return (0);
50760786Sps	*sp = regpattern->startp[0];
50860786Sps	*ep = regpattern->endp[0];
50960786Sps#endif
51060786Sps#if NO_REGEX
51160786Sps	matched = match(last_pattern, line, sp, ep);
51260786Sps#endif
51360786Sps	return (matched);
51460786Sps}
51560786Sps
51660786Sps#if HILITE_SEARCH
51760786Sps/*
51860786Sps * Clear the hilite list.
51960786Sps */
52060786Sps	public void
52160786Spsclr_hilite()
52260786Sps{
52360786Sps	struct hilite *hl;
52460786Sps	struct hilite *nexthl;
52560786Sps
52660786Sps	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = nexthl)
52760786Sps	{
52860786Sps		nexthl = hl->hl_next;
52960786Sps		free((void*)hl);
53060786Sps	}
53160786Sps	hilite_anchor.hl_first = NULL;
53260786Sps	prep_startpos = prep_endpos = NULL_POSITION;
53360786Sps}
53460786Sps
53560786Sps/*
53660786Sps * Should any characters in a specified range be highlighted?
53760786Sps * If nohide is nonzero, don't consider hide_hilite.
53860786Sps */
53960786Sps	public int
54060786Spsis_hilited(pos, epos, nohide)
54160786Sps	POSITION pos;
54260786Sps	POSITION epos;
54360786Sps	int nohide;
54460786Sps{
54560786Sps	struct hilite *hl;
54660786Sps
54763131Sps	if (!status_col &&
54863131Sps	    start_attnpos != NULL_POSITION &&
54960786Sps	    pos < end_attnpos &&
55060786Sps	     (epos == NULL_POSITION || epos > start_attnpos))
55160786Sps		/*
55260786Sps		 * The attn line overlaps this range.
55360786Sps		 */
55460786Sps		return (1);
55560786Sps
55660786Sps	if (hilite_search == 0)
55760786Sps		/*
55860786Sps		 * Not doing highlighting.
55960786Sps		 */
56060786Sps		return (0);
56160786Sps
56260786Sps	if (!nohide && hide_hilite)
56360786Sps		/*
56460786Sps		 * Highlighting is hidden.
56560786Sps		 */
56660786Sps		return (0);
56760786Sps
56860786Sps	/*
56960786Sps	 * Look at each highlight and see if any part of it falls in the range.
57060786Sps	 */
57160786Sps	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
57260786Sps	{
57360786Sps		if (hl->hl_endpos > pos &&
57460786Sps		    (epos == NULL_POSITION || epos > hl->hl_startpos))
57560786Sps			return (1);
57660786Sps	}
57760786Sps	return (0);
57860786Sps}
57960786Sps
58060786Sps/*
58160786Sps * Add a new hilite to a hilite list.
58260786Sps */
58360786Sps	static void
58460786Spsadd_hilite(anchor, hl)
58560786Sps	struct hilite *anchor;
58660786Sps	struct hilite *hl;
58760786Sps{
58860786Sps	struct hilite *ihl;
58960786Sps
59060786Sps	/*
59160786Sps	 * Hilites are sorted in the list; find where new one belongs.
59260786Sps	 * Insert new one after ihl.
59360786Sps	 */
59460786Sps	for (ihl = anchor;  ihl->hl_next != NULL;  ihl = ihl->hl_next)
59560786Sps	{
59660786Sps		if (ihl->hl_next->hl_startpos > hl->hl_startpos)
59760786Sps			break;
59860786Sps	}
59960786Sps
60060786Sps	/*
60160786Sps	 * Truncate hilite so it doesn't overlap any existing ones
60260786Sps	 * above and below it.
60360786Sps	 */
60460786Sps	if (ihl != anchor)
60560786Sps		hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
60660786Sps	if (ihl->hl_next != NULL)
60760786Sps		hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
60860786Sps	if (hl->hl_startpos >= hl->hl_endpos)
60960786Sps	{
61060786Sps		/*
61160786Sps		 * Hilite was truncated out of existence.
61260786Sps		 */
61360786Sps		free(hl);
61460786Sps		return;
61560786Sps	}
61660786Sps	hl->hl_next = ihl->hl_next;
61760786Sps	ihl->hl_next = hl;
61860786Sps}
61960786Sps
62060786Sps/*
62160786Sps * Adjust hl_startpos & hl_endpos to account for backspace processing.
62260786Sps */
62360786Sps	static void
624128348Stjradj_hilite(anchor, linepos, cvt_ops)
62560786Sps	struct hilite *anchor;
62660786Sps	POSITION linepos;
627128348Stjr	int cvt_ops;
62860786Sps{
62960786Sps	char *line;
63060786Sps	struct hilite *hl;
63160786Sps	int checkstart;
63260786Sps	POSITION opos;
63360786Sps	POSITION npos;
63460786Sps
63560786Sps	/*
63660786Sps	 * The line was already scanned and hilites were added (in hilite_line).
63760786Sps	 * But it was assumed that each char position in the line
63860786Sps	 * correponds to one char position in the file.
63960786Sps	 * This may not be true if there are backspaces in the line.
64060786Sps	 * Get the raw line again.  Look at each character.
64160786Sps	 */
64260786Sps	(void) forw_raw_line(linepos, &line);
64360786Sps	opos = npos = linepos;
64460786Sps	hl = anchor->hl_first;
64560786Sps	checkstart = TRUE;
64660786Sps	while (hl != NULL)
64760786Sps	{
64860786Sps		/*
64960786Sps		 * See if we need to adjust the current hl_startpos or
65060786Sps		 * hl_endpos.  After adjusting startpos[i], move to endpos[i].
65160786Sps		 * After adjusting endpos[i], move to startpos[i+1].
65260786Sps		 * The hilite list must be sorted thus:
65360786Sps		 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
65460786Sps		 */
65560786Sps		if (checkstart && hl->hl_startpos == opos)
65660786Sps		{
65760786Sps			hl->hl_startpos = npos;
65860786Sps			checkstart = FALSE;
65960786Sps			continue; /* {{ not really necessary }} */
66060786Sps		} else if (!checkstart && hl->hl_endpos == opos)
66160786Sps		{
66260786Sps			hl->hl_endpos = npos;
66360786Sps			checkstart = TRUE;
66460786Sps			hl = hl->hl_next;
66560786Sps			continue; /* {{ necessary }} */
66660786Sps		}
66760786Sps		if (*line == '\0')
66860786Sps			break;
669128348Stjr		if (cvt_ops & CVT_ANSI)
670128348Stjr		{
671128348Stjr			while (line[0] == ESC)
672128348Stjr			{
673128348Stjr				/*
674128348Stjr				 * Found an ESC.  The file position moves
675128348Stjr				 * forward past the entire ANSI escape sequence.
676128348Stjr				 */
677128348Stjr				line++;
678128348Stjr				npos++;
679128348Stjr				while (*line != '\0')
680128348Stjr				{
681128348Stjr					npos++;
682128348Stjr					if (is_ansi_end(*line++))
683128348Stjr						break;
684128348Stjr				}
685128348Stjr			}
686128348Stjr		}
68760786Sps		opos++;
68860786Sps		npos++;
68960786Sps		line++;
690128348Stjr		if (cvt_ops & CVT_BS)
69160786Sps		{
692128348Stjr			while (line[0] == '\b' && line[1] != '\0')
693128348Stjr			{
694128348Stjr				/*
695128348Stjr				 * Found a backspace.  The file position moves
696128348Stjr				 * forward by 2 relative to the processed line
697128348Stjr				 * which was searched in hilite_line.
698128348Stjr				 */
699128348Stjr				npos += 2;
700128348Stjr				line += 2;
701128348Stjr			}
70260786Sps		}
70360786Sps	}
70460786Sps}
70560786Sps
70660786Sps/*
70760786Sps * Make a hilite for each string in a physical line which matches
70860786Sps * the current pattern.
70960786Sps * sp,ep delimit the first match already found.
71060786Sps */
71160786Sps	static void
712128348Stjrhilite_line(linepos, line, sp, ep, cvt_ops)
71360786Sps	POSITION linepos;
71460786Sps	char *line;
71560786Sps	char *sp;
71660786Sps	char *ep;
717128348Stjr	int cvt_ops;
71860786Sps{
71960786Sps	char *searchp;
72060786Sps	struct hilite *hl;
72160786Sps	struct hilite hilites;
72260786Sps
72360786Sps	if (sp == NULL || ep == NULL)
72460786Sps		return;
72560786Sps	/*
72660786Sps	 * sp and ep delimit the first match in the line.
72760786Sps	 * Mark the corresponding file positions, then
72860786Sps	 * look for further matches and mark them.
72960786Sps	 * {{ This technique, of calling match_pattern on subsequent
73060786Sps	 *    substrings of the line, may mark more than is correct
73160786Sps	 *    if the pattern starts with "^".  This bug is fixed
73260786Sps	 *    for those regex functions that accept a notbol parameter
73360786Sps	 *    (currently POSIX and V8-with-regexec2). }}
73460786Sps	 */
73560786Sps	searchp = line;
73660786Sps	/*
73760786Sps	 * Put the hilites into a temporary list until they're adjusted.
73860786Sps	 */
73960786Sps	hilites.hl_first = NULL;
74060786Sps	do {
74160786Sps		if (ep > sp)
74260786Sps		{
74360786Sps			/*
74460786Sps			 * Assume that each char position in the "line"
74560786Sps			 * buffer corresponds to one char position in the file.
74660786Sps			 * This is not quite true; we need to adjust later.
74760786Sps			 */
74860786Sps			hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
74960786Sps			hl->hl_startpos = linepos + (sp-line);
75060786Sps			hl->hl_endpos = linepos + (ep-line);
75160786Sps			add_hilite(&hilites, hl);
75260786Sps		}
75360786Sps		/*
75460786Sps		 * If we matched more than zero characters,
75560786Sps		 * move to the first char after the string we matched.
75660786Sps		 * If we matched zero, just move to the next char.
75760786Sps		 */
75860786Sps		if (ep > searchp)
75960786Sps			searchp = ep;
76060786Sps		else if (*searchp != '\0')
76160786Sps			searchp++;
76260786Sps		else /* end of line */
76360786Sps			break;
76460786Sps	} while (match_pattern(searchp, &sp, &ep, 1));
76560786Sps
76660786Sps	/*
767128348Stjr	 * If there were backspaces in the original line, they
768128348Stjr	 * were removed, and hl_startpos/hl_endpos are not correct.
769128348Stjr	 * {{ This is very ugly. }}
770128348Stjr	 */
771128348Stjr	adj_hilite(&hilites, linepos, cvt_ops);
772128348Stjr
773128348Stjr	/*
77460786Sps	 * Now put the hilites into the real list.
77560786Sps	 */
77660786Sps	while ((hl = hilites.hl_next) != NULL)
77760786Sps	{
77860786Sps		hilites.hl_next = hl->hl_next;
77960786Sps		add_hilite(&hilite_anchor, hl);
78060786Sps	}
78160786Sps}
78260786Sps#endif
78360786Sps
78460786Sps/*
78560786Sps * Change the caseless-ness of searches.
78660786Sps * Updates the internal search state to reflect a change in the -i flag.
78760786Sps */
78860786Sps	public void
78960786Spschg_caseless()
79060786Sps{
79160786Sps	if (!is_ucase_pattern)
79260786Sps		/*
79360786Sps		 * Pattern did not have uppercase.
79460786Sps		 * Just set the search caselessness to the global caselessness.
79560786Sps		 */
79660786Sps		is_caseless = caseless;
79760786Sps	else
79860786Sps		/*
79960786Sps		 * Pattern did have uppercase.
80060786Sps		 * Discard the pattern; we can't change search caselessness now.
80160786Sps		 */
80260786Sps		uncompile_pattern();
80360786Sps}
80460786Sps
80560786Sps#if HILITE_SEARCH
80660786Sps/*
80760786Sps * Find matching text which is currently on screen and highlight it.
80860786Sps */
80960786Sps	static void
81060786Spshilite_screen()
81160786Sps{
81260786Sps	struct scrpos scrpos;
81360786Sps
81460786Sps	get_scrpos(&scrpos);
81560786Sps	if (scrpos.pos == NULL_POSITION)
81660786Sps		return;
81760786Sps	prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
81860786Sps	repaint_hilite(1);
81960786Sps}
82060786Sps
82160786Sps/*
82260786Sps * Change highlighting parameters.
82360786Sps */
82460786Sps	public void
82560786Spschg_hilite()
82660786Sps{
82760786Sps	/*
82860786Sps	 * Erase any highlights currently on screen.
82960786Sps	 */
83060786Sps	clr_hilite();
83160786Sps	hide_hilite = 0;
83260786Sps
83360786Sps	if (hilite_search == OPT_ONPLUS)
83460786Sps		/*
83560786Sps		 * Display highlights.
83660786Sps		 */
83760786Sps		hilite_screen();
83860786Sps}
83960786Sps#endif
84060786Sps
84160786Sps/*
84260786Sps * Figure out where to start a search.
84360786Sps */
84460786Sps	static POSITION
84560786Spssearch_pos(search_type)
84660786Sps	int search_type;
84760786Sps{
84860786Sps	POSITION pos;
84960786Sps	int linenum;
85060786Sps
85160786Sps	if (empty_screen())
85260786Sps	{
85360786Sps		/*
85460786Sps		 * Start at the beginning (or end) of the file.
85560786Sps		 * The empty_screen() case is mainly for
85660786Sps		 * command line initiated searches;
85760786Sps		 * for example, "+/xyz" on the command line.
85860786Sps		 * Also for multi-file (SRCH_PAST_EOF) searches.
85960786Sps		 */
86060786Sps		if (search_type & SRCH_FORW)
86160786Sps		{
86260786Sps			return (ch_zero());
86360786Sps		} else
86460786Sps		{
86560786Sps			pos = ch_length();
86660786Sps			if (pos == NULL_POSITION)
86760786Sps			{
86860786Sps				(void) ch_end_seek();
86960786Sps				pos = ch_length();
87060786Sps			}
87160786Sps			return (pos);
87260786Sps		}
87360786Sps	}
87460786Sps	if (how_search)
87560786Sps	{
87660786Sps		/*
87760786Sps		 * Search does not include current screen.
87860786Sps		 */
87960786Sps		if (search_type & SRCH_FORW)
88060786Sps			linenum = BOTTOM_PLUS_ONE;
88160786Sps		else
88260786Sps			linenum = TOP;
88360786Sps		pos = position(linenum);
88460786Sps	} else
88560786Sps	{
88660786Sps		/*
88760786Sps		 * Search includes current screen.
88860786Sps		 * It starts at the jump target (if searching backwards),
88960786Sps		 * or at the jump target plus one (if forwards).
89060786Sps		 */
89160786Sps		linenum = adjsline(jump_sline);
89260786Sps		pos = position(linenum);
89360786Sps		if (search_type & SRCH_FORW)
89460786Sps		{
89560786Sps			pos = forw_raw_line(pos, (char **)NULL);
89660786Sps			while (pos == NULL_POSITION)
89760786Sps			{
89860786Sps				if (++linenum >= sc_height)
89960786Sps					break;
90060786Sps				pos = position(linenum);
90160786Sps			}
90260786Sps		} else
90360786Sps		{
90460786Sps			while (pos == NULL_POSITION)
90560786Sps			{
90660786Sps				if (--linenum < 0)
90760786Sps					break;
90860786Sps				pos = position(linenum);
90960786Sps			}
91060786Sps		}
91160786Sps	}
91260786Sps	return (pos);
91360786Sps}
91460786Sps
91560786Sps/*
91660786Sps * Search a subset of the file, specified by start/end position.
91760786Sps */
91860786Sps	static int
91960786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
92060786Sps	POSITION pos;
92160786Sps	POSITION endpos;
92260786Sps	int search_type;
92360786Sps	int matches;
92460786Sps	int maxlines;
92560786Sps	POSITION *plinepos;
92660786Sps	POSITION *pendpos;
92760786Sps{
92860786Sps	char *line;
929128348Stjr	LINENUM linenum;
93060786Sps	char *sp, *ep;
93160786Sps	int line_match;
932128348Stjr	int cvt_ops;
93360786Sps	POSITION linepos, oldpos;
93460786Sps
93560786Sps	linenum = find_linenum(pos);
93660786Sps	oldpos = pos;
93760786Sps	for (;;)
93860786Sps	{
93960786Sps		/*
94060786Sps		 * Get lines until we find a matching one or until
94160786Sps		 * we hit end-of-file (or beginning-of-file if we're
94260786Sps		 * going backwards), or until we hit the end position.
94360786Sps		 */
94460786Sps		if (ABORT_SIGS())
94560786Sps		{
94660786Sps			/*
94760786Sps			 * A signal aborts the search.
94860786Sps			 */
94960786Sps			return (-1);
95060786Sps		}
95160786Sps
95260786Sps		if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
95360786Sps		{
95460786Sps			/*
95560786Sps			 * Reached end position without a match.
95660786Sps			 */
95760786Sps			if (pendpos != NULL)
95860786Sps				*pendpos = pos;
95960786Sps			return (matches);
96060786Sps		}
96160786Sps		if (maxlines > 0)
96260786Sps			maxlines--;
96360786Sps
96460786Sps		if (search_type & SRCH_FORW)
96560786Sps		{
96660786Sps			/*
96760786Sps			 * Read the next line, and save the
96860786Sps			 * starting position of that line in linepos.
96960786Sps			 */
97060786Sps			linepos = pos;
97160786Sps			pos = forw_raw_line(pos, &line);
97260786Sps			if (linenum != 0)
97360786Sps				linenum++;
97460786Sps		} else
97560786Sps		{
97660786Sps			/*
97760786Sps			 * Read the previous line and save the
97860786Sps			 * starting position of that line in linepos.
97960786Sps			 */
98060786Sps			pos = back_raw_line(pos, &line);
98160786Sps			linepos = pos;
98260786Sps			if (linenum != 0)
98360786Sps				linenum--;
98460786Sps		}
98560786Sps
98660786Sps		if (pos == NULL_POSITION)
98760786Sps		{
98860786Sps			/*
98960786Sps			 * Reached EOF/BOF without a match.
99060786Sps			 */
99160786Sps			if (pendpos != NULL)
99260786Sps				*pendpos = oldpos;
99360786Sps			return (matches);
99460786Sps		}
99560786Sps
99660786Sps		/*
99760786Sps		 * If we're using line numbers, we might as well
99860786Sps		 * remember the information we have now (the position
99960786Sps		 * and line number of the current line).
100060786Sps		 * Don't do it for every line because it slows down
100160786Sps		 * the search.  Remember the line number only if
100260786Sps		 * we're "far" from the last place we remembered it.
100360786Sps		 */
100460786Sps		if (linenums && abs((int)(pos - oldpos)) > 1024)
100560786Sps			add_lnum(linenum, pos);
100660786Sps		oldpos = pos;
100760786Sps
100860786Sps		/*
100960786Sps		 * If it's a caseless search, convert the line to lowercase.
101060786Sps		 * If we're doing backspace processing, delete backspaces.
101160786Sps		 */
1012128348Stjr		cvt_ops = get_cvt_ops();
1013128348Stjr		cvt_text(line, line, cvt_ops);
101460786Sps
101560786Sps		/*
101660786Sps		 * Test the next line to see if we have a match.
101760786Sps		 * We are successful if we either want a match and got one,
101860786Sps		 * or if we want a non-match and got one.
101960786Sps		 */
102060786Sps		line_match = match_pattern(line, &sp, &ep, 0);
102160786Sps		line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
102260786Sps				((search_type & SRCH_NO_MATCH) && !line_match);
102360786Sps		if (!line_match)
102460786Sps			continue;
102560786Sps		/*
102660786Sps		 * Got a match.
102760786Sps		 */
102860786Sps		if (search_type & SRCH_FIND_ALL)
102960786Sps		{
103060786Sps#if HILITE_SEARCH
103160786Sps			/*
103260786Sps			 * We are supposed to find all matches in the range.
103360786Sps			 * Just add the matches in this line to the
103460786Sps			 * hilite list and keep searching.
103560786Sps			 */
103660786Sps			if (line_match)
1037128348Stjr				hilite_line(linepos, line, sp, ep, cvt_ops);
103860786Sps#endif
103960786Sps		} else if (--matches <= 0)
104060786Sps		{
104160786Sps			/*
104260786Sps			 * Found the one match we're looking for.
104360786Sps			 * Return it.
104460786Sps			 */
104560786Sps#if HILITE_SEARCH
104660786Sps			if (hilite_search == 1)
104760786Sps			{
104860786Sps				/*
104960786Sps				 * Clear the hilite list and add only
105060786Sps				 * the matches in this one line.
105160786Sps				 */
105260786Sps				clr_hilite();
105360786Sps				if (line_match)
1054128348Stjr					hilite_line(linepos, line, sp, ep, cvt_ops);
105560786Sps			}
105660786Sps#endif
105760786Sps			if (plinepos != NULL)
105860786Sps				*plinepos = linepos;
105960786Sps			return (0);
106060786Sps		}
106160786Sps	}
106260786Sps}
106360786Sps
106460786Sps/*
106560786Sps * Search for the n-th occurrence of a specified pattern,
106660786Sps * either forward or backward.
106760786Sps * Return the number of matches not yet found in this file
106860786Sps * (that is, n minus the number of matches found).
106960786Sps * Return -1 if the search should be aborted.
107060786Sps * Caller may continue the search in another file
107160786Sps * if less than n matches are found in this file.
107260786Sps */
107360786Sps	public int
107460786Spssearch(search_type, pattern, n)
107560786Sps	int search_type;
107660786Sps	char *pattern;
107760786Sps	int n;
107860786Sps{
107960786Sps	POSITION pos;
108060786Sps	int ucase;
108160786Sps
108260786Sps	if (pattern == NULL || *pattern == '\0')
108360786Sps	{
108460786Sps		/*
108560786Sps		 * A null pattern means use the previously compiled pattern.
108660786Sps		 */
108760786Sps		if (!prev_pattern())
108860786Sps		{
108960786Sps			error("No previous regular expression", NULL_PARG);
109060786Sps			return (-1);
109160786Sps		}
109260786Sps		if ((search_type & SRCH_NO_REGEX) !=
109360786Sps		    (last_search_type & SRCH_NO_REGEX))
109460786Sps		{
109560786Sps			error("Please re-enter search pattern", NULL_PARG);
109660786Sps			return -1;
109760786Sps		}
109860786Sps#if HILITE_SEARCH
109960786Sps		if (hilite_search == OPT_ON)
110060786Sps		{
110160786Sps			/*
110260786Sps			 * Erase the highlights currently on screen.
110360786Sps			 * If the search fails, we'll redisplay them later.
110460786Sps			 */
110560786Sps			repaint_hilite(0);
110660786Sps		}
110760786Sps		if (hilite_search == OPT_ONPLUS && hide_hilite)
110860786Sps		{
110960786Sps			/*
111060786Sps			 * Highlight any matches currently on screen,
111160786Sps			 * before we actually start the search.
111260786Sps			 */
111360786Sps			hide_hilite = 0;
111460786Sps			hilite_screen();
111560786Sps		}
111660786Sps		hide_hilite = 0;
111760786Sps#endif
111860786Sps	} else
111960786Sps	{
112060786Sps		/*
112160786Sps		 * Compile the pattern.
112260786Sps		 */
112360786Sps		ucase = is_ucase(pattern);
112460786Sps		if (caseless == OPT_ONPLUS)
112560786Sps			cvt_text(pattern, pattern, CVT_TO_LC);
112660786Sps		if (compile_pattern(pattern, search_type) < 0)
112760786Sps			return (-1);
112860786Sps		/*
112960786Sps		 * Ignore case if -I is set OR
113060786Sps		 * -i is set AND the pattern is all lowercase.
113160786Sps		 */
113260786Sps		is_ucase_pattern = ucase;
113360786Sps		if (is_ucase_pattern && caseless != OPT_ONPLUS)
113460786Sps			is_caseless = 0;
113560786Sps		else
113660786Sps			is_caseless = caseless;
113760786Sps#if HILITE_SEARCH
113860786Sps		if (hilite_search)
113960786Sps		{
114060786Sps			/*
114160786Sps			 * Erase the highlights currently on screen.
114260786Sps			 * Also permanently delete them from the hilite list.
114360786Sps			 */
114460786Sps			repaint_hilite(0);
114560786Sps			hide_hilite = 0;
114660786Sps			clr_hilite();
114760786Sps		}
114860786Sps		if (hilite_search == OPT_ONPLUS)
114960786Sps		{
115060786Sps			/*
115160786Sps			 * Highlight any matches currently on screen,
115260786Sps			 * before we actually start the search.
115360786Sps			 */
115460786Sps			hilite_screen();
115560786Sps		}
115660786Sps#endif
115760786Sps	}
115860786Sps
115960786Sps	/*
116060786Sps	 * Figure out where to start the search.
116160786Sps	 */
116260786Sps	pos = search_pos(search_type);
116360786Sps	if (pos == NULL_POSITION)
116460786Sps	{
116560786Sps		/*
116660786Sps		 * Can't find anyplace to start searching from.
116760786Sps		 */
116860786Sps		if (search_type & SRCH_PAST_EOF)
116960786Sps			return (n);
117060786Sps		/* repaint(); -- why was this here? */
117160786Sps		error("Nothing to search", NULL_PARG);
117260786Sps		return (-1);
117360786Sps	}
117460786Sps
117560786Sps	n = search_range(pos, NULL_POSITION, search_type, n, -1,
117660786Sps			&pos, (POSITION*)NULL);
117760786Sps	if (n != 0)
117860786Sps	{
117960786Sps		/*
118060786Sps		 * Search was unsuccessful.
118160786Sps		 */
118260786Sps#if HILITE_SEARCH
118360786Sps		if (hilite_search == OPT_ON && n > 0)
118460786Sps			/*
118560786Sps			 * Redisplay old hilites.
118660786Sps			 */
118760786Sps			repaint_hilite(1);
118860786Sps#endif
118960786Sps		return (n);
119060786Sps	}
119160786Sps
119260786Sps	if (!(search_type & SRCH_NO_MOVE))
119360786Sps	{
119460786Sps		/*
119560786Sps		 * Go to the matching line.
119660786Sps		 */
119760786Sps		jump_loc(pos, jump_sline);
119860786Sps	}
119960786Sps
120060786Sps#if HILITE_SEARCH
120160786Sps	if (hilite_search == OPT_ON)
120260786Sps		/*
120360786Sps		 * Display new hilites in the matching line.
120460786Sps		 */
120560786Sps		repaint_hilite(1);
120660786Sps#endif
120760786Sps	return (0);
120860786Sps}
120960786Sps
121060786Sps
121160786Sps#if HILITE_SEARCH
121260786Sps/*
121360786Sps * Prepare hilites in a given range of the file.
121460786Sps *
121560786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region
121660786Sps * of the file that has been "prepared"; that is, scanned for matches for
121760786Sps * the current search pattern, and hilites have been created for such matches.
121860786Sps * If prep_startpos == NULL_POSITION, the prep region is empty.
121960786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
122060786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region.
122160786Sps */
122260786Sps	public void
122360786Spsprep_hilite(spos, epos, maxlines)
122460786Sps	POSITION spos;
122560786Sps	POSITION epos;
122660786Sps	int maxlines;
122760786Sps{
122860786Sps	POSITION nprep_startpos = prep_startpos;
122960786Sps	POSITION nprep_endpos = prep_endpos;
123060786Sps	POSITION new_epos;
123160786Sps	POSITION max_epos;
123260786Sps	int result;
123360786Sps	int i;
123460786Sps/*
123560786Sps * Search beyond where we're asked to search, so the prep region covers
123660786Sps * more than we need.  Do one big search instead of a bunch of small ones.
123760786Sps */
123860786Sps#define	SEARCH_MORE (3*size_linebuf)
123960786Sps
124060786Sps	if (!prev_pattern())
124160786Sps		return;
124260786Sps
124360786Sps	/*
124460786Sps	 * If we're limited to a max number of lines, figure out the
124560786Sps	 * file position we should stop at.
124660786Sps	 */
124760786Sps	if (maxlines < 0)
124860786Sps		max_epos = NULL_POSITION;
124960786Sps	else
125060786Sps	{
125160786Sps		max_epos = spos;
125260786Sps		for (i = 0;  i < maxlines;  i++)
125360786Sps			max_epos = forw_raw_line(max_epos, (char **)NULL);
125460786Sps	}
125560786Sps
125660786Sps	/*
125760786Sps	 * Find two ranges:
125860786Sps	 * The range that we need to search (spos,epos); and the range that
125960786Sps	 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
126060786Sps	 */
126160786Sps
126260786Sps	if (prep_startpos == NULL_POSITION ||
126360786Sps	    (epos != NULL_POSITION && epos < prep_startpos) ||
126460786Sps	    spos > prep_endpos)
126560786Sps	{
126660786Sps		/*
126760786Sps		 * New range is not contiguous with old prep region.
126860786Sps		 * Discard the old prep region and start a new one.
126960786Sps		 */
127060786Sps		clr_hilite();
127160786Sps		if (epos != NULL_POSITION)
127260786Sps			epos += SEARCH_MORE;
127360786Sps		nprep_startpos = spos;
127460786Sps	} else
127560786Sps	{
127660786Sps		/*
127760786Sps		 * New range partially or completely overlaps old prep region.
127860786Sps		 */
127960786Sps		if (epos == NULL_POSITION)
128060786Sps		{
128160786Sps			/*
128260786Sps			 * New range goes to end of file.
128360786Sps			 */
128460786Sps			;
128560786Sps		} else if (epos > prep_endpos)
128660786Sps		{
128760786Sps			/*
128860786Sps			 * New range ends after old prep region.
128960786Sps			 * Extend prep region to end at end of new range.
129060786Sps			 */
129160786Sps			epos += SEARCH_MORE;
129260786Sps		} else /* (epos <= prep_endpos) */
129360786Sps		{
129460786Sps			/*
129560786Sps			 * New range ends within old prep region.
129660786Sps			 * Truncate search to end at start of old prep region.
129760786Sps			 */
129860786Sps			epos = prep_startpos;
129960786Sps		}
130060786Sps
130160786Sps		if (spos < prep_startpos)
130260786Sps		{
130360786Sps			/*
130460786Sps			 * New range starts before old prep region.
130560786Sps			 * Extend old prep region backwards to start at
130660786Sps			 * start of new range.
130760786Sps			 */
130860786Sps			if (spos < SEARCH_MORE)
130960786Sps				spos = 0;
131060786Sps			else
131160786Sps				spos -= SEARCH_MORE;
131260786Sps			nprep_startpos = spos;
131360786Sps		} else /* (spos >= prep_startpos) */
131460786Sps		{
131560786Sps			/*
131660786Sps			 * New range starts within or after old prep region.
131760786Sps			 * Trim search to start at end of old prep region.
131860786Sps			 */
131960786Sps			spos = prep_endpos;
132060786Sps		}
132160786Sps	}
132260786Sps
132360786Sps	if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
132460786Sps	    epos > max_epos)
132560786Sps		/*
132660786Sps		 * Don't go past the max position we're allowed.
132760786Sps		 */
132860786Sps		epos = max_epos;
132960786Sps
133060786Sps	if (epos == NULL_POSITION || epos > spos)
133160786Sps	{
133260786Sps		result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
133360786Sps				maxlines, (POSITION*)NULL, &new_epos);
133460786Sps		if (result < 0)
133560786Sps			return;
133660786Sps		if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
133760786Sps			nprep_endpos = new_epos;
133860786Sps	}
133960786Sps	prep_startpos = nprep_startpos;
134060786Sps	prep_endpos = nprep_endpos;
134160786Sps}
134260786Sps#endif
134360786Sps
134460786Sps/*
134560786Sps * Simple pattern matching function.
134660786Sps * It supports no metacharacters like *, etc.
134760786Sps */
134860786Sps	static int
134960786Spsmatch(pattern, buf, pfound, pend)
135060786Sps	char *pattern, *buf;
135160786Sps	char **pfound, **pend;
135260786Sps{
135360786Sps	register char *pp, *lp;
135460786Sps
135560786Sps	for ( ;  *buf != '\0';  buf++)
135660786Sps	{
135760786Sps		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
135860786Sps			if (*pp == '\0' || *lp == '\0')
135960786Sps				break;
136060786Sps		if (*pp == '\0')
136160786Sps		{
136260786Sps			if (pfound != NULL)
136360786Sps				*pfound = buf;
136460786Sps			if (pend != NULL)
136560786Sps				*pend = lp;
136660786Sps			return (1);
136760786Sps		}
136860786Sps	}
136960786Sps	return (0);
137060786Sps}
137160786Sps
137260786Sps#if HAVE_V8_REGCOMP
137360786Sps/*
137460786Sps * This function is called by the V8 regcomp to report
137560786Sps * errors in regular expressions.
137660786Sps */
137760786Sps	void
137860786Spsregerror(s)
137960786Sps	char *s;
138060786Sps{
138160786Sps	PARG parg;
138260786Sps
138360786Sps	parg.p_string = s;
138460786Sps	error("%s", &parg);
138560786Sps}
138660786Sps#endif
138760786Sps
1388