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