aboutsummaryrefslogtreecommitdiff
path: root/src/format.c
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-11-18 19:36:11 +0100
committerFederico Angelilli <code@fedang.net>2024-11-18 19:36:11 +0100
commit9df5b01201498081e20bf85a3b80d85f88a0161f (patch)
treea58f8bb732ab2523a4cfc63ddd3ebc42f5b14f95 /src/format.c
parentaa19580474f96c9aacf5e85008013891ad2a7045 (diff)
Update format
Diffstat (limited to 'src/format.c')
-rw-r--r--src/format.c138
1 files changed, 69 insertions, 69 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);
}