1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
4 */
5
6 #ifndef DATA_STORAGE_H__
7 #define DATA_STORAGE_H__
8
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13
14 enum data_type {
15 DATA_ARRAY,
16 DATA_HASH,
17 DATA_STRING,
18 DATA_INT,
19 DATA_NULL,
20 };
21
22 struct data_node_array {
23 enum data_type type;
24 unsigned int array_len;
25 unsigned int array_used;
26 struct data_node *array[];
27 };
28
29 struct data_hash_elem {
30 struct data_node *node;
31 char *id;
32 };
33
34 struct data_node_hash {
35 enum data_type type;
36 unsigned int elems_len;
37 unsigned int elems_used;
38 struct data_hash_elem elems[];
39 };
40
41 struct data_node_string {
42 enum data_type type;
43 char val[];
44 };
45
46 struct data_node_int {
47 enum data_type type;
48 long val;
49 };
50
51 struct data_node {
52 union {
53 enum data_type type;
54 struct data_node_hash hash;
55 struct data_node_array array;
56 struct data_node_string string;
57 struct data_node_int i;
58 };
59 };
60
data_type_name(enum data_type type)61 static inline const char* data_type_name(enum data_type type)
62 {
63 switch (type) {
64 case DATA_ARRAY:
65 return "array";
66 case DATA_HASH:
67 return "hash";
68 case DATA_STRING:
69 return "string";
70 case DATA_INT:
71 return "int";
72 case DATA_NULL:
73 return "null";
74 default:
75 return "???";
76 }
77 }
78
data_node_string(const char * string)79 static inline struct data_node *data_node_string(const char *string)
80 {
81 size_t size = sizeof(struct data_node_string) + strlen(string) + 1;
82 struct data_node *node = malloc(size);
83
84 if (!node)
85 return NULL;
86
87 node->type = DATA_STRING;
88 strcpy(node->string.val, string);
89
90 return node;
91 }
92
data_node_int(long i)93 static inline struct data_node *data_node_int(long i)
94 {
95 struct data_node *node = malloc(sizeof(struct data_node_int));
96
97 if (!node)
98 return NULL;
99
100 node->type = DATA_INT;
101 node->i.val = i;
102
103 return node;
104 }
105
data_node_null(void)106 static inline struct data_node *data_node_null(void)
107 {
108 struct data_node *node = malloc(sizeof(struct data_node));
109
110 if (!node)
111 return NULL;
112
113 node->type = DATA_NULL;
114
115 return node;
116 }
117
118 #define MAX_ELEMS 100
119
data_node_hash(void)120 static inline struct data_node *data_node_hash(void)
121 {
122 size_t size = sizeof(struct data_node_hash)
123 + MAX_ELEMS * sizeof(struct data_hash_elem);
124 struct data_node *node = malloc(size);
125
126 if (!node)
127 return NULL;
128
129 node->type = DATA_HASH;
130 node->hash.elems_len = MAX_ELEMS;
131 node->hash.elems_used = 0;
132
133 return node;
134 }
135
data_node_array(void)136 static inline struct data_node *data_node_array(void)
137 {
138 size_t size = sizeof(struct data_node_array) +
139 + MAX_ELEMS * sizeof(struct data_node*);
140 struct data_node *node = malloc(size);
141
142 if (!node)
143 return NULL;
144
145 node->type = DATA_ARRAY;
146 node->array.array_len = MAX_ELEMS;
147 node->array.array_used = 0;
148
149 return node;
150 }
151
data_node_hash_add(struct data_node * self,const char * id,struct data_node * payload)152 static inline int data_node_hash_add(struct data_node *self, const char *id, struct data_node *payload)
153 {
154 if (self->type != DATA_HASH)
155 return 1;
156
157 struct data_node_hash *hash = &self->hash;
158
159 if (hash->elems_used == hash->elems_len)
160 return 1;
161
162 struct data_hash_elem *elem = &hash->elems[hash->elems_used++];
163
164 elem->node = payload;
165 elem->id = strdup(id);
166
167 return 0;
168 }
169
data_node_free(struct data_node * self)170 static inline void data_node_free(struct data_node *self)
171 {
172 unsigned int i;
173
174 switch (self->type) {
175 case DATA_STRING:
176 case DATA_INT:
177 case DATA_NULL:
178 break;
179 case DATA_HASH:
180 for (i = 0; i < self->hash.elems_used; i++) {
181 data_node_free(self->hash.elems[i].node);
182 free(self->hash.elems[i].id);
183 }
184 break;
185 case DATA_ARRAY:
186 for (i = 0; i < self->array.array_used; i++)
187 data_node_free(self->array.array[i]);
188 break;
189 }
190
191 free(self);
192 }
193
data_node_hash_del(struct data_node * self,const char * id)194 static inline int data_node_hash_del(struct data_node *self, const char *id)
195 {
196 unsigned int i;
197 struct data_node_hash *hash = &self->hash;
198
199 for (i = 0; i < hash->elems_used; i++) {
200 if (!strcmp(hash->elems[i].id, id))
201 break;
202 }
203
204 if (i >= hash->elems_used)
205 return 0;
206
207 data_node_free(hash->elems[i].node);
208 free(hash->elems[i].id);
209
210 hash->elems[i] = hash->elems[--hash->elems_used];
211
212 return 1;
213 }
214
data_node_hash_get(struct data_node * self,const char * id)215 static struct data_node *data_node_hash_get(struct data_node *self, const char *id)
216 {
217 unsigned int i;
218 struct data_node_hash *hash = &self->hash;
219
220 for (i = 0; i < hash->elems_used; i++) {
221 if (!strcmp(hash->elems[i].id, id))
222 break;
223 }
224
225 if (i >= hash->elems_used)
226 return NULL;
227
228 return hash->elems[i].node;
229 }
230
data_node_array_add(struct data_node * self,struct data_node * payload)231 static inline int data_node_array_add(struct data_node *self, struct data_node *payload)
232 {
233 if (self->type != DATA_ARRAY)
234 return 1;
235
236 struct data_node_array *array = &self->array;
237
238 if (array->array_used == array->array_len)
239 return 1;
240
241 array->array[array->array_used++] = payload;
242
243 return 0;
244 }
245
data_node_array_len(struct data_node * self)246 static inline unsigned int data_node_array_len(struct data_node *self)
247 {
248 if (self->type != DATA_ARRAY)
249 return 0;
250
251 return self->array.array_used;
252 }
253
254
data_node_array_last(struct data_node * self)255 static inline struct data_node *data_node_array_last(struct data_node *self)
256 {
257 if (self->type != DATA_ARRAY)
258 return NULL;
259
260 unsigned int array_used = self->array.array_used;
261 if (!array_used)
262 return NULL;
263
264 return self->array.array[array_used-1];
265 }
266
data_node_array_last_rem(struct data_node * self)267 static inline void data_node_array_last_rem(struct data_node *self)
268 {
269 if (self->type != DATA_ARRAY)
270 return;
271
272 unsigned int array_used = self->array.array_used;
273 if (!array_used)
274 return;
275
276 data_node_free(self->array.array[array_used-1]);
277
278 self->array.array[array_used-1] = NULL;
279 self->array.array_used--;
280 }
281
data_print_padd(unsigned int i)282 static inline void data_print_padd(unsigned int i)
283 {
284 while (i-- > 0)
285 putchar(' ');
286 }
287
data_node_print_(struct data_node * self,unsigned int padd)288 static inline void data_node_print_(struct data_node *self, unsigned int padd)
289 {
290 unsigned int i;
291
292 switch (self->type) {
293 case DATA_INT:
294 data_print_padd(padd);
295 printf("%li\n", self->i.val);
296 break;
297 case DATA_STRING:
298 data_print_padd(padd);
299 printf("'%s'\n", self->string.val);
300 break;
301 case DATA_NULL:
302 data_print_padd(padd);
303 printf("null\n");
304 break;
305 case DATA_HASH:
306 for (i = 0; i < self->hash.elems_used; i++) {
307 data_print_padd(padd);
308 printf("%s = {\n", self->hash.elems[i].id);
309 data_node_print_(self->hash.elems[i].node, padd+1);
310 data_print_padd(padd);
311 printf("},\n");
312 }
313 break;
314 case DATA_ARRAY:
315 for (i = 0; i < self->array.array_used; i++) {
316 data_print_padd(padd);
317 printf("{\n");
318 data_node_print_(self->array.array[i], padd+1);
319 data_print_padd(padd);
320 printf("},\n");
321 }
322 break;
323 }
324 }
325
data_node_print(struct data_node * self)326 static inline void data_node_print(struct data_node *self)
327 {
328 printf("{\n");
329 data_node_print_(self, 1);
330 printf("}\n");
331 }
332
333 static inline void data_fprintf(FILE *f, unsigned int padd, const char *fmt, ...)
334 __attribute__((format (printf, 3, 4)));
335
data_fprintf(FILE * f,unsigned int padd,const char * fmt,...)336 static inline void data_fprintf(FILE *f, unsigned int padd, const char *fmt, ...)
337 {
338 va_list va;
339
340 while (padd-- > 0)
341 putc(' ', f);
342
343 va_start(va, fmt);
344 vfprintf(f, fmt, va);
345 va_end(va);
346 }
347
data_fprintf_esc(FILE * f,unsigned int padd,const char * str)348 static inline void data_fprintf_esc(FILE *f, unsigned int padd, const char *str)
349 {
350 while (padd-- > 0)
351 fputc(' ', f);
352
353 fputc('"', f);
354
355 while (*str) {
356 switch (*str) {
357 case '\\':
358 fputs("\\\\", f);
359 break;
360 case '"':
361 fputs("\\\"", f);
362 break;
363 case '\t':
364 fputs(" ", f);
365 break;
366 default:
367 /* RFC 8259 specify chars before 0x20 as invalid */
368 if (*str >= 0x20)
369 putc(*str, f);
370 else
371 fprintf(stderr, "%s:%d: WARNING: invalid character for JSON: %x\n",
372 __FILE__, __LINE__, *str);
373 break;
374 }
375 str++;
376 }
377
378 fputc('"', f);
379 }
380
data_to_json_(struct data_node * self,FILE * f,unsigned int padd,int do_padd)381 static inline void data_to_json_(struct data_node *self, FILE *f, unsigned int padd, int do_padd)
382 {
383 unsigned int i;
384
385 switch (self->type) {
386 case DATA_INT:
387 padd = do_padd ? padd : 0;
388 data_fprintf(f, padd, "%li", self->i.val);
389 break;
390 case DATA_STRING:
391 padd = do_padd ? padd : 0;
392 data_fprintf_esc(f, padd, self->string.val);
393 break;
394 case DATA_NULL:
395 padd = do_padd ? padd : 0;
396 data_fprintf(f, padd, "null");
397 break;
398 case DATA_HASH:
399 for (i = 0; i < self->hash.elems_used; i++) {
400 data_fprintf(f, padd, "\"%s\": ", self->hash.elems[i].id);
401 data_to_json_(self->hash.elems[i].node, f, padd+1, 0);
402 if (i < self->hash.elems_used - 1)
403 fprintf(f, ",\n");
404 else
405 fprintf(f, "\n");
406 }
407 break;
408 case DATA_ARRAY:
409 data_fprintf(f, do_padd ? padd : 0, "[\n");
410 for (i = 0; i < self->array.array_used; i++) {
411 data_to_json_(self->array.array[i], f, padd+1, 1);
412 if (i < self->array.array_used - 1)
413 fprintf(f, ",\n");
414 else
415 fprintf(f, "\n");
416 }
417 data_fprintf(f, padd, "]");
418 break;
419 }
420 }
421
data_to_json(struct data_node * self,FILE * f,unsigned int padd)422 static inline void data_to_json(struct data_node *self, FILE *f, unsigned int padd)
423 {
424 fprintf(f, "{\n");
425 data_to_json_(self, f, padd + 1, 1);
426 data_fprintf(f, padd, "}");
427 }
428
429 #endif /* DATA_STORAGE_H__ */
430