Commit | Line | Data |
---|---|---|
7766f137 GS |
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 | ||
13 | const int driveCount = 30; | |
14 | ||
15 | class VDir | |
16 | { | |
17 | public: | |
f7aeb604 | 18 | VDir(int bManageDir = 1); |
7766f137 GS |
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 | ||
63 | protected: | |
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; | |
f7aeb604 | 94 | int nDefault, bManageDirectory; |
7766f137 GS |
95 | char *dirTableA[driveCount]; |
96 | char szLocalBufferA[MAX_PATH+1]; | |
97 | WCHAR *dirTableW[driveCount]; | |
98 | WCHAR szLocalBufferW[MAX_PATH+1]; | |
99 | }; | |
100 | ||
101 | ||
f7aeb604 | 102 | VDir::VDir(int bManageDir /* = 1 */) |
7766f137 GS |
103 | { |
104 | nDefault = 0; | |
f7aeb604 | 105 | bManageDirectory = bManageDir; |
7766f137 GS |
106 | memset(dirTableA, 0, sizeof(dirTableA)); |
107 | memset(dirTableW, 0, sizeof(dirTableW)); | |
108 | } | |
109 | ||
110 | void VDir::Init(VDir* pDir, VMem *p) | |
111 | { | |
112 | int index; | |
113 | DWORD driveBits; | |
f7aeb604 | 114 | int nSave; |
7766f137 GS |
115 | char szBuffer[MAX_PATH*driveCount]; |
116 | ||
117 | pMem = p; | |
118 | if (pDir) { | |
119 | for (index = 0; index < driveCount; ++index) { | |
120 | SetDirW(pDir->GetDirW(index), index); | |
121 | } | |
122 | nDefault = pDir->GetDefault(); | |
123 | } | |
124 | else { | |
f7aeb604 GS |
125 | nSave = bManageDirectory; |
126 | bManageDirectory = 0; | |
7766f137 GS |
127 | driveBits = GetLogicalDrives(); |
128 | if (GetLogicalDriveStrings(sizeof(szBuffer), szBuffer)) { | |
129 | char* pEnv = GetEnvironmentStrings(); | |
130 | char* ptr = szBuffer; | |
131 | for (index = 0; index < driveCount; ++index) { | |
132 | if (driveBits & (1<<index)) { | |
133 | ptr += SetDirA(ptr, index) + 1; | |
134 | FromEnvA(pEnv, index); | |
135 | } | |
136 | } | |
137 | FreeEnvironmentStrings(pEnv); | |
138 | } | |
139 | SetDefaultA("."); | |
f7aeb604 | 140 | bManageDirectory = nSave; |
7766f137 GS |
141 | } |
142 | } | |
143 | ||
144 | int VDir::SetDirA(char const *pPath, int index) | |
145 | { | |
146 | char chr, *ptr; | |
147 | int length = 0; | |
148 | WCHAR wBuffer[MAX_PATH+1]; | |
149 | if (index < driveCount && pPath != NULL) { | |
150 | length = strlen(pPath); | |
151 | pMem->Free(dirTableA[index]); | |
152 | ptr = dirTableA[index] = (char*)pMem->Malloc(length+2); | |
153 | if (ptr != NULL) { | |
154 | strcpy(ptr, pPath); | |
155 | ptr += length-1; | |
156 | chr = *ptr++; | |
157 | if (chr != '\\' && chr != '/') { | |
158 | *ptr++ = '\\'; | |
159 | *ptr = '\0'; | |
160 | } | |
161 | MultiByteToWideChar(CP_ACP, 0, dirTableA[index], -1, | |
162 | wBuffer, (sizeof(wBuffer)/sizeof(WCHAR))); | |
163 | length = wcslen(wBuffer); | |
164 | pMem->Free(dirTableW[index]); | |
165 | dirTableW[index] = (WCHAR*)pMem->Malloc((length+1)*2); | |
166 | if (dirTableW[index] != NULL) { | |
167 | wcscpy(dirTableW[index], wBuffer); | |
168 | } | |
169 | } | |
170 | } | |
f7aeb604 GS |
171 | |
172 | if(bManageDirectory) | |
173 | ::SetCurrentDirectoryA(pPath); | |
174 | ||
7766f137 GS |
175 | return length; |
176 | } | |
177 | ||
178 | void VDir::FromEnvA(char *pEnv, int index) | |
179 | { /* gets the directory for index from the environment variable. */ | |
180 | while (*pEnv != '\0') { | |
181 | if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)) { | |
182 | SetDirA(&pEnv[4], index); | |
183 | break; | |
184 | } | |
185 | else | |
186 | pEnv += strlen(pEnv)+1; | |
187 | } | |
188 | } | |
189 | ||
190 | void VDir::SetDefaultA(char const *pDefault) | |
191 | { | |
192 | char szBuffer[MAX_PATH+1]; | |
193 | char *pPtr; | |
194 | ||
195 | if (GetFullPathNameA(pDefault, sizeof(szBuffer), szBuffer, &pPtr)) { | |
196 | if (*pDefault != '.' && pPtr != NULL) | |
197 | *pPtr = '\0'; | |
198 | ||
199 | SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0])); | |
200 | } | |
201 | } | |
202 | ||
203 | int VDir::SetDirW(WCHAR const *pPath, int index) | |
204 | { | |
205 | WCHAR chr, *ptr; | |
206 | char szBuffer[MAX_PATH+1]; | |
207 | int length = 0; | |
208 | if (index < driveCount && pPath != NULL) { | |
209 | length = wcslen(pPath); | |
210 | pMem->Free(dirTableW[index]); | |
211 | ptr = dirTableW[index] = (WCHAR*)pMem->Malloc((length+2)*2); | |
212 | if (ptr != NULL) { | |
213 | wcscpy(ptr, pPath); | |
214 | ptr += length-1; | |
215 | chr = *ptr++; | |
216 | if (chr != '\\' && chr != '/') { | |
217 | *ptr++ = '\\'; | |
218 | *ptr = '\0'; | |
219 | } | |
220 | WideCharToMultiByte(CP_ACP, 0, dirTableW[index], -1, szBuffer, sizeof(szBuffer), NULL, NULL); | |
221 | length = strlen(szBuffer); | |
222 | pMem->Free(dirTableA[index]); | |
223 | dirTableA[index] = (char*)pMem->Malloc(length+1); | |
224 | if (dirTableA[index] != NULL) { | |
225 | strcpy(dirTableA[index], szBuffer); | |
226 | } | |
227 | } | |
228 | } | |
f7aeb604 GS |
229 | |
230 | if(bManageDirectory) | |
231 | ::SetCurrentDirectoryW(pPath); | |
232 | ||
7766f137 GS |
233 | return length; |
234 | } | |
235 | ||
236 | void VDir::SetDefaultW(WCHAR const *pDefault) | |
237 | { | |
238 | WCHAR szBuffer[MAX_PATH+1]; | |
239 | WCHAR *pPtr; | |
240 | ||
241 | if (GetFullPathNameW(pDefault, (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr)) { | |
242 | if (*pDefault != '.' && pPtr != NULL) | |
243 | *pPtr = '\0'; | |
244 | ||
245 | SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0])); | |
246 | } | |
247 | } | |
248 | ||
249 | inline BOOL IsPathSep(char ch) | |
250 | { | |
251 | return (ch == '\\' || ch == '/'); | |
252 | } | |
253 | ||
254 | inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest) | |
255 | { | |
256 | char *pPtr; | |
257 | ||
258 | /* | |
259 | * On WinNT GetFullPathName does not fail, (or at least always | |
260 | * succeeds when the drive is valid) WinNT does set *Dest to Nullch | |
261 | * On Win98 GetFullPathName will set last error if it fails, but | |
262 | * does not touch *Dest | |
263 | */ | |
264 | *Dest = '\0'; | |
265 | GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr); | |
266 | } | |
267 | ||
268 | char *VDir::MapPathA(const char *pInName) | |
269 | { /* | |
270 | * possiblities -- relative path or absolute path with or without drive letter | |
271 | * OR UNC name | |
272 | */ | |
273 | char szBuffer[(MAX_PATH+1)*2]; | |
274 | char szlBuf[MAX_PATH+1]; | |
275 | ||
276 | if (strlen(pInName) > MAX_PATH) { | |
277 | strncpy(szlBuf, pInName, MAX_PATH); | |
278 | if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) { | |
279 | /* absolute path - reduce length by 2 for drive specifier */ | |
280 | szlBuf[MAX_PATH-2] = '\0'; | |
281 | } | |
282 | else | |
283 | szlBuf[MAX_PATH] = '\0'; | |
284 | pInName = szlBuf; | |
285 | } | |
286 | /* strlen(pInName) is now <= MAX_PATH */ | |
287 | ||
288 | if (pInName[1] == ':') { | |
289 | /* has drive letter */ | |
290 | if (IsPathSep(pInName[2])) { | |
291 | /* absolute with drive letter */ | |
292 | strcpy(szLocalBufferA, pInName); | |
293 | } | |
294 | else { | |
295 | /* relative path with drive letter */ | |
296 | strcpy(szBuffer, GetDirA(DriveIndex(*pInName))); | |
297 | strcat(szBuffer, &pInName[2]); | |
298 | if(strlen(szBuffer) > MAX_PATH) | |
299 | szBuffer[MAX_PATH] = '\0'; | |
300 | ||
301 | DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); | |
302 | } | |
303 | } | |
304 | else { | |
305 | /* no drive letter */ | |
306 | if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) { | |
307 | /* UNC name */ | |
308 | strcpy(szLocalBufferA, pInName); | |
309 | } | |
310 | else { | |
311 | strcpy(szBuffer, GetDefaultDirA()); | |
312 | if (IsPathSep(pInName[0])) { | |
313 | /* absolute path */ | |
314 | szLocalBufferA[0] = szBuffer[0]; | |
315 | szLocalBufferA[1] = szBuffer[1]; | |
316 | strcpy(&szLocalBufferA[2], pInName); | |
317 | } | |
318 | else { | |
319 | /* relative path */ | |
320 | strcat(szBuffer, pInName); | |
321 | if (strlen(szBuffer) > MAX_PATH) | |
322 | szBuffer[MAX_PATH] = '\0'; | |
323 | ||
324 | DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); | |
325 | } | |
326 | } | |
327 | } | |
328 | ||
329 | return szLocalBufferA; | |
330 | } | |
331 | ||
332 | int VDir::SetCurrentDirectoryA(char *lpBuffer) | |
333 | { | |
334 | HANDLE hHandle; | |
335 | WIN32_FIND_DATA win32FD; | |
336 | char szBuffer[MAX_PATH+1], *pPtr; | |
fd9459bc | 337 | int length, nRet = -1; |
7766f137 GS |
338 | |
339 | GetFullPathNameA(MapPathA(lpBuffer), sizeof(szBuffer), szBuffer, &pPtr); | |
fd9459bc GS |
340 | /* if the last char is a '\\' or a '/' then add |
341 | * an '*' before calling FindFirstFile | |
342 | */ | |
343 | length = strlen(szBuffer); | |
344 | if(length > 0 && IsPathSep(szBuffer[length-1])) { | |
345 | szBuffer[length] = '*'; | |
346 | szBuffer[length+1] = '\0'; | |
347 | } | |
7766f137 | 348 | |
fd9459bc | 349 | hHandle = FindFirstFileA(szBuffer, &win32FD); |
7766f137 GS |
350 | if (hHandle != INVALID_HANDLE_VALUE) { |
351 | FindClose(hHandle); | |
7766f137 | 352 | |
fd9459bc GS |
353 | /* if an '*' was added remove it */ |
354 | if(szBuffer[length] == '*') | |
355 | szBuffer[length] = '\0'; | |
7766f137 | 356 | |
fd9459bc | 357 | SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0])); |
7766f137 GS |
358 | nRet = 0; |
359 | } | |
360 | return nRet; | |
361 | } | |
362 | ||
363 | DWORD VDir::CalculateEnvironmentSpace(void) | |
364 | { /* the current directory environment strings are stored as '=d=d:\path' */ | |
365 | int index; | |
366 | DWORD dwSize = 0; | |
367 | for (index = 0; index < driveCount; ++index) { | |
368 | if (dirTableA[index] != NULL) { | |
369 | dwSize += strlen(dirTableA[index]) + 4; /* add 1 for trailing NULL and 3 for '=d=' */ | |
370 | } | |
371 | } | |
372 | return dwSize; | |
373 | } | |
374 | ||
375 | LPSTR VDir::BuildEnvironmentSpace(LPSTR lpStr) | |
376 | { /* store the current directory environment strings as '=d=d:\path' */ | |
377 | int index; | |
378 | LPSTR lpDirStr; | |
379 | for (index = 0; index < driveCount; ++index) { | |
380 | lpDirStr = dirTableA[index]; | |
381 | if (lpDirStr != NULL) { | |
382 | lpStr[0] = '='; | |
383 | lpStr[1] = lpDirStr[0]; | |
384 | lpStr[2] = '='; | |
385 | strcpy(&lpStr[3], lpDirStr); | |
386 | lpStr += strlen(lpDirStr) + 4; /* add 1 for trailing NULL and 3 for '=d=' */ | |
387 | } | |
388 | } | |
389 | return lpStr; | |
390 | } | |
391 | ||
392 | inline BOOL IsPathSep(WCHAR ch) | |
393 | { | |
394 | return (ch == '\\' || ch == '/'); | |
395 | } | |
396 | ||
397 | inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest) | |
398 | { | |
399 | WCHAR *pPtr; | |
400 | ||
401 | /* | |
402 | * On WinNT GetFullPathName does not fail, (or at least always | |
403 | * succeeds when the drive is valid) WinNT does set *Dest to Nullch | |
404 | * On Win98 GetFullPathName will set last error if it fails, but | |
405 | * does not touch *Dest | |
406 | */ | |
407 | *Dest = '\0'; | |
408 | GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr); | |
409 | } | |
410 | ||
411 | WCHAR* VDir::MapPathW(const WCHAR *pInName) | |
412 | { /* | |
413 | * possiblities -- relative path or absolute path with or without drive letter | |
414 | * OR UNC name | |
415 | */ | |
416 | WCHAR szBuffer[(MAX_PATH+1)*2]; | |
417 | WCHAR szlBuf[MAX_PATH+1]; | |
418 | ||
419 | if (wcslen(pInName) > MAX_PATH) { | |
420 | wcsncpy(szlBuf, pInName, MAX_PATH); | |
421 | if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) { | |
422 | /* absolute path - reduce length by 2 for drive specifier */ | |
423 | szlBuf[MAX_PATH-2] = '\0'; | |
424 | } | |
425 | else | |
426 | szlBuf[MAX_PATH] = '\0'; | |
427 | pInName = szlBuf; | |
428 | } | |
429 | /* strlen(pInName) is now <= MAX_PATH */ | |
430 | ||
431 | if (pInName[1] == ':') { | |
432 | /* has drive letter */ | |
433 | if (IsPathSep(pInName[2])) { | |
434 | /* absolute with drive letter */ | |
435 | wcscpy(szLocalBufferW, pInName); | |
436 | } | |
437 | else { | |
438 | /* relative path with drive letter */ | |
439 | wcscpy(szBuffer, GetDirW(DriveIndex((char)*pInName))); | |
440 | wcscat(szBuffer, &pInName[2]); | |
441 | if(wcslen(szBuffer) > MAX_PATH) | |
442 | szBuffer[MAX_PATH] = '\0'; | |
443 | ||
444 | DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); | |
445 | } | |
446 | } | |
447 | else { | |
448 | /* no drive letter */ | |
449 | if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) { | |
450 | /* UNC name */ | |
451 | wcscpy(szLocalBufferW, pInName); | |
452 | } | |
453 | else { | |
454 | wcscpy(szBuffer, GetDefaultDirW()); | |
455 | if (IsPathSep(pInName[0])) { | |
456 | /* absolute path */ | |
457 | szLocalBufferW[0] = szBuffer[0]; | |
458 | szLocalBufferW[1] = szBuffer[1]; | |
459 | wcscpy(&szLocalBufferW[2], pInName); | |
460 | } | |
461 | else { | |
462 | /* relative path */ | |
463 | wcscat(szBuffer, pInName); | |
464 | if (wcslen(szBuffer) > MAX_PATH) | |
465 | szBuffer[MAX_PATH] = '\0'; | |
466 | ||
467 | DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); | |
468 | } | |
469 | } | |
470 | } | |
471 | return szLocalBufferW; | |
472 | } | |
473 | ||
fd9459bc GS |
474 | int VDir::SetCurrentDirectoryW(WCHAR *lpBuffer) |
475 | { | |
476 | HANDLE hHandle; | |
477 | WIN32_FIND_DATAW win32FD; | |
478 | WCHAR szBuffer[MAX_PATH+1], *pPtr; | |
479 | int length, nRet = -1; | |
480 | ||
481 | GetFullPathNameW(MapPathW(lpBuffer), (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr); | |
482 | /* if the last char is a '\\' or a '/' then add | |
483 | * an '*' before calling FindFirstFile | |
484 | */ | |
485 | length = wcslen(szBuffer); | |
486 | if(length > 0 && IsPathSep(szBuffer[length-1])) { | |
487 | szBuffer[length] = '*'; | |
488 | szBuffer[length+1] = '\0'; | |
489 | } | |
490 | ||
491 | hHandle = FindFirstFileW(szBuffer, &win32FD); | |
492 | if (hHandle != INVALID_HANDLE_VALUE) { | |
493 | FindClose(hHandle); | |
494 | ||
495 | /* if an '*' was added remove it */ | |
496 | if(szBuffer[length] == '*') | |
497 | szBuffer[length] = '\0'; | |
498 | ||
499 | SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0])); | |
500 | nRet = 0; | |
501 | } | |
502 | return nRet; | |
503 | } | |
7766f137 GS |
504 | |
505 | #endif /* ___VDir_H___ */ |