Update SMACK, Fix a crash of terminating sequence, etc, ...
[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
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                 DbgPrint("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                 DbgPrint("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)\n", file, option);
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         DbgPrint("Update info [%dx%d]\n", w, h);
382         info->w = w;
383         info->h = h;
384
385         info->port_data = info->port->create(file, option);
386         if (!info->port_data) {
387                 ErrPrint("Failed to create a port (%s - %s)\n", file, option);
388                 fb_destroy(info->fb);
389                 DbgFree(info);
390                 return NULL;
391         }
392
393         return info;
394 }
395
396 HAPI int script_handler_destroy(struct script_info *info)
397 {
398         struct block *block;
399         int ret;
400
401         if (!info || !info->port) {
402                 ErrPrint("port is not valid\n");
403                 return LB_STATUS_ERROR_INVALID;
404         }
405
406         if (info->loaded != 0) {
407                 ErrPrint("Script handler is not unloaded\n");
408                 return LB_STATUS_ERROR_INVALID;
409         }
410
411         ret = info->port->destroy(info->port_data);
412         if (ret < 0)
413                 ErrPrint("Failed to destroy port, but go ahead: %d\n", ret);
414
415         fb_destroy(info->fb);
416
417         EINA_LIST_FREE(info->cached_blocks, block) {
418                 delete_block(block);
419         }
420         DbgFree(info);
421         return LB_STATUS_SUCCESS;
422 }
423
424 HAPI int script_handler_is_loaded(struct script_info *info)
425 {
426         return info ? info->loaded > 0 : 0;
427 }
428
429 HAPI struct fb_info *script_handler_fb(struct script_info *info)
430 {
431         return info ? info->fb : NULL;
432 }
433
434 HAPI void *script_handler_evas(struct script_info *info)
435 {
436         if (!info)
437                 return NULL;
438
439         if (!info->ee)
440                 return NULL;
441
442         return ecore_evas_get(info->ee);
443 }
444
445 static int update_script_color(struct inst_info *inst, struct block *block, int is_pd)
446 {
447         struct script_info *info;
448         Evas *e;
449
450         if (!block || !block->part || !block->data) {
451                 ErrPrint("Block or part or data is not valid\n");
452                 return LB_STATUS_ERROR_INVALID;
453         }
454
455         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
456         if (!info) {
457                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
458                 return LB_STATUS_ERROR_FAULT;
459         }
460
461         if (!info->port) {
462                 ErrPrint("info->port is NIL (%d, %s)\n", is_pd, instance_id(inst));
463                 return LB_STATUS_ERROR_INVALID;
464         }
465
466         e = script_handler_evas(info);
467         if (e)
468                 info->port->update_color(info->port_data, e, block->id, block->part, block->data);
469         else
470                 ErrPrint("Evas(nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
471
472         return LB_STATUS_SUCCESS;
473 }
474
475 static int update_script_text(struct inst_info *inst, struct block *block, int is_pd)
476 {
477         struct script_info *info;
478         Evas *e;
479
480         if (!block || !block->part || !block->data) {
481                 ErrPrint("Block or part or data is not valid\n");
482                 return LB_STATUS_ERROR_INVALID;
483         }
484
485         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
486         if (!info) {
487                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
488                 return LB_STATUS_ERROR_FAULT;
489         }
490
491         if (!info->port) {
492                 ErrPrint("info->port is NIL\n");
493                 return LB_STATUS_ERROR_INVALID;
494         }
495
496         e = script_handler_evas(info);
497         if (e)
498                 info->port->update_text(info->port_data, e, block->id, block->part, block->data);
499         else
500                 ErrPrint("Evas(nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
501         return LB_STATUS_SUCCESS;
502 }
503
504 static int update_script_image(struct inst_info *inst, struct block *block, int is_pd)
505 {
506         struct script_info *info;
507         Evas *e;
508
509         if (!block || !block->part) {
510                 ErrPrint("Block or part is not valid\n");
511                 return LB_STATUS_ERROR_INVALID;
512         }
513
514         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
515         if (!info) {
516                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
517                 return LB_STATUS_ERROR_FAULT;
518         }
519
520         if (!info->port) {
521                 ErrPrint("info->port is NIL\n");
522                 return LB_STATUS_ERROR_INVALID;
523         }
524
525         e = script_handler_evas(info);
526         if (e)
527                 info->port->update_image(info->port_data, e, block->id, block->part, block->data, block->option);
528         else
529                 ErrPrint("Evas: (nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
530         return LB_STATUS_SUCCESS;
531 }
532
533 static int update_access(struct inst_info *inst, struct block *block, int is_pd)
534 {
535         struct script_info *info;
536         Evas *e;
537
538         if (!block || !block->part) {
539                 ErrPrint("Block or block->part is NIL\n");
540                 return LB_STATUS_ERROR_INVALID;
541         }
542
543         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
544         if (!info) {
545                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
546                 return LB_STATUS_ERROR_FAULT;
547         }
548
549         if (!info->port) {
550                 ErrPrint("info->port is NIL\n");
551                 return LB_STATUS_ERROR_INVALID;
552         }
553
554         e = script_handler_evas(info);
555         if (e)
556                 info->port->update_access(info->port_data, e, block->id, block->part, block->data, block->option);
557         else
558                 ErrPrint("Evas: (nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
559         return LB_STATUS_SUCCESS;
560 }
561
562 static int update_script_script(struct inst_info *inst, struct block *block, int is_pd)
563 {
564         struct script_info *info;
565         Evas *e;
566
567         if (!block || !block->part) {
568                 ErrPrint("Block or part is NIL\n");
569                 return LB_STATUS_ERROR_INVALID;
570         }
571
572         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
573         if (!info) {
574                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
575                 return LB_STATUS_ERROR_FAULT;
576         }
577
578         if (!info->port) {
579                 ErrPrint("info->port is NIL\n");
580                 return LB_STATUS_ERROR_INVALID;
581         }
582
583         e = script_handler_evas(info);
584         if (e)
585                 info->port->update_script(info->port_data, e, block->id, block->target_id, block->part, block->data, block->option);
586         else
587                 ErrPrint("Evas: (nil) id[%s] part[%s] data[%s] option[%s]\n",
588                                                 block->id, block->part, block->data, block->option);
589         return LB_STATUS_SUCCESS;
590 }
591
592 static int update_script_signal(struct inst_info *inst, struct block *block, int is_pd)
593 {
594         struct script_info *info;
595         Evas *e;
596
597         if (!block) {
598                 ErrPrint("block is NIL\n");
599                 return LB_STATUS_ERROR_INVALID;
600         }
601
602         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
603         if (!info) {
604                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
605                 return LB_STATUS_ERROR_FAULT;
606         }
607
608         if (!info->port) {
609                 ErrPrint("info->port is NIL\n");
610                 return LB_STATUS_ERROR_INVALID;
611         }
612
613         e = script_handler_evas(info);
614         if (e)
615                 info->port->update_signal(info->port_data, e, block->id, block->part, block->data);
616         else
617                 ErrPrint("Evas(nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
618         return LB_STATUS_SUCCESS;
619 }
620
621 static int update_script_drag(struct inst_info *inst, struct block *block, int is_pd)
622 {
623         struct script_info *info;
624         double dx, dy;
625         Evas *e;
626
627         if (!block || !block->data || !block->part) {
628                 ErrPrint("block or block->data or block->part is NIL\n");
629                 return LB_STATUS_ERROR_INVALID;
630         }
631
632         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
633         if (!info) {
634                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
635                 return LB_STATUS_ERROR_FAULT;
636         }
637
638         if (sscanf(block->data, "%lfx%lf", &dx, &dy) != 2) {
639                 ErrPrint("Invalid format of data (DRAG data [%s])\n", block->data);
640                 return LB_STATUS_ERROR_INVALID;
641         }
642
643         if (!info->port) {
644                 ErrPrint("info->port is NIL\n");
645                 return LB_STATUS_ERROR_INVALID;
646         }
647
648         e = script_handler_evas(info);
649         if (e)
650                 info->port->update_drag(info->port_data, e, block->id, block->part, dx, dy);
651         else
652                 ErrPrint("Evas(nil) id[%s] part[%s] %lfx%lf\n", block->id, block->part, dx, dy);
653         return LB_STATUS_SUCCESS;
654 }
655
656 HAPI int script_handler_resize(struct script_info *info, int w, int h)
657 {
658         if (!info) {
659         //|| (info->w == w && info->h == h)) {
660                 ErrPrint("info[%p] resize is ignored\n", info);
661                 return LB_STATUS_SUCCESS;
662         }
663
664         fb_resize(script_handler_fb(info), w, h);
665
666         if (info->port->update_size) {
667                 Evas *e;
668                 e = script_handler_evas(info);
669                 if (e)
670                         info->port->update_size(info->port_data, e, NULL , w, h);
671                 else
672                         ErrPrint("Evas(nil) resize to %dx%d\n", w, h);
673         }
674
675         if (instance_lb_script(info->inst) == info) {
676                 instance_set_lb_size(info->inst, w, h);
677         } else if (instance_pd_script(info->inst) == info) {
678                 instance_set_pd_size(info->inst, w, h);
679         } else {
680                 ErrPrint("Script is not known\n");
681         }
682
683         info->w = w;
684         info->h = h;
685
686         return LB_STATUS_SUCCESS;
687 }
688
689 static int update_info(struct inst_info *inst, struct block *block, int is_pd)
690 {
691         struct script_info *info;
692
693         if (!block || !block->part || !block->data) {
694                 ErrPrint("block or block->part or block->data is NIL\n");
695                 return LB_STATUS_ERROR_INVALID;
696         }
697
698         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
699         if (!info) {
700                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
701                 return LB_STATUS_ERROR_FAULT;
702         }
703
704         if (!info->port) {
705                 ErrPrint("info->port is NIL\n");
706                 return LB_STATUS_ERROR_INVALID;
707         }
708
709         if (!strcasecmp(block->part, INFO_SIZE)) {
710                 Evas_Coord w, h;
711
712                 if (sscanf(block->data, "%dx%d", &w, &h) != 2) {
713                         ErrPrint("Invalid format for SIZE(%s)\n", block->data);
714                         return LB_STATUS_ERROR_INVALID;
715                 }
716
717                 if (!block->id) {
718                         script_handler_resize(info, w, h);
719                 } else {
720                         Evas *e;
721                         e = script_handler_evas(info);
722                         if (e)
723                                 info->port->update_size(info->port_data, e, block->id, w, h);
724                         else
725                                 ErrPrint("Evas(nil): id[%s] %dx%d\n", block->id, w, h);
726                 }
727         } else if (!strcasecmp(block->part, INFO_CATEGORY)) {
728                 Evas *e;
729                 e = script_handler_evas(info);
730                 if (e)
731                         info->port->update_category(info->port_data, e, block->id, block->data);
732                 else
733                         ErrPrint("Evas(nil): id[%s] data[%s]\n", block->id, block->data);
734         }
735
736         return LB_STATUS_SUCCESS;
737 }
738
739 static inline void consuming_parsed_block(int lineno, struct inst_info *inst, int is_pd, struct block *block)
740 {
741         struct script_info *info;
742         /*!
743          * To speed up, use the static.
744          * But this will increase the memory slightly.
745          */
746         static struct {
747                 const char *type;
748                 int (*handler)(struct inst_info *inst, struct block *block, int is_pd);
749         } handlers[] = {
750                 {
751                         .type = TYPE_COLOR,
752                         .handler = update_script_color,
753                 },
754                 {
755                         .type = TYPE_TEXT,
756                         .handler = update_script_text,
757                 },
758                 {
759                         .type = TYPE_IMAGE,
760                         .handler = update_script_image,
761                 },
762                 {
763                         .type = TYPE_EDJE,
764                         .handler = update_script_script,
765                 },
766                 {
767                         .type = TYPE_SIGNAL,
768                         .handler = update_script_signal,
769                 },
770                 {
771                         .type = TYPE_DRAG,
772                         .handler = update_script_drag,
773                 },
774                 {
775                         .type = TYPE_INFO,
776                         .handler = update_info,
777                 },
778                 {
779                         .type = TYPE_ACCESS,
780                         .handler = update_access,
781                 },
782                 {
783                         .type = NULL,
784                         .handler = NULL,
785                 },
786         };
787
788         info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
789         if (!info) {
790                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
791                 goto free_out;
792         }
793
794         if (script_handler_is_loaded(info)) {
795                 register int i = 0;
796
797                 while (handlers[i].type) {
798                         if (!strcasecmp(handlers[i].type, block->type)) {
799                                 handlers[i].handler(inst, block, is_pd);
800                                 break;
801                         }
802                         i++;
803                 }
804
805                 if (!handlers[i].type)
806                         ErrPrint("%d: Unknown block type: %s\n", lineno, block->type);
807
808                 goto free_out;
809         } else {
810                 info->cached_blocks = eina_list_append(info->cached_blocks, block);
811                 DbgPrint("%d: Block is cached (%p), %d, %s\n", lineno, block, eina_list_count(info->cached_blocks), instance_id(inst));
812         }
813
814         return;
815
816 free_out:
817         delete_block(block);
818 }
819
820 HAPI int script_handler_parse_desc(const char *pkgname, const char *id, const char *descfile, int is_pd)
821 {
822         struct inst_info *inst;
823         FILE *fp;
824         int ch;
825         int lineno;
826         enum state {
827                 UNKNOWN = 0x10,
828                 BLOCK_OPEN = 0x11,
829                 FIELD = 0x12,
830                 VALUE = 0x13,
831                 BLOCK_CLOSE = 0x14,
832
833                 VALUE_TYPE = 0x00,
834                 VALUE_PART = 0x01,
835                 VALUE_DATA = 0x02,
836                 VALUE_FILE = 0x03,
837                 VALUE_OPTION = 0x04,
838                 VALUE_ID = 0x05,
839                 VALUE_TARGET = 0x06,
840         };
841         const char *field_name[] = {
842                 "type",
843                 "part",
844                 "data",
845                 "file",
846                 "option",
847                 "id",
848                 "target",
849                 NULL
850         };
851         enum state state;
852         register int field_idx;
853         register int idx = 0;
854         struct block *block;
855
856         block = NULL;
857         inst = package_find_instance_by_id(pkgname, id);
858         if (!inst) {
859                 ErrPrint("Instance is not exists\n");
860                 return LB_STATUS_ERROR_NOT_EXIST;
861         }
862
863         fp = fopen(descfile, "rt");
864         if (!fp) {
865                 ErrPrint("Error: %s [%s]\n", descfile, strerror(errno));
866                 return LB_STATUS_ERROR_IO;
867         }
868
869         DbgPrint("Start parsing %s\n", descfile);
870
871         state = UNKNOWN;
872         field_idx = 0;
873         lineno = 1;
874
875         block = NULL;
876         while (!feof(fp)) {
877                 ch = getc(fp);
878                 if (ch == '\n')
879                         lineno++;
880
881                 switch (state) {
882                 case UNKNOWN:
883                         if (ch == '{') {
884                                 state = BLOCK_OPEN;
885                                 break;
886                         }
887
888                         if (!isspace(ch) && ch != EOF) {
889                                 ErrPrint("%d: Syntax error: Desc is not started with '{' or space - (%c = 0x%x)\n", lineno, ch, ch);
890                                 if (fclose(fp) != 0)
891                                         ErrPrint("fclose: %s\n", strerror(errno));
892                                 return LB_STATUS_ERROR_INVALID;
893                         }
894                         break;
895
896                 case BLOCK_OPEN:
897                         if (isblank(ch))
898                                 break;
899
900                         if (ch != '\n') {
901                                 ErrPrint("%d: Syntax error: New line must has to be started right after '{'\n", lineno);
902                                 goto errout;
903                         }
904
905                         block = calloc(1, sizeof(*block));
906                         if (!block) {
907                                 ErrPrint("Heap: %s\n", strerror(errno));
908                                 if (fclose(fp) != 0)
909                                         ErrPrint("fclose: %s\n", strerror(errno));
910                                 return LB_STATUS_ERROR_MEMORY;
911                         }
912
913                         state = FIELD;
914                         idx = 0;
915                         field_idx = 0;
916                         break;
917
918                 case FIELD:
919                         if (isspace(ch))
920                                 break;
921
922                         if (ch == '}') {
923                                 state = BLOCK_CLOSE;
924                                 break;
925                         }
926
927                         if (ch == '=') {
928                                 if (field_name[field_idx][idx] != '\0') {
929                                         ErrPrint("%d: Syntax error: Unrecognized field\n", lineno);
930                                         goto errout;
931                                 }
932
933                                 switch (field_idx) {
934                                 case 0:
935                                         state = VALUE_TYPE;
936                                         if (block->type) {
937                                                 DbgFree(block->type);
938                                                 block->type = NULL;
939                                                 block->type_len = 0;
940                                         }
941                                         idx = 0;
942                                         break;
943                                 case 1:
944                                         state = VALUE_PART;
945                                         if (block->part) {
946                                                 DbgFree(block->part);
947                                                 block->part = NULL;
948                                                 block->part_len = 0;
949                                         }
950                                         idx = 0;
951                                         break;
952                                 case 2:
953                                         state = VALUE_DATA;
954                                         if (block->data) {
955                                                 DbgFree(block->data);
956                                                 block->data = NULL;
957                                                 block->data_len = 0;
958                                         }
959                                         idx = 0;
960                                         break;
961                                 case 3:
962                                         state = VALUE_FILE;
963                                         if (block->file) {
964                                                 DbgFree(block->file);
965                                                 block->file = NULL;
966                                                 block->file_len = 0;
967                                         }
968                                         idx = 0;
969                                         break;
970                                 case 4:
971                                         state = VALUE_OPTION;
972                                         if (block->option) {
973                                                 DbgFree(block->option);
974                                                 block->option = NULL;
975                                                 block->option_len = 0;
976                                         }
977                                         idx = 0;
978                                         break;
979                                 case 5:
980                                         state = VALUE_ID;
981                                         if (block->id) {
982                                                 DbgFree(block->id);
983                                                 block->id = NULL;
984                                                 block->id_len = 0;
985                                         }
986                                         idx = 0;
987                                         break;
988                                 case 6:
989                                         state = VALUE_TARGET;
990                                         if (block->target_id) {
991                                                 DbgFree(block->target_id);
992                                                 block->target_id = NULL;
993                                                 block->target_len = 0;
994                                         }
995                                         idx = 0;
996                                         break;
997                                 default:
998                                         ErrPrint("%d: Syntax error: Unrecognized field\n", lineno);
999                                         goto errout;
1000                                 }
1001
1002                                 break;
1003                         }
1004
1005                         if (ch == '\n')
1006                                 goto errout;
1007
1008                         if (field_name[field_idx][idx] != ch) {
1009                                 ungetc(ch, fp);
1010                                 if (ch == '\n')
1011                                         lineno--;
1012
1013                                 while (--idx >= 0)
1014                                         ungetc(field_name[field_idx][idx], fp);
1015
1016                                 field_idx++;
1017                                 if (field_name[field_idx] == NULL) {
1018                                         ErrPrint("%d: Syntax error: Unrecognized field\n", lineno);
1019                                         goto errout;
1020                                 }
1021
1022                                 idx = 0;
1023                                 break;
1024                         }
1025
1026                         idx++;
1027                         break;
1028
1029                 case VALUE_TYPE:
1030                         if (idx == block->type_len) {
1031                                 char *tmp;
1032                                 block->type_len += ADDEND;
1033                                 tmp = realloc(block->type, block->type_len);
1034                                 if (!tmp) {
1035                                         ErrPrint("Heap: %s\n", strerror(errno));
1036                                         goto errout;
1037                                 }
1038                                 block->type = tmp;
1039                         }
1040
1041                         if (ch == '\n') {
1042                                 block->type[idx] = '\0';
1043                                 state = FIELD;
1044                                 idx = 0;
1045                                 field_idx = 0;
1046                                 break;
1047                         }
1048
1049                         block->type[idx] = ch;
1050                         idx++;
1051                         break;
1052
1053                 case VALUE_PART:
1054                         if (idx == block->part_len) {
1055                                 char *tmp;
1056                                 block->part_len += ADDEND;
1057                                 tmp = realloc(block->part, block->part_len);
1058                                 if (!tmp) {
1059                                         ErrPrint("Heap: %s\n", strerror(errno));
1060                                         goto errout;
1061                                 }
1062                                 block->part = tmp;
1063                         }
1064
1065                         if (ch == '\n') {
1066                                 block->part[idx] = '\0';
1067                                 state = FIELD;
1068                                 idx = 0;
1069                                 field_idx = 0;
1070                                 break;
1071                         }
1072
1073                         block->part[idx] = ch;
1074                         idx++;
1075                         break;
1076
1077                 case VALUE_DATA:
1078                         if (idx == block->data_len) {
1079                                 char *tmp;
1080                                 block->data_len += ADDEND;
1081                                 tmp = realloc(block->data, block->data_len);
1082                                 if (!tmp) {
1083                                         ErrPrint("Heap: %s\n", strerror(errno));
1084                                         goto errout;
1085                                 }
1086                                 block->data = tmp;
1087                         }
1088
1089                         if (ch == '\n') {
1090                                 block->data[idx] = '\0';
1091                                 state = FIELD;
1092                                 idx = 0;
1093                                 field_idx = 0;
1094                                 break;
1095                         }
1096
1097                         block->data[idx] = ch;
1098                         idx++;
1099                         break;
1100
1101                 case VALUE_FILE:
1102                         if (idx == block->file_len) {
1103                                 char *tmp;
1104                                 block->file_len += ADDEND;
1105                                 tmp = realloc(block->file, block->file_len);
1106                                 if (!tmp) {
1107                                         ErrPrint("Heap: %s\n", strerror(errno));
1108                                         goto errout;
1109                                 }
1110                                 block->file = tmp;
1111                         }
1112
1113                         if (ch == '\n') {
1114                                 block->file[idx] = '\0';
1115                                 state = FIELD;
1116                                 idx = 0;
1117                                 field_idx = 0;
1118                                 break;
1119                         }
1120
1121                         block->file[idx] = ch;
1122                         idx++;
1123                         break;
1124
1125                 case VALUE_OPTION:
1126                         if (idx == block->option_len) {
1127                                 char *tmp;
1128                                 block->option_len += ADDEND;
1129                                 tmp = realloc(block->option, block->option_len);
1130                                 if (!tmp) {
1131                                         ErrPrint("Heap: %s\n", strerror(errno));
1132                                         goto errout;
1133                                 }
1134                                 block->option = tmp;
1135                         }
1136
1137                         if (ch == '\n') {
1138                                 block->option[idx] = '\0';
1139                                 state = FIELD;
1140                                 idx = 0;
1141                                 field_idx = 0;
1142                                 break;
1143                         }
1144
1145                         block->option[idx] = ch;
1146                         idx++;
1147                         break;
1148                 case VALUE_ID:
1149                         if (idx == block->id_len) {
1150                                 char *tmp;
1151                                 block->id_len += ADDEND;
1152                                 tmp = realloc(block->id, block->id_len);
1153                                 if (!tmp) {
1154                                         ErrPrint("Heap: %s\n", strerror(errno));
1155                                         goto errout;
1156                                 }
1157                                 block->id = tmp;
1158                         }
1159
1160                         if (ch == '\n') {
1161                                 block->id[idx] = '\0';
1162                                 state = FIELD;
1163                                 idx = 0;
1164                                 field_idx = 0;
1165                                 break;
1166                         }
1167
1168                         block->id[idx] = ch;
1169                         idx++;
1170                         break;
1171                 case VALUE_TARGET:
1172                         if (idx == block->target_len) {
1173                                 char *tmp;
1174                                 block->target_len += ADDEND;
1175                                 tmp = realloc(block->target_id, block->target_len);
1176                                 if (!tmp) {
1177                                         ErrPrint("Heap: %s\n", strerror(errno));
1178                                         goto errout;
1179                                 }
1180                                 block->target_id = tmp;
1181                         }
1182
1183                         if (ch == '\n') {
1184                                 block->target_id[idx] = '\0';
1185                                 state = FIELD;
1186                                 idx = 0;
1187                                 field_idx = 0;
1188                                 break;
1189                         }
1190
1191                         block->target_id[idx] = ch;
1192                         idx++;
1193                         break;
1194                 case BLOCK_CLOSE:
1195                         if (!block->file) {
1196                                 block->file = strdup(util_uri_to_path(id));
1197                                 if (!block->file) {
1198                                         ErrPrint("Heap: %s\n", strerror(errno));
1199                                         goto errout;
1200                                 }
1201                         }
1202
1203                         consuming_parsed_block(lineno, inst, is_pd, block);
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 */