Use the base class cwd() method.
[p5sagit/p5-mst-13.2.git] / lib / File / Spec / OS2.pm
CommitLineData
270d1e39 1package File::Spec::OS2;
2
270d1e39 3use strict;
b4296952 4use vars qw(@ISA $VERSION);
cbc7acb0 5require File::Spec::Unix;
b4296952 6
07824bd1 7$VERSION = '1.2';
b4296952 8
270d1e39 9@ISA = qw(File::Spec::Unix);
10
cbc7acb0 11sub devnull {
12 return "/dev/nul";
13}
270d1e39 14
46726cbe 15sub case_tolerant {
16 return 1;
17}
18
270d1e39 19sub file_name_is_absolute {
cbc7acb0 20 my ($self,$file) = @_;
1b1e14d3 21 return scalar($file =~ m{^([a-z]:)?[\\/]}is);
270d1e39 22}
23
24sub path {
270d1e39 25 my $path = $ENV{PATH};
26 $path =~ s:\\:/:g;
cbc7acb0 27 my @path = split(';',$path);
28 foreach (@path) { $_ = '.' if $_ eq '' }
29 return @path;
270d1e39 30}
31
07824bd1 32=pod
33
34=item tmpdir
35
36Returns a string representation of the first existing directory
37from the following list:
38
39 $ENV{TMPDIR}
40 $ENV{TEMP}
41 $ENV{TMP}
42 /tmp
43 /
44
45Since Perl 5.8.0, if running under taint mode, and if the environment
46variables are tainted, they are not used.
47
48=cut
49
cbc7acb0 50my $tmpdir;
51sub tmpdir {
52 return $tmpdir if defined $tmpdir;
53 my $self = shift;
07824bd1 54 $tmpdir = $self->_tmpdir( @ENV{qw(TMPDIR TEMP TMP)},
55 '/tmp',
56 '/' );
99804bbb 57}
58
f1e20921 59=item canonpath
60
61No physical check on the filesystem, but a logical cleanup of a
62path. On UNIX eliminated successive slashes and successive "/.".
63
64=cut
65
66sub canonpath {
67 my ($self,$path) = @_;
68 $path =~ s/^([a-z]:)/\l$1/s;
69 $path =~ s|\\|/|g;
70 $path =~ s|([^/])/+|$1/|g; # xx////xx -> xx/xx
71 $path =~ s|(/\.)+/|/|g; # xx/././xx -> xx/xx
72 $path =~ s|^(\./)+(?=[^/])||s; # ./xx -> xx
73 $path =~ s|/\Z(?!\n)||
74 unless $path =~ m#^([a-z]:)?/\Z(?!\n)#si;# xx/ -> xx
75 return $path;
76}
77
78=item splitpath
79
80 ($volume,$directories,$file) = File::Spec->splitpath( $path );
81 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
82
40d020d9 83Splits a path into volume, directory, and filename portions. Assumes that
f1e20921 84the last file is a path unless the path ends in '/', '/.', '/..'
85or $no_file is true. On Win32 this means that $no_file true makes this return
40d020d9 86( $volume, $path, '' ).
f1e20921 87
88Separators accepted are \ and /.
89
90Volumes can be drive letters or UNC sharenames (\\server\share).
91
92The results can be passed to L</catpath> to get back a path equivalent to
93(usually identical to) the original path.
94
95=cut
96
97sub splitpath {
98 my ($self,$path, $nofile) = @_;
99 my ($volume,$directory,$file) = ('','','');
100 if ( $nofile ) {
101 $path =~
102 m{^( (?:[a-zA-Z]:|(?:\\\\|//)[^\\/]+[\\/][^\\/]+)? )
103 (.*)
104 }xs;
105 $volume = $1;
106 $directory = $2;
107 }
108 else {
109 $path =~
110 m{^ ( (?: [a-zA-Z]: |
111 (?:\\\\|//)[^\\/]+[\\/][^\\/]+
112 )?
113 )
114 ( (?:.*[\\\\/](?:\.\.?\Z(?!\n))?)? )
115 (.*)
116 }xs;
117 $volume = $1;
118 $directory = $2;
119 $file = $3;
120 }
121
122 return ($volume,$directory,$file);
123}
124
125
126=item splitdir
127
128The opposite of L<catdir()|File::Spec/catdir()>.
129
130 @dirs = File::Spec->splitdir( $directories );
131
132$directories must be only the directory portion of the path on systems
133that have the concept of a volume or that have path syntax that differentiates
134files from directories.
135
136Unlike just splitting the directories on the separator, leading empty and
137trailing directory entries can be returned, because these are significant
138on some OSs. So,
139
140 File::Spec->splitdir( "/a/b//c/" );
141
142Yields:
143
144 ( '', 'a', 'b', '', 'c', '' )
145
146=cut
147
148sub splitdir {
149 my ($self,$directories) = @_ ;
150 split m|[\\/]|, $directories, -1;
151}
152
153
154=item catpath
155
156Takes volume, directory and file portions and returns an entire path. Under
157Unix, $volume is ignored, and this is just like catfile(). On other OSs,
158the $volume become significant.
159
160=cut
161
162sub catpath {
163 my ($self,$volume,$directory,$file) = @_;
164
165 # If it's UNC, make sure the glue separator is there, reusing
166 # whatever separator is first in the $volume
167 $volume .= $1
168 if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s &&
169 $directory =~ m@^[^\\/]@s
170 ) ;
171
172 $volume .= $directory ;
173
174 # If the volume is not just A:, make sure the glue separator is
175 # there, reusing whatever separator is first in the $volume if possible.
176 if ( $volume !~ m@^[a-zA-Z]:\Z(?!\n)@s &&
177 $volume =~ m@[^\\/]\Z(?!\n)@ &&
178 $file =~ m@[^\\/]@
179 ) {
180 $volume =~ m@([\\/])@ ;
181 my $sep = $1 ? $1 : '/' ;
182 $volume .= $sep ;
183 }
184
185 $volume .= $file ;
186
187 return $volume ;
188}
189
190
191sub abs2rel {
192 my($self,$path,$base) = @_;
193
194 # Clean up $path
195 if ( ! $self->file_name_is_absolute( $path ) ) {
196 $path = $self->rel2abs( $path ) ;
197 } else {
198 $path = $self->canonpath( $path ) ;
199 }
200
201 # Figure out the effective $base and clean it up.
202 if ( !defined( $base ) || $base eq '' ) {
72f15715 203 require Cwd;
f1e20921 204 $base = Cwd::sys_cwd() ;
205 } elsif ( ! $self->file_name_is_absolute( $base ) ) {
206 $base = $self->rel2abs( $base ) ;
207 } else {
208 $base = $self->canonpath( $base ) ;
209 }
210
211 # Split up paths
212 my ( undef, $path_directories, $path_file ) =
213 $self->splitpath( $path, 1 ) ;
214
215 my $base_directories = ($self->splitpath( $base, 1 ))[1] ;
216
217 # Now, remove all leading components that are the same
218 my @pathchunks = $self->splitdir( $path_directories );
219 my @basechunks = $self->splitdir( $base_directories );
220
221 while ( @pathchunks &&
222 @basechunks &&
223 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
224 ) {
225 shift @pathchunks ;
226 shift @basechunks ;
227 }
228
229 # No need to catdir, we know these are well formed.
230 $path_directories = CORE::join( '/', @pathchunks );
231 $base_directories = CORE::join( '/', @basechunks );
232
233 # $base_directories now contains the directories the resulting relative
234 # path must ascend out of before it can descend to $path_directory. So,
235 # replace all names with $parentDir
236
237 #FA Need to replace between backslashes...
238 $base_directories =~ s|[^\\/]+|..|g ;
239
240 # Glue the two together, using a separator if necessary, and preventing an
241 # empty result.
242
243 #FA Must check that new directories are not empty.
244 if ( $path_directories ne '' && $base_directories ne '' ) {
245 $path_directories = "$base_directories/$path_directories" ;
246 } else {
247 $path_directories = "$base_directories$path_directories" ;
248 }
249
250 return $self->canonpath(
251 $self->catpath( "", $path_directories, $path_file )
252 ) ;
253}
254
255
256sub rel2abs {
257 my ($self,$path,$base ) = @_;
258
259 if ( ! $self->file_name_is_absolute( $path ) ) {
260
261 if ( !defined( $base ) || $base eq '' ) {
72f15715 262 require Cwd;
f1e20921 263 $base = Cwd::sys_cwd() ;
264 }
265 elsif ( ! $self->file_name_is_absolute( $base ) ) {
266 $base = $self->rel2abs( $base ) ;
267 }
268 else {
269 $base = $self->canonpath( $base ) ;
270 }
271
272 my ( $path_directories, $path_file ) =
273 ($self->splitpath( $path, 1 ))[1,2] ;
274
275 my ( $base_volume, $base_directories ) =
276 $self->splitpath( $base, 1 ) ;
277
278 $path = $self->catpath(
279 $base_volume,
280 $self->catdir( $base_directories, $path_directories ),
281 $path_file
282 ) ;
283 }
284
285 return $self->canonpath( $path ) ;
286}
287
270d1e39 2881;
289__END__
290
291=head1 NAME
292
293File::Spec::OS2 - methods for OS/2 file specs
294
295=head1 SYNOPSIS
296
cbc7acb0 297 require File::Spec::OS2; # Done internally by File::Spec if needed
270d1e39 298
299=head1 DESCRIPTION
300
72f15715 301See L<File::Spec> and L<File::Spec::Unix>. This package overrides the
302implementation of these methods, not the semantics.