]> git.draconx.ca Git - dxcommon.git/blobdiff - src/help.c
help_print_desc: Simplify implementation.
[dxcommon.git] / src / help.c
index d1dd5f5bc44055bf50a4599b0e1f24cf15ddc0bf..3aa083003a03710560976034a209cc44b2f5cb3a 100644 (file)
@@ -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 <locale.h>
 #      include <gettext.h>
 #      include <mbswidth.h>
 #else
  */
 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,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)
@@ -74,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);
@@ -179,14 +199,14 @@ 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) {
-               const char *nl = strchr(s, '\n');
-               int n = (nl ? nl-s : -1);
+       if (opt)
+               s = pgettext_expr(opt->name, s);
 
-               printf("%*s%.*s\n", i-w, "", n, s);
-               if (!nl)
-                       break;
+       do {
+               size_t n = strcspn(s, "\n");
 
-               s = nl+1;
-       }
+               printf("%*s%.*s\n", n ? i-w : 0, "", (int)n, s);
+               s += n + (s[n] != '\0');
+               w = 0;
+       } while (*s);
 }