2 * Copyright © 2021-2023 Nick Bowler
4 * Helper functions for formatting --help program output.
6 * In order to support localized output, this depends on the Gnulib gettext-h
7 * and mbswidth modules. However, if ENABLE_NLS is not defined (or defined to
8 * 0) then these modules are not required.
10 * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
11 * This is free software: you are free to do what the fuck you want to.
12 * There is NO WARRANTY, to the extent permitted by law.
33 # include <mbswidth.h>
35 # define gettext(s) (s)
36 # define pgettext_expr(c, s) (s)
37 # define mbsnwidth(a, b, c) (assert(0), 0)
40 #define _(s) gettext(s)
42 /* Returns a single numeric value depending on the type of option:
44 * 6 - if the option has a short option character and an optional argument
45 * 5 - if the option has a short option character and a mandatory argument
46 * 4 - if the option has a short option charater and no argument
48 * 2 - if the option has no short option character and an optional argument
49 * 1 - if the option has no short option character and a mandatory argument
50 * 0 - if the option has no short option character and no argument
52 static int option_type(const struct option *opt)
54 int ret = opt->has_arg & 3;
57 ret |= (opt->val <= CHAR_MAX) << 2;
63 OPT_SHORT_WITH_OPTIONAL_ARG = 6,
64 OPT_SHORT_WITH_MANDATORY_ARG = 5,
65 OPT_SHORT_WITHOUT_ARG = 4,
66 OPT_LONG_WITH_OPTIONAL_ARG = 2,
67 OPT_LONG_WITH_MANDATORY_ARG = 1,
68 OPT_LONG_WITHOUT_ARG = 0,
72 * When NLS is enabled, we assume snprintf is available. The GNU libintl
73 * library should provide a suitable fallback if necessary.
75 #if ENABLE_NLS && !defined(help_do_snprintf)
76 #define help_do_snprintf snprintf
78 #define help_do_snprintf fake_snprintf
79 static inline int fake_snprintf(char *buf, size_t n, const char *fmt, ...)
85 int help_print_optstring(const struct option *opt, const char *argname, int l)
93 switch (option_type(opt)) {
94 #if HELP_GETOPT_LONG_ONLY
95 case OPT_SHORT_WITH_OPTIONAL_ARG:
96 case OPT_LONG_WITH_OPTIONAL_ARG:
97 w = help_do_snprintf(optstring, sizeof optstring,
98 _(" -%s [%s]"), opt->name,
99 pgettext_expr(opt->name, argname));
101 case OPT_SHORT_WITH_MANDATORY_ARG:
102 case OPT_LONG_WITH_MANDATORY_ARG:
103 w = help_do_snprintf(optstring, sizeof optstring,
104 _(" -%s %s"), opt->name,
105 pgettext_expr(opt->name, argname));
107 case OPT_SHORT_WITHOUT_ARG:
108 case OPT_LONG_WITHOUT_ARG:
109 w = help_do_snprintf(optstring, sizeof optstring,
110 _(" -%s"), opt->name);
113 case OPT_SHORT_WITH_OPTIONAL_ARG:
114 w = help_do_snprintf(optstring, sizeof optstring,
115 _(" -%c, --%s[=%s]"), opt->val, opt->name,
116 pgettext_expr(opt->name, argname));
118 case OPT_LONG_WITH_OPTIONAL_ARG:
119 w = help_do_snprintf(optstring, sizeof optstring,
120 _(" --%s[=%s]"), opt->name,
121 pgettext_expr(opt->name, argname));
123 case OPT_SHORT_WITH_MANDATORY_ARG:
124 w = help_do_snprintf(optstring, sizeof optstring,
125 _(" -%c, --%s=%s"), opt->val, opt->name,
126 pgettext_expr(opt->name, argname));
128 case OPT_LONG_WITH_MANDATORY_ARG:
129 w = help_do_snprintf(optstring, sizeof optstring,
130 _(" --%s=%s"), opt->name,
131 pgettext_expr(opt->name, argname));
133 case OPT_SHORT_WITHOUT_ARG:
134 w = help_do_snprintf(optstring, sizeof optstring,
135 _(" -%c, --%s"), opt->val, opt->name);
137 case OPT_LONG_WITHOUT_ARG:
138 w = help_do_snprintf(optstring, sizeof optstring,
139 _(" --%s"), opt->name);
146 if (w < 0 || w >= sizeof optstring)
149 w = mbsnwidth(optstring, w, 0);
150 printf("%s", optstring);
154 switch (option_type(opt)) {
155 #if HELP_GETOPT_LONG_ONLY
156 case OPT_SHORT_WITH_OPTIONAL_ARG:
157 case OPT_LONG_WITH_OPTIONAL_ARG:
158 w = printf(" -%s [%s]", opt->name, argname);
160 case OPT_SHORT_WITH_MANDATORY_ARG:
161 case OPT_LONG_WITH_MANDATORY_ARG:
162 w = printf(" -%s %s", opt->name, argname);
164 case OPT_SHORT_WITHOUT_ARG:
165 case OPT_LONG_WITHOUT_ARG:
166 w = printf(" -%s", opt->name);
169 case OPT_SHORT_WITH_OPTIONAL_ARG:
170 w = printf(" -%c, --%s[=%s]", opt->val, opt->name, argname);
172 case OPT_LONG_WITH_OPTIONAL_ARG:
173 w = printf(" --%s[=%s]", opt->name, argname);
175 case OPT_SHORT_WITH_MANDATORY_ARG:
176 w = printf(" -%c, --%s=%s", opt->val, opt->name, argname);
178 case OPT_LONG_WITH_MANDATORY_ARG:
179 w = printf(" --%s=%s", opt->name, argname);
181 case OPT_SHORT_WITHOUT_ARG:
182 w = printf(" -%c, --%s", opt->val, opt->name);
184 case OPT_LONG_WITHOUT_ARG:
185 w = printf(" --%s", opt->name);
192 if (w < 0 || w > l) {
200 void help_print_desc(const struct option *opt, const char *s, int i, int w)
203 s = pgettext_expr(opt->name, s);
205 if (i && s[0] == '\0')
209 const char *nl = strchr(s, '\n');
210 int n = (nl ? nl-s : -1);
212 printf("%*s%.*s\n", i-w, "", n, s);