1 package File::Spec::Win32;
6 use vars qw(@ISA $VERSION);
7 require File::Spec::Unix;
11 @ISA = qw(File::Spec::Unix);
15 File::Spec::Win32 - methods for Win32 file specs
19 require File::Spec::Win32; # Done internally by File::Spec if needed
23 See File::Spec::Unix for a documentation of the methods provided
24 there. This package overrides the implementation of these methods, not
31 Returns a string representation of the null device.
41 Returns a string representation of the first existing directory
42 from the following list:
52 The SYS:/temp is preferred in Novell NetWare (the File::Spec::Win32
53 is used also for NetWare).
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)},
75 sub file_name_is_absolute {
76 my ($self,$file) = @_;
77 return scalar($file =~ m{^([a-z]:)?[\\/]}is);
82 Concatenate one or more directory names and a filename to form a
83 complete path ending with a filename
89 my $file = $self->canonpath(pop @_);
90 return $file unless @_;
91 my $dir = $self->catdir(@_);
92 $dir .= "\\" unless substr($dir,-1) eq "\\";
97 my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
98 my @path = split(';',$path);
99 foreach (@path) { $_ = '.' if $_ eq '' }
105 No physical check on the filesystem, but a logical cleanup of a
106 path. On UNIX eliminated successive slashes and successive "/.".
109 dir1\dir2\dir3\..\..\dir4 -> \dir\dir4 and even
110 dir1\dir2\dir3\...\dir4 -> \dir\dir4
115 my ($self,$path) = @_;
116 my $orig_path = $path;
117 $path =~ s/^([a-z]:)/\u$1/s;
119 $path =~ s|([^\\])\\+|$1\\|g; # xx\\\\xx -> xx\xx
120 $path =~ s|(\\\.)+\\|\\|g; # xx\.\.\xx -> xx\xx
121 $path =~ s|^(\.\\)+||s unless $path eq ".\\"; # .\xx -> xx
122 $path =~ s|\\\Z(?!\n)||
123 unless $path =~ m{^([A-Z]:)?\\\Z(?!\n)}s; # xx\ -> xx
124 # xx1/xx2/xx3/../../xx -> xx1/xx
125 $path =~ s|\\\.\.\.\\|\\\.\.\\\.\.\\|g; # \...\ is 2 levels up
126 $path =~ s|^\.\.\.\\|\.\.\\\.\.\\|g; # ...\ is 2 levels up
127 return $path if $path =~ m|^\.\.|; # skip relative paths
128 return $path unless $path =~ /\.\./; # too few .'s to cleanup
129 return $path if $path =~ /\.\.\.\./; # too many .'s to cleanup
130 return $path if $orig_path =~ m|^\Q/../\E|
131 and $orig_path =~ m|\/$|; # don't do /../dirs/ when called
132 # from rel2abs() for ../dirs/
133 1 while $path =~ s{^\\\.\.}{}; # \..\xx -> \xx
135 my ($vol,$dirs,$file) = $self->splitpath($path);
136 my @dirs = $self->splitdir($dirs);
137 my (@base_dirs, @path_dirs);
138 my $dest = \@base_dirs;
140 $dest = \@path_dirs if $dir eq $self->updir;
143 # for each .. in @path_dirs pop one item from
145 while (my $dir = shift @path_dirs){
146 unless ($dir eq $self->updir){
147 unshift @path_dirs, $dir;
152 $path = $self->catpath(
154 $self->catdir(@base_dirs, @path_dirs),
162 ($volume,$directories,$file) = File::Spec->splitpath( $path );
163 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
165 Splits a path into volume, directory, and filename portions. Assumes that
166 the last file is a path unless the path ends in '\\', '\\.', '\\..'
167 or $no_file is true. On Win32 this means that $no_file true makes this return
168 ( $volume, $path, '' ).
170 Separators accepted are \ and /.
172 Volumes can be drive letters or UNC sharenames (\\server\share).
174 The results can be passed to L</catpath> to get back a path equivalent to
175 (usually identical to) the original path.
180 my ($self,$path, $nofile) = @_;
181 my ($volume,$directory,$file) = ('','','');
184 m{^( (?:[a-zA-Z]:|(?:\\\\|//)[^\\/]+[\\/][^\\/]+)? )
192 m{^ ( (?: [a-zA-Z]: |
193 (?:\\\\|//)[^\\/]+[\\/][^\\/]+
196 ( (?:.*[\\\\/](?:\.\.?\Z(?!\n))?)? )
204 return ($volume,$directory,$file);
210 The opposite of L<catdir()|File::Spec/catdir()>.
212 @dirs = File::Spec->splitdir( $directories );
214 $directories must be only the directory portion of the path on systems
215 that have the concept of a volume or that have path syntax that differentiates
216 files from directories.
218 Unlike just splitting the directories on the separator, leading empty and
219 trailing directory entries can be returned, because these are significant
222 File::Spec->splitdir( "/a/b/c" );
226 ( '', 'a', 'b', '', 'c', '' )
231 my ($self,$directories) = @_ ;
233 # split() likes to forget about trailing null fields, so here we
234 # check to be sure that there will not be any before handling the
237 if ( $directories !~ m|[\\/]\Z(?!\n)| ) {
238 return split( m|[\\/]|, $directories );
242 # since there was a trailing separator, add a file name to the end,
243 # then do the split, then replace it with ''.
245 my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
246 $directories[ $#directories ]= '' ;
247 return @directories ;
254 Takes volume, directory and file portions and returns an entire path. Under
255 Unix, $volume is ignored, and this is just like catfile(). On other OSs,
256 the $volume become significant.
261 my ($self,$volume,$directory,$file) = @_;
263 # If it's UNC, make sure the glue separator is there, reusing
264 # whatever separator is first in the $volume
266 if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s &&
267 $directory =~ m@^[^\\/]@s
270 $volume .= $directory ;
272 # If the volume is not just A:, make sure the glue separator is
273 # there, reusing whatever separator is first in the $volume if possible.
274 if ( $volume !~ m@^[a-zA-Z]:\Z(?!\n)@s &&
275 $volume =~ m@[^\\/]\Z(?!\n)@ &&
278 $volume =~ m@([\\/])@ ;
279 my $sep = $1 ? $1 : '\\' ;
290 my($self,$path,$base) = @_;
291 $base = $self->cwd() unless defined $base and length $base;
294 $_ = $self->canonpath($self->rel2abs($_));
296 my ($path_volume, $path_directories) = $self->splitpath($path, 1) ;
297 my ($base_volume, $base_directories) = $self->splitpath($base, 1);
299 if ($path_volume and not $base_volume) {
300 ($base_volume) = $self->splitpath($self->cwd);
303 # Can't relativize across volumes
304 return $path unless $path_volume eq $base_volume;
306 # Now, remove all leading components that are the same
307 my @pathchunks = $self->splitdir( $path_directories );
308 my @basechunks = $self->splitdir( $base_directories );
310 while ( @pathchunks &&
312 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
318 my $result_dirs = $self->catdir( ($self->updir) x @basechunks, @pathchunks );
320 return $self->canonpath( $self->catpath('', $result_dirs, '') );
325 my ($self,$path,$base ) = @_;
327 if ( ! $self->file_name_is_absolute( $path ) ) {
329 if ( !defined( $base ) || $base eq '' ) {
330 $base = $self->cwd() ;
332 elsif ( ! $self->file_name_is_absolute( $base ) ) {
333 $base = $self->rel2abs( $base ) ;
336 $base = $self->canonpath( $base ) ;
339 my ( $path_directories, $path_file ) =
340 ($self->splitpath( $path, 1 ))[1,2] ;
342 my ( $base_volume, $base_directories ) =
343 $self->splitpath( $base, 1 ) ;
345 $path = $self->catpath(
347 $self->catdir( $base_directories, $path_directories ),
352 return $self->canonpath( $path ) ;
357 =head2 Note For File::Spec::Win32 Maintainers
359 Novell NetWare inherits its File::Spec behaviour from File::Spec::Win32.