From 476f42d951d7e9f9f30e1a6acb34982466936490 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 15 Nov 2023 20:33:31 -0500 Subject: [PATCH] help_print_optstring: Don't depend on snprintf. The current code calls snprintf unconditionally, even if NLS is disabled (although the function is not called, the code is still compiled), so it won't build in environments which lack this function. For the NLS-enabled case we can rely on the GNU libintl fallback being available as required. Otherwise we can just provide a stub to ensure the dead code compiles, and for the NLS test programs hack in sprintf as a replacement which should work just fine. --- src/help.c | 66 ++++++++++++++++++++++++++++++------------------- t/nls/gettext.h | 20 +++++++++++++++ 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/help.c b/src/help.c index f96025f..4b77b2c 100644 --- a/src/help.c +++ b/src/help.c @@ -68,9 +68,23 @@ 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) @@ -80,56 +94,56 @@ int help_print_optstring(const struct option *opt, const char *argname, int l) #if HELP_GETOPT_LONG_ONLY case OPT_SHORT_WITH_OPTIONAL_ARG: 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: 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: case OPT_LONG_WITHOUT_ARG: - w = snprintf(optstring, sizeof optstring, - _(" -%s"), opt->name); + w = help_do_snprintf(optstring, sizeof optstring, + _(" -%s"), opt->name); break; #else case OPT_SHORT_WITH_OPTIONAL_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_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); diff --git a/t/nls/gettext.h b/t/nls/gettext.h index b8a8060..8392992 100644 --- a/t/nls/gettext.h +++ b/t/nls/gettext.h @@ -11,7 +11,27 @@ #ifndef TEST_NLS_GETTEXT_H_ #define TEST_NLS_GETTEXT_H_ +#include +#include + #define gettext(s) (s) #define pgettext_expr(a, s) (s) +/* + * We don't need a real snprintf for testing help functionality; substitute + * using vsprintf to ease testing on C89 implementations. + */ +#define help_do_snprintf help_do_snprintf +static inline int help_do_snprintf(char *buf, size_t n, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsprintf(buf, fmt, ap); + va_end(ap); + + return ret; +} + #endif -- 2.43.2