summaryrefslogtreecommitdiffstats
path: root/src/json.h
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-26 12:25:48 -0300
committerMurilo Ijanc <[email protected]>2026-07-26 12:25:48 -0300
commite2c6ae13af335b311da2429c903032124f926df2 (patch)
tree73776fab7f3e52124a217e2768968fc9a8a76c34 /src/json.h
downloadc-e2c6ae13af335b311da2429c903032124f926df2.tar.gz
Initial importv0.1.0
Diffstat (limited to 'src/json.h')
-rw-r--r--src/json.h82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/json.h b/src/json.h
new file mode 100644
index 0000000..4d41714
--- /dev/null
+++ b/src/json.h
@@ -0,0 +1,82 @@
+/**
+ * @file json.h
+ * @brief Minimal JSON reader, internal to this library.
+ *
+ * Read-only, allocation-per-node, no streaming and no writer. It is here
+ * because C ships no JSON parser and the shapes this client has to read are
+ * small and fixed. It handles the whole grammar it is fed: UTF-8 throughout,
+ * `\uXXXX` escapes with surrogate pairs, and the full number syntax.
+ */
+#ifndef CEPIS_JSON_H
+#define CEPIS_JSON_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/** Deepest nesting accepted, so a hostile body cannot exhaust the stack. */
+#define JSON_MAX_DEPTH 64
+
+/** Kind of a ::json_value_t. */
+typedef enum json_type {
+ JSON_NULL,
+ JSON_BOOL,
+ JSON_NUMBER,
+ JSON_STRING,
+ JSON_ARRAY,
+ JSON_OBJECT
+} json_type_t;
+
+typedef struct json_value json_value_t;
+
+/** A parsed JSON value. Owns everything it points at. */
+struct json_value {
+ json_type_t type;
+ union {
+ bool boolean;
+ double number;
+ /** NUL-terminated UTF-8, escapes already decoded. */
+ char *string;
+ struct {
+ json_value_t **items;
+ size_t count;
+ } array;
+ struct {
+ char **keys;
+ json_value_t **values;
+ size_t count;
+ } object;
+ } as;
+};
+
+/**
+ * @brief Parse @p len bytes of JSON.
+ * @return The root value, owned by the caller, or `NULL` when @p text is not
+ * one complete JSON value followed only by whitespace.
+ */
+json_value_t *json_parse(const char *text, size_t len);
+
+/** @brief Release a value and everything below it. `NULL` is ignored. */
+void json_free(json_value_t *value);
+
+/**
+ * @brief Look a key up in an object.
+ * @return The member, borrowed from @p object, or `NULL` when @p object is not
+ * an object or has no such key. The first match wins.
+ */
+const json_value_t *json_object_get(const json_value_t *object,
+ const char *key);
+
+/** @brief The string a value holds, or `NULL` when it is not a string. */
+const char *json_as_string(const json_value_t *value);
+
+/**
+ * @brief Read a value as a number, accepting a numeric string.
+ * @return `false` when the value is absent or cannot be read as a number, in
+ * which case @p out is untouched.
+ */
+bool json_as_double(const json_value_t *value, double *out);
+
+/** @brief Like ::json_as_double, truncating towards zero. */
+bool json_as_llong(const json_value_t *value, long long *out);
+
+#endif