summaryrefslogtreecommitdiff
path: root/cfgparse.c
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-06-01 12:19:16 +1000
committerquou <quou@disroot.org>2024-06-01 12:20:17 +1000
commitea7cd94f7aeb177618db3907a6c86b7252e018f0 (patch)
treee972f9cf590ef756c2e41f3eac5b03e16db08300 /cfgparse.c
Initial commit.
Diffstat (limited to 'cfgparse.c')
-rw-r--r--cfgparse.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/cfgparse.c b/cfgparse.c
new file mode 100644
index 0000000..6d1668f
--- /dev/null
+++ b/cfgparse.c
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cfgparse.h"
+
+static const char* next_line(const char* line) {
+ const char* c;
+ for (c = line; *c != '\n'; c++) {
+ if (!*c) return 0;
+ }
+ return c + 1;
+}
+
+static int is_object(
+ const char* line,
+ const char** start,
+ int* len
+) {
+ const char* c;
+ if (line[0] != '[') return 0;
+ *start = line + 1;
+ for (
+ c = line, *len = 0;
+ *c && *c != '\n';
+ c++, *len = *len + 1
+ ) if (*c == ']') {
+ *len = *len - 1;
+ return 1;
+ }
+ return 0;
+}
+
+static int is_iden(char c) {
+ return
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c == '_');
+}
+
+static int is_prop(
+ const char* line,
+ const char** start,
+ int* len
+) {
+ const char* c;
+ *start = line;
+ for (
+ c = line, *len = 0;
+ *c && *c != '\n';
+ c++, *len = *len + 1
+ ) if (*c == ':') {
+ *len = *len;
+ return 1;
+ } else if (!is_iden(*c)) return 0;
+ return 0;
+}
+
+static void fill_prop_string(
+ cfg_Prop* p,
+ Arena* arena,
+ const char* start,
+ int len
+) {
+ p->type = cfg_type_string;
+ p->as.str = arena_alloc(arena, len + 1);
+ memcpy(p->as.str, start, len);
+ p->as.str[len] = 0;
+}
+
+static void fill_prop_number(
+ cfg_Prop* p,
+ const char* start,
+ int len
+) {
+ (void)len;
+ p->type = cfg_type_int;
+ p->as.num = (int)strtol(start, 0, 10);
+}
+
+static void fill_prop_bool(
+ cfg_Prop* p,
+ const char* start,
+ int len
+) {
+ (void)len;
+ p->type = cfg_type_int;
+ if (!memcmp("true", start, 4))
+ p->as.num = 1;
+ else
+ p->as.num = 0;
+}
+
+static void fill_prop_data(
+ cfg_Prop* p,
+ Arena* arena,
+ const char* start,
+ int len
+) {
+ int i, size;
+ char s[3];
+ s[2] = 0;
+ size = len / 2;
+ p->type = cfg_type_data;
+ p->as.data.data = arena_alloc(arena, size);
+ p->as.data.size = size;
+ for (i = 0; i < size; i++) {
+ s[0] = start[i * 2];
+ s[1] = start[i * 2 + 1];
+ sscanf(s, "%x", (unsigned*)&p->as.data.data[i]);
+ }
+}
+
+static void fill_prop_val(
+ cfg_Prop* p,
+ Arena* arena,
+ const char* start
+) {
+ const char* c;
+ int len;
+ for (; *start && (*start == ' ' || *start == '\t'); start++);
+ for (len = 0, c = start; *c && *c != '\n'; c++, len++);
+ switch (start[0]) {
+ case '"':
+ fill_prop_string(p, arena, start + 1, len - 1);
+ break;
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ case '6': case '7': case '8':
+ case '9': case '-':
+ fill_prop_number(p, start, len);
+ break;
+ case 'f': case 't':
+ fill_prop_bool(p, start, len);
+ break;
+ case '$':
+ fill_prop_data(p, arena, start + 1, len - 1);
+ break;
+ default:
+ p->type = cfg_type_none;
+ break;
+ }
+}
+
+cfg_Object* cfg_parse(const char* src, Arena* arena) {
+ const char* line, * start;
+ int len;
+ cfg_Object* root = 0, * obj = 0, * pobj;
+ cfg_Prop* prop = 0, * pprop;
+ for (line = src; line; line = next_line(line)) {
+ len = 0;
+ if (is_object(line, &start, &len) || line == src) {
+ pobj = obj;
+ obj = arena_alloc(arena, sizeof *obj);
+ obj->prop_count = 0;
+ obj->props = 0;
+ obj->next = 0;
+ memcpy(obj->name, start, len);
+ obj->name[len] = 0;
+ if (!root)
+ root = obj;
+ else
+ pobj->next = obj;
+ } else if (!obj) continue;
+ if (is_prop(line, &start, &len)) {
+ pprop = prop;
+ prop = arena_alloc(arena, sizeof *prop);
+ prop->next = 0;
+ memcpy(prop->name, start, len);
+ prop->name[len] = 0;
+ fill_prop_val(prop, arena, line + len + 1);
+ obj->prop_count++;
+ if (!obj->props)
+ obj->props = prop;
+ else
+ pprop->next = prop;
+ }
+ }
+ return root;
+}
+
+const cfg_Prop* find_prop(
+ const cfg_Object* obj,
+ const char* name
+) {
+ const cfg_Prop* p;
+ for (p = obj->props; p; p = p->next) {
+ if (!strcmp(p->name, name)) {
+ return p;
+ }
+ }
+ return 0;
+}
+
+const cfg_Prop* find_prop_of(
+ const cfg_Object* obj,
+ const char* name,
+ cfg_Type type
+) {
+ const cfg_Prop* p;
+ for (p = obj->props; p; p = p->next) {
+ if (p->type == type && !strcmp(p->name, name)) {
+ return p;
+ }
+ }
+ return 0;
+}
+
+int find_int_default(
+ const cfg_Object* obj,
+ const char* name,
+ int def
+) {
+ const cfg_Prop* prop;
+ prop = find_prop_of(obj, name, cfg_type_int);
+ if (prop) {
+ return prop->as.num;
+ }
+ return def;
+}
+
+const char* find_string_default(
+ const cfg_Object* obj,
+ const char* name,
+ const char* def
+) {
+ const cfg_Prop* prop;
+ prop = find_prop_of(obj, name, cfg_type_string);
+ if (prop) {
+ return prop->as.str;
+ }
+ return def;
+}