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