~ubuntu-branches/ubuntu/raring/less/raring-proposed

« back to all changes in this revision

Viewing changes to search.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Schoepf
  • Date: 2002-04-04 16:43:52 UTC
  • Revision ID: james.westby@ubuntu.com-20020404164352-qldq048yoc7x5sd5
Tags: upstream-374
ImportĀ upstreamĀ versionĀ 374

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1984-2000  Mark Nudelman
 
3
 *
 
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.
 
6
 *
 
7
 * For more information about less, or for information on how to 
 
8
 * contact the author, see the README file.
 
9
 */
 
10
 
 
11
 
 
12
/*
 
13
 * Routines to search a file for a pattern.
 
14
 */
 
15
 
 
16
#include "less.h"
 
17
#include "position.h"
 
18
 
 
19
#define MINPOS(a,b)     (((a) < (b)) ? (a) : (b))
 
20
#define MAXPOS(a,b)     (((a) > (b)) ? (a) : (b))
 
21
 
 
22
#if HAVE_POSIX_REGCOMP
 
23
#include <regex.h>
 
24
#ifdef REG_EXTENDED
 
25
#define REGCOMP_FLAG    REG_EXTENDED
 
26
#else
 
27
#define REGCOMP_FLAG    0
 
28
#endif
 
29
#endif
 
30
#if HAVE_PCRE
 
31
#include <pcre.h>
 
32
#endif
 
33
#if HAVE_RE_COMP
 
34
char *re_comp();
 
35
int re_exec();
 
36
#endif
 
37
#if HAVE_REGCMP
 
38
char *regcmp();
 
39
char *regex();
 
40
extern char *__loc1;
 
41
#endif
 
42
#if HAVE_V8_REGCOMP
 
43
#include "regexp.h"
 
44
#endif
 
45
 
 
46
static int match();
 
47
 
 
48
extern int sigs;
 
49
extern int how_search;
 
50
extern int caseless;
 
51
extern int linenums;
 
52
extern int sc_height;
 
53
extern int jump_sline;
 
54
extern int bs_mode;
 
55
extern int status_col;
 
56
extern POSITION start_attnpos;
 
57
extern POSITION end_attnpos;
 
58
#if HILITE_SEARCH
 
59
extern int hilite_search;
 
60
extern int screen_trashed;
 
61
extern int size_linebuf;
 
62
extern int squished;
 
63
extern int can_goto_line;
 
64
static int hide_hilite;
 
65
static POSITION prep_startpos;
 
66
static POSITION prep_endpos;
 
67
 
 
68
struct hilite
 
69
{
 
70
        struct hilite *hl_next;
 
71
        POSITION hl_startpos;
 
72
        POSITION hl_endpos;
 
73
};
 
74
static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
 
75
#define hl_first        hl_next
 
76
#endif
 
77
 
 
78
/*
 
79
 * These are the static variables that represent the "remembered"
 
80
 * search pattern.  
 
81
 */
 
82
#if HAVE_POSIX_REGCOMP
 
83
static regex_t *regpattern = NULL;
 
84
#endif
 
85
#if HAVE_PCRE
 
86
pcre *regpattern = NULL;
 
87
#endif
 
88
#if HAVE_RE_COMP
 
89
int re_pattern = 0;
 
90
#endif
 
91
#if HAVE_REGCMP
 
92
static char *cpattern = NULL;
 
93
#endif
 
94
#if HAVE_V8_REGCOMP
 
95
static struct regexp *regpattern = NULL;
 
96
#endif
 
97
 
 
98
static int is_caseless;
 
99
static int is_ucase_pattern;
 
100
static int last_search_type;
 
101
static char *last_pattern = NULL;
 
102
 
 
103
/*
 
104
 * Convert text.  Perform one or more of these transformations:
 
105
 */
 
106
#define CVT_TO_LC       01      /* Convert upper-case to lower-case */
 
107
#define CVT_BS          02      /* Do backspace processing */
 
108
#define CVT_CRLF        04      /* Remove CR after LF */
 
109
 
 
110
        static void
 
111
cvt_text(odst, osrc, ops)
 
112
        char *odst;
 
113
        char *osrc;
 
114
        int ops;
 
115
{
 
116
        register char *dst;
 
117
        register char *src;
 
118
 
 
119
        for (src = osrc, dst = odst;  *src != '\0';  src++, dst++)
 
120
        {
 
121
                if ((ops & CVT_TO_LC) && isupper((unsigned char) *src))
 
122
                        /* Convert uppercase to lowercase. */
 
123
                        *dst = tolower((unsigned char) *src);
 
124
                else if ((ops & CVT_BS) && *src == '\b' && dst > odst)
 
125
                        /* Delete BS and preceding char. */
 
126
                        dst -= 2;
 
127
                else 
 
128
                        /* Just copy. */
 
129
                        *dst = *src;
 
130
        }
 
131
        if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
 
132
                dst--;
 
133
        *dst = '\0';
 
134
}
 
135
 
 
136
/*
 
137
 * Are there any uppercase letters in this string?
 
138
 */
 
139
        static int
 
140
is_ucase(s)
 
141
        char *s;
 
142
{
 
143
        register char *p;
 
144
 
 
145
        for (p = s;  *p != '\0';  p++)
 
146
                if (isupper((unsigned char) *p))
 
147
                        return (1);
 
148
        return (0);
 
149
}
 
150
 
 
151
/*
 
152
 * Is there a previous (remembered) search pattern?
 
153
 */
 
154
        static int
 
155
prev_pattern()
 
156
{
 
157
        if (last_search_type & SRCH_NO_REGEX)
 
158
                return (last_pattern != NULL);
 
159
#if HAVE_POSIX_REGCOMP
 
160
        return (regpattern != NULL);
 
161
#endif
 
162
#if HAVE_PCRE
 
163
        return (regpattern != NULL);
 
164
#endif
 
165
#if HAVE_RE_COMP
 
166
        return (re_pattern != 0);
 
167
#endif
 
168
#if HAVE_REGCMP
 
169
        return (cpattern != NULL);
 
170
#endif
 
171
#if HAVE_V8_REGCOMP
 
172
        return (regpattern != NULL);
 
173
#endif
 
174
#if NO_REGEX
 
175
        return (last_pattern != NULL);
 
176
#endif
 
177
}
 
