[PATCH v3 6/6] posix: let the getopt caller choose the textdomain for translation
Vivien Kraus
vivien@planete-kraus.eu
Sat May 31 21:14:49 GMT 2025
Using the same solution as for the option translation context, a new
opttextdomain variable is defined.
---
manual/argp.texi | 7 +++++--
manual/getopt.texi | 11 +++++++++--
posix/Versions | 2 +-
posix/bits/getopt_core.h | 5 +++++
posix/getopt.c | 28 ++++++++++++++++++++--------
posix/getopt_int.h | 1 +
posix/tstgetoptl.c | 9 +++------
7 files changed, 44 insertions(+), 19 deletions(-)
diff --git a/manual/argp.texi b/manual/argp.texi
index 97456ef20e..50d67b6c55 100644
--- a/manual/argp.texi
+++ b/manual/argp.texi
@@ -208,8 +208,11 @@ messages. @xref{Argp Help Filtering}.
If non-zero, the strings used in the argp library are translated using
the domain described by this string. If zero, the current default
domain is used. The long option names are always translated with the
-current default domain, and with the @samp{"command-line option"}
-disambiguation string.
+current default domain (not this one), and with the
+@samp{"command-line option"} disambiguation string. This is because
+all the option names, including those defined in sub-parsers, must be
+in the same textdomain for @command{getopt} to process the options
+correctly.
@end table
@end deftp
diff --git a/manual/getopt.texi b/manual/getopt.texi
index 3eb44849f0..af2c65347b 100644
--- a/manual/getopt.texi
+++ b/manual/getopt.texi
@@ -59,8 +59,15 @@ names in the current textdomain. Since option names may be short words
instead of long sentences, they may have different translations in
other places of the program. @xref{Contexts, , Using contexts for
solving ambiguities, gettext, the GNU Gettext manual}, for more
-information. If this is @code{NULL}, then the translations will be
-retrieved without a context.
+information. If this is @code{NULL} (the default), then the
+translations will be retrieved without a context.
+@end deftypevar
+
+@deftypevar {const char *} opttextdomain
+Option names may be translated in a textdomain that is not currently
+the default (@pxref{Interface to gettext, , The Interface, gettext,
+the GNU Gettext manual}). If this is @code{NULL} (the default), the
+translation will be searched in the current text domain.
@end deftypevar
@deftypefun int getopt (int @var{argc}, char *const *@var{argv}, const char *@var{options})
diff --git a/posix/Versions b/posix/Versions
index 3ef3609711..0fe3d103f3 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -18,7 +18,7 @@ libc {
__environ; _environ;
# variables in normal name space
- environ; optarg; opterr; optind; optopt; optctxt;
+ environ; optarg; opterr; optind; optopt; optctxt; opttextdomain;
re_max_failures; re_syntax_options;
# a*
diff --git a/posix/bits/getopt_core.h b/posix/bits/getopt_core.h
index 32bf787491..6d651d099a 100644
--- a/posix/bits/getopt_core.h
+++ b/posix/bits/getopt_core.h
@@ -64,6 +64,11 @@ extern int optopt;
extern const char *optctxt;
+/* Callers store the textdomain to use to retrieve option names, or
+ NULL to use the current textdomain. */
+
+extern const char *opttextdomain;
+
/* Get definitions and prototypes for functions to process the
arguments in ARGV (ARGC of them, minus the program name) for
options given in OPTS.
diff --git a/posix/getopt.c b/posix/getopt.c
index 2033c34bb7..9323a8af68 100644
--- a/posix/getopt.c
+++ b/posix/getopt.c
@@ -118,6 +118,11 @@ int optopt = '?';
const char *optctxt = NULL;
+/* Callers store the textdomain in which the option names are to be
+ looked up. */
+
+const char *opttextdomain = NULL;
+
/* Keep a global copy of all internal members of getopt_data. */
static struct _getopt_data getopt_data;
@@ -188,7 +193,8 @@ exchange (char **argv, struct _getopt_data *d)
/* FIXME: use pgettext_expr when available. */
static const char *
-translate_option_name (const char *context, const char *long_option_name)
+translate_option_name (const char *context, const char *textdomain,
+ const char *long_option_name)
{
char *msgid;
const char *translated = long_option_name;
@@ -201,7 +207,7 @@ translate_option_name (const char *context, const char *long_option_name)
strcpy (msgid, context);
msgid[strlen (context)] = '\004';
strcpy (msgid + strlen (context) + 1, long_option_name);
- translated = gettext (msgid);
+ translated = dgettext (textdomain, msgid);
if (!strcmp (translated, msgid))
{
translated = long_option_name;
@@ -210,12 +216,13 @@ translate_option_name (const char *context, const char *long_option_name)
free (msgid);
}
else
- translated = gettext (long_option_name);
+ translated = dgettext (textdomain, long_option_name);
return translated;
}
-/* Return 1 iff a translation for opt_name has been found and it
- matches the substring from argument, length argument_length.
+/* Return 1 iff a translation for opt_name in opt_textdomain has been
+ found and it matches the substring from argument, length
+ argument_length.
The translation is disambiguated iff translation_context is not
NULL.
@@ -223,9 +230,11 @@ translate_option_name (const char *context, const char *long_option_name)
static const int
match_translated_option_name (const char *argument, size_t argument_length,
const char *translation_context,
+ const char *opt_textdomain,
const char *opt_name)
{
- const char *translated = translate_option_name (translation_context, opt_name);
+ const char *translated =
+ translate_option_name (translation_context, opt_textdomain, opt_name);
return (!strncmp (translated, argument, argument_length)
&& argument_length == strlen (translated));
}
@@ -274,7 +283,8 @@ process_long_option (int argc, char **argv, const char *optstring,
names. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (match_translated_option_name (d->__nextchar, namelen,
- d->optctxt, p->name))
+ d->optctxt, d->opttextdomain,
+ p->name))
{
/* Exact match found with translation. */
pfound = p;
@@ -398,7 +408,8 @@ process_long_option (int argc, char **argv, const char *optstring,
/* We have found a matching long option. Consume it. */
d->optind++;
d->__nextchar = NULL;
- translated_option_name = translate_option_name (d->optctxt, pfound->name);
+ translated_option_name =
+ translate_option_name (d->optctxt, d->opttextdomain, pfound->name);
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
@@ -802,6 +813,7 @@ _getopt_internal (int argc, char **argv, const char *optstring,
getopt_data.optind = optind;
getopt_data.opterr = opterr;
getopt_data.optctxt = optctxt;
+ getopt_data.opttextdomain = opttextdomain;
result = _getopt_internal_r (argc, argv, optstring, longopts,
longind, long_only, &getopt_data,
diff --git a/posix/getopt_int.h b/posix/getopt_int.h
index 5c10d7b99e..e93f8921d9 100644
--- a/posix/getopt_int.h
+++ b/posix/getopt_int.h
@@ -68,6 +68,7 @@ struct _getopt_data
int optopt;
char *optarg;
const char *optctxt;
+ const char *opttextdomain;
/* Internal members. */
diff --git a/posix/tstgetoptl.c b/posix/tstgetoptl.c
index bffd56f47d..3580358a67 100644
--- a/posix/tstgetoptl.c
+++ b/posix/tstgetoptl.c
@@ -27,13 +27,8 @@ prepare_localedir (void)
fputs ("Cannot call bindtextdomain.\n", stderr);
return -1;
}
- if (textdomain ("tstgetoptl") == NULL)
- {
- fputs ("Cannot call textdomain.\n", stderr);
- return -1;
- }
/* Check that the catalog is OK: */
- if (strcmp (gettext (TRANSLATION_CONTEXT "\004" "color"), "colour") != 0)
+ if (strcmp (dgettext ("tstgetoptl", TRANSLATION_CONTEXT "\004" "color"), "colour") != 0)
{
fputs ("The mo file does not work.\n", stderr);
return -1;
@@ -45,6 +40,7 @@ int
main (int argc, char **argv)
{
static const char *translation_context = TRANSLATION_CONTEXT;
+ static const char *translation_textdomain = "tstgetoptl";
static const struct option options[] =
{
{"required", required_argument, NULL, 'r'},
@@ -72,6 +68,7 @@ main (int argc, char **argv)
return 1;
}
optctxt = translation_context;
+ opttextdomain = translation_textdomain;
while ((c = getopt_long (argc, argv, "abc:", options, NULL)) >= 0)
switch (c)
{
--
2.49.0
More information about the Libc-alpha
mailing list