Skip to content

Commit

Permalink
Implement DIR_DELETEDIR
Browse files Browse the repository at this point in the history
  • Loading branch information
nickg committed Aug 2, 2023
1 parent 0db7f38 commit e1429ee
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 6 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Implemented the `'reflect` attribute and associated protected types
from VHDL-2019.
- Added support for VHDL-2019 sequential block statements.
- Implemented the VHDL-2019 directory I/O functions in `std.env`.

## Version 1.10.1 - 2023-07-28
- Fixed incorrect sensitivity list generation with concurrent statements
Expand Down
15 changes: 11 additions & 4 deletions lib/std.19/env-body.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -352,21 +352,28 @@ package body env is
procedure dir_deletedir (path : in string;
status : out dir_delete_status) is
begin
report "not implemented" severity failure;
dir_deletedir(path, false, status);
end procedure;

procedure dir_deletedir (path : in string;
recursive : in boolean;
status : out dir_delete_status) is
procedure impl (path : in string;
recursive : in boolean;
status : out dir_delete_status);
attribute foreign of impl : procedure is "_std_env_deletedir";
begin
report "not implemented" severity failure;
impl(path, recursive, status);
end procedure;

impure function dir_deletedir (path : in string;
recursive : in boolean := false)
return dir_delete_status is
return dir_delete_status
is
variable status : dir_delete_status;
begin
report "not implemented" severity failure;
dir_deletedir(path, recursive, status);
return status;
end function;

procedure dir_deletefile (path : in string;
Expand Down
78 changes: 77 additions & 1 deletion src/rt/stdenv.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ typedef enum {
FILE_DELETE_STATUS_ERROR = 3
} file_delete_status_t;

typedef enum {
DIR_DELETE_STATUS_OK = 0,
DIR_DELETE_STATUS_NO_DIRECTORY = 1,
DIR_DELETE_STATUS_NOT_EMPTY = 2,
DIR_DELETE_STATUS_ACCESS_DENIED = 3,
DIR_DELETE_STATUS_ERROR = 4
} dir_delete_status_t;

typedef struct {
ffi_uarray_t *name;
ffi_uarray_t *file_name;
Expand Down Expand Up @@ -146,11 +154,23 @@ static int8_t errno_to_file_delete_status(void)
switch (errno) {
case 0: return FILE_DELETE_STATUS_OK;
case ENOENT: return FILE_DELETE_STATUS_NO_FILE;
case EACCES: return DIR_CREATE_STATUS_ACCESS_DENIED;
case EACCES: return FILE_DELETE_STATUS_ACCESS_DENIED;
default: return FILE_DELETE_STATUS_ERROR;
}
}

static int8_t errno_to_dir_delete_status(void)
{
switch (errno) {
case 0: return DIR_DELETE_STATUS_OK;
case ENOENT:
case ENOTDIR: return DIR_DELETE_STATUS_NO_DIRECTORY;
case ENOTEMPTY: return DIR_DELETE_STATUS_NOT_EMPTY;
case EACCES: return DIR_DELETE_STATUS_ACCESS_DENIED;
default: return DIR_DELETE_STATUS_ERROR;
}
}

static const char *find_dir_separator(const char *str)
{
// Forward slash is a valid separator even on Windows
Expand Down Expand Up @@ -445,6 +465,62 @@ void _std_env_deletefile(const uint8_t *path_ptr, int64_t path_len,
*status = FILE_DELETE_STATUS_OK;
}

static int8_t delete_tree(const char *path)
{
DIR *d = opendir(path);
if (d == NULL)
return errno_to_dir_delete_status();

LOCAL_TEXT_BUF tb = tb_new();
int8_t status = DIR_DELETE_STATUS_OK;

struct dirent *e;
while (status == DIR_DELETE_STATUS_OK && (e = readdir(d))) {
if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
continue;

tb_rewind(tb);
tb_cat(tb, path);
tb_cat(tb, DIR_SEP);
tb_cat(tb, e->d_name);

#if defined __MINGW32__ || !defined DT_DIR
file_info_t info;
get_file_info(tb_get(tb), &info);

const bool is_dir = (info.type == FILE_DIR);
#else
const bool is_dir = (e->d_type == DT_DIR);
#endif

if (is_dir)
status = delete_tree(tb_get(tb));
else if (remove(tb_get(tb)) == -1)
status = errno_to_dir_delete_status();
}

closedir(d);

if (status == DIR_DELETE_STATUS_OK && rmdir(path) == -1)
return errno_to_dir_delete_status();

return status;
}

DLLEXPORT
void _std_env_deletedir(const uint8_t *path_ptr, int64_t path_len,
int8_t recursive, int8_t *status)
{
char *path LOCAL = to_cstring(path_ptr, path_len);

if (recursive)
*status = delete_tree(path);
else if (rmdir(path) == -1)
*status = errno_to_dir_delete_status();
else
*status = DIR_DELETE_STATUS_OK;
}

DLLEXPORT
void _std_env_dir_open(const uint8_t *path_ptr, int64_t path_len,
directory_t *dir, int8_t *status)
Expand Down
1 change: 1 addition & 0 deletions src/symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# Exported from src/rt/stdenv.c
_std_env_add_trec_real;
_std_env_createdir;
_std_env_deletedir;
_std_env_deletefile;
_std_env_diff_trec;
_std_env_dir_open;
Expand Down
17 changes: 17 additions & 0 deletions test/regress/stdenv6.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@ begin

assert dir_deletefile("tmp.txt") = STATUS_NO_FILE;

assert dir_createdir("testdir") = STATUS_OK;
assert dir_itemisdir("testdir");
assert dir_deletedir("testdir") = STATUS_OK;

assert dir_deletedir("nothere") = STATUS_NO_DIRECTORY;

assert dir_createdir("testdir") = STATUS_OK;
file_open(f, "testdir/tmp.txt", write_mode);
file_close(f);
assert dir_createdir("testdir/sub") = STATUS_OK;
file_open(f, "testdir/sub/sub.txt", write_mode);
file_close(f);
assert dir_deletedir("testdir") = STATUS_NOT_EMPTY;

assert dir_deletedir("testdir", recursive => true) = STATUS_OK;
assert not dir_itemexists("testdir");

wait;
end process;

Expand Down
2 changes: 1 addition & 1 deletion www/features.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ table below.
<td><a href="http://www.eda-twiki.org/cgi-bin/view.cgi/P1076/LCS2016_006e">
LCS2016-006c</td>
<td>Directory API</td>
<td class="feature-partial">master</td>
<td class="feature-done">master</td>
</tr>
<tr>
<td><a href="http://www.eda-twiki.org/cgi-bin/view.cgi/P1076/LCS2016_006e">
Expand Down

0 comments on commit e1429ee

Please sign in to comment.