PERFORCE change 12583 for review

[email protected] (Chris Nandor) Mon, 22 Oct 2001 18:00:19 -0400
Newsgroups perl.perl5.changes.mac
Message-ID <p0510030db7fa3f82ac38@[10.0.1.177]>
Change 12583 by pudge@pudge-mobile on 2001/10/22 19:26:00

	Add in lots of File::Spec changes, from Thomas Wegner,
	and sync with changes from bleadperl.

Affected files ...

... //depot/maint-5.6/macperl/lib/File/Spec.pm#2 edit
... //depot/maint-5.6/macperl/lib/File/Spec/Epoc.pm#2 edit
... //depot/maint-5.6/macperl/lib/File/Spec/Functions.pm#2 edit
... //depot/maint-5.6/macperl/lib/File/Spec/Mac.pm#3 edit
... //depot/maint-5.6/macperl/lib/File/Spec/Unix.pm#2 edit
... //depot/maint-5.6/macperl/lib/File/Spec/VMS.pm#2 edit
... //depot/maint-5.6/macperl/lib/File/Spec/Win32.pm#2 edit
... //depot/maint-5.6/macperl/t/lib/filespec.t#3 edit

Differences ...

==== //depot/maint-5.6/macperl/lib/File/Spec.pm#2 (text) ====
Index: perl/lib/File/Spec.pm
--- perl/lib/File/Spec.pm.~1~	Mon Oct 22 13:30:06 2001
+++ perl/lib/File/Spec.pm	Mon Oct 22 13:30:06 2001
@@ -1,9 +1,9 @@
 package File::Spec;
 
 use strict;
-use vars qw(@ISA $VERSION);
+our(@ISA, $VERSION);
 
-$VERSION = 0.82 ;
+$VERSION = 0.83 ;
 
 my %module = (MacOS   => 'Mac',
 	      MSWin32 => 'Win32',
@@ -16,6 +16,7 @@
 @ISA = ("File::Spec::$module");
 
 1;
+
 __END__
 
 =head1 NAME
@@ -58,7 +59,7 @@
 only under that OS, it may not be possible to load all modules under all
 operating systems.
 
-Since File::Spec is object oriented, subroutines should not called directly,
+Since File::Spec is object oriented, subroutines should not be called directly,
 as in:
 
 	File::Spec::catfile('a','b');
@@ -70,24 +71,217 @@
 For simple uses, L<File::Spec::Functions> provides convenient functional
 forms of these methods.
 
-For a list of available methods, please consult L<File::Spec::Unix>,
-which contains the entire set, and which is inherited by the modules for
-other platforms. For further information, please see L<File::Spec::Mac>,
-L<File::Spec::OS2>, L<File::Spec::Win32>, or L<File::Spec::VMS>.
+=head1 METHODS
+
+=over 2
+
+=item canonpath
+
+No physical check on the filesystem, but a logical cleanup of a
+path.
+
+    $cpath = File::Spec->canonpath( $path ) ;
+
+=item catdir
+
+Concatenate two or more directory names to form a complete path ending
+with a directory. But remove the trailing slash from the resulting
+string, because it doesn't look good, isn't necessary and confuses
+OS2. Of course, if this is the root directory, don't cut off the
+trailing slash :-)
+
+    $path = File::Spec->catdir( @directories );
+
+=item catfile
+
+Concatenate one or more directory names and a filename to form a
+complete path ending with a filename
+
+    $path = File::Spec->catfile( @directories, $filename );
+
+=item curdir
+
+Returns a string representation of the current directory.
+
+    $curdir = File::Spec->curdir();
+
+=item devnull
+
+Returns a string representation of the null device.
+
+    $devnull = File::Spec->devnull();
+
+=item rootdir
+
+Returns a string representation of the root directory.
+
+    $rootdir = File::Spec->rootdir();
+
+=item tmpdir
+
+Returns a string representation of the first writable directory from a
+list of possible temporary directories.  Returns "" if no writable
+temporary directories are found.  The list of directories checked
+depends on the platform; e.g. File::Spec::Unix checks $ENV{TMPDIR} and
+/tmp.
+
+    $tmpdir = File::Spec->tmpdir();
+
+=item updir
+
+Returns a string representation of the parent directory.
+
+    $updir = File::Spec->updir();
+
+=item no_upwards
+
+Given a list of file names, strip out those that refer to a parent
+directory. (Does not strip symlinks, only '.', '..', and equivalents.)
+
+    @paths = File::Spec->no_upwards( @paths );
+
+=item case_tolerant
+
+Returns a true or false value indicating, respectively, that alphabetic
+is not or is significant when comparing file specifications.
+
+    $is_case_tolerant = File::Spec->case_tolerant();
+
+=item file_name_is_absolute
+
+Takes as argument a path and returns true if it is an absolute path.
+
+    $is_absolute = File::Spec->file_name_is_absolute( $path );
+
+This does not consult the local filesystem on Unix, Win32, OS/2, or
+Mac OS (Classic).  It does consult the working environment for VMS
+(see L<File::Spec::VMS/file_name_is_absolute>).
+
+=item path
+
+Takes no argument, returns the environment variable PATH as an array.
+
+    @PATH = File::Spec->path();
+
+=item join
+
+join is the same as catfile.
+
+=item splitpath
+
+Splits a path in to volume, directory, and filename portions. On systems
+with no concept of volume, returns undef for volume. 
+
+    ($volume,$directories,$file) = File::Spec->splitpath( $path );
+    ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
+
+For systems with no syntax differentiating filenames from directories, 
+assumes that the last file is a path unless $no_file is true or a 
+trailing separator or /. or /.. is present. On Unix this means that $no_file
+true makes this return ( '', $path, '' ).
+
+The directory portion may or may not be returned with a trailing '/'.
+
+The results can be passed to L</catpath()> to get back a path equivalent to
+(usually identical to) the original path.
+
+=item splitdir
+
+The opposite of L</catdir()>.
+
+    @dirs = File::Spec->splitdir( $directories );
+
+$directories must be only the directory portion of the path on systems 
+that have the concept of a volume or that have path syntax that differentiates
+files from directories.
+
+Unlike just splitting the directories on the separator, empty
+directory names (C<''>) can be returned, because these are significant
+on some OSs.
+
+=item catpath()
+
+Takes volume, directory and file portions and returns an entire path. Under
+Unix, $volume is ignored, and directory and file are catenated.  A '/' is
+inserted if need be.  On other OSs, $volume is significant.
+
+    $full_path = File::Spec->catpath( $volume, $directory, $file );
+
+=item abs2rel
+
+Takes a destination path and an optional base path returns a relative path
+from the base path to the destination path:
+
+    $rel_path = File::Spec->abs2rel( $path ) ;
+    $rel_path = File::Spec->abs2rel( $path, $base ) ;
+
+If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative, 
+then it is converted to absolute form using L</rel2abs()>. This means that it
+is taken to be relative to L<cwd()|Cwd>.
+
+On systems with the concept of a volume, this assumes that both paths 
+are on the $destination volume, and ignores the $base volume. 
+
+On systems that have a grammar that indicates filenames, this ignores the 
+$base filename as well. Otherwise all path components are assumed to be
+directories.
+
+If $path is relative, it is converted to absolute form using L</rel2abs()>.
+This means that it is taken to be relative to L<cwd()|Cwd>.
+
+No checks against the filesystem are made.  On VMS, there is
+interaction with the working environment, as logicals and
+macros are expanded.
+
+Based on code written by Shigio Yamaguchi.
+
+=item rel2abs()
+
+Converts a relative path to an absolute path. 
+
+    $abs_path = File::Spec->rel2abs( $path ) ;
+    $abs_path = File::Spec->rel2abs( $path, $base ) ;
+
+If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative, 
+then it is converted to absolute form using L</rel2abs()>. This means that it
+is taken to be relative to L<cwd()|Cwd>.
+
+On systems with the concept of a volume, this assumes that both paths 
+are on the $base volume, and ignores the $path volume. 
+
+On systems that have a grammar that indicates filenames, this ignores the 
+$base filename as well. Otherwise all path components are assumed to be
+directories.
+
+If $path is absolute, it is cleaned up and returned using L</canonpath()>.
+
+No checks against the filesystem are made.  On VMS, there is
+interaction with the working environment, as logicals and
+macros are expanded.
+
+Based on code written by Shigio Yamaguchi.
+
+=back
+
+For further information, please see L<File::Spec::Unix>,
+L<File::Spec::Mac>, L<File::Spec::OS2>, L<File::Spec::Win32>, or
+L<File::Spec::VMS>.
 
 =head1 SEE ALSO
 
