Here is the latest attempt.  Still not fully tested.

The VMS format of logical foo:bar, such as sys$scratch:foo seems to be causing all sorts of problems.

catpath("sys$scratch:",,"foo.bar") can not work. The catpath method can not deal with an empty directory, so will treat 'foo.bar' as a directory. So the splitpath("sys$scratch:foo.bar") must translate the sys$scratch: to its device and directory component.

Some new regression tests that may be needed for EFS/VMS mode.

[wrapped line below]
perl -"MFile::Spec::Functions" -e -
"print File::Spec->abs2rel('../lib/Module/Pluggable','../lib/Module/Pluggable/');"

returns "."

perl -"MFile::Spec::Functions" -e -
"print catdir('sys$scratch:','foo', 'bar');

returns "device:[dir.foo.bar]'

perl -"MFile::Spec::Functions" -e "print catdir('[]','foo', 'bar');

returns "[.foo.bar]"

File::Spec->splitpath('sys$scratch:compilet.exe') returns ('dev:', '[dir]', 'compilet.exe').


It looks like there are still issues with:
   ext/Test-Harness,
   lib/Archive/Extract,
   lib/Archive/Tar
   CPANPLUS,
   Various lib/ExtUtils,
   lib/Module/Build,
   lib/Pod/Simple

And i need to make a test run to make sure that I did not change the working EFS/Unix and non-EFS modes.

Regards,
-John
--- /rsync_root/perl/lib/File/Spec/VMS.pm       Sun May 10 04:02:09 2009
+++ lib/File/Spec/VMS.pm        Tue Jun  9 00:03:27 2009
@@ -105,7 +105,6 @@
 
 sub canonpath {
     my($self,$path) = @_;
-
     return undef unless defined $path;
 
     my $efs = $self->_efs;
@@ -195,6 +194,32 @@
 
         if ($efs) {
             # Extended character set in use, go into DWIM mode.
+            if ($path =~ /:$/) {
+                # We have a problem.  If we do a syntax only conversion
+                # we can break existing code that does not understand how
+                # logical names and directories can be combined.
+                my $test_path = $path;
+                my $i = 0;
+                while ($i < 10) {
+                    # We need to do a logical name check, but we do not have
+                    # logical name services in perl.  So we need to $ENV until
+                    # that can be remedied.
+                    $test_path =~ s/:$//;
+                    my $test_trnlnm = $ENV{$test_path};
+                    last unless defined $test_trnlnm;
+                    if ($test_trnlnm =~ /\.[\]>]$/) {
+                        # A rooted logical name, same as device so use as is.
+                        last;
+                    }
+                    if ($test_trnlnm =~ /[\]>]$/) {
+                        # Found a directory, use this instead of the path
+                        $path = $test_trnlnm;
+                        last;
+                    }
+                    $test_path = $test_trnlnm;
+                    $i++;
+                }
+            }
 
             # Now we need to identify what the directory is in
             # of the specification in order to merge them.
