mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 09:40:21 +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;
|
|
}
|
|
}
|
|
}
|