summaryrefslogtreecommitdiff
path: root/src/lib/ecore/ecore_getopt.c
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>2013-12-17 21:06:53 -0200
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>2013-12-17 21:06:53 -0200
commit0b86e5119f328b6fa979bcbff6391a6458c6efe8 (patch)
treefeeaf8fdd1b446a2699ae65050d258d4260ed41d /src/lib/ecore/ecore_getopt.c
parent1c1f9ea0e1a2c4014d5cb5ca0f749164dcd384e5 (diff)
getopt: add positional argument handling.
positional arguments must appear at the end of the description array (after the last option) and should have a metavar set and not have shortname or longname. Simple, elegant and fit :-) There is a new function to parse the positional arguments, ecore_getopt_parse_positional() because we may want to not try to parse them in the case of a quit-option such as --help, --license, --copyright, --version or some user-defined action. This avoids us producing errors of missing positional arguments when printing help and adds some flexibility as well. This should make Tasn happy :-)
Diffstat (limited to 'src/lib/ecore/ecore_getopt.c')
-rw-r--r--src/lib/ecore/ecore_getopt.c299
1 files changed, 293 insertions, 6 deletions
diff --git a/src/lib/ecore/ecore_getopt.c b/src/lib/ecore/ecore_getopt.c
index 2a7850f48b..2af5d47183 100644
--- a/src/lib/ecore/ecore_getopt.c
+++ b/src/lib/ecore/ecore_getopt.c
@@ -43,6 +43,12 @@ static int _argc = 0;
43static int cols = 80; 43static int cols = 80;
44static int helpcol = 80 / 3; 44static int helpcol = 80 / 3;
45 45
46
47static Eina_Bool _ecore_getopt_desc_is_sentinel(const Ecore_Getopt_Desc *desc);
48static Ecore_Getopt_Desc_Arg_Requirement _ecore_getopt_desc_arg_requirement(const Ecore_Getopt_Desc *desc);
49static void _ecore_getopt_help_desc_setup_metavar(const Ecore_Getopt_Desc *desc, char *metavar, int *metavarlen, int maxsize);
50
51
46static void 52static void
47_ecore_getopt_help_print_replace_program(FILE *fp, 53_ecore_getopt_help_print_replace_program(FILE *fp,
48 const Ecore_Getopt *parser EINA_UNUSED, 54 const Ecore_Getopt *parser EINA_UNUSED,
@@ -98,7 +104,42 @@ _ecore_getopt_help_usage(FILE *fp,
98 104
99 if (!parser->usage) 105 if (!parser->usage)
100 { 106 {
101 fprintf(fp, _("%s [options]\n"), prog); 107 const Ecore_Getopt_Desc *d;
108
109 fprintf(fp, _("%s [options]"), prog);
110
111 for (d = parser->descs; !_ecore_getopt_desc_is_sentinel(d); d++);
112
113 if (d->metavar)
114 {
115 for (; d->metavar != NULL; d++)
116 {
117 Ecore_Getopt_Desc_Arg_Requirement ar;
118 char metavar[32];
119 int metavarlen = 0;
120
121 ar = _ecore_getopt_desc_arg_requirement(d);
122 _ecore_getopt_help_desc_setup_metavar(d, metavar,
123 &metavarlen,
124 sizeof(metavar));
125
126 fputc(' ', fp);
127 if (ar != ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES)
128 fputc('[', fp);
129 fputs(metavar, fp);
130
131 if (ar != ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES)
132 fputc(']', fp);
133
134 if (d->action == ECORE_GETOPT_ACTION_APPEND)
135 {
136 fprintf(fp, " [%s] ...", metavar);
137 break;
138 }
139 }
140 }
141
142 fputc('\n', fp);
102 return; 143 return;
103 } 144 }
104 145
@@ -358,7 +399,8 @@ static int
358_ecore_getopt_help_desc_show_arg(FILE *fp, 399_ecore_getopt_help_desc_show_arg(FILE *fp,
359 Ecore_Getopt_Desc_Arg_Requirement requirement, 400 Ecore_Getopt_Desc_Arg_Requirement requirement,
360 const char *metavar, 401 const char *metavar,
361 int metavarlen) 402 int metavarlen,
403 Eina_Bool show_attr)
362{ 404{
363 int used; 405 int used;
364 406
@@ -375,9 +417,13 @@ _ecore_getopt_help_desc_show_arg(FILE *fp,
375 417
376 if (requirement != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO) 418 if (requirement != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
377 { 419 {
378 fputc('=', fp); 420 if (show_attr)
421 {
422 fputc('=', fp);
423 used++;
424 }
379 fputs(metavar, fp); 425 fputs(metavar, fp);
380 used += metavarlen + 1; 426 used += metavarlen;
381 } 427 }
382 428
383 if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL) 429 if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL)
@@ -597,7 +643,7 @@ _ecore_getopt_help_desc(FILE *fp,
597 fputc(desc->shortname, fp); 643 fputc(desc->shortname, fp);
598 used += 2; 644 used += 2;
599 used += _ecore_getopt_help_desc_show_arg 645 used += _ecore_getopt_help_desc_show_arg
600 (fp, arg_req, metavar, metavarlen); 646 (fp, arg_req, metavar, metavarlen, EINA_TRUE);
601 } 647 }
602 648
603 if (desc->shortname && desc->longname) 649 if (desc->shortname && desc->longname)
@@ -614,7 +660,12 @@ _ecore_getopt_help_desc(FILE *fp,
614 fputs(desc->longname, fp); 660 fputs(desc->longname, fp);
615 used += 2 + namelen; 661 used += 2 + namelen;
616 used += _ecore_getopt_help_desc_show_arg 662 used += _ecore_getopt_help_desc_show_arg
617 (fp, arg_req, metavar, metavarlen); 663 (fp, arg_req, metavar, metavarlen, EINA_TRUE);
664 }
665 else if ((!desc->shortname) && (desc->metavar))
666 {
667 used += _ecore_getopt_help_desc_show_arg
668 (fp, arg_req, metavar, metavarlen, EINA_FALSE);
618 } 669 }
619 670
620 if (!desc->help) 671 if (!desc->help)
@@ -668,6 +719,14 @@ _ecore_getopt_help_options(FILE *fp,
668 _ecore_getopt_help_desc(fp, desc); 719 _ecore_getopt_help_desc(fp, desc);
669 720
670 fputc('\n', fp); 721 fputc('\n', fp);
722
723 if (!desc->metavar) return;
724
725 fputs(_("Positional arguments:\n"), fp);
726 for (; desc->metavar != NULL; desc++)
727 _ecore_getopt_help_desc(fp, desc);
728
729 fputc('\n', fp);
671} 730}
672 731
673/** 732/**
@@ -877,6 +936,14 @@ _ecore_getopt_desc_print_error(const Ecore_Getopt_Desc *desc,
877 fputs("--", stderr); 936 fputs("--", stderr);
878 fputs(desc->longname, stderr); 937 fputs(desc->longname, stderr);
879 } 938 }
939 else if ((!desc->shortname) && (desc->metavar))
940 {
941 char metavar[32];
942 int metavarlen = 0;
943 _ecore_getopt_help_desc_setup_metavar(desc, metavar, &metavarlen,
944 sizeof(metavar));
945 fputs(metavar, stderr);
946 }
880 947
881 fputs(": ", stderr); 948 fputs(": ", stderr);
882 949
@@ -1667,6 +1734,98 @@ _ecore_getopt_parse_arg(const Ecore_Getopt *parser,
1667 return _ecore_getopt_parse_arg_short(parser, values, argc, argv, idx, nonargs, arg + 1); 1734 return _ecore_getopt_parse_arg_short(parser, values, argc, argv, idx, nonargs, arg + 1);
1668} 1735}
1669 1736
1737static Eina_Bool
1738_ecore_getopt_parse_pos(const Ecore_Getopt *parser,
1739 const Ecore_Getopt_Desc **p_desc,
1740 Ecore_Getopt_Value *values,
1741 int argc,
1742 char **argv,
1743 int *idx,
1744 int *nonargs)
1745{
1746 const Ecore_Getopt_Desc *desc = *p_desc;
1747 Ecore_Getopt_Desc_Arg_Requirement arg_req;
1748 char metavar[32];
1749 int metavarlen = 0;
1750 const char *arg_val;
1751 int desc_idx;
1752 Ecore_Getopt_Value *value;
1753 Eina_Bool ret;
1754
1755 _ecore_getopt_help_desc_setup_metavar
1756 (desc, metavar, &metavarlen, sizeof(metavar));
1757
1758 desc_idx = desc - parser->descs;
1759 value = values + desc_idx;
1760
1761 arg_req = _ecore_getopt_desc_arg_requirement(desc);
1762 if (*idx >= argc)
1763 {
1764 (*p_desc)++;
1765 if (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES)
1766 {
1767 /* TODO: should we consider callback here as well? */
1768 if ((desc->action == ECORE_GETOPT_ACTION_APPEND) &&
1769 (value->listp) && (*value->listp))
1770 {
1771 printf("append desc: %s (%d), value: %p\n",
1772 desc->metavar, desc_idx, value->listp);
1773 return EINA_TRUE;
1774 }
1775
1776 fprintf(stderr,
1777 _("ERROR: missing required positional argument %s.\n"),
1778 metavar);
1779 return EINA_FALSE;
1780 }
1781 return EINA_TRUE;
1782 }
1783
1784 arg_val = argv[*idx];
1785
1786 switch (desc->action)
1787 {
1788 case ECORE_GETOPT_ACTION_STORE:
1789 ret = _ecore_getopt_parse_store(parser, desc, value, arg_val);
1790 (*p_desc)++;
1791 break;
1792
1793 case ECORE_GETOPT_ACTION_CHOICE:
1794 ret = _ecore_getopt_parse_choice(parser, desc, value, arg_val);
1795 (*p_desc)++;
1796 break;
1797
1798 case ECORE_GETOPT_ACTION_APPEND:
1799 ret = _ecore_getopt_parse_append(parser, desc, value, arg_val);
1800 /* no changes to p_desc, we keep appending until the end */
1801 break;
1802
1803 case ECORE_GETOPT_ACTION_CALLBACK:
1804 ret = _ecore_getopt_parse_callback(parser, desc, value, arg_val);
1805 (*p_desc)++;
1806 break;
1807
1808 default:
1809 fprintf(stderr, _("ERROR: unsupported action type %d "
1810 "for positional argument %s\n"),
1811 desc->action, metavar);
1812 (*p_desc)++;
1813 ret = EINA_FALSE;
1814 break;
1815 }
1816
1817 if (ret)
1818 {
1819 (*idx)++;
1820 (*nonargs)++;
1821 }
1822
1823 if ((!ret) && parser->strict)
1824 return EINA_FALSE;
1825
1826 return EINA_TRUE;
1827}
1828
1670static const Ecore_Getopt_Desc * 1829static const Ecore_Getopt_Desc *
1671_ecore_getopt_parse_find_short_other(const Ecore_Getopt *parser, 1830_ecore_getopt_parse_find_short_other(const Ecore_Getopt *parser,
1672 const Ecore_Getopt_Desc *orig) 1831 const Ecore_Getopt_Desc *orig)
@@ -1803,6 +1962,15 @@ _ecore_getopt_find_help(const Ecore_Getopt *parser)
1803 * and copyright may be translated, standard/global gettext() call 1962 * and copyright may be translated, standard/global gettext() call
1804 * will be applied on them if ecore was compiled with such support. 1963 * will be applied on them if ecore was compiled with such support.
1805 * 1964 *
1965 * This function will @b not parse positional arguments! If these are
1966 * declared (metavar is defined with both shortname and longname being
1967 * empty), then you must call ecore_getopt_parse_positional() with the
1968 * last argument (@c start) being the result of this function. This is
1969 * done so you can have "quit options", those that once called you
1970 * want to exit without doing further parsing, as is the case with
1971 * help, license, copyright, version and eventually others you may
1972 * define.
1973 *
1806 * @param parser description of how to work. 1974 * @param parser description of how to work.
1807 * @param values where to store values, it is assumed that this is a vector 1975 * @param values where to store values, it is assumed that this is a vector
1808 * of the same size as @c parser->descs. Values should be previously 1976 * of the same size as @c parser->descs. Values should be previously
@@ -1812,6 +1980,8 @@ _ecore_getopt_find_help(const Ecore_Getopt *parser)
1812 * @param argv command line parameters. 1980 * @param argv command line parameters.
1813 * 1981 *
1814 * @return index of first non-option parameter or -1 on error. 1982 * @return index of first non-option parameter or -1 on error.
1983 *
1984 * @see ecore_getopt_parse_positional()
1815 */ 1985 */
1816EAPI int 1986EAPI int
1817ecore_getopt_parse(const Ecore_Getopt *parser, 1987ecore_getopt_parse(const Ecore_Getopt *parser,
@@ -1878,6 +2048,123 @@ error:
1878} 2048}
1879 2049
1880/** 2050/**
2051 * Parse command line positional parameters.
2052 *
2053 * Walks the command line positional parameters (those that do not
2054 * start with "-" or "--") and parse them based on @a parser
2055 * description, doing actions based on @c parser->descs->action, like
2056 * storing values of some type.
2057 *
2058 * It is expected that @a values is of the same size than @c
2059 * parser->descs, same as with ecore_getopt_parse().
2060 *
2061 * All values are expected to be initialized before use.
2062 *
2063 * Unlike the ecore_getopt_parse(), only the following options are
2064 * supported:
2065 * - @c ECORE_GETOPT_ACTION_STORE
2066 * - @c ECORE_GETOPT_ACTION_CHOICE
2067 * - @c ECORE_GETOPT_ACTION_APPEND
2068 * - @c ECORE_GETOPT_ACTION_CALLBACK
2069 *
2070 * There is a special case for @c ECORE_GETOPT_ACTION_APPEND as it
2071 * will consume all remaining elements. It is also special in the
2072 * sense that it will allocate memory and thus need to be freed. For
2073 * consistency between all of appended subtypes, @c eina_list->data
2074 * will contain an allocated memory with the value, that is, for @c
2075 * ECORE_GETOPT_TYPE_STR it will contain a copy of the argument, @c
2076 * ECORE_GETOPT_TYPE_INT a pointer to an allocated integer and so on.
2077 *
2078 * If parser is in strict mode (see @c Ecore_Getopt->strict), then any
2079 * error will abort parsing and @c -1 is returned. Otherwise it will try
2080 * to continue as far as possible.
2081 *
2082 * Translation of help strings (description) and metavar may be done,
2083 * standard/global gettext() call will be applied on them if ecore was
2084 * compiled with such support.
2085 *
2086 * @param parser description of how to work.
2087 * @param values where to store values, it is assumed that this is a vector
2088 * of the same size as @c parser->descs. Values should be previously
2089 * initialized.
2090 * @param argc how many elements in @a argv. If not provided it will be
2091 * retrieved with ecore_app_args_get().
2092 * @param argv command line parameters.
2093 * @param start the initial position argument to look at, usually the
2094 * return of ecore_getopt_parse(). If less than 1, will try to
2095 * find it automatically.
2096 *
2097 * @return index of first non-option parameter or -1 on error. If the
2098 * last positional argument is of action @c
2099 * ECORE_GETOPT_ACTION_APPEND then it will be the same as @a argc.
2100 */
2101EAPI int
2102ecore_getopt_parse_positional(const Ecore_Getopt *parser,
2103 Ecore_Getopt_Value *values,
2104 int argc,
2105 char **argv,
2106 int start)
2107{
2108 const Ecore_Getopt_Desc *desc;
2109 int nonargs;
2110
2111 if (!parser)
2112 {
2113 fputs(_("ERROR: no parser provided.\n"), stderr);
2114 return -1;
2115 }
2116 if (!values)
2117 {
2118 fputs(_("ERROR: no values provided.\n"), stderr);
2119 return -1;
2120 }
2121
2122 if ((argc < 1) || (!argv))
2123 ecore_app_args_get(&argc, &argv);
2124
2125 if (argc < 1)
2126 {
2127 fputs(_("ERROR: no arguments provided.\n"), stderr);
2128 return -1;
2129 }
2130
2131 if (argv[0])
2132 prog = argv[0];
2133 else
2134 prog = parser->prog;
2135
2136 if (start > argc)
2137 start = argc;
2138 else if (start < 1)
2139 start = _ecore_getopt_parse_find_nonargs_base(parser, argc, argv);
2140
2141 nonargs = start;
2142 for (desc = parser->descs; !_ecore_getopt_desc_is_sentinel(desc); desc++);
2143 while (desc->metavar)
2144 if (!_ecore_getopt_parse_pos
2145 (parser, &desc, values, argc, argv, &start, &nonargs))
2146 goto error;
2147
2148 return nonargs;
2149
2150error:
2151 {
2152 const Ecore_Getopt_Desc *help;
2153 fputs(_("ERROR: invalid positional arguments found."), stderr);
2154
2155 help = _ecore_getopt_find_help(parser);
2156 if (!help)
2157 fputc('\n', stderr);
2158 else if (help->longname)
2159 fprintf(stderr, _(" See --%s.\n"), help->longname);
2160 else
2161 fprintf(stderr, _(" See -%c.\n"), help->shortname);
2162 }
2163
2164 return -1;
2165}
2166
2167/**
1881 * Utility to free list and nodes allocated by @a ECORE_GETOPT_ACTION_APPEND. 2168 * Utility to free list and nodes allocated by @a ECORE_GETOPT_ACTION_APPEND.
1882 * 2169 *
1883 * @param list pointer to list to be freed. 2170 * @param list pointer to list to be freed.