1 commit 6cd59e232112243bca08c588185ce3d397e89fd3
2 Author: Colin Watson <cjwatson@debian.org>
3 Date: Mon May 28 17:41:05 2018 +0100
5 Fix domain handling in argp
7 man-db sets its default text domain to "man-db", and keeps all Gnulib's
8 strings in a separate "man-db-gnulib" domain, using 'gnulib-tool
9 --po-domain=man-db' which results in
10 -DDEFAULT_TEXT_DOMAIN=\"man-db-gnulib\". (I checked this general
11 approach with Bruno a while back and he said it was fine.)
13 However, Gnulib's argp implementation has three bugs which cause this
16 * It hardcodes "libc" as a domain in two places. This is obviously
19 * It uses argp_domain as both the domain used to translate its own
20 strings (i.e. string literals in lib/argp-*.c) and the domain used
21 to translate strings provided by the user, which normally have to
22 use gettext_noop so that they can be used as 'struct argp_option'
23 initialisers. This is dreadfully inconvenient because you have to
24 copy strings about all over the place and keep your POT file up to
25 date as the argp implementation changes. If argp is in libc then
26 this is obviously impossible.
28 Instead, argp should use DEFAULT_TEXT_DOMAIN to translate its own
29 string literals (falling back to the default program domain if that
30 is not set), and should reserve argp_domain for translating strings
31 that appear in that argp structure.
33 * In a number of places, argp uses the domain of the root argp
34 structure when translating text from a child argp structure. This is
35 the direct cause of Robert's bug, because the standard --help and
36 --version options are implemented as a child argp structure with its
39 My patch changes this to use argp_domain from the child instead.
40 However, on reflection, I'm not certain that this is correct;
41 arguably it needs to walk up the tree until it finds a domain to
42 use. This depends on whether you think that argp_domain == NULL
43 means "use default program domain" or "use same domain as parent
46 https://lists.gnu.org/r/bug-gnulib/2008-03/msg00144.html
48 diff --git a/gl/lib/argp-help.c b/gl/lib/argp-help.c
49 index de98f2143..09a716e69 100644
50 --- a/gl/lib/argp-help.c
51 +++ b/gl/lib/argp-help.c
57 +# define ARGP_TEXT_DOMAIN "libc"
59 +# ifdef DEFAULT_TEXT_DOMAIN
60 +# define ARGP_TEXT_DOMAIN DEFAULT_TEXT_DOMAIN
62 +# define ARGP_TEXT_DOMAIN NULL
67 #include "argp-fmtstream.h"
68 #include "argp-namefrob.h"
69 @@ -144,7 +154,7 @@ validate_uparams (const struct argp_state *state, struct uparams *upptr)
70 if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin)
72 __argp_failure (state, 0, 0,
73 - dgettext (state->root_argp->argp_domain,
74 + dgettext (ARGP_TEXT_DOMAIN,
76 ARGP_HELP_FMT: %s value is less than or equal to %s"),
78 @@ -220,7 +230,7 @@ fill_in_uparams (const struct argp_state *state)
79 if (unspec && !un->is_bool)
80 __argp_failure (state, 0, 0,
81 dgettext (state == NULL ? NULL
82 - : state->root_argp->argp_domain,
85 %.*s: ARGP_HELP_FMT parameter requires a value"),
87 @@ -231,7 +241,7 @@ fill_in_uparams (const struct argp_state *state)
88 if (un == uparam_names + nuparam_names)
89 __argp_failure (state, 0, 0,
90 dgettext (state == NULL ? NULL
91 - : state->root_argp->argp_domain, "\
92 + : ARGP_TEXT_DOMAIN, "\
93 %.*s: Unknown ARGP_HELP_FMT parameter"),
96 @@ -243,7 +253,7 @@ fill_in_uparams (const struct argp_state *state)
98 __argp_failure (state, 0, 0,
99 dgettext (state == NULL ? NULL
100 - : state->root_argp->argp_domain,
101 + : ARGP_TEXT_DOMAIN,
102 "Garbage in ARGP_HELP_FMT: %s"), var);
105 @@ -1120,7 +1130,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
106 __argp_fmtstream_putc (stream, *so);
107 if (!have_long_opt || uparams.dup_args)
108 arg (real, " %s", "[%s]",
109 - state == NULL ? NULL : state->root_argp->argp_domain,
110 + state == NULL ? NULL : entry->argp->argp_domain,
113 hhstate->suppressed_dup_arg = 1;
114 @@ -1142,7 +1152,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
115 should be pretty rare anyway... */
116 __argp_fmtstream_puts (stream,
117 dgettext (state == NULL ? NULL
118 - : state->root_argp->argp_domain,
119 + : entry->argp->argp_domain,
123 @@ -1156,7 +1166,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
124 comma (uparams.long_opt_col, &pest);
125 __argp_fmtstream_printf (stream, "--%s", opt->name);
126 arg (real, "=%s", "[=%s]",
127 - state == NULL ? NULL : state->root_argp->argp_domain, stream);
128 + state == NULL ? NULL : entry->argp->argp_domain, stream);
132 @@ -1176,7 +1186,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
135 const char *tstr = real->doc ? dgettext (state == NULL ? NULL
136 - : state->root_argp->argp_domain,
137 + : entry->argp->argp_domain,
139 const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
141 @@ -1225,7 +1235,7 @@ hol_help (struct hol *hol, const struct argp_state *state,
142 if (hhstate.suppressed_dup_arg && uparams.dup_args_note)
144 const char *tstr = dgettext (state == NULL ? NULL
145 - : state->root_argp->argp_domain, "\
146 + : ARGP_TEXT_DOMAIN, "\
147 Mandatory or optional arguments to long options are also mandatory or \
148 optional for any corresponding short options.");
149 const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE,
150 @@ -1612,11 +1622,11 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
153 __argp_fmtstream_printf (fs, "%s %s",
154 - dgettext (argp->argp_domain, "Usage:"),
155 + dgettext (ARGP_TEXT_DOMAIN, "Usage:"),
158 __argp_fmtstream_printf (fs, "%s %s",
159 - dgettext (argp->argp_domain, " or: "),
160 + dgettext (ARGP_TEXT_DOMAIN, " or: "),
163 /* We set the lmargin as well as the wmargin, because hol_usage
164 @@ -1627,7 +1637,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
165 /* Just show where the options go. */
167 if (hol->num_entries > 0)
168 - __argp_fmtstream_puts (fs, dgettext (argp->argp_domain,
169 + __argp_fmtstream_puts (fs, dgettext (ARGP_TEXT_DOMAIN,
173 @@ -1655,7 +1665,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
175 if (flags & ARGP_HELP_SEE)
177 - __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\
178 + __argp_fmtstream_printf (fs, dgettext (ARGP_TEXT_DOMAIN, "\
179 Try '%s --help' or '%s --usage' for more information.\n"),
182 @@ -1682,7 +1692,7 @@ Try '%s --help' or '%s --usage' for more information.\n"),
185 __argp_fmtstream_putc (fs, '\n');
186 - __argp_fmtstream_printf (fs, dgettext (argp->argp_domain,
187 + __argp_fmtstream_printf (fs, dgettext (ARGP_TEXT_DOMAIN,
188 "Report bugs to %s.\n"),
189 argp_program_bug_address);
191 @@ -1883,8 +1893,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
194 if (! s && ! (s = strerror (errnum)))
195 - s = dgettext (state->root_argp->argp_domain,
196 - "Unknown system error");
197 + s = dgettext (ARGP_TEXT_DOMAIN, "Unknown system error");
198 fputs_unlocked (s, stream);
201 diff --git a/gl/lib/argp-parse.c b/gl/lib/argp-parse.c
202 index ae55e9e19..3f8b0ba69 100644
203 --- a/gl/lib/argp-parse.c
204 +++ b/gl/lib/argp-parse.c
207 #define N_(msgid) msgid
210 +# define ARGP_TEXT_DOMAIN "libc"
212 +# ifdef DEFAULT_TEXT_DOMAIN
213 +# define ARGP_TEXT_DOMAIN DEFAULT_TEXT_DOMAIN
215 +# define ARGP_TEXT_DOMAIN NULL
220 #include "argp-namefrob.h"
222 @@ -135,7 +145,8 @@ argp_default_parser (int key, char *arg, struct argp_state *state)
225 static const struct argp argp_default_argp =
226 - {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL, "libc"};
227 + {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL,
231 static const struct argp_option argp_version_options[] =
232 @@ -156,7 +167,7 @@ argp_version_parser (int key, char *arg, struct argp_state *state)
233 fprintf (state->out_stream, "%s\n", argp_program_version);
235 __argp_error (state, "%s",
236 - dgettext (state->root_argp->argp_domain,
237 + dgettext (ARGP_TEXT_DOMAIN,
238 "(PROGRAM ERROR) No version known!?"));
239 if (! (state->flags & ARGP_NO_EXIT))
241 @@ -168,7 +179,8 @@ argp_version_parser (int key, char *arg, struct argp_state *state)
244 static const struct argp argp_version_argp =
245 - {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"};
246 + {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL,
249 /* Returns the offset into the getopt long options array LONG_OPTIONS of a
250 long option with called NAME, or -1 if none is found. Passing NULL as
251 @@ -609,8 +621,7 @@ parser_finalize (struct parser *parser,
252 if (!(parser->state.flags & ARGP_NO_ERRS)
253 && parser->state.err_stream)
254 fprintf (parser->state.err_stream,
255 - dgettext (parser->argp->argp_domain,
256 - "%s: Too many arguments\n"),
257 + dgettext (ARGP_TEXT_DOMAIN, "%s: Too many arguments\n"),
261 @@ -759,7 +770,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
262 N_("(PROGRAM ERROR) Option should have been recognized!?");
264 __argp_error (&parser->state, "-%c: %s", opt,
265 - dgettext (parser->argp->argp_domain, bad_key_err));
266 + dgettext (ARGP_TEXT_DOMAIN, bad_key_err));
269 struct option *long_opt = parser->long_opts;
270 @@ -767,7 +778,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
272 __argp_error (&parser->state, "--%s: %s",
273 long_opt->name ? long_opt->name : "???",
274 - dgettext (parser->argp->argp_domain, bad_key_err));
275 + dgettext (ARGP_TEXT_DOMAIN, bad_key_err));