xref: /vim-8.2.3635/src/findfile.c (revision 723d165c)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * findfile.c: Search for files in directories listed in 'path'
12  */
13 
14 #include "vim.h"
15 
16 /*
17  * File searching functions for 'path', 'tags' and 'cdpath' options.
18  * External visible functions:
19  * vim_findfile_init()		creates/initialises the search context
20  * vim_findfile_free_visited()	free list of visited files/dirs of search
21  *				context
22  * vim_findfile()		find a file in the search context
23  * vim_findfile_cleanup()	cleanup/free search context created by
24  *				vim_findfile_init()
25  *
26  * All static functions and variables start with 'ff_'
27  *
28  * In general it works like this:
29  * First you create yourself a search context by calling vim_findfile_init().
30  * It is possible to give a search context from a previous call to
31  * vim_findfile_init(), so it can be reused. After this you call vim_findfile()
32  * until you are satisfied with the result or it returns NULL. On every call it
33  * returns the next file which matches the conditions given to
34  * vim_findfile_init(). If it doesn't find a next file it returns NULL.
35  *
36  * It is possible to call vim_findfile_init() again to reinitialise your search
37  * with some new parameters. Don't forget to pass your old search context to
38  * it, so it can reuse it and especially reuse the list of already visited
39  * directories. If you want to delete the list of already visited directories
40  * simply call vim_findfile_free_visited().
41  *
42  * When you are done call vim_findfile_cleanup() to free the search context.
43  *
44  * The function vim_findfile_init() has a long comment, which describes the
45  * needed parameters.
46  *
47  *
48  *
49  * ATTENTION:
50  * ==========
51  *	Also we use an allocated search context here, this functions are NOT
52  *	thread-safe!!!!!
53  *
54  *	To minimize parameter passing (or because I'm to lazy), only the
55  *	external visible functions get a search context as a parameter. This is
56  *	then assigned to a static global, which is used throughout the local
57  *	functions.
58  */
59 
60 /*
61  * type for the directory search stack
62  */
63 typedef struct ff_stack
64 {
65     struct ff_stack	*ffs_prev;
66 
67     // the fix part (no wildcards) and the part containing the wildcards
68     // of the search path
69     char_u		*ffs_fix_path;
70 #ifdef FEAT_PATH_EXTRA
71     char_u		*ffs_wc_path;
72 #endif
73 
74     // files/dirs found in the above directory, matched by the first wildcard
75     // of wc_part
76     char_u		**ffs_filearray;
77     int			ffs_filearray_size;
78     char_u		ffs_filearray_cur;   // needed for partly handled dirs
79 
80     // to store status of partly handled directories
81     // 0: we work on this directory for the first time
82     // 1: this directory was partly searched in an earlier step
83     int			ffs_stage;
84 
85     // How deep are we in the directory tree?
86     // Counts backward from value of level parameter to vim_findfile_init
87     int			ffs_level;
88 
89     // Did we already expand '**' to an empty string?
90     int			ffs_star_star_empty;
91 } ff_stack_T;
92 
93 /*
94  * type for already visited directories or files.
95  */
96 typedef struct ff_visited
97 {
98     struct ff_visited	*ffv_next;
99 
100 #ifdef FEAT_PATH_EXTRA
101     // Visited directories are different if the wildcard string are
102     // different. So we have to save it.
103     char_u		*ffv_wc_path;
104 #endif
105     // for unix use inode etc for comparison (needed because of links), else
106     // use filename.
107 #ifdef UNIX
108     int			ffv_dev_valid;	// ffv_dev and ffv_ino were set
109     dev_t		ffv_dev;	// device number
110     ino_t		ffv_ino;	// inode number
111 #endif
112     // The memory for this struct is allocated according to the length of
113     // ffv_fname.
114     char_u		ffv_fname[1];	// actually longer
115 } ff_visited_T;
116 
117 /*
118  * We might have to manage several visited lists during a search.
119  * This is especially needed for the tags option. If tags is set to:
120  *      "./++/tags,./++/TAGS,++/tags"  (replace + with *)
121  * So we have to do 3 searches:
122  *   1) search from the current files directory downward for the file "tags"
123  *   2) search from the current files directory downward for the file "TAGS"
124  *   3) search from Vims current directory downwards for the file "tags"
125  * As you can see, the first and the third search are for the same file, so for
126  * the third search we can use the visited list of the first search. For the
127  * second search we must start from a empty visited list.
128  * The struct ff_visited_list_hdr is used to manage a linked list of already
129  * visited lists.
130  */
131 typedef struct ff_visited_list_hdr
132 {
133     struct ff_visited_list_hdr	*ffvl_next;
134 
135     // the filename the attached visited list is for
136     char_u			*ffvl_filename;
137 
138     ff_visited_T		*ffvl_visited_list;
139 
140 } ff_visited_list_hdr_T;
141 
142 
143 /*
144  * '**' can be expanded to several directory levels.
145  * Set the default maximum depth.
146  */
147 #define FF_MAX_STAR_STAR_EXPAND ((char_u)30)
148 
149 /*
150  * The search context:
151  *   ffsc_stack_ptr:	the stack for the dirs to search
152  *   ffsc_visited_list: the currently active visited list
153  *   ffsc_dir_visited_list: the currently active visited list for search dirs
154  *   ffsc_visited_lists_list: the list of all visited lists
155  *   ffsc_dir_visited_lists_list: the list of all visited lists for search dirs
156  *   ffsc_file_to_search:     the file to search for
157  *   ffsc_start_dir:	the starting directory, if search path was relative
158  *   ffsc_fix_path:	the fix part of the given path (without wildcards)
159  *			Needed for upward search.
160  *   ffsc_wc_path:	the part of the given path containing wildcards
161  *   ffsc_level:	how many levels of dirs to search downwards
162  *   ffsc_stopdirs_v:	array of stop directories for upward search
163  *   ffsc_find_what:	FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE
164  *   ffsc_tagfile:	searching for tags file, don't use 'suffixesadd'
165  */
166 typedef struct ff_search_ctx_T
167 {
168      ff_stack_T			*ffsc_stack_ptr;
169      ff_visited_list_hdr_T	*ffsc_visited_list;
170      ff_visited_list_hdr_T	*ffsc_dir_visited_list;
171      ff_visited_list_hdr_T	*ffsc_visited_lists_list;
172      ff_visited_list_hdr_T	*ffsc_dir_visited_lists_list;
173      char_u			*ffsc_file_to_search;
174      char_u			*ffsc_start_dir;
175      char_u			*ffsc_fix_path;
176 #ifdef FEAT_PATH_EXTRA
177      char_u			*ffsc_wc_path;
178      int			ffsc_level;
179      char_u			**ffsc_stopdirs_v;
180 #endif
181      int			ffsc_find_what;
182      int			ffsc_tagfile;
183 } ff_search_ctx_T;
184 
185 // locally needed functions
186 #ifdef FEAT_PATH_EXTRA
187 static int ff_check_visited(ff_visited_T **, char_u *, char_u *);
188 #else
189 static int ff_check_visited(ff_visited_T **, char_u *);
190 #endif
191 static void vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp);
192 static void ff_free_visited_list(ff_visited_T *vl);
193 static ff_visited_list_hdr_T* ff_get_visited_list(char_u *, ff_visited_list_hdr_T **list_headp);
194 
195 static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr);
196 static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx);
197 static void ff_clear(ff_search_ctx_T *search_ctx);
198 static void ff_free_stack_element(ff_stack_T *stack_ptr);
199 #ifdef FEAT_PATH_EXTRA
200 static ff_stack_T *ff_create_stack_element(char_u *, char_u *, int, int);
201 #else
202 static ff_stack_T *ff_create_stack_element(char_u *, int, int);
203 #endif
204 #ifdef FEAT_PATH_EXTRA
205 static int ff_path_in_stoplist(char_u *, int, char_u **);
206 #endif
207 
208 static char_u e_pathtoolong[] = N_("E854: path too long for completion");
209 
210 static char_u	*ff_expand_buffer = NULL; // used for expanding filenames
211 
212 #if 0
213 /*
214  * if someone likes findfirst/findnext, here are the functions
215  * NOT TESTED!!
216  */
217 
218 static void *ff_fn_search_context = NULL;
219 
220     char_u *
221 vim_findfirst(char_u *path, char_u *filename, int level)
222 {
223     ff_fn_search_context =
224 	vim_findfile_init(path, filename, NULL, level, TRUE, FALSE,
225 		ff_fn_search_context, rel_fname);
226     if (NULL == ff_fn_search_context)
227 	return NULL;
228     else
229 	return vim_findnext()
230 }
231 
232     char_u *
233 vim_findnext(void)
234 {
235     char_u *ret = vim_findfile(ff_fn_search_context);
236 
237     if (NULL == ret)
238     {
239 	vim_findfile_cleanup(ff_fn_search_context);
240 	ff_fn_search_context = NULL;
241     }
242     return ret;
243 }
244 #endif
245 
246 /*
247  * Initialization routine for vim_findfile().
248  *
249  * Returns the newly allocated search context or NULL if an error occurred.
250  *
251  * Don't forget to clean up by calling vim_findfile_cleanup() if you are done
252  * with the search context.
253  *
254  * Find the file 'filename' in the directory 'path'.
255  * The parameter 'path' may contain wildcards. If so only search 'level'
256  * directories deep. The parameter 'level' is the absolute maximum and is
257  * not related to restricts given to the '**' wildcard. If 'level' is 100
258  * and you use '**200' vim_findfile() will stop after 100 levels.
259  *
260  * 'filename' cannot contain wildcards!  It is used as-is, no backslashes to
261  * escape special characters.
262  *
263  * If 'stopdirs' is not NULL and nothing is found downward, the search is
264  * restarted on the next higher directory level. This is repeated until the
265  * start-directory of a search is contained in 'stopdirs'. 'stopdirs' has the
266  * format ";*<dirname>*\(;<dirname>\)*;\=$".
267  *
268  * If the 'path' is relative, the starting dir for the search is either VIM's
269  * current dir or if the path starts with "./" the current files dir.
270  * If the 'path' is absolute, the starting dir is that part of the path before
271  * the first wildcard.
272  *
273  * Upward search is only done on the starting dir.
274  *
275  * If 'free_visited' is TRUE the list of already visited files/directories is
276  * cleared. Set this to FALSE if you just want to search from another
277  * directory, but want to be sure that no directory from a previous search is
278  * searched again. This is useful if you search for a file at different places.
279  * The list of visited files/dirs can also be cleared with the function
280  * vim_findfile_free_visited().
281  *
282  * Set the parameter 'find_what' to FINDFILE_DIR if you want to search for
283  * directories only, FINDFILE_FILE for files only, FINDFILE_BOTH for both.
284  *
285  * A search context returned by a previous call to vim_findfile_init() can be
286  * passed in the parameter "search_ctx_arg".  This context is reused and
287  * reinitialized with the new parameters.  The list of already visited
288  * directories from this context is only deleted if the parameter
289  * "free_visited" is true.  Be aware that the passed "search_ctx_arg" is freed
290  * if the reinitialization fails.
291  *
292  * If you don't have a search context from a previous call "search_ctx_arg"
293  * must be NULL.
294  *
295  * This function silently ignores a few errors, vim_findfile() will have
296  * limited functionality then.
297  */
298     void *
299 vim_findfile_init(
300     char_u	*path,
301     char_u	*filename,
302     char_u	*stopdirs UNUSED,
303     int		level,
304     int		free_visited,
305     int		find_what,
306     void	*search_ctx_arg,
307     int		tagfile,	// expanding names of tags files
308     char_u	*rel_fname)	// file name to use for "."
309 {
310 #ifdef FEAT_PATH_EXTRA
311     char_u		*wc_part;
312 #endif
313     ff_stack_T		*sptr;
314     ff_search_ctx_T	*search_ctx;
315 
316     // If a search context is given by the caller, reuse it, else allocate a
317     // new one.
318     if (search_ctx_arg != NULL)
319 	search_ctx = search_ctx_arg;
320     else
321     {
322 	search_ctx = (ff_search_ctx_T*)alloc((unsigned)sizeof(ff_search_ctx_T));
323 	if (search_ctx == NULL)
324 	    goto error_return;
325 	vim_memset(search_ctx, 0, sizeof(ff_search_ctx_T));
326     }
327     search_ctx->ffsc_find_what = find_what;
328     search_ctx->ffsc_tagfile = tagfile;
329 
330     // clear the search context, but NOT the visited lists
331     ff_clear(search_ctx);
332 
333     // clear visited list if wanted
334     if (free_visited == TRUE)
335 	vim_findfile_free_visited(search_ctx);
336     else
337     {
338 	// Reuse old visited lists. Get the visited list for the given
339 	// filename. If no list for the current filename exists, creates a new
340 	// one.
341 	search_ctx->ffsc_visited_list = ff_get_visited_list(filename,
342 					&search_ctx->ffsc_visited_lists_list);
343 	if (search_ctx->ffsc_visited_list == NULL)
344 	    goto error_return;
345 	search_ctx->ffsc_dir_visited_list = ff_get_visited_list(filename,
346 				    &search_ctx->ffsc_dir_visited_lists_list);
347 	if (search_ctx->ffsc_dir_visited_list == NULL)
348 	    goto error_return;
349     }
350 
351     if (ff_expand_buffer == NULL)
352     {
353 	ff_expand_buffer = (char_u*)alloc(MAXPATHL);
354 	if (ff_expand_buffer == NULL)
355 	    goto error_return;
356     }
357 
358     // Store information on starting dir now if path is relative.
359     // If path is absolute, we do that later.
360     if (path[0] == '.'
361 	    && (vim_ispathsep(path[1]) || path[1] == NUL)
362 	    && (!tagfile || vim_strchr(p_cpo, CPO_DOTTAG) == NULL)
363 	    && rel_fname != NULL)
364     {
365 	int	len = (int)(gettail(rel_fname) - rel_fname);
366 
367 	if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL)
368 	{
369 	    // Make the start dir an absolute path name.
370 	    vim_strncpy(ff_expand_buffer, rel_fname, len);
371 	    search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, FALSE);
372 	}
373 	else
374 	    search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len);
375 	if (search_ctx->ffsc_start_dir == NULL)
376 	    goto error_return;
377 	if (*++path != NUL)
378 	    ++path;
379     }
380     else if (*path == NUL || !vim_isAbsName(path))
381     {
382 #ifdef BACKSLASH_IN_FILENAME
383 	// "c:dir" needs "c:" to be expanded, otherwise use current dir
384 	if (*path != NUL && path[1] == ':')
385 	{
386 	    char_u  drive[3];
387 
388 	    drive[0] = path[0];
389 	    drive[1] = ':';
390 	    drive[2] = NUL;
391 	    if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
392 		goto error_return;
393 	    path += 2;
394 	}
395 	else
396 #endif
397 	if (mch_dirname(ff_expand_buffer, MAXPATHL) == FAIL)
398 	    goto error_return;
399 
400 	search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer);
401 	if (search_ctx->ffsc_start_dir == NULL)
402 	    goto error_return;
403 
404 #ifdef BACKSLASH_IN_FILENAME
405 	// A path that starts with "/dir" is relative to the drive, not to the
406 	// directory (but not for "//machine/dir").  Only use the drive name.
407 	if ((*path == '/' || *path == '\\')
408 		&& path[1] != path[0]
409 		&& search_ctx->ffsc_start_dir[1] == ':')
410 	    search_ctx->ffsc_start_dir[2] = NUL;
411 #endif
412     }
413 
414 #ifdef FEAT_PATH_EXTRA
415     /*
416      * If stopdirs are given, split them into an array of pointers.
417      * If this fails (mem allocation), there is no upward search at all or a
418      * stop directory is not recognized -> continue silently.
419      * If stopdirs just contains a ";" or is empty,
420      * search_ctx->ffsc_stopdirs_v will only contain a  NULL pointer. This
421      * is handled as unlimited upward search.  See function
422      * ff_path_in_stoplist() for details.
423      */
424     if (stopdirs != NULL)
425     {
426 	char_u	*walker = stopdirs;
427 	int	dircount;
428 
429 	while (*walker == ';')
430 	    walker++;
431 
432 	dircount = 1;
433 	search_ctx->ffsc_stopdirs_v =
434 				 (char_u **)alloc((unsigned)sizeof(char_u *));
435 
436 	if (search_ctx->ffsc_stopdirs_v != NULL)
437 	{
438 	    do
439 	    {
440 		char_u	*helper;
441 		void	*ptr;
442 
443 		helper = walker;
444 		ptr = vim_realloc(search_ctx->ffsc_stopdirs_v,
445 					   (dircount + 1) * sizeof(char_u *));
446 		if (ptr)
447 		    search_ctx->ffsc_stopdirs_v = ptr;
448 		else
449 		    // ignore, keep what we have and continue
450 		    break;
451 		walker = vim_strchr(walker, ';');
452 		if (walker)
453 		{
454 		    search_ctx->ffsc_stopdirs_v[dircount-1] =
455 				 vim_strnsave(helper, (int)(walker - helper));
456 		    walker++;
457 		}
458 		else
459 		    // this might be "", which means ascent till top
460 		    // of directory tree.
461 		    search_ctx->ffsc_stopdirs_v[dircount-1] =
462 							  vim_strsave(helper);
463 
464 		dircount++;
465 
466 	    } while (walker != NULL);
467 	    search_ctx->ffsc_stopdirs_v[dircount-1] = NULL;
468 	}
469     }
470 #endif
471 
472 #ifdef FEAT_PATH_EXTRA
473     search_ctx->ffsc_level = level;
474 
475     /*
476      * split into:
477      *  -fix path
478      *  -wildcard_stuff (might be NULL)
479      */
480     wc_part = vim_strchr(path, '*');
481     if (wc_part != NULL)
482     {
483 	int	llevel;
484 	int	len;
485 	char	*errpt;
486 
487 	// save the fix part of the path
488 	search_ctx->ffsc_fix_path = vim_strnsave(path, (int)(wc_part - path));
489 
490 	/*
491 	 * copy wc_path and add restricts to the '**' wildcard.
492 	 * The octet after a '**' is used as a (binary) counter.
493 	 * So '**3' is transposed to '**^C' ('^C' is ASCII value 3)
494 	 * or '**76' is transposed to '**N'( 'N' is ASCII value 76).
495 	 * For EBCDIC you get different character values.
496 	 * If no restrict is given after '**' the default is used.
497 	 * Due to this technique the path looks awful if you print it as a
498 	 * string.
499 	 */
500 	len = 0;
501 	while (*wc_part != NUL)
502 	{
503 	    if (len + 5 >= MAXPATHL)
504 	    {
505 		emsg(_(e_pathtoolong));
506 		break;
507 	    }
508 	    if (STRNCMP(wc_part, "**", 2) == 0)
509 	    {
510 		ff_expand_buffer[len++] = *wc_part++;
511 		ff_expand_buffer[len++] = *wc_part++;
512 
513 		llevel = strtol((char *)wc_part, &errpt, 10);
514 		if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255)
515 		    ff_expand_buffer[len++] = llevel;
516 		else if ((char_u *)errpt != wc_part && llevel == 0)
517 		    // restrict is 0 -> remove already added '**'
518 		    len -= 2;
519 		else
520 		    ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND;
521 		wc_part = (char_u *)errpt;
522 		if (*wc_part != NUL && !vim_ispathsep(*wc_part))
523 		{
524 		    semsg(_("E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."), PATHSEPSTR);
525 		    goto error_return;
526 		}
527 	    }
528 	    else
529 		ff_expand_buffer[len++] = *wc_part++;
530 	}
531 	ff_expand_buffer[len] = NUL;
532 	search_ctx->ffsc_wc_path = vim_strsave(ff_expand_buffer);
533 
534 	if (search_ctx->ffsc_wc_path == NULL)
535 	    goto error_return;
536     }
537     else
538 #endif
539 	search_ctx->ffsc_fix_path = vim_strsave(path);
540 
541     if (search_ctx->ffsc_start_dir == NULL)
542     {
543 	// store the fix part as startdir.
544 	// This is needed if the parameter path is fully qualified.
545 	search_ctx->ffsc_start_dir = vim_strsave(search_ctx->ffsc_fix_path);
546 	if (search_ctx->ffsc_start_dir == NULL)
547 	    goto error_return;
548 	search_ctx->ffsc_fix_path[0] = NUL;
549     }
550 
551     // create an absolute path
552     if (STRLEN(search_ctx->ffsc_start_dir)
553 			  + STRLEN(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL)
554     {
555 	emsg(_(e_pathtoolong));
556 	goto error_return;
557     }
558     STRCPY(ff_expand_buffer, search_ctx->ffsc_start_dir);
559     add_pathsep(ff_expand_buffer);
560     {
561 	int    eb_len = (int)STRLEN(ff_expand_buffer);
562 	char_u *buf = alloc(eb_len
563 				+ (int)STRLEN(search_ctx->ffsc_fix_path) + 1);
564 
565 	STRCPY(buf, ff_expand_buffer);
566 	STRCPY(buf + eb_len, search_ctx->ffsc_fix_path);
567 	if (mch_isdir(buf))
568 	{
569 	    STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path);
570 	    add_pathsep(ff_expand_buffer);
571 	}
572 #ifdef FEAT_PATH_EXTRA
573 	else
574 	{
575 	    char_u *p =  gettail(search_ctx->ffsc_fix_path);
576 	    char_u *wc_path = NULL;
577 	    char_u *temp = NULL;
578 	    int    len = 0;
579 
580 	    if (p > search_ctx->ffsc_fix_path)
581 	    {
582 		len = (int)(p - search_ctx->ffsc_fix_path) - 1;
583 		STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len);
584 		add_pathsep(ff_expand_buffer);
585 	    }
586 	    else
587 		len = (int)STRLEN(search_ctx->ffsc_fix_path);
588 
589 	    if (search_ctx->ffsc_wc_path != NULL)
590 	    {
591 		wc_path = vim_strsave(search_ctx->ffsc_wc_path);
592 		temp = alloc((int)(STRLEN(search_ctx->ffsc_wc_path)
593 				 + STRLEN(search_ctx->ffsc_fix_path + len)
594 				 + 1));
595 		if (temp == NULL || wc_path == NULL)
596 		{
597 		    vim_free(buf);
598 		    vim_free(temp);
599 		    vim_free(wc_path);
600 		    goto error_return;
601 		}
602 
603 		STRCPY(temp, search_ctx->ffsc_fix_path + len);
604 		STRCAT(temp, search_ctx->ffsc_wc_path);
605 		vim_free(search_ctx->ffsc_wc_path);
606 		vim_free(wc_path);
607 		search_ctx->ffsc_wc_path = temp;
608 	    }
609 	}
610 #endif
611 	vim_free(buf);
612     }
613 
614     sptr = ff_create_stack_element(ff_expand_buffer,
615 #ifdef FEAT_PATH_EXTRA
616 	    search_ctx->ffsc_wc_path,
617 #endif
618 	    level, 0);
619 
620     if (sptr == NULL)
621 	goto error_return;
622 
623     ff_push(search_ctx, sptr);
624 
625     search_ctx->ffsc_file_to_search = vim_strsave(filename);
626     if (search_ctx->ffsc_file_to_search == NULL)
627 	goto error_return;
628 
629     return search_ctx;
630 
631 error_return:
632     /*
633      * We clear the search context now!
634      * Even when the caller gave us a (perhaps valid) context we free it here,
635      * as we might have already destroyed it.
636      */
637     vim_findfile_cleanup(search_ctx);
638     return NULL;
639 }
640 
641 #if defined(FEAT_PATH_EXTRA) || defined(PROTO)
642 /*
643  * Get the stopdir string.  Check that ';' is not escaped.
644  */
645     char_u *
646 vim_findfile_stopdir(char_u *buf)
647 {
648     char_u	*r_ptr = buf;
649 
650     while (*r_ptr != NUL && *r_ptr != ';')
651     {
652 	if (r_ptr[0] == '\\' && r_ptr[1] == ';')
653 	{
654 	    // Overwrite the escape char,
655 	    // use STRLEN(r_ptr) to move the trailing '\0'.
656 	    STRMOVE(r_ptr, r_ptr + 1);
657 	    r_ptr++;
658 	}
659 	r_ptr++;
660     }
661     if (*r_ptr == ';')
662     {
663 	*r_ptr = 0;
664 	r_ptr++;
665     }
666     else if (*r_ptr == NUL)
667 	r_ptr = NULL;
668     return r_ptr;
669 }
670 #endif
671 
672 /*
673  * Clean up the given search context. Can handle a NULL pointer.
674  */
675     void
676 vim_findfile_cleanup(void *ctx)
677 {
678     if (ctx == NULL)
679 	return;
680 
681     vim_findfile_free_visited(ctx);
682     ff_clear(ctx);
683     vim_free(ctx);
684 }
685 
686 /*
687  * Find a file in a search context.
688  * The search context was created with vim_findfile_init() above.
689  * Return a pointer to an allocated file name or NULL if nothing found.
690  * To get all matching files call this function until you get NULL.
691  *
692  * If the passed search_context is NULL, NULL is returned.
693  *
694  * The search algorithm is depth first. To change this replace the
695  * stack with a list (don't forget to leave partly searched directories on the
696  * top of the list).
697  */
698     char_u *
699 vim_findfile(void *search_ctx_arg)
700 {
701     char_u	*file_path;
702 #ifdef FEAT_PATH_EXTRA
703     char_u	*rest_of_wildcards;
704     char_u	*path_end = NULL;
705 #endif
706     ff_stack_T	*stackp;
707 #if defined(FEAT_SEARCHPATH) || defined(FEAT_PATH_EXTRA)
708     int		len;
709 #endif
710     int		i;
711     char_u	*p;
712 #ifdef FEAT_SEARCHPATH
713     char_u	*suf;
714 #endif
715     ff_search_ctx_T *search_ctx;
716 
717     if (search_ctx_arg == NULL)
718 	return NULL;
719 
720     search_ctx = (ff_search_ctx_T *)search_ctx_arg;
721 
722     /*
723      * filepath is used as buffer for various actions and as the storage to
724      * return a found filename.
725      */
726     if ((file_path = alloc((int)MAXPATHL)) == NULL)
727 	return NULL;
728 
729 #ifdef FEAT_PATH_EXTRA
730     // store the end of the start dir -- needed for upward search
731     if (search_ctx->ffsc_start_dir != NULL)
732 	path_end = &search_ctx->ffsc_start_dir[
733 					  STRLEN(search_ctx->ffsc_start_dir)];
734 #endif
735 
736 #ifdef FEAT_PATH_EXTRA
737     // upward search loop
738     for (;;)
739     {
740 #endif
741 	// downward search loop
742 	for (;;)
743 	{
744 	    // check if user user wants to stop the search
745 	    ui_breakcheck();
746 	    if (got_int)
747 		break;
748 
749 	    // get directory to work on from stack
750 	    stackp = ff_pop(search_ctx);
751 	    if (stackp == NULL)
752 		break;
753 
754 	    /*
755 	     * TODO: decide if we leave this test in
756 	     *
757 	     * GOOD: don't search a directory(-tree) twice.
758 	     * BAD:  - check linked list for every new directory entered.
759 	     *       - check for double files also done below
760 	     *
761 	     * Here we check if we already searched this directory.
762 	     * We already searched a directory if:
763 	     * 1) The directory is the same.
764 	     * 2) We would use the same wildcard string.
765 	     *
766 	     * Good if you have links on same directory via several ways
767 	     *  or you have selfreferences in directories (e.g. SuSE Linux 6.3:
768 	     *  /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop)
769 	     *
770 	     * This check is only needed for directories we work on for the
771 	     * first time (hence stackp->ff_filearray == NULL)
772 	     */
773 	    if (stackp->ffs_filearray == NULL
774 		    && ff_check_visited(&search_ctx->ffsc_dir_visited_list
775 							  ->ffvl_visited_list,
776 			stackp->ffs_fix_path
777 #ifdef FEAT_PATH_EXTRA
778 			, stackp->ffs_wc_path
779 #endif
780 			) == FAIL)
781 	    {
782 #ifdef FF_VERBOSE
783 		if (p_verbose >= 5)
784 		{
785 		    verbose_enter_scroll();
786 		    smsg("Already Searched: %s (%s)",
787 				   stackp->ffs_fix_path, stackp->ffs_wc_path);
788 		    // don't overwrite this either
789 		    msg_puts("\n");
790 		    verbose_leave_scroll();
791 		}
792 #endif
793 		ff_free_stack_element(stackp);
794 		continue;
795 	    }
796 #ifdef FF_VERBOSE
797 	    else if (p_verbose >= 5)
798 	    {
799 		verbose_enter_scroll();
800 		smsg("Searching: %s (%s)",
801 				   stackp->ffs_fix_path, stackp->ffs_wc_path);
802 		// don't overwrite this either
803 		msg_puts("\n");
804 		verbose_leave_scroll();
805 	    }
806 #endif
807 
808 	    // check depth
809 	    if (stackp->ffs_level <= 0)
810 	    {
811 		ff_free_stack_element(stackp);
812 		continue;
813 	    }
814 
815 	    file_path[0] = NUL;
816 
817 	    /*
818 	     * If no filearray till now expand wildcards
819 	     * The function expand_wildcards() can handle an array of paths
820 	     * and all possible expands are returned in one array. We use this
821 	     * to handle the expansion of '**' into an empty string.
822 	     */
823 	    if (stackp->ffs_filearray == NULL)
824 	    {
825 		char_u *dirptrs[2];
826 
827 		// we use filepath to build the path expand_wildcards() should
828 		// expand.
829 		dirptrs[0] = file_path;
830 		dirptrs[1] = NULL;
831 
832 		// if we have a start dir copy it in
833 		if (!vim_isAbsName(stackp->ffs_fix_path)
834 						&& search_ctx->ffsc_start_dir)
835 		{
836 		    if (STRLEN(search_ctx->ffsc_start_dir) + 1 < MAXPATHL)
837 		    {
838 			STRCPY(file_path, search_ctx->ffsc_start_dir);
839 			add_pathsep(file_path);
840 		    }
841 		    else
842 		    {
843 			ff_free_stack_element(stackp);
844 			goto fail;
845 		    }
846 		}
847 
848 		// append the fix part of the search path
849 		if (STRLEN(file_path) + STRLEN(stackp->ffs_fix_path) + 1
850 								    < MAXPATHL)
851 		{
852 		    STRCAT(file_path, stackp->ffs_fix_path);
853 		    add_pathsep(file_path);
854 		}
855 		else
856 		{
857 		    ff_free_stack_element(stackp);
858 		    goto fail;
859 		}
860 
861 #ifdef FEAT_PATH_EXTRA
862 		rest_of_wildcards = stackp->ffs_wc_path;
863 		if (*rest_of_wildcards != NUL)
864 		{
865 		    len = (int)STRLEN(file_path);
866 		    if (STRNCMP(rest_of_wildcards, "**", 2) == 0)
867 		    {
868 			// pointer to the restrict byte
869 			// The restrict byte is not a character!
870 			p = rest_of_wildcards + 2;
871 
872 			if (*p > 0)
873 			{
874 			    (*p)--;
875 			    if (len + 1 < MAXPATHL)
876 				file_path[len++] = '*';
877 			    else
878 			    {
879 				ff_free_stack_element(stackp);
880 				goto fail;
881 			    }
882 			}
883 
884 			if (*p == 0)
885 			{
886 			    // remove '**<numb> from wildcards
887 			    STRMOVE(rest_of_wildcards, rest_of_wildcards + 3);
888 			}
889 			else
890 			    rest_of_wildcards += 3;
891 
892 			if (stackp->ffs_star_star_empty == 0)
893 			{
894 			    // if not done before, expand '**' to empty
895 			    stackp->ffs_star_star_empty = 1;
896 			    dirptrs[1] = stackp->ffs_fix_path;
897 			}
898 		    }
899 
900 		    /*
901 		     * Here we copy until the next path separator or the end of
902 		     * the path. If we stop at a path separator, there is
903 		     * still something else left. This is handled below by
904 		     * pushing every directory returned from expand_wildcards()
905 		     * on the stack again for further search.
906 		     */
907 		    while (*rest_of_wildcards
908 			    && !vim_ispathsep(*rest_of_wildcards))
909 			if (len + 1 < MAXPATHL)
910 			    file_path[len++] = *rest_of_wildcards++;
911 			else
912 			{
913 			    ff_free_stack_element(stackp);
914 			    goto fail;
915 			}
916 
917 		    file_path[len] = NUL;
918 		    if (vim_ispathsep(*rest_of_wildcards))
919 			rest_of_wildcards++;
920 		}
921 #endif
922 
923 		/*
924 		 * Expand wildcards like "*" and "$VAR".
925 		 * If the path is a URL don't try this.
926 		 */
927 		if (path_with_url(dirptrs[0]))
928 		{
929 		    stackp->ffs_filearray = (char_u **)
930 					      alloc((unsigned)sizeof(char *));
931 		    if (stackp->ffs_filearray != NULL
932 			    && (stackp->ffs_filearray[0]
933 				= vim_strsave(dirptrs[0])) != NULL)
934 			stackp->ffs_filearray_size = 1;
935 		    else
936 			stackp->ffs_filearray_size = 0;
937 		}
938 		else
939 		    // Add EW_NOTWILD because the expanded path may contain
940 		    // wildcard characters that are to be taken literally.
941 		    // This is a bit of a hack.
942 		    expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs,
943 			    &stackp->ffs_filearray_size,
944 			    &stackp->ffs_filearray,
945 			    EW_DIR|EW_ADDSLASH|EW_SILENT|EW_NOTWILD);
946 
947 		stackp->ffs_filearray_cur = 0;
948 		stackp->ffs_stage = 0;
949 	    }
950 #ifdef FEAT_PATH_EXTRA
951 	    else
952 		rest_of_wildcards = &stackp->ffs_wc_path[
953 						 STRLEN(stackp->ffs_wc_path)];
954 #endif
955 
956 	    if (stackp->ffs_stage == 0)
957 	    {
958 		// this is the first time we work on this directory
959 #ifdef FEAT_PATH_EXTRA
960 		if (*rest_of_wildcards == NUL)
961 #endif
962 		{
963 		    /*
964 		     * We don't have further wildcards to expand, so we have to
965 		     * check for the final file now.
966 		     */
967 		    for (i = stackp->ffs_filearray_cur;
968 					  i < stackp->ffs_filearray_size; ++i)
969 		    {
970 			if (!path_with_url(stackp->ffs_filearray[i])
971 				      && !mch_isdir(stackp->ffs_filearray[i]))
972 			    continue;   /* not a directory */
973 
974 			// prepare the filename to be checked for existence
975 			// below
976 			if (STRLEN(stackp->ffs_filearray[i]) + 1
977 				+ STRLEN(search_ctx->ffsc_file_to_search)
978 								    < MAXPATHL)
979 			{
980 			    STRCPY(file_path, stackp->ffs_filearray[i]);
981 			    add_pathsep(file_path);
982 			    STRCAT(file_path, search_ctx->ffsc_file_to_search);
983 			}
984 			else
985 			{
986 			    ff_free_stack_element(stackp);
987 			    goto fail;
988 			}
989 
990 			/*
991 			 * Try without extra suffix and then with suffixes
992 			 * from 'suffixesadd'.
993 			 */
994 #ifdef FEAT_SEARCHPATH
995 			len = (int)STRLEN(file_path);
996 			if (search_ctx->ffsc_tagfile)
997 			    suf = (char_u *)"";
998 			else
999 			    suf = curbuf->b_p_sua;
1000 			for (;;)
1001 #endif
1002 			{
1003 			    // if file exists and we didn't already find it
1004 			    if ((path_with_url(file_path)
1005 				  || (mch_getperm(file_path) >= 0
1006 				      && (search_ctx->ffsc_find_what
1007 							      == FINDFILE_BOTH
1008 					  || ((search_ctx->ffsc_find_what
1009 							      == FINDFILE_DIR)
1010 						   == mch_isdir(file_path)))))
1011 #ifndef FF_VERBOSE
1012 				    && (ff_check_visited(
1013 					    &search_ctx->ffsc_visited_list->ffvl_visited_list,
1014 					    file_path
1015 #ifdef FEAT_PATH_EXTRA
1016 					    , (char_u *)""
1017 #endif
1018 					    ) == OK)
1019 #endif
1020 			       )
1021 			    {
1022 #ifdef FF_VERBOSE
1023 				if (ff_check_visited(
1024 					    &search_ctx->ffsc_visited_list->ffvl_visited_list,
1025 					    file_path
1026 #ifdef FEAT_PATH_EXTRA
1027 					    , (char_u *)""
1028 #endif
1029 						    ) == FAIL)
1030 				{
1031 				    if (p_verbose >= 5)
1032 				    {
1033 					verbose_enter_scroll();
1034 					smsg("Already: %s",
1035 								   file_path);
1036 					// don't overwrite this either
1037 					msg_puts("\n");
1038 					verbose_leave_scroll();
1039 				    }
1040 				    continue;
1041 				}
1042 #endif
1043 
1044 				// push dir to examine rest of subdirs later
1045 				stackp->ffs_filearray_cur = i + 1;
1046 				ff_push(search_ctx, stackp);
1047 
1048 				if (!path_with_url(file_path))
1049 				    simplify_filename(file_path);
1050 				if (mch_dirname(ff_expand_buffer, MAXPATHL)
1051 									== OK)
1052 				{
1053 				    p = shorten_fname(file_path,
1054 							    ff_expand_buffer);
1055 				    if (p != NULL)
1056 					STRMOVE(file_path, p);
1057 				}
1058 #ifdef FF_VERBOSE
1059 				if (p_verbose >= 5)
1060 				{
1061 				    verbose_enter_scroll();
1062 				    smsg("HIT: %s", file_path);
1063 				    // don't overwrite this either
1064 				    msg_puts("\n");
1065 				    verbose_leave_scroll();
1066 				}
1067 #endif
1068 				return file_path;
1069 			    }
1070 
1071 #ifdef FEAT_SEARCHPATH
1072 			    // Not found or found already, try next suffix.
1073 			    if (*suf == NUL)
1074 				break;
1075 			    copy_option_part(&suf, file_path + len,
1076 							 MAXPATHL - len, ",");
1077 #endif
1078 			}
1079 		    }
1080 		}
1081 #ifdef FEAT_PATH_EXTRA
1082 		else
1083 		{
1084 		    /*
1085 		     * still wildcards left, push the directories for further
1086 		     * search
1087 		     */
1088 		    for (i = stackp->ffs_filearray_cur;
1089 					  i < stackp->ffs_filearray_size; ++i)
1090 		    {
1091 			if (!mch_isdir(stackp->ffs_filearray[i]))
1092 			    continue;	// not a directory
1093 
1094 			ff_push(search_ctx,
1095 				ff_create_stack_element(
1096 						     stackp->ffs_filearray[i],
1097 						     rest_of_wildcards,
1098 						     stackp->ffs_level - 1, 0));
1099 		    }
1100 		}
1101 #endif
1102 		stackp->ffs_filearray_cur = 0;
1103 		stackp->ffs_stage = 1;
1104 	    }
1105 
1106 #ifdef FEAT_PATH_EXTRA
1107 	    /*
1108 	     * if wildcards contains '**' we have to descent till we reach the
1109 	     * leaves of the directory tree.
1110 	     */
1111 	    if (STRNCMP(stackp->ffs_wc_path, "**", 2) == 0)
1112 	    {
1113 		for (i = stackp->ffs_filearray_cur;
1114 					  i < stackp->ffs_filearray_size; ++i)
1115 		{
1116 		    if (fnamecmp(stackp->ffs_filearray[i],
1117 						   stackp->ffs_fix_path) == 0)
1118 			continue; // don't repush same directory
1119 		    if (!mch_isdir(stackp->ffs_filearray[i]))
1120 			continue;   // not a directory
1121 		    ff_push(search_ctx,
1122 			    ff_create_stack_element(stackp->ffs_filearray[i],
1123 				stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
1124 		}
1125 	    }
1126 #endif
1127 
1128 	    // we are done with the current directory
1129 	    ff_free_stack_element(stackp);
1130 
1131 	}
1132 
1133 #ifdef FEAT_PATH_EXTRA
1134 	// If we reached this, we didn't find anything downwards.
1135 	// Let's check if we should do an upward search.
1136 	if (search_ctx->ffsc_start_dir
1137 		&& search_ctx->ffsc_stopdirs_v != NULL && !got_int)
1138 	{
1139 	    ff_stack_T  *sptr;
1140 
1141 	    // is the last starting directory in the stop list?
1142 	    if (ff_path_in_stoplist(search_ctx->ffsc_start_dir,
1143 		       (int)(path_end - search_ctx->ffsc_start_dir),
1144 		       search_ctx->ffsc_stopdirs_v) == TRUE)
1145 		break;
1146 
1147 	    // cut of last dir
1148 	    while (path_end > search_ctx->ffsc_start_dir
1149 						  && vim_ispathsep(*path_end))
1150 		path_end--;
1151 	    while (path_end > search_ctx->ffsc_start_dir
1152 					      && !vim_ispathsep(path_end[-1]))
1153 		path_end--;
1154 	    *path_end = 0;
1155 	    path_end--;
1156 
1157 	    if (*search_ctx->ffsc_start_dir == 0)
1158 		break;
1159 
1160 	    if (STRLEN(search_ctx->ffsc_start_dir) + 1
1161 		    + STRLEN(search_ctx->ffsc_fix_path) < MAXPATHL)
1162 	    {
1163 		STRCPY(file_path, search_ctx->ffsc_start_dir);
1164 		add_pathsep(file_path);
1165 		STRCAT(file_path, search_ctx->ffsc_fix_path);
1166 	    }
1167 	    else
1168 		goto fail;
1169 
1170 	    // create a new stack entry
1171 	    sptr = ff_create_stack_element(file_path,
1172 		    search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0);
1173 	    if (sptr == NULL)
1174 		break;
1175 	    ff_push(search_ctx, sptr);
1176 	}
1177 	else
1178 	    break;
1179     }
1180 #endif
1181 
1182 fail:
1183     vim_free(file_path);
1184     return NULL;
1185 }
1186 
1187 /*
1188  * Free the list of lists of visited files and directories
1189  * Can handle it if the passed search_context is NULL;
1190  */
1191     void
1192 vim_findfile_free_visited(void *search_ctx_arg)
1193 {
1194     ff_search_ctx_T *search_ctx;
1195 
1196     if (search_ctx_arg == NULL)
1197 	return;
1198 
1199     search_ctx = (ff_search_ctx_T *)search_ctx_arg;
1200     vim_findfile_free_visited_list(&search_ctx->ffsc_visited_lists_list);
1201     vim_findfile_free_visited_list(&search_ctx->ffsc_dir_visited_lists_list);
1202 }
1203 
1204     static void
1205 vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp)
1206 {
1207     ff_visited_list_hdr_T *vp;
1208 
1209     while (*list_headp != NULL)
1210     {
1211 	vp = (*list_headp)->ffvl_next;
1212 	ff_free_visited_list((*list_headp)->ffvl_visited_list);
1213 
1214 	vim_free((*list_headp)->ffvl_filename);
1215 	vim_free(*list_headp);
1216 	*list_headp = vp;
1217     }
1218     *list_headp = NULL;
1219 }
1220 
1221     static void
1222 ff_free_visited_list(ff_visited_T *vl)
1223 {
1224     ff_visited_T *vp;
1225 
1226     while (vl != NULL)
1227     {
1228 	vp = vl->ffv_next;
1229 #ifdef FEAT_PATH_EXTRA
1230 	vim_free(vl->ffv_wc_path);
1231 #endif
1232 	vim_free(vl);
1233 	vl = vp;
1234     }
1235     vl = NULL;
1236 }
1237 
1238 /*
1239  * Returns the already visited list for the given filename. If none is found it
1240  * allocates a new one.
1241  */
1242     static ff_visited_list_hdr_T*
1243 ff_get_visited_list(
1244     char_u			*filename,
1245     ff_visited_list_hdr_T	**list_headp)
1246 {
1247     ff_visited_list_hdr_T  *retptr = NULL;
1248 
1249     // check if a visited list for the given filename exists
1250     if (*list_headp != NULL)
1251     {
1252 	retptr = *list_headp;
1253 	while (retptr != NULL)
1254 	{
1255 	    if (fnamecmp(filename, retptr->ffvl_filename) == 0)
1256 	    {
1257 #ifdef FF_VERBOSE
1258 		if (p_verbose >= 5)
1259 		{
1260 		    verbose_enter_scroll();
1261 		    smsg("ff_get_visited_list: FOUND list for %s",
1262 								    filename);
1263 		    // don't overwrite this either
1264 		    msg_puts("\n");
1265 		    verbose_leave_scroll();
1266 		}
1267 #endif
1268 		return retptr;
1269 	    }
1270 	    retptr = retptr->ffvl_next;
1271 	}
1272     }
1273 
1274 #ifdef FF_VERBOSE
1275     if (p_verbose >= 5)
1276     {
1277 	verbose_enter_scroll();
1278 	smsg("ff_get_visited_list: new list for %s", filename);
1279 	// don't overwrite this either
1280 	msg_puts("\n");
1281 	verbose_leave_scroll();
1282     }
1283 #endif
1284 
1285     /*
1286      * if we reach this we didn't find a list and we have to allocate new list
1287      */
1288     retptr = (ff_visited_list_hdr_T*)alloc((unsigned)sizeof(*retptr));
1289     if (retptr == NULL)
1290 	return NULL;
1291 
1292     retptr->ffvl_visited_list = NULL;
1293     retptr->ffvl_filename = vim_strsave(filename);
1294     if (retptr->ffvl_filename == NULL)
1295     {
1296 	vim_free(retptr);
1297 	return NULL;
1298     }
1299     retptr->ffvl_next = *list_headp;
1300     *list_headp = retptr;
1301 
1302     return retptr;
1303 }
1304 
1305 #ifdef FEAT_PATH_EXTRA
1306 /*
1307  * check if two wildcard paths are equal. Returns TRUE or FALSE.
1308  * They are equal if:
1309  *  - both paths are NULL
1310  *  - they have the same length
1311  *  - char by char comparison is OK
1312  *  - the only differences are in the counters behind a '**', so
1313  *    '**\20' is equal to '**\24'
1314  */
1315     static int
1316 ff_wc_equal(char_u *s1, char_u *s2)
1317 {
1318     int		i, j;
1319     int		c1 = NUL;
1320     int		c2 = NUL;
1321     int		prev1 = NUL;
1322     int		prev2 = NUL;
1323 
1324     if (s1 == s2)
1325 	return TRUE;
1326 
1327     if (s1 == NULL || s2 == NULL)
1328 	return FALSE;
1329 
1330     for (i = 0, j = 0; s1[i] != NUL && s2[j] != NUL;)
1331     {
1332 	c1 = PTR2CHAR(s1 + i);
1333 	c2 = PTR2CHAR(s2 + j);
1334 
1335 	if ((p_fic ? MB_TOLOWER(c1) != MB_TOLOWER(c2) : c1 != c2)
1336 		&& (prev1 != '*' || prev2 != '*'))
1337 	    return FALSE;
1338 	prev2 = prev1;
1339 	prev1 = c1;
1340 
1341 	i += MB_PTR2LEN(s1 + i);
1342 	j += MB_PTR2LEN(s2 + j);
1343     }
1344     return s1[i] == s2[j];
1345 }
1346 #endif
1347 
1348 /*
1349  * maintains the list of already visited files and dirs
1350  * returns FAIL if the given file/dir is already in the list
1351  * returns OK if it is newly added
1352  *
1353  * TODO: What to do on memory allocation problems?
1354  *	 -> return TRUE - Better the file is found several times instead of
1355  *	    never.
1356  */
1357     static int
1358 ff_check_visited(
1359     ff_visited_T	**visited_list,
1360     char_u		*fname
1361 #ifdef FEAT_PATH_EXTRA
1362     , char_u		*wc_path
1363 #endif
1364     )
1365 {
1366     ff_visited_T	*vp;
1367 #ifdef UNIX
1368     stat_T		st;
1369     int			url = FALSE;
1370 #endif
1371 
1372     // For an URL we only compare the name, otherwise we compare the
1373     // device/inode (unix) or the full path name (not Unix).
1374     if (path_with_url(fname))
1375     {
1376 	vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);
1377 #ifdef UNIX
1378 	url = TRUE;
1379 #endif
1380     }
1381     else
1382     {
1383 	ff_expand_buffer[0] = NUL;
1384 #ifdef UNIX
1385 	if (mch_stat((char *)fname, &st) < 0)
1386 #else
1387 	if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
1388 #endif
1389 	    return FAIL;
1390     }
1391 
1392     // check against list of already visited files
1393     for (vp = *visited_list; vp != NULL; vp = vp->ffv_next)
1394     {
1395 	if (
1396 #ifdef UNIX
1397 		!url ? (vp->ffv_dev_valid && vp->ffv_dev == st.st_dev
1398 						  && vp->ffv_ino == st.st_ino)
1399 		     :
1400 #endif
1401 		fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
1402 	   )
1403 	{
1404 #ifdef FEAT_PATH_EXTRA
1405 	    // are the wildcard parts equal
1406 	    if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
1407 #endif
1408 		// already visited
1409 		return FAIL;
1410 	}
1411     }
1412 
1413     /*
1414      * New file/dir.  Add it to the list of visited files/dirs.
1415      */
1416     vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T)
1417 						 + STRLEN(ff_expand_buffer)));
1418 
1419     if (vp != NULL)
1420     {
1421 #ifdef UNIX
1422 	if (!url)
1423 	{
1424 	    vp->ffv_dev_valid = TRUE;
1425 	    vp->ffv_ino = st.st_ino;
1426 	    vp->ffv_dev = st.st_dev;
1427 	    vp->ffv_fname[0] = NUL;
1428 	}
1429 	else
1430 	{
1431 	    vp->ffv_dev_valid = FALSE;
1432 #endif
1433 	    STRCPY(vp->ffv_fname, ff_expand_buffer);
1434 #ifdef UNIX
1435 	}
1436 #endif
1437 #ifdef FEAT_PATH_EXTRA
1438 	if (wc_path != NULL)
1439 	    vp->ffv_wc_path = vim_strsave(wc_path);
1440 	else
1441 	    vp->ffv_wc_path = NULL;
1442 #endif
1443 
1444 	vp->ffv_next = *visited_list;
1445 	*visited_list = vp;
1446     }
1447 
1448     return OK;
1449 }
1450 
1451 /*
1452  * create stack element from given path pieces
1453  */
1454     static ff_stack_T *
1455 ff_create_stack_element(
1456     char_u	*fix_part,
1457 #ifdef FEAT_PATH_EXTRA
1458     char_u	*wc_part,
1459 #endif
1460     int		level,
1461     int		star_star_empty)
1462 {
1463     ff_stack_T	*new;
1464 
1465     new = (ff_stack_T *)alloc((unsigned)sizeof(ff_stack_T));
1466     if (new == NULL)
1467 	return NULL;
1468 
1469     new->ffs_prev	   = NULL;
1470     new->ffs_filearray	   = NULL;
1471     new->ffs_filearray_size = 0;
1472     new->ffs_filearray_cur  = 0;
1473     new->ffs_stage	   = 0;
1474     new->ffs_level	   = level;
1475     new->ffs_star_star_empty = star_star_empty;
1476 
1477     // the following saves NULL pointer checks in vim_findfile
1478     if (fix_part == NULL)
1479 	fix_part = (char_u *)"";
1480     new->ffs_fix_path = vim_strsave(fix_part);
1481 
1482 #ifdef FEAT_PATH_EXTRA
1483     if (wc_part == NULL)
1484 	wc_part  = (char_u *)"";
1485     new->ffs_wc_path = vim_strsave(wc_part);
1486 #endif
1487 
1488     if (new->ffs_fix_path == NULL
1489 #ifdef FEAT_PATH_EXTRA
1490 	    || new->ffs_wc_path == NULL
1491 #endif
1492 	    )
1493     {
1494 	ff_free_stack_element(new);
1495 	new = NULL;
1496     }
1497 
1498     return new;
1499 }
1500 
1501 /*
1502  * Push a dir on the directory stack.
1503  */
1504     static void
1505 ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr)
1506 {
1507     // check for NULL pointer, not to return an error to the user, but
1508     // to prevent a crash
1509     if (stack_ptr != NULL)
1510     {
1511 	stack_ptr->ffs_prev = search_ctx->ffsc_stack_ptr;
1512 	search_ctx->ffsc_stack_ptr = stack_ptr;
1513     }
1514 }
1515 
1516 /*
1517  * Pop a dir from the directory stack.
1518  * Returns NULL if stack is empty.
1519  */
1520     static ff_stack_T *
1521 ff_pop(ff_search_ctx_T *search_ctx)
1522 {
1523     ff_stack_T  *sptr;
1524 
1525     sptr = search_ctx->ffsc_stack_ptr;
1526     if (search_ctx->ffsc_stack_ptr != NULL)
1527 	search_ctx->ffsc_stack_ptr = search_ctx->ffsc_stack_ptr->ffs_prev;
1528 
1529     return sptr;
1530 }
1531 
1532 /*
1533  * free the given stack element
1534  */
1535     static void
1536 ff_free_stack_element(ff_stack_T *stack_ptr)
1537 {
1538     // vim_free handles possible NULL pointers
1539     vim_free(stack_ptr->ffs_fix_path);
1540 #ifdef FEAT_PATH_EXTRA
1541     vim_free(stack_ptr->ffs_wc_path);
1542 #endif
1543 
1544     if (stack_ptr->ffs_filearray != NULL)
1545 	FreeWild(stack_ptr->ffs_filearray_size, stack_ptr->ffs_filearray);
1546 
1547     vim_free(stack_ptr);
1548 }
1549 
1550 /*
1551  * Clear the search context, but NOT the visited list.
1552  */
1553     static void
1554 ff_clear(ff_search_ctx_T *search_ctx)
1555 {
1556     ff_stack_T   *sptr;
1557 
1558     // clear up stack
1559     while ((sptr = ff_pop(search_ctx)) != NULL)
1560 	ff_free_stack_element(sptr);
1561 
1562     vim_free(search_ctx->ffsc_file_to_search);
1563     vim_free(search_ctx->ffsc_start_dir);
1564     vim_free(search_ctx->ffsc_fix_path);
1565 #ifdef FEAT_PATH_EXTRA
1566     vim_free(search_ctx->ffsc_wc_path);
1567 #endif
1568 
1569 #ifdef FEAT_PATH_EXTRA
1570     if (search_ctx->ffsc_stopdirs_v != NULL)
1571     {
1572 	int  i = 0;
1573 
1574 	while (search_ctx->ffsc_stopdirs_v[i] != NULL)
1575 	{
1576 	    vim_free(search_ctx->ffsc_stopdirs_v[i]);
1577 	    i++;
1578 	}
1579 	vim_free(search_ctx->ffsc_stopdirs_v);
1580     }
1581     search_ctx->ffsc_stopdirs_v = NULL;
1582 #endif
1583 
1584     // reset everything
1585     search_ctx->ffsc_file_to_search = NULL;
1586     search_ctx->ffsc_start_dir = NULL;
1587     search_ctx->ffsc_fix_path = NULL;
1588 #ifdef FEAT_PATH_EXTRA
1589     search_ctx->ffsc_wc_path = NULL;
1590     search_ctx->ffsc_level = 0;
1591 #endif
1592 }
1593 
1594 #ifdef FEAT_PATH_EXTRA
1595 /*
1596  * check if the given path is in the stopdirs
1597  * returns TRUE if yes else FALSE
1598  */
1599     static int
1600 ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v)
1601 {
1602     int		i = 0;
1603 
1604     // eat up trailing path separators, except the first
1605     while (path_len > 1 && vim_ispathsep(path[path_len - 1]))
1606 	path_len--;
1607 
1608     // if no path consider it as match
1609     if (path_len == 0)
1610 	return TRUE;
1611 
1612     for (i = 0; stopdirs_v[i] != NULL; i++)
1613     {
1614 	if ((int)STRLEN(stopdirs_v[i]) > path_len)
1615 	{
1616 	    // match for parent directory. So '/home' also matches
1617 	    // '/home/rks'. Check for PATHSEP in stopdirs_v[i], else
1618 	    // '/home/r' would also match '/home/rks'
1619 	    if (fnamencmp(stopdirs_v[i], path, path_len) == 0
1620 		    && vim_ispathsep(stopdirs_v[i][path_len]))
1621 		return TRUE;
1622 	}
1623 	else
1624 	{
1625 	    if (fnamecmp(stopdirs_v[i], path) == 0)
1626 		return TRUE;
1627 	}
1628     }
1629     return FALSE;
1630 }
1631 #endif
1632 
1633 #if defined(FEAT_SEARCHPATH) || defined(PROTO)
1634 /*
1635  * Find the file name "ptr[len]" in the path.  Also finds directory names.
1636  *
1637  * On the first call set the parameter 'first' to TRUE to initialize
1638  * the search.  For repeating calls to FALSE.
1639  *
1640  * Repeating calls will return other files called 'ptr[len]' from the path.
1641  *
1642  * Only on the first call 'ptr' and 'len' are used.  For repeating calls they
1643  * don't need valid values.
1644  *
1645  * If nothing found on the first call the option FNAME_MESS will issue the
1646  * message:
1647  *	    'Can't find file "<file>" in path'
1648  * On repeating calls:
1649  *	    'No more file "<file>" found in path'
1650  *
1651  * options:
1652  * FNAME_MESS	    give error message when not found
1653  *
1654  * Uses NameBuff[]!
1655  *
1656  * Returns an allocated string for the file name.  NULL for error.
1657  *
1658  */
1659     char_u *
1660 find_file_in_path(
1661     char_u	*ptr,		// file name
1662     int		len,		// length of file name
1663     int		options,
1664     int		first,		// use count'th matching file name
1665     char_u	*rel_fname)	// file name searching relative to
1666 {
1667     return find_file_in_path_option(ptr, len, options, first,
1668 	    *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path,
1669 	    FINDFILE_BOTH, rel_fname, curbuf->b_p_sua);
1670 }
1671 
1672 static char_u	*ff_file_to_find = NULL;
1673 static void	*fdip_search_ctx = NULL;
1674 
1675 # if defined(EXITFREE) || defined(PROTO)
1676     void
1677 free_findfile(void)
1678 {
1679     vim_free(ff_file_to_find);
1680     vim_findfile_cleanup(fdip_search_ctx);
1681     vim_free(ff_expand_buffer);
1682 }
1683 # endif
1684 
1685 /*
1686  * Find the directory name "ptr[len]" in the path.
1687  *
1688  * options:
1689  * FNAME_MESS	    give error message when not found
1690  * FNAME_UNESC	    unescape backslashes.
1691  *
1692  * Uses NameBuff[]!
1693  *
1694  * Returns an allocated string for the file name.  NULL for error.
1695  */
1696     char_u *
1697 find_directory_in_path(
1698     char_u	*ptr,		// file name
1699     int		len,		// length of file name
1700     int		options,
1701     char_u	*rel_fname)	// file name searching relative to
1702 {
1703     return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath,
1704 				       FINDFILE_DIR, rel_fname, (char_u *)"");
1705 }
1706 
1707     char_u *
1708 find_file_in_path_option(
1709     char_u	*ptr,		// file name
1710     int		len,		// length of file name
1711     int		options,
1712     int		first,		// use count'th matching file name
1713     char_u	*path_option,	// p_path or p_cdpath
1714     int		find_what,	// FINDFILE_FILE, _DIR or _BOTH
1715     char_u	*rel_fname,	// file name we are looking relative to.
1716     char_u	*suffixes)	// list of suffixes, 'suffixesadd' option
1717 {
1718     static char_u	*dir;
1719     static int		did_findfile_init = FALSE;
1720     char_u		save_char;
1721     char_u		*file_name = NULL;
1722     char_u		*buf = NULL;
1723     int			rel_to_curdir;
1724 # ifdef AMIGA
1725     struct Process	*proc = (struct Process *)FindTask(0L);
1726     APTR		save_winptr = proc->pr_WindowPtr;
1727 
1728     // Avoid a requester here for a volume that doesn't exist.
1729     proc->pr_WindowPtr = (APTR)-1L;
1730 # endif
1731 
1732     if (first == TRUE)
1733     {
1734 	// copy file name into NameBuff, expanding environment variables
1735 	save_char = ptr[len];
1736 	ptr[len] = NUL;
1737 	expand_env_esc(ptr, NameBuff, MAXPATHL, FALSE, TRUE, NULL);
1738 	ptr[len] = save_char;
1739 
1740 	vim_free(ff_file_to_find);
1741 	ff_file_to_find = vim_strsave(NameBuff);
1742 	if (ff_file_to_find == NULL)	// out of memory
1743 	{
1744 	    file_name = NULL;
1745 	    goto theend;
1746 	}
1747 	if (options & FNAME_UNESC)
1748 	{
1749 	    // Change all "\ " to " ".
1750 	    for (ptr = ff_file_to_find; *ptr != NUL; ++ptr)
1751 		if (ptr[0] == '\\' && ptr[1] == ' ')
1752 		    mch_memmove(ptr, ptr + 1, STRLEN(ptr));
1753 	}
1754     }
1755 
1756     rel_to_curdir = (ff_file_to_find[0] == '.'
1757 		    && (ff_file_to_find[1] == NUL
1758 			|| vim_ispathsep(ff_file_to_find[1])
1759 			|| (ff_file_to_find[1] == '.'
1760 			    && (ff_file_to_find[2] == NUL
1761 				|| vim_ispathsep(ff_file_to_find[2])))));
1762     if (vim_isAbsName(ff_file_to_find)
1763 	    // "..", "../path", "." and "./path": don't use the path_option
1764 	    || rel_to_curdir
1765 # if defined(MSWIN)
1766 	    // handle "\tmp" as absolute path
1767 	    || vim_ispathsep(ff_file_to_find[0])
1768 	    // handle "c:name" as absolute path
1769 	    || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':')
1770 # endif
1771 # ifdef AMIGA
1772 	    // handle ":tmp" as absolute path
1773 	    || ff_file_to_find[0] == ':'
1774 # endif
1775        )
1776     {
1777 	/*
1778 	 * Absolute path, no need to use "path_option".
1779 	 * If this is not a first call, return NULL.  We already returned a
1780 	 * filename on the first call.
1781 	 */
1782 	if (first == TRUE)
1783 	{
1784 	    int		l;
1785 	    int		run;
1786 
1787 	    if (path_with_url(ff_file_to_find))
1788 	    {
1789 		file_name = vim_strsave(ff_file_to_find);
1790 		goto theend;
1791 	    }
1792 
1793 	    // When FNAME_REL flag given first use the directory of the file.
1794 	    // Otherwise or when this fails use the current directory.
1795 	    for (run = 1; run <= 2; ++run)
1796 	    {
1797 		l = (int)STRLEN(ff_file_to_find);
1798 		if (run == 1
1799 			&& rel_to_curdir
1800 			&& (options & FNAME_REL)
1801 			&& rel_fname != NULL
1802 			&& STRLEN(rel_fname) + l < MAXPATHL)
1803 		{
1804 		    STRCPY(NameBuff, rel_fname);
1805 		    STRCPY(gettail(NameBuff), ff_file_to_find);
1806 		    l = (int)STRLEN(NameBuff);
1807 		}
1808 		else
1809 		{
1810 		    STRCPY(NameBuff, ff_file_to_find);
1811 		    run = 2;
1812 		}
1813 
1814 		// When the file doesn't exist, try adding parts of
1815 		// 'suffixesadd'.
1816 		buf = suffixes;
1817 		for (;;)
1818 		{
1819 		    if (mch_getperm(NameBuff) >= 0
1820 			     && (find_what == FINDFILE_BOTH
1821 				 || ((find_what == FINDFILE_DIR)
1822 						    == mch_isdir(NameBuff))))
1823 		    {
1824 			file_name = vim_strsave(NameBuff);
1825 			goto theend;
1826 		    }
1827 		    if (*buf == NUL)
1828 			break;
1829 		    copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ",");
1830 		}
1831 	    }
1832 	}
1833     }
1834     else
1835     {
1836 	/*
1837 	 * Loop over all paths in the 'path' or 'cdpath' option.
1838 	 * When "first" is set, first setup to the start of the option.
1839 	 * Otherwise continue to find the next match.
1840 	 */
1841 	if (first == TRUE)
1842 	{
1843 	    // vim_findfile_free_visited can handle a possible NULL pointer
1844 	    vim_findfile_free_visited(fdip_search_ctx);
1845 	    dir = path_option;
1846 	    did_findfile_init = FALSE;
1847 	}
1848 
1849 	for (;;)
1850 	{
1851 	    if (did_findfile_init)
1852 	    {
1853 		file_name = vim_findfile(fdip_search_ctx);
1854 		if (file_name != NULL)
1855 		    break;
1856 
1857 		did_findfile_init = FALSE;
1858 	    }
1859 	    else
1860 	    {
1861 		char_u  *r_ptr;
1862 
1863 		if (dir == NULL || *dir == NUL)
1864 		{
1865 		    // We searched all paths of the option, now we can
1866 		    // free the search context.
1867 		    vim_findfile_cleanup(fdip_search_ctx);
1868 		    fdip_search_ctx = NULL;
1869 		    break;
1870 		}
1871 
1872 		if ((buf = alloc((int)(MAXPATHL))) == NULL)
1873 		    break;
1874 
1875 		// copy next path
1876 		buf[0] = 0;
1877 		copy_option_part(&dir, buf, MAXPATHL, " ,");
1878 
1879 # ifdef FEAT_PATH_EXTRA
1880 		// get the stopdir string
1881 		r_ptr = vim_findfile_stopdir(buf);
1882 # else
1883 		r_ptr = NULL;
1884 # endif
1885 		fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find,
1886 					    r_ptr, 100, FALSE, find_what,
1887 					   fdip_search_ctx, FALSE, rel_fname);
1888 		if (fdip_search_ctx != NULL)
1889 		    did_findfile_init = TRUE;
1890 		vim_free(buf);
1891 	    }
1892 	}
1893     }
1894     if (file_name == NULL && (options & FNAME_MESS))
1895     {
1896 	if (first == TRUE)
1897 	{
1898 	    if (find_what == FINDFILE_DIR)
1899 		semsg(_("E344: Can't find directory \"%s\" in cdpath"),
1900 			ff_file_to_find);
1901 	    else
1902 		semsg(_("E345: Can't find file \"%s\" in path"),
1903 			ff_file_to_find);
1904 	}
1905 	else
1906 	{
1907 	    if (find_what == FINDFILE_DIR)
1908 		semsg(_("E346: No more directory \"%s\" found in cdpath"),
1909 			ff_file_to_find);
1910 	    else
1911 		semsg(_("E347: No more file \"%s\" found in path"),
1912 			ff_file_to_find);
1913 	}
1914     }
1915 
1916 theend:
1917 # ifdef AMIGA
1918     proc->pr_WindowPtr = save_winptr;
1919 # endif
1920     return file_name;
1921 }
1922 
1923 /*
1924  * Get the file name at the cursor.
1925  * If Visual mode is active, use the selected text if it's in one line.
1926  * Returns the name in allocated memory, NULL for failure.
1927  */
1928     char_u *
1929 grab_file_name(long count, linenr_T *file_lnum)
1930 {
1931     int options = FNAME_MESS|FNAME_EXP|FNAME_REL|FNAME_UNESC;
1932 
1933     if (VIsual_active)
1934     {
1935 	int	len;
1936 	char_u	*ptr;
1937 
1938 	if (get_visual_text(NULL, &ptr, &len) == FAIL)
1939 	    return NULL;
1940 	return find_file_name_in_path(ptr, len, options,
1941 						     count, curbuf->b_ffname);
1942     }
1943     return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
1944 }
1945 
1946 /*
1947  * Return the file name under or after the cursor.
1948  *
1949  * The 'path' option is searched if the file name is not absolute.
1950  * The string returned has been alloc'ed and should be freed by the caller.
1951  * NULL is returned if the file name or file is not found.
1952  *
1953  * options:
1954  * FNAME_MESS	    give error messages
1955  * FNAME_EXP	    expand to path
1956  * FNAME_HYP	    check for hypertext link
1957  * FNAME_INCL	    apply "includeexpr"
1958  */
1959     char_u *
1960 file_name_at_cursor(int options, long count, linenr_T *file_lnum)
1961 {
1962     return file_name_in_line(ml_get_curline(),
1963 		      curwin->w_cursor.col, options, count, curbuf->b_ffname,
1964 		      file_lnum);
1965 }
1966 
1967 /*
1968  * Return the name of the file under or after ptr[col].
1969  * Otherwise like file_name_at_cursor().
1970  */
1971     char_u *
1972 file_name_in_line(
1973     char_u	*line,
1974     int		col,
1975     int		options,
1976     long	count,
1977     char_u	*rel_fname,	// file we are searching relative to
1978     linenr_T	*file_lnum)	// line number after the file name
1979 {
1980     char_u	*ptr;
1981     int		len;
1982     int		in_type = TRUE;
1983     int		is_url = FALSE;
1984 
1985     /*
1986      * search forward for what could be the start of a file name
1987      */
1988     ptr = line + col;
1989     while (*ptr != NUL && !vim_isfilec(*ptr))
1990 	MB_PTR_ADV(ptr);
1991     if (*ptr == NUL)		// nothing found
1992     {
1993 	if (options & FNAME_MESS)
1994 	    emsg(_("E446: No file name under cursor"));
1995 	return NULL;
1996     }
1997 
1998     /*
1999      * Search backward for first char of the file name.
2000      * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
2001      */
2002     while (ptr > line)
2003     {
2004 	if (has_mbyte && (len = (*mb_head_off)(line, ptr - 1)) > 0)
2005 	    ptr -= len + 1;
2006 	else if (vim_isfilec(ptr[-1])
2007 		|| ((options & FNAME_HYP) && path_is_url(ptr - 1)))
2008 	    --ptr;
2009 	else
2010 	    break;
2011     }
2012 
2013     /*
2014      * Search forward for the last char of the file name.
2015      * Also allow "://" when ':' is not in 'isfname'.
2016      */
2017     len = 0;
2018     while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
2019 			 || ((options & FNAME_HYP) && path_is_url(ptr + len))
2020 			 || (is_url && vim_strchr((char_u *)":?&=", ptr[len]) != NULL))
2021     {
2022 	// After type:// we also include :, ?, & and = as valid characters, so that
2023 	// http://google.com:8080?q=this&that=ok works.
2024 	if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z'))
2025 	{
2026 	    if (in_type && path_is_url(ptr + len + 1))
2027 		is_url = TRUE;
2028 	}
2029 	else
2030 	    in_type = FALSE;
2031 
2032 	if (ptr[len] == '\\')
2033 	    // Skip over the "\" in "\ ".
2034 	    ++len;
2035 	if (has_mbyte)
2036 	    len += (*mb_ptr2len)(ptr + len);
2037 	else
2038 	    ++len;
2039     }
2040 
2041     /*
2042      * If there is trailing punctuation, remove it.
2043      * But don't remove "..", could be a directory name.
2044      */
2045     if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
2046 						       && ptr[len - 2] != '.')
2047 	--len;
2048 
2049     if (file_lnum != NULL)
2050     {
2051 	char_u *p;
2052 
2053 	// Get the number after the file name and a separator character
2054 	p = ptr + len;
2055 	p = skipwhite(p);
2056 	if (*p != NUL)
2057 	{
2058 	    if (!isdigit(*p))
2059 		++p;		    // skip the separator
2060 	    p = skipwhite(p);
2061 	    if (isdigit(*p))
2062 		*file_lnum = (int)getdigits(&p);
2063 	}
2064     }
2065 
2066     return find_file_name_in_path(ptr, len, options, count, rel_fname);
2067 }
2068 
2069 # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
2070     static char_u *
2071 eval_includeexpr(char_u *ptr, int len)
2072 {
2073     char_u	*res;
2074 
2075     set_vim_var_string(VV_FNAME, ptr, len);
2076     res = eval_to_string_safe(curbuf->b_p_inex, NULL,
2077 		      was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL));
2078     set_vim_var_string(VV_FNAME, NULL, 0);
2079     return res;
2080 }
2081 # endif
2082 
2083 /*
2084  * Return the name of the file ptr[len] in 'path'.
2085  * Otherwise like file_name_at_cursor().
2086  */
2087     char_u *
2088 find_file_name_in_path(
2089     char_u	*ptr,
2090     int		len,
2091     int		options,
2092     long	count,
2093     char_u	*rel_fname)	// file we are searching relative to
2094 {
2095     char_u	*file_name;
2096     int		c;
2097 # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
2098     char_u	*tofree = NULL;
2099 
2100     if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
2101     {
2102 	tofree = eval_includeexpr(ptr, len);
2103 	if (tofree != NULL)
2104 	{
2105 	    ptr = tofree;
2106 	    len = (int)STRLEN(ptr);
2107 	}
2108     }
2109 # endif
2110 
2111     if (options & FNAME_EXP)
2112     {
2113 	file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
2114 							     TRUE, rel_fname);
2115 
2116 # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
2117 	/*
2118 	 * If the file could not be found in a normal way, try applying
2119 	 * 'includeexpr' (unless done already).
2120 	 */
2121 	if (file_name == NULL
2122 		&& !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
2123 	{
2124 	    tofree = eval_includeexpr(ptr, len);
2125 	    if (tofree != NULL)
2126 	    {
2127 		ptr = tofree;
2128 		len = (int)STRLEN(ptr);
2129 		file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
2130 							     TRUE, rel_fname);
2131 	    }
2132 	}
2133 # endif
2134 	if (file_name == NULL && (options & FNAME_MESS))
2135 	{
2136 	    c = ptr[len];
2137 	    ptr[len] = NUL;
2138 	    semsg(_("E447: Can't find file \"%s\" in path"), ptr);
2139 	    ptr[len] = c;
2140 	}
2141 
2142 	// Repeat finding the file "count" times.  This matters when it
2143 	// appears several times in the path.
2144 	while (file_name != NULL && --count > 0)
2145 	{
2146 	    vim_free(file_name);
2147 	    file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
2148 	}
2149     }
2150     else
2151 	file_name = vim_strnsave(ptr, len);
2152 
2153 # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
2154     vim_free(tofree);
2155 # endif
2156 
2157     return file_name;
2158 }
2159 
2160 /*
2161  * Return the end of the directory name, on the first path
2162  * separator:
2163  * "/path/file", "/path/dir/", "/path//dir", "/file"
2164  *	 ^	       ^	     ^	      ^
2165  */
2166     static char_u *
2167 gettail_dir(char_u *fname)
2168 {
2169     char_u	*dir_end = fname;
2170     char_u	*next_dir_end = fname;
2171     int		look_for_sep = TRUE;
2172     char_u	*p;
2173 
2174     for (p = fname; *p != NUL; )
2175     {
2176 	if (vim_ispathsep(*p))
2177 	{
2178 	    if (look_for_sep)
2179 	    {
2180 		next_dir_end = p;
2181 		look_for_sep = FALSE;
2182 	    }
2183 	}
2184 	else
2185 	{
2186 	    if (!look_for_sep)
2187 		dir_end = next_dir_end;
2188 	    look_for_sep = TRUE;
2189 	}
2190 	MB_PTR_ADV(p);
2191     }
2192     return dir_end;
2193 }
2194 
2195 /*
2196  * return TRUE if 'c' is a path list separator.
2197  */
2198     int
2199 vim_ispathlistsep(int c)
2200 {
2201 # ifdef UNIX
2202     return (c == ':');
2203 # else
2204     return (c == ';');	// might not be right for every system...
2205 # endif
2206 }
2207 
2208 /*
2209  * Moves "*psep" back to the previous path separator in "path".
2210  * Returns FAIL is "*psep" ends up at the beginning of "path".
2211  */
2212     static int
2213 find_previous_pathsep(char_u *path, char_u **psep)
2214 {
2215     // skip the current separator
2216     if (*psep > path && vim_ispathsep(**psep))
2217 	--*psep;
2218 
2219     // find the previous separator
2220     while (*psep > path)
2221     {
2222 	if (vim_ispathsep(**psep))
2223 	    return OK;
2224 	MB_PTR_BACK(path, *psep);
2225     }
2226 
2227     return FAIL;
2228 }
2229 
2230 /*
2231  * Returns TRUE if "maybe_unique" is unique wrt other_paths in "gap".
2232  * "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]".
2233  */
2234     static int
2235 is_unique(char_u *maybe_unique, garray_T *gap, int i)
2236 {
2237     int	    j;
2238     int	    candidate_len;
2239     int	    other_path_len;
2240     char_u  **other_paths = (char_u **)gap->ga_data;
2241     char_u  *rival;
2242 
2243     for (j = 0; j < gap->ga_len; j++)
2244     {
2245 	if (j == i)
2246 	    continue;  // don't compare it with itself
2247 
2248 	candidate_len = (int)STRLEN(maybe_unique);
2249 	other_path_len = (int)STRLEN(other_paths[j]);
2250 	if (other_path_len < candidate_len)
2251 	    continue;  // it's different when it's shorter
2252 
2253 	rival = other_paths[j] + other_path_len - candidate_len;
2254 	if (fnamecmp(maybe_unique, rival) == 0
2255 		&& (rival == other_paths[j] || vim_ispathsep(*(rival - 1))))
2256 	    return FALSE;  // match
2257     }
2258 
2259     return TRUE;  // no match found
2260 }
2261 
2262 /*
2263  * Split the 'path' option into an array of strings in garray_T.  Relative
2264  * paths are expanded to their equivalent fullpath.  This includes the "."
2265  * (relative to current buffer directory) and empty path (relative to current
2266  * directory) notations.
2267  *
2268  * TODO: handle upward search (;) and path limiter (**N) notations by
2269  * expanding each into their equivalent path(s).
2270  */
2271     static void
2272 expand_path_option(char_u *curdir, garray_T *gap)
2273 {
2274     char_u	*path_option = *curbuf->b_p_path == NUL
2275 						  ? p_path : curbuf->b_p_path;
2276     char_u	*buf;
2277     char_u	*p;
2278     int		len;
2279 
2280     if ((buf = alloc((int)MAXPATHL)) == NULL)
2281 	return;
2282 
2283     while (*path_option != NUL)
2284     {
2285 	copy_option_part(&path_option, buf, MAXPATHL, " ,");
2286 
2287 	if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1])))
2288 	{
2289 	    // Relative to current buffer:
2290 	    // "/path/file" + "." -> "/path/"
2291 	    // "/path/file"  + "./subdir" -> "/path/subdir"
2292 	    if (curbuf->b_ffname == NULL)
2293 		continue;
2294 	    p = gettail(curbuf->b_ffname);
2295 	    len = (int)(p - curbuf->b_ffname);
2296 	    if (len + (int)STRLEN(buf) >= MAXPATHL)
2297 		continue;
2298 	    if (buf[1] == NUL)
2299 		buf[len] = NUL;
2300 	    else
2301 		STRMOVE(buf + len, buf + 2);
2302 	    mch_memmove(buf, curbuf->b_ffname, len);
2303 	    simplify_filename(buf);
2304 	}
2305 	else if (buf[0] == NUL)
2306 	    // relative to current directory
2307 	    STRCPY(buf, curdir);
2308 	else if (path_with_url(buf))
2309 	    // URL can't be used here
2310 	    continue;
2311 	else if (!mch_isFullName(buf))
2312 	{
2313 	    // Expand relative path to their full path equivalent
2314 	    len = (int)STRLEN(curdir);
2315 	    if (len + (int)STRLEN(buf) + 3 > MAXPATHL)
2316 		continue;
2317 	    STRMOVE(buf + len + 1, buf);
2318 	    STRCPY(buf, curdir);
2319 	    buf[len] = PATHSEP;
2320 	    simplify_filename(buf);
2321 	}
2322 
2323 	if (ga_grow(gap, 1) == FAIL)
2324 	    break;
2325 
2326 # if defined(MSWIN)
2327 	// Avoid the path ending in a backslash, it fails when a comma is
2328 	// appended.
2329 	len = (int)STRLEN(buf);
2330 	if (buf[len - 1] == '\\')
2331 	    buf[len - 1] = '/';
2332 # endif
2333 
2334 	p = vim_strsave(buf);
2335 	if (p == NULL)
2336 	    break;
2337 	((char_u **)gap->ga_data)[gap->ga_len++] = p;
2338     }
2339 
2340     vim_free(buf);
2341 }
2342 
2343 /*
2344  * Returns a pointer to the file or directory name in "fname" that matches the
2345  * longest path in "ga"p, or NULL if there is no match. For example:
2346  *
2347  *    path: /foo/bar/baz
2348  *   fname: /foo/bar/baz/quux.txt
2349  * returns:		 ^this
2350  */
2351     static char_u *
2352 get_path_cutoff(char_u *fname, garray_T *gap)
2353 {
2354     int	    i;
2355     int	    maxlen = 0;
2356     char_u  **path_part = (char_u **)gap->ga_data;
2357     char_u  *cutoff = NULL;
2358 
2359     for (i = 0; i < gap->ga_len; i++)
2360     {
2361 	int j = 0;
2362 
2363 	while ((fname[j] == path_part[i][j]
2364 # if defined(MSWIN)
2365 		|| (vim_ispathsep(fname[j]) && vim_ispathsep(path_part[i][j]))
2366 # endif
2367 			     ) && fname[j] != NUL && path_part[i][j] != NUL)
2368 	    j++;
2369 	if (j > maxlen)
2370 	{
2371 	    maxlen = j;
2372 	    cutoff = &fname[j];
2373 	}
2374     }
2375 
2376     // skip to the file or directory name
2377     if (cutoff != NULL)
2378 	while (vim_ispathsep(*cutoff))
2379 	    MB_PTR_ADV(cutoff);
2380 
2381     return cutoff;
2382 }
2383 
2384 /*
2385  * Sorts, removes duplicates and modifies all the fullpath names in "gap" so
2386  * that they are unique with respect to each other while conserving the part
2387  * that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len".
2388  */
2389     void
2390 uniquefy_paths(garray_T *gap, char_u *pattern)
2391 {
2392     int		i;
2393     int		len;
2394     char_u	**fnames = (char_u **)gap->ga_data;
2395     int		sort_again = FALSE;
2396     char_u	*pat;
2397     char_u      *file_pattern;
2398     char_u	*curdir;
2399     regmatch_T	regmatch;
2400     garray_T	path_ga;
2401     char_u	**in_curdir = NULL;
2402     char_u	*short_name;
2403 
2404     remove_duplicates(gap);
2405     ga_init2(&path_ga, (int)sizeof(char_u *), 1);
2406 
2407     /*
2408      * We need to prepend a '*' at the beginning of file_pattern so that the
2409      * regex matches anywhere in the path. FIXME: is this valid for all
2410      * possible patterns?
2411      */
2412     len = (int)STRLEN(pattern);
2413     file_pattern = alloc(len + 2);
2414     if (file_pattern == NULL)
2415 	return;
2416     file_pattern[0] = '*';
2417     file_pattern[1] = NUL;
2418     STRCAT(file_pattern, pattern);
2419     pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE);
2420     vim_free(file_pattern);
2421     if (pat == NULL)
2422 	return;
2423 
2424     regmatch.rm_ic = TRUE;		// always ignore case
2425     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
2426     vim_free(pat);
2427     if (regmatch.regprog == NULL)
2428 	return;
2429 
2430     if ((curdir = alloc((int)(MAXPATHL))) == NULL)
2431 	goto theend;
2432     mch_dirname(curdir, MAXPATHL);
2433     expand_path_option(curdir, &path_ga);
2434 
2435     in_curdir = (char_u **)alloc_clear(gap->ga_len * sizeof(char_u *));
2436     if (in_curdir == NULL)
2437 	goto theend;
2438 
2439     for (i = 0; i < gap->ga_len && !got_int; i++)
2440     {
2441 	char_u	    *path = fnames[i];
2442 	int	    is_in_curdir;
2443 	char_u	    *dir_end = gettail_dir(path);
2444 	char_u	    *pathsep_p;
2445 	char_u	    *path_cutoff;
2446 
2447 	len = (int)STRLEN(path);
2448 	is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
2449 					     && curdir[dir_end - path] == NUL;
2450 	if (is_in_curdir)
2451 	    in_curdir[i] = vim_strsave(path);
2452 
2453 	// Shorten the filename while maintaining its uniqueness
2454 	path_cutoff = get_path_cutoff(path, &path_ga);
2455 
2456 	// Don't assume all files can be reached without path when search
2457 	// pattern starts with star star slash, so only remove path_cutoff
2458 	// when possible.
2459 	if (pattern[0] == '*' && pattern[1] == '*'
2460 		&& vim_ispathsep_nocolon(pattern[2])
2461 		&& path_cutoff != NULL
2462 		&& vim_regexec(&regmatch, path_cutoff, (colnr_T)0)
2463 		&& is_unique(path_cutoff, gap, i))
2464 	{
2465 	    sort_again = TRUE;
2466 	    mch_memmove(path, path_cutoff, STRLEN(path_cutoff) + 1);
2467 	}
2468 	else
2469 	{
2470 	    // Here all files can be reached without path, so get shortest
2471 	    // unique path.  We start at the end of the path.
2472 	    pathsep_p = path + len - 1;
2473 
2474 	    while (find_previous_pathsep(path, &pathsep_p))
2475 		if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
2476 			&& is_unique(pathsep_p + 1, gap, i)
2477 			&& path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
2478 		{
2479 		    sort_again = TRUE;
2480 		    mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
2481 		    break;
2482 		}
2483 	}
2484 
2485 	if (mch_isFullName(path))
2486 	{
2487 	    /*
2488 	     * Last resort: shorten relative to curdir if possible.
2489 	     * 'possible' means:
2490 	     * 1. It is under the current directory.
2491 	     * 2. The result is actually shorter than the original.
2492 	     *
2493 	     *	    Before		  curdir	After
2494 	     *	    /foo/bar/file.txt	  /foo/bar	./file.txt
2495 	     *	    c:\foo\bar\file.txt   c:\foo\bar	.\file.txt
2496 	     *	    /file.txt		  /		/file.txt
2497 	     *	    c:\file.txt		  c:\		.\file.txt
2498 	     */
2499 	    short_name = shorten_fname(path, curdir);
2500 	    if (short_name != NULL && short_name > path + 1
2501 # if defined(MSWIN)
2502 		    // On windows,
2503 		    //	    shorten_fname("c:\a\a.txt", "c:\a\b")
2504 		    // returns "\a\a.txt", which is not really the short
2505 		    // name, hence:
2506 		    && !vim_ispathsep(*short_name)
2507 # endif
2508 		)
2509 	    {
2510 		STRCPY(path, ".");
2511 		add_pathsep(path);
2512 		STRMOVE(path + STRLEN(path), short_name);
2513 	    }
2514 	}
2515 	ui_breakcheck();
2516     }
2517 
2518     // Shorten filenames in /in/current/directory/{filename}
2519     for (i = 0; i < gap->ga_len && !got_int; i++)
2520     {
2521 	char_u *rel_path;
2522 	char_u *path = in_curdir[i];
2523 
2524 	if (path == NULL)
2525 	    continue;
2526 
2527 	// If the {filename} is not unique, change it to ./{filename}.
2528 	// Else reduce it to {filename}
2529 	short_name = shorten_fname(path, curdir);
2530 	if (short_name == NULL)
2531 	    short_name = path;
2532 	if (is_unique(short_name, gap, i))
2533 	{
2534 	    STRCPY(fnames[i], short_name);
2535 	    continue;
2536 	}
2537 
2538 	rel_path = alloc((int)(STRLEN(short_name) + STRLEN(PATHSEPSTR) + 2));
2539 	if (rel_path == NULL)
2540 	    goto theend;
2541 	STRCPY(rel_path, ".");
2542 	add_pathsep(rel_path);
2543 	STRCAT(rel_path, short_name);
2544 
2545 	vim_free(fnames[i]);
2546 	fnames[i] = rel_path;
2547 	sort_again = TRUE;
2548 	ui_breakcheck();
2549     }
2550 
2551 theend:
2552     vim_free(curdir);
2553     if (in_curdir != NULL)
2554     {
2555 	for (i = 0; i < gap->ga_len; i++)
2556 	    vim_free(in_curdir[i]);
2557 	vim_free(in_curdir);
2558     }
2559     ga_clear_strings(&path_ga);
2560     vim_regfree(regmatch.regprog);
2561 
2562     if (sort_again)
2563 	remove_duplicates(gap);
2564 }
2565 
2566 /*
2567  * Calls globpath() with 'path' values for the given pattern and stores the
2568  * result in "gap".
2569  * Returns the total number of matches.
2570  */
2571     int
2572 expand_in_path(
2573     garray_T	*gap,
2574     char_u	*pattern,
2575     int		flags)		// EW_* flags
2576 {
2577     char_u	*curdir;
2578     garray_T	path_ga;
2579     char_u	*paths = NULL;
2580     int		glob_flags = 0;
2581 
2582     if ((curdir = alloc((unsigned)MAXPATHL)) == NULL)
2583 	return 0;
2584     mch_dirname(curdir, MAXPATHL);
2585 
2586     ga_init2(&path_ga, (int)sizeof(char_u *), 1);
2587     expand_path_option(curdir, &path_ga);
2588     vim_free(curdir);
2589     if (path_ga.ga_len == 0)
2590 	return 0;
2591 
2592     paths = ga_concat_strings(&path_ga, ",");
2593     ga_clear_strings(&path_ga);
2594     if (paths == NULL)
2595 	return 0;
2596 
2597     if (flags & EW_ICASE)
2598 	glob_flags |= WILD_ICASE;
2599     if (flags & EW_ADDSLASH)
2600 	glob_flags |= WILD_ADD_SLASH;
2601     globpath(paths, pattern, gap, glob_flags);
2602     vim_free(paths);
2603 
2604     return gap->ga_len;
2605 }
2606 
2607 #endif // FEAT_SEARCHPATH
2608