Author: PQCraft <0456523@gmail.com>
Init
.gitignore | 19 +++++ LICENSE | 18 ++++ Makefile | 149 +++++++++++++++++++++++++++++++++++++++++ include/confio/confio.h | 57 +++++++++++++++ include/confio/handlers.h | 31 ++++++++ include/confio/version.h | 8 ++ src/confio.c | 10 ++ src/crc.c | 70 +++++++++++++++++++ src/crc.h | 12 +++ src/handlers.c | 1 src/vlb.h | 81 ++++++++++++++++++++++ tests/.gitignore | 10 ++ tests/Makefile | 29 +++++++ tests/common.mk | 104 ++++++++++++++++++++++++++++ tests/example/main.c | 22 ++++++ tests/harness.h | 67 ++++++++++++++++++
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..af0ab48d8b604598ef94df8ae2007450e78eb8c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +* +!/docs/ +!/docs/** +!/examples/ +!/examples/** +!/include/ +!/include/** +!/src/ +!/src/** +!/tests/ +!/tests/** +!/*.md +!/*.sh +!/LICENSE +!/Makefile +!/README.md +.** +!/.gitattributes +!/.gitignore diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..120397215bdd48ed96c0a214856d5bd02726348c --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) non-bloat collective contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3669c25fbb6f9bd3184275bcddc91fa492278c3a --- /dev/null +++ b/Makefile @@ -0,0 +1,149 @@ +export CFLAGS CPPFLAGS LDFLAGS LDLIBS DEBUG ASAN O + +SRCDIR ?= src +INCDIR ?= include +OBJDIR ?= obj +OUTDIR ?= lib + +ifneq ($(DEBUG),y) + OBJDIR := $(OBJDIR)/release +else + OBJDIR := $(OBJDIR)/debug +endif +ifeq ($(ASAN),y) + OBJDIR := $(OBJDIR)_asan +endif +OBJDIR_STATIC := $(OBJDIR)/static +OBJDIR_DYNAMIC := $(OBJDIR)/dynamic + +SOURCES := $(wildcard $(SRCDIR)/*.c) +OBJECTS_STATIC := $(patsubst $(SRCDIR)/%.c,$(OBJDIR_STATIC)/%.o,$(SOURCES)) +OBJECTS_DYNAMIC := $(patsubst $(SRCDIR)/%.c,$(OBJDIR_DYNAMIC)/%.o,$(SOURCES)) + +VER_MAJOR := $(shell grep -m 1 '#define CONFIO_VER_MAJOR ' $(INCDIR)/confio/version.h | sed 's/#define .* //') +VER_MINOR := $(shell grep -m 1 '#define CONFIO_VER_MINOR ' $(INCDIR)/confio/version.h | sed 's/#define .* //') +VER_PATCH := $(shell grep -m 1 '#define CONFIO_VER_PATCH ' $(INCDIR)/confio/version.h | sed 's/#define .* //') +VER := $(VER_MAJOR).$(VER_MINOR).$(VER_PATCH) + +BIN ?= confio +BIN_STATIC := lib$(BIN).a +BIN_DYNAMIC := lib$(BIN).so + +TARGET_STATIC := $(OUTDIR)/$(BIN_STATIC) +TARGET_DYNAMIC := $(OUTDIR)/$(BIN_DYNAMIC).$(VER) + +SYSROOT ?= /usr +SYSINC ?= $(SYSROOT)/include +SYSLIB ?= $(SYSROOT)/lib + +CC ?= gcc +LD := $(CC) +AR ?= ar +_CC := $(TOOLCHAIN)$(CC) +_LD := $(TOOLCHAIN)$(LD) +_AR := $(TOOLCHAIN)$(AR) + +_CFLAGS := $(CFLAGS) -std=c99 -Wall -Wextra -Wuninitialized -Wundef +_CPPFLAGS := $(CPPFLAGS) -I$(INCDIR) +_LDFLAGS := $(LDFLAGS) +_LDLIBS := $(LDLIBS) + +ifeq ($(DEBUG),y) + _CFLAGS += -g -fsanitize=address -fno-omit-frame-pointer -Wdouble-promotion + #_CFLAGS += -Wconversion + _LDFLAGS += -fsanitize=address + O ?= g +else + _CPPFLAGS += -DNDEBUG + O ?= 2 +endif +_CFLAGS += -O$(O) +ifeq ($(ASAN),y) + _CFLAGS += -fsanitize=address + _LDFLAGS += -fsanitize=address +endif + +.SECONDEXPANSION: + +define mkdir +if [ ! -d '$(1)' ]; then echo 'Creating $(1)/...'; mkdir -p '$(1)'; fi; true +endef +define rm +if [ -f '$(1)' ]; then echo 'Removing $(1)...'; rm -f '$(1)'; fi; true +endef +define rmdir +if [ -d '$(1)' ]; then echo 'Removing $(1)/...'; rm -rf '$(1)'; fi; true +endef + +deps.filter := %.c %.h +deps.option := -MM +define deps +$$(filter $$(deps.filter),,$$(shell $(_CC) $(_CFLAGS) $(_CPPFLAGS) -E $(deps.option) $(1))) +endef + +build: $(TARGET_STATIC) $(TARGET_DYNAMIC) + @: + +static: $(TARGET_STATIC) + @: + +dynamic: $(TARGET_DYNAMIC) + @: + +$(OUTDIR): + @$(call mkdir,$@) + +$(OBJDIR_STATIC): + @$(call mkdir,$@) + +$(OBJDIR_DYNAMIC): + @$(call mkdir,$@) + +$(OBJDIR_STATIC)/%.o: $(SRCDIR)/%.c $(call deps,$(SRCDIR)/%.c) | $(OBJDIR_STATIC) $(OUTDIR) + @echo Compiling $<... + @$(_CC) $(_CFLAGS) $(_CPPFLAGS) $< -c -o $@ + @echo Compiled $< + +$(OBJDIR_DYNAMIC)/%.o: $(SRCDIR)/%.c $(call deps,$(SRCDIR)/%.c) | $(OBJDIR_DYNAMIC) $(OUTDIR) + @echo Compiling $<... '(dynamic)' + @$(_CC) $(_CFLAGS) -fPIC $(_CPPFLAGS) -DCONFIO_DYNAMIC $< -c -o $@ + @echo Compiled $< '(dynamic)' + +$(TARGET_STATIC): $(OBJECTS_STATIC) | $(OUTDIR) + @echo Creating $@... + @$(_AR) rcs $@ $^ + @echo Created $@ + +$(TARGET_DYNAMIC): $(OBJECTS_DYNAMIC) | $(OUTDIR) + @echo Linking $@... + @$(_LD) $(_LDFLAGS) -shared $^ $(_LDLIBS) -o $@ + -@cd $(OUTDIR) && ln -s $(BIN_DYNAMIC).$(VER) $(BIN_DYNAMIC).$(VER_MAJOR) + -@cd $(OUTDIR) && ln -s $(BIN_DYNAMIC).$(VER_MAJOR) $(BIN_DYNAMIC) + @echo Linked $@ + +clean: + @$(call rmdir,$(OBJDIR)) + +distclean: clean + @$(call rm,$(TARGET_STATIC)) + @$(call rm,$(OUTDIR)/$(BIN_DYNAMIC)) + @$(call rm,$(OUTDIR)/$(BIN_DYNAMIC).$(VER_MAJOR)) + @$(call rm,$(TARGET_DYNAMIC)) + +tests: + @$(MAKE) -C tests + +clean-tests: + @$(MAKE) -C tests clean + +distclean-tests: + @$(MAKE) -C tests distclean + +install: + @echo Installing headers... + @cp -r $(INCDIR)/* $(SYSINC)/ + @echo Installing libraries... + @cp -r $(OUTDIR)/* $(SYSLIB)/ + @echo Done + +.PHONY: build static dynamic clean distclean tests clean-tests distclean-tests install diff --git a/include/confio/confio.h b/include/confio/confio.h new file mode 100644 index 0000000000000000000000000000000000000000..861489a09a161d93fb32c29cf4d27ead710a2ec4 --- /dev/null +++ b/include/confio/confio.h @@ -0,0 +1,57 @@ +#ifndef CONFIO_H +#define CONFIO_H + +#include <stdio.h> /* TODO: 'NO_STDIO' option */ +#include <stdbool.h> + +#include "version.h" + +// Get the version (useless for static linking, slightly useful for dynamic linking) +// - returns a pointer to {major, minor, patch} +const unsigned* ConfIO_GetVersion(void); + +// Called when a var is being read in +// - return false to indicate an error +typedef bool ConfIO_ReadVarFunc(void* ctx, const char* val, size_t len); +typedef ConfIO_ReadVarFunc* ConfIO_ReadVar; +// Called when a var is being written out +// - *len is initialized to -1 which indicates that strlen() should be called on the return value if it is non-NULL +// - return NULL to indicate an error +typedef const char* ConfIO_WriteVarFunc(void* ctx, size_t* len); +typedef ConfIO_WriteVarFunc* ConfIO_WriteVar; + +typedef struct ConfIO ConfIO; + +ConfIO* ConfIO_New(void); +void ConfIO_Del(ConfIO*); + +// Set the handlers for a variable +// - if 'sectLen' is -1, use strlen() to get the length of 'sect' +// - if 'varLen' is -1, use strlen() to get the length of 'var' +bool ConfIO_SetHandlers( + ConfIO*, char* sect, size_t sectLen, char* var, size_t varLen, + ConfIO_ReadVar, void* readVarCtx, ConfIO_WriteVar, void* writeVarCtx +); + +// Read in a file +bool ConfIO_ReadFile(ConfIO*, FILE*); +// Write out a file +bool ConfIO_WriteFile(ConfIO*, FILE*); +// TODO: ReadStream and WriteStream + +// Set a variable by calling its ReadVar handler +// - if 'sectLen' is -1, use strlen() to get the length of 'sect' +// - if 'varLen' is -1, use strlen() to get the length of 'var' +// - returns false if no ReadVar handler is set, or the handler indicates an error +bool ConfIO_SetVar(ConfIO*, char* sect, size_t sectLen, char* var, size_t varLen, const char* val, size_t valLen); +// Get a variable by calling its WriteVar handler +// - 'valLen' can be NULL if you do not want strlen() to be called if the handler outputs a 'len' of -1 +// - returns NULL if no WriteVar handler is set, or the handler indicates an error +const char* ConfIO_GetVar(ConfIO*, char* sect, size_t sectLen, char* var, size_t varLen, size_t* valLen); + +#ifndef CONFIO_NO_DEFAULT_HANDLERS + // Includes the default ConfIO_{Read|Write}Var_... handlers + #include "handlers.h" +#endif + +#endif diff --git a/include/confio/handlers.h b/include/confio/handlers.h new file mode 100644 index 0000000000000000000000000000000000000000..7a9e035a3852251ea94d172d3b612448f945c0ed --- /dev/null +++ b/include/confio/handlers.h @@ -0,0 +1,31 @@ +#ifndef CONFIO_HANDLERS_H +#define CONFIO_HANDLERS_H + +#include "confio.h" + +#include <stdint.h> + +// Convenience macro for ConfIO_SetHandlers +#define CONFIO_HANDLERS(TYPE, VAR) ConfIO_ReadVar_##TYPE, &VAR, ConfIO_WriteVar_##TYPE, &VAR + +// char, short, int, long, long long +ConfIO_ReadVarFunc ConfIO_ReadVar_C, ConfIO_ReadVar_SI, ConfIO_ReadVar_I, ConfIO_ReadVar_LI, ConfIO_ReadVar_LLI; +ConfIO_WriteVarFunc ConfIO_WriteVar_C, ConfIO_WriteVar_SI, ConfIO_WriteVar_I, ConfIO_WriteVar_LI, ConfIO_WriteVar_LLI; + +// unsigned char, short unsigned, unsigned, long unsigned, long long unsigned +ConfIO_ReadVarFunc ConfIO_ReadVar_UC, ConfIO_ReadVar_SU, ConfIO_ReadVar_U, ConfIO_ReadVar_LU, ConfIO_ReadVar_LLU; +ConfIO_WriteVarFunc ConfIO_WriteVar_UC, ConfIO_WriteVar_SU, ConfIO_WriteVar_U, ConfIO_WriteVar_LU, ConfIO_WriteVar_LLU; + +// float, double, long double +ConfIO_ReadVarFunc ConfIO_ReadVar_F, ConfIO_ReadVar_D, ConfIO_ReadVar_LD; +ConfIO_WriteVarFunc ConfIO_WriteVar_F, ConfIO_WriteVar_D, ConfIO_WriteVar_LD; + +// int8_t, int16_t, int32_t, int64_t +ConfIO_ReadVarFunc ConfIO_ReadVar_I8, ConfIO_ReadVar_I16, ConfIO_ReadVar_I32, ConfIO_ReadVar_I64; +ConfIO_WriteVarFunc ConfIO_WriteVar_I8, ConfIO_WriteVar_I16, ConfIO_WriteVar_I32, ConfIO_WriteVar_I64; + +// uint8_t, uint16_t, uint32_t, uint64_t +ConfIO_ReadVarFunc ConfIO_ReadVar_U8, ConfIO_ReadVar_U16, ConfIO_ReadVar_U32, ConfIO_ReadVar_U64; +ConfIO_WriteVarFunc ConfIO_WriteVar_U8, ConfIO_WriteVar_U16, ConfIO_WriteVar_U32, ConfIO_WriteVar_U64; + +#endif diff --git a/include/confio/version.h b/include/confio/version.h new file mode 100644 index 0000000000000000000000000000000000000000..2542ebe45884fc29a8508e5fffc623863921cace --- /dev/null +++ b/include/confio/version.h @@ -0,0 +1,8 @@ +#ifndef CONFIO_VERSION_H +#define CONFIO_VERSION_H + +#define CONFIO_VER_MAJOR 1 +#define CONFIO_VER_MINOR 0 +#define CONFIO_VER_PATCH 0 + +#endif diff --git a/src/confio.c b/src/confio.c new file mode 100644 index 0000000000000000000000000000000000000000..1f143d3d1a86907d0694a7e2350c34836787b66a --- /dev/null +++ b/src/confio.c @@ -0,0 +1,10 @@ +#include <confio/confio.h> + +const unsigned* ConfIO_GetVersion(void) { + static const unsigned ver[3] = { + CONFIO_VER_MAJOR, + CONFIO_VER_MINOR, + CONFIO_VER_PATCH + }; + return ver; +} diff --git a/src/crc.c b/src/crc.c new file mode 100644 index 0000000000000000000000000000000000000000..2b8c6b08ea91396d8f24ab521d194c9b5687a099 --- /dev/null +++ b/src/crc.c @@ -0,0 +1,70 @@ +#include "crc.h" + +#include <ctype.h> + +static const uint32_t crc32Table[] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +uint32_t ConfIO_Crc32(const char* d, size_t l) { + uint32_t crc = 0; + for (size_t i = 0; i < l; ++i) { + crc = crc32Table[(crc ^ ((unsigned char*)d)[i]) & 0xFF] ^ (crc >> 8); + } + return crc; +} + +uint32_t ConfIO_CaseCrc32(const char* d, size_t l) { + uint32_t crc = 0; + for (size_t i = 0; i < l; ++i) { + char c = tolower(d[i]); + crc = crc32Table[(crc ^ c) & 0xFF] ^ (crc >> 8); + } + return crc; +} + +uint32_t ConfIO_ContCrc32(uint32_t crc, const char* d, size_t l) { + for (size_t i = 0; i < l; ++i) { + crc = crc32Table[(crc ^ ((unsigned char*)d)[i]) & 0xFF] ^ (crc >> 8); + } + return crc; +} + +uint32_t ConfIO_ContCaseCrc32(uint32_t crc, const char* d, size_t l) { + for (size_t i = 0; i < l; ++i) { + char c = tolower(d[i]); + crc = crc32Table[(crc ^ c) & 0xFF] ^ (crc >> 8); + } + return crc; +} diff --git a/src/crc.h b/src/crc.h new file mode 100644 index 0000000000000000000000000000000000000000..d3b2735a2a2b05c8046077765cc82e70949ee3a9 --- /dev/null +++ b/src/crc.h @@ -0,0 +1,12 @@ +#ifndef CONFIO_CRC_H +#define CONFIO_CRC_H + +#include <stdint.h> +#include <stddef.h> + +uint32_t ConfIO_Crc32(const char*, size_t); +uint32_t ConfIO_CaseCrc32(const char*, size_t); +uint32_t ConfIO_ContCrc32(uint32_t, const char*, size_t); +uint32_t ConfIO_ContCaseCrc32(uint32_t, const char*, size_t); + +#endif diff --git a/src/handlers.c b/src/handlers.c new file mode 100644 index 0000000000000000000000000000000000000000..daa98bb591ce6b1d80c874c142f9df2137ab2984 --- /dev/null +++ b/src/handlers.c @@ -0,0 +1 @@ +#include <confio/handlers.h> diff --git a/src/vlb.h b/src/vlb.h new file mode 100644 index 0000000000000000000000000000000000000000..4e3bfead7a058b0be3a585510bd17d5df7cc02cc --- /dev/null +++ b/src/vlb.h @@ -0,0 +1,81 @@ +#ifndef CONFIO_VLB_H +#define CONFIO_VLB_H + +#include <stddef.h> +#include <stdlib.h> + +#define VLB(T) {\ + T* data;\ + size_t len;\ + size_t size;\ +} + +#define VLB_OOM_NOP + +#define VLB__EXP(VLB__b, VLB__en, VLB__ed, VLB__do, ...) do {\ + if ((VLB__b).len != (VLB__b).size) {\ + VLB__do;\ + } else {\ + register size_t VLB__tmp = (VLB__b).size;\ + VLB__tmp = VLB__tmp * (VLB__en) / (VLB__ed);\ + if (VLB__tmp <= (VLB__b).size) VLB__tmp = (VLB__b).size + 1;\ + void* VLB__ptr = realloc((VLB__b).data, VLB__tmp * sizeof(*(VLB__b).data));\ + if (VLB__ptr) {(VLB__b).data = VLB__ptr; VLB__do; (VLB__b).size = VLB__tmp;}\ + else {__VA_ARGS__}\ + }\ +} while (0) +#define VLB__EXP_MULTI(VLB__b, VLB__l, VLB__en, VLB__ed, ...) do {\ + if ((VLB__l) > (VLB__b).size) {\ + register size_t VLB__tmp = (VLB__b).size;\ + do {\ + register size_t VLB__old = VLB__tmp;\ + VLB__tmp = VLB__tmp * (VLB__en) / (VLB__ed);\ + if (VLB__tmp <= VLB__old) VLB__tmp = VLB__old + 1;\ + } while (VLB__tmp < (VLB__l));\ + void* VLB__ptr = realloc((VLB__b).data, VLB__tmp * sizeof(*(VLB__b).data));\ + if (VLB__ptr) {(VLB__b).data = VLB__ptr; (VLB__b).len = (VLB__l); (VLB__b).size = VLB__tmp;}\ + else {__VA_ARGS__}\ + } else if ((VLB__l) > (VLB__b).len) {\ + (VLB__b).len = (VLB__l);\ + }\ +} while (0) + +#define VLB_INIT(VLB__b, VLB__sz, ...) do {\ + (VLB__b).data = malloc((VLB__sz) * sizeof(*(VLB__b).data));\ + if ((VLB__b).data || !(VLB__sz)) {\ + (VLB__b).len = 0;\ + (VLB__b).size = (VLB__sz);\ + } else {\ + __VA_ARGS__\ + }\ +} while (0) +#define VLB_ZINIT(VLB__b) do {\ + (VLB__b).data = NULL;\ + (VLB__b).len = 0;\ + (VLB__b).size = 0;\ +} while (0) +#define VLB_FREE(b) free((b).data) + +#define VLB_ADD(VLB__b, VLB__d, VLB__en, VLB__ed, ...) do {\ + VLB__EXP((VLB__b), (VLB__en), (VLB__ed), (VLB__b).data[(VLB__b).len++] = (VLB__d), __VA_ARGS__);\ +} while (0) +#define VLB_NEXTPTR(VLB__b, VLB__o, VLB__en, VLB__ed, ...) do {\ + VLB__EXP((VLB__b), (VLB__en), (VLB__ed), (VLB__o) = &(VLB__b).data[(VLB__b).len++], __VA_ARGS__);\ +} while (0) + +#define VLB_EXPANDBY(VLB__b, VLB__a, VLB__en, VLB__ed, ...) do {\ + register size_t VLB__l = (VLB__b).len + (VLB__a);\ + VLB__EXP_MULTI((VLB__b), (VLB__l), (VLB__en), (VLB__ed), __VA_ARGS__);\ +} while (0) +#define VLB_EXPANDTO(VLB__b, VLB__l, VLB__en, VLB__ed, ...) do {\ + VLB__EXP_MULTI((VLB__b), (VLB__l), (VLB__en), (VLB__ed), __VA_ARGS__);\ +} while (0) +#define VLB_SHRINK(VLB__b, ...) do {\ + if ((VLB__b).len != (VLB__b).size) {\ + void* VLB__ptr = realloc((VLB__b).data, (VLB__b).len * sizeof(*(VLB__b).data));\ + if (VLB__ptr || !(VLB__b).len) {(VLB__b).data = VLB__ptr; (VLB__b).size = (VLB__b).len;}\ + else {__VA_ARGS__}\ + }\ +} while (0) + +#endif diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..77cbd2032a3b8ee61b70c6498a767e4d34da84db --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,10 @@ +* +!/*/ +!/*/*.c +!/*/*.h +!/*.h +!/common.mk +!/Makefile +!/README.md +.** +!/.gitignore diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e29b34a7fb05c22af6613a423edd0a9363885d6c --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,29 @@ +export + +DIRS := $(patsubst %/,%,$(dir $(wildcard */))) + +RUN := $(DIRS:%=run\ %) +BUILD := $(DIRS:%=build\ %) +CLEAN := $(DIRS:%=clean\ %) +DISTCLEAN := $(DIRS:%=distclean\ %) + +all run: $(RUN) +$(RUN): + @$(MAKE) -C $(wordlist 2,2,$@) -f ../common.mk run + +build: $(BUILD) +$(BUILD): + @$(MAKE) -C $(wordlist 2,2,$@) -f ../common.mk build + +clean: $(CLEAN) +$(CLEAN): + @$(MAKE) -C $(wordlist 2,2,$@) -f ../common.mk clean + +distclean: $(DISTCLEAN) +$(DISTCLEAN): + @$(MAKE) -C $(wordlist 2,2,$@) -f ../common.mk distclean + +ls: + @printf '%s\n' $(DIRS) + +.PHONY: all run $(RUN) build $(BUILD) clean $(CLEAN) distclean $(DISTCLEAN) ls diff --git a/tests/common.mk b/tests/common.mk new file mode 100644 index 0000000000000000000000000000000000000000..ba3accaea97ecd803d30455e0aa262b230d6e586 --- /dev/null +++ b/tests/common.mk @@ -0,0 +1,104 @@ +export CFLAGS CPPFLAGS LDFLAGS LDLIBS DEBUG ASAN O + +SRCDIR ?= . +OBJDIR ?= obj +OUTDIR ?= . + +CONFIO_DIR ?= ../../ +CONFIO_SRCDIR ?= $(CONFIO_DIR)/src +CONFIO_INCDIR ?= $(CONFIO_DIR)/include +CONFIO_OUTDIR ?= $(CONFIO_DIR)/lib + +CONFIO_SOURCES := $(wildcard $(CONFIO_SRCDIR)/*.c) + +ifneq ($(DEBUG),y) + OBJDIR := $(OBJDIR)/release +else + OBJDIR := $(OBJDIR)/debug +endif +ifeq ($(ASAN),y) + OBJDIR := $(OBJDIR)_asan +endif + +SOURCES := $(wildcard $(SRCDIR)/*.c) +OBJECTS := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SOURCES)) + +BIN := $(notdir $(CURDIR)) +TARGET := $(OUTDIR)/$(BIN) + +CC ?= gcc +LD := $(CC) +_CC := $(TOOLCHAIN)$(CC) +_LD := $(TOOLCHAIN)$(LD) + +_CFLAGS := $(CFLAGS) -std=c99 -Wall -Wextra -Wuninitialized -Wundef +_CPPFLAGS := $(CPPFLAGS) -I$(CONFIO_INCDIR) -I$(CONFIO_SRCDIR) -DTESTNAME='"$(BIN)"' +_LDFLAGS := $(LDFLAGS) -L$(CONFIO_OUTDIR) +_LDLIBS := $(LDLIBS) -lconfio + +ifeq ($(DEBUG),y) + _CFLAGS += -g -fsanitize=address -fno-omit-frame-pointer -Wdouble-promotion + #_CFLAGS += -Wconversion + _LDFLAGS += -fsanitize=address + O ?= g +else + _CPPFLAGS += -DNDEBUG + O ?= 2 +endif +_CFLAGS += -O$(O) +ifeq ($(ASAN),y) + _CFLAGS += -fsanitize=address + _LDFLAGS += -fsanitize=address +endif + +.SECONDEXPANSION: + +define mkdir +if [ ! -d '$(1)' ]; then echo 'Creating $(1)/...'; mkdir -p '$(1)'; fi; true +endef +define rm +if [ -f '$(1)' ]; then echo 'Removing $(1)...'; rm -f '$(1)'; fi; true +endef +define rmdir +if [ -d '$(1)' ]; then echo 'Removing $(1)/...'; rm -rf '$(1)'; fi; true +endef + +deps.filter := %.c %.h +deps.option := -MM +define deps +$$(filter $$(deps.filter),,$$(shell $(_CC) $(_CFLAGS) $(_CPPFLAGS) -E $(deps.option) $(1))) +endef + +run: build + @echo Running $(BIN)... + @'$(dir $(BIN))$(notdir $(BIN))' $(RUNFLAGS) + +build: $(TARGET) + @: + +$(OUTDIR): + @$(call mkdir,$@) + +$(OBJDIR): + @$(call mkdir,$@) + +$(OBJDIR)/%.o: $(SRCDIR)/%.c $(call deps,$(SRCDIR)/%.c) | $(OBJDIR) $(OUTDIR) + @echo Compiling $(notdir $(CURDIR))/$<... + @$(_CC) $(_CFLAGS) $(_CPPFLAGS) $< -c -o $@ + @echo Compiled $(notdir $(CURDIR))/$< + +$(TARGET): $(OBJECTS) $(CONFIO_OUTDIR)/libconfio.a | $(OUTDIR) + @echo Linking $@... + @$(_LD) $(_LDFLAGS) $(OBJECTS) $(_LDLIBS) -o $@ + @echo Linked $@ + +$(CONFIO_OUTDIR)/libconfio.a: $(CONFIO_SOURCES) + @$(MAKE) -C $(CONFIO_DIR) static + +clean: + @$(call rmdir,$(OBJDIR)) + +distclean: clean + @$(call rm,$(TARGET)) + +.PHONY: build run clean distclean diff --git a/tests/example/main.c b/tests/example/main.c new file mode 100644 index 0000000000000000000000000000000000000000..be1ba9a15b5f7385b608c00e9298db6f7876292e --- /dev/null +++ b/tests/example/main.c @@ -0,0 +1,22 @@ +#define H_STATUSPREFIX " " TESTNAME ": " +#include "../harness.h" + +#include <confio/confio.h> + +#include <stdio.h> + +H_TEST(version, "Example (check if version matches)", + const unsigned* ver = ConfIO_GetVersion(); + if (!ver) H_FAIL(); + + if (ver[0] != CONFIO_VER_MAJOR) H_FAILEX("Major %u != %u", ver[0], CONFIO_VER_MAJOR); + if (ver[1] != CONFIO_VER_MINOR) H_FAILEX("Minor %u != %u", ver[1], CONFIO_VER_MINOR); + if (ver[2] != CONFIO_VER_PATCH) H_FAILEX("Patch %u != %u", ver[2], CONFIO_VER_PATCH); + + // H_PASS() is implied +) + +int main() { + if (!H_DOTEST(version)) return 1; + return 0; +} diff --git a/tests/harness.h b/tests/harness.h new file mode 100644 index 0000000000000000000000000000000000000000..05b980c00ceba6a62ffc0643a1a25fd86a727b9d --- /dev/null +++ b/tests/harness.h @@ -0,0 +1,67 @@ +#ifndef NB_HARNESS_H +#define NB_HARNESS_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> + +#define H__STR_EVAL(VAL) #VAL +#define H__STR(VAL) H__STR_EVAL(VAL) + +#ifndef H_STATUSPREFIX + #define H_STATUSPREFIX "" +#endif + +#define H_TEST(H__NAME, H__FANCYNAME, ...) static bool H__TEST_##H__NAME(void* H_USERDATA) { \ + /* silence "unused parameter" warning */ \ + (void)H_USERDATA; \ + \ + /* internal defs */ \ + unsigned H__FAILLINE; \ + \ + /* user-facing defs */ \ + static const char* H_NAME = (H__FANCYNAME) ? H__FANCYNAME : H__STR(H__NAME); \ + \ + printf("%sRunning test \"%s\"...", (H_STATUSPREFIX), H_NAME); \ + fflush(stdout); \ + static const unsigned H__FIRSTLINE = __LINE__; \ + {__VA_ARGS__} \ + \ + H__PASS: \ + puts(" PASS"); \ + return true; \ + \ + H__FAIL: \ + printf(" FAIL on line %u (%s:%u)\n", H__FAILLINE - H__FIRSTLINE, __FILE__, H__FAILLINE); \ + return false; \ + \ + /* silence "unused label" warnings */ \ + goto H__PASS;\ + goto H__FAIL;\ +} + +#define H_PASS() do { \ + goto H_PASS; \ +} while (0) +#define H_FAIL() do { \ + H__FAILLINE = __LINE__; \ + goto H__FAIL; \ +} while (0) +#define H_PASSEX(...) do { \ + fputs(" PASS: ", stdout); \ + printf(__VA_ARGS__); \ + putchar('\n'); \ + return true; \ +} while (0) +#define H_FAILEX(...) do { \ + H__FAILLINE = __LINE__; \ + printf(" FAIL on line %u (%s:%u): ", H__FAILLINE - H__FIRSTLINE, __FILE__, H__FAILLINE); \ + printf(__VA_ARGS__); \ + putchar('\n'); \ + return false; \ +} while (0) + +#define H_DOTEST(NAME) H__TEST_##NAME(NULL) +#define H_DOTESTEX(NAME, USERDATA) H__TEST_##NAME((USERDATA)) + +#endif