diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 42e4a54..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,9 +0,0 @@
-[submodule "encoding/baseven"]
- path = encoding/baseven
- url = https://git.redxen.eu/corelibs/baseven
-[submodule "llist"]
- path = llist
- url = https://git.redxen.eu/corelibs/llist
-[submodule "dynarray"]
- path = dynarray
- url = https://git.redxen.eu/corelibs/dynarray
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..30c7aca
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+include config.mk
+
+OBJ = ${SRC:.c=.o}
+
+all: ${OBJ} ${OUT}
+
+%.o: %.c
+ ${CC} -o $@ -c ${CFLAGS} $<
+
+clean:
+ rm -f ${OBJ} ${OUT}
+
+ifneq (${OUT},)
+${OUT}: ${OBJ}
+ ${CC} -o "$@" ${LDFLAGS} $^
+endif
+
+.PHONY: all clean
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..76a3719
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,46 @@
+# Defaults
+CC = clang
+DEBUG = 1
+STATIC = 0
+
+LDFLAGS =
+CFLAGS =\
+ -std=c99 \
+ -Weverything \
+ -Wno-padded \
+ -Wno-disabled-macro-expansion \
+ -pedantic
+
+# Sources / Results
+SRC =\
+ src/dynarray/dynarray.c \
+ src/llist/llist.c \
+ src/encoding/baseven/baseven.c \
+ src/types/error/error.c
+
+LIBDIR =
+LIB =\
+ c
+
+INCDIR =\
+ src/
+
+OUT =
+
+# Conditionals / Appends
+LDFLAGS +=\
+ $(addprefix -L,${LIBDIR})\
+ $(addprefix -l,${LIB})
+
+CFLAGS +=\
+ $(addprefix -I,${INCDIR})
+
+ifeq (${DEBUG},1)
+CFLAGS += -g
+else
+CFLAGS += -O2 -Werror
+endif
+
+ifeq (${STATIC},1)
+LDFLAGS += -static
+endif
diff --git a/dynarray b/dynarray
deleted file mode 160000
index 12b6867..0000000
--- a/dynarray
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 12b6867f4684913b36962d0abda3ac6c7cfbc9c4
diff --git a/encoding/baseven b/encoding/baseven
deleted file mode 160000
index cc74293..0000000
--- a/encoding/baseven
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit cc742932a2d665c0fc5b1c7d0909aee308c23988
diff --git a/llist b/llist
deleted file mode 160000
index 2d89d5f..0000000
--- a/llist
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 2d89d5f40cde60bf5c87206268dcb810b7175740
diff --git a/src/dynarray/dynarray.c b/src/dynarray/dynarray.c
new file mode 100644
index 0000000..99817bd
--- /dev/null
+++ b/src/dynarray/dynarray.c
@@ -0,0 +1,388 @@
+/*
+ * This file is part of corelibs. (https://git.redxen.eu/corelibs)
+ * Copyright (c) 2021 Alex-David Denes
+ *
+ * corelibs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * corelibs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with corelibs. If not, see .
+ */
+
+#include "dynarray/dynarray.h"
+
+#include "types/error/error.h"
+
+#include // bool
+#include // malloc() free()
+#include // memcpy()
+
+static cl_error_t
+corelibs_dynarray_export_slice (const cl_dynarray_t *, uintmax_t, uintmax_t, void *),
+ corelibs_dynarray_make_new (size_t, cl_dynarray_t **),
+ corelibs_dynarray_make_slice (const cl_dynarray_t *, uintmax_t, uintmax_t, cl_dynarray_t **),
+ corelibs_dynarray_free (cl_dynarray_t *),
+ corelibs_dynarray_mod_arr_cap (cl_dynarray_t *, uintmax_t),
+ corelibs_dynarray_mod_arr_lock (cl_dynarray_t *, bool),
+ corelibs_dynarray_mod_dat_app (cl_dynarray_t *, uintmax_t, const void *),
+ corelibs_dynarray_mod_dat_ins (cl_dynarray_t *, uintmax_t, uintmax_t, const void *),
+ corelibs_dynarray_mod_dat_rep (cl_dynarray_t *, uintmax_t, uintmax_t, const void *),
+ corelibs_dynarray_mod_dat_rm (cl_dynarray_t *, uintmax_t, uintmax_t),
+ corelibs_dynarray_get_len (const cl_dynarray_t *, uintmax_t *),
+ corelibs_dynarray_get_size (const cl_dynarray_t *, size_t *),
+ corelibs_dynarray_get_cap_len (const cl_dynarray_t *, uintmax_t *),
+ corelibs_dynarray_get_cap_lock (const cl_dynarray_t *, bool *),
+ corelibs_dynarray_cmp_data (const cl_dynarray_t *a, const cl_dynarray_t *b, bool *eq),
+ corelibs_dynarray_bcheck (const cl_dynarray_t *, uintmax_t, uintmax_t);
+
+struct cl_dynarray_t {
+ void * addr; // Location of element
+ uintmax_t len; // Element count
+ struct {
+ bool lock; // Is the capacity frozen?
+ uintmax_t len; // Capacity
+ } cap;
+ size_t es; // Size of element
+};
+
+const struct corelibs_dynarray_interface cl_dynarray = {
+ .make = {
+ .new = corelibs_dynarray_make_new,
+ .slice = corelibs_dynarray_make_slice,
+ },
+ .free = corelibs_dynarray_free,
+ .mod = {
+ .arr = {
+ .cap = corelibs_dynarray_mod_arr_cap,
+ .lock = corelibs_dynarray_mod_arr_lock,
+ },
+ .dat = {
+ .app = corelibs_dynarray_mod_dat_app,
+ .ins = corelibs_dynarray_mod_dat_ins,
+ .rep = corelibs_dynarray_mod_dat_rep,
+ .rm = corelibs_dynarray_mod_dat_rm,
+ },
+ },
+ .cmp = {
+ .data = corelibs_dynarray_cmp_data,
+ },
+ .export = {
+ .slice = corelibs_dynarray_export_slice,
+ },
+ .get = {
+ .len = corelibs_dynarray_get_len,
+ .size = corelibs_dynarray_get_size,
+ .cap = {
+ .len = corelibs_dynarray_get_cap_len,
+ .lock = corelibs_dynarray_get_cap_lock,
+ },
+ },
+};
+
+static cl_error_t
+corelibs_dynarray_make_new (size_t sbyte, cl_dynarray_t **ptr) {
+ cl_error_t err = cl_error.err.ok;
+ if (ptr == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ cl_dynarray_t *new = malloc (sizeof (*new));
+ if (new != NULL) {
+ new->addr = NULL;
+ new->es = sbyte;
+ new->len = 0;
+ new->cap.len = 0;
+ new->cap.lock = false;
+ *ptr = new;
+ } else {
+ err = cl_error.err.mem.alloc;
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_make_slice (const cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt, cl_dynarray_t **save) {
+ cl_error_t err = cl_error.err.ok;
+ if (save == NULL || arr == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ if (cnt == 0) {
+ // Don't copy anything, just make new array
+ return corelibs_dynarray_make_new (arr->es, save);
+ }
+
+ // Can we slice these elements?
+ if (!(err = corelibs_dynarray_bcheck (arr, pos, cnt))) {
+ // Create new array
+ cl_dynarray_t *new;
+ if (!(err = corelibs_dynarray_make_new (arr->es, &new))) {
+ // Resize array to fit contents
+ if (!(err = corelibs_dynarray_mod_arr_cap (new, cnt))) {
+ // Copy contents from old array to new one
+ if (!(err = corelibs_dynarray_export_slice (arr, pos, cnt, new->addr))) {
+ new->len = cnt;
+ new->cap.lock = arr->cap.lock; // Inherit capacity lock
+ *save = new;
+ }
+ }
+ if (err) corelibs_dynarray_free (new);
+ }
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_free (cl_dynarray_t *arr) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ if (!(err = corelibs_dynarray_mod_arr_cap (arr, 0))) {
+ free (arr);
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_mod_arr_cap (cl_dynarray_t *arr, uintmax_t len) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ if (len == 0) {
+ free (arr->addr);
+ arr->cap.len = 0;
+ } else if (!arr->cap.lock) {
+ void * reg = NULL;
+ const size_t nl = len * arr->es;
+
+ if (arr->addr == NULL) {
+ reg = malloc (nl);
+ } else if (arr->cap.len != len) {
+ reg = realloc (arr->addr, nl);
+ }
+
+ if (reg != NULL) {
+ arr->cap.len = len;
+ arr->addr = reg;
+ if (arr->cap.len < arr->len) arr->len = arr->cap.len; // Cut out discarded elements if resized to shorter size
+ } else {
+ err = cl_error.err.mem.alloc;
+ }
+ } else {
+ err = cl_error.err.data.immut;
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_mod_arr_lock (cl_dynarray_t *arr, bool lock) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ arr->cap.lock = lock;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_mod_dat_app (cl_dynarray_t *arr, uintmax_t cnt, const void *elem) {
+ return corelibs_dynarray_mod_dat_ins (arr, arr->len, cnt, elem);
+}
+
+static cl_error_t
+corelibs_dynarray_mod_dat_ins (cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt, const void *elem) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL || elem == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ // Resize array to fit inserted objects
+ if (!(err = corelibs_dynarray_mod_arr_cap (arr, ((arr->cap.len < pos) ? pos : arr->cap.len) + cnt))) {
+ // CHECKPOINT: From here it is safe to commit changes as required conditions are met
+ // and no errors should be possible (unless you have some special hardware)
+
+ uintmax_t clen = arr->len; // Lenght pre-resize
+
+ if (arr->len < pos) arr->len = pos;
+ arr->len += cnt;
+
+ uintptr_t src, // Source of copy address without pointer aritmethic
+ dest; // Destination to copy to
+ size_t bcnt; // Amount of bytes to copy
+
+ // If we are inserting and not appending
+ if (pos < clen) {
+ src = (uintptr_t) arr->addr + (pos * arr->es);
+ dest = src + (cnt * arr->es);
+ bcnt = (clen - pos) * arr->es;
+ memmove ((void *) dest, (void *) src, bcnt); // Shift bytes to after insertion region
+ }
+
+ src = (uintptr_t) elem;
+ dest = (uintptr_t) arr->addr + (pos * arr->es);
+ bcnt = cnt * arr->es;
+ memcpy ((void *) dest, (void *) src, bcnt); // No overlaps possible
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_mod_dat_rep (cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt, const void *elem) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL || elem == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ if (corelibs_dynarray_bcheck (arr, pos, cnt) == cl_error.err.mem.oob) {
+ // Resize array to fit new elements
+ err = corelibs_dynarray_mod_arr_cap (arr, pos + cnt);
+ }
+
+ if (!err) {
+ // CHECKPOINT: From here it is safe to commit changes as required conditions are met
+ // and no errors should be possible (unless you have some special hardware)
+
+ uintptr_t src, // Source of copy address without pointer aritmethic
+ dest; // Destination to copy to
+ size_t bcnt; // Amount of bytes to copy
+
+ src = (uintptr_t) elem;
+ dest = (uintptr_t) arr->addr + (pos * arr->es);
+ bcnt = cnt * arr->es;
+ memcpy ((void *) dest, (void *) src, bcnt);
+ if (arr->len < pos + cnt) arr->len = pos + cnt; // Set length at end of replacement if not already same or longer
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_mod_dat_rm (cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ // Are we removing elements we don't have?
+ if (!(err = corelibs_dynarray_bcheck (arr, pos, cnt))) {
+ // Allocate intermediate buffer
+ void *tbuf = malloc (arr->es * arr->len);
+ if (tbuf != NULL) {
+ // CHECKPOINT: From here it is safe to commit changes as required conditions are met
+ // and no errors should be possible (unless you have some special hardware)
+
+ arr->len -= cnt; // We remove cnt elements from array
+
+ uintptr_t src, // Source of copy address without pointer aritmethic
+ dest; // Destination to copy to
+ size_t bcnt; // Amount of bytes to copy
+
+ dest = (uintptr_t) tbuf;
+ src = (uintptr_t) arr->addr;
+ bcnt = arr->len * arr->es;
+ memcpy ((void *) dest, (void *) src, bcnt); // Copy current contents up to arr->len to intermediate buffer
+
+ // If tail is the only thing removed, don't copy back
+ if (pos + cnt != arr->len) {
+ // Copy back slice and overwrite region removed
+ dest += pos * arr->es;
+ src += (pos + cnt) * arr->es;
+ bcnt -= pos * arr->es;
+ memcpy ((void *) dest, (void *) src, bcnt);
+ }
+
+ free (arr->addr);
+ arr->addr = tbuf; // Swap buffers and free previous one
+ } else {
+ err = cl_error.err.mem.alloc;
+ }
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_export_slice (const cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt, void *save) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL || save == NULL) err = cl_error.err.mem.null;
+ if (!err || cnt != 0) {
+ // Do we have the requested slice?
+ if (!(err = corelibs_dynarray_bcheck (arr, pos, cnt))) {
+ uintptr_t src, // Source of copy address without pointer aritmethic
+ dest; // Destination to copy to
+ size_t bcnt; // Amount of bytes to copy
+
+ src = (uintptr_t) arr->addr + (arr->es * pos);
+ dest = (uintptr_t) save;
+ bcnt = arr->es * cnt;
+ memcpy ((void *) dest, (void *) src, bcnt);
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_get_len (const cl_dynarray_t *arr, uintmax_t *save) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL || save == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ *save = arr->len;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_get_cap_len (const cl_dynarray_t *arr, uintmax_t *save) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL || save == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ *save = arr->cap.len;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_get_cap_lock (const cl_dynarray_t *arr, bool *save) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL || save == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ *save = arr->cap.lock;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_get_size (const cl_dynarray_t *arr, size_t *save) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL || save == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ *save = arr->es;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_dynarray_cmp_data (const cl_dynarray_t *a, const cl_dynarray_t *b, bool *eq) {
+ cl_error_t err = cl_error.err.ok;
+ if (a == NULL || b == NULL) err = cl_error.err.mem.null;
+ if (a->es != b->es) err = cl_error.err.data.incompat;
+ if (!err) {
+ if (a->len != b->len) {
+ *eq = false;
+ } else {
+ *eq = (memcmp (a->addr, b->addr, a->len) != 0) ? false : true;
+ }
+ }
+ return err;
+}
+
+// Private functions
+static cl_error_t
+corelibs_dynarray_bcheck (const cl_dynarray_t *arr, uintmax_t pos, uintmax_t len) {
+ cl_error_t err = cl_error.err.ok;
+ if (arr == NULL) err = cl_error.err.mem.null;
+ if (arr->cap.len < pos + len) err = cl_error.err.mem.oob;
+ return err;
+}
diff --git a/src/dynarray/dynarray.h b/src/dynarray/dynarray.h
new file mode 100644
index 0000000..3b214d0
--- /dev/null
+++ b/src/dynarray/dynarray.h
@@ -0,0 +1,81 @@
+/*
+ * This file is part of corelibs. (https://git.redxen.eu/corelibs)
+ * Copyright (c) 2021 Alex-David Denes
+ *
+ * corelibs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * corelibs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with corelibs. If not, see .
+ */
+
+#include "types/error/error.h"
+
+#include // bool
+#include // size_t
+#include // uintmax_t
+
+#ifndef CORELIBS_GUARD_DYNARRAY
+#define CORELIBS_GUARD_DYNARRAY
+
+typedef struct cl_dynarray_t cl_dynarray_t;
+
+struct corelibs_dynarray_interface {
+
+ // Makers
+ const struct {
+ cl_error_t (*const new) (size_t sbyte, cl_dynarray_t **ptr), // New - allocate new array
+ (*const slice) (const cl_dynarray_t *arr, uintmax_t pos, uintmax_t len, cl_dynarray_t **ssave); // Slicer - gets a slice of a array
+ } make;
+
+ // Free
+ cl_error_t (*const free) (cl_dynarray_t *arr);
+
+ // Modifiers
+ const struct {
+
+ const struct {
+ cl_error_t (*const app) (cl_dynarray_t *arr, uintmax_t cnt, const void *elem), // Appender - Adds element at end of array
+ (*const ins) (cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt, const void *elem), // Inserter - Adds element at position, pushing next element 1 position further
+ (*const rep) (cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt, const void *elem), // Replacer - Replaces array item or creates it if not existent
+ (*const rm) (cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt); // Remover - removes element from array
+ } dat;
+
+ const struct {
+ cl_error_t (*const cap) (cl_dynarray_t *ptr, uintmax_t len), // Capacity
+ (*const lock) (cl_dynarray_t *ptr, bool cap); // Capacity lock (dynamic / static capacity)
+ } arr;
+
+ } mod;
+
+ // Fetchers
+ const struct {
+ cl_error_t (*const len) (const cl_dynarray_t *arr, uintmax_t *save),
+ (*const size) (const cl_dynarray_t *arr, size_t *save);
+ const struct {
+ cl_error_t (*const len) (const cl_dynarray_t *arr, uintmax_t *save),
+ (*const lock) (const cl_dynarray_t *arr, bool *save);
+ } cap;
+ } get;
+
+ // Comparers
+ const struct {
+ cl_error_t (*const data) (const cl_dynarray_t *a, const cl_dynarray_t *b, bool *eq);
+ } cmp;
+
+ // Exporter
+ const struct {
+ cl_error_t (*const slice) (const cl_dynarray_t *arr, uintmax_t pos, uintmax_t cnt, void *save);
+ } export;
+};
+extern const struct corelibs_dynarray_interface cl_dynarray;
+
+#endif /* CORELIBS_GUARD_DYNARRAY */
+
diff --git a/src/encoding/baseven/baseven.c b/src/encoding/baseven/baseven.c
new file mode 100644
index 0000000..5db1a38
--- /dev/null
+++ b/src/encoding/baseven/baseven.c
@@ -0,0 +1,155 @@
+/*
+ * This file is part of corelibs. (https://git.redxen.eu/corelibs)
+ * Copyright (c) 2021 Alex-David Denes
+ *
+ * corelibs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * corelibs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with corelibs. If not, see .
+ */
+
+#include "encoding/baseven/baseven.h"
+
+#include // assert()
+#include
+#include // bool
+#include // putchar()
+#include // malloc() free()
+
+#define ENCODED 8
+#define DECODED 7
+#define RESERVED (ENCODED - DECODED)
+#define RESERVEDBIT (1 << 7)
+
+static cl_error_t corelibs_baseven_encode (const uint8_t *, size_t, uint8_t *, size_t),
+ corelibs_baseven_decode (const uint8_t *, size_t, uint8_t *, size_t);
+
+static uintmax_t corelibs_baseven_size_encoded (uintmax_t),
+ corelibs_baseven_size_decoded (uintmax_t);
+
+static uint8_t corelibs_baseven_bits_first (uint8_t, uint8_t),
+ corelibs_baseven_bits_last (uint8_t, uint8_t);
+
+static bool corelibs_baseven_bits_nth (uint8_t, uint8_t);
+
+const struct corelibs_baseven_interface cl_baseven = {
+ .encode = corelibs_baseven_encode,
+ .decode = corelibs_baseven_decode,
+ .size = {
+ .decoded = corelibs_baseven_size_decoded,
+ .encoded = corelibs_baseven_size_encoded,
+ },
+};
+
+static cl_error_t
+corelibs_baseven_encode (const uint8_t *src, size_t len, uint8_t *dest, size_t max) {
+ cl_error_t err = cl_error.err.ok;
+
+ if (src == NULL || dest == NULL) err = cl_error.err.data.inval;
+ if (corelibs_baseven_size_encoded (len) > max) err = cl_error.err.mem.oob;
+
+ if (!err) {
+ const uint8_t *const end = src + len;
+
+ uint8_t bits = 0,
+ last = 0;
+
+ while (src < end) {
+ const uint8_t rev = RESERVED, keep = DECODED;
+
+ last |= corelibs_baseven_bits_first (*src, rev) >> (bits + rev); // Save first bit into the last byte to append to byte series
+ *dest = corelibs_baseven_bits_last (*src, keep) | RESERVEDBIT; // Write the kept bytes in the output buffer
+
+ src++;
+ dest++;
+ bits++;
+
+ if (bits == DECODED || src == end) {
+ *(dest++) = last | RESERVEDBIT;
+
+ bits = 0;
+ last = 0;
+ }
+ }
+ }
+
+ return err;
+}
+
+static cl_error_t
+corelibs_baseven_decode (const uint8_t *src, size_t len, uint8_t *dest, size_t max) {
+ cl_error_t err = cl_error.err.ok;
+
+ if (src == NULL || dest == NULL) err = cl_error.err.data.inval;
+ if (corelibs_baseven_size_decoded (len) > max) err = cl_error.err.mem.oob;
+
+ if (!err) {
+ while (1) {
+ const uint8_t con = ((ENCODED - 1) < len) ? (ENCODED - 1) : (uint8_t) len - 1; // Count of bytes to the extra post-encoding byte as OFFSET (8 -> 7)
+
+ for (uint8_t p = 0; p < con; p++) {
+ dest[p] = (uint8_t) ((corelibs_baseven_bits_nth (src[con], p + 1) << (ENCODED - 1)) // Get n-th bit from last byte and shift it to the beginning
+ | (src[p] ^ RESERVEDBIT) // Discard reserved bit and merge it with bit from last
+ );
+ }
+ if ((ENCODED - 1) < len) {
+ dest += con;
+ len -= con;
+ src += ENCODED;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return err;
+}
+
+static uintmax_t
+corelibs_baseven_size_encoded (uintmax_t b) {
+ return b + ((b / DECODED) + (bool) (b % DECODED));
+}
+
+static uintmax_t
+corelibs_baseven_size_decoded (uintmax_t b) {
+ return b - ((b / ENCODED) + (bool) (b % ENCODED));
+}
+
+static uint8_t
+corelibs_baseven_bits_first (const uint8_t byte, const uint8_t cnt) {
+ assert (cnt < ENCODED);
+ const uint8_t fb = (uint8_t) ~0;
+ return byte & ((fb >> cnt) ^ fb);
+}
+
+static uint8_t
+corelibs_baseven_bits_last (const uint8_t byte, const uint8_t cnt) {
+ assert (cnt < ENCODED);
+ const uint8_t fb = (uint8_t) ~0;
+ return byte & ((fb << cnt) ^ fb);
+}
+
+static bool
+corelibs_baseven_bits_nth (const uint8_t byte, const uint8_t index) {
+ assert (index < ENCODED);
+ uint8_t off = (ENCODED - 1) - index;
+ /*
+ * 00100000
+ *
+ * 00000001 << ((8 - 1) - 2)
+ * * 10000000 << (7)
+ * * 00100000 >> (2)
+ *
+ * 00100000 >> ((8 - 1) - 2)
+ * * 00000001 >> (5)
+ */
+ return (byte & (1 << off)) >> off;
+}
diff --git a/src/encoding/baseven/baseven.h b/src/encoding/baseven/baseven.h
new file mode 100644
index 0000000..04444ea
--- /dev/null
+++ b/src/encoding/baseven/baseven.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of corelibs. (https://git.redxen.eu/corelibs)
+ * Copyright (c) 2021 Alex-David Denes
+ *
+ * corelibs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * corelibs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with corelibs. If not, see .
+ */
+
+#include "types/error/error.h"
+
+#include // bool
+#include // size_t
+#include // uintmax_t
+
+#ifndef CORELIBS_GUARD_BASEVEN
+#define CORELIBS_GUARD_BASEVEN
+
+typedef struct cl_baseven_t cl_baseven_t;
+
+struct corelibs_baseven_interface {
+ cl_error_t (*const encode) (const uint8_t *src, size_t len, uint8_t *dest, size_t cap),
+ (*const decode) (const uint8_t *src, size_t len, uint8_t *dest, size_t cap);
+
+ const struct {
+ uintmax_t (*const decoded) (uintmax_t enc_size),
+ (*const encoded) (uintmax_t dec_size);
+ } size;
+};
+extern const struct corelibs_baseven_interface cl_baseven;
+
+#endif /* CORELIBS_GUARD_BASEVEN */
+
diff --git a/src/llist/llist.c b/src/llist/llist.c
new file mode 100644
index 0000000..3e79c0a
--- /dev/null
+++ b/src/llist/llist.c
@@ -0,0 +1,227 @@
+/*
+ * This file is part of corelibs. (https://git.redxen.eu/corelibs)
+ * Copyright (c) 2021 Alex-David Denes
+ *
+ * corelibs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * corelibs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with corelibs. If not, see .
+ */
+
+#include "llist/llist.h"
+
+#include // va_args
+#include // uintmax_t
+#include // malloc() free()
+
+static cl_error_t
+corelibs_llist_create (void *, void (*) (void *), cl_llist_t **),
+ corelibs_llist_link (uintmax_t, ...),
+ corelibs_llist_rep (cl_llist_t *, cl_llist_t *),
+ corelibs_llist_free_list (cl_llist_t *),
+ corelibs_llist_free_elem (cl_llist_t *),
+ corelibs_llist_free_cont (cl_llist_t *),
+ corelibs_llist_set_cont (cl_llist_t *, void *),
+ corelibs_llist_set_free (cl_llist_t *, void (*) (void *)),
+ corelibs_llist_get_next (const cl_llist_t *, cl_llist_t **),
+ corelibs_llist_get_prev (const cl_llist_t *, cl_llist_t **),
+ corelibs_llist_get_cont (const cl_llist_t *, void **);
+
+static void corelibs_llist_remove (cl_llist_t *);
+
+struct cl_llist_t {
+ struct cl_llist_t *next, *prev;
+ void * cont;
+ void (*free) (void *);
+};
+
+struct corelibs_llist_interface const cl_llist = {
+ .create = corelibs_llist_create,
+ .link = corelibs_llist_link,
+ .rep = corelibs_llist_rep,
+ .free = {
+ .list = corelibs_llist_free_list,
+ .elem = corelibs_llist_free_elem,
+ .cont = corelibs_llist_free_cont,
+ },
+ .set = {
+ .cont = corelibs_llist_set_cont,
+ .free = corelibs_llist_set_free,
+ },
+ .get = {
+ .prev = corelibs_llist_get_prev,
+ .cont = corelibs_llist_get_cont,
+ .next = corelibs_llist_get_next,
+ },
+};
+
+static cl_error_t
+corelibs_llist_create (void *c, void (*const f) (void *), cl_llist_t **s) {
+ cl_error_t err = cl_error.err.ok;
+ if (s == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ cl_llist_t *cur = malloc (sizeof (*cur));
+ if (cur != NULL) {
+ cur->prev = NULL;
+ cur->next = NULL;
+ cur->cont = c;
+ cur->free = f;
+ *s = cur;
+ } else {
+ err = cl_error.err.mem.alloc;
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_free_list (cl_llist_t *l) {
+ cl_error_t err = cl_error.err.ok;
+ if (l == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ // Free previous elements if we have any
+ if (l->prev != NULL) {
+ for (cl_llist_t *p = l->prev; p != NULL;) {
+ cl_llist_t *c = p;
+ p = p->prev;
+ corelibs_llist_remove (c);
+ }
+ }
+
+ // Free current and next elements
+ for (cl_llist_t *p = l; p != NULL;) {
+ cl_llist_t *c = p;
+ p = p->next;
+ corelibs_llist_remove (c);
+ }
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_free_elem (cl_llist_t *l) {
+ cl_error_t err = cl_error.err.ok;
+ if (l == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ corelibs_llist_remove (l);
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_free_cont (cl_llist_t *l) {
+ cl_error_t err = cl_error.err.ok;
+ if (l == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ if (l->free != NULL) l->free (l->cont);
+ l->free = NULL;
+ l->cont = NULL;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_link (uintmax_t cnt, ...) {
+ cl_error_t err = cl_error.err.ok;
+ if (cnt <= 1) err = cl_error.err.args.mis;
+ if (!err) {
+ va_list ap;
+ va_start (ap, cnt);
+
+ uintmax_t ccnt = 0;
+ cl_llist_t *a = NULL, *b = NULL;
+ while (ccnt < cnt) {
+ a = b;
+ b = va_arg (ap, cl_llist_t *);
+ if (ccnt < 1) continue; // Fill at least first 2 slots
+
+ if (a != NULL) a->next = b;
+ if (b != NULL) b->prev = a;
+
+ ccnt++;
+ }
+
+ va_end (ap);
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_rep (cl_llist_t *dest, cl_llist_t *src) {
+ cl_error_t err = cl_error.err.ok;
+ if (src == NULL || dest == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ if (dest->prev != NULL) dest->prev->next = src;
+ if (dest->next != NULL) dest->next->prev = src;
+ corelibs_llist_free_elem (dest);
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_get_next (const cl_llist_t *e, cl_llist_t **save) {
+ cl_error_t err = cl_error.err.ok;
+ if (e == NULL || save == NULL) err = cl_error.err.mem.null;
+ if (e->next == NULL) err = cl_error.err.undef;
+ if (!err) {
+ *save = e->next;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_get_prev (const cl_llist_t *e, cl_llist_t **save) {
+ cl_error_t err = cl_error.err.ok;
+ if (e == NULL || save == NULL) err = cl_error.err.mem.null;
+ if (e->prev == NULL) err = cl_error.err.undef;
+ if (!err) {
+ *save = e->prev;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_get_cont (const cl_llist_t *e, void **save) {
+ cl_error_t err = cl_error.err.ok;
+ if (e == NULL || save == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ *save = e->cont;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_set_cont (cl_llist_t *e, void *i) {
+ cl_error_t err = cl_error.err.ok;
+ if (e == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ e->cont = i;
+ }
+ return err;
+}
+
+static cl_error_t
+corelibs_llist_set_free (cl_llist_t *e, void (*const f) (void *)) {
+ cl_error_t err = cl_error.err.ok;
+ if (e == NULL) err = cl_error.err.mem.null;
+ if (!err) {
+ e->free = f;
+ }
+ return err;
+}
+
+// Private function
+static void
+corelibs_llist_remove (cl_llist_t *e) {
+ corelibs_llist_link (2, e->prev, e->next);
+ if (e->free != NULL) e->free (e->cont);
+ free (e);
+}
diff --git a/src/llist/llist.h b/src/llist/llist.h
new file mode 100644
index 0000000..a35281b
--- /dev/null
+++ b/src/llist/llist.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of corelibs. (https://git.redxen.eu/corelibs)
+ * Copyright (c) 2021 Alex-David Denes
+ *
+ * corelibs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * corelibs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with corelibs. If not, see .
+ */
+
+#include "types/error/error.h"
+
+#include // uintmax_t
+
+#ifndef CORELIBS_GUARD_LLIST
+#define CORELIBS_GUARD_LLIST
+
+typedef struct cl_llist_t cl_llist_t;
+
+struct corelibs_llist_interface {
+ cl_error_t (*const create) (void *content, void (*const free_function) (void *), cl_llist_t **save);
+ cl_error_t (*const link) (uintmax_t elements, ...);
+ cl_error_t (*const rep) (cl_llist_t *dest, cl_llist_t *src);
+ const struct {
+ cl_error_t (*const list) (cl_llist_t *element);
+ cl_error_t (*const elem) (cl_llist_t *element);
+ cl_error_t (*const cont) (cl_llist_t *element);
+ } free;
+ const struct {
+ cl_error_t (*const cont) (cl_llist_t *element, void *content);
+ cl_error_t (*const free) (cl_llist_t *element, void (*const free_function) (void *));
+ } set;
+ const struct {
+ cl_error_t (*const prev) (const cl_llist_t *element, cl_llist_t **save);
+ cl_error_t (*const next) (const cl_llist_t *element, cl_llist_t **save);
+ cl_error_t (*const cont) (const cl_llist_t *element, void **save);
+ } get;
+};
+extern const struct corelibs_llist_interface cl_llist;
+
+#endif /* CORELIBS_GUARD_LLIST */
+
diff --git a/src/types/error/error.c b/src/types/error/error.c
new file mode 100644
index 0000000..ddae4eb
--- /dev/null
+++ b/src/types/error/error.c
@@ -0,0 +1,92 @@
+/*
+ * This file is part of corelibs. (https://git.redxen.eu/corelibs)
+ * Copyright (c) 2021 Alex-David Denes
+ *
+ * corelibs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * corelibs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with corelibs. If not, see .
+ */
+
+#include "types/error/error.h"
+
+#include
+#include
+
+static const char *corelibs_error_string (cl_error_lang, cl_error_t);
+
+enum {
+ CORELIBS_ERROR_LANG_EN = 0,
+ CORELIBS_ERROR_LANG_COUNT, // Must be last
+};
+
+enum {
+ CORELIBS_ERROR_ERR_OK = 0,
+ CORELIBS_ERROR_ERR_UNK,
+ CORELIBS_ERROR_ERR_UNDEF,
+ CORELIBS_ERROR_ERR_INVAL,
+ CORELIBS_ERROR_ERR_MEM_ALLOC,
+ CORELIBS_ERROR_ERR_MEM_NULL,
+ CORELIBS_ERROR_ERR_MEM_OOB,
+ CORELIBS_ERROR_ERR_DATA_IMMUT,
+ CORELIBS_ERROR_ERR_DATA_INVAL,
+ CORELIBS_ERROR_ERR_DATA_INCOMPAT,
+ CORELIBS_ERROR_ERR_ARGS_MIS,
+ CORELIBS_ERROR_ERR_COUNT, // Must be last
+};
+
+static const char *const cl_error_strings[CORELIBS_ERROR_LANG_COUNT][CORELIBS_ERROR_ERR_COUNT] = {
+ [CORELIBS_ERROR_LANG_EN] = {
+ // General
+ [CORELIBS_ERROR_ERR_OK] = "OK",
+ [CORELIBS_ERROR_ERR_UNK] = "Unknown error",
+ [CORELIBS_ERROR_ERR_UNDEF] = "Undefined or missing variable",
+ [CORELIBS_ERROR_ERR_INVAL] = "Invalid action",
+ // Memory
+ [CORELIBS_ERROR_ERR_MEM_ALLOC] = "Allocation failed",
+ [CORELIBS_ERROR_ERR_MEM_NULL] = "NULL address",
+ [CORELIBS_ERROR_ERR_MEM_OOB] = "Out of bounds",
+ // Data
+ [CORELIBS_ERROR_ERR_DATA_IMMUT] = "Immutable data",
+ [CORELIBS_ERROR_ERR_DATA_INCOMPAT] = "Incompatible data",
+ [CORELIBS_ERROR_ERR_DATA_INVAL] = "Invalid data",
+ // Arguments
+ [CORELIBS_ERROR_ERR_ARGS_MIS] = "Missing argument(s)",
+ },
+};
+
+struct corelibs_error_tree const cl_error = {
+ .string = corelibs_error_string,
+ .err = {
+ .ok = CORELIBS_ERROR_ERR_OK,
+ .unk = CORELIBS_ERROR_ERR_UNK,
+ .undef = CORELIBS_ERROR_ERR_UNDEF,
+ .mem = {
+ .null = CORELIBS_ERROR_ERR_MEM_NULL,
+ .alloc = CORELIBS_ERROR_ERR_MEM_ALLOC,
+ .oob = CORELIBS_ERROR_ERR_MEM_OOB,
+ },
+ .data = {
+ .immut = CORELIBS_ERROR_ERR_DATA_IMMUT,
+ .incompat = CORELIBS_ERROR_ERR_DATA_INCOMPAT,
+ .inval = CORELIBS_ERROR_ERR_DATA_INVAL,
+ },
+ .args = {
+ .mis = CORELIBS_ERROR_ERR_ARGS_MIS,
+ },
+ },
+};
+
+static const char *
+corelibs_error_string (const cl_error_lang lang, const cl_error_t err) {
+ if (lang >= CORELIBS_ERROR_LANG_COUNT || err < 0 || err >= CORELIBS_ERROR_ERR_COUNT) return NULL;
+ return cl_error_strings[lang][err];
+}
diff --git a/src/types/error/error.h b/src/types/error/error.h
new file mode 100644
index 0000000..d467b9e
--- /dev/null
+++ b/src/types/error/error.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of corelibs. (https://git.redxen.eu/corelibs)
+ * Copyright (c) 2021 Alex-David Denes
+ *
+ * corelibs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * corelibs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with corelibs. If not, see .
+ */
+
+#include // int_least16_t
+
+#ifndef CORELIBS_GUARD_ERROR
+#define CORELIBS_GUARD_ERROR
+
+typedef int_least16_t cl_error_t;
+typedef uint_least8_t cl_error_lang;
+
+struct corelibs_error_tree {
+ const char *(*const string) (cl_error_lang language, cl_error_t errno);
+ const struct {
+ const cl_error_t ok,
+ unk,
+ undef;
+ const struct {
+ const cl_error_t null,
+ alloc,
+ oob;
+ } mem;
+ const struct {
+ const cl_error_t immut,
+ incompat,
+ inval;
+ } data;
+ const struct {
+ const cl_error_t mis;
+ } args;
+ } err;
+};
+extern const struct corelibs_error_tree cl_error;
+
+#endif /* CORELIBS_GUARD_ERROR */
+