xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/File/Spec/Mac.pm (revision 0:68f95e015346)
1*0Sstevel@tonic-gatepackage File::Spec::Mac;
2*0Sstevel@tonic-gate
3*0Sstevel@tonic-gateuse strict;
4*0Sstevel@tonic-gateuse vars qw(@ISA $VERSION);
5*0Sstevel@tonic-gaterequire File::Spec::Unix;
6*0Sstevel@tonic-gate
7*0Sstevel@tonic-gate$VERSION = '1.4';
8*0Sstevel@tonic-gate
9*0Sstevel@tonic-gate@ISA = qw(File::Spec::Unix);
10*0Sstevel@tonic-gate
11*0Sstevel@tonic-gatemy $macfiles;
12*0Sstevel@tonic-gateif ($^O eq 'MacOS') {
13*0Sstevel@tonic-gate	$macfiles = eval { require Mac::Files };
14*0Sstevel@tonic-gate}
15*0Sstevel@tonic-gate
16*0Sstevel@tonic-gatesub case_tolerant { 1 }
17*0Sstevel@tonic-gate
18*0Sstevel@tonic-gate
19*0Sstevel@tonic-gate=head1 NAME
20*0Sstevel@tonic-gate
21*0Sstevel@tonic-gateFile::Spec::Mac - File::Spec for Mac OS (Classic)
22*0Sstevel@tonic-gate
23*0Sstevel@tonic-gate=head1 SYNOPSIS
24*0Sstevel@tonic-gate
25*0Sstevel@tonic-gate require File::Spec::Mac; # Done internally by File::Spec if needed
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate=head1 DESCRIPTION
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gateMethods for manipulating file specifications.
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gate=head1 METHODS
32*0Sstevel@tonic-gate
33*0Sstevel@tonic-gate=over 2
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gate=item canonpath
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gateOn Mac OS, there's nothing to be done. Returns what it's given.
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gate=cut
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gatesub canonpath {
42*0Sstevel@tonic-gate    my ($self,$path) = @_;
43*0Sstevel@tonic-gate    return $path;
44*0Sstevel@tonic-gate}
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gate=item catdir()
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gateConcatenate two or more directory names to form a path separated by colons
49*0Sstevel@tonic-gate(":") ending with a directory. Resulting paths are B<relative> by default,
50*0Sstevel@tonic-gatebut can be forced to be absolute (but avoid this, see below). Automatically
51*0Sstevel@tonic-gateputs a trailing ":" on the end of the complete path, because that's what's
52*0Sstevel@tonic-gatedone in MacPerl's environment and helps to distinguish a file path from a
53*0Sstevel@tonic-gatedirectory path.
54*0Sstevel@tonic-gate
55*0Sstevel@tonic-gateB<IMPORTANT NOTE:> Beginning with version 1.3 of this module, the resulting
56*0Sstevel@tonic-gatepath is relative by default and I<not> absolute. This descision was made due
57*0Sstevel@tonic-gateto portability reasons. Since C<File::Spec-E<gt>catdir()> returns relative paths
58*0Sstevel@tonic-gateon all other operating systems, it will now also follow this convention on Mac
59*0Sstevel@tonic-gateOS. Note that this may break some existing scripts.
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gateThe intended purpose of this routine is to concatenate I<directory names>.
62*0Sstevel@tonic-gateBut because of the nature of Macintosh paths, some additional possibilities
63*0Sstevel@tonic-gateare allowed to make using this routine give reasonable results for some
64*0Sstevel@tonic-gatecommon situations. In other words, you are also allowed to concatenate
65*0Sstevel@tonic-gateI<paths> instead of directory names (strictly speaking, a string like ":a"
66*0Sstevel@tonic-gateis a path, but not a name, since it contains a punctuation character ":").
67*0Sstevel@tonic-gate
68*0Sstevel@tonic-gateSo, beside calls like
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gate    catdir("a") = ":a:"
71*0Sstevel@tonic-gate    catdir("a","b") = ":a:b:"
72*0Sstevel@tonic-gate    catdir() = ""                    (special case)
73*0Sstevel@tonic-gate
74*0Sstevel@tonic-gatecalls like the following
75*0Sstevel@tonic-gate
76*0Sstevel@tonic-gate    catdir(":a:") = ":a:"
77*0Sstevel@tonic-gate    catdir(":a","b") = ":a:b:"
78*0Sstevel@tonic-gate    catdir(":a:","b") = ":a:b:"
79*0Sstevel@tonic-gate    catdir(":a:",":b:") = ":a:b:"
80*0Sstevel@tonic-gate    catdir(":") = ":"
81*0Sstevel@tonic-gate
82*0Sstevel@tonic-gateare allowed.
83*0Sstevel@tonic-gate
84*0Sstevel@tonic-gateHere are the rules that are used in C<catdir()>; note that we try to be as
85*0Sstevel@tonic-gatecompatible as possible to Unix:
86*0Sstevel@tonic-gate
87*0Sstevel@tonic-gate=over 2
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate=item 1.
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gateThe resulting path is relative by default, i.e. the resulting path will have a
92*0Sstevel@tonic-gateleading colon.
93*0Sstevel@tonic-gate
94*0Sstevel@tonic-gate=item 2.
95*0Sstevel@tonic-gate
96*0Sstevel@tonic-gateA trailing colon is added automatically to the resulting path, to denote a
97*0Sstevel@tonic-gatedirectory.
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate=item 3.
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gateGenerally, each argument has one leading ":" and one trailing ":"
102*0Sstevel@tonic-gateremoved (if any). They are then joined together by a ":". Special
103*0Sstevel@tonic-gatetreatment applies for arguments denoting updir paths like "::lib:",
104*0Sstevel@tonic-gatesee (4), or arguments consisting solely of colons ("colon paths"),
105*0Sstevel@tonic-gatesee (5).
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate=item 4.
108*0Sstevel@tonic-gate
109*0Sstevel@tonic-gateWhen an updir path like ":::lib::" is passed as argument, the number
110*0Sstevel@tonic-gateof directories to climb up is handled correctly, not removing leading
111*0Sstevel@tonic-gateor trailing colons when necessary. E.g.
112*0Sstevel@tonic-gate
113*0Sstevel@tonic-gate    catdir(":::a","::b","c")    = ":::a::b:c:"
114*0Sstevel@tonic-gate    catdir(":::a::","::b","c")  = ":::a:::b:c:"
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate=item 5.
117*0Sstevel@tonic-gate
118*0Sstevel@tonic-gateAdding a colon ":" or empty string "" to a path at I<any> position
119*0Sstevel@tonic-gatedoesn't alter the path, i.e. these arguments are ignored. (When a ""
120*0Sstevel@tonic-gateis passed as the first argument, it has a special meaning, see
121*0Sstevel@tonic-gate(6)). This way, a colon ":" is handled like a "." (curdir) on Unix,
122*0Sstevel@tonic-gatewhile an empty string "" is generally ignored (see
123*0Sstevel@tonic-gateC<Unix-E<gt>canonpath()> ). Likewise, a "::" is handled like a ".."
124*0Sstevel@tonic-gate(updir), and a ":::" is handled like a "../.." etc.  E.g.
125*0Sstevel@tonic-gate
126*0Sstevel@tonic-gate    catdir("a",":",":","b")   = ":a:b:"
127*0Sstevel@tonic-gate    catdir("a",":","::",":b") = ":a::b:"
128*0Sstevel@tonic-gate
129*0Sstevel@tonic-gate=item 6.
130*0Sstevel@tonic-gate
131*0Sstevel@tonic-gateIf the first argument is an empty string "" or is a volume name, i.e. matches
132*0Sstevel@tonic-gatethe pattern /^[^:]+:/, the resulting path is B<absolute>.
133*0Sstevel@tonic-gate
134*0Sstevel@tonic-gate=item 7.
135*0Sstevel@tonic-gate
136*0Sstevel@tonic-gatePassing an empty string "" as the first argument to C<catdir()> is
137*0Sstevel@tonic-gatelike passingC<File::Spec-E<gt>rootdir()> as the first argument, i.e.
138*0Sstevel@tonic-gate
139*0Sstevel@tonic-gate    catdir("","a","b")          is the same as
140*0Sstevel@tonic-gate
141*0Sstevel@tonic-gate    catdir(rootdir(),"a","b").
142*0Sstevel@tonic-gate
143*0Sstevel@tonic-gateThis is true on Unix, where C<catdir("","a","b")> yields "/a/b" and
144*0Sstevel@tonic-gateC<rootdir()> is "/". Note that C<rootdir()> on Mac OS is the startup
145*0Sstevel@tonic-gatevolume, which is the closest in concept to Unix' "/". This should help
146*0Sstevel@tonic-gateto run existing scripts originally written for Unix.
147*0Sstevel@tonic-gate
148*0Sstevel@tonic-gate=item 8.
149*0Sstevel@tonic-gate
150*0Sstevel@tonic-gateFor absolute paths, some cleanup is done, to ensure that the volume
151*0Sstevel@tonic-gatename isn't immediately followed by updirs. This is invalid, because
152*0Sstevel@tonic-gatethis would go beyond "root". Generally, these cases are handled like
153*0Sstevel@tonic-gatetheir Unix counterparts:
154*0Sstevel@tonic-gate
155*0Sstevel@tonic-gate Unix:
156*0Sstevel@tonic-gate    Unix->catdir("","")                 =  "/"
157*0Sstevel@tonic-gate    Unix->catdir("",".")                =  "/"
158*0Sstevel@tonic-gate    Unix->catdir("","..")               =  "/"              # can't go beyond root
159*0Sstevel@tonic-gate    Unix->catdir("",".","..","..","a")  =  "/a"
160*0Sstevel@tonic-gate Mac:
161*0Sstevel@tonic-gate    Mac->catdir("","")                  =  rootdir()         # (e.g. "HD:")
162*0Sstevel@tonic-gate    Mac->catdir("",":")                 =  rootdir()
163*0Sstevel@tonic-gate    Mac->catdir("","::")                =  rootdir()         # can't go beyond root
164*0Sstevel@tonic-gate    Mac->catdir("",":","::","::","a")   =  rootdir() . "a:"  # (e.g. "HD:a:")
165*0Sstevel@tonic-gate
166*0Sstevel@tonic-gateHowever, this approach is limited to the first arguments following
167*0Sstevel@tonic-gate"root" (again, see C<Unix-E<gt>canonpath()> ). If there are more
168*0Sstevel@tonic-gatearguments that move up the directory tree, an invalid path going
169*0Sstevel@tonic-gatebeyond root can be created.
170*0Sstevel@tonic-gate
171*0Sstevel@tonic-gate=back
172*0Sstevel@tonic-gate
173*0Sstevel@tonic-gateAs you've seen, you can force C<catdir()> to create an absolute path
174*0Sstevel@tonic-gateby passing either an empty string or a path that begins with a volume
175*0Sstevel@tonic-gatename as the first argument. However, you are strongly encouraged not
176*0Sstevel@tonic-gateto do so, since this is done only for backward compatibility. Newer
177*0Sstevel@tonic-gateversions of File::Spec come with a method called C<catpath()> (see
178*0Sstevel@tonic-gatebelow), that is designed to offer a portable solution for the creation
179*0Sstevel@tonic-gateof absolute paths.  It takes volume, directory and file portions and
180*0Sstevel@tonic-gatereturns an entire path. While C<catdir()> is still suitable for the
181*0Sstevel@tonic-gateconcatenation of I<directory names>, you are encouraged to use
182*0Sstevel@tonic-gateC<catpath()> to concatenate I<volume names> and I<directory
183*0Sstevel@tonic-gatepaths>. E.g.
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate    $dir      = File::Spec->catdir("tmp","sources");
186*0Sstevel@tonic-gate    $abs_path = File::Spec->catpath("MacintoshHD:", $dir,"");
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gateyields
189*0Sstevel@tonic-gate
190*0Sstevel@tonic-gate    "MacintoshHD:tmp:sources:" .
191*0Sstevel@tonic-gate
192*0Sstevel@tonic-gate=cut
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gatesub catdir {
195*0Sstevel@tonic-gate	my $self = shift;
196*0Sstevel@tonic-gate	return '' unless @_;
197*0Sstevel@tonic-gate	my @args = @_;
198*0Sstevel@tonic-gate	my $first_arg;
199*0Sstevel@tonic-gate	my $relative;
200*0Sstevel@tonic-gate
201*0Sstevel@tonic-gate	# take care of the first argument
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate	if ($args[0] eq '')  { # absolute path, rootdir
204*0Sstevel@tonic-gate		shift @args;
205*0Sstevel@tonic-gate		$relative = 0;
206*0Sstevel@tonic-gate		$first_arg = $self->rootdir;
207*0Sstevel@tonic-gate
208*0Sstevel@tonic-gate	} elsif ($args[0] =~ /^[^:]+:/) { # absolute path, volume name
209*0Sstevel@tonic-gate		$relative = 0;
210*0Sstevel@tonic-gate		$first_arg = shift @args;
211*0Sstevel@tonic-gate		# add a trailing ':' if need be (may be it's a path like HD:dir)
212*0Sstevel@tonic-gate		$first_arg = "$first_arg:" unless ($first_arg =~ /:\Z(?!\n)/);
213*0Sstevel@tonic-gate
214*0Sstevel@tonic-gate	} else { # relative path
215*0Sstevel@tonic-gate		$relative = 1;
216*0Sstevel@tonic-gate		if ( $args[0] =~ /^::+\Z(?!\n)/ ) {
217*0Sstevel@tonic-gate			# updir colon path ('::', ':::' etc.), don't shift
218*0Sstevel@tonic-gate			$first_arg = ':';
219*0Sstevel@tonic-gate		} elsif ($args[0] eq ':') {
220*0Sstevel@tonic-gate			$first_arg = shift @args;
221*0Sstevel@tonic-gate		} else {
222*0Sstevel@tonic-gate			# add a trailing ':' if need be
223*0Sstevel@tonic-gate			$first_arg = shift @args;
224*0Sstevel@tonic-gate			$first_arg = "$first_arg:" unless ($first_arg =~ /:\Z(?!\n)/);
225*0Sstevel@tonic-gate		}
226*0Sstevel@tonic-gate	}
227*0Sstevel@tonic-gate
228*0Sstevel@tonic-gate	# For all other arguments,
229*0Sstevel@tonic-gate	# (a) ignore arguments that equal ':' or '',
230*0Sstevel@tonic-gate	# (b) handle updir paths specially:
231*0Sstevel@tonic-gate	#     '::' 			-> concatenate '::'
232*0Sstevel@tonic-gate	#     '::' . '::' 	-> concatenate ':::' etc.
233*0Sstevel@tonic-gate	# (c) add a trailing ':' if need be
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate	my $result = $first_arg;
236*0Sstevel@tonic-gate	while (@args) {
237*0Sstevel@tonic-gate		my $arg = shift @args;
238*0Sstevel@tonic-gate		unless (($arg eq '') || ($arg eq ':')) {
239*0Sstevel@tonic-gate			if ($arg =~ /^::+\Z(?!\n)/ ) { # updir colon path like ':::'
240*0Sstevel@tonic-gate				my $updir_count = length($arg) - 1;
241*0Sstevel@tonic-gate				while ((@args) && ($args[0] =~ /^::+\Z(?!\n)/) ) { # while updir colon path
242*0Sstevel@tonic-gate					$arg = shift @args;
243*0Sstevel@tonic-gate					$updir_count += (length($arg) - 1);
244*0Sstevel@tonic-gate				}
245*0Sstevel@tonic-gate				$arg = (':' x $updir_count);
246*0Sstevel@tonic-gate			} else {
247*0Sstevel@tonic-gate				$arg =~ s/^://s; # remove a leading ':' if any
248*0Sstevel@tonic-gate				$arg = "$arg:" unless ($arg =~ /:\Z(?!\n)/); # ensure trailing ':'
249*0Sstevel@tonic-gate			}
250*0Sstevel@tonic-gate			$result .= $arg;
251*0Sstevel@tonic-gate		}#unless
252*0Sstevel@tonic-gate	}
253*0Sstevel@tonic-gate
254*0Sstevel@tonic-gate	if ( ($relative) && ($result !~ /^:/) ) {
255*0Sstevel@tonic-gate		# add a leading colon if need be
256*0Sstevel@tonic-gate		$result = ":$result";
257*0Sstevel@tonic-gate	}
258*0Sstevel@tonic-gate
259*0Sstevel@tonic-gate	unless ($relative) {
260*0Sstevel@tonic-gate		# remove updirs immediately following the volume name
261*0Sstevel@tonic-gate		$result =~ s/([^:]+:)(:*)(.*)\Z(?!\n)/$1$3/;
262*0Sstevel@tonic-gate	}
263*0Sstevel@tonic-gate
264*0Sstevel@tonic-gate	return $result;
265*0Sstevel@tonic-gate}
266*0Sstevel@tonic-gate
267*0Sstevel@tonic-gate=item catfile
268*0Sstevel@tonic-gate
269*0Sstevel@tonic-gateConcatenate one or more directory names and a filename to form a
270*0Sstevel@tonic-gatecomplete path ending with a filename. Resulting paths are B<relative>
271*0Sstevel@tonic-gateby default, but can be forced to be absolute (but avoid this).
272*0Sstevel@tonic-gate
273*0Sstevel@tonic-gateB<IMPORTANT NOTE:> Beginning with version 1.3 of this module, the
274*0Sstevel@tonic-gateresulting path is relative by default and I<not> absolute. This
275*0Sstevel@tonic-gatedescision was made due to portability reasons. Since
276*0Sstevel@tonic-gateC<File::Spec-E<gt>catfile()> returns relative paths on all other
277*0Sstevel@tonic-gateoperating systems, it will now also follow this convention on Mac OS.
278*0Sstevel@tonic-gateNote that this may break some existing scripts.
279*0Sstevel@tonic-gate
280*0Sstevel@tonic-gateThe last argument is always considered to be the file portion. Since
281*0Sstevel@tonic-gateC<catfile()> uses C<catdir()> (see above) for the concatenation of the
282*0Sstevel@tonic-gatedirectory portions (if any), the following with regard to relative and
283*0Sstevel@tonic-gateabsolute paths is true:
284*0Sstevel@tonic-gate
285*0Sstevel@tonic-gate    catfile("")     = ""
286*0Sstevel@tonic-gate    catfile("file") = "file"
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gatebut
289*0Sstevel@tonic-gate
290*0Sstevel@tonic-gate    catfile("","")        = rootdir()         # (e.g. "HD:")
291*0Sstevel@tonic-gate    catfile("","file")    = rootdir() . file  # (e.g. "HD:file")
292*0Sstevel@tonic-gate    catfile("HD:","file") = "HD:file"
293*0Sstevel@tonic-gate
294*0Sstevel@tonic-gateThis means that C<catdir()> is called only when there are two or more
295*0Sstevel@tonic-gatearguments, as one might expect.
296*0Sstevel@tonic-gate
297*0Sstevel@tonic-gateNote that the leading ":" is removed from the filename, so that
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate    catfile("a","b","file")  = ":a:b:file"    and
300*0Sstevel@tonic-gate
301*0Sstevel@tonic-gate    catfile("a","b",":file") = ":a:b:file"
302*0Sstevel@tonic-gate
303*0Sstevel@tonic-gategive the same answer.
304*0Sstevel@tonic-gate
305*0Sstevel@tonic-gateTo concatenate I<volume names>, I<directory paths> and I<filenames>,
306*0Sstevel@tonic-gateyou are encouraged to use C<catpath()> (see below).
307*0Sstevel@tonic-gate
308*0Sstevel@tonic-gate=cut
309*0Sstevel@tonic-gate
310*0Sstevel@tonic-gatesub catfile {
311*0Sstevel@tonic-gate    my $self = shift;
312*0Sstevel@tonic-gate    return '' unless @_;
313*0Sstevel@tonic-gate    my $file = pop @_;
314*0Sstevel@tonic-gate    return $file unless @_;
315*0Sstevel@tonic-gate    my $dir = $self->catdir(@_);
316*0Sstevel@tonic-gate    $file =~ s/^://s;
317*0Sstevel@tonic-gate    return $dir.$file;
318*0Sstevel@tonic-gate}
319*0Sstevel@tonic-gate
320*0Sstevel@tonic-gate=item curdir
321*0Sstevel@tonic-gate
322*0Sstevel@tonic-gateReturns a string representing the current directory. On Mac OS, this is ":".
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gate=cut
325*0Sstevel@tonic-gate
326*0Sstevel@tonic-gatesub curdir {
327*0Sstevel@tonic-gate    return ":";
328*0Sstevel@tonic-gate}
329*0Sstevel@tonic-gate
330*0Sstevel@tonic-gate=item devnull
331*0Sstevel@tonic-gate
332*0Sstevel@tonic-gateReturns a string representing the null device. On Mac OS, this is "Dev:Null".
333*0Sstevel@tonic-gate
334*0Sstevel@tonic-gate=cut
335*0Sstevel@tonic-gate
336*0Sstevel@tonic-gatesub devnull {
337*0Sstevel@tonic-gate    return "Dev:Null";
338*0Sstevel@tonic-gate}
339*0Sstevel@tonic-gate
340*0Sstevel@tonic-gate=item rootdir
341*0Sstevel@tonic-gate
342*0Sstevel@tonic-gateReturns a string representing the root directory.  Under MacPerl,
343*0Sstevel@tonic-gatereturns the name of the startup volume, since that's the closest in
344*0Sstevel@tonic-gateconcept, although other volumes aren't rooted there. The name has a
345*0Sstevel@tonic-gatetrailing ":", because that's the correct specification for a volume
346*0Sstevel@tonic-gatename on Mac OS.
347*0Sstevel@tonic-gate
348*0Sstevel@tonic-gateIf Mac::Files could not be loaded, the empty string is returned.
349*0Sstevel@tonic-gate
350*0Sstevel@tonic-gate=cut
351*0Sstevel@tonic-gate
352*0Sstevel@tonic-gatesub rootdir {
353*0Sstevel@tonic-gate#
354*0Sstevel@tonic-gate#  There's no real root directory on Mac OS. The name of the startup
355*0Sstevel@tonic-gate#  volume is returned, since that's the closest in concept.
356*0Sstevel@tonic-gate#
357*0Sstevel@tonic-gate    return '' unless $macfiles;
358*0Sstevel@tonic-gate    my $system = Mac::Files::FindFolder(&Mac::Files::kOnSystemDisk,
359*0Sstevel@tonic-gate	&Mac::Files::kSystemFolderType);
360*0Sstevel@tonic-gate    $system =~ s/:.*\Z(?!\n)/:/s;
361*0Sstevel@tonic-gate    return $system;
362*0Sstevel@tonic-gate}
363*0Sstevel@tonic-gate
364*0Sstevel@tonic-gate=item tmpdir
365*0Sstevel@tonic-gate
366*0Sstevel@tonic-gateReturns the contents of $ENV{TMPDIR}, if that directory exits or the
367*0Sstevel@tonic-gatecurrent working directory otherwise. Under MacPerl, $ENV{TMPDIR} will
368*0Sstevel@tonic-gatecontain a path like "MacintoshHD:Temporary Items:", which is a hidden
369*0Sstevel@tonic-gatedirectory on your startup volume.
370*0Sstevel@tonic-gate
371*0Sstevel@tonic-gate=cut
372*0Sstevel@tonic-gate
373*0Sstevel@tonic-gatemy $tmpdir;
374*0Sstevel@tonic-gatesub tmpdir {
375*0Sstevel@tonic-gate    return $tmpdir if defined $tmpdir;
376*0Sstevel@tonic-gate    my $self = shift;
377*0Sstevel@tonic-gate    $tmpdir = $self->_tmpdir( $ENV{TMPDIR} );
378*0Sstevel@tonic-gate}
379*0Sstevel@tonic-gate
380*0Sstevel@tonic-gate=item updir
381*0Sstevel@tonic-gate
382*0Sstevel@tonic-gateReturns a string representing the parent directory. On Mac OS, this is "::".
383*0Sstevel@tonic-gate
384*0Sstevel@tonic-gate=cut
385*0Sstevel@tonic-gate
386*0Sstevel@tonic-gatesub updir {
387*0Sstevel@tonic-gate    return "::";
388*0Sstevel@tonic-gate}
389*0Sstevel@tonic-gate
390*0Sstevel@tonic-gate=item file_name_is_absolute
391*0Sstevel@tonic-gate
392*0Sstevel@tonic-gateTakes as argument a path and returns true, if it is an absolute path.
393*0Sstevel@tonic-gateIf the path has a leading ":", it's a relative path. Otherwise, it's an
394*0Sstevel@tonic-gateabsolute path, unless the path doesn't contain any colons, i.e. it's a name
395*0Sstevel@tonic-gatelike "a". In this particular case, the path is considered to be relative
396*0Sstevel@tonic-gate(i.e. it is considered to be a filename). Use ":" in the appropriate place
397*0Sstevel@tonic-gatein the path if you want to distinguish unambiguously. As a special case,
398*0Sstevel@tonic-gatethe filename '' is always considered to be absolute. Note that with version
399*0Sstevel@tonic-gate1.2 of File::Spec::Mac, this does no longer consult the local filesystem.
400*0Sstevel@tonic-gate
401*0Sstevel@tonic-gateE.g.
402*0Sstevel@tonic-gate
403*0Sstevel@tonic-gate    File::Spec->file_name_is_absolute("a");             # false (relative)
404*0Sstevel@tonic-gate    File::Spec->file_name_is_absolute(":a:b:");         # false (relative)
405*0Sstevel@tonic-gate    File::Spec->file_name_is_absolute("MacintoshHD:");  # true (absolute)
406*0Sstevel@tonic-gate    File::Spec->file_name_is_absolute("");              # true (absolute)
407*0Sstevel@tonic-gate
408*0Sstevel@tonic-gate
409*0Sstevel@tonic-gate=cut
410*0Sstevel@tonic-gate
411*0Sstevel@tonic-gatesub file_name_is_absolute {
412*0Sstevel@tonic-gate    my ($self,$file) = @_;
413*0Sstevel@tonic-gate    if ($file =~ /:/) {
414*0Sstevel@tonic-gate	return (! ($file =~ m/^:/s) );
415*0Sstevel@tonic-gate    } elsif ( $file eq '' ) {
416*0Sstevel@tonic-gate        return 1 ;
417*0Sstevel@tonic-gate    } else {
418*0Sstevel@tonic-gate	return 0; # i.e. a file like "a"
419*0Sstevel@tonic-gate    }
420*0Sstevel@tonic-gate}
421*0Sstevel@tonic-gate
422*0Sstevel@tonic-gate=item path
423*0Sstevel@tonic-gate
424*0Sstevel@tonic-gateReturns the null list for the MacPerl application, since the concept is
425*0Sstevel@tonic-gateusually meaningless under Mac OS. But if you're using the MacPerl tool under
426*0Sstevel@tonic-gateMPW, it gives back $ENV{Commands} suitably split, as is done in
427*0Sstevel@tonic-gate:lib:ExtUtils:MM_Mac.pm.
428*0Sstevel@tonic-gate
429*0Sstevel@tonic-gate=cut
430*0Sstevel@tonic-gate
431*0Sstevel@tonic-gatesub path {
432*0Sstevel@tonic-gate#
433*0Sstevel@tonic-gate#  The concept is meaningless under the MacPerl application.
434*0Sstevel@tonic-gate#  Under MPW, it has a meaning.
435*0Sstevel@tonic-gate#
436*0Sstevel@tonic-gate    return unless exists $ENV{Commands};
437*0Sstevel@tonic-gate    return split(/,/, $ENV{Commands});
438*0Sstevel@tonic-gate}
439*0Sstevel@tonic-gate
440*0Sstevel@tonic-gate=item splitpath
441*0Sstevel@tonic-gate
442*0Sstevel@tonic-gate    ($volume,$directories,$file) = File::Spec->splitpath( $path );
443*0Sstevel@tonic-gate    ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
444*0Sstevel@tonic-gate
445*0Sstevel@tonic-gateSplits a path into volume, directory, and filename portions.
446*0Sstevel@tonic-gate
447*0Sstevel@tonic-gateOn Mac OS, assumes that the last part of the path is a filename unless
448*0Sstevel@tonic-gate$no_file is true or a trailing separator ":" is present.
449*0Sstevel@tonic-gate
450*0Sstevel@tonic-gateThe volume portion is always returned with a trailing ":". The directory portion
451*0Sstevel@tonic-gateis always returned with a leading (to denote a relative path) and a trailing ":"
452*0Sstevel@tonic-gate(to denote a directory). The file portion is always returned I<without> a leading ":".
453*0Sstevel@tonic-gateEmpty portions are returned as empty string ''.
454*0Sstevel@tonic-gate
455*0Sstevel@tonic-gateThe results can be passed to C<catpath()> to get back a path equivalent to
456*0Sstevel@tonic-gate(usually identical to) the original path.
457*0Sstevel@tonic-gate
458*0Sstevel@tonic-gate
459*0Sstevel@tonic-gate=cut
460*0Sstevel@tonic-gate
461*0Sstevel@tonic-gatesub splitpath {
462*0Sstevel@tonic-gate    my ($self,$path, $nofile) = @_;
463*0Sstevel@tonic-gate    my ($volume,$directory,$file);
464*0Sstevel@tonic-gate
465*0Sstevel@tonic-gate    if ( $nofile ) {
466*0Sstevel@tonic-gate        ( $volume, $directory ) = $path =~ m|^((?:[^:]+:)?)(.*)|s;
467*0Sstevel@tonic-gate    }
468*0Sstevel@tonic-gate    else {
469*0Sstevel@tonic-gate        $path =~
470*0Sstevel@tonic-gate            m|^( (?: [^:]+: )? )
471*0Sstevel@tonic-gate               ( (?: .*: )? )
472*0Sstevel@tonic-gate               ( .* )
473*0Sstevel@tonic-gate             |xs;
474*0Sstevel@tonic-gate        $volume    = $1;
475*0Sstevel@tonic-gate        $directory = $2;
476*0Sstevel@tonic-gate        $file      = $3;
477*0Sstevel@tonic-gate    }
478*0Sstevel@tonic-gate
479*0Sstevel@tonic-gate    $volume = '' unless defined($volume);
480*0Sstevel@tonic-gate	$directory = ":$directory" if ( $volume && $directory ); # take care of "HD::dir"
481*0Sstevel@tonic-gate    if ($directory) {
482*0Sstevel@tonic-gate        # Make sure non-empty directories begin and end in ':'
483*0Sstevel@tonic-gate        $directory .= ':' unless (substr($directory,-1) eq ':');
484*0Sstevel@tonic-gate        $directory = ":$directory" unless (substr($directory,0,1) eq ':');
485*0Sstevel@tonic-gate    } else {
486*0Sstevel@tonic-gate	$directory = '';
487*0Sstevel@tonic-gate    }
488*0Sstevel@tonic-gate    $file = '' unless defined($file);
489*0Sstevel@tonic-gate
490*0Sstevel@tonic-gate    return ($volume,$directory,$file);
491*0Sstevel@tonic-gate}
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gate
494*0Sstevel@tonic-gate=item splitdir
495*0Sstevel@tonic-gate
496*0Sstevel@tonic-gateThe opposite of C<catdir()>.
497*0Sstevel@tonic-gate
498*0Sstevel@tonic-gate    @dirs = File::Spec->splitdir( $directories );
499*0Sstevel@tonic-gate
500*0Sstevel@tonic-gate$directories should be only the directory portion of the path on systems
501*0Sstevel@tonic-gatethat have the concept of a volume or that have path syntax that differentiates
502*0Sstevel@tonic-gatefiles from directories. Consider using C<splitpath()> otherwise.
503*0Sstevel@tonic-gate
504*0Sstevel@tonic-gateUnlike just splitting the directories on the separator, empty directory names
505*0Sstevel@tonic-gate(C<"">) can be returned. Since C<catdir()> on Mac OS always appends a trailing
506*0Sstevel@tonic-gatecolon to distinguish a directory path from a file path, a single trailing colon
507*0Sstevel@tonic-gatewill be ignored, i.e. there's no empty directory name after it.
508*0Sstevel@tonic-gate
509*0Sstevel@tonic-gateHence, on Mac OS, both
510*0Sstevel@tonic-gate
511*0Sstevel@tonic-gate    File::Spec->splitdir( ":a:b::c:" );    and
512*0Sstevel@tonic-gate    File::Spec->splitdir( ":a:b::c" );
513*0Sstevel@tonic-gate
514*0Sstevel@tonic-gateyield:
515*0Sstevel@tonic-gate
516*0Sstevel@tonic-gate    ( "a", "b", "::", "c")
517*0Sstevel@tonic-gate
518*0Sstevel@tonic-gatewhile
519*0Sstevel@tonic-gate
520*0Sstevel@tonic-gate    File::Spec->splitdir( ":a:b::c::" );
521*0Sstevel@tonic-gate
522*0Sstevel@tonic-gateyields:
523*0Sstevel@tonic-gate
524*0Sstevel@tonic-gate    ( "a", "b", "::", "c", "::")
525*0Sstevel@tonic-gate
526*0Sstevel@tonic-gate
527*0Sstevel@tonic-gate=cut
528*0Sstevel@tonic-gate
529*0Sstevel@tonic-gatesub splitdir {
530*0Sstevel@tonic-gate	my ($self, $path) = @_;
531*0Sstevel@tonic-gate	my @result = ();
532*0Sstevel@tonic-gate	my ($head, $sep, $tail, $volume, $directories);
533*0Sstevel@tonic-gate
534*0Sstevel@tonic-gate	return ('') if ( (!defined($path)) || ($path eq '') );
535*0Sstevel@tonic-gate	return (':') if ($path eq ':');
536*0Sstevel@tonic-gate
537*0Sstevel@tonic-gate	( $volume, $sep, $directories ) = $path =~ m|^((?:[^:]+:)?)(:*)(.*)|s;
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gate	# deprecated, but handle it correctly
540*0Sstevel@tonic-gate	if ($volume) {
541*0Sstevel@tonic-gate		push (@result, $volume);
542*0Sstevel@tonic-gate		$sep .= ':';
543*0Sstevel@tonic-gate	}
544*0Sstevel@tonic-gate
545*0Sstevel@tonic-gate	while ($sep || $directories) {
546*0Sstevel@tonic-gate		if (length($sep) > 1) {
547*0Sstevel@tonic-gate			my $updir_count = length($sep) - 1;
548*0Sstevel@tonic-gate			for (my $i=0; $i<$updir_count; $i++) {
549*0Sstevel@tonic-gate				# push '::' updir_count times;
550*0Sstevel@tonic-gate				# simulate Unix '..' updirs
551*0Sstevel@tonic-gate				push (@result, '::');
552*0Sstevel@tonic-gate			}
553*0Sstevel@tonic-gate		}
554*0Sstevel@tonic-gate		$sep = '';
555*0Sstevel@tonic-gate		if ($directories) {
556*0Sstevel@tonic-gate			( $head, $sep, $tail ) = $directories =~ m|^((?:[^:]+)?)(:*)(.*)|s;
557*0Sstevel@tonic-gate			push (@result, $head);
558*0Sstevel@tonic-gate			$directories = $tail;
559*0Sstevel@tonic-gate		}
560*0Sstevel@tonic-gate	}
561*0Sstevel@tonic-gate	return @result;
562*0Sstevel@tonic-gate}
563*0Sstevel@tonic-gate
564*0Sstevel@tonic-gate
565*0Sstevel@tonic-gate=item catpath
566*0Sstevel@tonic-gate
567*0Sstevel@tonic-gate    $path = File::Spec->catpath($volume,$directory,$file);
568*0Sstevel@tonic-gate
569*0Sstevel@tonic-gateTakes volume, directory and file portions and returns an entire path. On Mac OS,
570*0Sstevel@tonic-gate$volume, $directory and $file are concatenated.  A ':' is inserted if need be. You
571*0Sstevel@tonic-gatemay pass an empty string for each portion. If all portions are empty, the empty
572*0Sstevel@tonic-gatestring is returned. If $volume is empty, the result will be a relative path,
573*0Sstevel@tonic-gatebeginning with a ':'. If $volume and $directory are empty, a leading ":" (if any)
574*0Sstevel@tonic-gateis removed form $file and the remainder is returned. If $file is empty, the
575*0Sstevel@tonic-gateresulting path will have a trailing ':'.
576*0Sstevel@tonic-gate
577*0Sstevel@tonic-gate
578*0Sstevel@tonic-gate=cut
579*0Sstevel@tonic-gate
580*0Sstevel@tonic-gatesub catpath {
581*0Sstevel@tonic-gate    my ($self,$volume,$directory,$file) = @_;
582*0Sstevel@tonic-gate
583*0Sstevel@tonic-gate    if ( (! $volume) && (! $directory) ) {
584*0Sstevel@tonic-gate	$file =~ s/^:// if $file;
585*0Sstevel@tonic-gate	return $file ;
586*0Sstevel@tonic-gate    }
587*0Sstevel@tonic-gate
588*0Sstevel@tonic-gate    # We look for a volume in $volume, then in $directory, but not both
589*0Sstevel@tonic-gate
590*0Sstevel@tonic-gate    my ($dir_volume, $dir_dirs) = $self->splitpath($directory, 1);
591*0Sstevel@tonic-gate
592*0Sstevel@tonic-gate    $volume = $dir_volume unless length $volume;
593*0Sstevel@tonic-gate    my $path = $volume; # may be ''
594*0Sstevel@tonic-gate    $path .= ':' unless (substr($path, -1) eq ':'); # ensure trailing ':'
595*0Sstevel@tonic-gate
596*0Sstevel@tonic-gate    if ($directory) {
597*0Sstevel@tonic-gate	$directory = $dir_dirs if $volume;
598*0Sstevel@tonic-gate	$directory =~ s/^://; # remove leading ':' if any
599*0Sstevel@tonic-gate	$path .= $directory;
600*0Sstevel@tonic-gate	$path .= ':' unless (substr($path, -1) eq ':'); # ensure trailing ':'
601*0Sstevel@tonic-gate    }
602*0Sstevel@tonic-gate
603*0Sstevel@tonic-gate    if ($file) {
604*0Sstevel@tonic-gate	$file =~ s/^://; # remove leading ':' if any
605*0Sstevel@tonic-gate	$path .= $file;
606*0Sstevel@tonic-gate    }
607*0Sstevel@tonic-gate
608*0Sstevel@tonic-gate    return $path;
609*0Sstevel@tonic-gate}
610*0Sstevel@tonic-gate
611*0Sstevel@tonic-gate=item abs2rel
612*0Sstevel@tonic-gate
613*0Sstevel@tonic-gateTakes a destination path and an optional base path and returns a relative path
614*0Sstevel@tonic-gatefrom the base path to the destination path:
615*0Sstevel@tonic-gate
616*0Sstevel@tonic-gate    $rel_path = File::Spec->abs2rel( $path ) ;
617*0Sstevel@tonic-gate    $rel_path = File::Spec->abs2rel( $path, $base ) ;
618*0Sstevel@tonic-gate
619*0Sstevel@tonic-gateNote that both paths are assumed to have a notation that distinguishes a
620*0Sstevel@tonic-gatedirectory path (with trailing ':') from a file path (without trailing ':').
621*0Sstevel@tonic-gate
622*0Sstevel@tonic-gateIf $base is not present or '', then the current working directory is used.
623*0Sstevel@tonic-gateIf $base is relative, then it is converted to absolute form using C<rel2abs()>.
624*0Sstevel@tonic-gateThis means that it is taken to be relative to the current working directory.
625*0Sstevel@tonic-gate
626*0Sstevel@tonic-gateIf $path and $base appear to be on two different volumes, we will not
627*0Sstevel@tonic-gateattempt to resolve the two paths, and we will instead simply return
628*0Sstevel@tonic-gate$path.  Note that previous versions of this module ignored the volume
629*0Sstevel@tonic-gateof $base, which resulted in garbage results part of the time.
630*0Sstevel@tonic-gate
631*0Sstevel@tonic-gateIf $base doesn't have a trailing colon, the last element of $base is
632*0Sstevel@tonic-gateassumed to be a filename.  This filename is ignored.  Otherwise all path
633*0Sstevel@tonic-gatecomponents are assumed to be directories.
634*0Sstevel@tonic-gate
635*0Sstevel@tonic-gateIf $path is relative, it is converted to absolute form using C<rel2abs()>.
636*0Sstevel@tonic-gateThis means that it is taken to be relative to the current working directory.
637*0Sstevel@tonic-gate
638*0Sstevel@tonic-gateBased on code written by Shigio Yamaguchi.
639*0Sstevel@tonic-gate
640*0Sstevel@tonic-gate
641*0Sstevel@tonic-gate=cut
642*0Sstevel@tonic-gate
643*0Sstevel@tonic-gate# maybe this should be done in canonpath() ?
644*0Sstevel@tonic-gatesub _resolve_updirs {
645*0Sstevel@tonic-gate	my $path = shift @_;
646*0Sstevel@tonic-gate	my $proceed;
647*0Sstevel@tonic-gate
648*0Sstevel@tonic-gate	# resolve any updirs, e.g. "HD:tmp::file" -> "HD:file"
649*0Sstevel@tonic-gate	do {
650*0Sstevel@tonic-gate		$proceed = ($path =~ s/^(.*):[^:]+::(.*?)\z/$1:$2/);
651*0Sstevel@tonic-gate	} while ($proceed);
652*0Sstevel@tonic-gate
653*0Sstevel@tonic-gate	return $path;
654*0Sstevel@tonic-gate}
655*0Sstevel@tonic-gate
656*0Sstevel@tonic-gate
657*0Sstevel@tonic-gatesub abs2rel {
658*0Sstevel@tonic-gate    my($self,$path,$base) = @_;
659*0Sstevel@tonic-gate
660*0Sstevel@tonic-gate    # Clean up $path
661*0Sstevel@tonic-gate    if ( ! $self->file_name_is_absolute( $path ) ) {
662*0Sstevel@tonic-gate        $path = $self->rel2abs( $path ) ;
663*0Sstevel@tonic-gate    }
664*0Sstevel@tonic-gate
665*0Sstevel@tonic-gate    # Figure out the effective $base and clean it up.
666*0Sstevel@tonic-gate    if ( !defined( $base ) || $base eq '' ) {
667*0Sstevel@tonic-gate	$base = $self->_cwd();
668*0Sstevel@tonic-gate    }
669*0Sstevel@tonic-gate    elsif ( ! $self->file_name_is_absolute( $base ) ) {
670*0Sstevel@tonic-gate        $base = $self->rel2abs( $base ) ;
671*0Sstevel@tonic-gate	$base = _resolve_updirs( $base ); # resolve updirs in $base
672*0Sstevel@tonic-gate    }
673*0Sstevel@tonic-gate    else {
674*0Sstevel@tonic-gate	$base = _resolve_updirs( $base );
675*0Sstevel@tonic-gate    }
676*0Sstevel@tonic-gate
677*0Sstevel@tonic-gate    # Split up paths - ignore $base's file
678*0Sstevel@tonic-gate    my ( $path_vol, $path_dirs, $path_file ) =  $self->splitpath( $path );
679*0Sstevel@tonic-gate    my ( $base_vol, $base_dirs )             =  $self->splitpath( $base );
680*0Sstevel@tonic-gate
681*0Sstevel@tonic-gate    return $path unless lc( $path_vol ) eq lc( $base_vol );
682*0Sstevel@tonic-gate
683*0Sstevel@tonic-gate    # Now, remove all leading components that are the same
684*0Sstevel@tonic-gate    my @pathchunks = $self->splitdir( $path_dirs );
685*0Sstevel@tonic-gate    my @basechunks = $self->splitdir( $base_dirs );
686*0Sstevel@tonic-gate
687*0Sstevel@tonic-gate    while ( @pathchunks &&
688*0Sstevel@tonic-gate	    @basechunks &&
689*0Sstevel@tonic-gate	    lc( $pathchunks[0] ) eq lc( $basechunks[0] ) ) {
690*0Sstevel@tonic-gate        shift @pathchunks ;
691*0Sstevel@tonic-gate        shift @basechunks ;
692*0Sstevel@tonic-gate    }
693*0Sstevel@tonic-gate
694*0Sstevel@tonic-gate    # @pathchunks now has the directories to descend in to.
695*0Sstevel@tonic-gate    # ensure relative path, even if @pathchunks is empty
696*0Sstevel@tonic-gate    $path_dirs = $self->catdir( ':', @pathchunks );
697*0Sstevel@tonic-gate
698*0Sstevel@tonic-gate    # @basechunks now contains the number of directories to climb out of.
699*0Sstevel@tonic-gate    $base_dirs = (':' x @basechunks) . ':' ;
700*0Sstevel@tonic-gate
701*0Sstevel@tonic-gate    return $self->catpath( '', $self->catdir( $base_dirs, $path_dirs ), $path_file ) ;
702*0Sstevel@tonic-gate}
703*0Sstevel@tonic-gate
704*0Sstevel@tonic-gate=item rel2abs
705*0Sstevel@tonic-gate
706*0Sstevel@tonic-gateConverts a relative path to an absolute path:
707*0Sstevel@tonic-gate
708*0Sstevel@tonic-gate    $abs_path = File::Spec->rel2abs( $path ) ;
709*0Sstevel@tonic-gate    $abs_path = File::Spec->rel2abs( $path, $base ) ;
710*0Sstevel@tonic-gate
711*0Sstevel@tonic-gateNote that both paths are assumed to have a notation that distinguishes a
712*0Sstevel@tonic-gatedirectory path (with trailing ':') from a file path (without trailing ':').
713*0Sstevel@tonic-gate
714*0Sstevel@tonic-gateIf $base is not present or '', then $base is set to the current working
715*0Sstevel@tonic-gatedirectory. If $base is relative, then it is converted to absolute form
716*0Sstevel@tonic-gateusing C<rel2abs()>. This means that it is taken to be relative to the
717*0Sstevel@tonic-gatecurrent working directory.
718*0Sstevel@tonic-gate
719*0Sstevel@tonic-gateIf $base doesn't have a trailing colon, the last element of $base is
720*0Sstevel@tonic-gateassumed to be a filename.  This filename is ignored.  Otherwise all path
721*0Sstevel@tonic-gatecomponents are assumed to be directories.
722*0Sstevel@tonic-gate
723*0Sstevel@tonic-gateIf $path is already absolute, it is returned and $base is ignored.
724*0Sstevel@tonic-gate
725*0Sstevel@tonic-gateBased on code written by Shigio Yamaguchi.
726*0Sstevel@tonic-gate
727*0Sstevel@tonic-gate=cut
728*0Sstevel@tonic-gate
729*0Sstevel@tonic-gatesub rel2abs {
730*0Sstevel@tonic-gate    my ($self,$path,$base) = @_;
731*0Sstevel@tonic-gate
732*0Sstevel@tonic-gate    if ( ! $self->file_name_is_absolute($path) ) {
733*0Sstevel@tonic-gate        # Figure out the effective $base and clean it up.
734*0Sstevel@tonic-gate        if ( !defined( $base ) || $base eq '' ) {
735*0Sstevel@tonic-gate	    $base = $self->_cwd();
736*0Sstevel@tonic-gate        }
737*0Sstevel@tonic-gate        elsif ( ! $self->file_name_is_absolute($base) ) {
738*0Sstevel@tonic-gate            $base = $self->rel2abs($base) ;
739*0Sstevel@tonic-gate        }
740*0Sstevel@tonic-gate
741*0Sstevel@tonic-gate	# Split up paths
742*0Sstevel@tonic-gate
743*0Sstevel@tonic-gate	# igonore $path's volume
744*0Sstevel@tonic-gate        my ( $path_dirs, $path_file ) = ($self->splitpath($path))[1,2] ;
745*0Sstevel@tonic-gate
746*0Sstevel@tonic-gate        # ignore $base's file part
747*0Sstevel@tonic-gate	my ( $base_vol, $base_dirs ) = $self->splitpath($base) ;
748*0Sstevel@tonic-gate
749*0Sstevel@tonic-gate	# Glom them together
750*0Sstevel@tonic-gate	$path_dirs = ':' if ($path_dirs eq '');
751*0Sstevel@tonic-gate	$base_dirs =~ s/:$//; # remove trailing ':', if any
752*0Sstevel@tonic-gate	$base_dirs = $base_dirs . $path_dirs;
753*0Sstevel@tonic-gate
754*0Sstevel@tonic-gate        $path = $self->catpath( $base_vol, $base_dirs, $path_file );
755*0Sstevel@tonic-gate    }
756*0Sstevel@tonic-gate    return $path;
757*0Sstevel@tonic-gate}
758*0Sstevel@tonic-gate
759*0Sstevel@tonic-gate
760*0Sstevel@tonic-gate=back
761*0Sstevel@tonic-gate
762*0Sstevel@tonic-gate=head1 AUTHORS
763*0Sstevel@tonic-gate
764*0Sstevel@tonic-gateSee the authors list in I<File::Spec>. Mac OS support by Paul Schinder
765*0Sstevel@tonic-gate<schinder@pobox.com> and Thomas Wegner <wegner_thomas@yahoo.com>.
766*0Sstevel@tonic-gate
767*0Sstevel@tonic-gate=head1 SEE ALSO
768*0Sstevel@tonic-gate
769*0Sstevel@tonic-gateSee L<File::Spec> and L<File::Spec::Unix>.  This package overrides the
770*0Sstevel@tonic-gateimplementation of these methods, not the semantics.
771*0Sstevel@tonic-gate
772*0Sstevel@tonic-gate=cut
773*0Sstevel@tonic-gate
774*0Sstevel@tonic-gate1;
775