source: trunk/third/perl/lib/File/Spec/Mac.pm @ 17035

Revision 17035, 8.7 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17034, which included commits to RCS files with non-trunk default branches.
Line 
1package File::Spec::Mac;
2
3use strict;
4use vars qw(@ISA $VERSION);
5require File::Spec::Unix;
6
7$VERSION = '1.2';
8
9@ISA = qw(File::Spec::Unix);
10
11=head1 NAME
12
13File::Spec::Mac - File::Spec for MacOS
14
15=head1 SYNOPSIS
16
17 require File::Spec::Mac; # Done internally by File::Spec if needed
18
19=head1 DESCRIPTION
20
21Methods for manipulating file specifications.
22
23=head1 METHODS
24
25=over 2
26
27=item canonpath
28
29On MacOS, there's nothing to be done.  Returns what it's given.
30
31=cut
32
33sub canonpath {
34    my ($self,$path) = @_;
35    return $path;
36}
37
38=item catdir
39
40Concatenate two or more directory names to form a complete path ending with
41a directory.  Put a trailing : on the end of the complete path if there
42isn't one, because that's what's done in MacPerl's environment.
43
44The fundamental requirement of this routine is that
45
46          File::Spec->catdir(split(":",$path)) eq $path
47
48But because of the nature of Macintosh paths, some additional
49possibilities are allowed to make using this routine give reasonable results
50for some common situations.  Here are the rules that are used.  Each
51argument has its trailing ":" removed.  Each argument, except the first,
52has its leading ":" removed.  They are then joined together by a ":".
53
54So
55
56          File::Spec->catdir("a","b") = "a:b:"
57          File::Spec->catdir("a:",":b") = "a:b:"
58          File::Spec->catdir("a:","b") = "a:b:"
59          File::Spec->catdir("a",":b") = "a:b"
60          File::Spec->catdir("a","","b") = "a::b"
61
62etc.
63
64To get a relative path (one beginning with :), begin the first argument with :
65or put a "" as the first argument.
66
67If you don't want to worry about these rules, never allow a ":" on the ends
68of any of the arguments except at the beginning of the first.
69
70Under MacPerl, there is an additional ambiguity.  Does the user intend that
71
72          File::Spec->catfile("LWP","Protocol","http.pm")
73
74be relative or absolute?  There's no way of telling except by checking for the
75existence of LWP: or :LWP, and even there he may mean a dismounted volume or
76a relative path in a different directory (like in @INC).   So those checks
77aren't done here. This routine will treat this as absolute.
78
79=cut
80
81sub catdir {
82    shift;
83    my @args = @_;
84    my $result = shift @args;
85    $result =~ s/:\Z(?!\n)//;
86    foreach (@args) {
87        s/:\Z(?!\n)//;
88        s/^://s;
89        $result .= ":$_";
90    }
91    return "$result:";
92}
93
94=item catfile
95
96Concatenate one or more directory names and a filename to form a
97complete path ending with a filename.  Since this uses catdir, the
98same caveats apply.  Note that the leading : is removed from the filename,
99so that
100
101          File::Spec->catfile($ENV{HOME},"file");
102
103and
104
105          File::Spec->catfile($ENV{HOME},":file");
106
107give the same answer, as one might expect.
108
109=cut
110
111sub catfile {
112    my $self = shift;
113    my $file = pop @_;
114    return $file unless @_;
115    my $dir = $self->catdir(@_);
116    $file =~ s/^://s;
117    return $dir.$file;
118}
119
120=item curdir
121
122Returns a string representing the current directory.
123
124=cut
125
126sub curdir {
127    return ":";
128}
129
130=item devnull
131
132Returns a string representing the null device.
133
134=cut
135
136sub devnull {
137    return "Dev:Null";
138}
139
140=item rootdir
141
142Returns a string representing the root directory.  Under MacPerl,
143returns the name of the startup volume, since that's the closest in
144concept, although other volumes aren't rooted there.
145
146=cut
147
148sub rootdir {
149#
150#  There's no real root directory on MacOS.  The name of the startup
151#  volume is returned, since that's the closest in concept.
152#
153    require Mac::Files;
154    my $system =  Mac::Files::FindFolder(&Mac::Files::kOnSystemDisk,
155                                         &Mac::Files::kSystemFolderType);
156    $system =~ s/:.*\Z(?!\n)/:/s;
157    return $system;
158}
159
160=item tmpdir
161
162Returns a string representation of the first existing directory
163from the following list or '' if none exist:
164
165    $ENV{TMPDIR}
166
167=cut
168
169my $tmpdir;
170sub tmpdir {
171    return $tmpdir if defined $tmpdir;
172    $tmpdir = $ENV{TMPDIR} if -d $ENV{TMPDIR};
173    $tmpdir = '' unless defined $tmpdir;
174    return $tmpdir;
175}
176
177=item updir
178
179Returns a string representing the parent directory.
180
181=cut
182
183sub updir {
184    return "::";
185}
186
187=item file_name_is_absolute
188
189Takes as argument a path and returns true, if it is an absolute path.  In
190the case where a name can be either relative or absolute (for example, a
191folder named "HD" in the current working directory on a drive named "HD"),
192relative wins.  Use ":" in the appropriate place in the path if you want to
193distinguish unambiguously.
194
195As a special case, the file name '' is always considered to be absolute.
196
197=cut
198
199sub file_name_is_absolute {
200    my ($self,$file) = @_;
201    if ($file =~ /:/) {
202        return ($file !~ m/^:/s);
203    } elsif ( $file eq '' ) {
204        return 1 ;
205    } else {
206        return (! -e ":$file");
207    }
208}
209
210=item path
211
212Returns the null list for the MacPerl application, since the concept is
213usually meaningless under MacOS. But if you're using the MacPerl tool under
214MPW, it gives back $ENV{Commands} suitably split, as is done in
215:lib:ExtUtils:MM_Mac.pm.
216
217=cut
218
219sub path {
220#
221#  The concept is meaningless under the MacPerl application.
222#  Under MPW, it has a meaning.
223#
224    return unless exists $ENV{Commands};
225    return split(/,/, $ENV{Commands});
226}
227
228=item splitpath
229
230=cut
231
232sub splitpath {
233    my ($self,$path, $nofile) = @_;
234
235    my ($volume,$directory,$file) = ('','','');
236
237    if ( $nofile ) {
238        ( $volume, $directory ) = $path =~ m@((?:[^:]+(?::|\Z(?!\n)))?)(.*)@s;
239    }
240    else {
241        $path =~
242            m@^( (?: [^:]+: )? )
243                ( (?: .*: )? )
244                ( .* )
245             @xs;
246        $volume    = $1;
247        $directory = $2;
248        $file      = $3;
249    }
250
251    # Make sure non-empty volumes and directories end in ':'
252    $volume    .= ':' if $volume    =~ m@[^:]\Z(?!\n)@ ;
253    $directory .= ':' if $directory =~ m@[^:]\Z(?!\n)@ ;
254    return ($volume,$directory,$file);
255}
256
257
258=item splitdir
259
260=cut
261
262sub splitdir {
263    my ($self,$directories) = @_ ;
264    #
265    # split() likes to forget about trailing null fields, so here we
266    # check to be sure that there will not be any before handling the
267    # simple case.
268    #
269    if ( $directories !~ m@:\Z(?!\n)@ ) {
270        return split( m@:@, $directories );
271    }
272    else {
273        #
274        # since there was a trailing separator, add a file name to the end,
275        # then do the split, then replace it with ''.
276        #
277        my( @directories )= split( m@:@, "${directories}dummy" ) ;
278        $directories[ $#directories ]= '' ;
279        return @directories ;
280    }
281}
282
283
284=item catpath
285
286=cut
287
288sub catpath {
289    my $self = shift ;
290
291    my $result = shift ;
292    $result =~ s@^([^/])@/$1@s ;
293
294    my $segment ;
295    for $segment ( @_ ) {
296        if ( $result =~ m@[^/]\Z(?!\n)@ && $segment =~ m@^[^/]@s ) {
297            $result .= "/$segment" ;
298        }
299        elsif ( $result =~ m@/\Z(?!\n)@ && $segment =~ m@^/@s ) {
300            $result  =~ s@/+\Z(?!\n)@/@;
301            $segment =~ s@^/+@@s;
302            $result  .= "$segment" ;
303        }
304        else {
305            $result  .= $segment ;
306        }
307    }
308
309    return $result ;
310}
311
312=item abs2rel
313
314See L<File::Spec::Unix/abs2rel> for general documentation.
315
316Unlike C<File::Spec::Unix->abs2rel()>, this function will make
317checks against the local filesystem if necessary.  See
318L</file_name_is_absolute> for details.
319
320=cut
321
322sub abs2rel {
323    my($self,$path,$base) = @_;
324
325    # Clean up $path
326    if ( ! $self->file_name_is_absolute( $path ) ) {
327        $path = $self->rel2abs( $path ) ;
328    }
329
330    # Figure out the effective $base and clean it up.
331    if ( !defined( $base ) || $base eq '' ) {
332        $base = cwd() ;
333    }
334    elsif ( ! $self->file_name_is_absolute( $base ) ) {
335        $base = $self->rel2abs( $base ) ;
336    }
337
338    # Now, remove all leading components that are the same
339    my @pathchunks = $self->splitdir( $path );
340    my @basechunks = $self->splitdir( $base );
341
342    while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
343        shift @pathchunks ;
344        shift @basechunks ;
345    }
346
347    $path = join( ':', @pathchunks );
348
349    # @basechunks now contains the number of directories to climb out of.
350    $base = ':' x @basechunks ;
351
352    return "$base:$path" ;
353}
354
355=item rel2abs
356
357See L<File::Spec::Unix/rel2abs> for general documentation.
358
359Unlike C<File::Spec::Unix->rel2abs()>, this function will make
360checks against the local filesystem if necessary.  See
361L</file_name_is_absolute> for details.
362
363=cut
364
365sub rel2abs {
366    my ($self,$path,$base ) = @_;
367
368    if ( ! $self->file_name_is_absolute( $path ) ) {
369        if ( !defined( $base ) || $base eq '' ) {
370            $base = cwd() ;
371        }
372        elsif ( ! $self->file_name_is_absolute( $base ) ) {
373            $base = $self->rel2abs( $base ) ;
374        }
375        else {
376            $base = $self->canonpath( $base ) ;
377        }
378
379        $path = $self->canonpath("$base$path") ;
380    }
381
382    return $path ;
383}
384
385
386=back
387
388=head1 SEE ALSO
389
390L<File::Spec>
391
392=cut
393
3941;
Note: See TracBrowser for help on using the repository browser.