Update to less-418:
[dragonfly.git] / contrib / less-406 / search.c
blob380d278a4a49f1f0cf0ef770cd374823ddd04d3a
1 /*
2 * Copyright (C) 1984-2007 Mark Nudelman
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.
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
13 * Routines to search a file for a pattern.
16 #include "less.h"
17 #include "position.h"
19 #define MINPOS(a,b) (((a) < (b)) ? (a) : (b))
20 #define MAXPOS(a,b) (((a) > (b)) ? (a) : (b))
22 #if HAVE_POSIX_REGCOMP
23 #include <regex.h>
24 #ifdef REG_EXTENDED
25 #define REGCOMP_FLAG REG_EXTENDED
26 #else
27 #define REGCOMP_FLAG 0
28 #endif
29 #endif
30 #if HAVE_PCRE
31 #include <pcre.h>
32 #endif
33 #if HAVE_RE_COMP
34 char *re_comp();
35 int re_exec();
36 #endif
37 #if HAVE_REGCMP
38 char *regcmp();
39 char *regex();
40 extern char *__loc1;
41 #endif
42 #if HAVE_V8_REGCOMP
43 #include "regexp.h"
44 #endif
46 static int match();
48 extern int sigs;
49 extern int how_search;
50 extern int caseless;
51 extern int linenums;
52 extern int sc_height;
53 extern int jump_sline;
54 extern int bs_mode;
55 extern int ctldisp;
56 extern int status_col;
57 extern void * constant ml_search;
58 extern POSITION start_attnpos;
59 extern POSITION end_attnpos;
60 #if HILITE_SEARCH
61 extern int hilite_search;
62 extern int screen_trashed;
63 extern int size_linebuf;
64 extern int squished;
65 extern int can_goto_line;
66 static int hide_hilite;
67 static int oldbot;
68 static POSITION prep_startpos;
69 static POSITION prep_endpos;
71 struct hilite
73 struct hilite *hl_next;
74 POSITION hl_startpos;
75 POSITION hl_endpos;
77 static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
78 #define hl_first hl_next
79 #endif
82 * These are the static variables that represent the "remembered"
83 * search pattern.
85 #if HAVE_POSIX_REGCOMP
86 static regex_t *regpattern = NULL;
87 #endif
88 #if HAVE_PCRE
89 pcre *regpattern = NULL;
90 #endif
91 #if HAVE_RE_COMP
92 int re_pattern = 0;
93 #endif
94 #if HAVE_REGCMP
95 static char *cpattern = NULL;
96 #endif
97 #if HAVE_V8_REGCOMP
98 static struct regexp *regpattern = NULL;
99 #endif
101 static int is_caseless;
102 static int is_ucase_pattern;
103 static int last_search_type;
104 static char *last_pattern = NULL;
107 * Convert text. Perform one or more of these transformations:
109 #define CVT_TO_LC 01 /* Convert upper-case to lower-case */
110 #define CVT_BS 02 /* Do backspace processing */
111 #define CVT_CRLF 04 /* Remove CR after LF */
112 #define CVT_ANSI 010 /* Remove ANSI escape sequences */
114 static void
115 cvt_text(odst, osrc, lenp, ops)
116 char *odst;
117 char *osrc;
118 int *lenp;
119 int ops;
121 register char *dst;
122 register char *src;
123 register char *src_end;
125 if (lenp != NULL)
126 src_end = osrc + *lenp;
127 else
128 src_end = osrc + strlen(osrc);
130 for (src = osrc, dst = odst; src < src_end; src++)
132 if ((ops & CVT_TO_LC) && IS_UPPER(*src))
133 /* Convert uppercase to lowercase. */
134 *dst++ = TO_LOWER(*src);
135 else if ((ops & CVT_BS) && *src == '\b' && dst > odst)
136 /* Delete BS and preceding char. */
137 dst--;
138 else if ((ops & CVT_ANSI) && *src == ESC)
140 /* Skip to end of ANSI escape sequence. */
141 while (src + 1 != src_end)
142 if (!is_ansi_middle(*++src))
143 break;
144 } else
145 /* Just copy. */
146 *dst++ = *src;
148 if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
149 dst--;
150 *dst = '\0';
151 if (lenp != NULL)
152 *lenp = dst - odst;
156 * Determine which conversions to perform.
158 static int
159 get_cvt_ops()
161 int ops = 0;
162 if (is_caseless || bs_mode == BS_SPECIAL)
164 if (is_caseless)
165 ops |= CVT_TO_LC;
166 if (bs_mode == BS_SPECIAL)
167 ops |= CVT_BS;
168 if (bs_mode != BS_CONTROL)
169 ops |= CVT_CRLF;
170 } else if (bs_mode != BS_CONTROL)
172 ops |= CVT_CRLF;
174 if (ctldisp == OPT_ONPLUS)
175 ops |= CVT_ANSI;
176 return (ops);
180 * Are there any uppercase letters in this string?
182 static int
183 is_ucase(s)
184 char *s;
186 register char *p;
188 for (p = s; *p != '\0'; p++)
189 if (IS_UPPER(*p))
190 return (1);
191 return (0);
195 * Is there a previous (remembered) search pattern?
197 static int
198 prev_pattern()
200 if (last_search_type & SRCH_NO_REGEX)
201 return (last_pattern != NULL);
202 #if HAVE_POSIX_REGCOMP
203 return (regpattern != NULL);
204 #endif
205 #if HAVE_PCRE
206 return (regpattern != NULL);
207 #endif
208 #if HAVE_RE_COMP
209 return (re_pattern != 0);
210 #endif
211 #if HAVE_REGCMP
212 return (cpattern != NULL);
213 #endif
214 #if HAVE_V8_REGCOMP
215 return (regpattern != NULL);
216 #endif
217 #if NO_REGEX
218 return (last_pattern != NULL);
219 #endif
222 #if HILITE_SEARCH
224 * Repaint the hilites currently displayed on the screen.
225 * Repaint each line which contains highlighted text.
226 * If on==0, force all hilites off.
228 public void
229 repaint_hilite(on)
230 int on;
232 int slinenum;
233 POSITION pos;
234 POSITION epos;
235 int save_hide_hilite;
237 if (squished)
238 repaint();
240 save_hide_hilite = hide_hilite;
241 if (!on)
243 if (hide_hilite)
244 return;
245 hide_hilite = 1;
248 if (!can_goto_line)
250 repaint();
251 hide_hilite = save_hide_hilite;
252 return;
255 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
257 pos = position(slinenum);
258 if (pos == NULL_POSITION)
259 continue;
260 epos = position(slinenum+1);
261 #if 0
263 * If any character in the line is highlighted,
264 * repaint the line.
266 * {{ This doesn't work -- if line is drawn with highlights
267 * which should be erased (e.g. toggle -i with status column),
268 * we must redraw the line even if it has no highlights.
269 * For now, just repaint every line. }}
271 if (is_hilited(pos, epos, 1, NULL))
272 #endif
274 (void) forw_line(pos);
275 goto_line(slinenum);
276 put_line();
279 if (!oldbot)
280 lower_left();
281 hide_hilite = save_hide_hilite;
285 * Clear the attn hilite.
287 public void
288 clear_attn()
290 int slinenum;
291 POSITION old_start_attnpos;
292 POSITION old_end_attnpos;
293 POSITION pos;
294 POSITION epos;
295 int moved = 0;
297 if (start_attnpos == NULL_POSITION)
298 return;
299 old_start_attnpos = start_attnpos;
300 old_end_attnpos = end_attnpos;
301 start_attnpos = end_attnpos = NULL_POSITION;
303 if (!can_goto_line)
305 repaint();
306 return;
308 if (squished)
309 repaint();
311 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
313 pos = position(slinenum);
314 if (pos == NULL_POSITION)
315 continue;
316 epos = position(slinenum+1);
317 if (pos < old_end_attnpos &&
318 (epos == NULL_POSITION || epos > old_start_attnpos))
320 (void) forw_line(pos);
321 goto_line(slinenum);
322 put_line();
323 moved = 1;
326 if (moved)
327 lower_left();
329 #endif
332 * Hide search string highlighting.
334 public void
335 undo_search()
337 if (!prev_pattern())
339 error("No previous regular expression", NULL_PARG);
340 return;
342 #if HILITE_SEARCH
343 hide_hilite = !hide_hilite;
344 repaint_hilite(1);
345 #endif
349 * Compile a search pattern, for future use by match_pattern.
351 static int
352 compile_pattern(pattern, search_type)
353 char *pattern;
354 int search_type;
356 if ((search_type & SRCH_NO_REGEX) == 0)
358 #if HAVE_POSIX_REGCOMP
359 regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
360 if (regcomp(s, pattern, REGCOMP_FLAG))
362 free(s);
363 error("Invalid pattern", NULL_PARG);
364 return (-1);
366 if (regpattern != NULL)
367 regfree(regpattern);
368 regpattern = s;
369 #endif
370 #if HAVE_PCRE
371 pcre *comp;
372 const char *errstring;
373 int erroffset;
374 PARG parg;
375 comp = pcre_compile(pattern, 0,
376 &errstring, &erroffset, NULL);
377 if (comp == NULL)
379 parg.p_string = (char *) errstring;
380 error("%s", &parg);
381 return (-1);
383 regpattern = comp;
384 #endif
385 #if HAVE_RE_COMP
386 PARG parg;
387 if ((parg.p_string = re_comp(pattern)) != NULL)
389 error("%s", &parg);
390 return (-1);
392 re_pattern = 1;
393 #endif
394 #if HAVE_REGCMP
395 char *s;
396 if ((s = regcmp(pattern, 0)) == NULL)
398 error("Invalid pattern", NULL_PARG);
399 return (-1);
401 if (cpattern != NULL)
402 free(cpattern);
403 cpattern = s;
404 #endif
405 #if HAVE_V8_REGCOMP
406 struct regexp *s;
407 if ((s = regcomp(pattern)) == NULL)
410 * regcomp has already printed an error message
411 * via regerror().
413 return (-1);
415 if (regpattern != NULL)
416 free(regpattern);
417 regpattern = s;
418 #endif
421 if (last_pattern != NULL)
422 free(last_pattern);
423 last_pattern = (char *) calloc(1, strlen(pattern)+1);
424 if (last_pattern != NULL)
425 strcpy(last_pattern, pattern);
427 last_search_type = search_type;
428 return (0);
432 * Forget that we have a compiled pattern.
434 static void
435 uncompile_pattern()
437 #if HAVE_POSIX_REGCOMP
438 if (regpattern != NULL)
439 regfree(regpattern);
440 regpattern = NULL;
441 #endif
442 #if HAVE_PCRE
443 if (regpattern != NULL)
444 pcre_free(regpattern);
445 regpattern = NULL;
446 #endif
447 #if HAVE_RE_COMP
448 re_pattern = 0;
449 #endif
450 #if HAVE_REGCMP
451 if (cpattern != NULL)
452 free(cpattern);
453 cpattern = NULL;
454 #endif
455 #if HAVE_V8_REGCOMP
456 if (regpattern != NULL)
457 free(regpattern);
458 regpattern = NULL;
459 #endif
460 last_pattern = NULL;
464 * Perform a pattern match with the previously compiled pattern.
465 * Set sp and ep to the start and end of the matched string.
467 static int
468 match_pattern(line, line_len, sp, ep, notbol)
469 char *line;
470 int line_len;
471 char **sp;
472 char **ep;
473 int notbol;
475 int matched;
477 if (last_search_type & SRCH_NO_REGEX)
478 return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
480 #if HAVE_POSIX_REGCOMP
482 regmatch_t rm;
483 int flags = (notbol) ? REG_NOTBOL : 0;
484 matched = !regexec(regpattern, line, 1, &rm, flags);
485 if (!matched)
486 return (0);
487 #ifndef __WATCOMC__
488 *sp = line + rm.rm_so;
489 *ep = line + rm.rm_eo;
490 #else
491 *sp = rm.rm_sp;
492 *ep = rm.rm_ep;
493 #endif
495 #endif
496 #if HAVE_PCRE
498 int flags = (notbol) ? PCRE_NOTBOL : 0;
499 int ovector[3];
500 matched = pcre_exec(regpattern, NULL, line, line_len,
501 0, flags, ovector, 3) >= 0;
502 if (!matched)
503 return (0);
504 *sp = line + ovector[0];
505 *ep = line + ovector[1];
507 #endif
508 #if HAVE_RE_COMP
509 matched = (re_exec(line) == 1);
511 * re_exec doesn't seem to provide a way to get the matched string.
513 *sp = *ep = NULL;
514 #endif
515 #if HAVE_REGCMP
516 *ep = regex(cpattern, line);
517 matched = (*ep != NULL);
518 if (!matched)
519 return (0);
520 *sp = __loc1;
521 #endif
522 #if HAVE_V8_REGCOMP
523 #if HAVE_REGEXEC2
524 matched = regexec2(regpattern, line, notbol);
525 #else
526 matched = regexec(regpattern, line);
527 #endif
528 if (!matched)
529 return (0);
530 *sp = regpattern->startp[0];
531 *ep = regpattern->endp[0];
532 #endif
533 #if NO_REGEX
534 matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
535 #endif
536 return (matched);
539 #if HILITE_SEARCH
541 * Clear the hilite list.
543 public void
544 clr_hilite()
546 struct hilite *hl;
547 struct hilite *nexthl;
549 for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl)
551 nexthl = hl->hl_next;
552 free((void*)hl);
554 hilite_anchor.hl_first = NULL;
555 prep_startpos = prep_endpos = NULL_POSITION;
559 * Should any characters in a specified range be highlighted?
561 static int
562 is_hilited_range(pos, epos)
563 POSITION pos;
564 POSITION epos;
566 struct hilite *hl;
569 * Look at each highlight and see if any part of it falls in the range.
571 for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next)
573 if (hl->hl_endpos > pos &&
574 (epos == NULL_POSITION || epos > hl->hl_startpos))
575 return (1);
577 return (0);
581 * Should any characters in a specified range be highlighted?
582 * If nohide is nonzero, don't consider hide_hilite.
584 public int
585 is_hilited(pos, epos, nohide, p_matches)
586 POSITION pos;
587 POSITION epos;
588 int nohide;
589 int *p_matches;
591 int match;
593 if (p_matches != NULL)
594 *p_matches = 0;
596 if (!status_col &&
597 start_attnpos != NULL_POSITION &&
598 pos < end_attnpos &&
599 (epos == NULL_POSITION || epos > start_attnpos))
601 * The attn line overlaps this range.
603 return (1);
605 match = is_hilited_range(pos, epos);
606 if (!match)
607 return (0);
609 if (p_matches != NULL)
611 * Report matches, even if we're hiding highlights.
613 *p_matches = 1;
615 if (hilite_search == 0)
617 * Not doing highlighting.
619 return (0);
621 if (!nohide && hide_hilite)
623 * Highlighting is hidden.
625 return (0);
627 return (1);
631 * Add a new hilite to a hilite list.
633 static void
634 add_hilite(anchor, hl)
635 struct hilite *anchor;
636 struct hilite *hl;
638 struct hilite *ihl;
641 * Hilites are sorted in the list; find where new one belongs.
642 * Insert new one after ihl.
644 for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next)
646 if (ihl->hl_next->hl_startpos > hl->hl_startpos)
647 break;
651 * Truncate hilite so it doesn't overlap any existing ones
652 * above and below it.
654 if (ihl != anchor)
655 hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
656 if (ihl->hl_next != NULL)
657 hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
658 if (hl->hl_startpos >= hl->hl_endpos)
661 * Hilite was truncated out of existence.
663 free(hl);
664 return;
666 hl->hl_next = ihl->hl_next;
667 ihl->hl_next = hl;
670 static void
671 adj_hilite_ansi(cvt_ops, line, line_len, npos)
672 int cvt_ops;
673 char **line;
674 int line_len;
675 POSITION *npos;
677 char *line_end = *line + line_len;
679 if (cvt_ops & CVT_ANSI)
680 while (**line == ESC)
683 * Found an ESC. The file position moves
684 * forward past the entire ANSI escape sequence.
686 (*line)++;
687 (*npos)++;
688 while (*line < line_end)
690 (*npos)++;
691 if (!is_ansi_middle(*(*line)++))
692 break;
698 * Adjust hl_startpos & hl_endpos to account for backspace processing.
700 static void
701 adj_hilite(anchor, linepos, cvt_ops)
702 struct hilite *anchor;
703 POSITION linepos;
704 int cvt_ops;
706 char *line;
707 int line_len;
708 char *line_end;
709 struct hilite *hl;
710 int checkstart;
711 POSITION opos;
712 POSITION npos;
715 * The line was already scanned and hilites were added (in hilite_line).
716 * But it was assumed that each char position in the line
717 * correponds to one char position in the file.
718 * This may not be true if there are backspaces in the line.
719 * Get the raw line again. Look at each character.
721 (void) forw_raw_line(linepos, &line, &line_len);
722 line_end = line + line_len;
723 opos = npos = linepos;
724 hl = anchor->hl_first;
725 checkstart = TRUE;
726 while (hl != NULL)
729 * See if we need to adjust the current hl_startpos or
730 * hl_endpos. After adjusting startpos[i], move to endpos[i].
731 * After adjusting endpos[i], move to startpos[i+1].
732 * The hilite list must be sorted thus:
733 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
735 if (checkstart && hl->hl_startpos == opos)
737 hl->hl_startpos = npos;
738 checkstart = FALSE;
739 continue; /* {{ not really necessary }} */
740 } else if (!checkstart && hl->hl_endpos == opos)
742 hl->hl_endpos = npos;
743 checkstart = TRUE;
744 hl = hl->hl_next;
745 continue; /* {{ necessary }} */
747 if (line == line_end)
748 break;
749 adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos);
750 opos++;
751 npos++;
752 line++;
753 if (cvt_ops & CVT_BS)
755 while (*line == '\b')
757 npos++;
758 line++;
759 adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos);
760 if (line == line_end)
762 --npos;
763 --line;
764 break;
767 * Found a backspace. The file position moves
768 * forward by 2 relative to the processed line
769 * which was searched in hilite_line.
771 npos++;
772 line++;
779 * Make a hilite for each string in a physical line which matches
780 * the current pattern.
781 * sp,ep delimit the first match already found.
783 static void
784 hilite_line(linepos, line, line_len, sp, ep, cvt_ops)
785 POSITION linepos;
786 char *line;
787 int line_len;
788 char *sp;
789 char *ep;
790 int cvt_ops;
792 char *searchp;
793 char *line_end = line + line_len;
794 struct hilite *hl;
795 struct hilite hilites;
797 if (sp == NULL || ep == NULL)
798 return;
800 * sp and ep delimit the first match in the line.
801 * Mark the corresponding file positions, then
802 * look for further matches and mark them.
803 * {{ This technique, of calling match_pattern on subsequent
804 * substrings of the line, may mark more than is correct
805 * if the pattern starts with "^". This bug is fixed
806 * for those regex functions that accept a notbol parameter
807 * (currently POSIX, PCRE and V8-with-regexec2). }}
809 searchp = line;
811 * Put the hilites into a temporary list until they're adjusted.
813 hilites.hl_first = NULL;
814 do {
815 if (ep > sp)
818 * Assume that each char position in the "line"
819 * buffer corresponds to one char position in the file.
820 * This is not quite true; we need to adjust later.
822 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
823 hl->hl_startpos = linepos + (sp-line);
824 hl->hl_endpos = linepos + (ep-line);
825 add_hilite(&hilites, hl);
828 * If we matched more than zero characters,
829 * move to the first char after the string we matched.
830 * If we matched zero, just move to the next char.
832 if (ep > searchp)
833 searchp = ep;
834 else if (searchp != line_end)
835 searchp++;
836 else /* end of line */
837 break;
838 } while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1));
841 * If there were backspaces in the original line, they
842 * were removed, and hl_startpos/hl_endpos are not correct.
843 * {{ This is very ugly. }}
845 adj_hilite(&hilites, linepos, cvt_ops);
848 * Now put the hilites into the real list.
850 while ((hl = hilites.hl_next) != NULL)
852 hilites.hl_next = hl->hl_next;
853 add_hilite(&hilite_anchor, hl);
856 #endif
859 * Change the caseless-ness of searches.
860 * Updates the internal search state to reflect a change in the -i flag.
862 public void
863 chg_caseless()
865 if (!is_ucase_pattern)
867 * Pattern did not have uppercase.
868 * Just set the search caselessness to the global caselessness.
870 is_caseless = caseless;
871 else
873 * Pattern did have uppercase.
874 * Discard the pattern; we can't change search caselessness now.
876 uncompile_pattern();
879 #if HILITE_SEARCH
881 * Find matching text which is currently on screen and highlight it.
883 static void
884 hilite_screen()
886 struct scrpos scrpos;
888 get_scrpos(&scrpos);
889 if (scrpos.pos == NULL_POSITION)
890 return;
891 prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
892 repaint_hilite(1);
896 * Change highlighting parameters.
898 public void
899 chg_hilite()
902 * Erase any highlights currently on screen.
904 clr_hilite();
905 hide_hilite = 0;
907 if (hilite_search == OPT_ONPLUS)
909 * Display highlights.
911 hilite_screen();
913 #endif
916 * Figure out where to start a search.
918 static POSITION
919 search_pos(search_type)
920 int search_type;
922 POSITION pos;
923 int linenum;
925 if (empty_screen())
928 * Start at the beginning (or end) of the file.
929 * The empty_screen() case is mainly for
930 * command line initiated searches;
931 * for example, "+/xyz" on the command line.
932 * Also for multi-file (SRCH_PAST_EOF) searches.
934 if (search_type & SRCH_FORW)
936 return (ch_zero());
937 } else
939 pos = ch_length();
940 if (pos == NULL_POSITION)
942 (void) ch_end_seek();
943 pos = ch_length();
945 return (pos);
948 if (how_search)
951 * Search does not include current screen.
953 if (search_type & SRCH_FORW)
954 linenum = BOTTOM_PLUS_ONE;
955 else
956 linenum = TOP;
957 pos = position(linenum);
958 } else
961 * Search includes current screen.
962 * It starts at the jump target (if searching backwards),
963 * or at the jump target plus one (if forwards).
965 linenum = adjsline(jump_sline);
966 pos = position(linenum);
967 if (search_type & SRCH_FORW)
969 pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
970 while (pos == NULL_POSITION)
972 if (++linenum >= sc_height)
973 break;
974 pos = position(linenum);
976 } else
978 while (pos == NULL_POSITION)
980 if (--linenum < 0)
981 break;
982 pos = position(linenum);
986 return (pos);
990 * Search a subset of the file, specified by start/end position.
992 static int
993 search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
994 POSITION pos;
995 POSITION endpos;
996 int search_type;
997 int matches;
998 int maxlines;
999 POSITION *plinepos;
1000 POSITION *pendpos;
1002 char *line;
1003 int line_len;
1004 LINENUM linenum;
1005 char *sp, *ep;
1006 int line_match;
1007 int cvt_ops;
1008 POSITION linepos, oldpos;
1010 linenum = find_linenum(pos);
1011 oldpos = pos;
1012 for (;;)
1015 * Get lines until we find a matching one or until
1016 * we hit end-of-file (or beginning-of-file if we're
1017 * going backwards), or until we hit the end position.
1019 if (ABORT_SIGS())
1022 * A signal aborts the search.
1024 return (-1);
1027 if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
1030 * Reached end position without a match.
1032 if (pendpos != NULL)
1033 *pendpos = pos;
1034 return (matches);
1036 if (maxlines > 0)
1037 maxlines--;
1039 if (search_type & SRCH_FORW)
1042 * Read the next line, and save the
1043 * starting position of that line in linepos.
1045 linepos = pos;
1046 pos = forw_raw_line(pos, &line, &line_len);
1047 if (linenum != 0)
1048 linenum++;
1049 } else
1052 * Read the previous line and save the
1053 * starting position of that line in linepos.
1055 pos = back_raw_line(pos, &line, &line_len);
1056 linepos = pos;
1057 if (linenum != 0)
1058 linenum--;
1061 if (pos == NULL_POSITION)
1064 * Reached EOF/BOF without a match.
1066 if (pendpos != NULL)
1067 *pendpos = oldpos;
1068 return (matches);
1072 * If we're using line numbers, we might as well
1073 * remember the information we have now (the position
1074 * and line number of the current line).
1075 * Don't do it for every line because it slows down
1076 * the search. Remember the line number only if
1077 * we're "far" from the last place we remembered it.
1079 if (linenums && abs((int)(pos - oldpos)) > 1024)
1080 add_lnum(linenum, pos);
1081 oldpos = pos;
1084 * If it's a caseless search, convert the line to lowercase.
1085 * If we're doing backspace processing, delete backspaces.
1087 cvt_ops = get_cvt_ops();
1088 cvt_text(line, line, &line_len, cvt_ops);
1091 * Test the next line to see if we have a match.
1092 * We are successful if we either want a match and got one,
1093 * or if we want a non-match and got one.
1095 line_match = match_pattern(line, line_len, &sp, &ep, 0);
1096 line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
1097 ((search_type & SRCH_NO_MATCH) && !line_match);
1098 if (!line_match)
1099 continue;
1101 * Got a match.
1103 if (search_type & SRCH_FIND_ALL)
1105 #if HILITE_SEARCH
1107 * We are supposed to find all matches in the range.
1108 * Just add the matches in this line to the
1109 * hilite list and keep searching.
1111 if (line_match)
1112 hilite_line(linepos, line, line_len, sp, ep, cvt_ops);
1113 #endif
1114 } else if (--matches <= 0)
1117 * Found the one match we're looking for.
1118 * Return it.
1120 #if HILITE_SEARCH
1121 if (hilite_search == OPT_ON)
1124 * Clear the hilite list and add only
1125 * the matches in this one line.
1127 clr_hilite();
1128 if (line_match)
1129 hilite_line(linepos, line, line_len, sp, ep, cvt_ops);
1131 #endif
1132 if (plinepos != NULL)
1133 *plinepos = linepos;
1134 return (0);
1140 * search for a pattern in history. If found, compile that pattern.
1142 static int
1143 hist_pattern(search_type)
1144 int search_type;
1146 #if CMD_HISTORY
1147 char *pattern;
1149 set_mlist(ml_search, 0);
1150 pattern = cmd_lastpattern();
1151 if (pattern == NULL)
1152 return (0);
1154 if (caseless == OPT_ONPLUS)
1155 cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC);
1157 if (compile_pattern(pattern, search_type) < 0)
1158 return (0);
1160 is_ucase_pattern = is_ucase(pattern);
1161 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1162 is_caseless = 0;
1163 else
1164 is_caseless = caseless;
1166 #if HILITE_SEARCH
1167 if (hilite_search == OPT_ONPLUS && !hide_hilite)
1168 hilite_screen();
1169 #endif
1171 return (1);
1172 #else /* CMD_HISTORY */
1173 return (0);
1174 #endif /* CMD_HISTORY */
1178 * Search for the n-th occurrence of a specified pattern,
1179 * either forward or backward.
1180 * Return the number of matches not yet found in this file
1181 * (that is, n minus the number of matches found).
1182 * Return -1 if the search should be aborted.
1183 * Caller may continue the search in another file
1184 * if less than n matches are found in this file.
1186 public int
1187 search(search_type, pattern, n)
1188 int search_type;
1189 char *pattern;
1190 int n;
1192 POSITION pos;
1193 int ucase;
1195 if (pattern == NULL || *pattern == '\0')
1198 * A null pattern means use the previously compiled pattern.
1200 if (!prev_pattern() && !hist_pattern(search_type))
1202 error("No previous regular expression", NULL_PARG);
1203 return (-1);
1205 if ((search_type & SRCH_NO_REGEX) !=
1206 (last_search_type & SRCH_NO_REGEX))
1208 error("Please re-enter search pattern", NULL_PARG);
1209 return -1;
1211 #if HILITE_SEARCH
1212 if (hilite_search == OPT_ON)
1215 * Erase the highlights currently on screen.
1216 * If the search fails, we'll redisplay them later.
1218 repaint_hilite(0);
1220 if (hilite_search == OPT_ONPLUS && hide_hilite)
1223 * Highlight any matches currently on screen,
1224 * before we actually start the search.
1226 hide_hilite = 0;
1227 hilite_screen();
1229 hide_hilite = 0;
1230 #endif
1231 } else
1234 * Compile the pattern.
1236 ucase = is_ucase(pattern);
1237 if (caseless == OPT_ONPLUS)
1238 cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC);
1239 if (compile_pattern(pattern, search_type) < 0)
1240 return (-1);
1242 * Ignore case if -I is set OR
1243 * -i is set AND the pattern is all lowercase.
1245 is_ucase_pattern = ucase;
1246 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1247 is_caseless = 0;
1248 else
1249 is_caseless = caseless;
1250 #if HILITE_SEARCH
1251 if (hilite_search)
1254 * Erase the highlights currently on screen.
1255 * Also permanently delete them from the hilite list.
1257 repaint_hilite(0);
1258 hide_hilite = 0;
1259 clr_hilite();
1261 if (hilite_search == OPT_ONPLUS)
1264 * Highlight any matches currently on screen,
1265 * before we actually start the search.
1267 hilite_screen();
1269 #endif
1273 * Figure out where to start the search.
1275 pos = search_pos(search_type);
1276 if (pos == NULL_POSITION)
1279 * Can't find anyplace to start searching from.
1281 if (search_type & SRCH_PAST_EOF)
1282 return (n);
1283 /* repaint(); -- why was this here? */
1284 error("Nothing to search", NULL_PARG);
1285 return (-1);
1288 n = search_range(pos, NULL_POSITION, search_type, n, -1,
1289 &pos, (POSITION*)NULL);
1290 if (n != 0)
1293 * Search was unsuccessful.
1295 #if HILITE_SEARCH
1296 if (hilite_search == OPT_ON && n > 0)
1298 * Redisplay old hilites.
1300 repaint_hilite(1);
1301 #endif
1302 return (n);
1305 if (!(search_type & SRCH_NO_MOVE))
1308 * Go to the matching line.
1310 jump_loc(pos, jump_sline);
1313 #if HILITE_SEARCH
1314 if (hilite_search == OPT_ON)
1316 * Display new hilites in the matching line.
1318 repaint_hilite(1);
1319 #endif
1320 return (0);
1324 #if HILITE_SEARCH
1326 * Prepare hilites in a given range of the file.
1328 * The pair (prep_startpos,prep_endpos) delimits a contiguous region
1329 * of the file that has been "prepared"; that is, scanned for matches for
1330 * the current search pattern, and hilites have been created for such matches.
1331 * If prep_startpos == NULL_POSITION, the prep region is empty.
1332 * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
1333 * prep_hilite asks that the range (spos,epos) be covered by the prep region.
1335 public void
1336 prep_hilite(spos, epos, maxlines)
1337 POSITION spos;
1338 POSITION epos;
1339 int maxlines;
1341 POSITION nprep_startpos = prep_startpos;
1342 POSITION nprep_endpos = prep_endpos;
1343 POSITION new_epos;
1344 POSITION max_epos;
1345 int result;
1346 int i;
1348 * Search beyond where we're asked to search, so the prep region covers
1349 * more than we need. Do one big search instead of a bunch of small ones.
1351 #define SEARCH_MORE (3*size_linebuf)
1353 if (!prev_pattern())
1354 return;
1357 * If we're limited to a max number of lines, figure out the
1358 * file position we should stop at.
1360 if (maxlines < 0)
1361 max_epos = NULL_POSITION;
1362 else
1364 max_epos = spos;
1365 for (i = 0; i < maxlines; i++)
1366 max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
1370 * Find two ranges:
1371 * The range that we need to search (spos,epos); and the range that
1372 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
1375 if (prep_startpos == NULL_POSITION ||
1376 (epos != NULL_POSITION && epos < prep_startpos) ||
1377 spos > prep_endpos)
1380 * New range is not contiguous with old prep region.
1381 * Discard the old prep region and start a new one.
1383 clr_hilite();
1384 if (epos != NULL_POSITION)
1385 epos += SEARCH_MORE;
1386 nprep_startpos = spos;
1387 } else
1390 * New range partially or completely overlaps old prep region.
1392 if (epos == NULL_POSITION)
1395 * New range goes to end of file.
1398 } else if (epos > prep_endpos)
1401 * New range ends after old prep region.
1402 * Extend prep region to end at end of new range.
1404 epos += SEARCH_MORE;
1405 } else /* (epos <= prep_endpos) */
1408 * New range ends within old prep region.
1409 * Truncate search to end at start of old prep region.
1411 epos = prep_startpos;
1414 if (spos < prep_startpos)
1417 * New range starts before old prep region.
1418 * Extend old prep region backwards to start at
1419 * start of new range.
1421 if (spos < SEARCH_MORE)
1422 spos = 0;
1423 else
1424 spos -= SEARCH_MORE;
1425 nprep_startpos = spos;
1426 } else /* (spos >= prep_startpos) */
1429 * New range starts within or after old prep region.
1430 * Trim search to start at end of old prep region.
1432 spos = prep_endpos;
1436 if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
1437 epos > max_epos)
1439 * Don't go past the max position we're allowed.
1441 epos = max_epos;
1443 if (epos == NULL_POSITION || epos > spos)
1445 result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
1446 maxlines, (POSITION*)NULL, &new_epos);
1447 if (result < 0)
1448 return;
1449 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
1450 nprep_endpos = new_epos;
1452 prep_startpos = nprep_startpos;
1453 prep_endpos = nprep_endpos;
1455 #endif
1458 * Simple pattern matching function.
1459 * It supports no metacharacters like *, etc.
1461 static int
1462 match(pattern, pattern_len, buf, buf_len, pfound, pend)
1463 char *pattern;
1464 int pattern_len;
1465 char *buf;
1466 int buf_len;
1467 char **pfound, **pend;
1469 register char *pp, *lp;
1470 register char *pattern_end = pattern + pattern_len;
1471 register char *buf_end = buf + buf_len;
1473 for ( ; buf < buf_end; buf++)
1475 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
1476 if (pp == pattern_end || lp == buf_end)
1477 break;
1478 if (pp == pattern_end)
1480 if (pfound != NULL)
1481 *pfound = buf;
1482 if (pend != NULL)
1483 *pend = lp;
1484 return (1);
1487 return (0);
1490 #if HAVE_V8_REGCOMP
1492 * This function is called by the V8 regcomp to report
1493 * errors in regular expressions.
1495 void
1496 regerror(s)
1497 char *s;
1499 PARG parg;
1501 parg.p_string = s;
1502 error("%s", &parg);
1504 #endif