cd681897c3556a68df4af627d1828a06fe059c41
[framework/uifw/ecore.git] / src / lib / ecore / ecore_getopt.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #ifdef HAVE_ALLOCA_H
6 # include <alloca.h>
7 #elif defined __GNUC__
8 # define alloca __builtin_alloca
9 #elif defined _AIX
10 # define alloca __alloca
11 #elif defined _MSC_VER
12 # include <malloc.h>
13 # define alloca _alloca
14 #else
15 # include <stddef.h>
16 # ifdef  __cplusplus
17 extern "C"
18 # endif
19 void *alloca(size_t);
20 #endif
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <ctype.h>
27
28 #ifdef ENABLE_NLS
29 # include <libintl.h>
30 #else
31 # define gettext(x)          (x)
32 # define dgettext(domain, x) (x)
33 #endif
34
35 #define _(x)                 dgettext("ecore", x)
36
37 #ifdef _WIN32_WCE
38 # include <Evil.h>
39 #endif
40
41 #ifdef HAVE_EXOTIC
42 # include <Exotic.h>
43 #endif
44
45 #include "Ecore.h"
46 #include "Ecore_Getopt.h"
47
48 static const char *prog = NULL;
49 static char **argv = NULL;
50 static int argc = 0;
51 static int cols = 80;
52 static int helpcol = 80 / 3;
53
54 static void
55 _ecore_getopt_help_print_replace_program(FILE               *fp,
56                                          const Ecore_Getopt *parser __UNUSED__,
57                                          const char         *text)
58 {
59    do
60      {
61         const char *d = strchr(text, '%');
62
63         if (!d)
64           {
65              fputs(text, fp);
66              break;
67           }
68
69         if (fwrite(text, 1, d - text, fp) != (size_t)(d - text))
70           return;
71         d++;
72         if (strncmp(d, "prog", sizeof("prog") - 1) == 0)
73           {
74              fputs(prog ? prog : "???", fp);
75              d += sizeof("prog") - 1;
76           }
77         else
78           {
79              if (d[0] == '%')
80                d++;
81              fputc('%', fp);
82           }
83
84         text = d;
85      }
86    while (text[0] != '\0');
87
88    fputc('\n', fp);
89 }
90
91 static void
92 _ecore_getopt_version(FILE               *fp,
93                       const Ecore_Getopt *parser)
94 {
95    fputs(_("Version:"), fp);
96    fputc(' ', fp);
97    _ecore_getopt_help_print_replace_program(fp, parser, parser->version);
98 }
99
100 static void
101 _ecore_getopt_help_usage(FILE               *fp,
102                          const Ecore_Getopt *parser)
103 {
104    fputs(_("Usage:"), fp);
105    fputc(' ', fp);
106
107    if (!parser->usage)
108      {
109         fprintf(fp, _("%s [options]\n"), prog);
110         return;
111      }
112
113    _ecore_getopt_help_print_replace_program(fp, parser, gettext(parser->usage));
114 }
115
116 static int
117 _ecore_getopt_help_line(FILE       *fp,
118                         const int   base,
119                         const int   total,
120                         int         used,
121                         const char *text,
122                         int         len)
123 {
124    int linebreak = 0;
125    do
126      {
127         /* process line considering spaces (new line and tabs are spaces!) */
128          while ((used < total) && (len > 0))
129            {
130               const char *space = NULL;
131               int i, todo;
132
133               todo = total - used;
134               if (todo > len)
135                 todo = len;
136
137               for (i = 0; i < todo; i++)
138                 if (isspace((unsigned char)text[i]))
139                   {
140                      space = text + i;
141                      break;
142                   }
143
144               if (space)
145                 {
146                    i = fwrite(text, 1, i, fp);
147                    i++;
148                    text += i;
149                    len -= i;
150                    used += i;
151
152                    if (linebreak)
153                      {
154                         linebreak = 0;
155                         continue;
156                      }
157
158                    if (space[0] == '\n')
159                      break;
160                    else if (space[0] == '\t')
161                      {
162                         int c;
163
164                         used--;
165                         c = ((used / 8) + 1) * 8;
166                         if (c < total)
167                           {
168                              for (; used < c; used++)
169                                fputc(' ', fp);
170                           }
171                         else
172                           {
173                              text--;
174                              len++;
175                              break;
176                           }
177                      }
178                    else if (used < total)
179                      fputc(space[0], fp);
180                 }
181               else
182                 {
183                    i = fwrite(text, 1, i, fp);
184                    text += i;
185                    len -= i;
186                    used += i;
187                 }
188               linebreak = 0;
189            }
190          if (len <= 0)
191            break;
192          linebreak = 1;
193          fputc('\n', fp);
194          for (used = 0; used < base; used++)
195            fputc(' ', fp);
196      }
197    while (1);
198
199    return used;
200 }
201
202 static void
203 _ecore_getopt_help_description(FILE               *fp,
204                                const Ecore_Getopt *parser)
205 {
206    const char *p, *prg, *ver;
207    int used, prglen, verlen;
208
209    p = gettext(parser->description);
210    if (!p)
211      return;
212
213    fputc('\n', fp);
214
215    prg = prog ? prog : "???";
216    ver = parser->version ? parser->version : "???";
217
218    prglen = strlen(prg);
219    verlen = strlen(ver);
220
221    used = 0;
222
223    do
224      {
225         const char *d = strchr(p, '%');
226
227         if (!d)
228           {
229              _ecore_getopt_help_line(fp, 0, cols, used, p, strlen(p));
230              break;
231           }
232
233         used = _ecore_getopt_help_line(fp, 0, cols, used, p, d - p);
234         d++;
235         if (strncmp(d, "prog", sizeof("prog") - 1) == 0)
236           {
237              used = _ecore_getopt_help_line(fp, 0, cols, used, prg, prglen);
238              d += sizeof("prog") - 1;
239           }
240         else if (strncmp(d, "version", sizeof("version") - 1) == 0)
241           {
242              used = _ecore_getopt_help_line(fp, 0, cols, used, ver, verlen);
243              d += sizeof("version") - 1;
244           }
245         else
246           {
247              if (d[0] == '%')
248                d++;
249              used = _ecore_getopt_help_line(fp, 0, cols, used, "%", 1);
250           }
251
252         p = d;
253      }
254    while (p[0] != '\0');
255
256    fputs("\n\n", fp);
257 }
258
259 static void
260 _ecore_getopt_copyright(FILE               *fp,
261                         const Ecore_Getopt *parser)
262 {
263    const char *txt = gettext(parser->copyright);
264    fputs(_("Copyright:"), fp);
265    fputs("\n   ", fp);
266    _ecore_getopt_help_line
267      (fp, 3, cols, 3, txt, strlen(txt));
268    fputc('\n', fp);
269 }
270
271 static void
272 _ecore_getopt_license(FILE               *fp,
273                       const Ecore_Getopt *parser)
274 {
275    const char *txt = gettext(parser->license);
276    fputs(_("License:"), fp);
277    fputs("\n   ", fp);
278    _ecore_getopt_help_line
279      (fp, 3, cols, 3, txt, strlen(txt));
280    fputc('\n', fp);
281 }
282
283 static Ecore_Getopt_Desc_Arg_Requirement
284 _ecore_getopt_desc_arg_requirement(const Ecore_Getopt_Desc *desc)
285 {
286    switch (desc->action)
287      {
288       case ECORE_GETOPT_ACTION_STORE:
289         return desc->action_param.store.arg_req;
290
291       case ECORE_GETOPT_ACTION_STORE_CONST:
292         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
293
294       case ECORE_GETOPT_ACTION_STORE_TRUE:
295         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
296
297       case ECORE_GETOPT_ACTION_STORE_FALSE:
298         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
299
300       case ECORE_GETOPT_ACTION_CHOICE:
301         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES;
302
303       case ECORE_GETOPT_ACTION_APPEND:
304         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES;
305
306       case ECORE_GETOPT_ACTION_COUNT:
307         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
308
309       case ECORE_GETOPT_ACTION_CALLBACK:
310         return desc->action_param.callback.arg_req;
311
312       case ECORE_GETOPT_ACTION_HELP:
313         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
314
315       case ECORE_GETOPT_ACTION_VERSION:
316         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
317
318       default:
319         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
320      }
321 }
322
323 static void
324 _ecore_getopt_help_desc_setup_metavar(const Ecore_Getopt_Desc *desc,
325                                       char                    *metavar,
326                                       int                     *metavarlen,
327                                       int                      maxsize)
328 {
329    if (desc->metavar)
330      {
331         const char *txt = gettext(desc->metavar);
332         *metavarlen = strlen(txt);
333         if (*metavarlen > maxsize - 1)
334           *metavarlen = maxsize - 1;
335
336         memcpy(metavar, txt, *metavarlen);
337         metavar[*metavarlen] = '\0';
338      }
339    else if (desc->longname)
340      {
341         int i;
342
343         *metavarlen = strlen(desc->longname);
344         if (*metavarlen > maxsize - 1)
345           *metavarlen = maxsize - 1;
346
347         for (i = 0; i < *metavarlen; i++)
348           metavar[i] = toupper((int) desc->longname[i]);
349         metavar[i] = '\0';
350      }
351 }
352
353 static int
354 _ecore_getopt_help_desc_show_arg(FILE                             *fp,
355                                  Ecore_Getopt_Desc_Arg_Requirement requirement,
356                                  const char                       *metavar,
357                                  int                               metavarlen)
358 {
359    int used;
360
361    if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
362      return 0;
363
364    used = 0;
365
366    if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL)
367      {
368         fputc('[', fp);
369         used++;
370      }
371
372    if (requirement != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
373      {
374         fputc('=', fp);
375         fputs(metavar, fp);
376         used += metavarlen + 1;
377      }
378
379    if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL)
380      {
381         fputc(']', fp);
382         used++;
383      }
384
385    return used;
386 }
387
388 static int
389 _ecore_getopt_help_desc_store(FILE                    *fp,
390                               const int                base,
391                               const int                total,
392                               int                      used,
393                               const Ecore_Getopt_Desc *desc)
394 {
395    const Ecore_Getopt_Desc_Store *store = &desc->action_param.store;
396    char buf[64];
397    const char *str;
398    size_t len;
399
400    fputc('\n', fp);
401    for (used = 0; used < base; used++)
402      fputc(' ', fp);
403
404    switch (store->type)
405      {
406       case ECORE_GETOPT_TYPE_STR:
407         str = "STR";
408         len = sizeof("STR") - 1;
409         break;
410
411       case ECORE_GETOPT_TYPE_BOOL:
412         str = "BOOL";
413         len = sizeof("BOOL") - 1;
414         break;
415
416       case ECORE_GETOPT_TYPE_SHORT:
417         str = "SHORT";
418         len = sizeof("SHORT") - 1;
419         break;
420
421       case ECORE_GETOPT_TYPE_INT:
422         str = "INT";
423         len = sizeof("INT") - 1;
424         break;
425
426       case ECORE_GETOPT_TYPE_LONG:
427         str = "LONG";
428         len = sizeof("LONG") - 1;
429         break;
430
431       case ECORE_GETOPT_TYPE_USHORT:
432         str = "USHORT";
433         len = sizeof("USHORT") - 1;
434         break;
435
436       case ECORE_GETOPT_TYPE_UINT:
437         str = "UINT";
438         len = sizeof("UINT") - 1;
439         break;
440
441       case ECORE_GETOPT_TYPE_ULONG:
442         str = "ULONG";
443         len = sizeof("ULONG") - 1;
444         break;
445
446       case ECORE_GETOPT_TYPE_DOUBLE:
447         str = "DOUBLE";
448         len = sizeof("DOUBLE") - 1;
449         break;
450
451       default:
452         str = "???";
453         len = sizeof("???") - 1;
454      }
455
456    used = _ecore_getopt_help_line
457        (fp, base, total, used, _("Type: "), strlen(_("Type: ")));
458    used = _ecore_getopt_help_line(fp, base, total, used, str, len);
459
460    if (store->arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES)
461      goto end;
462
463    used = _ecore_getopt_help_line
464        (fp, base, total, used, ". ", sizeof(". ") - 1);
465
466    switch (store->type)
467      {
468       case ECORE_GETOPT_TYPE_STR:
469         str = store->def.strv;
470         len = str ? strlen(str) : 0;
471         break;
472
473       case ECORE_GETOPT_TYPE_BOOL:
474         str = store->def.boolv ? "true" : "false";
475         len = strlen(str);
476         break;
477
478       case ECORE_GETOPT_TYPE_SHORT:
479         str = buf;
480         len = snprintf(buf, sizeof(buf), "%hd", store->def.shortv);
481         if (len > sizeof(buf) - 1)
482           len = sizeof(buf) - 1;
483         break;
484
485       case ECORE_GETOPT_TYPE_INT:
486         str = buf;
487         len = snprintf(buf, sizeof(buf), "%d", store->def.intv);
488         if (len > sizeof(buf) - 1)
489           len = sizeof(buf) - 1;
490         break;
491
492       case ECORE_GETOPT_TYPE_LONG:
493         str = buf;
494         len = snprintf(buf, sizeof(buf), "%ld", store->def.longv);
495         if (len > sizeof(buf) - 1)
496           len = sizeof(buf) - 1;
497         break;
498
499       case ECORE_GETOPT_TYPE_USHORT:
500         str = buf;
501         len = snprintf(buf, sizeof(buf), "%hu", store->def.ushortv);
502         if (len > sizeof(buf) - 1)
503           len = sizeof(buf) - 1;
504         break;
505
506       case ECORE_GETOPT_TYPE_UINT:
507         str = buf;
508         len = snprintf(buf, sizeof(buf), "%u", store->def.uintv);
509         if (len > sizeof(buf) - 1)
510           len = sizeof(buf) - 1;
511         break;
512
513       case ECORE_GETOPT_TYPE_ULONG:
514         str = buf;
515         len = snprintf(buf, sizeof(buf), "%lu", store->def.ulongv);
516         if (len > sizeof(buf) - 1)
517           len = sizeof(buf) - 1;
518         break;
519
520       case ECORE_GETOPT_TYPE_DOUBLE:
521         str = buf;
522         len = snprintf(buf, sizeof(buf), "%f", store->def.doublev);
523         if (len > sizeof(buf) - 1)
524           len = sizeof(buf) - 1;
525         break;
526
527       default:
528         str = "???";
529         len = sizeof("???") - 1;
530      }
531
532    used = _ecore_getopt_help_line
533        (fp, base, total, used, _("Default: "), strlen(_("Default: ")));
534    used = _ecore_getopt_help_line(fp, base, total, used, str, len);
535
536 end:
537    return _ecore_getopt_help_line(fp, base, total, used, ".", 1);
538 }
539
540 static int
541 _ecore_getopt_help_desc_choices(FILE                    *fp,
542                                 const int                base,
543                                 const int                total,
544                                 int                      used,
545                                 const Ecore_Getopt_Desc *desc)
546 {
547    const char *const *itr;
548    const char sep[] = ", ";
549    const int seplen = sizeof(sep) - 1;
550
551    if (used > 0)
552      {
553         fputc('\n', fp);
554         used = 0;
555      }
556    for (; used < base; used++)
557      fputc(' ', fp);
558
559    used = _ecore_getopt_help_line
560        (fp, base, total, used, _("Choices: "), strlen(_("Choices: ")));
561
562    for (itr = desc->action_param.choices; *itr; itr++)
563      {
564         used = _ecore_getopt_help_line
565             (fp, base, total, used, *itr, strlen(*itr));
566         if (itr[1])
567           used = _ecore_getopt_help_line(fp, base, total, used, sep, seplen);
568      }
569
570    return _ecore_getopt_help_line(fp, base, total, used, ".", 1);
571 }
572
573 static void
574 _ecore_getopt_help_desc(FILE                    *fp,
575                         const Ecore_Getopt_Desc *desc)
576 {
577    Ecore_Getopt_Desc_Arg_Requirement arg_req;
578    char metavar[32] = "ARG";
579    int metavarlen = 3;
580    int used;
581
582    arg_req = _ecore_getopt_desc_arg_requirement(desc);
583    if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
584      _ecore_getopt_help_desc_setup_metavar
585        (desc, metavar, &metavarlen, sizeof(metavar));
586
587    fputs("  ", fp);
588    used = 2;
589
590    if (desc->shortname)
591      {
592         fputc('-', fp);
593         fputc(desc->shortname, fp);
594         used += 2;
595         used += _ecore_getopt_help_desc_show_arg
596             (fp, arg_req, metavar, metavarlen);
597      }
598
599    if (desc->shortname && desc->longname)
600      {
601         fputs(", ", fp);
602         used += 2;
603      }
604
605    if (desc->longname)
606      {
607         int namelen = strlen(desc->longname);
608
609         fputs("--", fp);
610         fputs(desc->longname, fp);
611         used += 2 + namelen;
612         used += _ecore_getopt_help_desc_show_arg
613             (fp, arg_req, metavar, metavarlen);
614      }
615
616    if (!desc->help)
617      goto end;
618
619    if (used + 3 >= helpcol)
620      {
621         fputc('\n', fp);
622         used = 0;
623      }
624
625    for (; used < helpcol; used++)
626      fputc(' ', fp);
627
628    used = _ecore_getopt_help_line
629        (fp, helpcol, cols, used, desc->help, strlen(desc->help));
630
631    switch (desc->action)
632      {
633       case ECORE_GETOPT_ACTION_STORE:
634         _ecore_getopt_help_desc_store(fp, helpcol, cols, used, desc);
635         break;
636
637       case ECORE_GETOPT_ACTION_CHOICE:
638         _ecore_getopt_help_desc_choices(fp, helpcol, cols, used, desc);
639         break;
640
641       default:
642         break;
643      }
644
645 end:
646    fputc('\n', fp);
647 }
648
649 static Eina_Bool
650 _ecore_getopt_desc_is_sentinel(const Ecore_Getopt_Desc *desc)
651 {
652    return (desc->shortname == '\0') && (!desc->longname);
653 }
654
655 static void
656 _ecore_getopt_help_options(FILE               *fp,
657                            const Ecore_Getopt *parser)
658 {
659    const Ecore_Getopt_Desc *desc;
660
661    fputs(_("Options:\n"), fp);
662
663    for (desc = parser->descs; !_ecore_getopt_desc_is_sentinel(desc); desc++)
664      _ecore_getopt_help_desc(fp, desc);
665
666    fputc('\n', fp);
667 }
668
669 /**
670  * Show nicely formatted help message for the given parser.
671  *
672  * Message will be print to stderr.
673  */
674 void
675 ecore_getopt_help(FILE               *fp,
676                   const Ecore_Getopt *parser)
677 {
678    const char *var;
679
680    if (!parser) return;
681
682    if (argc < 1)
683      {
684         ecore_app_args_get(&argc, &argv);
685         if ((argc > 0) && (argv[0]))
686           prog = argv[0];
687         else
688           prog = parser->prog;
689      }
690
691    var = getenv("COLUMNS");
692    if (var)
693      {
694         cols = atoi(var);
695         if (cols < 20)
696           cols = 20;
697
698         helpcol = cols / 3;
699      }
700
701    _ecore_getopt_help_usage(fp, parser);
702    _ecore_getopt_help_description(fp, parser);
703    _ecore_getopt_help_options(fp, parser);
704 }
705
706 static const Ecore_Getopt_Desc *
707 _ecore_getopt_parse_find_long(const Ecore_Getopt *parser,
708                               const char         *name)
709 {
710    const Ecore_Getopt_Desc *desc = parser->descs;
711    const char *p = strchr(name, '=');
712    int len = 0;
713
714    if (p)
715      len = p - name;
716
717    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
718      {
719         if (!desc->longname)
720           continue;
721
722         if (p)
723           {
724              if ((strncmp(name, desc->longname, len) == 0) &&
725                  (desc->longname[len] == '\0'))
726                return desc;
727           }
728         else
729           {
730              if (strcmp(name, desc->longname) == 0)
731                return desc;
732           }
733      }
734
735    return NULL;
736 }
737
738 static const Ecore_Getopt_Desc *
739 _ecore_getopt_parse_find_short(const Ecore_Getopt *parser,
740                                char                name)
741 {
742    const Ecore_Getopt_Desc *desc = parser->descs;
743    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
744      if (name == desc->shortname)
745        return desc;
746    return NULL;
747 }
748
749 static int
750 _ecore_getopt_parse_find_nonargs_base(const Ecore_Getopt *parser,
751                                       int                 argc,
752                                       char              **argv)
753 {
754    char **nonargs;
755    int src, dst, used, base;
756
757    nonargs = alloca(sizeof(char *) * argc);
758    src = 1;
759    dst = 1;
760    used = 0;
761    base = 0;
762    while (src < argc)
763      {
764         const Ecore_Getopt_Desc *desc;
765         Ecore_Getopt_Desc_Arg_Requirement arg_req;
766         char *arg = argv[src];
767
768         if (arg[0] != '-')
769           goto found_nonarg;
770
771         if (arg[1] == '-')
772           {
773              if (arg[2] == '\0') /* explicit end of options, "--" */
774                {
775                   base = 1;
776                   break;
777                }
778              desc = _ecore_getopt_parse_find_long(parser, arg + 2);
779           }
780         else
781           desc = _ecore_getopt_parse_find_short(parser, arg[1]);
782
783         if (!desc)
784           {
785              if (arg[1] == '-')
786                fprintf(stderr, _("ERROR: unknown option --%s.\n"), arg + 2);
787              else
788                fprintf(stderr, _("ERROR: unknown option -%c.\n"), arg[1]);
789              if (parser->strict)
790                {
791                   memmove(argv + dst, nonargs, used * sizeof(char *));
792                   return -1;
793                }
794              else
795                goto found_nonarg;
796           }
797
798         if (src != dst)
799           argv[dst] = argv[src];
800         src++;
801         dst++;
802
803         arg_req = _ecore_getopt_desc_arg_requirement(desc);
804         if (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
805           continue;
806
807         if (strchr(arg, '='))
808           continue;
809
810         if ((src >= argc) || (argv[src][0] == '-'))
811           continue;
812
813         if (src != dst)
814           argv[dst] = argv[src];
815         src++;
816         dst++;
817         continue;
818
819 found_nonarg:
820         nonargs[used] = arg;
821         used++;
822         src++;
823      }
824
825    if (!base) /* '--' not found */
826      base = dst;
827    else
828      {
829         base = dst;
830         if (src != dst)
831           argv[dst] = argv[src];
832         dst++;
833      }
834
835    memmove(argv + dst, nonargs, used * sizeof(char *));
836    return base;
837 }
838
839 static void
840 _ecore_getopt_desc_print_error(const Ecore_Getopt_Desc *desc,
841                                const char              *fmt,
842                                ...)
843 {
844    va_list ap;
845
846    fputs(_("ERROR: "), stderr);
847
848    if (desc->shortname)
849      {
850         fputc('-', stderr);
851         fputc(desc->shortname, stderr);
852      }
853
854    if (desc->shortname && desc->longname)
855      fputs(", ", stderr);
856
857    if (desc->longname)
858      {
859         fputs("--", stderr);
860         fputs(desc->longname, stderr);
861      }
862
863    fputs(": ", stderr);
864
865    va_start(ap, fmt);
866    vfprintf(stderr, fmt, ap);
867    va_end(ap);
868 }
869
870 static Eina_Bool
871 _ecore_getopt_parse_bool(const char *str,
872                          Eina_Bool  *v)
873 {
874    if ((strcmp(str, "0") == 0) ||
875        (strcasecmp(str, "f") == 0) ||
876        (strcasecmp(str, "false") == 0) ||
877        (strcasecmp(str, "no") == 0) ||
878        (strcasecmp(str, "off") == 0)
879        )
880      {
881         *v = EINA_FALSE;
882         return EINA_TRUE;
883      }
884    else if ((strcmp(str, "1") == 0) ||
885             (strcasecmp(str, "t") == 0) ||
886             (strcasecmp(str, "true") == 0) ||
887             (strcasecmp(str, "yes") == 0) ||
888             (strcasecmp(str, "on") == 0)
889             )
890      {
891         *v = EINA_TRUE;
892         return EINA_TRUE;
893      }
894
895    return EINA_FALSE;
896 }
897
898 static Eina_Bool
899 _ecore_getopt_parse_long(const char *str,
900                          long int   *v)
901 {
902    char *endptr = NULL;
903    *v = strtol(str, &endptr, 0);
904    return endptr > str;
905 }
906
907 static Eina_Bool
908 _ecore_getopt_parse_double(const char *str,
909                            double     *v)
910 {
911    char *endptr = NULL;
912    *v = strtod(str, &endptr);
913    return endptr > str;
914 }
915
916 static Eina_Bool
917 _ecore_getopt_parse_store(const Ecore_Getopt      *parser __UNUSED__,
918                           const Ecore_Getopt_Desc *desc,
919                           Ecore_Getopt_Value      *value,
920                           const char              *arg_val)
921 {
922    const Ecore_Getopt_Desc_Store *store = &desc->action_param.store;
923    long int v;
924    double d;
925    Eina_Bool b;
926
927    if (!value->ptrp)
928      {
929         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
930         return EINA_FALSE;
931      }
932
933    switch (store->arg_req)
934      {
935       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO:
936         goto use_optional;
937
938       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL:
939         if (!arg_val)
940           goto use_optional;
941
942       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES:
943         break;
944      }
945
946    switch (store->type)
947      {
948       case ECORE_GETOPT_TYPE_STR:
949         *value->strp = (char *)arg_val;
950         return EINA_TRUE;
951
952       case ECORE_GETOPT_TYPE_BOOL:
953         if (_ecore_getopt_parse_bool(arg_val, &b))
954           {
955              *value->boolp = b;
956              return EINA_TRUE;
957           }
958         else
959           {
960              _ecore_getopt_desc_print_error
961                (desc, _("unknown boolean value %s.\n"), arg_val);
962              return EINA_FALSE;
963           }
964
965       case ECORE_GETOPT_TYPE_SHORT:
966         if (!_ecore_getopt_parse_long(arg_val, &v))
967           goto error;
968         *value->shortp = v;
969         return EINA_TRUE;
970
971       case ECORE_GETOPT_TYPE_INT:
972         if (!_ecore_getopt_parse_long(arg_val, &v))
973           goto error;
974         *value->intp = v;
975         return EINA_TRUE;
976
977       case ECORE_GETOPT_TYPE_LONG:
978         if (!_ecore_getopt_parse_long(arg_val, &v))
979           goto error;
980         *value->longp = v;
981         return EINA_TRUE;
982
983       case ECORE_GETOPT_TYPE_USHORT:
984         if (!_ecore_getopt_parse_long(arg_val, &v))
985           goto error;
986         *value->ushortp = v;
987         return EINA_TRUE;
988
989       case ECORE_GETOPT_TYPE_UINT:
990         if (!_ecore_getopt_parse_long(arg_val, &v))
991           goto error;
992         *value->uintp = v;
993         return EINA_TRUE;
994
995       case ECORE_GETOPT_TYPE_ULONG:
996         if (!_ecore_getopt_parse_long(arg_val, &v))
997           goto error;
998         *value->ulongp = v;
999         return EINA_TRUE;
1000
1001       case ECORE_GETOPT_TYPE_DOUBLE:
1002         if (!_ecore_getopt_parse_double(arg_val, &d))
1003           goto error;
1004         *value->doublep = d;
1005         break;
1006      }
1007
1008    return EINA_TRUE;
1009
1010 error:
1011    _ecore_getopt_desc_print_error
1012      (desc, _("invalid number format %s\n"), arg_val);
1013    return EINA_FALSE;
1014
1015 use_optional:
1016    switch (store->type)
1017      {
1018       case ECORE_GETOPT_TYPE_STR:
1019         *value->strp = (char *)store->def.strv;
1020         break;
1021
1022       case ECORE_GETOPT_TYPE_BOOL:
1023         *value->boolp = store->def.boolv;
1024         break;
1025
1026       case ECORE_GETOPT_TYPE_SHORT:
1027         *value->shortp = store->def.shortv;
1028         break;
1029
1030       case ECORE_GETOPT_TYPE_INT:
1031         *value->intp = store->def.intv;
1032         break;
1033
1034       case ECORE_GETOPT_TYPE_LONG:
1035         *value->longp = store->def.longv;
1036         break;
1037
1038       case ECORE_GETOPT_TYPE_USHORT:
1039         *value->ushortp = store->def.ushortv;
1040         break;
1041
1042       case ECORE_GETOPT_TYPE_UINT:
1043         *value->uintp = store->def.uintv;
1044         break;
1045
1046       case ECORE_GETOPT_TYPE_ULONG:
1047         *value->ulongp = store->def.ulongv;
1048         break;
1049
1050       case ECORE_GETOPT_TYPE_DOUBLE:
1051         *value->doublep = store->def.doublev;
1052         break;
1053      }
1054
1055    return EINA_TRUE;
1056 }
1057
1058 static Eina_Bool
1059 _ecore_getopt_parse_store_const(const Ecore_Getopt      *parser __UNUSED__,
1060                                 const Ecore_Getopt_Desc *desc,
1061                                 Ecore_Getopt_Value      *val,
1062                                 const char              *arg_val __UNUSED__)
1063 {
1064    if (!val->ptrp)
1065      {
1066         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1067         return EINA_FALSE;
1068      }
1069
1070    *val->ptrp = (void *)desc->action_param.store_const;
1071    return EINA_TRUE;
1072 }
1073
1074 static Eina_Bool
1075 _ecore_getopt_parse_store_true(const Ecore_Getopt      *parser __UNUSED__,
1076                                const Ecore_Getopt_Desc *desc,
1077                                Ecore_Getopt_Value      *val,
1078                                const char              *arg_val __UNUSED__)
1079 {
1080    if (!val->boolp)
1081      {
1082         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1083         return EINA_FALSE;
1084      }
1085    *val->boolp = EINA_TRUE;
1086    return EINA_TRUE;
1087 }
1088
1089 static Eina_Bool
1090 _ecore_getopt_parse_store_false(const Ecore_Getopt      *parser __UNUSED__,
1091                                 const Ecore_Getopt_Desc *desc,
1092                                 Ecore_Getopt_Value      *val,
1093                                 const char              *arg_val __UNUSED__)
1094 {
1095    if (!val->boolp)
1096      {
1097         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1098         return EINA_FALSE;
1099      }
1100    *val->boolp = EINA_FALSE;
1101    return EINA_TRUE;
1102 }
1103
1104 static Eina_Bool
1105 _ecore_getopt_parse_choice(const Ecore_Getopt      *parser __UNUSED__,
1106                            const Ecore_Getopt_Desc *desc,
1107                            Ecore_Getopt_Value      *val,
1108                            const char              *arg_val)
1109 {
1110    const char *const *pchoice;
1111
1112    if (!val->strp)
1113      {
1114         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1115         return EINA_FALSE;
1116      }
1117
1118    pchoice = desc->action_param.choices;
1119    for (; *pchoice; pchoice++)
1120      if (strcmp(*pchoice, arg_val) == 0)
1121        {
1122           *val->strp = (char *)*pchoice;
1123           return EINA_TRUE;
1124        }
1125
1126    _ecore_getopt_desc_print_error
1127      (desc, _("invalid choice \"%s\". Valid values are: "), arg_val);
1128
1129    pchoice = desc->action_param.choices;
1130    for (; *pchoice; pchoice++)
1131      {
1132         fputs(*pchoice, stderr);
1133         if (pchoice[1])
1134           fputs(", ", stderr);
1135      }
1136
1137    fputs(".\n", stderr);
1138    return EINA_FALSE;
1139 }
1140
1141 static Eina_Bool
1142 _ecore_getopt_parse_append(const Ecore_Getopt      *parser __UNUSED__,
1143                            const Ecore_Getopt_Desc *desc,
1144                            Ecore_Getopt_Value      *val,
1145                            const char              *arg_val)
1146 {
1147    void *data;
1148    long int v;
1149    double d;
1150    Eina_Bool b;
1151
1152    if (!arg_val)
1153      {
1154         _ecore_getopt_desc_print_error
1155           (desc, _("missing parameter to append.\n"));
1156         return EINA_FALSE;
1157      }
1158
1159    if (!val->listp)
1160      {
1161         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1162         return EINA_FALSE;
1163      }
1164
1165    switch (desc->action_param.append_type)
1166      {
1167       case ECORE_GETOPT_TYPE_STR:
1168         data = strdup(arg_val);
1169         break;
1170
1171       case ECORE_GETOPT_TYPE_BOOL:
1172       {
1173          if (_ecore_getopt_parse_bool(arg_val, &b))
1174            {
1175               data = malloc(sizeof(Eina_Bool));
1176               if (data)
1177                 *(Eina_Bool *)data = b;
1178            }
1179          else
1180            {
1181               _ecore_getopt_desc_print_error(desc, _("unknown boolean value %s.\n"), arg_val);
1182               return EINA_FALSE;
1183            }
1184       }
1185       break;
1186
1187       case ECORE_GETOPT_TYPE_SHORT:
1188       {
1189          if (!_ecore_getopt_parse_long(arg_val, &v))
1190            goto error;
1191          data = malloc(sizeof(short));
1192          if (data)
1193            *(short *)data = (short)v;
1194       }
1195       break;
1196
1197       case ECORE_GETOPT_TYPE_INT:
1198       {
1199          if (!_ecore_getopt_parse_long(arg_val, &v))
1200            goto error;
1201          data = malloc(sizeof(int));
1202          if (data)
1203            *(int *)data = (int)v;
1204       }
1205       break;
1206
1207       case ECORE_GETOPT_TYPE_LONG:
1208       {
1209          if (!_ecore_getopt_parse_long(arg_val, &v))
1210            goto error;
1211          data = malloc(sizeof(long));
1212          if (data)
1213            *(long *)data = v;
1214       }
1215       break;
1216
1217       case ECORE_GETOPT_TYPE_USHORT:
1218       {
1219          if (!_ecore_getopt_parse_long(arg_val, &v))
1220            goto error;
1221          data = malloc(sizeof(unsigned short));
1222          if (data)
1223            *(unsigned short *)data = (unsigned short)v;
1224       }
1225       break;
1226
1227       case ECORE_GETOPT_TYPE_UINT:
1228       {
1229          if (!_ecore_getopt_parse_long(arg_val, &v))
1230            goto error;
1231          data = malloc(sizeof(unsigned int));
1232          if (data)
1233            *(unsigned int *)data = (unsigned int)v;
1234       }
1235       break;
1236
1237       case ECORE_GETOPT_TYPE_ULONG:
1238       {
1239          if (!_ecore_getopt_parse_long(arg_val, &v))
1240            goto error;
1241          data = malloc(sizeof(unsigned long));
1242          if (data)
1243            *(unsigned long *)data = v;
1244       }
1245       break;
1246
1247       case ECORE_GETOPT_TYPE_DOUBLE:
1248       {
1249          if (!_ecore_getopt_parse_double(arg_val, &d))
1250            goto error;
1251          data = malloc(sizeof(double));
1252          if (data)
1253            *(double *)data = d;
1254       }
1255       break;
1256
1257       default:
1258       {
1259          _ecore_getopt_desc_print_error(desc, _("could not parse value.\n"));
1260          return EINA_FALSE;
1261       }
1262      }
1263
1264    *val->listp = eina_list_append(*val->listp, data);
1265    return EINA_TRUE;
1266
1267 error:
1268    _ecore_getopt_desc_print_error
1269      (desc, _("invalid number format %s\n"), arg_val);
1270    return EINA_FALSE;
1271 }
1272
1273 static Eina_Bool
1274 _ecore_getopt_parse_count(const Ecore_Getopt      *parser __UNUSED__,
1275                           const Ecore_Getopt_Desc *desc,
1276                           Ecore_Getopt_Value      *val,
1277                           const char              *arg_val __UNUSED__)
1278 {
1279    if (!val->intp)
1280      {
1281         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1282         return EINA_FALSE;
1283      }
1284
1285    (*val->intp)++;
1286    return EINA_TRUE;
1287 }
1288
1289 static Eina_Bool
1290 _ecore_getopt_parse_callback(const Ecore_Getopt      *parser,
1291                              const Ecore_Getopt_Desc *desc,
1292                              Ecore_Getopt_Value      *val,
1293                              const char              *arg_val)
1294 {
1295    const Ecore_Getopt_Desc_Callback *cb = &desc->action_param.callback;
1296
1297    switch (cb->arg_req)
1298      {
1299       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO:
1300         arg_val = cb->def;
1301         break;
1302
1303       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL:
1304         if (!arg_val)
1305           arg_val = cb->def;
1306         break;
1307
1308       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES:
1309         break;
1310      }
1311
1312    if (cb->arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
1313      {
1314         if ((!arg_val) || (arg_val[0] == '\0'))
1315           {
1316              _ecore_getopt_desc_print_error(desc, _("missing parameter.\n"));
1317              return EINA_FALSE;
1318           }
1319
1320         if (!val->ptrp)
1321           {
1322              _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1323              return EINA_FALSE;
1324           }
1325      }
1326
1327    if (!cb->func)
1328      {
1329         _ecore_getopt_desc_print_error(desc, _("missing callback function!\n"));
1330         return EINA_FALSE;
1331      }
1332
1333    return cb->func(parser, desc, arg_val, (void *)cb->data, val);
1334 }
1335
1336 static Eina_Bool
1337 _ecore_getopt_parse_help(const Ecore_Getopt      *parser,
1338                          const Ecore_Getopt_Desc *desc __UNUSED__,
1339                          Ecore_Getopt_Value      *val,
1340                          const char              *arg_val __UNUSED__)
1341 {
1342    if (val->boolp)
1343      (*val->boolp) = EINA_TRUE;
1344    ecore_getopt_help(stdout, parser);
1345    return EINA_TRUE;
1346 }
1347
1348 static Eina_Bool
1349 _ecore_getopt_parse_version(const Ecore_Getopt      *parser,
1350                             const Ecore_Getopt_Desc *desc,
1351                             Ecore_Getopt_Value      *val,
1352                             const char              *arg_val __UNUSED__)
1353 {
1354    if (val->boolp)
1355      (*val->boolp) = EINA_TRUE;
1356    if (!parser->version)
1357      {
1358         _ecore_getopt_desc_print_error(desc, _("no version was defined.\n"));
1359         return EINA_FALSE;
1360      }
1361    _ecore_getopt_version(stdout, parser);
1362    return EINA_TRUE;
1363 }
1364
1365 static Eina_Bool
1366 _ecore_getopt_parse_copyright(const Ecore_Getopt      *parser,
1367                               const Ecore_Getopt_Desc *desc,
1368                               Ecore_Getopt_Value      *val,
1369                               const char              *arg_val __UNUSED__)
1370 {
1371    if (val->boolp)
1372      (*val->boolp) = EINA_TRUE;
1373    if (!parser->copyright)
1374      {
1375         _ecore_getopt_desc_print_error(desc, _("no copyright was defined.\n"));
1376         return EINA_FALSE;
1377      }
1378    _ecore_getopt_copyright(stdout, parser);
1379    return EINA_TRUE;
1380 }
1381
1382 static Eina_Bool
1383 _ecore_getopt_parse_license(const Ecore_Getopt      *parser,
1384                             const Ecore_Getopt_Desc *desc,
1385                             Ecore_Getopt_Value      *val,
1386                             const char              *arg_val __UNUSED__)
1387 {
1388    if (val->boolp)
1389      (*val->boolp) = EINA_TRUE;
1390    if (!parser->license)
1391      {
1392         _ecore_getopt_desc_print_error(desc, _("no license was defined.\n"));
1393         return EINA_FALSE;
1394      }
1395    _ecore_getopt_license(stdout, parser);
1396    return EINA_TRUE;
1397 }
1398
1399 static Eina_Bool
1400 _ecore_getopt_desc_handle(const Ecore_Getopt      *parser,
1401                           const Ecore_Getopt_Desc *desc,
1402                           Ecore_Getopt_Value      *value,
1403                           const char              *arg_val)
1404 {
1405    switch (desc->action)
1406      {
1407       case ECORE_GETOPT_ACTION_STORE:
1408         return _ecore_getopt_parse_store(parser, desc, value, arg_val);
1409
1410       case ECORE_GETOPT_ACTION_STORE_CONST:
1411         return _ecore_getopt_parse_store_const(parser, desc, value, arg_val);
1412
1413       case ECORE_GETOPT_ACTION_STORE_TRUE:
1414         return _ecore_getopt_parse_store_true(parser, desc, value, arg_val);
1415
1416       case ECORE_GETOPT_ACTION_STORE_FALSE:
1417         return _ecore_getopt_parse_store_false(parser, desc, value, arg_val);
1418
1419       case ECORE_GETOPT_ACTION_CHOICE:
1420         return _ecore_getopt_parse_choice(parser, desc, value, arg_val);
1421
1422       case ECORE_GETOPT_ACTION_APPEND:
1423         return _ecore_getopt_parse_append(parser, desc, value, arg_val);
1424
1425       case ECORE_GETOPT_ACTION_COUNT:
1426         return _ecore_getopt_parse_count(parser, desc, value, arg_val);
1427
1428       case ECORE_GETOPT_ACTION_CALLBACK:
1429         return _ecore_getopt_parse_callback(parser, desc, value, arg_val);
1430
1431       case ECORE_GETOPT_ACTION_HELP:
1432         return _ecore_getopt_parse_help(parser, desc, value, arg_val);
1433
1434       case ECORE_GETOPT_ACTION_VERSION:
1435         return _ecore_getopt_parse_version(parser, desc, value, arg_val);
1436
1437       case ECORE_GETOPT_ACTION_COPYRIGHT:
1438         return _ecore_getopt_parse_copyright(parser, desc, value, arg_val);
1439
1440       case ECORE_GETOPT_ACTION_LICENSE:
1441         return _ecore_getopt_parse_license(parser, desc, value, arg_val);
1442
1443       default:
1444         return EINA_FALSE;
1445      }
1446 }
1447
1448 static Eina_Bool
1449 _ecore_getopt_parse_arg_long(const Ecore_Getopt *parser,
1450                              Ecore_Getopt_Value *values,
1451                              int                 argc __UNUSED__,
1452                              char              **argv,
1453                              int                *idx,
1454                              int                *nonargs,
1455                              const char         *arg)
1456 {
1457    const Ecore_Getopt_Desc *desc;
1458    Ecore_Getopt_Desc_Arg_Requirement arg_req;
1459    const char *arg_val;
1460    int desc_idx;
1461    Ecore_Getopt_Value *value;
1462    Eina_Bool ret;
1463
1464    desc = _ecore_getopt_parse_find_long(parser, arg);
1465    if (!desc)
1466      {
1467         fprintf(stderr, _("ERROR: unknown option --%s, ignored.\n"), arg);
1468         if (parser->strict)
1469           return EINA_FALSE;
1470
1471         (*idx)++;
1472         return EINA_TRUE;
1473      }
1474
1475    (*idx)++;
1476
1477    arg_req = _ecore_getopt_desc_arg_requirement(desc);
1478    if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
1479      {
1480         arg_val = strchr(arg, '=');
1481         if (arg_val)
1482           arg_val++;
1483         else
1484           {
1485              if ((*idx < *nonargs) && (argv[*idx][0] != '-'))
1486                {
1487                   arg_val = argv[*idx];
1488                   (*idx)++;
1489                }
1490              else
1491                arg_val = NULL;
1492           }
1493
1494         if (arg_val && arg_val[0] == '\0')
1495           arg_val = NULL;
1496
1497         if ((!arg_val) && (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES))
1498           {
1499              fprintf
1500                (stderr, _("ERROR: option --%s requires an argument!\n"), arg);
1501              if (parser->strict)
1502                return EINA_FALSE;
1503              return EINA_TRUE;
1504           }
1505      }
1506    else
1507      arg_val = NULL;
1508
1509    desc_idx = desc - parser->descs;
1510    value = values + desc_idx;
1511    ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val);
1512    if ((!ret) && parser->strict)
1513      return EINA_FALSE;
1514
1515    return EINA_TRUE;
1516 }
1517
1518 static Eina_Bool
1519 _ecore_getopt_parse_arg_short(const Ecore_Getopt *parser,
1520                               Ecore_Getopt_Value *values,
1521                               int                 argc __UNUSED__,
1522                               char              **argv,
1523                               int                *idx,
1524                               int                *nonargs,
1525                               const char         *arg)
1526 {
1527    int run = 1;
1528    while (run && (arg[0] != '\0'))
1529      {
1530         int opt = arg[0];
1531         const Ecore_Getopt_Desc *desc;
1532         Ecore_Getopt_Desc_Arg_Requirement arg_req;
1533         const char *arg_val;
1534         int desc_idx;
1535         Ecore_Getopt_Value *value;
1536         Eina_Bool ret;
1537
1538         desc = _ecore_getopt_parse_find_short(parser, arg[0]);
1539         if (!desc)
1540           {
1541              fprintf
1542                (stderr, _("ERROR: unknown option -%c, ignored.\n"), arg[0]);
1543              if (parser->strict)
1544                return EINA_FALSE;
1545
1546              arg++;
1547              continue;
1548           }
1549
1550         arg++;
1551
1552         arg_req = _ecore_getopt_desc_arg_requirement(desc);
1553         if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
1554           {
1555              (*idx)++;
1556              run = 0;
1557
1558              if (arg[0] == '=')
1559                arg_val = arg + 1;
1560              else if (arg[0] != '\0')
1561                arg_val = arg;
1562              else
1563                {
1564                   if ((*idx < *nonargs) && (argv[*idx][0] != '-'))
1565                     {
1566                        arg_val = argv[*idx];
1567                        (*idx)++;
1568                     }
1569                   else
1570                     arg_val = NULL;
1571                }
1572
1573              if (arg_val && arg_val[0] == '\0')
1574                arg_val = NULL;
1575
1576              if ((!arg_val) &&
1577                  (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES))
1578                {
1579                   fprintf
1580                     (stderr, _("ERROR: option -%c requires an argument!\n"),
1581                     opt);
1582                   if (parser->strict)
1583                     return EINA_FALSE;
1584                   return EINA_TRUE;
1585                }
1586           }
1587         else
1588           arg_val = NULL;
1589
1590         desc_idx = desc - parser->descs;
1591         value = values + desc_idx;
1592         ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val);
1593         if ((!ret) && parser->strict)
1594           return EINA_FALSE;
1595      }
1596
1597    if (run)
1598      (*idx)++;
1599
1600    return EINA_TRUE;
1601 }
1602
1603 static Eina_Bool
1604 _ecore_getopt_parse_arg(const Ecore_Getopt *parser,
1605                         Ecore_Getopt_Value *values,
1606                         int                 argc,
1607                         char              **argv,
1608                         int                *idx,
1609                         int                *nonargs)
1610 {
1611    char *arg = argv[*idx];
1612
1613    if (arg[0] != '-')
1614      {
1615         char **dst, **src, **src_end;
1616
1617         dst = argv + *idx;
1618         src = dst + 1;
1619         src_end = src + *nonargs - *idx - 1;
1620
1621         for (; src < src_end; src++, dst++)
1622           *dst = *src;
1623
1624         *dst = arg;
1625         (*nonargs)--;
1626         return EINA_TRUE;
1627      }
1628
1629    if (arg[1] == '-')
1630      return _ecore_getopt_parse_arg_long(parser, values, argc, argv, idx, nonargs, arg + 2);
1631    else
1632      return _ecore_getopt_parse_arg_short(parser, values, argc, argv, idx, nonargs, arg + 1);
1633 }
1634
1635 static const Ecore_Getopt_Desc *
1636 _ecore_getopt_parse_find_short_other(const Ecore_Getopt      *parser,
1637                                      const Ecore_Getopt_Desc *orig)
1638 {
1639    const Ecore_Getopt_Desc *desc = parser->descs;
1640    const char c = orig->shortname;
1641
1642    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
1643      {
1644         if (desc == orig)
1645           return NULL;
1646
1647         if (c == desc->shortname)
1648           return desc;
1649      }
1650
1651    return NULL;
1652 }
1653
1654 static const Ecore_Getopt_Desc *
1655 _ecore_getopt_parse_find_long_other(const Ecore_Getopt      *parser,
1656                                     const Ecore_Getopt_Desc *orig)
1657 {
1658    const Ecore_Getopt_Desc *desc = parser->descs;
1659    const char *name = orig->longname;
1660
1661    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
1662      {
1663         if (desc == orig)
1664           return NULL;
1665
1666         if (desc->longname && (strcmp(name, desc->longname) == 0))
1667           return desc;
1668      }
1669
1670    return NULL;
1671 }
1672
1673 /**
1674  * Check parser for duplicate entries, print them out.
1675  *
1676  * @return EINA_TRUE if there are duplicates, EINA_FALSE otherwise.
1677  */
1678 Eina_Bool
1679 ecore_getopt_parser_has_duplicates(const Ecore_Getopt *parser)
1680 {
1681    const Ecore_Getopt_Desc *desc = parser->descs;
1682    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
1683      {
1684         if (desc->shortname)
1685           {
1686              const Ecore_Getopt_Desc *other;
1687              other = _ecore_getopt_parse_find_short_other(parser, desc);
1688              if (other)
1689                {
1690                   _ecore_getopt_desc_print_error(desc, "short name -%c already exists.", desc->shortname);
1691
1692                   if (other->longname)
1693                     fprintf(stderr, " Other is --%s.\n", other->longname);
1694                   else
1695                     fputc('\n', stderr);
1696                   return EINA_TRUE;
1697                }
1698           }
1699
1700         if (desc->longname)
1701           {
1702              const Ecore_Getopt_Desc *other;
1703              other = _ecore_getopt_parse_find_long_other(parser, desc);
1704              if (other)
1705                {
1706                   _ecore_getopt_desc_print_error(desc, "long name --%s already exists.", desc->longname);
1707
1708                   if (other->shortname)
1709                     fprintf(stderr, " Other is -%c.\n", other->shortname);
1710                   else
1711                     fputc('\n', stderr);
1712                   return EINA_TRUE;
1713                }
1714           }
1715      }
1716    return EINA_FALSE;
1717 }
1718
1719 static const Ecore_Getopt_Desc *
1720 _ecore_getopt_find_help(const Ecore_Getopt *parser)
1721 {
1722    const Ecore_Getopt_Desc *desc = parser->descs;
1723    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
1724      if (desc->action == ECORE_GETOPT_ACTION_HELP)
1725        return desc;
1726    return NULL;
1727 }
1728
1729 /**
1730  * Parse command line parameters.
1731  *
1732  * Walks the command line parameters and parse them based on @a parser
1733  * description, doing actions based on @c parser->descs->action, like
1734  * showing help text, license, copyright, storing values in values and
1735  * so on.
1736  *
1737  * It is expected that values is of the same size than @c parser->descs,
1738  * options that do not need a value it will be left untouched.
1739  *
1740  * All values are expected to be initialized before use. Options with
1741  * action @c ECORE_GETOPT_ACTION_STORE and non required arguments
1742  * (others than @c ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES), are expected
1743  * to provide a value in @c def to be used.
1744  *
1745  * The following actions will store 1 on value as a boolean
1746  * (@c value->boolp) if it's not NULL to indicate these actions were executed:
1747  *   - @c ECORE_GETOPT_ACTION_HELP
1748  *   - @c ECORE_GETOPT_ACTION_VERSION
1749  *   - @c ECORE_GETOPT_ACTION_COPYRIGHT
1750  *   - @c ECORE_GETOPT_ACTION_LICENSE
1751  *
1752  * Just @c ECORE_GETOPT_ACTION_APPEND will allocate memory and thus
1753  * need to be freed. For consistency between all of appended subtypes,
1754  * @c eina_list->data will contain an allocated memory with the value,
1755  * that is, for @c ECORE_GETOPT_TYPE_STR it will contain a copy of the
1756  * argument, @c ECORE_GETOPT_TYPE_INT a pointer to an allocated
1757  * integer and so on.
1758  *
1759  * If parser is in strict mode (see @c Ecore_Getopt->strict), then any
1760  * error will abort parsing and -1 is returned. Otherwise it will try
1761  * to continue as far as possible.
1762  *
1763  * This function may reorder @a argv elements.
1764  *
1765  * Translation of help strings (description), metavar, usage, license
1766  * and copyright may be translated, standard/global gettext() call
1767  * will be applied on them if ecore was compiled with such support.
1768  *
1769  * @param parser description of how to work.
1770  * @param values where to store values, it is assumed that this is a vector
1771  *        of the same size as @c parser->descs. Values should be previously
1772  *        initialized.
1773  * @param argc how many elements in @a argv. If not provided it will be
1774  *        retrieved with ecore_app_args_get().
1775  * @param argv command line parameters.
1776  *
1777  * @return index of first non-option parameter or -1 on error.
1778  */
1779 int
1780 ecore_getopt_parse(const Ecore_Getopt *parser,
1781                    Ecore_Getopt_Value *values,
1782                    int                 argc,
1783                    char              **argv)
1784 {
1785    int i, nonargs;
1786
1787    if (!parser)
1788      {
1789         fputs(_("ERROR: no parser provided.\n"), stderr);
1790         return -1;
1791      }
1792    if (!values)
1793      {
1794         fputs(_("ERROR: no values provided.\n"), stderr);
1795         return -1;
1796      }
1797
1798    if ((argc < 1) || (!argv))
1799      ecore_app_args_get(&argc, &argv);
1800
1801    if (argc < 1)
1802      {
1803         fputs(_("ERROR: no arguments provided.\n"), stderr);
1804         return -1;
1805      }
1806
1807    if (argv[0])
1808      prog = argv[0];
1809    else
1810      prog = parser->prog;
1811
1812    nonargs = _ecore_getopt_parse_find_nonargs_base(parser, argc, argv);
1813    if (nonargs < 0)
1814      goto error;
1815
1816    if (nonargs > argc)
1817      nonargs = argc;
1818
1819    i = 1;
1820    while (i < nonargs)
1821      if (!_ecore_getopt_parse_arg(parser, values, argc, argv, &i, &nonargs))
1822        goto error;
1823
1824    return nonargs;
1825
1826 error:
1827    {
1828       const Ecore_Getopt_Desc *help;
1829       fputs(_("ERROR: invalid options found."), stderr);
1830
1831       help = _ecore_getopt_find_help(parser);
1832       if (!help)
1833         fputc('\n', stderr);
1834       else if (help->longname)
1835         fprintf(stderr, _(" See --%s.\n"), help->longname);
1836       else
1837         fprintf(stderr, _(" See -%c.\n"), help->shortname);
1838    }
1839
1840    return -1;
1841 }
1842
1843 /**
1844  * Utility to free list and nodes allocated by @a ECORE_GETOPT_ACTION_APPEND.
1845  *
1846  * @param list pointer to list to be freed.
1847  * @return always NULL, so you can easily make your list head NULL.
1848  */
1849 Eina_List *
1850 ecore_getopt_list_free(Eina_List *list)
1851 {
1852    void *data;
1853
1854    EINA_LIST_FREE(list, data)
1855      free(data);
1856    return NULL;
1857 }
1858
1859 /**
1860  * Helper ecore_getopt callback to parse geometry (x:y:w:h).
1861  *
1862  * @param str Geometry value
1863  * @param storage must be a pointer to @c Eina_Rectangle and will be used to
1864  * store the four values passed in the given string.
1865  *
1866  * @c callback_data value is ignored, you can safely use @c NULL.
1867  */
1868 Eina_Bool
1869 ecore_getopt_callback_geometry_parse(const Ecore_Getopt      *parser __UNUSED__,
1870                                      const Ecore_Getopt_Desc *desc __UNUSED__,
1871                                      const char              *str,
1872                                      void                    *data __UNUSED__,
1873                                      Ecore_Getopt_Value      *storage)
1874 {
1875    Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp;
1876
1877    if (sscanf(str, "%d:%d:%d:%d", &v->x, &v->y, &v->w, &v->h) != 4)
1878      {
1879         fprintf(stderr, _("ERROR: incorrect geometry value '%s'\n"), str);
1880         return EINA_FALSE;
1881      }
1882
1883    return EINA_TRUE;
1884 }
1885
1886 /**
1887  * Helper ecore_getopt callback to parse geometry size (WxH).
1888  *
1889  * @param str size value
1890  * @param storage must be a pointer to @c Eina_Rectangle and will be used to
1891  * store the two values passed in the given string and 0 in the x and y
1892  * fields.
1893  *
1894  * @c callback_data value is ignored, you can safely use @c NULL.
1895  */
1896 Eina_Bool
1897 ecore_getopt_callback_size_parse(const Ecore_Getopt      *parser __UNUSED__,
1898                                  const Ecore_Getopt_Desc *desc __UNUSED__,
1899                                  const char              *str,
1900                                  void                    *data __UNUSED__,
1901                                  Ecore_Getopt_Value      *storage)
1902 {
1903    Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp;
1904
1905    if (sscanf(str, "%dx%d", &v->w, &v->h) != 2)
1906      {
1907         fprintf(stderr, _("ERROR: incorrect size value '%s'\n"), str);
1908         return EINA_FALSE;
1909      }
1910    v->x = 0;
1911    v->y = 0;
1912
1913    return EINA_TRUE;
1914 }
1915