1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif /* ifdef HAVE_CONFIG_H */
4
5 #include <string.h>
6 #include <stdio.h>
7
8 #include <Eina.h>
9
10 #include "Eet.h"
11 #include "Eet_private.h"
12
13 static Eina_Mempool *_eet_node_mp = NULL;
14
15 Eet_Node *
eet_node_new(void)16 eet_node_new(void)
17 {
18 Eet_Node *result;
19
20 result = eina_mempool_malloc(_eet_node_mp, sizeof (Eet_Node));
21 if (!result)
22 return NULL;
23
24 memset(result, 0, sizeof (Eet_Node));
25 return result;
26 }
27
28 void
eet_node_free(Eet_Node * node)29 eet_node_free(Eet_Node *node)
30 {
31 eina_mempool_free(_eet_node_mp, node);
32 }
33
34 static Eet_Node *
_eet_node_new(const char * name,int type)35 _eet_node_new(const char *name,
36 int type)
37 {
38 Eet_Node *n;
39
40 n = eet_node_new();
41 if (!n)
42 return NULL;
43
44 n->type = type;
45 n->name = eina_stringshare_add(name);
46
47 return n;
48 }
49
50 static void
_eet_node_append(Eet_Node * n,Eina_List * nodes)51 _eet_node_append(Eet_Node *n,
52 Eina_List *nodes)
53 {
54 Eet_Node *value;
55 Eina_List *l;
56
57 EINA_LIST_REVERSE_FOREACH(nodes, l, value)
58 {
59 value->next = n->values;
60 n->values = value;
61 }
62 }
63
64 #define EET_NODE_NEW(Eet_type, Name, Value, Type) \
65 EAPI Eet_Node * \
66 eet_node_ ## Name ## _new(const char *name, Type Value) \
67 { \
68 Eet_Node *n; \
69 \
70 n = _eet_node_new(name, Eet_type); \
71 if (!n) { return NULL; } \
72 \
73 n->data.value.Value = Value; \
74 \
75 return n; \
76 }
77
78 #define EET_NODE_STR_NEW(Eet_type, Name, Value, Type) \
79 EAPI Eet_Node * \
80 eet_node_ ## Name ## _new(const char *name, Type Value) \
81 { \
82 Eet_Node *n; \
83 \
84 n = _eet_node_new(name, Eet_type); \
85 if (!n) { return NULL; } \
86 \
87 n->data.value.Value = eina_stringshare_add(Value); \
88 \
89 return n; \
90 }
91
EET_NODE_NEW(EET_T_CHAR,char,c,char)92 EET_NODE_NEW(EET_T_CHAR, char, c, char)
93 EET_NODE_NEW(EET_T_SHORT, short, s, short)
94 EET_NODE_NEW(EET_T_INT, int, i, int)
95 EET_NODE_NEW(EET_T_LONG_LONG, long_long, l, long long)
96 EET_NODE_NEW(EET_T_FLOAT, float, f, float)
97 EET_NODE_NEW(EET_T_DOUBLE, double, d, double)
98 EET_NODE_NEW(EET_T_UCHAR, unsigned_char, uc, unsigned char)
99 EET_NODE_NEW(EET_T_USHORT, unsigned_short, us, unsigned short)
100 EET_NODE_NEW(EET_T_UINT, unsigned_int, ui, unsigned int)
101 EET_NODE_NEW(EET_T_ULONG_LONG, unsigned_long_long, ul, unsigned long long)
102 EET_NODE_STR_NEW(EET_T_STRING, string, str, const char *)
103 EET_NODE_STR_NEW(EET_T_INLINED_STRING, inlined_string, str, const char *)
104
105 Eet_Node *
106 eet_node_null_new(const char *name)
107 {
108 Eet_Node *n;
109
110 n = _eet_node_new(name, EET_T_NULL);
111 if (!n)
112 return NULL;
113
114 n->data.value.str = NULL;
115
116 return n;
117 }
118
119 Eet_Node *
eet_node_list_new(const char * name,Eina_List * nodes)120 eet_node_list_new(const char *name,
121 Eina_List *nodes)
122 {
123 Eet_Node *n;
124
125 n = _eet_node_new(name, EET_G_LIST);
126 if (!n)
127 return NULL;
128
129 _eet_node_append(n, nodes);
130
131 return n;
132 }
133
134 Eet_Node *
eet_node_array_new(const char * name,int count,Eina_List * nodes)135 eet_node_array_new(const char *name,
136 int count,
137 Eina_List *nodes)
138 {
139 Eet_Node *n;
140
141 n = _eet_node_new(name, EET_G_ARRAY);
142 if (!n)
143 return NULL;
144
145 n->count = count;
146
147 _eet_node_append(n, nodes);
148
149 return n;
150 }
151
152 Eet_Node *
eet_node_var_array_new(const char * name,Eina_List * nodes)153 eet_node_var_array_new(const char *name,
154 Eina_List *nodes)
155 {
156 Eet_Node *n;
157
158 n = _eet_node_new(name, EET_G_VAR_ARRAY);
159 if (!n)
160 return NULL;
161
162 n->count = eina_list_count(nodes);
163
164 _eet_node_append(n, nodes);
165
166 return n;
167 }
168
169 Eet_Node *
eet_node_hash_new(const char * name,const char * key,Eet_Node * node)170 eet_node_hash_new(const char *name,
171 const char *key,
172 Eet_Node *node)
173 {
174 Eina_List *nodes;
175 Eet_Node *n;
176
177 if (!node)
178 return NULL;
179
180 n = _eet_node_new(name, EET_G_HASH);
181 if (!n)
182 return NULL;
183
184 n->key = eina_stringshare_add(key);
185 nodes = eina_list_append(NULL, node);
186
187 _eet_node_append(n, nodes);
188
189 return n;
190 }
191
192 Eet_Node *
eet_node_struct_new(const char * name,Eina_List * nodes)193 eet_node_struct_new(const char *name,
194 Eina_List *nodes)
195 {
196 Eet_Node *n;
197
198 n = _eet_node_new(name, EET_G_UNKNOWN);
199 if (!n)
200 return NULL;
201
202 _eet_node_append(n, nodes);
203
204 return n;
205 }
206
207 Eet_Node *
eet_node_struct_child_new(const char * parent,Eet_Node * child)208 eet_node_struct_child_new(const char *parent,
209 Eet_Node *child)
210 {
211 Eet_Node *n;
212
213 if (!child) return NULL;
214
215 if (child->type != EET_G_UNKNOWN)
216 return child;
217
218 n = _eet_node_new(parent, EET_G_UNKNOWN);
219 if (!n)
220 return NULL;
221
222 _eet_node_append(n, eina_list_prepend(NULL, child));
223
224 return n;
225 }
226
227 Eet_Node *
eet_node_children_get(Eet_Node * node)228 eet_node_children_get(Eet_Node *node)
229 {
230 if (!node) return NULL;
231 return node->values;
232 }
233
234 Eet_Node *
eet_node_next_get(Eet_Node * node)235 eet_node_next_get(Eet_Node *node)
236 {
237 if (!node) return NULL;
238 return node->next;
239 }
240
241 Eet_Node *
eet_node_parent_get(Eet_Node * node)242 eet_node_parent_get(Eet_Node *node)
243 {
244 if (!node) return NULL;
245 return node->parent;
246 }
247
248 void
eet_node_list_append(Eet_Node * parent,const char * name,Eet_Node * child)249 eet_node_list_append(Eet_Node *parent,
250 const char *name,
251 Eet_Node *child)
252 {
253 const char *tmp;
254 Eet_Node *nn;
255
256 if ((!parent) || (!child)) return;
257 tmp = eina_stringshare_add(name);
258
259 for (nn = parent->values; nn; nn = nn->next)
260 if (nn->name == tmp && nn->type == EET_G_LIST)
261 {
262 Eet_Node *n;
263
264 if (!nn->values)
265 nn->values = child;
266 else
267 {
268 for (n = nn->values; n->next; n = n->next)
269 ;
270 n->next = child;
271 }
272
273 child->next = NULL;
274 child->parent = parent;
275
276 eina_stringshare_del(tmp);
277
278 return;
279 }
280
281 /* No list found, so create it. */
282 nn = eet_node_list_new(tmp, eina_list_append(NULL, child));
283
284 /* And add it to the parent. */
285 nn->next = parent->values;
286 parent->values = nn;
287 child->parent = parent;
288
289 eina_stringshare_del(tmp);
290 }
291
292 void
eet_node_struct_append(Eet_Node * parent,const char * name,Eet_Node * child)293 eet_node_struct_append(Eet_Node *parent,
294 const char *name,
295 Eet_Node *child)
296 {
297 const char *tmp;
298 Eet_Node *prev;
299 Eet_Node *nn;
300
301 if ((!parent) || (!child)) return;
302 if (parent->type != EET_G_UNKNOWN)
303 {
304 ERR("[%s] is not a structure. Will not insert [%s] in it",
305 parent->name,
306 name);
307 eet_node_del(child);
308 return;
309 }
310
311 tmp = eina_stringshare_add(name);
312
313 for (prev = NULL, nn = parent->values; nn; prev = nn, nn = nn->next)
314 if (nn->name == tmp && nn->type == child->type)
315 {
316 if (prev)
317 prev->next = nn->next;
318 else
319 parent->values = nn->next;
320
321 nn->next = NULL;
322 eet_node_del(nn);
323
324 break;
325 }
326
327 if (prev)
328 {
329 prev->next = child;
330 child->next = NULL;
331 }
332 else
333 {
334 child->next = NULL;
335 parent->values = child;
336 }
337 child->parent = parent;
338
339 eina_stringshare_del(tmp);
340 }
341
342 void
eet_node_hash_add(Eet_Node * parent,const char * name,const char * key,Eet_Node * child)343 eet_node_hash_add(Eet_Node *parent,
344 const char *name,
345 const char *key,
346 Eet_Node *child)
347 {
348 Eet_Node *nn;
349
350 if ((!parent) || (!child)) return;
351
352 /* No list found, so create it. */
353 nn = eet_node_hash_new(name, key, child);
354
355 /* And add it to the parent. */
356 nn->next = parent->values;
357 parent->values = nn;
358 child->parent = parent;
359 }
360
361 int
eet_node_type_get(Eet_Node * node)362 eet_node_type_get(Eet_Node *node)
363 {
364 if (!node) return EET_T_UNKNOW;
365 return node->type;
366 }
367
368 Eet_Node_Data *
eet_node_value_get(Eet_Node * node)369 eet_node_value_get(Eet_Node *node)
370 {
371 if (!node) return NULL;
372 return &node->data;
373 }
374
375 const char *
eet_node_name_get(Eet_Node * node)376 eet_node_name_get(Eet_Node *node)
377 {
378 if (!node) return NULL;
379 return node->name;
380 }
381
382 void
eet_node_del(Eet_Node * n)383 eet_node_del(Eet_Node *n)
384 {
385 Eet_Node *nn;
386 Eet_Node *tmp;
387
388 if (!n)
389 return;
390
391 switch (n->type)
392 {
393 case EET_G_HASH:
394 eina_stringshare_del(n->key);
395 /* No break here as we want it to fall through and free the resources */
396 EINA_FALLTHROUGH;
397
398 case EET_G_UNKNOWN:
399 case EET_G_VAR_ARRAY:
400 case EET_G_ARRAY:
401 case EET_G_LIST:
402 for (nn = n->values; nn; )
403 {
404 tmp = nn;
405 nn = nn->next;
406 eet_node_del(tmp);
407 }
408 break;
409
410 case EET_T_STRING:
411 case EET_T_INLINED_STRING:
412 eina_stringshare_del(n->data.value.str);
413 break;
414
415 case EET_T_CHAR:
416 case EET_T_SHORT:
417 case EET_T_INT:
418 case EET_T_LONG_LONG:
419 case EET_T_FLOAT:
420 case EET_T_DOUBLE:
421 case EET_T_UCHAR:
422 case EET_T_USHORT:
423 case EET_T_UINT:
424 break;
425 }
426
427 eina_stringshare_del(n->name);
428 eet_node_free(n);
429 }
430
431 static const char *eet_node_dump_g_name[6] = {
432 "struct",
433 "array",
434 "var_array",
435 "list",
436 "hash",
437 "???"
438 };
439
440 static const char *eet_node_dump_t_name[14][2] = {
441 { "???: ", "???" },
442 { "char: ", "%hhi" },
443 { "short: ", "%hi" },
444 { "int: ", "%i" },
445 { "long_long: ", "%lli" },
446 { "float: ", "%1.25f" },
447 { "double: ", "%1.25f" },
448 { "uchar: ", "%hhu" },
449 { "ushort: ", "%i" },
450 { "uint: ", "%u" },
451 { "ulong_long: ", "%llu" },
452 { "null", "" }
453 };
454
455 static void
eet_node_dump_level(int level,Eet_Dump_Callback dumpfunc,void * dumpdata)456 eet_node_dump_level(int level,
457 Eet_Dump_Callback dumpfunc,
458 void *dumpdata)
459 {
460 int i;
461
462 for (i = 0; i < level; i++) dumpfunc(dumpdata, " ");
463 }
464
465 static char *
eet_node_string_escape(const char * str)466 eet_node_string_escape(const char *str)
467 {
468 char *s, *sp;
469 const char *strp;
470 int sz = 0;
471
472 for (strp = str; *strp; strp++)
473 {
474 if (*strp == '\"')
475 sz += 2;
476 else if (*strp == '\\')
477 sz += 2;
478 else if (*strp == '\n')
479 sz += 2;
480 else
481 sz += 1;
482 }
483 s = malloc(sz + 1);
484 if (!s)
485 return NULL;
486
487 for (strp = str, sp = s; *strp; strp++, sp++)
488 {
489 if (*strp == '\"'
490 || *strp == '\\'
491 || *strp == '\n')
492 {
493 *sp = '\\';
494 sp++;
495 }
496
497 if (*strp == '\n')
498 *sp = 'n';
499 else
500 *sp = *strp;
501 }
502 *sp = 0;
503 return s;
504 }
505
506 static void
eet_node_dump_string_escape(void * dumpdata,Eet_Dump_Callback dumpfunc,const char * str)507 eet_node_dump_string_escape(void *dumpdata,
508 Eet_Dump_Callback dumpfunc,
509 const char *str)
510 {
511 char *s;
512
513 s = eet_node_string_escape(str);
514 if (!s)
515 return;
516
517 dumpfunc(dumpdata, s);
518 free(s);
519 }
520
521 static void
eet_node_dump_simple_type(Eet_Node * n,int level,Eet_Dump_Callback dumpfunc,void * dumpdata)522 eet_node_dump_simple_type(Eet_Node *n,
523 int level,
524 Eet_Dump_Callback dumpfunc,
525 void *dumpdata)
526 {
527 const char *type_name = NULL;
528 char tbuf[256];
529
530 eet_node_dump_level(level, dumpfunc, dumpdata);
531 dumpfunc(dumpdata, "value \"");
532 eet_node_dump_string_escape(dumpdata, dumpfunc, n->name);
533 dumpfunc(dumpdata, "\" ");
534
535 #ifdef EET_T_TYPE
536 # undef EET_T_TYPE
537 #endif /* ifdef EET_T_TYPE */
538
539 #define EET_T_TYPE(Eet_Type, Type) \
540 case Eet_Type: \
541 { \
542 dumpfunc(dumpdata, eet_node_dump_t_name[Eet_Type][0]); \
543 snprintf(tbuf, \
544 sizeof (tbuf), \
545 eet_node_dump_t_name[Eet_Type][1], \
546 n->data.value.Type); \
547 dumpfunc(dumpdata, tbuf); \
548 break; \
549 }
550
551 switch (n->type)
552 {
553 EET_T_TYPE(EET_T_CHAR, c);
554 EET_T_TYPE(EET_T_SHORT, s);
555 EET_T_TYPE(EET_T_INT, i);
556 EET_T_TYPE(EET_T_LONG_LONG, l);
557 EET_T_TYPE(EET_T_FLOAT, f);
558 EET_T_TYPE(EET_T_DOUBLE, d);
559 EET_T_TYPE(EET_T_UCHAR, uc);
560 EET_T_TYPE(EET_T_USHORT, us);
561 EET_T_TYPE(EET_T_UINT, ui);
562 EET_T_TYPE(EET_T_ULONG_LONG, ul);
563
564 case EET_T_INLINED_STRING:
565 type_name = "inlined: \"";
566 /* inlined string are just like a string, but not inside the general
567 * dictionnary. No need to duplicate code. */
568 EINA_FALLTHROUGH;
569
570 case EET_T_STRING:
571 if (!type_name)
572 type_name = "string: \"";
573
574 dumpfunc(dumpdata, type_name);
575 eet_node_dump_string_escape(dumpdata, dumpfunc, n->data.value.str);
576 dumpfunc(dumpdata, "\"");
577 break;
578
579 case EET_T_NULL:
580 dumpfunc(dumpdata, "null");
581 break;
582
583 default:
584 dumpfunc(dumpdata, "???: ???");
585 break;
586 }
587
588 dumpfunc(dumpdata, ";\n");
589 }
590
591 static void
eet_node_dump_group_start(int level,Eet_Dump_Callback dumpfunc,void * dumpdata,int group_type,const char * name)592 eet_node_dump_group_start(int level,
593 Eet_Dump_Callback dumpfunc,
594 void *dumpdata,
595 int group_type,
596 const char *name)
597 {
598 int chnk_type;
599
600 chnk_type = (group_type >= EET_G_UNKNOWN && group_type <= EET_G_HASH) ?
601 group_type : EET_G_UNKNOWN;
602
603 eet_node_dump_level(level, dumpfunc, dumpdata);
604 dumpfunc(dumpdata, "group \"");
605 eet_node_dump_string_escape(dumpdata, dumpfunc, name);
606 dumpfunc(dumpdata, "\" ");
607
608 dumpfunc(dumpdata, eet_node_dump_g_name[chnk_type - EET_G_UNKNOWN]);
609 dumpfunc(dumpdata, " {\n");
610 }
611
612 static void
eet_node_dump_group_end(int level,Eet_Dump_Callback dumpfunc,void * dumpdata)613 eet_node_dump_group_end(int level,
614 Eet_Dump_Callback dumpfunc,
615 void *dumpdata)
616 {
617 eet_node_dump_level(level, dumpfunc, dumpdata);
618 dumpfunc(dumpdata, "}\n");
619 }
620
621 void
eet_node_dump(Eet_Node * n,int dumplevel,Eet_Dump_Callback dumpfunc,void * dumpdata)622 eet_node_dump(Eet_Node *n,
623 int dumplevel,
624 Eet_Dump_Callback dumpfunc,
625 void *dumpdata)
626 {
627 Eet_Node *it;
628
629 if (!n)
630 return;
631
632 switch (n->type)
633 {
634 case EET_G_VAR_ARRAY:
635 case EET_G_ARRAY:
636 case EET_G_UNKNOWN:
637 case EET_G_HASH:
638 case EET_G_LIST:
639 eet_node_dump_group_start(dumplevel,
640 dumpfunc,
641 dumpdata,
642 n->type,
643 n->name);
644
645 if (n->type == EET_G_VAR_ARRAY
646 || n->type == EET_G_ARRAY)
647 {
648 char tbuf[256];
649
650 eet_node_dump_level(dumplevel, dumpfunc, dumpdata);
651 dumpfunc(dumpdata, " count ");
652 eina_convert_itoa(n->count, tbuf);
653 dumpfunc(dumpdata, tbuf);
654 dumpfunc(dumpdata, ";\n");
655 }
656 else if (n->type == EET_G_HASH)
657 {
658 eet_node_dump_level(dumplevel, dumpfunc, dumpdata);
659 dumpfunc(dumpdata, " key \"");
660 eet_node_dump_string_escape(dumpdata, dumpfunc, n->key);
661 dumpfunc(dumpdata, "\";\n");
662 }
663
664 for (it = n->values; it; it = it->next)
665 eet_node_dump(it, dumplevel + 2, dumpfunc, dumpdata);
666
667 eet_node_dump_group_end(dumplevel, dumpfunc, dumpdata);
668 break;
669
670 case EET_T_STRING:
671 case EET_T_INLINED_STRING:
672 case EET_T_CHAR:
673 case EET_T_SHORT:
674 case EET_T_INT:
675 case EET_T_LONG_LONG:
676 case EET_T_FLOAT:
677 case EET_T_DOUBLE:
678 case EET_T_UCHAR:
679 case EET_T_USHORT:
680 case EET_T_UINT:
681 case EET_T_ULONG_LONG:
682 eet_node_dump_simple_type(n, dumplevel, dumpfunc, dumpdata);
683 break;
684 }
685 }
686
687 void *
eet_node_walk(void * parent,const char * name,Eet_Node * root,Eet_Node_Walk * cb,void * user_data)688 eet_node_walk(void *parent,
689 const char *name,
690 Eet_Node *root,
691 Eet_Node_Walk *cb,
692 void *user_data)
693 {
694 Eet_Node *it;
695 void *me = NULL;
696 int i;
697
698 if (!root)
699 {
700 if (parent)
701 cb->struct_add(parent, name, NULL, user_data);
702
703 return NULL;
704 }
705
706 switch (root->type)
707 {
708 case EET_G_UNKNOWN:
709 me = cb->struct_alloc(root->name, user_data);
710
711 for (it = root->values; it; it = it->next)
712 eet_node_walk(me, it->name, it, cb, user_data);
713
714 break;
715
716 case EET_G_VAR_ARRAY:
717 case EET_G_ARRAY:
718 me = cb->array(root->type == EET_G_VAR_ARRAY ? EINA_TRUE : EINA_FALSE,
719 root->name, root->count, user_data);
720
721 for (i = 0, it = root->values; it; it = it->next)
722 cb->insert(me, i++, eet_node_walk(NULL,
723 NULL,
724 it,
725 cb,
726 user_data), user_data);
727
728 break;
729
730 case EET_G_LIST:
731 me = cb->list(root->name, user_data);
732
733 for (it = root->values; it; it = it->next)
734 cb->append(me, eet_node_walk(NULL,
735 NULL,
736 it,
737 cb,
738 user_data), user_data);
739
740 break;
741
742 case EET_G_HASH:
743 if (!parent)
744 return NULL;
745
746 return cb->hash(parent, root->name, root->key,
747 eet_node_walk(NULL,
748 NULL,
749 root->values,
750 cb,
751 user_data), user_data);
752
753 case EET_T_STRING:
754 case EET_T_INLINED_STRING:
755 case EET_T_CHAR:
756 case EET_T_SHORT:
757 case EET_T_INT:
758 case EET_T_LONG_LONG:
759 case EET_T_FLOAT:
760 case EET_T_DOUBLE:
761 case EET_T_UCHAR:
762 case EET_T_USHORT:
763 case EET_T_UINT:
764 case EET_T_ULONG_LONG:
765 me = cb->simple(root->type, &root->data, user_data);
766 break;
767 }
768
769 if (parent)
770 cb->struct_add(parent, name, me, user_data);
771
772 return me;
773 }
774
775 int
eet_node_init(void)776 eet_node_init(void)
777 {
778 const char *choice;
779 const char *tmp;
780
781 #ifdef EINA_DEFAULT_MEMPOOL
782 choice = "pass_through";
783 #else
784 choice = "chained_mempool";
785 #endif
786 tmp = getenv("EINA_MEMPOOL");
787 if (tmp && tmp[0])
788 choice = tmp;
789
790 _eet_node_mp =
791 eina_mempool_add(choice, "eet-node-alloc", NULL, sizeof(Eet_Node), 32);
792
793 return _eet_node_mp ? 1 : 0;
794 }
795
796 void
eet_node_shutdown(void)797 eet_node_shutdown(void)
798 {
799 eina_mempool_del(_eet_node_mp);
800 _eet_node_mp = NULL;
801 }
802
803