search.c revision 60786
1/*
2 * Copyright (C) 1984-2000  Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
10
11
12/*
13 * Routines to search a file for a pattern.
14 */
15
16#include "less.h"
17#include "position.h"
18
19#define	MINPOS(a,b)	(((a) < (b)) ? (a) : (b))
20#define	MAXPOS(a,b)	(((a) > (b)) ? (a) : (b))
21
22#if HAVE_POSIX_REGCOMP
23#include <regex.h>
24#ifdef REG_EXTENDED
25#define	REGCOMP_FLAG	REG_EXTENDED
26#else
27#define	REGCOMP_FLAG	0
28#endif
29#endif
30#if HAVE_PCRE
31#include <pcre.h>
32#endif
33#if HAVE_RE_COMP
34char *re_comp();
35int re_exec();
36#endif
37#if HAVE_REGCMP
38char *regcmp();
39char *regex();
40extern char *__loc1;
41#endif
42#if HAVE_V8_REGCOMP
43#include "regexp.h"
44#endif
45
46static int match();
47
48extern int sigs;
49extern int how_search;
50extern int caseless;
51extern int linenums;
52extern int sc_height;
53extern int jump_sline;
54extern int bs_mode;
55extern POSITION start_attnpos;
56extern POSITION end_attnpos;
57#if HILITE_SEARCH
58extern int hilite_search;
59extern int screen_trashed;
60extern int size_linebuf;
61extern int squished;
62extern int can_goto_line;
63static int hide_hilite;
64static POSITION prep_startpos;
65static POSITION prep_endpos;
66
67struct hilite
68{
69	struct hilite *hl_next;
70	POSITION hl_startpos;
71	POSITION hl_endpos;
72};
73static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
74#define	hl_first	hl_next
75#endif
76
77/*
78 * These are the static variables that represent the "remembered"
79 * search pattern.
80 */
81#if HAVE_POSIX_REGCOMP
82static regex_t *regpattern = NULL;
83#endif
84#if HAVE_PCRE
85pcre *regpattern = NULL;
86#endif
87#if HAVE_RE_COMP
88int re_pattern = 0;
89#endif
90#if HAVE_REGCMP
91static char *cpattern = NULL;
92#endif
93#if HAVE_V8_REGCOMP
94static struct regexp *regpattern = NULL;
95#endif
96
97static int is_caseless;
98static int is_ucase_pattern;
99static int last_search_type;
100static char *last_pattern = NULL;
101
102/*
103 * Convert text.  Perform one or more of these transformations:
104 */
105#define	CVT_TO_LC	01	/* Convert upper-case to lower-case */
106#define	CVT_BS		02	/* Do backspace processing */
107#define	CVT_CRLF	04	/* Remove CR after LF */
108
109	static void
110cvt_text(odst, osrc, ops)
111	char *odst;
112	char *osrc;
113	int ops;
114{
115	register char *dst;
116	register char *src;
117
118	for (src = osrc, dst = odst;  *src != '\0';  src++, dst++)
119	{
120		if ((ops & CVT_TO_LC) && isupper((unsigned char) *src))
121			/* Convert uppercase to lowercase. */
122			*dst = tolower((unsigned char) *src);
123		else if ((ops & CVT_BS) && *src == '\b' && dst > odst)
124			/* Delete BS and preceding char. */
125			dst -= 2;
126		else
127			/* Just copy. */
128			*dst = *src;
129	}
130	if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
131		dst--;
132	*dst = '\0';
133}
134
135/*
136 * Are there any uppercase letters in this string?
137 */
138	static int
139is_ucase(s)
140	char *s;
141{
142	register char *p;
143
144	for (p = s;  *p != '\0';  p++)
145		if (isupper((unsigned char) *p))
146			return (1);
147	return (0);
148}
149
150/*
151 * Is there a previous (remembered) search pattern?
152 */
153	static int
154prev_pattern()
155{
156	if (last_search_type & SRCH_NO_REGEX)
157		return (last_pattern != NULL);
158#if HAVE_POSIX_REGCOMP
159	return (regpattern != NULL);
160#endif
161#if HAVE_PCRE
162	return (regpattern != NULL);
163#endif
164#if HAVE_RE_COMP
165	return (re_pattern != 0);
166#endif
167#if HAVE_REGCMP
168	return (cpattern != NULL);
169#endif
170#if HAVE_V8_REGCOMP
171	return (regpattern != NULL);
172#endif
173#if NO_REGEX
174	return (last_pattern != NULL);
175#endif
176}
177
178#if HILITE_SEARCH
179/*
180 * Repaint the hilites currently displayed on the screen.
181 * Repaint each line which contains highlighted text.
182 * If on==0, force all hilites off.
183 */
184	public void
185repaint_hilite(on)
186	int on;
187{
188	int slinenum;
189	POSITION pos;
190	POSITION epos;
191	int save_hide_hilite;
192
193	if (squished)
194		repaint();
195
196	save_hide_hilite = hide_hilite;
197	if (!on)
198	{
199		if (hide_hilite)
200			return;
201		hide_hilite = 1;
202	}
203
204	if (!can_goto_line)
205	{
206		repaint();
207		hide_hilite = save_hide_hilite;
208		return;
209	}
210
211	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
212	{
213		pos = position(slinenum);
214		if (pos == NULL_POSITION)
215			continue;
216		epos = position(slinenum+1);
217		/*
218		 * If any character in the line is highlighted,
219		 * repaint the line.
220		 */
221		if (is_hilited(pos, epos, 1))
222		{
223			(void) forw_line(pos);
224			goto_line(slinenum);
225			put_line();
226		}
227	}
228	hide_hilite = save_hide_hilite;
229}
230
231/*
232 * Clear the attn hilite.
233 */
234	public void
235clear_attn()
236{
237	int slinenum;
238	POSITION old_start_attnpos;
239	POSITION old_end_attnpos;
240	POSITION pos;
241	POSITION epos;
242
243	if (start_attnpos == NULL_POSITION)
244		return;
245	old_start_attnpos = start_attnpos;
246	old_end_attnpos = end_attnpos;
247	start_attnpos = end_attnpos = NULL_POSITION;
248
249	if (!can_goto_line)
250	{
251		repaint();
252		return;
253	}
254	if (squished)
255		repaint();
256
257	for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
258	{
259		pos = position(slinenum);
260		if (pos == NULL_POSITION)
261			continue;
262		epos = position(slinenum+1);
263		if (pos < old_end_attnpos &&
264		     (epos == NULL_POSITION || epos > old_start_attnpos))
265		{
266			(void) forw_line(pos);
267			goto_line(slinenum);
268			put_line();
269		}
270	}
271}
272#endif
273
274/*
275 * Hide search string highlighting.
276 */
277	public void
278undo_search()
279{
280	if (!prev_pattern())
281	{
282		error("No previous regular expression", NULL_PARG);
283		return;
284	}
285#if HILITE_SEARCH
286	hide_hilite = !hide_hilite;
287	repaint_hilite(1);
288#endif
289}
290
291/*
292 * Compile a search pattern, for future use by match_pattern.
293 */
294	static int
295compile_pattern(pattern, search_type)
296	char *pattern;
297	int search_type;
298{
299	if ((search_type & SRCH_NO_REGEX) == 0)
300	{
301#if HAVE_POSIX_REGCOMP
302		regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
303		if (regcomp(s, pattern, REGCOMP_FLAG))
304		{
305			free(s);
306			error("Invalid pattern", NULL_PARG);
307			return (-1);
308		}
309		if (regpattern != NULL)
310			regfree(regpattern);
311		regpattern = s;
312#endif
313#if HAVE_PCRE
314		pcre *comp;
315		const char *errstring;
316		int erroffset;
317		PARG parg;
318		comp = pcre_compile(pattern, 0,
319				&errstring, &erroffset, NULL);
320		if (comp == NULL)
321		{
322			parg.p_string = (char *) errstring;
323			error("%s", &parg);
324			return (-1);
325		}
326		regpattern = comp;
327#endif
328#if HAVE_RE_COMP
329		PARG parg;
330		if ((parg.p_string = re_comp(pattern)) != NULL)
331		{
332			error("%s", &parg);
333			return (-1);
334		}
335		re_pattern = 1;
336#endif
337#if HAVE_REGCMP
338		char *s;
339		if ((s = regcmp(pattern, 0)) == NULL)
340		{
341			error("Invalid pattern", NULL_PARG);
342			return (-1);
343		}
344		if (cpattern != NULL)
345			free(cpattern);
346		cpattern = s;
347#endif
348#if HAVE_V8_REGCOMP
349		struct regexp *s;
350		if ((s = regcomp(pattern)) == NULL)
351		{
352			/*
353			 * regcomp has already printed an error message
354			 * via regerror().
355			 */
356			return (-1);
357		}
358		if (regpattern != NULL)
359			free(regpattern);
360		regpattern = s;
361#endif
362	}
363
364	if (last_pattern != NULL)
365		free(last_pattern);
366	last_pattern = (char *) calloc(1, strlen(pattern)+1);
367	if (last_pattern != NULL)
368		strcpy(last_pattern, pattern);
369
370	last_search_type = search_type;
371	return (0);
372}
373
374/*
375 * Forget that we have a compiled pattern.
376 */
377	static void
378uncompile_pattern()
379{
380#if HAVE_POSIX_REGCOMP
381	if (regpattern != NULL)
382		regfree(regpattern);
383	regpattern = NULL;
384#endif
385#if HAVE_PCRE
386	if (regpattern != NULL)
387		pcre_free(regpattern);
388	regpattern = NULL;
389#endif
390#if HAVE_RE_COMP
391	re_pattern = 0;
392#endif
393#if HAVE_REGCMP
394	if (cpattern != NULL)
395		free(cpattern);
396	cpattern = NULL;
397#endif
398#if HAVE_V8_REGCOMP
399	if (regpattern != NULL)
400		free(regpattern);
401	regpattern = NULL;
402#endif
403	last_pattern = NULL;
404}
405
406/*
407 * Perform a pattern match with the previously compiled pattern.
408 * Set sp and ep to the start and end of the matched string.
409 */
410	static int
411match_pattern(line, sp, ep, notbol)
412	char *line;
413	char **sp;
414	char **ep;
415	int notbol;
416{
417	int matched;
418
419	if (last_search_type & SRCH_NO_REGEX)
420		return (match(last_pattern, line, sp, ep));
421
422#if HAVE_POSIX_REGCOMP
423	{
424		regmatch_t rm;
425		int flags = (notbol) ? REG_NOTBOL : 0;
426		matched = !regexec(regpattern, line, 1, &rm, flags);
427		if (!matched)
428			return (0);
429#ifndef __WATCOMC__
430		*sp = line + rm.rm_so;
431		*ep = line + rm.rm_eo;
432#else
433		*sp = rm.rm_sp;
434		*ep = rm.rm_ep;
435#endif
436	}
437#endif
438#if HAVE_PCRE
439	{
440		int flags = (notbol) ? PCRE_NOTBOL : 0;
441		int ovector[3];
442		matched = pcre_exec(regpattern, NULL, line, strlen(line),
443			0, flags, ovector, 3) >= 0;
444		if (!matched)
445			return (0);
446		*sp = line + ovector[0];
447		*ep = line + ovector[1];
448	}
449#endif
450#if HAVE_RE_COMP
451	matched = (re_exec(line) == 1);
452	/*
453	 * re_exec doesn't seem to provide a way to get the matched string.
454	 */
455	*sp = *ep = NULL;
456#endif
457#if HAVE_REGCMP
458	*ep = regex(cpattern, line);
459	matched = (*ep != NULL);
460	if (!matched)
461		return (0);
462	*sp = __loc1;
463#endif
464#if HAVE_V8_REGCOMP
465#if HAVE_REGEXEC2
466	matched = regexec2(regpattern, line, notbol);
467#else
468	matched = regexec(regpattern, line);
469#endif
470	if (!matched)
471		return (0);
472	*sp = regpattern->startp[0];
473	*ep = regpattern->endp[0];
474#endif
475#if NO_REGEX
476	matched = match(last_pattern, line, sp, ep);
477#endif
478	return (matched);
479}
480
481#if HILITE_SEARCH
482/*
483 * Clear the hilite list.
484 */
485	public void
486clr_hilite()
487{
488	struct hilite *hl;
489	struct hilite *nexthl;
490
491	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = nexthl)
492	{
493		nexthl = hl->hl_next;
494		free((void*)hl);
495	}
496	hilite_anchor.hl_first = NULL;
497	prep_startpos = prep_endpos = NULL_POSITION;
498}
499
500/*
501 * Should any characters in a specified range be highlighted?
502 * If nohide is nonzero, don't consider hide_hilite.
503 */
504	public int
505is_hilited(pos, epos, nohide)
506	POSITION pos;
507	POSITION epos;
508	int nohide;
509{
510	struct hilite *hl;
511
512	if (start_attnpos != NULL_POSITION &&
513	    pos < end_attnpos &&
514	     (epos == NULL_POSITION || epos > start_attnpos))
515		/*
516		 * The attn line overlaps this range.
517		 */
518		return (1);
519
520	if (hilite_search == 0)
521		/*
522		 * Not doing highlighting.
523		 */
524		return (0);
525
526	if (!nohide && hide_hilite)
527		/*
528		 * Highlighting is hidden.
529		 */
530		return (0);
531
532	/*
533	 * Look at each highlight and see if any part of it falls in the range.
534	 */
535	for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
536	{
537		if (hl->hl_endpos > pos &&
538		    (epos == NULL_POSITION || epos > hl->hl_startpos))
539			return (1);
540	}
541	return (0);
542}
543
544/*
545 * Add a new hilite to a hilite list.
546 */
547	static void
548add_hilite(anchor, hl)
549	struct hilite *anchor;
550	struct hilite *hl;
551{
552	struct hilite *ihl;
553
554	/*
555	 * Hilites are sorted in the list; find where new one belongs.
556	 * Insert new one after ihl.
557	 */
558	for (ihl = anchor;  ihl->hl_next != NULL;  ihl = ihl->hl_next)
559	{
560		if (ihl->hl_next->hl_startpos > hl->hl_startpos)
561			break;
562	}
563
564	/*
565	 * Truncate hilite so it doesn't overlap any existing ones
566	 * above and below it.
567	 */
568	if (ihl != anchor)
569		hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
570	if (ihl->hl_next != NULL)
571		hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
572	if (hl->hl_startpos >= hl->hl_endpos)
573	{
574		/*
575		 * Hilite was truncated out of existence.
576		 */
577		free(hl);
578		return;
579	}
580	hl->hl_next = ihl->hl_next;
581	ihl->hl_next = hl;
582}
583
584/*
585 * Adjust hl_startpos & hl_endpos to account for backspace processing.
586 */
587	static void
588adj_hilite(anchor, linepos)
589	struct hilite *anchor;
590	POSITION linepos;
591{
592	char *line;
593	struct hilite *hl;
594	int checkstart;
595	POSITION opos;
596	POSITION npos;
597
598	/*
599	 * The line was already scanned and hilites were added (in hilite_line).
600	 * But it was assumed that each char position in the line
601	 * correponds to one char position in the file.
602	 * This may not be true if there are backspaces in the line.
603	 * Get the raw line again.  Look at each character.
604	 */
605	(void) forw_raw_line(linepos, &line);
606	opos = npos = linepos;
607	hl = anchor->hl_first;
608	checkstart = TRUE;
609	while (hl != NULL)
610	{
611		/*
612		 * See if we need to adjust the current hl_startpos or
613		 * hl_endpos.  After adjusting startpos[i], move to endpos[i].
614		 * After adjusting endpos[i], move to startpos[i+1].
615		 * The hilite list must be sorted thus:
616		 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
617		 */
618		if (checkstart && hl->hl_startpos == opos)
619		{
620			hl->hl_startpos = npos;
621			checkstart = FALSE;
622			continue; /* {{ not really necessary }} */
623		} else if (!checkstart && hl->hl_endpos == opos)
624		{
625			hl->hl_endpos = npos;
626			checkstart = TRUE;
627			hl = hl->hl_next;
628			continue; /* {{ necessary }} */
629		}
630		if (*line == '\0')
631			break;
632		opos++;
633		npos++;
634		line++;
635		while (line[0] == '\b' && line[1] != '\0')
636		{
637			/*
638			 * Found a backspace.  The file position moves
639			 * forward by 2 relative to the processed line
640			 * which was searched in hilite_line.
641			 */
642			npos += 2;
643			line += 2;
644		}
645	}
646}
647
648/*
649 * Make a hilite for each string in a physical line which matches
650 * the current pattern.
651 * sp,ep delimit the first match already found.
652 */
653	static void
654hilite_line(linepos, line, sp, ep)
655	POSITION linepos;
656	char *line;
657	char *sp;
658	char *ep;
659{
660	char *searchp;
661	struct hilite *hl;
662	struct hilite hilites;
663
664	if (sp == NULL || ep == NULL)
665		return;
666	/*
667	 * sp and ep delimit the first match in the line.
668	 * Mark the corresponding file positions, then
669	 * look for further matches and mark them.
670	 * {{ This technique, of calling match_pattern on subsequent
671	 *    substrings of the line, may mark more than is correct
672	 *    if the pattern starts with "^".  This bug is fixed
673	 *    for those regex functions that accept a notbol parameter
674	 *    (currently POSIX and V8-with-regexec2). }}
675	 */
676	searchp = line;
677	/*
678	 * Put the hilites into a temporary list until they're adjusted.
679	 */
680	hilites.hl_first = NULL;
681	do {
682		if (ep > sp)
683		{
684			/*
685			 * Assume that each char position in the "line"
686			 * buffer corresponds to one char position in the file.
687			 * This is not quite true; we need to adjust later.
688			 */
689			hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
690			hl->hl_startpos = linepos + (sp-line);
691			hl->hl_endpos = linepos + (ep-line);
692			add_hilite(&hilites, hl);
693		}
694		/*
695		 * If we matched more than zero characters,
696		 * move to the first char after the string we matched.
697		 * If we matched zero, just move to the next char.
698		 */
699		if (ep > searchp)
700			searchp = ep;
701		else if (*searchp != '\0')
702			searchp++;
703		else /* end of line */
704			break;
705	} while (match_pattern(searchp, &sp, &ep, 1));
706
707	if (bs_mode == BS_SPECIAL)
708	{
709		/*
710		 * If there were backspaces in the original line, they
711		 * were removed, and hl_startpos/hl_endpos are not correct.
712		 * {{ This is very ugly. }}
713		 */
714		adj_hilite(&hilites, linepos);
715	}
716	/*
717	 * Now put the hilites into the real list.
718	 */
719	while ((hl = hilites.hl_next) != NULL)
720	{
721		hilites.hl_next = hl->hl_next;
722		add_hilite(&hilite_anchor, hl);
723	}
724}
725#endif
726
727/*
728 * Change the caseless-ness of searches.
729 * Updates the internal search state to reflect a change in the -i flag.
730 */
731	public void
732chg_caseless()
733{
734	if (!is_ucase_pattern)
735		/*
736		 * Pattern did not have uppercase.
737		 * Just set the search caselessness to the global caselessness.
738		 */
739		is_caseless = caseless;
740	else
741		/*
742		 * Pattern did have uppercase.
743		 * Discard the pattern; we can't change search caselessness now.
744		 */
745		uncompile_pattern();
746}
747
748#if HILITE_SEARCH
749/*
750 * Find matching text which is currently on screen and highlight it.
751 */
752	static void
753hilite_screen()
754{
755	struct scrpos scrpos;
756
757	get_scrpos(&scrpos);
758	if (scrpos.pos == NULL_POSITION)
759		return;
760	prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
761	repaint_hilite(1);
762}
763
764/*
765 * Change highlighting parameters.
766 */
767	public void
768chg_hilite()
769{
770	/*
771	 * Erase any highlights currently on screen.
772	 */
773	clr_hilite();
774	hide_hilite = 0;
775
776	if (hilite_search == OPT_ONPLUS)
777		/*
778		 * Display highlights.
779		 */
780		hilite_screen();
781}
782#endif
783
784/*
785 * Figure out where to start a search.
786 */
787	static POSITION
788search_pos(search_type)
789	int search_type;
790{
791	POSITION pos;
792	int linenum;
793
794	if (empty_screen())
795	{
796		/*
797		 * Start at the beginning (or end) of the file.
798		 * The empty_screen() case is mainly for
799		 * command line initiated searches;
800		 * for example, "+/xyz" on the command line.
801		 * Also for multi-file (SRCH_PAST_EOF) searches.
802		 */
803		if (search_type & SRCH_FORW)
804		{
805			return (ch_zero());
806		} else
807		{
808			pos = ch_length();
809			if (pos == NULL_POSITION)
810			{
811				(void) ch_end_seek();
812				pos = ch_length();
813			}
814			return (pos);
815		}
816	}
817	if (how_search)
818	{
819		/*
820		 * Search does not include current screen.
821		 */
822		if (search_type & SRCH_FORW)
823			linenum = BOTTOM_PLUS_ONE;
824		else
825			linenum = TOP;
826		pos = position(linenum);
827	} else
828	{
829		/*
830		 * Search includes current screen.
831		 * It starts at the jump target (if searching backwards),
832		 * or at the jump target plus one (if forwards).
833		 */
834		linenum = adjsline(jump_sline);
835		pos = position(linenum);
836		if (search_type & SRCH_FORW)
837		{
838			pos = forw_raw_line(pos, (char **)NULL);
839			while (pos == NULL_POSITION)
840			{
841				if (++linenum >= sc_height)
842					break;
843				pos = position(linenum);
844			}
845		} else
846		{
847			while (pos == NULL_POSITION)
848			{
849				if (--linenum < 0)
850					break;
851				pos = position(linenum);
852			}
853		}
854	}
855	return (pos);
856}
857
858/*
859 * Search a subset of the file, specified by start/end position.
860 */
861	static int
862search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
863	POSITION pos;
864	POSITION endpos;
865	int search_type;
866	int matches;
867	int maxlines;
868	POSITION *plinepos;
869	POSITION *pendpos;
870{
871	char *line;
872	int linenum;
873	char *sp, *ep;
874	int line_match;
875	POSITION linepos, oldpos;
876
877	linenum = find_linenum(pos);
878	oldpos = pos;
879	for (;;)
880	{
881		/*
882		 * Get lines until we find a matching one or until
883		 * we hit end-of-file (or beginning-of-file if we're
884		 * going backwards), or until we hit the end position.
885		 */
886		if (ABORT_SIGS())
887		{
888			/*
889			 * A signal aborts the search.
890			 */
891			return (-1);
892		}
893
894		if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
895		{
896			/*
897			 * Reached end position without a match.
898			 */
899			if (pendpos != NULL)
900				*pendpos = pos;
901			return (matches);
902		}
903		if (maxlines > 0)
904			maxlines--;
905
906		if (search_type & SRCH_FORW)
907		{
908			/*
909			 * Read the next line, and save the
910			 * starting position of that line in linepos.
911			 */
912			linepos = pos;
913			pos = forw_raw_line(pos, &line);
914			if (linenum != 0)
915				linenum++;
916		} else
917		{
918			/*
919			 * Read the previous line and save the
920			 * starting position of that line in linepos.
921			 */
922			pos = back_raw_line(pos, &line);
923			linepos = pos;
924			if (linenum != 0)
925				linenum--;
926		}
927
928		if (pos == NULL_POSITION)
929		{
930			/*
931			 * Reached EOF/BOF without a match.
932			 */
933			if (pendpos != NULL)
934				*pendpos = oldpos;
935			return (matches);
936		}
937
938		/*
939		 * If we're using line numbers, we might as well
940		 * remember the information we have now (the position
941		 * and line number of the current line).
942		 * Don't do it for every line because it slows down
943		 * the search.  Remember the line number only if
944		 * we're "far" from the last place we remembered it.
945		 */
946		if (linenums && abs((int)(pos - oldpos)) > 1024)
947			add_lnum(linenum, pos);
948		oldpos = pos;
949
950		/*
951		 * If it's a caseless search, convert the line to lowercase.
952		 * If we're doing backspace processing, delete backspaces.
953		 */
954		if (is_caseless || bs_mode == BS_SPECIAL)
955		{
956			int ops = 0;
957			if (is_caseless)
958				ops |= CVT_TO_LC;
959			if (bs_mode == BS_SPECIAL)
960				ops |= CVT_BS;
961			if (bs_mode != BS_CONTROL)
962				ops |= CVT_CRLF;
963			cvt_text(line, line, ops);
964		} else if (bs_mode != BS_CONTROL)
965		{
966			cvt_text(line, line, CVT_CRLF);
967		}
968
969		/*
970		 * Test the next line to see if we have a match.
971		 * We are successful if we either want a match and got one,
972		 * or if we want a non-match and got one.
973		 */
974		line_match = match_pattern(line, &sp, &ep, 0);
975		line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
976				((search_type & SRCH_NO_MATCH) && !line_match);
977		if (!line_match)
978			continue;
979		/*
980		 * Got a match.
981		 */
982		if (search_type & SRCH_FIND_ALL)
983		{
984#if HILITE_SEARCH
985			/*
986			 * We are supposed to find all matches in the range.
987			 * Just add the matches in this line to the
988			 * hilite list and keep searching.
989			 */
990			if (line_match)
991				hilite_line(linepos, line, sp, ep);
992#endif
993		} else if (--matches <= 0)
994		{
995			/*
996			 * Found the one match we're looking for.
997			 * Return it.
998			 */
999#if HILITE_SEARCH
1000			if (hilite_search == 1)
1001			{
1002				/*
1003				 * Clear the hilite list and add only
1004				 * the matches in this one line.
1005				 */
1006				clr_hilite();
1007				if (line_match)
1008					hilite_line(linepos, line, sp, ep);
1009			}
1010#endif
1011			if (plinepos != NULL)
1012				*plinepos = linepos;
1013			return (0);
1014		}
1015	}
1016}
1017
1018/*
1019 * Search for the n-th occurrence of a specified pattern,
1020 * either forward or backward.
1021 * Return the number of matches not yet found in this file
1022 * (that is, n minus the number of matches found).
1023 * Return -1 if the search should be aborted.
1024 * Caller may continue the search in another file
1025 * if less than n matches are found in this file.
1026 */
1027	public int
1028search(search_type, pattern, n)
1029	int search_type;
1030	char *pattern;
1031	int n;
1032{
1033	POSITION pos;
1034	int ucase;
1035
1036	if (pattern == NULL || *pattern == '\0')
1037	{
1038		/*
1039		 * A null pattern means use the previously compiled pattern.
1040		 */
1041		if (!prev_pattern())
1042		{
1043			error("No previous regular expression", NULL_PARG);
1044			return (-1);
1045		}
1046		if ((search_type & SRCH_NO_REGEX) !=
1047		    (last_search_type & SRCH_NO_REGEX))
1048		{
1049			error("Please re-enter search pattern", NULL_PARG);
1050			return -1;
1051		}
1052#if HILITE_SEARCH
1053		if (hilite_search == OPT_ON)
1054		{
1055			/*
1056			 * Erase the highlights currently on screen.
1057			 * If the search fails, we'll redisplay them later.
1058			 */
1059			repaint_hilite(0);
1060		}
1061		if (hilite_search == OPT_ONPLUS && hide_hilite)
1062		{
1063			/*
1064			 * Highlight any matches currently on screen,
1065			 * before we actually start the search.
1066			 */
1067			hide_hilite = 0;
1068			hilite_screen();
1069		}
1070		hide_hilite = 0;
1071#endif
1072	} else
1073	{
1074		/*
1075		 * Compile the pattern.
1076		 */
1077		ucase = is_ucase(pattern);
1078		if (caseless == OPT_ONPLUS)
1079			cvt_text(pattern, pattern, CVT_TO_LC);
1080		if (compile_pattern(pattern, search_type) < 0)
1081			return (-1);
1082		/*
1083		 * Ignore case if -I is set OR
1084		 * -i is set AND the pattern is all lowercase.
1085		 */
1086		is_ucase_pattern = ucase;
1087		if (is_ucase_pattern && caseless != OPT_ONPLUS)
1088			is_caseless = 0;
1089		else
1090			is_caseless = caseless;
1091#if HILITE_SEARCH
1092		if (hilite_search)
1093		{
1094			/*
1095			 * Erase the highlights currently on screen.
1096			 * Also permanently delete them from the hilite list.
1097			 */
1098			repaint_hilite(0);
1099			hide_hilite = 0;
1100			clr_hilite();
1101		}
1102		if (hilite_search == OPT_ONPLUS)
1103		{
1104			/*
1105			 * Highlight any matches currently on screen,
1106			 * before we actually start the search.
1107			 */
1108			hilite_screen();
1109		}
1110#endif
1111	}
1112
1113	/*
1114	 * Figure out where to start the search.
1115	 */
1116	pos = search_pos(search_type);
1117	if (pos == NULL_POSITION)
1118	{
1119		/*
1120		 * Can't find anyplace to start searching from.
1121		 */
1122		if (search_type & SRCH_PAST_EOF)
1123			return (n);
1124		/* repaint(); -- why was this here? */
1125		error("Nothing to search", NULL_PARG);
1126		return (-1);
1127	}
1128
1129	n = search_range(pos, NULL_POSITION, search_type, n, -1,
1130			&pos, (POSITION*)NULL);
1131	if (n != 0)
1132	{
1133		/*
1134		 * Search was unsuccessful.
1135		 */
1136#if HILITE_SEARCH
1137		if (hilite_search == OPT_ON && n > 0)
1138			/*
1139			 * Redisplay old hilites.
1140			 */
1141			repaint_hilite(1);
1142#endif
1143		return (n);
1144	}
1145
1146	if (!(search_type & SRCH_NO_MOVE))
1147	{
1148		/*
1149		 * Go to the matching line.
1150		 */
1151		jump_loc(pos, jump_sline);
1152	}
1153
1154#if HILITE_SEARCH
1155	if (hilite_search == OPT_ON)
1156		/*
1157		 * Display new hilites in the matching line.
1158		 */
1159		repaint_hilite(1);
1160#endif
1161	return (0);
1162}
1163
1164
1165#if HILITE_SEARCH
1166/*
1167 * Prepare hilites in a given range of the file.
1168 *
1169 * The pair (prep_startpos,prep_endpos) delimits a contiguous region
1170 * of the file that has been "prepared"; that is, scanned for matches for
1171 * the current search pattern, and hilites have been created for such matches.
1172 * If prep_startpos == NULL_POSITION, the prep region is empty.
1173 * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
1174 * prep_hilite asks that the range (spos,epos) be covered by the prep region.
1175 */
1176	public void
1177prep_hilite(spos, epos, maxlines)
1178	POSITION spos;
1179	POSITION epos;
1180	int maxlines;
1181{
1182	POSITION nprep_startpos = prep_startpos;
1183	POSITION nprep_endpos = prep_endpos;
1184	POSITION new_epos;
1185	POSITION max_epos;
1186	int result;
1187	int i;
1188/*
1189 * Search beyond where we're asked to search, so the prep region covers
1190 * more than we need.  Do one big search instead of a bunch of small ones.
1191 */
1192#define	SEARCH_MORE (3*size_linebuf)
1193
1194	if (!prev_pattern())
1195		return;
1196
1197	/*
1198	 * If we're limited to a max number of lines, figure out the
1199	 * file position we should stop at.
1200	 */
1201	if (maxlines < 0)
1202		max_epos = NULL_POSITION;
1203	else
1204	{
1205		max_epos = spos;
1206		for (i = 0;  i < maxlines;  i++)
1207			max_epos = forw_raw_line(max_epos, (char **)NULL);
1208	}
1209
1210	/*
1211	 * Find two ranges:
1212	 * The range that we need to search (spos,epos); and the range that
1213	 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
1214	 */
1215
1216	if (prep_startpos == NULL_POSITION ||
1217	    (epos != NULL_POSITION && epos < prep_startpos) ||
1218	    spos > prep_endpos)
1219	{
1220		/*
1221		 * New range is not contiguous with old prep region.
1222		 * Discard the old prep region and start a new one.
1223		 */
1224		clr_hilite();
1225		if (epos != NULL_POSITION)
1226			epos += SEARCH_MORE;
1227		nprep_startpos = spos;
1228	} else
1229	{
1230		/*
1231		 * New range partially or completely overlaps old prep region.
1232		 */
1233		if (epos == NULL_POSITION)
1234		{
1235			/*
1236			 * New range goes to end of file.
1237			 */
1238			;
1239		} else if (epos > prep_endpos)
1240		{
1241			/*
1242			 * New range ends after old prep region.
1243			 * Extend prep region to end at end of new range.
1244			 */
1245			epos += SEARCH_MORE;
1246		} else /* (epos <= prep_endpos) */
1247		{
1248			/*
1249			 * New range ends within old prep region.
1250			 * Truncate search to end at start of old prep region.
1251			 */
1252			epos = prep_startpos;
1253		}
1254
1255		if (spos < prep_startpos)
1256		{
1257			/*
1258			 * New range starts before old prep region.
1259			 * Extend old prep region backwards to start at
1260			 * start of new range.
1261			 */
1262			if (spos < SEARCH_MORE)
1263				spos = 0;
1264			else
1265				spos -= SEARCH_MORE;
1266			nprep_startpos = spos;
1267		} else /* (spos >= prep_startpos) */
1268		{
1269			/*
1270			 * New range starts within or after old prep region.
1271			 * Trim search to start at end of old prep region.
1272			 */
1273			spos = prep_endpos;
1274		}
1275	}
1276
1277	if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
1278	    epos > max_epos)
1279		/*
1280		 * Don't go past the max position we're allowed.
1281		 */
1282		epos = max_epos;
1283
1284	if (epos == NULL_POSITION || epos > spos)
1285	{
1286		result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
1287				maxlines, (POSITION*)NULL, &new_epos);
1288		if (result < 0)
1289			return;
1290		if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
1291			nprep_endpos = new_epos;
1292	}
1293	prep_startpos = nprep_startpos;
1294	prep_endpos = nprep_endpos;
1295}
1296#endif
1297
1298/*
1299 * Simple pattern matching function.
1300 * It supports no metacharacters like *, etc.
1301 */
1302	static int
1303match(pattern, buf, pfound, pend)
1304	char *pattern, *buf;
1305	char **pfound, **pend;
1306{
1307	register char *pp, *lp;
1308
1309	for ( ;  *buf != '\0';  buf++)
1310	{
1311		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
1312			if (*pp == '\0' || *lp == '\0')
1313				break;
1314		if (*pp == '\0')
1315		{
1316			if (pfound != NULL)
1317				*pfound = buf;
1318			if (pend != NULL)
1319				*pend = lp;
1320			return (1);
1321		}
1322	}
1323	return (0);
1324}
1325
1326#if HAVE_V8_REGCOMP
1327/*
1328 * This function is called by the V8 regcomp to report
1329 * errors in regular expressions.
1330 */
1331	void
1332regerror(s)
1333	char *s;
1334{
1335	PARG parg;
1336
1337	parg.p_string = s;
1338	error("%s", &parg);
1339}
1340#endif
1341
1342#if !HAVE_STRCHR
1343/*
1344 * strchr is used by regexp.c.
1345 */
1346	char *
1347strchr(s, c)
1348	char *s;
1349	int c;
1350{
1351	for ( ;  *s != '\0';  s++)
1352		if (*s == c)
1353			return (s);
1354	if (c == '\0')
1355		return (s);
1356	return (NULL);
1357}
1358#endif
1359
1360