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