X-Git-Url: http://git.draconx.ca/gitweb/dxcommon.git/blobdiff_plain/843799dbec995b276a7d017bb32c053747b55400..9cacb902a5d6f6c4271ee3066e2efe13663f145a:/src/help.c diff --git a/src/help.c b/src/help.c index 0ceb8f4..4b77b2c 100644 --- a/src/help.c +++ b/src/help.c @@ -1,5 +1,5 @@ /* - * Copyright © 2021 Nick Bowler + * Copyright © 2021-2023 Nick Bowler * * Helper functions for formatting --help program output. * @@ -28,6 +28,7 @@ #endif #if ENABLE_NLS +# include # include # include #else @@ -50,7 +51,12 @@ */ static int option_type(const struct option *opt) { - return ((opt->val <= CHAR_MAX) << 2) | (opt->has_arg & 3); + int ret = opt->has_arg & 3; + + if (!opt->flag) + ret |= (opt->val <= CHAR_MAX) << 2; + + return ret; } enum { @@ -62,48 +68,82 @@ enum { OPT_LONG_WITHOUT_ARG = 0, }; +/* + * When NLS is enabled, we assume snprintf is available. The GNU libintl + * library should provide a suitable fallback if necessary. + */ +#if ENABLE_NLS && !defined(help_do_snprintf) +#define help_do_snprintf snprintf +#elif !ENABLE_NLS +#define help_do_snprintf fake_snprintf +static inline int fake_snprintf(char *buf, size_t n, const char *fmt, ...) +{ + return -1; +} +#endif + int help_print_optstring(const struct option *opt, const char *argname, int l) { - char optstring[100]; + char optstring[256]; int w; if (!ENABLE_NLS) goto no_translate; switch (option_type(opt)) { +#if HELP_GETOPT_LONG_ONLY case OPT_SHORT_WITH_OPTIONAL_ARG: - w = snprintf(optstring, sizeof optstring, - _(" -%c, --%s[=%s]"), opt->val, opt->name, - pgettext_expr(opt->name, argname)); + case OPT_LONG_WITH_OPTIONAL_ARG: + w = help_do_snprintf(optstring, sizeof optstring, + _(" -%s [%s]"), opt->name, + pgettext_expr(opt->name, argname)); + break; + case OPT_SHORT_WITH_MANDATORY_ARG: + case OPT_LONG_WITH_MANDATORY_ARG: + w = help_do_snprintf(optstring, sizeof optstring, + _(" -%s %s"), opt->name, + pgettext_expr(opt->name, argname)); + break; + case OPT_SHORT_WITHOUT_ARG: + case OPT_LONG_WITHOUT_ARG: + w = help_do_snprintf(optstring, sizeof optstring, + _(" -%s"), opt->name); + break; +#else + case OPT_SHORT_WITH_OPTIONAL_ARG: + w = help_do_snprintf(optstring, sizeof optstring, + _(" -%c, --%s[=%s]"), opt->val, opt->name, + pgettext_expr(opt->name, argname)); break; case OPT_LONG_WITH_OPTIONAL_ARG: - w = snprintf(optstring, sizeof optstring, - _(" --%s[=%s]"), opt->name, - pgettext_expr(opt->name, argname)); + w = help_do_snprintf(optstring, sizeof optstring, + _(" --%s[=%s]"), opt->name, + pgettext_expr(opt->name, argname)); break; case OPT_SHORT_WITH_MANDATORY_ARG: - w = snprintf(optstring, sizeof optstring, - _(" -%c, --%s=%s"), opt->val, opt->name, - pgettext_expr(opt->name, argname)); + w = help_do_snprintf(optstring, sizeof optstring, + _(" -%c, --%s=%s"), opt->val, opt->name, + pgettext_expr(opt->name, argname)); break; case OPT_LONG_WITH_MANDATORY_ARG: - w = snprintf(optstring, sizeof optstring, - _(" --%s=%s"), opt->name, - pgettext_expr(opt->name, argname)); + w = help_do_snprintf(optstring, sizeof optstring, + _(" --%s=%s"), opt->name, + pgettext_expr(opt->name, argname)); break; case OPT_SHORT_WITHOUT_ARG: - w = snprintf(optstring, sizeof optstring, - _(" -%c, --%s"), opt->val, opt->name); + w = help_do_snprintf(optstring, sizeof optstring, + _(" -%c, --%s"), opt->val, opt->name); break; case OPT_LONG_WITHOUT_ARG: - w = snprintf(optstring, sizeof optstring, - _(" --%s"), opt->name); + w = help_do_snprintf(optstring, sizeof optstring, + _(" --%s"), opt->name); break; +#endif default: assert(0); } - if (w < 0) + if (w < 0 || w >= sizeof optstring) goto no_translate; w = mbsnwidth(optstring, w, 0); @@ -112,6 +152,20 @@ int help_print_optstring(const struct option *opt, const char *argname, int l) no_translate: switch (option_type(opt)) { +#if HELP_GETOPT_LONG_ONLY + case OPT_SHORT_WITH_OPTIONAL_ARG: + case OPT_LONG_WITH_OPTIONAL_ARG: + w = printf(" -%s [%s]", opt->name, argname); + break; + case OPT_SHORT_WITH_MANDATORY_ARG: + case OPT_LONG_WITH_MANDATORY_ARG: + w = printf(" -%s %s", opt->name, argname); + break; + case OPT_SHORT_WITHOUT_ARG: + case OPT_LONG_WITHOUT_ARG: + w = printf(" -%s", opt->name); + break; +#else case OPT_SHORT_WITH_OPTIONAL_ARG: w = printf(" -%c, --%s[=%s]", opt->val, opt->name, argname); break; @@ -130,6 +184,7 @@ no_translate: case OPT_LONG_WITHOUT_ARG: w = printf(" --%s", opt->name); break; +#endif default: assert(0); } @@ -144,7 +199,13 @@ out: void help_print_desc(const struct option *opt, const char *s, int i, int w) { - for (s = pgettext_expr(opt->name, s); *s; w = 0) { + if (opt) + s = pgettext_expr(opt->name, s); + + if (i && s[0] == '\0') + putchar('\n'); + + for (; *s; w = 0) { const char *nl = strchr(s, '\n'); int n = (nl ? nl-s : -1);