Deleted Added
full compact
search.c (191930) search.c (195941)
1/* $FreeBSD: head/contrib/less/search.c 191930 2009-05-09 01:35:27Z delphij $ */
1/* $FreeBSD: head/contrib/less/search.c 195941 2009-07-29 09:20:32Z delphij $ */
2/*
2/*
3 * Copyright (C) 1984-2008 Mark Nudelman
3 * Copyright (C) 1984-2009 Mark Nudelman
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Less License, as specified in the README file.
7 *
8 * For more information about less, or for information on how to
9 * contact the author, see the README file.
10 */
11
12
13/*
14 * Routines to search a file for a pattern.
15 */
16
17#include "less.h"
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Less License, as specified in the README file.
7 *
8 * For more information about less, or for information on how to
9 * contact the author, see the README file.
10 */
11
12
13/*
14 * Routines to search a file for a pattern.
15 */
16
17#include "less.h"
18#include "pattern.h"
18#include "position.h"
19#include "charset.h"
20
21#define MINPOS(a,b) (((a) < (b)) ? (a) : (b))
22#define MAXPOS(a,b) (((a) > (b)) ? (a) : (b))
23
19#include "position.h"
20#include "charset.h"
21
22#define MINPOS(a,b) (((a) < (b)) ? (a) : (b))
23#define MAXPOS(a,b) (((a) > (b)) ? (a) : (b))
24
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
36char *re_comp();
37int re_exec();
38#endif
39#if HAVE_REGCMP
40char *regcmp();
41char *regex();
42extern char *__loc1;
43#endif
44#if HAVE_V8_REGCOMP
45#include "regexp.h"
46#endif
47
48static int match();
49
50extern int sigs;
51extern int how_search;
52extern int caseless;
53extern int linenums;
54extern int sc_height;
55extern int jump_sline;
56extern int bs_mode;
57extern int less_is_more;

--- 5 unchanged lines hidden (view full) ---

63extern int utf_mode;
64extern int screen_trashed;
65#if HILITE_SEARCH
66extern int hilite_search;
67extern int size_linebuf;
68extern int squished;
69extern int can_goto_line;
70static int hide_hilite;
25extern int sigs;
26extern int how_search;
27extern int caseless;
28extern int linenums;
29extern int sc_height;
30extern int jump_sline;
31extern int bs_mode;
32extern int less_is_more;

--- 5 unchanged lines hidden (view full) ---

