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

Annotation of src/usr.bin/vim/search.c, Revision 1.1

1.1     ! downsj      1: /* $OpenBSD$   */
        !             2: /* vi:set ts=4 sw=4:
        !             3:  *
        !             4:  * VIM - Vi IMproved       by Bram Moolenaar
        !             5:  *
        !             6:  * Do ":help uganda"  in Vim to read copying and usage conditions.
        !             7:  * Do ":help credits" in Vim to see a list of people who contributed.
        !             8:  */
        !             9: /*
        !            10:  * search.c: code for normal mode searching commands
        !            11:  */
        !            12:
        !            13: #include "vim.h"
        !            14: #include "globals.h"
        !            15: #include "proto.h"
        !            16: #include "option.h"
        !            17: #include "ops.h"       /* for op_inclusive */
        !            18:
        !            19: /* modified Henry Spencer's regular expression routines */
        !            20: #include "regexp.h"
        !            21:
        !            22: static int inmacro __ARGS((char_u *, char_u *));
        !            23: static int cls __ARGS((void));
        !            24: static int skip_chars __ARGS((int, int));
        !            25: static void back_in_line __ARGS((void));
        !            26: static void find_first_blank __ARGS((FPOS *));
        !            27: static void show_pat_in_path __ARGS((char_u *, int,
        !            28:                                         int, int, FILE *, linenr_t *, long));
        !            29: static void give_warning __ARGS((char_u *));
        !            30:
        !            31: static char_u *top_bot_msg = (char_u *)"search hit TOP, continuing at BOTTOM";
        !            32: static char_u *bot_top_msg = (char_u *)"search hit BOTTOM, continuing at TOP";
        !            33:
        !            34: /*
        !            35:  * This file contains various searching-related routines. These fall into
        !            36:  * three groups:
        !            37:  * 1. string searches (for /, ?, n, and N)
        !            38:  * 2. character searches within a single line (for f, F, t, T, etc)
        !            39:  * 3. "other" kinds of searches like the '%' command, and 'word' searches.
        !            40:  */
        !            41:
        !            42: /*
        !            43:  * String searches
        !            44:  *
        !            45:  * The string search functions are divided into two levels:
        !            46:  * lowest: searchit(); called by do_search() and edit().
        !            47:  * Highest: do_search(); changes curwin->w_cursor, called by normal().
        !            48:  *
        !            49:  * The last search pattern is remembered for repeating the same search.
        !            50:  * This pattern is shared between the :g, :s, ? and / commands.
        !            51:  * This is in myregcomp().
        !            52:  *
        !            53:  * The actual string matching is done using a heavily modified version of
        !            54:  * Henry Spencer's regular expression library.
        !            55:  */
        !            56:
        !            57: /*
        !            58:  * Two search patterns are remembered: One for the :substitute command and
        !            59:  * one for other searches. last_pattern points to the one that was
        !            60:  * used the last time.
        !            61:  */
        !            62: static char_u  *search_pattern = NULL;
        !            63: static int     search_magic = TRUE;
        !            64: static int     search_no_scs = FALSE;
        !            65: static char_u  *subst_pattern = NULL;
        !            66: static int     subst_magic = TRUE;
        !            67: static int     subst_no_scs = FALSE;
        !            68: static char_u  *last_pattern = NULL;
        !            69: static int     last_magic = TRUE;
        !            70: static int     last_no_scs = FALSE;
        !            71: static char_u  *mr_pattern = NULL;     /* pattern used by myregcomp() */
        !            72:
        !            73: static int     want_start;             /* looking for start of line? */
        !            74:
        !            75: /*
        !            76:  * Type used by find_pattern_in_path() to remember which included files have
        !            77:  * been searched already.
        !            78:  */
        !            79: typedef struct SearchedFile
        !            80: {
        !            81:    FILE        *fp;        /* File pointer */
        !            82:    char_u      *name;      /* Full name of file */
        !            83:    linenr_t    lnum;       /* Line we were up to in file */
        !            84:    int         matched;    /* Found a match in this file */
        !            85: } SearchedFile;
        !            86:
        !            87: /*
        !            88:  * translate search pattern for vim_regcomp()
        !            89:  *
        !            90:  * sub_cmd == RE_SEARCH: save pat in search_pattern (normal search command)
        !            91:  * sub_cmd == RE_SUBST: save pat in subst_pattern (:substitute command)
        !            92:  * sub_cmd == RE_BOTH: save pat in both patterns (:global command)
        !            93:  * which_pat == RE_SEARCH: use previous search pattern if "pat" is NULL
        !            94:  * which_pat == RE_SUBST: use previous sustitute pattern if "pat" is NULL
        !            95:  * which_pat == RE_LAST: use last used pattern if "pat" is NULL
        !            96:  * options & SEARCH_HIS: put search string in history
        !            97:  * options & SEARCH_KEEP: keep previous search pattern
        !            98:  *
        !            99:  */
        !           100:    regexp *
        !           101: myregcomp(pat, sub_cmd, which_pat, options)
        !           102:    char_u  *pat;
        !           103:    int     sub_cmd;
        !           104:    int     which_pat;
        !           105:    int     options;
        !           106: {
        !           107:    rc_did_emsg = FALSE;
        !           108:    reg_magic = p_magic;
        !           109:    if (pat == NULL || *pat == NUL)     /* use previous search pattern */
        !           110:    {
        !           111:        if (which_pat == RE_SEARCH)
        !           112:        {
        !           113:            if (search_pattern == NULL)
        !           114:            {
        !           115:                emsg(e_noprevre);
        !           116:                rc_did_emsg = TRUE;
        !           117:                return (regexp *) NULL;
        !           118:            }
        !           119:            pat = search_pattern;
        !           120:            reg_magic = search_magic;
        !           121:            no_smartcase = search_no_scs;
        !           122:        }
        !           123:        else if (which_pat == RE_SUBST)
        !           124:        {
        !           125:            if (subst_pattern == NULL)
        !           126:            {
        !           127:                emsg(e_nopresub);
        !           128:                rc_did_emsg = TRUE;
        !           129:                return (regexp *) NULL;
        !           130:            }
        !           131:            pat = subst_pattern;
        !           132:            reg_magic = subst_magic;
        !           133:            no_smartcase = subst_no_scs;
        !           134:        }
        !           135:        else    /* which_pat == RE_LAST */
        !           136:        {
        !           137:            if (last_pattern == NULL)
        !           138:            {
        !           139:                emsg(e_noprevre);
        !           140:                rc_did_emsg = TRUE;
        !           141:                return (regexp *) NULL;
        !           142:            }
        !           143:            pat = last_pattern;
        !           144:            reg_magic = last_magic;
        !           145:            no_smartcase = last_no_scs;
        !           146:        }
        !           147:    }
        !           148:    else if (options & SEARCH_HIS)
        !           149:        add_to_history(1, pat);         /* put new pattern in history */
        !           150:
        !           151:    mr_pattern = pat;
        !           152:
        !           153:    /*
        !           154:     * save the currently used pattern in the appropriate place,
        !           155:     * unless the pattern should not be remembered
        !           156:     */
        !           157:    if (!(options & SEARCH_KEEP))
        !           158:    {
        !           159:        /*
        !           160:         * search or global command
        !           161:         */
        !           162:        if (sub_cmd == RE_SEARCH || sub_cmd == RE_BOTH)
        !           163:        {
        !           164:            if (search_pattern != pat)
        !           165:            {
        !           166:                vim_free(search_pattern);
        !           167:                search_pattern = strsave(pat);
        !           168:                last_pattern = search_pattern;
        !           169:                search_magic = reg_magic;
        !           170:                last_magic = reg_magic;     /* Magic sticks with the r.e. */
        !           171:                search_no_scs = no_smartcase;
        !           172:                last_no_scs = no_smartcase;
        !           173:            }
        !           174:        }
        !           175:        /*
        !           176:         * substitute or global command
        !           177:         */
        !           178:        if (sub_cmd == RE_SUBST || sub_cmd == RE_BOTH)
        !           179:        {
        !           180:            if (subst_pattern != pat)
        !           181:            {
        !           182:                vim_free(subst_pattern);
        !           183:                subst_pattern = strsave(pat);
        !           184:                last_pattern = subst_pattern;
        !           185:                subst_magic = reg_magic;
        !           186:                last_magic = reg_magic;     /* Magic sticks with the r.e. */
        !           187:                subst_no_scs = no_smartcase;
        !           188:                last_no_scs = no_smartcase;
        !           189:            }
        !           190:        }
        !           191:    }
        !           192:
        !           193:    want_start = (*pat == '^'); /* looking for start of line? */
        !           194:    set_reg_ic(pat);            /* tell the vim_regexec routine how to search */
        !           195:    return vim_regcomp(pat);
        !           196: }
        !           197:
        !           198: /*
        !           199:  * Set reg_ic according to p_ic, p_scs and the search pattern.
        !           200:  */
        !           201:    void
        !           202: set_reg_ic(pat)
        !           203:    char_u  *pat;
        !           204: {
        !           205:    char_u *p;
        !           206:
        !           207:    reg_ic = p_ic;
        !           208:    if (!no_smartcase && p_scs
        !           209: #ifdef INSERT_EXPAND
        !           210:                                && !(ctrl_x_mode && curbuf->b_p_inf)
        !           211: #endif
        !           212:                                                                    )
        !           213:    {
        !           214:        /* don't ignore case if pattern has uppercase */
        !           215:        for (p = pat; *p; )
        !           216:            if (isupper(*p++))
        !           217:                reg_ic = FALSE;
        !           218:    }
        !           219:    no_smartcase = FALSE;
        !           220: }
        !           221:
        !           222: /*
        !           223:  * lowest level search function.
        !           224:  * Search for 'count'th occurrence of 'str' in direction 'dir'.
        !           225:  * Start at position 'pos' and return the found position in 'pos'.
        !           226:  *
        !           227:  * if (options & SEARCH_MSG) == 0 don't give any messages
        !           228:  * if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages
        !           229:  * if (options & SEARCH_MSG) == SEARCH_MSG give all messages
        !           230:  * if (options & SEARCH_HIS) put search pattern in history
        !           231:  * if (options & SEARCH_END) return position at end of match
        !           232:  * if (options & SEARCH_START) accept match at pos itself
        !           233:  * if (options & SEARCH_KEEP) keep previous search pattern
        !           234:  *
        !           235:  * Return OK for success, FAIL for failure.
        !           236:  */
        !           237:    int
        !           238: searchit(pos, dir, str, count, options, which_pat)
        !           239:    FPOS    *pos;
        !           240:    int     dir;
        !           241:    char_u  *str;
        !           242:    long    count;
        !           243:    int     options;
        !           244:    int     which_pat;
        !           245: {
        !           246:    int                 found;
        !           247:    linenr_t            lnum;           /* no init to shut up Apollo cc */
        !           248:    regexp              *prog;
        !           249:    char_u              *ptr;
        !           250:    register char_u     *match = NULL, *matchend = NULL;    /* init for GCC */
        !           251:    int                 loop;
        !           252:    FPOS                start_pos;
        !           253:    int                 at_first_line;
        !           254:    int                 extra_col;
        !           255:    int                 match_ok;
        !           256:    char_u              *p;
        !           257:
        !           258:    if ((prog = myregcomp(str, RE_SEARCH, which_pat,
        !           259:                             (options & (SEARCH_HIS + SEARCH_KEEP)))) == NULL)
        !           260:    {
        !           261:        if ((options & SEARCH_MSG) && !rc_did_emsg)
        !           262:            emsg2((char_u *)"Invalid search string: %s", mr_pattern);
        !           263:        return FAIL;
        !           264:    }
        !           265:
        !           266:    if (options & SEARCH_START)
        !           267:        extra_col = 0;
        !           268:    else
        !           269:        extra_col = 1;
        !           270:
        !           271:
        !           272: /*
        !           273:  * find the string
        !           274:  */
        !           275:    do                          /* loop for count */
        !           276:    {
        !           277:        start_pos = *pos;       /* remember start pos for detecting no match */
        !           278:        found = 0;              /* default: not found */
        !           279:
        !           280:        /*
        !           281:         * Start searching in current line, unless searching backwards and
        !           282:         * we're in column 0 or searching forward and we're past the end of
        !           283:         * the line
        !           284:         */
        !           285:        if (dir == BACKWARD && start_pos.col == 0)
        !           286:        {
        !           287:            lnum = pos->lnum - 1;
        !           288:            at_first_line = FALSE;
        !           289:        }
        !           290:        else
        !           291:        {
        !           292:            lnum = pos->lnum;
        !           293:            at_first_line = TRUE;
        !           294:        }
        !           295:
        !           296:        for (loop = 0; loop <= 1; ++loop)   /* loop twice if 'wrapscan' set */
        !           297:        {
        !           298:            for ( ; lnum > 0 && lnum <= curbuf->b_ml.ml_line_count;
        !           299:                                           lnum += dir, at_first_line = FALSE)
        !           300:            {
        !           301:                ptr = ml_get(lnum);
        !           302:                                            /* forward search, first line */
        !           303:                if (dir == FORWARD && at_first_line && start_pos.col > 0 &&
        !           304:                                                                   want_start)
        !           305:                    continue;               /* match not possible */
        !           306:
        !           307:                /*
        !           308:                 * Look for a match somewhere in the line.
        !           309:                 */
        !           310:                if (vim_regexec(prog, ptr, TRUE))
        !           311:                {
        !           312:                    match = prog->startp[0];
        !           313:                    matchend = prog->endp[0];
        !           314:
        !           315:                    /*
        !           316:                     * Forward search in the first line: match should be after
        !           317:                     * the start position. If not, continue at the end of the
        !           318:                     * match (this is vi compatible).
        !           319:                     */
        !           320:                    if (dir == FORWARD && at_first_line)
        !           321:                    {
        !           322:                        match_ok = TRUE;
        !           323:                        /*
        !           324:                         * When *match == NUL the cursor will be put one back
        !           325:                         * afterwards, compare with that position, otherwise
        !           326:                         * "/$" will get stuck on end of line.  Same for
        !           327:                         * matchend.
        !           328:                         */
        !           329:                        while ((options & SEARCH_END) ?
        !           330:                        ((int)(matchend - ptr) - 1 - (int)(*matchend == NUL) <
        !           331:                                             (int)start_pos.col + extra_col) :
        !           332:                                  ((int)(match - ptr) - (int)(*match == NUL) <
        !           333:                                              (int)start_pos.col + extra_col))
        !           334:                        {
        !           335:                            /*
        !           336:                             * If vi-compatible searching, continue at the end
        !           337:                             * of the match, otherwise continue one position
        !           338:                             * forward.
        !           339:                             */
        !           340:                            if (vim_strchr(p_cpo, CPO_SEARCH) != NULL)
        !           341:                            {
        !           342:                                p = matchend;
        !           343:                                if (match == p && *p != NUL)
        !           344:                                    ++p;
        !           345:                            }
        !           346:                            else
        !           347:                            {
        !           348:                                p = match;
        !           349:                                if (*p != NUL)
        !           350:                                    ++p;
        !           351:                            }
        !           352:                            if (*p != NUL && vim_regexec(prog, p, FALSE))
        !           353:                            {
        !           354:                                match = prog->startp[0];
        !           355:                                matchend = prog->endp[0];
        !           356:                            }
        !           357:                            else
        !           358:                            {
        !           359:                                match_ok = FALSE;
        !           360:                                break;
        !           361:                            }
        !           362:                        }
        !           363:                        if (!match_ok)
        !           364:                            continue;
        !           365:                    }
        !           366:                    if (dir == BACKWARD && !want_start)
        !           367:                    {
        !           368:                        /*
        !           369:                         * Now, if there are multiple matches on this line,
        !           370:                         * we have to get the last one. Or the last one before
        !           371:                         * the cursor, if we're on that line.
        !           372:                         * When putting the new cursor at the end, compare
        !           373:                         * relative to the end of the match.
        !           374:                         */
        !           375:                        match_ok = FALSE;
        !           376:                        for (;;)
        !           377:                        {
        !           378:                            if (!at_first_line || ((options & SEARCH_END) ?
        !           379:                                        ((prog->endp[0] - ptr) - 1 + extra_col
        !           380:                                                      <= (int)start_pos.col) :
        !           381:                                          ((prog->startp[0] - ptr) + extra_col
        !           382:                                                      <= (int)start_pos.col)))
        !           383:                            {
        !           384:                                match_ok = TRUE;
        !           385:                                match = prog->startp[0];
        !           386:                                matchend = prog->endp[0];
        !           387:                            }
        !           388:                            else
        !           389:                                break;
        !           390:                            /*
        !           391:                             * If vi-compatible searching, continue at the end
        !           392:                             * of the match, otherwise continue one position
        !           393:                             * forward.
        !           394:                             */
        !           395:                            if (vim_strchr(p_cpo, CPO_SEARCH) != NULL)
        !           396:                            {
        !           397:                                p = matchend;
        !           398:                                if (p == match && *p != NUL)
        !           399:                                    ++p;
        !           400:                            }
        !           401:                            else
        !           402:                            {
        !           403:                                p = match;
        !           404:                                if (*p != NUL)
        !           405:                                    ++p;
        !           406:                            }
        !           407:                            if (*p == NUL || !vim_regexec(prog, p, (int)FALSE))
        !           408:                                break;
        !           409:                        }
        !           410:
        !           411:                        /*
        !           412:                         * If there is only a match after the cursor, skip
        !           413:                         * this match.
        !           414:                         */
        !           415:                        if (!match_ok)
        !           416:                            continue;
        !           417:                    }
        !           418:
        !           419:                    pos->lnum = lnum;
        !           420:                    if (options & SEARCH_END && !(options & SEARCH_NOOF))
        !           421:                        pos->col = (int) (matchend - ptr - 1);
        !           422:                    else
        !           423:                        pos->col = (int) (match - ptr);
        !           424:                    found = 1;
        !           425:                    break;
        !           426:                }
        !           427:                line_breakcheck();      /* stop if ctrl-C typed */
        !           428:                if (got_int)
        !           429:                    break;
        !           430:
        !           431:                if (loop && lnum == start_pos.lnum)
        !           432:                    break;          /* if second loop, stop where started */
        !           433:            }
        !           434:            at_first_line = FALSE;
        !           435:
        !           436:            /*
        !           437:             * stop the search if wrapscan isn't set, after an interrupt and
        !           438:             * after a match
        !           439:             */
        !           440:            if (!p_ws || got_int || found)
        !           441:                break;
        !           442:
        !           443:            /*
        !           444:             * If 'wrapscan' is set we continue at the other end of the file.
        !           445:             * If 'shortmess' does not contain 's', we give a message.
        !           446:             * This message is also remembered in keep_msg for when the screen
        !           447:             * is redrawn. The keep_msg is cleared whenever another message is
        !           448:             * written.
        !           449:             */
        !           450:            if (dir == BACKWARD)    /* start second loop at the other end */
        !           451:            {
        !           452:                lnum = curbuf->b_ml.ml_line_count;
        !           453:                if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
        !           454:                    give_warning(top_bot_msg);
        !           455:            }
        !           456:            else
        !           457:            {
        !           458:                lnum = 1;
        !           459:                if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
        !           460:                    give_warning(bot_top_msg);
        !           461:            }
        !           462:        }
        !           463:        if (got_int)
        !           464:            break;
        !           465:    }
        !           466:    while (--count > 0 && found);   /* stop after count matches or no match */
        !           467:
        !           468:    vim_free(prog);
        !           469:
        !           470:    if (!found)             /* did not find it */
        !           471:    {
        !           472:        if (got_int)
        !           473:            emsg(e_interr);
        !           474:        else if ((options & SEARCH_MSG) == SEARCH_MSG)
        !           475:        {
        !           476:            if (p_ws)
        !           477:                EMSG2("Pattern not found: %s", mr_pattern);
        !           478:            else if (lnum == 0)
        !           479:                EMSG2("search hit TOP without match for: %s", mr_pattern);
        !           480:            else
        !           481:                EMSG2("search hit BOTTOM without match for: %s", mr_pattern);
        !           482:        }
        !           483:        return FAIL;
        !           484:    }
        !           485:    search_match_len = matchend - match;
        !           486:
        !           487:    return OK;
        !           488: }
        !           489:
        !           490: /*
        !           491:  * Highest level string search function.
        !           492:  * Search for the 'count'th occurence of string 'str' in direction 'dirc'
        !           493:  *               If 'dirc' is 0: use previous dir.
        !           494:  *    If 'str' is NULL or empty : use previous string.
        !           495:  *   If 'options & SEARCH_REV' : go in reverse of previous dir.
        !           496:  *   If 'options & SEARCH_ECHO': echo the search command and handle options
        !           497:  *   If 'options & SEARCH_MSG' : may give error message
        !           498:  *   If 'options & SEARCH_OPT' : interpret optional flags
        !           499:  *   If 'options & SEARCH_HIS' : put search pattern in history
        !           500:  *   If 'options & SEARCH_NOOF': don't add offset to position
        !           501:  *   If 'options & SEARCH_MARK': set previous context mark
        !           502:  *   If 'options & SEARCH_KEEP': keep previous search pattern
        !           503:  *
        !           504:  * Careful: If lastoffline == TRUE and lastoff == 0 this makes the
        !           505:  * movement linewise without moving the match position.
        !           506:  *
        !           507:  * return 0 for failure, 1 for found, 2 for found and line offset added
        !           508:  */
        !           509:    int
        !           510: do_search(dirc, str, count, options)
        !           511:    int             dirc;
        !           512:    char_u         *str;
        !           513:    long            count;
        !           514:    int             options;
        !           515: {
        !           516:    FPOS            pos;        /* position of the last match */
        !           517:    char_u          *searchstr;
        !           518:    static int      lastsdir = '/'; /* previous search direction */
        !           519:    static int      lastoffline;/* previous/current search has line offset */
        !           520:    static int      lastend;    /* previous/current search set cursor at end */
        !           521:    static long     lastoff;    /* previous/current line or char offset */
        !           522:    int             old_lastsdir;
        !           523:    int             old_lastoffline;
        !           524:    int             old_lastend;
        !           525:    long            old_lastoff;
        !           526:    int             retval;     /* Return value */
        !           527:    register char_u *p;
        !           528:    register long   c;
        !           529:    char_u          *dircp;
        !           530:    int             i = 0;      /* init for GCC */
        !           531:
        !           532:    /*
        !           533:     * A line offset is not remembered, this is vi compatible.
        !           534:     */
        !           535:    if (lastoffline && vim_strchr(p_cpo, CPO_LINEOFF) != NULL)
        !           536:    {
        !           537:        lastoffline = FALSE;
        !           538:        lastoff = 0;
        !           539:    }
        !           540:
        !           541:    /*
        !           542:     * Save the values for when (options & SEARCH_KEEP) is used.
        !           543:     * (there is no "if ()" around this because gcc wants them initialized)
        !           544:     */
        !           545:    old_lastsdir = lastsdir;
        !           546:    old_lastoffline = lastoffline;
        !           547:    old_lastend = lastend;
        !           548:    old_lastoff = lastoff;
        !           549:
        !           550:    pos = curwin->w_cursor;     /* start searching at the cursor position */
        !           551:
        !           552:    /*
        !           553:     * Find out the direction of the search.
        !           554:     */
        !           555:    if (dirc == 0)
        !           556:        dirc = lastsdir;
        !           557:    else
        !           558:        lastsdir = dirc;
        !           559:    if (options & SEARCH_REV)
        !           560:    {
        !           561: #ifdef WIN32
        !           562:        /* There is a bug in the Visual C++ 2.2 compiler which means that
        !           563:         * dirc always ends up being '/' */
        !           564:        dirc = (dirc == '/')  ?  '?'  :  '/';
        !           565: #else
        !           566:        if (dirc == '/')
        !           567:            dirc = '?';
        !           568:        else
        !           569:            dirc = '/';
        !           570: #endif
        !           571:    }
        !           572:
        !           573:    /*
        !           574:     * Repeat the search when pattern followed by ';', e.g. "/foo/;?bar".
        !           575:     */
        !           576:    for (;;)
        !           577:    {
        !           578:        searchstr = str;
        !           579:        dircp = NULL;
        !           580:                                            /* use previous pattern */
        !           581:        if (str == NULL || *str == NUL || *str == dirc)
        !           582:        {
        !           583:            if (search_pattern == NULL)     /* no previous pattern */
        !           584:            {
        !           585:                emsg(e_noprevre);
        !           586:                retval = 0;
        !           587:                goto end_do_search;
        !           588:            }
        !           589:            searchstr = (char_u *)"";  /* make myregcomp() use search_pattern */
        !           590:        }
        !           591:
        !           592:        if (str != NULL && *str != NUL) /* look for (new) offset */
        !           593:        {
        !           594:            /*
        !           595:             * Find end of regular expression.
        !           596:             * If there is a matching '/' or '?', toss it.
        !           597:             */
        !           598:            p = skip_regexp(str, dirc);
        !           599:            if (*p == dirc)
        !           600:            {
        !           601:                dircp = p;      /* remember where we put the NUL */
        !           602:                *p++ = NUL;
        !           603:            }
        !           604:            lastoffline = FALSE;
        !           605:            lastend = FALSE;
        !           606:            lastoff = 0;
        !           607:            /*
        !           608:             * Check for a line offset or a character offset.
        !           609:             * For get_address (echo off) we don't check for a character
        !           610:             * offset, because it is meaningless and the 's' could be a
        !           611:             * substitute command.
        !           612:             */
        !           613:            if (*p == '+' || *p == '-' || isdigit(*p))
        !           614:                lastoffline = TRUE;
        !           615:            else if ((options & SEARCH_OPT) &&
        !           616:                                        (*p == 'e' || *p == 's' || *p == 'b'))
        !           617:            {
        !           618:                if (*p == 'e')          /* end */
        !           619:                    lastend = SEARCH_END;
        !           620:                ++p;
        !           621:            }
        !           622:            if (isdigit(*p) || *p == '+' || *p == '-')     /* got an offset */
        !           623:            {
        !           624:                if (isdigit(*p) || isdigit(*(p + 1)))
        !           625:                    lastoff = atol((char *)p);      /* 'nr' or '+nr' or '-nr' */
        !           626:                else if (*p == '-')         /* single '-' */
        !           627:                    lastoff = -1;
        !           628:                else                        /* single '+' */
        !           629:                    lastoff = 1;
        !           630:                ++p;
        !           631:                while (isdigit(*p))         /* skip number */
        !           632:                    ++p;
        !           633:            }
        !           634:            searchcmdlen = p - str;         /* compute length of search command
        !           635:                                                            for get_address() */
        !           636:            str = p;                        /* put str after search command */
        !           637:        }
        !           638:
        !           639:        if (options & SEARCH_ECHO)
        !           640:        {
        !           641:            msg_start();
        !           642:            msg_outchar(dirc);
        !           643:            msg_outtrans(*searchstr == NUL ? search_pattern : searchstr);
        !           644:            if (lastoffline || lastend || lastoff)
        !           645:            {
        !           646:                msg_outchar(dirc);
        !           647:                if (lastend)
        !           648:                    msg_outchar('e');
        !           649:                else if (!lastoffline)
        !           650:                    msg_outchar('s');
        !           651:                if (lastoff < 0)
        !           652:                {
        !           653:                    msg_outchar('-');
        !           654:                    msg_outnum((long)-lastoff);
        !           655:                }
        !           656:                else if (lastoff > 0 || lastoffline)
        !           657:                {
        !           658:                    msg_outchar('+');
        !           659:                    msg_outnum((long)lastoff);
        !           660:                }
        !           661:            }
        !           662:            msg_clr_eos();
        !           663:            (void)msg_check();
        !           664:
        !           665:            gotocmdline(FALSE);
        !           666:            flushbuf();
        !           667:        }
        !           668:
        !           669:        /*
        !           670:         * If there is a character offset, subtract it from the current
        !           671:         * position, so we don't get stuck at "?pat?e+2" or "/pat/s-2".
        !           672:         * This is not done for a line offset, because then we would not be vi
        !           673:         * compatible.
        !           674:         */
        !           675:        if (!lastoffline && lastoff)
        !           676:        {
        !           677:            if (lastoff > 0)
        !           678:            {
        !           679:                c = lastoff;
        !           680:                while (c--)
        !           681:                    if ((i = dec(&pos)) != 0)
        !           682:                        break;
        !           683:                if (i == -1)                /* at start of buffer */
        !           684:                    goto_endofbuf(&pos);
        !           685:            }
        !           686:            else
        !           687:            {
        !           688:                c = -lastoff;
        !           689:                while (c--)
        !           690:                    if ((i = inc(&pos)) != 0)
        !           691:                        break;
        !           692:                if (i == -1)                /* at end of buffer */
        !           693:                {
        !           694:                    pos.lnum = 1;
        !           695:                    pos.col = 0;
        !           696:                }
        !           697:            }
        !           698:        }
        !           699:
        !           700:        c = searchit(&pos, dirc == '/' ? FORWARD : BACKWARD, searchstr, count,
        !           701:                lastend + (options &
        !           702:                       (SEARCH_KEEP + SEARCH_HIS + SEARCH_MSG +
        !           703:                           ((str != NULL && *str == ';') ? 0 : SEARCH_NOOF))),
        !           704:                2);
        !           705:        if (dircp != NULL)
        !           706:            *dircp = dirc;      /* put second '/' or '?' back for normal() */
        !           707:        if (c == FAIL)
        !           708:        {
        !           709:            retval = 0;
        !           710:            goto end_do_search;
        !           711:        }
        !           712:        if (lastend)
        !           713:            op_inclusive = TRUE;    /* 'e' includes last character */
        !           714:
        !           715:        retval = 1;                 /* pattern found */
        !           716:
        !           717:        /*
        !           718:         * Add character and/or line offset
        !           719:         */
        !           720:        if (!(options & SEARCH_NOOF) || *str == ';')
        !           721:        {
        !           722:            if (lastoffline)            /* Add the offset to the line number. */
        !           723:            {
        !           724:                c = pos.lnum + lastoff;
        !           725:                if (c < 1)
        !           726:                    pos.lnum = 1;
        !           727:                else if (c > curbuf->b_ml.ml_line_count)
        !           728:                    pos.lnum = curbuf->b_ml.ml_line_count;
        !           729:                else
        !           730:                    pos.lnum = c;
        !           731:                pos.col = 0;
        !           732:
        !           733:                retval = 2;             /* pattern found, line offset added */
        !           734:            }
        !           735:            else
        !           736:            {
        !           737:                if (lastoff > 0)    /* to the right, check for end of line */
        !           738:                {
        !           739:                    p = ml_get_pos(&pos) + 1;
        !           740:                    c = lastoff;
        !           741:                    while (c-- && *p++ != NUL)
        !           742:                        ++pos.col;
        !           743:                }
        !           744:                else                /* to the left, check for start of line */
        !           745:                {
        !           746:                    if ((c = pos.col + lastoff) < 0)
        !           747:                        c = 0;
        !           748:                    pos.col = c;
        !           749:                }
        !           750:            }
        !           751:        }
        !           752:
        !           753:        /*
        !           754:         * The search command can be followed by a ';' to do another search.
        !           755:         * For example: "/pat/;/foo/+3;?bar"
        !           756:         * This is like doing another search command, except:
        !           757:         * - The remembered direction '/' or '?' is from the first search.
        !           758:         * - When an error happens the cursor isn't moved at all.
        !           759:         * Don't do this when called by get_address() (it handles ';' itself).
        !           760:         */
        !           761:        if (!(options & SEARCH_OPT) || str == NULL || *str != ';')
        !           762:            break;
        !           763:
        !           764:        dirc = *++str;
        !           765:        if (dirc != '?' && dirc != '/')
        !           766:        {
        !           767:            retval = 0;
        !           768:            EMSG("Expected '?' or '/'  after ';'");
        !           769:            goto end_do_search;
        !           770:        }
        !           771:        ++str;
        !           772:    }
        !           773:
        !           774:    if (options & SEARCH_MARK)
        !           775:        setpcmark();
        !           776:    curwin->w_cursor = pos;
        !           777:    curwin->w_set_curswant = TRUE;
        !           778:
        !           779: end_do_search:
        !           780:    if (options & SEARCH_KEEP)
        !           781:    {
        !           782:        lastsdir = old_lastsdir;
        !           783:        lastoffline = old_lastoffline;
        !           784:        lastend = old_lastend;
        !           785:        lastoff = old_lastoff;
        !           786:    }
        !           787:    return retval;
        !           788: }
        !           789:
        !           790: /*
        !           791:  * search_for_exact_line(pos, dir, pat)
        !           792:  *
        !           793:  * Search for a line starting with the given pattern (ignoring leading
        !           794:  * white-space), starting from pos and going in direction dir. pos will
        !           795:  * contain the position of the match found.    Blank lines will never match.
        !           796:  * Return OK for success, or FAIL if no line found.
        !           797:  */
        !           798:    int
        !           799: search_for_exact_line(pos, dir, pat)
        !           800:    FPOS        *pos;
        !           801:    int         dir;
        !           802:    char_u      *pat;
        !           803: {
        !           804:    linenr_t    start = 0;
        !           805:    char_u      *ptr;
        !           806:    char_u      *p;
        !           807:
        !           808:    if (curbuf->b_ml.ml_line_count == 0)
        !           809:        return FAIL;
        !           810:    for (;;)
        !           811:    {
        !           812:        pos->lnum += dir;
        !           813:        if (pos->lnum < 1)
        !           814:        {
        !           815:            if (p_ws)
        !           816:            {
        !           817:                pos->lnum = curbuf->b_ml.ml_line_count;
        !           818:                if (!shortmess(SHM_SEARCH))
        !           819:                    give_warning(top_bot_msg);
        !           820:            }
        !           821:            else
        !           822:            {
        !           823:                pos->lnum = 1;
        !           824:                break;
        !           825:            }
        !           826:        }
        !           827:        else if (pos->lnum > curbuf->b_ml.ml_line_count)
        !           828:        {
        !           829:            if (p_ws)
        !           830:            {
        !           831:                pos->lnum = 1;
        !           832:                if (!shortmess(SHM_SEARCH))
        !           833:                    give_warning(bot_top_msg);
        !           834:            }
        !           835:            else
        !           836:            {
        !           837:                pos->lnum = 1;
        !           838:                break;
        !           839:            }
        !           840:        }
        !           841:        if (pos->lnum == start)
        !           842:            break;
        !           843:        if (start == 0)
        !           844:            start = pos->lnum;
        !           845:        ptr = ml_get(pos->lnum);
        !           846:        p = skipwhite(ptr);
        !           847:        pos->col = p - ptr;
        !           848:        if (*p != NUL && STRNCMP(p, pat, STRLEN(pat)) == 0)
        !           849:            return OK;
        !           850:        else if (*p != NUL && p_ic)
        !           851:        {
        !           852:            ptr = pat;
        !           853:            while (*p && TO_LOWER(*p) == TO_LOWER(*ptr))
        !           854:            {
        !           855:                ++p;
        !           856:                ++ptr;
        !           857:            }
        !           858:            if (*ptr == NUL)
        !           859:                return OK;
        !           860:        }
        !           861:    }
        !           862:    return FAIL;
        !           863: }
        !           864:
        !           865: /*
        !           866:  * Character Searches
        !           867:  */
        !           868:
        !           869: /*
        !           870:  * searchc(c, dir, type, count)
        !           871:  *
        !           872:  * Search for character 'c', in direction 'dir'. If 'type' is 0, move to the
        !           873:  * position of the character, otherwise move to just before the char.
        !           874:  * Repeat this 'count' times.
        !           875:  */
        !           876:    int
        !           877: searchc(c, dir, type, count)
        !           878:    int             c;
        !           879:    register int    dir;
        !           880:    int             type;
        !           881:    long            count;
        !           882: {
        !           883:    static int      lastc = NUL;    /* last character searched for */
        !           884:    static int      lastcdir;       /* last direction of character search */
        !           885:    static int      lastctype;      /* last type of search ("find" or "to") */
        !           886:    register int    col;
        !           887:    char_u          *p;
        !           888:    int             len;
        !           889:
        !           890:    if (c != NUL)       /* normal search: remember args for repeat */
        !           891:    {
        !           892:        if (!KeyStuffed)    /* don't remember when redoing */
        !           893:        {
        !           894:            lastc = c;
        !           895:            lastcdir = dir;
        !           896:            lastctype = type;
        !           897:        }
        !           898:    }
        !           899:    else                /* repeat previous search */
        !           900:    {
        !           901:        if (lastc == NUL)
        !           902:            return FALSE;
        !           903:        if (dir)        /* repeat in opposite direction */
        !           904:            dir = -lastcdir;
        !           905:        else
        !           906:            dir = lastcdir;
        !           907:        type = lastctype;
        !           908:        c = lastc;
        !           909:    }
        !           910:
        !           911:    p = ml_get_curline();
        !           912:    col = curwin->w_cursor.col;
        !           913:    len = STRLEN(p);
        !           914:
        !           915:    while (count--)
        !           916:    {
        !           917:        for (;;)
        !           918:        {
        !           919:            if ((col += dir) < 0 || col >= len)
        !           920:                return FALSE;
        !           921:            if (p[col] == c)
        !           922:                break;
        !           923:        }
        !           924:    }
        !           925:    if (type)
        !           926:        col -= dir;
        !           927:    curwin->w_cursor.col = col;
        !           928:    return TRUE;
        !           929: }
        !           930:
        !           931: /*
        !           932:  * "Other" Searches
        !           933:  */
        !           934:
        !           935: /*
        !           936:  * findmatch - find the matching paren or brace
        !           937:  *
        !           938:  * Improvement over vi: Braces inside quotes are ignored.
        !           939:  */
        !           940:    FPOS *
        !           941: findmatch(initc)
        !           942:    int     initc;
        !           943: {
        !           944:    return findmatchlimit(initc, 0, 0);
        !           945: }
        !           946:
        !           947: /*
        !           948:  * findmatchlimit -- find the matching paren or brace, if it exists within
        !           949:  * maxtravel lines of here.  A maxtravel of 0 means search until you fall off
        !           950:  * the edge of the file.
        !           951:  *
        !           952:  * flags: FM_BACKWARD  search backwards (when initc is '/', '*' or '#')
        !           953:  *           FM_FORWARD    search forwards (when initc is '/', '*' or '#')
        !           954:  *       FM_BLOCKSTOP  stop at start/end of block ({ or } in column 0)
        !           955:  *       FM_SKIPCOMM   skip comments (not implemented yet!)
        !           956:  */
        !           957:
        !           958:    FPOS *
        !           959: findmatchlimit(initc, flags, maxtravel)
        !           960:    int     initc;
        !           961:    int     flags;
        !           962:    int     maxtravel;
        !           963: {
        !           964:    static FPOS     pos;                /* current search position */
        !           965:    int             findc;              /* matching brace */
        !           966:    int             c;
        !           967:    int             count = 0;          /* cumulative number of braces */
        !           968:    int             idx = 0;            /* init for gcc */
        !           969:    static char_u   table[6] = {'(', ')', '[', ']', '{', '}'};
        !           970: #ifdef RIGHTLEFT
        !           971:    static char_u   table_rl[6] = {')', '(', ']', '[', '}', '{'};
        !           972: #endif
        !           973:    int             inquote = FALSE;    /* TRUE when inside quotes */
        !           974:    register char_u *linep;             /* pointer to current line */
        !           975:    char_u          *ptr;
        !           976:    int             do_quotes;          /* check for quotes in current line */
        !           977:    int             at_start;           /* do_quotes value at start position */
        !           978:    int             hash_dir = 0;       /* Direction searched for # things */
        !           979:    int             comment_dir = 0;    /* Direction searched for comments */
        !           980:    FPOS            match_pos;          /* Where last slash-star was found */
        !           981:    int             start_in_quotes;    /* start position is in quotes */
        !           982:    int             traveled = 0;       /* how far we've searched so far */
        !           983:    int             ignore_cend = FALSE;    /* ignore comment end */
        !           984:    int             cpo_match;          /* vi compatible matching */
        !           985:    int             dir;                /* Direction to search */
        !           986:
        !           987:    pos = curwin->w_cursor;
        !           988:    linep = ml_get(pos.lnum);
        !           989:
        !           990:    cpo_match = (vim_strchr(p_cpo, CPO_MATCH) != NULL);
        !           991:
        !           992:    /* Direction to search when initc is '/', '*' or '#' */
        !           993:    if (flags & FM_BACKWARD)
        !           994:        dir = BACKWARD;
        !           995:    else if (flags & FM_FORWARD)
        !           996:        dir = FORWARD;
        !           997:    else
        !           998:        dir = 0;
        !           999:
        !          1000:    /*
        !          1001:     * if initc given, look in the table for the matching character
        !          1002:     * '/' and '*' are special cases: look for start or end of comment.
        !          1003:     * When '/' is used, we ignore running backwards into an star-slash, for
        !          1004:     * "[*" command, we just want to find any comment.
        !          1005:     */
        !          1006:    if (initc == '/' || initc == '*')
        !          1007:    {
        !          1008:        comment_dir = dir;
        !          1009:        if (initc == '/')
        !          1010:            ignore_cend = TRUE;
        !          1011:        idx = (dir == FORWARD) ? 0 : 1;
        !          1012:        initc = NUL;
        !          1013:    }
        !          1014:    else if (initc != '#' && initc != NUL)
        !          1015:    {
        !          1016:        for (idx = 0; idx < 6; ++idx)
        !          1017: #ifdef RIGHTLEFT
        !          1018:            if ((curwin->w_p_rl ? table_rl : table)[idx] == initc)
        !          1019:            {
        !          1020:                initc = (curwin->w_p_rl ? table_rl : table)[idx = idx ^ 1];
        !          1021:
        !          1022: #else
        !          1023:            if (table[idx] == initc)
        !          1024:            {
        !          1025:                initc = table[idx = idx ^ 1];
        !          1026: #endif
        !          1027:                break;
        !          1028:            }
        !          1029:        if (idx == 6)           /* invalid initc! */
        !          1030:            return NULL;
        !          1031:    }
        !          1032:    /*
        !          1033:     * Either initc is '#', or no initc was given and we need to look under the
        !          1034:     * cursor.
        !          1035:     */
        !          1036:    else
        !          1037:    {
        !          1038:        if (initc == '#')
        !          1039:        {
        !          1040:            hash_dir = dir;
        !          1041:        }
        !          1042:        else
        !          1043:        {
        !          1044:            /*
        !          1045:             * initc was not given, must look for something to match under
        !          1046:             * or near the cursor.
        !          1047:             */
        !          1048:            if (linep[0] == '#' && pos.col == 0)
        !          1049:            {
        !          1050:                /* If it's not #if, #else etc, we should look for a brace
        !          1051:                 * instead */
        !          1052:                for (c = 1; vim_iswhite(linep[c]); c++)
        !          1053:                    ;
        !          1054:                if (STRNCMP(linep + c, "if", (size_t)2) == 0 ||
        !          1055:                    STRNCMP(linep + c, "endif", (size_t)5) == 0 ||
        !          1056:                    STRNCMP(linep + c, "el", (size_t)2) == 0)
        !          1057:                        hash_dir = 1;
        !          1058:            }
        !          1059:
        !          1060:            /*
        !          1061:             * Are we on a comment?
        !          1062:             */
        !          1063:            else if (linep[pos.col] == '/')
        !          1064:            {
        !          1065:                if (linep[pos.col + 1] == '*')
        !          1066:                {
        !          1067:                    comment_dir = 1;
        !          1068:                    idx = 0;
        !          1069:                    pos.col++;
        !          1070:                }
        !          1071:                else if (pos.col > 0 && linep[pos.col - 1] == '*')
        !          1072:                {
        !          1073:                    comment_dir = -1;
        !          1074:                    idx = 1;
        !          1075:                    pos.col--;
        !          1076:                }
        !          1077:            }
        !          1078:            else if (linep[pos.col] == '*')
        !          1079:            {
        !          1080:                if (linep[pos.col + 1] == '/')
        !          1081:                {
        !          1082:                    comment_dir = -1;
        !          1083:                    idx = 1;
        !          1084:                }
        !          1085:                else if (pos.col > 0 && linep[pos.col - 1] == '/')
        !          1086:                {
        !          1087:                    comment_dir = 1;
        !          1088:                    idx = 0;
        !          1089:                }
        !          1090:            }
        !          1091:
        !          1092:            /*
        !          1093:             * If we are not on a comment or the # at the start of a line, then
        !          1094:             * look for brace anywhere on this line after the cursor.
        !          1095:             */
        !          1096:            if (!hash_dir && !comment_dir)
        !          1097:            {
        !          1098:                /*
        !          1099:                 * find the brace under or after the cursor
        !          1100:                 */
        !          1101:                linep = ml_get(pos.lnum);
        !          1102:                idx = 6;                    /* error if this line is empty */
        !          1103:                for (;;)
        !          1104:                {
        !          1105:                    initc = linep[pos.col];
        !          1106:                    if (initc == NUL)
        !          1107:                        break;
        !          1108:
        !          1109:                    for (idx = 0; idx < 6; ++idx)
        !          1110: #ifdef RIGHTLEFT
        !          1111:                        if ((curwin->w_p_rl ? table_rl : table)[idx] == initc)
        !          1112: #else
        !          1113:                        if (table[idx] == initc)
        !          1114: #endif
        !          1115:                            break;
        !          1116:                    if (idx != 6)
        !          1117:                        break;
        !          1118:                    ++pos.col;
        !          1119:                }
        !          1120:                if (idx == 6)
        !          1121:                {
        !          1122:                    if (linep[0] == '#')
        !          1123:                        hash_dir = 1;
        !          1124:                    else
        !          1125:                        return NULL;
        !          1126:                }
        !          1127:            }
        !          1128:        }
        !          1129:        if (hash_dir)
        !          1130:        {
        !          1131:            /*
        !          1132:             * Look for matching #if, #else, #elif, or #endif
        !          1133:             */
        !          1134:            op_motion_type = MLINE;     /* Linewise for this case only */
        !          1135:            if (initc != '#')
        !          1136:            {
        !          1137:                ptr = skipwhite(linep + 1);
        !          1138:                if (STRNCMP(ptr, "if", (size_t)2) == 0 ||
        !          1139:                                       STRNCMP(ptr, "el", (size_t)2) == 0)
        !          1140:                    hash_dir = 1;
        !          1141:                else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
        !          1142:                    hash_dir = -1;
        !          1143:                else
        !          1144:                    return NULL;
        !          1145:            }
        !          1146:            pos.col = 0;
        !          1147:            while (!got_int)
        !          1148:            {
        !          1149:                if (hash_dir > 0)
        !          1150:                {
        !          1151:                    if (pos.lnum == curbuf->b_ml.ml_line_count)
        !          1152:                        break;
        !          1153:                }
        !          1154:                else if (pos.lnum == 1)
        !          1155:                    break;
        !          1156:                pos.lnum += hash_dir;
        !          1157:                linep = ml_get(pos.lnum);
        !          1158:                line_breakcheck();
        !          1159:                if (linep[0] != '#')
        !          1160:                    continue;
        !          1161:                ptr = linep + 1;
        !          1162:                while (*ptr == ' ' || *ptr == TAB)
        !          1163:                    ptr++;
        !          1164:                if (hash_dir > 0)
        !          1165:                {
        !          1166:                    if (STRNCMP(ptr, "if", (size_t)2) == 0)
        !          1167:                        count++;
        !          1168:                    else if (STRNCMP(ptr, "el", (size_t)2) == 0)
        !          1169:                    {
        !          1170:                        if (count == 0)
        !          1171:                            return &pos;
        !          1172:                    }
        !          1173:                    else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
        !          1174:                    {
        !          1175:                        if (count == 0)
        !          1176:                            return &pos;
        !          1177:                        count--;
        !          1178:                    }
        !          1179:                }
        !          1180:                else
        !          1181:                {
        !          1182:                    if (STRNCMP(ptr, "if", (size_t)2) == 0)
        !          1183:                    {
        !          1184:                        if (count == 0)
        !          1185:                            return &pos;
        !          1186:                        count--;
        !          1187:                    }
        !          1188:                    else if (initc == '#' && STRNCMP(ptr, "el", (size_t)2) == 0)
        !          1189:                    {
        !          1190:                        if (count == 0)
        !          1191:                            return &pos;
        !          1192:                    }
        !          1193:                    else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
        !          1194:                        count++;
        !          1195:                }
        !          1196:            }
        !          1197:            return NULL;
        !          1198:        }
        !          1199:    }
        !          1200:
        !          1201: #ifdef RIGHTLEFT
        !          1202:    findc = (curwin->w_p_rl ? table_rl : table)[idx ^ 1];
        !          1203: #else
        !          1204:    findc = table[idx ^ 1];     /* get matching brace */
        !          1205: #endif
        !          1206:    idx &= 1;
        !          1207:
        !          1208:    do_quotes = -1;
        !          1209:    start_in_quotes = MAYBE;
        !          1210:    while (!got_int)
        !          1211:    {
        !          1212:        /*
        !          1213:         * Go to the next position, forward or backward. We could use
        !          1214:         * inc() and dec() here, but that is much slower
        !          1215:         */
        !          1216:        if (idx)                        /* backward search */
        !          1217:        {
        !          1218:            if (pos.col == 0)           /* at start of line, go to prev. one */
        !          1219:            {
        !          1220:                if (pos.lnum == 1)      /* start of file */
        !          1221:                    break;
        !          1222:                --pos.lnum;
        !          1223:
        !          1224:                if (maxtravel && traveled++ > maxtravel)
        !          1225:                    break;
        !          1226:
        !          1227:                linep = ml_get(pos.lnum);
        !          1228:                pos.col = STRLEN(linep);    /* put pos.col on trailing NUL */
        !          1229:                do_quotes = -1;
        !          1230:                line_breakcheck();
        !          1231:            }
        !          1232:            else
        !          1233:                --pos.col;
        !          1234:        }
        !          1235:        else                            /* forward search */
        !          1236:        {
        !          1237:            if (linep[pos.col] == NUL)  /* at end of line, go to next one */
        !          1238:            {
        !          1239:                if (pos.lnum == curbuf->b_ml.ml_line_count) /* end of file */
        !          1240:                    break;
        !          1241:                ++pos.lnum;
        !          1242:
        !          1243:                if (maxtravel && traveled++ > maxtravel)
        !          1244:                    break;
        !          1245:
        !          1246:                linep = ml_get(pos.lnum);
        !          1247:                pos.col = 0;
        !          1248:                do_quotes = -1;
        !          1249:                line_breakcheck();
        !          1250:            }
        !          1251:            else
        !          1252:                ++pos.col;
        !          1253:        }
        !          1254:
        !          1255:        /*
        !          1256:         * If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0.
        !          1257:         */
        !          1258:        if (pos.col == 0 && (flags & FM_BLOCKSTOP) &&
        !          1259:                                         (linep[0] == '{' || linep[0] == '}'))
        !          1260:        {
        !          1261:            if (linep[0] == findc && count == 0)        /* match! */
        !          1262:                return &pos;
        !          1263:            break;                                      /* out of scope */
        !          1264:        }
        !          1265:
        !          1266:        if (comment_dir)
        !          1267:        {
        !          1268:            /* Note: comments do not nest, and we ignore quotes in them */
        !          1269:            if (comment_dir == 1)
        !          1270:            {
        !          1271:                if (linep[pos.col] == '*' && linep[pos.col + 1] == '/')
        !          1272:                {
        !          1273:                    pos.col++;
        !          1274:                    return &pos;
        !          1275:                }
        !          1276:            }
        !          1277:            else    /* Searching backwards */
        !          1278:            {
        !          1279:                /*
        !          1280:                 * A comment may contain slash-star, it may also start or end
        !          1281:                 * with slash-star-slash.  I'm not using real examples though
        !          1282:                 * because "gcc -Wall" would complain -- webb
        !          1283:                 */
        !          1284:                if (pos.col == 0)
        !          1285:                    continue;
        !          1286:                else if (linep[pos.col - 1] == '/' && linep[pos.col] == '*')
        !          1287:                {
        !          1288:                    count++;
        !          1289:                    match_pos = pos;
        !          1290:                    match_pos.col--;
        !          1291:                }
        !          1292:                else if (linep[pos.col - 1] == '*' && linep[pos.col] == '/')
        !          1293:                {
        !          1294:                    if (count > 0)
        !          1295:                        pos = match_pos;
        !          1296:                    else if (pos.col > 1 && linep[pos.col - 2] == '/')
        !          1297:                        pos.col -= 2;
        !          1298:                    else if (ignore_cend)
        !          1299:                        continue;
        !          1300:                    else
        !          1301:                        return NULL;
        !          1302:                    return &pos;
        !          1303:                }
        !          1304:            }
        !          1305:            continue;
        !          1306:        }
        !          1307:
        !          1308:        /*
        !          1309:         * If smart matching ('cpoptions' does not contain '%'), braces inside
        !          1310:         * of quotes are ignored, but only if there is an even number of
        !          1311:         * quotes in the line.
        !          1312:         */
        !          1313:        if (cpo_match)
        !          1314:            do_quotes = 0;
        !          1315:        else if (do_quotes == -1)
        !          1316:        {
        !          1317:            /*
        !          1318:             * count the number of quotes in the line, skipping \" and '"'
        !          1319:             */
        !          1320:            at_start = do_quotes;
        !          1321:            for (ptr = linep; *ptr; ++ptr)
        !          1322:            {
        !          1323:                if (ptr == linep + curwin->w_cursor.col)
        !          1324:                    at_start = (do_quotes & 1);
        !          1325:                if (*ptr == '"' && (ptr == linep || ptr[-1] != '\\') &&
        !          1326:                            (ptr == linep || ptr[-1] != '\'' || ptr[1] != '\''))
        !          1327:                    ++do_quotes;
        !          1328:            }
        !          1329:            do_quotes &= 1;         /* result is 1 with even number of quotes */
        !          1330:
        !          1331:            /*
        !          1332:             * If we find an uneven count, check current line and previous
        !          1333:             * one for a '\' at the end.
        !          1334:             */
        !          1335:            if (!do_quotes)
        !          1336:            {
        !          1337:                inquote = FALSE;
        !          1338:                if (ptr[-1] == '\\')
        !          1339:                {
        !          1340:                    do_quotes = 1;
        !          1341:                    if (start_in_quotes == MAYBE)
        !          1342:                    {
        !          1343:                        inquote = !at_start;
        !          1344:                        if (inquote)
        !          1345:                            start_in_quotes = TRUE;
        !          1346:                    }
        !          1347:                    else if (idx)               /* backward search */
        !          1348:                        inquote = TRUE;
        !          1349:                }
        !          1350:                if (pos.lnum > 1)
        !          1351:                {
        !          1352:                    ptr = ml_get(pos.lnum - 1);
        !          1353:                    if (*ptr && *(ptr + STRLEN(ptr) - 1) == '\\')
        !          1354:                    {
        !          1355:                        do_quotes = 1;
        !          1356:                        if (start_in_quotes == MAYBE)
        !          1357:                        {
        !          1358:                            inquote = at_start;
        !          1359:                            if (inquote)
        !          1360:                                start_in_quotes = TRUE;
        !          1361:                        }
        !          1362:                        else if (!idx)              /* forward search */
        !          1363:                            inquote = TRUE;
        !          1364:                    }
        !          1365:                }
        !          1366:            }
        !          1367:        }
        !          1368:        if (start_in_quotes == MAYBE)
        !          1369:            start_in_quotes = FALSE;
        !          1370:
        !          1371:        /*
        !          1372:         * If 'smartmatch' is set:
        !          1373:         *   Things inside quotes are ignored by setting 'inquote'.  If we
        !          1374:         *   find a quote without a preceding '\' invert 'inquote'.  At the
        !          1375:         *   end of a line not ending in '\' we reset 'inquote'.
        !          1376:         *
        !          1377:         *   In lines with an uneven number of quotes (without preceding '\')
        !          1378:         *   we do not know which part to ignore. Therefore we only set
        !          1379:         *   inquote if the number of quotes in a line is even, unless this
        !          1380:         *   line or the previous one ends in a '\'.  Complicated, isn't it?
        !          1381:         */
        !          1382:        switch (c = linep[pos.col])
        !          1383:        {
        !          1384:        case NUL:
        !          1385:                /* at end of line without trailing backslash, reset inquote */
        !          1386:            if (pos.col == 0 || linep[pos.col - 1] != '\\')
        !          1387:            {
        !          1388:                inquote = FALSE;
        !          1389:                start_in_quotes = FALSE;
        !          1390:            }
        !          1391:            break;
        !          1392:
        !          1393:        case '"':
        !          1394:                /* a quote that is preceded with a backslash is ignored */
        !          1395:            if (do_quotes && (pos.col == 0 || linep[pos.col - 1] != '\\'))
        !          1396:            {
        !          1397:                inquote = !inquote;
        !          1398:                start_in_quotes = FALSE;
        !          1399:            }
        !          1400:            break;
        !          1401:
        !          1402:        /*
        !          1403:         * If smart matching ('cpoptions' does not contain '%'):
        !          1404:         *   Skip things in single quotes: 'x' or '\x'.  Be careful for single
        !          1405:         *   single quotes, eg jon's.  Things like '\233' or '\x3f' are not
        !          1406:         *   skipped, there is never a brace in them.
        !          1407:         */
        !          1408:        case '\'':
        !          1409:            if (vim_strchr(p_cpo, CPO_MATCH) == NULL)
        !          1410:            {
        !          1411:                if (idx)                        /* backward search */
        !          1412:                {
        !          1413:                    if (pos.col > 1)
        !          1414:                    {
        !          1415:                        if (linep[pos.col - 2] == '\'')
        !          1416:                            pos.col -= 2;
        !          1417:                        else if (linep[pos.col - 2] == '\\' &&
        !          1418:                                    pos.col > 2 && linep[pos.col - 3] == '\'')
        !          1419:                            pos.col -= 3;
        !          1420:                    }
        !          1421:                }
        !          1422:                else if (linep[pos.col + 1])    /* forward search */
        !          1423:                {
        !          1424:                    if (linep[pos.col + 1] == '\\' &&
        !          1425:                            linep[pos.col + 2] && linep[pos.col + 3] == '\'')
        !          1426:                        pos.col += 3;
        !          1427:                    else if (linep[pos.col + 2] == '\'')
        !          1428:                        pos.col += 2;
        !          1429:                }
        !          1430:            }
        !          1431:            break;
        !          1432:
        !          1433:        default:
        !          1434:                    /* Check for match outside of quotes, and inside of
        !          1435:                     * quotes when the start is also inside of quotes */
        !          1436:            if (!inquote || start_in_quotes == TRUE)
        !          1437:            {
        !          1438:                if (c == initc)
        !          1439:                    count++;
        !          1440:                else if (c == findc)
        !          1441:                {
        !          1442:                    if (count == 0)
        !          1443:                        return &pos;
        !          1444:                    count--;
        !          1445:                }
        !          1446:            }
        !          1447:        }
        !          1448:    }
        !          1449:
        !          1450:    if (comment_dir == -1 && count > 0)
        !          1451:    {
        !          1452:        pos = match_pos;
        !          1453:        return &pos;
        !          1454:    }
        !          1455:    return (FPOS *) NULL;       /* never found it */
        !          1456: }
        !          1457:
        !          1458: /*
        !          1459:  * Move cursor briefly to character matching the one under the cursor.
        !          1460:  * Show the match only if it is visible on the screen.
        !          1461:  */
        !          1462:    void
        !          1463: showmatch()
        !          1464: {
        !          1465:    FPOS           *lpos, csave;
        !          1466:    colnr_t         vcol;
        !          1467:
        !          1468:    if ((lpos = findmatch(NUL)) == NULL)        /* no match, so beep */
        !          1469:        beep_flush();
        !          1470:    else if (lpos->lnum >= curwin->w_topline)
        !          1471:    {
        !          1472:        if (!curwin->w_p_wrap)
        !          1473:            getvcol(curwin, lpos, NULL, &vcol, NULL);
        !          1474:        if (curwin->w_p_wrap || (vcol >= curwin->w_leftcol &&
        !          1475:                                          vcol < curwin->w_leftcol + Columns))
        !          1476:        {
        !          1477:            updateScreen(VALID_TO_CURSCHAR); /* show the new char first */
        !          1478:            csave = curwin->w_cursor;
        !          1479:            curwin->w_cursor = *lpos;   /* move to matching char */
        !          1480:            cursupdate();
        !          1481:            showruler(0);
        !          1482:            setcursor();
        !          1483:            cursor_on();                /* make sure that the cursor is shown */
        !          1484:            flushbuf();
        !          1485:
        !          1486:            /*
        !          1487:             * brief pause, unless 'm' is present in 'cpo' and a character is
        !          1488:             * available.
        !          1489:             */
        !          1490:            if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL)
        !          1491:                mch_delay(500L, TRUE);
        !          1492:            else if (!char_avail())
        !          1493:                mch_delay(500L, FALSE);
        !          1494:            curwin->w_cursor = csave;   /* restore cursor position */
        !          1495:            cursupdate();
        !          1496:        }
        !          1497:    }
        !          1498: }
        !          1499:
        !          1500: /*
        !          1501:  * findsent(dir, count) - Find the start of the next sentence in direction
        !          1502:  * 'dir' Sentences are supposed to end in ".", "!" or "?" followed by white
        !          1503:  * space or a line break. Also stop at an empty line.
        !          1504:  * Return OK if the next sentence was found.
        !          1505:  */
        !          1506:    int
        !          1507: findsent(dir, count)
        !          1508:    int     dir;
        !          1509:    long    count;
        !          1510: {
        !          1511:    FPOS            pos, tpos;
        !          1512:    register int    c;
        !          1513:    int             (*func) __PARMS((FPOS *));
        !          1514:    int             startlnum;
        !          1515:    int             noskip = FALSE;         /* do not skip blanks */
        !          1516:
        !          1517:    pos = curwin->w_cursor;
        !          1518:    if (dir == FORWARD)
        !          1519:        func = incl;
        !          1520:    else
        !          1521:        func = decl;
        !          1522:
        !          1523:    while (count--)
        !          1524:    {
        !          1525:        /*
        !          1526:         * if on an empty line, skip upto a non-empty line
        !          1527:         */
        !          1528:        if (gchar(&pos) == NUL)
        !          1529:        {
        !          1530:            do
        !          1531:                if ((*func)(&pos) == -1)
        !          1532:                    break;
        !          1533:            while (gchar(&pos) == NUL);
        !          1534:            if (dir == FORWARD)
        !          1535:                goto found;
        !          1536:        }
        !          1537:        /*
        !          1538:         * if on the start of a paragraph or a section and searching forward,
        !          1539:         * go to the next line
        !          1540:         */
        !          1541:        else if (dir == FORWARD && pos.col == 0 &&
        !          1542:                                                startPS(pos.lnum, NUL, FALSE))
        !          1543:        {
        !          1544:            if (pos.lnum == curbuf->b_ml.ml_line_count)
        !          1545:                return FAIL;
        !          1546:            ++pos.lnum;
        !          1547:            goto found;
        !          1548:        }
        !          1549:        else if (dir == BACKWARD)
        !          1550:            decl(&pos);
        !          1551:
        !          1552:        /* go back to the previous non-blank char */
        !          1553:        while ((c = gchar(&pos)) == ' ' || c == '\t' ||
        !          1554:             (dir == BACKWARD && vim_strchr((char_u *)".!?)]\"'", c) != NULL))
        !          1555:        {
        !          1556:            if (decl(&pos) == -1)
        !          1557:                break;
        !          1558:            /* when going forward: Stop in front of empty line */
        !          1559:            if (lineempty(pos.lnum) && dir == FORWARD)
        !          1560:            {
        !          1561:                incl(&pos);
        !          1562:                goto found;
        !          1563:            }
        !          1564:        }
        !          1565:
        !          1566:        /* remember the line where the search started */
        !          1567:        startlnum = pos.lnum;
        !          1568:
        !          1569:        for (;;)                /* find end of sentence */
        !          1570:        {
        !          1571:            c = gchar(&pos);
        !          1572:            if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
        !          1573:            {
        !          1574:                if (dir == BACKWARD && pos.lnum != startlnum)
        !          1575:                    ++pos.lnum;
        !          1576:                break;
        !          1577:            }
        !          1578:            if (c == '.' || c == '!' || c == '?')
        !          1579:            {
        !          1580:                tpos = pos;
        !          1581:                do
        !          1582:                    if ((c = inc(&tpos)) == -1)
        !          1583:                        break;
        !          1584:                while (vim_strchr((char_u *)")]\"'", c = gchar(&tpos)) != NULL);
        !          1585:                if (c == -1  || c == ' ' || c == '\t' || c == NUL)
        !          1586:                {
        !          1587:                    pos = tpos;
        !          1588:                    if (gchar(&pos) == NUL) /* skip NUL at EOL */
        !          1589:                        inc(&pos);
        !          1590:                    break;
        !          1591:                }
        !          1592:            }
        !          1593:            if ((*func)(&pos) == -1)
        !          1594:            {
        !          1595:                if (count)
        !          1596:                    return FAIL;
        !          1597:                noskip = TRUE;
        !          1598:                break;
        !          1599:            }
        !          1600:        }
        !          1601: found:
        !          1602:            /* skip white space */
        !          1603:        while (!noskip && ((c = gchar(&pos)) == ' ' || c == '\t'))
        !          1604:            if (incl(&pos) == -1)
        !          1605:                break;
        !          1606:    }
        !          1607:
        !          1608:    setpcmark();
        !          1609:    curwin->w_cursor = pos;
        !          1610:    return OK;
        !          1611: }
        !          1612:
        !          1613: /*
        !          1614:  * findpar(dir, count, what) - Find the next paragraph in direction 'dir'
        !          1615:  * Paragraphs are currently supposed to be separated by empty lines.
        !          1616:  * Return TRUE if the next paragraph was found.
        !          1617:  * If 'what' is '{' or '}' we go to the next section.
        !          1618:  * If 'both' is TRUE also stop at '}'.
        !          1619:  */
        !          1620:    int
        !          1621: findpar(dir, count, what, both)
        !          1622:    register int    dir;
        !          1623:    long            count;
        !          1624:    int             what;
        !          1625:    int             both;
        !          1626: {
        !          1627:    register linenr_t   curr;
        !          1628:    int                 did_skip;       /* TRUE after separating lines have
        !          1629:                                                been skipped */
        !          1630:    int                 first;          /* TRUE on first line */
        !          1631:
        !          1632:    curr = curwin->w_cursor.lnum;
        !          1633:
        !          1634:    while (count--)
        !          1635:    {
        !          1636:        did_skip = FALSE;
        !          1637:        for (first = TRUE; ; first = FALSE)
        !          1638:        {
        !          1639:            if (*ml_get(curr) != NUL)
        !          1640:                did_skip = TRUE;
        !          1641:
        !          1642:            if (!first && did_skip && startPS(curr, what, both))
        !          1643:                break;
        !          1644:
        !          1645:            if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
        !          1646:            {
        !          1647:                if (count)
        !          1648:                    return FALSE;
        !          1649:                curr -= dir;
        !          1650:                break;
        !          1651:            }
        !          1652:        }
        !          1653:    }
        !          1654:    setpcmark();
        !          1655:    if (both && *ml_get(curr) == '}')   /* include line with '}' */
        !          1656:        ++curr;
        !          1657:    curwin->w_cursor.lnum = curr;
        !          1658:    if (curr == curbuf->b_ml.ml_line_count)
        !          1659:    {
        !          1660:        if ((curwin->w_cursor.col = STRLEN(ml_get(curr))) != 0)
        !          1661:        {
        !          1662:            --curwin->w_cursor.col;
        !          1663:            op_inclusive = TRUE;
        !          1664:        }
        !          1665:    }
        !          1666:    else
        !          1667:        curwin->w_cursor.col = 0;
        !          1668:    return TRUE;
        !          1669: }
        !          1670:
        !          1671: /*
        !          1672:  * check if the string 's' is a nroff macro that is in option 'opt'
        !          1673:  */
        !          1674:    static int
        !          1675: inmacro(opt, s)
        !          1676:    char_u          *opt;
        !          1677:    register char_u *s;
        !          1678: {
        !          1679:    register char_u *macro;
        !          1680:
        !          1681:    for (macro = opt; macro[0]; ++macro)
        !          1682:    {
        !          1683:        if (macro[0] == s[0] && (((s[1] == NUL || s[1] == ' ') &&
        !          1684:                   (macro[1] == NUL || macro[1] == ' ')) || macro[1] == s[1]))
        !          1685:            break;
        !          1686:        ++macro;
        !          1687:        if (macro[0] == NUL)
        !          1688:            break;
        !          1689:    }
        !          1690:    return (macro[0] != NUL);
        !          1691: }
        !          1692:
        !          1693: /*
        !          1694:  * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
        !          1695:  * If 'para' is '{' or '}' only check for sections.
        !          1696:  * If 'both' is TRUE also stop at '}'
        !          1697:  */
        !          1698:    int
        !          1699: startPS(lnum, para, both)
        !          1700:    linenr_t    lnum;
        !          1701:    int         para;
        !          1702:    int         both;
        !          1703: {
        !          1704:    register char_u *s;
        !          1705:
        !          1706:    s = ml_get(lnum);
        !          1707:    if (*s == para || *s == '\f' || (both && *s == '}'))
        !          1708:        return TRUE;
        !          1709:    if (*s == '.' && (inmacro(p_sections, s + 1) ||
        !          1710:                                           (!para && inmacro(p_para, s + 1))))
        !          1711:        return TRUE;
        !          1712:    return FALSE;
        !          1713: }
        !          1714:
        !          1715: /*
        !          1716:  * The following routines do the word searches performed by the 'w', 'W',
        !          1717:  * 'b', 'B', 'e', and 'E' commands.
        !          1718:  */
        !          1719:
        !          1720: /*
        !          1721:  * To perform these searches, characters are placed into one of three
        !          1722:  * classes, and transitions between classes determine word boundaries.
        !          1723:  *
        !          1724:  * The classes are:
        !          1725:  *
        !          1726:  * 0 - white space
        !          1727:  * 1 - keyword charactes (letters, digits and underscore)
        !          1728:  * 2 - everything else
        !          1729:  */
        !          1730:
        !          1731: static int     stype;          /* type of the word motion being performed */
        !          1732:
        !          1733: /*
        !          1734:  * cls() - returns the class of character at curwin->w_cursor
        !          1735:  *
        !          1736:  * The 'type' of the current search modifies the classes of characters if a
        !          1737:  * 'W', 'B', or 'E' motion is being done. In this case, chars. from class 2
        !          1738:  * are reported as class 1 since only white space boundaries are of interest.
        !          1739:  */
        !          1740:    static int
        !          1741: cls()
        !          1742: {
        !          1743:    register int c;
        !          1744:
        !          1745:    c = gchar_cursor();
        !          1746:    if (c == ' ' || c == '\t' || c == NUL)
        !          1747:        return 0;
        !          1748:
        !          1749:    if (iswordchar(c))
        !          1750:        return 1;
        !          1751:
        !          1752:    /*
        !          1753:     * If stype is non-zero, report these as class 1.
        !          1754:     */
        !          1755:    return (stype == 0) ? 2 : 1;
        !          1756: }
        !          1757:
        !          1758:
        !          1759: /*
        !          1760:  * fwd_word(count, type, eol) - move forward one word
        !          1761:  *
        !          1762:  * Returns FAIL if the cursor was already at the end of the file.
        !          1763:  * If eol is TRUE, last word stops at end of line (for operators).
        !          1764:  */
        !          1765:    int
        !          1766: fwd_word(count, type, eol)
        !          1767:    long        count;
        !          1768:    int         type;
        !          1769:    int         eol;
        !          1770: {
        !          1771:    int         sclass;     /* starting class */
        !          1772:    int         i;
        !          1773:    int         last_line;
        !          1774:
        !          1775:    stype = type;
        !          1776:    while (--count >= 0)
        !          1777:    {
        !          1778:        sclass = cls();
        !          1779:
        !          1780:        /*
        !          1781:         * We always move at least one character, unless on the last character
        !          1782:         * in the buffer.
        !          1783:         */
        !          1784:        last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
        !          1785:        i = inc_cursor();
        !          1786:        if (i == -1 || (i == 1 && last_line))
        !          1787:                                            /* started at last char in file */
        !          1788:            return FAIL;
        !          1789:        if (i == 1 && eol && count == 0)    /* started at last char in line */
        !          1790:            return OK;
        !          1791:
        !          1792:        /*
        !          1793:         * Go one char past end of current word (if any)
        !          1794:         */
        !          1795:        if (sclass != 0)
        !          1796:            while (cls() == sclass)
        !          1797:            {
        !          1798:                i = inc_cursor();
        !          1799:                if (i == -1 || (i == 1 && eol && count == 0))
        !          1800:                    return OK;
        !          1801:            }
        !          1802:
        !          1803:        /*
        !          1804:         * go to next non-white
        !          1805:         */
        !          1806:        while (cls() == 0)
        !          1807:        {
        !          1808:            /*
        !          1809:             * We'll stop if we land on a blank line
        !          1810:             */
        !          1811:            if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
        !          1812:                break;
        !          1813:
        !          1814:            i = inc_cursor();
        !          1815:            if (i == -1 || (i == 1 && eol && count == 0))
        !          1816:                return OK;
        !          1817:        }
        !          1818:    }
        !          1819:    return OK;
        !          1820: }
        !          1821:
        !          1822: /*
        !          1823:  * bck_word() - move backward 'count' words
        !          1824:  *
        !          1825:  * If stop is TRUE and we are already on the start of a word, move one less.
        !          1826:  *
        !          1827:  * Returns FAIL if top of the file was reached.
        !          1828:  */
        !          1829:    int
        !          1830: bck_word(count, type, stop)
        !          1831:    long        count;
        !          1832:    int         type;
        !          1833:    int         stop;
        !          1834: {
        !          1835:    int         sclass;     /* starting class */
        !          1836:
        !          1837:    stype = type;
        !          1838:    while (--count >= 0)
        !          1839:    {
        !          1840:        sclass = cls();
        !          1841:        if (dec_cursor() == -1)     /* started at start of file */
        !          1842:            return FAIL;
        !          1843:
        !          1844:        if (!stop || sclass == cls() || sclass == 0)
        !          1845:        {
        !          1846:            /*
        !          1847:             * Skip white space before the word.
        !          1848:             * Stop on an empty line.
        !          1849:             */
        !          1850:            while (cls() == 0)
        !          1851:            {
        !          1852:                if (curwin->w_cursor.col == 0 &&
        !          1853:                                             lineempty(curwin->w_cursor.lnum))
        !          1854:                    goto finished;
        !          1855:
        !          1856:                if (dec_cursor() == -1)     /* hit start of file, stop here */
        !          1857:                    return OK;
        !          1858:            }
        !          1859:
        !          1860:            /*
        !          1861:             * Move backward to start of this word.
        !          1862:             */
        !          1863:            if (skip_chars(cls(), BACKWARD))
        !          1864:                return OK;
        !          1865:        }
        !          1866:
        !          1867:        inc_cursor();                    /* overshot - forward one */
        !          1868: finished:
        !          1869:        stop = FALSE;
        !          1870:    }
        !          1871:    return OK;
        !          1872: }
        !          1873:
        !          1874: /*
        !          1875:  * end_word() - move to the end of the word
        !          1876:  *
        !          1877:  * There is an apparent bug in the 'e' motion of the real vi. At least on the
        !          1878:  * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
        !          1879:  * motion crosses blank lines. When the real vi crosses a blank line in an
        !          1880:  * 'e' motion, the cursor is placed on the FIRST character of the next
        !          1881:  * non-blank line. The 'E' command, however, works correctly. Since this
        !          1882:  * appears to be a bug, I have not duplicated it here.
        !          1883:  *
        !          1884:  * Returns FAIL if end of the file was reached.
        !          1885:  *
        !          1886:  * If stop is TRUE and we are already on the end of a word, move one less.
        !          1887:  * If empty is TRUE stop on an empty line.
        !          1888:  */
        !          1889:    int
        !          1890: end_word(count, type, stop, empty)
        !          1891:    long        count;
        !          1892:    int         type;
        !          1893:    int         stop;
        !          1894:    int         empty;
        !          1895: {
        !          1896:    int         sclass;     /* starting class */
        !          1897:
        !          1898:    stype = type;
        !          1899:    while (--count >= 0)
        !          1900:    {
        !          1901:        sclass = cls();
        !          1902:        if (inc_cursor() == -1)
        !          1903:            return FAIL;
        !          1904:
        !          1905:        /*
        !          1906:         * If we're in the middle of a word, we just have to move to the end
        !          1907:         * of it.
        !          1908:         */
        !          1909:        if (cls() == sclass && sclass != 0)
        !          1910:        {
        !          1911:            /*
        !          1912:             * Move forward to end of the current word
        !          1913:             */
        !          1914:            if (skip_chars(sclass, FORWARD))
        !          1915:                return FAIL;
        !          1916:        }
        !          1917:        else if (!stop || sclass == 0)
        !          1918:        {
        !          1919:            /*
        !          1920:             * We were at the end of a word. Go to the end of the next word.
        !          1921:             * First skip white space, if 'empty' is TRUE, stop at empty line.
        !          1922:             */
        !          1923:            while (cls() == 0)
        !          1924:            {
        !          1925:                if (empty && curwin->w_cursor.col == 0 &&
        !          1926:                                             lineempty(curwin->w_cursor.lnum))
        !          1927:                    goto finished;
        !          1928:                if (inc_cursor() == -1)     /* hit end of file, stop here */
        !          1929:                    return FAIL;
        !          1930:            }
        !          1931:
        !          1932:            /*
        !          1933:             * Move forward to the end of this word.
        !          1934:             */
        !          1935:            if (skip_chars(cls(), FORWARD))
        !          1936:                return FAIL;
        !          1937:        }
        !          1938:        dec_cursor();                   /* overshot - one char backward */
        !          1939: finished:
        !          1940:        stop = FALSE;                   /* we move only one word less */
        !          1941:    }
        !          1942:    return OK;
        !          1943: }
        !          1944:
        !          1945: /*
        !          1946:  * bckend_word(count, type) - move back to the end of the word
        !          1947:  *
        !          1948:  * If 'eol' is TRUE, stop at end of line.
        !          1949:  *
        !          1950:  * Returns FAIL if start of the file was reached.
        !          1951:  */
        !          1952:    int
        !          1953: bckend_word(count, type, eol)
        !          1954:    long        count;
        !          1955:    int         type;
        !          1956:    int         eol;
        !          1957: {
        !          1958:    int         sclass;     /* starting class */
        !          1959:    int         i;
        !          1960:
        !          1961:    stype = type;
        !          1962:    while (--count >= 0)
        !          1963:    {
        !          1964:        sclass = cls();
        !          1965:        if ((i = dec_cursor()) == -1)
        !          1966:            return FAIL;
        !          1967:        if (eol && i == 1)
        !          1968:            return OK;
        !          1969:
        !          1970:        /*
        !          1971:         * Move backward to before the start of this word.
        !          1972:         */
        !          1973:        if (sclass != 0)
        !          1974:        {
        !          1975:            while (cls() == sclass)
        !          1976:                if ((i = dec_cursor()) == -1 || (eol && i == 1))
        !          1977:                    return OK;
        !          1978:        }
        !          1979:
        !          1980:        /*
        !          1981:         * Move backward to end of the previous word
        !          1982:         */
        !          1983:        while (cls() == 0)
        !          1984:        {
        !          1985:            if (curwin->w_cursor.col == 0 && lineempty(curwin->w_cursor.lnum))
        !          1986:                break;
        !          1987:            if ((i = dec_cursor()) == -1 || (eol && i == 1))
        !          1988:                return OK;
        !          1989:        }
        !          1990:    }
        !          1991:    return OK;
        !          1992: }
        !          1993:
        !          1994:    static int
        !          1995: skip_chars(cclass, dir)
        !          1996:    int     cclass;
        !          1997:    int     dir;
        !          1998: {
        !          1999:    while (cls() == cclass)
        !          2000:        if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
        !          2001:            return TRUE;
        !          2002:    return FALSE;
        !          2003: }
        !          2004:
        !          2005: /*
        !          2006:  * Go back to the start of the word or the start of white space
        !          2007:  */
        !          2008:    static void
        !          2009: back_in_line()
        !          2010: {
        !          2011:    int         sclass;             /* starting class */
        !          2012:
        !          2013:    sclass = cls();
        !          2014:    for (;;)
        !          2015:    {
        !          2016:        if (curwin->w_cursor.col == 0)      /* stop at start of line */
        !          2017:            break;
        !          2018:        --curwin->w_cursor.col;
        !          2019:        if (cls() != sclass)                /* stop at start of word */
        !          2020:        {
        !          2021:            ++curwin->w_cursor.col;
        !          2022:            break;
        !          2023:        }
        !          2024:    }
        !          2025: }
        !          2026:
        !          2027: /*
        !          2028:  * Find word under cursor, cursor at end
        !          2029:  */
        !          2030:    int
        !          2031: current_word(count, type)
        !          2032:    long        count;
        !          2033:    int         type;
        !          2034: {
        !          2035:    FPOS        start;
        !          2036:    FPOS        pos;
        !          2037:    int         inclusive = TRUE;
        !          2038:
        !          2039:    stype = type;
        !          2040:
        !          2041:    /*
        !          2042:     * When visual area is bigger than one character: Extend it.
        !          2043:     */
        !          2044:    if (VIsual_active && !equal(curwin->w_cursor, VIsual))
        !          2045:    {
        !          2046:        if (lt(curwin->w_cursor, VIsual))
        !          2047:        {
        !          2048:            if (decl(&curwin->w_cursor) == -1)
        !          2049:                return FAIL;
        !          2050:            if (cls() == 0)
        !          2051:            {
        !          2052:                if (bckend_word(count, type, TRUE) == FAIL)
        !          2053:                    return FAIL;
        !          2054:                (void)incl(&curwin->w_cursor);
        !          2055:            }
        !          2056:            else
        !          2057:            {
        !          2058:                if (bck_word(count, type, TRUE) == FAIL)
        !          2059:                    return FAIL;
        !          2060:            }
        !          2061:        }
        !          2062:        else
        !          2063:        {
        !          2064:            if (incl(&curwin->w_cursor) == -1)
        !          2065:                return FAIL;
        !          2066:            if (cls() == 0)
        !          2067:            {
        !          2068:                if (fwd_word(count, type, TRUE) == FAIL)
        !          2069:                    return FAIL;
        !          2070:                (void)oneleft();
        !          2071:            }
        !          2072:            else
        !          2073:            {
        !          2074:                if (end_word(count, type, TRUE, TRUE) == FAIL)
        !          2075:                    return FAIL;
        !          2076:            }
        !          2077:        }
        !          2078:        return OK;
        !          2079:    }
        !          2080:
        !          2081:    /*
        !          2082:     * Go to start of current word or white space.
        !          2083:     */
        !          2084:    back_in_line();
        !          2085:    start = curwin->w_cursor;
        !          2086:
        !          2087:    /*
        !          2088:     * If the start is on white space, find end of word.
        !          2089:     * Otherwise find start of next word.
        !          2090:     */
        !          2091:    if (cls() == 0)
        !          2092:    {
        !          2093:        if (end_word(count, type, TRUE, TRUE) == FAIL)
        !          2094:            return FAIL;
        !          2095:    }
        !          2096:    else
        !          2097:    {
        !          2098:        if (fwd_word(count, type, TRUE) == FAIL)
        !          2099:            return FAIL;
        !          2100:        /*
        !          2101:         * If end is just past a new-line, we don't want to include the first
        !          2102:         * character on the line
        !          2103:         */
        !          2104:        if (oneleft() == FAIL)          /* put cursor on last char of area */
        !          2105:            inclusive = FALSE;
        !          2106:        else
        !          2107:        {
        !          2108:            pos = curwin->w_cursor;     /* save cursor position */
        !          2109:            /*
        !          2110:             * If we don't include white space at the end, move the start to
        !          2111:             * include some white space there. This makes "d." work better on
        !          2112:             * the last word in a sentence. Don't delete white space at start
        !          2113:             * of line (indent).
        !          2114:             */
        !          2115:            if (cls() != 0)
        !          2116:            {
        !          2117:                curwin->w_cursor = start;
        !          2118:                if (oneleft() == OK)
        !          2119:                {
        !          2120:                    back_in_line();
        !          2121:                    if (cls() == 0 && curwin->w_cursor.col > 0)
        !          2122:                        start = curwin->w_cursor;
        !          2123:                }
        !          2124:            }
        !          2125:            curwin->w_cursor = pos;     /* put cursor back at end */
        !          2126:        }
        !          2127:    }
        !          2128:    if (VIsual_active)
        !          2129:    {
        !          2130:        /* should do something when inclusive == FALSE ! */
        !          2131:        VIsual = start;
        !          2132:        VIsual_mode = 'v';
        !          2133:        update_curbuf(NOT_VALID);       /* update the inversion */
        !          2134:    }
        !          2135:    else
        !          2136:    {
        !          2137:        curbuf->b_op_start = start;
        !          2138:        op_motion_type = MCHAR;
        !          2139:        op_inclusive = inclusive;
        !          2140:    }
        !          2141:    return OK;
        !          2142: }
        !          2143:
        !          2144: /*
        !          2145:  * Find sentence under the cursor, cursor at end.
        !          2146:  */
        !          2147:    int
        !          2148: current_sent(count)
        !          2149:    long    count;
        !          2150: {
        !          2151:    FPOS    start;
        !          2152:    FPOS    pos;
        !          2153:    int     start_blank;
        !          2154:    int     c;
        !          2155:
        !          2156:    pos = curwin->w_cursor;
        !          2157:    start = pos;
        !          2158:
        !          2159:    /*
        !          2160:     * When visual area is bigger than one character: Extend it.
        !          2161:     */
        !          2162:    if (VIsual_active && !equal(curwin->w_cursor, VIsual))
        !          2163:    {
        !          2164:        if (lt(pos, VIsual))
        !          2165:        {
        !          2166:            /*
        !          2167:             * Do a "sentence backward" on the next character.
        !          2168:             * If we end up on the same position, we were already at the start
        !          2169:             * of a sentence
        !          2170:             */
        !          2171:            if (incl(&curwin->w_cursor) == -1)
        !          2172:                return FAIL;
        !          2173:            findsent(BACKWARD, 1L);
        !          2174:            start = curwin->w_cursor;
        !          2175:            if (count > 1)
        !          2176:                findsent(BACKWARD, count - 1);
        !          2177:            /*
        !          2178:             * When at start of sentence: Include blanks in front of sentence.
        !          2179:             * Use current_word() to cross line boundaries.
        !          2180:             * If we don't end up on a blank or on an empty line, go back to
        !          2181:             * the start of the previous sentence.
        !          2182:             */
        !          2183:            if (equal(pos, start))
        !          2184:            {
        !          2185:                current_word(1L, 0);
        !          2186:                c = gchar_cursor();
        !          2187:                if (c != NUL && !vim_iswhite(c))
        !          2188:                    findsent(BACKWARD, 1L);
        !          2189:            }
        !          2190:
        !          2191:        }
        !          2192:        else
        !          2193:        {
        !          2194:            /*
        !          2195:             * When one char before start of sentence: Don't include blanks in
        !          2196:             * front of next sentence.
        !          2197:             * Else go count sentences forward.
        !          2198:             */
        !          2199:            findsent(FORWARD, 1L);
        !          2200:            incl(&pos);
        !          2201:            if (equal(pos, curwin->w_cursor))
        !          2202:            {
        !          2203:                findsent(FORWARD, count);
        !          2204:                find_first_blank(&curwin->w_cursor);
        !          2205:            }
        !          2206:            else if (count > 1)
        !          2207:                findsent(FORWARD, count - 1);
        !          2208:            decl(&curwin->w_cursor);
        !          2209:        }
        !          2210:        return OK;
        !          2211:    }
        !          2212:
        !          2213:    /*
        !          2214:     * Find start of next sentence.
        !          2215:     */
        !          2216:    findsent(FORWARD, 1L);
        !          2217:
        !          2218:    /*
        !          2219:     * If cursor started on blank, check if it is just before the start of the
        !          2220:     * next sentence.
        !          2221:     */
        !          2222:    while (vim_iswhite(gchar(&pos)))
        !          2223:        incl(&pos);
        !          2224:    if (equal(pos, curwin->w_cursor))
        !          2225:    {
        !          2226:        start_blank = TRUE;
        !          2227:        /*
        !          2228:         * go back to first blank
        !          2229:         */
        !          2230:        while (decl(&start) != -1)
        !          2231:        {
        !          2232:            if (!vim_iswhite(gchar(&start)))
        !          2233:            {
        !          2234:                incl(&start);
        !          2235:                break;
        !          2236:            }
        !          2237:        }
        !          2238:    }
        !          2239:    else
        !          2240:    {
        !          2241:        start_blank = FALSE;
        !          2242:        findsent(BACKWARD, 1L);
        !          2243:        start = curwin->w_cursor;
        !          2244:    }
        !          2245:    findsent(FORWARD, count);
        !          2246:
        !          2247:    /*
        !          2248:     * If the blank in front of the sentence is included, exclude the blanks
        !          2249:     * at the end of the sentence, go back to the first blank.
        !          2250:     */
        !          2251:    if (start_blank)
        !          2252:        find_first_blank(&curwin->w_cursor);
        !          2253:    else
        !          2254:    {
        !          2255:        /*
        !          2256:         * If there are no trailing blanks, try to include leading blanks
        !          2257:         */
        !          2258:        pos = curwin->w_cursor;
        !          2259:        decl(&pos);
        !          2260:        if (!vim_iswhite(gchar(&pos)))
        !          2261:            find_first_blank(&start);
        !          2262:    }
        !          2263:
        !          2264:    if (VIsual_active)
        !          2265:    {
        !          2266:        VIsual = start;
        !          2267:        VIsual_mode = 'v';
        !          2268:        decl(&curwin->w_cursor);        /* don't include the cursor char */
        !          2269:        update_curbuf(NOT_VALID);       /* update the inversion */
        !          2270:    }
        !          2271:    else
        !          2272:    {
        !          2273:        curbuf->b_op_start = start;
        !          2274:        op_motion_type = MCHAR;
        !          2275:        op_inclusive = FALSE;
        !          2276:    }
        !          2277:    return OK;
        !          2278: }
        !          2279:
        !          2280:    int
        !          2281: current_block(what, count)
        !          2282:    int     what;           /* '(' or '{' */
        !          2283:    long    count;
        !          2284: {
        !          2285:    FPOS    old_pos;
        !          2286:    FPOS    *pos = NULL;
        !          2287:    FPOS    start_pos;
        !          2288:    FPOS    *end_pos;
        !          2289:    FPOS    old_start, old_end;
        !          2290:    int     inclusive = FALSE;
        !          2291:    int     other;
        !          2292:
        !          2293:    old_pos = curwin->w_cursor;
        !          2294:    if (what == '{')
        !          2295:        other = '}';
        !          2296:    else
        !          2297:        other = ')';
        !          2298:
        !          2299:    old_end = curwin->w_cursor;             /* remember where we started */
        !          2300:    old_start = old_end;
        !          2301:
        !          2302:    /*
        !          2303:     * If we start on '(', '{', ')' or '}', use the whole block inclusive.
        !          2304:     */
        !          2305:    if (!VIsual_active || (VIsual.lnum == curwin->w_cursor.lnum &&
        !          2306:                                          VIsual.col == curwin->w_cursor.col))
        !          2307:    {
        !          2308:        if (what == '{')                    /* ignore indent */
        !          2309:            while (inindent(1))
        !          2310:                if (inc_cursor() != 0)
        !          2311:                    break;
        !          2312:        if (gchar_cursor() == what)         /* cursor on '(' or '{' */
        !          2313:        {
        !          2314:            ++curwin->w_cursor.col;
        !          2315:            inclusive = TRUE;
        !          2316:        }
        !          2317:        else if (gchar_cursor() == other)   /* cursor on ')' or '}' */
        !          2318:            inclusive = TRUE;
        !          2319:    }
        !          2320:    else if (lt(VIsual, curwin->w_cursor))
        !          2321:    {
        !          2322:        old_start = VIsual;
        !          2323:        curwin->w_cursor = VIsual;          /* cursor at low end of Visual */
        !          2324:    }
        !          2325:    else
        !          2326:        old_end = VIsual;
        !          2327:
        !          2328:    /*
        !          2329:     * Search backwards for unclosed '(' or '{'.
        !          2330:     * put this position in start_pos.
        !          2331:     */
        !          2332:    while (count--)
        !          2333:    {
        !          2334:        if ((pos = findmatch(what)) == NULL)
        !          2335:            break;
        !          2336:        curwin->w_cursor = *pos;
        !          2337:        start_pos = *pos;   /* the findmatch for end_pos will overwrite *pos */
        !          2338:    }
        !          2339:
        !          2340:    /*
        !          2341:     * Search for matching ')' or '}'.
        !          2342:     * Put this position in curwin->w_cursor.
        !          2343:     */
        !          2344:    if (pos == NULL || (end_pos = findmatch(other)) == NULL)
        !          2345:    {
        !          2346:        curwin->w_cursor = old_pos;
        !          2347:        return FAIL;
        !          2348:    }
        !          2349:    curwin->w_cursor = *end_pos;
        !          2350:
        !          2351:    /*
        !          2352:     * Try to exclude the '(', '{', ')' and '}'.
        !          2353:     * If the ending '}' is only preceded by indent, skip that indent.
        !          2354:     * But only if the resulting area is not smaller than what we started with.
        !          2355:     */
        !          2356:    if (!inclusive)
        !          2357:    {
        !          2358:        incl(&start_pos);
        !          2359:        old_pos = curwin->w_cursor;
        !          2360:        decl(&curwin->w_cursor);
        !          2361:        if (what == '{')
        !          2362:            while (inindent(0))
        !          2363:                if (decl(&curwin->w_cursor) != 0)
        !          2364:                    break;
        !          2365:        if (!lt(start_pos, old_start) && !lt(old_end, curwin->w_cursor))
        !          2366:        {
        !          2367:            decl(&start_pos);
        !          2368:            curwin->w_cursor = old_pos;
        !          2369:        }
        !          2370:    }
        !          2371:
        !          2372:    if (VIsual_active)
        !          2373:    {
        !          2374:        VIsual = start_pos;
        !          2375:        VIsual_mode = 'v';
        !          2376:        update_curbuf(NOT_VALID);       /* update the inversion */
        !          2377:        showmode();
        !          2378:    }
        !          2379:    else
        !          2380:    {
        !          2381:        curbuf->b_op_start = start_pos;
        !          2382:        op_motion_type = MCHAR;
        !          2383:        op_inclusive = TRUE;
        !          2384:    }
        !          2385:
        !          2386:    return OK;
        !          2387: }
        !          2388:
        !          2389:    int
        !          2390: current_par(type, count)
        !          2391:    int     type;           /* 'p' for paragraph, 'S' for section */
        !          2392:    long    count;
        !          2393: {
        !          2394:    linenr_t    start;
        !          2395:    linenr_t    end;
        !          2396:    int         white_in_front;
        !          2397:    int         dir;
        !          2398:    int         start_is_white;
        !          2399:    int         retval = OK;
        !          2400:
        !          2401:    if (type == 'S')        /* not implemented yet */
        !          2402:        return FAIL;
        !          2403:
        !          2404:    start = curwin->w_cursor.lnum;
        !          2405:
        !          2406:    /*
        !          2407:     * When visual area is more than one line: extend it.
        !          2408:     */
        !          2409:    if (VIsual_active && start != VIsual.lnum)
        !          2410:    {
        !          2411:        if (start < VIsual.lnum)
        !          2412:            dir = BACKWARD;
        !          2413:        else
        !          2414:            dir = FORWARD;
        !          2415:        while (count--)
        !          2416:        {
        !          2417:            if (start == (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count))
        !          2418:                retval = FAIL;
        !          2419:
        !          2420:            start_is_white = -1;
        !          2421:            for (;;)
        !          2422:            {
        !          2423:                if (start == (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count))
        !          2424:                    break;
        !          2425:                if (start_is_white >= 0 &&
        !          2426:                                  (start_is_white != linewhite(start + dir) ||
        !          2427:                                    startPS(start + (dir > 0 ? 1 : 0), 0, 0)))
        !          2428:                    break;
        !          2429:                start += dir;
        !          2430:                if (start_is_white < 0)
        !          2431:                    start_is_white = linewhite(start);
        !          2432:            }
        !          2433:        }
        !          2434:        curwin->w_cursor.lnum = start;
        !          2435:        curwin->w_cursor.col = 0;
        !          2436:        return retval;
        !          2437:    }
        !          2438:
        !          2439:    /*
        !          2440:     * First move back to the start of the paragraph or white lines
        !          2441:     */
        !          2442:    white_in_front = linewhite(start);
        !          2443:    while (start > 1)
        !          2444:    {
        !          2445:        if (white_in_front)         /* stop at first white line */
        !          2446:        {
        !          2447:            if (!linewhite(start - 1))
        !          2448:                break;
        !          2449:        }
        !          2450:        else            /* stop at first non-white line of start of paragraph */
        !          2451:        {
        !          2452:            if (linewhite(start - 1) || startPS(start, 0, 0))
        !          2453:                break;
        !          2454:        }
        !          2455:        --start;
        !          2456:    }
        !          2457:
        !          2458:    /*
        !          2459:     * Move past the end of the white lines.
        !          2460:     */
        !          2461:    end = start;
        !          2462:    while (linewhite(end) && end < curbuf->b_ml.ml_line_count)
        !          2463:        ++end;
        !          2464:
        !          2465:    --end;
        !          2466:    while (count--)
        !          2467:    {
        !          2468:        if (end == curbuf->b_ml.ml_line_count)
        !          2469:            return FAIL;
        !          2470:
        !          2471:        ++end;
        !          2472:        /*
        !          2473:         * skip to end of paragraph
        !          2474:         */
        !          2475:        while (end < curbuf->b_ml.ml_line_count &&
        !          2476:                               !linewhite(end + 1) && !startPS(end + 1, 0, 0))
        !          2477:            ++end;
        !          2478:
        !          2479:        if (count == 0 && white_in_front)
        !          2480:            break;
        !          2481:
        !          2482:        /*
        !          2483:         * skip to end of white lines after paragraph
        !          2484:         */
        !          2485:        while (end < curbuf->b_ml.ml_line_count && linewhite(end + 1))
        !          2486:            ++end;
        !          2487:    }
        !          2488:
        !          2489:    /*
        !          2490:     * If there are no empty lines at the end, try to find some empty lines at
        !          2491:     * the start (unless that has been done already).
        !          2492:     */
        !          2493:    if (!white_in_front && !linewhite(end))
        !          2494:        while (start > 1 && linewhite(start - 1))
        !          2495:            --start;
        !          2496:
        !          2497:    if (VIsual_active)
        !          2498:    {
        !          2499:        VIsual.lnum = start;
        !          2500:        VIsual_mode = 'V';
        !          2501:        update_curbuf(NOT_VALID);       /* update the inversion */
        !          2502:        showmode();
        !          2503:    }
        !          2504:    else
        !          2505:    {
        !          2506:        curbuf->b_op_start.lnum = start;
        !          2507:        op_motion_type = MLINE;
        !          2508:    }
        !          2509:    curwin->w_cursor.lnum = end;
        !          2510:    curwin->w_cursor.col = 0;
        !          2511:
        !          2512:    return OK;
        !          2513: }
        !          2514:
        !          2515: /*
        !          2516:  * linewhite -- return TRUE if line 'lnum' is empty or has white chars only.
        !          2517:  */
        !          2518:    int
        !          2519: linewhite(lnum)
        !          2520:    linenr_t    lnum;
        !          2521: {
        !          2522:    char_u  *p;
        !          2523:
        !          2524:    p = skipwhite(ml_get(lnum));
        !          2525:    return (*p == NUL);
        !          2526: }
        !          2527:
        !          2528:    static void
        !          2529: find_first_blank(posp)
        !          2530:    FPOS    *posp;
        !          2531: {
        !          2532:    while (decl(posp) != -1)
        !          2533:    {
        !          2534:        if (!vim_iswhite(gchar(posp)))
        !          2535:        {
        !          2536:            incl(posp);
        !          2537:            break;
        !          2538:        }
        !          2539:    }
        !          2540: }
        !          2541:
        !          2542:    void
        !          2543: find_pattern_in_path(ptr, len, whole, skip_comments,
        !          2544:                                    type, count, action, start_lnum, end_lnum)
        !          2545:    char_u  *ptr;           /* pointer to search pattern */
        !          2546:    int     len;            /* length of search pattern */
        !          2547:    int     whole;          /* match whole words only */
        !          2548:    int     skip_comments;  /* don't match inside comments */
        !          2549:    int     type;           /* Type of search; are we looking for a type?  a
        !          2550:                                macro? */
        !          2551:    long    count;
        !          2552:    int     action;         /* What to do when we find it */
        !          2553:    linenr_t    start_lnum; /* first line to start searching */
        !          2554:    linenr_t    end_lnum;   /* last line for searching */
        !          2555: {
        !          2556:    SearchedFile *files;                /* Stack of included files */
        !          2557:    SearchedFile *bigger;               /* When we need more space */
        !          2558:    int         max_path_depth = 50;
        !          2559:    long        match_count = 1;
        !          2560:
        !          2561:    char_u      *pat;
        !          2562:    char_u      *new_fname;
        !          2563:    char_u      *curr_fname = curbuf->b_xfilename;
        !          2564:    char_u      *prev_fname = NULL;
        !          2565:    linenr_t    lnum;
        !          2566:    int         depth;
        !          2567:    int         depth_displayed;        /* For type==CHECK_PATH */
        !          2568:    int         old_files;
        !          2569:    int         already_searched;
        !          2570:    char_u      *file_line;
        !          2571:    char_u      *line;
        !          2572:    char_u      *p;
        !          2573:    char_u      *p2 = NUL;              /* Init for gcc */
        !          2574:    char_u      save_char = NUL;
        !          2575:    int         define_matched;
        !          2576:    struct regexp *prog = NULL;
        !          2577:    struct regexp *include_prog = NULL;
        !          2578:    struct regexp *define_prog = NULL;
        !          2579:    int         matched = FALSE;
        !          2580:    int         did_show = FALSE;
        !          2581:    int         found = FALSE;
        !          2582:    int         i;
        !          2583:
        !          2584:    file_line = alloc(LSIZE);
        !          2585:    if (file_line == NULL)
        !          2586:        return;
        !          2587:
        !          2588:    reg_magic = p_magic;
        !          2589:    if (type != CHECK_PATH)
        !          2590:    {
        !          2591:        pat = alloc(len + 5);
        !          2592:        if (pat == NULL)
        !          2593:            goto fpip_end;
        !          2594:        sprintf((char *)pat, whole ? "\\<%.*s\\>" : "%.*s", len, ptr);
        !          2595:        set_reg_ic(pat);    /* set reg_ic according to p_ic, p_scs and pat */
        !          2596:        prog = vim_regcomp(pat);
        !          2597:        vim_free(pat);
        !          2598:        if (prog == NULL)
        !          2599:            goto fpip_end;
        !          2600:    }
        !          2601:    reg_ic = FALSE;     /* don't ignore case in include and define patterns */
        !          2602:    if (*p_inc != NUL)
        !          2603:    {
        !          2604:        include_prog = vim_regcomp(p_inc);
        !          2605:        if (include_prog == NULL)
        !          2606:            goto fpip_end;
        !          2607:    }
        !          2608:    if (type == FIND_DEFINE && *p_def != NUL)
        !          2609:    {
        !          2610:        define_prog = vim_regcomp(p_def);
        !          2611:        if (define_prog == NULL)
        !          2612:            goto fpip_end;
        !          2613:    }
        !          2614:    files = (SearchedFile *)lalloc(max_path_depth * sizeof(SearchedFile), TRUE);
        !          2615:    if (files == NULL)
        !          2616:        goto fpip_end;
        !          2617:    for (i = 0; i < max_path_depth; i++)
        !          2618:    {
        !          2619:        files[i].fp = NULL;
        !          2620:        files[i].name = NULL;
        !          2621:        files[i].lnum = 0;
        !          2622:        files[i].matched = FALSE;
        !          2623:    }
        !          2624:    old_files = max_path_depth;
        !          2625:    depth = depth_displayed = -1;
        !          2626:
        !          2627:    lnum = start_lnum;
        !          2628:    if (end_lnum > curbuf->b_ml.ml_line_count)
        !          2629:        end_lnum = curbuf->b_ml.ml_line_count;
        !          2630:    if (lnum > end_lnum)                /* do at least one line */
        !          2631:        lnum = end_lnum;
        !          2632:    line = ml_get(lnum);
        !          2633:
        !          2634:    for (;;)
        !          2635:    {
        !          2636:        if (include_prog != NULL && vim_regexec(include_prog, line, TRUE))
        !          2637:        {
        !          2638:            new_fname = get_file_name_in_path(include_prog->endp[0] + 1,
        !          2639:                                                                0, FNAME_EXP);
        !          2640:            already_searched = FALSE;
        !          2641:            if (new_fname != NULL)
        !          2642:            {
        !          2643:                /* Check whether we have already searched in this file */
        !          2644:                for (i = 0;; i++)
        !          2645:                {
        !          2646:                    if (i == depth + 1)
        !          2647:                        i = old_files;
        !          2648:                    if (i == max_path_depth)
        !          2649:                        break;
        !          2650:                    if (STRCMP(new_fname, files[i].name) == 0)
        !          2651:                    {
        !          2652:                        if (type != CHECK_PATH &&
        !          2653:                                action == ACTION_SHOW_ALL && files[i].matched)
        !          2654:                        {
        !          2655:                            msg_outchar('\n');      /* cursor below last one */
        !          2656:                            if (!got_int)           /* don't display if 'q'
        !          2657:                                                       typed at "--more--"
        !          2658:                                                       mesage */
        !          2659:                            {
        !          2660:                                set_highlight('d'); /* Same as for dirs */
        !          2661:                                start_highlight();
        !          2662:                                msg_home_replace(new_fname);
        !          2663:                                stop_highlight();
        !          2664:                                MSG_OUTSTR(" (includes previously listed match)");
        !          2665:                                prev_fname = NULL;
        !          2666:                            }
        !          2667:                        }
        !          2668:                        vim_free(new_fname);
        !          2669:                        new_fname = NULL;
        !          2670:                        already_searched = TRUE;
        !          2671:                        break;
        !          2672:                    }
        !          2673:                }
        !          2674:            }
        !          2675:
        !          2676:            if (type == CHECK_PATH && (action == ACTION_SHOW_ALL ||
        !          2677:                                    (new_fname == NULL && !already_searched)))
        !          2678:            {
        !          2679:                if (did_show)
        !          2680:                    msg_outchar('\n');      /* cursor below last one */
        !          2681:                else
        !          2682:                {
        !          2683:                    gotocmdline(TRUE);      /* cursor at status line */
        !          2684:                    set_highlight('t');     /* Highlight title */
        !          2685:                    start_highlight();
        !          2686:                    MSG_OUTSTR("--- Included files ");
        !          2687:                    if (action != ACTION_SHOW_ALL)
        !          2688:                        MSG_OUTSTR("not found ");
        !          2689:                    MSG_OUTSTR("in path ---\n");
        !          2690:                    stop_highlight();
        !          2691:                }
        !          2692:                did_show = TRUE;
        !          2693:                while (depth_displayed < depth && !got_int)
        !          2694:                {
        !          2695:                    ++depth_displayed;
        !          2696:                    for (i = 0; i < depth_displayed; i++)
        !          2697:                        MSG_OUTSTR("  ");
        !          2698:                    msg_home_replace(files[depth_displayed].name);
        !          2699:                    MSG_OUTSTR(" -->\n");
        !          2700:                }
        !          2701:                if (!got_int)               /* don't display if 'q' typed
        !          2702:                                               for "--more--" message */
        !          2703:                {
        !          2704:                    for (i = 0; i <= depth_displayed; i++)
        !          2705:                        MSG_OUTSTR("  ");
        !          2706:                    set_highlight('d');     /* Same as for directories */
        !          2707:                    start_highlight();
        !          2708:                    /*
        !          2709:                     * Isolate the file name.
        !          2710:                     * Include the surrounding "" or <> if present.
        !          2711:                     */
        !          2712:                    for (p = include_prog->endp[0] + 1; !isfilechar(*p); p++)
        !          2713:                        ;
        !          2714:                    for (i = 0; isfilechar(p[i]); i++)
        !          2715:                        ;
        !          2716:                    if (p[-1] == '"' || p[-1] == '<')
        !          2717:                    {
        !          2718:                        --p;
        !          2719:                        ++i;
        !          2720:                    }
        !          2721:                    if (p[i] == '"' || p[i] == '>')
        !          2722:                        ++i;
        !          2723:                    save_char = p[i];
        !          2724:                    p[i] = NUL;
        !          2725:                    msg_outstr(p);
        !          2726:                    p[i] = save_char;
        !          2727:                    stop_highlight();
        !          2728:                    if (new_fname == NULL && action == ACTION_SHOW_ALL)
        !          2729:                    {
        !          2730:                        if (already_searched)
        !          2731:                            MSG_OUTSTR("  (Already listed)");
        !          2732:                        else
        !          2733:                            MSG_OUTSTR("  NOT FOUND");
        !          2734:                    }
        !          2735:                }
        !          2736:                flushbuf();         /* output each line directly */
        !          2737:            }
        !          2738:
        !          2739:            if (new_fname != NULL)
        !          2740:            {
        !          2741:                /* Push the new file onto the file stack */
        !          2742:                if (depth + 1 == old_files)
        !          2743:                {
        !          2744:                    bigger = (SearchedFile *)lalloc(max_path_depth * 2
        !          2745:                                                * sizeof(SearchedFile), TRUE);
        !          2746:                    if (bigger != NULL)
        !          2747:                    {
        !          2748:                        for (i = 0; i <= depth; i++)
        !          2749:                            bigger[i] = files[i];
        !          2750:                        for (i = depth + 1; i < old_files + max_path_depth; i++)
        !          2751:                        {
        !          2752:                            bigger[i].fp = NULL;
        !          2753:                            bigger[i].name = NULL;
        !          2754:                            bigger[i].lnum = 0;
        !          2755:                            bigger[i].matched = FALSE;
        !          2756:                        }
        !          2757:                        for (i = old_files; i < max_path_depth; i++)
        !          2758:                            bigger[i + max_path_depth] = files[i];
        !          2759:                        old_files += max_path_depth;
        !          2760:                        max_path_depth *= 2;
        !          2761:                        vim_free(files);
        !          2762:                        files = bigger;
        !          2763:                    }
        !          2764:                }
        !          2765:                if ((files[depth + 1].fp = fopen((char *)new_fname, "r"))
        !          2766:                                                                    == NULL)
        !          2767:                    vim_free(new_fname);
        !          2768:                else
        !          2769:                {
        !          2770:                    if (++depth == old_files)
        !          2771:                    {
        !          2772:                        /*
        !          2773:                         * lalloc() for 'bigger' must have failed above.  We
        !          2774:                         * will forget one of our already visited files now.
        !          2775:                         */
        !          2776:                        vim_free(files[old_files].name);
        !          2777:                        ++old_files;
        !          2778:                    }
        !          2779:                    files[depth].name = curr_fname = new_fname;
        !          2780:                    files[depth].lnum = 0;
        !          2781:                    files[depth].matched = FALSE;
        !          2782:                }
        !          2783:            }
        !          2784:        }
        !          2785:        else
        !          2786:        {
        !          2787:            /*
        !          2788:             * Check if the line is a define (type == FIND_DEFINE)
        !          2789:             */
        !          2790:            p = line;
        !          2791:            define_matched = FALSE;
        !          2792:            if (define_prog != NULL && vim_regexec(define_prog, line, TRUE))
        !          2793:            {
        !          2794:                /*
        !          2795:                 * Pattern must be first identifier after 'define', so skip
        !          2796:                 * to that position before checking for match of pattern.  Also
        !          2797:                 * don't let it match beyond the end of this identifier.
        !          2798:                 */
        !          2799:                p = define_prog->endp[0] + 1;
        !          2800:                while (*p && !isidchar(*p))
        !          2801:                    p++;
        !          2802:                p2 = p;
        !          2803:                while (*p2 && isidchar(*p2))
        !          2804:                    p2++;
        !          2805:                save_char = *p2;
        !          2806:                *p2 = NUL;
        !          2807:                define_matched = TRUE;
        !          2808:            }
        !          2809:
        !          2810:            /*
        !          2811:             * Look for a match.  Don't do this if we are looking for a
        !          2812:             * define and this line didn't match define_prog above.
        !          2813:             */
        !          2814:            if ((define_prog == NULL || define_matched) &&
        !          2815:                              prog != NULL && vim_regexec(prog, p, p == line))
        !          2816:            {
        !          2817:                matched = TRUE;
        !          2818:                /*
        !          2819:                 * Check if the line is not a comment line (unless we are
        !          2820:                 * looking for a define).  A line starting with "# define" is
        !          2821:                 * not considered to be a comment line.
        !          2822:                 */
        !          2823:                if (!define_matched && skip_comments)
        !          2824:                {
        !          2825:                    fo_do_comments = TRUE;
        !          2826:                    if ((*line != '#' ||
        !          2827:                            STRNCMP(skipwhite(line + 1), "define", 6) != 0) &&
        !          2828:                                                   get_leader_len(line, NULL))
        !          2829:                        matched = FALSE;
        !          2830:
        !          2831:                    /*
        !          2832:                     * Also check for a "/ *" or "/ /" before the match.
        !          2833:                     * Skips lines like "int idx;  / * normal index * /" when
        !          2834:                     * looking for "normal".
        !          2835:                     */
        !          2836:                    else
        !          2837:                        for (p = line; *p && p < prog->startp[0]; ++p)
        !          2838:                            if (p[0] == '/' && (p[1] == '*' || p[1] == '/'))
        !          2839:                            {
        !          2840:                                matched = FALSE;
        !          2841:                                break;
        !          2842:                            }
        !          2843:                    fo_do_comments = FALSE;
        !          2844:                }
        !          2845:            }
        !          2846:            if (define_matched)
        !          2847:                *p2 = save_char;
        !          2848:        }
        !          2849:        if (matched)
        !          2850:        {
        !          2851: #ifdef INSERT_EXPAND
        !          2852:            if (action == ACTION_EXPAND)
        !          2853:            {
        !          2854:                if (depth == -1 && lnum == curwin->w_cursor.lnum)
        !          2855:                    break;
        !          2856:                found = TRUE;
        !          2857:                p = prog->startp[0];
        !          2858:                while (iswordchar(*p))
        !          2859:                    ++p;
        !          2860:                if (add_completion_and_infercase(prog->startp[0],
        !          2861:                                                   (int)(p - prog->startp[0]),
        !          2862:                        curr_fname == curbuf->b_xfilename ? NULL : curr_fname,
        !          2863:                                                        FORWARD) == RET_ERROR)
        !          2864:                    break;
        !          2865:            }
        !          2866:            else
        !          2867: #endif
        !          2868:                 if (action == ACTION_SHOW_ALL)
        !          2869:            {
        !          2870:                found = TRUE;
        !          2871:                if (!did_show)
        !          2872:                    gotocmdline(TRUE);          /* cursor at status line */
        !          2873:                if (curr_fname != prev_fname)
        !          2874:                {
        !          2875:                    if (did_show)
        !          2876:                        msg_outchar('\n');      /* cursor below last one */
        !          2877:                    if (!got_int)               /* don't display if 'q' typed
        !          2878:                                                    at "--more--" mesage */
        !          2879:                    {
        !          2880:                        set_highlight('d');     /* Same as for directories */
        !          2881:                        start_highlight();
        !          2882:                        msg_home_replace(curr_fname);
        !          2883:                        stop_highlight();
        !          2884:                    }
        !          2885:                    prev_fname = curr_fname;
        !          2886:                }
        !          2887:                did_show = TRUE;
        !          2888:                if (!got_int)
        !          2889:                    show_pat_in_path(line, type, TRUE, action,
        !          2890:                            (depth == -1) ? NULL : files[depth].fp,
        !          2891:                            (depth == -1) ? &lnum : &files[depth].lnum,
        !          2892:                            match_count++);
        !          2893:
        !          2894:                /* Set matched flag for this file and all the ones that
        !          2895:                 * include it */
        !          2896:                for (i = 0; i <= depth; ++i)
        !          2897:                    files[i].matched = TRUE;
        !          2898:            }
        !          2899:            else if (--count <= 0)
        !          2900:            {
        !          2901:                found = TRUE;
        !          2902:                if (depth == -1 && lnum == curwin->w_cursor.lnum)
        !          2903:                    EMSG("Match is on current line");
        !          2904:                else if (action == ACTION_SHOW)
        !          2905:                {
        !          2906:                    show_pat_in_path(line, type, did_show, action,
        !          2907:                        (depth == -1) ? NULL : files[depth].fp,
        !          2908:                        (depth == -1) ? &lnum : &files[depth].lnum, 1L);
        !          2909:                    did_show = TRUE;
        !          2910:                }
        !          2911:                else
        !          2912:                {
        !          2913:                    if (action == ACTION_SPLIT)
        !          2914:                    {
        !          2915:                        if (win_split(0, FALSE) == FAIL)
        !          2916:                            break;
        !          2917:                    }
        !          2918:                    if (depth == -1)
        !          2919:                    {
        !          2920:                        setpcmark();
        !          2921:                        curwin->w_cursor.lnum = lnum;
        !          2922:                    }
        !          2923:                    else
        !          2924:                        if (getfile(0, files[depth].name, NULL, TRUE,
        !          2925:                                                        files[depth].lnum) > 0)
        !          2926:                            break;      /* failed to jump to file */
        !          2927:                }
        !          2928:                if (action != ACTION_SHOW)
        !          2929:                {
        !          2930:                    curwin->w_cursor.col = prog->startp[0] - line;
        !          2931:                    curwin->w_set_curswant = TRUE;
        !          2932:                }
        !          2933:                break;
        !          2934:            }
        !          2935:            matched = FALSE;
        !          2936:        }
        !          2937:        line_breakcheck();
        !          2938:        if (got_int)
        !          2939:            break;
        !          2940:        while (depth >= 0)
        !          2941:        {
        !          2942:            if (!vim_fgets(line = file_line, LSIZE, files[depth].fp))
        !          2943:            {
        !          2944:                ++files[depth].lnum;
        !          2945:                break;
        !          2946:            }
        !          2947:            fclose(files[depth].fp);
        !          2948:            --old_files;
        !          2949:            files[old_files].name = files[depth].name;
        !          2950:            files[old_files].matched = files[depth].matched;
        !          2951:            --depth;
        !          2952:            curr_fname = (depth == -1) ? curbuf->b_xfilename
        !          2953:                                       : files[depth].name;
        !          2954:            if (depth < depth_displayed)
        !          2955:                depth_displayed = depth;
        !          2956:        }
        !          2957:        if (depth < 0)
        !          2958:        {
        !          2959:            if (++lnum > end_lnum)
        !          2960:                break;
        !          2961:            line = ml_get(lnum);
        !          2962:        }
        !          2963:    }
        !          2964:    for (i = 0; i <= depth; i++)
        !          2965:    {
        !          2966:        fclose(files[i].fp);
        !          2967:        vim_free(files[i].name);
        !          2968:    }
        !          2969:    for (i = old_files; i < max_path_depth; i++)
        !          2970:        vim_free(files[i].name);
        !          2971:    vim_free(files);
        !          2972:
        !          2973:    if (type == CHECK_PATH)
        !          2974:    {
        !          2975:        if (!did_show)
        !          2976:        {
        !          2977:            if (action != ACTION_SHOW_ALL)
        !          2978:                MSG("All included files were found");
        !          2979:            else
        !          2980:                MSG("No included files");
        !          2981:        }
        !          2982:    }
        !          2983:    else if (!found
        !          2984: #ifdef INSERT_EXPAND
        !          2985:                    && action != ACTION_EXPAND
        !          2986: #endif
        !          2987:                                                )
        !          2988:    {
        !          2989:        if (got_int)
        !          2990:            emsg(e_interr);
        !          2991:        else if (type == FIND_DEFINE)
        !          2992:            EMSG("Couldn't find definition");
        !          2993:        else
        !          2994:            EMSG("Couldn't find pattern");
        !          2995:    }
        !          2996:    if (action == ACTION_SHOW || action == ACTION_SHOW_ALL)
        !          2997:        msg_end();
        !          2998:
        !          2999: fpip_end:
        !          3000:    vim_free(file_line);
        !          3001:    vim_free(prog);
        !          3002:    vim_free(include_prog);
        !          3003:    vim_free(define_prog);
        !          3004: }
        !          3005:
        !          3006:    static void
        !          3007: show_pat_in_path(line, type, did_show, action, fp, lnum, count)
        !          3008:    char_u  *line;
        !          3009:    int     type;
        !          3010:    int     did_show;
        !          3011:    int     action;
        !          3012:    FILE    *fp;
        !          3013:    linenr_t *lnum;
        !          3014:    long    count;
        !          3015: {
        !          3016:    char_u  *p;
        !          3017:
        !          3018:    if (did_show)
        !          3019:        msg_outchar('\n');      /* cursor below last one */
        !          3020:    else
        !          3021:        gotocmdline(TRUE);      /* cursor at status line */
        !          3022:    if (got_int)                /* 'q' typed at "--more--" message */
        !          3023:        return;
        !          3024:    for (;;)
        !          3025:    {
        !          3026:        p = line + STRLEN(line) - 1;
        !          3027:        if (fp != NULL)
        !          3028:        {
        !          3029:            /* We used fgets(), so get rid of newline at end */
        !          3030:            if (p >= line && *p == '\n')
        !          3031:                --p;
        !          3032:            if (p >= line && *p == '\r')
        !          3033:                --p;
        !          3034:            *(p + 1) = NUL;
        !          3035:        }
        !          3036:        if (action == ACTION_SHOW_ALL)
        !          3037:        {
        !          3038:            sprintf((char *)IObuff, "%3ld: ", count);   /* show match nr */
        !          3039:            msg_outstr(IObuff);
        !          3040:            set_highlight('n');                 /* Highlight line numbers */
        !          3041:            start_highlight();
        !          3042:            sprintf((char *)IObuff, "%4ld", *lnum);     /* show line nr */
        !          3043:            msg_outstr(IObuff);
        !          3044:            stop_highlight();
        !          3045:            MSG_OUTSTR(" ");
        !          3046:        }
        !          3047:        msg_prt_line(line);
        !          3048:        flushbuf();                     /* show one line at a time */
        !          3049:
        !          3050:        /* Definition continues until line that doesn't end with '\' */
        !          3051:        if (got_int || type != FIND_DEFINE || p < line || *p != '\\')
        !          3052:            break;
        !          3053:
        !          3054:        if (fp != NULL)
        !          3055:        {
        !          3056:            if (vim_fgets(line, LSIZE, fp)) /* end of file */
        !          3057:                break;
        !          3058:            ++*lnum;
        !          3059:        }
        !          3060:        else
        !          3061:        {
        !          3062:            if (++*lnum > curbuf->b_ml.ml_line_count)
        !          3063:                break;
        !          3064:            line = ml_get(*lnum);
        !          3065:        }
        !          3066:        msg_outchar('\n');
        !          3067:    }
        !          3068: }
        !          3069:
        !          3070: #ifdef VIMINFO
        !          3071:    int
        !          3072: read_viminfo_search_pattern(line, fp, force)
        !          3073:    char_u  *line;
        !          3074:    FILE    *fp;
        !          3075:    int     force;
        !          3076: {
        !          3077:    char_u  *lp;
        !          3078:    char_u  **pattern;
        !          3079:
        !          3080:    lp = line;
        !          3081:    if (lp[0] == '~')
        !          3082:        lp++;
        !          3083:    if (lp[0] == '/')
        !          3084:        pattern = &search_pattern;
        !          3085:    else
        !          3086:        pattern = &subst_pattern;
        !          3087:    if (*pattern != NULL && force)
        !          3088:        vim_free(*pattern);
        !          3089:    if (force || *pattern == NULL)
        !          3090:    {
        !          3091:        viminfo_readstring(lp);
        !          3092:        *pattern = strsave(lp + 1);
        !          3093:        if (line[0] == '~')
        !          3094:            last_pattern = *pattern;
        !          3095:    }
        !          3096:    return vim_fgets(line, LSIZE, fp);
        !          3097: }
        !          3098:
        !          3099:    void
        !          3100: write_viminfo_search_pattern(fp)
        !          3101:    FILE    *fp;
        !          3102: {
        !          3103:    if (get_viminfo_parameter('/') != 0)
        !          3104:    {
        !          3105:        if (search_pattern != NULL)
        !          3106:        {
        !          3107:            fprintf(fp, "\n# Last Search Pattern:\n");
        !          3108:            fprintf(fp, "%s/", (last_pattern == search_pattern) ? "~" : "");
        !          3109:            viminfo_writestring(fp, search_pattern);
        !          3110:        }
        !          3111:        if (subst_pattern != NULL)
        !          3112:        {
        !          3113:            fprintf(fp, "\n# Last Substitute Search Pattern:\n");
        !          3114:            fprintf(fp, "%s&", (last_pattern == subst_pattern) ? "~" : "");
        !          3115:            viminfo_writestring(fp, subst_pattern);
        !          3116:        }
        !          3117:    }
        !          3118: }
        !          3119: #endif /* VIMINFO */
        !          3120:
        !          3121: /*
        !          3122:  * Give a warning message.
        !          3123:  * Use 'w' highlighting and may repeat the message after redrawing
        !          3124:  */
        !          3125:    static void
        !          3126: give_warning(message)
        !          3127:    char_u  *message;
        !          3128: {
        !          3129:    (void)set_highlight('w');
        !          3130:    msg_highlight = TRUE;
        !          3131:    if (msg(message) && !msg_scroll)
        !          3132:    {
        !          3133:        keep_msg = message;
        !          3134:        keep_msg_highlight = 'w';
        !          3135:    }
        !          3136:    msg_didout = FALSE;     /* overwrite this message */
        !          3137:    msg_col = 0;
        !          3138: }