Skip to content

Commit 4ff15ba

Browse files
committed
updated for version 7.4.016
Problem: MS-Windows: File name completion doesn't work properly with Chinese characters. (Yue Wu) Solution: Add fname_casew(). (Ken Takata)
1 parent abfb216 commit 4ff15ba

File tree

2 files changed

+152
-1
lines changed

2 files changed

+152
-1
lines changed

src/os_win32.c

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2500,9 +2500,125 @@ mch_check_win(
25002500
}
25012501

25022502

2503+
#ifdef FEAT_MBYTE
2504+
/*
2505+
* fname_casew(): Wide version of fname_case(). Set the case of the file name,
2506+
* if it already exists. When "len" is > 0, also expand short to long
2507+
* filenames.
2508+
* Return FAIL if wide functions are not available, OK otherwise.
2509+
* NOTE: much of this is identical to fname_case(), keep in sync!
2510+
*/
2511+
static int
2512+
fname_casew(
2513+
WCHAR *name,
2514+
int len)
2515+
{
2516+
WCHAR szTrueName[_MAX_PATH + 2];
2517+
WCHAR szTrueNameTemp[_MAX_PATH + 2];
2518+
WCHAR *ptrue, *ptruePrev;
2519+
WCHAR *porig, *porigPrev;
2520+
int flen;
2521+
WIN32_FIND_DATAW fb;
2522+
HANDLE hFind;
2523+
int c;
2524+
int slen;
2525+
2526+
flen = (int)wcslen(name);
2527+
if (flen > _MAX_PATH)
2528+
return OK;
2529+
2530+
/* slash_adjust(name) not needed, already adjusted by fname_case(). */
2531+
2532+
/* Build the new name in szTrueName[] one component at a time. */
2533+
porig = name;
2534+
ptrue = szTrueName;
2535+
2536+
if (iswalpha(porig[0]) && porig[1] == L':')
2537+
{
2538+
/* copy leading drive letter */
2539+
*ptrue++ = *porig++;
2540+
*ptrue++ = *porig++;
2541+
*ptrue = NUL; /* in case nothing follows */
2542+
}
2543+
2544+
while (*porig != NUL)
2545+
{
2546+
/* copy \ characters */
2547+
while (*porig == psepc)
2548+
*ptrue++ = *porig++;
2549+
2550+
ptruePrev = ptrue;
2551+
porigPrev = porig;
2552+
while (*porig != NUL && *porig != psepc)
2553+
{
2554+
*ptrue++ = *porig++;
2555+
}
2556+
*ptrue = NUL;
2557+
2558+
/* To avoid a slow failure append "\*" when searching a directory,
2559+
* server or network share. */
2560+
wcscpy(szTrueNameTemp, szTrueName);
2561+
slen = (int)wcslen(szTrueNameTemp);
2562+
if (*porig == psepc && slen + 2 < _MAX_PATH)
2563+
wcscpy(szTrueNameTemp + slen, L"\\*");
2564+
2565+
/* Skip "", "." and "..". */
2566+
if (ptrue > ptruePrev
2567+
&& (ptruePrev[0] != L'.'
2568+
|| (ptruePrev[1] != NUL
2569+
&& (ptruePrev[1] != L'.' || ptruePrev[2] != NUL)))
2570+
&& (hFind = FindFirstFileW(szTrueNameTemp, &fb))
2571+
!= INVALID_HANDLE_VALUE)
2572+
{
2573+
c = *porig;
2574+
*porig = NUL;
2575+
2576+
/* Only use the match when it's the same name (ignoring case) or
2577+
* expansion is allowed and there is a match with the short name
2578+
* and there is enough room. */
2579+
if (_wcsicoll(porigPrev, fb.cFileName) == 0
2580+
|| (len > 0
2581+
&& (_wcsicoll(porigPrev, fb.cAlternateFileName) == 0
2582+
&& (int)(ptruePrev - szTrueName)
2583+
+ (int)wcslen(fb.cFileName) < len)))
2584+
{
2585+
wcscpy(ptruePrev, fb.cFileName);
2586+
2587+
/* Look for exact match and prefer it if found. Must be a
2588+
* long name, otherwise there would be only one match. */
2589+
while (FindNextFileW(hFind, &fb))
2590+
{
2591+
if (*fb.cAlternateFileName != NUL
2592+
&& (wcscoll(porigPrev, fb.cFileName) == 0
2593+
|| (len > 0
2594+
&& (_wcsicoll(porigPrev,
2595+
fb.cAlternateFileName) == 0
2596+
&& (int)(ptruePrev - szTrueName)
2597+
+ (int)wcslen(fb.cFileName) < len))))
2598+
{
2599+
wcscpy(ptruePrev, fb.cFileName);
2600+
break;
2601+
}
2602+
}
2603+
}
2604+
FindClose(hFind);
2605+
*porig = c;
2606+
ptrue = ptruePrev + wcslen(ptruePrev);
2607+
}
2608+
else if (hFind == INVALID_HANDLE_VALUE
2609+
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2610+
return FAIL;
2611+
}
2612+
2613+
wcscpy(name, szTrueName);
2614+
return OK;
2615+
}
2616+
#endif
2617+
25032618
/*
25042619
* fname_case(): Set the case of the file name, if it already exists.
25052620
* When "len" is > 0, also expand short to long filenames.
2621+
* NOTE: much of this is identical to fname_casew(), keep in sync!
25062622
*/
25072623
void
25082624
fname_case(
@@ -2520,11 +2636,44 @@ fname_case(
25202636
int slen;
25212637

25222638
flen = (int)STRLEN(name);
2523-
if (flen == 0 || flen > _MAX_PATH)
2639+
if (flen == 0)
25242640
return;
25252641

25262642
slash_adjust(name);
25272643

2644+
#ifdef FEAT_MBYTE
2645+
if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2646+
{
2647+
WCHAR *p = enc_to_utf16(name, NULL);
2648+
2649+
if (p != NULL)
2650+
{
2651+
char_u *q;
2652+
WCHAR buf[_MAX_PATH + 2];
2653+
2654+
wcscpy(buf, p);
2655+
vim_free(p);
2656+
2657+
if (fname_casew(buf, (len > 0) ? _MAX_PATH : 0) == OK)
2658+
{
2659+
q = utf16_to_enc(buf, NULL);
2660+
if (q != NULL)
2661+
{
2662+
vim_strncpy(name, q, (len > 0) ? len - 1 : flen);
2663+
vim_free(q);
2664+
return;
2665+
}
2666+
}
2667+
}
2668+
/* Retry with non-wide function (for Windows 98). */
2669+
}
2670+
#endif
2671+
2672+
/* If 'enc' is utf-8, flen can be larger than _MAX_PATH.
2673+
* So we should check this after calling wide function. */
2674+
if (flen > _MAX_PATH)
2675+
return;
2676+
25282677
/* Build the new name in szTrueName[] one component at a time. */
25292678
porig = name;
25302679
ptrue = szTrueName;

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,8 @@ static char *(features[]) =
738738

739739
static int included_patches[] =
740740
{ /* Add new patch number below this line */
741+
/**/
742+
16,
741743
/**/
742744
15,
743745
/**/

0 commit comments

Comments
 (0)