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