better variant of change#4644 (from Andy Dougherty)
[p5sagit/p5-mst-13.2.git] / win32 / vdir.h
CommitLineData
7766f137 1/* vdir.h
2 *
3 * (c) 1999 Microsoft Corporation. All rights reserved.
4 * Portions (c) 1999 ActiveState Tool Corp, http://www.ActiveState.com/
5 *
6 * You may distribute under the terms of either the GNU General Public
7 * License or the Artistic License, as specified in the README file.
8 */
9
10#ifndef ___VDir_H___
11#define ___VDir_H___
12
13const int driveCount = 30;
14
15class VDir
16{
17public:
18 VDir();
19 ~VDir() {};
20
21 void Init(VDir* pDir, VMem *pMem);
22 void SetDefaultA(char const *pDefault);
23 void SetDefaultW(WCHAR const *pDefault);
24 char* MapPathA(const char *pInName);
25 WCHAR* MapPathW(const WCHAR *pInName);
26 int SetCurrentDirectoryA(char *lpBuffer);
27 int SetCurrentDirectoryW(WCHAR *lpBuffer);
28 inline const char *GetDirA(int index)
29 {
30 return dirTableA[index];
31 };
32 inline const WCHAR *GetDirW(int index)
33 {
34 return dirTableW[index];
35 };
36 inline int GetDefault(void) { return nDefault; };
37
38 inline char* GetCurrentDirectoryA(int dwBufSize, char *lpBuffer)
39 {
40 char* ptr = dirTableA[nDefault];
41 while (dwBufSize--)
42 {
43 if ((*lpBuffer++ = *ptr++) == '\0')
44 break;
45 }
46 return lpBuffer;
47 };
48 inline WCHAR* GetCurrentDirectoryW(int dwBufSize, WCHAR *lpBuffer)
49 {
50 WCHAR* ptr = dirTableW[nDefault];
51 while (dwBufSize--)
52 {
53 if ((*lpBuffer++ = *ptr++) == '\0')
54 break;
55 }
56 return lpBuffer;
57 };
58
59
60 DWORD CalculateEnvironmentSpace(void);
61 LPSTR BuildEnvironmentSpace(LPSTR lpStr);
62
63protected:
64 int SetDirA(char const *pPath, int index);
65 void FromEnvA(char *pEnv, int index);
66 inline const char *GetDefaultDirA(void)
67 {
68 return dirTableA[nDefault];
69 };
70
71 inline void SetDefaultDirA(char const *pPath, int index)
72 {
73 SetDirA(pPath, index);
74 nDefault = index;
75 };
76 int SetDirW(WCHAR const *pPath, int index);
77 inline const WCHAR *GetDefaultDirW(void)
78 {
79 return dirTableW[nDefault];
80 };
81
82 inline void SetDefaultDirW(WCHAR const *pPath, int index)
83 {
84 SetDirW(pPath, index);
85 nDefault = index;
86 };
87
88 inline int DriveIndex(char chr)
89 {
90 return (chr | 0x20)-'a';
91 };
92
93 VMem *pMem;
94 int nDefault;
95 char *dirTableA[driveCount];
96 char szLocalBufferA[MAX_PATH+1];
97 WCHAR *dirTableW[driveCount];
98 WCHAR szLocalBufferW[MAX_PATH+1];
99};
100
101
102VDir::VDir()
103{
104 nDefault = 0;
105 memset(dirTableA, 0, sizeof(dirTableA));
106 memset(dirTableW, 0, sizeof(dirTableW));
107}
108
109void VDir::Init(VDir* pDir, VMem *p)
110{
111 int index;
112 DWORD driveBits;
113 char szBuffer[MAX_PATH*driveCount];
114
115 pMem = p;
116 if (pDir) {
117 for (index = 0; index < driveCount; ++index) {
118 SetDirW(pDir->GetDirW(index), index);
119 }
120 nDefault = pDir->GetDefault();
121 }
122 else {
123 driveBits = GetLogicalDrives();
124 if (GetLogicalDriveStrings(sizeof(szBuffer), szBuffer)) {
125 char* pEnv = GetEnvironmentStrings();
126 char* ptr = szBuffer;
127 for (index = 0; index < driveCount; ++index) {
128 if (driveBits & (1<<index)) {
129 ptr += SetDirA(ptr, index) + 1;
130 FromEnvA(pEnv, index);
131 }
132 }
133 FreeEnvironmentStrings(pEnv);
134 }
135 SetDefaultA(".");
136 }
137}
138
139int VDir::SetDirA(char const *pPath, int index)
140{
141 char chr, *ptr;
142 int length = 0;
143 WCHAR wBuffer[MAX_PATH+1];
144 if (index < driveCount && pPath != NULL) {
145 length = strlen(pPath);
146 pMem->Free(dirTableA[index]);
147 ptr = dirTableA[index] = (char*)pMem->Malloc(length+2);
148 if (ptr != NULL) {
149 strcpy(ptr, pPath);
150 ptr += length-1;
151 chr = *ptr++;
152 if (chr != '\\' && chr != '/') {
153 *ptr++ = '\\';
154 *ptr = '\0';
155 }
156 MultiByteToWideChar(CP_ACP, 0, dirTableA[index], -1,
157 wBuffer, (sizeof(wBuffer)/sizeof(WCHAR)));
158 length = wcslen(wBuffer);
159 pMem->Free(dirTableW[index]);
160 dirTableW[index] = (WCHAR*)pMem->Malloc((length+1)*2);
161 if (dirTableW[index] != NULL) {
162 wcscpy(dirTableW[index], wBuffer);
163 }
164 }
165 }
166 return length;
167}
168
169void VDir::FromEnvA(char *pEnv, int index)
170{ /* gets the directory for index from the environment variable. */
171 while (*pEnv != '\0') {
172 if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)) {
173 SetDirA(&pEnv[4], index);
174 break;
175 }
176 else
177 pEnv += strlen(pEnv)+1;
178 }
179}
180
181void VDir::SetDefaultA(char const *pDefault)
182{
183 char szBuffer[MAX_PATH+1];
184 char *pPtr;
185
186 if (GetFullPathNameA(pDefault, sizeof(szBuffer), szBuffer, &pPtr)) {
187 if (*pDefault != '.' && pPtr != NULL)
188 *pPtr = '\0';
189
190 SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
191 }
192}
193
194int VDir::SetDirW(WCHAR const *pPath, int index)
195{
196 WCHAR chr, *ptr;
197 char szBuffer[MAX_PATH+1];
198 int length = 0;
199 if (index < driveCount && pPath != NULL) {
200 length = wcslen(pPath);
201 pMem->Free(dirTableW[index]);
202 ptr = dirTableW[index] = (WCHAR*)pMem->Malloc((length+2)*2);
203 if (ptr != NULL) {
204 wcscpy(ptr, pPath);
205 ptr += length-1;
206 chr = *ptr++;
207 if (chr != '\\' && chr != '/') {
208 *ptr++ = '\\';
209 *ptr = '\0';
210 }
211 WideCharToMultiByte(CP_ACP, 0, dirTableW[index], -1, szBuffer, sizeof(szBuffer), NULL, NULL);
212 length = strlen(szBuffer);
213 pMem->Free(dirTableA[index]);
214 dirTableA[index] = (char*)pMem->Malloc(length+1);
215 if (dirTableA[index] != NULL) {
216 strcpy(dirTableA[index], szBuffer);
217 }
218 }
219 }
220 return length;
221}
222
223void VDir::SetDefaultW(WCHAR const *pDefault)
224{
225 WCHAR szBuffer[MAX_PATH+1];
226 WCHAR *pPtr;
227
228 if (GetFullPathNameW(pDefault, (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr)) {
229 if (*pDefault != '.' && pPtr != NULL)
230 *pPtr = '\0';
231
232 SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0]));
233 }
234}
235
236inline BOOL IsPathSep(char ch)
237{
238 return (ch == '\\' || ch == '/');
239}
240
241inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest)
242{
243 char *pPtr;
244
245 /*
246 * On WinNT GetFullPathName does not fail, (or at least always
247 * succeeds when the drive is valid) WinNT does set *Dest to Nullch
248 * On Win98 GetFullPathName will set last error if it fails, but
249 * does not touch *Dest
250 */
251 *Dest = '\0';
252 GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr);
253}
254
255char *VDir::MapPathA(const char *pInName)
256{ /*
257 * possiblities -- relative path or absolute path with or without drive letter
258 * OR UNC name
259 */
260 char szBuffer[(MAX_PATH+1)*2];
261 char szlBuf[MAX_PATH+1];
262
263 if (strlen(pInName) > MAX_PATH) {
264 strncpy(szlBuf, pInName, MAX_PATH);
265 if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {
266 /* absolute path - reduce length by 2 for drive specifier */
267 szlBuf[MAX_PATH-2] = '\0';
268 }
269 else
270 szlBuf[MAX_PATH] = '\0';
271 pInName = szlBuf;
272 }
273 /* strlen(pInName) is now <= MAX_PATH */
274
275 if (pInName[1] == ':') {
276 /* has drive letter */
277 if (IsPathSep(pInName[2])) {
278 /* absolute with drive letter */
279 strcpy(szLocalBufferA, pInName);
280 }
281 else {
282 /* relative path with drive letter */
283 strcpy(szBuffer, GetDirA(DriveIndex(*pInName)));
284 strcat(szBuffer, &pInName[2]);
285 if(strlen(szBuffer) > MAX_PATH)
286 szBuffer[MAX_PATH] = '\0';
287
288 DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
289 }
290 }
291 else {
292 /* no drive letter */
293 if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
294 /* UNC name */
295 strcpy(szLocalBufferA, pInName);
296 }
297 else {
298 strcpy(szBuffer, GetDefaultDirA());
299 if (IsPathSep(pInName[0])) {
300 /* absolute path */
301 szLocalBufferA[0] = szBuffer[0];
302 szLocalBufferA[1] = szBuffer[1];
303 strcpy(&szLocalBufferA[2], pInName);
304 }
305 else {
306 /* relative path */
307 strcat(szBuffer, pInName);
308 if (strlen(szBuffer) > MAX_PATH)
309 szBuffer[MAX_PATH] = '\0';
310
311 DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
312 }
313 }
314 }
315
316 return szLocalBufferA;
317}
318
319int VDir::SetCurrentDirectoryA(char *lpBuffer)
320{
321 HANDLE hHandle;
322 WIN32_FIND_DATA win32FD;
323 char szBuffer[MAX_PATH+1], *pPtr;
fd9459bc 324 int length, nRet = -1;
7766f137 325
326 GetFullPathNameA(MapPathA(lpBuffer), sizeof(szBuffer), szBuffer, &pPtr);
fd9459bc 327 /* if the last char is a '\\' or a '/' then add
328 * an '*' before calling FindFirstFile
329 */
330 length = strlen(szBuffer);
331 if(length > 0 && IsPathSep(szBuffer[length-1])) {
332 szBuffer[length] = '*';
333 szBuffer[length+1] = '\0';
334 }
7766f137 335
fd9459bc 336 hHandle = FindFirstFileA(szBuffer, &win32FD);
7766f137 337 if (hHandle != INVALID_HANDLE_VALUE) {
338 FindClose(hHandle);
7766f137 339
fd9459bc 340 /* if an '*' was added remove it */
341 if(szBuffer[length] == '*')
342 szBuffer[length] = '\0';
7766f137 343
fd9459bc 344 SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
7766f137 345 nRet = 0;
346 }
347 return nRet;
348}
349
350DWORD VDir::CalculateEnvironmentSpace(void)
351{ /* the current directory environment strings are stored as '=d=d:\path' */
352 int index;
353 DWORD dwSize = 0;
354 for (index = 0; index < driveCount; ++index) {
355 if (dirTableA[index] != NULL) {
356 dwSize += strlen(dirTableA[index]) + 4; /* add 1 for trailing NULL and 3 for '=d=' */
357 }
358 }
359 return dwSize;
360}
361
362LPSTR VDir::BuildEnvironmentSpace(LPSTR lpStr)
363{ /* store the current directory environment strings as '=d=d:\path' */
364 int index;
365 LPSTR lpDirStr;
366 for (index = 0; index < driveCount; ++index) {
367 lpDirStr = dirTableA[index];
368 if (lpDirStr != NULL) {
369 lpStr[0] = '=';
370 lpStr[1] = lpDirStr[0];
371 lpStr[2] = '=';
372 strcpy(&lpStr[3], lpDirStr);
373 lpStr += strlen(lpDirStr) + 4; /* add 1 for trailing NULL and 3 for '=d=' */
374 }
375 }
376 return lpStr;
377}
378
379inline BOOL IsPathSep(WCHAR ch)
380{
381 return (ch == '\\' || ch == '/');
382}
383
384inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest)
385{
386 WCHAR *pPtr;
387
388 /*
389 * On WinNT GetFullPathName does not fail, (or at least always
390 * succeeds when the drive is valid) WinNT does set *Dest to Nullch
391 * On Win98 GetFullPathName will set last error if it fails, but
392 * does not touch *Dest
393 */
394 *Dest = '\0';
395 GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr);
396}
397
398WCHAR* VDir::MapPathW(const WCHAR *pInName)
399{ /*
400 * possiblities -- relative path or absolute path with or without drive letter
401 * OR UNC name
402 */
403 WCHAR szBuffer[(MAX_PATH+1)*2];
404 WCHAR szlBuf[MAX_PATH+1];
405
406 if (wcslen(pInName) > MAX_PATH) {
407 wcsncpy(szlBuf, pInName, MAX_PATH);
408 if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {
409 /* absolute path - reduce length by 2 for drive specifier */
410 szlBuf[MAX_PATH-2] = '\0';
411 }
412 else
413 szlBuf[MAX_PATH] = '\0';
414 pInName = szlBuf;
415 }
416 /* strlen(pInName) is now <= MAX_PATH */
417
418 if (pInName[1] == ':') {
419 /* has drive letter */
420 if (IsPathSep(pInName[2])) {
421 /* absolute with drive letter */
422 wcscpy(szLocalBufferW, pInName);
423 }
424 else {
425 /* relative path with drive letter */
426 wcscpy(szBuffer, GetDirW(DriveIndex((char)*pInName)));
427 wcscat(szBuffer, &pInName[2]);
428 if(wcslen(szBuffer) > MAX_PATH)
429 szBuffer[MAX_PATH] = '\0';
430
431 DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
432 }
433 }
434 else {
435 /* no drive letter */
436 if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
437 /* UNC name */
438 wcscpy(szLocalBufferW, pInName);
439 }
440 else {
441 wcscpy(szBuffer, GetDefaultDirW());
442 if (IsPathSep(pInName[0])) {
443 /* absolute path */
444 szLocalBufferW[0] = szBuffer[0];
445 szLocalBufferW[1] = szBuffer[1];
446 wcscpy(&szLocalBufferW[2], pInName);
447 }
448 else {
449 /* relative path */
450 wcscat(szBuffer, pInName);
451 if (wcslen(szBuffer) > MAX_PATH)
452 szBuffer[MAX_PATH] = '\0';
453
454 DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
455 }
456 }
457 }
458 return szLocalBufferW;
459}
460
fd9459bc 461int VDir::SetCurrentDirectoryW(WCHAR *lpBuffer)
462{
463 HANDLE hHandle;
464 WIN32_FIND_DATAW win32FD;
465 WCHAR szBuffer[MAX_PATH+1], *pPtr;
466 int length, nRet = -1;
467
468 GetFullPathNameW(MapPathW(lpBuffer), (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr);
469 /* if the last char is a '\\' or a '/' then add
470 * an '*' before calling FindFirstFile
471 */
472 length = wcslen(szBuffer);
473 if(length > 0 && IsPathSep(szBuffer[length-1])) {
474 szBuffer[length] = '*';
475 szBuffer[length+1] = '\0';
476 }
477
478 hHandle = FindFirstFileW(szBuffer, &win32FD);
479 if (hHandle != INVALID_HANDLE_VALUE) {
480 FindClose(hHandle);
481
482 /* if an '*' was added remove it */
483 if(szBuffer[length] == '*')
484 szBuffer[length] = '\0';
485
486 SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0]));
487 nRet = 0;
488 }
489 return nRet;
490}
7766f137 491
492#endif /* ___VDir_H___ */