1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
37 static void inc_lines(unsigned *line, const char *s, size_t n) {
46 f = memchr(p, '\n', n);
56 static int json_parse_string(const char **p, char **ret) {
57 _cleanup_free_ char *s = NULL;
58 size_t n = 0, allocated = 0;
79 /* Check for control characters 0x00..0x1f */
80 if (*c > 0 && *c < ' ')
83 /* Check for control character 0x7f */
109 if (IN_SET(*c, '"', '\\', '/'))
121 else if (*c == 'u') {
125 aa = unhexchar(c[1]);
129 bb = unhexchar(c[2]);
133 cc = unhexchar(c[3]);
137 dd = unhexchar(c[4]);
142 x = ((uint16_t) aa << 12) |
143 ((uint16_t) bb << 8) |
144 ((uint16_t) cc << 4) |
150 if (!GREEDY_REALLOC(s, allocated, n + 4))
153 n += utf8_encode_unichar(x, s + n);
159 if (!GREEDY_REALLOC(s, allocated, n + 2))
167 len = utf8_encoded_valid_unichar(c);
171 if (!GREEDY_REALLOC(s, allocated, n + len + 1))
174 memcpy(s + n, c, len);
180 static int json_parse_number(const char **p, union json_value *ret) {
181 bool negative = false, exponent_negative = false, is_double = false;
182 double x = 0.0, y = 0.0, exponent = 0.0, shift = 1.0;
200 if (!strchr("123456789", *c) || *c == 0)
207 t = 10 * i + (*c - '0');
208 if (t < i) /* overflow */
214 x = 10.0 * x + (*c - '0');
216 } while (strchr("0123456789", *c) && *c != 0);
223 if (!strchr("0123456789", *c) || *c == 0)
227 y = 10.0 * y + (*c - '0');
228 shift = 10.0 * shift;
230 } while (strchr("0123456789", *c) && *c != 0);
233 if (*c == 'e' || *c == 'E') {
238 exponent_negative = true;
240 } else if (*c == '+')
243 if (!strchr("0123456789", *c) || *c == 0)
247 exponent = 10.0 * exponent + (*c - '0');
249 } while (strchr("0123456789", *c) && *c != 0);
258 ret->real = ((negative ? -1.0 : 1.0) * (x + (y / shift))) * exp10((exponent_negative ? -1.0 : 1.0) * exponent);
261 ret->integer = negative ? -i : i;
269 union json_value *ret_value,
283 t = PTR_TO_INT(*state);
286 if (t == STATE_NULL) {
295 b = c + strspn(c, WHITESPACE);
299 inc_lines(line, c, b - c);
308 *ret_value = JSON_VALUE_NULL;
310 *state = INT_TO_PTR(STATE_VALUE);
311 return JSON_OBJECT_OPEN;
313 } else if (*c == '}') {
315 *ret_value = JSON_VALUE_NULL;
317 *state = INT_TO_PTR(STATE_VALUE_POST);
318 return JSON_OBJECT_CLOSE;
320 } else if (*c == '[') {
322 *ret_value = JSON_VALUE_NULL;
324 *state = INT_TO_PTR(STATE_VALUE);
325 return JSON_ARRAY_OPEN;
327 } else if (*c == ']') {
329 *ret_value = JSON_VALUE_NULL;
331 *state = INT_TO_PTR(STATE_VALUE_POST);
332 return JSON_ARRAY_CLOSE;
334 } else if (*c == '"') {
335 r = json_parse_string(&c, ret_string);
339 *ret_value = JSON_VALUE_NULL;
341 *state = INT_TO_PTR(STATE_VALUE_POST);
344 } else if (strchr("-0123456789", *c)) {
345 r = json_parse_number(&c, ret_value);
351 *state = INT_TO_PTR(STATE_VALUE_POST);
354 } else if (startswith(c, "true")) {
356 ret_value->boolean = true;
358 *state = INT_TO_PTR(STATE_VALUE_POST);
361 } else if (startswith(c, "false")) {
363 ret_value->boolean = false;
365 *state = INT_TO_PTR(STATE_VALUE_POST);
368 } else if (startswith(c, "null")) {
370 *ret_value = JSON_VALUE_NULL;
372 *state = INT_TO_PTR(STATE_VALUE_POST);
378 case STATE_VALUE_POST:
382 *ret_value = JSON_VALUE_NULL;
384 *state = INT_TO_PTR(STATE_VALUE);
386 } else if (*c == ',') {
388 *ret_value = JSON_VALUE_NULL;
390 *state = INT_TO_PTR(STATE_VALUE);
392 } else if (*c == '}') {
394 *ret_value = JSON_VALUE_NULL;
396 *state = INT_TO_PTR(STATE_VALUE_POST);
397 return JSON_OBJECT_CLOSE;
398 } else if (*c == ']') {
400 *ret_value = JSON_VALUE_NULL;
402 *state = INT_TO_PTR(STATE_VALUE_POST);
403 return JSON_ARRAY_CLOSE;