home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / search.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-18  |  103.3 KB  |  4,387 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9. /*
  10.  * search.c: code for normal mode searching commands
  11.  */
  12.  
  13. #include "vim.h"
  14.  
  15. static void save_re_pat __ARGS((int idx, char_u *pat, int magic));
  16. #ifdef FEAT_EVAL
  17. static int first_submatch __ARGS((regmmatch_T *rp));
  18. #endif
  19. static int inmacro __ARGS((char_u *, char_u *));
  20. static int check_linecomment __ARGS((char_u *line));
  21. static int cls __ARGS((void));
  22. static int skip_chars __ARGS((int, int));
  23. #ifdef FEAT_TEXTOBJ
  24. static void back_in_line __ARGS((void));
  25. static void find_first_blank __ARGS((pos_T *));
  26. static void findsent_forward __ARGS((long count, int at_start_sent));
  27. #endif
  28. #ifdef FEAT_FIND_ID
  29. static void show_pat_in_path __ARGS((char_u *, int,
  30.                      int, int, FILE *, linenr_T *, long));
  31. #endif
  32. #ifdef FEAT_VIMINFO
  33. static void wvsp_one __ARGS((FILE *fp, int idx, char *s, int sc));
  34. #endif
  35.  
  36. static char_u *top_bot_msg = (char_u *)N_("search hit TOP, continuing at BOTTOM");
  37. static char_u *bot_top_msg = (char_u *)N_("search hit BOTTOM, continuing at TOP");
  38.  
  39. /*
  40.  * This file contains various searching-related routines. These fall into
  41.  * three groups:
  42.  * 1. string searches (for /, ?, n, and N)
  43.  * 2. character searches within a single line (for f, F, t, T, etc)
  44.  * 3. "other" kinds of searches like the '%' command, and 'word' searches.
  45.  */
  46.  
  47. /*
  48.  * String searches
  49.  *
  50.  * The string search functions are divided into two levels:
  51.  * lowest:  searchit(); uses an pos_T for starting position and found match.
  52.  * Highest: do_search(); uses curwin->w_cursor; calls searchit().
  53.  *
  54.  * The last search pattern is remembered for repeating the same search.
  55.  * This pattern is shared between the :g, :s, ? and / commands.
  56.  * This is in search_regcomp().
  57.  *
  58.  * The actual string matching is done using a heavily modified version of
  59.  * Henry Spencer's regular expression library.  See regexp.c.
  60.  */
  61.  
  62. /* The offset for a search command is store in a soff struct */
  63. /* Note: only spats[0].off is really used */
  64. struct soffset
  65. {
  66.     int        dir;        /* search direction */
  67.     int        line;        /* search has line offset */
  68.     int        end;        /* search set cursor at end */
  69.     long    off;        /* line or char offset */
  70. };
  71.  
  72. /* A search pattern and its attributes are stored in a spat struct */
  73. struct spat
  74. {
  75.     char_u        *pat;    /* the pattern (in allocated memory) or NULL */
  76.     int            magic;    /* magicness of the pattern */
  77.     int            no_scs;    /* no smarcase for this pattern */
  78.     struct soffset  off;
  79. };
  80.  
  81. /*
  82.  * Two search patterns are remembered: One for the :substitute command and
  83.  * one for other searches.  last_idx points to the one that was used the last
  84.  * time.
  85.  */
  86. static struct spat spats[2] =
  87. {
  88.     {NULL, TRUE, FALSE, {'/', 0, 0, 0L}},    /* last used search pat */
  89.     {NULL, TRUE, FALSE, {'/', 0, 0, 0L}}    /* last used substitute pat */
  90. };
  91.  
  92. static int last_idx = 0;    /* index in spats[] for RE_LAST */
  93.  
  94. #if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)
  95. /* copy of spats[], for keeping the search patterns while executing autocmds */
  96. static struct spat  saved_spats[2];
  97. static int        saved_last_idx = 0;
  98. # ifdef FEAT_SEARCH_EXTRA
  99. static int        saved_no_hlsearch = 0;
  100. # endif
  101. #endif
  102.  
  103. static char_u        *mr_pattern = NULL;    /* pattern used by search_regcomp() */
  104. #ifdef FEAT_RIGHTLEFT
  105. static int        mr_pattern_alloced = FALSE; /* mr_pattern was allocated */
  106. static char_u        *reverse_text __ARGS((char_u *s));
  107. #endif
  108.  
  109. #ifdef FEAT_FIND_ID
  110. /*
  111.  * Type used by find_pattern_in_path() to remember which included files have
  112.  * been searched already.
  113.  */
  114. typedef struct SearchedFile
  115. {
  116.     FILE    *fp;        /* File pointer */
  117.     char_u    *name;        /* Full name of file */
  118.     linenr_T    lnum;        /* Line we were up to in file */
  119.     int        matched;    /* Found a match in this file */
  120. } SearchedFile;
  121. #endif
  122.  
  123. /*
  124.  * translate search pattern for vim_regcomp()
  125.  *
  126.  * pat_save == RE_SEARCH: save pat in spats[RE_SEARCH].pat (normal search cmd)
  127.  * pat_save == RE_SUBST: save pat in spats[RE_SUBST].pat (:substitute command)
  128.  * pat_save == RE_BOTH: save pat in both patterns (:global command)
  129.  * pat_use  == RE_SEARCH: use previous search pattern if "pat" is NULL
  130.  * pat_use  == RE_SUBST: use previous sustitute pattern if "pat" is NULL
  131.  * pat_use  == RE_LAST: use last used pattern if "pat" is NULL
  132.  * options & SEARCH_HIS: put search string in history
  133.  * options & SEARCH_KEEP: keep previous search pattern
  134.  *
  135.  * returns FAIL if failed, OK otherwise.
  136.  */
  137.     int
  138. search_regcomp(pat, pat_save, pat_use, options, regmatch)
  139.     char_u    *pat;
  140.     int        pat_save;
  141.     int        pat_use;
  142.     int        options;
  143.     regmmatch_T    *regmatch;    /* return: pattern and ignore-case flag */
  144. {
  145.     int        magic;
  146.     int        i;
  147.  
  148.     rc_did_emsg = FALSE;
  149.     magic = p_magic;
  150.  
  151.     /*
  152.      * If no pattern given, use a previously defined pattern.
  153.      */
  154.     if (pat == NULL || *pat == NUL)
  155.     {
  156.     if (pat_use == RE_LAST)
  157.         i = last_idx;
  158.     else
  159.         i = pat_use;
  160.     if (spats[i].pat == NULL)    /* pattern was never defined */
  161.     {
  162.         if (pat_use == RE_SUBST)
  163.         EMSG(_(e_nopresub));
  164.         else
  165.         EMSG(_(e_noprevre));
  166.         rc_did_emsg = TRUE;
  167.         return FAIL;
  168.     }
  169.     pat = spats[i].pat;
  170.     magic = spats[i].magic;
  171.     no_smartcase = spats[i].no_scs;
  172.     }
  173. #ifdef FEAT_CMDHIST
  174.     else if (options & SEARCH_HIS)    /* put new pattern in history */
  175.     add_to_history(HIST_SEARCH, pat, TRUE);
  176. #endif
  177.  
  178. #ifdef FEAT_RIGHTLEFT
  179.     if (mr_pattern_alloced)
  180.     {
  181.     vim_free(mr_pattern);
  182.     mr_pattern_alloced = FALSE;
  183.     }
  184.  
  185.     if (curwin->w_p_rl && *curwin->w_p_rlc == 's')
  186.     {
  187.     char_u *rev_pattern;
  188.  
  189.     rev_pattern = reverse_text(pat);
  190.     if (rev_pattern == NULL)
  191.         mr_pattern = pat;        /* out of memory, keep normal pattern. */
  192.     else
  193.     {
  194.         mr_pattern = rev_pattern;
  195.         mr_pattern_alloced = TRUE;
  196.     }
  197.     }
  198.     else
  199. #endif
  200.     mr_pattern = pat;
  201.  
  202.     /*
  203.      * Save the currently used pattern in the appropriate place,
  204.      * unless the pattern should not be remembered.
  205.      */
  206.     if (!(options & SEARCH_KEEP))
  207.     {
  208.     /* search or global command */
  209.     if (pat_save == RE_SEARCH || pat_save == RE_BOTH)
  210.         save_re_pat(RE_SEARCH, pat, magic);
  211.     /* substitute or global command */
  212.     if (pat_save == RE_SUBST || pat_save == RE_BOTH)
  213.         save_re_pat(RE_SUBST, pat, magic);
  214.     }
  215.  
  216.     regmatch->rmm_ic = ignorecase(pat);
  217.     regmatch->regprog = vim_regcomp(pat, magic ? RE_MAGIC : 0);
  218.     if (regmatch->regprog == NULL)
  219.     return FAIL;
  220.     return OK;
  221. }
  222.  
  223. /*
  224.  * Get search pattern used by search_regcomp().
  225.  */
  226.     char_u *
  227. get_search_pat()
  228. {
  229.     return mr_pattern;
  230. }
  231.  
  232. #ifdef FEAT_RIGHTLEFT
  233. /*
  234.  * Reverse text into allocated memory.
  235.  * Returns the allocated string, NULL when out of memory.
  236.  */
  237.     static char_u *
  238. reverse_text(s)
  239.     char_u *s;
  240. {
  241.     unsigned    len;
  242.     unsigned    s_i, rev_i;
  243.     char_u    *rev;
  244.  
  245.     /*
  246.      * Reverse the pattern.
  247.      */
  248.     len = (unsigned)STRLEN(s);
  249.     rev = alloc(len + 1);
  250.     if (rev != NULL)
  251.     {
  252.     rev_i = len;
  253.     for (s_i = 0; s_i < len; ++s_i)
  254.     {
  255. # ifdef FEAT_MBYTE
  256.         if (has_mbyte)
  257.         {
  258.         int    mb_len;
  259.  
  260.         mb_len = (*mb_ptr2len_check)(s + s_i);
  261.         rev_i -= mb_len;
  262.         mch_memmove(rev + rev_i, s + s_i, mb_len);
  263.         s_i += mb_len - 1;
  264.         }
  265.         else
  266. # endif
  267.         rev[--rev_i] = s[s_i];
  268.  
  269.     }
  270.     rev[len] = NUL;
  271.     }
  272.     return rev;
  273. }
  274. #endif
  275.  
  276.     static void
  277. save_re_pat(idx, pat, magic)
  278.     int        idx;
  279.     char_u    *pat;
  280.     int        magic;
  281. {
  282.     if (spats[idx].pat != pat)
  283.     {
  284.     vim_free(spats[idx].pat);
  285.     spats[idx].pat = vim_strsave(pat);
  286.     spats[idx].magic = magic;
  287.     spats[idx].no_scs = no_smartcase;
  288.     last_idx = idx;
  289. #ifdef FEAT_SEARCH_EXTRA
  290.     /* If 'hlsearch' set and search pat changed: need redraw. */
  291.     if (p_hls)
  292.         redraw_all_later(NOT_VALID);
  293.     no_hlsearch = FALSE;
  294. #endif
  295.     }
  296. }
  297.  
  298. #if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)
  299. /*
  300.  * Save the search patterns, so they can be restored later.
  301.  * Used before/after executing autocommands and user functions.
  302.  */
  303. static int save_level = 0;
  304.  
  305.     void
  306. save_search_patterns()
  307. {
  308.     if (save_level++ == 0)
  309.     {
  310.     saved_spats[0] = spats[0];
  311.     if (spats[0].pat != NULL)
  312.         saved_spats[0].pat = vim_strsave(spats[0].pat);
  313.     saved_spats[1] = spats[1];
  314.     if (spats[1].pat != NULL)
  315.         saved_spats[1].pat = vim_strsave(spats[1].pat);
  316.     saved_last_idx = last_idx;
  317. # ifdef FEAT_SEARCH_EXTRA
  318.     saved_no_hlsearch = no_hlsearch;
  319. # endif
  320.     }
  321. }
  322.  
  323.     void
  324. restore_search_patterns()
  325. {
  326.     if (--save_level == 0)
  327.     {
  328.     vim_free(spats[0].pat);
  329.     spats[0] = saved_spats[0];
  330.     vim_free(spats[1].pat);
  331.     spats[1] = saved_spats[1];
  332.     last_idx = saved_last_idx;
  333. # ifdef FEAT_SEARCH_EXTRA
  334.     no_hlsearch = saved_no_hlsearch;
  335. # endif
  336.     }
  337. }
  338. #endif
  339.  
  340. /*
  341.  * Return TRUE when case should be ignored for search pattern "pat".
  342.  * Uses the 'ignorecase' and 'smartcase' options.
  343.  */
  344.     int
  345. ignorecase(pat)
  346.     char_u    *pat;
  347. {
  348.     char_u    *p;
  349.     int        ic;
  350.  
  351.     ic = p_ic;
  352.     if (ic && !no_smartcase && p_scs
  353. #ifdef FEAT_INS_EXPAND
  354.                 && !(ctrl_x_mode && curbuf->b_p_inf)
  355. #endif
  356.                                     )
  357.     {
  358.     /* don't ignore case if pattern has uppercase */
  359.     for (p = pat; *p; )
  360.     {
  361. #ifdef FEAT_MBYTE
  362.         int        l;
  363.  
  364.         if (has_mbyte && (l = (*mb_ptr2len_check)(p)) > 1)
  365.         {
  366.         if (enc_utf8 && utf_isupper(utf_ptr2char(p)))
  367.         {
  368.             ic = FALSE;
  369.             break;
  370.         }
  371.         p += l;
  372.         }
  373.         else
  374. #endif
  375.         if (*p == '\\' && p[1] != NUL)    /* skip "\S" et al. */
  376.             p += 2;
  377.         else if (isupper(*p++))
  378.         {
  379.             ic = FALSE;
  380.             break;
  381.         }
  382.     }
  383.     }
  384.     no_smartcase = FALSE;
  385.  
  386.     return ic;
  387. }
  388.  
  389.     char_u *
  390. last_search_pat()
  391. {
  392.     return spats[last_idx].pat;
  393. }
  394.  
  395. /*
  396.  * Reset search direction to forward.  For "gd" and "gD" commands.
  397.  */
  398.     void
  399. reset_search_dir()
  400. {
  401.     spats[0].off.dir = '/';
  402. }
  403.  
  404. #if defined(FEAT_EVAL) || defined(FEAT_VIMINFO)
  405. /*
  406.  * Set the last search pattern.  For ":let @/ =" and viminfo.
  407.  * Also set the saved search pattern, so that this works in an autocommand.
  408.  */
  409.     void
  410. set_last_search_pat(s, idx, magic, setlast)
  411.     char_u    *s;
  412.     int        idx;
  413.     int        magic;
  414.     int        setlast;
  415. {
  416.     vim_free(spats[idx].pat);
  417.     /* An empty string means that nothing should be matched. */
  418.     if (*s == NUL)
  419.     spats[idx].pat = NULL;
  420.     else
  421.     spats[idx].pat = vim_strsave(s);
  422.     spats[idx].magic = magic;
  423.     spats[idx].no_scs = FALSE;
  424.     spats[idx].off.dir = '/';
  425.     spats[idx].off.line = FALSE;
  426.     spats[idx].off.end = FALSE;
  427.     spats[idx].off.off = 0;
  428.     if (setlast)
  429.     last_idx = idx;
  430.     if (save_level)
  431.     {
  432.     vim_free(saved_spats[idx].pat);
  433.     saved_spats[idx] = spats[0];
  434.     if (spats[idx].pat == NULL)
  435.         saved_spats[idx].pat = NULL;
  436.     else
  437.         saved_spats[idx].pat = vim_strsave(spats[idx].pat);
  438.     saved_last_idx = last_idx;
  439.     }
  440. # ifdef FEAT_SEARCH_EXTRA
  441.     /* If 'hlsearch' set and search pat changed: need redraw. */
  442.     if (p_hls && idx == last_idx && !no_hlsearch)
  443.     redraw_all_later(NOT_VALID);
  444. # endif
  445. }
  446. #endif
  447.  
  448. #ifdef FEAT_SEARCH_EXTRA
  449. /*
  450.  * Get a regexp program for the last used search pattern.
  451.  * This is used for highlighting all matches in a window.
  452.  * Values returned in regmatch->regprog and regmatch->rmm_ic.
  453.  */
  454.     void
  455. last_pat_prog(regmatch)
  456.     regmmatch_T    *regmatch;
  457. {
  458.     if (spats[last_idx].pat == NULL)
  459.     {
  460.     regmatch->regprog = NULL;
  461.     return;
  462.     }
  463.     ++emsg_off;        /* So it doesn't beep if bad expr */
  464.     (void)search_regcomp((char_u *)"", 0, last_idx, SEARCH_KEEP, regmatch);
  465.     --emsg_off;
  466. }
  467. #endif
  468.  
  469. /*
  470.  * lowest level search function.
  471.  * Search for 'count'th occurrence of pattern 'pat' in direction 'dir'.
  472.  * Start at position 'pos' and return the found position in 'pos'.
  473.  *
  474.  * if (options & SEARCH_MSG) == 0 don't give any messages
  475.  * if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages
  476.  * if (options & SEARCH_MSG) == SEARCH_MSG give all messages
  477.  * if (options & SEARCH_HIS) put search pattern in history
  478.  * if (options & SEARCH_END) return position at end of match
  479.  * if (options & SEARCH_START) accept match at pos itself
  480.  * if (options & SEARCH_KEEP) keep previous search pattern
  481.  * if (options & SEARCH_FOLD) match only once in a closed fold
  482.  * if (options & SEARCH_PEEK) check for typed char, cancel search
  483.  *
  484.  * Return FAIL (zero) for failure, non-zero for success.
  485.  * When FEAT_EVAL is defined, returns the index of the first matching
  486.  * subpattern plus one; one if there was none.
  487.  */
  488.     int
  489. searchit(win, buf, pos, dir, pat, count, options, pat_use)
  490.     win_T    *win;        /* window to search in; can be NULL for a
  491.                    buffer without a window! */
  492.     buf_T    *buf;
  493.     pos_T    *pos;
  494.     int        dir;
  495.     char_u    *pat;
  496.     long    count;
  497.     int        options;
  498.     int        pat_use;
  499. {
  500.     int        found;
  501.     linenr_T    lnum;        /* no init to shut up Apollo cc */
  502.     regmmatch_T    regmatch;
  503.     char_u    *ptr;
  504.     colnr_T    matchcol;
  505.     colnr_T    startcol;
  506.     lpos_T    endpos;
  507.     int        loop;
  508.     pos_T    start_pos;
  509.     int        at_first_line;
  510.     int        extra_col;
  511.     int        match_ok;
  512.     long    nmatched;
  513.     int        submatch = 0;
  514.     linenr_T    first_lnum;
  515. #ifdef FEAT_SEARCH_EXTRA
  516.     int        break_loop = FALSE;
  517. #else
  518. # define break_loop FALSE
  519. #endif
  520.  
  521.     if (search_regcomp(pat, RE_SEARCH, pat_use,
  522.            (options & (SEARCH_HIS + SEARCH_KEEP)), ®match) == FAIL)
  523.     {
  524.     if ((options & SEARCH_MSG) && !rc_did_emsg)
  525.         EMSG2(_("E383: Invalid search string: %s"), mr_pattern);
  526.     return FAIL;
  527.     }
  528.  
  529.     if (options & SEARCH_START)
  530.     extra_col = 0;
  531. #ifdef FEAT_MBYTE
  532.     /* Watch out for the "col" being MAXCOL - 2, used in a closed fold. */
  533.     else if (has_mbyte && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count
  534.                              && pos->col < MAXCOL - 2)
  535.     extra_col = (*mb_ptr2len_check)(ml_get_buf(buf, pos->lnum, FALSE)
  536.                                   + pos->col);
  537. #endif
  538.     else
  539.     extra_col = 1;
  540.  
  541. /*
  542.  * find the string
  543.  */
  544.     called_emsg = FALSE;
  545.     do    /* loop for count */
  546.     {
  547.     start_pos = *pos;    /* remember start pos for detecting no match */
  548.     found = 0;        /* default: not found */
  549.     at_first_line = TRUE;    /* default: start in first line */
  550.     if (pos->lnum == 0)    /* correct lnum for when starting in line 0 */
  551.     {
  552.         pos->lnum = 1;
  553.         pos->col = 0;
  554.         at_first_line = FALSE;  /* not in first line now */
  555.     }
  556.  
  557.     /*
  558.      * Start searching in current line, unless searching backwards and
  559.      * we're in column 0.
  560.      */
  561.     if (dir == BACKWARD && start_pos.col == 0)
  562.     {
  563.         lnum = pos->lnum - 1;
  564.         at_first_line = FALSE;
  565.     }
  566.     else
  567.         lnum = pos->lnum;
  568.  
  569.     for (loop = 0; loop <= 1; ++loop)   /* loop twice if 'wrapscan' set */
  570.     {
  571.         for ( ; lnum > 0 && lnum <= buf->b_ml.ml_line_count;
  572.                        lnum += dir, at_first_line = FALSE)
  573.         {
  574.         /*
  575.          * Look for a match somewhere in the line.
  576.          */
  577.         first_lnum = lnum;
  578.         nmatched = vim_regexec_multi(®match, win, buf,
  579.                                 lnum, (colnr_T)0);
  580.         /* Abort searching on an error (e.g., out of stack). */
  581.         if (called_emsg)
  582.             break;
  583.         if (nmatched > 0)
  584.         {
  585.             /* match may actually be in another line when using \zs */
  586.             lnum += regmatch.startpos[0].lnum;
  587.             ptr = ml_get_buf(buf, lnum, FALSE);
  588.             startcol = regmatch.startpos[0].col;
  589.             endpos = regmatch.endpos[0];
  590. # ifdef FEAT_EVAL
  591.             submatch = first_submatch(®match);
  592. # endif
  593.  
  594.             /*
  595.              * Forward search in the first line: match should be after
  596.              * the start position. If not, continue at the end of the
  597.              * match (this is vi compatible) or on the next char.
  598.              */
  599.             if (dir == FORWARD && at_first_line)
  600.             {
  601.             match_ok = TRUE;
  602.             /*
  603.              * When match lands on a NUL the cursor will be put
  604.              * one back afterwards, compare with that position,
  605.              * otherwise "/$" will get stuck on end of line.
  606.              */
  607.             while ((options & SEARCH_END)
  608.                 ?  (nmatched == 1
  609.                     && (int)endpos.col - 1
  610.                          < (int)start_pos.col + extra_col)
  611.                 : ((int)startcol - (ptr[startcol] == NUL)
  612.                         < (int)start_pos.col + extra_col))
  613.             {
  614.                 /*
  615.                  * If vi-compatible searching, continue at the end
  616.                  * of the match, otherwise continue one position
  617.                  * forward.
  618.                  */
  619.                 if (vim_strchr(p_cpo, CPO_SEARCH) != NULL)
  620.                 {
  621.                 if (nmatched > 1)
  622.                 {
  623.                     /* end is in next line, thus no match in
  624.                      * this line */
  625.                     match_ok = FALSE;
  626.                     break;
  627.                 }
  628.                 matchcol = endpos.col;
  629.                 /* for empty match: advance one char */
  630.                 if (matchcol == startcol
  631.                               && ptr[matchcol] != NUL)
  632.                 {
  633. #ifdef FEAT_MBYTE
  634.                     if (has_mbyte)
  635.                     matchcol +=
  636.                       (*mb_ptr2len_check)(ptr + matchcol);
  637.                     else
  638. #endif
  639.                     ++matchcol;
  640.                 }
  641.                 }
  642.                 else
  643.                 {
  644.                 matchcol = startcol;
  645.                 if (ptr[matchcol] != NUL)
  646.                 {
  647. #ifdef FEAT_MBYTE
  648.                     if (has_mbyte)
  649.                     matchcol += (*mb_ptr2len_check)(ptr
  650.                                   + matchcol);
  651.                     else
  652. #endif
  653.                     ++matchcol;
  654.                 }
  655.                 }
  656.                 if (ptr[matchcol] == NUL
  657.                     || (nmatched = vim_regexec_multi(®match,
  658.                           win, buf, lnum, matchcol)) == 0)
  659.                 {
  660.                 match_ok = FALSE;
  661.                 break;
  662.                 }
  663.                 startcol = regmatch.startpos[0].col;
  664.                 endpos = regmatch.endpos[0];
  665. # ifdef FEAT_EVAL
  666.                 submatch = first_submatch(®match);
  667. # endif
  668.  
  669.                 /* Need to get the line pointer again, a
  670.                  * multi-line search may have made it invalid. */
  671.                 ptr = ml_get_buf(buf, lnum, FALSE);
  672.             }
  673.             if (!match_ok)
  674.                 continue;
  675.             }
  676.             if (dir == BACKWARD)
  677.             {
  678.             /*
  679.              * Now, if there are multiple matches on this line,
  680.              * we have to get the last one. Or the last one before
  681.              * the cursor, if we're on that line.
  682.              * When putting the new cursor at the end, compare
  683.              * relative to the end of the match.
  684.              */
  685.             match_ok = FALSE;
  686.             for (;;)
  687.             {
  688.                 if (!at_first_line
  689.                     || ((options & SEARCH_END)
  690.                     ?  (nmatched == 1
  691.                         && (int)regmatch.endpos[0].col - 1
  692.                                    + extra_col
  693.                             <= (int)start_pos.col)
  694.                     : ((int)regmatch.startpos[0].col
  695.                                    + extra_col
  696.                               <= (int)start_pos.col)))
  697.                 {
  698.                 /* Remember this position, we use it if it's
  699.                  * the last match in the line. */
  700.                 match_ok = TRUE;
  701.                 startcol = regmatch.startpos[0].col;
  702.                 endpos = regmatch.endpos[0];
  703. # ifdef FEAT_EVAL
  704.                 submatch = first_submatch(®match);
  705. # endif
  706.                 }
  707.                 else
  708.                 break;
  709.  
  710.                 /*
  711.                  * We found a valid match, now check if there is
  712.                  * another one after it.
  713.                  * If vi-compatible searching, continue at the end
  714.                  * of the match, otherwise continue one position
  715.                  * forward.
  716.                  */
  717.                 if (vim_strchr(p_cpo, CPO_SEARCH) != NULL)
  718.                 {
  719.                 if (nmatched > 1)
  720.                     break;
  721.                 matchcol = endpos.col;
  722.                 /* for empty match: advance one char */
  723.                 if (matchcol == startcol
  724.                               && ptr[matchcol] != NUL)
  725.                 {
  726. #ifdef FEAT_MBYTE
  727.                     if (has_mbyte)
  728.                     matchcol +=
  729.                       (*mb_ptr2len_check)(ptr + matchcol);
  730.                     else
  731. #endif
  732.                     ++matchcol;
  733.                 }
  734.                 }
  735.                 else
  736.                 {
  737.                 matchcol = startcol;
  738.                 if (ptr[matchcol] != NUL)
  739.                 {
  740. #ifdef FEAT_MBYTE
  741.                     if (has_mbyte)
  742.                     matchcol +=
  743.                       (*mb_ptr2len_check)(ptr + matchcol);
  744.                     else
  745. #endif
  746.                     ++matchcol;
  747.                 }
  748.                 }
  749.                 if (ptr[matchcol] == NUL
  750.                     || (nmatched = vim_regexec_multi(®match,
  751.                           win, buf, lnum, matchcol)) == 0)
  752.                 break;
  753.  
  754.                 /* Need to get the line pointer again, a
  755.                  * multi-line search may have made it invalid. */
  756.                 ptr = ml_get_buf(buf, lnum, FALSE);
  757.             }
  758.  
  759.             /*
  760.              * If there is only a match after the cursor, skip
  761.              * this match.
  762.              */
  763.             if (!match_ok)
  764.                 continue;
  765.             }
  766.  
  767.             if (options & SEARCH_END && !(options & SEARCH_NOOF))
  768.             {
  769.             pos->lnum = endpos.lnum + first_lnum;
  770.             pos->col = endpos.col - 1;
  771.             }
  772.             else
  773.             {
  774.             pos->lnum = lnum;
  775.             pos->col = startcol;
  776.             }
  777. #ifdef FEAT_VIRTUALEDIT
  778.             pos->coladd = 0;
  779. #endif
  780.             found = 1;
  781.  
  782.             /* Set variables used for 'incsearch' highlighting. */
  783.             search_match_lines = endpos.lnum - (lnum - first_lnum);
  784.             search_match_endcol = endpos.col;
  785.             break;
  786.         }
  787.         line_breakcheck();    /* stop if ctrl-C typed */
  788.         if (got_int)
  789.             break;
  790.  
  791. #ifdef FEAT_SEARCH_EXTRA
  792.         /* Cancel searching if a character was typed.  Used for
  793.          * 'incsearch'.  Don't check too often, that would slowdown
  794.          * searching too much. */
  795.         if ((options & SEARCH_PEEK)
  796.             && ((lnum - pos->lnum) & 0x3f) == 0
  797.             && char_avail())
  798.         {
  799.             break_loop = TRUE;
  800.             break;
  801.         }
  802. #endif
  803.  
  804.         if (loop && lnum == start_pos.lnum)
  805.             break;        /* if second loop, stop where started */
  806.         }
  807.         at_first_line = FALSE;
  808.  
  809.         /*
  810.          * stop the search if wrapscan isn't set, after an interrupt and
  811.          * after a match
  812.          */
  813.         if (!p_ws || got_int || called_emsg || break_loop || found)
  814.         break;
  815.  
  816.         /*
  817.          * If 'wrapscan' is set we continue at the other end of the file.
  818.          * If 'shortmess' does not contain 's', we give a message.
  819.          * This message is also remembered in keep_msg for when the screen
  820.          * is redrawn. The keep_msg is cleared whenever another message is
  821.          * written.
  822.          */
  823.         if (dir == BACKWARD)    /* start second loop at the other end */
  824.         {
  825.         lnum = buf->b_ml.ml_line_count;
  826.         if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
  827.             give_warning((char_u *)_(top_bot_msg), TRUE);
  828.         }
  829.         else
  830.         {
  831.         lnum = 1;
  832.         if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
  833.             give_warning((char_u *)_(bot_top_msg), TRUE);
  834.         }
  835.     }
  836.     if (got_int || called_emsg || break_loop)
  837.         break;
  838.     }
  839.     while (--count > 0 && found);   /* stop after count matches or no match */
  840.  
  841.     vim_free(regmatch.regprog);
  842.  
  843.     if (!found)            /* did not find it */
  844.     {
  845.     if (got_int)
  846.         EMSG(_(e_interr));
  847.     else if ((options & SEARCH_MSG) == SEARCH_MSG)
  848.     {
  849.         if (p_ws)
  850.         EMSG2(_(e_patnotf2), mr_pattern);
  851.         else if (lnum == 0)
  852.         EMSG2(_("E384: search hit TOP without match for: %s"),
  853.                                   mr_pattern);
  854.         else
  855.         EMSG2(_("E385: search hit BOTTOM without match for: %s"),
  856.                                   mr_pattern);
  857.     }
  858.     return FAIL;
  859.     }
  860.  
  861.     return submatch + 1;
  862. }
  863.  
  864. #ifdef FEAT_EVAL
  865. /*
  866.  * Return the number of the first subpat that matched.
  867.  */
  868.     static int
  869. first_submatch(rp)
  870.     regmmatch_T    *rp;
  871. {
  872.     int        submatch;
  873.  
  874.     for (submatch = 1; ; ++submatch)
  875.     {
  876.     if (rp->startpos[submatch].lnum >= 0)
  877.         break;
  878.     if (submatch == 9)
  879.     {
  880.         submatch = 0;
  881.         break;
  882.     }
  883.     }
  884.     return submatch;
  885. }
  886. #endif
  887.  
  888. /*
  889.  * Highest level string search function.
  890.  * Search for the 'count'th occurence of pattern 'pat' in direction 'dirc'
  891.  *          If 'dirc' is 0: use previous dir.
  892.  *    If 'pat' is NULL or empty : use previous string.
  893.  *    If 'options & SEARCH_REV' : go in reverse of previous dir.
  894.  *    If 'options & SEARCH_ECHO': echo the search command and handle options
  895.  *    If 'options & SEARCH_MSG' : may give error message
  896.  *    If 'options & SEARCH_OPT' : interpret optional flags
  897.  *    If 'options & SEARCH_HIS' : put search pattern in history
  898.  *    If 'options & SEARCH_NOOF': don't add offset to position
  899.  *    If 'options & SEARCH_MARK': set previous context mark
  900.  *    If 'options & SEARCH_KEEP': keep previous search pattern
  901.  *    If 'options & SEARCH_START': accept match at curpos itself
  902.  *    If 'options & SEARCH_PEEK': check for typed char, cancel search
  903.  *
  904.  * Careful: If spats[0].off.line == TRUE and spats[0].off.off == 0 this
  905.  * makes the movement linewise without moving the match position.
  906.  *
  907.  * return 0 for failure, 1 for found, 2 for found and line offset added
  908.  */
  909.     int
  910. do_search(oap, dirc, pat, count, options)
  911.     oparg_T        *oap;    /* can be NULL */
  912.     int            dirc;    /* '/' or '?' */
  913.     char_u       *pat;
  914.     long        count;
  915.     int            options;
  916. {
  917.     pos_T        pos;    /* position of the last match */
  918.     char_u        *searchstr;
  919.     struct soffset  old_off;
  920.     int            retval;    /* Return value */
  921.     char_u        *p;
  922.     long        c;
  923.     char_u        *dircp;
  924.     char_u        *strcopy = NULL;
  925.     char_u        *ps;
  926.  
  927.     /*
  928.      * A line offset is not remembered, this is vi compatible.
  929.      */
  930.     if (spats[0].off.line && vim_strchr(p_cpo, CPO_LINEOFF) != NULL)
  931.     {
  932.     spats[0].off.line = FALSE;
  933.     spats[0].off.off = 0;
  934.     }
  935.  
  936.     /*
  937.      * Save the values for when (options & SEARCH_KEEP) is used.
  938.      * (there is no "if ()" around this because gcc wants them initialized)
  939.      */
  940.     old_off = spats[0].off;
  941.  
  942.     pos = curwin->w_cursor;    /* start searching at the cursor position */
  943.  
  944.     /*
  945.      * Find out the direction of the search.
  946.      */
  947.     if (dirc == 0)
  948.     dirc = spats[0].off.dir;
  949.     else
  950.     spats[0].off.dir = dirc;
  951.     if (options & SEARCH_REV)
  952.     {
  953. #ifdef WIN32
  954.     /* There is a bug in the Visual C++ 2.2 compiler which means that
  955.      * dirc always ends up being '/' */
  956.     dirc = (dirc == '/')  ?  '?'  :  '/';
  957. #else
  958.     if (dirc == '/')
  959.         dirc = '?';
  960.     else
  961.         dirc = '/';
  962. #endif
  963.     }
  964.  
  965. #ifdef FEAT_FOLDING
  966.     /* If the cursor is in a closed fold, don't find another match in the same
  967.      * fold. */
  968.     if (dirc == '/')
  969.     {
  970.     if (hasFolding(pos.lnum, NULL, &pos.lnum))
  971.         pos.col = MAXCOL - 2;    /* avoid overflow when adding 1 */
  972.     }
  973.     else
  974.     {
  975.     if (hasFolding(pos.lnum, &pos.lnum, NULL))
  976.         pos.col = 0;
  977.     }
  978. #endif
  979.  
  980. #ifdef FEAT_SEARCH_EXTRA
  981.     /*
  982.      * Turn 'hlsearch' highlighting back on.
  983.      */
  984.     if (no_hlsearch && !(options & SEARCH_KEEP))
  985.     {
  986.     redraw_all_later(NOT_VALID);
  987.     no_hlsearch = FALSE;
  988.     }
  989. #endif
  990.  
  991.     /*
  992.      * Repeat the search when pattern followed by ';', e.g. "/foo/;?bar".
  993.      */
  994.     for (;;)
  995.     {
  996.     searchstr = pat;
  997.     dircp = NULL;
  998.                         /* use previous pattern */
  999.     if (pat == NULL || *pat == NUL || *pat == dirc)
  1000.     {
  1001.         if (spats[RE_SEARCH].pat == NULL)        /* no previous pattern */
  1002.         {
  1003.         EMSG(_(e_noprevre));
  1004.         retval = 0;
  1005.         goto end_do_search;
  1006.         }
  1007.         /* make search_regcomp() use spats[RE_SEARCH].pat */
  1008.         searchstr = (char_u *)"";
  1009.     }
  1010.  
  1011.     if (pat != NULL && *pat != NUL)    /* look for (new) offset */
  1012.     {
  1013.         /*
  1014.          * Find end of regular expression.
  1015.          * If there is a matching '/' or '?', toss it.
  1016.          */
  1017.         ps = strcopy;
  1018.         p = skip_regexp(pat, dirc, (int)p_magic, &strcopy);
  1019.         if (strcopy != ps)
  1020.         {
  1021.         /* made a copy of "pat" to change "\?" to "?" */
  1022.         searchcmdlen += STRLEN(pat) - STRLEN(strcopy);
  1023.         pat = strcopy;
  1024.         searchstr = strcopy;
  1025.         }
  1026.         if (*p == dirc)
  1027.         {
  1028.         dircp = p;    /* remember where we put the NUL */
  1029.         *p++ = NUL;
  1030.         }
  1031.         spats[0].off.line = FALSE;
  1032.         spats[0].off.end = FALSE;
  1033.         spats[0].off.off = 0;
  1034.         /*
  1035.          * Check for a line offset or a character offset.
  1036.          * For get_address (echo off) we don't check for a character
  1037.          * offset, because it is meaningless and the 's' could be a
  1038.          * substitute command.
  1039.          */
  1040.         if (*p == '+' || *p == '-' || isdigit(*p))
  1041.         spats[0].off.line = TRUE;
  1042.         else if ((options & SEARCH_OPT) &&
  1043.                     (*p == 'e' || *p == 's' || *p == 'b'))
  1044.         {
  1045.         if (*p == 'e')        /* end */
  1046.             spats[0].off.end = SEARCH_END;
  1047.         ++p;
  1048.         }
  1049.         if (isdigit(*p) || *p == '+' || *p == '-')       /* got an offset */
  1050.         {
  1051.                         /* 'nr' or '+nr' or '-nr' */
  1052.         if (isdigit(*p) || isdigit(*(p + 1)))
  1053.             spats[0].off.off = atol((char *)p);
  1054.         else if (*p == '-')        /* single '-' */
  1055.             spats[0].off.off = -1;
  1056.         else                /* single '+' */
  1057.             spats[0].off.off = 1;
  1058.         ++p;
  1059.         while (isdigit(*p))        /* skip number */
  1060.             ++p;
  1061.         }
  1062.  
  1063.         /* compute length of search command for get_address() */
  1064.         searchcmdlen += (int)(p - pat);
  1065.  
  1066.         pat = p;                /* put pat after search command */
  1067.     }
  1068.  
  1069.     if ((options & SEARCH_ECHO) && messaging() && !cmd_silent)
  1070.     {
  1071.         char_u    *msgbuf;
  1072.         char_u    *trunc;
  1073.  
  1074.         if (*searchstr == NUL)
  1075.         p = spats[last_idx].pat;
  1076.         else
  1077.         p = searchstr;
  1078.         msgbuf = alloc((unsigned)(STRLEN(p) + 40));
  1079.         if (msgbuf != NULL)
  1080.         {
  1081.         msgbuf[0] = dirc;
  1082.         STRCPY(msgbuf + 1, p);
  1083.         if (spats[0].off.line || spats[0].off.end || spats[0].off.off)
  1084.         {
  1085.             p = msgbuf + STRLEN(msgbuf);
  1086.             *p++ = dirc;
  1087.             if (spats[0].off.end)
  1088.             *p++ = 'e';
  1089.             else if (!spats[0].off.line)
  1090.             *p++ = 's';
  1091.             if (spats[0].off.off > 0 || spats[0].off.line)
  1092.             *p++ = '+';
  1093.             if (spats[0].off.off != 0 || spats[0].off.line)
  1094.             sprintf((char *)p, "%ld", spats[0].off.off);
  1095.             else
  1096.             *p = NUL;
  1097.         }
  1098.  
  1099.         msg_start();
  1100.         trunc = msg_strtrunc(msgbuf);
  1101.  
  1102. #ifdef FEAT_RIGHTLEFT
  1103.         /* The search pattern could be shown on the right in rightleft
  1104.          * mode, but the 'ruler' and 'showcmd' area use it too, thus
  1105.          * it would be blanked out again very soon.  Show it on the
  1106.          * left, but do reverse the text. */
  1107.         if (curwin->w_p_rl && *curwin->w_p_rlc == 's')
  1108.         {
  1109.             char_u *r;
  1110.  
  1111.             r = reverse_text(trunc != NULL ? trunc : msgbuf);
  1112.             if (r != NULL)
  1113.             {
  1114.             vim_free(trunc);
  1115.             trunc = r;
  1116.             }
  1117.         }
  1118. #endif
  1119.         if (trunc != NULL)
  1120.         {
  1121.             msg_outtrans(trunc);
  1122.             vim_free(trunc);
  1123.         }
  1124.         else
  1125.             msg_outtrans(msgbuf);
  1126.         msg_clr_eos();
  1127.         msg_check();
  1128.         vim_free(msgbuf);
  1129.  
  1130.         gotocmdline(FALSE);
  1131.         out_flush();
  1132.         msg_nowait = TRUE;        /* don't wait for this message */
  1133.         }
  1134.     }
  1135.  
  1136.     /*
  1137.      * If there is a character offset, subtract it from the current
  1138.      * position, so we don't get stuck at "?pat?e+2" or "/pat/s-2".
  1139.      * This is not done for a line offset, because then we would not be vi
  1140.      * compatible.
  1141.      */
  1142.     if (!spats[0].off.line && spats[0].off.off)
  1143.     {
  1144.         if (spats[0].off.off > 0)
  1145.         {
  1146.         for (c = spats[0].off.off; c; --c)
  1147.             if (decl(&pos) == -1)
  1148.             break;
  1149.         if (c)            /* at start of buffer */
  1150.         {
  1151.             pos.lnum = 0;    /* allow lnum == 0 here */
  1152.             pos.col = MAXCOL;
  1153.         }
  1154.         }
  1155.         else
  1156.         {
  1157.         for (c = spats[0].off.off; c; ++c)
  1158.             if (incl(&pos) == -1)
  1159.             break;
  1160.         if (c)            /* at end of buffer */
  1161.         {
  1162.             pos.lnum = curbuf->b_ml.ml_line_count + 1;
  1163.             pos.col = 0;
  1164.         }
  1165.         }
  1166.     }
  1167.  
  1168. #ifdef FEAT_FKMAP    /* when in Farsi mode, reverse the character flow */
  1169.     if (p_altkeymap && curwin->w_p_rl)
  1170.          lrFswap(searchstr,0);
  1171. #endif
  1172.  
  1173.     c = searchit(curwin, curbuf, &pos, dirc == '/' ? FORWARD : BACKWARD,
  1174.         searchstr, count, spats[0].off.end + (options &
  1175.                (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS
  1176.             + SEARCH_MSG + SEARCH_START
  1177.             + ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF))),
  1178.         RE_LAST);
  1179.  
  1180.     if (dircp != NULL)
  1181.         *dircp = dirc;    /* restore second '/' or '?' for normal_cmd() */
  1182.     if (c == FAIL)
  1183.     {
  1184.         retval = 0;
  1185.         goto end_do_search;
  1186.     }
  1187.     if (spats[0].off.end && oap != NULL)
  1188.         oap->inclusive = TRUE;  /* 'e' includes last character */
  1189.  
  1190.     retval = 1;            /* pattern found */
  1191.  
  1192.     /*
  1193.      * Add character and/or line offset
  1194.      */
  1195.     if (!(options & SEARCH_NOOF) || *pat == ';')
  1196.     {
  1197.         if (spats[0].off.line)    /* Add the offset to the line number. */
  1198.         {
  1199.         c = pos.lnum + spats[0].off.off;
  1200.         if (c < 1)
  1201.             pos.lnum = 1;
  1202.         else if (c > curbuf->b_ml.ml_line_count)
  1203.             pos.lnum = curbuf->b_ml.ml_line_count;
  1204.         else
  1205.             pos.lnum = c;
  1206.         pos.col = 0;
  1207.  
  1208.         retval = 2;        /* pattern found, line offset added */
  1209.         }
  1210.         else
  1211.         {
  1212.         /* to the right, check for end of file */
  1213.         if (spats[0].off.off > 0)
  1214.         {
  1215.             for (c = spats[0].off.off; c; --c)
  1216.             if (incl(&pos) == -1)
  1217.                 break;
  1218.         }
  1219.         /* to the left, check for start of file */
  1220.         else
  1221.         {
  1222.             if ((c = pos.col + spats[0].off.off) >= 0)
  1223.             pos.col = c;
  1224.             else
  1225.             for (c = spats[0].off.off; c; ++c)
  1226.                 if (decl(&pos) == -1)
  1227.                 break;
  1228.         }
  1229.         }
  1230.     }
  1231.  
  1232.     /*
  1233.      * The search command can be followed by a ';' to do another search.
  1234.      * For example: "/pat/;/foo/+3;?bar"
  1235.      * This is like doing another search command, except:
  1236.      * - The remembered direction '/' or '?' is from the first search.
  1237.      * - When an error happens the cursor isn't moved at all.
  1238.      * Don't do this when called by get_address() (it handles ';' itself).
  1239.      */
  1240.     if (!(options & SEARCH_OPT) || pat == NULL || *pat != ';')
  1241.         break;
  1242.  
  1243.     dirc = *++pat;
  1244.     if (dirc != '?' && dirc != '/')
  1245.     {
  1246.         retval = 0;
  1247.         EMSG(_("E386: Expected '?' or '/'  after ';'"));
  1248.         goto end_do_search;
  1249.     }
  1250.     ++pat;
  1251.     }
  1252.  
  1253.     if (options & SEARCH_MARK)
  1254.     setpcmark();
  1255.     curwin->w_cursor = pos;
  1256.     curwin->w_set_curswant = TRUE;
  1257.  
  1258. end_do_search:
  1259.     if (options & SEARCH_KEEP)
  1260.     spats[0].off = old_off;
  1261.     vim_free(strcopy);
  1262.  
  1263.     return retval;
  1264. }
  1265.  
  1266. #if defined(FEAT_INS_EXPAND) || defined(PROTO)
  1267. /*
  1268.  * search_for_exact_line(buf, pos, dir, pat)
  1269.  *
  1270.  * Search for a line starting with the given pattern (ignoring leading
  1271.  * white-space), starting from pos and going in direction dir.    pos will
  1272.  * contain the position of the match found.    Blank lines match only if
  1273.  * ADDING is set.  if p_ic is set then the pattern must be in lowercase.
  1274.  * Return OK for success, or FAIL if no line found.
  1275.  */
  1276.     int
  1277. search_for_exact_line(buf, pos, dir, pat)
  1278.     buf_T    *buf;
  1279.     pos_T    *pos;
  1280.     int        dir;
  1281.     char_u    *pat;
  1282. {
  1283.     linenr_T    start = 0;
  1284.     char_u    *ptr;
  1285.     char_u    *p;
  1286.  
  1287.     if (buf->b_ml.ml_line_count == 0)
  1288.     return FAIL;
  1289.     for (;;)
  1290.     {
  1291.     pos->lnum += dir;
  1292.     if (pos->lnum < 1)
  1293.     {
  1294.         if (p_ws)
  1295.         {
  1296.         pos->lnum = buf->b_ml.ml_line_count;
  1297.         if (!shortmess(SHM_SEARCH))
  1298.             give_warning((char_u *)_(top_bot_msg), TRUE);
  1299.         }
  1300.         else
  1301.         {
  1302.         pos->lnum = 1;
  1303.         break;
  1304.         }
  1305.     }
  1306.     else if (pos->lnum > buf->b_ml.ml_line_count)
  1307.     {
  1308.         if (p_ws)
  1309.         {
  1310.         pos->lnum = 1;
  1311.         if (!shortmess(SHM_SEARCH))
  1312.             give_warning((char_u *)_(bot_top_msg), TRUE);
  1313.         }
  1314.         else
  1315.         {
  1316.         pos->lnum = 1;
  1317.         break;
  1318.         }
  1319.     }
  1320.     if (pos->lnum == start)
  1321.         break;
  1322.     if (start == 0)
  1323.         start = pos->lnum;
  1324.     ptr = ml_get_buf(buf, pos->lnum, FALSE);
  1325.     p = skipwhite(ptr);
  1326.     pos->col = (colnr_T) (p - ptr);
  1327.  
  1328.     /* when adding lines the matching line may be empty but it is not
  1329.      * ignored because we are interested in the next line -- Acevedo */
  1330.     if ((continue_status & CONT_ADDING) && !(continue_status & CONT_SOL))
  1331.     {
  1332.         if ((p_ic ? MB_STRICMP(p, pat) : STRCMP(p, pat)) == 0)
  1333.         return OK;
  1334.     }
  1335.     else if (*p != NUL)    /* ignore empty lines */
  1336.     {    /* expanding lines or words */
  1337.         if ((p_ic ? MB_STRNICMP(p, pat, completion_length)
  1338.                    : STRNCMP(p, pat, completion_length)) == 0)
  1339.         return OK;
  1340.     }
  1341.     }
  1342.     return FAIL;
  1343. }
  1344. #endif /* FEAT_INS_EXPAND */
  1345.  
  1346. /*
  1347.  * Character Searches
  1348.  */
  1349.  
  1350. /*
  1351.  * Search for a character in a line.  If "t_cmd" is FALSE, move to the
  1352.  * position of the character, otherwise move to just before the char.
  1353.  * Do this "cap->count1" times.
  1354.  * Return FAIL or OK.
  1355.  */
  1356.     int
  1357. searchc(cap, t_cmd)
  1358.     cmdarg_T    *cap;
  1359.     int        t_cmd;
  1360. {
  1361.     int            c = cap->nchar;    /* char to search for */
  1362.     int            dir = cap->arg;    /* TRUE for searching forward */
  1363.     long        count = cap->count1;    /* repeat count */
  1364.     static int        lastc = NUL;    /* last character searched for */
  1365.     static int        lastcdir;    /* last direction of character search */
  1366.     static int        last_t_cmd;    /* last search t_cmd */
  1367.     int            col;
  1368.     char_u        *p;
  1369.     int            len;
  1370. #ifdef FEAT_MBYTE
  1371.     static char_u    bytes[MB_MAXBYTES];
  1372.     static int        bytelen = 1;    /* >1 for multi-byte char */
  1373. #endif
  1374.  
  1375.     if (c != NUL)    /* normal search: remember args for repeat */
  1376.     {
  1377.     if (!KeyStuffed)    /* don't remember when redoing */
  1378.     {
  1379.         lastc = c;
  1380.         lastcdir = dir;
  1381.         last_t_cmd = t_cmd;
  1382. #ifdef FEAT_MBYTE
  1383.         bytelen = (*mb_char2bytes)(c, bytes);
  1384.         if (cap->ncharC1 != 0)
  1385.         {
  1386.         bytelen += (*mb_char2bytes)(cap->ncharC1, bytes + bytelen);
  1387.         if (cap->ncharC2 != 0)
  1388.             bytelen += (*mb_char2bytes)(cap->ncharC2, bytes + bytelen);
  1389.         }
  1390. #endif
  1391.     }
  1392.     }
  1393.     else        /* repeat previous search */
  1394.     {
  1395.     if (lastc == NUL)
  1396.         return FAIL;
  1397.     if (dir)    /* repeat in opposite direction */
  1398.         dir = -lastcdir;
  1399.     else
  1400.         dir = lastcdir;
  1401.     t_cmd = last_t_cmd;
  1402.     c = lastc;
  1403.     /* For multi-byte re-use last bytes[] and bytelen. */
  1404.     }
  1405.  
  1406.     p = ml_get_curline();
  1407.     col = curwin->w_cursor.col;
  1408.     len = (int)STRLEN(p);
  1409.  
  1410.     while (count--)
  1411.     {
  1412. #ifdef FEAT_MBYTE
  1413.     if (has_mbyte)
  1414.     {
  1415.         for (;;)
  1416.         {
  1417.         if (dir > 0)
  1418.         {
  1419.             col += (*mb_ptr2len_check)(p + col);
  1420.             if (col >= len)
  1421.             return FAIL;
  1422.         }
  1423.         else
  1424.         {
  1425.             if (col == 0)
  1426.             return FAIL;
  1427.             col -= (*mb_head_off)(p, p + col - 1) + 1;
  1428.         }
  1429.         if (bytelen == 1)
  1430.         {
  1431.             if (p[col] == c)
  1432.             break;
  1433.         }
  1434.         else
  1435.         {
  1436.             if (vim_memcmp(p + col, bytes, bytelen) == 0)
  1437.             break;
  1438.         }
  1439.         }
  1440.     }
  1441.     else
  1442. #endif
  1443.     {
  1444.         for (;;)
  1445.         {
  1446.         if ((col += dir) < 0 || col >= len)
  1447.             return FAIL;
  1448.         if (p[col] == c)
  1449.             break;
  1450.         }
  1451.     }
  1452.     }
  1453.  
  1454.     if (t_cmd)
  1455.     {
  1456.     /* backup to before the character (possibly double-byte) */
  1457.     col -= dir;
  1458. #ifdef FEAT_MBYTE
  1459.     if (has_mbyte)
  1460.     {
  1461.         if (dir < 0)
  1462.         /* Landed on the search char which is bytelen long */
  1463.         col += bytelen - 1;
  1464.         else
  1465.         /* To previous char, which may be multi-byte. */
  1466.         col -= (*mb_head_off)(p, p + col);
  1467.     }
  1468. #endif
  1469.     }
  1470.     curwin->w_cursor.col = col;
  1471.  
  1472.     return OK;
  1473. }
  1474.  
  1475. /*
  1476.  * "Other" Searches
  1477.  */
  1478.  
  1479. /*
  1480.  * findmatch - find the matching paren or brace
  1481.  *
  1482.  * Improvement over vi: Braces inside quotes are ignored.
  1483.  */
  1484.     pos_T *
  1485. findmatch(oap, initc)
  1486.     oparg_T   *oap;
  1487.     int        initc;
  1488. {
  1489.     return findmatchlimit(oap, initc, 0, 0);
  1490. }
  1491.  
  1492. /*
  1493.  * findmatchlimit -- find the matching paren or brace, if it exists within
  1494.  * maxtravel lines of here.  A maxtravel of 0 means search until falling off
  1495.  * the edge of the file.
  1496.  *
  1497.  * "initc" is the character to find a match for.  NUL means to find the
  1498.  * character at or after the cursor.
  1499.  *
  1500.  * flags: FM_BACKWARD    search backwards (when initc is '/', '*' or '#')
  1501.  *      FM_FORWARD    search forwards (when initc is '/', '*' or '#')
  1502.  *      FM_BLOCKSTOP    stop at start/end of block ({ or } in column 0)
  1503.  *      FM_SKIPCOMM    skip comments (not implemented yet!)
  1504.  */
  1505.  
  1506.     pos_T *
  1507. findmatchlimit(oap, initc, flags, maxtravel)
  1508.     oparg_T    *oap;
  1509.     int        initc;
  1510.     int        flags;
  1511.     int        maxtravel;
  1512. {
  1513.     static pos_T pos;            /* current search position */
  1514.     int        findc = 0;        /* matching brace */
  1515.     int        c;
  1516.     int        count = 0;        /* cumulative number of braces */
  1517.     int        backwards = FALSE;    /* init for gcc */
  1518.     int        inquote = FALSE;    /* TRUE when inside quotes */
  1519.     char_u    *linep;            /* pointer to current line */
  1520.     char_u    *ptr;
  1521.     int        do_quotes;        /* check for quotes in current line */
  1522.     int        at_start;        /* do_quotes value at start position */
  1523.     int        hash_dir = 0;        /* Direction searched for # things */
  1524.     int        comment_dir = 0;    /* Direction searched for comments */
  1525.     pos_T    match_pos;        /* Where last slash-star was found */
  1526.     int        start_in_quotes;    /* start position is in quotes */
  1527.     int        traveled = 0;        /* how far we've searched so far */
  1528.     int        ignore_cend = FALSE;    /* ignore comment end */
  1529.     int        cpo_match;        /* vi compatible matching */
  1530.     int        cpo_bsl;        /* don't recognize backslashes */
  1531.     int        match_escaped = 0;    /* search for escaped match */
  1532.     int        dir;            /* Direction to search */
  1533.     int        comment_col = MAXCOL;   /* start of / / comment */
  1534.  
  1535.     pos = curwin->w_cursor;
  1536.     linep = ml_get(pos.lnum);
  1537.  
  1538.     cpo_match = (vim_strchr(p_cpo, CPO_MATCH) != NULL);
  1539.     cpo_bsl = (vim_strchr(p_cpo, CPO_MATCHBSL) != NULL);
  1540.  
  1541.     /* Direction to search when initc is '/', '*' or '#' */
  1542.     if (flags & FM_BACKWARD)
  1543.     dir = BACKWARD;
  1544.     else if (flags & FM_FORWARD)
  1545.     dir = FORWARD;
  1546.     else
  1547.     dir = 0;
  1548.  
  1549.     /*
  1550.      * if initc given, look in the table for the matching character
  1551.      * '/' and '*' are special cases: look for start or end of comment.
  1552.      * When '/' is used, we ignore running backwards into an star-slash, for
  1553.      * "[*" command, we just want to find any comment.
  1554.      */
  1555.     if (initc == '/' || initc == '*')
  1556.     {
  1557.     comment_dir = dir;
  1558.     if (initc == '/')
  1559.         ignore_cend = TRUE;
  1560.     backwards = (dir == FORWARD) ? FALSE : TRUE;
  1561.     initc = NUL;
  1562.     }
  1563.     else if (initc != '#' && initc != NUL)
  1564.     {
  1565.     /* 'matchpairs' is "x:y,x:y" */
  1566.     for (ptr = curbuf->b_p_mps; *ptr; ptr += 2)
  1567.     {
  1568.         if (*ptr == initc)
  1569.         {
  1570.         findc = initc;
  1571.         initc = ptr[2];
  1572.         backwards = TRUE;
  1573.         break;
  1574.         }
  1575.         ptr += 2;
  1576.         if (*ptr == initc)
  1577.         {
  1578.         findc = initc;
  1579.         initc = ptr[-2];
  1580.         backwards = FALSE;
  1581.         break;
  1582.         }
  1583.     }
  1584.     if (!findc)        /* invalid initc! */
  1585.         return NULL;
  1586.     }
  1587.     /*
  1588.      * Either initc is '#', or no initc was given and we need to look under the
  1589.      * cursor.
  1590.      */
  1591.     else
  1592.     {
  1593.     if (initc == '#')
  1594.     {
  1595.         hash_dir = dir;
  1596.     }
  1597.     else
  1598.     {
  1599.         /*
  1600.          * initc was not given, must look for something to match under
  1601.          * or near the cursor.
  1602.          * Only check for special things when 'cpo' doesn't have '%'.
  1603.          */
  1604.         if (!cpo_match)
  1605.         {
  1606.         /* Are we before or at #if, #else etc.? */
  1607.         ptr = skipwhite(linep);
  1608.         if (*ptr == '#' && pos.col <= (colnr_T)(ptr - linep))
  1609.         {
  1610.             ptr = skipwhite(ptr + 1);
  1611.             if (   STRNCMP(ptr, "if", 2) == 0
  1612.             || STRNCMP(ptr, "endif", 5) == 0
  1613.             || STRNCMP(ptr, "el", 2) == 0)
  1614.             hash_dir = 1;
  1615.         }
  1616.  
  1617.         /* Are we on a comment? */
  1618.         else if (linep[pos.col] == '/')
  1619.         {
  1620.             if (linep[pos.col + 1] == '*')
  1621.             {
  1622.             comment_dir = FORWARD;
  1623.             backwards = FALSE;
  1624.             pos.col++;
  1625.             }
  1626.             else if (pos.col > 0 && linep[pos.col - 1] == '*')
  1627.             {
  1628.             comment_dir = BACKWARD;
  1629.             backwards = TRUE;
  1630.             pos.col--;
  1631.             }
  1632.         }
  1633.         else if (linep[pos.col] == '*')
  1634.         {
  1635.             if (linep[pos.col + 1] == '/')
  1636.             {
  1637.             comment_dir = BACKWARD;
  1638.             backwards = TRUE;
  1639.             }
  1640.             else if (pos.col > 0 && linep[pos.col - 1] == '/')
  1641.             {
  1642.             comment_dir = FORWARD;
  1643.             backwards = FALSE;
  1644.             }
  1645.         }
  1646.         }
  1647.  
  1648.         /*
  1649.          * If we are not on a comment or the # at the start of a line, then
  1650.          * look for brace anywhere on this line after the cursor.
  1651.          */
  1652.         if (!hash_dir && !comment_dir)
  1653.         {
  1654.         /*
  1655.          * Find the brace under or after the cursor.
  1656.          * If beyond the end of the line, use the last character in
  1657.          * the line.
  1658.          */
  1659.         if (linep[pos.col] == NUL && pos.col)
  1660.             --pos.col;
  1661.         for (;;)
  1662.         {
  1663.             initc = linep[pos.col];
  1664.             if (initc == NUL)
  1665.             break;
  1666.  
  1667.             for (ptr = curbuf->b_p_mps; *ptr; ++ptr)
  1668.             {
  1669.             if (*ptr == initc)
  1670.             {
  1671.                 findc = ptr[2];
  1672.                 backwards = FALSE;
  1673.                 break;
  1674.             }
  1675.             ptr += 2;
  1676.             if (*ptr == initc)
  1677.             {
  1678.                 findc = ptr[-2];
  1679.                 backwards = TRUE;
  1680.                 break;
  1681.             }
  1682.             if (!*++ptr)
  1683.                 break;
  1684.             }
  1685.             if (findc)
  1686.             break;
  1687. #ifdef FEAT_MBYTE
  1688.             if (has_mbyte)
  1689.             pos.col += (*mb_ptr2len_check)(linep + pos.col);
  1690.             else
  1691. #endif
  1692.             ++pos.col;
  1693.         }
  1694.         if (!findc)
  1695.         {
  1696.             /* no brace in the line, maybe use "  #if" then */
  1697.             if (!cpo_match && *skipwhite(linep) == '#')
  1698.             hash_dir = 1;
  1699.             else
  1700.             return NULL;
  1701.         }
  1702.         else if (!cpo_bsl)
  1703.         {
  1704.             int col, bslcnt = 0;
  1705.  
  1706.             /* Set "match_escaped" if there are an odd number of
  1707.              * backslashes. */
  1708.             for (col = pos.col - 1; col >= 0 && linep[col] == '\\';
  1709.                                     col--)
  1710.             bslcnt++;
  1711.             match_escaped = (bslcnt & 1);
  1712.         }
  1713.         }
  1714.     }
  1715.     if (hash_dir)
  1716.     {
  1717.         /*
  1718.          * Look for matching #if, #else, #elif, or #endif
  1719.          */
  1720.         if (oap != NULL)
  1721.         oap->motion_type = MLINE;   /* Linewise for this case only */
  1722.         if (initc != '#')
  1723.         {
  1724.         ptr = skipwhite(skipwhite(linep) + 1);
  1725.         if (STRNCMP(ptr, "if", 2) == 0 || STRNCMP(ptr, "el", 2) == 0)
  1726.             hash_dir = 1;
  1727.         else if (STRNCMP(ptr, "endif", 5) == 0)
  1728.             hash_dir = -1;
  1729.         else
  1730.             return NULL;
  1731.         }
  1732.         pos.col = 0;
  1733.         while (!got_int)
  1734.         {
  1735.         if (hash_dir > 0)
  1736.         {
  1737.             if (pos.lnum == curbuf->b_ml.ml_line_count)
  1738.             break;
  1739.         }
  1740.         else if (pos.lnum == 1)
  1741.             break;
  1742.         pos.lnum += hash_dir;
  1743.         linep = ml_get(pos.lnum);
  1744.         line_breakcheck();    /* check for CTRL-C typed */
  1745.         ptr = skipwhite(linep);
  1746.         if (*ptr != '#')
  1747.             continue;
  1748.         pos.col = (colnr_T) (ptr - linep);
  1749.         ptr = skipwhite(ptr + 1);
  1750.         if (hash_dir > 0)
  1751.         {
  1752.             if (STRNCMP(ptr, "if", 2) == 0)
  1753.             count++;
  1754.             else if (STRNCMP(ptr, "el", 2) == 0)
  1755.             {
  1756.             if (count == 0)
  1757.                 return &pos;
  1758.             }
  1759.             else if (STRNCMP(ptr, "endif", 5) == 0)
  1760.             {
  1761.             if (count == 0)
  1762.                 return &pos;
  1763.             count--;
  1764.             }
  1765.         }
  1766.         else
  1767.         {
  1768.             if (STRNCMP(ptr, "if", 2) == 0)
  1769.             {
  1770.             if (count == 0)
  1771.                 return &pos;
  1772.             count--;
  1773.             }
  1774.             else if (initc == '#' && STRNCMP(ptr, "el", 2) == 0)
  1775.             {
  1776.             if (count == 0)
  1777.                 return &pos;
  1778.             }
  1779.             else if (STRNCMP(ptr, "endif", 5) == 0)
  1780.             count++;
  1781.         }
  1782.         }
  1783.         return NULL;
  1784.     }
  1785.     }
  1786.  
  1787. #ifdef FEAT_RIGHTLEFT
  1788.     /* This is just guessing: when 'rightleft' is set, search for a maching
  1789.      * paren/brace in the other direction. */
  1790.     if (curwin->w_p_rl && vim_strchr((char_u *)"()[]{}<>", initc) != NULL)
  1791.     backwards = !backwards;
  1792. #endif
  1793.  
  1794.     do_quotes = -1;
  1795.     start_in_quotes = MAYBE;
  1796.     /* backward search: Check if this line contains a single-line comment */
  1797.     if (backwards && comment_dir)
  1798.     comment_col = check_linecomment(linep);
  1799.     while (!got_int)
  1800.     {
  1801.     /*
  1802.      * Go to the next position, forward or backward. We could use
  1803.      * inc() and dec() here, but that is much slower
  1804.      */
  1805.     if (backwards)
  1806.     {
  1807.         if (pos.col == 0)        /* at start of line, go to prev. one */
  1808.         {
  1809.         if (pos.lnum == 1)    /* start of file */
  1810.             break;
  1811.         --pos.lnum;
  1812.  
  1813.         if (maxtravel && traveled++ > maxtravel)
  1814.             break;
  1815.  
  1816.         linep = ml_get(pos.lnum);
  1817.         pos.col = (colnr_T)STRLEN(linep); /* pos.col on trailing NUL */
  1818.         do_quotes = -1;
  1819.         line_breakcheck();
  1820.  
  1821.         /* Check if this line contains a single-line comment */
  1822.         if (comment_dir)
  1823.             comment_col = check_linecomment(linep);
  1824.         }
  1825.         else
  1826.         {
  1827.         --pos.col;
  1828. #ifdef FEAT_MBYTE
  1829.         if (has_mbyte)
  1830.             pos.col -= (*mb_head_off)(linep, linep + pos.col);
  1831. #endif
  1832.         }
  1833.     }
  1834.     else                /* forward search */
  1835.     {
  1836.         if (linep[pos.col] == NUL)    /* at end of line, go to next one */
  1837.         {
  1838.         if (pos.lnum == curbuf->b_ml.ml_line_count) /* end of file */
  1839.             break;
  1840.         ++pos.lnum;
  1841.  
  1842.         if (maxtravel && traveled++ > maxtravel)
  1843.             break;
  1844.  
  1845.         linep = ml_get(pos.lnum);
  1846.         pos.col = 0;
  1847.         do_quotes = -1;
  1848.         line_breakcheck();
  1849.         }
  1850.         else
  1851.         {
  1852. #ifdef FEAT_MBYTE
  1853.         if (has_mbyte)
  1854.             pos.col += (*mb_ptr2len_check)(linep + pos.col);
  1855.         else
  1856. #endif
  1857.             ++pos.col;
  1858.         }
  1859.     }
  1860.  
  1861.     /*
  1862.      * If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0.
  1863.      */
  1864.     if (pos.col == 0 && (flags & FM_BLOCKSTOP) &&
  1865.                      (linep[0] == '{' || linep[0] == '}'))
  1866.     {
  1867.         if (linep[0] == findc && count == 0)    /* match! */
  1868.         return &pos;
  1869.         break;                    /* out of scope */
  1870.     }
  1871.  
  1872.     if (comment_dir)
  1873.     {
  1874.         /* Note: comments do not nest, and we ignore quotes in them */
  1875.         /* TODO: ignore comment brackets inside strings */
  1876.         if (comment_dir == FORWARD)
  1877.         {
  1878.         if (linep[pos.col] == '*' && linep[pos.col + 1] == '/')
  1879.         {
  1880.             pos.col++;
  1881.             return &pos;
  1882.         }
  1883.         }
  1884.         else    /* Searching backwards */
  1885.         {
  1886.         /*
  1887.          * A comment may contain / * or / /, it may also start or end
  1888.          * with / * /.    Ignore a / * after / /.
  1889.          */
  1890.         if (pos.col == 0)
  1891.             continue;
  1892.         else if (  linep[pos.col - 1] == '/'
  1893.             && linep[pos.col] == '*'
  1894.             && (int)pos.col < comment_col)
  1895.         {
  1896.             count++;
  1897.             match_pos = pos;
  1898.             match_pos.col--;
  1899.         }
  1900.         else if (linep[pos.col - 1] == '*' && linep[pos.col] == '/')
  1901.         {
  1902.             if (count > 0)
  1903.             pos = match_pos;
  1904.             else if (pos.col > 1 && linep[pos.col - 2] == '/'
  1905.                            && (int)pos.col <= comment_col)
  1906.             pos.col -= 2;
  1907.             else if (ignore_cend)
  1908.             continue;
  1909.             else
  1910.             return NULL;
  1911.             return &pos;
  1912.         }
  1913.         }
  1914.         continue;
  1915.     }
  1916.  
  1917.     /*
  1918.      * If smart matching ('cpoptions' does not contain '%'), braces inside
  1919.      * of quotes are ignored, but only if there is an even number of
  1920.      * quotes in the line.
  1921.      */
  1922.     if (cpo_match)
  1923.         do_quotes = 0;
  1924.     else if (do_quotes == -1)
  1925.     {
  1926.         /*
  1927.          * Count the number of quotes in the line, skipping \" and '"'.
  1928.          * Watch out for "\\".
  1929.          */
  1930.         at_start = do_quotes;
  1931.         for (ptr = linep; *ptr; ++ptr)
  1932.         {
  1933.         if (ptr == linep + pos.col + backwards)
  1934.             at_start = (do_quotes & 1);
  1935.         if (*ptr == '"'
  1936.             && (ptr == linep || ptr[-1] != '\'' || ptr[1] != '\''))
  1937.             ++do_quotes;
  1938.         if (*ptr == '\\' && ptr[1] != NUL)
  1939.             ++ptr;
  1940.         }
  1941.         do_quotes &= 1;        /* result is 1 with even number of quotes */
  1942.  
  1943.         /*
  1944.          * If we find an uneven count, check current line and previous
  1945.          * one for a '\' at the end.
  1946.          */
  1947.         if (!do_quotes)
  1948.         {
  1949.         inquote = FALSE;
  1950.         if (ptr[-1] == '\\')
  1951.         {
  1952.             do_quotes = 1;
  1953.             if (start_in_quotes == MAYBE)
  1954.             {
  1955.             /* Do we need to use at_start here? */
  1956.             inquote = TRUE;
  1957.             start_in_quotes = TRUE;
  1958.             }
  1959.             else if (backwards)
  1960.             inquote = TRUE;
  1961.         }
  1962.         if (pos.lnum > 1)
  1963.         {
  1964.             ptr = ml_get(pos.lnum - 1);
  1965.             if (*ptr && *(ptr + STRLEN(ptr) - 1) == '\\')
  1966.             {
  1967.             do_quotes = 1;
  1968.             if (start_in_quotes == MAYBE)
  1969.             {
  1970.                 inquote = at_start;
  1971.                 if (inquote)
  1972.                 start_in_quotes = TRUE;
  1973.             }
  1974.             else if (!backwards)
  1975.                 inquote = TRUE;
  1976.             }
  1977.         }
  1978.         }
  1979.     }
  1980.     if (start_in_quotes == MAYBE)
  1981.         start_in_quotes = FALSE;
  1982.  
  1983.     /*
  1984.      * If 'smartmatch' is set:
  1985.      *   Things inside quotes are ignored by setting 'inquote'.  If we
  1986.      *   find a quote without a preceding '\' invert 'inquote'.  At the
  1987.      *   end of a line not ending in '\' we reset 'inquote'.
  1988.      *
  1989.      *   In lines with an uneven number of quotes (without preceding '\')
  1990.      *   we do not know which part to ignore. Therefore we only set
  1991.      *   inquote if the number of quotes in a line is even, unless this
  1992.      *   line or the previous one ends in a '\'.  Complicated, isn't it?
  1993.      */
  1994.     switch (c = linep[pos.col])
  1995.     {
  1996.     case NUL:
  1997.         /* at end of line without trailing backslash, reset inquote */
  1998.         if (pos.col == 0 || linep[pos.col - 1] != '\\')
  1999.         {
  2000.         inquote = FALSE;
  2001.         start_in_quotes = FALSE;
  2002.         }
  2003.         break;
  2004.  
  2005.     case '"':
  2006.         /* a quote that is preceded with an odd number of backslashes is
  2007.          * ignored */
  2008.         if (do_quotes)
  2009.         {
  2010.         int col;
  2011.  
  2012.         for (col = pos.col - 1; col >= 0; --col)
  2013.             if (linep[col] != '\\')
  2014.             break;
  2015.         if ((((int)pos.col - 1 - col) & 1) == 0)
  2016.         {
  2017.             inquote = !inquote;
  2018.             start_in_quotes = FALSE;
  2019.         }
  2020.         }
  2021.         break;
  2022.  
  2023.     /*
  2024.      * If smart matching ('cpoptions' does not contain '%'):
  2025.      *   Skip things in single quotes: 'x' or '\x'.  Be careful for single
  2026.      *   single quotes, eg jon's.  Things like '\233' or '\x3f' are not
  2027.      *   skipped, there is never a brace in them.
  2028.      *   Ignore this when finding matches for `'.
  2029.      */
  2030.     case '\'':
  2031.         if (!cpo_match && initc != '\'' && findc != '\'')
  2032.         {
  2033.         if (backwards)
  2034.         {
  2035.             if (pos.col > 1)
  2036.             {
  2037.             if (linep[pos.col - 2] == '\'')
  2038.             {
  2039.                 pos.col -= 2;
  2040.                 break;
  2041.             }
  2042.             else if (linep[pos.col - 2] == '\\' &&
  2043.                     pos.col > 2 && linep[pos.col - 3] == '\'')
  2044.             {
  2045.                 pos.col -= 3;
  2046.                 break;
  2047.             }
  2048.             }
  2049.         }
  2050.         else if (linep[pos.col + 1])    /* forward search */
  2051.         {
  2052.             if (linep[pos.col + 1] == '\\' &&
  2053.                 linep[pos.col + 2] && linep[pos.col + 3] == '\'')
  2054.             {
  2055.             pos.col += 3;
  2056.             break;
  2057.             }
  2058.             else if (linep[pos.col + 2] == '\'')
  2059.             {
  2060.             pos.col += 2;
  2061.             break;
  2062.             }
  2063.         }
  2064.         }
  2065.         /* FALLTHROUGH */
  2066.  
  2067.     default:
  2068. #ifdef FEAT_LISP
  2069.         /* For Lisp skip over backslashed (), {} and []. */
  2070.         if (curbuf->b_p_lisp
  2071.             && vim_strchr((char_u *)"(){}[]", c) != NULL
  2072.             && pos.col > 0
  2073.             && linep[pos.col - 1] == '\\')
  2074.         break;
  2075. #endif
  2076.  
  2077.         /* Check for match outside of quotes, and inside of
  2078.          * quotes when the start is also inside of quotes. */
  2079.         if ((!inquote || start_in_quotes == TRUE)
  2080.             && (c == initc || c == findc))
  2081.         {
  2082.         int    col, bslcnt = 0;
  2083.  
  2084.         if (!cpo_bsl)
  2085.         {
  2086.             for (col = pos.col - 1; col >= 0 && linep[col] == '\\';
  2087.                                     col--)
  2088.             bslcnt++;
  2089.         }
  2090.         /* Only accept a match when 'M' is in 'cpo' or when ecaping is
  2091.          * what we expect. */
  2092.         if (cpo_bsl || (bslcnt & 1) == match_escaped)
  2093.         {
  2094.             if (c == initc)
  2095.             count++;
  2096.             else
  2097.             {
  2098.             if (count == 0)
  2099.                 return &pos;
  2100.             count--;
  2101.             }
  2102.         }
  2103.         }
  2104.     }
  2105.     }
  2106.  
  2107.     if (comment_dir == BACKWARD && count > 0)
  2108.     {
  2109.     pos = match_pos;
  2110.     return &pos;
  2111.     }
  2112.     return (pos_T *)NULL;    /* never found it */
  2113. }
  2114.  
  2115. /*
  2116.  * Check if line[] contains a / / comment.
  2117.  * Return MAXCOL if not, otherwise return the column.
  2118.  * TODO: skip strings.
  2119.  */
  2120.     static int
  2121. check_linecomment(line)
  2122.     char_u    *line;
  2123. {
  2124.     char_u  *p;
  2125.  
  2126.     p = line;
  2127.     while ((p = vim_strchr(p, '/')) != NULL)
  2128.     {
  2129.     if (p[1] == '/')
  2130.         break;
  2131.     ++p;
  2132.     }
  2133.  
  2134.     if (p == NULL)
  2135.     return MAXCOL;
  2136.     return (int)(p - line);
  2137. }
  2138.  
  2139. /*
  2140.  * Move cursor briefly to character matching the one under the cursor.
  2141.  * Used for Insert mode and "r" command.
  2142.  * Show the match only if it is visible on the screen.
  2143.  * If there isn't a match, then beep.
  2144.  */
  2145.     void
  2146. showmatch()
  2147. {
  2148.     pos_T       *lpos, save_cursor;
  2149.     pos_T        mpos;
  2150.     colnr_T        vcol;
  2151.     long        save_so;
  2152. #ifdef CURSOR_SHAPE
  2153.     int            save_state;
  2154. #endif
  2155.     colnr_T        save_dollar_vcol;
  2156.  
  2157.     if ((lpos = findmatch(NULL, NUL)) == NULL)        /* no match, so beep */
  2158.     vim_beep();
  2159.     else if (lpos->lnum >= curwin->w_topline)
  2160.     {
  2161.     if (!curwin->w_p_wrap)
  2162.         getvcol(curwin, lpos, NULL, &vcol, NULL);
  2163.     if (curwin->w_p_wrap || (vcol >= curwin->w_leftcol
  2164.                    && vcol < curwin->w_leftcol + W_WIDTH(curwin)))
  2165.     {
  2166.         mpos = *lpos;    /* save the pos, update_screen() may change it */
  2167.         save_cursor = curwin->w_cursor;
  2168.         save_so = p_so;
  2169.         /* Handle "$" in 'cpo': If the ')' is typed on top of the "$",
  2170.          * stop displaying the "$". */
  2171.         if (dollar_vcol > 0 && dollar_vcol == curwin->w_virtcol)
  2172.         dollar_vcol = 0;
  2173.         ++curwin->w_virtcol;    /* do display ')' just before "$" */
  2174.         update_screen(VALID);    /* show the new char first */
  2175.  
  2176.         save_dollar_vcol = dollar_vcol;
  2177. #ifdef CURSOR_SHAPE
  2178.         save_state = State;
  2179.         State = SHOWMATCH;
  2180.         ui_cursor_shape();        /* may show different cursor shape */
  2181. #endif
  2182.         curwin->w_cursor = mpos;    /* move to matching char */
  2183.         p_so = 0;            /* don't use 'scrolloff' here */
  2184.         showruler(FALSE);
  2185.         setcursor();
  2186.         cursor_on();        /* make sure that the cursor is shown */
  2187.         out_flush();
  2188. #ifdef FEAT_GUI
  2189.         if (gui.in_use)
  2190.         {
  2191.         gui_update_cursor(TRUE, FALSE);
  2192.         gui_mch_flush();
  2193.         }
  2194. #endif
  2195.         /* Restore collar_vcol(), because setcursor() may call curs_rows()
  2196.          * which resets it if the matching position is in a previous line
  2197.          * and has a higher column number. */
  2198.         dollar_vcol = save_dollar_vcol;
  2199.  
  2200.         /*
  2201.          * brief pause, unless 'm' is present in 'cpo' and a character is
  2202.          * available.
  2203.          */
  2204.         if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL)
  2205.         ui_delay(p_mat * 100L, TRUE);
  2206.         else if (!char_avail())
  2207.         ui_delay(p_mat * 100L, FALSE);
  2208.         curwin->w_cursor = save_cursor;    /* restore cursor position */
  2209.         p_so = save_so;
  2210. #ifdef CURSOR_SHAPE
  2211.         State = save_state;
  2212.         ui_cursor_shape();        /* may show different cursor shape */
  2213. #endif
  2214.     }
  2215.     }
  2216. }
  2217.  
  2218. /*
  2219.  * findsent(dir, count) - Find the start of the next sentence in direction
  2220.  * 'dir' Sentences are supposed to end in ".", "!" or "?" followed by white
  2221.  * space or a line break. Also stop at an empty line.
  2222.  * Return OK if the next sentence was found.
  2223.  */
  2224.     int
  2225. findsent(dir, count)
  2226.     int        dir;
  2227.     long    count;
  2228. {
  2229.     pos_T    pos, tpos;
  2230.     int        c;
  2231.     int        (*func) __ARGS((pos_T *));
  2232.     int        startlnum;
  2233.     int        noskip = FALSE;        /* do not skip blanks */
  2234.     int        cpo_J;
  2235.  
  2236.     pos = curwin->w_cursor;
  2237.     if (dir == FORWARD)
  2238.     func = incl;
  2239.     else
  2240.     func = decl;
  2241.  
  2242.     while (count--)
  2243.     {
  2244.     /*
  2245.      * if on an empty line, skip upto a non-empty line
  2246.      */
  2247.     if (gchar_pos(&pos) == NUL)
  2248.     {
  2249.         do
  2250.         if ((*func)(&pos) == -1)
  2251.             break;
  2252.         while (gchar_pos(&pos) == NUL);
  2253.         if (dir == FORWARD)
  2254.         goto found;
  2255.     }
  2256.     /*
  2257.      * if on the start of a paragraph or a section and searching forward,
  2258.      * go to the next line
  2259.      */
  2260.     else if (dir == FORWARD && pos.col == 0 &&
  2261.                         startPS(pos.lnum, NUL, FALSE))
  2262.     {
  2263.         if (pos.lnum == curbuf->b_ml.ml_line_count)
  2264.         return FAIL;
  2265.         ++pos.lnum;
  2266.         goto found;
  2267.     }
  2268.     else if (dir == BACKWARD)
  2269.         decl(&pos);
  2270.  
  2271.     /* go back to the previous non-blank char */
  2272.     while ((c = gchar_pos(&pos)) == ' ' || c == '\t' ||
  2273.          (dir == BACKWARD && vim_strchr((char_u *)".!?)]\"'", c) != NULL))
  2274.     {
  2275.         if (decl(&pos) == -1)
  2276.         break;
  2277.         /* when going forward: Stop in front of empty line */
  2278.         if (lineempty(pos.lnum) && dir == FORWARD)
  2279.         {
  2280.         incl(&pos);
  2281.         goto found;
  2282.         }
  2283.     }
  2284.  
  2285.     /* remember the line where the search started */
  2286.     startlnum = pos.lnum;
  2287.     cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL;
  2288.  
  2289.     for (;;)        /* find end of sentence */
  2290.     {
  2291.         c = gchar_pos(&pos);
  2292.         if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
  2293.         {
  2294.         if (dir == BACKWARD && pos.lnum != startlnum)
  2295.             ++pos.lnum;
  2296.         break;
  2297.         }
  2298.         if (c == '.' || c == '!' || c == '?')
  2299.         {
  2300.         tpos = pos;
  2301.         do
  2302.             if ((c = inc(&tpos)) == -1)
  2303.             break;
  2304.         while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos))
  2305.             != NULL);
  2306.         if (c == -1  || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL
  2307.             || (cpo_J && (c == ' ' && inc(&tpos) >= 0
  2308.                   && gchar_pos(&tpos) == ' ')))
  2309.         {
  2310.             pos = tpos;
  2311.             if (gchar_pos(&pos) == NUL) /* skip NUL at EOL */
  2312.             inc(&pos);
  2313.             break;
  2314.         }
  2315.         }
  2316.         if ((*func)(&pos) == -1)
  2317.         {
  2318.         if (count)
  2319.             return FAIL;
  2320.         noskip = TRUE;
  2321.         break;
  2322.         }
  2323.     }
  2324. found:
  2325.         /* skip white space */
  2326.     while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
  2327.         if (incl(&pos) == -1)
  2328.         break;
  2329.     }
  2330.  
  2331.     setpcmark();
  2332.     curwin->w_cursor = pos;
  2333.     return OK;
  2334. }
  2335.  
  2336. /*
  2337.  * findpar(dir, count, what) - Find the next paragraph in direction 'dir'
  2338.  * Paragraphs are currently supposed to be separated by empty lines.
  2339.  * Return TRUE if the next paragraph was found.
  2340.  * If 'what' is '{' or '}' we go to the next section.
  2341.  * If 'both' is TRUE also stop at '}'.
  2342.  */
  2343.     int
  2344. findpar(oap, dir, count, what, both)
  2345.     oparg_T        *oap;
  2346.     int            dir;
  2347.     long        count;
  2348.     int            what;
  2349.     int            both;
  2350. {
  2351.     linenr_T    curr;
  2352.     int        did_skip;   /* TRUE after separating lines have been skipped */
  2353.     int        first;        /* TRUE on first line */
  2354.  
  2355.     curr = curwin->w_cursor.lnum;
  2356.  
  2357.     while (count--)
  2358.     {
  2359.     did_skip = FALSE;
  2360.     for (first = TRUE; ; first = FALSE)
  2361.     {
  2362.         if (*ml_get(curr) != NUL)
  2363.         did_skip = TRUE;
  2364.  
  2365.         if (!first && did_skip && startPS(curr, what, both))
  2366.         break;
  2367.  
  2368.         if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
  2369.         {
  2370.         if (count)
  2371.             return FALSE;
  2372.         curr -= dir;
  2373.         break;
  2374.         }
  2375.     }
  2376.     }
  2377.     setpcmark();
  2378.     if (both && *ml_get(curr) == '}')    /* include line with '}' */
  2379.     ++curr;
  2380.     curwin->w_cursor.lnum = curr;
  2381.     if (curr == curbuf->b_ml.ml_line_count && what != '}')
  2382.     {
  2383.     if ((curwin->w_cursor.col = (colnr_T)STRLEN(ml_get(curr))) != 0)
  2384.     {
  2385.         --curwin->w_cursor.col;
  2386.         oap->inclusive = TRUE;
  2387.     }
  2388.     }
  2389.     else
  2390.     curwin->w_cursor.col = 0;
  2391.     return TRUE;
  2392. }
  2393.  
  2394. /*
  2395.  * check if the string 's' is a nroff macro that is in option 'opt'
  2396.  */
  2397.     static int
  2398. inmacro(opt, s)
  2399.     char_u    *opt;
  2400.     char_u    *s;
  2401. {
  2402.     char_u    *macro;
  2403.  
  2404.     for (macro = opt; macro[0]; ++macro)
  2405.     {
  2406.     if (macro[0] == s[0] && (((s[1] == NUL || s[1] == ' ') &&
  2407.            (macro[1] == NUL || macro[1] == ' ')) || macro[1] == s[1]))
  2408.         break;
  2409.     ++macro;
  2410.     if (macro[0] == NUL)
  2411.         break;
  2412.     }
  2413.     return (macro[0] != NUL);
  2414. }
  2415.  
  2416. /*
  2417.  * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
  2418.  * If 'para' is '{' or '}' only check for sections.
  2419.  * If 'both' is TRUE also stop at '}'
  2420.  */
  2421.     int
  2422. startPS(lnum, para, both)
  2423.     linenr_T    lnum;
  2424.     int        para;
  2425.     int        both;
  2426. {
  2427.     char_u    *s;
  2428.  
  2429.     s = ml_get(lnum);
  2430.     if (*s == para || *s == '\f' || (both && *s == '}'))
  2431.     return TRUE;
  2432.     if (*s == '.' && (inmacro(p_sections, s + 1) ||
  2433.                        (!para && inmacro(p_para, s + 1))))
  2434.     return TRUE;
  2435.     return FALSE;
  2436. }
  2437.  
  2438. /*
  2439.  * The following routines do the word searches performed by the 'w', 'W',
  2440.  * 'b', 'B', 'e', and 'E' commands.
  2441.  */
  2442.  
  2443. /*
  2444.  * To perform these searches, characters are placed into one of three
  2445.  * classes, and transitions between classes determine word boundaries.
  2446.  *
  2447.  * The classes are:
  2448.  *
  2449.  * 0 - white space
  2450.  * 1 - punctuation
  2451.  * 2 or higher - keyword characters (letters, digits and underscore)
  2452.  */
  2453.  
  2454. static int    cls_bigword;    /* TRUE for "W", "B" or "E" */
  2455.  
  2456. /*
  2457.  * cls() - returns the class of character at curwin->w_cursor
  2458.  *
  2459.  * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars
  2460.  * from class 2 and higher are reported as class 1 since only white space
  2461.  * boundaries are of interest.
  2462.  */
  2463.     static int
  2464. cls()
  2465. {
  2466.     int        c;
  2467.  
  2468.     c = gchar_cursor();
  2469. #ifdef FEAT_FKMAP    /* when 'akm' (Farsi mode), take care of Farsi blank */
  2470.     if (p_altkeymap && c == F_BLANK)
  2471.     return 0;
  2472. #endif
  2473.     if (c == ' ' || c == '\t' || c == NUL)
  2474.     return 0;
  2475. #ifdef FEAT_MBYTE
  2476.     if (enc_dbcs != 0 && c > 0xFF)
  2477.     {
  2478.     /* If cls_bigword, report multi-byte chars as class 1. */
  2479.     if (enc_dbcs == DBCS_KOR && cls_bigword)
  2480.         return 1;
  2481.  
  2482.     /* process code leading/trailing bytes */
  2483.     return dbcs_class(((unsigned)c >> 8), (c & 0xFF));
  2484.     }
  2485.     if (enc_utf8)
  2486.     {
  2487.     c = utf_class(c);
  2488.     if (c != 0 && cls_bigword)
  2489.         return 1;
  2490.     return c;
  2491.     }
  2492. #endif
  2493.  
  2494.     /* If cls_bigword is TRUE, report all non-blanks as class 1. */
  2495.     if (cls_bigword)
  2496.     return 1;
  2497.  
  2498.     if (vim_iswordc(c))
  2499.     return 2;
  2500.     return 1;
  2501. }
  2502.  
  2503.  
  2504. /*
  2505.  * fwd_word(count, type, eol) - move forward one word
  2506.  *
  2507.  * Returns FAIL if the cursor was already at the end of the file.
  2508.  * If eol is TRUE, last word stops at end of line (for operators).
  2509.  */
  2510.     int
  2511. fwd_word(count, bigword, eol)
  2512.     long    count;
  2513.     int        bigword;    /* "W", "E" or "B" */
  2514.     int        eol;
  2515. {
  2516.     int        sclass;        /* starting class */
  2517.     int        i;
  2518.     int        last_line;
  2519.  
  2520. #ifdef FEAT_VIRTUALEDIT
  2521.     curwin->w_cursor.coladd = 0;
  2522. #endif
  2523.     cls_bigword = bigword;
  2524.     while (--count >= 0)
  2525.     {
  2526. #ifdef FEAT_FOLDING
  2527.     /* When inside a range of folded lines, move to the last char of the
  2528.      * last line. */
  2529.     if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
  2530.         coladvance((colnr_T)MAXCOL);
  2531. #endif
  2532.     sclass = cls();
  2533.  
  2534.     /*
  2535.      * We always move at least one character, unless on the last
  2536.      * character in the buffer.
  2537.      */
  2538.     last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
  2539.     i = inc_cursor();
  2540.     if (i == -1 || (i >= 1 && last_line)) /* started at last char in file */
  2541.         return FAIL;
  2542.     if (i == 1 && eol && count == 0)      /* started at last char in line */
  2543.         return OK;
  2544.  
  2545.     /*
  2546.      * Go one char past end of current word (if any)
  2547.      */
  2548.     if (sclass != 0)
  2549.         while (cls() == sclass)
  2550.         {
  2551.         i = inc_cursor();
  2552.         if (i == -1 || (i >= 1 && eol && count == 0))
  2553.             return OK;
  2554.         }
  2555.  
  2556.     /*
  2557.      * go to next non-white
  2558.      */
  2559.     while (cls() == 0)
  2560.     {
  2561.         /*
  2562.          * We'll stop if we land on a blank line
  2563.          */
  2564.         if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
  2565.         break;
  2566.  
  2567.         i = inc_cursor();
  2568.         if (i == -1 || (i >= 1 && eol && count == 0))
  2569.         return OK;
  2570.     }
  2571.     }
  2572.     return OK;
  2573. }
  2574.  
  2575. /*
  2576.  * bck_word() - move backward 'count' words
  2577.  *
  2578.  * If stop is TRUE and we are already on the start of a word, move one less.
  2579.  *
  2580.  * Returns FAIL if top of the file was reached.
  2581.  */
  2582.     int
  2583. bck_word(count, bigword, stop)
  2584.     long    count;
  2585.     int        bigword;
  2586.     int        stop;
  2587. {
  2588.     int        sclass;        /* starting class */
  2589.  
  2590. #ifdef FEAT_VIRTUALEDIT
  2591.     curwin->w_cursor.coladd = 0;
  2592. #endif
  2593.     cls_bigword = bigword;
  2594.     while (--count >= 0)
  2595.     {
  2596. #ifdef FEAT_FOLDING
  2597.     /* When inside a range of folded lines, move to the first char of the
  2598.      * first line. */
  2599.     if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL))
  2600.         curwin->w_cursor.col = 0;
  2601. #endif
  2602.     sclass = cls();
  2603.     if (dec_cursor() == -1)        /* started at start of file */
  2604.         return FAIL;
  2605.  
  2606.     if (!stop || sclass == cls() || sclass == 0)
  2607.     {
  2608.         /*
  2609.          * Skip white space before the word.
  2610.          * Stop on an empty line.
  2611.          */
  2612.         while (cls() == 0)
  2613.         {
  2614.         if (curwin->w_cursor.col == 0
  2615.                       && lineempty(curwin->w_cursor.lnum))
  2616.             goto finished;
  2617.         if (dec_cursor() == -1) /* hit start of file, stop here */
  2618.             return OK;
  2619.         }
  2620.  
  2621.         /*
  2622.          * Move backward to start of this word.
  2623.          */
  2624.         if (skip_chars(cls(), BACKWARD))
  2625.         return OK;
  2626.     }
  2627.  
  2628.     inc_cursor();            /* overshot - forward one */
  2629. finished:
  2630.     stop = FALSE;
  2631.     }
  2632.     return OK;
  2633. }
  2634.  
  2635. /*
  2636.  * end_word() - move to the end of the word
  2637.  *
  2638.  * There is an apparent bug in the 'e' motion of the real vi. At least on the
  2639.  * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
  2640.  * motion crosses blank lines. When the real vi crosses a blank line in an
  2641.  * 'e' motion, the cursor is placed on the FIRST character of the next
  2642.  * non-blank line. The 'E' command, however, works correctly. Since this
  2643.  * appears to be a bug, I have not duplicated it here.
  2644.  *
  2645.  * Returns FAIL if end of the file was reached.
  2646.  *
  2647.  * If stop is TRUE and we are already on the end of a word, move one less.
  2648.  * If empty is TRUE stop on an empty line.
  2649.  */
  2650.     int
  2651. end_word(count, bigword, stop, empty)
  2652.     long    count;
  2653.     int        bigword;
  2654.     int        stop;
  2655.     int        empty;
  2656. {
  2657.     int        sclass;        /* starting class */
  2658.  
  2659. #ifdef FEAT_VIRTUALEDIT
  2660.     curwin->w_cursor.coladd = 0;
  2661. #endif
  2662.     cls_bigword = bigword;
  2663.     while (--count >= 0)
  2664.     {
  2665. #ifdef FEAT_FOLDING
  2666.     /* When inside a range of folded lines, move to the last char of the
  2667.      * last line. */
  2668.     if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
  2669.         coladvance((colnr_T)MAXCOL);
  2670. #endif
  2671.     sclass = cls();
  2672.     if (inc_cursor() == -1)
  2673.         return FAIL;
  2674.  
  2675.     /*
  2676.      * If we're in the middle of a word, we just have to move to the end
  2677.      * of it.
  2678.      */
  2679.     if (cls() == sclass && sclass != 0)
  2680.     {
  2681.         /*
  2682.          * Move forward to end of the current word
  2683.          */
  2684.         if (skip_chars(sclass, FORWARD))
  2685.         return FAIL;
  2686.     }
  2687.     else if (!stop || sclass == 0)
  2688.     {
  2689.         /*
  2690.          * We were at the end of a word. Go to the end of the next word.
  2691.          * First skip white space, if 'empty' is TRUE, stop at empty line.
  2692.          */
  2693.         while (cls() == 0)
  2694.         {
  2695.         if (empty && curwin->w_cursor.col == 0
  2696.                       && lineempty(curwin->w_cursor.lnum))
  2697.             goto finished;
  2698.         if (inc_cursor() == -1)        /* hit end of file, stop here */
  2699.             return FAIL;
  2700.         }
  2701.  
  2702.         /*
  2703.          * Move forward to the end of this word.
  2704.          */
  2705.         if (skip_chars(cls(), FORWARD))
  2706.         return FAIL;
  2707.     }
  2708.     dec_cursor();            /* overshot - one char backward */
  2709. finished:
  2710.     stop = FALSE;            /* we move only one word less */
  2711.     }
  2712.     return OK;
  2713. }
  2714.  
  2715. /*
  2716.  * Move back to the end of the word.
  2717.  *
  2718.  * Returns FAIL if start of the file was reached.
  2719.  */
  2720.     int
  2721. bckend_word(count, bigword, eol)
  2722.     long    count;
  2723.     int        bigword;    /* TRUE for "B" */
  2724.     int        eol;        /* TRUE: stop at end of line. */
  2725. {
  2726.     int        sclass;        /* starting class */
  2727.     int        i;
  2728.  
  2729. #ifdef FEAT_VIRTUALEDIT
  2730.     curwin->w_cursor.coladd = 0;
  2731. #endif
  2732.     cls_bigword = bigword;
  2733.     while (--count >= 0)
  2734.     {
  2735.     sclass = cls();
  2736.     if ((i = dec_cursor()) == -1)
  2737.         return FAIL;
  2738.     if (eol && i == 1)
  2739.         return OK;
  2740.  
  2741.     /*
  2742.      * Move backward to before the start of this word.
  2743.      */
  2744.     if (sclass != 0)
  2745.     {
  2746.         while (cls() == sclass)
  2747.         if ((i = dec_cursor()) == -1 || (eol && i == 1))
  2748.             return OK;
  2749.     }
  2750.  
  2751.     /*
  2752.      * Move backward to end of the previous word
  2753.      */
  2754.     while (cls() == 0)
  2755.     {
  2756.         if (curwin->w_cursor.col == 0 && lineempty(curwin->w_cursor.lnum))
  2757.         break;
  2758.         if ((i = dec_cursor()) == -1 || (eol && i == 1))
  2759.         return OK;
  2760.     }
  2761.     }
  2762.     return OK;
  2763. }
  2764.  
  2765. /*
  2766.  * Skip a row of characters of the same class.
  2767.  * Return TRUE when end-of-file reached, FALSE otherwise.
  2768.  */
  2769.     static int
  2770. skip_chars(cclass, dir)
  2771.     int        cclass;
  2772.     int        dir;
  2773. {
  2774.     while (cls() == cclass)
  2775.     if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
  2776.         return TRUE;
  2777.     return FALSE;
  2778. }
  2779.  
  2780. #ifdef FEAT_TEXTOBJ
  2781. /*
  2782.  * Go back to the start of the word or the start of white space
  2783.  */
  2784.     static void
  2785. back_in_line()
  2786. {
  2787.     int        sclass;            /* starting class */
  2788.  
  2789.     sclass = cls();
  2790.     for (;;)
  2791.     {
  2792.     if (curwin->w_cursor.col == 0)        /* stop at start of line */
  2793.         break;
  2794.     dec_cursor();
  2795.     if (cls() != sclass)            /* stop at start of word */
  2796.     {
  2797.         inc_cursor();
  2798.         break;
  2799.     }
  2800.     }
  2801. }
  2802.  
  2803.     static void
  2804. find_first_blank(posp)
  2805.     pos_T    *posp;
  2806. {
  2807.     int        c;
  2808.  
  2809.     while (decl(posp) != -1)
  2810.     {
  2811.     c = gchar_pos(posp);
  2812.     if (!vim_iswhite(c))
  2813.     {
  2814.         incl(posp);
  2815.         break;
  2816.     }
  2817.     }
  2818. }
  2819.  
  2820. /*
  2821.  * Skip count/2 sentences and count/2 separating white spaces.
  2822.  */
  2823.     static void
  2824. findsent_forward(count, at_start_sent)
  2825.     long    count;
  2826.     int        at_start_sent;    /* cursor is at start of sentence */
  2827. {
  2828.     while (count--)
  2829.     {
  2830.     findsent(FORWARD, 1L);
  2831.     if (at_start_sent)
  2832.         find_first_blank(&curwin->w_cursor);
  2833.     if (count == 0 || at_start_sent)
  2834.         decl(&curwin->w_cursor);
  2835.     at_start_sent = !at_start_sent;
  2836.     }
  2837. }
  2838.  
  2839. /*
  2840.  * Find word under cursor, cursor at end.
  2841.  * Used while an operator is pending, and in Visual mode.
  2842.  */
  2843.     int
  2844. current_word(oap, count, include, bigword)
  2845.     oparg_T    *oap;
  2846.     long    count;
  2847.     int        include;    /* TRUE: include word and white space */
  2848.     int        bigword;    /* FALSE == word, TRUE == WORD */
  2849. {
  2850.     pos_T    start_pos;
  2851.     pos_T    pos;
  2852.     int        inclusive = TRUE;
  2853.  
  2854.     cls_bigword = bigword;
  2855.  
  2856. #ifdef FEAT_VISUAL
  2857.     /* Correct cursor when 'selection' is exclusive */
  2858.     if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor))
  2859.     dec_cursor();
  2860.  
  2861.     /*
  2862.      * When Visual mode is not active, or when the VIsual area is only one
  2863.      * character, select the word and/or white space under the cursor.
  2864.      */
  2865.     if (!VIsual_active || equal(curwin->w_cursor, VIsual))
  2866. #endif
  2867.     {
  2868.     /*
  2869.      * Go to start of current word or white space.
  2870.      */
  2871.     back_in_line();
  2872.     start_pos = curwin->w_cursor;
  2873.  
  2874.     /*
  2875.      * If the start is on white space, and white space should be included
  2876.      * ("    word"), or start is not on white space, and white space should
  2877.      * not be included ("word"), find end of word.
  2878.      */
  2879.     if ((cls() == 0) == include)
  2880.     {
  2881.         if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
  2882.         return FAIL;
  2883.     }
  2884.     else
  2885.     {
  2886.         /*
  2887.          * If the start is not on white space, and white space should be
  2888.          * included ("word     "), or start is on white space and white
  2889.          * space should not be included ("     "), find start of word.
  2890.          * If we end up in the first column of the next line (single char
  2891.          * word) back up to end of the line.
  2892.          */
  2893.         fwd_word(1L, bigword, TRUE);
  2894.         if (curwin->w_cursor.col == 0)
  2895.         decl(&curwin->w_cursor);
  2896.         else
  2897.         oneleft();
  2898.  
  2899.         if (include)
  2900.         {
  2901.         /*
  2902.          * If we don't include white space at the end, move the start
  2903.          * to include some white space there. This makes "daw" work
  2904.          * better on the last word in a sentence. Don't delete white
  2905.          * space at start of line (indent).
  2906.          */
  2907.         if (cls() != 0)
  2908.         {
  2909.             pos = curwin->w_cursor;    /* save cursor position */
  2910.             curwin->w_cursor = start_pos;
  2911.             if (oneleft() == OK)
  2912.             {
  2913.             back_in_line();
  2914.             if (cls() == 0 && curwin->w_cursor.col > 0)
  2915.                 start_pos = curwin->w_cursor;
  2916.             }
  2917.             curwin->w_cursor = pos;    /* put cursor back at end */
  2918.         }
  2919.         }
  2920.     }
  2921.  
  2922. #ifdef FEAT_VISUAL
  2923.     if (VIsual_active)
  2924.     {
  2925.         /* should do something when inclusive == FALSE ! */
  2926.         VIsual = start_pos;
  2927.         redraw_curbuf_later(INVERTED);    /* update the inversion */
  2928.     }
  2929.     else
  2930. #endif
  2931.     {
  2932.         oap->start = start_pos;
  2933.         oap->motion_type = MCHAR;
  2934.     }
  2935.     --count;
  2936.     }
  2937.  
  2938.     /*
  2939.      * When count is still > 0, extend with more objects.
  2940.      */
  2941.     while (count > 0)
  2942.     {
  2943.     inclusive = TRUE;
  2944. #ifdef FEAT_VISUAL
  2945.     if (VIsual_active && lt(curwin->w_cursor, VIsual))
  2946.     {
  2947.         /*
  2948.          * In Visual mode, with cursor at start: move cursor back.
  2949.          */
  2950.         if (decl(&curwin->w_cursor) == -1)
  2951.         return FAIL;
  2952.         if (include != (cls() != 0))
  2953.         {
  2954.         if (bck_word(1L, bigword, TRUE) == FAIL)
  2955.             return FAIL;
  2956.         }
  2957.         else
  2958.         {
  2959.         if (bckend_word(1L, bigword, TRUE) == FAIL)
  2960.             return FAIL;
  2961.         (void)incl(&curwin->w_cursor);
  2962.         }
  2963.     }
  2964.     else
  2965. #endif
  2966.     {
  2967.         /*
  2968.          * Move cursor forward one word and/or white area.
  2969.          */
  2970.         if (incl(&curwin->w_cursor) == -1)
  2971.         return FAIL;
  2972.         if (include != (cls() == 0))
  2973.         {
  2974.         if (fwd_word(1L, bigword, TRUE) == FAIL)
  2975.             return FAIL;
  2976.         /*
  2977.          * If end is just past a new-line, we don't want to include
  2978.          * the first character on the line
  2979.          */
  2980.         if (oneleft() == FAIL)    /* put cursor on last char of white */
  2981.             inclusive = FALSE;
  2982.         }
  2983.         else
  2984.         {
  2985.         if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
  2986.             return FAIL;
  2987.         }
  2988.     }
  2989.     --count;
  2990.     }
  2991. #ifdef FEAT_VISUAL
  2992.     if (VIsual_active)
  2993.     {
  2994.     if (*p_sel == 'e' && inclusive && ltoreq(VIsual, curwin->w_cursor))
  2995.         inc_cursor();
  2996.     if (VIsual_mode == 'V')
  2997.     {
  2998.         VIsual_mode = 'v';
  2999.         redraw_cmdline = TRUE;        /* show mode later */
  3000.     }
  3001.     }
  3002.     else
  3003. #endif
  3004.     oap->inclusive = inclusive;
  3005.  
  3006.     return OK;
  3007. }
  3008.  
  3009. /*
  3010.  * Find sentence(s) under the cursor, cursor at end.
  3011.  * When Visual active, extend it by one or more sentences.
  3012.  */
  3013.     int
  3014. current_sent(oap, count, include)
  3015.     oparg_T    *oap;
  3016.     long    count;
  3017.     int        include;
  3018. {
  3019.     pos_T    start_pos;
  3020.     pos_T    pos;
  3021.     int        start_blank;
  3022.     int        c;
  3023.     int        at_start_sent;
  3024.     long    ncount;
  3025.  
  3026.     start_pos = curwin->w_cursor;
  3027.     pos = start_pos;
  3028.     findsent(FORWARD, 1L);    /* Find start of next sentence. */
  3029.  
  3030. #ifdef FEAT_VISUAL
  3031.     /*
  3032.      * When visual area is bigger than one character: Extend it.
  3033.      */
  3034.     if (VIsual_active && !equal(start_pos, VIsual))
  3035.     {
  3036. extend:
  3037.     if (lt(start_pos, VIsual))
  3038.     {
  3039.         /*
  3040.          * Cursor at start of Visual area.
  3041.          * Find out where we are:
  3042.          * - in the white space before a sentence
  3043.          * - in a sentence or just after it
  3044.          * - at the start of a sentence
  3045.          */
  3046.         at_start_sent = TRUE;
  3047.         decl(&pos);
  3048.         while (lt(pos, curwin->w_cursor))
  3049.         {
  3050.         c = gchar_pos(&pos);
  3051.         if (!vim_iswhite(c))
  3052.         {
  3053.             at_start_sent = FALSE;
  3054.             break;
  3055.         }
  3056.         incl(&pos);
  3057.         }
  3058.         if (!at_start_sent)
  3059.         {
  3060.         findsent(BACKWARD, 1L);
  3061.         if (equal(curwin->w_cursor, start_pos))
  3062.             at_start_sent = TRUE;  /* exactly at start of sentence */
  3063.         else
  3064.             /* inside a sentence, go to its end (start of next) */
  3065.             findsent(FORWARD, 1L);
  3066.         }
  3067.         if (include)    /* "as" gets twice as much as "is" */
  3068.         count *= 2;
  3069.         while (count--)
  3070.         {
  3071.         if (at_start_sent)
  3072.             find_first_blank(&curwin->w_cursor);
  3073.         c = gchar_cursor();
  3074.         if (!at_start_sent || (!include && !vim_iswhite(c)))
  3075.             findsent(BACKWARD, 1L);
  3076.         at_start_sent = !at_start_sent;
  3077.         }
  3078.     }
  3079.     else
  3080.     {
  3081.         /*
  3082.          * Cursor at end of Visual area.
  3083.          * Find out where we are:
  3084.          * - just before a sentence
  3085.          * - just before or in the white space before a sentence
  3086.          * - in a sentence
  3087.          */
  3088.         incl(&pos);
  3089.         at_start_sent = TRUE;
  3090.         if (!equal(pos, curwin->w_cursor))    /* not just before a sentence */
  3091.         {
  3092.         at_start_sent = FALSE;
  3093.         while (lt(pos, curwin->w_cursor))
  3094.         {
  3095.             c = gchar_pos(&pos);
  3096.             if (!vim_iswhite(c))
  3097.             {
  3098.             at_start_sent = TRUE;
  3099.             break;
  3100.             }
  3101.             incl(&pos);
  3102.         }
  3103.         if (at_start_sent)    /* in the sentence */
  3104.             findsent(BACKWARD, 1L);
  3105.         else        /* in/before white before a sentence */
  3106.             curwin->w_cursor = start_pos;
  3107.         }
  3108.  
  3109.         if (include)    /* "as" gets twice as much as "is" */
  3110.         count *= 2;
  3111.         findsent_forward(count, at_start_sent);
  3112.         if (*p_sel == 'e')
  3113.         ++curwin->w_cursor.col;
  3114.     }
  3115.     return OK;
  3116.     }
  3117. #endif
  3118.  
  3119.     /*
  3120.      * If cursor started on blank, check if it is just before the start of the
  3121.      * next sentence.
  3122.      */
  3123.     while (c = gchar_pos(&pos), vim_iswhite(c))    /* vim_iswhite() is a macro */
  3124.     incl(&pos);
  3125.     if (equal(pos, curwin->w_cursor))
  3126.     {
  3127.     start_blank = TRUE;
  3128.     find_first_blank(&start_pos);    /* go back to first blank */
  3129.     }
  3130.     else
  3131.     {
  3132.     start_blank = FALSE;
  3133.     findsent(BACKWARD, 1L);
  3134.     start_pos = curwin->w_cursor;
  3135.     }
  3136.     if (include)
  3137.     ncount = count * 2;
  3138.     else
  3139.     {
  3140.     ncount = count;
  3141.     if (start_blank)
  3142.         --ncount;
  3143.     }
  3144.     if (ncount)
  3145.     findsent_forward(ncount, TRUE);
  3146.     else
  3147.     decl(&curwin->w_cursor);
  3148.  
  3149.     if (include)
  3150.     {
  3151.     /*
  3152.      * If the blank in front of the sentence is included, exclude the
  3153.      * blanks at the end of the sentence, go back to the first blank.
  3154.      * If there are no trailing blanks, try to include leading blanks.
  3155.      */
  3156.     if (start_blank)
  3157.     {
  3158.         find_first_blank(&curwin->w_cursor);
  3159.         c = gchar_pos(&curwin->w_cursor);    /* vim_iswhite() is a macro */
  3160.         if (vim_iswhite(c))
  3161.         decl(&curwin->w_cursor);
  3162.     }
  3163.     else if (c = gchar_cursor(), !vim_iswhite(c))
  3164.         find_first_blank(&start_pos);
  3165.     }
  3166.  
  3167. #ifdef FEAT_VISUAL
  3168.     if (VIsual_active)
  3169.     {
  3170.     /* avoid getting stuck with "is" on a single space before a sent. */
  3171.     if (equal(start_pos, curwin->w_cursor))
  3172.         goto extend;
  3173.     if (*p_sel == 'e')
  3174.         ++curwin->w_cursor.col;
  3175.     VIsual = start_pos;
  3176.     VIsual_mode = 'v';
  3177.     redraw_curbuf_later(INVERTED);    /* update the inversion */
  3178.     }
  3179.     else
  3180. #endif
  3181.     {
  3182.     /* include a newline after the sentence, if there is one */
  3183.     if (incl(&curwin->w_cursor) == -1)
  3184.         oap->inclusive = TRUE;
  3185.     else
  3186.         oap->inclusive = FALSE;
  3187.     oap->start = start_pos;
  3188.     oap->motion_type = MCHAR;
  3189.     }
  3190.     return OK;
  3191. }
  3192.  
  3193.     int
  3194. current_block(oap, count, include, what, other)
  3195.     oparg_T    *oap;
  3196.     long    count;
  3197.     int        include;    /* TRUE == include white space */
  3198.     int        what;        /* '(', '{', etc. */
  3199.     int        other;        /* ')', '}', etc. */
  3200. {
  3201.     pos_T    old_pos;
  3202.     pos_T    *pos = NULL;
  3203.     pos_T    start_pos;
  3204.     pos_T    *end_pos;
  3205.     pos_T    old_start, old_end;
  3206.     char_u    *save_cpo;
  3207.     int        sol = FALSE;    /* { at start of line */
  3208.  
  3209.     old_pos = curwin->w_cursor;
  3210.     old_end = curwin->w_cursor;            /* remember where we started */
  3211.     old_start = old_end;
  3212.  
  3213.     /*
  3214.      * If we start on '(', '{', ')', '}', etc., use the whole block inclusive.
  3215.      */
  3216. #ifdef FEAT_VISUAL
  3217.     if (!VIsual_active || equal(VIsual, curwin->w_cursor))
  3218. #endif
  3219.     {
  3220.     setpcmark();
  3221.     if (what == '{')            /* ignore indent */
  3222.         while (inindent(1))
  3223.         if (inc_cursor() != 0)
  3224.             break;
  3225.     if (gchar_cursor() == what)        /* cursor on '(' or '{' */
  3226.         ++curwin->w_cursor.col;
  3227.     }
  3228. #ifdef FEAT_VISUAL
  3229.     else if (lt(VIsual, curwin->w_cursor))
  3230.     {
  3231.     old_start = VIsual;
  3232.     curwin->w_cursor = VIsual;        /* cursor at low end of Visual */
  3233.     }
  3234.     else
  3235.     old_end = VIsual;
  3236. #endif
  3237.  
  3238.     /*
  3239.      * Search backwards for unclosed '(', '{', etc..
  3240.      * Put this position in start_pos.
  3241.      * Ignory quotes here.
  3242.      */
  3243.     save_cpo = p_cpo;
  3244.     p_cpo = (char_u *)"%";
  3245.     while (count-- > 0)
  3246.     {
  3247.     if ((pos = findmatch(NULL, what)) == NULL)
  3248.         break;
  3249.     curwin->w_cursor = *pos;
  3250.     start_pos = *pos;   /* the findmatch for end_pos will overwrite *pos */
  3251.     }
  3252.     p_cpo = save_cpo;
  3253.  
  3254.     /*
  3255.      * Search for matching ')', '}', etc.
  3256.      * Put this position in curwin->w_cursor.
  3257.      */
  3258.     if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL)
  3259.     {
  3260.     curwin->w_cursor = old_pos;
  3261.     return FAIL;
  3262.     }
  3263.     curwin->w_cursor = *end_pos;
  3264.  
  3265.     /*
  3266.      * Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE.
  3267.      * If the ending '}' is only preceded by indent, skip that indent.
  3268.      * But only if the resulting area is not smaller than what we started with.
  3269.      */
  3270.     while (!include)
  3271.     {
  3272.     incl(&start_pos);
  3273.     sol = (curwin->w_cursor.col == 0);
  3274.     decl(&curwin->w_cursor);
  3275.     if (what == '{')
  3276.         while (inindent(1))
  3277.         {
  3278.         sol = TRUE;
  3279.         if (decl(&curwin->w_cursor) != 0)
  3280.             break;
  3281.         }
  3282. #ifdef FEAT_VISUAL
  3283.     /*
  3284.      * In Visual mode, when the resulting area is not bigger than what we
  3285.      * started with, extend it to the next block, and then exclude again.
  3286.      */
  3287.     if (!lt(start_pos, old_start) && !lt(old_end, curwin->w_cursor)
  3288.         && VIsual_active)
  3289.     {
  3290.         curwin->w_cursor = old_start;
  3291.         decl(&curwin->w_cursor);
  3292.         if ((pos = findmatch(NULL, what)) == NULL)
  3293.         {
  3294.         curwin->w_cursor = old_pos;
  3295.         return FAIL;
  3296.         }
  3297.         start_pos = *pos;
  3298.         curwin->w_cursor = *pos;
  3299.         if ((end_pos = findmatch(NULL, other)) == NULL)
  3300.         {
  3301.         curwin->w_cursor = old_pos;
  3302.         return FAIL;
  3303.         }
  3304.         curwin->w_cursor = *end_pos;
  3305.     }
  3306.     else
  3307. #endif
  3308.         break;
  3309.     }
  3310.  
  3311. #ifdef FEAT_VISUAL
  3312.     if (VIsual_active)
  3313.     {
  3314.     if (*p_sel == 'e')
  3315.         ++curwin->w_cursor.col;
  3316.     if (sol)
  3317.         inc(&curwin->w_cursor);    /* include the line break */
  3318.     VIsual = start_pos;
  3319.     VIsual_mode = 'v';
  3320.     redraw_curbuf_later(INVERTED);    /* update the inversion */
  3321.     showmode();
  3322.     }
  3323.     else
  3324. #endif
  3325.     {
  3326.     oap->start = start_pos;
  3327.     oap->motion_type = MCHAR;
  3328.     if (sol)
  3329.     {
  3330.         incl(&curwin->w_cursor);
  3331.         oap->inclusive = FALSE;
  3332.     }
  3333.     else
  3334.         oap->inclusive = TRUE;
  3335.     }
  3336.  
  3337.     return OK;
  3338. }
  3339.  
  3340.     int
  3341. current_par(oap, count, include, type)
  3342.     oparg_T    *oap;
  3343.     long    count;
  3344.     int        include;    /* TRUE == include white space */
  3345.     int        type;        /* 'p' for paragraph, 'S' for section */
  3346. {
  3347.     linenr_T    start_lnum;
  3348.     linenr_T    end_lnum;
  3349.     int        white_in_front;
  3350.     int        dir;
  3351.     int        start_is_white;
  3352.     int        prev_start_is_white;
  3353.     int        retval = OK;
  3354.     int        do_white = FALSE;
  3355.     int        t;
  3356.     int        i;
  3357.  
  3358.     if (type == 'S')        /* not implemented yet */
  3359.     return FAIL;
  3360.  
  3361.     start_lnum = curwin->w_cursor.lnum;
  3362.  
  3363. #ifdef FEAT_VISUAL
  3364.     /*
  3365.      * When visual area is more than one line: extend it.
  3366.      */
  3367.     if (VIsual_active && start_lnum != VIsual.lnum)
  3368.     {
  3369. extend:
  3370.     if (start_lnum < VIsual.lnum)
  3371.         dir = BACKWARD;
  3372.     else
  3373.         dir = FORWARD;
  3374.     for (i = count; --i >= 0; )
  3375.     {
  3376.         if (start_lnum ==
  3377.                (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count))
  3378.         {
  3379.         retval = FAIL;
  3380.         break;
  3381.         }
  3382.  
  3383.         prev_start_is_white = -1;
  3384.         for (t = 0; t < 2; ++t)
  3385.         {
  3386.         start_lnum += dir;
  3387.         start_is_white = linewhite(start_lnum);
  3388.         if (prev_start_is_white == start_is_white)
  3389.         {
  3390.             start_lnum -= dir;
  3391.             break;
  3392.         }
  3393.         for (;;)
  3394.         {
  3395.             if (start_lnum == (dir == BACKWARD
  3396.                         ? 1 : curbuf->b_ml.ml_line_count))
  3397.             break;
  3398.             if (start_is_white != linewhite(start_lnum + dir)
  3399.                 || (!start_is_white
  3400.                     && startPS(start_lnum + (dir > 0
  3401.                                  ? 1 : 0), 0, 0)))
  3402.             break;
  3403.             start_lnum += dir;
  3404.         }
  3405.         if (!include)
  3406.             break;
  3407.         if (start_lnum == (dir == BACKWARD
  3408.                         ? 1 : curbuf->b_ml.ml_line_count))
  3409.             break;
  3410.         prev_start_is_white = start_is_white;
  3411.         }
  3412.     }
  3413.     curwin->w_cursor.lnum = start_lnum;
  3414.     curwin->w_cursor.col = 0;
  3415.     return retval;
  3416.     }
  3417. #endif
  3418.  
  3419.     /*
  3420.      * First move back to the start_lnum of the paragraph or white lines
  3421.      */
  3422.     white_in_front = linewhite(start_lnum);
  3423.     while (start_lnum > 1)
  3424.     {
  3425.     if (white_in_front)        /* stop at first white line */
  3426.     {
  3427.         if (!linewhite(start_lnum - 1))
  3428.         break;
  3429.     }
  3430.     else        /* stop at first non-white line of start of paragraph */
  3431.     {
  3432.         if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0))
  3433.         break;
  3434.     }
  3435.     --start_lnum;
  3436.     }
  3437.  
  3438.     /*
  3439.      * Move past the end of any white lines.
  3440.      */
  3441.     end_lnum = start_lnum;
  3442.     while (linewhite(end_lnum) && end_lnum < curbuf->b_ml.ml_line_count)
  3443.         ++end_lnum;
  3444.  
  3445.     --end_lnum;
  3446.     i = count;
  3447.     if (!include && white_in_front)
  3448.     --i;
  3449.     while (i--)
  3450.     {
  3451.     if (end_lnum == curbuf->b_ml.ml_line_count)
  3452.         return FAIL;
  3453.  
  3454.     if (!include)
  3455.         do_white = linewhite(end_lnum + 1);
  3456.  
  3457.     if (include || !do_white)
  3458.     {
  3459.         ++end_lnum;
  3460.         /*
  3461.          * skip to end of paragraph
  3462.          */
  3463.         while (end_lnum < curbuf->b_ml.ml_line_count
  3464.             && !linewhite(end_lnum + 1)
  3465.             && !startPS(end_lnum + 1, 0, 0))
  3466.         ++end_lnum;
  3467.     }
  3468.  
  3469.     if (i == 0 && white_in_front)
  3470.         break;
  3471.  
  3472.     /*
  3473.      * skip to end of white lines after paragraph
  3474.      */
  3475.     if (include || do_white)
  3476.         while (end_lnum < curbuf->b_ml.ml_line_count
  3477.                            && linewhite(end_lnum + 1))
  3478.         ++end_lnum;
  3479.     }
  3480.  
  3481.     /*
  3482.      * If there are no empty lines at the end, try to find some empty lines at
  3483.      * the start (unless that has been done already).
  3484.      */
  3485.     if (!white_in_front && !linewhite(end_lnum) && include)
  3486.     while (start_lnum > 1 && linewhite(start_lnum - 1))
  3487.         --start_lnum;
  3488.  
  3489. #ifdef FEAT_VISUAL
  3490.     if (VIsual_active)
  3491.     {
  3492.     /* Problem: when doing "Vipipip" nothing happens in a single white
  3493.      * line, we get stuck there.  Trap this here. */
  3494.     if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum)
  3495.         goto extend;
  3496.     VIsual.lnum = start_lnum;
  3497.     VIsual_mode = 'V';
  3498.     redraw_curbuf_later(INVERTED);    /* update the inversion */
  3499.     showmode();
  3500.     }
  3501.     else
  3502. #endif
  3503.     {
  3504.     oap->start.lnum = start_lnum;
  3505.     oap->motion_type = MLINE;
  3506.     }
  3507.     curwin->w_cursor.lnum = end_lnum;
  3508.     curwin->w_cursor.col = 0;
  3509.  
  3510.     return OK;
  3511. }
  3512. #endif
  3513.  
  3514. #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(FEAT_TEXTOBJ) \
  3515.     || defined(PROTO)
  3516. /*
  3517.  * return TRUE if line 'lnum' is empty or has white chars only.
  3518.  */
  3519.     int
  3520. linewhite(lnum)
  3521.     linenr_T    lnum;
  3522. {
  3523.     char_u  *p;
  3524.  
  3525.     p = skipwhite(ml_get(lnum));
  3526.     return (*p == NUL);
  3527. }
  3528. #endif
  3529.  
  3530. #if defined(FEAT_FIND_ID) || defined(PROTO)
  3531. /*
  3532.  * Find identifiers or defines in included files.
  3533.  * if p_ic && (continue_status & CONT_SOL) then ptr must be in lowercase.
  3534.  */
  3535. /*ARGSUSED*/
  3536.     void
  3537. find_pattern_in_path(ptr, dir, len, whole, skip_comments,
  3538.                     type, count, action, start_lnum, end_lnum)
  3539.     char_u    *ptr;        /* pointer to search pattern */
  3540.     int        dir;        /* direction of expansion */
  3541.     int        len;        /* length of search pattern */
  3542.     int        whole;        /* match whole words only */
  3543.     int        skip_comments;    /* don't match inside comments */
  3544.     int        type;        /* Type of search; are we looking for a type?
  3545.                    a macro? */
  3546.     long    count;
  3547.     int        action;        /* What to do when we find it */
  3548.     linenr_T    start_lnum;    /* first line to start searching */
  3549.     linenr_T    end_lnum;    /* last line for searching */
  3550. {
  3551.     SearchedFile *files;        /* Stack of included files */
  3552.     SearchedFile *bigger;        /* When we need more space */
  3553.     int        max_path_depth = 50;
  3554.     long    match_count = 1;
  3555.  
  3556.     char_u    *pat;
  3557.     char_u    *new_fname;
  3558.     char_u    *curr_fname = curbuf->b_fname;
  3559.     char_u    *prev_fname = NULL;
  3560.     linenr_T    lnum;
  3561.     int        depth;
  3562.     int        depth_displayed;    /* For type==CHECK_PATH */
  3563.     int        old_files;
  3564.     int        already_searched;
  3565.     char_u    *file_line;
  3566.     char_u    *line;
  3567.     char_u    *p;
  3568.     char_u    save_char;
  3569.     int        define_matched;
  3570.     regmatch_T    regmatch;
  3571.     regmatch_T    incl_regmatch;
  3572.     regmatch_T    def_regmatch;
  3573.     int        matched = FALSE;
  3574.     int        did_show = FALSE;
  3575.     int        found = FALSE;
  3576.     int        i;
  3577.     char_u    *already = NULL;
  3578.     char_u    *startp = NULL;
  3579. #ifdef RISCOS
  3580.     int        previous_munging = __riscosify_control;
  3581. #endif
  3582. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  3583.     win_T    *curwin_save = NULL;
  3584. #endif
  3585.  
  3586.     regmatch.regprog = NULL;
  3587.     incl_regmatch.regprog = NULL;
  3588.     def_regmatch.regprog = NULL;
  3589.  
  3590.     file_line = alloc(LSIZE);
  3591.     if (file_line == NULL)
  3592.     return;
  3593.  
  3594. #ifdef RISCOS
  3595.     /* UnixLib knows best how to munge c file names - turn munging back on. */
  3596.     __riscosify_control = __RISCOSIFY_LONG_TRUNCATE;
  3597. #endif
  3598.  
  3599.     if (type != CHECK_PATH && type != FIND_DEFINE
  3600. #ifdef FEAT_INS_EXPAND
  3601.     /* when CONT_SOL is set compare "ptr" with the beginning of the line
  3602.      * is faster than quote_meta/regcomp/regexec "ptr" -- Acevedo */
  3603.         && !(continue_status & CONT_SOL)
  3604. #endif
  3605.        )
  3606.     {
  3607.     pat = alloc(len + 5);
  3608.     if (pat == NULL)
  3609.         goto fpip_end;
  3610.     sprintf((char *)pat, whole ? "\\<%.*s\\>" : "%.*s", len, ptr);
  3611.     /* ignore case according to p_ic, p_scs and pat */
  3612.     regmatch.rm_ic = ignorecase(pat);
  3613.     regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
  3614.     vim_free(pat);
  3615.     if (regmatch.regprog == NULL)
  3616.         goto fpip_end;
  3617.     }
  3618.     if (*curbuf->b_p_inc != NUL || *p_inc != NUL)
  3619.     {
  3620.     incl_regmatch.regprog = vim_regcomp(*curbuf->b_p_inc == NUL
  3621.                ? p_inc : curbuf->b_p_inc, p_magic ? RE_MAGIC : 0);
  3622.     if (incl_regmatch.regprog == NULL)
  3623.         goto fpip_end;
  3624.     incl_regmatch.rm_ic = FALSE;    /* don't ignore case in incl. pat. */
  3625.     }
  3626.     if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL))
  3627.     {
  3628.     def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL
  3629.                ? p_def : curbuf->b_p_def, p_magic ? RE_MAGIC : 0);
  3630.     if (def_regmatch.regprog == NULL)
  3631.         goto fpip_end;
  3632.     def_regmatch.rm_ic = FALSE;    /* don't ignore case in define pat. */
  3633.     }
  3634.     files = (SearchedFile *)lalloc((long_u)
  3635.                    (max_path_depth * sizeof(SearchedFile)), TRUE);
  3636.     if (files == NULL)
  3637.     goto fpip_end;
  3638.     for (i = 0; i < max_path_depth; i++)
  3639.     {
  3640.     files[i].fp = NULL;
  3641.     files[i].name = NULL;
  3642.     files[i].lnum = 0;
  3643.     files[i].matched = FALSE;
  3644.     }
  3645.     old_files = max_path_depth;
  3646.     depth = depth_displayed = -1;
  3647.  
  3648.     lnum = start_lnum;
  3649.     if (end_lnum > curbuf->b_ml.ml_line_count)
  3650.     end_lnum = curbuf->b_ml.ml_line_count;
  3651.     if (lnum > end_lnum)        /* do at least one line */
  3652.     lnum = end_lnum;
  3653.     line = ml_get(lnum);
  3654.  
  3655.     for (;;)
  3656.     {
  3657.     if (incl_regmatch.regprog != NULL
  3658.         && vim_regexec(&incl_regmatch, line, (colnr_T)0))
  3659.     {
  3660.         new_fname = file_name_in_line(incl_regmatch.endp[0],
  3661.             0, FNAME_EXP|FNAME_INCL|FNAME_REL, 1L,
  3662.             curr_fname == curbuf->b_fname
  3663.                          ? curbuf->b_ffname : curr_fname);
  3664.         already_searched = FALSE;
  3665.         if (new_fname != NULL)
  3666.         {
  3667.         /* Check whether we have already searched in this file */
  3668.         for (i = 0;; i++)
  3669.         {
  3670.             if (i == depth + 1)
  3671.             i = old_files;
  3672.             if (i == max_path_depth)
  3673.             break;
  3674.             if (fullpathcmp(new_fname, files[i].name, TRUE) & FPC_SAME)
  3675.             {
  3676.             if (type != CHECK_PATH &&
  3677.                 action == ACTION_SHOW_ALL && files[i].matched)
  3678.             {
  3679.                 msg_putchar('\n');        /* cursor below last one */
  3680.                 if (!got_int)        /* don't display if 'q'
  3681.                                typed at "--more--"
  3682.                                mesage */
  3683.                 {
  3684.                 msg_home_replace_hl(new_fname);
  3685.                 MSG_PUTS(_(" (includes previously listed match)"));
  3686.                 prev_fname = NULL;
  3687.                 }
  3688.             }
  3689.             vim_free(new_fname);
  3690.             new_fname = NULL;
  3691.             already_searched = TRUE;
  3692.             break;
  3693.             }
  3694.         }
  3695.         }
  3696.  
  3697.         if (type == CHECK_PATH && (action == ACTION_SHOW_ALL
  3698.                  || (new_fname == NULL && !already_searched)))
  3699.         {
  3700.         if (did_show)
  3701.             msg_putchar('\n');        /* cursor below last one */
  3702.         else
  3703.         {
  3704.             gotocmdline(TRUE);        /* cursor at status line */
  3705.             MSG_PUTS_TITLE(_("--- Included files "));
  3706.             if (action != ACTION_SHOW_ALL)
  3707.             MSG_PUTS_TITLE(_("not found "));
  3708.             MSG_PUTS_TITLE(_("in path ---\n"));
  3709.         }
  3710.         did_show = TRUE;
  3711.         while (depth_displayed < depth && !got_int)
  3712.         {
  3713.             ++depth_displayed;
  3714.             for (i = 0; i < depth_displayed; i++)
  3715.             MSG_PUTS("  ");
  3716.             msg_home_replace(files[depth_displayed].name);
  3717.             MSG_PUTS(" -->\n");
  3718.         }
  3719.         if (!got_int)            /* don't display if 'q' typed
  3720.                            for "--more--" message */
  3721.         {
  3722.             for (i = 0; i <= depth_displayed; i++)
  3723.             MSG_PUTS("  ");
  3724.             /*
  3725.              * Isolate the file name.
  3726.              * Include the surrounding "" or <> if present.
  3727.              */
  3728.             for (p = incl_regmatch.endp[0] + 1; !vim_isfilec(*p); p++)
  3729.             ;
  3730.             for (i = 0; vim_isfilec(p[i]); i++)
  3731.             ;
  3732.             if (p[-1] == '"' || p[-1] == '<')
  3733.             {
  3734.             --p;
  3735.             ++i;
  3736.             }
  3737.             if (p[i] == '"' || p[i] == '>')
  3738.             ++i;
  3739.             save_char = p[i];
  3740.             p[i] = NUL;
  3741.                 /* Same highlighting as for directories */
  3742.             msg_outtrans_attr(p, hl_attr(HLF_D));
  3743.             p[i] = save_char;
  3744.             if (new_fname == NULL && action == ACTION_SHOW_ALL)
  3745.             {
  3746.             if (already_searched)
  3747.                 MSG_PUTS(_("  (Already listed)"));
  3748.             else
  3749.                 MSG_PUTS(_("  NOT FOUND"));
  3750.             }
  3751.         }
  3752.         out_flush();        /* output each line directly */
  3753.         }
  3754.  
  3755.         if (new_fname != NULL)
  3756.         {
  3757.         /* Push the new file onto the file stack */
  3758.         if (depth + 1 == old_files)
  3759.         {
  3760.             bigger = (SearchedFile *)lalloc((long_u)(
  3761.                 max_path_depth * 2 * sizeof(SearchedFile)), TRUE);
  3762.             if (bigger != NULL)
  3763.             {
  3764.             for (i = 0; i <= depth; i++)
  3765.                 bigger[i] = files[i];
  3766.             for (i = depth + 1; i < old_files + max_path_depth; i++)
  3767.             {
  3768.                 bigger[i].fp = NULL;
  3769.                 bigger[i].name = NULL;
  3770.                 bigger[i].lnum = 0;
  3771.                 bigger[i].matched = FALSE;
  3772.             }
  3773.             for (i = old_files; i < max_path_depth; i++)
  3774.                 bigger[i + max_path_depth] = files[i];
  3775.             old_files += max_path_depth;
  3776.             max_path_depth *= 2;
  3777.             vim_free(files);
  3778.             files = bigger;
  3779.             }
  3780.         }
  3781.         if ((files[depth + 1].fp = mch_fopen((char *)new_fname, "r"))
  3782.                                     == NULL)
  3783.             vim_free(new_fname);
  3784.         else
  3785.         {
  3786.             if (++depth == old_files)
  3787.             {
  3788.             /*
  3789.              * lalloc() for 'bigger' must have failed above.  We
  3790.              * will forget one of our already visited files now.
  3791.              */
  3792.             vim_free(files[old_files].name);
  3793.             ++old_files;
  3794.             }
  3795.             files[depth].name = curr_fname = new_fname;
  3796.             files[depth].lnum = 0;
  3797.             files[depth].matched = FALSE;
  3798. #ifdef FEAT_INS_EXPAND
  3799.             if (action == ACTION_EXPAND)
  3800.             {
  3801.             sprintf((char*)IObuff, _("Scanning included file: %s"),
  3802.                 (char *)new_fname);
  3803.             msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
  3804.             }
  3805. #endif
  3806.         }
  3807.         }
  3808.     }
  3809.     else
  3810.     {
  3811.         /*
  3812.          * Check if the line is a define (type == FIND_DEFINE)
  3813.          */
  3814.         p = line;
  3815. search_line:
  3816.         define_matched = FALSE;
  3817.         if (def_regmatch.regprog != NULL
  3818.                   && vim_regexec(&def_regmatch, line, (colnr_T)0))
  3819.         {
  3820.         /*
  3821.          * Pattern must be first identifier after 'define', so skip
  3822.          * to that position before checking for match of pattern.  Also
  3823.          * don't let it match beyond the end of this identifier.
  3824.          */
  3825.         p = def_regmatch.endp[0];
  3826.         while (*p && !vim_iswordc(*p))
  3827.             p++;
  3828.         define_matched = TRUE;
  3829.         }
  3830.  
  3831.         /*
  3832.          * Look for a match.  Don't do this if we are looking for a
  3833.          * define and this line didn't match define_prog above.
  3834.          */
  3835.         if (def_regmatch.regprog == NULL || define_matched)
  3836.         {
  3837.         if (define_matched
  3838. #ifdef FEAT_INS_EXPAND
  3839.             || (continue_status & CONT_SOL)
  3840. #endif
  3841.             )
  3842.         {
  3843.             /* compare the first "len" chars from "ptr" */
  3844.             startp = skipwhite(p);
  3845.             if (p_ic)
  3846.             matched = !MB_STRNICMP(startp, ptr, len);
  3847.             else
  3848.             matched = !STRNCMP(startp, ptr, len);
  3849.             if (matched && define_matched && whole
  3850.                           && vim_iswordc(startp[len]))
  3851.             matched = FALSE;
  3852.         }
  3853.         else if (regmatch.regprog != NULL
  3854.              && vim_regexec(®match, line, (colnr_T)(p - line)))
  3855.         {
  3856.             matched = TRUE;
  3857.             startp = regmatch.startp[0];
  3858.             /*
  3859.              * Check if the line is not a comment line (unless we are
  3860.              * looking for a define).  A line starting with "# define"
  3861.              * is not considered to be a comment line.
  3862.              */
  3863.             if (!define_matched && skip_comments)
  3864.             {
  3865. #ifdef FEAT_COMMENTS
  3866.             if ((*line != '#' ||
  3867.                 STRNCMP(skipwhite(line + 1), "define", 6) != 0)
  3868.                 && get_leader_len(line, NULL, FALSE))
  3869.                 matched = FALSE;
  3870.  
  3871.             /*
  3872.              * Also check for a "/ *" or "/ /" before the match.
  3873.              * Skips lines like "int backwards;  / * normal index
  3874.              * * /" when looking for "normal".
  3875.              * Note: Doesn't skip "/ *" in comments.
  3876.              */
  3877.             p = skipwhite(line);
  3878.             if (matched
  3879.                 || (p[0] == '/' && p[1] == '*') || p[0] == '*')
  3880. #endif
  3881.                 for (p = line; *p && p < startp; ++p)
  3882.                 {
  3883.                 if (matched
  3884.                     && p[0] == '/'
  3885.                     && (p[1] == '*' || p[1] == '/'))
  3886.                 {
  3887.                     matched = FALSE;
  3888.                     /* After "//" all text is comment */
  3889.                     if (p[1] == '/')
  3890.                     break;
  3891.                     ++p;
  3892.                 }
  3893.                 else if (!matched && p[0] == '*' && p[1] == '/')
  3894.                 {
  3895.                     /* Can find match after "* /". */
  3896.                     matched = TRUE;
  3897.                     ++p;
  3898.                 }
  3899.                 }
  3900.             }
  3901.         }
  3902.         }
  3903.     }
  3904.     if (matched)
  3905.     {
  3906. #ifdef FEAT_INS_EXPAND
  3907.         if (action == ACTION_EXPAND)
  3908.         {
  3909.         int    reuse = 0;
  3910.         int    add_r;
  3911.         char_u    *aux;
  3912.  
  3913.         if (depth == -1 && lnum == curwin->w_cursor.lnum)
  3914.             break;
  3915.         found = TRUE;
  3916.         aux = p = startp;
  3917.         if (continue_status & CONT_ADDING)
  3918.         {
  3919.             p += completion_length;
  3920.             if (vim_iswordp(p))
  3921.             goto exit_matched;
  3922.             p = find_word_start(p);
  3923.         }
  3924.         p = find_word_end(p);
  3925.         i = (int)(p - aux);
  3926.  
  3927.         if ((continue_status & CONT_ADDING) && i == completion_length)
  3928.         {
  3929.             /* get the next line */
  3930.             /* IOSIZE > completion_length, so the STRNCPY works */
  3931.             STRNCPY(IObuff, aux, i);
  3932.             if (!(     depth < 0
  3933.                 && lnum < end_lnum
  3934.                 && (line = ml_get(++lnum)) != NULL)
  3935.             && !(    depth >= 0
  3936.                 && !vim_fgets(line = file_line,
  3937.                              LSIZE, files[depth].fp)))
  3938.             goto exit_matched;
  3939.  
  3940.             /* we read a line, set "already" to check this "line" later
  3941.              * if depth >= 0 we'll increase files[depth].lnum far
  3942.              * bellow  -- Acevedo */
  3943.             already = aux = p = skipwhite(line);
  3944.             p = find_word_start(p);
  3945.             p = find_word_end(p);
  3946.             if (p > aux)
  3947.             {
  3948.             if (*aux != ')' && IObuff[i-1] != TAB)
  3949.             {
  3950.                 if (IObuff[i-1] != ' ')
  3951.                 IObuff[i++] = ' ';
  3952.                 /* IObuf =~ "\(\k\|\i\).* ", thus i >= 2*/
  3953.                 if (p_js
  3954.                 && (IObuff[i-2] == '.'
  3955.                     || (vim_strchr(p_cpo, CPO_JOINSP) == NULL
  3956.                     && (IObuff[i-2] == '?'
  3957.                         || IObuff[i-2] == '!'))))
  3958.                 IObuff[i++] = ' ';
  3959.             }
  3960.             /* copy as much as posible of the new word */
  3961.             if (p - aux >= IOSIZE - i)
  3962.                 p = aux + IOSIZE - i - 1;
  3963.             STRNCPY(IObuff + i, aux, p - aux);
  3964.             i += (int)(p - aux);
  3965.             reuse |= CONT_S_IPOS;
  3966.             }
  3967.             IObuff[i] = NUL;
  3968.             aux = IObuff;
  3969.  
  3970.             if (i == completion_length)
  3971.             goto exit_matched;
  3972.         }
  3973.  
  3974.         add_r = ins_compl_add_infercase(aux, i,
  3975.             curr_fname == curbuf->b_fname ? NULL : curr_fname,
  3976.             dir, reuse);
  3977.         if (add_r == OK)
  3978.             /* if dir was BACKWARD then honor it just once */
  3979.             dir = FORWARD;
  3980.         else if (add_r == RET_ERROR)
  3981.             break;
  3982.         }
  3983.         else
  3984. #endif
  3985.          if (action == ACTION_SHOW_ALL)
  3986.         {
  3987.         found = TRUE;
  3988.         if (!did_show)
  3989.             gotocmdline(TRUE);        /* cursor at status line */
  3990.         if (curr_fname != prev_fname)
  3991.         {
  3992.             if (did_show)
  3993.             msg_putchar('\n');    /* cursor below last one */
  3994.             if (!got_int)        /* don't display if 'q' typed
  3995.                             at "--more--" mesage */
  3996.             msg_home_replace_hl(curr_fname);
  3997.             prev_fname = curr_fname;
  3998.         }
  3999.         did_show = TRUE;
  4000.         if (!got_int)
  4001.             show_pat_in_path(line, type, TRUE, action,
  4002.                 (depth == -1) ? NULL : files[depth].fp,
  4003.                 (depth == -1) ? &lnum : &files[depth].lnum,
  4004.                 match_count++);
  4005.  
  4006.         /* Set matched flag for this file and all the ones that
  4007.          * include it */
  4008.         for (i = 0; i <= depth; ++i)
  4009.             files[i].matched = TRUE;
  4010.         }
  4011.         else if (--count <= 0)
  4012.         {
  4013.         found = TRUE;
  4014.         if (depth == -1 && lnum == curwin->w_cursor.lnum
  4015. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  4016.                               && g_do_tagpreview == 0
  4017. #endif
  4018.                               )
  4019.             EMSG(_("E387: Match is on current line"));
  4020.         else if (action == ACTION_SHOW)
  4021.         {
  4022.             show_pat_in_path(line, type, did_show, action,
  4023.             (depth == -1) ? NULL : files[depth].fp,
  4024.             (depth == -1) ? &lnum : &files[depth].lnum, 1L);
  4025.             did_show = TRUE;
  4026.         }
  4027.         else
  4028.         {
  4029. #ifdef FEAT_GUI
  4030.             need_mouse_correct = TRUE;
  4031. #endif
  4032. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  4033.             /* ":psearch" uses the preview window */
  4034.             if (g_do_tagpreview != 0)
  4035.             {
  4036.             curwin_save = curwin;
  4037.             prepare_tagpreview();
  4038.             }
  4039. #endif
  4040.             if (action == ACTION_SPLIT)
  4041.             {
  4042. #ifdef FEAT_WINDOWS
  4043.             if (win_split(0, 0) == FAIL)
  4044. #endif
  4045.                 break;
  4046. #ifdef FEAT_SCROLLBIND
  4047.             curwin->w_p_scb = FALSE;
  4048. #endif
  4049.             }
  4050.             if (depth == -1)
  4051.             {
  4052.             /* match in current file */
  4053. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  4054.             if (g_do_tagpreview != 0)
  4055.             {
  4056.                 if (getfile(0, curwin_save->w_buffer->b_fname,
  4057.                          NULL, TRUE, lnum, FALSE) > 0)
  4058.                 break;    /* failed to jump to file */
  4059.             }
  4060.             else
  4061. #endif
  4062.                 setpcmark();
  4063.             curwin->w_cursor.lnum = lnum;
  4064.             }
  4065.             else
  4066.             {
  4067.             if (getfile(0, files[depth].name, NULL, TRUE,
  4068.                         files[depth].lnum, FALSE) > 0)
  4069.                 break;    /* failed to jump to file */
  4070.             /* autocommands may have changed the lnum, we don't
  4071.              * want that here */
  4072.             curwin->w_cursor.lnum = files[depth].lnum;
  4073.             }
  4074.         }
  4075.         if (action != ACTION_SHOW)
  4076.         {
  4077.             curwin->w_cursor.col = (colnr_T) (startp - line);
  4078.             curwin->w_set_curswant = TRUE;
  4079.         }
  4080.  
  4081. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  4082.         if (g_do_tagpreview != 0
  4083.             && curwin != curwin_save && win_valid(curwin_save))
  4084.         {
  4085.             /* Return cursor to where we were */
  4086.             validate_cursor();
  4087.             redraw_later(VALID);
  4088.             win_enter(curwin_save, TRUE);
  4089.         }
  4090. #endif
  4091.         break;
  4092.         }
  4093. #ifdef FEAT_INS_EXPAND
  4094. exit_matched:
  4095. #endif
  4096.         matched = FALSE;
  4097.         /* look for other matches in the rest of the line if we
  4098.          * are not at the end of it already */
  4099.         if (def_regmatch.regprog == NULL
  4100. #ifdef FEAT_INS_EXPAND
  4101.             && action == ACTION_EXPAND
  4102.             && !(continue_status & CONT_SOL)
  4103. #endif
  4104.             && *(p = startp + 1))
  4105.         goto search_line;
  4106.     }
  4107.     line_breakcheck();
  4108. #ifdef FEAT_INS_EXPAND
  4109.     if (action == ACTION_EXPAND)
  4110.         ins_compl_check_keys();
  4111.     if (got_int || completion_interrupted)
  4112. #else
  4113.     if (got_int)
  4114. #endif
  4115.         break;
  4116.  
  4117.     /*
  4118.      * Read the next line.  When reading an included file and encountering
  4119.      * end-of-file, close the file and continue in the file that included
  4120.      * it.
  4121.      */
  4122.     while (depth >= 0 && !already
  4123.         && vim_fgets(line = file_line, LSIZE, files[depth].fp))
  4124.     {
  4125.         fclose(files[depth].fp);
  4126.         --old_files;
  4127.         files[old_files].name = files[depth].name;
  4128.         files[old_files].matched = files[depth].matched;
  4129.         --depth;
  4130.         curr_fname = (depth == -1) ? curbuf->b_fname
  4131.                        : files[depth].name;
  4132.         if (depth < depth_displayed)
  4133.         depth_displayed = depth;
  4134.     }
  4135.     if (depth >= 0)        /* we could read the line */
  4136.         files[depth].lnum++;
  4137.     else if (!already)
  4138.     {
  4139.         if (++lnum > end_lnum)
  4140.         break;
  4141.         line = ml_get(lnum);
  4142.     }
  4143.     already = NULL;
  4144.     }
  4145.     /* End of big for (;;) loop. */
  4146.  
  4147.     /* Close any files that are still open. */
  4148.     for (i = 0; i <= depth; i++)
  4149.     {
  4150.     fclose(files[i].fp);
  4151.     vim_free(files[i].name);
  4152.     }
  4153.     for (i = old_files; i < max_path_depth; i++)
  4154.     vim_free(files[i].name);
  4155.     vim_free(files);
  4156.  
  4157.     if (type == CHECK_PATH)
  4158.     {
  4159.     if (!did_show)
  4160.     {
  4161.         if (action != ACTION_SHOW_ALL)
  4162.         MSG(_("All included files were found"));
  4163.         else
  4164.         MSG(_("No included files"));
  4165.     }
  4166.     }
  4167.     else if (!found
  4168. #ifdef FEAT_INS_EXPAND
  4169.             && action != ACTION_EXPAND
  4170. #endif
  4171.                         )
  4172.     {
  4173. #ifdef FEAT_INS_EXPAND
  4174.     if (got_int || completion_interrupted)
  4175. #else
  4176.     if (got_int)
  4177. #endif
  4178.         EMSG(_(e_interr));
  4179.     else if (type == FIND_DEFINE)
  4180.         EMSG(_("E388: Couldn't find definition"));
  4181.     else
  4182.         EMSG(_("E389: Couldn't find pattern"));
  4183.     }
  4184.     if (action == ACTION_SHOW || action == ACTION_SHOW_ALL)
  4185.     msg_end();
  4186.  
  4187. fpip_end:
  4188.     vim_free(file_line);
  4189.     vim_free(regmatch.regprog);
  4190.     vim_free(incl_regmatch.regprog);
  4191.     vim_free(def_regmatch.regprog);
  4192.  
  4193. #ifdef RISCOS
  4194.    /* Restore previous file munging state. */
  4195.     __riscosify_control = previous_munging;
  4196. #endif
  4197. }
  4198.  
  4199.     static void
  4200. show_pat_in_path(line, type, did_show, action, fp, lnum, count)
  4201.     char_u  *line;
  4202.     int        type;
  4203.     int        did_show;
  4204.     int        action;
  4205.     FILE    *fp;
  4206.     linenr_T *lnum;
  4207.     long    count;
  4208. {
  4209.     char_u  *p;
  4210.  
  4211.     if (did_show)
  4212.     msg_putchar('\n');    /* cursor below last one */
  4213.     else
  4214.     gotocmdline(TRUE);    /* cursor at status line */
  4215.     if (got_int)        /* 'q' typed at "--more--" message */
  4216.     return;
  4217.     for (;;)
  4218.     {
  4219.     p = line + STRLEN(line) - 1;
  4220.     if (fp != NULL)
  4221.     {
  4222.         /* We used fgets(), so get rid of newline at end */
  4223.         if (p >= line && *p == '\n')
  4224.         --p;
  4225.         if (p >= line && *p == '\r')
  4226.         --p;
  4227.         *(p + 1) = NUL;
  4228.     }
  4229.     if (action == ACTION_SHOW_ALL)
  4230.     {
  4231.         sprintf((char *)IObuff, "%3ld: ", count);    /* show match nr */
  4232.         msg_puts(IObuff);
  4233.         sprintf((char *)IObuff, "%4ld", *lnum);    /* show line nr */
  4234.                         /* Highlight line numbers */
  4235.         msg_puts_attr(IObuff, hl_attr(HLF_N));
  4236.         MSG_PUTS(" ");
  4237.     }
  4238.     msg_prt_line(line);
  4239.     out_flush();            /* show one line at a time */
  4240.  
  4241.     /* Definition continues until line that doesn't end with '\' */
  4242.     if (got_int || type != FIND_DEFINE || p < line || *p != '\\')
  4243.         break;
  4244.  
  4245.     if (fp != NULL)
  4246.     {
  4247.         if (vim_fgets(line, LSIZE, fp)) /* end of file */
  4248.         break;
  4249.         ++*lnum;
  4250.     }
  4251.     else
  4252.     {
  4253.         if (++*lnum > curbuf->b_ml.ml_line_count)
  4254.         break;
  4255.         line = ml_get(*lnum);
  4256.     }
  4257.     msg_putchar('\n');
  4258.     }
  4259. }
  4260. #endif
  4261.  
  4262. #ifdef FEAT_VIMINFO
  4263.     int
  4264. read_viminfo_search_pattern(virp, force)
  4265.     vir_T    *virp;
  4266.     int        force;
  4267. {
  4268.     char_u    *lp;
  4269.     int        idx = -1;
  4270.     int        magic = FALSE;
  4271.     int        no_scs = FALSE;
  4272.     int        off_line = FALSE;
  4273.     int        off_end = FALSE;
  4274.     long    off = 0;
  4275.     int        setlast = FALSE;
  4276. #ifdef FEAT_SEARCH_EXTRA
  4277.     static int    hlsearch_on = FALSE;
  4278. #endif
  4279.     char_u    *val;
  4280.  
  4281.     /*
  4282.      * Old line types:
  4283.      * "/pat", "&pat": search/subst. pat
  4284.      * "~/pat", "~&pat": last used search/subst. pat
  4285.      * New line types:
  4286.      * "~h", "~H": hlsearch highlighting off/on
  4287.      * "~<magic><smartcase><line><end><off><last><which>pat"
  4288.      * <magic>: 'm' off, 'M' on
  4289.      * <smartcase>: 's' off, 'S' on
  4290.      * <line>: 'L' line offset, 'l' char offset
  4291.      * <end>: 'E' from end, 'e' from start
  4292.      * <off>: decimal, offset
  4293.      * <last>: '~' last used pattern
  4294.      * <which>: '/' search pat, '&' subst. pat
  4295.      */
  4296.     lp = virp->vir_line;
  4297.     if (lp[0] == '~' && (lp[1] == 'm' || lp[1] == 'M'))    /* new line type */
  4298.     {
  4299.     if (lp[1] == 'M')        /* magic on */
  4300.         magic = TRUE;
  4301.     if (lp[2] == 's')
  4302.         no_scs = TRUE;
  4303.     if (lp[3] == 'L')
  4304.         off_line = TRUE;
  4305.     if (lp[4] == 'E')
  4306.         off_end = TRUE;
  4307.     lp += 5;
  4308.     off = getdigits(&lp);
  4309.     }
  4310.     if (lp[0] == '~')        /* use this pattern for last-used pattern */
  4311.     {
  4312.     setlast = TRUE;
  4313.     lp++;
  4314.     }
  4315.     if (lp[0] == '/')
  4316.     idx = RE_SEARCH;
  4317.     else if (lp[0] == '&')
  4318.     idx = RE_SUBST;
  4319. #ifdef FEAT_SEARCH_EXTRA
  4320.     else if (lp[0] == 'h')    /* ~h: 'hlsearch' highlighting off */
  4321.     hlsearch_on = FALSE;
  4322.     else if (lp[0] == 'H')    /* ~H: 'hlsearch' highlighting on */
  4323.     hlsearch_on = TRUE;
  4324. #endif
  4325.     if (idx >= 0)
  4326.     {
  4327.     if (force || spats[idx].pat == NULL)
  4328.     {
  4329.         val = viminfo_readstring(virp, (int)(lp - virp->vir_line + 1),
  4330.                                     TRUE);
  4331.         if (val != NULL)
  4332.         {
  4333.         set_last_search_pat(val, idx, magic, setlast);
  4334.         vim_free(val);
  4335.         spats[idx].no_scs = no_scs;
  4336.         spats[idx].off.line = off_line;
  4337.         spats[idx].off.end = off_end;
  4338.         spats[idx].off.off = off;
  4339. #ifdef FEAT_SEARCH_EXTRA
  4340.         if (setlast)
  4341.             no_hlsearch = !hlsearch_on;
  4342. #endif
  4343.         }
  4344.     }
  4345.     }
  4346.     return viminfo_readline(virp);
  4347. }
  4348.  
  4349.     void
  4350. write_viminfo_search_pattern(fp)
  4351.     FILE    *fp;
  4352. {
  4353.     if (get_viminfo_parameter('/') != 0)
  4354.     {
  4355. #ifdef FEAT_SEARCH_EXTRA
  4356.     fprintf(fp, "\n# hlsearch on (H) or off (h):\n~%c",
  4357.         (no_hlsearch || find_viminfo_parameter('h') != NULL) ? 'h' : 'H');
  4358. #endif
  4359.     wvsp_one(fp, RE_SEARCH, "", '/');
  4360.     wvsp_one(fp, RE_SUBST, "Substitute ", '&');
  4361.     }
  4362. }
  4363.  
  4364.     static void
  4365. wvsp_one(fp, idx, s, sc)
  4366.     FILE    *fp;    /* file to write to */
  4367.     int        idx;    /* spats[] index */
  4368.     char    *s;    /* search pat */
  4369.     int        sc;    /* dir char */
  4370. {
  4371.     if (spats[idx].pat != NULL)
  4372.     {
  4373.     fprintf(fp, "\n# Last %sSearch Pattern:\n~", s);
  4374.     /* off.dir is not stored, it's reset to forward */
  4375.     fprintf(fp, "%c%c%c%c%ld%s%c",
  4376.         spats[idx].magic    ? 'M' : 'm',    /* magic */
  4377.         spats[idx].no_scs   ? 's' : 'S',    /* smartcase */
  4378.         spats[idx].off.line ? 'L' : 'l',    /* line offset */
  4379.         spats[idx].off.end  ? 'E' : 'e',    /* offset from end */
  4380.         spats[idx].off.off,            /* offset */
  4381.         last_idx == idx        ? "~" : "",        /* last used pat */
  4382.         sc);
  4383.     viminfo_writestring(fp, spats[idx].pat);
  4384.     }
  4385. }
  4386. #endif /* FEAT_VIMINFO */
  4387.