38extern int utf_mode;
39extern int screen_trashed;
40#if HILITE_SEARCH
41extern int hilite_search;
42extern int size_linebuf;
43extern int squished;
44extern int can_goto_line;
45static int hide_hilite;
71static int oldbot;
72static POSITION prep_startpos;
73static POSITION prep_endpos;
46static POSITION prep_startpos;
47static POSITION prep_endpos;
48static int is_caseless;
49static int is_ucase_pattern;
74
75struct hilite
76{
77 struct hilite *hl_next;
78 POSITION hl_startpos;
79 POSITION hl_endpos;
80};
81static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
82static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION };
83#define hl_first hl_next
84#endif
85
86/*
87 * These are the static variables that represent the "remembered"
50
51struct hilite
52{
53 struct hilite *hl_next;
54 POSITION hl_startpos;
55 POSITION hl_endpos;
56};
57static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
58static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION };
59#define hl_first hl_next
60#endif
61
62/*
63 * These are the static variables that represent the "remembered"
88 * search pattern.
64 * search pattern and filter pattern.
89 */
65 */
90#if HAVE_POSIX_REGCOMP
91#define DEFINE_PATTERN(name) static regex_t *name = NULL
92#endif
93#if HAVE_PCRE
94#define DEFINE_PATTERN(name) pcre *name = NULL;
95#endif
96#if HAVE_RE_COMP
97#define DEFINE_PATTERN(name) int name = 0;
98#endif
99#if HAVE_REGCMP
100#define DEFINE_PATTERN(name) static char *name = NULL;
101#endif
102#if HAVE_V8_REGCOMP
103#define DEFINE_PATTERN(name) static struct regexp *name = NULL;
104#endif
66struct pattern_info {
67 DEFINE_PATTERN(compiled);
68 char* text;
69 int search_type;
70};
71
72static struct pattern_info search_info;
73static struct pattern_info filter_info;
105
74
106DEFINE_PATTERN(search_pattern);
107DEFINE_PATTERN(filter_pattern);
108
109static int is_caseless;
110static int is_ucase_pattern;
111static int last_search_type;
112static int last_filter_type;
113static char *last_pattern = NULL;
114
115#define CVT_TO_LC 01 /* Convert upper-case to lower-case */
116#define CVT_BS 02 /* Do backspace processing */
117#define CVT_CRLF 04 /* Remove CR after LF */
118#define CVT_ANSI 010 /* Remove ANSI escape sequences */
119
120/*
75/*
121 * Get the length of a buffer needed to convert a string.
76 * Compile and save a search pattern.
122 */
123 static int
77 */
78 static int
124cvt_length(len, ops)
125 int len;
126 int ops;
79set_pattern(info, pattern, search_type)
80 struct pattern_info *info;
81 char *pattern;
82 int search_type;
127{
83{
128 if (utf_mode)
129 /*
130 * Just copying a string in UTF-8 mode can cause it to grow
131 * in length.
132 * Six output bytes for one input byte is the worst case
133 * (and unfortunately is far more than is needed in any
134 * non-pathological situation, so this is very wasteful).
135 */
136 len *= 6;
137 return len + 1;
84 if (pattern == NULL)
85 CLEAR_PATTERN(search_info.compiled);
86 else if (compile_pattern(pattern, search_type, &info->compiled) < 0)
87 return -1;
88 /* Pattern compiled successfully; save the text too. */
89 if (info->text != NULL)
90 free(info->text);
91 info->text = NULL;
92 if (pattern != NULL)
93 {
94 info->text = (char *) ecalloc(1, strlen(pattern)+1);
95 strcpy(info->text, pattern);
96 }
97 info->search_type = search_type;
98 return 0;
138}
139
140/*
99}
100
101/*
141 * Convert text. Perform the transformations specified by ops.
102 * Discard a saved pattern.
142 */
143 static void
103 */
104 static void
144cvt_text(odst, osrc, lenp, ops)
145 char *odst;
146 char *osrc;
147 int *lenp;
148 int ops;
105clear_pattern(info)
106 struct pattern_info *info;
149{
107{
150 char *dst;
151 char *src;
152 register char *src_end;
153 LWCHAR ch;
108 if (info->text != NULL)
109 free(info->text);
110 info->text = NULL;
111 uncompile_pattern(&info->compiled);
112}
154
113
155 if (lenp != NULL)
156 src_end = osrc + *lenp;
157 else
158 src_end = osrc + strlen(osrc);
114/*
115 * Initialize saved pattern to nothing.
116 */
117 static void
118init_pattern(info)
119 struct pattern_info *info;
120{
121 CLEAR_PATTERN(info->compiled);
122 info->text = NULL;
123 info->search_type = 0;
124}
159
125
160 for (src = osrc, dst = odst; src < src_end; )
161 {
162 ch = step_char(&src, +1, src_end);
163 if ((ops & CVT_TO_LC) && IS_UPPER(ch))
164 {
165 /* Convert uppercase to lowercase. */
166 put_wchar(&dst, TO_LOWER(ch));
167 } else if ((ops & CVT_BS) && ch == '\b' && dst > odst)
168 {
169 /* Delete backspace and preceding char. */
170 do {
171 dst--;
172 } while (dst > odst &&
173 !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
174 } else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
175 {
176 /* Skip to end of ANSI escape sequence. */
177 src++; /* skip the CSI start char */
178 while (src < src_end)
179 if (!is_ansi_middle(*src++))
180 break;
181 } else
182 /* Just copy. */
183 put_wchar(&dst, ch);
184 }
185 if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
186 dst--;
187 *dst = '\0';
188 if (lenp != NULL)
189 *lenp = dst - odst;
126/*
127 * Initialize search variables.
128 */
129 public void
130init_search()
131{
132 init_pattern(&search_info);
133 init_pattern(&filter_info);
190}
191
192/*
134}
135
136/*
193 * Determine which conversions to perform.
137 * Determine which text conversions to perform before pattern matching.
194 */
195 static int
196get_cvt_ops()
197{
198 int ops = 0;
199 if (is_caseless || bs_mode == BS_SPECIAL)
200 {
201 if (is_caseless)

--- 29 unchanged lines hidden (view full) ---

231 }
232 return (0);
233}
234
235/*
236 * Is there a previous (remembered) search pattern?
237 */
238 static int
138 */
139 static int
140get_cvt_ops()
141{
142 int ops = 0;
143 if (is_caseless || bs_mode == BS_SPECIAL)
144 {
145 if (is_caseless)

--- 29 unchanged lines hidden (view full) ---

175 }
176 return (0);
177}
178
179/*
180 * Is there a previous (remembered) search pattern?
181 */
182 static int
239prev_pattern()
183prev_pattern(info)
184 struct pattern_info *info;
240{
185{
241 if (last_search_type & SRCH_NO_REGEX)
242 return (last_pattern != NULL);
243#if HAVE_POSIX_REGCOMP
244 return (search_pattern != NULL);
245#endif
246#if HAVE_PCRE
247 return (search_pattern != NULL);
248#endif
249#if HAVE_RE_COMP
250 return (search_pattern != 0);
251#endif
252#if HAVE_REGCMP
253 return (search_pattern != NULL);
254#endif
255#if HAVE_V8_REGCOMP
256 return (search_pattern != NULL);
257#endif
258#if NO_REGEX
259 return (search_pattern != NULL);
260#endif
186 if (info->search_type & SRCH_NO_REGEX)
187 return (info->text != NULL);
188 return (!is_null_pattern(info->compiled));
261}
262
263#if HILITE_SEARCH
264/*
265 * Repaint the hilites currently displayed on the screen.
266 * Repaint each line which contains highlighted text.
267 * If on==0, force all hilites off.
268 */

--- 25 unchanged lines hidden (view full) ---

294 }
295
296 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
297 {
298 pos = position(slinenum);
299 if (pos == NULL_POSITION)
300 continue;
301 epos = position(slinenum+1);
189}
190
191#if HILITE_SEARCH
192/*
193 * Repaint the hilites currently displayed on the screen.
194 * Repaint each line which contains highlighted text.
195 * If on==0, force all hilites off.
196 */

--- 25 unchanged lines hidden (view full) ---

222 }
223
224 for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
225 {
226 pos = position(slinenum);
227 if (pos == NULL_POSITION)
228 continue;
229 epos = position(slinenum+1);
302#if 0
303 /*
304 * If any character in the line is highlighted,
305 * repaint the line.
306 *
307 * {{ This doesn't work -- if line is drawn with highlights
308 * which should be erased (e.g. toggle -i with status column),
309 * we must redraw the line even if it has no highlights.
310 * For now, just repaint every line. }}
311 */
312 if (is_hilited(pos, epos, 1, NULL))
313#endif
314 {
315 (void) forw_line(pos);
316 goto_line(slinenum);
317 put_line();
318 }
230 (void) forw_line(pos);
231 goto_line(slinenum);
232 put_line();
319 }
233 }
320 if (!oldbot)
321 lower_left();
234 lower_left(); // if !oldbot
322 hide_hilite = save_hide_hilite;
323}
324
325/*
326 * Clear the attn hilite.
327 */
328 public void
329clear_attn()

--- 40 unchanged lines hidden (view full) ---

