ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/staticperl/perl/lib/File/Spec/Win32.pm
Revision: 1.1
Committed: Thu Jun 30 14:27:12 2005 UTC (21 years, 4 months ago) by root
Branch: MAIN
CVS Tags: PERL-5-8-7, HEAD
Branch point for: PERL
Log Message:
*** empty log message ***

File Contents

# Content
1 package File::Spec::Win32;
2
3 use strict;
4
5 use vars qw(@ISA $VERSION);
6 require File::Spec::Unix;
7
8 $VERSION = '1.5';
9
10 @ISA = qw(File::Spec::Unix);
11
12 =head1 NAME
13
14 File::Spec::Win32 - methods for Win32 file specs
15
16 =head1 SYNOPSIS
17
18 require File::Spec::Win32; # Done internally by File::Spec if needed
19
20 =head1 DESCRIPTION
21
22 See File::Spec::Unix for a documentation of the methods provided
23 there. This package overrides the implementation of these methods, not
24 the semantics.
25
26 =over 4
27
28 =item devnull
29
30 Returns a string representation of the null device.
31
32 =cut
33
34 sub devnull {
35 return "nul";
36 }
37
38 =item tmpdir
39
40 Returns a string representation of the first existing directory
41 from the following list:
42
43 $ENV{TMPDIR}
44 $ENV{TEMP}
45 $ENV{TMP}
46 SYS:/temp
47 C:/temp
48 /tmp
49 /
50
51 The SYS:/temp is preferred in Novell NetWare (the File::Spec::Win32
52 is used also for NetWare).
53
54 Since Perl 5.8.0, if running under taint mode, and if the environment
55 variables are tainted, they are not used.
56
57 =cut
58
59 my $tmpdir;
60 sub tmpdir {
61 return $tmpdir if defined $tmpdir;
62 my $self = shift;
63 $tmpdir = $self->_tmpdir( @ENV{qw(TMPDIR TEMP TMP)},
64 'SYS:/temp',
65 'C:/temp',
66 '/tmp',
67 '/' );
68 }
69
70 sub case_tolerant {
71 return 1;
72 }
73
74 sub file_name_is_absolute {
75 my ($self,$file) = @_;
76 return scalar($file =~ m{^([a-z]:)?[\\/]}is);
77 }
78
79 =item catfile
80
81 Concatenate one or more directory names and a filename to form a
82 complete path ending with a filename
83
84 =cut
85
86 sub catfile {
87 my $self = shift;
88 my $file = $self->canonpath(pop @_);
89 return $file unless @_;
90 my $dir = $self->catdir(@_);
91 $dir .= "\\" unless substr($dir,-1) eq "\\";
92 return $dir.$file;
93 }
94
95 sub catdir {
96 my $self = shift;
97 my @args = @_;
98 foreach (@args) {
99 tr[/][\\];
100 # append a backslash to each argument unless it has one there
101 $_ .= "\\" unless m{\\$};
102 }
103 return $self->canonpath(join('', @args));
104 }
105
106 sub path {
107 my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
108 my @path = split(';',$path);
109 foreach (@path) { $_ = '.' if $_ eq '' }
110 return @path;
111 }
112
113 =item canonpath
114
115 No physical check on the filesystem, but a logical cleanup of a
116 path. On UNIX eliminated successive slashes and successive "/.".
117 On Win32 makes
118
119 dir1\dir2\dir3\..\..\dir4 -> \dir\dir4 and even
120 dir1\dir2\dir3\...\dir4 -> \dir\dir4
121
122 =cut
123
124 sub canonpath {
125 my ($self,$path) = @_;
126 my $orig_path = $path;
127 $path =~ s/^([a-z]:)/\u$1/s;
128 $path =~ s|/|\\|g;
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
142
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;
147 for my $dir (@dirs){
148 $dest = \@path_dirs if $dir eq $self->updir;
149 push @$dest, $dir;
150 }
151 # for each .. in @path_dirs pop one item from
152 # @base_dirs
153 while (my $dir = shift @path_dirs){
154 unless ($dir eq $self->updir){
155 unshift @path_dirs, $dir;
156 last;
157 }
158 pop @base_dirs;
159 }
160 $path = $self->catpath(
161 $vol,
162 $self->catdir(@base_dirs, @path_dirs),
163 $file
164 );
165 return $path;
166 }
167
168 =item splitpath
169
170 ($volume,$directories,$file) = File::Spec->splitpath( $path );
171 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
172
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, '' ).
177
178 Separators accepted are \ and /.
179
180 Volumes can be drive letters or UNC sharenames (\\server\share).
181
182 The results can be passed to L</catpath> to get back a path equivalent to
183 (usually identical to) the original path.
184
185 =cut
186
187 sub splitpath {
188 my ($self,$path, $nofile) = @_;
189 my ($volume,$directory,$file) = ('','','');
190 if ( $nofile ) {
191 $path =~
192 m{^( (?:[a-zA-Z]:|(?:\\\\|//)[^\\/]+[\\/][^\\/]+)? )
193 (.*)
194 }xs;
195 $volume = $1;
196 $directory = $2;
197 }
198 else {
199 $path =~
200 m{^ ( (?: [a-zA-Z]: |
201 (?:\\\\|//)[^\\/]+[\\/][^\\/]+
202 )?
203 )
204 ( (?:.*[\\/](?:\.\.?\Z(?!\n))?)? )
205 (.*)
206 }xs;
207 $volume = $1;
208 $directory = $2;
209 $file = $3;
210 }
211
212 return ($volume,$directory,$file);
213 }
214
215
216 =item splitdir
217
218 The opposite of L<catdir()|File::Spec/catdir()>.
219
220 @dirs = File::Spec->splitdir( $directories );
221
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.
225
226 Unlike just splitting the directories on the separator, leading empty and
227 trailing directory entries can be returned, because these are significant
228 on some OSs. So,
229
230 File::Spec->splitdir( "/a/b/c" );
231
232 Yields:
233
234 ( '', 'a', 'b', '', 'c', '' )
235
236 =cut
237
238 sub splitdir {
239 my ($self,$directories) = @_ ;
240 #
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
243 # simple case.
244 #
245 if ( $directories !~ m|[\\/]\Z(?!\n)| ) {
246 return split( m|[\\/]|, $directories );
247 }
248 else {
249 #
250 # since there was a trailing separator, add a file name to the end,
251 # then do the split, then replace it with ''.
252 #
253 my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
254 $directories[ $#directories ]= '' ;
255 return @directories ;
256 }
257 }
258
259
260 =item catpath
261
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.
265
266 =cut
267
268 sub catpath {
269 my ($self,$volume,$directory,$file) = @_;
270
271 # If it's UNC, make sure the glue separator is there, reusing
272 # whatever separator is first in the $volume
273 $volume .= $1
274 if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s &&
275 $directory =~ m@^[^\\/]@s
276 ) ;
277
278 $volume .= $directory ;
279
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)@ &&
284 $file =~ m@[^\\/]@
285 ) {
286 $volume =~ m@([\\/])@ ;
287 my $sep = $1 ? $1 : '\\' ;
288 $volume .= $sep ;
289 }
290
291 $volume .= $file ;
292
293 return $volume ;
294 }
295
296
297 sub abs2rel {
298 my($self,$path,$base) = @_;
299 $base = $self->_cwd() unless defined $base and length $base;
300
301 for ($path, $base) { $_ = $self->canonpath($_) }
302
303 my ($path_volume) = $self->splitpath($path, 1);
304 my ($base_volume) = $self->splitpath($base, 1);
305
306 # Can't relativize across volumes
307 return $path unless $path_volume eq $base_volume;
308
309 for ($path, $base) { $_ = $self->rel2abs($_) }
310
311 my $path_directories = ($self->splitpath($path, 1))[1];
312 my $base_directories = ($self->splitpath($base, 1))[1];
313
314 # Now, remove all leading components that are the same
315 my @pathchunks = $self->splitdir( $path_directories );
316 my @basechunks = $self->splitdir( $base_directories );
317
318 while ( @pathchunks &&
319 @basechunks &&
320 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
321 ) {
322 shift @pathchunks ;
323 shift @basechunks ;
324 }
325
326 my $result_dirs = $self->catdir( ($self->updir) x @basechunks, @pathchunks );
327
328 return $self->canonpath( $self->catpath('', $result_dirs, '') );
329 }
330
331
332 sub rel2abs {
333 my ($self,$path,$base ) = @_;
334
335 if ( ! $self->file_name_is_absolute( $path ) ) {
336
337 if ( !defined( $base ) || $base eq '' ) {
338 require Cwd ;
339 $base = Cwd::getdcwd( ($self->splitpath( $path ))[0] ) if defined &Cwd::getdcwd ;
340 $base = $self->_cwd() unless defined $base ;
341 }
342 elsif ( ! $self->file_name_is_absolute( $base ) ) {
343 $base = $self->rel2abs( $base ) ;
344 }
345 else {
346 $base = $self->canonpath( $base ) ;
347 }
348
349 my ( $path_directories, $path_file ) =
350 ($self->splitpath( $path, 1 ))[1,2] ;
351
352 my ( $base_volume, $base_directories ) =
353 $self->splitpath( $base, 1 ) ;
354
355 $path = $self->catpath(
356 $base_volume,
357 $self->catdir( $base_directories, $path_directories ),
358 $path_file
359 ) ;
360 }
361
362 return $self->canonpath( $path ) ;
363 }
364
365 =back
366
367 =head2 Note For File::Spec::Win32 Maintainers
368
369 Novell NetWare inherits its File::Spec behaviour from File::Spec::Win32.
370
371 =head1 COPYRIGHT
372
373 Copyright (c) 2004 by the Perl 5 Porters. All rights reserved.
374
375 This program is free software; you can redistribute it and/or modify
376 it under the same terms as Perl itself.
377
378 =head1 SEE ALSO
379
380 See L<File::Spec> and L<File::Spec::Unix>. This package overrides the
381 implementation of these methods, not the semantics.
382
383 =cut
384
385 1;