178
 
 
179
#if HILITE_SEARCH
 
180
/*
 
181
 * Repaint the hilites currently displayed on the screen.
 
182
 * Repaint each line which contains highlighted text.
 
183
 * If on==0, force all hilites off.
 
184
 */
 
185
        public void
 
186
repaint_hilite(on)
 
187
        int on;
 
188
{
 
189
        int slinenum;
 
190
        POSITION pos;
 
191
        POSITION epos;
 
192
        int save_hide_hilite;
 
193
 
 
194
        if (squished)
 
195
                repaint();
 
196
 
 
197
        save_hide_hilite = hide_hilite;
 
198
        if (!on)
 
199
        {
 
200
                if (hide_hilite)
 
201
                        return;
 
202
                hide_hilite = 1;
 
203
        }
 
204
 
 
205
        if (!can_goto_line)
 
206
        {
 
207
                repaint();
 
208
                hide_hilite = save_hide_hilite;
 
209
                return;
 
210
        }
 
211
 
 
212
        for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
 
213
        {
 
214
                pos = position(slinenum);
 
215
                if (pos == NULL_POSITION)
 
216
                        continue;
 
217
                epos = position(slinenum+1);
 
218
                /*
 
219
                 * If any character in the line is highlighted, 
 
220
                 * repaint the line.
 
221
                 */
 
222
                if (is_hilited(pos, epos, 1))
 
223
                {
 
224
                        (void) forw_line(pos);
 
225
                        goto_line(slinenum);
 
226
                        put_line();
 
227
                }
 
228
        }
 
229
        hide_hilite = save_hide_hilite;
 
230
}
 
231
 
 
232
/*
 
233
 * Clear the attn hilite.
 
234
 */
 
235
        public void
 
236
clear_attn()
 
237
{
 
238
        int slinenum;
 
239
        POSITION old_start_attnpos;
 
240
        POSITION old_end_attnpos;
 
241
        POSITION pos;
 
242
        POSITION epos;
 
243
 
 
244
        if (start_attnpos == NULL_POSITION)
 
245
                return;
 
246
        old_start_attnpos = start_attnpos;
 
247
        old_end_attnpos = end_attnpos;
 
248
        start_attnpos = end_attnpos = NULL_POSITION;
 
249
 
 
250
        if (!can_goto_line)
 
251
        {
 
252
                repaint();
 
253
                return;
 
254
        }
 
255
        if (squished)
 
256
                repaint();
 
257
 
 
258
        for (slinenum = TOP;  slinenum < TOP + sc_height-1;  slinenum++)
 
259
        {
 
260
                pos = position(slinenum);
 
261
                if (pos == NULL_POSITION)
 
262
                        continue;
 
263
                epos = position(slinenum+1);
 
264
                if (pos < old_end_attnpos &&
 
265
                     (epos == NULL_POSITION || epos > old_start_attnpos))
 
266
                {
 
267
                        (void) forw_line(pos);
 
268
                        goto_line(slinenum);
 
269
                        put_line();
 
270
                }
 
271
        }
 
272
}
 
273
#endif
 
274
 
 
275
/*
 
276
 * Hide search string highlighting.
 
277
 */
 
278
        public void
 
279
undo_search()
 
280
{
 
281
        if (!prev_pattern())
 
282
        {
 
283
                error("No previous regular expression", NULL_PARG);
 
284
                return;
 
285
        }
 
286
#if HILITE_SEARCH
 
287
        hide_hilite = !hide_hilite;
 
288
        repaint_hilite(1);
 
289
#endif
 
290
}
 
291
 
 
292
/*
 
293
 * Compile a search pattern, for future use by match_pattern.
 
294
 */
 
295
        static int
 
296
compile_pattern(pattern, search_type)
 
297
        char *pattern;
 
298
        int search_type;
 
299
{
 
300
        if ((search_type & SRCH_NO_REGEX) == 0)
 
301
        {
 
302
#if HAVE_POSIX_REGCOMP
 
303
                regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
 
304
                if (regcomp(s, pattern, REGCOMP_FLAG))
 
305
                {
 
306
                        free(s);
 
307
                        error("Invalid pattern", NULL_PARG);
 
308
                        return (-1);
 
309
                }
 
310
                if (regpattern != NULL)
 
311
                        regfree(regpattern);
 
312
                regpattern = s;
 
313
#endif
 
314
#if HAVE_PCRE
 
315
                pcre *comp;
 
316
                const char *errstring;
 
317
                int erroffset;
 
318
                PARG parg;
 
319
                comp = pcre_compile(pattern, 0,
 
320
                                &errstring, &erroffset, NULL);
 
321
                if (comp == NULL)
 
322
                {
 
323
                        parg.p_string = (char *) errstring;
 
324
                        error("%s", &parg);
 
325
                        return (-1);
 
326
                }
 
327
                regpattern = comp;
 
328
#endif
 
329
#if HAVE_RE_COMP
 
330
                PARG parg;
 
331
                if ((parg.p_string = re_comp(pattern)) != NULL)
 
332
                {
 
333
                        error("%s", &parg);
 
334
                        return (-1);
 
335
                }
 
336
                re_pattern = 1;
 
337
#endif
 
338
#if HAVE_REGCMP
 
339
                char *s;
 
340
                if ((s = regcmp(pattern, 0)) == NULL)
 
341
                {
 
342
                        error("Invalid pattern", NULL_PARG);
 
343
                        return (-1);
 
344
                }
 
345
                if (cpattern != NULL)
 
346
                        free(cpattern);
 
347
                cpattern = s;
 
348
#endif
 
349
#if HAVE_V8_REGCOMP
 
350
                struct regexp *s;
 
351
                if ((s = regcomp(pattern)) == NULL)
 
352
                {
 
353
                        /*
 
354
                         * regcomp has already printed an error message 
 
355
                         * via regerror().
 
356
                         */
 
357
                        return (-1);
 
358
                }
 
359
                if (regpattern != NULL)
 
360
                        free(regpattern);
 
361
                regpattern = s;
 
362
#endif
 
363
        }
 
364
 
 
365
        if (last_pattern != NULL)
 
366
                free(last_pattern);
 
367
        last_pattern = (char *) calloc(1, strlen(pattern)+1);
 
368
        if (last_pattern != NULL)
 
369
                strcpy(last_pattern, pattern);
 
370
 
 
371
        last_search_type = search_type;
 
372
        return (0);
 
373
}
 
