]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0924: patch 9.1.0923 causes issues v9.1.0924
authorChristian Brabandt <cb@256bit.org>
Fri, 13 Dec 2024 16:54:33 +0000 (17:54 +0100)
committerChristian Brabandt <cb@256bit.org>
Fri, 13 Dec 2024 16:56:46 +0000 (17:56 +0100)
Problem:  patch 9.1.0923 causes issues (Shane-XB-Qian)
Solution: back-out the change

This reverts commit e29c8bafa78847414419522baecd008e287389db (v9.1.0923)

fixes: #16213
related: #16160

Signed-off-by: Christian Brabandt <cb@256bit.org>
src/filepath.c
src/os_unix.c
src/proto/filepath.pro
src/version.c

index 729884252716a8d66c2b09e554cd3f736a3c1be5..3dd71bc407e92b253b9146286e71ad45156496af 100644 (file)
     static int
 get_short_pathname(char_u **fnamep, char_u **bufp, int *fnamelen)
 {
-    int                l;
+    int                l, len;
     WCHAR      *newbuf;
     WCHAR      *wfname;
 
-    newbuf = alloc(MAXPATHL * sizeof(*newbuf));
+    len = MAXPATHL;
+    newbuf = malloc(len * sizeof(*newbuf));
     if (newbuf == NULL)
        return FAIL;
 
@@ -44,8 +45,8 @@ get_short_pathname(char_u **fnamep, char_u **bufp, int *fnamelen)
        return FAIL;
     }
 
