os_scandir: mch/unix_expandpath() -> path_expand()

Merge unix_expandpath with dos_expandpath from upstream vim and use
os_scandir() over POSIX readdir().
This commit is contained in:
Scott Prager 2014-09-19 20:21:02 -04:00 committed by Thiago de Arruda
parent 3f74067565
commit 24da0d49d0

View File

@ -438,7 +438,7 @@ static int pstrcmp(const void *a, const void *b)
} }
#endif #endif
/// Checks if a path has a character expandpath can expand. /// Checks if a path has a character path_expand can expand.
/// @param p The path to expand. /// @param p The path to expand.
/// @returns Unix: True if it contains one of *?[{. /// @returns Unix: True if it contains one of *?[{.
/// @returns Windows: True if it contains one of *?[. /// @returns Windows: True if it contains one of *?[.
@ -463,38 +463,40 @@ bool path_has_exp_wildcard(const char_u *p)
return false; return false;
} }
/* /// Recursively expands one path component into all matching files and/or
* Recursively expand one path component into all matching files and/or /// directories. Handles "*", "?", "[a-z]", "**", etc.
* directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc. /// @remark "**" in `path` requests recursive expansion.
* "path" has backslashes before chars that are not to be expanded, starting ///
* at "path + wildoff". /// @param[out] gap The matches found.
* Return the number of matches found. /// @param path The path to search.
* NOTE: much of this is identical to dos_expandpath(), keep in sync! /// @param flags Flags for regexp expansion.
*/ /// - EW_ICASE: Ignore case.
int /// - EW_NOERROR: Silence error messeges.
unix_expandpath ( /// - EW_NOTWILD: Add matches literally.
garray_T *gap, /// @returns the number of matches found.
char_u *path, static size_t path_expand(garray_T *gap, const char_u *path, int flags)
int wildoff, FUNC_ATTR_NONNULL_ALL
int flags, /* EW_* flags */ {
int didstar /* expanded "**" once already */ 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();
@ -513,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. */
@ -562,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);
@ -585,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(&regmatch, && ((regmatch.regprog != NULL && vim_regexec(&regmatch, 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) {
@ -613,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 (path_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 */
@ -633,8 +634,7 @@ unix_expandpath (
} }
} }
} }
os_closedir(&dir);
closedir(dirp);
} }
free(buf); free(buf);
@ -646,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".
@ -1144,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);
} }
} }
@ -1722,19 +1721,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.
/// ///