374
 
 
375
/*
 
376
 * Forget that we have a compiled pattern.
 
377
 */
 
378
        static void
 
379
uncompile_pattern()
 
380
{
 
381
#if HAVE_POSIX_REGCOMP
 
382
        if (regpattern != NULL)
 
383
                regfree(regpattern);
 
384
        regpattern = NULL;
 
385
#endif
 
386
#if HAVE_PCRE
 
387
        if (regpattern != NULL)
 
388
                pcre_free(regpattern);
 
389
        regpattern = NULL;
 
390
#endif
 
391
#if HAVE_RE_COMP
 
392
        re_pattern = 0;
 
393
#endif
 
394
#if HAVE_REGCMP
 
395
        if (cpattern != NULL)
 
396
                free(cpattern);
 
397
        cpattern = NULL;
 
398
#endif
 
399
#if HAVE_V8_REGCOMP
 
400
        if (regpattern != NULL)
 
401
                free(regpattern);
 
402
        regpattern = NULL;
 
403
#endif
 
404
        last_pattern = NULL;
 
405
}
 
406
 
 
407
/*
 
408
 * Perform a pattern match with the previously compiled pattern.
 
409
 * Set sp and ep to the start and end of the matched string.
 
410
 */
 
411
        static int
 
412
match_pattern(line, sp, ep, notbol)
 
413
        char *line;
 
414
        char **sp;
 
415
        char **ep;
 
416
        int notbol;
 
417
{
 
418
        int matched;
 
419
 
 
420
        if (last_search_type & SRCH_NO_REGEX)
 
421
                return (match(last_pattern, line, sp, ep));
 
422
 
 
423
#if HAVE_POSIX_REGCOMP
 
424
        {
 
425
                regmatch_t rm;
 
426
                int flags = (notbol) ? REG_NOTBOL : 0;
 
427
                matched = !regexec(regpattern, line, 1, &rm, flags);
 
428
                if (!matched)
 
429
                        return (0);
 
430
#ifndef __WATCOMC__
 
431
                *sp = line + rm.rm_so;
 
432
                *ep = line + rm.rm_eo;
 
433
#else
 
434
                *sp = rm.rm_sp;
 
435
                *ep = rm.rm_ep;
 
436
#endif
 
437
        }
 
438
#endif
 
439
#if HAVE_PCRE
 
440
        {
 
441
                int flags = (notbol) ? PCRE_NOTBOL : 0;
 
442
                int ovector[3];
 
443
                matched = pcre_exec(regpattern, NULL, line, strlen(line),
 
444
                        0, flags, ovector, 3) >= 0;
 
445
                if (!matched)
 
446
                        return (0);
 
447
                *sp = line + ovector[0];
 
448
                *ep = line + ovector[1];
 
449
        }
 
450
#endif
 
451
#if HAVE_RE_COMP
 
452
        matched = (re_exec(line) == 1);
 
453
        /*
 
454
         * re_exec doesn't seem to provide a way to get the matched string.
 
455
         */
 
456
        *sp = *ep = NULL;
 
457
#endif
 
458
#if HAVE_REGCMP
 
459
        *ep = regex(cpattern, line);
 
460
        matched = (*ep != NULL);
 
461
        if (!matched)
 
462
                return (0);
 
463
        *sp = __loc1;
 
464
#endif
 
465
#if HAVE_V8_REGCOMP
 
466
#if HAVE_REGEXEC2
 
467
        matched = regexec2(regpattern, line, notbol);
 
468
#else
 
469
        matched = regexec(regpattern, line);
 
470
#endif
 
471
        if (!matched)
 
472
                return (0);
 
473
        *sp = regpattern->startp[0];
 
474
        *ep = regpattern->endp[0];
 
475
#endif
 
476
#if NO_REGEX
 
477
        matched = match(last_pattern, line, sp, ep);
 
478
#endif
 
479
        return (matched);
 
480
}
 
481
 
 
482
#if HILITE_SEARCH
 
483
/*
 
484
 * Clear the hilite list.
 
485
 */
 
486
        public void
 
487
clr_hilite()
 
488
{
 
489
        struct hilite *hl;
 
490
        struct hilite *nexthl;
 
491
 
 
492
        for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = nexthl)
 
493
        {
 
494
                nexthl = hl->hl_next;
 
495
                free((void*)hl);
 
496
        }
 
497
        hilite_anchor.hl_first = NULL;
 
498
        prep_startpos = prep_endpos = NULL_POSITION;
 
499
}
 
500
 
 
501
/*
 
502
 * Should any characters in a specified range be highlighted?
 
503
 * If nohide is nonzero, don't consider hide_hilite.
 
504
 */
 
505
        public int
 
506
is_hilited(pos, epos, nohide)
 
507
        POSITION pos;
 
508
        POSITION epos;
 
509
        int nohide;
 
