• 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 };
19 
20 struct data_node_array {
21 	enum data_type type;
22 	unsigned int array_len;
23 	unsigned int array_used;
24 	struct data_node *array[];
25 };
26 
27 struct data_hash_elem {
28 	struct data_node *node;
29 	char *id;
30 };
31 
32 struct data_node_hash {
33 	enum data_type type;
34 	unsigned int elems_len;
35 	unsigned int elems_used;
36 	struct data_hash_elem elems[];
37 };
38 
39 struct data_node_string {
40 	enum data_type type;
41 	char val[];
42 };
43 
44 struct data_node {
45 	union {
46 		enum data_type type;
47 		struct data_node_hash hash;
48 		struct data_node_array array;
49 		struct data_node_string string;
50 	};
51 };
52 
data_node_string(const char * string)53 static inline struct data_node *data_node_string(const char *string)
54 {
55 	size_t size = sizeof(struct data_node_string) + strlen(string) + 1;
56 	struct data_node *node = malloc(size);
57 
58 	if (!node)
59 		return NULL;
60 
61 	node->type = DATA_STRING;
62 	strcpy(node->string.val, string);
63 
64 	return node;
65 }
66 
67 #define MAX_ELEMS 100
68 
data_node_hash(void)69 static inline struct data_node *data_node_hash(void)
70 {
71 	size_t size = sizeof(struct data_node_hash)
72 	              + MAX_ELEMS * sizeof(struct data_hash_elem);
73 	struct data_node *node = malloc(size);
74 
75 	if (!node)
76 		return NULL;
77 
78 	node->type = DATA_HASH;
79 	node->hash.elems_len = MAX_ELEMS;
80 	node->hash.elems_used = 0;
81 
82 	return node;
83 }
84 
data_node_array(void)85 static inline struct data_node *data_node_array(void)
86 {
87 	size_t size = sizeof(struct data_node_array) +
88 	              + MAX_ELEMS * sizeof(struct data_node*);
89 	struct data_node *node = malloc(size);
90 
91 	if (!node)
92 		return NULL;
93 
94 	node->type = DATA_ARRAY;
95 	node->array.array_len = MAX_ELEMS;
96 	node->array.array_used = 0;
97 
98 	return node;
99 }
100 
data_node_hash_add(struct data_node * self,const char * id,struct data_node * payload)101 static inline int data_node_hash_add(struct data_node *self, const char *id, struct data_node *payload)
102 {
103 	if (self->type != DATA_HASH)
104 		return 1;
105 
106 	struct data_node_hash *hash = &self->hash;
107 
108 	if (hash->elems_used == hash->elems_len)
109 		return 1;
110 
111 	struct data_hash_elem *elem = &hash->elems[hash->elems_used++];
112 
113 	elem->node = payload;
114 	elem->id = strdup(id);
115 
116 	return 0;
117 }
118 
data_node_free(struct data_node * self)119 static inline void data_node_free(struct data_node *self)
120 {
121 	unsigned int i;
122 
123 	switch (self->type) {
124 	case DATA_STRING:
125 	break;
126 	case DATA_HASH:
127 		for (i = 0; i < self->hash.elems_used; i++) {
128 			data_node_free(self->hash.elems[i].node);
129 			free(self->hash.elems[i].id);
130 		}
131 	break;
132 	case DATA_ARRAY:
133 		for (i = 0; i < self->array.array_used; i++)
134 			data_node_free(self->array.array[i]);
135 	break;
136 	}
137 
138 	free(self);
139 }
140 
data_node_hash_del(struct data_node * self,const char * id)141 static inline int data_node_hash_del(struct data_node *self, const char *id)
142 {
143 	unsigned int i;
144 	struct data_node_hash *hash = &self->hash;
145 
146 	for (i = 0; i < hash->elems_used; i++) {
147 		if (!strcmp(hash->elems[i].id, id))
148 			break;
149 	}
150 
151 	if (i >= hash->elems_used)
152 		return 0;
153 
154 	data_node_free(hash->elems[i].node);
155 	free(hash->elems[i].id);
156 
157 	hash->elems[i] = hash->elems[--hash->elems_used];
158 
159 	return 1;
160 }
161 
data_node_hash_get(struct data_node * self,const char * id)162 static struct data_node *data_node_hash_get(struct data_node *self, const char *id)
163 {
164 	unsigned int i;
165 	struct data_node_hash *hash = &self->hash;
166 
167 	for (i = 0; i < hash->elems_used; i++) {
168 		if (!strcmp(hash->elems[i].id, id))
169 			break;
170 	}
171 
172 	if (i >= hash->elems_used)
173 		return NULL;
174 
175 	return hash->elems[i].node;
176 }
177 
data_node_array_add(struct data_node * self,struct data_node * payload)178 static inline int data_node_array_add(struct data_node *self, struct data_node *payload)
179 {
180 	if (self->type != DATA_ARRAY)
181 		return 1;
182 
183 	struct data_node_array *array = &self->array;
184 
185 	if (array->array_used == array->array_len)
186 		return 1;
187 
188 	array->array[array->array_used++] = payload;
189 
190 	return 0;
191 }
192 
data_node_array_len(struct data_node * self)193 static inline unsigned int data_node_array_len(struct data_node *self)
194 {
195 	if (self->type != DATA_ARRAY)
196 		return 0;
197 
198 	return self->array.array_used;
199 }
200 
data_print_padd(unsigned int i)201 static inline void data_print_padd(unsigned int i)
202 {
203 	while (i-- > 0)
204 		putchar(' ');
205 }
206 
data_node_print_(struct data_node * self,unsigned int padd)207 static inline void data_node_print_(struct data_node *self, unsigned int padd)
208 {
209 	unsigned int i;
210 
211 	switch (self->type) {
212 	case DATA_STRING:
213 		data_print_padd(padd);
214 		printf("'%s'\n", self->string.val);
215 	break;
216 	case DATA_HASH:
217 		for (i = 0; i < self->hash.elems_used; i++) {
218 			data_print_padd(padd);
219 			printf("%s = {\n", self->hash.elems[i].id);
220 			data_node_print_(self->hash.elems[i].node, padd+1);
221 			data_print_padd(padd);
222 			printf("},\n");
223 		}
224 	break;
225 	case DATA_ARRAY:
226 		for (i = 0; i < self->array.array_used; i++) {
227 			data_print_padd(padd);
228 			printf("{\n");
229 			data_node_print_(self->array.array[i], padd+1);
230 			data_print_padd(padd);
231 			printf("},\n");
232 		}
233 	break;
234 	}
235 }
236 
data_node_print(struct data_node * self)237 static inline void data_node_print(struct data_node *self)
238 {
239 	printf("{\n");
240 	data_node_print_(self, 1);
241 	printf("}\n");
242 }
243 
244 static inline void data_fprintf(FILE *f, unsigned int padd, const char *fmt, ...)
245                    __attribute__((format (printf, 3, 4)));
246 
data_fprintf(FILE * f,unsigned int padd,const char * fmt,...)247 static inline void data_fprintf(FILE *f, unsigned int padd, const char *fmt, ...)
248 {
249 	va_list va;
250 
251 	while (padd-- > 0)
252 		putc(' ', f);
253 
254 	va_start(va, fmt);
255 	vfprintf(f, fmt, va);
256 	va_end(va);
257 }
258 
259 
data_fprintf_esc(FILE * f,unsigned int padd,const char * str)260 static inline void data_fprintf_esc(FILE *f, unsigned int padd, const char *str)
261 {
262 	while (padd-- > 0)
263 		fputc(' ', f);
264 
265 	fputc('"', f);
266 
267 	while (*str) {
268 		switch (*str) {
269 		case '\\':
270 			fputs("\\\\", f);
271 			break;
272 		case '"':
273 			fputs("\\\"", f);
274 			break;
275 		case '\t':
276 			fputs("        ", f);
277 			break;
278 		default:
279 			/* RFC 8259 specify  chars before 0x20 as invalid */
280 			if (*str >= 0x20)
281 				putc(*str, f);
282 			else
283 				fprintf(stderr, "%s:%d: WARNING: invalid character for JSON: %x\n",
284 						__FILE__, __LINE__, *str);
285 			break;
286 		}
287 		str++;
288 	}
289 
290 	fputc('"', f);
291 }
292 
data_to_json_(struct data_node * self,FILE * f,unsigned int padd,int do_padd)293 static inline void data_to_json_(struct data_node *self, FILE *f, unsigned int padd, int do_padd)
294 {
295 	unsigned int i;
296 
297 	switch (self->type) {
298 	case DATA_STRING:
299 		padd = do_padd ? padd : 0;
300 		data_fprintf_esc(f, padd, self->string.val);
301 	break;
302 	case DATA_HASH:
303 		for (i = 0; i < self->hash.elems_used; i++) {
304 			data_fprintf(f, padd, "\"%s\": ", self->hash.elems[i].id);
305 			data_to_json_(self->hash.elems[i].node, f, padd+1, 0);
306 			if (i < self->hash.elems_used - 1)
307 				fprintf(f, ",\n");
308 			else
309 				fprintf(f, "\n");
310 		}
311 	break;
312 	case DATA_ARRAY:
313 		data_fprintf(f, do_padd ? padd : 0, "[\n");
314 		for (i = 0; i < self->array.array_used; i++) {
315 			data_to_json_(self->array.array[i], f, padd+1, 1);
316 			if (i < self->array.array_used - 1)
317 				fprintf(f, ",\n");
318 			else
319 				fprintf(f, "\n");
320 		}
321 		data_fprintf(f, padd, "]");
322 	break;
323 	}
324 }
325 
data_to_json(struct data_node * self,FILE * f,unsigned int padd)326 static inline void data_to_json(struct data_node *self, FILE *f, unsigned int padd)
327 {
328 	fprintf(f, "{\n");
329 	data_to_json_(self, f, padd + 1, 1);
330 	data_fprintf(f, padd, "}");
331 }
332 
333 #endif /* DATA_STORAGE_H__ */
334