mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Updated Path. Some work towards loading dirs.
This commit is contained in:
@@ -29,6 +29,7 @@ fault IoError
|
||||
OUT_OF_DISK,
|
||||
INVALID_PUSHBACK,
|
||||
EOF,
|
||||
CANNOT_READ_DIR,
|
||||
TOO_MANY_DESCRIPTORS,
|
||||
FILE_IS_DIR,
|
||||
READ_ONLY,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -3,6 +3,7 @@ import libc;
|
||||
|
||||
$if (env::os_is_darwin()):
|
||||
|
||||
|
||||
struct DarwinTimespec @private
|
||||
{
|
||||
long tv_sec;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.105"
|
||||
#define COMPILER_VERSION "0.4.106"
|
||||
@@ -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:`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user