diff options
| author | Federico Angelilli <code@fedang.net> | 2024-05-13 00:01:14 +0200 |
|---|---|---|
| committer | Federico Angelilli <code@fedang.net> | 2024-05-13 00:01:14 +0200 |
| commit | af0de70502d4b5bd8e18cd2b7b4b732c17610844 (patch) | |
| tree | b9cdbbc38c0569422fd81292af19801ed9b9e8b8 /any_ini.h | |
| parent | b5ee786a0aece3e0401d08f5d378d3a0e4e8a7c1 (diff) | |
Add any_ini.h and related test
Diffstat (limited to 'any_ini.h')
| -rw-r--r-- | any_ini.h | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/any_ini.h b/any_ini.h new file mode 100644 index 0000000..540e6b3 --- /dev/null +++ b/any_ini.h @@ -0,0 +1,205 @@ +#ifndef ANY_INI_INCLUDE +#define ANY_INI_INCLUDE + +#ifndef ANY_INI_MALLOC +#define ANY_INI_MALLOC malloc +#include <stdlib.h> +#endif + +#include <stddef.h> + +typedef struct { + const char *source; + size_t length; + size_t cursor; +} any_ini_t; + +void any_ini_init(any_ini_t *ini, const char *source, size_t length); + +char *any_ini_next_section(any_ini_t *ini); + +char *any_ini_next_key(any_ini_t *ini); + +char *any_ini_next_value(any_ini_t *ini); + +#endif + +#ifdef ANY_INI_IMPLEMENT + +#include <string.h> +#include <stdbool.h> +#include <ctype.h> + +#ifndef ANY_INI_DELIM_COMMENT +#define ANY_INI_DELIM_COMMENT ';' +#endif + +#ifndef ANY_INI_DELIM_COMMENT2 +#define ANY_INI_DELIM_COMMENT2 '#' +#endif + +#ifndef ANY_INI_DELIM_PAIR +#define ANY_INI_DELIM_PAIR '=' +#endif + +#ifndef ANY_INI_SECTION_START +#define ANY_INI_SECTION_START '[' +#endif + +#ifndef ANY_INI_SECTION_END +#define ANY_INI_SECTION_END ']' +#endif + +void any_ini_init(any_ini_t *ini, const char *source, size_t length) +{ + ini->source = source; + ini->length = length; + ini->cursor = 0; +} + +static inline bool any_ini_more(any_ini_t *ini) +{ + return ini->cursor < ini->length; +} + +static inline bool any_ini_special(char c) +{ + return c == ANY_INI_DELIM_PAIR + || c == ANY_INI_SECTION_START + || c == ANY_INI_SECTION_END; +} + +static size_t any_ini_trim(any_ini_t *ini, size_t start, size_t end) +{ + while (isspace(ini->source[end - 1])) + end--; + + return end - start; +} + +static void any_ini_skip_comment(any_ini_t *ini) +{ + while (ini->cursor < ini->length) { + switch (ini->source[ini->cursor]) { + case ' ': + case '\t': + case '\v': + case '\r': + case '\n': + break; + + case ANY_INI_DELIM_COMMENT: +#ifdef ANY_INI_DELIM_COMMENT2 + case ANY_INI_DELIM_COMMENT2: +#endif + while (any_ini_more(ini) && ini->source[ini->cursor] != '\n') + ini->cursor++; + break; + + default: + return; + } + ini->cursor++; + } +} + +char *any_ini_next_section(any_ini_t *ini) +{ + any_ini_skip_comment(ini); + + if (!any_ini_more(ini) || ini->source[ini->cursor] != ANY_INI_SECTION_START) + return NULL; + + size_t start = ++ini->cursor; + + while (any_ini_more(ini) && ini->source[ini->cursor] != '\n') + ini->cursor++; + + size_t end = ini->cursor; + + // NOTE: Does not handle the case where ANY_INI_SECTION_END is not found + while (end > start && ini->source[end] != ANY_INI_SECTION_END) + end--; + + size_t length = end - start; + + char *section = ANY_INI_MALLOC(length + 1); + memcpy(section, &ini->source[start], length); + section[length] = '\0'; + + return section; +} + +char *any_ini_next_key(any_ini_t *ini) +{ + any_ini_skip_comment(ini); + + if (!any_ini_more(ini) || any_ini_special(ini->source[ini->cursor])) + return NULL; + + size_t start = ini->cursor; + + while (any_ini_more(ini)) { + switch (ini->source[ini->cursor]) { + case '\n': + case ANY_INI_DELIM_COMMENT: +#ifdef ANY_INI_DELIM_COMMENT2 + case ANY_INI_DELIM_COMMENT2: +#endif + case ANY_INI_DELIM_PAIR: + break; + + default: + ini->cursor++; + continue; + } + break; + } + + size_t end = ini->cursor; + size_t length = any_ini_trim(ini, start, end); + + char *key = ANY_INI_MALLOC(length + 1); + memcpy(key, &ini->source[start], length); + key[length] = '\0'; + + return key; +} + +char *any_ini_next_value(any_ini_t *ini) +{ + if (!any_ini_more(ini) || ini->source[ini->cursor] != ANY_INI_DELIM_PAIR) + return NULL; + + ++ini->cursor; + any_ini_skip_comment(ini); + + size_t start = ini->cursor; + + while (any_ini_more(ini)) { + switch (ini->source[ini->cursor]) { + case '\n': + case ANY_INI_DELIM_COMMENT: +#ifdef ANY_INI_DELIM_COMMENT2 + case ANY_INI_DELIM_COMMENT2: +#endif + break; + + default: + ini->cursor++; + continue; + } + break; + } + + size_t end = ini->cursor; + size_t length = any_ini_trim(ini, start, end); + + char *value = ANY_INI_MALLOC(length + 1); + memcpy(value, &ini->source[start], length); + value[length] = '\0'; + + return value; +} + +#endif |
