aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/format.c119
-rw-r--r--src/format.h42
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