summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.md2
-rw-r--r--gen_cmake.c223
-rw-r--r--gen_inl.c134
-rw-r--r--include/kit.inl.h1118
-rw-r--r--source/kit/CMakeLists.txt10
-rw-r--r--source/kit/array_ref.h4
-rw-r--r--source/kit/file.h4
-rw-r--r--source/kit/string_ref.h4
-rw-r--r--source/kit_test/CMakeLists.txt6
-rw-r--r--source/test/unittests/CMakeLists.txt11
11 files changed, 1502 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index 18d5ae0..50dcc4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
/*build*/
*.swp
+gen_inl
+gen_cmake
diff --git a/README.md b/README.md
index 0dfffb3..f6e9a4f 100644
--- a/README.md
+++ b/README.md
@@ -17,4 +17,6 @@
Condition variables, mutual exclusions and threads implementation was forked from [Mesa][mesa_link] source code.
+Folder `include` contains header-only version of this library.
+
[mesa_link]: https://gitlab.freedesktop.org/mesa/mesa
diff --git a/gen_cmake.c b/gen_cmake.c
new file mode 100644
index 0000000..c3bc110
--- /dev/null
+++ b/gen_cmake.c
@@ -0,0 +1,223 @@
+#if 0
+gcc -fsanitize=address,leak gen_cmake.c -o gen_cmake && ./gen_cmake
+exit
+#endif
+
+#include "include/kit.inl.h"
+
+#include <stdio.h>
+
+kit_allocator_t ALLOC;
+
+typedef struct {
+ kit_status_t status;
+ int have_cmakelists;
+} gen_result_t;
+
+/* FIXME
+ * Barbarian strings!!!
+ */
+char const *sz_(str_t const s) {
+ static char buf[1000];
+ int n = s.size;
+ if (n > 999)
+ n = 999;
+ memcpy(buf, s.values, s.size);
+ buf[s.size] = '\0';
+ return buf;
+}
+
+int make_sz(string_t *const s) {
+ ptrdiff_t const n = s->size;
+ DA_RESIZE(*s, n + 1);
+ if (s->size != n + 1) {
+ printf("Error: Bad alloc.\n");
+ return 0;
+ }
+ s->values[n] = '\0';
+ return 1;
+}
+
+int is_header(str_t const file) {
+ return file.size > 2 && file.values[file.size - 2] == '.' &&
+ file.values[file.size - 1] == 'h';
+}
+
+int is_source(str_t const file) {
+ return file.size > 2 && file.values[file.size - 2] == '.' &&
+ file.values[file.size - 1] == 'c';
+}
+
+gen_result_t gen_cmakelists_for(str_t const target,
+ str_t const folder) {
+ gen_result_t result = { KIT_OK, 0 };
+
+ path_list_t const list = file_enum_folder(folder, ALLOC);
+
+ if (list.status != KIT_OK) {
+ printf("Error: file_enum_folder failed with code %d.\n",
+ list.status);
+ result.status = list.status;
+ return result;
+ }
+
+ int have_headers = 0;
+ int have_sources = 0;
+ int have_folders = 0;
+
+ FILE *out = NULL;
+
+ string_t cmakelists_path = path_join(folder, SZ("CMakeLists.txt"),
+ ALLOC);
+
+ if (!make_sz(&cmakelists_path)) {
+ result.status = KIT_ERROR_BAD_ALLOC;
+ result.have_cmakelists = 0;
+ DA_DESTROY(cmakelists_path);
+ path_list_destroy(list);
+ return result;
+ }
+
+#define OPEN_CMAKELISTS \
+ do { \
+ if (out == NULL) { \
+ out = fopen(cmakelists_path.values, "wt"); \
+ if (out == NULL) { \
+ result.status = 101; \
+ result.have_cmakelists = 0; \
+ DA_DESTROY(cmakelists_path); \
+ path_list_destroy(list); \
+ return result; \
+ } \
+ } \
+ } while (0)
+
+#define CHECK_TYPE(type_) \
+ string_t const full_path_ = path_join(folder, WRAP_STR(item), \
+ ALLOC); \
+ int check_ = path_type(WRAP_STR(full_path_)) == (type_); \
+ DA_DESTROY(full_path_); \
+ if (!check_) \
+ continue
+
+ for (ptrdiff_t i = 0; i < list.files.size; i++) {
+ str_t const item = WRAP_STR(list.files.values[i]);
+
+ CHECK_TYPE(PATH_FILE);
+
+ if (!is_header(item))
+ continue;
+
+ OPEN_CMAKELISTS;
+
+ if (!have_headers)
+ fprintf(out, "target_sources(\n %*s\n PUBLIC",
+ (int) target.size, sz_(target));
+
+ fprintf(
+ out,
+ "\n $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/%*s>",
+ (int) item.size, sz_(item));
+
+ have_headers = 1;
+ }
+
+ ptrdiff_t const LINE_LIMIT = 80;
+ ptrdiff_t line_length = LINE_LIMIT;
+
+ for (ptrdiff_t i = 0; i < list.files.size; i++) {
+ str_t const item = WRAP_STR(list.files.values[i]);
+
+ CHECK_TYPE(PATH_FILE);
+
+ if (!is_source(item))
+ continue;
+
+ OPEN_CMAKELISTS;
+
+ if (!have_headers && !have_sources)
+ fprintf(out, "target_sources(\n %*s\n PRIVATE",
+ (int) target.size, sz_(target));
+ else if (!have_sources)
+ fprintf(out, "\n PRIVATE");
+
+ if (line_length + item.size > LINE_LIMIT) {
+ fprintf(out, "\n ");
+ line_length = 5;
+ }
+
+ fprintf(out, " %*s", (int) item.size, sz_(item));
+ line_length += 1 + item.size;
+
+ have_sources = 1;
+ }
+
+ if (have_headers || have_sources)
+ fprintf(out, ")\n");
+
+ for (ptrdiff_t i = 0; i < list.files.size; i++) {
+ str_t const item = WRAP_STR(list.files.values[i]);
+
+ CHECK_TYPE(PATH_FOLDER);
+
+ string_t const subfolder = path_join(folder, item, ALLOC);
+ gen_result_t const r = gen_cmakelists_for(target,
+ WRAP_STR(subfolder));
+ DA_DESTROY(subfolder);
+ if (r.status != KIT_OK) {
+ result.status = r.status;
+ break;
+ }
+
+ if (!r.have_cmakelists)
+ continue;
+
+ OPEN_CMAKELISTS;
+
+ if (have_headers || have_sources)
+ fprintf(out, "\n");
+
+ fprintf(out, "add_subdirectory(%*s)\n", (int) item.size,
+ sz_(item));
+
+ have_folders = 1;
+ }
+
+ if (out != NULL)
+ fclose(out);
+
+ DA_DESTROY(cmakelists_path);
+ path_list_destroy(list);
+
+ if (result.status == KIT_OK)
+ result.have_cmakelists = have_headers || have_sources ||
+ have_folders;
+
+ if (!result.have_cmakelists && out != NULL)
+ file_remove(WRAP_STR(cmakelists_path));
+
+ return result;
+}
+
+int main(int argc, char **argv) {
+ ALLOC = kit_alloc_default();
+
+ str_t const targets[] = { SZ("kit"), SZ("kit_test"),
+ SZ("kit_test_suite") };
+
+ string_t folders[] = { path_norm(SZ("./source/kit"), ALLOC),
+ path_norm(SZ("./source/kit_test"), ALLOC),
+ path_norm(SZ("./source/test/unittests"),
+ ALLOC) };
+
+ int ok = 1;
+
+ for (ptrdiff_t i = 0; i < sizeof folders / sizeof *folders; i++)
+ ok = ok && gen_cmakelists_for(targets[i], WRAP_STR(folders[i]))
+ .status == KIT_OK;
+
+ for (ptrdiff_t i = 0; i < sizeof folders / sizeof *folders; i++)
+ DA_DESTROY(folders[i]);
+
+ return ok ? 0 : 1;
+}
diff --git a/gen_inl.c b/gen_inl.c
new file mode 100644
index 0000000..dab36dc
--- /dev/null
+++ b/gen_inl.c
@@ -0,0 +1,134 @@
+#if 0
+gcc gen_inl.c -o gen_inl && ./gen_inl
+exit
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char const *const SOURCES[] = {
+ "./source/kit/status.h", "./source/kit/allocator.h",
+ "./source/kit/array_ref.h", "./source/kit/dynamic_array.h",
+ "./source/kit/string_ref.h", "./source/kit/file.h",
+ "./source/kit/allocator.c", "./source/kit/array_ref.c",
+ "./source/kit/dynamic_array.c", "./source/kit/file.c"
+};
+
+char const *repeat(int n, char c) {
+ static char buf[200];
+ for (int i = 0; i < n && i < 199; i++) buf[i] = c;
+ buf[n] = '\0';
+ return buf;
+}
+
+int skip_whitespaces(char const *const line, int i) {
+ while (line[i] == ' ') i++;
+ return i;
+}
+
+int skip(char const *const line, int i, char const *const s) {
+ int j = 0;
+ while (s[j] != '\0') {
+ if (line[i] != s[j])
+ return -1;
+ i++;
+ j++;
+ }
+ return i;
+}
+
+int is_local_include(char const *const line) {
+ if (line[0] != '#')
+ return 0;
+ int i = skip_whitespaces(line, 1);
+ i = skip(line, i, "include");
+ if (i == -1)
+ return 0;
+ i = skip_whitespaces(line, i);
+ if (line[i] != '"')
+ return 0;
+ return 1;
+}
+
+int is_empty_line(char const *const line) {
+ int i = skip_whitespaces(line, 0);
+ return line[i] == '\0' || line[i] == '\n';
+}
+
+int write_file(FILE *out, char const *const source) {
+ assert(out != NULL);
+ assert(source != NULL);
+
+ FILE *in = fopen(source, "rt");
+
+ if (in == NULL) {
+ fprintf(stderr, "File not found: %s\n", source);
+ return 1;
+ }
+
+ fprintf(out, "/*%s*\n", repeat(70, '*'));
+ fprintf(out, " *%s*\n", repeat(70, ' '));
+ fprintf(out, " *%s*\n", repeat(70, ' '));
+ fprintf(out, " * FILE: %s%s*\n", source,
+ repeat(58 - strlen(source), ' '));
+ fprintf(out, " *%s*\n", repeat(70, ' '));
+ fprintf(out, " *%s*\n", repeat(70, ' '));
+ fprintf(out, " *%s*/\n", repeat(70, '*'));
+
+ char line[200];
+ char buf[400];
+ int prev_empty = 0;
+
+ while (fgets(line, 199, in) != NULL) {
+ int empty = is_empty_line(line) || is_local_include(line);
+
+ if (empty) {
+ if (!prev_empty)
+ fprintf(out, "\n");
+ } else {
+ int j = 0;
+ for (int i = 0; line[i] != '\0'; i++) {
+ if (line[i] == '\t') {
+ buf[j++] = ' ';
+ buf[j++] = ' ';
+ } else if (line[i] != '\n' && line[i] != '\r')
+ buf[j++] = line[i];
+ }
+ buf[j] = '\0';
+ fprintf(out, "%s\n", buf);
+ }
+
+ prev_empty = empty;
+ }
+
+ fclose(in);
+ fprintf(out, "\n");
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ char const *const out_file = "./include/kit.inl.h";
+ FILE *out = fopen(out_file, "wt");
+ if (out == NULL) {
+ fprintf(stderr, "Can't write: %s\n", out_file);
+ return 1;
+ }
+
+ fprintf(out, "#ifndef KIT_INL_H\n");
+ fprintf(out, "#define KIT_INL_H\n");
+ fprintf(out, "\n");
+
+ for (int i = 0; i < sizeof SOURCES / sizeof *SOURCES; i++)
+ if (write_file(out, SOURCES[i]) != 0) {
+ fclose(out);
+ return 1;
+ }
+
+ fprintf(out, "\n");
+ fprintf(out, "#endif\n");
+
+ fclose(out);
+ return 0;
+}
diff --git a/include/kit.inl.h b/include/kit.inl.h
new file mode 100644
index 0000000..cfa123e
--- /dev/null
+++ b/include/kit.inl.h
@@ -0,0 +1,1118 @@
+#ifndef KIT_INL_H
+#define KIT_INL_H
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/status.h *
+ * *
+ * *
+ ************************************************************************/
+#ifndef KIT_STATUS_H
+#define KIT_STATUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ KIT_OK,
+ KIT_ERROR_BAD_ALLOC,
+ KIT_ERROR_MKDIR_FAILED,
+ KIT_ERROR_RMDIR_FAILED,
+ KIT_ERROR_UNLINK_FAILED,
+ KIT_ERROR_FILE_ALREADY_EXISTS,
+ KIT_ERROR_FILE_DO_NOT_EXIST,
+ KIT_ERROR_PATH_TOO_LONG
+};
+
+typedef int kit_status_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/allocator.h *
+ * *
+ * *
+ ************************************************************************/
+#ifndef KIT_ALLOCATOR_H
+#define KIT_ALLOCATOR_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum { KIT_ALLOCATE, KIT_DEALLOCATE, KIT_REALLOCATE };
+
+typedef void *(*kit_allocate_fn)(int request, void *state,
+ ptrdiff_t size,
+ ptrdiff_t previous_size,
+ void *pointer);
+
+typedef struct {
+ void *state;
+ kit_allocate_fn allocate;
+} kit_allocator_t;
+
+/* Application should implement this function if custom allocator
+ * dispatch is enabled.
+ *
+ * See KIT_ENABLE_CUSTOM_ALLOC_DISPATCH
+ */
+void *kit_alloc_dispatch(kit_allocator_t alloc, int request,
+ ptrdiff_t size, ptrdiff_t previous_size,
+ void *pointer);
+
+kit_allocator_t kit_alloc_default(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/array_ref.h *
+ * *
+ * *
+ ************************************************************************/
+#ifndef KIT_ARRAY_REF_H
+#define KIT_ARRAY_REF_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*kit_ar_compare_fn)(void const *left, void const *right);
+
+int kit_ar_equal_bytes(ptrdiff_t left_element_size,
+ ptrdiff_t left_size, void const *left_data,
+ ptrdiff_t right_element_size,
+ ptrdiff_t right_size, void const *right_data);
+
+int kit_ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size,
+ void const *left_data,
+ ptrdiff_t right_element_size, ptrdiff_t right_size,
+ void const *right_data, kit_ar_compare_fn compare);
+
+#define KIT_AR_MUT(type_) \
+ struct { \
+ ptrdiff_t size; \
+ type_ *values; \
+ }
+
+#define KIT_AR(type_) \
+ struct { \
+ ptrdiff_t size; \
+ type_ const *values; \
+ }
+
+#define KIT_AR_MUT_WRAP(name_, element_type_, array_) \
+ struct { \
+ ptrdiff_t size; \
+ element_type_ *values; \
+ } name_ = { .size = (sizeof(array_) / sizeof((array_)[0])), \
+ .values = (array_) }
+
+#define KIT_AR_WRAP(name_, element_type_, array_) \
+ struct { \
+ ptrdiff_t size; \
+ element_type_ const *values; \
+ } name_ = { .size = (sizeof(array_) / sizeof((array_)[0])), \
+ .values = (array_) }
+
+#define KIT_AR_EQUAL(left_, right_) \
+ kit_ar_equal_bytes(sizeof((left_).values[0]), (left_).size, \
+ (left_).values, sizeof((right_).values[0]), \
+ (right_).size, (right_).values)
+
+#define KIT_AR_COMPARE(left_, right_, compare_) \
+ kit_ar_compare(sizeof((left_).values[0]), (left_).size, \
+ (left_).values, sizeof((right_).values[0]), \
+ (right_).size, (right_).values, \
+ (kit_ar_compare_fn) (compare_))
+
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define ar_compare_fn kit_ar_compare_fn
+# define ar_equal_bytes kit_ar_equal_bytes
+# define ar_compare kit_ar_compare
+
+# define AR_MUT KIT_AR_MUT
+# define AR KIT_AR
+# define AR_MUT_WRAP KIT_AR_MUT_WRAP
+# define AR_WRAP KIT_AR_WRAP
+# define AR_EQUAL KIT_AR_EQUAL
+# define AR_COMPARE KIT_AR_COMPARE
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/dynamic_array.h *
+ * *
+ * *
+ ************************************************************************/
+#ifndef KIT_DYNAMIC_ARRAY_H
+#define KIT_DYNAMIC_ARRAY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ ptrdiff_t capacity;
+ ptrdiff_t size;
+ void *values;
+ kit_allocator_t alloc;
+} kit_da_void_t;
+
+void kit_da_init(kit_da_void_t *array, ptrdiff_t element_size,
+ ptrdiff_t size, kit_allocator_t alloc);
+
+void kit_da_resize(kit_da_void_t *array, ptrdiff_t element_size,
+ ptrdiff_t size);
+
+/* Dynamic array type definition.
+ */
+#define KIT_DA(element_type_) \
+ struct { \
+ ptrdiff_t capacity; \
+ ptrdiff_t size; \
+ element_type_ *values; \
+ kit_allocator_t alloc; \
+ }
+
+/* Initialize dynamic array.
+ */
+#define KIT_DA_INIT(array_, size_, alloc_) \
+ kit_da_init((kit_da_void_t *) &(array_), \
+ sizeof((array_).values[0]), (size_), (alloc_))
+
+/* Declare and initialize dynamic array.
+ */
+#define KIT_DA_CREATE(name_, element_type_, size_) \
+ KIT_DA(element_type_) name_; \
+ KIT_DA_INIT(name_, (size_), kit_alloc_default())
+
+/* Destroy dynamic array.
+ */
+#define KIT_DA_DESTROY(array_) \
+ do { \
+ if ((array_).values != NULL) \
+ kit_alloc_dispatch((array_).alloc, KIT_DEALLOCATE, 0, 0, \
+ (array_).values); \
+ } while (0)
+
+/* Resize dynamic array.
+ */
+#define KIT_DA_RESIZE(array_, size_) \
+ kit_da_resize((kit_da_void_t *) &(array_), \
+ sizeof((array_).values[0]), size_)
+
+/* Append a value to dynamic array.
+ */
+#define KIT_DA_APPEND(array_, value_) \
+ do { \
+ ptrdiff_t const kit_index_back_ = (array_).size; \
+ KIT_DA_RESIZE((array_), kit_index_back_ + 1); \
+ if (kit_index_back_ < (array_).size) \
+ (array_).values[kit_index_back_] = (value_); \
+ } while (0)
+
+/* Insert a value into dynamic array.
+ */
+#define KIT_DA_INSERT(array_, index_, value_) \
+ do { \
+ ptrdiff_t kit_i_; \
+ ptrdiff_t const kit_index_back_ = (array_).size; \
+ ptrdiff_t const kit_indert_n_ = (index_); \
+ KIT_DA_RESIZE((array_), kit_index_back_ + 1); \
+ if (kit_index_back_ + 1 == (array_).size) { \
+ for (kit_i_ = kit_index_back_; kit_i_ > kit_indert_n_; \
+ kit_i_--) \
+ (array_).values[kit_i_] = (array_).values[kit_i_ - 1]; \
+ (array_).values[kit_indert_n_] = (value_); \
+ } \
+ } while (0)
+
+/* Erase a value from dynamic array.
+ */
+#define KIT_DA_ERASE(array_, index_) \
+ do { \
+ ptrdiff_t i_; \
+ for (i_ = (index_) + 1; i_ < (array_).size; i_++) \
+ (array_).values[i_ - 1] = (array_).values[i_]; \
+ KIT_DA_RESIZE((array_), (array_).size - 1); \
+ } while (0)
+
+typedef KIT_DA(char) kit_string_t;
+
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define da_void_t kit_da_void_t
+# define da_init kit_da_init
+# define da_resize kit_da_resize
+# define string_t kit_string_t
+
+# define DA KIT_DA
+# define DA_INIT KIT_DA_INIT
+# define DA_CREATE KIT_DA_CREATE
+# define DA_DESTROY KIT_DA_DESTROY
+# define DA_RESIZE KIT_DA_RESIZE
+# define DA_APPEND KIT_DA_APPEND
+# define DA_INSERT KIT_DA_INSERT
+# define DA_ERASE KIT_DA_ERASE
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/string_ref.h *
+ * *
+ * *
+ ************************************************************************/
+#ifndef KIT_STRING_REF_H
+#define KIT_STRING_REF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef KIT_AR_MUT(char) kit_string_mut_t;
+typedef KIT_AR(char) kit_string_ref_t;
+
+typedef kit_string_mut_t kit_out_str_t;
+typedef kit_string_ref_t kit_str_t;
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-function"
+# pragma GCC diagnostic ignored "-Wunknown-pragmas"
+# pragma GCC push_options
+# pragma GCC optimize("O3")
+#endif
+
+static kit_str_t kit_str(ptrdiff_t const size,
+ char const *const static_string) {
+ kit_str_t const s = { .size = size, .values = static_string };
+ return s;
+}
+
+#ifdef __GNUC__
+# pragma GCC pop_options
+# pragma GCC diagnostic pop
+#endif
+
+#define KIT_SZ(static_str_) \
+ kit_str(sizeof(static_str_) - 1, (static_str_))
+
+#define KIT_WRAP_STR(string_) \
+ kit_str((string_).size, (string_).values)
+
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define string_mut_t kit_string_mut_t
+# define string_ref_t kit_string_ref_t
+# define out_str_t kit_out_str_t
+# define str_t kit_str_t
+
+# define SZ KIT_SZ
+# define WRAP_STR KIT_WRAP_STR
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/file.h *
+ * *
+ * *
+ ************************************************************************/
+#ifndef KIT_FILE_H
+#define KIT_FILE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# define KIT_PATH_DELIM '\\'
+# define KIT_ENV_HOME "USERPROFILE"
+#else
+# define KIT_PATH_DELIM '/'
+# define KIT_ENV_HOME "HOME"
+#endif
+
+typedef enum {
+ KIT_PATH_NONE,
+ KIT_PATH_FILE,
+ KIT_PATH_FOLDER
+} kit_path_type_t;
+
+enum { KIT_FILE_SIZE_ERROR = -1 };
+
+kit_string_t kit_path_norm(kit_str_t path, kit_allocator_t alloc);
+
+kit_string_t kit_path_join(kit_str_t left, kit_str_t right,
+ kit_allocator_t alloc);
+
+kit_string_t kit_path_user(kit_allocator_t alloc);
+
+kit_str_t kit_path_index(kit_str_t path, ptrdiff_t index);
+
+kit_str_t kit_path_take(kit_str_t path, ptrdiff_t 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_file_remove(kit_str_t path);
+
+kit_status_t kit_file_remove_folder(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);
+
+typedef struct {
+ kit_status_t status;
+
+ int64_t time_modified_sec;
+ int32_t time_modified_nsec;
+ int64_t size;
+} kit_file_info_t;
+
+kit_file_info_t kit_file_info(kit_str_t path);
+
+typedef struct {
+ kit_status_t status;
+ KIT_DA(kit_string_t) files;
+} kit_path_list_t;
+
+kit_path_list_t kit_file_enum_folder(kit_str_t path,
+ kit_allocator_t alloc);
+
+void kit_path_list_destroy(kit_path_list_t list);
+
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define path_norm kit_path_norm
+# define path_join kit_path_join
+# define path_user kit_path_user
+# 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 file_remove kit_file_remove
+# define file_remove_folder kit_file_remove_folder
+# define file_remove_recursive kit_file_remove_recursive
+# define path_type kit_path_type
+# define file_size_result_t kit_file_size_result_t
+# define file_size kit_file_size
+# define path_type_t kit_path_type_t
+# define path_list_t kit_path_list_t
+# define file_enum_folder kit_file_enum_folder
+# define path_list_destroy kit_path_list_destroy
+
+# define PATH_NONE KIT_PATH_NONE
+# define PATH_FILE KIT_PATH_FILE
+# define PATH_FOLDER KIT_PATH_FOLDER
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/allocator.c *
+ * *
+ * *
+ ************************************************************************/
+
+#include <assert.h>
+
+#ifndef KIT_DISABLE_SYSTEM_MALLOC
+# include <stdlib.h>
+#endif
+
+static void *allocate(int request, void *state, ptrdiff_t size,
+ ptrdiff_t previous_size, void *pointer) {
+#ifndef KIT_DISABLE_SYSTEM_MALLOC
+ switch (request) {
+ case KIT_ALLOCATE:
+ assert(previous_size == 0);
+ assert(pointer == NULL);
+ return malloc(size);
+
+ case KIT_DEALLOCATE:
+ assert(size == 0);
+ assert(pointer != NULL);
+ free(pointer);
+ return NULL;
+
+ case KIT_REALLOCATE:
+ /* FIXME
+ * Not implemented.
+ */
+ assert(0);
+ return NULL;
+
+ default: assert(0);
+ }
+#else
+ assert(0);
+#endif
+ return NULL;
+}
+
+#ifndef KIT_ENABLE_CUSTOM_ALLOC_DISPATCH
+void *kit_alloc_dispatch(kit_allocator_t alloc, int request,
+ ptrdiff_t size, ptrdiff_t previous_size,
+ void *pointer) {
+ assert(alloc.allocate != NULL);
+ if (alloc.allocate == NULL)
+ return NULL;
+ return alloc.allocate(request, alloc.state, size, previous_size,
+ pointer);
+}
+#endif
+
+kit_allocator_t kit_alloc_default(void) {
+ kit_allocator_t alloc = { .state = NULL, .allocate = allocate };
+ return alloc;
+}
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/array_ref.c *
+ * *
+ * *
+ ************************************************************************/
+
+#include <string.h>
+
+int kit_ar_equal_bytes(ptrdiff_t left_element_size,
+ ptrdiff_t left_size, void const *left_data,
+ ptrdiff_t right_element_size,
+ ptrdiff_t right_size, void const *right_data) {
+ ptrdiff_t i;
+ if (left_element_size != right_element_size)
+ return 0;
+ if (left_size != right_size)
+ return 0;
+ for (i = 0; i < left_size; i++)
+ if (memcmp((char const *) left_data + i * left_element_size,
+ (char const *) right_data + i * left_element_size,
+ left_element_size) != 0)
+ return 0;
+ return 1;
+}
+
+int kit_ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size,
+ void const *left_data,
+ ptrdiff_t right_element_size, ptrdiff_t right_size,
+ void const *right_data,
+ kit_ar_compare_fn compare) {
+ ptrdiff_t i;
+ if (left_element_size < right_element_size)
+ return -1;
+ if (left_element_size > right_element_size)
+ return 1;
+ for (i = 0; i < left_size && i < right_size; i++) {
+ int const c = compare(
+ (char const *) left_data + i * left_element_size,
+ (char const *) right_data + i * left_element_size);
+ if (c != 0)
+ return c;
+ }
+ if (left_size < right_size)
+ return -1;
+ if (left_size > right_size)
+ return 1;
+ return 0;
+}
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/dynamic_array.c *
+ * *
+ * *
+ ************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+void kit_da_init(kit_da_void_t *array, ptrdiff_t element_size,
+ ptrdiff_t size, kit_allocator_t alloc) {
+ assert(array != NULL);
+ assert(element_size > 0);
+ assert(size >= 0);
+ assert(alloc.allocate != NULL);
+
+ memset(array, 0, sizeof(kit_da_void_t));
+
+ if (size > 0)
+ array->values = kit_alloc_dispatch(alloc, KIT_ALLOCATE,
+ element_size * size, 0, NULL);
+
+ if (array->values != NULL) {
+ array->capacity = size;
+ array->size = size;
+ }
+
+ array->alloc = alloc;
+}
+
+static ptrdiff_t eval_capacity(ptrdiff_t current_cap,
+ ptrdiff_t required_cap) {
+ if (current_cap == 0)
+ return required_cap;
+ ptrdiff_t cap = current_cap;
+ while (cap < required_cap) cap *= 2;
+ return cap;
+}
+
+void kit_da_resize(kit_da_void_t *array, ptrdiff_t element_size,
+ ptrdiff_t size) {
+ assert(array != NULL);
+ assert(element_size > 0);
+ assert(size >= 0);
+
+ if (size <= array->capacity) {
+ array->size = size;
+ } else {
+ ptrdiff_t capacity = eval_capacity(array->capacity, size);
+
+ assert(array->alloc.allocate != NULL);
+
+ void *bytes = kit_alloc_dispatch(
+ array->alloc, KIT_ALLOCATE, element_size * capacity, 0, NULL);
+
+ if (bytes != NULL) {
+ if (array->size > 0)
+ memcpy(bytes, array->values, element_size * array->size);
+ if (array->values != NULL)
+ kit_alloc_dispatch(array->alloc, KIT_DEALLOCATE, 0, 0,
+ array->values);
+ array->capacity = capacity;
+ array->size = size;
+ array->values = bytes;
+ }
+ }
+}
+
+/************************************************************************
+ * *
+ * *
+ * FILE: ./source/kit/file.c *
+ * *
+ * *
+ ************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum { PATH_BUF_SIZE = 4096 };
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# include <stdint.h>
+# include <Windows.h>
+#else
+# include <dirent.h>
+# include <sys/stat.h>
+# include <unistd.h>
+#endif
+
+#ifdef __APPLE__
+# define st_mtim st_mtimespec
+#endif
+
+static int is_delim(char const c) {
+ return c == '/' || c == '\\';
+}
+
+kit_string_t kit_path_norm(kit_str_t const path,
+ kit_allocator_t const alloc) {
+ str_t const parent = SZ("..");
+ ptrdiff_t i, i1, j;
+
+ string_t norm;
+ DA_INIT(norm, path.size, alloc);
+ assert(norm.size == path.size);
+
+ if (norm.size != path.size)
+ return norm;
+
+ memcpy(norm.values, path.values, path.size);
+
+ for (i1 = 0, i = 0; i < path.size; i++) {
+ if (!is_delim(path.values[i]))
+ continue;
+
+ str_t const s = { .size = i - i1 - 1,
+ .values = path.values + i1 + 1 };
+ if (AR_EQUAL(s, parent)) {
+ int have_parent = 0;
+ ptrdiff_t i0 = 0;
+
+ for (j = 0; j < i1; j++) {
+ if (norm.values[j] != '\0')
+ have_parent = 1;
+ if (is_delim(norm.values[j]))
+ i0 = j;
+ }
+
+ if (have_parent) {
+ memset(norm.values + i0, '\0', i - i0);
+
+ if (!is_delim(path.values[i0]))
+ norm.values[i] = '\0';
+ }
+ }
+
+ i1 = i;
+ }
+
+ ptrdiff_t size = 0;
+
+ for (i = 0; i < norm.size; i++) {
+ if (norm.values[i] != '\0') {
+ if (is_delim(norm.values[i]))
+ norm.values[size] = KIT_PATH_DELIM;
+ else
+ norm.values[size] = norm.values[i];
+ size++;
+ }
+ }
+
+ norm.size = size;
+ return norm;
+}
+
+kit_string_t kit_path_join(kit_str_t const left,
+ kit_str_t const right,
+ kit_allocator_t const alloc) {
+ ptrdiff_t left_size = left.size;
+ ptrdiff_t right_size = right.size;
+ char const *right_values = right.values;
+
+ if (left_size > 0 && is_delim(left.values[left_size - 1]))
+ left_size--;
+ if (right_size > 0 && is_delim(right.values[0])) {
+ right_size--;
+ right_values++;
+ }
+
+ kit_string_t joined;
+ DA_INIT(joined, left_size + right_size + 1, alloc);
+ assert(joined.size == left_size + right_size + 1);
+
+ if (joined.size != left_size + right_size + 1)
+ return joined;
+
+ memcpy(joined.values, left.values, left_size);
+ joined.values[left_size] = KIT_PATH_DELIM;
+ memcpy(joined.values + left_size + 1, right_values, right_size);
+
+ return joined;
+}
+
+kit_string_t kit_path_user(kit_allocator_t const alloc) {
+ char *home = getenv(KIT_ENV_HOME);
+ ptrdiff_t const size = home != NULL ? (ptrdiff_t) strlen(home) : 0;
+
+ string_t user;
+ DA_INIT(user, size, alloc);
+ assert(user.size == size);
+
+ if (user.size == size)
+ memcpy(user.values, home, user.size);
+ else {
+ DA_RESIZE(user, 1);
+ assert(user.size == 1);
+
+ if (user.size == 1)
+ user.values[0] = '.';
+ }
+
+ return user;
+}
+
+kit_str_t kit_path_index(kit_str_t const path,
+ ptrdiff_t const index) {
+ str_t s = { .size = 0, .values = NULL };
+
+ ptrdiff_t i0 = 0;
+ ptrdiff_t i = 0;
+ ptrdiff_t n = 0;
+
+ for (; i < path.size; i++) {
+ if (!is_delim(path.values[i]))
+ continue;
+
+ if (i0 < i) {
+ if (n++ == index) {
+ s.values = path.values + i0;
+ s.size = i - i0;
+ return s;
+ }
+ }
+
+ i0 = i + 1;
+ }
+
+ if (n == index) {
+ s.values = path.values + i0;
+ s.size = i - i0;
+ }
+
+ return s;
+}
+
+kit_str_t kit_path_take(kit_str_t const path, ptrdiff_t const count) {
+ str_t s = { .size = 0, .values = path.values };
+
+ ptrdiff_t i0 = 0;
+ ptrdiff_t i = 0;
+ ptrdiff_t n = 0;
+
+ for (; i < path.size; i++) {
+ if (!is_delim(path.values[i]))
+ continue;
+
+ if (i0 < i) {
+ if (n++ == count) {
+ s.size = i;
+ return s;
+ }
+ }
+
+ i0 = i + 1;
+ }
+
+ if (n == count)
+ s.size = i;
+
+ return s;
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static void win32_prepare_path_(WCHAR *const buf,
+ kit_str_t const 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 (ptrdiff_t 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 *const buf,
+ kit_str_t const 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 const path) {
+ PREPARE_PATH_BUF_;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return CreateDirectoryW(buf, NULL) ? KIT_OK
+ : KIT_ERROR_MKDIR_FAILED;
+#else
+ return mkdir(buf, 0755) == 0 ? KIT_OK : KIT_ERROR_MKDIR_FAILED;
+#endif
+}
+
+kit_status_t kit_file_create_folder_recursive(kit_str_t const path) {
+ ptrdiff_t i;
+
+ for (i = 0;; i++) {
+ str_t const part = kit_path_take(path, i);
+ int const type = kit_path_type(part);
+ if (type == KIT_PATH_FILE)
+ return KIT_ERROR_FILE_ALREADY_EXISTS;
+ if (type == KIT_PATH_NONE) {
+ kit_status_t const s = kit_file_create_folder(part);
+ if (s != KIT_OK)
+ return s;
+ }
+ if (part.size == path.size)
+ break;
+ }
+
+ return KIT_OK;
+}
+
+kit_status_t kit_file_remove(kit_str_t const path) {
+ PREPARE_PATH_BUF_;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return DeleteFileW(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 const path) {
+ PREPARE_PATH_BUF_;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return RemoveDirectoryW(buf) ? KIT_OK : KIT_ERROR_RMDIR_FAILED;
+#else
+ return rmdir(buf) == 0 ? KIT_OK : KIT_ERROR_RMDIR_FAILED;
+#endif
+}
+
+kit_status_t kit_file_remove_recursive(kit_str_t const path,
+ kit_allocator_t const alloc) {
+ int type = kit_path_type(path);
+ ptrdiff_t i;
+
+ switch (type) {
+ case KIT_PATH_FILE: return kit_file_remove(path);
+
+ case KIT_PATH_FOLDER: {
+ kit_path_list_t list = kit_file_enum_folder(path, alloc);
+ if (list.status != KIT_OK) {
+ kit_path_list_destroy(list);
+ return list.status;
+ }
+ for (i = 0; i < list.files.size; i++) {
+ str_t const s = { .size = list.files.values[i].size,
+ .values = list.files.values[i].values };
+ kit_file_remove_recursive(s, alloc);
+ }
+ kit_path_list_destroy(list);
+ return kit_file_remove_folder(path);
+ }
+
+ default:;
+ }
+
+ return KIT_ERROR_FILE_DO_NOT_EXIST;
+}
+
+kit_path_type_t kit_path_type(kit_str_t const path) {
+ PREPARE_PATH_BUF_;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (PathFileExistsW(buf)) {
+ if ((GetFileAttributesW(buf) & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ return KIT_PATH_FOLDER;
+ else
+ return KIT_PATH_FILE;
+ }
+#else
+ struct stat info;
+ if (stat(buf, &info) == 0) {
+ if (S_ISREG(info.st_mode))
+ return KIT_PATH_FILE;
+ if (S_ISDIR(info.st_mode))
+ return KIT_PATH_FOLDER;
+ }
+#endif
+ return KIT_PATH_NONE;
+}
+
+kit_file_info_t kit_file_info(kit_str_t const path) {
+ kit_file_info_t result;
+ memset(&result, 0, sizeof result);
+
+ PREPARE_PATH_BUF_;
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ HANDLE f = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (f != INVALID_HANDLE_VALUE) {
+ FILETIME ft;
+ if (GetFileTime(f, NULL, NULL, &ft) != 0) {
+ uint64_t const nsec100 = (((uint64_t) ft.dwHighDateTime)
+ << 32) |
+ (uint64_t) ft.dwLowDateTime;
+ result.time_modified_sec = (int64_t) (nsec100 / 10000000);
+ result.time_modified_nsec = (int32_t) (100 *
+ (nsec100 % 10000000));
+ } else {
+ assert(0);
+ }
+
+ DWORD high;
+ DWORD low = GetFileSize(f, &high);
+
+ result.size = (int64_t) ((((uint64_t) high) << 32) |
+ (uint64_t) low);
+ result.status = KIT_OK;
+
+ CloseHandle(f);
+ return result;
+ }
+#else
+ struct stat info;
+ if (stat(buf, &info) == 0 && S_ISREG(info.st_mode)) {
+ result.size = (int64_t) info.st_size;
+# ifndef st_mtime
+ /* No support for nanosecond timestamps.
+ */
+ result.time_modified_sec = (int64_t) info.st_mtime;
+# else
+ result.time_modified_sec = (int64_t) info.st_mtim.tv_sec;
+ result.time_modified_nsec = (int32_t) info.st_mtim.tv_nsec;
+# endif
+ result.status = KIT_OK;
+ return result;
+ }
+#endif
+
+ result.status = KIT_ERROR_FILE_DO_NOT_EXIST;
+ return result;
+}
+
+kit_path_list_t kit_file_enum_folder(kit_str_t const path,
+ kit_allocator_t const 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) {
+ 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);
+
+ if (find == INVALID_HANDLE_VALUE)
+ return result;
+
+ do {
+ ptrdiff_t const n = result.files.size;
+ DA_RESIZE(result.files, n + 1);
+ if (result.files.size != n + 1) {
+ result.status = KIT_ERROR_BAD_ALLOC;
+ break;
+ }
+
+ ptrdiff_t size = 0;
+ while (size < MAX_PATH && data.cFileName[size] != L'\0') size++;
+ 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 (ptrdiff_t i = 0; i < size; i++)
+ result.files.values[n].values[i] = data.cFileName[i];
+ } while (FindNextFileW(find, &data) != 0);
+
+ FindClose(find);
+#else
+ DIR *directory = opendir(buf);
+
+ if (directory == NULL)
+ return result;
+
+ for (;;) {
+ struct dirent *entry = readdir(directory);
+
+ if (entry == NULL)
+ break;
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ ptrdiff_t const n = result.files.size;
+ DA_RESIZE(result.files, n + 1);
+ if (result.files.size != n + 1) {
+ result.status = KIT_ERROR_BAD_ALLOC;
+ break;
+ }
+
+ ptrdiff_t const size = (ptrdiff_t) strlen(entry->d_name);
+ 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;
+ }
+
+ if (size > 0)
+ memcpy(result.files.values[n].values, entry->d_name, size);
+ }
+
+ closedir(directory);
+#endif
+
+ return result;
+}
+
+void kit_path_list_destroy(kit_path_list_t list) {
+ ptrdiff_t i;
+ for (i = 0; i < list.files.size; i++)
+ DA_DESTROY(list.files.values[i]);
+ DA_DESTROY(list.files);
+}
+
+
+#endif
diff --git a/source/kit/CMakeLists.txt b/source/kit/CMakeLists.txt
index a0206b3..2e89133 100644
--- a/source/kit/CMakeLists.txt
+++ b/source/kit/CMakeLists.txt
@@ -1,9 +1,5 @@
target_sources(
kit
- PRIVATE
- input_buffer.c secure_random.c sha256.c thread.posix.c
- atomic.win32.c condition_variable.c thread.win32.c input_stream.c file.c
- allocator.c array_ref.c dynamic_array.c mutex.c mersenne_twister_64.c
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/mutex.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/status.h>
@@ -24,4 +20,8 @@ target_sources(
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/sha256.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/file.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/array_ref.h>
- $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/mersenne_twister_64.h>)
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/mersenne_twister_64.h>
+ PRIVATE
+ input_buffer.c secure_random.c sha256.c thread.posix.c atomic.win32.c
+ condition_variable.c thread.win32.c input_stream.c file.c allocator.c
+ array_ref.c dynamic_array.c mutex.c mersenne_twister_64.c)
diff --git a/source/kit/array_ref.h b/source/kit/array_ref.h
index 029c20c..39f1e8b 100644
--- a/source/kit/array_ref.h
+++ b/source/kit/array_ref.h
@@ -24,13 +24,13 @@ int kit_ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size,
struct { \
ptrdiff_t size; \
type_ *values; \
- }
+ }
#define KIT_AR(type_) \
struct { \
ptrdiff_t size; \
type_ const *values; \
- }
+ }
#define KIT_AR_MUT_WRAP(name_, element_type_, array_) \
struct { \
diff --git a/source/kit/file.h b/source/kit/file.h
index b00ec4f..a773e02 100644
--- a/source/kit/file.h
+++ b/source/kit/file.h
@@ -88,6 +88,10 @@ void kit_path_list_destroy(kit_path_list_t list);
# define path_list_t kit_path_list_t
# define file_enum_folder kit_file_enum_folder
# define path_list_destroy kit_path_list_destroy
+
+# define PATH_NONE KIT_PATH_NONE
+# define PATH_FILE KIT_PATH_FILE
+# define PATH_FOLDER KIT_PATH_FOLDER
#endif
#ifdef __cplusplus
diff --git a/source/kit/string_ref.h b/source/kit/string_ref.h
index 4b2cabd..1497bb0 100644
--- a/source/kit/string_ref.h
+++ b/source/kit/string_ref.h
@@ -35,6 +35,9 @@ static kit_str_t kit_str(ptrdiff_t const size,
#define KIT_SZ(static_str_) \
kit_str(sizeof(static_str_) - 1, (static_str_))
+#define KIT_WRAP_STR(string_) \
+ kit_str((string_).size, (string_).values)
+
#ifndef KIT_DISABLE_SHORT_NAMES
# define string_mut_t kit_string_mut_t
# define string_ref_t kit_string_ref_t
@@ -42,6 +45,7 @@ static kit_str_t kit_str(ptrdiff_t const size,
# define str_t kit_str_t
# define SZ KIT_SZ
+# define WRAP_STR KIT_WRAP_STR
#endif
#ifdef __cplusplus
diff --git a/source/kit_test/CMakeLists.txt b/source/kit_test/CMakeLists.txt
index 0e61fe3..56aa9a4 100644
--- a/source/kit_test/CMakeLists.txt
+++ b/source/kit_test/CMakeLists.txt
@@ -1,7 +1,7 @@
target_sources(
kit_test
- PRIVATE
- test.c bench.c
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/bench.h>
- $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/test.h>)
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/test.h>
+ PRIVATE
+ test.c bench.c)
diff --git a/source/test/unittests/CMakeLists.txt b/source/test/unittests/CMakeLists.txt
index b8a6dca..e071ed4 100644
--- a/source/test/unittests/CMakeLists.txt
+++ b/source/test/unittests/CMakeLists.txt
@@ -1,9 +1,8 @@
target_sources(
kit_test_suite
PRIVATE
- async_function.test.c bigint.test.c mutex.test.c
- test_duration.test.c main.test.c string_ref.test.c atomic.test.c foo.bench.c
- thread.test.c array_ref.test.c input_stream.test.c sha256.test.c
- lower_bound.test.c secure_random.test.c condition_variable.test.c
- mersenne_twister_64.test.c input_buffer.test.c move_back.test.c dynamic_array.test.c
- file.test.c)
+ async_function.test.c bigint.test.c mutex.test.c test_duration.test.c
+ main.test.c string_ref.test.c atomic.test.c foo.bench.c thread.test.c
+ array_ref.test.c input_stream.test.c sha256.test.c lower_bound.test.c
+ secure_random.test.c condition_variable.test.c mersenne_twister_64.test.c
+ input_buffer.test.c move_back.test.c dynamic_array.test.c file.test.c)