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:
51 The SYS:/temp is preferred in Novell NetWare (the File::Spec::Win32
52 is used also for NetWare).
54 Since Perl 5.8.0, if running under taint mode, and if the environment
55 variables are tainted, they are not used.
61 return $tmpdir if defined $tmpdir;
63 $tmpdir = $self->_tmpdir( @ENV{qw(TMPDIR TEMP TMP)},
74 sub file_name_is_absolute {
75 my ($self,$file) = @_;
76 return scalar($file =~ m{^([a-z]:)?[\\/]}is);
81 Concatenate one or more directory names and a filename to form a
82 complete path ending with a filename
88 my $file = $self->canonpath(pop @_);
89 return $file unless @_;
90 my $dir = $self->catdir(@_);
91 $dir .= "\\" unless substr($dir,-1) eq "\\";
100 # append a backslash to each argument unless it has one there
101 $_ .= "\\" unless m{\\$};
103 return $self->canonpath(join('', @args));
107 my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
108 my @path = split(';',$path);
109 foreach (@path) { $_ = '.' if $_ eq '' }
115 No physical check on the filesystem, but a logical cleanup of a
116 path. On UNIX eliminated successive slashes and successive "/.".
119 dir1\dir2\dir3\..\..\dir4 -> \dir\dir4 and even
120 dir1\dir2\dir3\...\dir4 -> \dir\dir4
125 my ($self,$path) = @_;
126 my $orig_path = $path;
127 $path =~ s/^([a-z]:)/\u$1/s;
129 $path =~ s|([^\\])\\+|$1\\|g; # xx\\\\xx -> xx\xx
130 $path =~ s|(\\\.)+\\|\\|g; # xx\.\.\xx -> xx\xx
131 $path =~ s|^(\.\\)+||s unless $path eq ".\\"; # .\xx -> xx
132 $path =~ s|\\\Z(?!\n)||
133 unless $path =~ m{^([A-Z]:)?\\\Z(?!\n)}s; # xx\ -> xx
134 # xx1/xx2/xx3/../../xx -> xx1/xx
135 $path =~ s|\\\.\.\.\\|\\\.\.\\\.\.\\|g; # \...\ is 2 levels up
136 $path =~ s|^\.\.\.\\|\.\.\\\.\.\\|g; # ...\ is 2 levels up
137 return $path if $path =~ m|^\.\.|; # skip relative paths
138 return $path unless $path =~ /\.\./; # too few .'s to cleanup
139 return $path if $path =~ /\.\.\.\./; # too many .'s to cleanup
140 $path =~ s{^\\\.\.$}{\\}; # \.. -> \
141 1 while $path =~ s{^\\\.\.}{}; # \..\xx -> \xx
143 my ($vol,$dirs,$file) = $self->splitpath($path);
144 my @dirs = $self->splitdir($dirs);
145 my (@base_dirs, @path_dirs);
146 my $dest = \@base_dirs;
148 $dest = \@path_dirs if $dir eq $self->updir;
151 # for each .. in @path_dirs pop one item from
153 while (my $dir = shift @path_dirs){
154 unless ($dir eq $self->updir){
155 unshift @path_dirs, $dir;
160 $path = $self->catpath(
162 $self->catdir(@base_dirs, @path_dirs),
170 ($volume,$directories,$file) = File::Spec->splitpath( $path );
171 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
173 Splits a path into volume, directory, and filename portions. Assumes that
174 the last file is a path unless the path ends in '\\', '\\.', '\\..'
175 or $no_file is true. On Win32 this means that $no_file true makes this return
176 ( $volume, $path, '' ).
178 Separators accepted are \ and /.
180 Volumes can be drive letters or UNC sharenames (\\server\share).
182 The results can be passed to L</catpath> to get back a path equivalent to
183 (usually identical to) the original path.
188 my ($self,$path, $nofile) = @_;
189 my ($volume,$directory,$file) = ('','','');
192 m{^( (?:[a-zA-Z]:|(?:\\\\|//)[^\\/]+[\\/][^\\/]+)? )
200 m{^ ( (?: [a-zA-Z]: |
201 (?:\\\\|//)[^\\/]+[\\/][^\\/]+
204 ( (?:.*[\\/](?:\.\.?\Z(?!\n))?)? )
212 return ($volume,$directory,$file);
218 The opposite of L<catdir()|File::Spec/catdir()>.
220 @dirs = File::Spec->splitdir( $directories );
222 $directories must be only the directory portion of the path on systems
223 that have the concept of a volume or that have path syntax that differentiates
224 files from directories.
226 Unlike just splitting the directories on the separator, leading empty and
227 trailing directory entries can be returned, because these are significant
230 File::Spec->splitdir( "/a/b/c" );
234 ( '', 'a', 'b', '', 'c', '' )
239 my ($self,$directories) = @_ ;
241 # split() likes to forget about trailing null fields, so here we
242 # check to be sure that there will not be any before handling the
245 if ( $directories !~ m|[\\/]\Z(?!\n)| ) {
246 return split( m|[\\/]|, $directories );
250 # since there was a trailing separator, add a file name to the end,
251 # then do the split, then replace it with ''.
253 my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
254 $directories[ $#directories ]= '' ;
255 return @directories ;
262 Takes volume, directory and file portions and returns an entire path. Under
263 Unix, $volume is ignored, and this is just like catfile(). On other OSs,
264 the $volume become significant.
269 my ($self,$volume,$directory,$file) = @_;
271 # If it's UNC, make sure the glue separator is there, reusing
272 # whatever separator is first in the $volume
274 if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s &&
275 $directory =~ m@^[^\\/]@s
278 $volume .= $directory ;
280 # If the volume is not just A:, make sure the glue separator is
281 # there, reusing whatever separator is first in the $volume if possible.
282 if ( $volume !~ m@^[a-zA-Z]:\Z(?!\n)@s &&
283 $volume =~ m@[^\\/]\Z(?!\n)@ &&
286 $volume =~ m@([\\/])@ ;
287 my $sep = $1 ? $1 : '\\' ;
298 my($self,$path,$base) = @_;
299 $base = $self->_cwd() unless defined $base and length $base;
301 for ($path, $base) { $_ = $self->canonpath($_) }
303 my ($path_volume) = $self->splitpath($path, 1);
304 my ($base_volume) = $self->splitpath($base, 1);
306 # Can't relativize across volumes
307 return $path unless $path_volume eq $base_volume;
309 for ($path, $base) { $_ = $self->rel2abs($_) }
311 my $path_directories = ($self->splitpath($path, 1))[1];
312 my $base_directories = ($self->splitpath($base, 1))[1];
314 # Now, remove all leading components that are the same
315 my @pathchunks = $self->splitdir( $path_directories );
316 my @basechunks = $self->splitdir( $base_directories );
318 while ( @pathchunks &&
320 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
326 my $result_dirs = $self->catdir( ($self->updir) x @basechunks, @pathchunks );
328 return $self->canonpath( $self->catpath('', $result_dirs, '') );
333 my ($self,$path,$base ) = @_;
335 if ( ! $self->file_name_is_absolute( $path ) ) {
337 if ( !defined( $base ) || $base eq '' ) {
339 $base = Cwd::getdcwd( ($self->splitpath( $path ))[0] ) if defined &Cwd::getdcwd ;
340 $base = $self->_cwd() unless defined $base ;
342 elsif ( ! $self->file_name_is_absolute( $base ) ) {
343 $base = $self->rel2abs( $base ) ;
346 $base = $self->canonpath( $base ) ;
349 my ( $path_directories, $path_file ) =
350 ($self->splitpath( $path, 1 ))[1,2] ;
352 my ( $base_volume, $base_directories ) =
353 $self->splitpath( $base, 1 ) ;
355 $path = $self->catpath(
357 $self->catdir( $base_directories, $path_directories ),
362 return $self->canonpath( $path ) ;
367 =head2 Note For File::Spec::Win32 Maintainers
369 Novell NetWare inherits its File::Spec behaviour from File::Spec::Win32.
373 See L<File::Spec> and L<File::Spec::Unix>. This package overrides the
374 implementation of these methods, not the semantics.