q66 pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=edc548fac5497c1bd8d7c35c2942f6686baa64c4
commit edc548fac5497c1bd8d7c35c2942f6686baa64c4 Author: Daniel Kolesa <quake...@gmail.com> Date: Mon Jan 20 17:10:21 2014 +0000 ecore_getopt: support for per-category help listing --- src/lib/ecore/Ecore_Getopt.h | 11 ++-- src/lib/ecore/ecore_getopt.c | 149 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 137 insertions(+), 23 deletions(-) diff --git a/src/lib/ecore/Ecore_Getopt.h b/src/lib/ecore/Ecore_Getopt.h index d41ed3e..e4f5eb5 100644 --- a/src/lib/ecore/Ecore_Getopt.h +++ b/src/lib/ecore/Ecore_Getopt.h @@ -360,9 +360,9 @@ struct _Ecore_Getopt ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, \ NULL) -#define ECORE_GETOPT_HELP(shortname, longname) \ - {shortname, longname, "show this message.", NULL, \ - ECORE_GETOPT_ACTION_HELP, \ +#define ECORE_GETOPT_HELP(shortname, longname) \ + {shortname, longname, "show this message.", "CATEGORY", \ + ECORE_GETOPT_ACTION_HELP, \ {.dummy = NULL}} #define ECORE_GETOPT_VERSION(shortname, longname) \ @@ -390,8 +390,8 @@ struct _Ecore_Getopt ECORE_GETOPT_ACTION_BREAK, \ {.dummy = NULL}} -#define ECORE_GETOPT_CATEGORY(name) \ - {0, NULL, name, NULL, ECORE_GETOPT_ACTION_CATEGORY, {.dummy = NULL}} +#define ECORE_GETOPT_CATEGORY(name, help) \ + {0, name, help, NULL, ECORE_GETOPT_ACTION_CATEGORY, {.dummy = NULL}} #define ECORE_GETOPT_SENTINEL {0, NULL, NULL, NULL, 0, {.dummy = NULL}} @@ -410,6 +410,7 @@ struct _Ecore_Getopt #define ECORE_GETOPT_VALUE_NONE {.ptrp = NULL} EAPI void ecore_getopt_help(FILE *fp, const Ecore_Getopt *info); +EAPI Eina_Bool ecore_getopt_help_category(FILE *fp, const Ecore_Getopt *info, const char *category); EAPI Eina_Bool ecore_getopt_parser_has_duplicates(const Ecore_Getopt *parser); EAPI int ecore_getopt_parse(const Ecore_Getopt *parser, Ecore_Getopt_Value *values, int argc, char **argv); diff --git a/src/lib/ecore/ecore_getopt.c b/src/lib/ecore/ecore_getopt.c index b2195be..7a1505f 100644 --- a/src/lib/ecore/ecore_getopt.c +++ b/src/lib/ecore/ecore_getopt.c @@ -355,7 +355,7 @@ _ecore_getopt_desc_arg_requirement(const Ecore_Getopt_Desc *desc) return desc->action_param.callback.arg_req; case ECORE_GETOPT_ACTION_HELP: - return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL; case ECORE_GETOPT_ACTION_VERSION: return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; @@ -620,9 +620,55 @@ _ecore_getopt_help_desc_choices(FILE *fp, return _ecore_getopt_help_line(fp, base, total, used, ".", 1); } +static int +_ecore_getopt_help_desc_categories(FILE *fp, + const int base, + const int total, + int used, + const Ecore_Getopt_Desc *desc) +{ + const char sep[] = ", "; + const int seplen = sizeof(sep) - 1; + Eina_Bool cat_before = EINA_FALSE; + + if (used > 0) + { + fputc('\n', fp); + used = 0; + } + for (; used < base; used++) + fputc(' ', fp); + + /* do not print available categories if none available */ + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + if (desc->action == ECORE_GETOPT_ACTION_CATEGORY) goto hascat; + + return _ecore_getopt_help_line(fp, base, total, used, + _("No categories available."), + strlen(_("No categories available."))); + +hascat: + used = _ecore_getopt_help_line + (fp, base, total, used, _("Categories: "), strlen(_("Categories: "))); + + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + { + if (desc->action != ECORE_GETOPT_ACTION_CATEGORY || !desc->longname) + continue; + if (cat_before) + used = _ecore_getopt_help_line(fp, base, total, used, sep, seplen); + used = _ecore_getopt_help_line + (fp, base, total, used, desc->longname, strlen(desc->longname)); + cat_before = EINA_TRUE; + } + + return _ecore_getopt_help_line(fp, base, total, used, ".", 1); +} + static void _ecore_getopt_help_desc(FILE *fp, - const Ecore_Getopt_Desc *desc) + const Ecore_Getopt_Desc *desc, + const Ecore_Getopt *parser) { Ecore_Getopt_Desc_Arg_Requirement arg_req; char metavar[32] = "ARG"; @@ -699,6 +745,11 @@ _ecore_getopt_help_desc(FILE *fp, _ecore_getopt_help_desc_choices(fp, helpcol, cols, used, desc); break; + case ECORE_GETOPT_ACTION_HELP: + _ecore_getopt_help_desc_categories(fp, helpcol, cols, used, + parser->descs); + break; + default: break; } @@ -710,7 +761,8 @@ end: static Eina_Bool _ecore_getopt_desc_is_sentinel(const Ecore_Getopt_Desc *desc) { - return (desc->shortname == '\0') && (!desc->longname); + return (desc->shortname == '\0') && (!desc->longname) + && (desc->action != ECORE_GETOPT_ACTION_CATEGORY); } static void @@ -722,7 +774,7 @@ _ecore_getopt_help_options(FILE *fp, fputs(_("Options:\n"), fp); for (desc = parser->descs; !_ecore_getopt_desc_is_sentinel(desc); desc++) - _ecore_getopt_help_desc(fp, desc); + _ecore_getopt_help_desc(fp, desc, parser); fputc('\n', fp); @@ -730,25 +782,18 @@ _ecore_getopt_help_options(FILE *fp, fputs(_("Positional arguments:\n"), fp); for (; desc->metavar != NULL; desc++) - _ecore_getopt_help_desc(fp, desc); + _ecore_getopt_help_desc(fp, desc, parser); fputc('\n', fp); } -/** - * Show nicely formatted help message for the given parser. - * - * @param fp The file the message will be printed on. - * @param parser The parser to be used. - */ -EAPI void -ecore_getopt_help(FILE *fp, - const Ecore_Getopt *parser) +static Eina_Bool +_ecore_getopt_help_prepare(const Ecore_Getopt *parser) { const char *var; EINA_MAIN_LOOP_CHECK_RETURN; - if (!parser) return; + if (!parser) return EINA_FALSE; if (_argc < 1) { @@ -769,11 +814,75 @@ ecore_getopt_help(FILE *fp, helpcol = cols / 3; } + return EINA_TRUE; +} + +/** + * Show nicely formatted help message for the given parser. + * + * @param fp The file the message will be printed on. + * @param parser The parser to be used. + * + * @see ecore_getopt_help_category() + */ +EAPI void +ecore_getopt_help(FILE *fp, + const Ecore_Getopt *parser) +{ + if (!_ecore_getopt_help_prepare(parser)) + return; + _ecore_getopt_help_usage(fp, parser); _ecore_getopt_help_description(fp, parser); _ecore_getopt_help_options(fp, parser); } +/** + * Show help for a single category (along with program usage and description). + * + * @param fp The file the message will be printed on. + * @param parser The parser to be used. + * @param category The category to print. + * + * @return @c EINA_TRUE when the category exists, @c EINA_FALSE otherwise. + * + * @see ecore_getopt_help() + */ +EAPI Eina_Bool +ecore_getopt_help_category(FILE *fp, + const Ecore_Getopt *parser, + const char *category) +{ + const Ecore_Getopt_Desc *desc; + Eina_Bool found = EINA_FALSE; + + if (!category || !_ecore_getopt_help_prepare(parser)) return EINA_FALSE; + for (desc = parser->descs; !_ecore_getopt_desc_is_sentinel(desc); desc++) + { + if (desc->action != ECORE_GETOPT_ACTION_CATEGORY) continue; + if (!desc->longname || strcmp(desc->longname, category)) continue; + found = EINA_TRUE; + break; + } + if (!found) + { + fprintf(stderr, _("ERROR: unknown category '%s'.\n"), category); + return EINA_FALSE; + } + + _ecore_getopt_help_usage(fp, parser); + _ecore_getopt_help_description(fp, parser); + + fprintf(fp, "%s\n", (desc++)->help); + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + { + if (desc->action == ECORE_GETOPT_ACTION_CATEGORY) break; + _ecore_getopt_help_desc(fp, desc, parser); + } + + return EINA_TRUE; +} + static const Ecore_Getopt_Desc * _ecore_getopt_parse_find_long(const Ecore_Getopt *parser, const char *name) @@ -787,7 +896,7 @@ _ecore_getopt_parse_find_long(const Ecore_Getopt *parser, for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) { - if (!desc->longname) + if (!desc->longname || desc->action == ECORE_GETOPT_ACTION_CATEGORY) continue; if (p) @@ -873,7 +982,7 @@ _ecore_getopt_parse_find_nonargs_base(const Ecore_Getopt *parser, goto found_nonarg; } - + if (desc->action == ECORE_GETOPT_ACTION_BREAK) abreak = 1; @@ -1430,10 +1539,12 @@ static Eina_Bool _ecore_getopt_parse_help(const Ecore_Getopt *parser, const Ecore_Getopt_Desc *desc EINA_UNUSED, Ecore_Getopt_Value *val, - const char *arg_val EINA_UNUSED) + const char *arg_val) { if (val->boolp) (*val->boolp) = EINA_TRUE; + if (arg_val) + return ecore_getopt_help_category(stdout, parser, arg_val); ecore_getopt_help(stdout, parser); return EINA_TRUE; } @@ -1862,6 +1973,8 @@ _ecore_getopt_parse_find_long_other(const Ecore_Getopt *parser, { if (desc == orig) return NULL; + if (desc->action == ECORE_GETOPT_ACTION_CATEGORY) + continue; if (desc->longname && (strcmp(name, desc->longname) == 0)) return desc; --