summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2023-09-22 19:48:59 +0200
committerMitya Selivanov <automainint@guattari.tech>2023-09-22 19:48:59 +0200
commit10ff42656df228b5d0f5d9cc4ad194940d227dee (patch)
tree90722b9043e63c1d008a57085cd342373fef2dd8
parent136742c16b42b3a2ddc2ab5ce5f1a384e8d2fa09 (diff)
downloadkit-10ff42656df228b5d0f5d9cc4ad194940d227dee.zip
Update single header
-rw-r--r--gen_inl.c39
-rw-r--r--include/kit.inl.h1009
2 files changed, 896 insertions, 152 deletions
diff --git a/gen_inl.c b/gen_inl.c
index 31af196..c6f5d3c 100644
--- a/gen_inl.c
+++ b/gen_inl.c
@@ -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, "&lt;", 4) == 0)
+ buf.values[buf.size++] = '<';
+ else if (n == 3 && memcmp(str->values + i, "&gt;", 4) == 0)
+ buf.values[buf.size++] = '>';
+ else if (n == 4 && memcmp(str->values + i, "&amp;", 5) == 0)
+ buf.values[buf.size++] = '&';
+ else if (n == 5 && memcmp(str->values + i, "&quot;", 6) == 0)
+ buf.values[buf.size++] = '"';
+ else if (n == 5 && memcmp(str->values + i, "&apos;", 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