Commit | Line | Data |
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 | |
13 | const int driveCount = 30; |
14 | |
15 | class VDir |
16 | { |
17 | public: |
f7aeb604 |
18 | VDir(int bManageDir = 1); |
7766f137 |
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 |
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 |
103 | { |
104 | nDefault = 0; |
f7aeb604 |
105 | bManageDirectory = bManageDir; |
7766f137 |
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 |
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 |
125 | nSave = bManageDirectory; |
126 | bManageDirectory = 0; |
7766f137 |
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 |
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 |
171 | |
172 | if(bManageDirectory) |
173 | ::SetCurrentDirectoryA(pPath); |
174 | |
7766f137 |
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 |
229 | |
230 | if(bManageDirectory) |
231 | ::SetCurrentDirectoryW(pPath); |
232 | |
7766f137 |
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 |
338 | |
339 | GetFullPathNameA(MapPathA(lpBuffer), sizeof(szBuffer), szBuffer, &pPtr); |
fd9459bc |
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 |
350 | if (hHandle != INVALID_HANDLE_VALUE) { |
351 | FindClose(hHandle); |
7766f137 |
352 | |
fd9459bc |
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 |
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 |
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 |
504 | |
505 | #endif /* ___VDir_H___ */ |