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