xref: /openbsd-src/gnu/usr.bin/perl/dist/PathTools/lib/File/Spec/Win32.pm (revision 3d61058aa5c692477b6d18acfbbdb653a9930ff9)
16fb12b70Safresh1package File::Spec::Win32;
26fb12b70Safresh1
36fb12b70Safresh1use strict;
46fb12b70Safresh1
59f11ffb7Safresh1use Cwd ();
66fb12b70Safresh1require File::Spec::Unix;
76fb12b70Safresh1
8*3d61058aSafresh1our $VERSION = '3.91';
9b8851fccSafresh1$VERSION =~ tr/_//d;
106fb12b70Safresh1
119f11ffb7Safresh1our @ISA = qw(File::Spec::Unix);
126fb12b70Safresh1
136fb12b70Safresh1# Some regexes we use for path splitting
146fb12b70Safresh1my $DRIVE_RX = '[a-zA-Z]:';
156fb12b70Safresh1my $UNC_RX = '(?:\\\\\\\\|//)[^\\\\/]+[\\\\/][^\\\\/]+';
166fb12b70Safresh1my $VOL_RX = "(?:$DRIVE_RX|$UNC_RX)";
176fb12b70Safresh1
186fb12b70Safresh1
196fb12b70Safresh1=head1 NAME
206fb12b70Safresh1
216fb12b70Safresh1File::Spec::Win32 - methods for Win32 file specs
226fb12b70Safresh1
236fb12b70Safresh1=head1 SYNOPSIS
246fb12b70Safresh1
256fb12b70Safresh1 require File::Spec::Win32; # Done internally by File::Spec if needed
266fb12b70Safresh1
276fb12b70Safresh1=head1 DESCRIPTION
286fb12b70Safresh1
296fb12b70Safresh1See File::Spec::Unix for a documentation of the methods provided
306fb12b70Safresh1there. This package overrides the implementation of these methods, not
316fb12b70Safresh1the semantics.
326fb12b70Safresh1
336fb12b70Safresh1=over 4
346fb12b70Safresh1
356fb12b70Safresh1=item devnull
366fb12b70Safresh1
376fb12b70Safresh1Returns a string representation of the null device.
386fb12b70Safresh1
396fb12b70Safresh1=cut
406fb12b70Safresh1
416fb12b70Safresh1sub devnull {
426fb12b70Safresh1    return "nul";
436fb12b70Safresh1}
446fb12b70Safresh1
456fb12b70Safresh1sub rootdir { '\\' }
466fb12b70Safresh1
476fb12b70Safresh1
486fb12b70Safresh1=item tmpdir
496fb12b70Safresh1
506fb12b70Safresh1Returns a string representation of the first existing directory
516fb12b70Safresh1from the following list:
526fb12b70Safresh1
536fb12b70Safresh1    $ENV{TMPDIR}
546fb12b70Safresh1    $ENV{TEMP}
556fb12b70Safresh1    $ENV{TMP}
566fb12b70Safresh1    SYS:/temp
576fb12b70Safresh1    C:\system\temp
586fb12b70Safresh1    C:/temp
596fb12b70Safresh1    /tmp
606fb12b70Safresh1    /
616fb12b70Safresh1
626fb12b70Safresh1The SYS:/temp is preferred in Novell NetWare and the C:\system\temp
636fb12b70Safresh1for Symbian (the File::Spec::Win32 is used also for those platforms).
646fb12b70Safresh1
656fb12b70Safresh1If running under taint mode, and if the environment
666fb12b70Safresh1variables are tainted, they are not used.
676fb12b70Safresh1
686fb12b70Safresh1=cut
696fb12b70Safresh1
706fb12b70Safresh1sub tmpdir {
716fb12b70Safresh1    my $tmpdir = $_[0]->_cached_tmpdir(qw(TMPDIR TEMP TMP));
726fb12b70Safresh1    return $tmpdir if defined $tmpdir;
736fb12b70Safresh1    $tmpdir = $_[0]->_tmpdir( map( $ENV{$_}, qw(TMPDIR TEMP TMP) ),
746fb12b70Safresh1			      'SYS:/temp',
756fb12b70Safresh1			      'C:\system\temp',
766fb12b70Safresh1			      'C:/temp',
776fb12b70Safresh1			      '/tmp',
786fb12b70Safresh1			      '/'  );
796fb12b70Safresh1    $_[0]->_cache_tmpdir($tmpdir, qw(TMPDIR TEMP TMP));
806fb12b70Safresh1}
816fb12b70Safresh1
826fb12b70Safresh1=item case_tolerant
836fb12b70Safresh1
846fb12b70Safresh1MSWin32 case-tolerance depends on GetVolumeInformation() $ouFsFlags == FS_CASE_SENSITIVE,
856fb12b70Safresh1indicating the case significance when comparing file specifications.
866fb12b70Safresh1Since XP FS_CASE_SENSITIVE is effectively disabled for the NT subsubsystem.
8756d68f1eSafresh1See L<http://cygwin.com/ml/cygwin/2007-07/msg00891.html>
886fb12b70Safresh1Default: 1
896fb12b70Safresh1
906fb12b70Safresh1=cut
916fb12b70Safresh1
926fb12b70Safresh1sub case_tolerant {
930b7734b3Safresh1  eval {
940b7734b3Safresh1    local @INC = @INC;
950b7734b3Safresh1    pop @INC if $INC[-1] eq '.';
960b7734b3Safresh1    require Win32API::File;
970b7734b3Safresh1  } or return 1;
986fb12b70Safresh1  my $drive = shift || "C:";
996fb12b70Safresh1  my $osFsType = "\0"x256;
1006fb12b70Safresh1  my $osVolName = "\0"x256;
1016fb12b70Safresh1  my $ouFsFlags = 0;
1026fb12b70Safresh1  Win32API::File::GetVolumeInformation($drive, $osVolName, 256, [], [], $ouFsFlags, $osFsType, 256 );
1036fb12b70Safresh1  if ($ouFsFlags & Win32API::File::FS_CASE_SENSITIVE()) { return 0; }
1046fb12b70Safresh1  else { return 1; }
1056fb12b70Safresh1}
1066fb12b70Safresh1
1076fb12b70Safresh1=item file_name_is_absolute
1086fb12b70Safresh1
1096fb12b70Safresh1As of right now, this returns 2 if the path is absolute with a
1106fb12b70Safresh1volume, 1 if it's absolute with no volume, 0 otherwise.
1116fb12b70Safresh1
1126fb12b70Safresh1=cut
1136fb12b70Safresh1
1146fb12b70Safresh1sub file_name_is_absolute {
1156fb12b70Safresh1
1166fb12b70Safresh1    my ($self,$file) = @_;
1176fb12b70Safresh1
1186fb12b70Safresh1    if ($file =~ m{^($VOL_RX)}o) {
1196fb12b70Safresh1      my $vol = $1;
1206fb12b70Safresh1      return ($vol =~ m{^$UNC_RX}o ? 2
1216fb12b70Safresh1	      : $file =~ m{^$DRIVE_RX[\\/]}o ? 2
1226fb12b70Safresh1	      : 0);
1236fb12b70Safresh1    }
1246fb12b70Safresh1    return $file =~  m{^[\\/]} ? 1 : 0;
1256fb12b70Safresh1}
1266fb12b70Safresh1
1276fb12b70Safresh1=item catfile
1286fb12b70Safresh1
1296fb12b70Safresh1Concatenate one or more directory names and a filename to form a
1306fb12b70Safresh1complete path ending with a filename
1316fb12b70Safresh1
1326fb12b70Safresh1=cut
1336fb12b70Safresh1
1346fb12b70Safresh1sub catfile {
1356fb12b70Safresh1    shift;
1366fb12b70Safresh1
1376fb12b70Safresh1    # Legacy / compatibility support
1386fb12b70Safresh1    #
1396fb12b70Safresh1    shift, return _canon_cat( "/", @_ )
140b46d8ef2Safresh1	if !@_ || $_[0] eq "";
1416fb12b70Safresh1
1426fb12b70Safresh1    # Compatibility with File::Spec <= 3.26:
1436fb12b70Safresh1    #     catfile('A:', 'foo') should return 'A:\foo'.
1446fb12b70Safresh1    return _canon_cat( ($_[0].'\\'), @_[1..$#_] )
1456fb12b70Safresh1        if $_[0] =~ m{^$DRIVE_RX\z}o;
1466fb12b70Safresh1
1476fb12b70Safresh1    return _canon_cat( @_ );
1486fb12b70Safresh1}
1496fb12b70Safresh1
1506fb12b70Safresh1sub catdir {
1516fb12b70Safresh1    shift;
1526fb12b70Safresh1
1536fb12b70Safresh1    # Legacy / compatibility support
1546fb12b70Safresh1    #
1556fb12b70Safresh1    return ""
1566fb12b70Safresh1    	unless @_;
1576fb12b70Safresh1    shift, return _canon_cat( "/", @_ )
1586fb12b70Safresh1	if $_[0] eq "";
1596fb12b70Safresh1
1606fb12b70Safresh1    # Compatibility with File::Spec <= 3.26:
1616fb12b70Safresh1    #     catdir('A:', 'foo') should return 'A:\foo'.
1626fb12b70Safresh1    return _canon_cat( ($_[0].'\\'), @_[1..$#_] )
1636fb12b70Safresh1        if $_[0] =~ m{^$DRIVE_RX\z}o;
1646fb12b70Safresh1
1656fb12b70Safresh1    return _canon_cat( @_ );
1666fb12b70Safresh1}
1676fb12b70Safresh1
1686fb12b70Safresh1sub path {
1696fb12b70Safresh1    my @path = split(';', $ENV{PATH});
1706fb12b70Safresh1    s/"//g for @path;
1716fb12b70Safresh1    @path = grep length, @path;
1726fb12b70Safresh1    unshift(@path, ".");
1736fb12b70Safresh1    return @path;
1746fb12b70Safresh1}
1756fb12b70Safresh1
1766fb12b70Safresh1=item canonpath
1776fb12b70Safresh1
1786fb12b70Safresh1No physical check on the filesystem, but a logical cleanup of a
1796fb12b70Safresh1path. On UNIX eliminated successive slashes and successive "/.".
1806fb12b70Safresh1On Win32 makes
1816fb12b70Safresh1
1826fb12b70Safresh1	dir1\dir2\dir3\..\..\dir4 -> \dir\dir4 and even
1836fb12b70Safresh1	dir1\dir2\dir3\...\dir4   -> \dir\dir4
1846fb12b70Safresh1
1856fb12b70Safresh1=cut
1866fb12b70Safresh1
1876fb12b70Safresh1sub canonpath {
1886fb12b70Safresh1    # Legacy / compatibility support
1896fb12b70Safresh1    #
1906fb12b70Safresh1    return $_[1] if !defined($_[1]) or $_[1] eq '';
1916fb12b70Safresh1    return _canon_cat( $_[1] );
1926fb12b70Safresh1}
1936fb12b70Safresh1
1946fb12b70Safresh1=item splitpath
1956fb12b70Safresh1
1966fb12b70Safresh1   ($volume,$directories,$file) = File::Spec->splitpath( $path );
1976fb12b70Safresh1   ($volume,$directories,$file) = File::Spec->splitpath( $path,
1986fb12b70Safresh1                                                         $no_file );
1996fb12b70Safresh1
2006fb12b70Safresh1Splits a path into volume, directory, and filename portions. Assumes that
2016fb12b70Safresh1the last file is a path unless the path ends in '\\', '\\.', '\\..'
2026fb12b70Safresh1or $no_file is true.  On Win32 this means that $no_file true makes this return
2036fb12b70Safresh1( $volume, $path, '' ).
2046fb12b70Safresh1
2056fb12b70Safresh1Separators accepted are \ and /.
2066fb12b70Safresh1
2076fb12b70Safresh1Volumes can be drive letters or UNC sharenames (\\server\share).
2086fb12b70Safresh1
2096fb12b70Safresh1The results can be passed to L</catpath> to get back a path equivalent to
2106fb12b70Safresh1(usually identical to) the original path.
2116fb12b70Safresh1
2126fb12b70Safresh1=cut
2136fb12b70Safresh1
2146fb12b70Safresh1sub splitpath {
2156fb12b70Safresh1    my ($self,$path, $nofile) = @_;
2166fb12b70Safresh1    my ($volume,$directory,$file) = ('','','');
2176fb12b70Safresh1    if ( $nofile ) {
2186fb12b70Safresh1        $path =~
2196fb12b70Safresh1            m{^ ( $VOL_RX ? ) (.*) }sox;
2206fb12b70Safresh1        $volume    = $1;
2216fb12b70Safresh1        $directory = $2;
2226fb12b70Safresh1    }
2236fb12b70Safresh1    else {
2246fb12b70Safresh1        $path =~
2256fb12b70Safresh1            m{^ ( $VOL_RX ? )
2266fb12b70Safresh1                ( (?:.*[\\/](?:\.\.?\Z(?!\n))?)? )
2276fb12b70Safresh1                (.*)
2286fb12b70Safresh1             }sox;
2296fb12b70Safresh1        $volume    = $1;
2306fb12b70Safresh1        $directory = $2;
2316fb12b70Safresh1        $file      = $3;
2326fb12b70Safresh1    }
2336fb12b70Safresh1
2346fb12b70Safresh1    return ($volume,$directory,$file);
2356fb12b70Safresh1}
2366fb12b70Safresh1
2376fb12b70Safresh1
2386fb12b70Safresh1=item splitdir
2396fb12b70Safresh1
2406fb12b70Safresh1The opposite of L<catdir()|File::Spec/catdir>.
2416fb12b70Safresh1
2426fb12b70Safresh1    @dirs = File::Spec->splitdir( $directories );
2436fb12b70Safresh1
2446fb12b70Safresh1$directories must be only the directory portion of the path on systems
2456fb12b70Safresh1that have the concept of a volume or that have path syntax that differentiates
2466fb12b70Safresh1files from directories.
2476fb12b70Safresh1
2486fb12b70Safresh1Unlike just splitting the directories on the separator, leading empty and
2496fb12b70Safresh1trailing directory entries can be returned, because these are significant
2506fb12b70Safresh1on some OSs. So,
2516fb12b70Safresh1
252*3d61058aSafresh1    File::Spec->splitdir( "/a/b//c/" );
2536fb12b70Safresh1
2546fb12b70Safresh1Yields:
2556fb12b70Safresh1
2566fb12b70Safresh1    ( '', 'a', 'b', '', 'c', '' )
2576fb12b70Safresh1
2586fb12b70Safresh1=cut
2596fb12b70Safresh1
2606fb12b70Safresh1sub splitdir {
2616fb12b70Safresh1    my ($self,$directories) = @_ ;
2626fb12b70Safresh1    #
2636fb12b70Safresh1    # split() likes to forget about trailing null fields, so here we
2646fb12b70Safresh1    # check to be sure that there will not be any before handling the
2656fb12b70Safresh1    # simple case.
2666fb12b70Safresh1    #
2676fb12b70Safresh1    if ( $directories !~ m|[\\/]\Z(?!\n)| ) {
2686fb12b70Safresh1        return split( m|[\\/]|, $directories );
2696fb12b70Safresh1    }
2706fb12b70Safresh1    else {
2716fb12b70Safresh1        #
2726fb12b70Safresh1        # since there was a trailing separator, add a file name to the end,
2736fb12b70Safresh1        # then do the split, then replace it with ''.
2746fb12b70Safresh1        #
2756fb12b70Safresh1        my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
2766fb12b70Safresh1        $directories[ $#directories ]= '' ;
2776fb12b70Safresh1        return @directories ;
2786fb12b70Safresh1    }
2796fb12b70Safresh1}
2806fb12b70Safresh1
2816fb12b70Safresh1
2826fb12b70Safresh1=item catpath
2836fb12b70Safresh1
2846fb12b70Safresh1Takes volume, directory and file portions and returns an entire path. Under
2856fb12b70Safresh1Unix, $volume is ignored, and this is just like catfile(). On other OSs,
2866fb12b70Safresh1the $volume become significant.
2876fb12b70Safresh1
2886fb12b70Safresh1=cut
2896fb12b70Safresh1
2906fb12b70Safresh1sub catpath {
2916fb12b70Safresh1    my ($self,$volume,$directory,$file) = @_;
2926fb12b70Safresh1
2936fb12b70Safresh1    # If it's UNC, make sure the glue separator is there, reusing
2946fb12b70Safresh1    # whatever separator is first in the $volume
2956fb12b70Safresh1    my $v;
2966fb12b70Safresh1    $volume .= $v
2976fb12b70Safresh1        if ( (($v) = $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s) &&
2986fb12b70Safresh1             $directory =~ m@^[^\\/]@s
2996fb12b70Safresh1           ) ;
3006fb12b70Safresh1
3016fb12b70Safresh1    $volume .= $directory ;
3026fb12b70Safresh1
3036fb12b70Safresh1    # If the volume is not just A:, make sure the glue separator is
3046fb12b70Safresh1    # there, reusing whatever separator is first in the $volume if possible.
3056fb12b70Safresh1    if ( $volume !~ m@^[a-zA-Z]:\Z(?!\n)@s &&
3066fb12b70Safresh1         $volume =~ m@[^\\/]\Z(?!\n)@      &&
3076fb12b70Safresh1         $file   =~ m@[^\\/]@
3086fb12b70Safresh1       ) {
3096fb12b70Safresh1        $volume =~ m@([\\/])@ ;
3106fb12b70Safresh1        my $sep = $1 ? $1 : '\\' ;
3116fb12b70Safresh1        $volume .= $sep ;
3126fb12b70Safresh1    }
3136fb12b70Safresh1
3146fb12b70Safresh1    $volume .= $file ;
3156fb12b70Safresh1
3166fb12b70Safresh1    return $volume ;
3176fb12b70Safresh1}
3186fb12b70Safresh1
3196fb12b70Safresh1sub _same {
3206fb12b70Safresh1  lc($_[1]) eq lc($_[2]);
3216fb12b70Safresh1}
3226fb12b70Safresh1
3236fb12b70Safresh1sub rel2abs {
3246fb12b70Safresh1    my ($self,$path,$base ) = @_;
3256fb12b70Safresh1
3266fb12b70Safresh1    my $is_abs = $self->file_name_is_absolute($path);
3276fb12b70Safresh1
3286fb12b70Safresh1    # Check for volume (should probably document the '2' thing...)
3296fb12b70Safresh1    return $self->canonpath( $path ) if $is_abs == 2;
3306fb12b70Safresh1
3316fb12b70Safresh1    if ($is_abs) {
3326fb12b70Safresh1      # It's missing a volume, add one
3339f11ffb7Safresh1      my $vol = ($self->splitpath( Cwd::getcwd() ))[0];
3346fb12b70Safresh1      return $self->canonpath( $vol . $path );
3356fb12b70Safresh1    }
3366fb12b70Safresh1
3376fb12b70Safresh1    if ( !defined( $base ) || $base eq '' ) {
3386fb12b70Safresh1      $base = Cwd::getdcwd( ($self->splitpath( $path ))[0] ) if defined &Cwd::getdcwd ;
3399f11ffb7Safresh1      $base = Cwd::getcwd() unless defined $base ;
3406fb12b70Safresh1    }
3416fb12b70Safresh1    elsif ( ! $self->file_name_is_absolute( $base ) ) {
3426fb12b70Safresh1      $base = $self->rel2abs( $base ) ;
3436fb12b70Safresh1    }
3446fb12b70Safresh1    else {
3456fb12b70Safresh1      $base = $self->canonpath( $base ) ;
3466fb12b70Safresh1    }
3476fb12b70Safresh1
3486fb12b70Safresh1    my ( $path_directories, $path_file ) =
3496fb12b70Safresh1      ($self->splitpath( $path, 1 ))[1,2] ;
3506fb12b70Safresh1
3516fb12b70Safresh1    my ( $base_volume, $base_directories ) =
3526fb12b70Safresh1      $self->splitpath( $base, 1 ) ;
3536fb12b70Safresh1
3546fb12b70Safresh1    $path = $self->catpath(
3556fb12b70Safresh1			   $base_volume,
3566fb12b70Safresh1			   $self->catdir( $base_directories, $path_directories ),
3576fb12b70Safresh1			   $path_file
3586fb12b70Safresh1			  ) ;
3596fb12b70Safresh1
3606fb12b70Safresh1    return $self->canonpath( $path ) ;
3616fb12b70Safresh1}
3626fb12b70Safresh1
3636fb12b70Safresh1=back
3646fb12b70Safresh1
3656fb12b70Safresh1=head2 Note For File::Spec::Win32 Maintainers
3666fb12b70Safresh1
3676fb12b70Safresh1Novell NetWare inherits its File::Spec behaviour from File::Spec::Win32.
3686fb12b70Safresh1
3696fb12b70Safresh1=head1 COPYRIGHT
3706fb12b70Safresh1
3716fb12b70Safresh1Copyright (c) 2004,2007 by the Perl 5 Porters.  All rights reserved.
3726fb12b70Safresh1
3736fb12b70Safresh1This program is free software; you can redistribute it and/or modify
3746fb12b70Safresh1it under the same terms as Perl itself.
3756fb12b70Safresh1
3766fb12b70Safresh1=head1 SEE ALSO
3776fb12b70Safresh1
3786fb12b70Safresh1See L<File::Spec> and L<File::Spec::Unix>.  This package overrides the
3796fb12b70Safresh1implementation of these methods, not the semantics.
3806fb12b70Safresh1
3816fb12b70Safresh1=cut
3826fb12b70Safresh1
3836fb12b70Safresh1
3846fb12b70Safresh1sub _canon_cat				# @path -> path
3856fb12b70Safresh1{
3866fb12b70Safresh1    my ($first, @rest) = @_;
3876fb12b70Safresh1
3886fb12b70Safresh1    my $volume = $first =~ s{ \A ([A-Za-z]:) ([\\/]?) }{}x	# drive letter
3896fb12b70Safresh1    	       ? ucfirst( $1 ).( $2 ? "\\" : "" )
3906fb12b70Safresh1	       : $first =~ s{ \A (?:\\\\|//) ([^\\/]+)
3916fb12b70Safresh1				 (?: [\\/] ([^\\/]+) )?
3926fb12b70Safresh1	       			 [\\/]? }{}xs			# UNC volume
3936fb12b70Safresh1	       ? "\\\\$1".( defined $2 ? "\\$2" : "" )."\\"
3946fb12b70Safresh1	       : $first =~ s{ \A [\\/] }{}x			# root dir
3956fb12b70Safresh1	       ? "\\"
3966fb12b70Safresh1	       : "";
3976fb12b70Safresh1    my $path   = join "\\", $first, @rest;
3986fb12b70Safresh1
3996fb12b70Safresh1    $path =~ tr#\\/#\\\\#s;		# xx/yy --> xx\yy & xx\\yy --> xx\yy
4006fb12b70Safresh1
4016fb12b70Safresh1    					# xx/././yy --> xx/yy
4026fb12b70Safresh1    $path =~ s{(?:
4036fb12b70Safresh1		(?:\A|\\)		# at begin or after a slash
4046fb12b70Safresh1		\.
4056fb12b70Safresh1		(?:\\\.)*		# and more
4066fb12b70Safresh1		(?:\\|\z) 		# at end or followed by slash
4076fb12b70Safresh1	       )+			# performance boost -- I do not know why
4086fb12b70Safresh1	     }{\\}gx;
4096fb12b70Safresh1
4106fb12b70Safresh1    					# xx\yy\..\zz --> xx\zz
4116fb12b70Safresh1    while ( $path =~ s{(?:
4126fb12b70Safresh1		(?:\A|\\)		# at begin or after a slash
4136fb12b70Safresh1		[^\\]+			# rip this 'yy' off
4146fb12b70Safresh1		\\\.\.
4156fb12b70Safresh1		(?<!\A\.\.\\\.\.)	# do *not* replace ^..\..
4166fb12b70Safresh1		(?<!\\\.\.\\\.\.)	# do *not* replace \..\..
4176fb12b70Safresh1		(?:\\|\z) 		# at end or followed by slash
4186fb12b70Safresh1	       )+			# performance boost -- I do not know why
4196fb12b70Safresh1	     }{\\}sx ) {}
4206fb12b70Safresh1
4216fb12b70Safresh1    $path =~ s#\A\\##;			# \xx --> xx  NOTE: this is *not* root
4226fb12b70Safresh1    $path =~ s#\\\z##;			# xx\ --> xx
4236fb12b70Safresh1
4246fb12b70Safresh1    if ( $volume =~ m#\\\z# )
4256fb12b70Safresh1    {					# <vol>\.. --> <vol>\
4266fb12b70Safresh1	$path =~ s{ \A			# at begin
4276fb12b70Safresh1		    \.\.
4286fb12b70Safresh1		    (?:\\\.\.)*		# and more
4296fb12b70Safresh1		    (?:\\|\z) 		# at end or followed by slash
4306fb12b70Safresh1		 }{}x;
4316fb12b70Safresh1
4326fb12b70Safresh1	return $1			# \\HOST\SHARE\ --> \\HOST\SHARE
4336fb12b70Safresh1	    if    $path eq ""
4346fb12b70Safresh1	      and $volume =~ m#\A(\\\\.*)\\\z#s;
4356fb12b70Safresh1    }
4366fb12b70Safresh1    return $path ne "" || $volume ? $volume.$path : ".";
4376fb12b70Safresh1}
4386fb12b70Safresh1
4396fb12b70Safresh11;
440