This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
File::Temp 0.14 from Tim Jenness, now with OO interface.
[perl5.git] / lib / File / Spec / OS2.pm
CommitLineData
270d1e39
GS
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
GS
9@ISA = qw(File::Spec::Unix);
10
cbc7acb0
JD
11sub devnull {
12 return "/dev/nul";
13}
270d1e39 14
46726cbe
CB
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
GS
22}
23
24sub path {
270d1e39
GS
25 my $path = $ENV{PATH};
26 $path =~ s:\\:/:g;
cbc7acb0
JD
27 my @path = split(';',$path);
28 foreach (@path) { $_ = '.' if $_ eq '' }
29 return @path;
270d1e39
GS
30}
31
07824bd1
JH
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
JD
50my $tmpdir;
51sub tmpdir {
52 return $tmpdir if defined $tmpdir;
53 my $self = shift;
07824bd1
JH
54 $tmpdir = $self->_tmpdir( @ENV{qw(TMPDIR TEMP TMP)},
55 '/tmp',
56 '/' );
99804bbb
GS
57}
58
f1e20921
IZ
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
IZ
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
IZ
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 '' ) {
203 $base = Cwd::sys_cwd() ;
204 } elsif ( ! $self->file_name_is_absolute( $base ) ) {
205 $base = $self->rel2abs( $base ) ;
206 } else {
207 $base = $self->canonpath( $base ) ;
208 }
209
210 # Split up paths
211 my ( undef, $path_directories, $path_file ) =
212 $self->splitpath( $path, 1 ) ;
213
214 my $base_directories = ($self->splitpath( $base, 1 ))[1] ;
215
216 # Now, remove all leading components that are the same
217 my @pathchunks = $self->splitdir( $path_directories );
218 my @basechunks = $self->splitdir( $base_directories );
219
220 while ( @pathchunks &&
221 @basechunks &&
222 lc( $pathchunks[0] ) eq lc( $basechunks[0] )
223 ) {
224 shift @pathchunks ;
225 shift @basechunks ;
226 }
227
228 # No need to catdir, we know these are well formed.
229 $path_directories = CORE::join( '/', @pathchunks );
230 $base_directories = CORE::join( '/', @basechunks );
231
232 # $base_directories now contains the directories the resulting relative
233 # path must ascend out of before it can descend to $path_directory. So,
234 # replace all names with $parentDir
235
236 #FA Need to replace between backslashes...
237 $base_directories =~ s|[^\\/]+|..|g ;
238
239 # Glue the two together, using a separator if necessary, and preventing an
240 # empty result.
241
242 #FA Must check that new directories are not empty.
243 if ( $path_directories ne '' && $base_directories ne '' ) {
244 $path_directories = "$base_directories/$path_directories" ;
245 } else {
246 $path_directories = "$base_directories$path_directories" ;
247 }
248
249 return $self->canonpath(
250 $self->catpath( "", $path_directories, $path_file )
251 ) ;
252}
253
254
255sub rel2abs {
256 my ($self,$path,$base ) = @_;
257
258 if ( ! $self->file_name_is_absolute( $path ) ) {
259
260 if ( !defined( $base ) || $base eq '' ) {
261 $base = Cwd::sys_cwd() ;
262 }
263 elsif ( ! $self->file_name_is_absolute( $base ) ) {
264 $base = $self->rel2abs( $base ) ;
265 }
266 else {
267 $base = $self->canonpath( $base ) ;
268 }
269
270 my ( $path_directories, $path_file ) =
271 ($self->splitpath( $path, 1 ))[1,2] ;
272
273 my ( $base_volume, $base_directories ) =
274 $self->splitpath( $base, 1 ) ;
275
276 $path = $self->catpath(
277 $base_volume,
278 $self->catdir( $base_directories, $path_directories ),
279 $path_file
280 ) ;
281 }
282
283 return $self->canonpath( $path ) ;
284}
285
270d1e39
GS
2861;
287__END__
288
289=head1 NAME
290
291File::Spec::OS2 - methods for OS/2 file specs
292
293=head1 SYNOPSIS
294
cbc7acb0 295 require File::Spec::OS2; # Done internally by File::Spec if needed
270d1e39
GS
296
297=head1 DESCRIPTION
298
299See File::Spec::Unix for a documentation of the methods provided
300there. This package overrides the implementation of these methods, not
301the semantics.