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