@@ -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
25082624fname_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 ;
0 commit comments