diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-03 17:29:12 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-03 18:42:58 +0900 |
| commit | 3654ce578e6fff53950874adf7e0e4ae0a6eb956 (patch) | |
| tree | 5b6c04273de38dba70b7c25e55da144f5f7c37da /src/lib | |
| parent | 1b406b13b03055d2b2d08e8279a4a80c41ca7c20 (diff) | |
| download | ducc-3654ce578e6fff53950874adf7e0e4ae0a6eb956.tar.gz ducc-3654ce578e6fff53950874adf7e0e4ae0a6eb956.tar.zst ducc-3654ce578e6fff53950874adf7e0e4ae0a6eb956.zip | |
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/common.c | 88 | ||||
| -rw-r--r-- | src/lib/common.h | 41 | ||||
| -rw-r--r-- | src/lib/ducc.h | 11 | ||||
| -rw-r--r-- | src/lib/json.c | 112 | ||||
| -rw-r--r-- | src/lib/json.h | 32 |
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 |
