Adjust list width.
[dragonfly.git] / contrib / less-4 / search.c
blob8d2d13edd7a1dc36b5907c26832a6e16b6ad16e0
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"
18 #include "charset.h"
20 #define MINPOS(a,b) (((a) < (b)) ? (a) : (b))
21 #define MAXPOS(a,b) (((a) > (b)) ? (a) : (b))
23 #if HAVE_POSIX_REGCOMP
24 #include <regex.h>
25 #ifdef REG_EXTENDED
26 #define REGCOMP_FLAG REG_EXTENDED
27 #else
28 #define REGCOMP_FLAG 0
29 #endif
30 #endif
31 #if HAVE_PCRE
32 #include <pcre.h>
33 #endif
34 #if HAVE_RE_COMP
35 char *re_comp();
36 int re_exec();
37 #endif
38 #if HAVE_REGCMP
39 char *regcmp();
40 char *regex();
41 extern char *__loc1;
42 #endif
43 #if HAVE_V8_REGCOMP
44 #include "regexp.h"
45 #endif
47 static int match();
49 extern int sigs;
50 extern int how_search;
51 extern int caseless;
52 extern int linenums;
53 extern int sc_height;
54 extern int jump_sline;
55 extern int bs_mode;
56 extern int ctldisp;
57 extern int status_col;
58 extern void * constant ml_search;
59 extern POSITION start_attnpos;
60 extern POSITION end_attnpos;
61 #if HILITE_SEARCH
62 extern int hilite_search;
63 extern int screen_trashed;
64 extern int size_linebuf;
65 extern int squished;
66 extern int can_goto_line;
67 extern int utf_mode;
68 static int hide_hilite;
69 static int oldbot;
70 static POSITION prep_startpos;
71 static POSITION prep_endpos;
73 struct hilite
75 struct hilite *hl_next;
76 POSITION hl_startpos;
77 POSITION hl_endpos;
79 static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
80 #define hl_first hl_next
81 #endif
84 * These are the static variables that represent the "remembered"
85 * search pattern.
87 #if HAVE_POSIX_REGCOMP
88 static regex_t *regpattern = NULL;
89 #endif
90 #if HAVE_PCRE
91 pcre *regpattern = NULL;
92 #endif
93 #if HAVE_RE_COMP
94 int re_pattern = 0;
95 #endif
96 #if HAVE_REGCMP
97 static char *cpattern = NULL;
98 #endif
99 #if HAVE_V8_REGCOMP
100 static struct regexp *regpattern = NULL;
101 #endif
103 static int is_caseless;
104 static int is_ucase_pattern;
105 static int last_search_type;
106 static char *last_pattern = NULL;
108 #define CVT_TO_LC 01 /* Convert upper-case to lower-case */
109 #define CVT_BS 02 /* Do backspace processing */
110 #define CVT_CRLF 04 /* Remove CR after LF */
111 #define CVT_ANSI 010 /* Remove ANSI escape sequences */
114 * Get the length of a buffer needed to convert a string.
116 static int
117 cvt_length(len, ops)
118 int len;
119 int ops;
121 if (utf_mode)
123 * Just copying a string in UTF-8 mode can cause it to grow
124 * in length.
125 * Six output bytes for one input byte is the worst case
126 * (and unfortunately is far more than is needed in any
127 * non-pathological situation, so this is very wasteful).
129 len *= 6;
130 return len + 1;
134 * Convert text. Perform one or more of these transformations:
136 static void
137 cvt_text(odst, osrc, lenp, ops)
138 char *odst;
139 char *osrc;
140 int *lenp;
141 int ops;
143 char *dst;
144 char *src;
145 register char *src_end;
146 LWCHAR ch;
148 if (lenp != NULL)
149 src_end = osrc + *lenp;
150 else
151 src_end = osrc + strlen(osrc);
153 for (src = osrc, dst = odst; src < src_end; )
155 ch = step_char(&src, +1, src_end);
156 if ((ops & CVT_TO_LC) && IS_UPPER(ch))
158 /* Convert uppercase to lowercase. */
159 put_wchar(&dst, TO_LOWER(ch));
160 } else if ((ops & CVT_BS) && ch == '\b' && dst > odst)
162 /* Delete backspace and preceding char. */
163 do {
164 dst--;
165 } while (dst > odst &&
166 !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
167 } else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
169 /* Skip to end of ANSI escape sequence. */
170 src++; /* skip the CSI start char */
171 while (src < src_end)
172 if (!is_ansi_middle(*src++))
173 break;
174 } else
175 /* Just copy. */
176 put_wchar(&dst, ch);
178 if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
179 dst--;
180 *dst = '\0';
181 if (lenp != NULL)
182 *lenp = dst - odst;
186 * Determine which conversions to perform.
188 static int
189 get_cvt_ops()
191 int ops = 0;
192 if (is_caseless || bs_mode == BS_SPECIAL)
194 if (is_caseless)
195 ops |= CVT_TO_LC;
196 if (bs_mode == BS_SPECIAL)
197 ops |= CVT_BS;
198 if (bs_mode != BS_CONTROL)
199 ops |= CVT_CRLF;
200 } else if (bs_mode != BS_CONTROL)
202 ops |= CVT_CRLF;
204 if (ctldisp == OPT_ONPLUS)
205 ops |= CVT_ANSI;
206 return (ops);
210 * Are there any uppercase letters in this string?
212 static int
213 is_ucase(str)
214 char *str;
216 char *str_end = str + strlen(str);
217 LWCHAR ch;
219 while (str < str_end)
221 ch = step_char(&str, +1, str_end);
222 if (IS_UPPER(ch))
223 return (1);
225 return (0);
229 * Is there a previous (remembered) search pattern?
231 static int
232 prev_pattern()
234 if (last_search_type & SRCH_NO_REGEX)
235 return (last_pattern != NULL);
236 #if HAVE_POSIX_REGCOMP
237 return (regpattern != NULL);
238 #endif
239 #if HAVE_PCRE
240 return (regpattern != NULL);
241 #endif
242 #if HAVE_RE_COMP
243 return (re_pattern != 0);
244 #endif
245 #if HAVE_REGCMP
246 return (cpattern != NULL);
247 #endif
248 #if HAVE_V8_REGCOMP
249 return (regpattern != NULL);
250 #endif
251 #if NO_REGEX
252 return (last_pattern != NULL);
253 #endif
256 #if HILITE_SEARCH
258 * Repaint the hilites currently displayed on the screen.
259 * Repaint each line which contains highlighted text.
260 * If on==0, force all hilites off.
262 public void
263 repaint_hilite(on)
264 int on;
266 int slinenum;
267 POSITION pos;
268 POSITION epos;
269 int save_hide_hilite;
271 if (squished)
272 repaint();
274 save_hide_hilite = hide_hilite;
275 if (!on)
277 if (hide_hilite)
278 return;
279 hide_hilite = 1;
282 if (!can_goto_line)
284 repaint();
285 hide_hilite = save_hide_hilite;
286 return;
289 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
291 pos = position(slinenum);
292 if (pos == NULL_POSITION)
293 continue;
294 epos = position(slinenum+1);
295 #if 0
297 * If any character in the line is highlighted,
298 * repaint the line.
300 * {{ This doesn't work -- if line is drawn with highlights
301 * which should be erased (e.g. toggle -i with status column),
302 * we must redraw the line even if it has no highlights.
303 * For now, just repaint every line. }}
305 if (is_hilited(pos, epos, 1, NULL))
306 #endif
308 (void) forw_line(pos);
309 goto_line(slinenum);
310 put_line();
313 if (!oldbot)
314 lower_left();
315 hide_hilite = save_hide_hilite;
319 * Clear the attn hilite.
321 public void
322 clear_attn()
324 int slinenum;
325 POSITION old_start_attnpos;
326 POSITION old_end_attnpos;
327 POSITION pos;
328 POSITION epos;
329 int moved = 0;
331 if (start_attnpos == NULL_POSITION)
332 return;
333 old_start_attnpos = start_attnpos;
334 old_end_attnpos = end_attnpos;
335 start_attnpos = end_attnpos = NULL_POSITION;
337 if (!can_goto_line)
339 repaint();
340 return;
342 if (squished)
343 repaint();
345 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
347 pos = position(slinenum);
348 if (pos == NULL_POSITION)
349 continue;
350 epos = position(slinenum+1);
351 if (pos < old_end_attnpos &&
352 (epos == NULL_POSITION || epos > old_start_attnpos))
354 (void) forw_line(pos);
355 goto_line(slinenum);
356 put_line();
357 moved = 1;
360 if (moved)
361 lower_left();
363 #endif
366 * Hide search string highlighting.
368 public void
369 undo_search()
371 if (!prev_pattern())
373 error("No previous regular expression", NULL_PARG);
374 return;
376 #if HILITE_SEARCH
377 hide_hilite = !hide_hilite;
378 repaint_hilite(1);
379 #endif
383 * Compile a search pattern, for future use by match_pattern.
385 static int
386 compile_pattern2(pattern, search_type)
387 char *pattern;
388 int search_type;
390 if ((search_type & SRCH_NO_REGEX) == 0)
392 #if HAVE_POSIX_REGCOMP
393 regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
394 if (regcomp(s, pattern, REGCOMP_FLAG))
396 free(s);
397 error("Invalid pattern", NULL_PARG);
398 return (-1);
400 if (regpattern != NULL)
401 regfree(regpattern);
402 regpattern = s;
403 #endif
404 #if HAVE_PCRE
405 pcre *comp;
406 const char *errstring;
407 int erroffset;
408 PARG parg;
409 comp = pcre_compile(pattern, 0,
410 &errstring, &erroffset, NULL);
411 if (comp == NULL)
413 parg.p_string = (char *) errstring;
414 error("%s", &parg);
415 return (-1);
417 regpattern = comp;
418 #endif
419 #if HAVE_RE_COMP
420 PARG parg;
421 if ((parg.p_string = re_comp(pattern)) != NULL)
423 error("%s", &parg);
424 return (-1);
426 re_pattern = 1;
427 #endif
428 #if HAVE_REGCMP
429 char *s;
430 if ((s = regcmp(pattern, 0)) == NULL)
432 error("Invalid pattern", NULL_PARG);
433 return (-1);
435 if (cpattern != NULL)
436 free(cpattern);
437 cpattern = s;
438 #endif
439 #if HAVE_V8_REGCOMP
440 struct regexp *s;
441 if ((s = regcomp(pattern)) == NULL)
444 * regcomp has already printed an error message
445 * via regerror().
447 return (-1);
449 if (regpattern != NULL)
450 free(regpattern);
451 regpattern = s;
452 #endif
455 if (last_pattern != NULL)
456 free(last_pattern);
457 last_pattern = (char *) calloc(1, strlen(pattern)+1);
458 if (last_pattern != NULL)
459 strcpy(last_pattern, pattern);
461 last_search_type = search_type;
462 return (0);
466 * Like compile_pattern, but convert the pattern to lowercase if necessary.
468 static int
469 compile_pattern(pattern, search_type)
470 char *pattern;
471 int search_type;
473 char *cvt_pattern;
474 int result;
476 if (caseless != OPT_ONPLUS)
477 cvt_pattern = pattern;
478 else
480 cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
481 cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC);
483 result = compile_pattern2(cvt_pattern, search_type);
484 if (cvt_pattern != pattern)
485 free(cvt_pattern);
486 return (result);
490 * Forget that we have a compiled pattern.
492 static void
493 uncompile_pattern()
495 #if HAVE_POSIX_REGCOMP
496 if (regpattern != NULL)
497 regfree(regpattern);
498 regpattern = NULL;
499 #endif
500 #if HAVE_PCRE
501 if (regpattern != NULL)
502 pcre_free(regpattern);
503 regpattern = NULL;
504 #endif
505 #if HAVE_RE_COMP
506 re_pattern = 0;
507 #endif
508 #if HAVE_REGCMP
509 if (cpattern != NULL)
510 free(cpattern);
511 cpattern = NULL;
512 #endif
513 #if HAVE_V8_REGCOMP
514 if (regpattern != NULL)
515 free(regpattern);
516 regpattern = NULL;
517 #endif
518 last_pattern = NULL;
522 * Perform a pattern match with the previously compiled pattern.
523 * Set sp and ep to the start and end of the matched string.
525 static int
526 match_pattern(line, line_len, sp, ep, notbol)
527 char *line;
528 int line_len;
529 char **sp;
530 char **ep;
531 int notbol;
533 int matched;
535 if (last_search_type & SRCH_NO_REGEX)
536 return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
538 #if HAVE_POSIX_REGCOMP
540 regmatch_t rm;
541 int flags = (notbol) ? REG_NOTBOL : 0;
542 matched = !regexec(regpattern, line, 1, &rm, flags);
543 if (!matched)
544 return (0);
545 #ifndef __WATCOMC__
546 *sp = line + rm.rm_so;
547 *ep = line + rm.rm_eo;
548 #else
549 *sp = rm.rm_sp;
550 *ep = rm.rm_ep;
551 #endif
553 #endif
554 #if HAVE_PCRE
556 int flags = (notbol) ? PCRE_NOTBOL : 0;
557 int ovector[3];
558 matched = pcre_exec(regpattern, NULL, line, line_len,
559 0, flags, ovector, 3) >= 0;
560 if (!matched)
561 return (0);
562 *sp = line + ovector[0];
563 *ep = line + ovector[1];
565 #endif
566 #if HAVE_RE_COMP
567 matched = (re_exec(line) == 1);
569 * re_exec doesn't seem to provide a way to get the matched string.
571 *sp = *ep = NULL;
572 #endif
573 #if HAVE_REGCMP
574 *ep = regex(cpattern, line);
575 matched = (*ep != NULL);
576 if (!matched)
577 return (0);
578 *sp = __loc1;
579 #endif
580 #if HAVE_V8_REGCOMP
581 #if HAVE_REGEXEC2
582 matched = regexec2(regpattern, line, notbol);
583 #else
584 matched = regexec(regpattern, line);
585 #endif
586 if (!matched)
587 return (0);
588 *sp = regpattern->startp[0];
589 *ep = regpattern->endp[0];
590 #endif
591 #if NO_REGEX
592 matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
593 #endif
594 return (matched);
597 #if HILITE_SEARCH
599 * Clear the hilite list.
601 public void
602 clr_hilite()
604 struct hilite *hl;
605 struct hilite *nexthl;
607 for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl)
609 nexthl = hl->hl_next;
610 free((void*)hl);
612 hilite_anchor.hl_first = NULL;
613 prep_startpos = prep_endpos = NULL_POSITION;
617 * Should any characters in a specified range be highlighted?
619 static int
620 is_hilited_range(pos, epos)
621 POSITION pos;
622 POSITION epos;
624 struct hilite *hl;
627 * Look at each highlight and see if any part of it falls in the range.
629 for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next)
631 if (hl->hl_endpos > pos &&
632 (epos == NULL_POSITION || epos > hl->hl_startpos))
633 return (1);
635 return (0);
639 * Should any characters in a specified range be highlighted?
640 * If nohide is nonzero, don't consider hide_hilite.
642 public int
643 is_hilited(pos, epos, nohide, p_matches)
644 POSITION pos;
645 POSITION epos;
646 int nohide;
647 int *p_matches;
649 int match;
651 if (p_matches != NULL)
652 *p_matches = 0;
654 if (!status_col &&
655 start_attnpos != NULL_POSITION &&
656 pos < end_attnpos &&
657 (epos == NULL_POSITION || epos > start_attnpos))
659 * The attn line overlaps this range.
661 return (1);
663 match = is_hilited_range(pos, epos);
664 if (!match)
665 return (0);
667 if (p_matches != NULL)
669 * Report matches, even if we're hiding highlights.
671 *p_matches = 1;
673 if (hilite_search == 0)
675 * Not doing highlighting.
677 return (0);
679 if (!nohide && hide_hilite)
681 * Highlighting is hidden.
683 return (0);
685 return (1);
689 * Add a new hilite to a hilite list.
691 static void
692 add_hilite(anchor, hl)
693 struct hilite *anchor;
694 struct hilite *hl;
696 struct hilite *ihl;
699 * Hilites are sorted in the list; find where new one belongs.
700 * Insert new one after ihl.
702 for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next)
704 if (ihl->hl_next->hl_startpos > hl->hl_startpos)
705 break;
709 * Truncate hilite so it doesn't overlap any existing ones
710 * above and below it.
712 if (ihl != anchor)
713 hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
714 if (ihl->hl_next != NULL)
715 hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
716 if (hl->hl_startpos >= hl->hl_endpos)
719 * Hilite was truncated out of existence.
721 free(hl);
722 return;
724 hl->hl_next = ihl->hl_next;
725 ihl->hl_next = hl;
729 * Adjust hl_startpos & hl_endpos to account for processing by cvt_text.
731 static void
732 adj_hilite(anchor, linepos, cvt_ops)
733 struct hilite *anchor;
734 POSITION linepos;
735 int cvt_ops;
737 char *line;
738 char *oline;
739 int line_len;
740 char *line_end;
741 struct hilite *hl;
742 int checkstart;
743 POSITION opos;
744 POSITION npos;
745 LWCHAR ch;
746 int ncwidth;
749 * The line was already scanned and hilites were added (in hilite_line).
750 * But it was assumed that each char position in the line
751 * correponds to one char position in the file.
752 * This may not be true if cvt_text modified the line.
753 * Get the raw line again. Look at each character.
755 (void) forw_raw_line(linepos, &line, &line_len);
756 line_end = line + line_len;
757 opos = npos = linepos;
758 hl = anchor->hl_first;
759 checkstart = TRUE;
760 while (hl != NULL)
763 * See if we need to adjust the current hl_startpos or
764 * hl_endpos. After adjusting startpos[i], move to endpos[i].
765 * After adjusting endpos[i], move to startpos[i+1].
766 * The hilite list must be sorted thus:
767 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
769 if (checkstart && hl->hl_startpos == opos)
771 hl->hl_startpos = npos;
772 checkstart = FALSE;
773 continue; /* {{ not really necessary }} */
774 } else if (!checkstart && hl->hl_endpos == opos)
776 hl->hl_endpos = npos;
777 checkstart = TRUE;
778 hl = hl->hl_next;
779 continue; /* {{ necessary }} */
781 if (line == line_end)
782 break;
784 /* Get the next char from the line. */
785 oline = line;
786 ch = step_char(&line, +1, line_end);
787 ncwidth = line - oline;
788 npos += ncwidth;
790 /* Figure out how this char was processed by cvt_text. */
791 if ((cvt_ops & CVT_BS) && ch == '\b')
793 /* Skip the backspace and the following char. */
794 oline = line;
795 ch = step_char(&line, +1, line_end);
796 ncwidth = line - oline;
797 npos += ncwidth;
798 } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch))
800 /* Converted uppercase to lower.
801 * Note that this may have changed the number of bytes
802 * that the character occupies. */
803 char dbuf[6];
804 char *dst = dbuf;
805 put_wchar(&dst, TO_LOWER(ch));
806 opos += dst - dbuf;
807 } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch))
809 /* Skip to end of ANSI escape sequence. */
810 line++; /* skip the CSI start char */
811 npos++;
812 while (line < line_end)
814 npos++;
815 if (!is_ansi_middle(*line++))
816 break;
818 } else
820 /* Ordinary unprocessed character. */
821 opos += ncwidth;
827 * Make a hilite for each string in a physical line which matches
828 * the current pattern.
829 * sp,ep delimit the first match already found.
831 static void
832 hilite_line(linepos, line, line_len, sp, ep, cvt_ops)
833 POSITION linepos;
834 char *line;
835 int line_len;
836 char *sp;
837 char *ep;
838 int cvt_ops;
840 char *searchp;
841 char *line_end = line + line_len;
842 struct hilite *hl;
843 struct hilite hilites;
845 if (sp == NULL || ep == NULL)
846 return;
848 * sp and ep delimit the first match in the line.
849 * Mark the corresponding file positions, then
850 * look for further matches and mark them.
851 * {{ This technique, of calling match_pattern on subsequent
852 * substrings of the line, may mark more than is correct
853 * if the pattern starts with "^". This bug is fixed
854 * for those regex functions that accept a notbol parameter
855 * (currently POSIX, PCRE and V8-with-regexec2). }}
857 searchp = line;
859 * Put the hilites into a temporary list until they're adjusted.
861 hilites.hl_first = NULL;
862 do {
863 if (ep > sp)
866 * Assume that each char position in the "line"
867 * buffer corresponds to one char position in the file.
868 * This is not quite true; we need to adjust later.
870 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
871 hl->hl_startpos = linepos + (sp-line);
872 hl->hl_endpos = linepos + (ep-line);
873 add_hilite(&hilites, hl);
876 * If we matched more than zero characters,
877 * move to the first char after the string we matched.
878 * If we matched zero, just move to the next char.
880 if (ep > searchp)
881 searchp = ep;
882 else if (searchp != line_end)
883 searchp++;
884 else /* end of line */
885 break;
886 } while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1));
889 * If there were backspaces in the original line, they
890 * were removed, and hl_startpos/hl_endpos are not correct.
891 * {{ This is very ugly. }}
893 adj_hilite(&hilites, linepos, cvt_ops);
896 * Now put the hilites into the real list.
898 while ((hl = hilites.hl_next) != NULL)
900 hilites.hl_next = hl->hl_next;
901 add_hilite(&hilite_anchor, hl);
904 #endif
907 * Change the caseless-ness of searches.
908 * Updates the internal search state to reflect a change in the -i flag.
910 public void
911 chg_caseless()
913 if (!is_ucase_pattern)
915 * Pattern did not have uppercase.
916 * Just set the search caselessness to the global caselessness.
918 is_caseless = caseless;
919 else
921 * Pattern did have uppercase.
922 * Discard the pattern; we can't change search caselessness now.
924 uncompile_pattern();
927 #if HILITE_SEARCH
929 * Find matching text which is currently on screen and highlight it.
931 static void
932 hilite_screen()
934 struct scrpos scrpos;
936 get_scrpos(&scrpos);
937 if (scrpos.pos == NULL_POSITION)
938 return;
939 prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
940 repaint_hilite(1);
944 * Change highlighting parameters.
946 public void
947 chg_hilite()
950 * Erase any highlights currently on screen.
952 clr_hilite();
953 hide_hilite = 0;
955 if (hilite_search == OPT_ONPLUS)
957 * Display highlights.
959 hilite_screen();
961 #endif
964 * Figure out where to start a search.
966 static POSITION
967 search_pos(search_type)
968 int search_type;
970 POSITION pos;
971 int linenum;
973 if (empty_screen())
976 * Start at the beginning (or end) of the file.
977 * The empty_screen() case is mainly for
978 * command line initiated searches;
979 * for example, "+/xyz" on the command line.
980 * Also for multi-file (SRCH_PAST_EOF) searches.
982 if (search_type & SRCH_FORW)
984 return (ch_zero());
985 } else
987 pos = ch_length();
988 if (pos == NULL_POSITION)
990 (void) ch_end_seek();
991 pos = ch_length();
993 return (pos);
996 if (how_search)
999 * Search does not include current screen.
1001 if (search_type & SRCH_FORW)
1002 linenum = BOTTOM_PLUS_ONE;
1003 else
1004 linenum = TOP;
1005 pos = position(linenum);
1006 } else
1009 * Search includes current screen.
1010 * It starts at the jump target (if searching backwards),
1011 * or at the jump target plus one (if forwards).
1013 linenum = adjsline(jump_sline);
1014 pos = position(linenum);
1015 if (search_type & SRCH_FORW)
1017 pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
1018 while (pos == NULL_POSITION)
1020 if (++linenum >= sc_height)
1021 break;
1022 pos = position(linenum);
1024 } else
1026 while (pos == NULL_POSITION)
1028 if (--linenum < 0)
1029 break;
1030 pos = position(linenum);
1034 return (pos);
1038 * Search a subset of the file, specified by start/end position.
1040 static int
1041 search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
1042 POSITION pos;
1043 POSITION endpos;
1044 int search_type;
1045 int matches;
1046 int maxlines;
1047 POSITION *plinepos;
1048 POSITION *pendpos;
1050 char *line;
1051 char *cline;
1052 int line_len;
1053 LINENUM linenum;
1054 char *sp, *ep;
1055 int line_match;
1056 int cvt_ops;
1057 POSITION linepos, oldpos;
1059 linenum = find_linenum(pos);
1060 oldpos = pos;
1061 for (;;)
1064 * Get lines until we find a matching one or until
1065 * we hit end-of-file (or beginning-of-file if we're
1066 * going backwards), or until we hit the end position.
1068 if (ABORT_SIGS())
1071 * A signal aborts the search.
1073 return (-1);
1076 if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
1079 * Reached end position without a match.
1081 if (pendpos != NULL)
1082 *pendpos = pos;
1083 return (matches);
1085 if (maxlines > 0)
1086 maxlines--;
1088 if (search_type & SRCH_FORW)
1091 * Read the next line, and save the
1092 * starting position of that line in linepos.
1094 linepos = pos;
1095 pos = forw_raw_line(pos, &line, &line_len);
1096 if (linenum != 0)
1097 linenum++;
1098 } else
1101 * Read the previous line and save the
1102 * starting position of that line in linepos.
1104 pos = back_raw_line(pos, &line, &line_len);
1105 linepos = pos;
1106 if (linenum != 0)
1107 linenum--;
1110 if (pos == NULL_POSITION)
1113 * Reached EOF/BOF without a match.
1115 if (pendpos != NULL)
1116 *pendpos = oldpos;
1117 return (matches);
1121 * If we're using line numbers, we might as well
1122 * remember the information we have now (the position
1123 * and line number of the current line).
1124 * Don't do it for every line because it slows down
1125 * the search. Remember the line number only if
1126 * we're "far" from the last place we remembered it.
1128 if (linenums && abs((int)(pos - oldpos)) > 1024)
1129 add_lnum(linenum, pos);
1130 oldpos = pos;
1133 * If it's a caseless search, convert the line to lowercase.
1134 * If we're doing backspace processing, delete backspaces.
1136 cvt_ops = get_cvt_ops();
1137 cline = calloc(1, cvt_length(line_len, cvt_ops));
1138 cvt_text(cline, line, &line_len, cvt_ops);
1141 * Test the next line to see if we have a match.
1142 * We are successful if we either want a match and got one,
1143 * or if we want a non-match and got one.
1145 line_match = match_pattern(cline, line_len, &sp, &ep, 0);
1146 line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
1147 ((search_type & SRCH_NO_MATCH) && !line_match);
1148 if (!line_match)
1150 free(cline);
1151 continue;
1154 * Got a match.
1156 if (search_type & SRCH_FIND_ALL)
1158 #if HILITE_SEARCH
1160 * We are supposed to find all matches in the range.
1161 * Just add the matches in this line to the
1162 * hilite list and keep searching.
1164 if (line_match)
1165 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
1166 #endif
1167 free(cline);
1168 } else if (--matches <= 0)
1171 * Found the one match we're looking for.
1172 * Return it.
1174 #if HILITE_SEARCH
1175 if (hilite_search == OPT_ON)
1178 * Clear the hilite list and add only
1179 * the matches in this one line.
1181 clr_hilite();
1182 if (line_match)
1183 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
1185 #endif
1186 free(cline);
1187 if (plinepos != NULL)
1188 *plinepos = linepos;
1189 return (0);
1195 * search for a pattern in history. If found, compile that pattern.
1197 static int
1198 hist_pattern(search_type)
1199 int search_type;
1201 #if CMD_HISTORY
1202 char *pattern;
1204 set_mlist(ml_search, 0);
1205 pattern = cmd_lastpattern();
1206 if (pattern == NULL)
1207 return (0);
1209 if (compile_pattern(pattern, search_type) < 0)
1210 return (0);
1212 is_ucase_pattern = is_ucase(pattern);
1213 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1214 is_caseless = 0;
1215 else
1216 is_caseless = caseless;
1218 #if HILITE_SEARCH
1219 if (hilite_search == OPT_ONPLUS && !hide_hilite)
1220 hilite_screen();
1221 #endif
1223 return (1);
1224 #else /* CMD_HISTORY */
1225 return (0);
1226 #endif /* CMD_HISTORY */
1230 * Search for the n-th occurrence of a specified pattern,
1231 * either forward or backward.
1232 * Return the number of matches not yet found in this file
1233 * (that is, n minus the number of matches found).
1234 * Return -1 if the search should be aborted.
1235 * Caller may continue the search in another file
1236 * if less than n matches are found in this file.
1238 public int
1239 search(search_type, pattern, n)
1240 int search_type;
1241 char *pattern;
1242 int n;
1244 POSITION pos;
1245 int result;
1247 if (pattern == NULL || *pattern == '\0')
1250 * A null pattern means use the previously compiled pattern.
1252 if (!prev_pattern() && !hist_pattern(search_type))
1254 error("No previous regular expression", NULL_PARG);
1255 return (-1);
1257 if ((search_type & SRCH_NO_REGEX) !=
1258 (last_search_type & SRCH_NO_REGEX))
1260 error("Please re-enter search pattern", NULL_PARG);
1261 return -1;
1263 #if HILITE_SEARCH
1264 if (hilite_search == OPT_ON)
1267 * Erase the highlights currently on screen.
1268 * If the search fails, we'll redisplay them later.
1270 repaint_hilite(0);
1272 if (hilite_search == OPT_ONPLUS && hide_hilite)
1275 * Highlight any matches currently on screen,
1276 * before we actually start the search.
1278 hide_hilite = 0;
1279 hilite_screen();
1281 hide_hilite = 0;
1282 #endif
1283 } else
1286 * Compile the pattern.
1288 if (compile_pattern(pattern, search_type) < 0)
1289 return (-1);
1291 * Ignore case if -I is set OR
1292 * -i is set AND the pattern is all lowercase.
1294 is_ucase_pattern = is_ucase(pattern);
1295 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1296 is_caseless = 0;
1297 else
1298 is_caseless = caseless;
1299 #if HILITE_SEARCH
1300 if (hilite_search)
1303 * Erase the highlights currently on screen.
1304 * Also permanently delete them from the hilite list.
1306 repaint_hilite(0);
1307 hide_hilite = 0;
1308 clr_hilite();
1310 if (hilite_search == OPT_ONPLUS)
1313 * Highlight any matches currently on screen,
1314 * before we actually start the search.
1316 hilite_screen();
1318 #endif
1322 * Figure out where to start the search.
1324 pos = search_pos(search_type);
1325 if (pos == NULL_POSITION)
1328 * Can't find anyplace to start searching from.
1330 if (search_type & SRCH_PAST_EOF)
1331 return (n);
1332 /* repaint(); -- why was this here? */
1333 error("Nothing to search", NULL_PARG);
1334 return (-1);
1337 n = search_range(pos, NULL_POSITION, search_type, n, -1,
1338 &pos, (POSITION*)NULL);
1339 if (n != 0)
1342 * Search was unsuccessful.
1344 #if HILITE_SEARCH
1345 if (hilite_search == OPT_ON && n > 0)
1347 * Redisplay old hilites.
1349 repaint_hilite(1);
1350 #endif
1351 return (n);
1354 if (!(search_type & SRCH_NO_MOVE))
1357 * Go to the matching line.
1359 jump_loc(pos, jump_sline);
1362 #if HILITE_SEARCH
1363 if (hilite_search == OPT_ON)
1365 * Display new hilites in the matching line.
1367 repaint_hilite(1);
1368 #endif
1369 return (0);
1373 #if HILITE_SEARCH
1375 * Prepare hilites in a given range of the file.
1377 * The pair (prep_startpos,prep_endpos) delimits a contiguous region
1378 * of the file that has been "prepared"; that is, scanned for matches for
1379 * the current search pattern, and hilites have been created for such matches.
1380 * If prep_startpos == NULL_POSITION, the prep region is empty.
1381 * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
1382 * prep_hilite asks that the range (spos,epos) be covered by the prep region.
1384 public void
1385 prep_hilite(spos, epos, maxlines)
1386 POSITION spos;
1387 POSITION epos;
1388 int maxlines;
1390 POSITION nprep_startpos = prep_startpos;
1391 POSITION nprep_endpos = prep_endpos;
1392 POSITION new_epos;
1393 POSITION max_epos;
1394 int result;
1395 int i;
1397 * Search beyond where we're asked to search, so the prep region covers
1398 * more than we need. Do one big search instead of a bunch of small ones.
1400 #define SEARCH_MORE (3*size_linebuf)
1402 if (!prev_pattern())
1403 return;
1406 * If we're limited to a max number of lines, figure out the
1407 * file position we should stop at.
1409 if (maxlines < 0)
1410 max_epos = NULL_POSITION;
1411 else
1413 max_epos = spos;
1414 for (i = 0; i < maxlines; i++)
1415 max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
1419 * Find two ranges:
1420 * The range that we need to search (spos,epos); and the range that
1421 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
1424 if (prep_startpos == NULL_POSITION ||
1425 (epos != NULL_POSITION && epos < prep_startpos) ||
1426 spos > prep_endpos)
1429 * New range is not contiguous with old prep region.
1430 * Discard the old prep region and start a new one.
1432 clr_hilite();
1433 if (epos != NULL_POSITION)
1434 epos += SEARCH_MORE;
1435 nprep_startpos = spos;
1436 } else
1439 * New range partially or completely overlaps old prep region.
1441 if (epos == NULL_POSITION)
1444 * New range goes to end of file.
1447 } else if (epos > prep_endpos)
1450 * New range ends after old prep region.
1451 * Extend prep region to end at end of new range.
1453 epos += SEARCH_MORE;
1454 } else /* (epos <= prep_endpos) */
1457 * New range ends within old prep region.
1458 * Truncate search to end at start of old prep region.
1460 epos = prep_startpos;
1463 if (spos < prep_startpos)
1466 * New range starts before old prep region.
1467 * Extend old prep region backwards to start at
1468 * start of new range.
1470 if (spos < SEARCH_MORE)
1471 spos = 0;
1472 else
1473 spos -= SEARCH_MORE;
1474 nprep_startpos = spos;
1475 } else /* (spos >= prep_startpos) */
1478 * New range starts within or after old prep region.
1479 * Trim search to start at end of old prep region.
1481 spos = prep_endpos;
1485 if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
1486 epos > max_epos)
1488 * Don't go past the max position we're allowed.
1490 epos = max_epos;
1492 if (epos == NULL_POSITION || epos > spos)
1494 result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
1495 maxlines, (POSITION*)NULL, &new_epos);
1496 if (result < 0)
1497 return;
1498 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
1499 nprep_endpos = new_epos;
1501 prep_startpos = nprep_startpos;
1502 prep_endpos = nprep_endpos;
1504 #endif
1507 * Simple pattern matching function.
1508 * It supports no metacharacters like *, etc.
1510 static int
1511 match(pattern, pattern_len, buf, buf_len, pfound, pend)
1512 char *pattern;
1513 int pattern_len;
1514 char *buf;
1515 int buf_len;
1516 char **pfound, **pend;
1518 register char *pp, *lp;
1519 register char *pattern_end = pattern + pattern_len;
1520 register char *buf_end = buf + buf_len;
1522 for ( ; buf < buf_end; buf++)
1524 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
1525 if (pp == pattern_end || lp == buf_end)
1526 break;
1527 if (pp == pattern_end)
1529 if (pfound != NULL)
1530 *pfound = buf;
1531 if (pend != NULL)
1532 *pend = lp;
1533 return (1);
1536 return (0);
1539 #if HAVE_V8_REGCOMP
1541 * This function is called by the V8 regcomp to report
1542 * errors in regular expressions.
1544 void
1545 regerror(s)
1546 char *s;
1548 PARG parg;
1550 parg.p_string = s;
1551 error("%s", &parg);
1553 #endif