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