a7633bd0bae95ccbf41b1e5887237dc5af9fbe62
[apps/livebox/data-provider-master.git] / src / parser.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 <stdlib.h> /* strtod */
19 #include <errno.h>
20 #include <ctype.h> /* isspace */
21
22 #include <Eina.h>
23 #include <dlog.h>
24
25 #include <livebox-service.h>
26 #include <livebox-errno.h>
27
28 #include "util.h"
29 #include "debug.h"
30 #include "conf.h"
31 #include "parser.h"
32
33 static Eina_List *s_list;
34 int errno;
35
36 #if __x86__64__
37 #define RETURN_TYPE long long
38 #else
39 #define RETURN_TYPE int
40 #endif
41
42 struct parser {
43         char *filename;
44         double period;
45         int timeout;
46         int network;
47         char *auto_launch;
48         unsigned int size;
49         unsigned int pd_width;
50         unsigned int pd_height;
51         char *group;
52         int secured;
53
54         char *pd_path;
55         char *pd_group;
56
57         char *lb_path;
58         char *lb_group;
59         int pinup;
60         int text_pd;
61         int text_lb;
62         int buffer_pd;
63         int buffer_lb;
64
65         char *abi;
66
67         char *script;
68 };
69
70 HAPI double parser_period(struct parser *handle)
71 {
72         return handle->period;
73 }
74
75 HAPI int parser_network(struct parser *handle)
76 {
77         return handle->network;
78 }
79
80 HAPI int parser_timeout(struct parser *handle)
81 {
82         return handle->timeout;
83 }
84
85 HAPI const char *parser_auto_launch(struct parser *handle)
86 {
87         return handle->auto_launch;
88 }
89
90 HAPI const char *parser_script(struct parser *handle)
91 {
92         return handle->script;
93 }
94
95 HAPI const char *parser_abi(struct parser *handle)
96 {
97         return handle->abi;
98 }
99
100 HAPI unsigned int parser_size(struct parser *handle)
101 {
102         return handle->size;
103 }
104
105 HAPI const char *parser_lb_path(struct parser *handle)
106 {
107         return handle->lb_path;
108 }
109
110 HAPI const char *parser_lb_group(struct parser *handle)
111 {
112         return handle->lb_group;
113 }
114
115 HAPI const char *parser_pd_path(struct parser *handle)
116 {
117         return handle->pd_path;
118 }
119
120 HAPI const char *parser_pd_group(struct parser *handle)
121 {
122         return handle->pd_group;
123 }
124
125 HAPI const char *parser_group_str(struct parser *handle)
126 {
127         return handle->group;
128 }
129
130 HAPI int parser_secured(struct parser *handle)
131 {
132         return handle->secured;
133 }
134
135 HAPI void parser_get_pdsize(struct parser *handle, unsigned int *width, unsigned int *height)
136 {
137         *width = handle->pd_width;
138         *height = handle->pd_height;
139 }
140
141 HAPI int parser_pinup(struct parser *handle)
142 {
143         return handle->pinup;
144 }
145
146 HAPI int parser_text_lb(struct parser *handle)
147 {
148         return handle->text_lb;
149 }
150
151 HAPI int parser_text_pd(struct parser *handle)
152 {
153         return handle->text_pd;
154 }
155
156 HAPI int parser_buffer_lb(struct parser *handle)
157 {
158         return handle->buffer_lb;
159 }
160
161 HAPI int parser_buffer_pd(struct parser *handle)
162 {
163         return handle->buffer_pd;
164 }
165
166 HAPI RETURN_TYPE parser_find(const char *pkgname)
167 {
168         Eina_List *l;
169         struct parser *item;
170         char *filename;
171         int len;
172         int ret;
173
174         len = strlen(pkgname) * 2 + strlen(CONF_PATH);
175
176         filename = malloc(len);
177         if (!filename) {
178                 return (RETURN_TYPE)0;
179         }
180
181         ret = snprintf(filename, len, CONF_PATH, pkgname, pkgname);
182         if (ret < 0) {
183                 DbgFree(filename);
184                 return (RETURN_TYPE)0;
185         }
186
187         DbgPrint("Conf file %s for package %s\n", filename, pkgname);
188
189         EINA_LIST_FOREACH(s_list, l, item) {
190                 if (!strcmp(item->filename, filename)) {
191                         DbgFree(filename);
192                         return (RETURN_TYPE)item;
193                 }
194         }
195
196         DbgFree(filename);
197         return (RETURN_TYPE)0;
198 }
199
200 static inline int parse_size(const char *buffer, unsigned int *size)
201 {
202         register int i;
203         int w;
204         int h;
205
206         enum {
207                 START,
208                 WIDTH,
209                 DELIM,
210                 HEIGHT,
211                 ERROR,
212                 STOP,
213                 END
214         } state;
215
216         *size = 0;
217         state = START;
218         i = 0;
219         w = 0;
220         h = 0;
221
222         while (state != ERROR && state != END) {
223                 switch (state) {
224                 case START:
225                         switch (buffer[i]) {
226                         case '1'...'9':
227                                 state = WIDTH;
228                                 break;
229                         case ' ':
230                         case '\t':
231                         case ';':
232                                 i++;
233                                 break;
234                         case '\0':
235                                 state = END;
236                                 break;
237                         default:
238                                 state = ERROR;
239                                 break;
240                         }
241                         break;
242                 case WIDTH:
243                         switch (buffer[i]) {
244                         case '0'...'9':
245                                 w = (w * 10) + (buffer[i] - '0');
246                                 i++;
247                                 break;
248                         case 'x':
249                                 state = DELIM;
250                                 i++;
251                                 break;
252                         default:
253                                 state = ERROR;
254                                 break;
255                         }
256
257                         break;
258                 case DELIM:
259                         switch (buffer[i]) {
260                         case '1'...'9':
261                                 state = HEIGHT;
262                                 break;
263                         case ' ':
264                         case '\t':
265                                 i++;
266                                 break;
267                         default:
268                                 state = ERROR;
269                                 break;
270                         }
271                         break;
272                 case HEIGHT:
273                         switch (buffer[i]) {
274                         case '0'...'9':
275                                 h = (h * 10) + (buffer[i] - '0');
276                                 i++;
277                                 break;
278                         case ';':
279                         case '\0':
280                                 state = STOP;
281                                 break;
282                         default:
283                                 state = ERROR;
284                                 break;
285                         }
286                         break;
287                 case STOP:
288                         if (w == 1 && h == 1) {
289                                 *size |= LB_SIZE_TYPE_1x1;
290                         } else if (w == 2 && h == 1) {
291                                 *size |= LB_SIZE_TYPE_2x1;
292                         } else if (w == 2 && h == 2) {
293                                 *size |= LB_SIZE_TYPE_2x2;
294                         } else if (w == 4 && h == 1) {
295                                 *size |= LB_SIZE_TYPE_4x1;
296                         } else if (w == 4 && h == 2) {
297                                 *size |= LB_SIZE_TYPE_4x2;
298                         } else if (w == 4 && h == 3) {
299                                 *size |= LB_SIZE_TYPE_4x3;
300                         } else if (w == 4 && h == 4) {
301                                 *size |= LB_SIZE_TYPE_4x4;
302                         } else if (w == 21 && h == 21) {
303                                 *size |= LB_SIZE_TYPE_EASY_1x1;
304                         } else if (w == 23 && h == 21) {
305                                 *size |= LB_SIZE_TYPE_EASY_3x1;
306                         } else if (w == 23 && h == 23) {
307                                 *size |= LB_SIZE_TYPE_EASY_3x3;
308                         } else {
309                                 ErrPrint("Invalid size type: %dx%d\n", w, h);
310                         }
311
312                         if (buffer[i] == ';') {
313                                 state = START;
314                         } else if (buffer[i] == '\0') {
315                                 state = END;
316                         }
317
318                         w = 0;
319                         h = 0;
320                         break;
321                 default:
322                         return -1;
323                 }
324         }
325
326         return *size ? 0 : -1;
327 }
328
329 /*!
330  * \note
331  * This will change the value of "buffer"
332  */
333 static inline const char *rtrim(char *buffer)
334 {
335         int len;
336
337         len = strlen(buffer);
338         while (len > 0 && isspace(buffer[len - 1])) {
339                 len--;
340         }
341
342         if (len <= 0) {
343                 return NULL;
344         }
345
346         buffer[len] = '\0';
347
348         return buffer;
349 }
350
351 /*!
352  * \note
353  * This will change the value of "buffer"
354  */
355 static inline char *dup_rtrim(char *buffer)
356 {
357         char *ret;
358
359         if (!rtrim(buffer)) {
360                 return NULL;
361         }
362
363         ret = strdup(buffer);
364         if (!ret) {
365                 ErrPrint("Heap: %s\n", strerror(errno));
366                 return NULL;
367         }
368
369         return ret;
370 }
371
372 static void period_handler(struct parser *item, char *buffer)
373 {
374         char *tmp = NULL;
375
376         if (!rtrim(buffer)) {
377                 return;
378         }
379
380         item->period = strtod(buffer, &tmp);
381 }
382
383 static void timeout_handler(struct parser *item, char *buffer)
384 {
385         if (!rtrim(buffer)) {
386                 return;
387         }
388
389         item->timeout = atoi(buffer);
390 }
391
392 static void network_handler(struct parser *item, char *buffer)
393 {
394         if (!rtrim(buffer)) {
395                 return;
396         }
397
398         item->network = !!atoi(buffer);
399 }
400
401 static void auto_launch_handler(struct parser *item, char *buffer)
402 {
403         if (!rtrim(buffer)) {
404                 return;
405         }
406
407         item->auto_launch = strdup(buffer);
408         if (!item->auto_launch) {
409                 ErrPrint("Heap: %s\n", strerror(errno));
410                 return;
411         }
412 }
413
414 static void size_handler(struct parser *item, char *buffer)
415 {
416         if (parse_size(buffer, &item->size) == -1) {
417                 ErrPrint("Failed to get size\n");
418                 item->size = 0x00000001;
419         }
420 }
421
422 static void pd_size_handler(struct parser *item, char *buffer)
423 {
424         if (sscanf(buffer, "%ux%u", &item->pd_width, &item->pd_height) != 2) {
425                 ErrPrint("parse pd size\n");
426         }
427 }
428
429 static void text_lb_handler(struct parser *item, char *buffer)
430 {
431         if (!rtrim(buffer)) {
432                 return;
433         }
434
435         item->text_lb = !!atoi(buffer);
436 }
437
438 static void abi_handler(struct parser *item, char *buffer)
439 {
440         item->abi = dup_rtrim(buffer);
441 }
442
443 static void script_handler(struct parser *item, char *buffer)
444 {
445         item->script = dup_rtrim(buffer);
446 }
447
448 static void buffer_pd_handler(struct parser *item, char *buffer)
449 {
450         if (!rtrim(buffer)) {
451                 return;
452         }
453
454         item->buffer_pd = !!atoi(buffer);
455 }
456
457 static void buffer_lb_handler(struct parser *item, char *buffer)
458 {
459         if (!rtrim(buffer)) {
460                 return;
461         }
462
463         item->buffer_lb = !!atoi(buffer);
464 }
465
466 static void text_pd_handler(struct parser *item, char *buffer)
467 {
468         if (!rtrim(buffer)) {
469                 return;
470         }
471
472         item->text_pd = !!atoi(buffer);
473 }
474
475 static void pinup_handler(struct parser *item, char *buffer)
476 {
477         if (!rtrim(buffer)) {
478                 return;
479         }
480
481         item->pinup = !!atoi(buffer);
482 }
483
484 static void lb_path_handler(struct parser *item, char *buffer)
485 {
486         if (item->lb_path) {
487                 DbgFree(item->lb_path);
488         }
489
490         item->lb_path = dup_rtrim(buffer);
491         if (!item->lb_path) {
492                 ErrPrint("Error: %s\n", strerror(errno));
493         }
494 }
495
496 static void group_handler(struct parser *item, char *buffer)
497 {
498         if (item->group) {
499                 DbgFree(item->group);
500         }
501
502         item->group = dup_rtrim(buffer);
503         if (!item->group) {
504                 ErrPrint("Error: %s\n", strerror(errno));
505         }
506 }
507
508 static void secured_handler(struct parser *item, char *buffer)
509 {
510         if (!rtrim(buffer)) {
511                 return;
512         }
513
514         item->secured = !!atoi(buffer);
515 }
516
517 static void lb_group_handler(struct parser *item, char *buffer)
518 {
519         if (item->lb_group) {
520                 DbgFree(item->lb_group);
521         }
522
523         item->lb_group = dup_rtrim(buffer);
524         if (!item->lb_group) {
525                 ErrPrint("Error: %s\n", strerror(errno));
526         }
527 }
528
529 static void pd_path_handler(struct parser *item, char *buffer)
530 {
531         if (item->pd_path) {
532                 DbgFree(item->pd_path);
533         }
534
535         item->pd_path = dup_rtrim(buffer);
536         if (!item->pd_path) {
537                 ErrPrint("Error: %s\n", strerror(errno));
538         }
539 }
540
541 static void pd_group_handler(struct parser *item, char *buffer)
542 {
543         if (item->pd_group) {
544                 DbgFree(item->pd_group);
545         }
546
547         item->pd_group = dup_rtrim(buffer);
548         if (!item->pd_group) {
549                 ErrPrint("Error: %s\n", strerror(errno));
550         }
551 }
552
553 HAPI struct parser *parser_load(const char *pkgname)
554 {
555         struct parser *item;
556         FILE *fp;
557         int c;
558         enum state {
559                 START,
560                 SPACE,
561                 TOKEN,
562                 VALUE,
563                 ERROR,
564                 COMMENT,
565                 END
566         } state;
567         int ch_idx;
568         int token_idx;
569         int buffer_idx;
570         int quote;
571         int len;
572         int linelen;
573         char buffer[256];
574         static const struct token_parser {
575                 const char *name;
576                 void (*handler)(struct parser *, char *buffer);
577         } token_handler[] = {
578                 {
579                         .name = "period",
580                         .handler = period_handler,
581                 },
582                 {
583                         .name = "timeout",
584                         .handler = timeout_handler,
585                 },
586                 {
587                         .name = "network",
588                         .handler = network_handler,
589                 },
590                 {
591                         .name = "auto_launch",
592                         .handler = auto_launch_handler,
593                 },
594                 {
595                         .name = "size",
596                         .handler = size_handler,
597                 },
598                 {
599                         .name = "group",
600                         .handler = group_handler,
601                 },
602                 {
603                         .name = "secured",
604                         .handler = secured_handler,
605                 },
606                 {
607                         .name = "livebox_path",
608                         .handler = lb_path_handler,
609                 },
610                 {
611                         .name = "livebox_group",
612                         .handler = lb_group_handler,
613                 },
614                 {
615                         .name = "pd_path",
616                         .handler = pd_path_handler,
617                 },
618                 {
619                         .name = "pd_group",
620                         .handler = pd_group_handler,
621                 },
622                 {
623                         .name = "pd_size",
624                         .handler = pd_size_handler,
625                 },
626                 {
627                         .name = "pinup",
628                         .handler = pinup_handler,
629                 },
630                 {
631                         .name = "text_livebox",
632                         .handler = text_lb_handler,
633                 },
634                 {
635                         .name = "text_pd",
636                         .handler = text_pd_handler,
637                 },
638                 {
639                         .name = "buffer_livebox",
640                         .handler = buffer_lb_handler,
641                 },
642                 {
643                         .name = "buffer_pd",
644                         .handler = buffer_pd_handler,
645                 },
646                 {
647                         .name = "script",
648                         .handler = script_handler,
649                 },
650                 {
651                         .name = "abi",
652                         .handler = abi_handler,
653                 },
654                 {
655                         .name = NULL,
656                         .handler = NULL,
657                 },
658         };
659         int ret;
660
661         item = calloc(1, sizeof(*item));
662         if (!item) {
663                 return 0;
664         }
665
666         /* live-, .conf */
667         len = strlen(CONF_PATH) + strlen(pkgname) * 2;
668         item->filename = malloc(len);
669         if (!item->filename) {
670                 ErrPrint("Error: %s\n", strerror(errno));
671                 DbgFree(item);
672                 return 0;
673         }
674
675         ret = snprintf(item->filename, len, CONF_PATH, pkgname, pkgname);
676         if (ret < 0) {
677                 ErrPrint("Error: %s\n", strerror(errno));
678                 DbgFree(item->filename);
679                 DbgFree(item);
680                 return 0;
681         }
682
683         item->lb_path = NULL;
684         item->lb_group = NULL;
685         item->pd_width = 0;
686         item->pd_height = 0;
687         item->auto_launch = NULL;
688         item->size = 0x00000001;
689         item->group = NULL;
690         item->secured = 0;
691         item->pinup = 0;
692
693         fp = fopen(item->filename, "rt");
694         if (!fp) {
695                 DbgFree(item->filename);
696                 DbgFree(item);
697                 return 0;
698         }
699
700         state = START;
701         ch_idx = 0;
702         token_idx = -1;
703         buffer_idx = 0;
704         quote = 0;
705         linelen = 0;
706         do {
707                 c = getc(fp);
708                 if ((c == EOF) && (state == VALUE)) {
709                         state = END;
710                 }
711
712                 switch (state) {
713                 case COMMENT:
714                         if (c == CR || c == LF || c == EOF) {
715                                 buffer[buffer_idx] = '\0';
716
717                                 state = START;
718                                 token_idx = -1;
719                                 ch_idx = 0;
720                                 buffer_idx = 0;
721                                 linelen = -1; /* Will be ZERO by follwing increment code */
722                                 quote = 0;
723                         } else {
724                                 buffer[buffer_idx++] = c;
725                                 if (buffer_idx == (sizeof(buffer) - 1)) {
726                                         buffer[buffer_idx] = '\0';
727                                         buffer_idx = 0;
728                                 }
729                         }
730                         break;
731                 case START:
732                         if (linelen == 0 && c == '#') {
733                                 state = COMMENT;
734                         } else if (isspace(c)) {
735                                 /* Ignore empty space */
736                         } else {
737                                 state = TOKEN;
738                                 ungetc(c, fp);
739                         }
740                         break;
741                 case SPACE:
742                         if (c == '=') {
743                                 state = VALUE;
744                         } else if (!isspace(c)) {
745                                 state = ERROR;
746                         }
747                         break;
748                 case VALUE:
749                         if (c == '"') {
750                                 if (quote == 1) {
751                                         buffer[buffer_idx] = '\0';
752                                         state = END;
753                                 } else if (buffer_idx != 0) {
754                                         buffer[buffer_idx++] = c;
755                                         if (buffer_idx >= sizeof(buffer)) {
756                                                 state = ERROR;
757                                         }
758                                 } else {
759                                         quote = 1;
760                                 }
761                         } else if (isspace(c)) {
762                                 if (buffer_idx == 0) {
763                                         /* Ignore */
764                                 } else if (quote == 1) {
765                                         buffer[buffer_idx++] = c;
766                                         if (buffer_idx >= sizeof(buffer)) {
767                                                 state = ERROR;
768                                         }
769                                 } else {
770                                         buffer[buffer_idx] = '\0';
771                                         ungetc(c, fp);
772                                         state = END;
773                                 }
774                         } else {
775                                 buffer[buffer_idx++] = c;
776                                 if (buffer_idx >= sizeof(buffer)) {
777                                         state = ERROR;
778                                 }
779                         }
780                         break;
781                 case TOKEN:
782                         if (c == '=') {
783                                 if (token_idx < 0) {
784                                         state = ERROR;
785                                 } else {
786                                         state = VALUE;
787                                 }
788                         } else if (isspace(c)) {
789                                 if (token_idx < 0) {
790                                         break;
791                                 }
792
793                                 if (token_handler[token_idx].name[ch_idx] != '\0') {
794                                         state = ERROR;
795                                 } else {
796                                         state = SPACE;
797                                 }
798                         } else  {
799                                 if (token_idx < 0) {
800                                         /* Now start to find a token! */
801                                         token_idx = 0;
802                                 }
803
804                                 if (token_handler[token_idx].name[ch_idx] == c) {
805                                         ch_idx++;
806                                 } else {
807                                         ungetc(c, fp);
808                                         while (ch_idx-- > 0) {
809                                                 ungetc(token_handler[token_idx].name[ch_idx], fp);
810                                         }
811
812                                         token_idx++;
813
814                                         if (token_handler[token_idx].name == NULL) {
815                                                 state = ERROR;
816                                         } else {
817                                                 ch_idx = 0;
818                                         }
819                                 }
820                         }
821                         break;
822                 case ERROR:
823                         if (c == CR || c == LF || c == EOF) {
824                                 state = START;
825                                 token_idx = -1;
826                                 buffer_idx = 0;
827                                 ch_idx = 0;
828                                 linelen = -1;
829                                 quote = 0;
830                         }
831                         break;
832                 case END:
833                         if (c == LF || c == CR || c == EOF) {
834                                 state = START;
835
836                                 /*!
837                                  * \NOTE
838                                  * Make the string terminator
839                                  */
840                                 buffer[buffer_idx] = '\0';
841
842                                 if (token_idx >= 0 && token_handler[token_idx].handler) {
843                                         token_handler[token_idx].handler(item, buffer);
844                                 }
845
846                                 token_idx = -1;
847                                 ch_idx = 0;
848                                 buffer_idx = 0;
849                                 linelen = -1;
850                                 quote = 0;
851                                 /* Finish */
852                         } else if (isspace(c)) {
853                                 /* ignore */
854                         } else {
855                                 state = ERROR;
856                         }
857                         break;
858                 default:
859                         /* ?? */
860                         break;
861                 }
862
863                 linelen++;
864          } while (c != EOF);
865
866         if (fclose(fp) != 0) {
867                 ErrPrint("fclose: %s\n", strerror(errno));
868         }
869
870         s_list = eina_list_append(s_list, item);
871         return item;
872 }
873
874 HAPI int parser_unload(struct parser *item)
875 {
876         s_list = eina_list_remove(s_list, item);
877
878         DbgFree(item->auto_launch);
879         DbgFree(item->abi);
880         DbgFree(item->script);
881         DbgFree(item->group);
882         DbgFree(item->pd_group);
883         DbgFree(item->pd_path);
884         DbgFree(item->lb_group);
885         DbgFree(item->lb_path);
886         DbgFree(item->filename);
887         DbgFree(item);
888         return LB_STATUS_SUCCESS;
889 }
890
891 /* End of a file */