510
{
 
511
        struct hilite *hl;
 
512
 
 
513
        if (!status_col &&
 
514
            start_attnpos != NULL_POSITION && 
 
515
            pos < end_attnpos &&
 
516
             (epos == NULL_POSITION || epos > start_attnpos))
 
517
                /*
 
518
                 * The attn line overlaps this range.
 
519
                 */
 
520
                return (1);
 
521
 
 
522
        if (hilite_search == 0)
 
523
                /*
 
524
                 * Not doing highlighting.
 
525
                 */
 
526
                return (0);
 
527
 
 
528
        if (!nohide && hide_hilite)
 
529
                /*
 
530
                 * Highlighting is hidden.
 
531
                 */
 
532
                return (0);
 
533
 
 
534
        /*
 
535
         * Look at each highlight and see if any part of it falls in the range.
 
536
         */
 
537
        for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
 
538
        {
 
539
                if (hl->hl_endpos > pos &&
 
540
                    (epos == NULL_POSITION || epos > hl->hl_startpos))
 
541
                        return (1);
 
542
        }
 
543
        return (0);
 
544
}
 
545
 
 
546
/*
 
547
 * Add a new hilite to a hilite list.
 
548
 */
 
549
        static void
 
550
add_hilite(anchor, hl)
 
551
        struct hilite *anchor;
 
552
        struct hilite *hl;
 
553
{
 
554
        struct hilite *ihl;
 
555
 
 
556
        /*
 
557
         * Hilites are sorted in the list; find where new one belongs.
 
558
         * Insert new one after ihl.
 
559
         */
 
560
        for (ihl = anchor;  ihl->hl_next != NULL;  ihl = ihl->hl_next)
 
561
        {
 
562
                if (ihl->hl_next->hl_startpos > hl->hl_startpos)
 
563
                        break;
 
564
        }
 
565
 
 
566
        /*
 
567
         * Truncate hilite so it doesn't overlap any existing ones
 
568
         * above and below it.
 
569
         */
 
570
        if (ihl != anchor)
 
571
                hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
 
572
        if (ihl->hl_next != NULL)
 
573
                hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
 
574
        if (hl->hl_startpos >= hl->hl_endpos)
 
575
        {
 
576
                /*
 
577
                 * Hilite was truncated out of existence.
 
578
                 */
 
579
                free(hl);
 
580
                return;
 
581
        }
 
582
        hl->hl_next = ihl->hl_next;
 
583
        ihl->hl_next = hl;
 
584
}
 
585
 
 
586
/*
 
587
 * Adjust hl_startpos & hl_endpos to account for backspace processing.
 
588
 */
 
589
        static void
 
590
adj_hilite(anchor, linepos)
 
591
        struct hilite *anchor;
 
592
        POSITION linepos;
 
593
{
 
594
        char *line;
 
595
        struct hilite *hl;
 
596
        int checkstart;
 
597
        POSITION opos;
 
598
        POSITION npos;
 
599
 
 
600
        /*
 
601
         * The line was already scanned and hilites were added (in hilite_line).
 
602
         * But it was assumed that each char position in the line 
 
603
         * correponds to one char position in the file.
 
604
         * This may not be true if there are backspaces in the line.
 
605
         * Get the raw line again.  Look at each character.
 
606
         */
 
607
        (void) forw_raw_line(linepos, &line);
 
608
        opos = npos = linepos;
 
609
        hl = anchor->hl_first;
 
610
        checkstart = TRUE;
 
611
        while (hl != NULL)
 
612
        {
 
613
                /*
 
614
                 * See if we need to adjust the current hl_startpos or 
 
615
                 * hl_endpos.  After adjusting startpos[i], move to endpos[i].
 
616
                 * After adjusting endpos[i], move to startpos[i+1].
 
617
                 * The hilite list must be sorted thus: 
 
618
                 * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
 
619
                 */
 
620
                if (checkstart && hl->hl_startpos == opos)
 
621
                {
 
622
                        hl->hl_startpos = npos;
 
623
                        checkstart = FALSE;
 
624
                        continue; /* {{ not really necessary }} */
 
625
                } else if (!checkstart && hl->hl_endpos == opos)
 
626
                {
 
627
                        hl->hl_endpos = npos;
 
628
                        checkstart = TRUE;
 
629
                        hl = hl->hl_next;
 
630
                        continue; /* {{ necessary }} */
 
631
                }
 
632
                if (*line == '\0')
 
633
                        break;
 
634
                opos++;
 
635
                npos++;
 
636
                line++;
 
637
                while (line[0] == '\b' && line[1] != '\0')
 
638
                {
 
639
                        /*
 
640
                         * Found a backspace.  The file position moves
 
641
                         * forward by 2 relative to the processed line
 
642
                         * which was searched in hilite_line.
 
643
                         */
 
644
                        npos += 2;
 
645
                        line += 2;
 
646
                }
 
647
        }
 
648
}
 
649
 
 
650
/*
 
651
 * Make a hilite for each string in a physical line which matches 
 
652
 * the current pattern.
 
653
 * sp,ep delimit the first match already found.
 
654
 */
 
655
        static void
 
656
hilite_line(linepos, line, sp, ep)
 
657
        POSITION linepos;
 
658
        char *line;
 
659
        char *sp;
 
660
        char *ep;
 
