diff options
Diffstat (limited to 'src/nvim/path.c')
-rw-r--r-- | src/nvim/path.c | 157 |
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(®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; - 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(®match, 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(®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; + 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 } |