-File::Spec::Unix, File::Spec::Mac, File::Spec::OS2, File::Spec::Win32,
-File::Spec::VMS, File::Spec::Functions, ExtUtils::MakeMaker
+L<File::Spec::Unix>, L<File::Spec::Mac>, L<File::Spec::OS2>,
+L<File::Spec::Win32>, L<File::Spec::VMS>, L<File::Spec::Functions>,
+L<ExtUtils::MakeMaker>
 
 =head1 AUTHORS
 
-Kenneth Albanowski <F<[email protected]>>, Andy Dougherty
-<F<[email protected]>>, Andreas KE<ouml>nig
-<F<[email protected]>>, Tim Bunce <F<[email protected]>>. VMS
-support by Charles Bailey <F<[email protected]>>.  OS/2 support by
-Ilya Zakharevich <F<[email protected]>>. Mac support by Paul Schinder
-<F<[email protected]>>.  abs2rel() and rel2abs() written by
-Shigio Yamaguchi <F<[email protected]>>, modified by Barrie Slaymaker
-<F<[email protected]>>.  splitpath(), splitdir(), catpath() and catdir()
-by Barrie Slaymaker.
+Kenneth Albanowski <[email protected]>, Andy Dougherty
+<[email protected]>, Andreas KE<ouml>nig
+<[email protected]>, Tim Bunce <[email protected].
+VMS support by Charles Bailey <[email protected]>.
+OS/2 support by Ilya Zakharevich <[email protected]>.
+Mac support by Paul Schinder <[email protected]>, and Thomas Wegner
+<[email protected]>.  abs2rel() and rel2abs() written by Shigio
+Yamaguchi <[email protected]>, modified by Barrie Slaymaker
+<[email protected]>.  splitpath(), splitdir(), catpath() and
+catdir() by Barrie Slaymaker.

==== //depot/maint-5.6/macperl/lib/File/Spec/Epoc.pm#2 (text) ====
Index: perl/lib/File/Spec/Epoc.pm
--- perl/lib/File/Spec/Epoc.pm.~1~	Mon Oct 22 13:30:06 2001
+++ perl/lib/File/Spec/Epoc.pm	Mon Oct 22 13:30:06 2001
@@ -24,7 +24,7 @@
 [email protected]
 
 
-=over
+=over 4
 
 =item devnull
 
@@ -62,11 +62,12 @@
 there is no search path supported, it returns undef, sorry.
 
 =cut
+
 sub path {
     return undef;
 }
 
-=item canonpath
+=item canonpath()
 
 No physical check on the filesystem, but a logical cleanup of a
 path. On UNIX eliminated successive slashes and successive "/.".
@@ -133,7 +134,7 @@
 
 =item splitdir
 
-The opposite of L</catdir()>.
+The opposite of L<catdir()|File::Spec/catdir()>.
 
     @dirs = File::Spec->splitdir( $directories );
 
@@ -220,9 +221,9 @@
     $rel_path = File::Spec->abs2rel( $destination ) ;
     $rel_path = File::Spec->abs2rel( $destination, $base ) ;
 
-If $base is not present or '', then L</cwd()> is used. If $base is relative, 
+If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative, 
 then it is converted to absolute form using L</rel2abs()>. This means that it
-is taken to be relative to L<cwd()>.
+is taken to be relative to L<cwd()|Cwd>.
 
 On systems with the concept of a volume, this assumes that both paths 
 are on the $destination volume, and ignores the $base volume.
@@ -232,7 +233,7 @@
 directories.
 
 If $path is relative, it is converted to absolute form using L</rel2abs()>.
-This means that it is taken to be relative to L</cwd()>.
+This means that it is taken to be relative to L<cwd()|Cwd>.
 
 Based on code written by Shigio Yamaguchi.
 
@@ -310,16 +311,16 @@
     ) ;
 }
 
-=item rel2abs
+=item rel2abs()
 
 Converts a relative path to an absolute path. 
 
     $abs_path = File::Spec->rel2abs( $destination ) ;
     $abs_path = File::Spec->rel2abs( $destination, $base ) ;
 
-If $base is not present or '', then L<cwd()> is used. If $base is relative, 
+If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative, 
 then it is converted to absolute form using L</rel2abs()>. This means that it
-is taken to be relative to L</cwd()>.
+is taken to be relative to L<cwd()|Cwd>.
 
 Assumes that both paths are on the $base volume, and ignores the 
 $destination volume. 

==== //depot/maint-5.6/macperl/lib/File/Spec/Functions.pm#2 (text) ====
Index: perl/lib/File/Spec/Functions.pm
--- perl/lib/File/Spec/Functions.pm.~1~	Mon Oct 22 13:30:06 2001
+++ perl/lib/File/Spec/Functions.pm	Mon Oct 22 13:30:06 2001
@@ -3,9 +3,9 @@
 use File::Spec;
 use strict;
 
-use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
+our (@ISA,@EXPORT,@EXPORT_OK,%EXPORT_TAGS,$VERSION);
 
-$VERSION = '1.1';
+$VERSION = '1.2';
 
 require Exporter;
 

==== //depot/maint-5.6/macperl/lib/File/Spec/Mac.pm#3 (text) ====
Index: perl/lib/File/Spec/Mac.pm
--- perl/lib/File/Spec/Mac.pm.~1~	Mon Oct 22 13:30:06 2001
+++ perl/lib/File/Spec/Mac.pm	Mon Oct 22 13:30:06 2001
@@ -4,7 +4,7 @@
 use vars qw(@ISA $VERSION);
 require File::Spec::Unix;
 
-$VERSION = '1.2';
+$VERSION = '1.3';
 
 @ISA = qw(File::Spec::Unix);
 
@@ -12,7 +12,7 @@
 
 =head1 NAME
 
-File::Spec::Mac - File::Spec for MacOS
+File::Spec::Mac - File::Spec for Mac OS (Classic)
 
 =head1 SYNOPSIS
 
@@ -28,7 +28,7 @@
 
 =item canonpath
 
-On MacOS, there's nothing to be done.  Returns what it's given.
+On Mac OS, there's nothing to be done. Returns what it's given.
 
 =cut
 
@@ -37,12 +37,20 @@
     return $path;
 }
 
-=item catdir
+=item catdir()
 
 Concatenate two or more directory names to form a path separated by colons
-(":") ending with a directory.  Automatically puts a trailing ":" on the
-end of the complete path, because that's what's done in MacPerl's
-environment and helps to distinguish a file path from a directory path.
+(":") ending with a directory. Resulting paths are B<relative> by default,
+but can be forced to be absolute (but avoid this, see below). Automatically
+puts a trailing ":" on the end of the complete path, because that's what's
+done in MacPerl's environment and helps to distinguish a file path from a
+directory path.
+
+B<IMPORTANT NOTE:> Beginning with version 1.3 of this module, the resulting
+path is relative by default and I<not> absolute. This descision was made due
+to portability reasons. Since C<File::Spec-E<gt>catdir()> returns relative paths
+on all other operating systems, it will now also follow this convention on Mac
+OS. Note that this may break some existing scripts.
 
 The intended purpose of this routine is to concatenate I<directory names>.
 But because of the nature of Macintosh paths, some additional possibilities
@@ -51,100 +59,245 @@
 I<paths> instead of directory names (strictly speaking, a string like ":a"
 is a path, but not a name, since it contains a punctuation character ":").
 
-Here are the rules that are used: Each argument has its trailing ":" removed.
-Each argument, except the first, has its leading ":" removed.  They are then
-joined together by a ":" and a trailing ":" is added to the path.
-
 So, beside calls like
 