661
{
 
662
        char *searchp;
 
663
        struct hilite *hl;
 
664
        struct hilite hilites;
 
665
 
 
666
        if (sp == NULL || ep == NULL)
 
667
                return;
 
668
        /*
 
669
         * sp and ep delimit the first match in the line.
 
670
         * Mark the corresponding file positions, then
 
671
         * look for further matches and mark them.
 
672
         * {{ This technique, of calling match_pattern on subsequent
 
673
         *    substrings of the line, may mark more than is correct
 
674
         *    if the pattern starts with "^".  This bug is fixed
 
675
         *    for those regex functions that accept a notbol parameter
 
676
         *    (currently POSIX and V8-with-regexec2). }}
 
677
         */
 
678
        searchp = line;
 
679
        /*
 
680
         * Put the hilites into a temporary list until they're adjusted.
 
681
         */
 
682
        hilites.hl_first = NULL;
 
683
        do {
 
684
                if (ep > sp)
 
685
                {
 
686
                        /*
 
687
                         * Assume that each char position in the "line"
 
688
                         * buffer corresponds to one char position in the file.
 
689
                         * This is not quite true; we need to adjust later.
 
690
                         */
 
691
                        hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
 
692
                        hl->hl_startpos = linepos + (sp-line);
 
693
                        hl->hl_endpos = linepos + (ep-line);
 
694
                        add_hilite(&hilites, hl);
 
695
                }
 
696
                /*
 
697
                 * If we matched more than zero characters,
 
698
                 * move to the first char after the string we matched.
 
699
                 * If we matched zero, just move to the next char.
 
700
                 */
 
701
                if (ep > searchp)
 
702
                        searchp = ep;
 
703
                else if (*searchp != '\0')
 
704
                        searchp++;
 
705
                else /* end of line */
 
706
                        break;
 
707
        } while (match_pattern(searchp, &sp, &ep, 1));
 
708
 
 
709
        if (bs_mode == BS_SPECIAL) 
 
710
        {
 
711
                /*
 
712
                 * If there were backspaces in the original line, they
 
713
                 * were removed, and hl_startpos/hl_endpos are not correct.
 
714
                 * {{ This is very ugly. }}
 
715
                 */
 
716
                adj_hilite(&hilites, linepos);
 
717
        }
 
718
        /*
 
719
         * Now put the hilites into the real list.
 
720
         */
 
721
        while ((hl = hilites.hl_next) != NULL)
 
722
        {
 
723
                hilites.hl_next = hl->hl_next;
 
724
                add_hilite(&hilite_anchor, hl);
 
725
        }
 
726
}
 
727
#endif
 
728
 
 
729
/*
 
730
 * Change the caseless-ness of searches.  
 
731
 * Updates the internal search state to reflect a change in the -i flag.
 
732
 */
 
733
        public void
 
734
chg_caseless()
 
735
{
 
736
        if (!is_ucase_pattern)
 
737
                /*
 
738
                 * Pattern did not have uppercase.
 
739
                 * Just set the search caselessness to the global caselessness.
 
740
                 */
 
741
                is_caseless = caseless;
 
742
        else
 
743
                /*
 
744
                 * Pattern did have uppercase.
 
745
                 * Discard the pattern; we can't change search caselessness now.
 
746
                 */
 
747
                uncompile_pattern();
 
748
}
 
749
 
 
750
#if HILITE_SEARCH
 
751
/*
 
752
 * Find matching text which is currently on screen and highlight it.
 
753
 */
 
754
        static void
 
755
hilite_screen()
 
756
{
 
757
        struct scrpos scrpos;
 
758
 
 
759
        get_scrpos(&scrpos);
 
760
        if (scrpos.pos == NULL_POSITION)
 
761
                return;
 
762
        prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
 
763
        repaint_hilite(1);
 
764
}
 
765
 
 
766
/*
 
767
 * Change highlighting parameters.
 
768
 */
 
769
        public void
 
770
chg_hilite()
 
771
{
 
772
        /*
 
773
         * Erase any highlights currently on screen.
 
774
         */
 
775
        clr_hilite();
 
776
        hide_hilite = 0;
 
777
 
 
778
        if (hilite_search == OPT_ONPLUS)
 
779
                /*
 
780
                 * Display highlights.
 
781
                 */
 
782
                hilite_screen();
 
783
}
 
784
#endif
 
785
 
 
786
/*
 
787
 * Figure out where to start a search.
 
788
 */
 
789
        static POSITION
 
790
search_pos(search_type)
 
791
        int search_type;
 
792
{
 
793
        POSITION pos;
 
794
        int linenum;
 
795
 
 
796
        if (empty_screen())
 
797
        {
 
798
                /*
 
799
                 * Start at the beginning (or end) of the file.
 
800
                 * The empty_screen() case is mainly for 
 
801
                 * command line initiated searches;
 
802
                 * for example, "+/xyz" on the command line.
 
803
                 * Also for multi-file (SRCH_PAST_EOF) searches.
 
804
                 */
 
805
                if (search_type & SRCH_FORW)
 
806
                {
 
807
                        return (ch_zero());
 
808
                } else
 
809
                {
 
810
                        pos = ch_length();
 
811
                        if (pos == NULL_POSITION)
 
812
                        {
 
813
                                (void) ch_end_seek();
 
814
                                pos = ch_length();
 
815
                        }
 
816
                        return (pos);
 
817
                }
 
818
        }
 
819
        if (how_search)
 
820
        {
 
821
                /*
 
822
                 * Search does not include current screen.
 
823
                 */
 
824
                if (search_type & SRCH_FORW)
 
825
                        linenum = BOTTOM_PLUS_ONE;
 
826
                else
 
827
                        linenum = TOP;
 
828
                pos = position(linenum);
 
829
        } else
 
830
        {
 
831
                /*
 
832
                 * Search includes current screen.
 
833
                 * It starts at the jump target (if searching backwards),
 
834
                 * or at the jump target plus one (if forwards).
 
835
                 */
 
836
                linenum = adjsline(jump_sline);
 
837
                pos = position(linenum);
 
838
                if (search_type & SRCH_FORW)
 
839
                {
 
840
                        pos = forw_raw_line(pos, (char **)NULL);
 
841
                        while (pos == NULL_POSITION)
 
842
                        {
 
843
                                if (++linenum >= sc_height)
 
844
                                        break;
 
845
                                pos = position(linenum);
 
846
                        }
 
847
                } else 
 
848
                {
 
849
                        while (pos == NULL_POSITION)
 
850
                        {
 
851
                                if (--linenum < 0)
 
852
                                        break;
 
853
                                pos = position(linenum);
 
854
                        }
 
855
                }
 
856
        }
 
857
        return (pos);
 
858
}
 
