1 package File::Spec::Win32;
6 require File::Spec::Unix;
7 @ISA = qw(File::Spec::Unix);
11 File::Spec::Win32 - methods for Win32 file specs
15 require File::Spec::Win32; # Done internally by File::Spec if needed
19 See File::Spec::Unix for a documentation of the methods provided
20 there. This package overrides the implementation of these methods, not
27 Returns a string representation of the null device.
37 Returns a string representation of the first existing directory
38 from the following list:
50 return $tmpdir if defined $tmpdir;
52 foreach (@ENV{qw(TMPDIR TEMP TMP)}, qw(/tmp /)) {
53 next unless defined && -d;
57 $tmpdir = '' unless defined $tmpdir;
58 $tmpdir = $self->canonpath($tmpdir);
62 sub file_name_is_absolute {
63 my ($self,$file) = @_;
64 return scalar($file =~ m{^([a-z]:)?[\\/]}i);
69 Concatenate one or more directory names and a filename to form a
70 complete path ending with a filename
77 return $file unless @_;
78 my $dir = $self->catdir(@_);
79 $dir .= "\\" unless substr($dir,-1) eq "\\";
85 my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
86 my @path = split(';',$path);
87 foreach (@path) { $_ = '.' if $_ eq '' }
93 No physical check on the filesystem, but a logical cleanup of a
94 path. On UNIX eliminated successive slashes and successive "/.".
99 my ($self,$path,$reduce_ricochet) = @_;
100 $path =~ s/^([a-z]:)/\u$1/;
102 $path =~ s|([^\\])\\+|$1\\|g; # xx////xx -> xx/xx
103 $path =~ s|(\\\.)+\\|\\|g; # xx/././xx -> xx/xx
104 $path =~ s|^(\.\\)+|| unless $path eq ".\\"; # ./xx -> xx
106 unless $path =~ m#^([A-Z]:)?\\$#; # xx/ -> xx
112 ($volume,$directories,$file) = File::Spec->splitpath( $path );
113 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
115 Splits a path in to volume, directory, and filename portions. Assumes that
116 the last file is a path unless the path ends in '\\', '\\.', '\\..'
117 or $no_file is true. On Win32 this means that $no_file true makes this return
118 ( $volume, $path, undef ).
120 Separators accepted are \ and /.
122 Volumes can be drive letters or UNC sharenames (\\server\share).
124 The results can be passed to L</catpath()> to get back a path equivalent to
125 (usually identical to) the original path.
130 my ($self,$path, $nofile) = @_;
131 my ($volume,$directory,$file) = ('','','');
134 m@^( (?:[a-zA-Z]:|(?:\\\\\\\\|//)[^\\\\/]+[\\\\/][^\\\\/]+)? )
142 m@^ ( (?: [a-zA-Z]: |
143 (?:\\\\\\\\|//)[^\\\\/]+[\\\\/][^\\\\/]+
146 ( (?:.*[\\\\/](?:\.\.?$)?)? )
154 return ($volume,$directory,$file);
160 The opposite of L</catdir()>.
162 @dirs = File::Spec->splitdir( $directories );
164 $directories must be only the directory portion of the path on systems
165 that have the concept of a volume or that have path syntax that differentiates
166 files from directories.
168 Unlike just splitting the directories on the separator, leading empty and
169 trailing directory entries can be returned, because these are significant
172 File::Spec->splitdir( "/a/b/c" );
176 ( '', 'a', 'b', '', 'c', '' )
181 my ($self,$directories) = @_ ;
183 # split() likes to forget about trailing null fields, so here we
184 # check to be sure that there will not be any before handling the
187 if ( $directories !~ m|[\\/]$| ) {
188 return split( m|[\\/]|, $directories );
192 # since there was a trailing separator, add a file name to the end,
193 # then do the split, then replace it with ''.
195 my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
196 $directories[ $#directories ]= '' ;
197 return @directories ;
204 Takes volume, directory and file portions and returns an entire path. Under
205 Unix, $volume is ignored, and this is just like catfile(). On other OSs,
206 the $volume become significant.
211 my ($self,$volume,$directory,$file) = @_;
213 # If it's UNC, make sure the glue separator is there, reusing
214 # whatever separator is first in the $volume
216 if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+$@ &&
217 $directory =~ m@^[^\\/]@
220 $volume .= $directory ;
222 # If the volume is not just A:, make sure the glue separator is
223 # there, reusing whatever separator is first in the $volume if possible.
224 if ( $volume !~ m@^[a-zA-Z]:$@ &&
225 $volume !~ m@[\\/]$@ &&
228 $volume =~ m@([\\/])@ ;
229 my $sep = $1 ? $1 : '\\' ;
241 Takes a destination path and an optional base path returns a relative path
242 from the base path to the destination path:
244 $rel_path = File::Spec->abs2rel( $destination ) ;
245 $rel_path = File::Spec->abs2rel( $destination, $base ) ;
247 If $base is not present or '', then L</cwd()> is used. If $base is relative,
248 then it is converted to absolute form using L</rel2abs()>. This means that it
249 is taken to be relative to L<cwd()>.
251 On systems with the concept of a volume, this assumes that both paths
252 are on the $destination volume, and ignores the $base volume.
254 On systems that have a grammar that indicates filenames, this ignores the
255 $base filename as well. Otherwise all path components are assumed to be
258 If $path is relative, it is converted to absolute form using L</rel2abs()>.
259 This means that it is taken to be relative to L</cwd()>.
261 Based on code written by Shigio Yamaguchi.
263 No checks against the filesystem are made.
268 my($self,$path,$base) = @_;
271 if ( ! $self->file_name_is_absolute( $path ) ) {
272 $path = $self->rel2abs( $path ) ;
275 $path = $self->canonpath( $path ) ;
278 # Figure out the effective $base and clean it up.
279 if ( ! $self->file_name_is_absolute( $base ) ) {
280 $base = $self->rel2abs( $base ) ;
282 elsif ( !defined( $base ) || $base eq '' ) {
286 $base = $self->canonpath( $base ) ;
290 my ( $path_volume, $path_directories, $path_file ) =
291 $self->splitpath( $path, 1 ) ;
293 my ( undef, $base_directories, undef ) =
294 $self->splitpath( $base, 1 ) ;
296 # Now, remove all leading components that are the same
297 my @pathchunks = $self->splitdir( $path_directories );
298 my @basechunks = $self->splitdir( $base_directories );
300 while ( @pathchunks &&
302 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
308 # No need to catdir, we know these are well formed.
309 $path_directories = CORE::join( '\\', @pathchunks );
310 $base_directories = CORE::join( '\\', @basechunks );
312 # $base_directories now contains the directories the resulting relative
313 # path must ascend out of before it can descend to $path_directory. So,
314 # replace all names with $parentDir
316 #FA Need to replace between backslashes...
317 $base_directories =~ s|[^\\]+|..|g ;
319 # Glue the two together, using a separator if necessary, and preventing an
322 #FA Must check that new directories are not empty.
323 if ( $path_directories ne '' && $base_directories ne '' ) {
324 $path_directories = "$base_directories\\$path_directories" ;
326 $path_directories = "$base_directories$path_directories" ;
329 return $self->canonpath(
330 $self->catpath( $path_volume, $path_directories, $path_file )
336 Converts a relative path to an absolute path.
338 $abs_path = $File::Spec->rel2abs( $destination ) ;
339 $abs_path = $File::Spec->rel2abs( $destination, $base ) ;
341 If $base is not present or '', then L<cwd()> is used. If $base is relative,
342 then it is converted to absolute form using L</rel2abs()>. This means that it
343 is taken to be relative to L</cwd()>.
345 Assumes that both paths are on the $base volume, and ignores the
348 On systems that have a grammar that indicates filenames, this ignores the
349 $base filename as well. Otherwise all path components are assumed to be
352 If $path is absolute, it is cleaned up and returned using L</canonpath()>.
354 Based on code written by Shigio Yamaguchi.
356 No checks against the filesystem are made.
361 my ($self,$path,$base ) = @_;
363 # Clean up and split up $path
364 if ( ! $self->file_name_is_absolute( $path ) ) {
366 # Figure out the effective $base and clean it up.
367 if ( ! $self->file_name_is_absolute( $base ) ) {
368 $base = $self->rel2abs( $base ) ;
370 elsif ( !defined( $base ) || $base eq '' ) {
374 $base = $self->canonpath( $base ) ;
378 my ( undef, $path_directories, $path_file ) =
379 $self->splitpath( $path, 1 ) ;
381 my ( $base_volume, $base_directories, undef ) =
382 $self->splitpath( $base, 1 ) ;
384 $path = $self->catpath(
386 $self->catdir( $base_directories, $path_directories ),
391 return $self->canonpath( $path ) ;