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.
53 Since Perl 5.8.0, if running under taint mode, and if the environment
54 variables are tainted, they are not used.
60 return $tmpdir if defined $tmpdir;
62 my @dirlist = (@ENV{qw(TMPDIR TEMP TMP)}, qw(C:/temp /tmp /));
65 if (${"\cTAINT"}) { # Check for taint mode on perl >= 5.8.0
67 @dirlist = grep { ! Scalar::Util::tainted $_ } @dirlist;
71 next unless defined && -d;
75 $tmpdir = '' unless defined $tmpdir;
76 $tmpdir = $self->canonpath($tmpdir);
84 sub file_name_is_absolute {
85 my ($self,$file) = @_;
86 return scalar($file =~ m{^([a-z]:)?[\\/]}is);
91 Concatenate one or more directory names and a filename to form a
92 complete path ending with a filename
99 return $file unless @_;
100 my $dir = $self->catdir(@_);
101 $dir .= "\\" unless substr($dir,-1) eq "\\";
106 my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
107 my @path = split(';',$path);
108 foreach (@path) { $_ = '.' if $_ eq '' }
114 No physical check on the filesystem, but a logical cleanup of a
115 path. On UNIX eliminated successive slashes and successive "/.".
120 my ($self,$path) = @_;
121 $path =~ s/^([a-z]:)/\u$1/s;
123 $path =~ s|([^\\])\\+|$1\\|g; # xx\\\\xx -> xx\xx
124 $path =~ s|(\\\.)+\\|\\|g; # xx\.\.\xx -> xx\xx
125 $path =~ s|^(\.\\)+||s unless $path eq ".\\"; # .\xx -> xx
126 $path =~ s|\\\Z(?!\n)||
127 unless $path =~ m#^([A-Z]:)?\\\Z(?!\n)#s; # xx\ -> xx
133 ($volume,$directories,$file) = File::Spec->splitpath( $path );
134 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
136 Splits a path in to volume, directory, and filename portions. Assumes that
137 the last file is a path unless the path ends in '\\', '\\.', '\\..'
138 or $no_file is true. On Win32 this means that $no_file true makes this return
139 ( $volume, $path, undef ).
141 Separators accepted are \ and /.
143 Volumes can be drive letters or UNC sharenames (\\server\share).
145 The results can be passed to L</catpath> to get back a path equivalent to
146 (usually identical to) the original path.
151 my ($self,$path, $nofile) = @_;
152 my ($volume,$directory,$file) = ('','','');
155 m{^( (?:[a-zA-Z]:|(?:\\\\|//)[^\\/]+[\\/][^\\/]+)? )
163 m{^ ( (?: [a-zA-Z]: |
164 (?:\\\\|//)[^\\/]+[\\/][^\\/]+
167 ( (?:.*[\\\\/](?:\.\.?\Z(?!\n))?)? )
175 return ($volume,$directory,$file);
181 The opposite of L<catdir()|File::Spec/catdir()>.
183 @dirs = File::Spec->splitdir( $directories );
185 $directories must be only the directory portion of the path on systems
186 that have the concept of a volume or that have path syntax that differentiates
187 files from directories.
189 Unlike just splitting the directories on the separator, leading empty and
190 trailing directory entries can be returned, because these are significant
193 File::Spec->splitdir( "/a/b/c" );
197 ( '', 'a', 'b', '', 'c', '' )
202 my ($self,$directories) = @_ ;
204 # split() likes to forget about trailing null fields, so here we
205 # check to be sure that there will not be any before handling the
208 if ( $directories !~ m|[\\/]\Z(?!\n)| ) {
209 return split( m|[\\/]|, $directories );
213 # since there was a trailing separator, add a file name to the end,
214 # then do the split, then replace it with ''.
216 my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
217 $directories[ $#directories ]= '' ;
218 return @directories ;
225 Takes volume, directory and file portions and returns an entire path. Under
226 Unix, $volume is ignored, and this is just like catfile(). On other OSs,
227 the $volume become significant.
232 my ($self,$volume,$directory,$file) = @_;
234 # If it's UNC, make sure the glue separator is there, reusing
235 # whatever separator is first in the $volume
237 if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s &&
238 $directory =~ m@^[^\\/]@s
241 $volume .= $directory ;
243 # If the volume is not just A:, make sure the glue separator is
244 # there, reusing whatever separator is first in the $volume if possible.
245 if ( $volume !~ m@^[a-zA-Z]:\Z(?!\n)@s &&
246 $volume =~ m@[^\\/]\Z(?!\n)@ &&
249 $volume =~ m@([\\/])@ ;
250 my $sep = $1 ? $1 : '\\' ;
261 my($self,$path,$base) = @_;
264 if ( ! $self->file_name_is_absolute( $path ) ) {
265 $path = $self->rel2abs( $path ) ;
268 $path = $self->canonpath( $path ) ;
271 # Figure out the effective $base and clean it up.
272 if ( !defined( $base ) || $base eq '' ) {
275 elsif ( ! $self->file_name_is_absolute( $base ) ) {
276 $base = $self->rel2abs( $base ) ;
279 $base = $self->canonpath( $base ) ;
283 my ( undef, $path_directories, $path_file ) =
284 $self->splitpath( $path, 1 ) ;
286 my $base_directories = ($self->splitpath( $base, 1 ))[1] ;
288 # Now, remove all leading components that are the same
289 my @pathchunks = $self->splitdir( $path_directories );
290 my @basechunks = $self->splitdir( $base_directories );
292 while ( @pathchunks &&
294 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
300 # No need to catdir, we know these are well formed.
301 $path_directories = CORE::join( '\\', @pathchunks );
302 $base_directories = CORE::join( '\\', @basechunks );
304 # $base_directories now contains the directories the resulting relative
305 # path must ascend out of before it can descend to $path_directory. So,
306 # replace all names with $parentDir
308 #FA Need to replace between backslashes...
309 $base_directories =~ s|[^\\]+|..|g ;
311 # Glue the two together, using a separator if necessary, and preventing an
314 #FA Must check that new directories are not empty.
315 if ( $path_directories ne '' && $base_directories ne '' ) {
316 $path_directories = "$base_directories\\$path_directories" ;
318 $path_directories = "$base_directories$path_directories" ;
321 return $self->canonpath(
322 $self->catpath( "", $path_directories, $path_file )
328 my ($self,$path,$base ) = @_;
330 if ( ! $self->file_name_is_absolute( $path ) ) {
332 if ( !defined( $base ) || $base eq '' ) {
335 elsif ( ! $self->file_name_is_absolute( $base ) ) {
336 $base = $self->rel2abs( $base ) ;
339 $base = $self->canonpath( $base ) ;
342 my ( $path_directories, $path_file ) =
343 ($self->splitpath( $path, 1 ))[1,2] ;
345 my ( $base_volume, $base_directories ) =
346 $self->splitpath( $base, 1 ) ;
348 $path = $self->catpath(
350 $self->catdir( $base_directories, $path_directories ),
355 return $self->canonpath( $path ) ;
360 =head2 Note For File::Spec::Win32 Maintainers
362 Novell NetWare inherits its File::Spec behaviour from File::Spec::Win32.