859
 
 
860
/*
 
861
 * Search a subset of the file, specified by start/end position.
 
862
 */
 
863
        static int
 
864
search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
 
865
        POSITION pos;
 
866
        POSITION endpos;
 
867
        int search_type;
 
868
        int matches;
 
869
        int maxlines;
 
870
        POSITION *plinepos;
 
871
        POSITION *pendpos;
 
872
{
 
873
        char *line;
 
874
        int linenum;
 
875
        char *sp, *ep;
 
876
        int line_match;
 
877
        POSITION linepos, oldpos;
 
878
 
 
879
        linenum = find_linenum(pos);
 
880
        oldpos = pos;
 
881
        for (;;)
 
882
        {
 
883
                /*
 
884
                 * Get lines until we find a matching one or until
 
885
                 * we hit end-of-file (or beginning-of-file if we're 
 
886
                 * going backwards), or until we hit the end position.
 
887
                 */
 
888
                if (ABORT_SIGS())
 
889
                {
 
890
                        /*
 
891
                         * A signal aborts the search.
 
892
                         */
 
893
                        return (-1);
 
894
                }
 
895
 
 
896
                if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
 
897
                {
 
898
                        /*
 
899
                         * Reached end position without a match.
 
900
                         */
 
901
                        if (pendpos != NULL)
 
902
                                *pendpos = pos;
 
903
                        return (matches);
 
904
                }
 
905
                if (maxlines > 0)
 
906
                        maxlines--;
 
907
 
 
908
                if (search_type & SRCH_FORW)
 
909
                {
 
910
                        /*
 
911
                         * Read the next line, and save the 
 
912
                         * starting position of that line in linepos.
 
913
                         */
 
914
                        linepos = pos;
 
915
                        pos = forw_raw_line(pos, &line);
 
916
                        if (linenum != 0)
 
917
                                linenum++;
 
918
                } else
 
919
                {
 
920
                        /*
 
921
                         * Read the previous line and save the
 
922
                         * starting position of that line in linepos.
 
923
                         */
 
924
                        pos = back_raw_line(pos, &line);
 
925
                        linepos = pos;
 
926
                        if (linenum != 0)
 
927
                                linenum--;
 
928
                }
 
929
 
 
930
                if (pos == NULL_POSITION)
 
931
                {
 
932
                        /*
 
933
                         * Reached EOF/BOF without a match.
 
934
                         */
 
935
                        if (pendpos != NULL)
 
936
                                *pendpos = oldpos;
 
937
                        return (matches);
 
938
                }
 
939
 
 
940
                /*
 
941
                 * If we're using line numbers, we might as well
 
942
                 * remember the information we have now (the position
 
943
                 * and line number of the current line).
 
944
                 * Don't do it for every line because it slows down
 
945
                 * the search.  Remember the line number only if
 
946
                 * we're "far" from the last place we remembered it.
 
947
                 */
 
948
                if (linenums && abs((int)(pos - oldpos)) > 1024)
 
949
                        add_lnum(linenum, pos);
 
950
                oldpos = pos;
 
951
 
 
952
                /*
 
953
                 * If it's a caseless search, convert the line to lowercase.
 
954
                 * If we're doing backspace processing, delete backspaces.
 
955
                 */
 
956
                if (is_caseless || bs_mode == BS_SPECIAL)
 
957
                {
 
958
                        int ops = 0;
 
959
                        if (is_caseless) 
 
960
                                ops |= CVT_TO_LC;
 
961
                        if (bs_mode == BS_SPECIAL)
 
962
                                ops |= CVT_BS;
 
963
                        if (bs_mode != BS_CONTROL)
 
964
                                ops |= CVT_CRLF;
 
965
                        cvt_text(line, line, ops);
 
966
                } else if (bs_mode != BS_CONTROL)
 
967
                {
 
968
                        cvt_text(line, line, CVT_CRLF);
 
969
                }
 
970
 
 
971
                /*
 
972
                 * Test the next line to see if we have a match.
 
973
                 * We are successful if we either want a match and got one,
 
974
                 * or if we want a non-match and got one.
 
975
                 */
 
976
                line_match = match_pattern(line, &sp, &ep, 0);
 
977
                line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
 
978
                                ((search_type & SRCH_NO_MATCH) && !line_match);
 
979
                if (!line_match)
 
980
                        continue;
 
981
                /*
 
982
                 * Got a match.
 
983
                 */
 
984
                if (search_type & SRCH_FIND_ALL)
 
985
                {
 
986
#if HILITE_SEARCH
 
987
                        /*
 
988
                         * We are supposed to find all matches in the range.
 
989
                         * Just add the matches in this line to the 
 
990
                         * hilite list and keep searching.
 
991
                         */
 
992
                        if (line_match)
 
993
                                hilite_line(linepos, line, sp, ep);
 
994
#endif
 
995
                } else if (--matches <= 0)
 
996
                {
 
997
                        /*
 
998
                         * Found the one match we're looking for.
 
999
                         * Return it.
 
1000
                         */
 
1001
#if HILITE_SEARCH
 
1002
                        if (hilite_search == 1)
 
1003
                        {
 
1004
                                /*
 
1005
                                 * Clear the hilite list and add only
 
1006
                                 * the matches in this one line.
 
1007
                                 */
 
1008
                                clr_hilite();
 
1009
                                if (line_match)
 
1010
                                        hilite_line(linepos, line, sp, ep);
 
1011
                        }
 
1012
#endif
 
1013
                        if (plinepos != NULL)
 
1014
                                *plinepos = linepos;
 
1015
                        return (0);
 
1016
                }
 
1017
        }
 
1018
}
 
1019
 
 
1020
/*
 
1021
 * Search for the n-th occurrence of a specified pattern, 
 
1022
 * either forward or backward.
 
1023
 * Return the number of matches not yet found in this file
 
1024
 * (that is, n minus the number of matches found).
 
1025
 * Return -1 if the search should be aborted.
 
1026
 * Caller may continue the search in another file 
 
1027
 * if less than n matches are found in this file.
 
1028
 */
 
