aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/edje/src/lib/edje_match.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/edje/src/lib/edje_match.c814
1 files changed, 814 insertions, 0 deletions
diff --git a/libraries/edje/src/lib/edje_match.c b/libraries/edje/src/lib/edje_match.c
new file mode 100644
index 0000000..f113f7b
--- /dev/null
+++ b/libraries/edje/src/lib/edje_match.c
@@ -0,0 +1,814 @@
1#include "edje_private.h"
2
3/* States manipulations. */
4
5typedef struct _Edje_State Edje_State;
6struct _Edje_State
7{
8 size_t idx;
9 size_t pos;
10};
11
12struct _Edje_States
13{
14 size_t size;
15 Edje_State *states;
16 Eina_Bool *has;
17};
18
19static 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
34static 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
90static 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
113static 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
123enum status
124{
125 patterns_not_found = 0,
126 patterns_found = 1,
127 patterns_syntax_error = 2
128};
129
130static 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
154static 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
172static 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
203static 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
231static 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
380EDJE_MATCH_INIT_LIST(edje_match_collection_dir_init,
381 Edje_Part_Collection_Directory_Entry,
382 entry, 0);
383EDJE_MATCH_INIT_ARRAY(edje_match_programs_signal_init,
384 Edje_Program,
385 signal, 0);
386EDJE_MATCH_INIT_ARRAY(edje_match_programs_source_init,
387 Edje_Program,
388 source, 0);
389EDJE_MATCH_INIT_LIST(edje_match_callback_signal_init,
390 Edje_Signal_Callback,
391 signal, 0);
392EDJE_MATCH_INIT_LIST(edje_match_callback_source_init,
393 Edje_Signal_Callback,
394 source, 0);
395
396static 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
410static Eina_Bool
411edje_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
451static int
452edje_match_callback_exec_check_finals(const Edje_Patterns *singal_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 size_t i;
466 size_t j;
467 int r = 1;
468
469 for (i = 0; i < signal_states->size; ++i)
470 {
471 if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx])
472 {
473 for (j = 0; j < source_states->size; ++j)
474 {
475 if (signal_states->states[i].idx == source_states->states[j].idx
476 && source_states->states[j].pos >= source_finals[source_states->states[j].idx])
477 {
478 Edje_Signal_Callback *escb;
479
480 escb = eina_list_nth(callbacks, signal_states->states[i].idx);
481 if (escb)
482 {
483 if ((prop) && (escb->propagate)) continue;
484 if ((!escb->just_added)
485 && (!escb->delete_me))
486 {
487 escb->func(escb->data, ed->obj, sig, source);
488 r = 2;
489 }
490 if (_edje_block_break(ed))
491 return 0;
492 if ((singal_ppat->delete_me) || (source_ppat->delete_me))
493 return 0;
494 }
495 }
496 }
497 }
498 }
499
500 return r;
501}
502
503
504static Edje_States*
505_edje_match_fn(const Edje_Patterns *ppat,
506 const char *string,
507 Edje_States *states)
508{
509 Edje_States *new_states = states + 1;
510 const char *c;
511
512 for (c = string; *c && states->size; ++c)
513 {
514 size_t i;
515
516 _edje_match_states_clear(new_states, ppat->patterns_size, ppat->max_length);
517
518 for (i = 0; i < states->size; ++i)
519 {
520 const size_t idx = states->states[i].idx;
521 const size_t pos = states->states[i].pos;
522
523 if (!ppat->patterns[idx][pos])
524 continue;
525 else if (ppat->patterns[idx][pos] == '*')
526 {
527 _edje_match_states_insert(states, ppat->max_length, idx, pos + 1);
528 _edje_match_states_insert(new_states, ppat->max_length, idx, pos);
529 }
530 else
531 {
532 size_t m;
533
534 if (_edje_match_patterns_exec_token(ppat->patterns[idx] + pos,
535 *c,
536 &m) != EDJE_MATCH_OK)
537 return NULL;
538
539 if (m)
540 _edje_match_states_insert(new_states, ppat->max_length, idx, pos + m);
541 }
542 }
543 {
544 Edje_States *tmp = states;
545
546 states = new_states;
547 new_states = tmp;
548 }
549 }
550
551 return states;
552}
553
554Eina_Bool
555edje_match_collection_dir_exec(const Edje_Patterns *ppat,
556 const char *string)
557{
558 Edje_States *result;
559 Eina_Bool r = EINA_FALSE;
560
561 /* under high memory presure, it could be NULL */
562 if (!ppat) return EINA_FALSE;
563
564 _edje_match_patterns_exec_init_states(ppat->states, ppat->patterns_size, ppat->max_length);
565
566 result = _edje_match_fn(ppat, string, ppat->states);
567
568 if (result)
569 r = _edje_match_collection_dir_exec_finals(ppat->finals, result);
570
571 return r;
572}
573
574Eina_Bool
575edje_match_programs_exec(const Edje_Patterns *ppat_signal,
576 const Edje_Patterns *ppat_source,
577 const char *sig,
578 const char *source,
579 Edje_Program **programs,
580 Eina_Bool (*func)(Edje_Program *pr, void *data),
581 void *data,
582 Eina_Bool prop)
583{
584 Edje_States *signal_result;
585 Edje_States *source_result;
586 Eina_Bool r = EINA_FALSE;
587
588 /* under high memory presure, they could be NULL */
589 if (!ppat_source || !ppat_signal) return EINA_FALSE;
590
591 _edje_match_patterns_exec_init_states(ppat_signal->states,
592 ppat_signal->patterns_size,
593 ppat_signal->max_length);
594 _edje_match_patterns_exec_init_states(ppat_source->states,
595 ppat_source->patterns_size,
596 ppat_source->max_length);
597
598 signal_result = _edje_match_fn(ppat_signal, sig, ppat_signal->states);
599 source_result = _edje_match_fn(ppat_source, source, ppat_source->states);
600
601 if (signal_result && source_result)
602 r = edje_match_programs_exec_check_finals(ppat_signal->finals,
603 ppat_source->finals,
604 signal_result,
605 source_result,
606 programs,
607 func,
608 data,
609 prop);
610 return r;
611}
612
613int
614edje_match_callback_exec(Edje_Patterns *ppat_signal,
615 Edje_Patterns *ppat_source,
616 const char *sig,
617 const char *source,
618 Eina_List *callbacks,
619 Edje *ed,
620 Eina_Bool prop
621 )
622{
623 Edje_States *signal_result;
624 Edje_States *source_result;
625 int r = 0;
626
627 /* under high memory presure, they could be NULL */
628 if (!ppat_source || !ppat_signal) return 0;
629
630 ppat_signal->ref++;
631 ppat_source->ref++;
632 _edje_match_patterns_exec_init_states(ppat_signal->states,
633 ppat_signal->patterns_size,
634 ppat_signal->max_length);
635 _edje_match_patterns_exec_init_states(ppat_source->states,
636 ppat_source->patterns_size,
637 ppat_source->max_length);
638
639 signal_result = _edje_match_fn(ppat_signal, sig, ppat_signal->states);
640 source_result = _edje_match_fn(ppat_source, source, ppat_source->states);
641
642 if (signal_result && source_result)
643 r = edje_match_callback_exec_check_finals(ppat_signal,
644 ppat_source,
645 ppat_signal->finals,
646 ppat_source->finals,
647 signal_result,
648 source_result,
649 sig,
650 source,
651 callbacks,
652 ed,
653 prop);
654 ppat_signal->ref--;
655 ppat_source->ref--;
656 if (ppat_signal->ref <= 0) edje_match_patterns_free(ppat_signal);
657 if (ppat_source->ref <= 0) edje_match_patterns_free(ppat_source);
658 return r;
659}
660
661void
662edje_match_patterns_free(Edje_Patterns *ppat)
663{
664 if (!ppat) return ;
665
666 ppat->delete_me = 1;
667 ppat->ref--;
668 if (ppat->ref > 0) return;
669 _edje_match_states_free(ppat->states, 2);
670 free(ppat);
671}
672
673void
674_edje_signals_sources_patterns_clean(Edje_Signals_Sources_Patterns *ssp)
675{
676 if (!ssp->signals_patterns)
677 return;
678
679 edje_match_patterns_free(ssp->signals_patterns);
680 edje_match_patterns_free(ssp->sources_patterns);
681 ssp->signals_patterns = NULL;
682 ssp->sources_patterns = NULL;
683}
684
685static Eina_Rbtree_Direction
686_edje_signal_source_node_cmp(const Edje_Signal_Source_Char *n1,
687 const Edje_Signal_Source_Char *n2,
688 __UNUSED__ void *data)
689{
690 int cmp;
691
692 cmp = strcmp(n1->signal, n2->signal);
693 if (cmp) return cmp < 0 ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
694
695 return strcmp(n1->source, n2->source) < 0 ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
696}
697
698static int
699_edje_signal_source_key_cmp(const Edje_Signal_Source_Char *node,
700 const char *sig,
701 __UNUSED__ int length,
702 const char *source)
703{
704 int cmp;
705
706 cmp = strcmp(node->signal, sig);
707 if (cmp) return cmp;
708
709 return strcmp(node->source, source);
710}
711
712
713Eina_List *
714edje_match_program_hash_build(Edje_Program * const *programs,
715 unsigned int count,
716 Eina_Rbtree **tree)
717{
718 Eina_List *result = NULL;
719 Eina_Rbtree *new = NULL;
720 unsigned int i;
721
722 for (i = 0; i < count; ++i)
723 {
724 if (programs[i]->signal && !strpbrk(programs[i]->signal, "*?[\\")
725 && programs[i]->source && !strpbrk(programs[i]->source, "*?[\\"))
726 {
727 Edje_Signal_Source_Char *item;
728
729 item = (Edje_Signal_Source_Char*) eina_rbtree_inline_lookup(new, programs[i]->signal, 0,
730 EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), programs[i]->source);
731 if (!item)
732 {
733 item = malloc(sizeof (Edje_Signal_Source_Char));
734 if (!item) continue;
735
736 item->signal = programs[i]->signal;
737 item->source = programs[i]->source;
738 item->list = NULL;
739
740 new = eina_rbtree_inline_insert(new, EINA_RBTREE_GET(item),
741 EINA_RBTREE_CMP_NODE_CB(_edje_signal_source_node_cmp), NULL);
742 }
743
744 item->list = eina_list_prepend(item->list, programs[i]);
745 }
746 else
747 result = eina_list_prepend(result, programs[i]);
748 }
749
750 *tree = new;
751 return result;
752}
753
754Eina_List *
755edje_match_callback_hash_build(const Eina_List *callbacks,
756 Eina_Rbtree **tree)
757{
758 Eina_List *result = NULL;
759 Eina_Rbtree *new = NULL;
760 Edje_Signal_Callback *callback;
761 const Eina_List *l;
762
763 EINA_LIST_FOREACH(callbacks, l, callback)
764 {
765 if (callback->signal && !strpbrk(callback->signal, "*?[\\")
766 && callback->source && !strpbrk(callback->source, "*?[\\"))
767 {
768 Edje_Signal_Source_Char *item;
769
770 item = (Edje_Signal_Source_Char*) eina_rbtree_inline_lookup(new, callback->signal, 0,
771 EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), callback->source);
772 if (!item)
773 {
774 item = malloc(sizeof (Edje_Signal_Source_Char));
775 if (!item) continue;
776
777 item->signal = callback->signal;
778 item->source = callback->source;
779 item->list = NULL;
780
781 new = eina_rbtree_inline_insert(new, EINA_RBTREE_GET(item),
782 EINA_RBTREE_CMP_NODE_CB(_edje_signal_source_node_cmp), NULL);
783 }
784
785 item->list = eina_list_prepend(item->list, callback);
786 }
787 else
788 result = eina_list_prepend(result, callback);
789 }
790
791 *tree = new;
792 return result;
793}
794
795const Eina_List *
796edje_match_signal_source_hash_get(const char *sig,
797 const char *source,
798 const Eina_Rbtree *tree)
799{
800 Edje_Signal_Source_Char *lookup;
801
802 lookup = (Edje_Signal_Source_Char*) eina_rbtree_inline_lookup(tree, sig, 0,
803 EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), source);
804
805 if (lookup) return lookup->list;
806 return NULL;
807}
808
809void
810edje_match_signal_source_free(Edje_Signal_Source_Char *key, __UNUSED__ void *data)
811{
812 eina_list_free(key->list);
813 free(key);
814}