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