mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.0875: getting attributes for directory entries is slow
Problem: Getting attributes for directory entries is slow. Solution: Add readdirex(). (Ken Takata, closes #5619)
This commit is contained in:
@@ -2676,6 +2676,7 @@ rand([{expr}]) Number get pseudo-random number
|
|||||||
range({expr} [, {max} [, {stride}]])
|
range({expr} [, {max} [, {stride}]])
|
||||||
List items from {expr} to {max}
|
List items from {expr} to {max}
|
||||||
readdir({dir} [, {expr}]) List file names in {dir} selected by {expr}
|
readdir({dir} [, {expr}]) List file names in {dir} selected by {expr}
|
||||||
|
readdirex({dir} [, {expr}]) List file info in {dir} selected by {expr}
|
||||||
readfile({fname} [, {type} [, {max}]])
|
readfile({fname} [, {type} [, {max}]])
|
||||||
List get list of lines from file {fname}
|
List get list of lines from file {fname}
|
||||||
reg_executing() String get the executing register name
|
reg_executing() String get the executing register name
|
||||||
@@ -7840,11 +7841,11 @@ rand([{expr}]) *rand()* *random*
|
|||||||
:echo rand(seed)
|
:echo rand(seed)
|
||||||
:echo rand(seed) % 16 " random number 0 - 15
|
:echo rand(seed) % 16 " random number 0 - 15
|
||||||
<
|
<
|
||||||
*readdir()*
|
readdir({directory} [, {expr}]) *readdir()*
|
||||||
readdir({directory} [, {expr}])
|
|
||||||
Return a list with file and directory names in {directory}.
|
Return a list with file and directory names in {directory}.
|
||||||
You can also use |glob()| if you don't need to do complicated
|
You can also use |glob()| if you don't need to do complicated
|
||||||
things, such as limiting the number of matches.
|
things, such as limiting the number of matches.
|
||||||
|
The list will be sorted (case sensitive).
|
||||||
|
|
||||||
When {expr} is omitted all entries are included.
|
When {expr} is omitted all entries are included.
|
||||||
When {expr} is given, it is evaluated to check what to do:
|
When {expr} is given, it is evaluated to check what to do:
|
||||||
@@ -7854,6 +7855,7 @@ readdir({directory} [, {expr}])
|
|||||||
added to the list.
|
added to the list.
|
||||||
If {expr} results in 1 then this entry will be added
|
If {expr} results in 1 then this entry will be added
|
||||||
to the list.
|
to the list.
|
||||||
|
The entries "." and ".." are always excluded.
|
||||||
Each time {expr} is evaluated |v:val| is set to the entry name.
|
Each time {expr} is evaluated |v:val| is set to the entry name.
|
||||||
When {expr} is a function the name is passed as the argument.
|
When {expr} is a function the name is passed as the argument.
|
||||||
For example, to get a list of files ending in ".txt": >
|
For example, to get a list of files ending in ".txt": >
|
||||||
@@ -7871,6 +7873,59 @@ readdir({directory} [, {expr}])
|
|||||||
<
|
<
|
||||||
Can also be used as a |method|: >
|
Can also be used as a |method|: >
|
||||||
GetDirName()->readdir()
|
GetDirName()->readdir()
|
||||||
|
<
|
||||||
|
readdirex({directory} [, {expr}]) *readdirex()*
|
||||||
|
Extended version of |readdir()|.
|
||||||
|
Return a list of Dictionaries with file and directory
|
||||||
|
information in {directory}.
|
||||||
|
This is useful if you want to get the attributes of file and
|
||||||
|
directory at the same time as getting a list of a directory.
|
||||||
|
This is much faster than calling |readdir()| then calling
|
||||||
|
|getfperm()|, |getfsize()|, |getftime()| and |getftype()| for
|
||||||
|
each file and directory especially on MS-Windows.
|
||||||
|
The list will be sorted by name (case sensitive).
|
||||||
|
|
||||||
|
The Dictionary for file and directory information has the
|
||||||
|
following items:
|
||||||
|
group Group name of the entry. (Only on Unix)
|
||||||
|
name Name of the entry.
|
||||||
|
perm Permissions of the entry. See |getfperm()|.
|
||||||
|
size Size of the entry. See |getfsize()|.
|
||||||
|
time Timestamp of the entry. See |getftime()|.
|
||||||
|
type Type of the entry.
|
||||||
|
On Unix, almost same as |getftype()| except:
|
||||||
|
Symlink to a dir "linkd"
|
||||||
|
Other symlink "link"
|
||||||
|
On MS-Windows:
|
||||||
|
Normal file "file"
|
||||||
|
Directory "dir"
|
||||||
|
Junction "junction"
|
||||||
|
Symlink to a dir "linkd"
|
||||||
|
Other symlink "link"
|
||||||
|
Other reparse point "reparse"
|
||||||
|
user User name of the entry's owner. (Only on Unix)
|
||||||
|
On Unix, if the entry is a symlink, the Dictionary includes
|
||||||
|
the information of the target (except the "type" item).
|
||||||
|
On MS-Windows, it includes the information of the symlink
|
||||||
|
itself because of performance reasons.
|
||||||
|
|
||||||
|
When {expr} is omitted all entries are included.
|
||||||
|
When {expr} is given, it is evaluated to check what to do:
|
||||||
|
If {expr} results in -1 then no further entries will
|
||||||
|
be handled.
|
||||||
|
If {expr} results in 0 then this entry will not be
|
||||||
|
added to the list.
|
||||||
|
If {expr} results in 1 then this entry will be added
|
||||||
|
to the list.
|
||||||
|
The entries "." and ".." are always excluded.
|
||||||
|
Each time {expr} is evaluated |v:val| is set to a Dictionary
|
||||||
|
of the entry.
|
||||||
|
When {expr} is a function the entry is passed as the argument.
|
||||||
|
For example, to get a list of files ending in ".txt": >
|
||||||
|
readdirex(dirname, {e -> e.name =~ '.txt$'})
|
||||||
|
<
|
||||||
|
Can also be used as a |method|: >
|
||||||
|
GetDirName()->readdirex()
|
||||||
<
|
<
|
||||||
*readfile()*
|
*readfile()*
|
||||||
readfile({fname} [, {type} [, {max}]])
|
readfile({fname} [, {type} [, {max}]])
|
||||||
|
@@ -791,6 +791,7 @@ System functions and manipulation of files:
|
|||||||
hostname() name of the system
|
hostname() name of the system
|
||||||
readfile() read a file into a List of lines
|
readfile() read a file into a List of lines
|
||||||
readdir() get a List of file names in a directory
|
readdir() get a List of file names in a directory
|
||||||
|
readdirex() get a List of file information in a directory
|
||||||
writefile() write a List of lines or Blob into a file
|
writefile() write a List of lines or Blob into a file
|
||||||
|
|
||||||
Date and Time: *date-functions* *time-functions*
|
Date and Time: *date-functions* *time-functions*
|
||||||
|
@@ -767,6 +767,7 @@ static funcentry_T global_functions[] =
|
|||||||
{"rand", 0, 1, FEARG_1, ret_number, f_rand},
|
{"rand", 0, 1, FEARG_1, ret_number, f_rand},
|
||||||
{"range", 1, 3, FEARG_1, ret_list_number, f_range},
|
{"range", 1, 3, FEARG_1, ret_list_number, f_range},
|
||||||
{"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
|
{"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
|
||||||
|
{"readdirex", 1, 2, FEARG_1, ret_list_dict_any, f_readdirex},
|
||||||
{"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
|
{"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
|
||||||
{"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
|
{"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
|
||||||
{"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
|
{"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
|
||||||
|
340
src/fileio.c
340
src/fileio.c
@@ -16,6 +16,10 @@
|
|||||||
#if defined(__TANDEM) || defined(__MINT__)
|
#if defined(__TANDEM) || defined(__MINT__)
|
||||||
# include <limits.h> // for SSIZE_MAX
|
# include <limits.h> // for SSIZE_MAX
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(UNIX) && defined(FEAT_EVAL)
|
||||||
|
# include <pwd.h>
|
||||||
|
# include <grp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Is there any system that doesn't have access()?
|
// Is there any system that doesn't have access()?
|
||||||
#define USE_MCH_ACCESS
|
#define USE_MCH_ACCESS
|
||||||
@@ -4420,32 +4424,270 @@ write_lnum_adjust(linenr_T offset)
|
|||||||
curbuf->b_no_eol_lnum += offset;
|
curbuf->b_no_eol_lnum += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subfuncions for readdirex()
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
# ifdef MSWIN
|
||||||
|
static char_u *
|
||||||
|
getfpermwfd(WIN32_FIND_DATAW *wfd, char_u *perm)
|
||||||
|
{
|
||||||
|
stat_T st;
|
||||||
|
unsigned short st_mode;
|
||||||
|
DWORD flag = wfd->dwFileAttributes;
|
||||||
|
WCHAR *wp;
|
||||||
|
|
||||||
|
st_mode = (flag & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
? (_S_IFDIR | _S_IEXEC) : _S_IFREG;
|
||||||
|
st_mode |= (flag & FILE_ATTRIBUTE_READONLY)
|
||||||
|
? _S_IREAD : (_S_IREAD | _S_IWRITE);
|
||||||
|
|
||||||
|
wp = wcsrchr(wfd->cFileName, L'.');
|
||||||
|
if (wp != NULL)
|
||||||
|
{
|
||||||
|
if (_wcsicmp(wp, L".exe") == 0 ||
|
||||||
|
_wcsicmp(wp, L".com") == 0 ||
|
||||||
|
_wcsicmp(wp, L".cmd") == 0 ||
|
||||||
|
_wcsicmp(wp, L".bat") == 0)
|
||||||
|
st_mode |= _S_IEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy user bits to group/other.
|
||||||
|
st_mode |= (st_mode & 0700) >> 3;
|
||||||
|
st_mode |= (st_mode & 0700) >> 6;
|
||||||
|
|
||||||
|
st.st_mode = st_mode;
|
||||||
|
return getfpermst(&st, perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char_u *
|
||||||
|
getftypewfd(WIN32_FIND_DATAW *wfd)
|
||||||
|
{
|
||||||
|
DWORD flag = wfd->dwFileAttributes;
|
||||||
|
DWORD tag = wfd->dwReserved0;
|
||||||
|
|
||||||
|
if (flag & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
{
|
||||||
|
if (tag == IO_REPARSE_TAG_MOUNT_POINT)
|
||||||
|
return (char_u*)"junction";
|
||||||
|
else if (tag == IO_REPARSE_TAG_SYMLINK)
|
||||||
|
{
|
||||||
|
if (flag & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
return (char_u*)"linkd";
|
||||||
|
else
|
||||||
|
return (char_u*)"link";
|
||||||
|
}
|
||||||
|
return (char_u*)"reparse"; // unknown reparse point type
|
||||||
|
}
|
||||||
|
if (flag & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
return (char_u*)"dir";
|
||||||
|
else
|
||||||
|
return (char_u*)"file";
|
||||||
|
}
|
||||||
|
|
||||||
|
static dict_T *
|
||||||
|
create_readdirex_item(WIN32_FIND_DATAW *wfd)
|
||||||
|
{
|
||||||
|
dict_T *item;
|
||||||
|
char_u *p;
|
||||||
|
varnumber_T size, time;
|
||||||
|
char_u permbuf[] = "---------";
|
||||||
|
|
||||||
|
item = dict_alloc();
|
||||||
|
if (item == NULL)
|
||||||
|
return NULL;
|
||||||
|
item->dv_refcount++;
|
||||||
|
|
||||||
|
p = utf16_to_enc(wfd->cFileName, NULL);
|
||||||
|
if (p == NULL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_string(item, "name", p) == FAIL)
|
||||||
|
{
|
||||||
|
vim_free(p);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
vim_free(p);
|
||||||
|
|
||||||
|
size = (((varnumber_T)wfd->nFileSizeHigh) << 32) | wfd->nFileSizeLow;
|
||||||
|
if (dict_add_number(item, "size", size) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
// Convert FILETIME to unix time.
|
||||||
|
time = (((((varnumber_T)wfd->ftLastWriteTime.dwHighDateTime) << 32) |
|
||||||
|
wfd->ftLastWriteTime.dwLowDateTime)
|
||||||
|
- 116444736000000000) / 10000000;
|
||||||
|
if (dict_add_number(item, "time", time) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
if (dict_add_string(item, "type", getftypewfd(wfd)) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_string(item, "perm", getfpermwfd(wfd, permbuf)) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
if (dict_add_string(item, "user", (char_u*)"") == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_string(item, "group", (char_u*)"") == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
|
||||||
|
theend:
|
||||||
|
dict_unref(item);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
static dict_T *
|
||||||
|
create_readdirex_item(char_u *path, char_u *name)
|
||||||
|
{
|
||||||
|
dict_T *item;
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
stat_T st;
|
||||||
|
int ret, link = FALSE;
|
||||||
|
varnumber_T size;
|
||||||
|
char_u permbuf[] = "---------";
|
||||||
|
char_u *q;
|
||||||
|
struct passwd *pw;
|
||||||
|
struct group *gr;
|
||||||
|
|
||||||
|
item = dict_alloc();
|
||||||
|
if (item == NULL)
|
||||||
|
return NULL;
|
||||||
|
item->dv_refcount++;
|
||||||
|
|
||||||
|
len = STRLEN(path) + 1 + STRLEN(name) + 1;
|
||||||
|
p = alloc(len);
|
||||||
|
if (p == NULL)
|
||||||
|
goto theend;
|
||||||
|
vim_snprintf(p, len, "%s/%s", path, name);
|
||||||
|
ret = mch_lstat(p, &st);
|
||||||
|
if (ret >= 0 && S_ISLNK(st.st_mode))
|
||||||
|
{
|
||||||
|
link = TRUE;
|
||||||
|
ret = mch_stat(p, &st);
|
||||||
|
}
|
||||||
|
vim_free(p);
|
||||||
|
|
||||||
|
if (dict_add_string(item, "name", name) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
size = (varnumber_T)st.st_size;
|
||||||
|
if (S_ISDIR(st.st_mode))
|
||||||
|
size = 0;
|
||||||
|
// non-perfect check for overflow
|
||||||
|
if ((off_T)size != (off_T)st.st_size)
|
||||||
|
size = -2;
|
||||||
|
if (dict_add_number(item, "size", size) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_number(item, "time", (varnumber_T)st.st_mtime) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
if (link)
|
||||||
|
{
|
||||||
|
if (S_ISDIR(st.st_mode))
|
||||||
|
q = (char_u*)"linkd";
|
||||||
|
else
|
||||||
|
q = (char_u*)"link";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
q = getftypest(&st);
|
||||||
|
if (dict_add_string(item, "type", q) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_string(item, "perm", getfpermst(&st, permbuf)) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
pw = getpwuid(st.st_uid);
|
||||||
|
if (pw == NULL)
|
||||||
|
q = (char_u*)"";
|
||||||
|
else
|
||||||
|
q = (char_u*)pw->pw_name;
|
||||||
|
if (dict_add_string(item, "user", q) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
gr = getgrgid(st.st_gid);
|
||||||
|
if (gr == NULL)
|
||||||
|
q = (char_u*)"";
|
||||||
|
else
|
||||||
|
q = (char_u*)gr->gr_name;
|
||||||
|
if (dict_add_string(item, "group", q) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dict_add_number(item, "size", -1) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_number(item, "time", -1) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_string(item, "type", (char_u*)"") == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_string(item, "perm", (char_u*)"") == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_string(item, "user", (char_u*)"") == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dict_add_string(item, "group", (char_u*)"") == FAIL)
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
|
||||||
|
theend:
|
||||||
|
dict_unref(item);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_readdirex_item(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
char_u *name1, *name2;
|
||||||
|
|
||||||
|
name1 = dict_get_string(*(dict_T**)p1, (char_u*)"name", FALSE);
|
||||||
|
name2 = dict_get_string(*(dict_T**)p2, (char_u*)"name", FALSE);
|
||||||
|
return STRCMP(name1, name2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(TEMPDIRNAMES) || defined(FEAT_EVAL) || defined(PROTO)
|
#if defined(TEMPDIRNAMES) || defined(FEAT_EVAL) || defined(PROTO)
|
||||||
/*
|
/*
|
||||||
* Core part of "readdir()" function.
|
* Core part of "readdir()" and "readdirex()" function.
|
||||||
* Retrieve the list of files/directories of "path" into "gap".
|
* Retrieve the list of files/directories of "path" into "gap".
|
||||||
|
* If "withattr" is TRUE, retrieve the names and their attributes.
|
||||||
|
* If "withattr" is FALSE, retrieve the names only.
|
||||||
* Return OK for success, FAIL for failure.
|
* Return OK for success, FAIL for failure.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
readdir_core(
|
readdir_core(
|
||||||
garray_T *gap,
|
garray_T *gap,
|
||||||
char_u *path,
|
char_u *path,
|
||||||
|
int withattr UNUSED,
|
||||||
void *context,
|
void *context,
|
||||||
int (*checkitem)(void *context, char_u *name))
|
int (*checkitem)(void *context, void *item))
|
||||||
{
|
{
|
||||||
int failed = FALSE;
|
int failed = FALSE;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
|
||||||
ga_init2(gap, (int)sizeof(char *), 20);
|
|
||||||
|
|
||||||
# ifdef MSWIN
|
# ifdef MSWIN
|
||||||
{
|
|
||||||
char_u *buf;
|
char_u *buf;
|
||||||
int ok;
|
int ok;
|
||||||
HANDLE hFind = INVALID_HANDLE_VALUE;
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
||||||
WIN32_FIND_DATAW wfb;
|
WIN32_FIND_DATAW wfd;
|
||||||
WCHAR *wn = NULL; // UTF-16 name, NULL when not used.
|
WCHAR *wn = NULL; // UTF-16 name, NULL when not used.
|
||||||
|
# else
|
||||||
|
DIR *dirp;
|
||||||
|
struct dirent *dp;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
ga_init2(gap, (int)sizeof(void *), 20);
|
||||||
|
|
||||||
|
# ifdef FEAT_EVAL
|
||||||
|
# define FREE_ITEM(item) do { \
|
||||||
|
if (withattr) \
|
||||||
|
dict_unref((dict_T*)item); \
|
||||||
|
else \
|
||||||
|
vim_free(item); \
|
||||||
|
} while (0)
|
||||||
|
# else
|
||||||
|
# define FREE_ITEM(item) vim_free(item)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef MSWIN
|
||||||
buf = alloc(MAXPATHL);
|
buf = alloc(MAXPATHL);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -4454,11 +4696,11 @@ readdir_core(
|
|||||||
MB_PTR_BACK(buf, p);
|
MB_PTR_BACK(buf, p);
|
||||||
if (*p == '\\' || *p == '/')
|
if (*p == '\\' || *p == '/')
|
||||||
*p = NUL;
|
*p = NUL;
|
||||||
STRCAT(buf, "\\*");
|
STRCAT(p, "\\*");
|
||||||
|
|
||||||
wn = enc_to_utf16(buf, NULL);
|
wn = enc_to_utf16(buf, NULL);
|
||||||
if (wn != NULL)
|
if (wn != NULL)
|
||||||
hFind = FindFirstFileW(wn, &wfb);
|
hFind = FindFirstFileW(wn, &wfd);
|
||||||
ok = (hFind != INVALID_HANDLE_VALUE);
|
ok = (hFind != INVALID_HANDLE_VALUE);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
@@ -4470,20 +4712,32 @@ readdir_core(
|
|||||||
while (ok)
|
while (ok)
|
||||||
{
|
{
|
||||||
int ignore;
|
int ignore;
|
||||||
|
void *item;
|
||||||
|
WCHAR *wp;
|
||||||
|
|
||||||
p = utf16_to_enc(wfb.cFileName, NULL); // p is allocated here
|
wp = wfd.cFileName;
|
||||||
if (p == NULL)
|
ignore = wp[0] == L'.' &&
|
||||||
break; // out of memory
|
(wp[1] == NUL ||
|
||||||
|
(wp[1] == L'.' && wp[2] == NUL));
|
||||||
|
# ifdef FEAT_EVAL
|
||||||
|
if (withattr)
|
||||||
|
item = (void*)create_readdirex_item(&wfd);
|
||||||
|
else
|
||||||
|
# endif
|
||||||
|
item = (void*)utf16_to_enc(wfd.cFileName, NULL);
|
||||||
|
if (item == NULL)
|
||||||
|
{
|
||||||
|
failed = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ignore = p[0] == '.' && (p[1] == NUL
|
|
||||||
|| (p[1] == '.' && p[2] == NUL));
|
|
||||||
if (!ignore && checkitem != NULL)
|
if (!ignore && checkitem != NULL)
|
||||||
{
|
{
|
||||||
int r = checkitem(context, p);
|
int r = checkitem(context, item);
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
{
|
{
|
||||||
vim_free(p);
|
FREE_ITEM(item);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
@@ -4493,29 +4747,25 @@ readdir_core(
|
|||||||
if (!ignore)
|
if (!ignore)
|
||||||
{
|
{
|
||||||
if (ga_grow(gap, 1) == OK)
|
if (ga_grow(gap, 1) == OK)
|
||||||
((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
|
((void**)gap->ga_data)[gap->ga_len++] = item;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
failed = TRUE;
|
failed = TRUE;
|
||||||
vim_free(p);
|
FREE_ITEM(item);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
FREE_ITEM(item);
|
||||||
|
|
||||||
vim_free(p);
|
ok = FindNextFileW(hFind, &wfd);
|
||||||
ok = FindNextFileW(hFind, &wfb);
|
|
||||||
}
|
}
|
||||||
FindClose(hFind);
|
FindClose(hFind);
|
||||||
}
|
}
|
||||||
|
|
||||||
vim_free(buf);
|
vim_free(buf);
|
||||||
vim_free(wn);
|
vim_free(wn);
|
||||||
}
|
# else // MSWIN
|
||||||
# else
|
|
||||||
{
|
|
||||||
DIR *dirp;
|
|
||||||
struct dirent *dp;
|
|
||||||
|
|
||||||
dirp = opendir((char *)path);
|
dirp = opendir((char *)path);
|
||||||
if (dirp == NULL)
|
if (dirp == NULL)
|
||||||
{
|
{
|
||||||
@@ -4527,6 +4777,7 @@ readdir_core(
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
int ignore;
|
int ignore;
|
||||||
|
void *item;
|
||||||
|
|
||||||
dp = readdir(dirp);
|
dp = readdir(dirp);
|
||||||
if (dp == NULL)
|
if (dp == NULL)
|
||||||
@@ -4536,12 +4787,27 @@ readdir_core(
|
|||||||
ignore = p[0] == '.' &&
|
ignore = p[0] == '.' &&
|
||||||
(p[1] == NUL ||
|
(p[1] == NUL ||
|
||||||
(p[1] == '.' && p[2] == NUL));
|
(p[1] == '.' && p[2] == NUL));
|
||||||
|
# ifdef FEAT_EVAL
|
||||||
|
if (withattr)
|
||||||
|
item = (void*)create_readdirex_item(path, p);
|
||||||
|
else
|
||||||
|
# endif
|
||||||
|
item = (void*)vim_strsave(p);
|
||||||
|
if (item == NULL)
|
||||||
|
{
|
||||||
|
failed = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ignore && checkitem != NULL)
|
if (!ignore && checkitem != NULL)
|
||||||
{
|
{
|
||||||
int r = checkitem(context, p);
|
int r = checkitem(context, item);
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
{
|
||||||
|
FREE_ITEM(item);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
ignore = TRUE;
|
ignore = TRUE;
|
||||||
}
|
}
|
||||||
@@ -4549,22 +4815,34 @@ readdir_core(
|
|||||||
if (!ignore)
|
if (!ignore)
|
||||||
{
|
{
|
||||||
if (ga_grow(gap, 1) == OK)
|
if (ga_grow(gap, 1) == OK)
|
||||||
((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
|
((void**)gap->ga_data)[gap->ga_len++] = item;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
failed = TRUE;
|
failed = TRUE;
|
||||||
|
FREE_ITEM(item);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
FREE_ITEM(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dirp);
|
closedir(dirp);
|
||||||
}
|
}
|
||||||
}
|
# endif // MSWIN
|
||||||
# endif
|
|
||||||
|
# undef FREE_ITEM
|
||||||
|
|
||||||
if (!failed && gap->ga_len > 0)
|
if (!failed && gap->ga_len > 0)
|
||||||
|
{
|
||||||
|
# ifdef FEAT_EVAL
|
||||||
|
if (withattr)
|
||||||
|
qsort((void*)gap->ga_data, (size_t)gap->ga_len, sizeof(dict_T*),
|
||||||
|
compare_readdirex_item);
|
||||||
|
else
|
||||||
|
# endif
|
||||||
sort_strings((char_u **)gap->ga_data, gap->ga_len);
|
sort_strings((char_u **)gap->ga_data, gap->ga_len);
|
||||||
|
}
|
||||||
|
|
||||||
return failed ? FAIL : OK;
|
return failed ? FAIL : OK;
|
||||||
}
|
}
|
||||||
@@ -4594,7 +4872,7 @@ delete_recursive(char_u *name)
|
|||||||
exp = vim_strsave(name);
|
exp = vim_strsave(name);
|
||||||
if (exp == NULL)
|
if (exp == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
if (readdir_core(&ga, exp, NULL, NULL) == OK)
|
if (readdir_core(&ga, exp, FALSE, NULL, NULL) == OK)
|
||||||
{
|
{
|
||||||
for (i = 0; i < ga.ga_len; ++i)
|
for (i = 0; i < ga.ga_len; ++i)
|
||||||
{
|
{
|
||||||
|
157
src/filepath.c
157
src/filepath.c
@@ -1028,6 +1028,25 @@ f_getcwd(typval_T *argvars, typval_T *rettv)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert "st" to file permission string.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
getfpermst(stat_T *st, char_u *perm)
|
||||||
|
{
|
||||||
|
char_u flags[] = "rwx";
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 9; i++)
|
||||||
|
{
|
||||||
|
if (st->st_mode & (1 << (8 - i)))
|
||||||
|
perm[i] = flags[i % 3];
|
||||||
|
else
|
||||||
|
perm[i] = '-';
|
||||||
|
}
|
||||||
|
return perm;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "getfperm({fname})" function
|
* "getfperm({fname})" function
|
||||||
*/
|
*/
|
||||||
@@ -1037,24 +1056,13 @@ f_getfperm(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u *fname;
|
char_u *fname;
|
||||||
stat_T st;
|
stat_T st;
|
||||||
char_u *perm = NULL;
|
char_u *perm = NULL;
|
||||||
char_u flags[] = "rwx";
|
char_u permbuf[] = "---------";
|
||||||
int i;
|
|
||||||
|
|
||||||
fname = tv_get_string(&argvars[0]);
|
fname = tv_get_string(&argvars[0]);
|
||||||
|
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
if (mch_stat((char *)fname, &st) >= 0)
|
if (mch_stat((char *)fname, &st) >= 0)
|
||||||
{
|
perm = vim_strsave(getfpermst(&st, permbuf));
|
||||||
perm = vim_strsave((char_u *)"---------");
|
|
||||||
if (perm != NULL)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 9; i++)
|
|
||||||
{
|
|
||||||
if (st.st_mode & (1 << (8 - i)))
|
|
||||||
perm[i] = flags[i % 3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rettv->vval.v_string = perm;
|
rettv->vval.v_string = perm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1105,6 +1113,33 @@ f_getftime(typval_T *argvars, typval_T *rettv)
|
|||||||
rettv->vval.v_number = -1;
|
rettv->vval.v_number = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert "st" to file type string.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
getftypest(stat_T *st)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
if (S_ISREG(st->st_mode))
|
||||||
|
t = "file";
|
||||||
|
else if (S_ISDIR(st->st_mode))
|
||||||
|
t = "dir";
|
||||||
|
else if (S_ISLNK(st->st_mode))
|
||||||
|
t = "link";
|
||||||
|
else if (S_ISBLK(st->st_mode))
|
||||||
|
t = "bdev";
|
||||||
|
else if (S_ISCHR(st->st_mode))
|
||||||
|
t = "cdev";
|
||||||
|
else if (S_ISFIFO(st->st_mode))
|
||||||
|
t = "fifo";
|
||||||
|
else if (S_ISSOCK(st->st_mode))
|
||||||
|
t = "socket";
|
||||||
|
else
|
||||||
|
t = "other";
|
||||||
|
return (char_u*)t;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "getftype({fname})" function
|
* "getftype({fname})" function
|
||||||
*/
|
*/
|
||||||
@@ -1114,31 +1149,12 @@ f_getftype(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u *fname;
|
char_u *fname;
|
||||||
stat_T st;
|
stat_T st;
|
||||||
char_u *type = NULL;
|
char_u *type = NULL;
|
||||||
char *t;
|
|
||||||
|
|
||||||
fname = tv_get_string(&argvars[0]);
|
fname = tv_get_string(&argvars[0]);
|
||||||
|
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
if (mch_lstat((char *)fname, &st) >= 0)
|
if (mch_lstat((char *)fname, &st) >= 0)
|
||||||
{
|
type = vim_strsave(getftypest(&st));
|
||||||
if (S_ISREG(st.st_mode))
|
|
||||||
t = "file";
|
|
||||||
else if (S_ISDIR(st.st_mode))
|
|
||||||
t = "dir";
|
|
||||||
else if (S_ISLNK(st.st_mode))
|
|
||||||
t = "link";
|
|
||||||
else if (S_ISBLK(st.st_mode))
|
|
||||||
t = "bdev";
|
|
||||||
else if (S_ISCHR(st.st_mode))
|
|
||||||
t = "cdev";
|
|
||||||
else if (S_ISFIFO(st.st_mode))
|
|
||||||
t = "fifo";
|
|
||||||
else if (S_ISSOCK(st.st_mode))
|
|
||||||
t = "socket";
|
|
||||||
else
|
|
||||||
t = "other";
|
|
||||||
type = vim_strsave((char_u *)t);
|
|
||||||
}
|
|
||||||
rettv->vval.v_string = type;
|
rettv->vval.v_string = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1359,7 +1375,7 @@ f_pathshorten(typval_T *argvars, typval_T *rettv)
|
|||||||
* Evaluate "expr" (= "context") for readdir().
|
* Evaluate "expr" (= "context") for readdir().
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
readdir_checkitem(void *context, char_u *name)
|
readdir_checkitem(void *context, void *item)
|
||||||
{
|
{
|
||||||
typval_T *expr = (typval_T *)context;
|
typval_T *expr = (typval_T *)context;
|
||||||
typval_T save_val;
|
typval_T save_val;
|
||||||
@@ -1367,9 +1383,7 @@ readdir_checkitem(void *context, char_u *name)
|
|||||||
typval_T argv[2];
|
typval_T argv[2];
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
int error = FALSE;
|
int error = FALSE;
|
||||||
|
char_u *name = (char_u*)item;
|
||||||
if (expr->v_type == VAR_UNKNOWN)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
prepare_vimvar(VV_VAL, &save_val);
|
prepare_vimvar(VV_VAL, &save_val);
|
||||||
set_vim_var_string(VV_VAL, name, -1);
|
set_vim_var_string(VV_VAL, name, -1);
|
||||||
@@ -1408,8 +1422,9 @@ f_readdir(typval_T *argvars, typval_T *rettv)
|
|||||||
path = tv_get_string(&argvars[0]);
|
path = tv_get_string(&argvars[0]);
|
||||||
expr = &argvars[1];
|
expr = &argvars[1];
|
||||||
|
|
||||||
ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
|
ret = readdir_core(&ga, path, FALSE, (void *)expr,
|
||||||
if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
|
(expr->v_type == VAR_UNKNOWN) ? NULL : readdir_checkitem);
|
||||||
|
if (ret == OK)
|
||||||
{
|
{
|
||||||
for (i = 0; i < ga.ga_len; i++)
|
for (i = 0; i < ga.ga_len; i++)
|
||||||
{
|
{
|
||||||
@@ -1420,6 +1435,70 @@ f_readdir(typval_T *argvars, typval_T *rettv)
|
|||||||
ga_clear_strings(&ga);
|
ga_clear_strings(&ga);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evaluate "expr" (= "context") for readdirex().
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
readdirex_checkitem(void *context, void *item)
|
||||||
|
{
|
||||||
|
typval_T *expr = (typval_T *)context;
|
||||||
|
typval_T save_val;
|
||||||
|
typval_T rettv;
|
||||||
|
typval_T argv[2];
|
||||||
|
int retval = 0;
|
||||||
|
int error = FALSE;
|
||||||
|
dict_T *dict = (dict_T*)item;
|
||||||
|
|
||||||
|
prepare_vimvar(VV_VAL, &save_val);
|
||||||
|
set_vim_var_dict(VV_VAL, dict);
|
||||||
|
argv[0].v_type = VAR_DICT;
|
||||||
|
argv[0].vval.v_dict = dict;
|
||||||
|
|
||||||
|
if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
retval = tv_get_number_chk(&rettv, &error);
|
||||||
|
if (error)
|
||||||
|
retval = -1;
|
||||||
|
clear_tv(&rettv);
|
||||||
|
|
||||||
|
theend:
|
||||||
|
set_vim_var_dict(VV_VAL, NULL);
|
||||||
|
restore_vimvar(VV_VAL, &save_val);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "readdirex()" function
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
f_readdirex(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
typval_T *expr;
|
||||||
|
int ret;
|
||||||
|
char_u *path;
|
||||||
|
garray_T ga;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (rettv_list_alloc(rettv) == FAIL)
|
||||||
|
return;
|
||||||
|
path = tv_get_string(&argvars[0]);
|
||||||
|
expr = &argvars[1];
|
||||||
|
|
||||||
|
ret = readdir_core(&ga, path, TRUE, (void *)expr,
|
||||||
|
(expr->v_type == VAR_UNKNOWN) ? NULL : readdirex_checkitem);
|
||||||
|
if (ret == OK)
|
||||||
|
{
|
||||||
|
for (i = 0; i < ga.ga_len; i++)
|
||||||
|
{
|
||||||
|
dict_T *dict = ((dict_T**)ga.ga_data)[i];
|
||||||
|
list_append_dict(rettv->vval.v_list, dict);
|
||||||
|
dict_unref(dict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ga_clear(&ga);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "readfile()" function
|
* "readfile()" function
|
||||||
*/
|
*/
|
||||||
|
@@ -31,7 +31,7 @@ int buf_check_timestamp(buf_T *buf, int focus);
|
|||||||
void buf_reload(buf_T *buf, int orig_mode);
|
void buf_reload(buf_T *buf, int orig_mode);
|
||||||
void buf_store_time(buf_T *buf, stat_T *st, char_u *fname);
|
void buf_store_time(buf_T *buf, stat_T *st, char_u *fname);
|
||||||
void write_lnum_adjust(linenr_T offset);
|
void write_lnum_adjust(linenr_T offset);
|
||||||
int readdir_core(garray_T *gap, char_u *path, void *context, int (*checkitem)(void *context, char_u *name));
|
int readdir_core(garray_T *gap, char_u *path, int withattr, void *context, int (*checkitem)(void *context, void *item));
|
||||||
int delete_recursive(char_u *name);
|
int delete_recursive(char_u *name);
|
||||||
void vim_deltempdir(void);
|
void vim_deltempdir(void);
|
||||||
char_u *vim_tempname(int extra_char, int keep);
|
char_u *vim_tempname(int extra_char, int keep);
|
||||||
|
@@ -10,9 +10,11 @@ void f_finddir(typval_T *argvars, typval_T *rettv);
|
|||||||
void f_findfile(typval_T *argvars, typval_T *rettv);
|
void f_findfile(typval_T *argvars, typval_T *rettv);
|
||||||
void f_fnamemodify(typval_T *argvars, typval_T *rettv);
|
void f_fnamemodify(typval_T *argvars, typval_T *rettv);
|
||||||
void f_getcwd(typval_T *argvars, typval_T *rettv);
|
void f_getcwd(typval_T *argvars, typval_T *rettv);
|
||||||
|
char_u *getfpermst(stat_T *st, char_u *perm);
|
||||||
void f_getfperm(typval_T *argvars, typval_T *rettv);
|
void f_getfperm(typval_T *argvars, typval_T *rettv);
|
||||||
void f_getfsize(typval_T *argvars, typval_T *rettv);
|
void f_getfsize(typval_T *argvars, typval_T *rettv);
|
||||||
void f_getftime(typval_T *argvars, typval_T *rettv);
|
void f_getftime(typval_T *argvars, typval_T *rettv);
|
||||||
|
char_u *getftypest(stat_T *st);
|
||||||
void f_getftype(typval_T *argvars, typval_T *rettv);
|
void f_getftype(typval_T *argvars, typval_T *rettv);
|
||||||
void f_glob(typval_T *argvars, typval_T *rettv);
|
void f_glob(typval_T *argvars, typval_T *rettv);
|
||||||
void f_glob2regpat(typval_T *argvars, typval_T *rettv);
|
void f_glob2regpat(typval_T *argvars, typval_T *rettv);
|
||||||
@@ -21,6 +23,7 @@ void f_isdirectory(typval_T *argvars, typval_T *rettv);
|
|||||||
void f_mkdir(typval_T *argvars, typval_T *rettv);
|
void f_mkdir(typval_T *argvars, typval_T *rettv);
|
||||||
void f_pathshorten(typval_T *argvars, typval_T *rettv);
|
void f_pathshorten(typval_T *argvars, typval_T *rettv);
|
||||||
void f_readdir(typval_T *argvars, typval_T *rettv);
|
void f_readdir(typval_T *argvars, typval_T *rettv);
|
||||||
|
void f_readdirex(typval_T *argvars, typval_T *rettv);
|
||||||
void f_readfile(typval_T *argvars, typval_T *rettv);
|
void f_readfile(typval_T *argvars, typval_T *rettv);
|
||||||
void f_resolve(typval_T *argvars, typval_T *rettv);
|
void f_resolve(typval_T *argvars, typval_T *rettv);
|
||||||
void f_tempname(typval_T *argvars, typval_T *rettv);
|
void f_tempname(typval_T *argvars, typval_T *rettv);
|
||||||
|
@@ -1834,7 +1834,7 @@ func Test_readdir()
|
|||||||
call assert_equal(['bar.txt', 'dir', 'foo.txt'], sort(files))
|
call assert_equal(['bar.txt', 'dir', 'foo.txt'], sort(files))
|
||||||
|
|
||||||
" Only results containing "f"
|
" Only results containing "f"
|
||||||
let files = 'Xdir'->readdir({ x -> stridx(x, 'f') !=- 1 })
|
let files = 'Xdir'->readdir({ x -> stridx(x, 'f') != -1 })
|
||||||
call assert_equal(['foo.txt'], sort(files))
|
call assert_equal(['foo.txt'], sort(files))
|
||||||
|
|
||||||
" Only .txt files
|
" Only .txt files
|
||||||
@@ -1857,6 +1857,45 @@ func Test_readdir()
|
|||||||
eval 'Xdir'->delete('rf')
|
eval 'Xdir'->delete('rf')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_readdirex()
|
||||||
|
call mkdir('Xdir')
|
||||||
|
call writefile([], 'Xdir/foo.txt')
|
||||||
|
call writefile([], 'Xdir/bar.txt')
|
||||||
|
call mkdir('Xdir/dir')
|
||||||
|
|
||||||
|
" All results
|
||||||
|
let files = readdirex('Xdir')->map({-> v:val.name})
|
||||||
|
call assert_equal(['bar.txt', 'dir', 'foo.txt'], sort(files))
|
||||||
|
|
||||||
|
" Only results containing "f"
|
||||||
|
let files = 'Xdir'->readdirex({ e -> stridx(e.name, 'f') != -1 })
|
||||||
|
\ ->map({-> v:val.name})
|
||||||
|
call assert_equal(['foo.txt'], sort(files))
|
||||||
|
|
||||||
|
" Only .txt files
|
||||||
|
let files = readdirex('Xdir', { e -> e.name =~ '.txt$' })
|
||||||
|
\ ->map({-> v:val.name})
|
||||||
|
call assert_equal(['bar.txt', 'foo.txt'], sort(files))
|
||||||
|
|
||||||
|
" Only .txt files with string
|
||||||
|
let files = readdirex('Xdir', 'v:val.name =~ ".txt$"')
|
||||||
|
\ ->map({-> v:val.name})
|
||||||
|
call assert_equal(['bar.txt', 'foo.txt'], sort(files))
|
||||||
|
|
||||||
|
" Limit to 1 result.
|
||||||
|
let l = []
|
||||||
|
let files = readdirex('Xdir', {e -> len(add(l, e.name)) == 2 ? -1 : 1})
|
||||||
|
\ ->map({-> v:val.name})
|
||||||
|
call assert_equal(1, len(files))
|
||||||
|
|
||||||
|
" Nested readdirex() must not crash
|
||||||
|
let files = readdirex('Xdir', 'readdirex("Xdir", "1") != []')
|
||||||
|
\ ->map({-> v:val.name})
|
||||||
|
call sort(files)->assert_equal(['bar.txt', 'dir', 'foo.txt'])
|
||||||
|
|
||||||
|
eval 'Xdir'->delete('rf')
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_delete_rf()
|
func Test_delete_rf()
|
||||||
call mkdir('Xdir')
|
call mkdir('Xdir')
|
||||||
call writefile([], 'Xdir/foo.txt')
|
call writefile([], 'Xdir/foo.txt')
|
||||||
|
@@ -746,6 +746,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
875,
|
||||||
/**/
|
/**/
|
||||||
874,
|
874,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user