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