diff options
Diffstat (limited to 'data/vim/patches/8.1.0914')
-rw-r--r-- | data/vim/patches/8.1.0914 | 6010 |
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(®match, 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(®match, 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(®match, 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(®match, 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 /// |