From 16671fa8682aaeb6e23147b8039b0e4b1bde20a4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 11 Mar 2023 22:25:50 +0000 Subject: [PATCH] Implement FILE_MODE and FILE_STATE --- src/common.c | 3 ++- src/common.h | 1 + src/parse.c | 17 +++++++++++++ src/rt/fileio.c | 54 +++++++++++++++++++++++++++++++++++++++++ src/symbols.txt | 2 ++ test/regress/file12.vhd | 6 +++++ 6 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/common.c b/src/common.c index 14ea8a88..8f48a930 100644 --- a/src/common.c +++ b/src/common.c @@ -1173,7 +1173,7 @@ static tree_t cached_std(tree_t hint) type_t std_type(tree_t std, std_type_t which) { - static type_t cache[STD_FILE_ORIGIN_KIND + 1] = {}; + static type_t cache[STD_FILE_OPEN_STATE + 1] = {}; assert(which < ARRAY_LEN(cache)); if (cache[which] == NULL) { @@ -1192,6 +1192,7 @@ type_t std_type(tree_t std, std_type_t which) "BIT_VECTOR", "SEVERITY_LEVEL", "FILE_ORIGIN_KIND", + "FILE_OPEN_STATE", }; tree_t d = search_decls(cached_std(std), ident_new(names[which]), 0); diff --git a/src/common.h b/src/common.h index 72329b5d..560a2cf7 100644 --- a/src/common.h +++ b/src/common.h @@ -147,6 +147,7 @@ typedef enum { STD_BIT_VECTOR, STD_SEVERITY_LEVEL, STD_FILE_ORIGIN_KIND, + STD_FILE_OPEN_STATE, } std_type_t; type_t std_type(tree_t std, std_type_t which); diff --git a/src/parse.c b/src/parse.c index d4e4acc6..a1915c0b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1234,8 +1234,11 @@ static void declare_predefined_ops(tree_t container, type_t t) ident_t seek_i = ident_new("FILE_SEEK"); ident_t begin_i = ident_new("FILE_ORIGIN_BEGIN"); ident_t truncate_i = ident_new("FILE_TRUNCATE"); + ident_t state_i = ident_new("FILE_STATE"); + ident_t mode_i = ident_new("FILE_MODE"); type_t origin_kind = std_type(NULL, STD_FILE_ORIGIN_KIND); + type_t open_state = std_type(NULL, STD_FILE_OPEN_STATE); tree_t origin_begin = search_decls(std, begin_i, 0); assert(origin_begin != NULL); @@ -1277,6 +1280,20 @@ static void declare_predefined_ops(tree_t container, type_t t) make_ref(origin_begin)); insert_name(nametab, truncate, truncate_i); tree_add_decl(container, truncate); + + tree_t state = builtin_fn(state_i, open_state, S_FOREIGN, + "F", t, NULL); + tree_set_ident2(state, ident_new("__nvc_file_state")); + tree_set_class(tree_port(state, 0), C_FILE); + insert_name(nametab, state, state_i); + tree_add_decl(container, state); + + tree_t mode = builtin_fn(mode_i, open_kind, S_FOREIGN, + "F", t, NULL); + tree_set_ident2(mode, ident_new("__nvc_file_mode")); + tree_set_class(tree_port(mode, 0), C_FILE); + insert_name(nametab, mode, mode_i); + tree_add_decl(container, mode); } type_t of = type_file(t); diff --git a/src/rt/fileio.c b/src/rt/fileio.c index 0715487b..20ebe57d 100644 --- a/src/rt/fileio.c +++ b/src/rt/fileio.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef __MINGW32__ #include @@ -50,6 +51,18 @@ typedef enum { FILE_ORIGIN_END } file_origin_kind_t; +typedef enum { + STATE_OPEN, + STATE_CLOSED +} file_open_state_t; + +typedef enum { + READ_MODE, + WRITE_MODE, + APPEND_MODE, + READ_WRITE_MODE +} file_open_kind_t; + DLLEXPORT void __nvc_flush(FILE **fp) { @@ -141,6 +154,47 @@ void __nvc_truncate(FILE **fp, int32_t size, int8_t origin) jit_msg(NULL, DIAG_FATAL, "FILE_TRUNCATE failed: %s", strerror(errno)); } +DLLEXPORT +int8_t __nvc_file_state(FILE **fp) +{ + return *fp == NULL ? STATE_CLOSED : STATE_OPEN; +} + +DLLEXPORT +int8_t __nvc_file_mode(FILE **fp) +{ + if (*fp == NULL) + jit_msg(NULL, DIAG_FATAL, "FILE_MODE called on closed file"); + +#ifdef __MINGW32__ + fflush(*fp); + + HANDLE handle = (HANDLE)_get_osfhandle(_fileno(*fp)); + const bool can_read = ReadFile(handle, NULL, 0, NULL, NULL); + const bool can_write = WriteFile(handle, NULL, 0, NULL, NULL); + + if (can_read && can_write) + return READ_WRITE_MODE; + else if (can_read) + return READ_MODE; + else if (can_write) + return WRITE_MODE; +#else + const int mode = fcntl(fileno(*fp), F_GETFL); + if (mode < 0) + jit_msg(NULL, DIAG_FATAL, "FILE_MODE failed: %s", strerror(errno)); + + switch (mode & O_ACCMODE) { + case O_RDONLY: return READ_MODE; + case O_WRONLY: return (mode & O_APPEND) ? APPEND_MODE : WRITE_MODE; + case O_RDWR: return READ_WRITE_MODE; + } +#endif + + jit_msg(NULL, DIAG_WARN, "cannot determine file mode"); + return READ_MODE; +} + void _file_io_init(void) { // Dummy function to force linking diff --git a/src/symbols.txt b/src/symbols.txt index 1a35c370..1c792bd0 100644 --- a/src/symbols.txt +++ b/src/symbols.txt @@ -34,6 +34,8 @@ _nvc_ieee_warnings; # Exported from src/rt/fileio.c + __nvc_file_mode; + __nvc_file_state; __nvc_flush; __nvc_open3; __nvc_rewind; diff --git a/test/regress/file12.vhd b/test/regress/file12.vhd index a71c3301..310e36d1 100644 --- a/test/regress/file12.vhd +++ b/test/regress/file12.vhd @@ -10,11 +10,14 @@ begin variable c : character; begin file_open(f, "test.txt", WRITE_MODE); + assert file_mode(f) = WRITE_MODE; write(f, 'x'); write(f, 'y'); write(f, 'z'); file_close(f); + assert file_state(f) = STATE_CLOSED; + assert file_open(f, "test.txt", READ_WRITE_MODE) = OPEN_OK; read(f, c); assert c = 'x'; @@ -51,6 +54,9 @@ begin assert c = '1'; assert endfile(f); + assert file_state(f) = STATE_OPEN; + assert file_mode(f) = READ_WRITE_MODE; + wait; end process; -- 2.39.2