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.c166
1 files changed, 85 insertions, 81 deletions
diff --git a/src/nvim/path.c b/src/nvim/path.c
index e4c2253357..c7212c7ade 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1,8 +1,4 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
#include <assert.h>
-#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
@@ -11,32 +7,33 @@
#include <string.h>
#include "auto/config.h"
-#include "nvim/ascii.h"
-#include "nvim/buffer_defs.h"
+#include "nvim/ascii_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/func_attr.h"
#include "nvim/garray.h"
+#include "nvim/garray_defs.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
-#include "nvim/macros.h"
+#include "nvim/macros_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
-#include "nvim/os/fs_defs.h"
+#include "nvim/option_vars.h"
+#include "nvim/os/fs.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
-#include "nvim/pos.h"
#include "nvim/regexp.h"
#include "nvim/strings.h"
-#include "nvim/types.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
#include "nvim/window.h"
enum {
@@ -620,7 +617,7 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
static int stardepth = 0; // depth for "**" expansion
// Expanding "**" may take a long time, check for CTRL-C.
- if (stardepth > 0) {
+ if (stardepth > 0 && !(flags & EW_NOBREAK)) {
os_breakcheck();
if (got_int) {
return 0;
@@ -641,7 +638,7 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
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((char *)path_end)) {
+ if (path_end >= path + wildoff && rem_backslash(path_end)) {
*p++ = *path_end++;
} else if (vim_ispathsep_nocolon(*path_end)) {
if (e != NULL) {
@@ -649,14 +646,16 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
}
s = p + 1;
} else if (path_end >= path + wildoff
+#ifdef MSWIN
+ && vim_strchr("*?[~", (uint8_t)(*path_end)) != NULL
+#else
&& (vim_strchr("*?[{~$", (uint8_t)(*path_end)) != NULL
-#ifndef MSWIN
- || (!p_fic && (flags & EW_ICASE) && mb_isalpha(utf_ptr2char((char *)path_end)))
+ || (!p_fic && (flags & EW_ICASE) && mb_isalpha(utf_ptr2char(path_end))))
#endif
- )) { // NOLINT(whitespace/parens)
+ ) { // NOLINT(whitespace/parens)
e = p;
}
- len = (size_t)(utfc_ptr2len((char *)path_end));
+ len = (size_t)(utfc_ptr2len(path_end));
memcpy(p, path_end, len);
p += len;
path_end += len;
@@ -701,7 +700,8 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
if (flags & (EW_NOERROR | EW_NOTWILD)) {
emsg_silent++;
}
- regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
+ bool nobreak = (flags & EW_NOBREAK);
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC | (nobreak ? RE_NOBREAK : 0));
if (flags & (EW_NOERROR | EW_NOTWILD)) {
emsg_silent--;
}
@@ -727,14 +727,14 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
char *dirpath = (*buf == NUL ? "." : buf);
if (os_file_is_readable(dirpath) && os_scandir(&dir, dirpath)) {
// Find all matching entries.
- char *name;
+ const char *name;
scandir_next_with_dots(NULL); // initialize
- while (!got_int && (name = (char *)scandir_next_with_dots(&dir)) != NULL) {
+ while (!got_int && (name = scandir_next_with_dots(&dir)) != NULL) {
if ((name[0] != '.'
|| starts_with_dot
|| ((flags & EW_DODOT)
&& name[1] != NUL
- && (name[1] != '.' || name[2] != NUL))) // -V557
+ && (name[1] != '.' || name[2] != NUL)))
&& ((regmatch.regprog != NULL && vim_regexec(&regmatch, name, 0))
|| ((flags & EW_NOTWILD)
&& path_fnamencmp(path + (s - buf), name, (size_t)(e - s)) == 0))) {
@@ -810,7 +810,7 @@ static int find_previous_pathsep(char *path, char **psep)
}
/// 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]".
+/// "maybe_unique" is the end portion of "((char **)gap->ga_data)[i]".
static bool is_unique(char *maybe_unique, garray_T *gap, int i)
{
char **other_paths = gap->ga_data;
@@ -879,7 +879,7 @@ static void expand_path_option(char *curdir, garray_T *gap)
}
STRMOVE(buf + len + 1, buf);
STRCPY(buf, curdir);
- buf[len] = (char_u)PATHSEP;
+ buf[len] = PATHSEP;
simplify_filename(buf);
}
@@ -973,7 +973,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern)
for (int i = 0; i < gap->ga_len && !got_int; i++) {
char *path = fnames[i];
int is_in_curdir;
- char *dir_end = (char *)gettail_dir((const char *)path);
+ const char *dir_end = gettail_dir(path);
char *pathsep_p;
char *path_cutoff;
@@ -993,7 +993,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern)
if (pattern[0] == '*' && pattern[1] == '*'
&& vim_ispathsep_nocolon(pattern[2])
&& path_cutoff != NULL
- && vim_regexec(&regmatch, path_cutoff, (colnr_T)0)
+ && vim_regexec(&regmatch, path_cutoff, 0)
&& is_unique(path_cutoff, gap, i)) {
sort_again = true;
memmove(path, path_cutoff, strlen(path_cutoff) + 1);
@@ -1002,7 +1002,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern)
// 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)
+ if (vim_regexec(&regmatch, pathsep_p + 1, 0)
&& is_unique(pathsep_p + 1, gap, i)
&& path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) {
sort_again = true;
@@ -1162,7 +1162,7 @@ static bool has_env_var(char *p)
// Return true if "p" contains a special wildcard character, one that Vim
// cannot expand, requires using a shell.
-static bool has_special_wildchar(char *p)
+static bool has_special_wildchar(char *p, int flags)
{
for (; *p; MB_PTR_ADV(p)) {
// Disallow line break characters.
@@ -1173,6 +1173,10 @@ static bool has_special_wildchar(char *p)
if (*p == '\\' && p[1] != NUL && p[1] != '\r' && p[1] != '\n') {
p++;
} else if (vim_strchr(SPECIAL_WILDCHAR, (uint8_t)(*p)) != NULL) {
+ // Need a shell for curly braces only when including non-existing files.
+ if (*p == '{' && !(flags & EW_NOTFOUND)) {
+ continue;
+ }
// A { must be followed by a matching }.
if (*p == '{' && vim_strchr(p, '}') == NULL) {
continue;
@@ -1232,7 +1236,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i
// avoids starting the shell for each argument separately.
// For `=expr` do use the internal function.
for (int i = 0; i < num_pat; i++) {
- if (has_special_wildchar(pat[i])
+ if (has_special_wildchar(pat[i], flags)
&& !(vim_backtick(pat[i]) && pat[i][1] == '=')) {
return os_expand_wildcards(num_pat, pat, num_file, file, flags);
}
@@ -1368,10 +1372,10 @@ static int expand_backtick(garray_T *gap, char *pat, int flags)
int cnt = 0;
// Create the command: lop off the backticks.
- char *cmd = xstrnsave(pat + 1, strlen(pat) - 2);
+ char *cmd = xmemdupz(pat + 1, strlen(pat) - 2);
if (*cmd == '=') { // `={expr}`: Expand expression
- buffer = eval_to_string(cmd + 1, &p, true);
+ buffer = eval_to_string(cmd + 1, true);
} else {
buffer = get_cmd_output(cmd, NULL, (flags & EW_SILENT) ? kShellOptSilent : 0, NULL);
}
@@ -1498,11 +1502,10 @@ void addfile(garray_T *gap, char *f, int flags)
void simplify_filename(char *filename)
{
int components = 0;
- char *p, *tail, *start;
bool stripping_disabled = false;
bool relative = true;
- p = filename;
+ char *p = filename;
#ifdef BACKSLASH_IN_FILENAME
if (p[0] != NUL && p[1] == ':') { // skip "x:"
p += 2;
@@ -1515,7 +1518,7 @@ void simplify_filename(char *filename)
p++;
} while (vim_ispathsep(*p));
}
- start = p; // remember start after "c:/" or "/" or "///"
+ char *start = p; // remember start after "c:/" or "/" or "///"
do {
// At this point "p" is pointing to the char following a single "/"
@@ -1531,7 +1534,7 @@ void simplify_filename(char *filename)
// and there is no trailing path separator, either strip "/." if
// we are after "start", or strip "." if we are at the beginning
// of an absolute path name.
- tail = p + 1;
+ char *tail = p + 1;
if (p[1] != NUL) {
while (vim_ispathsep(*tail)) {
MB_PTR_ADV(tail);
@@ -1544,21 +1547,20 @@ void simplify_filename(char *filename)
} else if (p[0] == '.' && p[1] == '.'
&& (vim_ispathsep(p[2]) || p[2] == NUL)) {
// Skip to after ".." or "../" or "..///".
- tail = p + 2;
+ char *tail = p + 2;
while (vim_ispathsep(*tail)) {
MB_PTR_ADV(tail);
}
if (components > 0) { // strip one preceding component
bool do_strip = false;
- char saved_char;
// Don't strip for an erroneous file name.
if (!stripping_disabled) {
// If the preceding component does not exist in the file
// system, we strip it. On Unix, we don't accept a symbolic
// link that refers to a non-existent file.
- saved_char = p[-1];
+ char saved_char = p[-1];
p[-1] = NUL;
FileInfo file_info;
if (!os_fileinfo_link(filename, &file_info)) {
@@ -1661,10 +1663,15 @@ void simplify_filename(char *filename)
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);
- char *res = eval_to_string_safe(curbuf->b_p_inex, NULL,
+ 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, "includeexpr", OPT_LOCAL));
+
set_vim_var_string(VV_FNAME, NULL, 0);
+ current_sctx = save_sctx;
return res;
}
@@ -1690,8 +1697,11 @@ char *find_file_name_in_path(char *ptr, size_t len, int options, long count, cha
}
if (options & FNAME_EXP) {
- file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, true,
- rel_fname);
+ 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).
@@ -1702,7 +1712,7 @@ char *find_file_name_in_path(char *ptr, size_t len, int options, long count, cha
ptr = tofree;
len = strlen(ptr);
file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
- true, rel_fname);
+ true, rel_fname, &file_to_find, &search_ctx);
}
}
if (file_name == NULL && (options & FNAME_MESS)) {
@@ -1716,9 +1726,12 @@ char *find_file_name_in_path(char *ptr, size_t len, int options, long count, cha
// 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,
+ &file_to_find, &search_ctx);
}
+
+ xfree(file_to_find);
+ vim_findfile_cleanup(search_ctx);
} else {
file_name = xstrnsave(ptr, len);
}
@@ -1794,11 +1807,11 @@ bool path_with_extension(const char *path, const char *extension)
if (!last_dot) {
return false;
}
- return strcmp(last_dot + 1, extension) == 0;
+ return mb_strcmp_ic((bool)p_fic, last_dot + 1, extension) == 0;
}
/// Return true if "name" is a full (absolute) path name or URL.
-bool vim_isAbsName(char *name)
+bool vim_isAbsName(const char *name)
{
return path_with_url(name) != 0 || path_is_absolute(name);
}
@@ -1859,7 +1872,7 @@ char *fix_fname(const char *fname)
#ifdef UNIX
return FullName_save(fname, true);
#else
- if (!vim_isAbsName((char *)fname)
+ if (!vim_isAbsName(fname)
|| strstr(fname, "..") != NULL
|| strstr(fname, "//") != NULL
# ifdef BACKSLASH_IN_FILENAME
@@ -1911,8 +1924,8 @@ void path_fix_case(char *name)
return;
}
- char *entry;
- while ((entry = (char *)os_scandir_next(&dir))) {
+ const char *entry;
+ while ((entry = os_scandir_next(&dir))) {
// Only accept names that differ in case and are the same byte
// length. TODO: accept different length name.
if (STRICMP(tail, entry) == 0 && strlen(tail) == strlen(entry)) {
@@ -1923,7 +1936,7 @@ void path_fix_case(char *name)
xstrlcpy(newname + (tail - name), entry,
(size_t)(MAXPATHL - (tail - name) + 1));
FileInfo file_info_new;
- if (os_fileinfo_link((char *)newname, &file_info_new)
+ if (os_fileinfo_link(newname, &file_info_new)
&& os_fileinfo_id_equal(&file_info, &file_info_new)) {
STRCPY(tail, entry);
break;
@@ -1956,11 +1969,11 @@ bool same_directory(char *f1, char *f2)
return false;
}
- (void)vim_FullName(f1, (char *)ffname, MAXPATHL, false);
+ (void)vim_FullName(f1, ffname, MAXPATHL, false);
t1 = path_tail_with_sep(ffname);
t2 = path_tail_with_sep(f2);
return t1 - ffname == t2 - f2
- && pathcmp((char *)ffname, f2, (int)(t1 - ffname)) == 0;
+ && pathcmp(ffname, f2, (int)(t1 - ffname)) == 0;
}
// Compare path "p[]" to "q[]".
@@ -1969,12 +1982,11 @@ bool same_directory(char *f1, char *f2)
int pathcmp(const char *p, const char *q, int maxlen)
{
int i, j;
- int c1, c2;
const char *s = NULL;
for (i = 0, j = 0; maxlen < 0 || (i < maxlen && j < maxlen);) {
- c1 = utf_ptr2char(p + i);
- c2 = utf_ptr2char(q + j);
+ int c1 = utf_ptr2char(p + i);
+ int c2 = utf_ptr2char(q + j);
// End of "p": check if "q" also ends or just has a slash.
if (c1 == NUL) {
@@ -2016,12 +2028,12 @@ int pathcmp(const char *p, const char *q, int maxlen)
return 0;
}
- c1 = utf_ptr2char(s + i);
- c2 = utf_ptr2char(s + i + utfc_ptr2len(s + i));
+ int c1 = utf_ptr2char(s + i);
+ int c2 = utf_ptr2char(s + i + utfc_ptr2len(s + i));
// ignore a trailing slash, but not "//" or ":/"
if (c2 == NUL
&& i > 0
- && !after_pathsep((char *)s, (char *)s + i)
+ && !after_pathsep(s, s + i)
#ifdef BACKSLASH_IN_FILENAME
&& (c1 == '/' || c1 == '\\')
#else
@@ -2075,17 +2087,17 @@ char *path_shorten_fname(char *full_path, char *dir_name)
assert(dir_name != NULL);
size_t len = strlen(dir_name);
- // If dir_name is a path head, full_path can always be made relative.
- if (len == (size_t)path_head_length() && is_path_head(dir_name)) {
- return full_path + len;
- }
-
// If full_path and dir_name do not match, it's impossible to make one
// relative to the other.
if (path_fnamencmp(dir_name, full_path, len) != 0) {
return NULL;
}
+ // If dir_name is a path head, full_path can always be made relative.
+ if (len == (size_t)path_head_length() && is_path_head(dir_name)) {
+ return full_path + len;
+ }
+
char *p = full_path + len;
// If *p is not pointing to a path separator, this means that full_path's
@@ -2117,7 +2129,7 @@ int expand_wildcards_eval(char **pat, int *num_file, char ***file, int flags)
int ret = FAIL;
char *eval_pat = NULL;
char *exp_pat = *pat;
- char *ignored_msg;
+ const char *ignored_msg;
size_t usedlen;
const bool is_cur_alt_file = *exp_pat == '%' || *exp_pat == '#';
bool star_follows = false;
@@ -2172,12 +2184,7 @@ int expand_wildcards_eval(char **pat, int *num_file, char ***file, int flags)
/// NULL or points to "".
int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int flags)
{
- int retval;
- int i, j;
- char *p;
- int non_suf_match; // number without matching suffix
-
- retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags);
+ int retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags);
// When keeping all matches, return here
if ((flags & EW_KEEPALL) || retval == FAIL) {
@@ -2186,18 +2193,16 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int
// Remove names that match 'wildignore'.
if (*p_wig) {
- char *ffname;
-
// check all files in (*files)[]
assert(*num_files == 0 || *files != NULL);
- for (i = 0; i < *num_files; i++) {
- ffname = FullName_save((*files)[i], false);
+ for (int i = 0; i < *num_files; i++) {
+ char *ffname = FullName_save((*files)[i], false);
assert((*files)[i] != NULL);
assert(ffname != NULL);
if (match_file_list(p_wig, (*files)[i], ffname)) {
// remove this matching file from the list
xfree((*files)[i]);
- for (j = i; j + 1 < *num_files; j++) {
+ for (int j = i; j + 1 < *num_files; j++) {
(*files)[j] = (*files)[j + 1];
}
(*num_files)--;
@@ -2211,12 +2216,12 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int
// Skip when interrupted, the result probably won't be used.
assert(*num_files == 0 || *files != NULL);
if (*num_files > 1 && !got_int) {
- non_suf_match = 0;
- for (i = 0; i < *num_files; i++) {
+ int non_suf_match = 0; // number without matching suffix
+ for (int i = 0; i < *num_files; i++) {
if (!match_suffix((*files)[i])) {
// Move the name without matching suffix to the front of the list.
- p = (*files)[i];
- for (j = i; j > non_suf_match; j--) {
+ char *p = (*files)[i];
+ for (int j = i; j > non_suf_match; j--) {
(*files)[j] = (*files)[j - 1];
}
(*files)[non_suf_match++] = p;
@@ -2354,11 +2359,11 @@ int append_path(char *path, const char *to_append, size_t max_len)
/// @return FAIL for failure, OK for success.
static int path_to_absolute(const char *fname, char *buf, size_t len, int force)
{
- char *p;
+ const char *p;
*buf = NUL;
char *relative_directory = xmalloc(len);
- char *end_of_path = (char *)fname;
+ const char *end_of_path = fname;
// expand it if forced or not an absolute path
if (force || !path_is_absolute(fname)) {
@@ -2375,7 +2380,6 @@ static int path_to_absolute(const char *fname, char *buf, size_t len, int force)
end_of_path = p + 1;
} else {
relative_directory[0] = NUL;
- end_of_path = (char *)fname;
}
if (FAIL == path_full_dir_name(relative_directory, buf, len)) {