Update cwd() to return the "short" pathname if the long one doesn't fit the codepage
Jan Dubois [Mon, 18 Dec 2006 21:37:25 +0000 (13:37 -0800)]
Message-ID: <3rteo219or8hqr511e4vg1fnsgvgemb4sh@4ax.com>

p4raw-id: //depot/perl@29598

win32/perlhost.h
win32/vdir.h

index fe026dd..d6e1e0f 100644 (file)
 #include "vmem.h"
 #include "vdir.h"
 
+#ifndef WC_NO_BEST_FIT_CHARS
+#  define WC_NO_BEST_FIT_CHARS 0x00000400
+#endif
+
 START_EXTERN_C
 extern char *          g_win32_get_privlib(const char *pl);
 extern char *          g_win32_get_sitelib(const char *pl);
@@ -2236,20 +2240,52 @@ CPerlHost::FreeLocalEnvironmentStrings(LPSTR lpStr)
     Safefree(lpStr);
 }
 
+static char *
+get_valid_filename(pTHX_ WCHAR *widename)
+{
+    char *name;
+    BOOL use_default = FALSE;
+    size_t widelen = wcslen(widename)+1;
+    int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
+                                  NULL, 0, NULL, NULL);
+    Newx(name, len, char);
+    WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
+                        name, len, NULL, &use_default);
+    if (use_default) {
+        WCHAR *shortname;
+        DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
+        Newx(shortname, shortlen, WCHAR);
+        shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
+        len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
+                                  NULL, 0, NULL, NULL);
+        Renew(name, len, char);
+        WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
+                            name, len, NULL, NULL);
+        Safefree(shortname);
+    }
+    return name;
+}
+
 char*
 CPerlHost::GetChildDir(void)
 {
     dTHX;
-    int length;
     char* ptr;
-    Newx(ptr, MAX_PATH+1, char);
-    if(ptr) {
-       m_pvDir->GetCurrentDirectoryA(MAX_PATH+1, ptr);
-       length = strlen(ptr);
-       if (length > 3) {
-           if ((ptr[length-1] == '\\') || (ptr[length-1] == '/'))
-               ptr[length-1] = 0;
-       }
+    size_t length;
+
+    if (IsWin95()) {
+        Newx(ptr, MAX_PATH+1, char);
+        m_pvDir->GetCurrentDirectoryA(MAX_PATH+1, ptr);
+    }
+    else {
+        WCHAR path[MAX_PATH+1];
+        m_pvDir->GetCurrentDirectoryW(MAX_PATH+1, path);
+        ptr = get_valid_filename(aTHX_ path);
+    }
+    length = strlen(ptr);
+    if (length > 3) {
+        if ((ptr[length-1] == '\\') || (ptr[length-1] == '/'))
+            ptr[length-1] = 0;
     }
     return ptr;
 }
index 10119ea..fb80e38 100644 (file)
@@ -34,47 +34,48 @@ public:
     inline char* GetCurrentDirectoryA(int dwBufSize, char *lpBuffer)
     {
        char* ptr = dirTableA[nDefault];
-       while (dwBufSize--)
+       while (--dwBufSize)
        {
            if ((*lpBuffer++ = *ptr++) == '\0')
                break;
        }
-       return lpBuffer;
+        *lpBuffer = '\0';
+       return /* unused */ NULL;
     };
     inline WCHAR* GetCurrentDirectoryW(int dwBufSize, WCHAR *lpBuffer)
     {
        WCHAR* ptr = dirTableW[nDefault];
-       while (dwBufSize--)
+       while (--dwBufSize)
        {
            if ((*lpBuffer++ = *ptr++) == '\0')
                break;
        }
-       return lpBuffer;
+        *lpBuffer = '\0';
+       return /* unused */ NULL;
     };
 
-
     DWORD CalculateEnvironmentSpace(void);
     LPSTR BuildEnvironmentSpace(LPSTR lpStr);
 
 protected:
     int SetDirA(char const *pPath, int index);
+    int SetDirW(WCHAR const *pPath, int index);
     void FromEnvA(char *pEnv, int index);
+    void FromEnvW(WCHAR *pEnv, int index);
+
     inline const char *GetDefaultDirA(void)
     {
        return dirTableA[nDefault];
     };
-
     inline void SetDefaultDirA(char const *pPath, int index)
     {
        SetDirA(pPath, index);
        nDefault = index;
     };
-    int SetDirW(WCHAR const *pPath, int index);
     inline const WCHAR *GetDefaultDirW(void)
     {
        return dirTableW[nDefault];
     };
-
     inline void SetDefaultDirW(WCHAR const *pPath, int index)
     {
        SetDirW(pPath, index);
@@ -134,9 +135,6 @@ VDir::VDir(int bManageDir /* = 1 */)
 void VDir::Init(VDir* pDir, VMem *p)
 {
     int index;
-    DWORD driveBits;
-    int nSave;
-    char szBuffer[MAX_PATH*driveCount];
 
     pMem = p;
     if (pDir) {
@@ -146,23 +144,47 @@ void VDir::Init(VDir* pDir, VMem *p)
        nDefault = pDir->GetDefault();
     }
     else {
-       nSave = bManageDirectory;
+       int bSave = bManageDirectory;
+       DWORD driveBits = GetLogicalDrives();
+        OSVERSIONINFO osver;
+
+        memset(&osver, 0, sizeof(osver));
+        osver.dwOSVersionInfoSize = sizeof(osver);
+        GetVersionEx(&osver);
+
        bManageDirectory = 0;
-       driveBits = GetLogicalDrives();
-       if (GetLogicalDriveStrings(sizeof(szBuffer), szBuffer)) {
-           char* pEnv = (char*)GetEnvironmentStrings();
-           char* ptr = szBuffer;
-           for (index = 0; index < driveCount; ++index) {
-               if (driveBits & (1<<index)) {
-                   ptr += SetDirA(ptr, index) + 1;
-                   FromEnvA(pEnv, index);
-               }
-           }
-           FreeEnvironmentStrings(pEnv);
-       }
-       SetDefaultA(".");
-       bManageDirectory = nSave;
-    }
+        if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+            char szBuffer[MAX_PATH*driveCount];
+            if (GetLogicalDriveStringsA(sizeof(szBuffer), szBuffer)) {
+                char* pEnv = (char*)GetEnvironmentStringsA();
+                char* ptr = szBuffer;
+                for (index = 0; index < driveCount; ++index) {
+                    if (driveBits & (1<<index)) {
+                        ptr += SetDirA(ptr, index) + 1;
+                        FromEnvA(pEnv, index);
+                    }
+                }
+                FreeEnvironmentStringsA(pEnv);
+            }
+            SetDefaultA(".");
+        }
+        else { /* Windows NT or later */
+            WCHAR szBuffer[MAX_PATH*driveCount];
+            if (GetLogicalDriveStringsW(sizeof(szBuffer), szBuffer)) {
+                WCHAR* pEnv = GetEnvironmentStringsW();
+                WCHAR* ptr = szBuffer;
+                for (index = 0; index < driveCount; ++index) {
+                    if (driveBits & (1<<index)) {
+                        ptr += SetDirW(ptr, index) + 1;
+                        FromEnvW(pEnv, index);
+                    }
+                }
+                FreeEnvironmentStringsW(pEnv);
+            }
+            SetDefaultW(L".");
+        }
+       bManageDirectory = bSave;
+  }
 }
 
 int VDir::SetDirA(char const *pPath, int index)
@@ -211,6 +233,18 @@ void VDir::FromEnvA(char *pEnv, int index)
     }
 }
 
+void VDir::FromEnvW(WCHAR *pEnv, int index)
+{   /* gets the directory for index from the environment variable. */
+    while (*pEnv != '\0') {
+       if ((pEnv[0] == '=') && (DriveIndex((char)pEnv[1]) == index)) {
+           SetDirW(&pEnv[4], index);
+           break;
+       }
+       else
+           pEnv += wcslen(pEnv)+1;
+    }
+}
+
 void VDir::SetDefaultA(char const *pDefault)
 {
     char szBuffer[MAX_PATH+1];