370#endif
371
372/*
373 * Hide search string highlighting.
374 */
375 public void
376undo_search()
377{
235 hide_hilite = save_hide_hilite;
236}
237
238/*
239 * Clear the attn hilite.
240 */
241 public void
242clear_attn()

--- 40 unchanged lines hidden (view full) ---

283#endif
284
285/*
286 * Hide search string highlighting.
287 */
288 public void
289undo_search()
290{
378 if (!prev_pattern())
291 if (!prev_pattern(&search_info))
379 {
380 error("No previous regular expression", NULL_PARG);
381 return;
382 }
383#if HILITE_SEARCH
384 hide_hilite = !hide_hilite;
385 repaint_hilite(1);
386#endif
387}
388
292 {
293 error("No previous regular expression", NULL_PARG);
294 return;
295 }
296#if HILITE_SEARCH
297 hide_hilite = !hide_hilite;
298 repaint_hilite(1);
299#endif
300}
301
389/*
390 * Compile a search pattern, for future use by match_pattern.
391 */
392 static int
393compile_pattern2(pattern, search_type, comp_pattern)
394 char *pattern;
395 int search_type;
396 void **comp_pattern;
397{
398 if ((search_type & SRCH_NO_REGEX) == 0)
399 {
400#if HAVE_POSIX_REGCOMP
401 regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
402 regex_t **pcomp = (regex_t **) comp_pattern;
403 if (regcomp(comp, pattern, REGCOMP_FLAG))
404 {
405 free(comp);
406 error("Invalid pattern", NULL_PARG);
407 return (-1);
408 }
409 if (*pcomp != NULL)
410 regfree(*pcomp);
411 *pcomp = comp;
412#endif
413#if HAVE_PCRE
414 pcre *comp;
415 pcre **pcomp = (pcre **) comp_pattern;
416 const char *errstring;
417 int erroffset;
418 PARG parg;
419 comp = pcre_compile(pattern, 0,
420 &errstring, &erroffset, NULL);
421 if (comp == NULL)
422 {
423 parg.p_string = (char *) errstring;
424 error("%s", &parg);
425 return (-1);
426 }
427 *pcomp = comp;
428#endif
429#if HAVE_RE_COMP
430 PARG parg;
431 int *pcomp = (int *) comp_pattern;
432 if ((parg.p_string = re_comp(pattern)) != NULL)
433 {
434 error("%s", &parg);
435 return (-1);
436 }
437 *pcomp = 1;
438#endif
439#if HAVE_REGCMP
440 char *comp;
441 char **pcomp = (char **) comp_pattern;
442 if ((comp = regcmp(pattern, 0)) == NULL)
443 {
444 error("Invalid pattern", NULL_PARG);
445 return (-1);
446 }
447 if (pcomp != NULL)
448 free(*pcomp);
449 *pcomp = comp;
450#endif
451#if HAVE_V8_REGCOMP
452 struct regexp *comp;
453 struct regexp **pcomp = (struct regexp **) comp_pattern;
454 if ((comp = regcomp(pattern)) == NULL)
455 {
456 /*
457 * regcomp has already printed an error message
458 * via regerror().
459 */
460 return (-1);
461 }
462 if (*pcomp != NULL)
463 free(*pcomp);
464 *pcomp = comp;
465#endif
466 }
467
468 if (comp_pattern == (void **) &search_pattern)
469 {
470 if (last_pattern != NULL)
471 free(last_pattern);
472 last_pattern = (char *) calloc(1, strlen(pattern)+1);
473 if (last_pattern != NULL)
474 strcpy(last_pattern, pattern);
475 last_search_type = search_type;
476 } else
477 {
478 last_filter_type = search_type;
479 }
480 return (0);
481}
482
483/*
484 * Like compile_pattern2, but convert the pattern to lowercase if necessary.
485 */
486 static int
487compile_pattern(pattern, search_type, comp_pattern)
488 char *pattern;
489 int search_type;
490 void **comp_pattern;
491{
492 char *cvt_pattern;
493 int result;
494
495 if (caseless != OPT_ONPLUS)
496 cvt_pattern = pattern;
497 else
498 {
499 cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
500 cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC);
501 }
502 result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
503 if (cvt_pattern != pattern)
504 free(cvt_pattern);
505 return (result);
506}
507
508/*
509 * Forget that we have a compiled pattern.
510 */
511 static void
512uncompile_pattern(pattern)
513 void **pattern;
514{
515#if HAVE_POSIX_REGCOMP
516 regex_t **pcomp = (regex_t **) pattern;
517 if (*pcomp != NULL)
518 regfree(*pcomp);
519 *pcomp = NULL;
520#endif
521#if HAVE_PCRE
522 pcre **pcomp = (pcre **) pattern;
523 if (*pcomp != NULL)
524 pcre_free(*pcomp);
525 *pcomp = NULL;
526#endif
527#if HAVE_RE_COMP
528 int *pcomp = (int *) pattern;
529 *pcomp = 0;
530#endif
531#if HAVE_REGCMP
532 char **pcomp = (char **) pattern;
533 if (*pcomp != NULL)
534 free(*pcomp);
535 *pcomp = NULL;
536#endif
537#if HAVE_V8_REGCOMP
538 struct regexp **pcomp = (struct regexp **) pattern;
539 if (*pcomp != NULL)
540 free(*pcomp);
541 *pcomp = NULL;
542#endif
543}
544
545 static void
546uncompile_search_pattern()
547{
548 uncompile_pattern(&search_pattern);
549 last_pattern = NULL;
550}
551
552 static void
553uncompile_filter_pattern()
554{
555 uncompile_pattern(&filter_pattern);
556}
557
558/*
559 * Is a compiled pattern null?
560 */
561 static int
562is_null_pattern(pattern)
563 void *pattern;
564{
565#if HAVE_POSIX_REGCOMP
566 return (pattern == NULL);
567#endif
568#if HAVE_PCRE
569 return (pattern == NULL);
570#endif
571#if HAVE_RE_COMP
572 return (pattern == 0);
573#endif
574#if HAVE_REGCMP
575 return (pattern == NULL);
576#endif
577#if HAVE_V8_REGCOMP
578 return (pattern == NULL);
579#endif
580}
581
582/*
583 * Perform a pattern match with the previously compiled pattern.
584 * Set sp and ep to the start and end of the matched string.
585 */
586 static int
587match_pattern(pattern, line, line_len, sp, ep, notbol, search_type)
588 void *pattern;
589 char *line;
590 int line_len;
591 char **sp;
592 char **ep;
593 int notbol;
594 int search_type;
595{
596 int matched;
597#if HAVE_POSIX_REGCOMP
598 regex_t *spattern = (regex_t *) pattern;
599#endif
600#if HAVE_PCRE
601 pcre *spattern = (pcre *) pattern;
602#endif
603#if HAVE_RE_COMP
604 int spattern = (int) pattern;
605#endif
606#if HAVE_REGCMP
607 char *spattern = (char *) pattern;
608#endif
609#if HAVE_V8_REGCOMP
610 struct regexp *spattern = (struct regexp *) pattern;
611#endif
612
613 if (search_type & SRCH_NO_REGEX)
614 return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
615
616#if HAVE_POSIX_REGCOMP
617 {
618 regmatch_t rm;
619 int flags = (notbol) ? REG_NOTBOL : 0;
620 matched = !regexec(spattern, line, 1, &rm, flags);
621 if (matched)
622 {
623#ifndef __WATCOMC__
624 *sp = line + rm.rm_so;
625 *ep = line + rm.rm_eo;
626#else
627 *sp = rm.rm_sp;
628 *ep = rm.rm_ep;
629#endif
630 }
631 }
632#endif
633#if HAVE_PCRE
634 {
635 int flags = (notbol) ? PCRE_NOTBOL : 0;
636 int ovector[3];
637 matched = pcre_exec(spattern, NULL, line, line_len,
638 0, flags, ovector, 3) >= 0;
639 if (matched)
640 {
641 *sp = line + ovector[0];
642 *ep = line + ovector[1];
643 }
644 }
645#endif
646#if HAVE_RE_COMP
647 matched = (re_exec(line) == 1);
648 /*
649 * re_exec doesn't seem to provide a way to get the matched string.
650 */
651 *sp = *ep = NULL;
652#endif
653#if HAVE_REGCMP
654 *ep = regex(spattern, line);
655 matched = (*ep != NULL);
656 if (matched)
657 *sp = __loc1;
658#endif
659#if HAVE_V8_REGCOMP
660#if HAVE_REGEXEC2
661 matched = regexec2(spattern, line, notbol);
662#else
663 matched = regexec(spattern, line);
664#endif
665 if (matched)
666 {
667 *sp = spattern->startp[0];
668 *ep = spattern->endp[0];
669 }
670#endif
671#if NO_REGEX
672 matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
673#endif
674 matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
675 ((search_type & SRCH_NO_MATCH) && !matched);
676 return (matched);
677}
678
679#if HILITE_SEARCH
680/*
681 * Clear the hilite list.
682 */
683 public void
684clr_hlist(anchor)
685 struct hilite *anchor;
686{

--- 153 unchanged lines hidden (view full) ---

840 free(hl);
841 return;
842 }
843 hl->hl_next = ihl->hl_next;
844 ihl->hl_next = hl;
845}
846
847/*
302#if HILITE_SEARCH
303/*
304 * Clear the hilite list.
305 */
306 public void
307clr_hlist(anchor)
308 struct hilite *anchor;
309{

--- 153 unchanged lines hidden (view full) ---

463 free(hl);
464 return;
465 }
466 hl->hl_next = ihl->hl_next;
467 ihl->hl_next = hl;
468}
469
470/*
848 * Adjust hl_startpos & hl_endpos to account for processing by cvt_text.
849 */
850 static void
851adj_hilite(anchor, linepos, cvt_ops)
852 struct hilite *anchor;
853 POSITION linepos;
854 int cvt_ops;
855{
856 char *line;
857 char *oline;
858 int line_len;
859 char *line_end;
860 struct hilite *hl;
861 int checkstart;
862 POSITION opos;
863 POSITION npos;
864 POSITION hl_opos;
865 POSITION hl_npos;
866 LWCHAR ch;
867 int ncwidth;
868
869 /*
870 * The line was already scanned and hilites were added (in hilite_line).
871 * But it was assumed that each char position in the line
872 * correponds to one char position in the file.
873 * This may not be true if cvt_text modified the line.
874 * Get the raw line again. Look at each character.
875 */
876 (void) forw_raw_line(linepos, &line, &line_len);
877 line_end = line + line_len;
878 opos = npos = linepos;
879 hl = anchor->hl_first;
880 if (hl == NULL)
881 return;
882 hl_opos = hl_npos = hl->hl_startpos;
883 checkstart = TRUE;
884
885 while (hl != NULL && line < line_end)
886 {
887 /*
888 * See if we need to adjust the current hl_startpos or
889 * hl_endpos. After adjusting startpos[i], move to endpos[i].
890 * After adjusting endpos[i], move to startpos[i+1].
891 * The hilite list must be sorted thus:
892 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
893 */
894 oline = line;
895 ch = step_char(&line, +1, line_end);
896 ncwidth = line - oline;
897 npos += ncwidth;
898
899 /* Figure out how this char was processed by cvt_text. */
900 if ((cvt_ops & CVT_BS) && ch == '\b')
901 {
902 /* Skip the backspace and the following char. */
903 oline = line;
904 ch = step_char(&line, +1, line_end);
905 ncwidth = line - oline;
906 npos += ncwidth;
907 } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch))
908 {
909 /* Converted uppercase to lower.
910 * Note that this may have changed the number of bytes
911 * that the character occupies. */
912 char dbuf[6];
913 char *dst = dbuf;
914 put_wchar(&dst, TO_LOWER(ch));
915 opos += dst - dbuf;
916 } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch))
917 {
918 /* Skip to end of ANSI escape sequence. */
919 line++; /* skip the CSI start char */
920 npos++;
921 while (line < line_end)
922 {
923 npos++;
924 if (!is_ansi_middle(*line++))
925 break;
926 }
927 } else
928 {
929 /* Ordinary unprocessed character. */
930 opos += ncwidth;
931 }
932
933 if (opos == hl_opos) {
934 /* Adjust highlight position. */
935 hl_npos = npos;
936 }
937 if (opos > hl_opos)
938 {
939 /*
940 * We've moved past the highlight position; store the
941 * adjusted highlight position and move to the next highlight.
942 */
943 if (checkstart)
944 {
945 hl->hl_startpos = hl_npos;
946 hl_opos = hl->hl_endpos;
947 checkstart = FALSE;
948 } else
949 {
950 hl->hl_endpos = hl_npos;
951 hl = hl->hl_next;
952 if (hl != NULL)
953 hl_opos = hl->hl_startpos;
954 checkstart = TRUE;
955 }
956 hl_npos = npos;
957 }
958 }
959}
960
961/*
962 * Make a hilite for each string in a physical line which matches
963 * the current pattern.
964 * sp,ep delimit the first match already found.
965 */
966 static void
471 * Make a hilite for each string in a physical line which matches
472 * the current pattern.
473 * sp,ep delimit the first match already found.
474 */
475 static void
967hilite_line(linepos, line, line_len, sp, ep, cvt_ops)
476hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops)
968 POSITION linepos;
969 char *line;
970 int line_len;
477 POSITION linepos;
478 char *line;
479 int line_len;
480 int *chpos;
971 char *sp;
972 char *ep;
973 int cvt_ops;
974{
975 char *searchp;
976 char *line_end = line + line_len;
977 struct hilite *hl;
481 char *sp;
482 char *ep;
483 int cvt_ops;
484{
485 char *searchp;
486 char *line_end = line + line_len;
487 struct hilite *hl;
978 struct hilite hilites;
979
980 if (sp == NULL || ep == NULL)
981 return;
982 /*
983 * sp and ep delimit the first match in the line.
984 * Mark the corresponding file positions, then
985 * look for further matches and mark them.
986 * {{ This technique, of calling match_pattern on subsequent
987 * substrings of the line, may mark more than is correct
988 * if the pattern starts with "^". This bug is fixed
989 * for those regex functions that accept a notbol parameter
990 * (currently POSIX, PCRE and V8-with-regexec2). }}
991 */
992 searchp = line;
488
489 if (sp == NULL || ep == NULL)
490 return;
491 /*
492 * sp and ep delimit the first match in the line.
493 * Mark the corresponding file positions, then
494 * look for further matches and mark them.
495 * {{ This technique, of calling match_pattern on subsequent
496 * substrings of the line, may mark more than is correct
497 * if the pattern starts with "^". This bug is fixed
498 * for those regex functions that accept a notbol parameter
499 * (currently POSIX, PCRE and V8-with-regexec2). }}
500 */
501 searchp = line;
993 /*
994 * Put the hilites into a temporary list until they're adjusted.
995 */
996 hilites.hl_first = NULL;
997 do {
998 if (ep > sp)
999 {
502 do {
503 if (ep > sp)
504 {
1000 /*
1001 * Assume that each char position in the "line"
1002 * buffer corresponds to one char position in the file.
1003 * This is not quite true; we need to adjust later.
1004 */
1005 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
505 hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
1006 hl->hl_startpos = linepos + (sp-line);
1007 hl->hl_endpos = linepos + (ep-line);
1008 add_hilite(&hilites, hl);
506 hl->hl_startpos = linepos + chpos[sp-line];
507 hl->hl_endpos = linepos + chpos[ep-line];
508 add_hilite(&hilite_anchor, hl);
1009 }
1010 /*
1011 * If we matched more than zero characters,
1012 * move to the first char after the string we matched.
1013 * If we matched zero, just move to the next char.
1014 */
1015 if (ep > searchp)
1016 searchp = ep;
1017 else if (searchp != line_end)
1018 searchp++;
1019 else /* end of line */
1020 break;
509 }
510 /*
511 * If we matched more than zero characters,
512 * move to the first char after the string we matched.
513 * If we matched zero, just move to the next char.
514 */
515 if (ep > searchp)
516 searchp = ep;
517 else if (searchp != line_end)
518 searchp++;
519 else /* end of line */
520 break;
1021 } while (match_pattern(search_pattern, searchp, line_end - searchp, &sp, &ep, 1, last_search_type));
1022
1023 /*
1024 * If there were backspaces in the original line, they
1025 * were removed, and hl_startpos/hl_endpos are not correct.
1026 * {{ This is very ugly. }}
1027 */
1028 adj_hilite(&hilites, linepos, cvt_ops);
1029
1030 /*
1031 * Now put the hilites into the real list.
1032 */
1033 while ((hl = hilites.hl_next) != NULL)
1034 {
1035 hilites.hl_next = hl->hl_next;
1036 add_hilite(&hilite_anchor, hl);
1037 }
521 } while (match_pattern(search_info.compiled, search_info.text,
522 searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type));
1038}
1039#endif
1040
1041/*
1042 * Change the caseless-ness of searches.
1043 * Updates the internal search state to reflect a change in the -i flag.
1044 */
1045 public void

--- 5 unchanged lines hidden (view full) ---

1051 * Just set the search caselessness to the global caselessness.
1052 */
1053 is_caseless = caseless;
1054 else
1055 /*
1056 * Pattern did have uppercase.
1057 * Discard the pattern; we can't change search caselessness now.
1058 */
523}
524#endif
525
526/*
527 * Change the caseless-ness of searches.
528 * Updates the internal search state to reflect a change in the -i flag.
529 */
530 public void

