2 * Copyright © 2021 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 return ((opt->val <= CHAR_MAX) << 2) | (opt->has_arg & 3);
58 OPT_SHORT_WITH_OPTIONAL_ARG = 6,
59 OPT_SHORT_WITH_MANDATORY_ARG = 5,
60 OPT_SHORT_WITHOUT_ARG = 4,
61 OPT_LONG_WITH_OPTIONAL_ARG = 2,
62 OPT_LONG_WITH_MANDATORY_ARG = 1,
63 OPT_LONG_WITHOUT_ARG = 0,
66 int help_print_optstring(const struct option *opt, const char *argname, int l)
74 switch (option_type(opt)) {
75 #if HELP_GETOPT_LONG_ONLY
76 case OPT_SHORT_WITH_OPTIONAL_ARG:
77 case OPT_LONG_WITH_OPTIONAL_ARG:
78 w = snprintf(optstring, sizeof optstring,
79 _(" -%s [%s]"), opt->name,
80 pgettext_expr(opt->name, argname));
82 case OPT_SHORT_WITH_MANDATORY_ARG:
83 case OPT_LONG_WITH_MANDATORY_ARG:
84 w = snprintf(optstring, sizeof optstring,
85 _(" -%s %s"), opt->name,
86 pgettext_expr(opt->name, argname));
88 case OPT_SHORT_WITHOUT_ARG:
89 case OPT_LONG_WITHOUT_ARG:
90 w = snprintf(optstring, sizeof optstring,
91 _(" -%s"), opt->name);
94 case OPT_SHORT_WITH_OPTIONAL_ARG:
95 w = snprintf(optstring, sizeof optstring,
96 _(" -%c, --%s[=%s]"), opt->val, opt->name,
97 pgettext_expr(opt->name, argname));
99 case OPT_LONG_WITH_OPTIONAL_ARG:
100 w = snprintf(optstring, sizeof optstring,
101 _(" --%s[=%s]"), opt->name,
102 pgettext_expr(opt->name, argname));
104 case OPT_SHORT_WITH_MANDATORY_ARG:
105 w = snprintf(optstring, sizeof optstring,
106 _(" -%c, --%s=%s"), opt->val, opt->name,
107 pgettext_expr(opt->name, argname));
109 case OPT_LONG_WITH_MANDATORY_ARG:
110 w = snprintf(optstring, sizeof optstring,
111 _(" --%s=%s"), opt->name,
112 pgettext_expr(opt->name, argname));
114 case OPT_SHORT_WITHOUT_ARG:
115 w = snprintf(optstring, sizeof optstring,
116 _(" -%c, --%s"), opt->val, opt->name);
118 case OPT_LONG_WITHOUT_ARG:
119 w = snprintf(optstring, sizeof optstring,
120 _(" --%s"), opt->name);
130 w = mbsnwidth(optstring, w, 0);
131 printf("%s", optstring);
135 switch (option_type(opt)) {
136 #if HELP_GETOPT_LONG_ONLY
137 case OPT_SHORT_WITH_OPTIONAL_ARG:
138 case OPT_LONG_WITH_OPTIONAL_ARG:
139 w = printf(" -%s [%s]", opt->name, argname);
141 case OPT_SHORT_WITH_MANDATORY_ARG:
142 case OPT_LONG_WITH_MANDATORY_ARG:
143 w = printf(" -%s %s", opt->name, argname);
145 case OPT_SHORT_WITHOUT_ARG:
146 case OPT_LONG_WITHOUT_ARG:
147 w = printf(" -%s", opt->name);
150 case OPT_SHORT_WITH_OPTIONAL_ARG:
151 w = printf(" -%c, --%s[=%s]", opt->val, opt->name, argname);
153 case OPT_LONG_WITH_OPTIONAL_ARG:
154 w = printf(" --%s[=%s]", opt->name, argname);
156 case OPT_SHORT_WITH_MANDATORY_ARG:
157 w = printf(" -%c, --%s=%s", opt->val, opt->name, argname);
159 case OPT_LONG_WITH_MANDATORY_ARG:
160 w = printf(" --%s=%s", opt->name, argname);
162 case OPT_SHORT_WITHOUT_ARG:
163 w = printf(" -%c, --%s", opt->val, opt->name);
165 case OPT_LONG_WITHOUT_ARG:
166 w = printf(" --%s", opt->name);
173 if (w < 0 || w > l) {
181 void help_print_desc(const struct option *opt, const char *s, int i, int w)
184 s = pgettext_expr(opt->name, s);
187 const char *nl = strchr(s, '\n');
188 int n = (nl ? nl-s : -1);
190 printf("%*s%.*s\n", i-w, "", n, s);