[PATCH v21 7/9] posix: check for collisions in getopt_long
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Wed Feb 18 20:03:42 GMT 2026
On 03/02/26 14:51, Vivien Kraus wrote:
> There are 2 kinds of problems that can arise with translations:
> 1. The developer introduces a new option name that collides with a
> translation of another option;
> 2. The translator gave the same translation to 2 different options.
>
> Both are bugs, as the program behavior changes while the invocation is
> the same. With this check, those bugs are detected at run-time, and
> getopt_long returns '?' with optind set to 1, after printing a message
> to stderr. The message helps the translator know what to change to
> fix the issue.
>
> While the checks do not do anything if translations are disabled, they
> necessarily loop over all pairs of distinct options otherwise, so it
> may be costly for a program with many arguments. The proposal is to
> only run the test during the first call to getopt_long, and never try
> again after. If we failed repeatedly until collisions were resolved,
> then the common pattern to continue processing options until the
> return value is -1 would lead to an infinite loop.
>
> Since getopt does not have an initialization function, knowing whether
> this is the first time we parse arguments is not trivial. The
> solution is this:
> - for reentrant use: we add a boolean to the state, initially set to
> false, and set to true once the first call returns.
> - for non-reentrant use: we add a global (but not exported) boolean,
> initially set to false, set to false when we call
> getopt_long_enable_translations, and set to true when we disable the
> translations or a non-reentrant getopt_long version returns.
>
> Another approach would be to only check collisions when an option is
> recognized (while processing argv), but the translator would then have
> to try all the program options to detect the collisions.
>
> Another approach would be to only check collisions with the argp API,
> since it has a proper initialization method, but it is useful also for
> getopt_long users.
The new tst-getopt_long_collision.c test require a LOCALE update:
diff --git a/posix/Makefile b/posix/Makefile
index 48715cf1c1..869cf0f797 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -534,6 +534,7 @@ LOCALES := \
en_US.UTF-8 \
es_US.ISO-8859-1 \
es_US.UTF-8 \
+ fr_FR.UTF-8 \
ja_JP.EUC-JP \
tr_TR.UTF-8 \
# LOCALES
But even with this I am seeing a regression:
$ make test t=posix/tst-getopt_long_collision
[...]
tst-getopt_long_collision.c:64: error: string comparison failed
left string: 10 bytes
right string: 3 bytes
left (evaluated from dgettext ("tst-getopt_long_collision", "kind 1\004foo")):
"kind 1\004foo"
6B 69 6E 64 20 31 04 66 6F 6F
right (evaluated from "bar"):
"bar"
62 61 72
tst-getopt_long_collision.c:66: error: string comparison failed
left string: 10 bytes
right string: 3 bytes
left (evaluated from dgettext ("tst-getopt_long_collision", "kind 1\004bar")):
"kind 1\004bar"
6B 69 6E 64 20 31 04 62 61 72
right (evaluated from "baz"):
"baz"
62 61 7A
tst-getopt_long_collision.c:68: error: string comparison failed
left string: 10 bytes
right string: 4 bytes
left (evaluated from dgettext ("tst-getopt_long_collision", "kind 2\004foo")):
"kind 2\004foo"
6B 69 6E 64 20 32 04 66 6F 6F
right (evaluated from "same"):
"same"
73 61 6D 65
tst-getopt_long_collision.c:70: error: string comparison failed
left string: 10 bytes
right string: 4 bytes
left (evaluated from dgettext ("tst-getopt_long_collision", "kind 2\004bar")):
"kind 2\004bar"
6B 69 6E 64 20 32 04 62 61 72
right (evaluated from "same"):
"same"
73 61 6D 65
Start test 1.
tst-getopt_long_collision.c:100: numeric comparison failure
left: 104 (0x68); from: c
right: 63 (0x3f); from: expected
tst-getopt_long_collision.c:101: numeric comparison failure
left: 2 (0x2); from: optind
right: 1 (0x1); from: optind_after_first_run
Restart test 1, we expect no problems.
tst-getopt_long_collision.c:105: numeric comparison failure
left: -1 (0xffffffff); from: c
right: 104 (0x68); from: expected_second_run
Start test 2.
tst-getopt_long_collision.c:100: numeric comparison failure
left: 104 (0x68); from: c
right: 63 (0x3f); from: expected
tst-getopt_long_collision.c:101: numeric comparison failure
left: 2 (0x2); from: optind
right: 1 (0x1); from: optind_after_first_run
Restart test 2, we expect no problems.
tst-getopt_long_collision.c:105: numeric comparison failure
left: -1 (0xffffffff); from: c
right: 104 (0x68); from: expected_second_run
Start test 3.
Restart test 3, we expect no problems.
error: 10 test failures
Any idea why? I tried to also check with the full set applied but it show the
same regression. I will need to debug further to see if it is something related
to my environment.
> ---
> manual/getopt.texi | 11 ++-
> posix/Makefile | 10 +++
> posix/getopt.c | 104 ++++++++++++++++++++++-
> posix/getopt1.c | 28 +++++--
> posix/getopt_int.h | 10 ++-
> posix/tst-getopt_long_collision.c | 128 +++++++++++++++++++++++++++++
> posix/tst-getopt_long_collision.po | 32 ++++++++
> posix/tstgetoptl.c | 11 +--
> posix/tstgetoptl.po | 6 --
> 9 files changed, 316 insertions(+), 24 deletions(-)
> create mode 100644 posix/tst-getopt_long_collision.c
> create mode 100644 posix/tst-getopt_long_collision.po
>
> diff --git a/manual/getopt.texi b/manual/getopt.texi
> index bd58e1b7d8..dbee16b62e 100644
> --- a/manual/getopt.texi
> +++ b/manual/getopt.texi
> @@ -23,7 +23,9 @@ use this facility, your program must include the header file
> @deftypevar int opterr
> @standards{POSIX.2, unistd.h}
> If the value of this variable is nonzero, then @code{getopt} prints an
> -error message to the standard error stream if it encounters an unknown
> +error message to the standard error stream if it detects a collision
> +between an untranslated long option name and a translation of a
> +different option, or it encounters an unknown
> option character or an option with a missing required argument. This is
> the default behavior. If you set this variable to zero, @code{getopt}
> does not print any messages, but it still returns the character @code{?}
> @@ -268,6 +270,13 @@ 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.
>
> +Once translations have been enabled, the next call to
> +@code{getopt_long} or @code{getopt_long_only}, and only this next
> +call, will check for collisions between long option name translations.
> +If a collision is found, a message is printed to @code{stderr}, this
> +next call will fail, returning @code{'?'}, while @code{optind} will be
> +set to 1.
> +
> @code{getopt_long_enable_translations} returns 0 on success, or -1 and
> sets errno.
> @end deftypefun
> diff --git a/posix/Makefile b/posix/Makefile
> index db3bfef3df..3e2514f41e 100644
> --- a/posix/Makefile
> +++ b/posix/Makefile
> @@ -288,6 +288,7 @@ tests := \
> tst-fork \
> tst-gai_strerror \
> tst-getopt_long1 \
> + tst-getopt_long_collision \
> tst-glob-bz30635 \
> tst-glob-tilde \
> tst-glob_symlinks \
> @@ -813,3 +814,12 @@ $(tstgetoptl_mo): tstgetoptl.po
>
> $(objpfx)tstgetoptl.out: $(tstgetoptl_mo) $(gen-locales)
> CFLAGS-tstgetoptl.c += -DOBJPFX=\"$(objpfx)\"
> +
> +tst_getopt_long_collision_mo = $(objpfx)domaindir/fr_FR/LC_MESSAGES/tst-getopt_long_collision.mo
> +$(tst_getopt_long_collision_mo): tst-getopt_long_collision.po
> + $(make-target-directory)
> + msgfmt -o $@T $<
> + mv -f $@T $@
> +
> +$(objpfx)tst-getopt_long_collision.out: $(tst_getopt_long_collision_mo) $(gen-locales)
> +CFLAGS-tst-getopt_long_collision.c += -DOBJPFX=\"$(objpfx)\"
> diff --git a/posix/getopt.c b/posix/getopt.c
> index 399abeea74..2983fe6ea7 100644
> --- a/posix/getopt.c
> +++ b/posix/getopt.c
> @@ -483,11 +483,93 @@ _getopt_initialize (_GL_UNUSED int argc,
> d->__ordering = REQUIRE_ORDER;
> else
> d->__ordering = PERMUTE;
> -
> d->__initialized = 1;
> return optstring;
> }
>
> +
> +static bool
> +has_translation_collisions (const char *domain,
> + const char *context,
> + const struct option *long_options,
> + char *(*do_translate) (const char *__domain,
> + const char *__context,
> + const char *__name,
> + char **__allocated),
> + bool print_errors,
> + const char *argv0)
> +{
> + /* Otherwise, this is a double loop. */
> + size_t n_options = 0;
> + size_t option_index_a, option_index_b;
> + char *a_buffer = NULL;
> + const char *a_name = NULL;
> + const struct option *option_a;
> + char *b_buffer = NULL;
> + const char *b_name = NULL;
> + const struct option *option_b;
> + bool has_collision = false;
> +
> + if (do_translate == NULL || context == NULL)
> + /* Translations are disabled, we can skip. */
> + return false;
> + /* Count the number of options. */
> + for (n_options = 0; long_options[n_options].name; n_options++)
> + ;
> + /* Detect collisions between the non-translated name of an option
> + and the translation of a *different* option, or the translations
> + of two different options. */
> + for (option_index_a = 0;
> + option_index_a < n_options;
> + option_index_a++)
> + {
> + option_a = &(long_options[option_index_a]);
> + a_name = do_translate (domain, context, option_a->name, &a_buffer);
> + for (option_index_b = 0;
> + option_index_b < n_options;
> + option_index_b++)
> + if (option_index_b != option_index_a)
> + {
> + option_b = &(long_options[option_index_b]);
> + b_name = do_translate (domain, context, option_b->name, &b_buffer);
> + if (strcmp (option_a->name, b_name) == 0)
> + {
> + if (print_errors)
> + /* Since we do not consider a particular use of an
> + option, but its general name, we do not know what
> + prefix it has ("--", "-", or "-W "). */
> + fprintf (stderr,
> + _("%s: you found a translation bug! "
> + "domain '%s', context '%s': "
> + "option *'%s'* exists "
> + "and option '%s' translates to *'%s'*\n"),
> + argv0,
> + domain, context,
> + option_a->name,
> + option_b->name, b_name);
> + has_collision = true;
> + }
> + if (strcmp (a_name, b_name) == 0
> + && strcmp (option_a->name, a_name) != 0
> + && strcmp (option_b->name, b_name) != 0
> + && option_index_a < option_index_b)
> + {
> + if (print_errors)
> + fprintf (stderr,
> + _("%s: you found a translation bug! "
> + "domain '%s', context '%s': "
> + "both '%s' and '%s' translate to '%s'\n"),
> + argv0, domain, context,
> + option_a->name, option_b->name, a_name);
> + has_collision = true;
> + }
> + free (b_buffer);
> + }
> + free (a_buffer);
> + }
> + return has_collision;
> +}
> +
> /* Scan elements of ARGV (whose length is ARGC) for option characters
> given in OPTSTRING.
>
> @@ -563,6 +645,19 @@ _getopt_internal_r (int argc, char **argv, const char *optstring,
> else if (optstring[0] == '-' || optstring[0] == '+')
> optstring++;
>
> + /* Only ever check translations for the first time we call
> + getopt_long, since it is costly. We cannot check them in
> + _getopt_initialize, because gettext may not be set up yet when it
> + is called. */
> + if (!d->__translation_collisions_checked)
> + {
> + d->__translation_collisions_checked = true;
> + if (has_translation_collisions (d->opttextdomain, d->optctxt,
> + longopts, translate, print_errors,
> + argv[0]))
> + return '?';
> + }
> +
> if (optstring[0] == ':')
> print_errors = 0;
>
> @@ -788,7 +883,8 @@ _getopt_internal (int argc, char **argv, const char *optstring,
> char *(*translate) (const char *, const char *,
> const char *, char **),
> const char *ctxt,
> - const char *domain)
> + const char *domain,
> + bool translation_collisions_checked)
> {
> int result;
>
> @@ -796,6 +892,8 @@ _getopt_internal (int argc, char **argv, const char *optstring,
> getopt_data.opterr = opterr;
> getopt_data.optctxt = ctxt;
> getopt_data.opttextdomain = domain;
> + getopt_data.__translation_collisions_checked =
> + translation_collisions_checked;
>
> result = _getopt_internal_r (argc, argv, optstring, longopts,
> longind, long_only, &getopt_data,
> @@ -818,7 +916,7 @@ _getopt_internal (int argc, char **argv, const char *optstring,
> { \
> return _getopt_internal (argc, (char **)argv, optstring, \
> NULL, NULL, 0, POSIXLY_CORRECT, \
> - NULL, NULL, NULL); \
> + NULL, NULL, NULL, true); \
> }
>
> #ifdef _LIBC
> diff --git a/posix/getopt1.c b/posix/getopt1.c
> index cc844a0508..06639c4b96 100644
> --- a/posix/getopt1.c
> +++ b/posix/getopt1.c
> @@ -41,6 +41,11 @@ char *optctxt = NULL;
>
> char *opttextdomain = NULL;
>
> +/* This is reset each time we call getopt_long_enable_translations,
> + and set to true as soon as getopt_long is called. */
> +
> +bool translation_collisions_checked = false;
> +
> /* FIXME: use pgettext_expr. */
> static char *
> do_translate (const char *domain, const char *context, const char *msgid,
> @@ -77,9 +82,13 @@ int
> getopt_long (int argc, char *__getopt_argv_const *argv, const char *options,
> const struct option *long_options, int *opt_index)
> {
> - return _getopt_internal (argc, (char **) argv, options, long_options,
> - opt_index, 0, 0, do_translate,
> - optctxt, opttextdomain);
> + int c = _getopt_internal (argc, (char **) argv, options, long_options,
> + opt_index, 0, 0, do_translate,
> + optctxt, opttextdomain,
> + translation_collisions_checked);
> + /* Translations are checked at most once. */
> + translation_collisions_checked = true;
> + return c;
> }
>
> int
> @@ -101,9 +110,12 @@ getopt_long_only (int argc, char *__getopt_argv_const *argv,
> const char *options,
> const struct option *long_options, int *opt_index)
> {
> - return _getopt_internal (argc, (char **) argv, options, long_options,
> - opt_index, 1, 0, do_translate,
> - optctxt, opttextdomain);
> + int c = _getopt_internal (argc, (char **) argv, options, long_options,
> + opt_index, 1, 0, do_translate,
> + optctxt, opttextdomain,
> + translation_collisions_checked);
> + translation_collisions_checked = true;
> + return c;
> }
>
> int
> @@ -122,6 +134,8 @@ disable_translations (void)
> free (opttextdomain);
> optctxt = NULL;
> opttextdomain = NULL;
> + /* No translations so no possibilities for collisions. */
> + translation_collisions_checked = true;
> }
>
> int
> @@ -140,6 +154,8 @@ getopt_long_enable_translations (const char *msgctxt, const char *textdomain)
> disable_translations ();
> return -1;
> }
> + /* Next call to getopt_long will check for collisions. */
> + translation_collisions_checked = false;
> }
> return 0;
> }
> diff --git a/posix/getopt_int.h b/posix/getopt_int.h
> index a770776dc1..2d7079e770 100644
> --- a/posix/getopt_int.h
> +++ b/posix/getopt_int.h
> @@ -21,6 +21,7 @@
> #define _GETOPT_INT_H 1
>
> #include <getopt.h>
> +#include <stdbool.h>
>
> /* The translate argument here is optional (can be NULL), it is used
> to avoid depending on the gettext functions in the posix getopt
> @@ -31,7 +32,8 @@ extern int _getopt_internal (int ___argc, char **___argv,
> int __long_only, int __posixly_correct,
> char *(*translate) (const char *, const char *,
> const char *, char **),
> - const char *__optctxt, const char *__optdomain);
> + const char *__optctxt, const char *__optdomain,
> + bool __translation_collisions_checked);
>
>
> /* Reentrant versions which can handle parsing multiple argument
> @@ -100,6 +102,12 @@ struct _getopt_data
>
> int __first_nonopt;
> int __last_nonopt;
> +
> + /* Checking for collision in translations of long options. */
> +
> + /* Checking for collisions is costly; it must compare O(n²) strings,
> + when there are n options. So, it is only done once. */
> + bool __translation_collisions_checked;
> };
>
> /* The initializer is necessary to set OPTIND and OPTERR to their
> diff --git a/posix/tst-getopt_long_collision.c b/posix/tst-getopt_long_collision.c
> new file mode 100644
> index 0000000000..2e603ec9f8
> --- /dev/null
> +++ b/posix/tst-getopt_long_collision.c
> @@ -0,0 +1,128 @@
> +/* Copyright (C) 2026 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <getopt.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <libintl.h>
> +#include <locale.h>
> +#include <support/support.h>
> +#include <support/check.h>
> +
> +#define PN_(ctxt, str) (str)
> +
> +/* There are 2 types of collision that can happen: a translation equal
> + to an existing option, or two different options translating to the
> + same thing.
> +
> + We test both kinds. In the first test, we have this setup:
> + foo -> bar
> + bar -> baz
> +
> + In the second test, we have this setup:
> + foo -> same
> + bar -> same
> +
> + In the third, we don’t translate anything:
> + foo -> foo
> + bar -> bar
> + */
> +
> +static const struct option options[] =
> + {
> + {"foo", no_argument, NULL, 'f'},
> + {"bar", no_argument, NULL, 'b'},
> + {"help", no_argument, NULL, 'h'},
> + {NULL, 0, NULL, 0}
> + };
> +
> +static void
> +setup_catalog (void)
> +{
> + xsetlocale (LC_MESSAGES, "fr_FR.UTF-8");
> + TEST_VERIFY_EXIT (
> + bindtextdomain ("tst-getopt_long_collision", OBJPFX "domaindir")
> + != NULL);
> + TEST_VERIFY_EXIT (textdomain ("tst-getopt_long_collision") != NULL);
> + /* Check that the catalog is OK: */
> + TEST_COMPARE_STRING (dgettext ("tst-getopt_long_collision", "kind 1\004foo"),
> + "bar");
> + TEST_COMPARE_STRING (dgettext ("tst-getopt_long_collision", "kind 1\004bar"),
> + "baz");
> + TEST_COMPARE_STRING (dgettext ("tst-getopt_long_collision", "kind 2\004foo"),
> + "same");
> + TEST_COMPARE_STRING (dgettext ("tst-getopt_long_collision", "kind 2\004bar"),
> + "same");
> + TEST_COMPARE_STRING (dgettext ("tst-getopt_long_collision", "kind 3\004foo"),
> + "kind 3\004foo");
> + TEST_COMPARE_STRING (dgettext ("tst-getopt_long_collision", "kind 3\004bar"),
> + "kind 3\004bar");
> +}
> +
> +static void
> +do_test (int kind, int expected, int optind_after_first_run,
> + int expected_second_run)
> +{
> + /* Check test --help with one of the 3 tests. We expect the first
> + call to getopt_long to return expected, while setting optind to
> + optind_after_first_run. We call getopt_long a second time, and
> + we expect it to return expected_second_run, while setting optind
> + to 2. */
> + static const char *contexts[] = { "kind 1", "kind 2", "kind 3" };
> + const char *context = contexts[kind];
> + int c;
> + int option_index = 0;
> + const static char *argv[] =
> + { (char *) "tst-getopt_long_collision", "--help", NULL };
> + const static int argc = 2;
> + optind = 0;
> + TEST_VERIFY_EXIT (getopt_long_enable_translations (context, NULL) == 0);
> + fprintf (stderr, "Start test %d.\n", kind + 1);
> + /* First pass should detect the problem immediately, even if we do
> + not trigger the option. */
> + c = getopt_long (argc, (char **) argv, "fbh", options, &option_index);
> + TEST_COMPARE (c, expected);
> + TEST_COMPARE (optind, optind_after_first_run);
> + /* The translations check is only run once. */
> + fprintf (stderr, "Restart test %d, we expect no problems.\n", kind + 1);
> + c = getopt_long (argc, (char **) argv, "fbh", options, &option_index);
> + TEST_COMPARE (c, expected_second_run);
> + TEST_COMPARE (optind, 2);
> +}
> +
> +static int
> +do_all_tests (void)
> +{
> + setup_catalog ();
> + /* In failure cases, the first time we parse, we should get '?', and
> + optind stays at 1. The second time, we parse the first option.
> +
> + In the normal case, the first time we parse, we should get the
> + first option and optind jumps directly to 2. The second time, we
> + parsed everything.
> + */
> + do_test (0, '?', 1, 'h');
> + do_test (1, '?', 1, 'h');
> + do_test (2, 'h', 2, -1);
> + getopt_long_disable_translations ();
> + return 0;
> +}
> +
> +#define TEST_FUNCTION do_all_tests
> +#include <support/test-driver.c>
> diff --git a/posix/tst-getopt_long_collision.po b/posix/tst-getopt_long_collision.po
> new file mode 100644
> index 0000000000..2f39001c6d
> --- /dev/null
> +++ b/posix/tst-getopt_long_collision.po
> @@ -0,0 +1,32 @@
> +# French translations for tst-getopt_long_collision.c
> +# Copyright (C) 2026 THE GNU C Library'S COPYRIGHT HOLDER
> +# This file is distributed under the same license as the GNU C Library.
> +#
> +msgid ""
> +msgstr ""
> +"Project-Id-Version: GNU C Library (see version.h)\n"
> +"Report-Msgid-Bugs-To: \n"
> +"POT-Creation-Date: 2025-06-06 22:37+0200\n"
> +"PO-Revision-Date: 2025-06-06 22:38+0200\n"
> +"Language-Team: English (British) <(nothing)>\n"
> +"Language: en_GB\n"
> +"MIME-Version: 1.0\n"
> +"Content-Type: text/plain; charset=ASCII\n"
> +"Content-Transfer-Encoding: 8bit\n"
> +"Plural-Forms: nplurals=2; plural=(n > 1);\n"
> +
> +msgctxt "kind 1"
> +msgid "foo"
> +msgstr "bar"
> +
> +msgctxt "kind 1"
> +msgid "bar"
> +msgstr "baz"
> +
> +msgctxt "kind 2"
> +msgid "foo"
> +msgstr "same"
> +
> +msgctxt "kind 2"
> +msgid "bar"
> +msgstr "same"
> diff --git a/posix/tstgetoptl.c b/posix/tstgetoptl.c
> index ad5755ddbd..bdc20b7e3d 100644
> --- a/posix/tstgetoptl.c
> +++ b/posix/tstgetoptl.c
> @@ -31,13 +31,10 @@
> This echoes tstgetopt.c, where --colour was an option name alias
> for --color, so it had to be listed twice. */
>
> -/* This uses the en_GB locale so that colour means color. As a
> - special case, we also check that non-translated options have
> - precedence over translated options, by translating "optional" as
> - "required". We also check that getopt only matches translations
> - for actual options, by having the user pass --flavour (which is a
> - known translation of flavor) without the program recognizing a
> - --flavor option. */
> +/* This uses the en_GB locale so that colour means color. We also
> + check that getopt only matches translations for actual options, by
> + having the user pass --flavour (which is a known translation of
> + flavor) without the program recognizing a --flavor option. */
>
> #define TRANSLATION_CONTEXT "command-line option"
>
> diff --git a/posix/tstgetoptl.po b/posix/tstgetoptl.po
> index 7dc15e71f3..b1dc11c468 100644
> --- a/posix/tstgetoptl.po
> +++ b/posix/tstgetoptl.po
> @@ -24,9 +24,3 @@ msgstr "colour"
> msgctxt "command-line option"
> msgid "flavor"
> msgstr "flavour"
> -
> -# This is to make sure the translator cannot redirect options.
> -#: xxx.c:yy
> -msgctxt "command-line option"
> -msgid "optional"
> -msgstr "required"
More information about the Libc-alpha
mailing list