From bb99e12cacd9b833fcb88f31a0cf45126ceb0b28 Mon Sep 17 00:00:00 2001 From: Harry Rose Date: Sat, 13 Dec 2025 15:15:29 +0000 Subject: [PATCH 1/6] Add option for inkcpp to compile without exceptions --- CMakeLists.txt | 2 ++ shared/public/system.h | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5764136d..2953515f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,8 @@ set(INKCPP_INKLECATE set_property(CACHE INKCPP_INKLECATE PROPERTY STRINGS "NONE" "OS" "ALL") option(INKCPP_NO_RTTI "Disable real time type information depended code. Used to build without RTTI." OFF) +option(INKCPP_NO_EXCEPTIONS + "Used to build without support for exceptions." OFF) option(INKCPP_NO_EXCEPTIONS "Used to build without support for exceptions, disables try/catch blocks and throws" OFF) option(INKCPP_NO_STD "Disables the use of C(++) std libs." OFF) diff --git a/shared/public/system.h b/shared/public/system.h index e9522079..a04fbbe3 100644 --- a/shared/public/system.h +++ b/shared/public/system.h @@ -231,14 +231,18 @@ void ink_assert(bool condition, const char* msg = nullptr, Args... args) size_t size = snprintf(nullptr, 0, msg, args...) + 1; char* message = static_cast(malloc(size)); snprintf(message, size, msg, args...); +#ifdef INK_ENABLE_EXCEPTIONS msg = message; +#else + fprintf(stderr, "Ink Assert: %s\n", message); + abort(); +#endif } -# ifdef INK_ENABLE_EXCEPTIONS throw ink_exception(msg); -# elif defined(INK_ENABLE_CSTD) fprintf(stderr, "Ink Assert: %s\n", msg); abort(); +#endif # else # error "This path needs a way to warn and then terminate, otherwise it'll silently fail" # endif From 2add7d304250f88d0333329e0d655db2f6762a39 Mon Sep 17 00:00:00 2001 From: Harry Rose Date: Sat, 13 Dec 2025 15:23:05 +0000 Subject: [PATCH 2/6] Run clang-format --- shared/public/system.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/shared/public/system.h b/shared/public/system.h index a04fbbe3..60f0fb2c 100644 --- a/shared/public/system.h +++ b/shared/public/system.h @@ -231,18 +231,14 @@ void ink_assert(bool condition, const char* msg = nullptr, Args... args) size_t size = snprintf(nullptr, 0, msg, args...) + 1; char* message = static_cast(malloc(size)); snprintf(message, size, msg, args...); -#ifdef INK_ENABLE_EXCEPTIONS msg = message; -#else - fprintf(stderr, "Ink Assert: %s\n", message); - abort(); -#endif } - +#ifdef INK_ENABLE_EXCEPTIONS throw ink_exception(msg); +#else fprintf(stderr, "Ink Assert: %s\n", msg); abort(); -#endif +# endif # else # error "This path needs a way to warn and then terminate, otherwise it'll silently fail" # endif From c7ed6a3bcd0e608ae9a9106901685e90bdb25a21 Mon Sep 17 00:00:00 2001 From: Harry Rose Date: Sun, 14 Dec 2025 13:16:32 +0000 Subject: [PATCH 3/6] Combine INK_ENABLE_EH and INK_ENABLE_EXCEPTIONS defines/options --- CMakeLists.txt | 6 ++---- shared/public/config.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2953515f..1c1448ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,10 +67,8 @@ set(INKCPP_INKLECATE set_property(CACHE INKCPP_INKLECATE PROPERTY STRINGS "NONE" "OS" "ALL") option(INKCPP_NO_RTTI "Disable real time type information depended code. Used to build without RTTI." OFF) -option(INKCPP_NO_EXCEPTIONS - "Used to build without support for exceptions." OFF) -option(INKCPP_NO_EXCEPTIONS - "Used to build without support for exceptions, disables try/catch blocks and throws" OFF) +option(INKCPP_NO_EXCEPTIONS "Used to build without support for exceptions, disables try/catch blocks and throws" OFF) + option(INKCPP_NO_STD "Disables the use of C(++) std libs." OFF) if(INKCPP_NO_RTTI) diff --git a/shared/public/config.h b/shared/public/config.h index 76d58f42..b67f43f7 100644 --- a/shared/public/config.h +++ b/shared/public/config.h @@ -19,7 +19,7 @@ # ifndef INKCPP_NO_STD # define INK_ENABLE_STL # define INK_ENABLE_CSTD -# endif +#endif #endif #ifndef INKCPP_NO_RTTI From d804139ca3ec94857a3ae7783570faa1decc0a1f Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Wed, 10 Dec 2025 11:14:21 +0100 Subject: [PATCH 4/6] fix(STL): guard references to STL and CSTD behind compile options + disable C++STL, EH and RTTI for CLIB + add c bindnings for story::from_binary and snapshot::from_binary + add compile option INKCPP_NO_STL to generate more standalone lib files --- CMakeLists.txt | 2 - inkcpp/CMakeLists.txt | 114 ++++++++++-------- inkcpp/include/list.h | 4 +- inkcpp/include/runner.h | 2 - inkcpp/include/story.h | 132 ++++++++++---------- inkcpp/runner_impl.cpp | 12 +- inkcpp/runner_impl.h | 2 - inkcpp/story_impl.cpp | 10 +- inkcpp/story_impl.h | 6 +- inkcpp/string_utils.h | 17 +-- inkcpp/value.h | 6 +- inkcpp_c/CMakeLists.txt | 108 +++++++++-------- inkcpp_c/include/inkcpp.h | 29 ++++- inkcpp_c/inkcpp.cpp | 100 +++++++++++----- inkcpp_cl/CMakeLists.txt | 87 ++++++++------ inkcpp_compiler/json_compiler.cpp | 4 +- inkcpp_test/CMakeLists.txt | 193 ++++++++++++++++-------------- shared/public/system.h | 36 +++--- 18 files changed, 487 insertions(+), 377 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c1448ac..d4e6a359 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,8 +67,6 @@ set(INKCPP_INKLECATE set_property(CACHE INKCPP_INKLECATE PROPERTY STRINGS "NONE" "OS" "ALL") option(INKCPP_NO_RTTI "Disable real time type information depended code. Used to build without RTTI." OFF) -option(INKCPP_NO_EXCEPTIONS "Used to build without support for exceptions, disables try/catch blocks and throws" OFF) - option(INKCPP_NO_STD "Disables the use of C(++) std libs." OFF) if(INKCPP_NO_RTTI) diff --git a/inkcpp/CMakeLists.txt b/inkcpp/CMakeLists.txt index 7c9ce0da..1785fdc2 100644 --- a/inkcpp/CMakeLists.txt +++ b/inkcpp/CMakeLists.txt @@ -1,73 +1,89 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) -list(APPEND SOURCES - array.h - choice.cpp - functional.cpp - functions.h functions.cpp - globals_impl.h globals_impl.cpp - output.h output.cpp - platform.h - runner_impl.h runner_impl.cpp - simple_restorable_stack.h stack.h stack.cpp - story_impl.h story_impl.cpp - snapshot_impl.h snapshot_impl.cpp snapshot_interface.h - story_ptr.cpp - system.cpp - value.h value.cpp +list( + APPEND + SOURCES + array.h + choice.cpp + functional.cpp + functions.h + functions.cpp + globals_impl.h + globals_impl.cpp + output.h + output.cpp + platform.h + runner_impl.h + runner_impl.cpp + simple_restorable_stack.h + stack.h + stack.cpp + story_impl.h + story_impl.cpp + snapshot_impl.h + snapshot_impl.cpp + snapshot_interface.h + story_ptr.cpp + system.cpp + value.h + value.cpp tuple.hpp - string_table.h string_table.cpp - list_table.h list_table.cpp - list_impl.h list_impl.cpp - operations.h operation_bases.h - list_operations.h list_operations.cpp - container_operations.h container_operations.cpp - numeric_operations.h numeric_operations.cpp - string_operations.h string_operations.cpp + string_table.h + string_table.cpp + list_table.h + list_table.cpp + list_impl.h + list_impl.cpp + operations.h + operation_bases.h + list_operations.h + list_operations.cpp + container_operations.h + container_operations.cpp + numeric_operations.h + numeric_operations.cpp + string_operations.h + string_operations.cpp string_operations.cpp numeric_operations.cpp casting.h executioner.h string_utils.h header.cpp - random.h -) -list(APPEND COLLECTION_SOURCES - collections/restorable.h - collections/restorable.cpp -) -FILE(GLOB PUBLIC_HEADERS "include/*") + random.h) +list(APPEND COLLECTION_SOURCES collections/restorable.h collections/restorable.cpp) +file(GLOB PUBLIC_HEADERS "include/*") source_group(Collections REGULAR_EXPRESSION collections/.*) add_library(inkcpp_o OBJECT ${SOURCES} ${COLLECTION_SOURCES}) -target_include_directories(inkcpp_o PUBLIC - $ - $ -) -add_library(inkcpp $) -target_include_directories(inkcpp PUBLIC - $ - $ -) +target_include_directories(inkcpp_o PUBLIC $ + $) +target_compile_definitions(inkcpp_o PRIVATE INKCPP_BUILD_CLIB INKCPP_NO_EXCEPTIONS INKCPP_NO_RTTI) +add_library(inkcpp ${SOURCES} ${COLLECTION_SOURCES}) +target_include_directories(inkcpp PUBLIC $ + $) set_target_properties(inkcpp PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}") -# Make sure the include directory is included +# Make sure the include directory is included target_link_libraries(inkcpp_o PUBLIC inkcpp_shared) target_link_libraries(inkcpp PUBLIC inkcpp_shared) # Make sure this project and all dependencies use the C++17 standard target_compile_features(inkcpp PUBLIC cxx_std_17) - # Unreal installation list(REMOVE_ITEM SOURCES "avl_array.h") -configure_file("avl_array.h" "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/ThirdParty/Private/avl_array.h" COPYONLY) -foreach(FILE IN LISTS SOURCES) - configure_file("${FILE}" "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/inkcpp/Private/ink/${FILE}" COPYONLY) +configure_file("avl_array.h" + "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/ThirdParty/Private/avl_array.h" COPYONLY) +foreach(file IN LISTS SOURCES) + configure_file("${file}" "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/inkcpp/Private/ink/${file}" + COPYONLY) endforeach() -foreach(FILE IN LISTS PUBLIC_HEADERS) - get_filename_component(FILE "${FILE}" NAME) - configure_file("include/${FILE}" "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/inkcpp/Public/ink/${FILE}" COPYONLY) +foreach(file IN LISTS PUBLIC_HEADERS) + get_filename_component(file "${file}" NAME) + configure_file("include/${file}" + "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/inkcpp/Public/ink/${FILE}" COPYONLY) endforeach() -foreach(FILE IN LISTS COLLECTION_SOURCES) - configure_file("${FILE}" "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/inkcpp/Private/ink/${FILE}" COPYONLY) +foreach(file IN LISTS COLLECTION_SOURCES) + configure_file("${file}" "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/inkcpp/Private/ink/${file}" + COPYONLY) endforeach() diff --git a/inkcpp/include/list.h b/inkcpp/include/list.h index 910a94f2..7a3ee7ee 100644 --- a/inkcpp/include/list.h +++ b/inkcpp/include/list.h @@ -12,7 +12,7 @@ # include #endif -#ifdef INK_BUILD_CLIB +#ifdef INKCPP_BUILD_CLIB struct InkListIter; struct HInkList; int ink_list_flags(const HInkList*, InkListIter*); @@ -61,7 +61,7 @@ class list_interface int _i; bool _one_list_iterator; ///< iterates only though values of one list friend list_interface; -#ifdef INK_BUILD_CLIB +#ifdef INKCPP_BUILD_CLIB friend int ::ink_list_flags(const HInkList*, InkListIter*); friend int ::ink_list_flags_from(const HInkList*, const char*, InkListIter*); friend int ::ink_list_iter_next(InkListIter* self); diff --git a/inkcpp/include/runner.h b/inkcpp/include/runner.h index f9a647b4..c48a8797 100644 --- a/inkcpp/include/runner.h +++ b/inkcpp/include/runner.h @@ -83,7 +83,6 @@ class runner_interface */ virtual snapshot* create_snapshot() const = 0; -#ifdef INK_ENABLE_CSTD /** * Continue execution until the next newline, then allocate a c-style * string with the output. This allocated string is managed by the runtime @@ -93,7 +92,6 @@ class runner_interface * @return allocated c-style string with the output of a single line of execution */ virtual const char* getline_alloc() = 0; -#endif #if defined(INK_ENABLE_STL) || defined(INK_ENABLE_UNREAL) /** diff --git a/inkcpp/include/story.h b/inkcpp/include/story.h index cc696fb7..06591779 100644 --- a/inkcpp/include/story.h +++ b/inkcpp/include/story.h @@ -27,79 +27,79 @@ class story public: virtual ~story(){}; #pragma region Interface Methods - /** - * Creates a new global store - * - * Creates a new global store that can be passed in when - * creating new runners for this story. Note: Can not be - * used for other stories. It is tied to this story. - * - * @return managed pointer to a new global store - */ - virtual globals new_globals() = 0; - /** Reconstructs globals from snapshot - * @param obj snapshot to load - */ - virtual globals new_globals_from_snapshot(const snapshot& obj) = 0; + /** + * Creates a new global store + * + * Creates a new global store that can be passed in when + * creating new runners for this story. Note: Can not be + * used for other stories. It is tied to this story. + * + * @return managed pointer to a new global store + */ + virtual globals new_globals() = 0; + /** Reconstructs globals from snapshot + * @param obj snapshot to load + */ + virtual globals new_globals_from_snapshot(const snapshot& obj) = 0; - /** - * Creates a new runner - * - * Creates a new runner whose initial instruction pointer - * is the first instruction in this story. If no global - * store is passed, a new one will be created for the runner. - * - * @param store globals to use for the runner - * @return managed pointer to a new runner - */ - virtual runner new_runner(globals store = nullptr) = 0; - /** - * @brief reconstruct runner from a snapshot - * @attention runner must be snap_shotted from the same story - * @attention if globals is explicit set, - * make sure the globals are from the same snapshot as - * @attention if you snap_shotted a multiple runner with shared global - * please reconstruct it in the same fashion - * @param obj - * @param store can be set if explicit access to globals is required or multiple runner with a - * shared global are used - * @param runner_id if the snapshot was of a multiple runner one global situation load first the - * global, and then each runner with global set and increasing idx - */ - virtual runner new_runner_from_snapshot( - const snapshot& obj, globals store = nullptr, unsigned runner_id = 0 - ) = 0; + /** + * Creates a new runner + * + * Creates a new runner whose initial instruction pointer + * is the first instruction in this story. If no global + * store is passed, a new one will be created for the runner. + * + * @param store globals to use for the runner + * @return managed pointer to a new runner + */ + virtual runner new_runner(globals store = nullptr) = 0; + /** + * @brief reconstruct runner from a snapshot + * @attention runner must be snap_shotted from the same story + * @attention if globals is explicit set, + * make sure the globals are from the same snapshot as + * @attention if you snap_shotted a multiple runner with shared global + * please reconstruct it in the same fashion + * @param obj + * @param store can be set if explicit access to globals is required or multiple runner with a + * shared global are used + * @param runner_id if the snapshot was of a multiple runner one global situation load first the + * global, and then each runner with global set and increasing idx + */ + virtual runner + new_runner_from_snapshot(const snapshot& obj, globals store = nullptr, unsigned runner_id = 0) + = 0; #pragma endregion #pragma region Factory Methods - /** - * Creates a new story object from a file. - * - * Requires STL or other extension which allows files - * to be loaded and read. Will allocate all the data - * necessary to load the file and close it. - * - * @param filename filename of the binary ink data - * @return new story object - */ - static story* from_file(const char* filename); + /** + * Creates a new story object from a file. + * + * Requires STL or other extension which allows files + * to be loaded and read. Will allocate all the data + * necessary to load the file and close it. + * + * @param filename filename of the binary ink data + * @return new story object + */ + static story* from_file(const char* filename); - /** - * Create a new story object from binary buffer - * - * No extensions required. Creates the story from binary - * data already loaded into memory. By default, the story - * will free this buffer when it is destroyed. - * - * @param data binary data - * @param length of the binary data in bytes - * @param freeOnDestroy if true, free this buffer once the story is destroyed - * @return new story object - */ - static story* from_binary(unsigned char* data, size_t length, bool freeOnDestroy = true); + /** + * Create a new story object from binary buffer + * + * No extensions required. Creates the story from binary + * data already loaded into memory. By default, the story + * will free this buffer when it is destroyed. + * + * @param data binary data + * @param length of the binary data in bytes + * @param freeOnDestroy if true, free this buffer once the story is destroyed + * @return new story object + */ + static story* from_binary(const unsigned char* data, size_t length, bool freeOnDestroy = true); #pragma endregion }; -} +} // namespace ink::runtime /** @namespace ink * Namespace contaning all modules and classes from InkCPP diff --git a/inkcpp/runner_impl.cpp b/inkcpp/runner_impl.cpp index 8c459096..68d389e4 100644 --- a/inkcpp/runner_impl.cpp +++ b/inkcpp/runner_impl.cpp @@ -15,11 +15,12 @@ #include "system.h" #include "value.h" -#include -#include +#ifdef INK_ENABLE_STL +# include namespace ink::runtime { +#ifdef INK_ENABLE_STL static void write_hash(std::ostream& out, ink::hash_t value) { using namespace std; @@ -28,6 +29,7 @@ static void write_hash(std::ostream& out, ink::hash_t value) out << "0x" << hex << setfill('0') << setw(8) << static_cast(value); out.flags(state); } +#endif const choice* runner_interface::get_choice(size_t index) const { @@ -472,7 +474,11 @@ runner_impl::runner_impl(const story_impl* data, globals global) , _choices() , _tags_begin(0, ~0) , _container(ContainerData{}) +#ifdef INK_ENABLE_CSTD , _rng(static_cast(time(NULL))) +#else + , _rng() +#endif { @@ -711,7 +717,6 @@ const unsigned char* runner_impl::snap_load(const unsigned char* data, loader& l return ptr; } -#ifdef INK_ENABLE_CSTD const char* runner_impl::getline_alloc() { advance_line(); @@ -722,7 +727,6 @@ const char* runner_impl::getline_alloc() inkAssert(_output.is_empty(), "Output should be empty after getline!"); return res; } -#endif bool runner_impl::move_to(hash_t path) { diff --git a/inkcpp/runner_impl.h b/inkcpp/runner_impl.h index 0d5359a3..aed0c91e 100644 --- a/inkcpp/runner_impl.h +++ b/inkcpp/runner_impl.h @@ -124,10 +124,8 @@ class runner_impl size_t snap(unsigned char* data, snapper&) const; const unsigned char* snap_load(const unsigned char* data, loader&); -#ifdef INK_ENABLE_CSTD // c-style getline virtual const char* getline_alloc() override; -#endif // move to path virtual bool move_to(hash_t path) override; diff --git a/inkcpp/story_impl.cpp b/inkcpp/story_impl.cpp index 3f58d42f..becc06f5 100644 --- a/inkcpp/story_impl.cpp +++ b/inkcpp/story_impl.cpp @@ -19,7 +19,7 @@ namespace ink::runtime story* story::from_file(const char* filename) { return new internal::story_impl(filename); } #endif -story* story::from_binary(unsigned char* data, size_t length, bool freeOnDestroy) +story* story::from_binary(const unsigned char* data, size_t length, bool freeOnDestroy) { return new internal::story_impl(data, length, freeOnDestroy); } @@ -35,9 +35,7 @@ unsigned char* read_file_into_memory(const char* filename, size_t* read) ifstream ifs(filename, ios::binary | ios::ate); - if (! ifs.is_open()) { - ink_assert(false, "Failed to open file: %s", filename); - } + inkAssert(ifs.is_open(), "Failed to open file: " FORMAT_STRING_STR, filename); ifstream::pos_type pos = ifs.tellg(); size_t length = ( size_t ) pos; @@ -69,7 +67,7 @@ story_impl::story_impl(const char* filename) } #endif -story_impl::story_impl(unsigned char* binary, size_t len, bool manage /*= true*/) +story_impl::story_impl(const unsigned char* binary, size_t len, bool manage /*= true*/) : _file(binary) , _length(len) , _managed(manage) @@ -269,7 +267,7 @@ runner story_impl::new_runner_from_snapshot(const snapshot& data, globals store, void story_impl::setup_pointers() { using header = ink::internal::header; - _header = header::parse_header(reinterpret_cast(_file)); + _header = header::parse_header(reinterpret_cast(_file)); // String table is after the header _string_table = ( char* ) _file + header::Size; diff --git a/inkcpp/story_impl.h b/inkcpp/story_impl.h index e8cc1217..83dd37cb 100644 --- a/inkcpp/story_impl.h +++ b/inkcpp/story_impl.h @@ -25,7 +25,7 @@ class story_impl : public story #endif // Create story from allocated binary data in memory. If manage is true, this class will delete // the pointers on destruction - story_impl(unsigned char* binary, size_t len, bool manage = true); + story_impl(const unsigned char* binary, size_t len, bool manage = true); virtual ~story_impl(); const char* string(uint32_t index) const; @@ -65,8 +65,8 @@ class story_impl : public story private: // file information - unsigned char* _file; - size_t _length; + const unsigned char* _file; + size_t _length; ink::internal::header _header; diff --git a/inkcpp/string_utils.h b/inkcpp/string_utils.h index 295389a0..7f056fe1 100644 --- a/inkcpp/string_utils.h +++ b/inkcpp/string_utils.h @@ -10,8 +10,6 @@ #include "traits.h" #include "value.h" -#include - #ifndef EINVAL # define EINVAL -1 #endif @@ -58,13 +56,6 @@ inline int toStr(char* buffer, size_t size, int32_t value) // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/gcvt-s?view=msvc-160 inline int toStr(char* buffer, size_t size, float value) { -#ifdef WIN32 - int digits = 7; - for (float f = value; f > 1.f; f /= 10.f) { - ++digits; - } - int ec = _gcvt_s(buffer, size, value, digits); // number of significant digits -#else if (buffer == nullptr || size < 1) { return EINVAL; } @@ -73,8 +64,7 @@ inline int toStr(char* buffer, size_t size, float value) return EINVAL; } // trunc cat zeros B007 - int ec = 0; -#endif + int ec = 0; char* itr = buffer + strlen(buffer) - 1; while (*itr == '0') { *itr-- = 0; @@ -185,6 +175,11 @@ inline constexpr const char* str_find(const char* str, char c) return nullptr; } +inline constexpr bool isspace(int c) +{ + return c == ' ' || c == '\t' || c == '\v' || c == '\n' || c == '\f' || c == '\r'; +} + /** removes leading & tailing spaces as wide spaces * @param begin iterator of string * @param end iterator of string diff --git a/inkcpp/value.h b/inkcpp/value.h index aef705da..38995dc2 100644 --- a/inkcpp/value.h +++ b/inkcpp/value.h @@ -14,7 +14,6 @@ #include "system.h" #include "command.h" #include "list_table.h" -#include "snapshot_impl.h" #include "tuple.hpp" #include "types.h" @@ -185,8 +184,9 @@ class value : public snapshot_interface } else if (ty != type()) { return redefine(oth, env); } else { - return internal::redefine::type, tuple>(env - )(get(), oth.get()); + return internal::redefine::type, tuple>(env)( + get(), oth.get() + ); } } diff --git a/inkcpp_c/CMakeLists.txt b/inkcpp_c/CMakeLists.txt index 49f5bbbc..0d3c0704 100644 --- a/inkcpp_c/CMakeLists.txt +++ b/inkcpp_c/CMakeLists.txt @@ -1,62 +1,66 @@ -add_library(inkcpp_c inkcpp.cpp - $ - $ ) -target_include_directories(inkcpp_c PUBLIC - $ - $ -) -target_include_directories(inkcpp_c PUBLIC - $ - $ - $ - $ -) +add_library(inkcpp_c inkcpp.cpp $) +target_include_directories(inkcpp_c PUBLIC $ + $) +target_include_directories( + inkcpp_c + PUBLIC $ + $ $) set_target_properties(inkcpp_c PROPERTIES PUBLIC_HEADER "include/inkcpp.h") target_link_libraries(inkcpp_c PRIVATE inkcpp_shared) -target_compile_definitions(inkcpp_c PRIVATE INK_BUILD_CLIB) +target_compile_definitions(inkcpp_c PRIVATE INKCPP_BUILD_CLIB INKCPP_NO_EXCEPTIONS INKCPP_NO_RTTI) -install(TARGETS inkcpp_c - EXPORT inkcppTarget - ARCHIVE DESTINATION "lib/ink" - COMPONENT lib EXCLUDE_FROM_ALL - PUBLIC_HEADER DESTINATION "include/ink/c" - COMPONENT lib EXCLUDE_FROM_ALL -) +install( + TARGETS inkcpp_c + EXPORT inkcppTarget + ARCHIVE DESTINATION "lib/ink" + COMPONENT lib + EXCLUDE_FROM_ALL + PUBLIC_HEADER + DESTINATION "include/ink/c" + COMPONENT lib + EXCLUDE_FROM_ALL) -install(TARGETS inkcpp_c inkcpp_shared - EXPORT inkcpp_cTarget - ARCHIVE DESTINATION "lib/ink" - COMPONENT clib EXCLUDE_FROM_ALL - PUBLIC_HEADER DESTINATION "include/ink/" - COMPONENT clib EXCLUDE_FROM_ALL) +install( + TARGETS inkcpp_c inkcpp_shared + EXPORT inkcpp_cTarget + ARCHIVE DESTINATION "lib/ink" + COMPONENT clib + EXCLUDE_FROM_ALL + PUBLIC_HEADER + DESTINATION "include/ink/" + COMPONENT clib + EXCLUDE_FROM_ALL) include(CMakePackageConfigHelpers) -configure_package_config_file(${PROJECT_SOURCE_DIR}/Config.cmake.in - "${CMAKE_CURRENT_BINARY_DIR}/inkcppConfig.cmake" - INSTALL_DESTINATION "lib/cmake/inkcpp" - NO_SET_AND_CHECK_MACRO - NO_CHECK_REQUIRED_COMPONENTS_MACRO) +configure_package_config_file( + ${PROJECT_SOURCE_DIR}/Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/inkcppConfig.cmake" + INSTALL_DESTINATION "lib/cmake/inkcpp" + NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/inkcppConfigVersion.cmake" - VERSION "${inkcpp_VERSION_MAJOR}.${inkcpp_VERSION_MINOR}" - COMPATIBILITY AnyNewerVersion) -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/inkcppConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/inkcppConfigVersion.cmake - DESTINATION lib/cmake/inkcpp COMPONENT clib EXCLUDE_FROM_ALL) -export(EXPORT inkcpp_cTarget - FILE "${CMAKE_CURRENT_BINARY_DIR}/inkcppTargets.cmake") -install(EXPORT inkcpp_cTarget - FILE inkcppTargets.cmake DESTINATION "lib/cmake/inkcpp" - COMPONENT clib EXCLUDE_FROM_ALL) + "${CMAKE_CURRENT_BINARY_DIR}/inkcppConfigVersion.cmake" + VERSION "${inkcpp_VERSION_MAJOR}.${inkcpp_VERSION_MINOR}" + COMPATIBILITY AnyNewerVersion) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/inkcppConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/inkcppConfigVersion.cmake + DESTINATION lib/cmake/inkcpp + COMPONENT clib + EXCLUDE_FROM_ALL) +export(EXPORT inkcpp_cTarget FILE "${CMAKE_CURRENT_BINARY_DIR}/inkcppTargets.cmake") +install( + EXPORT inkcpp_cTarget + FILE inkcppTargets.cmake + DESTINATION "lib/cmake/inkcpp" + COMPONENT clib + EXCLUDE_FROM_ALL) # configure in two steps to get the current installation prefix set(PREFIX "@PREFIX@") -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/inkcpp_c.pc.in - ${CMAKE_BINARY_DIR}/inkcpp_c.pc.in - @ONLY) -install(CODE [[ - get_filename_component(PREFIX ${CMAKE_INSTALL_PREFIX} ABSOLUTE) - configure_file(inkcpp_c.pc.in ${PREFIX}/lib/pkgconfig/inkcpp.pc @ONLY) - ]] COMPONENT clib EXCLUDE_FROM_ALL) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/inkcpp_c.pc.in ${CMAKE_BINARY_DIR}/inkcpp_c.pc.in @ONLY) +install( + CODE [[ + get_filename_component(PREFIX ${CMAKE_INSTALL_PREFIX} ABSOLUTE) + configure_file(inkcpp_c.pc.in ${PREFIX}/lib/pkgconfig/inkcpp.pc @ONLY) + ]] + COMPONENT clib + EXCLUDE_FROM_ALL) diff --git a/inkcpp_c/include/inkcpp.h b/inkcpp_c/include/inkcpp.h index eb16edd4..7725de87 100644 --- a/inkcpp_c/include/inkcpp.h +++ b/inkcpp_c/include/inkcpp.h @@ -67,18 +67,35 @@ typedef struct HInkSTory HInkStory; struct HInkSnapshot; /** @memberof HInkSnapshot * @copydoc ink::runtime::snapshot::from_file() + * @attention only supported if build with STL libraries. + * @sa ink_snapshot_from_binary() */ HInkSnapshot* ink_snapshot_from_file(const char* filename); + /** @memberof HInkSnapshot + * @copydoc ink::runtime::snapshot::from_binary() + */ + HInkSnapshot* + ink_snapshot_from_binary(const unsigned char* data, size_t length, bool freeOnDestroy); /** @memberof HInkSnapshot * @copydoc ink::runtime::snapshot::num_runners() * @param self */ - int ink_snapshot_num_runners(const HInkSnapshot* self); + int ink_snapshot_num_runners(const HInkSnapshot* self); /** @memberof HInkSnapshot * @copydoc ink::runtime::snapshot::write_to_file() * @param self + * @attention only supported if build with STL libraries. + * @sa ink_snapshot_get_binary() + */ + void ink_snapshot_write_to_file(const HInkSnapshot* self, const char* filename); + /** @memberof HInkSnapshot + * @param self + * @param[out] data pointer to snapshot data + * @param[out] data_length length of snapshot data */ - void ink_snapshot_write_to_file(const HInkSnapshot* self, const char* filename); + void ink_snapshot_get_binary( + const HInkSnapshot* self, const unsigned char** data, size_t* data_length + ); /** @class HInkChoice * @ingroup clib @@ -381,9 +398,15 @@ typedef struct HInkSTory HInkStory; */ struct HInkStory; /** @memberof HInkStory - * @copydoc ink::runtime::story::from_file + * @copydoc ink::runtime::story::from_file() + * @attention only supported if build with STL libraries. + * @sa ink_story_from_binary() */ HInkStory* ink_story_from_file(const char* filename); + /** @memberof HInkStory + * @copydoc ink::runtime::story::from_binary() + */ + HInkStory* ink_story_from_binary(const unsigned char* data, size_t length, bool freeOnDestroy); /** @memberof HInkStory * deletes a story and all assoziated resources * @param self diff --git a/inkcpp_c/inkcpp.cpp b/inkcpp_c/inkcpp.cpp index c12ea018..d0073e02 100644 --- a/inkcpp_c/inkcpp.cpp +++ b/inkcpp_c/inkcpp.cpp @@ -1,17 +1,21 @@ #include "inkcpp.h" +#include "include/inkcpp.h" #include "list.h" #include "system.h" #include "types.h" -#include +#ifdef INK_ENABLE_CSTD +# include +# include +# include +#endif + -#include #include #include #include #include #include -#include using namespace ink::runtime; @@ -64,19 +68,78 @@ value inkvar_from_c(InkValue& val) } extern "C" { - HInkSnapshot* ink_snapshot_from_file(const char* filename) +#ifdef INK_ENABLE_CSTD + HInkStory* ink_story_from_file(const char* filename) { - return reinterpret_cast(snapshot::from_file(filename)); + FILE* file = fopen(filename, "rb"); + fseek(file, 0, SEEK_END); + long file_length = ftell(file); + fseek(file, 0, SEEK_SET); + unsigned char* data = static_cast(malloc(file_length)); + inkAssert(data, "Malloc of size %u failed", file_length); + unsigned length = fread_s(data, file_length, 1, file_length, file); + inkAssert( + file_length == length, "Expected to read file of size %u, but only read %u", file_length, + length + ); + fclose(file); + return reinterpret_cast(story::from_binary(data, file_length)); } - int ink_snapshot_num_runners(const HInkSnapshot* self) + HInkSnapshot* ink_snapshot_from_file(const char* filename) { - return reinterpret_cast(self)->num_runners(); + FILE* file = fopen(filename, "rb"); + fseek(file, 0, SEEK_END); + long file_length = ftell(file); + fseek(file, 0, SEEK_SET); + unsigned char* data = static_cast(malloc(file_length)); + inkAssert(data, "Malloc of size %u failed", file_length); + unsigned length = fread_s(data, file_length, sizeof(unsigned char), file_length, file); + inkAssert( + file_length == length, "Expected to read file of size %u, but only read %u", file_length, + length + ); + fclose(file); + return reinterpret_cast(snapshot::from_binary(data, file_length)); } void ink_snapshot_write_to_file(const HInkSnapshot* self, const char* filename) { - reinterpret_cast(self)->write_to_file(filename); + FILE* file = fopen(filename, "wb"); + const snapshot& snap = *reinterpret_cast(self); + unsigned length = fwrite(snap.get_data(), sizeof(unsigned char), snap.get_data_len(), file); + inkAssert( + length == snap.get_data_len(), + "Snapshot write failed, snapshot of size %u, but only %u bytes where written.", + snap.get_data_len(), length + ); + fclose(file); + } +#endif + + HInkStory* ink_story_from_binary(const unsigned char* data, size_t length, bool freeOnDestroy) + { + return reinterpret_cast(story::from_binary(data, length, freeOnDestroy)); + } + + HInkSnapshot* + ink_snapshot_from_binary(const unsigned char* data, size_t length, bool freeOnDestroy) + { + return reinterpret_cast(snapshot::from_binary(data, length, freeOnDestroy)); + } + + void ink_snapshot_get_binary( + const HInkSnapshot* self, const unsigned char** data, size_t* data_length + ) + { + const snapshot& snap = *reinterpret_cast(self); + *data = snap.get_data(); + *data_length = snap.get_data_len(); + } + + int ink_snapshot_num_runners(const HInkSnapshot* self) + { + return reinterpret_cast(self)->num_runners(); } const char* ink_choice_text(const HInkChoice* self) @@ -303,11 +366,6 @@ extern "C" { return reinterpret_cast(self)->get()->set(variable_name, inkvar_from_c(val)); } - HInkStory* ink_story_from_file(const char* filename) - { - return reinterpret_cast(story::from_file(filename)); - } - void ink_story_delete(HInkStory* self) { delete reinterpret_cast(self); } HInkRunner* ink_story_new_runner(HInkStory* self, HInkGlobals* global_store) @@ -349,20 +407,4 @@ extern "C" { )) ); } - - void ink_compile_json(const char* input_filename, const char* output_filename, const char** error) - { - ink::compiler::compilation_results result; - ink::compiler::run(input_filename, output_filename, &result); - if (error != nullptr && ! result.errors.empty() || ! result.warnings.empty()) { - std::string str{}; - for (auto& warn : result.warnings) { - str += "WARNING: " + warn + '\n'; - } - for (auto& err : result.errors) { - str += "ERROR: " + err + '\n'; - } - *error = strdup(str.c_str()); - } - } } diff --git a/inkcpp_cl/CMakeLists.txt b/inkcpp_cl/CMakeLists.txt index eea6a759..f10455ad 100644 --- a/inkcpp_cl/CMakeLists.txt +++ b/inkcpp_cl/CMakeLists.txt @@ -1,4 +1,8 @@ # Create executable +if(INKCPP_NO_STL) + message(WARNING "Will not build CL because") + return() +endif() add_executable(inkcpp_cl inkcpp_cl.cpp test.h test.cpp) # Include compiler and runtime libraries @@ -6,44 +10,59 @@ target_link_libraries(inkcpp_cl PUBLIC inkcpp inkcpp_compiler inkcpp_shared) # For https://en.cppreference.com/w/cpp/filesystem#Notes if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.1") - target_link_libraries(inkcpp_cl PRIVATE stdc++fs) - endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.1") + target_link_libraries(inkcpp_cl PRIVATE stdc++fs) + endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0") - target_link_libraries(inkcpp_cl PRIVATE stdc++fs) - endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0") + target_link_libraries(inkcpp_cl PRIVATE stdc++fs) + endif() endif() # Install -install(TARGETS inkcpp_cl DESTINATION . COMPONENT cl EXCLUDE_FROM_ALL) +install( + TARGETS inkcpp_cl + DESTINATION . + COMPONENT cl + EXCLUDE_FROM_ALL) string(TOUPPER "${INKCPP_INKLECATE}" inkcpp_inklecate_upper) -unset(inklecate_dir) +unset(INKLECATE_DIR) if((inkcpp_inklecate_upper STREQUAL "ALL") OR (inkcpp_inklecate_upper STREQUAL "OS")) - if(UNIX AND NOT APPLE) - FetchContent_GetProperties(inklecate_linux) - if(inklecate_linux_POPULATED) - set(inklecate_dir "${inklecate_linux_SOURCE_DIR}") - else() - message(WARNING "Inklecate for this OS was not downloaded successfully, and will therfore not be packat with cl") - endif(inklecate_linux_POPULATED) - elseif(APPLE) - if(inklecate_mac_POPULATED) - set(inklecate_dir "${inklecate_mac_SOURCE_DIR}") - else() - message(WARNING "Inklecate for this OS was not downloaded successfully, and will therfore not be packat with cl") - endif(inklecate_mac_POPULATED) - elseif(MSYS OR MINGW OR WIN32 OR CYGWIN) - if(inklecate_windows_POPULATED) - set(inklecate_dir "${inklecate_windows_SOURCE_DIR}") - else() - message(WARNING "Inklecate for this OS was not downloaded successfully, and will therfore not be packat with cl") - endif(inklecate_windows_POPULATED) - else() - message(WARNING "Failed to determine OS for bundling inklecate with command line application!") - endif() - if(inklecate_dir) - file(GLOB inklecate_files "${inklecate_dir}/*") - install(FILES ${inklecate_files} DESTINATION . COMPONENT cl EXCLUDE_FROM_ALL) - endif(inklecate_dir) + if(UNIX AND NOT APPLE) + FetchContent_GetProperties(inklecate_linux) + if(inklecate_linux_POPULATED) + set(INKLECATE_DIR "${inklecate_linux_SOURCE_DIR}") + else() + message(WARNING "Inklecate for this OS was not downloaded successfully, \ + and will therfore not be packat with cl") + endif(inklecate_linux_POPULATED) + elseif(APPLE) + if(inklecate_mac_POPULATED) + set(INKLECATE_DIR "${inklecate_mac_SOURCE_DIR}") + else() + message(WARNING "Inklecate for this OS was not downloaded successfully, \ + and will therfore not be packat with cl") + endif(inklecate_mac_POPULATED) + elseif( + MSYS + OR MINGW + OR WIN32 + OR CYGWIN) + if(inklecate_windows_POPULATED) + set(INKLECATE_DIR "${inklecate_windows_SOURCE_DIR}") + else() + message(WARNING "Inklecate for this OS was not downloaded successfully, \ + and will therfore not be packat with cl") + endif(inklecate_windows_POPULATED) + else() + message(WARNING "Failed to determine OS for bundling inklecate with command line application!") + endif() + if(INKLECATE_DIR) + file(GLOB inklecate_files "${INKLECATE_DIR}/*") + install( + FILES ${inklecate_files} + DESTINATION . + COMPONENT cl + EXCLUDE_FROM_ALL) + endif(INKLECATE_DIR) endif((inkcpp_inklecate_upper STREQUAL "ALL") OR (inkcpp_inklecate_upper STREQUAL "OS")) diff --git a/inkcpp_compiler/json_compiler.cpp b/inkcpp_compiler/json_compiler.cpp index 51de770c..e6550f0e 100644 --- a/inkcpp_compiler/json_compiler.cpp +++ b/inkcpp_compiler/json_compiler.cpp @@ -411,9 +411,7 @@ void json_compiler::compile_complex_command(const nlohmann::json& command) else if (get(command, "#", val)) { if (_ink_version > 20) { - throw ink_exception( - "with inkVerison 21 the tag system chages, and the '#: ' is deprecated now" - ); + inkFail("with inkVerison 21 the tag system chages, and the '#: ' is deprecated now"); } _emitter->write_string(Command::TAG, CommandFlag::NO_FLAGS, val); } diff --git a/inkcpp_test/CMakeLists.txt b/inkcpp_test/CMakeLists.txt index 1a628535..172cb84a 100644 --- a/inkcpp_test/CMakeLists.txt +++ b/inkcpp_test/CMakeLists.txt @@ -1,119 +1,136 @@ -add_executable(inkcpp_test catch.hpp Main.cpp - Array.cpp - Pointer.cpp - Stack.cpp - Callstack.cpp - Restorable.cpp - Value.cpp - Globals.cpp - Lists.cpp - Tags.cpp - NewLines.cpp - FallbackFunction.cpp - LabelCondition.cpp - Observer.cpp - InkyJson.cpp - SpaceAfterBracketChoice.cpp - ThirdTierChoiceAfterBrackets.cpp - NoEarlyTags.cpp - ExternalFunctionsExecuteProperly.cpp +if(INKCPP_NO_STL) + message(FATAL_ERROR "Can not build tests without STL support, please disable INKCPP_TEST") +endif() +add_executable( + inkcpp_test + catch.hpp + Main.cpp + Array.cpp + Pointer.cpp + Stack.cpp + Callstack.cpp + Restorable.cpp + Value.cpp + Globals.cpp + Lists.cpp + Tags.cpp + NewLines.cpp + FallbackFunction.cpp + LabelCondition.cpp + Observer.cpp + InkyJson.cpp + SpaceAfterBracketChoice.cpp + ThirdTierChoiceAfterBrackets.cpp + NoEarlyTags.cpp + ExternalFunctionsExecuteProperly.cpp ExternalFunctionTypes.cpp - LookaheadSafe.cpp - EmptyStringForDivert.cpp - MoveTo.cpp - Fixes.cpp -) + LookaheadSafe.cpp + EmptyStringForDivert.cpp + MoveTo.cpp + Fixes.cpp) target_link_libraries(inkcpp_test PUBLIC inkcpp inkcpp_compiler inkcpp_shared) target_include_directories(inkcpp_test PRIVATE ../shared/private/) # For https://en.cppreference.com/w/cpp/filesystem#Notes if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.1") - target_link_libraries(inkcpp_test PRIVATE stdc++fs) - endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.1") + target_link_libraries(inkcpp_test PRIVATE stdc++fs) + endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0") - target_link_libraries(inkcpp_test PRIVATE stdc++fs) - endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0") + target_link_libraries(inkcpp_test PRIVATE stdc++fs) + endif() endif() add_test(NAME UnitTests COMMAND $) -if ($ENV{INKLECATE}) - set(INKLECATE_CMD $ENV{INKLECATE}) +if($ENV{INKLECATE}) + set(INKLECATE_CMD $ENV{INKLECATE}) else() - set(INKLECATE_CMD "inklecate") + set(INKLECATE_CMD "inklecate") endif() string(TOUPPER "${INKCPP_INKLECATE}" inkcpp_inklecate_upper) if((inkcpp_inklecate_upper STREQUAL "ALL") OR (inkcpp_inklecate_upper STREQUAL "OS")) - if(UNIX AND NOT APPLE) - FetchContent_GetProperties(inklecate_linux) - if(inklecate_linux_POPULATED) - set(INKLECATE_CMD "${inklecate_linux_SOURCE_DIR}/inklecate") - else() - message(FATAL_ERROR "inklecate download is not provided, please check if the download failed. - You may set INKCPP_INKLECATE=NONE and provide inkcleate via your PATH or the INKLECATE enviroment variable. - You can also disable tests altogether by setting INKCPP_TEST=OFF") - endif(inklecate_linux_POPULATED) - elseif(APPLE) - if(inklecate_mac_POPULATED) - set(INKLECATE_CMD "${inklecate_mac_SOURCE_DIR}/inklecate") - else() - message(FATAL_ERROR "inklecate download is not provided, please check if the download failed. - You may set INKCPP_INKLECATE=NONE and provide inkcleate via your PATH or the INKLECATE enviroment variable. - You can also disable tests altogether by setting INKCPP_TEST=OFF") - endif(inklecate_mac_POPULATED) - elseif(MSYS OR MINGW OR WIN32 OR CYGWIN) - if(inklecate_windows_POPULATED) - set(INKLECATE_CMD "${inklecate_windows_SOURCE_DIR}/inklecate") - else() - message(FATAL_ERROR "inklecate download is not provided, please check if the download failed. - You may set INKCPP_INKLECATE=NONE and provide inkcleate via your PATH or the INKLECATE enviroment variable. - You can also disable tests altogether by setting INKCPP_TEST=OFF") - endif(inklecate_windows_POPULATED) - else() - message(FATAL_ERROR "Current os could not be identified, therfore inklecate must be provided explicit for the tests to work - please set INKCPP_INKLECATE=NONE and provide inklecate via your PATH or the INKLECATE enviroment variables. - Alternatily disable tests by setting INKCPP_TEST=OFF.") - endif() + if(UNIX AND NOT APPLE) + FetchContent_GetProperties(inklecate_linux) + if(inklecate_linux_POPULATED) + set(INKLECATE_CMD "${inklecate_linux_SOURCE_DIR}/inklecate") + else() + message( + FATAL_ERROR + "inklecate download is not provided, please check if the download failed. + You may set INKCPP_INKLECATE=NONE and provide inkcleate via your PATH or \ + the INKLECATE enviroment variable. + You can also disable tests altogether by setting INKCPP_TEST=OFF") + endif(inklecate_linux_POPULATED) + elseif(APPLE) + if(inklecate_mac_POPULATED) + set(INKLECATE_CMD "${inklecate_mac_SOURCE_DIR}/inklecate") + else() + message( + FATAL_ERROR + "inklecate download is not provided, please check if the download failed. + You may set INKCPP_INKLECATE=NONE and provide inkcleate via your PATH or \ + the INKLECATE enviroment variable. + You can also disable tests altogether by setting INKCPP_TEST=OFF") + endif(inklecate_mac_POPULATED) + elseif( + MSYS + OR MINGW + OR WIN32 + OR CYGWIN) + if(inklecate_windows_POPULATED) + set(INKLECATE_CMD "${inklecate_windows_SOURCE_DIR}/inklecate") + else() + message( + FATAL_ERROR + "inklecate download is not provided, please check if the download failed. + You may set INKCPP_INKLECATE=NONE and provide inkcleate via your PATH or \ + the INKLECATE enviroment variable. + You can also disable tests altogether by setting INKCPP_TEST=OFF") + endif(inklecate_windows_POPULATED) + else() + message( + FATAL_ERROR + "Current os could not be identified, \ + therfore inklecate must be provided explicit for the tests to work + please set INKCPP_INKLECATE=NONE and provide inklecate via your PATH or \ + the INKLECATE enviroment variables. + Alternatily disable tests by setting INKCPP_TEST=OFF.") + endif() endif((inkcpp_inklecate_upper STREQUAL "ALL") OR (inkcpp_inklecate_upper STREQUAL "OS")) set(INK_TEST_RESOURCE_DIR "${PROJECT_BINARY_DIR}/ink") file(MAKE_DIRECTORY "${INK_TEST_RESOURCE_DIR}") -target_compile_definitions(inkcpp_test PRIVATE - INK_TEST_RESOURCE_DIR="${INK_TEST_RESOURCE_DIR}/") +target_compile_definitions(inkcpp_test PRIVATE INK_TEST_RESOURCE_DIR="${INK_TEST_RESOURCE_DIR}/") file(GLOB JSON_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ink/*.json") -file(COPY ${JSON_FILES} DESTINATION ${INK_TEST_RESOURCE_DIR}) +file(COPY ${JSON_FILES} DESTINATION ${INK_TEST_RESOURCE_DIR}) file(GLOB INK_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ink/*.ink") -foreach(INK_FILE IN LISTS INK_FILES) - get_filename_component(INK_FILENAME ${INK_FILE} NAME_WE) - set(output "${INK_TEST_RESOURCE_DIR}/${INK_FILENAME}.bin") - add_custom_command( - OUTPUT ${output} - COMMAND $ -o "${output}" --inklecate "${INKLECATE_CMD}" "${INK_FILE}" - DEPENDS ${INK_FILE} inkcpp_compiler - COMMENT "Compile test ink file '${INK_FILENAME}.ink' -> '${output}'" - ) - list(APPEND INK_OUT_FILES ${output}) +foreach(ink_file IN LISTS INK_FILES) + get_filename_component(INK_FILENAME ${ink_file} NAME_WE) + set(OUTPUT "${INK_TEST_RESOURCE_DIR}/${INK_FILENAME}.bin") + add_custom_command( + OUTPUT ${OUTPUT} + COMMAND $ -o "${OUTPUT}" --inklecate "${INKLECATE_CMD}" "${ink_file}" + DEPENDS ${ink_file} inkcpp_compiler + COMMENT "Compile test ink file '${INK_FILENAME}.ink' -> '${OUTPUT}'") + list(APPEND INK_OUT_FILES ${OUTPUT}) endforeach() target_sources(inkcpp_test PRIVATE ${INK_OUT_FILES}) if(TARGET inkcpp_c) - file(GLOB TEST_FILES "${PROJECT_SOURCE_DIR}/inkcpp_c/tests/*.c") - foreach(TEST_FILE IN LISTS TEST_FILES) - get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE) - add_executable(${TEST_NAME} ${TEST_FILE}) - target_link_libraries(${TEST_NAME} PRIVATE inkcpp_c) - target_compile_definitions(${TEST_NAME} PRIVATE - INK_TEST_RESOURCE_DIR="${INK_TEST_RESOURCE_DIR}/") - add_test( - NAME ${TEST_NAME} - COMMAND $ - ) - endforeach() + file(GLOB TEST_FILES "${PROJECT_SOURCE_DIR}/inkcpp_c/tests/*.c") + foreach(test_file IN LISTS TEST_FILES) + get_filename_component(TEST_NAME ${test_file} NAME_WE) + add_executable(${TEST_NAME} ${test_file}) + target_link_libraries(${TEST_NAME} PRIVATE inkcpp_c) + target_compile_definitions(${TEST_NAME} + PRIVATE INK_TEST_RESOURCE_DIR="${INK_TEST_RESOURCE_DIR}/") + add_test(NAME ${TEST_NAME} COMMAND $) + endforeach() endif(TARGET inkcpp_c) diff --git a/shared/public/system.h b/shared/public/system.h index 60f0fb2c..a3f5ca9f 100644 --- a/shared/public/system.h +++ b/shared/public/system.h @@ -22,11 +22,11 @@ # include # include # include -# include -# include #endif #ifdef INK_ENABLE_CSTD +# include # include +# include #endif // Platform specific defines // @@ -45,8 +45,10 @@ #else # define inkAssert ink::ink_assert # define inkFail(...) ink::ink_assert(false, __VA_ARGS__) + #endif + namespace ink { /** define basic numeric type @@ -156,21 +158,20 @@ namespace internal while (true) { switch (*(string++)) { case 0: return true; + case '\f': [[fallthrough]]; + case '\r': [[fallthrough]]; case '\n': if (! includeNewline) return false; [[fallthrough]]; case '\t': [[fallthrough]]; + case '\v': [[fallthrough]]; case ' ': continue; default: return false; } } } - - /** check if character can be only part of a word, when two part of word characters put together - * the will be a space inserted I049 - */ - static inline bool is_part_of_word(char character) + inline bool is_part_of_word(char character) { return isalpha(character) || isdigit(character); } { return isalpha(character) || isdigit(character); } @@ -197,7 +198,7 @@ namespace internal #endif } // namespace internal -#ifdef INK_ENABLE_EXCEPTIONS +#ifdef INK_ENABLE_STL /** exception type thrown if something goes wrong */ using ink_exception = std::runtime_error; #else @@ -218,7 +219,6 @@ class ink_exception #endif // assert -#ifndef INK_ENABLE_UNREAL template void ink_assert(bool condition, const char* msg = nullptr, Args... args) { @@ -227,21 +227,22 @@ void ink_assert(bool condition, const char* msg = nullptr, Args... args) msg = EMPTY; } if (! condition) { +#if defined(INKCPP_ENABLE_STL) || defined(INKCPP_ENABLE_CSTD) if constexpr (sizeof...(args) > 0) { size_t size = snprintf(nullptr, 0, msg, args...) + 1; char* message = static_cast(malloc(size)); snprintf(message, size, msg, args...); msg = message; - } -#ifdef INK_ENABLE_EXCEPTIONS - throw ink_exception(msg); -#else - fprintf(stderr, "Ink Assert: %s\n", msg); - abort(); -# endif + } else +#endif + { +# ifdef INK_ENABLE_EXCEPTIONS + throw ink_exception(msg); # else -# error "This path needs a way to warn and then terminate, otherwise it'll silently fail" + fprintf(stderr, "Ink Assert: %s\n", msg); + abort(); # endif + } } } @@ -251,7 +252,6 @@ template ink_assert(false, msg, args...); exit(EXIT_FAILURE); } -#endif namespace runtime::internal { From 97186083afd162bd5f0fb6ae4660589e849f7e87 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Tue, 6 Jan 2026 14:14:31 +0100 Subject: [PATCH 5/6] fix(NO_STD): touchups needed for rebase of current master --- inkcpp/avl_array.h | 22 +++++++++++----------- inkcpp/functional.cpp | 6 +++--- inkcpp/include/types.h | 14 ++++++++++++++ inkcpp/runner_impl.cpp | 6 ++---- inkcpp/snapshot_interface.h | 4 ++-- inkcpp_c/include/inkcpp.h | 1 + inkcpp_c/inkcpp.cpp | 4 ++-- shared/public/system.h | 32 +++++++++++++++++++++++++------- 8 files changed, 60 insertions(+), 29 deletions(-) diff --git a/inkcpp/avl_array.h b/inkcpp/avl_array.h index d3847a51..b015e517 100644 --- a/inkcpp/avl_array.h +++ b/inkcpp/avl_array.h @@ -65,13 +65,13 @@ class avl_array // node storage, due to possible structure packing effects, single arrays are used instead of a // 'node' structure - ink::runtime::internal::if_t key_; - ink::runtime::internal::if_t val_; - ink::runtime::internal::if_t balance_; - ink::runtime::internal::if_t child_; - size_type size_; // actual size - size_type _capacity; - size_type root_; // root node + ink::runtime::internal::if_t key_; + ink::runtime::internal::if_t val_; + ink::runtime::internal::if_t balance_; + ink::runtime::internal::if_t child_; + size_type size_; // actual size + size_type _capacity; + size_type root_; // root node ink::runtime::internal::if_t parent_; // invalid index (like 'nullptr' in a pointer implementation) @@ -197,7 +197,7 @@ class avl_array if constexpr (dynamic) { key_ = new Key[Size]; val_ = new T[Size]; - balance_ = new std::int8_t[Size]; + balance_ = new char[Size]; child_ = new child_type[Size]; if constexpr (Fast) { parent_ = new size_type[Size]; @@ -285,7 +285,7 @@ class avl_array val_ = new_data; } { - std::int8_t* new_data = new std::int8_t[new_size]; + char* new_data = new char[new_size]; for (size_type i = 0; i < _capacity; ++i) { new_data[i] = balance_[i]; } @@ -660,7 +660,7 @@ class avl_array set_parent(target, get_parent(source)); } - void insert_balance(size_type node, std::int8_t balance) + void insert_balance(size_type node, char balance) { while (node != INVALID_IDX) { balance = (balance_[node] += balance); @@ -691,7 +691,7 @@ class avl_array } } - void delete_balance(size_type node, std::int8_t balance) + void delete_balance(size_type node, char balance) { while (node != INVALID_IDX) { balance = (balance_[node] += balance); diff --git a/inkcpp/functional.cpp b/inkcpp/functional.cpp index 8ed82ea6..735e7fe7 100644 --- a/inkcpp/functional.cpp +++ b/inkcpp/functional.cpp @@ -33,21 +33,21 @@ int32_t function_base::pop(basic_eval_stack* stack, list_table&) } template<> -uint32_t function_base::pop(basic_eval_stack* stack, list_table& lists) +uint32_t function_base::pop(basic_eval_stack* stack, list_table&) { value val = stack->pop(); return casting::numeric_cast(val); } template<> -bool function_base::pop(basic_eval_stack* stack, list_table& lists) +bool function_base::pop(basic_eval_stack* stack, list_table&) { value val = stack->pop(); return casting::numeric_cast(val) != 0; } template<> -float function_base::pop(basic_eval_stack* stack, list_table& lists) +float function_base::pop(basic_eval_stack* stack, list_table&) { value val = stack->pop(); return casting::numeric_cast(val); diff --git a/inkcpp/include/types.h b/inkcpp/include/types.h index 8183e6c2..c771cb1a 100644 --- a/inkcpp/include/types.h +++ b/inkcpp/include/types.h @@ -113,6 +113,20 @@ struct value { } } + constexpr value& operator=(const value& v) + { + type = v.type; + switch (type) { + case Type::Bool: v_bool = v.v_bool; break; + case Type::Uint32: v_uint32 = v.v_uint32; break; + case Type::Int32: v_int32 = v.v_int32; break; + case Type::String: v_string = v.v_string; break; + case Type::Float: v_float = v.v_float; break; + case Type::List: v_list = v.v_list; break; + } + return *this; + } + /// @} /** Get value to corresponding type diff --git a/inkcpp/runner_impl.cpp b/inkcpp/runner_impl.cpp index 68d389e4..996eec31 100644 --- a/inkcpp/runner_impl.cpp +++ b/inkcpp/runner_impl.cpp @@ -17,6 +17,7 @@ #ifdef INK_ENABLE_STL # include +#endif namespace ink::runtime { @@ -312,11 +313,8 @@ void runner_impl::jump(ip_t dest, bool record_visits, bool track_knot_visit) container_t id; ip_t offset = nullptr; bool reversed = _ptr > dest; - - // move to destination and update container stack on the go - const ContainerData* c_iter = nullptr; // number of container which were already on the stack at current position - size_t comm_end = _container.size(); + size_t comm_end = _container.size(); iter = nullptr; while (_story->iterate_containers(iter, id, offset)) { diff --git a/inkcpp/snapshot_interface.h b/inkcpp/snapshot_interface.h index 10a1e35d..fa7f3b0f 100644 --- a/inkcpp/snapshot_interface.h +++ b/inkcpp/snapshot_interface.h @@ -22,7 +22,7 @@ class value; class snapshot_interface { public: - constexpr snapshot_interface(){}; + constexpr snapshot_interface() {}; static unsigned char* snap_write(unsigned char* ptr, const void* data, size_t length, bool write) { @@ -70,7 +70,7 @@ class snapshot_interface const char* story_string_table; const snap_tag* runner_tags = nullptr; - loader(managed_array& string_table, const char* story_sting_table) + loader(managed_array& string_table, const char* story_string_table) : string_table{string_table} , story_string_table{story_string_table} { diff --git a/inkcpp_c/include/inkcpp.h b/inkcpp_c/include/inkcpp.h index 7725de87..44ad21e1 100644 --- a/inkcpp_c/include/inkcpp.h +++ b/inkcpp_c/include/inkcpp.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/inkcpp_c/inkcpp.cpp b/inkcpp_c/inkcpp.cpp index d0073e02..3b5d85c9 100644 --- a/inkcpp_c/inkcpp.cpp +++ b/inkcpp_c/inkcpp.cpp @@ -77,7 +77,7 @@ extern "C" { fseek(file, 0, SEEK_SET); unsigned char* data = static_cast(malloc(file_length)); inkAssert(data, "Malloc of size %u failed", file_length); - unsigned length = fread_s(data, file_length, 1, file_length, file); + unsigned length = fread(data, sizeof(unsigned char), file_length, file); inkAssert( file_length == length, "Expected to read file of size %u, but only read %u", file_length, length @@ -94,7 +94,7 @@ extern "C" { fseek(file, 0, SEEK_SET); unsigned char* data = static_cast(malloc(file_length)); inkAssert(data, "Malloc of size %u failed", file_length); - unsigned length = fread_s(data, file_length, sizeof(unsigned char), file_length, file); + unsigned length = fread(data, sizeof(unsigned char), file_length, file); inkAssert( file_length == length, "Expected to read file of size %u, but only read %u", file_length, length diff --git a/shared/public/system.h b/shared/public/system.h index a3f5ca9f..f37dfce2 100644 --- a/shared/public/system.h +++ b/shared/public/system.h @@ -25,6 +25,7 @@ #endif #ifdef INK_ENABLE_CSTD # include +# include # include # include #endif @@ -171,10 +172,8 @@ namespace internal } } } + inline bool is_part_of_word(char character) { return isalpha(character) || isdigit(character); } - { - return isalpha(character) || isdigit(character); - } static inline constexpr bool is_whitespace(char character, bool includeNewline = true) { @@ -218,6 +217,16 @@ class ink_exception }; #endif +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +#else +# pragma warning(push) +# pragma warning( \ + disable : 4100, \ + justification : "dependend on rtti, exception and stl support not all arguments are needed" \ + ) +#endif // assert template void ink_assert(bool condition, const char* msg = nullptr, Args... args) @@ -233,24 +242,33 @@ void ink_assert(bool condition, const char* msg = nullptr, Args... args) char* message = static_cast(malloc(size)); snprintf(message, size, msg, args...); msg = message; - } else + } else #endif { -# ifdef INK_ENABLE_EXCEPTIONS +#ifdef INK_ENABLE_EXCEPTIONS throw ink_exception(msg); -# else +#elif defined(INK_ENABLE_CSTD) fprintf(stderr, "Ink Assert: %s\n", msg); abort(); -# endif +#else +# warning no assertion handling this could lead to invalid code paths +#endif } } } +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#else +# pragma warning(pop) +#endif template [[noreturn]] inline void ink_assert(const char* msg = nullptr, Args... args) { ink_assert(false, msg, args...); +#ifdef INK_ENABLE_CSTD exit(EXIT_FAILURE); +#endif } namespace runtime::internal From 5de3b2e8c102ee6a2028c838f289aab41297e6fa Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Sun, 11 Jan 2026 16:10:35 +0100 Subject: [PATCH 6/6] style: run clang-format --- inkcpp/snapshot_interface.h | 2 +- shared/public/config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inkcpp/snapshot_interface.h b/inkcpp/snapshot_interface.h index fa7f3b0f..660fc5a7 100644 --- a/inkcpp/snapshot_interface.h +++ b/inkcpp/snapshot_interface.h @@ -22,7 +22,7 @@ class value; class snapshot_interface { public: - constexpr snapshot_interface() {}; + constexpr snapshot_interface(){}; static unsigned char* snap_write(unsigned char* ptr, const void* data, size_t length, bool write) { diff --git a/shared/public/config.h b/shared/public/config.h index b67f43f7..76d58f42 100644 --- a/shared/public/config.h +++ b/shared/public/config.h @@ -19,7 +19,7 @@ # ifndef INKCPP_NO_STD # define INK_ENABLE_STL # define INK_ENABLE_CSTD -#endif +# endif #endif #ifndef INKCPP_NO_RTTI