[PATCH v2 6/7] posix: let the getopt caller choose the textdomain for translation

Vivien Kraus vivien@planete-kraus.eu
Thu May 29 17:28:01 GMT 2025


Using the same solution as for the option translation context, a new
opttextdomain variable is defined.
---
 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 +++------
 6 files changed, 39 insertions(+), 17 deletions(-)

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 62a2486002..632c063805 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 5e7fa9c402..03a2911c43 100644
--- a/posix/tstgetoptl.c
+++ b/posix/tstgetoptl.c
@@ -129,13 +129,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;
@@ -147,6 +142,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'},
@@ -172,6 +168,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