-    File::Spec->catdir("a") = "a:"
-    File::Spec->catdir("a","b") = "a:b:"
-    File::Spec->catdir("","a","b") = ":a:b:"
-    File::Spec->catdir("a","","b") = "a::b:"
-    File::Spec->catdir("") = ":"
-    File::Spec->catdir("a","b","") = "a:b::"     (!)
-    File::Spec->catdir() = ""                    (special case)
+    catdir("a") = ":a:"
+    catdir("a","b") = ":a:b:"
+    catdir() = ""                    (special case)
 
 calls like the following
 
-    File::Spec->catdir("a:",":b") = "a:b:"
-    File::Spec->catdir("a:b:",":c") = "a:b:c:"
-    File::Spec->catdir("a:","b") = "a:b:"
-    File::Spec->catdir("a",":b") = "a:b:"
-    File::Spec->catdir(":a","b") = ":a:b:"
-    File::Spec->catdir("","",":a",":b") = "::a:b:"
-    File::Spec->catdir("",":a",":b") = ":a:b:" (!)
-    File::Spec->catdir(":") = ":"
+    catdir(":a:") = ":a:"
+    catdir(":a","b") = ":a:b:"
+    catdir(":a:","b") = ":a:b:"
+    catdir(":a:",":b:") = ":a:b:"
+    catdir(":") = ":"
 
 are allowed.
 
-To get a path beginning with a ":" (a relative path), put a "" as the first
-argument. Beginning the first argument with a ":" (e.g. ":a") will also work
-(see the examples).
+Here are the rules that are used in C<catdir()>; note that we try to be as
+compatible as possible to Unix:
+
+=over 2
+
+=item 1.
+
+The resulting path is relative by default, i.e. the resulting path will have a
+leading colon.
+
+=item 2.
+
+A trailing colon is added automatically to the resulting path, to denote a
+directory.
+
+=item 3.
+
+Generally, each argument has one leading ":" and one trailing ":"
+removed (if any). They are then joined together by a ":". Special
+treatment applies for arguments denoting updir paths like "::lib:",
+see (4), or arguments consisting solely of colons ("colon paths"),
+see (5).
+
+=item 4.
+
+When an updir path like ":::lib::" is passed as argument, the number
+of directories to climb up is handled correctly, not removing leading
+or trailing colons when necessary. E.g.
+
+    catdir(":::a","::b","c")    = ":::a::b:c:"
+    catdir(":::a::","::b","c")  = ":::a:::b:c:"
+
+=item 5.
+
+Adding a colon ":" or empty string "" to a path at I<any> position
+doesn't alter the path, i.e. these arguments are ignored. (When a ""
+is passed as the first argument, it has a special meaning, see
+(6)). This way, a colon ":" is handled like a "." (curdir) on Unix,
+while an empty string "" is generally ignored (see
+C<Unix-E<gt>canonpath()> ). Likewise, a "::" is handled like a ".."
+(updir), and a ":::" is handled like a "../.." etc.  E.g.
+
+    catdir("a",":",":","b")   = ":a:b:"
+    catdir("a",":","::",":b") = ":a::b:"
+
+=item 6.
+
+If the first argument is an empty string "" or is a volume name, i.e. matches
+the pattern /^[^:]+:/, the resulting path is B<absolute>.
+
+=item 7.
+
+Passing an empty string "" as the first argument to C<catdir()> is
+like passingC<File::Spec-E<gt>rootdir()> as the first argument, i.e.
+
+    catdir("","a","b")          is the same as
+
+    catdir(rootdir(),"a","b").
+
+This is true on Unix, where C<catdir("","a","b")> yields "/a/b" and
+C<rootdir()> is "/". Note that C<rootdir()> on Mac OS is the startup
+volume, which is the closest in concept to Unix' "/". This should help
+to run existing scripts originally written for Unix.
+
+=item 8.
+
+For absolute paths, some cleanup is done, to ensure that the volume
+name isn't immediately followed by updirs. This is invalid, because
+this would go beyond "root". Generally, these cases are handled like
+their Unix counterparts:
 
-Since Mac OS (Classic) uses the concept of volumes, there is an ambiguity:
-Does the first argument in
+ Unix:
+    Unix->catdir("","")                 =  "/"
+    Unix->catdir("",".")                =  "/"
+    Unix->catdir("","..")               =  "/"              # can't go beyond root
+    Unix->catdir("",".","..","..","a")  =  "/a"
+ Mac:
+    Mac->catdir("","")                  =  rootdir()         # (e.g. "HD:")
+    Mac->catdir("",":")                 =  rootdir()
+    Mac->catdir("","::")                =  rootdir()         # can't go beyond root
+    Mac->catdir("",":","::","::","a")   =  rootdir() . "a:"  # (e.g. "HD:a:")
 
-    File::Spec->catdir("LWP","Protocol");
+However, this approach is limited to the first arguments following
+"root" (again, see C<Unix-E<gt>canonpath()> ). If there are more
+arguments that move up the directory tree, an invalid path going
+beyond root can be created.
 
-denote a volume or a directory, i.e. should the path be relative or absolute?
-There is no way of telling except by checking for the existence of "LWP:" (a
-volume) or ":LWP" (a directory), but those checks aren't made here. Thus, according
-to the above rules, the path "LWP:Protocol:" will be returned, which, considered
-alone, is an absolute path, although the volume "LWP:" may not exist. Hence, don't
-forget to put a ":" in the appropriate place in the path if you want to
-distinguish unambiguously. (Remember that a valid relative path should always begin
-with a ":", unless you are specifying a file or a directory that resides in the
-I<current> directory. In that case, the leading ":" is not mandatory.)
+=back
 
-With version 1.2 of File::Spec, there's a new method called C<catpath>, that
-takes volume, directory and file portions and returns an entire path (see below).
-While C<catdir> is still suitable for the concatenation of I<directory names>,
-you should consider using C<catpath> to concatenate I<volume names> and
-I<directory paths>, because it avoids any ambiguities. E.g.
+As you've seen, you can force C<catdir()> to create an absolute path
+by passing either an empty string or a path that begins with a volume
+name as the first argument. However, you are strongly encouraged not
+to do so, since this is done only for backward compatibility. Newer
+versions of File::Spec come with a method called C<catpath()> (see
+below), that is designed to offer a portable solution for the creation
+of absolute paths.  It takes volume, directory and file portions and
+returns an entire path. While C<catdir()> is still suitable for the
+concatenation of I<directory names>, you are encouraged to use
+C<catpath()> to concatenate I<volume names> and I<directory
+paths>. E.g.
 
-    $dir      = File::Spec->catdir("LWP","Protocol");
-    $abs_path = File::Spec->catpath("MacintoshHD:", $dir, "");
+    $dir      = File::Spec->catdir("tmp","sources");
+    $abs_path = File::Spec->catpath("MacintoshHD:", $dir,"");
 
 yields
 
-    "MacintoshHD:LWP:Protocol:" .
+    "MacintoshHD:tmp:sources:" .
 
