renames vmcb->control.v_irq to virq_pending
[freebsd-src/fkvm-freebsd.git] / contrib / less / search.c
blob4fb169c39d7edc8588f38e040dc8caf287e6a226
1 /* $FreeBSD$ */
2 /*
3 * Copyright (C) 1984-2007 Mark Nudelman
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Less License, as specified in the README file.
8 * For more information about less, or for information on how to
9 * contact the author, see the README file.
14 * Routines to search a file for a pattern.
17 #include "less.h"
18 #include "position.h"
19 #include "charset.h"
21 #define MINPOS(a,b) (((a) < (b)) ? (a) : (b))
22 #define MAXPOS(a,b) (((a) > (b)) ? (a) : (b))
24 #if HAVE_POSIX_REGCOMP
25 #include <regex.h>
26 #ifdef REG_EXTENDED
27 #define REGCOMP_FLAG (less_is_more ? 0 : REG_EXTENDED)
28 #else
29 #define REGCOMP_FLAG 0
30 #endif
31 #endif
32 #if HAVE_PCRE
33 #include <pcre.h>
34 #endif
35 #if HAVE_RE_COMP
36 char *re_comp();
37 int re_exec();
38 #endif
39 #if HAVE_REGCMP
40 char *regcmp();
41 char *regex();
42 extern char *__loc1;
43 #endif
44 #if HAVE_V8_REGCOMP
45 #include "regexp.h"
46 #endif
48 static int match();
50 extern int sigs;
51 extern int how_search;
52 extern int caseless;
53 extern int linenums;
54 extern int sc_height;
55 extern int jump_sline;
56 extern int bs_mode;
57 extern int less_is_more;
58 extern int ctldisp;
59 extern int status_col;
60 extern void * constant ml_search;
61 extern POSITION start_attnpos;
62 extern POSITION end_attnpos;
63 #if HILITE_SEARCH
64 extern int hilite_search;
65 extern int screen_trashed;
66 extern int size_linebuf;
67 extern int squished;
68 extern int can_goto_line;
69 extern int utf_mode;
70 static int hide_hilite;
71 static int oldbot;
72 static POSITION prep_startpos;
73 static POSITION prep_endpos;
75 struct hilite
77 struct hilite *hl_next;
78 POSITION hl_startpos;
79 POSITION hl_endpos;
81 static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
82 #define hl_first hl_next
83 #endif
86 * These are the static variables that represent the "remembered"
87 * search pattern.
89 #if HAVE_POSIX_REGCOMP
90 static regex_t *regpattern = NULL;
91 #endif
92 #if HAVE_PCRE
93 pcre *regpattern = NULL;
94 #endif
95 #if HAVE_RE_COMP
96 int re_pattern = 0;
97 #endif
98 #if HAVE_REGCMP
99 static char *cpattern = NULL;
100 #endif
101 #if HAVE_V8_REGCOMP
102 static struct regexp *regpattern = NULL;
103 #endif
105 static int is_caseless;
106 static int is_ucase_pattern;
107 static int last_search_type;
108 static char *last_pattern = NULL;
110 #define CVT_TO_LC 01 /* Convert upper-case to lower-case */
111 #define CVT_BS 02 /* Do backspace processing */
112 #define CVT_CRLF 04 /* Remove CR after LF */
113 #define CVT_ANSI 010 /* Remove ANSI escape sequences */
116 * Get the length of a buffer needed to convert a string.
118 static int
119 cvt_length(len, ops)
120 int len;
121 int ops;
123 if (utf_mode)
125 * Just copying a string in UTF-8 mode can cause it to grow
126 * in length.
127 * Six output bytes for one input byte is the worst case
128 * (and unfortunately is far more than is needed in any
129 * non-pathological situation, so this is very wasteful).
131 len *= 6;
132 return len + 1;
136 * Convert text. Perform one or more of these transformations:
138 static void
139 cvt_text(odst, osrc, lenp, ops)
140 char *odst;
141 char *osrc;
142 int *lenp;
143 int ops;
145 char *dst;
146 char *src;
147 register char *src_end;
148 LWCHAR ch;
150 if (lenp != NULL)
151 src_end = osrc + *lenp;
152 else
153 src_end = osrc + strlen(osrc);
155 for (src = osrc, dst = odst; src < src_end; )
157 ch = step_char(&src, +1, src_end);
158 if ((ops & CVT_TO_LC) && IS_UPPER(ch))
160 /* Convert uppercase to lowercase. */
161 put_wchar(&dst, TO_LOWER(ch));
162 } else if ((ops & CVT_BS) && ch == '\b' && dst > odst)
164 /* Delete backspace and preceding char. */
165 do {
166 dst--;
167 } while (dst > odst &&
168 !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
169 } else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
171 /* Skip to end of ANSI escape sequence. */
172 while (src + 1 != src_end)
173 if (!is_ansi_middle(*++src))
174 break;
175 } else
176 /* Just copy. */
177 put_wchar(&dst, ch);
179 if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
180 dst--;
181 *dst = '\0';
182 if (lenp != NULL)
183 *lenp = dst - odst;
187 * Determine which conversions to perform.
189 static int
190 get_cvt_ops()
192 int ops = 0;
193 if (is_caseless || bs_mode == BS_SPECIAL)
195 if (is_caseless)
196 ops |= CVT_TO_LC;
197 if (bs_mode == BS_SPECIAL)
198 ops |= CVT_BS;
199 if (bs_mode != BS_CONTROL)
200 ops |= CVT_CRLF;
201 } else if (bs_mode != BS_CONTROL)
203 ops |= CVT_CRLF;
205 if (ctldisp == OPT_ONPLUS)
206 ops |= CVT_ANSI;
207 return (ops);
211 * Are there any uppercase letters in this string?
213 static int
214 is_ucase(str)
215 char *str;
217 char *str_end = str + strlen(str);
218 LWCHAR ch;
220 while (str < str_end)
222 ch = step_char(&str, +1, str_end);
223 if (IS_UPPER(ch))
224 return (1);
226 return (0);
230 * Is there a previous (remembered) search pattern?
232 static int
233 prev_pattern()
235 if (last_search_type & SRCH_NO_REGEX)
236 return (last_pattern != NULL);
237 #if HAVE_POSIX_REGCOMP
238 return (regpattern != NULL);
239 #endif
240 #if HAVE_PCRE
241 return (regpattern != NULL);
242 #endif
243 #if HAVE_RE_COMP
244 return (re_pattern != 0);
245 #endif
246 #if HAVE_REGCMP
247 return (cpattern != NULL);
248 #endif
249 #if HAVE_V8_REGCOMP
250 return (regpattern != NULL);
251 #endif
252 #if NO_REGEX
253 return (last_pattern != NULL);
254 #endif
257 #if HILITE_SEARCH
259 * Repaint the hilites currently displayed on the screen.
260 * Repaint each line which contains highlighted text.
261 * If on==0, force all hilites off.
263 public void
264 repaint_hilite(on)
265 int on;
267 int slinenum;
268 POSITION pos;
269 POSITION epos;
270 int save_hide_hilite;
272 if (squished)
273 repaint();
275 save_hide_hilite = hide_hilite;
276 if (!on)
278 if (hide_hilite)
279 return;
280 hide_hilite = 1;
283 if (!can_goto_line)
285 repaint();
286 hide_hilite = save_hide_hilite;
287 return;
290 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
292 pos = position(slinenum);
293 if (pos == NULL_POSITION)
294 continue;
295 epos = position(slinenum+1);
296 #if 0
298 * If any character in the line is highlighted,
299 * repaint the line.
301 * {{ This doesn't work -- if line is drawn with highlights
302 * which should be erased (e.g. toggle -i with status column),
303 * we must redraw the line even if it has no highlights.
304 * For now, just repaint every line. }}
306 if (is_hilited(pos, epos, 1, NULL))
307 #endif
309 (void) forw_line(pos);
310 goto_line(slinenum);
311 put_line();
314 if (!oldbot)
315 lower_left();
316 hide_hilite = save_hide_hilite;
320 * Clear the attn hilite.
322 public void
323 clear_attn()
325 int slinenum;
326 POSITION old_start_attnpos;
327 POSITION old_end_attnpos;
328 POSITION pos;
329 POSITION epos;
330 int moved = 0;
332 if (start_attnpos == NULL_POSITION)
333 return;
334 old_start_attnpos = start_attnpos;
335 old_end_attnpos = end_attnpos;
336 start_attnpos = end_attnpos = NULL_POSITION;
338 if (!can_goto_line)
340 repaint();
341 return;
343 if (squished)
344 repaint();
346 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
348 pos = position(slinenum);
349 if (pos == NULL_POSITION)
350 continue;
351 epos = position(slinenum+1);
352 if (pos < old_end_attnpos &&
353 (epos == NULL_POSITION || epos > old_start_attnpos))
355 (void) forw_line(pos);
356 goto_line(slinenum);
357 put_line();
358 moved = 1;
361 if (moved)
362 lower_left();
364 #endif
367 * Hide search string highlighting.
369 public void
370 undo_search()
372 if (!prev_pattern())
374 error("No previous regular expression", NULL_PARG);
375 return;
377 #if HILITE_SEARCH
378 hide_hilite = !hide_hilite;
379 repaint_hilite(1);
380 #endif
384 * Compile a search pattern, for future use by match_pattern.
386 static int
387 compile_pattern2(pattern, search_type)
388 char *pattern;
389 int search_type;
391 if ((search_type & SRCH_NO_REGEX) == 0)
393 #if HAVE_POSIX_REGCOMP
394 regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
395 if (regcomp(s, pattern, REGCOMP_FLAG))
397 free(s);
398 error("Invalid pattern", NULL_PARG);
399 return (-1);
401 if (regpattern != NULL)
402 regfree(regpattern);
403 regpattern = s;
404 #endif
405 #if HAVE_PCRE
406 pcre *comp;
407 const char *errstring;
408 int erroffset;
409 PARG parg;
410 comp = pcre_compile(pattern, 0,
411 &errstring, &erroffset, NULL);
412 if (comp == NULL)
414 parg.p_string = (char *) errstring;
415 error("%s", &parg);
416 return (-1);
418 regpattern = comp;
419 #endif
420 #if HAVE_RE_COMP
421 PARG parg;
422 if ((parg.p_string = re_comp(pattern)) != NULL)
424 error("%s", &parg);
425 return (-1);
427 re_pattern = 1;
428 #endif
429 #if HAVE_REGCMP
430 char *s;
431 if ((s = regcmp(pattern, 0)) == NULL)
433 error("Invalid pattern", NULL_PARG);
434 return (-1);
436 if (cpattern != NULL)
437 free(cpattern);
438 cpattern = s;
439 #endif
440 #if HAVE_V8_REGCOMP
441 struct regexp *s;
442 if ((s = regcomp(pattern)) == NULL)
445 * regcomp has already printed an error message
446 * via regerror().
448 return (-1);
450 if (regpattern != NULL)
451 free(regpattern);
452 regpattern = s;
453 #endif
456 if (last_pattern != NULL)
457 free(last_pattern);
458 last_pattern = (char *) calloc(1, strlen(pattern)+1);
459 if (last_pattern != NULL)
460 strcpy(last_pattern, pattern);
462 last_search_type = search_type;
463 return (0);
467 * Like compile_pattern, but convert the pattern to lowercase if necessary.
469 static int
470 compile_pattern(pattern, search_type)
471 char *pattern;
472 int search_type;
474 char *cvt_pattern;
475 int result;
477 if (caseless != OPT_ONPLUS)
478 cvt_pattern = pattern;
479 else
481 cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
482 cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC);
484 result = compile_pattern2(cvt_pattern, search_type);
485 if (cvt_pattern != pattern)
486 free(cvt_pattern);
487 return (result);
491 * Forget that we have a compiled pattern.
493 static void
494 uncompile_pattern()
496 #if HAVE_POSIX_REGCOMP
497 if (regpattern != NULL)
498 regfree(regpattern);
499 regpattern = NULL;
500 #endif
501 #if HAVE_PCRE
502 if (regpattern != NULL)
503 pcre_free(regpattern);
504 regpattern = NULL;
505 #endif
506 #if HAVE_RE_COMP
507 re_pattern = 0;
508 #endif
509 #if HAVE_REGCMP
510 if (cpattern != NULL)
511 free(cpattern);
512 cpattern = NULL;
513 #endif
514 #if HAVE_V8_REGCOMP
515 if (regpattern != NULL)
516 free(regpattern);
517 regpattern = NULL;
518 #endif
519 last_pattern = NULL;
523 * Perform a pattern match with the previously compiled pattern.
524 * Set sp and ep to the start and end of the matched string.
526 static int
527 match_pattern(line, line_len, sp, ep, notbol)
528 char *line;
529 int line_len;
530 char **sp;
531 char **ep;
532 int notbol;
534 int matched;
536 if (last_search_type & SRCH_NO_REGEX)
537 return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
539 #if HAVE_POSIX_REGCOMP
541 regmatch_t rm;
542 int flags = (notbol) ? REG_NOTBOL : 0;
543 matched = !regexec(regpattern, line, 1, &rm, flags);
544 if (!matched)
545 return (0);
546 #ifndef __WATCOMC__
547 *sp = line + rm.rm_so;
548 *ep = line + rm.rm_eo;
549 #else
550 *sp = rm.rm_sp;
551 *ep = rm.rm_ep;
552 #endif
554 #endif
555 #if HAVE_PCRE
557 int flags = (notbol) ? PCRE_NOTBOL : 0;
558 int ovector[3];
559 matched = pcre_exec(regpattern, NULL, line, line_len,
560 0, flags, ovector, 3) >= 0;
561 if (!matched)
562 return (0);
563 *sp = line + ovector[0];
564 *ep = line + ovector[1];
566 #endif
567 #if HAVE_RE_COMP
568 matched = (re_exec(line) == 1);
570 * re_exec doesn't seem to provide a way to get the matched string.
572 *sp = *ep = NULL;
573 #endif
574 #if HAVE_REGCMP
575 *ep = regex(cpattern, line);
576 matched = (*ep != NULL);
577 if (!matched)
578 return (0);
579 *sp = __loc1;
580 #endif
581 #if HAVE_V8_REGCOMP
582 #if HAVE_REGEXEC2
583 matched = regexec2(regpattern, line, notbol);
584 #else
585 matched = regexec(regpattern, line);
586 #endif
587 if (!matched)
588 return (0);
589 *sp = regpattern->startp[0];
590 *ep = regpattern->endp[0];
591 #endif
592 #if NO_REGEX
593 matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
594 #endif
595 return (matched);
598 #if HILITE_SEARCH
600 * Clear the hilite list.
602 public void
603 clr_hilite()
605 struct hilite *hl;
606 struct hilite *nexthl;
608 for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl)
610 nexthl = hl->hl_next;
611 free((void*)hl);
613 hilite_anchor.hl_first = NULL;
614 prep_startpos = prep_endpos = NULL_POSITION;
618 * Should any characters in a specified range be highlighted?
620 static int
621 is_hilited_range(pos, epos)
622 POSITION pos;
623 POSITION epos;
625 struct hilite *hl;
628 * Look at each highlight and see if any part of it falls in the range.
630 for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next)
632 if (hl->hl_endpos > pos &&
633 (epos == NULL_POSITION || epos > hl->hl_startpos))
634 return (1);
636 return (0);
640 * Should any characters in a specified range be highlighted?
641 * If nohide is nonzero, don't consider hide_hilite.
643 public int
644 is_hilited(pos, epos, nohide, p_matches)
645 POSITION pos;
646 POSITION epos;
647 int nohide;
648 int *p_matches;
650 int match;
652 if (p_matches != NULL)
653 *p_matches = 0;
655 if (!status_col &&
656 start_attnpos != NULL_POSITION &&
657 pos < end_attnpos &&
658 (epos == NULL_POSITION || epos > start_attnpos))
660 * The attn line overlaps this range.
662 return (1);
664 match = is_hilited_range(pos, epos);
665 if (!match)
666 return (0);
668 if (p_matches != NULL)
670 * Report matches, even if we're hiding highlights.
672 *p_matches = 1;
674 if (hilite_search == 0)
676 * Not doing highlighting.
678 return (0);
680 if (!nohide && hide_hilite)
682 * Highlighting is hidden.
684 return (0);
686 return (1);
690 * Add a new hilite to a hilite list.
692 static void
693 add_hilite(anchor, hl)
694 struct hilite *anchor;
695 struct hilite *hl;
697 struct hilite *ihl;
700 * Hilites are sorted in the list; find where new one belongs.
701 * Insert new one after ihl.
703 for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next)
705 if (ihl->hl_next->hl_startpos > hl->hl_startpos)
706 break;
710 * Truncate hilite so it doesn't overlap any existing ones
711 * above and below it.
713 if (ihl != anchor)
714 hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
715 if (ihl->hl_next != NULL)
716 hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
717 if (hl->hl_startpos >= hl->hl_endpos)
720 * Hilite was truncated out of existence.
722 free(hl);
723 return;
725 hl->hl_next = ihl->hl_next;
726 ihl->hl_next = hl;
730 * Adjust hl_startpos & hl_endpos to account for processing by cvt_text.
732 static void
733 adj_hilite(anchor, linepos, cvt_ops)
734 struct hilite *anchor;
735 POSITION linepos;
736 int cvt_ops;
738 char *line;
739 char *oline;
740 int line_len;
741 char *line_end;
742 struct hilite *hl;
743 int checkstart;
744 POSITION opos;
745 POSITION npos;
746 LWCHAR ch;
747 int ncwidth;
750 * The line was already scanned and hilites were added (in hilite_line).
751 * But it was assumed that each char position in the line
752 * correponds to one char position in the file.
753 * This may not be true if cvt_text modified the line.
754 * Get the raw line again. Look at each character.
756 (void) forw_raw_line(linepos, &line, &line_len);
757 line_end = line + line_len;
758 opos = npos = linepos;
759 hl = anchor->hl_first;
760 checkstart = TRUE;
761 while (hl != NULL)
764 * See if we need to adjust the current hl_startpos or
765 * hl_endpos. After adjusting startpos[i], move to endpos[i].
766 * After adjusting endpos[i], move to startpos[i+1].
767 * The hilite list must be sorted thus:
768 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
770 if (checkstart && hl->hl_startpos == opos)
772 hl->hl_startpos = npos;
773 checkstart = FALSE;
774 continue; /* {{ not really necessary }} */
775 } else if (!checkstart && hl->hl_endpos == opos)
777 hl->hl_endpos = npos;
778 checkstart = TRUE;
779 hl = hl->hl_next;
780 continue; /* {{ necessary }} */
782 if (line == line_end)
783 break;
785 /* Get the next char from the line. */
786 oline = line;
787 ch = step_char(&line, +1, line_end);
788 ncwidth = line - oline;
789 npos += ncwidth;
791 /* Figure out how this char was processed by cvt_text. */
792 if ((cvt_ops & CVT_BS) && ch == '\b')
794 /* Skip the backspace and the following char. */
795 oline = line;
796 ch = step_char(&line, +1, line_end);
797 ncwidth = line - oline;
798 npos += ncwidth;
799 } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch))
801 /* Converted uppercase to lower.
802 * Note that this may have changed the number of bytes
803 * that the character occupies. */
804 char dbuf[6];
805 char *dst = dbuf;
806 put_wchar(&dst, TO_LOWER(ch));
807 opos += dst - dbuf;
808 } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch))
810 /* Skip to end of ANSI escape sequence. */
811 while (line < line_end)
813 npos++;
814 if (!is_ansi_middle(*++line))
815 break;
817 } else
819 /* Ordinary unprocessed character. */
820 opos += ncwidth;
826 * Make a hilite for each string in a physical line which matches
827 * the current pattern.
828 * sp,ep delimit the first match already found.
830 static void
831 hilite_line(linepos, line, line_len, sp, ep, cvt_ops)
832 POSITION linepos;
833 char *line;
834 int line_len;
835 char *sp;
836 char *ep;
837 int cvt_ops;
839 char *searchp;
840 char *line_end = line + line_len;
841 struct hilite *hl;
842 struct hilite hilites;
844 if (sp == NULL || ep == NULL)
845 return;
847 * sp and ep delimit the first match in the line.
848 * Mark the corresponding file positions, then
849 * look for further matches and mark them.
850 * {{ This technique, of calling match_pattern on subsequent
851 * substrings of the line, may mark more than is correct
852 * if the pattern starts with "^". This bug is fixed
853 * for those regex functions that accept a notbol parameter
854 * (currently POSIX, PCRE and V8-with-regexec2). }}
856 searchp = line;
858 * Put the hilites into a temporary list until they're adjusted.
860 hilites.hl_first = NULL;
861 do {
862 if (ep > sp)
865 * Assume that each char position in the "line"
866 * buffer corresponds to one char position in the file.
867 * This is not quite true; we need to adjust later.
869 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
870 hl->hl_startpos = linepos + (sp-line);
871 hl->hl_endpos = linepos + (ep-line);
872 add_hilite(&hilites, hl);
875 * If we matched more than zero characters,
876 * move to the first char after the string we matched.
877 * If we matched zero, just move to the next char.
879 if (ep > searchp)
880 searchp = ep;
881 else if (searchp != line_end)
882 searchp++;
883 else /* end of line */
884 break;
885 } while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1));
888 * If there were backspaces in the original line, they
889 * were removed, and hl_startpos/hl_endpos are not correct.
890 * {{ This is very ugly. }}
892 adj_hilite(&hilites, linepos, cvt_ops);
895 * Now put the hilites into the real list.
897 while ((hl = hilites.hl_next) != NULL)
899 hilites.hl_next = hl->hl_next;
900 add_hilite(&hilite_anchor, hl);
903 #endif
906 * Change the caseless-ness of searches.
907 * Updates the internal search state to reflect a change in the -i flag.
909 public void
910 chg_caseless()
912 if (!is_ucase_pattern)
914 * Pattern did not have uppercase.
915 * Just set the search caselessness to the global caselessness.
917 is_caseless = caseless;
918 else
920 * Pattern did have uppercase.
921 * Discard the pattern; we can't change search caselessness now.
923 uncompile_pattern();
926 #if HILITE_SEARCH
928 * Find matching text which is currently on screen and highlight it.
930 static void
931 hilite_screen()
933 struct scrpos scrpos;
935 get_scrpos(&scrpos);
936 if (scrpos.pos == NULL_POSITION)
937 return;
938 prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
939 repaint_hilite(1);
943 * Change highlighting parameters.
945 public void
946 chg_hilite()
949 * Erase any highlights currently on screen.
951 clr_hilite();
952 hide_hilite = 0;
954 if (hilite_search == OPT_ONPLUS)
956 * Display highlights.
958 hilite_screen();
960 #endif
963 * Figure out where to start a search.
965 static POSITION
966 search_pos(search_type)
967 int search_type;
969 POSITION pos;
970 int linenum;
972 if (empty_screen())
975 * Start at the beginning (or end) of the file.
976 * The empty_screen() case is mainly for
977 * command line initiated searches;
978 * for example, "+/xyz" on the command line.
979 * Also for multi-file (SRCH_PAST_EOF) searches.
981 if (search_type & SRCH_FORW)
983 return (ch_zero());
984 } else
986 pos = ch_length();
987 if (pos == NULL_POSITION)
989 (void) ch_end_seek();
990 pos = ch_length();
992 return (pos);
995 if (how_search)
998 * Search does not include current screen.
1000 if (search_type & SRCH_FORW)
1001 linenum = BOTTOM_PLUS_ONE;
1002 else
1003 linenum = TOP;
1004 pos = position(linenum);
1005 } else
1008 * Search includes current screen.
1009 * It starts at the jump target (if searching backwards),
1010 * or at the jump target plus one (if forwards).
1012 linenum = adjsline(jump_sline);
1013 pos = position(linenum);
1014 if (search_type & SRCH_FORW)
1016 pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
1017 while (pos == NULL_POSITION)
1019 if (++linenum >= sc_height)
1020 break;
1021 pos = position(linenum);
1023 } else
1025 while (pos == NULL_POSITION)
1027 if (--linenum < 0)
1028 break;
1029 pos = position(linenum);
1033 return (pos);
1037 * Search a subset of the file, specified by start/end position.
1039 static int
1040 search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
1041 POSITION pos;
1042 POSITION endpos;
1043 int search_type;
1044 int matches;
1045 int maxlines;
1046 POSITION *plinepos;
1047 POSITION *pendpos;
1049 char *line;
1050 char *cline;
1051 int line_len;
1052 LINENUM linenum;
1053 char *sp, *ep;
1054 int line_match;
1055 int cvt_ops;
1056 POSITION linepos, oldpos;
1058 linenum = find_linenum(pos);
1059 oldpos = pos;
1060 for (;;)
1063 * Get lines until we find a matching one or until
1064 * we hit end-of-file (or beginning-of-file if we're
1065 * going backwards), or until we hit the end position.
1067 if (ABORT_SIGS())
1070 * A signal aborts the search.
1072 return (-1);
1075 if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
1078 * Reached end position without a match.
1080 if (pendpos != NULL)
1081 *pendpos = pos;
1082 return (matches);
1084 if (maxlines > 0)
1085 maxlines--;
1087 if (search_type & SRCH_FORW)
1090 * Read the next line, and save the
1091 * starting position of that line in linepos.
1093 linepos = pos;
1094 pos = forw_raw_line(pos, &line, &line_len);
1095 if (linenum != 0)
1096 linenum++;
1097 } else
1100 * Read the previous line and save the
1101 * starting position of that line in linepos.
1103 pos = back_raw_line(pos, &line, &line_len);
1104 linepos = pos;
1105 if (linenum != 0)
1106 linenum--;
1109 if (pos == NULL_POSITION)
1112 * Reached EOF/BOF without a match.
1114 if (pendpos != NULL)
1115 *pendpos = oldpos;
1116 return (matches);
1120 * If we're using line numbers, we might as well
1121 * remember the information we have now (the position
1122 * and line number of the current line).
1123 * Don't do it for every line because it slows down
1124 * the search. Remember the line number only if
1125 * we're "far" from the last place we remembered it.
1127 if (linenums && abs((int)(pos - oldpos)) > 1024)
1128 add_lnum(linenum, pos);
1129 oldpos = pos;
1132 * If it's a caseless search, convert the line to lowercase.
1133 * If we're doing backspace processing, delete backspaces.
1135 cvt_ops = get_cvt_ops();
1136 cline = calloc(1, cvt_length(line_len, cvt_ops));
1137 cvt_text(cline, line, &line_len, cvt_ops);
1140 * Test the next line to see if we have a match.
1141 * We are successful if we either want a match and got one,
1142 * or if we want a non-match and got one.
1144 line_match = match_pattern(cline, line_len, &sp, &ep, 0);
1145 line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
1146 ((search_type & SRCH_NO_MATCH) && !line_match);
1147 if (!line_match)
1149 free(cline);
1150 continue;
1153 * Got a match.
1155 if (search_type & SRCH_FIND_ALL)
1157 #if HILITE_SEARCH
1159 * We are supposed to find all matches in the range.
1160 * Just add the matches in this line to the
1161 * hilite list and keep searching.
1163 if (line_match)
1164 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
1165 #endif
1166 free(cline);
1167 } else if (--matches <= 0)
1170 * Found the one match we're looking for.
1171 * Return it.
1173 #if HILITE_SEARCH
1174 if (hilite_search == OPT_ON)
1177 * Clear the hilite list and add only
1178 * the matches in this one line.
1180 clr_hilite();
1181 if (line_match)
1182 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
1184 #endif
1185 free(cline);
1186 if (plinepos != NULL)
1187 *plinepos = linepos;
1188 return (0);
1194 * search for a pattern in history. If found, compile that pattern.
1196 static int
1197 hist_pattern(search_type)
1198 int search_type;
1200 #if CMD_HISTORY
1201 char *pattern;
1203 set_mlist(ml_search, 0);
1204 pattern = cmd_lastpattern();
1205 if (pattern == NULL)
1206 return (0);
1208 if (compile_pattern(pattern, search_type) < 0)
1209 return (0);
1211 is_ucase_pattern = is_ucase(pattern);
1212 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1213 is_caseless = 0;
1214 else
1215 is_caseless = caseless;
1217 #if HILITE_SEARCH
1218 if (hilite_search == OPT_ONPLUS && !hide_hilite)
1219 hilite_screen();
1220 #endif
1222 return (1);
1223 #else /* CMD_HISTORY */
1224 return (0);
1225 #endif /* CMD_HISTORY */
1229 * Search for the n-th occurrence of a specified pattern,
1230 * either forward or backward.
1231 * Return the number of matches not yet found in this file
1232 * (that is, n minus the number of matches found).
1233 * Return -1 if the search should be aborted.
1234 * Caller may continue the search in another file
1235 * if less than n matches are found in this file.
1237 public int
1238 search(search_type, pattern, n)
1239 int search_type;
1240 char *pattern;
1241 int n;
1243 POSITION pos;
1244 int result;
1246 if (pattern == NULL || *pattern == '\0')
1249 * A null pattern means use the previously compiled pattern.
1251 if (!prev_pattern() && !hist_pattern(search_type))
1253 error("No previous regular expression", NULL_PARG);
1254 return (-1);
1256 if ((search_type & SRCH_NO_REGEX) !=
1257 (last_search_type & SRCH_NO_REGEX))
1259 error("Please re-enter search pattern", NULL_PARG);
1260 return -1;
1262 #if HILITE_SEARCH
1263 if (hilite_search == OPT_ON)
1266 * Erase the highlights currently on screen.
1267 * If the search fails, we'll redisplay them later.
1269 repaint_hilite(0);
1271 if (hilite_search == OPT_ONPLUS && hide_hilite)
1274 * Highlight any matches currently on screen,
1275 * before we actually start the search.
1277 hide_hilite = 0;
1278 hilite_screen();
1280 hide_hilite = 0;
1281 #endif
1282 } else
1285 * Compile the pattern.
1287 if (compile_pattern(pattern, search_type) < 0)
1288 return (-1);
1290 * Ignore case if -I is set OR
1291 * -i is set AND the pattern is all lowercase.
1293 is_ucase_pattern = is_ucase(pattern);
1294 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1295 is_caseless = 0;
1296 else
1297 is_caseless = caseless;
1298 #if HILITE_SEARCH
1299 if (hilite_search)
1302 * Erase the highlights currently on screen.
1303 * Also permanently delete them from the hilite list.
1305 repaint_hilite(0);
1306 hide_hilite = 0;
1307 clr_hilite();
1309 if (hilite_search == OPT_ONPLUS)
1312 * Highlight any matches currently on screen,
1313 * before we actually start the search.
1315 hilite_screen();
1317 #endif
1321 * Figure out where to start the search.
1323 pos = search_pos(search_type);
1324 if (pos == NULL_POSITION)
1327 * Can't find anyplace to start searching from.
1329 if (search_type & SRCH_PAST_EOF)
1330 return (n);
1331 /* repaint(); -- why was this here? */
1332 error("Nothing to search", NULL_PARG);
1333 return (-1);
1336 n = search_range(pos, NULL_POSITION, search_type, n, -1,
1337 &pos, (POSITION*)NULL);
1338 if (n != 0)
1341 * Search was unsuccessful.
1343 #if HILITE_SEARCH
1344 if (hilite_search == OPT_ON && n > 0)
1346 * Redisplay old hilites.
1348 repaint_hilite(1);
1349 #endif
1350 return (n);
1353 if (!(search_type & SRCH_NO_MOVE))
1356 * Go to the matching line.
1358 jump_loc(pos, jump_sline);
1361 #if HILITE_SEARCH
1362 if (hilite_search == OPT_ON)
1364 * Display new hilites in the matching line.
1366 repaint_hilite(1);
1367 #endif
1368 return (0);
1372 #if HILITE_SEARCH
1374 * Prepare hilites in a given range of the file.
1376 * The pair (prep_startpos,prep_endpos) delimits a contiguous region
1377 * of the file that has been "prepared"; that is, scanned for matches for
1378 * the current search pattern, and hilites have been created for such matches.
1379 * If prep_startpos == NULL_POSITION, the prep region is empty.
1380 * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
1381 * prep_hilite asks that the range (spos,epos) be covered by the prep region.
1383 public void
1384 prep_hilite(spos, epos, maxlines)
1385 POSITION spos;
1386 POSITION epos;
1387 int maxlines;
1389 POSITION nprep_startpos = prep_startpos;
1390 POSITION nprep_endpos = prep_endpos;
1391 POSITION new_epos;
1392 POSITION max_epos;
1393 int result;
1394 int i;
1396 * Search beyond where we're asked to search, so the prep region covers
1397 * more than we need. Do one big search instead of a bunch of small ones.
1399 #define SEARCH_MORE (3*size_linebuf)
1401 if (!prev_pattern())
1402 return;
1405 * If we're limited to a max number of lines, figure out the
1406 * file position we should stop at.
1408 if (maxlines < 0)
1409 max_epos = NULL_POSITION;
1410 else
1412 max_epos = spos;
1413 for (i = 0; i < maxlines; i++)
1414 max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
1418 * Find two ranges:
1419 * The range that we need to search (spos,epos); and the range that
1420 * the "prep" region will then cover (nprep_startpos,nprep_endpos).
1423 if (prep_startpos == NULL_POSITION ||
1424 (epos != NULL_POSITION && epos < prep_startpos) ||
1425 spos > prep_endpos)
1428 * New range is not contiguous with old prep region.
1429 * Discard the old prep region and start a new one.
1431 clr_hilite();
1432 if (epos != NULL_POSITION)
1433 epos += SEARCH_MORE;
1434 nprep_startpos = spos;
1435 } else
1438 * New range partially or completely overlaps old prep region.
1440 if (epos == NULL_POSITION)
1443 * New range goes to end of file.
1446 } else if (epos > prep_endpos)
1449 * New range ends after old prep region.
1450 * Extend prep region to end at end of new range.
1452 epos += SEARCH_MORE;
1453 } else /* (epos <= prep_endpos) */
1456 * New range ends within old prep region.
1457 * Truncate search to end at start of old prep region.
1459 epos = prep_startpos;
1462 if (spos < prep_startpos)
1465 * New range starts before old prep region.
1466 * Extend old prep region backwards to start at
1467 * start of new range.
1469 if (spos < SEARCH_MORE)
1470 spos = 0;
1471 else
1472 spos -= SEARCH_MORE;
1473 nprep_startpos = spos;
1474 } else /* (spos >= prep_startpos) */
1477 * New range starts within or after old prep region.
1478 * Trim search to start at end of old prep region.
1480 spos = prep_endpos;
1484 if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
1485 epos > max_epos)
1487 * Don't go past the max position we're allowed.
1489 epos = max_epos;
1491 if (epos == NULL_POSITION || epos > spos)
1493 result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
1494 maxlines, (POSITION*)NULL, &new_epos);
1495 if (result < 0)
1496 return;
1497 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
1498 nprep_endpos = new_epos;
1500 prep_startpos = nprep_startpos;
1501 prep_endpos = nprep_endpos;
1503 #endif
1506 * Simple pattern matching function.
1507 * It supports no metacharacters like *, etc.
1509 static int
1510 match(pattern, pattern_len, buf, buf_len, pfound, pend)
1511 char *pattern;
1512 int pattern_len;
1513 char *buf;
1514 int buf_len;
1515 char **pfound, **pend;
1517 register char *pp, *lp;
1518 register char *pattern_end = pattern + pattern_len;
1519 register char *buf_end = buf + buf_len;
1521 for ( ; buf < buf_end; buf++)
1523 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
1524 if (pp == pattern_end || lp == buf_end)
1525 break;
1526 if (pp == pattern_end)
1528 if (pfound != NULL)
1529 *pfound = buf;
1530 if (pend != NULL)
1531 *pend = lp;
1532 return (1);
1535 return (0);
1538 #if HAVE_V8_REGCOMP
1540 * This function is called by the V8 regcomp to report
1541 * errors in regular expressions.
1543 void
1544 regerror(s)
1545 char *s;
1547 PARG parg;
1549 parg.p_string = s;
1550 error("%s", &parg);
1552 #endif