This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perlform: Revise link
[perl5.git] / cpan / Win32 / longpath.inc
1 #ifndef isSLASH\r
2 #define isSLASH(c) ((c) == '/' || (c) == '\\')\r
3 #define SKIP_SLASHES(s) \\r
4     STMT_START {                                \\r
5         while (*(s) && isSLASH(*(s)))           \\r
6             ++(s);                              \\r
7     } STMT_END\r
8 #define COPY_NONSLASHES(d,s) \\r
9     STMT_START {                                \\r
10         while (*(s) && !isSLASH(*(s)))          \\r
11             *(d)++ = *(s)++;                    \\r
12     } STMT_END\r
13 #endif\r
14 \r
15 /* Find the longname of a given path.  path is destructively modified.\r
16  * It should have space for at least MAX_PATH characters. */\r
17 \r
18 CHAR_T *\r
19 LONGPATH(CHAR_T *path)\r
20 {\r
21     WIN32_FIND_DATA_T fdata;\r
22     HANDLE fhand;\r
23     CHAR_T tmpbuf[MAX_PATH+1];\r
24     CHAR_T *tmpstart = tmpbuf;\r
25     CHAR_T *start = path;\r
26     CHAR_T sep;\r
27     if (!path)\r
28         return NULL;\r
29 \r
30     /* drive prefix */\r
31     if (isALPHA(path[0]) && path[1] == ':') {\r
32         start = path + 2;\r
33         *tmpstart++ = toupper(path[0]);\r
34         *tmpstart++ = ':';\r
35     }\r
36     /* UNC prefix */\r
37     else if (isSLASH(path[0]) && isSLASH(path[1])) {\r
38         start = path + 2;\r
39         *tmpstart++ = path[0];\r
40         *tmpstart++ = path[1];\r
41         SKIP_SLASHES(start);\r
42         COPY_NONSLASHES(tmpstart,start);        /* copy machine name */\r
43         if (*start) {\r
44             *tmpstart++ = *start++;\r
45             SKIP_SLASHES(start);\r
46             COPY_NONSLASHES(tmpstart,start);    /* copy share name */\r
47         }\r
48     }\r
49     *tmpstart = '\0';\r
50     while (*start) {\r
51         /* copy initial slash, if any */\r
52         if (isSLASH(*start)) {\r
53             *tmpstart++ = *start++;\r
54             *tmpstart = '\0';\r
55             SKIP_SLASHES(start);\r
56         }\r
57 \r
58         /* FindFirstFile() expands "." and "..", so we need to pass\r
59          * those through unmolested */\r
60         if (*start == '.'\r
61             && (!start[1] || isSLASH(start[1])\r
62                 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))\r
63         {\r
64             COPY_NONSLASHES(tmpstart,start);    /* copy "." or ".." */\r
65             *tmpstart = '\0';\r
66             continue;\r
67         }\r
68 \r
69         /* if this is the end, bust outta here */\r
70         if (!*start)\r
71             break;\r
72 \r
73         /* now we're at a non-slash; walk up to next slash */\r
74         while (*start && !isSLASH(*start))\r
75             ++start;\r
76 \r
77         /* stop and find full name of component */\r
78         sep = *start;\r
79         *start = '\0';\r
80         fhand = FN_FINDFIRSTFILE(path,&fdata);\r
81         *start = sep;\r
82         if (fhand != INVALID_HANDLE_VALUE) {\r
83             STRLEN len = FN_STRLEN(fdata.cFileName);\r
84             if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {\r
85                 FN_STRCPY(tmpstart, fdata.cFileName);\r
86                 tmpstart += len;\r
87                 FindClose(fhand);\r
88             }\r
89             else {\r
90                 FindClose(fhand);\r
91                 errno = ERANGE;\r
92                 return NULL;\r
93             }\r
94         }\r
95         else {\r
96             /* failed a step, just return without side effects */\r
97             /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/\r
98             errno = EINVAL;\r
99             return NULL;\r
100         }\r
101     }\r
102     FN_STRCPY(path,tmpbuf);\r
103     return path;\r
104 }\r
105 \r
106 #undef CHAR_T\r
107 #undef WIN32_FIND_DATA_T\r
108 #undef FN_FINDFIRSTFILE\r
109 #undef FN_STRLEN\r
110 #undef FN_STRCPY\r
111 #undef LONGPATH\r