diff --git a/meson.build b/meson.build index d5d3fd5e..0ea9fd5b 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('cthulhu', 'c', - license : 'LGPLv3', - version : '0.2.8', + license : 'LGPL-3.0-only AND GPL-3.0-only', + version : '0.2.9', license_files : 'LICENSE', meson_version : '>=1.3.0', default_options : [ @@ -93,35 +93,6 @@ if unit_tests.enabled() and is_release and cc.get_id() == 'gcc' warning('enabling unit tests in release mode with gcc will result in degraded performance') endif -version = meson.project_version() -host = host_machine.system() -parts = version.split('.') - -source_dir = meson.project_source_root() / 'src' -data_dir = meson.project_source_root() / 'data' - -config_cdata = configuration_data() - -config_cdata.set('CTU_MAJOR', parts[0].to_int()) -config_cdata.set('CTU_MINOR', parts[1].to_int()) -config_cdata.set('CTU_PATCH', parts[2].to_int()) - -config_cdata.set10('CTU_DEBUG', is_debug) -config_cdata.set10('CTU_PARANOID', opt_paranoid.allowed()) -config_cdata.set10('CTU_BUILD_SHARED', default_library == 'shared') - -# we use `__attribute__((const|pure))` heavily, but during unit tests we -# violate function preconditions to test assertions. -# msvc and clang dont mind, but gcc does. so we disable the attributes for gcc -config_cdata.set10('CTU_DISABLE_FN_PURITY', unit_tests.allowed() and cc.get_id() == 'gcc') - -# gcc warns about __PRETY_FUNCTION__ not being ISO C when warning_leve=3 -# which is weird seeing as we specify gnu11, maybe its a gcc bug? -config_cdata.set10('CTU_HAS_PRETTY_FUNCTION', warning_level < 3) - -config_cdata.set10('CTU_TRACE_MEMORY', trace_memory.allowed()) -config_cdata.set10('CTU_STB_SPRINTF', opt_stb_sprintf.allowed()) - # args for all code all_args = cc.get_supported_arguments( # we use flexible array members @@ -218,6 +189,7 @@ add_project_arguments(all_args, language : [ 'c' ]) lexargs = [] parseargs = [] +host = host_machine.system() # setup required flex/bison args if host == 'windows' lexargs += [ '--wincompat' ] @@ -270,6 +242,9 @@ endif doxygen = find_program('doxygen', required : get_option('doxygen')) if doxygen.found() + source_dir = meson.project_source_root() / 'src' + data_dir = meson.project_source_root() / 'data' + doxy_sources = [ source_dir / 'common', source_dir / 'cthulhu', diff --git a/src/common/core/data/module_api.h.in b/src/common/core/data/module_api.h.in index a6972cd9..399b68bb 100644 --- a/src/common/core/data/module_api.h.in +++ b/src/common/core/data/module_api.h.in @@ -4,7 +4,7 @@ #include "core/compiler.h" // IWYU pragma: export -#if CTU_BUILD_SHARED +#if CT_BUILD_SHARED # if CT_@MOD@_BUILD # define CT_@MOD@_API CT_EXPORT # else diff --git a/src/common/core/include/core/macros.h b/src/common/core/include/core/macros.h index 6636866c..c6a8a6eb 100644 --- a/src/common/core/include/core/macros.h +++ b/src/common/core/include/core/macros.h @@ -48,6 +48,8 @@ #define CT_INNER_STR(x) #x #define CT_STR(x) CT_INNER_STR(x) +#define CT_VERSION CT_STR(CTU_MAJOR) "." CT_STR(CTU_MINOR) "." CT_STR(CTU_PATCH) + /// @defgroup ansi_colour ANSI Colour macros /// @brief ANSI escape string colour macros /// @ingroup core diff --git a/src/common/core/include/ctu_config.h b/src/common/core/include/ctu_config.h new file mode 100644 index 00000000..ecd331b6 --- /dev/null +++ b/src/common/core/include/ctu_config.h @@ -0,0 +1,9 @@ +#pragma once + +#define CT_BUILDTYPE_SHARED 1 +#define CT_BUILDTYPE_STATIC 2 + +#include + +#define CT_BUILD_SHARED (CTU_BUILDTYPE == CT_BUILDTYPE_SHARED) +#define CT_BUILD_STATIC (CTU_BUILDTYPE == CT_BUILDTYPE_STATIC) diff --git a/src/common/core/meson.build b/src/common/core/meson.build index ed82ede8..af85fe7c 100644 --- a/src/common/core/meson.build +++ b/src/common/core/meson.build @@ -1,5 +1,31 @@ +version = meson.project_version() +parts = version.split('.') + +config_cdata = configuration_data() + +config_cdata.set('CTU_MAJOR', parts[0].to_int()) +config_cdata.set('CTU_MINOR', parts[1].to_int()) +config_cdata.set('CTU_PATCH', parts[2].to_int()) + +config_cdata.set10('CTU_DEBUG', is_debug) +config_cdata.set10('CTU_PARANOID', opt_paranoid.allowed()) + +if default_library == 'shared' + config_cdata.set('CTU_BUILDTYPE', 'CT_BUILDTYPE_SHARED') +else + config_cdata.set('CTU_BUILDTYPE', 'CT_BUILDTYPE_STATIC') +endif + +# we use `__attribute__((const|pure))` heavily, but during unit tests we +# violate function preconditions to test assertions. +# msvc and clang dont mind, but gcc does. so we disable the attributes for gcc +config_cdata.set10('CTU_DISABLE_FN_PURITY', unit_tests.allowed() and cc.get_id() == 'gcc') + +config_cdata.set10('CTU_TRACE_MEMORY', trace_memory.allowed()) +config_cdata.set10('CTU_STB_SPRINTF', opt_stb_sprintf.allowed()) + ctu_config_header = configure_file( - output : 'ctu_config.h', + output : 'ctu_core_config.h', configuration : config_cdata ) diff --git a/src/common/fs/include/fs/fs.h b/src/common/fs/include/fs/fs.h index a26ef37f..0e736dc0 100644 --- a/src/common/fs/include/fs/fs.h +++ b/src/common/fs/include/fs/fs.h @@ -6,8 +6,6 @@ #include "os/core.h" -#include "fs/impl.h" - #include CT_BEGIN_API @@ -21,6 +19,10 @@ typedef struct vector_t vector_t; /// @ingroup common /// @{ +typedef struct fs_t fs_t; +typedef struct fs_inode_t fs_inode_t; +typedef struct fs_iter_t fs_iter_t; + /// @brief delete a filesystem handle /// /// @param fs the filesystem to delete @@ -128,6 +130,8 @@ typedef void (*fs_dirent_callback_t)(const char *path, const char *name, os_dire CT_FS_API void fs_iter_dirents(fs_t *fs, const char *path, void *data, fs_dirent_callback_t callback); +CT_FS_API bool fs_inode_is(IN_NOTNULL const fs_inode_t *inode, os_dirent_t type); + CT_FS_API os_error_t fs_iter_begin( IN_NOTNULL fs_t *fs, IN_STRING const char *path, diff --git a/src/common/fs/include/fs/impl.h b/src/common/fs/include/fs/impl.h deleted file mode 100644 index 16171800..00000000 --- a/src/common/fs/include/fs/impl.h +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only - -#pragma once - -#include - -#include "os/core.h" - -CT_BEGIN_API - -/// @ingroup fs -/// @{ - -/// @brief a filesystem interface -typedef struct fs_t fs_t; - -/// @brief a filesystem inode -typedef struct fs_inode_t -{ - /// @brief the type of the inode - os_dirent_t type; - - /// @brief internal data - char data[]; -} fs_inode_t; - -/// @brief a filesystem iterator -typedef struct fs_iter_t -{ - /// @brief the parent filesystem - fs_t *fs; - - /// @brief internal data - char data[]; -} fs_iter_t; - -/// @} - -CT_END_API diff --git a/src/common/fs/src/common.c b/src/common/fs/src/common.c index d429bfec..3edfab0b 100644 --- a/src/common/fs/src/common.c +++ b/src/common/fs/src/common.c @@ -16,9 +16,9 @@ fs_inode_t gInvalidFileNode = { .type = eOsNodeNone }; -static fs_inode_t *inode_new(os_dirent_t type, const void *data, size_t size, arena_t *arena) +fs_inode_t *inode_new(os_dirent_t type, const void *data, size_t size, arena_t *arena) { - CTASSERT(type < eOsNodeCount); + CT_ASSERT_RANGE(type, 0, eOsNodeCount - 1); fs_inode_t *inode = ARENA_MALLOC(sizeof(fs_inode_t) + size, "inode", NULL, arena); inode->type = type; @@ -43,6 +43,13 @@ void *inode_data(fs_inode_t *inode) return inode->data; } +void *iter_data(fs_iter_t *iter) +{ + CTASSERT(iter != NULL); + + return iter->data; +} + bool inode_is(fs_inode_t *inode, os_dirent_t type) { CTASSERT(inode != NULL); diff --git a/src/common/fs/src/common.h b/src/common/fs/src/common.h index bd217ded..1742a703 100644 --- a/src/common/fs/src/common.h +++ b/src/common/fs/src/common.h @@ -9,6 +9,19 @@ typedef struct map_t map_t; typedef struct arena_t arena_t; +typedef struct fs_inode_t +{ + os_dirent_t type; + char data[]; +} fs_inode_t; + +typedef struct fs_iter_t +{ + fs_t *fs; + fs_inode_t *current; + char data[]; +} fs_iter_t; + typedef struct inode_result_t { fs_inode_t *node; @@ -25,6 +38,10 @@ typedef os_error_t (*fs_file_delete_t)(fs_t *fs, fs_inode_t *node, const char *n typedef inode_result_t (*fs_dir_create_t)(fs_t *fs, fs_inode_t *node, const char *name); typedef os_error_t (*fs_dir_delete_t)(fs_t *fs, fs_inode_t *node, const char *name); +typedef os_error_t (*fs_iter_begin_t)(fs_t *fs, fs_inode_t *dir, fs_iter_t *iter); +typedef os_error_t (*fs_iter_next_t)(fs_iter_t *iter); +typedef os_error_t (*fs_iter_end_t)(fs_iter_t *iter); + /// @brief fs callback to delete the fs /// /// @param fs the fs to delete @@ -43,6 +60,12 @@ typedef struct fs_callbacks_t fs_file_create_t pfn_create_file; fs_file_delete_t pfn_delete_file; + + fs_iter_begin_t pfn_iter_begin; + fs_iter_next_t pfn_iter_next; + fs_iter_end_t pfn_iter_end; + + size_t iter_size; } fs_callbacks_t; typedef struct fs_t @@ -60,10 +83,13 @@ CT_LOCAL extern fs_inode_t gInvalidFileNode; CT_LOCAL fs_inode_t *inode_file(const void *data, size_t size, arena_t *arena); CT_LOCAL fs_inode_t *inode_dir(const void *data, size_t size, arena_t *arena); +CT_LOCAL fs_inode_t *inode_new(os_dirent_t type, const void *data, size_t size, arena_t *arena); CT_LOCAL void *inode_data(fs_inode_t *inode); CT_LOCAL bool inode_is(fs_inode_t *inode, os_dirent_t type); +CT_LOCAL void *iter_data(fs_iter_t *iter); + // helpers CT_LOCAL os_error_t mkdir_recursive(const char *path, arena_t *arena); diff --git a/src/common/fs/src/fs.c b/src/common/fs/src/fs.c index c76fe5b1..7d54b761 100644 --- a/src/common/fs/src/fs.c +++ b/src/common/fs/src/fs.c @@ -23,7 +23,7 @@ static vector_t *path_split(const char *path, arena_t *arena) // fs interface api -static fs_inode_t *query_inode(fs_t *fs, fs_inode_t *node, const char *name) +static fs_inode_t *impl_query_inode(fs_t *fs, fs_inode_t *node, const char *name) { CTASSERT(fs != NULL); CTASSERT(node != NULL); @@ -35,7 +35,7 @@ static fs_inode_t *query_inode(fs_t *fs, fs_inode_t *node, const char *name) return fs->cb->pfn_query_node(fs, node, name); } -static map_t *query_dirents(fs_t *fs, fs_inode_t *node) +static map_t *impl_query_dirents(fs_t *fs, fs_inode_t *node) { CTASSERT(fs != NULL); CTASSERT(node != NULL); @@ -46,7 +46,7 @@ static map_t *query_dirents(fs_t *fs, fs_inode_t *node) return fs->cb->pfn_query_dirents(fs, node); } -static io_t *query_file(fs_t *fs, fs_inode_t *node, os_access_t flags) +static io_t *impl_query_file(fs_t *fs, fs_inode_t *node, os_access_t flags) { CTASSERT(fs != NULL); CTASSERT(node != NULL); @@ -57,7 +57,7 @@ static io_t *query_file(fs_t *fs, fs_inode_t *node, os_access_t flags) return fs->cb->pfn_query_file(fs, node, flags); } -static fs_inode_t *create_file(fs_t *fs, fs_inode_t *node, const char *name) +static fs_inode_t *impl_create_file(fs_t *fs, fs_inode_t *node, const char *name) { CTASSERT(fs != NULL); CTASSERT(node != NULL); @@ -71,7 +71,7 @@ static fs_inode_t *create_file(fs_t *fs, fs_inode_t *node, const char *name) return result.node; } -static os_error_t delete_file(fs_t *fs, fs_inode_t *node, const char *name) +static os_error_t impl_delete_file(fs_t *fs, fs_inode_t *node, const char *name) { CTASSERT(fs != NULL); CTASSERT(node != NULL); @@ -83,7 +83,7 @@ static os_error_t delete_file(fs_t *fs, fs_inode_t *node, const char *name) return fs->cb->pfn_delete_file(fs, node, name); } -static fs_inode_t *create_dir(fs_t *fs, fs_inode_t *node, const char *name) +static fs_inode_t *impl_create_dir(fs_t *fs, fs_inode_t *node, const char *name) { CTASSERT(fs != NULL); CTASSERT(node != NULL); @@ -97,7 +97,7 @@ static fs_inode_t *create_dir(fs_t *fs, fs_inode_t *node, const char *name) return result.node; } -static os_error_t delete_dir(fs_t *fs, fs_inode_t *node, const char *name) +static os_error_t impl_delete_dir(fs_t *fs, fs_inode_t *node, const char *name) { CTASSERT(fs != NULL); CTASSERT(node != NULL); @@ -109,6 +109,80 @@ static os_error_t delete_dir(fs_t *fs, fs_inode_t *node, const char *name) return fs->cb->pfn_delete_dir(fs, node, name); } +// static os_error_t impl_delete_inode(fs_t *fs, fs_inode_t *node) +// { +// CTASSERT(fs != NULL); +// CTASSERT(node != NULL); + +// CTASSERT(fs->cb->pfn_delete_inode != NULL); + +// return fs->cb->pfn_delete_inode(fs, node); +// } + +static os_error_t impl_iter_begin(fs_t *fs, fs_inode_t *dir, fs_iter_t *iter) +{ + CTASSERT(fs != NULL); + CTASSERT(dir != NULL); + CTASSERT(iter != NULL); + + CTASSERT(inode_is(dir, eOsNodeDir)); + CTASSERT(fs->cb->pfn_iter_begin != NULL); + + return fs->cb->pfn_iter_begin(fs, dir, iter); +} + +static os_error_t impl_iter_next(fs_iter_t *iter) +{ + CTASSERT(iter != NULL); + CTASSERT(iter->fs != NULL); + + CTASSERT(iter->fs->cb->pfn_iter_next != NULL); + + return iter->fs->cb->pfn_iter_next(iter); +} + +static os_error_t impl_iter_end(fs_iter_t *iter) +{ + CTASSERT(iter != NULL); + CTASSERT(iter->fs != NULL); + + CTASSERT(iter->fs->cb->pfn_iter_end != NULL); + + return iter->fs->cb->pfn_iter_end(iter); +} + +// private impl + +static fs_inode_t *fsi_find_node(fs_t *fs, fs_inode_t *start, const char *path) +{ + vector_t *parts = path_split(path, fs->arena); + size_t len = vector_len(parts); + fs_inode_t *current = start; + + CTASSERT(len > 0); + + for (size_t i = 0; i < len - 1; i++) + { + const char *part = vector_get(parts, i); + fs_inode_t *node = impl_query_inode(fs, current, part); + switch (node->type) + { + case eOsNodeDir: + current = node; + break; + + case eOsNodeNone: + case eOsNodeFile: + return NULL; + + default: + CT_NEVER("invalid inode type (%s)", os_dirent_string(node->type)); + } + } + + return impl_query_inode(fs, current, vector_tail(parts)); +} + // fs delete USE_DECL @@ -131,7 +205,7 @@ void fs_file_create(fs_t *fs, const char *path) for (size_t i = 0; i < len - 1; i++) { const char *part = vector_get(parts, i); - fs_inode_t *node = query_inode(fs, current, part); + fs_inode_t *node = impl_query_inode(fs, current, part); switch (node->type) { case eOsNodeDir: current = node; break; @@ -139,7 +213,7 @@ void fs_file_create(fs_t *fs, const char *path) } } - create_file(fs, current, vector_tail(parts)); + impl_create_file(fs, current, vector_tail(parts)); } USE_DECL @@ -152,7 +226,7 @@ bool fs_file_exists(fs_t *fs, const char *path) for (size_t i = 0; i < len - 1; i++) { const char *part = vector_get(parts, i); - fs_inode_t *node = query_inode(fs, current, part); + fs_inode_t *node = impl_query_inode(fs, current, part); switch (node->type) { case eOsNodeDir: current = node; break; @@ -160,7 +234,7 @@ bool fs_file_exists(fs_t *fs, const char *path) } } - fs_inode_t *file = query_inode(fs, current, vector_tail(parts)); + fs_inode_t *file = impl_query_inode(fs, current, vector_tail(parts)); return inode_is(file, eOsNodeFile); } @@ -174,7 +248,7 @@ os_error_t fs_file_delete(fs_t *fs, const char *path) for (size_t i = 0; i < len - 1; i++) { const char *part = vector_get(parts, i); - fs_inode_t *node = query_inode(fs, current, part); + fs_inode_t *node = impl_query_inode(fs, current, part); switch (node->type) { case eOsNodeDir: current = node; break; @@ -182,14 +256,14 @@ os_error_t fs_file_delete(fs_t *fs, const char *path) } } - return delete_file(fs, current, vector_tail(parts)); + return impl_delete_file(fs, current, vector_tail(parts)); } static const io_callbacks_t kInvalidIo = { 0 }; static io_t *make_invalid_file(const char *name, os_access_t flags, arena_t *arena) { - io_t *io = io_new(&kInvalidIo, flags, name, NULL, 0, arena); + io_t *io = io_new(&kInvalidIo, flags, name, NULL, arena); io->error = eOsNotFound; return io; } @@ -206,27 +280,27 @@ io_t *fs_open(fs_t *fs, const char *path, os_access_t flags) for (size_t i = 0; i < len - 1; i++) { const char *part = vector_get(parts, i); - fs_inode_t *node = query_inode(fs, current, part); + fs_inode_t *node = impl_query_inode(fs, current, part); switch (node->type) { case eOsNodeDir: current = node; break; - case eOsNodeNone: current = create_dir(fs, current, part); break; + case eOsNodeNone: current = impl_create_dir(fs, current, part); break; default: return make_invalid_file(path, flags, fs->arena); } } - fs_inode_t *file = query_inode(fs, current, vector_tail(parts)); + fs_inode_t *file = impl_query_inode(fs, current, vector_tail(parts)); switch (file->type) { case eOsNodeFile: - return query_file(fs, file, flags); + return impl_query_file(fs, file, flags); break; case eOsNodeNone: if (flags == eOsAccessRead) return make_invalid_file(path, flags, fs->arena); - file = create_file(fs, current, vector_tail(parts)); - return query_file(fs, file, flags); + file = impl_create_file(fs, current, vector_tail(parts)); + return impl_query_file(fs, file, flags); break; default: return make_invalid_file(path, flags, fs->arena); @@ -237,11 +311,11 @@ io_t *fs_open(fs_t *fs, const char *path, os_access_t flags) static fs_inode_t *get_dir_or_create(fs_t *fs, fs_inode_t *node, const char *name) { - fs_inode_t *dir = query_inode(fs, node, name); + fs_inode_t *dir = impl_query_inode(fs, node, name); switch (dir->type) { case eOsNodeDir: return dir; - case eOsNodeNone: return create_dir(fs, node, name); + case eOsNodeNone: return impl_create_dir(fs, node, name); default: return NULL; } @@ -249,11 +323,11 @@ static fs_inode_t *get_dir_or_create(fs_t *fs, fs_inode_t *node, const char *nam static fs_inode_t *get_file_or_create(fs_t *fs, fs_inode_t *node, const char *name) { - fs_inode_t *file = query_inode(fs, node, name); + fs_inode_t *file = impl_query_inode(fs, node, name); switch (file->type) { case eOsNodeFile: return file; - case eOsNodeNone: return create_file(fs, node, name); + case eOsNodeNone: return impl_create_file(fs, node, name); default: return NULL; } @@ -283,14 +357,14 @@ os_error_t fs_dir_create(fs_t *fs, const char *path) for (size_t i = 0; i < len; i++) { const char *part = vector_get(parts, i); - fs_inode_t *node = query_inode(fs, current, part); + fs_inode_t *node = impl_query_inode(fs, current, part); switch (node->type) { case eOsNodeDir: current = node; break; case eOsNodeNone: - current = create_dir(fs, current, part); + current = impl_create_dir(fs, current, part); break; case eOsNodeFile: @@ -314,7 +388,7 @@ bool fs_dir_exists(fs_t *fs, const char *path) for (size_t i = 0; i < len; i++) { const char *part = vector_get(parts, i); - fs_inode_t *node = query_inode(fs, current, part); + fs_inode_t *node = impl_query_inode(fs, current, part); switch (node->type) { case eOsNodeDir: @@ -345,7 +419,7 @@ os_error_t fs_dir_delete(fs_t *fs, const char *path) for (size_t i = 0; i < len - 1; i++) { const char *part = vector_get(parts, i); - fs_inode_t *node = query_inode(fs, current, part); + fs_inode_t *node = impl_query_inode(fs, current, part); switch (node->type) { case eOsNodeDir: @@ -362,18 +436,29 @@ os_error_t fs_dir_delete(fs_t *fs, const char *path) } // TODO: recursively delete all files and directories inside the directory - return delete_dir(fs, current, vector_tail(parts)); + return impl_delete_dir(fs, current, vector_tail(parts)); } // fs sync -static void sync_file(fs_t *dst_fs, fs_t *src_fs, fs_inode_t *dst_node, fs_inode_t *src_node) +static os_error_t sync_file(fs_t *dst_fs, fs_t *src_fs, fs_inode_t *dst_node, fs_inode_t *src_node) { CTASSERT(inode_is(dst_node, eOsNodeFile)); CTASSERT(inode_is(src_node, eOsNodeFile)); - io_t *src_io = query_file(src_fs, src_node, eOsAccessRead); - io_t *dst_io = query_file(dst_fs, dst_node, eOsAccessWrite); + os_error_t err = eOsSuccess; + io_t *src_io = impl_query_file(src_fs, src_node, eOsAccessRead); + io_t *dst_io = impl_query_file(dst_fs, dst_node, eOsAccessWrite | eOsAccessTruncate); + + if ((err = io_error(src_io)) != eOsSuccess) + { + goto cleanup; + } + + if ((err = io_error(dst_io)) != eOsSuccess) + { + goto cleanup; + } size_t size = io_size(src_io); if (size > 0) @@ -383,14 +468,18 @@ static void sync_file(fs_t *dst_fs, fs_t *src_fs, fs_inode_t *dst_node, fs_inode io_write(dst_io, data, size); } +cleanup: + // TODO: do we care about the error from closing the io? io_close(dst_io); io_close(src_io); + return err; } static sync_result_t sync_dir(fs_t *dst, fs_t *src, fs_inode_t *dst_node, fs_inode_t *src_node) { - map_t *dirents = query_dirents(src, src_node); + map_t *dirents = impl_query_dirents(src, src_node); map_iter_t iter = map_iter(dirents); + os_error_t err = eOsSuccess; const char *name = NULL; fs_inode_t *child = NULL; while (CTU_MAP_NEXT(&iter, &name, &child)) @@ -408,7 +497,11 @@ static sync_result_t sync_dir(fs_t *dst, fs_t *src, fs_inode_t *dst_node, fs_ino sync_dir(dst, src, other, child); break; case eOsNodeFile: - sync_file(dst, src, other, child); + if ((err = sync_file(dst, src, other, child)) != eOsSuccess) + { + sync_result_t result = { .path = name }; + return result; + } break; default: @@ -443,7 +536,7 @@ static void iter_dirents(fs_t *fs, fs_inode_t *node, const char *path, const cha const char *dir = str_format(fs->arena, "%s/%s", path, name); - map_t *dirents = query_dirents(fs, node); + map_t *dirents = impl_query_dirents(fs, node); map_iter_t iter = map_iter(dirents); const char *id = NULL; fs_inode_t *child = NULL; @@ -459,7 +552,16 @@ void fs_iter_dirents(fs_t *fs, const char *path, void *data, fs_dirent_callback_ CTASSERT(path != NULL); CTASSERT(callback != NULL); - iter_dirents(fs, query_inode(fs, fs->root, path), ".", path, data, callback); + iter_dirents(fs, impl_query_inode(fs, fs->root, path), ".", path, data, callback); +} + +USE_DECL +bool fs_inode_is(const fs_inode_t *inode, os_dirent_t type) +{ + CTASSERT(inode != NULL); + CT_ASSERT_RANGE(type, 0, eOsNodeCount - 1); + + return inode->type == type; } USE_DECL @@ -469,6 +571,31 @@ os_error_t fs_iter_begin(fs_t *fs, const char *path, fs_iter_t **iter) CTASSERT(path != NULL); CTASSERT(iter != NULL); + fs_inode_t *node = fsi_find_node(fs, fs->root, path); + if (node == NULL) + { + return eOsNotFound; + } + + if (!inode_is(node, eOsNodeDir)) + { + return eOsExists; + } + + const size_t sz = sizeof(fs_iter_t) + fs->cb->iter_size; + + fs_iter_t *data = ARENA_MALLOC(sz, "fs_iter", node, fs->arena); + data->fs = fs; + data->current = NULL; + + os_error_t err = impl_iter_begin(fs, node, data); + if (err != eOsSuccess) + { + arena_free(data, sz, fs->arena); + return err; + } + + *iter = data; return eOsSuccess; } @@ -476,8 +603,12 @@ USE_DECL os_error_t fs_iter_end(fs_iter_t *iter) { CTASSERT(iter != NULL); + const size_t sz = sizeof(fs_iter_t) + iter->fs->cb->iter_size; - return eOsSuccess; + os_error_t err = impl_iter_end(iter); + arena_free(iter, sz, iter->fs->arena); + + return err; } USE_DECL @@ -486,5 +617,11 @@ os_error_t fs_iter_next(fs_iter_t *iter, fs_inode_t **inode) CTASSERT(iter != NULL); CTASSERT(inode != NULL); - return eOsSuccess; + os_error_t err = impl_iter_next(iter); + if (err == eOsSuccess) + { + *inode = iter->current; + } + + return err; } diff --git a/src/common/fs/src/physical.c b/src/common/fs/src/physical.c index b36a250e..48f332e8 100644 --- a/src/common/fs/src/physical.c +++ b/src/common/fs/src/physical.c @@ -182,6 +182,28 @@ static os_error_t pfs_file_delete(fs_t *fs, fs_inode_t *self, const char *name) return os_file_delete(absolute); } +static os_error_t pfs_iter_begin(fs_t *fs, fs_inode_t *dir, fs_iter_t *iter) +{ + const char *absolute = get_absolute(fs, dir, NULL); + return os_iter_begin(absolute, iter_data(iter)); +} + +static os_error_t pfs_iter_next(fs_iter_t *iter) +{ + os_inode_t cur = { 0 }; + if (os_iter_next(iter_data(iter), &cur)) + { + + } + + return eOsSuccess; +} + +static os_error_t pfs_iter_end(fs_iter_t *iter) +{ + return os_iter_end(iter_data(iter)); +} + static const fs_callbacks_t kPhysicalInterface = { .pfn_query_node = pfs_query_node, .pfn_query_dirents = pfs_query_dirents, @@ -192,6 +214,12 @@ static const fs_callbacks_t kPhysicalInterface = { .pfn_create_file = pfs_file_create, .pfn_delete_file = pfs_file_delete, + + .pfn_iter_begin = pfs_iter_begin, + .pfn_iter_next = pfs_iter_next, + .pfn_iter_end = pfs_iter_end, + + .iter_size = sizeof(os_iter_t) }; USE_DECL diff --git a/src/common/fs/src/virtual.c b/src/common/fs/src/virtual.c index b5eda104..6804e407 100644 --- a/src/common/fs/src/virtual.c +++ b/src/common/fs/src/virtual.c @@ -96,10 +96,10 @@ static void *vfs_map(io_t *self, os_protect_t protect) return io->data->data; } -static void vfs_close(io_t *self) +static os_error_t vfs_close(io_t *self) { CT_UNUSED(self); - /* empty */ + return eOsSuccess; } static const io_callbacks_t kVirtualCallbacks = { @@ -111,6 +111,8 @@ static const io_callbacks_t kVirtualCallbacks = { .fn_map = vfs_map, .fn_close = vfs_close, + + .size = sizeof(virtual_io_t), }; static io_t *vfs_io(virtual_file_t *file, os_access_t flags, arena_t *arena) @@ -125,7 +127,7 @@ static io_t *vfs_io(virtual_file_t *file, os_access_t flags, arena_t *arena) file->used = 0; } - return io_new(&kVirtualCallbacks, flags, file->name, &data, sizeof(virtual_io_t), arena); + return io_new(&kVirtualCallbacks, flags, file->name, &data, arena); } // fs impl @@ -225,6 +227,8 @@ static const fs_callbacks_t kVirtualInterface = { .pfn_create_file = vfs_create_file, .pfn_delete_file = vfs_delete_file, + + .iter_size = sizeof(map_iter_t) }; USE_DECL diff --git a/src/common/io/include/io/impl.h b/src/common/io/include/io/impl.h index 9507b7bb..f2bbd131 100644 --- a/src/common/io/include/io/impl.h +++ b/src/common/io/include/io/impl.h @@ -76,7 +76,7 @@ typedef void *(*io_map_t)(io_t *self, os_protect_t protect); /// destroy an io objects backing data and any associated resources /// /// @param self the io object -typedef void (*io_close_t)(io_t *self); +typedef os_error_t (*io_close_t)(io_t *self); /// @brief io callback interface typedef struct io_callbacks_t @@ -92,7 +92,7 @@ typedef struct io_callbacks_t /// @brief write format callback /// may be NULL on non-writable objects /// @note if this is NULL, @a fn_write will be used instead - io_write_format_t fn_write_format; + io_write_format_t fn_fwrite; /// @brief total size callback /// must always be provided @@ -109,6 +109,9 @@ typedef struct io_callbacks_t /// @brief close callback /// optional if backing data does not require lifetime management io_close_t fn_close; + + /// @brief the size of the io objects private data + size_t size; } io_callbacks_t; /// @brief io object implementation @@ -162,7 +165,6 @@ CT_IO_API io_t *io_new( os_access_t flags, IN_STRING const char *name, IN_READS(size) const void *data, - IN_RANGE(>, 0) size_t size, IN_NOTNULL arena_t *arena); /// @} diff --git a/src/common/io/include/io/io.h b/src/common/io/include/io/io.h index a9279c29..5d6fb197 100644 --- a/src/common/io/include/io/io.h +++ b/src/common/io/include/io/io.h @@ -24,7 +24,7 @@ typedef os_error_t io_error_t; /// @brief destroy an IO object /// /// @param io the io object -CT_IO_API void io_close(OUT_PTR_INVALID io_t *io); +CT_IO_API io_error_t io_close(OUT_PTR_INVALID io_t *io); /// @brief create an IO object from a file /// diff --git a/src/common/io/src/buffer.c b/src/common/io/src/buffer.c index ade8cfbd..f4d594a1 100644 --- a/src/common/io/src/buffer.c +++ b/src/common/io/src/buffer.c @@ -7,6 +7,7 @@ #include "base/panic.h" #include "base/util.h" +#include "os/os.h" /// @brief a read/write in memory file typedef struct buffer_t @@ -70,10 +71,12 @@ static void *mem_map(io_t *self, os_protect_t protect) return mem->data; } -static void mem_close(io_t *self) +static os_error_t mem_close(io_t *self) { buffer_t *mem = mem_data(self); arena_free(mem->data, mem->total, self->arena); + + return eOsSuccess; } static const io_callbacks_t kBufferCallbacks = { @@ -84,7 +87,9 @@ static const io_callbacks_t kBufferCallbacks = { .fn_seek = mem_seek, .fn_map = mem_map, - .fn_close = mem_close + .fn_close = mem_close, + + .size = sizeof(buffer_t) }; USE_DECL @@ -103,7 +108,7 @@ io_t *io_memory(const char *name, const void *data, size_t size, os_access_t fla ctu_memcpy(buffer.data, data, size); - io_t *io = io_new(&kBufferCallbacks, flags, name, &buffer, sizeof(buffer_t), arena); + io_t *io = io_new(&kBufferCallbacks, flags, name, &buffer, arena); ARENA_REPARENT(buffer.data, io, arena); return io; } @@ -121,7 +126,7 @@ io_t *io_blob(const char *name, size_t size, os_access_t flags, arena_t *arena) .offset = 0 }; - io_t *io = io_new(&kBufferCallbacks, flags, name, &buffer, sizeof(buffer_t), arena); + io_t *io = io_new(&kBufferCallbacks, flags, name, &buffer, arena); ARENA_REPARENT(buffer.data, io, arena); return io; } diff --git a/src/common/io/src/common.c b/src/common/io/src/common.c index d4b1885a..06c85b90 100644 --- a/src/common/io/src/common.c +++ b/src/common/io/src/common.c @@ -17,8 +17,7 @@ void *io_data(io_t *io) return io->data; } -io_t *io_new(const io_callbacks_t *cb, os_access_t flags, const char *name, const void *data, - size_t size, arena_t *arena) +io_t *io_new(const io_callbacks_t *cb, os_access_t flags, const char *name, const void *data, arena_t *arena) { CTASSERT(cb != NULL); CTASSERT(name != NULL); @@ -31,12 +30,12 @@ io_t *io_new(const io_callbacks_t *cb, os_access_t flags, const char *name, cons if (flags & eOsAccessRead) CTASSERTF(cb->fn_read != NULL, "%s provided no `fn_read` for a readable object", name); - io_t *io = ARENA_MALLOC(sizeof(io_t) + size, name, NULL, arena); + io_t *io = ARENA_MALLOC(sizeof(io_t) + cb->size, name, NULL, arena); - if (size > 0) + if (cb->size > 0) { CTASSERT(data != NULL); - ctu_memcpy(io_data(io), data, size); + ctu_memcpy(io_data(io), data, cb->size); } io->cb = cb; diff --git a/src/common/io/src/console.c b/src/common/io/src/console.c index 5fa8effe..5d40f8a1 100644 --- a/src/common/io/src/console.c +++ b/src/common/io/src/console.c @@ -7,28 +7,40 @@ #include -static size_t con_out_write(io_t *self, const char *fmt, va_list args) +static size_t cout_write(io_t *self, const void *src, size_t size) { CT_UNUSED(self); + return fwrite(src, 1, size, stdout); +} +static size_t cout_fwrite(io_t *self, const char *fmt, va_list args) +{ + CT_UNUSED(self); return vfprintf(stdout, fmt, args); } -static size_t con_error_write(io_t *self, const char *fmt, va_list args) +static size_t cerr_write(io_t *self, const void *src, size_t size) { CT_UNUSED(self); + return fwrite(src, 1, size, stderr); +} +static size_t cerr_fwrite(io_t *self, const char *fmt, va_list args) +{ + CT_UNUSED(self); return vfprintf(stderr, fmt, args); } // TODO: find a way to simplify this down to a single io_t static const io_callbacks_t kConsoleOutCallbacks = { - .fn_write_format = con_out_write, + .fn_write = cout_write, + .fn_fwrite = cout_fwrite, }; static const io_callbacks_t kConsoleErrorCallbacks = { - .fn_write_format = con_error_write, + .fn_write = cerr_write, + .fn_fwrite = cerr_fwrite, }; static io_t gConsoleOutIo = { diff --git a/src/common/io/src/file.c b/src/common/io/src/file.c index c25a5c80..7cf438ed 100644 --- a/src/common/io/src/file.c +++ b/src/common/io/src/file.c @@ -77,22 +77,19 @@ static void *fd_map(io_t *self, os_protect_t protect) return os_mapping_data(&file->mapping); } -static void fd_close(io_t *self) +static os_error_t fd_close(io_t *self) { io_file_t *file = fd_data(self); - if (io_error(self) == 0) - { - os_error_t err = 0; - - if (os_mapping_active(&file->mapping)) - { - err = os_unmap(&file->mapping); - CTASSERTF(err == 0, "failed to unmap file (%s)", os_error_string(err, self->arena)); - } + os_error_t err = 0; - err = os_file_close(&file->file); - CTASSERTF(err == 0, "failed to close file (%s)", os_error_string(err, self->arena)); + if (os_mapping_active(&file->mapping)) + { + err = os_unmap(&file->mapping); + if (err != eOsSuccess) + return err; } + + return os_file_close(&file->file); } static const io_callbacks_t kFileCallbacks = { @@ -104,6 +101,8 @@ static const io_callbacks_t kFileCallbacks = { .fn_map = fd_map, .fn_close = fd_close, + + .size = sizeof(io_file_t), }; USE_DECL @@ -119,7 +118,7 @@ io_t *io_file(const char *path, os_access_t mode, arena_t *arena) .file = fd, }; - io_t *io = io_new(&kFileCallbacks, mode, path, &data, sizeof(io_file_t), arena); + io_t *io = io_new(&kFileCallbacks, mode, path, &data, arena); io->error = err; return io; diff --git a/src/common/io/src/io.c b/src/common/io/src/io.c index 51048d2a..c0107256 100644 --- a/src/common/io/src/io.c +++ b/src/common/io/src/io.c @@ -3,15 +3,25 @@ #include "io/io.h" #include "io/impl.h" +#include "os/os.h" #include "base/panic.h" #include "std/str.h" +#include "arena/arena.h" -void io_close(io_t *io) +io_error_t io_close(io_t *io) { CTASSERT(io != NULL); + io_error_t err = io_error(io); + if (err != eOsSuccess) + return err; + if (io->cb->fn_close != NULL) - io->cb->fn_close(io); + return io->cb->fn_close(io); + + arena_free(io, sizeof(io_t) + io->cb->size, io->arena); + + return eOsSuccess; } USE_DECL @@ -55,9 +65,9 @@ size_t io_vprintf(io_t *io, const char *fmt, va_list args) CTASSERT(io != NULL); const io_callbacks_t *cb = io->cb; - if (cb->fn_write_format != NULL) + if (cb->fn_fwrite != NULL) { - return cb->fn_write_format(io, fmt, args); + return cb->fn_fwrite(io, fmt, args); } text_t text = text_vformat(io->arena, fmt, args); @@ -98,15 +108,15 @@ void *io_map(io_t *io, os_protect_t protect) CTASSERTF(protect != eOsProtectNone, "cannot io_map(%s). protect is eOsProtectNone", io_name(io)); - // validate protect against access flags + // validate protect flags against access flags if (protect & eOsProtectRead) { - CTASSERTF(io->flags & eOsAccessRead, "io.map(%s) flags not readable", io_name(io)); + CTASSERTF(io->flags & eOsAccessRead, "io_map(%s) flags not readable", io_name(io)); } if (protect & eOsProtectWrite) { - CTASSERTF(io->flags & eOsAccessWrite, "io.map(%s) flags not writable", io_name(io)); + CTASSERTF(io->flags & eOsAccessWrite, "io_map(%s) flags not writable", io_name(io)); } if (io_size(io) == 0) { return ""; } diff --git a/src/common/io/src/view.c b/src/common/io/src/view.c index 2853d415..59c4e8da 100644 --- a/src/common/io/src/view.c +++ b/src/common/io/src/view.c @@ -53,12 +53,13 @@ static void *view_map(io_t *self, os_protect_t protect) static const io_callbacks_t kViewCallbacks = { .fn_read = view_read, - .fn_write = NULL, .fn_get_size = view_size, .fn_seek = view_seek, - .fn_map = view_map + .fn_map = view_map, + + .size = sizeof(view_t), }; USE_DECL @@ -76,7 +77,7 @@ io_t *io_view(const char *name, const void *data, size_t size, arena_t *arena) .offset = 0 }; - return io_new(&kViewCallbacks, flags, name, &view, sizeof(view_t), arena); + return io_new(&kViewCallbacks, flags, name, &view, arena); } USE_DECL diff --git a/src/common/os/include/os/core.h b/src/common/os/include/os/core.h index 34420e78..513d38e6 100644 --- a/src/common/os/include/os/core.h +++ b/src/common/os/include/os/core.h @@ -22,6 +22,9 @@ CT_BEGIN_API /// @brief file handle typedef struct os_file_t os_file_t; +/// @brief memory mapping handle +typedef struct os_mapping_t os_mapping_t; + /// @brief inode handle typedef struct os_inode_t os_inode_t; @@ -146,6 +149,23 @@ CT_OS_API char *os_cwd_string(IN_NOTNULL arena_t *arena); RET_INSPECT CT_OS_API os_error_t os_getcwd(OUT_NOTNULL text_t *text, IN_NOTNULL arena_t *arena); +/// @brief get the type of an inode +/// +/// @param node the inode to get the type of +/// +/// @return the type of the inode +CT_NODISCARD +CT_OS_API os_dirent_t os_inode_type(IN_NOTNULL const os_inode_t *node); + +/// @brief get the name of an inode +/// @note the name is only valid for the lifetime of the inode +/// +/// @param node the inode to get the name of +/// +/// @return the name of the inode +CT_NODISCARD +CT_OS_API const char *os_inode_name(IN_NOTNULL const os_inode_t *node); + /// @brief get the string representation of a directory entry type /// /// @param type the directory entry type diff --git a/src/common/os/include/os/impl/posix.h b/src/common/os/include/os/impl/posix.h index 520c71c4..8787a814 100644 --- a/src/common/os/include/os/impl/posix.h +++ b/src/common/os/include/os/impl/posix.h @@ -8,6 +8,8 @@ typedef void *os_library_impl_t; typedef FILE *os_file_impl_t; +typedef struct dirent *os_inode_impl_t; +typedef DIR *os_iter_impl_t; typedef struct os_mapping_t { @@ -15,17 +17,6 @@ typedef struct os_mapping_t size_t size; } os_mapping_t; -typedef struct os_iter_t -{ - DIR *dir; - int error; -} os_iter_t; - -typedef struct os_inode_t -{ - struct dirent *ent; -} os_inode_t; - enum { eOsSuccess = 0, eOsNotFound = ENOENT, @@ -36,5 +27,11 @@ enum { #define CT_OS_INVALID_FILE NULL #define CT_OS_INVALID_LIBRARY NULL #define CT_OS_INVALID_MAPPING NULL - -#define CT_OS_NAME_MAX NAME_MAX +#define CT_OS_INVALID_ITER NULL + +// TODO: this is wrong, im not sure how i might go about fixing it +#ifdef _DIRENT_HAVE_D_NAMLEN +# define CT_OS_NAME_MAX NAME_MAX +#else +# define CT_OS_NAME_MAX 255 +#endif diff --git a/src/common/os/include/os/impl/win32.h b/src/common/os/include/os/impl/win32.h index ba02ff36..c28967df 100644 --- a/src/common/os/include/os/impl/win32.h +++ b/src/common/os/include/os/impl/win32.h @@ -9,6 +9,8 @@ typedef HMODULE os_library_impl_t; typedef HANDLE os_file_impl_t; +typedef WIN32_FIND_DATA os_inode_impl_t; +typedef HANDLE os_iter_impl_t; typedef struct os_mapping_t { @@ -17,18 +19,6 @@ typedef struct os_mapping_t size_t size; } os_mapping_t; -typedef struct os_iter_t -{ - HANDLE find; - WIN32_FIND_DATA data; - DWORD error; -} os_iter_t; - -typedef struct os_inode_t -{ - WIN32_FIND_DATA data; -} os_inode_t; - enum { eOsSuccess = ERROR_SUCCESS, eOsNotFound = ERROR_FILE_NOT_FOUND, @@ -39,5 +29,6 @@ enum { #define CT_OS_INVALID_FILE INVALID_HANDLE_VALUE #define CT_OS_INVALID_LIBRARY NULL #define CT_OS_INVALID_MAPPING NULL +#define CT_OS_INVALID_ITER INVALID_HANDLE_VALUE #define CT_OS_NAME_MAX MAX_PATH diff --git a/src/common/os/include/os/os.h b/src/common/os/include/os/os.h index 54642955..7e2fdb65 100644 --- a/src/common/os/include/os/os.h +++ b/src/common/os/include/os/os.h @@ -23,18 +23,46 @@ CT_BEGIN_API /// @warning do not access the library handle directly, it is platform specific typedef struct os_library_t { + // used by os_common const char *name; - os_library_impl_t library; + + // used by os_native + os_library_impl_t impl; } os_library_t; /// @brief a file handle /// @warning do not access the file handle directly, it is platform specific typedef struct os_file_t { + // used by os_common const char *path; - os_file_impl_t file; + + // used by os_native + os_file_impl_t impl; } os_file_t; +/// @brief an inode entry +/// @warning do not access the inode entry directly, it is platform specific +typedef struct os_inode_t +{ + // used by os_common + os_dirent_t type; + char name[CT_OS_NAME_MAX]; +} os_inode_t; + +/// @brief a directory iterator +/// @warning do not access the iterator directly, it is platform specific +typedef struct os_iter_t +{ + // used by os_common + os_error_t error; + os_inode_t inode; + + // used by os_native + os_iter_impl_t impl; + os_inode_impl_t current; +} os_iter_t; + /// shared library api /// @brief open a shared library from disk @@ -65,7 +93,7 @@ CT_OS_API os_error_t os_library_close( CT_NODISCARD CT_OS_API os_error_t os_library_symbol( INOUT_NOTNULL os_library_t *library, - OUT_NOTNULL os_symbol_t *symbol, + OUT_NOTNULL void **symbol, IN_STRING const char *name); /// @brief get the name of a shared library diff --git a/src/common/os/src/os.c b/src/common/os/src/os.c index dde1c709..14ec92d6 100644 --- a/src/common/os/src/os.c +++ b/src/common/os/src/os.c @@ -99,7 +99,7 @@ size_t os_dir_get_string(const os_inode_t *dir, char *buffer, size_t size) } CTASSERT(buffer != NULL); - const char *name = impl_dirname(dir); + const char *name = os_inode_name(dir); size_t len = ctu_strlen(name); size_t copy = CT_MIN(len, size - 1); ctu_strcpy(buffer, name, copy); @@ -197,7 +197,7 @@ os_error_t os_library_open(const char *path, os_library_t *library) return impl_last_error(); } - library->library = lib; + library->impl = lib; library->name = path; return eOsSuccess; @@ -208,7 +208,7 @@ os_error_t os_library_close(os_library_t *library) { CTASSERT(library != NULL); - if (!impl_library_close(library->library)) + if (!impl_library_close(library->impl)) { return impl_last_error(); } @@ -217,12 +217,12 @@ os_error_t os_library_close(os_library_t *library) } USE_DECL -os_error_t os_library_symbol(os_library_t *library, os_symbol_t *symbol, const char *name) +os_error_t os_library_symbol(os_library_t *library, void **symbol, const char *name) { CTASSERT(library != NULL); CTASSERT(name != NULL); - os_symbol_t addr = impl_library_symbol(library->library, name); + void *addr = impl_library_symbol(library->impl, name); if (addr == NULL) { return impl_last_error(); @@ -259,8 +259,8 @@ os_error_t os_file_open(const char *path, os_access_t access, os_file_t *file) return impl_last_error(); } - file->file = fd; file->path = path; + file->impl = fd; return eOsSuccess; } @@ -269,9 +269,9 @@ USE_DECL os_error_t os_file_close(os_file_t *fd) { CTASSERT(fd != NULL); - CTASSERTF(fd->file != CT_OS_INVALID_FILE, "invalid file handle (%s)", fd->path); + CTASSERTF(fd->impl != CT_OS_INVALID_FILE, "invalid file handle (%s)", fd->path); - if (!impl_file_close(fd)) + if (!impl_file_close(fd->impl)) { return impl_last_error(); } @@ -356,3 +356,106 @@ bool os_dir_exists(const char *path) os_dirent_t type = os_dirent_type(path); return type == eOsNodeDir; } + +/// +/// directory iteration operations +/// + +static void inode_create(os_inode_t *dst, const os_inode_impl_t *src) +{ + dst->type = impl_inode_type(src); + ctu_strcpy(dst->name, impl_inode_name(src), CT_OS_NAME_MAX); +} + +static bool iter_next(os_iter_t *iter, os_inode_impl_t *result) +{ + bool ok = impl_iter_next(iter->impl, result); + if (!ok) + { + iter->error = impl_last_error(); + } + + return ok; +} + +USE_DECL +os_error_t os_iter_begin(const char *path, os_iter_t *result) +{ + CTASSERT(path != NULL); + CTASSERT(result != NULL); + + result->error = eOsSuccess; + result->impl = impl_iter_open(path, &result->current); + if (result->impl == CT_OS_INVALID_ITER) + { + result->error = impl_last_error(); + } + + return result->error; +} + +USE_DECL +os_error_t os_iter_end(os_iter_t *iter) +{ + CTASSERT(iter != NULL); + + if (!impl_iter_close(iter->impl)) + { + return impl_last_error(); + } + + return eOsSuccess; +} + +USE_DECL +bool os_iter_next(os_iter_t *iter, os_inode_t *result) +{ + CTASSERT(iter != NULL); + CTASSERT(result != NULL); + + if (iter->error != eOsSuccess) + return false; + + os_inode_impl_t data; + while (iter_next(iter, &data)) + { + if (!is_path_special(impl_inode_name(&data))) + { + break; + } + } + + if (iter->error != eOsSuccess) + return false; + + inode_create(result, &data); + return true; +} + +USE_DECL +os_error_t os_iter_error(const os_iter_t *iter) +{ + CTASSERT(iter != NULL); + + return iter->error; +} + +/// +/// inode operations +/// + +USE_DECL +os_dirent_t os_inode_type(const os_inode_t *node) +{ + CTASSERT(node != NULL); + + return node->type; +} + +USE_DECL +const char *os_inode_name(const os_inode_t *node) +{ + CTASSERT(node != NULL); + + return node->name; +} diff --git a/src/common/os/src/os_common.h b/src/common/os/src/os_common.h index 351812ce..25a26944 100644 --- a/src/common/os/src/os_common.h +++ b/src/common/os/src/os_common.h @@ -17,9 +17,6 @@ CT_BEGIN_API // get the last error CT_LOCAL os_error_t impl_last_error(void); -// get the name of an inode -CT_LOCAL const char *impl_dirname(const os_inode_t *inode); - // get the max length of a name or path CT_LOCAL size_t impl_maxname(void); CT_LOCAL size_t impl_maxpath(void); @@ -30,15 +27,28 @@ CT_LOCAL os_error_t impl_copyfile(const char *dst, const char *src); // files CT_LOCAL os_file_impl_t impl_file_open(const char *path, os_access_t access); -CT_LOCAL bool impl_file_close(os_file_t *file); + +// close a file handle +// return false if there was an error +CT_LOCAL bool impl_file_close(os_file_impl_t impl); // file mapping CT_LOCAL void *impl_file_map(os_file_t *file, os_protect_t protect, size_t size, os_mapping_t *map); CT_LOCAL os_error_t impl_unmap(os_mapping_t *map); +// iteration + +// returns true if there was a new inode +CT_LOCAL os_iter_impl_t impl_iter_open(const char *path, os_inode_impl_t *inode); +CT_LOCAL bool impl_iter_next(os_iter_impl_t impl, os_inode_impl_t *inode); +CT_LOCAL bool impl_iter_close(os_iter_impl_t impl); + +CT_LOCAL const char *impl_inode_name(const os_inode_impl_t *inode); +CT_LOCAL os_dirent_t impl_inode_type(const os_inode_impl_t *inode); + // libraries CT_LOCAL os_library_impl_t impl_library_open(const char *path); CT_LOCAL bool impl_library_close(os_library_impl_t lib); -CT_LOCAL os_symbol_t impl_library_symbol(os_library_impl_t lib, const char *name); +CT_LOCAL void *impl_library_symbol(os_library_impl_t lib, const char *name); CT_END_API diff --git a/src/common/os/src/posix/dir.c b/src/common/os/src/posix/dir.c index ce2627cb..2cb0a83f 100644 --- a/src/common/os/src/posix/dir.c +++ b/src/common/os/src/posix/dir.c @@ -2,81 +2,35 @@ #include "os/os.h" #include "os_common.h" +#include "core/macros.h" -#include "base/panic.h" -#include "base/util.h" - -#include - -USE_DECL -os_error_t os_iter_begin(const char *path, os_iter_t *result) +os_iter_impl_t impl_iter_open(const char *path, os_inode_impl_t *inode) { - CTASSERT(path != NULL); - CTASSERT(result != NULL); - - DIR *dir = opendir(path); - if (dir == NULL) - { - return errno; - } + CT_UNUSED(inode); - os_iter_t iter = { - .dir = dir - }; - *result = iter; - return 0; + return opendir(path); } -os_error_t os_iter_end(os_iter_t *iter) +bool impl_iter_next(os_iter_impl_t impl, os_inode_impl_t *inode) { - CTASSERT(iter != NULL); - - if (closedir(iter->dir) != 0) - { - return errno; - } - - return 0; + struct dirent *ent = readdir(impl); + *inode = ent; + return ent != NULL; } -USE_DECL -bool os_iter_next(os_iter_t *iter, os_inode_t *result) +bool impl_iter_close(os_iter_impl_t impl) { - CTASSERT(iter != NULL); - CTASSERT(result != NULL); - - struct dirent *ent = NULL; - while ((ent = readdir(iter->dir)) != NULL) - { - if (!is_path_special(ent->d_name)) - { - break; - } - } - - if (ent == NULL) - { - iter->error = errno; - return false; - } - - os_inode_t dir = { - .ent = ent - }; - *result = dir; - - return true; + return closedir(impl) == 0; } -USE_DECL -os_error_t os_iter_error(const os_iter_t *iter) +const char *impl_inode_name(const os_inode_impl_t *inode) { - CTASSERT(iter != NULL); - - return iter->error; + struct dirent *ent = *inode; + return ent->d_name; } -const char *impl_dirname(const os_inode_t *inode) +os_dirent_t impl_inode_type(const os_inode_impl_t *inode) { - return inode->ent->d_name; + struct dirent *ent = *inode; + return ent->d_type == DT_DIR ? eOsNodeDir : eOsNodeFile; } diff --git a/src/common/os/src/posix/file.c b/src/common/os/src/posix/file.c index 27eaeaf6..d618abcc 100644 --- a/src/common/os/src/posix/file.c +++ b/src/common/os/src/posix/file.c @@ -65,16 +65,16 @@ os_error_t os_tmpfile_open(os_file_t *file) os_file_t result = { .path = "", - .file = fd, + .impl = fd, }; *file = result; return 0; } -bool impl_file_close(os_file_t *file) +bool impl_file_close(os_file_impl_t file) { - return fclose(file->file) == 0; + return fclose(file) == 0; } USE_DECL @@ -85,11 +85,11 @@ os_error_t os_file_read(os_file_t *file, void *buffer, size_t size, size_t *actu CTASSERT(size > 0); CTASSERT(actual != NULL); - size_t read = fread(buffer, 1, size, file->file); + size_t read = fread(buffer, 1, size, file->impl); if (read < size) { - if (ferror(file->file)) + if (ferror(file->impl)) { return errno; } @@ -107,11 +107,11 @@ os_error_t os_file_write(os_file_t *file, const void *buffer, size_t size, size_ CTASSERT(size > 0); CTASSERT(actual != NULL); - size_t written = fwrite(buffer, 1, size, file->file); + size_t written = fwrite(buffer, 1, size, file->impl); if (written < size) { - if (ferror(file->file)) + if (ferror(file->impl)) { return errno; } @@ -127,15 +127,15 @@ os_error_t os_file_size(os_file_t *file, size_t *actual) CTASSERT(file != NULL); CTASSERT(actual != NULL); - long pos = ftell(file->file); + long pos = ftell(file->impl); if (pos < 0) { return errno; } - if (fseek(file->file, 0, SEEK_END) < 0) { return errno; } + if (fseek(file->impl, 0, SEEK_END) < 0) { return errno; } - long size = ftell(file->file); + long size = ftell(file->impl); if (size < 0) { return errno; } - if (fseek(file->file, pos, SEEK_SET) < 0) { return errno; } + if (fseek(file->impl, pos, SEEK_SET) < 0) { return errno; } *actual = size; return 0; @@ -147,16 +147,16 @@ os_error_t os_file_expand(os_file_t *file, size_t size) CTASSERT(file != NULL); // save the current position - long pos = ftell(file->file); + long pos = ftell(file->impl); if (pos < 0) return errno; - int result = ftruncate(fileno(file->file), size); + int result = ftruncate(fileno(file->impl), size); if (result < 0) return errno; // restore the position - result = fseek(file->file, pos, SEEK_SET); + result = fseek(file->impl, pos, SEEK_SET); if (result < 0) return errno; @@ -170,7 +170,7 @@ os_error_t os_file_seek(os_file_t *file, size_t offset, size_t *actual) CTASSERT(offset < LONG_MAX); CTASSERT(actual != NULL); - int result = fseek(file->file, (long)offset, SEEK_SET); + int result = fseek(file->impl, (long)offset, SEEK_SET); if (result < 0) { return errno; @@ -186,7 +186,7 @@ os_error_t os_file_tell(os_file_t *file, size_t *actual) CTASSERT(file != NULL); CTASSERT(actual != NULL); - long pos = ftell(file->file); + long pos = ftell(file->impl); if (pos < 0) { @@ -225,7 +225,7 @@ void *impl_file_map(os_file_t *file, os_protect_t protect, size_t size, os_mappi int prot = get_mmap_prot(protect); - int fd = fileno(file->file); + int fd = fileno(file->impl); return mmap(NULL, size, prot, MAP_PRIVATE, fd, 0); } diff --git a/src/common/os/src/posix/library.c b/src/common/os/src/posix/library.c index 173ee085..73244be0 100644 --- a/src/common/os/src/posix/library.c +++ b/src/common/os/src/posix/library.c @@ -24,12 +24,12 @@ bool impl_library_close(os_library_impl_t lib) # pragma GCC diagnostic ignored "-Wpedantic" #endif -os_symbol_t impl_library_symbol(os_library_impl_t lib, const char *name) +void *impl_library_symbol(os_library_impl_t lib, const char *name) { // clear any previous errors dlerror(); - os_symbol_t addr = (os_symbol_t)dlsym(lib, name); + void *addr = (void*)dlsym(lib, name); const char *error = dlerror(); if (error != NULL) diff --git a/src/common/os/src/windows/dir.c b/src/common/os/src/windows/dir.c index 3fc50080..4a8b18f8 100644 --- a/src/common/os/src/windows/dir.c +++ b/src/common/os/src/windows/dir.c @@ -1,112 +1,35 @@ // SPDX-License-Identifier: LGPL-3.0-only - #include "os/os.h" #include "os_common.h" -#include "base/util.h" #include "core/win32.h" // IWYU pragma: keep -#include "base/panic.h" - #include "std/str.h" -static BOOL find_next(HANDLE handle, WIN32_FIND_DATA *data, DWORD *error) -{ - BOOL result = FindNextFileA(handle, data); - if (result == 0) - { - *error = GetLastError(); - } - return result; -} - -USE_DECL -os_error_t os_iter_begin(const char *path, os_iter_t *result) +os_iter_impl_t impl_iter_open(const char *path, os_inode_impl_t *inode) { - CTASSERT(path != NULL); - CTASSERT(result != NULL); - - char wild[MAX_PATH]; - str_sprintf(wild, sizeof(wild), "%s" CT_NATIVE_PATH_SEPARATOR "*", path); - - WIN32_FIND_DATA data; - DWORD error = ERROR_SUCCESS; - HANDLE find = FindFirstFileA(wild, &data); - - if (find == INVALID_HANDLE_VALUE) - { - return GetLastError(); - } - - do - { - if (!is_path_special(data.cFileName)) - { - break; - } - } while (find_next(find, &data, &error) != 0); + char wildcard[MAX_PATH]; + str_sprintf(wildcard, MAX_PATH, "%s" CT_NATIVE_PATH_SEPARATOR "*", path); - os_iter_t iter = { - .find = find, - .data = data, - .error = error - }; - - *result = iter; - return ERROR_SUCCESS; + return FindFirstFileA(wildcard, inode); } -USE_DECL -os_error_t os_iter_end(os_iter_t *iter) +bool impl_iter_next(os_iter_impl_t impl, os_inode_impl_t *inode) { - CTASSERT(iter != NULL); - - if (FindClose(iter->find) == 0) - { - return GetLastError(); - } - - return ERROR_SUCCESS; + return FindNextFileA(impl, inode); } -USE_DECL -bool os_iter_next(os_iter_t *iter, os_inode_t *result) +bool impl_iter_close(os_iter_impl_t impl) { - CTASSERT(iter != NULL); - CTASSERT(result != NULL); - - // check for error from previous iteration - if (iter->error != ERROR_SUCCESS) - return false; - - PWIN32_FIND_DATA data = &iter->data; - os_inode_t dir = { .data = iter->data }; - - // get the next directory - while (find_next(iter->find, data, &iter->error) != 0) - { - if (!is_path_special(data->cFileName)) - { - break; - } - } - - *result = dir; - return true; + return FindClose(impl) != 0; } -USE_DECL -os_error_t os_iter_error(const os_iter_t *iter) +const char *impl_inode_name(const os_inode_impl_t *inode) { - CTASSERT(iter != NULL); - - if (iter->error == ERROR_NO_MORE_FILES) - return ERROR_SUCCESS; - - return iter->error; + return inode->cFileName; } -const char *impl_dirname(const os_inode_t *inode) +os_dirent_t impl_inode_type(const os_inode_impl_t *inode) { - return inode->data.cFileName; + return (inode->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? eOsNodeDir : eOsNodeFile; } diff --git a/src/common/os/src/windows/error.c b/src/common/os/src/windows/error.c index 5c697823..e1f2518b 100644 --- a/src/common/os/src/windows/error.c +++ b/src/common/os/src/windows/error.c @@ -24,7 +24,7 @@ static DWORD format_inner(os_error_t error, char *buffer, size_t size) /* dwMessageId = */ (DWORD)error, /* dwLanguageId = */ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* lpBuffer = */ buffer, - /* nSize = */ size, + /* nSize = */ (DWORD)size, /* Arguments = */ NULL); } @@ -34,7 +34,11 @@ size_t os_error_get_string(os_error_t error, char *buffer, size_t size) if (size == 0) { // caller is asking for the size of the buffer - return format_inner(error, NULL, 0); + CTASSERT(buffer == NULL); + + // TODO: is there a way of asking for the size of the buffer at all? + // this is what .NET core does, but its not clear if this is correct. + return 0x1000 * sizeof(TCHAR); } CTASSERT(buffer != NULL); @@ -50,5 +54,8 @@ size_t os_error_get_string(os_error_t error, char *buffer, size_t size) text_t text = text_make(buffer, written); str_replace_inplace(&text, "\r\n\t", " "); + // trim trailing whitespace and . characters + str_trim_back_inplace(&text, "\r\n\t ."); + return text.length; } diff --git a/src/common/os/src/windows/file.c b/src/common/os/src/windows/file.c index 2792eafa..a844e777 100644 --- a/src/common/os/src/windows/file.c +++ b/src/common/os/src/windows/file.c @@ -108,9 +108,9 @@ os_error_t os_tmpfile_open(os_file_t *file) return os_file_open(name, eOsAccessWrite, file); } -bool impl_file_close(os_file_t *fd) +bool impl_file_close(os_file_impl_t impl) { - return CloseHandle(fd->file) != 0; + return CloseHandle(impl) != 0; } USE_DECL @@ -122,7 +122,7 @@ os_error_t os_file_read(os_file_t *file, void *buffer, size_t size, size_t *actu CTASSERTF(size <= UINT32_MAX, "cannot read more than %u bytes at once (%zu is too big)", UINT32_MAX, size); DWORD read_size = 0; - BOOL result = ReadFile(file->file, buffer, (DWORD)size, &read_size, NULL); + BOOL result = ReadFile(file->impl, buffer, (DWORD)size, &read_size, NULL); size_t read = read_size; @@ -144,7 +144,7 @@ os_error_t os_file_write(os_file_t *file, const void *buffer, size_t size, size_ CTASSERTF(size <= UINT32_MAX, "cannot write more than %u bytes at once (%zu is too big)", UINT32_MAX, size); DWORD written_size = 0; - BOOL result = WriteFile(file->file, buffer, (DWORD)size, &written_size, NULL); + BOOL result = WriteFile(file->impl, buffer, (DWORD)size, &written_size, NULL); size_t written = written_size; @@ -164,7 +164,7 @@ os_error_t os_file_size(os_file_t *file, size_t *actual) CTASSERT(actual != NULL); LARGE_INTEGER size; - BOOL result = GetFileSizeEx(file->file, &size); + BOOL result = GetFileSizeEx(file->impl, &size); *actual = size.QuadPart; if (!result) @@ -183,7 +183,7 @@ os_error_t os_file_seek(os_file_t *file, size_t offset, size_t *actual) LARGE_INTEGER it = { .QuadPart = (LONGLONG)offset }; LARGE_INTEGER out = { 0 }; - BOOL result = SetFilePointerEx(file->file, it, &out, FILE_BEGIN); + BOOL result = SetFilePointerEx(file->impl, it, &out, FILE_BEGIN); *actual = out.QuadPart; if (!result) @@ -201,7 +201,7 @@ os_error_t os_file_tell(os_file_t *file, size_t *actual) LARGE_INTEGER offset = { 0 }; LARGE_INTEGER zero = { 0 }; - BOOL result = SetFilePointerEx(file->file, zero, &offset, FILE_CURRENT); + BOOL result = SetFilePointerEx(file->impl, zero, &offset, FILE_CURRENT); *actual = offset.QuadPart; if (!result) @@ -218,13 +218,13 @@ os_error_t os_file_expand(os_file_t *file, size_t size) CTASSERT(file != NULL); LARGE_INTEGER it = { .QuadPart = (LONGLONG)size }; - BOOL result = SetFilePointerEx(file->file, it, NULL, FILE_BEGIN); + BOOL result = SetFilePointerEx(file->impl, it, NULL, FILE_BEGIN); if (!result) { return GetLastError(); } - result = SetEndOfFile(file->file); + result = SetEndOfFile(file->impl); if (!result) { return GetLastError(); @@ -283,7 +283,7 @@ void *impl_file_map(os_file_t *file, os_protect_t protect, size_t size, os_mappi DWORD low = (DWORD)(size & 0xFFFFFFFF); HANDLE handle = CreateFileMapping( - /* hFile = */ file->file, + /* hFile = */ file->impl, /* lpFileMappingAttributes = */ NULL, /* flProtect = */ prot, /* dwMaximumSizeHigh = */ high, diff --git a/src/common/os/src/windows/library.c b/src/common/os/src/windows/library.c index 60a931da..125c7031 100644 --- a/src/common/os/src/windows/library.c +++ b/src/common/os/src/windows/library.c @@ -12,7 +12,7 @@ bool impl_library_close(os_library_impl_t lib) return FreeLibrary(lib); } -os_symbol_t impl_library_symbol(os_library_impl_t lib, const char *name) +void *impl_library_symbol(os_library_impl_t lib, const char *name) { - return (os_symbol_t)GetProcAddress(lib, name); + return (void*)GetProcAddress(lib, name); } diff --git a/src/common/os/src/windows/meson.build b/src/common/os/src/windows/meson.build index efeb8eb7..275b6441 100644 --- a/src/common/os/src/windows/meson.build +++ b/src/common/os/src/windows/meson.build @@ -8,5 +8,5 @@ src = files('init.c', 'file.c', 'dir.c', 'fs.c', 'error.c', 'library.c') os_native = declare_dependency( sources : src, - dependencies : [ arena ] + dependencies : [ core ] ) diff --git a/src/common/std/include/std/str.h b/src/common/std/include/std/str.h index d746b186..82aed6bf 100644 --- a/src/common/std/include/std/str.h +++ b/src/common/std/include/std/str.h @@ -249,6 +249,12 @@ CT_STD_API char *str_replace(IN_STRING const char *str, IN_STRING const char *se /// @param repl the replacement substring CT_STD_API void str_replace_inplace(INOUT_NOTNULL text_t *text, IN_STRING const char *search, IN_STRING const char *repl); +/// @brief trim chars from the back of a string in place +/// +/// @param text the text to trim +/// @param chars the characters to trim +CT_STD_API void str_trim_back_inplace(INOUT_NOTNULL text_t *text, IN_STRING const char *chars); + /// @brief replace all instances of a each substring in a string with provided replacement /// /// @param str the string to replace elements in diff --git a/src/common/std/src/str.c b/src/common/std/src/str.c index 88427c72..88b5d677 100644 --- a/src/common/std/src/str.c +++ b/src/common/std/src/str.c @@ -628,6 +628,25 @@ void str_replace_inplace(text_t *text, const char *search, const char *repl) str[len] = '\0'; } +USE_DECL +void str_trim_back_inplace(text_t *text, const char *chars) +{ + CTASSERT(text != NULL); + CTASSERT(chars != NULL); + CTASSERT(text->text != NULL); + + size_t len = text->length; + char *str = text->text; + + while (len > 0 && char_is_any_of(str[len - 1], chars)) + { + len -= 1; + } + + text->length = len; + str[len] = '\0'; +} + USE_DECL char *str_replace_many(const char *str, const map_t *repl, arena_t *arena) { diff --git a/src/frontend/cli/main.c b/src/frontend/cli/main.c index ff5e4cbb..51060ae2 100644 --- a/src/frontend/cli/main.c +++ b/src/frontend/cli/main.c @@ -111,7 +111,7 @@ static bool add_shared_module(cli_t *cli, const char *path, module_type_t type) CT_UNUSED(path); CT_UNUSED(type); -#if CTU_LOADER_DYNAMIC +#if CT_BUILD_SHARED loaded_module_t mod = { 0 }; if (!support_load_module(cli->support, eModLanguage, path, &mod)) diff --git a/src/frontend/gui/draw/meson.build b/src/frontend/gui/draw/meson.build index b4f015e3..a9a5e9ab 100644 --- a/src/frontend/gui/draw/meson.build +++ b/src/frontend/gui/draw/meson.build @@ -2,7 +2,7 @@ src = [ 'src/draw.cpp' ] inc = include_directories('include') deps = [ imgui, implot ] -libdraw = library('draw', src, +libdraw = static_library('draw', src, cpp_args : gui_args, build_by_default : false, install : not meson.is_subproject(), diff --git a/src/frontend/gui/editor/src/main.cpp b/src/frontend/gui/editor/src/main.cpp index f31f75b9..31410196 100644 --- a/src/frontend/gui/editor/src/main.cpp +++ b/src/frontend/gui/editor/src/main.cpp @@ -312,7 +312,7 @@ class EditorUi auto& get_loader_panel() { -#if CTU_LOADER_STATIC +#if CT_BUILD_STATIC return static_module_panel; #else return dynamic_module_panel; @@ -488,8 +488,8 @@ class EditorUi void draw_loader_window() { - auto& loader = get_loader_panel(); - if (!loader.is_enabled()) + auto& panel = get_loader_panel(); + if (!panel.is_enabled()) return; const ImGuiViewport *viewport = ImGui::GetMainViewport(); @@ -502,7 +502,7 @@ class EditorUi if (ImGui::Begin("Loader", nullptr, kMainFlags)) { - loader.draw(); + panel.draw(); } ImGui::End(); } diff --git a/src/frontend/gui/editor/src/panels/arena.cpp b/src/frontend/gui/editor/src/panels/arena.cpp index 54f5c0af..dfd52384 100644 --- a/src/frontend/gui/editor/src/panels/arena.cpp +++ b/src/frontend/gui/editor/src/panels/arena.cpp @@ -12,8 +12,8 @@ TraceArena::backtrace_t TraceArena::get_backtrace() { backtrace_t capture{}; - bt_read([](bt_address_t address, void *user) { - backtrace_t *capture = static_cast(user); + bt_read([](bt_address_t address, void *ptr) { + backtrace_t *capture = static_cast(ptr); if (capture->full()) return; @@ -327,12 +327,12 @@ void TraceArena::draw_backtrace(bt_address_t it) const } } -void TraceArena::draw_name(const alloc_info_t& info) const +void TraceArena::draw_name(const alloc_info_t& alloc) const { - ScopeID scope(info.name.c_str()); - if (!info.name.empty()) + ScopeID scope(alloc.name.c_str()); + if (!alloc.name.empty()) { - ImGui::Text("%s", info.name.c_str()); + ImGui::Text("%s", alloc.name.c_str()); } else { @@ -343,7 +343,7 @@ void TraceArena::draw_name(const alloc_info_t& info) const { if (enable_stacktrace) { - draw_backtrace(info.trace); + draw_backtrace(alloc.trace); } else { @@ -357,10 +357,10 @@ void TraceArena::draw_extern_name(const void *ptr) const { if (auto it = allocs.find(ptr); it != allocs.end()) { - const auto& info = it->second; - if (!info.name.empty()) + const auto& alloc = it->second; + if (!alloc.name.empty()) { - ImGui::Text("%s (external)", info.name.c_str()); + ImGui::Text("%s (external)", alloc.name.c_str()); } else { @@ -383,36 +383,36 @@ static const ImGuiTreeNodeFlags kValueNodeFlags | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen; -void TraceArena::draw_tree_child(const void *ptr, const alloc_info_t& info) const +void TraceArena::draw_tree_child(const void *ptr, const alloc_info_t& alloc) const { ImGui::TreeNodeEx(ptr, kValueNodeFlags, "%p", ptr); ImGui::TableNextColumn(); - ImGui::Text("%zu", info.size); + ImGui::Text("%zu", alloc.size); ImGui::TableNextColumn(); - draw_name(info); + draw_name(alloc); if (ImGui::BeginItemTooltip()) { - ImGui::Text("parent: %p", info.parent); + ImGui::Text("parent: %p", alloc.parent); ImGui::EndTooltip(); } } -void TraceArena::draw_tree_group(const void *ptr, const alloc_info_t& info) const +void TraceArena::draw_tree_group(const void *ptr, const alloc_info_t& alloc) const { bool is_open = ImGui::TreeNodeEx(ptr, kGroupNodeFlags, "%p", ptr); ImGui::TableNextColumn(); - ImGui::Text("%zu", info.size); + ImGui::Text("%zu", alloc.size); ImGui::TableNextColumn(); - draw_name(info); + draw_name(alloc); if (ImGui::BeginItemTooltip()) { - ImGui::Text("parent: %p", info.parent); + ImGui::Text("parent: %p", alloc.parent); ImGui::EndTooltip(); } @@ -427,17 +427,17 @@ void TraceArena::draw_tree_group(const void *ptr, const alloc_info_t& info) cons } } -void TraceArena::draw_tree_node_info(const void *ptr, const alloc_info_t& info) const +void TraceArena::draw_tree_node_info(const void *ptr, const alloc_info_t& alloc) const { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (has_children(ptr)) { - draw_tree_group(ptr, info); + draw_tree_group(ptr, alloc); } else { - draw_tree_child(ptr, info); + draw_tree_child(ptr, alloc); } } @@ -478,15 +478,15 @@ void TraceArena::draw_tree() const if (is_external(root) && !has_parent(root)) { - alloc_info_t info = { .name = "extern" }; - draw_tree_node_info(root, info); + alloc_info_t it = { .name = "extern" }; + draw_tree_node_info(root, it); } } // draw all nodes that don't have parents and don't have children - for (auto& [ptr, info] : allocs) + for (auto& [ptr, alloc] : allocs) { - if (info.parent != nullptr || has_children(ptr)) continue; + if (alloc.parent != nullptr || has_children(ptr)) continue; draw_tree_node(ptr); } @@ -508,7 +508,7 @@ void TraceArena::draw_flat() const ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableHeadersRow(); - for (const auto& [ptr, info] : allocs) + for (const auto& [ptr, alloc] : allocs) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -516,18 +516,18 @@ void TraceArena::draw_flat() const ImGui::Text("%p", ptr); ImGui::TableNextColumn(); - ImGui::Text("%zu", info.size); + ImGui::Text("%zu", alloc.size); ImGui::TableNextColumn(); - draw_name(info); + draw_name(alloc); ImGui::TableNextColumn(); - if (info.parent) + if (alloc.parent) { - ImGui::Text("%p", info.parent); + ImGui::Text("%p", alloc.parent); if (ImGui::BeginItemTooltip()) { - draw_extern_name(info.parent); + draw_extern_name(alloc.parent); ImGui::EndTooltip(); } } diff --git a/src/frontend/gui/editor/src/panels/info.cpp b/src/frontend/gui/editor/src/panels/info.cpp index c4950d7e..4c5fcbd4 100644 --- a/src/frontend/gui/editor/src/panels/info.cpp +++ b/src/frontend/gui/editor/src/panels/info.cpp @@ -202,12 +202,12 @@ void LanguageInfoPanel::draw_content() for (size_t i = 0; i < lang.builtin.length; i++) { - const char *name = "no name"; + const char *id = "no name"; if (lang.builtin.names) - name = lang.builtin.names[i]; + id = lang.builtin.names[i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::TextUnformatted(name ? name : "no name"); + ImGui::TextUnformatted(id ? id : "no name"); ImGui::TableNextColumn(); ImGui::Text("%zu", lang.builtin.decls[i]); } diff --git a/src/frontend/gui/imfilebrowser/meson.build b/src/frontend/gui/imfilebrowser/meson.build index aed13965..72d5e6e5 100644 --- a/src/frontend/gui/imfilebrowser/meson.build +++ b/src/frontend/gui/imfilebrowser/meson.build @@ -1,7 +1,7 @@ src = [ 'imfilebrowser.cpp' ] inc = include_directories('.') -libimfilebrowser = library('imfilebrowser', src, +libimfilebrowser = static_library('imfilebrowser', src, include_directories : inc, dependencies : imgui ) diff --git a/src/frontend/gui/imgui/imconfig.h b/src/frontend/gui/imgui/imconfig.h index 582d32b4..a872acb1 100644 --- a/src/frontend/gui/imgui/imconfig.h +++ b/src/frontend/gui/imgui/imconfig.h @@ -26,6 +26,7 @@ #if CTU_STB_SPRINTF # define IMGUI_USE_STB_SPRINTF +# define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION #endif #define IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/src/frontend/gui/implot/meson.build b/src/frontend/gui/implot/meson.build index f636f6d6..37474882 100644 --- a/src/frontend/gui/implot/meson.build +++ b/src/frontend/gui/implot/meson.build @@ -7,7 +7,7 @@ src = [ inc = include_directories('.') args = cpp.get_supported_arguments('/wd4127') -libimplot = library('implot', src, +libimplot = static_library('implot', src, cpp_args : args, include_directories : inc, dependencies : imgui diff --git a/src/loader/loader/include/support/loader.h b/src/loader/loader/include/support/loader.h index 9a9df5a3..e4d00b0e 100644 --- a/src/loader/loader/include/support/loader.h +++ b/src/loader/loader/include/support/loader.h @@ -3,10 +3,10 @@ #pragma once #include -#include #include "core/analyze.h" #include "os/core.h" +#include "os/os.h" typedef struct arena_t arena_t; typedef struct typevec_t typevec_t; @@ -51,6 +51,7 @@ typedef struct loaded_module_t const language_t *lang; const plugin_t *plugin; const target_t *target; + os_library_t library; load_error_t error; os_error_t os; } loaded_module_t; diff --git a/src/loader/loader/meson.build b/src/loader/loader/meson.build index 6a6982bd..1fe99f35 100644 --- a/src/loader/loader/meson.build +++ b/src/loader/loader/meson.build @@ -86,15 +86,6 @@ else src += [ 'src/disable_shared.c' ] endif -loader_cdata = configuration_data() -loader_cdata.set10('CTU_LOADER_STATIC', default_library == 'static') -loader_cdata.set10('CTU_LOADER_DYNAMIC', default_library == 'shared') - -loader_config = configure_file( - output : 'loader_config.h', - configuration : loader_cdata -) - support_include = include_directories('.', 'include') support_impl_include = include_directories('src') diff --git a/src/loader/loader/src/common.h b/src/loader/loader/src/common.h index e5902672..19a882a8 100644 --- a/src/loader/loader/src/common.h +++ b/src/loader/loader/src/common.h @@ -2,8 +2,11 @@ #pragma once -#include - #include "support/loader.h" +typedef struct loader_t +{ + arena_t *arena; +} loader_t; + loaded_module_t load_error(load_error_t error, os_error_t os); diff --git a/src/loader/loader/src/load_shared.c b/src/loader/loader/src/load_shared.c index b13538da..eb9f88fd 100644 --- a/src/loader/loader/src/load_shared.c +++ b/src/loader/loader/src/load_shared.c @@ -6,6 +6,7 @@ #include "os/os.h" #include "base/panic.h" +#include loaded_module_t load_shared_module(loader_t *loader, module_type_t mask, const char *name) { @@ -20,13 +21,13 @@ loaded_module_t load_shared_module(loader_t *loader, module_type_t mask, const c return load_error(eLoadErrorLibrary, error); } - loaded_module_t mod = { .type = eModNone, .error = eLoadErrorNoEntry }; + loaded_module_t mod = { .type = eModNone, .library = library, .error = eLoadErrorNoEntry }; if (mask & eModLanguage) { lang_main_t fn_lang; - error = os_library_symbol(&library, (os_symbol_t*)&fn_lang, CT_LANG_ENTRY); - if (error == 0) + error = os_library_symbol(&library, (void**)&fn_lang, CT_LANG_ENTRY); + if (error == eOsSuccess) { mod.type |= eModLanguage; mod.lang = fn_lang(); @@ -37,8 +38,8 @@ loaded_module_t load_shared_module(loader_t *loader, module_type_t mask, const c if (mask & eModTarget) { target_main_t fn_target; - error = os_library_symbol(&library, (os_symbol_t*)&fn_target, CT_TARGET_ENTRY); - if (error == 0) + error = os_library_symbol(&library, (void**)&fn_target, CT_TARGET_ENTRY); + if (error == eOsSuccess) { mod.type |= eModTarget; mod.target = fn_target(); @@ -49,8 +50,8 @@ loaded_module_t load_shared_module(loader_t *loader, module_type_t mask, const c if (mask & eModPlugin) { plugin_main_t fn_plugin; - error = os_library_symbol(&library, (os_symbol_t*)&fn_plugin, CT_PLUGIN_ENTRY); - if (error == 0) + error = os_library_symbol(&library, (void**)&fn_plugin, CT_PLUGIN_ENTRY); + if (error == eOsSuccess) { mod.type |= eModPlugin; mod.plugin = fn_plugin(); @@ -58,8 +59,5 @@ loaded_module_t load_shared_module(loader_t *loader, module_type_t mask, const c } } - // TODO: what should we do if this fails? - (void)os_library_close(&library); - return mod; } diff --git a/src/loader/loader/src/load_static.c b/src/loader/loader/src/load_static.c index 46724e06..de103573 100644 --- a/src/loader/loader/src/load_static.c +++ b/src/loader/loader/src/load_static.c @@ -26,18 +26,18 @@ loaded_module_t load_static_module(loader_t *loader, module_type_t mask, const c const language_t *lang = mods.langs[i]; const module_info_t *info = &lang->info; - if (str_equal(info->id, name)) + if (!str_equal(info->id, name)) + continue; + + if (mod.lang != NULL) { - if (mod.lang != NULL) - { - const language_t *old = mod.lang; - const module_info_t *prev = &old->info; - CT_NEVER("multiple static languages with the same id: %s (prev: %s, new: %s)", info->id, prev->name, info->name); - } - - mod.type |= eModLanguage; - mod.lang = lang; + const language_t *old = mod.lang; + const module_info_t *prev = &old->info; + CT_NEVER("multiple static languages with the same id: %s (prev: %s, new: %s)", info->id, prev->name, info->name); } + + mod.type |= eModLanguage; + mod.lang = lang; } } @@ -48,18 +48,18 @@ loaded_module_t load_static_module(loader_t *loader, module_type_t mask, const c const plugin_t *plugin = mods.plugins[i]; const module_info_t *info = &plugin->info; - if (str_equal(info->id, name)) + if (!str_equal(info->id, name)) + continue; + + if (mod.plugin != NULL) { - if (mod.plugin != NULL) - { - const plugin_t *old = mod.plugin; - const module_info_t *prev = &old->info; - CT_NEVER("multiple static plugins with the same id: %s (prev: %s, new: %s)", info->id, prev->name, info->name); - } - - mod.type |= eModPlugin; - mod.plugin = plugin; + const plugin_t *old = mod.plugin; + const module_info_t *prev = &old->info; + CT_NEVER("multiple static plugins with the same id: %s (prev: %s, new: %s)", info->id, prev->name, info->name); } + + mod.type |= eModPlugin; + mod.plugin = plugin; } } @@ -69,18 +69,18 @@ loaded_module_t load_static_module(loader_t *loader, module_type_t mask, const c { const target_t *target = mods.targets[i]; const module_info_t *info = &target->info; - if (str_equal(info->id, name)) + if (!str_equal(info->id, name)) + continue; + + if (mod.target != NULL) { - if (mod.target != NULL) - { - const target_t *old = mod.target; - const module_info_t *prev = &old->info; - CT_NEVER("multiple static targets with the same id: %s (prev: %s, new: %s)", info->id, prev->name, info->name); - } - - mod.type |= eModTarget; - mod.target = target; + const target_t *old = mod.target; + const module_info_t *prev = &old->info; + CT_NEVER("multiple static targets with the same id: %s (prev: %s, new: %s)", info->id, prev->name, info->name); } + + mod.type |= eModTarget; + mod.target = target; } } diff --git a/src/loader/loader/src/loader.c b/src/loader/loader/src/loader.c index 499004c3..f458fcb5 100644 --- a/src/loader/loader/src/loader.c +++ b/src/loader/loader/src/loader.c @@ -5,26 +5,23 @@ #include "arena/arena.h" #include "base/panic.h" -#if CTU_LOADER_STATIC +#include + +#if CT_BUILD_STATIC # include "enum_modules.h" #endif #include "std/typed/vector.h" static const loader_config_t kConfig = eLoadNone -#if CTU_LOADER_STATIC +#if CT_BUILD_STATIC | eLoadStatic #endif -#if CTU_LOADER_DYNAMIC +#if CT_BUILD_SHARED | eLoadDynamic #endif ; -typedef struct loader_t -{ - arena_t *arena; -} loader_t; - loaded_module_t load_error(load_error_t error, os_error_t os) { loaded_module_t mod = { @@ -57,7 +54,7 @@ typevec_t *load_default_modules(loader_t *loader) { CTASSERT(loader != NULL); -#if CTU_LOADER_STATIC +#if CT_BUILD_STATIC static_modules_t mods = get_static_modules(); typevec_t *vec = typevec_new(sizeof(loaded_module_t), CT_LANG_COUNT + CT_PLUGIN_COUNT + CT_TARGET_COUNT, loader->arena); diff --git a/src/loader/loader/src/support.c b/src/loader/loader/src/support.c index 85a8c74c..c5099f96 100644 --- a/src/loader/loader/src/support.c +++ b/src/loader/loader/src/support.c @@ -13,6 +13,7 @@ #include "std/typed/vector.h" #include "std/map.h" #include "std/set.h" +#include typedef struct support_t { @@ -44,7 +45,9 @@ static void add_loaded_module(support_t *support, loaded_module_t mod) if (mod.type & eModLanguage) { const language_t *lang = mod.lang; + CTASSERTF(lang != NULL, "language module is NULL"); const module_info_t *info = &lang->info; + CTASSERTF(info != NULL, "language info is NULL"); CTASSERTF_ALWAYS(str_startswith(info->id, "lang/"), "language id `%s` must start with `lang/`", info->id); const char *id = info->id + sizeof("lang/") - 1; diff --git a/src/target/cfamily/src/target.c b/src/target/cfamily/src/target.c index 2eb1df96..0b5084d9 100644 --- a/src/target/cfamily/src/target.c +++ b/src/target/cfamily/src/target.c @@ -17,14 +17,6 @@ static void cfamily_destroy(target_runtime_t *runtime) CT_UNUSED(runtime); } -static void cfamily_tree(target_runtime_t *runtime, const tree_t *tree, target_emit_t *emit) -{ - // empty - CT_UNUSED(runtime); - CT_UNUSED(tree); - CT_UNUSED(emit); -} - static void cfamily_ssa(target_runtime_t *runtime, const ssa_result_t *ssa, target_emit_t *emit) { // empty diff --git a/src/tools/harness/main.c b/src/tools/harness/main.c index d3d3e117..71b3a9fe 100644 --- a/src/tools/harness/main.c +++ b/src/tools/harness/main.c @@ -224,7 +224,7 @@ int run_test_harness(int argc, const char **argv, arena_t *arena) const char *name = argv[1]; int start = 2; -#if CTU_LOADER_DYNAMIC +#if CT_BUILD_SHARED start = 3; loaded_module_t mod = {0}; CTASSERTF(support_load_module(support, eModLanguage, argv[2], &mod), "failed to load module `%s` (%s: %s)", argv[2], load_error_string(mod.error), os_error_string(mod.os, arena)); @@ -262,6 +262,7 @@ int run_test_harness(int argc, const char **argv, arena_t *arena) const char *path = argv[i]; const char *ext = str_ext(path, arena); language_runtime_t *lang = support_get_lang(support, ext); + CTASSERTF(lang != NULL, "no language for extension `%s`", ext); io_t *io = make_file(path, eOsAccessRead, arena);