From 7b6ee47d8eaf998fd9e9762ce3a6841688a843d1 Mon Sep 17 00:00:00 2001 From: Alex Denes Date: Sun, 28 Nov 2021 18:39:59 +0000 Subject: [PATCH] Merge modules into one Makefile due to cross-dependencies --- .gitmodules | 9 - Makefile | 18 ++ config.mk | 46 ++++ dynarray | 1 - encoding/baseven | 1 - llist | 1 - src/dynarray/dynarray.c | 388 +++++++++++++++++++++++++++++++++ src/dynarray/dynarray.h | 81 +++++++ src/encoding/baseven/baseven.c | 155 +++++++++++++ src/encoding/baseven/baseven.h | 42 ++++ src/llist/llist.c | 227 +++++++++++++++++++ src/llist/llist.h | 50 +++++ src/types/error/error.c | 92 ++++++++ src/types/error/error.h | 51 +++++ 14 files changed, 1150 insertions(+), 12 deletions(-) delete mode 100644 .gitmodules create mode 100644 Makefile create mode 100644 config.mk delete mode 160000 dynarray delete mode 160000 encoding/baseven delete mode 160000 llist create mode 100644 src/dynarray/dynarray.c create mode 100644 src/dynarray/dynarray.h create mode 100644 src/encoding/baseven/baseven.c create mode 100644 src/encoding/baseven/baseven.h create mode 100644 src/llist/llist.c create mode 100644 src/llist/llist.h create mode 100644 src/types/error/error.c create mode 100644 src/types/error/error.h 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 */ +