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:
52 The SYS:/temp is preferred in Novell NetWare and the C:\system\temp
53 for Symbian (the File::Spec::Win32 is used also for those platforms).
55 Since Perl 5.8.0, if running under taint mode, and if the environment
56 variables are tainted, they are not used.
62 return $tmpdir if defined $tmpdir;
64 $tmpdir = $self->_tmpdir( @ENV{qw(TMPDIR TEMP TMP)},
76 sub file_name_is_absolute {
77 my ($self,$file) = @_;
78 return scalar($file =~ m{^([a-z]:)?[\\/]}is);
83 Concatenate one or more directory names and a filename to form a
84 complete path ending with a filename
90 my $file = $self->canonpath(pop @_);
91 return $file unless @_;
92 my $dir = $self->catdir(@_);
93 $dir .= "\\" unless substr($dir,-1) eq "\\";
102 # append a backslash to each argument unless it has one there
103 $_ .= "\\" unless m{\\$};
105 return $self->canonpath(join('', @args));
109 my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
110 my @path = split(';',$path);
111 foreach (@path) { $_ = '.' if $_ eq '' }
117 No physical check on the filesystem, but a logical cleanup of a
118 path. On UNIX eliminated successive slashes and successive "/.".
121 dir1\dir2\dir3\..\..\dir4 -> \dir\dir4 and even
122 dir1\dir2\dir3\...\dir4 -> \dir\dir4
127 my ($self,$path) = @_;
128 my $orig_path = $path;
129 $path =~ s/^([a-z]:)/\u$1/s;
131 $path =~ s|([^\\])\\+|$1\\|g; # xx\\\\xx -> xx\xx
132 $path =~ s|(\\\.)+\\|\\|g; # xx\.\.\xx -> xx\xx
133 $path =~ s|^(\.\\)+||s unless $path eq ".\\"; # .\xx -> xx
134 $path =~ s|\\\Z(?!\n)||
135 unless $path =~ m{^([A-Z]:)?\\\Z(?!\n)}s; # xx\ -> xx
136 # xx1/xx2/xx3/../../xx -> xx1/xx
137 $path =~ s|\\\.\.\.\\|\\\.\.\\\.\.\\|g; # \...\ is 2 levels up
138 $path =~ s|^\.\.\.\\|\.\.\\\.\.\\|g; # ...\ is 2 levels up
139 return $path if $path =~ m|^\.\.|; # skip relative paths
140 return $path unless $path =~ /\.\./; # too few .'s to cleanup
141 return $path if $path =~ /\.\.\.\./; # too many .'s to cleanup
142 $path =~ s{^\\\.\.$}{\\}; # \.. -> \
143 1 while $path =~ s{^\\\.\.}{}; # \..\xx -> \xx
145 my ($vol,$dirs,$file) = $self->splitpath($path);
146 my @dirs = $self->splitdir($dirs);
147 my (@base_dirs, @path_dirs);
148 my $dest = \@base_dirs;
150 $dest = \@path_dirs if $dir eq $self->updir;
153 # for each .. in @path_dirs pop one item from
155 while (my $dir = shift @path_dirs){
156 unless ($dir eq $self->updir){
157 unshift @path_dirs, $dir;
162 $path = $self->catpath(
164 $self->catdir(@base_dirs, @path_dirs),
172 ($volume,$directories,$file) = File::Spec->splitpath( $path );
173 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
175 Splits a path into volume, directory, and filename portions. Assumes that
176 the last file is a path unless the path ends in '\\', '\\.', '\\..'
177 or $no_file is true. On Win32 this means that $no_file true makes this return
178 ( $volume, $path, '' ).
180 Separators accepted are \ and /.
182 Volumes can be drive letters or UNC sharenames (\\server\share).
184 The results can be passed to L</catpath> to get back a path equivalent to
185 (usually identical to) the original path.
190 my ($self,$path, $nofile) = @_;
191 my ($volume,$directory,$file) = ('','','');
194 m{^( (?:[a-zA-Z]:|(?:\\\\|//)[^\\/]+[\\/][^\\/]+)? )
202 m{^ ( (?: [a-zA-Z]: |
203 (?:\\\\|//)[^\\/]+[\\/][^\\/]+
206 ( (?:.*[\\/](?:\.\.?\Z(?!\n))?)? )
214 return ($volume,$directory,$file);
220 The opposite of L<catdir()|File::Spec/catdir()>.
222 @dirs = File::Spec->splitdir( $directories );
224 $directories must be only the directory portion of the path on systems
225 that have the concept of a volume or that have path syntax that differentiates
226 files from directories.
228 Unlike just splitting the directories on the separator, leading empty and
229 trailing directory entries can be returned, because these are significant
232 File::Spec->splitdir( "/a/b/c" );
236 ( '', 'a', 'b', '', 'c', '' )
241 my ($self,$directories) = @_ ;
243 # split() likes to forget about trailing null fields, so here we
244 # check to be sure that there will not be any before handling the
247 if ( $directories !~ m|[\\/]\Z(?!\n)| ) {
248 return split( m|[\\/]|, $directories );
252 # since there was a trailing separator, add a file name to the end,
253 # then do the split, then replace it with ''.
255 my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
256 $directories[ $#directories ]= '' ;
257 return @directories ;
264 Takes volume, directory and file portions and returns an entire path. Under
265 Unix, $volume is ignored, and this is just like catfile(). On other OSs,
266 the $volume become significant.
271 my ($self,$volume,$directory,$file) = @_;
273 # If it's UNC, make sure the glue separator is there, reusing
274 # whatever separator is first in the $volume
276 if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s &&
277 $directory =~ m@^[^\\/]@s
280 $volume .= $directory ;
282 # If the volume is not just A:, make sure the glue separator is
283 # there, reusing whatever separator is first in the $volume if possible.
284 if ( $volume !~ m@^[a-zA-Z]:\Z(?!\n)@s &&
285 $volume =~ m@[^\\/]\Z(?!\n)@ &&
288 $volume =~ m@([\\/])@ ;
289 my $sep = $1 ? $1 : '\\' ;
300 my($self,$path,$base) = @_;
301 $base = $self->_cwd() unless defined $base and length $base;
303 for ($path, $base) { $_ = $self->canonpath($_) }
305 my ($path_volume) = $self->splitpath($path, 1);
306 my ($base_volume) = $self->splitpath($base, 1);
308 # Can't relativize across volumes
309 return $path unless $path_volume eq $base_volume;
311 for ($path, $base) { $_ = $self->rel2abs($_) }
313 my $path_directories = ($self->splitpath($path, 1))[1];
314 my $base_directories = ($self->splitpath($base, 1))[1];
316 # Now, remove all leading components that are the same
317 my @pathchunks = $self->splitdir( $path_directories );
318 my @basechunks = $self->splitdir( $base_directories );
320 while ( @pathchunks &&
322 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
328 my $result_dirs = $self->catdir( ($self->updir) x @basechunks, @pathchunks );
330 return $self->canonpath( $self->catpath('', $result_dirs, '') );
335 my ($self,$path,$base ) = @_;
337 if ( ! $self->file_name_is_absolute( $path ) ) {
339 if ( !defined( $base ) || $base eq '' ) {
341 $base = Cwd::getdcwd( ($self->splitpath( $path ))[0] ) if defined &Cwd::getdcwd ;
342 $base = $self->_cwd() unless defined $base ;
344 elsif ( ! $self->file_name_is_absolute( $base ) ) {
345 $base = $self->rel2abs( $base ) ;
348 $base = $self->canonpath( $base ) ;
351 my ( $path_directories, $path_file ) =
352 ($self->splitpath( $path, 1 ))[1,2] ;
354 my ( $base_volume, $base_directories ) =
355 $self->splitpath( $base, 1 ) ;
357 $path = $self->catpath(
359 $self->catdir( $base_directories, $path_directories ),
364 return $self->canonpath( $path ) ;
369 =head2 Note For File::Spec::Win32 Maintainers
371 Novell NetWare inherits its File::Spec behaviour from File::Spec::Win32.
375 Copyright (c) 2004 by the Perl 5 Porters. All rights reserved.
377 This program is free software; you can redistribute it and/or modify
378 it under the same terms as Perl itself.
382 See L<File::Spec> and L<File::Spec::Unix>. This package overrides the
383 implementation of these methods, not the semantics.