@@ -202,14 +227,14 @@
             $path_unix = 1 if ($path =~ m#/#);
             $path_unix = 1 if ($path =~ /^\.\.?$/);
             my $path_vms = 0;
-            $path_vms = 1 if ($path =~ m#[\[<\]]#);
-            $path_vms = 1 if ($path =~ /^--?$/);
+            $path_vms = 1 if ($path =~ m#(?:[\[<\]]|:$)#);
+            $path_vms = 1 if ($path =~ /^--*$/);
             my $dir_unix = 0;
             $dir_unix = 1 if ($dir =~ m#/#);
             $dir_unix = 1 if ($dir =~ /^\.\.?$/);
             my $dir_vms = 0;
             $dir_vms = 1 if ($dir =~ m#[\[<\]]#);
-            $dir_vms = 1 if ($dir =~ /^--?$/);
+            $dir_vms = 1 if ($dir =~ /^--*$/);
 
             my $unix_mode = 0;
             if (($path_unix != $dir_unix) && ($path_vms != $dir_vms)) {
@@ -237,20 +262,31 @@
                 #with <> posible instead of [.
                 # Normalize the brackets
                 # Fixme - need to not switch when preceded by ^.
-                $path =~ s/</\[/g;
-                $path =~ s/>/\]/g;
+                if ($path !~ /:$/) {
+                    $path =~ s/</\[/g;
+                    $path =~ s/>/\]/g;
+                }
                 $dir =~ s/</\[/g;
                 $dir =~ s/>/\]/g;
 
                 # Fix up mixed syntax imput as good as possible - GIGO
-                $path = vmsify($path) if $path_unix;
-                $dir = vmsify($dir) if $dir_unix;
+                if ($path_unix) {
+                    $path = vmspath($path);
+                    $path_vms = 1;
+                    $path_unix = 0;
+                }
+                if ($dir_unix) {
+                    $dir = vmspath($dir);
+                    $dir_vms = 1;
+                    $dir_unix = 0;
+                }
 
                 #Possible path values: foo: [.foo] [foo] foo, and $(foo)
                 #or starting with '-', or foo.dir
                 #If path is foo, it needs to be converted to [.foo]
 
                 # Fix up a bare path name.
+                my $is_abs_path = 0;
                 unless ($path_vms) {
                     $path =~ s/\.dir\Z(?!\n)//i;
                     if (($path ne '') && ($path !~ /^-/)) {
@@ -258,6 +294,7 @@
                         $path = '[.' . $path;
                     } else {
                         # Just start a directory.
+                        $is_abs_path = 1 if $path eq '';
                         $path = '[' . $path;
                     }
                 } else {
@@ -276,16 +313,25 @@
                     $dir =~ s/\]$//;
                 }
 
-                #strip off the leading dot if present.
-                $dir =~ s/^\.//;
-
                 # Now put the specifications together.
                 if ($dir ne '') {
-                    # Add a separator unless this is an absolute path
-                    $path .= '.' if ($path ne '[');
-                    $rslt = $path . $dir . ']';
+                    if ($path =~ /:$/) {
+                        $rslt = $path . '[' . $dir . ']';
+                    } else {
+
+                        #strip off the leading dot if present.
+                        $dir =~ s/^\.//;
+
+                        # Add a separator unless this is an absolute path
+                        $path .= '.' unless $is_abs_path;
+                        $rslt = $path . $dir . ']';
+                    }
                 } else {
-                    $rslt = $path . ']';
+                    if ($path =~ /:$/) {
+                        $rslt = $path;
+                    } else {
+                        $rslt = $path . ']';
+                    }
                 }
             }
 
@@ -427,7 +473,7 @@
                 $spath_unix = 1 if ($spath =~ m#/#);
                 $spath_unix = 1 if ($spath =~ /^\.\.?$/);
                 my $spath_vms = 0;
-                $spath_vms = 1 if ($spath =~ m#[\[<\]]#);
+                $spath_vms = 1 if ($spath =~ m#(?:[\[<\]]|:$)#);
                 $spath_vms = 1 if ($spath =~ /^--?$/);
 
                 # Assume VMS mode
@@ -439,13 +485,19 @@
                      $unix_mode = 1
                          if (($spath_unix || $file_unix) && $unix_rpt);
                 }
-
                 if (!$unix_mode) {
                     if ($spath_vms) {
-                        $spath = '[' . $spath . ']' if $spath =~ /^-/;
-                        $rslt = vmspath($spath);
+                        if ($spath =~ /^-/) {
+                            $rslt = '[' . $spath . ']';
+                        } else {
+                            $rslt = $spath;
+                        }
                     } else {
-                        $rslt = '[.' . $spath . ']';
+                        if ($spath_unix) {
+                            $rslt = vmspath($spath);
+                        } else {
+                            $rslt = '[.' . $spath . ']';
+                        }
                     }
                     $file = vmsify($file) if ($file_unix);
                 } else {
@@ -459,7 +511,7 @@
                 }
 
                 $rslt .= $file;
-                $rslt =~ s/\]\[//;
+                $rslt =~ s/\]\[// if !$unix_mode;
 
            } else {
                # Traditional VMS Perl mode expects that this is done.
@@ -638,8 +690,8 @@
     my $vmsify_path = vmsify($path);
     if ($efs) {
         my $path_vms = 0;
-        $path_vms = 1 if ($path =~ m#[\[<\]]#);
-        $path_vms = 1 if ($path =~ /^--?$/);
+        $path_vms = 1 if ($path =~ m#(?:[\[<\]:])#);
+        $path_vms = 1 if ($path =~ /^--*$/);
         if (!$path_vms) {
             return $self->SUPER::splitpath($path, $nofile);
         }
@@ -658,7 +710,35 @@
     }
     else {
         $vmsify_path =~ /(.+:)?([\[<].*[\]>])?(.*)/s;
-        return ($1 || '',$2 || '',$3);
+        $dev = $1 || ''; $dir = $2 || ''; $file = $3; 
+
+        # Need to handle things like 'sys$scratch:foo'
+        # We have to expand the logical name because catpath can not
+        # deal with an empty directory.
+        if (($dir eq '') && ($file ne '')) {
+
+            my $test_dev = $dev;
+            my $i = 0;
+            while ($i < 10) {
+                $test_dev =~ s/:$//;
+                my $test_trnlnm = $ENV{$test_dev};
+                last unless defined $test_trnlnm;
+                if ($test_trnlnm =~ /\.[\]>]$/) {
+                    # A rooted logical name, same as device so use as is.
+                    last;
+                }
+                if ($test_trnlnm =~ /[\]>]$/) {
+                    # Found a directory, use this instead of the dev, dir
+                    $test_trnlnm =~ /(.+:)?([\[<].*[\]>])?/s;
+                    $dev = $1; $dir = $2;
+                    last;
+                }
+                $test_dev = $test_trnlnm;
+                $i++;
+            }
+        }
+
+        return ($dev, $dir, $file);
     }
 }
 
@@ -715,7 +795,6 @@
 
 sub catpath {
     my($self,$dev,$dir,$file) = @_;
-    
     my $efs = $self->_efs;
     my $unix_rpt = $self->_unix_rpt;
 
@@ -734,7 +813,6 @@
             $unix_mode = $dir_unix;
         }
     } 
-
     # We look for a volume in $dev, then in $dir, but not both
     # but only if using VMS syntax.
     if (!$unix_mode) {
@@ -789,6 +867,7 @@
     my $path_vms = 0;
     $path_vms = 1 if ($path =~ m#[\[<\]]#);
     $path_vms = 1 if ($path =~ /^--?$/);
+    $path_vms = 1 if ($path =~ /:$/);
 
     my $unix_mode = 0;
     if ($path_vms == $path_unix) {
@@ -803,8 +882,8 @@
     if (defined $base) {
         $base_unix = 1 if ($base =~ m#/#);
         $base_unix = 1 if ($base =~ /^\.\.?$/);
-        $base_vms = 1 if ($base =~ m#[\[<\]]#);
-        $base_vms = 1 if ($base =~ /^--?$/);
+        $base_vms = 1 if ($base =~ m#(?:[\[<\]]|:$)#);
+        $base_vms = 1 if ($base =~ /^--*$/);
 
         if ($path_vms == $path_unix) {
             if ($base_vms == $base_unix) {
@@ -821,7 +900,7 @@
         if ($unix_mode) {
             # We are UNIX mode.
             $base = unixpath($base) if $base_vms;
-            $base = unixify($path) if $path_vms;
+            $path = unixify($path) if $path_vms;
 
             # Here VMS is different, and in order to do this right
             # we have to take the realpath for both the path and the base
@@ -839,11 +918,20 @@
                 return $path;
             }
 
-            return File::Spec::Unix::abs2rel( $self, $path, $base );
+            # Handle it as Unix.
+            my $rslt = File::Spec::Unix::abs2rel($self, $path, $base);
+
+            # If we are not in Unix mode, something that the Unix code
+            # if flipping this to VMS format.  We need to put this back.
+            unless ($unix_rpt) {
+                $rslt = unixify($rslt) if $rslt =~ m#(?:[\[\<\]]|:$)#;
+                $rslt =~ s#/$## if ($rslt ne '/');
+            }
+            return $rslt;
 
         } else {
             $base = vmspath($base) if $base_unix;
-            $path = vmsify($path) if $path_unix;
+            $path = vmspath($path) if $path_unix;
         }
     }
 
@@ -923,8 +1011,8 @@
     $path_unix = 1 if ($path =~ m#/#);
     $path_unix = 1 if ($path =~ /^\.\.?$/);
     my $path_vms = 0;
-    $path_vms = 1 if ($path =~ m#[\[<\]]#);
-    $path_vms = 1 if ($path =~ /^--?$/);
+    $path_vms = 1 if ($path =~ m#(?:[\[<\]]|:$)#);
+    $path_vms = 1 if ($path =~ /^--*$/);
 
     my $unix_mode = 0;
     if ($path_vms == $path_unix) {
@@ -939,8 +1027,8 @@
     if (defined $base) {
         $base_unix = 1 if ($base =~ m#/#);
         $base_unix = 1 if ($base =~ /^\.\.?$/);
-        $base_vms = 1 if ($base =~ m#[\[<\]]#);
-        $base_vms = 1 if ($base =~ /^--?$/);
+        $base_vms = 1 if ($base =~ m#(?:[\[<\]]|:$)#);
+        $base_vms = 1 if ($base =~ /^--*$/);
 
         # If we could not determine the path mode, see if we can find out
         # from the base.

Reply via email to