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