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