--- 5 unchanged lines hidden (view full) ---

536 * Just set the search caselessness to the global caselessness.
537 */
538 is_caseless = caseless;
539 else
540 /*
541 * Pattern did have uppercase.
542 * Discard the pattern; we can't change search caselessness now.
543 */
1059 uncompile_search_pattern();
544 clear_pattern(&search_info);
1060}
1061
1062#if HILITE_SEARCH
1063/*
1064 * Find matching text which is currently on screen and highlight it.
1065 */
1066 static void
1067hilite_screen()

--- 116 unchanged lines hidden (view full) ---

1184{
1185 char *line;
1186 char *cline;
1187 int line_len;
1188 LINENUM linenum;
1189 char *sp, *ep;
1190 int line_match;
1191 int cvt_ops;
545}
546
547#if HILITE_SEARCH
548/*
549 * Find matching text which is currently on screen and highlight it.
550 */
551 static void
552hilite_screen()

--- 116 unchanged lines hidden (view full) ---

669{
670 char *line;
671 char *cline;
672 int line_len;
673 LINENUM linenum;
674 char *sp, *ep;
675 int line_match;
676 int cvt_ops;
677 int cvt_len;
678 int *chpos;
1192 POSITION linepos, oldpos;
1193
1194 linenum = find_linenum(pos);
1195 oldpos = pos;
1196 for (;;)
1197 {
1198 /*
1199 * Get lines until we find a matching one or until

--- 55 unchanged lines hidden (view full) ---

1255 /*
1256 * If we're using line numbers, we might as well
1257 * remember the information we have now (the position
1258 * and line number of the current line).
1259 * Don't do it for every line because it slows down
1260 * the search. Remember the line number only if
1261 * we're "far" from the last place we remembered it.
1262 */
679 POSITION linepos, oldpos;
680
681 linenum = find_linenum(pos);
682 oldpos = pos;
683 for (;;)
684 {
685 /*
686 * Get lines until we find a matching one or until

--- 55 unchanged lines hidden (view full) ---

742 /*
743 * If we're using line numbers, we might as well
744 * remember the information we have now (the position
745 * and line number of the current line).
746 * Don't do it for every line because it slows down
747 * the search. Remember the line number only if
748 * we're "far" from the last place we remembered it.
749 */
1263 if (linenums && abs((int)(pos - oldpos)) > 1024)
750 if (linenums && abs((int)(pos - oldpos)) > 2048)
1264 add_lnum(linenum, pos);
1265 oldpos = pos;
1266
1267 if (is_filtered(linepos))
1268 continue;
1269
1270 /*
1271 * If it's a caseless search, convert the line to lowercase.
1272 * If we're doing backspace processing, delete backspaces.
1273 */
1274 cvt_ops = get_cvt_ops();
751 add_lnum(linenum, pos);
752 oldpos = pos;
753
754 if (is_filtered(linepos))
755 continue;
756
757 /*
758 * If it's a caseless search, convert the line to lowercase.
759 * If we're doing backspace processing, delete backspaces.
760 */
761 cvt_ops = get_cvt_ops();
1275 cline = calloc(1, cvt_length(line_len, cvt_ops));
1276 cvt_text(cline, line, &line_len, cvt_ops);
762 cvt_len = cvt_length(line_len, cvt_ops);
763 cline = (char *) ecalloc(1, cvt_len);
764 chpos = cvt_alloc_chpos(cvt_len);
765 cvt_text(cline, line, chpos, &line_len, cvt_ops);
1277
1278#if HILITE_SEARCH
1279 /*
1280 * Check to see if the line matches the filter pattern.
1281 * If so, add an entry to the filter list.
1282 */
766
767#if HILITE_SEARCH
768 /*
769 * Check to see if the line matches the filter pattern.
770 * If so, add an entry to the filter list.
771 */
1283 if ((search_type & SRCH_FIND_ALL) &&
1284 !is_null_pattern(filter_pattern))
1285 {
1286 int line_filter = match_pattern(filter_pattern,
1287 cline, line_len, &sp, &ep, 0, last_filter_type);
772 if ((search_type & SRCH_FIND_ALL) && prev_pattern(&filter_info)) {
773 int line_filter = match_pattern(filter_info.compiled, filter_info.text,
774 cline, line_len, &sp, &ep, 0, filter_info.search_type);
1288 if (line_filter)
1289 {
1290 struct hilite *hl = (struct hilite *)
1291 ecalloc(1, sizeof(struct hilite));
1292 hl->hl_startpos = linepos;
1293 hl->hl_endpos = pos;
1294 add_hilite(&filter_anchor, hl);
1295 }
1296 }
1297#endif
1298
1299 /*
1300 * Test the next line to see if we have a match.
1301 * We are successful if we either want a match and got one,
1302 * or if we want a non-match and got one.
1303 */
775 if (line_filter)
776 {
777 struct hilite *hl = (struct hilite *)
778 ecalloc(1, sizeof(struct hilite));
779 hl->hl_startpos = linepos;
780 hl->hl_endpos = pos;
781 add_hilite(&filter_anchor, hl);
782 }
783 }
784#endif
785
786 /*
787 * Test the next line to see if we have a match.
788 * We are successful if we either want a match and got one,
789 * or if we want a non-match and got one.
790 */
1304 if (!is_null_pattern(search_pattern))
791 if (prev_pattern(&search_info))
1305 {
792 {
1306 line_match = match_pattern(search_pattern,
1307 cline, line_len, &sp, &ep, 0, search_type);
793 line_match = match_pattern(search_info.compiled, search_info.text,
794 cline, line_len, &sp, &ep, 0, search_type); //FIXME search_info.search_type
1308 if (line_match)
1309 {
1310 /*
1311 * Got a match.
1312 */
1313 if (search_type & SRCH_FIND_ALL)
1314 {
1315#if HILITE_SEARCH
1316 /*
1317 * We are supposed to find all matches in the range.
1318 * Just add the matches in this line to the
1319 * hilite list and keep searching.
1320 */
795 if (line_match)
796 {
797 /*
798 * Got a match.
799 */
800 if (search_type & SRCH_FIND_ALL)
801 {
802#if HILITE_SEARCH
803 /*
804 * We are supposed to find all matches in the range.
805 * Just add the matches in this line to the
806 * hilite list and keep searching.
807 */
1321 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
808 hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
1322#endif
1323 } else if (--matches <= 0)
1324 {
1325 /*
1326 * Found the one match we're looking for.
1327 * Return it.
1328 */
1329#if HILITE_SEARCH
1330 if (hilite_search == OPT_ON)
1331 {
1332 /*
1333 * Clear the hilite list and add only
1334 * the matches in this one line.
1335 */
1336 clr_hilite();
809#endif
810 } else if (--matches <= 0)
811 {
812 /*
813 * Found the one match we're looking for.
814 * Return it.
815 */
816#if HILITE_SEARCH
817 if (hilite_search == OPT_ON)
818 {
819 /*
820 * Clear the hilite list and add only
821 * the matches in this one line.
822 */
823 clr_hilite();
1337 hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
824 hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
1338 }
1339#endif
1340 free(cline);
825 }
826#endif
827 free(cline);
828 free(chpos);
1341 if (plinepos != NULL)
1342 *plinepos = linepos;
1343 return (0);
1344 }
1345 }
1346 }
1347 free(cline);
829 if (plinepos != NULL)
830 *plinepos = linepos;
831 return (0);
832 }
833 }
834 }
835 free(cline);
836 free(chpos);
1348 }
1349}
1350
1351/*
1352 * search for a pattern in history. If found, compile that pattern.
1353 */
1354 static int
1355hist_pattern(search_type)
1356 int search_type;
1357{
1358#if CMD_HISTORY
1359 char *pattern;
1360
1361 set_mlist(ml_search, 0);
1362 pattern = cmd_lastpattern();
1363 if (pattern == NULL)
1364 return (0);
1365
837 }
838}
839
840/*
841 * search for a pattern in history. If found, compile that pattern.
842 */
843 static int
844hist_pattern(search_type)
845 int search_type;
846{
847#if CMD_HISTORY
848 char *pattern;
849
850 set_mlist(ml_search, 0);
851 pattern = cmd_lastpattern();
852 if (pattern == NULL)
853 return (0);
854
1366 if (compile_pattern(pattern, search_type, &search_pattern) < 0)
855 if (set_pattern(&search_info, pattern, search_type) < 0)
1367 return (0);
1368
1369 is_ucase_pattern = is_ucase(pattern);
1370 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1371 is_caseless = 0;
1372 else
1373 is_caseless = caseless;
1374

--- 25 unchanged lines hidden (view full) ---

1400{
1401 POSITION pos;
1402
1403 if (pattern == NULL || *pattern == '\0')
1404 {
1405 /*
1406 * A null pattern means use the previously compiled pattern.
1407 */
856 return (0);
857
858 is_ucase_pattern = is_ucase(pattern);
859 if (is_ucase_pattern && caseless != OPT_ONPLUS)
860 is_caseless = 0;
861 else
862 is_caseless = caseless;
863

--- 25 unchanged lines hidden (view full) ---

889{
890 POSITION pos;
891
892 if (pattern == NULL || *pattern == '\0')
893 {
894 /*
895 * A null pattern means use the previously compiled pattern.
896 */
1408 if (!prev_pattern() && !hist_pattern(search_type))
897 if (!prev_pattern(&search_info) && !hist_pattern(search_type))
1409 {
1410 error("No previous regular expression", NULL_PARG);
1411 return (-1);
1412 }
1413 if ((search_type & SRCH_NO_REGEX) !=
898 {
899 error("No previous regular expression", NULL_PARG);
900 return (-1);
901 }
902 if ((search_type & SRCH_NO_REGEX) !=
1414 (last_search_type & SRCH_NO_REGEX))
903 (search_info.search_type & SRCH_NO_REGEX))
1415 {
1416 error("Please re-enter search pattern", NULL_PARG);
1417 return -1;
1418 }
1419#if HILITE_SEARCH
1420 if (hilite_search == OPT_ON)
1421 {
1422 /*

--- 13 unchanged lines hidden (view full) ---

1436 }
1437 hide_hilite = 0;
1438#endif
1439 } else
1440 {
1441 /*
1442 * Compile the pattern.
1443 */
904 {
905 error("Please re-enter search pattern", NULL_PARG);
906 return -1;
907 }
908#if HILITE_SEARCH
909 if (hilite_search == OPT_ON)
910 {
911 /*

--- 13 unchanged lines hidden (view full) ---

925 }
926 hide_hilite = 0;
927#endif
928 } else
929 {
930 /*
931 * Compile the pattern.
932 */
1444 if (compile_pattern(pattern, search_type, &search_pattern) < 0)
933 if (set_pattern(&search_info, pattern, search_type) < 0)
1445 return (-1);
1446 /*
1447 * Ignore case if -I is set OR
1448 * -i is set AND the pattern is all lowercase.
1449 */
1450 is_ucase_pattern = is_ucase(pattern);
1451 if (is_ucase_pattern && caseless != OPT_ONPLUS)
1452 is_caseless = 0;

--- 91 unchanged lines hidden (view full) ---

1544 int maxlines;
1545{
1546 POSITION nprep_startpos = prep_startpos;
1547 POSITION nprep_endpos = prep_endpos;
1548 POSITION new_epos;
1549 POSITION max_epos;
1550 int result;
1551 int i;
934 return (-1);
935 /*
936 * Ignore case if -I is set OR
937 * -i is set AND the pattern is all lowercase.
938 */
939 is_ucase_pattern = is_ucase(pattern);
940 if (is_ucase_pattern && caseless != OPT_ONPLUS)
941 is_caseless = 0;

--- 91 unchanged lines hidden (view full) ---

1033 int maxlines;
1034{
1035 POSITION nprep_startpos = prep_startpos;
1036 POSITION nprep_endpos = prep_endpos;
1037 POSITION new_epos;
1038 POSITION max_epos;
1039 int result;
1040 int i;
1041
1552/*
1553 * Search beyond where we're asked to search, so the prep region covers
1554 * more than we need. Do one big search instead of a bunch of small ones.
1555 */
1556#define SEARCH_MORE (3*size_linebuf)
1557
1042/*
1043 * Search beyond where we're asked to search, so the prep region covers
1044 * more than we need. Do one big search instead of a bunch of small ones.
1045 */
1046#define SEARCH_MORE (3*size_linebuf)
1047
1558 if (!prev_pattern() && !is_filtering())
1048 if (!prev_pattern(&search_info) && !is_filtering())
1559 return;
1560
1561 /*
1562 * If we're limited to a max number of lines, figure out the
1563 * file position we should stop at.
1564 */
1565 if (maxlines < 0)
1566 max_epos = NULL_POSITION;

--- 76 unchanged lines hidden (view full) ---

1643 epos > max_epos)
1644 /*
1645 * Don't go past the max position we're allowed.
1646 */
1647 epos = max_epos;
1648
1649 if (epos == NULL_POSITION || epos > spos)
1650 {
1049 return;
1050
1051 /*
1052 * If we're limited to a max number of lines, figure out the
1053 * file position we should stop at.
1054 */
1055 if (maxlines < 0)
1056 max_epos = NULL_POSITION;

--- 76 unchanged lines hidden (view full) ---

1133 epos > max_epos)
1134 /*
1135 * Don't go past the max position we're allowed.
1136 */
1137 epos = max_epos;
1138
1139 if (epos == NULL_POSITION || epos > spos)
1140 {
1651 result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
1141 int search_type = SRCH_FORW | SRCH_FIND_ALL;
1142 search_type |= (search_info.search_type & SRCH_NO_REGEX);
1143 result = search_range(spos, epos, search_type, 0,
1652 maxlines, (POSITION*)NULL, &new_epos);
1653 if (result < 0)
1654 return;
1655 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
1656 nprep_endpos = new_epos;
1657 }
1658 prep_startpos = nprep_startpos;
1659 prep_endpos = nprep_endpos;

--- 4 unchanged lines hidden (view full) ---

1664 */
1665 public void
1666set_filter_pattern(pattern, search_type)
1667 char *pattern;
1668 int search_type;
1669{
1670 clr_filter();
1671 if (pattern == NULL || *pattern == '\0')
1144 maxlines, (POSITION*)NULL, &new_epos);
1145 if (result < 0)
1146 return;
1147 if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
1148 nprep_endpos = new_epos;
1149 }
1150 prep_startpos = nprep_startpos;
1151 prep_endpos = nprep_endpos;

--- 4 unchanged lines hidden (view full) ---

1156 */
1157 public void
1158set_filter_pattern(pattern, search_type)
1159 char *pattern;
1160 int search_type;
1161{
1162 clr_filter();
1163 if (pattern == NULL || *pattern == '\0')
1672 uncompile_filter_pattern();
1164 clear_pattern(&filter_info);
1673 else
1165 else
1674 compile_pattern(pattern, search_type, &filter_pattern);
1166 set_pattern(&filter_info, pattern, search_type);
1675 screen_trashed = 1;
1676}
1677
1678/*
1679 * Is there a line filter in effect?
1680 */
1681 public int
1682is_filtering()
1683{
1684 if (ch_getflags() & CH_HELPFILE)
1685 return (0);
1167 screen_trashed = 1;
1168}
1169
1170/*
1171 * Is there a line filter in effect?
1172 */
1173 public int
1174is_filtering()
1175{
1176 if (ch_getflags() & CH_HELPFILE)
1177 return (0);
1686 return !is_null_pattern(filter_pattern);
1178 return prev_pattern(&filter_info);
1687}
1688#endif
1689
1179}
1180#endif
1181
1690/*
1691 * Simple pattern matching function.
1692 * It supports no metacharacters like *, etc.
1693 */
1694 static int
1695match(pattern, pattern_len, buf, buf_len, pfound, pend)
1696 char *pattern;
1697 int pattern_len;
1698 char *buf;
1699 int buf_len;
1700 char **pfound, **pend;
1701{
1702 register char *pp, *lp;
1703 register char *pattern_end = pattern + pattern_len;
1704 register char *buf_end = buf + buf_len;
1705
1706 for ( ; buf < buf_end; buf++)
1707 {
1708 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
1709 if (pp == pattern_end || lp == buf_end)
1710 break;
1711 if (pp == pattern_end)
1712 {
1713 if (pfound != NULL)
1714 *pfound = buf;
1715 if (pend != NULL)
1716 *pend = lp;
1717 return (1);
1718 }
1719 }
1720 return (0);
1721}
1722
1723#if HAVE_V8_REGCOMP
1724/*
1725 * This function is called by the V8 regcomp to report
1726 * errors in regular expressions.
1727 */
1728 void
1729regerror(s)
1730 char *s;
1731{
1732 PARG parg;
1733
1734 parg.p_string = s;
1735 error("%s", &parg);
1736}
1737#endif
1738
1182#if HAVE_V8_REGCOMP
1183/*
1184 * This function is called by the V8 regcomp to report
1185 * errors in regular expressions.
1186 */
1187 void
1188regerror(s)
1189 char *s;
1190{
1191 PARG parg;
1192
1193 parg.p_string = s;
1194 error("%s", &parg);
1195}
1196#endif
1197