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