diff options
| -rw-r--r-- | src/format.c | 119 | ||||
| -rw-r--r-- | src/format.h | 42 |
2 files changed, 161 insertions, 0 deletions
diff --git a/src/format.c b/src/format.c new file mode 100644 index 0000000..a7bad77 --- /dev/null +++ b/src/format.c @@ -0,0 +1,119 @@ +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "format.h" +#include "any_log.h" +#include "util.h" + +format_status_t format_init(format_t *format, const char *string, char delim, const format_pair_t *pairs) +{ + format_status_t status = FORMAT_SUCCESS; + + char **parts = NULL; + size_t length = 0, n = 0; + size_t start = 0, end = 0; + + size_t i = 0; + while (string[i] != '\0') { + if (string[i] == delim) { + // TODO + //if (string[i + 1] == delim) { + //} + + if (string[i + 1] == '{') { + if (start != end) { + parts = realloc(parts, ++length * sizeof(char **)); + parts[n++] = strslice(string, start, end); + } + + start = end = i + 2; + while (string[end] != '}') { + if (string[end] == '\0') { + status = FORMAT_UNTERMINATED; + goto clean; + } + if (string[end] == '$' && string[end + 1] == '{') { + status = FORMAT_NESTED; + goto clean; + } + end++; + } + + size_t l = end - start; + size_t next = --end; + + while (start <= end && isspace(string[start])) start++, l--; + while (start <= end && isspace(string[end])) end--, l--; + + log_info("%c'", string[end]); + log_info("'%.*s'", (int)l, string + start); + + for (size_t p = 0; pairs[p].action != FORMAT_NONE; p++) { + if (pairs[p].key == NULL || + (strlen(pairs[p].key) == l && !strncmp(string + start, pairs[p].key, l))) { + + parts = realloc(parts, ++length * sizeof(char **)); + switch (pairs[p].action) { + case FORMAT_STRING: + parts[n++] = strcopy(pairs[p].value); + break; + + case FORMAT_BYTE: + parts[n++] = (char *)(uintptr_t)pairs[p].byte; + break; + + case FORMAT_FUNCTION: + if (pairs[p].key == NULL) { + char *key = strslice(string, start, l + start); + parts[n++] = pairs[p].fn(key); + free(key); + } else + parts[n++] = pairs[p].fn(pairs[p].key); + break; + + default: + unreachable(); + } + + start = i = ++next; + goto next; + } + } + + status = FORMAT_UNKNOWN; + goto clean; + } + + } + + end = i++; +next: + } + + if (string[end] != '\0') { + while (string[end] != '\0') end++; + parts = realloc(parts, ++length * sizeof(char **)); + parts[n++] = strslice(string, start, end); + } + + format->parts = parts; + format->length = n; + + return status; + +clean: + for (size_t i = 0; i < length; i++) { + // XXX: Ugly and probably will explode + if ((uintptr_t)parts[i] > UINT8_MAX) + free(parts[i]); + } + free(parts); + + return status; +} + +void format_free(format_t *format) +{ + free(format->parts); +} diff --git a/src/format.h b/src/format.h new file mode 100644 index 0000000..bceff0c --- /dev/null +++ b/src/format.h @@ -0,0 +1,42 @@ +#ifndef COMET_FORMAT_H +#define COMET_FORMAT_H + +#include <stdint.h> +#include <stdbool.h> + +typedef struct { + char **parts; + size_t length; +} format_t; + +typedef enum { + FORMAT_SUCCESS, + FORMAT_NESTED, + FORMAT_UNKNOWN, + FORMAT_UNTERMINATED, +} format_status_t; + +typedef enum { + FORMAT_NONE, + FORMAT_STRING, + FORMAT_BYTE, + FORMAT_FUNCTION, +} format_action_t; + +typedef char *(*format_function_t)(const char *key); + +typedef struct { + format_action_t action; + const char *key; + union { + const char *value; + uint8_t byte; + format_function_t fn; + }; +} format_pair_t; + +format_status_t format_init(format_t *format, const char *string, char delim, const format_pair_t *pairs); + +void format_free(format_t *format); + +#endif |
