X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=win32%2Fvdir.h;h=db7ec8417fef425597e9c36e18dc88b288beeb09;hb=cb39f75f02caa9f23c14dfcac8a46fb1bd154b4f;hp=50822a7aa4936784015f385a514f42169d4327ca;hpb=f7aeb604c5566ea382e11775c0d364a41af8fbb9;p=p5sagit%2Fp5-mst-13.2.git diff --git a/win32/vdir.h b/win32/vdir.h index 50822a7..db7ec84 100644 --- a/win32/vdir.h +++ b/win32/vdir.h @@ -10,7 +10,11 @@ #ifndef ___VDir_H___ #define ___VDir_H___ -const int driveCount = 30; +/* + * Allow one slot for each possible drive letter + * and one additional slot for a UNC name + */ +const int driveCount = ('Z'-'A')+1+1; class VDir { @@ -25,68 +29,89 @@ public: WCHAR* MapPathW(const WCHAR *pInName); int SetCurrentDirectoryA(char *lpBuffer); int SetCurrentDirectoryW(WCHAR *lpBuffer); - inline const char *GetDirA(int index) - { - return dirTableA[index]; - }; - inline const WCHAR *GetDirW(int index) - { - return dirTableW[index]; - }; inline int GetDefault(void) { return nDefault; }; 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); nDefault = index; }; + inline const char *GetDirA(int index) + { + char *ptr = dirTableA[index]; + if (!ptr) { + /* simulate the existance of this drive */ + ptr = szLocalBufferA; + ptr[0] = 'A' + index; + ptr[1] = ':'; + ptr[2] = '\\'; + ptr[3] = 0; + } + return ptr; + }; + inline const WCHAR *GetDirW(int index) + { + WCHAR *ptr = dirTableW[index]; + if (!ptr) { + /* simulate the existance of this drive */ + ptr = szLocalBufferW; + ptr[0] = 'A' + index; + ptr[1] = ':'; + ptr[2] = '\\'; + ptr[3] = 0; + } + return ptr; + }; inline int DriveIndex(char chr) { + if (chr == '\\' || chr == '/') + return ('Z'-'A')+1; return (chr | 0x20)-'a'; }; @@ -110,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) { @@ -122,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 = GetEnvironmentStrings(); - char* ptr = szBuffer; - for (index = 0; index < driveCount; ++index) { - if (driveBits & (1<Free(dirTableA[index]); dirTableA[index] = (char*)pMem->Malloc(length+1); if (dirTableA[index] != NULL) { - strcpy(dirTableA[index], szBuffer); + strcpy(dirTableA[index], ansi); } + win32_free(ansi); } } @@ -257,7 +316,7 @@ inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest) /* * On WinNT GetFullPathName does not fail, (or at least always - * succeeds when the drive is valid) WinNT does set *Dest to Nullch + * succeeds when the drive is valid) WinNT does set *Dest to NULL * On Win98 GetFullPathName will set last error if it fails, but * does not touch *Dest */ @@ -265,6 +324,82 @@ inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest) GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr); } +inline bool IsSpecialFileName(const char* pName) +{ + /* specical file names are devices that the system can open + * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$ + * (x is a single digit, and names are case-insensitive) + */ + char ch = (pName[0] & ~0x20); + switch (ch) + { + case 'A': /* AUX */ + if (((pName[1] & ~0x20) == 'U') + && ((pName[2] & ~0x20) == 'X') + && !pName[3]) + return true; + break; + case 'C': /* CLOCK$, COMx, CON, CONIN$ CONOUT$ */ + ch = (pName[1] & ~0x20); + switch (ch) + { + case 'L': /* CLOCK$ */ + if (((pName[2] & ~0x20) == 'O') + && ((pName[3] & ~0x20) == 'C') + && ((pName[4] & ~0x20) == 'K') + && (pName[5] == '$') + && !pName[6]) + return true; + break; + case 'O': /* COMx, CON, CONIN$ CONOUT$ */ + if ((pName[2] & ~0x20) == 'M') { + if ((pName[3] >= '1') && (pName[3] <= '9') + && !pName[4]) + return true; + } + else if ((pName[2] & ~0x20) == 'N') { + if (!pName[3]) + return true; + else if ((pName[3] & ~0x20) == 'I') { + if (((pName[4] & ~0x20) == 'N') + && (pName[5] == '$') + && !pName[6]) + return true; + } + else if ((pName[3] & ~0x20) == 'O') { + if (((pName[4] & ~0x20) == 'U') + && ((pName[5] & ~0x20) == 'T') + && (pName[6] == '$') + && !pName[7]) + return true; + } + } + break; + } + break; + case 'L': /* LPTx */ + if (((pName[1] & ~0x20) == 'U') + && ((pName[2] & ~0x20) == 'X') + && (pName[3] >= '1') && (pName[3] <= '9') + && !pName[4]) + return true; + break; + case 'N': /* NUL */ + if (((pName[1] & ~0x20) == 'U') + && ((pName[2] & ~0x20) == 'L') + && !pName[3]) + return true; + break; + case 'P': /* PRN */ + if (((pName[1] & ~0x20) == 'R') + && ((pName[2] & ~0x20) == 'N') + && !pName[3]) + return true; + break; + } + return false; +} + char *VDir::MapPathA(const char *pInName) { /* * possiblities -- relative path or absolute path with or without drive letter @@ -272,8 +407,12 @@ char *VDir::MapPathA(const char *pInName) */ char szBuffer[(MAX_PATH+1)*2]; char szlBuf[MAX_PATH+1]; + int length = strlen(pInName); + + if (!length) + return (char*)pInName; - if (strlen(pInName) > MAX_PATH) { + if (length > MAX_PATH) { strncpy(szlBuf, pInName, MAX_PATH); if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) { /* absolute path - reduce length by 2 for drive specifier */ @@ -289,7 +428,7 @@ char *VDir::MapPathA(const char *pInName) /* has drive letter */ if (IsPathSep(pInName[2])) { /* absolute with drive letter */ - strcpy(szLocalBufferA, pInName); + DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA); } else { /* relative path with drive letter */ @@ -305,23 +444,27 @@ char *VDir::MapPathA(const char *pInName) /* no drive letter */ if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) { /* UNC name */ - strcpy(szLocalBufferA, pInName); + DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA); } else { strcpy(szBuffer, GetDefaultDirA()); if (IsPathSep(pInName[0])) { /* absolute path */ - szLocalBufferA[0] = szBuffer[0]; - szLocalBufferA[1] = szBuffer[1]; - strcpy(&szLocalBufferA[2], pInName); + strcpy(&szBuffer[2], pInName); + DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); } else { /* relative path */ - strcat(szBuffer, pInName); - if (strlen(szBuffer) > MAX_PATH) - szBuffer[MAX_PATH] = '\0'; + if (IsSpecialFileName(pInName)) { + return (char*)pInName; + } + else { + strcat(szBuffer, pInName); + if (strlen(szBuffer) > MAX_PATH) + szBuffer[MAX_PATH] = '\0'; - DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); + DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); + } } } } @@ -331,59 +474,60 @@ char *VDir::MapPathA(const char *pInName) int VDir::SetCurrentDirectoryA(char *lpBuffer) { - HANDLE hHandle; - WIN32_FIND_DATA win32FD; - char szBuffer[MAX_PATH+1], *pPtr; + char *pPtr; int length, nRet = -1; - GetFullPathNameA(MapPathA(lpBuffer), sizeof(szBuffer), szBuffer, &pPtr); - /* if the last char is a '\\' or a '/' then add - * an '*' before calling FindFirstFile - */ - length = strlen(szBuffer); - if(length > 0 && IsPathSep(szBuffer[length-1])) { - szBuffer[length] = '*'; - szBuffer[length+1] = '\0'; + pPtr = MapPathA(lpBuffer); + length = strlen(pPtr); + if(length > 3 && IsPathSep(pPtr[length-1])) { + /* don't remove the trailing slash from 'x:\' */ + pPtr[length-1] = '\0'; } - hHandle = FindFirstFileA(szBuffer, &win32FD); - if (hHandle != INVALID_HANDLE_VALUE) { - FindClose(hHandle); - - /* if an '*' was added remove it */ - if(szBuffer[length] == '*') - szBuffer[length] = '\0'; - + DWORD r = GetFileAttributesA(pPtr); + if ((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY)) + { + char szBuffer[(MAX_PATH+1)*2]; + DoGetFullPathNameA(pPtr, sizeof(szBuffer), szBuffer); SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0])); nRet = 0; } + return nRet; } DWORD VDir::CalculateEnvironmentSpace(void) -{ /* the current directory environment strings are stored as '=d=d:\path' */ +{ /* the current directory environment strings are stored as '=D:=d:\path' */ int index; DWORD dwSize = 0; for (index = 0; index < driveCount; ++index) { if (dirTableA[index] != NULL) { - dwSize += strlen(dirTableA[index]) + 4; /* add 1 for trailing NULL and 3 for '=d=' */ + dwSize += strlen(dirTableA[index]) + 5; /* add 1 for trailing NULL and 4 for '=D:=' */ } } return dwSize; } LPSTR VDir::BuildEnvironmentSpace(LPSTR lpStr) -{ /* store the current directory environment strings as '=d=d:\path' */ - int index; +{ /* store the current directory environment strings as '=D:=d:\path' */ + int index, length; LPSTR lpDirStr; for (index = 0; index < driveCount; ++index) { lpDirStr = dirTableA[index]; if (lpDirStr != NULL) { lpStr[0] = '='; lpStr[1] = lpDirStr[0]; - lpStr[2] = '='; - strcpy(&lpStr[3], lpDirStr); - lpStr += strlen(lpDirStr) + 4; /* add 1 for trailing NULL and 3 for '=d=' */ + lpStr[2] = '\0'; + CharUpper(&lpStr[1]); + lpStr[2] = ':'; + lpStr[3] = '='; + strcpy(&lpStr[4], lpDirStr); + length = strlen(lpDirStr); + lpStr += length + 5; /* add 1 for trailing NULL and 4 for '=D:=' */ + if (length > 3 && IsPathSep(lpStr[-2])) { + lpStr[-2] = '\0'; /* remove the trailing path separator */ + --lpStr; + } } } return lpStr; @@ -400,7 +544,7 @@ inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest) /* * On WinNT GetFullPathName does not fail, (or at least always - * succeeds when the drive is valid) WinNT does set *Dest to Nullch + * succeeds when the drive is valid) WinNT does set *Dest to NULL * On Win98 GetFullPathName will set last error if it fails, but * does not touch *Dest */ @@ -408,6 +552,82 @@ inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest) GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr); } +inline bool IsSpecialFileName(const WCHAR* pName) +{ + /* specical file names are devices that the system can open + * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$ + * (x is a single digit, and names are case-insensitive) + */ + WCHAR ch = (pName[0] & ~0x20); + switch (ch) + { + case 'A': /* AUX */ + if (((pName[1] & ~0x20) == 'U') + && ((pName[2] & ~0x20) == 'X') + && !pName[3]) + return true; + break; + case 'C': /* CLOCK$, COMx, CON, CONIN$ CONOUT$ */ + ch = (pName[1] & ~0x20); + switch (ch) + { + case 'L': /* CLOCK$ */ + if (((pName[2] & ~0x20) == 'O') + && ((pName[3] & ~0x20) == 'C') + && ((pName[4] & ~0x20) == 'K') + && (pName[5] == '$') + && !pName[6]) + return true; + break; + case 'O': /* COMx, CON, CONIN$ CONOUT$ */ + if ((pName[2] & ~0x20) == 'M') { + if ((pName[3] >= '1') && (pName[3] <= '9') + && !pName[4]) + return true; + } + else if ((pName[2] & ~0x20) == 'N') { + if (!pName[3]) + return true; + else if ((pName[3] & ~0x20) == 'I') { + if (((pName[4] & ~0x20) == 'N') + && (pName[5] == '$') + && !pName[6]) + return true; + } + else if ((pName[3] & ~0x20) == 'O') { + if (((pName[4] & ~0x20) == 'U') + && ((pName[5] & ~0x20) == 'T') + && (pName[6] == '$') + && !pName[7]) + return true; + } + } + break; + } + break; + case 'L': /* LPTx */ + if (((pName[1] & ~0x20) == 'U') + && ((pName[2] & ~0x20) == 'X') + && (pName[3] >= '1') && (pName[3] <= '9') + && !pName[4]) + return true; + break; + case 'N': /* NUL */ + if (((pName[1] & ~0x20) == 'U') + && ((pName[2] & ~0x20) == 'L') + && !pName[3]) + return true; + break; + case 'P': /* PRN */ + if (((pName[1] & ~0x20) == 'R') + && ((pName[2] & ~0x20) == 'N') + && !pName[3]) + return true; + break; + } + return false; +} + WCHAR* VDir::MapPathW(const WCHAR *pInName) { /* * possiblities -- relative path or absolute path with or without drive letter @@ -415,8 +635,12 @@ WCHAR* VDir::MapPathW(const WCHAR *pInName) */ WCHAR szBuffer[(MAX_PATH+1)*2]; WCHAR szlBuf[MAX_PATH+1]; + int length = wcslen(pInName); - if (wcslen(pInName) > MAX_PATH) { + if (!length) + return (WCHAR*)pInName; + + if (length > MAX_PATH) { wcsncpy(szlBuf, pInName, MAX_PATH); if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) { /* absolute path - reduce length by 2 for drive specifier */ @@ -432,7 +656,7 @@ WCHAR* VDir::MapPathW(const WCHAR *pInName) /* has drive letter */ if (IsPathSep(pInName[2])) { /* absolute with drive letter */ - wcscpy(szLocalBufferW, pInName); + DoGetFullPathNameW((WCHAR*)pInName, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); } else { /* relative path with drive letter */ @@ -448,23 +672,27 @@ WCHAR* VDir::MapPathW(const WCHAR *pInName) /* no drive letter */ if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) { /* UNC name */ - wcscpy(szLocalBufferW, pInName); + DoGetFullPathNameW((WCHAR*)pInName, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); } else { wcscpy(szBuffer, GetDefaultDirW()); if (IsPathSep(pInName[0])) { /* absolute path */ - szLocalBufferW[0] = szBuffer[0]; - szLocalBufferW[1] = szBuffer[1]; - wcscpy(&szLocalBufferW[2], pInName); + wcscpy(&szBuffer[2], pInName); + DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); } else { /* relative path */ - wcscat(szBuffer, pInName); - if (wcslen(szBuffer) > MAX_PATH) - szBuffer[MAX_PATH] = '\0'; + if (IsSpecialFileName(pInName)) { + return (WCHAR*)pInName; + } + else { + wcscat(szBuffer, pInName); + if (wcslen(szBuffer) > MAX_PATH) + szBuffer[MAX_PATH] = '\0'; - DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); + DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); + } } } } @@ -473,32 +701,25 @@ WCHAR* VDir::MapPathW(const WCHAR *pInName) int VDir::SetCurrentDirectoryW(WCHAR *lpBuffer) { - HANDLE hHandle; - WIN32_FIND_DATAW win32FD; - WCHAR szBuffer[MAX_PATH+1], *pPtr; + WCHAR *pPtr; int length, nRet = -1; - GetFullPathNameW(MapPathW(lpBuffer), (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr); - /* if the last char is a '\\' or a '/' then add - * an '*' before calling FindFirstFile - */ - length = wcslen(szBuffer); - if(length > 0 && IsPathSep(szBuffer[length-1])) { - szBuffer[length] = '*'; - szBuffer[length+1] = '\0'; + pPtr = MapPathW(lpBuffer); + length = wcslen(pPtr); + if(length > 3 && IsPathSep(pPtr[length-1])) { + /* don't remove the trailing slash from 'x:\' */ + pPtr[length-1] = '\0'; } - hHandle = FindFirstFileW(szBuffer, &win32FD); - if (hHandle != INVALID_HANDLE_VALUE) { - FindClose(hHandle); - - /* if an '*' was added remove it */ - if(szBuffer[length] == '*') - szBuffer[length] = '\0'; - - SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0])); + DWORD r = GetFileAttributesW(pPtr); + if ((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY)) + { + WCHAR wBuffer[(MAX_PATH+1)*2]; + DoGetFullPathNameW(pPtr, (sizeof(wBuffer)/sizeof(WCHAR)), wBuffer); + SetDefaultDirW(wBuffer, DriveIndex((char)wBuffer[0])); nRet = 0; } + return nRet; }