diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-29 22:40:31 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-29 22:40:31 +0000 |
commit | 339e2d15cc26fe86988ea06468d912a46c8d6f29 (patch) | |
tree | a6167fc8fcfc6ae2dc102f57b2473858eac34063 /src/nvim/path.c | |
parent | 067dc73729267c0262438a6fdd66e586f8496946 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-339e2d15cc26fe86988ea06468d912a46c8d6f29.tar.gz rneovim-339e2d15cc26fe86988ea06468d912a46c8d6f29.tar.bz2 rneovim-339e2d15cc26fe86988ea06468d912a46c8d6f29.zip |
Merge remote-tracking branch 'upstream/master' into fix_repeatcmdline
Diffstat (limited to 'src/nvim/path.c')
-rw-r--r-- | src/nvim/path.c | 168 |
1 files changed, 86 insertions, 82 deletions
diff --git a/src/nvim/path.c b/src/nvim/path.c index 513f366a27..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(®match, 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(®match, path_cutoff, (colnr_T)0) + && vim_regexec(®match, 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(®match, pathsep_p + 1, (colnr_T)0) + if (vim_regexec(®match, pathsep_p + 1, 0) && is_unique(pathsep_p + 1, gap, i) && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) { sort_again = true; @@ -1138,7 +1138,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl if (flags & EW_ADDSLASH) { glob_flags |= WILD_ADD_SLASH; } - globpath(paths, pattern, gap, glob_flags); + globpath(paths, pattern, gap, glob_flags, false); xfree(paths); return gap->ga_len; @@ -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)) { |