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