diff options
Diffstat (limited to 'src/nvim/path.c')
-rw-r--r-- | src/nvim/path.c | 150 |
1 files changed, 40 insertions, 110 deletions
diff --git a/src/nvim/path.c b/src/nvim/path.c index d782d1a989..9cce504831 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -8,23 +8,17 @@ #include "auto/config.h" #include "nvim/ascii_defs.h" -#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/eval.h" -#include "nvim/eval/typval_defs.h" #include "nvim/ex_docmd.h" -#include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/garray.h" -#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/macros_defs.h" #include "nvim/mbyte.h" #include "nvim/memory.h" -#include "nvim/message.h" #include "nvim/option.h" -#include "nvim/option_defs.h" #include "nvim/option_vars.h" #include "nvim/os/fs.h" #include "nvim/os/fs_defs.h" @@ -37,7 +31,6 @@ #include "nvim/regexp_defs.h" #include "nvim/strings.h" #include "nvim/vim_defs.h" -#include "nvim/window.h" enum { URL_SLASH = 1, // path_is_url() has found ":/" @@ -390,14 +383,14 @@ int path_fnamencmp(const char *const fname1, const char *const fname2, size_t le c2 = utf_ptr2char(p2); if ((c1 == NUL || c2 == NUL || (!((c1 == '/' || c1 == '\\') && (c2 == '\\' || c2 == '/')))) - && (p_fic ? (c1 != c2 && CH_FOLD(c1) != CH_FOLD(c2)) : c1 != c2)) { + && (p_fic ? (c1 != c2 && utf_fold(c1) != utf_fold(c2)) : c1 != c2)) { break; } len -= (size_t)utfc_ptr2len(p1); p1 += utfc_ptr2len(p1); p2 += utfc_ptr2len(p2); } - return p_fic ? CH_FOLD(c1) - CH_FOLD(c2) : c1 - c2; + return p_fic ? utf_fold(c1) - utf_fold(c2) : c1 - c2; #else if (p_fic) { return mb_strnicmp(fname1, fname2, len); @@ -842,17 +835,18 @@ static bool is_unique(char *maybe_unique, garray_T *gap, int i) 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(vim): handle upward search (;) and path limiter (**N) notations by -// expanding each into their equivalent path(s). -static void expand_path_option(char *curdir, garray_T *gap) +/// 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. +/// +/// @param path_option p_path or p_cdpath +/// +/// TODO(vim): handle upward search (;) and path limiter (**N) notations by +/// expanding each into their equivalent path(s). +static void expand_path_option(char *curdir, char *path_option, garray_T *gap) FUNC_ATTR_NONNULL_ALL { - char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char *buf = xmalloc(MAXPATHL); while (*path_option != NUL) { @@ -942,7 +936,9 @@ static char *get_path_cutoff(char *fname, garray_T *gap) /// 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 *pattern) +/// +/// @param path_option p_path or p_cdpath +static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option) FUNC_ATTR_NONNULL_ALL { char **fnames = gap->ga_data; @@ -962,8 +958,8 @@ static void uniquefy_paths(garray_T *gap, char *pattern) char *file_pattern = xmalloc(len + 2); file_pattern[0] = '*'; file_pattern[1] = NUL; - STRCAT(file_pattern, pattern); - char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, true); + strcat(file_pattern, pattern); + char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, false); xfree(file_pattern); if (pat == NULL) { return; @@ -978,7 +974,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) char *curdir = xmalloc(MAXPATHL); os_dirname(curdir, MAXPATHL); - expand_path_option(curdir, &path_ga); + expand_path_option(curdir, path_option, &path_ga); in_curdir = xcalloc((size_t)gap->ga_len, sizeof(char *)); @@ -1065,7 +1061,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) rel_path = xmalloc(strlen(short_name) + strlen(PATHSEPSTR) + 2); STRCPY(rel_path, "."); add_pathsep(rel_path); - STRCAT(rel_path, short_name); + strcat(rel_path, short_name); xfree(fnames[i]); fnames[i] = rel_path; @@ -1127,12 +1123,17 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl FUNC_ATTR_NONNULL_ALL { garray_T path_ga; + char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char *const curdir = xmalloc(MAXPATHL); os_dirname(curdir, MAXPATHL); ga_init(&path_ga, (int)sizeof(char *), 1); - expand_path_option(curdir, &path_ga); + if (flags & EW_CDPATH) { + expand_path_option(curdir, p_cdpath, &path_ga); + } else { + expand_path_option(curdir, path_option, &path_ga); + } xfree(curdir); if (GA_EMPTY(&path_ga)) { return 0; @@ -1148,7 +1149,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl if (flags & EW_ADDSLASH) { glob_flags |= WILD_ADD_SLASH; } - globpath(paths, pattern, gap, glob_flags, false); + globpath(paths, pattern, gap, glob_flags, !!(flags & EW_CDPATH)); xfree(paths); return gap->ga_len; @@ -1229,6 +1230,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i static bool recursive = false; int add_pat; bool did_expand_in_path = false; + char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; // expand_env() is called to expand things like "~user". If this fails, // it calls ExpandOne(), which brings us back here. In this case, always @@ -1302,7 +1304,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i // Otherwise: Add the file name if it exists or when EW_NOTFOUND is // given. if (path_has_exp_wildcard(p) || (flags & EW_ICASE)) { - if ((flags & EW_PATH) + if ((flags & (EW_PATH | EW_CDPATH)) && !path_is_absolute(p) && !(p[0] == '.' && (vim_ispathsep(p[1]) @@ -1338,8 +1340,8 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i } } - if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & EW_PATH)) { - uniquefy_paths(&ga, p); + if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & (EW_PATH | EW_CDPATH))) { + uniquefy_paths(&ga, p, path_option); } if (p != pat[i]) { xfree(p); @@ -1389,7 +1391,7 @@ static int expand_backtick(garray_T *gap, char *pat, int flags) char *cmd = xmemdupz(pat + 1, strlen(pat) - 2); if (*cmd == '=') { // `={expr}`: Expand expression - buffer = eval_to_string(cmd + 1, true); + buffer = eval_to_string(cmd + 1, true, false); } else { buffer = get_cmd_output(cmd, NULL, (flags & EW_SILENT) ? kShellOptSilent : 0, NULL); } @@ -1678,86 +1680,6 @@ void simplify_filename(char *filename) } while (*p != NUL); } -static char *eval_includeexpr(const char *const ptr, const size_t len) -{ - const sctx_T save_sctx = current_sctx; - set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); - current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx; - - char *res = eval_to_string_safe(curbuf->b_p_inex, - was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL)); - - set_vim_var_string(VV_FNAME, NULL, 0); - current_sctx = save_sctx; - return res; -} - -/// Return the name of the file ptr[len] in 'path'. -/// Otherwise like file_name_at_cursor(). -/// -/// @param rel_fname file we are searching relative to -char *find_file_name_in_path(char *ptr, size_t len, int options, long count, char *rel_fname) -{ - char *file_name; - char *tofree = NULL; - - if (len == 0) { - return NULL; - } - - if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) { - tofree = eval_includeexpr(ptr, len); - if (tofree != NULL) { - ptr = tofree; - len = strlen(ptr); - } - } - - if (options & FNAME_EXP) { - char *file_to_find = NULL; - char *search_ctx = NULL; - - file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, - true, rel_fname, &file_to_find, &search_ctx); - - // 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 = strlen(ptr); - file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, - true, rel_fname, &file_to_find, &search_ctx); - } - } - if (file_name == NULL && (options & FNAME_MESS)) { - char 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) { - xfree(file_name); - file_name = find_file_in_path(ptr, len, options, false, rel_fname, - &file_to_find, &search_ctx); - } - - xfree(file_to_find); - vim_findfile_cleanup(search_ctx); - } else { - file_name = xstrnsave(ptr, len); - } - - xfree(tofree); - - return file_name; -} - /// Checks for a Windows drive letter ("C:/") at the start of the path. /// /// @see https://url.spec.whatwg.org/#start-with-a-windows-drive-letter @@ -2384,11 +2306,19 @@ static int path_to_absolute(const char *fname, char *buf, size_t len, int force) p = strrchr(fname, '\\'); } #endif + if (p == NULL && strcmp(fname, "..") == 0) { + // Handle ".." without path separators. + p = fname + 2; + } if (p != NULL) { + if (vim_ispathsep_nocolon(*p) && strcmp(p + 1, "..") == 0) { + // For "/path/dir/.." include the "/..". + p += 3; + } assert(p >= fname); memcpy(relative_directory, fname, (size_t)(p - fname + 1)); relative_directory[p - fname + 1] = NUL; - end_of_path = p + 1; + end_of_path = (vim_ispathsep_nocolon(*p) ? p + 1 : p); } else { relative_directory[0] = NUL; } |