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