diff options
author | Nicholas Clark <nick@ccl4.org> | 2009-10-02 17:57:13 +0100 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2009-10-02 17:57:13 +0100 |
commit | 43aed010bf8b6e3fe32d5f9e8e086dda22b5b4c6 (patch) | |
tree | 8079ba2a658289bdccc9cff62d201268b0173612 /cpan/Win32/longpath.inc | |
parent | 610892605b3814cdf4f5f2215ee00d25d7ffba45 (diff) | |
download | perl-43aed010bf8b6e3fe32d5f9e8e086dda22b5b4c6.tar.gz |
Move Win32 from ext/ to cpan/
Diffstat (limited to 'cpan/Win32/longpath.inc')
-rw-r--r-- | cpan/Win32/longpath.inc | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/cpan/Win32/longpath.inc b/cpan/Win32/longpath.inc new file mode 100644 index 0000000000..ea6c1de48a --- /dev/null +++ b/cpan/Win32/longpath.inc @@ -0,0 +1,111 @@ +#ifndef isSLASH +#define isSLASH(c) ((c) == '/' || (c) == '\\') +#define SKIP_SLASHES(s) \ + STMT_START { \ + while (*(s) && isSLASH(*(s))) \ + ++(s); \ + } STMT_END +#define COPY_NONSLASHES(d,s) \ + STMT_START { \ + while (*(s) && !isSLASH(*(s))) \ + *(d)++ = *(s)++; \ + } STMT_END +#endif + +/* Find the longname of a given path. path is destructively modified. + * It should have space for at least MAX_PATH characters. */ + +CHAR_T * +LONGPATH(CHAR_T *path) +{ + WIN32_FIND_DATA_T fdata; + HANDLE fhand; + CHAR_T tmpbuf[MAX_PATH+1]; + CHAR_T *tmpstart = tmpbuf; + CHAR_T *start = path; + CHAR_T sep; + if (!path) + return NULL; + + /* drive prefix */ + if (isALPHA(path[0]) && path[1] == ':') { + start = path + 2; + *tmpstart++ = toupper(path[0]); + *tmpstart++ = ':'; + } + /* UNC prefix */ + else if (isSLASH(path[0]) && isSLASH(path[1])) { + start = path + 2; + *tmpstart++ = path[0]; + *tmpstart++ = path[1]; + SKIP_SLASHES(start); + COPY_NONSLASHES(tmpstart,start); /* copy machine name */ + if (*start) { + *tmpstart++ = *start++; + SKIP_SLASHES(start); + COPY_NONSLASHES(tmpstart,start); /* copy share name */ + } + } + *tmpstart = '\0'; + while (*start) { + /* copy initial slash, if any */ + if (isSLASH(*start)) { + *tmpstart++ = *start++; + *tmpstart = '\0'; + SKIP_SLASHES(start); + } + + /* FindFirstFile() expands "." and "..", so we need to pass + * those through unmolested */ + if (*start == '.' + && (!start[1] || isSLASH(start[1]) + || (start[1] == '.' && (!start[2] || isSLASH(start[2]))))) + { + COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */ + *tmpstart = '\0'; + continue; + } + + /* if this is the end, bust outta here */ + if (!*start) + break; + + /* now we're at a non-slash; walk up to next slash */ + while (*start && !isSLASH(*start)) + ++start; + + /* stop and find full name of component */ + sep = *start; + *start = '\0'; + fhand = FN_FINDFIRSTFILE(path,&fdata); + *start = sep; + if (fhand != INVALID_HANDLE_VALUE) { + STRLEN len = FN_STRLEN(fdata.cFileName); + if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) { + FN_STRCPY(tmpstart, fdata.cFileName); + tmpstart += len; + FindClose(fhand); + } + else { + FindClose(fhand); + errno = ERANGE; + return NULL; + } + } + else { + /* failed a step, just return without side effects */ + /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/ + errno = EINVAL; + return NULL; + } + } + FN_STRCPY(path,tmpbuf); + return path; +} + +#undef CHAR_T +#undef WIN32_FIND_DATA_T +#undef FN_FINDFIRSTFILE +#undef FN_STRLEN +#undef FN_STRCPY +#undef LONGPATH |