diff --git a/README.md b/README.md index c973886..d0187e6 100644 --- a/README.md +++ b/README.md @@ -119,13 +119,22 @@ Type-libs in text-format follows this format. "c_includes" : ["../../tests/dl_test_included.h", ""], + // "tld_includes" is a list of other type libraries which this type library uses types from. If the types only are used as + // metadata then including the type library is enough, but if the types are used for members then the type lib c header + // also needs to be added to c_includes above. These tld_includes can be either binary or text files. + // Note that the mapping from "include path" to "what it means" is interpreted outside of DL's library, thus it doesn't + // have to be filesystem paths, it can be any string. By default the dltlc tool treats them as file paths. + "tld_includes" : [ + "to_include.bin", + ], + // A typelibrary can have any number of "enums" sections. In each of these sections enum-types are specified. // An enum is just the same thing as in c/c++ a collection of integer-values. "enums" : { // each key in "enums" declare an enum with that name, in this case an enum called "my_enum" "my_enum" : { // an enum can be declared "extern", declaring a type extern will make it NOT be generated in .h-files and - // the actual definition is expected to be found in "other ways" ( from other includes most likely ). + // the actual definition is expected to be found in "other ways" ( from other c_includes most likely ). // dl will however generate static_assert():s to check that all values are set correctly and exist. // Defaults to `false` if not set "extern" : true, diff --git a/bam.lua b/bam.lua index 19d114d..f44d08b 100755 --- a/bam.lua +++ b/bam.lua @@ -3,13 +3,14 @@ BUILD_PATH = "local" EXTERNALS_PATH = 'external' GTEST_PATH = PathJoin( EXTERNALS_PATH, 'gtest' ) -function dl_type_lib( tlc_file, dltlc, dl_tests ) +function dl_type_lib( tlc_file, dltlc, dl_tests, dependency ) local output_path = PathJoin( BUILD_PATH, 'generated' ) local out_file = PathJoin( output_path, PathFilename( PathBase( tlc_file ) ) ) - local out_header = out_file .. ".h" - local out_lib = out_file .. ".bin" - local out_lib_h = out_file .. ".bin.h" - local out_lib_txt_h = out_file .. ".txt.h" + local type_lib_outputs = {} + type_lib_outputs.out_header = out_file .. ".h" + type_lib_outputs.out_lib = out_file .. ".bin" + type_lib_outputs.out_lib_h = out_file .. ".bin.h" + type_lib_outputs.out_lib_txt_h = out_file .. ".txt.h" local BIN2HEX = _bam_exe .. " -e tool/bin2hex.lua" @@ -17,13 +18,20 @@ function dl_type_lib( tlc_file, dltlc, dl_tests ) dltlc = string.gsub( dltlc, "/", "\\" ) end - AddJob( out_lib, "tlc " .. out_lib, dltlc .. " -o " .. out_lib .. " " .. tlc_file, tlc_file ) - AddJob( out_lib_h, "tlc " .. out_lib_h, BIN2HEX .. " dst=" .. out_lib_h .. " src=" .. out_lib, out_lib ) - AddJob( out_lib_txt_h, "tlc " .. out_lib_h, BIN2HEX .. " dst=" .. out_lib_txt_h .. " src=" .. tlc_file, tlc_file ) - AddJob( out_header, "tlc " .. out_header, dltlc .. " -c -o " .. out_header .. " " .. tlc_file, tlc_file ) + AddJob( type_lib_outputs.out_lib, "tlc " .. type_lib_outputs.out_lib, dltlc .. " -o " .. type_lib_outputs.out_lib .. " " .. tlc_file, tlc_file ) + AddJob( type_lib_outputs.out_lib_h, "tlc " .. type_lib_outputs.out_lib_h, BIN2HEX .. " dst=" .. type_lib_outputs.out_lib_h .. " src=" .. type_lib_outputs.out_lib, type_lib_outputs.out_lib ) + AddJob( type_lib_outputs.out_lib_txt_h, "tlc " .. type_lib_outputs.out_lib_h, BIN2HEX .. " dst=" .. type_lib_outputs.out_lib_txt_h .. " src=" .. tlc_file, tlc_file ) + AddJob( type_lib_outputs.out_header, "tlc " .. type_lib_outputs.out_header, dltlc .. " -c -o " .. type_lib_outputs.out_header .. " " .. tlc_file, tlc_file ) AddDependency( tlc_file, dltlc ) - AddDependency( dl_tests, out_lib_h ) + if dependency then + AddDependency( tlc_file, dependency ) + end + AddDependency( dl_tests, type_lib_outputs.out_lib_h ) + AddDependency( dl_tests, type_lib_outputs.out_header ) + AddDependency( dl_tests, type_lib_outputs.out_lib_txt_h ) + + return type_lib_outputs end function DefaultSettings( platform, config, compiler ) @@ -269,13 +277,14 @@ dltlc = Link( build_settings, "dltlc", Compile( dl_settings, CollectRecurs dl_tests = Link( test_settings, "dl_tests", Compile( test_settings, Collect("tests/*.cpp") ), dl_lib, gtest_lib ) dlbench = Link( test_settings, "dlbench", Compile( test_settings, Collect("benchmark/*.cpp") ), dl_lib ) -tl1 = dl_type_lib( "tests/sized_enums.tld", dltlc, dl_tests ) -tl2 = dl_type_lib( "tests/unittest.tld", dltlc, dl_tests ) -tl3 = dl_type_lib( "tests/unittest2.tld", dltlc, dl_tests ) -tl4 = dl_type_lib( "tests/small.tld", dltlc, dl_tests ) +tl1 = dl_type_lib( "tests/to_include.tld", dltlc, dl_tests ) +tl2 = dl_type_lib( "tests/sized_enums.tld", dltlc, dl_tests ) +tl3 = dl_type_lib( "tests/unittest.tld", dltlc, dl_tests, tl1.out_lib ) +tl4 = dl_type_lib( "tests/unittest2.tld", dltlc, dl_tests, "tests/to_include.tld" ) +tl5 = dl_type_lib( "tests/small.tld", dltlc, dl_tests ) tlbench = dl_type_lib( "benchmark/dlbench.tld", dltlc, dl_tests ) -dl_test_valid_c = Compile( dl_settings, Collect( "tests/*.c" ), tl1, tl2, tl3, tl4, tlbench ) +dl_test_valid_c = Compile( dl_settings, Collect( "tests/*.c" ) ) local test_args = "" local py_test_args = "" diff --git a/include/dl/dl.h b/include/dl/dl.h old mode 100755 new mode 100644 index c14699f..e2311ec --- a/include/dl/dl.h +++ b/include/dl/dl.h @@ -87,6 +87,7 @@ typedef enum DL_NODISCARD DL_ERROR_TXT_MULTIPLE_MEMBERS_IN_UNION_SET, DL_ERROR_TYPELIB_MISSING_MEMBERS_IN_TYPE, + DL_ERROR_TYPELIB_MISSING_INCLUDE_HANDLER, DL_ERROR_UTIL_FILE_NOT_FOUND, DL_ERROR_UTIL_FILE_TYPE_MISMATCH, diff --git a/include/dl/dl_defines.h b/include/dl/dl_defines.h old mode 100755 new mode 100644 diff --git a/include/dl/dl_typelib.h b/include/dl/dl_typelib.h index 6cf05e1..95beff5 100644 --- a/include/dl/dl_typelib.h +++ b/include/dl/dl_typelib.h @@ -19,19 +19,49 @@ extern "C" { #include
+/* + Function pointer type: dl_include_handler + Is responsible for locating and loading a type-library into dl_ctx. + + Parameters: + handler_ctx - context passed in to dl_context_load_txt_type_library() + dl_ctx - dl-context to load typelib into. + include_identifier - the text given in the include, commonly a relative path but could be any string + + Return: + DL_ERROR_OK on success. + */ +typedef dl_error_t ( *dl_include_handler )( void* handler_ctx, dl_ctx_t dl_ctx, const char* include_identifier ); + +/* + Struct: dl_load_txt_type_library_params_t + Passed with configuration parameters to dl_context_load_txt_type_library. + This struct is open to change in later versions of dl. + + Members: + include_handler - a callback function which tries to load the given type library, can be nullptr + handler_ctx - this will be passed straight down to the include_handler callback +*/ +typedef struct dl_load_type_library_params_t +{ + dl_include_handler include_handler; + void* handler_ctx; +} dl_load_type_library_params_t; + /* Function: dl_context_load_txt_type_library Load type-library from text representation into dl_ctx. Parameters: - dl_ctx - dl-context to load typelib into.. + dl_ctx - dl-context to load typelib into. lib_data - pointer to loaded txt-type library to load. lib_data_size - size of string pointed to by lib_data. + load_params - optional parameters which controls how the type library is loaded. Note: This function do not have the same rules of memory allocation and might allocate memory behind the scenes. */ -dl_error_t DL_DLL_EXPORT dl_context_load_txt_type_library( dl_ctx_t dl_ctx, const char* lib_data, size_t lib_data_size ); +dl_error_t DL_DLL_EXPORT dl_context_load_txt_type_library( dl_ctx_t dl_ctx, const char* lib_data, size_t lib_data_size, const dl_load_type_library_params_t* load_params ); /* Function: dl_context_write_type_library diff --git a/src/dl.cpp b/src/dl.cpp index bb1b2d1..90511d4 100644 --- a/src/dl.cpp +++ b/src/dl.cpp @@ -593,6 +593,7 @@ const char* dl_error_to_string( dl_error_t error ) DL_ERR_TO_STR(DL_ERROR_TXT_MULTIPLE_MEMBERS_IN_UNION_SET); DL_ERR_TO_STR(DL_ERROR_TYPELIB_MISSING_MEMBERS_IN_TYPE); + DL_ERR_TO_STR(DL_ERROR_TYPELIB_MISSING_INCLUDE_HANDLER); DL_ERR_TO_STR(DL_ERROR_UTIL_FILE_NOT_FOUND); DL_ERR_TO_STR(DL_ERROR_UTIL_FILE_TYPE_MISMATCH); diff --git a/src/dl_txt_read.h b/src/dl_txt_read.h index 8f1d8b3..345c98c 100644 --- a/src/dl_txt_read.h +++ b/src/dl_txt_read.h @@ -5,6 +5,8 @@ #include #include "dl_types.h" +#include
+ struct dl_txt_read_ctx { jmp_buf jumpbuf; @@ -12,6 +14,8 @@ struct dl_txt_read_ctx const char* end; const char* iter; dl_error_t err; + dl_include_handler include_handler; + void* include_handler_ctx; }; diff --git a/src/dl_typelib_read_bin.cpp b/src/dl_typelib_read_bin.cpp index 16e880d..87eee69 100644 --- a/src/dl_typelib_read_bin.cpp +++ b/src/dl_typelib_read_bin.cpp @@ -159,18 +159,26 @@ dl_error_t dl_context_load_type_library( dl_ctx_t dl_ctx, const unsigned char* l if(dl_ctx->type_descs[ dl_ctx->type_count + i ].comment != UINT32_MAX) dl_ctx->type_descs[ dl_ctx->type_count + i ].comment += td_str_offset; dl_ctx->type_descs[ dl_ctx->type_count + i ].member_start += dl_ctx->member_count; - if( dl_ctx->type_descs[ dl_ctx->type_count + i ].metadata_start ) - dl_ctx->type_descs[ dl_ctx->type_count + i ].metadata_start += dl_ctx->metadatas_count; + dl_ctx->type_descs[ dl_ctx->type_count + i ].metadata_start += dl_ctx->metadatas_count; + + if( dl_ctx->performing_include ) + { + dl_ctx->type_descs[ dl_ctx->type_count + i ].flags |= (uint32_t)DL_TYPE_FLAG_IS_EXTERNAL; + dl_ctx->type_descs[ dl_ctx->type_count + i ].flags &= ~(uint32_t)DL_TYPE_FLAG_VERIFY_EXTERNAL_SIZE_ALIGN; + } } for( unsigned int i = 0; i < header.member_count; ++i ) { dl_ctx->member_descs[ dl_ctx->member_count + i ].name += td_str_offset; - if( dl_ctx->member_descs[dl_ctx->member_count + i].metadata_start ) - dl_ctx->member_descs[dl_ctx->member_count + i].metadata_start += dl_ctx->metadatas_count; + if( dl_ctx->member_descs[ dl_ctx->member_count + i ].metadata_start ) + dl_ctx->member_descs[ dl_ctx->member_count + i ].metadata_start += dl_ctx->metadatas_count; - if( dl_ctx->member_descs[dl_ctx->member_count + i].default_value_offset != UINT32_MAX ) - dl_ctx->member_descs[dl_ctx->member_count + i].default_value_offset += (uint32_t)dl_ctx->default_data_size; + if( dl_ctx->member_descs[ dl_ctx->member_count + i ].default_value_offset != UINT32_MAX ) + dl_ctx->member_descs[ dl_ctx->member_count + i ].default_value_offset += (uint32_t)dl_ctx->default_data_size; + + if( dl_ctx->performing_include ) + dl_ctx->member_descs[ dl_ctx->member_count + i ].flags &= ~(uint32_t)DL_MEMBER_FLAG_VERIFY_EXTERNAL_SIZE_OFFSET; } for( unsigned int i = 0; i < header.enum_count; ++i ) @@ -182,6 +190,11 @@ dl_error_t dl_context_load_type_library( dl_ctx_t dl_ctx, const unsigned char* l dl_ctx->enum_descs[ dl_ctx->enum_count + i ].alias_start += dl_ctx->enum_alias_count; if( dl_ctx->enum_descs[ dl_ctx->enum_count + i ].metadata_start ) dl_ctx->enum_descs[ dl_ctx->enum_count + i ].metadata_start += dl_ctx->metadatas_count; + if( dl_ctx->performing_include ) + { + dl_ctx->enum_descs[ dl_ctx->enum_count + i ].flags |= (uint32_t)DL_TYPE_FLAG_IS_EXTERNAL; + dl_ctx->enum_descs[ dl_ctx->enum_count + i ].flags &= ~(uint32_t)DL_TYPE_FLAG_VERIFY_EXTERNAL_SIZE_ALIGN; + } } for( unsigned int i = 0; i < header.enum_alias_count; ++i ) diff --git a/src/dl_typelib_read_txt.cpp b/src/dl_typelib_read_txt.cpp index 5343659..1f00a64 100644 --- a/src/dl_typelib_read_txt.cpp +++ b/src/dl_typelib_read_txt.cpp @@ -16,6 +16,12 @@ # define DL_CONSTANT_EXPRESSION(expr) (expr) #endif +template +static inline bool dl_streq( const char ( &s1 )[len], const char* s2 ) +{ + return strncmp( s1, s2, len - 1 ) == 0; +} + template static inline T* dl_grow_array( dl_allocator* alloc, T* ptr, size_t* cap, size_t min_inc ) { @@ -685,12 +691,12 @@ static void dl_context_load_txt_type_library_read_enum_values( dl_ctx_t ctx, dl_txt_eat_char( ctx, read_state, ':' ); - if( strncmp( "value", key.str, 5 ) == 0 ) + if( dl_streq( "value", key.str ) ) { value->value = dl_context_load_txt_type_library_read_enum_value( ctx, storage, read_state ); value_set = true; } - else if( strncmp( "aliases", key.str, 7 ) == 0 ) + else if( dl_streq( "aliases", key.str ) ) { dl_txt_eat_char( ctx, read_state, '[' ); do @@ -703,7 +709,7 @@ static void dl_context_load_txt_type_library_read_enum_values( dl_ctx_t ctx, } while( dl_txt_try_eat_char( read_state, ',' ) ); dl_txt_eat_char( ctx, read_state, ']' ); } - else if( strncmp( "comment", key.str, 7 ) == 0 ) + else if( dl_streq( "comment", key.str ) ) { if(value->comment != 0xFFFFFFFF) dl_txt_read_failed( ctx, read_state, DL_ERROR_MALFORMED_DATA, "enum value have multiple 'comment'-sections present!" ); @@ -739,12 +745,14 @@ static void dl_context_load_txt_type_library_find_enum_keys( dl_ctx_t ctx, const char** values_iter, const char** type_iter, const char** end_iter, - bool* is_extern) + bool* is_extern, + bool* verify) { *values_iter = 0x0; *type_iter = 0x0; *end_iter = 0x0; *is_extern = false; + *verify = true; dl_txt_eat_char( ctx, read_state, '{' ); do @@ -753,25 +761,29 @@ static void dl_context_load_txt_type_library_find_enum_keys( dl_ctx_t ctx, dl_txt_eat_char( ctx, read_state, ':' ); dl_txt_eat_white( read_state ); - if( strncmp( "values", key.str, 6 ) == 0 ) + if( dl_streq( "values", key.str ) ) { if(*values_iter) dl_txt_read_failed( ctx, read_state, DL_ERROR_MALFORMED_DATA, "'values' set twice on enum '%.*s'", name->len, name->str ); *values_iter = read_state->iter; read_state->iter = dl_txt_skip_map(read_state->iter, read_state->end); } - else if( strncmp( "type", key.str, 4 ) == 0 ) + else if( dl_streq( "type", key.str ) ) { if(*type_iter) dl_txt_read_failed( ctx, read_state, DL_ERROR_MALFORMED_DATA, "'type' set twice on enum '%.*s'", name->len, name->str ); *type_iter = read_state->iter; read_state->iter = dl_txt_skip_string(read_state->iter + 1, read_state->end) + 1; // TODO: fix haxx, skip_string is not eating ' or " } - else if( strncmp( "extern", key.str, 6 ) == 0 ) + else if( dl_streq( "extern", key.str ) ) { *is_extern = dl_txt_eat_bool( read_state ) == 1; } - else if( strncmp( "comment", key.str, 7 ) == 0 ) + else if( dl_streq( "verify", key.str ) ) + { + *verify = dl_txt_eat_bool( read_state ) == 1; + } + else if( dl_streq( "comment", key.str ) ) { *comment = dl_txt_eat_and_expect_string( ctx, read_state ); } @@ -801,8 +813,9 @@ static void dl_context_load_txt_type_library_read_enum( dl_ctx_t ctx, dl_txt_rea const char* end_iter; dl_substr comment = { 0, 0 }; bool is_extern; + bool verify; uint32_t meta_data_record[2] = {0,0}; - dl_context_load_txt_type_library_find_enum_keys(ctx, read_state, name, &comment, meta_data_record, &values_iter, &type_iter, &end_iter, &is_extern); + dl_context_load_txt_type_library_find_enum_keys(ctx, read_state, name, &comment, meta_data_record, &values_iter, &type_iter, &end_iter, &is_extern, &verify); dl_type_storage_t storage = DL_TYPE_STORAGE_CNT; if(type_iter) @@ -816,23 +829,23 @@ static void dl_context_load_txt_type_library_read_enum( dl_ctx_t ctx, dl_txt_rea { case 4: { - if( strncmp("int8", type_str.str, 4) == 0 ) + if( dl_streq("int8", type_str.str) ) storage = DL_TYPE_STORAGE_ENUM_INT8; } break; case 5: { - if( strncmp("int16", type_str.str, 5) == 0 ) storage = DL_TYPE_STORAGE_ENUM_INT16; - else if( strncmp("int32", type_str.str, 5) == 0 ) storage = DL_TYPE_STORAGE_ENUM_INT32; - else if( strncmp("int64", type_str.str, 5) == 0 ) storage = DL_TYPE_STORAGE_ENUM_INT64; - else if( strncmp("uint8", type_str.str, 5) == 0 ) storage = DL_TYPE_STORAGE_ENUM_UINT8; + if( dl_streq("int16", type_str.str) ) storage = DL_TYPE_STORAGE_ENUM_INT16; + else if( dl_streq("int32", type_str.str) ) storage = DL_TYPE_STORAGE_ENUM_INT32; + else if( dl_streq("int64", type_str.str) ) storage = DL_TYPE_STORAGE_ENUM_INT64; + else if( dl_streq("uint8", type_str.str) ) storage = DL_TYPE_STORAGE_ENUM_UINT8; } break; case 6: { - if( strncmp("uint16", type_str.str, 6) == 0 ) storage = DL_TYPE_STORAGE_ENUM_UINT16; - else if( strncmp("uint32", type_str.str, 6) == 0 ) storage = DL_TYPE_STORAGE_ENUM_UINT32; - else if( strncmp("uint64", type_str.str, 6) == 0 ) storage = DL_TYPE_STORAGE_ENUM_UINT64; + if( dl_streq("uint16", type_str.str) ) storage = DL_TYPE_STORAGE_ENUM_UINT16; + else if( dl_streq("uint32", type_str.str) ) storage = DL_TYPE_STORAGE_ENUM_UINT32; + else if( dl_streq("uint64", type_str.str) ) storage = DL_TYPE_STORAGE_ENUM_UINT64; } break; default: @@ -868,7 +881,11 @@ static void dl_context_load_txt_type_library_read_enum( dl_ctx_t ctx, dl_txt_rea // TODO: add test for missing enum value ... dl_enum_desc* edesc = dl_alloc_enum(ctx, name); - edesc->flags = is_extern ? (uint32_t)DL_TYPE_FLAG_IS_EXTERNAL : 0; + edesc->flags = 0; + if( is_extern || ctx->performing_include ) + edesc->flags |= (uint32_t)DL_TYPE_FLAG_IS_EXTERNAL; + if( verify && !ctx->performing_include ) + edesc->flags |= (uint32_t)DL_TYPE_FLAG_VERIFY_EXTERNAL_SIZE_ALIGN; edesc->storage = storage; edesc->value_count = ctx->enum_value_count - value_start; edesc->value_start = value_start; @@ -881,7 +898,6 @@ static void dl_context_load_txt_type_library_read_enum( dl_ctx_t ctx, dl_txt_rea static void dl_context_load_txt_type_library_read_c_includes( dl_ctx_t ctx, dl_txt_read_ctx* read_state ) { - // uint32_t includes = 0; dl_txt_eat_char( ctx, read_state, '[' ); dl_txt_eat_white( read_state ); if( *read_state->iter == ']' ) @@ -896,6 +912,40 @@ static void dl_context_load_txt_type_library_read_c_includes( dl_ctx_t ctx, dl_t dl_txt_eat_char( ctx, read_state, ']' ); } +static void dl_context_load_txt_type_library_read_includes( dl_ctx_t ctx, dl_txt_read_ctx* read_state ) +{ + dl_txt_eat_char( ctx, read_state, '[' ); + dl_txt_eat_white( read_state ); + if( *read_state->iter == ']' ) + return; // ... empty includes ... + + do + { + dl_substr include = dl_txt_eat_and_expect_string( ctx, read_state ); + if( read_state->include_handler == nullptr ) + dl_txt_read_failed( ctx, read_state, DL_ERROR_TYPELIB_MISSING_INCLUDE_HANDLER, "Found include '%.*s', but there is no include handler installed", include.len, include.str ); + + char include_path[512]; + if( size_t(include.len) < sizeof( include_path ) ) + { + memcpy( include_path, include.str, size_t(include.len) ); + include_path[include.len] = '\0'; + + bool was_performing_include = ctx->performing_include; + ctx->performing_include = true; + dl_error_t err = read_state->include_handler( read_state->include_handler_ctx, ctx, include_path ); + if( err != DL_ERROR_OK ) + dl_txt_read_failed( ctx, read_state, err, "Failed to include '%s'", include_path ); + ctx->performing_include = was_performing_include; + } + else + dl_txt_read_failed( ctx, read_state, DL_ERROR_INTERNAL_ERROR, "Too long include path '%.*s', max is 511 chars", include.len, include.str ); + + } while (dl_txt_try_eat_char( read_state, ',')); + + dl_txt_eat_char( ctx, read_state, ']' ); +} + static void dl_context_load_txt_type_library_read_enums( dl_ctx_t ctx, dl_txt_read_ctx* read_state ) { dl_txt_eat_char( ctx, read_state, '{' ); @@ -915,7 +965,7 @@ static void dl_context_load_txt_type_library_read_enums( dl_ctx_t ctx, dl_txt_re static int dl_parse_type( dl_ctx_t ctx, dl_substr* type, dl_member_desc* member, dl_txt_read_ctx* read_state ) { - #define DL_PARSE_TYPE_VALID_FMT_STR "\nvalid formats, 'type', 'type*', 'type[count]', 'type[]', 'bitfield:bits'" + #define DL_PARSE_TYPE_VALID_FMT_STR "\nvalid formats, 'type', 'type*', 'type[count]', 'type[]', 'bitfield:bits'" // ... strip whitespace ... char type_name[2048]; @@ -949,77 +999,77 @@ static int dl_parse_type( dl_ctx_t ctx, dl_substr* type, dl_member_desc* member, } switch( *iter ) { - case '[': - { - ++iter; - if( *iter == ']' ) - is_array = true; - else - { - char* next = 0x0; - inline_array_len = (unsigned int)strtoul( iter, &next, 0 ); - if( iter == next ) - { - // ... failed to parse inline array as number, try it as an enum .. - while( *next != ']' && ( isalnum(*next) || *next == '_' ) ) ++next; - - if( *next != ']' ) - dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, "%.*s is not a valid type", type->len, type->str ); - - inline_array_enum_value = iter; - inline_array_enum_value_size = (size_t)(next - iter); - } - else - { - if( *next != ']' ) - dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, "%.*s is not a valid type", type->len, type->str ); - } - iter = next + 1; - is_inline_array = true; - } - } - break; - - case ':': - { - if(strcmp( "bitfield", type_name ) != 0) - dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, - "found char (':') when parsing type '%.*s', this is only valid for type 'bitfield'" - DL_PARSE_TYPE_VALID_FMT_STR, - type->len, type->str ); - - ++iter; - - member->type = dl_make_type( DL_TYPE_ATOM_BITFIELD, DL_TYPE_STORAGE_UINT8 ); - member->type_id = 0; - char* next = 0x0; - unsigned int bits = (unsigned int)strtoul( iter, &next, 0 ); - if( iter == next || *next != '\"' ) - dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, "bitfield has a bad format, should be \"bitfield:\"" ); - - member->set_bitfield_bits( bits ); - - // type etc? - return 1; - } - break; - case '*': - { - // ignore ... - } - break; - - default: - { - dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, - "invalid char ('%c') found when parsing type '%.*s'\n" - DL_PARSE_TYPE_VALID_FMT_STR, - *iter, type->len, type->str ); - } + case '[': + { + ++iter; + if( *iter == ']' ) + is_array = true; + else + { + char* next = 0x0; + inline_array_len = (unsigned int)strtoul( iter, &next, 0 ); + if( iter == next ) + { + // ... failed to parse inline array as number, try it as an enum .. + while( *next != ']' && ( isalnum(*next) || *next == '_' ) ) ++next; + + if( *next != ']' ) + dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, "%.*s is not a valid type", type->len, type->str ); + + inline_array_enum_value = iter; + inline_array_enum_value_size = (size_t)(next - iter); + } + else + { + if( *next != ']' ) + dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, "%.*s is not a valid type", type->len, type->str ); + } + iter = next + 1; + is_inline_array = true; + } + } + break; + + case ':': + { + if(strcmp( "bitfield", type_name ) != 0) + dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, + "found char (':') when parsing type '%.*s', this is only valid for type 'bitfield'" + DL_PARSE_TYPE_VALID_FMT_STR, + type->len, type->str ); + + ++iter; + + member->type = dl_make_type( DL_TYPE_ATOM_BITFIELD, DL_TYPE_STORAGE_UINT8 ); + member->type_id = 0; + char* next = 0x0; + unsigned int bits = (unsigned int)strtoul( iter, &next, 0 ); + if( iter == next || *next != '\"' ) + dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, "bitfield has a bad format, should be \"bitfield:\"" ); + + member->set_bitfield_bits( bits ); + + // type etc? + return 1; + } + break; + case '*': + { + // ignore ... + } + break; + + default: + { + dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, + "invalid char ('%c') found when parsing type '%.*s'\n" + DL_PARSE_TYPE_VALID_FMT_STR, + *iter, type->len, type->str ); + } } } - if( strcmp( "bitfield", type_name ) == 0 ) + if( dl_streq( "bitfield", type_name ) ) dl_txt_read_failed( ctx, read_state, DL_ERROR_TXT_PARSE_ERROR, "bitfield has a bad format, should be \"bitfield:\"" ); dl_type_atom_t atom = DL_TYPE_ATOM_POD; @@ -1066,7 +1116,7 @@ static int dl_parse_type( dl_ctx_t ctx, dl_substr* type, dl_member_desc* member, } } - #undef DL_PARSE_TYPE_VALID_FMT_STR + #undef DL_PARSE_TYPE_VALID_FMT_STR return 1; } @@ -1104,19 +1154,19 @@ static void dl_context_load_txt_type_library_read_member( dl_ctx_t ctx, dl_txt_r dl_substr key = dl_txt_eat_and_expect_string( ctx, read_state ); dl_txt_eat_char( ctx, read_state, ':' ); - if( strncmp( "name", key.str, 4 ) == 0 ) + if( dl_streq( "name", key.str ) ) { name = dl_txt_eat_and_expect_string( ctx, read_state ); } - else if( strncmp( "type", key.str, 4 ) == 0 ) + else if( dl_streq( "type", key.str ) ) { type = dl_txt_eat_and_expect_string( ctx, read_state ); } - else if( strncmp( "comment", key.str, 7 ) == 0 ) + else if( dl_streq( "comment", key.str ) ) { comment = dl_txt_eat_and_expect_string( ctx, read_state ); } - else if( strncmp( "default", key.str, 7 ) == 0 ) + else if( dl_streq( "default", key.str ) ) { dl_txt_eat_white( read_state ); const char* start = read_state->iter; @@ -1141,11 +1191,11 @@ static void dl_context_load_txt_type_library_read_member( dl_ctx_t ctx, dl_txt_r default_val.len = (int)(end - start); read_state->iter = end; } - else if( strncmp( "const", key.str, 5) == 0) + else if( dl_streq( "const", key.str ) ) { is_const = dl_txt_eat_bool( read_state ) == 1; } - else if( strncmp( "verify", key.str, 6) == 0) + else if( dl_streq( "verify", key.str ) ) { verify = dl_txt_eat_bool( read_state ) == 1; } @@ -1173,9 +1223,9 @@ static void dl_context_load_txt_type_library_read_member( dl_ctx_t ctx, dl_txt_r member->default_value_size = (uint32_t)default_val.len; } - if(is_const) + if( is_const ) member->flags |= (uint32_t)DL_MEMBER_FLAG_IS_CONST; - if(verify) + if( verify && !ctx->performing_include ) member->flags |= (uint32_t)DL_MEMBER_FLAG_VERIFY_EXTERNAL_SIZE_OFFSET; dl_txt_eat_char( ctx, read_state, '}' ); @@ -1226,23 +1276,23 @@ static void dl_context_load_txt_type_library_read_type( dl_ctx_t ctx, dl_txt_rea break; dl_txt_eat_char( ctx, read_state, ':' ); - if( strncmp( "members", key.str, 7 ) == 0 ) + if( dl_streq( "members", key.str ) ) { member_count = dl_context_load_txt_type_library_read_members( ctx, read_state, name ); } - else if( strncmp( "align", key.str, 5 ) == 0 ) + else if( dl_streq( "align", key.str ) ) { align = dl_txt_pack_eat_uint32( ctx, read_state ); } - else if( strncmp( "extern", key.str, 6 ) == 0 ) + else if( dl_streq( "extern", key.str ) ) { is_extern = dl_txt_eat_bool( read_state ) == 1; } - else if( strncmp( "verify", key.str, 6 ) == 0 ) + else if( dl_streq( "verify", key.str ) ) { verify = dl_txt_eat_bool( read_state ) == 1; } - else if( strncmp( "comment", key.str, 7 ) == 0 ) + else if( dl_streq( "comment", key.str ) ) { comment = dl_txt_eat_and_expect_string( ctx, read_state ); } @@ -1276,11 +1326,11 @@ static void dl_context_load_txt_type_library_read_type( dl_ctx_t ctx, dl_txt_rea type->metadata_count = meta_data_record[0]; type->metadata_start = meta_data_record[1]; - if( is_extern ) + if( is_extern || ctx->performing_include ) type->flags |= (uint32_t)DL_TYPE_FLAG_IS_EXTERNAL; if( is_union ) type->flags |= (uint32_t)DL_TYPE_FLAG_IS_UNION; - if( verify ) + if( verify && !ctx->performing_include ) type->flags |= (uint32_t)DL_TYPE_FLAG_VERIFY_EXTERNAL_SIZE_ALIGN; dl_txt_eat_char( ctx, read_state, '}' ); @@ -1320,6 +1370,12 @@ static const dl_type_desc* dl_internal_member_owner( dl_ctx_t ctx, const dl_memb static void dl_context_load_txt_type_library_inner( dl_ctx_t ctx, dl_txt_read_ctx* read_state ) { + struct SMemberRange + { + uint32_t start; + uint32_t end; + }; + CArrayStatic member_ranges(ctx->alloc); #if defined(_MSC_VER ) #pragma warning(push) #pragma warning(disable:4611) @@ -1330,7 +1386,7 @@ static void dl_context_load_txt_type_library_inner( dl_ctx_t ctx, dl_txt_read_ct #endif { uint32_t type_start = ctx->type_count; - uint32_t member_start = ctx->member_count; + member_ranges.Add( { ctx->member_count, 0 } ); uint32_t metadata_start = (uint32_t) ctx->metadatas_count; dl_txt_eat_char( ctx, read_state, '{' ); @@ -1340,24 +1396,30 @@ static void dl_context_load_txt_type_library_inner( dl_ctx_t ctx, dl_txt_read_ct dl_substr key = dl_txt_eat_and_expect_string( ctx, read_state ); dl_txt_eat_char( ctx, read_state, ':' ); - if( strncmp( "module", key.str, 6 ) == 0 ) + if( dl_streq( "module", key.str ) ) { dl_substr module = dl_txt_eat_and_expect_string( ctx, read_state ); (void)module; } - else if( strncmp( "c_includes", key.str, 10 ) == 0 ) + else if( dl_streq( "c_includes", key.str ) ) { dl_context_load_txt_type_library_read_c_includes( ctx, read_state ); } - else if( strncmp( "enums", key.str, 5 ) == 0 ) + else if( dl_streq( "tld_includes", key.str ) ) + { + member_ranges[member_ranges.Len() - 1].end = ctx->member_count; + dl_context_load_txt_type_library_read_includes( ctx, read_state ); + member_ranges.Add( { ctx->member_count, 0 } ); + } + else if( dl_streq( "enums", key.str ) ) { dl_context_load_txt_type_library_read_enums( ctx, read_state ); } - else if( strncmp( "unions", key.str, 6 ) == 0 ) + else if( dl_streq( "unions", key.str ) ) { dl_context_load_txt_type_library_read_types( ctx, read_state, true ); } - else if( strncmp( "types", key.str, 5 ) == 0 ) + else if( dl_streq( "types", key.str ) ) { dl_context_load_txt_type_library_read_types( ctx, read_state, false ); } @@ -1367,39 +1429,48 @@ static void dl_context_load_txt_type_library_inner( dl_ctx_t ctx, dl_txt_read_ct } while( dl_txt_try_eat_char( read_state, ',') ); dl_txt_eat_char( ctx, read_state, '}' ); + member_ranges[member_ranges.Len() - 1].end = ctx->member_count; for( unsigned int i = type_start; i < ctx->type_count; ++i ) dl_load_txt_calc_type_size_and_align( ctx, read_state, ctx->type_descs + i ); // fixup members - for( uint32_t member_index = member_start; member_index < ctx->member_count; ++member_index ) + for( uint32_t member_range = 0; member_range < member_ranges.Len(); ++member_range ) { - dl_member_desc* member = ctx->member_descs + member_index; - if( member->type_id ) + for( uint32_t member_index = member_ranges[member_range].start; member_index < member_ranges[member_range].end; ++member_index ) { - const dl_enum_desc* enum_sub_type = dl_internal_find_enum( ctx, member->type_id ); - if( enum_sub_type ) - { - // ... type was really an enum ... - member->set_storage( enum_sub_type->storage ); - } - else + dl_member_desc* member = ctx->member_descs + member_index; + if( member->type_id ) { - const dl_type_desc* sub_type = dl_internal_find_type( ctx, member->type_id ); - if( sub_type == 0x0 ) - { - const dl_type_desc* owner_type = dl_internal_member_owner( ctx, member ); - dl_txt_read_failed( ctx, read_state, DL_ERROR_TYPE_NOT_FOUND, - "couldn't find type for member '%s::%s'", - dl_internal_type_name( ctx, owner_type ), - dl_internal_member_name( ctx, member ) ); - } + const dl_enum_desc* enum_sub_type = dl_internal_find_enum( ctx, member->type_id ); + if( enum_sub_type ) + { + // ... type was really an enum ... + member->set_storage( enum_sub_type->storage ); + } + else + { + const dl_type_desc* sub_type = dl_internal_find_type( ctx, member->type_id ); + if( sub_type == 0x0 ) + { + const dl_type_desc* owner_type = dl_internal_member_owner( ctx, member ); + dl_txt_read_failed( ctx, read_state, DL_ERROR_TYPE_NOT_FOUND, + "couldn't find type for member '%s::%s'", + dl_internal_type_name( ctx, owner_type ), + dl_internal_member_name( ctx, member ) ); + } + } } } } - for( uint32_t member_index = member_start; member_index < ctx->member_count; ++member_index ) - dl_load_txt_build_default_data( ctx, read_state, member_index ); + for( uint32_t member_range = 0; member_range < member_ranges.Len(); ++member_range ) + { + for( uint32_t member_index = member_ranges[member_range].start; member_index < member_ranges[member_range].end; ++member_index ) + { + dl_load_txt_build_default_data( ctx, read_state, member_index ); + } + } for( unsigned int i = type_start; i < ctx->type_count; ++i ) dl_context_load_txt_type_set_flags( ctx, read_state, ctx->type_descs + i ); @@ -1413,7 +1484,7 @@ static void dl_context_load_txt_type_library_inner( dl_ctx_t ctx, dl_txt_read_ct } } -dl_error_t dl_context_load_txt_type_library( dl_ctx_t ctx, const char* lib_data, size_t lib_data_size ) +dl_error_t dl_context_load_txt_type_library( dl_ctx_t ctx, const char* lib_data, size_t lib_data_size, const dl_load_type_library_params_t* load_params ) { (void)lib_data_size; @@ -1422,6 +1493,8 @@ dl_error_t dl_context_load_txt_type_library( dl_ctx_t ctx, const char* lib_data, read_state.end = lib_data + lib_data_size; read_state.iter = lib_data; read_state.err = DL_ERROR_OK; + read_state.include_handler = load_params ? load_params->include_handler : nullptr; + read_state.include_handler_ctx = load_params ? load_params->handler_ctx : nullptr; dl_context_load_txt_type_library_inner( ctx, &read_state ); diff --git a/src/dl_types.h b/src/dl_types.h index cbc4e99..e36ca00 100755 --- a/src/dl_types.h +++ b/src/dl_types.h @@ -323,6 +323,7 @@ struct dl_context uint8_t* default_data; size_t default_data_size; + bool performing_include; }; struct dl_substr diff --git a/src/dl_util.cpp b/src/dl_util.cpp old mode 100755 new mode 100644 diff --git a/tests/dl_test_common.h b/tests/dl_test_common.h index 67b6cf6..2af070d 100755 --- a/tests/dl_test_common.h +++ b/tests/dl_test_common.h @@ -10,6 +10,7 @@ #include "generated/unittest.h" #include "generated/unittest2.h" #include "generated/sized_enums.h" +#include "generated/to_include.h" #include diff --git a/tests/dl_tests_typelib.cpp b/tests/dl_tests_typelib.cpp index 7aa592e..f9f9a21 100644 --- a/tests/dl_tests_typelib.cpp +++ b/tests/dl_tests_typelib.cpp @@ -88,12 +88,12 @@ TEST_F( DLTypeLibTxt, simple_read_write ) }); // ... load typelib ... - EXPECT_DL_ERR_EQ( DL_ERROR_OK, dl_context_load_txt_type_library( ctx, single_member_typelib, sizeof(single_member_typelib)-1 ) ); + EXPECT_DL_ERR_EQ( DL_ERROR_OK, dl_context_load_txt_type_library( ctx, single_member_typelib, sizeof(single_member_typelib)-1, 0 ) ); } static void typelibtxt_expect_error( dl_ctx_t ctx, dl_error_t expect, const char* libstr ) { - EXPECT_DL_ERR_EQ( expect, dl_context_load_txt_type_library( ctx, libstr, strlen(libstr) ) ); + EXPECT_DL_ERR_EQ( expect, dl_context_load_txt_type_library( ctx, libstr, strlen(libstr), 0 ) ); } TEST_F( DLTypeLibTxt, member_missing_type ) @@ -140,7 +140,7 @@ TEST_F( DLTypeLibTxt, missing_comma ) }); // ... load typelib ... - EXPECT_DL_ERR_EQ( DL_ERROR_TXT_PARSE_ERROR, dl_context_load_txt_type_library( ctx, single_member_typelib, sizeof(single_member_typelib)-1 ) ); + EXPECT_DL_ERR_EQ( DL_ERROR_TXT_PARSE_ERROR, dl_context_load_txt_type_library( ctx, single_member_typelib, sizeof(single_member_typelib)-1, 0 ) ); } TEST_F( DLTypeLibTxt, crash1 ) @@ -164,7 +164,7 @@ TEST_F( DLTypeLibTxt, crash1 ) }); // ... load typelib ... - EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, single_member_typelib, sizeof(single_member_typelib)-1 ) ); + EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, single_member_typelib, sizeof(single_member_typelib)-1, 0 ) ); } TEST_F( DLTypeLibTxt, nonexisting_type ) @@ -252,7 +252,7 @@ TEST_F( DLTypeLibTxt, invalid_type_fmt_bitfield ) TEST_F( DLTypeLibTxt, empty_typelib ) { - EXPECT_DL_ERR_EQ( DL_ERROR_TXT_PARSE_ERROR, dl_context_load_txt_type_library( ctx, 0x0, 0 ) ); + EXPECT_DL_ERR_EQ( DL_ERROR_TXT_PARSE_ERROR, dl_context_load_txt_type_library( ctx, 0x0, 0, 0 ) ); } TEST_F( DLTypeLibTxt, invalid_type_fmt_pointer_to_pod ) @@ -343,7 +343,7 @@ TEST_F( DLTypeLibUnpackTxt, round_about ) }); // ... pack from text ... - EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, testlib1, sizeof(testlib1)-1 ) ); + EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, testlib1, sizeof(testlib1)-1, 0 ) ); size_t txt_size = 0; char testlib_txt_buffer[2048]; @@ -354,7 +354,7 @@ TEST_F( DLTypeLibUnpackTxt, round_about ) DL_CREATE_PARAMS_SET_DEFAULT(p); p.error_msg_func = test_log_error; EXPECT_DL_ERR_OK( dl_context_create( &ctx2, &p ) ); - EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx2, testlib_txt_buffer, txt_size ) ); + EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx2, testlib_txt_buffer, txt_size, 0 ) ); // ... check that typelib contain the enum and the type ... dl_type_context_info_t info; @@ -370,9 +370,18 @@ TEST_F( DLTypeLibUnpackTxt, round_about_big ) const char testlib1[] = { #include "generated/unittest.txt.h" }; + dl_include_handler include_handler = []( void* handler_ctx, dl_ctx_t dl_ctx, const char* file_to_include ) -> dl_error_t { + const char testlib2[] = { + #include "generated/to_include.txt.h" + }; + EXPECT_STREQ( "../local/generated/to_include.bin", file_to_include ); + EXPECT_EQ( (void*)1, handler_ctx ); + return dl_context_load_txt_type_library( dl_ctx, testlib2, sizeof(testlib2) - 1, 0 ); + }; // ... pack from text ... - EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, testlib1, sizeof(testlib1)-1 ) ); + dl_load_type_library_params_t load_params{ include_handler, (void*)1 }; + EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, testlib1, sizeof(testlib1) - 1, &load_params ) ); size_t txt_buffer_size = 4096*8; size_t txt_size = 0; @@ -384,7 +393,7 @@ TEST_F( DLTypeLibUnpackTxt, round_about_big ) DL_CREATE_PARAMS_SET_DEFAULT(p); p.error_msg_func = test_log_error; EXPECT_DL_ERR_OK( dl_context_create( &ctx2, &p ) ); - EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx2, testlib_txt_buffer, txt_size ) ); + EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx2, testlib_txt_buffer, txt_size, 0 ) ); free((void*)testlib_txt_buffer); @@ -399,7 +408,7 @@ static uint8_t* test_pack_txt_type_lib( const char* lib_txt, size_t lib_txt_size DL_CREATE_PARAMS_SET_DEFAULT(p); p.error_msg_func = test_log_error; EXPECT_DL_ERR_OK( dl_context_create( &ctx, &p ) ); - EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, lib_txt, lib_txt_size ) ); + EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, lib_txt, lib_txt_size, 0 ) ); EXPECT_DL_ERR_OK( dl_context_write_type_library( ctx, 0x0, 0, out_size ) ); uint8_t* packed = (uint8_t*)malloc(*out_size); @@ -470,7 +479,8 @@ TEST_F( DLTypeLibTxt, DISABLED_default_inl_arr_of_bits ) "InlineArray": { "members": [ { "name": "seeds", "type": "BitField[2]", "default": [ { "bits": 1 } ] } ] } } } ); - EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, json_typelib, sizeof( json_typelib ) - 1 ) ); + + EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, json_typelib, sizeof( json_typelib ) - 1, 0 ) ); } TEST_F( DLTypeLibTxt, long_default_value ) @@ -509,5 +519,5 @@ TEST_F( DLTypeLibTxt, long_default_value ) } ); // ... load typelib ... - EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, json_typelib, sizeof( json_typelib ) - 1 ) ); + EXPECT_DL_ERR_OK( dl_context_load_txt_type_library( ctx, json_typelib, sizeof( json_typelib ) - 1, 0 ) ); } diff --git a/tests/to_include.tld b/tests/to_include.tld new file mode 100644 index 0000000..2a526fd --- /dev/null +++ b/tests/to_include.tld @@ -0,0 +1,5 @@ +{ + "types" : { + "included_type" : { "members" : [ { "name" : "name", "type" : "string", "default" : "" } ] } + } +} diff --git a/tests/unittest.tld b/tests/unittest.tld index ee54258..bc417f3 100755 --- a/tests/unittest.tld +++ b/tests/unittest.tld @@ -3,6 +3,9 @@ "c_includes" : [ "" ], // just testing... not actually needed! + // Testing an include of a binary type library definition, used only as a metadata type and thus not added to c_includes + "tld_includes" : [ "../local/generated/to_include.bin" ], + "enums" : { "TestEnum1" : { "values" : { @@ -50,6 +53,14 @@ "types" : { "unused" : { "members" : [ { "name" : "member", "type" : "int32", "comment" : "only used in unittests to check for errors" } ] }, + "use_included_type" : { + "members" : [ + { "name" : "member", "type" : "int8" } + ] + //"metadata" : [ + // { "included_type" : { "name": "use_included_type" } } + //] + }, "Pods" : { "members" : [ { "name" : "i8", "type" : "int8" }, diff --git a/tests/unittest2.tld b/tests/unittest2.tld index f60e337..143b4a2 100755 --- a/tests/unittest2.tld +++ b/tests/unittest2.tld @@ -1,7 +1,13 @@ { "module" : "unit_test_2", - "c_includes" : [ "../../tests/dl_test_included.h" ], + "c_includes" : [ + "../../tests/dl_test_included.h", + "to_include.h" + ], + + // Testing an include of a text based type library definition, used as a member type and thus also added in c_includes above + "tld_includes" : [ "to_include.tld" ], "enums" : { "extern_enum" : { @@ -16,6 +22,12 @@ }, "types" : { + "use_included_type2" : { + "members" : [ + { "name" : "member", "type" : "included_type" } + ] + }, + "BugTest1_InArray" : { "members" : [ { "name" : "u64_1", "type" : "uint64" }, { "name" : "u64_2", "type" : "uint64" }, { "name" : "u16", "type" : "uint16" } ] }, diff --git a/tool/dlpack/dlpack.cpp b/tool/dlpack/dlpack.cpp old mode 100755 new mode 100644 diff --git a/tool/dltlc/dltlc.cpp b/tool/dltlc/dltlc.cpp index 7acf7c0..7799ac2 100644 --- a/tool/dltlc/dltlc.cpp +++ b/tool/dltlc/dltlc.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include #ifdef _MSC_VER @@ -26,6 +28,7 @@ struct dltlc_args static int verbose = 0; std::vector inputs; +std::vector include_dirs; #define VERBOSE_OUTPUT(fmt, ...) if( verbose ) { fprintf(stderr, fmt "\n", ##__VA_ARGS__); } @@ -36,12 +39,13 @@ static int parse_args( int argc, const char** argv, dltlc_args* args ) const getopt_option_t option_list[] = { - { "help", 'h', GETOPT_OPTION_TYPE_NO_ARG, 0x0, 'h', "displays this help-message", 0x0 }, - { "output", 'o', GETOPT_OPTION_TYPE_REQUIRED, 0x0, 'o', "output to file", "file" }, - { "unpack", 'u', GETOPT_OPTION_TYPE_FLAG_SET, &args->unpack, 1, "force dl_pack to treat input data as a packed instance that should be unpacked.", 0x0 }, - { "info", 'i', GETOPT_OPTION_TYPE_FLAG_SET, &args->show_info, 1, "make dl_pack show info about a packed instance.", 0x0 }, - { "verbose", 'v', GETOPT_OPTION_TYPE_FLAG_SET, &verbose, 1, "verbose output", 0x0 }, - { "c-header", 'c', GETOPT_OPTION_TYPE_FLAG_SET, &args->c_header, 1, "output c header instead of tld binary", 0x0 }, + { "help", 'h', GETOPT_OPTION_TYPE_NO_ARG, 0x0, 'h', "displays this help-message", 0x0 }, + { "output", 'o', GETOPT_OPTION_TYPE_REQUIRED, 0x0, 'o', "output to file", "file" }, + { "search-dir",'s', GETOPT_OPTION_TYPE_REQUIRED, 0x0, 's', "directory where included .tld files should be searched for.", 0x0 }, + { "unpack", 'u', GETOPT_OPTION_TYPE_FLAG_SET, &args->unpack, 1, "force dl_pack to treat input data as a packed instance that should be unpacked.", 0x0 }, + { "info", 'i', GETOPT_OPTION_TYPE_FLAG_SET, &args->show_info, 1, "make dl_pack show info about a packed instance.", 0x0 }, + { "verbose", 'v', GETOPT_OPTION_TYPE_FLAG_SET, &verbose, 1, "verbose output", 0x0 }, + { "c-header", 'c', GETOPT_OPTION_TYPE_FLAG_SET, &args->c_header, 1, "output c header instead of tld binary", 0x0 }, GETOPT_OPTIONS_END }; @@ -76,6 +80,10 @@ static int parse_args( int argc, const char** argv, dltlc_args* args ) args->output = go_ctx.current_opt_arg; break; + case 's': + include_dirs.push_back(go_ctx.current_opt_arg); + break; + case '!': fprintf( stderr, "incorrect usage of flag \"%s\"\n", go_ctx.current_opt_arg ); return 1; @@ -89,6 +97,8 @@ static int parse_args( int argc, const char** argv, dltlc_args* args ) break; } } + // The "current local include dir" will be stored last and this vector will be searched backwards so reverse it + std::reverse(include_dirs.begin(), include_dirs.end()); if( args->show_info + args->c_header + args->unpack > 1 ) { @@ -123,20 +133,64 @@ static unsigned char* read_entire_stream( FILE* file, size_t* out_size ) return out_buffer; } -static bool load_typelib( dl_ctx_t ctx, FILE* f ) +static dl_error_t load_typelib( dl_ctx_t ctx, unsigned char* lib_data, size_t lib_data_siz, std::vector* include_dirs ); + +static dl_error_t include_handler( void* callback_context, dl_ctx_t ctx, const char* file_to_include ) { + std::vector* include_directories = (std::vector*)callback_context; + char path[512]; + FILE* f = nullptr; + for( auto include_dir : *include_directories ) + { + snprintf( path, sizeof( path ), "%s/%s", include_dir, file_to_include ); + f = fopen( path, "rb" ); + if( f != nullptr ) + { + break; + } + } + if( f == 0x0 ) + { + fprintf( stderr, "failed to open \"%s\"\n", file_to_include ); + return DL_ERROR_UTIL_FILE_NOT_FOUND; + } + size_t size = 0; unsigned char* data = read_entire_stream( f, &size ); + fclose( f ); - dl_error_t err = dl_context_load_type_library( ctx, data, size ); - if( err != DL_ERROR_OK ) - err = dl_context_load_txt_type_library( ctx, (const char*)data, size ); // ... try text ... + const char* prev_local_include_folder = include_directories->back(); + include_directories->pop_back(); + + std::string input = path; + size_t slash = input.find_last_of( "/\\" ); + std::string folder = input.substr( 0, slash ); + if( input.npos == slash ) + include_directories->push_back( "." ); + else + include_directories->push_back( folder.c_str() ); + dl_error_t err = load_typelib( ctx, data, size, include_directories ); free( data ); + include_directories->pop_back(); + include_directories->push_back( prev_local_include_folder ); + + return err; +} + +static dl_error_t load_typelib( dl_ctx_t ctx, unsigned char* lib_data, size_t lib_data_size, std::vector* include_directories ) +{ + dl_error_t err = dl_context_load_type_library( ctx, lib_data, lib_data_size ); + if (err != DL_ERROR_OK) + { + dl_load_type_library_params_t load_params{ include_handler, (void*)include_directories }; + err = dl_context_load_txt_type_library( ctx, (const char*)lib_data, lib_data_size, &load_params ); // ... try text ... + } + if( err != DL_ERROR_OK ) VERBOSE_OUTPUT( "failed to load typelib with error %s", dl_error_to_string( err ) ); - return err == DL_ERROR_OK; + return err; } static int write_tl_as_text( dl_ctx_t ctx, FILE* out ) @@ -334,8 +388,13 @@ int main( int argc, const char** argv ) if( inputs.size() == 0 ) { VERBOSE_OUTPUT( "loading typelib from stdin" ); - - if( !load_typelib( ctx, stdin ) ) + include_dirs.push_back( "." ); + + size_t size = 0; + unsigned char* data = read_entire_stream( stdin, &size ); + err = load_typelib( ctx, data, size, &include_dirs ); + free( data ); + if( err != DL_ERROR_OK ) { return 1; } @@ -344,21 +403,31 @@ int main( int argc, const char** argv ) { for( size_t i = 0; i < inputs.size(); ++i ) { + std::string input = inputs[i]; + size_t slash = input.find_last_of( "/\\" ); + std::string folder = input.substr( 0, slash ); + if( input.npos == slash ) + include_dirs.push_back( "." ); + else + include_dirs.push_back( folder.c_str() ); FILE* f = fopen( inputs[i], "rb" ); if( f == 0x0 ) { fprintf( stderr, "failed to open \"%s\"\n", inputs[i] ); return 1; } + + size_t size = 0; + unsigned char* data = read_entire_stream( f, &size ); + fclose( f ); - if( !load_typelib( ctx, f ) ) + err = load_typelib( ctx, data, size, &include_dirs ); + free( data ); + if( err != DL_ERROR_OK ) { fprintf( stderr, "failed to load typelib from \"%s\"\n", inputs[i] ); - fclose( f ); return 1; } - - fclose( f ); } }