]> mj.ucw.cz Git - libucw.git/blob - ucw-json/json.c
Debian: The build system is packaged as a part of libucw-dev
[libucw.git] / ucw-json / json.c
1 /*
2  *      UCW JSON Library -- Data Representation
3  *
4  *      (c) 2015 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include <ucw/lib.h>
11 #include <ucw/gary.h>
12 #include <ucw/mempool.h>
13 #include <ucw-json/json.h>
14
15 #include <limits.h>
16 #include <math.h>
17 #include <stdint.h>
18
19 static void json_init(struct json_context *js)
20 {
21   mp_save(js->pool, &js->init_state);
22   js->trivial_token = json_new_node(js, JSON_INVALID);
23 }
24
25 struct json_context *json_new(void)
26 {
27   struct mempool *mp = mp_new(4096);
28   struct json_context *js = mp_alloc_zero(mp, sizeof(*js));
29   js->pool = mp;
30   json_init(js);
31   return js;
32 }
33
34 void json_delete(struct json_context *js)
35 {
36   mp_delete(js->pool);
37 }
38
39 void json_reset(struct json_context *js)
40 {
41   struct mempool *mp = js->pool;
42   mp_restore(mp, &js->init_state);
43   bzero(js, sizeof(*js));
44   js->pool = mp;
45   json_init(js);
46 }
47
48 void json_push(struct json_context *js)
49 {
50   ASSERT(!js->next_token);
51   mp_push(js->pool);
52 }
53
54 void json_pop(struct json_context *js)
55 {
56   ASSERT(!js->next_token);
57   mp_pop(js->pool);
58 }
59
60 struct json_node *json_new_node(struct json_context *js, enum json_node_type type)
61 {
62   struct json_node *n = mp_alloc_fast(js->pool, sizeof(*n));
63   n->type = type;
64   return n;
65 }
66
67 struct json_node *json_new_number(struct json_context *js, double value)
68 {
69   ASSERT(isfinite(value));
70   struct json_node *n = json_new_node(js, JSON_NUMBER);
71   n->number = value;
72   return n;
73 }
74
75 #define JSON_NUM_TO(_type, _min, _max)                                  \
76   bool json_number_to_##_type(struct json_node *num, _type *dest)       \
77   {                                                                     \
78     if (num->type == JSON_NUMBER &&                                     \
79         num->number >= _min && num->number <= _max)                     \
80       {                                                                 \
81         *dest = num->number;                                            \
82         return 1;                                                       \
83       }                                                                 \
84     return 0;                                                           \
85   }
86
87 JSON_NUM_TO(int, INT_MIN, INT_MAX)
88 JSON_NUM_TO(uint, 0, UINT_MAX)
89 JSON_NUM_TO(s64, INT64_MIN, INT64_MAX)
90 JSON_NUM_TO(u64, 0, UINT64_MAX)
91
92 struct json_node *json_new_array(struct json_context *js)
93 {
94   struct json_node *n = json_new_node(js, JSON_ARRAY);
95   GARY_INIT_SPACE_ALLOC(n->elements, 4, mp_get_allocator(js->pool));
96   return n;
97 }
98
99 void json_array_append(struct json_node *array, struct json_node *elt)
100 {
101   ASSERT(array->type == JSON_ARRAY);
102   *GARY_PUSH(array->elements) = elt;
103 }
104
105 struct json_node *json_new_object(struct json_context *js)
106 {
107   struct json_node *n = json_new_node(js, JSON_OBJECT);
108   GARY_INIT_SPACE_ALLOC(n->pairs, 4, mp_get_allocator(js->pool));
109   return n;
110 }
111
112 void json_object_set(struct json_node *n, const char *key, struct json_node *value)
113 {
114   for (size_t i=0; i < GARY_SIZE(n->pairs); i++)
115     if (!strcmp(n->pairs[i].key, key))
116       {
117         if (value)
118           n->pairs[i].value = value;
119         else
120           {
121             n->pairs[i] = n->pairs[GARY_SIZE(n->pairs) - 1];
122             GARY_POP(n->pairs);
123           }
124         return;
125       }
126
127   if (value)
128     {
129       struct json_pair *p = GARY_PUSH(n->pairs);
130       p->key = key;
131       p->value = value;
132     }
133 }
134
135 struct json_node *json_object_get(struct json_node *n, const char *key)
136 {
137   for (size_t i=0; i < GARY_SIZE(n->pairs); i++)
138     if (!strcmp(n->pairs[i].key, key))
139       return n->pairs[i].value;
140   return NULL;
141 }