First release of SPVM::File::Spec, a port of Perl's File::Spec to SPVM. The repository is SPVM::File::Spec.
What is File::Spec?
File::Spec is a Perl module to handle file paths in an OS-independent manner, allowing Linux, Mac, and Windows to have similar descriptions of file paths.
File::Spec implementation difficulties.
Numerous regular expressions
One of the difficulties of implementing File::Spec is that it uses many regular expressions to handle file paths.
Therefore, in porting File::Spec to SPVM, it was necessary to be able to use regular expressions.
I ported Google RE2, a regular expression library, to SPVM as Resource::Re2, and created SPVM::Regex, a wrapper for it.
This allows regular expressions to be used.
See some of the complex regular expressions in SPVM::File::Spec. The handling of file paths, especially on Windows, is complex. This is part of the implementation of a method called canonnpath in SPVM::File::Spec::Win32 to make a path a unique expression.
private method _canon_cat : string ($parts : string[]) {
my $first = $parts->[0];
my $volume = (string)undef;
# drive letter - (C:)
my $re_drive = Regex->new("\A([A-Za-z]:)([\\\\/]?)") ;
$first = $re_drive->replace($first, "");
if ($re_drive->replaced_count > 0) {
$volume = Fn->ucfirst($re_drive->cap1);
if (length $re_drive->cap2) {
$volume . = "\\";
}
}
else {
my $re_unc = Regex->new("\A(? :\\\\\\\\|//)([^\\\\/]+)(? :[\\\\/]([^\\\\/]+))? [\\\\/]?" , "s");
$first = $re_unc->replace($first, "");
# UNC volume (\192.168.201.101)
if ($re_unc->replaced_count > 0) {
$volume = "\\\\" . $re_unc->cap1;
if ($re_unc->cap2) {
$volume . = "\\" . $re_unc->cap2;
}
$volume . = "\\" ;
}
else {
my $re_root = Regex->new("\A[\\\\/]");
$first = $re_root->replace($first, "");
# root dir (\foo)
if ($re_root->replaced_count > 0) {
$volume = "\foo";
}
else {
$volume = "";
}
}
}
$parts->[0] = $first;
my $path = Fn->join("\", $parts);
# /+ to \
$path = Regex->new("/+")->replace_g($path, "\");
# /+ to \
$path = Regex->new("\\\\+")->replace_g($path, "\\");
# xx\. \. \yy --> xx\yy.
$path = Regex->new("(? :(? :\A|\\\\)\. (? :\\\\\.) *(? :\\\\|\z))+")->replace_g($path, "\");
# xx\yy. \zz --> xx\z.
my $parts_list = StringList->new;
$parts = Fn->split("\\", $path);
for (my $i = 0; $i < @$parts; $i++) {
my $part = $parts->[$i];
if ($part eq "...") {
if ($parts_list->length > 0) {
my $before_part = $parts_list->get($parts_list->length - 1);
unless ($before_part eq "...") {
$parts_list->pop;
next;
}
}
}
$parts_list->push($part);
}
$parts = $parts_list->to_array;
$path = Fn->join("\\", $parts);
# \xx --> xx
$path = Regex->new("\A\\\\")->replace_g($path, "");
# xx --> xx
$path = Regex->new("\\\\\z")->replace_g($path, "");
if (Regex->new("\\\\\z")->match($volume)) {
# <vol>\. --> <vol>\.
$path = Regex->new("\A\. \. (? :\\\\\. \.)\.) *(? :\\\\|\z)")->replace($path, "");
# \HOSTHCOSTHCARE --> \HOSTHCARE
my $re = Regex->new("\A(\\\\\\\\. *)\\\\\z", "s");
if (!length $path && $re->match($volume)) {
$path = $re->cap1;
return $path;
}
}
if (length $path || length $volume) {
$path = $volume . $path;
}
else {
$path = "." ;
}
return $path;
}
```
### File Test Operators
File::Spec checks whether a temporary directory is writable in order to locate it. For this reason, file tests must be implemented.
I have implemented the <a href="https://metacpan.org/pod/SPVM::Sys::FileTest">SPVM::Sys::FileTest</a> module for file testing.
method _tmpdir : string ($dirlist : string[]) {
my $interface = (File::Spec::Interface)$self;
my $tmpdir = (string)undef;
for my $dir (@$dirlist) {
if ($dir && Sys::FileTest->d($dir) && Sys::FileTest->w($dir)){
$tmpdir = $dir;
last;
}
}
unless ($tmpdir) {
$tmpdir = $interface->curdir;
}
$tmpdir = $interface->canonpath($tmpdir);
if (! $interface->file_name_is_absolute($tmpdir)) {
$tmpdir = $interface->rel2abs($tmpdir);
if (! $interface->file_name_is_absolute($tmpdir)) {
die "A temporary directory must be converted to an absolute path";
}
}
return $tmpdir;
}
## Current directory
File::Spec needs to be able to handle the current directory for absolute and relative path conversion.
For this purpose I have implemented <a href="https://metacpan.org/pod/SPVM::Cwd">SPVM::Cwd</a>.
The following is an implementation of the rel2abs method that converts a relative path to an absolute path.
method rel2abs : string ($path : string, $base = undef : string) {
my $interface = (File::Spec::Interface)$self;
# Clean up $path
if (! $interface->file_name_is_absolute($path)) {
# Figure out the effective $base and clean it up.
If (! $base || $base eq "") {
$base = Cwd->getcwd;
}
elsif (! $interface->file_name_is_absolute($base)) {
$base = $interface->rel2abs($base) ;
}
else {
$base = $interface->canonpath($base);
}
# Glom them together
$path = $interface->catdir([$base, $path]);
}
my $rel2abs = $interface->canonpath($path);
return $rel2abs;
}
## Inheritance
Since File::Spec is implemented using inheritance, SPVM also supports inheritance. There are subtle differences between statically and dynamically typed languages in terms of expressive feasibility, and SPVM is designed to be as close as possible to Perl's inheritance.
class File::Spec::Unix extends File::Spec {
}
## Immediate Goals
In February 2023, our goal is to port the modules that handle file paths to SPVM.
Porting of File::Copy, FindBin, File::Path, File::Find, File::Temp, etc. to SPVM will be initiated.
Translated with www.DeepL.com/Translator (free version)
Top comments (0)