Imported Upstream version 1.7.4
[platform/upstream/edje.git] / src / bin / edje_cc_out.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #ifdef STDC_HEADERS
6 # include <stdlib.h>
7 # include <stddef.h>
8 #else
9 # ifdef HAVE_STDLIB_H
10 #  include <stdlib.h>
11 # endif
12 #endif
13 #ifdef HAVE_ALLOCA_H
14 # include <alloca.h>
15 #elif !defined alloca
16 # ifdef __GNUC__
17 #  define alloca __builtin_alloca
18 # elif defined _AIX
19 #  define alloca __alloca
20 # elif defined _MSC_VER
21 #  include <malloc.h>
22 #  define alloca _alloca
23 # elif !defined HAVE_ALLOCA
24 #  ifdef  __cplusplus
25 extern "C"
26 #  endif
27 void *alloca (size_t);
28 # endif
29 #endif
30
31 #include <string.h>
32 #include <limits.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35
36 #include <Ecore_Evas.h>
37
38 #include "edje_cc.h"
39 #include "edje_convert.h"
40 #include "edje_multisense_convert.h"
41
42 #include <lua.h>
43 #include <lauxlib.h>
44
45 typedef struct _External_Lookup External_Lookup;
46 typedef struct _Part_Lookup Part_Lookup;
47 typedef struct _Program_Lookup Program_Lookup;
48 typedef struct _Group_Lookup Group_Lookup;
49 typedef struct _Image_Lookup Image_Lookup;
50 typedef struct _Slave_Lookup Slave_Lookup;
51 typedef struct _Code_Lookup Code_Lookup;
52
53
54 struct _External_Lookup
55 {
56    char *name;
57 };
58
59 struct _Part_Lookup
60 {
61    Edje_Part_Collection *pc;
62    char *name;
63    int *dest;
64 };
65
66 struct _Program_Lookup
67 {
68    Edje_Part_Collection *pc;
69
70    union
71    {
72       char *name;
73       Edje_Program *ep;
74    } u;
75
76    int *dest;
77
78    Eina_Bool anonymous : 1;
79 };
80
81 struct _Group_Lookup
82 {
83    char *name;
84    Edje_Part *part;
85 };
86
87 struct _String_Lookup
88 {
89    char *name;
90    int *dest;
91 };
92
93 struct _Image_Lookup
94 {
95    char *name;
96    int *dest;
97    Eina_Bool *set;
98 };
99
100 struct _Slave_Lookup
101 {
102    int *master;
103    int *slave;
104 };
105
106 struct _Code_Lookup
107 {
108    char *ptr;
109    int   len;
110    int   val;
111    Eina_Bool set;
112 };
113
114 typedef struct _Script_Lua_Writer Script_Lua_Writer;
115
116 struct _Script_Lua_Writer
117 {
118    char *buf;
119    int size;
120 };
121
122 typedef struct _Script_Write Script_Write;;
123 typedef struct _Head_Write Head_Write;
124 typedef struct _Fonts_Write Fonts_Write;
125 typedef struct _Image_Write Image_Write;
126 typedef struct _Sound_Write Sound_Write;
127 typedef struct _Group_Write Group_Write;
128
129 struct _Script_Write
130 {
131    Eet_File *ef;
132    Code *cd;
133    int i;
134    Ecore_Exe *exe;
135    int tmpn_fd, tmpo_fd;
136    char tmpn[PATH_MAX];
137    char tmpo[PATH_MAX];
138    char *errstr;
139 };
140
141 struct _Head_Write
142 {
143    Eet_File *ef;
144    char *errstr;
145 };
146
147 struct _Fonts_Write
148 {
149    Eet_File *ef;
150    Font *fn;
151    char *errstr;
152 };
153
154 struct _Image_Write
155 {
156    Eet_File *ef;
157    Edje_Image_Directory_Entry *img;
158    Evas_Object *im;
159    int w, h;
160    int alpha;
161    unsigned int *data;
162    char *path;
163    char *errstr;
164 };
165
166 struct _Sound_Write
167 {
168    Eet_File *ef;
169    Edje_Sound_Sample *sample;
170    int i;
171 };
172
173 struct _Group_Write
174 {
175    Eet_File *ef;
176    Edje_Part_Collection *pc;
177    char *errstr;
178 };
179
180 static int pending_threads = 0;
181
182 static void data_process_string(Edje_Part_Collection *pc, const char *prefix, char *s, void (*func)(Edje_Part_Collection *pc, char *name, char* ptr, int len));
183
184 Edje_File *edje_file = NULL;
185 Eina_List *edje_collections = NULL;
186 Eina_List *externals = NULL;
187 Eina_List *fonts = NULL;
188 Eina_List *codes = NULL;
189 Eina_List *code_lookups = NULL;
190 Eina_List *aliases = NULL;
191
192 static Eet_Data_Descriptor *edd_edje_file = NULL;
193 static Eet_Data_Descriptor *edd_edje_part_collection = NULL;
194
195 static Eina_List *part_lookups = NULL;
196 static Eina_List *program_lookups = NULL;
197 static Eina_List *group_lookups = NULL;
198 static Eina_List *image_lookups = NULL;
199 static Eina_List *part_slave_lookups = NULL;
200 static Eina_List *image_slave_lookups= NULL;
201
202 void
203 error_and_abort(Eet_File *ef __UNUSED__, const char *fmt, ...)
204 {
205    va_list ap;
206
207    va_start(ap, fmt);
208    eina_log_vprint(_edje_cc_log_dom, EINA_LOG_LEVEL_CRITICAL,
209                    "unknown", "unknown", 0, fmt, ap);
210    va_end(ap);
211    unlink(file_out);
212    exit(-1);
213 }
214
215 void
216 data_setup(void)
217 {
218    edd_edje_file = _edje_edd_edje_file;
219    edd_edje_part_collection = _edje_edd_edje_part_collection;
220 }
221
222 static void
223 check_image_part_desc(Edje_Part_Collection *pc, Edje_Part *ep,
224                       Edje_Part_Description_Image *epd, Eet_File *ef)
225 {
226    unsigned int i;
227
228    /* FIXME: This check sounds like not a useful one */
229    if (epd->image.id == -1 && epd->common.visible)
230      WRN("Collection %s(%i): image attributes missing for "
231          "part \"%s\", description \"%s\" %f",
232          pc->part, pc->id, ep->name, epd->common.state.name, epd->common.state.value);
233
234    for (i = 0; i < epd->image.tweens_count; ++i)
235      {
236         if (epd->image.tweens[i]->id == -1)
237           error_and_abort(ef, "Collection %i: tween image id missing for "
238                           "part \"%s\", description \"%s\" %f",
239                           pc->id, ep->name, epd->common.state.name, epd->common.state.value);
240     }
241 }
242
243 static void
244 check_packed_items(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef)
245 {
246    unsigned int i;
247
248    for (i = 0; i < ep->items_count; ++i)
249      {
250         if (ep->items[i]->type == EDJE_PART_TYPE_GROUP && !ep->items[i]->source)
251           error_and_abort(ef, "Collection %i: missing source on packed item "
252                           "of type GROUP in part \"%s\"",
253                           pc->id, ep->name);
254         if (ep->type == EDJE_PART_TYPE_TABLE && (ep->items[i]->col < 0 || ep->items[i]->row < 0))
255           error_and_abort(ef, "Collection %i: missing col/row on packed item "
256                           "for part \"%s\" of type TABLE",
257                           pc->id, ep->name);
258      }
259 }
260
261 static void
262 check_nameless_state(Edje_Part_Collection *pc, Edje_Part *ep, Edje_Part_Description_Common *ed, Eet_File *ef)
263 {
264    if (!ed->state.name)
265       error_and_abort(ef, "Collection %i: description with state missing on part \"%s\"",
266                       pc->id, ep->name);
267 }
268
269 static void
270 check_part(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef)
271 {
272    unsigned int i;
273    /* FIXME: check image set and sort them. */
274    if (!ep->default_desc)
275      error_and_abort(ef, "Collection %i: default description missing "
276                      "for part \"%s\"", pc->id, ep->name);
277
278    for (i = 0; i < ep->other.desc_count; ++i)
279      check_nameless_state(pc, ep, ep->other.desc[i], ef);
280
281    if (ep->type == EDJE_PART_TYPE_IMAGE)
282      {
283         check_image_part_desc(pc, ep, (Edje_Part_Description_Image*) ep->default_desc, ef);
284
285         for (i = 0; i < ep->other.desc_count; ++i)
286           check_image_part_desc (pc, ep, (Edje_Part_Description_Image*) ep->other.desc[i], ef);
287      }
288    else if ((ep->type == EDJE_PART_TYPE_BOX) ||
289             (ep->type == EDJE_PART_TYPE_TABLE))
290      check_packed_items(pc, ep, ef);
291
292    /* FIXME: When mask are supported remove this check */
293    if (ep->clip_to_id != -1 &&
294        pc->parts[ep->clip_to_id]->type != EDJE_PART_TYPE_RECTANGLE)
295      error_and_abort(ef, "Collection %i: clip_to point to a non RECT part '%s' !",
296                      pc->id, pc->parts[ep->clip_to_id]->name);
297 }
298
299 static void
300 check_program(Edje_Part_Collection *pc, Edje_Program *ep, Eet_File *ef)
301 {
302    switch (ep->action)
303      {
304       case EDJE_ACTION_TYPE_STATE_SET:
305       case EDJE_ACTION_TYPE_ACTION_STOP:
306       case EDJE_ACTION_TYPE_DRAG_VAL_SET:
307       case EDJE_ACTION_TYPE_DRAG_VAL_STEP:
308       case EDJE_ACTION_TYPE_DRAG_VAL_PAGE:
309          if (!ep->targets)
310            error_and_abort(ef, "Collection %i: target missing in program "
311                            "\"%s\"", pc->id, ep->name);
312          break;
313       default:
314          break;
315      }
316 }
317
318 static void
319 data_thread_head(void *data, Ecore_Thread *thread __UNUSED__)
320 {
321    Head_Write *hw = data;
322    int bytes = 0;
323    char buf[PATH_MAX];
324
325    if (edje_file)
326      {
327         if (edje_file->collection)
328           {
329              Edje_Part_Collection_Directory_Entry *ce;
330
331              EINA_LIST_FREE(aliases, ce)
332                {
333                   Edje_Part_Collection_Directory_Entry *sce;
334                   Eina_Iterator *it;
335
336                   if (!ce->entry)
337                     {
338                        snprintf(buf, sizeof(buf),
339                                 "Collection %i: name missing.", ce->id);
340                        hw->errstr = strdup(buf);
341                        return;
342                     }
343
344                   it = eina_hash_iterator_data_new(edje_file->collection);
345
346                   EINA_ITERATOR_FOREACH(it, sce)
347                     {
348                        if (ce->id == sce->id)
349                          {
350                             memcpy(&ce->count, &sce->count, sizeof (ce->count));
351                             break;
352                          }
353                     }
354
355                   if (!sce)
356                     {
357                        snprintf(buf, sizeof(buf),
358                                 "Collection %s (%i) can't find an correct alias.",
359                                 ce->entry, ce->id);
360                        hw->errstr = strdup(buf);
361                        return;
362                     }
363                   eina_iterator_free(it);
364                   eina_hash_direct_add(edje_file->collection, ce->entry, ce);
365                }
366           }
367         bytes = eet_data_write(hw->ef, edd_edje_file, "edje/file", edje_file,
368                                compress_mode);
369         if (bytes <= 0)
370           {
371              snprintf(buf, sizeof(buf),
372                       "Unable to write \"edje_file\" entry to \"%s\"",
373                       file_out);
374              hw->errstr = strdup(buf);
375              return;
376           }
377      }
378
379    INF("Wrote %9i bytes (%4iKb) for \"edje_file\" header",
380        bytes, (bytes + 512) / 1024);
381 }
382
383 static void
384 data_thread_head_end(void *data, Ecore_Thread *thread __UNUSED__)
385 {
386    Head_Write *hw = data;
387
388    pending_threads--;
389    if (pending_threads <= 0) ecore_main_loop_quit();
390    if (hw->errstr)
391      {
392         error_and_abort(hw->ef, hw->errstr);
393         free(hw->errstr);
394      }
395    free(hw);
396 }
397
398 static void
399 data_write_header(Eet_File *ef)
400 {
401    Head_Write  *hw;
402
403    hw = calloc(1, sizeof(Head_Write));
404    hw->ef = ef;
405    pending_threads++;
406    if (threads)
407      ecore_thread_run(data_thread_head, data_thread_head_end, NULL, hw);
408    else
409      {
410         data_thread_head(hw, NULL);
411         data_thread_head_end(hw, NULL);
412      }
413 }
414
415 static void
416 data_thread_fonts(void *data, Ecore_Thread *thread __UNUSED__)
417 {
418    Fonts_Write *fc = data;
419    Eina_List *ll;
420    Eina_File *f = NULL;
421    void *m = NULL;
422    int bytes = 0;
423    char buf[PATH_MAX];
424    char buf2[PATH_MAX];
425
426    f = eina_file_open(fc->fn->file, 0);
427    if (f)
428      {
429         using_file(fc->fn->file);
430         m = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
431      }
432    else
433      {
434         char *dat;
435
436         EINA_LIST_FOREACH(fnt_dirs, ll, dat)
437           {
438              snprintf(buf, sizeof(buf), "%s/%s", dat, fc->fn->file);
439              f = eina_file_open(buf, 0);
440              if (f)
441                {
442                   using_file(buf);
443                   m = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
444                   if (m) break;
445                   eina_file_close(f);
446                   f = NULL;
447                }
448           }
449      }
450    if (!m)
451      {
452         if (f) eina_file_close(f);
453         snprintf(buf, sizeof(buf),
454                  "Unable to load font part \"%s\" entry to %s",
455                  fc->fn->file, file_out);
456         fc->errstr = strdup(buf);
457         return;
458      }
459
460    snprintf(buf, sizeof(buf), "edje/fonts/%s", fc->fn->name);
461    bytes = eet_write(fc->ef, buf, m, eina_file_size_get(f), compress_mode);
462
463    if ((bytes <= 0) || eina_file_map_faulted(f, m))
464      {
465         eina_file_map_free(f, m);
466         eina_file_close(f);
467         snprintf(buf2, sizeof(buf2),
468                  "Unable to write font part \"%s\" as \"%s\" "
469                  "part entry to %s", fc->fn->file, buf, file_out);
470         fc->errstr = strdup(buf2);
471         return;
472      }
473
474    INF("Wrote %9i bytes (%4iKb) for \"%s\" font entry \"%s\" compress: [real: %2.1f%%]",
475        bytes, (bytes + 512) / 1024, buf, fc->fn->file,
476        100 - (100 * (double)bytes) / ((double)(eina_file_size_get(f)))
477        );
478    eina_file_map_free(f, m);
479    eina_file_close(f);
480 }
481
482 static void
483 data_thread_fonts_end(void *data, Ecore_Thread *thread __UNUSED__)
484 {
485    Fonts_Write *fc = data;
486    pending_threads--;
487    if (pending_threads <= 0) ecore_main_loop_quit();
488    if (fc->errstr)
489      {
490         error_and_abort(fc->ef, fc->errstr);
491         free(fc->errstr);
492      }
493    free(fc);
494 }
495
496 static void
497 data_write_fonts(Eet_File *ef, int *font_num)
498 {
499    Eina_Iterator *it;
500    Font *fn;
501
502    if (!edje_file->fonts) return;
503
504    it = eina_hash_iterator_data_new(edje_file->fonts);
505    EINA_ITERATOR_FOREACH(it, fn)
506      {
507         Fonts_Write *fc;
508
509         fc = calloc(1, sizeof(Fonts_Write));
510         if (!fc) continue;
511         fc->ef = ef;
512         fc->fn = fn;
513         pending_threads++;
514         if (threads)
515           ecore_thread_run(data_thread_fonts, data_thread_fonts_end, NULL, fc);
516         else
517           {
518              data_thread_fonts(fc, NULL);
519              data_thread_fonts_end(fc, NULL);
520           }
521         *font_num += 1;
522      }
523    eina_iterator_free(it);
524 }
525
526 static void
527 error_and_abort_image_load_error(Eet_File *ef, const char *file, int error)
528 {
529    const char *errmsg = evas_load_error_str(error);
530    char hint[1024] = "";
531
532    if (error == EVAS_LOAD_ERROR_DOES_NOT_EXIST)
533      {
534         snprintf
535           (hint, sizeof(hint),
536            " Check if path to file \"%s\" is correct "
537            "(both directory and file name).",
538            file);
539      }
540    else if (error == EVAS_LOAD_ERROR_CORRUPT_FILE)
541      {
542         snprintf
543           (hint, sizeof(hint),
544            " Check if file \"%s\" is consistent.",
545            file);
546      }
547    else if (error == EVAS_LOAD_ERROR_UNKNOWN_FORMAT)
548      {
549         const char *ext = strrchr(file, '.');
550         const char **itr, *known_loaders[] = {
551           /* list from evas_image_load.c */
552           "png",
553           "jpg",
554           "jpeg",
555           "jfif",
556           "eet",
557           "edj",
558           "eap",
559           "edb",
560           "xpm",
561           "tiff",
562           "tif",
563           "svg",
564           "svgz",
565           "gif",
566           "pbm",
567           "pgm",
568           "ppm",
569           "pnm",
570           "bmp",
571           "ico",
572           "tga",
573           NULL
574         };
575
576         if (!ext)
577           {
578              snprintf
579                (hint, sizeof(hint),
580                 " File \"%s\" does not have an extension, "
581                 "maybe it should?",
582                 file);
583              goto show_err;
584           }
585
586         ext++;
587         for (itr = known_loaders; *itr; itr++)
588           {
589              if (strcasecmp(ext, *itr) == 0)
590                {
591                   snprintf
592                     (hint, sizeof(hint),
593                      " Check if Evas was compiled with %s module enabled and "
594                      "all required dependencies exist.",
595                      ext);
596                   goto show_err;
597                }
598           }
599
600         snprintf(hint, sizeof(hint),
601                  " Check if Evas supports loading files of type \"%s\" (%s) "
602                  "and this module was compiled and all its dependencies exist.",
603                  ext, file);
604      }
605  show_err:
606    error_and_abort
607      (ef, "Unable to load image \"%s\" used by file \"%s\": %s.%s",
608       file, file_out, errmsg, hint);
609 }
610
611 static void
612 data_thread_image(void *data, Ecore_Thread *thread __UNUSED__)
613 {
614    Image_Write *iw = data;
615    char buf[PATH_MAX], buf2[PATH_MAX];
616    unsigned int *start, *end;
617    Eina_Bool opaque = EINA_TRUE;
618    int bytes = 0;
619
620    if ((iw->data) && (iw->w > 0) && (iw->h > 0))
621      {
622         int mode, qual;
623
624         snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
625         qual = 80;
626         if ((iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) &&
627             (iw->img->source_param == 0))
628           mode = 0; /* RAW */
629         else if ((iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) &&
630                  (iw->img->source_param == 1))
631           mode = 1; /* COMPRESS */
632         else
633           mode = 2; /* LOSSY */
634         if ((mode == 0) && (no_raw))
635           {
636              mode = 1; /* promote compression */
637              iw->img->source_param = 95;
638           }
639         if ((mode == 2) && (no_lossy)) mode = 1; /* demote compression */
640         if ((mode == 1) && (no_comp))
641           {
642              if (no_lossy) mode = 0; /* demote compression */
643              else if (no_raw)
644                {
645                   iw->img->source_param = 90;
646                   mode = 2; /* no choice. lossy */
647                }
648           }
649         if (mode == 2)
650           {
651              qual = iw->img->source_param;
652              if (qual < min_quality) qual = min_quality;
653              if (qual > max_quality) qual = max_quality;
654           }
655         if (iw->alpha)
656           {
657              start = (unsigned int *) iw->data;
658              end = start + (iw->w * iw->h);
659              while (start < end)
660                {
661                   if ((*start & 0xff000000) != 0xff000000)
662                     {
663                        opaque = EINA_FALSE;
664                        break;
665                     }
666                   start++;
667                }
668              if (opaque) iw->alpha = 0;
669           }
670         if (mode == 0)
671           bytes = eet_data_image_write(iw->ef, buf,
672                                        iw->data, iw->w, iw->h,
673                                        iw->alpha,
674                                        0, 0, 0);
675         else if (mode == 1)
676           bytes = eet_data_image_write(iw->ef, buf,
677                                        iw->data, iw->w, iw->h,
678                                        iw->alpha,
679                                        compress_mode,
680                                        0, 0);
681         else if (mode == 2)
682           bytes = eet_data_image_write(iw->ef, buf,
683                                        iw->data, iw->w, iw->h,
684                                        iw->alpha,
685                                        0, qual, 1);
686         if (bytes <= 0)
687           {
688              snprintf(buf2, sizeof(buf2),
689                       "Unable to write image part "
690                       "\"%s\" as \"%s\" part entry to "
691                       "%s", iw->img->entry, buf, file_out);
692              iw->errstr = strdup(buf2);
693              return;
694           }
695      }
696    else
697      {
698         snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
699         snprintf(buf2, sizeof(buf2),
700                  "Unable to load image part "
701                  "\"%s\" as \"%s\" part entry to "
702                  "%s", iw->img->entry, buf, file_out);
703         iw->errstr = strdup(buf2);
704         return;
705      }
706
707    if (eina_log_domain_level_check(_edje_cc_log_dom, EINA_LOG_LEVEL_INFO))
708      {
709         struct stat st;
710
711         if (!iw->path || (stat(iw->path, &st))) st.st_size = 0;
712         INF("Wrote %9i bytes (%4iKb) for \"%s\" image entry \"%s\" compress: [raw: %2.1f%%] [real: %2.1f%%]",
713                bytes, (bytes + 512) / 1024, buf, iw->img->entry,
714                100 - (100 * (double)bytes) / ((double)(iw->w * iw->h * 4)),
715                100 - (100 * (double)bytes) / ((double)(st.st_size))
716               );
717      }
718 }
719
720 static void
721 data_thread_image_end(void *data, Ecore_Thread *thread __UNUSED__)
722 {
723    Image_Write *iw = data;
724
725    pending_threads--;
726    if (pending_threads <= 0) ecore_main_loop_quit();
727    if (iw->errstr)
728      {
729         error_and_abort(iw->ef, iw->errstr);
730         free(iw->errstr);
731      }
732    if (iw->path) free(iw->path);
733    evas_object_del(iw->im);
734    free(iw);
735 }
736
737 static void
738 data_image_preload_done(void *data, Evas *e __UNUSED__, Evas_Object *o, void *event_info __UNUSED__)
739 {
740    Image_Write *iw = data;
741
742    evas_object_image_size_get(o, &iw->w, &iw->h);
743    iw->alpha = evas_object_image_alpha_get(o);
744    iw->data = evas_object_image_data_get(o, 0);
745    if (threads)
746      ecore_thread_run(data_thread_image, data_thread_image_end, NULL, iw);
747    else
748      {
749         data_thread_image(iw, NULL);
750         data_thread_image_end(iw, NULL);
751      }
752 }
753
754 static void
755 data_write_images(Eet_File *ef, int *image_num)
756 {
757    int i;
758    Ecore_Evas *ee;
759    Evas *evas;
760
761    if (!((edje_file) && (edje_file->image_dir))) return;
762
763    ecore_evas_init();
764    ee = ecore_evas_buffer_new(1, 1);
765    if (!ee)
766      error_and_abort(ef, "Cannot create buffer engine canvas for image load.");
767    evas = ecore_evas_get(ee);
768
769    for (i = 0; i < (int)edje_file->image_dir->entries_count; i++)
770      {
771         Edje_Image_Directory_Entry *img;
772
773         img = &edje_file->image_dir->entries[i];
774         if ((img->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) ||
775             (img->entry == NULL))
776           {
777           }
778         else
779           {
780              Evas_Object *im;
781              Eina_List *ll;
782              char *s;
783              int load_err = EVAS_LOAD_ERROR_NONE;
784              Image_Write *iw;
785
786              iw = calloc(1, sizeof(Image_Write));
787              iw->ef = ef;
788              iw->img = img;
789              iw->im = im = evas_object_image_add(evas);
790              if (threads)
791                evas_object_event_callback_add(im,
792                                               EVAS_CALLBACK_IMAGE_PRELOADED,
793                                               data_image_preload_done,
794                                               iw);
795              EINA_LIST_FOREACH(img_dirs, ll, s)
796                {
797                   char buf[PATH_MAX];
798
799                   snprintf(buf, sizeof(buf), "%s/%s", s, img->entry);
800                   evas_object_image_file_set(im, buf, NULL);
801                   load_err = evas_object_image_load_error_get(im);
802                   if (load_err == EVAS_LOAD_ERROR_NONE)
803                     {
804                        *image_num += 1;
805                        iw->path = strdup(buf);
806                        pending_threads++;
807                        if (threads)
808                          evas_object_image_preload(im, 0);
809                        using_file(buf);
810                        if (!threads)
811                          data_image_preload_done(iw, evas, im, NULL);
812                        break;
813                     }
814                }
815              if (load_err != EVAS_LOAD_ERROR_NONE)
816                {
817                   evas_object_image_file_set(im, img->entry, NULL);
818                   load_err = evas_object_image_load_error_get(im);
819                   if (load_err == EVAS_LOAD_ERROR_NONE)
820                     {
821                        *image_num += 1;
822                        iw->path = strdup(img->entry);
823                        pending_threads++;
824                        if (threads)
825                          evas_object_image_preload(im, 0);
826                        using_file(img->entry);
827                        if (!threads)
828                          data_image_preload_done(iw, evas, im, NULL);
829                     }
830                   else
831                     error_and_abort_image_load_error
832                     (ef, img->entry, load_err);
833                }
834           }
835      }
836 }
837
838 static void
839 data_thread_sounds(void *data, Ecore_Thread *thread __UNUSED__)
840 {
841    Sound_Write *sw = data;
842    Eina_List *ll;
843 #ifdef HAVE_LIBSNDFILE
844    Edje_Sound_Encode *enc_info;
845 #endif
846    char *dir_path = NULL;
847    char snd_path[PATH_MAX];
848    char sndid_str[15];
849    Eina_File *f = NULL;
850    void *m = NULL;
851    int bytes = 0;
852
853    // Search the Sound file in all the -sd ( sound directory )
854    EINA_LIST_FOREACH(snd_dirs, ll, dir_path)
855      {
856         snprintf((char *)snd_path, sizeof(snd_path), "%s/%s", dir_path,
857                  sw->sample->snd_src);
858         f = eina_file_open(snd_path, 0);
859         if (f) break;
860      }
861    if (!f)
862      {
863         snprintf((char *)snd_path, sizeof(snd_path), "%s",
864                  sw->sample->snd_src);
865         f = eina_file_open(snd_path, 0);
866      }
867 #ifdef HAVE_LIBSNDFILE
868    if (f) eina_file_close(f);
869    enc_info = _edje_multisense_encode(snd_path, sw->sample,
870                                       sw->sample->quality);
871    f = eina_file_open(enc_info->file, 0);
872    if (f) using_file(enc_info->file);
873 #else
874    if (f) using_file(snd_path);
875 #endif
876    if (!f)
877      {
878         ERR("Unable to load sound data of: %s", sw->sample->name);
879         exit(-1);
880      }
881
882    snprintf(sndid_str, sizeof(sndid_str), "edje/sounds/%i", sw->sample->id);
883    m = eina_file_map_all(f, EINA_FILE_WILLNEED);
884    if (m)
885      {
886         bytes = eet_write(sw->ef, sndid_str, m, eina_file_size_get(f),
887                           EET_COMPRESSION_NONE);
888         if (eina_file_map_faulted(f, m))
889           {
890              ERR("File access error when reading '%s'",
891                  eina_file_filename_get(f));
892              exit(-1);
893           }
894         eina_file_map_free(f, m);
895      }
896    eina_file_close(f);
897
898 #ifdef HAVE_LIBSNDFILE
899    //If encoded temporary file, delete it.
900    if (enc_info->encoded) unlink(enc_info->file);
901 #endif
902 #ifdef HAVE_LIBSNDFILE
903    INF("Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry \"%s\"",
904        bytes, (bytes + 512) / 1024,
905        sndid_str, enc_info->comp_type, sw->sample->name);
906 #else
907    INF("Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry \"%s\"",
908        bytes, (bytes + 512) / 1024,
909        sndid_str, "RAW PCM", sw->sample->name);
910 #endif
911
912 #ifdef HAVE_LIBSNDFILE
913    if ((enc_info->file) && (!enc_info->encoded))
914      eina_stringshare_del(enc_info->file);
915    if (enc_info) free(enc_info);
916    enc_info = NULL;
917 #endif
918 }
919
920 static void
921 data_thread_sounds_end(void *data, Ecore_Thread *thread __UNUSED__)
922 {
923    Sound_Write *sw = data;
924    pending_threads--;
925    if (pending_threads <= 0) ecore_main_loop_quit();
926    free(sw);
927 }
928
929 static void
930 data_write_sounds(Eet_File *ef, int *sound_num)
931 {
932    if ((edje_file) && (edje_file->sound_dir))
933      {
934         int i;
935
936         for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
937           {
938              Sound_Write *sw;
939
940              sw = calloc(1, sizeof(Sound_Write));
941              if (!sw) continue;
942              sw->ef = ef;
943              sw->sample = &edje_file->sound_dir->samples[i];
944              sw->i = i;
945              *sound_num += 1;
946              pending_threads++;
947              if (threads)
948                ecore_thread_run(data_thread_sounds, data_thread_sounds_end, NULL, sw);
949              else
950                {
951                   data_thread_sounds(sw, NULL);
952                   data_thread_sounds_end(sw, NULL);
953                }
954           }
955      }
956 }
957
958 static void
959 check_groups(Eet_File *ef)
960 {
961    Edje_Part_Collection *pc;
962    Eina_List *l;
963
964    /* sanity checks for parts and programs */
965    EINA_LIST_FOREACH(edje_collections, l, pc)
966      {
967         unsigned int i;
968
969         for (i = 0; i < pc->parts_count; ++i)
970           check_part(pc, pc->parts[i], ef);
971
972 #define CHECK_PROGRAM(Type, Pc, It)                             \
973         for (It = 0; It < Pc->programs.Type ## _count; ++It)    \
974           check_program(Pc, Pc->programs.Type[i], ef);          \
975
976         CHECK_PROGRAM(fnmatch, pc, i);
977         CHECK_PROGRAM(strcmp, pc, i);
978         CHECK_PROGRAM(strncmp, pc, i);
979         CHECK_PROGRAM(strrncmp, pc, i);
980         CHECK_PROGRAM(nocmp, pc, i);
981      }
982 }
983
984 static void
985 data_thread_group(void *data, Ecore_Thread *thread __UNUSED__)
986 {
987    Group_Write *gw = data;
988    int bytes;
989    char buf[PATH_MAX];
990    char buf2[PATH_MAX];
991
992    snprintf(buf, sizeof(buf), "edje/collections/%i", gw->pc->id);
993    bytes = eet_data_write(gw->ef, edd_edje_part_collection, buf, gw->pc,
994                           compress_mode);
995    return;
996    if (bytes <= 0)
997      {
998         snprintf(buf2, sizeof(buf2),
999                  "Unable to write \"%s\" part entry to %s",
1000                  buf, file_out);
1001         gw->errstr = strdup(buf2);
1002         return;
1003      }
1004
1005    INF("Wrote %9i bytes (%4iKb) for \"%s\" aka \"%s\" collection entry",
1006        bytes, (bytes + 512) / 1024, buf, gw->pc->part);
1007 }
1008
1009 static void
1010 data_thread_group_end(void *data, Ecore_Thread *thread __UNUSED__)
1011 {
1012    Group_Write *gw = data;
1013    pending_threads--;
1014    if (pending_threads <= 0) ecore_main_loop_quit();
1015    if (gw->errstr)
1016      {
1017         error_and_abort(gw->ef, gw->errstr);
1018         free(gw->errstr);
1019      }
1020    free(gw);
1021 }
1022
1023 static void
1024 data_write_groups(Eet_File *ef, int *collection_num)
1025 {
1026    Eina_List *l;
1027    Edje_Part_Collection *pc;
1028
1029    EINA_LIST_FOREACH(edje_collections, l, pc)
1030      {
1031         Group_Write *gw;
1032
1033         gw = calloc(1, sizeof(Group_Write));
1034         if (!gw)
1035           {
1036              error_and_abort(ef, "Cannot allocate memory for group writer");
1037              return;
1038           }
1039         gw->ef = ef;
1040         gw->pc = pc;
1041         pending_threads++;
1042         if (threads)
1043           ecore_thread_run(data_thread_group, data_thread_group_end, NULL, gw);
1044         else
1045           {
1046              data_thread_group(gw, NULL);
1047              data_thread_group_end(gw, NULL);
1048           }
1049         *collection_num += 1;
1050      }
1051 }
1052
1053 static void
1054 create_script_file(Eet_File *ef, const char *filename, const Code *cd, int fd)
1055 {
1056    FILE *f = fdopen(fd, "wb");
1057    if (!f)
1058      error_and_abort(ef, "Unable to open temp file \"%s\" for script "
1059                      "compilation.", filename);
1060
1061    Eina_List *ll;
1062    Code_Program *cp;
1063
1064    fprintf(f, "#include <edje>\n");
1065    int ln = 2;
1066
1067    if (cd->shared)
1068      {
1069         while (ln < (cd->l1 - 1))
1070           {
1071              fprintf(f, " \n");
1072              ln++;
1073           }
1074         {
1075            char *sp;
1076            int hash = 0;
1077            int newlined = 0;
1078
1079            for (sp = cd->shared; *sp; sp++)
1080              {
1081                 if ((sp[0] == '#') && (newlined))
1082                   {
1083                      hash = 1;
1084                   }
1085                 newlined = 0;
1086                 if (sp[0] == '\n') newlined = 1;
1087                 if (!hash) fputc(sp[0], f);
1088                 else if (sp[0] == '\n') hash = 0;
1089              }
1090            fputc('\n', f);
1091         }
1092         ln += cd->l2 - cd->l1 + 1;
1093      }
1094    EINA_LIST_FOREACH(cd->programs, ll, cp)
1095      {
1096         if (cp->script)
1097           {
1098              while (ln < (cp->l1 - 1))
1099                {
1100                   fprintf(f, " \n");
1101                   ln++;
1102                }
1103              /* FIXME: this prototype needs to be */
1104              /* formalised and set in stone */
1105              fprintf(f, "public _p%i(sig[], src[]) {", cp->id);
1106              {
1107                 char *sp;
1108                 int hash = 0;
1109                 int newlined = 0;
1110
1111                 for (sp = cp->script; *sp; sp++)
1112                   {
1113                      if ((sp[0] == '#') && (newlined))
1114                        {
1115                           hash = 1;
1116                        }
1117                      newlined = 0;
1118                      if (sp[0] == '\n') newlined = 1;
1119                      if (!hash) fputc(sp[0], f);
1120                      else if (sp[0] == '\n') hash = 0;
1121                   }
1122              }
1123              fprintf(f, "}\n");
1124              ln += cp->l2 - cp->l1 + 1;
1125           }
1126      }
1127
1128    fclose(f);
1129 }
1130
1131 static void
1132 data_thread_script(void *data, Ecore_Thread *thread __UNUSED__)
1133 {
1134    Script_Write *sc = data;
1135    FILE *f;
1136    int size;
1137    char buf[PATH_MAX];
1138
1139    f = fdopen(sc->tmpo_fd, "rb");
1140    if (!f)
1141      {
1142         snprintf(buf, sizeof(buf),
1143                  "Unable to open script object \"%s\" for reading.",
1144                  sc->tmpo);
1145         sc->errstr = strdup(buf);
1146         return;
1147      }
1148
1149    fseek(f, 0, SEEK_END);
1150    size = ftell(f);
1151    rewind(f);
1152
1153    if (size > 0)
1154      {
1155         void *dat = malloc(size);
1156
1157         if (dat)
1158           {
1159              if (fread(dat, size, 1, f) != 1)
1160                {
1161                   snprintf(buf, sizeof(buf),
1162                            "Unable to read all of script object \"%s\"",
1163                            sc->tmpo);
1164                   sc->errstr = strdup(buf);
1165                   return;
1166                }
1167              snprintf(buf, sizeof(buf), "edje/scripts/embryo/compiled/%i",
1168                       sc->i);
1169              eet_write(sc->ef, buf, dat, size, compress_mode);
1170              free(dat);
1171           }
1172         else
1173           {
1174              snprintf(buf, sizeof(buf),
1175                       "Alloc failed for %lu bytes", (unsigned long)size);
1176              sc->errstr = strdup(buf);
1177              return;
1178           }
1179      }
1180    fclose(f);
1181
1182    if (!no_save)
1183      {
1184         Eina_List *ll;
1185         Code_Program *cp;
1186
1187         if (sc->cd->original)
1188           {
1189              snprintf(buf, PATH_MAX, "edje/scripts/embryo/source/%i", sc->i);
1190              eet_write(sc->ef, buf, sc->cd->original,
1191                        strlen(sc->cd->original) + 1, compress_mode);
1192           }
1193         EINA_LIST_FOREACH(sc->cd->programs, ll, cp)
1194           {
1195              if (!cp->original) continue;
1196              snprintf(buf, PATH_MAX, "edje/scripts/embryo/source/%i/%i",
1197                       sc->i, cp->id);
1198              eet_write(sc->ef, buf, cp->original,
1199                        strlen(cp->original) + 1, compress_mode);
1200           }
1201      }
1202
1203    unlink(sc->tmpn);
1204    unlink(sc->tmpo);
1205    close(sc->tmpn_fd);
1206    close(sc->tmpo_fd);
1207 }
1208
1209 static void
1210 data_thread_script_end(void *data, Ecore_Thread *thread __UNUSED__)
1211 {
1212    Script_Write *sc = data;
1213    pending_threads--;
1214    if (pending_threads <= 0) ecore_main_loop_quit();
1215    if (sc->errstr)
1216      {
1217         error_and_abort(sc->ef, sc->errstr);
1218         free(sc->errstr);
1219      }
1220    free(sc);
1221 }
1222
1223 static Eina_Bool
1224 data_scripts_exe_del_cb(void *data __UNUSED__, int evtype __UNUSED__, void *evinfo)
1225 {
1226    Script_Write *sc = data;
1227    Ecore_Exe_Event_Del *ev = evinfo;
1228
1229    if (!ev->exe) return ECORE_CALLBACK_RENEW;
1230    if (ecore_exe_data_get(ev->exe) != sc) return ECORE_CALLBACK_RENEW;
1231    if (ev->exit_code != 0)
1232      {
1233         error_and_abort(sc->ef, "Compiling script code not clean.");
1234         return ECORE_CALLBACK_CANCEL;
1235      }
1236    if (threads)
1237      {
1238         pending_threads++;
1239         ecore_thread_run(data_thread_script, data_thread_script_end, NULL, sc);
1240      }
1241    else
1242      {
1243         pending_threads++;
1244         data_thread_script(sc, NULL);
1245         data_thread_script_end(sc, NULL);
1246      }
1247    pending_threads--;
1248    if (pending_threads <= 0) ecore_main_loop_quit();
1249    return ECORE_CALLBACK_CANCEL;
1250 }
1251
1252 static void
1253 data_write_scripts(Eet_File *ef)
1254 {
1255    Eina_List *l;
1256    int i;
1257
1258    if (!tmp_dir)
1259 #ifdef HAVE_EVIL
1260      tmp_dir = (char *)evil_tmpdir_get();
1261 #else
1262      tmp_dir = "/tmp";
1263 #endif
1264
1265    for (i = 0, l = codes; l; l = eina_list_next(l), i++)
1266      {
1267         Code *cd = eina_list_data_get(l);
1268         Script_Write *sc;
1269         char buf[PATH_MAX];
1270
1271         if (cd->is_lua)
1272           continue;
1273         if ((!cd->shared) && (!cd->programs))
1274           continue;
1275         sc = calloc(1, sizeof(Script_Write));
1276         sc->ef = ef;
1277         sc->cd = cd;
1278         sc->i = i;
1279         snprintf(sc->tmpn, PATH_MAX, "%s/edje_cc.sma-tmp-XXXXXX", tmp_dir);
1280         sc->tmpn_fd = mkstemp(sc->tmpn);
1281         if (sc->tmpn_fd < 0)
1282           error_and_abort(ef, "Unable to open temp file \"%s\" for script "
1283                           "compilation.", sc->tmpn);
1284         snprintf(sc->tmpo, PATH_MAX, "%s/edje_cc.amx-tmp-XXXXXX", tmp_dir);
1285         sc->tmpo_fd = mkstemp(sc->tmpo);
1286         if (sc->tmpo_fd < 0)
1287           {
1288              unlink(sc->tmpn);
1289              error_and_abort(ef, "Unable to open temp file \"%s\" for script "
1290                              "compilation.", sc->tmpn);
1291           }
1292         create_script_file(ef, sc->tmpn, cd, sc->tmpn_fd);
1293         snprintf(buf, sizeof(buf),
1294                  "%s/embryo_cc -i %s/include -o %s %s",
1295                  eina_prefix_bin_get(pfx),
1296                  eina_prefix_data_get(pfx),
1297                  sc->tmpo, sc->tmpn);
1298         pending_threads++;
1299         sc->exe = ecore_exe_run(buf, sc);
1300         ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
1301                                 data_scripts_exe_del_cb, sc);
1302      }
1303 }
1304
1305 #ifdef LUA_BINARY
1306 static int
1307 _edje_lua_script_writer(lua_State *L __UNUSED__, const void *chunk_buf, size_t chunk_size, void *_data)
1308 {
1309    Script_Lua_Writer *data;
1310    void *old;
1311
1312    data = (Script_Lua_Writer *)_data;
1313    old = data->buf;
1314    data->buf = malloc(data->size + chunk_size);
1315    memcpy(data->buf, old, data->size);
1316    memcpy(&((data->buf)[data->size]), chunk_buf, chunk_size);
1317    if (old) free(old);
1318    data->size += chunk_size;
1319
1320    return 0;
1321 }
1322 #endif
1323
1324 void
1325 _edje_lua_error_and_abort(lua_State *L, int err_code, Script_Write *sc)
1326 {
1327    char buf[PATH_MAX];
1328    char *err_type;
1329
1330    switch (err_code)
1331      {
1332       case LUA_ERRRUN:
1333         err_type = "runtime";
1334         break;
1335       case LUA_ERRSYNTAX:
1336         err_type = "syntax";
1337         break;
1338       case LUA_ERRMEM:
1339         err_type = "memory allocation";
1340         break;
1341       case LUA_ERRERR:
1342         err_type = "error handler";
1343         break;
1344       default:
1345         err_type = "unknown";
1346         break;
1347      }
1348    snprintf(buf, sizeof(buf),
1349             "Lua %s error: %s", err_type, lua_tostring(L, -1));
1350    sc->errstr = strdup(buf);
1351 }
1352
1353 static void
1354 data_thread_lua_script(void *data, Ecore_Thread *thread __UNUSED__)
1355 {
1356    Script_Write *sc = data;
1357    char buf[PATH_MAX];
1358    lua_State *L;
1359    int ln = 1;
1360    luaL_Buffer b;
1361    Script_Lua_Writer dat;
1362    Eina_List *ll;
1363    Code_Program *cp;
1364 #ifdef LUA_BINARY
1365    int err_code;
1366 #endif
1367
1368    L = luaL_newstate();
1369    if (!L)
1370      {
1371         snprintf(buf, sizeof(buf),
1372                  "Lua error: Lua state could not be initialized");
1373         sc->errstr = strdup(buf);
1374         return;
1375      }
1376
1377    luaL_buffinit(L, &b);
1378
1379    dat.buf = NULL;
1380    dat.size = 0;
1381    if (sc->cd->shared)
1382      {
1383         while (ln < (sc->cd->l1 - 1))
1384           {
1385              luaL_addchar(&b, '\n');
1386              ln++;
1387           }
1388         luaL_addstring(&b, sc->cd->shared);
1389         ln += sc->cd->l2 - sc->cd->l1;
1390      }
1391
1392    EINA_LIST_FOREACH(sc->cd->programs, ll, cp)
1393      {
1394         if (cp->script)
1395           {
1396              while (ln < (cp->l1 - 1))
1397                {
1398                   luaL_addchar(&b, '\n');
1399                   ln++;
1400                }
1401              luaL_addstring(&b, "_G[");
1402              lua_pushnumber(L, cp->id);
1403              luaL_addvalue(&b);
1404              luaL_addstring(&b, "] = function (ed, signal, source)");
1405              luaL_addstring(&b, cp->script);
1406              luaL_addstring(&b, "end\n");
1407              ln += cp->l2 - cp->l1 + 1;
1408           }
1409      }
1410    luaL_pushresult(&b);
1411 #ifdef LUA_BINARY
1412    if (err_code = luaL_loadstring(L, lua_tostring (L, -1)))
1413      {
1414         _edje_lua_error_and_abort(L, err_code, sc);
1415         return;
1416      }
1417    lua_dump(L, _edje_lua_script_writer, &dat);
1418 #else // LUA_PLAIN_TEXT
1419    dat.buf = (char *)lua_tostring(L, -1);
1420    dat.size = strlen(dat.buf);
1421 #endif
1422    //printf("lua chunk size: %d\n", dat.size);
1423
1424    /*
1425     * TODO load and test Lua chunk
1426     */
1427
1428    /*
1429     if (luaL_loadbuffer(L, globbuf, globbufsize, "edje_lua_script"))
1430     printf("lua load error: %s\n", lua_tostring (L, -1));
1431     if (lua_pcall(L, 0, 0, 0))
1432     printf("lua call error: %s\n", lua_tostring (L, -1));
1433     */
1434
1435    snprintf(buf, sizeof(buf), "edje/scripts/lua/%i", sc->i);
1436    if (eet_write(sc->ef, buf, dat.buf, dat.size, compress_mode) <= 0)
1437      {
1438         snprintf(buf, sizeof(buf),
1439                  "Unable to write script %i", sc->i);
1440         sc->errstr = strdup(buf);
1441         return;
1442      }
1443 #ifdef LUA_BINARY
1444    free(dat.buf);
1445 #endif
1446    lua_close(L);
1447 }
1448
1449 static void
1450 data_thread_lua_script_end(void *data, Ecore_Thread *thread __UNUSED__)
1451 {
1452    Script_Write *sc = data;
1453    pending_threads--;
1454    if (pending_threads <= 0) ecore_main_loop_quit();
1455    if (sc->errstr)
1456      {
1457         error_and_abort(sc->ef, sc->errstr);
1458         free(sc->errstr);
1459      }
1460    free(sc);
1461 }
1462
1463 static void
1464 data_write_lua_scripts(Eet_File *ef)
1465 {
1466    Eina_List *l;
1467    int i;
1468
1469    for (i = 0, l = codes; l; l = eina_list_next(l), i++)
1470      {
1471         Code *cd;
1472         Script_Write *sc;
1473
1474         cd = (Code *)eina_list_data_get(l);
1475         if (!cd->is_lua)
1476           continue;
1477         if ((!cd->shared) && (!cd->programs))
1478           continue;
1479
1480         sc = calloc(1, sizeof(Script_Write));
1481         sc->ef = ef;
1482         sc->cd = cd;
1483         sc->i = i;
1484         pending_threads++;
1485         if (threads)
1486           ecore_thread_run(data_thread_lua_script, data_thread_lua_script_end, NULL, sc);
1487         else
1488           {
1489              data_thread_lua_script(sc, NULL);
1490              data_thread_lua_script_end(sc, NULL);
1491           }
1492      }
1493 }
1494
1495 static void
1496 data_thread_source(void *data, Ecore_Thread *thread __UNUSED__)
1497 {
1498    Eet_File *ef = data;
1499    source_append(ef);
1500 }
1501
1502 static void
1503 data_thread_source_end(void *data __UNUSED__, Ecore_Thread *thread __UNUSED__)
1504 {
1505    pending_threads--;
1506    if (pending_threads <= 0) ecore_main_loop_quit();
1507 }
1508
1509 static void
1510 data_thread_fontmap(void *data, Ecore_Thread *thread __UNUSED__)
1511 {
1512    Eet_File *ef = data;
1513    source_fontmap_save(ef, fonts);
1514 }
1515
1516 static void
1517 data_thread_fontmap_end(void *data __UNUSED__, Ecore_Thread *thread __UNUSED__)
1518 {
1519    pending_threads--;
1520    if (pending_threads <= 0) ecore_main_loop_quit();
1521 }
1522
1523 void
1524 data_write(void)
1525 {
1526    Eet_File *ef;
1527    int image_num = 0;
1528    int sound_num = 0;
1529    int font_num = 0;
1530    int collection_num = 0;
1531    double t;
1532
1533    if (!edje_file)
1534      {
1535         ERR("No data to put in \"%s\"", file_out);
1536         exit(-1);
1537      }
1538
1539    ef = eet_open(file_out, EET_FILE_MODE_WRITE);
1540    if (!ef)
1541      {
1542         ERR("Unable to open \"%s\" for writing output", file_out);
1543         exit(-1);
1544      }
1545
1546    check_groups(ef);
1547
1548    ecore_thread_max_set(ecore_thread_max_get() * 2);
1549
1550    pending_threads++;
1551    t = ecore_time_get();
1552    data_write_header(ef);
1553
1554    INF("header: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1555    data_write_groups(ef, &collection_num);
1556    INF("groups: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1557    data_write_scripts(ef);
1558    INF("scripts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1559    data_write_lua_scripts(ef);
1560    INF("lua scripts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1561
1562    pending_threads++;
1563    if (threads)
1564      ecore_thread_run(data_thread_source, data_thread_source_end, NULL, ef);
1565    else
1566      {
1567         data_thread_source(ef, NULL);
1568         data_thread_source_end(ef, NULL);
1569      }
1570    INF("source: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1571    pending_threads++;
1572    if (threads)
1573      ecore_thread_run(data_thread_fontmap, data_thread_fontmap_end, NULL, ef);
1574    else
1575      {
1576         data_thread_fontmap(ef, NULL);
1577         data_thread_fontmap_end(ef, NULL);
1578      }
1579    INF("fontmap: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1580    data_write_images(ef, &image_num);
1581    INF("images: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1582    data_write_fonts(ef, &font_num);
1583    INF("fonts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1584    data_write_sounds(ef, &sound_num);
1585    INF("sounds: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1586    pending_threads--;
1587    if (pending_threads > 0) ecore_main_loop_begin();
1588    INF("THREADS: %3.5f", ecore_time_get() - t); t = ecore_time_get();
1589
1590    eet_close(ef);
1591
1592    if (eina_log_domain_level_check(_edje_cc_log_dom, EINA_LOG_LEVEL_INFO))
1593      {
1594         printf("Summary:\n"
1595                "  Wrote %i collections\n"
1596                "  Wrote %i images\n"
1597                "  Wrote %i sounds\n"
1598                "  Wrote %i fonts\n"
1599                ,
1600                collection_num,
1601                image_num,
1602                sound_num,
1603                font_num);
1604      }
1605 }
1606
1607 void
1608 reorder_parts(void)
1609 {
1610    Edje_Part_Collection *pc;
1611    Edje_Part **parts;
1612    Edje_Part_Parser *ep, *ep2;
1613    Eina_List *l;
1614
1615    /* sanity checks for parts and programs */
1616    EINA_LIST_FOREACH(edje_collections, l, pc)
1617      {
1618         unsigned int i, j, k;
1619         Eina_Bool found = EINA_FALSE;
1620
1621         for (i = 0; i < pc->parts_count; i++)
1622           {
1623              ep = (Edje_Part_Parser *)pc->parts[i];
1624              if (ep->reorder.insert_before && ep->reorder.insert_after)
1625                ERR("Unable to use together insert_before and insert_after in part \"%s\".", pc->parts[i]->name);
1626
1627              if (ep->reorder.done)
1628                {
1629                   continue;
1630                }
1631              if (ep->reorder.insert_before || ep->reorder.insert_after)
1632                {
1633                   found = EINA_FALSE;
1634                   for (j = 0; j < pc->parts_count; j++)
1635                     {
1636                        if (ep->reorder.insert_before &&
1637                            !strcmp(ep->reorder.insert_before, pc->parts[j]->name))
1638                          {
1639                             ep2 = (Edje_Part_Parser *)pc->parts[j];
1640                             if (ep2->reorder.after)
1641                               ERR("The part \"%s\" is ambiguous ordered part.",
1642                                   pc->parts[i]->name);
1643                             if (ep2->reorder.linked_prev)
1644                               ERR("Unable to insert two or more parts in same part \"%s\".",
1645                                   pc->parts[j]->name);
1646                             /* Need it to be able to insert an element before the first */
1647                             if (j == 0) k = 0;
1648                             else k = j - 1;
1649                             found = EINA_TRUE;
1650                             ep2->reorder.linked_prev += ep->reorder.linked_prev + 1;
1651                             ep->reorder.before = (Edje_Part_Parser *)pc->parts[j];
1652                             while (ep2->reorder.before)
1653                               {
1654                                  ep2->reorder.before->reorder.linked_prev = ep2->reorder.linked_prev + 1;
1655                                  ep2 = ep2->reorder.before;
1656                               }
1657                             break;
1658                          }
1659                        else if (ep->reorder.insert_after &&
1660                            !strcmp(ep->reorder.insert_after, pc->parts[j]->name))
1661                          {
1662                             ep2 = (Edje_Part_Parser *)pc->parts[j];
1663                             if (ep2->reorder.before)
1664                               ERR("The part \"%s\" is ambiguous ordered part.", pc->parts[i]->name);
1665                             if (ep2->reorder.linked_next)
1666                               ERR("Unable to insert two or more parts in same part \"%s\".", pc->parts[j]->name);
1667                             k = j;
1668                             found = EINA_TRUE;
1669                             ep2->reorder.linked_next += ep->reorder.linked_next + 1;
1670                             ep->reorder.after = (Edje_Part_Parser *)pc->parts[j];
1671                             while (ep2->reorder.after)
1672                               {
1673                                  ep2->reorder.after->reorder.linked_next = ep2->reorder.linked_next + 1;
1674                                  ep2 = ep2->reorder.after;
1675                               }
1676                             break;
1677                          }
1678                     }
1679                   if (found)
1680                     {
1681                        unsigned int amount, linked;
1682
1683                        if (((i > k) && ((i - ep->reorder.linked_prev) <= k))
1684                            || ((i < k) && ((i + ep->reorder.linked_next) >= k)))
1685                          ERR("The part order is wrong. It has circular dependency.");
1686
1687                        amount = ep->reorder.linked_prev + ep->reorder.linked_next + 1;
1688                        linked = i - ep->reorder.linked_prev;
1689                        parts = malloc(amount * sizeof(Edje_Part));
1690                        for (j = 0 ; j < amount ; j++)
1691                          {
1692                             parts[j] = pc->parts[linked];
1693                             linked++;
1694                          }
1695                        if (i > k)
1696                          {
1697                             for (j = i - ep->reorder.linked_prev ; j > k; j--)
1698                               {
1699                                  pc->parts[j + amount - 1] = pc->parts[j - 1];
1700                                  pc->parts[j + amount - 1]->id = j + amount - 1;
1701                               }
1702                             for (j = 0 ; j < amount ; j++)
1703                               {
1704                                  pc->parts[j + k] = parts[j];
1705                                  pc->parts[j + k]->id = j + k;
1706                               }
1707                          }
1708                        else if (i < k)
1709                          {
1710                             for (j = i + ep->reorder.linked_next + 1 ; j <= k ; j++)
1711                               {
1712                                  pc->parts[j - amount] = pc->parts[j];
1713                                  pc->parts[j - amount]->id = j - amount;
1714                               }
1715                             for (j = 0 ; j < amount ; j++)
1716                               {
1717                                  pc->parts[j + k - amount + 1] = parts[j];
1718                                  pc->parts[j + k - amount + 1]->id = j + k - amount + 1;
1719                               }
1720                             i -= amount;
1721                          }
1722                        ep->reorder.done = EINA_TRUE;
1723                        free(parts);
1724                     }
1725                }
1726           }
1727      }
1728 }
1729
1730 void
1731 data_queue_group_lookup(const char *name, Edje_Part *part)
1732 {
1733    Group_Lookup *gl;
1734
1735    if (!name || !name[0]) return;
1736
1737    gl = mem_alloc(SZ(Group_Lookup));
1738    group_lookups = eina_list_append(group_lookups, gl);
1739    gl->name = mem_strdup(name);
1740    gl->part = part;
1741 }
1742
1743 //#define NEWPARTLOOKUP 1
1744 #ifdef NEWPARTLOOKUP
1745 static Eina_Hash *_part_lookups_hash = NULL;
1746 static Eina_Hash *_part_lookups_dest_hash = NULL;
1747 #endif
1748
1749 void
1750 data_queue_part_lookup(Edje_Part_Collection *pc, const char *name, int *dest)
1751 {
1752    Part_Lookup *pl = NULL;
1753    Eina_List *l;
1754 #ifdef NEWPARTLOOKUP
1755    char buf[256];
1756 #endif
1757
1758 #ifdef NEWPARTLOOKUP
1759    snprintf(buf, sizeof(buf), "%lu-%lu",
1760             (unsigned long)name, (unsigned long)dest);
1761    if (_part_lookups_hash) pl = eina_hash_find(_part_lookups_hash, buf);
1762    if (pl)
1763      {
1764         free(pl->name);
1765         if (name[0])
1766           pl->name = mem_strdup(name);
1767         else
1768           {
1769              eina_hash_del(_part_lookups_hash, buf, pl);
1770              snprintf(buf, sizeof(buf), "%lu", (unsigned long)dest);
1771              eina_hash_del(_part_lookups_dest_hash, buf, pl);
1772              part_lookups = eina_list_remove(part_lookups, pl);
1773              free(pl);
1774           }
1775         return;
1776      }
1777 #else
1778    EINA_LIST_FOREACH(part_lookups, l, pl)
1779      {
1780         if ((pl->pc == pc) && (pl->dest == dest))
1781           {
1782              free(pl->name);
1783              if (name[0])
1784                pl->name = mem_strdup(name);
1785              else
1786                {
1787                   part_lookups = eina_list_remove(part_lookups, pl);
1788                   free(pl);
1789                }
1790              return;
1791           }
1792      }
1793 #endif
1794    if (!name[0]) return;
1795
1796    pl = mem_alloc(SZ(Part_Lookup));
1797    part_lookups = eina_list_prepend(part_lookups, pl);
1798    pl->pc = pc;
1799    pl->name = mem_strdup(name);
1800    pl->dest = dest;
1801 #ifdef NEWPARTLOOKUP
1802    if (!_part_lookups_hash)
1803      _part_lookups_hash = eina_hash_string_superfast_new(NULL);
1804    eina_hash_add(_part_lookups_hash, buf, pl);
1805
1806    snprintf(buf, sizeof(buf), "%lu", (unsigned long)dest);
1807    if (!_part_lookups_dest_hash)
1808      _part_lookups_dest_hash = eina_hash_string_superfast_new(NULL);
1809    l = eina_hash_find(_part_lookups_dest_hash, buf);
1810    if (l)
1811      {
1812         l = eina_list_append(l, pl);
1813         eina_hash_modify(_part_lookups_dest_hash, buf, l);
1814      }
1815    else
1816      {
1817         l = eina_list_append(l, pl);
1818         eina_hash_add(_part_lookups_dest_hash, buf, l);
1819      }
1820 #endif
1821 }
1822
1823 void
1824 data_queue_copied_part_lookup(Edje_Part_Collection *pc, int *src, int *dest)
1825 {
1826    Eina_List *l;
1827    Part_Lookup *pl;
1828 #ifdef NEWPARTLOOKUP
1829    Eina_List *list;
1830    char buf[256];
1831 #endif
1832
1833 #ifdef NEWPARTLOOKUP
1834    if (!_part_lookups_dest_hash) return;
1835    snprintf(buf, sizeof(buf), "%lu", (unsigned long)src);
1836    list = eina_hash_find(_part_lookups_dest_hash, buf);
1837    EINA_LIST_FOREACH(list, l, pl)
1838      {
1839         data_queue_part_lookup(pc, pl->name, dest);
1840      }
1841 #else
1842    EINA_LIST_FOREACH(part_lookups, l, pl)
1843      {
1844         if (pl->dest == src)
1845           data_queue_part_lookup(pc, pl->name, dest);
1846      }
1847 #endif
1848 }
1849
1850 void
1851 data_queue_anonymous_lookup(Edje_Part_Collection *pc, Edje_Program *ep, int *dest)
1852 {
1853    Eina_List *l, *l2;
1854    Program_Lookup *pl;
1855
1856    if (!ep) return ; /* FIXME: should we stop compiling ? */
1857
1858    EINA_LIST_FOREACH(program_lookups, l, pl)
1859      {
1860         if (pl->u.ep == ep)
1861           {
1862              Code *cd;
1863              Code_Program *cp;
1864
1865              cd = eina_list_data_get(eina_list_last(codes));
1866
1867              EINA_LIST_FOREACH(cd->programs, l2, cp)
1868                {
1869                   if (&(cp->id) == pl->dest)
1870                     {
1871                        cd->programs = eina_list_remove(cd->programs, cp);
1872                        free(cp);
1873                        cp = NULL;
1874                     }
1875                }
1876              program_lookups = eina_list_remove(program_lookups, pl);
1877              free(pl);
1878           }
1879      }
1880
1881    if (dest)
1882      {
1883         pl = mem_alloc(SZ(Program_Lookup));
1884         program_lookups = eina_list_append(program_lookups, pl);
1885         pl->pc = pc;
1886         pl->u.ep = ep;
1887         pl->dest = dest;
1888         pl->anonymous = EINA_TRUE;
1889      }
1890 }
1891
1892 void
1893 data_queue_copied_anonymous_lookup(Edje_Part_Collection *pc, int *src, int *dest)
1894 {
1895    Eina_List *l;
1896    Program_Lookup *pl;
1897    unsigned int i;
1898
1899    EINA_LIST_FOREACH(program_lookups, l, pl)
1900      {
1901         if (pl->dest == src)
1902           {
1903              for (i = 0 ; i < pc->programs.fnmatch_count ; i++)
1904                {
1905                   if (pl->u.ep->name && pc->programs.fnmatch[i]->name &&
1906                       !strcmp(pl->u.ep->name, pc->programs.fnmatch[i]->name))
1907                     data_queue_anonymous_lookup(pc, pc->programs.fnmatch[i], dest);
1908                }
1909              for (i = 0 ; i < pc->programs.strcmp_count ; i++)
1910                {
1911                   if (pl->u.ep->name && pc->programs.strcmp[i]->name &&
1912                       !strcmp(pl->u.ep->name, pc->programs.strcmp[i]->name))
1913                     data_queue_anonymous_lookup(pc, pc->programs.strcmp[i], dest);
1914                }
1915              for (i = 0 ; i < pc->programs.strncmp_count ; i++)
1916                {
1917                   if (pl->u.ep->name && pc->programs.strncmp[i]->name &&
1918                       !strcmp(pl->u.ep->name, pc->programs.strncmp[i]->name))
1919                     data_queue_anonymous_lookup(pc, pc->programs.strncmp[i], dest);
1920                }
1921              for (i = 0 ; i < pc->programs.strrncmp_count ; i++)
1922                {
1923                   if (pl->u.ep->name && pc->programs.strrncmp[i]->name &&
1924                       !strcmp(pl->u.ep->name, pc->programs.strrncmp[i]->name))
1925                     data_queue_anonymous_lookup(pc, pc->programs.strrncmp[i], dest);
1926                }
1927              for (i = 0 ; i < pc->programs.nocmp_count ; i++)
1928                {
1929                   if (pl->u.ep->name && pc->programs.nocmp[i]->name &&
1930                       !strcmp(pl->u.ep->name, pc->programs.nocmp[i]->name))
1931                     data_queue_anonymous_lookup(pc, pc->programs.nocmp[i], dest);
1932                }
1933           }
1934      }
1935 }
1936
1937 void
1938 data_queue_program_lookup(Edje_Part_Collection *pc, const char *name, int *dest)
1939 {
1940    Program_Lookup *pl;
1941
1942    if (!name) return ; /* FIXME: should we stop compiling ? */
1943
1944    pl = mem_alloc(SZ(Program_Lookup));
1945    program_lookups = eina_list_append(program_lookups, pl);
1946    pl->pc = pc;
1947    pl->u.name = mem_strdup(name);
1948    pl->dest = dest;
1949    pl->anonymous = EINA_FALSE;
1950 }
1951
1952 void
1953 data_queue_copied_program_lookup(Edje_Part_Collection *pc, int *src, int *dest)
1954 {
1955    Eina_List *l;
1956    Program_Lookup *pl;
1957
1958    EINA_LIST_FOREACH(program_lookups, l, pl)
1959      {
1960         if (pl->dest == src)
1961           data_queue_program_lookup(pc, pl->u.name, dest);
1962      }
1963 }
1964
1965 void
1966 data_queue_image_lookup(char *name, int *dest, Eina_Bool *set)
1967 {
1968    Image_Lookup *il;
1969
1970    il = mem_alloc(SZ(Image_Lookup));
1971    image_lookups = eina_list_append(image_lookups, il);
1972    il->name = mem_strdup(name);
1973    il->dest = dest;
1974    il->set = set;
1975 }
1976
1977 void
1978 data_queue_image_remove(int *dest, Eina_Bool *set)
1979 {
1980    Eina_List *l;
1981    Image_Lookup *il;
1982
1983    EINA_LIST_FOREACH(image_lookups, l, il)
1984      {
1985         if (il->dest == dest && il->set == set)
1986           {
1987              image_lookups = eina_list_remove_list(image_lookups, l);
1988              free(il->name);
1989              free(il);
1990              return ;
1991           }
1992      }
1993  }
1994
1995 void
1996 data_queue_copied_image_lookup(int *src, int *dest, Eina_Bool *set)
1997 {
1998    Eina_List *l;
1999    Image_Lookup *il;
2000
2001    EINA_LIST_FOREACH(image_lookups, l, il)
2002      {
2003         if (il->dest == src)
2004           data_queue_image_lookup(il->name, dest, set);
2005      }
2006 }
2007 void
2008 data_queue_part_slave_lookup(int *master, int *slave)
2009 {
2010    Slave_Lookup *sl;
2011
2012    sl = mem_alloc(SZ(Slave_Lookup));
2013    part_slave_lookups = eina_list_append(part_slave_lookups, sl);
2014    sl->master = master;
2015    sl->slave = slave;
2016 }
2017
2018 void
2019 data_queue_image_slave_lookup(int *master, int *slave)
2020 {
2021    Slave_Lookup *sl;
2022
2023    sl = mem_alloc(SZ(Slave_Lookup));
2024    image_slave_lookups = eina_list_append(image_slave_lookups, sl);
2025    sl->master = master;
2026    sl->slave = slave;
2027 }
2028
2029 void
2030 handle_slave_lookup(Eina_List *list, int *master, int value)
2031 {
2032    Eina_List *l;
2033    Slave_Lookup *sl;
2034
2035    EINA_LIST_FOREACH(list, l, sl)
2036      if (sl->master == master)
2037        *sl->slave = value;
2038 }
2039
2040 void
2041 data_process_lookups(void)
2042 {
2043    Edje_Part_Collection *pc;
2044    Part_Lookup *part;
2045    Program_Lookup *program;
2046    Group_Lookup *group;
2047    Image_Lookup *image;
2048    Eina_List *l2;
2049    Eina_List *l;
2050    Eina_Hash *images_in_use;
2051    void *data;
2052    Eina_Bool is_lua = EINA_FALSE;
2053
2054    /* remove all unreferenced Edje_Part_Collection */
2055    EINA_LIST_FOREACH_SAFE(edje_collections, l, l2, pc)
2056      {
2057         Edje_Part_Collection_Directory_Entry *alias;
2058         Edje_Part_Collection_Directory_Entry *find;
2059         Eina_List *l3;
2060         unsigned int id = 0;
2061         unsigned int i;
2062
2063         if (!pc->part)
2064           {
2065              ERR("A collection without a name was detected, that's not allowed.");
2066              exit(-1);
2067           }
2068         find = eina_hash_find(edje_file->collection, pc->part);
2069         if (find && find->id == pc->id)
2070           continue ;
2071
2072         EINA_LIST_FOREACH(aliases, l3, alias)
2073           if (alias->id == pc->id)
2074             continue ;
2075
2076         /* This Edje_Part_Collection is not used at all */
2077         edje_collections = eina_list_remove_list(edje_collections, l);
2078         l3 = eina_list_nth_list(codes, pc->id);
2079         codes = eina_list_remove_list(codes, l3);
2080
2081         /* Unref all image used by that group */
2082         for (i = 0; i < pc->parts_count; ++i)
2083           part_description_image_cleanup(pc->parts[i]);
2084
2085         /* Correct all id */
2086         EINA_LIST_FOREACH(edje_collections, l3, pc)
2087           {
2088              Eina_List *l4;
2089
2090              /* Some group could be removed from the collection, but still be referenced by alias */
2091              find = eina_hash_find(edje_file->collection, pc->part);
2092              if (pc->id != find->id) find = NULL;
2093
2094              /* Update all matching alias */
2095              EINA_LIST_FOREACH(aliases, l4, alias)
2096                if (pc->id == alias->id)
2097                  alias->id = id;
2098
2099              pc->id = id++;
2100              if (find) find->id = pc->id;
2101           }
2102      }
2103
2104    EINA_LIST_FOREACH(edje_collections, l, pc)
2105      {
2106         unsigned int count = 0;
2107         unsigned int i;
2108
2109         if (pc->lua_script_only)
2110           is_lua = EINA_TRUE;
2111 #define PROGRAM_ID_SET(Type, Pc, It, Count)                             \
2112         for (It = 0; It < Pc->programs.Type ## _count; ++It)            \
2113           {                                                             \
2114              Pc->programs.Type[It]->id = Count++;                       \
2115           }
2116
2117         PROGRAM_ID_SET(fnmatch, pc, i, count);
2118         PROGRAM_ID_SET(strcmp, pc, i, count);
2119         PROGRAM_ID_SET(strncmp, pc, i, count);
2120         PROGRAM_ID_SET(strrncmp, pc, i, count);
2121         PROGRAM_ID_SET(nocmp, pc, i, count);
2122
2123 #undef PROGRAM_ID_SET
2124      }
2125
2126    EINA_LIST_FREE(part_lookups, part)
2127      {
2128         Edje_Part *ep;
2129         unsigned int i;
2130
2131         if (!strcmp(part->name, "-"))
2132           {
2133              *(part->dest) = -1;
2134           }
2135         else
2136           {
2137              char *alias;
2138              alias = eina_hash_find(part->pc->alias, part->name);
2139              if (!alias)
2140                alias = part->name;
2141              for (i = 0; i < part->pc->parts_count; ++i)
2142                {
2143                   ep = part->pc->parts[i];
2144
2145                   if ((ep->name) && (!strcmp(ep->name, alias)))
2146                     {
2147                        handle_slave_lookup(part_slave_lookups, part->dest, ep->id);
2148                        *(part->dest) = ep->id;
2149                        break;
2150                     }
2151                }
2152
2153              if (i == part->pc->parts_count)
2154                {
2155                   ERR("Unable to find part name \"%s\" needed in group '%s'.",
2156                       alias, part->pc->part);
2157                   exit(-1);
2158                }
2159           }
2160
2161         free(part->name);
2162         free(part);
2163      }
2164
2165    EINA_LIST_FREE(program_lookups, program)
2166      {
2167         unsigned int i;
2168         Eina_Bool find = EINA_FALSE;
2169
2170 #define PROGRAM_MATCH(Type, Pl, It)                                     \
2171         for (It = 0; It < Pl->pc->programs.Type ## _count; ++It)        \
2172           {                                                             \
2173              Edje_Program *ep;                                          \
2174              \
2175              ep = Pl->pc->programs.Type[It];                            \
2176              \
2177              if ((Pl->anonymous && ep == Pl->u.ep) ||                   \
2178                  ((!Pl->anonymous) && (ep->name) && (!strcmp(ep->name, Pl->u.name)))) \
2179                {                                                        \
2180                   *(Pl->dest) = ep->id;                                 \
2181                   find = EINA_TRUE;                                     \
2182                   break;                                                \
2183                }                                                        \
2184           }
2185
2186         PROGRAM_MATCH(fnmatch, program, i);
2187         PROGRAM_MATCH(strcmp, program, i);
2188         PROGRAM_MATCH(strncmp, program, i);
2189         PROGRAM_MATCH(strrncmp, program, i);
2190         PROGRAM_MATCH(nocmp, program, i);
2191
2192 #undef PROGRAM_MATCH
2193
2194         if (!find)
2195           {
2196              if (!program->anonymous)
2197                ERR("Unable to find program name \"%s\".",
2198                    program->u.name);
2199              else
2200                ERR("Unable to find anonymous program.");
2201              exit(-1);
2202           }
2203
2204         if (!program->anonymous)
2205           free(program->u.name);
2206         free(program);
2207      }
2208
2209    EINA_LIST_FREE(group_lookups, group)
2210      {
2211         Edje_Part_Collection_Directory_Entry *de;
2212
2213         if (group->part)
2214           {
2215              if (group->part->type != EDJE_PART_TYPE_GROUP
2216                  && group->part->type != EDJE_PART_TYPE_TEXTBLOCK
2217                  && group->part->type != EDJE_PART_TYPE_BOX
2218                  && group->part->type != EDJE_PART_TYPE_TABLE)
2219                goto free_group;
2220           }
2221
2222         de = eina_hash_find(edje_file->collection, group->name);
2223
2224         if (!de)
2225           {
2226              Eina_Bool found = EINA_FALSE;
2227
2228              EINA_LIST_FOREACH(aliases, l, de)
2229                if (strcmp(de->entry, group->name) == 0)
2230                  {
2231                     found = EINA_TRUE;
2232                     break;
2233                  }
2234              if (!found) de = NULL;
2235           }
2236
2237         if (!de)
2238           {
2239              ERR("Unable to find group name \"%s\".", group->name);
2240              exit(-1);
2241           }
2242
2243 free_group:
2244         free(group->name);
2245         free(group);
2246      }
2247
2248    images_in_use = eina_hash_string_superfast_new(NULL);
2249
2250    EINA_LIST_FREE(image_lookups, image)
2251      {
2252         Eina_Bool find = EINA_FALSE;
2253
2254         if (edje_file->image_dir)
2255           {
2256              Edje_Image_Directory_Entry *de;
2257              unsigned int i;
2258
2259              for (i = 0; i < edje_file->image_dir->entries_count; ++i)
2260                {
2261                   de = edje_file->image_dir->entries + i;
2262
2263                   if ((de->entry) && (!strcmp(de->entry, image->name)))
2264                     {
2265                        handle_slave_lookup(image_slave_lookups, image->dest, de->id);
2266                        if (de->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL)
2267                          *(image->dest) = -de->id - 1;
2268                        else
2269                          *(image->dest) = de->id;
2270                        *(image->set) = EINA_FALSE;
2271                        find = EINA_TRUE;
2272
2273                        if (!eina_hash_find(images_in_use, image->name))
2274                          eina_hash_direct_add(images_in_use, de->entry, de);
2275                        break;
2276                     }
2277                }
2278
2279              if (!find)
2280                {
2281                   Edje_Image_Directory_Set *set;
2282
2283                   for (i = 0; i < edje_file->image_dir->sets_count; ++i)
2284                     {
2285                        set = edje_file->image_dir->sets + i;
2286
2287                        if ((set->name) && (!strcmp(set->name, image->name)))
2288                          {
2289                             Edje_Image_Directory_Set_Entry *child;
2290                             Eina_List *lc;
2291
2292                             handle_slave_lookup(image_slave_lookups, image->dest, set->id);
2293                             *(image->dest) = set->id;
2294                             *(image->set) = EINA_TRUE;
2295                             find = EINA_TRUE;
2296
2297                             EINA_LIST_FOREACH(set->entries, lc, child)
2298                                if (!eina_hash_find(images_in_use, child->name))
2299                                  eina_hash_direct_add(images_in_use, child->name, child);
2300
2301                             if (!eina_hash_find(images_in_use, image->name))
2302                               eina_hash_direct_add(images_in_use, set->name, set);
2303                             break;
2304                          }
2305                     }
2306                }
2307           }
2308
2309         if (!find)
2310           {
2311              ERR("Unable to find image name \"%s\".", image->name);
2312              exit(-1);
2313           }
2314
2315         free(image->name);
2316         free(image);
2317      }
2318
2319    if (edje_file->image_dir && !is_lua)
2320      {
2321         Edje_Image_Directory_Entry *de;
2322         Edje_Image_Directory_Set *set;
2323         unsigned int i;
2324
2325         for (i = 0; i < edje_file->image_dir->entries_count; ++i)
2326           {
2327              de = edje_file->image_dir->entries + i;
2328
2329              if (de->entry && eina_hash_find(images_in_use, de->entry))
2330                continue ;
2331
2332              INF("Image '%s' in resource 'edje/image/%i' will not be included as it is unused.",
2333                  de->entry, de->id);
2334
2335              de->entry = NULL;
2336           }
2337
2338         for (i = 0; i < edje_file->image_dir->sets_count; ++i)
2339           {
2340              set = edje_file->image_dir->sets + i;
2341
2342              if (set->name && eina_hash_find(images_in_use, set->name))
2343                continue ;
2344
2345              INF("Set '%s' will not be included as it is unused.", set->name);
2346
2347              set->name = NULL;
2348              set->entries = NULL;
2349           }
2350      }
2351
2352    eina_hash_free(images_in_use);
2353
2354    EINA_LIST_FREE(part_slave_lookups, data)
2355      free(data);
2356
2357    EINA_LIST_FREE(image_slave_lookups, data)
2358      free(data);
2359 }
2360
2361 static void
2362 data_process_string(Edje_Part_Collection *pc, const char *prefix, char *s, void (*func)(Edje_Part_Collection *pc, char *name, char* ptr, int len))
2363 {
2364    char *p;
2365    char *key;
2366    int keyl;
2367    int quote, escape;
2368
2369    key = alloca(strlen(prefix) + 2 + 1);
2370    if (!key) return;
2371    strcpy(key, prefix);
2372    strcat(key, ":\"");
2373    keyl = strlen(key);
2374    quote = 0;
2375    escape = 0;
2376    for (p = s; (p) && (*p); p++)
2377      {
2378         if (!quote)
2379           {
2380              if (*p == '\"')
2381                {
2382                   quote = 1;
2383                   p++;
2384                }
2385           }
2386         if (!quote)
2387           {
2388              if (!strncmp(p, key, keyl))
2389                {
2390                   char *ptr;
2391                   int len;
2392                   int inesc = 0;
2393                   char *name;
2394
2395                   ptr = p;
2396                   p += keyl;
2397                   while ((*p))
2398                     {
2399                        if (!inesc)
2400                          {
2401                             if (*p == '\\') inesc = 1;
2402                             else if (*p == '\"')
2403                               {
2404                                  /* string concatenation, see below */
2405                                  if (*(p + 1) != '\"')
2406                                    break;
2407                                  else
2408                                    p++;
2409                               }
2410                          }
2411                        else
2412                             inesc = 0;
2413                        p++;
2414                     }
2415                   len = p - ptr + 1;
2416                   name = alloca(len);
2417                   if (name)
2418                     {
2419                        char *pp;
2420                        int i;
2421
2422                        name[0] = 0;
2423                        pp = ptr + keyl;
2424                        inesc = 0;
2425                        i = 0;
2426                        while (*pp)
2427                          {
2428                             if (!inesc)
2429                               {
2430                                  if (*pp == '\\') inesc = 1;
2431                                  else if (*pp == '\"')
2432                                    {
2433                                       /* concat strings like "foo""bar" to "foobar" */
2434                                       if (*(pp + 1) == '\"')
2435                                         pp++;
2436                                       else
2437                                         {
2438                                            name[i] = 0;
2439                                            break;
2440                                         }
2441                                    }
2442                                  else
2443                                    {
2444                                       name[i] = *pp;
2445                                       name[i + 1] = 0;
2446                                       i++;
2447                                    }
2448                               }
2449                             else
2450                               inesc = 0;
2451                             pp++;
2452                         }
2453                       func(pc, name, ptr, len);
2454                    }
2455               }
2456           }
2457         else
2458           {
2459              if (!escape)
2460                {
2461                   if (*p == '\"') quote = 0;
2462                   else if (*p == '\\') escape = 1;
2463                }
2464              else if (escape)
2465                {
2466                   escape = 0;
2467                }
2468           }
2469      }
2470 }
2471
2472 static void
2473 _data_queue_part_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len)
2474 {
2475    Code_Lookup *cl;
2476
2477    cl = mem_alloc(SZ(Code_Lookup));
2478    cl->ptr = ptr;
2479    cl->len = len;
2480
2481    data_queue_part_lookup(pc, name, &(cl->val));
2482
2483    code_lookups = eina_list_append(code_lookups, cl);
2484 }
2485 static void
2486 _data_queue_program_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len)
2487 {
2488    Code_Lookup *cl;
2489
2490    cl = mem_alloc(SZ(Code_Lookup));
2491    cl->ptr = ptr;
2492    cl->len = len;
2493
2494    data_queue_program_lookup(pc, name, &(cl->val));
2495
2496    code_lookups = eina_list_append(code_lookups, cl);
2497 }
2498 static void
2499 _data_queue_group_lookup(Edje_Part_Collection *pc __UNUSED__, char *name, char *ptr __UNUSED__, int len __UNUSED__)
2500 {
2501    data_queue_group_lookup(name, NULL);
2502 }
2503 static void
2504 _data_queue_image_pc_lookup(Edje_Part_Collection *pc __UNUSED__, char *name, char *ptr, int len)
2505 {
2506    Code_Lookup *cl;
2507
2508    cl = mem_alloc(SZ(Code_Lookup));
2509    cl->ptr = ptr;
2510    cl->len = len;
2511
2512    data_queue_image_lookup(name, &(cl->val),  &(cl->set));
2513
2514    code_lookups = eina_list_append(code_lookups, cl);
2515 }
2516
2517 void
2518 data_process_scripts(void)
2519 {
2520    Eina_List *l, *l2;
2521
2522    for (l = codes, l2 = edje_collections; (l) && (l2); l = eina_list_next(l), l2 = eina_list_next(l2))
2523      {
2524         Edje_Part_Collection *pc;
2525         Code *cd;
2526
2527         cd = eina_list_data_get(l);
2528         pc = eina_list_data_get(l2);
2529
2530         if ((cd->shared) && (!cd->is_lua))
2531           {
2532              data_process_string(pc, "PART",    cd->shared, _data_queue_part_lookup);
2533              data_process_string(pc, "PROGRAM", cd->shared, _data_queue_program_lookup);
2534              data_process_string(pc, "IMAGE",   cd->shared, _data_queue_image_pc_lookup);
2535              data_process_string(pc, "GROUP",   cd->shared, _data_queue_group_lookup);
2536           }
2537
2538         if (cd->programs)
2539           {
2540              Code_Program *cp;
2541              Eina_List *ll;
2542
2543              EINA_LIST_FOREACH(cd->programs, ll, cp)
2544                {
2545                   if (cp->script)
2546                     {
2547                        data_process_string(pc, "PART",    cp->script, _data_queue_part_lookup);
2548                        data_process_string(pc, "PROGRAM", cp->script, _data_queue_program_lookup);
2549                        data_process_string(pc, "IMAGE",   cp->script, _data_queue_image_pc_lookup);
2550                        data_process_string(pc, "GROUP",   cp->script, _data_queue_group_lookup);
2551                     }
2552                }
2553           }
2554      }
2555 }
2556
2557 void
2558 data_process_script_lookups(void)
2559 {
2560    Eina_List *l;
2561    Code_Lookup *cl;
2562
2563    EINA_LIST_FOREACH(code_lookups, l, cl)
2564      {
2565         char buf[12];
2566         int n;
2567
2568         /* FIXME !! Handle set in program */
2569         n = eina_convert_itoa(cl->val, buf);
2570         if (n > cl->len)
2571           {
2572              ERR("The unexpected happened. A numeric replacement string was larger than the original!");
2573              exit(-1);
2574           }
2575         memset(cl->ptr, ' ', cl->len);
2576         strncpy(cl->ptr, buf, n);
2577      }
2578 }
2579
2580 void
2581 using_file(const char *filename)
2582 {
2583    FILE *f;
2584
2585    if (!watchfile) return;
2586    f = fopen(watchfile, "ab");
2587    if (!f) return ;
2588    fputs(filename, f);
2589    fputc('\n', f);
2590    fclose(f);
2591 }