diff options
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | any_ini.h | 205 | ||||
| -rw-r--r-- | test/ini.c | 38 |
3 files changed, 244 insertions, 1 deletions
@@ -1,6 +1,6 @@ # any\_libs -single-file C library licensed under MIT +single-file C libraries licensed under MIT **NOTE: Still in early stages of development! Use at your own risk** 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 diff --git a/test/ini.c b/test/ini.c new file mode 100644 index 0000000..3097e98 --- /dev/null +++ b/test/ini.c @@ -0,0 +1,38 @@ +#include <string.h> +#include <stdio.h> + +#define ANY_INI_IMPLEMENT +#include "any_ini.h" + +int main() +{ + const char *src = + "ciao = 10\n" + "global = yes\n" + " complex name with space = value with space \n" + "\n[sus]\n" + "nice = 1\n" + ";comment\n" + "another=10;x\n" + "true=1 ;xx\n" + " # comment 2 ;\n" + "\ntry = catch 123 bool\n" + " k e y = value pair! ; comment\n"; + + any_ini_t ini; + any_ini_init(&ini, src, strlen(src)); + + char *section = "", *key, *value; + + do { + printf("SECTION: %s\n", section); + + while ((key = any_ini_next_key(&ini)) != NULL) { + value = any_ini_next_value(&ini); + printf("PAIR: `%s` = `%s`\n", key, value); + } + + } while ((section = any_ini_next_section(&ini)) != NULL); + + return 0; +} |
