278 lines
12 KiB
Diff
278 lines
12 KiB
Diff
commit cc9028a3c3fa4dea795d475808c6c758c9b21be2
|
||
Author: Colin Watson <cjwatson@debian.org>
|
||
Date: Mon May 28 17:41:05 2018 +0100
|
||
|
||
Fix domain handling in argp
|
||
|
||
man-db sets its default text domain to "man-db", and keeps all Gnulib's
|
||
strings in a separate "man-db-gnulib" domain, using 'gnulib-tool
|
||
--po-domain=man-db' which results in
|
||
-DDEFAULT_TEXT_DOMAIN=\"man-db-gnulib\". (I checked this general
|
||
approach with Bruno a while back and he said it was fine.)
|
||
|
||
However, Gnulib's argp implementation has three bugs which cause this
|
||
not to work properly:
|
||
|
||
* It hardcodes "libc" as a domain in two places. This is obviously
|
||
wrong in Gnulib.
|
||
|
||
* It uses argp_domain as both the domain used to translate its own
|
||
strings (i.e. string literals in lib/argp-*.c) and the domain used
|
||
to translate strings provided by the user, which normally have to
|
||
use gettext_noop so that they can be used as 'struct argp_option'
|
||
initialisers. This is dreadfully inconvenient because you have to
|
||
copy strings about all over the place and keep your POT file up to
|
||
date as the argp implementation changes. If argp is in libc then
|
||
this is obviously impossible.
|
||
|
||
Instead, argp should use DEFAULT_TEXT_DOMAIN to translate its own
|
||
string literals (falling back to the default program domain if that
|
||
is not set), and should reserve argp_domain for translating strings
|
||
that appear in that argp structure.
|
||
|
||
* In a number of places, argp uses the domain of the root argp
|
||
structure when translating text from a child argp structure. This is
|
||
the direct cause of Robert's bug, because the standard --help and
|
||
--version options are implemented as a child argp structure with its
|
||
own domain.
|
||
|
||
My patch changes this to use argp_domain from the child instead.
|
||
However, on reflection, I'm not certain that this is correct;
|
||
arguably it needs to walk up the tree until it finds a domain to
|
||
use. This depends on whether you think that argp_domain == NULL
|
||
means "use default program domain" or "use same domain as parent
|
||
argp structure".
|
||
|
||
https://lists.gnu.org/r/bug-gnulib/2008-03/msg00144.html
|
||
|
||
diff --git a/gl/lib/argp-help.c b/gl/lib/argp-help.c
|
||
index 9c7456642c..aa8cc701d2 100644
|
||
--- a/gl/lib/argp-help.c
|
||
+++ b/gl/lib/argp-help.c
|
||
@@ -48,6 +48,16 @@
|
||
# include "gettext.h"
|
||
#endif
|
||
|
||
+#ifdef _LIBC
|
||
+# define ARGP_TEXT_DOMAIN "libc"
|
||
+#else
|
||
+# ifdef DEFAULT_TEXT_DOMAIN
|
||
+# define ARGP_TEXT_DOMAIN DEFAULT_TEXT_DOMAIN
|
||
+# else
|
||
+# define ARGP_TEXT_DOMAIN NULL
|
||
+# endif
|
||
+#endif
|
||
+
|
||
#include "argp.h"
|
||
#include "argp-fmtstream.h"
|
||
#include "argp-namefrob.h"
|
||
@@ -147,7 +157,7 @@ validate_uparams (const struct argp_state *state, struct uparams *upptr)
|
||
{
|
||
__argp_failure (state, 0, 0,
|
||
dgettext (state == NULL ? NULL
|
||
- : state->root_argp->argp_domain,
|
||
+ : ARGP_TEXT_DOMAIN,
|
||
"\
|
||
ARGP_HELP_FMT: %s value is less than or equal to %s"),
|
||
"rmargin", up->name);
|
||
@@ -223,7 +233,7 @@ fill_in_uparams (const struct argp_state *state)
|
||
if (unspec && !un->is_bool)
|
||
__argp_failure (state, 0, 0,
|
||
dgettext (state == NULL ? NULL
|
||
- : state->root_argp->argp_domain,
|
||
+ : ARGP_TEXT_DOMAIN,
|
||
"\
|
||
%.*s: ARGP_HELP_FMT parameter requires a value"),
|
||
(int) var_len, var);
|
||
@@ -234,7 +244,7 @@ fill_in_uparams (const struct argp_state *state)
|
||
if (un == uparam_names + nuparam_names)
|
||
__argp_failure (state, 0, 0,
|
||
dgettext (state == NULL ? NULL
|
||
- : state->root_argp->argp_domain, "\
|
||
+ : ARGP_TEXT_DOMAIN, "\
|
||
%.*s: Unknown ARGP_HELP_FMT parameter"),
|
||
(int) var_len, var);
|
||
|
||
@@ -246,7 +256,7 @@ fill_in_uparams (const struct argp_state *state)
|
||
{
|
||
__argp_failure (state, 0, 0,
|
||
dgettext (state == NULL ? NULL
|
||
- : state->root_argp->argp_domain,
|
||
+ : ARGP_TEXT_DOMAIN,
|
||
"Garbage in ARGP_HELP_FMT: %s"), var);
|
||
break;
|
||
}
|
||
@@ -1260,7 +1270,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
|
||
__argp_fmtstream_putc (stream, *so);
|
||
if (!have_long_opt || uparams.dup_args)
|
||
arg (real, " %s", "[%s]",
|
||
- state == NULL ? NULL : state->root_argp->argp_domain,
|
||
+ state == NULL ? NULL : entry->argp->argp_domain,
|
||
stream);
|
||
else if (real->arg)
|
||
hhstate->suppressed_dup_arg = 1;
|
||
@@ -1282,7 +1292,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
|
||
should be pretty rare anyway... */
|
||
__argp_fmtstream_puts (stream,
|
||
dgettext (state == NULL ? NULL
|
||
- : state->root_argp->argp_domain,
|
||
+ : entry->argp->argp_domain,
|
||
opt->name));
|
||
}
|
||
}
|
||
@@ -1296,7 +1306,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
|
||
comma (uparams.long_opt_col, &pest);
|
||
__argp_fmtstream_printf (stream, "--%s", opt->name);
|
||
arg (real, "=%s", "[=%s]",
|
||
- state == NULL ? NULL : state->root_argp->argp_domain, stream);
|
||
+ state == NULL ? NULL : entry->argp->argp_domain, stream);
|
||
}
|
||
}
|
||
|
||
@@ -1316,7 +1326,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
|
||
else
|
||
{
|
||
const char *tstr = real->doc ? dgettext (state == NULL ? NULL
|
||
- : state->root_argp->argp_domain,
|
||
+ : entry->argp->argp_domain,
|
||
real->doc) : NULL;
|
||
const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
|
||
if (fstr && *fstr)
|
||
@@ -1365,7 +1375,7 @@ hol_help (struct hol *hol, const struct argp_state *state,
|
||
if (hhstate.suppressed_dup_arg && uparams.dup_args_note)
|
||
{
|
||
const char *tstr = dgettext (state == NULL ? NULL
|
||
- : state->root_argp->argp_domain, "\
|
||
+ : ARGP_TEXT_DOMAIN, "\
|
||
Mandatory or optional arguments to long options are also mandatory or \
|
||
optional for any corresponding short options.");
|
||
const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE,
|
||
@@ -1731,11 +1741,11 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
|
||
|
||
if (first_pattern)
|
||
__argp_fmtstream_printf (fs, "%s %s",
|
||
- dgettext (argp->argp_domain, "Usage:"),
|
||
+ dgettext (ARGP_TEXT_DOMAIN, "Usage:"),
|
||
name);
|
||
else
|
||
__argp_fmtstream_printf (fs, "%s %s",
|
||
- dgettext (argp->argp_domain, " or: "),
|
||
+ dgettext (ARGP_TEXT_DOMAIN, " or: "),
|
||
name);
|
||
|
||
/* We set the lmargin as well as the wmargin, because hol_usage
|
||
@@ -1746,7 +1756,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
|
||
/* Just show where the options go. */
|
||
{
|
||
if (hol->num_entries > 0)
|
||
- __argp_fmtstream_puts (fs, dgettext (argp->argp_domain,
|
||
+ __argp_fmtstream_puts (fs, dgettext (ARGP_TEXT_DOMAIN,
|
||
" [OPTION...]"));
|
||
}
|
||
else
|
||
@@ -1774,7 +1784,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
|
||
|
||
if (flags & ARGP_HELP_SEE)
|
||
{
|
||
- __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\
|
||
+ __argp_fmtstream_printf (fs, dgettext (ARGP_TEXT_DOMAIN, "\
|
||
Try '%s --help' or '%s --usage' for more information.\n"),
|
||
name, name);
|
||
anything = 1;
|
||
@@ -1801,7 +1811,7 @@ Try '%s --help' or '%s --usage' for more information.\n"),
|
||
{
|
||
if (anything)
|
||
__argp_fmtstream_putc (fs, '\n');
|
||
- __argp_fmtstream_printf (fs, dgettext (argp->argp_domain,
|
||
+ __argp_fmtstream_printf (fs, dgettext (ARGP_TEXT_DOMAIN,
|
||
"Report bugs to %s.\n"),
|
||
argp_program_bug_address);
|
||
anything = 1;
|
||
@@ -2002,8 +2012,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
|
||
# endif
|
||
# endif
|
||
if (! s && ! (s = strerror (errnum)))
|
||
- s = dgettext (state->root_argp->argp_domain,
|
||
- "Unknown system error");
|
||
+ s = dgettext (ARGP_TEXT_DOMAIN, "Unknown system error");
|
||
fputs_unlocked (s, stream);
|
||
#endif
|
||
}
|
||
diff --git a/gl/lib/argp-parse.c b/gl/lib/argp-parse.c
|
||
index 6293169da4..0d00e89814 100644
|
||
--- a/gl/lib/argp-parse.c
|
||
+++ b/gl/lib/argp-parse.c
|
||
@@ -39,6 +39,16 @@
|
||
#endif
|
||
#define N_(msgid) msgid
|
||
|
||
+#ifdef _LIBC
|
||
+# define ARGP_TEXT_DOMAIN "libc"
|
||
+#else
|
||
+# ifdef DEFAULT_TEXT_DOMAIN
|
||
+# define ARGP_TEXT_DOMAIN DEFAULT_TEXT_DOMAIN
|
||
+# else
|
||
+# define ARGP_TEXT_DOMAIN NULL
|
||
+# endif
|
||
+#endif
|
||
+
|
||
#include "argp.h"
|
||
#include "argp-namefrob.h"
|
||
|
||
@@ -134,7 +144,8 @@ argp_default_parser (int key, char *arg, struct argp_state *state)
|
||
}
|
||
|
||
static const struct argp argp_default_argp =
|
||
- {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL, "libc"};
|
||
+ {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL,
|
||
+ ARGP_TEXT_DOMAIN};
|
||
|
||
|
||
static const struct argp_option argp_version_options[] =
|
||
@@ -155,7 +166,7 @@ argp_version_parser (int key, char *arg, struct argp_state *state)
|
||
fprintf (state->out_stream, "%s\n", argp_program_version);
|
||
else
|
||
__argp_error (state, "%s",
|
||
- dgettext (state->root_argp->argp_domain,
|
||
+ dgettext (ARGP_TEXT_DOMAIN,
|
||
"(PROGRAM ERROR) No version known!?"));
|
||
if (! (state->flags & ARGP_NO_EXIT))
|
||
exit (0);
|
||
@@ -167,7 +178,8 @@ argp_version_parser (int key, char *arg, struct argp_state *state)
|
||
}
|
||
|
||
static const struct argp argp_version_argp =
|
||
- {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"};
|
||
+ {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL,
|
||
+ ARGP_TEXT_DOMAIN};
|
||
|
||
/* Returns the offset into the getopt long options array LONG_OPTIONS of a
|
||
long option with called NAME, or -1 if none is found. Passing NULL as
|
||
@@ -608,8 +620,7 @@ parser_finalize (struct parser *parser,
|
||
if (!(parser->state.flags & ARGP_NO_ERRS)
|
||
&& parser->state.err_stream)
|
||
fprintf (parser->state.err_stream,
|
||
- dgettext (parser->argp->argp_domain,
|
||
- "%s: Too many arguments\n"),
|
||
+ dgettext (ARGP_TEXT_DOMAIN, "%s: Too many arguments\n"),
|
||
parser->state.name);
|
||
err = EBADKEY;
|
||
}
|
||
@@ -758,7 +769,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
|
||
N_("(PROGRAM ERROR) Option should have been recognized!?");
|
||
if (group_key == 0)
|
||
__argp_error (&parser->state, "-%c: %s", opt,
|
||
- dgettext (parser->argp->argp_domain, bad_key_err));
|
||
+ dgettext (ARGP_TEXT_DOMAIN, bad_key_err));
|
||
else
|
||
{
|
||
struct option *long_opt = parser->long_opts;
|
||
@@ -766,7 +777,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
|
||
long_opt++;
|
||
__argp_error (&parser->state, "--%s: %s",
|
||
long_opt->name ? long_opt->name : "???",
|
||
- dgettext (parser->argp->argp_domain, bad_key_err));
|
||
+ dgettext (ARGP_TEXT_DOMAIN, bad_key_err));
|
||
}
|
||
}
|
||
|