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