1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include <locale.h>
6 #include <fnmatch.h>
7
8 #include <Ecore.h>
9 #include <Ecore_Getopt.h>
10
11 #include "Edje.h"
12
13 static int _log_dom;
14 #define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
15 #define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
16 #define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
17 #define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
18 #define CRI(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
19
20 #define INDENT " "
21 #define INDENT2 INDENT INDENT
22 #define INDENT3 INDENT2 INDENT
23 #define INDENT4 INDENT3 INDENT
24
25 static char *module_patterns_str = NULL;
26
27 static int detail = 1;
28 static Eina_Bool machine = EINA_FALSE;
29 static char *type_glob = NULL;
30 static char *const *module_patterns;
31 static const Eina_List *modules;
32
33 static char *
_module_patterns_str_new(void)34 _module_patterns_str_new(void)
35 {
36 Eina_Strbuf *buf;
37 char *const *itr;
38 char *ret;
39 if (!module_patterns) return strdup("*");
40
41 buf = eina_strbuf_new();
42 for (itr = module_patterns; *itr != NULL; itr++)
43 {
44 eina_strbuf_append(buf, *itr);
45 if (itr[1]) eina_strbuf_append(buf, ", ");
46 }
47 ret = eina_strbuf_string_steal(buf);
48 eina_strbuf_free(buf);
49 return ret;
50 }
51
52 static Eina_Bool
module_matches(const char * name)53 module_matches(const char *name)
54 {
55 char *const *itr;
56 if (!module_patterns) return EINA_TRUE;
57
58 for (itr = module_patterns; *itr != NULL; itr++)
59 if (fnmatch(*itr, name, 0) == 0) return EINA_TRUE;
60
61 return EINA_FALSE;
62 }
63
64 static inline Eina_Bool
type_matches(const char * name)65 type_matches(const char *name)
66 {
67 if (!type_glob) return EINA_TRUE;
68 return fnmatch(type_glob, name, 0) == 0;
69 }
70
71 static int
_types_sort(const void * pa,const void * pb)72 _types_sort(const void *pa, const void *pb)
73 {
74 const Eina_Hash_Tuple *ha = pa, *hb = pb;
75 const Edje_External_Type *ta = ha->data, *tb = hb->data;
76 const char *na = ha->key, *nb = hb->key;
77 int r;
78
79 if (!ta->module) return -1;
80 if (!tb->module) return 1;
81 r = strcmp(ta->module, tb->module);
82 if (r != 0) return r;
83
84 if (!na) return -1;
85 if (!nb) return 1;
86 return strcmp(na, nb);
87 }
88
89 static const char *
_param_type_str_get(const Edje_External_Param_Info * param)90 _param_type_str_get(const Edje_External_Param_Info *param)
91 {
92 switch (param->type)
93 {
94 case EDJE_EXTERNAL_PARAM_TYPE_INT: return "int";
95
96 case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE: return "double";
97
98 case EDJE_EXTERNAL_PARAM_TYPE_STRING: return "string";
99
100 case EDJE_EXTERNAL_PARAM_TYPE_BOOL: return "bool";
101
102 case EDJE_EXTERNAL_PARAM_TYPE_CHOICE: return "choice";
103
104 default:
105 ERR("Unknown parameter type %d", param->type);
106 return "???";
107 }
108 }
109
110 static const char *
_param_value_str_get(const Edje_External_Type * type,const Edje_External_Param_Info * param,char * buf,size_t buflen)111 _param_value_str_get(const Edje_External_Type *type, const Edje_External_Param_Info *param, char *buf, size_t buflen)
112 {
113 switch (param->type)
114 {
115 case EDJE_EXTERNAL_PARAM_TYPE_INT:
116 if (param->info.i.def == EDJE_EXTERNAL_INT_UNSET) return NULL;
117 snprintf(buf, buflen, "%d", param->info.i.def);
118 return buf;
119
120 case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
121 if (EINA_DBL_EQ(param->info.d.def, EDJE_EXTERNAL_DOUBLE_UNSET)) return NULL;
122 snprintf(buf, buflen, "%g", param->info.d.def);
123 return buf;
124
125 case EDJE_EXTERNAL_PARAM_TYPE_STRING:
126 return param->info.s.def;
127
128 case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
129 if (param->info.b.def == 0) return "0";
130 else if (param->info.b.def == 1)
131 return "1";
132 return NULL;
133
134 case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
135 {
136 char *def;
137 if (param->info.c.def) return param->info.c.def;
138 if (!param->info.c.def_get) return NULL;
139 def = param->info.c.def_get(type->data, param);
140 if (!def) return NULL;
141 eina_strlcpy(buf, def, buflen);
142 free(def);
143 return buf;
144 }
145
146 default:
147 ERR("Unknown parameter type %d", param->type);
148 return NULL;
149 }
150 }
151
152 static const char *
_param_flags_str_get(const Edje_External_Param_Info * param)153 _param_flags_str_get(const Edje_External_Param_Info *param)
154 {
155 static char buf[] = "GET|SET|STATE|CONSTRUCTOR";
156
157 if (param->flags == EDJE_EXTERNAL_PARAM_FLAGS_NONE) return "NONE";
158 if (param->flags == EDJE_EXTERNAL_PARAM_FLAGS_REGULAR) return "REGULAR";
159
160 buf[0] = '\0';
161
162 if (param->flags & EDJE_EXTERNAL_PARAM_FLAGS_GET)
163 strcat(buf, "GET");
164
165 if (param->flags & EDJE_EXTERNAL_PARAM_FLAGS_SET)
166 {
167 if (buf[0] != '\0') strcat(buf, "|");
168 strcat(buf, "SET");
169 }
170
171 if (param->flags & EDJE_EXTERNAL_PARAM_FLAGS_STATE)
172 {
173 if (buf[0] != '\0') strcat(buf, "|");
174 strcat(buf, "STATE");
175 }
176
177 if (param->flags & EDJE_EXTERNAL_PARAM_FLAGS_CONSTRUCTOR)
178 {
179 if (buf[0] != '\0') strcat(buf, "|");
180 strcat(buf, "CONSTRUCTOR");
181 }
182
183 return buf;
184 }
185
186 static void
_param_choices_print(const char * const * choices)187 _param_choices_print(const char *const *choices)
188 {
189 if (machine) puts("CHOICES-BEGIN");
190 else fputs(", choices:", stdout);
191 for (; *choices != NULL; choices++)
192 {
193 if (machine) puts(*choices);
194 else printf(" \"%s\"", *choices);
195 }
196 if (machine) puts("CHOICES-END");
197 }
198
199 static void
_param_extra_details(const Edje_External_Type * type,const Edje_External_Param_Info * param)200 _param_extra_details(const Edje_External_Type *type, const Edje_External_Param_Info *param)
201 {
202 const char *str = _param_flags_str_get(param);
203 if (machine) printf("FLAGS: %s\n", str);
204 else printf(" /* flags: %s", str);
205
206 switch (param->type)
207 {
208 case EDJE_EXTERNAL_PARAM_TYPE_INT:
209 if (param->info.i.min != EDJE_EXTERNAL_INT_UNSET)
210 {
211 if (machine) printf("MIN: %d\n", param->info.i.min);
212 else printf(", min: %d", param->info.i.min);
213 }
214 if (param->info.i.max != EDJE_EXTERNAL_INT_UNSET)
215 {
216 if (machine) printf("MAX: %d\n", param->info.i.max);
217 else printf(", max: %d", param->info.i.max);
218 }
219 if (param->info.i.step != EDJE_EXTERNAL_INT_UNSET)
220 {
221 if (machine) printf("STEP: %d\n", param->info.i.step);
222 else printf(", step: %d", param->info.i.step);
223 }
224 break;
225
226 case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
227 if (EINA_DBL_EQ(param->info.d.min, EDJE_EXTERNAL_DOUBLE_UNSET))
228 {
229 if (machine) printf("MIN: %g\n", param->info.d.min);
230 else printf(", min: %g", param->info.d.min);
231 }
232 if (EINA_DBL_EQ(param->info.d.max, EDJE_EXTERNAL_DOUBLE_UNSET))
233 {
234 if (machine) printf("MAX: %g\n", param->info.d.max);
235 else printf(", max: %g", param->info.d.max);
236 }
237 if (EINA_DBL_EQ(param->info.d.step, EDJE_EXTERNAL_DOUBLE_UNSET))
238 {
239 if (machine) printf("STEP: %g\n", param->info.d.step);
240 else printf(", step: %g", param->info.d.step);
241 }
242 break;
243
244 case EDJE_EXTERNAL_PARAM_TYPE_STRING:
245 if (param->info.s.accept_fmt)
246 {
247 if (machine) printf("ACCEPT_FMT: %s\n", param->info.s.accept_fmt);
248 else printf(", accept_fmt: \"%s\"", param->info.s.accept_fmt);
249 }
250 if (param->info.s.deny_fmt)
251 {
252 if (machine) printf("DENY_FMT: %s\n", param->info.s.deny_fmt);
253 else printf(", deny_fmt: \"%s\"", param->info.s.deny_fmt);
254 }
255 break;
256
257 case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
258 if (param->info.b.false_str)
259 {
260 if (machine) printf("FALSE_STR: %s\n", param->info.b.false_str);
261 else printf(", false_str: \"%s\"", param->info.b.false_str);
262 }
263 if (param->info.b.true_str)
264 {
265 if (machine) printf("TRUE_STR: %s\n", param->info.b.true_str);
266 else printf(", true_str: \"%s\"", param->info.b.true_str);
267 }
268 break;
269
270 case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
271 {
272 if (param->info.c.choices)
273 _param_choices_print(param->info.c.choices);
274 else if (param->info.c.query)
275 {
276 char **choices = param->info.c.query(type->data, param);
277 if (choices)
278 {
279 char **itr;
280 _param_choices_print((const char *const *)choices);
281 for (itr = choices; *itr; itr++)
282 free(*itr);
283 free(choices);
284 }
285 }
286 }
287 break;
288
289 default:
290 ERR("Unknown parameter type %d", param->type);
291 }
292
293 if (!machine) fputs(" */", stdout); /* \n not desired */
294 }
295
296 static int
_info_list(void)297 _info_list(void)
298 {
299 Eina_Iterator *itr;
300 Eina_List *types;
301 const Eina_Hash_Tuple *tuple;
302 const Eina_List *l;
303 const char *name, *last_module;
304 Eina_Bool module_found = EINA_FALSE, type_found = EINA_FALSE;
305 Eina_Bool in_module = EINA_FALSE;
306
307 EINA_LIST_FOREACH(modules, l, name)
308 {
309 if (!module_matches(name))
310 {
311 DBG("filter out module '%s': does not match '%s'",
312 name, module_patterns_str);
313 continue;
314 }
315
316 if (!edje_module_load(name))
317 {
318 ERR("error loading external '%s'", name);
319 continue;
320 }
321
322 module_found = EINA_TRUE;
323 }
324
325 itr = edje_external_iterator_get();
326 types = NULL;
327 EINA_ITERATOR_FOREACH(itr, tuple)
328 {
329 const Edje_External_Type *type = tuple->data;
330 name = tuple->key;
331
332 if (!type)
333 {
334 ERR("no type value for '%s'", name);
335 continue;
336 }
337 else if (type->abi_version != edje_external_type_abi_version_get())
338 {
339 ERR("type '%s' with incorrect abi_version %u (expected %u)",
340 name, type->abi_version, edje_external_type_abi_version_get());
341 continue;
342 }
343
344 if (!type_matches(name))
345 {
346 DBG("filter out type '%s': does not match '%s'", name, type_glob);
347 continue;
348 }
349
350 types = eina_list_append(types, tuple);
351 type_found = EINA_TRUE;
352 }
353 eina_iterator_free(itr);
354
355 last_module = NULL;
356 types = eina_list_sort(types, 0, _types_sort);
357 EINA_LIST_FREE(types, tuple)
358 {
359 Eina_Bool changed_module = EINA_FALSE;
360 const Edje_External_Type *type = tuple->data;
361 const Edje_External_Param_Info *param;
362 name = tuple->key;
363
364 if ((last_module) && (type->module))
365 {
366 changed_module = ((last_module != type->module) &&
367 (!strcmp(last_module, type->module)));
368 }
369 else if ((!last_module) && (type->module))
370 changed_module = EINA_TRUE;
371
372 if (changed_module)
373 {
374 if (in_module)
375 {
376 if (machine) puts("TYPES-END\nMODULE-END");
377 else puts(INDENT "}\n}");
378 }
379
380 if (machine)
381 printf("MODULE-BEGIN\n"
382 "NAME: %s\n"
383 "FRIENDLY-NAME: %s\n"
384 "TYPES-BEGIN\n",
385 type->module, type->module_name);
386 else
387 printf("module {\n"
388 INDENT "name: \"%s\";\n"
389 INDENT "friendly_name: \"%s\";\n"
390 INDENT "types {\n",
391 type->module, type->module_name);
392
393 in_module = EINA_TRUE;
394 }
395
396 if (machine) printf("TYPE-BEGIN\nNAME: %s\n", name);
397 else printf(INDENT2 "type {\n" INDENT3 "name: \"%s\";\n", name);
398
399 if (detail > 1)
400 {
401 const char *str;
402
403 if (!type->label_get) str = NULL;
404 else str = type->label_get(type->data);
405 if (machine) printf("LABEL: %s\n", str ? str : "");
406 else if (str)
407 printf(INDENT3 "label: \"%s\";\n", str);
408
409 if (!type->description_get) str = NULL;
410 else str = type->description_get(type->data);
411 if (machine) printf("DESCRIPTION: %s\n", str ? str : "");
412 else if (str)
413 printf(INDENT3 "description: \"%s\";\n", str);
414 }
415
416 if (machine) puts("PARAMS-BEGIN");
417 else puts(INDENT3 "params {");
418
419 for (param = type->parameters_info; param->name != NULL; param++)
420 {
421 const char *pt = _param_type_str_get(param);
422 char buf[128];
423
424 if (machine)
425 printf("PARAM-BEGIN\nNAME: %s\nTYPE: %s\n", param->name, pt);
426 else printf(INDENT4 "%s: \"%s\"", pt, param->name);
427
428 if (detail > 0)
429 {
430 const char *str = _param_value_str_get
431 (type, param, buf, sizeof(buf));
432 if (machine) printf("DEFAULT: %s\n", str ? str : "");
433 else if (str)
434 printf(" \"%s\"", str);
435
436 if (detail > 1)
437 {
438 if (!machine) putchar(';');
439 _param_extra_details(type, param);
440 }
441 }
442
443 if (machine) puts("PARAM-END");
444 else if (detail > 1)
445 putchar('\n');
446 else puts(";");
447 }
448
449 if (machine) puts("PARAMS-END\nTYPE-END");
450 else puts(INDENT3 "}\n" INDENT2 "}");
451
452 last_module = type->module;
453 }
454
455 if (in_module)
456 {
457 if (machine) puts("MODULE-END");
458 else puts(INDENT "}\n}");
459 }
460
461 if (!module_found) WRN("no modules match '%s'", module_patterns_str);
462 if (!type_found) WRN("no types match '%s'", type_glob);
463 return (!module_found) || (!type_found);
464 }
465
466 static int
_types_names_list(void)467 _types_names_list(void)
468 {
469 Eina_Iterator *itr;
470 Eina_List *types;
471 const Eina_Hash_Tuple *tuple;
472 const Eina_List *l;
473 const char *name;
474 Eina_Bool module_found = EINA_FALSE, type_found = EINA_FALSE;
475
476 EINA_LIST_FOREACH(modules, l, name)
477 {
478 if (!module_matches(name))
479 {
480 DBG("filter out module '%s': does not match '%s'",
481 name, module_patterns_str);
482 continue;
483 }
484
485 if (!edje_module_load(name))
486 {
487 ERR("error loading external '%s'", name);
488 continue;
489 }
490
491 module_found = EINA_TRUE;
492 }
493
494 itr = edje_external_iterator_get();
495 types = NULL;
496 EINA_ITERATOR_FOREACH(itr, tuple)
497 {
498 const Edje_External_Type *type = tuple->data;
499 name = tuple->key;
500
501 if (!type)
502 {
503 ERR("no type value for '%s'", name);
504 continue;
505 }
506 else if (type->abi_version != edje_external_type_abi_version_get())
507 {
508 ERR("type '%s' with incorrect abi_version %u (expected %u)",
509 name, type->abi_version, edje_external_type_abi_version_get());
510 continue;
511 }
512
513 if (!type_matches(name))
514 {
515 DBG("filter out type '%s': does not match '%s'", name, type_glob);
516 continue;
517 }
518
519 types = eina_list_append(types, tuple);
520 type_found = EINA_TRUE;
521 }
522 eina_iterator_free(itr);
523
524 types = eina_list_sort(types, 0, _types_sort);
525 EINA_LIST_FREE(types, tuple)
526 puts(tuple->key);
527
528 if (!module_found) WRN("no modules match '%s'", module_patterns_str);
529 if (!type_found) WRN("no types match '%s'", type_glob);
530 return (!module_found) || (!type_found);
531 }
532
533 static int
_modules_names_list(void)534 _modules_names_list(void)
535 {
536 const Eina_List *l;
537 const char *name;
538 Eina_Bool found = EINA_FALSE;
539
540 EINA_LIST_FOREACH(modules, l, name)
541 {
542 if (!module_matches(name))
543 {
544 DBG("filter out module '%s': does not match '%s'",
545 name, module_patterns_str);
546 continue;
547 }
548 found = EINA_TRUE;
549 puts(name);
550 }
551
552 if (!found) WRN("no modules match '%s'", module_patterns_str);
553 return !found;
554 }
555
556 static const char *mode_choices[] = {
557 "info",
558 "modules-names",
559 "types-names",
560 NULL,
561 };
562
563 static const char *detail_choices[] = {
564 "none",
565 "terse",
566 "all",
567 NULL
568 };
569
570 const Ecore_Getopt optdesc = {
571 "edje_external_inspector",
572 "%prog [options] [module|module-glob] ... [module|module-glob]",
573 PACKAGE_VERSION,
574 "(C) 2010 - The Enlightenment Project",
575 "BSD",
576 "Edje external module inspector.",
577 0,
578 {
579 ECORE_GETOPT_CHOICE('m', "mode", "Choose which mode to operate.",
580 mode_choices),
581 ECORE_GETOPT_STORE_STR('t', "type", "Limit output to type (or glob)."),
582 ECORE_GETOPT_CHOICE('d', "detail", "Choose detail level (default=terse)",
583 detail_choices),
584 ECORE_GETOPT_STORE_TRUE('M', "machine", "Produce machine readable output."),
585 ECORE_GETOPT_LICENSE('L', "license"),
586 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
587 ECORE_GETOPT_VERSION('V', "version"),
588 ECORE_GETOPT_HELP('h', "help"),
589 ECORE_GETOPT_SENTINEL
590 }
591 };
592
593 int
main(int argc,char ** argv)594 main(int argc, char **argv)
595 {
596 Eina_Bool quit_option = EINA_FALSE;
597 char *mode = NULL;
598 char *detail_name = NULL;
599 int arg_index;
600 int ret = 0;
601 Ecore_Getopt_Value values[] = {
602 ECORE_GETOPT_VALUE_STR(mode),
603 ECORE_GETOPT_VALUE_STR(type_glob),
604 ECORE_GETOPT_VALUE_STR(detail_name),
605 ECORE_GETOPT_VALUE_BOOL(machine),
606 ECORE_GETOPT_VALUE_BOOL(quit_option),
607 ECORE_GETOPT_VALUE_BOOL(quit_option),
608 ECORE_GETOPT_VALUE_BOOL(quit_option),
609 ECORE_GETOPT_VALUE_BOOL(quit_option),
610 ECORE_GETOPT_VALUE_NONE
611 };
612
613 setlocale(LC_NUMERIC, "C");
614
615 ecore_app_no_system_modules();
616
617 eina_init();
618
619 _log_dom = eina_log_domain_register
620 ("edje_external_inspector", EINA_COLOR_YELLOW);
621 if (_log_dom < 0)
622 {
623 EINA_LOG_CRIT
624 ("could not register log domain 'edje_external_inspector'");
625 ret = 1;
626 goto error_log;
627 }
628
629 edje_init();
630
631 arg_index = ecore_getopt_parse(&optdesc, values, argc, argv);
632 if (arg_index < 0)
633 {
634 ERR("could not parse arguments.");
635 ret = 1;
636 goto error_getopt;
637 }
638 else if (quit_option)
639 goto error_getopt;
640
641 if (!mode) mode = (char *)mode_choices[0];
642
643 if (detail_name)
644 {
645 if (!strcmp(detail_name, "none")) detail = 0;
646 else if (!strcmp(detail_name, "terse"))
647 detail = 1;
648 else if (!strcmp(detail_name, "all"))
649 detail = 2;
650 else ERR("Unknown detail level: '%s'", detail_name);
651 }
652
653 if (arg_index < argc) module_patterns = argv + arg_index;
654 else module_patterns = NULL;
655
656 modules = edje_available_modules_get();
657 module_patterns_str = _module_patterns_str_new();
658
659 if (!strcmp(mode, "info")) ret = _info_list();
660 else if (!strcmp(mode, "modules-names"))
661 ret = _modules_names_list();
662 else if (!strcmp(mode, "types-names"))
663 ret = _types_names_list();
664 else
665 {
666 ERR("Unknown mode: %s", mode);
667 ret = 1;
668 }
669
670 free(module_patterns_str);
671
672 error_getopt:
673 edje_shutdown();
674 eina_log_domain_unregister(_log_dom);
675 error_log:
676 eina_shutdown();
677
678 return ret;
679 }
680
681