source: trunk/third/perl/win32/vdir.h @ 14545

Revision 14545, 16.6 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14544, which included commits to RCS files with non-trunk default branches.
Line 
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(int bManageDir = 1);
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 int GetDefault(void) { return nDefault; };
29
30    inline char* GetCurrentDirectoryA(int dwBufSize, char *lpBuffer)
31    {
32        char* ptr = dirTableA[nDefault];
33        while (dwBufSize--)
34        {
35            if ((*lpBuffer++ = *ptr++) == '\0')
36                break;
37        }
38        return lpBuffer;
39    };
40    inline WCHAR* GetCurrentDirectoryW(int dwBufSize, WCHAR *lpBuffer)
41    {
42        WCHAR* ptr = dirTableW[nDefault];
43        while (dwBufSize--)
44        {
45            if ((*lpBuffer++ = *ptr++) == '\0')
46                break;
47        }
48        return lpBuffer;
49    };
50
51
52    DWORD CalculateEnvironmentSpace(void);
53    LPSTR BuildEnvironmentSpace(LPSTR lpStr);
54
55protected:
56    int SetDirA(char const *pPath, int index);
57    void FromEnvA(char *pEnv, int index);
58    inline const char *GetDefaultDirA(void)
59    {
60        return dirTableA[nDefault];
61    };
62
63    inline void SetDefaultDirA(char const *pPath, int index)
64    {
65        SetDirA(pPath, index);
66        nDefault = index;
67    };
68    int SetDirW(WCHAR const *pPath, int index);
69    inline const WCHAR *GetDefaultDirW(void)
70    {
71        return dirTableW[nDefault];
72    };
73
74    inline void SetDefaultDirW(WCHAR const *pPath, int index)
75    {
76        SetDirW(pPath, index);
77        nDefault = index;
78    };
79    inline const char *GetDirA(int index)
80    {
81        char *ptr = dirTableA[index];
82        if (!ptr) {
83            /* simulate the existance of this drive */
84            ptr = szLocalBufferA;
85            ptr[0] = 'A' + index;
86            ptr[1] = ':';
87            ptr[2] = '\\';
88            ptr[3] = 0;
89        }
90        return ptr;
91    };
92    inline const WCHAR *GetDirW(int index)
93    {
94        WCHAR *ptr = dirTableW[index];
95        if (!ptr) {
96            /* simulate the existance of this drive */
97            ptr = szLocalBufferW;
98            ptr[0] = 'A' + index;
99            ptr[1] = ':';
100            ptr[2] = '\\';
101            ptr[3] = 0;
102        }
103        return ptr;
104    };
105
106    inline int DriveIndex(char chr)
107    {
108        return (chr | 0x20)-'a';
109    };
110
111    VMem *pMem;
112    int nDefault, bManageDirectory;
113    char *dirTableA[driveCount];
114    char szLocalBufferA[MAX_PATH+1];
115    WCHAR *dirTableW[driveCount];
116    WCHAR szLocalBufferW[MAX_PATH+1];
117};
118
119
120VDir::VDir(int bManageDir /* = 1 */)
121{
122    nDefault = 0;
123    bManageDirectory = bManageDir;
124    memset(dirTableA, 0, sizeof(dirTableA));
125    memset(dirTableW, 0, sizeof(dirTableW));
126}
127
128void VDir::Init(VDir* pDir, VMem *p)
129{
130    int index;
131    DWORD driveBits;
132    int nSave;
133    char szBuffer[MAX_PATH*driveCount];
134
135    pMem = p;
136    if (pDir) {
137        for (index = 0; index < driveCount; ++index) {
138            SetDirW(pDir->GetDirW(index), index);
139        }
140        nDefault = pDir->GetDefault();
141    }
142    else {
143        nSave = bManageDirectory;
144        bManageDirectory = 0;
145        driveBits = GetLogicalDrives();
146        if (GetLogicalDriveStrings(sizeof(szBuffer), szBuffer)) {
147            char* pEnv = GetEnvironmentStrings();
148            char* ptr = szBuffer;
149            for (index = 0; index < driveCount; ++index) {
150                if (driveBits & (1<<index)) {
151                    ptr += SetDirA(ptr, index) + 1;
152                    FromEnvA(pEnv, index);
153                }
154            }
155            FreeEnvironmentStrings(pEnv);
156        }
157        SetDefaultA(".");
158        bManageDirectory = nSave;
159    }
160}
161
162int VDir::SetDirA(char const *pPath, int index)
163{
164    char chr, *ptr;
165    int length = 0;
166    WCHAR wBuffer[MAX_PATH+1];
167    if (index < driveCount && pPath != NULL) {
168        length = strlen(pPath);
169        pMem->Free(dirTableA[index]);
170        ptr = dirTableA[index] = (char*)pMem->Malloc(length+2);
171        if (ptr != NULL) {
172            strcpy(ptr, pPath);
173            ptr += length-1;
174            chr = *ptr++;
175            if (chr != '\\' && chr != '/') {
176                *ptr++ = '\\';
177                *ptr = '\0';
178            }
179            MultiByteToWideChar(CP_ACP, 0, dirTableA[index], -1,
180                    wBuffer, (sizeof(wBuffer)/sizeof(WCHAR)));
181            length = wcslen(wBuffer);
182            pMem->Free(dirTableW[index]);
183            dirTableW[index] = (WCHAR*)pMem->Malloc((length+1)*2);
184            if (dirTableW[index] != NULL) {
185                wcscpy(dirTableW[index], wBuffer);
186            }
187        }
188    }
189
190    if(bManageDirectory)
191        ::SetCurrentDirectoryA(pPath);
192
193    return length;
194}
195
196void VDir::FromEnvA(char *pEnv, int index)
197{   /* gets the directory for index from the environment variable. */
198    while (*pEnv != '\0') {
199        if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)) {
200            SetDirA(&pEnv[4], index);
201            break;
202        }
203        else
204            pEnv += strlen(pEnv)+1;
205    }
206}
207
208void VDir::SetDefaultA(char const *pDefault)
209{
210    char szBuffer[MAX_PATH+1];
211    char *pPtr;
212
213    if (GetFullPathNameA(pDefault, sizeof(szBuffer), szBuffer, &pPtr)) {
214        if (*pDefault != '.' && pPtr != NULL)
215            *pPtr = '\0';
216
217        SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
218    }
219}
220
221int VDir::SetDirW(WCHAR const *pPath, int index)
222{
223    WCHAR chr, *ptr;
224    char szBuffer[MAX_PATH+1];
225    int length = 0;
226    if (index < driveCount && pPath != NULL) {
227        length = wcslen(pPath);
228        pMem->Free(dirTableW[index]);
229        ptr = dirTableW[index] = (WCHAR*)pMem->Malloc((length+2)*2);
230        if (ptr != NULL) {
231            wcscpy(ptr, pPath);
232            ptr += length-1;
233            chr = *ptr++;
234            if (chr != '\\' && chr != '/') {
235                *ptr++ = '\\';
236                *ptr = '\0';
237            }
238            WideCharToMultiByte(CP_ACP, 0, dirTableW[index], -1, szBuffer, sizeof(szBuffer), NULL, NULL);
239            length = strlen(szBuffer);
240            pMem->Free(dirTableA[index]);
241            dirTableA[index] = (char*)pMem->Malloc(length+1);
242            if (dirTableA[index] != NULL) {
243                strcpy(dirTableA[index], szBuffer);
244            }
245        }
246    }
247
248    if(bManageDirectory)
249        ::SetCurrentDirectoryW(pPath);
250
251    return length;
252}
253
254void VDir::SetDefaultW(WCHAR const *pDefault)
255{
256    WCHAR szBuffer[MAX_PATH+1];
257    WCHAR *pPtr;
258
259    if (GetFullPathNameW(pDefault, (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr)) {
260        if (*pDefault != '.' && pPtr != NULL)
261            *pPtr = '\0';
262
263        SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0]));
264    }
265}
266
267inline BOOL IsPathSep(char ch)
268{
269    return (ch == '\\' || ch == '/');
270}
271
272inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest)
273{
274    char *pPtr;
275
276    /*
277     * On WinNT GetFullPathName does not fail, (or at least always
278     * succeeds when the drive is valid) WinNT does set *Dest to Nullch
279     * On Win98 GetFullPathName will set last error if it fails, but
280     * does not touch *Dest
281     */
282    *Dest = '\0';
283    GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr);
284}
285
286inline bool IsSpecialFileName(const char* pName)
287{
288    /* specical file names are devices that the system can open
289     * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$
290     * (x is a single digit, and names are case-insensitive)
291     */
292    char ch = (pName[0] & ~0x20);
293    switch (ch)
294    {
295        case 'A': /* AUX */
296            if (((pName[1] & ~0x20) == 'U')
297                && ((pName[2] & ~0x20) == 'X')
298                && !pName[3])
299                    return true;
300            break;
301        case 'C': /* CLOCK$, COMx,  CON, CONIN$ CONOUT$ */
302            ch = (pName[1] & ~0x20);
303            switch (ch)
304            {
305                case 'L': /* CLOCK$ */
306                    if (((pName[2] & ~0x20) == 'O')
307                        && ((pName[3] & ~0x20) == 'C')
308                        && ((pName[4] & ~0x20) == 'K')
309                        && (pName[5] == '$')
310                        && !pName[6])
311                            return true;
312                    break;
313                case 'O': /* COMx,  CON, CONIN$ CONOUT$ */
314                    if ((pName[2] & ~0x20) == 'M') {
315                        if ((pName[3] >= '1') && (pName[3] <= '9')
316                            && !pName[4])
317                            return true;
318                    }
319                    else if ((pName[2] & ~0x20) == 'N') {
320                        if (!pName[3])
321                            return true;
322                        else if ((pName[3] & ~0x20) == 'I') {
323                            if (((pName[4] & ~0x20) == 'N')
324                                && (pName[5] == '$')
325                                && !pName[6])
326                            return true;
327                        }
328                        else if ((pName[3] & ~0x20) == 'O') {
329                            if (((pName[4] & ~0x20) == 'U')
330                                && ((pName[5] & ~0x20) == 'T')
331                                && (pName[6] == '$')
332                                && !pName[7])
333                            return true;
334                        }
335                    }
336                    break;
337            }
338            break;
339        case 'L': /* LPTx */
340            if (((pName[1] & ~0x20) == 'U')
341                && ((pName[2] & ~0x20) == 'X')
342                && (pName[3] >= '1') && (pName[3] <= '9')
343                && !pName[4])
344                    return true;
345            break;
346        case 'N': /* NUL */
347            if (((pName[1] & ~0x20) == 'U')
348                && ((pName[2] & ~0x20) == 'L')
349                && !pName[3])
350                    return true;
351            break;
352        case 'P': /* PRN */
353            if (((pName[1] & ~0x20) == 'R')
354                && ((pName[2] & ~0x20) == 'N')
355                && !pName[3])
356                    return true;
357            break;
358    }
359    return false;
360}
361
362char *VDir::MapPathA(const char *pInName)
363{   /*
364     * possiblities -- relative path or absolute path with or without drive letter
365     * OR UNC name
366     */
367    char szBuffer[(MAX_PATH+1)*2];
368    char szlBuf[MAX_PATH+1];
369
370    if (strlen(pInName) > MAX_PATH) {
371        strncpy(szlBuf, pInName, MAX_PATH);
372        if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {   
373            /* absolute path - reduce length by 2 for drive specifier */
374            szlBuf[MAX_PATH-2] = '\0';
375        }
376        else
377            szlBuf[MAX_PATH] = '\0';
378        pInName = szlBuf;
379    }
380    /* strlen(pInName) is now <= MAX_PATH */
381
382    if (pInName[1] == ':') {
383        /* has drive letter */
384        if (IsPathSep(pInName[2])) {
385            /* absolute with drive letter */
386            strcpy(szLocalBufferA, pInName);
387        }
388        else {
389            /* relative path with drive letter */
390            strcpy(szBuffer, GetDirA(DriveIndex(*pInName)));
391            strcat(szBuffer, &pInName[2]);
392            if(strlen(szBuffer) > MAX_PATH)
393                szBuffer[MAX_PATH] = '\0';
394
395            DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
396        }
397    }
398    else {
399        /* no drive letter */
400        if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
401            /* UNC name */
402            strcpy(szLocalBufferA, pInName);
403        }
404        else {
405            strcpy(szBuffer, GetDefaultDirA());
406            if (IsPathSep(pInName[0])) {
407                /* absolute path */
408                szLocalBufferA[0] = szBuffer[0];
409                szLocalBufferA[1] = szBuffer[1];
410                strcpy(&szLocalBufferA[2], pInName);
411            }
412            else {
413                /* relative path */
414                if (IsSpecialFileName(pInName)) {
415                    return (char*)pInName;
416                }
417                else {
418                    strcat(szBuffer, pInName);
419                    if (strlen(szBuffer) > MAX_PATH)
420                        szBuffer[MAX_PATH] = '\0';
421
422                    DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
423                }
424            }
425        }
426    }
427
428    return szLocalBufferA;
429}
430
431int VDir::SetCurrentDirectoryA(char *lpBuffer)
432{
433    HANDLE hHandle;
434    WIN32_FIND_DATA win32FD;
435    char szBuffer[MAX_PATH+1], *pPtr;
436    int length, nRet = -1;
437
438    GetFullPathNameA(MapPathA(lpBuffer), sizeof(szBuffer), szBuffer, &pPtr);
439    /* if the last char is a '\\' or a '/' then add
440     * an '*' before calling FindFirstFile
441     */
442    length = strlen(szBuffer);
443    if(length > 0 && IsPathSep(szBuffer[length-1])) {
444        szBuffer[length] = '*';
445        szBuffer[length+1] = '\0';
446    }
447
448    hHandle = FindFirstFileA(szBuffer, &win32FD);
449    if (hHandle != INVALID_HANDLE_VALUE) {
450        FindClose(hHandle);
451
452        /* if an '*' was added remove it */
453        if(szBuffer[length] == '*')
454            szBuffer[length] = '\0';
455
456        SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
457        nRet = 0;
458    }
459    return nRet;
460}
461
462DWORD VDir::CalculateEnvironmentSpace(void)
463{   /* the current directory environment strings are stored as '=d=d:\path' */
464    int index;
465    DWORD dwSize = 0;
466    for (index = 0; index < driveCount; ++index) {
467        if (dirTableA[index] != NULL) {
468            dwSize += strlen(dirTableA[index]) + 4;  /* add 1 for trailing NULL and 3 for '=d=' */
469        }
470    }
471    return dwSize;
472}
473
474LPSTR VDir::BuildEnvironmentSpace(LPSTR lpStr)
475{   /* store the current directory environment strings as '=d=d:\path' */
476    int index;
477    LPSTR lpDirStr;
478    for (index = 0; index < driveCount; ++index) {
479        lpDirStr = dirTableA[index];
480        if (lpDirStr != NULL) {
481            lpStr[0] = '=';
482            lpStr[1] = lpDirStr[0];
483            lpStr[2] = '=';
484            strcpy(&lpStr[3], lpDirStr);
485            lpStr += strlen(lpDirStr) + 4; /* add 1 for trailing NULL and 3 for '=d=' */
486        }
487    }
488    return lpStr;
489}
490
491inline BOOL IsPathSep(WCHAR ch)
492{
493    return (ch == '\\' || ch == '/');
494}
495
496inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest)
497{
498    WCHAR *pPtr;
499
500    /*
501     * On WinNT GetFullPathName does not fail, (or at least always
502     * succeeds when the drive is valid) WinNT does set *Dest to Nullch
503     * On Win98 GetFullPathName will set last error if it fails, but
504     * does not touch *Dest
505     */
506    *Dest = '\0';
507    GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr);
508}
509
510inline bool IsSpecialFileName(const WCHAR* pName)
511{
512    /* specical file names are devices that the system can open
513     * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$
514     * (x is a single digit, and names are case-insensitive)
515     */
516    WCHAR ch = (pName[0] & ~0x20);
517    switch (ch)
518    {
519        case 'A': /* AUX */
520            if (((pName[1] & ~0x20) == 'U')
521                && ((pName[2] & ~0x20) == 'X')
522                && !pName[3])
523                    return true;
524            break;
525        case 'C': /* CLOCK$, COMx,  CON, CONIN$ CONOUT$ */
526            ch = (pName[1] & ~0x20);
527            switch (ch)
528            {
529                case 'L': /* CLOCK$ */
530                    if (((pName[2] & ~0x20) == 'O')
531                        && ((pName[3] & ~0x20) == 'C')
532                        && ((pName[4] & ~0x20) == 'K')
533                        && (pName[5] == '$')
534                        && !pName[6])
535                            return true;
536                    break;
537                case 'O': /* COMx,  CON, CONIN$ CONOUT$ */
538                    if ((pName[2] & ~0x20) == 'M') {
539                        if ((pName[3] >= '1') && (pName[3] <= '9')
540                            && !pName[4])
541                            return true;
542                    }
543                    else if ((pName[2] & ~0x20) == 'N') {
544                        if (!pName[3])
545                            return true;
546                        else if ((pName[3] & ~0x20) == 'I') {
547                            if (((pName[4] & ~0x20) == 'N')
548                                && (pName[5] == '$')
549                                && !pName[6])
550                            return true;
551                        }
552                        else if ((pName[3] & ~0x20) == 'O') {
553                            if (((pName[4] & ~0x20) == 'U')
554                                && ((pName[5] & ~0x20) == 'T')
555                                && (pName[6] == '$')
556                                && !pName[7])
557                            return true;
558                        }
559                    }
560                    break;
561            }
562            break;
563        case 'L': /* LPTx */
564            if (((pName[1] & ~0x20) == 'U')
565                && ((pName[2] & ~0x20) == 'X')
566                && (pName[3] >= '1') && (pName[3] <= '9')
567                && !pName[4])
568                    return true;
569            break;
570        case 'N': /* NUL */
571            if (((pName[1] & ~0x20) == 'U')
572                && ((pName[2] & ~0x20) == 'L')
573                && !pName[3])
574                    return true;
575            break;
576        case 'P': /* PRN */
577            if (((pName[1] & ~0x20) == 'R')
578                && ((pName[2] & ~0x20) == 'N')
579                && !pName[3])
580                    return true;
581            break;
582    }
583    return false;
584}
585
586WCHAR* VDir::MapPathW(const WCHAR *pInName)
587{   /*
588     * possiblities -- relative path or absolute path with or without drive letter
589     * OR UNC name
590     */
591    WCHAR szBuffer[(MAX_PATH+1)*2];
592    WCHAR szlBuf[MAX_PATH+1];
593
594    if (wcslen(pInName) > MAX_PATH) {
595        wcsncpy(szlBuf, pInName, MAX_PATH);
596        if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {   
597            /* absolute path - reduce length by 2 for drive specifier */
598            szlBuf[MAX_PATH-2] = '\0';
599        }
600        else
601            szlBuf[MAX_PATH] = '\0';
602        pInName = szlBuf;
603    }
604    /* strlen(pInName) is now <= MAX_PATH */
605
606    if (pInName[1] == ':') {
607        /* has drive letter */
608        if (IsPathSep(pInName[2])) {
609            /* absolute with drive letter */
610            wcscpy(szLocalBufferW, pInName);
611        }
612        else {
613            /* relative path with drive letter */
614            wcscpy(szBuffer, GetDirW(DriveIndex((char)*pInName)));
615            wcscat(szBuffer, &pInName[2]);
616            if(wcslen(szBuffer) > MAX_PATH)
617                szBuffer[MAX_PATH] = '\0';
618
619            DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
620        }
621    }
622    else {
623        /* no drive letter */
624        if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
625            /* UNC name */
626            wcscpy(szLocalBufferW, pInName);
627        }
628        else {
629            wcscpy(szBuffer, GetDefaultDirW());
630            if (IsPathSep(pInName[0])) {
631                /* absolute path */
632                szLocalBufferW[0] = szBuffer[0];
633                szLocalBufferW[1] = szBuffer[1];
634                wcscpy(&szLocalBufferW[2], pInName);
635            }
636            else {
637                /* relative path */
638                if (IsSpecialFileName(pInName)) {
639                    return (WCHAR*)pInName;
640                }
641                else {
642                    wcscat(szBuffer, pInName);
643                    if (wcslen(szBuffer) > MAX_PATH)
644                        szBuffer[MAX_PATH] = '\0';
645
646                    DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
647                }
648            }
649        }
650    }
651    return szLocalBufferW;
652}
653
654int VDir::SetCurrentDirectoryW(WCHAR *lpBuffer)
655{
656    HANDLE hHandle;
657    WIN32_FIND_DATAW win32FD;
658    WCHAR szBuffer[MAX_PATH+1], *pPtr;
659    int length, nRet = -1;
660
661    GetFullPathNameW(MapPathW(lpBuffer), (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr);
662    /* if the last char is a '\\' or a '/' then add
663     * an '*' before calling FindFirstFile
664     */
665    length = wcslen(szBuffer);
666    if(length > 0 && IsPathSep(szBuffer[length-1])) {
667        szBuffer[length] = '*';
668        szBuffer[length+1] = '\0';
669    }
670
671    hHandle = FindFirstFileW(szBuffer, &win32FD);
672    if (hHandle != INVALID_HANDLE_VALUE) {
673        FindClose(hHandle);
674
675        /* if an '*' was added remove it */
676        if(szBuffer[length] == '*')
677            szBuffer[length] = '\0';
678
679        SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0]));
680        nRet = 0;
681    }
682    return nRet;
683}
684
685#endif  /* ___VDir_H___ */
Note: See TracBrowser for help on using the repository browser.