diff options
Diffstat (limited to 'src/nvim/path.c')
-rw-r--r-- | src/nvim/path.c | 212 |
1 files changed, 105 insertions, 107 deletions
diff --git a/src/nvim/path.c b/src/nvim/path.c index a0b09bcec2..a5cec6772f 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -8,9 +8,9 @@ #include "nvim/ascii.h" #include "nvim/charset.h" +#include "nvim/cmdexpand.h" #include "nvim/eval.h" #include "nvim/ex_docmd.h" -#include "nvim/ex_getln.h" #include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/garray.h" @@ -33,7 +33,7 @@ #include "nvim/vim.h" #include "nvim/window.h" -#define URL_SLASH 1 // path_is_url() has found "://" +#define URL_SLASH 1 // path_is_url() has found ":/" #define URL_BACKSLASH 2 // path_is_url() has found ":\\" #ifdef gen_expand_wildcards @@ -62,7 +62,7 @@ FileComparison path_full_compare(char *const s1, char *const s2, const bool chec FileID file_id_1, file_id_2; if (expandenv) { - expand_env((char_u *)s1, (char_u *)exp1, MAXPATHL); + expand_env(s1, exp1, MAXPATHL); } else { STRLCPY(exp1, s1, MAXPATHL); } @@ -104,7 +104,7 @@ char *path_tail(const char *fname) return ""; } - const char *tail = (char *)get_past_head((char_u *)fname); + const char *tail = get_past_head(fname); const char *p = tail; // Find last part of path. while (*p != NUL) { @@ -130,7 +130,7 @@ char *path_tail_with_sep(char *fname) assert(fname != NULL); // Don't remove the '/' from "c:/file". - char *past_head = (char *)get_past_head((char_u *)fname); + char *past_head = get_past_head(fname); char *tail = path_tail(fname); while (tail > past_head && after_pathsep(fname, tail)) { tail--; @@ -150,7 +150,7 @@ char *path_tail_with_sep(char *fname) const char_u *invocation_path_tail(const char_u *invocation, size_t *len) FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) { - const char_u *tail = get_past_head((char_u *)invocation); + const char_u *tail = (char_u *)get_past_head((char *)invocation); const char_u *p = tail; while (*p != NUL && *p != ' ') { bool was_sep = vim_ispathsep_nocolon(*p); @@ -215,28 +215,26 @@ bool is_path_head(const char_u *path) /// 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(const char_u *path) +char *get_past_head(const char *path) { - const char_u *retval = path; + const char *retval = path; #ifdef WIN32 // May skip "c:" - if (is_path_head(path)) { + if (is_path_head((char_u *)path)) { retval = path + 2; } #endif while (vim_ispathsep(*retval)) { - ++retval; + retval++; } - return (char_u *)retval; + return (char *)retval; } -/* - * Return TRUE if 'c' is a path separator. - * Note that for MS-Windows this includes the colon. - */ +/// Return true if 'c' is a path separator. +/// Note that for MS-Windows this includes the colon. int vim_ispathsep(int c) { #ifdef UNIX @@ -262,9 +260,7 @@ int vim_ispathsep_nocolon(int c) ; } -/* - * return TRUE if 'c' is a path list separator. - */ +/// return true if 'c' is a path list separator. int vim_ispathlistsep(int c) { #ifdef UNIX @@ -314,16 +310,14 @@ void shorten_dir_len(char_u *str, int trim_len) /// Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname" /// It's done in-place. -void shorten_dir(char_u *str) +void shorten_dir(char *str) { - shorten_dir_len(str, 1); + shorten_dir_len((char_u *)str, 1); } -/* - * Return TRUE if the directory of "fname" exists, FALSE otherwise. - * Also returns TRUE if there is no directory name. - * "fname" must be writable!. - */ +/// Return true if the directory of "fname" exists, false otherwise. +/// Also returns true if there is no directory name. +/// "fname" must be writable!. bool dir_of_file_exists(char_u *fname) { char *p = path_tail_with_sep((char *)fname); @@ -332,7 +326,7 @@ bool dir_of_file_exists(char_u *fname) } char c = *p; *p = NUL; - bool retval = os_isdir(fname); + bool retval = os_isdir((char *)fname); *p = c; return retval; } @@ -376,16 +370,16 @@ int path_fnamencmp(const char *const fname1, const char *const fname2, size_t le const char *p1 = fname1; const char *p2 = fname2; while (len > 0) { - c1 = utf_ptr2char((const char_u *)p1); - c2 = utf_ptr2char((const char_u *)p2); + c1 = utf_ptr2char(p1); + 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)) { break; } - len -= (size_t)utfc_ptr2len((const char_u *)p1); - p1 += utfc_ptr2len((const char_u *)p1); - p2 += utfc_ptr2len((const char_u *)p2); + 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; #else @@ -637,7 +631,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, 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((char *)path_end)) { *p++ = *path_end++; } else if (vim_ispathsep_nocolon(*path_end)) { if (e != NULL) { @@ -663,16 +657,16 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, // Now we have one wildcard component between "s" and "e". /* Remove backslashes between "wildoff" and the start of the wildcard * component. */ - for (p = buf + wildoff; p < s; ++p) { - if (rem_backslash(p)) { + for (p = buf + wildoff; p < s; p++) { + if (rem_backslash((char *)p)) { STRMOVE(p, p + 1); - --e; - --s; + e--; + s--; } } // Check for "**" between "s" and "e". - for (p = s; p < e; ++p) { + for (p = s; p < e; p++) { if (p[0] == '*' && p[1] == '*') { starstar = true; } @@ -695,11 +689,11 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, regmatch.rm_ic = true; // Always ignore case on Windows. #endif if (flags & (EW_NOERROR | EW_NOTWILD)) { - ++emsg_silent; + emsg_silent++; } regmatch.regprog = vim_regcomp(pat, RE_MAGIC); if (flags & (EW_NOERROR | EW_NOTWILD)) { - --emsg_silent; + emsg_silent--; } xfree(pat); @@ -725,7 +719,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, // Find all matching entries. char_u *name; scandir_next_with_dots(NULL); // initialize - while ((name = (char_u *)scandir_next_with_dots(&dir)) != NULL) { + while (!got_int && (name = (char_u *)scandir_next_with_dots(&dir)) != NULL) { if ((name[0] != '.' || starts_with_dot || ((flags & EW_DODOT) @@ -742,9 +736,9 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, * find matches. */ STRCPY(buf + len, "/**"); STRCPY(buf + len + 3, path_end); - ++stardepth; + stardepth++; (void)do_path_expand(gap, buf, len + 1, flags, true); - --stardepth; + stardepth--; } STRCPY(buf + len, path_end); @@ -758,7 +752,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, // no more wildcards, check if there is a match // remove backslashes for the remaining components only if (*path_end != NUL) { - backslash_halve(buf + len + 1); + backslash_halve((char *)buf + len + 1); } // add existing file or symbolic link if ((flags & EW_ALLLINKS) ? os_fileinfo_link((char *)buf, &file_info) @@ -774,8 +768,10 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, xfree(buf); vim_regfree(regmatch.regprog); + // When interrupted the matches probably won't be used and sorting can be + // slow, thus skip it. size_t matches = (size_t)(gap->ga_len - start_len); - if (matches > 0) { + if (matches > 0 && !got_int) { qsort(((char_u **)gap->ga_data) + start_len, matches, sizeof(char_u *), pstrcmp); } @@ -804,10 +800,8 @@ static int find_previous_pathsep(char_u *path, char_u **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]". - */ +/// 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 bool is_unique(char_u *maybe_unique, garray_T *gap, int i) { char_u **other_paths = (char_u **)gap->ga_data; @@ -841,7 +835,7 @@ static bool is_unique(char_u *maybe_unique, garray_T *gap, int i) */ 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 *path_option = *curbuf->b_p_path == NUL ? p_path : (char_u *)curbuf->b_p_path; char_u *buf = xmalloc(MAXPATHL); while (*path_option != NUL) { @@ -1141,16 +1135,14 @@ static int expand_in_path(garray_T *const gap, char_u *const pattern, const int if (flags & EW_ADDSLASH) { glob_flags |= WILD_ADD_SLASH; } - globpath(paths, pattern, gap, glob_flags); + globpath((char *)paths, (char *)pattern, gap, glob_flags); xfree(paths); return gap->ga_len; } -/* - * Return TRUE if "p" contains what looks like an environment variable. - * Allowing for escaping. - */ +/// Return true if "p" contains what looks like an environment variable. +/// Allowing for escaping. static bool has_env_var(char_u *p) { for (; *p; MB_PTR_ADV(p)) { @@ -1165,7 +1157,7 @@ static bool has_env_var(char_u *p) #ifdef SPECIAL_WILDCHAR -// Return TRUE if "p" contains a special wildcard character, one that Vim +// Return true if "p" contains a special wildcard character, one that Vim // cannot expand, requires using a shell. static bool has_special_wildchar(char_u *p) { @@ -1254,7 +1246,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i */ ga_init(&ga, (int)sizeof(char_u *), 30); - for (int i = 0; i < num_pat; ++i) { + for (int i = 0; i < num_pat && !got_int; i++) { add_pat = -1; p = (char_u *)pat[i]; @@ -1320,7 +1312,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i } if (add_pat == -1 || (add_pat == 0 && (flags & EW_NOTFOUND))) { - char_u *t = backslash_halve_save(p); + char_u *t = (char_u *)backslash_halve_save((char *)p); /* When EW_NOTFOUND is used, always add files and dirs. Makes * "vim c:/" work. */ @@ -1363,9 +1355,7 @@ void FreeWild(int count, char **files) xfree(files); } -/* - * Return TRUE if we can expand this backtick thing here. - */ +/// Return true if we can expand this backtick thing here. static int vim_backtick(char_u *p) { return *p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`'; @@ -1401,7 +1391,7 @@ static int expand_backtick(garray_T *gap, char_u *pat, int flags) cmd = skipwhite(cmd); // skip over white space p = cmd; while (*p != NUL && *p != '\r' && *p != '\n') { // skip over entry - ++p; + p++; } // add an entry if it is not empty if (p > cmd) { @@ -1409,11 +1399,11 @@ static int expand_backtick(garray_T *gap, char_u *pat, int flags) *p = NUL; addfile(gap, (char_u *)cmd, flags); *p = i; - ++cnt; + cnt++; } cmd = p; while (*cmd != NUL && (*cmd == '\r' || *cmd == '\n')) { - ++cmd; + cmd++; } } @@ -1482,7 +1472,7 @@ void addfile(garray_T *gap, char_u *f, int flags) } #endif - isdir = os_isdir(f); + isdir = os_isdir((char *)f); if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE))) { return; } @@ -1656,12 +1646,12 @@ void simplify_filename(char_u *filename) *p = NUL; } else { if (p > start && tail[-1] == '.') { - --p; + p--; } STRMOVE(p, tail); // strip previous component } - --components; + components--; } } else if (p == start && !relative) { // leading "/.." or "/../" STRMOVE(p, tail); // strip ".." or "../" @@ -1682,7 +1672,7 @@ void simplify_filename(char_u *filename) static char *eval_includeexpr(const char *const ptr, const size_t len) { set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); - char *res = eval_to_string_safe((char *)curbuf->b_p_inex, NULL, + char *res = eval_to_string_safe(curbuf->b_p_inex, NULL, was_set_insecurely(curwin, "includeexpr", OPT_LOCAL)); set_vim_var_string(VV_FNAME, NULL, 0); return res; @@ -1724,7 +1714,7 @@ char_u *find_file_name_in_path(char_u *ptr, size_t len, int options, long count, ptr = tofree; len = STRLEN(ptr); file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, - TRUE, rel_fname); + true, rel_fname); } } if (file_name == NULL && (options & FNAME_MESS)) { @@ -1738,7 +1728,7 @@ char_u *find_file_name_in_path(char_u *ptr, size_t len, int options, long count, * 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_name = find_file_in_path(ptr, len, options, false, rel_fname); } } else { file_name = vim_strnsave(ptr, len); @@ -1749,12 +1739,26 @@ char_u *find_file_name_in_path(char_u *ptr, size_t len, int options, long count, return file_name; } -// Check if the "://" of a URL is at the pointer, return URL_SLASH. +/// 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 +bool path_has_drive_letter(const char *p) + FUNC_ATTR_NONNULL_ALL +{ + return strlen(p) >= 2 + && ASCII_ISALPHA(p[0]) + && (p[1] == ':' || p[1] == '|') + && (strlen(p) == 2 || ((p[2] == '/') | (p[2] == '\\') | (p[2] == '?') | (p[2] == '#'))); +} + +// 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(const char *p) { - if (strncmp(p, "://", 3) == 0) { + // In the spec ':' is enough to recognize a scheme + // https://url.spec.whatwg.org/#scheme-state + if (strncmp(p, ":/", 2) == 0) { return URL_SLASH; } else if (strncmp(p, ":\\\\", 3) == 0) { return URL_BACKSLASH; @@ -1779,6 +1783,10 @@ int path_with_url(const char *fname) return 0; } + if (path_has_drive_letter(fname)) { + return 0; + } + // check body: alpha or dash for (p = fname + 1; (isalpha(*p) || (*p == '-')); p++) {} @@ -1787,7 +1795,7 @@ int path_with_url(const char *fname) return 0; } - // "://" or ":\\" must follow + // ":/" or ":\\" must follow return path_is_url(p); } @@ -1800,9 +1808,7 @@ bool path_with_extension(const char *path, const char *extension) return strcmp(last_dot + 1, extension) == 0; } -/* - * Return TRUE if "name" is a full (absolute) path name or URL. - */ +/// Return true if "name" is a full (absolute) path name or URL. bool vim_isAbsName(char_u *name) { return path_with_url((char *)name) != 0 || path_is_absolute(name); @@ -1839,7 +1845,7 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force) return OK; } - int rv = path_to_absolute((char_u *)fname, (char_u *)buf, len, force); + int rv = path_to_absolute(fname, buf, len, force); if (rv == FAIL) { xstrlcpy(buf, fname, len); // something failed; use the filename } @@ -1898,7 +1904,7 @@ void path_fix_case(char *name) } // Open the directory where the file is located. - char *slash = (char *)STRRCHR(name, '/'); + char *slash = strrchr(name, '/'); char *tail; Directory dir; bool ok; @@ -1939,21 +1945,17 @@ void path_fix_case(char *name) os_closedir(&dir); } -/* - * Return TRUE if "p" points to just after a path separator. - * Takes care of multi-byte characters. - * "b" must point to the start of the file name - */ +/// Return true if "p" points to just after a path separator. +/// Takes care of multi-byte characters. +/// "b" must point to the start of the file name int after_pathsep(const char *b, const char *p) { return p > b && vim_ispathsep(p[-1]) && utf_head_off((char_u *)b, (char_u *)p - 1) == 0; } -/* - * Return TRUE if file names "f1" and "f2" are in the same directory. - * "f1" may be a short name, "f2" must be a full path. - */ +/// Return true if file names "f1" and "f2" are in the same directory. +/// "f1" may be a short name, "f2" must be a full path. bool same_directory(char_u *f1, char_u *f2) { char ffname[MAXPATHL]; @@ -1965,7 +1967,7 @@ bool same_directory(char_u *f1, char_u *f2) return false; } - (void)vim_FullName((char *)f1, (char *)ffname, MAXPATHL, FALSE); + (void)vim_FullName((char *)f1, (char *)ffname, MAXPATHL, false); t1 = path_tail_with_sep(ffname); t2 = path_tail_with_sep((char *)f2); return t1 - ffname == (char_u *)t2 - f2 @@ -2133,10 +2135,11 @@ int expand_wildcards_eval(char_u **pat, int *num_file, char ***file, int flags) if (*exp_pat == '%' || *exp_pat == '#' || *exp_pat == '<') { emsg_off++; - eval_pat = eval_vars((char_u *)exp_pat, (char_u *)exp_pat, &usedlen, NULL, &ignored_msg, NULL); + eval_pat = eval_vars((char_u *)exp_pat, (char_u *)exp_pat, &usedlen, NULL, &ignored_msg, NULL, + true); emsg_off--; if (eval_pat != NULL) { - exp_pat = (char *)concat_str(eval_pat, (char_u *)exp_pat + usedlen); + exp_pat = concat_str((char *)eval_pat, exp_pat + usedlen); } } @@ -2192,7 +2195,7 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int ffname = (char_u *)FullName_save((*files)[i], false); assert((*files)[i] != NULL); assert(ffname != NULL); - if (match_file_list(p_wig, (char_u *)(*files)[i], ffname)) { + if (match_file_list((char_u *)p_wig, (char_u *)(*files)[i], ffname)) { // remove this matching file from the list xfree((*files)[i]); for (j = i; j + 1 < *num_files; j++) { @@ -2205,17 +2208,14 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int } } - // // Move the names where 'suffixes' match to the end. - // + // Skip when interrupted, the result probably won't be used. assert(*num_files == 0 || *files != NULL); - if (*num_files > 1) { + if (*num_files > 1 && !got_int) { non_suf_match = 0; for (i = 0; i < *num_files; i++) { if (!match_suffix((char_u *)(*files)[i])) { - // // Move the name without matching suffix to the front of the list. - // p = (char_u *)(*files)[i]; for (j = i; j > non_suf_match; j--) { (*files)[j] = (*files)[j - 1]; @@ -2234,9 +2234,7 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int return retval; } -/* - * Return TRUE if "fname" matches with an entry in 'suffixes'. - */ +/// Return true if "fname" matches with an entry in 'suffixes'. int match_suffix(char_u *fname) { #define MAXSUFLEN 30 // maximum length of a file suffix @@ -2355,20 +2353,20 @@ int append_path(char *path, const char *to_append, size_t max_len) /// @param force also expand when "fname" is already absolute. /// /// @return FAIL for failure, OK for success. -static int path_to_absolute(const char_u *fname, char_u *buf, size_t len, int force) +static int path_to_absolute(const char *fname, char *buf, size_t len, int force) { - char_u *p; + char *p; *buf = NUL; char *relative_directory = xmalloc(len); char *end_of_path = (char *)fname; // expand it if forced or not an absolute path - if (force || !path_is_absolute(fname)) { - p = STRRCHR(fname, '/'); + if (force || !path_is_absolute((char_u *)fname)) { + p = strrchr(fname, '/'); #ifdef WIN32 if (p == NULL) { - p = STRRCHR(fname, '\\'); + p = strrchr(fname, '\\'); } #endif if (p != NULL) { @@ -2382,24 +2380,24 @@ static int path_to_absolute(const char_u *fname, char_u *buf, size_t len, int fo memcpy(relative_directory, fname, (size_t)(p - fname)); relative_directory[p - fname] = NUL; } - end_of_path = (char *)(p + 1); + end_of_path = p + 1; } else { relative_directory[0] = NUL; end_of_path = (char *)fname; } - if (FAIL == path_full_dir_name(relative_directory, (char *)buf, len)) { + if (FAIL == path_full_dir_name(relative_directory, buf, len)) { xfree(relative_directory); return FAIL; } } xfree(relative_directory); - return append_path((char *)buf, end_of_path, len); + return append_path(buf, end_of_path, len); } /// Check if file `fname` is a full (absolute) path. /// -/// @return `TRUE` if "fname" is absolute. +/// @return `true` if "fname" is absolute. int path_is_absolute(const char_u *fname) { #ifdef WIN32 |