Upgrade to less-429.
[dragonfly.git] / contrib / less / search.c
1 /*
2  * Copyright (C) 1984-2008  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 #include "charset.h"
19
20 #define MINPOS(a,b)     (((a) < (b)) ? (a) : (b))
21 #define MAXPOS(a,b)     (((a) > (b)) ? (a) : (b))
22
23 #if HAVE_POSIX_REGCOMP
24 #include <regex.h>
25 #ifdef REG_EXTENDED
26 #define REGCOMP_FLAG    REG_EXTENDED
27 #else
28 #define REGCOMP_FLAG    0
29 #endif
30 #endif
31 #if HAVE_PCRE
32 #include <pcre.h>
33 #endif
34 #if HAVE_RE_COMP
35 char *re_comp();
36 int re_exec();
37 #endif
38 #if HAVE_REGCMP
39 char *regcmp();
40 char *regex();
41 extern char *__loc1;
42 #endif
43 #if HAVE_V8_REGCOMP
44 #include "regexp.h"
45 #endif
46
47 static int match();
48
49 extern int sigs;
50 extern int how_search;
51 extern int caseless;
52 extern int linenums;
53 extern int sc_height;
54 extern int jump_sline;
55 extern int bs_mode;
56 extern int ctldisp;
57 extern int status_col;
58 extern void * constant ml_search;
59 extern POSITION start_attnpos;
60 extern POSITION end_attnpos;
61 extern int utf_mode;
62 extern int screen_trashed;
63 #if HILITE_SEARCH
64 extern int hilite_search;
65 extern int size_linebuf;
66 extern int squished;
67 extern int can_goto_line;
68 static int hide_hilite;
69 static int oldbot;
70 static POSITION prep_startpos;
71 static POSITION prep_endpos;
72
73 struct hilite
74 {
75         struct hilite *hl_next;
76         POSITION hl_startpos;
77         POSITION hl_endpos;
78 };
79 static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
80 static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION };
81 #define hl_first        hl_next
82 #endif
83
84 /*
85  * These are the static variables that represent the "remembered"
86  * search pattern.  
87  */
88 #if HAVE_POSIX_REGCOMP
89 #define DEFINE_PATTERN(name)  static regex_t *name = NULL
90 #endif
91 #if HAVE_PCRE
92 #define DEFINE_PATTERN(name)  pcre *name = NULL;
93 #endif
94 #if HAVE_RE_COMP
95 #define DEFINE_PATTERN(name)  int name = 0;
96 #endif
97 #if HAVE_REGCMP
98 #define DEFINE_PATTERN(name)  static char *name = NULL;
99 #endif
100 #if HAVE_V8_REGCOMP
101 #define DEFINE_PATTERN(name)  static struct regexp *name = NULL;
102 #endif
103
104 DEFINE_PATTERN(search_pattern);
105 DEFINE_PATTERN(filter_pattern);
106
107 static int is_caseless;
108 static int is_ucase_pattern;
109 static int last_search_type;
110 static int last_filter_type;
111 static char *last_pattern = NULL;
112
113 #define CVT_TO_LC       01      /* Convert upper-case to lower-case */
114 #define CVT_BS          02      /* Do backspace processing */
115 #define CVT_CRLF        04      /* Remove CR after LF */
116 #define CVT_ANSI        010     /* Remove ANSI escape sequences */
117
118 /*
119  * Get the length of a buffer needed to convert a string.
120  */
121         static int
122 cvt_length(len, ops)
123         int len;
124         int ops;
125 {
126         if (utf_mode)
127                 /*
128                  * Just copying a string in UTF-8 mode can cause it to grow 
129                  * in length.
130                  * Six output bytes for one input byte is the worst case
131                  * (and unfortunately is far more than is needed in any 
132                  * non-pathological situation, so this is very wasteful).
133                  */
134                 len *= 6;
135         return len + 1;
136 }
137
138 /*
139  * Convert text.  Perform the transformations specified by ops.
140  */
141         static void
142 cvt_text(odst, osrc, lenp, ops)
143         char *odst;
144         char *osrc;
145         int *lenp;
146         int ops;
147 {
148         char *dst;
149         char *src;
150         register char *src_end;
151         LWCHAR ch;
152
153         if (lenp != NULL)
154                 src_end = osrc + *lenp;
155         else
156                 src_end = osrc + strlen(osrc);
157
158         for (src = osrc, dst = odst;  src < src_end;  )
159         {
160                 ch = step_char(&src, +1, src_end);
161                 if ((ops & CVT_TO_LC) && IS_UPPER(ch))
162                 {
163                         /* Convert uppercase to lowercase. */
164                         put_wchar(&dst, TO_LOWER(ch));
165                 } else if ((ops & CVT_BS) && ch == '\b' && dst > odst)
166                 {
167                         /* Delete backspace and preceding char. */
168                         do {
169                                 dst--;
170                         } while (dst > odst &&
171                                 !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
172                 } else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
173                 {
174                         /* Skip to end of ANSI escape sequence. */
175                         src++;  /* skip the CSI start char */
176                         while (src < src_end)
177                                 if (!is_ansi_middle(*src++))
178                                         break;
179                 } else 
180                         /* Just copy. */
181                         put_wchar(&dst, ch);
182         }
183         if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
184                 dst--;
185         *dst = '\0';
186         if (lenp != NULL)
187                 *lenp = dst - odst;
188 }
189
190 /*
191  * Determine which conversions to perform.
192  */
193         static int
194 get_cvt_ops()
195 {
196         int ops = 0;
197         if (is_caseless || bs_mode == BS_SPECIAL)
198         {
199                 if (is_caseless) 
200                         ops |= CVT_TO_LC;
201                 if (bs_mode == BS_SPECIAL)
202                         ops |= CVT_BS;
203                 if (bs_mode != BS_CONTROL)
204                         ops |= CVT_CRLF;
205         } else if (bs_mode != BS_CONTROL)
206         {
207                 ops |= CVT_CRLF;
208         }
209         if (ctldisp == OPT_ONPLUS)
210                 ops |= CVT_ANSI;
211         return (ops);
212 }
213
214 /*
215  * Are there any uppercase letters in this string?
216  */
217         static int
218 is_ucase(str)
219         char *str;
220 {
221         char *str_end = str + strlen(str);
222         LWCHAR ch;
223
224         while (str < str_end)
225         {
226                 ch = step_char(&str, +1, str_end);
227                 if (IS_UPPER(ch))
228                         return (1);
229         }
230         return (0);
231 }
232
233 /*
234  * Is there a previous (remembered) search pattern?
235  */
236         static int
237 prev_pattern()
238 {
239         if (last_search_type & SRCH_NO_REGEX)
240                 return (last_pattern != NULL);
241 #if HAVE_POSIX_REGCOMP
242         return (search_pattern != NULL);
243 #endif
244 #if HAVE_PCRE
245         return (search_pattern != NULL);
246 #endif
247 #if HAVE_RE_COMP
248         return (search_pattern != 0);
249 #endif
250 #if HAVE_REGCMP
251         return (search_pattern != NULL);
252 #endif
253 #if HAVE_V8_REGCOMP
254         return (search_pattern != NULL);
255 #endif
256 #if NO_REGEX
257         return (search_pattern != NULL);
258 #endif
259 }
260
261 #if HILITE_SEARCH
262 /*
263  * Repaint the hilites currently displayed on the screen.
264  * Repaint each line which contains highlighted text.
265  * If on==0, force all hilites off.
266  */
267         public void
268 repaint_hilite(on)
269         int on;
270 {
271         int slinenum;
272         POSITION pos;
273         POSITION epos;
274         int save_hide_hilite;
275
276         if (squished)
277                 repaint();
278
279         save_hide_hilite = hide_hilite;
280         if (!on)
281         {
282                 if (hide_hilite)
283                         return;
284                 hide_hilite = 1;
285         }
286
287         if (!can_goto_line)
288         {
289                 repaint();
290                 hide_hilite = save_hide_hilite;
291                 return;
292         }
293
294         for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
295         {
296                 pos = position(slinenum);
297                 if (pos == NULL_POSITION)
298                         continue;
299                 epos = position(slinenum+1);
300 #if 0
301                 /*
302                  * If any character in the line is highlighted, 
303                  * repaint the line.
304                  *
305                  * {{ This doesn't work -- if line is drawn with highlights
306                  * which should be erased (e.g. toggle -i with status column),
307                  * we must redraw the line even if it has no highlights.
308                  * For now, just repaint every line. }}
309                  */
310                 if (is_hilited(pos, epos, 1, NULL))
311 #endif
312                 {
313                         (void) forw_line(pos);
314                         goto_line(slinenum);
315                         put_line();
316                 }
317         }
318         if (!oldbot)
319                 lower_left();
320         hide_hilite = save_hide_hilite;
321 }
322
323 /*
324  * Clear the attn hilite.
325  */
326         public void
327 clear_attn()
328 {
329         int slinenum;
330         POSITION old_start_attnpos;
331         POSITION old_end_attnpos;
332         POSITION pos;
333         POSITION epos;
334         int moved = 0;
335
336         if (start_attnpos == NULL_POSITION)
337                 return;
338         old_start_attnpos = start_attnpos;
339         old_end_attnpos = end_attnpos;
340         start_attnpos = end_attnpos = NULL_POSITION;
341
342         if (!can_goto_line)
343         {
344                 repaint();
345                 return;
346         }
347         if (squished)
348                 repaint();
349
350         for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
351         {
352                 pos = position(slinenum);
353                 if (pos == NULL_POSITION)
354                         continue;
355                 epos = position(slinenum+1);
356                 if (pos < old_end_attnpos &&
357                      (epos == NULL_POSITION || epos > old_start_attnpos))
358                 {
359                         (void) forw_line(pos);
360                         goto_line(slinenum);
361                         put_line();
362                         moved = 1;
363                 }
364         }
365         if (moved)
366                 lower_left();
367 }
368 #endif
369
370 /*
371  * Hide search string highlighting.
372  */
373         public void
374 undo_search()
375 {
376         if (!prev_pattern())
377         {
378                 error("No previous regular expression", NULL_PARG);
379                 return;
380         }
381 #if HILITE_SEARCH
382         hide_hilite = !hide_hilite;
383         repaint_hilite(1);
384 #endif
385 }
386
387 /*
388  * Compile a search pattern, for future use by match_pattern.
389  */
390         static int
391 compile_pattern2(pattern, search_type, comp_pattern)
392         char *pattern;
393         int search_type;
394         void **comp_pattern;
395 {
396         if ((search_type & SRCH_NO_REGEX) == 0)
397         {
398 #if HAVE_POSIX_REGCOMP
399                 regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
400                 regex_t **pcomp = (regex_t **) comp_pattern;
401                 if (regcomp(comp, pattern, REGCOMP_FLAG))
402                 {
403                         free(comp);
404                         error("Invalid pattern", NULL_PARG);
405                         return (-1);
406                 }
407                 if (*pcomp != NULL)
408                         regfree(*pcomp);
409                 *pcomp = comp;
410 #endif
411 #if HAVE_PCRE
412                 pcre *comp;
413                 pcre **pcomp = (pcre **) comp_pattern;
414                 const char *errstring;
415                 int erroffset;
416                 PARG parg;
417                 comp = pcre_compile(pattern, 0,
418                                 &errstring, &erroffset, NULL);
419                 if (comp == NULL)
420                 {
421                         parg.p_string = (char *) errstring;
422                         error("%s", &parg);
423                         return (-1);
424                 }
425                 *pcomp = comp;
426 #endif
427 #if HAVE_RE_COMP
428                 PARG parg;
429                 int *pcomp = (int *) comp_pattern;
430                 if ((parg.p_string = re_comp(pattern)) != NULL)
431                 {
432                         error("%s", &parg);
433                         return (-1);
434                 }
435                 *pcomp = 1;
436 #endif
437 #if HAVE_REGCMP
438                 char *comp;
439                 char **pcomp = (char **) comp_pattern;
440                 if ((comp = regcmp(pattern, 0)) == NULL)
441                 {
442                         error("Invalid pattern", NULL_PARG);
443                         return (-1);
444                 }
445                 if (pcomp != NULL)
446                         free(*pcomp);
447                 *pcomp = comp;
448 #endif
449 #if HAVE_V8_REGCOMP
450                 struct regexp *comp;
451                 struct regexp **pcomp = (struct regexp **) comp_pattern;
452                 if ((comp = regcomp(pattern)) == NULL)
453                 {
454                         /*
455                          * regcomp has already printed an error message 
456                          * via regerror().
457                          */
458                         return (-1);
459                 }
460                 if (*pcomp != NULL)
461                         free(*pcomp);
462                 *pcomp = comp;
463 #endif
464         }
465
466         if (comp_pattern == (void **) &search_pattern)
467         {
468                 if (last_pattern != NULL)
469                         free(last_pattern);
470                 last_pattern = (char *) calloc(1, strlen(pattern)+1);
471                 if (last_pattern != NULL)
472                         strcpy(last_pattern, pattern);
473                 last_search_type = search_type;
474         } else
475         {
476                 last_filter_type = search_type;
477         }
478         return (0);
479 }
480
481 /*
482  * Like compile_pattern2, but convert the pattern to lowercase if necessary.
483  */
484         static int
485 compile_pattern(pattern, search_type, comp_pattern)
486         char *pattern;
487         int search_type;
488         void **comp_pattern;
489 {
490         char *cvt_pattern;
491         int result;
492
493         if (caseless != OPT_ONPLUS)
494                 cvt_pattern = pattern;
495         else
496         {
497                 cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
498                 cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC);
499         }
500         result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
501         if (cvt_pattern != pattern)
502                 free(cvt_pattern);
503         return (result);
504 }
505
506 /*
507  * Forget that we have a compiled pattern.
508  */
509         static void
510 uncompile_pattern(pattern)
511         void **pattern;
512 {
513 #if HAVE_POSIX_REGCOMP
514         regex_t **pcomp = (regex_t **) pattern;
515         if (*pcomp != NULL)
516                 regfree(*pcomp);
517         *pcomp = NULL;
518 #endif
519 #if HAVE_PCRE
520         pcre **pcomp = (pcre **) pattern;
521         if (*pcomp != NULL)
522                 pcre_free(*pcomp);
523         *pcomp = NULL;
524 #endif
525 #if HAVE_RE_COMP
526         int *pcomp = (int *) pattern;
527         *pcomp = 0;
528 #endif
529 #if HAVE_REGCMP
530         char **pcomp = (char **) pattern;
531         if (*pcomp != NULL)
532                 free(*pcomp);
533         *pcomp = NULL;
534 #endif
535 #if HAVE_V8_REGCOMP
536         struct regexp **pcomp = (struct regexp **) pattern;
537         if (*pcomp != NULL)
538                 free(*pcomp);
539         *pcomp = NULL;
540 #endif
541 }
542
543         static void
544 uncompile_search_pattern()
545 {
546         uncompile_pattern(&search_pattern);
547         last_pattern = NULL;
548 }
549
550         static void
551 uncompile_filter_pattern()
552 {
553         uncompile_pattern(&filter_pattern);
554 }
555
556 /*
557  * Is a compiled pattern null?
558  */
559         static int
560 is_null_pattern(pattern)
561         void *pattern;
562 {
563 #if HAVE_POSIX_REGCOMP
564         return (pattern == NULL);
565 #endif
566 #if HAVE_PCRE
567         return (pattern == NULL);
568 #endif
569 #if HAVE_RE_COMP
570         return (pattern == 0);
571 #endif
572 #if HAVE_REGCMP
573         return (pattern == NULL);
574 #endif
575 #if HAVE_V8_REGCOMP
576         return (pattern == NULL);
577 #endif
578 }
579
580 /*
581  * Perform a pattern match with the previously compiled pattern.
582  * Set sp and ep to the start and end of the matched string.
583  */
584         static int
585 match_pattern(pattern, line, line_len, sp, ep, notbol, search_type)
586         void *pattern;
587         char *line;
588         int line_len;
589         char **sp;
590         char **ep;
591         int notbol;
592         int search_type;
593 {
594         int matched;
595 #if HAVE_POSIX_REGCOMP
596         regex_t *spattern = (regex_t *) pattern;
597 #endif
598 #if HAVE_PCRE
599         pcre *spattern = (pcre *) pattern;
600 #endif
601 #if HAVE_RE_COMP
602         int spattern = (int) pattern;
603 #endif
604 #if HAVE_REGCMP
605         char *spattern = (char *) pattern;
606 #endif
607 #if HAVE_V8_REGCOMP
608         struct regexp *spattern = (struct regexp *) pattern;
609 #endif
610
611         if (search_type & SRCH_NO_REGEX)
612                 return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
613
614 #if HAVE_POSIX_REGCOMP
615         {
616                 regmatch_t rm;
617                 int flags = (notbol) ? REG_NOTBOL : 0;
618                 matched = !regexec(spattern, line, 1, &rm, flags);
619                 if (matched)
620                 {
621 #ifndef __WATCOMC__
622                         *sp = line + rm.rm_so;
623                         *ep = line + rm.rm_eo;
624 #else
625                         *sp = rm.rm_sp;
626                         *ep = rm.rm_ep;
627 #endif
628                 }
629         }
630 #endif
631 #if HAVE_PCRE
632         {
633                 int flags = (notbol) ? PCRE_NOTBOL : 0;
634                 int ovector[3];
635                 matched = pcre_exec(spattern, NULL, line, line_len,
636                         0, flags, ovector, 3) >= 0;
637                 if (matched)
638                 {
639                         *sp = line + ovector[0];
640                         *ep = line + ovector[1];
641                 }
642         }
643 #endif
644 #if HAVE_RE_COMP
645         matched = (re_exec(line) == 1);
646         /*
647          * re_exec doesn't seem to provide a way to get the matched string.
648          */
649         *sp = *ep = NULL;
650 #endif
651 #if HAVE_REGCMP
652         *ep = regex(spattern, line);
653         matched = (*ep != NULL);
654         if (matched)
655                 *sp = __loc1;
656 #endif
657 #if HAVE_V8_REGCOMP
658 #if HAVE_REGEXEC2
659         matched = regexec2(spattern, line, notbol);
660 #else
661         matched = regexec(spattern, line);
662 #endif
663         if (matched)
664         {
665                 *sp = spattern->startp[0];
666                 *ep = spattern->endp[0];
667         }
668 #endif
669 #if NO_REGEX
670         matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
671 #endif
672         matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
673                         ((search_type & SRCH_NO_MATCH) && !matched);
674         return (matched);
675 }
676
677 #if HILITE_SEARCH
678 /*
679  * Clear the hilite list.
680  */
681         public void
682 clr_hlist(anchor)
683         struct hilite *anchor;
684 {
685         struct hilite *hl;
686         struct hilite *nexthl;
687
688         for (hl = anchor->hl_first;  hl != NULL;  hl = nexthl)
689         {
690                 nexthl = hl->hl_next;
691                 free((void*)hl);
692         }
693         anchor->hl_first = NULL;
694         prep_startpos = prep_endpos = NULL_POSITION;
695 }
696
697         public void
698 clr_hilite()
699 {
700         clr_hlist(&hilite_anchor);
701 }
702
703         public void
704 clr_filter()
705 {
706         clr_hlist(&filter_anchor);
707 }
708
709 /*
710  * Should any characters in a specified range be highlighted?
711  */
712         static int
713 is_hilited_range(pos, epos)
714         POSITION pos;
715         POSITION epos;
716 {
717         struct hilite *hl;
718
719         /*
720          * Look at each highlight and see if any part of it falls in the range.
721          */
722         for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
723         {
724                 if (hl->hl_endpos > pos &&
725                     (epos == NULL_POSITION || epos > hl->hl_startpos))
726                         return (1);
727         }
728         return (0);
729 }
730
731 /* 
732  * Is a line "filtered" -- that is, should it be hidden?
733  */
734         public int
735 is_filtered(pos)
736         POSITION pos;
737 {
738         struct hilite *hl;
739
740         if (ch_getflags() & CH_HELPFILE)
741                 return (0);
742
743         /*
744          * Look at each filter and see if the start position
745          * equals the start position of the line.
746          */
747         for (hl = filter_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
748         {
749                 if (hl->hl_startpos == pos)
750                         return (1);
751         }
752         return (0);
753 }
754
755 /*
756  * Should any characters in a specified range be highlighted?
757  * If nohide is nonzero, don't consider hide_hilite.
758  */
759         public int
760 is_hilited(pos, epos, nohide, p_matches)
761         POSITION pos;
762         POSITION epos;
763         int nohide;
764         int *p_matches;
765 {
766         int match;
767
768         if (p_matches != NULL)
769                 *p_matches = 0;
770
771         if (!status_col &&
772             start_attnpos != NULL_POSITION && 
773             pos < end_attnpos &&
774              (epos == NULL_POSITION || epos > start_attnpos))
775                 /*
776                  * The attn line overlaps this range.
777                  */
778                 return (1);
779
780         match = is_hilited_range(pos, epos);
781         if (!match)
782                 return (0);
783
784         if (p_matches != NULL)
785                 /*
786                  * Report matches, even if we're hiding highlights.
787                  */
788                 *p_matches = 1;
789
790         if (hilite_search == 0)
791                 /*
792                  * Not doing highlighting.
793                  */
794                 return (0);
795
796         if (!nohide && hide_hilite)
797                 /*
798                  * Highlighting is hidden.
799                  */
800                 return (0);
801
802         return (1);
803 }
804
805 /*
806  * Add a new hilite to a hilite list.
807  */
808         static void
809 add_hilite(anchor, hl)
810         struct hilite *anchor;
811         struct hilite *hl;
812 {
813         struct hilite *ihl;
814
815         /*
816          * Hilites are sorted in the list; find where new one belongs.
817          * Insert new one after ihl.
818          */
819         for (ihl = anchor;  ihl->hl_next != NULL;  ihl = ihl->hl_next)
820         {
821                 if (ihl->hl_next->hl_startpos > hl->hl_startpos)
822                         break;
823         }
824
825         /*
826          * Truncate hilite so it doesn't overlap any existing ones
827          * above and below it.
828          */
829         if (ihl != anchor)
830                 hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
831         if (ihl->hl_next != NULL)
832                 hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
833         if (hl->hl_startpos >= hl->hl_endpos)
834         {
835                 /*
836                  * Hilite was truncated out of existence.
837                  */
838                 free(hl);
839                 return;
840         }
841         hl->hl_next = ihl->hl_next;
842         ihl->hl_next = hl;
843 }
844
845 /*
846  * Adjust hl_startpos & hl_endpos to account for processing by cvt_text.
847  */
848         static void
849 adj_hilite(anchor, linepos, cvt_ops)
850         struct hilite *anchor;
851         POSITION linepos;
852         int cvt_ops;
853 {
854         char *line;
855         char *oline;
856         int line_len;
857         char *line_end;
858         struct hilite *hl;
859         int checkstart;
860         POSITION opos;
861         POSITION npos;
862         POSITION hl_opos;
863         POSITION hl_npos;
864         LWCHAR ch;
865         int ncwidth;
866
867         /*
868          * The line was already scanned and hilites were added (in hilite_line).
869          * But it was assumed that each char position in the line 
870          * correponds to one char position in the file.
871          * This may not be true if cvt_text modified the line.
872          * Get the raw line again.  Look at each character.
873          */
874         (void) forw_raw_line(linepos, &line, &line_len);
875         line_end = line + line_len;
876         opos = npos = linepos;
877         hl = anchor->hl_first;
878     if (hl == NULL)
879         return;
880     hl_opos = hl_npos = hl->hl_startpos;
881         checkstart = TRUE;
882
883         while (hl != NULL && line < line_end)
884         {
885                 /*
886                  * See if we need to adjust the current hl_startpos or 
887                  * hl_endpos.  After adjusting startpos[i], move to endpos[i].
888                  * After adjusting endpos[i], move to startpos[i+1].
889                  * The hilite list must be sorted thus: 
890                  * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
891                  */
892                 oline = line;
893                 ch = step_char(&line, +1, line_end);
894                 ncwidth = line - oline;
895                 npos += ncwidth;
896
897                 /* Figure out how this char was processed by cvt_text. */
898                 if ((cvt_ops & CVT_BS) && ch == '\b')
899                 {
900                         /* Skip the backspace and the following char. */
901                         oline = line;
902                         ch = step_char(&line, +1, line_end);
903                         ncwidth = line - oline;
904                         npos += ncwidth;
905                 } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch))
906                 {
907                         /* Converted uppercase to lower.
908                          * Note that this may have changed the number of bytes 
909                          * that the character occupies. */
910                         char dbuf[6];
911                         char *dst = dbuf;
912                         put_wchar(&dst, TO_LOWER(ch));
913                         opos += dst - dbuf;
914                 } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch))
915                 {
916                         /* Skip to end of ANSI escape sequence. */
917                         line++;  /* skip the CSI start char */
918                         npos++;
919                         while (line < line_end)
920                         {
921                                 npos++;
922                                 if (!is_ansi_middle(*line++))
923                                         break;
924                         }
925                 } else 
926                 {
927                         /* Ordinary unprocessed character. */
928                         opos += ncwidth;
929                 }
930
931         if (opos == hl_opos) {
932             /* Adjust highlight position. */
933             hl_npos = npos;
934         }
935         if (opos > hl_opos)
936         {
937             /*
938              * We've moved past the highlight position; store the
939              * adjusted highlight position and move to the next highlight.
940              */
941             if (checkstart)
942             {
943                 hl->hl_startpos = hl_npos;
944                 hl_opos = hl->hl_endpos;
945                 checkstart = FALSE;
946             } else
947             {
948                 hl->hl_endpos = hl_npos;
949                 hl = hl->hl_next;
950                 if (hl != NULL)
951                     hl_opos = hl->hl_startpos;
952                 checkstart = TRUE;
953             }
954             hl_npos = npos;
955         }
956         }
957 }
958
959 /*
960  * Make a hilite for each string in a physical line which matches 
961  * the current pattern.
962  * sp,ep delimit the first match already found.
963  */
964         static void
965 hilite_line(linepos, line, line_len, sp, ep, cvt_ops)
966         POSITION linepos;
967         char *line;
968         int line_len;
969         char *sp;
970         char *ep;
971         int cvt_ops;
972 {
973         char *searchp;
974         char *line_end = line + line_len;
975         struct hilite *hl;
976         struct hilite hilites;
977
978         if (sp == NULL || ep == NULL)
979                 return;
980         /*
981          * sp and ep delimit the first match in the line.
982          * Mark the corresponding file positions, then
983          * look for further matches and mark them.
984          * {{ This technique, of calling match_pattern on subsequent
985          *    substrings of the line, may mark more than is correct
986          *    if the pattern starts with "^".  This bug is fixed
987          *    for those regex functions that accept a notbol parameter
988          *    (currently POSIX, PCRE and V8-with-regexec2). }}
989          */
990         searchp = line;
991         /*
992          * Put the hilites into a temporary list until they're adjusted.
993          */
994         hilites.hl_first = NULL;
995         do {
996                 if (ep > sp)
997                 {
998                         /*
999                          * Assume that each char position in the "line"
1000                          * buffer corresponds to one char position in the file.
1001                          * This is not quite true; we need to adjust later.
1002                          */
1003                         hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
1004                         hl->hl_startpos = linepos + (sp-line);
1005                         hl->hl_endpos = linepos + (ep-line);
1006                         add_hilite(&hilites, hl);
1007                 }
1008                 /*
1009                  * If we matched more than zero characters,
1010                  * move to the first char after the string we matched.
1011                  * If we matched zero, just move to the next char.
1012                  */
1013                 if (ep > searchp)
1014                         searchp = ep;
1015                 else if (searchp != line_end)
1016                         searchp++;
1017                 else /* end of line */
1018                         break;
1019         } while (match_pattern(search_pattern, searchp, line_end - searchp, &sp, &ep, 1, last_search_type));
1020
1021         /*
1022          * If there were backspaces in the original line, they
1023          * were removed, and hl_startpos/hl_endpos are not correct.
1024          * {{ This is very ugly. }}
1025          */
1026         adj_hilite(&hilites, linepos, cvt_ops);
1027
1028         /*
1029          * Now put the hilites into the real list.
1030          */
1031         while ((hl = hilites.hl_next) != NULL)
1032         {
1033                 hilites.hl_next = hl->hl_next;
1034                 add_hilite(&hilite_anchor, hl);
1035         }
1036 }
1037 #endif
1038
1039 /*
1040  * Change the caseless-ness of searches.  
1041  * Updates the internal search state to reflect a change in the -i flag.
1042  */
1043         public void
1044 chg_caseless()
1045 {
1046         if (!is_ucase_pattern)
1047                 /*
1048                  * Pattern did not have uppercase.
1049                  * Just set the search caselessness to the global caselessness.
1050                  */
1051                 is_caseless = caseless;
1052         else
1053                 /*
1054                  * Pattern did have uppercase.
1055                  * Discard the pattern; we can't change search caselessness now.
1056                  */
1057                 uncompile_search_pattern();
1058 }
1059
1060 #if HILITE_SEARCH
1061 /*
1062  * Find matching text which is currently on screen and highlight it.
1063  */
1064         static void
1065 hilite_screen()
1066 {
1067         struct scrpos scrpos;
1068
1069         get_scrpos(&scrpos);
1070         if (scrpos.pos == NULL_POSITION)
1071                 return;
1072         prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
1073         repaint_hilite(1);
1074 }
1075
1076 /*
1077  * Change highlighting parameters.
1078  */
1079         public void
1080 chg_hilite()
1081 {
1082         /*
1083          * Erase any highlights currently on screen.
1084          */
1085         clr_hilite();
1086         hide_hilite = 0;
1087
1088         if (hilite_search == OPT_ONPLUS)
1089                 /*
1090                  * Display highlights.
1091                  */
1092                 hilite_screen();
1093 }
1094 #endif
1095
1096 /*
1097  * Figure out where to start a search.
1098  */
1099         static POSITION
1100 search_pos(search_type)
1101         int search_type;
1102 {
1103         POSITION pos;
1104         int linenum;
1105
1106         if (empty_screen())
1107         {
1108                 /*
1109                  * Start at the beginning (or end) of the file.
1110                  * The empty_screen() case is mainly for 
1111                  * command line initiated searches;
1112                  * for example, "+/xyz" on the command line.
1113                  * Also for multi-file (SRCH_PAST_EOF) searches.
1114                  */
1115                 if (search_type & SRCH_FORW)
1116                 {
1117                         return (ch_zero());
1118                 } else
1119                 {
1120                         pos = ch_length();
1121                         if (pos == NULL_POSITION)
1122                         {
1123                                 (void) ch_end_seek();
1124                                 pos = ch_length();
1125                         }
1126                         return (pos);
1127                 }
1128         }
1129         if (how_search)
1130         {
1131                 /*
1132                  * Search does not include current screen.
1133                  */
1134                 if (search_type & SRCH_FORW)
1135                         linenum = BOTTOM_PLUS_ONE;
1136                 else
1137                         linenum = TOP;
1138                 pos = position(linenum);
1139         } else
1140         {
1141                 /*
1142                  * Search includes current screen.
1143                  * It starts at the jump target (if searching backwards),
1144                  * or at the jump target plus one (if forwards).
1145                  */
1146                 linenum = adjsline(jump_sline);
1147                 pos = position(linenum);
1148                 if (search_type & SRCH_FORW)
1149                 {
1150                         pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
1151                         while (pos == NULL_POSITION)
1152                         {
1153                                 if (++linenum >= sc_height)
1154                                         break;
1155                                 pos = position(linenum);
1156                         }
1157                 } else 
1158                 {
1159                         while (pos == NULL_POSITION)
1160                         {
1161                                 if (--linenum < 0)
1162                                         break;
1163                                 pos = position(linenum);
1164                         }
1165                 }
1166         }
1167         return (pos);
1168 }
1169
1170 /*
1171  * Search a subset of the file, specified by start/end position.
1172  */
1173         static int
1174 search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
1175         POSITION pos;
1176         POSITION endpos;
1177         int search_type;
1178         int matches;
1179         int maxlines;
1180         POSITION *plinepos;
1181         POSITION *pendpos;
1182 {
1183         char *line;
1184         char *cline;
1185         int line_len;
1186         LINENUM linenum;
1187         char *sp, *ep;
1188         int line_match;
1189         int cvt_ops;
1190         POSITION linepos, oldpos;
1191
1192         linenum = find_linenum(pos);
1193         oldpos = pos;
1194         for (;;)
1195         {
1196                 /*
1197                  * Get lines until we find a matching one or until
1198                  * we hit end-of-file (or beginning-of-file if we're 
1199                  * going backwards), or until we hit the end position.
1200                  */
1201                 if (ABORT_SIGS())
1202                 {
1203                         /*
1204                          * A signal aborts the search.
1205                          */
1206                         return (-1);
1207                 }
1208
1209                 if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
1210                 {
1211                         /*
1212                          * Reached end position without a match.
1213                          */
1214                         if (pendpos != NULL)
1215                                 *pendpos = pos;
1216                         return (matches);
1217                 }
1218                 if (maxlines > 0)
1219                         maxlines--;
1220
1221                 if (search_type & SRCH_FORW)
1222                 {
1223                         /*
1224                          * Read the next line, and save the 
1225                          * starting position of that line in linepos.
1226                          */
1227                         linepos = pos;
1228                         pos = forw_raw_line(pos, &line, &line_len);
1229                         if (linenum != 0)
1230                                 linenum++;
1231                 } else
1232                 {
1233                         /*
1234                          * Read the previous line and save the
1235                          * starting position of that line in linepos.
1236                          */
1237                         pos = back_raw_line(pos, &line, &line_len);
1238                         linepos = pos;
1239                         if (linenum != 0)
1240                                 linenum--;
1241                 }
1242
1243                 if (pos == NULL_POSITION)
1244                 {
1245                         /*
1246                          * Reached EOF/BOF without a match.
1247                          */
1248                         if (pendpos != NULL)
1249                                 *pendpos = oldpos;
1250                         return (matches);
1251                 }
1252
1253                 /*
1254                  * If we're using line numbers, we might as well
1255                  * remember the information we have now (the position
1256                  * and line number of the current line).
1257                  * Don't do it for every line because it slows down
1258                  * the search.  Remember the line number only if
1259                  * we're "far" from the last place we remembered it.
1260                  */
1261                 if (linenums && abs((int)(pos - oldpos)) > 1024)
1262                         add_lnum(linenum, pos);
1263                 oldpos = pos;
1264
1265                 if (is_filtered(linepos))
1266                         continue;
1267
1268                 /*
1269                  * If it's a caseless search, convert the line to lowercase.
1270                  * If we're doing backspace processing, delete backspaces.
1271                  */
1272                 cvt_ops = get_cvt_ops();
1273                 cline = calloc(1, cvt_length(line_len, cvt_ops));
1274                 cvt_text(cline, line, &line_len, cvt_ops);
1275
1276 #if HILITE_SEARCH
1277                 /*
1278                  * Check to see if the line matches the filter pattern.
1279                  * If so, add an entry to the filter list.
1280                  */
1281                 if ((search_type & SRCH_FIND_ALL) &&
1282                         !is_null_pattern(filter_pattern))
1283                 {
1284                         int line_filter = match_pattern(filter_pattern, 
1285                                 cline, line_len, &sp, &ep, 0, last_filter_type);
1286                         if (line_filter)
1287                         {
1288                                 struct hilite *hl = (struct hilite *)
1289                                         ecalloc(1, sizeof(struct hilite));
1290                                 hl->hl_startpos = linepos;
1291                                 hl->hl_endpos = pos;
1292                                 add_hilite(&filter_anchor, hl);
1293                         }
1294                 }
1295 #endif
1296
1297                 /*
1298                  * Test the next line to see if we have a match.
1299                  * We are successful if we either want a match and got one,
1300                  * or if we want a non-match and got one.
1301                  */
1302                 if (!is_null_pattern(search_pattern))
1303                 {
1304                         line_match = match_pattern(search_pattern, 
1305                                 cline, line_len, &sp, &ep, 0, search_type);
1306                         if (line_match)
1307                         {
1308                                 /*
1309                                  * Got a match.
1310                                  */
1311                                 if (search_type & SRCH_FIND_ALL)
1312                                 {
1313 #if HILITE_SEARCH
1314                                         /*
1315                                          * We are supposed to find all matches in the range.
1316                                          * Just add the matches in this line to the 
1317                                          * hilite list and keep searching.
1318                                          */
1319                                         hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
1320 #endif
1321                                 } else if (--matches <= 0)
1322                                 {
1323                                         /*
1324                                          * Found the one match we're looking for.
1325                                          * Return it.
1326                                          */
1327 #if HILITE_SEARCH
1328                                         if (hilite_search == OPT_ON)
1329                                         {
1330                                                 /*
1331                                                  * Clear the hilite list and add only
1332                                                  * the matches in this one line.
1333                                                  */
1334                                                 clr_hilite();
1335                                                 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
1336                                         }
1337 #endif
1338                                         free(cline);
1339                                         if (plinepos != NULL)
1340                                                 *plinepos = linepos;
1341                                         return (0);
1342                                 }
1343                         }
1344                 }
1345                 free(cline);
1346         }
1347 }
1348
1349 /*
1350  * search for a pattern in history. If found, compile that pattern.
1351  */
1352         static int 
1353 hist_pattern(search_type) 
1354         int search_type;
1355 {
1356 #if CMD_HISTORY
1357         char *pattern;
1358
1359         set_mlist(ml_search, 0);
1360         pattern = cmd_lastpattern();
1361         if (pattern == NULL)
1362                 return (0);
1363
1364         if (compile_pattern(pattern, search_type, &search_pattern) < 0)
1365                 return (0);
1366
1367         is_ucase_pattern = is_ucase(pattern);
1368         if (is_ucase_pattern && caseless != OPT_ONPLUS)
1369                 is_caseless = 0;
1370         else
1371                 is_caseless = caseless;
1372
1373 #if HILITE_SEARCH
1374         if (hilite_search == OPT_ONPLUS && !hide_hilite)
1375                 hilite_screen();
1376 #endif
1377
1378         return (1);
1379 #else /* CMD_HISTORY */
1380         return (0);
1381 #endif /* CMD_HISTORY */
1382 }
1383
1384 /*
1385  * Search for the n-th occurrence of a specified pattern, 
1386  * either forward or backward.
1387  * Return the number of matches not yet found in this file
1388  * (that is, n minus the number of matches found).
1389  * Return -1 if the search should be aborted.
1390  * Caller may continue the search in another file 
1391  * if less than n matches are found in this file.
1392  */
1393         public int
1394 search(search_type, pattern, n)
1395         int search_type;
1396         char *pattern;
1397         int n;
1398 {
1399         POSITION pos;
1400
1401         if (pattern == NULL || *pattern == '\0')
1402         {
1403                 /*
1404                  * A null pattern means use the previously compiled pattern.
1405                  */
1406                 if (!prev_pattern() && !hist_pattern(search_type))
1407                 {
1408                         error("No previous regular expression", NULL_PARG);
1409                         return (-1);
1410                 }
1411                 if ((search_type & SRCH_NO_REGEX) != 
1412                     (last_search_type & SRCH_NO_REGEX))
1413                 {
1414                         error("Please re-enter search pattern", NULL_PARG);
1415                         return -1;
1416                 }
1417 #if HILITE_SEARCH
1418                 if (hilite_search == OPT_ON)
1419                 {
1420                         /*
1421                          * Erase the highlights currently on screen.
1422                          * If the search fails, we'll redisplay them later.
1423                          */
1424                         repaint_hilite(0);
1425                 }
1426                 if (hilite_search == OPT_ONPLUS && hide_hilite)
1427                 {
1428                         /*
1429                          * Highlight any matches currently on screen,
1430                          * before we actually start the search.
1431                          */
1432                         hide_hilite = 0;
1433                         hilite_screen();
1434                 }
1435                 hide_hilite = 0;
1436 #endif
1437         } else
1438         {
1439                 /*
1440                  * Compile the pattern.
1441                  */
1442                 if (compile_pattern(pattern, search_type, &search_pattern) < 0)
1443                         return (-1);
1444                 /*
1445                  * Ignore case if -I is set OR
1446                  * -i is set AND the pattern is all lowercase.
1447                  */
1448                 is_ucase_pattern = is_ucase(pattern);
1449                 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1450                         is_caseless = 0;
1451                 else
1452                         is_caseless = caseless;
1453 #if HILITE_SEARCH
1454                 if (hilite_search)
1455                 {
1456                         /*
1457                          * Erase the highlights currently on screen.
1458                          * Also permanently delete them from the hilite list.
1459                          */
1460                         repaint_hilite(0);
1461                         hide_hilite = 0;
1462                         clr_hilite();
1463                 }
1464                 if (hilite_search == OPT_ONPLUS)
1465                 {
1466                         /*
1467                          * Highlight any matches currently on screen,
1468                          * before we actually start the search.
1469                          */
1470                         hilite_screen();
1471                 }
1472 #endif
1473         }
1474
1475         /*
1476          * Figure out where to start the search.
1477          */
1478         pos = search_pos(search_type);
1479         if (pos == NULL_POSITION)
1480         {
1481                 /*
1482                  * Can't find anyplace to start searching from.
1483                  */
1484                 if (search_type & SRCH_PAST_EOF)
1485                         return (n);
1486                 /* repaint(); -- why was this here? */
1487                 error("Nothing to search", NULL_PARG);
1488                 return (-1);
1489         }
1490
1491         n = search_range(pos, NULL_POSITION, search_type, n, -1,
1492                         &pos, (POSITION*)NULL);
1493         if (n != 0)
1494         {
1495                 /*
1496                  * Search was unsuccessful.
1497                  */
1498 #if HILITE_SEARCH
1499                 if (hilite_search == OPT_ON && n > 0)
1500                         /*
1501                          * Redisplay old hilites.
1502                          */
1503                         repaint_hilite(1);
1504 #endif
1505                 return (n);
1506         }
1507
1508         if (!(search_type & SRCH_NO_MOVE))
1509         {
1510                 /*
1511                  * Go to the matching line.
1512                  */
1513                 jump_loc(pos, jump_sline);
1514         }
1515
1516 #if HILITE_SEARCH
1517         if (hilite_search == OPT_ON)
1518                 /*
1519                  * Display new hilites in the matching line.
1520                  */
1521                 repaint_hilite(1);
1522 #endif
1523         return (0);
1524 }
1525
1526
1527 #if HILITE_SEARCH
1528 /*
1529  * Prepare hilites in a given range of the file.
1530  *
1531  * The pair (prep_startpos,prep_endpos) delimits a contiguous region
1532  * of the file that has been "prepared"; that is, scanned for matches for
1533  * the current search pattern, and hilites have been created for such matches.
1534  * If prep_startpos == NULL_POSITION, the prep region is empty.
1535  * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
1536  * prep_hilite asks that the range (spos,epos) be covered by the prep region.
1537  */
1538         public void
1539 prep_hilite(spos, epos, maxlines)
1540         POSITION spos;
1541         POSITION epos;
1542         int maxlines;
1543 {
1544         POSITION nprep_startpos = prep_startpos;
1545         POSITION nprep_endpos = prep_endpos;
1546         POSITION new_epos;
1547         POSITION max_epos;
1548         int result;
1549         int i;
1550 /*
1551  * Search beyond where we're asked to search, so the prep region covers
1552  * more than we need.  Do one big search instead of a bunch of small ones.
1553  */
1554 #define SEARCH_MORE (3*size_linebuf)
1555
1556         if (!prev_pattern() && !is_filtering())
1557                 return;
1558
1559         /*
1560          * If we're limited to a max number of lines, figure out the
1561          * file position we should stop at.
1562          */
1563         if (maxlines < 0)
1564                 max_epos = NULL_POSITION;
1565         else
1566         {
1567                 max_epos = spos;
1568                 for (i = 0;  i < maxlines;  i++)
1569                         max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
1570         }
1571
1572         /*
1573          * Find two ranges:
1574          * The range that we need to search (spos,epos); and the range that
1575          * the "prep" region will then cover (nprep_startpos,nprep_endpos).
1576          */
1577
1578         if (prep_startpos == NULL_POSITION ||
1579             (epos != NULL_POSITION && epos < prep_startpos) ||
1580             spos > prep_endpos)
1581         {
1582                 /*
1583                  * New range is not contiguous with old prep region.
1584                  * Discard the old prep region and start a new one.
1585                  */
1586                 clr_hilite();
1587                 clr_filter();
1588                 if (epos != NULL_POSITION)
1589                         epos += SEARCH_MORE;
1590                 nprep_startpos = spos;
1591         } else
1592         {
1593                 /*
1594                  * New range partially or completely overlaps old prep region.
1595                  */
1596                 if (epos == NULL_POSITION)
1597                 {
1598                         /*
1599                          * New range goes to end of file.
1600                          */
1601                         ;
1602                 } else if (epos > prep_endpos)
1603                 {
1604                         /*
1605                          * New range ends after old prep region.
1606                          * Extend prep region to end at end of new range.
1607                          */
1608                         epos += SEARCH_MORE;
1609                 } else /* (epos <= prep_endpos) */
1610                 {
1611                         /*
1612                          * New range ends within old prep region.
1613                          * Truncate search to end at start of old prep region.
1614                          */
1615                         epos = prep_startpos;
1616                 }
1617
1618                 if (spos < prep_startpos)
1619                 {
1620                         /*
1621                          * New range starts before old prep region.
1622                          * Extend old prep region backwards to start at 
1623                          * start of new range.
1624                          */
1625                         if (spos < SEARCH_MORE)
1626                                 spos = 0;
1627                         else
1628                                 spos -= SEARCH_MORE;
1629                         nprep_startpos = spos;
1630                 } else /* (spos >= prep_startpos) */
1631                 {
1632                         /*
1633                          * New range starts within or after old prep region.
1634                          * Trim search to start at end of old prep region.
1635                          */
1636                         spos = prep_endpos;
1637                 }
1638         }
1639
1640         if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
1641             epos > max_epos)
1642                 /*
1643                  * Don't go past the max position we're allowed.
1644                  */
1645                 epos = max_epos;
1646
1647         if (epos == NULL_POSITION || epos > spos)
1648         {
1649                 result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
1650                                 maxlines, (POSITION*)NULL, &new_epos);
1651                 if (result < 0)
1652                         return;
1653                 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
1654                         nprep_endpos = new_epos;
1655         }
1656         prep_startpos = nprep_startpos;
1657         prep_endpos = nprep_endpos;
1658 }
1659
1660 /*
1661  * Set the pattern to be used for line filtering.
1662  */
1663         public void
1664 set_filter_pattern(pattern, search_type)
1665         char *pattern;
1666         int search_type;
1667 {
1668         clr_filter();
1669         if (pattern == NULL || *pattern == '\0')
1670                 uncompile_filter_pattern();
1671         else
1672                 compile_pattern(pattern, search_type, &filter_pattern);
1673         screen_trashed = 1;
1674 }
1675
1676 /*
1677  * Is there a line filter in effect?
1678  */
1679         public int
1680 is_filtering()
1681 {
1682         if (ch_getflags() & CH_HELPFILE)
1683                 return (0);
1684         return !is_null_pattern(filter_pattern);
1685 }
1686 #endif
1687
1688 /*
1689  * Simple pattern matching function.
1690  * It supports no metacharacters like *, etc.
1691  */
1692         static int
1693 match(pattern, pattern_len, buf, buf_len, pfound, pend)
1694         char *pattern;
1695         int pattern_len;
1696         char *buf;
1697         int buf_len;
1698         char **pfound, **pend;
1699 {
1700         register char *pp, *lp;
1701         register char *pattern_end = pattern + pattern_len;
1702         register char *buf_end = buf + buf_len;
1703
1704         for ( ;  buf < buf_end;  buf++)
1705         {
1706                 for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
1707                         if (pp == pattern_end || lp == buf_end)
1708                                 break;
1709                 if (pp == pattern_end)
1710                 {
1711                         if (pfound != NULL)
1712                                 *pfound = buf;
1713                         if (pend != NULL)
1714                                 *pend = lp;
1715                         return (1);
1716                 }
1717         }
1718         return (0);
1719 }
1720
1721 #if HAVE_V8_REGCOMP
1722 /*
1723  * This function is called by the V8 regcomp to report 
1724  * errors in regular expressions.
1725  */
1726         void 
1727 regerror(s) 
1728         char *s; 
1729 {
1730         PARG parg;
1731
1732         parg.p_string = s;
1733         error("%s", &parg);
1734 }
1735 #endif
1736