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