1238730Sdelphij/*
2238730Sdelphij * Copyright (C) 1984-2012  Mark Nudelman
3238730Sdelphij *
4238730Sdelphij * You may distribute under the terms of either the GNU General Public
5238730Sdelphij * License or the Less License, as specified in the README file.
6238730Sdelphij *
7238730Sdelphij * For more information, see the README file.
8238730Sdelphij */
960786Sps
1060786Sps
1160786Sps/*
1260786Sps * Routines to search a file for a pattern.
1360786Sps */
1460786Sps
1560786Sps#include "less.h"
16195941Sdelphij#include "pattern.h"
1760786Sps#include "position.h"
18172471Sdelphij#include "charset.h"
1960786Sps
2060786Sps#define	MINPOS(a,b)	(((a) < (b)) ? (a) : (b))
2160786Sps#define	MAXPOS(a,b)	(((a) > (b)) ? (a) : (b))
2260786Sps
2360786Spsextern int sigs;
2460786Spsextern int how_search;
2560786Spsextern int caseless;
2660786Spsextern int linenums;
2760786Spsextern int sc_height;
2860786Spsextern int jump_sline;
2960786Spsextern int bs_mode;
30128348Stjrextern int ctldisp;
3163131Spsextern int status_col;
32170259Sdelphijextern void * constant ml_search;
3360786Spsextern POSITION start_attnpos;
3460786Spsextern POSITION end_attnpos;
35191930Sdelphijextern int utf_mode;
36191930Sdelphijextern int screen_trashed;
3760786Sps#if HILITE_SEARCH
3860786Spsextern int hilite_search;
3960786Spsextern int size_linebuf;
4060786Spsextern int squished;
4160786Spsextern int can_goto_line;
4260786Spsstatic int hide_hilite;
4360786Spsstatic POSITION prep_startpos;
4460786Spsstatic POSITION prep_endpos;
45195941Sdelphijstatic int is_caseless;
46195941Sdelphijstatic int is_ucase_pattern;
4760786Sps
4860786Spsstruct hilite
4960786Sps{
5060786Sps	struct hilite *hl_next;
5160786Sps	POSITION hl_startpos;
5260786Sps	POSITION hl_endpos;
5360786Sps};
5460786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
55191930Sdelphijstatic struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION };
5660786Sps#define	hl_first	hl_next
5760786Sps#endif
5860786Sps
5960786Sps/*
6060786Sps * These are the static variables that represent the "remembered"
61195941Sdelphij * search pattern and filter pattern.
6260786Sps */
63195941Sdelphijstruct pattern_info {
64195941Sdelphij	DEFINE_PATTERN(compiled);
65195941Sdelphij	char* text;
66195941Sdelphij	int search_type;
67195941Sdelphij};
68237613Sdelphij
69237613Sdelphij#if NO_REGEX
70237613Sdelphij#define info_compiled(info) ((void*)0)
71237613Sdelphij#else
72237613Sdelphij#define info_compiled(info) ((info)->compiled)
73237613Sdelphij#endif
74195941Sdelphij
75195941Sdelphijstatic struct pattern_info search_info;
76195941Sdelphijstatic struct pattern_info filter_info;
7760786Sps
78173685Sdelphij/*
79221715Sdelphij * Are there any uppercase letters in this string?
80221715Sdelphij */
81221715Sdelphij	static int
82221715Sdelphijis_ucase(str)
83221715Sdelphij	char *str;
84221715Sdelphij{
85221715Sdelphij	char *str_end = str + strlen(str);
86221715Sdelphij	LWCHAR ch;
87221715Sdelphij
88221715Sdelphij	while (str < str_end)
89221715Sdelphij	{
90221715Sdelphij		ch = step_char(&str, +1, str_end);
91221715Sdelphij		if (IS_UPPER(ch))
92221715Sdelphij			return (1);
93221715Sdelphij	}
94221715Sdelphij	return (0);
95221715Sdelphij}
96221715Sdelphij
97221715Sdelphij/*
98195941Sdelphij * Compile and save a search pattern.
99173685Sdelphij */
100173685Sdelphij	static int
101195941Sdelphijset_pattern(info, pattern, search_type)
102195941Sdelphij	struct pattern_info *info;
103195941Sdelphij	char *pattern;
104195941Sdelphij	int search_type;
105173685Sdelphij{
106237613Sdelphij#if !NO_REGEX
107195941Sdelphij	if (pattern == NULL)
108237613Sdelphij		CLEAR_PATTERN(info->compiled);
109195941Sdelphij	else if (compile_pattern(pattern, search_type, &info->compiled) < 0)
110195941Sdelphij		return -1;
111237613Sdelphij#endif
112195941Sdelphij	/* Pattern compiled successfully; save the text too. */
113195941Sdelphij	if (info->text != NULL)
114195941Sdelphij		free(info->text);
115195941Sdelphij	info->text = NULL;
116195941Sdelphij	if (pattern != NULL)
117195941Sdelphij	{
118195941Sdelphij		info->text = (char *) ecalloc(1, strlen(pattern)+1);
119195941Sdelphij		strcpy(info->text, pattern);
120195941Sdelphij	}
121195941Sdelphij	info->search_type = search_type;
122221715Sdelphij
123221715Sdelphij	/*
124221715Sdelphij	 * Ignore case if -I is set OR
125221715Sdelphij	 * -i is set AND the pattern is all lowercase.
126221715Sdelphij	 */
127221715Sdelphij	is_ucase_pattern = is_ucase(pattern);
128221715Sdelphij	if (is_ucase_pattern && caseless != OPT_ONPLUS)
129221715Sdelphij		is_caseless = 0;
130221715Sdelphij	else
131221715Sdelphij		is_caseless = caseless;
132195941Sdelphij	return 0;
133173685Sdelphij}
134173685Sdelphij
135173685Sdelphij/*
136195941Sdelphij * Discard a saved pattern.
137173685Sdelphij */
13860786Sps	static void
139195941Sdelphijclear_pattern(info)
140195941Sdelphij	struct pattern_info *info;
14160786Sps{
142195941Sdelphij	if (info->text != NULL)
143195941Sdelphij		free(info->text);
144195941Sdelphij	info->text = NULL;
145237613Sdelphij#if !NO_REGEX
146195941Sdelphij	uncompile_pattern(&info->compiled);
147237613Sdelphij#endif
148195941Sdelphij}
14960786Sps
150195941Sdelphij/*
151195941Sdelphij * Initialize saved pattern to nothing.
152195941Sdelphij */
153195941Sdelphij	static void
154195941Sdelphijinit_pattern(info)
155195941Sdelphij	struct pattern_info *info;
156195941Sdelphij{
157195941Sdelphij	CLEAR_PATTERN(info->compiled);
158195941Sdelphij	info->text = NULL;
159195941Sdelphij	info->search_type = 0;
160195941Sdelphij}
161170259Sdelphij
162195941Sdelphij/*
163195941Sdelphij * Initialize search variables.
164195941Sdelphij */
165195941Sdelphij	public void
166195941Sdelphijinit_search()
167195941Sdelphij{
168195941Sdelphij	init_pattern(&search_info);
169195941Sdelphij	init_pattern(&filter_info);
17060786Sps}
17160786Sps
17260786Sps/*
173195941Sdelphij * Determine which text conversions to perform before pattern matching.
174128348Stjr */
175128348Stjr	static int
176128348Stjrget_cvt_ops()
177128348Stjr{
178128348Stjr	int ops = 0;
179128348Stjr	if (is_caseless || bs_mode == BS_SPECIAL)
180128348Stjr	{
181128348Stjr		if (is_caseless)
182128348Stjr			ops |= CVT_TO_LC;
183128348Stjr		if (bs_mode == BS_SPECIAL)
184128348Stjr			ops |= CVT_BS;
185128348Stjr		if (bs_mode != BS_CONTROL)
186128348Stjr			ops |= CVT_CRLF;
187128348Stjr	} else if (bs_mode != BS_CONTROL)
188128348Stjr	{
189128348Stjr		ops |= CVT_CRLF;
190128348Stjr	}
191128348Stjr	if (ctldisp == OPT_ONPLUS)
192128348Stjr		ops |= CVT_ANSI;
193128348Stjr	return (ops);
194128348Stjr}
195128348Stjr
196128348Stjr/*
19760786Sps * Is there a previous (remembered) search pattern?
19860786Sps */
19960786Sps	static int
200195941Sdelphijprev_pattern(info)
201195941Sdelphij	struct pattern_info *info;
20260786Sps{
203237613Sdelphij#if !NO_REGEX
204237613Sdelphij	if ((info->search_type & SRCH_NO_REGEX) == 0)
205237613Sdelphij		return (!is_null_pattern(info->compiled));
206237613Sdelphij#endif
207237613Sdelphij	return (info->text != NULL);
20860786Sps}
20960786Sps
21060786Sps#if HILITE_SEARCH
21160786Sps/*
21260786Sps * Repaint the hilites currently displayed on the screen.
21360786Sps * Repaint each line which contains highlighted text.
21460786Sps * If on==0, force all hilites off.
21560786Sps */
21660786Sps	public void
21760786Spsrepaint_hilite(on)
21860786Sps	int on;
21960786Sps{
22060786Sps	int slinenum;
22160786Sps	POSITION pos;
22260786Sps	POSITION epos;
22360786Sps	int save_hide_hilite;
22460786Sps
22560786Sps	if (squished)
22660786Sps		repaint();
22760786Sps
22860786Sps	save_hide_hilite = hide_hilite;
22960786Sps	if (!on)
23060786Sps	{
23160786Sps		if (hide_hilite)
23260786Sps			return;
23360786Sps		hide_hilite = 1;
23460786Sps	}
23560786Sps
23660786Sps	if (!can_goto_line)
23760786Sps	{
23860786Sps		repaint();
23960786Sps		hide_hilite = save_hide_hilite;
24060786Sps		return;
24160786Sps	}
24260786Sps
24360786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
24460786Sps	{
24560786Sps		pos = position(slinenum);
24660786Sps		if (pos == NULL_POSITION)
24760786Sps			continue;
24860786Sps		epos = position(slinenum+1);
249195941Sdelphij		(void) forw_line(pos);
250195941Sdelphij		goto_line(slinenum);
251195941Sdelphij		put_line();
25260786Sps	}
253221715Sdelphij	lower_left();
25460786Sps	hide_hilite = save_hide_hilite;
25560786Sps}
25660786Sps
25760786Sps/*
25860786Sps * Clear the attn hilite.
25960786Sps */
26060786Sps	public void
26160786Spsclear_attn()
26260786Sps{
26360786Sps	int slinenum;
26460786Sps	POSITION old_start_attnpos;
26560786Sps	POSITION old_end_attnpos;
26660786Sps	POSITION pos;
26760786Sps	POSITION epos;
268170898Sdelphij	int moved = 0;
26960786Sps
27060786Sps	if (start_attnpos == NULL_POSITION)
27160786Sps		return;
27260786Sps	old_start_attnpos = start_attnpos;
27360786Sps	old_end_attnpos = end_attnpos;
27460786Sps	start_attnpos = end_attnpos = NULL_POSITION;
27560786Sps
27660786Sps	if (!can_goto_line)
27760786Sps	{
27860786Sps		repaint();
27960786Sps		return;
28060786Sps	}
28160786Sps	if (squished)
28260786Sps		repaint();
28360786Sps
28460786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
28560786Sps	{
28660786Sps		pos = position(slinenum);
28760786Sps		if (pos == NULL_POSITION)
28860786Sps			continue;
28960786Sps		epos = position(slinenum+1);
29060786Sps		if (pos < old_end_attnpos &&
29160786Sps		     (epos == NULL_POSITION || epos > old_start_attnpos))
29260786Sps		{
29360786Sps			(void) forw_line(pos);
29460786Sps			goto_line(slinenum);
29560786Sps			put_line();
296170898Sdelphij			moved = 1;
29760786Sps		}
29860786Sps	}
299170898Sdelphij	if (moved)
300170898Sdelphij		lower_left();
30160786Sps}
30260786Sps#endif
30360786Sps
30460786Sps/*
30560786Sps * Hide search string highlighting.
30660786Sps */
30760786Sps	public void
30860786Spsundo_search()
30960786Sps{
310195941Sdelphij	if (!prev_pattern(&search_info))
31160786Sps	{
31260786Sps		error("No previous regular expression", NULL_PARG);
31360786Sps		return;
31460786Sps	}
31560786Sps#if HILITE_SEARCH
31660786Sps	hide_hilite = !hide_hilite;
31760786Sps	repaint_hilite(1);
31860786Sps#endif
31960786Sps}
32060786Sps
32160786Sps#if HILITE_SEARCH
32260786Sps/*
32360786Sps * Clear the hilite list.
32460786Sps */
32560786Sps	public void
326191930Sdelphijclr_hlist(anchor)
327191930Sdelphij	struct hilite *anchor;
32860786Sps{
32960786Sps	struct hilite *hl;
33060786Sps	struct hilite *nexthl;
33160786Sps
332191930Sdelphij	for (hl = anchor->hl_first;  hl != NULL;  hl = nexthl)
33360786Sps	{
33460786Sps		nexthl = hl->hl_next;
33560786Sps		free((void*)hl);
33660786Sps	}
337191930Sdelphij	anchor->hl_first = NULL;
33860786Sps	prep_startpos = prep_endpos = NULL_POSITION;
33960786Sps}
34060786Sps
341191930Sdelphij	public void
342191930Sdelphijclr_hilite()
343191930Sdelphij{
344191930Sdelphij	clr_hlist(&hilite_anchor);
345191930Sdelphij}
346191930Sdelphij
347191930Sdelphij	public void
348191930Sdelphijclr_filter()
349191930Sdelphij{
350191930Sdelphij	clr_hlist(&filter_anchor);
351191930Sdelphij}
352191930Sdelphij
35360786Sps/*
35460786Sps * Should any characters in a specified range be highlighted?
355161478Sdelphij */
356161478Sdelphij	static int
357161478Sdelphijis_hilited_range(pos, epos)
358161478Sdelphij	POSITION pos;
359161478Sdelphij	POSITION epos;
360161478Sdelphij{
361161478Sdelphij	struct hilite *hl;
362161478Sdelphij
363161478Sdelphij	/*
364161478Sdelphij	 * Look at each highlight and see if any part of it falls in the range.
365161478Sdelphij	 */
366161478Sdelphij	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
367161478Sdelphij	{
368161478Sdelphij		if (hl->hl_endpos > pos &&
369161478Sdelphij		    (epos == NULL_POSITION || epos > hl->hl_startpos))
370161478Sdelphij			return (1);
371161478Sdelphij	}
372161478Sdelphij	return (0);
373161478Sdelphij}
374161478Sdelphij
375191930Sdelphij/*
376191930Sdelphij * Is a line "filtered" -- that is, should it be hidden?
377191930Sdelphij */
378191930Sdelphij	public int
379191930Sdelphijis_filtered(pos)
380191930Sdelphij	POSITION pos;
381191930Sdelphij{
382191930Sdelphij	struct hilite *hl;
383191930Sdelphij
384191930Sdelphij	if (ch_getflags() & CH_HELPFILE)
385191930Sdelphij		return (0);
386191930Sdelphij
387191930Sdelphij	/*
388191930Sdelphij	 * Look at each filter and see if the start position
389191930Sdelphij	 * equals the start position of the line.
390191930Sdelphij	 */
391191930Sdelphij	for (hl = filter_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
392191930Sdelphij	{
393191930Sdelphij		if (hl->hl_startpos == pos)
394191930Sdelphij			return (1);
395191930Sdelphij	}
396191930Sdelphij	return (0);
397191930Sdelphij}
398191930Sdelphij
399161478Sdelphij/*
400161478Sdelphij * Should any characters in a specified range be highlighted?
40160786Sps * If nohide is nonzero, don't consider hide_hilite.
40260786Sps */
40360786Sps	public int
404161478Sdelphijis_hilited(pos, epos, nohide, p_matches)
40560786Sps	POSITION pos;
40660786Sps	POSITION epos;
40760786Sps	int nohide;
408161478Sdelphij	int *p_matches;
40960786Sps{
410161478Sdelphij	int match;
41160786Sps
412161478Sdelphij	if (p_matches != NULL)
413161478Sdelphij		*p_matches = 0;
414161478Sdelphij
41563131Sps	if (!status_col &&
41663131Sps	    start_attnpos != NULL_POSITION &&
41760786Sps	    pos < end_attnpos &&
41860786Sps	     (epos == NULL_POSITION || epos > start_attnpos))
41960786Sps		/*
42060786Sps		 * The attn line overlaps this range.
42160786Sps		 */
42260786Sps		return (1);
42360786Sps
424161478Sdelphij	match = is_hilited_range(pos, epos);
425161478Sdelphij	if (!match)
426161478Sdelphij		return (0);
427161478Sdelphij
428161478Sdelphij	if (p_matches != NULL)
429161478Sdelphij		/*
430161478Sdelphij		 * Report matches, even if we're hiding highlights.
431161478Sdelphij		 */
432161478Sdelphij		*p_matches = 1;
433161478Sdelphij
43460786Sps	if (hilite_search == 0)
43560786Sps		/*
43660786Sps		 * Not doing highlighting.
43760786Sps		 */
43860786Sps		return (0);
43960786Sps
44060786Sps	if (!nohide && hide_hilite)
44160786Sps		/*
44260786Sps		 * Highlighting is hidden.
44360786Sps		 */
44460786Sps		return (0);
44560786Sps
446161478Sdelphij	return (1);
44760786Sps}
44860786Sps
44960786Sps/*
45060786Sps * Add a new hilite to a hilite list.
45160786Sps */
45260786Sps	static void
45360786Spsadd_hilite(anchor, hl)
45460786Sps	struct hilite *anchor;
45560786Sps	struct hilite *hl;
45660786Sps{
45760786Sps	struct hilite *ihl;
45860786Sps
45960786Sps	/*
46060786Sps	 * Hilites are sorted in the list; find where new one belongs.
46160786Sps	 * Insert new one after ihl.
46260786Sps	 */
46360786Sps	for (ihl = anchor;  ihl->hl_next != NULL;  ihl = ihl->hl_next)
46460786Sps	{
46560786Sps		if (ihl->hl_next->hl_startpos > hl->hl_startpos)
46660786Sps			break;
46760786Sps	}
46860786Sps
46960786Sps	/*
47060786Sps	 * Truncate hilite so it doesn't overlap any existing ones
47160786Sps	 * above and below it.
47260786Sps	 */
47360786Sps	if (ihl != anchor)
47460786Sps		hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
47560786Sps	if (ihl->hl_next != NULL)
47660786Sps		hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
47760786Sps	if (hl->hl_startpos >= hl->hl_endpos)
47860786Sps	{
47960786Sps		/*
48060786Sps		 * Hilite was truncated out of existence.
48160786Sps		 */
48260786Sps		free(hl);
48360786Sps		return;
48460786Sps	}
48560786Sps	hl->hl_next = ihl->hl_next;
48660786Sps	ihl->hl_next = hl;
48760786Sps}
48860786Sps
48960786Sps/*
490237613Sdelphij * Hilight every character in a range of displayed characters.
491237613Sdelphij */
492237613Sdelphij	static void
493237613Sdelphijcreate_hilites(linepos, start_index, end_index, chpos)
494237613Sdelphij	POSITION linepos;
495237613Sdelphij	int start_index;
496237613Sdelphij	int end_index;
497237613Sdelphij	int *chpos;
498237613Sdelphij{
499237613Sdelphij	struct hilite *hl;
500237613Sdelphij	int i;
501237613Sdelphij
502237613Sdelphij	/* Start the first hilite. */
503237613Sdelphij	hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
504237613Sdelphij	hl->hl_startpos = linepos + chpos[start_index];
505237613Sdelphij
506237613Sdelphij	/*
507237613Sdelphij	 * Step through the displayed chars.
508237613Sdelphij	 * If the source position (before cvt) of the char is one more
509237613Sdelphij	 * than the source pos of the previous char (the usual case),
510237613Sdelphij	 * just increase the size of the current hilite by one.
511237613Sdelphij	 * Otherwise (there are backspaces or something involved),
512237613Sdelphij	 * finish the current hilite and start a new one.
513237613Sdelphij	 */
514237613Sdelphij	for (i = start_index+1;  i <= end_index;  i++)
515237613Sdelphij	{
516237613Sdelphij		if (chpos[i] != chpos[i-1] + 1 || i == end_index)
517237613Sdelphij		{
518237613Sdelphij			hl->hl_endpos = linepos + chpos[i-1] + 1;
519237613Sdelphij			add_hilite(&hilite_anchor, hl);
520237613Sdelphij			/* Start new hilite unless this is the last char. */
521237613Sdelphij			if (i < end_index)
522237613Sdelphij			{
523237613Sdelphij				hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
524237613Sdelphij				hl->hl_startpos = linepos + chpos[i];
525237613Sdelphij			}
526237613Sdelphij		}
527237613Sdelphij	}
528237613Sdelphij}
529237613Sdelphij
530237613Sdelphij/*
53160786Sps * Make a hilite for each string in a physical line which matches
53260786Sps * the current pattern.
53360786Sps * sp,ep delimit the first match already found.
53460786Sps */
53560786Sps	static void
536195941Sdelphijhilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops)
53760786Sps	POSITION linepos;
53860786Sps	char *line;
539170259Sdelphij	int line_len;
540195941Sdelphij	int *chpos;
54160786Sps	char *sp;
54260786Sps	char *ep;
543128348Stjr	int cvt_ops;
54460786Sps{
54560786Sps	char *searchp;
546170259Sdelphij	char *line_end = line + line_len;
54760786Sps
54860786Sps	if (sp == NULL || ep == NULL)
54960786Sps		return;
55060786Sps	/*
55160786Sps	 * sp and ep delimit the first match in the line.
55260786Sps	 * Mark the corresponding file positions, then
55360786Sps	 * look for further matches and mark them.
55460786Sps	 * {{ This technique, of calling match_pattern on subsequent
55560786Sps	 *    substrings of the line, may mark more than is correct
55660786Sps	 *    if the pattern starts with "^".  This bug is fixed
55760786Sps	 *    for those regex functions that accept a notbol parameter
558170259Sdelphij	 *    (currently POSIX, PCRE and V8-with-regexec2). }}
55960786Sps	 */
56060786Sps	searchp = line;
56160786Sps	do {
562237613Sdelphij		create_hilites(linepos, sp-line, ep-line, chpos);
56360786Sps		/*
56460786Sps		 * If we matched more than zero characters,
56560786Sps		 * move to the first char after the string we matched.
56660786Sps		 * If we matched zero, just move to the next char.
56760786Sps		 */
56860786Sps		if (ep > searchp)
56960786Sps			searchp = ep;
570170259Sdelphij		else if (searchp != line_end)
57160786Sps			searchp++;
57260786Sps		else /* end of line */
57360786Sps			break;
574237613Sdelphij	} while (match_pattern(info_compiled(&search_info), search_info.text,
575195941Sdelphij			searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type));
57660786Sps}
57760786Sps#endif
57860786Sps
57960786Sps/*
58060786Sps * Change the caseless-ness of searches.
58160786Sps * Updates the internal search state to reflect a change in the -i flag.
58260786Sps */
58360786Sps	public void
58460786Spschg_caseless()
58560786Sps{
58660786Sps	if (!is_ucase_pattern)
58760786Sps		/*
58860786Sps		 * Pattern did not have uppercase.
58960786Sps		 * Just set the search caselessness to the global caselessness.
59060786Sps		 */
59160786Sps		is_caseless = caseless;
59260786Sps	else
59360786Sps		/*
59460786Sps		 * Pattern did have uppercase.
59560786Sps		 * Discard the pattern; we can't change search caselessness now.
59660786Sps		 */
597195941Sdelphij		clear_pattern(&search_info);
59860786Sps}
59960786Sps
60060786Sps#if HILITE_SEARCH
60160786Sps/*
60260786Sps * Find matching text which is currently on screen and highlight it.
60360786Sps */
60460786Sps	static void
60560786Spshilite_screen()
60660786Sps{
60760786Sps	struct scrpos scrpos;
60860786Sps
60960786Sps	get_scrpos(&scrpos);
61060786Sps	if (scrpos.pos == NULL_POSITION)
61160786Sps		return;
61260786Sps	prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
61360786Sps	repaint_hilite(1);
61460786Sps}
61560786Sps
61660786Sps/*
61760786Sps * Change highlighting parameters.
61860786Sps */
61960786Sps	public void
62060786Spschg_hilite()
62160786Sps{
62260786Sps	/*
62360786Sps	 * Erase any highlights currently on screen.
62460786Sps	 */
62560786Sps	clr_hilite();
62660786Sps	hide_hilite = 0;
62760786Sps
62860786Sps	if (hilite_search == OPT_ONPLUS)
62960786Sps		/*
63060786Sps		 * Display highlights.
63160786Sps		 */
63260786Sps		hilite_screen();
63360786Sps}
63460786Sps#endif
63560786Sps
63660786Sps/*
63760786Sps * Figure out where to start a search.
63860786Sps */
63960786Sps	static POSITION
64060786Spssearch_pos(search_type)
64160786Sps	int search_type;
64260786Sps{
64360786Sps	POSITION pos;
64460786Sps	int linenum;
64560786Sps
64660786Sps	if (empty_screen())
64760786Sps	{
64860786Sps		/*
64960786Sps		 * Start at the beginning (or end) of the file.
65060786Sps		 * The empty_screen() case is mainly for
65160786Sps		 * command line initiated searches;
65260786Sps		 * for example, "+/xyz" on the command line.
65360786Sps		 * Also for multi-file (SRCH_PAST_EOF) searches.
65460786Sps		 */
65560786Sps		if (search_type & SRCH_FORW)
65660786Sps		{
657221715Sdelphij			pos = ch_zero();
65860786Sps		} else
65960786Sps		{
66060786Sps			pos = ch_length();
66160786Sps			if (pos == NULL_POSITION)
66260786Sps			{
66360786Sps				(void) ch_end_seek();
66460786Sps				pos = ch_length();
66560786Sps			}
66660786Sps		}
667221715Sdelphij		linenum = 0;
668221715Sdelphij	} else
66960786Sps	{
670221715Sdelphij		int add_one = 0;
671221715Sdelphij
672221715Sdelphij		if (how_search == OPT_ON)
67360786Sps		{
674221715Sdelphij			/*
675221715Sdelphij			 * Search does not include current screen.
676221715Sdelphij			 */
677221715Sdelphij			if (search_type & SRCH_FORW)
678221715Sdelphij				linenum = BOTTOM_PLUS_ONE;
679221715Sdelphij			else
680221715Sdelphij				linenum = TOP;
681221715Sdelphij		} else if (how_search == OPT_ONPLUS && !(search_type & SRCH_AFTER_TARGET))
682221715Sdelphij		{
683221715Sdelphij			/*
684221715Sdelphij			 * Search includes all of displayed screen.
685221715Sdelphij			 */
686221715Sdelphij			if (search_type & SRCH_FORW)
687221715Sdelphij				linenum = TOP;
688221715Sdelphij			else
689221715Sdelphij				linenum = BOTTOM_PLUS_ONE;
69060786Sps		} else
69160786Sps		{
692221715Sdelphij			/*
693221715Sdelphij			 * Search includes the part of current screen beyond the jump target.
694221715Sdelphij			 * It starts at the jump target (if searching backwards),
695221715Sdelphij			 * or at the jump target plus one (if forwards).
696221715Sdelphij			 */
697221715Sdelphij			linenum = jump_sline;
698221715Sdelphij			if (search_type & SRCH_FORW)
699221715Sdelphij			    add_one = 1;
70060786Sps		}
701221715Sdelphij		linenum = adjsline(linenum);
702221715Sdelphij		pos = position(linenum);
703221715Sdelphij		if (add_one)
704221715Sdelphij			pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
70560786Sps	}
706221715Sdelphij
707221715Sdelphij	/*
708221715Sdelphij	 * If the line is empty, look around for a plausible starting place.
709221715Sdelphij	 */
710221715Sdelphij	if (search_type & SRCH_FORW)
711221715Sdelphij	{
712221715Sdelphij	    while (pos == NULL_POSITION)
713221715Sdelphij	    {
714221715Sdelphij	        if (++linenum >= sc_height)
715221715Sdelphij	            break;
716221715Sdelphij	        pos = position(linenum);
717221715Sdelphij	    }
718221715Sdelphij	} else
719221715Sdelphij	{
720221715Sdelphij	    while (pos == NULL_POSITION)
721221715Sdelphij	    {
722221715Sdelphij	        if (--linenum < 0)
723221715Sdelphij	            break;
724221715Sdelphij	        pos = position(linenum);
725221715Sdelphij	    }
726221715Sdelphij	}
72760786Sps	return (pos);
72860786Sps}
72960786Sps
73060786Sps/*
73160786Sps * Search a subset of the file, specified by start/end position.
73260786Sps */
73360786Sps	static int
73460786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
73560786Sps	POSITION pos;
73660786Sps	POSITION endpos;
73760786Sps	int search_type;
73860786Sps	int matches;
73960786Sps	int maxlines;
74060786Sps	POSITION *plinepos;
74160786Sps	POSITION *pendpos;
74260786Sps{
74360786Sps	char *line;
744173685Sdelphij	char *cline;
745170259Sdelphij	int line_len;
746128348Stjr	LINENUM linenum;
74760786Sps	char *sp, *ep;
74860786Sps	int line_match;
749128348Stjr	int cvt_ops;
750195941Sdelphij	int cvt_len;
751195941Sdelphij	int *chpos;
75260786Sps	POSITION linepos, oldpos;
75360786Sps
75460786Sps	linenum = find_linenum(pos);
75560786Sps	oldpos = pos;
75660786Sps	for (;;)
75760786Sps	{
75860786Sps		/*
75960786Sps		 * Get lines until we find a matching one or until
76060786Sps		 * we hit end-of-file (or beginning-of-file if we're
76160786Sps		 * going backwards), or until we hit the end position.
76260786Sps		 */
76360786Sps		if (ABORT_SIGS())
76460786Sps		{
76560786Sps			/*
76660786Sps			 * A signal aborts the search.
76760786Sps			 */
76860786Sps			return (-1);
76960786Sps		}
77060786Sps
77160786Sps		if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
77260786Sps		{
77360786Sps			/*
77460786Sps			 * Reached end position without a match.
77560786Sps			 */
77660786Sps			if (pendpos != NULL)
77760786Sps				*pendpos = pos;
77860786Sps			return (matches);
77960786Sps		}
78060786Sps		if (maxlines > 0)
78160786Sps			maxlines--;
78260786Sps
78360786Sps		if (search_type & SRCH_FORW)
78460786Sps		{
78560786Sps			/*
78660786Sps			 * Read the next line, and save the
78760786Sps			 * starting position of that line in linepos.
78860786Sps			 */
78960786Sps			linepos = pos;
790170259Sdelphij			pos = forw_raw_line(pos, &line, &line_len);
79160786Sps			if (linenum != 0)
79260786Sps				linenum++;
79360786Sps		} else
79460786Sps		{
79560786Sps			/*
79660786Sps			 * Read the previous line and save the
79760786Sps			 * starting position of that line in linepos.
79860786Sps			 */
799170259Sdelphij			pos = back_raw_line(pos, &line, &line_len);
80060786Sps			linepos = pos;
80160786Sps			if (linenum != 0)
80260786Sps				linenum--;
80360786Sps		}
80460786Sps
80560786Sps		if (pos == NULL_POSITION)
80660786Sps		{
80760786Sps			/*
80860786Sps			 * Reached EOF/BOF without a match.
80960786Sps			 */
81060786Sps			if (pendpos != NULL)
81160786Sps				*pendpos = oldpos;
81260786Sps			return (matches);
81360786Sps		}
81460786Sps
81560786Sps		/*
81660786Sps		 * If we're using line numbers, we might as well
81760786Sps		 * remember the information we have now (the position
81860786Sps		 * and line number of the current line).
81960786Sps		 * Don't do it for every line because it slows down
82060786Sps		 * the search.  Remember the line number only if
82160786Sps		 * we're "far" from the last place we remembered it.
82260786Sps		 */
823195941Sdelphij		if (linenums && abs((int)(pos - oldpos)) > 2048)
82460786Sps			add_lnum(linenum, pos);
82560786Sps		oldpos = pos;
82660786Sps
827191930Sdelphij		if (is_filtered(linepos))
828191930Sdelphij			continue;
829191930Sdelphij
83060786Sps		/*
83160786Sps		 * If it's a caseless search, convert the line to lowercase.
83260786Sps		 * If we're doing backspace processing, delete backspaces.
83360786Sps		 */
834128348Stjr		cvt_ops = get_cvt_ops();
835195941Sdelphij		cvt_len = cvt_length(line_len, cvt_ops);
836195941Sdelphij		cline = (char *) ecalloc(1, cvt_len);
837195941Sdelphij		chpos = cvt_alloc_chpos(cvt_len);
838195941Sdelphij		cvt_text(cline, line, chpos, &line_len, cvt_ops);
83960786Sps
840191930Sdelphij#if HILITE_SEARCH
84160786Sps		/*
842191930Sdelphij		 * Check to see if the line matches the filter pattern.
843191930Sdelphij		 * If so, add an entry to the filter list.
84460786Sps		 */
845195941Sdelphij		if ((search_type & SRCH_FIND_ALL) && prev_pattern(&filter_info)) {
846237613Sdelphij			int line_filter = match_pattern(info_compiled(&filter_info), filter_info.text,
847195941Sdelphij				cline, line_len, &sp, &ep, 0, filter_info.search_type);
848191930Sdelphij			if (line_filter)
849191930Sdelphij			{
850191930Sdelphij				struct hilite *hl = (struct hilite *)
851191930Sdelphij					ecalloc(1, sizeof(struct hilite));
852191930Sdelphij				hl->hl_startpos = linepos;
853191930Sdelphij				hl->hl_endpos = pos;
854191930Sdelphij				add_hilite(&filter_anchor, hl);
855191930Sdelphij			}
856173685Sdelphij		}
857191930Sdelphij#endif
858191930Sdelphij
85960786Sps		/*
860191930Sdelphij		 * Test the next line to see if we have a match.
861191930Sdelphij		 * We are successful if we either want a match and got one,
862191930Sdelphij		 * or if we want a non-match and got one.
86360786Sps		 */
864195941Sdelphij		if (prev_pattern(&search_info))
86560786Sps		{
866237613Sdelphij			line_match = match_pattern(info_compiled(&search_info), search_info.text,
867221715Sdelphij				cline, line_len, &sp, &ep, 0, search_type);
86860786Sps			if (line_match)
86960786Sps			{
87060786Sps				/*
871191930Sdelphij				 * Got a match.
87260786Sps				 */
873191930Sdelphij				if (search_type & SRCH_FIND_ALL)
874191930Sdelphij				{
875191930Sdelphij#if HILITE_SEARCH
876191930Sdelphij					/*
877191930Sdelphij					 * We are supposed to find all matches in the range.
878191930Sdelphij					 * Just add the matches in this line to the
879191930Sdelphij					 * hilite list and keep searching.
880191930Sdelphij					 */
881195941Sdelphij					hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
882191930Sdelphij#endif
883191930Sdelphij				} else if (--matches <= 0)
884191930Sdelphij				{
885191930Sdelphij					/*
886191930Sdelphij					 * Found the one match we're looking for.
887191930Sdelphij					 * Return it.
888191930Sdelphij					 */
889191930Sdelphij#if HILITE_SEARCH
890191930Sdelphij					if (hilite_search == OPT_ON)
891191930Sdelphij					{
892191930Sdelphij						/*
893191930Sdelphij						 * Clear the hilite list and add only
894191930Sdelphij						 * the matches in this one line.
895191930Sdelphij						 */
896191930Sdelphij						clr_hilite();
897195941Sdelphij						hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
898191930Sdelphij					}
899191930Sdelphij#endif
900191930Sdelphij					free(cline);
901195941Sdelphij					free(chpos);
902191930Sdelphij					if (plinepos != NULL)
903191930Sdelphij						*plinepos = linepos;
904191930Sdelphij					return (0);
905191930Sdelphij				}
90660786Sps			}
90760786Sps		}
908191930Sdelphij		free(cline);
909195941Sdelphij		free(chpos);
91060786Sps	}
91160786Sps}
91260786Sps
913191930Sdelphij/*
914170259Sdelphij * search for a pattern in history. If found, compile that pattern.
915170259Sdelphij */
916170259Sdelphij	static int
917170259Sdelphijhist_pattern(search_type)
918170259Sdelphij	int search_type;
919170259Sdelphij{
920170259Sdelphij#if CMD_HISTORY
921170259Sdelphij	char *pattern;
922170259Sdelphij
923170259Sdelphij	set_mlist(ml_search, 0);
924170259Sdelphij	pattern = cmd_lastpattern();
925170259Sdelphij	if (pattern == NULL)
926170259Sdelphij		return (0);
927170259Sdelphij
928195941Sdelphij	if (set_pattern(&search_info, pattern, search_type) < 0)
929170259Sdelphij		return (0);
930170259Sdelphij
931170259Sdelphij#if HILITE_SEARCH
932170259Sdelphij	if (hilite_search == OPT_ONPLUS && !hide_hilite)
933170259Sdelphij		hilite_screen();
934170259Sdelphij#endif
935170259Sdelphij
936170259Sdelphij	return (1);
937170259Sdelphij#else /* CMD_HISTORY */
938170259Sdelphij	return (0);
939170259Sdelphij#endif /* CMD_HISTORY */
940170259Sdelphij}
941170259Sdelphij
94260786Sps/*
94360786Sps * Search for the n-th occurrence of a specified pattern,
94460786Sps * either forward or backward.
94560786Sps * Return the number of matches not yet found in this file
94660786Sps * (that is, n minus the number of matches found).
94760786Sps * Return -1 if the search should be aborted.
94860786Sps * Caller may continue the search in another file
94960786Sps * if less than n matches are found in this file.
95060786Sps */
95160786Sps	public int
95260786Spssearch(search_type, pattern, n)
95360786Sps	int search_type;
95460786Sps	char *pattern;
95560786Sps	int n;
95660786Sps{
95760786Sps	POSITION pos;
95860786Sps
95960786Sps	if (pattern == NULL || *pattern == '\0')
96060786Sps	{
96160786Sps		/*
96260786Sps		 * A null pattern means use the previously compiled pattern.
96360786Sps		 */
964221715Sdelphij		search_type |= SRCH_AFTER_TARGET;
965195941Sdelphij		if (!prev_pattern(&search_info) && !hist_pattern(search_type))
96660786Sps		{
96760786Sps			error("No previous regular expression", NULL_PARG);
96860786Sps			return (-1);
96960786Sps		}
97060786Sps		if ((search_type & SRCH_NO_REGEX) !=
971195941Sdelphij		      (search_info.search_type & SRCH_NO_REGEX))
97260786Sps		{
97360786Sps			error("Please re-enter search pattern", NULL_PARG);
97460786Sps			return -1;
97560786Sps		}
97660786Sps#if HILITE_SEARCH
97760786Sps		if (hilite_search == OPT_ON)
97860786Sps		{
97960786Sps			/*
98060786Sps			 * Erase the highlights currently on screen.
98160786Sps			 * If the search fails, we'll redisplay them later.
98260786Sps			 */
98360786Sps			repaint_hilite(0);
98460786Sps		}
98560786Sps		if (hilite_search == OPT_ONPLUS && hide_hilite)
98660786Sps		{
98760786Sps			/*
98860786Sps			 * Highlight any matches currently on screen,
98960786Sps			 * before we actually start the search.
99060786Sps			 */
99160786Sps			hide_hilite = 0;
99260786Sps			hilite_screen();
99360786Sps		}
99460786Sps		hide_hilite = 0;
99560786Sps#endif
99660786Sps	} else
99760786Sps	{
99860786Sps		/*
99960786Sps		 * Compile the pattern.
100060786Sps		 */
1001195941Sdelphij		if (set_pattern(&search_info, pattern, search_type) < 0)
100260786Sps			return (-1);
100360786Sps#if HILITE_SEARCH
100460786Sps		if (hilite_search)
100560786Sps		{
100660786Sps			/*
100760786Sps			 * Erase the highlights currently on screen.
100860786Sps			 * Also permanently delete them from the hilite list.
100960786Sps			 */
101060786Sps			repaint_hilite(0);
101160786Sps			hide_hilite = 0;
101260786Sps			clr_hilite();
101360786Sps		}
101460786Sps		if (hilite_search == OPT_ONPLUS)
101560786Sps		{
101660786Sps			/*
101760786Sps			 * Highlight any matches currently on screen,
101860786Sps			 * before we actually start the search.
101960786Sps			 */
102060786Sps			hilite_screen();
102160786Sps		}
102260786Sps#endif
102360786Sps	}
102460786Sps
102560786Sps	/*
102660786Sps	 * Figure out where to start the search.
102760786Sps	 */
102860786Sps	pos = search_pos(search_type);
102960786Sps	if (pos == NULL_POSITION)
103060786Sps	{
103160786Sps		/*
103260786Sps		 * Can't find anyplace to start searching from.
103360786Sps		 */
103460786Sps		if (search_type & SRCH_PAST_EOF)
103560786Sps			return (n);
103660786Sps		/* repaint(); -- why was this here? */
103760786Sps		error("Nothing to search", NULL_PARG);
103860786Sps		return (-1);
103960786Sps	}
104060786Sps
104160786Sps	n = search_range(pos, NULL_POSITION, search_type, n, -1,
104260786Sps			&pos, (POSITION*)NULL);
104360786Sps	if (n != 0)
104460786Sps	{
104560786Sps		/*
104660786Sps		 * Search was unsuccessful.
104760786Sps		 */
104860786Sps#if HILITE_SEARCH
104960786Sps		if (hilite_search == OPT_ON && n > 0)
105060786Sps			/*
105160786Sps			 * Redisplay old hilites.
105260786Sps			 */
105360786Sps			repaint_hilite(1);
105460786Sps#endif
105560786Sps		return (n);
105660786Sps	}
105760786Sps
105860786Sps	if (!(search_type & SRCH_NO_MOVE))
105960786Sps	{
106060786Sps		/*
106160786Sps		 * Go to the matching line.
106260786Sps		 */
106360786Sps		jump_loc(pos, jump_sline);
106460786Sps	}
106560786Sps
106660786Sps#if HILITE_SEARCH
106760786Sps	if (hilite_search == OPT_ON)
106860786Sps		/*
106960786Sps		 * Display new hilites in the matching line.
107060786Sps		 */
107160786Sps		repaint_hilite(1);
107260786Sps#endif
107360786Sps	return (0);
107460786Sps}
107560786Sps
107660786Sps
107760786Sps#if HILITE_SEARCH
107860786Sps/*
107960786Sps * Prepare hilites in a given range of the file.
108060786Sps *
108160786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region
108260786Sps * of the file that has been "prepared"; that is, scanned for matches for
108360786Sps * the current search pattern, and hilites have been created for such matches.
108460786Sps * If prep_startpos == NULL_POSITION, the prep region is empty.
108560786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
108660786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region.
108760786Sps */
108860786Sps	public void
108960786Spsprep_hilite(spos, epos, maxlines)
109060786Sps	POSITION spos;
109160786Sps	POSITION epos;
109260786Sps	int maxlines;
109360786Sps{
109460786Sps	POSITION nprep_startpos = prep_startpos;
109560786Sps	POSITION nprep_endpos = prep_endpos;
109660786Sps	POSITION new_epos;
109760786Sps	POSITION max_epos;
109860786Sps	int result;
109960786Sps	int i;
1100195941Sdelphij
110160786Sps/*
110260786Sps * Search beyond where we're asked to search, so the prep region covers
110360786Sps * more than we need.  Do one big search instead of a bunch of small ones.
110460786Sps */
110560786Sps#define	SEARCH_MORE (3*size_linebuf)
110660786Sps
1107195941Sdelphij	if (!prev_pattern(&search_info) && !is_filtering())
110860786Sps		return;
110960786Sps
111060786Sps	/*
111160786Sps	 * If we're limited to a max number of lines, figure out the
111260786Sps	 * file position we should stop at.
111360786Sps	 */
111460786Sps	if (maxlines < 0)
111560786Sps		max_epos = NULL_POSITION;
111660786Sps	else
111760786Sps	{
111860786Sps		max_epos = spos;
111960786Sps		for (i = 0;  i < maxlines;  i++)
1120170259Sdelphij			max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
112160786Sps	}
112260786Sps
112360786Sps	/*
112460786Sps	 * Find two ranges:
112560786Sps	 * The range that we need to search (spos,epos); and the range that
112660786Sps	 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
112760786Sps	 */
112860786Sps
112960786Sps	if (prep_startpos == NULL_POSITION ||
113060786Sps	    (epos != NULL_POSITION && epos < prep_startpos) ||
113160786Sps	    spos > prep_endpos)
113260786Sps	{
113360786Sps		/*
113460786Sps		 * New range is not contiguous with old prep region.
113560786Sps		 * Discard the old prep region and start a new one.
113660786Sps		 */
113760786Sps		clr_hilite();
1138191930Sdelphij		clr_filter();
113960786Sps		if (epos != NULL_POSITION)
114060786Sps			epos += SEARCH_MORE;
114160786Sps		nprep_startpos = spos;
114260786Sps	} else
114360786Sps	{
114460786Sps		/*
114560786Sps		 * New range partially or completely overlaps old prep region.
114660786Sps		 */
114760786Sps		if (epos == NULL_POSITION)
114860786Sps		{
114960786Sps			/*
115060786Sps			 * New range goes to end of file.
115160786Sps			 */
115260786Sps			;
115360786Sps		} else if (epos > prep_endpos)
115460786Sps		{
115560786Sps			/*
115660786Sps			 * New range ends after old prep region.
115760786Sps			 * Extend prep region to end at end of new range.
115860786Sps			 */
115960786Sps			epos += SEARCH_MORE;
116060786Sps		} else /* (epos <= prep_endpos) */
116160786Sps		{
116260786Sps			/*
116360786Sps			 * New range ends within old prep region.
116460786Sps			 * Truncate search to end at start of old prep region.
116560786Sps			 */
116660786Sps			epos = prep_startpos;
116760786Sps		}
116860786Sps
116960786Sps		if (spos < prep_startpos)
117060786Sps		{
117160786Sps			/*
117260786Sps			 * New range starts before old prep region.
117360786Sps			 * Extend old prep region backwards to start at
117460786Sps			 * start of new range.
117560786Sps			 */
117660786Sps			if (spos < SEARCH_MORE)
117760786Sps				spos = 0;
117860786Sps			else
117960786Sps				spos -= SEARCH_MORE;
118060786Sps			nprep_startpos = spos;
118160786Sps		} else /* (spos >= prep_startpos) */
118260786Sps		{
118360786Sps			/*
118460786Sps			 * New range starts within or after old prep region.
118560786Sps			 * Trim search to start at end of old prep region.
118660786Sps			 */
118760786Sps			spos = prep_endpos;
118860786Sps		}
118960786Sps	}
119060786Sps
119160786Sps	if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
119260786Sps	    epos > max_epos)
119360786Sps		/*
119460786Sps		 * Don't go past the max position we're allowed.
119560786Sps		 */
119660786Sps		epos = max_epos;
119760786Sps
119860786Sps	if (epos == NULL_POSITION || epos > spos)
119960786Sps	{
1200195941Sdelphij		int search_type = SRCH_FORW | SRCH_FIND_ALL;
1201195941Sdelphij		search_type |= (search_info.search_type & SRCH_NO_REGEX);
1202195941Sdelphij		result = search_range(spos, epos, search_type, 0,
120360786Sps				maxlines, (POSITION*)NULL, &new_epos);
120460786Sps		if (result < 0)
120560786Sps			return;
120660786Sps		if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
120760786Sps			nprep_endpos = new_epos;
120860786Sps	}
120960786Sps	prep_startpos = nprep_startpos;
121060786Sps	prep_endpos = nprep_endpos;
121160786Sps}
1212191930Sdelphij
1213191930Sdelphij/*
1214191930Sdelphij * Set the pattern to be used for line filtering.
1215191930Sdelphij */
1216191930Sdelphij	public void
1217191930Sdelphijset_filter_pattern(pattern, search_type)
1218191930Sdelphij	char *pattern;
1219191930Sdelphij	int search_type;
1220191930Sdelphij{
1221191930Sdelphij	clr_filter();
1222191930Sdelphij	if (pattern == NULL || *pattern == '\0')
1223195941Sdelphij		clear_pattern(&filter_info);
1224191930Sdelphij	else
1225195941Sdelphij		set_pattern(&filter_info, pattern, search_type);
1226191930Sdelphij	screen_trashed = 1;
1227191930Sdelphij}
1228191930Sdelphij
1229191930Sdelphij/*
1230191930Sdelphij * Is there a line filter in effect?
1231191930Sdelphij */
1232191930Sdelphij	public int
1233191930Sdelphijis_filtering()
1234191930Sdelphij{
1235191930Sdelphij	if (ch_getflags() & CH_HELPFILE)
1236191930Sdelphij		return (0);
1237195941Sdelphij	return prev_pattern(&filter_info);
1238191930Sdelphij}
123960786Sps#endif
124060786Sps
124160786Sps#if HAVE_V8_REGCOMP
124260786Sps/*
124360786Sps * This function is called by the V8 regcomp to report
124460786Sps * errors in regular expressions.
124560786Sps */
124660786Sps	void
124760786Spsregerror(s)
124860786Sps	char *s;
124960786Sps{
125060786Sps	PARG parg;
125160786Sps
125260786Sps	parg.p_string = s;
125360786Sps	error("%s", &parg);
125460786Sps}
125560786Sps#endif
125660786Sps
1257