aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/common.c88
-rw-r--r--src/lib/common.h41
-rw-r--r--src/lib/ducc.h11
-rw-r--r--src/lib/json.c112
-rw-r--r--src/lib/json.h32
5 files changed, 284 insertions, 0 deletions
diff --git a/src/lib/common.c b/src/lib/common.c
new file mode 100644
index 0000000..af35064
--- /dev/null
+++ b/src/lib/common.c
@@ -0,0 +1,88 @@
+#include "common.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void fatal_error(const char* msg, ...) {
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+bool str_starts_with(const char* s, const char* prefix) {
+ size_t l1 = strlen(s);
+ size_t l2 = strlen(prefix);
+ if (l1 < l2)
+ return false;
+ return strncmp(s, prefix, l2) == 0;
+}
+
+bool str_ends_with(const char* s, const char* suffix) {
+ size_t l1 = strlen(s);
+ size_t l2 = strlen(suffix);
+ if (l1 < l2)
+ return false;
+ return strcmp(s + l1 - l2, suffix) == 0;
+}
+
+void strbuilder_init(StrBuilder* b) {
+ b->len = 0;
+ b->capacity = 16;
+ b->buf = calloc(b->capacity, sizeof(char));
+}
+
+// `size` must include a trailing null byte.
+void strbuilder_reserve(StrBuilder* b, size_t size) {
+ if (size <= b->capacity)
+ return;
+ while (b->capacity < size) {
+ b->capacity *= 2;
+ }
+ b->buf = realloc(b->buf, b->capacity * sizeof(char));
+ memset(b->buf + b->len, 0, (b->capacity - b->len) * sizeof(char));
+}
+
+void strbuilder_append_char(StrBuilder* b, int c) {
+ strbuilder_reserve(b, b->len + 1 + 1);
+ b->buf[b->len++] = c;
+}
+
+void strbuilder_append_string(StrBuilder* b, const char* s) {
+ int len = strlen(s);
+ strbuilder_reserve(b, b->len + len + 1);
+ for (int i = 0; i < len; ++i) {
+ b->buf[b->len++] = s[i];
+ }
+}
+
+void strings_init(StrArray* strings) {
+ strings->len = 0;
+ strings->capacity = 32;
+ strings->data = calloc(strings->capacity, sizeof(const char*));
+}
+
+void strings_reserve(StrArray* strings, size_t size) {
+ if (size <= strings->capacity)
+ return;
+ while (strings->capacity < size) {
+ strings->capacity *= 2;
+ }
+ strings->data = realloc(strings->data, strings->capacity * sizeof(const char*));
+ memset(strings->data + strings->len, 0, (strings->capacity - strings->len) * sizeof(const char*));
+}
+
+int strings_push(StrArray* strings, const char* str) {
+ strings_reserve(strings, strings->len + 1);
+ strings->data[strings->len] = str;
+ return ++strings->len;
+}
+
+void strings_pop(StrArray* strings) {
+ if (strings->len > 0) {
+ strings->len--;
+ }
+}
diff --git a/src/lib/common.h b/src/lib/common.h
new file mode 100644
index 0000000..bb94e79
--- /dev/null
+++ b/src/lib/common.h
@@ -0,0 +1,41 @@
+#ifndef DUCC_COMMON_H
+#define DUCC_COMMON_H
+
+#include "ducc.h"
+
+_Noreturn void fatal_error(const char* msg, ...);
+
+// TODO
+#ifdef __ducc__
+#define unreachable() fatal_error("%s:%d: unreachable", __FILE__, __LINE__)
+#endif
+
+#define unimplemented() fatal_error("%s:%d: unimplemented", __FILE__, __LINE__)
+
+bool str_starts_with(const char* s, const char* prefix);
+bool str_ends_with(const char* s, const char* suffix);
+
+typedef struct {
+ size_t len;
+ size_t capacity;
+ char* buf;
+} StrBuilder;
+
+void strbuilder_init(StrBuilder* b);
+// `size` must include a trailing null byte.
+void strbuilder_reserve(StrBuilder* b, size_t size);
+void strbuilder_append_char(StrBuilder* b, int c);
+void strbuilder_append_string(StrBuilder* b, const char* s);
+
+typedef struct {
+ size_t len;
+ size_t capacity;
+ const char** data;
+} StrArray;
+
+void strings_init(StrArray* strings);
+void strings_reserve(StrArray* strings, size_t size);
+int strings_push(StrArray* strings, const char* str);
+void strings_pop(StrArray* strings);
+
+#endif
diff --git a/src/lib/ducc.h b/src/lib/ducc.h
new file mode 100644
index 0000000..31ee977
--- /dev/null
+++ b/src/lib/ducc.h
@@ -0,0 +1,11 @@
+#ifndef DUCC_DUCC_H
+#define DUCC_DUCC_H
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#endif
diff --git a/src/lib/json.c b/src/lib/json.c
new file mode 100644
index 0000000..0384516
--- /dev/null
+++ b/src/lib/json.c
@@ -0,0 +1,112 @@
+#include "json.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+
+struct JsonBuilder {
+ StrBuilder buf;
+ // not supported by ducc for now
+ // bool has_output_element[256];
+ bool* has_output_element;
+ int depth;
+};
+
+JsonBuilder* jsonbuilder_new() {
+ JsonBuilder* b = calloc(1, sizeof(JsonBuilder));
+ strbuilder_init(&b->buf);
+ b->has_output_element = calloc(256, sizeof(bool));
+ return b;
+}
+
+const char* jsonbuilder_get_output(JsonBuilder* b) {
+ return b->buf.buf;
+}
+
+static void emit_comma_if_needed(JsonBuilder* b) {
+ if (b->has_output_element[b->depth - 1]) {
+ strbuilder_append_char(&b->buf, ',');
+ }
+}
+
+void jsonbuilder_object_start(JsonBuilder* b) {
+ strbuilder_append_char(&b->buf, '{');
+ b->has_output_element[b->depth++] = false;
+}
+
+void jsonbuilder_object_end(JsonBuilder* b) {
+ b->depth--;
+ strbuilder_append_char(&b->buf, '}');
+}
+
+void jsonbuilder_object_member_start(JsonBuilder* b, const char* key) {
+ emit_comma_if_needed(b);
+ jsonbuilder_string(b, key);
+ strbuilder_append_char(&b->buf, ':');
+}
+
+void jsonbuilder_object_member_end(JsonBuilder* b) {
+ b->has_output_element[b->depth - 1] = true;
+}
+
+void jsonbuilder_array_start(JsonBuilder* b) {
+ strbuilder_append_char(&b->buf, '[');
+ b->has_output_element[b->depth++] = false;
+}
+
+void jsonbuilder_array_end(JsonBuilder* b) {
+ b->depth--;
+ strbuilder_append_char(&b->buf, ']');
+}
+
+void jsonbuilder_array_element_start(JsonBuilder* b) {
+ emit_comma_if_needed(b);
+}
+
+void jsonbuilder_array_element_end(JsonBuilder* b) {
+ b->has_output_element[b->depth - 1] = true;
+}
+
+void jsonbuilder_null(JsonBuilder* b) {
+ strbuilder_append_string(&b->buf, "null");
+}
+
+void jsonbuilder_boolean(JsonBuilder* b, bool value) {
+ strbuilder_append_string(&b->buf, value ? "true" : "false");
+}
+
+void jsonbuilder_integer(JsonBuilder* b, int value) {
+ char buf[32];
+ sprintf(buf, "%d", value);
+ strbuilder_append_string(&b->buf, buf);
+}
+
+void jsonbuilder_string(JsonBuilder* b, const char* value) {
+ if (!value) {
+ jsonbuilder_null(b);
+ return;
+ }
+
+ strbuilder_append_char(&b->buf, '"');
+
+ for (const char* p = value; *p; p++) {
+ if (*p == '"') {
+ strbuilder_append_string(&b->buf, "\\\"");
+ } else if (*p == '\\') {
+ strbuilder_append_string(&b->buf, "\\\\");
+ } else if (*p == '\b') {
+ strbuilder_append_string(&b->buf, "\\b");
+ } else if (*p == '\f') {
+ strbuilder_append_string(&b->buf, "\\f");
+ } else if (*p == '\n') {
+ strbuilder_append_string(&b->buf, "\\n");
+ } else if (*p == '\r') {
+ strbuilder_append_string(&b->buf, "\\r");
+ } else if (*p == '\t') {
+ strbuilder_append_string(&b->buf, "\\t");
+ } else {
+ strbuilder_append_char(&b->buf, *p);
+ }
+ }
+
+ strbuilder_append_char(&b->buf, '"');
+}
diff --git a/src/lib/json.h b/src/lib/json.h
new file mode 100644
index 0000000..9322901
--- /dev/null
+++ b/src/lib/json.h
@@ -0,0 +1,32 @@
+#ifndef DUCC_JSON_H
+#define DUCC_JSON_H
+
+struct JsonBuilder;
+typedef struct JsonBuilder JsonBuilder;
+
+JsonBuilder* jsonbuilder_new();
+const char* jsonbuilder_get_output(JsonBuilder* b);
+
+void jsonbuilder_object_start(JsonBuilder* b);
+void jsonbuilder_object_end(JsonBuilder* b);
+void jsonbuilder_object_member_start(JsonBuilder* b, const char* key);
+void jsonbuilder_object_member_end(JsonBuilder* b);
+
+void jsonbuilder_array_start(JsonBuilder* b);
+void jsonbuilder_array_end(JsonBuilder* b);
+void jsonbuilder_array_element_start(JsonBuilder* b);
+void jsonbuilder_array_element_end(JsonBuilder* b);
+
+void jsonbuilder_null(JsonBuilder* b);
+void jsonbuilder_boolean(JsonBuilder* b, bool value);
+void jsonbuilder_integer(JsonBuilder* b, int value);
+void jsonbuilder_string(JsonBuilder* b, const char* value);
+
+#define JSON_DUMP(x, f) \
+ do { \
+ JsonBuilder* _builder = jsonbuilder_new(); \
+ f(_builder, (x)); \
+ fprintf(stderr, "%s\n", jsonbuilder_get_output(_builder)); \
+ } while (0)
+
+#endif