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