ff03488f0284249ff58b4bb5d4c35f89ae782e6c
[apps/livebox/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         s_info.cluster_list = eina_list_append(s_info.cluster_list, cluster);
209         return cluster;
210 }
211
212 HAPI struct cluster *group_find_cluster(const char *name)
213 {
214         Eina_List *l;
215         struct cluster *cluster;
216
217         EINA_LIST_FOREACH(s_info.cluster_list, l, cluster) {
218                 if (!strcasecmp(cluster->name, name)) {
219                         return cluster;
220                 }
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         cluster->category_list = eina_list_append(cluster->category_list, category);
247         return category;
248 }
249
250 static inline void destroy_cluster(struct cluster *cluster)
251 {
252         struct category *category;
253         Eina_List *l;
254         Eina_List *n;
255
256         EINA_LIST_FOREACH_SAFE(cluster->category_list, l, n, category) {
257                 group_destroy_category(category);
258         }
259
260         DbgFree(cluster->name);
261         DbgFree(cluster);
262 }
263
264 HAPI int group_destroy_cluster(struct cluster *cluster)
265 {
266         Eina_List *l;
267         Eina_List *n;
268         struct cluster *item;
269
270         EINA_LIST_FOREACH_SAFE(s_info.cluster_list, l, n, item) {
271                 if (item == cluster) {
272                         s_info.cluster_list = eina_list_remove_list(s_info.cluster_list, l);
273                         destroy_cluster(cluster);
274                         return LB_STATUS_SUCCESS;
275                 }
276         }
277
278         return LB_STATUS_ERROR_NOT_EXIST;
279 }
280
281 static inline void destroy_category(struct category *category)
282 {
283         Eina_List *l;
284         Eina_List *n;
285         struct context_info *info;
286
287         EINA_LIST_FOREACH_SAFE(category->info_list, l, n, info) {
288                 group_destroy_context_info(info);
289         }
290
291         DbgFree(category->name);
292         DbgFree(category);
293 }
294
295 HAPI int group_destroy_category(struct category *category)
296 {
297         struct cluster *cluster;
298
299         cluster = category->cluster;
300         if (cluster) {
301                 cluster->category_list = eina_list_remove(cluster->category_list, category);
302         }
303
304         destroy_category(category);
305         return LB_STATUS_SUCCESS;
306 }
307
308 HAPI struct category *group_find_category(struct cluster *cluster, const char *name)
309 {
310         struct category *category;
311         Eina_List *l;
312
313         EINA_LIST_FOREACH(cluster->category_list, l, category) {
314                 if (!strcasecmp(category->name, name)) {
315                         return category;
316                 }
317         }
318
319         return NULL;
320 }
321
322 HAPI Eina_List * const group_context_info_list(struct category *category)
323 {
324         return category->info_list;
325 }
326
327 HAPI Eina_List *const group_context_item_list(struct context_info *info)
328 {
329         return info->context_list;
330 }
331
332 HAPI Eina_List *const group_context_option_list(struct context_item *item)
333 {
334         return item->option_list;
335 }
336
337 HAPI Eina_List *const group_cluster_list(void)
338 {
339         return s_info.cluster_list;
340 }
341
342 HAPI Eina_List * const group_category_list(struct cluster *cluster)
343 {
344         return cluster->category_list;
345 }
346
347 HAPI struct context_info * const group_context_info_from_item(struct context_item *item)
348 {
349         return item->info;
350 }
351
352 HAPI struct category * const group_category_from_context_info(struct context_info *info)
353 {
354         return info->category;
355 }
356
357 HAPI const char * const group_pkgname_from_context_info(struct context_info *info)
358 {
359         return info->pkgname;
360 }
361
362 HAPI const char * const group_option_item_key(struct context_option *option)
363 {
364         return option->key;
365 }
366
367 HAPI const char * const group_option_item_value(struct context_option *option)
368 {
369         return option->value;
370 }
371
372 HAPI const char * const group_context_item(struct context_item *item)
373 {
374         return item->ctx_item;
375 }
376
377 HAPI int group_context_item_add_data(struct context_item *item, const char *tag, void *data)
378 {
379         struct context_item_data *tmp;
380
381         tmp = malloc(sizeof(*tmp));
382         if (!tmp) {
383                 return LB_STATUS_ERROR_MEMORY;
384         }
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
408         return NULL;
409 }
410
411 HAPI void *group_context_item_del_data(struct context_item *item, const char *tag)
412 {
413         struct context_item_data *tmp;
414         Eina_List *l;
415         Eina_List *n;
416
417         EINA_LIST_FOREACH_SAFE(item->data_list, l, n, tmp) {
418                 if (!strcmp(tmp->tag, tag)) {
419                         void *data;
420
421                         item->data_list = eina_list_remove(item->data_list, tmp);
422
423                         data = tmp->data;
424
425                         DbgFree(tmp->tag);
426                         DbgFree(tmp);
427
428                         return data;
429                 }
430         }
431
432         return NULL;
433 }
434
435 HAPI const char * const group_category_name(struct category *category)
436 {
437         return category ? category->name : NULL;
438 }
439
440 HAPI const char * const group_cluster_name(struct cluster *cluster)
441 {
442         return cluster ? cluster->name : NULL;
443 }
444
445 HAPI const char *group_cluster_name_by_category(struct category *category)
446 {
447         return !category ? NULL : (category->cluster ? category->cluster->name : NULL);
448 }
449
450 static inline char *get_token(char *ptr, int *len)
451 {
452         char *name;
453         int _len;
454
455         if (*len == 0) {
456                 ErrPrint("Start brace but len = 0\n");
457                 return NULL;
458         }
459
460         _len = *len;
461
462         while (_len > 0 && isspace(ptr[_len])) {
463                 _len--;
464         }
465
466         if (_len == 0) {
467                 ErrPrint("Token has no string\n");
468                 return NULL;
469         }
470
471         name = malloc(_len + 1);
472         if (!name) {
473                 ErrPrint("Heap: %s\n", strerror(errno));
474                 return NULL;
475         }
476
477         strncpy(name, ptr - *len, _len);
478         name[_len] = '\0';
479
480         *len = _len;
481         return name;
482 }
483
484 HAPI int group_add_livebox(const char *group, const char *pkgname)
485 {
486         struct cluster *cluster;
487         struct category *category;
488         struct context_info *info = NULL;
489         struct context_item *item = NULL;
490         char *key;
491         char *name;
492         char *ptr;
493         int len;
494         int is_open = 0;
495         enum {
496                 CLUSTER,
497                 CATEGORY,
498                 CONTEXT_ITEM,
499                 CONTEXT_OPTION_KEY,
500                 CONTEXT_OPTION_VALUE,
501                 CONTEXT_ERROR = 0xFFFFFFFF
502         } state;
503
504         state = CLUSTER;
505
506         ptr = (char *)group;
507         len = 0;
508         key = NULL;
509
510         /* Skip the first space characters */
511         while (*ptr && isspace(*ptr)) ptr++;
512
513         cluster = NULL;
514         while (*ptr) {
515                 if (*ptr == '{') {
516                         name = get_token(ptr, &len);
517                         if (!name) {
518                                 ErrPrint("Failed to get token\n");
519                                 return LB_STATUS_ERROR_FAULT;
520                         }
521                         /* cluster{category{context{key=value,key=value},context{key=value}}} */
522                         /* cluster{category} */
523
524                         switch (state) {
525                         case CLUSTER:
526                                 cluster = group_find_cluster(name);
527                                 if (!cluster) {
528                                         cluster = group_create_cluster(name);
529                                 }
530
531                                 if (!cluster) {
532                                         ErrPrint("Failed to get cluster\n");
533                                         DbgFree(name);
534                                         return LB_STATUS_ERROR_FAULT;
535                                 }
536
537                                 state = CATEGORY;
538                                 break;
539
540                         case CATEGORY:
541                                 category = group_find_category(cluster, name);
542                                 if (!category) {
543                                         category = group_create_category(cluster, name);
544                                 }
545
546                                 if (!category) {
547                                         ErrPrint("Failed to get category\n");
548                                         DbgFree(name);
549                                         return LB_STATUS_ERROR_FAULT;
550                                 }
551
552                                 info = group_create_context_info(category, pkgname);
553                                 if (!info) {
554                                         ErrPrint("Failed to create ctx info\n");
555                                         DbgFree(name);
556                                         return LB_STATUS_ERROR_FAULT;
557                                 }
558
559                                 state = CONTEXT_ITEM;
560                                 break;
561
562                         case CONTEXT_ITEM:
563                                 item = group_add_context_item(info, name);
564                                 if (!item) {
565                                         ErrPrint("Failed to create a context item\n");
566                                         DbgFree(name);
567                                         return LB_STATUS_ERROR_FAULT;
568                                 }
569
570                                 state = CONTEXT_OPTION_KEY;
571                                 break;
572
573                         case CONTEXT_OPTION_KEY:
574                         case CONTEXT_OPTION_VALUE:
575                         default:
576                                 ErrPrint("Invalid state\n");
577                                 DbgFree(name);
578                                 return LB_STATUS_ERROR_FAULT;
579                         }
580
581                         DbgFree(name);
582                         is_open++;
583                         len = 0;
584                         ptr++;
585                         while (*ptr && isspace(*ptr)) ptr++;
586                         continue;
587                 } else if (*ptr == ',') {
588                         name = get_token(ptr, &len);
589                         if (!name) {
590                                 ErrPrint("Failed to get token (len:%d)\n", len);
591                                 len = 0;
592                                 ptr++;
593                                 while (*ptr && isspace(*ptr)) ptr++;
594                                 continue;
595                         }
596
597                         switch (state) {
598                         case CLUSTER:
599                                 if (is_open != 0) {
600                                         ErrPrint("Invalid state\n");
601                                         DbgFree(name);
602                                         return LB_STATUS_ERROR_FAULT;
603                                 }
604                                 cluster = group_find_cluster(name);
605                                 if (!cluster) {
606                                         cluster = group_create_cluster(name);
607                                 }
608
609                                 if (!cluster) {
610                                         ErrPrint("Failed to get cluster\n");
611                                         DbgFree(name);
612                                         return LB_STATUS_ERROR_FAULT;
613                                 }
614
615                                 state = CATEGORY;
616                                 break;
617
618                         case CATEGORY:
619                                 if (is_open != 1) {
620                                         ErrPrint("Invalid state\n");
621                                         DbgFree(name);
622                                         return LB_STATUS_ERROR_FAULT;
623                                 }
624                                 category = group_find_category(cluster, name);
625                                 if (!category) {
626                                         category = group_create_category(cluster, name);
627                                 }
628
629                                 if (!category) {
630                                         ErrPrint("Failed to get category\n");
631                                         DbgFree(name);
632                                         return LB_STATUS_ERROR_FAULT;
633                                 }
634
635                                 info = group_create_context_info(category, pkgname);
636                                 if (!info) {
637                                         ErrPrint("Failed to create ctx info\n");
638                                         DbgFree(name);
639                                         return LB_STATUS_ERROR_FAULT;
640                                 }
641
642                                 state = CONTEXT_ITEM;
643                                 break;
644                         case CONTEXT_ITEM:
645                                 if (is_open == 1) {
646                                         category = group_find_category(cluster, name);
647                                         if (!category) {
648                                                 category = group_create_category(cluster, name);
649                                         }
650
651                                         if (!category) {
652                                                 ErrPrint("Failed to get category\n");
653                                                 DbgFree(name);
654                                                 return LB_STATUS_ERROR_FAULT;
655                                         }
656
657                                         info = group_create_context_info(category, pkgname);
658                                         if (!info) {
659                                                 ErrPrint("Failed to create ctx info\n");
660                                                 DbgFree(name);
661                                                 return LB_STATUS_ERROR_FAULT;
662                                         }
663                                 } else if (is_open == 2) {
664                                         item = group_add_context_item(info, name);
665                                         if (!item) {
666                                                 ErrPrint("Failed to create a context item\n");
667                                                 DbgFree(name);
668                                                 return LB_STATUS_ERROR_FAULT;
669                                         }
670                                         state = CONTEXT_OPTION_KEY;
671                                 } else {
672                                         ErrPrint("Invalid state\n");
673                                         DbgFree(name);
674                                         return LB_STATUS_ERROR_FAULT;
675                                 }
676
677                                 break;
678                         case CONTEXT_OPTION_VALUE:
679                                 if (is_open != 3) {
680                                         ErrPrint("Invalid state\n");
681                                         DbgFree(name);
682                                         return LB_STATUS_ERROR_FAULT;
683                                 }
684
685                                 if (group_add_option(item, key, name) < 0) {
686                                         ErrPrint("Failed to add a new option: %s - %s\n", key, name);
687                                 }
688
689                                 DbgFree(key);
690                                 key = NULL;
691
692                                 state = CONTEXT_OPTION_KEY;
693                                 break;
694                         case CONTEXT_OPTION_KEY:
695                         default:
696                                 ErrPrint("Invalid state (%s)\n", name);
697                                 DbgFree(name);
698                                 return LB_STATUS_ERROR_FAULT;
699                         }
700
701                         DbgFree(name);
702                         len = 0;
703                         ptr++;
704                         while (*ptr && isspace(*ptr)) ptr++;
705                         continue;
706                 } else if (*ptr == '=') {
707                         if (is_open != 3 || state != CONTEXT_OPTION_KEY) {
708                                 ErrPrint("Invalid state\n");
709                                 return LB_STATUS_ERROR_FAULT;
710                         }
711
712                         key = get_token(ptr, &len);
713                         if (!key) {
714                                 ErrPrint("Failed to get token\n");
715                                 return LB_STATUS_ERROR_FAULT;
716                         }
717
718                         state = CONTEXT_OPTION_VALUE;
719                         len = 0;
720                         ptr++;
721                         while (*ptr && isspace(*ptr)) ptr++;
722                         continue;
723                 } else if (*ptr == '}') {
724                         if (is_open <= 0) {
725                                 ErrPrint("Invalid state\n");
726                                 return LB_STATUS_ERROR_FAULT;
727                         }
728
729                         name = get_token(ptr, &len);
730                         if (!name) {
731                                 ErrPrint("Failed to get token, len:%d\n", len);
732                                 is_open--;
733                                 len = 0;
734                                 ptr++;
735                                 while (*ptr && isspace(*ptr)) ptr++;
736                                 continue;
737                         }
738
739                         switch (state) {
740                         case CATEGORY:
741                                 category = group_find_category(cluster, name);
742                                 if (!category) {
743                                         category = group_create_category(cluster, name);
744                                 }
745
746                                 if (!category) {
747                                         ErrPrint("Failed to get category\n");
748                                         DbgFree(name);
749                                         return LB_STATUS_ERROR_FAULT;
750                                 }
751
752                                 info = group_create_context_info(category, pkgname);
753                                 if (!info) {
754                                         ErrPrint("Failed to create ctx info\n");
755                                         DbgFree(name);
756                                         return LB_STATUS_ERROR_FAULT;
757                                 }
758
759                                 state = CLUSTER;
760                                 break;
761                         case CONTEXT_ITEM:
762                                 if (is_open == 1) {
763                                         category = group_find_category(cluster, name);
764                                         if (!category) {
765                                                 category = group_create_category(cluster, name);
766                                         }
767
768                                         if (!category) {
769                                                 ErrPrint("Failed to get category\n");
770                                                 DbgFree(name);
771                                                 return LB_STATUS_ERROR_FAULT;
772                                         }
773
774                                         info = group_create_context_info(category, pkgname);
775                                         if (!info) {
776                                                 ErrPrint("Failed to create ctx info\n");
777                                                 DbgFree(name);
778                                                 return LB_STATUS_ERROR_FAULT;
779                                         }
780
781                                         state = CLUSTER;
782                                 } else if (is_open == 2) {
783                                         state = CATEGORY;
784                                 } else {
785                                         ErrPrint("Invalid state\n");
786                                         DbgFree(name);
787                                         return LB_STATUS_ERROR_FAULT;
788                                 }
789                                 break;
790                         case CONTEXT_OPTION_VALUE:
791                                 if (is_open != 2) {
792                                         ErrPrint("Invalid state (%s)\n", name);
793                                         DbgFree(name);
794                                         return LB_STATUS_ERROR_FAULT;
795                                 }
796
797                                 if (group_add_option(item, key, name) < 0) {
798                                         ErrPrint("Failed to add a new option: %s - %s\n", key, name);
799                                 }
800
801                                 DbgFree(key);
802                                 key = NULL;
803
804                                 state = CONTEXT_ITEM;
805                                 break;
806                         case CONTEXT_OPTION_KEY:
807                         case CLUSTER:
808                         default:
809                                 ErrPrint("Invalid state (%s)\n", name);
810                                 break;
811                         }
812
813                         DbgFree(name);
814                         is_open--;
815                         len = 0;
816                         ptr++;
817                         while (*ptr && isspace(*ptr)) ptr++;
818                         continue;
819                 }
820
821                 len++;
822                 ptr++;
823         }
824
825         /* If some cases, the key is not released, try release it, doesn't need to check NULL */
826         DbgFree(key);
827
828         if (state != CLUSTER) {
829                 return LB_STATUS_ERROR_INVALID;
830         }
831
832         return LB_STATUS_SUCCESS;
833 }
834
835 HAPI int group_del_livebox(const char *pkgname)
836 {
837         Eina_List *l;
838         Eina_List *n;
839         Eina_List *s_l;
840         Eina_List *s_n;
841         Eina_List *i_l;
842         Eina_List *i_n;
843         struct cluster *cluster;
844         struct category *category;
845         struct context_info *info;
846
847         EINA_LIST_FOREACH_SAFE(s_info.cluster_list, l, n, cluster) {
848                 EINA_LIST_FOREACH_SAFE(cluster->category_list, s_l, s_n, category) {
849                         EINA_LIST_FOREACH_SAFE(category->info_list, i_l, i_n, info) {
850                                 if (!strcmp(pkgname, info->pkgname)) {
851                                         group_destroy_context_info(info);
852                                 }
853                         }
854
855                         if (!category->info_list) {
856                                 group_destroy_category(category);
857                         }
858                 }
859
860                 if (!cluster->category_list) {
861                         group_destroy_cluster(cluster);
862                 }
863         }
864
865         return LB_STATUS_SUCCESS;
866 }
867
868 HAPI int group_init(void)
869 {
870         return LB_STATUS_SUCCESS;
871 }
872
873 HAPI int group_fini(void)
874 {
875         struct cluster *cluster;
876         struct category *category;
877
878         EINA_LIST_FREE(s_info.cluster_list, cluster) {
879
880                 EINA_LIST_FREE(cluster->category_list, category) {
881                         destroy_category(category);
882                 }
883
884                 destroy_cluster(cluster);
885         }
886         return LB_STATUS_SUCCESS;
887 }
888
889 /* End of a file */