#include #include #include #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); }