]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/json.h
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / shared / json.h
CommitLineData
cd0b6c53 1/* SPDX-License-Identifier: LGPL-2.1+ */
cd0b6c53
LP
2#pragma once
3
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdint.h>
7
8#include "macro.h"
9#include "string-util.h"
10#include "util.h"
11
12/*
13 In case you wonder why we have our own JSON implementation, here are a couple of reasons why this implementation has
14 benefits over various other implementatins:
15
16 - We need support for 64bit signed and unsigned integers, i.e. the full 64,5bit range of -9223372036854775808…18446744073709551615
17 - All our variants are immutable after creation
18 - Special values such as true, false, zero, null, empty strings, empty array, empty objects require zero dynamic memory
19 - Progressive parsing
20 - Our integer/real type implicitly converts, but only if that's safe and loss-lessly possible
21 - There's a "builder" for putting together objects easily in varargs function calls
22 - There's a "dispatcher" for mapping objects to C data structures
23 - Every variant optionally carries parsing location information, which simplifies debugging and parse log error generation
24 - Formatter has color, line, column support
25
26 Limitations:
27 - Doesn't allow embedded NUL in strings
28 - Can't store integers outside of the -9223372036854775808…18446744073709551615 range (it will use 'long double' for
29 values outside this range, which is lossy)
30 - Can't store negative zero (will be treated identical to positive zero, and not retained across serialization)
31 - Can't store non-integer numbers that can't be stored in "long double" losslessly
32 - Allows creation and parsing of objects with duplicate keys. The "dispatcher" will refuse them however. This means
33 we can parse and pass around such objects, but will carefully refuse them when we convert them into our own data.
34
35 (These limitations should be pretty much in line with those of other JSON implementations, in fact might be less
36 limiting in most cases even.)
37*/
38
39typedef struct JsonVariant JsonVariant;
40
41typedef enum JsonVariantType {
42 JSON_VARIANT_STRING,
43 JSON_VARIANT_INTEGER,
44 JSON_VARIANT_UNSIGNED,
45 JSON_VARIANT_REAL,
46 JSON_VARIANT_NUMBER, /* This a pseudo-type: we can never create variants of this type, but we use it as wildcard check for the above three types */
47 JSON_VARIANT_BOOLEAN,
48 JSON_VARIANT_ARRAY,
49 JSON_VARIANT_OBJECT,
50 JSON_VARIANT_NULL,
51 _JSON_VARIANT_TYPE_MAX,
52 _JSON_VARIANT_TYPE_INVALID = -1
53} JsonVariantType;
54
55int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n);
56int json_variant_new_integer(JsonVariant **ret, intmax_t i);
57int json_variant_new_unsigned(JsonVariant **ret, uintmax_t u);
58int json_variant_new_real(JsonVariant **ret, long double d);
59int json_variant_new_boolean(JsonVariant **ret, bool b);
60int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n);
61int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n);
62int json_variant_new_array_strv(JsonVariant **ret, char **l);
63int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n);
64int json_variant_new_null(JsonVariant **ret);
65
66static inline int json_variant_new_string(JsonVariant **ret, const char *s) {
67 return json_variant_new_stringn(ret, s, strlen_ptr(s));
68}
69
70JsonVariant *json_variant_ref(JsonVariant *v);
71JsonVariant *json_variant_unref(JsonVariant *v);
72void json_variant_unref_many(JsonVariant **array, size_t n);
73
74DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant *, json_variant_unref);
75
76const char *json_variant_string(JsonVariant *v);
77intmax_t json_variant_integer(JsonVariant *v);
78uintmax_t json_variant_unsigned(JsonVariant *v);
79long double json_variant_real(JsonVariant *v);
80bool json_variant_boolean(JsonVariant *v);
81
82JsonVariantType json_variant_type(JsonVariant *v);
83bool json_variant_has_type(JsonVariant *v, JsonVariantType type);
84
85static inline bool json_variant_is_string(JsonVariant *v) {
86 return json_variant_has_type(v, JSON_VARIANT_STRING);
87}
88
89static inline bool json_variant_is_integer(JsonVariant *v) {
90 return json_variant_has_type(v, JSON_VARIANT_INTEGER);
91}
92
93static inline bool json_variant_is_unsigned(JsonVariant *v) {
94 return json_variant_has_type(v, JSON_VARIANT_UNSIGNED);
95}
96
97static inline bool json_variant_is_real(JsonVariant *v) {
98 return json_variant_has_type(v, JSON_VARIANT_REAL);
99}
100
101static inline bool json_variant_is_number(JsonVariant *v) {
102 return json_variant_has_type(v, JSON_VARIANT_NUMBER);
103}
104
105static inline bool json_variant_is_boolean(JsonVariant *v) {
106 return json_variant_has_type(v, JSON_VARIANT_BOOLEAN);
107}
108
109static inline bool json_variant_is_array(JsonVariant *v) {
110 return json_variant_has_type(v, JSON_VARIANT_ARRAY);
111}
112
113static inline bool json_variant_is_object(JsonVariant *v) {
114 return json_variant_has_type(v, JSON_VARIANT_OBJECT);
115}
116
117static inline bool json_variant_is_null(JsonVariant *v) {
118 return json_variant_has_type(v, JSON_VARIANT_NULL);
119}
120
121bool json_variant_is_negative(JsonVariant *v);
122
123size_t json_variant_elements(JsonVariant *v);
124JsonVariant *json_variant_by_index(JsonVariant *v, size_t index);
125JsonVariant *json_variant_by_key(JsonVariant *v, const char *key);
126JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVariant **ret_key);
127
128bool json_variant_equal(JsonVariant *a, JsonVariant *b);
129
130struct json_variant_foreach_state {
131 JsonVariant *variant;
132 size_t idx;
133};
134
135#define JSON_VARIANT_ARRAY_FOREACH(i, v) \
136 for (struct json_variant_foreach_state _state = { (v), 0 }; \
137 _state.idx < json_variant_elements(_state.variant) && \
138 ({ i = json_variant_by_index(_state.variant, _state.idx); \
139 true; }); \
140 _state.idx++)
141
142#define JSON_VARIANT_OBJECT_FOREACH(k, e, v) \
143 for (struct json_variant_foreach_state _state = { (v), 0 }; \
144 _state.idx < json_variant_elements(_state.variant) && \
145 ({ k = json_variant_by_index(_state.variant, _state.idx); \
146 e = json_variant_by_index(_state.variant, _state.idx + 1); \
147 true; }); \
148 _state.idx += 2)
149
150int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column);
151
897f099b 152typedef enum JsonFormatFlags {
ab91733c
LP
153 JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
154 JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
155 JSON_FORMAT_COLOR = 1 << 2, /* insert ANSI color sequences */
6af022fe 156 JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insert ANSI color sequences if colors_enabled() says so */
ab91733c
LP
157 JSON_FORMAT_SOURCE = 1 << 4, /* prefix with source filename/line/column */
158 JSON_FORMAT_SSE = 1 << 5, /* prefix/suffix with W3C server-sent events */
159 JSON_FORMAT_SEQ = 1 << 6, /* prefix/suffix with RFC 7464 application/json-seq */
897f099b 160} JsonFormatFlags;
cd0b6c53 161
897f099b
LP
162int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
163void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
cd0b6c53
LP
164
165int json_parse(const char *string, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
166int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
167int json_parse_file(FILE *f, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
168
169enum {
170 _JSON_BUILD_STRING,
171 _JSON_BUILD_INTEGER,
172 _JSON_BUILD_UNSIGNED,
173 _JSON_BUILD_REAL,
174 _JSON_BUILD_BOOLEAN,
175 _JSON_BUILD_ARRAY_BEGIN,
176 _JSON_BUILD_ARRAY_END,
177 _JSON_BUILD_OBJECT_BEGIN,
178 _JSON_BUILD_OBJECT_END,
179 _JSON_BUILD_PAIR,
319a4f27 180 _JSON_BUILD_PAIR_CONDITION,
cd0b6c53
LP
181 _JSON_BUILD_NULL,
182 _JSON_BUILD_VARIANT,
183 _JSON_BUILD_LITERAL,
184 _JSON_BUILD_STRV,
185 _JSON_BUILD_MAX,
186};
187
188#define JSON_BUILD_STRING(s) _JSON_BUILD_STRING, ({ const char *_x = s; _x; })
189#define JSON_BUILD_INTEGER(i) _JSON_BUILD_INTEGER, ({ intmax_t _x = i; _x; })
190#define JSON_BUILD_UNSIGNED(u) _JSON_BUILD_UNSIGNED, ({ uintmax_t _x = u; _x; })
191#define JSON_BUILD_REAL(d) _JSON_BUILD_REAL, ({ long double _x = d; _x; })
192#define JSON_BUILD_BOOLEAN(b) _JSON_BUILD_BOOLEAN, ({ bool _x = b; _x; })
193#define JSON_BUILD_ARRAY(...) _JSON_BUILD_ARRAY_BEGIN, __VA_ARGS__, _JSON_BUILD_ARRAY_END
194#define JSON_BUILD_OBJECT(...) _JSON_BUILD_OBJECT_BEGIN, __VA_ARGS__, _JSON_BUILD_OBJECT_END
195#define JSON_BUILD_PAIR(n, ...) _JSON_BUILD_PAIR, ({ const char *_x = n; _x; }), __VA_ARGS__
319a4f27 196#define JSON_BUILD_PAIR_CONDITION(c, n, ...) _JSON_BUILD_PAIR_CONDITION, ({ bool _x = c; _x; }), ({ const char *_x = n; _x; }), __VA_ARGS__
cd0b6c53
LP
197#define JSON_BUILD_NULL _JSON_BUILD_NULL
198#define JSON_BUILD_VARIANT(v) _JSON_BUILD_VARIANT, ({ JsonVariant *_x = v; _x; })
199#define JSON_BUILD_LITERAL(l) _JSON_BUILD_LITERAL, ({ const char *_x = l; _x; })
200#define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, ({ char **_x = l; _x; })
201
202int json_build(JsonVariant **ret, ...);
203int json_buildv(JsonVariant **ret, va_list ap);
204
205/* A bitmask of flags used by the dispatch logic. Note that this is a combined bit mask, that is generated from the bit
206 * mask originally passed into json_dispatch(), the individual bitmask associated with the static JsonDispatch callout
207 * entry, as well the bitmask specified for json_log() calls */
208typedef enum JsonDispatchFlags {
209 /* The following three may be set in JsonDispatch's .flags field or the json_dispatch() flags parameter */
210 JSON_PERMISSIVE = 1 << 0, /* Shall parsing errors be considered fatal for this property? */
211 JSON_MANDATORY = 1 << 1, /* Should existance of this property be mandatory? */
212 JSON_LOG = 1 << 2, /* Should the parser log about errors? */
213
214 /* The following two may be passed into log_json() in addition to the three above */
215 JSON_DEBUG = 1 << 3, /* Indicates that this log message is a debug message */
216 JSON_WARNING = 1 << 4, /* Indicates that this log message is a warning message */
217} JsonDispatchFlags;
218
219typedef int (*JsonDispatchCallback)(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
220
221typedef struct JsonDispatch {
222 const char *name;
223 JsonVariantType type;
224 JsonDispatchCallback callback;
225 size_t offset;
226 JsonDispatchFlags flags;
227} JsonDispatch;
228
229int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata);
230
231int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
232int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
233int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
234int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
235int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
236int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
237int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
238int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
239int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
240
241assert_cc(sizeof(uintmax_t) == sizeof(uint64_t))
242#define json_dispatch_uint64 json_dispatch_unsigned
243
244assert_cc(sizeof(intmax_t) == sizeof(int64_t))
245#define json_dispatch_int64 json_dispatch_integer
246
247static inline int json_dispatch_level(JsonDispatchFlags flags) {
248
249 /* Did the user request no logging? If so, then never log higher than LOG_DEBUG. Also, if this is marked as
250 * debug message, then also log at debug level. */
251
252 if (!(flags & JSON_LOG) ||
253 (flags & JSON_DEBUG))
254 return LOG_DEBUG;
255
256 /* Are we invoked in permissive mode, or is this explicitly marked as warning message? Then this should be
257 * printed at LOG_WARNING */
258 if (flags & (JSON_PERMISSIVE|JSON_WARNING))
259 return LOG_WARNING;
260
261 /* Otherwise it's an error. */
262 return LOG_ERR;
263}
264
265int json_log_internal(JsonVariant *variant, int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(7, 8);
266
267#define json_log(variant, flags, error, ...) \
268 ({ \
269 int _level = json_dispatch_level(flags), _e = (error); \
270 (log_get_max_level() >= LOG_PRI(_level)) \
271 ? json_log_internal(variant, _level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
272 : -abs(_e); \
273 })
274
d520d519
LP
275#define JSON_VARIANT_STRING_CONST(x) _JSON_VARIANT_STRING_CONST(UNIQ, (x))
276
90b365ce 277#define _JSON_VARIANT_STRING_CONST(xq, x) \
d520d519 278 ({ \
90b365ce 279 _align_(2) static const char UNIQ_T(json_string_const, xq)[] = (x); \
d520d519
LP
280 assert((((uintptr_t) UNIQ_T(json_string_const, xq)) & 1) == 0); \
281 (JsonVariant*) ((uintptr_t) UNIQ_T(json_string_const, xq) + 1); \
282 })
283
cd0b6c53
LP
284const char *json_variant_type_to_string(JsonVariantType t);
285JsonVariantType json_variant_type_from_string(const char *s);