[BACK]Return to search.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/search.c, Revision 1.1.1.3

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