search.c revision 170898
160812Sps/* $FreeBSD: head/contrib/less/search.c 170898 2007-06-17 23:20:43Z 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"
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
26170259Sdelphij#define	REGCOMP_FLAG	(less_is_more ? 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;
56170259Sdelphijextern int less_is_more;
57128348Stjrextern int ctldisp;
5863131Spsextern int status_col;
59170259Sdelphijextern void * constant ml_search;
6060786Spsextern POSITION start_attnpos;
6160786Spsextern POSITION end_attnpos;
6260786Sps#if HILITE_SEARCH
6360786Spsextern int hilite_search;
6460786Spsextern int screen_trashed;
6560786Spsextern int size_linebuf;
6660786Spsextern int squished;
6760786Spsextern int can_goto_line;
6860786Spsstatic int hide_hilite;
69170259Sdelphijstatic int oldbot;
7060786Spsstatic POSITION prep_startpos;
7160786Spsstatic POSITION prep_endpos;
7260786Sps
7360786Spsstruct hilite
7460786Sps{
7560786Sps	struct hilite *hl_next;
7660786Sps	POSITION hl_startpos;
7760786Sps	POSITION hl_endpos;
7860786Sps};
7960786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
8060786Sps#define	hl_first	hl_next
8160786Sps#endif
8260786Sps
8360786Sps/*
8460786Sps * These are the static variables that represent the "remembered"
8560786Sps * search pattern.
8660786Sps */
8760786Sps#if HAVE_POSIX_REGCOMP
8860786Spsstatic regex_t *regpattern = NULL;
8960786Sps#endif
9060786Sps#if HAVE_PCRE
9160786Spspcre *regpattern = NULL;
9260786Sps#endif
9360786Sps#if HAVE_RE_COMP
9460786Spsint re_pattern = 0;
9560786Sps#endif
9660786Sps#if HAVE_REGCMP
9760786Spsstatic char *cpattern = NULL;
9860786Sps#endif
9960786Sps#if HAVE_V8_REGCOMP
10060786Spsstatic struct regexp *regpattern = NULL;
10160786Sps#endif
10260786Sps
10360786Spsstatic int is_caseless;
10460786Spsstatic int is_ucase_pattern;
10560786Spsstatic int last_search_type;
10660786Spsstatic char *last_pattern = NULL;
10760786Sps
10860786Sps/*
10960786Sps * Convert text.  Perform one or more of these transformations:
11060786Sps */
11160786Sps#define	CVT_TO_LC	01	/* Convert upper-case to lower-case */
11260786Sps#define	CVT_BS		02	/* Do backspace processing */
11360786Sps#define	CVT_CRLF	04	/* Remove CR after LF */
114128348Stjr#define	CVT_ANSI	010	/* Remove ANSI escape sequences */
11560786Sps
11660786Sps	static void
117170259Sdelphijcvt_text(odst, osrc, lenp, ops)
11860786Sps	char *odst;
11960786Sps	char *osrc;
120170259Sdelphij	int *lenp;
12160786Sps	int ops;
12260786Sps{
12360786Sps	register char *dst;
12460786Sps	register char *src;
125170259Sdelphij	register char *src_end;
12660786Sps
127170259Sdelphij	if (lenp != NULL)
128170259Sdelphij		src_end = osrc + *lenp;
129170259Sdelphij	else
130170259Sdelphij		src_end = osrc + strlen(osrc);
131170259Sdelphij
132170259Sdelphij	for (src = osrc, dst = odst;  src < src_end;  src++)
13360786Sps	{
134161478Sdelphij		if ((ops & CVT_TO_LC) && IS_UPPER(*src))
13560786Sps			/* Convert uppercase to lowercase. */
136161478Sdelphij			*dst++ = TO_LOWER(*src);
13760786Sps		else if ((ops & CVT_BS) && *src == '\b' && dst > odst)
13860786Sps			/* Delete BS and preceding char. */
139128348Stjr			dst--;
140128348Stjr		else if ((ops & CVT_ANSI) && *src == ESC)
141128348Stjr		{
142128348Stjr			/* Skip to end of ANSI escape sequence. */
143170259Sdelphij			while (src + 1 != src_end)
144161478Sdelphij				if (!is_ansi_middle(*++src))
145128348Stjr					break;
146128348Stjr		} else
14760786Sps			/* Just copy. */
148128348Stjr			*dst++ = *src;
14960786Sps	}
15060786Sps	if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
15160786Sps		dst--;
15260786Sps	*dst = '\0';
153170259Sdelphij	if (lenp != NULL)
154170259Sdelphij		*lenp = dst - odst;
15560786Sps}
15660786Sps
15760786Sps/*
158128348Stjr * Determine which conversions to perform.
159128348Stjr */
160128348Stjr	static int
161128348Stjrget_cvt_ops()
162128348Stjr{
163128348Stjr	int ops = 0;
164128348Stjr	if (is_caseless || bs_mode == BS_SPECIAL)
165128348Stjr	{
166128348Stjr		if (is_caseless)
167128348Stjr			ops |= CVT_TO_LC;
168128348Stjr		if (bs_mode == BS_SPECIAL)
169128348Stjr			ops |= CVT_BS;
170128348Stjr		if (bs_mode != BS_CONTROL)
171128348Stjr			ops |= CVT_CRLF;
172128348Stjr	} else if (bs_mode != BS_CONTROL)
173128348Stjr	{
174128348Stjr		ops |= CVT_CRLF;
175128348Stjr	}
176128348Stjr	if (ctldisp == OPT_ONPLUS)
177128348Stjr		ops |= CVT_ANSI;
178128348Stjr	return (ops);
179128348Stjr}
180128348Stjr
181128348Stjr/*
18260786Sps * Are there any uppercase letters in this string?
18360786Sps */
18460786Sps	static int
18560786Spsis_ucase(s)
18660786Sps	char *s;
18760786Sps{
18860786Sps	register char *p;
18960786Sps
19060786Sps	for (p = s;  *p != '\0';  p++)
191161478Sdelphij		if (IS_UPPER(*p))
19260786Sps			return (1);
19360786Sps	return (0);
19460786Sps}
19560786Sps
19660786Sps/*
19760786Sps * Is there a previous (remembered) search pattern?
19860786Sps */
19960786Sps	static int
20060786Spsprev_pattern()
20160786Sps{
20260786Sps	if (last_search_type & SRCH_NO_REGEX)
20360786Sps		return (last_pattern != NULL);
20460786Sps#if HAVE_POSIX_REGCOMP
20560786Sps	return (regpattern != NULL);
20660786Sps#endif
20760786Sps#if HAVE_PCRE
20860786Sps	return (regpattern != NULL);
20960786Sps#endif
21060786Sps#if HAVE_RE_COMP
21160786Sps	return (re_pattern != 0);
21260786Sps#endif
21360786Sps#if HAVE_REGCMP
21460786Sps	return (cpattern != NULL);
21560786Sps#endif
21660786Sps#if HAVE_V8_REGCOMP
21760786Sps	return (regpattern != NULL);
21860786Sps#endif
21960786Sps#if NO_REGEX
22060786Sps	return (last_pattern != NULL);
22160786Sps#endif
22260786Sps}
22360786Sps
22460786Sps#if HILITE_SEARCH
22560786Sps/*
22660786Sps * Repaint the hilites currently displayed on the screen.
22760786Sps * Repaint each line which contains highlighted text.
22860786Sps * If on==0, force all hilites off.
22960786Sps */
23060786Sps	public void
23160786Spsrepaint_hilite(on)
23260786Sps	int on;
23360786Sps{
23460786Sps	int slinenum;
23560786Sps	POSITION pos;
23660786Sps	POSITION epos;
23760786Sps	int save_hide_hilite;
23860786Sps
23960786Sps	if (squished)
24060786Sps		repaint();
24160786Sps
24260786Sps	save_hide_hilite = hide_hilite;
24360786Sps	if (!on)
24460786Sps	{
24560786Sps		if (hide_hilite)
24660786Sps			return;
24760786Sps		hide_hilite = 1;
24860786Sps	}
24960786Sps
25060786Sps	if (!can_goto_line)
25160786Sps	{
25260786Sps		repaint();
25360786Sps		hide_hilite = save_hide_hilite;
25460786Sps		return;
25560786Sps	}
25660786Sps
25760786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
25860786Sps	{
25960786Sps		pos = position(slinenum);
26060786Sps		if (pos == NULL_POSITION)
26160786Sps			continue;
26260786Sps		epos = position(slinenum+1);
263161478Sdelphij#if 0
26460786Sps		/*
26560786Sps		 * If any character in the line is highlighted,
26660786Sps		 * repaint the line.
267161478Sdelphij		 *
268161478Sdelphij		 * {{ This doesn't work -- if line is drawn with highlights
269161478Sdelphij		 * which should be erased (e.g. toggle -i with status column),
270161478Sdelphij		 * we must redraw the line even if it has no highlights.
271161478Sdelphij		 * For now, just repaint every line. }}
27260786Sps		 */
273161478Sdelphij		if (is_hilited(pos, epos, 1, NULL))
274161478Sdelphij#endif
27560786Sps		{
27660786Sps			(void) forw_line(pos);
27760786Sps			goto_line(slinenum);
27860786Sps			put_line();
27960786Sps		}
28060786Sps	}
281170259Sdelphij	if (!oldbot)
282170259Sdelphij		lower_left();
28360786Sps	hide_hilite = save_hide_hilite;
28460786Sps}
28560786Sps
28660786Sps/*
28760786Sps * Clear the attn hilite.
28860786Sps */
28960786Sps	public void
29060786Spsclear_attn()
29160786Sps{
29260786Sps	int slinenum;
29360786Sps	POSITION old_start_attnpos;
29460786Sps	POSITION old_end_attnpos;
29560786Sps	POSITION pos;
29660786Sps	POSITION epos;
297170898Sdelphij	int moved = 0;
29860786Sps
29960786Sps	if (start_attnpos == NULL_POSITION)
30060786Sps		return;
30160786Sps	old_start_attnpos = start_attnpos;
30260786Sps	old_end_attnpos = end_attnpos;
30360786Sps	start_attnpos = end_attnpos = NULL_POSITION;
30460786Sps
30560786Sps	if (!can_goto_line)
30660786Sps	{
30760786Sps		repaint();
30860786Sps		return;
30960786Sps	}
31060786Sps	if (squished)
31160786Sps		repaint();
31260786Sps
31360786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
31460786Sps	{
31560786Sps		pos = position(slinenum);
31660786Sps		if (pos == NULL_POSITION)
31760786Sps			continue;
31860786Sps		epos = position(slinenum+1);
31960786Sps		if (pos < old_end_attnpos &&
32060786Sps		     (epos == NULL_POSITION || epos > old_start_attnpos))
32160786Sps		{
32260786Sps			(void) forw_line(pos);
32360786Sps			goto_line(slinenum);
32460786Sps			put_line();
325170898Sdelphij			moved = 1;
32660786Sps		}
32760786Sps	}
328170898Sdelphij	if (moved)
329170898Sdelphij		lower_left();
33060786Sps}
33160786Sps#endif
33260786Sps
33360786Sps/*
33460786Sps * Hide search string highlighting.
33560786Sps */
33660786Sps	public void
33760786Spsundo_search()
33860786Sps{
33960786Sps	if (!prev_pattern())
34060786Sps	{
34160786Sps		error("No previous regular expression", NULL_PARG);
34260786Sps		return;
34360786Sps	}
34460786Sps#if HILITE_SEARCH
34560786Sps	hide_hilite = !hide_hilite;
34660786Sps	repaint_hilite(1);
34760786Sps#endif
34860786Sps}
34960786Sps
35060786Sps/*
35160786Sps * Compile a search pattern, for future use by match_pattern.
35260786Sps */
35360786Sps	static int
35460786Spscompile_pattern(pattern, search_type)
35560786Sps	char *pattern;
35660786Sps	int search_type;
35760786Sps{
35860786Sps	if ((search_type & SRCH_NO_REGEX) == 0)
35960786Sps	{
36060786Sps#if HAVE_POSIX_REGCOMP
36160786Sps		regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
36260786Sps		if (regcomp(s, pattern, REGCOMP_FLAG))
36360786Sps		{
36460786Sps			free(s);
36560786Sps			error("Invalid pattern", NULL_PARG);
36660786Sps			return (-1);
36760786Sps		}
36860786Sps		if (regpattern != NULL)
36960786Sps			regfree(regpattern);
37060786Sps		regpattern = s;
37160786Sps#endif
37260786Sps#if HAVE_PCRE
37360786Sps		pcre *comp;
37460786Sps		const char *errstring;
37560786Sps		int erroffset;
37660786Sps		PARG parg;
37760786Sps		comp = pcre_compile(pattern, 0,
37860786Sps				&errstring, &erroffset, NULL);
37960786Sps		if (comp == NULL)
38060786Sps		{
38160786Sps			parg.p_string = (char *) errstring;
38260786Sps			error("%s", &parg);
38360786Sps			return (-1);
38460786Sps		}
38560786Sps		regpattern = comp;
38660786Sps#endif
38760786Sps#if HAVE_RE_COMP
38860786Sps		PARG parg;
38960786Sps		if ((parg.p_string = re_comp(pattern)) != NULL)
39060786Sps		{
39160786Sps			error("%s", &parg);
39260786Sps			return (-1);
39360786Sps		}
39460786Sps		re_pattern = 1;
39560786Sps#endif
39660786Sps#if HAVE_REGCMP
39760786Sps		char *s;
39860786Sps		if ((s = regcmp(pattern, 0)) == NULL)
39960786Sps		{
40060786Sps			error("Invalid pattern", NULL_PARG);
40160786Sps			return (-1);
40260786Sps		}
40360786Sps		if (cpattern != NULL)
40460786Sps			free(cpattern);
40560786Sps		cpattern = s;
40660786Sps#endif
40760786Sps#if HAVE_V8_REGCOMP
40860786Sps		struct regexp *s;
40960786Sps		if ((s = regcomp(pattern)) == NULL)
41060786Sps		{
41160786Sps			/*
41260786Sps			 * regcomp has already printed an error message
41360786Sps			 * via regerror().
41460786Sps			 */
41560786Sps			return (-1);
41660786Sps		}
41760786Sps		if (regpattern != NULL)
41860786Sps			free(regpattern);
41960786Sps		regpattern = s;
42060786Sps#endif
42160786Sps	}
42260786Sps
42360786Sps	if (last_pattern != NULL)
42460786Sps		free(last_pattern);
42560786Sps	last_pattern = (char *) calloc(1, strlen(pattern)+1);
42660786Sps	if (last_pattern != NULL)
42760786Sps		strcpy(last_pattern, pattern);
42860786Sps
42960786Sps	last_search_type = search_type;
43060786Sps	return (0);
43160786Sps}
43260786Sps
43360786Sps/*
43460786Sps * Forget that we have a compiled pattern.
43560786Sps */
43660786Sps	static void
43760786Spsuncompile_pattern()
43860786Sps{
43960786Sps#if HAVE_POSIX_REGCOMP
44060786Sps	if (regpattern != NULL)
44160786Sps		regfree(regpattern);
44260786Sps	regpattern = NULL;
44360786Sps#endif
44460786Sps#if HAVE_PCRE
44560786Sps	if (regpattern != NULL)
44660786Sps		pcre_free(regpattern);
44760786Sps	regpattern = NULL;
44860786Sps#endif
44960786Sps#if HAVE_RE_COMP
45060786Sps	re_pattern = 0;
45160786Sps#endif
45260786Sps#if HAVE_REGCMP
45360786Sps	if (cpattern != NULL)
45460786Sps		free(cpattern);
45560786Sps	cpattern = NULL;
45660786Sps#endif
45760786Sps#if HAVE_V8_REGCOMP
45860786Sps	if (regpattern != NULL)
45960786Sps		free(regpattern);
46060786Sps	regpattern = NULL;
46160786Sps#endif
46260786Sps	last_pattern = NULL;
46360786Sps}
46460786Sps
46560786Sps/*
46660786Sps * Perform a pattern match with the previously compiled pattern.
46760786Sps * Set sp and ep to the start and end of the matched string.
46860786Sps */
46960786Sps	static int
470170259Sdelphijmatch_pattern(line, line_len, sp, ep, notbol)
47160786Sps	char *line;
472170259Sdelphij	int line_len;
47360786Sps	char **sp;
47460786Sps	char **ep;
47560786Sps	int notbol;
47660786Sps{
47760786Sps	int matched;
47860786Sps
47960786Sps	if (last_search_type & SRCH_NO_REGEX)
480170259Sdelphij		return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
48160786Sps
48260786Sps#if HAVE_POSIX_REGCOMP
48360786Sps	{
48460786Sps		regmatch_t rm;
48560786Sps		int flags = (notbol) ? REG_NOTBOL : 0;
48660786Sps		matched = !regexec(regpattern, line, 1, &rm, flags);
48760786Sps		if (!matched)
48860786Sps			return (0);
48960786Sps#ifndef __WATCOMC__
49060786Sps		*sp = line + rm.rm_so;
49160786Sps		*ep = line + rm.rm_eo;
49260786Sps#else
49360786Sps		*sp = rm.rm_sp;
49460786Sps		*ep = rm.rm_ep;
49560786Sps#endif
49660786Sps	}
49760786Sps#endif
49860786Sps#if HAVE_PCRE
49960786Sps	{
50060786Sps		int flags = (notbol) ? PCRE_NOTBOL : 0;
50160786Sps		int ovector[3];
502170259Sdelphij		matched = pcre_exec(regpattern, NULL, line, line_len,
50360786Sps			0, flags, ovector, 3) >= 0;
50460786Sps		if (!matched)
50560786Sps			return (0);
50660786Sps		*sp = line + ovector[0];
50760786Sps		*ep = line + ovector[1];
50860786Sps	}
50960786Sps#endif
51060786Sps#if HAVE_RE_COMP
51160786Sps	matched = (re_exec(line) == 1);
51260786Sps	/*
51360786Sps	 * re_exec doesn't seem to provide a way to get the matched string.
51460786Sps	 */
51560786Sps	*sp = *ep = NULL;
51660786Sps#endif
51760786Sps#if HAVE_REGCMP
51860786Sps	*ep = regex(cpattern, line);
51960786Sps	matched = (*ep != NULL);
52060786Sps	if (!matched)
52160786Sps		return (0);
52260786Sps	*sp = __loc1;
52360786Sps#endif
52460786Sps#if HAVE_V8_REGCOMP
52560786Sps#if HAVE_REGEXEC2
52660786Sps	matched = regexec2(regpattern, line, notbol);
52760786Sps#else
52860786Sps	matched = regexec(regpattern, line);
52960786Sps#endif
53060786Sps	if (!matched)
53160786Sps		return (0);
53260786Sps	*sp = regpattern->startp[0];
53360786Sps	*ep = regpattern->endp[0];
53460786Sps#endif
53560786Sps#if NO_REGEX
536170259Sdelphij	matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
53760786Sps#endif
53860786Sps	return (matched);
53960786Sps}
54060786Sps
54160786Sps#if HILITE_SEARCH
54260786Sps/*
54360786Sps * Clear the hilite list.
54460786Sps */
54560786Sps	public void
54660786Spsclr_hilite()
54760786Sps{
54860786Sps	struct hilite *hl;
54960786Sps	struct hilite *nexthl;
55060786Sps
55160786Sps	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = nexthl)
55260786Sps	{
55360786Sps		nexthl = hl->hl_next;
55460786Sps		free((void*)hl);
55560786Sps	}
55660786Sps	hilite_anchor.hl_first = NULL;
55760786Sps	prep_startpos = prep_endpos = NULL_POSITION;
55860786Sps}
55960786Sps
56060786Sps/*
56160786Sps * Should any characters in a specified range be highlighted?
562161478Sdelphij */
563161478Sdelphij	static int
564161478Sdelphijis_hilited_range(pos, epos)
565161478Sdelphij	POSITION pos;
566161478Sdelphij	POSITION epos;
567161478Sdelphij{
568161478Sdelphij	struct hilite *hl;
569161478Sdelphij
570161478Sdelphij	/*
571161478Sdelphij	 * Look at each highlight and see if any part of it falls in the range.
572161478Sdelphij	 */
573161478Sdelphij	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
574161478Sdelphij	{
575161478Sdelphij		if (hl->hl_endpos > pos &&
576161478Sdelphij		    (epos == NULL_POSITION || epos > hl->hl_startpos))
577161478Sdelphij			return (1);
578161478Sdelphij	}
579161478Sdelphij	return (0);
580161478Sdelphij}
581161478Sdelphij
582161478Sdelphij/*
583161478Sdelphij * Should any characters in a specified range be highlighted?
58460786Sps * If nohide is nonzero, don't consider hide_hilite.
58560786Sps */
58660786Sps	public int
587161478Sdelphijis_hilited(pos, epos, nohide, p_matches)
58860786Sps	POSITION pos;
58960786Sps	POSITION epos;
59060786Sps	int nohide;
591161478Sdelphij	int *p_matches;
59260786Sps{
593161478Sdelphij	int match;
59460786Sps
595161478Sdelphij	if (p_matches != NULL)
596161478Sdelphij		*p_matches = 0;
597161478Sdelphij
59863131Sps	if (!status_col &&
59963131Sps	    start_attnpos != NULL_POSITION &&
60060786Sps	    pos < end_attnpos &&
60160786Sps	     (epos == NULL_POSITION || epos > start_attnpos))
60260786Sps		/*
60360786Sps		 * The attn line overlaps this range.
60460786Sps		 */
60560786Sps		return (1);
60660786Sps
607161478Sdelphij	match = is_hilited_range(pos, epos);
608161478Sdelphij	if (!match)
609161478Sdelphij		return (0);
610161478Sdelphij
611161478Sdelphij	if (p_matches != NULL)
612161478Sdelphij		/*
613161478Sdelphij		 * Report matches, even if we're hiding highlights.
614161478Sdelphij		 */
615161478Sdelphij		*p_matches = 1;
616161478Sdelphij
61760786Sps	if (hilite_search == 0)
61860786Sps		/*
61960786Sps		 * Not doing highlighting.
62060786Sps		 */
62160786Sps		return (0);
62260786Sps
62360786Sps	if (!nohide && hide_hilite)
62460786Sps		/*
62560786Sps		 * Highlighting is hidden.
62660786Sps		 */
62760786Sps		return (0);
62860786Sps
629161478Sdelphij	return (1);
63060786Sps}
63160786Sps
63260786Sps/*
63360786Sps * Add a new hilite to a hilite list.
63460786Sps */
63560786Sps	static void
63660786Spsadd_hilite(anchor, hl)
63760786Sps	struct hilite *anchor;
63860786Sps	struct hilite *hl;
63960786Sps{
64060786Sps	struct hilite *ihl;
64160786Sps
64260786Sps	/*
64360786Sps	 * Hilites are sorted in the list; find where new one belongs.
64460786Sps	 * Insert new one after ihl.
64560786Sps	 */
64660786Sps	for (ihl = anchor;  ihl->hl_next != NULL;  ihl = ihl->hl_next)
64760786Sps	{
64860786Sps		if (ihl->hl_next->hl_startpos > hl->hl_startpos)
64960786Sps			break;
65060786Sps	}
65160786Sps
65260786Sps	/*
65360786Sps	 * Truncate hilite so it doesn't overlap any existing ones
65460786Sps	 * above and below it.
65560786Sps	 */
65660786Sps	if (ihl != anchor)
65760786Sps		hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
65860786Sps	if (ihl->hl_next != NULL)
65960786Sps		hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
66060786Sps	if (hl->hl_startpos >= hl->hl_endpos)
66160786Sps	{
66260786Sps		/*
66360786Sps		 * Hilite was truncated out of existence.
66460786Sps		 */
66560786Sps		free(hl);
66660786Sps		return;
66760786Sps	}
66860786Sps	hl->hl_next = ihl->hl_next;
66960786Sps	ihl->hl_next = hl;
67060786Sps}
67160786Sps
672161478Sdelphij	static void
673170259Sdelphijadj_hilite_ansi(cvt_ops, line, line_len, npos)
674161478Sdelphij	int cvt_ops;
675161478Sdelphij	char **line;
676170259Sdelphij	int line_len;
677161478Sdelphij	POSITION *npos;
678161478Sdelphij{
679170259Sdelphij	char *line_end = *line + line_len;
680170259Sdelphij
681161478Sdelphij	if (cvt_ops & CVT_ANSI)
682161478Sdelphij		while (**line == ESC)
683161478Sdelphij		{
684161478Sdelphij			/*
685161478Sdelphij			 * Found an ESC.  The file position moves
686161478Sdelphij			 * forward past the entire ANSI escape sequence.
687161478Sdelphij			 */
688161478Sdelphij			(*line)++;
689161478Sdelphij			(*npos)++;
690170259Sdelphij			while (*line < line_end)
691161478Sdelphij			{
692161478Sdelphij				(*npos)++;
693161478Sdelphij				if (!is_ansi_middle(*(*line)++))
694161478Sdelphij					break;
695161478Sdelphij			}
696161478Sdelphij		}
697161478Sdelphij}
698161478Sdelphij
69960786Sps/*
70060786Sps * Adjust hl_startpos & hl_endpos to account for backspace processing.
70160786Sps */
70260786Sps	static void
703128348Stjradj_hilite(anchor, linepos, cvt_ops)
70460786Sps	struct hilite *anchor;
70560786Sps	POSITION linepos;
706128348Stjr	int cvt_ops;
70760786Sps{
70860786Sps	char *line;
709170259Sdelphij	int line_len;
710170259Sdelphij	char *line_end;
71160786Sps	struct hilite *hl;
71260786Sps	int checkstart;
71360786Sps	POSITION opos;
71460786Sps	POSITION npos;
71560786Sps
71660786Sps	/*
71760786Sps	 * The line was already scanned and hilites were added (in hilite_line).
71860786Sps	 * But it was assumed that each char position in the line
71960786Sps	 * correponds to one char position in the file.
72060786Sps	 * This may not be true if there are backspaces in the line.
72160786Sps	 * Get the raw line again.  Look at each character.
72260786Sps	 */
723170259Sdelphij	(void) forw_raw_line(linepos, &line, &line_len);
724170259Sdelphij	line_end = line + line_len;
72560786Sps	opos = npos = linepos;
72660786Sps	hl = anchor->hl_first;
72760786Sps	checkstart = TRUE;
72860786Sps	while (hl != NULL)
72960786Sps	{
73060786Sps		/*
73160786Sps		 * See if we need to adjust the current hl_startpos or
73260786Sps		 * hl_endpos.  After adjusting startpos[i], move to endpos[i].
73360786Sps		 * After adjusting endpos[i], move to startpos[i+1].
73460786Sps		 * The hilite list must be sorted thus:
73560786Sps		 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
73660786Sps		 */
73760786Sps		if (checkstart && hl->hl_startpos == opos)
73860786Sps		{
73960786Sps			hl->hl_startpos = npos;
74060786Sps			checkstart = FALSE;
74160786Sps			continue; /* {{ not really necessary }} */
74260786Sps		} else if (!checkstart && hl->hl_endpos == opos)
74360786Sps		{
74460786Sps			hl->hl_endpos = npos;
74560786Sps			checkstart = TRUE;
74660786Sps			hl = hl->hl_next;
74760786Sps			continue; /* {{ necessary }} */
74860786Sps		}
749170259Sdelphij		if (line == line_end)
75060786Sps			break;
751170259Sdelphij		adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos);
75260786Sps		opos++;
75360786Sps		npos++;
75460786Sps		line++;
755128348Stjr		if (cvt_ops & CVT_BS)
75660786Sps		{
757161478Sdelphij			while (*line == '\b')
758128348Stjr			{
759161478Sdelphij				npos++;
760161478Sdelphij				line++;
761170259Sdelphij				adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos);
762170259Sdelphij				if (line == line_end)
763161478Sdelphij				{
764161478Sdelphij					--npos;
765161478Sdelphij					--line;
766161478Sdelphij					break;
767161478Sdelphij				}
768128348Stjr				/*
769128348Stjr				 * Found a backspace.  The file position moves
770128348Stjr				 * forward by 2 relative to the processed line
771128348Stjr				 * which was searched in hilite_line.
772128348Stjr				 */
773161478Sdelphij				npos++;
774161478Sdelphij				line++;
775128348Stjr			}
77660786Sps		}
77760786Sps	}
77860786Sps}
77960786Sps
78060786Sps/*
78160786Sps * Make a hilite for each string in a physical line which matches
78260786Sps * the current pattern.
78360786Sps * sp,ep delimit the first match already found.
78460786Sps */
78560786Sps	static void
786170259Sdelphijhilite_line(linepos, line, line_len, sp, ep, cvt_ops)
78760786Sps	POSITION linepos;
78860786Sps	char *line;
789170259Sdelphij	int line_len;
79060786Sps	char *sp;
79160786Sps	char *ep;
792128348Stjr	int cvt_ops;
79360786Sps{
79460786Sps	char *searchp;
795170259Sdelphij	char *line_end = line + line_len;
79660786Sps	struct hilite *hl;
79760786Sps	struct hilite hilites;
79860786Sps
79960786Sps	if (sp == NULL || ep == NULL)
80060786Sps		return;
80160786Sps	/*
80260786Sps	 * sp and ep delimit the first match in the line.
80360786Sps	 * Mark the corresponding file positions, then
80460786Sps	 * look for further matches and mark them.
80560786Sps	 * {{ This technique, of calling match_pattern on subsequent
80660786Sps	 *    substrings of the line, may mark more than is correct
80760786Sps	 *    if the pattern starts with "^".  This bug is fixed
80860786Sps	 *    for those regex functions that accept a notbol parameter
809170259Sdelphij	 *    (currently POSIX, PCRE and V8-with-regexec2). }}
81060786Sps	 */
81160786Sps	searchp = line;
81260786Sps	/*
81360786Sps	 * Put the hilites into a temporary list until they're adjusted.
81460786Sps	 */
81560786Sps	hilites.hl_first = NULL;
81660786Sps	do {
81760786Sps		if (ep > sp)
81860786Sps		{
81960786Sps			/*
82060786Sps			 * Assume that each char position in the "line"
82160786Sps			 * buffer corresponds to one char position in the file.
82260786Sps			 * This is not quite true; we need to adjust later.
82360786Sps			 */
82460786Sps			hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
82560786Sps			hl->hl_startpos = linepos + (sp-line);
82660786Sps			hl->hl_endpos = linepos + (ep-line);
82760786Sps			add_hilite(&hilites, hl);
82860786Sps		}
82960786Sps		/*
83060786Sps		 * If we matched more than zero characters,
83160786Sps		 * move to the first char after the string we matched.
83260786Sps		 * If we matched zero, just move to the next char.
83360786Sps		 */
83460786Sps		if (ep > searchp)
83560786Sps			searchp = ep;
836170259Sdelphij		else if (searchp != line_end)
83760786Sps			searchp++;
83860786Sps		else /* end of line */
83960786Sps			break;
840170259Sdelphij	} while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1));
84160786Sps
84260786Sps	/*
843128348Stjr	 * If there were backspaces in the original line, they
844128348Stjr	 * were removed, and hl_startpos/hl_endpos are not correct.
845128348Stjr	 * {{ This is very ugly. }}
846128348Stjr	 */
847128348Stjr	adj_hilite(&hilites, linepos, cvt_ops);
848128348Stjr
849128348Stjr	/*
85060786Sps	 * Now put the hilites into the real list.
85160786Sps	 */
85260786Sps	while ((hl = hilites.hl_next) != NULL)
85360786Sps	{
85460786Sps		hilites.hl_next = hl->hl_next;
85560786Sps		add_hilite(&hilite_anchor, hl);
85660786Sps	}
85760786Sps}
85860786Sps#endif
85960786Sps
86060786Sps/*
86160786Sps * Change the caseless-ness of searches.
86260786Sps * Updates the internal search state to reflect a change in the -i flag.
86360786Sps */
86460786Sps	public void
86560786Spschg_caseless()
86660786Sps{
86760786Sps	if (!is_ucase_pattern)
86860786Sps		/*
86960786Sps		 * Pattern did not have uppercase.
87060786Sps		 * Just set the search caselessness to the global caselessness.
87160786Sps		 */
87260786Sps		is_caseless = caseless;
87360786Sps	else
87460786Sps		/*
87560786Sps		 * Pattern did have uppercase.
87660786Sps		 * Discard the pattern; we can't change search caselessness now.
87760786Sps		 */
87860786Sps		uncompile_pattern();
87960786Sps}
88060786Sps
88160786Sps#if HILITE_SEARCH
88260786Sps/*
88360786Sps * Find matching text which is currently on screen and highlight it.
88460786Sps */
88560786Sps	static void
88660786Spshilite_screen()
88760786Sps{
88860786Sps	struct scrpos scrpos;
88960786Sps
89060786Sps	get_scrpos(&scrpos);
89160786Sps	if (scrpos.pos == NULL_POSITION)
89260786Sps		return;
89360786Sps	prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
89460786Sps	repaint_hilite(1);
89560786Sps}
89660786Sps
89760786Sps/*
89860786Sps * Change highlighting parameters.
89960786Sps */
90060786Sps	public void
90160786Spschg_hilite()
90260786Sps{
90360786Sps	/*
90460786Sps	 * Erase any highlights currently on screen.
90560786Sps	 */
90660786Sps	clr_hilite();
90760786Sps	hide_hilite = 0;
90860786Sps
90960786Sps	if (hilite_search == OPT_ONPLUS)
91060786Sps		/*
91160786Sps		 * Display highlights.
91260786Sps		 */
91360786Sps		hilite_screen();
91460786Sps}
91560786Sps#endif
91660786Sps
91760786Sps/*
91860786Sps * Figure out where to start a search.
91960786Sps */
92060786Sps	static POSITION
92160786Spssearch_pos(search_type)
92260786Sps	int search_type;
92360786Sps{
92460786Sps	POSITION pos;
92560786Sps	int linenum;
92660786Sps
92760786Sps	if (empty_screen())
92860786Sps	{
92960786Sps		/*
93060786Sps		 * Start at the beginning (or end) of the file.
93160786Sps		 * The empty_screen() case is mainly for
93260786Sps		 * command line initiated searches;
93360786Sps		 * for example, "+/xyz" on the command line.
93460786Sps		 * Also for multi-file (SRCH_PAST_EOF) searches.
93560786Sps		 */
93660786Sps		if (search_type & SRCH_FORW)
93760786Sps		{
93860786Sps			return (ch_zero());
93960786Sps		} else
94060786Sps		{
94160786Sps			pos = ch_length();
94260786Sps			if (pos == NULL_POSITION)
94360786Sps			{
94460786Sps				(void) ch_end_seek();
94560786Sps				pos = ch_length();
94660786Sps			}
94760786Sps			return (pos);
94860786Sps		}
94960786Sps	}
95060786Sps	if (how_search)
95160786Sps	{
95260786Sps		/*
95360786Sps		 * Search does not include current screen.
95460786Sps		 */
95560786Sps		if (search_type & SRCH_FORW)
95660786Sps			linenum = BOTTOM_PLUS_ONE;
95760786Sps		else
95860786Sps			linenum = TOP;
95960786Sps		pos = position(linenum);
96060786Sps	} else
96160786Sps	{
96260786Sps		/*
96360786Sps		 * Search includes current screen.
96460786Sps		 * It starts at the jump target (if searching backwards),
96560786Sps		 * or at the jump target plus one (if forwards).
96660786Sps		 */
96760786Sps		linenum = adjsline(jump_sline);
96860786Sps		pos = position(linenum);
96960786Sps		if (search_type & SRCH_FORW)
97060786Sps		{
971170259Sdelphij			pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
97260786Sps			while (pos == NULL_POSITION)
97360786Sps			{
97460786Sps				if (++linenum >= sc_height)
97560786Sps					break;
97660786Sps				pos = position(linenum);
97760786Sps			}
97860786Sps		} else
97960786Sps		{
98060786Sps			while (pos == NULL_POSITION)
98160786Sps			{
98260786Sps				if (--linenum < 0)
98360786Sps					break;
98460786Sps				pos = position(linenum);
98560786Sps			}
98660786Sps		}
98760786Sps	}
98860786Sps	return (pos);
98960786Sps}
99060786Sps
99160786Sps/*
99260786Sps * Search a subset of the file, specified by start/end position.
99360786Sps */
99460786Sps	static int
99560786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
99660786Sps	POSITION pos;
99760786Sps	POSITION endpos;
99860786Sps	int search_type;
99960786Sps	int matches;
100060786Sps	int maxlines;
100160786Sps	POSITION *plinepos;
100260786Sps	POSITION *pendpos;
100360786Sps{
100460786Sps	char *line;
1005170259Sdelphij	int line_len;
1006128348Stjr	LINENUM linenum;
100760786Sps	char *sp, *ep;
100860786Sps	int line_match;
1009128348Stjr	int cvt_ops;
101060786Sps	POSITION linepos, oldpos;
101160786Sps
101260786Sps	linenum = find_linenum(pos);
101360786Sps	oldpos = pos;
101460786Sps	for (;;)
101560786Sps	{
101660786Sps		/*
101760786Sps		 * Get lines until we find a matching one or until
101860786Sps		 * we hit end-of-file (or beginning-of-file if we're
101960786Sps		 * going backwards), or until we hit the end position.
102060786Sps		 */
102160786Sps		if (ABORT_SIGS())
102260786Sps		{
102360786Sps			/*
102460786Sps			 * A signal aborts the search.
102560786Sps			 */
102660786Sps			return (-1);
102760786Sps		}
102860786Sps
102960786Sps		if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
103060786Sps		{
103160786Sps			/*
103260786Sps			 * Reached end position without a match.
103360786Sps			 */
103460786Sps			if (pendpos != NULL)
103560786Sps				*pendpos = pos;
103660786Sps			return (matches);
103760786Sps		}
103860786Sps		if (maxlines > 0)
103960786Sps			maxlines--;
104060786Sps
104160786Sps		if (search_type & SRCH_FORW)
104260786Sps		{
104360786Sps			/*
104460786Sps			 * Read the next line, and save the
104560786Sps			 * starting position of that line in linepos.
104660786Sps			 */
104760786Sps			linepos = pos;
1048170259Sdelphij			pos = forw_raw_line(pos, &line, &line_len);
104960786Sps			if (linenum != 0)
105060786Sps				linenum++;
105160786Sps		} else
105260786Sps		{
105360786Sps			/*
105460786Sps			 * Read the previous line and save the
105560786Sps			 * starting position of that line in linepos.
105660786Sps			 */
1057170259Sdelphij			pos = back_raw_line(pos, &line, &line_len);
105860786Sps			linepos = pos;
105960786Sps			if (linenum != 0)
106060786Sps				linenum--;
106160786Sps		}
106260786Sps
106360786Sps		if (pos == NULL_POSITION)
106460786Sps		{
106560786Sps			/*
106660786Sps			 * Reached EOF/BOF without a match.
106760786Sps			 */
106860786Sps			if (pendpos != NULL)
106960786Sps				*pendpos = oldpos;
107060786Sps			return (matches);
107160786Sps		}
107260786Sps
107360786Sps		/*
107460786Sps		 * If we're using line numbers, we might as well
107560786Sps		 * remember the information we have now (the position
107660786Sps		 * and line number of the current line).
107760786Sps		 * Don't do it for every line because it slows down
107860786Sps		 * the search.  Remember the line number only if
107960786Sps		 * we're "far" from the last place we remembered it.
108060786Sps		 */
108160786Sps		if (linenums && abs((int)(pos - oldpos)) > 1024)
108260786Sps			add_lnum(linenum, pos);
108360786Sps		oldpos = pos;
108460786Sps
108560786Sps		/*
108660786Sps		 * If it's a caseless search, convert the line to lowercase.
108760786Sps		 * If we're doing backspace processing, delete backspaces.
108860786Sps		 */
1089128348Stjr		cvt_ops = get_cvt_ops();
1090170259Sdelphij		cvt_text(line, line, &line_len, cvt_ops);
109160786Sps
109260786Sps		/*
109360786Sps		 * Test the next line to see if we have a match.
109460786Sps		 * We are successful if we either want a match and got one,
109560786Sps		 * or if we want a non-match and got one.
109660786Sps		 */
1097170259Sdelphij		line_match = match_pattern(line, line_len, &sp, &ep, 0);
109860786Sps		line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
109960786Sps				((search_type & SRCH_NO_MATCH) && !line_match);
110060786Sps		if (!line_match)
110160786Sps			continue;
110260786Sps		/*
110360786Sps		 * Got a match.
110460786Sps		 */
110560786Sps		if (search_type & SRCH_FIND_ALL)
110660786Sps		{
110760786Sps#if HILITE_SEARCH
110860786Sps			/*
110960786Sps			 * We are supposed to find all matches in the range.
111060786Sps			 * Just add the matches in this line to the
111160786Sps			 * hilite list and keep searching.
111260786Sps			 */
111360786Sps			if (line_match)
1114170259Sdelphij				hilite_line(linepos, line, line_len, sp, ep, cvt_ops);
111560786Sps#endif
111660786Sps		} else if (--matches <= 0)
111760786Sps		{
111860786Sps			/*
111960786Sps			 * Found the one match we're looking for.
112060786Sps			 * Return it.
112160786Sps			 */
112260786Sps#if HILITE_SEARCH
1123161478Sdelphij			if (hilite_search == OPT_ON)
112460786Sps			{
112560786Sps				/*
112660786Sps				 * Clear the hilite list and add only
112760786Sps				 * the matches in this one line.
112860786Sps				 */
112960786Sps				clr_hilite();
113060786Sps				if (line_match)
1131170259Sdelphij					hilite_line(linepos, line, line_len, sp, ep, cvt_ops);
113260786Sps			}
113360786Sps#endif
113460786Sps			if (plinepos != NULL)
113560786Sps				*plinepos = linepos;
113660786Sps			return (0);
113760786Sps		}
113860786Sps	}
113960786Sps}
114060786Sps
1141170259Sdelphij /*
1142170259Sdelphij * search for a pattern in history. If found, compile that pattern.
1143170259Sdelphij */
1144170259Sdelphij	static int
1145170259Sdelphijhist_pattern(search_type)
1146170259Sdelphij	int search_type;
1147170259Sdelphij{
1148170259Sdelphij#if CMD_HISTORY
1149170259Sdelphij	char *pattern;
1150170259Sdelphij
1151170259Sdelphij	set_mlist(ml_search, 0);
1152170259Sdelphij	pattern = cmd_lastpattern();
1153170259Sdelphij	if (pattern == NULL)
1154170259Sdelphij		return (0);
1155170259Sdelphij
1156170259Sdelphij	if (caseless == OPT_ONPLUS)
1157170259Sdelphij		cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC);
1158170259Sdelphij
1159170259Sdelphij	if (compile_pattern(pattern, search_type) < 0)
1160170259Sdelphij		return (0);
1161170259Sdelphij
1162170259Sdelphij	is_ucase_pattern = is_ucase(pattern);
1163170259Sdelphij	if (is_ucase_pattern && caseless != OPT_ONPLUS)
1164170259Sdelphij		is_caseless = 0;
1165170259Sdelphij	else
1166170259Sdelphij		is_caseless = caseless;
1167170259Sdelphij
1168170259Sdelphij#if HILITE_SEARCH
1169170259Sdelphij	if (hilite_search == OPT_ONPLUS && !hide_hilite)
1170170259Sdelphij		hilite_screen();
1171170259Sdelphij#endif
1172170259Sdelphij
1173170259Sdelphij	return (1);
1174170259Sdelphij#else /* CMD_HISTORY */
1175170259Sdelphij	return (0);
1176170259Sdelphij#endif /* CMD_HISTORY */
1177170259Sdelphij}
1178170259Sdelphij
117960786Sps/*
118060786Sps * Search for the n-th occurrence of a specified pattern,
118160786Sps * either forward or backward.
118260786Sps * Return the number of matches not yet found in this file
118360786Sps * (that is, n minus the number of matches found).
118460786Sps * Return -1 if the search should be aborted.
118560786Sps * Caller may continue the search in another file
118660786Sps * if less than n matches are found in this file.
118760786Sps */
118860786Sps	public int
118960786Spssearch(search_type, pattern, n)
119060786Sps	int search_type;
119160786Sps	char *pattern;
119260786Sps	int n;
119360786Sps{
119460786Sps	POSITION pos;
119560786Sps	int ucase;
119660786Sps
119760786Sps	if (pattern == NULL || *pattern == '\0')
119860786Sps	{
119960786Sps		/*
120060786Sps		 * A null pattern means use the previously compiled pattern.
120160786Sps		 */
1202170259Sdelphij		if (!prev_pattern() && !hist_pattern(search_type))
120360786Sps		{
120460786Sps			error("No previous regular expression", NULL_PARG);
120560786Sps			return (-1);
120660786Sps		}
120760786Sps		if ((search_type & SRCH_NO_REGEX) !=
120860786Sps		    (last_search_type & SRCH_NO_REGEX))
120960786Sps		{
121060786Sps			error("Please re-enter search pattern", NULL_PARG);
121160786Sps			return -1;
121260786Sps		}
121360786Sps#if HILITE_SEARCH
121460786Sps		if (hilite_search == OPT_ON)
121560786Sps		{
121660786Sps			/*
121760786Sps			 * Erase the highlights currently on screen.
121860786Sps			 * If the search fails, we'll redisplay them later.
121960786Sps			 */
122060786Sps			repaint_hilite(0);
122160786Sps		}
122260786Sps		if (hilite_search == OPT_ONPLUS && hide_hilite)
122360786Sps		{
122460786Sps			/*
122560786Sps			 * Highlight any matches currently on screen,
122660786Sps			 * before we actually start the search.
122760786Sps			 */
122860786Sps			hide_hilite = 0;
122960786Sps			hilite_screen();
123060786Sps		}
123160786Sps		hide_hilite = 0;
123260786Sps#endif
123360786Sps	} else
123460786Sps	{
123560786Sps		/*
123660786Sps		 * Compile the pattern.
123760786Sps		 */
123860786Sps		ucase = is_ucase(pattern);
123960786Sps		if (caseless == OPT_ONPLUS)
1240170259Sdelphij			cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC);
124160786Sps		if (compile_pattern(pattern, search_type) < 0)
124260786Sps			return (-1);
124360786Sps		/*
124460786Sps		 * Ignore case if -I is set OR
124560786Sps		 * -i is set AND the pattern is all lowercase.
124660786Sps		 */
124760786Sps		is_ucase_pattern = ucase;
124860786Sps		if (is_ucase_pattern && caseless != OPT_ONPLUS)
124960786Sps			is_caseless = 0;
125060786Sps		else
125160786Sps			is_caseless = caseless;
125260786Sps#if HILITE_SEARCH
125360786Sps		if (hilite_search)
125460786Sps		{
125560786Sps			/*
125660786Sps			 * Erase the highlights currently on screen.
125760786Sps			 * Also permanently delete them from the hilite list.
125860786Sps			 */
125960786Sps			repaint_hilite(0);
126060786Sps			hide_hilite = 0;
126160786Sps			clr_hilite();
126260786Sps		}
126360786Sps		if (hilite_search == OPT_ONPLUS)
126460786Sps		{
126560786Sps			/*
126660786Sps			 * Highlight any matches currently on screen,
126760786Sps			 * before we actually start the search.
126860786Sps			 */
126960786Sps			hilite_screen();
127060786Sps		}
127160786Sps#endif
127260786Sps	}
127360786Sps
127460786Sps	/*
127560786Sps	 * Figure out where to start the search.
127660786Sps	 */
127760786Sps	pos = search_pos(search_type);
127860786Sps	if (pos == NULL_POSITION)
127960786Sps	{
128060786Sps		/*
128160786Sps		 * Can't find anyplace to start searching from.
128260786Sps		 */
128360786Sps		if (search_type & SRCH_PAST_EOF)
128460786Sps			return (n);
128560786Sps		/* repaint(); -- why was this here? */
128660786Sps		error("Nothing to search", NULL_PARG);
128760786Sps		return (-1);
128860786Sps	}
128960786Sps
129060786Sps	n = search_range(pos, NULL_POSITION, search_type, n, -1,
129160786Sps			&pos, (POSITION*)NULL);
129260786Sps	if (n != 0)
129360786Sps	{
129460786Sps		/*
129560786Sps		 * Search was unsuccessful.
129660786Sps		 */
129760786Sps#if HILITE_SEARCH
129860786Sps		if (hilite_search == OPT_ON && n > 0)
129960786Sps			/*
130060786Sps			 * Redisplay old hilites.
130160786Sps			 */
130260786Sps			repaint_hilite(1);
130360786Sps#endif
130460786Sps		return (n);
130560786Sps	}
130660786Sps
130760786Sps	if (!(search_type & SRCH_NO_MOVE))
130860786Sps	{
130960786Sps		/*
131060786Sps		 * Go to the matching line.
131160786Sps		 */
131260786Sps		jump_loc(pos, jump_sline);
131360786Sps	}
131460786Sps
131560786Sps#if HILITE_SEARCH
131660786Sps	if (hilite_search == OPT_ON)
131760786Sps		/*
131860786Sps		 * Display new hilites in the matching line.
131960786Sps		 */
132060786Sps		repaint_hilite(1);
132160786Sps#endif
132260786Sps	return (0);
132360786Sps}
132460786Sps
132560786Sps
132660786Sps#if HILITE_SEARCH
132760786Sps/*
132860786Sps * Prepare hilites in a given range of the file.
132960786Sps *
133060786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region
133160786Sps * of the file that has been "prepared"; that is, scanned for matches for
133260786Sps * the current search pattern, and hilites have been created for such matches.
133360786Sps * If prep_startpos == NULL_POSITION, the prep region is empty.
133460786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
133560786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region.
133660786Sps */
133760786Sps	public void
133860786Spsprep_hilite(spos, epos, maxlines)
133960786Sps	POSITION spos;
134060786Sps	POSITION epos;
134160786Sps	int maxlines;
134260786Sps{
134360786Sps	POSITION nprep_startpos = prep_startpos;
134460786Sps	POSITION nprep_endpos = prep_endpos;
134560786Sps	POSITION new_epos;
134660786Sps	POSITION max_epos;
134760786Sps	int result;
134860786Sps	int i;
134960786Sps/*
135060786Sps * Search beyond where we're asked to search, so the prep region covers
135160786Sps * more than we need.  Do one big search instead of a bunch of small ones.
135260786Sps */
135360786Sps#define	SEARCH_MORE (3*size_linebuf)
135460786Sps
135560786Sps	if (!prev_pattern())
135660786Sps		return;
135760786Sps
135860786Sps	/*
135960786Sps	 * If we're limited to a max number of lines, figure out the
136060786Sps	 * file position we should stop at.
136160786Sps	 */
136260786Sps	if (maxlines < 0)
136360786Sps		max_epos = NULL_POSITION;
136460786Sps	else
136560786Sps	{
136660786Sps		max_epos = spos;
136760786Sps		for (i = 0;  i < maxlines;  i++)
1368170259Sdelphij			max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
136960786Sps	}
137060786Sps
137160786Sps	/*
137260786Sps	 * Find two ranges:
137360786Sps	 * The range that we need to search (spos,epos); and the range that
137460786Sps	 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
137560786Sps	 */
137660786Sps
137760786Sps	if (prep_startpos == NULL_POSITION ||
137860786Sps	    (epos != NULL_POSITION && epos < prep_startpos) ||
137960786Sps	    spos > prep_endpos)
138060786Sps	{
138160786Sps		/*
138260786Sps		 * New range is not contiguous with old prep region.
138360786Sps		 * Discard the old prep region and start a new one.
138460786Sps		 */
138560786Sps		clr_hilite();
138660786Sps		if (epos != NULL_POSITION)
138760786Sps			epos += SEARCH_MORE;
138860786Sps		nprep_startpos = spos;
138960786Sps	} else
139060786Sps	{
139160786Sps		/*
139260786Sps		 * New range partially or completely overlaps old prep region.
139360786Sps		 */
139460786Sps		if (epos == NULL_POSITION)
139560786Sps		{
139660786Sps			/*
139760786Sps			 * New range goes to end of file.
139860786Sps			 */
139960786Sps			;
140060786Sps		} else if (epos > prep_endpos)
140160786Sps		{
140260786Sps			/*
140360786Sps			 * New range ends after old prep region.
140460786Sps			 * Extend prep region to end at end of new range.
140560786Sps			 */
140660786Sps			epos += SEARCH_MORE;
140760786Sps		} else /* (epos <= prep_endpos) */
140860786Sps		{
140960786Sps			/*
141060786Sps			 * New range ends within old prep region.
141160786Sps			 * Truncate search to end at start of old prep region.
141260786Sps			 */
141360786Sps			epos = prep_startpos;
141460786Sps		}
141560786Sps
141660786Sps		if (spos < prep_startpos)
141760786Sps		{
141860786Sps			/*
141960786Sps			 * New range starts before old prep region.
142060786Sps			 * Extend old prep region backwards to start at
142160786Sps			 * start of new range.
142260786Sps			 */
142360786Sps			if (spos < SEARCH_MORE)
142460786Sps				spos = 0;
142560786Sps			else
142660786Sps				spos -= SEARCH_MORE;
142760786Sps			nprep_startpos = spos;
142860786Sps		} else /* (spos >= prep_startpos) */
142960786Sps		{
143060786Sps			/*
143160786Sps			 * New range starts within or after old prep region.
143260786Sps			 * Trim search to start at end of old prep region.
143360786Sps			 */
143460786Sps			spos = prep_endpos;
143560786Sps		}
143660786Sps	}
143760786Sps
143860786Sps	if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
143960786Sps	    epos > max_epos)
144060786Sps		/*
144160786Sps		 * Don't go past the max position we're allowed.
144260786Sps		 */
144360786Sps		epos = max_epos;
144460786Sps
144560786Sps	if (epos == NULL_POSITION || epos > spos)
144660786Sps	{
144760786Sps		result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
144860786Sps				maxlines, (POSITION*)NULL, &new_epos);
144960786Sps		if (result < 0)
145060786Sps			return;
145160786Sps		if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
145260786Sps			nprep_endpos = new_epos;
145360786Sps	}
145460786Sps	prep_startpos = nprep_startpos;
145560786Sps	prep_endpos = nprep_endpos;
145660786Sps}
145760786Sps#endif
145860786Sps
145960786Sps/*
146060786Sps * Simple pattern matching function.
146160786Sps * It supports no metacharacters like *, etc.
146260786Sps */
146360786Sps	static int
1464170259Sdelphijmatch(pattern, pattern_len, buf, buf_len, pfound, pend)
1465170259Sdelphij	char *pattern;
1466170259Sdelphij	int pattern_len;
1467170259Sdelphij	char *buf;
1468170259Sdelphij	int buf_len;
146960786Sps	char **pfound, **pend;
147060786Sps{
147160786Sps	register char *pp, *lp;
1472170259Sdelphij	register char *pattern_end = pattern + pattern_len;
1473170259Sdelphij	register char *buf_end = buf + buf_len;
147460786Sps
1475170259Sdelphij	for ( ;  buf < buf_end;  buf++)
147660786Sps	{
147760786Sps		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
1478170259Sdelphij			if (pp == pattern_end || lp == buf_end)
147960786Sps				break;
1480170259Sdelphij		if (pp == pattern_end)
148160786Sps		{
148260786Sps			if (pfound != NULL)
148360786Sps				*pfound = buf;
148460786Sps			if (pend != NULL)
148560786Sps				*pend = lp;
148660786Sps			return (1);
148760786Sps		}
148860786Sps	}
148960786Sps	return (0);
149060786Sps}
149160786Sps
149260786Sps#if HAVE_V8_REGCOMP
149360786Sps/*
149460786Sps * This function is called by the V8 regcomp to report
149560786Sps * errors in regular expressions.
149660786Sps */
149760786Sps	void
149860786Spsregerror(s)
149960786Sps	char *s;
150060786Sps{
150160786Sps	PARG parg;
150260786Sps
150360786Sps	parg.p_string = s;
150460786Sps	error("%s", &parg);
150560786Sps}
150660786Sps#endif
150760786Sps
1508