16fb12b70Safresh1package File::Spec::VMS; 26fb12b70Safresh1 36fb12b70Safresh1use strict; 49f11ffb7Safresh1use Cwd (); 56fb12b70Safresh1require File::Spec::Unix; 66fb12b70Safresh1 7*3d61058aSafresh1our $VERSION = '3.91'; 8b8851fccSafresh1$VERSION =~ tr/_//d; 96fb12b70Safresh1 109f11ffb7Safresh1our @ISA = qw(File::Spec::Unix); 116fb12b70Safresh1 126fb12b70Safresh1use File::Basename; 136fb12b70Safresh1use VMS::Filespec; 146fb12b70Safresh1 156fb12b70Safresh1=head1 NAME 166fb12b70Safresh1 176fb12b70Safresh1File::Spec::VMS - methods for VMS file specs 186fb12b70Safresh1 196fb12b70Safresh1=head1 SYNOPSIS 206fb12b70Safresh1 216fb12b70Safresh1 require File::Spec::VMS; # Done internally by File::Spec if needed 226fb12b70Safresh1 236fb12b70Safresh1=head1 DESCRIPTION 246fb12b70Safresh1 256fb12b70Safresh1See File::Spec::Unix for a documentation of the methods provided 266fb12b70Safresh1there. This package overrides the implementation of these methods, not 276fb12b70Safresh1the semantics. 286fb12b70Safresh1 296fb12b70Safresh1The default behavior is to allow either VMS or Unix syntax on input and to 306fb12b70Safresh1return VMS syntax on output unless Unix syntax has been explicitly requested 316fb12b70Safresh1via the C<DECC$FILENAME_UNIX_REPORT> CRTL feature. 326fb12b70Safresh1 336fb12b70Safresh1=over 4 346fb12b70Safresh1 356fb12b70Safresh1=cut 366fb12b70Safresh1 376fb12b70Safresh1# Need to look up the feature settings. The preferred way is to use the 386fb12b70Safresh1# VMS::Feature module, but that may not be available to dual life modules. 396fb12b70Safresh1 406fb12b70Safresh1my $use_feature; 416fb12b70Safresh1BEGIN { 420b7734b3Safresh1 if (eval { local $SIG{__DIE__}; 430b7734b3Safresh1 local @INC = @INC; 440b7734b3Safresh1 pop @INC if $INC[-1] eq '.'; 450b7734b3Safresh1 require VMS::Feature; }) { 466fb12b70Safresh1 $use_feature = 1; 476fb12b70Safresh1 } 486fb12b70Safresh1} 496fb12b70Safresh1 506fb12b70Safresh1# Need to look up the UNIX report mode. This may become a dynamic mode 516fb12b70Safresh1# in the future. 526fb12b70Safresh1sub _unix_rpt { 536fb12b70Safresh1 my $unix_rpt; 546fb12b70Safresh1 if ($use_feature) { 556fb12b70Safresh1 $unix_rpt = VMS::Feature::current("filename_unix_report"); 566fb12b70Safresh1 } else { 576fb12b70Safresh1 my $env_unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; 586fb12b70Safresh1 $unix_rpt = $env_unix_rpt =~ /^[ET1]/i; 596fb12b70Safresh1 } 606fb12b70Safresh1 return $unix_rpt; 616fb12b70Safresh1} 626fb12b70Safresh1 636fb12b70Safresh1=item canonpath (override) 646fb12b70Safresh1 656fb12b70Safresh1Removes redundant portions of file specifications and returns results 666fb12b70Safresh1in native syntax unless Unix filename reporting has been enabled. 676fb12b70Safresh1 686fb12b70Safresh1=cut 696fb12b70Safresh1 706fb12b70Safresh1 716fb12b70Safresh1sub canonpath { 726fb12b70Safresh1 my($self,$path) = @_; 736fb12b70Safresh1 746fb12b70Safresh1 return undef unless defined $path; 756fb12b70Safresh1 766fb12b70Safresh1 my $unix_rpt = $self->_unix_rpt; 776fb12b70Safresh1 786fb12b70Safresh1 if ($path =~ m|/|) { 796fb12b70Safresh1 my $pathify = $path =~ m|/\Z(?!\n)|; 806fb12b70Safresh1 $path = $self->SUPER::canonpath($path); 816fb12b70Safresh1 826fb12b70Safresh1 return $path if $unix_rpt; 836fb12b70Safresh1 $path = $pathify ? vmspath($path) : vmsify($path); 846fb12b70Safresh1 } 856fb12b70Safresh1 866fb12b70Safresh1 $path =~ s/(?<!\^)</[/; # < and > ==> [ and ] 876fb12b70Safresh1 $path =~ s/(?<!\^)>/]/; 886fb12b70Safresh1 $path =~ s/(?<!\^)\]\[\./\.\]\[/g; # ][. ==> .][ 896fb12b70Safresh1 $path =~ s/(?<!\^)\[000000\.\]\[/\[/g; # [000000.][ ==> [ 906fb12b70Safresh1 $path =~ s/(?<!\^)\[000000\./\[/g; # [000000. ==> [ 916fb12b70Safresh1 $path =~ s/(?<!\^)\.\]\[000000\]/\]/g; # .][000000] ==> ] 926fb12b70Safresh1 $path =~ s/(?<!\^)\.\]\[/\./g; # foo.][bar ==> foo.bar 936fb12b70Safresh1 1 while ($path =~ s/(?<!\^)([\[\.])(-+)\.(-+)([\.\]])/$1$2$3$4/); 946fb12b70Safresh1 # That loop does the following 956fb12b70Safresh1 # with any amount of dashes: 966fb12b70Safresh1 # .-.-. ==> .--. 976fb12b70Safresh1 # [-.-. ==> [--. 986fb12b70Safresh1 # .-.-] ==> .--] 996fb12b70Safresh1 # [-.-] ==> [--] 1009f11ffb7Safresh1 1 while ($path =~ s/(?<!\^)([\[\.])(?:\^.|[^\]\.])+\.-(-+)([\]\.])/$1$2$3/); 1016fb12b70Safresh1 # That loop does the following 1026fb12b70Safresh1 # with any amount (minimum 2) 1036fb12b70Safresh1 # of dashes: 1046fb12b70Safresh1 # .foo.--. ==> .-. 1056fb12b70Safresh1 # .foo.--] ==> .-] 1066fb12b70Safresh1 # [foo.--. ==> [-. 1076fb12b70Safresh1 # [foo.--] ==> [-] 1086fb12b70Safresh1 # 1096fb12b70Safresh1 # And then, the remaining cases 1106fb12b70Safresh1 $path =~ s/(?<!\^)\[\.-/[-/; # [.- ==> [- 1119f11ffb7Safresh1 $path =~ s/(?<!\^)\.(?:\^.|[^\]\.])+\.-\./\./g; # .foo.-. ==> . 1129f11ffb7Safresh1 $path =~ s/(?<!\^)\[(?:\^.|[^\]\.])+\.-\./\[/g; # [foo.-. ==> [ 1139f11ffb7Safresh1 $path =~ s/(?<!\^)\.(?:\^.|[^\]\.])+\.-\]/\]/g; # .foo.-] ==> ] 1146fb12b70Safresh1 # [foo.-] ==> [000000] 1159f11ffb7Safresh1 $path =~ s/(?<!\^)\[(?:\^.|[^\]\.])+\.-\]/\[000000\]/g; 1166fb12b70Safresh1 # [] ==> 1176fb12b70Safresh1 $path =~ s/(?<!\^)\[\]// unless $path eq '[]'; 1186fb12b70Safresh1 return $unix_rpt ? unixify($path) : $path; 1196fb12b70Safresh1} 1206fb12b70Safresh1 1216fb12b70Safresh1=item catdir (override) 1226fb12b70Safresh1 1236fb12b70Safresh1Concatenates a list of file specifications, and returns the result as a 1246fb12b70Safresh1native directory specification unless the Unix filename reporting feature 1256fb12b70Safresh1has been enabled. No check is made for "impossible" cases (e.g. elements 1266fb12b70Safresh1other than the first being absolute filespecs). 1276fb12b70Safresh1 1286fb12b70Safresh1=cut 1296fb12b70Safresh1 1306fb12b70Safresh1sub catdir { 1316fb12b70Safresh1 my $self = shift; 1326fb12b70Safresh1 my $dir = pop; 1336fb12b70Safresh1 1346fb12b70Safresh1 my $unix_rpt = $self->_unix_rpt; 1356fb12b70Safresh1 1366fb12b70Safresh1 my @dirs = grep {defined() && length()} @_; 1376fb12b70Safresh1 1386fb12b70Safresh1 my $rslt; 1396fb12b70Safresh1 if (@dirs) { 1406fb12b70Safresh1 my $path = (@dirs == 1 ? $dirs[0] : $self->catdir(@dirs)); 1416fb12b70Safresh1 my ($spath,$sdir) = ($path,$dir); 1426fb12b70Safresh1 $spath =~ s/\.dir\Z(?!\n)//i; $sdir =~ s/\.dir\Z(?!\n)//i; 1436fb12b70Safresh1 1446fb12b70Safresh1 if ($unix_rpt) { 1456fb12b70Safresh1 $spath = unixify($spath) unless $spath =~ m#/#; 1466fb12b70Safresh1 $sdir= unixify($sdir) unless $sdir =~ m#/#; 1476fb12b70Safresh1 return $self->SUPER::catdir($spath, $sdir) 1486fb12b70Safresh1 } 1496fb12b70Safresh1 150b8851fccSafresh1 $rslt = vmspath( unixify($spath) . '/' . unixify($sdir)); 1516fb12b70Safresh1 1526fb12b70Safresh1 # Special case for VMS absolute directory specs: these will have 1536fb12b70Safresh1 # had device prepended during trip through Unix syntax in 1546fb12b70Safresh1 # eliminate_macros(), since Unix syntax has no way to express 1556fb12b70Safresh1 # "absolute from the top of this device's directory tree". 1566fb12b70Safresh1 if ($spath =~ /^[\[<][^.\-]/s) { $rslt =~ s/^[^\[<]+//s; } 1576fb12b70Safresh1 1586fb12b70Safresh1 } else { 1596fb12b70Safresh1 # Single directory. Return an empty string on null input; otherwise 1606fb12b70Safresh1 # just return a canonical path. 1616fb12b70Safresh1 1626fb12b70Safresh1 if (not defined $dir or not length $dir) { 1636fb12b70Safresh1 $rslt = ''; 1646fb12b70Safresh1 } else { 1656fb12b70Safresh1 $rslt = $unix_rpt ? $dir : vmspath($dir); 1666fb12b70Safresh1 } 1676fb12b70Safresh1 } 1686fb12b70Safresh1 return $self->canonpath($rslt); 1696fb12b70Safresh1} 1706fb12b70Safresh1 1716fb12b70Safresh1=item catfile (override) 1726fb12b70Safresh1 1736fb12b70Safresh1Concatenates a list of directory specifications with a filename specification 1746fb12b70Safresh1to build a path. 1756fb12b70Safresh1 1766fb12b70Safresh1=cut 1776fb12b70Safresh1 1786fb12b70Safresh1sub catfile { 1796fb12b70Safresh1 my $self = shift; 1806fb12b70Safresh1 my $tfile = pop(); 1816fb12b70Safresh1 my $file = $self->canonpath($tfile); 1826fb12b70Safresh1 my @files = grep {defined() && length()} @_; 1836fb12b70Safresh1 1846fb12b70Safresh1 my $unix_rpt = $self->_unix_rpt; 1856fb12b70Safresh1 1866fb12b70Safresh1 my $rslt; 1876fb12b70Safresh1 if (@files) { 1886fb12b70Safresh1 my $path = (@files == 1 ? $files[0] : $self->catdir(@files)); 1896fb12b70Safresh1 my $spath = $path; 1906fb12b70Safresh1 1916fb12b70Safresh1 # Something building a VMS path in pieces may try to pass a 1926fb12b70Safresh1 # directory name in filename format, so normalize it. 1936fb12b70Safresh1 $spath =~ s/\.dir\Z(?!\n)//i; 1946fb12b70Safresh1 1956fb12b70Safresh1 # If the spath ends with a directory delimiter and the file is bare, 1966fb12b70Safresh1 # then just concatenate them. 1976fb12b70Safresh1 if ($spath =~ /^(?<!\^)[^\)\]\/:>]+\)\Z(?!\n)/s && basename($file) eq $file) { 1986fb12b70Safresh1 $rslt = "$spath$file"; 1996fb12b70Safresh1 } else { 200b8851fccSafresh1 $rslt = unixify($spath); 2016fb12b70Safresh1 $rslt .= (defined($rslt) && length($rslt) ? '/' : '') . unixify($file); 2026fb12b70Safresh1 $rslt = vmsify($rslt) unless $unix_rpt; 2036fb12b70Safresh1 } 2046fb12b70Safresh1 } 2056fb12b70Safresh1 else { 2066fb12b70Safresh1 # Only passed a single file? 2076fb12b70Safresh1 my $xfile = (defined($file) && length($file)) ? $file : ''; 2086fb12b70Safresh1 209b8851fccSafresh1 $rslt = $unix_rpt ? $xfile : vmsify($xfile); 2106fb12b70Safresh1 } 2116fb12b70Safresh1 return $self->canonpath($rslt) unless $unix_rpt; 2126fb12b70Safresh1 2136fb12b70Safresh1 # In Unix report mode, do not strip off redundant path information. 2146fb12b70Safresh1 return $rslt; 2156fb12b70Safresh1} 2166fb12b70Safresh1 2176fb12b70Safresh1 2186fb12b70Safresh1=item curdir (override) 2196fb12b70Safresh1 2206fb12b70Safresh1Returns a string representation of the current directory: '[]' or '.' 2216fb12b70Safresh1 2226fb12b70Safresh1=cut 2236fb12b70Safresh1 2246fb12b70Safresh1sub curdir { 2256fb12b70Safresh1 my $self = shift @_; 2266fb12b70Safresh1 return '.' if ($self->_unix_rpt); 2276fb12b70Safresh1 return '[]'; 2286fb12b70Safresh1} 2296fb12b70Safresh1 2306fb12b70Safresh1=item devnull (override) 2316fb12b70Safresh1 2326fb12b70Safresh1Returns a string representation of the null device: '_NLA0:' or '/dev/null' 2336fb12b70Safresh1 2346fb12b70Safresh1=cut 2356fb12b70Safresh1 2366fb12b70Safresh1sub devnull { 2376fb12b70Safresh1 my $self = shift @_; 2386fb12b70Safresh1 return '/dev/null' if ($self->_unix_rpt); 2396fb12b70Safresh1 return "_NLA0:"; 2406fb12b70Safresh1} 2416fb12b70Safresh1 2426fb12b70Safresh1=item rootdir (override) 2436fb12b70Safresh1 2446fb12b70Safresh1Returns a string representation of the root directory: 'SYS$DISK:[000000]' 2456fb12b70Safresh1or '/' 2466fb12b70Safresh1 2476fb12b70Safresh1=cut 2486fb12b70Safresh1 2496fb12b70Safresh1sub rootdir { 2506fb12b70Safresh1 my $self = shift @_; 2516fb12b70Safresh1 if ($self->_unix_rpt) { 2526fb12b70Safresh1 # Root may exist, try it first. 2536fb12b70Safresh1 my $try = '/'; 2546fb12b70Safresh1 my ($dev1, $ino1) = stat('/'); 2556fb12b70Safresh1 my ($dev2, $ino2) = stat('.'); 2566fb12b70Safresh1 2576fb12b70Safresh1 # Perl falls back to '.' if it can not determine '/' 2586fb12b70Safresh1 if (($dev1 != $dev2) || ($ino1 != $ino2)) { 2596fb12b70Safresh1 return $try; 2606fb12b70Safresh1 } 2616fb12b70Safresh1 # Fall back to UNIX format sys$disk. 2626fb12b70Safresh1 return '/sys$disk/'; 2636fb12b70Safresh1 } 2646fb12b70Safresh1 return 'SYS$DISK:[000000]'; 2656fb12b70Safresh1} 2666fb12b70Safresh1 2676fb12b70Safresh1=item tmpdir (override) 2686fb12b70Safresh1 2696fb12b70Safresh1Returns a string representation of the first writable directory 2706fb12b70Safresh1from the following list or '' if none are writable: 2716fb12b70Safresh1 2726fb12b70Safresh1 /tmp if C<DECC$FILENAME_UNIX_REPORT> is enabled. 2736fb12b70Safresh1 sys$scratch: 2746fb12b70Safresh1 $ENV{TMPDIR} 2756fb12b70Safresh1 2766fb12b70Safresh1If running under taint mode, and if $ENV{TMPDIR} 2776fb12b70Safresh1is tainted, it is not used. 2786fb12b70Safresh1 2796fb12b70Safresh1=cut 2806fb12b70Safresh1 2816fb12b70Safresh1sub tmpdir { 2826fb12b70Safresh1 my $self = shift @_; 2836fb12b70Safresh1 my $tmpdir = $self->_cached_tmpdir('TMPDIR'); 2846fb12b70Safresh1 return $tmpdir if defined $tmpdir; 2856fb12b70Safresh1 if ($self->_unix_rpt) { 2866fb12b70Safresh1 $tmpdir = $self->_tmpdir('/tmp', '/sys$scratch', $ENV{TMPDIR}); 2876fb12b70Safresh1 } 2886fb12b70Safresh1 else { 2896fb12b70Safresh1 $tmpdir = $self->_tmpdir( 'sys$scratch:', $ENV{TMPDIR} ); 2906fb12b70Safresh1 } 2916fb12b70Safresh1 $self->_cache_tmpdir($tmpdir, 'TMPDIR'); 2926fb12b70Safresh1} 2936fb12b70Safresh1 2946fb12b70Safresh1=item updir (override) 2956fb12b70Safresh1 2966fb12b70Safresh1Returns a string representation of the parent directory: '[-]' or '..' 2976fb12b70Safresh1 2986fb12b70Safresh1=cut 2996fb12b70Safresh1 3006fb12b70Safresh1sub updir { 3016fb12b70Safresh1 my $self = shift @_; 3026fb12b70Safresh1 return '..' if ($self->_unix_rpt); 3036fb12b70Safresh1 return '[-]'; 3046fb12b70Safresh1} 3056fb12b70Safresh1 3066fb12b70Safresh1=item case_tolerant (override) 3076fb12b70Safresh1 3086fb12b70Safresh1VMS file specification syntax is case-tolerant. 3096fb12b70Safresh1 3106fb12b70Safresh1=cut 3116fb12b70Safresh1 3126fb12b70Safresh1sub case_tolerant { 3136fb12b70Safresh1 return 1; 3146fb12b70Safresh1} 3156fb12b70Safresh1 3166fb12b70Safresh1=item path (override) 3176fb12b70Safresh1 3186fb12b70Safresh1Translate logical name DCL$PATH as a searchlist, rather than trying 3196fb12b70Safresh1to C<split> string value of C<$ENV{'PATH'}>. 3206fb12b70Safresh1 3216fb12b70Safresh1=cut 3226fb12b70Safresh1 3236fb12b70Safresh1sub path { 3246fb12b70Safresh1 my (@dirs,$dir,$i); 3256fb12b70Safresh1 while ($dir = $ENV{'DCL$PATH;' . $i++}) { push(@dirs,$dir); } 3266fb12b70Safresh1 return @dirs; 3276fb12b70Safresh1} 3286fb12b70Safresh1 3296fb12b70Safresh1=item file_name_is_absolute (override) 3306fb12b70Safresh1 3316fb12b70Safresh1Checks for VMS directory spec as well as Unix separators. 3326fb12b70Safresh1 3336fb12b70Safresh1=cut 3346fb12b70Safresh1 3356fb12b70Safresh1sub file_name_is_absolute { 3366fb12b70Safresh1 my ($self,$file) = @_; 3376fb12b70Safresh1 # If it's a logical name, expand it. 3386fb12b70Safresh1 $file = $ENV{$file} while $file =~ /^[\w\$\-]+\Z(?!\n)/s && $ENV{$file}; 3396fb12b70Safresh1 return scalar($file =~ m!^/!s || 3406fb12b70Safresh1 $file =~ m![<\[][^.\-\]>]! || 3416fb12b70Safresh1 $file =~ /^[A-Za-z0-9_\$\-\~]+(?<!\^):/); 3426fb12b70Safresh1} 3436fb12b70Safresh1 3446fb12b70Safresh1=item splitpath (override) 3456fb12b70Safresh1 3466fb12b70Safresh1 ($volume,$directories,$file) = File::Spec->splitpath( $path ); 3476fb12b70Safresh1 ($volume,$directories,$file) = File::Spec->splitpath( $path, 3486fb12b70Safresh1 $no_file ); 3496fb12b70Safresh1 3506fb12b70Safresh1Passing a true value for C<$no_file> indicates that the path being 3516fb12b70Safresh1split only contains directory components, even on systems where you 3526fb12b70Safresh1can usually (when not supporting a foreign syntax) tell the difference 3536fb12b70Safresh1between directories and files at a glance. 3546fb12b70Safresh1 3556fb12b70Safresh1=cut 3566fb12b70Safresh1 3576fb12b70Safresh1sub splitpath { 3586fb12b70Safresh1 my($self,$path, $nofile) = @_; 3596fb12b70Safresh1 my($dev,$dir,$file) = ('','',''); 3606fb12b70Safresh1 my $vmsify_path = vmsify($path); 3616fb12b70Safresh1 3626fb12b70Safresh1 if ( $nofile ) { 3636fb12b70Safresh1 #vmsify('d1/d2/d3') returns '[.d1.d2]d3' 3646fb12b70Safresh1 #vmsify('/d1/d2/d3') returns 'd1:[d2]d3' 3656fb12b70Safresh1 if( $vmsify_path =~ /(.*)\](.+)/ ){ 3666fb12b70Safresh1 $vmsify_path = $1.'.'.$2.']'; 3676fb12b70Safresh1 } 3686fb12b70Safresh1 $vmsify_path =~ /(.+:)?(.*)/s; 3696fb12b70Safresh1 $dir = defined $2 ? $2 : ''; # dir can be '0' 3706fb12b70Safresh1 return ($1 || '',$dir,$file); 3716fb12b70Safresh1 } 3726fb12b70Safresh1 else { 3736fb12b70Safresh1 $vmsify_path =~ /(.+:)?([\[<].*[\]>])?(.*)/s; 3746fb12b70Safresh1 return ($1 || '',$2 || '',$3); 3756fb12b70Safresh1 } 3766fb12b70Safresh1} 3776fb12b70Safresh1 3786fb12b70Safresh1=item splitdir (override) 3796fb12b70Safresh1 3806fb12b70Safresh1Split a directory specification into the components. 3816fb12b70Safresh1 3826fb12b70Safresh1=cut 3836fb12b70Safresh1 3846fb12b70Safresh1sub splitdir { 3856fb12b70Safresh1 my($self,$dirspec) = @_; 3866fb12b70Safresh1 my @dirs = (); 3876fb12b70Safresh1 return @dirs if ( (!defined $dirspec) || ('' eq $dirspec) ); 3886fb12b70Safresh1 3896fb12b70Safresh1 $dirspec =~ s/(?<!\^)</[/; # < and > ==> [ and ] 3906fb12b70Safresh1 $dirspec =~ s/(?<!\^)>/]/; 3916fb12b70Safresh1 $dirspec =~ s/(?<!\^)\]\[\./\.\]\[/g; # ][. ==> .][ 3926fb12b70Safresh1 $dirspec =~ s/(?<!\^)\[000000\.\]\[/\[/g; # [000000.][ ==> [ 3936fb12b70Safresh1 $dirspec =~ s/(?<!\^)\[000000\./\[/g; # [000000. ==> [ 3946fb12b70Safresh1 $dirspec =~ s/(?<!\^)\.\]\[000000\]/\]/g; # .][000000] ==> ] 3956fb12b70Safresh1 $dirspec =~ s/(?<!\^)\.\]\[/\./g; # foo.][bar ==> foo.bar 3966fb12b70Safresh1 while ($dirspec =~ s/(^|[\[\<\.])\-(\-+)($|[\]\>\.])/$1-.$2$3/g) {} 3976fb12b70Safresh1 # That loop does the following 3986fb12b70Safresh1 # with any amount of dashes: 3996fb12b70Safresh1 # .--. ==> .-.-. 4006fb12b70Safresh1 # [--. ==> [-.-. 4016fb12b70Safresh1 # .--] ==> .-.-] 4026fb12b70Safresh1 # [--] ==> [-.-] 4036fb12b70Safresh1 $dirspec = "[$dirspec]" unless $dirspec =~ /(?<!\^)[\[<]/; # make legal 4046fb12b70Safresh1 $dirspec =~ s/^(\[|<)\./$1/; 4056fb12b70Safresh1 @dirs = split /(?<!\^)\./, vmspath($dirspec); 4066fb12b70Safresh1 $dirs[0] =~ s/^[\[<]//s; $dirs[-1] =~ s/[\]>]\Z(?!\n)//s; 4076fb12b70Safresh1 @dirs; 4086fb12b70Safresh1} 4096fb12b70Safresh1 4106fb12b70Safresh1 4116fb12b70Safresh1=item catpath (override) 4126fb12b70Safresh1 4136fb12b70Safresh1Construct a complete filespec. 4146fb12b70Safresh1 4156fb12b70Safresh1=cut 4166fb12b70Safresh1 4176fb12b70Safresh1sub catpath { 4186fb12b70Safresh1 my($self,$dev,$dir,$file) = @_; 4196fb12b70Safresh1 4206fb12b70Safresh1 # We look for a volume in $dev, then in $dir, but not both 4216fb12b70Safresh1 my ($dir_volume, $dir_dir, $dir_file) = $self->splitpath($dir); 4226fb12b70Safresh1 $dev = $dir_volume unless length $dev; 4236fb12b70Safresh1 $dir = length $dir_file ? $self->catfile($dir_dir, $dir_file) : $dir_dir; 4246fb12b70Safresh1 4256fb12b70Safresh1 if ($dev =~ m|^(?<!\^)/+([^/]+)|) { $dev = "$1:"; } 4266fb12b70Safresh1 else { $dev .= ':' unless $dev eq '' or $dev =~ /:\Z(?!\n)/; } 4276fb12b70Safresh1 if (length($dev) or length($dir)) { 4286fb12b70Safresh1 $dir = "[$dir]" unless $dir =~ /(?<!\^)[\[<\/]/; 4296fb12b70Safresh1 $dir = vmspath($dir); 4306fb12b70Safresh1 } 4316fb12b70Safresh1 $dir = '' if length($dev) && ($dir eq '[]' || $dir eq '<>'); 4326fb12b70Safresh1 "$dev$dir$file"; 4336fb12b70Safresh1} 4346fb12b70Safresh1 4356fb12b70Safresh1=item abs2rel (override) 4366fb12b70Safresh1 4376fb12b70Safresh1Attempt to convert an absolute file specification to a relative specification. 4386fb12b70Safresh1 4396fb12b70Safresh1=cut 4406fb12b70Safresh1 4416fb12b70Safresh1sub abs2rel { 4426fb12b70Safresh1 my $self = shift; 4436fb12b70Safresh1 my($path,$base) = @_; 444b8851fccSafresh1 4459f11ffb7Safresh1 $base = Cwd::getcwd() unless defined $base and length $base; 4466fb12b70Safresh1 447b8851fccSafresh1 # If there is no device or directory syntax on $base, make sure it 448b8851fccSafresh1 # is treated as a directory. 449b8851fccSafresh1 $base = vmspath($base) unless $base =~ m{(?<!\^)[\[<:]}; 450b8851fccSafresh1 451b8851fccSafresh1 for ($path, $base) { $_ = $self->rel2abs($_) } 4526fb12b70Safresh1 4536fb12b70Safresh1 # Are we even starting $path on the same (node::)device as $base? Note that 4546fb12b70Safresh1 # logical paths or nodename differences may be on the "same device" 4556fb12b70Safresh1 # but the comparison that ignores device differences so as to concatenate 4566fb12b70Safresh1 # [---] up directory specs is not even a good idea in cases where there is 4576fb12b70Safresh1 # a logical path difference between $path and $base nodename and/or device. 4586fb12b70Safresh1 # Hence we fall back to returning the absolute $path spec 4596fb12b70Safresh1 # if there is a case blind device (or node) difference of any sort 4606fb12b70Safresh1 # and we do not even try to call $parse() or consult %ENV for $trnlnm() 4616fb12b70Safresh1 # (this module needs to run on non VMS platforms after all). 4626fb12b70Safresh1 4636fb12b70Safresh1 my ($path_volume, $path_directories, $path_file) = $self->splitpath($path); 4646fb12b70Safresh1 my ($base_volume, $base_directories, $base_file) = $self->splitpath($base); 465b8851fccSafresh1 return $self->canonpath( $path ) unless lc($path_volume) eq lc($base_volume); 4666fb12b70Safresh1 4676fb12b70Safresh1 # Now, remove all leading components that are the same 4686fb12b70Safresh1 my @pathchunks = $self->splitdir( $path_directories ); 4696fb12b70Safresh1 my $pathchunks = @pathchunks; 4706fb12b70Safresh1 unshift(@pathchunks,'000000') unless $pathchunks[0] eq '000000'; 4716fb12b70Safresh1 my @basechunks = $self->splitdir( $base_directories ); 4726fb12b70Safresh1 my $basechunks = @basechunks; 4736fb12b70Safresh1 unshift(@basechunks,'000000') unless $basechunks[0] eq '000000'; 4746fb12b70Safresh1 4756fb12b70Safresh1 while ( @pathchunks && 4766fb12b70Safresh1 @basechunks && 4776fb12b70Safresh1 lc( $pathchunks[0] ) eq lc( $basechunks[0] ) 4786fb12b70Safresh1 ) { 4796fb12b70Safresh1 shift @pathchunks ; 4806fb12b70Safresh1 shift @basechunks ; 4816fb12b70Safresh1 } 4826fb12b70Safresh1 4836fb12b70Safresh1 # @basechunks now contains the directories to climb out of, 4846fb12b70Safresh1 # @pathchunks now has the directories to descend in to. 4856fb12b70Safresh1 if ((@basechunks > 0) || ($basechunks != $pathchunks)) { 4866fb12b70Safresh1 $path_directories = join '.', ('-' x @basechunks, @pathchunks) ; 4876fb12b70Safresh1 } 4886fb12b70Safresh1 else { 4896fb12b70Safresh1 $path_directories = join '.', @pathchunks; 4906fb12b70Safresh1 } 4916fb12b70Safresh1 $path_directories = '['.$path_directories.']'; 4926fb12b70Safresh1 return $self->canonpath( $self->catpath( '', $path_directories, $path_file ) ) ; 4936fb12b70Safresh1} 4946fb12b70Safresh1 4956fb12b70Safresh1 4966fb12b70Safresh1=item rel2abs (override) 4976fb12b70Safresh1 4986fb12b70Safresh1Return an absolute file specification from a relative one. 4996fb12b70Safresh1 5006fb12b70Safresh1=cut 5016fb12b70Safresh1 5026fb12b70Safresh1sub rel2abs { 5036fb12b70Safresh1 my $self = shift ; 5046fb12b70Safresh1 my ($path,$base ) = @_; 5056fb12b70Safresh1 return undef unless defined $path; 5066fb12b70Safresh1 if ($path =~ m/\//) { 5076fb12b70Safresh1 $path = ( -d $path || $path =~ m/\/\z/ # educated guessing about 5086fb12b70Safresh1 ? vmspath($path) # whether it's a directory 5096fb12b70Safresh1 : vmsify($path) ); 5106fb12b70Safresh1 } 5116fb12b70Safresh1 $base = vmspath($base) if defined $base && $base =~ m/\//; 5126fb12b70Safresh1 5136fb12b70Safresh1 # Clean up and split up $path 5146fb12b70Safresh1 if ( ! $self->file_name_is_absolute( $path ) ) { 5156fb12b70Safresh1 # Figure out the effective $base and clean it up. 5166fb12b70Safresh1 if ( !defined( $base ) || $base eq '' ) { 5179f11ffb7Safresh1 $base = Cwd::getcwd(); 5186fb12b70Safresh1 } 5196fb12b70Safresh1 elsif ( ! $self->file_name_is_absolute( $base ) ) { 5206fb12b70Safresh1 $base = $self->rel2abs( $base ) ; 5216fb12b70Safresh1 } 5226fb12b70Safresh1 else { 5236fb12b70Safresh1 $base = $self->canonpath( $base ) ; 5246fb12b70Safresh1 } 5256fb12b70Safresh1 5266fb12b70Safresh1 # Split up paths 5276fb12b70Safresh1 my ( $path_directories, $path_file ) = 5286fb12b70Safresh1 ($self->splitpath( $path ))[1,2] ; 5296fb12b70Safresh1 5306fb12b70Safresh1 my ( $base_volume, $base_directories ) = 5316fb12b70Safresh1 $self->splitpath( $base ) ; 5326fb12b70Safresh1 5336fb12b70Safresh1 $path_directories = '' if $path_directories eq '[]' || 5346fb12b70Safresh1 $path_directories eq '<>'; 5356fb12b70Safresh1 my $sep = '' ; 5366fb12b70Safresh1 $sep = '.' 5376fb12b70Safresh1 if ( $base_directories =~ m{[^.\]>]\Z(?!\n)} && 5386fb12b70Safresh1 $path_directories =~ m{^[^.\[<]}s 5396fb12b70Safresh1 ) ; 5406fb12b70Safresh1 $base_directories = "$base_directories$sep$path_directories"; 5416fb12b70Safresh1 $base_directories =~ s{\.?[\]>][\[<]\.?}{.}; 5426fb12b70Safresh1 5436fb12b70Safresh1 $path = $self->catpath( $base_volume, $base_directories, $path_file ); 5446fb12b70Safresh1 } 5456fb12b70Safresh1 5466fb12b70Safresh1 return $self->canonpath( $path ) ; 5476fb12b70Safresh1} 5486fb12b70Safresh1 5496fb12b70Safresh1 5506fb12b70Safresh1=back 5516fb12b70Safresh1 5526fb12b70Safresh1=head1 COPYRIGHT 5536fb12b70Safresh1 554b8851fccSafresh1Copyright (c) 2004-14 by the Perl 5 Porters. All rights reserved. 5556fb12b70Safresh1 5566fb12b70Safresh1This program is free software; you can redistribute it and/or modify 5576fb12b70Safresh1it under the same terms as Perl itself. 5586fb12b70Safresh1 5596fb12b70Safresh1=head1 SEE ALSO 5606fb12b70Safresh1 5616fb12b70Safresh1See L<File::Spec> and L<File::Spec::Unix>. This package overrides the 5626fb12b70Safresh1implementation of these methods, not the semantics. 5636fb12b70Safresh1 5646fb12b70Safresh1An explanation of VMS file specs can be found at 5656fb12b70Safresh1L<http://h71000.www7.hp.com/doc/731FINAL/4506/4506pro_014.html#apps_locating_naming_files>. 5666fb12b70Safresh1 5676fb12b70Safresh1=cut 5686fb12b70Safresh1 5696fb12b70Safresh11; 570