253 lines
8.2 KiB
C
253 lines
8.2 KiB
C
#ifndef JSON_INCLUDED
|
|
#define JSON_INCLUDED
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// BASICS
|
|
/////////////////////////////////////////////////////////
|
|
|
|
// Utility string type
|
|
typedef struct {
|
|
char *ptr;
|
|
int len;
|
|
} JSON_String;
|
|
|
|
// Translate string literal to JSON_String
|
|
#define JSON_STR(X) ((JSON_String) { (X), (int) sizeof(X)-1 })
|
|
|
|
typedef struct {
|
|
char msg[100];
|
|
} JSON_Error;
|
|
|
|
typedef struct {
|
|
char *last;
|
|
char *ptr;
|
|
size_t len;
|
|
size_t cur;
|
|
} JSON_Arena;
|
|
|
|
JSON_Arena json_arena_init(char *ptr, size_t len);
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// DECODE
|
|
/////////////////////////////////////////////////////////
|
|
|
|
// Type tag for the JSON struct
|
|
typedef enum {
|
|
JSON_TYPE_BOOL,
|
|
JSON_TYPE_NULL,
|
|
JSON_TYPE_OBJECT,
|
|
JSON_TYPE_ARRAY,
|
|
JSON_TYPE_FLOAT,
|
|
JSON_TYPE_INT,
|
|
JSON_TYPE_STRING,
|
|
} JSON_Type;
|
|
|
|
// This represents a "JSON value"
|
|
//
|
|
// Although there are helper functions to access
|
|
// data from JSON values, accessing these fields
|
|
// directly is allowed.
|
|
typedef struct JSON JSON;
|
|
struct JSON {
|
|
|
|
// If this value is contained by an object
|
|
// or array, this points to the next item
|
|
// that object or array. If NULL, this is
|
|
// the last element.
|
|
JSON *next;
|
|
|
|
// Type encoded by this struct
|
|
JSON_Type type;
|
|
|
|
// If this value is contained by an object,
|
|
// this pointer and length encode the key
|
|
// associated to this value in that object.
|
|
// If the value is not contained by an object,
|
|
// the key is NULL and the length is 0.
|
|
char *key;
|
|
size_t key_len;
|
|
|
|
// Number of elements contained by this
|
|
// array. The meaning on this field depends
|
|
// on the type encoded by this struct:
|
|
// string -> number of characters
|
|
// object -> number of key-value pairs
|
|
// array -> number of items
|
|
// For any other type, this is set to 0.
|
|
size_t len;
|
|
|
|
union {
|
|
|
|
// Pointer to the first child value when the
|
|
// type of this value is array or object
|
|
JSON *head;
|
|
|
|
// Floating-point value
|
|
double fval;
|
|
|
|
// Integer value
|
|
int64_t ival;
|
|
|
|
// String value
|
|
//
|
|
// This is not null-terminated. The length is
|
|
// stored in the "len" field.
|
|
char *sval;
|
|
|
|
// Boolean value
|
|
bool bval;
|
|
};
|
|
};
|
|
|
|
JSON *json_decode(char *src, int len, JSON_Arena *arena, JSON_Error *error);
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// UTILITIES
|
|
/////////////////////////////////////////////////////////
|
|
|
|
// Returns a human-readable version of the type
|
|
const char *json_type_name(JSON_Type type);
|
|
|
|
// Return the type of a JSON value.
|
|
//
|
|
// The argument can't be NULL.
|
|
JSON_Type json_get_type(JSON *json);
|
|
|
|
// Return the key associated to a JSON value.
|
|
//
|
|
// This operation is only valid if the value is
|
|
// contained by an object JSON value.
|
|
JSON_String json_get_key(JSON *json);
|
|
|
|
// Return the boolean value associated to this
|
|
// JSON value.
|
|
//
|
|
// If the value is NULL or not a boolean, the
|
|
// fallback value is returned.
|
|
bool json_get_bool(JSON *json, bool fallback);
|
|
|
|
// Return the integer value associated to this
|
|
// JSON value.
|
|
//
|
|
// If the value is NULL or not an integer, the
|
|
// fallback value is returned.
|
|
int64_t json_get_int(JSON *json, int64_t fallback);
|
|
|
|
// Return the floating point value associated to
|
|
// this JSON value.
|
|
//
|
|
// If the value is NULL or not an double, the
|
|
// fallback value is returned.
|
|
double json_get_float(JSON *json, double fallback);
|
|
|
|
// Return the string value associated to this
|
|
// JSON value.
|
|
//
|
|
// If the value is NULL or not a string, the
|
|
// empty string is returned.
|
|
JSON_String json_get_string(JSON *json);
|
|
|
|
// Return the children of an object with the
|
|
// specified key.
|
|
//
|
|
// If the value is NULL, not an object, or does
|
|
// not contain the key, NULL is returned.
|
|
JSON *json_get_field(JSON *obj, JSON_String key);
|
|
|
|
// Note that there is no helper method for accessing
|
|
// array values. To iterate over an array JSON value,
|
|
// you need to follow the next pointers:
|
|
//
|
|
// JSON *array = ...;
|
|
// for (JSON *child = array->head; child; child = child->next) {
|
|
// ...
|
|
// }
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// INTERNAL
|
|
/////////////////////////////////////////////////////////
|
|
|
|
#define __JSON_HELPER_ARG(X) \
|
|
_Generic((X), \
|
|
bool* : json_match_arg_bool, \
|
|
int64_t* : json_match_arg_int, \
|
|
double* : json_match_arg_float, \
|
|
JSON_String*: json_match_arg_string, \
|
|
JSON** : json_match_arg_any \
|
|
)(X)
|
|
|
|
// Helper macros
|
|
#define __JSON_HELPER_DISPATCH_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
|
|
#define __JSON_HELPER_CONCAT_0(A, B) A ## B
|
|
#define __JSON_HELPER_CONCAT_1(A, B) __JSON_HELPER_CONCAT_0(A, B)
|
|
#define __JSON_HELPER_ARGS_0() (JSON_MatchArgs) { 0, (JSON_MatchArg[]) {}}
|
|
#define __JSON_HELPER_ARGS_1(a) (JSON_MatchArgs) { 1, (JSON_MatchArg[]) { __JSON_HELPER_ARG(a) }}
|
|
#define __JSON_HELPER_ARGS_2(a, b) (JSON_MatchArgs) { 2, (JSON_MatchArg[]) { __JSON_HELPER_ARG(a), __JSON_HELPER_ARG(b) }}
|
|
#define __JSON_HELPER_ARGS_3(a, b, c) (JSON_MatchArgs) { 3, (JSON_MatchArg[]) { __JSON_HELPER_ARG(a), __JSON_HELPER_ARG(b), __JSON_HELPER_ARG(c) }}
|
|
#define __JSON_HELPER_ARGS_4(a, b, c, d) (JSON_MatchArgs) { 4, (JSON_MatchArg[]) { __JSON_HELPER_ARG(a), __JSON_HELPER_ARG(b), __JSON_HELPER_ARG(c), __JSON_HELPER_ARG(d) }}
|
|
#define __JSON_HELPER_ARGS_5(a, b, c, d, e) (JSON_MatchArgs) { 5, (JSON_MatchArg[]) { __JSON_HELPER_ARG(a), __JSON_HELPER_ARG(b), __JSON_HELPER_ARG(c), __JSON_HELPER_ARG(d), __JSON_HELPER_ARG(e) }}
|
|
#define __JSON_HELPER_ARGS_6(a, b, c, d, e, f) (JSON_MatchArgs) { 6, (JSON_MatchArg[]) { __JSON_HELPER_ARG(a), __JSON_HELPER_ARG(b), __JSON_HELPER_ARG(c), __JSON_HELPER_ARG(d), __JSON_HELPER_ARG(e), __JSON_HELPER_ARG(f) }}
|
|
#define __JSON_HELPER_ARGS_7(a, b, c, d, e, f, g) (JSON_MatchArgs) { 7, (JSON_MatchArg[]) { __JSON_HELPER_ARG(a), __JSON_HELPER_ARG(b), __JSON_HELPER_ARG(c), __JSON_HELPER_ARG(d), __JSON_HELPER_ARG(e), __JSON_HELPER_ARG(f), __JSON_HELPER_ARG(g) }}
|
|
#define __JSON_HELPER_ARGS_8(a, b, c, d, e, f, g, h) (JSON_MatchArgs) { 8, (JSON_MatchArg[]) { __JSON_HELPER_ARG(a), __JSON_HELPER_ARG(b), __JSON_HELPER_ARG(c), __JSON_HELPER_ARG(d), __JSON_HELPER_ARG(e), __JSON_HELPER_ARG(f), __JSON_HELPER_ARG(g), __JSON_HELPER_ARG(h) }}
|
|
#define __JSON_COUNT_ARGS(...) __JSON_HELPER_DISPATCH_N(DUMMY, ##__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
|
|
|
#define JSON_MATCH_ARGS(...) __JSON_HELPER_CONCAT_1(__JSON_HELPER_ARGS_, __JSON_COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// PATTERN MATCHING
|
|
/////////////////////////////////////////////////////////
|
|
|
|
typedef enum {
|
|
JSON_MATCH_ARG_TYPE_BOOL,
|
|
JSON_MATCH_ARG_TYPE_INT,
|
|
JSON_MATCH_ARG_TYPE_FLOAT,
|
|
JSON_MATCH_ARG_TYPE_STRING,
|
|
JSON_MATCH_ARG_TYPE_ANY,
|
|
} JSON_MatchArgType;
|
|
|
|
typedef struct {
|
|
JSON_MatchArgType type;
|
|
union {
|
|
bool *bptr;
|
|
int64_t *iptr;
|
|
double *fptr;
|
|
JSON_String *sptr;
|
|
JSON **anyptr;
|
|
};
|
|
} JSON_MatchArg;
|
|
|
|
typedef struct {
|
|
int len;
|
|
JSON_MatchArg *ptr;
|
|
} JSON_MatchArgs;
|
|
|
|
// Returns:
|
|
// 0 Pattern matched
|
|
// 1 Pattern didn't match
|
|
// -1 Invalid pattern
|
|
int json_match_impl(JSON *json, JSON_Error *err, char *pattern, JSON_MatchArgs args);
|
|
|
|
#define json_match(json, err, pattern, ...) \
|
|
json_match_impl((json), (err), (pattern), JSON_MATCH_ARGS(__VA_ARGS__))
|
|
|
|
// Don't use these directly
|
|
JSON_MatchArg json_match_arg_bool (bool *x);
|
|
JSON_MatchArg json_match_arg_int (int64_t *x);
|
|
JSON_MatchArg json_match_arg_float (double *x);
|
|
JSON_MatchArg json_match_arg_string(JSON_String *x);
|
|
JSON_MatchArg json_match_arg_any (JSON **x);
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// STRING ESCAPING
|
|
/////////////////////////////////////////////////////////
|
|
|
|
JSON_String json_escape(JSON_Arena *arena, JSON_String str);
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// END
|
|
/////////////////////////////////////////////////////////
|
|
#endif // JSON_INCLUDED
|