-
 =cut
 
 sub catdir {
-    my $self = shift;
-    return '' unless @_;
-    my @args = @_;
-    my $result = shift @args;
-    #  To match the actual end of the string,
-    #  not ignoring newline, you can use \Z(?!\n).
-    $result =~ s/:\Z(?!\n)//;
-    foreach (@args) {
-	s/:\Z(?!\n)//;
-	s/^://s;
-	$result .= ":$_";
-    }
-    return "$result:";
+	my $self = shift;
+	return '' unless @_;
+	my @args = @_;
+	my $first_arg;
+	my $relative;
+
+	# take care of the first argument
+
+	if ($args[0] eq '')  { # absolute path, rootdir
+		shift @args;
+		$relative = 0;
+		$first_arg = $self->rootdir;
+
+	} elsif ($args[0] =~ /^[^:]+:/) { # absolute path, volume name
+		$relative = 0;
+		$first_arg = shift @args;
+		# add a trailing ':' if need be (may be it's a path like HD:dir)
+		$first_arg = "$first_arg:" unless ($first_arg =~ /:\Z(?!\n)/);
+
+	} else { # relative path
+		$relative = 1;
+		if ( $args[0] =~ /^::+\Z(?!\n)/ ) {
+			# updir colon path ('::', ':::' etc.), don't shift
+			$first_arg = ':';
+		} elsif ($args[0] eq ':') {
+			$first_arg = shift @args;
+		} else {
+			# add a trailing ':' if need be
+			$first_arg = shift @args;
+			$first_arg = "$first_arg:" unless ($first_arg =~ /:\Z(?!\n)/);
+		}
+	}
+
+	# For all other arguments,
+	# (a) ignore arguments that equal ':' or '',
+	# (b) handle updir paths specially:
+	#     '::' 			-> concatenate '::'
+	#     '::' . '::' 	-> concatenate ':::' etc.
+	# (c) add a trailing ':' if need be
+
+	my $result = $first_arg;
+	while (@args) {
+		my $arg = shift @args;
+		unless (($arg eq '') || ($arg eq ':')) {
+			if ($arg =~ /^::+\Z(?!\n)/ ) { # updir colon path like ':::'
+				my $updir_count = length($arg) - 1;
+				while ((@args) && ($args[0] =~ /^::+\Z(?!\n)/) ) { # while updir colon path
+					$arg = shift @args;
+					$updir_count += (length($arg) - 1);
+				}
+				$arg = (':' x $updir_count);
+			} else {
+				$arg =~ s/^://s; # remove a leading ':' if any
+				$arg = "$arg:" unless ($arg =~ /:\Z(?!\n)/); # ensure trailing ':'
+			}
+			$result .= $arg;
+		}#unless
+	}
+
+	if ( ($relative) && ($result !~ /^:/) ) {
+		# add a leading colon if need be
+		$result = ":$result";
+	}
+
+	unless ($relative) {
+		# remove updirs immediately following the volume name
+		$result =~ s/([^:]+:)(:*)(.*)\Z(?!\n)/$1$3/;
+	}
+
+	return $result;
 }
 
 =item catfile
 
 Concatenate one or more directory names and a filename to form a
-complete path ending with a filename.  Since this uses catdir, the
-same caveats apply.  Note that the leading ":" is removed from the
-filename, so that
+complete path ending with a filename. Resulting paths are B<relative>
+by default, but can be forced to be absolute (but avoid this).
+
+B<IMPORTANT NOTE:> Beginning with version 1.3 of this module, the
+resulting path is relative by default and I<not> absolute. This
+descision was made due to portability reasons. Since
+C<File::Spec-E<gt>catfile()> returns relative paths on all other
+operating systems, it will now also follow this convention on Mac OS.
+Note that this may break some existing scripts.
+
+The last argument is always considered to be the file portion. Since
+C<catfile()> uses C<catdir()> (see above) for the concatenation of the
+directory portions (if any), the following with regard to relative and
+absolute paths is true:
+
+    catfile("")     = ""
+    catfile("file") = "file"
+
+but
+
+    catfile("","")        = rootdir()         # (e.g. "HD:")
+    catfile("","file")    = rootdir() . file  # (e.g. "HD:file")
+    catfile("HD:","file") = "HD:file"
+
+This means that C<catdir()> is called only when there are two or more
+arguments, as one might expect.
+
+Note that the leading ":" is removed from the filename, so that
 
-    File::Spec->catfile("a", "b", "file"); # = "a:b:file"
+    catfile("a","b","file")  = ":a:b:file"    and
 
-and
+    catfile("a","b",":file") = ":a:b:file"
 
-    File::Spec->catfile("a", "b", ":file"); # = "a:b:file"
+give the same answer.
 
-give the same answer, as one might expect. To concatenate I<volume names>,
-I<directory paths> and I<filenames>, you should consider using C<catpath>
-(see below).
+To concatenate I<volume names>, I<directory paths> and I<filenames>,
+you are encouraged to use C<catpath()> (see below).
 
 =cut
 
