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