mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			208 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Raku
		
	
	
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Raku
		
	
	
	
	
	
my class IO::Spec::Win32 is IO::Spec::Unix {
 | 
						|
 | 
						|
    # Some regexes we use for path splitting
 | 
						|
    my $slash	    = regex {  <[\/ \\]> }
 | 
						|
    my $notslash    = regex { <-[\/ \\]> }
 | 
						|
    my $driveletter = regex { <[A..Z a..z]> ':' }
 | 
						|
    my $UNCpath     = regex { [<$slash> ** 2] <$notslash>+  <$slash>  [<$notslash>+ | $] }
 | 
						|
    my $volume_rx   = regex { <$driveletter> | <$UNCpath> }
 | 
						|
 | 
						|
    method canonpath ($path, :$parent) {
 | 
						|
        $path eq '' ?? '' !! self!canon-cat($path, :$parent);
 | 
						|
    }
 | 
						|
 | 
						|
    method catdir(*@dirs) {
 | 
						|
        return "" unless @dirs;
 | 
						|
        return self!canon-cat( "\\", |@dirs ) if @dirs[0] eq "";
 | 
						|
        self!canon-cat(|@dirs);
 | 
						|
    }
 | 
						|
 | 
						|
    method splitdir($dir)        { $dir.split($slash)  }
 | 
						|
    method catfile(|c)           { self.catdir(|c)     }
 | 
						|
    method devnull               { 'nul'               }
 | 
						|
    method rootdir               { '\\'                }
 | 
						|
 | 
						|
    method tmpdir {
 | 
						|
        first( { .defined && .IO.d && .IO.w },
 | 
						|
            %*ENV<TMPDIR>,
 | 
						|
            %*ENV<TEMP>,
 | 
						|
            %*ENV<TMP>,
 | 
						|
            'SYS:/temp',
 | 
						|
            'C:\system\temp',
 | 
						|
            'C:/temp',
 | 
						|
            '/tmp',
 | 
						|
            '/')
 | 
						|
          || self.curdir;
 | 
						|
    }
 | 
						|
 | 
						|
    method path {
 | 
						|
       my @path = split(';', %*ENV<PATH>);
 | 
						|
       @path».=subst(:global, q/"/, '');
 | 
						|
       @path = grep *.chars, @path;
 | 
						|
       unshift @path, ".";
 | 
						|
       return @path;
 | 
						|
   }
 | 
						|
 | 
						|
    method is-absolute ($path) {
 | 
						|
        # As of right now, this returns 2 if the path is absolute with a
 | 
						|
        # volume, 1 if it's absolute with no volume, 0 otherwise.
 | 
						|
        given $path {
 | 
						|
            when /^ [<$driveletter> <$slash> | <$UNCpath>]/ { 2 }
 | 
						|
            when /^ <$slash> /                              { 1 }
 | 
						|
            default                     { 0 }
 | 
						|
        }   #/
 | 
						|
    }
 | 
						|
 | 
						|
    method split ($path as Str is copy) { 
 | 
						|
        $path ~~ s[ <$slash>+ $] = ''                       #=
 | 
						|
            unless $path ~~ /^ <$driveletter>? <$slash>+ $/;
 | 
						|
 | 
						|
        $path ~~ 
 | 
						|
            m/^ ( <$volume_rx> ? )
 | 
						|
            ( [ .* <$slash> ]? )
 | 
						|
            (.*)
 | 
						|
             /;
 | 
						|
        my ($volume, $directory, $basename) = (~$0, ~$1, ~$2);
 | 
						|
        $directory ~~ s/ <?after .> <$slash>+ $//;
 | 
						|
 | 
						|
 | 
						|
        if all($directory, $basename) eq '' && $volume ne '' {
 | 
						|
            $directory = $volume ~~ /^<$driveletter>/
 | 
						|
                     ?? '.' !! '\\';
 | 
						|
        }
 | 
						|
        $basename = '\\'  if $directory eq any('/', '\\') && $basename eq '';
 | 
						|
        $directory = '.'  if $directory eq ''             && $basename ne '';
 | 
						|
 | 
						|
        return (:$volume, :$directory, :$basename);
 | 
						|
    }
 | 
						|
 | 
						|
    method join ($volume, $directory is copy, $file is copy) { 
 | 
						|
        $directory = '' if $directory eq '.' && $file.chars;
 | 
						|
        if $directory.match( /^<$slash>$/ ) && $file.match( /^<$slash>$/ ) {
 | 
						|
            $file = '';
 | 
						|
            $directory = '' if $volume.chars > 2; #i.e. UNC path
 | 
						|
        }
 | 
						|
        self.catpath($volume, $directory, $file);
 | 
						|
    }
 | 
						|
 | 
						|
    method splitpath($path as Str, :$nofile = False) { 
 | 
						|
 | 
						|
        my ($volume,$directory,$file) = ('','','');
 | 
						|
        if ( $nofile ) {
 | 
						|
            $path ~~ 
 | 
						|
                /^ (<$volume_rx>?) (.*) /;
 | 
						|
            $volume    = ~$0;
 | 
						|
            $directory = ~$1;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            $path ~~ 
 | 
						|
                m/^ ( <$volume_rx> ? )
 | 
						|
                ( [ .* <$slash> [ '.' ** 1..2 $]? ]? )
 | 
						|
                (.*)
 | 
						|
                 /;
 | 
						|
            $volume    = ~$0;
 | 
						|
            $directory = ~$1;
 | 
						|
            $file      = ~$2;
 | 
						|
        }
 | 
						|
 | 
						|
        return ($volume,$directory,$file);
 | 
						|
    }
 | 
						|
 | 
						|
    method catpath($volume is copy, $directory, $file) {
 | 
						|
 | 
						|
        # Make sure the glue separator is present
 | 
						|
        # unless it's a relative path like A:foo.txt
 | 
						|
        if $volume.chars and $directory.chars
 | 
						|
           and $volume !~~ /^<$driveletter>/
 | 
						|
           and $volume !~~ /<$slash> $/
 | 
						|
           and $directory !~~ /^ <$slash>/
 | 
						|
            { $volume ~= '\\' }
 | 
						|
        if $file.chars and $directory.chars
 | 
						|
           and $directory !~~ /<$slash> $/
 | 
						|
            { $volume ~ $directory ~ '\\' ~ $file; }
 | 
						|
        else     { $volume ~ $directory     ~    $file; }
 | 
						|
    }
 | 
						|
 | 
						|
    method rel2abs ($path is copy, $base? is copy) {
 | 
						|
 | 
						|
        my $is_abs = self.is-absolute($path);
 | 
						|
 | 
						|
        # Check for volume (should probably document the '2' thing...)
 | 
						|
        return self.canonpath( $path ) if $is_abs == 2;
 | 
						|
 | 
						|
        if $is_abs {
 | 
						|
            # It's missing a volume, add one
 | 
						|
            my $vol;
 | 
						|
            $vol = self.splitpath($base)[0] if $base.defined;
 | 
						|
            $vol ||= self.splitpath($*CWD)[0];
 | 
						|
            return self.canonpath( $vol ~ $path );
 | 
						|
        }
 | 
						|
 | 
						|
        if not defined $base {
 | 
						|
        # TODO: implement _getdcwd call ( Windows maintains separate CWD for each volume )
 | 
						|
        # See: http://msdn.microsoft.com/en-us/library/1e5zwe0c%28v=vs.80%29.aspx
 | 
						|
            #$base = Cwd::getdcwd( (self.splitpath: $path)[0] ) if defined &Cwd::getdcwd ;
 | 
						|
            #$base //= $*CWD ;
 | 
						|
            $base = $*CWD;
 | 
						|
        }
 | 
						|
        elsif ( !self.is-absolute( $base ) ) {
 | 
						|
            $base = self.rel2abs( $base );
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            $base = self.canonpath( $base );
 | 
						|
        }
 | 
						|
 | 
						|
        my ($path_directories, $path_file) = self.splitpath( $path )[1..2] ;
 | 
						|
 | 
						|
        my ($base_volume, $base_directories) = self.splitpath( $base, :nofile ) ;
 | 
						|
 | 
						|
        $path = self.catpath( 
 | 
						|
                    $base_volume, 
 | 
						|
                    self.catdir( $base_directories, $path_directories ), 
 | 
						|
                    $path_file
 | 
						|
                    ) ;
 | 
						|
 | 
						|
        return self.canonpath( $path ) ;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    method !canon-cat ( $first, *@rest, :$parent --> Str) {
 | 
						|
 | 
						|
        $first ~~ /^ ([   <$driveletter> <$slash>?
 | 
						|
                        | <$UNCpath>
 | 
						|
                        | [<$slash> ** 2] <$notslash>+
 | 
						|
                        | <$slash> ]?)
 | 
						|
                       (.*)
 | 
						|
                   /;
 | 
						|
        my Str ($volume, $path) = ~$0, ~$1;
 | 
						|
 | 
						|
        $volume.=subst(:g, '/', '\\');
 | 
						|
        if $volume ~~ /^<$driveletter>/ {
 | 
						|
            $volume.=uc;
 | 
						|
        }
 | 
						|
        elsif $volume.chars && $volume !~~ / '\\' $/ {
 | 
						|
            $volume ~= '\\';
 | 
						|
        }
 | 
						|
 | 
						|
        $path = join "\\", $path, @rest.flat;
 | 
						|
        $path ~~ s:g/ <$slash>+ /\\/;                              # /xx\\yy   --> \xx\yy
 | 
						|
        $path ~~ s:g/[ ^ | '\\']   '.'  '\\.'*  [ '\\' | $ ]/\\/;  # xx/././yy --> xx/yy
 | 
						|
        if $parent {
 | 
						|
            while $path ~~ s:g { [^ | <?after '\\'>] <!before '..\\'> <-[\\]>+ '\\..' ['\\' | $ ] } = '' { };
 | 
						|
        }
 | 
						|
        $path ~~ s/^ '\\'+ //;        # \xx --> xx  NOTE: this is *not* root
 | 
						|
        $path ~~ s/ '\\'+ $//;        # xx\ --> xx
 | 
						|
        if $volume ~~ / '\\' $ / {    # <vol>\.. --> <vol>\ 
 | 
						|
            $path ~~ s/ ^  '..'  '\\..'*  [ '\\' | $ ] //;
 | 
						|
        }
 | 
						|
 | 
						|
        if $path eq '' {        # \\HOST\SHARE\ --> \\HOST\SHARE
 | 
						|
            $volume ~~ s/<?after '\\\\' .*> '\\' $ //;
 | 
						|
            $volume || '.';
 | 
						|
        }
 | 
						|
	else {
 | 
						|
            $volume ~ $path;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |