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