]> granicus.if.org Git - vim/commitdiff
updated for version 7.4.016 v7.4.016
authorBram Moolenaar <Bram@vim.org>
Fri, 30 Aug 2013 15:29:16 +0000 (17:29 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 30 Aug 2013 15:29:16 +0000 (17:29 +0200)
Problem:    MS-Windows: File name completion doesn't work properly with
            Chinese characters. (Yue Wu)
Solution:   Add fname_casew(). (Ken Takata)

src/os_win32.c
src/version.c

index 33a72565aac712784ebf443dc1f8b09cd4f2dd89..f36dfb3db903160a2cd2644a6a0ce8bda82d9688 100644 (file)
@@ -2500,9 +2500,125 @@ mch_check_win(
 }
 
 
+#ifdef FEAT_MBYTE
+/*
+ * fname_casew(): Wide version of fname_case().  Set the case of the file name,
+ * if it already exists.  When "len" is > 0, also expand short to long
+ * filenames.
+ * Return FAIL if wide functions are not available, OK otherwise.
+ * NOTE: much of this is identical to fname_case(), keep in sync!
+ */
+    static int
+fname_casew(
+    WCHAR      *name,
+    int                len)
+{
+    WCHAR              szTrueName[_MAX_PATH + 2];
+    WCHAR              szTrueNameTemp[_MAX_PATH + 2];
+    WCHAR              *ptrue, *ptruePrev;
+    WCHAR              *porig, *porigPrev;
+    int                        flen;
+    WIN32_FIND_DATAW   fb;
+    HANDLE             hFind;
+    int                        c;
+    int                        slen;
+
+    flen = (int)wcslen(name);
+    if (flen > _MAX_PATH)
+       return OK;
+
+    /* slash_adjust(name) not needed, already adjusted by fname_case(). */
+
+    /* Build the new name in szTrueName[] one component at a time. */
+    porig = name;
+    ptrue = szTrueName;
+
+    if (iswalpha(porig[0]) && porig[1] == L':')
+    {
+       /* copy leading drive letter */
+       *ptrue++ = *porig++;
+       *ptrue++ = *porig++;
+       *ptrue = NUL;       /* in case nothing follows */
+    }
+
+    while (*porig != NUL)
+    {
+       /* copy \ characters */
+       while (*porig == psepc)
+           *ptrue++ = *porig++;
+
+       ptruePrev = ptrue;
+       porigPrev = porig;
+       while (*porig != NUL && *porig != psepc)
+       {
+           *ptrue++ = *porig++;
+       }
+       *ptrue = NUL;
+
+       /* To avoid a slow failure append "\*" when searching a directory,
+        * server or network share. */
+       wcscpy(szTrueNameTemp, szTrueName);
+       slen = (int)wcslen(szTrueNameTemp);
+       if (*porig == psepc && slen + 2 < _MAX_PATH)
+           wcscpy(szTrueNameTemp + slen, L"\\*");
+
+       /* Skip "", "." and "..". */
+       if (ptrue > ptruePrev
+               && (ptruePrev[0] != L'.'
+                   || (ptruePrev[1] != NUL
+                       && (ptruePrev[1] != L'.' || ptruePrev[2] != NUL)))
+               && (hFind = FindFirstFileW(szTrueNameTemp, &fb))
+                                                     != INVALID_HANDLE_VALUE)
+       {
+           c = *porig;
+           *porig = NUL;
+
+           /* Only use the match when it's the same name (ignoring case) or
+            * expansion is allowed and there is a match with the short name
+            * and there is enough room. */
+           if (_wcsicoll(porigPrev, fb.cFileName) == 0
+                   || (len > 0
+                       && (_wcsicoll(porigPrev, fb.cAlternateFileName) == 0
+                           && (int)(ptruePrev - szTrueName)
+                                          + (int)wcslen(fb.cFileName) < len)))
+           {
+               wcscpy(ptruePrev, fb.cFileName);
+
+               /* Look for exact match and prefer it if found.  Must be a
+                * long name, otherwise there would be only one match. */
+               while (FindNextFileW(hFind, &fb))
+               {
+                   if (*fb.cAlternateFileName != NUL
+                           && (wcscoll(porigPrev, fb.cFileName) == 0
+                               || (len > 0
+                                   && (_wcsicoll(porigPrev,
+                                                  fb.cAlternateFileName) == 0
+                                   && (int)(ptruePrev - szTrueName)
+                                        + (int)wcslen(fb.cFileName) < len))))
+                   {
+                       wcscpy(ptruePrev, fb.cFileName);
+                       break;
+                   }
+               }
+           }
+           FindClose(hFind);
+           *porig = c;
+           ptrue = ptruePrev + wcslen(ptruePrev);
+       }
+       else if (hFind == INVALID_HANDLE_VALUE
+               && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+           return FAIL;
+    }
+
+    wcscpy(name, szTrueName);
+    return OK;
+}
+#endif
+
 /*
  * fname_case(): Set the case of the file name, if it already exists.
  * When "len" is > 0, also expand short to long filenames.
+ * NOTE: much of this is identical to fname_casew(), keep in sync!
  */
     void
 fname_case(
@@ -2520,11 +2636,44 @@ fname_case(
     int                        slen;
 
     flen = (int)STRLEN(name);
-    if (flen == 0 || flen > _MAX_PATH)
+    if (flen == 0)
        return;
 
     slash_adjust(name);
 
+#ifdef FEAT_MBYTE
+    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+    {
+       WCHAR   *p = enc_to_utf16(name, NULL);
+
+       if (p != NULL)
+       {
+           char_u      *q;
+           WCHAR       buf[_MAX_PATH + 2];
+
+           wcscpy(buf, p);
+           vim_free(p);
+
+           if (fname_casew(buf, (len > 0) ? _MAX_PATH : 0) == OK)
+           {
+               q = utf16_to_enc(buf, NULL);
+               if (q != NULL)
+               {
+                   vim_strncpy(name, q, (len > 0) ? len - 1 : flen);
+                   vim_free(q);
+                   return;
+               }
+           }
+       }
+       /* Retry with non-wide function (for Windows 98). */
+    }
+#endif
+
+    /* If 'enc' is utf-8, flen can be larger than _MAX_PATH.
+     * So we should check this after calling wide function. */
+    if (flen > _MAX_PATH)
+       return;
+
     /* Build the new name in szTrueName[] one component at a time. */
     porig = name;
     ptrue = szTrueName;
index fb145933106d30577f5a267b1849d997c39f3415..ce71dff777b8a811ab05b3bcdfd807728c6b6536 100644 (file)
@@ -738,6 +738,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    16,
 /**/
     15,
 /**/