search.c revision 172471
160812Sps/* $FreeBSD: head/contrib/less/search.c 172471 2007-10-08 16:17:42Z delphij $ */
260786Sps/*
3170259Sdelphij * Copyright (C) 1984-2007  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"
19172471Sdelphij#include "charset.h"
2060786Sps
2160786Sps#define	MINPOS(a,b)	(((a) < (b)) ? (a) : (b))
2260786Sps#define	MAXPOS(a,b)	(((a) > (b)) ? (a) : (b))
2360786Sps
2460786Sps#if HAVE_POSIX_REGCOMP
2560786Sps#include <regex.h>
2660786Sps#ifdef REG_EXTENDED
27170259Sdelphij#define	REGCOMP_FLAG	(less_is_more ? 0 : REG_EXTENDED)
2860786Sps#else
2960786Sps#define	REGCOMP_FLAG	0
3060786Sps#endif
3160786Sps#endif
3260786Sps#if HAVE_PCRE
3360786Sps#include <pcre.h>
3460786Sps#endif
3560786Sps#if HAVE_RE_COMP
3660786Spschar *re_comp();
3760786Spsint re_exec();
3860786Sps#endif
3960786Sps#if HAVE_REGCMP
4060786Spschar *regcmp();
4160786Spschar *regex();
4260786Spsextern char *__loc1;
4360786Sps#endif
4460786Sps#if HAVE_V8_REGCOMP
4560786Sps#include "regexp.h"
4660786Sps#endif
4760786Sps
4860786Spsstatic int match();
4960786Sps
5060786Spsextern int sigs;
5160786Spsextern int how_search;
5260786Spsextern int caseless;
5360786Spsextern int linenums;
5460786Spsextern int sc_height;
5560786Spsextern int jump_sline;
5660786Spsextern int bs_mode;
57170259Sdelphijextern int less_is_more;
58128348Stjrextern int ctldisp;
5963131Spsextern int status_col;
60170259Sdelphijextern void * constant ml_search;
6160786Spsextern POSITION start_attnpos;
6260786Spsextern POSITION end_attnpos;
6360786Sps#if HILITE_SEARCH
6460786Spsextern int hilite_search;
6560786Spsextern int screen_trashed;
6660786Spsextern int size_linebuf;
6760786Spsextern int squished;
6860786Spsextern int can_goto_line;
6960786Spsstatic int hide_hilite;
70170259Sdelphijstatic int oldbot;
7160786Spsstatic POSITION prep_startpos;
7260786Spsstatic POSITION prep_endpos;
7360786Sps
7460786Spsstruct hilite
7560786Sps{
7660786Sps	struct hilite *hl_next;
7760786Sps	POSITION hl_startpos;
7860786Sps	POSITION hl_endpos;
7960786Sps};
8060786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
8160786Sps#define	hl_first	hl_next
8260786Sps#endif
8360786Sps
8460786Sps/*
8560786Sps * These are the static variables that represent the "remembered"
8660786Sps * search pattern.
8760786Sps */
8860786Sps#if HAVE_POSIX_REGCOMP
8960786Spsstatic regex_t *regpattern = NULL;
9060786Sps#endif
9160786Sps#if HAVE_PCRE
9260786Spspcre *regpattern = NULL;
9360786Sps#endif
9460786Sps#if HAVE_RE_COMP
9560786Spsint re_pattern = 0;
9660786Sps#endif
9760786Sps#if HAVE_REGCMP
9860786Spsstatic char *cpattern = NULL;
9960786Sps#endif
10060786Sps#if HAVE_V8_REGCOMP
10160786Spsstatic struct regexp *regpattern = NULL;
10260786Sps#endif
10360786Sps
10460786Spsstatic int is_caseless;
10560786Spsstatic int is_ucase_pattern;
10660786Spsstatic int last_search_type;
10760786Spsstatic char *last_pattern = NULL;
10860786Sps
10960786Sps/*
11060786Sps * Convert text.  Perform one or more of these transformations:
11160786Sps */
11260786Sps#define	CVT_TO_LC	01	/* Convert upper-case to lower-case */
11360786Sps#define	CVT_BS		02	/* Do backspace processing */
11460786Sps#define	CVT_CRLF	04	/* Remove CR after LF */
115128348Stjr#define	CVT_ANSI	010	/* Remove ANSI escape sequences */
11660786Sps
11760786Sps	static void
118170259Sdelphijcvt_text(odst, osrc, lenp, ops)
11960786Sps	char *odst;
12060786Sps	char *osrc;
121170259Sdelphij	int *lenp;
12260786Sps	int ops;
12360786Sps{
124172471Sdelphij	char *dst;
125172471Sdelphij	char *src;
126170259Sdelphij	register char *src_end;
127172471Sdelphij	LWCHAR ch;
12860786Sps
129170259Sdelphij	if (lenp != NULL)
130170259Sdelphij		src_end = osrc + *lenp;
131170259Sdelphij	else
132170259Sdelphij		src_end = osrc + strlen(osrc);
133170259Sdelphij
134172471Sdelphij	for (src = osrc, dst = odst;  src < src_end;  )
13560786Sps	{
136172471Sdelphij		ch = step_char(&src, +1, src_end);
137172471Sdelphij		if ((ops & CVT_TO_LC) && IS_UPPER(ch))
138172471Sdelphij		{
13960786Sps			/* Convert uppercase to lowercase. */
140172471Sdelphij			put_wchar(&dst, TO_LOWER(ch));
141172471Sdelphij		} else if ((ops & CVT_BS) && ch == '\b' && dst > odst)
142172471Sdelphij		{
14360786Sps			/* Delete BS and preceding char. */
144172471Sdelphij			do {
145172471Sdelphij				dst--;
146172471Sdelphij			} while (dst > odst &&
147172471Sdelphij				!IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
148172471Sdelphij		} else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
149128348Stjr		{
150128348Stjr			/* Skip to end of ANSI escape sequence. */
151170259Sdelphij			while (src + 1 != src_end)
152161478Sdelphij				if (!is_ansi_middle(*++src))
153128348Stjr					break;
154128348Stjr		} else
15560786Sps			/* Just copy. */
156172471Sdelphij			put_wchar(&dst, ch);
15760786Sps	}
15860786Sps	if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
15960786Sps		dst--;
16060786Sps	*dst = '\0';
161170259Sdelphij	if (lenp != NULL)
162170259Sdelphij		*lenp = dst - odst;
16360786Sps}
16460786Sps
16560786Sps/*
166128348Stjr * Determine which conversions to perform.
167128348Stjr */
168128348Stjr	static int
169128348Stjrget_cvt_ops()
170128348Stjr{
171128348Stjr	int ops = 0;
172128348Stjr	if (is_caseless || bs_mode == BS_SPECIAL)
173128348Stjr	{
174128348Stjr		if (is_caseless)
175128348Stjr			ops |= CVT_TO_LC;
176128348Stjr		if (bs_mode == BS_SPECIAL)
177128348Stjr			ops |= CVT_BS;
178128348Stjr		if (bs_mode != BS_CONTROL)
179128348Stjr			ops |= CVT_CRLF;
180128348Stjr	} else if (bs_mode != BS_CONTROL)
181128348Stjr	{
182128348Stjr		ops |= CVT_CRLF;
183128348Stjr	}
184128348Stjr	if (ctldisp == OPT_ONPLUS)
185128348Stjr		ops |= CVT_ANSI;
186128348Stjr	return (ops);
187128348Stjr}
188128348Stjr
189128348Stjr/*
19060786Sps * Are there any uppercase letters in this string?
19160786Sps */
19260786Sps	static int
193172471Sdelphijis_ucase(str)
194172471Sdelphij	char *str;
19560786Sps{
196172471Sdelphij	char *str_end = str + strlen(str);
197172471Sdelphij	LWCHAR ch;
19860786Sps
199172471Sdelphij	while (str < str_end)
200172471Sdelphij	{
201172471Sdelphij		ch = step_char(&str, +1, str_end);
202172471Sdelphij		if (IS_UPPER(ch))
20360786Sps			return (1);
204172471Sdelphij	}
20560786Sps	return (0);
20660786Sps}
20760786Sps
20860786Sps/*
20960786Sps * Is there a previous (remembered) search pattern?
21060786Sps */
21160786Sps	static int
21260786Spsprev_pattern()
21360786Sps{
21460786Sps	if (last_search_type & SRCH_NO_REGEX)
21560786Sps		return (last_pattern != NULL);
21660786Sps#if HAVE_POSIX_REGCOMP
21760786Sps	return (regpattern != NULL);
21860786Sps#endif
21960786Sps#if HAVE_PCRE
22060786Sps	return (regpattern != NULL);
22160786Sps#endif
22260786Sps#if HAVE_RE_COMP
22360786Sps	return (re_pattern != 0);
22460786Sps#endif
22560786Sps#if HAVE_REGCMP
22660786Sps	return (cpattern != NULL);
22760786Sps#endif
22860786Sps#if HAVE_V8_REGCOMP
22960786Sps	return (regpattern != NULL);
23060786Sps#endif
23160786Sps#if NO_REGEX
23260786Sps	return (last_pattern != NULL);
23360786Sps#endif
23460786Sps}
23560786Sps
23660786Sps#if HILITE_SEARCH
23760786Sps/*
23860786Sps * Repaint the hilites currently displayed on the screen.
23960786Sps * Repaint each line which contains highlighted text.
24060786Sps * If on==0, force all hilites off.
24160786Sps */
24260786Sps	public void
24360786Spsrepaint_hilite(on)
24460786Sps	int on;
24560786Sps{
24660786Sps	int slinenum;
24760786Sps	POSITION pos;
24860786Sps	POSITION epos;
24960786Sps	int save_hide_hilite;
25060786Sps
25160786Sps	if (squished)
25260786Sps		repaint();
25360786Sps
25460786Sps	save_hide_hilite = hide_hilite;
25560786Sps	if (!on)
25660786Sps	{
25760786Sps		if (hide_hilite)
25860786Sps			return;
25960786Sps		hide_hilite = 1;
26060786Sps	}
26160786Sps
26260786Sps	if (!can_goto_line)
26360786Sps	{
26460786Sps		repaint();
26560786Sps		hide_hilite = save_hide_hilite;
26660786Sps		return;
26760786Sps	}
26860786Sps
26960786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
27060786Sps	{
27160786Sps		pos = position(slinenum);
27260786Sps		if (pos == NULL_POSITION)
27360786Sps			continue;
27460786Sps		epos = position(slinenum+1);
275161478Sdelphij#if 0
27660786Sps		/*
27760786Sps		 * If any character in the line is highlighted,
27860786Sps		 * repaint the line.
279161478Sdelphij		 *
280161478Sdelphij		 * {{ This doesn't work -- if line is drawn with highlights
281161478Sdelphij		 * which should be erased (e.g. toggle -i with status column),
282161478Sdelphij		 * we must redraw the line even if it has no highlights.
283161478Sdelphij		 * For now, just repaint every line. }}
28460786Sps		 */
285161478Sdelphij		if (is_hilited(pos, epos, 1, NULL))
286161478Sdelphij#endif
28760786Sps		{
28860786Sps			(void) forw_line(pos);
28960786Sps			goto_line(slinenum);
29060786Sps			put_line();
29160786Sps		}
29260786Sps	}
293170259Sdelphij	if (!oldbot)
294170259Sdelphij		lower_left();
29560786Sps	hide_hilite = save_hide_hilite;
29660786Sps}
29760786Sps
29860786Sps/*
29960786Sps * Clear the attn hilite.
30060786Sps */
30160786Sps	public void
30260786Spsclear_attn()
30360786Sps{
30460786Sps	int slinenum;
30560786Sps	POSITION old_start_attnpos;
30660786Sps	POSITION old_end_attnpos;
30760786Sps	POSITION pos;
30860786Sps	POSITION epos;
309170898Sdelphij	int moved = 0;
31060786Sps
31160786Sps	if (start_attnpos == NULL_POSITION)
31260786Sps		return;
31360786Sps	old_start_attnpos = start_attnpos;
31460786Sps	old_end_attnpos = end_attnpos;
31560786Sps	start_attnpos = end_attnpos = NULL_POSITION;
31660786Sps
31760786Sps	if (!can_goto_line)
31860786Sps	{
31960786Sps		repaint();
32060786Sps		return;
32160786Sps	}
32260786Sps	if (squished)
32360786Sps		repaint();
32460786Sps
32560786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
32660786Sps	{
32760786Sps		pos = position(slinenum);
32860786Sps		if (pos == NULL_POSITION)
32960786Sps			continue;
33060786Sps		epos = position(slinenum+1);
33160786Sps		if (pos < old_end_attnpos &&
33260786Sps		     (epos == NULL_POSITION || epos > old_start_attnpos))
33360786Sps		{
33460786Sps			(void) forw_line(pos);
33560786Sps			goto_line(slinenum);
33660786Sps			put_line();
337170898Sdelphij			moved = 1;
33860786Sps		}
33960786Sps	}
340170898Sdelphij	if (moved)
341170898Sdelphij		lower_left();
34260786Sps}
34360786Sps#endif
34460786Sps
34560786Sps/*
34660786Sps * Hide search string highlighting.
34760786Sps */
34860786Sps	public void
34960786Spsundo_search()
35060786Sps{
35160786Sps	if (!prev_pattern())
35260786Sps	{
35360786Sps		error("No previous regular expression", NULL_PARG);
35460786Sps		return;
35560786Sps	}
35660786Sps#if HILITE_SEARCH
35760786Sps	hide_hilite = !hide_hilite;
35860786Sps	repaint_hilite(1);
35960786Sps#endif
36060786Sps}
36160786Sps
36260786Sps/*
36360786Sps * Compile a search pattern, for future use by match_pattern.
36460786Sps */
36560786Sps	static int
36660786Spscompile_pattern(pattern, search_type)
36760786Sps	char *pattern;
36860786Sps	int search_type;
36960786Sps{
37060786Sps	if ((search_type & SRCH_NO_REGEX) == 0)
37160786Sps	{
37260786Sps#if HAVE_POSIX_REGCOMP
37360786Sps		regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
37460786Sps		if (regcomp(s, pattern, REGCOMP_FLAG))
37560786Sps		{
37660786Sps			free(s);
37760786Sps			error("Invalid pattern", NULL_PARG);
37860786Sps			return (-1);
37960786Sps		}
38060786Sps		if (regpattern != NULL)
38160786Sps			regfree(regpattern);
38260786Sps		regpattern = s;
38360786Sps#endif
38460786Sps#if HAVE_PCRE
38560786Sps		pcre *comp;
38660786Sps		const char *errstring;
38760786Sps		int erroffset;
38860786Sps		PARG parg;
38960786Sps		comp = pcre_compile(pattern, 0,
39060786Sps				&errstring, &erroffset, NULL);
39160786Sps		if (comp == NULL)
39260786Sps		{
39360786Sps			parg.p_string = (char *) errstring;
39460786Sps			error("%s", &parg);
39560786Sps			return (-1);
39660786Sps		}
39760786Sps		regpattern = comp;
39860786Sps#endif
39960786Sps#if HAVE_RE_COMP
40060786Sps		PARG parg;
40160786Sps		if ((parg.p_string = re_comp(pattern)) != NULL)
40260786Sps		{
40360786Sps			error("%s", &parg);
40460786Sps			return (-1);
40560786Sps		}
40660786Sps		re_pattern = 1;
40760786Sps#endif
40860786Sps#if HAVE_REGCMP
40960786Sps		char *s;
41060786Sps		if ((s = regcmp(pattern, 0)) == NULL)
41160786Sps		{
41260786Sps			error("Invalid pattern", NULL_PARG);
41360786Sps			return (-1);
41460786Sps		}
41560786Sps		if (cpattern != NULL)
41660786Sps			free(cpattern);
41760786Sps		cpattern = s;
41860786Sps#endif
41960786Sps#if HAVE_V8_REGCOMP
42060786Sps		struct regexp *s;
42160786Sps		if ((s = regcomp(pattern)) == NULL)
42260786Sps		{
42360786Sps			/*
42460786Sps			 * regcomp has already printed an error message
42560786Sps			 * via regerror().
42660786Sps			 */
42760786Sps			return (-1);
42860786Sps		}
42960786Sps		if (regpattern != NULL)
43060786Sps			free(regpattern);
43160786Sps		regpattern = s;
43260786Sps#endif
43360786Sps	}
43460786Sps
43560786Sps	if (last_pattern != NULL)
43660786Sps		free(last_pattern);
43760786Sps	last_pattern = (char *) calloc(1, strlen(pattern)+1);
43860786Sps	if (last_pattern != NULL)
43960786Sps		strcpy(last_pattern, pattern);
44060786Sps
44160786Sps	last_search_type = search_type;
44260786Sps	return (0);
44360786Sps}
44460786Sps
44560786Sps/*
44660786Sps * Forget that we have a compiled pattern.
44760786Sps */
44860786Sps	static void
44960786Spsuncompile_pattern()
45060786Sps{
45160786Sps#if HAVE_POSIX_REGCOMP
45260786Sps	if (regpattern != NULL)
45360786Sps		regfree(regpattern);
45460786Sps	regpattern = NULL;
45560786Sps#endif
45660786Sps#if HAVE_PCRE
45760786Sps	if (regpattern != NULL)
45860786Sps		pcre_free(regpattern);
45960786Sps	regpattern = NULL;
46060786Sps#endif
46160786Sps#if HAVE_RE_COMP
46260786Sps	re_pattern = 0;
46360786Sps#endif
46460786Sps#if HAVE_REGCMP
46560786Sps	if (cpattern != NULL)
46660786Sps		free(cpattern);
46760786Sps	cpattern = NULL;
46860786Sps#endif
46960786Sps#if HAVE_V8_REGCOMP
47060786Sps	if (regpattern != NULL)
47160786Sps		free(regpattern);
47260786Sps	regpattern = NULL;
47360786Sps#endif
47460786Sps	last_pattern = NULL;
47560786Sps}
47660786Sps
47760786Sps/*
47860786Sps * Perform a pattern match with the previously compiled pattern.
47960786Sps * Set sp and ep to the start and end of the matched string.
48060786Sps */
48160786Sps	static int
482170259Sdelphijmatch_pattern(line, line_len, sp, ep, notbol)
48360786Sps	char *line;
484170259Sdelphij	int line_len;
48560786Sps	char **sp;
48660786Sps	char **ep;
48760786Sps	int notbol;
48860786Sps{
48960786Sps	int matched;
49060786Sps
49160786Sps	if (last_search_type & SRCH_NO_REGEX)
492170259Sdelphij		return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
49360786Sps
49460786Sps#if HAVE_POSIX_REGCOMP
49560786Sps	{
49660786Sps		regmatch_t rm;
49760786Sps		int flags = (notbol) ? REG_NOTBOL : 0;
49860786Sps		matched = !regexec(regpattern, line, 1, &rm, flags);
49960786Sps		if (!matched)
50060786Sps			return (0);
50160786Sps#ifndef __WATCOMC__
50260786Sps		*sp = line + rm.rm_so;
50360786Sps		*ep = line + rm.rm_eo;
50460786Sps#else
50560786Sps		*sp = rm.rm_sp;
50660786Sps		*ep = rm.rm_ep;
50760786Sps#endif
50860786Sps	}
50960786Sps#endif
51060786Sps#if HAVE_PCRE
51160786Sps	{
51260786Sps		int flags = (notbol) ? PCRE_NOTBOL : 0;
51360786Sps		int ovector[3];
514170259Sdelphij		matched = pcre_exec(regpattern, NULL, line, line_len,
51560786Sps			0, flags, ovector, 3) >= 0;
51660786Sps		if (!matched)
51760786Sps			return (0);
51860786Sps		*sp = line + ovector[0];
51960786Sps		*ep = line + ovector[1];
52060786Sps	}
52160786Sps#endif
52260786Sps#if HAVE_RE_COMP
52360786Sps	matched = (re_exec(line) == 1);
52460786Sps	/*
52560786Sps	 * re_exec doesn't seem to provide a way to get the matched string.
52660786Sps	 */
52760786Sps	*sp = *ep = NULL;
52860786Sps#endif
52960786Sps#if HAVE_REGCMP
53060786Sps	*ep = regex(cpattern, line);
53160786Sps	matched = (*ep != NULL);
53260786Sps	if (!matched)
53360786Sps		return (0);
53460786Sps	*sp = __loc1;
53560786Sps#endif
53660786Sps#if HAVE_V8_REGCOMP
53760786Sps#if HAVE_REGEXEC2
53860786Sps	matched = regexec2(regpattern, line, notbol);
53960786Sps#else
54060786Sps	matched = regexec(regpattern, line);
54160786Sps#endif
54260786Sps	if (!matched)
54360786Sps		return (0);
54460786Sps	*sp = regpattern->startp[0];
54560786Sps	*ep = regpattern->endp[0];
54660786Sps#endif
54760786Sps#if NO_REGEX
548170259Sdelphij	matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
54960786Sps#endif
55060786Sps	return (matched);
55160786Sps}
55260786Sps
55360786Sps#if HILITE_SEARCH
55460786Sps/*
55560786Sps * Clear the hilite list.
55660786Sps */
55760786Sps	public void
55860786Spsclr_hilite()
55960786Sps{
56060786Sps	struct hilite *hl;
56160786Sps	struct hilite *nexthl;
56260786Sps
56360786Sps	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = nexthl)
56460786Sps	{
56560786Sps		nexthl = hl->hl_next;
56660786Sps		free((void*)hl);
56760786Sps	}
56860786Sps	hilite_anchor.hl_first = NULL;
56960786Sps	prep_startpos = prep_endpos = NULL_POSITION;
57060786Sps}
57160786Sps
57260786Sps/*
57360786Sps * Should any characters in a specified range be highlighted?
574161478Sdelphij */
575161478Sdelphij	static int
576161478Sdelphijis_hilited_range(pos, epos)
577161478Sdelphij	POSITION pos;
578161478Sdelphij	POSITION epos;
579161478Sdelphij{
580161478Sdelphij	struct hilite *hl;
581161478Sdelphij
582161478Sdelphij	/*
583161478Sdelphij	 * Look at each highlight and see if any part of it falls in the range.
584161478Sdelphij	 */
585161478Sdelphij	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
586161478Sdelphij	{
587161478Sdelphij		if (hl->hl_endpos > pos &&
588161478Sdelphij		    (epos == NULL_POSITION || epos > hl->hl_startpos))
589161478Sdelphij			return (1);
590161478Sdelphij	}
591161478Sdelphij	return (0);
592161478Sdelphij}
593161478Sdelphij
594161478Sdelphij/*
595161478Sdelphij * Should any characters in a specified range be highlighted?
59660786Sps * If nohide is nonzero, don't consider hide_hilite.
59760786Sps */
59860786Sps	public int
599161478Sdelphijis_hilited(pos, epos, nohide, p_matches)
60060786Sps	POSITION pos;
60160786Sps	POSITION epos;
60260786Sps	int nohide;
603161478Sdelphij	int *p_matches;
60460786Sps{
605161478Sdelphij	int match;
60660786Sps
607161478Sdelphij	if (p_matches != NULL)
608161478Sdelphij		*p_matches = 0;
609161478Sdelphij
61063131Sps	if (!status_col &&
61163131Sps	    start_attnpos != NULL_POSITION &&
61260786Sps	    pos < end_attnpos &&
61360786Sps	     (epos == NULL_POSITION || epos > start_attnpos))
61460786Sps		/*
61560786Sps		 * The attn line overlaps this range.
61660786Sps		 */
61760786Sps		return (1);
61860786Sps
619161478Sdelphij	match = is_hilited_range(pos, epos);
620161478Sdelphij	if (!match)
621161478Sdelphij		return (0);
622161478Sdelphij
623161478Sdelphij	if (p_matches != NULL)
624161478Sdelphij		/*
625161478Sdelphij		 * Report matches, even if we're hiding highlights.
626161478Sdelphij		 */
627161478Sdelphij		*p_matches = 1;
628161478Sdelphij
62960786Sps	if (hilite_search == 0)
63060786Sps		/*
63160786Sps		 * Not doing highlighting.
63260786Sps		 */
63360786Sps		return (0);
63460786Sps
63560786Sps	if (!nohide && hide_hilite)
63660786Sps		/*
63760786Sps		 * Highlighting is hidden.
63860786Sps		 */
63960786Sps		return (0);
64060786Sps
641161478Sdelphij	return (1);
64260786Sps}
64360786Sps
64460786Sps/*
64560786Sps * Add a new hilite to a hilite list.
64660786Sps */
64760786Sps	static void
64860786Spsadd_hilite(anchor, hl)
64960786Sps	struct hilite *anchor;
65060786Sps	struct hilite *hl;
65160786Sps{
65260786Sps	struct hilite *ihl;
65360786Sps
65460786Sps	/*
65560786Sps	 * Hilites are sorted in the list; find where new one belongs.
65660786Sps	 * Insert new one after ihl.
65760786Sps	 */
65860786Sps	for (ihl = anchor;  ihl->hl_next != NULL;  ihl = ihl->hl_next)
65960786Sps	{
66060786Sps		if (ihl->hl_next->hl_startpos > hl->hl_startpos)
66160786Sps			break;
66260786Sps	}
66360786Sps
66460786Sps	/*
66560786Sps	 * Truncate hilite so it doesn't overlap any existing ones
66660786Sps	 * above and below it.
66760786Sps	 */
66860786Sps	if (ihl != anchor)
66960786Sps		hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
67060786Sps	if (ihl->hl_next != NULL)
67160786Sps		hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
67260786Sps	if (hl->hl_startpos >= hl->hl_endpos)
67360786Sps	{
67460786Sps		/*
67560786Sps		 * Hilite was truncated out of existence.
67660786Sps		 */
67760786Sps		free(hl);
67860786Sps		return;
67960786Sps	}
68060786Sps	hl->hl_next = ihl->hl_next;
68160786Sps	ihl->hl_next = hl;
68260786Sps}
68360786Sps
684161478Sdelphij	static void
685170259Sdelphijadj_hilite_ansi(cvt_ops, line, line_len, npos)
686161478Sdelphij	int cvt_ops;
687161478Sdelphij	char **line;
688170259Sdelphij	int line_len;
689161478Sdelphij	POSITION *npos;
690161478Sdelphij{
691170259Sdelphij	char *line_end = *line + line_len;
692170259Sdelphij
693161478Sdelphij	if (cvt_ops & CVT_ANSI)
694172471Sdelphij		while (IS_CSI_START(**line))
695161478Sdelphij		{
696161478Sdelphij			/*
697161478Sdelphij			 * Found an ESC.  The file position moves
698161478Sdelphij			 * forward past the entire ANSI escape sequence.
699161478Sdelphij			 */
700161478Sdelphij			(*line)++;
701161478Sdelphij			(*npos)++;
702170259Sdelphij			while (*line < line_end)
703161478Sdelphij			{
704161478Sdelphij				(*npos)++;
705161478Sdelphij				if (!is_ansi_middle(*(*line)++))
706161478Sdelphij					break;
707161478Sdelphij			}
708161478Sdelphij		}
709161478Sdelphij}
710161478Sdelphij
71160786Sps/*
71260786Sps * Adjust hl_startpos & hl_endpos to account for backspace processing.
71360786Sps */
71460786Sps	static void
715128348Stjradj_hilite(anchor, linepos, cvt_ops)
71660786Sps	struct hilite *anchor;
71760786Sps	POSITION linepos;
718128348Stjr	int cvt_ops;
71960786Sps{
72060786Sps	char *line;
721170259Sdelphij	int line_len;
722170259Sdelphij	char *line_end;
72360786Sps	struct hilite *hl;
72460786Sps	int checkstart;
72560786Sps	POSITION opos;
72660786Sps	POSITION npos;
72760786Sps
72860786Sps	/*
72960786Sps	 * The line was already scanned and hilites were added (in hilite_line).
73060786Sps	 * But it was assumed that each char position in the line
73160786Sps	 * correponds to one char position in the file.
73260786Sps	 * This may not be true if there are backspaces in the line.
73360786Sps	 * Get the raw line again.  Look at each character.
73460786Sps	 */
735170259Sdelphij	(void) forw_raw_line(linepos, &line, &line_len);
736170259Sdelphij	line_end = line + line_len;
73760786Sps	opos = npos = linepos;
73860786Sps	hl = anchor->hl_first;
73960786Sps	checkstart = TRUE;
74060786Sps	while (hl != NULL)
74160786Sps	{
74260786Sps		/*
74360786Sps		 * See if we need to adjust the current hl_startpos or
74460786Sps		 * hl_endpos.  After adjusting startpos[i], move to endpos[i].
74560786Sps		 * After adjusting endpos[i], move to startpos[i+1].
74660786Sps		 * The hilite list must be sorted thus:
74760786Sps		 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
74860786Sps		 */
74960786Sps		if (checkstart && hl->hl_startpos == opos)
75060786Sps		{
75160786Sps			hl->hl_startpos = npos;
75260786Sps			checkstart = FALSE;
75360786Sps			continue; /* {{ not really necessary }} */
75460786Sps		} else if (!checkstart && hl->hl_endpos == opos)
75560786Sps		{
75660786Sps			hl->hl_endpos = npos;
75760786Sps			checkstart = TRUE;
75860786Sps			hl = hl->hl_next;
75960786Sps			continue; /* {{ necessary }} */
76060786Sps		}
761170259Sdelphij		if (line == line_end)
76260786Sps			break;
763170259Sdelphij		adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos);
76460786Sps		opos++;
76560786Sps		npos++;
76660786Sps		line++;
767128348Stjr		if (cvt_ops & CVT_BS)
76860786Sps		{
769161478Sdelphij			while (*line == '\b')
770128348Stjr			{
771161478Sdelphij				npos++;
772161478Sdelphij				line++;
773170259Sdelphij				adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos);
774170259Sdelphij				if (line == line_end)
775161478Sdelphij				{
776161478Sdelphij					--npos;
777161478Sdelphij					--line;
778161478Sdelphij					break;
779161478Sdelphij				}
780128348Stjr				/*
781128348Stjr				 * Found a backspace.  The file position moves
782128348Stjr				 * forward by 2 relative to the processed line
783128348Stjr				 * which was searched in hilite_line.
784128348Stjr				 */
785161478Sdelphij				npos++;
786161478Sdelphij				line++;
787128348Stjr			}
78860786Sps		}
78960786Sps	}
79060786Sps}
79160786Sps
79260786Sps/*
79360786Sps * Make a hilite for each string in a physical line which matches
79460786Sps * the current pattern.
79560786Sps * sp,ep delimit the first match already found.
79660786Sps */
79760786Sps	static void
798170259Sdelphijhilite_line(linepos, line, line_len, sp, ep, cvt_ops)
79960786Sps	POSITION linepos;
80060786Sps	char *line;
801170259Sdelphij	int line_len;
80260786Sps	char *sp;
80360786Sps	char *ep;
804128348Stjr	int cvt_ops;
80560786Sps{
80660786Sps	char *searchp;
807170259Sdelphij	char *line_end = line + line_len;
80860786Sps	struct hilite *hl;
80960786Sps	struct hilite hilites;
81060786Sps
81160786Sps	if (sp == NULL || ep == NULL)
81260786Sps		return;
81360786Sps	/*
81460786Sps	 * sp and ep delimit the first match in the line.
81560786Sps	 * Mark the corresponding file positions, then
81660786Sps	 * look for further matches and mark them.
81760786Sps	 * {{ This technique, of calling match_pattern on subsequent
81860786Sps	 *    substrings of the line, may mark more than is correct
81960786Sps	 *    if the pattern starts with "^".  This bug is fixed
82060786Sps	 *    for those regex functions that accept a notbol parameter
821170259Sdelphij	 *    (currently POSIX, PCRE and V8-with-regexec2). }}
82260786Sps	 */
82360786Sps	searchp = line;
82460786Sps	/*
82560786Sps	 * Put the hilites into a temporary list until they're adjusted.
82660786Sps	 */
82760786Sps	hilites.hl_first = NULL;
82860786Sps	do {
82960786Sps		if (ep > sp)
83060786Sps		{
83160786Sps			/*
83260786Sps			 * Assume that each char position in the "line"
83360786Sps			 * buffer corresponds to one char position in the file.
83460786Sps			 * This is not quite true; we need to adjust later.
83560786Sps			 */
83660786Sps			hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
83760786Sps			hl->hl_startpos = linepos + (sp-line);
83860786Sps			hl->hl_endpos = linepos + (ep-line);
83960786Sps			add_hilite(&hilites, hl);
84060786Sps		}
84160786Sps		/*
84260786Sps		 * If we matched more than zero characters,
84360786Sps		 * move to the first char after the string we matched.
84460786Sps		 * If we matched zero, just move to the next char.
84560786Sps		 */
84660786Sps		if (ep > searchp)
84760786Sps			searchp = ep;
848170259Sdelphij		else if (searchp != line_end)
84960786Sps			searchp++;
85060786Sps		else /* end of line */
85160786Sps			break;
852170259Sdelphij	} while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1));
85360786Sps
85460786Sps	/*
855128348Stjr	 * If there were backspaces in the original line, they
856128348Stjr	 * were removed, and hl_startpos/hl_endpos are not correct.
857128348Stjr	 * {{ This is very ugly. }}
858128348Stjr	 */
859128348Stjr	adj_hilite(&hilites, linepos, cvt_ops);
860128348Stjr
861128348Stjr	/*
86260786Sps	 * Now put the hilites into the real list.
86360786Sps	 */
86460786Sps	while ((hl = hilites.hl_next) != NULL)
86560786Sps	{
86660786Sps		hilites.hl_next = hl->hl_next;
86760786Sps		add_hilite(&hilite_anchor, hl);
86860786Sps	}
86960786Sps}
87060786Sps#endif
87160786Sps
87260786Sps/*
87360786Sps * Change the caseless-ness of searches.
87460786Sps * Updates the internal search state to reflect a change in the -i flag.
87560786Sps */
87660786Sps	public void
87760786Spschg_caseless()
87860786Sps{
87960786Sps	if (!is_ucase_pattern)
88060786Sps		/*
88160786Sps		 * Pattern did not have uppercase.
88260786Sps		 * Just set the search caselessness to the global caselessness.
88360786Sps		 */
88460786Sps		is_caseless = caseless;
88560786Sps	else
88660786Sps		/*
88760786Sps		 * Pattern did have uppercase.
88860786Sps		 * Discard the pattern; we can't change search caselessness now.
88960786Sps		 */
89060786Sps		uncompile_pattern();
89160786Sps}
89260786Sps
89360786Sps#if HILITE_SEARCH
89460786Sps/*
89560786Sps * Find matching text which is currently on screen and highlight it.
89660786Sps */
89760786Sps	static void
89860786Spshilite_screen()
89960786Sps{
90060786Sps	struct scrpos scrpos;
90160786Sps
90260786Sps	get_scrpos(&scrpos);
90360786Sps	if (scrpos.pos == NULL_POSITION)
90460786Sps		return;
90560786Sps	prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
90660786Sps	repaint_hilite(1);
90760786Sps}
90860786Sps
90960786Sps/*
91060786Sps * Change highlighting parameters.
91160786Sps */
91260786Sps	public void
91360786Spschg_hilite()
91460786Sps{
91560786Sps	/*
91660786Sps	 * Erase any highlights currently on screen.
91760786Sps	 */
91860786Sps	clr_hilite();
91960786Sps	hide_hilite = 0;
92060786Sps
92160786Sps	if (hilite_search == OPT_ONPLUS)
92260786Sps		/*
92360786Sps		 * Display highlights.
92460786Sps		 */
92560786Sps		hilite_screen();
92660786Sps}
92760786Sps#endif
92860786Sps
92960786Sps/*
93060786Sps * Figure out where to start a search.
93160786Sps */
93260786Sps	static POSITION
93360786Spssearch_pos(search_type)
93460786Sps	int search_type;
93560786Sps{
93660786Sps	POSITION pos;
93760786Sps	int linenum;
93860786Sps
93960786Sps	if (empty_screen())
94060786Sps	{
94160786Sps		/*
94260786Sps		 * Start at the beginning (or end) of the file.
94360786Sps		 * The empty_screen() case is mainly for
94460786Sps		 * command line initiated searches;
94560786Sps		 * for example, "+/xyz" on the command line.
94660786Sps		 * Also for multi-file (SRCH_PAST_EOF) searches.
94760786Sps		 */
94860786Sps		if (search_type & SRCH_FORW)
94960786Sps		{
95060786Sps			return (ch_zero());
95160786Sps		} else
95260786Sps		{
95360786Sps			pos = ch_length();
95460786Sps			if (pos == NULL_POSITION)
95560786Sps			{
95660786Sps				(void) ch_end_seek();
95760786Sps				pos = ch_length();
95860786Sps			}
95960786Sps			return (pos);
96060786Sps		}
96160786Sps	}
96260786Sps	if (how_search)
96360786Sps	{
96460786Sps		/*
96560786Sps		 * Search does not include current screen.
96660786Sps		 */
96760786Sps		if (search_type & SRCH_FORW)
96860786Sps			linenum = BOTTOM_PLUS_ONE;
96960786Sps		else
97060786Sps			linenum = TOP;
97160786Sps		pos = position(linenum);
97260786Sps	} else
97360786Sps	{
97460786Sps		/*
97560786Sps		 * Search includes current screen.
97660786Sps		 * It starts at the jump target (if searching backwards),
97760786Sps		 * or at the jump target plus one (if forwards).
97860786Sps		 */
97960786Sps		linenum = adjsline(jump_sline);
98060786Sps		pos = position(linenum);
98160786Sps		if (search_type & SRCH_FORW)
98260786Sps		{
983170259Sdelphij			pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
98460786Sps			while (pos == NULL_POSITION)
98560786Sps			{
98660786Sps				if (++linenum >= sc_height)
98760786Sps					break;
98860786Sps				pos = position(linenum);
98960786Sps			}
99060786Sps		} else
99160786Sps		{
99260786Sps			while (pos == NULL_POSITION)
99360786Sps			{
99460786Sps				if (--linenum < 0)
99560786Sps					break;
99660786Sps				pos = position(linenum);
99760786Sps			}
99860786Sps		}
99960786Sps	}
100060786Sps	return (pos);
100160786Sps}
100260786Sps
100360786Sps/*
100460786Sps * Search a subset of the file, specified by start/end position.
100560786Sps */
100660786Sps	static int
100760786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
100860786Sps	POSITION pos;
100960786Sps	POSITION endpos;
101060786Sps	int search_type;
101160786Sps	int matches;
101260786Sps	int maxlines;
101360786Sps	POSITION *plinepos;
101460786Sps	POSITION *pendpos;
101560786Sps{
101660786Sps	char *line;
1017170259Sdelphij	int line_len;
1018128348Stjr	LINENUM linenum;
101960786Sps	char *sp, *ep;
102060786Sps	int line_match;
1021128348Stjr	int cvt_ops;
102260786Sps	POSITION linepos, oldpos;
102360786Sps
102460786Sps	linenum = find_linenum(pos);
102560786Sps	oldpos = pos;
102660786Sps	for (;;)
102760786Sps	{
102860786Sps		/*
102960786Sps		 * Get lines until we find a matching one or until
103060786Sps		 * we hit end-of-file (or beginning-of-file if we're
103160786Sps		 * going backwards), or until we hit the end position.
103260786Sps		 */
103360786Sps		if (ABORT_SIGS())
103460786Sps		{
103560786Sps			/*
103660786Sps			 * A signal aborts the search.
103760786Sps			 */
103860786Sps			return (-1);
103960786Sps		}
104060786Sps
104160786Sps		if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
104260786Sps		{
104360786Sps			/*
104460786Sps			 * Reached end position without a match.
104560786Sps			 */
104660786Sps			if (pendpos != NULL)
104760786Sps				*pendpos = pos;
104860786Sps			return (matches);
104960786Sps		}
105060786Sps		if (maxlines > 0)
105160786Sps			maxlines--;
105260786Sps
105360786Sps		if (search_type & SRCH_FORW)
105460786Sps		{
105560786Sps			/*
105660786Sps			 * Read the next line, and save the
105760786Sps			 * starting position of that line in linepos.
105860786Sps			 */
105960786Sps			linepos = pos;
1060170259Sdelphij			pos = forw_raw_line(pos, &line, &line_len);
106160786Sps			if (linenum != 0)
106260786Sps				linenum++;
106360786Sps		} else
106460786Sps		{
106560786Sps			/*
106660786Sps			 * Read the previous line and save the
106760786Sps			 * starting position of that line in linepos.
106860786Sps			 */
1069170259Sdelphij			pos = back_raw_line(pos, &line, &line_len);
107060786Sps			linepos = pos;
107160786Sps			if (linenum != 0)
107260786Sps				linenum--;
107360786Sps		}
107460786Sps
107560786Sps		if (pos == NULL_POSITION)
107660786Sps		{
107760786Sps			/*
107860786Sps			 * Reached EOF/BOF without a match.
107960786Sps			 */
108060786Sps			if (pendpos != NULL)
108160786Sps				*pendpos = oldpos;
108260786Sps			return (matches);
108360786Sps		}
108460786Sps
108560786Sps		/*
108660786Sps		 * If we're using line numbers, we might as well
108760786Sps		 * remember the information we have now (the position
108860786Sps		 * and line number of the current line).
108960786Sps		 * Don't do it for every line because it slows down
109060786Sps		 * the search.  Remember the line number only if
109160786Sps		 * we're "far" from the last place we remembered it.
109260786Sps		 */
109360786Sps		if (linenums && abs((int)(pos - oldpos)) > 1024)
109460786Sps			add_lnum(linenum, pos);
109560786Sps		oldpos = pos;
109660786Sps
109760786Sps		/*
109860786Sps		 * If it's a caseless search, convert the line to lowercase.
109960786Sps		 * If we're doing backspace processing, delete backspaces.
110060786Sps		 */
1101128348Stjr		cvt_ops = get_cvt_ops();
1102170259Sdelphij		cvt_text(line, line, &line_len, cvt_ops);
110360786Sps
110460786Sps		/*
110560786Sps		 * Test the next line to see if we have a match.
110660786Sps		 * We are successful if we either want a match and got one,
110760786Sps		 * or if we want a non-match and got one.
110860786Sps		 */
1109170259Sdelphij		line_match = match_pattern(line, line_len, &sp, &ep, 0);
111060786Sps		line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
111160786Sps				((search_type & SRCH_NO_MATCH) && !line_match);
111260786Sps		if (!line_match)
111360786Sps			continue;
111460786Sps		/*
111560786Sps		 * Got a match.
111660786Sps		 */
111760786Sps		if (search_type & SRCH_FIND_ALL)
111860786Sps		{
111960786Sps#if HILITE_SEARCH
112060786Sps			/*
112160786Sps			 * We are supposed to find all matches in the range.
112260786Sps			 * Just add the matches in this line to the
112360786Sps			 * hilite list and keep searching.
112460786Sps			 */
112560786Sps			if (line_match)
1126170259Sdelphij				hilite_line(linepos, line, line_len, sp, ep, cvt_ops);
112760786Sps#endif
112860786Sps		} else if (--matches <= 0)
112960786Sps		{
113060786Sps			/*
113160786Sps			 * Found the one match we're looking for.
113260786Sps			 * Return it.
113360786Sps			 */
113460786Sps#if HILITE_SEARCH
1135161478Sdelphij			if (hilite_search == OPT_ON)
113660786Sps			{
113760786Sps				/*
113860786Sps				 * Clear the hilite list and add only
113960786Sps				 * the matches in this one line.
114060786Sps				 */
114160786Sps				clr_hilite();
114260786Sps				if (line_match)
1143170259Sdelphij					hilite_line(linepos, line, line_len, sp, ep, cvt_ops);
114460786Sps			}
114560786Sps#endif
114660786Sps			if (plinepos != NULL)
114760786Sps				*plinepos = linepos;
114860786Sps			return (0);
114960786Sps		}
115060786Sps	}
115160786Sps}
115260786Sps
1153170259Sdelphij /*
1154170259Sdelphij * search for a pattern in history. If found, compile that pattern.
1155170259Sdelphij */
1156170259Sdelphij	static int
1157170259Sdelphijhist_pattern(search_type)
1158170259Sdelphij	int search_type;
1159170259Sdelphij{
1160170259Sdelphij#if CMD_HISTORY
1161170259Sdelphij	char *pattern;
1162170259Sdelphij
1163170259Sdelphij	set_mlist(ml_search, 0);
1164170259Sdelphij	pattern = cmd_lastpattern();
1165170259Sdelphij	if (pattern == NULL)
1166170259Sdelphij		return (0);
1167170259Sdelphij
1168170259Sdelphij	if (caseless == OPT_ONPLUS)
1169170259Sdelphij		cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC);
1170170259Sdelphij
1171170259Sdelphij	if (compile_pattern(pattern, search_type) < 0)
1172170259Sdelphij		return (0);
1173170259Sdelphij
1174170259Sdelphij	is_ucase_pattern = is_ucase(pattern);
1175170259Sdelphij	if (is_ucase_pattern && caseless != OPT_ONPLUS)
1176170259Sdelphij		is_caseless = 0;
1177170259Sdelphij	else
1178170259Sdelphij		is_caseless = caseless;
1179170259Sdelphij
1180170259Sdelphij#if HILITE_SEARCH
1181170259Sdelphij	if (hilite_search == OPT_ONPLUS && !hide_hilite)
1182170259Sdelphij		hilite_screen();
1183170259Sdelphij#endif
1184170259Sdelphij
1185170259Sdelphij	return (1);
1186170259Sdelphij#else /* CMD_HISTORY */
1187170259Sdelphij	return (0);
1188170259Sdelphij#endif /* CMD_HISTORY */
1189170259Sdelphij}
1190170259Sdelphij
119160786Sps/*
119260786Sps * Search for the n-th occurrence of a specified pattern,
119360786Sps * either forward or backward.
119460786Sps * Return the number of matches not yet found in this file
119560786Sps * (that is, n minus the number of matches found).
119660786Sps * Return -1 if the search should be aborted.
119760786Sps * Caller may continue the search in another file
119860786Sps * if less than n matches are found in this file.
119960786Sps */
120060786Sps	public int
120160786Spssearch(search_type, pattern, n)
120260786Sps	int search_type;
120360786Sps	char *pattern;
120460786Sps	int n;
120560786Sps{
120660786Sps	POSITION pos;
120760786Sps	int ucase;
120860786Sps
120960786Sps	if (pattern == NULL || *pattern == '\0')
121060786Sps	{
121160786Sps		/*
121260786Sps		 * A null pattern means use the previously compiled pattern.
121360786Sps		 */
1214170259Sdelphij		if (!prev_pattern() && !hist_pattern(search_type))
121560786Sps		{
121660786Sps			error("No previous regular expression", NULL_PARG);
121760786Sps			return (-1);
121860786Sps		}
121960786Sps		if ((search_type & SRCH_NO_REGEX) !=
122060786Sps		    (last_search_type & SRCH_NO_REGEX))
122160786Sps		{
122260786Sps			error("Please re-enter search pattern", NULL_PARG);
122360786Sps			return -1;
122460786Sps		}
122560786Sps#if HILITE_SEARCH
122660786Sps		if (hilite_search == OPT_ON)
122760786Sps		{
122860786Sps			/*
122960786Sps			 * Erase the highlights currently on screen.
123060786Sps			 * If the search fails, we'll redisplay them later.
123160786Sps			 */
123260786Sps			repaint_hilite(0);
123360786Sps		}
123460786Sps		if (hilite_search == OPT_ONPLUS && hide_hilite)
123560786Sps		{
123660786Sps			/*
123760786Sps			 * Highlight any matches currently on screen,
123860786Sps			 * before we actually start the search.
123960786Sps			 */
124060786Sps			hide_hilite = 0;
124160786Sps			hilite_screen();
124260786Sps		}
124360786Sps		hide_hilite = 0;
124460786Sps#endif
124560786Sps	} else
124660786Sps	{
124760786Sps		/*
124860786Sps		 * Compile the pattern.
124960786Sps		 */
125060786Sps		ucase = is_ucase(pattern);
125160786Sps		if (caseless == OPT_ONPLUS)
1252170259Sdelphij			cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC);
125360786Sps		if (compile_pattern(pattern, search_type) < 0)
125460786Sps			return (-1);
125560786Sps		/*
125660786Sps		 * Ignore case if -I is set OR
125760786Sps		 * -i is set AND the pattern is all lowercase.
125860786Sps		 */
125960786Sps		is_ucase_pattern = ucase;
126060786Sps		if (is_ucase_pattern && caseless != OPT_ONPLUS)
126160786Sps			is_caseless = 0;
126260786Sps		else
126360786Sps			is_caseless = caseless;
126460786Sps#if HILITE_SEARCH
126560786Sps		if (hilite_search)
126660786Sps		{
126760786Sps			/*
126860786Sps			 * Erase the highlights currently on screen.
126960786Sps			 * Also permanently delete them from the hilite list.
127060786Sps			 */
127160786Sps			repaint_hilite(0);
127260786Sps			hide_hilite = 0;
127360786Sps			clr_hilite();
127460786Sps		}
127560786Sps		if (hilite_search == OPT_ONPLUS)
127660786Sps		{
127760786Sps			/*
127860786Sps			 * Highlight any matches currently on screen,
127960786Sps			 * before we actually start the search.
128060786Sps			 */
128160786Sps			hilite_screen();
128260786Sps		}
128360786Sps#endif
128460786Sps	}
128560786Sps
128660786Sps	/*
128760786Sps	 * Figure out where to start the search.
128860786Sps	 */
128960786Sps	pos = search_pos(search_type);
129060786Sps	if (pos == NULL_POSITION)
129160786Sps	{
129260786Sps		/*
129360786Sps		 * Can't find anyplace to start searching from.
129460786Sps		 */
129560786Sps		if (search_type & SRCH_PAST_EOF)
129660786Sps			return (n);
129760786Sps		/* repaint(); -- why was this here? */
129860786Sps		error("Nothing to search", NULL_PARG);
129960786Sps		return (-1);
130060786Sps	}
130160786Sps
130260786Sps	n = search_range(pos, NULL_POSITION, search_type, n, -1,
130360786Sps			&pos, (POSITION*)NULL);
130460786Sps	if (n != 0)
130560786Sps	{
130660786Sps		/*
130760786Sps		 * Search was unsuccessful.
130860786Sps		 */
130960786Sps#if HILITE_SEARCH
131060786Sps		if (hilite_search == OPT_ON && n > 0)
131160786Sps			/*
131260786Sps			 * Redisplay old hilites.
131360786Sps			 */
131460786Sps			repaint_hilite(1);
131560786Sps#endif
131660786Sps		return (n);
131760786Sps	}
131860786Sps
131960786Sps	if (!(search_type & SRCH_NO_MOVE))
132060786Sps	{
132160786Sps		/*
132260786Sps		 * Go to the matching line.
132360786Sps		 */
132460786Sps		jump_loc(pos, jump_sline);
132560786Sps	}
132660786Sps
132760786Sps#if HILITE_SEARCH
132860786Sps	if (hilite_search == OPT_ON)
132960786Sps		/*
133060786Sps		 * Display new hilites in the matching line.
133160786Sps		 */
133260786Sps		repaint_hilite(1);
133360786Sps#endif
133460786Sps	return (0);
133560786Sps}
133660786Sps
133760786Sps
133860786Sps#if HILITE_SEARCH
133960786Sps/*
134060786Sps * Prepare hilites in a given range of the file.
134160786Sps *
134260786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region
134360786Sps * of the file that has been "prepared"; that is, scanned for matches for
134460786Sps * the current search pattern, and hilites have been created for such matches.
134560786Sps * If prep_startpos == NULL_POSITION, the prep region is empty.
134660786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
134760786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region.
134860786Sps */
134960786Sps	public void
135060786Spsprep_hilite(spos, epos, maxlines)
135160786Sps	POSITION spos;
135260786Sps	POSITION epos;
135360786Sps	int maxlines;
135460786Sps{
135560786Sps	POSITION nprep_startpos = prep_startpos;
135660786Sps	POSITION nprep_endpos = prep_endpos;
135760786Sps	POSITION new_epos;
135860786Sps	POSITION max_epos;
135960786Sps	int result;
136060786Sps	int i;
136160786Sps/*
136260786Sps * Search beyond where we're asked to search, so the prep region covers
136360786Sps * more than we need.  Do one big search instead of a bunch of small ones.
136460786Sps */
136560786Sps#define	SEARCH_MORE (3*size_linebuf)
136660786Sps
136760786Sps	if (!prev_pattern())
136860786Sps		return;
136960786Sps
137060786Sps	/*
137160786Sps	 * If we're limited to a max number of lines, figure out the
137260786Sps	 * file position we should stop at.
137360786Sps	 */
137460786Sps	if (maxlines < 0)
137560786Sps		max_epos = NULL_POSITION;
137660786Sps	else
137760786Sps	{
137860786Sps		max_epos = spos;
137960786Sps		for (i = 0;  i < maxlines;  i++)
1380170259Sdelphij			max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
138160786Sps	}
138260786Sps
138360786Sps	/*
138460786Sps	 * Find two ranges:
138560786Sps	 * The range that we need to search (spos,epos); and the range that
138660786Sps	 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
138760786Sps	 */
138860786Sps
138960786Sps	if (prep_startpos == NULL_POSITION ||
139060786Sps	    (epos != NULL_POSITION && epos < prep_startpos) ||
139160786Sps	    spos > prep_endpos)
139260786Sps	{
139360786Sps		/*
139460786Sps		 * New range is not contiguous with old prep region.
139560786Sps		 * Discard the old prep region and start a new one.
139660786Sps		 */
139760786Sps		clr_hilite();
139860786Sps		if (epos != NULL_POSITION)
139960786Sps			epos += SEARCH_MORE;
140060786Sps		nprep_startpos = spos;
140160786Sps	} else
140260786Sps	{
140360786Sps		/*
140460786Sps		 * New range partially or completely overlaps old prep region.
140560786Sps		 */
140660786Sps		if (epos == NULL_POSITION)
140760786Sps		{
140860786Sps			/*
140960786Sps			 * New range goes to end of file.
141060786Sps			 */
141160786Sps			;
141260786Sps		} else if (epos > prep_endpos)
141360786Sps		{
141460786Sps			/*
141560786Sps			 * New range ends after old prep region.
141660786Sps			 * Extend prep region to end at end of new range.
141760786Sps			 */
141860786Sps			epos += SEARCH_MORE;
141960786Sps		} else /* (epos <= prep_endpos) */
142060786Sps		{
142160786Sps			/*
142260786Sps			 * New range ends within old prep region.
142360786Sps			 * Truncate search to end at start of old prep region.
142460786Sps			 */
142560786Sps			epos = prep_startpos;
142660786Sps		}
142760786Sps
142860786Sps		if (spos < prep_startpos)
142960786Sps		{
143060786Sps			/*
143160786Sps			 * New range starts before old prep region.
143260786Sps			 * Extend old prep region backwards to start at
143360786Sps			 * start of new range.
143460786Sps			 */
143560786Sps			if (spos < SEARCH_MORE)
143660786Sps				spos = 0;
143760786Sps			else
143860786Sps				spos -= SEARCH_MORE;
143960786Sps			nprep_startpos = spos;
144060786Sps		} else /* (spos >= prep_startpos) */
144160786Sps		{
144260786Sps			/*
144360786Sps			 * New range starts within or after old prep region.
144460786Sps			 * Trim search to start at end of old prep region.
144560786Sps			 */
144660786Sps			spos = prep_endpos;
144760786Sps		}
144860786Sps	}
144960786Sps
145060786Sps	if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
145160786Sps	    epos > max_epos)
145260786Sps		/*
145360786Sps		 * Don't go past the max position we're allowed.
145460786Sps		 */
145560786Sps		epos = max_epos;
145660786Sps
145760786Sps	if (epos == NULL_POSITION || epos > spos)
145860786Sps	{
145960786Sps		result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
146060786Sps				maxlines, (POSITION*)NULL, &new_epos);
146160786Sps		if (result < 0)
146260786Sps			return;
146360786Sps		if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
146460786Sps			nprep_endpos = new_epos;
146560786Sps	}
146660786Sps	prep_startpos = nprep_startpos;
146760786Sps	prep_endpos = nprep_endpos;
146860786Sps}
146960786Sps#endif
147060786Sps
147160786Sps/*
147260786Sps * Simple pattern matching function.
147360786Sps * It supports no metacharacters like *, etc.
147460786Sps */
147560786Sps	static int
1476170259Sdelphijmatch(pattern, pattern_len, buf, buf_len, pfound, pend)
1477170259Sdelphij	char *pattern;
1478170259Sdelphij	int pattern_len;
1479170259Sdelphij	char *buf;
1480170259Sdelphij	int buf_len;
148160786Sps	char **pfound, **pend;
148260786Sps{
148360786Sps	register char *pp, *lp;
1484170259Sdelphij	register char *pattern_end = pattern + pattern_len;
1485170259Sdelphij	register char *buf_end = buf + buf_len;
148660786Sps
1487170259Sdelphij	for ( ;  buf < buf_end;  buf++)
148860786Sps	{
148960786Sps		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
1490170259Sdelphij			if (pp == pattern_end || lp == buf_end)
149160786Sps				break;
1492170259Sdelphij		if (pp == pattern_end)
149360786Sps		{
149460786Sps			if (pfound != NULL)
149560786Sps				*pfound = buf;
149660786Sps			if (pend != NULL)
149760786Sps				*pend = lp;
149860786Sps			return (1);
149960786Sps		}
150060786Sps	}
150160786Sps	return (0);
150260786Sps}
150360786Sps
150460786Sps#if HAVE_V8_REGCOMP
150560786Sps/*
150660786Sps * This function is called by the V8 regcomp to report
150760786Sps * errors in regular expressions.
150860786Sps */
150960786Sps	void
151060786Spsregerror(s)
151160786Sps	char *s;
151260786Sps{
151360786Sps	PARG parg;
151460786Sps
151560786Sps	parg.p_string = s;
151660786Sps	error("%s", &parg);
151760786Sps}
151860786Sps#endif
151960786Sps
1520