summaryrefslogtreecommitdiff
path: root/src/misc1.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2005-07-25 20:46:57 +0000
committerBram Moolenaar <Bram@vim.org>2005-07-25 20:46:57 +0000
commit231334e6efbf3a7f89183f8257e09492534a5f8c (patch)
treeb28b269502f6374b49f3fed5814c746f2edd3517 /src/misc1.c
parent027436338b4b3e746ae5087b8a01c7404619d97b (diff)
downloadvim-git-231334e6efbf3a7f89183f8257e09492534a5f8c.tar.gz
updated for version 7.0116v7.0116
Diffstat (limited to 'src/misc1.c')
-rw-r--r--src/misc1.c295
1 files changed, 279 insertions, 16 deletions
diff --git a/src/misc1.c b/src/misc1.c
index f0de5935a..7c50470f7 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -8158,24 +8158,33 @@ namelowcpy(
# endif
/*
- * Recursively build up a list of files in "gap" matching the first wildcard
- * in `path'. Called by expand_wildcards().
+ * Recursively expand one path component into all matching files and/or
+ * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc.
* Return the number of matches found.
* "path" has backslashes before chars that are not to be expanded, starting
* at "path[wildoff]".
+ * Return the number of matches found.
+ * NOTE: much of this is identical to unix_expandpath(), keep in sync!
*/
static int
dos_expandpath(
garray_T *gap,
char_u *path,
int wildoff,
- int flags) /* EW_* flags */
+ int flags, /* EW_* flags */
+ int didstar) /* expaneded "**" once already */
{
- char_u *buf;
- char_u *path_end;
- char_u *p, *s, *e;
- int start_len = gap->ga_len;
- int ok;
+ char_u *buf;
+ char_u *path_end;
+ char_u *p, *s, *e;
+ int start_len = gap->ga_len;
+ char_u *pat;
+ regmatch_T regmatch;
+ int starts_with_dot;
+ int matches;
+ int len;
+ int starstar = FALSE;
+ static int stardepth = 0; /* depth for "**" expansion */
#ifdef WIN3264
WIN32_FIND_DATA fb;
HANDLE hFind = (HANDLE)0;
@@ -8186,15 +8195,19 @@ dos_expandpath(
#else
struct ffblk fb;
#endif
- int matches;
- int starts_with_dot;
- int len;
- char_u *pat;
- regmatch_T regmatch;
char_u *matchname;
+ int ok;
+
+ /* Expanding "**" may take a long time, check for CTRL-C. */
+ if (stardepth > 0)
+ {
+ ui_breakcheck();
+ if (got_int)
+ return 0;
+ }
/* make room for file name */
- buf = alloc((unsigned int)STRLEN(path) + BASENAMELEN + 5);
+ buf = alloc((int)STRLEN(path) + BASENAMELEN + 5);
if (buf == NULL)
return 0;
@@ -8247,6 +8260,11 @@ dos_expandpath(
--s;
}
+ /* Check for "**" between "s" and "e". */
+ for (p = s; p < e; ++p)
+ if (p[0] == '*' && p[1] == '*')
+ starstar = TRUE;
+
starts_with_dot = (*s == '.');
pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
if (pat == NULL)
@@ -8269,6 +8287,17 @@ dos_expandpath(
/* remember the pattern or file name being looked for */
matchname = vim_strsave(s);
+ /* If "**" is by itself, this is the first time we encounter it and more
+ * is following then find matches without any directory. */
+ if (!didstar && stardepth < 100 && starstar && e - s == 2
+ && *path_end == '/')
+ {
+ STRCPY(s, path_end + 1);
+ ++stardepth;
+ (void)dos_expandpath(gap, buf, (int)(s - buf), flags, TRUE);
+ --stardepth;
+ }
+
/* Scan all files in the directory with "dir/ *.*" */
STRCPY(s, "*.*");
#ifdef WIN3264
@@ -8325,12 +8354,24 @@ dos_expandpath(
namelowcpy(s, p);
#endif
len = (int)STRLEN(buf);
+
+ if (starstar && stardepth < 100)
+ {
+ /* For "**" in the pattern first go deeper in the tree to
+ * find matches. */
+ STRCPY(buf + len, "/**");
+ STRCPY(buf + len + 3, path_end);
+ ++stardepth;
+ (void)dos_expandpath(gap, buf, len + 1, flags, TRUE);
+ --stardepth;
+ }
+
STRCPY(buf + len, path_end);
if (mch_has_exp_wildcard(path_end))
{
/* need to expand another component of the path */
/* remove backslashes for the remaining components only */
- (void)dos_expandpath(gap, buf, len + 1, flags);
+ (void)dos_expandpath(gap, buf, len + 1, flags, FALSE);
}
else
{
@@ -8408,10 +8449,232 @@ mch_expandpath(
char_u *path,
int flags) /* EW_* flags */
{
- return dos_expandpath(gap, path, 0, flags);
+ return dos_expandpath(gap, path, 0, flags, FALSE);
}
# endif /* MSDOS || FEAT_GUI_W16 || WIN3264 */
+#if (defined(UNIX) && !defined(VMS)) || defined(USE_UNIXFILENAME) \
+ || defined(PROTO)
+/*
+ * Unix style wildcard expansion code.
+ * It's here because it's used both for Unix and Mac.
+ */
+static int pstrcmp __ARGS((const void *, const void *));
+
+ static int
+pstrcmp(a, b)
+ const void *a, *b;
+{
+ return (pathcmp(*(char **)a, *(char **)b, -1));
+}
+
+/*
+ * Recursively expand one path component into all matching files and/or
+ * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc.
+ * "path" has backslashes before chars that are not to be expanded, starting
+ * at "path + wildoff".
+ * Return the number of matches found.
+ * NOTE: much of this is identical to dos_expandpath(), keep in sync!
+ */
+ int
+unix_expandpath(gap, path, wildoff, flags, didstar)
+ garray_T *gap;
+ char_u *path;
+ int wildoff;
+ int flags; /* EW_* flags */
+ int didstar; /* expanded "**" once already */
+{
+ char_u *buf;
+ char_u *path_end;
+ char_u *p, *s, *e;
+ int start_len = gap->ga_len;
+ char_u *pat;
+ regmatch_T regmatch;
+ int starts_with_dot;
+ int matches;
+ int len;
+ int starstar = FALSE;
+ static int stardepth = 0; /* depth for "**" expansion */
+
+ DIR *dirp;
+ struct dirent *dp;
+
+ /* Expanding "**" may take a long time, check for CTRL-C. */
+ if (stardepth > 0)
+ {
+ ui_breakcheck();
+ if (got_int)
+ return 0;
+ }
+
+ /* make room for file name */
+ buf = alloc((int)STRLEN(path) + BASENAMELEN + 5);
+ if (buf == NULL)
+ return 0;
+
+ /*
+ * Find the first part in the path name that contains a wildcard.
+ * Copy it into "buf", including the preceding characters.
+ */
+ p = buf;
+ s = buf;
+ e = NULL;
+ path_end = path;
+ 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(path_end))
+ *p++ = *path_end++;
+ else if (*path_end == '/')
+ {
+ if (e != NULL)
+ break;
+ s = p + 1;
+ }
+ else if (path_end >= path + wildoff
+ && vim_strchr((char_u *)"*?[{~$", *path_end) != NULL)
+ e = p;
+#ifdef FEAT_MBYTE
+ if (has_mbyte)
+ {
+ len = (*mb_ptr2len_check)(path_end);
+ STRNCPY(p, path_end, len);
+ p += len;
+ path_end += len;
+ }
+ else
+#endif
+ *p++ = *path_end++;
+ }
+ e = p;
+ *e = NUL;
+
+ /* now we have one wildcard component between "s" and "e" */
+ /* Remove backslashes between "wildoff" and the start of the wildcard
+ * component. */
+ for (p = buf + wildoff; p < s; ++p)
+ if (rem_backslash(p))
+ {
+ STRCPY(p, p + 1);
+ --e;
+ --s;
+ }
+
+ /* Check for "**" between "s" and "e". */
+ for (p = s; p < e; ++p)
+ if (p[0] == '*' && p[1] == '*')
+ starstar = TRUE;
+
+ /* convert the file pattern to a regexp pattern */
+ starts_with_dot = (*s == '.');
+ pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
+ if (pat == NULL)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* compile the regexp into a program */
+#ifdef MACOS_X /* Can/Should we use CASE_INSENSITIVE_FILENAME instead ?*/
+ regmatch.rm_ic = TRUE; /* Behave like Terminal.app */
+#else
+ regmatch.rm_ic = FALSE; /* Don't ever ignore case */
+#endif
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
+ vim_free(pat);
+
+ if (regmatch.regprog == NULL)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* If "**" is by itself, this is the first time we encounter it and more
+ * is following then find matches without any directory. */
+ if (!didstar && stardepth < 100 && starstar && e - s == 2
+ && *path_end == '/')
+ {
+ STRCPY(s, path_end + 1);
+ ++stardepth;
+ (void)unix_expandpath(gap, buf, (int)(s - buf), flags, TRUE);
+ --stardepth;
+ }
+
+ /* open the directory for scanning */
+ *s = NUL;
+ dirp = opendir(*buf == NUL ? "." : (char *)buf);
+
+ /* Find all matching entries */
+ if (dirp != NULL)
+ {
+ for (;;)
+ {
+ dp = readdir(dirp);
+ if (dp == NULL)
+ break;
+ if ((dp->d_name[0] != '.' || starts_with_dot)
+ && vim_regexec(&regmatch, (char_u *)dp->d_name, (colnr_T)0))
+ {
+ STRCPY(s, dp->d_name);
+ len = STRLEN(buf);
+
+ if (starstar && stardepth < 100)
+ {
+ /* For "**" in the pattern first go deeper in the tree to
+ * find matches. */
+ STRCPY(buf + len, "/**");
+ STRCPY(buf + len + 3, path_end);
+ ++stardepth;
+ (void)unix_expandpath(gap, buf, len + 1, flags, TRUE);
+ --stardepth;
+ }
+
+ STRCPY(buf + len, path_end);
+ if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
+ {
+ /* need to expand another component of the path */
+ /* remove backslashes for the remaining components only */
+ (void)unix_expandpath(gap, buf, len + 1, flags, FALSE);
+ }
+ else
+ {
+ /* no more wildcards, check if there is a match */
+ /* remove backslashes for the remaining components only */
+ if (*path_end != NUL)
+ backslash_halve(buf + len + 1);
+ if (mch_getperm(buf) >= 0) /* add existing file */
+ {
+#if defined(MACOS_X) && defined(FEAT_MBYTE)
+ size_t precomp_len = STRLEN(buf)+1;
+ char_u *precomp_buf =
+ mac_precompose_path(buf, precomp_len, &precomp_len);
+ if (precomp_buf)
+ {
+ mch_memmove(buf, precomp_buf, precomp_len);
+ vim_free(precomp_buf);
+ }
+#endif
+ addfile(gap, buf, flags);
+ }
+ }
+ }
+ }
+
+ closedir(dirp);
+ }
+
+ vim_free(buf);
+ vim_free(regmatch.regprog);
+
+ matches = gap->ga_len - start_len;
+ if (matches > 0)
+ qsort(((char_u **)gap->ga_data) + start_len, matches,
+ sizeof(char_u *), pstrcmp);
+ return matches;
+}
+#endif
+
/*
* Generic wildcard expansion code.
*