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