aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/path.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/path.c')
-rw-r--r--src/nvim/path.c150
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;
}