priv: Define and use PRIV_VARSYM_SYS
[dragonfly.git] / contrib / less / search.c
blob14fc10b181b7b8d25af246945737aaa401f20e6d
1 /*
2 * Copyright (C) 1984-2008 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 extern int utf_mode;
62 extern int screen_trashed;
63 #if HILITE_SEARCH
64 extern int hilite_search;
65 extern int size_linebuf;
66 extern int squished;
67 extern int can_goto_line;
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 static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION };
81 #define hl_first hl_next
82 #endif
85 * These are the static variables that represent the "remembered"
86 * search pattern.
88 #if HAVE_POSIX_REGCOMP
89 #define DEFINE_PATTERN(name) static regex_t *name = NULL
90 #endif
91 #if HAVE_PCRE
92 #define DEFINE_PATTERN(name) pcre *name = NULL;
93 #endif
94 #if HAVE_RE_COMP
95 #define DEFINE_PATTERN(name) int name = 0;
96 #endif
97 #if HAVE_REGCMP
98 #define DEFINE_PATTERN(name) static char *name = NULL;
99 #endif
100 #if HAVE_V8_REGCOMP
101 #define DEFINE_PATTERN(name) static struct regexp *name = NULL;
102 #endif
104 DEFINE_PATTERN(search_pattern);
105 DEFINE_PATTERN(filter_pattern);
107 static int is_caseless;
108 static int is_ucase_pattern;
109 static int last_search_type;
110 static int last_filter_type;
111 static char *last_pattern = NULL;
113 #define CVT_TO_LC 01 /* Convert upper-case to lower-case */
114 #define CVT_BS 02 /* Do backspace processing */
115 #define CVT_CRLF 04 /* Remove CR after LF */
116 #define CVT_ANSI 010 /* Remove ANSI escape sequences */
119 * Get the length of a buffer needed to convert a string.
121 static int
122 cvt_length(len, ops)
123 int len;
124 int ops;
126 if (utf_mode)
128 * Just copying a string in UTF-8 mode can cause it to grow
129 * in length.
130 * Six output bytes for one input byte is the worst case
131 * (and unfortunately is far more than is needed in any
132 * non-pathological situation, so this is very wasteful).
134 len *= 6;
135 return len + 1;
139 * Convert text. Perform the transformations specified by ops.
141 static void
142 cvt_text(odst, osrc, lenp, ops)
143 char *odst;
144 char *osrc;
145 int *lenp;
146 int ops;
148 char *dst;
149 char *src;
150 register char *src_end;
151 LWCHAR ch;
153 if (lenp != NULL)
154 src_end = osrc + *lenp;
155 else
156 src_end = osrc + strlen(osrc);
158 for (src = osrc, dst = odst; src < src_end; )
160 ch = step_char(&src, +1, src_end);
161 if ((ops & CVT_TO_LC) && IS_UPPER(ch))
163 /* Convert uppercase to lowercase. */
164 put_wchar(&dst, TO_LOWER(ch));
165 } else if ((ops & CVT_BS) && ch == '\b' && dst > odst)
167 /* Delete backspace and preceding char. */
168 do {
169 dst--;
170 } while (dst > odst &&
171 !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
172 } else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
174 /* Skip to end of ANSI escape sequence. */
175 src++; /* skip the CSI start char */
176 while (src < src_end)
177 if (!is_ansi_middle(*src++))
178 break;
179 } else
180 /* Just copy. */
181 put_wchar(&dst, ch);
183 if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
184 dst--;
185 *dst = '\0';
186 if (lenp != NULL)
187 *lenp = dst - odst;
191 * Determine which conversions to perform.
193 static int
194 get_cvt_ops()
196 int ops = 0;
197 if (is_caseless || bs_mode == BS_SPECIAL)
199 if (is_caseless)
200 ops |= CVT_TO_LC;
201 if (bs_mode == BS_SPECIAL)
202 ops |= CVT_BS;
203 if (bs_mode != BS_CONTROL)
204 ops |= CVT_CRLF;
205 } else if (bs_mode != BS_CONTROL)
207 ops |= CVT_CRLF;
209 if (ctldisp == OPT_ONPLUS)
210 ops |= CVT_ANSI;
211 return (ops);
215 * Are there any uppercase letters in this string?
217 static int
218 is_ucase(str)
219 char *str;
221 char *str_end = str + strlen(str);
222 LWCHAR ch;
224 while (str < str_end)
226 ch = step_char(&str, +1, str_end);
227 if (IS_UPPER(ch))
228 return (1);
230 return (0);
234 * Is there a previous (remembered) search pattern?
236 static int
237 prev_pattern()
239 if (last_search_type & SRCH_NO_REGEX)
240 return (last_pattern != NULL);
241 #if HAVE_POSIX_REGCOMP
242 return (search_pattern != NULL);
243 #endif
244 #if HAVE_PCRE
245 return (search_pattern != NULL);
246 #endif
247 #if HAVE_RE_COMP
248 return (search_pattern != 0);
249 #endif
250 #if HAVE_REGCMP
251 return (search_pattern != NULL);
252 #endif
253 #if HAVE_V8_REGCOMP
254 return (search_pattern != NULL);
255 #endif
256 #if NO_REGEX
257 return (search_pattern != NULL);
258 #endif
261 #if HILITE_SEARCH
263 * Repaint the hilites currently displayed on the screen.
264 * Repaint each line which contains highlighted text.
265 * If on==0, force all hilites off.
267 public void
268 repaint_hilite(on)
269 int on;
271 int slinenum;
272 POSITION pos;
273 POSITION epos;
274 int save_hide_hilite;
276 if (squished)
277 repaint();
279 save_hide_hilite = hide_hilite;
280 if (!on)
282 if (hide_hilite)
283 return;
284 hide_hilite = 1;
287 if (!can_goto_line)
289 repaint();
290 hide_hilite = save_hide_hilite;
291 return;
294 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
296 pos = position(slinenum);
297 if (pos == NULL_POSITION)
298 continue;
299 epos = position(slinenum+1);
300 #if 0
302 * If any character in the line is highlighted,
303 * repaint the line.
305 * {{ This doesn't work -- if line is drawn with highlights
306 * which should be erased (e.g. toggle -i with status column),
307 * we must redraw the line even if it has no highlights.
308 * For now, just repaint every line. }}
310 if (is_hilited(pos, epos, 1, NULL))
311 #endif
313 (void) forw_line(pos);
314 goto_line(slinenum);
315 put_line();
318 if (!oldbot)
319 lower_left();
320 hide_hilite = save_hide_hilite;
324 * Clear the attn hilite.
326 public void
327 clear_attn()
329 int slinenum;
330 POSITION old_start_attnpos;
331 POSITION old_end_attnpos;
332 POSITION pos;
333 POSITION epos;
334 int moved = 0;
336 if (start_attnpos == NULL_POSITION)
337 return;
338 old_start_attnpos = start_attnpos;
339 old_end_attnpos = end_attnpos;
340 start_attnpos = end_attnpos = NULL_POSITION;
342 if (!can_goto_line)
344 repaint();
345 return;
347 if (squished)
348 repaint();
350 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
352 pos = position(slinenum);
353 if (pos == NULL_POSITION)
354 continue;
355 epos = position(slinenum+1);
356 if (pos < old_end_attnpos &&
357 (epos == NULL_POSITION || epos > old_start_attnpos))
359 (void) forw_line(pos);
360 goto_line(slinenum);
361 put_line();
362 moved = 1;
365 if (moved)
366 lower_left();
368 #endif
371 * Hide search string highlighting.
373 public void
374 undo_search()
376 if (!prev_pattern())
378 error("No previous regular expression", NULL_PARG);
379 return;
381 #if HILITE_SEARCH
382 hide_hilite = !hide_hilite;
383 repaint_hilite(1);
384 #endif
388 * Compile a search pattern, for future use by match_pattern.
390 static int
391 compile_pattern2(pattern, search_type, comp_pattern)
392 char *pattern;
393 int search_type;
394 void **comp_pattern;
396 if ((search_type & SRCH_NO_REGEX) == 0)
398 #if HAVE_POSIX_REGCOMP
399 regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
400 regex_t **pcomp = (regex_t **) comp_pattern;
401 if (regcomp(comp, pattern, REGCOMP_FLAG))
403 free(comp);
404 error("Invalid pattern", NULL_PARG);
405 return (-1);
407 if (*pcomp != NULL)
408 regfree(*pcomp);
409 *pcomp = comp;
410 #endif
411 #if HAVE_PCRE
412 pcre *comp;
413 pcre **pcomp = (pcre **) comp_pattern;
414 const char *errstring;
415 int erroffset;
416 PARG parg;
417 comp = pcre_compile(pattern, 0,
418 &errstring, &erroffset, NULL);
419 if (comp == NULL)
421 parg.p_string = (char *) errstring;
422 error("%s", &parg);
423 return (-1);
425 *pcomp = comp;
426 #endif
427 #if HAVE_RE_COMP
428 PARG parg;
429 int *pcomp = (int *) comp_pattern;
430 if ((parg.p_string = re_comp(pattern)) != NULL)
432 error("%s", &parg);
433 return (-1);
435 *pcomp = 1;
436 #endif
437 #if HAVE_REGCMP
438 char *comp;
439 char **pcomp = (char **) comp_pattern;
440 if ((comp = regcmp(pattern, 0)) == NULL)
442 error("Invalid pattern", NULL_PARG);
443 return (-1);
445 if (pcomp != NULL)
446 free(*pcomp);
447 *pcomp = comp;
448 #endif
449 #if HAVE_V8_REGCOMP
450 struct regexp *comp;
451 struct regexp **pcomp = (struct regexp **) comp_pattern;
452 if ((comp = regcomp(pattern)) == NULL)
455 * regcomp has already printed an error message
456 * via regerror().
458 return (-1);
460 if (*pcomp != NULL)
461 free(*pcomp);
462 *pcomp = comp;
463 #endif
466 if (comp_pattern == (void **) &search_pattern)
468 if (last_pattern != NULL)
469 free(last_pattern);
470 last_pattern = (char *) calloc(1, strlen(pattern)+1);
471 if (last_pattern != NULL)
472 strcpy(last_pattern, pattern);
473 last_search_type = search_type;
474 } else
476 last_filter_type = search_type;
478 return (0);
482 * Like compile_pattern2, but convert the pattern to lowercase if necessary.
484 static int
485 compile_pattern(pattern, search_type, comp_pattern)
486 char *pattern;
487 int search_type;
488 void **comp_pattern;
490 char *cvt_pattern;
491 int result;
493 if (caseless != OPT_ONPLUS)
494 cvt_pattern = pattern;
495 else
497 cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
498 cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC);
500 result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
501 if (cvt_pattern != pattern)
502 free(cvt_pattern);
503 return (result);
507 * Forget that we have a compiled pattern.
509 static void
510 uncompile_pattern(pattern)
511 void **pattern;
513 #if HAVE_POSIX_REGCOMP
514 regex_t **pcomp = (regex_t **) pattern;
515 if (*pcomp != NULL)
516 regfree(*pcomp);
517 *pcomp = NULL;
518 #endif
519 #if HAVE_PCRE
520 pcre **pcomp = (pcre **) pattern;
521 if (*pcomp != NULL)
522 pcre_free(*pcomp);
523 *pcomp = NULL;
524 #endif
525 #if HAVE_RE_COMP
526 int *pcomp = (int *) pattern;
527 *pcomp = 0;
528 #endif
529 #if HAVE_REGCMP
530 char **pcomp = (char **) pattern;
531 if (*pcomp != NULL)
532 free(*pcomp);
533 *pcomp = NULL;
534 #endif
535 #if HAVE_V8_REGCOMP
536 struct regexp **pcomp = (struct regexp **) pattern;
537 if (*pcomp != NULL)
538 free(*pcomp);
539 *pcomp = NULL;
540 #endif
543 static void
544 uncompile_search_pattern()
546 uncompile_pattern(&search_pattern);
547 last_pattern = NULL;
550 static void
551 uncompile_filter_pattern()
553 uncompile_pattern(&filter_pattern);
557 * Is a compiled pattern null?
559 static int
560 is_null_pattern(pattern)
561 void *pattern;
563 #if HAVE_POSIX_REGCOMP
564 return (pattern == NULL);
565 #endif
566 #if HAVE_PCRE
567 return (pattern == NULL);
568 #endif
569 #if HAVE_RE_COMP
570 return (pattern == 0);
571 #endif
572 #if HAVE_REGCMP
573 return (pattern == NULL);
574 #endif
575 #if HAVE_V8_REGCOMP
576 return (pattern == NULL);
577 #endif
581 * Perform a pattern match with the previously compiled pattern.
582 * Set sp and ep to the start and end of the matched string.
584 static int
585 match_pattern(pattern, line, line_len, sp, ep, notbol, search_type)
586 void *pattern;
587 char *line;
588 int line_len;
589 char **sp;
590 char **ep;
591 int notbol;
592 int search_type;
594 int matched;
595 #if HAVE_POSIX_REGCOMP
596 regex_t *spattern = (regex_t *) pattern;
597 #endif
598 #if HAVE_PCRE
599 pcre *spattern = (pcre *) pattern;
600 #endif
601 #if HAVE_RE_COMP
602 int spattern = (int) pattern;
603 #endif
604 #if HAVE_REGCMP
605 char *spattern = (char *) pattern;
606 #endif
607 #if HAVE_V8_REGCOMP
608 struct regexp *spattern = (struct regexp *) pattern;
609 #endif
611 if (search_type & SRCH_NO_REGEX)
612 return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
614 #if HAVE_POSIX_REGCOMP
616 regmatch_t rm;
617 int flags = (notbol) ? REG_NOTBOL : 0;
618 matched = !regexec(spattern, line, 1, &rm, flags);
619 if (matched)
621 #ifndef __WATCOMC__
622 *sp = line + rm.rm_so;
623 *ep = line + rm.rm_eo;
624 #else
625 *sp = rm.rm_sp;
626 *ep = rm.rm_ep;
627 #endif
630 #endif
631 #if HAVE_PCRE
633 int flags = (notbol) ? PCRE_NOTBOL : 0;
634 int ovector[3];
635 matched = pcre_exec(spattern, NULL, line, line_len,
636 0, flags, ovector, 3) >= 0;
637 if (matched)
639 *sp = line + ovector[0];
640 *ep = line + ovector[1];
643 #endif
644 #if HAVE_RE_COMP
645 matched = (re_exec(line) == 1);
647 * re_exec doesn't seem to provide a way to get the matched string.
649 *sp = *ep = NULL;
650 #endif
651 #if HAVE_REGCMP
652 *ep = regex(spattern, line);
653 matched = (*ep != NULL);
654 if (matched)
655 *sp = __loc1;
656 #endif
657 #if HAVE_V8_REGCOMP
658 #if HAVE_REGEXEC2
659 matched = regexec2(spattern, line, notbol);
660 #else
661 matched = regexec(spattern, line);
662 #endif
663 if (matched)
665 *sp = spattern->startp[0];
666 *ep = spattern->endp[0];
668 #endif
669 #if NO_REGEX
670 matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
671 #endif
672 matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
673 ((search_type & SRCH_NO_MATCH) && !matched);
674 return (matched);
677 #if HILITE_SEARCH
679 * Clear the hilite list.
681 public void
682 clr_hlist(anchor)
683 struct hilite *anchor;
685 struct hilite *hl;
686 struct hilite *nexthl;
688 for (hl = anchor->hl_first; hl != NULL; hl = nexthl)
690 nexthl = hl->hl_next;
691 free((void*)hl);
693 anchor->hl_first = NULL;
694 prep_startpos = prep_endpos = NULL_POSITION;
697 public void
698 clr_hilite()
700 clr_hlist(&hilite_anchor);
703 public void
704 clr_filter()
706 clr_hlist(&filter_anchor);
710 * Should any characters in a specified range be highlighted?
712 static int
713 is_hilited_range(pos, epos)
714 POSITION pos;
715 POSITION epos;
717 struct hilite *hl;
720 * Look at each highlight and see if any part of it falls in the range.
722 for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next)
724 if (hl->hl_endpos > pos &&
725 (epos == NULL_POSITION || epos > hl->hl_startpos))
726 return (1);
728 return (0);
732 * Is a line "filtered" -- that is, should it be hidden?
734 public int
735 is_filtered(pos)
736 POSITION pos;
738 struct hilite *hl;
740 if (ch_getflags() & CH_HELPFILE)
741 return (0);
744 * Look at each filter and see if the start position
745 * equals the start position of the line.
747 for (hl = filter_anchor.hl_first; hl != NULL; hl = hl->hl_next)
749 if (hl->hl_startpos == pos)
750 return (1);
752 return (0);
756 * Should any characters in a specified range be highlighted?
757 * If nohide is nonzero, don't consider hide_hilite.
759 public int
760 is_hilited(pos, epos, nohide, p_matches)
761 POSITION pos;
762 POSITION epos;
763 int nohide;
764 int *p_matches;
766 int match;
768 if (p_matches != NULL)
769 *p_matches = 0;
771 if (!status_col &&
772 start_attnpos != NULL_POSITION &&
773 pos < end_attnpos &&
774 (epos == NULL_POSITION || epos > start_attnpos))
776 * The attn line overlaps this range.
778 return (1);
780 match = is_hilited_range(pos, epos);
781 if (!match)
782 return (0);
784 if (p_matches != NULL)
786 * Report matches, even if we're hiding highlights.
788 *p_matches = 1;
790 if (hilite_search == 0)
792 * Not doing highlighting.
794 return (0);
796 if (!nohide && hide_hilite)
798 * Highlighting is hidden.
800 return (0);
802 return (1);
806 * Add a new hilite to a hilite list.
808 static void
809 add_hilite(anchor, hl)
810 struct hilite *anchor;
811 struct hilite *hl;
813 struct hilite *ihl;
816 * Hilites are sorted in the list; find where new one belongs.
817 * Insert new one after ihl.
819 for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next)
821 if (ihl->hl_next->hl_startpos > hl->hl_startpos)
822 break;
826 * Truncate hilite so it doesn't overlap any existing ones
827 * above and below it.
829 if (ihl != anchor)
830 hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
831 if (ihl->hl_next != NULL)
832 hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
833 if (hl->hl_startpos >= hl->hl_endpos)
836 * Hilite was truncated out of existence.
838 free(hl);
839 return;
841 hl->hl_next = ihl->hl_next;
842 ihl->hl_next = hl;
846 * Adjust hl_startpos & hl_endpos to account for processing by cvt_text.
848 static void
849 adj_hilite(anchor, linepos, cvt_ops)
850 struct hilite *anchor;
851 POSITION linepos;
852 int cvt_ops;
854 char *line;
855 char *oline;
856 int line_len;
857 char *line_end;
858 struct hilite *hl;
859 int checkstart;
860 POSITION opos;
861 POSITION npos;
862 POSITION hl_opos;
863 POSITION hl_npos;
864 LWCHAR ch;
865 int ncwidth;
868 * The line was already scanned and hilites were added (in hilite_line).
869 * But it was assumed that each char position in the line
870 * correponds to one char position in the file.
871 * This may not be true if cvt_text modified the line.
872 * Get the raw line again. Look at each character.
874 (void) forw_raw_line(linepos, &line, &line_len);
875 line_end = line + line_len;
876 opos = npos = linepos;
877 hl = anchor->hl_first;
878 if (hl == NULL)
879 return;
880 hl_opos = hl_npos = hl->hl_startpos;
881 checkstart = TRUE;
883 while (hl != NULL && line < line_end)
886 * See if we need to adjust the current hl_startpos or
887 * hl_endpos. After adjusting startpos[i], move to endpos[i].
888 * After adjusting endpos[i], move to startpos[i+1].
889 * The hilite list must be sorted thus:
890 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
892 oline = line;
893 ch = step_char(&line, +1, line_end);
894 ncwidth = line - oline;
895 npos += ncwidth;
897 /* Figure out how this char was processed by cvt_text. */
898 if ((cvt_ops & CVT_BS) && ch == '\b')
900 /* Skip the backspace and the following char. */
901 oline = line;
902 ch = step_char(&line, +1, line_end);
903 ncwidth = line - oline;
904 npos += ncwidth;
905 } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch))
907 /* Converted uppercase to lower.
908 * Note that this may have changed the number of bytes
909 * that the character occupies. */
910 char dbuf[6];
911 char *dst = dbuf;
912 put_wchar(&dst, TO_LOWER(ch));
913 opos += dst - dbuf;
914 } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch))
916 /* Skip to end of ANSI escape sequence. */
917 line++; /* skip the CSI start char */
918 npos++;
919 while (line < line_end)
921 npos++;
922 if (!is_ansi_middle(*line++))
923 break;
925 } else
927 /* Ordinary unprocessed character. */
928 opos += ncwidth;
931 if (opos == hl_opos) {
932 /* Adjust highlight position. */
933 hl_npos = npos;
935 if (opos > hl_opos)
938 * We've moved past the highlight position; store the
939 * adjusted highlight position and move to the next highlight.
941 if (checkstart)
943 hl->hl_startpos = hl_npos;
944 hl_opos = hl->hl_endpos;
945 checkstart = FALSE;
946 } else
948 hl->hl_endpos = hl_npos;
949 hl = hl->hl_next;
950 if (hl != NULL)
951 hl_opos = hl->hl_startpos;
952 checkstart = TRUE;
954 hl_npos = npos;
960 * Make a hilite for each string in a physical line which matches
961 * the current pattern.
962 * sp,ep delimit the first match already found.
964 static void
965 hilite_line(linepos, line, line_len, sp, ep, cvt_ops)
966 POSITION linepos;
967 char *line;
968 int line_len;
969 char *sp;
970 char *ep;
971 int cvt_ops;
973 char *searchp;
974 char *line_end = line + line_len;
975 struct hilite *hl;
976 struct hilite hilites;
978 if (sp == NULL || ep == NULL)
979 return;
981 * sp and ep delimit the first match in the line.
982 * Mark the corresponding file positions, then
983 * look for further matches and mark them.
984 * {{ This technique, of calling match_pattern on subsequent
985 * substrings of the line, may mark more than is correct
986 * if the pattern starts with "^". This bug is fixed
987 * for those regex functions that accept a notbol parameter
988 * (currently POSIX, PCRE and V8-with-regexec2). }}
990 searchp = line;
992 * Put the hilites into a temporary list until they're adjusted.
994 hilites.hl_first = NULL;
995 do {
996 if (ep > sp)
999 * Assume that each char position in the "line"
1000 * buffer corresponds to one char position in the file.
1001 * This is not quite true; we need to adjust later.
1003 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
1004 hl->hl_startpos = linepos + (sp-line);
1005 hl->hl_endpos = linepos + (ep-line);
1006 add_hilite(&hilites, hl);
1009 * If we matched more than zero characters,
1010 * move to the first char after the string we matched.
1011 * If we matched zero, just move to the next char.
1013 if (ep > searchp)
1014 searchp = ep;
1015 else if (searchp != line_end)
1016 searchp++;
1017 else /* end of line */
1018 break;
1019 } while (match_pattern(search_pattern, searchp, line_end - searchp, &sp, &ep, 1, last_search_type));
1022 * If there were backspaces in the original line, they
1023 * were removed, and hl_startpos/hl_endpos are not correct.
1024 * {{ This is very ugly. }}
1026 adj_hilite(&hilites, linepos, cvt_ops);
1029 * Now put the hilites into the real list.
1031 while ((hl = hilites.hl_next) != NULL)
1033 hilites.hl_next = hl->hl_next;
1034 add_hilite(&hilite_anchor, hl);
1037 #endif
1040 * Change the caseless-ness of searches.
1041 * Updates the internal search state to reflect a change in the -i flag.
1043 public void
1044 chg_caseless()
1046 if (!is_ucase_pattern)
1048 * Pattern did not have uppercase.
1049 * Just set the search caselessness to the global caselessness.
1051 is_caseless = caseless;
1052 else
1054 * Pattern did have uppercase.
1055 * Discard the pattern; we can't change search caselessness now.
1057 uncompile_search_pattern();
1060 #if HILITE_SEARCH
1062 * Find matching text which is currently on screen and highlight it.
1064 static void
1065 hilite_screen()
1067 struct scrpos scrpos;
1069 get_scrpos(&scrpos);
1070 if (scrpos.pos == NULL_POSITION)
1071 return;
1072 prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
1073 repaint_hilite(1);
1077 * Change highlighting parameters.
1079 public void
1080 chg_hilite()
1083 * Erase any highlights currently on screen.
1085 clr_hilite();
1086 hide_hilite = 0;
1088 if (hilite_search == OPT_ONPLUS)
1090 * Display highlights.
1092 hilite_screen();
1094 #endif
1097 * Figure out where to start a search.
1099 static POSITION
1100 search_pos(search_type)
1101 int search_type;
1103 POSITION pos;
1104 int linenum;
1106 if (empty_screen())
1109 * Start at the beginning (or end) of the file.
1110 * The empty_screen() case is mainly for
1111 * command line initiated searches;
1112 * for example, "+/xyz" on the command line.
1113 * Also for multi-file (SRCH_PAST_EOF) searches.
1115 if (search_type & SRCH_FORW)
1117 return (ch_zero());
1118 } else
1120 pos = ch_length();
1121 if (pos == NULL_POSITION)
1123 (void) ch_end_seek();
1124 pos = ch_length();
1126 return (pos);
1129 if (how_search)
1132 * Search does not include current screen.
1134 if (search_type & SRCH_FORW)
1135 linenum = BOTTOM_PLUS_ONE;
1136 else
1137 linenum = TOP;
1138 pos = position(linenum);
1139 } else
1142 * Search includes current screen.
1143 * It starts at the jump target (if searching backwards),
1144 * or at the jump target plus one (if forwards).
1146 linenum = adjsline(jump_sline);
1147 pos = position(linenum);
1148 if (search_type & SRCH_FORW)
1150 pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
1151 while (pos == NULL_POSITION)
1153 if (++linenum >= sc_height)
1154 break;
1155 pos = position(linenum);
1157 } else
1159 while (pos == NULL_POSITION)
1161 if (--linenum < 0)
1162 break;
1163 pos = position(linenum);
1167 return (pos);
1171 * Search a subset of the file, specified by start/end position.
1173 static int
1174 search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
1175 POSITION pos;
1176 POSITION endpos;
1177 int search_type;
1178 int matches;
1179 int maxlines;
1180 POSITION *plinepos;
1181 POSITION *pendpos;
1183 char *line;
1184 char *cline;
1185 int line_len;
1186 LINENUM linenum;
1187 char *sp, *ep;
1188 int line_match;
1189 int cvt_ops;
1190 POSITION linepos, oldpos;
1192 linenum = find_linenum(pos);
1193 oldpos = pos;
1194 for (;;)
1197 * Get lines until we find a matching one or until
1198 * we hit end-of-file (or beginning-of-file if we're
1199 * going backwards), or until we hit the end position.
1201 if (ABORT_SIGS())
1204 * A signal aborts the search.
1206 return (-1);
1209 if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
1212 * Reached end position without a match.
1214 if (pendpos != NULL)
1215 *pendpos = pos;
1216 return (matches);
1218 if (maxlines > 0)
1219 maxlines--;
1221 if (search_type & SRCH_FORW)
1224 * Read the next line, and save the
1225 * starting position of that line in linepos.
1227 linepos = pos;
1228 pos = forw_raw_line(pos, &line, &line_len);
1229 if (linenum != 0)
1230 linenum++;
1231 } else
1234 * Read the previous line and save the
1235 * starting position of that line in linepos.
1237 pos = back_raw_line(pos, &line, &line_len);
1238 linepos = pos;
1239 if (linenum != 0)
1240 linenum--;
1243 if (pos == NULL_POSITION)
1246 * Reached EOF/BOF without a match.
1248 if (pendpos != NULL)
1249 *pendpos = oldpos;
1250 return (matches);
1254 * If we're using line numbers, we might as well
1255 * remember the information we have now (the position
1256 * and line number of the current line).
1257 * Don't do it for every line because it slows down
1258 * the search. Remember the line number only if
1259 * we're "far" from the last place we remembered it.
1261 if (linenums && abs((int)(pos - oldpos)) > 1024)
1262 add_lnum(linenum, pos);
1263 oldpos = pos;
1265 if (is_filtered(linepos))
1266 continue;
1269 * If it's a caseless search, convert the line to lowercase.
1270 * If we're doing backspace processing, delete backspaces.
1272 cvt_ops = get_cvt_ops();
1273 cline = calloc(1, cvt_length(line_len, cvt_ops));
1274 cvt_text(cline, line, &line_len, cvt_ops);
1276 #if HILITE_SEARCH
1278 * Check to see if the line matches the filter pattern.
1279 * If so, add an entry to the filter list.
1281 if ((search_type & SRCH_FIND_ALL) &&
1282 !is_null_pattern(filter_pattern))
1284 int line_filter = match_pattern(filter_pattern,
1285 cline, line_len, &sp, &ep, 0, last_filter_type);
1286 if (line_filter)
1288 struct hilite *hl = (struct hilite *)
1289 ecalloc(1, sizeof(struct hilite));
1290 hl->hl_startpos = linepos;
1291 hl->hl_endpos = pos;
1292 add_hilite(&filter_anchor, hl);
1295 #endif
1298 * Test the next line to see if we have a match.
1299 * We are successful if we either want a match and got one,
1300 * or if we want a non-match and got one.
1302 if (!is_null_pattern(search_pattern))
1304 line_match = match_pattern(search_pattern,
1305 cline, line_len, &sp, &ep, 0, search_type);
1306 if (line_match)
1309 * Got a match.
1311 if (search_type & SRCH_FIND_ALL)
1313 #if HILITE_SEARCH
1315 * We are supposed to find all matches in the range.
1316 * Just add the matches in this line to the
1317 * hilite list and keep searching.
1319 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
1320 #endif
1321 } else if (--matches <= 0)
1324 * Found the one match we're looking for.
1325 * Return it.
1327 #if HILITE_SEARCH
1328 if (hilite_search == OPT_ON)
1331 * Clear the hilite list and add only
1332 * the matches in this one line.
1334 clr_hilite();
1335 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
1337 #endif
1338 free(cline);
1339 if (plinepos != NULL)
1340 *plinepos = linepos;
1341 return (0);
1345 free(cline);
1350 * search for a pattern in history. If found, compile that pattern.
1352 static int
1353 hist_pattern(search_type)
1354 int search_type;
1356 #if CMD_HISTORY
1357 char *pattern;
1359 set_mlist(ml_search, 0);
1360 pattern = cmd_lastpattern();
1361 if (pattern == NULL)
1362 return (0);
1364 if (compile_pattern(pattern, search_type, &search_pattern) < 0)
1365 return (0);
1367 is_ucase_pattern = is_ucase(pattern);
1368 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1369 is_caseless = 0;
1370 else
1371 is_caseless = caseless;
1373 #if HILITE_SEARCH
1374 if (hilite_search == OPT_ONPLUS && !hide_hilite)
1375 hilite_screen();
1376 #endif
1378 return (1);
1379 #else /* CMD_HISTORY */
1380 return (0);
1381 #endif /* CMD_HISTORY */
1385 * Search for the n-th occurrence of a specified pattern,
1386 * either forward or backward.
1387 * Return the number of matches not yet found in this file
1388 * (that is, n minus the number of matches found).
1389 * Return -1 if the search should be aborted.
1390 * Caller may continue the search in another file
1391 * if less than n matches are found in this file.
1393 public int
1394 search(search_type, pattern, n)
1395 int search_type;
1396 char *pattern;
1397 int n;
1399 POSITION pos;
1401 if (pattern == NULL || *pattern == '\0')
1404 * A null pattern means use the previously compiled pattern.
1406 if (!prev_pattern() && !hist_pattern(search_type))
1408 error("No previous regular expression", NULL_PARG);
1409 return (-1);
1411 if ((search_type & SRCH_NO_REGEX) !=
1412 (last_search_type & SRCH_NO_REGEX))
1414 error("Please re-enter search pattern", NULL_PARG);
1415 return -1;
1417 #if HILITE_SEARCH
1418 if (hilite_search == OPT_ON)
1421 * Erase the highlights currently on screen.
1422 * If the search fails, we'll redisplay them later.
1424 repaint_hilite(0);
1426 if (hilite_search == OPT_ONPLUS && hide_hilite)
1429 * Highlight any matches currently on screen,
1430 * before we actually start the search.
1432 hide_hilite = 0;
1433 hilite_screen();
1435 hide_hilite = 0;
1436 #endif
1437 } else
1440 * Compile the pattern.
1442 if (compile_pattern(pattern, search_type, &search_pattern) < 0)
1443 return (-1);
1445 * Ignore case if -I is set OR
1446 * -i is set AND the pattern is all lowercase.
1448 is_ucase_pattern = is_ucase(pattern);
1449 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1450 is_caseless = 0;
1451 else
1452 is_caseless = caseless;
1453 #if HILITE_SEARCH
1454 if (hilite_search)
1457 * Erase the highlights currently on screen.
1458 * Also permanently delete them from the hilite list.
1460 repaint_hilite(0);
1461 hide_hilite = 0;
1462 clr_hilite();
1464 if (hilite_search == OPT_ONPLUS)
1467 * Highlight any matches currently on screen,
1468 * before we actually start the search.
1470 hilite_screen();
1472 #endif
1476 * Figure out where to start the search.
1478 pos = search_pos(search_type);
1479 if (pos == NULL_POSITION)
1482 * Can't find anyplace to start searching from.
1484 if (search_type & SRCH_PAST_EOF)
1485 return (n);
1486 /* repaint(); -- why was this here? */
1487 error("Nothing to search", NULL_PARG);
1488 return (-1);
1491 n = search_range(pos, NULL_POSITION, search_type, n, -1,
1492 &pos, (POSITION*)NULL);
1493 if (n != 0)
1496 * Search was unsuccessful.
1498 #if HILITE_SEARCH
1499 if (hilite_search == OPT_ON && n > 0)
1501 * Redisplay old hilites.
1503 repaint_hilite(1);
1504 #endif
1505 return (n);
1508 if (!(search_type & SRCH_NO_MOVE))
1511 * Go to the matching line.
1513 jump_loc(pos, jump_sline);
1516 #if HILITE_SEARCH
1517 if (hilite_search == OPT_ON)
1519 * Display new hilites in the matching line.
1521 repaint_hilite(1);
1522 #endif
1523 return (0);
1527 #if HILITE_SEARCH
1529 * Prepare hilites in a given range of the file.
1531 * The pair (prep_startpos,prep_endpos) delimits a contiguous region
1532 * of the file that has been "prepared"; that is, scanned for matches for
1533 * the current search pattern, and hilites have been created for such matches.
1534 * If prep_startpos == NULL_POSITION, the prep region is empty.
1535 * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
1536 * prep_hilite asks that the range (spos,epos) be covered by the prep region.
1538 public void
1539 prep_hilite(spos, epos, maxlines)
1540 POSITION spos;
1541 POSITION epos;
1542 int maxlines;
1544 POSITION nprep_startpos = prep_startpos;
1545 POSITION nprep_endpos = prep_endpos;
1546 POSITION new_epos;
1547 POSITION max_epos;
1548 int result;
1549 int i;
1551 * Search beyond where we're asked to search, so the prep region covers
1552 * more than we need. Do one big search instead of a bunch of small ones.
1554 #define SEARCH_MORE (3*size_linebuf)
1556 if (!prev_pattern() && !is_filtering())
1557 return;
1560 * If we're limited to a max number of lines, figure out the
1561 * file position we should stop at.
1563 if (maxlines < 0)
1564 max_epos = NULL_POSITION;
1565 else
1567 max_epos = spos;
1568 for (i = 0; i < maxlines; i++)
1569 max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
1573 * Find two ranges:
1574 * The range that we need to search (spos,epos); and the range that
1575 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
1578 if (prep_startpos == NULL_POSITION ||
1579 (epos != NULL_POSITION && epos < prep_startpos) ||
1580 spos > prep_endpos)
1583 * New range is not contiguous with old prep region.
1584 * Discard the old prep region and start a new one.
1586 clr_hilite();
1587 clr_filter();
1588 if (epos != NULL_POSITION)
1589 epos += SEARCH_MORE;
1590 nprep_startpos = spos;
1591 } else
1594 * New range partially or completely overlaps old prep region.
1596 if (epos == NULL_POSITION)
1599 * New range goes to end of file.
1602 } else if (epos > prep_endpos)
1605 * New range ends after old prep region.
1606 * Extend prep region to end at end of new range.
1608 epos += SEARCH_MORE;
1609 } else /* (epos <= prep_endpos) */
1612 * New range ends within old prep region.
1613 * Truncate search to end at start of old prep region.
1615 epos = prep_startpos;
1618 if (spos < prep_startpos)
1621 * New range starts before old prep region.
1622 * Extend old prep region backwards to start at
1623 * start of new range.
1625 if (spos < SEARCH_MORE)
1626 spos = 0;
1627 else
1628 spos -= SEARCH_MORE;
1629 nprep_startpos = spos;
1630 } else /* (spos >= prep_startpos) */
1633 * New range starts within or after old prep region.
1634 * Trim search to start at end of old prep region.
1636 spos = prep_endpos;
1640 if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
1641 epos > max_epos)
1643 * Don't go past the max position we're allowed.
1645 epos = max_epos;
1647 if (epos == NULL_POSITION || epos > spos)
1649 result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
1650 maxlines, (POSITION*)NULL, &new_epos);
1651 if (result < 0)
1652 return;
1653 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
1654 nprep_endpos = new_epos;
1656 prep_startpos = nprep_startpos;
1657 prep_endpos = nprep_endpos;
1661 * Set the pattern to be used for line filtering.
1663 public void
1664 set_filter_pattern(pattern, search_type)
1665 char *pattern;
1666 int search_type;
1668 clr_filter();
1669 if (pattern == NULL || *pattern == '\0')
1670 uncompile_filter_pattern();
1671 else
1672 compile_pattern(pattern, search_type, &filter_pattern);
1673 screen_trashed = 1;
1677 * Is there a line filter in effect?
1679 public int
1680 is_filtering()
1682 if (ch_getflags() & CH_HELPFILE)
1683 return (0);
1684 return !is_null_pattern(filter_pattern);
1686 #endif
1689 * Simple pattern matching function.
1690 * It supports no metacharacters like *, etc.
1692 static int
1693 match(pattern, pattern_len, buf, buf_len, pfound, pend)
1694 char *pattern;
1695 int pattern_len;
1696 char *buf;
1697 int buf_len;
1698 char **pfound, **pend;
1700 register char *pp, *lp;
1701 register char *pattern_end = pattern + pattern_len;
1702 register char *buf_end = buf + buf_len;
1704 for ( ; buf < buf_end; buf++)
1706 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
1707 if (pp == pattern_end || lp == buf_end)
1708 break;
1709 if (pp == pattern_end)
1711 if (pfound != NULL)
1712 *pfound = buf;
1713 if (pend != NULL)
1714 *pend = lp;
1715 return (1);
1718 return (0);
1721 #if HAVE_V8_REGCOMP
1723 * This function is called by the V8 regcomp to report
1724 * errors in regular expressions.
1726 void
1727 regerror(s)
1728 char *s;
1730 PARG parg;
1732 parg.p_string = s;
1733 error("%s", &parg);
1735 #endif