diff options
Diffstat (limited to 'lib/File/Spec/VMS.pm')
-rw-r--r-- | lib/File/Spec/VMS.pm | 1165 |
1 files changed, 0 insertions, 1165 deletions
diff --git a/lib/File/Spec/VMS.pm b/lib/File/Spec/VMS.pm deleted file mode 100644 index 34b592abbf..0000000000 --- a/lib/File/Spec/VMS.pm +++ /dev/null @@ -1,1165 +0,0 @@ -package File::Spec::VMS; - -use strict; -use vars qw(@ISA $VERSION); -require File::Spec::Unix; - -$VERSION = '3.30'; -$VERSION = eval $VERSION; - -@ISA = qw(File::Spec::Unix); - -use File::Basename; -use VMS::Filespec; - -=head1 NAME - -File::Spec::VMS - methods for VMS file specs - -=head1 SYNOPSIS - - require File::Spec::VMS; # Done internally by File::Spec if needed - -=head1 DESCRIPTION - -See File::Spec::Unix for a documentation of the methods provided -there. This package overrides the implementation of these methods, not -the semantics. - -The mode of operation of these routines depend on the VMS features that -are controlled by the DECC features C<DECC$FILENAME_REPORT_UNIX> and -C<DECC$EFS_CHARSET>. - -Perl needs to be at least at 5.10 for these feature settings to work. -Use of them on older perl versions on VMS will result in unpredictable -operations. - -The default and traditional mode of these routines have been to expect VMS -syntax on input and to return VMS syntax on output, even when Unix syntax was -given on input. - -The default and traditional mode is also incompatible with the VMS -C<EFS>, Extended File system character set, and with running Perl scripts -under <GNV>, Gnu is not VMS, an optional Unix like runtime environment on VMS. - -If the C<DECC$EFS_CHARSET> feature is enabled, These routines will now accept -either VMS or UNIX syntax. If the input parameters are clearly VMS syntax, -the return value will be in VMS syntax. If the input parameters are clearly -in Unix syntax, the output will be in Unix syntax. - -This corresponds to the way that the VMS C library routines have always -handled filenames, and what a programmer who has not specifically read this -pod before would also expect. - -If the C<DECC$FILENAME_REPORT_UNIX> feature is enabled, then if the output -syntax can not be determined from the input syntax, the output syntax will be -UNIX. If the feature is not enabled, VMS output will be the default. - -=over 4 - -=cut - -# Need to look up the feature settings. The preferred way is to use the -# VMS::Feature module, but that may not be available to dual life modules. - -my $use_feature; -BEGIN { - if (eval { local $SIG{__DIE__}; require VMS::Feature; }) { - $use_feature = 1; - } -} - -# Need to look up the UNIX report mode. This may become a dynamic mode -# in the future. -sub _unix_rpt { - my $unix_rpt; - if ($use_feature) { - $unix_rpt = VMS::Feature::current("filename_unix_report"); - } else { - my $env_unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; - $unix_rpt = $env_unix_rpt =~ /^[ET1]/i; - } - return $unix_rpt; -} - -# Need to look up the EFS character set mode. This may become a dynamic -# mode in the future. -sub _efs { - my $efs; - if ($use_feature) { - $efs = VMS::Feature::current("efs_charset"); - } else { - my $env_efs = $ENV{'DECC$EFS_CHARSET'} || ''; - $efs = $env_efs =~ /^[ET1]/i; - } - return $efs; -} - -=item canonpath (override) - -Removes redundant portions of file specifications according to the syntax -detected. - -=cut - - -sub canonpath { - my($self,$path) = @_; - - return undef unless defined $path; - - my $efs = $self->_efs; - - if ($path =~ m|/|) { # Fake Unix - my $pathify = $path =~ m|/\Z(?!\n)|; - $path = $self->SUPER::canonpath($path); - - # Do not convert to VMS when EFS character sets are in use - return $path if $efs; - - if ($pathify) { return vmspath($path); } - else { return vmsify($path); } - } - else { - -#FIXME - efs parsing has different rules. Characters in a VMS filespec -# are only delimiters if not preceded by '^'; - - $path =~ tr/<>/[]/; # < and > ==> [ and ] - $path =~ s/\]\[\./\.\]\[/g; # ][. ==> .][ - $path =~ s/\[000000\.\]\[/\[/g; # [000000.][ ==> [ - $path =~ s/\[000000\./\[/g; # [000000. ==> [ - $path =~ s/\.\]\[000000\]/\]/g; # .][000000] ==> ] - $path =~ s/\.\]\[/\./g; # foo.][bar ==> foo.bar - 1 while ($path =~ s/([\[\.])(-+)\.(-+)([\.\]])/$1$2$3$4/); - # That loop does the following - # with any amount of dashes: - # .-.-. ==> .--. - # [-.-. ==> [--. - # .-.-] ==> .--] - # [-.-] ==> [--] - 1 while ($path =~ s/([\[\.])[^\]\.]+\.-(-+)([\]\.])/$1$2$3/); - # That loop does the following - # with any amount (minimum 2) - # of dashes: - # .foo.--. ==> .-. - # .foo.--] ==> .-] - # [foo.--. ==> [-. - # [foo.--] ==> [-] - # - # And then, the remaining cases - $path =~ s/\[\.-/[-/; # [.- ==> [- - $path =~ s/\.[^\]\.]+\.-\./\./g; # .foo.-. ==> . - $path =~ s/\[[^\]\.]+\.-\./\[/g; # [foo.-. ==> [ - $path =~ s/\.[^\]\.]+\.-\]/\]/g; # .foo.-] ==> ] - $path =~ s/\[[^\]\.]+\.-\]/\[000000\]/g;# [foo.-] ==> [000000] - $path =~ s/\[\]// unless $path eq '[]'; # [] ==> - return $path; - } -} - -=item catdir (override) - -Concatenates a list of file specifications, and returns the result as a -directory specification. No check is made for "impossible" -cases (e.g. elements other than the first being absolute filespecs). - -=cut - -sub catdir { - my $self = shift; - my $dir = pop; - - my $efs = $self->_efs; - my $unix_rpt = $self->_unix_rpt; - - - my @dirs = grep {defined() && length()} @_; - if ($efs) { - # Legacy mode removes blank entries. - # But that breaks existing generic perl code that - # uses a blank path at the beginning of the array - # to indicate an absolute path. - # So put it back if found. - if (@_) { - if ($_[0] eq '') { - unshift @dirs, ''; - } - } - } - - my $rslt; - if (@dirs) { - my $path = (@dirs == 1 ? $dirs[0] : $self->catdir(@dirs)); - my ($spath,$sdir) = ($path,$dir); - - if ($efs) { - # Extended character set in use, go into DWIM mode. - - # Now we need to identify what the directory is in - # of the specification in order to merge them. - my $path_unix = 0; - $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 =~ /^--?$/); - 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 =~ /^--?$/); - - my $unix_mode = 0; - if (($path_unix != $dir_unix) && ($path_vms != $dir_vms)) { - # Ambiguous, so if in $unix_rpt mode then assume UNIX. - $unix_mode = 1 if $unix_rpt; - } else { - $unix_mode = 1 if (!$path_vms && !$dir_vms && $unix_rpt); - $unix_mode = 1 if ($path_unix || $dir_unix); - } - - if ($unix_mode) { - - # Fix up mixed syntax imput as good as possible - GIGO - $path = unixify($path) if $path_vms; - $dir = unixify($dir) if $dir_vms; - - $rslt = $path; - # Append a path delimiter - $rslt .= '/' unless ($rslt =~ m#/$#); - - $rslt .= $dir; - return $self->SUPER::canonpath($rslt); - } else { - - #with <> posible instead of [. - # Normalize the brackets - # Fixme - need to not switch when preceded by ^. - $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; - - #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. - unless ($path_vms) { - $path =~ s/\.dir\Z(?!\n)//i; - if (($path ne '') && ($path !~ /^-/)) { - # Non blank and not prefixed with '-', add a dot - $path = '[.' . $path; - } else { - # Just start a directory. - $path = '[' . $path; - } - } else { - $path =~ s/\]$//; - } - - #Possible dir values: [.dir] dir and $(foo) - - # No punctuation may have a trailing .dir - unless ($dir_vms) { - $dir =~ s/\.dir\Z(?!\n)//i; - } else { - - #strip off the brackets - $dir =~ s/^\[//; - $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 . ']'; - } else { - $rslt = $path . ']'; - } - } - - } else { - # Traditional ODS-2 mode. - $spath =~ s/\.dir\Z(?!\n)//i; $sdir =~ s/\.dir\Z(?!\n)//i; - - $sdir = $self->eliminate_macros($sdir) - unless $sdir =~ /^[\w\-]+\Z(?!\n)/s; - $rslt = $self->fixpath($self->eliminate_macros($spath)."/$sdir",1); - - # Special case for VMS absolute directory specs: these will have - # had device prepended during trip through Unix syntax in - # eliminate_macros(), since Unix syntax has no way to express - # "absolute from the top of this device's directory tree". - if ($spath =~ /^[\[<][^.\-]/s) { $rslt =~ s/^[^\[<]+//s; } - } - } else { - # Single directory, just make sure it is in directory format - # Return an empty string on null input, and pass through macros. - - if (not defined $dir or not length $dir) { $rslt = ''; } - elsif ($dir =~ /^\$\([^\)]+\)\Z(?!\n)/s) { - $rslt = $dir; - } else { - my $unix_mode = 0; - - if ($efs) { - 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 =~ /^--?$/); - - if ($dir_vms == $dir_unix) { - # Ambiguous, so if in $unix_rpt mode then assume UNIX. - $unix_mode = 1 if $unix_rpt; - } else { - $unix_mode = 1 if $dir_unix; - } - } - - if ($unix_mode) { - return $dir; - } else { - # For VMS, force it to be in directory format - $rslt = vmspath($dir); - } - } - } - return $self->canonpath($rslt); -} - -=item catfile (override) - -Concatenates a list of directory specifications with a filename specification -to build a path. - -=cut - -sub catfile { - my $self = shift; - my $tfile = pop(); - my $file = $self->canonpath($tfile); - my @files = grep {defined() && length()} @_; - - my $efs = $self->_efs; - my $unix_rpt = $self->_unix_rpt; - - # Assume VMS mode - my $unix_mode = 0; - my $file_unix = 0; - my $file_vms = 0; - if ($efs) { - - # Now we need to identify format the file is in - # of the specification in order to merge them. - $file_unix = 1 if ($tfile =~ m#/#); - $file_unix = 1 if ($tfile =~ /^\.\.?$/); - $file_vms = 1 if ($tfile =~ m#[\[<\]]#); - $file_vms = 1 if ($tfile =~ /^--?$/); - - # We may know for sure what the format is. - if (($file_unix != $file_vms)) { - $unix_mode = 1 if ($file_unix && $unix_rpt); - } - } - - my $rslt; - if (@files) { - # concatenate the directories. - my $path; - if (@files == 1) { - $path = $files[0]; - } else { - if ($file_vms) { - # We need to make sure this is in VMS mode to avoid doing - # both a vmsify and unixfy on the same path, as that may - # lose significant data. - my $i = @files - 1; - my $tdir = $files[$i]; - my $tdir_vms = 0; - my $tdir_unix = 0; - $tdir_vms = 1 if ($tdir =~ m#[\[<\]]#); - $tdir_unix = 1 if ($tdir =~ m#/#); - $tdir_unix = 1 if ($tdir =~ /^\.\.?$/); - - if (!$tdir_vms) { - if ($tdir_unix) { - $tdir = vmspath($tdir); - } else { - $tdir =~ s/\.dir\Z(?!\n)//i; - $tdir = '[.' . $tdir . ']'; - } - $files[$i] = $tdir; - } - } - $path = $self->catdir(@files); - } - my $spath = $path; - - # Some thing building a VMS path in pieces may try to pass a - # directory name in filename format, so normalize it. - $spath =~ s/\.dir\Z(?!\n)//i; - - # if the spath ends with a directory delimiter and the file is bare, - # then just concat them. - # FIX-ME: In VMS format "[]<>:" are not delimiters if preceded by '^' - # Quite a bit of Perl does not know that yet. - if ($spath =~ /^[^\)\]\/:>]+\)\Z(?!\n)/s && basename($file) eq $file) { - $rslt = "$spath$file"; - } else { - if ($efs) { - - # Now we need to identify what the directory is in - # of the specification in order to merge them. - my $spath_unix = 0; - $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 =~ /^--?$/); - - # Assume VMS mode - if (($spath_unix == $spath_vms) && - ($file_unix == $file_vms)) { - # Ambigous, so if in $unix_rpt mode then assume UNIX. - $unix_mode = 1 if $unix_rpt; - } else { - $unix_mode = 1 - if (($spath_unix || $file_unix) && $unix_rpt); - } - - if (!$unix_mode) { - if ($spath_vms) { - $spath = '[' . $spath . ']' if $spath =~ /^-/; - $rslt = vmspath($spath); - } else { - $rslt = '[.' . $spath . ']'; - } - $file = vmsify($file) if ($file_unix); - } else { - $spath = unixify($spath) if ($spath_vms); - $rslt = $spath; - $file = unixify($file) if ($file_vms); - - # Unix merge may need a directory delimitor. - # A null path indicates root on Unix. - $rslt .= '/' unless ($rslt =~ m#/$#); - } - - $rslt .= $file; - $rslt =~ s/\]\[//; - - } else { - # Traditional VMS Perl mode expects that this is done. - # Note for future maintainers: - # This is left here for compatibility with perl scripts - # that have come to expect this behavior, even though - # usually the Perl scripts ported to VMS have to be - # patched because of it changing Unix syntax file - # to VMS format. - - $rslt = $self->eliminate_macros($spath); - - - $rslt = vmsify($rslt.((defined $rslt) && - ($rslt ne '') ? '/' : '').unixify($file)); - } - } - } - else { - # Only passed a single file? - my $xfile = $file; - - # Traditional VMS perl expects this conversion. - $xfile = vmsify($file) unless ($efs); - - $rslt = (defined($file) && length($file)) ? $xfile : ''; - } - return $self->canonpath($rslt) unless $unix_rpt; - - # In Unix report mode, do not strip off redundent path information. - return $rslt; -} - - -=item curdir (override) - -Returns a string representation of the current directory: '[]' or '.' - -=cut - -sub curdir { - my $self = shift @_; - return '.' if ($self->_unix_rpt); - return '[]'; -} - -=item devnull (override) - -Returns a string representation of the null device: '_NLA0:' or '/dev/null' - -=cut - -sub devnull { - my $self = shift @_; - return '/dev/null' if ($self->_unix_rpt); - return "_NLA0:"; -} - -=item rootdir (override) - -Returns a string representation of the root directory: 'SYS$DISK:[000000]' -or '/' - -=cut - -sub rootdir { - my $self = shift @_; - if ($self->_unix_rpt) { - # Root may exist, try it first. - my $try = '/'; - my ($dev1, $ino1) = stat('/'); - my ($dev2, $ino2) = stat('.'); - - # Perl falls back to '.' if it can not determine '/' - if (($dev1 != $dev2) || ($ino1 != $ino2)) { - return $try; - } - # Fall back to UNIX format sys$disk. - return '/sys$disk/'; - } - return 'SYS$DISK:[000000]'; -} - -=item tmpdir (override) - -Returns a string representation of the first writable directory -from the following list or '' if none are writable: - - /tmp if C<DECC$FILENAME_REPORT_UNIX> is enabled. - sys$scratch: - $ENV{TMPDIR} - -Since perl 5.8.0, if running under taint mode, and if $ENV{TMPDIR} -is tainted, it is not used. - -=cut - -my $tmpdir; -sub tmpdir { - my $self = shift @_; - return $tmpdir if defined $tmpdir; - if ($self->_unix_rpt) { - $tmpdir = $self->_tmpdir('/tmp', '/sys$scratch', $ENV{TMPDIR}); - return $tmpdir; - } - - $tmpdir = $self->_tmpdir( 'sys$scratch:', $ENV{TMPDIR} ); -} - -=item updir (override) - -Returns a string representation of the parent directory: '[-]' or '..' - -=cut - -sub updir { - my $self = shift @_; - return '..' if ($self->_unix_rpt); - return '[-]'; -} - -=item case_tolerant (override) - -VMS file specification syntax is case-tolerant. - -=cut - -sub case_tolerant { - return 1; -} - -=item path (override) - -Translate logical name DCL$PATH as a searchlist, rather than trying -to C<split> string value of C<$ENV{'PATH'}>. - -=cut - -sub path { - my (@dirs,$dir,$i); - while ($dir = $ENV{'DCL$PATH;' . $i++}) { push(@dirs,$dir); } - return @dirs; -} - -=item file_name_is_absolute (override) - -Checks for VMS directory spec as well as Unix separators. - -=cut - -sub file_name_is_absolute { - my ($self,$file) = @_; - # If it's a logical name, expand it. - $file = $ENV{$file} while $file =~ /^[\w\$\-]+\Z(?!\n)/s && $ENV{$file}; - return scalar($file =~ m!^/!s || - $file =~ m![<\[][^.\-\]>]! || - $file =~ /:[^<\[]/); -} - -=item splitpath (override) - - ($volume,$directories,$file) = File::Spec->splitpath( $path ); - ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file ); - -Passing a true value for C<$no_file> indicates that the path being -split only contains directory components, even on systems where you -can usually (when not supporting a foreign syntax) tell the difference -between directories and files at a glance. - -=cut - -sub splitpath { - my($self,$path, $nofile) = @_; - my($dev,$dir,$file) = ('','',''); - my $efs = $self->_efs; - my $vmsify_path = vmsify($path); - if ($efs) { - my $path_vms = 0; - $path_vms = 1 if ($path =~ m#[\[<\]]#); - $path_vms = 1 if ($path =~ /^--?$/); - if (!$path_vms) { - return $self->SUPER::splitpath($path, $nofile); - } - $vmsify_path = $path; - } - - if ( $nofile ) { - #vmsify('d1/d2/d3') returns '[.d1.d2]d3' - #vmsify('/d1/d2/d3') returns 'd1:[d2]d3' - if( $vmsify_path =~ /(.*)\](.+)/ ){ - $vmsify_path = $1.'.'.$2.']'; - } - $vmsify_path =~ /(.+:)?(.*)/s; - $dir = defined $2 ? $2 : ''; # dir can be '0' - return ($1 || '',$dir,$file); - } - else { - $vmsify_path =~ /(.+:)?([\[<].*[\]>])?(.*)/s; - return ($1 || '',$2 || '',$3); - } -} - -=item splitdir (override) - -Split a directory specification into the components. - -=cut - -sub splitdir { - my($self,$dirspec) = @_; - my @dirs = (); - return @dirs if ( (!defined $dirspec) || ('' eq $dirspec) ); - - my $efs = $self->_efs; - - my $dir_unix = 0; - $dir_unix = 1 if ($dirspec =~ m#/#); - $dir_unix = 1 if ($dirspec =~ /^\.\.?$/); - - # Unix filespecs in EFS mode handled by Unix routines. - if ($efs && $dir_unix) { - return $self->SUPER::splitdir($dirspec); - } - - # FIX ME, only split for VMS delimiters not prefixed with '^'. - - $dirspec =~ tr/<>/[]/; # < and > ==> [ and ] - $dirspec =~ s/\]\[\./\.\]\[/g; # ][. ==> .][ - $dirspec =~ s/\[000000\.\]\[/\[/g; # [000000.][ ==> [ - $dirspec =~ s/\[000000\./\[/g; # [000000. ==> [ - $dirspec =~ s/\.\]\[000000\]/\]/g; # .][000000] ==> ] - $dirspec =~ s/\.\]\[/\./g; # foo.][bar ==> foo.bar - while ($dirspec =~ s/(^|[\[\<\.])\-(\-+)($|[\]\>\.])/$1-.$2$3/g) {} - # That loop does the following - # with any amount of dashes: - # .--. ==> .-.-. - # [--. ==> [-.-. - # .--] ==> .-.-] - # [--] ==> [-.-] - $dirspec = "[$dirspec]" unless $dirspec =~ /[\[<]/; # make legal - $dirspec =~ s/^(\[|<)\./$1/; - @dirs = split /(?<!\^)\./, vmspath($dirspec); - $dirs[0] =~ s/^[\[<]//s; $dirs[-1] =~ s/[\]>]\Z(?!\n)//s; - @dirs; -} - - -=item catpath (override) - -Construct a complete filespec. - -=cut - -sub catpath { - my($self,$dev,$dir,$file) = @_; - - my $efs = $self->_efs; - my $unix_rpt = $self->_unix_rpt; - - my $unix_mode = 0; - 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 =~ /^--?$/); - - if ($efs && (length($dev) == 0)) { - if ($dir_unix == $dir_vms) { - $unix_mode = $unix_rpt; - } else { - $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) { - $dir = vmspath($dir) if $dir_unix; - my ($dir_volume, $dir_dir, $dir_file) = $self->splitpath($dir); - $dev = $dir_volume unless length $dev; - $dir = length $dir_file ? $self->catfile($dir_dir, $dir_file) : - $dir_dir; - } - if ($dev =~ m|^/+([^/]+)|) { $dev = "$1:"; } - else { $dev .= ':' unless $dev eq '' or $dev =~ /:\Z(?!\n)/; } - if (length($dev) or length($dir)) { - if ($efs) { - if ($unix_mode) { - $dir .= '/' unless ($dir =~ m#/$#); - } else { - $dir = vmspath($dir) if (($dir =~ m#/#) || ($dir =~ /^\.\.?$/)); - $dir = "[$dir]" unless $dir =~ /^[\[<]/; - } - } else { - $dir = "[$dir]" unless $dir =~ /[\[<\/]/; - $dir = vmspath($dir); - } - } - "$dev$dir$file"; -} - -=item abs2rel (override) - -Attempt to convert a file specification to a relative specification. -On a system with volumes, like VMS, this may not be possible. - -=cut - -sub abs2rel { - my $self = shift; - my($path,$base) = @_; - - my $efs = $self->_efs; - my $unix_rpt = $self->_unix_rpt; - - if (!$efs) { - return vmspath(File::Spec::Unix::abs2rel( $self, @_ )) - if grep m{/}, @_; - } - - # We need to identify what the directory is in - # of the specification in order to process them - my $path_unix = 0; - $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 =~ /^--?$/); - - my $unix_mode = 0; - if ($path_vms == $path_unix) { - $unix_mode = $unix_rpt; - } else { - $unix_mode = $path_unix; - } - - my $base_unix = 0; - my $base_vms = 0; - - 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 =~ /^--?$/); - - if ($path_vms == $path_unix) { - if ($base_vms == $base_unix) { - $unix_mode = $unix_rpt; - } else { - $unix_mode = $base_unix; - } - } else { - $unix_mode = 0 if $base_vms; - } - } - - if ($efs) { - if ($unix_mode) { - # We are UNIX mode. - $base = unixpath($base) if $base_vms; - $base = 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 - # so that we can remove the common components. - - if ($path =~ m#^/#) { - if (defined $base) { - - # For the shorterm, if the starting directories are - # common, remove them. - my $bq = qq($base); - $bq =~ s/\$/\\\$/; - $path =~ s/^$bq//i; - } - return $path; - } - - return File::Spec::Unix::abs2rel( $self, $path, $base ); - - } else { - $base = vmspath($base) if $base_unix; - $path = vmsify($path) if $path_unix; - } - } - - unless (defined $base and length $base) { - $base = $self->_cwd(); - if ($efs) { - $base_unix = 1 if ($base =~ m#/#); - $base_unix = 1 if ($base =~ /^\.\.?$/); - $base = vmspath($base) if $base_unix; - } - } - - for ($path, $base) { $_ = $self->canonpath($_) } - - # Are we even starting $path on the same (node::)device as $base? Note that - # logical paths or nodename differences may be on the "same device" - # but the comparison that ignores device differences so as to concatenate - # [---] up directory specs is not even a good idea in cases where there is - # a logical path difference between $path and $base nodename and/or device. - # Hence we fall back to returning the absolute $path spec - # if there is a case blind device (or node) difference of any sort - # and we do not even try to call $parse() or consult %ENV for $trnlnm() - # (this module needs to run on non VMS platforms after all). - - my ($path_volume, $path_directories, $path_file) = $self->splitpath($path); - my ($base_volume, $base_directories, $base_file) = $self->splitpath($base); - return $path unless lc($path_volume) eq lc($base_volume); - - for ($path, $base) { $_ = $self->rel2abs($_) } - - # Now, remove all leading components that are the same - my @pathchunks = $self->splitdir( $path_directories ); - my $pathchunks = @pathchunks; - unshift(@pathchunks,'000000') unless $pathchunks[0] eq '000000'; - my @basechunks = $self->splitdir( $base_directories ); - my $basechunks = @basechunks; - unshift(@basechunks,'000000') unless $basechunks[0] eq '000000'; - - while ( @pathchunks && - @basechunks && - lc( $pathchunks[0] ) eq lc( $basechunks[0] ) - ) { - shift @pathchunks ; - shift @basechunks ; - } - - # @basechunks now contains the directories to climb out of, - # @pathchunks now has the directories to descend in to. - if ((@basechunks > 0) || ($basechunks != $pathchunks)) { - $path_directories = join '.', ('-' x @basechunks, @pathchunks) ; - } - else { - $path_directories = join '.', @pathchunks; - } - $path_directories = '['.$path_directories.']'; - return $self->canonpath( $self->catpath( '', $path_directories, $path_file ) ) ; -} - - -=item rel2abs (override) - -Return an absolute file specification from a relative one. - -=cut - -sub rel2abs { - my $self = shift ; - my ($path,$base ) = @_; - return undef unless defined $path; - - my $efs = $self->_efs; - my $unix_rpt = $self->_unix_rpt; - - # We need to identify what the directory is in - # of the specification in order to process them - my $path_unix = 0; - $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 =~ /^--?$/); - - my $unix_mode = 0; - if ($path_vms == $path_unix) { - $unix_mode = $unix_rpt; - } else { - $unix_mode = $path_unix; - } - - my $base_unix = 0; - my $base_vms = 0; - - 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 =~ /^--?$/); - - # If we could not determine the path mode, see if we can find out - # from the base. - if ($path_vms == $path_unix) { - if ($base_vms != $base_unix) { - $unix_mode = $base_unix; - } - } - } - - if (!$efs) { - # Legacy behavior, convert to VMS syntax. - $unix_mode = 0; - if (defined $base) { - $base = vmspath($base) if $base =~ m/\//; - } - - if ($path =~ m/\//) { - $path = ( -d $path || $path =~ m/\/\z/ # educated guessing about - ? vmspath($path) # whether it's a directory - : vmsify($path) ); - } - } - - # Clean up and split up $path - if ( ! $self->file_name_is_absolute( $path ) ) { - # Figure out the effective $base and clean it up. - if ( !defined( $base ) || $base eq '' ) { - $base = $self->_cwd; - } - elsif ( ! $self->file_name_is_absolute( $base ) ) { - $base = $self->rel2abs( $base ) ; - } - else { - $base = $self->canonpath( $base ) ; - } - - if ($efs) { - # base may have changed, so need to look up format again. - if ($unix_mode) { - $base_vms = 1 if ($base =~ m#[\[<\]]#); - $base_vms = 1 if ($base =~ /^--?$/); - $base = unixpath($base) if $base_vms; - $base .= '/' unless ($base =~ m#/$#); - } else { - $base_unix = 1 if ($base =~ m#/#); - $base_unix = 1 if ($base =~ /^\.\.?$/); - $base = vmspath($base) if $base_unix; - } - } - - # Split up paths - my ( $path_directories, $path_file ) = - ($self->splitpath( $path ))[1,2] ; - - my ( $base_volume, $base_directories ) = - $self->splitpath( $base ) ; - - $path_directories = '' if $path_directories eq '[]' || - $path_directories eq '<>'; - my $sep = '' ; - - if ($efs) { - # Merge the paths assuming that the base is absolute. - $base_directories = $self->catdir('', - $base_directories, - $path_directories); - } else { - # Legacy behavior assumes VMS only paths - $sep = '.' - if ( $base_directories =~ m{[^.\]>]\Z(?!\n)} && - $path_directories =~ m{^[^.\[<]}s - ) ; - $base_directories = "$base_directories$sep$path_directories"; - $base_directories =~ s{\.?[\]>][\[<]\.?}{.}; - } - - $path_file = '' if ($path_file eq '.') && $unix_mode; - - $path = $self->catpath( $base_volume, $base_directories, $path_file ); - } - - return $self->canonpath( $path ) ; -} - - -# eliminate_macros() and fixpath() are MakeMaker-specific methods -# which are used inside catfile() and catdir(). MakeMaker has its own -# copies as of 6.06_03 which are the canonical ones. We leave these -# here, in peace, so that File::Spec continues to work with MakeMakers -# prior to 6.06_03. -# -# Please consider these two methods deprecated. Do not patch them, -# patch the ones in ExtUtils::MM_VMS instead. -# -# Update: MakeMaker 6.48 is still using these routines on VMS. -# so they need to be kept up to date with ExtUtils::MM_VMS. -# -# The traditional VMS mode using ODS-2 disks depends on these routines -# being here. These routines should not be called in when the -# C<DECC$EFS_CHARSET> or C<DECC$FILENAME_REPORT_UNIX> modes are enabled. - -sub eliminate_macros { - my($self,$path) = @_; - return '' unless (defined $path) && ($path ne ''); - $self = {} unless ref $self; - - if ($path =~ /\s/) { - return join ' ', map { $self->eliminate_macros($_) } split /\s+/, $path; - } - - my $npath = unixify($path); - # sometimes unixify will return a string with an off-by-one trailing null - $npath =~ s{\0$}{}; - - my($complex) = 0; - my($head,$macro,$tail); - - # perform m##g in scalar context so it acts as an iterator - while ($npath =~ m#(.*?)\$\((\S+?)\)(.*)#gs) { - if (defined $self->{$2}) { - ($head,$macro,$tail) = ($1,$2,$3); - if (ref $self->{$macro}) { - if (ref $self->{$macro} eq 'ARRAY') { - $macro = join ' ', @{$self->{$macro}}; - } - else { - print "Note: can't expand macro \$($macro) containing ",ref($self->{$macro}), - "\n\t(using MMK-specific deferred substitutuon; MMS will break)\n"; - $macro = "\cB$macro\cB"; - $complex = 1; - } - } - else { ($macro = unixify($self->{$macro})) =~ s#/\Z(?!\n)##; } - $npath = "$head$macro$tail"; - } - } - if ($complex) { $npath =~ s#\cB(.*?)\cB#\${$1}#gs; } - $npath; -} - -# Deprecated. See the note above for eliminate_macros(). - -# Catchall routine to clean up problem MM[SK]/Make macros. Expands macros -# in any directory specification, in order to avoid juxtaposing two -# VMS-syntax directories when MM[SK] is run. Also expands expressions which -# are all macro, so that we can tell how long the expansion is, and avoid -# overrunning DCL's command buffer when MM[KS] is running. - -# fixpath() checks to see whether the result matches the name of a -# directory in the current default directory and returns a directory or -# file specification accordingly. C<$is_dir> can be set to true to -# force fixpath() to consider the path to be a directory or false to force -# it to be a file. - -sub fixpath { - my($self,$path,$force_path) = @_; - return '' unless $path; - $self = bless {}, $self unless ref $self; - my($fixedpath,$prefix,$name); - - if ($path =~ /\s/) { - return join ' ', - map { $self->fixpath($_,$force_path) } - split /\s+/, $path; - } - - if ($path =~ m#^\$\([^\)]+\)\Z(?!\n)#s || $path =~ m#[/:>\]]#) { - if ($force_path or $path =~ /(?:DIR\)|\])\Z(?!\n)/) { - $fixedpath = vmspath($self->eliminate_macros($path)); - } - else { - $fixedpath = vmsify($self->eliminate_macros($path)); - } - } - elsif ((($prefix,$name) = ($path =~ m#^\$\(([^\)]+)\)(.+)#s)) && $self->{$prefix}) { - my($vmspre) = $self->eliminate_macros("\$($prefix)"); - # is it a dir or just a name? - $vmspre = ($vmspre =~ m|/| or $prefix =~ /DIR\Z(?!\n)/) ? vmspath($vmspre) : ''; - $fixedpath = ($vmspre ? $vmspre : $self->{$prefix}) . $name; - $fixedpath = vmspath($fixedpath) if $force_path; - } - else { - $fixedpath = $path; - $fixedpath = vmspath($fixedpath) if $force_path; - } - # No hints, so we try to guess - if (!defined($force_path) and $fixedpath !~ /[:>(.\]]/) { - $fixedpath = vmspath($fixedpath) if -d $fixedpath; - } - - # Trim off root dirname if it's had other dirs inserted in front of it. - $fixedpath =~ s/\.000000([\]>])/$1/; - # Special case for VMS absolute directory specs: these will have had device - # prepended during trip through Unix syntax in eliminate_macros(), since - # Unix syntax has no way to express "absolute from the top of this device's - # directory tree". - if ($path =~ /^[\[>][^.\-]/) { $fixedpath =~ s/^[^\[<]+//; } - $fixedpath; -} - - -=back - -=head1 COPYRIGHT - -Copyright (c) 2004 by the Perl 5 Porters. All rights reserved. - -This program is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. - -=head1 SEE ALSO - -See L<File::Spec> and L<File::Spec::Unix>. This package overrides the -implementation of these methods, not the semantics. - -An explanation of VMS file specs can be found at -L<"http://h71000.www7.hp.com/doc/731FINAL/4506/4506pro_014.html#apps_locating_naming_files">. - -=cut - -1; |