From 08a5f3441675c446482b473777cbba53d5191f20 Mon Sep 17 00:00:00 2001 From: Thomas Schmucker Date: Sun, 21 Jun 2026 17:20:13 +0200 Subject: rework: add testing framework --- lib/.clang-format | 45 ----- lib/.clang-tidy | 19 --- lib/compile_flags.txt | 8 - lib/config.mk | 4 - lib/include/csv.h | 71 -------- lib/makefile | 20 --- lib/src/csv.c | 464 -------------------------------------------------- 7 files changed, 631 deletions(-) delete mode 100644 lib/.clang-format delete mode 100644 lib/.clang-tidy delete mode 100644 lib/compile_flags.txt delete mode 100644 lib/config.mk delete mode 100644 lib/include/csv.h delete mode 100644 lib/makefile delete mode 100644 lib/src/csv.c (limited to 'lib') diff --git a/lib/.clang-format b/lib/.clang-format deleted file mode 100644 index b32bad6..0000000 --- a/lib/.clang-format +++ /dev/null @@ -1,45 +0,0 @@ ---- -AccessModifierOffset: -4 -AlignConsecutiveAssignments: 'true' -AlignConsecutiveDeclarations: 'true' -AlignEscapedNewlines: Left -AlignTrailingComments: 'true' -AlwaysBreakAfterReturnType: TopLevelDefinitions -BreakBeforeBraces: Stroustrup -BreakConstructorInitializers: BeforeComma -BreakInheritanceList: BeforeComma -ColumnLimit: '0' -CompactNamespaces: 'false' -Cpp11BracedListStyle: 'false' -FixNamespaceComments: 'true' -IncludeBlocks: Regroup -IncludeCategories: - - Regex: '^.*(precomp|pch|stdafx)' - Priority: -1 - - Regex: '^<.*>' - Priority: 1 - - Regex: '^".*"' - Priority: 2 - - Regex: '.*' - Priority: 3 -IndentCaseLabels: 'false' -IndentPPDirectives: AfterHash -IndentWidth: '4' -IndentWrappedFunctionNames: 'false' -KeepEmptyLinesAtTheStartOfBlocks: 'false' -PointerAlignment: Right -SortIncludes: 'true' -SpaceAfterCStyleCast: 'true' -SpaceAfterTemplateKeyword: 'false' -SpaceBeforeAssignmentOperators: 'true' -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: 'false' -SpaceInEmptyParentheses: 'false' -SpacesInAngles: 'false' -SpacesInCStyleCastParentheses: 'false' -SpacesInConditionalStatement: 'true' -SpacesInParentheses: 'false' -Standard: Auto -TabWidth: '4' -UseTab: ForIndentation -... diff --git a/lib/.clang-tidy b/lib/.clang-tidy deleted file mode 100644 index 0bceb5b..0000000 --- a/lib/.clang-tidy +++ /dev/null @@ -1,19 +0,0 @@ ---- -Checks: "*, - -abseil-*, - -altera-*, - -android-*, - -fuchsia-*, - -google-*, - -llvm*, - -modernize-use-trailing-return-type, - -zircon-*, - -readability-else-after-return, - -readability-static-accessed-through-instance, - -readability-avoid-const-params-in-decls, - -cppcoreguidelines-non-private-member-variables-in-classes, - -misc-non-private-member-variables-in-classes, -" -WarningsAsErrors: '' -HeaderFilterRegex: '' -FormatStyle: none diff --git a/lib/compile_flags.txt b/lib/compile_flags.txt deleted file mode 100644 index 8b85c07..0000000 --- a/lib/compile_flags.txt +++ /dev/null @@ -1,8 +0,0 @@ --Wall --Wextra --Wsign-compare --Wsign-conversion --pedantic --std=c99 --O2 --Iinclude diff --git a/lib/config.mk b/lib/config.mk deleted file mode 100644 index 6b4ff86..0000000 --- a/lib/config.mk +++ /dev/null @@ -1,4 +0,0 @@ -BUILD_DIR=../build -ARFLAGS=rcs -CFLAGS=-Wall -Wextra -Wsign-compare -Wsign-conversion -pedantic -std=c99 -O2 -Iinclude -DNDEBUG - diff --git a/lib/include/csv.h b/lib/include/csv.h deleted file mode 100644 index 9ac7c05..0000000 --- a/lib/include/csv.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include /* size_t */ -#include /* FILE */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - CSV_ERR_OK = 0, - CSV_ERR_OUT_OF_MEMORY = -1, - CSV_ERR_OUT_OF_RANGE = -2, - CSV_ERR_IO_READ = -3, - CSV_ERR_IO_WRITE = -4 -} csv_err_t; - -typedef struct { - int field_delimiter; - int field_separator; - - void (*cb_error)(csv_err_t, void *); - void *cb_error_arg; - - void *(*cb_allocate)(size_t, size_t, void *); - void *(*cb_reallocate)(void *, size_t, size_t, void *); - void (*cb_free)(void *, size_t, size_t, void *); - void *cb_memory_arg; -} csv_options_t; - -extern const csv_options_t csv_default_options; - -typedef struct { - char * str; - size_t cap, pos; -} csv_string_t; - -typedef struct { - size_t *fields; - size_t cap, pos; -} csv_field_t; - -typedef struct { - const csv_options_t *csv_options; - csv_string_t csv_string; - csv_field_t csv_field; -} csv_t; - -/* version */ -extern const char csv_version[]; - -/* initialization */ -void csv_init(csv_t *csv); -void csv_init_opt(csv_t *csv, const csv_options_t *const csv_options); - -/* cleanup after error */ -void csv_cleanup(csv_t *csv); - -/* read */ -size_t csv_read(csv_t *csv, FILE *in); - -/* field access */ -size_t csv_nfields(const csv_t *const csv); -const char *csv_field(const csv_t *const csv, size_t idx); - -/* error handling */ -const char *csv_err_str(csv_err_t csv_err); - -#ifdef __cplusplus -} -#endif diff --git a/lib/makefile b/lib/makefile deleted file mode 100644 index 5c832ba..0000000 --- a/lib/makefile +++ /dev/null @@ -1,20 +0,0 @@ -include config.mk - -LIBRARY=$(BUILD_DIR)/libcsv.a -OBJS=$(BUILD_DIR)/csv.o - -$(LIBRARY): $(OBJS) - ar $(ARFLAGS) $@ $(OBJS) - -$(BUILD_DIR)/%.o: src/%.c | $(BUILD_DIR) - cc $(CFLAGS) -c $< -o $@ - -$(BUILD_DIR): - mkdir -p $@ - -compile_flags.txt: - echo "$(CFLAGS)" | tr ' ' '\n' > $@ - -.PHONY: clean -clean: - rm -f $(LIBRARY) $(OBJS) diff --git a/lib/src/csv.c b/lib/src/csv.c deleted file mode 100644 index ba78dbd..0000000 --- a/lib/src/csv.c +++ /dev/null @@ -1,464 +0,0 @@ -#include "csv.h" - -#include -#include -#include -#include -#include - -// === Compile time options === - -#ifndef CSV_DEFAULT_DELIMITER -# define CSV_DEFAULT_DELIMITER '"' -#endif - -#ifndef CSV_DEFAULT_SEPARATOR -# define CSV_DEFAULT_SEPARATOR ',' -#endif - -// === some useful Makros === - -#define UNUSED(x) (void) (x) // mark a parameter as 'unused' -#define STR(s) #s // Stringify a Makro -#define XSTR(s) STR(s) - -// === Semantic Version Information === - -#define CSV_VER_MAJOR 1 -#define CSV_VER_MINOR 0 -#define CSV_VER_PATCH 0 -#define CSV_VER_APPENDIX "-dev" - -const char csv_version[] = XSTR(CSV_VER_MAJOR) "." XSTR(CSV_VER_MINOR) "." XSTR(CSV_VER_PATCH) CSV_VER_APPENDIX "\0" __DATE__ "\0" __TIME__; - -// === CSV-MEMORY Interface === - -static void * -csv_mem_reallocate(void *ptr, size_t num, size_t size, void *cb_arg) -{ - UNUSED(cb_arg); - - return reallocarray(ptr, num, size); -} - -static void -csv_mem_free(void *ptr, size_t num, size_t size, void *cb_arg) -{ - UNUSED(num); - UNUSED(size); - UNUSED(cb_arg); - - free(ptr); -} - -// === CSV-OPTIONS Interface === - -const csv_options_t csv_default_options = { - .field_delimiter = CSV_DEFAULT_DELIMITER, - .field_separator = CSV_DEFAULT_SEPARATOR, - .cb_error = NULL, - .cb_reallocate = csv_mem_reallocate, - .cb_free = csv_mem_free -}; - -// === CSV-ERROR Interface === - -static void -csv_fatal_error(csv_err_t csv_err, const csv_options_t *const csv_options) -{ - if ( csv_options->cb_error != NULL ) { - (*csv_options->cb_error)(csv_err, csv_options->cb_error_arg); - } - (void) fprintf(stderr, "fatal error: %s\n", csv_err_str(csv_err)); - abort(); -} - -// === CSV-STRING Interface === - -static inline void -csv_string_init(csv_string_t *csv_string) -{ - assert(csv_string != NULL); - - csv_string->str = NULL; - csv_string->cap = 0; - csv_string->pos = 0; -} - -static inline void -csv_string_reset(csv_string_t *csv_string) -{ - assert(csv_string != NULL); - - csv_string->pos = 0; -} - -static inline int -csv_string_isempty(csv_string_t *csv_string) -{ - assert(csv_string != NULL); - - return (csv_string->pos == 0) ? 1 : 0; -} - -static inline size_t -growth_strategy(size_t current_cap) -{ - static const size_t INITIAL_CAP = 16; - - return (current_cap == 0) ? INITIAL_CAP : (current_cap * 3) / 2; -} - -static inline void -csv_string_grow_if_needed(csv_string_t *csv_string, const csv_options_t *const csv_options) -{ - assert(csv_string != NULL); - assert(csv_options != NULL); - - if ( csv_string->pos == csv_string->cap ) { - size_t cap = growth_strategy(csv_string->cap); - char *str = csv_options->cb_reallocate(csv_string->str, cap, 1, csv_options->cb_memory_arg); - if ( str == NULL ) { - csv_fatal_error(CSV_ERR_OUT_OF_MEMORY, csv_options); - return; - } - csv_string->str = str; - csv_string->cap = cap; - } -} - -static inline void -csv_string_append(csv_string_t *csv_string, int ch, const csv_options_t *const csv_options) -{ - assert(csv_string != NULL); - assert(csv_options != NULL); - - csv_string_grow_if_needed(csv_string, csv_options); - - csv_string->str[csv_string->pos++] = (char) ch; // append char -} - -static inline void -csv_string_free(csv_string_t *csv_string, const csv_options_t *const csv_options) -{ - assert(csv_string != NULL); - assert(csv_options != NULL); - - csv_options->cb_free(csv_string->str, csv_string->cap, 1, csv_options->cb_memory_arg); - - // call *_init() for sane default values; prevent possible double-free - csv_string_init(csv_string); -} - -// === CSV-FIELD Interface === - -static inline void -csv_field_init(csv_field_t *csv_field) -{ - assert(csv_field != NULL); - - csv_field->fields = NULL; - csv_field->cap = 0; - csv_field->pos = 0; -} - -static inline void -csv_field_reset(csv_field_t *csv_field) -{ - assert(csv_field != NULL); - - csv_field->pos = 0; -} - -static inline void -csv_field_grow_if_needed(csv_field_t *csv_field, const csv_options_t *const csv_options) -{ - assert(csv_field != NULL); - assert(csv_options != NULL); - - if ( csv_field->pos == csv_field->cap ) { - size_t cap = growth_strategy(csv_field->cap); - size_t *fields = csv_options->cb_reallocate(csv_field->fields, cap, sizeof(csv_field->fields[0]), csv_options->cb_memory_arg); - if ( fields == NULL ) { - csv_fatal_error(CSV_ERR_OUT_OF_MEMORY, csv_options); - return; - } - csv_field->fields = fields; - csv_field->cap = cap; - } -} - -static inline void -csv_field_append(csv_field_t *csv_field, size_t idx, const csv_options_t *const csv_options) -{ - assert(csv_field != NULL); - assert(csv_options != NULL); - - csv_field_grow_if_needed(csv_field, csv_options); - - csv_field->fields[csv_field->pos++] = idx; // append index -} - -static inline void -csv_field_free(csv_field_t *csv_field, const csv_options_t *const csv_options) -{ - assert(csv_field != NULL); - assert(csv_options != NULL); - - csv_options->cb_free(csv_field->fields, csv_field->cap, sizeof(csv_field->fields[0]), csv_options->cb_memory_arg); - - csv_field_init(csv_field); -} - -// === CSV Interface === - -void -csv_init(csv_t *csv) -{ - assert(csv != NULL); - - csv_init_opt(csv, NULL); -} - -void -csv_init_opt(csv_t *csv, const csv_options_t *const csv_options) -{ - assert(csv != NULL); - - if ( csv_options != NULL ) { - csv->csv_options = csv_options; - } - else { - csv->csv_options = &csv_default_options; - } - - csv_string_init(&csv->csv_string); - csv_field_init(&csv->csv_field); -} - -void -csv_cleanup(csv_t *csv) -{ - assert(csv != NULL); - assert(csv->csv_options != NULL); - - csv_string_free(&csv->csv_string, csv->csv_options); - csv_field_free(&csv->csv_field, csv->csv_options); -} - -size_t -csv_nfields(const csv_t *const csv) -{ - assert(csv != NULL); - - return csv->csv_field.pos; -} - -const char * -csv_field(const csv_t *const csv, size_t idx) -{ - assert(csv != NULL); - assert(idx >= 0 && idx < csv->csv_field.pos); - - if ( idx >= csv->csv_field.pos ) { - csv_fatal_error(CSV_ERR_OUT_OF_RANGE, csv->csv_options); - return NULL; - } - return &csv->csv_string.str[csv->csv_field.fields[idx]]; -} - -size_t -csv_read(csv_t *csv, FILE *in) -{ - assert(csv != NULL); - assert(in != NULL); - - // initialize if needed... - if ( csv->csv_options == NULL ) { - csv_init(csv); - } - - if ( ferror(in) ) { - csv_fatal_error(CSV_ERR_IO_READ, csv->csv_options); - return 0; - } - - // do not try to read if EOF has already been seen - if ( feof(in) ) { - csv_cleanup(csv); - return 0; - } - - enum { - STATE_START_FIELD, - STATE_QUOTED_FIELD, - STATE_SIMPLE_FIELD, - STATE_END_FIELD, - STATE_END_LINE, - STATE_END_FILE, - }; - - register const int DELIM = csv->csv_options->field_delimiter; - register const int SEP = csv->csv_options->field_separator; - - csv_string_reset(&csv->csv_string); - csv_field_reset(&csv->csv_field); - - for ( int state = STATE_START_FIELD;; ) { - int chr; - - switch ( state ) { - case STATE_START_FIELD: - csv_field_append(&csv->csv_field, csv->csv_string.pos, csv->csv_options); - - chr = getc(in); - if ( chr == EOF ) { - state = STATE_END_FILE; - } - else if ( chr == '\r' ) { // test for CR.. - chr = getc(in); - if ( chr != '\n' ) { // ..LF - (void) ungetc(chr, in); - } - state = STATE_END_LINE; - } - else if ( chr == '\n' ) { - state = STATE_END_LINE; - } - else if ( chr == SEP ) { - state = STATE_END_FIELD; - } - else if ( chr == DELIM ) { - state = STATE_QUOTED_FIELD; - } - else { - if ( chr != '\0' ) { - csv_string_append(&csv->csv_string, chr, csv->csv_options); - } - state = STATE_SIMPLE_FIELD; - } - break; - - case STATE_QUOTED_FIELD: - do { - chr = getc(in); - if ( chr == EOF ) { - state = STATE_END_FILE; - } - else if ( chr == DELIM ) { - chr = getc(in); - if ( chr == EOF ) { - state = STATE_END_FILE; - } - else if ( chr == DELIM ) { - csv_string_append(&csv->csv_string, DELIM, csv->csv_options); - } - else if ( chr == SEP ) { - state = STATE_END_FIELD; - } - else if ( chr == '\r' ) { - chr = getc(in); - if ( chr != '\n' ) { - (void) ungetc(chr, in); - } - state = STATE_END_LINE; - } - else if ( chr == '\n' ) { - state = STATE_END_LINE; - } - else { - csv_string_append(&csv->csv_string, DELIM, csv->csv_options); - (void) ungetc(chr, in); // we have read too far... Put the character back! - } - } - else { - if ( chr != '\0' ) { - csv_string_append(&csv->csv_string, chr, csv->csv_options); - } - } - } while ( state == STATE_QUOTED_FIELD ); - break; - - case STATE_SIMPLE_FIELD: - do { - chr = getc(in); - if ( chr == EOF ) { - state = STATE_END_FILE; - } - else if ( chr == SEP ) { - state = STATE_END_FIELD; - } - else if ( chr == '\r' ) { - chr = getc(in); - if ( chr != '\n' ) { - (void) ungetc(chr, in); - } - state = STATE_END_LINE; - } - else if ( chr == '\n' ) { - state = STATE_END_LINE; - } - else { - if ( chr != '\0' ) { - csv_string_append(&csv->csv_string, chr, csv->csv_options); - } - } - } while ( state == STATE_SIMPLE_FIELD ); - break; - - case STATE_END_FIELD: - csv_string_append(&csv->csv_string, '\0', csv->csv_options); - state = STATE_START_FIELD; - break; - - case STATE_END_LINE: - csv_string_append(&csv->csv_string, '\0', csv->csv_options); - return csv->csv_field.pos; - - case STATE_END_FILE: - if ( ferror(in) ) { - csv_fatal_error(CSV_ERR_IO_READ, csv->csv_options); - return 0; - } - - if ( csv_string_isempty(&csv->csv_string) ) { - csv_cleanup(csv); - return 0; // EOF reached - } - - /* - * The last data record was not terminated with a NEWLINE-Symbol. - * So we can't signal End-Of-File for now. Terminate the current - * field and return the number of fields processed so far. - */ - csv_string_append(&csv->csv_string, '\0', csv->csv_options); - - return csv->csv_field.pos; - - default: - assert(!"this should never be happen..."); - break; - } - } - // NOT REACHED -} - -const char * -csv_err_str(csv_err_t csv_err) -{ - switch ( csv_err ) { - case CSV_ERR_OK: - return "no error"; - case CSV_ERR_OUT_OF_MEMORY: - return "out of memory"; - case CSV_ERR_OUT_OF_RANGE: - return "index out of range"; - case CSV_ERR_IO_READ: - return "read error"; - case CSV_ERR_IO_WRITE: - return "write error"; - default: - return "unknown error"; - } - // NOT REACHED -} -- cgit v1.3