diff options
| -rw-r--r-- | src/format.c | 138 | ||||
| -rw-r--r-- | src/format.h | 28 |
2 files changed, 74 insertions, 92 deletions
diff --git a/src/format.c b/src/format.c index a7bad77..2678536 100644 --- a/src/format.c +++ b/src/format.c @@ -1,119 +1,119 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <assert.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) +#define format_grow() \ + do { \ + if (n + 1 >= length) { \ + length += 4; \ + parts = realloc(parts, length * sizeof(char *)); \ + assert(parts != NULL); \ + marks = realloc(marks, length * sizeof(bool)); \ + assert(marks != NULL); \ + } \ + } while (0) + +bool format_init(format_t *format, const char *string, char delim) { - format_status_t status = FORMAT_SUCCESS; - char **parts = NULL; + uint8_t *marks = 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) { - //} + while (string[end] != '\0') { + if (string[end] == delim) { + // TODO: Escape formatting - if (string[i + 1] == '{') { + if (string[end + 1] == '{') { if (start != end) { - parts = realloc(parts, ++length * sizeof(char **)); - parts[n++] = strslice(string, start, end); + format_grow(); + parts[n] = strslice(string, start, end); + marks[n] = false; + n++; } - start = end = i + 2; + start = end += 2; while (string[end] != '}') { - if (string[end] == '\0') { - status = FORMAT_UNTERMINATED; - goto clean; - } - if (string[end] == '$' && string[end + 1] == '{') { - status = FORMAT_NESTED; - goto clean; + if (string[end] == '\0' || (string[end] == '$' && string[end + 1] == '{')) { + for (size_t k = 0; k < n; k++) + free(parts[k]); + + free(parts); + free(marks); + return false; } end++; } size_t l = end - start; - size_t next = --end; + 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; - } - } + parts[n] = strslice(string, start, start + l); + marks[n] = true; + n++; - status = FORMAT_UNKNOWN; - goto clean; + start = end = ++next; + goto next; } - } - end = i++; + end++; next: } if (string[end] != '\0') { while (string[end] != '\0') end++; - parts = realloc(parts, ++length * sizeof(char **)); - parts[n++] = strslice(string, start, end); + + format_grow(); + parts[n] = strslice(string, start, end); + marks[n] = false; + n++; } format->parts = parts; + format->marks = marks; format->length = n; - return status; + return true; +} -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]); +bool format_remark(format_t *format, const char *label, const format_pair_t *pairs) +{ + int errors = 0; + for (size_t i = 0; i < format->length; i++) { + // Skip regular strings + if (!format->marks[i]) continue; + + for (size_t j = 0; pairs[j].key != NULL; j++) { + if (!strcmp(pairs[j].key, format->parts[i])) { + format->marks[i] = pairs[j].mark; + goto next; + } + } + + errors++; + if (label != NULL) + log_error("Unknown format option '%s' for %s", format->parts[i], label); +next: } - free(parts); - return status; + return errors == 0; } void format_free(format_t *format) { + for (size_t i = 0; i < format->length; i++) + free(format->parts[i]); + free(format->parts); + free(format->marks); } diff --git a/src/format.h b/src/format.h index bceff0c..69d9fa8 100644 --- a/src/format.h +++ b/src/format.h @@ -6,36 +6,18 @@ typedef struct { char **parts; + uint8_t *marks; 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; - }; + uint8_t mark; } format_pair_t; -format_status_t format_init(format_t *format, const char *string, char delim, const format_pair_t *pairs); +bool format_init(format_t *format, const char *string, char delim); + +bool format_remark(format_t *format, const char *label, const format_pair_t *pairs); void format_free(format_t *format); |
