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.c212
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