160812Sps/* $FreeBSD$ */
260786Sps/*
3240121Sdelphij * Copyright (C) 1984-2012  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 *
8240121Sdelphij * For more information, see the README file.
960786Sps */
1060786Sps
1160786Sps
1260786Sps/*
1360786Sps * Routines to search a file for a pattern.
1460786Sps */
1560786Sps
1660786Sps#include "less.h"
17195941Sdelphij#include "pattern.h"
1860786Sps#include "position.h"
19172471Sdelphij#include "charset.h"
2060786Sps
2160786Sps#define	MINPOS(a,b)	(((a) < (b)) ? (a) : (b))
2260786Sps#define	MAXPOS(a,b)	(((a) > (b)) ? (a) : (b))
2360786Sps
2460786Spsextern int sigs;
2560786Spsextern int how_search;
2660786Spsextern int caseless;
2760786Spsextern int linenums;
2860786Spsextern int sc_height;
2960786Spsextern int jump_sline;
3060786Spsextern int bs_mode;
31170259Sdelphijextern int less_is_more;
32128348Stjrextern int ctldisp;
3363131Spsextern int status_col;
34170259Sdelphijextern void * constant ml_search;
3560786Spsextern POSITION start_attnpos;
3660786Spsextern POSITION end_attnpos;
37191930Sdelphijextern int utf_mode;
38191930Sdelphijextern int screen_trashed;
3960786Sps#if HILITE_SEARCH
4060786Spsextern int hilite_search;
4160786Spsextern int size_linebuf;
4260786Spsextern int squished;
4360786Spsextern int can_goto_line;
4460786Spsstatic int hide_hilite;
4560786Spsstatic POSITION prep_startpos;
4660786Spsstatic POSITION prep_endpos;
47195941Sdelphijstatic int is_caseless;
48195941Sdelphijstatic int is_ucase_pattern;
4960786Sps
5060786Spsstruct hilite
5160786Sps{
5260786Sps	struct hilite *hl_next;
5360786Sps	POSITION hl_startpos;
5460786Sps	POSITION hl_endpos;
5560786Sps};
5660786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
57191930Sdelphijstatic struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION };
5860786Sps#define	hl_first	hl_next
5960786Sps#endif
6060786Sps
6160786Sps/*
6260786Sps * These are the static variables that represent the "remembered"
63195941Sdelphij * search pattern and filter pattern.
6460786Sps */
65195941Sdelphijstruct pattern_info {
66195941Sdelphij	DEFINE_PATTERN(compiled);
67195941Sdelphij	char* text;
68195941Sdelphij	int search_type;
69195941Sdelphij};
70240121Sdelphij
71240121Sdelphij#if NO_REGEX
72240121Sdelphij#define info_compiled(info) ((void*)0)
73240121Sdelphij#else
74240121Sdelphij#define info_compiled(info) ((info)->compiled)
75240121Sdelphij#endif
76195941Sdelphij
77195941Sdelphijstatic struct pattern_info search_info;
78195941Sdelphijstatic struct pattern_info filter_info;
7960786Sps
80173685Sdelphij/*
81221715Sdelphij * Are there any uppercase letters in this string?
82221715Sdelphij */
83221715Sdelphij	static int
84221715Sdelphijis_ucase(str)
85221715Sdelphij	char *str;
86221715Sdelphij{
87221715Sdelphij	char *str_end = str + strlen(str);
88221715Sdelphij	LWCHAR ch;
89221715Sdelphij
90221715Sdelphij	while (str < str_end)
91221715Sdelphij	{
92221715Sdelphij		ch = step_char(&str, +1, str_end);
93221715Sdelphij		if (IS_UPPER(ch))
94221715Sdelphij			return (1);
95221715Sdelphij	}
96221715Sdelphij	return (0);
97221715Sdelphij}
98221715Sdelphij
99221715Sdelphij/*
100195941Sdelphij * Compile and save a search pattern.
101173685Sdelphij */
102173685Sdelphij	static int
103195941Sdelphijset_pattern(info, pattern, search_type)
104195941Sdelphij	struct pattern_info *info;
105195941Sdelphij	char *pattern;
106195941Sdelphij	int search_type;
107173685Sdelphij{
108240121Sdelphij#if !NO_REGEX
109195941Sdelphij	if (pattern == NULL)
110240121Sdelphij		CLEAR_PATTERN(info->compiled);
111195941Sdelphij	else if (compile_pattern(pattern, search_type, &info->compiled) < 0)
112195941Sdelphij		return -1;
113240121Sdelphij#endif
114195941Sdelphij	/* Pattern compiled successfully; save the text too. */
115195941Sdelphij	if (info->text != NULL)
116195941Sdelphij		free(info->text);
117195941Sdelphij	info->text = NULL;
118195941Sdelphij	if (pattern != NULL)
119195941Sdelphij	{
120195941Sdelphij		info->text = (char *) ecalloc(1, strlen(pattern)+1);
121195941Sdelphij		strcpy(info->text, pattern);
122195941Sdelphij	}
123195941Sdelphij	info->search_type = search_type;
124221715Sdelphij
125221715Sdelphij	/*
126221715Sdelphij	 * Ignore case if -I is set OR
127221715Sdelphij	 * -i is set AND the pattern is all lowercase.
128221715Sdelphij	 */
129221715Sdelphij	is_ucase_pattern = is_ucase(pattern);
130221715Sdelphij	if (is_ucase_pattern && caseless != OPT_ONPLUS)
131221715Sdelphij		is_caseless = 0;
132221715Sdelphij	else
133221715Sdelphij		is_caseless = caseless;
134195941Sdelphij	return 0;
135173685Sdelphij}
136173685Sdelphij
137173685Sdelphij/*
138195941Sdelphij * Discard a saved pattern.
139173685Sdelphij */
14060786Sps	static void
141195941Sdelphijclear_pattern(info)
142195941Sdelphij	struct pattern_info *info;
14360786Sps{
144195941Sdelphij	if (info->text != NULL)
145195941Sdelphij		free(info->text);
146195941Sdelphij	info->text = NULL;
147240121Sdelphij#if !NO_REGEX
148195941Sdelphij	uncompile_pattern(&info->compiled);
149240121Sdelphij#endif
150195941Sdelphij}
15160786Sps
152195941Sdelphij/*
153195941Sdelphij * Initialize saved pattern to nothing.
154195941Sdelphij */
155195941Sdelphij	static void
156195941Sdelphijinit_pattern(info)
157195941Sdelphij	struct pattern_info *info;
158195941Sdelphij{
159195941Sdelphij	CLEAR_PATTERN(info->compiled);
160195941Sdelphij	info->text = NULL;
161195941Sdelphij	info->search_type = 0;
162195941Sdelphij}
163170259Sdelphij
164195941Sdelphij/*
165195941Sdelphij * Initialize search variables.
166195941Sdelphij */
167195941Sdelphij	public void
168195941Sdelphijinit_search()
169195941Sdelphij{
170195941Sdelphij	init_pattern(&search_info);
171195941Sdelphij	init_pattern(&filter_info);
17260786Sps}
17360786Sps
17460786Sps/*
175195941Sdelphij * Determine which text conversions to perform before pattern matching.
176128348Stjr */
177128348Stjr	static int
178128348Stjrget_cvt_ops()
179128348Stjr{
180128348Stjr	int ops = 0;
181128348Stjr	if (is_caseless || bs_mode == BS_SPECIAL)
182128348Stjr	{
183128348Stjr		if (is_caseless)
184128348Stjr			ops |= CVT_TO_LC;
185128348Stjr		if (bs_mode == BS_SPECIAL)
186128348Stjr			ops |= CVT_BS;
187128348Stjr		if (bs_mode != BS_CONTROL)
188128348Stjr			ops |= CVT_CRLF;
189128348Stjr	} else if (bs_mode != BS_CONTROL)
190128348Stjr	{
191128348Stjr		ops |= CVT_CRLF;
192128348Stjr	}
193128348Stjr	if (ctldisp == OPT_ONPLUS)
194128348Stjr		ops |= CVT_ANSI;
195128348Stjr	return (ops);
196128348Stjr}
197128348Stjr
198128348Stjr/*
19960786Sps * Is there a previous (remembered) search pattern?
20060786Sps */
20160786Sps	static int
202195941Sdelphijprev_pattern(info)
203195941Sdelphij	struct pattern_info *info;
20460786Sps{
205240121Sdelphij#if !NO_REGEX
206240121Sdelphij	if ((info->search_type & SRCH_NO_REGEX) == 0)
207240121Sdelphij		return (!is_null_pattern(info->compiled));
208240121Sdelphij#endif
209240121Sdelphij	return (info->text != NULL);
21060786Sps}
21160786Sps
21260786Sps#if HILITE_SEARCH
21360786Sps/*
21460786Sps * Repaint the hilites currently displayed on the screen.
21560786Sps * Repaint each line which contains highlighted text.
21660786Sps * If on==0, force all hilites off.
21760786Sps */
21860786Sps	public void
21960786Spsrepaint_hilite(on)
22060786Sps	int on;
22160786Sps{
22260786Sps	int slinenum;
22360786Sps	POSITION pos;
22460786Sps	POSITION epos;
22560786Sps	int save_hide_hilite;
22660786Sps
22760786Sps	if (squished)
22860786Sps		repaint();
22960786Sps
23060786Sps	save_hide_hilite = hide_hilite;
23160786Sps	if (!on)
23260786Sps	{
23360786Sps		if (hide_hilite)
23460786Sps			return;
23560786Sps		hide_hilite = 1;
23660786Sps	}
23760786Sps
23860786Sps	if (!can_goto_line)
23960786Sps	{
24060786Sps		repaint();
24160786Sps		hide_hilite = save_hide_hilite;
24260786Sps		return;
24360786Sps	}
24460786Sps
24560786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
24660786Sps	{
24760786Sps		pos = position(slinenum);
24860786Sps		if (pos == NULL_POSITION)
24960786Sps			continue;
25060786Sps		epos = position(slinenum+1);
251195941Sdelphij		(void) forw_line(pos);
252195941Sdelphij		goto_line(slinenum);
253195941Sdelphij		put_line();
25460786Sps	}
255221715Sdelphij	lower_left();
25660786Sps	hide_hilite = save_hide_hilite;
25760786Sps}
25860786Sps
25960786Sps/*
26060786Sps * Clear the attn hilite.
26160786Sps */
26260786Sps	public void
26360786Spsclear_attn()
26460786Sps{
26560786Sps	int slinenum;
26660786Sps	POSITION old_start_attnpos;
26760786Sps	POSITION old_end_attnpos;
26860786Sps	POSITION pos;
26960786Sps	POSITION epos;
270170898Sdelphij	int moved = 0;
27160786Sps
27260786Sps	if (start_attnpos == NULL_POSITION)
27360786Sps		return;
27460786Sps	old_start_attnpos = start_attnpos;
27560786Sps	old_end_attnpos = end_attnpos;
27660786Sps	start_attnpos = end_attnpos = NULL_POSITION;
27760786Sps
27860786Sps	if (!can_goto_line)
27960786Sps	{
28060786Sps		repaint();
28160786Sps		return;
28260786Sps	}
28360786Sps	if (squished)
28460786Sps		repaint();
28560786Sps
28660786Sps	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
28760786Sps	{
28860786Sps		pos = position(slinenum);
28960786Sps		if (pos == NULL_POSITION)
29060786Sps			continue;
29160786Sps		epos = position(slinenum+1);
29260786Sps		if (pos < old_end_attnpos &&
29360786Sps		     (epos == NULL_POSITION || epos > old_start_attnpos))
29460786Sps		{
29560786Sps			(void) forw_line(pos);
29660786Sps			goto_line(slinenum);
29760786Sps			put_line();
298170898Sdelphij			moved = 1;
29960786Sps		}
30060786Sps	}
301170898Sdelphij	if (moved)
302170898Sdelphij		lower_left();
30360786Sps}
30460786Sps#endif
30560786Sps
30660786Sps/*
30760786Sps * Hide search string highlighting.
30860786Sps */
30960786Sps	public void
31060786Spsundo_search()
31160786Sps{
312195941Sdelphij	if (!prev_pattern(&search_info))
31360786Sps	{
31460786Sps		error("No previous regular expression", NULL_PARG);
31560786Sps		return;
31660786Sps	}
31760786Sps#if HILITE_SEARCH
31860786Sps	hide_hilite = !hide_hilite;
31960786Sps	repaint_hilite(1);
32060786Sps#endif
32160786Sps}
32260786Sps
32360786Sps#if HILITE_SEARCH
32460786Sps/*
32560786Sps * Clear the hilite list.
32660786Sps */
32760786Sps	public void
328191930Sdelphijclr_hlist(anchor)
329191930Sdelphij	struct hilite *anchor;
33060786Sps{
33160786Sps	struct hilite *hl;
33260786Sps	struct hilite *nexthl;
33360786Sps
334191930Sdelphij	for (hl = anchor->hl_first;  hl != NULL;  hl = nexthl)
33560786Sps	{
33660786Sps		nexthl = hl->hl_next;
33760786Sps		free((void*)hl);
33860786Sps	}
339191930Sdelphij	anchor->hl_first = NULL;
34060786Sps	prep_startpos = prep_endpos = NULL_POSITION;
34160786Sps}
34260786Sps
343191930Sdelphij	public void
344191930Sdelphijclr_hilite()
345191930Sdelphij{
346191930Sdelphij	clr_hlist(&hilite_anchor);
347191930Sdelphij}
348191930Sdelphij
349191930Sdelphij	public void
350191930Sdelphijclr_filter()
351191930Sdelphij{
352191930Sdelphij	clr_hlist(&filter_anchor);
353191930Sdelphij}
354191930Sdelphij
35560786Sps/*
35660786Sps * Should any characters in a specified range be highlighted?
357161478Sdelphij */
358161478Sdelphij	static int
359161478Sdelphijis_hilited_range(pos, epos)
360161478Sdelphij	POSITION pos;
361161478Sdelphij	POSITION epos;
362161478Sdelphij{
363161478Sdelphij	struct hilite *hl;
364161478Sdelphij
365161478Sdelphij	/*
366161478Sdelphij	 * Look at each highlight and see if any part of it falls in the range.
367161478Sdelphij	 */
368161478Sdelphij	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
369161478Sdelphij	{
370161478Sdelphij		if (hl->hl_endpos > pos &&
371161478Sdelphij		    (epos == NULL_POSITION || epos > hl->hl_startpos))
372161478Sdelphij			return (1);
373161478Sdelphij	}
374161478Sdelphij	return (0);
375161478Sdelphij}
376161478Sdelphij
377191930Sdelphij/*
378191930Sdelphij * Is a line "filtered" -- that is, should it be hidden?
379191930Sdelphij */
380191930Sdelphij	public int
381191930Sdelphijis_filtered(pos)
382191930Sdelphij	POSITION pos;
383191930Sdelphij{
384191930Sdelphij	struct hilite *hl;
385191930Sdelphij
386191930Sdelphij	if (ch_getflags() & CH_HELPFILE)
387191930Sdelphij		return (0);
388191930Sdelphij
389191930Sdelphij	/*
390191930Sdelphij	 * Look at each filter and see if the start position
391191930Sdelphij	 * equals the start position of the line.
392191930Sdelphij	 */
393191930Sdelphij	for (hl = filter_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
394191930Sdelphij	{
395191930Sdelphij		if (hl->hl_startpos == pos)
396191930Sdelphij			return (1);
397191930Sdelphij	}
398191930Sdelphij	return (0);
399191930Sdelphij}
400191930Sdelphij
401161478Sdelphij/*
402161478Sdelphij * Should any characters in a specified range be highlighted?
40360786Sps * If nohide is nonzero, don't consider hide_hilite.
40460786Sps */
40560786Sps	public int
406161478Sdelphijis_hilited(pos, epos, nohide, p_matches)
40760786Sps	POSITION pos;
40860786Sps	POSITION epos;
40960786Sps	int nohide;
410161478Sdelphij	int *p_matches;
41160786Sps{
412161478Sdelphij	int match;
41360786Sps
414161478Sdelphij	if (p_matches != NULL)
415161478Sdelphij		*p_matches = 0;
416161478Sdelphij
41763131Sps	if (!status_col &&
41863131Sps	    start_attnpos != NULL_POSITION &&
41960786Sps	    pos < end_attnpos &&
42060786Sps	     (epos == NULL_POSITION || epos > start_attnpos))
42160786Sps		/*
42260786Sps		 * The attn line overlaps this range.
42360786Sps		 */
42460786Sps		return (1);
42560786Sps
426161478Sdelphij	match = is_hilited_range(pos, epos);
427161478Sdelphij	if (!match)
428161478Sdelphij		return (0);
429161478Sdelphij
430161478Sdelphij	if (p_matches != NULL)
431161478Sdelphij		/*
432161478Sdelphij		 * Report matches, even if we're hiding highlights.
433161478Sdelphij		 */
434161478Sdelphij		*p_matches = 1;
435161478Sdelphij
43660786Sps	if (hilite_search == 0)
43760786Sps		/*
43860786Sps		 * Not doing highlighting.
43960786Sps		 */
44060786Sps		return (0);
44160786Sps
44260786Sps	if (!nohide && hide_hilite)
44360786Sps		/*
44460786Sps		 * Highlighting is hidden.
44560786Sps		 */
44660786Sps		return (0);
44760786Sps
448161478Sdelphij	return (1);
44960786Sps}
45060786Sps
45160786Sps/*
45260786Sps * Add a new hilite to a hilite list.
45360786Sps */
45460786Sps	static void
45560786Spsadd_hilite(anchor, hl)
45660786Sps	struct hilite *anchor;
45760786Sps	struct hilite *hl;
45860786Sps{
45960786Sps	struct hilite *ihl;
46060786Sps
46160786Sps	/*
46260786Sps	 * Hilites are sorted in the list; find where new one belongs.
46360786Sps	 * Insert new one after ihl.
46460786Sps	 */
46560786Sps	for (ihl = anchor;  ihl->hl_next != NULL;  ihl = ihl->hl_next)
46660786Sps	{
46760786Sps		if (ihl->hl_next->hl_startpos > hl->hl_startpos)
46860786Sps			break;
46960786Sps	}
47060786Sps
47160786Sps	/*
47260786Sps	 * Truncate hilite so it doesn't overlap any existing ones
47360786Sps	 * above and below it.
47460786Sps	 */
47560786Sps	if (ihl != anchor)
47660786Sps		hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
47760786Sps	if (ihl->hl_next != NULL)
47860786Sps		hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
47960786Sps	if (hl->hl_startpos >= hl->hl_endpos)
48060786Sps	{
48160786Sps		/*
48260786Sps		 * Hilite was truncated out of existence.
48360786Sps		 */
48460786Sps		free(hl);
48560786Sps		return;
48660786Sps	}
48760786Sps	hl->hl_next = ihl->hl_next;
48860786Sps	ihl->hl_next = hl;
48960786Sps}
49060786Sps
49160786Sps/*
492240121Sdelphij * Hilight every character in a range of displayed characters.
493240121Sdelphij */
494240121Sdelphij	static void
495240121Sdelphijcreate_hilites(linepos, start_index, end_index, chpos)
496240121Sdelphij	POSITION linepos;
497240121Sdelphij	int start_index;
498240121Sdelphij	int end_index;
499240121Sdelphij	int *chpos;
500240121Sdelphij{
501240121Sdelphij	struct hilite *hl;
502240121Sdelphij	int i;
503240121Sdelphij
504240121Sdelphij	/* Start the first hilite. */
505240121Sdelphij	hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
506240121Sdelphij	hl->hl_startpos = linepos + chpos[start_index];
507240121Sdelphij
508240121Sdelphij	/*
509240121Sdelphij	 * Step through the displayed chars.
510240121Sdelphij	 * If the source position (before cvt) of the char is one more
511240121Sdelphij	 * than the source pos of the previous char (the usual case),
512240121Sdelphij	 * just increase the size of the current hilite by one.
513240121Sdelphij	 * Otherwise (there are backspaces or something involved),
514240121Sdelphij	 * finish the current hilite and start a new one.
515240121Sdelphij	 */
516240121Sdelphij	for (i = start_index+1;  i <= end_index;  i++)
517240121Sdelphij	{
518240121Sdelphij		if (chpos[i] != chpos[i-1] + 1 || i == end_index)
519240121Sdelphij		{
520240121Sdelphij			hl->hl_endpos = linepos + chpos[i-1] + 1;
521240121Sdelphij			add_hilite(&hilite_anchor, hl);
522240121Sdelphij			/* Start new hilite unless this is the last char. */
523240121Sdelphij			if (i < end_index)
524240121Sdelphij			{
525240121Sdelphij				hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
526240121Sdelphij				hl->hl_startpos = linepos + chpos[i];
527240121Sdelphij			}
528240121Sdelphij		}
529240121Sdelphij	}
530240121Sdelphij}
531240121Sdelphij
532240121Sdelphij/*
53360786Sps * Make a hilite for each string in a physical line which matches
53460786Sps * the current pattern.
53560786Sps * sp,ep delimit the first match already found.
53660786Sps */
53760786Sps	static void
538195941Sdelphijhilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops)
53960786Sps	POSITION linepos;
54060786Sps	char *line;
541170259Sdelphij	int line_len;
542195941Sdelphij	int *chpos;
54360786Sps	char *sp;
54460786Sps	char *ep;
545128348Stjr	int cvt_ops;
54660786Sps{
54760786Sps	char *searchp;
548170259Sdelphij	char *line_end = line + line_len;
54960786Sps
55060786Sps	if (sp == NULL || ep == NULL)
55160786Sps		return;
55260786Sps	/*
55360786Sps	 * sp and ep delimit the first match in the line.
55460786Sps	 * Mark the corresponding file positions, then
55560786Sps	 * look for further matches and mark them.
55660786Sps	 * {{ This technique, of calling match_pattern on subsequent
55760786Sps	 *    substrings of the line, may mark more than is correct
55860786Sps	 *    if the pattern starts with "^".  This bug is fixed
55960786Sps	 *    for those regex functions that accept a notbol parameter
560170259Sdelphij	 *    (currently POSIX, PCRE and V8-with-regexec2). }}
56160786Sps	 */
56260786Sps	searchp = line;
56360786Sps	do {
564240121Sdelphij		create_hilites(linepos, sp-line, ep-line, chpos);
56560786Sps		/*
56660786Sps		 * If we matched more than zero characters,
56760786Sps		 * move to the first char after the string we matched.
56860786Sps		 * If we matched zero, just move to the next char.
56960786Sps		 */
57060786Sps		if (ep > searchp)
57160786Sps			searchp = ep;
572170259Sdelphij		else if (searchp != line_end)
57360786Sps			searchp++;
57460786Sps		else /* end of line */
57560786Sps			break;
576240121Sdelphij	} while (match_pattern(info_compiled(&search_info), search_info.text,
577195941Sdelphij			searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type));
57860786Sps}
57960786Sps#endif
58060786Sps
58160786Sps/*
58260786Sps * Change the caseless-ness of searches.
58360786Sps * Updates the internal search state to reflect a change in the -i flag.
58460786Sps */
58560786Sps	public void
58660786Spschg_caseless()
58760786Sps{
58860786Sps	if (!is_ucase_pattern)
58960786Sps		/*
59060786Sps		 * Pattern did not have uppercase.
59160786Sps		 * Just set the search caselessness to the global caselessness.
59260786Sps		 */
59360786Sps		is_caseless = caseless;
59460786Sps	else
59560786Sps		/*
59660786Sps		 * Pattern did have uppercase.
59760786Sps		 * Discard the pattern; we can't change search caselessness now.
59860786Sps		 */
599195941Sdelphij		clear_pattern(&search_info);
60060786Sps}
60160786Sps
60260786Sps#if HILITE_SEARCH
60360786Sps/*
60460786Sps * Find matching text which is currently on screen and highlight it.
60560786Sps */
60660786Sps	static void
60760786Spshilite_screen()
60860786Sps{
60960786Sps	struct scrpos scrpos;
61060786Sps
61160786Sps	get_scrpos(&scrpos);
61260786Sps	if (scrpos.pos == NULL_POSITION)
61360786Sps		return;
61460786Sps	prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
61560786Sps	repaint_hilite(1);
61660786Sps}
61760786Sps
61860786Sps/*
61960786Sps * Change highlighting parameters.
62060786Sps */
62160786Sps	public void
62260786Spschg_hilite()
62360786Sps{
62460786Sps	/*
62560786Sps	 * Erase any highlights currently on screen.
62660786Sps	 */
62760786Sps	clr_hilite();
62860786Sps	hide_hilite = 0;
62960786Sps
63060786Sps	if (hilite_search == OPT_ONPLUS)
63160786Sps		/*
63260786Sps		 * Display highlights.
63360786Sps		 */
63460786Sps		hilite_screen();
63560786Sps}
63660786Sps#endif
63760786Sps
63860786Sps/*
63960786Sps * Figure out where to start a search.
64060786Sps */
64160786Sps	static POSITION
64260786Spssearch_pos(search_type)
64360786Sps	int search_type;
64460786Sps{
64560786Sps	POSITION pos;
64660786Sps	int linenum;
64760786Sps
64860786Sps	if (empty_screen())
64960786Sps	{
65060786Sps		/*
65160786Sps		 * Start at the beginning (or end) of the file.
65260786Sps		 * The empty_screen() case is mainly for
65360786Sps		 * command line initiated searches;
65460786Sps		 * for example, "+/xyz" on the command line.
65560786Sps		 * Also for multi-file (SRCH_PAST_EOF) searches.
65660786Sps		 */
65760786Sps		if (search_type & SRCH_FORW)
65860786Sps		{
659221715Sdelphij			pos = ch_zero();
66060786Sps		} else
66160786Sps		{
66260786Sps			pos = ch_length();
66360786Sps			if (pos == NULL_POSITION)
66460786Sps			{
66560786Sps				(void) ch_end_seek();
66660786Sps				pos = ch_length();
66760786Sps			}
66860786Sps		}
669221715Sdelphij		linenum = 0;
670221715Sdelphij	} else
67160786Sps	{
672221715Sdelphij		int add_one = 0;
673221715Sdelphij
674221715Sdelphij		if (how_search == OPT_ON)
67560786Sps		{
676221715Sdelphij			/*
677221715Sdelphij			 * Search does not include current screen.
678221715Sdelphij			 */
679221715Sdelphij			if (search_type & SRCH_FORW)
680221715Sdelphij				linenum = BOTTOM_PLUS_ONE;
681221715Sdelphij			else
682221715Sdelphij				linenum = TOP;
683221715Sdelphij		} else if (how_search == OPT_ONPLUS && !(search_type & SRCH_AFTER_TARGET))
684221715Sdelphij		{
685221715Sdelphij			/*
686221715Sdelphij			 * Search includes all of displayed screen.
687221715Sdelphij			 */
688221715Sdelphij			if (search_type & SRCH_FORW)
689221715Sdelphij				linenum = TOP;
690221715Sdelphij			else
691221715Sdelphij				linenum = BOTTOM_PLUS_ONE;
69260786Sps		} else
69360786Sps		{
694221715Sdelphij			/*
695221715Sdelphij			 * Search includes the part of current screen beyond the jump target.
696221715Sdelphij			 * It starts at the jump target (if searching backwards),
697221715Sdelphij			 * or at the jump target plus one (if forwards).
698221715Sdelphij			 */
699221715Sdelphij			linenum = jump_sline;
700221715Sdelphij			if (search_type & SRCH_FORW)
701221715Sdelphij			    add_one = 1;
70260786Sps		}
703221715Sdelphij		linenum = adjsline(linenum);
704221715Sdelphij		pos = position(linenum);
705221715Sdelphij		if (add_one)
706221715Sdelphij			pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
70760786Sps	}
708221715Sdelphij
709221715Sdelphij	/*
710221715Sdelphij	 * If the line is empty, look around for a plausible starting place.
711221715Sdelphij	 */
712221715Sdelphij	if (search_type & SRCH_FORW)
713221715Sdelphij	{
714221715Sdelphij	    while (pos == NULL_POSITION)
715221715Sdelphij	    {
716221715Sdelphij	        if (++linenum >= sc_height)
717221715Sdelphij	            break;
718221715Sdelphij	        pos = position(linenum);
719221715Sdelphij	    }
720221715Sdelphij	} else
721221715Sdelphij	{
722221715Sdelphij	    while (pos == NULL_POSITION)
723221715Sdelphij	    {
724221715Sdelphij	        if (--linenum < 0)
725221715Sdelphij	            break;
726221715Sdelphij	        pos = position(linenum);
727221715Sdelphij	    }
728221715Sdelphij	}
72960786Sps	return (pos);
73060786Sps}
73160786Sps
73260786Sps/*
73360786Sps * Search a subset of the file, specified by start/end position.
73460786Sps */
73560786Sps	static int
73660786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
73760786Sps	POSITION pos;
73860786Sps	POSITION endpos;
73960786Sps	int search_type;
74060786Sps	int matches;
74160786Sps	int maxlines;
74260786Sps	POSITION *plinepos;
74360786Sps	POSITION *pendpos;
74460786Sps{
74560786Sps	char *line;
746173685Sdelphij	char *cline;
747170259Sdelphij	int line_len;
748128348Stjr	LINENUM linenum;
74960786Sps	char *sp, *ep;
75060786Sps	int line_match;
751128348Stjr	int cvt_ops;
752195941Sdelphij	int cvt_len;
753195941Sdelphij	int *chpos;
75460786Sps	POSITION linepos, oldpos;
75560786Sps
75660786Sps	linenum = find_linenum(pos);
75760786Sps	oldpos = pos;
75860786Sps	for (;;)
75960786Sps	{
76060786Sps		/*
76160786Sps		 * Get lines until we find a matching one or until
76260786Sps		 * we hit end-of-file (or beginning-of-file if we're
76360786Sps		 * going backwards), or until we hit the end position.
76460786Sps		 */
76560786Sps		if (ABORT_SIGS())
76660786Sps		{
76760786Sps			/*
76860786Sps			 * A signal aborts the search.
76960786Sps			 */
77060786Sps			return (-1);
77160786Sps		}
77260786Sps
77360786Sps		if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
77460786Sps		{
77560786Sps			/*
77660786Sps			 * Reached end position without a match.
77760786Sps			 */
77860786Sps			if (pendpos != NULL)
77960786Sps				*pendpos = pos;
78060786Sps			return (matches);
78160786Sps		}
78260786Sps		if (maxlines > 0)
78360786Sps			maxlines--;
78460786Sps
78560786Sps		if (search_type & SRCH_FORW)
78660786Sps		{
78760786Sps			/*
78860786Sps			 * Read the next line, and save the
78960786Sps			 * starting position of that line in linepos.
79060786Sps			 */
79160786Sps			linepos = pos;
792170259Sdelphij			pos = forw_raw_line(pos, &line, &line_len);
79360786Sps			if (linenum != 0)
79460786Sps				linenum++;
79560786Sps		} else
79660786Sps		{
79760786Sps			/*
79860786Sps			 * Read the previous line and save the
79960786Sps			 * starting position of that line in linepos.
80060786Sps			 */
801170259Sdelphij			pos = back_raw_line(pos, &line, &line_len);
80260786Sps			linepos = pos;
80360786Sps			if (linenum != 0)
80460786Sps				linenum--;
80560786Sps		}
80660786Sps
80760786Sps		if (pos == NULL_POSITION)
80860786Sps		{
80960786Sps			/*
81060786Sps			 * Reached EOF/BOF without a match.
81160786Sps			 */
81260786Sps			if (pendpos != NULL)
81360786Sps				*pendpos = oldpos;
81460786Sps			return (matches);
81560786Sps		}
81660786Sps
81760786Sps		/*
81860786Sps		 * If we're using line numbers, we might as well
81960786Sps		 * remember the information we have now (the position
82060786Sps		 * and line number of the current line).
82160786Sps		 * Don't do it for every line because it slows down
82260786Sps		 * the search.  Remember the line number only if
82360786Sps		 * we're "far" from the last place we remembered it.
82460786Sps		 */
825195941Sdelphij		if (linenums && abs((int)(pos - oldpos)) > 2048)
82660786Sps			add_lnum(linenum, pos);
82760786Sps		oldpos = pos;
82860786Sps
829191930Sdelphij		if (is_filtered(linepos))
830191930Sdelphij			continue;
831191930Sdelphij
83260786Sps		/*
83360786Sps		 * If it's a caseless search, convert the line to lowercase.
83460786Sps		 * If we're doing backspace processing, delete backspaces.
83560786Sps		 */
836128348Stjr		cvt_ops = get_cvt_ops();
837195941Sdelphij		cvt_len = cvt_length(line_len, cvt_ops);
838195941Sdelphij		cline = (char *) ecalloc(1, cvt_len);
839195941Sdelphij		chpos = cvt_alloc_chpos(cvt_len);
840195941Sdelphij		cvt_text(cline, line, chpos, &line_len, cvt_ops);
84160786Sps
842191930Sdelphij#if HILITE_SEARCH
84360786Sps		/*
844191930Sdelphij		 * Check to see if the line matches the filter pattern.
845191930Sdelphij		 * If so, add an entry to the filter list.
84660786Sps		 */
847195941Sdelphij		if ((search_type & SRCH_FIND_ALL) && prev_pattern(&filter_info)) {
848240121Sdelphij			int line_filter = match_pattern(info_compiled(&filter_info), filter_info.text,
849195941Sdelphij				cline, line_len, &sp, &ep, 0, filter_info.search_type);
850191930Sdelphij			if (line_filter)
851191930Sdelphij			{
852191930Sdelphij				struct hilite *hl = (struct hilite *)
853191930Sdelphij					ecalloc(1, sizeof(struct hilite));
854191930Sdelphij				hl->hl_startpos = linepos;
855191930Sdelphij				hl->hl_endpos = pos;
856191930Sdelphij				add_hilite(&filter_anchor, hl);
857191930Sdelphij			}
858173685Sdelphij		}
859191930Sdelphij#endif
860191930Sdelphij
86160786Sps		/*
862191930Sdelphij		 * Test the next line to see if we have a match.
863191930Sdelphij		 * We are successful if we either want a match and got one,
864191930Sdelphij		 * or if we want a non-match and got one.
86560786Sps		 */
866195941Sdelphij		if (prev_pattern(&search_info))
86760786Sps		{
868240121Sdelphij			line_match = match_pattern(info_compiled(&search_info), search_info.text,
869221715Sdelphij				cline, line_len, &sp, &ep, 0, search_type);
87060786Sps			if (line_match)
87160786Sps			{
87260786Sps				/*
873191930Sdelphij				 * Got a match.
87460786Sps				 */
875191930Sdelphij				if (search_type & SRCH_FIND_ALL)
876191930Sdelphij				{
877191930Sdelphij#if HILITE_SEARCH
878191930Sdelphij					/*
879191930Sdelphij					 * We are supposed to find all matches in the range.
880191930Sdelphij					 * Just add the matches in this line to the
881191930Sdelphij					 * hilite list and keep searching.
882191930Sdelphij					 */
883195941Sdelphij					hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
884191930Sdelphij#endif
885191930Sdelphij				} else if (--matches <= 0)
886191930Sdelphij				{
887191930Sdelphij					/*
888191930Sdelphij					 * Found the one match we're looking for.
889191930Sdelphij					 * Return it.
890191930Sdelphij					 */
891191930Sdelphij#if HILITE_SEARCH
892191930Sdelphij					if (hilite_search == OPT_ON)
893191930Sdelphij					{
894191930Sdelphij						/*
895191930Sdelphij						 * Clear the hilite list and add only
896191930Sdelphij						 * the matches in this one line.
897191930Sdelphij						 */
898191930Sdelphij						clr_hilite();
899195941Sdelphij						hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
900191930Sdelphij					}
901191930Sdelphij#endif
902191930Sdelphij					free(cline);
903195941Sdelphij					free(chpos);
904191930Sdelphij					if (plinepos != NULL)
905191930Sdelphij						*plinepos = linepos;
906191930Sdelphij					return (0);
907191930Sdelphij				}
90860786Sps			}
90960786Sps		}
910191930Sdelphij		free(cline);
911195941Sdelphij		free(chpos);
91260786Sps	}
91360786Sps}
91460786Sps
915191930Sdelphij/*
916170259Sdelphij * search for a pattern in history. If found, compile that pattern.
917170259Sdelphij */
918170259Sdelphij	static int
919170259Sdelphijhist_pattern(search_type)
920170259Sdelphij	int search_type;
921170259Sdelphij{
922170259Sdelphij#if CMD_HISTORY
923170259Sdelphij	char *pattern;
924170259Sdelphij
925170259Sdelphij	set_mlist(ml_search, 0);
926170259Sdelphij	pattern = cmd_lastpattern();
927170259Sdelphij	if (pattern == NULL)
928170259Sdelphij		return (0);
929170259Sdelphij
930195941Sdelphij	if (set_pattern(&search_info, pattern, search_type) < 0)
931170259Sdelphij		return (0);
932170259Sdelphij
933170259Sdelphij#if HILITE_SEARCH
934170259Sdelphij	if (hilite_search == OPT_ONPLUS && !hide_hilite)
935170259Sdelphij		hilite_screen();
936170259Sdelphij#endif
937170259Sdelphij
938170259Sdelphij	return (1);
939170259Sdelphij#else /* CMD_HISTORY */
940170259Sdelphij	return (0);
941170259Sdelphij#endif /* CMD_HISTORY */
942170259Sdelphij}
943170259Sdelphij
94460786Sps/*
94560786Sps * Search for the n-th occurrence of a specified pattern,
94660786Sps * either forward or backward.
94760786Sps * Return the number of matches not yet found in this file
94860786Sps * (that is, n minus the number of matches found).
94960786Sps * Return -1 if the search should be aborted.
95060786Sps * Caller may continue the search in another file
95160786Sps * if less than n matches are found in this file.
95260786Sps */
95360786Sps	public int
95460786Spssearch(search_type, pattern, n)
95560786Sps	int search_type;
95660786Sps	char *pattern;
95760786Sps	int n;
95860786Sps{
95960786Sps	POSITION pos;
96060786Sps
96160786Sps	if (pattern == NULL || *pattern == '\0')
96260786Sps	{
96360786Sps		/*
96460786Sps		 * A null pattern means use the previously compiled pattern.
96560786Sps		 */
966221715Sdelphij		search_type |= SRCH_AFTER_TARGET;
967195941Sdelphij		if (!prev_pattern(&search_info) && !hist_pattern(search_type))
96860786Sps		{
96960786Sps			error("No previous regular expression", NULL_PARG);
97060786Sps			return (-1);
97160786Sps		}
97260786Sps		if ((search_type & SRCH_NO_REGEX) !=
973195941Sdelphij		      (search_info.search_type & SRCH_NO_REGEX))
97460786Sps		{
97560786Sps			error("Please re-enter search pattern", NULL_PARG);
97660786Sps			return -1;
97760786Sps		}
97860786Sps#if HILITE_SEARCH
97960786Sps		if (hilite_search == OPT_ON)
98060786Sps		{
98160786Sps			/*
98260786Sps			 * Erase the highlights currently on screen.
98360786Sps			 * If the search fails, we'll redisplay them later.
98460786Sps			 */
98560786Sps			repaint_hilite(0);
98660786Sps		}
98760786Sps		if (hilite_search == OPT_ONPLUS && hide_hilite)
98860786Sps		{
98960786Sps			/*
99060786Sps			 * Highlight any matches currently on screen,
99160786Sps			 * before we actually start the search.
99260786Sps			 */
99360786Sps			hide_hilite = 0;
99460786Sps			hilite_screen();
99560786Sps		}
99660786Sps		hide_hilite = 0;
99760786Sps#endif
99860786Sps	} else
99960786Sps	{
100060786Sps		/*
100160786Sps		 * Compile the pattern.
100260786Sps		 */
1003195941Sdelphij		if (set_pattern(&search_info, pattern, search_type) < 0)
100460786Sps			return (-1);
100560786Sps#if HILITE_SEARCH
100660786Sps		if (hilite_search)
100760786Sps		{
100860786Sps			/*
100960786Sps			 * Erase the highlights currently on screen.
101060786Sps			 * Also permanently delete them from the hilite list.
101160786Sps			 */
101260786Sps			repaint_hilite(0);
101360786Sps			hide_hilite = 0;
101460786Sps			clr_hilite();
101560786Sps		}
101660786Sps		if (hilite_search == OPT_ONPLUS)
101760786Sps		{
101860786Sps			/*
101960786Sps			 * Highlight any matches currently on screen,
102060786Sps			 * before we actually start the search.
102160786Sps			 */
102260786Sps			hilite_screen();
102360786Sps		}
102460786Sps#endif
102560786Sps	}
102660786Sps
102760786Sps	/*
102860786Sps	 * Figure out where to start the search.
102960786Sps	 */
103060786Sps	pos = search_pos(search_type);
103160786Sps	if (pos == NULL_POSITION)
103260786Sps	{
103360786Sps		/*
103460786Sps		 * Can't find anyplace to start searching from.
103560786Sps		 */
103660786Sps		if (search_type & SRCH_PAST_EOF)
103760786Sps			return (n);
103860786Sps		/* repaint(); -- why was this here? */
103960786Sps		error("Nothing to search", NULL_PARG);
104060786Sps		return (-1);
104160786Sps	}
104260786Sps
104360786Sps	n = search_range(pos, NULL_POSITION, search_type, n, -1,
104460786Sps			&pos, (POSITION*)NULL);
104560786Sps	if (n != 0)
104660786Sps	{
104760786Sps		/*
104860786Sps		 * Search was unsuccessful.
104960786Sps		 */
105060786Sps#if HILITE_SEARCH
105160786Sps		if (hilite_search == OPT_ON && n > 0)
105260786Sps			/*
105360786Sps			 * Redisplay old hilites.
105460786Sps			 */
105560786Sps			repaint_hilite(1);
105660786Sps#endif
105760786Sps		return (n);
105860786Sps	}
105960786Sps
106060786Sps	if (!(search_type & SRCH_NO_MOVE))
106160786Sps	{
106260786Sps		/*
106360786Sps		 * Go to the matching line.
106460786Sps		 */
106560786Sps		jump_loc(pos, jump_sline);
106660786Sps	}
106760786Sps
106860786Sps#if HILITE_SEARCH
106960786Sps	if (hilite_search == OPT_ON)
107060786Sps		/*
107160786Sps		 * Display new hilites in the matching line.
107260786Sps		 */
107360786Sps		repaint_hilite(1);
107460786Sps#endif
107560786Sps	return (0);
107660786Sps}
107760786Sps
107860786Sps
107960786Sps#if HILITE_SEARCH
108060786Sps/*
108160786Sps * Prepare hilites in a given range of the file.
108260786Sps *
108360786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region
108460786Sps * of the file that has been "prepared"; that is, scanned for matches for
108560786Sps * the current search pattern, and hilites have been created for such matches.
108660786Sps * If prep_startpos == NULL_POSITION, the prep region is empty.
108760786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
108860786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region.
108960786Sps */
109060786Sps	public void
109160786Spsprep_hilite(spos, epos, maxlines)
109260786Sps	POSITION spos;
109360786Sps	POSITION epos;
109460786Sps	int maxlines;
109560786Sps{
109660786Sps	POSITION nprep_startpos = prep_startpos;
109760786Sps	POSITION nprep_endpos = prep_endpos;
109860786Sps	POSITION new_epos;
109960786Sps	POSITION max_epos;
110060786Sps	int result;
110160786Sps	int i;
1102195941Sdelphij
110360786Sps/*
110460786Sps * Search beyond where we're asked to search, so the prep region covers
110560786Sps * more than we need.  Do one big search instead of a bunch of small ones.
110660786Sps */
110760786Sps#define	SEARCH_MORE (3*size_linebuf)
110860786Sps
1109195941Sdelphij	if (!prev_pattern(&search_info) && !is_filtering())
111060786Sps		return;
111160786Sps
111260786Sps	/*
111360786Sps	 * If we're limited to a max number of lines, figure out the
111460786Sps	 * file position we should stop at.
111560786Sps	 */
111660786Sps	if (maxlines < 0)
111760786Sps		max_epos = NULL_POSITION;
111860786Sps	else
111960786Sps	{
112060786Sps		max_epos = spos;
112160786Sps		for (i = 0;  i < maxlines;  i++)
1122170259Sdelphij			max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
112360786Sps	}
112460786Sps
112560786Sps	/*
112660786Sps	 * Find two ranges:
112760786Sps	 * The range that we need to search (spos,epos); and the range that
112860786Sps	 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
112960786Sps	 */
113060786Sps
113160786Sps	if (prep_startpos == NULL_POSITION ||
113260786Sps	    (epos != NULL_POSITION && epos < prep_startpos) ||
113360786Sps	    spos > prep_endpos)
113460786Sps	{
113560786Sps		/*
113660786Sps		 * New range is not contiguous with old prep region.
113760786Sps		 * Discard the old prep region and start a new one.
113860786Sps		 */
113960786Sps		clr_hilite();
1140191930Sdelphij		clr_filter();
114160786Sps		if (epos != NULL_POSITION)
114260786Sps			epos += SEARCH_MORE;
114360786Sps		nprep_startpos = spos;
114460786Sps	} else
114560786Sps	{
114660786Sps		/*
114760786Sps		 * New range partially or completely overlaps old prep region.
114860786Sps		 */
114960786Sps		if (epos == NULL_POSITION)
115060786Sps		{
115160786Sps			/*
115260786Sps			 * New range goes to end of file.
115360786Sps			 */
115460786Sps			;
115560786Sps		} else if (epos > prep_endpos)
115660786Sps		{
115760786Sps			/*
115860786Sps			 * New range ends after old prep region.
115960786Sps			 * Extend prep region to end at end of new range.
116060786Sps			 */
116160786Sps			epos += SEARCH_MORE;
116260786Sps		} else /* (epos <= prep_endpos) */
116360786Sps		{
116460786Sps			/*
116560786Sps			 * New range ends within old prep region.
116660786Sps			 * Truncate search to end at start of old prep region.
116760786Sps			 */
116860786Sps			epos = prep_startpos;
116960786Sps		}
117060786Sps
117160786Sps		if (spos < prep_startpos)
117260786Sps		{
117360786Sps			/*
117460786Sps			 * New range starts before old prep region.
117560786Sps			 * Extend old prep region backwards to start at
117660786Sps			 * start of new range.
117760786Sps			 */
117860786Sps			if (spos < SEARCH_MORE)
117960786Sps				spos = 0;
118060786Sps			else
118160786Sps				spos -= SEARCH_MORE;
118260786Sps			nprep_startpos = spos;
118360786Sps		} else /* (spos >= prep_startpos) */
118460786Sps		{
118560786Sps			/*
118660786Sps			 * New range starts within or after old prep region.
118760786Sps			 * Trim search to start at end of old prep region.
118860786Sps			 */
118960786Sps			spos = prep_endpos;
119060786Sps		}
119160786Sps	}
119260786Sps
119360786Sps	if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
119460786Sps	    epos > max_epos)
119560786Sps		/*
119660786Sps		 * Don't go past the max position we're allowed.
119760786Sps		 */
119860786Sps		epos = max_epos;
119960786Sps
120060786Sps	if (epos == NULL_POSITION || epos > spos)
120160786Sps	{
1202195941Sdelphij		int search_type = SRCH_FORW | SRCH_FIND_ALL;
1203195941Sdelphij		search_type |= (search_info.search_type & SRCH_NO_REGEX);
1204195941Sdelphij		result = search_range(spos, epos, search_type, 0,
120560786Sps				maxlines, (POSITION*)NULL, &new_epos);
120660786Sps		if (result < 0)
120760786Sps			return;
120860786Sps		if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
120960786Sps			nprep_endpos = new_epos;
121060786Sps	}
121160786Sps	prep_startpos = nprep_startpos;
121260786Sps	prep_endpos = nprep_endpos;
121360786Sps}
1214191930Sdelphij
1215191930Sdelphij/*
1216191930Sdelphij * Set the pattern to be used for line filtering.
1217191930Sdelphij */
1218191930Sdelphij	public void
1219191930Sdelphijset_filter_pattern(pattern, search_type)
1220191930Sdelphij	char *pattern;
1221191930Sdelphij	int search_type;
1222191930Sdelphij{
1223191930Sdelphij	clr_filter();
1224191930Sdelphij	if (pattern == NULL || *pattern == '\0')
1225195941Sdelphij		clear_pattern(&filter_info);
1226191930Sdelphij	else
1227195941Sdelphij		set_pattern(&filter_info, pattern, search_type);
1228191930Sdelphij	screen_trashed = 1;
1229191930Sdelphij}
1230191930Sdelphij
1231191930Sdelphij/*
1232191930Sdelphij * Is there a line filter in effect?
1233191930Sdelphij */
1234191930Sdelphij	public int
1235191930Sdelphijis_filtering()
1236191930Sdelphij{
1237191930Sdelphij	if (ch_getflags() & CH_HELPFILE)
1238191930Sdelphij		return (0);
1239195941Sdelphij	return prev_pattern(&filter_info);
1240191930Sdelphij}
124160786Sps#endif
124260786Sps
124360786Sps#if HAVE_V8_REGCOMP
124460786Sps/*
124560786Sps * This function is called by the V8 regcomp to report
124660786Sps * errors in regular expressions.
124760786Sps */
124860786Sps	void
124960786Spsregerror(s)
125060786Sps	char *s;
125160786Sps{
125260786Sps	PARG parg;
125360786Sps
125460786Sps	parg.p_string = s;
125560786Sps	error("%s", &parg);
125660786Sps}
125760786Sps#endif
125860786Sps
1259