1c6ab9463643ea51d6f1dade8aac2b8a0057f250
[platform/framework/web/data-provider-master.git] / src / script_handler.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 <errno.h>
19 #include <stdlib.h> /* free */
20 #include <ctype.h>
21 #include <dlfcn.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29
30 #include <Ecore.h>
31 #include <Eina.h>
32
33 #include <dlog.h>
34 #include <packet.h>
35 #include <livebox-errno.h>
36
37 #include "slave_life.h"
38 #include "slave_rpc.h"
39 #include "client_life.h"
40 #include "package.h"
41 #include "instance.h"
42 #include "buffer_handler.h"
43 #include "script_handler.h"
44 #include "debug.h"
45 #include "conf.h"
46 #include "util.h"
47
48 #define INFO_SIZE "size"
49 #define INFO_CATEGORY "category"
50 #define ADDEND 256
51
52 static const char *type_list[] = {
53         "access",
54         "access,operation",
55         "color",
56         "drag",
57         "image",
58         "info",
59         "script",
60         "signal",
61         "text",
62         NULL
63 };
64
65 static const char *field_list[] = {
66         "type",
67         "part",
68         "data",
69         "option",
70         "id",
71         "target",
72         "file",
73         NULL
74 };
75
76 int errno;
77
78 static struct info {
79         Eina_List *script_port_list;
80         enum buffer_type env_buf_type;
81 } s_info = {
82         .script_port_list = NULL,
83         .env_buf_type = BUFFER_TYPE_FILE,
84 };
85
86 struct script_port {
87         void *handle;
88
89         const char *(*magic_id)(void);
90         int (*update_color)(void *handle, const char *id, const char *part, const char *rgba);
91         int (*update_text)(void *handle, const char *id, const char *part, const char *text);
92         int (*update_image)(void *handle, const char *id, const char *part, const char *path, const char *option);
93         int (*update_access)(void *handle, const char *id, const char *part, const char *text, const char *option);
94         int (*operate_access)(void *handle, const char *id, const char *part, const char *operation, const char *option);
95         int (*update_script)(void *handle, const char *src_id, const char *target_id, const char *part, const char *path, const char *option);
96         int (*update_signal)(void *handle, const char *id, const char *part, const char *signal);
97         int (*update_drag)(void *handle, const char *id, const char *part, double x, double y);
98         int (*update_size)(void *handle, const char *id, int w, int h);
99         int (*update_category)(void *handle, const char *id, const char *category);
100         int (*feed_event)(void *handle, int event_type, int x, int y, int down, unsigned int keycode, double timestamp);
101
102         void *(*create)(void *buffer_info, const char *file, const char *option);
103         int (*destroy)(void *handle);
104
105         int (*load)(void *handle, int (*render_pre)(void *buffer_info, void *data), int (*render_post)(void *buffer_info, void *data), void *data);
106         int (*unload)(void *handle);
107
108         int (*init)(double scale, int premultiplied);
109         int (*fini)(void);
110 };
111
112 enum block_type {
113         TYPE_ACCESS,
114         TYPE_ACCESS_OP,
115         TYPE_COLOR,
116         TYPE_DRAG,
117         TYPE_IMAGE,
118         TYPE_INFO,
119         TYPE_SCRIPT,
120         TYPE_SIGNAL,
121         TYPE_TEXT,
122         TYPE_MAX
123 };
124
125 enum field_type {
126         FIELD_TYPE,
127         FIELD_PART,
128         FIELD_DATA,
129         FIELD_OPTION,
130         FIELD_ID,
131         FIELD_TARGET,
132         FIELD_FILE
133 };
134
135 struct block {
136         enum block_type type;
137         char *part;
138         char *data;
139         char *option;
140         char *id;
141         char *target;
142         char *file;
143
144         /* Should be released */
145         char *filebuf;
146         const char *filename;
147 };
148
149 struct script_info {
150         struct buffer_info *buffer_handle; 
151         int loaded;
152
153         int w;
154         int h;
155
156         int x;
157         int y;
158         int down;
159
160         unsigned int keycode;
161
162         struct script_port *port;
163         void *port_data;
164
165         Eina_List *cached_blocks;
166 };
167
168 static inline void consuming_parsed_block(struct inst_info *inst, int is_pd, struct block *block);
169
170 static int load_all_ports(void)
171 {
172         struct script_port *item;
173         struct dirent *ent;
174         DIR *dir;
175         char *path;
176         int pathlen;
177
178         dir = opendir(SCRIPT_PORT_PATH);
179         if (!dir) {
180                 ErrPrint("Error: %s\n", strerror(errno));
181                 return LB_STATUS_ERROR_IO;
182         }
183
184         while ((ent = readdir(dir))) {
185                 if (ent->d_name[0] == '.') {
186                         continue;
187                 }
188
189                 pathlen = strlen(ent->d_name) + strlen(SCRIPT_PORT_PATH) + 1;
190                 path = malloc(pathlen);
191                 if (!path) {
192                         ErrPrint("Heap: %s %d\n", strerror(errno), pathlen);
193                         if (closedir(dir) < 0) {
194                                 ErrPrint("closedir: %s\n", strerror(errno));
195                         }
196                         return LB_STATUS_ERROR_MEMORY;
197                 }
198
199                 snprintf(path, pathlen, "%s%s", SCRIPT_PORT_PATH, ent->d_name);
200
201                 item = malloc(sizeof(*item));
202                 if (!item) {
203                         ErrPrint("Heap: %s\n", strerror(errno));
204                         DbgFree(path);
205                         if (closedir(dir) < 0) {
206                                 ErrPrint("closedir: %s\n", strerror(errno));
207                         }
208                         return LB_STATUS_ERROR_MEMORY;
209                 }
210
211                 DbgPrint("Open SCRIPT PORT: %s\n", path);
212                 item->handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW | RTLD_DEEPBIND);
213                 DbgFree(path);
214                 if (!item->handle) {
215                         ErrPrint("Error: %s\n", dlerror());
216                         DbgFree(item);
217                         if (closedir(dir) < 0) {
218                                 ErrPrint("closedir: %s\n", strerror(errno));
219                         }
220                         return LB_STATUS_ERROR_FAULT;
221                 }
222
223                 item->magic_id = dlsym(item->handle, "script_magic_id");
224                 if (!item->magic_id) {
225                         goto errout;
226                 }
227
228                 DbgPrint("SCRIPT PORT magic id: %s\n", item->magic_id());
229
230                 item->update_color = dlsym(item->handle, "script_update_color");
231                 if (!item->update_color) {
232                         goto errout;
233                 }
234
235                 item->update_text = dlsym(item->handle, "script_update_text");
236                 if (!item->update_text) {
237                         goto errout;
238                 }
239
240                 item->update_image = dlsym(item->handle, "script_update_image");
241                 if (!item->update_image) {
242                         goto errout;
243                 }
244
245                 item->update_access = dlsym(item->handle, "script_update_access");
246                 if (!item->update_access) {
247                         goto errout;
248                 }
249
250                 item->operate_access = dlsym(item->handle, "script_operate_access");
251                 if (!item->operate_access) {
252                         goto errout;
253                 }
254
255                 item->update_script = dlsym(item->handle, "script_update_script");
256                 if (!item->update_script) {
257                         goto errout;
258                 }
259
260                 item->update_signal = dlsym(item->handle, "script_update_signal");
261                 if (!item->update_signal) {
262                         goto errout;
263                 }
264
265                 item->update_drag = dlsym(item->handle, "script_update_drag");
266                 if (!item->update_drag) {
267                         goto errout;
268                 }
269
270                 item->update_size = dlsym(item->handle, "script_update_size");
271                 if (!item->update_size) {
272                         goto errout;
273                 }
274
275                 item->update_category = dlsym(item->handle, "script_update_category");
276                 if (!item->update_category) {
277                         goto errout;
278                 }
279
280                 item->create = dlsym(item->handle, "script_create");
281                 if (!item->create) {
282                         goto errout;
283                 }
284
285                 item->destroy = dlsym(item->handle, "script_destroy");
286                 if (!item->destroy) {
287                         goto errout;
288                 }
289
290                 item->load = dlsym(item->handle, "script_load");
291                 if (!item->load) {
292                         goto errout;
293                 }
294
295                 item->unload = dlsym(item->handle, "script_unload");
296                 if (!item->unload) {
297                         goto errout;
298                 }
299
300                 item->init = dlsym(item->handle, "script_init");
301                 if (!item->init) {
302                         goto errout;
303                 }
304
305                 item->fini = dlsym(item->handle, "script_fini");
306                 if (!item->fini) {
307                         goto errout;
308                 }
309
310                 item->feed_event = dlsym(item->handle, "script_feed_event");
311                 if (!item->feed_event) {
312                         goto errout;
313                 }
314
315                 if (item->init(SCALE_WIDTH_FACTOR, PREMULTIPLIED_COLOR) < 0) {
316                         ErrPrint("Failed to initialize script engine\n");
317                         goto errout;
318                 }
319
320                 s_info.script_port_list = eina_list_append(s_info.script_port_list, item);
321         }
322
323         if (closedir(dir) < 0) {
324                 ErrPrint("closedir: %s\n", strerror(errno));
325         }
326
327         return LB_STATUS_SUCCESS;
328
329 errout:
330         ErrPrint("Error: %s\n", dlerror());
331         if (dlclose(item->handle) != 0) {
332                 ErrPrint("dlclose: %s\n", strerror(errno));
333         }
334         DbgFree(item);
335         if (closedir(dir) < 0) {
336                 ErrPrint("closedir: %s\n", strerror(errno));
337         }
338         return LB_STATUS_ERROR_FAULT;
339 }
340
341 static inline struct script_port *find_port(const char *magic_id)
342 {
343         Eina_List *l;
344         struct script_port *item;
345
346         if (!s_info.script_port_list) {
347                 int ret;
348
349                 ret = load_all_ports();
350                 if (ret < 0) {
351                         ErrPrint("load_all_ports: %d\n", ret);
352                 }
353         }
354
355         EINA_LIST_FOREACH(s_info.script_port_list, l, item) {
356                 if (!strcmp(item->magic_id(), magic_id)) {
357                         return item;
358                 }
359         }
360
361         return NULL;
362 }
363
364 static inline void delete_block(struct block *block)
365 {
366         DbgFree(block->filebuf);
367         DbgFree(block);
368 }
369
370 static int render_post_cb(void *_buffer_handle, void *data)
371 {
372         PERF_INIT();
373         PERF_BEGIN();
374         struct inst_info *inst;
375         struct buffer_info *buffer_handle = _buffer_handle;
376         struct script_info *info;
377
378         inst = buffer_handler_instance(buffer_handle);
379         if (!inst) {
380                 goto out;
381         }
382
383         if (instance_state(inst) != INST_ACTIVATED) {
384                 ErrPrint("Render post invoked but instance is not activated\n");
385                 PERF_MARK(__func__);
386                 return LB_STATUS_ERROR_INVALID;
387         }
388
389         info = instance_lb_script(inst);
390         if (info && info == data) {
391                 buffer_handler_flush(buffer_handle);
392                 instance_lb_updated_by_instance(inst, NULL);
393                 PERF_MARK("lb,update");
394                 return LB_STATUS_SUCCESS;
395         }
396
397         info = instance_pd_script(inst);
398         if (info && info == data) {
399                 buffer_handler_flush(buffer_handle);
400                 instance_pd_updated_by_instance(inst, NULL);
401                 PERF_MARK("pd,update");
402                 return LB_STATUS_SUCCESS;
403         }
404
405 out:
406         ErrPrint("Failed to sync\n");
407         PERF_MARK(__func__);
408         return LB_STATUS_ERROR_FAULT;
409 }
410
411 /*!
412  * \NOTE
413  * Exported API
414  */
415 EAPI int script_signal_emit(void *buffer_handle, const char *part, const char *signal, double sx, double sy, double ex, double ey)
416 {
417         struct script_info *info;
418         struct inst_info *inst;
419         int w;
420         int h;
421         double fx;
422         double fy;
423
424         if (!buffer_handle) {
425                 ErrPrint("Invalid handle\n");
426                 return LB_STATUS_ERROR_INVALID;
427         }
428
429         info = buffer_handler_data(buffer_handle);
430         if (!info) {
431                 ErrPrint("Invalid handle\n");
432                 return LB_STATUS_ERROR_INVALID;
433         }
434
435         inst = buffer_handler_instance(buffer_handle);
436         if (!inst) {
437                 return LB_STATUS_ERROR_FAULT;
438         }
439
440         if (!signal || strlen(signal) == 0) {
441                 signal = "";
442         }
443
444         if (!part || strlen(part) == 0) {
445                 part = "";
446         }
447
448         buffer_handler_get_size(buffer_handle, &w, &h);
449
450         fx = (double)info->x / (double)w;
451         fy = (double)info->y / (double)h;
452
453         return instance_signal_emit(inst, signal, part, sx, sy, ex, ey, fx, fy, info->down);
454 }
455
456 static inline void flushing_cached_block(struct script_info *info)
457 {
458         struct block *block;
459         struct inst_info *inst;
460         int is_pd;
461
462         inst = buffer_handler_instance(info->buffer_handle);
463         if (!inst) {
464                 ErrPrint("Instance is not valid\n");
465         }
466
467         is_pd = instance_pd_script(inst) == info;
468
469         EINA_LIST_FREE(info->cached_blocks, block) {
470                 consuming_parsed_block(inst, is_pd, block);
471         }
472 }
473
474 HAPI int script_handler_load(struct script_info *info, int is_pd)
475 {
476         struct inst_info *inst;
477
478         if (!info || !info->port) {
479                 ErrPrint("Script handler is not created\n");
480                 return LB_STATUS_ERROR_INVALID;
481         }
482
483         if (info->loaded > 0) {
484                 info->loaded++;
485                 return LB_STATUS_SUCCESS;
486         }
487
488         if (info->port->load(info->port_data, NULL, render_post_cb, info) < 0) {
489                 ErrPrint("Unable to load the script\n");
490                 return LB_STATUS_ERROR_FAULT;
491         }
492
493         info->loaded = 1;
494         flushing_cached_block(info);
495
496         inst = buffer_handler_instance(info->buffer_handle);
497         if (inst) {
498                 script_signal_emit(info->buffer_handle, instance_id(inst),
499                                 is_pd ? "pd,show" : "lb,show", 0.0f, 0.0f, 0.0f, 0.0f);
500         }
501         buffer_handler_flush(info->buffer_handle);
502         return LB_STATUS_SUCCESS;
503 }
504
505 HAPI int script_handler_unload(struct script_info *info, int is_pd)
506 {
507         if (!info || !info->port) {
508                 return LB_STATUS_ERROR_INVALID;
509         }
510
511         info->loaded--;
512         if (info->loaded > 0) {
513                 return LB_STATUS_ERROR_BUSY;
514         }
515
516         if (info->loaded < 0) {
517                 info->loaded = 0;
518                 return LB_STATUS_ERROR_ALREADY;
519         }
520
521         if (info->port->unload(info->port_data) < 0) {
522                 ErrPrint("Failed to unload script object. but go ahead\n");
523         }
524
525         return LB_STATUS_SUCCESS;
526 }
527
528 HAPI struct script_info *script_handler_create(struct inst_info *inst, const char *file, const char *option, int w, int h)
529 {
530         struct script_info *info;
531
532         DbgPrint("Create script: %s (%s) %dx%d\n", file, option, w, h);
533
534         if (!file) {
535                 return NULL;
536         }
537
538         info = calloc(1, sizeof(*info));
539         if (!info) {
540                 ErrPrint("Heap: %s\n", strerror(errno));
541                 return NULL;
542         }
543
544         info->buffer_handle = buffer_handler_create(inst, s_info.env_buf_type, w, h, sizeof(int));
545         if (!info->buffer_handle) {
546                 /* buffer_handler_create will prints some log */
547                 DbgFree(info);
548                 return NULL;
549         }
550
551         (void)buffer_handler_set_data(info->buffer_handle, info);
552
553         info->port = find_port(package_script(instance_package(inst)));
554         if (!info->port) {
555                 ErrPrint("Failed to find a proper port for [%s]%s\n",
556                                         instance_package(inst), package_script(instance_package(inst)));
557                 buffer_handler_destroy(info->buffer_handle);
558                 DbgFree(info);
559                 return NULL;
560         }
561
562         info->port_data = info->port->create(info->buffer_handle, file, option);
563         if (!info->port_data) {
564                 ErrPrint("Failed to create a port (%s - %s)\n", file, option);
565                 buffer_handler_destroy(info->buffer_handle);
566                 DbgFree(info);
567                 return NULL;
568         }
569
570         return info;
571 }
572
573 HAPI int script_handler_destroy(struct script_info *info)
574 {
575         struct block *block;
576         int ret;
577
578         if (!info || !info->port) {
579                 ErrPrint("port is not valid\n");
580                 return LB_STATUS_ERROR_INVALID;
581         }
582
583         if (info->loaded != 0) {
584                 ErrPrint("Script handler is not unloaded\n");
585                 return LB_STATUS_ERROR_BUSY;
586         }
587
588         ret = info->port->destroy(info->port_data);
589         if (ret < 0) {
590                 ErrPrint("Failed to destroy port, but go ahead: %d\n", ret);
591         }
592
593         (void)buffer_handler_destroy(info->buffer_handle);
594
595         EINA_LIST_FREE(info->cached_blocks, block) {
596                 delete_block(block);
597         }
598
599         DbgFree(info);
600         return LB_STATUS_SUCCESS;
601 }
602
603 HAPI int script_handler_is_loaded(struct script_info *info)
604 {
605         return info ? info->loaded > 0 : 0;
606 }
607
608 HAPI struct buffer_info *script_handler_buffer_info(struct script_info *info)
609 {
610         if (!info) {
611                 return NULL;
612         }
613
614         return info->buffer_handle;
615 }
616
617 static int update_script_color(struct inst_info *inst, struct block *block, int is_pd)
618 {
619         PERF_INIT();
620         PERF_BEGIN();
621         struct script_info *info;
622         int ret;
623
624         if (!block || !block->part || !block->data) {
625                 ErrPrint("Block or part or data is not valid\n");
626                 PERF_MARK("color");
627                 return LB_STATUS_ERROR_INVALID;
628         }
629
630         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
631         if (!info) {
632                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
633                 PERF_MARK("color");
634                 return LB_STATUS_ERROR_FAULT;
635         }
636
637         if (!info->port) {
638                 ErrPrint("info->port is NIL (%d, %s)\n", is_pd, instance_id(inst));
639                 PERF_MARK("color");
640                 return LB_STATUS_ERROR_INVALID;
641         }
642
643         ret = info->port->update_color(info->port_data, block->id, block->part, block->data);
644         PERF_MARK("color");
645         return ret;
646 }
647
648 static int update_script_text(struct inst_info *inst, struct block *block, int is_pd)
649 {
650         PERF_INIT();
651         PERF_BEGIN();
652         struct script_info *info;
653         int ret;
654
655         if (!block || !block->part || !block->data) {
656                 ErrPrint("Block or part or data is not valid\n");
657                 PERF_MARK("text");
658                 return LB_STATUS_ERROR_INVALID;
659         }
660
661         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
662         if (!info) {
663                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
664                 PERF_MARK("text");
665                 return LB_STATUS_ERROR_FAULT;
666         }
667
668         if (!info->port) {
669                 ErrPrint("info->port is NIL\n");
670                 PERF_MARK("text");
671                 return LB_STATUS_ERROR_INVALID;
672         }
673
674         DbgPrint("[%s] %s (%s)\n", block->id, block->part, block->data);
675         ret = info->port->update_text(info->port_data, block->id, block->part, block->data);
676         
677         PERF_MARK("text");
678         return ret;
679 }
680
681 static int update_script_image(struct inst_info *inst, struct block *block, int is_pd)
682 {
683         PERF_INIT();
684         PERF_BEGIN();
685         struct script_info *info;
686         int ret;
687
688         if (!block || !block->part) {
689                 ErrPrint("Block or part is not valid\n");
690                 PERF_MARK("image");
691                 return LB_STATUS_ERROR_INVALID;
692         }
693
694         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
695         if (!info) {
696                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
697                 PERF_MARK("image");
698                 return LB_STATUS_ERROR_FAULT;
699         }
700
701         if (!info->port) {
702                 ErrPrint("info->port is NIL\n");
703                 PERF_MARK("image");
704                 return LB_STATUS_ERROR_INVALID;
705         }
706
707         DbgPrint("[%s] %s (%s)\n", block->id, block->part, block->data);
708         ret = info->port->update_image(info->port_data, block->id, block->part, block->data, block->option);
709         PERF_MARK("image");
710         return ret;
711 }
712
713 static int update_access(struct inst_info *inst, struct block *block, int is_pd)
714 {
715         PERF_INIT();
716         PERF_BEGIN();
717         struct script_info *info;
718         int ret;
719
720         if (!block || !block->part) {
721                 ErrPrint("Block or block->part is NIL\n");
722                 PERF_MARK("access");
723                 return LB_STATUS_ERROR_INVALID;
724         }
725
726         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
727         if (!info) {
728                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
729                 PERF_MARK("access");
730                 return LB_STATUS_ERROR_FAULT;
731         }
732
733         if (!info->port) {
734                 ErrPrint("info->port is NIL\n");
735                 PERF_MARK("access");
736                 return LB_STATUS_ERROR_INVALID;
737         }
738
739         ret = info->port->update_access(info->port_data, block->id, block->part, block->data, block->option);
740         PERF_MARK("access");
741         return ret;
742 }
743
744 static int operate_access(struct inst_info *inst, struct block *block, int is_pd)
745 {
746         PERF_INIT();
747         PERF_BEGIN();
748         struct script_info *info;
749         int ret;
750
751         if (!block || !block->part) {
752                 ErrPrint("Block or block->part is NIL\n");
753                 PERF_MARK("operate_access");
754                 return LB_STATUS_ERROR_INVALID;
755         }
756
757         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
758         if (!info) {
759                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
760                 PERF_MARK("operate_access");
761                 return LB_STATUS_ERROR_FAULT;
762         }
763
764         if (!info->port) {
765                 ErrPrint("info->port is NIL\n");
766                 PERF_MARK("operate_access");
767                 return LB_STATUS_ERROR_INVALID;
768         }
769
770         ret = info->port->operate_access(info->port_data, block->id, block->part, block->data, block->option);
771         PERF_MARK("operate_access");
772         return ret;
773 }
774
775 static int update_script_script(struct inst_info *inst, struct block *block, int is_pd)
776 {
777         PERF_INIT();
778         PERF_BEGIN();
779         struct script_info *info;
780         int ret;
781
782         if (!block || !block->part) {
783                 ErrPrint("Block or part is NIL\n");
784                 PERF_MARK("script");
785                 return LB_STATUS_ERROR_INVALID;
786         }
787
788         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
789         if (!info) {
790                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
791                 PERF_MARK("script");
792                 return LB_STATUS_ERROR_FAULT;
793         }
794
795         if (!info->port) {
796                 ErrPrint("info->port is NIL\n");
797                 PERF_MARK("script");
798                 return LB_STATUS_ERROR_INVALID;
799         }
800
801         ret = info->port->update_script(info->port_data, block->id, block->target, block->part, block->data, block->option);
802         PERF_MARK("script");
803         return ret;
804 }
805
806 static int update_script_signal(struct inst_info *inst, struct block *block, int is_pd)
807 {
808         PERF_INIT();
809         PERF_BEGIN();
810         struct script_info *info;
811         int ret;
812
813         if (!block) {
814                 ErrPrint("block is NIL\n");
815                 PERF_MARK("signal");
816                 return LB_STATUS_ERROR_INVALID;
817         }
818
819         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
820         if (!info) {
821                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
822                 PERF_MARK("signal");
823                 return LB_STATUS_ERROR_FAULT;
824         }
825
826         if (!info->port) {
827                 ErrPrint("info->port is NIL\n");
828                 PERF_MARK("signal");
829                 return LB_STATUS_ERROR_INVALID;
830         }
831
832         ret = info->port->update_signal(info->port_data, block->id, block->part, block->data);
833         PERF_MARK("signal");
834         return ret;
835 }
836
837 static int update_script_drag(struct inst_info *inst, struct block *block, int is_pd)
838 {
839         PERF_INIT();
840         PERF_BEGIN();
841         struct script_info *info;
842         double dx, dy;
843         int ret;
844
845         if (!block || !block->data || !block->part) {
846                 ErrPrint("block or block->data or block->part is NIL\n");
847                 PERF_MARK("drag");
848                 return LB_STATUS_ERROR_INVALID;
849         }
850
851         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
852         if (!info) {
853                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
854                 PERF_MARK("drag");
855                 return LB_STATUS_ERROR_FAULT;
856         }
857
858         if (sscanf(block->data, "%lfx%lf", &dx, &dy) != 2) {
859                 ErrPrint("Invalid format of data (DRAG data [%s])\n", block->data);
860                 PERF_MARK("drag");
861                 return LB_STATUS_ERROR_INVALID;
862         }
863
864         if (!info->port) {
865                 ErrPrint("info->port is NIL\n");
866                 PERF_MARK("drag");
867                 return LB_STATUS_ERROR_INVALID;
868         }
869
870         ret = info->port->update_drag(info->port_data, block->id, block->part, dx, dy);
871         PERF_MARK("drag");
872         return ret;
873 }
874
875 static void update_size_for_script(struct script_info *info, struct inst_info *inst, int w, int h)
876 {
877         /*!
878          * \note
879          * After update the buffer size,
880          * If it required to be unload and load.
881          * New size of buffer will be allocated
882          */
883         buffer_handler_update_size(info->buffer_handle, w, h);
884
885         if (info->port->update_size) {
886                 (void)info->port->update_size(info->port_data, NULL, w, h);
887         }
888
889         if (instance_lb_script(inst) == info) {
890                 instance_set_lb_size(inst, w, h);
891         } else if (instance_pd_script(inst) == info) {
892                 instance_set_pd_size(inst, w, h);
893         } else {
894                 ErrPrint("Unknown script\n");
895         }
896 }
897
898 HAPI int script_handler_resize(struct script_info *info, int w, int h)
899 {
900         PERF_INIT();
901         PERF_BEGIN();
902         struct inst_info *inst;
903
904         if (!info) {
905                 ErrPrint("info[%p] resize is ignored\n", info);
906                 PERF_MARK("resize");
907                 return LB_STATUS_SUCCESS;
908         }
909
910         inst = buffer_handler_instance(info->buffer_handle);
911         if (!inst) {
912                 ErrPrint("Instance is not valid\n");
913                 PERF_MARK("resize");
914                 return LB_STATUS_ERROR_INVALID;
915         }
916
917         update_size_for_script(info, inst, w, h);
918
919         PERF_MARK("resize");
920         return LB_STATUS_SUCCESS;
921 }
922
923 HAPI const char *script_handler_buffer_id(struct script_info *info)
924 {
925         if (!info || !info->buffer_handle) {
926                 ErrPrint("Invalid info\n");
927                 return "";
928         }
929
930         return buffer_handler_id(info->buffer_handle);
931 }
932
933 static int update_info(struct inst_info *inst, struct block *block, int is_pd)
934 {
935         PERF_INIT();
936         PERF_BEGIN();
937         struct script_info *info;
938
939         if (!block || !block->part || !block->data) {
940                 ErrPrint("block or block->part or block->data is NIL\n");
941                 PERF_MARK("info");
942                 return LB_STATUS_ERROR_INVALID;
943         }
944
945         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
946         if (!info) {
947                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
948                 PERF_MARK("info");
949                 return LB_STATUS_ERROR_FAULT;
950         }
951
952         if (!info->port) {
953                 ErrPrint("info->port is NIL\n");
954                 PERF_MARK("info");
955                 return LB_STATUS_ERROR_INVALID;
956         }
957
958         if (!strcasecmp(block->part, INFO_SIZE)) {
959                 int w, h;
960
961                 if (sscanf(block->data, "%dx%d", &w, &h) != 2) {
962                         ErrPrint("Invalid format for SIZE(%s)\n", block->data);
963                         PERF_MARK("info");
964                         return LB_STATUS_ERROR_INVALID;
965                 }
966
967                 if (!block->id) {
968                         update_size_for_script(info, inst, w, h);
969                 } else {
970                         (void)info->port->update_size(info->port_data, block->id, w, h);
971                 }
972         } else if (!strcasecmp(block->part, INFO_CATEGORY)) {
973                 (void)info->port->update_category(info->port_data, block->id, block->data);
974         }
975         PERF_MARK("info");
976
977         return LB_STATUS_SUCCESS;
978 }
979
980 static inline void consuming_parsed_block(struct inst_info *inst, int is_pd, struct block *block)
981 {
982         struct script_info *info;
983         typedef int (*update_function_t)(struct inst_info *inst, struct block *block, int is_pd);
984         update_function_t updators[] = {
985                 update_access,
986                 operate_access,
987                 update_script_color,
988                 update_script_drag,
989                 update_script_image,
990                 update_info,
991                 update_script_script,
992                 update_script_signal,
993                 update_script_text,
994                 NULL
995         };
996
997         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
998         if (!info) {
999                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
1000                 goto free_out;
1001         }
1002
1003         if (script_handler_is_loaded(info)) {
1004                 if (block->type >= 0 || block->type < TYPE_MAX) {
1005                         (void)updators[block->type](inst, block, is_pd);
1006                 } else {
1007                         ErrPrint("Block type[%d] is not valid\n", block->type);
1008                 }
1009         } else {
1010                 info->cached_blocks = eina_list_append(info->cached_blocks, block);
1011                 DbgPrint("Block is cached (%p), %d, %s\n", block, eina_list_count(info->cached_blocks), instance_id(inst));
1012                 return;
1013         }
1014
1015 free_out:
1016         delete_block(block);
1017 }
1018
1019 HAPI int script_init(void)
1020 {
1021         if (!strcasecmp(PROVIDER_METHOD, "shm")) {
1022                 s_info.env_buf_type = BUFFER_TYPE_SHM;
1023         } else if (!strcasecmp(PROVIDER_METHOD, "pixmap")) {
1024                 s_info.env_buf_type = BUFFER_TYPE_PIXMAP;
1025         }
1026
1027         return LB_STATUS_SUCCESS;
1028 }
1029
1030 HAPI int script_fini(void)
1031 {
1032         struct script_port *item;
1033         /*!
1034          * \TODO: Release all handles
1035          */
1036         EINA_LIST_FREE(s_info.script_port_list, item) {
1037                 item->fini();
1038                 if (dlclose(item->handle) != 0) {
1039                         ErrPrint("dlclose: %s\n", strerror(errno));
1040                 }
1041                 DbgFree(item);
1042         }
1043
1044         return 0;
1045 }
1046
1047 HAPI int script_handler_update_pointer(struct script_info *info, int x, int y, int down)
1048 {
1049         if (!info) {
1050                 return LB_STATUS_SUCCESS;
1051         }
1052
1053         info->x = x;
1054         info->y = y;
1055
1056         if (down == 0) {
1057                 info->down = 0;
1058         } else if (down == 1) {
1059                 info->down = 1;
1060         }
1061
1062         return LB_STATUS_SUCCESS;
1063 }
1064
1065 HAPI int script_handler_update_keycode(struct script_info *info, unsigned int keycode)
1066 {
1067         if (!info) {
1068                 return LB_STATUS_SUCCESS;
1069         }
1070
1071         info->keycode = keycode;
1072
1073         return LB_STATUS_SUCCESS;
1074 }
1075
1076 HAPI int script_handler_feed_event(struct script_info *info, int event, double timestamp)
1077 {
1078         int ret;
1079
1080         if (!info->port) {
1081                 ErrPrint("info->port is NIL\n");
1082                 return LB_STATUS_ERROR_INVALID;
1083         }
1084
1085         ret = info->port->feed_event(info->port_data, event, info->x, info->y, info->down, info->keycode, timestamp);
1086         return ret;
1087 }
1088
1089 static inline char *load_file(const char *filename)
1090 {
1091         char *filebuf = NULL;
1092         int fd;
1093         off_t filesize;
1094         int ret;
1095         size_t readsize = 0;
1096
1097         fd = open(filename, O_RDONLY);
1098         if (fd < 0) {
1099                 ErrPrint("open: %s\n", strerror(errno));
1100                 return NULL;
1101         }
1102
1103         filesize = lseek(fd, 0L, SEEK_END);
1104         if (filesize == (off_t)-1) {
1105                 ErrPrint("lseek: %s\n", strerror(errno));
1106                 goto errout;
1107         }
1108
1109         if (lseek(fd, 0L, SEEK_SET) < 0) {
1110                 ErrPrint("lseek: %s\n", strerror(errno));
1111                 goto errout;
1112         }
1113
1114         filebuf = malloc(filesize + 1);
1115         if (!filebuf) {
1116                 ErrPrint("malloc: %s\n", strerror(errno));
1117                 goto errout;
1118         }
1119
1120         while (readsize < filesize) {
1121                 ret = read(fd, filebuf + readsize, (size_t)filesize - readsize);
1122                 if (ret < 0) {
1123                         if (errno == EINTR) {
1124                                 DbgPrint("Read is interrupted\n");
1125                                 continue;
1126                         }
1127
1128                         ErrPrint("read: %s\n", strerror(errno));
1129                         free(filebuf);
1130                         filebuf = NULL;
1131                         break;
1132                 }
1133
1134                 readsize += ret;
1135         }
1136
1137         if (filebuf) {
1138                 filebuf[readsize] = '\0';
1139         }
1140
1141         /*!
1142          * \note
1143          * Now, we are ready to parse the filebuf.
1144          */
1145
1146 errout:
1147         if (close(fd) < 0) {
1148                 ErrPrint("close: %s\n", strerror(errno));
1149         }
1150
1151         return filebuf;
1152 }
1153
1154 #if defined(_APPLY_SCRIPT_ASYNC_UPDATE)
1155 struct apply_data {
1156         struct inst_info *inst;
1157         Eina_List *block_list;
1158         int is_pd;
1159 };
1160
1161 static Eina_Bool apply_changes_cb(void *_data)
1162 {
1163         struct apply_data *data = _data;
1164         struct block *block;
1165
1166         block = eina_list_nth(data->block_list, 0);
1167         data->block_list = eina_list_remove(data->block_list, block);
1168         consuming_parsed_block(data->inst, data->is_pd, block);
1169
1170         if (!data->block_list) {
1171                 free(data);
1172                 return ECORE_CALLBACK_CANCEL;
1173         }
1174
1175         return ECORE_CALLBACK_RENEW;
1176 }
1177 #endif
1178
1179
1180 HAPI int script_handler_parse_desc(struct inst_info *inst, const char *filename, int is_pd)
1181 {
1182         PERF_INIT();
1183         PERF_BEGIN();
1184         int type_idx = 0;
1185         int type_len = 0;
1186         int field_idx = 0;
1187         int field_len = 0;
1188         char *filebuf;
1189         char *fileptr;
1190         char *ptr = NULL;
1191         struct block *block = NULL;
1192         Eina_List *block_list = NULL;
1193         enum state {
1194                 BEGIN,
1195                 FIELD,
1196                 DATA,
1197                 END,
1198                 DONE,
1199                 ERROR,
1200         } state;
1201
1202         filebuf = load_file(filename);
1203         if (!filebuf) {
1204                 return LB_STATUS_ERROR_IO;
1205         }
1206
1207         fileptr = filebuf;
1208
1209         state = BEGIN;
1210         while (*fileptr && state != ERROR) {
1211                 switch (state) {
1212                 case BEGIN:
1213                         if (*fileptr == '{') {
1214                                 block = calloc(1, sizeof(*block));
1215                                 if (!block) {
1216                                         ErrPrint("calloc: %s\n", strerror(errno));
1217                                         state = ERROR;
1218                                         continue;
1219                                 }
1220                                 state = FIELD;
1221                                 ptr = NULL;
1222                         }
1223                         break;
1224                 case FIELD:
1225                         if (isspace(*fileptr)) {
1226                                 if (ptr != NULL) {
1227                                         *fileptr = '\0';
1228                                 }
1229                         } else if (*fileptr == '=') {
1230                                 *fileptr = '\0';
1231                                 ptr = NULL;
1232                                 state = DATA;
1233                         } else if (ptr == NULL) {
1234                                 ptr = fileptr;
1235                                 field_idx = 0;
1236                                 field_len = 0;
1237
1238                                 while (field_list[field_idx]) {
1239                                         if (field_list[field_idx][field_len] == *fileptr) {
1240                                                 break;
1241                                         }
1242                                         field_idx++;
1243                                 }
1244
1245                                 if (!field_list[field_idx]) {
1246                                         ErrPrint("Invalid field\n");
1247                                         state = ERROR;
1248                                         continue;
1249                                 }
1250
1251                                 field_len++;
1252                         } else {
1253                                 if (field_list[field_idx][field_len] != *fileptr) {
1254                                         field_idx++;
1255                                         while (field_list[field_idx]) {
1256                                                 if (!strncmp(field_list[field_idx], fileptr - field_len, field_len)) {
1257                                                         break;
1258                                                 } else {
1259                                                         field_idx++;
1260                                                 }
1261                                         }
1262
1263                                         if (!field_list[field_idx]) {
1264                                                 state = ERROR;
1265                                                 ErrPrint("field is not valid\n");
1266                                                 continue;
1267                                         }
1268                                 }
1269
1270                                 field_len++;
1271                         }
1272                         break;
1273                 case DATA:
1274                         switch (field_idx) {
1275                         case FIELD_TYPE:
1276                                 if (ptr == NULL) {
1277                                         if (isspace(*fileptr)) {
1278                                                 break;
1279                                         }
1280
1281                                         if (*fileptr == '\0') {
1282                                                 state = ERROR;
1283                                                 ErrPrint("Type is not valid\n");
1284                                                 continue;
1285                                         }
1286
1287                                         ptr = fileptr;
1288                                         type_idx = 0;
1289                                         type_len = 0;
1290                                 }
1291
1292                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1293                                         *fileptr = '\0';
1294                                 }
1295
1296                                 if (type_list[type_idx][type_len] != *fileptr) {
1297                                         type_idx++;
1298                                         while (type_list[type_idx]) {
1299                                                 if (!strncmp(type_list[type_idx], fileptr - type_len, type_len)) {
1300                                                         break;
1301                                                 } else {
1302                                                         type_idx++;
1303                                                 }
1304                                         }
1305
1306                                         if (!type_list[type_idx]) {
1307                                                 state = ERROR;
1308                                                 ErrPrint("type is not valid (%s)\n", fileptr - type_len);
1309                                                 continue;
1310                                         }
1311                                 }
1312
1313                                 if (!*fileptr) {
1314                                         block->type = type_idx;
1315                                         state = DONE;
1316                                         ptr = NULL;
1317                                 }
1318
1319                                 type_len++;
1320                                 break;
1321                         case FIELD_PART:
1322                                 if (ptr == NULL) {
1323                                         ptr = fileptr;
1324                                 }
1325
1326                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1327                                         *fileptr = '\0';
1328                                 }
1329
1330                                 if (!*fileptr) {
1331                                         block->part = ptr;
1332                                         state = DONE;
1333                                         ptr = NULL;
1334                                 }
1335                                 break;
1336                         case FIELD_DATA:
1337                                 if (ptr == NULL) {
1338                                         ptr = fileptr;
1339                                 }
1340
1341                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1342                                         *fileptr = '\0';
1343                                 }
1344
1345                                 if (!*fileptr) {
1346                                         block->data = ptr;
1347                                         state = DONE;
1348                                         ptr = NULL;
1349                                 }
1350                                 break;
1351                         case FIELD_OPTION:
1352                                 if (ptr == NULL) {
1353                                         ptr = fileptr;
1354                                 }
1355
1356                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1357                                         *fileptr = '\0';
1358                                 }
1359
1360                                 if (!*fileptr) {
1361                                         block->option = ptr;
1362                                         state = DONE;
1363                                         ptr = NULL;
1364                                 }
1365                                 break;
1366                         case FIELD_ID:
1367                                 if (ptr == NULL) {
1368                                         ptr = fileptr;
1369                                 }
1370
1371                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1372                                         *fileptr = '\0';
1373                                 }
1374
1375                                 if (!*fileptr) {
1376                                         block->id = ptr;
1377                                         state = DONE;
1378                                         ptr = NULL;
1379                                 }
1380                                 break;
1381                         case FIELD_TARGET:
1382                                 if (ptr == NULL) {
1383                                         ptr = fileptr;
1384                                 }
1385
1386                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1387                                         *fileptr = '\0';
1388                                 }
1389
1390                                 if (!*fileptr) {
1391                                         block->target = ptr;
1392                                         state = DONE;
1393                                         ptr = NULL;
1394                                 }
1395                                 break;
1396                         case FIELD_FILE:
1397                                 if (ptr == NULL) {
1398                                         ptr = fileptr;
1399                                 }
1400
1401                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1402                                         *fileptr = '\0';
1403                                 }
1404
1405                                 if (!*fileptr) {
1406                                         block->target = ptr;
1407                                         state = DONE;
1408                                         ptr = NULL;
1409                                 }
1410                         default:
1411                                 break;
1412                         }
1413
1414                         break;
1415                 case DONE:
1416                         if (isspace(*fileptr)) {
1417                         } else if (*fileptr == '}') {
1418                                         state = BEGIN;
1419                                         block->filename = filename;
1420                                         block_list = eina_list_append(block_list, block);
1421                                         block = NULL;
1422                         } else {
1423                                 state = FIELD;
1424                                 continue;
1425                         }
1426                         break;
1427                 case END:
1428                 default:
1429                         break;
1430                 }
1431
1432                 fileptr++;
1433         }
1434
1435         if (state != BEGIN) {
1436                 ErrPrint("State %d\n", state);
1437
1438                 free(filebuf);
1439                 free(block);
1440
1441                 EINA_LIST_FREE(block_list, block) {
1442                         free(block);
1443                 }
1444
1445                 PERF_MARK("parser");
1446                 return LB_STATUS_ERROR_FAULT;
1447         }
1448
1449         block = eina_list_data_get(eina_list_last(block_list));
1450         if (block) {
1451                 block->filebuf = filebuf;
1452         } else {
1453                 ErrPrint("Last block is not exists (There is no parsed block)\n");
1454                 free(filebuf);
1455         }
1456
1457         PERF_MARK("parser");
1458
1459 #if defined(_APPLY_SCRIPT_ASYNC_UPDATE)
1460         struct apply_data *data;
1461
1462         data = malloc(sizeof(*data));
1463         if (data) {
1464                 data->inst = inst;
1465                 data->is_pd = is_pd;
1466                 data->block_list = block_list;
1467                 if (!ecore_timer_add(0.001f, apply_changes_cb, data)) {
1468                         ErrPrint("Failed to add timer\n");
1469                         free(data);
1470                         EINA_LIST_FREE(block_list, block) {
1471                                 consuming_parsed_block(inst, is_pd, block);
1472                         }
1473                 }
1474         } else {
1475                 ErrPrint("Heap: %s\n", strerror(errno));
1476                 EINA_LIST_FREE(block_list, block) {
1477                         consuming_parsed_block(inst, is_pd, block);
1478                 }
1479         }
1480 #else
1481         ErrPrint("Begin: Set content for EDJE object\n");
1482         EINA_LIST_FREE(block_list, block) {
1483                 consuming_parsed_block(inst, is_pd, block);
1484         }
1485         ErrPrint("End: Set content for EDJE object\n");
1486
1487         /*!
1488          * Doesn't need to force to render the contents.
1489         struct script_info *info;
1490         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
1491         if (info && info->ee) {
1492                 ecore_evas_manual_render(info->ee);
1493         }
1494         */
1495 #endif
1496
1497         return LB_STATUS_SUCCESS;
1498 }
1499
1500 /* End of a file */