Update SMACK, Fix a crash of terminating sequence, etc, ...
[platform/framework/web/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 is %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                         DbgPrint("[%s:%d] VALUE state EOF\n", __func__, __LINE__);
676                         state = END;
677                 }
678
679                 switch (state) {
680                 case COMMENT:
681                         if (c == CR || c == LF || c == EOF) {
682                                 buffer[buffer_idx] = '\0';
683
684                                 state = START;
685                                 token_idx = -1;
686                                 ch_idx = 0;
687                                 buffer_idx = 0;
688                                 linelen = -1; /* Will be ZERO by follwing increment code */
689                                 quote = 0;
690                         } else {
691                                 buffer[buffer_idx++] = c;
692                                 if (buffer_idx == (sizeof(buffer) - 1)) {
693                                         buffer[buffer_idx] = '\0';
694                                         buffer_idx = 0;
695                                 }
696                         }
697                         break;
698                 case START:
699                         if (linelen == 0 && c == '#') {
700                                 state = COMMENT;
701                         } else if (isspace(c)) {
702                                 /* Ignore empty space */
703                         } else {
704                                 state = TOKEN;
705                                 ungetc(c, fp);
706                         }
707                         break;
708                 case SPACE:
709                         if (c == '=')
710                                 state = VALUE;
711                         else if (!isspace(c))
712                                 state = ERROR;
713                         break;
714                 case VALUE:
715                         if (c == '"') {
716                                 if (quote == 1) {
717                                         buffer[buffer_idx] = '\0';
718                                         state = END;
719                                 } else if (buffer_idx != 0) {
720                                         buffer[buffer_idx++] = c;
721                                         if (buffer_idx >= sizeof(buffer))
722                                                 state = ERROR;
723                                 } else {
724                                         quote = 1;
725                                 }
726                         } else if (isspace(c)) {
727                                 if (buffer_idx == 0) {
728                                         /* Ignore */
729                                 } else if (quote == 1) {
730                                         buffer[buffer_idx++] = c;
731                                         if (buffer_idx >= sizeof(buffer))
732                                                 state = ERROR;
733                                 } else {
734                                         buffer[buffer_idx] = '\0';
735                                         ungetc(c, fp);
736                                         state = END;
737                                 }
738                         } else {
739                                 buffer[buffer_idx++] = c;
740                                 if (buffer_idx >= sizeof(buffer))
741                                         state = ERROR;
742                         }
743                         break;
744                 case TOKEN:
745                         if (c == '=') {
746                                 if (token_idx < 0)
747                                         state = ERROR;
748                                 else
749                                         state = VALUE;
750                         } else if (isspace(c)) {
751                                 if (token_idx < 0)
752                                         break;
753
754                                 if (token_handler[token_idx].name[ch_idx] != '\0')
755                                         state = ERROR;
756                                 else
757                                         state = SPACE;
758                         } else  {
759                                 if (token_idx < 0) {
760                                         /* Now start to find a token! */
761                                         token_idx = 0;
762                                 }
763
764                                 if (token_handler[token_idx].name[ch_idx] == c) {
765                                         ch_idx++;
766                                 } else {
767                                         ungetc(c, fp);
768                                         while (ch_idx-- > 0)
769                                                 ungetc(token_handler[token_idx].name[ch_idx], fp);
770
771                                         token_idx++;
772
773                                         if (token_handler[token_idx].name == NULL)
774                                                 state = ERROR;
775                                         else
776                                                 ch_idx = 0;
777                                 }
778                         }
779                         break;
780                 case ERROR:
781                         if (c == CR || c == LF || c == EOF) {
782                                 state = START;
783                                 token_idx = -1;
784                                 buffer_idx = 0;
785                                 ch_idx = 0;
786                                 linelen = -1;
787                                 quote = 0;
788                         }
789                         break;
790                 case END:
791                         if (c == LF || c == CR || c == EOF) {
792                                 state = START;
793
794                                 /*!
795                                  * \NOTE
796                                  * Make the string terminator
797                                  */
798                                 buffer[buffer_idx] = '\0';
799
800                                 if (token_idx >= 0 && token_handler[token_idx].handler)
801                                         token_handler[token_idx].handler(item, buffer);
802
803                                 token_idx = -1;
804                                 ch_idx = 0;
805                                 buffer_idx = 0;
806                                 linelen = -1;
807                                 quote = 0;
808                                 /* Finish */
809                         } else if (isspace(c)) {
810                                 /* ignore */
811                         } else {
812                                 state = ERROR;
813                         }
814                         break;
815                 default:
816                         /* ?? */
817                         break;
818                 }
819
820                 linelen++;
821          } while (c != EOF);
822
823         if (fclose(fp) != 0)
824                 ErrPrint("fclose: %s\n", strerror(errno));
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 LB_STATUS_SUCCESS;
845 }
846
847 /* End of a file */