diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2023-09-22 19:48:59 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2023-09-22 19:48:59 +0200 |
commit | 10ff42656df228b5d0f5d9cc4ad194940d227dee (patch) | |
tree | 90722b9043e63c1d008a57085cd342373fef2dd8 | |
parent | 136742c16b42b3a2ddc2ab5ce5f1a384e8d2fa09 (diff) | |
download | kit-10ff42656df228b5d0f5d9cc4ad194940d227dee.zip |
Update single header
-rw-r--r-- | gen_inl.c | 39 | ||||
-rw-r--r-- | include/kit.inl.h | 1009 |
2 files changed, 896 insertions, 152 deletions
@@ -8,19 +8,29 @@ exit #include <stdlib.h> #include <string.h> -char *HEADERS[] = { - "source/kit/types.h", "source/kit/status.h", - "source/kit/allocator.h", "source/kit/time.h", - "source/kit/atomic.h", "source/kit/threads.h", - "source/kit/array_ref.h", "source/kit/dynamic_array.h", - "source/kit/string_ref.h", "source/kit/string_builder.h", - "source/kit/lower_bound.h", "source/kit/move_back.h", - "source/kit/bigint.h", "source/kit/input_stream.h", - "source/kit/input_buffer.h", "source/kit/async_function.h", - "source/kit/file.h", "source/kit/mersenne_twister_64.h", - "source/kit/secure_random.h", "source/kit/sha256.h", - "source/kit/sockets.h", "source/kit/shared_memory.h" -}; +char *HEADERS[] = { "source/kit/types.h", + "source/kit/status.h", + "source/kit/allocator.h", + "source/kit/time.h", + "source/kit/atomic.h", + "source/kit/threads.h", + "source/kit/array_ref.h", + "source/kit/dynamic_array.h", + "source/kit/string_ref.h", + "source/kit/string_builder.h", + "source/kit/lower_bound.h", + "source/kit/move_back.h", + "source/kit/bigint.h", + "source/kit/input_stream.h", + "source/kit/input_buffer.h", + "source/kit/async_function.h", + "source/kit/file.h", + "source/kit/mersenne_twister_64.h", + "source/kit/secure_random.h", + "source/kit/sha256.h", + "source/kit/sockets.h", + "source/kit/shared_memory.h", + "source/kit/xml.h" }; char *IMPL[] = { "source/kit/allocator.c", "source/kit/atomic.win32.c", @@ -35,7 +45,8 @@ char *IMPL[] = { "source/kit/allocator.c", "source/kit/secure_random.c", "source/kit/sha256.c", "source/kit/shared_memory.posix.c", - "source/kit/shared_memory.win32.c" }; + "source/kit/shared_memory.win32.c", + "source/kit/xml.c" }; char *repeat(int n, char c) { static char buf[200]; diff --git a/include/kit.inl.h b/include/kit.inl.h index 55e05ab..1b66297 100644 --- a/include/kit.inl.h +++ b/include/kit.inl.h @@ -64,25 +64,28 @@ typedef double f64; #define KIT_STATUS_H enum { KIT_OK = 0, - KIT_ERROR_NOT_IMPLEMENTED = 1, + KIT_ERROR_INTERNAL = 1, KIT_ERROR_BAD_ALLOC = (1 << 1), KIT_ERROR_INVALID_ARGUMENT = (1 << 2), KIT_ERROR_MKDIR_FAILED = (1 << 3), KIT_ERROR_RMDIR_FAILED = (1 << 4), KIT_ERROR_UNLINK_FAILED = (1 << 5), KIT_ERROR_FILE_ALREADY_EXISTS = (1 << 6), - KIT_ERROR_FILE_DO_NOT_EXIST = (1 << 7), + KIT_ERROR_FILE_DOES_NOT_EXIST = (1 << 7), KIT_ERROR_PATH_TOO_LONG = (1 << 8), KIT_ERROR_SOCKETS_STARTUP_FAILED = (1 << 9), KIT_ERROR_SOCKET_CONTROL_FAILED = (1 << 10), KIT_ERROR_NAME_TOO_LONG = (1 << 11), KIT_ERROR_INVALID_SIZE = (1 << 12), KIT_ERROR_INVALID_NAME = (1 << 13), - KIT_ERROR_SHM_OPEN_FAILED = (1 << 14), - KIT_ERROR_SHM_UNLINK_FAILED = (1 << 15), - KIT_ERROR_FTRUNCATE_FAILED = (1 << 16), - KIT_ERROR_MMAP_FAILED = (1 << 17), - KIT_ERROR_MUNMAP_FAILED = (1 << 18), + KIT_ERROR_INVALID_PATH = (1 << 14), + KIT_ERROR_OPEN_FAILED = (1 << 15), + KIT_ERROR_TRUNCATE_FAILED = (1 << 16), + KIT_ERROR_MAP_FAILED = (1 << 17), + KIT_ERROR_UNMAP_FAILED = (1 << 18), + KIT_ERROR_SYNC_FAILED = (1 << 19), + KIT_ERROR_CLOSE_FAILED = (1 << 20), + KIT_ERROR_NOT_IMPLEMENTED = (1 << 30), }; typedef i32 kit_status_t; #endif @@ -123,7 +126,7 @@ typedef struct { // See KIT_ENABLE_CUSTOM_ALLOC_DISPATCH macro. // void *kit_alloc_dispatch(kit_allocator_t *alloc, i32 request, - i64 size, i64 previous_size, void *poi32er); + i64 size, i64 previous_size, void *pointer); kit_allocator_t kit_alloc_default(void); kit_allocator_t kit_alloc_buffer(i64 size, void *buffer); #ifdef __cplusplus @@ -147,7 +150,7 @@ extern "C" { #ifndef TIME_UTC # define TIME_UTC 1 #endif -#ifdef __MINGW32__ +#ifdef KIT_REQUIRE_TIMESPEC_GET # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 # endif @@ -538,6 +541,7 @@ i8 kit_ar_compare(i64 left_element_size, i64 left_size, *********************************************************************/ #ifndef KIT_DYNAMIC_ARRAY_H #define KIT_DYNAMIC_ARRAY_H +#include <string.h> #ifdef __cplusplus extern "C" { #endif @@ -573,11 +577,14 @@ void kit_da_resize_exact(kit_da_void_t *array, i64 element_size, KIT_DA_INIT(name_, (size_), NULL) /* Destroy dynamic array. */ -#define KIT_DA_DESTROY(array_) \ - do { \ - if ((array_).values != NULL) \ - kit_alloc_dispatch((array_).alloc, KIT_DEALLOCATE, 0, 0, \ - (array_).values); \ +#define KIT_DA_DESTROY(array_) \ + do { \ + if ((array_).values != NULL) \ + kit_alloc_dispatch((array_).alloc, KIT_DEALLOCATE, 0, \ + (array_).capacity * \ + sizeof((array_).values[0]), \ + (array_).values); \ + memset(&(array_), 0, sizeof(array_)); \ } while (0) /* Resize dynamic array. */ @@ -673,7 +680,8 @@ static char *kit_make_bs(kit_str_t s) { i64 n = s.size; if (n > 4095) n = 4095; - memcpy(buf[index], s.values, n); + if (n > 0) + memcpy(buf[index], s.values, n); buf[index][n] = '\0'; char *result = buf[index]; index = (index + 1) % 8; @@ -686,10 +694,10 @@ static char *kit_make_bs(kit_str_t s) { #define KIT_SZ(static_str_) \ kit_str(sizeof(static_str_) - 1, (static_str_)) #define KIT_WRAP_BS(string_) kit_str(strlen(string_), (string_)) -#define KIT_WRAP_STR(string_) \ - kit_str((string_).size, (string_).values) +#define KIT_WRAP_STR(...) \ + kit_str((__VA_ARGS__).size, (__VA_ARGS__).values) #ifndef KIT_DISABLE_SHORT_NAMES -# define BS(string_) kit_make_bs(KIT_WRAP_STR(string_)) +# define BS(...) kit_make_bs(KIT_WRAP_STR(__VA_ARGS__)) # define str_t kit_str_t # define SZ KIT_SZ # define WRAP_BS KIT_WRAP_BS @@ -1331,26 +1339,44 @@ typedef struct { i64 offset; void *internal; kit_str_builder_t data; -} kit_ib_handle_t; -typedef i8 (*kit_ib_read_condition_fn)(kit_str_t data); -kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream, - kit_allocator_t *alloc); -kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, i64 size); -kit_ib_handle_t kit_ib_read_while(kit_ib_handle_t buf, - kit_ib_read_condition_fn condition); -void kit_ib_destroy(kit_ib_handle_t buf); +} kit_ib_t; +typedef i8 (*kit_ib_read_condition_fn)(kit_str_t data, void *context); +kit_ib_t kit_ib_wrap(kit_is_handle_t upstream, + kit_allocator_t *alloc); +kit_ib_t kit_ib_copy(kit_ib_t buf); +kit_ib_t kit_ib_read(kit_ib_t buf, i64 size); +kit_ib_t kit_ib_any(kit_ib_t buf, kit_str_t data); +kit_ib_t kit_ib_none(kit_ib_t buf, kit_str_t data); +kit_ib_t kit_ib_exact(kit_ib_t buf, kit_str_t data); +kit_ib_t kit_ib_until(kit_ib_t buf, kit_str_t data); +kit_ib_t kit_ib_while(kit_ib_t buf, + kit_ib_read_condition_fn condition, + void *context); +void kit_ib_destroy(kit_ib_t buf); #define KIT_IB_WRAP(upstream) kit_ib_wrap(upstream, NULL) +#define KIT_IB_SKIP(buf_, proc_, ...) \ + do { \ + kit_ib_t temp_buf_ = (buf_); \ + (buf_) = proc_((buf_), __VA_ARGS__); \ + kit_ib_destroy((temp_buf_)); \ + } while (0) #ifdef __cplusplus } #endif #ifndef KIT_DISABLE_SHORT_NAMES -# define ib_handle_t kit_ib_handle_t +# define ib_t kit_ib_t # define ib_read_condition_fn kit_ib_read_condition_fn # define ib_wrap kit_ib_wrap +# define ib_copy kit_ib_copy # define ib_read kit_ib_read -# define ib_read_while kit_ib_read_while +# define ib_any kit_ib_any +# define ib_none kit_ib_none +# define ib_exact kit_ib_exact +# define ib_until kit_ib_until +# define ib_while kit_ib_while # define ib_destroy kit_ib_destroy # define IB_WRAP KIT_IB_WRAP +# define IB_SKIP KIT_IB_SKIP #endif #endif /********************************************************************* @@ -1384,16 +1410,16 @@ typedef struct { #endif #define KIT_AF_INTERNAL(coro_) (*((kit_af_type_void *) (coro_))) #ifdef KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH -/* Application should implement this function if custom async - * function dispatch is enabled. - * - * See KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH macro. - */ +// Application should implement this function if custom async +// function dispatch is enabled. +// +// See KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH macro. +// void kit_async_function_dispatch(void *promise); #else static void kit_async_function_dispatch(void *promise) { - /* Dynamic dispatch by default. - */ + // Dynamic dispatch by default. + // KIT_AF_INTERNAL(promise)._state_machine(promise); } #endif @@ -1557,6 +1583,7 @@ static void kit_async_function_dispatch(void *promise) { *********************************************************************/ #ifndef KIT_FILE_H #define KIT_FILE_H +#include <stdio.h> #ifdef __cplusplus extern "C" { #endif @@ -1575,6 +1602,18 @@ typedef struct { kit_status_t status; KIT_DA(kit_str_builder_t) files; } kit_path_list_t; +enum { KIT_FILE_MAP_PRIVATE, KIT_FILE_MAP_SHARED }; +typedef struct { + kit_status_t status; + i64 size; + u8 *bytes; +#if defined(_WIN32) && !defined(__CYGWIN__) + void *_file; + void *_map; +#else + int _fd; +#endif +} kit_mapped_file_t; #if defined(_WIN32) && !defined(__CYGWIN__) # define KIT_PATH_DELIM_C '\\' # define KIT_PATH_DELIM "\\" @@ -1592,17 +1631,20 @@ kit_str_builder_t kit_path_user(kit_allocator_t *alloc); kit_str_builder_t kit_path_cache(kit_allocator_t *alloc); kit_str_t kit_path_index(kit_str_t path, i64 index); kit_str_t kit_path_take(kit_str_t path, i64 count); -kit_status_t kit_file_create_folder(kit_str_t path); -kit_status_t kit_file_create_folder_recursive(kit_str_t path); +kit_status_t kit_folder_create(kit_str_t path); +kit_status_t kit_folder_create_recursive(kit_str_t path); kit_status_t kit_file_remove(kit_str_t path); -kit_status_t kit_file_remove_folder(kit_str_t path); +kit_status_t kit_folder_remove(kit_str_t path); kit_status_t kit_file_remove_recursive(kit_str_t path, kit_allocator_t *alloc); kit_path_type_t kit_path_type(kit_str_t path); kit_file_info_t kit_file_info(kit_str_t path); -kit_path_list_t kit_file_enum_folder(kit_str_t path, - kit_allocator_t *alloc); +kit_path_list_t kit_folder_enum(kit_str_t path, + kit_allocator_t *alloc); void kit_path_list_destroy(kit_path_list_t list); +kit_mapped_file_t kit_file_map(kit_str_t path, i64 size, i32 mode); +kit_status_t kit_file_sync(kit_mapped_file_t *mf); +kit_status_t kit_file_unmap(kit_mapped_file_t *mf); #ifdef __cplusplus } #endif @@ -1613,19 +1655,24 @@ void kit_path_list_destroy(kit_path_list_t list); # define path_cache kit_path_cache # define path_index kit_path_index # define path_take kit_path_take -# define file_create_folder kit_file_create_folder -# define file_create_folder_recursive \ - kit_file_create_folder_recursive +# define folder_create kit_folder_create +# define folder_create_recursive kit_folder_create_recursive # define file_remove kit_file_remove -# define file_remove_folder kit_file_remove_folder +# define folder_remove kit_folder_remove # define file_remove_recursive kit_file_remove_recursive # define path_type_t kit_path_type_t # define path_type kit_path_type # define file_info_t kit_file_info_t # define file_info kit_file_info # define path_list_t kit_path_list_t -# define file_enum_folder kit_file_enum_folder +# define folder_enum kit_folder_enum # define path_list_destroy kit_path_list_destroy +# define mapped_file_t kit_mapped_file_t +# define file_map kit_file_map +# define file_sync kit_file_sync +# define file_unmap kit_file_unmap +# define FILE_MAP_PRIVATE KIT_FILE_MAP_PRIVATE +# define FILE_MAP_SHARED KIT_FILE_MAP_SHARED # define PATH_DELIM_C KIT_PATH_DELIM_C # define PATH_DELIM KIT_PATH_DELIM # define ENV_HOME KIT_ENV_HOME @@ -1824,7 +1871,6 @@ typedef struct { void *_handle; #else i8 _owned; - i32 _fd; char _name[NAME_MAX + 1]; #endif } kit_shared_memory_t; @@ -1835,9 +1881,70 @@ enum { kit_shared_memory_t kit_shared_memory_open(kit_str_t name, i64 size, i32 mode); kit_status_t kit_shared_memory_close(kit_shared_memory_t *mem); +kit_status_t kit_shared_memory_clean(kit_str_t name); #ifdef __cplusplus } #endif +#ifndef KIT_DISABLE_SHORT_NAMES +# define shared_memory_t kit_shared_memory_t +# define shared_memory_clean kit_shared_memory_clean +# define shared_memory_open kit_shared_memory_open +# define shared_memory_close kit_shared_memory_close +# define SHARED_MEMORY_OPEN KIT_SHARED_MEMORY_OPEN +# define SHARED_MEMORY_CREATE KIT_SHARED_MEMORY_CREATE +#endif +#endif +/********************************************************************* + * * + * File: source/kit/xml.h * + * * + *********************************************************************/ +#ifndef KIT_XML_H +#define KIT_XML_H +#ifdef __cplusplus +extern "C" { +#endif +typedef struct kit_xml_ kit_xml_t; +typedef struct { + kit_str_builder_t name; + kit_str_builder_t value; +} kit_xml_property_t; +typedef KIT_DA(kit_xml_property_t) kit_da_xml_property_t; +typedef KIT_DA(kit_xml_t) kit_da_xml_t; +struct kit_xml_ { + i8 is_declaration; + kit_str_builder_t tag; + kit_str_builder_t text; + kit_str_builder_t tail; + kit_da_xml_property_t properties; + kit_da_xml_t children; +}; +typedef struct { + kit_status_t status; + kit_xml_t xml; +} kit_xml_parse_result_t; +typedef struct { + kit_status_t status; + kit_str_builder_t text; +} kit_xml_text_t; +kit_xml_parse_result_t kit_xml_parse(kit_is_handle_t is, + kit_allocator_t *alloc); +kit_xml_text_t kit_xml_print(kit_xml_t *xml, kit_allocator_t *alloc); +kit_xml_text_t kit_xml_full_text(kit_xml_t *xml, + kit_allocator_t *alloc); +void kit_xml_destroy(kit_xml_t *xml); +#ifdef __cplusplus +} +#endif +#ifndef KIT_DISABLE_SHORT_NAMES +# define xml_parse kit_xml_parse +# define xml_print kit_xml_print +# define xml_full_text kit_xml_full_text +# define xml_destroy kit_xml_destroy +# define xml_t kit_xml_t +# define xml_parse_result_t kit_xml_parse_result_t +# define xml_text_t kit_xml_text_t +#endif #endif #ifdef KIT_IMPLEMENTATION /********************************************************************* @@ -2766,7 +2873,6 @@ void thrd_yield(void) { * * *********************************************************************/ #include <assert.h> -#include <string.h> void kit_da_init(kit_da_void_t *array, i64 element_size, i64 size, kit_allocator_t *alloc) { assert(array != NULL); @@ -2958,7 +3064,8 @@ static void kit_buf_acquire_(void *p) { ((internal_buffer_t *) p)->ref_count++; } static void kit_buf_release_(void *p) { - assert(p != NULL); + if (p == NULL) + return; internal_buffer_t *buf = (internal_buffer_t *) p; if (--buf->ref_count == 0) { DA_DESTROY(buf->data); @@ -2986,9 +3093,9 @@ static i64 kit_buf_read_(void *p, i64 offset, kit_str_t destination) { memcpy(destination.values, buf->data.values + offset, n); return n; } -kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream, - kit_allocator_t *alloc) { - kit_ib_handle_t buf; +kit_ib_t kit_ib_wrap(kit_is_handle_t upstream, + kit_allocator_t *alloc) { + kit_ib_t buf; memset(&buf, 0, sizeof buf); buf.status = KIT_OK; DA_INIT(buf.data, 0, alloc); @@ -2997,8 +3104,20 @@ kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream, buf.status = KIT_ERROR_BAD_ALLOC; return buf; } -kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, i64 size) { - kit_ib_handle_t next; +kit_ib_t kit_ib_copy(kit_ib_t buf) { + kit_ib_t next; + memset(&next, 0, sizeof next); + if (buf.status != KIT_OK) { + next.status = buf.status; + return next; + } + kit_buf_acquire_(buf.internal); + next.offset = buf.offset; + next.internal = buf.internal; + return next; +} +kit_ib_t kit_ib_read(kit_ib_t buf, i64 size) { + kit_ib_t next; memset(&next, 0, sizeof next); if (buf.status != KIT_OK) { next.status = buf.status; @@ -3019,9 +3138,8 @@ kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, i64 size) { next.status = KIT_ERROR_BAD_ALLOC; return next; } -kit_ib_handle_t kit_ib_read_while( - kit_ib_handle_t buf, kit_ib_read_condition_fn condition) { - kit_ib_handle_t next; +kit_ib_t kit_ib_any(kit_ib_t buf, kit_str_t data) { + kit_ib_t next; memset(&next, 0, sizeof next); if (buf.status != KIT_OK) { next.status = buf.status; @@ -3033,14 +3151,144 @@ kit_ib_handle_t kit_ib_read_while( for (;; ++size) { kit_buf_adjust_(buf.internal, buf.offset + size + 1); DA_RESIZE(next.data, size + 1); - if (next.data.size != size + 1) + assert(next.data.size == size + 1); + if (next.data.size != size + 1) { next.status = KIT_ERROR_BAD_ALLOC; + return next; + } + kit_str_t destination = { .size = 1, + .values = next.data.values + size }; + i64 n = kit_buf_read_(buf.internal, buf.offset + size, + destination); + if (n != 1) + break; + i8 found = 0; + for (i64 i = 0; i < data.size; i++) + if (data.values[i] == destination.values[0]) { + found = 1; + break; + } + if (!found) + break; + } + next.offset = buf.offset + size; + next.internal = buf.internal; + DA_RESIZE(next.data, size); + if (next.data.size != size) + next.status = KIT_ERROR_BAD_ALLOC; + return next; +} +kit_ib_t kit_ib_none(kit_ib_t buf, kit_str_t data) { + kit_ib_t next; + memset(&next, 0, sizeof next); + if (buf.status != KIT_OK) { + next.status = buf.status; + return next; + } + kit_buf_acquire_(buf.internal); + DA_INIT(next.data, 0, kit_buf_alloc_(buf.internal)); + i64 size = 0; + for (;; ++size) { + kit_buf_adjust_(buf.internal, buf.offset + size + 1); + DA_RESIZE(next.data, size + 1); + assert(next.data.size == size + 1); + if (next.data.size != size + 1) { + next.status = KIT_ERROR_BAD_ALLOC; + return next; + } + kit_str_t destination = { .size = 1, + .values = next.data.values + size }; + i64 n = kit_buf_read_(buf.internal, buf.offset + size, + destination); + if (n != 1) + break; + i8 found = 0; + for (i64 i = 0; i < data.size; i++) + if (data.values[i] == destination.values[0]) { + found = 1; + break; + } + if (found) + break; + } + next.offset = buf.offset + size; + next.internal = buf.internal; + DA_RESIZE(next.data, size); + if (next.data.size != size) + next.status = KIT_ERROR_BAD_ALLOC; + return next; +} +kit_ib_t kit_ib_exact(kit_ib_t buf, kit_str_t data) { + kit_ib_t res = kit_ib_read(buf, data.size); + if (!AR_EQUAL(res.data, data)) + res.status = KIT_ERROR_INTERNAL; + return res; +} +kit_ib_t kit_ib_until(kit_ib_t buf, kit_str_t data) { + kit_ib_t next; + memset(&next, 0, sizeof next); + if (buf.status != KIT_OK) { + next.status = buf.status; + return next; + } + kit_buf_acquire_(buf.internal); + DA_INIT(next.data, 0, kit_buf_alloc_(buf.internal)); + i64 size = 0; + for (;; ++size) { + kit_buf_adjust_(buf.internal, buf.offset + size + 1); + DA_RESIZE(next.data, size + 1); + assert(next.data.size == size + 1); + if (next.data.size != size + 1) { + next.status = KIT_ERROR_BAD_ALLOC; + return next; + } + kit_str_t destination = { .size = 1, + .values = next.data.values + size }; + i64 n = kit_buf_read_(buf.internal, buf.offset + size, + destination); + if (n != 1) + break; + if (size + 1 >= data.size && + AR_EQUAL(kit_str(data.size, + next.data.values + (size + 1 - data.size)), + data)) { + size -= data.size - 1; + break; + } + } + next.offset = buf.offset + size; + next.internal = buf.internal; + DA_RESIZE(next.data, size); + if (next.data.size != size) + next.status = KIT_ERROR_BAD_ALLOC; + return next; +} +kit_ib_t kit_ib_while(kit_ib_t buf, + kit_ib_read_condition_fn condition, + void *context) { + kit_ib_t next; + memset(&next, 0, sizeof next); + if (buf.status != KIT_OK) { + next.status = buf.status; + return next; + } + kit_buf_acquire_(buf.internal); + DA_INIT(next.data, 0, kit_buf_alloc_(buf.internal)); + i64 size = 0; + for (;; ++size) { + kit_buf_adjust_(buf.internal, buf.offset + size + 1); + DA_RESIZE(next.data, size + 1); + assert(next.data.size == size + 1); + if (next.data.size != size + 1) { + next.status = KIT_ERROR_BAD_ALLOC; + return next; + } kit_str_t destination = { .size = 1, .values = next.data.values + size }; i64 n = kit_buf_read_(buf.internal, buf.offset + size, destination); kit_str_t data = { .size = size + 1, .values = next.data.values }; - if (n != 1 || condition == NULL || condition(data) == 0) + if (n != 1 || condition == NULL || condition(data, context) == 0) break; } next.offset = buf.offset + size; @@ -3050,7 +3298,7 @@ kit_ib_handle_t kit_ib_read_while( next.status = KIT_ERROR_BAD_ALLOC; return next; } -void kit_ib_destroy(kit_ib_handle_t buf) { +void kit_ib_destroy(kit_ib_t buf) { kit_buf_release_(buf.internal); DA_DESTROY(buf.data); } @@ -3064,20 +3312,28 @@ void kit_ib_destroy(kit_ib_handle_t buf) { #include <string.h> enum { PATH_BUF_SIZE = 4096 }; #if defined(_WIN32) && !defined(__CYGWIN__) -# include <stdint.h> # ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN 1 +# define WIN32_LEAN_AND_MEAN # endif -# include <Windows.h> -# include <Shlwapi.h> +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include <windows.h> +# include <shlwapi.h> #else # include <dirent.h> +# include <sys/mman.h> # include <sys/stat.h> +# include <fcntl.h> # include <unistd.h> +# include <limits.h> #endif #ifdef __APPLE__ # define st_mtim st_mtimespec #endif +#ifndef PATH_MAX +# define PATH_MAX MAX_PATH +#endif static i32 is_delim(char c) { return c == '/' || c == '\\'; } @@ -3234,56 +3490,33 @@ kit_str_t kit_path_take(kit_str_t path, i64 count) { s.size = i; return s; } -#if defined(_WIN32) && !defined(__CYGWIN__) -static void win32_prepare_path_(WCHAR *buf, kit_str_t path) { - assert(path.size == 0 || path.values != NULL); - assert(path.size + 5 < PATH_BUF_SIZE); - memset(buf, 0, PATH_BUF_SIZE); - buf[0] = L'\\'; - buf[1] = L'\\'; - buf[2] = L'?'; - buf[3] = L'\\'; - if (path.size > 0 && path.size + 5 < PATH_BUF_SIZE) - for (i64 i = 0; i < path.size; i++) { - if (path.values[i] == '/') - buf[4 + i] = L'\\'; - else - buf[4 + i] = path.values[i]; - } -} -# define PREPARE_PATH_BUF_ \ - WCHAR buf[PATH_BUF_SIZE]; \ - win32_prepare_path_(buf, path) -#else -static void unix_prepare_path_(char *buf, kit_str_t path) { +static void kit_prepare_path_(char *buf, kit_str_t path) { assert(path.size == 0 || path.values != NULL); assert(path.size + 1 < PATH_BUF_SIZE); memset(buf, 0, PATH_BUF_SIZE); if (path.size > 0 && path.size + 1 < PATH_BUF_SIZE) memcpy(buf, path.values, path.size); } -# define PREPARE_PATH_BUF_ \ - char buf[PATH_BUF_SIZE]; \ - unix_prepare_path_(buf, path) -#endif -kit_status_t kit_file_create_folder(kit_str_t path) { +#define PREPARE_PATH_BUF_ \ + char buf[PATH_BUF_SIZE]; \ + kit_prepare_path_(buf, path) +kit_status_t kit_folder_create(kit_str_t path) { PREPARE_PATH_BUF_; #if defined(_WIN32) && !defined(__CYGWIN__) - return CreateDirectoryW(buf, NULL) ? KIT_OK + return CreateDirectoryA(buf, NULL) ? KIT_OK : KIT_ERROR_MKDIR_FAILED; #else - return mkdir(buf, 0755) == 0 ? KIT_OK : KIT_ERROR_MKDIR_FAILED; + return mkdir(buf, 0775) == 0 ? KIT_OK : KIT_ERROR_MKDIR_FAILED; #endif } -kit_status_t kit_file_create_folder_recursive(kit_str_t path) { - i64 i; - for (i = 0;; i++) { +kit_status_t kit_folder_create_recursive(kit_str_t path) { + for (i32 i = 0;; i++) { str_t part = kit_path_take(path, i); i32 type = kit_path_type(part); if (type == KIT_PATH_FILE) return KIT_ERROR_FILE_ALREADY_EXISTS; if (type == KIT_PATH_NONE) { - kit_status_t s = kit_file_create_folder(part); + kit_status_t s = kit_folder_create(part); if (s != KIT_OK) return s; } @@ -3295,15 +3528,15 @@ kit_status_t kit_file_create_folder_recursive(kit_str_t path) { kit_status_t kit_file_remove(kit_str_t path) { PREPARE_PATH_BUF_; #if defined(_WIN32) && !defined(__CYGWIN__) - return DeleteFileW(buf) ? KIT_OK : KIT_ERROR_UNLINK_FAILED; + return DeleteFileA(buf) ? KIT_OK : KIT_ERROR_UNLINK_FAILED; #else return unlink(buf) == 0 ? KIT_OK : KIT_ERROR_UNLINK_FAILED; #endif } -kit_status_t kit_file_remove_folder(kit_str_t path) { +kit_status_t kit_folder_remove(kit_str_t path) { PREPARE_PATH_BUF_; #if defined(_WIN32) && !defined(__CYGWIN__) - return RemoveDirectoryW(buf) ? KIT_OK : KIT_ERROR_RMDIR_FAILED; + return RemoveDirectoryA(buf) ? KIT_OK : KIT_ERROR_RMDIR_FAILED; #else return rmdir(buf) == 0 ? KIT_OK : KIT_ERROR_RMDIR_FAILED; #endif @@ -3313,30 +3546,40 @@ kit_status_t kit_file_remove_recursive(kit_str_t path, i32 type = kit_path_type(path); i64 i; switch (type) { - case KIT_PATH_FILE: return kit_file_remove(path); + case KIT_PATH_FILE: { + kit_status_t s = kit_file_remove(path); + assert(s == KIT_OK); + return s; + } case KIT_PATH_FOLDER: { - kit_path_list_t list = kit_file_enum_folder(path, alloc); + kit_path_list_t list = kit_folder_enum(path, alloc); + assert(list.status == KIT_OK); if (list.status != KIT_OK) { kit_path_list_destroy(list); return list.status; } for (i = 0; i < list.files.size; i++) { - str_t s = { .size = list.files.values[i].size, - .values = list.files.values[i].values }; - kit_file_remove_recursive(s, alloc); + str_builder_t full_path = kit_path_join( + path, WRAP_STR(list.files.values[i]), alloc); + kit_status_t s = kit_file_remove_recursive( + WRAP_STR(full_path), alloc); + DA_DESTROY(full_path); + assert(s == KIT_OK); } kit_path_list_destroy(list); - return kit_file_remove_folder(path); + kit_status_t s = kit_folder_remove(path); + assert(s == KIT_OK); + return s; } default:; } - return KIT_ERROR_FILE_DO_NOT_EXIST; + return KIT_ERROR_FILE_DOES_NOT_EXIST; } kit_path_type_t kit_path_type(kit_str_t path) { PREPARE_PATH_BUF_; #if defined(_WIN32) && !defined(__CYGWIN__) - if (PathFileExistsW(buf)) { - if ((GetFileAttributesW(buf) & FILE_ATTRIBUTE_DIRECTORY) != 0) + if (PathFileExistsA(buf)) { + if ((GetFileAttributesA(buf) & FILE_ATTRIBUTE_DIRECTORY) != 0) return KIT_PATH_FOLDER; else return KIT_PATH_FILE; @@ -3357,7 +3600,7 @@ kit_file_info_t kit_file_info(kit_str_t path) { memset(&result, 0, sizeof result); PREPARE_PATH_BUF_; #if defined(_WIN32) && !defined(__CYGWIN__) - HANDLE f = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL, + HANDLE f = CreateFileA(buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (f != INVALID_HANDLE_VALUE) { FILETIME ft; @@ -3381,54 +3624,55 @@ kit_file_info_t kit_file_info(kit_str_t path) { if (stat(buf, &info) == 0 && S_ISREG(info.st_mode)) { result.size = (i64) info.st_size; # ifndef st_mtime - /* No support for nanosecond timestamps. - */ + // No support for nanosecond timestamps. + // result.time_modified_sec = (i64) info.st_mtime; # else result.time_modified_sec = (i64) info.st_mtim.tv_sec; result.time_modified_nsec = (i32) info.st_mtim.tv_nsec; # endif - result.status = KIT_OK; + result.status = KIT_OK; return result; } #endif - result.status = KIT_ERROR_FILE_DO_NOT_EXIST; + result.status = KIT_ERROR_FILE_DOES_NOT_EXIST; return result; } -kit_path_list_t kit_file_enum_folder(kit_str_t path, - kit_allocator_t *alloc) { +kit_path_list_t kit_folder_enum(kit_str_t path, + kit_allocator_t *alloc) { PREPARE_PATH_BUF_; kit_path_list_t result = { .status = KIT_OK }; DA_INIT(result.files, 0, alloc); #if defined(_WIN32) && !defined(__CYGWIN__) - if (path.size + 7 >= PATH_BUF_SIZE) { + if (path.size + 3 >= PATH_BUF_SIZE) { result.status = KIT_ERROR_PATH_TOO_LONG; return result; } - buf[path.size + 4] = '\\'; - buf[path.size + 5] = '*'; - WIN32_FIND_DATAW data; - HANDLE find = FindFirstFileW(buf, &data); + buf[path.size] = '\\'; + buf[path.size + 1] = '*'; + WIN32_FIND_DATAA data; + HANDLE find = FindFirstFileA(buf, &data); if (find == INVALID_HANDLE_VALUE) return result; do { + if (strcmp(data.cFileName, ".") == 0 || + strcmp(data.cFileName, "..") == 0) + continue; i64 n = result.files.size; DA_RESIZE(result.files, n + 1); if (result.files.size != n + 1) { result.status = KIT_ERROR_BAD_ALLOC; break; } - i64 size = 0; - while (size < MAX_PATH && data.cFileName[size] != L'\0') size++; + i64 size = (i64) strlen(data.cFileName); DA_INIT(result.files.values[n], size, alloc); if (result.files.values[n].size != size) { DA_RESIZE(result.files, n); result.status = KIT_ERROR_BAD_ALLOC; break; } - for (i64 i = 0; i < size; i++) - result.files.values[n].values[i] = data.cFileName[i]; - } while (FindNextFileW(find, &data) != 0); + memcpy(result.files.values[n].values, data.cFileName, size); + } while (FindNextFileA(find, &data) != 0); FindClose(find); #else DIR *directory = opendir(buf); @@ -3466,6 +3710,135 @@ void kit_path_list_destroy(kit_path_list_t list) { DA_DESTROY(list.files.values[i]); DA_DESTROY(list.files); } +kit_mapped_file_t kit_file_map(kit_str_t path, i64 size, i32 mode) { + assert(size > 0); + assert(path.size > 0); + assert(path.size <= PATH_MAX); + assert(path.values != NULL); + kit_mapped_file_t mf; + memset(&mf, 0, sizeof mf); + if (size <= 0) { + mf.status = KIT_ERROR_INVALID_SIZE; + return mf; + } + if (path.size <= 0) { + mf.status = KIT_ERROR_INVALID_ARGUMENT; + return mf; + } + if (path.size > PATH_MAX) { + mf.status = KIT_ERROR_PATH_TOO_LONG; + return mf; + } +#if defined(_WIN32) && !defined(__CYGWIN__) + char buf[MAX_PATH + 1]; + memcpy(buf, path.values, path.size); + buf[path.size] = '\0'; + HANDLE file = CreateFileA( + buf, GENERIC_READ | GENERIC_WRITE, + mode == FILE_MAP_SHARED ? FILE_SHARE_READ | FILE_SHARE_WRITE + : 0, + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) { + mf.status = KIT_ERROR_OPEN_FAILED; + return mf; + } + LONG high = (LONG) (size >> 32); + if (SetFilePointer(file, (LONG) size, &high, FILE_BEGIN) == + INVALID_SET_FILE_POINTER) { + CloseHandle(file); + assert(0); + mf.status = KIT_ERROR_TRUNCATE_FAILED; + return mf; + } + if (!SetEndOfFile(file)) { + CloseHandle(file); + assert(0); + mf.status = KIT_ERROR_TRUNCATE_FAILED; + return mf; + } + HANDLE map = CreateFileMappingA(file, NULL, PAGE_READWRITE, + (DWORD) (size >> 32), (DWORD) size, + NULL); + if (map == INVALID_HANDLE_VALUE) { + CloseHandle(file); + assert(0); + mf.status = KIT_ERROR_MAP_FAILED; + return mf; + } + void *p = MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0, + (SIZE_T) size); + if (p == NULL) { + CloseHandle(map); + CloseHandle(file); + assert(0); + mf.status = KIT_ERROR_MAP_FAILED; + return mf; + } + mf.status = KIT_OK; + mf.size = size; + mf.bytes = p; + mf._file = file; + mf._map = map; +#else + char buf[PATH_MAX + 1]; + memcpy(buf, path.values, path.size); + buf[path.size] = '\0'; + i32 fd = open(buf, O_RDWR | O_CREAT, 0664); + if (fd == -1) { + mf.status = KIT_ERROR_OPEN_FAILED; + return mf; + } + if (ftruncate(fd, size) == -1) { + close(fd); + assert(0); + mf.status = KIT_ERROR_TRUNCATE_FAILED; + return mf; + } + void *p = mmap( + NULL, size, PROT_READ | PROT_WRITE, + mode == KIT_FILE_MAP_SHARED ? MAP_SHARED : MAP_PRIVATE, fd, 0); + if (p == MAP_FAILED) { + close(fd); + assert(0); + mf.status = KIT_ERROR_MAP_FAILED; + return mf; + } + mf.status = KIT_OK; + mf.size = size; + mf.bytes = (u8 *) p; + mf._fd = fd; +#endif + return mf; +} +kit_status_t kit_file_sync(kit_mapped_file_t *mf) { + assert(mf != NULL); + if (mf == NULL) + return KIT_ERROR_INVALID_ARGUMENT; + kit_status_t status = KIT_OK; +#if !defined(_WIN32) || defined(__CYGWIN__) + if (msync(mf->bytes, mf->size, MS_SYNC) != 0) + status |= KIT_ERROR_SYNC_FAILED; +#endif + return status; +} +kit_status_t kit_file_unmap(kit_mapped_file_t *mf) { + assert(mf != NULL); + if (mf == NULL) + return KIT_ERROR_INVALID_ARGUMENT; + kit_status_t status = KIT_OK; +#if defined(_WIN32) && !defined(__CYGWIN__) + if (!UnmapViewOfFile(mf->bytes)) + status |= KIT_ERROR_UNMAP_FAILED; + if (!CloseHandle(mf->_map) || !CloseHandle(mf->_file)) + status |= KIT_ERROR_CLOSE_FAILED; +#else + if (munmap(mf->bytes, mf->size) != 0) + status |= KIT_ERROR_UNMAP_FAILED; + if (close(mf->_fd) != 0) + status |= KIT_ERROR_CLOSE_FAILED; +#endif + return status; +} /********************************************************************* * * * File: source/kit/mersenne_twister_64.c * @@ -3737,28 +4110,28 @@ kit_shared_memory_t kit_shared_memory_open(kit_str_t name, i64 size, : O_RDWR, mode == KIT_SHARED_MEMORY_CREATE ? 0660 : 0); if (fd == -1) { - mem.status = KIT_ERROR_SHM_OPEN_FAILED; + mem.status = KIT_ERROR_OPEN_FAILED; return mem; } if (mode == KIT_SHARED_MEMORY_CREATE && ftruncate(fd, size) == -1) { shm_unlink(mem._name); assert(0); - mem.status = KIT_ERROR_FTRUNCATE_FAILED; + mem.status = KIT_ERROR_TRUNCATE_FAILED; return mem; } void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); if (p == MAP_FAILED) { shm_unlink(mem._name); assert(0); - mem.status = KIT_ERROR_MMAP_FAILED; + mem.status = KIT_ERROR_MAP_FAILED; return mem; } mem.status = KIT_OK; mem.size = size; mem.bytes = (u8 *) p; mem._owned = (mode == KIT_SHARED_MEMORY_CREATE); - mem._fd = fd; return mem; } kit_status_t kit_shared_memory_close(kit_shared_memory_t *mem) { @@ -3767,11 +4140,29 @@ kit_status_t kit_shared_memory_close(kit_shared_memory_t *mem) { return KIT_ERROR_INVALID_ARGUMENT; kit_status_t status = KIT_OK; if (munmap(mem->bytes, mem->size) != 0) - status |= KIT_ERROR_MUNMAP_FAILED; + status |= KIT_ERROR_UNMAP_FAILED; if (mem->_owned && shm_unlink(mem->_name) != 0) status |= KIT_ERROR_UNLINK_FAILED; return status; } +kit_status_t kit_shared_memory_clean(kit_str_t name) { + assert(name.size > 0); + assert(name.size + 1 <= NAME_MAX); + assert(name.values != NULL); + if (name.size <= 0) + return KIT_ERROR_INVALID_NAME; + if (name.size + 1 > NAME_MAX) + return KIT_ERROR_NAME_TOO_LONG; + for (i64 i = 0; i < name.size; i++) + if (name.values[i] == '/' || name.values[i] == '\\') + return KIT_ERROR_INVALID_NAME; + char buf[NAME_MAX + 1] = "/"; + memcpy(buf + 1, name.values, name.size); + buf[1 + name.size] = '\0'; + if (shm_unlink(buf) != 0) + return KIT_ERROR_UNLINK_FAILED; + return KIT_OK; +} #endif /********************************************************************* * * @@ -3811,18 +4202,19 @@ kit_shared_memory_t kit_shared_memory_open(kit_str_t name, i64 size, memcpy(buf + 7, name.values, name.size); buf[7 + name.size] = '\0'; HANDLE h = mode == KIT_SHARED_MEMORY_CREATE - ? CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, - PAGE_READWRITE, 0, size, buf) + ? CreateFileMappingA( + INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + (DWORD) (size >> 32), (DWORD) size, buf) : OpenFileMappingA(FILE_MAP_ALL_ACCESS, 0, buf); - if (h == NULL) { - mem.status = KIT_ERROR_SHM_OPEN_FAILED; + if (h == INVALID_HANDLE_VALUE) { + mem.status = KIT_ERROR_OPEN_FAILED; return mem; } - void *p = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, size); - assert(p != NULL); + void *p = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, + (SIZE_T) size); if (p == NULL) { CloseHandle(h); - mem.status = KIT_ERROR_MMAP_FAILED; + mem.status = KIT_ERROR_MAP_FAILED; return mem; } mem.status = KIT_OK; @@ -3835,11 +4227,352 @@ kit_status_t kit_shared_memory_close(kit_shared_memory_t *mem) { assert(mem != NULL); i32 status = KIT_OK; if (!UnmapViewOfFile(mem->bytes)) - status |= KIT_ERROR_MUNMAP_FAILED; + status |= KIT_ERROR_UNMAP_FAILED; if (!CloseHandle(mem->_handle)) status |= KIT_ERROR_UNLINK_FAILED; return status; } +kit_status_t kit_shared_memory_clean(kit_str_t name) { + // Do nothing. + // + return KIT_OK; +} #endif +/********************************************************************* + * * + * File: source/kit/xml.c * + * * + *********************************************************************/ +#include <assert.h> +typedef struct { + ib_t last; + kit_str_builder_t text; + kit_da_xml_t tags; +} kit_xml_intermediate_t; +static kit_status_t kit_xml_unescape_(str_builder_t *str) { + assert(str != NULL); + str_builder_t buf; + DA_INIT(buf, str->size, str->alloc); + buf.size = 0; + for (i64 i = 0; i < str->size; i++) + if (str->values[i] != '&') + buf.values[buf.size++] = str->values[i]; + else { + i64 n = 1; + while (i + n < str->size && str->values[i + n] != ';') n++; + if (i + n >= str->size) { + DA_DESTROY(buf); + return KIT_ERROR_INTERNAL; + } + if (n == 3 && memcmp(str->values + i, "<", 4) == 0) + buf.values[buf.size++] = '<'; + else if (n == 3 && memcmp(str->values + i, ">", 4) == 0) + buf.values[buf.size++] = '>'; + else if (n == 4 && memcmp(str->values + i, "&", 5) == 0) + buf.values[buf.size++] = '&'; + else if (n == 5 && memcmp(str->values + i, """, 6) == 0) + buf.values[buf.size++] = '"'; + else if (n == 5 && memcmp(str->values + i, "'", 6) == 0) + buf.values[buf.size++] = '\''; + else { + DA_DESTROY(buf); + return KIT_ERROR_INTERNAL; + } + i += n; + } + DA_DESTROY(*str); + *str = buf; + return KIT_OK; +} +static ib_t kit_xml_parse_text_(ib_t begin) { + ib_t text = ib_until(begin, SZ("<")); + ib_t last = ib_copy(text); + for (;;) { + ib_t comment_open = ib_exact(last, SZ("<!--")); + if (comment_open.status != KIT_OK) { + ib_destroy(comment_open); + break; + } + ib_t comment_text = ib_until(comment_open, SZ("-->")); + ib_t comment_close = ib_exact(comment_text, SZ("-->")); + ib_t next_text = ib_until(comment_close, SZ("<")); + if (next_text.status == KIT_OK && next_text.data.size > 0) { + i64 n = text.data.size; + DA_RESIZE(text.data, n + next_text.data.size); + if (text.data.size != n + next_text.data.size) + next_text.status = KIT_ERROR_BAD_ALLOC; + else + memcpy(text.data.values + n, next_text.data.values, + next_text.data.size); + } + ib_destroy(last); + last = ib_copy(next_text); + ib_destroy(comment_open); + ib_destroy(comment_text); + ib_destroy(comment_close); + ib_destroy(next_text); + } + // move + DA_DESTROY(last.data); + last.data = text.data; + memset(&text.data, 0, sizeof text.data); + kit_status_t s = kit_xml_unescape_(&last.data); + if (s != KIT_OK) + last.status = s; + ib_destroy(text); + return last; +} +static ib_t kit_xml_parse_string_(ib_t begin) { + ib_t quotes_open = ib_exact(begin, SZ("\"")); + ib_t apostr_open = ib_exact(begin, SZ("'")); + ib_t open = quotes_open.status == KIT_OK ? quotes_open + : apostr_open; + ib_t text = ib_until(open, WRAP_STR(open.data)); + ib_t close = ib_exact(text, WRAP_STR(open.data)); + // move + DA_DESTROY(close.data); + close.data = text.data; + memset(&text.data, 0, sizeof text.data); + kit_status_t s = kit_xml_unescape_(&close.data); + if (s == KIT_OK) + close.status = s; + ib_destroy(quotes_open); + ib_destroy(apostr_open); + ib_destroy(text); + return close; +} +static kit_xml_intermediate_t kit_xml_parse_buf_( + ib_t begin, kit_allocator_t *alloc) { + kit_xml_intermediate_t res; + memset(&res, 0, sizeof res); + ib_t last, spaces; + memset(&last, 0, sizeof last); + memset(&spaces, 0, sizeof spaces); + ib_t tag_text = kit_xml_parse_text_(begin); + last = ib_copy(tag_text); + DA_INIT(res.tags, 0, alloc); + for (;;) { + ib_t tagend_open = ib_exact(last, SZ("</")); + ib_destroy(tagend_open); + if (tagend_open.status == KIT_OK) + break; + ib_t tag_open = ib_exact(last, SZ("<")); + if (tag_open.status != KIT_OK) { + ib_destroy(tag_open); + break; + } + xml_t tag; + memset(&tag, 0, sizeof tag); + ib_t decl_open = ib_exact(tag_open, SZ("?")); + ib_destroy(last); + if (decl_open.status == KIT_OK) { + tag.is_declaration = 1; + last = ib_copy(decl_open); + } else + last = ib_copy(tag_open); + ib_destroy(decl_open); + spaces = ib_any(last, SZ(" \t\r\n")); + ib_t tag_name = ib_none(spaces, SZ(" \t\r\n/>")); + ib_destroy(spaces); + DA_INIT(tag.properties, 0, alloc); + ib_destroy(last); + last = ib_copy(tag_name); + for (;;) { + spaces = ib_any(last, SZ(" \t\r\n")); + ib_t property = ib_none(spaces, SZ(" \t\r\n=?/>")); + ib_destroy(spaces); + if (property.status != KIT_OK || property.data.size == 0) { + ib_destroy(property); + break; + } + spaces = ib_any(property, SZ(" \t\r\n")); + ib_t equals = ib_exact(spaces, SZ("=")); + ib_destroy(spaces); + spaces = ib_any(equals, SZ(" \t\r\n")); + ib_t value = kit_xml_parse_string_(spaces); + ib_destroy(spaces); + ib_destroy(last); + last = ib_copy(value); + if (last.status == KIT_OK) { + i64 n = tag.properties.size; + DA_RESIZE(tag.properties, n + 1); + if (tag.properties.size != n + 1) { + last.status = KIT_ERROR_BAD_ALLOC; + DA_DESTROY(tag.properties); + } else { + // move + tag.properties.values[n].name = property.data; + memset(&property.data, 0, sizeof property.data); + // move + tag.properties.values[n].value = value.data; + memset(&value.data, 0, sizeof value.data); + } + } + ib_destroy(property); + ib_destroy(equals); + ib_destroy(value); + } + spaces = ib_any(last, SZ(" \t\r\n")); + if (tag.is_declaration) { + ib_t tag_decl_close = ib_exact(spaces, SZ("?>")); + ib_destroy(spaces); + ib_destroy(last); + last = tag_decl_close; + DA_INIT(tag.text, 0, alloc); + DA_INIT(tag.children, 0, alloc); + } else { + ib_t tag_close = ib_exact(spaces, SZ(">")); + ib_t tag_close_empty = ib_exact(spaces, SZ("/>")); + ib_destroy(spaces); + if (tag_close.status == KIT_OK) { + kit_xml_intermediate_t im = kit_xml_parse_buf_(tag_close, + alloc); + tag.text = im.text; + tag.children = im.tags; + tagend_open = ib_exact(im.last, SZ("</")); + ib_destroy(im.last); + spaces = ib_any(tagend_open, SZ(" \t\r\n")); + ib_t tagend_name = ib_exact(spaces, WRAP_STR(tag_name.data)); + ib_destroy(spaces); + spaces = ib_any(tagend_name, SZ(" \t\r\n")); + ib_t tagend_close = ib_exact(spaces, SZ(">")); + ib_destroy(spaces); + ib_destroy(tagend_open); + ib_destroy(tagend_name); + ib_destroy(last); + last = tagend_close; + } else if (tag_close_empty.status == KIT_OK) { + ib_destroy(last); + last = ib_copy(tag_close_empty); + DA_INIT(tag.text, 0, alloc); + DA_INIT(tag.children, 0, alloc); + } else + last.status = KIT_ERROR_INTERNAL; + ib_destroy(tag_close); + ib_destroy(tag_close_empty); + } + ib_t tag_tail = kit_xml_parse_text_(last); + ib_destroy(last); + last = ib_copy(tag_tail); + if (last.status == KIT_OK) { + i64 n = res.tags.size; + DA_RESIZE(res.tags, n + 1); + if (res.tags.size != n + 1) { + last.status = KIT_ERROR_BAD_ALLOC; + xml_destroy(&tag); + } else { + // move + tag.tag = tag_name.data; + memset(&tag_name.data, 0, sizeof tag_name.data); + // move + tag.tail = tag_tail.data; + memset(&tag_tail.data, 0, sizeof tag_tail.data); + res.tags.values[n] = tag; + } + } else + xml_destroy(&tag); + ib_destroy(tag_open); + ib_destroy(tag_name); + ib_destroy(tag_tail); + } + if (last.status != KIT_OK) { + for (i64 i = 0; i < res.tags.size; i++) + xml_destroy(res.tags.values + i); + DA_DESTROY(res.text); + DA_DESTROY(res.tags); + } else { + // move + res.text = tag_text.data; + memset(&tag_text.data, 0, sizeof tag_text.data); + } + ib_destroy(tag_text); + res.last = last; + return res; +} +kit_xml_parse_result_t kit_xml_parse(kit_is_handle_t is, + kit_allocator_t *alloc) { + ib_t ib = ib_wrap(is, alloc); + kit_xml_intermediate_t im = kit_xml_parse_buf_(ib, alloc); + ib_destroy(ib); + kit_xml_parse_result_t res; + memset(&res, 0, sizeof res); + res.status = im.last.status; + ib_destroy(im.last); + if (res.status != KIT_OK) + return res; + if (im.text.size == 0 && im.tags.size == 1) { + res.xml = im.tags.values[0]; + DA_DESTROY(im.text); + DA_DESTROY(im.tags); + return res; + } + DA_INIT(res.xml.tag, 0, alloc); + DA_INIT(res.xml.tail, 0, alloc); + DA_INIT(res.xml.properties, 0, alloc); + res.xml.text = im.text; + res.xml.children = im.tags; + return res; +} +kit_xml_text_t kit_xml_print(kit_xml_t *xml, kit_allocator_t *alloc) { + assert(xml != NULL); + xml_text_t result; + memset(&result, 0, sizeof result); + result.status = KIT_ERROR_NOT_IMPLEMENTED; + return result; +} +static kit_status_t kit_xml_append_text_(str_builder_t *buf, + xml_t *xml) { + assert(buf != NULL); + assert(xml != NULL); + i64 n = buf->size; + DA_RESIZE(*buf, n + xml->text.size); + assert(buf->size == n + xml->text.size); + if (buf->size != n + xml->text.size) + return KIT_ERROR_BAD_ALLOC; + memcpy(buf->values + n, xml->text.values, xml->text.size); + for (i64 i = 0; i < xml->children.size; i++) { + kit_status_t s = kit_xml_append_text_(buf, + xml->children.values + i); + if (s != KIT_OK) + return s; + str_t tail = WRAP_STR(xml->children.values[i].tail); + if (tail.size <= 0) + continue; + n = buf->size; + DA_RESIZE(*buf, n + tail.size); + assert(buf->size == n + tail.size); + if (buf->size != n + tail.size) + return KIT_ERROR_BAD_ALLOC; + memcpy(buf->values + n, tail.values, tail.size); + } + return KIT_OK; +} +kit_xml_text_t kit_xml_full_text(kit_xml_t *xml, + kit_allocator_t *alloc) { + kit_xml_text_t res; + res.status = KIT_OK; + DA_INIT(res.text, 0, alloc); + if (xml != NULL) + res.status = kit_xml_append_text_(&res.text, xml); + else + res.status = KIT_ERROR_INVALID_ARGUMENT; + return res; +} +void kit_xml_destroy(kit_xml_t *xml) { + assert(xml != NULL); + if (xml == NULL) + return; + for (i64 i = 0; i < xml->properties.size; i++) { + DA_DESTROY(xml->properties.values[i].name); + DA_DESTROY(xml->properties.values[i].value); + } + for (i64 i = 0; i < xml->children.size; i++) + kit_xml_destroy(xml->children.values + i); + DA_DESTROY(xml->tag); + DA_DESTROY(xml->text); + DA_DESTROY(xml->tail); + DA_DESTROY(xml->properties); + DA_DESTROY(xml->children); +} #endif #endif |