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,
71 int help_print_optstring(const struct option *opt, const char *argname, int l)
79 switch (option_type(opt)) {
80 #if HELP_GETOPT_LONG_ONLY
81 case OPT_SHORT_WITH_OPTIONAL_ARG:
82 case OPT_LONG_WITH_OPTIONAL_ARG:
83 w = snprintf(optstring, sizeof optstring,
84 _(" -%s [%s]"), opt->name,
85 pgettext_expr(opt->name, argname));
87 case OPT_SHORT_WITH_MANDATORY_ARG:
88 case OPT_LONG_WITH_MANDATORY_ARG:
89 w = snprintf(optstring, sizeof optstring,
90 _(" -%s %s"), opt->name,
91 pgettext_expr(opt->name, argname));
93 case OPT_SHORT_WITHOUT_ARG:
94 case OPT_LONG_WITHOUT_ARG:
95 w = snprintf(optstring, sizeof optstring,
96 _(" -%s"), opt->name);
99 case OPT_SHORT_WITH_OPTIONAL_ARG:
100 w = snprintf(optstring, sizeof optstring,
101 _(" -%c, --%s[=%s]"), opt->val, opt->name,
102 pgettext_expr(opt->name, argname));
104 case OPT_LONG_WITH_OPTIONAL_ARG:
105 w = snprintf(optstring, sizeof optstring,
106 _(" --%s[=%s]"), opt->name,
107 pgettext_expr(opt->name, argname));
109 case OPT_SHORT_WITH_MANDATORY_ARG:
110 w = snprintf(optstring, sizeof optstring,
111 _(" -%c, --%s=%s"), opt->val, opt->name,
112 pgettext_expr(opt->name, argname));
114 case OPT_LONG_WITH_MANDATORY_ARG:
115 w = snprintf(optstring, sizeof optstring,
116 _(" --%s=%s"), opt->name,
117 pgettext_expr(opt->name, argname));
119 case OPT_SHORT_WITHOUT_ARG:
120 w = snprintf(optstring, sizeof optstring,
121 _(" -%c, --%s"), opt->val, opt->name);
123 case OPT_LONG_WITHOUT_ARG:
124 w = snprintf(optstring, sizeof optstring,
125 _(" --%s"), opt->name);
135 w = mbsnwidth(optstring, w, 0);
136 printf("%s", optstring);
140 switch (option_type(opt)) {
141 #if HELP_GETOPT_LONG_ONLY
142 case OPT_SHORT_WITH_OPTIONAL_ARG:
143 case OPT_LONG_WITH_OPTIONAL_ARG:
144 w = printf(" -%s [%s]", opt->name, argname);
146 case OPT_SHORT_WITH_MANDATORY_ARG:
147 case OPT_LONG_WITH_MANDATORY_ARG:
148 w = printf(" -%s %s", opt->name, argname);
150 case OPT_SHORT_WITHOUT_ARG:
151 case OPT_LONG_WITHOUT_ARG:
152 w = printf(" -%s", opt->name);
155 case OPT_SHORT_WITH_OPTIONAL_ARG:
156 w = printf(" -%c, --%s[=%s]", opt->val, opt->name, argname);
158 case OPT_LONG_WITH_OPTIONAL_ARG:
159 w = printf(" --%s[=%s]", opt->name, argname);
161 case OPT_SHORT_WITH_MANDATORY_ARG:
162 w = printf(" -%c, --%s=%s", opt->val, opt->name, argname);
164 case OPT_LONG_WITH_MANDATORY_ARG:
165 w = printf(" --%s=%s", opt->name, argname);
167 case OPT_SHORT_WITHOUT_ARG:
168 w = printf(" -%c, --%s", opt->val, opt->name);
170 case OPT_LONG_WITHOUT_ARG:
171 w = printf(" --%s", opt->name);
178 if (w < 0 || w > l) {
186 void help_print_desc(const struct option *opt, const char *s, int i, int w)
189 s = pgettext_expr(opt->name, s);
191 if (i && s[0] == '\0')
195 const char *nl = strchr(s, '\n');
196 int n = (nl ? nl-s : -1);
198 printf("%*s%.*s\n", i-w, "", n, s);