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.c157
1 files changed, 96 insertions, 61 deletions
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 41fd69f238..374d72ddd3 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -18,7 +18,6 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/misc2.h"
#include "nvim/option.h"
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
@@ -172,19 +171,23 @@ char_u *path_next_component(char_u *fname)
return fname;
}
-/*
- * Get a pointer to one character past the head of a path name.
- * Unix: after "/"; DOS: after "c:\"; Mac: no head.
- * If there is no head, path is returned.
- */
+/// Get a pointer to one character past the head of a path name.
+/// Unix: after "/"; Win: after "c:\"
+/// If there is no head, path is returned.
char_u *get_past_head(char_u *path)
{
- char_u *retval;
+ char_u *retval = path;
- retval = path;
+#ifdef WIN32
+ // May skip "c:"
+ if (isalpha(path[0]) && path[1] == ':') {
+ retval = path + 2;
+ }
+#endif
- while (vim_ispathsep(*retval))
+ while (vim_ispathsep(*retval)) {
++retval;
+ }
return retval;
}
@@ -388,15 +391,22 @@ char *concat_fnames_realloc(char *fname1, const char *fname2, bool sep)
fname2, len2, sep);
}
-/*
- * Add a path separator to a file name, unless it already ends in a path
- * separator.
- */
-void add_pathsep(char *p)
+/// Adds a path separator to a filename, unless it already ends in one.
+///
+/// @return `true` if the path separator was added or already existed.
+/// `false` if the filename is too long.
+bool add_pathsep(char *p)
FUNC_ATTR_NONNULL_ALL
{
- if (*p != NUL && !after_pathsep(p, p + strlen(p)))
- strcat(p, PATHSEPSTR);
+ const size_t len = strlen(p);
+ if (*p != NUL && !after_pathsep(p, p + len)) {
+ const size_t pathsep_len = sizeof(PATHSEPSTR);
+ if (len > MAXPATHL - pathsep_len) {
+ return false;
+ }
+ memcpy(p + len, PATHSEPSTR, pathsep_len);
+ }
+ return true;
}
/// Get an allocated copy of the full path to a file.
@@ -414,15 +424,11 @@ char *FullName_save(char *fname, bool force)
}
char *buf = xmalloc(MAXPATHL);
- char *new_fname = NULL;
- if (vim_FullName(fname, buf, MAXPATHL, force) != FAIL) {
- new_fname = xstrdup(buf);
- } else {
- new_fname = xstrdup(fname);
+ if (vim_FullName(fname, buf, MAXPATHL, force) == FAIL) {
+ xfree(buf);
+ return xstrdup(fname);
}
- xfree(buf);
-
- return new_fname;
+ return buf;
}
/// Saves the absolute path.
@@ -562,11 +568,12 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
while (*path_end != NUL) {
/* May ignore a wildcard that has a backslash before it; it will
* be removed by rem_backslash() or file_pat_to_reg_pat() below. */
- if (path_end >= path + wildoff && rem_backslash(path_end))
+ if (path_end >= path + wildoff && rem_backslash(path_end)) {
*p++ = *path_end++;
- else if (*path_end == '/') {
- if (e != NULL)
+ } else if (vim_ispathsep_nocolon(*path_end)) {
+ if (e != NULL) {
break;
+ }
s = p + 1;
} else if (path_end >= path + wildoff
&& (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL
@@ -579,7 +586,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
}
if (has_mbyte) {
len = (size_t)(*mb_ptr2len)(path_end);
- STRNCPY(p, path_end, len);
+ memcpy(p, path_end, len);
p += len;
path_end += len;
} else
@@ -684,7 +691,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
}
// add existing file or symbolic link
if ((flags & EW_ALLLINKS) ? os_fileinfo_link((char *)buf, &file_info)
- : os_file_exists(buf)) {
+ : os_path_exists(buf)) {
addfile(gap, buf, flags);
}
}
@@ -899,17 +906,30 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
/* Shorten the filename while maintaining its uniqueness */
path_cutoff = get_path_cutoff(path, &path_ga);
- /* we start at the end of the path */
- pathsep_p = path + len - 1;
-
- while (find_previous_pathsep(path, &pathsep_p))
- if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
- && is_unique(pathsep_p + 1, gap, i)
- && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) {
- sort_again = true;
- memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
- break;
+ // Don't assume all files can be reached without path when search
+ // pattern starts with **/, so only remove path_cutoff
+ // when possible.
+ if (pattern[0] == '*' && pattern[1] == '*'
+ && vim_ispathsep_nocolon(pattern[2])
+ && path_cutoff != NULL
+ && vim_regexec(&regmatch, path_cutoff, (colnr_T)0)
+ && is_unique(path_cutoff, gap, i)) {
+ sort_again = true;
+ memmove(path, path_cutoff, STRLEN(path_cutoff) + 1);
+ } else {
+ // Here all files can be reached without path, so get shortest
+ // unique path. We start at the end of the path. */
+ pathsep_p = path + len - 1;
+ while (find_previous_pathsep(path, &pathsep_p)) {
+ if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
+ && is_unique(pathsep_p + 1, gap, i)
+ && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) {
+ sort_again = true;
+ memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
+ break;
+ }
}
+ }
if (path_is_absolute_path(path)) {
/*
@@ -1205,10 +1225,11 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
/* When EW_NOTFOUND is used, always add files and dirs. Makes
* "vim c:/" work. */
- if (flags & EW_NOTFOUND)
+ if (flags & EW_NOTFOUND) {
addfile(&ga, t, flags | EW_DIR | EW_FILE);
- else if (os_file_exists(t))
+ } else if (os_path_exists(t)) {
addfile(&ga, t, flags);
+ }
xfree(t);
}
@@ -1327,7 +1348,7 @@ void addfile(
if (!(flags & EW_NOTFOUND)
&& ((flags & EW_ALLLINKS)
? !os_fileinfo_link((char *)f, &file_info)
- : !os_file_exists(f))) {
+ : !os_path_exists(f))) {
return;
}
@@ -1631,30 +1652,37 @@ bool vim_isAbsName(char_u *name)
/// Save absolute file name to "buf[len]".
///
-/// @param fname is the filename to evaluate
-/// @param[out] buf is the buffer for returning the absolute path for `fname`
-/// @param len is the length of `buf`
-/// @param force is a flag to force expanding even if the path is absolute
+/// @param fname filename to evaluate
+/// @param[out] buf contains `fname` absolute path, or:
+/// - truncated `fname` if longer than `len`
+/// - unmodified `fname` if absolute path fails or is a URL
+/// @param len length of `buf`
+/// @param force flag to force expanding even if the path is absolute
///
/// @return FAIL for failure, OK otherwise
int vim_FullName(const char *fname, char *buf, size_t len, bool force)
FUNC_ATTR_NONNULL_ARG(2)
{
- int retval = OK;
- int url;
-
*buf = NUL;
- if (fname == NULL)
+ if (fname == NULL) {
return FAIL;
+ }
- url = path_with_url(fname);
- if (!url)
- retval = path_get_absolute_path((char_u *)fname, (char_u *)buf, len, force);
- if (url || retval == FAIL) {
- /* something failed; use the file name (truncate when too long) */
+ if (strlen(fname) > (len - 1)) {
+ xstrlcpy(buf, fname, len); // truncate
+ return FAIL;
+ }
+
+ if (path_with_url(fname)) {
xstrlcpy(buf, fname, len);
+ return OK;
}
- return retval;
+
+ int rv = path_get_absolute_path((char_u *)fname, (char_u *)buf, len, force);
+ if (rv == FAIL) {
+ xstrlcpy(buf, fname, len); // something failed; use the filename
+ }
+ return rv;
}
/// Get the full resolved path for `fname`
@@ -2098,7 +2126,6 @@ int path_full_dir_name(char *directory, char *buffer, size_t len)
}
// Append to_append to path with a slash in between.
-// Append to_append to path with a slash in between.
int append_path(char *path, const char *to_append, size_t max_len)
{
size_t current_length = strlen(path);
@@ -2115,7 +2142,7 @@ int append_path(char *path, const char *to_append, size_t max_len)
}
// Glue both paths with a slash.
- if (current_length > 0 && path[current_length-1] != '/') {
+ if (current_length > 0 && !vim_ispathsep_nocolon(path[current_length-1])) {
current_length += 1; // Count the trailing slash.
// +1 for the NUL at the end.
@@ -2123,7 +2150,7 @@ int append_path(char *path, const char *to_append, size_t max_len)
return FAIL;
}
- STRCAT(path, "/");
+ STRCAT(path, PATHSEPSTR);
}
// +1 for the NUL at the end.
@@ -2161,7 +2188,8 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf,
relative_directory[0] = '/';
relative_directory[1] = NUL;
} else {
- STRNCPY(relative_directory, fname, p-fname);
+ assert(p >= fname);
+ memcpy(relative_directory, fname, (size_t)(p - fname));
relative_directory[p-fname] = NUL;
}
end_of_path = (char *) (p + 1);
@@ -2181,9 +2209,16 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf,
/// Check if the given file is absolute.
///
-/// This just checks if the file name starts with '/' or '~'.
/// @return `TRUE` if "fname" is absolute.
int path_is_absolute_path(const char_u *fname)
{
+#ifdef WIN32
+ // A name like "d:/foo" and "//server/share" is absolute
+ return ((isalpha(fname[0]) && fname[1] == ':'
+ && vim_ispathsep_nocolon(fname[2]))
+ || (vim_ispathsep_nocolon(fname[0]) && fname[0] == fname[1]));
+#else
+ // UNIX: This just checks if the file name starts with '/' or '~'.
return *fname == '/' || *fname == '~';
+#endif
}