Various patches are applied
[platform/framework/web/data-provider-master.git] / src / group.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <stdlib.h> /* malloc */
20 #include <errno.h>
21 #include <string.h> /* strdup */
22
23 #include <dlog.h>
24 #include <Eina.h>
25 #include <livebox-errno.h>
26
27 #include "util.h"
28 #include "debug.h"
29 #include "group.h"
30 #include "conf.h"
31
32 int errno;
33
34 static struct info {
35         Eina_List *cluster_list;
36 } s_info = {
37         .cluster_list = NULL,
38 };
39
40 struct cluster {
41         char *name;
42         Eina_List *category_list;
43 };
44
45 struct category {
46         char *name;
47         struct cluster *cluster;
48         Eina_List *info_list; /* list of instances of the struct inst_info */
49 };
50
51 struct context_info {
52         char *pkgname;
53         struct category *category;
54         Eina_List *context_list; /* context item list */
55 };
56
57 struct context_item_data {
58         char *tag;
59         void *data;
60 };
61
62 struct context_item {
63         char *ctx_item;
64         struct context_info *info;
65         Eina_List *option_list;
66         Eina_List *data_list;
67 };
68
69 struct context_option {
70         struct context_item *item;
71         char *key;
72         char *value;
73 };
74
75 HAPI struct context_info *group_create_context_info(struct category *category, const char *pkgname)
76 {
77         struct context_info *info;
78
79         info = calloc(1, sizeof(*info));
80         if (!info) {
81                 ErrPrint("Heap: %s\n", strerror(errno));
82                 return NULL;
83         }
84
85         info->pkgname = strdup(pkgname);
86         if (!info->pkgname) {
87                 ErrPrint("Heap: %s\n", strerror(errno));
88                 DbgFree(info);
89                 return NULL;
90         }
91
92         info->category = category;
93         category->info_list = eina_list_append(category->info_list, info);
94         return info;
95 }
96
97 static inline void del_options(struct context_item *item)
98 {
99         struct context_option *option;
100
101         EINA_LIST_FREE(item->option_list, option) {
102                 DbgFree(option->key);
103                 DbgFree(option->value);
104                 DbgFree(option);
105         }
106 }
107
108 static inline void del_context_item(struct context_info *info)
109 {
110         struct context_item *item;
111
112         EINA_LIST_FREE(info->context_list, item) {
113                 del_options(item);
114                 DbgFree(item->ctx_item);
115                 DbgFree(item);
116         }
117 }
118
119 HAPI struct context_item *group_add_context_item(struct context_info *info, const char *ctx_item)
120 {
121         struct context_item *item;
122
123         item = calloc(1, sizeof(*item));
124         if (!item) {
125                 ErrPrint("Heap: %s\n", strerror(errno));
126                 return NULL;
127         }
128
129         item->ctx_item = strdup(ctx_item);
130         if (!item->ctx_item) {
131                 ErrPrint("Heap: %s\n", strerror(errno));
132                 DbgFree(item);
133                 return NULL;
134         }
135
136         item->info = info;
137         info->context_list = eina_list_append(info->context_list, item);
138         return item;
139 }
140
141 HAPI int group_add_option(struct context_item *item, const char *key, const char *value)
142 {
143         struct context_option *option;
144
145         option = calloc(1, sizeof(*option));
146         if (!option) {
147                 ErrPrint("Heap: %s\n", strerror(errno));
148                 return LB_STATUS_ERROR_MEMORY;
149         }
150
151         option->key = strdup(key);
152         if (!option->key) {
153                 ErrPrint("Heap: %s\n", strerror(errno));
154                 DbgFree(option);
155                 return LB_STATUS_ERROR_MEMORY;
156         }
157
158         option->value = strdup(value);
159         if (!option->value) {
160                 ErrPrint("Heap: %s\n", strerror(errno));
161                 DbgFree(option->key);
162                 DbgFree(option);
163                 return LB_STATUS_ERROR_MEMORY;
164         }
165
166         option->item = item;
167         item->option_list = eina_list_append(item->option_list, option);
168         return LB_STATUS_SUCCESS;
169 }
170
171 HAPI int group_destroy_context_info(struct context_info *info)
172 {
173         struct category *category;
174
175         category = info->category;
176         if (!category) {
177                 ErrPrint("No category found\n");
178                 return LB_STATUS_ERROR_INVALID;
179         }
180
181         category->info_list = eina_list_remove(category->info_list, info);
182
183         del_context_item(info);
184         DbgFree(info->pkgname);
185         DbgFree(info);
186         return LB_STATUS_SUCCESS;
187 }
188
189 HAPI struct cluster *group_create_cluster(const char *name)
190 {
191         struct cluster *cluster;
192
193         cluster = malloc(sizeof(*cluster));
194         if (!cluster) {
195                 ErrPrint("Heap: %s\n", strerror(errno));
196                 return NULL;
197         }
198
199         cluster->name = strdup(name);
200         if (!cluster->name) {
201                 ErrPrint("Heap: %s\n", strerror(errno));
202                 DbgFree(cluster);
203                 return NULL;
204         }
205
206         cluster->category_list = NULL;
207
208         DbgPrint("Cluster %s is created\n", cluster->name);
209         s_info.cluster_list = eina_list_append(s_info.cluster_list, cluster);
210         return cluster;
211 }
212
213 HAPI struct cluster *group_find_cluster(const char *name)
214 {
215         Eina_List *l;
216         struct cluster *cluster;
217
218         EINA_LIST_FOREACH(s_info.cluster_list, l, cluster) {
219                 if (!strcasecmp(cluster->name, name))
220                         return cluster;
221         }
222
223         return NULL;
224 }
225
226 HAPI struct category *group_create_category(struct cluster *cluster, const char *name)
227 {
228         struct category *category;
229
230         category = malloc(sizeof(*category));
231         if (!category) {
232                 ErrPrint("Heap: %s\n", strerror(errno));
233                 return NULL;
234         }
235
236         category->name = strdup(name);
237         if (!category->name) {
238                 ErrPrint("Heap: %s\n", strerror(errno));
239                 DbgFree(category);
240                 return NULL;
241         }
242
243         category->cluster = cluster;
244         category->info_list = NULL;
245
246         DbgPrint("Category %s is created\n", category->name);
247         cluster->category_list = eina_list_append(cluster->category_list, category);
248         return category;
249 }
250
251 static inline void destroy_cluster(struct cluster *cluster)
252 {
253         struct category *category;
254         Eina_List *l;
255         Eina_List *n;
256
257         EINA_LIST_FOREACH_SAFE(cluster->category_list, l, n, category) {
258                 group_destroy_category(category);
259         }
260
261         DbgPrint("Destroy cluster: %s\n", cluster->name);
262         DbgFree(cluster->name);
263         DbgFree(cluster);
264 }
265
266 HAPI int group_destroy_cluster(struct cluster *cluster)
267 {
268         Eina_List *l;
269         Eina_List *n;
270         struct cluster *item;
271
272         EINA_LIST_FOREACH_SAFE(s_info.cluster_list, l, n, item) {
273                 if (item == cluster) {
274                         s_info.cluster_list = eina_list_remove_list(s_info.cluster_list, l);
275                         destroy_cluster(cluster);
276                         return LB_STATUS_SUCCESS;
277                 }
278         }
279
280         return LB_STATUS_ERROR_NOT_EXIST;
281 }
282
283 static inline void destroy_category(struct category *category)
284 {
285         Eina_List *l;
286         Eina_List *n;
287         struct context_info *info;
288
289         EINA_LIST_FOREACH_SAFE(category->info_list, l, n, info) {
290                 group_destroy_context_info(info);
291         }
292
293         DbgPrint("Destroy category: %s\n", category->name);
294         DbgFree(category->name);
295         DbgFree(category);
296 }
297
298 HAPI int group_destroy_category(struct category *category)
299 {
300         struct cluster *cluster;
301
302         cluster = category->cluster;
303         if (cluster)
304                 cluster->category_list = eina_list_remove(cluster->category_list, category);
305
306         destroy_category(category);
307         return LB_STATUS_SUCCESS;
308 }
309
310 HAPI struct category *group_find_category(struct cluster *cluster, const char *name)
311 {
312         struct category *category;
313         Eina_List *l;
314
315         EINA_LIST_FOREACH(cluster->category_list, l, category) {
316                 if (!strcasecmp(category->name, name))
317                         return category;
318         }
319
320         return NULL;
321 }
322
323 HAPI Eina_List * const group_context_info_list(struct category *category)
324 {
325         return category->info_list;
326 }
327
328 HAPI Eina_List *const group_context_item_list(struct context_info *info)
329 {
330         return info->context_list;
331 }
332
333 HAPI Eina_List *const group_context_option_list(struct context_item *item)
334 {
335         return item->option_list;
336 }
337
338 HAPI Eina_List *const group_cluster_list(void)
339 {
340         return s_info.cluster_list;
341 }
342
343 HAPI Eina_List * const group_category_list(struct cluster *cluster)
344 {
345         return cluster->category_list;
346 }
347
348 HAPI struct context_info * const group_context_info_from_item(struct context_item *item)
349 {
350         return item->info;
351 }
352
353 HAPI struct category * const group_category_from_context_info(struct context_info *info)
354 {
355         return info->category;
356 }
357
358 HAPI const char * const group_pkgname_from_context_info(struct context_info *info)
359 {
360         return info->pkgname;
361 }
362
363 HAPI const char * const group_option_item_key(struct context_option *option)
364 {
365         return option->key;
366 }
367
368 HAPI const char * const group_option_item_value(struct context_option *option)
369 {
370         return option->value;
371 }
372
373 HAPI const char * const group_context_item(struct context_item *item)
374 {
375         return item->ctx_item;
376 }
377
378 HAPI int group_context_item_add_data(struct context_item *item, const char *tag, void *data)
379 {
380         struct context_item_data *tmp;
381
382         tmp = malloc(sizeof(*tmp));
383         if (!tmp)
384                 return LB_STATUS_ERROR_MEMORY;
385
386         tmp->tag = strdup(tag);
387         if (!tmp->tag) {
388                 DbgFree(tmp);
389                 return LB_STATUS_ERROR_MEMORY;
390         }
391
392         tmp->data = data;
393         item->data_list = eina_list_append(item->data_list, tmp);
394         return LB_STATUS_SUCCESS;
395 }
396
397 HAPI void *group_context_item_data(struct context_item *item, const char *tag)
398 {
399         struct context_item_data *tmp;
400         Eina_List *l;
401
402         EINA_LIST_FOREACH(item->data_list, l, tmp) {
403                 if (!strcmp(tmp->tag, tag))
404                         return tmp->data;
405         }
406
407         return NULL;
408 }
409
410 HAPI void *group_context_item_del_data(struct context_item *item, const char *tag)
411 {
412         struct context_item_data *tmp;
413         Eina_List *l;
414         Eina_List *n;
415
416         EINA_LIST_FOREACH_SAFE(item->data_list, l, n, tmp) {
417                 if (!strcmp(tmp->tag, tag)) {
418                         void *data;
419
420                         item->data_list = eina_list_remove(item->data_list, tmp);
421
422                         data = tmp->data;
423
424                         DbgFree(tmp->tag);
425                         DbgFree(tmp);
426
427                         return data;
428                 }
429         }
430
431         return NULL;
432 }
433
434 HAPI const char * const group_category_name(struct category *category)
435 {
436         return category ? category->name : NULL;
437 }
438
439 HAPI const char * const group_cluster_name(struct cluster *cluster)
440 {
441         return cluster ? cluster->name : NULL;
442 }
443
444 HAPI const char *group_cluster_name_by_category(struct category *category)
445 {
446         return !category ? NULL : (category->cluster ? category->cluster->name : NULL);
447 }
448
449 static inline char *get_token(char *ptr, int *len)
450 {
451         char *name;
452         int _len;
453
454         if (*len == 0) {
455                 ErrPrint("Start brace but len = 0\n");
456                 return NULL;
457         }
458
459         _len = *len;
460
461         while (_len > 0 && isspace(ptr[_len]))
462                 _len--;
463
464         if (_len == 0) {
465                 ErrPrint("Token has no string\n");
466                 return NULL;
467         }
468
469         name = malloc(_len + 1);
470         if (!name) {
471                 ErrPrint("Heap: %s\n", strerror(errno));
472                 return NULL;
473         }
474
475         strncpy(name, ptr - *len, _len);
476         name[_len] = '\0';
477
478         *len = _len;
479         return name;
480 }
481
482 HAPI int group_add_livebox(const char *group, const char *pkgname)
483 {
484         struct cluster *cluster;
485         struct category *category;
486         struct context_info *info;
487         struct context_item *item;
488         char *key;
489         char *name;
490         char *ptr;
491         int len;
492         int is_open = 0;
493         enum {
494                 CLUSTER,
495                 CATEGORY,
496                 CONTEXT_ITEM,
497                 CONTEXT_OPTION_KEY,
498                 CONTEXT_OPTION_VALUE,
499                 CONTEXT_ERROR = 0xFFFFFFFF,
500         } state;
501
502         state = CLUSTER;
503
504         ptr = (char *)group;
505         len = 0;
506         key = NULL;
507
508         /* Skip the first space characters */
509         while (*ptr && isspace(*ptr)) ptr++;
510
511         cluster = NULL;
512         while (*ptr) {
513                 if (*ptr == '{') {
514                         name = get_token(ptr, &len);
515                         if (!name) {
516                                 ErrPrint("Failed to get token\n");
517                                 return LB_STATUS_ERROR_FAULT;
518                         }
519                         /* cluster{category{context{key=value,key=value},context{key=value}}} */
520                         /* cluster{category} */
521
522                         switch (state) {
523                         case CLUSTER:
524                                 cluster = group_find_cluster(name);
525                                 if (!cluster)
526                                         cluster = group_create_cluster(name);
527
528                                 if (!cluster) {
529                                         ErrPrint("Failed to get cluster\n");
530                                         DbgFree(name);
531                                         return LB_STATUS_ERROR_FAULT;
532                                 }
533
534                                 state = CATEGORY;
535                                 break;
536
537                         case CATEGORY:
538                                 category = group_find_category(cluster, name);
539                                 if (!category)
540                                         category = group_create_category(cluster, name);
541
542                                 if (!category) {
543                                         ErrPrint("Failed to get category\n");
544                                         DbgFree(name);
545                                         return LB_STATUS_ERROR_FAULT;
546                                 }
547
548                                 info = group_create_context_info(category, pkgname);
549                                 if (!info) {
550                                         ErrPrint("Failed to create ctx info\n");
551                                         DbgFree(name);
552                                         return LB_STATUS_ERROR_FAULT;
553                                 }
554
555                                 state = CONTEXT_ITEM;
556                                 break;
557
558                         case CONTEXT_ITEM:
559                                 item = group_add_context_item(info, name);
560                                 if (!item) {
561                                         ErrPrint("Failed to create a context item\n");
562                                         DbgFree(name);
563                                         return LB_STATUS_ERROR_FAULT;
564                                 }
565
566                                 state = CONTEXT_OPTION_KEY;
567                                 break;
568
569                         case CONTEXT_OPTION_KEY:
570                         case CONTEXT_OPTION_VALUE:
571                         default:
572                                 ErrPrint("Invalid state\n");
573                                 DbgFree(name);
574                                 return LB_STATUS_ERROR_FAULT;
575                         }
576
577                         DbgFree(name);
578                         is_open++;
579                         len = 0;
580                         ptr++;
581                         while (*ptr && isspace(*ptr)) ptr++;
582                         continue;
583                 } else if (*ptr == ',') {
584                         name = get_token(ptr, &len);
585                         if (!name) {
586                                 ErrPrint("Failed to get token (len:%d)\n", len);
587                                 len = 0;
588                                 ptr++;
589                                 while (*ptr && isspace(*ptr)) ptr++;
590                                 continue;
591                         }
592
593                         switch (state) {
594                         case CLUSTER:
595                                 if (is_open != 0) {
596                                         ErrPrint("Invalid state\n");
597                                         DbgFree(name);
598                                         return LB_STATUS_ERROR_FAULT;
599                                 }
600                                 cluster = group_find_cluster(name);
601                                 if (!cluster)
602                                         cluster = group_create_cluster(name);
603
604                                 if (!cluster) {
605                                         ErrPrint("Failed to get cluster\n");
606                                         DbgFree(name);
607                                         return LB_STATUS_ERROR_FAULT;
608                                 }
609
610                                 state = CATEGORY;
611                                 break;
612
613                         case CATEGORY:
614                                 if (is_open != 1) {
615                                         ErrPrint("Invalid state\n");
616                                         DbgFree(name);
617                                         return LB_STATUS_ERROR_FAULT;
618                                 }
619                                 category = group_find_category(cluster, name);
620                                 if (!category)
621                                         category = group_create_category(cluster, name);
622
623                                 if (!category) {
624                                         ErrPrint("Failed to get category\n");
625                                         DbgFree(name);
626                                         return LB_STATUS_ERROR_FAULT;
627                                 }
628
629                                 info = group_create_context_info(category, pkgname);
630                                 if (!info) {
631                                         ErrPrint("Failed to create ctx info\n");
632                                         DbgFree(name);
633                                         return LB_STATUS_ERROR_FAULT;
634                                 }
635
636                                 state = CONTEXT_ITEM;
637                                 break;
638                         case CONTEXT_ITEM:
639                                 if (is_open == 1) {
640                                         category = group_find_category(cluster, name);
641                                         if (!category)
642                                                 category = group_create_category(cluster, name);
643
644                                         if (!category) {
645                                                 ErrPrint("Failed to get category\n");
646                                                 DbgFree(name);
647                                                 return LB_STATUS_ERROR_FAULT;
648                                         }
649
650                                         info = group_create_context_info(category, pkgname);
651                                         if (!info) {
652                                                 ErrPrint("Failed to create ctx info\n");
653                                                 DbgFree(name);
654                                                 return LB_STATUS_ERROR_FAULT;
655                                         }
656                                         DbgPrint("Keep this syntax only for the compatibility\n");
657                                 } else if (is_open == 2) {
658                                         item = group_add_context_item(info, name);
659                                         if (!item) {
660                                                 ErrPrint("Failed to create a context item\n");
661                                                 DbgFree(name);
662                                                 return LB_STATUS_ERROR_FAULT;
663                                         }
664                                         state = CONTEXT_OPTION_KEY;
665                                 } else {
666                                         ErrPrint("Invalid state\n");
667                                         DbgFree(name);
668                                         return LB_STATUS_ERROR_FAULT;
669                                 }
670
671                                 break;
672                         case CONTEXT_OPTION_VALUE:
673                                 if (is_open != 3) {
674                                         ErrPrint("Invalid state\n");
675                                         DbgFree(name);
676                                         return LB_STATUS_ERROR_FAULT;
677                                 }
678
679                                 if (group_add_option(item, key, name) < 0)
680                                         ErrPrint("Failed to add a new option: %s - %s\n", key, name);
681
682                                 DbgFree(key);
683                                 key = NULL;
684
685                                 state = CONTEXT_OPTION_KEY;
686                                 break;
687                         case CONTEXT_OPTION_KEY:
688                         default:
689                                 ErrPrint("Invalid state (%s)\n", name);
690                                 DbgFree(name);
691                                 return LB_STATUS_ERROR_FAULT;
692                         }
693
694                         DbgFree(name);
695                         len = 0;
696                         ptr++;
697                         while (*ptr && isspace(*ptr)) ptr++;
698                         continue;
699                 } else if (*ptr == '=') {
700                         if (is_open != 3 || state != CONTEXT_OPTION_KEY) {
701                                 ErrPrint("Invalid state\n");
702                                 return LB_STATUS_ERROR_FAULT;
703                         }
704
705                         key = get_token(ptr, &len);
706                         if (!key) {
707                                 ErrPrint("Failed to get token\n");
708                                 return LB_STATUS_ERROR_FAULT;
709                         }
710
711                         state = CONTEXT_OPTION_VALUE;
712                         len = 0;
713                         ptr++;
714                         while (*ptr && isspace(*ptr)) ptr++;
715                         continue;
716                 } else if (*ptr == '}') {
717                         if (is_open <= 0) {
718                                 ErrPrint("Invalid state\n");
719                                 return LB_STATUS_ERROR_FAULT;
720                         }
721
722                         name = get_token(ptr, &len);
723                         if (!name) {
724                                 ErrPrint("Failed to get token, len:%d\n", len);
725                                 is_open--;
726                                 len = 0;
727                                 ptr++;
728                                 while (*ptr && isspace(*ptr)) ptr++;
729                                 continue;
730                         }
731
732                         switch (state) {
733                         case CATEGORY:
734                                 category = group_find_category(cluster, name);
735                                 if (!category)
736                                         category = group_create_category(cluster, name);
737
738                                 if (!category) {
739                                         ErrPrint("Failed to get category\n");
740                                         DbgFree(name);
741                                         return LB_STATUS_ERROR_FAULT;
742                                 }
743
744                                 info = group_create_context_info(category, pkgname);
745                                 if (!info) {
746                                         ErrPrint("Failed to create ctx info\n");
747                                         DbgFree(name);
748                                         return LB_STATUS_ERROR_FAULT;
749                                 }
750
751                                 DbgPrint("Keep this syntax only for the compatibility: %s\n", name);
752                                 state = CLUSTER;
753                                 break;
754                         case CONTEXT_ITEM:
755                                 if (is_open == 1) {
756                                         category = group_find_category(cluster, name);
757                                         if (!category)
758                                                 category = group_create_category(cluster, name);
759
760                                         if (!category) {
761                                                 ErrPrint("Failed to get category\n");
762                                                 DbgFree(name);
763                                                 return LB_STATUS_ERROR_FAULT;
764                                         }
765
766                                         info = group_create_context_info(category, pkgname);
767                                         if (!info) {
768                                                 ErrPrint("Failed to create ctx info\n");
769                                                 DbgFree(name);
770                                                 return LB_STATUS_ERROR_FAULT;
771                                         }
772
773                                         DbgPrint("Keep this syntax only for the compatibility: %s\n", name);
774                                         state = CLUSTER;
775                                 } else if (is_open == 2) {
776                                         state = CATEGORY;
777                                 } else {
778                                         ErrPrint("Invalid state\n");
779                                         DbgFree(name);
780                                         return LB_STATUS_ERROR_FAULT;
781                                 }
782                                 break;
783                         case CONTEXT_OPTION_VALUE:
784                                 if (is_open != 2) {
785                                         ErrPrint("Invalid state (%s)\n", name);
786                                         DbgFree(name);
787                                         return LB_STATUS_ERROR_FAULT;
788                                 }
789
790                                 if (group_add_option(item, key, name) < 0)
791                                         ErrPrint("Failed to add a new option: %s - %s\n", key, name);
792
793                                 DbgFree(key);
794                                 key = NULL;
795
796                                 state = CONTEXT_ITEM;
797                                 break;
798                         case CONTEXT_OPTION_KEY:
799                         case CLUSTER:
800                         default:
801                                 ErrPrint("Invalid state (%s)\n", name);
802                                 break;
803                         }
804
805                         DbgFree(name);
806                         is_open--;
807                         len = 0;
808                         ptr++;
809                         while (*ptr && isspace(*ptr)) ptr++;
810                         continue;
811                 }
812
813                 len++;
814                 ptr++;
815         }
816
817         if (state != CLUSTER)
818                 return LB_STATUS_ERROR_INVALID;
819
820         return LB_STATUS_SUCCESS;
821 }
822
823 HAPI int group_del_livebox(const char *pkgname)
824 {
825         Eina_List *l;
826         Eina_List *n;
827         Eina_List *s_l;
828         Eina_List *s_n;
829         Eina_List *i_l;
830         Eina_List *i_n;
831         struct cluster *cluster;
832         struct category *category;
833         struct context_info *info;
834
835         EINA_LIST_FOREACH_SAFE(s_info.cluster_list, l, n, cluster) {
836                 EINA_LIST_FOREACH_SAFE(cluster->category_list, s_l, s_n, category) {
837                         EINA_LIST_FOREACH_SAFE(category->info_list, i_l, i_n, info) {
838                                 if (!strcmp(pkgname, info->pkgname))
839                                         group_destroy_context_info(info);
840                         }
841
842                         if (!category->info_list)
843                                 group_destroy_category(category);
844                 }
845
846                 if (!cluster->category_list)
847                         group_destroy_cluster(cluster);
848         }
849
850         return LB_STATUS_SUCCESS;
851 }
852
853 HAPI int group_init(void)
854 {
855         return LB_STATUS_SUCCESS;
856 }
857
858 HAPI int group_fini(void)
859 {
860         struct cluster *cluster;
861         struct category *category;
862
863         EINA_LIST_FREE(s_info.cluster_list, cluster) {
864
865                 EINA_LIST_FREE(cluster->category_list, category) {
866                         destroy_category(category);
867                 }
868
869                 destroy_cluster(cluster);
870         }
871         return LB_STATUS_SUCCESS;
872 }
873
874 /* End of a file */