1 package File::Spec::Win32;
5 use vars qw(@ISA $VERSION);
6 require File::Spec::Unix;
10 @ISA = qw(File::Spec::Unix);
14 File::Spec::Win32 - methods for Win32 file specs
18 require File::Spec::Win32; # Done internally by File::Spec if needed
22 See File::Spec::Unix for a documentation of the methods provided
23 there. This package overrides the implementation of these methods, not
30 Returns a string representation of the null device.
40 Returns a string representation of the first existing directory
41 from the following list:
53 return $tmpdir if defined $tmpdir;
55 foreach (@ENV{qw(TMPDIR TEMP TMP)}, qw(/tmp /)) {
56 next unless defined && -d;
60 $tmpdir = '' unless defined $tmpdir;
61 $tmpdir = $self->canonpath($tmpdir);
69 sub file_name_is_absolute {
70 my ($self,$file) = @_;
71 return scalar($file =~ m{^([a-z]:)?[\\/]}is);
76 Concatenate one or more directory names and a filename to form a
77 complete path ending with a filename
84 return $file unless @_;
85 my $dir = $self->catdir(@_);
86 $dir .= "\\" unless substr($dir,-1) eq "\\";
91 my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
92 my @path = split(';',$path);
93 foreach (@path) { $_ = '.' if $_ eq '' }
99 No physical check on the filesystem, but a logical cleanup of a
100 path. On UNIX eliminated successive slashes and successive "/.".
105 my ($self,$path) = @_;
106 $path =~ s/^([a-z]:)/\u$1/s;
108 $path =~ s|([^\\])\\+|$1\\|g; # xx////xx -> xx/xx
109 $path =~ s|(\\\.)+\\|\\|g; # xx/././xx -> xx/xx
110 $path =~ s|^(\.\\)+||s unless $path eq ".\\"; # ./xx -> xx
112 unless $path =~ m#^([A-Z]:)?\\\z#s; # xx/ -> xx
118 ($volume,$directories,$file) = File::Spec->splitpath( $path );
119 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
121 Splits a path in to volume, directory, and filename portions. Assumes that
122 the last file is a path unless the path ends in '\\', '\\.', '\\..'
123 or $no_file is true. On Win32 this means that $no_file true makes this return
124 ( $volume, $path, undef ).
126 Separators accepted are \ and /.
128 Volumes can be drive letters or UNC sharenames (\\server\share).
130 The results can be passed to L</catpath> to get back a path equivalent to
131 (usually identical to) the original path.
136 my ($self,$path, $nofile) = @_;
137 my ($volume,$directory,$file) = ('','','');
140 m{^( (?:[a-zA-Z]:|(?:\\\\|//)[^\\/]+[\\/][^\\/]+)? )
148 m{^ ( (?: [a-zA-Z]: |
149 (?:\\\\|//)[^\\/]+[\\/][^\\/]+
152 ( (?:.*[\\\\/](?:\.\.?\z)?)? )
160 return ($volume,$directory,$file);
166 The opposite of L</catdir()>.
168 @dirs = File::Spec->splitdir( $directories );
170 $directories must be only the directory portion of the path on systems
171 that have the concept of a volume or that have path syntax that differentiates
172 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
178 File::Spec->splitdir( "/a/b/c" );
182 ( '', 'a', 'b', '', 'c', '' )
187 my ($self,$directories) = @_ ;
189 # split() likes to forget about trailing null fields, so here we
190 # check to be sure that there will not be any before handling the
193 if ( $directories !~ m|[\\/]\z| ) {
194 return split( m|[\\/]|, $directories );
198 # since there was a trailing separator, add a file name to the end,
199 # then do the split, then replace it with ''.
201 my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
202 $directories[ $#directories ]= '' ;
203 return @directories ;
210 Takes volume, directory and file portions and returns an entire path. Under
211 Unix, $volume is ignored, and this is just like catfile(). On other OSs,
212 the $volume become significant.
217 my ($self,$volume,$directory,$file) = @_;
219 # If it's UNC, make sure the glue separator is there, reusing
220 # whatever separator is first in the $volume
222 if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\z@s &&
223 $directory =~ m@^[^\\/]@s
226 $volume .= $directory ;
228 # If the volume is not just A:, make sure the glue separator is
229 # there, reusing whatever separator is first in the $volume if possible.
230 if ( $volume !~ m@^[a-zA-Z]:\z@s &&
231 $volume =~ m@[^\\/]\z@ &&
234 $volume =~ m@([\\/])@ ;
235 my $sep = $1 ? $1 : '\\' ;
247 Takes a destination path and an optional base path returns a relative path
248 from the base path to the destination path:
250 $rel_path = File::Spec->abs2rel( $destination ) ;
251 $rel_path = File::Spec->abs2rel( $destination, $base ) ;
253 If $base is not present or '', then L</cwd()> is used. If $base is relative,
254 then it is converted to absolute form using L</rel2abs()>. This means that it
255 is taken to be relative to L<cwd()>.
257 On systems with the concept of a volume, this assumes that both paths
258 are on the $destination volume, and ignores the $base volume.
260 On systems that have a grammar that indicates filenames, this ignores the
261 $base filename as well. Otherwise all path components are assumed to be
264 If $path is relative, it is converted to absolute form using L</rel2abs()>.
265 This means that it is taken to be relative to L</cwd()>.
267 Based on code written by Shigio Yamaguchi.
269 No checks against the filesystem are made.
274 my($self,$path,$base) = @_;
277 if ( ! $self->file_name_is_absolute( $path ) ) {
278 $path = $self->rel2abs( $path ) ;
281 $path = $self->canonpath( $path ) ;
284 # Figure out the effective $base and clean it up.
285 if ( ! $self->file_name_is_absolute( $base ) ) {
286 $base = $self->rel2abs( $base ) ;
288 elsif ( !defined( $base ) || $base eq '' ) {
292 $base = $self->canonpath( $base ) ;
296 my ( $path_volume, $path_directories, $path_file ) =
297 $self->splitpath( $path, 1 ) ;
299 my ( undef, $base_directories, undef ) =
300 $self->splitpath( $base, 1 ) ;
302 # Now, remove all leading components that are the same
303 my @pathchunks = $self->splitdir( $path_directories );
304 my @basechunks = $self->splitdir( $base_directories );
306 while ( @pathchunks &&
308 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
314 # No need to catdir, we know these are well formed.
315 $path_directories = CORE::join( '\\', @pathchunks );
316 $base_directories = CORE::join( '\\', @basechunks );
318 # $base_directories now contains the directories the resulting relative
319 # path must ascend out of before it can descend to $path_directory. So,
320 # replace all names with $parentDir
322 #FA Need to replace between backslashes...
323 $base_directories =~ s|[^\\]+|..|g ;
325 # Glue the two together, using a separator if necessary, and preventing an
328 #FA Must check that new directories are not empty.
329 if ( $path_directories ne '' && $base_directories ne '' ) {
330 $path_directories = "$base_directories\\$path_directories" ;
332 $path_directories = "$base_directories$path_directories" ;
335 # It makes no sense to add a relative path to a UNC volume
336 $path_volume = '' unless $path_volume =~ m{^[A-Z]:}is ;
338 return $self->canonpath(
339 $self->catpath($path_volume, $path_directories, $path_file )
345 Converts a relative path to an absolute path.
347 $abs_path = File::Spec->rel2abs( $destination ) ;
348 $abs_path = File::Spec->rel2abs( $destination, $base ) ;
350 If $base is not present or '', then L<cwd()> is used. If $base is relative,
351 then it is converted to absolute form using L</rel2abs()>. This means that it
352 is taken to be relative to L</cwd()>.
354 Assumes that both paths are on the $base volume, and ignores the
357 On systems that have a grammar that indicates filenames, this ignores the
358 $base filename as well. Otherwise all path components are assumed to be
361 If $path is absolute, it is cleaned up and returned using L</canonpath()>.
363 Based on code written by Shigio Yamaguchi.
365 No checks against the filesystem are made.
370 my ($self,$path,$base ) = @_;
372 if ( ! $self->file_name_is_absolute( $path ) ) {
374 if ( !defined( $base ) || $base eq '' ) {
377 elsif ( ! $self->file_name_is_absolute( $base ) ) {
378 $base = $self->rel2abs( $base ) ;
381 $base = $self->canonpath( $base ) ;
384 my ( undef, $path_directories, $path_file ) =
385 $self->splitpath( $path, 1 ) ;
387 my ( $base_volume, $base_directories, undef ) =
388 $self->splitpath( $base, 1 ) ;
390 $path = $self->catpath(
392 $self->catdir( $base_directories, $path_directories ),
397 return $self->canonpath( $path ) ;