#include #include #include #include #include "format.h" #include "any_log.h" #include "util.h" #define format_grow(need) \ do { \ if (n + 1 >= length) { \ length += (need); \ parts = realloc(parts, length * sizeof(char *)); \ assert(parts != NULL); \ marks = realloc(marks, length * sizeof(uint8_t)); \ assert(marks != NULL); \ } \ } while (0) bool format_init(format_t *format, const char *string, char delim) { char **parts = NULL; uint8_t *marks = NULL; size_t length = 0, n = 0; size_t start = 0, end = 0; while (string[end] != '\0') { if (string[end] == delim) { // TODO: Escape formatting if (string[end + 1] == '{') { format_grow(2); if (start != end) { parts[n] = strslice(string, start, end); marks[n] = false; n++; } start = end += 2; while (string[end] != '}') { 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--; while (start <= end && isspace(string[start])) start++, l--; while (start <= end && isspace(string[end])) end--, l--; parts[n] = strslice(string, start, start + l); marks[n] = true; n++; start = end = ++next; goto next; } } end++; next: } if (start != end || string[end] != '\0') { while (string[end] != '\0') end++; format_grow(1); parts[n] = strslice(string, start, end); marks[n] = false; n++; } format->parts = parts; format->marks = marks; format->length = n; return true; } 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; size_t l = strlen(format->parts[i]); for (size_t j = 0; pairs[j].key != NULL; j++) { size_t kl = strlen(pairs[j].key); if ((pairs[j].prefix && !strncmp(pairs[j].key, format->parts[i], kl)) || (pairs[j].postfix && l > kl && !strncmp(pairs[j].key, format->parts[i] + (l - kl), kl)) || !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 block '%s'", format->parts[i], label); next: } 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); }