-    l = GetShortPathNameW(wfname, newbuf, MAXPATHL);
-    if (l > MAXPATHL - 1)
+    l = GetShortPathNameW(wfname, newbuf, len);
+    if (l > len - 1)
     {
        // If that doesn't work (not enough space), then save the string
        // and try again with a new buffer big enough.
@@ -104,7 +105,7 @@ shortpath_for_invalid_fname(
     char_u     **bufp,
     int                *fnamelen)
 {
-    char_u     *short_fname = NULL, *save_fname = NULL, *pbuf_unused = NULL;
+    char_u     *short_fname, *save_fname, *pbuf_unused;
     char_u     *endp, *save_endp;
     char_u     ch;
     int                old_len, len;
@@ -114,11 +115,6 @@ shortpath_for_invalid_fname(
     // Make a copy
     old_len = *fnamelen;
     save_fname = vim_strnsave(*fname, old_len);
-    if (save_fname == NULL)
-    {
-       retval = FAIL;
-       goto theend;
-    }
     pbuf_unused = NULL;
     short_fname = NULL;
 
@@ -143,9 +139,9 @@ shortpath_for_invalid_fname(
         * resulting path.
         */
        ch = *endp;
-       *endp = NUL;
+       *endp = 0;
        short_fname = save_fname;
-       len = (int)(endp - save_fname) + 1;
+       len = (int)STRLEN(short_fname) + 1;
        if (get_short_pathname(&short_fname, &pbuf_unused, &len) == FAIL)
        {
            retval = FAIL;
@@ -229,7 +225,7 @@ shortpath_for_partial(
        if (vim_ispathsep(*p))
            ++sepcount;
 
-    // Need full path first (use expand_env_save() to remove a "~/")
+    // Need full path first (use expand_env() to remove a "~/")
     hasTilde = (**fnamep == '~');
     if (hasTilde)
        pbuf = tfname = expand_env_save(*fnamep);
@@ -277,7 +273,7 @@ shortpath_for_partial(
 
     // Copy in the string - p indexes into tfname - allocated at pbuf
     vim_free(*bufp);
-    *fnamelen = (int)((tfname + len) - p);
+    *fnamelen = (int)STRLEN(p);
     *bufp = pbuf;
     *fnamep = p;
 
@@ -418,7 +414,7 @@ repeat:
            continue;
        }
        pbuf = NULL;
-       // Need full path first (use expand_env_save() to remove a "~/")
+       // Need full path first (use expand_env() to remove a "~/")
        if (!has_fullname && !has_homerelative)
        {
            if (**fnamep == '~')
@@ -509,7 +505,7 @@ repeat:
        if (*fnamelen == 0)
        {
            // Result is empty.  Turn it into "." to make ":cd %:h" work.
-           p = vim_strnsave((char_u *)".", 1);
+           p = vim_strsave((char_u *)".");
            if (p == NULL)
                return -1;
            vim_free(*bufp);
@@ -1548,10 +1544,8 @@ f_mkdir(typval_T *argvars, typval_T *rettv)
        tv[0].vval.v_string = created;
        tv[1].v_type = VAR_STRING;
        tv[1].v_lock = 0;
-       if (defer_recurse)
-           tv[1].vval.v_string = vim_strnsave((char_u *)"rf", 2);
-       else
-           tv[1].vval.v_string = vim_strnsave((char_u *)"d", 1);
+       tv[1].vval.v_string = vim_strsave(
+                                      (char_u *)(defer_recurse ? "rf" : "d"));
        if (tv[0].vval.v_string == NULL || tv[1].vval.v_string == NULL
                || add_defer((char_u *)"delete", 2, tv) == FAIL)
        {
@@ -2064,8 +2058,6 @@ f_resolve(typval_T *argvars, typval_T *rettv)
     char_u     *p;
 #ifdef HAVE_READLINK
     char_u     *buf = NULL;
-    char_u     *remain = NULL;
-    int                p_was_allocated = FALSE;
 #endif
 
     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
@@ -2085,166 +2077,110 @@ f_resolve(typval_T *argvars, typval_T *rettv)
 #else
 # ifdef HAVE_READLINK
     {
-       size_t  plen;
-       size_t  buflen;
        char_u  *cpy;
-       size_t  cpysize;
-       char_u  *r = NULL;                      // points to current position in "remain"
-       size_t  rlen = 0;                       // length of r (excluding the NUL)
+       int     len;
+       char_u  *remain = NULL;
        char_u  *q;
        int     is_relative_to_current = FALSE;
        int     has_trailing_pathsep = FALSE;
        int     limit = 100;
-       size_t  len;
 
-       rettv->vval.v_string = NULL;
-
-       plen = STRLEN(p);
-       p = vim_strnsave(p, plen);
+       p = vim_strsave(p);
        if (p == NULL)
            goto fail;
-
-       p_was_allocated = TRUE;
        if (p[0] == '.' && (vim_ispathsep(p[1])
                                   || (p[1] == '.' && (vim_ispathsep(p[2])))))
            is_relative_to_current = TRUE;
 
-       if (plen > 1 && after_pathsep(p, p + plen))
+       len = STRLEN(p);
+       if (len > 1 && after_pathsep(p, p + len))
        {
            has_trailing_pathsep = TRUE;
-           p[--plen] = NUL;                    // the trailing slash breaks readlink()
+           p[len - 1] = NUL; // the trailing slash breaks readlink()
        }
 
        q = getnextcomp(p);
        if (*q != NUL)
        {
-           char_u  *q_prev = q - 1;
-
-           // getnextcomp() finds the first path separator.
-           // if there is a run of >1 path separators, set all
-           // but the last in the run to NUL.
-           while (*q != NUL && vim_ispathsep(*q))
-           {
-               *q_prev = NUL;
-               q_prev = q;
-               MB_PTR_ADV(q);
-           }
-           q = q_prev;
-
            // Separate the first path component in "p", and keep the
            // remainder (beginning with the path separator).
-           rlen = (size_t)(plen - (q - p));
-           r = remain = vim_strnsave(q, rlen);
-           if (remain == NULL)
-               rlen = 0;
-           *q = NUL;
-           plen -= rlen;
+           remain = vim_strsave(q - 1);
+           q[-1] = NUL;
        }
 
        buf = alloc(MAXPATHL + 1);
        if (buf == NULL)
+       {
+           vim_free(p);
+           vim_free(remain);
            goto fail;
+       }
 
        for (;;)
        {
            for (;;)
            {
-               ssize_t rv = readlink((char *)p, (char *)buf, MAXPATHL);
-               if (rv <= 0)
+               len = readlink((char *)p, (char *)buf, MAXPATHL);
+               if (len <= 0)
                    break;
+               buf[len] = NUL;
 
                if (limit-- == 0)
                {
+                   vim_free(p);
+                   vim_free(remain);
                    emsg(_(e_too_many_symbolic_links_cycle));
+                   rettv->vval.v_string = NULL;
                    goto fail;
                }
 
-               buflen = (size_t)rv;
-               buf[buflen] = NUL;
-
                // Ensure that the result will have a trailing path separator
                // if the argument has one.
-               if (remain == NULL && has_trailing_pathsep && !after_pathsep(buf, buf + buflen))
-               {
-                   STRCPY(buf + buflen, PATHSEPSTR);
-                   ++buflen;
-               }
+               if (remain == NULL && has_trailing_pathsep)
+                   add_pathsep(buf);
 
                // Separate the first path component in the link value and
                // concatenate the remainders.
                q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
                if (*q != NUL)
                {
-                   char_u  *q_prev = q - 1;
-
-                   // getnextcomp() finds the first path separator.
-                   // if there is a run of >1 path separators, set all
-                   // but the last in the run to NUL.
-                   while (*q != NUL && vim_ispathsep(*q))
-                   {
-                       *q_prev = NUL;
-                       q_prev = q;
-                       MB_PTR_ADV(q);
-                   }
-                   q = q_prev;
-
                    if (remain == NULL)
-                   {
-                       rlen = (size_t)(buflen - (q - buf));
-                       r = remain = vim_strnsave(q, rlen);
-                       if (remain == NULL)
-                           rlen = 0;
-                   }
+                       remain = vim_strsave(q - 1);
                    else
                    {
-                       len = (size_t)(buflen - (q - buf));
-                       cpysize = (size_t)(len + rlen + 1);             // +1 for NUL
-                       cpy = alloc(plen + buflen + 1);
-                       if (cpy == NULL)
-                           goto fail;
-
-                       rlen = (size_t)vim_snprintf((char *)cpy, cpysize, "%.*s%s", (int)len, q, r);
-                       vim_free(remain);
-                       r = remain = cpy;
+                       cpy = concat_str(q - 1, remain);
+                       if (cpy != NULL)
+                       {
+                           vim_free(remain);
+                           remain = cpy;
+                       }
                    }
-                   *q = NUL;
-                   buflen = (size_t)(q - buf);
+                   q[-1] = NUL;
                }
 
                q = gettail(p);
                if (q > p && *q == NUL)
                {
                    // Ignore trailing path separator.
-                   plen = (size_t)(q - p - 1);
-                   p[plen] = NUL;
+                   p[q - p - 1] = NUL;
                    q = gettail(p);
                }
                if (q > p && !mch_isFullName(buf))
                {
-                   char_u *tail;
-
                    // symlink is relative to directory of argument
-                   cpy = alloc(plen + buflen + 1);
-                   if (cpy == NULL)
-                       goto fail;
-
-                   STRCPY(cpy, p);
-                   tail = gettail(cpy);
-                   if (*tail != NUL)
-                       plen -= (size_t)(plen - (tail - cpy));  // remove portion that will be replaced
-                   STRCPY(tail, buf);
-                   vim_free(p);
-                   p = cpy;
-                   plen += buflen;
+                   cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
+                   if (cpy != NULL)
+                   {
+                       STRCPY(cpy, p);
+                       STRCPY(gettail(cpy), buf);
+                       vim_free(p);
+                       p = cpy;
+                   }
                }
                else
                {
                    vim_free(p);
-                   p = vim_strnsave(buf, buflen);
-                   if (p == NULL)
-                       goto fail;
-
-                   plen = buflen;
+                   p = vim_strsave(buf);
                }
            }
 
@@ -2252,29 +2188,20 @@ f_resolve(typval_T *argvars, typval_T *rettv)
                break;
 
            // Append the first path component of "remain" to "p".
-           q = getnextcomp(r + 1);
-           len = (size_t)(q - r);
-           cpysize = (size_t)(plen + len + 1);                 // +1 for NUL
-           cpy = alloc(cpysize);
-           if (cpy == NULL)
-               goto fail;
-
-           plen = (size_t)vim_snprintf((char *)cpy, cpysize, "%s%.*s", p, (int)len, r);
-           vim_free(p);
-           p = cpy;
-
-           // Shorten "remain".
-           if (*q != NUL)
+           q = getnextcomp(remain + 1);
+           len = q - remain - (*q != NUL);
+           cpy = vim_strnsave(p, STRLEN(p) + len);
+           if (cpy != NULL)
            {
-               r += len;
-               rlen -= len;
+               STRNCAT(cpy, remain, len);
+               vim_free(p);
+               p = cpy;
            }
+           // Shorten "remain".
+           if (*q != NUL)
+               STRMOVE(remain, q - 1);
            else
-           {
                VIM_CLEAR(remain);
-               r = NULL;
-               rlen = 0;
-           }
        }
 
        // If the result is a relative path name, make it explicitly relative to
@@ -2291,14 +2218,12 @@ f_resolve(typval_T *argvars, typval_T *rettv)
                                    || vim_ispathsep(p[2]))))))
            {
                // Prepend "./".
-               cpysize = plen + 3;                 // +2 for "./" and +1 for NUL
-               cpy = alloc(cpysize);
-               if (cpy == NULL)
-                   goto fail;
-
-               plen = (size_t)vim_snprintf((char *)cpy, cpysize, "./%s", p);
-               vim_free(p);
-               p = cpy;
+               cpy = concat_str((char_u *)"./", p);
+               if (cpy != NULL)
+               {
+                   vim_free(p);
+                   p = cpy;
+               }
            }
            else if (!is_relative_to_current)
            {
@@ -2307,17 +2232,18 @@ f_resolve(typval_T *argvars, typval_T *rettv)
                while (q[0] == '.' && vim_ispathsep(q[1]))
                    q += 2;
                if (q > p)
-               {
-                   mch_memmove(p, p + 2, (plen - 2) + 1);
-                   plen -= 2;
-               }
+                   STRMOVE(p, p + 2);
            }
        }
 
        // Ensure that the result will have no trailing path separator
        // if the argument had none.  But keep "/" or "//".
-       if (!has_trailing_pathsep && after_pathsep(p, p + plen))
-           *gettail_sep(p) = NUL;
+       if (!has_trailing_pathsep)
+       {
+           q = p + STRLEN(p);
+           if (after_pathsep(p, q))
+               *gettail_sep(p) = NUL;
+       }
 
        rettv->vval.v_string = p;
     }
@@ -2330,10 +2256,7 @@ f_resolve(typval_T *argvars, typval_T *rettv)
 
 #ifdef HAVE_READLINK
 fail:
-    if (rettv->vval.v_string == NULL && p_was_allocated)
-       vim_free(p);
     vim_free(buf);
-    vim_free(remain);
 #endif
     rettv->v_type = VAR_STRING;
 }
@@ -3041,7 +2964,6 @@ getnextcomp(char_u *fname)
 {
     while (*fname && !vim_ispathsep(*fname))
        MB_PTR_ADV(fname);
-
     if (*fname)
        ++fname;
     return fname;
@@ -3194,18 +3116,16 @@ vim_fnamencmp(char_u *x, char_u *y, size_t len)
     char_u  *
 concat_fnames(char_u *fname1, char_u *fname2, int sep)
 {
-    size_t  fname1len = STRLEN(fname1);
-    size_t  destsize = fname1len + STRLEN(fname2) + 3;
     char_u  *dest;
 
-    dest = alloc(destsize);
+    dest = alloc(STRLEN(fname1) + STRLEN(fname2) + 3);
     if (dest == NULL)
        return NULL;
 
-    vim_snprintf((char *)dest, destsize, "%s%s%s",
-           fname1,
-           (sep && !after_pathsep(fname1, fname1 + fname1len)) ? PATHSEPSTR : "",
-           fname2);
+    STRCPY(dest, fname1);
+    if (sep)
+       add_pathsep(dest);
+    STRCAT(dest, fname2);
     return dest;
 }
 
@@ -3216,14 +3136,8 @@ concat_fnames(char_u *fname1, char_u *fname2, int sep)
     void
 add_pathsep(char_u *p)
 {
-    size_t  plen;
-
-    if (p == NULL || *p == NUL)
-       return;
-
-    plen = STRLEN(p);
-    if (!after_pathsep(p, p + plen))
-       STRCPY(p + plen, PATHSEPSTR);
+    if (*p != NUL && !after_pathsep(p, p + STRLEN(p)))
+       STRCAT(p, PATHSEPSTR);
 }
 
 /*
@@ -3521,14 +3435,14 @@ expand_backtick(
 }
 #endif // VIM_BACKTICK
 
-#if defined(MSWIN) || (defined(UNIX) && !defined(VMS)) || defined(USE_UNIXFILENAME) || defined(PROTO)
+#if defined(MSWIN)
 /*
- * File name expansion code for Unix, Mac, MS-DOS, Win16 and Win32.  It's here because
+ * File name expansion code for MS-DOS, Win16 and Win32.  It's here because
  * it's shared between these systems.
  */
 
 /*
- * comparison function for qsort in unix_expandpath()
+ * comparison function for qsort in dos_expandpath()
  */
     static int
 pstrcmp(const void *a, const void *b)
@@ -3543,35 +3457,33 @@ pstrcmp(const void *a, const void *b)
  * "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!
  */
-    int
-unix_expandpath(
+    static int
+dos_expandpath(
     garray_T   *gap,
-    char_u  *path,
-    int            wildoff,
-    int            flags,      // EW_* flags
-    int            didstar)    // expanded "**" once already
+    char_u     *path,
+    int                wildoff,
+    int                flags,          // EW_* flags
+    int                didstar)        // expanded "**" once already
 {
-    char_u  *buf;
-    char_u  *path_end;
-    size_t  basepathlen;           // length of non-variable portion of the path
-    size_t  wildcardlen;           // length of wildcard segment
-    char_u  *p, *s, *e;
-    int            start_len = gap->ga_len;
-    char_u  *pat;
+    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;                // number of matches found
-    int            starstar = FALSE;
+    int                starts_with_dot;
+    int                matches;
+    int                len;
+    int                starstar = FALSE;
     static int stardepth = 0;      // depth for "**" expansion
-#ifdef MSWIN
-    HANDLE  hFind = INVALID_HANDLE_VALUE;
-    WIN32_FIND_DATAW   wfb;
-    WCHAR   *wn = NULL;                    // UCS-2 name, NULL when not used.
-#else
-    DIR            *dirp;
-#endif
-    int            ok;
+    HANDLE             hFind = INVALID_HANDLE_VALUE;
+    WIN32_FIND_DATAW    wfb;
+    WCHAR              *wn = NULL;     // UCS-2 name, NULL when not used.
+    char_u             *matchname;
+    int                        ok;
+    char_u             *p_alt;
 
     // Expanding "**" may take a long time, check for CTRL-C.
     if (stardepth > 0)
@@ -3581,16 +3493,15 @@ unix_expandpath(
            return 0;
     }
 
-    // Make room for file name. When doing encoding conversion the actual
-    // length may be quite a bit longer.
+    // Make room for file name.  When doing encoding conversion the actual
+    // length may be quite a bit longer, thus use the maximum possible length.
     buf = alloc(MAXPATHL);
     if (buf == NULL)
        return 0;
 
     /*
      * Find the first part in the path name that contains a wildcard or a ~1.
-     * Copy it into "buf", including the preceding characters.
-     * Note: for unix, when EW_ICASE is set every letter is considered to be a wildcard.
+     * Copy it into buf, including the preceding characters.
      */
     p = buf;
     s = buf;
@@ -3602,25 +3513,18 @@ unix_expandpath(
        // 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 (vim_ispathsep(*path_end))
+       else if (*path_end == '\\' || *path_end == ':' || *path_end == '/')
        {
            if (e != NULL)
                break;
            s = p + 1;
        }
        else if (path_end >= path + wildoff
-#ifdef MSWIN
-               && vim_strchr((char_u *)"*?[~", *path_end) != NULL
-#else
-               && (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL
-                    || (!p_fic && (flags & EW_ICASE)
-                         && vim_isalpha(PTR2CHAR(path_end))))
-#endif
-       )
+                        && vim_strchr((char_u *)"*?[~", *path_end) != NULL)
            e = p;
        if (has_mbyte)
        {
-           int len = (*mb_ptr2len)(path_end);
+           len = (*mb_ptr2len)(path_end);
            STRNCPY(p, path_end, len);
            p += len;
            path_end += len;
@@ -3631,38 +3535,270 @@ unix_expandpath(
     e = p;
     *e = NUL;
 
-    // Now we have one wildcard component between "s" and "e".
+    // now we have one wildcard component between s and e
     // Remove backslashes between "wildoff" and the start of the wildcard
     // component.
-    p = buf + wildoff;
-    if (p < s)
+    for (p = buf + wildoff; p < s; ++p)
+       if (rem_backslash(p))
+       {
+           STRMOVE(p, p + 1);
+           --e;
+           --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)
     {
-       size_t  psize = STRLEN(p) + 1;
+       vim_free(buf);
+       return 0;
+    }
 
-       do
+    // compile the regexp into a program
+    if (flags & (EW_NOERROR | EW_NOTWILD))
+       ++emsg_silent;
+    regmatch.rm_ic = TRUE;             // Always ignore case
+    regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
+    if (flags & (EW_NOERROR | EW_NOTWILD))
+       --emsg_silent;
+    vim_free(pat);
+
+    if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0)
+    {
+       vim_free(buf);
+       return 0;
+    }
+
+    // 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, "*.*");
+    wn = enc_to_utf16(buf, NULL);
+    if (wn != NULL)
+       hFind = FindFirstFileW(wn, &wfb);
+    ok = (hFind != INVALID_HANDLE_VALUE);
+
+    while (ok)
+    {
+       p = utf16_to_enc(wfb.cFileName, NULL);   // p is allocated here
+
+       if (p == NULL)
+           break;  // out of memory
+
+       // Do not use the alternate filename when the file name ends in '~',
+       // because it picks up backup files: short name for "foo.vim~" is
+       // "foo~1.vim", which matches "*.vim".
+       if (*wfb.cAlternateFileName == NUL || p[STRLEN(p) - 1] == '~')
+           p_alt = NULL;
+       else
+           p_alt = utf16_to_enc(wfb.cAlternateFileName, NULL);
+
+       // Ignore entries starting with a dot, unless when asked for.  Accept
+       // all entries found with "matchname".
+       if ((p[0] != '.' || starts_with_dot
+                        || ((flags & EW_DODOT)
+                            && p[1] != NUL && (p[1] != '.' || p[2] != NUL)))
+               && (matchname == NULL
+                 || (regmatch.regprog != NULL
+                     && (vim_regexec(&regmatch, p, (colnr_T)0)
+                        || (p_alt != NULL
+                               && vim_regexec(&regmatch, p_alt, (colnr_T)0))))
+                 || ((flags & EW_NOTWILD)
+                    && fnamencmp(path + (s - buf), p, e - s) == 0)))
        {
-           if (!rem_backslash(p))
-               ++p;
+           STRCPY(s, p);
+           len = (int)STRLEN(buf);
+
+           if (starstar && stardepth < 100
+                         && (wfb.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+           {
+               // 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, FALSE);
+           }
            else
            {
-               mch_memmove(p, p + 1, psize);
-               --e;
-               --s;
+               stat_T  sb;
+
+               // no more wildcards, check if there is a match
+               // remove backslashes for the remaining components only
+               if (*path_end != 0)
+                   backslash_halve(buf + len + 1);
+               // add existing file
+               if ((flags & EW_ALLLINKS) ? mch_lstat((char *)buf, &sb) >= 0
+                       : mch_getperm(buf) >= 0)
+                   addfile(gap, buf, flags);
            }
-           --psize;
-       } while (p < s);
+       }
+
+       vim_free(p_alt);
+       vim_free(p);
+       ok = FindNextFileW(hFind, &wfb);
     }
 
-    basepathlen = (size_t)(s - buf);
-    wildcardlen = (size_t)(e - s);
+    FindClose(hFind);
+    vim_free(wn);
+    vim_free(buf);
+    vim_regfree(regmatch.regprog);
+    vim_free(matchname);
+
+    matches = gap->ga_len - start_len;
+    if (matches > 0)
+       qsort(((char_u **)gap->ga_data) + start_len, (size_t)matches,
+                                                  sizeof(char_u *), pstrcmp);
+    return matches;
+}
+
+    int
+mch_expandpath(
+    garray_T   *gap,
+    char_u     *path,
+    int                flags)          // EW_* flags
+{
+    return dos_expandpath(gap, path, 0, flags, FALSE);
+}
+#endif // MSWIN
+
+#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(const void *a, const void *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(
+    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 (a bit too much to stay on the safe side)
+    size_t buflen = STRLEN(path) + MAXPATHL;
+    buf = alloc(buflen);
+    if (buf == NULL)
+       return 0;
+
+    /*
+     * Find the first part in the path name that contains a wildcard.
+     * When EW_ICASE is set every letter is considered to be 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
+                            || (!p_fic && (flags & EW_ICASE)
+                                         && vim_isalpha(PTR2CHAR(path_end)))))
+           e = p;
+       if (has_mbyte)
+       {
+           len = (*mb_ptr2len)(path_end);
+           STRNCPY(p, path_end, len);
+           p += len;
+           path_end += len;
+       }
+       else
+           *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))
+       {
+           STRMOVE(p, p + 1);
+           --e;
+           --s;
+       }
 
     // Check for "**" between "s" and "e".
     for (p = s; p < e; ++p)
        if (p[0] == '*' && p[1] == '*')
-       {
            starstar = TRUE;
-           break;
-       }
 
     // convert the file pattern to a regexp pattern
     starts_with_dot = *s == '.';
@@ -3674,14 +3810,10 @@ unix_expandpath(
     }
 
     // compile the regexp into a program
-#ifdef MSWIN
-    regmatch.rm_ic = TRUE;     // Always ignore case
-#else
     if (flags & EW_ICASE)
-       regmatch.rm_ic = TRUE;  // 'wildignorecase' set
+       regmatch.rm_ic = TRUE;          // 'wildignorecase' set
     else
-       regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set
-#endif
+       regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set
     if (flags & (EW_NOERROR | EW_NOTWILD))
        ++emsg_silent;
     regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
@@ -3697,100 +3829,51 @@ unix_expandpath(
 
     // 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 && wildcardlen == 2
-                             && *path_end == '/')
+    if (!didstar && stardepth < 100 && starstar && e - s == 2
+                                                         && *path_end == '/')
     {
        STRCPY(s, path_end + 1);
        ++stardepth;
-       (void)unix_expandpath(gap, buf, (int)basepathlen, flags, TRUE);
+       (void)unix_expandpath(gap, buf, (int)(s - buf), flags, TRUE);
        --stardepth;
     }
 
-#ifdef MSWIN
-    // open the directory for scanning
-    STRCPY(s, "*.*");
-    wn = enc_to_utf16(buf, NULL);
-    if (wn != NULL)
-       hFind = FindFirstFileW(wn, &wfb);
-    ok = (hFind != INVALID_HANDLE_VALUE);
-#else
     // open the directory for scanning
     *s = NUL;
     dirp = opendir(*buf == NUL ? "." : (char *)buf);
-    ok = (dirp != NULL);
-#endif
 
     // Find all matching entries
-    if (ok)
+    if (dirp != NULL)
     {
-       char_u  *d_name;
-#ifdef MSWIN
-       char_u  *d_name_alt;
-       // remember the pattern or file name being looked for
-       char_u  *matchname = vim_strnsave(s, basepathlen);
-#else
-       struct dirent   *dp;
-#endif
-
        while (!got_int)
        {
-#ifdef MSWIN
-           d_name = utf16_to_enc(wfb.cFileName, NULL);   // p is allocated here
-           if (d_name == NULL)
-               break;  // out of memory
-
-           // Do not use the alternate filename when the file name ends in '~',
-           // because it picks up backup files: short name for "foo.vim~" is
-           // "foo~1.vim", which matches "*.vim".
-           if (*wfb.cAlternateFileName == NUL || d_name[STRLEN(d_name) - 1] == '~')
-               d_name_alt = NULL;
-           else
-               d_name_alt = utf16_to_enc(wfb.cAlternateFileName, NULL);
-#else
            dp = readdir(dirp);
            if (dp == NULL)
                break;
-           d_name = (char_u *)dp->d_name;
-#endif
-
-           // Ignore entries starting with a dot, unless when asked for. For MSWIN accept
-           // all entries found with "matchname".
-           if (
-               (d_name[0] != '.' || starts_with_dot || (
-                   (flags & EW_DODOT) && d_name[1] != NUL &&
-                   (d_name[1] != '.' || d_name[2] != NUL)))
-            && (
-#ifdef MSWIN
-               matchname == NULL ||
-#endif
-               (regmatch.regprog != NULL
-                   && vim_regexec(&regmatch, (char_u *)d_name, (colnr_T)0))
-#ifdef MSWIN
-                || (d_name_alt != NULL
-                   && vim_regexec(&regmatch, d_name_alt, (colnr_T)0))
-#endif
+           if ((dp->d_name[0] != '.' || starts_with_dot
+                       || ((flags & EW_DODOT)
+                           && dp->d_name[1] != NUL
+                           && (dp->d_name[1] != '.' || dp->d_name[2] != NUL)))
+                && ((regmatch.regprog != NULL && vim_regexec(&regmatch,
+                                            (char_u *)dp->d_name, (colnr_T)0))
                   || ((flags & EW_NOTWILD)
-                    && fnamencmp(path + basepathlen, d_name, wildcardlen) == 0))
-           )
+                    && fnamencmp(path + (s - buf), dp->d_name, e - s) == 0)))
            {
-               int len = (int)basepathlen + vim_snprintf((char *)s, (size_t)(MAXPATHL - (basepathlen + 1)), "%s", d_name);
+               vim_strncpy(s, (char_u *)dp->d_name, buflen - (s - buf) - 1);
+               len = STRLEN(buf);
 
-               if (starstar && stardepth < 100
-#ifdef MSWIN
-                           && (wfb.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-#endif
-                   )
+               if (starstar && stardepth < 100)
                {
                    // For "**" in the pattern first go deeper in the tree to
                    // find matches.
-                   vim_snprintf((char *)buf + len, (size_t)(MAXPATHL - len),
-                                       "/**%s", path_end);
+                   vim_snprintf((char *)buf + len, buflen - len,
+                                                           "/**%s", path_end);
                    ++stardepth;
                    (void)unix_expandpath(gap, buf, len + 1, flags, TRUE);
                    --stardepth;
                }
 
-               vim_snprintf((char *)buf + len, (size_t)(MAXPATHL - len), "%s", path_end);
+               vim_snprintf((char *)buf + len, buflen - len, "%s", path_end);
                if (mch_has_exp_wildcard(path_end)) // handle more wildcards
                {
                    // need to expand another component of the path
@@ -3807,7 +3890,7 @@ unix_expandpath(
                        backslash_halve(buf + len + 1);
                    // add existing file or symbolic link
                    if ((flags & EW_ALLLINKS) ? mch_lstat((char *)buf, &sb) >= 0
-                                     : mch_getperm(buf) >= 0)
+                                                     : mch_getperm(buf) >= 0)
                    {
 #ifdef MACOS_CONVERT
                        size_t precomp_len = STRLEN(buf)+1;
@@ -3824,26 +3907,11 @@ unix_expandpath(
                    }
                }
            }
-
-#ifdef MSWIN
-           vim_free(d_name);
-           if (!FindNextFileW(hFind, &wfb))
-               break;
-#endif
        }
 
-#ifdef MSWIN
-       FindClose(hFind);
-       vim_free(matchname);
-       vim_free(d_name_alt);
-#else
        closedir(dirp);
-#endif
     }
 
-#ifdef MSWIN
-    vim_free(wn);
-#endif
     vim_free(buf);
     vim_regfree(regmatch.regprog);
 
@@ -3852,24 +3920,9 @@ unix_expandpath(
     matches = gap->ga_len - start_len;
     if (matches > 0 && !got_int)
        qsort(((char_u **)gap->ga_data) + start_len, matches,
-                          sizeof(char_u *), pstrcmp);
+                                                  sizeof(char_u *), pstrcmp);
     return matches;
 }
-
-/*
- * Expand a path into all matching files and/or directories.  Handles "*",
- * "?", "[a-z]", "**", etc where appropriate for the platform.
- * "path" has backslashes before chars that are not to be expanded.
- * Returns the number of matches found.
- */
-    int
-mch_expandpath(
-    garray_T   *gap,
-    char_u     *path,
-    int                flags)          // EW_* flags
-{
-    return unix_expandpath(gap, path, 0, flags, FALSE);
-}
 #endif
 
 /*
index ac78733d34558b5a46ed4f380a8f50379e5ea5a9..dc518fc6764d6345ec4109e40019c3074483ace0 100644 (file)
@@ -6796,6 +6796,21 @@ select_eintr:
     return result;
 }
 
+/*
+ * 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.
+ */
+    int
+mch_expandpath(
+    garray_T   *gap,
+    char_u     *path,
+    int                flags)          // EW_* flags
+{
+    return unix_expandpath(gap, path, 0, flags, FALSE);
+}
+
 /*
  * mch_expand_wildcards() - this code does wild-card pattern matching using
  * the shell
index 1665089e6c5b5057e21e63b6ded7b12ee4676a6d..46f51cb36fd7a41a5d88215e62975350b4758acd 100644 (file)
@@ -56,7 +56,6 @@ int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file, int flags
 int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files, int flags);
 int match_suffix(char_u *fname);
 int unix_expandpath(garray_T *gap, char_u *path, int wildoff, int flags, int didstar);
-int mch_expandpath(garray_T *gap, char_u *path, int flags);
 int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags);
 void addfile(garray_T *gap, char_u *f, int flags);
 void FreeWild(int count, char_u **files);
index 4feba92608bd4c6b8b325edec7dbc898c44847c1..ac695905dc87d5a3e0416aa9cb892d706e736fbc 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    924,
 /**/
     923,
 /**/