PageRenderTime 1233ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/perl/lib/File/Spec/Win32.pm

https://github.com/Tailgunner/CataMooseC
Perl | 444 lines | 362 code | 64 blank | 18 comment | 17 complexity | 785f3c54c771c9eb35ae37f637045135 MD5 | raw file
  1. package File::Spec::Win32;
  2. use strict;
  3. use vars qw(@ISA $VERSION);
  4. require File::Spec::Unix;
  5. $VERSION = '3.30';
  6. $VERSION = eval $VERSION;
  7. @ISA = qw(File::Spec::Unix);
  8. # Some regexes we use for path splitting
  9. my $DRIVE_RX = '[a-zA-Z]:';
  10. my $UNC_RX = '(?:\\\\\\\\|//)[^\\\\/]+[\\\\/][^\\\\/]+';
  11. my $VOL_RX = "(?:$DRIVE_RX|$UNC_RX)";
  12. =head1 NAME
  13. File::Spec::Win32 - methods for Win32 file specs
  14. =head1 SYNOPSIS
  15. require File::Spec::Win32; # Done internally by File::Spec if needed
  16. =head1 DESCRIPTION
  17. See File::Spec::Unix for a documentation of the methods provided
  18. there. This package overrides the implementation of these methods, not
  19. the semantics.
  20. =over 4
  21. =item devnull
  22. Returns a string representation of the null device.
  23. =cut
  24. sub devnull {
  25. return "nul";
  26. }
  27. sub rootdir { '\\' }
  28. =item tmpdir
  29. Returns a string representation of the first existing directory
  30. from the following list:
  31. $ENV{TMPDIR}
  32. $ENV{TEMP}
  33. $ENV{TMP}
  34. SYS:/temp
  35. C:\system\temp
  36. C:/temp
  37. /tmp
  38. /
  39. The SYS:/temp is preferred in Novell NetWare and the C:\system\temp
  40. for Symbian (the File::Spec::Win32 is used also for those platforms).
  41. Since Perl 5.8.0, if running under taint mode, and if the environment
  42. variables are tainted, they are not used.
  43. =cut
  44. my $tmpdir;
  45. sub tmpdir {
  46. return $tmpdir if defined $tmpdir;
  47. $tmpdir = $_[0]->_tmpdir( map( $ENV{$_}, qw(TMPDIR TEMP TMP) ),
  48. 'SYS:/temp',
  49. 'C:\system\temp',
  50. 'C:/temp',
  51. '/tmp',
  52. '/' );
  53. }
  54. =item case_tolerant
  55. MSWin32 case-tolerance depends on GetVolumeInformation() $ouFsFlags == FS_CASE_SENSITIVE,
  56. indicating the case significance when comparing file specifications.
  57. Since XP FS_CASE_SENSITIVE is effectively disabled for the NT subsubsystem.
  58. See http://cygwin.com/ml/cygwin/2007-07/msg00891.html
  59. Default: 1
  60. =cut
  61. sub case_tolerant {
  62. eval { require Win32API::File; } or return 1;
  63. my $drive = shift || "C:";
  64. my $osFsType = "\0"x256;
  65. my $osVolName = "\0"x256;
  66. my $ouFsFlags = 0;
  67. Win32API::File::GetVolumeInformation($drive, $osVolName, 256, [], [], $ouFsFlags, $osFsType, 256 );
  68. if ($ouFsFlags & Win32API::File::FS_CASE_SENSITIVE()) { return 0; }
  69. else { return 1; }
  70. }
  71. =item file_name_is_absolute
  72. As of right now, this returns 2 if the path is absolute with a
  73. volume, 1 if it's absolute with no volume, 0 otherwise.
  74. =cut
  75. sub file_name_is_absolute {
  76. my ($self,$file) = @_;
  77. if ($file =~ m{^($VOL_RX)}o) {
  78. my $vol = $1;
  79. return ($vol =~ m{^$UNC_RX}o ? 2
  80. : $file =~ m{^$DRIVE_RX[\\/]}o ? 2
  81. : 0);
  82. }
  83. return $file =~ m{^[\\/]} ? 1 : 0;
  84. }
  85. =item catfile
  86. Concatenate one or more directory names and a filename to form a
  87. complete path ending with a filename
  88. =cut
  89. sub catfile {
  90. shift;
  91. # Legacy / compatibility support
  92. #
  93. shift, return _canon_cat( "/", @_ )
  94. if $_[0] eq "";
  95. # Compatibility with File::Spec <= 3.26:
  96. # catfile('A:', 'foo') should return 'A:\foo'.
  97. return _canon_cat( ($_[0].'\\'), @_[1..$#_] )
  98. if $_[0] =~ m{^$DRIVE_RX\z}o;
  99. return _canon_cat( @_ );
  100. }
  101. sub catdir {
  102. shift;
  103. # Legacy / compatibility support
  104. #
  105. return ""
  106. unless @_;
  107. shift, return _canon_cat( "/", @_ )
  108. if $_[0] eq "";
  109. # Compatibility with File::Spec <= 3.26:
  110. # catdir('A:', 'foo') should return 'A:\foo'.
  111. return _canon_cat( ($_[0].'\\'), @_[1..$#_] )
  112. if $_[0] =~ m{^$DRIVE_RX\z}o;
  113. return _canon_cat( @_ );
  114. }
  115. sub path {
  116. my @path = split(';', $ENV{PATH});
  117. s/"//g for @path;
  118. @path = grep length, @path;
  119. unshift(@path, ".");
  120. return @path;
  121. }
  122. =item canonpath
  123. No physical check on the filesystem, but a logical cleanup of a
  124. path. On UNIX eliminated successive slashes and successive "/.".
  125. On Win32 makes
  126. dir1\dir2\dir3\..\..\dir4 -> \dir\dir4 and even
  127. dir1\dir2\dir3\...\dir4 -> \dir\dir4
  128. =cut
  129. sub canonpath {
  130. # Legacy / compatibility support
  131. #
  132. return $_[1] if !defined($_[1]) or $_[1] eq '';
  133. return _canon_cat( $_[1] );
  134. }
  135. =item splitpath
  136. ($volume,$directories,$file) = File::Spec->splitpath( $path );
  137. ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
  138. Splits a path into volume, directory, and filename portions. Assumes that
  139. the last file is a path unless the path ends in '\\', '\\.', '\\..'
  140. or $no_file is true. On Win32 this means that $no_file true makes this return
  141. ( $volume, $path, '' ).
  142. Separators accepted are \ and /.
  143. Volumes can be drive letters or UNC sharenames (\\server\share).
  144. The results can be passed to L</catpath> to get back a path equivalent to
  145. (usually identical to) the original path.
  146. =cut
  147. sub splitpath {
  148. my ($self,$path, $nofile) = @_;
  149. my ($volume,$directory,$file) = ('','','');
  150. if ( $nofile ) {
  151. $path =~
  152. m{^ ( $VOL_RX ? ) (.*) }sox;
  153. $volume = $1;
  154. $directory = $2;
  155. }
  156. else {
  157. $path =~
  158. m{^ ( $VOL_RX ? )
  159. ( (?:.*[\\/](?:\.\.?\Z(?!\n))?)? )
  160. (.*)
  161. }sox;
  162. $volume = $1;
  163. $directory = $2;
  164. $file = $3;
  165. }
  166. return ($volume,$directory,$file);
  167. }
  168. =item splitdir
  169. The opposite of L<catdir()|File::Spec/catdir()>.
  170. @dirs = File::Spec->splitdir( $directories );
  171. $directories must be only the directory portion of the path on systems
  172. that have the concept of a volume or that have path syntax that differentiates
  173. files from directories.
  174. Unlike just splitting the directories on the separator, leading empty and
  175. trailing directory entries can be returned, because these are significant
  176. on some OSs. So,
  177. File::Spec->splitdir( "/a/b/c" );
  178. Yields:
  179. ( '', 'a', 'b', '', 'c', '' )
  180. =cut
  181. sub splitdir {
  182. my ($self,$directories) = @_ ;
  183. #
  184. # split() likes to forget about trailing null fields, so here we
  185. # check to be sure that there will not be any before handling the
  186. # simple case.
  187. #
  188. if ( $directories !~ m|[\\/]\Z(?!\n)| ) {
  189. return split( m|[\\/]|, $directories );
  190. }
  191. else {
  192. #
  193. # since there was a trailing separator, add a file name to the end,
  194. # then do the split, then replace it with ''.
  195. #
  196. my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
  197. $directories[ $#directories ]= '' ;
  198. return @directories ;
  199. }
  200. }
  201. =item catpath
  202. Takes volume, directory and file portions and returns an entire path. Under
  203. Unix, $volume is ignored, and this is just like catfile(). On other OSs,
  204. the $volume become significant.
  205. =cut
  206. sub catpath {
  207. my ($self,$volume,$directory,$file) = @_;
  208. # If it's UNC, make sure the glue separator is there, reusing
  209. # whatever separator is first in the $volume
  210. my $v;
  211. $volume .= $v
  212. if ( (($v) = $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s) &&
  213. $directory =~ m@^[^\\/]@s
  214. ) ;
  215. $volume .= $directory ;
  216. # If the volume is not just A:, make sure the glue separator is
  217. # there, reusing whatever separator is first in the $volume if possible.
  218. if ( $volume !~ m@^[a-zA-Z]:\Z(?!\n)@s &&
  219. $volume =~ m@[^\\/]\Z(?!\n)@ &&
  220. $file =~ m@[^\\/]@
  221. ) {
  222. $volume =~ m@([\\/])@ ;
  223. my $sep = $1 ? $1 : '\\' ;
  224. $volume .= $sep ;
  225. }
  226. $volume .= $file ;
  227. return $volume ;
  228. }
  229. sub _same {
  230. lc($_[1]) eq lc($_[2]);
  231. }
  232. sub rel2abs {
  233. my ($self,$path,$base ) = @_;
  234. my $is_abs = $self->file_name_is_absolute($path);
  235. # Check for volume (should probably document the '2' thing...)
  236. return $self->canonpath( $path ) if $is_abs == 2;
  237. if ($is_abs) {
  238. # It's missing a volume, add one
  239. my $vol = ($self->splitpath( $self->_cwd() ))[0];
  240. return $self->canonpath( $vol . $path );
  241. }
  242. if ( !defined( $base ) || $base eq '' ) {
  243. require Cwd ;
  244. $base = Cwd::getdcwd( ($self->splitpath( $path ))[0] ) if defined &Cwd::getdcwd ;
  245. $base = $self->_cwd() unless defined $base ;
  246. }
  247. elsif ( ! $self->file_name_is_absolute( $base ) ) {
  248. $base = $self->rel2abs( $base ) ;
  249. }
  250. else {
  251. $base = $self->canonpath( $base ) ;
  252. }
  253. my ( $path_directories, $path_file ) =
  254. ($self->splitpath( $path, 1 ))[1,2] ;
  255. my ( $base_volume, $base_directories ) =
  256. $self->splitpath( $base, 1 ) ;
  257. $path = $self->catpath(
  258. $base_volume,
  259. $self->catdir( $base_directories, $path_directories ),
  260. $path_file
  261. ) ;
  262. return $self->canonpath( $path ) ;
  263. }
  264. =back
  265. =head2 Note For File::Spec::Win32 Maintainers
  266. Novell NetWare inherits its File::Spec behaviour from File::Spec::Win32.
  267. =head1 COPYRIGHT
  268. Copyright (c) 2004,2007 by the Perl 5 Porters. All rights reserved.
  269. This program is free software; you can redistribute it and/or modify
  270. it under the same terms as Perl itself.
  271. =head1 SEE ALSO
  272. See L<File::Spec> and L<File::Spec::Unix>. This package overrides the
  273. implementation of these methods, not the semantics.
  274. =cut
  275. sub _canon_cat # @path -> path
  276. {
  277. my ($first, @rest) = @_;
  278. my $volume = $first =~ s{ \A ([A-Za-z]:) ([\\/]?) }{}x # drive letter
  279. ? ucfirst( $1 ).( $2 ? "\\" : "" )
  280. : $first =~ s{ \A (?:\\\\|//) ([^\\/]+)
  281. (?: [\\/] ([^\\/]+) )?
  282. [\\/]? }{}xs # UNC volume
  283. ? "\\\\$1".( defined $2 ? "\\$2" : "" )."\\"
  284. : $first =~ s{ \A [\\/] }{}x # root dir
  285. ? "\\"
  286. : "";
  287. my $path = join "\\", $first, @rest;
  288. $path =~ tr#\\/#\\\\#s; # xx/yy --> xx\yy & xx\\yy --> xx\yy
  289. # xx/././yy --> xx/yy
  290. $path =~ s{(?:
  291. (?:\A|\\) # at begin or after a slash
  292. \.
  293. (?:\\\.)* # and more
  294. (?:\\|\z) # at end or followed by slash
  295. )+ # performance boost -- I do not know why
  296. }{\\}gx;
  297. # XXX I do not know whether more dots are supported by the OS supporting
  298. # this ... annotation (NetWare or symbian but not MSWin32).
  299. # Then .... could easily become ../../.. etc:
  300. # Replace \.\.\. by (\.\.\.+) and substitute with
  301. # { $1 . ".." . "\\.." x (length($2)-2) }gex
  302. # ... --> ../..
  303. $path =~ s{ (\A|\\) # at begin or after a slash
  304. \.\.\.
  305. (?=\\|\z) # at end or followed by slash
  306. }{$1..\\..}gx;
  307. # xx\yy\..\zz --> xx\zz
  308. while ( $path =~ s{(?:
  309. (?:\A|\\) # at begin or after a slash
  310. [^\\]+ # rip this 'yy' off
  311. \\\.\.
  312. (?<!\A\.\.\\\.\.) # do *not* replace ^..\..
  313. (?<!\\\.\.\\\.\.) # do *not* replace \..\..
  314. (?:\\|\z) # at end or followed by slash
  315. )+ # performance boost -- I do not know why
  316. }{\\}sx ) {}
  317. $path =~ s#\A\\##; # \xx --> xx NOTE: this is *not* root
  318. $path =~ s#\\\z##; # xx\ --> xx
  319. if ( $volume =~ m#\\\z# )
  320. { # <vol>\.. --> <vol>\
  321. $path =~ s{ \A # at begin
  322. \.\.
  323. (?:\\\.\.)* # and more
  324. (?:\\|\z) # at end or followed by slash
  325. }{}x;
  326. return $1 # \\HOST\SHARE\ --> \\HOST\SHARE
  327. if $path eq ""
  328. and $volume =~ m#\A(\\\\.*)\\\z#s;
  329. }
  330. return $path ne "" || $volume ? $volume.$path : ".";
  331. }
  332. 1;