@@ -190,7 +343,7 @@
 
 sub rootdir {
 #
-#  There's no real root directory on MacOS.  The name of the startup
+#  There's no real root directory on Mac OS. The name of the startup
 #  volume is returned, since that's the closest in concept.
 #
     require Mac::Files;
@@ -231,13 +384,13 @@
 =item file_name_is_absolute
 
 Takes as argument a path and returns true, if it is an absolute path.
-This does not consult the local filesystem. If
-the path has a leading ":", it's a relative path. Otherwise, it's an
+If the path has a leading ":", it's a relative path. Otherwise, it's an
 absolute path, unless the path doesn't contain any colons, i.e. it's a name
 like "a". In this particular case, the path is considered to be relative
 (i.e. it is considered to be a filename). Use ":" in the appropriate place
 in the path if you want to distinguish unambiguously. As a special case,
-the filename '' is always considered to be absolute.
+the filename '' is always considered to be absolute. Note that with version
+1.2 of File::Spec::Mac, this does no longer consult the local filesystem.
 
 E.g.
 
@@ -263,7 +416,7 @@
 =item path
 
 Returns the null list for the MacPerl application, since the concept is
-usually meaningless under MacOS. But if you're using the MacPerl tool under
+usually meaningless under Mac OS. But if you're using the MacPerl tool under
 MPW, it gives back $ENV{Commands} suitably split, as is done in
 :lib:ExtUtils:MM_Mac.pm.
 
@@ -291,9 +444,9 @@
 The volume portion is always returned with a trailing ":". The directory portion
 is always returned with a leading (to denote a relative path) and a trailing ":"
 (to denote a directory). The file portion is always returned I<without> a leading ":".
-Empty portions are returned as "".
+Empty portions are returned as empty string ''.
 
-The results can be passed to L</catpath()> to get back a path equivalent to
+The results can be passed to C<catpath()> to get back a path equivalent to
 (usually identical to) the original path.
 
 
@@ -334,13 +487,13 @@
 
 =item splitdir
 
-The opposite of L</catdir()>.
+The opposite of C<catdir()>.
 
     @dirs = File::Spec->splitdir( $directories );
 
-$directories must be only the directory portion of the path on systems
+$directories should be only the directory portion of the path on systems
 that have the concept of a volume or that have path syntax that differentiates
-files from directories.
+files from directories. Consider using C<splitpath()> otherwise.
 
 Unlike just splitting the directories on the separator, empty directory names
 (C<"">) can be returned. Since C<catdir()> on Mac OS always appends a trailing
@@ -354,7 +507,7 @@
 
 yield:
 
-    ( "", "a", "b", "", "c")
+    ( "a", "b", "::", "c")
 
 while
 
@@ -362,42 +515,44 @@
 
 yields:
 
-    ( "", "a", "b", "", "c", "")
+    ( "a", "b", "::", "c", "::")
 
 
 =cut
 
 sub splitdir {
-    my ($self,$directories) = @_ ;
+	my ($self, $path) = @_;
+	my @result = ();
+	my ($head, $sep, $tail, $volume, $directories);
+
+	return ('') if ( (!defined($path)) || ($path eq '') );
+	return (':') if ($path eq ':');
 
-    if ($directories =~ /^:*\Z(?!\n)/) {
-	# dir is an empty string or a colon path like ':', i.e. the
-	# current dir, or '::', the parent dir, etc. We return that
-	# dir (as is done on Unix).
-	return $directories;
-    }
+	( $volume, $sep, $directories ) = $path =~ m|^((?:[^:]+:)?)(:*)(.*)|s;
 
-    # remove a trailing colon, if any (this way, splitdir is the
-    # opposite of catdir, which automatically appends a ':')
-    $directories =~ s/:\Z(?!\n)//;
+	# deprecated, but handle it correctly
+	if ($volume) {
+		push (@result, $volume);
+		$sep .= ':';
+	}
 
-    #
-    # split() likes to forget about trailing null fields, so here we
-    # check to be sure that there will not be any before handling the
-    # simple case.
-    #
-    if ( $directories !~ m@:\Z(?!\n)@ ) {
-        return split( m@:@, $directories );
-    }
-    else {
-        #
-        # since there was a trailing separator, add a file name to the end,
-        # then do the split, then replace it with ''.
-        #
-        my( @directories )= split( m@:@, "${directories}dummy" ) ;
-        $directories[ $#directories ]= '' ;
-        return @directories ;
-    }
+	while ($sep || $directories) {
+		if (length($sep) > 1) {
+			my $updir_count = length($sep) - 1;
+			for (my $i=0; $i<$updir_count; $i++) {
+				# push '::' updir_count times;
+				# simulate Unix '..' updirs
+				push (@result, '::');
+			}
+		}
+		$sep = '';
+		if ($directories) {
+			( $head, $sep, $tail ) = $directories =~ m|^((?:[^:]+)?)(:*)(.*)|s;
+			push (@result, $head);
+			$directories = $tail;
+		}
+	}
+	return @result;
 }
 
 
@@ -512,9 +667,9 @@
     my $base_dirs = ($self->splitpath( $base ))[1] ;
 
     # Now, remove all leading components that are the same
-    my @pathchunks = $self->splitdir( $path_dirs );
-    my @basechunks = $self->splitdir( $base_dirs );
-
+    my @pathchunks = $self->splitdir( $path_dirs ); # expected: ('')
+    my @basechunks = $self->splitdir( $base_dirs ); # expected: (d1, d2)
+	
     while ( @pathchunks &&
 	    @basechunks &&
 	    lc( $pathchunks[0] ) eq lc( $basechunks[0] ) ) {
@@ -523,12 +678,13 @@
     }
 
     # @pathchunks now has the directories to descend in to.
-    $path_dirs = $self->catdir( @pathchunks );
+    # ensure relative path, even if @pathchunks is empty
+    $path_dirs = $self->catdir( ':', @pathchunks );
 
     # @basechunks now contains the number of directories to climb out of.
     $base_dirs = (':' x @basechunks) . ':' ;
 
-    return $self->catpath( '', $base_dirs . $path_dirs, $path_file ) ;
+    return $self->catpath( '', $self->catdir( $base_dirs, $path_dirs ), $path_file ) ;
 }
 
 =item rel2abs
@@ -591,7 +747,7 @@
 
 =head1 AUTHORS
 
-See the authors list in L<File::Spec>. Mac OS support by Paul Schinder
+See the authors list in I<File::Spec>. Mac OS support by Paul Schinder
 <[email protected]> and Thomas Wegner <[email protected]>.
 
 

==== //depot/maint-5.6/macperl/lib/File/Spec/Unix.pm#2 (text) ====
Index: perl/lib/File/Spec/Unix.pm
--- perl/lib/File/Spec/Unix.pm.~1~	Mon Oct 22 13:30:06 2001
+++ perl/lib/File/Spec/Unix.pm	Mon Oct 22 13:30:06 2001
@@ -1,15 +1,15 @@
 package File::Spec::Unix;
 
 use strict;
-use vars qw($VERSION);
+our($VERSION);
 
-$VERSION = '1.2';
+$VERSION = '1.3';
 
 use Cwd;
 
 =head1 NAME
 
-File::Spec::Unix - methods used by File::Spec
+File::Spec::Unix - File::Spec for Unix, base for other File::Spec modules
 
 =head1 SYNOPSIS
 
@@ -17,16 +17,18 @@
 
 =head1 DESCRIPTION
 
-Methods for manipulating file specifications.
+Methods for manipulating file specifications.  Other File::Spec
+modules, such as File::Spec::Mac, inherit from File::Spec::Unix and
+override specific methods.
 
 =head1 METHODS
 
 =over 2
 
-=item canonpath
+=item canonpath()
 
 No physical check on the filesystem, but a logical cleanup of a
-path. On UNIX eliminated successive slashes and successive "/.".
+path. On UNIX eliminates successive slashes and successive "/.".
 
     $cpath = File::Spec->canonpath( $path ) ;
 
@@ -34,15 +36,21 @@
 
 sub canonpath {
     my ($self,$path) = @_;
+    
+    # Handle POSIX-style node names beginning with double slash
+    my $node = '';
+    if ( $^O =~ m/^(?:qnx|nto)$/ && $path =~ s:^(//[^/]+)(/|\z):/:s ) {
+      $node = $1;
+    }
     $path =~ s|/+|/|g unless($^O eq 'cygwin');     # xx////xx  -> xx/xx
-    $path =~ s|(/\.)+/|/|g;                        # xx/././xx -> xx/xx
+    $path =~ s@(/\.)+(/|\Z(?!\n))@/@g;             # xx/././xx -> xx/xx
     $path =~ s|^(\./)+||s unless $path eq "./";    # ./xx      -> xx
     $path =~ s|^/(\.\./)+|/|s;                     # /../../xx -> xx
     $path =~ s|/\Z(?!\n)|| unless $path eq "/";          # xx/       -> xx
-    return $path;
+    return "$node$path";
 }
 
-=item catdir
+=item catdir()
 
 Concatenate two or more directory names to form a complete path ending
 with a directory. But remove the trailing slash from the resulting
@@ -167,9 +175,8 @@
 
 Takes as argument a path and returns true if it is an absolute path.
 
-This does not consult the local filesystem on Unix, Win32, or OS/2.  It
-does sometimes on MacOS (see L<File::Spec::MacOS/file_name_is_absolute>).
-It does consult the working environment for VMS (see
+This does not consult the local filesystem on Unix, Win32, OS/2 or Mac 
+OS (Classic).  It does consult the working environment for VMS (see
 L<File::Spec::VMS/file_name_is_absolute>).
 
 =cut
@@ -252,7 +259,7 @@
 
 Unlike just splitting the directories on the separator, empty
 directory names (C<''>) can be returned, because these are significant
-on some OSs (e.g. MacOS).
+on some OSs.
 
 On Unix,
 
@@ -286,7 +293,7 @@
 }
 
 
-=item catpath
+=item catpath()
 
 Takes volume, directory and file portions and returns an entire path. Under
 Unix, $volume is ignored, and directory and file are catenated.  A '/' is
@@ -319,9 +326,9 @@
     $rel_path = File::Spec->abs2rel( $path ) ;
     $rel_path = File::Spec->abs2rel( $path, $base ) ;
 
-If $base is not present or '', then L<cwd()> is used. If $base is relative, 
+If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative, 
 then it is converted to absolute form using L</rel2abs()>. This means that it
-is taken to be relative to L<cwd()>.
+is taken to be relative to L<cwd()|Cwd>.
 
 On systems with the concept of a volume, this assumes that both paths 
 are on the $destination volume, and ignores the $base volume. 
@@ -331,11 +338,9 @@
 directories.
 
 If $path is relative, it is converted to absolute form using L</rel2abs()>.
-This means that it is taken to be relative to L<cwd()>.
+This means that it is taken to be relative to L<cwd()|Cwd>.
 
-No checks against the filesystem are made on most systems.  On MacOS,
-the filesystem may be consulted (see
-L<File::Spec::MacOS/file_name_is_absolute>).  On VMS, there is
+No checks against the filesystem are made.  On VMS, there is
 interaction with the working environment, as logicals and
 macros are expanded.
 
@@ -393,16 +398,16 @@
     return $self->canonpath( $path ) ;
 }
 
-=item rel2abs
+=item rel2abs()
 
 Converts a relative path to an absolute path. 
 
     $abs_path = File::Spec->rel2abs( $path ) ;
     $abs_path = File::Spec->rel2abs( $path, $base ) ;
 
-If $base is not present or '', then L<cwd()> is used. If $base is relative, 
+If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative, 
 then it is converted to absolute form using L</rel2abs()>. This means that it
-is taken to be relative to L<cwd()>.
+is taken to be relative to L<cwd()|Cwd>.
 
 On systems with the concept of a volume, this assumes that both paths 
 are on the $base volume, and ignores the $path volume. 
@@ -413,9 +418,7 @@
 
 If $path is absolute, it is cleaned up and returned using L</canonpath()>.
 
-No checks against the filesystem are made on most systems.  On MacOS,
-the filesystem may be consulted (see
-L<File::Spec::MacOS/file_name_is_absolute>).  On VMS, there is
+No checks against the filesystem are made.  On VMS, there is
 interaction with the working environment, as logicals and
 macros are expanded.
 

==== //depot/maint-5.6/macperl/lib/File/Spec/VMS.pm#2 (text) ====
Index: perl/lib/File/Spec/VMS.pm
--- perl/lib/File/Spec/VMS.pm.~1~	Mon Oct 22 13:30:06 2001
+++ perl/lib/File/Spec/VMS.pm	Mon Oct 22 13:30:06 2001
@@ -4,7 +4,7 @@
 use vars qw(@ISA $VERSION);
 require File::Spec::Unix;
 
-$VERSION = '1.1';
+$VERSION = '1.2';
 
 @ISA = qw(File::Spec::Unix);
 
@@ -26,7 +26,7 @@
 there. This package overrides the implementation of these methods, not
 the semantics.
 
-=over
+=over 4
 
 =item eliminate_macros
 
@@ -138,7 +138,7 @@
 
 =head2 Methods always loaded
 
-=over
+=over 4
 
 =item canonpath (override)
 
@@ -156,8 +156,9 @@
       else          { return vmsify($path);  }
     }
     else {
+      $path =~ s/([\[<])000000\./$1/g;                  # [000000.foo     ==> [foo
+      $path =~ s/([^-]+)\.000000([\]\>])/$1$2/g;        # foo.000000]     ==> foo]
       $path =~ s-\]\[--g;  $path =~ s/><//g;            # foo.][bar       ==> foo.bar
-      $path =~ s/([\[<])000000\./$1/;                   # [000000.foo     ==> foo
       1 while $path =~ s{([\[<-])\.-}{$1-};             # [.-.-           ==> [--
       $path =~ s/\.[^\[<\.]+\.-([\]\>])/$1/;            # bar.foo.-]      ==> bar]
       $path =~ s/([\[<])(-+)/$1 . "\cx" x length($2)/e; # encode leading '-'s
@@ -405,6 +406,7 @@
     # Figure out the effective $base and clean it up.
     if ( !defined( $base ) || $base eq '' ) {
         $base = cwd() ;
+        $base = $self->canonpath( $base ) ;
     }
     elsif ( ! $self->file_name_is_absolute( $base ) ) {
         $base = $self->rel2abs( $base ) ;
@@ -427,7 +429,9 @@
 
     # Now, remove all leading components that are the same
     my @pathchunks = $self->splitdir( $path_directories );
+    unshift(@pathchunks,'000000') unless $pathchunks[0] eq '000000';
     my @basechunks = $self->splitdir( $base_directories );
+    unshift(@basechunks,'000000') unless $basechunks[0] eq '000000';
 
     while ( @pathchunks && 
             @basechunks && 

==== //depot/maint-5.6/macperl/lib/File/Spec/Win32.pm#2 (text) ====
==== //depot/maint-5.6/macperl/t/lib/filespec.t#3 (xtext) ====
Index: perl/t/lib/filespec.t
--- perl/t/lib/filespec.t.~1~	Mon Oct 22 13:30:06 2001
+++ perl/t/lib/filespec.t	Mon Oct 22 13:30:06 2001
@@ -1,17 +1,53 @@
 #!./perl
 
 BEGIN {
-    $^O = '';
     chdir 't' if -d 't';
     @INC = '../lib';
 }
+# Grab all of the plain routines from File::Spec
+use File::Spec @File::Spec::EXPORT_OK ;
+
+require File::Spec::Unix ;
+require File::Spec::Win32 ;
+
+eval {
+   require VMS::Filespec ;
+} ;
+
+my $skip_exception = "Install VMS::Filespec (from vms/ext)" ;
+
+if ( $@ ) {
+   # Not pretty, but it allows testing of things not implemented soley
+   # on VMS.  It might be better to change File::Spec::VMS to do this,
+   # making it more usable when running on (say) Unix but working with
+   # VMS paths.
+   eval qq-
+      sub File::Spec::VMS::vmsify  { die "$skip_exception" }
+      sub File::Spec::VMS::unixify { die "$skip_exception" }
+      sub File::Spec::VMS::vmspath { die "$skip_exception" }
+   - ;
+   $INC{"VMS/Filespec.pm"} = 1 ;
+}
+require File::Spec::VMS ;
+
+require File::Spec::OS2 ;
+require File::Spec::Mac ;
 
+# $root is only needed by Mac OS tests; these particular
+# tests are skipped on other OSs
+my $root;
+if ($^O eq 'MacOS') {
+	push @INC, "::lib:$MacPerl::Architecture";
+	$root = File::Spec::Mac->rootdir();
+}
+
 # Each element in this array is a single test. Storing them this way makes
 # maintenance easy, and should be OK since perl should be pretty functional
 # before these tests are run.
 
 @tests = (
-# Function                      Expected
+# [ Function          ,            Expected          ,         Platform ]
+
 [ "Unix->catfile('a','b','c')", 'a/b/c'  ],
 
 [ "Unix->splitpath('file')",            ',,file'            ],
@@ -53,7 +89,10 @@
 
 [ "Unix->canonpath('')",                                      ''          ],
 [ "Unix->canonpath('///../../..//./././a//b/.././c/././')",   '/a/b/../c' ],
-[ "Unix->canonpath('/.')",                                    '/.'        ],
+[ "Unix->canonpath('/.')",                                    '/'         ],
+[ "Unix->canonpath('/./')",                                   '/'         ],
+[ "Unix->canonpath('/a/./')",                                 '/a'        ],
+[ "Unix->canonpath('/a/.')",                                  '/a'        ],
 
 [  "Unix->abs2rel('/t1/t2/t3','/t1/t2/t3')",          ''                   ],
 [  "Unix->abs2rel('/t1/t2/t4','/t1/t2/t3')",          '../t4'              ],
@@ -63,7 +102,7 @@
 #[ "Unix->abs2rel('../t4','/t1/t2/t3')",              '../t4'              ],
 [  "Unix->abs2rel('/','/t1/t2/t3')",                  '../../..'           ],
 [  "Unix->abs2rel('///','/t1/t2/t3')",                '../../..'           ],
-[  "Unix->abs2rel('/.','/t1/t2/t3')",                 '../../../.'         ],
+[  "Unix->abs2rel('/.','/t1/t2/t3')",                 '../../..'           ],
 [  "Unix->abs2rel('/./','/t1/t2/t3')",                '../../..'           ],
 #[ "Unix->abs2rel('../t4','/t1/t2/t3')",              '../t4'              ],
 
@@ -226,7 +265,7 @@
 [ "VMS->catdir('','-','','d3')",                                          '[-.d3]'            ],
 [ "VMS->catdir('dir.dir','d2.dir','d3.dir')",                             '[.dir.d2.d3]'        ],
 [ "VMS->catdir('[.name]')",                                               '[.name]'            ],
-[ "VMS->catdir('[.name]','[.name]')",                                     '[.name.name]'],    
+[ "VMS->catdir('[.name]','[.name]')",                                     '[.name.name]'],
 
 [  "VMS->abs2rel('node::volume:[t1.t2.t3]','[t1.t2.t3]')", ''                 ],
 [  "VMS->abs2rel('node::volume:[t1.t2.t4]','[t1.t2.t3]')", '[-.t4]'           ],
@@ -236,7 +275,7 @@
 [  "VMS->abs2rel('[t1.t2]file','[t1.t2.t3]')",             '[-]file'          ],
 [  "VMS->abs2rel('[t1.t2.t3.t4]','[t1.t2.t3]')",           '[t4]'             ],
 [  "VMS->abs2rel('[t4.t5.t6]','[t1.t2.t3]')",              '[---.t4.t5.t6]'   ],
-[ "VMS->abs2rel('[000000]','[t1.t2.t3]')",                 '[---.000000]'     ],
+[ "VMS->abs2rel('[000000]','[t1.t2.t3]')",                 '[---]'            ],
 [ "VMS->abs2rel('a:[t1.t2.t4]','[t1.t2.t3]')",             '[-.t4]'           ],
 [ "VMS->abs2rel('[a.-.b.c.-]','[t1.t2.t3]')",              '[---.b]'          ],
 
@@ -257,7 +296,7 @@
 
 [ "Mac->catpath('hd','','')",            'hd:'             ],
 [ "Mac->catpath('hd:','','')",           'hd:'             ],
-[ "Mac->catpath('hd:',':','')",          'hd:'             ], 
+[ "Mac->catpath('hd:',':','')",          'hd:'             ],
 [ "Mac->catpath('hd:','::','')",         'hd::'            ],
 
 [ "Mac->catpath('hd','','file')",       'hd:file'          ],
@@ -310,93 +349,99 @@
 [ "Mac->splitpath('hd::d1:d2:file')", 'hd:,::d1:d2:,file' ], # invalid path
 [ "Mac->splitpath('hd:file')",        'hd:,,file'         ],
 
+[ "Mac->splitdir()",                   ''            ],
 [ "Mac->splitdir('')",                 ''            ],
 [ "Mac->splitdir(':')",                ':'           ],
 [ "Mac->splitdir('::')",               '::'          ],
-[ "Mac->splitdir(':::')",              ':::'         ],
-[ "Mac->splitdir(':::d1:d2')",         ',,,d1,d2'    ],
+[ "Mac->splitdir(':::')",              '::,::'       ],
+[ "Mac->splitdir(':::d1:d2')",         '::,::,d1,d2' ],
 
-[ "Mac->splitdir(':d1:d2:d3::')",      ',d1,d2,d3,'  ],
-[ "Mac->splitdir(':d1:d2:d3:')",       ',d1,d2,d3'   ],
-[ "Mac->splitdir(':d1:d2:d3')",        ',d1,d2,d3'   ],
+[ "Mac->splitdir(':d1:d2:d3::')",      'd1,d2,d3,::'],
+[ "Mac->splitdir(':d1:d2:d3:')",       'd1,d2,d3'   ],
+[ "Mac->splitdir(':d1:d2:d3')",        'd1,d2,d3'   ],
 
-[ "Mac->splitdir('hd:d1:d2:::')",      'hd,d1,d2,,'  ],
-[ "Mac->splitdir('hd:d1:d2::')",       'hd,d1,d2,'   ],
-[ "Mac->splitdir('hd:d1:d2:')",        'hd,d1,d2'    ],
-[ "Mac->splitdir('hd:d1:d2')",         'hd,d1,d2'    ],
-[ "Mac->splitdir('hd:d1::d2::')",      'hd,d1,,d2,'  ],
+# absolute paths in splitdir() work, but you'd better use splitpath()
+[ "Mac->splitdir('hd:')",              'hd:'              ],
+[ "Mac->splitdir('hd::')",             'hd:,::'           ], # invalid path, but it works
+[ "Mac->splitdir('hd::d1:')",          'hd:,::,d1'        ], # invalid path, but it works
+[ "Mac->splitdir('hd:d1:d2:::')",      'hd:,d1,d2,::,::'  ],
+[ "Mac->splitdir('hd:d1:d2::')",       'hd:,d1,d2,::'     ],
+[ "Mac->splitdir('hd:d1:d2:')",        'hd:,d1,d2'        ],
+[ "Mac->splitdir('hd:d1:d2')",         'hd:,d1,d2'        ],
+[ "Mac->splitdir('hd:d1::d2::')",      'hd:,d1,::,d2,::'  ],
 
-[ "Mac->catdir()",                 ''            ],
-[ "Mac->catdir('')",               ':'           ],
-[ "Mac->catdir(':')",              ':'           ],
+[ "Mac->catdir()",                 ''             ],
+[ "Mac->catdir('')",               $root, 'MacOS' ], # skipped on other OS
+[ "Mac->catdir(':')",              ':'            ],
 
-[ "Mac->catdir('', '')",           '::'          ], # Hmm... ":" ? 
-[ "Mac->catdir('', ':')",          '::'          ], # Hmm... ":" ? 
-[ "Mac->catdir(':', ':')",         '::'          ], # Hmm... ":" ? 
-[ "Mac->catdir(':', '')",          '::'          ], # Hmm... ":" ? 
+[ "Mac->catdir('', '')",           $root, 'MacOS' ], # skipped on other OS
+[ "Mac->catdir('', ':')",          $root, 'MacOS' ], # skipped on other OS
+[ "Mac->catdir(':', ':')",         ':'            ],
+[ "Mac->catdir(':', '')",          ':'            ],
 
-[ "Mac->catdir('', '::')",         '::'          ],
-[ "Mac->catdir(':', '::')",        '::'          ], # but catdir('::', ':') is ':::'
+[ "Mac->catdir('', '::')",         $root, 'MacOS' ], # skipped on other OS
+[ "Mac->catdir(':', '::')",        '::'           ],
 
-[ "Mac->catdir('::', '')",         ':::'         ], # Hmm... "::" ? 
-[ "Mac->catdir('::', ':')",        ':::'         ], # Hmm... "::" ? 
+[ "Mac->catdir('::', '')",         '::'           ],
+[ "Mac->catdir('::', ':')",        '::'           ],
 
-[ "Mac->catdir('::', '::')",       ':::'         ], # ok
+[ "Mac->catdir('::', '::')",       ':::'          ],
 
-#
-# Unix counterparts:
-#
+[ "Mac->catdir(':d1')",                    ':d1:'        ],
+[ "Mac->catdir(':d1:')",                   ':d1:'        ],
+[ "Mac->catdir(':d1','d2')",               ':d1:d2:'     ],
+[ "Mac->catdir(':d1',':d2')",              ':d1:d2:'     ],
+[ "Mac->catdir(':d1',':d2:')",             ':d1:d2:'     ],
+[ "Mac->catdir(':d1',':d2::')",            ':d1:d2::'     ],
+[ "Mac->catdir(':',':d1',':d2')",          ':d1:d2:'     ],
+[ "Mac->catdir('::',':d1',':d2')",         '::d1:d2:'    ],
+[ "Mac->catdir('::','::',':d1',':d2')",    ':::d1:d2:'   ],
+[ "Mac->catdir(':',':',':d1',':d2')",      ':d1:d2:'     ],
+[ "Mac->catdir('::',':',':d1',':d2')",     '::d1:d2:'    ],
 
-# Unix catdir('.') =        "."
+[ "Mac->catdir('d1')",                    ':d1:'         ],
+[ "Mac->catdir('d1','d2','d3')",          ':d1:d2:d3:'   ],
+[ "Mac->catdir('d1','d2/','d3')",         ':d1:d2/:d3:'  ],
+[ "Mac->catdir('d1','',':d2')",           ':d1:d2:'      ],
+[ "Mac->catdir('d1',':',':d2')",          ':d1:d2:'      ],
+[ "Mac->catdir('d1','::',':d2')",         ':d1::d2:'     ],
+[ "Mac->catdir('d1',':::',':d2')",        ':d1:::d2:'    ],
+[ "Mac->catdir('d1','::','::',':d2')",    ':d1:::d2:'    ],
+[ "Mac->catdir('d1','d2')",               ':d1:d2:'      ],
+[ "Mac->catdir('d1','d2', '')",           ':d1:d2:'      ],
+[ "Mac->catdir('d1','d2', ':')",          ':d1:d2:'      ],
+[ "Mac->catdir('d1','d2', '::')",         ':d1:d2::'     ],
+[ "Mac->catdir('d1','d2','','')",         ':d1:d2:'      ],
+[ "Mac->catdir('d1','d2',':','::')",      ':d1:d2::'     ],
+[ "Mac->catdir('d1','d2','::','::')",     ':d1:d2:::'    ],
+[ "Mac->catdir('d1',':d2')",              ':d1:d2:'      ],
+[ "Mac->catdir('d1',':d2:')",             ':d1:d2:'      ],
 
-# Unix catdir('','') =      "/"
-# Unix catdir('','.') =     "/"
-# Unix catdir('.','.') =    "."
-# Unix catdir('.','') =     "."
-
-# Unix catdir('','..') =    "/"
-# Unix catdir('.','..') =   ".."
-
-# Unix catdir('..','') =    ".."
-# Unix catdir('..','.') =   ".."
-# Unix catdir('..','..') =  "../.."
-
-[ "Mac->catdir(':d1','d2')",        ':d1:d2:'     ],
-[ "Mac->catdir('','d1','d2','d3')", ':d1:d2:d3:'  ],
-[ "Mac->catdir('','','d2','d3')",   '::d2:d3:'    ],
-[ "Mac->catdir('','','','d3')",     ':::d3:'      ],
-[ "Mac->catdir(':d1')",             ':d1:'        ],
-[ "Mac->catdir(':d1',':d2')",       ':d1:d2:'     ],
-[ "Mac->catdir('', ':d1',':d2')",   ':d1:d2:'     ],
-[ "Mac->catdir('','',':d1',':d2')", '::d1:d2:'    ],
+[ "Mac->catdir('','d1','d2','d3')",        $root . 'd1:d2:d3:', 'MacOS' ], # skipped on other OS
+[ "Mac->catdir('',':','d1','d2')",         $root . 'd1:d2:'   , 'MacOS' ], # skipped on other OS
+[ "Mac->catdir('','::','d1','d2')",        $root . 'd1:d2:'   , 'MacOS' ], # skipped on other OS
+[ "Mac->catdir('',':','','d1')",           $root . 'd1:'      , 'MacOS' ], # skipped on other OS
+[ "Mac->catdir('', ':d1',':d2')",          $root . 'd1:d2:'   , 'MacOS' ], # skipped on other OS
+[ "Mac->catdir('','',':d1',':d2')",        $root . 'd1:d2:'   , 'MacOS' ], # skipped on other OS
 
-[ "Mac->catdir('hd')",              'hd:'         ],
-[ "Mac->catdir('hd','d1','d2')",    'hd:d1:d2:'   ],
-[ "Mac->catdir('hd','d1/','d2')",   'hd:d1/:d2:'  ],
-[ "Mac->catdir('hd','',':d1')",     'hd::d1:'     ],
-[ "Mac->catdir('hd','d1')",         'hd:d1:'      ],
-[ "Mac->catdir('hd','d1', '')",     'hd:d1::'     ],
-[ "Mac->catdir('hd','d1','','')",   'hd:d1:::'    ],
 [ "Mac->catdir('hd:',':d1')",       'hd:d1:'      ],
 [ "Mac->catdir('hd:d1:',':d2')",    'hd:d1:d2:'   ],
 [ "Mac->catdir('hd:','d1')",        'hd:d1:'      ],
-[ "Mac->catdir('hd',':d1')",        'hd:d1:'      ],
 [ "Mac->catdir('hd:d1:',':d2')",    'hd:d1:d2:'   ],
 [ "Mac->catdir('hd:d1:',':d2:')",   'hd:d1:d2:'   ],
 
+[ "Mac->catfile()",                      ''                      ],
+[ "Mac->catfile('')",                    ''                      ],
+[ "Mac->catfile('', '')",                $root         , 'MacOS' ], # skipped on other OS
+[ "Mac->catfile('', 'file')",            $root . 'file', 'MacOS' ], # skipped on other OS
+[ "Mac->catfile(':')",                   ':'                     ],
+[ "Mac->catfile(':', '')",               ':'                     ],
 
-[ "Mac->catfile()",                      ''            ], 
-[ "Mac->catfile('')",                    ''            ],
-[ "Mac->catfile(':')",                   ':'           ],
-[ "Mac->catfile(':', '')",               ':'           ],
-
-[ "Mac->catfile('hd','d1','file')",      'hd:d1:file'  ],
-[ "Mac->catfile('hd','d1',':file')",     'hd:d1:file'  ],
-[ "Mac->catfile('file')",                'file'        ], 
-[ "Mac->catfile(':', 'file')",           ':file'       ], 
-[ "Mac->catfile('', 'file')",            ':file'       ], 
+[ "Mac->catfile('d1','d2','file')",      ':d1:d2:file' ],
+[ "Mac->catfile('d1','d2',':file')",     ':d1:d2:file' ],
+[ "Mac->catfile('file')",                'file'        ],
+[ "Mac->catfile(':', 'file')",           ':file'       ],
 
-
 [ "Mac->canonpath('')",                   ''     ],
 [ "Mac->canonpath(':')",                  ':'    ],
 [ "Mac->canonpath('::')",                 '::'   ],
@@ -405,7 +450,7 @@
 
 [ "Mac->abs2rel('hd:d1:d2:','hd:d1:d2:')",            ':'            ],
 [ "Mac->abs2rel('hd:d1:d2:','hd:d1:d2:file')",        ':'            ], # ignore base's file portion
-[ "Mac->abs2rel('hd:d1:d2:file','hd:d1:d2:')",        ':file'        ], 
+[ "Mac->abs2rel('hd:d1:d2:file','hd:d1:d2:')",        ':file'        ],
 [ "Mac->abs2rel('hd:d1:','hd:d1:d2:')",               '::'           ],
 [ "Mac->abs2rel('hd:d3:','hd:d1:d2:')",               ':::d3:'       ],
 [ "Mac->abs2rel('hd:d3:','hd:d1:d2::')",              '::d3:'        ],
@@ -416,11 +461,11 @@
 [ "Mac->abs2rel('hd:d3:','hd:d1:d2:')",               ':::d3:'       ], # same as above
 [ "Mac->abs2rel('hd:d1:d2:d3:','hd:d1:d2:')",         ':d3:'         ],
 [ "Mac->abs2rel('hd:d1:d2:d3::','hd:d1:d2:')",        ':d3::'        ],
-[ "Mac->abs2rel('v1:d3:d4:d5:','v2:d1:d2:')",         ':::d3:d4:d5:' ], # ignore base's volume
+[ "Mac->abs2rel('hd1:d3:d4:d5:','hd2:d1:d2:')",       ':::d3:d4:d5:' ], # ignore base's volume
 [ "Mac->abs2rel('hd:','hd:d1:d2:')",                  ':::'          ],
 
-[ "Mac->rel2abs(':d3:','hd:d1:d2:')",          'hd:d1:d2:d3:'     ], 
-[ "Mac->rel2abs(':d3:d4:','hd:d1:d2:')",       'hd:d1:d2:d3:d4:'  ], 
+[ "Mac->rel2abs(':d3:','hd:d1:d2:')",          'hd:d1:d2:d3:'     ],
+[ "Mac->rel2abs(':d3:d4:','hd:d1:d2:')",       'hd:d1:d2:d3:d4:'  ],
 [ "Mac->rel2abs('','hd:d1:d2:')",              ''                 ],
 [ "Mac->rel2abs('::','hd:d1:d2:')",            'hd:d1:d2::'       ],
 [ "Mac->rel2abs('::','hd:d1:d2:file')",        'hd:d1:d2::'       ],# ignore base's file portion
@@ -432,34 +477,6 @@
 [ "Mac->rel2abs('hd:d3:','hd:d1:file')",       'hd:d3:'           ],
 ) ;
 
-# Grab all of the plain routines from File::Spec
-use File::Spec @File::Spec::EXPORT_OK ;
-
-require File::Spec::Unix ;
-require File::Spec::Win32 ;
-
-eval {
-   require VMS::Filespec ;
-} ;
-
-my $skip_exception = "Install VMS::Filespec (from vms/ext)" ;
-
-if ( $@ ) {
-   # Not pretty, but it allows testing of things not implemented soley
-   # on VMS.  It might be better to change File::Spec::VMS to do this,
-   # making it more usable when running on (say) Unix but working with
-   # VMS paths.
-   eval qq-
-      sub File::Spec::VMS::vmsify  { die "$skip_exception" }
-      sub File::Spec::VMS::unixify { die "$skip_exception" }
-      sub File::Spec::VMS::vmspath { die "$skip_exception" }
-   - ;
-   $INC{"VMS/Filespec.pm"} = 1 ;
-}
-require File::Spec::VMS ;
-
-require File::Spec::OS2 ;
-require File::Spec::Mac ;
 
 print "1..", scalar( @tests ), "\n" ;
 
@@ -471,7 +488,6 @@
 }
 
 
-
 #
 # Tries a named function with the given args and compares the result against
 # an expected result. Works with functions that return scalars or arrays.
End of Patch.