Updated Path. Some work towards loading dirs.

This commit is contained in:
Christoffer Lerno
2023-03-11 18:32:44 +01:00
parent 7a2d73c690
commit 2607062cb6
6 changed files with 114 additions and 15 deletions

View File

@@ -29,6 +29,7 @@ fault IoError
OUT_OF_DISK,
INVALID_PUSHBACK,
EOF,
CANNOT_READ_DIR,
TOO_MANY_DESCRIPTORS,
FILE_IS_DIR,
READ_ONLY,

View File

@@ -1,10 +1,13 @@
module std::io::path;
import std::collections::list;
const PathEnv DEFAULT_PATH_ENV = env::os_is_win32() ? PathEnv.WIN32 : PathEnv.POSIX;
const char PREFERRED_SEPARATOR_WIN32 = '\\';
const char PREFERRED_SEPARATOR_POSIX = '/';
const char PREFERRED_SEPARATOR = env::os_is_win32() ? PREFERRED_SEPARATOR_WIN32 : PREFERRED_SEPARATOR_POSIX;
typedef PathList = List<Path>;
fault PathResult
{
INVALID_PATH,
@@ -100,6 +103,8 @@ fn Path! Path.append(Path path, String filename, Allocator* using = mem::heap())
};
}
fn Path! Path.tappend(Path path, String filename) => path.append(filename, mem::temp());
fn Path! temp_directory(Allocator* using = mem::heap())
{
return os::native_temp_directory(using);
@@ -214,8 +219,25 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
i++;
continue;
case 2:
// We're walking back, doing so when already at the root is invalid.
if (len == path_start) return PathResult.INVALID_PATH!;
// This is an error: /a/../..
if (len == path_start && has_root) return PathResult.INVALID_PATH!;
// If this .. at the start, or after ../? If so, we just copy ..
if (len == path_start ||
(len - path_start >= 3 && path_str[len - 1] == path_separator
&& path_str[len - 3] == '.' && path_str[len - 3] == '.' &&
(len - 3 == 0 || path_str[len - 4] == path_separator)))
{
if (i != len)
{
path_str[len] = '.';
path_str[len + 1] = '.';
}
len += 2;
if (len < path_len) path_str[len++] = path_separator;
i += 2;
continue;
}
// Step back, now looking at '/' abc/def/. -> abc/def/
len--;
// Step back until finding a separator or the start.
@@ -241,6 +263,8 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
return path_str[:len];
}
fn ZString Path.as_zstr(Path path) => (ZString)path.path_string.ptr;
fn String Path.root_directory(Path path)
{
String path_str = path.as_str();

View File

@@ -3,6 +3,7 @@ import libc;
$if (env::os_is_darwin()):
struct DarwinTimespec @private
{
long tv_sec;

View File

@@ -13,6 +13,40 @@ fn Path! native_temp_directory(Allocator* using = mem::heap())
return path::new("/tmp", using);
}
$if (env::COMPILER_LIBC_AVAILABLE):
extern fn void* opendir(ZString);
extern fn void closedir(void*);
const DT_UNKNOWN = 0;
const DT_FIFO = 1;
const DT_CHR = 2;
const DT_DIR = 4;
const DT_BLK = 6;
const DT_REG = 8;
const DT_LNK = 10;
const DT_SOCK = 12;
const DT_WHT = 14;
fn void! native_readdir(PathList* list, Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* using)
{
void* directory = opendir(dir.as_str() ? dir.as_zstr() : (ZString)".");
defer if (directory) closedir(directory);
if (!directory) return (dir.is_dir() ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)!;
NativeDirentry* entry;
while ((entry = readdir(directory)))
{
String name = ((ZString)&entry.name).as_str();
if (!name || name == "." || name == "..") continue;
if (entry.type == DT_LNK && no_symlinks) continue;
if (entry.type == DT_DIR && no_dirs) continue;
Path path = path::new(name.copy(using), using)!!;
list.append(path);
}
}
$endif;
$endif;
$if (!env::os_is_darwin() && !env::os_is_win32()):
@@ -67,4 +101,42 @@ fn bool native_is_file(String path)
$endif;
$endif;
$endif;
$switch (env::OS_TYPE):
$case IOS:
$case MACOSX:
$case TVOS:
$case WATCHOS:
extern fn NativeDirentry* readdir(void*) @extern("readdir$INODE64");
struct NativeDirentry
{
usz ino;
usz seekoff;
ushort reclen;
ushort namelen;
char type;
char[1024] name;
}
$case LINUX:
extern fn NativeDirentry* readdir(void*);
struct NativeDirentry
{
usz ino;
isz seekoff;
ushort reclen;
char type;
char[*] name;
}
$default:
// Fix this as we go along.
extern fn NativeDirentry* readdir(void*);
struct NativeDirentry
{
usz ino;
isz seekoff;
ushort reclen;
char type;
char[*] name;
}
$endswitch;

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.105"
#define COMPILER_VERSION "0.4.106"

View File

@@ -24,18 +24,10 @@ fn void! test_path_normalized()
assert(catch(path::new(`\\server\a\b\..\..\..\c`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`\\a`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`a/b/../../../c`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`a/b/../../../c`, .path_env = PathEnv.POSIX)));
assert(catch(path::new(`/a/b/../../../c`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`/a/b/../../../c`, .path_env = PathEnv.POSIX)));
assert(catch(path::new(`a/b/../../..`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`a/b/../../..`, .path_env = PathEnv.POSIX)));
assert(catch(path::new(`/a/b/../../..`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`/a/b/../../..`, .path_env = PathEnv.POSIX)));
assert(catch(path::new(`../a`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`../a`, .path_env = PathEnv.POSIX)));
assert(catch(path::new(`..`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`..`, .path_env = PathEnv.POSIX)));
assert(catch(path::new(`/../a`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`/../a`, .path_env = PathEnv.POSIX)));
assert(catch(path::new(`/..`, .path_env = PathEnv.WIN32)));
@@ -43,9 +35,6 @@ fn void! test_path_normalized()
assert(catch(path::new(`C:/a/b/../../../c`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`C:/../a`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`C:/..`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`C:a/b/../../../c`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`C:../a`, .path_env = PathEnv.WIN32)));
assert(catch(path::new(`C:..`, .path_env = PathEnv.WIN32)));
assert(path::new("/", .path_env = PathEnv.POSIX).as_str()? == "/");
assert(path::new("/./", .path_env = PathEnv.POSIX).as_str()? == "/");
@@ -64,6 +53,15 @@ fn void! test_path_normalized()
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(`a/b/../../../c`, .path_env = PathEnv.WIN32).as_str()? == `..\c`);
assert(path::new(`a/b/../../../c`, .path_env = PathEnv.POSIX).as_str()? == `../c`);
assert(path::new(`a/b/../../..`, .path_env = PathEnv.WIN32).as_str()? == `..`);
assert(path::new(`a/b/../../..`, .path_env = PathEnv.POSIX).as_str()? == `..`);
assert(path::new(`../a`, .path_env = PathEnv.WIN32).as_str()? == `..\a`);
assert(path::new(`../a`, .path_env = PathEnv.POSIX).as_str()? == `../a`);
assert(path::new(`..`, .path_env = PathEnv.WIN32).as_str()? == `..`);
assert(path::new(`..`, .path_env = PathEnv.POSIX).as_str()? == `..`);
assert(path::new(`a/b/../c`, .path_env = PathEnv.WIN32).as_str()? == `a\c`);
assert(path::new(`a/b/../c`, .path_env = PathEnv.POSIX).as_str()? == `a/c`);
assert(path::new(`a/b/../../c`, .path_env = PathEnv.WIN32).as_str()? == `c`);
@@ -162,12 +160,15 @@ fn void! test_path_normalized()
assert(path::new(`C:a/b//d`, .path_env = PathEnv.POSIX).as_str()? == `C:a/b/d`);
assert(path::new(`C:a/b/././.`, .path_env = PathEnv.WIN32).as_str()? == `C:a\b`);
assert(path::new(`C:a/b/././.`, .path_env = PathEnv.POSIX).as_str()? == `C:a/b`);
assert(path::new(`C:a/b/../../../c`, .path_env = PathEnv.WIN32).as_str()? == `C:..\c`);
assert(path::new(`C:./a`, .path_env = PathEnv.WIN32).as_str()? == `C:a`);
assert(path::new(`C:./a`, .path_env = PathEnv.POSIX).as_str()? == `C:./a`);
assert(path::new(`C:./`, .path_env = PathEnv.WIN32).as_str()? == `C:`);
assert(path::new(`C:./`, .path_env = PathEnv.POSIX).as_str()? == `C:.`);
assert(path::new(`C:../a`, .path_env = PathEnv.POSIX).as_str()? == `C:../a`);
assert(path::new(`C:../a`, .path_env = PathEnv.WIN32).as_str()? == `C:..\a`);
assert(path::new(`C:..`, .path_env = PathEnv.POSIX).as_str()? == `C:..`);
assert(path::new(`C:..`, .path_env = PathEnv.WIN32).as_str()? == `C:..`);
assert(path::new(`C:`, .path_env = PathEnv.WIN32).as_str()? == `C:`);
assert(path::new(`C:`, .path_env = PathEnv.POSIX).as_str()? == `C:`);