Tizen 2.1 base
[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  * @param fp The file the message will be printed on.
673  * @param parser The parser to be used.
674  */
675 EAPI void
676 ecore_getopt_help(FILE               *fp,
677                   const Ecore_Getopt *parser)
678 {
679    const char *var;
680
681    EINA_MAIN_LOOP_CHECK_RETURN;
682    if (!parser) return;
683
684    if (_argc < 1)
685      {
686         ecore_app_args_get(&_argc, &_argv);
687         if ((_argc > 0) && (_argv[0]))
688           prog = _argv[0];
689         else
690           prog = parser->prog;
691      }
692
693    var = getenv("COLUMNS");
694    if (var)
695      {
696         cols = atoi(var);
697         if (cols < 20)
698           cols = 20;
699
700         helpcol = cols / 3;
701      }
702
703    _ecore_getopt_help_usage(fp, parser);
704    _ecore_getopt_help_description(fp, parser);
705    _ecore_getopt_help_options(fp, parser);
706 }
707
708 static const Ecore_Getopt_Desc *
709 _ecore_getopt_parse_find_long(const Ecore_Getopt *parser,
710                               const char         *name)
711 {
712    const Ecore_Getopt_Desc *desc = parser->descs;
713    const char *p = strchr(name, '=');
714    int len = 0;
715
716    if (p)
717      len = p - name;
718
719    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
720      {
721         if (!desc->longname)
722           continue;
723
724         if (p)
725           {
726              if ((strncmp(name, desc->longname, len) == 0) &&
727                  (desc->longname[len] == '\0'))
728                return desc;
729           }
730         else
731           {
732              if (strcmp(name, desc->longname) == 0)
733                return desc;
734           }
735      }
736
737    return NULL;
738 }
739
740 static const Ecore_Getopt_Desc *
741 _ecore_getopt_parse_find_short(const Ecore_Getopt *parser,
742                                char                name)
743 {
744    const Ecore_Getopt_Desc *desc = parser->descs;
745    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
746      if (name == desc->shortname)
747        return desc;
748    return NULL;
749 }
750
751 static int
752 _ecore_getopt_parse_find_nonargs_base(const Ecore_Getopt *parser,
753                                       int                 argc,
754                                       char              **argv)
755 {
756    char **nonargs;
757    int src, dst, used, base;
758
759    nonargs = alloca(sizeof(char *) * argc);
760    src = 1;
761    dst = 1;
762    used = 0;
763    base = 0;
764    while (src < argc)
765      {
766         const Ecore_Getopt_Desc *desc;
767         Ecore_Getopt_Desc_Arg_Requirement arg_req;
768         char *arg = argv[src];
769
770         if (arg[0] != '-')
771           goto found_nonarg;
772
773         if (arg[1] == '-')
774           {
775              if (arg[2] == '\0') /* explicit end of options, "--" */
776                {
777                   base = 1;
778                   break;
779                }
780              desc = _ecore_getopt_parse_find_long(parser, arg + 2);
781           }
782         else
783           desc = _ecore_getopt_parse_find_short(parser, arg[1]);
784
785         if (!desc)
786           {
787              if (arg[1] == '-')
788                fprintf(stderr, _("ERROR: unknown option --%s.\n"), arg + 2);
789              else
790                fprintf(stderr, _("ERROR: unknown option -%c.\n"), arg[1]);
791              if (parser->strict)
792                {
793                   memmove(argv + dst, nonargs, used * sizeof(char *));
794                   return -1;
795                }
796              else
797                goto found_nonarg;
798           }
799
800         if (src != dst)
801           argv[dst] = argv[src];
802         src++;
803         dst++;
804
805         arg_req = _ecore_getopt_desc_arg_requirement(desc);
806         if (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
807           continue;
808
809         if (strchr(arg, '='))
810           continue;
811
812         if ((src >= argc) || (argv[src][0] == '-'))
813           continue;
814
815         if (src != dst)
816           argv[dst] = argv[src];
817         src++;
818         dst++;
819         continue;
820
821 found_nonarg:
822         nonargs[used] = arg;
823         used++;
824         src++;
825      }
826
827    if (!base) /* '--' not found */
828      base = dst;
829    else
830      {
831         base = dst;
832         if (src != dst)
833           argv[dst] = argv[src];
834         dst++;
835      }
836
837    memmove(argv + dst, nonargs, used * sizeof(char *));
838    return base;
839 }
840
841 static void
842 _ecore_getopt_desc_print_error(const Ecore_Getopt_Desc *desc,
843                                const char              *fmt,
844                                ...)
845 {
846    va_list ap;
847
848    fputs(_("ERROR: "), stderr);
849
850    if (desc->shortname)
851      {
852         fputc('-', stderr);
853         fputc(desc->shortname, stderr);
854      }
855
856    if (desc->shortname && desc->longname)
857      fputs(", ", stderr);
858
859    if (desc->longname)
860      {
861         fputs("--", stderr);
862         fputs(desc->longname, stderr);
863      }
864
865    fputs(": ", stderr);
866
867    va_start(ap, fmt);
868    vfprintf(stderr, fmt, ap);
869    va_end(ap);
870 }
871
872 static Eina_Bool
873 _ecore_getopt_parse_bool(const char *str,
874                          Eina_Bool  *v)
875 {
876    if ((strcmp(str, "0") == 0) ||
877        (strcasecmp(str, "f") == 0) ||
878        (strcasecmp(str, "false") == 0) ||
879        (strcasecmp(str, "no") == 0) ||
880        (strcasecmp(str, "off") == 0)
881        )
882      {
883         *v = EINA_FALSE;
884         return EINA_TRUE;
885      }
886    else if ((strcmp(str, "1") == 0) ||
887             (strcasecmp(str, "t") == 0) ||
888             (strcasecmp(str, "true") == 0) ||
889             (strcasecmp(str, "yes") == 0) ||
890             (strcasecmp(str, "on") == 0)
891             )
892      {
893         *v = EINA_TRUE;
894         return EINA_TRUE;
895      }
896
897    return EINA_FALSE;
898 }
899
900 static Eina_Bool
901 _ecore_getopt_parse_long(const char *str,
902                          long int   *v)
903 {
904    char *endptr = NULL;
905    *v = strtol(str, &endptr, 0);
906    return endptr > str;
907 }
908
909 static Eina_Bool
910 _ecore_getopt_parse_double(const char *str,
911                            double     *v)
912 {
913    char *endptr = NULL;
914    *v = strtod(str, &endptr);
915    return endptr > str;
916 }
917
918 static Eina_Bool
919 _ecore_getopt_parse_store(const Ecore_Getopt      *parser __UNUSED__,
920                           const Ecore_Getopt_Desc *desc,
921                           Ecore_Getopt_Value      *value,
922                           const char              *arg_val)
923 {
924    const Ecore_Getopt_Desc_Store *store = &desc->action_param.store;
925    long int v;
926    double d;
927    Eina_Bool b;
928
929    if (!value->ptrp)
930      {
931         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
932         return EINA_FALSE;
933      }
934
935    switch (store->arg_req)
936      {
937       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO:
938         goto use_optional;
939
940       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL:
941         if (!arg_val)
942           goto use_optional;
943
944       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES:
945         break;
946      }
947
948    switch (store->type)
949      {
950       case ECORE_GETOPT_TYPE_STR:
951         *value->strp = (char *)arg_val;
952         return EINA_TRUE;
953
954       case ECORE_GETOPT_TYPE_BOOL:
955         if (_ecore_getopt_parse_bool(arg_val, &b))
956           {
957              *value->boolp = b;
958              return EINA_TRUE;
959           }
960         else
961           {
962              _ecore_getopt_desc_print_error
963                (desc, _("unknown boolean value %s.\n"), arg_val);
964              return EINA_FALSE;
965           }
966
967       case ECORE_GETOPT_TYPE_SHORT:
968         if (!_ecore_getopt_parse_long(arg_val, &v))
969           goto error;
970         *value->shortp = v;
971         return EINA_TRUE;
972
973       case ECORE_GETOPT_TYPE_INT:
974         if (!_ecore_getopt_parse_long(arg_val, &v))
975           goto error;
976         *value->intp = v;
977         return EINA_TRUE;
978
979       case ECORE_GETOPT_TYPE_LONG:
980         if (!_ecore_getopt_parse_long(arg_val, &v))
981           goto error;
982         *value->longp = v;
983         return EINA_TRUE;
984
985       case ECORE_GETOPT_TYPE_USHORT:
986         if (!_ecore_getopt_parse_long(arg_val, &v))
987           goto error;
988         *value->ushortp = v;
989         return EINA_TRUE;
990
991       case ECORE_GETOPT_TYPE_UINT:
992         if (!_ecore_getopt_parse_long(arg_val, &v))
993           goto error;
994         *value->uintp = v;
995         return EINA_TRUE;
996
997       case ECORE_GETOPT_TYPE_ULONG:
998         if (!_ecore_getopt_parse_long(arg_val, &v))
999           goto error;
1000         *value->ulongp = v;
1001         return EINA_TRUE;
1002
1003       case ECORE_GETOPT_TYPE_DOUBLE:
1004         if (!_ecore_getopt_parse_double(arg_val, &d))
1005           goto error;
1006         *value->doublep = d;
1007         break;
1008      }
1009
1010    return EINA_TRUE;
1011
1012 error:
1013    _ecore_getopt_desc_print_error
1014      (desc, _("invalid number format %s\n"), arg_val);
1015    return EINA_FALSE;
1016
1017 use_optional:
1018    switch (store->type)
1019      {
1020       case ECORE_GETOPT_TYPE_STR:
1021         *value->strp = (char *)store->def.strv;
1022         break;
1023
1024       case ECORE_GETOPT_TYPE_BOOL:
1025         *value->boolp = store->def.boolv;
1026         break;
1027
1028       case ECORE_GETOPT_TYPE_SHORT:
1029         *value->shortp = store->def.shortv;
1030         break;
1031
1032       case ECORE_GETOPT_TYPE_INT:
1033         *value->intp = store->def.intv;
1034         break;
1035
1036       case ECORE_GETOPT_TYPE_LONG:
1037         *value->longp = store->def.longv;
1038         break;
1039
1040       case ECORE_GETOPT_TYPE_USHORT:
1041         *value->ushortp = store->def.ushortv;
1042         break;
1043
1044       case ECORE_GETOPT_TYPE_UINT:
1045         *value->uintp = store->def.uintv;
1046         break;
1047
1048       case ECORE_GETOPT_TYPE_ULONG:
1049         *value->ulongp = store->def.ulongv;
1050         break;
1051
1052       case ECORE_GETOPT_TYPE_DOUBLE:
1053         *value->doublep = store->def.doublev;
1054         break;
1055      }
1056
1057    return EINA_TRUE;
1058 }
1059
1060 static Eina_Bool
1061 _ecore_getopt_parse_store_const(const Ecore_Getopt      *parser __UNUSED__,
1062                                 const Ecore_Getopt_Desc *desc,
1063                                 Ecore_Getopt_Value      *val,
1064                                 const char              *arg_val __UNUSED__)
1065 {
1066    if (!val->ptrp)
1067      {
1068         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1069         return EINA_FALSE;
1070      }
1071
1072    *val->ptrp = (void *)desc->action_param.store_const;
1073    return EINA_TRUE;
1074 }
1075
1076 static Eina_Bool
1077 _ecore_getopt_parse_store_true(const Ecore_Getopt      *parser __UNUSED__,
1078                                const Ecore_Getopt_Desc *desc,
1079                                Ecore_Getopt_Value      *val,
1080                                const char              *arg_val __UNUSED__)
1081 {
1082    if (!val->boolp)
1083      {
1084         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1085         return EINA_FALSE;
1086      }
1087    *val->boolp = EINA_TRUE;
1088    return EINA_TRUE;
1089 }
1090
1091 static Eina_Bool
1092 _ecore_getopt_parse_store_false(const Ecore_Getopt      *parser __UNUSED__,
1093                                 const Ecore_Getopt_Desc *desc,
1094                                 Ecore_Getopt_Value      *val,
1095                                 const char              *arg_val __UNUSED__)
1096 {
1097    if (!val->boolp)
1098      {
1099         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1100         return EINA_FALSE;
1101      }
1102    *val->boolp = EINA_FALSE;
1103    return EINA_TRUE;
1104 }
1105
1106 static Eina_Bool
1107 _ecore_getopt_parse_choice(const Ecore_Getopt      *parser __UNUSED__,
1108                            const Ecore_Getopt_Desc *desc,
1109                            Ecore_Getopt_Value      *val,
1110                            const char              *arg_val)
1111 {
1112    const char *const *pchoice;
1113
1114    if (!val->strp)
1115      {
1116         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1117         return EINA_FALSE;
1118      }
1119
1120    pchoice = desc->action_param.choices;
1121    for (; *pchoice; pchoice++)
1122      if (strcmp(*pchoice, arg_val) == 0)
1123        {
1124           *val->strp = (char *)*pchoice;
1125           return EINA_TRUE;
1126        }
1127
1128    _ecore_getopt_desc_print_error
1129      (desc, _("invalid choice \"%s\". Valid values are: "), arg_val);
1130
1131    pchoice = desc->action_param.choices;
1132    for (; *pchoice; pchoice++)
1133      {
1134         fputs(*pchoice, stderr);
1135         if (pchoice[1])
1136           fputs(", ", stderr);
1137      }
1138
1139    fputs(".\n", stderr);
1140    return EINA_FALSE;
1141 }
1142
1143 static Eina_Bool
1144 _ecore_getopt_parse_append(const Ecore_Getopt      *parser __UNUSED__,
1145                            const Ecore_Getopt_Desc *desc,
1146                            Ecore_Getopt_Value      *val,
1147                            const char              *arg_val)
1148 {
1149    void *data;
1150    long int v;
1151    double d;
1152    Eina_Bool b;
1153
1154    if (!arg_val)
1155      {
1156         _ecore_getopt_desc_print_error
1157           (desc, _("missing parameter to append.\n"));
1158         return EINA_FALSE;
1159      }
1160
1161    if (!val->listp)
1162      {
1163         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1164         return EINA_FALSE;
1165      }
1166
1167    switch (desc->action_param.append_type)
1168      {
1169       case ECORE_GETOPT_TYPE_STR:
1170         data = strdup(arg_val);
1171         break;
1172
1173       case ECORE_GETOPT_TYPE_BOOL:
1174       {
1175          if (_ecore_getopt_parse_bool(arg_val, &b))
1176            {
1177               data = malloc(sizeof(Eina_Bool));
1178               if (data)
1179                 *(Eina_Bool *)data = b;
1180            }
1181          else
1182            {
1183               _ecore_getopt_desc_print_error(desc, _("unknown boolean value %s.\n"), arg_val);
1184               return EINA_FALSE;
1185            }
1186       }
1187       break;
1188
1189       case ECORE_GETOPT_TYPE_SHORT:
1190       {
1191          if (!_ecore_getopt_parse_long(arg_val, &v))
1192            goto error;
1193          data = malloc(sizeof(short));
1194          if (data)
1195            *(short *)data = (short)v;
1196       }
1197       break;
1198
1199       case ECORE_GETOPT_TYPE_INT:
1200       {
1201          if (!_ecore_getopt_parse_long(arg_val, &v))
1202            goto error;
1203          data = malloc(sizeof(int));
1204          if (data)
1205            *(int *)data = (int)v;
1206       }
1207       break;
1208
1209       case ECORE_GETOPT_TYPE_LONG:
1210       {
1211          if (!_ecore_getopt_parse_long(arg_val, &v))
1212            goto error;
1213          data = malloc(sizeof(long));
1214          if (data)
1215            *(long *)data = v;
1216       }
1217       break;
1218
1219       case ECORE_GETOPT_TYPE_USHORT:
1220       {
1221          if (!_ecore_getopt_parse_long(arg_val, &v))
1222            goto error;
1223          data = malloc(sizeof(unsigned short));
1224          if (data)
1225            *(unsigned short *)data = (unsigned short)v;
1226       }
1227       break;
1228
1229       case ECORE_GETOPT_TYPE_UINT:
1230       {
1231          if (!_ecore_getopt_parse_long(arg_val, &v))
1232            goto error;
1233          data = malloc(sizeof(unsigned int));
1234          if (data)
1235            *(unsigned int *)data = (unsigned int)v;
1236       }
1237       break;
1238
1239       case ECORE_GETOPT_TYPE_ULONG:
1240       {
1241          if (!_ecore_getopt_parse_long(arg_val, &v))
1242            goto error;
1243          data = malloc(sizeof(unsigned long));
1244          if (data)
1245            *(unsigned long *)data = v;
1246       }
1247       break;
1248
1249       case ECORE_GETOPT_TYPE_DOUBLE:
1250       {
1251          if (!_ecore_getopt_parse_double(arg_val, &d))
1252            goto error;
1253          data = malloc(sizeof(double));
1254          if (data)
1255            *(double *)data = d;
1256       }
1257       break;
1258
1259       default:
1260       {
1261          _ecore_getopt_desc_print_error(desc, _("could not parse value.\n"));
1262          return EINA_FALSE;
1263       }
1264      }
1265
1266    *val->listp = eina_list_append(*val->listp, data);
1267    return EINA_TRUE;
1268
1269 error:
1270    _ecore_getopt_desc_print_error
1271      (desc, _("invalid number format %s\n"), arg_val);
1272    return EINA_FALSE;
1273 }
1274
1275 static Eina_Bool
1276 _ecore_getopt_parse_count(const Ecore_Getopt      *parser __UNUSED__,
1277                           const Ecore_Getopt_Desc *desc,
1278                           Ecore_Getopt_Value      *val,
1279                           const char              *arg_val __UNUSED__)
1280 {
1281    if (!val->intp)
1282      {
1283         _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1284         return EINA_FALSE;
1285      }
1286
1287    (*val->intp)++;
1288    return EINA_TRUE;
1289 }
1290
1291 static Eina_Bool
1292 _ecore_getopt_parse_callback(const Ecore_Getopt      *parser,
1293                              const Ecore_Getopt_Desc *desc,
1294                              Ecore_Getopt_Value      *val,
1295                              const char              *arg_val)
1296 {
1297    const Ecore_Getopt_Desc_Callback *cb = &desc->action_param.callback;
1298
1299    switch (cb->arg_req)
1300      {
1301       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO:
1302         arg_val = cb->def;
1303         break;
1304
1305       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL:
1306         if (!arg_val)
1307           arg_val = cb->def;
1308         break;
1309
1310       case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES:
1311         break;
1312      }
1313
1314    if (cb->arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
1315      {
1316         if ((!arg_val) || (arg_val[0] == '\0'))
1317           {
1318              _ecore_getopt_desc_print_error(desc, _("missing parameter.\n"));
1319              return EINA_FALSE;
1320           }
1321
1322         if (!val->ptrp)
1323           {
1324              _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
1325              return EINA_FALSE;
1326           }
1327      }
1328
1329    if (!cb->func)
1330      {
1331         _ecore_getopt_desc_print_error(desc, _("missing callback function!\n"));
1332         return EINA_FALSE;
1333      }
1334
1335    return cb->func(parser, desc, arg_val, (void *)cb->data, val);
1336 }
1337
1338 static Eina_Bool
1339 _ecore_getopt_parse_help(const Ecore_Getopt      *parser,
1340                          const Ecore_Getopt_Desc *desc __UNUSED__,
1341                          Ecore_Getopt_Value      *val,
1342                          const char              *arg_val __UNUSED__)
1343 {
1344    if (val->boolp)
1345      (*val->boolp) = EINA_TRUE;
1346    ecore_getopt_help(stdout, parser);
1347    return EINA_TRUE;
1348 }
1349
1350 static Eina_Bool
1351 _ecore_getopt_parse_version(const Ecore_Getopt      *parser,
1352                             const Ecore_Getopt_Desc *desc,
1353                             Ecore_Getopt_Value      *val,
1354                             const char              *arg_val __UNUSED__)
1355 {
1356    if (val->boolp)
1357      (*val->boolp) = EINA_TRUE;
1358    if (!parser->version)
1359      {
1360         _ecore_getopt_desc_print_error(desc, _("no version was defined.\n"));
1361         return EINA_FALSE;
1362      }
1363    _ecore_getopt_version(stdout, parser);
1364    return EINA_TRUE;
1365 }
1366
1367 static Eina_Bool
1368 _ecore_getopt_parse_copyright(const Ecore_Getopt      *parser,
1369                               const Ecore_Getopt_Desc *desc,
1370                               Ecore_Getopt_Value      *val,
1371                               const char              *arg_val __UNUSED__)
1372 {
1373    if (val->boolp)
1374      (*val->boolp) = EINA_TRUE;
1375    if (!parser->copyright)
1376      {
1377         _ecore_getopt_desc_print_error(desc, _("no copyright was defined.\n"));
1378         return EINA_FALSE;
1379      }
1380    _ecore_getopt_copyright(stdout, parser);
1381    return EINA_TRUE;
1382 }
1383
1384 static Eina_Bool
1385 _ecore_getopt_parse_license(const Ecore_Getopt      *parser,
1386                             const Ecore_Getopt_Desc *desc,
1387                             Ecore_Getopt_Value      *val,
1388                             const char              *arg_val __UNUSED__)
1389 {
1390    if (val->boolp)
1391      (*val->boolp) = EINA_TRUE;
1392    if (!parser->license)
1393      {
1394         _ecore_getopt_desc_print_error(desc, _("no license was defined.\n"));
1395         return EINA_FALSE;
1396      }
1397    _ecore_getopt_license(stdout, parser);
1398    return EINA_TRUE;
1399 }
1400
1401 static Eina_Bool
1402 _ecore_getopt_desc_handle(const Ecore_Getopt      *parser,
1403                           const Ecore_Getopt_Desc *desc,
1404                           Ecore_Getopt_Value      *value,
1405                           const char              *arg_val)
1406 {
1407    switch (desc->action)
1408      {
1409       case ECORE_GETOPT_ACTION_STORE:
1410         return _ecore_getopt_parse_store(parser, desc, value, arg_val);
1411
1412       case ECORE_GETOPT_ACTION_STORE_CONST:
1413         return _ecore_getopt_parse_store_const(parser, desc, value, arg_val);
1414
1415       case ECORE_GETOPT_ACTION_STORE_TRUE:
1416         return _ecore_getopt_parse_store_true(parser, desc, value, arg_val);
1417
1418       case ECORE_GETOPT_ACTION_STORE_FALSE:
1419         return _ecore_getopt_parse_store_false(parser, desc, value, arg_val);
1420
1421       case ECORE_GETOPT_ACTION_CHOICE:
1422         return _ecore_getopt_parse_choice(parser, desc, value, arg_val);
1423
1424       case ECORE_GETOPT_ACTION_APPEND:
1425         return _ecore_getopt_parse_append(parser, desc, value, arg_val);
1426
1427       case ECORE_GETOPT_ACTION_COUNT:
1428         return _ecore_getopt_parse_count(parser, desc, value, arg_val);
1429
1430       case ECORE_GETOPT_ACTION_CALLBACK:
1431         return _ecore_getopt_parse_callback(parser, desc, value, arg_val);
1432
1433       case ECORE_GETOPT_ACTION_HELP:
1434         return _ecore_getopt_parse_help(parser, desc, value, arg_val);
1435
1436       case ECORE_GETOPT_ACTION_VERSION:
1437         return _ecore_getopt_parse_version(parser, desc, value, arg_val);
1438
1439       case ECORE_GETOPT_ACTION_COPYRIGHT:
1440         return _ecore_getopt_parse_copyright(parser, desc, value, arg_val);
1441
1442       case ECORE_GETOPT_ACTION_LICENSE:
1443         return _ecore_getopt_parse_license(parser, desc, value, arg_val);
1444
1445       default:
1446         return EINA_FALSE;
1447      }
1448 }
1449
1450 static Eina_Bool
1451 _ecore_getopt_parse_arg_long(const Ecore_Getopt *parser,
1452                              Ecore_Getopt_Value *values,
1453                              int                 argc __UNUSED__,
1454                              char              **argv,
1455                              int                *idx,
1456                              int                *nonargs,
1457                              const char         *arg)
1458 {
1459    const Ecore_Getopt_Desc *desc;
1460    Ecore_Getopt_Desc_Arg_Requirement arg_req;
1461    const char *arg_val;
1462    int desc_idx;
1463    Ecore_Getopt_Value *value;
1464    Eina_Bool ret;
1465
1466    desc = _ecore_getopt_parse_find_long(parser, arg);
1467    if (!desc)
1468      {
1469         fprintf(stderr, _("ERROR: unknown option --%s, ignored.\n"), arg);
1470         if (parser->strict)
1471           return EINA_FALSE;
1472
1473         (*idx)++;
1474         return EINA_TRUE;
1475      }
1476
1477    (*idx)++;
1478
1479    arg_req = _ecore_getopt_desc_arg_requirement(desc);
1480    if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
1481      {
1482         arg_val = strchr(arg, '=');
1483         if (arg_val)
1484           arg_val++;
1485         else
1486           {
1487              if ((*idx < *nonargs) && (argv[*idx][0] != '-'))
1488                {
1489                   arg_val = argv[*idx];
1490                   (*idx)++;
1491                }
1492              else
1493                arg_val = NULL;
1494           }
1495
1496         if (arg_val && arg_val[0] == '\0')
1497           arg_val = NULL;
1498
1499         if ((!arg_val) && (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES))
1500           {
1501              fprintf
1502                (stderr, _("ERROR: option --%s requires an argument!\n"), arg);
1503              if (parser->strict)
1504                return EINA_FALSE;
1505              return EINA_TRUE;
1506           }
1507      }
1508    else
1509      arg_val = NULL;
1510
1511    desc_idx = desc - parser->descs;
1512    value = values + desc_idx;
1513    ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val);
1514    if ((!ret) && parser->strict)
1515      return EINA_FALSE;
1516
1517    return EINA_TRUE;
1518 }
1519
1520 static Eina_Bool
1521 _ecore_getopt_parse_arg_short(const Ecore_Getopt *parser,
1522                               Ecore_Getopt_Value *values,
1523                               int                 argc __UNUSED__,
1524                               char              **argv,
1525                               int                *idx,
1526                               int                *nonargs,
1527                               const char         *arg)
1528 {
1529    int run = 1;
1530    while (run && (arg[0] != '\0'))
1531      {
1532         int opt = arg[0];
1533         const Ecore_Getopt_Desc *desc;
1534         Ecore_Getopt_Desc_Arg_Requirement arg_req;
1535         const char *arg_val;
1536         int desc_idx;
1537         Ecore_Getopt_Value *value;
1538         Eina_Bool ret;
1539
1540         desc = _ecore_getopt_parse_find_short(parser, arg[0]);
1541         if (!desc)
1542           {
1543              fprintf
1544                (stderr, _("ERROR: unknown option -%c, ignored.\n"), arg[0]);
1545              if (parser->strict)
1546                return EINA_FALSE;
1547
1548              arg++;
1549              continue;
1550           }
1551
1552         arg++;
1553
1554         arg_req = _ecore_getopt_desc_arg_requirement(desc);
1555         if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
1556           {
1557              (*idx)++;
1558              run = 0;
1559
1560              if (arg[0] == '=')
1561                arg_val = arg + 1;
1562              else if (arg[0] != '\0')
1563                arg_val = arg;
1564              else
1565                {
1566                   if ((*idx < *nonargs) && (argv[*idx][0] != '-'))
1567                     {
1568                        arg_val = argv[*idx];
1569                        (*idx)++;
1570                     }
1571                   else
1572                     arg_val = NULL;
1573                }
1574
1575              if (arg_val && arg_val[0] == '\0')
1576                arg_val = NULL;
1577
1578              if ((!arg_val) &&
1579                  (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES))
1580                {
1581                   fprintf
1582                     (stderr, _("ERROR: option -%c requires an argument!\n"),
1583                     opt);
1584                   if (parser->strict)
1585                     return EINA_FALSE;
1586                   return EINA_TRUE;
1587                }
1588           }
1589         else
1590           arg_val = NULL;
1591
1592         desc_idx = desc - parser->descs;
1593         value = values + desc_idx;
1594         ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val);
1595         if ((!ret) && parser->strict)
1596           return EINA_FALSE;
1597      }
1598
1599    if (run)
1600      (*idx)++;
1601
1602    return EINA_TRUE;
1603 }
1604
1605 static Eina_Bool
1606 _ecore_getopt_parse_arg(const Ecore_Getopt *parser,
1607                         Ecore_Getopt_Value *values,
1608                         int                 argc,
1609                         char              **argv,
1610                         int                *idx,
1611                         int                *nonargs)
1612 {
1613    char *arg = argv[*idx];
1614
1615    if (arg[0] != '-')
1616      {
1617         char **dst, **src, **src_end;
1618
1619         dst = argv + *idx;
1620         src = dst + 1;
1621         src_end = src + *nonargs - *idx - 1;
1622
1623         for (; src < src_end; src++, dst++)
1624           *dst = *src;
1625
1626         *dst = arg;
1627         (*nonargs)--;
1628         return EINA_TRUE;
1629      }
1630
1631    if (arg[1] == '-')
1632      return _ecore_getopt_parse_arg_long(parser, values, argc, argv, idx, nonargs, arg + 2);
1633    else
1634      return _ecore_getopt_parse_arg_short(parser, values, argc, argv, idx, nonargs, arg + 1);
1635 }
1636
1637 static const Ecore_Getopt_Desc *
1638 _ecore_getopt_parse_find_short_other(const Ecore_Getopt      *parser,
1639                                      const Ecore_Getopt_Desc *orig)
1640 {
1641    const Ecore_Getopt_Desc *desc = parser->descs;
1642    const char c = orig->shortname;
1643
1644    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
1645      {
1646         if (desc == orig)
1647           return NULL;
1648
1649         if (c == desc->shortname)
1650           return desc;
1651      }
1652
1653    return NULL;
1654 }
1655
1656 static const Ecore_Getopt_Desc *
1657 _ecore_getopt_parse_find_long_other(const Ecore_Getopt      *parser,
1658                                     const Ecore_Getopt_Desc *orig)
1659 {
1660    const Ecore_Getopt_Desc *desc = parser->descs;
1661    const char *name = orig->longname;
1662
1663    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
1664      {
1665         if (desc == orig)
1666           return NULL;
1667
1668         if (desc->longname && (strcmp(name, desc->longname) == 0))
1669           return desc;
1670      }
1671
1672    return NULL;
1673 }
1674
1675 /**
1676  * Check parser for duplicate entries, print them out.
1677  *
1678  * @return @c EINA_TRUE if there are duplicates, @c EINA_FALSE otherwise.
1679  * @param parser The parser to be checked.
1680  */
1681 EAPI Eina_Bool
1682 ecore_getopt_parser_has_duplicates(const Ecore_Getopt *parser)
1683 {
1684    const Ecore_Getopt_Desc *desc = parser->descs;
1685    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
1686      {
1687         if (desc->shortname)
1688           {
1689              const Ecore_Getopt_Desc *other;
1690              other = _ecore_getopt_parse_find_short_other(parser, desc);
1691              if (other)
1692                {
1693                   _ecore_getopt_desc_print_error(desc, "short name -%c already exists.", desc->shortname);
1694
1695                   if (other->longname)
1696                     fprintf(stderr, " Other is --%s.\n", other->longname);
1697                   else
1698                     fputc('\n', stderr);
1699                   return EINA_TRUE;
1700                }
1701           }
1702
1703         if (desc->longname)
1704           {
1705              const Ecore_Getopt_Desc *other;
1706              other = _ecore_getopt_parse_find_long_other(parser, desc);
1707              if (other)
1708                {
1709                   _ecore_getopt_desc_print_error(desc, "long name --%s already exists.", desc->longname);
1710
1711                   if (other->shortname)
1712                     fprintf(stderr, " Other is -%c.\n", other->shortname);
1713                   else
1714                     fputc('\n', stderr);
1715                   return EINA_TRUE;
1716                }
1717           }
1718      }
1719    return EINA_FALSE;
1720 }
1721
1722 static const Ecore_Getopt_Desc *
1723 _ecore_getopt_find_help(const Ecore_Getopt *parser)
1724 {
1725    const Ecore_Getopt_Desc *desc = parser->descs;
1726    for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
1727      if (desc->action == ECORE_GETOPT_ACTION_HELP)
1728        return desc;
1729    return NULL;
1730 }
1731
1732 /**
1733  * Parse command line parameters.
1734  *
1735  * Walks the command line parameters and parse them based on @a parser
1736  * description, doing actions based on @c parser->descs->action, like
1737  * showing help text, license, copyright, storing values in values and
1738  * so on.
1739  *
1740  * It is expected that values is of the same size than @c parser->descs,
1741  * options that do not need a value it will be left untouched.
1742  *
1743  * All values are expected to be initialized before use. Options with
1744  * action @c ECORE_GETOPT_ACTION_STORE and non required arguments
1745  * (others than @c ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES), are expected
1746  * to provide a value in @c def to be used.
1747  *
1748  * The following actions will store @c 1 on value as a boolean
1749  * (@c value->boolp) if it's not @c NULL to indicate these actions were
1750  * executed:
1751  *   - @c ECORE_GETOPT_ACTION_HELP
1752  *   - @c ECORE_GETOPT_ACTION_VERSION
1753  *   - @c ECORE_GETOPT_ACTION_COPYRIGHT
1754  *   - @c ECORE_GETOPT_ACTION_LICENSE
1755  *
1756  * Just @c ECORE_GETOPT_ACTION_APPEND will allocate memory and thus
1757  * need to be freed. For consistency between all of appended subtypes,
1758  * @c eina_list->data will contain an allocated memory with the value,
1759  * that is, for @c ECORE_GETOPT_TYPE_STR it will contain a copy of the
1760  * argument, @c ECORE_GETOPT_TYPE_INT a pointer to an allocated
1761  * integer and so on.
1762  *
1763  * If parser is in strict mode (see @c Ecore_Getopt->strict), then any
1764  * error will abort parsing and @c -1 is returned. Otherwise it will try
1765  * to continue as far as possible.
1766  *
1767  * This function may reorder @a argv elements.
1768  *
1769  * Translation of help strings (description), metavar, usage, license
1770  * and copyright may be translated, standard/global gettext() call
1771  * will be applied on them if ecore was compiled with such support.
1772  *
1773  * @param parser description of how to work.
1774  * @param values where to store values, it is assumed that this is a vector
1775  *        of the same size as @c parser->descs. Values should be previously
1776  *        initialized.
1777  * @param argc how many elements in @a argv. If not provided it will be
1778  *        retrieved with ecore_app_args_get().
1779  * @param argv command line parameters.
1780  *
1781  * @return index of first non-option parameter or -1 on error.
1782  */
1783 EAPI int
1784 ecore_getopt_parse(const Ecore_Getopt *parser,
1785                    Ecore_Getopt_Value *values,
1786                    int                 argc,
1787                    char              **argv)
1788 {
1789    int i, nonargs;
1790
1791    if (!parser)
1792      {
1793         fputs(_("ERROR: no parser provided.\n"), stderr);
1794         return -1;
1795      }
1796    if (!values)
1797      {
1798         fputs(_("ERROR: no values provided.\n"), stderr);
1799         return -1;
1800      }
1801
1802    if ((argc < 1) || (!argv))
1803      ecore_app_args_get(&argc, &argv);
1804
1805    if (argc < 1)
1806      {
1807         fputs(_("ERROR: no arguments provided.\n"), stderr);
1808         return -1;
1809      }
1810
1811    if (argv[0])
1812      prog = argv[0];
1813    else
1814      prog = parser->prog;
1815
1816    nonargs = _ecore_getopt_parse_find_nonargs_base(parser, argc, argv);
1817    if (nonargs < 0)
1818      goto error;
1819
1820    if (nonargs > argc)
1821      nonargs = argc;
1822
1823    i = 1;
1824    while (i < nonargs)
1825      if (!_ecore_getopt_parse_arg(parser, values, argc, argv, &i, &nonargs))
1826        goto error;
1827
1828    return nonargs;
1829
1830 error:
1831    {
1832       const Ecore_Getopt_Desc *help;
1833       fputs(_("ERROR: invalid options found."), stderr);
1834
1835       help = _ecore_getopt_find_help(parser);
1836       if (!help)
1837         fputc('\n', stderr);
1838       else if (help->longname)
1839         fprintf(stderr, _(" See --%s.\n"), help->longname);
1840       else
1841         fprintf(stderr, _(" See -%c.\n"), help->shortname);
1842    }
1843
1844    return -1;
1845 }
1846
1847 /**
1848  * Utility to free list and nodes allocated by @a ECORE_GETOPT_ACTION_APPEND.
1849  *
1850  * @param list pointer to list to be freed.
1851  * @return always @c NULL, so you can easily make your list head @c NULL.
1852  */
1853 EAPI Eina_List *
1854 ecore_getopt_list_free(Eina_List *list)
1855 {
1856    void *data;
1857
1858    EINA_LIST_FREE(list, data)
1859      free(data);
1860    return NULL;
1861 }
1862
1863 /**
1864  * Helper ecore_getopt callback to parse geometry (x:y:w:h).
1865  *
1866  * @param parser This parameter isn't in use.
1867  * @param desc This parameter isn't in use.
1868  * @param str Geometry value
1869  * @param data This parameter isn't in use.
1870  * @param storage must be a pointer to @c Eina_Rectangle and will be used to
1871  * store the four values passed in the given string.
1872  * @return @c EINA_TRUE on success, @c EINA_FALSE on incorrect geometry value.
1873  *
1874  * @c callback_data value is ignored, you can safely use @c NULL.
1875  */
1876 EAPI Eina_Bool
1877 ecore_getopt_callback_geometry_parse(const Ecore_Getopt      *parser __UNUSED__,
1878                                      const Ecore_Getopt_Desc *desc __UNUSED__,
1879                                      const char              *str,
1880                                      void                    *data __UNUSED__,
1881                                      Ecore_Getopt_Value      *storage)
1882 {
1883    Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp;
1884
1885    if (sscanf(str, "%d:%d:%d:%d", &v->x, &v->y, &v->w, &v->h) != 4)
1886      {
1887         fprintf(stderr, _("ERROR: incorrect geometry value '%s'\n"), str);
1888         return EINA_FALSE;
1889      }
1890
1891    return EINA_TRUE;
1892 }
1893
1894 /**
1895  * Helper ecore_getopt callback to parse geometry size (WxH).
1896  *
1897  * @param parser This parameter isn't in use.
1898  * @param desc This parameter isn't in use.
1899  * @param str size value
1900  * @param data This parameter isn't in use.
1901  * @param storage must be a pointer to @c Eina_Rectangle and will be used to
1902  * store the two values passed in the given string and @c 0 in the x and y
1903  * fields.
1904  * @return @c EINA_TRUE on success, @c EINA_FALSE on incorrect size value.
1905  *
1906  * @c callback_data value is ignored, you can safely use @c NULL.
1907  */
1908 EAPI Eina_Bool
1909 ecore_getopt_callback_size_parse(const Ecore_Getopt      *parser __UNUSED__,
1910                                  const Ecore_Getopt_Desc *desc __UNUSED__,
1911                                  const char              *str,
1912                                  void                    *data __UNUSED__,
1913                                  Ecore_Getopt_Value      *storage)
1914 {
1915    Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp;
1916
1917    if (sscanf(str, "%dx%d", &v->w, &v->h) != 2)
1918      {
1919         fprintf(stderr, _("ERROR: incorrect size value '%s'\n"), str);
1920         return EINA_FALSE;
1921      }
1922    v->x = 0;
1923    v->y = 0;
1924
1925    return EINA_TRUE;
1926 }
1927