1029
        public int
 
1030
search(search_type, pattern, n)
 
1031
        int search_type;
 
1032
        char *pattern;
 
1033
        int n;
 
1034
{
 
1035
        POSITION pos;
 
1036
        int ucase;
 
1037
 
 
1038
        if (pattern == NULL || *pattern == '\0')
 
1039
        {
 
1040
                /*
 
1041
                 * A null pattern means use the previously compiled pattern.
 
1042
                 */
 
1043
                if (!prev_pattern())
 
1044
                {
 
1045
                        error("No previous regular expression", NULL_PARG);
 
1046
                        return (-1);
 
1047
                }
 
1048
                if ((search_type & SRCH_NO_REGEX) != 
 
1049
                    (last_search_type & SRCH_NO_REGEX))
 
1050
                {
 
1051
                        error("Please re-enter search pattern", NULL_PARG);
 
1052
                        return -1;
 
1053
                }
 
1054
#if HILITE_SEARCH
 
1055
                if (hilite_search == OPT_ON)
 
1056
                {
 
1057
                        /*
 
1058
                         * Erase the highlights currently on screen.
 
1059
                         * If the search fails, we'll redisplay them later.
 
1060
                         */
 
1061
                        repaint_hilite(0);
 
1062
                }
 
1063
                if (hilite_search == OPT_ONPLUS && hide_hilite)
 
1064
                {
 
1065
                        /*
 
1066
                         * Highlight any matches currently on screen,
 
1067
                         * before we actually start the search.
 
1068
                         */
 
1069
                        hide_hilite = 0;
 
1070
                        hilite_screen();
 
1071
                }
 
1072
                hide_hilite = 0;
 
1073
#endif
 
1074
        } else
 
1075
        {
 
1076
                /*
 
1077
                 * Compile the pattern.
 
1078
                 */
 
1079
                ucase = is_ucase(pattern);
 
1080
                if (caseless == OPT_ONPLUS)
 
1081
                        cvt_text(pattern, pattern, CVT_TO_LC);
 
1082
                if (compile_pattern(pattern, search_type) < 0)
 
1083
                        return (-1);
 
1084
                /*
 
1085
                 * Ignore case if -I is set OR
 
1086
                 * -i is set AND the pattern is all lowercase.
 
1087
                 */
 
1088
                is_ucase_pattern = ucase;
 
1089
                if (is_ucase_pattern && caseless != OPT_ONPLUS)
 
1090
                        is_caseless = 0;
 
1091
                else
 
1092
                        is_caseless = caseless;
 
1093
#if HILITE_SEARCH
 
1094
                if (hilite_search)
 
1095
                {
 
1096
                        /*
 
1097
                         * Erase the highlights currently on screen.
 
1098
                         * Also permanently delete them from the hilite list.
 
1099
                         */
 
1100
                        repaint_hilite(0);
 
1101
                        hide_hilite = 0;
 
1102
                        clr_hilite();
 
1103
                }
 
1104
                if (hilite_search == OPT_ONPLUS)
 
1105
                {
 
1106
                        /*
 
1107
                         * Highlight any matches currently on screen,
 
1108
                         * before we actually start the search.
 
1109
                         */
 
1110
                        hilite_screen();
 
1111
                }
 
1112
#endif
 
1113
        }
 
1114
 
 
1115
        /*
 
1116
         * Figure out where to start the search.
 
1117
         */
 
1118
        pos = search_pos(search_type);
 
1119
        if (pos == NULL_POSITION)
 
1120
        {
 
1121
                /*
 
1122
                 * Can't find anyplace to start searching from.
 
1123
                 */
 
1124
                if (search_type & SRCH_PAST_EOF)
 
1125
                        return (n);
 
1126
                /* repaint(); -- why was this here? */
 
1127
                error("Nothing to search", NULL_PARG);
 
1128
                return (-1);
 
1129
        }
 
1130
 
 
1131
        n = search_range(pos, NULL_POSITION, search_type, n, -1,
 
1132
                        &pos, (POSITION*)NULL);
 
1133
        if (n != 0)
 
1134
        {
 
1135
                /*
 
1136
                 * Search was unsuccessful.
 
1137
                 */
 
1138
#if HILITE_SEARCH
 
1139
                if (hilite_search == OPT_ON && n > 0)
 
1140
                        /*
 
1141
                         * Redisplay old hilites.
 
1142
                         */
 
1143
                        repaint_hilite(1);
 
1144
#endif
 
1145
                return (n);
 
1146
        }
 
1147
 
 
1148
        if (!(search_type & SRCH_NO_MOVE))
 
1149
        {
 
1150
                /*
 
1151
                 * Go to the matching line.
 
1152
                 */
 
1153
                jump_loc(pos, jump_sline);
 
1154
        }
 
1155
 
 
1156
#if HILITE_SEARCH
 
1157
        if (hilite_search == OPT_ON)
 
1158
                /*
 
1159
                 * Display new hilites in the matching line.
 
1160
                 */
 
1161
                repaint_hilite(1);
 
1162
#endif
 
1163
        return (0);
 
1164
}
 
1165
 
 
1166
 
 
1167
#if HILITE_SEARCH
 
1168
/*
 
1169
 * Prepare hilites in a given range of the file.
 
1170
 *
 
1171
 * The pair (prep_startpos,prep_endpos) delimits a contiguous region
 
1172
 * of the file that has been "prepared"; that is, scanned for matches for
 
1173
 * the current search pattern, and hilites have been created for such matches.
 
1174
 * If prep_startpos == NULL_POSITION, the prep region is empty.
 
1175
 * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
 
1176
 * prep_hilite asks that the range (spos,epos) be covered by the prep region.
 
1177
 */
 
1178
        public void
 
1179
prep_hilite(spos, epos, maxlines)
 
1180
        POSITION spos;
 
