From 3bc8f0973328da93c66d8197edc7cea186082f15 Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Tue, 17 Dec 2013 21:06:53 -0200 Subject: [PATCH] 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 :-) --- unsorted/ecore/ecore_getopt_example.c | 84 +++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/unsorted/ecore/ecore_getopt_example.c b/unsorted/ecore/ecore_getopt_example.c index dc91f0c2..f299266e 100644 --- a/unsorted/ecore/ecore_getopt_example.c +++ b/unsorted/ecore/ecore_getopt_example.c @@ -5,6 +5,17 @@ #include #include +/* if defined will end the positional arguments with the special + * action ECORE_GETOPT_ACTION_APPEND that will require at least one + * trailing argument and will also consume the remaining arguments + * until the end. + * + * if not defined unhandled positional arguments start at the index + * returned by ecore_getopt_parse_positional(), that will be less or + * equal to argc. + */ +#define END_WITH_POS_APPEND 1 + static const char * available_choices[] = { "banana", "apple", @@ -15,8 +26,8 @@ static const char * available_choices[] = { static const Ecore_Getopt options = { /* program name, usually a macro PACKAGE_NAME */ "ecore_getopt_example", - /* usage line */ - "%prog [options]", + /* usage line, leave empty to generate one with positional arguments */ + NULL, /* program version, usually a macro PACKAGE_VERSION */ "0.1", /* copyright string */ @@ -136,6 +147,25 @@ static const Ecore_Getopt options = { ECORE_GETOPT_LICENSE('L', "license"), ECORE_GETOPT_HELP('h', "help"), + /* positional arguments can be handled as well, add their + * description after the last option was specified. They should + * have empty short and long options, but have the metavar + * defined. + */ + ECORE_GETOPT_STORE_METAVAR_STR(0, NULL, "Positional string.", "STRING"), + ECORE_GETOPT_STORE_METAVAR_INT(0, NULL, "Positional integer.", "INT"), + ECORE_GETOPT_CHOICE_METAVAR(0, NULL, "Positional choice.", "CHOICE", + available_choices), + +#ifdef END_WITH_POS_APPEND + /* this will consume until the end of the command line, forcing + * ecore_getopt_parse() to return args == argc on succes. + * It will require at least one argument in the end of the command line. + */ + ECORE_GETOPT_APPEND_METAVAR(0, NULL, "Extra options.", "ARG", + ECORE_GETOPT_TYPE_STR), +#endif + /* the sentinel is required to notify end of descriptions */ ECORE_GETOPT_SENTINEL } @@ -172,6 +202,12 @@ main(int argc, char **argv) Eina_List *lst_ints = NULL; Eina_Bool break_given = EINA_FALSE; Eina_Bool quit_option = EINA_FALSE; + char *pos_str = NULL; + int pos_int = 0; + char *pos_choice = NULL; +#ifdef END_WITH_POS_APPEND + Eina_List *pos_args = NULL; +#endif Ecore_Getopt_Value values[] = { /* block of options that store a single value in a variable of type */ ECORE_GETOPT_VALUE_STR(str_value), @@ -218,6 +254,15 @@ main(int argc, char **argv) ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */ ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */ + /* example of positiona argument */ + ECORE_GETOPT_VALUE_STR(pos_str), + ECORE_GETOPT_VALUE_INT(pos_int), + ECORE_GETOPT_VALUE_STR(pos_choice), + +#ifdef END_WITH_POS_APPEND + ECORE_GETOPT_VALUE_LIST(pos_args), +#endif + ECORE_GETOPT_VALUE_NONE /* sentinel */ }; int args, retval = EXIT_SUCCESS; @@ -240,6 +285,14 @@ main(int argc, char **argv) /* options that set 'quit_option' to true requires us to exit. */ if (quit_option) goto end; + args = ecore_getopt_parse_positional(&options, values, argc, argv, args); + if (args < 0) + { + fputs("ERROR: Could not parse positional arguments.\n", stderr); + retval = EXIT_FAILURE; + goto end; + } + printf("given values:\n" "string = %s\n" "bool = %s\n" @@ -269,6 +322,10 @@ main(int argc, char **argv) "choice = %s\n" "\n" "--break = %s\n" + "\nDeclared Positional:\n" + "STRING = %s\n" + "INT = %d\n" + "CHOICE = %s\n" "\n", str_value, bool_value ? "true" : "false", @@ -294,7 +351,10 @@ main(int argc, char **argv) use_z, count, choice, - break_given ? "given" : "omitted"); + break_given ? "given" : "omitted", + pos_str, + pos_int, + pos_choice); if (!lst_strs) puts("no --append-string=VALUE was given."); @@ -324,14 +384,30 @@ main(int argc, char **argv) } } +#ifdef END_WITH_POS_APPEND + assert(pos_args != NULL); + assert(args == argc); + if (1) + { + char *str; + printf("%u extra arguments:\n", + eina_list_count(pos_args)); + EINA_LIST_FREE(pos_args, str) + { + printf("\t%s\n", str); + free(str); + } + } +#else if (args == argc) - puts("no positional arguments were given."); + puts("no extra positional arguments were given."); else { printf("%d positional arguments were given:\n", argc - args); for (; args < argc; args++) printf("\t%s\n", argv[args]); } +#endif end: ecore_shutdown();