From ea457d5de2771095f4fcf64419b13073d006c29e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 30 Jul 2023 22:34:55 +0100 Subject: [PATCH] Implement DIR_OPEN and DIR_CLOSE --- lib/std.19/env-body.vhd | 24 +++++++++----- lib/std.19/env.vhdl | 2 +- src/rt/stdenv.c | 71 ++++++++++++++++++++++++++++++++++++++++ src/symbols.txt | 1 + test/regress/stdenv6.vhd | 18 ++++++++++ 5 files changed, 107 insertions(+), 9 deletions(-) diff --git a/lib/std.19/env-body.vhd b/lib/std.19/env-body.vhd index ee5bcb4f..fb0f1a0a 100644 --- a/lib/std.19/env-body.vhd +++ b/lib/std.19/env-body.vhd @@ -132,11 +132,11 @@ package body env is return trec + (-delta); end function; - function "-" (delta : real; trec : time_record) return time_record is - begin - -- It's not really clear what this is for - report "not implemented" severity failure; - end function; + -- function "-" (delta : real; trec : time_record) return time_record is + -- begin + -- -- It's not really clear what this is for + -- report "not implemented" severity failure; + -- end function; function "-" (tr1, tr2 : time_record) return real is function impl (tr1, tr2 : in time_record) return real; @@ -251,19 +251,27 @@ package body env is procedure dir_open (dir : out directory; path : in string; status : out dir_open_status) is + procedure impl (path : in string; + dir : out directory; + status : out dir_open_status); + attribute foreign of impl : procedure is "_std_env_dir_open"; begin - report "not implemented" severity failure; + impl(path, dir, status); end procedure; impure function dir_open (dir : out directory; path : in string) return dir_open_status is + variable status : dir_open_status; begin - report "not implemented" severity failure; + dir_open(dir, path, status); + return status; end function; procedure dir_close (variable dir : inout directory) is begin - report "not implemented" severity failure; + -- No-op with garbage collection + dir.name := null; + dir.items := null; end procedure; impure function dir_itemexists (path : in string) return boolean is diff --git a/lib/std.19/env.vhdl b/lib/std.19/env.vhdl index 127ecdc1..bd7d22c0 100644 --- a/lib/std.19/env.vhdl +++ b/lib/std.19/env.vhdl @@ -98,7 +98,7 @@ package ENV is function "+"(TREC: TIME_RECORD; DELTA: REAL) return TIME_RECORD; function "+"(DELTA: REAL; TREC: TIME_RECORD) return TIME_RECORD; function "-"(TREC: TIME_RECORD; DELTA: REAL) return TIME_RECORD; - function "-"(DELTA: REAL; TREC: TIME_RECORD) return TIME_RECORD; + --function "-"(DELTA: REAL; TREC: TIME_RECORD) return TIME_RECORD; -- Time difference in seconds. TR1, TR2 must both be in local -- time, or both in UTC. diff --git a/src/rt/stdenv.c b/src/rt/stdenv.c index fe16bba9..510d9a58 100644 --- a/src/rt/stdenv.c +++ b/src/rt/stdenv.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,11 @@ typedef struct { int64_t dayofyear; } time_record_t; +typedef struct { + ffi_uarray_t *name; + ffi_uarray_t *items; +} directory_t; + typedef enum { DIR_OPEN_STATUS_OK = 0, DIR_OPEN_STATUS_NOT_FOUND = 1, @@ -439,6 +445,71 @@ void _std_env_deletefile(const uint8_t *path_ptr, int64_t path_len, *status = FILE_DELETE_STATUS_OK; } +DLLEXPORT +void _std_env_dir_open(const uint8_t *path_ptr, int64_t path_len, + directory_t *dir, int8_t *status) +{ + char *path LOCAL = to_cstring(path_ptr, path_len); + + DIR *d = opendir(path); + if (d == NULL) { + *status = errno_to_dir_open_status(); + return; + } + + char resolved[PATH_MAX]; + realpath(path, resolved); + + const size_t resolvedsz = strlen(resolved); + size_t memsz = sizeof(ffi_uarray_t)*2 + resolvedsz; + struct dirent *e; + int count = 0; + while ((e = readdir(d))) { + const size_t nchars = strlen(e->d_name); + memsz += sizeof(ffi_uarray_t) + ALIGN_UP(nchars, 8); + count++; + } + memsz += count * sizeof(ffi_uarray_t *); + + rewinddir(d); + + void *mem = jit_mspace_alloc(memsz), *next = mem; + dir->items = next; + dir->items->dims[0].left = 0; + dir->items->dims[0].length = count; + dir->items->ptr = dir->items + 1; + + next += sizeof(ffi_uarray_t) + count * sizeof(ffi_uarray_t *); + + for (int nth = 0; (e = readdir(d)); nth++) { + const size_t nchars = strlen(e->d_name); + + ffi_uarray_t *u = next; + u->ptr = u + 1; + u->dims[0].left = 1; + u->dims[0].length = nchars; + memcpy(u->ptr, e->d_name, nchars); + + *((ffi_uarray_t **)dir->items->ptr + nth) = u; + + next += sizeof(ffi_uarray_t) + ALIGN_UP(nchars, 8); + } + + closedir(d); + + dir->name = next; + dir->name->ptr = dir->name + 1; + dir->name->dims[0].left = 1; + dir->name->dims[0].length = resolvedsz; + + memcpy(dir->name->ptr, resolved, resolvedsz); + + next += sizeof(ffi_uarray_t) + resolvedsz; + assert(next == mem + memsz); + + *status = 0; +} + DLLEXPORT void _std_env_get_call_path(ffi_uarray_t **ptr) { diff --git a/src/symbols.txt b/src/symbols.txt index 3d2c0df7..74025a34 100644 --- a/src/symbols.txt +++ b/src/symbols.txt @@ -15,6 +15,7 @@ _std_env_createdir; _std_env_deletefile; _std_env_diff_trec; + _std_env_dir_open; _std_env_epoch; _std_env_epoch_trec; _std_env_file_line; diff --git a/test/regress/stdenv6.vhd b/test/regress/stdenv6.vhd index 5d3df779..5cf573e5 100644 --- a/test/regress/stdenv6.vhd +++ b/test/regress/stdenv6.vhd @@ -10,12 +10,30 @@ begin p1: process is file f : text; variable status : file_delete_status; + variable dir : directory; + variable found : boolean; begin file_open(f, "tmp.txt", write_mode); file_close(f); assert dir_itemexists("tmp.txt"); + assert dir_open(dir, ".") = STATUS_OK; + + for i in dir.items'range loop + report dir.items(i).all; + if dir.items(i).all = "tmp.txt" then + assert not found; + found := true; + end if; + end loop; + + assert found report "missing tmp.txt"; + + report dir.name.all; + + dir_close(dir); + dir_deletefile("tmp.txt", status); assert status = STATUS_OK; -- 2.39.2