1181
        POSITION epos;
 
1182
        int maxlines;
 
1183
{
 
1184
        POSITION nprep_startpos = prep_startpos;
 
1185
        POSITION nprep_endpos = prep_endpos;
 
1186
        POSITION new_epos;
 
1187
        POSITION max_epos;
 
1188
        int result;
 
1189
        int i;
 
1190
/*
 
1191
 * Search beyond where we're asked to search, so the prep region covers
 
1192
 * more than we need.  Do one big search instead of a bunch of small ones.
 
1193
 */
 
1194
#define SEARCH_MORE (3*size_linebuf)
 
1195
 
 
1196
        if (!prev_pattern())
 
1197
                return;
 
1198
 
 
1199
        /*
 
1200
         * If we're limited to a max number of lines, figure out the
 
1201
         * file position we should stop at.
 
1202
         */
 
1203
        if (maxlines < 0)
 
1204
                max_epos = NULL_POSITION;
 
1205
        else
 
1206
        {
 
1207
                max_epos = spos;
 
1208
                for (i = 0;  i < maxlines;  i++)
 
1209
                        max_epos = forw_raw_line(max_epos, (char **)NULL);
 
1210
        }
 
1211
 
 
1212
        /*
 
1213
         * Find two ranges:
 
1214
         * The range that we need to search (spos,epos); and the range that
 
1215
         * the "prep" region will then cover (nprep_startpos,nprep_endpos).
 
1216
         */
 
1217
 
 
1218
        if (prep_startpos == NULL_POSITION ||
 
1219
            (epos != NULL_POSITION && epos < prep_startpos) ||
 
1220
            spos > prep_endpos)
 
1221
        {
 
1222
                /*
 
1223
                 * New range is not contiguous with old prep region.
 
1224
                 * Discard the old prep region and start a new one.
 
1225
                 */
 
1226
                clr_hilite();
 
1227
                if (epos != NULL_POSITION)
 
1228
                        epos += SEARCH_MORE;
 
1229
                nprep_startpos = spos;
 
1230
        } else
 
1231
        {
 
1232
                /*
 
1233
                 * New range partially or completely overlaps old prep region.
 
1234
                 */
 
1235
                if (epos == NULL_POSITION)
 
1236
                {
 
1237
                        /*
 
1238
                         * New range goes to end of file.
 
1239
                         */
 
1240
                        ;
 
1241
                } else if (epos > prep_endpos)
 
1242
                {
 
1243
                        /*
 
1244
                         * New range ends after old prep region.
 
1245
                         * Extend prep region to end at end of new range.
 
1246
                         */
 
1247
                        epos += SEARCH_MORE;
 
1248
                } else /* (epos <= prep_endpos) */
 
1249
                {
 
1250
                        /*
 
1251
                         * New range ends within old prep region.
 
1252
                         * Truncate search to end at start of old prep region.
 
1253
                         */
 
1254
                        epos = prep_startpos;
 
1255
                }
 
1256
 
 
1257
                if (spos < prep_startpos)
 
1258
                {
 
1259
                        /*
 
1260
                         * New range starts before old prep region.
 
1261
                         * Extend old prep region backwards to start at 
 
1262
                         * start of new range.
 
1263
                         */
 
1264
                        if (spos < SEARCH_MORE)
 
1265
                                spos = 0;
 
1266
                        else
 
1267
                                spos -= SEARCH_MORE;
 
1268
                        nprep_startpos = spos;
 
1269
                } else /* (spos >= prep_startpos) */
 
1270
                {
 
1271
                        /*
 
1272
                         * New range starts within or after old prep region.
 
1273
                         * Trim search to start at end of old prep region.
 
1274
                         */
 
1275
                        spos = prep_endpos;
 
1276
                }
 
1277
        }
 
1278
 
 
1279
        if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
 
1280
            epos > max_epos)
 
1281
                /*
 
1282
                 * Don't go past the max position we're allowed.
 
1283
                 */
 
1284
                epos = max_epos;
 
1285
 
 
1286
        if (epos == NULL_POSITION || epos > spos)
 
1287
        {
 
1288
                result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
 
1289
                                maxlines, (POSITION*)NULL, &new_epos);
 
1290
                if (result < 0)
 
1291
                        return;
 
1292
                if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
 
1293
                        nprep_endpos = new_epos;
 
1294
        }
 
1295
        prep_startpos = nprep_startpos;
 
1296
        prep_endpos = nprep_endpos;
 
1297
}
 
1298
#endif
 
1299
 
 
1300
/*
 
1301
 * Simple pattern matching function.
 
1302
 * It supports no metacharacters like *, etc.
 
1303
 */
 
1304
        static int
 
1305
match(pattern, buf, pfound, pend)
 
1306
        char *pattern, *buf;
 
1307
        char **pfound, **pend;
 
1308
{
 
1309
        register char *pp, *lp;
 
1310
 
 
1311
        for ( ;  *buf != '\0';  buf++)
 
1312
        {
 
1313
                for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
 
1314
                        if (*pp == '\0' || *lp == '\0')
 
1315
                                break;
 
1316
                if (*pp == '\0')
 
1317
                {
 
1318
                        if (pfound != NULL)
 
1319
                                *pfound = buf;
 
1320
                        if (pend != NULL)
 
1321
                                *pend = lp;
 
1322
                        return (1);
 
1323
                }
 
1324
        }
 
1325
        return (0);
 
1326
}
 
1327
 
 
1328
#if HAVE_V8_REGCOMP
 
1329
/*
 
1330
 * This function is called by the V8 regcomp to report 
 
1331
 * errors in regular expressions.
 
1332
 */
 
1333
        void 
 
1334
regerror(s) 
 
1335
        char *s; 
 
1336
{
 
1337
        PARG parg;
 
1338
 
 
1339
        parg.p_string = s;
 
1340
        error("%s", &parg);
 
1341
}
 
1342
#endif
 
1343