mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
add is_absolute and absolute methods to path::Path (#882)
* lib/std/io/os: remove unnecessary dup in native_ls Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * lib/std/core: add String.index_of_char and String.rindex_of_char Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * lib/std/io: add Path.is_absolute Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * lib/std/io: add Path.absolute Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * lib/std: fix Path.normalize on files starting with `.`; add Path.walk Signed-off-by: Pierre Curto <pierre.curto@gmail.com> --------- Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
@@ -202,6 +202,42 @@ fn bool String.contains(s, String needle)
|
||||
return @ok(s.index_of(needle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the first incidence of a string.
|
||||
*
|
||||
* @param [in] s
|
||||
* @pure
|
||||
* @ensure return < s.len
|
||||
* @return "the index of the needle"
|
||||
* @return! SearchResult.MISSING "if the needle cannot be found"
|
||||
**/
|
||||
fn usz! String.index_of_char(s, char needle)
|
||||
{
|
||||
foreach (i, c : s)
|
||||
{
|
||||
if (c == needle) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the first incidence of a string.
|
||||
*
|
||||
* @param [in] s
|
||||
* @pure
|
||||
* @ensure return < s.len
|
||||
* @return "the index of the needle"
|
||||
* @return! SearchResult.MISSING "if the needle cannot be found"
|
||||
**/
|
||||
fn usz! String.rindex_of_char(s, char needle)
|
||||
{
|
||||
foreach_r (i, c : s)
|
||||
{
|
||||
if (c == needle) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the first incidence of a string.
|
||||
*
|
||||
@@ -215,10 +251,11 @@ fn bool String.contains(s, String needle)
|
||||
**/
|
||||
fn usz! String.index_of(s, String needle)
|
||||
{
|
||||
usz match = 0;
|
||||
usz needed = needle.len;
|
||||
usz index_start = 0;
|
||||
char search = needle[0];
|
||||
if (needed == 1) return s.index_of_char(search);
|
||||
usz match = 0;
|
||||
usz index_start = 0;
|
||||
foreach (usz i, char c : s)
|
||||
{
|
||||
if (c == search)
|
||||
@@ -251,10 +288,11 @@ fn usz! String.index_of(s, String needle)
|
||||
**/
|
||||
fn usz! String.rindex_of(s, String needle)
|
||||
{
|
||||
usz match = 0;
|
||||
usz needed = needle.len;
|
||||
usz index_start = 0;
|
||||
char search = needle[^1];
|
||||
if (needed == 1) return s.rindex_of_char(search);
|
||||
usz match;
|
||||
usz index_start;
|
||||
foreach_r (usz i, char c : s)
|
||||
{
|
||||
if (c == search)
|
||||
|
||||
@@ -14,7 +14,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
|
||||
if (!name || name == "." || name == "..") continue;
|
||||
if (entry.d_type == posix::DT_LNK && no_symlinks) continue;
|
||||
if (entry.d_type == posix::DT_DIR && no_dirs) continue;
|
||||
Path path = path::new(name.copy(using), using)!!;
|
||||
Path path = path::new(name, using)!!;
|
||||
list.append(path);
|
||||
}
|
||||
return list;
|
||||
|
||||
@@ -26,7 +26,6 @@ enum PathEnv
|
||||
POSIX
|
||||
}
|
||||
|
||||
|
||||
fn Path! getcwd(Allocator* using = mem::heap())
|
||||
{
|
||||
@pool(using)
|
||||
@@ -138,7 +137,6 @@ fn bool Path.equals(self, Path p2)
|
||||
* Append the string to the current path.
|
||||
*
|
||||
* @param [in] filename
|
||||
* @ensure return.path_string.len >= self.path_string.len
|
||||
**/
|
||||
fn Path! Path.append(self, String filename, Allocator* using = mem::heap())
|
||||
{
|
||||
@@ -163,9 +161,38 @@ fn usz Path.start_of_base_name(self) @local
|
||||
if (!path_str.len) return 0;
|
||||
if (self.env == PathEnv.WIN32)
|
||||
{
|
||||
return path_str.rindex_of(`\`) + 1 ?? volume_name_len(path_str, self.env)!!;
|
||||
return path_str.rindex_of_char('\\') + 1 ?? volume_name_len(path_str, self.env)!!;
|
||||
}
|
||||
return path_str.rindex_of("/") + 1 ?? 0;
|
||||
return path_str.rindex_of_char('/') + 1 ?? 0;
|
||||
}
|
||||
|
||||
fn bool! Path.is_absolute(self)
|
||||
{
|
||||
String path_str = self.as_str();
|
||||
if (!path_str.len) return false;
|
||||
usz path_start = volume_name_len(path_str, self.env)!;
|
||||
return path_start < path_str.len && is_separator(path_str[path_start], self.env);
|
||||
}
|
||||
|
||||
fn Path! Path.absolute(self, Allocator* using = mem::heap())
|
||||
{
|
||||
String path_str = self.as_str();
|
||||
if (!path_str.len) path_str = ".";
|
||||
if (path_str == ".")
|
||||
{
|
||||
String cwd = os::getcwd(mem::temp())!;
|
||||
return new(cwd, using, self.env);
|
||||
}
|
||||
switch (self.env)
|
||||
{
|
||||
case WIN32:
|
||||
usz path_start = volume_name_len(path_str, self.env)!;
|
||||
if (path_start > 0) return self;
|
||||
case POSIX:
|
||||
if (path_str[0] == PREFERRED_SEPARATOR_POSIX) return self;
|
||||
}
|
||||
String cwd = os::getcwd(mem::temp())!;
|
||||
return Path{ cwd, self.env }.append(path_str, using)!;
|
||||
}
|
||||
|
||||
fn String Path.basename(self)
|
||||
@@ -247,7 +274,7 @@ fn Path! Path.parent(self)
|
||||
|
||||
fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
{
|
||||
if (!path_str.len) return path_str;
|
||||
if (!path_str.len) return "";
|
||||
usz path_start = volume_name_len(path_str, path_env)!;
|
||||
usz path_len = path_str.len;
|
||||
if (path_start == path_len) return path_str;
|
||||
@@ -288,14 +315,21 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
// Get the number of dots until next separator, expecting 1 or 2
|
||||
bool is_last = i == path_len - 1;
|
||||
int dots = 1;
|
||||
if (!is_last && path_str[i + 1] == '.')
|
||||
if (!is_last)
|
||||
{
|
||||
char next = path_str[i + 1];
|
||||
switch
|
||||
{
|
||||
case next == '.':
|
||||
dots = 2;
|
||||
is_last = i == path_len - 2;
|
||||
if (!is_last && !is_separator(path_str[i + 2], path_env))
|
||||
{
|
||||
dots = 0;
|
||||
}
|
||||
case !is_separator(next, path_env):
|
||||
dots = 0;
|
||||
}
|
||||
}
|
||||
switch (dots)
|
||||
{
|
||||
@@ -373,8 +407,24 @@ fn String Path.root_directory(self)
|
||||
return path_str;
|
||||
}
|
||||
|
||||
def PathWalker = fn bool(Path);
|
||||
|
||||
fn String Path.as_str(self)
|
||||
fn bool! Path.walk(self, PathWalker w, Allocator* using = mem::heap())
|
||||
{
|
||||
Path abs = self.absolute(using)!;
|
||||
defer abs.free();
|
||||
PathList files = ls(abs, .using = using)!;
|
||||
foreach (f : files)
|
||||
{
|
||||
if (f.as_str() == "." || f.as_str() == "..") continue;
|
||||
f = abs.append(f.as_str(), using)!;
|
||||
if (w(f)) return true;
|
||||
if (is_dir(f) && f.walk(w, using)!) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn String Path.as_str(self) @inline
|
||||
{
|
||||
return self.path_string;
|
||||
}
|
||||
@@ -385,13 +435,11 @@ fn bool Path.has_suffix(self, String str)
|
||||
return self.as_str().ends_with(str);
|
||||
}
|
||||
|
||||
|
||||
fn void Path.free(self)
|
||||
{
|
||||
free(self.path_string.ptr);
|
||||
}
|
||||
|
||||
|
||||
const bool[256] RESERVED_PATH_CHAR_POSIX = {
|
||||
[0] = true,
|
||||
['/'] = true,
|
||||
@@ -420,4 +468,3 @@ macro bool is_reserved_path_char(char c, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
? RESERVED_PATH_CHAR_WIN32[c]
|
||||
: RESERVED_PATH_CHAR_POSIX[c];
|
||||
}
|
||||
|
||||
|
||||
@@ -92,3 +92,19 @@ fn void! test_rindex_of()
|
||||
assert(test.rindex_of("world")! == 6);
|
||||
assert(@catchof(test.rindex_of("wi")));
|
||||
}
|
||||
|
||||
fn void! test_index_of_char()
|
||||
{
|
||||
String test = "hello world hello";
|
||||
assert(test.index_of_char('o')! == 4);
|
||||
assert(test.index_of_char('l')! == 2);
|
||||
assert(@catchof(test.index_of_char('x')));
|
||||
}
|
||||
|
||||
fn void! test_rindex_of_char()
|
||||
{
|
||||
String test = "hello world hello";
|
||||
assert(test.rindex_of_char('o')! == 16);
|
||||
assert(test.rindex_of_char('l')! == 15);
|
||||
assert(@catchof(test.index_of_char('x')));
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
module std::io::path @test;
|
||||
|
||||
|
||||
fn void! test_parent()
|
||||
{
|
||||
Path p = path::new("")!;
|
||||
@@ -42,6 +41,8 @@ fn void! test_path_normalized()
|
||||
assert(path::new("/foo/bar/../", .path_env = PathEnv.POSIX).as_str()! == "/foo");
|
||||
assert(path::new("/foo//bar", .path_env = PathEnv.POSIX).as_str()! == "/foo/bar");
|
||||
assert(path::new("/foo//bar/../", .path_env = PathEnv.POSIX).as_str()! == "/foo");
|
||||
assert(path::new("/foo/.bar", .path_env = PathEnv.POSIX).as_str()! == "/foo/.bar");
|
||||
assert(path::new(`\foo\.bar`, .path_env = PathEnv.WIN32).as_str()! == `\foo\.bar`);
|
||||
assert(path::new("a\\b/c.txt", .path_env = PathEnv.WIN32).as_str()! == `a\b\c.txt`);
|
||||
assert(path::new("a\\b/c.txt", .path_env = PathEnv.POSIX).as_str()! == "a\\b/c.txt");
|
||||
assert(path::new("C:\\a\\b/c.txt", .path_env = PathEnv.WIN32).as_str()! == `C:\a\b\c.txt`);
|
||||
@@ -223,7 +224,6 @@ fn void! test_extension()
|
||||
|
||||
fn void! test_basename()
|
||||
{
|
||||
|
||||
assert(path::new_windows("file.txt").basename()! == "file.txt");
|
||||
assert(path::new_posix("file.txt").basename()! == "file.txt");
|
||||
|
||||
@@ -251,7 +251,6 @@ fn void! test_basename()
|
||||
|
||||
fn void! test_dirname()
|
||||
{
|
||||
|
||||
assert(path::new_windows("file.txt").dirname()! == "");
|
||||
assert(path::new_posix("file.txt").dirname()! == "");
|
||||
|
||||
@@ -289,3 +288,25 @@ fn void! test_path_volume()
|
||||
assert(path::new_windows(`\\server\`).volume_name()! == `\\server`);
|
||||
assert(path::new_windows(`\\server\abc`).volume_name()! == `\\server`);
|
||||
}
|
||||
|
||||
fn void! test_path_is_absolute()
|
||||
{
|
||||
assert(!path::new_posix("").is_absolute()!);
|
||||
assert(path::new_posix("/").is_absolute()!);
|
||||
assert(path::new_posix("/a/b").is_absolute()!);
|
||||
assert(!path::new_posix("a/b").is_absolute()!);
|
||||
|
||||
assert(!path::new_windows(`C:`).is_absolute()!);
|
||||
assert(path::new_windows(`C:\abs`).is_absolute()!);
|
||||
assert(!path::new_windows(`C:abs`).is_absolute()!);
|
||||
assert(path::new_windows(`\\server\`).is_absolute()!);
|
||||
assert(path::new_windows(`\\server\abc`).is_absolute()!);
|
||||
}
|
||||
|
||||
fn void! test_path_absolute()
|
||||
{
|
||||
assert(path::new_posix("/").absolute()!.as_str() == "/");
|
||||
assert(path::new_posix(".").absolute()!.as_str() == path::getcwd(mem::temp())!!.as_str());
|
||||
|
||||
assert(path::new_windows(`C:\abs`).absolute()!.as_str() == `C:\abs`);
|
||||
}
|
||||
Reference in New Issue
Block a user