ecore_getopt: support for per-category help listing

This commit is contained in:
Daniel Kolesa 2014-01-20 17:10:21 +00:00
parent f0aac1b490
commit edc548fac5
2 changed files with 137 additions and 23 deletions

View File

@ -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);

View File

@ -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;