Imported Upstream version 1.7.7
[platform/upstream/edje.git] / src / lib / edje_match.c
1 #include "edje_private.h"
2
3 /* States manipulations. */
4
5 typedef struct _Edje_State Edje_State;
6 struct _Edje_State
7 {
8    size_t idx;
9    size_t pos;
10 };
11
12 struct _Edje_States
13 {
14    size_t      size;
15    Edje_State *states;
16    Eina_Bool  *has;
17 };
18
19 static void
20 _edje_match_states_free(Edje_States *states,
21                         size_t states_size)
22 {
23    (void)states_size;
24    free(states);
25 }
26
27 #define ALIGN(Size)               \
28   {                               \
29      Size--;                      \
30      Size |= sizeof (void *) - 1; \
31      Size++;                      \
32   };
33
34 static int
35 _edje_match_states_alloc(Edje_Patterns *ppat, int n)
36 {
37    Edje_States *l;
38
39    const size_t patterns_size = ppat->patterns_size;
40    const size_t patterns_max_length = ppat->max_length;
41
42    const size_t array_len = (patterns_max_length + 1) * patterns_size;
43
44    size_t states_size;
45    size_t has_size;
46    size_t states_has_size;
47    size_t struct_size;
48
49    unsigned char *states;
50    unsigned char *has;
51
52    int i;
53
54    states_size = sizeof (*l->states) * array_len;
55    ALIGN(states_size);
56
57    has_size = sizeof (*l->has) * array_len;
58    ALIGN(has_size);
59
60    states_has_size = states_size + has_size;
61
62    struct_size = sizeof (*l);
63    ALIGN(struct_size);
64    struct_size += states_has_size;
65
66    l = malloc(n * struct_size);
67    if (!l) return 0;
68
69    ppat->states = l;
70    ppat->states->size = 0;
71
72    states = (unsigned char *)(l + n);
73    has = states + states_size;
74
75    for (i = 0; i < n; ++i)
76      {
77         l[i].states = (Edje_State *)states;
78         l[i].has = (Eina_Bool *)has;
79         l[i].size = 0;
80
81         memset(l[i].has, 0, has_size);
82
83         states += states_has_size;
84         has += states_has_size;
85      }
86
87    return 1;
88 }
89
90 static void
91 _edje_match_states_insert(Edje_States *list,
92                           size_t patterns_max_length,
93                           size_t idx,
94                           size_t pos)
95 {
96    size_t i;
97
98    i = (idx * (patterns_max_length + 1)) + pos;
99
100    if (i < list->size)
101      {
102         if (list->has[i]) return;
103      }
104    list->has[i] = 1;
105
106    i = list->size;
107    list->states[i].idx = idx;
108    list->states[i].pos = pos;
109    list->has[i] = 0;
110    list->size++;
111 }
112
113 static void
114 _edje_match_states_clear(Edje_States *list,
115                          __UNUSED__ size_t patterns_size,
116                          __UNUSED__ size_t patterns_max_length)
117 {
118    list->size = 0;
119 }
120
121 /* Token manipulation. */
122
123 enum status
124 {
125    patterns_not_found           = 0,
126    patterns_found               = 1,
127    patterns_syntax_error        = 2
128 };
129
130 static size_t
131 _edje_match_patterns_exec_class_token(enum status *status,
132                                       const char *cl_tok,
133                                       char c)
134 {
135    if (!*cl_tok)
136      {
137         *status = patterns_syntax_error;
138         return 0;
139      }
140    else if (cl_tok[1] == '-' && cl_tok[2] != ']')
141      {
142         if (*cl_tok <= c && c <= cl_tok[2])
143           *status = patterns_found;
144         return 3;
145      }
146    else
147      {
148         if (c == *cl_tok)
149           *status = patterns_found;
150         return 1;
151      }
152 }
153
154 static Edje_Match_Error
155 _edje_match_patterns_exec_class_complement(const char *cl_tok, size_t *ret)
156 {
157    switch (*cl_tok)
158      {
159       case 0:
160         return EDJE_MATCH_SYNTAX_ERROR;
161
162       case '!':
163         *ret = 1;
164         return EDJE_MATCH_OK;
165
166       default:
167         *ret = 0;
168         return EDJE_MATCH_OK;
169      }
170 }
171
172 static Edje_Match_Error
173 _edje_match_patterns_exec_class(const char *cl,
174                                 char c,
175                                 size_t *ret)
176 {
177    enum status status = patterns_not_found;
178    int pos = 1;
179    size_t neg;
180
181    if (_edje_match_patterns_exec_class_complement(cl + 1, &neg) != EDJE_MATCH_OK)
182      return EDJE_MATCH_SYNTAX_ERROR;
183
184    pos += neg;
185
186    do
187      {
188         pos += _edje_match_patterns_exec_class_token(&status, cl + pos, c);
189      }
190    while (cl[pos] && cl[pos] != ']');
191
192    if (status == patterns_syntax_error || !cl[pos])
193      return EDJE_MATCH_SYNTAX_ERROR;
194
195    if (status == patterns_found)
196      *ret = neg ? 0 : pos + 1;
197    else
198      *ret = neg ? pos + 1 : 0;
199
200    return EDJE_MATCH_OK;
201 }
202
203 static Edje_Match_Error
204 _edje_match_patterns_exec_token(const char *tok,
205                                 char c,
206                                 size_t *ret)
207 {
208    switch (*tok)
209      {
210       case '\\':
211         if (tok[1])
212           {
213              *ret = tok[1] == c ? 2 : 0;
214              return EDJE_MATCH_OK;
215           }
216         return EDJE_MATCH_SYNTAX_ERROR;
217
218       case '?':
219         *ret = 1;
220         return EDJE_MATCH_OK;
221
222       case '[':
223         return _edje_match_patterns_exec_class(tok, c, ret);
224
225       default:
226         *ret = *tok == c ? 1 : 0;
227         return EDJE_MATCH_OK;
228      }
229 }
230
231 static void
232 _edje_match_patterns_exec_init_states(Edje_States *states,
233                                       size_t patterns_size,
234                                       size_t patterns_max_length)
235 {
236    size_t i;
237
238    states->size = patterns_size;
239
240    for (i = 0; i < patterns_size; ++i)
241      {
242         states->states[i].idx = i;
243         states->states[i].pos = 0;
244         states->has[i * (patterns_max_length + 1)] = 1;
245      }
246 }
247
248 /* Exported function. */
249
250 #define EDJE_MATCH_INIT_LIST(Func, Type, Source, Show)              \
251   Edje_Patterns *                                                   \
252   Func(const Eina_List *lst)                                        \
253   {                                                                 \
254      Edje_Patterns *r;                                              \
255      size_t i;                                                      \
256                                                                     \
257      if (!lst || eina_list_count(lst) <= 0)                         \
258        return NULL;                                                 \
259                                                                     \
260      r = malloc(sizeof (Edje_Patterns) +                            \
261                 eina_list_count(lst)                                \
262                 * sizeof(*r->finals)                                \
263                 * sizeof(*r->patterns));                            \
264      if (!r) return NULL;                                           \
265                                                                     \
266      r->ref = 1;                                                    \
267      r->delete_me = 0;                                              \
268      r->patterns_size = eina_list_count(lst);                       \
269      r->max_length = 0;                                             \
270      r->patterns = (const char **)r->finals + r->patterns_size + 1; \
271                                                                     \
272      for (i = 0; lst; ++i)                                          \
273        {                                                            \
274           const char *str;                                          \
275           Type *data;                                               \
276           size_t j;                                                 \
277           int special = 0;                                          \
278                                                                     \
279           data = eina_list_data_get(lst);                           \
280           if (!data)                                                \
281             {                                                       \
282                free(r);                                             \
283                return NULL;                                         \
284             }                                                       \
285                                                                     \
286           str = data->Source;                                       \
287           if (!str) str = "";                                       \
288           r->patterns[i] = str;                                     \
289                                                                     \
290           if (Show)                                                 \
291             INF("%lu [%s]", (unsigned long)i, str);                 \
292                                                                     \
293           r->finals[i] = 0;                                         \
294           for (j = 0; str[j]; ++j)                                  \
295             if (str[j] != '*')                                      \
296               {                                                     \
297                  r->finals[i] = j + 1;                              \
298                  special++;                                         \
299               }                                                     \
300           j += special ? special + 1 : 0;                           \
301                                                                     \
302           if (j > r->max_length)                                    \
303             r->max_length = j;                                      \
304                                                                     \
305           lst = eina_list_next(lst);                                \
306        }                                                            \
307                                                                     \
308      if (!_edje_match_states_alloc(r, 2))                           \
309        {                                                            \
310           free(r);                                                  \
311           return NULL;                                              \
312        }                                                            \
313                                                                     \
314      return r;                                                      \
315   }
316
317 #define EDJE_MATCH_INIT_ARRAY(Func, Type, Source, Show)             \
318   Edje_Patterns *                                                   \
319   Func(Type * const *lst, unsigned int count)                       \
320   {                                                                 \
321      Edje_Patterns *r;                                              \
322      size_t i;                                                      \
323                                                                     \
324      if (!lst || count == 0)                                        \
325        return NULL;                                                 \
326                                                                     \
327      r = malloc(sizeof (Edje_Patterns) +                            \
328                 count                                               \
329                 * sizeof(*r->finals)                                \
330                 * sizeof(*r->patterns));                            \
331      if (!r) return NULL;                                           \
332                                                                     \
333      r->ref = 1;                                                    \
334      r->delete_me = 0;                                              \
335      r->patterns_size = count;                                      \
336      r->max_length = 0;                                             \
337      r->patterns = (const char **)r->finals + r->patterns_size + 1; \
338                                                                     \
339      for (i = 0; i < count; ++i)                                    \
340        {                                                            \
341           const char *str;                                          \
342           size_t j;                                                 \
343           int special = 0;                                          \
344                                                                     \
345           if (!lst[i])                                              \
346             {                                                       \
347                free(r);                                             \
348                return NULL;                                         \
349             }                                                       \
350                                                                     \
351           str = lst[i]->Source;                                     \
352           if (!str) str = "";                                       \
353           r->patterns[i] = str;                                     \
354                                                                     \
355           if (Show)                                                 \
356             INF("%lu [%s]", (unsigned long)i, str);                 \
357                                                                     \
358           r->finals[i] = 0;                                         \
359           for (j = 0; str[j]; ++j)                                  \
360             if (str[j] != '*')                                      \
361               {                                                     \
362                  r->finals[i] = j + 1;                              \
363                  special++;                                         \
364               }                                                     \
365           j += special ? special + 1 : 0;                           \
366                                                                     \
367           if (j > r->max_length)                                    \
368             r->max_length = j;                                      \
369        }                                                            \
370                                                                     \
371      if (!_edje_match_states_alloc(r, 2))                           \
372        {                                                            \
373           free(r);                                                  \
374           return NULL;                                              \
375        }                                                            \
376                                                                     \
377      return r;                                                      \
378   }
379
380 EDJE_MATCH_INIT_LIST(edje_match_collection_dir_init,
381                      Edje_Part_Collection_Directory_Entry,
382                      entry, 0);
383 EDJE_MATCH_INIT_ARRAY(edje_match_programs_signal_init,
384                       Edje_Program,
385                       signal, 0);
386 EDJE_MATCH_INIT_ARRAY(edje_match_programs_source_init,
387                       Edje_Program,
388                       source, 0);
389 EDJE_MATCH_INIT_LIST(edje_match_callback_signal_init,
390                      Edje_Signal_Callback,
391                      signal, 0);
392 EDJE_MATCH_INIT_LIST(edje_match_callback_source_init,
393                      Edje_Signal_Callback,
394                      source, 0);
395
396 static Eina_Bool
397 _edje_match_collection_dir_exec_finals(const size_t *finals,
398                                        const Edje_States *states)
399 {
400    size_t i;
401
402    for (i = 0; i < states->size; ++i)
403      {
404         if (states->states[i].pos >= finals[states->states[i].idx])
405           return EINA_TRUE;
406      }
407    return EINA_FALSE;
408 }
409
410 static Eina_Bool
411 edje_match_programs_exec_check_finals(const size_t *signal_finals,
412                                       const size_t *source_finals,
413                                       const Edje_States *signal_states,
414                                       const Edje_States *source_states,
415                                       Edje_Program **programs,
416                                       Eina_Bool (*func)(Edje_Program *pr, void *data),
417                                       void *data,
418                                       Eina_Bool prop __UNUSED__)
419 {
420    size_t i;
421    size_t j;
422
423    /* when not enought memory, they could be NULL */
424    if (!signal_finals || !source_finals) return EINA_TRUE;
425
426    for (i = 0; i < signal_states->size; ++i)
427      {
428         if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx])
429           {
430              for (j = 0; j < source_states->size; ++j)
431                {
432                   if (signal_states->states[i].idx == source_states->states[j].idx
433                       && source_states->states[j].pos >= source_finals[source_states->states[j].idx])
434                     {
435                        Edje_Program *pr;
436
437                        pr = programs[signal_states->states[i].idx];
438                        if (pr)
439                          {
440                             if (func(pr, data))
441                               return EINA_FALSE;
442                          }
443                     }
444                }
445           }
446      }
447
448    return EINA_TRUE;
449 }
450
451 static int
452 edje_match_callback_exec_check_finals(const Edje_Patterns *signal_ppat,
453                                       const Edje_Patterns *source_ppat,
454                                       const size_t *signal_finals,
455                                       const size_t *source_finals,
456                                       const Edje_States *signal_states,
457                                       const Edje_States *source_states,
458                                       const char *sig,
459                                       const char *source,
460                                       Eina_List *callbacks,
461                                       Edje *ed,
462                                       Eina_Bool prop
463                                       )
464 {
465    Edje_Signal_Callback *escb;
466    Eina_Array run;
467    size_t i;
468    size_t j;
469    int r = 1;
470
471    eina_array_step_set(&run, sizeof (Eina_Array), 4);
472
473    for (i = 0; i < signal_states->size; ++i)
474      {
475         if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx])
476           {
477              for (j = 0; j < source_states->size; ++j)
478                {
479                   if (signal_states->states[i].idx == source_states->states[j].idx
480                       && source_states->states[j].pos >= source_finals[source_states->states[j].idx])
481                     {
482                        escb = eina_list_nth(callbacks, signal_states->states[i].idx);
483                        if (escb)
484                          {
485                             if ((prop) && (escb->propagate)) continue;
486                             if ((!escb->just_added)
487                                 && (!escb->delete_me))
488                               {
489                                  eina_array_push(&run, escb);
490                                  r = 2;
491                               }
492                          }
493                     }
494                }
495           }
496      }
497
498    while ((escb = eina_array_pop(&run)))
499      {
500         escb->func(escb->data, ed->obj, sig, source);
501         if (_edje_block_break(ed))
502           {
503              r = 0;
504              break;
505           }
506         if ((signal_ppat->delete_me) || (source_ppat->delete_me))
507           {
508              r = 0;
509              break;
510           }
511      }
512
513    eina_array_flush(&run);
514
515    return r;
516 }
517
518 static Edje_States *
519 _edje_match_fn(const Edje_Patterns *ppat,
520                const char *string,
521                Edje_States *states)
522 {
523    Edje_States *new_states = states + 1;
524    const char *c;
525
526    for (c = string; *c && states->size; ++c)
527      {
528         size_t i;
529
530         _edje_match_states_clear(new_states, ppat->patterns_size, ppat->max_length);
531
532         for (i = 0; i < states->size; ++i)
533           {
534              const size_t idx = states->states[i].idx;
535              const size_t pos = states->states[i].pos;
536
537              if (!ppat->patterns[idx][pos])
538                continue;
539              else if (ppat->patterns[idx][pos] == '*')
540                {
541                   _edje_match_states_insert(states, ppat->max_length, idx, pos + 1);
542                   _edje_match_states_insert(new_states, ppat->max_length, idx, pos);
543                }
544              else
545                {
546                   size_t m;
547
548                   if (_edje_match_patterns_exec_token(ppat->patterns[idx] + pos,
549                                                       *c,
550                                                       &m) != EDJE_MATCH_OK)
551                     return NULL;
552
553                   if (m)
554                     _edje_match_states_insert(new_states, ppat->max_length, idx, pos + m);
555                }
556           }
557         {
558            Edje_States *tmp = states;
559
560            states = new_states;
561            new_states = tmp;
562         }
563      }
564
565    return states;
566 }
567
568 Eina_Bool
569 edje_match_collection_dir_exec(const Edje_Patterns *ppat,
570                                const char *string)
571 {
572    Edje_States *result;
573    Eina_Bool r = EINA_FALSE;
574
575    /* under high memory presure, it could be NULL */
576    if (!ppat) return EINA_FALSE;
577
578    _edje_match_patterns_exec_init_states(ppat->states, ppat->patterns_size, ppat->max_length);
579
580    result = _edje_match_fn(ppat, string, ppat->states);
581
582    if (result)
583      r = _edje_match_collection_dir_exec_finals(ppat->finals, result);
584
585    return r;
586 }
587
588 Eina_Bool
589 edje_match_programs_exec(const Edje_Patterns *ppat_signal,
590                          const Edje_Patterns *ppat_source,
591                          const char *sig,
592                          const char *source,
593                          Edje_Program **programs,
594                          Eina_Bool (*func)(Edje_Program *pr, void *data),
595                          void *data,
596                          Eina_Bool prop)
597 {
598    Edje_States *signal_result;
599    Edje_States *source_result;
600    Eina_Bool r = EINA_FALSE;
601
602    /* under high memory presure, they could be NULL */
603    if (!ppat_source || !ppat_signal) return EINA_FALSE;
604
605    _edje_match_patterns_exec_init_states(ppat_signal->states,
606                                          ppat_signal->patterns_size,
607                                          ppat_signal->max_length);
608    _edje_match_patterns_exec_init_states(ppat_source->states,
609                                          ppat_source->patterns_size,
610                                          ppat_source->max_length);
611
612    signal_result = _edje_match_fn(ppat_signal, sig, ppat_signal->states);
613    source_result = _edje_match_fn(ppat_source, source, ppat_source->states);
614
615    if (signal_result && source_result)
616      r = edje_match_programs_exec_check_finals(ppat_signal->finals,
617                                                ppat_source->finals,
618                                                signal_result,
619                                                source_result,
620                                                programs,
621                                                func,
622                                                data,
623                                                prop);
624    return r;
625 }
626
627 int
628 edje_match_callback_exec(Edje_Patterns *ppat_signal,
629                          Edje_Patterns *ppat_source,
630                          const char *sig,
631                          const char *source,
632                          Eina_List *callbacks,
633                          Edje *ed,
634                          Eina_Bool prop
635                          )
636 {
637    Edje_States *signal_result;
638    Edje_States *source_result;
639    int r = 0;
640
641    /* under high memory presure, they could be NULL */
642    if (!ppat_source || !ppat_signal) return 0;
643
644    ppat_signal->ref++;
645    ppat_source->ref++;
646    _edje_match_patterns_exec_init_states(ppat_signal->states,
647                                          ppat_signal->patterns_size,
648                                          ppat_signal->max_length);
649    _edje_match_patterns_exec_init_states(ppat_source->states,
650                                          ppat_source->patterns_size,
651                                          ppat_source->max_length);
652
653    signal_result = _edje_match_fn(ppat_signal, sig, ppat_signal->states);
654    source_result = _edje_match_fn(ppat_source, source, ppat_source->states);
655
656    if (signal_result && source_result)
657      r = edje_match_callback_exec_check_finals(ppat_signal,
658                                                ppat_source,
659                                                ppat_signal->finals,
660                                                ppat_source->finals,
661                                                signal_result,
662                                                source_result,
663                                                sig,
664                                                source,
665                                                callbacks,
666                                                ed,
667                                                prop);
668    ppat_signal->ref--;
669    ppat_source->ref--;
670    if (ppat_signal->ref <= 0) edje_match_patterns_free(ppat_signal);
671    if (ppat_source->ref <= 0) edje_match_patterns_free(ppat_source);
672    return r;
673 }
674
675 void
676 edje_match_patterns_free(Edje_Patterns *ppat)
677 {
678    if (!ppat) return;
679
680    ppat->delete_me = 1;
681    ppat->ref--;
682    if (ppat->ref > 0) return;
683    _edje_match_states_free(ppat->states, 2);
684    free(ppat);
685 }
686
687 void
688 _edje_signals_sources_patterns_clean(Edje_Signals_Sources_Patterns *ssp)
689 {
690    if (!ssp->signals_patterns)
691      return;
692
693    edje_match_patterns_free(ssp->signals_patterns);
694    edje_match_patterns_free(ssp->sources_patterns);
695    ssp->signals_patterns = NULL;
696    ssp->sources_patterns = NULL;
697 }
698
699 static Eina_Rbtree_Direction
700 _edje_signal_source_node_cmp(const Edje_Signal_Source_Char *n1,
701                              const Edje_Signal_Source_Char *n2,
702                              __UNUSED__ void *data)
703 {
704    int cmp;
705
706    cmp = strcmp(n1->signal, n2->signal);
707    if (cmp) return cmp < 0 ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
708
709    return strcmp(n1->source, n2->source) < 0 ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
710 }
711
712 static int
713 _edje_signal_source_key_cmp(const Edje_Signal_Source_Char *node,
714                             const char *sig,
715                             __UNUSED__ int length,
716                             const char *source)
717 {
718    int cmp;
719
720    cmp = strcmp(node->signal, sig);
721    if (cmp) return cmp;
722
723    return strcmp(node->source, source);
724 }
725
726 Eina_List *
727 edje_match_program_hash_build(Edje_Program *const *programs,
728                               unsigned int count,
729                               Eina_Rbtree **tree)
730 {
731    Eina_List *result = NULL;
732    Eina_Rbtree *new = NULL;
733    unsigned int i;
734
735    for (i = 0; i < count; ++i)
736      {
737         if (programs[i]->signal && !strpbrk(programs[i]->signal, "*?[\\")
738             && programs[i]->source && !strpbrk(programs[i]->source, "*?[\\"))
739           {
740              Edje_Signal_Source_Char *item;
741
742              item = (Edje_Signal_Source_Char *)eina_rbtree_inline_lookup(new, programs[i]->signal, 0,
743                                                                          EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), programs[i]->source);
744              if (!item)
745                {
746                   item = malloc(sizeof (Edje_Signal_Source_Char));
747                   if (!item) continue;
748
749                   item->signal = programs[i]->signal;
750                   item->source = programs[i]->source;
751                   item->list = NULL;
752
753                   new = eina_rbtree_inline_insert(new, EINA_RBTREE_GET(item),
754                                                   EINA_RBTREE_CMP_NODE_CB(_edje_signal_source_node_cmp), NULL);
755                }
756
757              item->list = eina_list_prepend(item->list, programs[i]);
758           }
759         else
760           result = eina_list_prepend(result, programs[i]);
761      }
762
763    *tree = new;
764    return result;
765 }
766
767 Eina_List *
768 edje_match_callback_hash_build(const Eina_List *callbacks,
769                                Eina_Rbtree **tree)
770 {
771    Eina_List *result = NULL;
772    Eina_Rbtree *new = NULL;
773    Edje_Signal_Callback *callback;
774    const Eina_List *l;
775
776    EINA_LIST_FOREACH(callbacks, l, callback)
777      {
778         if (callback->signal && !strpbrk(callback->signal, "*?[\\")
779             && callback->source && !strpbrk(callback->source, "*?[\\"))
780           {
781              Edje_Signal_Source_Char *item;
782
783              item = (Edje_Signal_Source_Char *)eina_rbtree_inline_lookup(new, callback->signal, 0,
784                                                                          EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), callback->source);
785              if (!item)
786                {
787                   item = malloc(sizeof (Edje_Signal_Source_Char));
788                   if (!item) continue;
789
790                   item->signal = callback->signal;
791                   item->source = callback->source;
792                   item->list = NULL;
793
794                   new = eina_rbtree_inline_insert(new, EINA_RBTREE_GET(item),
795                                                   EINA_RBTREE_CMP_NODE_CB(_edje_signal_source_node_cmp), NULL);
796                }
797
798              item->list = eina_list_prepend(item->list, callback);
799           }
800         else
801           result = eina_list_prepend(result, callback);
802      }
803
804    *tree = new;
805    return result;
806 }
807
808 const Eina_List *
809 edje_match_signal_source_hash_get(const char *sig,
810                                   const char *source,
811                                   const Eina_Rbtree *tree)
812 {
813    Edje_Signal_Source_Char *lookup;
814
815    lookup = (Edje_Signal_Source_Char *)eina_rbtree_inline_lookup(tree, sig, 0,
816                                                                  EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), source);
817
818    if (lookup) return lookup->list;
819    return NULL;
820 }
821
822 void
823 edje_match_signal_source_free(Edje_Signal_Source_Char *key, __UNUSED__ void *data)
824 {
825    eina_list_free(key->list);
826    free(key);
827 }
828