mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge PR #1212 'os_scandir/scandir_next/closedir()'
This commit is contained in:
commit
ad7a317c42
@ -27,6 +27,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
|||||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ")
|
set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Enable fixing case-insensitive filenames for Mac.
|
||||||
|
set(USE_FNAME_CASE TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set available build types for CMake GUIs.
|
# Set available build types for CMake GUIs.
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#cmakedefine HAVE__NSGETENVIRON
|
#cmakedefine HAVE__NSGETENVIRON
|
||||||
#cmakedefine HAVE_CRT_EXTERNS_H
|
#cmakedefine HAVE_CRT_EXTERNS_H
|
||||||
#cmakedefine HAVE_DIRENT_H
|
|
||||||
#cmakedefine HAVE_FCNTL_H
|
#cmakedefine HAVE_FCNTL_H
|
||||||
#cmakedefine HAVE_FD_CLOEXEC
|
#cmakedefine HAVE_FD_CLOEXEC
|
||||||
#cmakedefine HAVE_FSEEKO
|
#cmakedefine HAVE_FSEEKO
|
||||||
@ -60,6 +59,7 @@
|
|||||||
#define SIGRETURN return
|
#define SIGRETURN return
|
||||||
#define TIME_WITH_SYS_TIME 1
|
#define TIME_WITH_SYS_TIME 1
|
||||||
#cmakedefine UNIX
|
#cmakedefine UNIX
|
||||||
|
#cmakedefine USE_FNAME_CASE
|
||||||
#define USEMAN_S 1
|
#define USEMAN_S 1
|
||||||
|
|
||||||
#define FEAT_BROWSE
|
#define FEAT_BROWSE
|
||||||
|
@ -2253,7 +2253,7 @@ setfname (
|
|||||||
}
|
}
|
||||||
sfname = vim_strsave(sfname);
|
sfname = vim_strsave(sfname);
|
||||||
#ifdef USE_FNAME_CASE
|
#ifdef USE_FNAME_CASE
|
||||||
fname_case(sfname, 0); /* set correct case for short file name */
|
path_fix_case(sfname); /* set correct case for short file name */
|
||||||
#endif
|
#endif
|
||||||
free(buf->b_ffname);
|
free(buf->b_ffname);
|
||||||
free(buf->b_sfname);
|
free(buf->b_sfname);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
#include "nvim/os_unix.h"
|
#include "nvim/os_unix.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
|
#include "nvim/path.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
@ -871,7 +872,7 @@ int vim_isfilec(int c)
|
|||||||
|
|
||||||
/// return TRUE if 'c' is a valid file-name character or a wildcard character
|
/// return TRUE if 'c' is a valid file-name character or a wildcard character
|
||||||
/// Assume characters above 0x100 are valid (multi-byte).
|
/// Assume characters above 0x100 are valid (multi-byte).
|
||||||
/// Explicitly interpret ']' as a wildcard character as mch_has_wildcard("]")
|
/// Explicitly interpret ']' as a wildcard character as path_has_wildcard("]")
|
||||||
/// returns false.
|
/// returns false.
|
||||||
///
|
///
|
||||||
/// @param c
|
/// @param c
|
||||||
@ -882,7 +883,7 @@ int vim_isfilec_or_wc(int c)
|
|||||||
char_u buf[2];
|
char_u buf[2];
|
||||||
buf[0] = (char_u)c;
|
buf[0] = (char_u)c;
|
||||||
buf[1] = NUL;
|
buf[1] = NUL;
|
||||||
return vim_isfilec(c) || c == ']' || mch_has_wildcard(buf);
|
return vim_isfilec(c) || c == ']' || path_has_wildcard(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return TRUE if 'c' is a printable character
|
/// return TRUE if 'c' is a printable character
|
||||||
|
@ -9895,9 +9895,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
|
|||||||
#if defined(WIN64) || defined(_WIN64)
|
#if defined(WIN64) || defined(_WIN64)
|
||||||
"win64",
|
"win64",
|
||||||
#endif
|
#endif
|
||||||
#ifndef CASE_INSENSITIVE_FILENAME
|
|
||||||
"fname_case",
|
"fname_case",
|
||||||
#endif
|
|
||||||
#ifdef HAVE_ACL
|
#ifdef HAVE_ACL
|
||||||
"acl",
|
"acl",
|
||||||
#endif
|
#endif
|
||||||
|
@ -2563,7 +2563,7 @@ do_ecmd (
|
|||||||
sfname = ffname;
|
sfname = ffname;
|
||||||
#ifdef USE_FNAME_CASE
|
#ifdef USE_FNAME_CASE
|
||||||
if (sfname != NULL)
|
if (sfname != NULL)
|
||||||
fname_case(sfname, 0); /* set correct case for sfname */
|
path_fix_case(sfname); // set correct case for sfname
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((flags & ECMD_ADDBUF) && (ffname == NULL || *ffname == NUL))
|
if ((flags & ECMD_ADDBUF) && (ffname == NULL || *ffname == NUL))
|
||||||
|
@ -3432,7 +3432,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
|
|||||||
* the file name contains a wildcard it should not cause expanding.
|
* the file name contains a wildcard it should not cause expanding.
|
||||||
* (it will be expanded anyway if there is a wildcard before replacing).
|
* (it will be expanded anyway if there is a wildcard before replacing).
|
||||||
*/
|
*/
|
||||||
has_wildcards = mch_has_wildcard(p);
|
has_wildcards = path_has_wildcard(p);
|
||||||
while (*p != NUL) {
|
while (*p != NUL) {
|
||||||
/* Skip over `=expr`, wildcards in it are not expanded. */
|
/* Skip over `=expr`, wildcards in it are not expanded. */
|
||||||
if (p[0] == '`' && p[1] == '=') {
|
if (p[0] == '`' && p[1] == '=') {
|
||||||
@ -3543,7 +3543,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
|
|||||||
|| vim_strchr(eap->arg, '~') != NULL) {
|
|| vim_strchr(eap->arg, '~') != NULL) {
|
||||||
expand_env_esc(eap->arg, NameBuff, MAXPATHL,
|
expand_env_esc(eap->arg, NameBuff, MAXPATHL,
|
||||||
TRUE, TRUE, NULL);
|
TRUE, TRUE, NULL);
|
||||||
has_wildcards = mch_has_wildcard(NameBuff);
|
has_wildcards = path_has_wildcard(NameBuff);
|
||||||
p = NameBuff;
|
p = NameBuff;
|
||||||
} else
|
} else
|
||||||
p = NULL;
|
p = NULL;
|
||||||
|
@ -1290,8 +1290,8 @@ scripterror:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_FNAME_CASE
|
#ifdef USE_FNAME_CASE
|
||||||
/* Make the case of the file name match the actual file. */
|
// Make the case of the file name match the actual file.
|
||||||
fname_case(p, 0);
|
path_fix_case(p);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
alist_add(&global_alist, p,
|
alist_add(&global_alist, p,
|
||||||
|
@ -348,6 +348,39 @@ int os_rmdir(const char *path)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opens a directory.
|
||||||
|
/// @param[out] dir The Directory object.
|
||||||
|
/// @param path Path to the directory.
|
||||||
|
/// @returns true if dir contains one or more items, false if not or an error
|
||||||
|
/// occurred.
|
||||||
|
bool os_scandir(Directory *dir, const char *path)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
int r = uv_fs_scandir(uv_default_loop(), &dir->request, path, 0, NULL);
|
||||||
|
if (r <= 0) {
|
||||||
|
os_closedir(dir);
|
||||||
|
}
|
||||||
|
return r > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increments the directory pointer.
|
||||||
|
/// @param dir The Directory object.
|
||||||
|
/// @returns a pointer to the next path in `dir` or `NULL`.
|
||||||
|
const char *os_scandir_next(Directory *dir)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
int err = uv_fs_scandir_next(&dir->request, &dir->ent);
|
||||||
|
return err != UV_EOF ? dir->ent.name : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frees memory associated with `os_scandir()`.
|
||||||
|
/// @param dir The directory.
|
||||||
|
void os_closedir(Directory *dir)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
uv_fs_req_cleanup(&dir->request);
|
||||||
|
}
|
||||||
|
|
||||||
/// Remove a file.
|
/// Remove a file.
|
||||||
///
|
///
|
||||||
/// @return `0` for success, non-zero for failure.
|
/// @return `0` for success, non-zero for failure.
|
||||||
|
@ -16,4 +16,9 @@ typedef struct {
|
|||||||
|
|
||||||
#define FILE_ID_EMPTY (FileID) {.inode = 0, .device_id = 0}
|
#define FILE_ID_EMPTY (FileID) {.inode = 0, .device_id = 0}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uv_fs_t request; ///< @private The request to uv for the directory.
|
||||||
|
uv_dirent_t ent; ///< @private The entry information.
|
||||||
|
} Directory;
|
||||||
|
|
||||||
#endif // NVIM_OS_FS_DEFS_H
|
#endif // NVIM_OS_FS_DEFS_H
|
||||||
|
@ -69,62 +69,6 @@ static int selinux_enabled = -1;
|
|||||||
# include "os_unix.c.generated.h"
|
# include "os_unix.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_FNAME_CASE)
|
|
||||||
/*
|
|
||||||
* Set the case of the file name, if it already exists. This will cause the
|
|
||||||
* file name to remain exactly the same.
|
|
||||||
* Only required for file systems where case is ignored and preserved.
|
|
||||||
*/
|
|
||||||
void fname_case(
|
|
||||||
char_u *name,
|
|
||||||
int len /* buffer size, only used when name gets longer */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
char_u *slash, *tail;
|
|
||||||
DIR *dirp;
|
|
||||||
struct dirent *dp;
|
|
||||||
|
|
||||||
FileInfo file_info;
|
|
||||||
if (os_fileinfo_link((char *)name, &file_info)) {
|
|
||||||
/* Open the directory where the file is located. */
|
|
||||||
slash = vim_strrchr(name, '/');
|
|
||||||
if (slash == NULL) {
|
|
||||||
dirp = opendir(".");
|
|
||||||
tail = name;
|
|
||||||
} else {
|
|
||||||
*slash = NUL;
|
|
||||||
dirp = opendir((char *)name);
|
|
||||||
*slash = '/';
|
|
||||||
tail = slash + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirp != NULL) {
|
|
||||||
while ((dp = readdir(dirp)) != NULL) {
|
|
||||||
/* Only accept names that differ in case and are the same byte
|
|
||||||
* length. TODO: accept different length name. */
|
|
||||||
if (STRICMP(tail, dp->d_name) == 0
|
|
||||||
&& STRLEN(tail) == STRLEN(dp->d_name)) {
|
|
||||||
char_u newname[MAXPATHL + 1];
|
|
||||||
|
|
||||||
/* Verify the inode is equal. */
|
|
||||||
STRLCPY(newname, name, MAXPATHL + 1);
|
|
||||||
STRLCPY(newname + (tail - name), dp->d_name,
|
|
||||||
MAXPATHL - (tail - name) + 1);
|
|
||||||
FileInfo file_info_new;
|
|
||||||
if (os_fileinfo_link((char *)newname, &file_info_new)
|
|
||||||
&& os_fileinfo_id_equal(&file_info, &file_info_new)) {
|
|
||||||
STRCPY(tail, dp->d_name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dirp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(HAVE_ACL)
|
#if defined(HAVE_ACL)
|
||||||
# ifdef HAVE_SYS_ACL_H
|
# ifdef HAVE_SYS_ACL_H
|
||||||
# include <sys/acl.h>
|
# include <sys/acl.h>
|
||||||
@ -719,47 +663,12 @@ static void save_patterns(int num_pat, char_u **pat, int *num_file,
|
|||||||
*num_file = num_pat;
|
*num_file = num_pat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
|
|
||||||
* expand.
|
|
||||||
*/
|
|
||||||
int mch_has_exp_wildcard(char_u *p)
|
|
||||||
{
|
|
||||||
for (; *p; mb_ptr_adv(p)) {
|
|
||||||
if (*p == '\\' && p[1] != NUL)
|
|
||||||
++p;
|
|
||||||
else if (vim_strchr((char_u *)
|
|
||||||
"*?[{'"
|
|
||||||
, *p) != NULL)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return TRUE if the string "p" contains a wildcard.
|
|
||||||
* Don't recognize '~' at the end as a wildcard.
|
|
||||||
*/
|
|
||||||
int mch_has_wildcard(char_u *p)
|
|
||||||
{
|
|
||||||
for (; *p; mb_ptr_adv(p)) {
|
|
||||||
if (*p == '\\' && p[1] != NUL)
|
|
||||||
++p;
|
|
||||||
else if (vim_strchr((char_u *)
|
|
||||||
"*?[{`'$"
|
|
||||||
, *p) != NULL
|
|
||||||
|| (*p == '~' && p[1] != NUL))
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int have_wildcard(int num, char_u **file)
|
static int have_wildcard(int num, char_u **file)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < num; i++)
|
for (i = 0; i < num; i++)
|
||||||
if (mch_has_wildcard(file[i]))
|
if (path_has_wildcard(file[i]))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -44,25 +44,6 @@
|
|||||||
# define SIGDUMMYARG
|
# define SIGDUMMYARG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_DIRENT_H
|
|
||||||
# include <dirent.h>
|
|
||||||
# ifndef NAMLEN
|
|
||||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define dirent direct
|
|
||||||
# define NAMLEN(dirent) (dirent)->d_namlen
|
|
||||||
# if HAVE_SYS_NDIR_H
|
|
||||||
# include <sys/ndir.h>
|
|
||||||
# endif
|
|
||||||
# if HAVE_SYS_DIR_H
|
|
||||||
# include <sys/dir.h>
|
|
||||||
# endif
|
|
||||||
# if HAVE_NDIR_H
|
|
||||||
# include <ndir.h>
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME)
|
#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME)
|
||||||
# include <time.h> /* on some systems time.h should not be
|
# include <time.h> /* on some systems time.h should not be
|
||||||
included together with sys/time.h */
|
included together with sys/time.h */
|
||||||
|
221
src/nvim/path.c
221
src/nvim/path.c
@ -400,6 +400,32 @@ char_u *save_absolute_path(const char_u *name)
|
|||||||
return vim_strsave((char_u *) name);
|
return vim_strsave((char_u *) name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if a path has a wildcard character including '~', unless at the end.
|
||||||
|
/// @param p The path to expand.
|
||||||
|
/// @returns Unix: True if it contains one of "?[{`'$".
|
||||||
|
/// @returns Windows: True if it contains one of "*?$[".
|
||||||
|
bool path_has_wildcard(const char_u *p)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
for (; *p; mb_ptr_adv(p)) {
|
||||||
|
#if defined(UNIX)
|
||||||
|
if (p[0] == '\\' && p[1] != NUL) {
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *wildcards = "*?[{`'$";
|
||||||
|
#else
|
||||||
|
// Windows:
|
||||||
|
const char *wildcards = "?*$[`";
|
||||||
|
#endif
|
||||||
|
if (vim_strchr((char_u *)wildcards, *p) != NULL
|
||||||
|
|| (p[0] == '~' && p[1] != NUL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(UNIX)
|
#if defined(UNIX)
|
||||||
/*
|
/*
|
||||||
@ -410,39 +436,67 @@ static int pstrcmp(const void *a, const void *b)
|
|||||||
{
|
{
|
||||||
return pathcmp(*(char **)a, *(char **)b, -1);
|
return pathcmp(*(char **)a, *(char **)b, -1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/// Checks if a path has a character path_expand can expand.
|
||||||
* Recursively expand one path component into all matching files and/or
|
/// @param p The path to expand.
|
||||||
* directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc.
|
/// @returns Unix: True if it contains one of *?[{.
|
||||||
* "path" has backslashes before chars that are not to be expanded, starting
|
/// @returns Windows: True if it contains one of *?[.
|
||||||
* at "path + wildoff".
|
bool path_has_exp_wildcard(const char_u *p)
|
||||||
* Return the number of matches found.
|
FUNC_ATTR_NONNULL_ALL
|
||||||
* NOTE: much of this is identical to dos_expandpath(), keep in sync!
|
{
|
||||||
*/
|
for (; *p != NUL; mb_ptr_adv(p)) {
|
||||||
int
|
#if defined(UNIX)
|
||||||
unix_expandpath (
|
if (p[0] == '\\' && p[1] != NUL) {
|
||||||
garray_T *gap,
|
p++;
|
||||||
char_u *path,
|
continue;
|
||||||
int wildoff,
|
}
|
||||||
int flags, /* EW_* flags */
|
|
||||||
int didstar /* expanded "**" once already */
|
const char *wildcards = "*?[{";
|
||||||
)
|
#else
|
||||||
|
const char *wildcards = "*?["; // Windows.
|
||||||
|
#endif
|
||||||
|
if (vim_strchr((char_u *) wildcards, *p) != NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recursively expands one path component into all matching files and/or
|
||||||
|
/// directories. Handles "*", "?", "[a-z]", "**", etc.
|
||||||
|
/// @remark "**" in `path` requests recursive expansion.
|
||||||
|
///
|
||||||
|
/// @param[out] gap The matches found.
|
||||||
|
/// @param path The path to search.
|
||||||
|
/// @param flags Flags for regexp expansion.
|
||||||
|
/// - EW_ICASE: Ignore case.
|
||||||
|
/// - EW_NOERROR: Silence error messeges.
|
||||||
|
/// - EW_NOTWILD: Add matches literally.
|
||||||
|
/// @returns the number of matches found.
|
||||||
|
static size_t path_expand(garray_T *gap, const char_u *path, int flags)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
return do_path_expand(gap, path, 0, flags, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of path_expand().
|
||||||
|
///
|
||||||
|
/// Chars before `path + wildoff` do not get expanded.
|
||||||
|
static size_t do_path_expand(garray_T *gap, const char_u *path,
|
||||||
|
size_t wildoff, int flags, bool didstar)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
char_u *buf;
|
char_u *buf;
|
||||||
char_u *path_end;
|
|
||||||
char_u *p, *s, *e;
|
char_u *p, *s, *e;
|
||||||
int start_len = gap->ga_len;
|
int start_len = gap->ga_len;
|
||||||
char_u *pat;
|
char_u *pat;
|
||||||
regmatch_T regmatch;
|
|
||||||
int starts_with_dot;
|
int starts_with_dot;
|
||||||
int matches;
|
int matches;
|
||||||
int len;
|
int len;
|
||||||
int starstar = FALSE;
|
int starstar = FALSE;
|
||||||
static int stardepth = 0; /* depth for "**" expansion */
|
static int stardepth = 0; /* depth for "**" expansion */
|
||||||
|
|
||||||
DIR *dirp;
|
|
||||||
struct dirent *dp;
|
|
||||||
|
|
||||||
/* Expanding "**" may take a long time, check for CTRL-C. */
|
/* Expanding "**" may take a long time, check for CTRL-C. */
|
||||||
if (stardepth > 0) {
|
if (stardepth > 0) {
|
||||||
os_breakcheck();
|
os_breakcheck();
|
||||||
@ -461,7 +515,7 @@ unix_expandpath (
|
|||||||
p = buf;
|
p = buf;
|
||||||
s = buf;
|
s = buf;
|
||||||
e = NULL;
|
e = NULL;
|
||||||
path_end = path;
|
const char_u *path_end = path;
|
||||||
while (*path_end != NUL) {
|
while (*path_end != NUL) {
|
||||||
/* May ignore a wildcard that has a backslash before it; it will
|
/* May ignore a wildcard that has a backslash before it; it will
|
||||||
* be removed by rem_backslash() or file_pat_to_reg_pat() below. */
|
* be removed by rem_backslash() or file_pat_to_reg_pat() below. */
|
||||||
@ -510,11 +564,14 @@ unix_expandpath (
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compile the regexp into a program */
|
// compile the regexp into a program
|
||||||
if (flags & EW_ICASE)
|
regmatch_T regmatch;
|
||||||
regmatch.rm_ic = TRUE; /* 'wildignorecase' set */
|
#if defined(UNIX)
|
||||||
else
|
// Ignore case if given 'wildignorecase', else respect 'fileignorecase'.
|
||||||
regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
|
regmatch.rm_ic = (flags & EW_ICASE) || p_fic;
|
||||||
|
#else
|
||||||
|
regmatch.rm_ic = true; // Always ignore case on Windows.
|
||||||
|
#endif
|
||||||
if (flags & (EW_NOERROR | EW_NOTWILD))
|
if (flags & (EW_NOERROR | EW_NOTWILD))
|
||||||
++emsg_silent;
|
++emsg_silent;
|
||||||
regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
|
regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
|
||||||
@ -533,26 +590,22 @@ unix_expandpath (
|
|||||||
&& *path_end == '/') {
|
&& *path_end == '/') {
|
||||||
STRCPY(s, path_end + 1);
|
STRCPY(s, path_end + 1);
|
||||||
++stardepth;
|
++stardepth;
|
||||||
(void)unix_expandpath(gap, buf, (int)(s - buf), flags, TRUE);
|
(void)do_path_expand(gap, buf, (int)(s - buf), flags, TRUE);
|
||||||
--stardepth;
|
--stardepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open the directory for scanning */
|
|
||||||
*s = NUL;
|
*s = NUL;
|
||||||
dirp = opendir(*buf == NUL ? "." : (char *)buf);
|
|
||||||
|
|
||||||
/* Find all matching entries */
|
Directory dir;
|
||||||
if (dirp != NULL) {
|
// open the directory for scanning
|
||||||
for (;; ) {
|
if (os_scandir(&dir, *buf == NUL ? "." : (char *)buf)) {
|
||||||
dp = readdir(dirp);
|
// Find all matching entries.
|
||||||
if (dp == NULL)
|
char_u *name;
|
||||||
break;
|
while((name = (char_u *) os_scandir_next(&dir))) {
|
||||||
if ((dp->d_name[0] != '.' || starts_with_dot)
|
if ((name[0] != '.' || starts_with_dot)
|
||||||
&& ((regmatch.regprog != NULL && vim_regexec(®match,
|
&& ((regmatch.regprog != NULL && vim_regexec(®match, name, 0))
|
||||||
(char_u *)dp->d_name, (colnr_T)0))
|
|
||||||
|| ((flags & EW_NOTWILD)
|
|| ((flags & EW_NOTWILD)
|
||||||
&& fnamencmp(path + (s - buf), dp->d_name, e - s) == 0))) {
|
&& fnamencmp(path + (s - buf), name, e - s) == 0))) {
|
||||||
STRCPY(s, dp->d_name);
|
STRCPY(s, name);
|
||||||
len = STRLEN(buf);
|
len = STRLEN(buf);
|
||||||
|
|
||||||
if (starstar && stardepth < 100) {
|
if (starstar && stardepth < 100) {
|
||||||
@ -561,15 +614,15 @@ unix_expandpath (
|
|||||||
STRCPY(buf + len, "/**");
|
STRCPY(buf + len, "/**");
|
||||||
STRCPY(buf + len + 3, path_end);
|
STRCPY(buf + len + 3, path_end);
|
||||||
++stardepth;
|
++stardepth;
|
||||||
(void)unix_expandpath(gap, buf, len + 1, flags, TRUE);
|
(void)do_path_expand(gap, buf, len + 1, flags, true);
|
||||||
--stardepth;
|
--stardepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
STRCPY(buf + len, path_end);
|
STRCPY(buf + len, path_end);
|
||||||
if (mch_has_exp_wildcard(path_end)) { /* handle more wildcards */
|
if (path_has_exp_wildcard(path_end)) { /* handle more wildcards */
|
||||||
/* need to expand another component of the path */
|
/* need to expand another component of the path */
|
||||||
/* remove backslashes for the remaining components only */
|
/* remove backslashes for the remaining components only */
|
||||||
(void)unix_expandpath(gap, buf, len + 1, flags, FALSE);
|
(void)do_path_expand(gap, buf, len + 1, flags, false);
|
||||||
} else {
|
} else {
|
||||||
/* no more wildcards, check if there is a match */
|
/* no more wildcards, check if there is a match */
|
||||||
/* remove backslashes for the remaining components only */
|
/* remove backslashes for the remaining components only */
|
||||||
@ -581,8 +634,7 @@ unix_expandpath (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
os_closedir(&dir);
|
||||||
closedir(dirp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
@ -594,7 +646,6 @@ unix_expandpath (
|
|||||||
sizeof(char_u *), pstrcmp);
|
sizeof(char_u *), pstrcmp);
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Moves "*psep" back to the previous path separator in "path".
|
* Moves "*psep" back to the previous path separator in "path".
|
||||||
@ -1078,7 +1129,7 @@ gen_expand_wildcards (
|
|||||||
* If there are no wildcards: Add the file name if it exists or
|
* If there are no wildcards: Add the file name if it exists or
|
||||||
* when EW_NOTFOUND is given.
|
* when EW_NOTFOUND is given.
|
||||||
*/
|
*/
|
||||||
if (mch_has_exp_wildcard(p)) {
|
if (path_has_exp_wildcard(p)) {
|
||||||
if ((flags & EW_PATH)
|
if ((flags & EW_PATH)
|
||||||
&& !path_is_absolute_path(p)
|
&& !path_is_absolute_path(p)
|
||||||
&& !(p[0] == '.'
|
&& !(p[0] == '.'
|
||||||
@ -1092,7 +1143,7 @@ gen_expand_wildcards (
|
|||||||
recursive = TRUE;
|
recursive = TRUE;
|
||||||
did_expand_in_path = TRUE;
|
did_expand_in_path = TRUE;
|
||||||
} else
|
} else
|
||||||
add_pat = mch_expandpath(&ga, p, flags);
|
add_pat = path_expand(&ga, p, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1566,13 +1617,68 @@ char_u *fix_fname(char_u *fname)
|
|||||||
fname = vim_strsave(fname);
|
fname = vim_strsave(fname);
|
||||||
|
|
||||||
# ifdef USE_FNAME_CASE
|
# ifdef USE_FNAME_CASE
|
||||||
fname_case(fname, 0); // set correct case for file name
|
path_fix_case(fname); // set correct case for file name
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
return fname;
|
return fname;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the case of the file name, if it already exists. This will cause the
|
||||||
|
/// file name to remain exactly the same.
|
||||||
|
/// Only required for file systems where case is ignored and preserved.
|
||||||
|
// TODO(SplinterOfChaos): Could also be used when mounting case-insensitive
|
||||||
|
// file systems.
|
||||||
|
void path_fix_case(char_u *name)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
FileInfo file_info;
|
||||||
|
if (!os_fileinfo_link((char *)name, &file_info)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the directory where the file is located.
|
||||||
|
char_u *slash = vim_strrchr(name, '/');
|
||||||
|
char_u *tail;
|
||||||
|
Directory dir;
|
||||||
|
bool ok;
|
||||||
|
if (slash == NULL) {
|
||||||
|
ok = os_scandir(&dir, ".");
|
||||||
|
tail = name;
|
||||||
|
} else {
|
||||||
|
*slash = NUL;
|
||||||
|
ok = os_scandir(&dir, (char *) name);
|
||||||
|
*slash = '/';
|
||||||
|
tail = slash + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char_u *entry;
|
||||||
|
while ((entry = (char_u *) 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)) {
|
||||||
|
char_u newname[MAXPATHL + 1];
|
||||||
|
|
||||||
|
// Verify the inode is equal.
|
||||||
|
STRLCPY(newname, name, MAXPATHL + 1);
|
||||||
|
STRLCPY(newname + (tail - name), entry,
|
||||||
|
MAXPATHL - (tail - name) + 1);
|
||||||
|
FileInfo file_info_new;
|
||||||
|
if (os_fileinfo_link((char *)newname, &file_info_new)
|
||||||
|
&& os_fileinfo_id_equal(&file_info, &file_info_new)) {
|
||||||
|
STRCPY(tail, entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os_closedir(&dir);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return TRUE if "p" points to just after a path separator.
|
* Return TRUE if "p" points to just after a path separator.
|
||||||
* Takes care of multi-byte characters.
|
* Takes care of multi-byte characters.
|
||||||
@ -1670,19 +1776,6 @@ int pathcmp(const char *p, const char *q, int maxlen)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Expand a path into all matching files and/or directories. Handles "*",
|
|
||||||
* "?", "[a-z]", "**", etc.
|
|
||||||
* "path" has backslashes before chars that are not to be expanded.
|
|
||||||
* Returns the number of matches found.
|
|
||||||
*
|
|
||||||
* Uses EW_* flags
|
|
||||||
*/
|
|
||||||
int mch_expandpath(garray_T *gap, char_u *path, int flags)
|
|
||||||
{
|
|
||||||
return unix_expandpath(gap, path, 0, flags, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to find a shortname by comparing the fullname with the current
|
/// Try to find a shortname by comparing the fullname with the current
|
||||||
/// directory.
|
/// directory.
|
||||||
///
|
///
|
||||||
|
@ -2587,7 +2587,7 @@ static char_u *expand_tag_fname(char_u *fname, char_u *tag_fname, int expand)
|
|||||||
/*
|
/*
|
||||||
* Expand file name (for environment variables) when needed.
|
* Expand file name (for environment variables) when needed.
|
||||||
*/
|
*/
|
||||||
if (expand && mch_has_wildcard(fname)) {
|
if (expand && path_has_wildcard(fname)) {
|
||||||
ExpandInit(&xpc);
|
ExpandInit(&xpc);
|
||||||
xpc.xp_context = EXPAND_FILES;
|
xpc.xp_context = EXPAND_FILES;
|
||||||
expanded_fname = ExpandOne(&xpc, fname, NULL,
|
expanded_fname = ExpandOne(&xpc, fname, NULL,
|
||||||
|
@ -418,6 +418,30 @@ describe('more path function', function()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('path_fix_case', function()
|
||||||
|
function fix_case(file)
|
||||||
|
c_file = to_cstr(file)
|
||||||
|
path.path_fix_case(c_file)
|
||||||
|
return ffi.string(c_file)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ffi.os == 'Windows' or ffi.os == 'OSX' then
|
||||||
|
it('Corrects the case of file names in Mac and Windows', function()
|
||||||
|
lfs.mkdir('CamelCase')
|
||||||
|
eq('CamelCase', fix_case('camelcase'))
|
||||||
|
eq('CamelCase', fix_case('cAMELcASE'))
|
||||||
|
lfs.rmdir('CamelCase')
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
it('does nothing on Linux', function()
|
||||||
|
lfs.mkdir('CamelCase')
|
||||||
|
eq('camelcase', fix_case('camelcase'))
|
||||||
|
eq('cAMELcASE', fix_case('cAMELcASE'))
|
||||||
|
lfs.mkdir('CamelCase')
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
describe('append_path', function()
|
describe('append_path', function()
|
||||||
it('joins given paths with a slash', function()
|
it('joins given paths with a slash', function()
|
||||||
local path1 = cstr(100, 'path1')
|
local path1 = cstr(100, 'path1')
|
||||||
|
Loading…
Reference in New Issue
Block a user