• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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