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