summaryrefslogtreecommitdiff
path: root/data/vim/patches/8.1.0914
diff options
context:
space:
mode:
Diffstat (limited to 'data/vim/patches/8.1.0914')
-rw-r--r--data/vim/patches/8.1.09146010
1 files changed, 0 insertions, 6010 deletions
diff --git a/data/vim/patches/8.1.0914 b/data/vim/patches/8.1.0914
deleted file mode 100644
index 8c2e83263..000000000
--- a/data/vim/patches/8.1.0914
+++ /dev/null
@@ -1,6010 +0,0 @@
-To: vim_dev@googlegroups.com
-Subject: Patch 8.1.0914
-Fcc: outbox
-From: Bram Moolenaar <Bram@moolenaar.net>
-Mime-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-------------
-
-Patch 8.1.0914
-Problem: Code related to findfile() is spread out.
-Solution: Put findfile() related code into a new source file. (Yegappan
- Lakshmanan, closes #3934)
-Files: Filelist, src/Make_bc5.mak, src/Make_cyg_ming.mak,
- src/Make_dice.mak, src/Make_ivc.mak, src/Make_manx.mak,
- src/Make_morph.mak, src/Make_mvc.mak, src/Make_sas.mak,
- src/Make_vms.mms, src/Makefile, src/README.txt, src/findfile.c,
- src/misc1.c, src/misc2.c, src/proto.h, src/proto/findfile.pro,
- src/proto/misc1.pro, src/proto/misc2.pro, src/proto/window.pro,
- src/window.c
-
-
-*** ../vim-8.1.0913/Filelist 2019-02-03 23:45:09.282345807 +0100
---- Filelist 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 41,46 ****
---- 41,47 ----
- src/farsi.h \
- src/feature.h \
- src/fileio.c \
-+ src/findfile.c \
- src/fold.c \
- src/getchar.c \
- src/globals.h \
-***************
-*** 170,175 ****
---- 171,177 ----
- src/proto/ex_getln.pro \
- src/proto/farsi.pro \
- src/proto/fileio.pro \
-+ src/proto/findfile.pro \
- src/proto/fold.pro \
- src/proto/getchar.pro \
- src/proto/gui.pro \
-*** ../vim-8.1.0913/src/Make_bc5.mak 2019-01-31 13:47:51.118632672 +0100
---- src/Make_bc5.mak 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 544,549 ****
---- 544,550 ----
- $(OBJDIR)\ex_getln.obj \
- $(OBJDIR)\farsi.obj \
- $(OBJDIR)\fileio.obj \
-+ $(OBJDIR)\findfile.obj \
- $(OBJDIR)\fold.obj \
- $(OBJDIR)\getchar.obj \
- $(OBJDIR)\hardcopy.obj \
-*** ../vim-8.1.0913/src/Make_cyg_ming.mak 2019-01-31 14:43:15.563570608 +0100
---- src/Make_cyg_ming.mak 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 716,721 ****
---- 716,722 ----
- $(OUTDIR)/ex_getln.o \
- $(OUTDIR)/farsi.o \
- $(OUTDIR)/fileio.o \
-+ $(OUTDIR)/findfile.o \
- $(OUTDIR)/fold.o \
- $(OUTDIR)/getchar.o \
- $(OUTDIR)/hardcopy.o \
-*** ../vim-8.1.0913/src/Make_dice.mak 2019-01-31 13:47:51.118632672 +0100
---- src/Make_dice.mak 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 46,51 ****
---- 46,52 ----
- ex_getln.c \
- farsi.c \
- fileio.c \
-+ findfile.c \
- fold.c \
- getchar.c \
- hardcopy.c \
-***************
-*** 105,110 ****
---- 106,112 ----
- o/ex_getln.o \
- o/farsi.o \
- o/fileio.o \
-+ o/findfile.o \
- o/fold.o \
- o/getchar.o \
- o/hardcopy.o \
-***************
-*** 203,208 ****
---- 205,212 ----
-
- o/fileio.o: fileio.c $(SYMS)
-
-+ o/findfile.o: findfile.c $(SYMS)
-+
- o/fold.o: fold.c $(SYMS)
-
- o/getchar.o: getchar.c $(SYMS)
-*** ../vim-8.1.0913/src/Make_ivc.mak 2019-01-31 13:47:51.118632672 +0100
---- src/Make_ivc.mak 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 230,235 ****
---- 230,236 ----
- "$(INTDIR)/ex_getln.obj" \
- "$(INTDIR)/farsi.obj" \
- "$(INTDIR)/fileio.obj" \
-+ "$(INTDIR)/findfile.obj" \
- "$(INTDIR)/fold.obj" \
- "$(INTDIR)/getchar.obj" \
- "$(INTDIR)/hardcopy.obj" \
-***************
-*** 419,424 ****
---- 420,429 ----
- SOURCE=.\fileio.c
- # End Source File
- # Begin Source File
-+ #
-+ SOURCE=.\findfile.c
-+ # End Source File
-+ # Begin Source File
-
- SOURCE=.\fold.c
- # End Source File
-*** ../vim-8.1.0913/src/Make_manx.mak 2019-01-31 13:47:51.118632672 +0100
---- src/Make_manx.mak 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 56,61 ****
---- 56,62 ----
- ex_getln.c \
- farsi.c \
- fileio.c \
-+ findfile.c \
- fold.c \
- getchar.c \
- hardcopy.c \
-***************
-*** 117,122 ****
---- 118,124 ----
- obj/ex_getln.o \
- obj/farsi.o \
- obj/fileio.o \
-+ obj/findfile.o \
- obj/fold.o \
- obj/getchar.o \
- obj/hardcopy.o \
-***************
-*** 176,181 ****
---- 178,184 ----
- proto/ex_getln.pro \
- proto/farsi.pro \
- proto/fileio.pro \
-+ proto/findfile.pro \
- proto/fold.pro \
- proto/getchar.pro \
- proto/hardcopy.pro \
-***************
-*** 320,325 ****
---- 323,331 ----
- obj/fileio.o: fileio.c
- $(CCSYM) $@ fileio.c
-
-+ obj/findfile.o: findfile.c
-+ $(CCSYM) $@ findfile.c
-+
- obj/fold.o: fold.c
- $(CCSYM) $@ fold.c
-
-*** ../vim-8.1.0913/src/Make_morph.mak 2019-01-31 13:47:51.118632672 +0100
---- src/Make_morph.mak 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 44,49 ****
---- 44,50 ----
- ex_getln.c \
- farsi.c \
- fileio.c \
-+ findfile.c \
- fold.c \
- getchar.c \
- hardcopy.c \
-*** ../vim-8.1.0913/src/Make_mvc.mak 2019-01-31 13:47:51.118632672 +0100
---- src/Make_mvc.mak 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 721,726 ****
---- 721,727 ----
- $(OUTDIR)\ex_getln.obj \
- $(OUTDIR)\farsi.obj \
- $(OUTDIR)\fileio.obj \
-+ $(OUTDIR)\findfile.obj \
- $(OUTDIR)\fold.obj \
- $(OUTDIR)\getchar.obj \
- $(OUTDIR)\hardcopy.obj \
-***************
-*** 1407,1412 ****
---- 1408,1415 ----
-
- $(OUTDIR)/fileio.obj: $(OUTDIR) fileio.c $(INCL)
-
-+ $(OUTDIR)/findfile.obj: $(OUTDIR) findfile.c $(INCL)
-+
- $(OUTDIR)/fold.obj: $(OUTDIR) fold.c $(INCL)
-
- $(OUTDIR)/getchar.obj: $(OUTDIR) getchar.c $(INCL)
-***************
-*** 1645,1650 ****
---- 1648,1654 ----
- proto/ex_getln.pro \
- proto/farsi.pro \
- proto/fileio.pro \
-+ proto/findfile.pro \
- proto/getchar.pro \
- proto/hardcopy.pro \
- proto/hashtab.pro \
-*** ../vim-8.1.0913/src/Make_sas.mak 2019-01-31 13:47:51.118632672 +0100
---- src/Make_sas.mak 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 109,114 ****
---- 109,115 ----
- ex_getln.c \
- farsi.c \
- fileio.c \
-+ findfile.c \
- fold.c \
- getchar.c \
- hardcopy.c \
-***************
-*** 169,174 ****
---- 170,176 ----
- ex_getln.o \
- farsi.o \
- fileio.o \
-+ findfile.o \
- fold.o \
- getchar.o \
- hardcopy.o \
-***************
-*** 229,234 ****
---- 231,237 ----
- proto/ex_getln.pro \
- proto/farsi.pro \
- proto/fileio.pro \
-+ proto/findfile.pro \
- proto/fold.pro \
- proto/getchar.pro \
- proto/hardcopy.pro \
-***************
-*** 363,368 ****
---- 366,373 ----
- proto/farsi.pro: farsi.c
- fileio.o: fileio.c
- proto/fileio.pro: fileio.c
-+ findfile.o: findfile.c
-+ proto/findfile.pro: findfile.c
- fold.o: fold.c
- proto/fold.pro: fold.c
- getchar.o: getchar.c
-*** ../vim-8.1.0913/src/Make_vms.mms 2019-01-31 13:47:51.118632672 +0100
---- src/Make_vms.mms 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 312,334 ****
- ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \
- $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB)
-
-! SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c charset.c crypt.c crypt_zip.c dict.c diff.c digraph.c edit.c eval.c \
-! evalfunc.c ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c if_cscope.c if_xcmdsrv.c farsi.c fileio.c fold.c \
-! getchar.c hardcopy.c hashtab.c indent.c json.c list.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \
-! misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c sign.c \
-! spell.c spellfile.c syntax.c tag.c term.c termlib.c textprop.c ui.c undo.c userfunc.c version.c screen.c \
-! window.c os_unix.c os_vms.c pathdef.c \
- $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \
- $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC)
-
-! OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj charset.obj crypt.obj crypt_zip.obj dict.obj diff.obj digraph.obj \
-! edit.obj eval.obj evalfunc.obj ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj if_cscope.obj \
-! if_xcmdsrv.obj farsi.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj indent.obj json.obj list.obj main.obj mark.obj \
-! menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \
-! move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj quickfix.obj \
-! regexp.obj search.obj sha256.obj sign.obj spell.obj spellfile.obj syntax.obj tag.obj term.obj termlib.obj textprop.obj \
-! ui.obj undo.obj userfunc.obj screen.obj version.obj window.obj os_unix.obj \
-! os_vms.obj pathdef.obj if_mzsch.obj\
- $(GUI_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(TCL_OBJ) \
- $(RUBY_OBJ) $(HANGULIN_OBJ) $(MZSCH_OBJ) $(XDIFF_OBJ)
-
---- 312,342 ----
- ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \
- $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB)
-
-! SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c charset.c \
-! crypt.c crypt_zip.c dict.c diff.c digraph.c edit.c eval.c evalfunc.c \
-! ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c if_cscope.c \
-! if_xcmdsrv.c farsi.c fileio.c findfile.c fold.c getchar.c hardcopy.c \
-! hashtab.c indent.c json.c list.c main.c mark.c menu.c mbyte.c \
-! memfile.c memline.c message.c misc1.c misc2.c move.c normal.c ops.c \
-! option.c popupmnu.c quickfix.c regexp.c search.c sha256.c sign.c \
-! spell.c spellfile.c syntax.c tag.c term.c termlib.c textprop.c ui.c \
-! undo.c userfunc.c version.c screen.c window.c os_unix.c os_vms.c \
-! pathdef.c
- $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \
- $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC)
-
-! OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj \
-! charset.obj crypt.obj crypt_zip.obj dict.obj diff.obj digraph.obj \
-! edit.obj eval.obj evalfunc.obj ex_cmds.obj ex_cmds2.obj ex_docmd.obj \
-! ex_eval.obj ex_getln.obj if_cscope.obj if_xcmdsrv.obj farsi.obj \
-! fileio.obj findfile.obj fold.obj getchar.obj hardcopy.obj hashtab.obj \
-! indent.obj json.obj list.obj main.obj mark.obj menu.obj memfile.obj \
-! memline.obj message.obj misc1.obj misc2.obj move.obj mbyte.obj \
-! normal.obj ops.obj option.obj popupmnu.obj quickfix.obj regexp.obj \
-! search.obj sha256.obj sign.obj spell.obj spellfile.obj syntax.obj \
-! tag.obj term.obj termlib.obj textprop.obj ui.obj undo.obj \
-! userfunc.obj screen.obj version.obj window.obj os_unix.obj os_vms.obj \
-! pathdef.obj if_mzsch.obj \
- $(GUI_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(TCL_OBJ) \
- $(RUBY_OBJ) $(HANGULIN_OBJ) $(MZSCH_OBJ) $(XDIFF_OBJ)
-
-***************
-*** 568,573 ****
---- 576,585 ----
- ascii.h keymap.h term.h macros.h structs.h regexp.h \
- gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
- globals.h farsi.h arabic.h
-+ findfile.obj : findfile.c vim.h [.auto]config.h feature.h os_unix.h \
-+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
-+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
-+ globals.h farsi.h arabic.h
- fold.obj : fold.c vim.h [.auto]config.h feature.h os_unix.h \
- ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
-*** ../vim-8.1.0913/src/Makefile 2019-02-01 20:42:18.718884011 +0100
---- src/Makefile 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 1592,1597 ****
---- 1592,1598 ----
- ex_getln.c \
- farsi.c \
- fileio.c \
-+ findfile.c \
- fold.c \
- getchar.c \
- hardcopy.c \
-***************
-*** 1705,1710 ****
---- 1706,1712 ----
- objects/ex_getln.o \
- objects/farsi.o \
- objects/fileio.o \
-+ objects/findfile.o \
- objects/fold.o \
- objects/getchar.o \
- objects/hardcopy.o \
-***************
-*** 1831,1836 ****
---- 1833,1839 ----
- ex_getln.pro \
- farsi.pro \
- fileio.pro \
-+ findfile.pro \
- fold.pro \
- getchar.pro \
- hardcopy.pro \
-***************
-*** 2999,3004 ****
---- 3002,3010 ----
- objects/fileio.o: fileio.c
- $(CCC) -o $@ fileio.c
-
-+ objects/findfile.o: findfile.c
-+ $(CCC) -o $@ findfile.c
-+
- objects/fold.o: fold.c
- $(CCC) -o $@ fold.c
-
-***************
-*** 3471,3476 ****
---- 3477,3487 ----
- auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
- proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
- proto.h globals.h farsi.h arabic.h
-+ objects/findfile.o: findfile.c vim.h protodef.h auto/config.h feature.h \
-+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
-+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
-+ proto.h globals.h farsi.h arabic.h libvterm/include/vterm.h \
-+ libvterm/include/vterm_keycodes.h
- objects/fold.o: fold.c vim.h protodef.h auto/config.h feature.h os_unix.h \
- auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
- proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
-*** ../vim-8.1.0913/src/README.txt 2019-01-26 16:20:44.260683581 +0100
---- src/README.txt 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 22,29 ****
---- 22,31 ----
- diff.c diff mode (vimdiff)
- eval.c expression evaluation
- fileio.c reading and writing files
-+ findfile.c search for files in 'path'
- fold.c folding
- getchar.c getting characters and key mapping
-+ indent.c C and Lisp indentation
- mark.c marks
- mbyte.c multi-byte character handling
- memfile.c storing lines for buffers in a swapfile
-*** ../vim-8.1.0913/src/findfile.c 2019-02-13 22:43:46.429534874 +0100
---- src/findfile.c 2019-02-13 22:32:25.770956617 +0100
-***************
-*** 0 ****
---- 1,2607 ----
-+ /* vi:set ts=8 sts=4 sw=4 noet:
-+ *
-+ * VIM - Vi IMproved by Bram Moolenaar
-+ *
-+ * Do ":help uganda" in Vim to read copying and usage conditions.
-+ * Do ":help credits" in Vim to see a list of people who contributed.
-+ * See README.txt for an overview of the Vim source code.
-+ */
-+
-+ /*
-+ * findfile.c: Search for files in directories listed in 'path'
-+ */
-+
-+ #include "vim.h"
-+
-+ /*
-+ * File searching functions for 'path', 'tags' and 'cdpath' options.
-+ * External visible functions:
-+ * vim_findfile_init() creates/initialises the search context
-+ * vim_findfile_free_visited() free list of visited files/dirs of search
-+ * context
-+ * vim_findfile() find a file in the search context
-+ * vim_findfile_cleanup() cleanup/free search context created by
-+ * vim_findfile_init()
-+ *
-+ * All static functions and variables start with 'ff_'
-+ *
-+ * In general it works like this:
-+ * First you create yourself a search context by calling vim_findfile_init().
-+ * It is possible to give a search context from a previous call to
-+ * vim_findfile_init(), so it can be reused. After this you call vim_findfile()
-+ * until you are satisfied with the result or it returns NULL. On every call it
-+ * returns the next file which matches the conditions given to
-+ * vim_findfile_init(). If it doesn't find a next file it returns NULL.
-+ *
-+ * It is possible to call vim_findfile_init() again to reinitialise your search
-+ * with some new parameters. Don't forget to pass your old search context to
-+ * it, so it can reuse it and especially reuse the list of already visited
-+ * directories. If you want to delete the list of already visited directories
-+ * simply call vim_findfile_free_visited().
-+ *
-+ * When you are done call vim_findfile_cleanup() to free the search context.
-+ *
-+ * The function vim_findfile_init() has a long comment, which describes the
-+ * needed parameters.
-+ *
-+ *
-+ *
-+ * ATTENTION:
-+ * ==========
-+ * Also we use an allocated search context here, this functions are NOT
-+ * thread-safe!!!!!
-+ *
-+ * To minimize parameter passing (or because I'm to lazy), only the
-+ * external visible functions get a search context as a parameter. This is
-+ * then assigned to a static global, which is used throughout the local
-+ * functions.
-+ */
-+
-+ /*
-+ * type for the directory search stack
-+ */
-+ typedef struct ff_stack
-+ {
-+ struct ff_stack *ffs_prev;
-+
-+ // the fix part (no wildcards) and the part containing the wildcards
-+ // of the search path
-+ char_u *ffs_fix_path;
-+ #ifdef FEAT_PATH_EXTRA
-+ char_u *ffs_wc_path;
-+ #endif
-+
-+ // files/dirs found in the above directory, matched by the first wildcard
-+ // of wc_part
-+ char_u **ffs_filearray;
-+ int ffs_filearray_size;
-+ char_u ffs_filearray_cur; // needed for partly handled dirs
-+
-+ // to store status of partly handled directories
-+ // 0: we work on this directory for the first time
-+ // 1: this directory was partly searched in an earlier step
-+ int ffs_stage;
-+
-+ // How deep are we in the directory tree?
-+ // Counts backward from value of level parameter to vim_findfile_init
-+ int ffs_level;
-+
-+ // Did we already expand '**' to an empty string?
-+ int ffs_star_star_empty;
-+ } ff_stack_T;
-+
-+ /*
-+ * type for already visited directories or files.
-+ */
-+ typedef struct ff_visited
-+ {
-+ struct ff_visited *ffv_next;
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ // Visited directories are different if the wildcard string are
-+ // different. So we have to save it.
-+ char_u *ffv_wc_path;
-+ #endif
-+ // for unix use inode etc for comparison (needed because of links), else
-+ // use filename.
-+ #ifdef UNIX
-+ int ffv_dev_valid; // ffv_dev and ffv_ino were set
-+ dev_t ffv_dev; // device number
-+ ino_t ffv_ino; // inode number
-+ #endif
-+ // The memory for this struct is allocated according to the length of
-+ // ffv_fname.
-+ char_u ffv_fname[1]; // actually longer
-+ } ff_visited_T;
-+
-+ /*
-+ * We might have to manage several visited lists during a search.
-+ * This is especially needed for the tags option. If tags is set to:
-+ * "./++/tags,./++/TAGS,++/tags" (replace + with *)
-+ * So we have to do 3 searches:
-+ * 1) search from the current files directory downward for the file "tags"
-+ * 2) search from the current files directory downward for the file "TAGS"
-+ * 3) search from Vims current directory downwards for the file "tags"
-+ * As you can see, the first and the third search are for the same file, so for
-+ * the third search we can use the visited list of the first search. For the
-+ * second search we must start from a empty visited list.
-+ * The struct ff_visited_list_hdr is used to manage a linked list of already
-+ * visited lists.
-+ */
-+ typedef struct ff_visited_list_hdr
-+ {
-+ struct ff_visited_list_hdr *ffvl_next;
-+
-+ // the filename the attached visited list is for
-+ char_u *ffvl_filename;
-+
-+ ff_visited_T *ffvl_visited_list;
-+
-+ } ff_visited_list_hdr_T;
-+
-+
-+ /*
-+ * '**' can be expanded to several directory levels.
-+ * Set the default maximum depth.
-+ */
-+ #define FF_MAX_STAR_STAR_EXPAND ((char_u)30)
-+
-+ /*
-+ * The search context:
-+ * ffsc_stack_ptr: the stack for the dirs to search
-+ * ffsc_visited_list: the currently active visited list
-+ * ffsc_dir_visited_list: the currently active visited list for search dirs
-+ * ffsc_visited_lists_list: the list of all visited lists
-+ * ffsc_dir_visited_lists_list: the list of all visited lists for search dirs
-+ * ffsc_file_to_search: the file to search for
-+ * ffsc_start_dir: the starting directory, if search path was relative
-+ * ffsc_fix_path: the fix part of the given path (without wildcards)
-+ * Needed for upward search.
-+ * ffsc_wc_path: the part of the given path containing wildcards
-+ * ffsc_level: how many levels of dirs to search downwards
-+ * ffsc_stopdirs_v: array of stop directories for upward search
-+ * ffsc_find_what: FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE
-+ * ffsc_tagfile: searching for tags file, don't use 'suffixesadd'
-+ */
-+ typedef struct ff_search_ctx_T
-+ {
-+ ff_stack_T *ffsc_stack_ptr;
-+ ff_visited_list_hdr_T *ffsc_visited_list;
-+ ff_visited_list_hdr_T *ffsc_dir_visited_list;
-+ ff_visited_list_hdr_T *ffsc_visited_lists_list;
-+ ff_visited_list_hdr_T *ffsc_dir_visited_lists_list;
-+ char_u *ffsc_file_to_search;
-+ char_u *ffsc_start_dir;
-+ char_u *ffsc_fix_path;
-+ #ifdef FEAT_PATH_EXTRA
-+ char_u *ffsc_wc_path;
-+ int ffsc_level;
-+ char_u **ffsc_stopdirs_v;
-+ #endif
-+ int ffsc_find_what;
-+ int ffsc_tagfile;
-+ } ff_search_ctx_T;
-+
-+ // locally needed functions
-+ #ifdef FEAT_PATH_EXTRA
-+ static int ff_check_visited(ff_visited_T **, char_u *, char_u *);
-+ #else
-+ static int ff_check_visited(ff_visited_T **, char_u *);
-+ #endif
-+ static void vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp);
-+ static void ff_free_visited_list(ff_visited_T *vl);
-+ static ff_visited_list_hdr_T* ff_get_visited_list(char_u *, ff_visited_list_hdr_T **list_headp);
-+
-+ static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr);
-+ static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx);
-+ static void ff_clear(ff_search_ctx_T *search_ctx);
-+ static void ff_free_stack_element(ff_stack_T *stack_ptr);
-+ #ifdef FEAT_PATH_EXTRA
-+ static ff_stack_T *ff_create_stack_element(char_u *, char_u *, int, int);
-+ #else
-+ static ff_stack_T *ff_create_stack_element(char_u *, int, int);
-+ #endif
-+ #ifdef FEAT_PATH_EXTRA
-+ static int ff_path_in_stoplist(char_u *, int, char_u **);
-+ #endif
-+
-+ static char_u e_pathtoolong[] = N_("E854: path too long for completion");
-+
-+ static char_u *ff_expand_buffer = NULL; // used for expanding filenames
-+
-+ #if 0
-+ /*
-+ * if someone likes findfirst/findnext, here are the functions
-+ * NOT TESTED!!
-+ */
-+
-+ static void *ff_fn_search_context = NULL;
-+
-+ char_u *
-+ vim_findfirst(char_u *path, char_u *filename, int level)
-+ {
-+ ff_fn_search_context =
-+ vim_findfile_init(path, filename, NULL, level, TRUE, FALSE,
-+ ff_fn_search_context, rel_fname);
-+ if (NULL == ff_fn_search_context)
-+ return NULL;
-+ else
-+ return vim_findnext()
-+ }
-+
-+ char_u *
-+ vim_findnext(void)
-+ {
-+ char_u *ret = vim_findfile(ff_fn_search_context);
-+
-+ if (NULL == ret)
-+ {
-+ vim_findfile_cleanup(ff_fn_search_context);
-+ ff_fn_search_context = NULL;
-+ }
-+ return ret;
-+ }
-+ #endif
-+
-+ /*
-+ * Initialization routine for vim_findfile().
-+ *
-+ * Returns the newly allocated search context or NULL if an error occurred.
-+ *
-+ * Don't forget to clean up by calling vim_findfile_cleanup() if you are done
-+ * with the search context.
-+ *
-+ * Find the file 'filename' in the directory 'path'.
-+ * The parameter 'path' may contain wildcards. If so only search 'level'
-+ * directories deep. The parameter 'level' is the absolute maximum and is
-+ * not related to restricts given to the '**' wildcard. If 'level' is 100
-+ * and you use '**200' vim_findfile() will stop after 100 levels.
-+ *
-+ * 'filename' cannot contain wildcards! It is used as-is, no backslashes to
-+ * escape special characters.
-+ *
-+ * If 'stopdirs' is not NULL and nothing is found downward, the search is
-+ * restarted on the next higher directory level. This is repeated until the
-+ * start-directory of a search is contained in 'stopdirs'. 'stopdirs' has the
-+ * format ";*<dirname>*\(;<dirname>\)*;\=$".
-+ *
-+ * If the 'path' is relative, the starting dir for the search is either VIM's
-+ * current dir or if the path starts with "./" the current files dir.
-+ * If the 'path' is absolute, the starting dir is that part of the path before
-+ * the first wildcard.
-+ *
-+ * Upward search is only done on the starting dir.
-+ *
-+ * If 'free_visited' is TRUE the list of already visited files/directories is
-+ * cleared. Set this to FALSE if you just want to search from another
-+ * directory, but want to be sure that no directory from a previous search is
-+ * searched again. This is useful if you search for a file at different places.
-+ * The list of visited files/dirs can also be cleared with the function
-+ * vim_findfile_free_visited().
-+ *
-+ * Set the parameter 'find_what' to FINDFILE_DIR if you want to search for
-+ * directories only, FINDFILE_FILE for files only, FINDFILE_BOTH for both.
-+ *
-+ * A search context returned by a previous call to vim_findfile_init() can be
-+ * passed in the parameter "search_ctx_arg". This context is reused and
-+ * reinitialized with the new parameters. The list of already visited
-+ * directories from this context is only deleted if the parameter
-+ * "free_visited" is true. Be aware that the passed "search_ctx_arg" is freed
-+ * if the reinitialization fails.
-+ *
-+ * If you don't have a search context from a previous call "search_ctx_arg"
-+ * must be NULL.
-+ *
-+ * This function silently ignores a few errors, vim_findfile() will have
-+ * limited functionality then.
-+ */
-+ void *
-+ vim_findfile_init(
-+ char_u *path,
-+ char_u *filename,
-+ char_u *stopdirs UNUSED,
-+ int level,
-+ int free_visited,
-+ int find_what,
-+ void *search_ctx_arg,
-+ int tagfile, // expanding names of tags files
-+ char_u *rel_fname) // file name to use for "."
-+ {
-+ #ifdef FEAT_PATH_EXTRA
-+ char_u *wc_part;
-+ #endif
-+ ff_stack_T *sptr;
-+ ff_search_ctx_T *search_ctx;
-+
-+ // If a search context is given by the caller, reuse it, else allocate a
-+ // new one.
-+ if (search_ctx_arg != NULL)
-+ search_ctx = search_ctx_arg;
-+ else
-+ {
-+ search_ctx = (ff_search_ctx_T*)alloc((unsigned)sizeof(ff_search_ctx_T));
-+ if (search_ctx == NULL)
-+ goto error_return;
-+ vim_memset(search_ctx, 0, sizeof(ff_search_ctx_T));
-+ }
-+ search_ctx->ffsc_find_what = find_what;
-+ search_ctx->ffsc_tagfile = tagfile;
-+
-+ // clear the search context, but NOT the visited lists
-+ ff_clear(search_ctx);
-+
-+ // clear visited list if wanted
-+ if (free_visited == TRUE)
-+ vim_findfile_free_visited(search_ctx);
-+ else
-+ {
-+ // Reuse old visited lists. Get the visited list for the given
-+ // filename. If no list for the current filename exists, creates a new
-+ // one.
-+ search_ctx->ffsc_visited_list = ff_get_visited_list(filename,
-+ &search_ctx->ffsc_visited_lists_list);
-+ if (search_ctx->ffsc_visited_list == NULL)
-+ goto error_return;
-+ search_ctx->ffsc_dir_visited_list = ff_get_visited_list(filename,
-+ &search_ctx->ffsc_dir_visited_lists_list);
-+ if (search_ctx->ffsc_dir_visited_list == NULL)
-+ goto error_return;
-+ }
-+
-+ if (ff_expand_buffer == NULL)
-+ {
-+ ff_expand_buffer = (char_u*)alloc(MAXPATHL);
-+ if (ff_expand_buffer == NULL)
-+ goto error_return;
-+ }
-+
-+ // Store information on starting dir now if path is relative.
-+ // If path is absolute, we do that later.
-+ if (path[0] == '.'
-+ && (vim_ispathsep(path[1]) || path[1] == NUL)
-+ && (!tagfile || vim_strchr(p_cpo, CPO_DOTTAG) == NULL)
-+ && rel_fname != NULL)
-+ {
-+ int len = (int)(gettail(rel_fname) - rel_fname);
-+
-+ if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL)
-+ {
-+ // Make the start dir an absolute path name.
-+ vim_strncpy(ff_expand_buffer, rel_fname, len);
-+ search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, FALSE);
-+ }
-+ else
-+ search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len);
-+ if (search_ctx->ffsc_start_dir == NULL)
-+ goto error_return;
-+ if (*++path != NUL)
-+ ++path;
-+ }
-+ else if (*path == NUL || !vim_isAbsName(path))
-+ {
-+ #ifdef BACKSLASH_IN_FILENAME
-+ // "c:dir" needs "c:" to be expanded, otherwise use current dir
-+ if (*path != NUL && path[1] == ':')
-+ {
-+ char_u drive[3];
-+
-+ drive[0] = path[0];
-+ drive[1] = ':';
-+ drive[2] = NUL;
-+ if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
-+ goto error_return;
-+ path += 2;
-+ }
-+ else
-+ #endif
-+ if (mch_dirname(ff_expand_buffer, MAXPATHL) == FAIL)
-+ goto error_return;
-+
-+ search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer);
-+ if (search_ctx->ffsc_start_dir == NULL)
-+ goto error_return;
-+
-+ #ifdef BACKSLASH_IN_FILENAME
-+ // A path that starts with "/dir" is relative to the drive, not to the
-+ // directory (but not for "//machine/dir"). Only use the drive name.
-+ if ((*path == '/' || *path == '\\')
-+ && path[1] != path[0]
-+ && search_ctx->ffsc_start_dir[1] == ':')
-+ search_ctx->ffsc_start_dir[2] = NUL;
-+ #endif
-+ }
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ /*
-+ * If stopdirs are given, split them into an array of pointers.
-+ * If this fails (mem allocation), there is no upward search at all or a
-+ * stop directory is not recognized -> continue silently.
-+ * If stopdirs just contains a ";" or is empty,
-+ * search_ctx->ffsc_stopdirs_v will only contain a NULL pointer. This
-+ * is handled as unlimited upward search. See function
-+ * ff_path_in_stoplist() for details.
-+ */
-+ if (stopdirs != NULL)
-+ {
-+ char_u *walker = stopdirs;
-+ int dircount;
-+
-+ while (*walker == ';')
-+ walker++;
-+
-+ dircount = 1;
-+ search_ctx->ffsc_stopdirs_v =
-+ (char_u **)alloc((unsigned)sizeof(char_u *));
-+
-+ if (search_ctx->ffsc_stopdirs_v != NULL)
-+ {
-+ do
-+ {
-+ char_u *helper;
-+ void *ptr;
-+
-+ helper = walker;
-+ ptr = vim_realloc(search_ctx->ffsc_stopdirs_v,
-+ (dircount + 1) * sizeof(char_u *));
-+ if (ptr)
-+ search_ctx->ffsc_stopdirs_v = ptr;
-+ else
-+ // ignore, keep what we have and continue
-+ break;
-+ walker = vim_strchr(walker, ';');
-+ if (walker)
-+ {
-+ search_ctx->ffsc_stopdirs_v[dircount-1] =
-+ vim_strnsave(helper, (int)(walker - helper));
-+ walker++;
-+ }
-+ else
-+ // this might be "", which means ascent till top
-+ // of directory tree.
-+ search_ctx->ffsc_stopdirs_v[dircount-1] =
-+ vim_strsave(helper);
-+
-+ dircount++;
-+
-+ } while (walker != NULL);
-+ search_ctx->ffsc_stopdirs_v[dircount-1] = NULL;
-+ }
-+ }
-+ #endif
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ search_ctx->ffsc_level = level;
-+
-+ /*
-+ * split into:
-+ * -fix path
-+ * -wildcard_stuff (might be NULL)
-+ */
-+ wc_part = vim_strchr(path, '*');
-+ if (wc_part != NULL)
-+ {
-+ int llevel;
-+ int len;
-+ char *errpt;
-+
-+ // save the fix part of the path
-+ search_ctx->ffsc_fix_path = vim_strnsave(path, (int)(wc_part - path));
-+
-+ /*
-+ * copy wc_path and add restricts to the '**' wildcard.
-+ * The octet after a '**' is used as a (binary) counter.
-+ * So '**3' is transposed to '**^C' ('^C' is ASCII value 3)
-+ * or '**76' is transposed to '**N'( 'N' is ASCII value 76).
-+ * For EBCDIC you get different character values.
-+ * If no restrict is given after '**' the default is used.
-+ * Due to this technique the path looks awful if you print it as a
-+ * string.
-+ */
-+ len = 0;
-+ while (*wc_part != NUL)
-+ {
-+ if (len + 5 >= MAXPATHL)
-+ {
-+ emsg(_(e_pathtoolong));
-+ break;
-+ }
-+ if (STRNCMP(wc_part, "**", 2) == 0)
-+ {
-+ ff_expand_buffer[len++] = *wc_part++;
-+ ff_expand_buffer[len++] = *wc_part++;
-+
-+ llevel = strtol((char *)wc_part, &errpt, 10);
-+ if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255)
-+ ff_expand_buffer[len++] = llevel;
-+ else if ((char_u *)errpt != wc_part && llevel == 0)
-+ // restrict is 0 -> remove already added '**'
-+ len -= 2;
-+ else
-+ ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND;
-+ wc_part = (char_u *)errpt;
-+ if (*wc_part != NUL && !vim_ispathsep(*wc_part))
-+ {
-+ semsg(_("E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."), PATHSEPSTR);
-+ goto error_return;
-+ }
-+ }
-+ else
-+ ff_expand_buffer[len++] = *wc_part++;
-+ }
-+ ff_expand_buffer[len] = NUL;
-+ search_ctx->ffsc_wc_path = vim_strsave(ff_expand_buffer);
-+
-+ if (search_ctx->ffsc_wc_path == NULL)
-+ goto error_return;
-+ }
-+ else
-+ #endif
-+ search_ctx->ffsc_fix_path = vim_strsave(path);
-+
-+ if (search_ctx->ffsc_start_dir == NULL)
-+ {
-+ // store the fix part as startdir.
-+ // This is needed if the parameter path is fully qualified.
-+ search_ctx->ffsc_start_dir = vim_strsave(search_ctx->ffsc_fix_path);
-+ if (search_ctx->ffsc_start_dir == NULL)
-+ goto error_return;
-+ search_ctx->ffsc_fix_path[0] = NUL;
-+ }
-+
-+ // create an absolute path
-+ if (STRLEN(search_ctx->ffsc_start_dir)
-+ + STRLEN(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL)
-+ {
-+ emsg(_(e_pathtoolong));
-+ goto error_return;
-+ }
-+ STRCPY(ff_expand_buffer, search_ctx->ffsc_start_dir);
-+ add_pathsep(ff_expand_buffer);
-+ {
-+ int eb_len = (int)STRLEN(ff_expand_buffer);
-+ char_u *buf = alloc(eb_len
-+ + (int)STRLEN(search_ctx->ffsc_fix_path) + 1);
-+
-+ STRCPY(buf, ff_expand_buffer);
-+ STRCPY(buf + eb_len, search_ctx->ffsc_fix_path);
-+ if (mch_isdir(buf))
-+ {
-+ STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path);
-+ add_pathsep(ff_expand_buffer);
-+ }
-+ #ifdef FEAT_PATH_EXTRA
-+ else
-+ {
-+ char_u *p = gettail(search_ctx->ffsc_fix_path);
-+ char_u *wc_path = NULL;
-+ char_u *temp = NULL;
-+ int len = 0;
-+
-+ if (p > search_ctx->ffsc_fix_path)
-+ {
-+ len = (int)(p - search_ctx->ffsc_fix_path) - 1;
-+ STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len);
-+ add_pathsep(ff_expand_buffer);
-+ }
-+ else
-+ len = (int)STRLEN(search_ctx->ffsc_fix_path);
-+
-+ if (search_ctx->ffsc_wc_path != NULL)
-+ {
-+ wc_path = vim_strsave(search_ctx->ffsc_wc_path);
-+ temp = alloc((int)(STRLEN(search_ctx->ffsc_wc_path)
-+ + STRLEN(search_ctx->ffsc_fix_path + len)
-+ + 1));
-+ if (temp == NULL || wc_path == NULL)
-+ {
-+ vim_free(buf);
-+ vim_free(temp);
-+ vim_free(wc_path);
-+ goto error_return;
-+ }
-+
-+ STRCPY(temp, search_ctx->ffsc_fix_path + len);
-+ STRCAT(temp, search_ctx->ffsc_wc_path);
-+ vim_free(search_ctx->ffsc_wc_path);
-+ vim_free(wc_path);
-+ search_ctx->ffsc_wc_path = temp;
-+ }
-+ }
-+ #endif
-+ vim_free(buf);
-+ }
-+
-+ sptr = ff_create_stack_element(ff_expand_buffer,
-+ #ifdef FEAT_PATH_EXTRA
-+ search_ctx->ffsc_wc_path,
-+ #endif
-+ level, 0);
-+
-+ if (sptr == NULL)
-+ goto error_return;
-+
-+ ff_push(search_ctx, sptr);
-+
-+ search_ctx->ffsc_file_to_search = vim_strsave(filename);
-+ if (search_ctx->ffsc_file_to_search == NULL)
-+ goto error_return;
-+
-+ return search_ctx;
-+
-+ error_return:
-+ /*
-+ * We clear the search context now!
-+ * Even when the caller gave us a (perhaps valid) context we free it here,
-+ * as we might have already destroyed it.
-+ */
-+ vim_findfile_cleanup(search_ctx);
-+ return NULL;
-+ }
-+
-+ #if defined(FEAT_PATH_EXTRA) || defined(PROTO)
-+ /*
-+ * Get the stopdir string. Check that ';' is not escaped.
-+ */
-+ char_u *
-+ vim_findfile_stopdir(char_u *buf)
-+ {
-+ char_u *r_ptr = buf;
-+
-+ while (*r_ptr != NUL && *r_ptr != ';')
-+ {
-+ if (r_ptr[0] == '\\' && r_ptr[1] == ';')
-+ {
-+ // Overwrite the escape char,
-+ // use STRLEN(r_ptr) to move the trailing '\0'.
-+ STRMOVE(r_ptr, r_ptr + 1);
-+ r_ptr++;
-+ }
-+ r_ptr++;
-+ }
-+ if (*r_ptr == ';')
-+ {
-+ *r_ptr = 0;
-+ r_ptr++;
-+ }
-+ else if (*r_ptr == NUL)
-+ r_ptr = NULL;
-+ return r_ptr;
-+ }
-+ #endif
-+
-+ /*
-+ * Clean up the given search context. Can handle a NULL pointer.
-+ */
-+ void
-+ vim_findfile_cleanup(void *ctx)
-+ {
-+ if (ctx == NULL)
-+ return;
-+
-+ vim_findfile_free_visited(ctx);
-+ ff_clear(ctx);
-+ vim_free(ctx);
-+ }
-+
-+ /*
-+ * Find a file in a search context.
-+ * The search context was created with vim_findfile_init() above.
-+ * Return a pointer to an allocated file name or NULL if nothing found.
-+ * To get all matching files call this function until you get NULL.
-+ *
-+ * If the passed search_context is NULL, NULL is returned.
-+ *
-+ * The search algorithm is depth first. To change this replace the
-+ * stack with a list (don't forget to leave partly searched directories on the
-+ * top of the list).
-+ */
-+ char_u *
-+ vim_findfile(void *search_ctx_arg)
-+ {
-+ char_u *file_path;
-+ #ifdef FEAT_PATH_EXTRA
-+ char_u *rest_of_wildcards;
-+ char_u *path_end = NULL;
-+ #endif
-+ ff_stack_T *stackp;
-+ #if defined(FEAT_SEARCHPATH) || defined(FEAT_PATH_EXTRA)
-+ int len;
-+ #endif
-+ int i;
-+ char_u *p;
-+ #ifdef FEAT_SEARCHPATH
-+ char_u *suf;
-+ #endif
-+ ff_search_ctx_T *search_ctx;
-+
-+ if (search_ctx_arg == NULL)
-+ return NULL;
-+
-+ search_ctx = (ff_search_ctx_T *)search_ctx_arg;
-+
-+ /*
-+ * filepath is used as buffer for various actions and as the storage to
-+ * return a found filename.
-+ */
-+ if ((file_path = alloc((int)MAXPATHL)) == NULL)
-+ return NULL;
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ // store the end of the start dir -- needed for upward search
-+ if (search_ctx->ffsc_start_dir != NULL)
-+ path_end = &search_ctx->ffsc_start_dir[
-+ STRLEN(search_ctx->ffsc_start_dir)];
-+ #endif
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ // upward search loop
-+ for (;;)
-+ {
-+ #endif
-+ // downward search loop
-+ for (;;)
-+ {
-+ // check if user user wants to stop the search
-+ ui_breakcheck();
-+ if (got_int)
-+ break;
-+
-+ // get directory to work on from stack
-+ stackp = ff_pop(search_ctx);
-+ if (stackp == NULL)
-+ break;
-+
-+ /*
-+ * TODO: decide if we leave this test in
-+ *
-+ * GOOD: don't search a directory(-tree) twice.
-+ * BAD: - check linked list for every new directory entered.
-+ * - check for double files also done below
-+ *
-+ * Here we check if we already searched this directory.
-+ * We already searched a directory if:
-+ * 1) The directory is the same.
-+ * 2) We would use the same wildcard string.
-+ *
-+ * Good if you have links on same directory via several ways
-+ * or you have selfreferences in directories (e.g. SuSE Linux 6.3:
-+ * /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop)
-+ *
-+ * This check is only needed for directories we work on for the
-+ * first time (hence stackp->ff_filearray == NULL)
-+ */
-+ if (stackp->ffs_filearray == NULL
-+ && ff_check_visited(&search_ctx->ffsc_dir_visited_list
-+ ->ffvl_visited_list,
-+ stackp->ffs_fix_path
-+ #ifdef FEAT_PATH_EXTRA
-+ , stackp->ffs_wc_path
-+ #endif
-+ ) == FAIL)
-+ {
-+ #ifdef FF_VERBOSE
-+ if (p_verbose >= 5)
-+ {
-+ verbose_enter_scroll();
-+ smsg("Already Searched: %s (%s)",
-+ stackp->ffs_fix_path, stackp->ffs_wc_path);
-+ // don't overwrite this either
-+ msg_puts("\n");
-+ verbose_leave_scroll();
-+ }
-+ #endif
-+ ff_free_stack_element(stackp);
-+ continue;
-+ }
-+ #ifdef FF_VERBOSE
-+ else if (p_verbose >= 5)
-+ {
-+ verbose_enter_scroll();
-+ smsg("Searching: %s (%s)",
-+ stackp->ffs_fix_path, stackp->ffs_wc_path);
-+ // don't overwrite this either
-+ msg_puts("\n");
-+ verbose_leave_scroll();
-+ }
-+ #endif
-+
-+ // check depth
-+ if (stackp->ffs_level <= 0)
-+ {
-+ ff_free_stack_element(stackp);
-+ continue;
-+ }
-+
-+ file_path[0] = NUL;
-+
-+ /*
-+ * If no filearray till now expand wildcards
-+ * The function expand_wildcards() can handle an array of paths
-+ * and all possible expands are returned in one array. We use this
-+ * to handle the expansion of '**' into an empty string.
-+ */
-+ if (stackp->ffs_filearray == NULL)
-+ {
-+ char_u *dirptrs[2];
-+
-+ // we use filepath to build the path expand_wildcards() should
-+ // expand.
-+ dirptrs[0] = file_path;
-+ dirptrs[1] = NULL;
-+
-+ // if we have a start dir copy it in
-+ if (!vim_isAbsName(stackp->ffs_fix_path)
-+ && search_ctx->ffsc_start_dir)
-+ {
-+ if (STRLEN(search_ctx->ffsc_start_dir) + 1 < MAXPATHL)
-+ {
-+ STRCPY(file_path, search_ctx->ffsc_start_dir);
-+ add_pathsep(file_path);
-+ }
-+ else
-+ {
-+ ff_free_stack_element(stackp);
-+ goto fail;
-+ }
-+ }
-+
-+ // append the fix part of the search path
-+ if (STRLEN(file_path) + STRLEN(stackp->ffs_fix_path) + 1
-+ < MAXPATHL)
-+ {
-+ STRCAT(file_path, stackp->ffs_fix_path);
-+ add_pathsep(file_path);
-+ }
-+ else
-+ {
-+ ff_free_stack_element(stackp);
-+ goto fail;
-+ }
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ rest_of_wildcards = stackp->ffs_wc_path;
-+ if (*rest_of_wildcards != NUL)
-+ {
-+ len = (int)STRLEN(file_path);
-+ if (STRNCMP(rest_of_wildcards, "**", 2) == 0)
-+ {
-+ // pointer to the restrict byte
-+ // The restrict byte is not a character!
-+ p = rest_of_wildcards + 2;
-+
-+ if (*p > 0)
-+ {
-+ (*p)--;
-+ if (len + 1 < MAXPATHL)
-+ file_path[len++] = '*';
-+ else
-+ {
-+ ff_free_stack_element(stackp);
-+ goto fail;
-+ }
-+ }
-+
-+ if (*p == 0)
-+ {
-+ // remove '**<numb> from wildcards
-+ STRMOVE(rest_of_wildcards, rest_of_wildcards + 3);
-+ }
-+ else
-+ rest_of_wildcards += 3;
-+
-+ if (stackp->ffs_star_star_empty == 0)
-+ {
-+ // if not done before, expand '**' to empty
-+ stackp->ffs_star_star_empty = 1;
-+ dirptrs[1] = stackp->ffs_fix_path;
-+ }
-+ }
-+
-+ /*
-+ * Here we copy until the next path separator or the end of
-+ * the path. If we stop at a path separator, there is
-+ * still something else left. This is handled below by
-+ * pushing every directory returned from expand_wildcards()
-+ * on the stack again for further search.
-+ */
-+ while (*rest_of_wildcards
-+ && !vim_ispathsep(*rest_of_wildcards))
-+ if (len + 1 < MAXPATHL)
-+ file_path[len++] = *rest_of_wildcards++;
-+ else
-+ {
-+ ff_free_stack_element(stackp);
-+ goto fail;
-+ }
-+
-+ file_path[len] = NUL;
-+ if (vim_ispathsep(*rest_of_wildcards))
-+ rest_of_wildcards++;
-+ }
-+ #endif
-+
-+ /*
-+ * Expand wildcards like "*" and "$VAR".
-+ * If the path is a URL don't try this.
-+ */
-+ if (path_with_url(dirptrs[0]))
-+ {
-+ stackp->ffs_filearray = (char_u **)
-+ alloc((unsigned)sizeof(char *));
-+ if (stackp->ffs_filearray != NULL
-+ && (stackp->ffs_filearray[0]
-+ = vim_strsave(dirptrs[0])) != NULL)
-+ stackp->ffs_filearray_size = 1;
-+ else
-+ stackp->ffs_filearray_size = 0;
-+ }
-+ else
-+ // Add EW_NOTWILD because the expanded path may contain
-+ // wildcard characters that are to be taken literally.
-+ // This is a bit of a hack.
-+ expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs,
-+ &stackp->ffs_filearray_size,
-+ &stackp->ffs_filearray,
-+ EW_DIR|EW_ADDSLASH|EW_SILENT|EW_NOTWILD);
-+
-+ stackp->ffs_filearray_cur = 0;
-+ stackp->ffs_stage = 0;
-+ }
-+ #ifdef FEAT_PATH_EXTRA
-+ else
-+ rest_of_wildcards = &stackp->ffs_wc_path[
-+ STRLEN(stackp->ffs_wc_path)];
-+ #endif
-+
-+ if (stackp->ffs_stage == 0)
-+ {
-+ // this is the first time we work on this directory
-+ #ifdef FEAT_PATH_EXTRA
-+ if (*rest_of_wildcards == NUL)
-+ #endif
-+ {
-+ /*
-+ * We don't have further wildcards to expand, so we have to
-+ * check for the final file now.
-+ */
-+ for (i = stackp->ffs_filearray_cur;
-+ i < stackp->ffs_filearray_size; ++i)
-+ {
-+ if (!path_with_url(stackp->ffs_filearray[i])
-+ && !mch_isdir(stackp->ffs_filearray[i]))
-+ continue; /* not a directory */
-+
-+ // prepare the filename to be checked for existence
-+ // below
-+ if (STRLEN(stackp->ffs_filearray[i]) + 1
-+ + STRLEN(search_ctx->ffsc_file_to_search)
-+ < MAXPATHL)
-+ {
-+ STRCPY(file_path, stackp->ffs_filearray[i]);
-+ add_pathsep(file_path);
-+ STRCAT(file_path, search_ctx->ffsc_file_to_search);
-+ }
-+ else
-+ {
-+ ff_free_stack_element(stackp);
-+ goto fail;
-+ }
-+
-+ /*
-+ * Try without extra suffix and then with suffixes
-+ * from 'suffixesadd'.
-+ */
-+ #ifdef FEAT_SEARCHPATH
-+ len = (int)STRLEN(file_path);
-+ if (search_ctx->ffsc_tagfile)
-+ suf = (char_u *)"";
-+ else
-+ suf = curbuf->b_p_sua;
-+ for (;;)
-+ #endif
-+ {
-+ // if file exists and we didn't already find it
-+ if ((path_with_url(file_path)
-+ || (mch_getperm(file_path) >= 0
-+ && (search_ctx->ffsc_find_what
-+ == FINDFILE_BOTH
-+ || ((search_ctx->ffsc_find_what
-+ == FINDFILE_DIR)
-+ == mch_isdir(file_path)))))
-+ #ifndef FF_VERBOSE
-+ && (ff_check_visited(
-+ &search_ctx->ffsc_visited_list->ffvl_visited_list,
-+ file_path
-+ #ifdef FEAT_PATH_EXTRA
-+ , (char_u *)""
-+ #endif
-+ ) == OK)
-+ #endif
-+ )
-+ {
-+ #ifdef FF_VERBOSE
-+ if (ff_check_visited(
-+ &search_ctx->ffsc_visited_list->ffvl_visited_list,
-+ file_path
-+ #ifdef FEAT_PATH_EXTRA
-+ , (char_u *)""
-+ #endif
-+ ) == FAIL)
-+ {
-+ if (p_verbose >= 5)
-+ {
-+ verbose_enter_scroll();
-+ smsg("Already: %s",
-+ file_path);
-+ // don't overwrite this either
-+ msg_puts("\n");
-+ verbose_leave_scroll();
-+ }
-+ continue;
-+ }
-+ #endif
-+
-+ // push dir to examine rest of subdirs later
-+ stackp->ffs_filearray_cur = i + 1;
-+ ff_push(search_ctx, stackp);
-+
-+ if (!path_with_url(file_path))
-+ simplify_filename(file_path);
-+ if (mch_dirname(ff_expand_buffer, MAXPATHL)
-+ == OK)
-+ {
-+ p = shorten_fname(file_path,
-+ ff_expand_buffer);
-+ if (p != NULL)
-+ STRMOVE(file_path, p);
-+ }
-+ #ifdef FF_VERBOSE
-+ if (p_verbose >= 5)
-+ {
-+ verbose_enter_scroll();
-+ smsg("HIT: %s", file_path);
-+ // don't overwrite this either
-+ msg_puts("\n");
-+ verbose_leave_scroll();
-+ }
-+ #endif
-+ return file_path;
-+ }
-+
-+ #ifdef FEAT_SEARCHPATH
-+ // Not found or found already, try next suffix.
-+ if (*suf == NUL)
-+ break;
-+ copy_option_part(&suf, file_path + len,
-+ MAXPATHL - len, ",");
-+ #endif
-+ }
-+ }
-+ }
-+ #ifdef FEAT_PATH_EXTRA
-+ else
-+ {
-+ /*
-+ * still wildcards left, push the directories for further
-+ * search
-+ */
-+ for (i = stackp->ffs_filearray_cur;
-+ i < stackp->ffs_filearray_size; ++i)
-+ {
-+ if (!mch_isdir(stackp->ffs_filearray[i]))
-+ continue; // not a directory
-+
-+ ff_push(search_ctx,
-+ ff_create_stack_element(
-+ stackp->ffs_filearray[i],
-+ rest_of_wildcards,
-+ stackp->ffs_level - 1, 0));
-+ }
-+ }
-+ #endif
-+ stackp->ffs_filearray_cur = 0;
-+ stackp->ffs_stage = 1;
-+ }
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ /*
-+ * if wildcards contains '**' we have to descent till we reach the
-+ * leaves of the directory tree.
-+ */
-+ if (STRNCMP(stackp->ffs_wc_path, "**", 2) == 0)
-+ {
-+ for (i = stackp->ffs_filearray_cur;
-+ i < stackp->ffs_filearray_size; ++i)
-+ {
-+ if (fnamecmp(stackp->ffs_filearray[i],
-+ stackp->ffs_fix_path) == 0)
-+ continue; // don't repush same directory
-+ if (!mch_isdir(stackp->ffs_filearray[i]))
-+ continue; // not a directory
-+ ff_push(search_ctx,
-+ ff_create_stack_element(stackp->ffs_filearray[i],
-+ stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
-+ }
-+ }
-+ #endif
-+
-+ // we are done with the current directory
-+ ff_free_stack_element(stackp);
-+
-+ }
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ // If we reached this, we didn't find anything downwards.
-+ // Let's check if we should do an upward search.
-+ if (search_ctx->ffsc_start_dir
-+ && search_ctx->ffsc_stopdirs_v != NULL && !got_int)
-+ {
-+ ff_stack_T *sptr;
-+
-+ // is the last starting directory in the stop list?
-+ if (ff_path_in_stoplist(search_ctx->ffsc_start_dir,
-+ (int)(path_end - search_ctx->ffsc_start_dir),
-+ search_ctx->ffsc_stopdirs_v) == TRUE)
-+ break;
-+
-+ // cut of last dir
-+ while (path_end > search_ctx->ffsc_start_dir
-+ && vim_ispathsep(*path_end))
-+ path_end--;
-+ while (path_end > search_ctx->ffsc_start_dir
-+ && !vim_ispathsep(path_end[-1]))
-+ path_end--;
-+ *path_end = 0;
-+ path_end--;
-+
-+ if (*search_ctx->ffsc_start_dir == 0)
-+ break;
-+
-+ if (STRLEN(search_ctx->ffsc_start_dir) + 1
-+ + STRLEN(search_ctx->ffsc_fix_path) < MAXPATHL)
-+ {
-+ STRCPY(file_path, search_ctx->ffsc_start_dir);
-+ add_pathsep(file_path);
-+ STRCAT(file_path, search_ctx->ffsc_fix_path);
-+ }
-+ else
-+ goto fail;
-+
-+ // create a new stack entry
-+ sptr = ff_create_stack_element(file_path,
-+ search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0);
-+ if (sptr == NULL)
-+ break;
-+ ff_push(search_ctx, sptr);
-+ }
-+ else
-+ break;
-+ }
-+ #endif
-+
-+ fail:
-+ vim_free(file_path);
-+ return NULL;
-+ }
-+
-+ /*
-+ * Free the list of lists of visited files and directories
-+ * Can handle it if the passed search_context is NULL;
-+ */
-+ void
-+ vim_findfile_free_visited(void *search_ctx_arg)
-+ {
-+ ff_search_ctx_T *search_ctx;
-+
-+ if (search_ctx_arg == NULL)
-+ return;
-+
-+ search_ctx = (ff_search_ctx_T *)search_ctx_arg;
-+ vim_findfile_free_visited_list(&search_ctx->ffsc_visited_lists_list);
-+ vim_findfile_free_visited_list(&search_ctx->ffsc_dir_visited_lists_list);
-+ }
-+
-+ static void
-+ vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp)
-+ {
-+ ff_visited_list_hdr_T *vp;
-+
-+ while (*list_headp != NULL)
-+ {
-+ vp = (*list_headp)->ffvl_next;
-+ ff_free_visited_list((*list_headp)->ffvl_visited_list);
-+
-+ vim_free((*list_headp)->ffvl_filename);
-+ vim_free(*list_headp);
-+ *list_headp = vp;
-+ }
-+ *list_headp = NULL;
-+ }
-+
-+ static void
-+ ff_free_visited_list(ff_visited_T *vl)
-+ {
-+ ff_visited_T *vp;
-+
-+ while (vl != NULL)
-+ {
-+ vp = vl->ffv_next;
-+ #ifdef FEAT_PATH_EXTRA
-+ vim_free(vl->ffv_wc_path);
-+ #endif
-+ vim_free(vl);
-+ vl = vp;
-+ }
-+ vl = NULL;
-+ }
-+
-+ /*
-+ * Returns the already visited list for the given filename. If none is found it
-+ * allocates a new one.
-+ */
-+ static ff_visited_list_hdr_T*
-+ ff_get_visited_list(
-+ char_u *filename,
-+ ff_visited_list_hdr_T **list_headp)
-+ {
-+ ff_visited_list_hdr_T *retptr = NULL;
-+
-+ // check if a visited list for the given filename exists
-+ if (*list_headp != NULL)
-+ {
-+ retptr = *list_headp;
-+ while (retptr != NULL)
-+ {
-+ if (fnamecmp(filename, retptr->ffvl_filename) == 0)
-+ {
-+ #ifdef FF_VERBOSE
-+ if (p_verbose >= 5)
-+ {
-+ verbose_enter_scroll();
-+ smsg("ff_get_visited_list: FOUND list for %s",
-+ filename);
-+ // don't overwrite this either
-+ msg_puts("\n");
-+ verbose_leave_scroll();
-+ }
-+ #endif
-+ return retptr;
-+ }
-+ retptr = retptr->ffvl_next;
-+ }
-+ }
-+
-+ #ifdef FF_VERBOSE
-+ if (p_verbose >= 5)
-+ {
-+ verbose_enter_scroll();
-+ smsg("ff_get_visited_list: new list for %s", filename);
-+ // don't overwrite this either
-+ msg_puts("\n");
-+ verbose_leave_scroll();
-+ }
-+ #endif
-+
-+ /*
-+ * if we reach this we didn't find a list and we have to allocate new list
-+ */
-+ retptr = (ff_visited_list_hdr_T*)alloc((unsigned)sizeof(*retptr));
-+ if (retptr == NULL)
-+ return NULL;
-+
-+ retptr->ffvl_visited_list = NULL;
-+ retptr->ffvl_filename = vim_strsave(filename);
-+ if (retptr->ffvl_filename == NULL)
-+ {
-+ vim_free(retptr);
-+ return NULL;
-+ }
-+ retptr->ffvl_next = *list_headp;
-+ *list_headp = retptr;
-+
-+ return retptr;
-+ }
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ /*
-+ * check if two wildcard paths are equal. Returns TRUE or FALSE.
-+ * They are equal if:
-+ * - both paths are NULL
-+ * - they have the same length
-+ * - char by char comparison is OK
-+ * - the only differences are in the counters behind a '**', so
-+ * '**\20' is equal to '**\24'
-+ */
-+ static int
-+ ff_wc_equal(char_u *s1, char_u *s2)
-+ {
-+ int i, j;
-+ int c1 = NUL;
-+ int c2 = NUL;
-+ int prev1 = NUL;
-+ int prev2 = NUL;
-+
-+ if (s1 == s2)
-+ return TRUE;
-+
-+ if (s1 == NULL || s2 == NULL)
-+ return FALSE;
-+
-+ for (i = 0, j = 0; s1[i] != NUL && s2[j] != NUL;)
-+ {
-+ c1 = PTR2CHAR(s1 + i);
-+ c2 = PTR2CHAR(s2 + j);
-+
-+ if ((p_fic ? MB_TOLOWER(c1) != MB_TOLOWER(c2) : c1 != c2)
-+ && (prev1 != '*' || prev2 != '*'))
-+ return FALSE;
-+ prev2 = prev1;
-+ prev1 = c1;
-+
-+ i += MB_PTR2LEN(s1 + i);
-+ j += MB_PTR2LEN(s2 + j);
-+ }
-+ return s1[i] == s2[j];
-+ }
-+ #endif
-+
-+ /*
-+ * maintains the list of already visited files and dirs
-+ * returns FAIL if the given file/dir is already in the list
-+ * returns OK if it is newly added
-+ *
-+ * TODO: What to do on memory allocation problems?
-+ * -> return TRUE - Better the file is found several times instead of
-+ * never.
-+ */
-+ static int
-+ ff_check_visited(
-+ ff_visited_T **visited_list,
-+ char_u *fname
-+ #ifdef FEAT_PATH_EXTRA
-+ , char_u *wc_path
-+ #endif
-+ )
-+ {
-+ ff_visited_T *vp;
-+ #ifdef UNIX
-+ stat_T st;
-+ int url = FALSE;
-+ #endif
-+
-+ // For an URL we only compare the name, otherwise we compare the
-+ // device/inode (unix) or the full path name (not Unix).
-+ if (path_with_url(fname))
-+ {
-+ vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);
-+ #ifdef UNIX
-+ url = TRUE;
-+ #endif
-+ }
-+ else
-+ {
-+ ff_expand_buffer[0] = NUL;
-+ #ifdef UNIX
-+ if (mch_stat((char *)fname, &st) < 0)
-+ #else
-+ if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
-+ #endif
-+ return FAIL;
-+ }
-+
-+ // check against list of already visited files
-+ for (vp = *visited_list; vp != NULL; vp = vp->ffv_next)
-+ {
-+ if (
-+ #ifdef UNIX
-+ !url ? (vp->ffv_dev_valid && vp->ffv_dev == st.st_dev
-+ && vp->ffv_ino == st.st_ino)
-+ :
-+ #endif
-+ fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
-+ )
-+ {
-+ #ifdef FEAT_PATH_EXTRA
-+ // are the wildcard parts equal
-+ if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
-+ #endif
-+ // already visited
-+ return FAIL;
-+ }
-+ }
-+
-+ /*
-+ * New file/dir. Add it to the list of visited files/dirs.
-+ */
-+ vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T)
-+ + STRLEN(ff_expand_buffer)));
-+
-+ if (vp != NULL)
-+ {
-+ #ifdef UNIX
-+ if (!url)
-+ {
-+ vp->ffv_dev_valid = TRUE;
-+ vp->ffv_ino = st.st_ino;
-+ vp->ffv_dev = st.st_dev;
-+ vp->ffv_fname[0] = NUL;
-+ }
-+ else
-+ {
-+ vp->ffv_dev_valid = FALSE;
-+ #endif
-+ STRCPY(vp->ffv_fname, ff_expand_buffer);
-+ #ifdef UNIX
-+ }
-+ #endif
-+ #ifdef FEAT_PATH_EXTRA
-+ if (wc_path != NULL)
-+ vp->ffv_wc_path = vim_strsave(wc_path);
-+ else
-+ vp->ffv_wc_path = NULL;
-+ #endif
-+
-+ vp->ffv_next = *visited_list;
-+ *visited_list = vp;
-+ }
-+
-+ return OK;
-+ }
-+
-+ /*
-+ * create stack element from given path pieces
-+ */
-+ static ff_stack_T *
-+ ff_create_stack_element(
-+ char_u *fix_part,
-+ #ifdef FEAT_PATH_EXTRA
-+ char_u *wc_part,
-+ #endif
-+ int level,
-+ int star_star_empty)
-+ {
-+ ff_stack_T *new;
-+
-+ new = (ff_stack_T *)alloc((unsigned)sizeof(ff_stack_T));
-+ if (new == NULL)
-+ return NULL;
-+
-+ new->ffs_prev = NULL;
-+ new->ffs_filearray = NULL;
-+ new->ffs_filearray_size = 0;
-+ new->ffs_filearray_cur = 0;
-+ new->ffs_stage = 0;
-+ new->ffs_level = level;
-+ new->ffs_star_star_empty = star_star_empty;
-+
-+ // the following saves NULL pointer checks in vim_findfile
-+ if (fix_part == NULL)
-+ fix_part = (char_u *)"";
-+ new->ffs_fix_path = vim_strsave(fix_part);
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ if (wc_part == NULL)
-+ wc_part = (char_u *)"";
-+ new->ffs_wc_path = vim_strsave(wc_part);
-+ #endif
-+
-+ if (new->ffs_fix_path == NULL
-+ #ifdef FEAT_PATH_EXTRA
-+ || new->ffs_wc_path == NULL
-+ #endif
-+ )
-+ {
-+ ff_free_stack_element(new);
-+ new = NULL;
-+ }
-+
-+ return new;
-+ }
-+
-+ /*
-+ * Push a dir on the directory stack.
-+ */
-+ static void
-+ ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr)
-+ {
-+ // check for NULL pointer, not to return an error to the user, but
-+ // to prevent a crash
-+ if (stack_ptr != NULL)
-+ {
-+ stack_ptr->ffs_prev = search_ctx->ffsc_stack_ptr;
-+ search_ctx->ffsc_stack_ptr = stack_ptr;
-+ }
-+ }
-+
-+ /*
-+ * Pop a dir from the directory stack.
-+ * Returns NULL if stack is empty.
-+ */
-+ static ff_stack_T *
-+ ff_pop(ff_search_ctx_T *search_ctx)
-+ {
-+ ff_stack_T *sptr;
-+
-+ sptr = search_ctx->ffsc_stack_ptr;
-+ if (search_ctx->ffsc_stack_ptr != NULL)
-+ search_ctx->ffsc_stack_ptr = search_ctx->ffsc_stack_ptr->ffs_prev;
-+
-+ return sptr;
-+ }
-+
-+ /*
-+ * free the given stack element
-+ */
-+ static void
-+ ff_free_stack_element(ff_stack_T *stack_ptr)
-+ {
-+ // vim_free handles possible NULL pointers
-+ vim_free(stack_ptr->ffs_fix_path);
-+ #ifdef FEAT_PATH_EXTRA
-+ vim_free(stack_ptr->ffs_wc_path);
-+ #endif
-+
-+ if (stack_ptr->ffs_filearray != NULL)
-+ FreeWild(stack_ptr->ffs_filearray_size, stack_ptr->ffs_filearray);
-+
-+ vim_free(stack_ptr);
-+ }
-+
-+ /*
-+ * Clear the search context, but NOT the visited list.
-+ */
-+ static void
-+ ff_clear(ff_search_ctx_T *search_ctx)
-+ {
-+ ff_stack_T *sptr;
-+
-+ // clear up stack
-+ while ((sptr = ff_pop(search_ctx)) != NULL)
-+ ff_free_stack_element(sptr);
-+
-+ vim_free(search_ctx->ffsc_file_to_search);
-+ vim_free(search_ctx->ffsc_start_dir);
-+ vim_free(search_ctx->ffsc_fix_path);
-+ #ifdef FEAT_PATH_EXTRA
-+ vim_free(search_ctx->ffsc_wc_path);
-+ #endif
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ if (search_ctx->ffsc_stopdirs_v != NULL)
-+ {
-+ int i = 0;
-+
-+ while (search_ctx->ffsc_stopdirs_v[i] != NULL)
-+ {
-+ vim_free(search_ctx->ffsc_stopdirs_v[i]);
-+ i++;
-+ }
-+ vim_free(search_ctx->ffsc_stopdirs_v);
-+ }
-+ search_ctx->ffsc_stopdirs_v = NULL;
-+ #endif
-+
-+ // reset everything
-+ search_ctx->ffsc_file_to_search = NULL;
-+ search_ctx->ffsc_start_dir = NULL;
-+ search_ctx->ffsc_fix_path = NULL;
-+ #ifdef FEAT_PATH_EXTRA
-+ search_ctx->ffsc_wc_path = NULL;
-+ search_ctx->ffsc_level = 0;
-+ #endif
-+ }
-+
-+ #ifdef FEAT_PATH_EXTRA
-+ /*
-+ * check if the given path is in the stopdirs
-+ * returns TRUE if yes else FALSE
-+ */
-+ static int
-+ ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v)
-+ {
-+ int i = 0;
-+
-+ // eat up trailing path separators, except the first
-+ while (path_len > 1 && vim_ispathsep(path[path_len - 1]))
-+ path_len--;
-+
-+ // if no path consider it as match
-+ if (path_len == 0)
-+ return TRUE;
-+
-+ for (i = 0; stopdirs_v[i] != NULL; i++)
-+ {
-+ if ((int)STRLEN(stopdirs_v[i]) > path_len)
-+ {
-+ // match for parent directory. So '/home' also matches
-+ // '/home/rks'. Check for PATHSEP in stopdirs_v[i], else
-+ // '/home/r' would also match '/home/rks'
-+ if (fnamencmp(stopdirs_v[i], path, path_len) == 0
-+ && vim_ispathsep(stopdirs_v[i][path_len]))
-+ return TRUE;
-+ }
-+ else
-+ {
-+ if (fnamecmp(stopdirs_v[i], path) == 0)
-+ return TRUE;
-+ }
-+ }
-+ return FALSE;
-+ }
-+ #endif
-+
-+ #if defined(FEAT_SEARCHPATH) || defined(PROTO)
-+ /*
-+ * Find the file name "ptr[len]" in the path. Also finds directory names.
-+ *
-+ * On the first call set the parameter 'first' to TRUE to initialize
-+ * the search. For repeating calls to FALSE.
-+ *
-+ * Repeating calls will return other files called 'ptr[len]' from the path.
-+ *
-+ * Only on the first call 'ptr' and 'len' are used. For repeating calls they
-+ * don't need valid values.
-+ *
-+ * If nothing found on the first call the option FNAME_MESS will issue the
-+ * message:
-+ * 'Can't find file "<file>" in path'
-+ * On repeating calls:
-+ * 'No more file "<file>" found in path'
-+ *
-+ * options:
-+ * FNAME_MESS give error message when not found
-+ *
-+ * Uses NameBuff[]!
-+ *
-+ * Returns an allocated string for the file name. NULL for error.
-+ *
-+ */
-+ char_u *
-+ find_file_in_path(
-+ char_u *ptr, // file name
-+ int len, // length of file name
-+ int options,
-+ int first, // use count'th matching file name
-+ char_u *rel_fname) // file name searching relative to
-+ {
-+ return find_file_in_path_option(ptr, len, options, first,
-+ *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path,
-+ FINDFILE_BOTH, rel_fname, curbuf->b_p_sua);
-+ }
-+
-+ static char_u *ff_file_to_find = NULL;
-+ static void *fdip_search_ctx = NULL;
-+
-+ # if defined(EXITFREE) || defined(PROTO)
-+ void
-+ free_findfile(void)
-+ {
-+ vim_free(ff_file_to_find);
-+ vim_findfile_cleanup(fdip_search_ctx);
-+ vim_free(ff_expand_buffer);
-+ }
-+ # endif
-+
-+ /*
-+ * Find the directory name "ptr[len]" in the path.
-+ *
-+ * options:
-+ * FNAME_MESS give error message when not found
-+ * FNAME_UNESC unescape backslashes.
-+ *
-+ * Uses NameBuff[]!
-+ *
-+ * Returns an allocated string for the file name. NULL for error.
-+ */
-+ char_u *
-+ find_directory_in_path(
-+ char_u *ptr, // file name
-+ int len, // length of file name
-+ int options,
-+ char_u *rel_fname) // file name searching relative to
-+ {
-+ return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath,
-+ FINDFILE_DIR, rel_fname, (char_u *)"");
-+ }
-+
-+ char_u *
-+ find_file_in_path_option(
-+ char_u *ptr, // file name
-+ int len, // length of file name
-+ int options,
-+ int first, // use count'th matching file name
-+ char_u *path_option, // p_path or p_cdpath
-+ int find_what, // FINDFILE_FILE, _DIR or _BOTH
-+ char_u *rel_fname, // file name we are looking relative to.
-+ char_u *suffixes) // list of suffixes, 'suffixesadd' option
-+ {
-+ static char_u *dir;
-+ static int did_findfile_init = FALSE;
-+ char_u save_char;
-+ char_u *file_name = NULL;
-+ char_u *buf = NULL;
-+ int rel_to_curdir;
-+ # ifdef AMIGA
-+ struct Process *proc = (struct Process *)FindTask(0L);
-+ APTR save_winptr = proc->pr_WindowPtr;
-+
-+ // Avoid a requester here for a volume that doesn't exist.
-+ proc->pr_WindowPtr = (APTR)-1L;
-+ # endif
-+
-+ if (first == TRUE)
-+ {
-+ // copy file name into NameBuff, expanding environment variables
-+ save_char = ptr[len];
-+ ptr[len] = NUL;
-+ expand_env_esc(ptr, NameBuff, MAXPATHL, FALSE, TRUE, NULL);
-+ ptr[len] = save_char;
-+
-+ vim_free(ff_file_to_find);
-+ ff_file_to_find = vim_strsave(NameBuff);
-+ if (ff_file_to_find == NULL) // out of memory
-+ {
-+ file_name = NULL;
-+ goto theend;
-+ }
-+ if (options & FNAME_UNESC)
-+ {
-+ // Change all "\ " to " ".
-+ for (ptr = ff_file_to_find; *ptr != NUL; ++ptr)
-+ if (ptr[0] == '\\' && ptr[1] == ' ')
-+ mch_memmove(ptr, ptr + 1, STRLEN(ptr));
-+ }
-+ }
-+
-+ rel_to_curdir = (ff_file_to_find[0] == '.'
-+ && (ff_file_to_find[1] == NUL
-+ || vim_ispathsep(ff_file_to_find[1])
-+ || (ff_file_to_find[1] == '.'
-+ && (ff_file_to_find[2] == NUL
-+ || vim_ispathsep(ff_file_to_find[2])))));
-+ if (vim_isAbsName(ff_file_to_find)
-+ // "..", "../path", "." and "./path": don't use the path_option
-+ || rel_to_curdir
-+ # if defined(MSWIN)
-+ // handle "\tmp" as absolute path
-+ || vim_ispathsep(ff_file_to_find[0])
-+ // handle "c:name" as absolute path
-+ || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':')
-+ # endif
-+ # ifdef AMIGA
-+ // handle ":tmp" as absolute path
-+ || ff_file_to_find[0] == ':'
-+ # endif
-+ )
-+ {
-+ /*
-+ * Absolute path, no need to use "path_option".
-+ * If this is not a first call, return NULL. We already returned a
-+ * filename on the first call.
-+ */
-+ if (first == TRUE)
-+ {
-+ int l;
-+ int run;
-+
-+ if (path_with_url(ff_file_to_find))
-+ {
-+ file_name = vim_strsave(ff_file_to_find);
-+ goto theend;
-+ }
-+
-+ // When FNAME_REL flag given first use the directory of the file.
-+ // Otherwise or when this fails use the current directory.
-+ for (run = 1; run <= 2; ++run)
-+ {
-+ l = (int)STRLEN(ff_file_to_find);
-+ if (run == 1
-+ && rel_to_curdir
-+ && (options & FNAME_REL)
-+ && rel_fname != NULL
-+ && STRLEN(rel_fname) + l < MAXPATHL)
-+ {
-+ STRCPY(NameBuff, rel_fname);
-+ STRCPY(gettail(NameBuff), ff_file_to_find);
-+ l = (int)STRLEN(NameBuff);
-+ }
-+ else
-+ {
-+ STRCPY(NameBuff, ff_file_to_find);
-+ run = 2;
-+ }
-+
-+ // When the file doesn't exist, try adding parts of
-+ // 'suffixesadd'.
-+ buf = suffixes;
-+ for (;;)
-+ {
-+ if (mch_getperm(NameBuff) >= 0
-+ && (find_what == FINDFILE_BOTH
-+ || ((find_what == FINDFILE_DIR)
-+ == mch_isdir(NameBuff))))
-+ {
-+ file_name = vim_strsave(NameBuff);
-+ goto theend;
-+ }
-+ if (*buf == NUL)
-+ break;
-+ copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ",");
-+ }
-+ }
-+ }
-+ }
-+ else
-+ {
-+ /*
-+ * Loop over all paths in the 'path' or 'cdpath' option.
-+ * When "first" is set, first setup to the start of the option.
-+ * Otherwise continue to find the next match.
-+ */
-+ if (first == TRUE)
-+ {
-+ // vim_findfile_free_visited can handle a possible NULL pointer
-+ vim_findfile_free_visited(fdip_search_ctx);
-+ dir = path_option;
-+ did_findfile_init = FALSE;
-+ }
-+
-+ for (;;)
-+ {
-+ if (did_findfile_init)
-+ {
-+ file_name = vim_findfile(fdip_search_ctx);
-+ if (file_name != NULL)
-+ break;
-+
-+ did_findfile_init = FALSE;
-+ }
-+ else
-+ {
-+ char_u *r_ptr;
-+
-+ if (dir == NULL || *dir == NUL)
-+ {
-+ // We searched all paths of the option, now we can
-+ // free the search context.
-+ vim_findfile_cleanup(fdip_search_ctx);
-+ fdip_search_ctx = NULL;
-+ break;
-+ }
-+
-+ if ((buf = alloc((int)(MAXPATHL))) == NULL)
-+ break;
-+
-+ // copy next path
-+ buf[0] = 0;
-+ copy_option_part(&dir, buf, MAXPATHL, " ,");
-+
-+ # ifdef FEAT_PATH_EXTRA
-+ // get the stopdir string
-+ r_ptr = vim_findfile_stopdir(buf);
-+ # else
-+ r_ptr = NULL;
-+ # endif
-+ fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find,
-+ r_ptr, 100, FALSE, find_what,
-+ fdip_search_ctx, FALSE, rel_fname);
-+ if (fdip_search_ctx != NULL)
-+ did_findfile_init = TRUE;
-+ vim_free(buf);
-+ }
-+ }
-+ }
-+ if (file_name == NULL && (options & FNAME_MESS))
-+ {
-+ if (first == TRUE)
-+ {
-+ if (find_what == FINDFILE_DIR)
-+ semsg(_("E344: Can't find directory \"%s\" in cdpath"),
-+ ff_file_to_find);
-+ else
-+ semsg(_("E345: Can't find file \"%s\" in path"),
-+ ff_file_to_find);
-+ }
-+ else
-+ {
-+ if (find_what == FINDFILE_DIR)
-+ semsg(_("E346: No more directory \"%s\" found in cdpath"),
-+ ff_file_to_find);
-+ else
-+ semsg(_("E347: No more file \"%s\" found in path"),
-+ ff_file_to_find);
-+ }
-+ }
-+
-+ theend:
-+ # ifdef AMIGA
-+ proc->pr_WindowPtr = save_winptr;
-+ # endif
-+ return file_name;
-+ }
-+
-+ /*
-+ * Get the file name at the cursor.
-+ * If Visual mode is active, use the selected text if it's in one line.
-+ * Returns the name in allocated memory, NULL for failure.
-+ */
-+ char_u *
-+ grab_file_name(long count, linenr_T *file_lnum)
-+ {
-+ int options = FNAME_MESS|FNAME_EXP|FNAME_REL|FNAME_UNESC;
-+
-+ if (VIsual_active)
-+ {
-+ int len;
-+ char_u *ptr;
-+
-+ if (get_visual_text(NULL, &ptr, &len) == FAIL)
-+ return NULL;
-+ return find_file_name_in_path(ptr, len, options,
-+ count, curbuf->b_ffname);
-+ }
-+ return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
-+ }
-+
-+ /*
-+ * Return the file name under or after the cursor.
-+ *
-+ * The 'path' option is searched if the file name is not absolute.
-+ * The string returned has been alloc'ed and should be freed by the caller.
-+ * NULL is returned if the file name or file is not found.
-+ *
-+ * options:
-+ * FNAME_MESS give error messages
-+ * FNAME_EXP expand to path
-+ * FNAME_HYP check for hypertext link
-+ * FNAME_INCL apply "includeexpr"
-+ */
-+ char_u *
-+ file_name_at_cursor(int options, long count, linenr_T *file_lnum)
-+ {
-+ return file_name_in_line(ml_get_curline(),
-+ curwin->w_cursor.col, options, count, curbuf->b_ffname,
-+ file_lnum);
-+ }
-+
-+ /*
-+ * Return the name of the file under or after ptr[col].
-+ * Otherwise like file_name_at_cursor().
-+ */
-+ char_u *
-+ file_name_in_line(
-+ char_u *line,
-+ int col,
-+ int options,
-+ long count,
-+ char_u *rel_fname, // file we are searching relative to
-+ linenr_T *file_lnum) // line number after the file name
-+ {
-+ char_u *ptr;
-+ int len;
-+ int in_type = TRUE;
-+ int is_url = FALSE;
-+
-+ /*
-+ * search forward for what could be the start of a file name
-+ */
-+ ptr = line + col;
-+ while (*ptr != NUL && !vim_isfilec(*ptr))
-+ MB_PTR_ADV(ptr);
-+ if (*ptr == NUL) // nothing found
-+ {
-+ if (options & FNAME_MESS)
-+ emsg(_("E446: No file name under cursor"));
-+ return NULL;
-+ }
-+
-+ /*
-+ * Search backward for first char of the file name.
-+ * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
-+ */
-+ while (ptr > line)
-+ {
-+ if (has_mbyte && (len = (*mb_head_off)(line, ptr - 1)) > 0)
-+ ptr -= len + 1;
-+ else if (vim_isfilec(ptr[-1])
-+ || ((options & FNAME_HYP) && path_is_url(ptr - 1)))
-+ --ptr;
-+ else
-+ break;
-+ }
-+
-+ /*
-+ * Search forward for the last char of the file name.
-+ * Also allow "://" when ':' is not in 'isfname'.
-+ */
-+ len = 0;
-+ while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
-+ || ((options & FNAME_HYP) && path_is_url(ptr + len))
-+ || (is_url && vim_strchr((char_u *)"?&=", ptr[len]) != NULL))
-+ {
-+ // After type:// we also include ?, & and = as valid characters, so that
-+ // http://google.com?q=this&that=ok works.
-+ if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z'))
-+ {
-+ if (in_type && path_is_url(ptr + len + 1))
-+ is_url = TRUE;
-+ }
-+ else
-+ in_type = FALSE;
-+
-+ if (ptr[len] == '\\')
-+ // Skip over the "\" in "\ ".
-+ ++len;
-+ if (has_mbyte)
-+ len += (*mb_ptr2len)(ptr + len);
-+ else
-+ ++len;
-+ }
-+
-+ /*
-+ * If there is trailing punctuation, remove it.
-+ * But don't remove "..", could be a directory name.
-+ */
-+ if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
-+ && ptr[len - 2] != '.')
-+ --len;
-+
-+ if (file_lnum != NULL)
-+ {
-+ char_u *p;
-+
-+ // Get the number after the file name and a separator character
-+ p = ptr + len;
-+ p = skipwhite(p);
-+ if (*p != NUL)
-+ {
-+ if (!isdigit(*p))
-+ ++p; // skip the separator
-+ p = skipwhite(p);
-+ if (isdigit(*p))
-+ *file_lnum = (int)getdigits(&p);
-+ }
-+ }
-+
-+ return find_file_name_in_path(ptr, len, options, count, rel_fname);
-+ }
-+
-+ # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-+ static char_u *
-+ eval_includeexpr(char_u *ptr, int len)
-+ {
-+ char_u *res;
-+
-+ set_vim_var_string(VV_FNAME, ptr, len);
-+ res = eval_to_string_safe(curbuf->b_p_inex, NULL,
-+ was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL));
-+ set_vim_var_string(VV_FNAME, NULL, 0);
-+ return res;
-+ }
-+ # endif
-+
-+ /*
-+ * Return the name of the file ptr[len] in 'path'.
-+ * Otherwise like file_name_at_cursor().
-+ */
-+ char_u *
-+ find_file_name_in_path(
-+ char_u *ptr,
-+ int len,
-+ int options,
-+ long count,
-+ char_u *rel_fname) // file we are searching relative to
-+ {
-+ char_u *file_name;
-+ int c;
-+ # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-+ char_u *tofree = NULL;
-+
-+ if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
-+ {
-+ tofree = eval_includeexpr(ptr, len);
-+ if (tofree != NULL)
-+ {
-+ ptr = tofree;
-+ len = (int)STRLEN(ptr);
-+ }
-+ }
-+ # endif
-+
-+ if (options & FNAME_EXP)
-+ {
-+ file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
-+ TRUE, rel_fname);
-+
-+ # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-+ /*
-+ * If the file could not be found in a normal way, try applying
-+ * 'includeexpr' (unless done already).
-+ */
-+ if (file_name == NULL
-+ && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
-+ {
-+ tofree = eval_includeexpr(ptr, len);
-+ if (tofree != NULL)
-+ {
-+ ptr = tofree;
-+ len = (int)STRLEN(ptr);
-+ file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
-+ TRUE, rel_fname);
-+ }
-+ }
-+ # endif
-+ if (file_name == NULL && (options & FNAME_MESS))
-+ {
-+ c = ptr[len];
-+ ptr[len] = NUL;
-+ semsg(_("E447: Can't find file \"%s\" in path"), ptr);
-+ ptr[len] = c;
-+ }
-+
-+ // Repeat finding the file "count" times. This matters when it
-+ // appears several times in the path.
-+ while (file_name != NULL && --count > 0)
-+ {
-+ vim_free(file_name);
-+ file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
-+ }
-+ }
-+ else
-+ file_name = vim_strnsave(ptr, len);
-+
-+ # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-+ vim_free(tofree);
-+ # endif
-+
-+ return file_name;
-+ }
-+
-+ /*
-+ * Return the end of the directory name, on the first path
-+ * separator:
-+ * "/path/file", "/path/dir/", "/path//dir", "/file"
-+ * ^ ^ ^ ^
-+ */
-+ static char_u *
-+ gettail_dir(char_u *fname)
-+ {
-+ char_u *dir_end = fname;
-+ char_u *next_dir_end = fname;
-+ int look_for_sep = TRUE;
-+ char_u *p;
-+
-+ for (p = fname; *p != NUL; )
-+ {
-+ if (vim_ispathsep(*p))
-+ {
-+ if (look_for_sep)
-+ {
-+ next_dir_end = p;
-+ look_for_sep = FALSE;
-+ }
-+ }
-+ else
-+ {
-+ if (!look_for_sep)
-+ dir_end = next_dir_end;
-+ look_for_sep = TRUE;
-+ }
-+ MB_PTR_ADV(p);
-+ }
-+ return dir_end;
-+ }
-+
-+ /*
-+ * return TRUE if 'c' is a path list separator.
-+ */
-+ int
-+ vim_ispathlistsep(int c)
-+ {
-+ # ifdef UNIX
-+ return (c == ':');
-+ # else
-+ return (c == ';'); // might not be right for every system...
-+ # endif
-+ }
-+
-+ /*
-+ * Moves "*psep" back to the previous path separator in "path".
-+ * Returns FAIL is "*psep" ends up at the beginning of "path".
-+ */
-+ static int
-+ find_previous_pathsep(char_u *path, char_u **psep)
-+ {
-+ // skip the current separator
-+ if (*psep > path && vim_ispathsep(**psep))
-+ --*psep;
-+
-+ // find the previous separator
-+ while (*psep > path)
-+ {
-+ if (vim_ispathsep(**psep))
-+ return OK;
-+ MB_PTR_BACK(path, *psep);
-+ }
-+
-+ return FAIL;
-+ }
-+
-+ /*
-+ * Returns TRUE if "maybe_unique" is unique wrt other_paths in "gap".
-+ * "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]".
-+ */
-+ static int
-+ is_unique(char_u *maybe_unique, garray_T *gap, int i)
-+ {
-+ int j;
-+ int candidate_len;
-+ int other_path_len;
-+ char_u **other_paths = (char_u **)gap->ga_data;
-+ char_u *rival;
-+
-+ for (j = 0; j < gap->ga_len; j++)
-+ {
-+ if (j == i)
-+ continue; // don't compare it with itself
-+
-+ candidate_len = (int)STRLEN(maybe_unique);
-+ other_path_len = (int)STRLEN(other_paths[j]);
-+ if (other_path_len < candidate_len)
-+ continue; // it's different when it's shorter
-+
-+ rival = other_paths[j] + other_path_len - candidate_len;
-+ if (fnamecmp(maybe_unique, rival) == 0
-+ && (rival == other_paths[j] || vim_ispathsep(*(rival - 1))))
-+ return FALSE; // match
-+ }
-+
-+ return TRUE; // no match found
-+ }
-+
-+ /*
-+ * Split the 'path' option into an array of strings in garray_T. Relative
-+ * paths are expanded to their equivalent fullpath. This includes the "."
-+ * (relative to current buffer directory) and empty path (relative to current
-+ * directory) notations.
-+ *
-+ * TODO: handle upward search (;) and path limiter (**N) notations by
-+ * expanding each into their equivalent path(s).
-+ */
-+ static void
-+ expand_path_option(char_u *curdir, garray_T *gap)
-+ {
-+ char_u *path_option = *curbuf->b_p_path == NUL
-+ ? p_path : curbuf->b_p_path;
-+ char_u *buf;
-+ char_u *p;
-+ int len;
-+
-+ if ((buf = alloc((int)MAXPATHL)) == NULL)
-+ return;
-+
-+ while (*path_option != NUL)
-+ {
-+ copy_option_part(&path_option, buf, MAXPATHL, " ,");
-+
-+ if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1])))
-+ {
-+ // Relative to current buffer:
-+ // "/path/file" + "." -> "/path/"
-+ // "/path/file" + "./subdir" -> "/path/subdir"
-+ if (curbuf->b_ffname == NULL)
-+ continue;
-+ p = gettail(curbuf->b_ffname);
-+ len = (int)(p - curbuf->b_ffname);
-+ if (len + (int)STRLEN(buf) >= MAXPATHL)
-+ continue;
-+ if (buf[1] == NUL)
-+ buf[len] = NUL;
-+ else
-+ STRMOVE(buf + len, buf + 2);
-+ mch_memmove(buf, curbuf->b_ffname, len);
-+ simplify_filename(buf);
-+ }
-+ else if (buf[0] == NUL)
-+ // relative to current directory
-+ STRCPY(buf, curdir);
-+ else if (path_with_url(buf))
-+ // URL can't be used here
-+ continue;
-+ else if (!mch_isFullName(buf))
-+ {
-+ // Expand relative path to their full path equivalent
-+ len = (int)STRLEN(curdir);
-+ if (len + (int)STRLEN(buf) + 3 > MAXPATHL)
-+ continue;
-+ STRMOVE(buf + len + 1, buf);
-+ STRCPY(buf, curdir);
-+ buf[len] = PATHSEP;
-+ simplify_filename(buf);
-+ }
-+
-+ if (ga_grow(gap, 1) == FAIL)
-+ break;
-+
-+ # if defined(MSWIN)
-+ // Avoid the path ending in a backslash, it fails when a comma is
-+ // appended.
-+ len = (int)STRLEN(buf);
-+ if (buf[len - 1] == '\\')
-+ buf[len - 1] = '/';
-+ # endif
-+
-+ p = vim_strsave(buf);
-+ if (p == NULL)
-+ break;
-+ ((char_u **)gap->ga_data)[gap->ga_len++] = p;
-+ }
-+
-+ vim_free(buf);
-+ }
-+
-+ /*
-+ * Returns a pointer to the file or directory name in "fname" that matches the
-+ * longest path in "ga"p, or NULL if there is no match. For example:
-+ *
-+ * path: /foo/bar/baz
-+ * fname: /foo/bar/baz/quux.txt
-+ * returns: ^this
-+ */
-+ static char_u *
-+ get_path_cutoff(char_u *fname, garray_T *gap)
-+ {
-+ int i;
-+ int maxlen = 0;
-+ char_u **path_part = (char_u **)gap->ga_data;
-+ char_u *cutoff = NULL;
-+
-+ for (i = 0; i < gap->ga_len; i++)
-+ {
-+ int j = 0;
-+
-+ while ((fname[j] == path_part[i][j]
-+ # if defined(MSWIN)
-+ || (vim_ispathsep(fname[j]) && vim_ispathsep(path_part[i][j]))
-+ # endif
-+ ) && fname[j] != NUL && path_part[i][j] != NUL)
-+ j++;
-+ if (j > maxlen)
-+ {
-+ maxlen = j;
-+ cutoff = &fname[j];
-+ }
-+ }
-+
-+ // skip to the file or directory name
-+ if (cutoff != NULL)
-+ while (vim_ispathsep(*cutoff))
-+ MB_PTR_ADV(cutoff);
-+
-+ return cutoff;
-+ }
-+
-+ /*
-+ * Sorts, removes duplicates and modifies all the fullpath names in "gap" so
-+ * that they are unique with respect to each other while conserving the part
-+ * that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len".
-+ */
-+ void
-+ uniquefy_paths(garray_T *gap, char_u *pattern)
-+ {
-+ int i;
-+ int len;
-+ char_u **fnames = (char_u **)gap->ga_data;
-+ int sort_again = FALSE;
-+ char_u *pat;
-+ char_u *file_pattern;
-+ char_u *curdir;
-+ regmatch_T regmatch;
-+ garray_T path_ga;
-+ char_u **in_curdir = NULL;
-+ char_u *short_name;
-+
-+ remove_duplicates(gap);
-+ ga_init2(&path_ga, (int)sizeof(char_u *), 1);
-+
-+ /*
-+ * We need to prepend a '*' at the beginning of file_pattern so that the
-+ * regex matches anywhere in the path. FIXME: is this valid for all
-+ * possible patterns?
-+ */
-+ len = (int)STRLEN(pattern);
-+ file_pattern = alloc(len + 2);
-+ if (file_pattern == NULL)
-+ return;
-+ file_pattern[0] = '*';
-+ file_pattern[1] = NUL;
-+ STRCAT(file_pattern, pattern);
-+ pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE);
-+ vim_free(file_pattern);
-+ if (pat == NULL)
-+ return;
-+
-+ regmatch.rm_ic = TRUE; // always ignore case
-+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
-+ vim_free(pat);
-+ if (regmatch.regprog == NULL)
-+ return;
-+
-+ if ((curdir = alloc((int)(MAXPATHL))) == NULL)
-+ goto theend;
-+ mch_dirname(curdir, MAXPATHL);
-+ expand_path_option(curdir, &path_ga);
-+
-+ in_curdir = (char_u **)alloc_clear(gap->ga_len * sizeof(char_u *));
-+ if (in_curdir == NULL)
-+ goto theend;
-+
-+ for (i = 0; i < gap->ga_len && !got_int; i++)
-+ {
-+ char_u *path = fnames[i];
-+ int is_in_curdir;
-+ char_u *dir_end = gettail_dir(path);
-+ char_u *pathsep_p;
-+ char_u *path_cutoff;
-+
-+ len = (int)STRLEN(path);
-+ is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
-+ && curdir[dir_end - path] == NUL;
-+ if (is_in_curdir)
-+ in_curdir[i] = vim_strsave(path);
-+
-+ // Shorten the filename while maintaining its uniqueness
-+ path_cutoff = get_path_cutoff(path, &path_ga);
-+
-+ // Don't assume all files can be reached without path when search
-+ // pattern starts with star star slash, so only remove path_cutoff
-+ // when possible.
-+ if (pattern[0] == '*' && pattern[1] == '*'
-+ && vim_ispathsep_nocolon(pattern[2])
-+ && path_cutoff != NULL
-+ && vim_regexec(&regmatch, path_cutoff, (colnr_T)0)
-+ && is_unique(path_cutoff, gap, i))
-+ {
-+ sort_again = TRUE;
-+ mch_memmove(path, path_cutoff, STRLEN(path_cutoff) + 1);
-+ }
-+ else
-+ {
-+ // Here all files can be reached without path, so get shortest
-+ // unique path. We start at the end of the path.
-+ pathsep_p = path + len - 1;
-+
-+ while (find_previous_pathsep(path, &pathsep_p))
-+ if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
-+ && is_unique(pathsep_p + 1, gap, i)
-+ && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
-+ {
-+ sort_again = TRUE;
-+ mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
-+ break;
-+ }
-+ }
-+
-+ if (mch_isFullName(path))
-+ {
-+ /*
-+ * Last resort: shorten relative to curdir if possible.
-+ * 'possible' means:
-+ * 1. It is under the current directory.
-+ * 2. The result is actually shorter than the original.
-+ *
-+ * Before curdir After
-+ * /foo/bar/file.txt /foo/bar ./file.txt
-+ * c:\foo\bar\file.txt c:\foo\bar .\file.txt
-+ * /file.txt / /file.txt
-+ * c:\file.txt c:\ .\file.txt
-+ */
-+ short_name = shorten_fname(path, curdir);
-+ if (short_name != NULL && short_name > path + 1
-+ # if defined(MSWIN)
-+ // On windows,
-+ // shorten_fname("c:\a\a.txt", "c:\a\b")
-+ // returns "\a\a.txt", which is not really the short
-+ // name, hence:
-+ && !vim_ispathsep(*short_name)
-+ # endif
-+ )
-+ {
-+ STRCPY(path, ".");
-+ add_pathsep(path);
-+ STRMOVE(path + STRLEN(path), short_name);
-+ }
-+ }
-+ ui_breakcheck();
-+ }
-+
-+ // Shorten filenames in /in/current/directory/{filename}
-+ for (i = 0; i < gap->ga_len && !got_int; i++)
-+ {
-+ char_u *rel_path;
-+ char_u *path = in_curdir[i];
-+
-+ if (path == NULL)
-+ continue;
-+
-+ // If the {filename} is not unique, change it to ./{filename}.
-+ // Else reduce it to {filename}
-+ short_name = shorten_fname(path, curdir);
-+ if (short_name == NULL)
-+ short_name = path;
-+ if (is_unique(short_name, gap, i))
-+ {
-+ STRCPY(fnames[i], short_name);
-+ continue;
-+ }
-+
-+ rel_path = alloc((int)(STRLEN(short_name) + STRLEN(PATHSEPSTR) + 2));
-+ if (rel_path == NULL)
-+ goto theend;
-+ STRCPY(rel_path, ".");
-+ add_pathsep(rel_path);
-+ STRCAT(rel_path, short_name);
-+
-+ vim_free(fnames[i]);
-+ fnames[i] = rel_path;
-+ sort_again = TRUE;
-+ ui_breakcheck();
-+ }
-+
-+ theend:
-+ vim_free(curdir);
-+ if (in_curdir != NULL)
-+ {
-+ for (i = 0; i < gap->ga_len; i++)
-+ vim_free(in_curdir[i]);
-+ vim_free(in_curdir);
-+ }
-+ ga_clear_strings(&path_ga);
-+ vim_regfree(regmatch.regprog);
-+
-+ if (sort_again)
-+ remove_duplicates(gap);
-+ }
-+
-+ /*
-+ * Calls globpath() with 'path' values for the given pattern and stores the
-+ * result in "gap".
-+ * Returns the total number of matches.
-+ */
-+ int
-+ expand_in_path(
-+ garray_T *gap,
-+ char_u *pattern,
-+ int flags) // EW_* flags
-+ {
-+ char_u *curdir;
-+ garray_T path_ga;
-+ char_u *paths = NULL;
-+ int glob_flags = 0;
-+
-+ if ((curdir = alloc((unsigned)MAXPATHL)) == NULL)
-+ return 0;
-+ mch_dirname(curdir, MAXPATHL);
-+
-+ ga_init2(&path_ga, (int)sizeof(char_u *), 1);
-+ expand_path_option(curdir, &path_ga);
-+ vim_free(curdir);
-+ if (path_ga.ga_len == 0)
-+ return 0;
-+
-+ paths = ga_concat_strings(&path_ga, ",");
-+ ga_clear_strings(&path_ga);
-+ if (paths == NULL)
-+ return 0;
-+
-+ if (flags & EW_ICASE)
-+ glob_flags |= WILD_ICASE;
-+ if (flags & EW_ADDSLASH)
-+ glob_flags |= WILD_ADD_SLASH;
-+ globpath(paths, pattern, gap, glob_flags);
-+ vim_free(paths);
-+
-+ return gap->ga_len;
-+ }
-+
-+ #endif // FEAT_SEARCHPATH
-*** ../vim-8.1.0913/src/misc1.c 2019-01-31 13:47:51.126632619 +0100
---- src/misc1.c 2019-02-13 22:06:27.637777681 +0100
-***************
-*** 21,26 ****
---- 21,29 ----
- static char_u *vim_version_dir(char_u *vimdir);
- static char_u *remove_tail(char_u *p, char_u *pend, char_u *name);
-
-+ #define URL_SLASH 1 /* path_is_url() has found "://" */
-+ #define URL_BACKSLASH 2 /* path_is_url() has found ":\\" */
-+
- /* All user names (for ~user completion as done by shell). */
- #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
- static garray_T ga_users;
-***************
-*** 5023,5065 ****
- return p1;
- }
-
-- #if defined(FEAT_SEARCHPATH)
-- /*
-- * Return the end of the directory name, on the first path
-- * separator:
-- * "/path/file", "/path/dir/", "/path//dir", "/file"
-- * ^ ^ ^ ^
-- */
-- static char_u *
-- gettail_dir(char_u *fname)
-- {
-- char_u *dir_end = fname;
-- char_u *next_dir_end = fname;
-- int look_for_sep = TRUE;
-- char_u *p;
--
-- for (p = fname; *p != NUL; )
-- {
-- if (vim_ispathsep(*p))
-- {
-- if (look_for_sep)
-- {
-- next_dir_end = p;
-- look_for_sep = FALSE;
-- }
-- }
-- else
-- {
-- if (!look_for_sep)
-- dir_end = next_dir_end;
-- look_for_sep = TRUE;
-- }
-- MB_PTR_ADV(p);
-- }
-- return dir_end;
-- }
-- #endif
--
- /*
- * Get pointer to tail of "fname", including path separators. Putting a NUL
- * here leaves the directory name. Takes care of "c:/" and "//".
---- 5026,5031 ----
-***************
-*** 5165,5185 ****
- ;
- }
-
-- #if defined(FEAT_SEARCHPATH) || defined(PROTO)
-- /*
-- * return TRUE if 'c' is a path list separator.
-- */
-- int
-- vim_ispathlistsep(int c)
-- {
-- #ifdef UNIX
-- return (c == ':');
-- #else
-- return (c == ';'); /* might not be right for every system... */
-- #endif
-- }
-- #endif
--
- /*
- * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname"
- * It's done in-place.
---- 5131,5136 ----
-***************
-*** 6183,6589 ****
- }
- #endif
-
-- #if defined(FEAT_SEARCHPATH)
-- /*
-- * Moves "*psep" back to the previous path separator in "path".
-- * Returns FAIL is "*psep" ends up at the beginning of "path".
-- */
-- static int
-- find_previous_pathsep(char_u *path, char_u **psep)
-- {
-- /* skip the current separator */
-- if (*psep > path && vim_ispathsep(**psep))
-- --*psep;
--
-- /* find the previous separator */
-- while (*psep > path)
-- {
-- if (vim_ispathsep(**psep))
-- return OK;
-- MB_PTR_BACK(path, *psep);
-- }
--
-- return FAIL;
-- }
--
-- /*
-- * Returns TRUE if "maybe_unique" is unique wrt other_paths in "gap".
-- * "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]".
-- */
-- static int
-- is_unique(char_u *maybe_unique, garray_T *gap, int i)
-- {
-- int j;
-- int candidate_len;
-- int other_path_len;
-- char_u **other_paths = (char_u **)gap->ga_data;
-- char_u *rival;
--
-- for (j = 0; j < gap->ga_len; j++)
-- {
-- if (j == i)
-- continue; /* don't compare it with itself */
--
-- candidate_len = (int)STRLEN(maybe_unique);
-- other_path_len = (int)STRLEN(other_paths[j]);
-- if (other_path_len < candidate_len)
-- continue; /* it's different when it's shorter */
--
-- rival = other_paths[j] + other_path_len - candidate_len;
-- if (fnamecmp(maybe_unique, rival) == 0
-- && (rival == other_paths[j] || vim_ispathsep(*(rival - 1))))
-- return FALSE; /* match */
-- }
--
-- return TRUE; /* no match found */
-- }
--
-- /*
-- * Split the 'path' option into an array of strings in garray_T. Relative
-- * paths are expanded to their equivalent fullpath. This includes the "."
-- * (relative to current buffer directory) and empty path (relative to current
-- * directory) notations.
-- *
-- * TODO: handle upward search (;) and path limiter (**N) notations by
-- * expanding each into their equivalent path(s).
-- */
-- static void
-- expand_path_option(char_u *curdir, garray_T *gap)
-- {
-- char_u *path_option = *curbuf->b_p_path == NUL
-- ? p_path : curbuf->b_p_path;
-- char_u *buf;
-- char_u *p;
-- int len;
--
-- if ((buf = alloc((int)MAXPATHL)) == NULL)
-- return;
--
-- while (*path_option != NUL)
-- {
-- copy_option_part(&path_option, buf, MAXPATHL, " ,");
--
-- if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1])))
-- {
-- /* Relative to current buffer:
-- * "/path/file" + "." -> "/path/"
-- * "/path/file" + "./subdir" -> "/path/subdir" */
-- if (curbuf->b_ffname == NULL)
-- continue;
-- p = gettail(curbuf->b_ffname);
-- len = (int)(p - curbuf->b_ffname);
-- if (len + (int)STRLEN(buf) >= MAXPATHL)
-- continue;
-- if (buf[1] == NUL)
-- buf[len] = NUL;
-- else
-- STRMOVE(buf + len, buf + 2);
-- mch_memmove(buf, curbuf->b_ffname, len);
-- simplify_filename(buf);
-- }
-- else if (buf[0] == NUL)
-- /* relative to current directory */
-- STRCPY(buf, curdir);
-- else if (path_with_url(buf))
-- /* URL can't be used here */
-- continue;
-- else if (!mch_isFullName(buf))
-- {
-- /* Expand relative path to their full path equivalent */
-- len = (int)STRLEN(curdir);
-- if (len + (int)STRLEN(buf) + 3 > MAXPATHL)
-- continue;
-- STRMOVE(buf + len + 1, buf);
-- STRCPY(buf, curdir);
-- buf[len] = PATHSEP;
-- simplify_filename(buf);
-- }
--
-- if (ga_grow(gap, 1) == FAIL)
-- break;
--
-- # if defined(MSWIN)
-- /* Avoid the path ending in a backslash, it fails when a comma is
-- * appended. */
-- len = (int)STRLEN(buf);
-- if (buf[len - 1] == '\\')
-- buf[len - 1] = '/';
-- # endif
--
-- p = vim_strsave(buf);
-- if (p == NULL)
-- break;
-- ((char_u **)gap->ga_data)[gap->ga_len++] = p;
-- }
--
-- vim_free(buf);
-- }
--
-- /*
-- * Returns a pointer to the file or directory name in "fname" that matches the
-- * longest path in "ga"p, or NULL if there is no match. For example:
-- *
-- * path: /foo/bar/baz
-- * fname: /foo/bar/baz/quux.txt
-- * returns: ^this
-- */
-- static char_u *
-- get_path_cutoff(char_u *fname, garray_T *gap)
-- {
-- int i;
-- int maxlen = 0;
-- char_u **path_part = (char_u **)gap->ga_data;
-- char_u *cutoff = NULL;
--
-- for (i = 0; i < gap->ga_len; i++)
-- {
-- int j = 0;
--
-- while ((fname[j] == path_part[i][j]
-- # if defined(MSWIN)
-- || (vim_ispathsep(fname[j]) && vim_ispathsep(path_part[i][j]))
-- #endif
-- ) && fname[j] != NUL && path_part[i][j] != NUL)
-- j++;
-- if (j > maxlen)
-- {
-- maxlen = j;
-- cutoff = &fname[j];
-- }
-- }
--
-- /* skip to the file or directory name */
-- if (cutoff != NULL)
-- while (vim_ispathsep(*cutoff))
-- MB_PTR_ADV(cutoff);
--
-- return cutoff;
-- }
--
-- /*
-- * Sorts, removes duplicates and modifies all the fullpath names in "gap" so
-- * that they are unique with respect to each other while conserving the part
-- * that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len".
-- */
-- static void
-- uniquefy_paths(garray_T *gap, char_u *pattern)
-- {
-- int i;
-- int len;
-- char_u **fnames = (char_u **)gap->ga_data;
-- int sort_again = FALSE;
-- char_u *pat;
-- char_u *file_pattern;
-- char_u *curdir;
-- regmatch_T regmatch;
-- garray_T path_ga;
-- char_u **in_curdir = NULL;
-- char_u *short_name;
--
-- remove_duplicates(gap);
-- ga_init2(&path_ga, (int)sizeof(char_u *), 1);
--
-- /*
-- * We need to prepend a '*' at the beginning of file_pattern so that the
-- * regex matches anywhere in the path. FIXME: is this valid for all
-- * possible patterns?
-- */
-- len = (int)STRLEN(pattern);
-- file_pattern = alloc(len + 2);
-- if (file_pattern == NULL)
-- return;
-- file_pattern[0] = '*';
-- file_pattern[1] = NUL;
-- STRCAT(file_pattern, pattern);
-- pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE);
-- vim_free(file_pattern);
-- if (pat == NULL)
-- return;
--
-- regmatch.rm_ic = TRUE; /* always ignore case */
-- regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
-- vim_free(pat);
-- if (regmatch.regprog == NULL)
-- return;
--
-- if ((curdir = alloc((int)(MAXPATHL))) == NULL)
-- goto theend;
-- mch_dirname(curdir, MAXPATHL);
-- expand_path_option(curdir, &path_ga);
--
-- in_curdir = (char_u **)alloc_clear(gap->ga_len * sizeof(char_u *));
-- if (in_curdir == NULL)
-- goto theend;
--
-- for (i = 0; i < gap->ga_len && !got_int; i++)
-- {
-- char_u *path = fnames[i];
-- int is_in_curdir;
-- char_u *dir_end = gettail_dir(path);
-- char_u *pathsep_p;
-- char_u *path_cutoff;
--
-- len = (int)STRLEN(path);
-- is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
-- && curdir[dir_end - path] == NUL;
-- if (is_in_curdir)
-- in_curdir[i] = vim_strsave(path);
--
-- /* Shorten the filename while maintaining its uniqueness */
-- path_cutoff = get_path_cutoff(path, &path_ga);
--
-- /* Don't assume all files can be reached without path when search
-- * pattern starts with star star slash, so only remove path_cutoff
-- * when possible. */
-- if (pattern[0] == '*' && pattern[1] == '*'
-- && vim_ispathsep_nocolon(pattern[2])
-- && path_cutoff != NULL
-- && vim_regexec(&regmatch, path_cutoff, (colnr_T)0)
-- && is_unique(path_cutoff, gap, i))
-- {
-- sort_again = TRUE;
-- mch_memmove(path, path_cutoff, STRLEN(path_cutoff) + 1);
-- }
-- else
-- {
-- /* Here all files can be reached without path, so get shortest
-- * unique path. We start at the end of the path. */
-- pathsep_p = path + len - 1;
--
-- while (find_previous_pathsep(path, &pathsep_p))
-- if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
-- && is_unique(pathsep_p + 1, gap, i)
-- && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
-- {
-- sort_again = TRUE;
-- mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
-- break;
-- }
-- }
--
-- if (mch_isFullName(path))
-- {
-- /*
-- * Last resort: shorten relative to curdir if possible.
-- * 'possible' means:
-- * 1. It is under the current directory.
-- * 2. The result is actually shorter than the original.
-- *
-- * Before curdir After
-- * /foo/bar/file.txt /foo/bar ./file.txt
-- * c:\foo\bar\file.txt c:\foo\bar .\file.txt
-- * /file.txt / /file.txt
-- * c:\file.txt c:\ .\file.txt
-- */
-- short_name = shorten_fname(path, curdir);
-- if (short_name != NULL && short_name > path + 1
-- #if defined(MSWIN)
-- /* On windows,
-- * shorten_fname("c:\a\a.txt", "c:\a\b")
-- * returns "\a\a.txt", which is not really the short
-- * name, hence: */
-- && !vim_ispathsep(*short_name)
-- #endif
-- )
-- {
-- STRCPY(path, ".");
-- add_pathsep(path);
-- STRMOVE(path + STRLEN(path), short_name);
-- }
-- }
-- ui_breakcheck();
-- }
--
-- /* Shorten filenames in /in/current/directory/{filename} */
-- for (i = 0; i < gap->ga_len && !got_int; i++)
-- {
-- char_u *rel_path;
-- char_u *path = in_curdir[i];
--
-- if (path == NULL)
-- continue;
--
-- /* If the {filename} is not unique, change it to ./{filename}.
-- * Else reduce it to {filename} */
-- short_name = shorten_fname(path, curdir);
-- if (short_name == NULL)
-- short_name = path;
-- if (is_unique(short_name, gap, i))
-- {
-- STRCPY(fnames[i], short_name);
-- continue;
-- }
--
-- rel_path = alloc((int)(STRLEN(short_name) + STRLEN(PATHSEPSTR) + 2));
-- if (rel_path == NULL)
-- goto theend;
-- STRCPY(rel_path, ".");
-- add_pathsep(rel_path);
-- STRCAT(rel_path, short_name);
--
-- vim_free(fnames[i]);
-- fnames[i] = rel_path;
-- sort_again = TRUE;
-- ui_breakcheck();
-- }
--
-- theend:
-- vim_free(curdir);
-- if (in_curdir != NULL)
-- {
-- for (i = 0; i < gap->ga_len; i++)
-- vim_free(in_curdir[i]);
-- vim_free(in_curdir);
-- }
-- ga_clear_strings(&path_ga);
-- vim_regfree(regmatch.regprog);
--
-- if (sort_again)
-- remove_duplicates(gap);
-- }
--
-- /*
-- * Calls globpath() with 'path' values for the given pattern and stores the
-- * result in "gap".
-- * Returns the total number of matches.
-- */
-- static int
-- expand_in_path(
-- garray_T *gap,
-- char_u *pattern,
-- int flags) /* EW_* flags */
-- {
-- char_u *curdir;
-- garray_T path_ga;
-- char_u *paths = NULL;
-- int glob_flags = 0;
--
-- if ((curdir = alloc((unsigned)MAXPATHL)) == NULL)
-- return 0;
-- mch_dirname(curdir, MAXPATHL);
--
-- ga_init2(&path_ga, (int)sizeof(char_u *), 1);
-- expand_path_option(curdir, &path_ga);
-- vim_free(curdir);
-- if (path_ga.ga_len == 0)
-- return 0;
--
-- paths = ga_concat_strings(&path_ga, ",");
-- ga_clear_strings(&path_ga);
-- if (paths == NULL)
-- return 0;
--
-- if (flags & EW_ICASE)
-- glob_flags |= WILD_ICASE;
-- if (flags & EW_ADDSLASH)
-- glob_flags |= WILD_ADD_SLASH;
-- globpath(paths, pattern, gap, glob_flags);
-- vim_free(paths);
--
-- return gap->ga_len;
-- }
-- #endif
--
- #if defined(FEAT_SEARCHPATH) || defined(FEAT_CMDL_COMPL) || defined(PROTO)
- /*
- * Sort "gap" and remove duplicate entries. "gap" is expected to contain a
---- 6134,6139 ----
-***************
-*** 7120,7122 ****
---- 6670,6744 ----
- #endif
- return p;
- }
-+
-+ /*
-+ * Check if the "://" of a URL is at the pointer, return URL_SLASH.
-+ * Also check for ":\\", which MS Internet Explorer accepts, return
-+ * URL_BACKSLASH.
-+ */
-+ int
-+ path_is_url(char_u *p)
-+ {
-+ if (STRNCMP(p, "://", (size_t)3) == 0)
-+ return URL_SLASH;
-+ else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
-+ return URL_BACKSLASH;
-+ return 0;
-+ }
-+
-+ /*
-+ * Check if "fname" starts with "name://". Return URL_SLASH if it does.
-+ * Return URL_BACKSLASH for "name:\\".
-+ * Return zero otherwise.
-+ */
-+ int
-+ path_with_url(char_u *fname)
-+ {
-+ char_u *p;
-+
-+ for (p = fname; isalpha(*p); ++p)
-+ ;
-+ return path_is_url(p);
-+ }
-+
-+ /*
-+ * Return TRUE if "name" is a full (absolute) path name or URL.
-+ */
-+ int
-+ vim_isAbsName(char_u *name)
-+ {
-+ return (path_with_url(name) != 0 || mch_isFullName(name));
-+ }
-+
-+ /*
-+ * Get absolute file name into buffer "buf[len]".
-+ *
-+ * return FAIL for failure, OK otherwise
-+ */
-+ int
-+ vim_FullName(
-+ char_u *fname,
-+ char_u *buf,
-+ int len,
-+ int force) /* force expansion even when already absolute */
-+ {
-+ int retval = OK;
-+ int url;
-+
-+ *buf = NUL;
-+ if (fname == NULL)
-+ return FAIL;
-+
-+ url = path_with_url(fname);
-+ if (!url)
-+ retval = mch_FullName(fname, buf, len, force);
-+ if (url || retval == FAIL)
-+ {
-+ /* something failed; use the file name (truncate when too long) */
-+ vim_strncpy(buf, fname, len - 1);
-+ }
-+ #if defined(MSWIN)
-+ slash_adjust(buf);
-+ #endif
-+ return retval;
-+ }
-*** ../vim-8.1.0913/src/misc2.c 2019-01-31 18:26:05.734803539 +0100
---- src/misc2.c 2019-02-13 22:06:27.641777652 +0100
-***************
-*** 14,21 ****
-
- static char_u *username = NULL; /* cached result of mch_get_user_name() */
-
-- static char_u *ff_expand_buffer = NULL; /* used for expanding filenames */
--
- static int coladvance2(pos_T *pos, int addspaces, int finetune, colnr_T wcol);
-
- /*
---- 14,19 ----
-***************
-*** 1047,1056 ****
-
- #if defined(EXITFREE) || defined(PROTO)
-
-- # if defined(FEAT_SEARCHPATH)
-- static void free_findfile(void);
-- # endif
--
- /*
- * Free everything that we allocated.
- * Can be used to detect memory leaks, e.g., with ccmalloc.
---- 1045,1050 ----
-***************
-*** 1161,1167 ****
- vim_free(new_last_cmdline);
- # endif
- set_keep_msg(NULL, 0);
-- vim_free(ff_expand_buffer);
-
- /* Clear cmdline history. */
- p_hi = 0;
---- 1155,1160 ----
-***************
-*** 3822,5746 ****
- #endif /* CURSOR_SHAPE */
-
-
-- /* TODO: make some #ifdef for this */
-- /*--------[ file searching ]-------------------------------------------------*/
-- /*
-- * File searching functions for 'path', 'tags' and 'cdpath' options.
-- * External visible functions:
-- * vim_findfile_init() creates/initialises the search context
-- * vim_findfile_free_visited() free list of visited files/dirs of search
-- * context
-- * vim_findfile() find a file in the search context
-- * vim_findfile_cleanup() cleanup/free search context created by
-- * vim_findfile_init()
-- *
-- * All static functions and variables start with 'ff_'
-- *
-- * In general it works like this:
-- * First you create yourself a search context by calling vim_findfile_init().
-- * It is possible to give a search context from a previous call to
-- * vim_findfile_init(), so it can be reused. After this you call vim_findfile()
-- * until you are satisfied with the result or it returns NULL. On every call it
-- * returns the next file which matches the conditions given to
-- * vim_findfile_init(). If it doesn't find a next file it returns NULL.
-- *
-- * It is possible to call vim_findfile_init() again to reinitialise your search
-- * with some new parameters. Don't forget to pass your old search context to
-- * it, so it can reuse it and especially reuse the list of already visited
-- * directories. If you want to delete the list of already visited directories
-- * simply call vim_findfile_free_visited().
-- *
-- * When you are done call vim_findfile_cleanup() to free the search context.
-- *
-- * The function vim_findfile_init() has a long comment, which describes the
-- * needed parameters.
-- *
-- *
-- *
-- * ATTENTION:
-- * ==========
-- * Also we use an allocated search context here, this functions are NOT
-- * thread-safe!!!!!
-- *
-- * To minimize parameter passing (or because I'm to lazy), only the
-- * external visible functions get a search context as a parameter. This is
-- * then assigned to a static global, which is used throughout the local
-- * functions.
-- */
--
-- /*
-- * type for the directory search stack
-- */
-- typedef struct ff_stack
-- {
-- struct ff_stack *ffs_prev;
--
-- /* the fix part (no wildcards) and the part containing the wildcards
-- * of the search path
-- */
-- char_u *ffs_fix_path;
-- #ifdef FEAT_PATH_EXTRA
-- char_u *ffs_wc_path;
-- #endif
--
-- /* files/dirs found in the above directory, matched by the first wildcard
-- * of wc_part
-- */
-- char_u **ffs_filearray;
-- int ffs_filearray_size;
-- char_u ffs_filearray_cur; /* needed for partly handled dirs */
--
-- /* to store status of partly handled directories
-- * 0: we work on this directory for the first time
-- * 1: this directory was partly searched in an earlier step
-- */
-- int ffs_stage;
--
-- /* How deep are we in the directory tree?
-- * Counts backward from value of level parameter to vim_findfile_init
-- */
-- int ffs_level;
--
-- /* Did we already expand '**' to an empty string? */
-- int ffs_star_star_empty;
-- } ff_stack_T;
--
-- /*
-- * type for already visited directories or files.
-- */
-- typedef struct ff_visited
-- {
-- struct ff_visited *ffv_next;
--
-- #ifdef FEAT_PATH_EXTRA
-- /* Visited directories are different if the wildcard string are
-- * different. So we have to save it.
-- */
-- char_u *ffv_wc_path;
-- #endif
-- /* for unix use inode etc for comparison (needed because of links), else
-- * use filename.
-- */
-- #ifdef UNIX
-- int ffv_dev_valid; /* ffv_dev and ffv_ino were set */
-- dev_t ffv_dev; /* device number */
-- ino_t ffv_ino; /* inode number */
-- #endif
-- /* The memory for this struct is allocated according to the length of
-- * ffv_fname.
-- */
-- char_u ffv_fname[1]; /* actually longer */
-- } ff_visited_T;
--
-- /*
-- * We might have to manage several visited lists during a search.
-- * This is especially needed for the tags option. If tags is set to:
-- * "./++/tags,./++/TAGS,++/tags" (replace + with *)
-- * So we have to do 3 searches:
-- * 1) search from the current files directory downward for the file "tags"
-- * 2) search from the current files directory downward for the file "TAGS"
-- * 3) search from Vims current directory downwards for the file "tags"
-- * As you can see, the first and the third search are for the same file, so for
-- * the third search we can use the visited list of the first search. For the
-- * second search we must start from a empty visited list.
-- * The struct ff_visited_list_hdr is used to manage a linked list of already
-- * visited lists.
-- */
-- typedef struct ff_visited_list_hdr
-- {
-- struct ff_visited_list_hdr *ffvl_next;
--
-- /* the filename the attached visited list is for */
-- char_u *ffvl_filename;
--
-- ff_visited_T *ffvl_visited_list;
--
-- } ff_visited_list_hdr_T;
--
--
-- /*
-- * '**' can be expanded to several directory levels.
-- * Set the default maximum depth.
-- */
-- #define FF_MAX_STAR_STAR_EXPAND ((char_u)30)
--
-- /*
-- * The search context:
-- * ffsc_stack_ptr: the stack for the dirs to search
-- * ffsc_visited_list: the currently active visited list
-- * ffsc_dir_visited_list: the currently active visited list for search dirs
-- * ffsc_visited_lists_list: the list of all visited lists
-- * ffsc_dir_visited_lists_list: the list of all visited lists for search dirs
-- * ffsc_file_to_search: the file to search for
-- * ffsc_start_dir: the starting directory, if search path was relative
-- * ffsc_fix_path: the fix part of the given path (without wildcards)
-- * Needed for upward search.
-- * ffsc_wc_path: the part of the given path containing wildcards
-- * ffsc_level: how many levels of dirs to search downwards
-- * ffsc_stopdirs_v: array of stop directories for upward search
-- * ffsc_find_what: FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE
-- * ffsc_tagfile: searching for tags file, don't use 'suffixesadd'
-- */
-- typedef struct ff_search_ctx_T
-- {
-- ff_stack_T *ffsc_stack_ptr;
-- ff_visited_list_hdr_T *ffsc_visited_list;
-- ff_visited_list_hdr_T *ffsc_dir_visited_list;
-- ff_visited_list_hdr_T *ffsc_visited_lists_list;
-- ff_visited_list_hdr_T *ffsc_dir_visited_lists_list;
-- char_u *ffsc_file_to_search;
-- char_u *ffsc_start_dir;
-- char_u *ffsc_fix_path;
-- #ifdef FEAT_PATH_EXTRA
-- char_u *ffsc_wc_path;
-- int ffsc_level;
-- char_u **ffsc_stopdirs_v;
-- #endif
-- int ffsc_find_what;
-- int ffsc_tagfile;
-- } ff_search_ctx_T;
--
-- /* locally needed functions */
-- #ifdef FEAT_PATH_EXTRA
-- static int ff_check_visited(ff_visited_T **, char_u *, char_u *);
-- #else
-- static int ff_check_visited(ff_visited_T **, char_u *);
-- #endif
-- static void vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp);
-- static void ff_free_visited_list(ff_visited_T *vl);
-- static ff_visited_list_hdr_T* ff_get_visited_list(char_u *, ff_visited_list_hdr_T **list_headp);
--
-- static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr);
-- static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx);
-- static void ff_clear(ff_search_ctx_T *search_ctx);
-- static void ff_free_stack_element(ff_stack_T *stack_ptr);
-- #ifdef FEAT_PATH_EXTRA
-- static ff_stack_T *ff_create_stack_element(char_u *, char_u *, int, int);
-- #else
-- static ff_stack_T *ff_create_stack_element(char_u *, int, int);
-- #endif
-- #ifdef FEAT_PATH_EXTRA
-- static int ff_path_in_stoplist(char_u *, int, char_u **);
-- #endif
--
-- static char_u e_pathtoolong[] = N_("E854: path too long for completion");
--
-- #if 0
-- /*
-- * if someone likes findfirst/findnext, here are the functions
-- * NOT TESTED!!
-- */
--
-- static void *ff_fn_search_context = NULL;
--
-- char_u *
-- vim_findfirst(char_u *path, char_u *filename, int level)
-- {
-- ff_fn_search_context =
-- vim_findfile_init(path, filename, NULL, level, TRUE, FALSE,
-- ff_fn_search_context, rel_fname);
-- if (NULL == ff_fn_search_context)
-- return NULL;
-- else
-- return vim_findnext()
-- }
--
-- char_u *
-- vim_findnext(void)
-- {
-- char_u *ret = vim_findfile(ff_fn_search_context);
--
-- if (NULL == ret)
-- {
-- vim_findfile_cleanup(ff_fn_search_context);
-- ff_fn_search_context = NULL;
-- }
-- return ret;
-- }
-- #endif
--
-- /*
-- * Initialization routine for vim_findfile().
-- *
-- * Returns the newly allocated search context or NULL if an error occurred.
-- *
-- * Don't forget to clean up by calling vim_findfile_cleanup() if you are done
-- * with the search context.
-- *
-- * Find the file 'filename' in the directory 'path'.
-- * The parameter 'path' may contain wildcards. If so only search 'level'
-- * directories deep. The parameter 'level' is the absolute maximum and is
-- * not related to restricts given to the '**' wildcard. If 'level' is 100
-- * and you use '**200' vim_findfile() will stop after 100 levels.
-- *
-- * 'filename' cannot contain wildcards! It is used as-is, no backslashes to
-- * escape special characters.
-- *
-- * If 'stopdirs' is not NULL and nothing is found downward, the search is
-- * restarted on the next higher directory level. This is repeated until the
-- * start-directory of a search is contained in 'stopdirs'. 'stopdirs' has the
-- * format ";*<dirname>*\(;<dirname>\)*;\=$".
-- *
-- * If the 'path' is relative, the starting dir for the search is either VIM's
-- * current dir or if the path starts with "./" the current files dir.
-- * If the 'path' is absolute, the starting dir is that part of the path before
-- * the first wildcard.
-- *
-- * Upward search is only done on the starting dir.
-- *
-- * If 'free_visited' is TRUE the list of already visited files/directories is
-- * cleared. Set this to FALSE if you just want to search from another
-- * directory, but want to be sure that no directory from a previous search is
-- * searched again. This is useful if you search for a file at different places.
-- * The list of visited files/dirs can also be cleared with the function
-- * vim_findfile_free_visited().
-- *
-- * Set the parameter 'find_what' to FINDFILE_DIR if you want to search for
-- * directories only, FINDFILE_FILE for files only, FINDFILE_BOTH for both.
-- *
-- * A search context returned by a previous call to vim_findfile_init() can be
-- * passed in the parameter "search_ctx_arg". This context is reused and
-- * reinitialized with the new parameters. The list of already visited
-- * directories from this context is only deleted if the parameter
-- * "free_visited" is true. Be aware that the passed "search_ctx_arg" is freed
-- * if the reinitialization fails.
-- *
-- * If you don't have a search context from a previous call "search_ctx_arg"
-- * must be NULL.
-- *
-- * This function silently ignores a few errors, vim_findfile() will have
-- * limited functionality then.
-- */
-- void *
-- vim_findfile_init(
-- char_u *path,
-- char_u *filename,
-- char_u *stopdirs UNUSED,
-- int level,
-- int free_visited,
-- int find_what,
-- void *search_ctx_arg,
-- int tagfile, /* expanding names of tags files */
-- char_u *rel_fname) /* file name to use for "." */
-- {
-- #ifdef FEAT_PATH_EXTRA
-- char_u *wc_part;
-- #endif
-- ff_stack_T *sptr;
-- ff_search_ctx_T *search_ctx;
--
-- /* If a search context is given by the caller, reuse it, else allocate a
-- * new one.
-- */
-- if (search_ctx_arg != NULL)
-- search_ctx = search_ctx_arg;
-- else
-- {
-- search_ctx = (ff_search_ctx_T*)alloc((unsigned)sizeof(ff_search_ctx_T));
-- if (search_ctx == NULL)
-- goto error_return;
-- vim_memset(search_ctx, 0, sizeof(ff_search_ctx_T));
-- }
-- search_ctx->ffsc_find_what = find_what;
-- search_ctx->ffsc_tagfile = tagfile;
--
-- /* clear the search context, but NOT the visited lists */
-- ff_clear(search_ctx);
--
-- /* clear visited list if wanted */
-- if (free_visited == TRUE)
-- vim_findfile_free_visited(search_ctx);
-- else
-- {
-- /* Reuse old visited lists. Get the visited list for the given
-- * filename. If no list for the current filename exists, creates a new
-- * one. */
-- search_ctx->ffsc_visited_list = ff_get_visited_list(filename,
-- &search_ctx->ffsc_visited_lists_list);
-- if (search_ctx->ffsc_visited_list == NULL)
-- goto error_return;
-- search_ctx->ffsc_dir_visited_list = ff_get_visited_list(filename,
-- &search_ctx->ffsc_dir_visited_lists_list);
-- if (search_ctx->ffsc_dir_visited_list == NULL)
-- goto error_return;
-- }
--
-- if (ff_expand_buffer == NULL)
-- {
-- ff_expand_buffer = (char_u*)alloc(MAXPATHL);
-- if (ff_expand_buffer == NULL)
-- goto error_return;
-- }
--
-- /* Store information on starting dir now if path is relative.
-- * If path is absolute, we do that later. */
-- if (path[0] == '.'
-- && (vim_ispathsep(path[1]) || path[1] == NUL)
-- && (!tagfile || vim_strchr(p_cpo, CPO_DOTTAG) == NULL)
-- && rel_fname != NULL)
-- {
-- int len = (int)(gettail(rel_fname) - rel_fname);
--
-- if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL)
-- {
-- /* Make the start dir an absolute path name. */
-- vim_strncpy(ff_expand_buffer, rel_fname, len);
-- search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, FALSE);
-- }
-- else
-- search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len);
-- if (search_ctx->ffsc_start_dir == NULL)
-- goto error_return;
-- if (*++path != NUL)
-- ++path;
-- }
-- else if (*path == NUL || !vim_isAbsName(path))
-- {
-- #ifdef BACKSLASH_IN_FILENAME
-- /* "c:dir" needs "c:" to be expanded, otherwise use current dir */
-- if (*path != NUL && path[1] == ':')
-- {
-- char_u drive[3];
--
-- drive[0] = path[0];
-- drive[1] = ':';
-- drive[2] = NUL;
-- if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
-- goto error_return;
-- path += 2;
-- }
-- else
-- #endif
-- if (mch_dirname(ff_expand_buffer, MAXPATHL) == FAIL)
-- goto error_return;
--
-- search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer);
-- if (search_ctx->ffsc_start_dir == NULL)
-- goto error_return;
--
-- #ifdef BACKSLASH_IN_FILENAME
-- /* A path that starts with "/dir" is relative to the drive, not to the
-- * directory (but not for "//machine/dir"). Only use the drive name. */
-- if ((*path == '/' || *path == '\\')
-- && path[1] != path[0]
-- && search_ctx->ffsc_start_dir[1] == ':')
-- search_ctx->ffsc_start_dir[2] = NUL;
-- #endif
-- }
--
-- #ifdef FEAT_PATH_EXTRA
-- /*
-- * If stopdirs are given, split them into an array of pointers.
-- * If this fails (mem allocation), there is no upward search at all or a
-- * stop directory is not recognized -> continue silently.
-- * If stopdirs just contains a ";" or is empty,
-- * search_ctx->ffsc_stopdirs_v will only contain a NULL pointer. This
-- * is handled as unlimited upward search. See function
-- * ff_path_in_stoplist() for details.
-- */
-- if (stopdirs != NULL)
-- {
-- char_u *walker = stopdirs;
-- int dircount;
--
-- while (*walker == ';')
-- walker++;
--
-- dircount = 1;
-- search_ctx->ffsc_stopdirs_v =
-- (char_u **)alloc((unsigned)sizeof(char_u *));
--
-- if (search_ctx->ffsc_stopdirs_v != NULL)
-- {
-- do
-- {
-- char_u *helper;
-- void *ptr;
--
-- helper = walker;
-- ptr = vim_realloc(search_ctx->ffsc_stopdirs_v,
-- (dircount + 1) * sizeof(char_u *));
-- if (ptr)
-- search_ctx->ffsc_stopdirs_v = ptr;
-- else
-- /* ignore, keep what we have and continue */
-- break;
-- walker = vim_strchr(walker, ';');
-- if (walker)
-- {
-- search_ctx->ffsc_stopdirs_v[dircount-1] =
-- vim_strnsave(helper, (int)(walker - helper));
-- walker++;
-- }
-- else
-- /* this might be "", which means ascent till top
-- * of directory tree.
-- */
-- search_ctx->ffsc_stopdirs_v[dircount-1] =
-- vim_strsave(helper);
--
-- dircount++;
--
-- } while (walker != NULL);
-- search_ctx->ffsc_stopdirs_v[dircount-1] = NULL;
-- }
-- }
-- #endif
--
-- #ifdef FEAT_PATH_EXTRA
-- search_ctx->ffsc_level = level;
--
-- /* split into:
-- * -fix path
-- * -wildcard_stuff (might be NULL)
-- */
-- wc_part = vim_strchr(path, '*');
-- if (wc_part != NULL)
-- {
-- int llevel;
-- int len;
-- char *errpt;
--
-- /* save the fix part of the path */
-- search_ctx->ffsc_fix_path = vim_strnsave(path, (int)(wc_part - path));
--
-- /*
-- * copy wc_path and add restricts to the '**' wildcard.
-- * The octet after a '**' is used as a (binary) counter.
-- * So '**3' is transposed to '**^C' ('^C' is ASCII value 3)
-- * or '**76' is transposed to '**N'( 'N' is ASCII value 76).
-- * For EBCDIC you get different character values.
-- * If no restrict is given after '**' the default is used.
-- * Due to this technique the path looks awful if you print it as a
-- * string.
-- */
-- len = 0;
-- while (*wc_part != NUL)
-- {
-- if (len + 5 >= MAXPATHL)
-- {
-- emsg(_(e_pathtoolong));
-- break;
-- }
-- if (STRNCMP(wc_part, "**", 2) == 0)
-- {
-- ff_expand_buffer[len++] = *wc_part++;
-- ff_expand_buffer[len++] = *wc_part++;
--
-- llevel = strtol((char *)wc_part, &errpt, 10);
-- if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255)
-- ff_expand_buffer[len++] = llevel;
-- else if ((char_u *)errpt != wc_part && llevel == 0)
-- /* restrict is 0 -> remove already added '**' */
-- len -= 2;
-- else
-- ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND;
-- wc_part = (char_u *)errpt;
-- if (*wc_part != NUL && !vim_ispathsep(*wc_part))
-- {
-- semsg(_("E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."), PATHSEPSTR);
-- goto error_return;
-- }
-- }
-- else
-- ff_expand_buffer[len++] = *wc_part++;
-- }
-- ff_expand_buffer[len] = NUL;
-- search_ctx->ffsc_wc_path = vim_strsave(ff_expand_buffer);
--
-- if (search_ctx->ffsc_wc_path == NULL)
-- goto error_return;
-- }
-- else
-- #endif
-- search_ctx->ffsc_fix_path = vim_strsave(path);
--
-- if (search_ctx->ffsc_start_dir == NULL)
-- {
-- /* store the fix part as startdir.
-- * This is needed if the parameter path is fully qualified.
-- */
-- search_ctx->ffsc_start_dir = vim_strsave(search_ctx->ffsc_fix_path);
-- if (search_ctx->ffsc_start_dir == NULL)
-- goto error_return;
-- search_ctx->ffsc_fix_path[0] = NUL;
-- }
--
-- /* create an absolute path */
-- if (STRLEN(search_ctx->ffsc_start_dir)
-- + STRLEN(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL)
-- {
-- emsg(_(e_pathtoolong));
-- goto error_return;
-- }
-- STRCPY(ff_expand_buffer, search_ctx->ffsc_start_dir);
-- add_pathsep(ff_expand_buffer);
-- {
-- int eb_len = (int)STRLEN(ff_expand_buffer);
-- char_u *buf = alloc(eb_len
-- + (int)STRLEN(search_ctx->ffsc_fix_path) + 1);
--
-- STRCPY(buf, ff_expand_buffer);
-- STRCPY(buf + eb_len, search_ctx->ffsc_fix_path);
-- if (mch_isdir(buf))
-- {
-- STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path);
-- add_pathsep(ff_expand_buffer);
-- }
-- #ifdef FEAT_PATH_EXTRA
-- else
-- {
-- char_u *p = gettail(search_ctx->ffsc_fix_path);
-- char_u *wc_path = NULL;
-- char_u *temp = NULL;
-- int len = 0;
--
-- if (p > search_ctx->ffsc_fix_path)
-- {
-- len = (int)(p - search_ctx->ffsc_fix_path) - 1;
-- STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len);
-- add_pathsep(ff_expand_buffer);
-- }
-- else
-- len = (int)STRLEN(search_ctx->ffsc_fix_path);
--
-- if (search_ctx->ffsc_wc_path != NULL)
-- {
-- wc_path = vim_strsave(search_ctx->ffsc_wc_path);
-- temp = alloc((int)(STRLEN(search_ctx->ffsc_wc_path)
-- + STRLEN(search_ctx->ffsc_fix_path + len)
-- + 1));
-- if (temp == NULL || wc_path == NULL)
-- {
-- vim_free(buf);
-- vim_free(temp);
-- vim_free(wc_path);
-- goto error_return;
-- }
--
-- STRCPY(temp, search_ctx->ffsc_fix_path + len);
-- STRCAT(temp, search_ctx->ffsc_wc_path);
-- vim_free(search_ctx->ffsc_wc_path);
-- vim_free(wc_path);
-- search_ctx->ffsc_wc_path = temp;
-- }
-- }
-- #endif
-- vim_free(buf);
-- }
--
-- sptr = ff_create_stack_element(ff_expand_buffer,
-- #ifdef FEAT_PATH_EXTRA
-- search_ctx->ffsc_wc_path,
-- #endif
-- level, 0);
--
-- if (sptr == NULL)
-- goto error_return;
--
-- ff_push(search_ctx, sptr);
--
-- search_ctx->ffsc_file_to_search = vim_strsave(filename);
-- if (search_ctx->ffsc_file_to_search == NULL)
-- goto error_return;
--
-- return search_ctx;
--
-- error_return:
-- /*
-- * We clear the search context now!
-- * Even when the caller gave us a (perhaps valid) context we free it here,
-- * as we might have already destroyed it.
-- */
-- vim_findfile_cleanup(search_ctx);
-- return NULL;
-- }
--
-- #if defined(FEAT_PATH_EXTRA) || defined(PROTO)
-- /*
-- * Get the stopdir string. Check that ';' is not escaped.
-- */
-- char_u *
-- vim_findfile_stopdir(char_u *buf)
-- {
-- char_u *r_ptr = buf;
--
-- while (*r_ptr != NUL && *r_ptr != ';')
-- {
-- if (r_ptr[0] == '\\' && r_ptr[1] == ';')
-- {
-- /* Overwrite the escape char,
-- * use STRLEN(r_ptr) to move the trailing '\0'. */
-- STRMOVE(r_ptr, r_ptr + 1);
-- r_ptr++;
-- }
-- r_ptr++;
-- }
-- if (*r_ptr == ';')
-- {
-- *r_ptr = 0;
-- r_ptr++;
-- }
-- else if (*r_ptr == NUL)
-- r_ptr = NULL;
-- return r_ptr;
-- }
-- #endif
--
-- /*
-- * Clean up the given search context. Can handle a NULL pointer.
-- */
-- void
-- vim_findfile_cleanup(void *ctx)
-- {
-- if (ctx == NULL)
-- return;
--
-- vim_findfile_free_visited(ctx);
-- ff_clear(ctx);
-- vim_free(ctx);
-- }
--
-- /*
-- * Find a file in a search context.
-- * The search context was created with vim_findfile_init() above.
-- * Return a pointer to an allocated file name or NULL if nothing found.
-- * To get all matching files call this function until you get NULL.
-- *
-- * If the passed search_context is NULL, NULL is returned.
-- *
-- * The search algorithm is depth first. To change this replace the
-- * stack with a list (don't forget to leave partly searched directories on the
-- * top of the list).
-- */
-- char_u *
-- vim_findfile(void *search_ctx_arg)
-- {
-- char_u *file_path;
-- #ifdef FEAT_PATH_EXTRA
-- char_u *rest_of_wildcards;
-- char_u *path_end = NULL;
-- #endif
-- ff_stack_T *stackp;
-- #if defined(FEAT_SEARCHPATH) || defined(FEAT_PATH_EXTRA)
-- int len;
-- #endif
-- int i;
-- char_u *p;
-- #ifdef FEAT_SEARCHPATH
-- char_u *suf;
-- #endif
-- ff_search_ctx_T *search_ctx;
--
-- if (search_ctx_arg == NULL)
-- return NULL;
--
-- search_ctx = (ff_search_ctx_T *)search_ctx_arg;
--
-- /*
-- * filepath is used as buffer for various actions and as the storage to
-- * return a found filename.
-- */
-- if ((file_path = alloc((int)MAXPATHL)) == NULL)
-- return NULL;
--
-- #ifdef FEAT_PATH_EXTRA
-- /* store the end of the start dir -- needed for upward search */
-- if (search_ctx->ffsc_start_dir != NULL)
-- path_end = &search_ctx->ffsc_start_dir[
-- STRLEN(search_ctx->ffsc_start_dir)];
-- #endif
--
-- #ifdef FEAT_PATH_EXTRA
-- /* upward search loop */
-- for (;;)
-- {
-- #endif
-- /* downward search loop */
-- for (;;)
-- {
-- /* check if user user wants to stop the search*/
-- ui_breakcheck();
-- if (got_int)
-- break;
--
-- /* get directory to work on from stack */
-- stackp = ff_pop(search_ctx);
-- if (stackp == NULL)
-- break;
--
-- /*
-- * TODO: decide if we leave this test in
-- *
-- * GOOD: don't search a directory(-tree) twice.
-- * BAD: - check linked list for every new directory entered.
-- * - check for double files also done below
-- *
-- * Here we check if we already searched this directory.
-- * We already searched a directory if:
-- * 1) The directory is the same.
-- * 2) We would use the same wildcard string.
-- *
-- * Good if you have links on same directory via several ways
-- * or you have selfreferences in directories (e.g. SuSE Linux 6.3:
-- * /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop)
-- *
-- * This check is only needed for directories we work on for the
-- * first time (hence stackp->ff_filearray == NULL)
-- */
-- if (stackp->ffs_filearray == NULL
-- && ff_check_visited(&search_ctx->ffsc_dir_visited_list
-- ->ffvl_visited_list,
-- stackp->ffs_fix_path
-- #ifdef FEAT_PATH_EXTRA
-- , stackp->ffs_wc_path
-- #endif
-- ) == FAIL)
-- {
-- #ifdef FF_VERBOSE
-- if (p_verbose >= 5)
-- {
-- verbose_enter_scroll();
-- smsg("Already Searched: %s (%s)",
-- stackp->ffs_fix_path, stackp->ffs_wc_path);
-- /* don't overwrite this either */
-- msg_puts("\n");
-- verbose_leave_scroll();
-- }
-- #endif
-- ff_free_stack_element(stackp);
-- continue;
-- }
-- #ifdef FF_VERBOSE
-- else if (p_verbose >= 5)
-- {
-- verbose_enter_scroll();
-- smsg("Searching: %s (%s)",
-- stackp->ffs_fix_path, stackp->ffs_wc_path);
-- /* don't overwrite this either */
-- msg_puts("\n");
-- verbose_leave_scroll();
-- }
-- #endif
--
-- /* check depth */
-- if (stackp->ffs_level <= 0)
-- {
-- ff_free_stack_element(stackp);
-- continue;
-- }
--
-- file_path[0] = NUL;
--
-- /*
-- * If no filearray till now expand wildcards
-- * The function expand_wildcards() can handle an array of paths
-- * and all possible expands are returned in one array. We use this
-- * to handle the expansion of '**' into an empty string.
-- */
-- if (stackp->ffs_filearray == NULL)
-- {
-- char_u *dirptrs[2];
--
-- /* we use filepath to build the path expand_wildcards() should
-- * expand.
-- */
-- dirptrs[0] = file_path;
-- dirptrs[1] = NULL;
--
-- /* if we have a start dir copy it in */
-- if (!vim_isAbsName(stackp->ffs_fix_path)
-- && search_ctx->ffsc_start_dir)
-- {
-- if (STRLEN(search_ctx->ffsc_start_dir) + 1 < MAXPATHL)
-- {
-- STRCPY(file_path, search_ctx->ffsc_start_dir);
-- add_pathsep(file_path);
-- }
-- else
-- {
-- ff_free_stack_element(stackp);
-- goto fail;
-- }
-- }
--
-- /* append the fix part of the search path */
-- if (STRLEN(file_path) + STRLEN(stackp->ffs_fix_path) + 1 < MAXPATHL)
-- {
-- STRCAT(file_path, stackp->ffs_fix_path);
-- add_pathsep(file_path);
-- }
-- else
-- {
-- ff_free_stack_element(stackp);
-- goto fail;
-- }
--
-- #ifdef FEAT_PATH_EXTRA
-- rest_of_wildcards = stackp->ffs_wc_path;
-- if (*rest_of_wildcards != NUL)
-- {
-- len = (int)STRLEN(file_path);
-- if (STRNCMP(rest_of_wildcards, "**", 2) == 0)
-- {
-- /* pointer to the restrict byte
-- * The restrict byte is not a character!
-- */
-- p = rest_of_wildcards + 2;
--
-- if (*p > 0)
-- {
-- (*p)--;
-- if (len + 1 < MAXPATHL)
-- file_path[len++] = '*';
-- else
-- {
-- ff_free_stack_element(stackp);
-- goto fail;
-- }
-- }
--
-- if (*p == 0)
-- {
-- /* remove '**<numb> from wildcards */
-- STRMOVE(rest_of_wildcards, rest_of_wildcards + 3);
-- }
-- else
-- rest_of_wildcards += 3;
--
-- if (stackp->ffs_star_star_empty == 0)
-- {
-- /* if not done before, expand '**' to empty */
-- stackp->ffs_star_star_empty = 1;
-- dirptrs[1] = stackp->ffs_fix_path;
-- }
-- }
--
-- /*
-- * Here we copy until the next path separator or the end of
-- * the path. If we stop at a path separator, there is
-- * still something else left. This is handled below by
-- * pushing every directory returned from expand_wildcards()
-- * on the stack again for further search.
-- */
-- while (*rest_of_wildcards
-- && !vim_ispathsep(*rest_of_wildcards))
-- if (len + 1 < MAXPATHL)
-- file_path[len++] = *rest_of_wildcards++;
-- else
-- {
-- ff_free_stack_element(stackp);
-- goto fail;
-- }
--
-- file_path[len] = NUL;
-- if (vim_ispathsep(*rest_of_wildcards))
-- rest_of_wildcards++;
-- }
-- #endif
--
-- /*
-- * Expand wildcards like "*" and "$VAR".
-- * If the path is a URL don't try this.
-- */
-- if (path_with_url(dirptrs[0]))
-- {
-- stackp->ffs_filearray = (char_u **)
-- alloc((unsigned)sizeof(char *));
-- if (stackp->ffs_filearray != NULL
-- && (stackp->ffs_filearray[0]
-- = vim_strsave(dirptrs[0])) != NULL)
-- stackp->ffs_filearray_size = 1;
-- else
-- stackp->ffs_filearray_size = 0;
-- }
-- else
-- /* Add EW_NOTWILD because the expanded path may contain
-- * wildcard characters that are to be taken literally.
-- * This is a bit of a hack. */
-- expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs,
-- &stackp->ffs_filearray_size,
-- &stackp->ffs_filearray,
-- EW_DIR|EW_ADDSLASH|EW_SILENT|EW_NOTWILD);
--
-- stackp->ffs_filearray_cur = 0;
-- stackp->ffs_stage = 0;
-- }
-- #ifdef FEAT_PATH_EXTRA
-- else
-- rest_of_wildcards = &stackp->ffs_wc_path[
-- STRLEN(stackp->ffs_wc_path)];
-- #endif
--
-- if (stackp->ffs_stage == 0)
-- {
-- /* this is the first time we work on this directory */
-- #ifdef FEAT_PATH_EXTRA
-- if (*rest_of_wildcards == NUL)
-- #endif
-- {
-- /*
-- * We don't have further wildcards to expand, so we have to
-- * check for the final file now.
-- */
-- for (i = stackp->ffs_filearray_cur;
-- i < stackp->ffs_filearray_size; ++i)
-- {
-- if (!path_with_url(stackp->ffs_filearray[i])
-- && !mch_isdir(stackp->ffs_filearray[i]))
-- continue; /* not a directory */
--
-- /* prepare the filename to be checked for existence
-- * below */
-- if (STRLEN(stackp->ffs_filearray[i]) + 1
-- + STRLEN(search_ctx->ffsc_file_to_search) < MAXPATHL)
-- {
-- STRCPY(file_path, stackp->ffs_filearray[i]);
-- add_pathsep(file_path);
-- STRCAT(file_path, search_ctx->ffsc_file_to_search);
-- }
-- else
-- {
-- ff_free_stack_element(stackp);
-- goto fail;
-- }
--
-- /*
-- * Try without extra suffix and then with suffixes
-- * from 'suffixesadd'.
-- */
-- #ifdef FEAT_SEARCHPATH
-- len = (int)STRLEN(file_path);
-- if (search_ctx->ffsc_tagfile)
-- suf = (char_u *)"";
-- else
-- suf = curbuf->b_p_sua;
-- for (;;)
-- #endif
-- {
-- /* if file exists and we didn't already find it */
-- if ((path_with_url(file_path)
-- || (mch_getperm(file_path) >= 0
-- && (search_ctx->ffsc_find_what
-- == FINDFILE_BOTH
-- || ((search_ctx->ffsc_find_what
-- == FINDFILE_DIR)
-- == mch_isdir(file_path)))))
-- #ifndef FF_VERBOSE
-- && (ff_check_visited(
-- &search_ctx->ffsc_visited_list->ffvl_visited_list,
-- file_path
-- #ifdef FEAT_PATH_EXTRA
-- , (char_u *)""
-- #endif
-- ) == OK)
-- #endif
-- )
-- {
-- #ifdef FF_VERBOSE
-- if (ff_check_visited(
-- &search_ctx->ffsc_visited_list->ffvl_visited_list,
-- file_path
-- #ifdef FEAT_PATH_EXTRA
-- , (char_u *)""
-- #endif
-- ) == FAIL)
-- {
-- if (p_verbose >= 5)
-- {
-- verbose_enter_scroll();
-- smsg("Already: %s",
-- file_path);
-- /* don't overwrite this either */
-- msg_puts("\n");
-- verbose_leave_scroll();
-- }
-- continue;
-- }
-- #endif
--
-- /* push dir to examine rest of subdirs later */
-- stackp->ffs_filearray_cur = i + 1;
-- ff_push(search_ctx, stackp);
--
-- if (!path_with_url(file_path))
-- simplify_filename(file_path);
-- if (mch_dirname(ff_expand_buffer, MAXPATHL)
-- == OK)
-- {
-- p = shorten_fname(file_path,
-- ff_expand_buffer);
-- if (p != NULL)
-- STRMOVE(file_path, p);
-- }
-- #ifdef FF_VERBOSE
-- if (p_verbose >= 5)
-- {
-- verbose_enter_scroll();
-- smsg("HIT: %s", file_path);
-- /* don't overwrite this either */
-- msg_puts("\n");
-- verbose_leave_scroll();
-- }
-- #endif
-- return file_path;
-- }
--
-- #ifdef FEAT_SEARCHPATH
-- /* Not found or found already, try next suffix. */
-- if (*suf == NUL)
-- break;
-- copy_option_part(&suf, file_path + len,
-- MAXPATHL - len, ",");
-- #endif
-- }
-- }
-- }
-- #ifdef FEAT_PATH_EXTRA
-- else
-- {
-- /*
-- * still wildcards left, push the directories for further
-- * search
-- */
-- for (i = stackp->ffs_filearray_cur;
-- i < stackp->ffs_filearray_size; ++i)
-- {
-- if (!mch_isdir(stackp->ffs_filearray[i]))
-- continue; /* not a directory */
--
-- ff_push(search_ctx,
-- ff_create_stack_element(
-- stackp->ffs_filearray[i],
-- rest_of_wildcards,
-- stackp->ffs_level - 1, 0));
-- }
-- }
-- #endif
-- stackp->ffs_filearray_cur = 0;
-- stackp->ffs_stage = 1;
-- }
--
-- #ifdef FEAT_PATH_EXTRA
-- /*
-- * if wildcards contains '**' we have to descent till we reach the
-- * leaves of the directory tree.
-- */
-- if (STRNCMP(stackp->ffs_wc_path, "**", 2) == 0)
-- {
-- for (i = stackp->ffs_filearray_cur;
-- i < stackp->ffs_filearray_size; ++i)
-- {
-- if (fnamecmp(stackp->ffs_filearray[i],
-- stackp->ffs_fix_path) == 0)
-- continue; /* don't repush same directory */
-- if (!mch_isdir(stackp->ffs_filearray[i]))
-- continue; /* not a directory */
-- ff_push(search_ctx,
-- ff_create_stack_element(stackp->ffs_filearray[i],
-- stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
-- }
-- }
-- #endif
--
-- /* we are done with the current directory */
-- ff_free_stack_element(stackp);
--
-- }
--
-- #ifdef FEAT_PATH_EXTRA
-- /* If we reached this, we didn't find anything downwards.
-- * Let's check if we should do an upward search.
-- */
-- if (search_ctx->ffsc_start_dir
-- && search_ctx->ffsc_stopdirs_v != NULL && !got_int)
-- {
-- ff_stack_T *sptr;
--
-- /* is the last starting directory in the stop list? */
-- if (ff_path_in_stoplist(search_ctx->ffsc_start_dir,
-- (int)(path_end - search_ctx->ffsc_start_dir),
-- search_ctx->ffsc_stopdirs_v) == TRUE)
-- break;
--
-- /* cut of last dir */
-- while (path_end > search_ctx->ffsc_start_dir
-- && vim_ispathsep(*path_end))
-- path_end--;
-- while (path_end > search_ctx->ffsc_start_dir
-- && !vim_ispathsep(path_end[-1]))
-- path_end--;
-- *path_end = 0;
-- path_end--;
--
-- if (*search_ctx->ffsc_start_dir == 0)
-- break;
--
-- if (STRLEN(search_ctx->ffsc_start_dir) + 1
-- + STRLEN(search_ctx->ffsc_fix_path) < MAXPATHL)
-- {
-- STRCPY(file_path, search_ctx->ffsc_start_dir);
-- add_pathsep(file_path);
-- STRCAT(file_path, search_ctx->ffsc_fix_path);
-- }
-- else
-- goto fail;
--
-- /* create a new stack entry */
-- sptr = ff_create_stack_element(file_path,
-- search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0);
-- if (sptr == NULL)
-- break;
-- ff_push(search_ctx, sptr);
-- }
-- else
-- break;
-- }
-- #endif
--
-- fail:
-- vim_free(file_path);
-- return NULL;
-- }
--
-- /*
-- * Free the list of lists of visited files and directories
-- * Can handle it if the passed search_context is NULL;
-- */
-- void
-- vim_findfile_free_visited(void *search_ctx_arg)
-- {
-- ff_search_ctx_T *search_ctx;
--
-- if (search_ctx_arg == NULL)
-- return;
--
-- search_ctx = (ff_search_ctx_T *)search_ctx_arg;
-- vim_findfile_free_visited_list(&search_ctx->ffsc_visited_lists_list);
-- vim_findfile_free_visited_list(&search_ctx->ffsc_dir_visited_lists_list);
-- }
--
-- static void
-- vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp)
-- {
-- ff_visited_list_hdr_T *vp;
--
-- while (*list_headp != NULL)
-- {
-- vp = (*list_headp)->ffvl_next;
-- ff_free_visited_list((*list_headp)->ffvl_visited_list);
--
-- vim_free((*list_headp)->ffvl_filename);
-- vim_free(*list_headp);
-- *list_headp = vp;
-- }
-- *list_headp = NULL;
-- }
--
-- static void
-- ff_free_visited_list(ff_visited_T *vl)
-- {
-- ff_visited_T *vp;
--
-- while (vl != NULL)
-- {
-- vp = vl->ffv_next;
-- #ifdef FEAT_PATH_EXTRA
-- vim_free(vl->ffv_wc_path);
-- #endif
-- vim_free(vl);
-- vl = vp;
-- }
-- vl = NULL;
-- }
--
-- /*
-- * Returns the already visited list for the given filename. If none is found it
-- * allocates a new one.
-- */
-- static ff_visited_list_hdr_T*
-- ff_get_visited_list(
-- char_u *filename,
-- ff_visited_list_hdr_T **list_headp)
-- {
-- ff_visited_list_hdr_T *retptr = NULL;
--
-- /* check if a visited list for the given filename exists */
-- if (*list_headp != NULL)
-- {
-- retptr = *list_headp;
-- while (retptr != NULL)
-- {
-- if (fnamecmp(filename, retptr->ffvl_filename) == 0)
-- {
-- #ifdef FF_VERBOSE
-- if (p_verbose >= 5)
-- {
-- verbose_enter_scroll();
-- smsg("ff_get_visited_list: FOUND list for %s",
-- filename);
-- /* don't overwrite this either */
-- msg_puts("\n");
-- verbose_leave_scroll();
-- }
-- #endif
-- return retptr;
-- }
-- retptr = retptr->ffvl_next;
-- }
-- }
--
-- #ifdef FF_VERBOSE
-- if (p_verbose >= 5)
-- {
-- verbose_enter_scroll();
-- smsg("ff_get_visited_list: new list for %s", filename);
-- /* don't overwrite this either */
-- msg_puts("\n");
-- verbose_leave_scroll();
-- }
-- #endif
--
-- /*
-- * if we reach this we didn't find a list and we have to allocate new list
-- */
-- retptr = (ff_visited_list_hdr_T*)alloc((unsigned)sizeof(*retptr));
-- if (retptr == NULL)
-- return NULL;
--
-- retptr->ffvl_visited_list = NULL;
-- retptr->ffvl_filename = vim_strsave(filename);
-- if (retptr->ffvl_filename == NULL)
-- {
-- vim_free(retptr);
-- return NULL;
-- }
-- retptr->ffvl_next = *list_headp;
-- *list_headp = retptr;
--
-- return retptr;
-- }
--
-- #ifdef FEAT_PATH_EXTRA
-- /*
-- * check if two wildcard paths are equal. Returns TRUE or FALSE.
-- * They are equal if:
-- * - both paths are NULL
-- * - they have the same length
-- * - char by char comparison is OK
-- * - the only differences are in the counters behind a '**', so
-- * '**\20' is equal to '**\24'
-- */
-- static int
-- ff_wc_equal(char_u *s1, char_u *s2)
-- {
-- int i, j;
-- int c1 = NUL;
-- int c2 = NUL;
-- int prev1 = NUL;
-- int prev2 = NUL;
--
-- if (s1 == s2)
-- return TRUE;
--
-- if (s1 == NULL || s2 == NULL)
-- return FALSE;
--
-- for (i = 0, j = 0; s1[i] != NUL && s2[j] != NUL;)
-- {
-- c1 = PTR2CHAR(s1 + i);
-- c2 = PTR2CHAR(s2 + j);
--
-- if ((p_fic ? MB_TOLOWER(c1) != MB_TOLOWER(c2) : c1 != c2)
-- && (prev1 != '*' || prev2 != '*'))
-- return FALSE;
-- prev2 = prev1;
-- prev1 = c1;
--
-- i += MB_PTR2LEN(s1 + i);
-- j += MB_PTR2LEN(s2 + j);
-- }
-- return s1[i] == s2[j];
-- }
-- #endif
--
-- /*
-- * maintains the list of already visited files and dirs
-- * returns FAIL if the given file/dir is already in the list
-- * returns OK if it is newly added
-- *
-- * TODO: What to do on memory allocation problems?
-- * -> return TRUE - Better the file is found several times instead of
-- * never.
-- */
-- static int
-- ff_check_visited(
-- ff_visited_T **visited_list,
-- char_u *fname
-- #ifdef FEAT_PATH_EXTRA
-- , char_u *wc_path
-- #endif
-- )
-- {
-- ff_visited_T *vp;
-- #ifdef UNIX
-- stat_T st;
-- int url = FALSE;
-- #endif
--
-- /* For an URL we only compare the name, otherwise we compare the
-- * device/inode (unix) or the full path name (not Unix). */
-- if (path_with_url(fname))
-- {
-- vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);
-- #ifdef UNIX
-- url = TRUE;
-- #endif
-- }
-- else
-- {
-- ff_expand_buffer[0] = NUL;
-- #ifdef UNIX
-- if (mch_stat((char *)fname, &st) < 0)
-- #else
-- if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
-- #endif
-- return FAIL;
-- }
--
-- /* check against list of already visited files */
-- for (vp = *visited_list; vp != NULL; vp = vp->ffv_next)
-- {
-- if (
-- #ifdef UNIX
-- !url ? (vp->ffv_dev_valid && vp->ffv_dev == st.st_dev
-- && vp->ffv_ino == st.st_ino)
-- :
-- #endif
-- fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
-- )
-- {
-- #ifdef FEAT_PATH_EXTRA
-- /* are the wildcard parts equal */
-- if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
-- #endif
-- /* already visited */
-- return FAIL;
-- }
-- }
--
-- /*
-- * New file/dir. Add it to the list of visited files/dirs.
-- */
-- vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T)
-- + STRLEN(ff_expand_buffer)));
--
-- if (vp != NULL)
-- {
-- #ifdef UNIX
-- if (!url)
-- {
-- vp->ffv_dev_valid = TRUE;
-- vp->ffv_ino = st.st_ino;
-- vp->ffv_dev = st.st_dev;
-- vp->ffv_fname[0] = NUL;
-- }
-- else
-- {
-- vp->ffv_dev_valid = FALSE;
-- #endif
-- STRCPY(vp->ffv_fname, ff_expand_buffer);
-- #ifdef UNIX
-- }
-- #endif
-- #ifdef FEAT_PATH_EXTRA
-- if (wc_path != NULL)
-- vp->ffv_wc_path = vim_strsave(wc_path);
-- else
-- vp->ffv_wc_path = NULL;
-- #endif
--
-- vp->ffv_next = *visited_list;
-- *visited_list = vp;
-- }
--
-- return OK;
-- }
--
-- /*
-- * create stack element from given path pieces
-- */
-- static ff_stack_T *
-- ff_create_stack_element(
-- char_u *fix_part,
-- #ifdef FEAT_PATH_EXTRA
-- char_u *wc_part,
-- #endif
-- int level,
-- int star_star_empty)
-- {
-- ff_stack_T *new;
--
-- new = (ff_stack_T *)alloc((unsigned)sizeof(ff_stack_T));
-- if (new == NULL)
-- return NULL;
--
-- new->ffs_prev = NULL;
-- new->ffs_filearray = NULL;
-- new->ffs_filearray_size = 0;
-- new->ffs_filearray_cur = 0;
-- new->ffs_stage = 0;
-- new->ffs_level = level;
-- new->ffs_star_star_empty = star_star_empty;
--
-- /* the following saves NULL pointer checks in vim_findfile */
-- if (fix_part == NULL)
-- fix_part = (char_u *)"";
-- new->ffs_fix_path = vim_strsave(fix_part);
--
-- #ifdef FEAT_PATH_EXTRA
-- if (wc_part == NULL)
-- wc_part = (char_u *)"";
-- new->ffs_wc_path = vim_strsave(wc_part);
-- #endif
--
-- if (new->ffs_fix_path == NULL
-- #ifdef FEAT_PATH_EXTRA
-- || new->ffs_wc_path == NULL
-- #endif
-- )
-- {
-- ff_free_stack_element(new);
-- new = NULL;
-- }
--
-- return new;
-- }
--
-- /*
-- * Push a dir on the directory stack.
-- */
-- static void
-- ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr)
-- {
-- /* check for NULL pointer, not to return an error to the user, but
-- * to prevent a crash */
-- if (stack_ptr != NULL)
-- {
-- stack_ptr->ffs_prev = search_ctx->ffsc_stack_ptr;
-- search_ctx->ffsc_stack_ptr = stack_ptr;
-- }
-- }
--
-- /*
-- * Pop a dir from the directory stack.
-- * Returns NULL if stack is empty.
-- */
-- static ff_stack_T *
-- ff_pop(ff_search_ctx_T *search_ctx)
-- {
-- ff_stack_T *sptr;
--
-- sptr = search_ctx->ffsc_stack_ptr;
-- if (search_ctx->ffsc_stack_ptr != NULL)
-- search_ctx->ffsc_stack_ptr = search_ctx->ffsc_stack_ptr->ffs_prev;
--
-- return sptr;
-- }
--
-- /*
-- * free the given stack element
-- */
-- static void
-- ff_free_stack_element(ff_stack_T *stack_ptr)
-- {
-- /* vim_free handles possible NULL pointers */
-- vim_free(stack_ptr->ffs_fix_path);
-- #ifdef FEAT_PATH_EXTRA
-- vim_free(stack_ptr->ffs_wc_path);
-- #endif
--
-- if (stack_ptr->ffs_filearray != NULL)
-- FreeWild(stack_ptr->ffs_filearray_size, stack_ptr->ffs_filearray);
--
-- vim_free(stack_ptr);
-- }
--
-- /*
-- * Clear the search context, but NOT the visited list.
-- */
-- static void
-- ff_clear(ff_search_ctx_T *search_ctx)
-- {
-- ff_stack_T *sptr;
--
-- /* clear up stack */
-- while ((sptr = ff_pop(search_ctx)) != NULL)
-- ff_free_stack_element(sptr);
--
-- vim_free(search_ctx->ffsc_file_to_search);
-- vim_free(search_ctx->ffsc_start_dir);
-- vim_free(search_ctx->ffsc_fix_path);
-- #ifdef FEAT_PATH_EXTRA
-- vim_free(search_ctx->ffsc_wc_path);
-- #endif
--
-- #ifdef FEAT_PATH_EXTRA
-- if (search_ctx->ffsc_stopdirs_v != NULL)
-- {
-- int i = 0;
--
-- while (search_ctx->ffsc_stopdirs_v[i] != NULL)
-- {
-- vim_free(search_ctx->ffsc_stopdirs_v[i]);
-- i++;
-- }
-- vim_free(search_ctx->ffsc_stopdirs_v);
-- }
-- search_ctx->ffsc_stopdirs_v = NULL;
-- #endif
--
-- /* reset everything */
-- search_ctx->ffsc_file_to_search = NULL;
-- search_ctx->ffsc_start_dir = NULL;
-- search_ctx->ffsc_fix_path = NULL;
-- #ifdef FEAT_PATH_EXTRA
-- search_ctx->ffsc_wc_path = NULL;
-- search_ctx->ffsc_level = 0;
-- #endif
-- }
--
-- #ifdef FEAT_PATH_EXTRA
-- /*
-- * check if the given path is in the stopdirs
-- * returns TRUE if yes else FALSE
-- */
-- static int
-- ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v)
-- {
-- int i = 0;
--
-- /* eat up trailing path separators, except the first */
-- while (path_len > 1 && vim_ispathsep(path[path_len - 1]))
-- path_len--;
--
-- /* if no path consider it as match */
-- if (path_len == 0)
-- return TRUE;
--
-- for (i = 0; stopdirs_v[i] != NULL; i++)
-- {
-- if ((int)STRLEN(stopdirs_v[i]) > path_len)
-- {
-- /* match for parent directory. So '/home' also matches
-- * '/home/rks'. Check for PATHSEP in stopdirs_v[i], else
-- * '/home/r' would also match '/home/rks'
-- */
-- if (fnamencmp(stopdirs_v[i], path, path_len) == 0
-- && vim_ispathsep(stopdirs_v[i][path_len]))
-- return TRUE;
-- }
-- else
-- {
-- if (fnamecmp(stopdirs_v[i], path) == 0)
-- return TRUE;
-- }
-- }
-- return FALSE;
-- }
-- #endif
--
-- #if defined(FEAT_SEARCHPATH) || defined(PROTO)
-- /*
-- * Find the file name "ptr[len]" in the path. Also finds directory names.
-- *
-- * On the first call set the parameter 'first' to TRUE to initialize
-- * the search. For repeating calls to FALSE.
-- *
-- * Repeating calls will return other files called 'ptr[len]' from the path.
-- *
-- * Only on the first call 'ptr' and 'len' are used. For repeating calls they
-- * don't need valid values.
-- *
-- * If nothing found on the first call the option FNAME_MESS will issue the
-- * message:
-- * 'Can't find file "<file>" in path'
-- * On repeating calls:
-- * 'No more file "<file>" found in path'
-- *
-- * options:
-- * FNAME_MESS give error message when not found
-- *
-- * Uses NameBuff[]!
-- *
-- * Returns an allocated string for the file name. NULL for error.
-- *
-- */
-- char_u *
-- find_file_in_path(
-- char_u *ptr, /* file name */
-- int len, /* length of file name */
-- int options,
-- int first, /* use count'th matching file name */
-- char_u *rel_fname) /* file name searching relative to */
-- {
-- return find_file_in_path_option(ptr, len, options, first,
-- *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path,
-- FINDFILE_BOTH, rel_fname, curbuf->b_p_sua);
-- }
--
-- static char_u *ff_file_to_find = NULL;
-- static void *fdip_search_ctx = NULL;
--
-- #if defined(EXITFREE)
-- static void
-- free_findfile(void)
-- {
-- vim_free(ff_file_to_find);
-- vim_findfile_cleanup(fdip_search_ctx);
-- }
-- #endif
--
-- /*
-- * Find the directory name "ptr[len]" in the path.
-- *
-- * options:
-- * FNAME_MESS give error message when not found
-- * FNAME_UNESC unescape backslashes.
-- *
-- * Uses NameBuff[]!
-- *
-- * Returns an allocated string for the file name. NULL for error.
-- */
-- char_u *
-- find_directory_in_path(
-- char_u *ptr, /* file name */
-- int len, /* length of file name */
-- int options,
-- char_u *rel_fname) /* file name searching relative to */
-- {
-- return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath,
-- FINDFILE_DIR, rel_fname, (char_u *)"");
-- }
--
-- char_u *
-- find_file_in_path_option(
-- char_u *ptr, /* file name */
-- int len, /* length of file name */
-- int options,
-- int first, /* use count'th matching file name */
-- char_u *path_option, /* p_path or p_cdpath */
-- int find_what, /* FINDFILE_FILE, _DIR or _BOTH */
-- char_u *rel_fname, /* file name we are looking relative to. */
-- char_u *suffixes) /* list of suffixes, 'suffixesadd' option */
-- {
-- static char_u *dir;
-- static int did_findfile_init = FALSE;
-- char_u save_char;
-- char_u *file_name = NULL;
-- char_u *buf = NULL;
-- int rel_to_curdir;
-- #ifdef AMIGA
-- struct Process *proc = (struct Process *)FindTask(0L);
-- APTR save_winptr = proc->pr_WindowPtr;
--
-- /* Avoid a requester here for a volume that doesn't exist. */
-- proc->pr_WindowPtr = (APTR)-1L;
-- #endif
--
-- if (first == TRUE)
-- {
-- /* copy file name into NameBuff, expanding environment variables */
-- save_char = ptr[len];
-- ptr[len] = NUL;
-- expand_env_esc(ptr, NameBuff, MAXPATHL, FALSE, TRUE, NULL);
-- ptr[len] = save_char;
--
-- vim_free(ff_file_to_find);
-- ff_file_to_find = vim_strsave(NameBuff);
-- if (ff_file_to_find == NULL) /* out of memory */
-- {
-- file_name = NULL;
-- goto theend;
-- }
-- if (options & FNAME_UNESC)
-- {
-- /* Change all "\ " to " ". */
-- for (ptr = ff_file_to_find; *ptr != NUL; ++ptr)
-- if (ptr[0] == '\\' && ptr[1] == ' ')
-- mch_memmove(ptr, ptr + 1, STRLEN(ptr));
-- }
-- }
--
-- rel_to_curdir = (ff_file_to_find[0] == '.'
-- && (ff_file_to_find[1] == NUL
-- || vim_ispathsep(ff_file_to_find[1])
-- || (ff_file_to_find[1] == '.'
-- && (ff_file_to_find[2] == NUL
-- || vim_ispathsep(ff_file_to_find[2])))));
-- if (vim_isAbsName(ff_file_to_find)
-- /* "..", "../path", "." and "./path": don't use the path_option */
-- || rel_to_curdir
-- #if defined(MSWIN)
-- /* handle "\tmp" as absolute path */
-- || vim_ispathsep(ff_file_to_find[0])
-- /* handle "c:name" as absolute path */
-- || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':')
-- #endif
-- #ifdef AMIGA
-- /* handle ":tmp" as absolute path */
-- || ff_file_to_find[0] == ':'
-- #endif
-- )
-- {
-- /*
-- * Absolute path, no need to use "path_option".
-- * If this is not a first call, return NULL. We already returned a
-- * filename on the first call.
-- */
-- if (first == TRUE)
-- {
-- int l;
-- int run;
--
-- if (path_with_url(ff_file_to_find))
-- {
-- file_name = vim_strsave(ff_file_to_find);
-- goto theend;
-- }
--
-- /* When FNAME_REL flag given first use the directory of the file.
-- * Otherwise or when this fails use the current directory. */
-- for (run = 1; run <= 2; ++run)
-- {
-- l = (int)STRLEN(ff_file_to_find);
-- if (run == 1
-- && rel_to_curdir
-- && (options & FNAME_REL)
-- && rel_fname != NULL
-- && STRLEN(rel_fname) + l < MAXPATHL)
-- {
-- STRCPY(NameBuff, rel_fname);
-- STRCPY(gettail(NameBuff), ff_file_to_find);
-- l = (int)STRLEN(NameBuff);
-- }
-- else
-- {
-- STRCPY(NameBuff, ff_file_to_find);
-- run = 2;
-- }
--
-- /* When the file doesn't exist, try adding parts of
-- * 'suffixesadd'. */
-- buf = suffixes;
-- for (;;)
-- {
-- if (mch_getperm(NameBuff) >= 0
-- && (find_what == FINDFILE_BOTH
-- || ((find_what == FINDFILE_DIR)
-- == mch_isdir(NameBuff))))
-- {
-- file_name = vim_strsave(NameBuff);
-- goto theend;
-- }
-- if (*buf == NUL)
-- break;
-- copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ",");
-- }
-- }
-- }
-- }
-- else
-- {
-- /*
-- * Loop over all paths in the 'path' or 'cdpath' option.
-- * When "first" is set, first setup to the start of the option.
-- * Otherwise continue to find the next match.
-- */
-- if (first == TRUE)
-- {
-- /* vim_findfile_free_visited can handle a possible NULL pointer */
-- vim_findfile_free_visited(fdip_search_ctx);
-- dir = path_option;
-- did_findfile_init = FALSE;
-- }
--
-- for (;;)
-- {
-- if (did_findfile_init)
-- {
-- file_name = vim_findfile(fdip_search_ctx);
-- if (file_name != NULL)
-- break;
--
-- did_findfile_init = FALSE;
-- }
-- else
-- {
-- char_u *r_ptr;
--
-- if (dir == NULL || *dir == NUL)
-- {
-- /* We searched all paths of the option, now we can
-- * free the search context. */
-- vim_findfile_cleanup(fdip_search_ctx);
-- fdip_search_ctx = NULL;
-- break;
-- }
--
-- if ((buf = alloc((int)(MAXPATHL))) == NULL)
-- break;
--
-- /* copy next path */
-- buf[0] = 0;
-- copy_option_part(&dir, buf, MAXPATHL, " ,");
--
-- #ifdef FEAT_PATH_EXTRA
-- /* get the stopdir string */
-- r_ptr = vim_findfile_stopdir(buf);
-- #else
-- r_ptr = NULL;
-- #endif
-- fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find,
-- r_ptr, 100, FALSE, find_what,
-- fdip_search_ctx, FALSE, rel_fname);
-- if (fdip_search_ctx != NULL)
-- did_findfile_init = TRUE;
-- vim_free(buf);
-- }
-- }
-- }
-- if (file_name == NULL && (options & FNAME_MESS))
-- {
-- if (first == TRUE)
-- {
-- if (find_what == FINDFILE_DIR)
-- semsg(_("E344: Can't find directory \"%s\" in cdpath"),
-- ff_file_to_find);
-- else
-- semsg(_("E345: Can't find file \"%s\" in path"),
-- ff_file_to_find);
-- }
-- else
-- {
-- if (find_what == FINDFILE_DIR)
-- semsg(_("E346: No more directory \"%s\" found in cdpath"),
-- ff_file_to_find);
-- else
-- semsg(_("E347: No more file \"%s\" found in path"),
-- ff_file_to_find);
-- }
-- }
--
-- theend:
-- #ifdef AMIGA
-- proc->pr_WindowPtr = save_winptr;
-- #endif
-- return file_name;
-- }
--
-- #endif /* FEAT_SEARCHPATH */
--
- /*
- * Change directory to "new_dir". If FEAT_SEARCHPATH is defined, search
- * 'cdpath' for relative directory names, otherwise just mch_chdir().
---- 3815,3820 ----
-*** ../vim-8.1.0913/src/proto.h 2019-01-31 13:47:51.126632619 +0100
---- src/proto.h 2019-02-13 22:06:27.641777652 +0100
-***************
-*** 80,85 ****
---- 80,86 ----
- # include "ex_eval.pro"
- # include "ex_getln.pro"
- # include "fileio.pro"
-+ # include "findfile.pro"
- # include "fold.pro"
- # include "getchar.pro"
- # ifdef FEAT_HANGULIN
-*** ../vim-8.1.0913/src/proto/findfile.pro 2019-02-13 22:43:46.449534680 +0100
---- src/proto/findfile.pro 2019-02-13 22:31:26.131353440 +0100
-***************
-*** 0 ****
---- 1,18 ----
-+ /* findfile.c */
-+ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int level, int free_visited, int find_what, void *search_ctx_arg, int tagfile, char_u *rel_fname);
-+ char_u *vim_findfile_stopdir(char_u *buf);
-+ void vim_findfile_cleanup(void *ctx);
-+ char_u *vim_findfile(void *search_ctx_arg);
-+ void vim_findfile_free_visited(void *search_ctx_arg);
-+ char_u *find_file_in_path(char_u *ptr, int len, int options, int first, char_u *rel_fname);
-+ void free_findfile(void);
-+ char_u *find_directory_in_path(char_u *ptr, int len, int options, char_u *rel_fname);
-+ char_u *find_file_in_path_option(char_u *ptr, int len, int options, int first, char_u *path_option, int find_what, char_u *rel_fname, char_u *suffixes);
-+ char_u *grab_file_name(long count, linenr_T *file_lnum);
-+ char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum);
-+ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u *rel_fname, linenr_T *file_lnum);
-+ char_u *find_file_name_in_path(char_u *ptr, int len, int options, long count, char_u *rel_fname);
-+ int vim_ispathlistsep(int c);
-+ void uniquefy_paths(garray_T *gap, char_u *pattern);
-+ int expand_in_path(garray_T *gap, char_u *pattern, int flags);
-+ /* vim: set ft=c : */
-*** ../vim-8.1.0913/src/proto/misc1.pro 2019-01-31 13:47:51.126632619 +0100
---- src/proto/misc1.pro 2019-02-13 22:07:22.757355997 +0100
-***************
-*** 74,80 ****
- char_u *get_past_head(char_u *path);
- int vim_ispathsep(int c);
- int vim_ispathsep_nocolon(int c);
-- int vim_ispathlistsep(int c);
- void shorten_dir(char_u *str);
- int dir_of_file_exists(char_u *fname);
- int vim_fnamecmp(char_u *x, char_u *y);
---- 74,79 ----
-***************
-*** 99,102 ****
---- 98,105 ----
- void FreeWild(int count, char_u **files);
- int goto_im(void);
- char_u *get_isolated_shell_name(void);
-+ int path_is_url(char_u *p);
-+ int path_with_url(char_u *fname);
-+ int vim_isAbsName(char_u *name);
-+ int vim_FullName(char_u *fname, char_u *buf, int len, int force);
- /* vim: set ft=c : */
-*** ../vim-8.1.0913/src/proto/misc2.pro 2019-01-13 23:38:33.407773189 +0100
---- src/proto/misc2.pro 2019-02-13 22:07:27.497320021 +0100
-***************
-*** 90,103 ****
- char *parse_shape_opt(int what);
- int get_shape_idx(int mouse);
- void update_mouseshape(int shape_idx);
-- void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int level, int free_visited, int find_what, void *search_ctx_arg, int tagfile, char_u *rel_fname);
-- char_u *vim_findfile_stopdir(char_u *buf);
-- void vim_findfile_cleanup(void *ctx);
-- char_u *vim_findfile(void *search_ctx_arg);
-- void vim_findfile_free_visited(void *search_ctx_arg);
-- char_u *find_file_in_path(char_u *ptr, int len, int options, int first, char_u *rel_fname);
-- char_u *find_directory_in_path(char_u *ptr, int len, int options, char_u *rel_fname);
-- char_u *find_file_in_path_option(char_u *ptr, int len, int options, int first, char_u *path_option, int find_what, char_u *rel_fname, char_u *suffixes);
- int vim_chdir(char_u *new_dir);
- int get_user_name(char_u *buf, int len);
- void sort_strings(char_u **files, int count);
---- 90,95 ----
-*** ../vim-8.1.0913/src/proto/window.pro 2019-02-10 22:58:58.976414779 +0100
---- src/proto/window.pro 2019-02-13 22:07:31.661288452 +0100
-***************
-*** 65,77 ****
- void command_height(void);
- void last_status(int morewin);
- int tabline_height(void);
-- char_u *grab_file_name(long count, linenr_T *file_lnum);
-- char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum);
-- char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u *rel_fname, linenr_T *file_lnum);
-- char_u *find_file_name_in_path(char_u *ptr, int len, int options, long count, char_u *rel_fname);
-- int path_with_url(char_u *fname);
-- int vim_isAbsName(char_u *name);
-- int vim_FullName(char_u *fname, char_u *buf, int len, int force);
- int min_rows(void);
- int only_one_window(void);
- void check_lnums(int do_curwin);
---- 65,70 ----
-*** ../vim-8.1.0913/src/window.c 2019-02-10 22:58:58.980414768 +0100
---- src/window.c 2019-02-13 22:06:27.641777652 +0100
-***************
-*** 9,15 ****
-
- #include "vim.h"
-
-- static int path_is_url(char_u *p);
- static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, long Prenum);
- static void win_init(win_T *newp, win_T *oldp, int flags);
- static void win_init_some(win_T *newp, win_T *oldp);
---- 9,14 ----
-***************
-*** 61,69 ****
-
- static win_T *win_alloc(win_T *after, int hidden);
-
-- #define URL_SLASH 1 /* path_is_url() has found "://" */
-- #define URL_BACKSLASH 2 /* path_is_url() has found ":\\" */
--
- #define NOWIN (win_T *)-1 /* non-existing window */
-
- #define ROWS_AVAIL (Rows - p_ch - tabline_height())
---- 60,65 ----
-***************
-*** 6098,6414 ****
- return 1;
- }
-
-- #if defined(FEAT_SEARCHPATH) || defined(PROTO)
-- /*
-- * Get the file name at the cursor.
-- * If Visual mode is active, use the selected text if it's in one line.
-- * Returns the name in allocated memory, NULL for failure.
-- */
-- char_u *
-- grab_file_name(long count, linenr_T *file_lnum)
-- {
-- int options = FNAME_MESS|FNAME_EXP|FNAME_REL|FNAME_UNESC;
--
-- if (VIsual_active)
-- {
-- int len;
-- char_u *ptr;
--
-- if (get_visual_text(NULL, &ptr, &len) == FAIL)
-- return NULL;
-- return find_file_name_in_path(ptr, len, options,
-- count, curbuf->b_ffname);
-- }
-- return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
-- }
--
-- /*
-- * Return the file name under or after the cursor.
-- *
-- * The 'path' option is searched if the file name is not absolute.
-- * The string returned has been alloc'ed and should be freed by the caller.
-- * NULL is returned if the file name or file is not found.
-- *
-- * options:
-- * FNAME_MESS give error messages
-- * FNAME_EXP expand to path
-- * FNAME_HYP check for hypertext link
-- * FNAME_INCL apply "includeexpr"
-- */
-- char_u *
-- file_name_at_cursor(int options, long count, linenr_T *file_lnum)
-- {
-- return file_name_in_line(ml_get_curline(),
-- curwin->w_cursor.col, options, count, curbuf->b_ffname,
-- file_lnum);
-- }
--
-- /*
-- * Return the name of the file under or after ptr[col].
-- * Otherwise like file_name_at_cursor().
-- */
-- char_u *
-- file_name_in_line(
-- char_u *line,
-- int col,
-- int options,
-- long count,
-- char_u *rel_fname, /* file we are searching relative to */
-- linenr_T *file_lnum) /* line number after the file name */
-- {
-- char_u *ptr;
-- int len;
-- int in_type = TRUE;
-- int is_url = FALSE;
--
-- /*
-- * search forward for what could be the start of a file name
-- */
-- ptr = line + col;
-- while (*ptr != NUL && !vim_isfilec(*ptr))
-- MB_PTR_ADV(ptr);
-- if (*ptr == NUL) /* nothing found */
-- {
-- if (options & FNAME_MESS)
-- emsg(_("E446: No file name under cursor"));
-- return NULL;
-- }
--
-- /*
-- * Search backward for first char of the file name.
-- * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
-- */
-- while (ptr > line)
-- {
-- if (has_mbyte && (len = (*mb_head_off)(line, ptr - 1)) > 0)
-- ptr -= len + 1;
-- else if (vim_isfilec(ptr[-1])
-- || ((options & FNAME_HYP) && path_is_url(ptr - 1)))
-- --ptr;
-- else
-- break;
-- }
--
-- /*
-- * Search forward for the last char of the file name.
-- * Also allow "://" when ':' is not in 'isfname'.
-- */
-- len = 0;
-- while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
-- || ((options & FNAME_HYP) && path_is_url(ptr + len))
-- || (is_url && vim_strchr((char_u *)"?&=", ptr[len]) != NULL))
-- {
-- /* After type:// we also include ?, & and = as valid characters, so that
-- * http://google.com?q=this&that=ok works. */
-- if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z'))
-- {
-- if (in_type && path_is_url(ptr + len + 1))
-- is_url = TRUE;
-- }
-- else
-- in_type = FALSE;
--
-- if (ptr[len] == '\\')
-- /* Skip over the "\" in "\ ". */
-- ++len;
-- if (has_mbyte)
-- len += (*mb_ptr2len)(ptr + len);
-- else
-- ++len;
-- }
--
-- /*
-- * If there is trailing punctuation, remove it.
-- * But don't remove "..", could be a directory name.
-- */
-- if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
-- && ptr[len - 2] != '.')
-- --len;
--
-- if (file_lnum != NULL)
-- {
-- char_u *p;
--
-- /* Get the number after the file name and a separator character */
-- p = ptr + len;
-- p = skipwhite(p);
-- if (*p != NUL)
-- {
-- if (!isdigit(*p))
-- ++p; /* skip the separator */
-- p = skipwhite(p);
-- if (isdigit(*p))
-- *file_lnum = (int)getdigits(&p);
-- }
-- }
--
-- return find_file_name_in_path(ptr, len, options, count, rel_fname);
-- }
--
-- # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-- static char_u *
-- eval_includeexpr(char_u *ptr, int len)
-- {
-- char_u *res;
--
-- set_vim_var_string(VV_FNAME, ptr, len);
-- res = eval_to_string_safe(curbuf->b_p_inex, NULL,
-- was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL));
-- set_vim_var_string(VV_FNAME, NULL, 0);
-- return res;
-- }
-- #endif
--
-- /*
-- * Return the name of the file ptr[len] in 'path'.
-- * Otherwise like file_name_at_cursor().
-- */
-- char_u *
-- find_file_name_in_path(
-- char_u *ptr,
-- int len,
-- int options,
-- long count,
-- char_u *rel_fname) /* file we are searching relative to */
-- {
-- char_u *file_name;
-- int c;
-- # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-- char_u *tofree = NULL;
--
-- if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
-- {
-- tofree = eval_includeexpr(ptr, len);
-- if (tofree != NULL)
-- {
-- ptr = tofree;
-- len = (int)STRLEN(ptr);
-- }
-- }
-- # endif
--
-- if (options & FNAME_EXP)
-- {
-- file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
-- TRUE, rel_fname);
--
-- # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-- /*
-- * If the file could not be found in a normal way, try applying
-- * 'includeexpr' (unless done already).
-- */
-- if (file_name == NULL
-- && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
-- {
-- tofree = eval_includeexpr(ptr, len);
-- if (tofree != NULL)
-- {
-- ptr = tofree;
-- len = (int)STRLEN(ptr);
-- file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
-- TRUE, rel_fname);
-- }
-- }
-- # endif
-- if (file_name == NULL && (options & FNAME_MESS))
-- {
-- c = ptr[len];
-- ptr[len] = NUL;
-- semsg(_("E447: Can't find file \"%s\" in path"), ptr);
-- ptr[len] = c;
-- }
--
-- /* Repeat finding the file "count" times. This matters when it
-- * appears several times in the path. */
-- while (file_name != NULL && --count > 0)
-- {
-- vim_free(file_name);
-- file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
-- }
-- }
-- else
-- file_name = vim_strnsave(ptr, len);
--
-- # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-- vim_free(tofree);
-- # endif
--
-- return file_name;
-- }
-- #endif /* FEAT_SEARCHPATH */
--
-- /*
-- * Check if the "://" of a URL is at the pointer, return URL_SLASH.
-- * Also check for ":\\", which MS Internet Explorer accepts, return
-- * URL_BACKSLASH.
-- */
-- static int
-- path_is_url(char_u *p)
-- {
-- if (STRNCMP(p, "://", (size_t)3) == 0)
-- return URL_SLASH;
-- else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
-- return URL_BACKSLASH;
-- return 0;
-- }
--
-- /*
-- * Check if "fname" starts with "name://". Return URL_SLASH if it does.
-- * Return URL_BACKSLASH for "name:\\".
-- * Return zero otherwise.
-- */
-- int
-- path_with_url(char_u *fname)
-- {
-- char_u *p;
--
-- for (p = fname; isalpha(*p); ++p)
-- ;
-- return path_is_url(p);
-- }
--
-- /*
-- * Return TRUE if "name" is a full (absolute) path name or URL.
-- */
-- int
-- vim_isAbsName(char_u *name)
-- {
-- return (path_with_url(name) != 0 || mch_isFullName(name));
-- }
--
-- /*
-- * Get absolute file name into buffer "buf[len]".
-- *
-- * return FAIL for failure, OK otherwise
-- */
-- int
-- vim_FullName(
-- char_u *fname,
-- char_u *buf,
-- int len,
-- int force) /* force expansion even when already absolute */
-- {
-- int retval = OK;
-- int url;
--
-- *buf = NUL;
-- if (fname == NULL)
-- return FAIL;
--
-- url = path_with_url(fname);
-- if (!url)
-- retval = mch_FullName(fname, buf, len, force);
-- if (url || retval == FAIL)
-- {
-- /* something failed; use the file name (truncate when too long) */
-- vim_strncpy(buf, fname, len - 1);
-- }
-- #if defined(MSWIN)
-- slash_adjust(buf);
-- #endif
-- return retval;
-- }
--
- /*
- * Return the minimal number of rows that is needed on the screen to display
- * the current number of windows.
---- 6094,6099 ----
-*** ../vim-8.1.0913/src/version.c 2019-02-13 21:47:32.961109662 +0100
---- src/version.c 2019-02-13 22:04:54.862441927 +0100
-***************
-*** 785,786 ****
---- 785,788 ----
- { /* Add new patch number below this line */
-+ /**/
-+ 914,
- /**/
-
-
---
-./configure
-Checking whether build environment is sane ...
-build environment is grinning and holding a spatula. Guess not.
-
- /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
-/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
-\\\ an exciting new programming language -- http://www.Zimbu.org ///
- \\\ help me help AIDS victims -- http://ICCF-Holland.org ///