From patchwork Tue Oct 7 18:13:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121437 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 200EC3858415 for ; Tue, 7 Oct 2025 18:17:48 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [89.234.140.182]) by sourceware.org (Postfix) with ESMTPS id A66073858C40 for ; Tue, 7 Oct 2025 18:15:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A66073858C40 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org A66073858C40 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=89.234.140.182 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860902; cv=none; b=a/El8ngnXyrcwdoxFlO5p8HubQ7viOUbwH8neI4hT5McuLfziGylpqeJ+UPO3Z4DlIZsP75gvE+MSl7JrpD1G2MncqOOlhlT4+ZHnnC+qzaCIRK6e5ptyue922nNJkySlpw+L86v1oZtYrm9a8YieUb+M+LCKoVQCAvVI3kFNqw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860902; c=relaxed/simple; bh=G0EHX8B4yYLy5FbHnJ8mhvid+9GQqQ3vrTMmDjwpwbY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=FWLwCUk3OkI9OnVSVAx4UV9sGMEOqm12sGK/lC7Z+iCt2BwYt/P/GgXkkqUc/s9nQ5kAqT0GJPZdfbxhyM9ea2jnS3bPXsNENY7d3FLaIZyhLZNUqhG+W/F7/n/gAWeZvHKZhunmhcz3pT0bh9g1FeTarZbsx+8zM+TpLfkdqMY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A66073858C40 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu header.a=rsa-sha1 header.s=albinoniA header.b=Qt0XxOeO Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 700719ae for ; Tue, 7 Oct 2025 18:14:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s= albinoniA; bh=jp9w/0tkaZXUSIHRmC2YrENd7z4=; b=Qt0XxOeOeFN952B+aX JOfVdpcvQBasWxqdOCjqDztIGPKFhQ99trrksMZUWSVWOYZpt5MkbDeuvvjTaebF gmzmm20gfHHxdOpf1dua1ZfOxSrAS+N9ezEShAepytqa+ZahAH2TNVErI1fiGNcX oqS73ys6lI2lwBUibG63vJ1TLiZR2BfdzttZCbW03faD/KbggWLV/CRXKu26mUiu gm6qKva7cwGemKWV4yEd+O1KM13KCaDOIzMZaIklMzxLuEAyfwDmehESSBSx8KPK gCQNKqc8Gd6IdvdUyIGmtSNa7GopdEBjnKyya8CAYoHnREeSjaNyq5mEM/4k+71O 1MyA== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id f62aae60 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:52 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 1/9] posix: allow getopt_long to match translated option names Date: Tue, 7 Oct 2025 20:13:25 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_SHORT, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org It is possible to support translated long option names in a program with no change to glibc by duplicating the option names in the struct options array: one version untranslated, and one version translated. However, doing so is significant work for all packages. With this change, getopt will try and match the untranslated options names, then the translated option names if not found. Abbreviations will only match the untranslated names. _getopt_internal{_r} has a new argument: a translation function pointer. This way, we can pass NULL to avoid linking to gettext in the posix version of getopt, or pass something that calls gettext otherwise. The test tstgetoptl is adapted from tstgetopt. --- manual/getopt.texi | 25 ++++++-- posix/Makefile | 13 +++++ posix/getopt.c | 97 +++++++++++++++++++++++++------ posix/getopt1.c | 11 ++-- posix/getopt_int.h | 9 ++- posix/tstgetoptl.c | 136 ++++++++++++++++++++++++++++++++++++++++++++ posix/tstgetoptl.po | 25 ++++++++ 7 files changed, 289 insertions(+), 27 deletions(-) create mode 100644 posix/tstgetoptl.c create mode 100644 posix/tstgetoptl.po diff --git a/manual/getopt.texi b/manual/getopt.texi index 79a942307c..da9df5225a 100644 --- a/manual/getopt.texi +++ b/manual/getopt.texi @@ -202,6 +202,15 @@ declared in @file{getopt.h}, not @file{unistd.h}. You should make every program accept long options if it uses any options, for this takes little extra work and helps beginners remember how to use the program. +Both long option names and their translations provided by the program +for the user's current locale are recognized. This helps users of +your program who do not speak English understand the meaning of the +options, and it does not break the function of the program in scripts +if the untranslated option names are used. If international +communication involves the invocation of your program, the program +users should be encouraged to use untranslated option names, or +publish the locale used for this invocation. + @deftp {Data Type} {struct option} @standards{GNU, getopt.h} This structure describes a single long option name for the sake of @@ -213,7 +222,9 @@ The @code{struct option} structure has these fields: @table @code @item const char *name -This field is the name of the option. It is a string. +This field is the name of the option. It is a string. In order for +@command{getopt_long} to accept either the long option name or its +translated form, you should mark this string for translation. @item int has_arg This field says whether the option takes an argument. It is an integer, @@ -248,10 +259,14 @@ When @code{getopt_long} encounters a short option, it does the same thing that @code{getopt} would do: it returns the character code for the option, and stores the option's argument (if it has one) in @code{optarg}. -When @code{getopt_long} encounters a long option, it takes actions based -on the @code{flag} and @code{val} fields of the definition of that -option. The option name may be abbreviated as long as the abbreviation is -unique. +When @code{getopt_long} encounters a long option or its translation in +the current textdomain, it takes actions based on the @code{flag} and +@code{val} fields of the definition of that option. The english name +of the option name may be abbreviated as long as the abbreviation is +unique. No abbreviation of the translated option name is recognized. +Since the untranslated option names have precedence over the +translated option names, it is not possible to hide or divert an +option with a translation. If @code{flag} is a null pointer, then @code{getopt_long} returns the contents of @code{val} to indicate which option it found. You should diff --git a/posix/Makefile b/posix/Makefile index a36e5decd3..1c787f53fb 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -328,8 +328,20 @@ tests := \ tst-waitid \ tst-wordexp-nocmd \ tstgetopt \ + tstgetoptl \ # tests +# tstgetoptl uses a translation catalog for translated option names. +tstgetoptl_mo = $(objpfx)domaindir/en_GB/LC_MESSAGES/tstgetoptl.mo + +$(tstgetoptl_mo): tstgetoptl.po + $(make-target-directory) + msgfmt -o $@T $< + mv -f $@T $@ + +$(objpfx)tstgetoptl.out: $(tstgetoptl_mo) +CFLAGS-tstgetoptl.c += -DOBJPFX=\"$(objpfx)\" + # Test for the glob symbol version that was replaced in glibc 2.27. ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes) tests += \ @@ -602,6 +614,7 @@ CFLAGS-fork.c = $(libio-mtsafe) $(config-cflags-wno-ignored-attributes) tstgetopt-ARGS = -a -b -cfoobar --required foobar --optional=bazbug \ --none random --col --color --colour +tstgetoptl-ARGS = $(tstgetopt-ARGS) tst-exec-ARGS = -- $(host-test-program-cmd) tst-exec-static-ARGS = $(tst-exec-ARGS) diff --git a/posix/getopt.c b/posix/getopt.c index 66b43850ee..9540821e1f 100644 --- a/posix/getopt.c +++ b/posix/getopt.c @@ -182,6 +182,21 @@ exchange (char **argv, struct _getopt_data *d) d->__last_nonopt = d->optind; } +/* Return 1 iff a translation for opt_name has been found and it + matches the substring from argument, length argument_length. +*/ +static const int +match_translated_option_name (char *(*translate) (const char *msgid), + const char *argument, size_t argument_length, + const char *opt_name) +{ + const char *translated = opt_name; + if (translate) + translated = translate (opt_name); + return (!strncmp (translated, argument, argument_length) + && argument_length == strlen (translated)); +} + /* Process the argument starting with d->__nextchar as a long option. d->optind should *not* have been advanced over this argument. @@ -194,7 +209,8 @@ static int process_long_option (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, - int print_errors, const char *prefix) + int print_errors, const char *prefix, + char *(*translate) (const char *msgid)) { char *nameend; size_t namelen; @@ -202,6 +218,7 @@ process_long_option (int argc, char **argv, const char *optstring, const struct option *pfound = NULL; int n_options; int option_index; + const char *translated_option_name; for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; @@ -221,7 +238,23 @@ process_long_option (int argc, char **argv, const char *optstring, if (pfound == NULL) { - /* Didn't find an exact match, so look for abbreviations. */ + /* Didn't find an exact match, try with translated option + names. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (match_translated_option_name (translate, d->__nextchar, namelen, p->name)) + { + /* Exact match found with translation. */ + pfound = p; + option_index = option_index; + break; + } + } + + if (pfound == NULL) + { + /* Didn't find an exact match with translations, so look for + abbreviations, but only for the option name in the C + locale. */ unsigned char *ambig_set = NULL; int ambig_malloced = 0; int ambig_fallback = 0; @@ -332,6 +365,7 @@ 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 (pfound->name); if (*nameend) { /* Don't test has_arg with >, because some C compilers don't @@ -341,10 +375,23 @@ process_long_option (int argc, char **argv, const char *optstring, else { if (print_errors) - fprintf (stderr, - _("%s: option '%s%s' doesn't allow an argument\n"), - argv[0], prefix, pfound->name); - + { + if (strcmp (translated_option_name, pfound->name) != 0) + { + /* Print both names of the option. */ + fprintf (stderr, + _("%s: option '%s%s' / '%s%s' doesn't allow an argument\n"), + argv[0], prefix, translated_option_name, prefix, pfound->name); + } + else + { + /* Either the option name is not translated, or its + translation is the same as the option name. */ + fprintf (stderr, + _("%s: option '%s%s' doesn't allow an argument\n"), + argv[0], prefix, pfound->name); + } + } d->optopt = pfound->val; return '?'; } @@ -356,9 +403,22 @@ process_long_option (int argc, char **argv, const char *optstring, else { if (print_errors) - fprintf (stderr, - _("%s: option '%s%s' requires an argument\n"), - argv[0], prefix, pfound->name); + { + /* Same dichotomy as when the option does not allow an + argument. */ + if (strcmp (translated_option_name, pfound->name) != 0) + { + fprintf (stderr, + _("%s: option '%s%s' / '%s%s' requires an argument\n"), + argv[0], prefix, translated_option_name, prefix, pfound->name); + } + else + { + fprintf (stderr, + _("%s: option '%s%s' requires an argument\n"), + argv[0], prefix, pfound->name); + } + } d->optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; @@ -470,7 +530,8 @@ _getopt_initialize (_GL_UNUSED int argc, int _getopt_internal_r (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, - int long_only, struct _getopt_data *d, int posixly_correct) + int long_only, struct _getopt_data *d, int posixly_correct, + char *(*translate) (const char *msgid)) { int print_errors = d->opterr; @@ -573,7 +634,8 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, d->__nextchar = argv[d->optind] + 2; return process_long_option (argc, argv, optstring, longopts, longind, long_only, d, - print_errors, "--"); + print_errors, "--", + translate); } /* If long_only and the ARGV-element has the form "-f", @@ -595,7 +657,8 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, d->__nextchar = argv[d->optind] + 1; code = process_long_option (argc, argv, optstring, longopts, longind, long_only, d, - print_errors, "-"); + print_errors, "-", + translate); if (code != -1) return code; } @@ -649,7 +712,8 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, d->__nextchar = d->optarg; d->optarg = NULL; return process_long_option (argc, argv, optstring, longopts, longind, - 0 /* long_only */, d, print_errors, "-W "); + 0 /* long_only */, d, print_errors, "-W ", + translate); } if (temp[1] == ':') { @@ -702,7 +766,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int _getopt_internal (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, - int posixly_correct) + int posixly_correct, char *(*translate) (const char *)) { int result; @@ -711,7 +775,7 @@ _getopt_internal (int argc, char **argv, const char *optstring, result = _getopt_internal_r (argc, argv, optstring, longopts, longind, long_only, &getopt_data, - posixly_correct); + posixly_correct, translate); optind = getopt_data.optind; optarg = getopt_data.optarg; @@ -729,7 +793,8 @@ _getopt_internal (int argc, char **argv, const char *optstring, NAME (int argc, char *const *argv, const char *optstring) \ { \ return _getopt_internal (argc, (char **)argv, optstring, \ - NULL, NULL, 0, POSIXLY_CORRECT); \ + NULL, NULL, 0, POSIXLY_CORRECT, \ + NULL); \ } #ifdef _LIBC diff --git a/posix/getopt1.c b/posix/getopt1.c index 733f58122a..6bf0087344 100644 --- a/posix/getopt1.c +++ b/posix/getopt1.c @@ -19,6 +19,9 @@ #ifndef _LIBC # include +# include "gettext.h" +#else +# include #endif #include "getopt.h" @@ -29,7 +32,7 @@ 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); + opt_index, 0, 0, gettext); } int @@ -38,7 +41,7 @@ _getopt_long_r (int argc, char **argv, const char *options, struct _getopt_data *d) { return _getopt_internal_r (argc, argv, options, long_options, opt_index, - 0, d, 0); + 0, d, 0, gettext); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. @@ -52,7 +55,7 @@ getopt_long_only (int argc, char *__getopt_argv_const *argv, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, (char **) argv, options, long_options, - opt_index, 1, 0); + opt_index, 1, 0, gettext); } int @@ -61,7 +64,7 @@ _getopt_long_only_r (int argc, char **argv, const char *options, struct _getopt_data *d) { return _getopt_internal_r (argc, argv, options, long_options, opt_index, - 1, d, 0); + 1, d, 0, gettext); } diff --git a/posix/getopt_int.h b/posix/getopt_int.h index 94c1945c5f..b15b21256a 100644 --- a/posix/getopt_int.h +++ b/posix/getopt_int.h @@ -22,10 +22,14 @@ #include +/* The translate argument here is optional (can be NULL), it is used + to avoid depending on the gettext functions in the posix getopt + function. */ extern int _getopt_internal (int ___argc, char **___argv, const char *__shortopts, const struct option *__longopts, int *__longind, - int __long_only, int __posixly_correct); + int __long_only, int __posixly_correct, + char *(*translate) (const char *msgid)); /* Reentrant versions which can handle parsing multiple argument @@ -102,7 +106,8 @@ extern int _getopt_internal_r (int ___argc, char **___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only, struct _getopt_data *__data, - int __posixly_correct); + int __posixly_correct, + char *(*translate) (const char *msgid)); extern int _getopt_long_r (int ___argc, char **___argv, const char *__shortopts, diff --git a/posix/tstgetoptl.c b/posix/tstgetoptl.c new file mode 100644 index 0000000000..f880cf71e5 --- /dev/null +++ b/posix/tstgetoptl.c @@ -0,0 +1,136 @@ +/* Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +/* This tests the same behavior as tstgetopt.c, but instead of having + two different options with the same short name, it has only one, + and the other one is a translation. */ + +/* 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 translated "optional" as + "required". */ + +static int +prepare_localedir (void) +{ + unsetenv ("LANGUAGE"); + setlocale (LC_ALL, "en_GB.UTF-8"); + if (bindtextdomain ("tstgetoptl", OBJPFX "domaindir") == NULL) + { + 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 ("color"), "colour") != 0) + { + fputs ("The mo file does not work.\n", stderr); + return -1; + } + return 0; +} + +int +main (int argc, char **argv) +{ + static const struct option options[] = + { + {"required", required_argument, NULL, 'r'}, + {"optional", optional_argument, NULL, 'o'}, + {"none", no_argument, NULL, 'n'}, + {"color", no_argument, NULL, 'C'}, + /* Now colour is handled as a translation of color */ + {NULL, 0, NULL, 0 } + }; + + /* The rest of the function is the same as in tstgetopt.c. */ + + int aflag = 0; + int bflag = 0; + char *cvalue = NULL; + int Cflag = 0; + int nflag = 0; + int index; + int c; + int result = 0; + + if (prepare_localedir () != 0) + { + fputs ("Error while setting up localedir.\n", stderr); + return 1; + } + while ((c = getopt_long (argc, argv, "abc:", options, NULL)) >= 0) + switch (c) + { + case 'a': + aflag = 1; + break; + case 'b': + bflag = 1; + break; + case 'c': + cvalue = optarg; + break; + case 'C': + ++Cflag; + break; + case '?': + fputs ("Unknown option.\n", stderr); + return 1; + default: + fprintf (stderr, "This should never happen!\n"); + return 1; + + case 'r': + printf ("--required %s\n", optarg); + result |= strcmp (optarg, "foobar") != 0; + break; + case 'o': + printf ("--optional %s\n", optarg); + result |= optarg == NULL || strcmp (optarg, "bazbug") != 0; + break; + case 'n': + puts ("--none"); + nflag = 1; + break; + } + + printf ("aflag = %d, bflag = %d, cvalue = %s, Cflags = %d, nflag = %d\n", + aflag, bflag, cvalue, Cflag, nflag); + + result |= (aflag != 1 || bflag != 1 || cvalue == NULL + || strcmp (cvalue, "foobar") != 0 || Cflag != 3 || nflag != 1); + + for (index = optind; index < argc; index++) + printf ("Non-option argument %s\n", argv[index]); + + result |= optind + 1 != argc || strcmp (argv[optind], "random") != 0; + + return result; +} diff --git a/posix/tstgetoptl.po b/posix/tstgetoptl.po new file mode 100644 index 0000000000..25cd595790 --- /dev/null +++ b/posix/tstgetoptl.po @@ -0,0 +1,25 @@ +# English translations for tstgetoptl, a test case in glibc. +# Copyright (C) 2025 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the glibc package. +# +msgid "" +msgstr "" +"Project-Id-Version: tstgetoptl 0.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-27 19:29+0200\n" +"PO-Revision-Date: 2025-05-27 19:30+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" + +#: xxx.c:yy +msgid "color" +msgstr "colour" + +# This is to make sure the translator cannot redirect options. +#: xxx.c:yy +msgid "optional" +msgstr "required" From patchwork Tue Oct 7 18:13:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121433 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E047C385843A for ; Tue, 7 Oct 2025 18:16:15 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [IPv6:2a00:5881:4008:2810::309]) by sourceware.org (Postfix) with ESMTPS id F2A5A3858C2A for ; Tue, 7 Oct 2025 18:15:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F2A5A3858C2A Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org F2A5A3858C2A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:5881:4008:2810::309 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860906; cv=none; b=bR+qTNBbiSCjEdbtskpWvva/C50ZPfRfxLdD9m0dmnepsEpZfCSUBaJI3yWuzirICMOmeUGZ2scrkudfp5H5I2x7DCpdHdRSyxgvX9V6Wo3Z9qyxIJvRuSKrxHOSFar5EBFquSrou54KVDYyczk0evE+HJm0V5iQuPqf7lRDNGI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860906; c=relaxed/simple; bh=spSQf/KWkfLTB4HDu/Sb/E5Qn6+V3mSFq4bzbWeC5V8=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=a5ezzJiGhX99XyweEi5U2AZptRRztD377J6AwAkyT0/h1+uqQeJrCY82w3RH1OMP/Jw0pP+zPENbJvX5FeMCL4S5Drpp743hGGIcpY0NX1wcgTeC0QtBdS5eksCC7dkfiDS/qB/340ofU+u3dqfJsdehSNKbLQ2I23GlCW4TlNA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F2A5A3858C2A Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu header.a=rsa-sha1 header.s=albinoniA header.b=KoCE8xDk Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 3b44e99d for ; Tue, 7 Oct 2025 18:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=albinoniA; bh=BJkvLWs HBy/UfQw19Pv/A6bxuB8=; b=KoCE8xDkxy+HcIf+6lVEK5Ol1ECRqwb3lxi93DW znqrkVs44Ek7pJbZCY5GlCrViXCztZPuYmMaDGrd2kVMLG1aMfNf8TU7bjKOBp5b g8x7UYx/jE+dHYdL+OcTOkcNFY6zmXSB+m7sn6D8qOqci5ti0k/2Aw3uDYrZkT+o Xw5JnFRGOd/5WGtzDRm6gYoyX0f24MJ395yQSucv9ID2B9D3WoB1hEGbsFJ8UqTf BjlZoiG2xfAa//Y9I4aQaeljeuZ7XjnAkhiLXD3d+EV/achx0MR9e7JqV39IJdlD vDqJtUrjhiwLazemBVuwvc5efjQy3EtLXDyThnLFXZY0puA== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id f5cd12ae (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:52 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 2/9] posix: let the getopt caller set the translation context Date: Tue, 7 Oct 2025 20:13:26 +0200 Message-Id: <36973f90225c5d2413ce90b3c66d707d91001673.1759860222.git.vivien@planete-kraus.eu> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Option names are typically one word, so they could be translated differently in different parts of the program. The use of a context lets the translator pick the most appropriate translation when used in the command-line. Another possibility would be to prepend two dashes to the option name before translation, such that it would be obvious this is the command-line option name. However, it would be difficult to mark this string for translation (to be processed by xgettext). This patch creates a new global variable / reentrant state field, optctxt, a pointer, so that the caller can override it. It is mandatory: if developers do not want to have option name translation, they just have to never set optctxt, or set it to NULL. pgettext_expr is not available yet, so we use a custom function to combine the context and the long option name, and discard the context if no translation was performed. --- manual/getopt.texi | 14 +++++- posix/Versions | 3 ++ posix/bits/getopt_ext.h | 7 +++ posix/getopt.c | 27 +++++++----- posix/getopt1.c | 43 +++++++++++++++++-- posix/getopt_int.h | 6 ++- posix/tstgetoptl.c | 6 ++- posix/tstgetoptl.po | 2 + sysdeps/mach/hurd/i386/libc.abilist | 1 + sysdeps/mach/hurd/x86_64/libc.abilist | 1 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arc/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 + sysdeps/unix/sysv/linux/csky/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + .../sysv/linux/loongarch/lp64/libc.abilist | 1 + .../sysv/linux/m68k/coldfire/libc.abilist | 1 + .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + .../sysv/linux/microblaze/be/libc.abilist | 1 + .../sysv/linux/microblaze/le/libc.abilist | 1 + .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 + .../sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 + .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../powerpc/powerpc32/nofpu/libc.abilist | 1 + .../linux/powerpc/powerpc64/be/libc.abilist | 1 + .../linux/powerpc/powerpc64/le/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv32/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 + .../sysv/linux/sparc/sparc32/libc.abilist | 1 + .../sysv/linux/sparc/sparc64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 42 files changed, 124 insertions(+), 18 deletions(-) diff --git a/manual/getopt.texi b/manual/getopt.texi index da9df5225a..65e24f1143 100644 --- a/manual/getopt.texi +++ b/manual/getopt.texi @@ -53,6 +53,16 @@ This variable is set by @code{getopt} to point at the value of the option argument, for those options that accept arguments. @end deftypevar +@deftypevar {const char *} optctxt +In order to match translated option names, @code{getopt} looks the +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 translated option names +will not be processed. +@end deftypevar + @deftypefun int getopt (int @var{argc}, char *const *@var{argv}, const char *@var{options}) @standards{POSIX.2, unistd.h} @safety{@prelim{}@mtunsafe{@mtasurace{:getopt} @mtsenv{}}@asunsafe{@ascuheap{} @ascuintl{} @asulock{} @asucorrupt{}}@acunsafe{@acsmem{} @aculock{} @acucorrupt{}}} @@ -224,7 +234,9 @@ The @code{struct option} structure has these fields: @item const char *name This field is the name of the option. It is a string. In order for @command{getopt_long} to accept either the long option name or its -translated form, you should mark this string for translation. +translated form, you should mark this string for translation with a +translation context, and set @code{optctxt} to the translation +context. @item int has_arg This field says whether the option takes an argument. It is an integer, diff --git a/posix/Versions b/posix/Versions index 0624d24bcc..5873e8ec56 100644 --- a/posix/Versions +++ b/posix/Versions @@ -159,6 +159,9 @@ libc { GLIBC_2.35 { posix_spawn_file_actions_addtcsetpgrp_np; } + GLIBC_2.43 { + optctxt; + } GLIBC_PRIVATE { __libc_fork; __libc_pread; __libc_pwrite; __nanosleep_nocancel; __pause_nocancel; diff --git a/posix/bits/getopt_ext.h b/posix/bits/getopt_ext.h index 42be8ec38e..07d9407b64 100644 --- a/posix/bits/getopt_ext.h +++ b/posix/bits/getopt_ext.h @@ -26,6 +26,13 @@ __BEGIN_DECLS +#ifdef __USE_GNU +/* Callers store the translation context in which to retrieve option + names. If unset, the option names will not be translated. */ + +extern const char *optctxt; +#endif + /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of 'struct option' terminated by an element containing a name which is diff --git a/posix/getopt.c b/posix/getopt.c index 9540821e1f..28f0be03f8 100644 --- a/posix/getopt.c +++ b/posix/getopt.c @@ -182,17 +182,19 @@ exchange (char **argv, struct _getopt_data *d) d->__last_nonopt = d->optind; } -/* Return 1 iff a translation for opt_name has been found and it - matches the substring from argument, length argument_length. +/* Return 1 iff translation_context is not NULL, a translation for + opt_name has been found and it matches the substring from argument, + length argument_length. */ static const int -match_translated_option_name (char *(*translate) (const char *msgid), +match_translated_option_name (char *(*translate) (const char *, const char *), const char *argument, size_t argument_length, + const char *translation_context, const char *opt_name) { const char *translated = opt_name; if (translate) - translated = translate (opt_name); + translated = translate (translation_context, opt_name); return (!strncmp (translated, argument, argument_length) && argument_length == strlen (translated)); } @@ -210,7 +212,7 @@ process_long_option (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, int print_errors, const char *prefix, - char *(*translate) (const char *msgid)) + char *(*translate) (const char *, const char *)) { char *nameend; size_t namelen; @@ -241,7 +243,9 @@ process_long_option (int argc, char **argv, const char *optstring, /* Didn't find an exact match, try with translated option names. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (match_translated_option_name (translate, d->__nextchar, namelen, p->name)) + if (match_translated_option_name (translate, + d->__nextchar, namelen, + d->optctxt, p->name)) { /* Exact match found with translation. */ pfound = p; @@ -365,7 +369,7 @@ 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 (pfound->name); + translated_option_name = translate (d->optctxt, pfound->name); if (*nameend) { /* Don't test has_arg with >, because some C compilers don't @@ -531,7 +535,7 @@ int _getopt_internal_r (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, int posixly_correct, - char *(*translate) (const char *msgid)) + char *(*translate) (const char *, const char *)) { int print_errors = d->opterr; @@ -766,12 +770,15 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int _getopt_internal (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, - int posixly_correct, char *(*translate) (const char *)) + int posixly_correct, + char *(*translate) (const char *, const char *), + const char *ctxt) { int result; getopt_data.optind = optind; getopt_data.opterr = opterr; + getopt_data.optctxt = ctxt; result = _getopt_internal_r (argc, argv, optstring, longopts, longind, long_only, &getopt_data, @@ -794,7 +801,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); \ } #ifdef _LIBC diff --git a/posix/getopt1.c b/posix/getopt1.c index 6bf0087344..28d090019d 100644 --- a/posix/getopt1.c +++ b/posix/getopt1.c @@ -26,13 +26,48 @@ #include "getopt.h" #include "getopt_int.h" +#include +#include + +/* Callers store an optional context to enable option name + translation. */ + +const char *optctxt = NULL; + +/* FIXME: use pgettext_expr. */ +static char * +do_translate (const char *context, const char *msgid) +{ + char *full_msgid; + const char *translated = msgid; + + if (context) + { + full_msgid = malloc (strlen (context) + 1 /* ^D */ + strlen (msgid) + 1); + if (msgid) + { + strcpy (full_msgid, context); + full_msgid[strlen (context)] = '\004'; + strcpy (full_msgid + strlen (context) + 1, msgid); + translated = __dcgettext (NULL, full_msgid, LC_MESSAGES); + if (!strcmp (translated, full_msgid)) + { + translated = msgid; + } + } + free (full_msgid); + } + else + translated = msgid; + return (char *) translated; +} 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, gettext); + opt_index, 0, 0, do_translate, optctxt); } int @@ -41,7 +76,7 @@ _getopt_long_r (int argc, char **argv, const char *options, struct _getopt_data *d) { return _getopt_internal_r (argc, argv, options, long_options, opt_index, - 0, d, 0, gettext); + 0, d, 0, do_translate); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. @@ -55,7 +90,7 @@ getopt_long_only (int argc, char *__getopt_argv_const *argv, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, (char **) argv, options, long_options, - opt_index, 1, 0, gettext); + opt_index, 1, 0, do_translate, optctxt); } int @@ -64,7 +99,7 @@ _getopt_long_only_r (int argc, char **argv, const char *options, struct _getopt_data *d) { return _getopt_internal_r (argc, argv, options, long_options, opt_index, - 1, d, 0, gettext); + 1, d, 0, do_translate); } diff --git a/posix/getopt_int.h b/posix/getopt_int.h index b15b21256a..1d091979c3 100644 --- a/posix/getopt_int.h +++ b/posix/getopt_int.h @@ -29,7 +29,8 @@ extern int _getopt_internal (int ___argc, char **___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only, int __posixly_correct, - char *(*translate) (const char *msgid)); + char *(*translate) (const char *, const char *), + const char *__optctxt); /* Reentrant versions which can handle parsing multiple argument @@ -71,6 +72,7 @@ struct _getopt_data int opterr; int optopt; char *optarg; + const char *optctxt; /* Internal members. */ @@ -107,7 +109,7 @@ extern int _getopt_internal_r (int ___argc, char **___argv, const struct option *__longopts, int *__longind, int __long_only, struct _getopt_data *__data, int __posixly_correct, - char *(*translate) (const char *msgid)); + char *(*translate) (const char *, const char *)); extern int _getopt_long_r (int ___argc, char **___argv, const char *__shortopts, diff --git a/posix/tstgetoptl.c b/posix/tstgetoptl.c index f880cf71e5..5ff1ba75c4 100644 --- a/posix/tstgetoptl.c +++ b/posix/tstgetoptl.c @@ -32,6 +32,8 @@ precedence over translated options, by translated "optional" as "required". */ +#define TRANSLATION_CONTEXT "command-line option" + static int prepare_localedir (void) { @@ -48,7 +50,7 @@ prepare_localedir (void) return -1; } /* Check that the catalog is OK: */ - if (strcmp (gettext ("color"), "colour") != 0) + if (strcmp (gettext (TRANSLATION_CONTEXT "\004" "color"), "colour") != 0) { fputs ("The mo file does not work.\n", stderr); return -1; @@ -59,6 +61,7 @@ prepare_localedir (void) int main (int argc, char **argv) { + static const char *translation_context = TRANSLATION_CONTEXT; static const struct option options[] = { {"required", required_argument, NULL, 'r'}, @@ -85,6 +88,7 @@ main (int argc, char **argv) fputs ("Error while setting up localedir.\n", stderr); return 1; } + optctxt = translation_context; while ((c = getopt_long (argc, argv, "abc:", options, NULL)) >= 0) switch (c) { diff --git a/posix/tstgetoptl.po b/posix/tstgetoptl.po index 25cd595790..e060c0d6e3 100644 --- a/posix/tstgetoptl.po +++ b/posix/tstgetoptl.po @@ -16,10 +16,12 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: xxx.c:yy +msgctxt "command-line option" msgid "color" msgstr "colour" # This is to make sure the translator cannot redirect options. #: xxx.c:yy +msgctxt "command-line option" msgid "optional" msgstr "required" diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist index e0dc8aea28..ef2389889d 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2664,6 +2664,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 pthread_cancel F GLIBC_2.43 pthread_clockjoin_np F GLIBC_2.43 pthread_detach F diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist index c0cac6d507..366f44b7b3 100644 --- a/sysdeps/mach/hurd/x86_64/libc.abilist +++ b/sysdeps/mach/hurd/x86_64/libc.abilist @@ -2345,6 +2345,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 pthread_cancel F GLIBC_2.43 pthread_clockjoin_np F GLIBC_2.43 pthread_detach F diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index bde5e66ce0..b5adb590b1 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2769,3 +2769,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 0060616d20..c97471e756 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -3116,6 +3116,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index 79895b9b37..7dd4589884 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2530,3 +2530,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index 3426d99f1e..35a50182f2 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2822,6 +2822,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index eca31a2e27..70f444545a 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2819,6 +2819,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 7c5ebdf3ba..83ac7a3a4f 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2806,3 +2806,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 742118e65e..85cfee194d 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2843,6 +2843,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index 8a8ff34e35..dea2312c5c 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -3026,6 +3026,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index 86b0246ad1..bde525090d 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2290,3 +2290,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 92cef27d98..89f275f92c 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2802,6 +2802,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 3b74574560..071de9934e 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2969,6 +2969,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index ae2d13ad8f..a983dd9776 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2855,3 +2855,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 1b0264df27..d8c4d03cee 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2852,3 +2852,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 8923228090..8431dca4fc 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2932,6 +2932,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 9ce80245f6..ff0d3bcb1b 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2930,6 +2930,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index e3c971367d..834ca53a26 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2938,6 +2938,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index db707fad52..e8dcdec523 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2840,6 +2840,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index 0780d53978..f69e29d8ec 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2280,3 +2280,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index f4f1551054..313b5ac2c2 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -3159,6 +3159,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index 34ec11f685..9ac04c675a 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -3204,6 +3204,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index b790b43f4b..030c44cfd6 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2913,6 +2913,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index b7de3f95a8..ba27c807a8 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2989,3 +2989,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index 2680eabc7c..59901b5a84 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2533,3 +2533,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 074ca2f280..d861e9348a 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2733,3 +2733,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 0573db9f50..94eddb2157 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -3157,6 +3157,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index 55760b901f..a8279df601 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2950,6 +2950,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index a15b4df221..dab732c1d3 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2849,6 +2849,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index b490e1064c..54fc47ab6c 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2846,6 +2846,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 8fd42d21d0..b73cd54dbb 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3180,6 +3180,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index b62dec6a63..dcd144bb46 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2816,6 +2816,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index fe23ac6682..b9549a8de1 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2765,6 +2765,7 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 986dfcca2a..35fc746c3b 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2784,3 +2784,4 @@ GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F +GLIBC_2.43 optctxt D 0x4 From patchwork Tue Oct 7 18:13:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121440 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 47836385275E for ; Tue, 7 Oct 2025 18:19:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 47836385275E Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu header.a=rsa-sha1 header.s=albinoniA header.b=KszhnI3A X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [89.234.140.182]) by sourceware.org (Postfix) with ESMTPS id 34AE13858D39 for ; Tue, 7 Oct 2025 18:15:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 34AE13858D39 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 34AE13858D39 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=89.234.140.182 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860907; cv=none; b=NuyRL3iDuOP/19PSOGSRZD+3HG85ISz817ThOwKPnCo4ZSUWKj+wiPzlfn0lZEBHb7J885VDbe5Vm/k+P1erUV/B4imu+77sQhP8V/CR0Dhd2AiQ9cb3VZ7JBAjrieGpZHGUV0YCinvbZXODZaVqQE/grWXpwBGZV0zBpZNYXeo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860907; c=relaxed/simple; bh=LVxZ9r2E/1coUtsrulB8mcLmTpVtKpmoFmIWcnC3iPI=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=cD+ZaqEZCUD1ORAUmJ+Rz+poaB4sQa8Uf9MGv7qRx8ufx87hNTzq3DY7upIrV7JOvDmYIU8VLpdTVUK2jzlDlDW7DRUo/Z3lzY80moX7fSeENPYXPemz1kRxAjbACyQitePs/FIyCqhn/YAM+ZS6uTYoSH620OlKgbiKEnGPfus= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 34AE13858D39 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 2b92f866 for ; Tue, 7 Oct 2025 18:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s= albinoniA; bh=u+9L5nYZ+GcRKxmtEanjfna776k=; b=KszhnI3AIGGaHcafIp a+eiWKSVjn+qlc0bwYMLMMxw9IsgOzdwGanvp01sSxaLHetBXSH2U+UCty1oKxFI JfP7FJD1RAJtvsX3HnZSDbZGQy+ywVEhFNydCzutFg/tGdbc8fDpgU/2xKOEZOVP NNafXyjfTHQemWWCsFwDFnZBeCc9nuZfLF6aAb2Y/YK1GJXLJnFsoZF0ZK3XCq3A lGhdZPhbjAgEcjorMnaUkFdffEXHWNeOn06olIhisv0bL/AbvnxP/MxBlcf4rHhw luULr7paMgnF3ddU9wbUZsnj9xtb7DmMD/AdmVgKypWF7ugIAM03aLmHA3c6gG99 drFg== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 3ad753bd (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:52 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 3/9] argp: document translated names in --help and --usage Date: Tue, 7 Oct 2025 20:13:27 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_SHORT, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org They are displayed in the --usage and --help output as the main option name, and the untranslated name is also displayed in parenthesis, so that someone reading a script (presumably with untranslated option names) can then figure out which translated option name it relates to. This help message processing uses dynamic memory allocation. If malloc fails, the translated option name will not be displayed. A translation context is required for translated options processing. However, its configuration would be most likely expected to be in the struct argp definition, but it would change this struct type. The easiest solution is to use a fixed context. Since the configuration of the translation domain is on a per-parser basis, and getopt_long is called with the union of all options (including options from children parsers), then all option names in all parsers must be in the same domain. However, it makes sense to use documentation from different domains. Thus, the translations for option names will all be searched in the current textdomain, while documentation will respect the parser’s domain. --- argp/Makefile | 14 +++++ argp/argp-help.c | 63 +++++++++++++++++--- argp/argp-parse.c | 1 + argp/tst-argphelp-localized.c | 102 +++++++++++++++++++++++++++++++++ argp/tst-argphelp-localized.po | 18 ++++++ argp/tst-argpusage-localized.c | 82 ++++++++++++++++++++++++++ manual/argp.texi | 22 ++++--- 7 files changed, 286 insertions(+), 16 deletions(-) create mode 100644 argp/tst-argphelp-localized.c create mode 100644 argp/tst-argphelp-localized.po create mode 100644 argp/tst-argpusage-localized.c diff --git a/argp/Makefile b/argp/Makefile index 01eb6b6db8..59fff5e1d0 100644 --- a/argp/Makefile +++ b/argp/Makefile @@ -44,6 +44,8 @@ tests = \ bug-argp2 \ tst-argp1 \ tst-argp2 \ + tst-argphelp-localized \ + tst-argpusage-localized \ tst-ldbl-argp \ # tests @@ -52,6 +54,18 @@ CFLAGS-argp-parse.c += $(uses-callbacks) $(config-cflags-wno-ignored-attributes) CFLAGS-argp-fmtstream.c += -fexceptions $(config-cflags-wno-ignored-attributes) CFLAGS-argp-fs-xinl.c += $(config-cflags-wno-ignored-attributes) +tst_argphelp_localized_mo = $(objpfx)domaindir/en_GB/LC_MESSAGES/tst-argphelp-localized.mo + +$(tst_argphelp_localized_mo): tst-argphelp-localized.po + $(make-target-directory) + msgfmt -o $@T $< + mv -f $@T $@ + +$(objpfx)tst-argphelp-localized.out: $(tst_argphelp_localized_mo) +$(objpfx)tst-argpusage-localized.out: $(tst_argphelp_localized_mo) +CFLAGS-tst-argphelp-localized.c += -DOBJPFX=\"$(objpfx)\" +CFLAGS-tst-argpusage-localized.c += -DOBJPFX=\"$(objpfx)\" + bug-argp1-ARGS = -- --help bug-argp2-ARGS = -- -d 111 --dstaddr 222 -p 333 --peer 444 diff --git a/argp/argp-help.c b/argp/argp-help.c index 3fe3a244ce..672e733fc8 100644 --- a/argp/argp-help.c +++ b/argp/argp-help.c @@ -1213,6 +1213,8 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state, unsigned num; const struct argp_option *real = entry->opt, *opt; char *so = entry->short_options; + char *option_msgid; + const char *translated_option_name; int have_long_opt = 0; /* We have any long options. */ /* Saved margins. */ int old_lm = __argp_fmtstream_set_lmargin (stream, 0); @@ -1276,9 +1278,25 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state, if (opt->name && ovisible (opt)) { comma (uparams.long_opt_col, &pest); - __argp_fmtstream_printf (stream, "--%s", opt->name); + option_msgid = + malloc (strlen ("command-line option\004") + + strlen (opt->name) + 1); + if (option_msgid) + { + strcpy (option_msgid, "command-line option\004"); + strcat (option_msgid, opt->name); + translated_option_name = gettext (option_msgid); + if (!strcmp (translated_option_name, option_msgid)) + translated_option_name = opt->name; + } + else + translated_option_name = opt->name; + __argp_fmtstream_printf (stream, "--%s", translated_option_name); arg (real, "=%s", "[=%s]", state == NULL ? NULL : state->root_argp->argp_domain, stream); + if (strcmp (translated_option_name, opt->name)) + __argp_fmtstream_printf (stream, " (--%s)", opt->name); + free (option_msgid); } } @@ -1420,6 +1438,8 @@ usage_long_opt (const struct argp_option *opt, { argp_fmtstream_t stream = cookie; const char *arg = opt->arg; + char *option_msgid; + const char *translated_opt_name = opt->name; int flags = opt->flags | real->flags; if (! arg) @@ -1427,16 +1447,41 @@ usage_long_opt (const struct argp_option *opt, if (! (flags & OPTION_NO_USAGE)) { + /* Since we cannot customize the translation context, we will + use a default one. FIXME: use pgettext_expr(). */ + static const char *default_context = "command-line option\004"; + option_msgid = malloc (strlen (default_context) + strlen (opt->name) + 1); + translated_opt_name = NULL; + if (option_msgid) + { + strcpy (option_msgid, default_context); + strcat (option_msgid, opt->name); + translated_opt_name = gettext (option_msgid); + if (!strcmp (translated_opt_name, option_msgid)) + translated_opt_name = opt->name; + } + if (!strcmp (translated_opt_name, opt->name)) + translated_opt_name = NULL; if (arg) - { - arg = dgettext (domain, arg); - if (flags & OPTION_ARG_OPTIONAL) - __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg); - else - __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg); - } + { + arg = dgettext (domain, arg); + if ((flags & OPTION_ARG_OPTIONAL) && translated_opt_name) + __argp_fmtstream_printf (stream, " [--%s[=%s] (--%s)]", + translated_opt_name, arg, opt->name); + else if (flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg); + else if (translated_opt_name) + __argp_fmtstream_printf (stream, " [--%s=%s (--%s)]", + translated_opt_name, arg, opt->name); + else + __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg); + } + else if (translated_opt_name) + __argp_fmtstream_printf (stream, " [--%s (--%s)]", + translated_opt_name, opt->name); else - __argp_fmtstream_printf (stream, " [--%s]", opt->name); + __argp_fmtstream_printf (stream, " [--%s]", opt->name); + free (option_msgid); } return 0; diff --git a/argp/argp-parse.c b/argp/argp-parse.c index 99f8d9ecd4..90525cdf61 100644 --- a/argp/argp-parse.c +++ b/argp/argp-parse.c @@ -472,6 +472,7 @@ parser_init (struct parser *parser, const struct argp *argp, struct parser_sizes szs; struct _getopt_data opt_data = _GETOPT_DATA_INITIALIZER; + opt_data.optctxt = "command-line option"; szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1; szs.long_len = 0; szs.num_groups = 0; diff --git a/argp/tst-argphelp-localized.c b/argp/tst-argphelp-localized.c new file mode 100644 index 0000000000..abc3325827 --- /dev/null +++ b/argp/tst-argphelp-localized.c @@ -0,0 +1,102 @@ +/* Test program for argp argument parser + Copyright (C) 2025 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 + . */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PN_(ctxt, str) (str) + +const char *argp_program_version = "argphelp-test 1.0"; + +struct argp_option options[] = +{ + {PN_ ("command-line option", "color"), 'c', 0, 0, "Rainbow!"}, + {0} +}; + +static int color_set = 0; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + (void) state; + if (key == 'c' && color_set) + { + fprintf (stderr, "%s:%d: color already set.\n", __FILE__, __LINE__); + abort (); + } + else if (key == 'c') + { + color_set = 1; + } + return 0; +} + +static struct argp argp = { options, parse_opt }; + +int +main (int argc, char *argv[]) +{ + char *test1_argv[3] = + { (char *) "/bin/tst-argphelp-localized", (char *) "--colour", NULL }; + char *test2_argv[3] = + { (char *) "/bin/tst-argphelp-localized", (char *) "--help", NULL }; + + unsetenv ("LANGUAGE"); + setlocale (LC_ALL, "en_GB.UTF-8"); + if (bindtextdomain ("tst-argphelp-localized", OBJPFX "domaindir") == NULL) + { + fprintf (stderr, "%s:%d: cannot call bindtextdomain.\n", + __FILE__, __LINE__); + abort (); + } + if (textdomain ("tst-argphelp-localized") == NULL) + { + fprintf (stderr, "%s:%d: cannot call textdomain.\n", + __FILE__, __LINE__); + abort (); + } + /* Check that the catalog is OK: */ + if (strcmp (gettext ("command-line option\004color"), "colour") != 0) + { + fprintf (stderr, "%s:%d: the mo file does not work.\n", + __FILE__, __LINE__); + abort (); + } + argp_parse (&argp, 2, test1_argv, 0, 0, NULL); + if (!color_set) + { + fprintf (stderr, "%s:%d: color not set.\n", __FILE__, __LINE__); + abort (); + } + argp_parse (&argp, 2, test2_argv, 0, 0, NULL); + fprintf (stderr, "%s:%d: --help did not exit the program.\n", __FILE__, __LINE__); + abort (); + return 0; +} diff --git a/argp/tst-argphelp-localized.po b/argp/tst-argphelp-localized.po new file mode 100644 index 0000000000..4e301bf278 --- /dev/null +++ b/argp/tst-argphelp-localized.po @@ -0,0 +1,18 @@ +# English translations for a GNU C Library test. +# This file is distributed under the same license as the GNU C Library. +# +msgid "" +msgstr "" +"Project-Id-Version: tst-argphelp-localized\n" +"Report-Msgid-Bugs-To: \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" + +#: tst-argphelp-localized.c:73 +msgctxt "command-line option" +msgid "color" +msgstr "colour" \ No newline at end of file diff --git a/argp/tst-argpusage-localized.c b/argp/tst-argpusage-localized.c new file mode 100644 index 0000000000..4061609fc3 --- /dev/null +++ b/argp/tst-argpusage-localized.c @@ -0,0 +1,82 @@ +/* Test program for argp argument parser + Copyright (C) 2025 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 + . */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PN_(ctxt, str) (str) + +const char *argp_program_version = "argpusage-test 1.0"; + +struct argp_option options[] = +{ + {PN_ ("command-line option", "color"), 'c', 0, 0, "Rainbow!"}, + {0} +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + return 0; +} + +static struct argp argp = { options, parse_opt }; + +int +main (int argc, char *argv[]) +{ + char *test_argv[3] = + { (char *) "/bin/tst-argpusage-localized", (char *) "--usage", NULL }; + + unsetenv ("LANGUAGE"); + setlocale (LC_ALL, "en_GB.UTF-8"); + if (bindtextdomain ("tst-argphelp-localized", OBJPFX "domaindir") == NULL) + { + fprintf (stderr, "%s:%d: cannot call bindtextdomain.\n", + __FILE__, __LINE__); + abort (); + } + if (textdomain ("tst-argphelp-localized") == NULL) + { + fprintf (stderr, "%s:%d: cannot call textdomain.\n", + __FILE__, __LINE__); + abort (); + } + /* Check that the catalog is OK: */ + if (strcmp (gettext ("command-line option\004color"), "colour") != 0) + { + fprintf (stderr, "%s:%d: the mo file does not work.\n", + __FILE__, __LINE__); + abort (); + } + argp_parse (&argp, 2, test_argv, 0, 0, NULL); + fprintf (stderr, "%s:%d: --usage did not exit the program.\n", __FILE__, __LINE__); + abort (); + return 0; +} diff --git a/manual/argp.texi b/manual/argp.texi index 0023441812..97456ef20e 100644 --- a/manual/argp.texi +++ b/manual/argp.texi @@ -206,8 +206,10 @@ messages. @xref{Argp Help Filtering}. @item const char *argp_domain 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 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. @end table @end deftp @@ -233,7 +235,9 @@ beginning, the unused fields left unspecified. The @code{options} field in a @code{struct argp} points to a vector of @code{struct argp_option} structures, each of which specifies an option that the argp parser supports. Multiple entries may be used for a single -option provided it has multiple names. This should be terminated by an +option provided it has multiple names. In any case, option names are +translated, so either the translated or untranslated form is +recognized for each option. This should be terminated by an entry with zero in all fields. Note that when using an initialized C array for options, writing @code{@{ 0 @}} is enough to achieve this. @@ -247,9 +251,12 @@ the following fields: @item const char *name The long name for this option, corresponding to the long option @samp{--@var{name}}; this field may be zero if this option @emph{only} -has a short name. To specify multiple names for an option, additional -entries may follow this one, with the @code{OPTION_ALIAS} flag -set. @xref{Argp Option Flags}. +has a short name. You should mark this string for translation with +the fixed @samp{"command-line option"} context. To specify multiple +names for an option, additional entries may follow this one, with the +@code{OPTION_ALIAS} flag set. @xref{Argp Option Flags}. Translations +are added automatically, it is not necessary to use an alias for +translations. @item int key The integer key provided by the current option to the option parser. If @@ -323,7 +330,8 @@ This option isn't displayed in any help messages. This option is an alias for the closest previous non-alias option. This means that it will be displayed in the same help entry, and will inherit fields other than @code{name} and @code{key} from the option being -aliased. +aliased. It is not necessary to list the translation of an option +name as an alias. @item OPTION_DOC From patchwork Tue Oct 7 18:13:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121434 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 544D9385AC1C for ; Tue, 7 Oct 2025 18:16:22 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [IPv6:2a00:5881:4008:2810::309]) by sourceware.org (Postfix) with ESMTPS id 8659C3858C54 for ; Tue, 7 Oct 2025 18:15:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8659C3858C54 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8659C3858C54 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:5881:4008:2810::309 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860908; cv=none; b=li6y+1DfQwTKgU3kvB1sCu/ElPZMIMYilIqjxGXhB7/VOzPrQdbabzJS0cstjWRpNnSQXW+W0fG7MYktGMGo8Ql2LvD8+wfKDsKagSqOIOtC9ue1nsQZwPN0HgelMDMQEmg7edOi9uppMitcFoVI+CDFn7vah3wyz8gyS5f2/P8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860908; c=relaxed/simple; bh=SpSksadZFceEMGUfxJVJgL9oFRW0RBA6CWA0dCDneZM=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=RzgV0poKRxyzLYhxSPA38bcwuX52fWCf7WE4dy886eDQgOqP+/hU1MrJcJY9gAVnZ0sRXKD/mAGcpcSz+UDjxVxuxHDhHqrSNGiekSHdClC2YL0cx3DbgnR6XV4cktTf7ipSM9iJh+kunWP74yVU5Izxb+k4kO8iXM4uHUmrrjQ= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 562853c3 for ; Tue, 7 Oct 2025 18:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=albinoniA; bh=aJZ/GBL SWvdNSCiT02nkX5lwm9E=; b=fGrcYarm04kDdXs8GwxTyNHerN5HAJqtHxKr9nY 2oLfqm5reyIHzomV7JkOSuBBAaetR8zyAhT/mqtPBxS1oi3Dzx3giD6vcyawCZfh PUGrN2+oCv5MjjZBkXsGhW0mw4sxsITkbvvhwqf1L2xbs+KoPiqzMKgT6+1renaJ LFxwQ7DHBzTCQtxdQFjzB4yKU8b2wviSp/Op18E7DtvTET6kZBIMF0XKlQ2Drr0Y za7BPSM4cqqe9LcEVzSaq024vJWp24/T4BBEdZOyOr0LNOcbbeLeyN2nVOS/CDXh URFbTreAgjJ4VGkDynm73V4Ug1iUw14JP1R/t2AaCy0Ie6w== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 346b9ce1 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:53 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 4/9] posix: let the getopt caller choose the textdomain for translation Date: Tue, 7 Oct 2025 20:13:28 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Using the same solution as for the option translation context, a new opttextdomain variable is defined. Note that all options in the call to getopt_long are looked up in the same domain. --- manual/argp.texi | 7 +++-- manual/getopt.texi | 11 +++++-- posix/Versions | 2 +- posix/bits/getopt_ext.h | 5 ++++ posix/getopt.c | 30 ++++++++++++------- posix/getopt1.c | 15 +++++++--- posix/getopt_int.h | 11 ++++--- posix/tstgetoptl.c | 9 ++---- sysdeps/mach/hurd/i386/libc.abilist | 1 + sysdeps/mach/hurd/x86_64/libc.abilist | 1 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arc/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 + sysdeps/unix/sysv/linux/csky/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + .../sysv/linux/loongarch/lp64/libc.abilist | 1 + .../sysv/linux/m68k/coldfire/libc.abilist | 1 + .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + .../sysv/linux/microblaze/be/libc.abilist | 1 + .../sysv/linux/microblaze/le/libc.abilist | 1 + .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 + .../sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 + .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../powerpc/powerpc32/nofpu/libc.abilist | 1 + .../linux/powerpc/powerpc64/be/libc.abilist | 1 + .../linux/powerpc/powerpc64/le/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv32/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 + .../sysv/linux/sparc/sparc32/libc.abilist | 1 + .../sysv/linux/sparc/sparc64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 42 files changed, 94 insertions(+), 30 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 65e24f1143..20be0fba69 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 translated option names -will not be processed. +information. If this is @code{NULL} (the default), then the +translated option names will not be processed. +@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 5873e8ec56..d1c2cffcf9 100644 --- a/posix/Versions +++ b/posix/Versions @@ -160,7 +160,7 @@ libc { posix_spawn_file_actions_addtcsetpgrp_np; } GLIBC_2.43 { - optctxt; + optctxt; opttextdomain; } GLIBC_PRIVATE { __libc_fork; __libc_pread; __libc_pwrite; diff --git a/posix/bits/getopt_ext.h b/posix/bits/getopt_ext.h index 07d9407b64..6cd0932596 100644 --- a/posix/bits/getopt_ext.h +++ b/posix/bits/getopt_ext.h @@ -31,6 +31,11 @@ __BEGIN_DECLS names. If unset, the option names will not be translated. */ 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; #endif /* Describe the long-named options requested by the application. diff --git a/posix/getopt.c b/posix/getopt.c index 28f0be03f8..28c8aa4bbf 100644 --- a/posix/getopt.c +++ b/posix/getopt.c @@ -185,16 +185,20 @@ exchange (char **argv, struct _getopt_data *d) /* Return 1 iff translation_context is not NULL, a translation for opt_name has been found and it matches the substring from argument, length argument_length. + + The translate function pointer is like dpgettext. */ static const int -match_translated_option_name (char *(*translate) (const char *, const char *), +match_translated_option_name (char *(*translate) (const char *, const char *, + const char *), const char *argument, size_t argument_length, const char *translation_context, + const char *opt_textdomain, const char *opt_name) { const char *translated = opt_name; if (translate) - translated = translate (translation_context, opt_name); + translated = translate (opt_textdomain, translation_context, opt_name); return (!strncmp (translated, argument, argument_length) && argument_length == strlen (translated)); } @@ -212,7 +216,8 @@ process_long_option (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, int print_errors, const char *prefix, - char *(*translate) (const char *, const char *)) + char *(*translate) (const char *, const char *, + const char *)) { char *nameend; size_t namelen; @@ -243,9 +248,9 @@ process_long_option (int argc, char **argv, const char *optstring, /* Didn't find an exact match, try with translated option names. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (match_translated_option_name (translate, - d->__nextchar, namelen, - d->optctxt, p->name)) + if (match_translated_option_name (translate, d->__nextchar, namelen, + d->optctxt, d->opttextdomain, + p->name)) { /* Exact match found with translation. */ pfound = p; @@ -369,7 +374,7 @@ 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 (d->optctxt, pfound->name); + translated_option_name = translate (d->opttextdomain, d->optctxt, pfound->name); if (*nameend) { /* Don't test has_arg with >, because some C compilers don't @@ -535,7 +540,8 @@ int _getopt_internal_r (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, int posixly_correct, - char *(*translate) (const char *, const char *)) + char *(*translate) (const char *, const char *, + const char *)) { int print_errors = d->opterr; @@ -771,14 +777,16 @@ int _getopt_internal (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, int posixly_correct, - char *(*translate) (const char *, const char *), - const char *ctxt) + char *(*translate) (const char *, const char *, const char *), + const char *ctxt, + const char *domain) { int result; getopt_data.optind = optind; getopt_data.opterr = opterr; getopt_data.optctxt = ctxt; + getopt_data.opttextdomain = domain; result = _getopt_internal_r (argc, argv, optstring, longopts, longind, long_only, &getopt_data, @@ -801,7 +809,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); \ } #ifdef _LIBC diff --git a/posix/getopt1.c b/posix/getopt1.c index 28d090019d..48852dc692 100644 --- a/posix/getopt1.c +++ b/posix/getopt1.c @@ -34,9 +34,14 @@ const char *optctxt = NULL; +/* Callers store the textdomain in which the option names are to be + looked up. */ + +const char *opttextdomain = NULL; + /* FIXME: use pgettext_expr. */ static char * -do_translate (const char *context, const char *msgid) +do_translate (const char *domain, const char *context, const char *msgid) { char *full_msgid; const char *translated = msgid; @@ -49,7 +54,7 @@ do_translate (const char *context, const char *msgid) strcpy (full_msgid, context); full_msgid[strlen (context)] = '\004'; strcpy (full_msgid + strlen (context) + 1, msgid); - translated = __dcgettext (NULL, full_msgid, LC_MESSAGES); + translated = __dcgettext (domain, full_msgid, LC_MESSAGES); if (!strcmp (translated, full_msgid)) { translated = msgid; @@ -67,7 +72,8 @@ 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); + opt_index, 0, 0, do_translate, + optctxt, opttextdomain); } int @@ -90,7 +96,8 @@ getopt_long_only (int argc, char *__getopt_argv_const *argv, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, (char **) argv, options, long_options, - opt_index, 1, 0, do_translate, optctxt); + opt_index, 1, 0, do_translate, + optctxt, opttextdomain); } int diff --git a/posix/getopt_int.h b/posix/getopt_int.h index 1d091979c3..1deb6cad35 100644 --- a/posix/getopt_int.h +++ b/posix/getopt_int.h @@ -24,13 +24,14 @@ /* The translate argument here is optional (can be NULL), it is used to avoid depending on the gettext functions in the posix getopt - function. */ + function. It is like dpgettext. */ extern int _getopt_internal (int ___argc, char **___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only, int __posixly_correct, - char *(*translate) (const char *, const char *), - const char *__optctxt); + char *(*translate) (const char *, const char *, + const char *), + const char *__optctxt, const char *__optdomain); /* Reentrant versions which can handle parsing multiple argument @@ -73,6 +74,7 @@ struct _getopt_data int optopt; char *optarg; const char *optctxt; + const char *opttextdomain; /* Internal members. */ @@ -109,7 +111,8 @@ extern int _getopt_internal_r (int ___argc, char **___argv, const struct option *__longopts, int *__longind, int __long_only, struct _getopt_data *__data, int __posixly_correct, - char *(*translate) (const char *, const char *)); + char *(*translate) (const char *, const char *, + const char *)); extern int _getopt_long_r (int ___argc, char **___argv, const char *__shortopts, diff --git a/posix/tstgetoptl.c b/posix/tstgetoptl.c index 5ff1ba75c4..ba9dbe4222 100644 --- a/posix/tstgetoptl.c +++ b/posix/tstgetoptl.c @@ -44,13 +44,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; @@ -62,6 +57,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'}, @@ -89,6 +85,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) { diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist index ef2389889d..d879f5a363 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2665,6 +2665,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.43 pthread_cancel F GLIBC_2.43 pthread_clockjoin_np F GLIBC_2.43 pthread_detach F diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist index 366f44b7b3..4b6580b2cc 100644 --- a/sysdeps/mach/hurd/x86_64/libc.abilist +++ b/sysdeps/mach/hurd/x86_64/libc.abilist @@ -2346,6 +2346,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 GLIBC_2.43 pthread_cancel F GLIBC_2.43 pthread_clockjoin_np F GLIBC_2.43 pthread_detach F diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index b5adb590b1..93730d969e 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2770,3 +2770,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index c97471e756..06412be15c 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -3117,6 +3117,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index 7dd4589884..e0c6c9f293 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2531,3 +2531,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index 35a50182f2..7929ecb5ce 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2823,6 +2823,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index 70f444545a..4b7ca1bdf0 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2820,6 +2820,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 83ac7a3a4f..326be1421c 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2807,3 +2807,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 85cfee194d..31be97a20d 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2844,6 +2844,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index dea2312c5c..3100d3720d 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -3027,6 +3027,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index bde525090d..521343313d 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2291,3 +2291,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 89f275f92c..974a643266 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2803,6 +2803,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 071de9934e..474da3c6e6 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2970,6 +2970,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index a983dd9776..3772bbf961 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2856,3 +2856,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index d8c4d03cee..81fdbf5528 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2853,3 +2853,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 8431dca4fc..8bf825fbd0 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2933,6 +2933,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index ff0d3bcb1b..3995eb7112 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2931,6 +2931,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 834ca53a26..c7f9d75936 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2939,6 +2939,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index e8dcdec523..fa4c0b6abb 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2841,6 +2841,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index f69e29d8ec..685e674205 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2281,3 +2281,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 313b5ac2c2..b739c5b3dd 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -3160,6 +3160,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index 9ac04c675a..25a45c7596 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -3205,6 +3205,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index 030c44cfd6..88979415c3 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2914,6 +2914,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index ba27c807a8..f55d5abaa1 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2990,3 +2990,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index 59901b5a84..d644e2b658 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2534,3 +2534,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index d861e9348a..8f90416e6f 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2734,3 +2734,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 94eddb2157..2eb7244ede 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -3158,6 +3158,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index a8279df601..0418207b55 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2951,6 +2951,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index dab732c1d3..c882ecd323 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2850,6 +2850,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index 54fc47ab6c..d8ad0073b8 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2847,6 +2847,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index b73cd54dbb..fee6128da5 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3181,6 +3181,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index dcd144bb46..78e1358a87 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2817,6 +2817,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index b9549a8de1..33afb283fa 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2766,6 +2766,7 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 +GLIBC_2.43 opttextdomain D 0x8 GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 35fc746c3b..6bf8159064 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2785,3 +2785,4 @@ GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 +GLIBC_2.43 opttextdomain D 0x4 From patchwork Tue Oct 7 18:13:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121435 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 89C323857013 for ; Tue, 7 Oct 2025 18:17:16 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 89C323857013 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu header.a=rsa-sha1 header.s=albinoniA header.b=RdLW30WP X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [89.234.140.182]) by sourceware.org (Postfix) with ESMTPS id 528473858C51 for ; Tue, 7 Oct 2025 18:15:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 528473858C51 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 528473858C51 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=89.234.140.182 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860912; cv=none; b=h9Rzg0MqJnjASnIYFD5SMdfYSGPwqmimfpiQxP+On5vIQx80qRhA8ylXOejGVcfSDWI17d9WNcun4l8p8MFbuAyl+LajTcbcGQedbFJgDhBefGtYQUSrJ7wuzdBSogEm7gIKnIOPETEgob6rpa2u6E1waSw3K6abNaZezZXUQ+k= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860912; c=relaxed/simple; bh=pFeScogVsVHltSxR64iiyM6D/ktitB952on31L9+m00=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=MQKbJCaKo5ljH/LQFUqZNAXcbDgAxs1ZBVDFwN2y8LALmgTPZ4CJ7CsiRuftSO9eyVKoL7IVArLlYUWQ9EvNHl55VfCjuQ7H6va/7kVh9h+T7ivyxddZPhVk7wX2sJtwoHe1g5h7jVA8yzTacCo4rItmuNxXXhb2ioIUjNOOGxE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 528473858C51 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 42be1b08 for ; Tue, 7 Oct 2025 18:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=albinoniA; bh=+67GtQE RnH6fW8O5QRp4KkqN3wY=; b=RdLW30WPKiDgDacS+QxF/zsqmD6FCQx0Ttt+Wiy Frss/Tio10kerHsFe/k8m9KqEVaYy8fCoah0Kn4qGVXA549W64Satu8df0wRxZKf 1zxEI/zHoGN/PcL9nQzmyDazQRHY0RsX0LYZV4dk79fvsR8Z/YxJRwcETBchtRE5 2Xoyi7FInZskCC94azEnDJM0z30r8boDvjVTLCd1lNTT3hzNHBRQRTXu98fGYV7Q 7ht3xAUOUuq2Mhk7vFshKLvv6Jmoi+braB48S0Bo7dLwLwKBSko7+zh8g1ebNGXM ZRlT2AuLlapuHHQ1Zu8UyhCsaKRhqJYOXFbM9bn2otPY23A== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 6362b4b5 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:53 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 5/9] posix: do not allow option name translations for secure programs Date: Tue, 7 Oct 2025 20:13:29 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org SETUID / SETGID / AT_SECURE programs should not accept translated names, so that the programmer knows exactly how the program can be invoked. --- posix/getopt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posix/getopt.c b/posix/getopt.c index 28c8aa4bbf..6b235fa4e3 100644 --- a/posix/getopt.c +++ b/posix/getopt.c @@ -197,7 +197,7 @@ match_translated_option_name (char *(*translate) (const char *, const char *, const char *opt_name) { const char *translated = opt_name; - if (translate) + if (translate != NULL && !__libc_enable_secure) translated = translate (opt_textdomain, translation_context, opt_name); return (!strncmp (translated, argument, argument_length) && argument_length == strlen (translated)); From patchwork Tue Oct 7 18:13:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121438 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 54E1938560AF for ; Tue, 7 Oct 2025 18:18:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 54E1938560AF Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu header.a=rsa-sha1 header.s=albinoniA header.b=jXdFJgNU X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [IPv6:2a00:5881:4008:2810::309]) by sourceware.org (Postfix) with ESMTPS id 696E83858C66 for ; Tue, 7 Oct 2025 18:15:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 696E83858C66 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 696E83858C66 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:5881:4008:2810::309 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860912; cv=none; b=c8uPj0W4cWWPgoUrfj+KdDz6qGW3xrzSNyCVKgQgKaH1HgGwHEinFFcPgnw84D/bZSWAytCzkxtQlK6A0qAswskiQrvAr5r99uxrp6Caw2t1zgXaU6zEkgKM4uhxdSQBeEJx5QKGNzPBf2PMGZ2z1x3kYLhI1nsJkSbn3Sfk+DI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860912; c=relaxed/simple; bh=PksPkds4YzRfcaw26Q7z68IGCvy9qJU017+81WDxoAA=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=joeWBwA1OqQZLm11JbEBpx1we92IGrc1INJqeaC3x7hYIW5yuF/+DhqyMbH/EYxT5Acvdsr9YCNwLFvGddvQgYETywQXFw/3cTt7cXwy6gO+oW9JuQ3k/admZ8JYAIJ9Pb56pJycAFP6Y3WYBOYzASKsOvLLA6nJvHVl099iJ2M= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 696E83858C66 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id cfdd4994 for ; Tue, 7 Oct 2025 18:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s= albinoniA; bh=ptTAW4ZxyuCHrAO5DmMoeUEc8Fg=; b=jXdFJgNUoW63o6jWWp NHXbLJ0cmVnQfS17bYUwl8+NrwrtVx5AB7UxldwSQpD/jkpNDGFvQ38awwnkhn+f DGtTb+NN8j16ic6/gcunmw2q2tV75gjDt7xn6UKtqvs0OYNzU/N4PQIqyLYOReFj /wDmjgXemkQmxWppLWM6ie90jds09b728XZO+JGN9Zd6th4Mi3j6Q1tzhv9jHqK9 F9NoFJh3fqFyxcmcHh9pQhUZy4BCU7zxjS0mWiWUDBFExr7Oi8L7tMCA4HDa6Cs/ O0GFrFf35JpV3U20Hp8OMV4zhHZB+IkrYivfFYrvVg8DWjSRWu64G7+TDzJDEHXh TNKA== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id f0e76799 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:53 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 6/9] posix, argp: Support deprecation of long option name translations Date: Tue, 7 Oct 2025 20:13:30 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org The translation for an option name is expected to be a space-separated list. The first field is the canonical translation. The other fields are deprecated translations. getopt will warn if they are recognized, and argp will not print them in help or usage output. I chose a space because it would be a bad choice to have a space character in an option name. --- argp/argp-help.c | 101 +++++++++++++++++++-------------- argp/tst-argphelp-localized.c | 69 +++++++++++++++++++++- argp/tst-argphelp-localized.po | 7 ++- argp/tst-argpusage-localized.c | 2 +- manual/getopt.texi | 5 ++ posix/Makefile | 2 +- posix/getopt.c | 62 +++++++++++++++++++- posix/tstgetoptl.c | 19 +++++-- posix/tstgetoptl.po | 4 +- 9 files changed, 214 insertions(+), 57 deletions(-) diff --git a/argp/argp-help.c b/argp/argp-help.c index 672e733fc8..08650ea5b1 100644 --- a/argp/argp-help.c +++ b/argp/argp-help.c @@ -1205,6 +1205,45 @@ comma (unsigned col, struct pentry_state *pest) indent_to (pest->stream, col); } +/* Return the canonical translation of an option name. There might be + multiple alternative translation for backward compatibility, but + only one should be documented. */ +static const char * +canonical_option_translation (const char *option_name, + char **allocated) +{ + char *option_msgid; + const char *all_names = option_name; + size_t canonical_length; + static const char *default_context = "command-line option\004"; + *allocated = NULL; + option_msgid = malloc (strlen (default_context) + strlen (option_name) + 1); + all_names = NULL; + if (option_msgid) + { + strcpy (option_msgid, default_context); + strcat (option_msgid, option_name); + all_names = gettext (option_msgid); + if (strcmp (all_names, option_msgid) == 0) + all_names = option_name; + } + if (strcmp (all_names, option_name) == 0) + all_names = option_name; + free (option_msgid); + if (strchr (all_names, ' ')) + { + canonical_length = strchr (all_names, ' ') - all_names; + *allocated = malloc (canonical_length + 1); + if (*allocated != NULL) + { + memcpy (*allocated, all_names, canonical_length); + (*allocated)[canonical_length] = '\0'; + all_names = *allocated; + } + } + return all_names; +} + /* Print help for ENTRY to STREAM. */ static void hol_entry_help (struct hol_entry *entry, const struct argp_state *state, @@ -1213,8 +1252,8 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state, unsigned num; const struct argp_option *real = entry->opt, *opt; char *so = entry->short_options; - char *option_msgid; - const char *translated_option_name; + char *canonical_translation_buffer; + const char *canonical_translation; int have_long_opt = 0; /* We have any long options. */ /* Saved margins. */ int old_lm = __argp_fmtstream_set_lmargin (stream, 0); @@ -1278,25 +1317,15 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state, if (opt->name && ovisible (opt)) { comma (uparams.long_opt_col, &pest); - option_msgid = - malloc (strlen ("command-line option\004") - + strlen (opt->name) + 1); - if (option_msgid) - { - strcpy (option_msgid, "command-line option\004"); - strcat (option_msgid, opt->name); - translated_option_name = gettext (option_msgid); - if (!strcmp (translated_option_name, option_msgid)) - translated_option_name = opt->name; - } - else - translated_option_name = opt->name; - __argp_fmtstream_printf (stream, "--%s", translated_option_name); + canonical_translation = + canonical_option_translation (opt->name, + &canonical_translation_buffer); + __argp_fmtstream_printf (stream, "--%s", canonical_translation); arg (real, "=%s", "[=%s]", state == NULL ? NULL : state->root_argp->argp_domain, stream); - if (strcmp (translated_option_name, opt->name)) + if (strcmp (canonical_translation, opt->name)) __argp_fmtstream_printf (stream, " (--%s)", opt->name); - free (option_msgid); + free (canonical_translation_buffer); } } @@ -1438,8 +1467,8 @@ usage_long_opt (const struct argp_option *opt, { argp_fmtstream_t stream = cookie; const char *arg = opt->arg; - char *option_msgid; - const char *translated_opt_name = opt->name; + const char *canonical_translation = opt->name; + char *canonical_translation_buffer; int flags = opt->flags | real->flags; if (! arg) @@ -1447,41 +1476,29 @@ usage_long_opt (const struct argp_option *opt, if (! (flags & OPTION_NO_USAGE)) { - /* Since we cannot customize the translation context, we will - use a default one. FIXME: use pgettext_expr(). */ - static const char *default_context = "command-line option\004"; - option_msgid = malloc (strlen (default_context) + strlen (opt->name) + 1); - translated_opt_name = NULL; - if (option_msgid) - { - strcpy (option_msgid, default_context); - strcat (option_msgid, opt->name); - translated_opt_name = gettext (option_msgid); - if (!strcmp (translated_opt_name, option_msgid)) - translated_opt_name = opt->name; - } - if (!strcmp (translated_opt_name, opt->name)) - translated_opt_name = NULL; + canonical_translation = + canonical_option_translation (opt->name, &canonical_translation_buffer); if (arg) { arg = dgettext (domain, arg); - if ((flags & OPTION_ARG_OPTIONAL) && translated_opt_name) + if ((flags & OPTION_ARG_OPTIONAL) + && strcmp (canonical_translation, opt->name) != 0) __argp_fmtstream_printf (stream, " [--%s[=%s] (--%s)]", - translated_opt_name, arg, opt->name); + canonical_translation, arg, opt->name); else if (flags & OPTION_ARG_OPTIONAL) __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg); - else if (translated_opt_name) + else if (strcmp (canonical_translation, opt->name) != 0) __argp_fmtstream_printf (stream, " [--%s=%s (--%s)]", - translated_opt_name, arg, opt->name); + canonical_translation, arg, opt->name); else __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg); } - else if (translated_opt_name) + else if (strcmp (canonical_translation, opt->name) != 0) __argp_fmtstream_printf (stream, " [--%s (--%s)]", - translated_opt_name, opt->name); + canonical_translation, opt->name); else __argp_fmtstream_printf (stream, " [--%s]", opt->name); - free (option_msgid); + free (canonical_translation_buffer); } return 0; diff --git a/argp/tst-argphelp-localized.c b/argp/tst-argphelp-localized.c index abc3325827..214f0d992f 100644 --- a/argp/tst-argphelp-localized.c +++ b/argp/tst-argphelp-localized.c @@ -37,10 +37,14 @@ const char *argp_program_version = "argphelp-test 1.0"; struct argp_option options[] = { {PN_ ("command-line option", "color"), 'c', 0, 0, "Rainbow!"}, + {PN_ ("command-line option", "flavor"), 'f', 0, 0, "Sweet!"}, + {PN_ ("command-line option", "texture"), 't', 0, 0, "Smooth!"}, {0} }; static int color_set = 0; +static int flavor_set = 0; +static int texture_set = 0; static error_t parse_opt (int key, char *arg, struct argp_state *state) @@ -55,6 +59,24 @@ parse_opt (int key, char *arg, struct argp_state *state) { color_set = 1; } + if (key == 'f' && flavor_set) + { + fprintf (stderr, "%s:%d: flavor already set.\n", __FILE__, __LINE__); + abort (); + } + else if (key == 'f') + { + flavor_set = 1; + } + else if (key == 't' && texture_set) + { + fprintf (stderr, "%s:%d: texture already set.\n", __FILE__, __LINE__); + abort (); + } + else if (key == 't') + { + texture_set = 1; + } return 0; } @@ -66,6 +88,16 @@ main (int argc, char *argv[]) char *test1_argv[3] = { (char *) "/bin/tst-argphelp-localized", (char *) "--colour", NULL }; char *test2_argv[3] = + { (char *) "/bin/tst-argphelp-localized", (char *) "--color", NULL }; + char *test3_argv[3] = + { (char *) "/bin/tst-argphelp-localized", (char *) "--coolur", NULL }; + char *test4_argv[3] = + { (char *) "/bin/tst-argphelp-localized", (char *) "--flavour", NULL }; + char *test5_argv[3] = + { (char *) "/bin/tst-argphelp-localized", (char *) "--flavor", NULL }; + char *test6_argv[3] = + { (char *) "/bin/tst-argphelp-localized", (char *) "--texture", NULL }; + char *test7_argv[3] = { (char *) "/bin/tst-argphelp-localized", (char *) "--help", NULL }; unsetenv ("LANGUAGE"); @@ -83,7 +115,7 @@ main (int argc, char *argv[]) abort (); } /* Check that the catalog is OK: */ - if (strcmp (gettext ("command-line option\004color"), "colour") != 0) + if (strcmp (gettext ("command-line option\004color"), "colour coolur") != 0) { fprintf (stderr, "%s:%d: the mo file does not work.\n", __FILE__, __LINE__); @@ -95,7 +127,42 @@ main (int argc, char *argv[]) fprintf (stderr, "%s:%d: color not set.\n", __FILE__, __LINE__); abort (); } + color_set = 0; argp_parse (&argp, 2, test2_argv, 0, 0, NULL); + if (!color_set) + { + fprintf (stderr, "%s:%d: color not set.\n", __FILE__, __LINE__); + abort (); + } + color_set = 0; + argp_parse (&argp, 2, test3_argv, 0, 0, NULL); + if (!color_set) + { + fprintf (stderr, "%s:%d: color not set.\n", __FILE__, __LINE__); + abort (); + } + flavor_set = 0; + argp_parse (&argp, 2, test4_argv, 0, 0, NULL); + if (!flavor_set) + { + fprintf (stderr, "%s:%d: flavor not set.\n", __FILE__, __LINE__); + abort (); + } + flavor_set = 0; + argp_parse (&argp, 2, test5_argv, 0, 0, NULL); + if (!flavor_set) + { + fprintf (stderr, "%s:%d: flavor not set.\n", __FILE__, __LINE__); + abort (); + } + texture_set = 0; + argp_parse (&argp, 2, test6_argv, 0, 0, NULL); + if (!flavor_set) + { + fprintf (stderr, "%s:%d: texture not set.\n", __FILE__, __LINE__); + abort (); + } + argp_parse (&argp, 2, test7_argv, 0, 0, NULL); fprintf (stderr, "%s:%d: --help did not exit the program.\n", __FILE__, __LINE__); abort (); return 0; diff --git a/argp/tst-argphelp-localized.po b/argp/tst-argphelp-localized.po index 4e301bf278..e87330f7b5 100644 --- a/argp/tst-argphelp-localized.po +++ b/argp/tst-argphelp-localized.po @@ -15,4 +15,9 @@ msgstr "" #: tst-argphelp-localized.c:73 msgctxt "command-line option" msgid "color" -msgstr "colour" \ No newline at end of file +msgstr "colour coolur" + +#: tst-argphelp-localized.c:74 +msgctxt "command-line option" +msgid "flavor" +msgstr "flavour" \ No newline at end of file diff --git a/argp/tst-argpusage-localized.c b/argp/tst-argpusage-localized.c index 4061609fc3..bb8865bc99 100644 --- a/argp/tst-argpusage-localized.c +++ b/argp/tst-argpusage-localized.c @@ -69,7 +69,7 @@ main (int argc, char *argv[]) abort (); } /* Check that the catalog is OK: */ - if (strcmp (gettext ("command-line option\004color"), "colour") != 0) + if (strcmp (gettext ("command-line option\004color"), "colour coolur") != 0) { fprintf (stderr, "%s:%d: the mo file does not work.\n", __FILE__, __LINE__); diff --git a/manual/getopt.texi b/manual/getopt.texi index 20be0fba69..7834f1c2a3 100644 --- a/manual/getopt.texi +++ b/manual/getopt.texi @@ -228,6 +228,11 @@ communication involves the invocation of your program, the program users should be encouraged to use untranslated option names, or publish the locale used for this invocation. +If the translation of an option name contains a space character, then +it means multiple translations recognize the same option name. This +is useful to upgrade a translation without disrupting the user's +workflow. + @deftp {Data Type} {struct option} @standards{GNU, getopt.h} This structure describes a single long option name for the sake of diff --git a/posix/Makefile b/posix/Makefile index 1c787f53fb..1a2cdb053f 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -614,7 +614,7 @@ CFLAGS-fork.c = $(libio-mtsafe) $(config-cflags-wno-ignored-attributes) tstgetopt-ARGS = -a -b -cfoobar --required foobar --optional=bazbug \ --none random --col --color --colour -tstgetoptl-ARGS = $(tstgetopt-ARGS) +tstgetoptl-ARGS = $(tstgetopt-ARGS) --coolur tst-exec-ARGS = -- $(host-test-program-cmd) tst-exec-static-ARGS = $(tst-exec-ARGS) diff --git a/posix/getopt.c b/posix/getopt.c index 6b235fa4e3..55afde8b4c 100644 --- a/posix/getopt.c +++ b/posix/getopt.c @@ -191,16 +191,70 @@ exchange (char **argv, struct _getopt_data *d) static const int match_translated_option_name (char *(*translate) (const char *, const char *, const char *), + const char *program_name, const char *prefix, const char *argument, size_t argument_length, const char *translation_context, const char *opt_textdomain, const char *opt_name) { const char *translated = opt_name; + /* Multiple alternative names can be provided by the translator, so + that continuous improvement of translations is possible. To + allow multiple translations, separate the translation with a + space character. */ + int canonical = 1; + const char *names_list; + const char *next_item; + size_t canonical_length; + char *canonical_name; + char *matched_name; + size_t item_length; if (translate != NULL && !__libc_enable_secure) translated = translate (opt_textdomain, translation_context, opt_name); - return (!strncmp (translated, argument, argument_length) - && argument_length == strlen (translated)); + if (strlen (translated) == argument_length + && strncmp (translated, argument, argument_length) == 0 + && !strchr (translated, ' ')) + return 1; + else if (!strchr (translated, ' ')) + return 0; + names_list = translated; + while (names_list != NULL) + { + item_length = strlen (names_list); + next_item = strchr (names_list, ' '); + if (next_item) + { + item_length = next_item - names_list; + next_item++; + } + if (item_length == argument_length + && strncmp (names_list, argument, argument_length) == 0) + { + if (!canonical) + { + canonical_length = strchr (translated, ' ') - translated; + canonical_name = malloc (canonical_length + 1); + matched_name = malloc (item_length + 1); + if (canonical_name != NULL && matched_name != NULL) + { + memcpy (canonical_name, translated, canonical_length); + canonical_name[canonical_length] = '\0'; + memcpy (matched_name, names_list, item_length); + matched_name[item_length] = '\0'; + fprintf (stderr, _("%s: option '%s%s' is deprecated, use '%s%s' instead\n"), + program_name, + prefix, matched_name, + prefix, canonical_name); + } + free (canonical_name); + free (matched_name); + } + return 1; + } + canonical = 0; + names_list = next_item; + } + return 0; } /* Process the argument starting with d->__nextchar as a long option. @@ -248,7 +302,9 @@ process_long_option (int argc, char **argv, const char *optstring, /* Didn't find an exact match, try with translated option names. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (match_translated_option_name (translate, d->__nextchar, namelen, + if (match_translated_option_name (translate, + argv[0], prefix, + d->__nextchar, namelen, d->optctxt, d->opttextdomain, p->name)) { diff --git a/posix/tstgetoptl.c b/posix/tstgetoptl.c index ba9dbe4222..38442c827e 100644 --- a/posix/tstgetoptl.c +++ b/posix/tstgetoptl.c @@ -27,8 +27,12 @@ two different options with the same short name, it has only one, and the other one is a translation. */ -/* This uses the en_GB locale so that colour means color. As a - special case, we also check that non-translated options have +/* This uses the en_GB locale so that colour means color. Oh no! The + translator made a mistake and translated with “coolur”. A bug-fix + has been released, but it has been decided to support both “colour” + and “coolur” with a deprecation warning. + + As a special case, we also check that non-translated options have precedence over translated options, by translated "optional" as "required". */ @@ -45,7 +49,9 @@ prepare_localedir (void) return -1; } /* Check that the catalog is OK: */ - if (strcmp (dgettext ("tstgetoptl", TRANSLATION_CONTEXT "\004" "color"), "colour") != 0) + if (strcmp (dgettext ("tstgetoptl", + TRANSLATION_CONTEXT "\004" "color"), + "colour coolur") != 0) { fputs ("The mo file does not work.\n", stderr); return -1; @@ -64,11 +70,12 @@ main (int argc, char **argv) {"optional", optional_argument, NULL, 'o'}, {"none", no_argument, NULL, 'n'}, {"color", no_argument, NULL, 'C'}, - /* Now colour is handled as a translation of color */ + /* Now colour (and coolur) is handled as a translation of color */ {NULL, 0, NULL, 0 } }; - /* The rest of the function is the same as in tstgetopt.c. */ + /* The rest of the function is the same as in tstgetopt.c, except we + expect 4 instances of -C instead of just 3. */ int aflag = 0; int bflag = 0; @@ -126,7 +133,7 @@ main (int argc, char **argv) aflag, bflag, cvalue, Cflag, nflag); result |= (aflag != 1 || bflag != 1 || cvalue == NULL - || strcmp (cvalue, "foobar") != 0 || Cflag != 3 || nflag != 1); + || strcmp (cvalue, "foobar") != 0 || Cflag != 4 || nflag != 1); for (index = optind; index < argc; index++) printf ("Non-option argument %s\n", argv[index]); diff --git a/posix/tstgetoptl.po b/posix/tstgetoptl.po index e060c0d6e3..f418776a6b 100644 --- a/posix/tstgetoptl.po +++ b/posix/tstgetoptl.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: tstgetoptl 0.0.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-05-27 19:29+0200\n" -"PO-Revision-Date: 2025-05-27 19:30+0200\n" +"PO-Revision-Date: 2025-06-06 21:22+0200\n" "Language-Team: English (British) <(nothing)>\n" "Language: en_GB\n" "MIME-Version: 1.0\n" @@ -18,7 +18,7 @@ msgstr "" #: xxx.c:yy msgctxt "command-line option" msgid "color" -msgstr "colour" +msgstr "colour coolur" # This is to make sure the translator cannot redirect options. #: xxx.c:yy From patchwork Tue Oct 7 18:13:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121441 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6698A3861035 for ; Tue, 7 Oct 2025 18:21:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6698A3861035 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu header.a=rsa-sha1 header.s=albinoniA header.b=WxS57kgI X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [89.234.140.182]) by sourceware.org (Postfix) with ESMTPS id CFFDC3858C2F for ; Tue, 7 Oct 2025 18:15:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CFFDC3858C2F Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CFFDC3858C2F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=89.234.140.182 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860916; cv=none; b=U8BY64MFAJkYoZBpjQEzcd+zkkudwGTVnl2yFYSPMoQpD95OQ2SaGVxhPb6lR3srKZCdAygzLH75U40ST752j6Ub/AA5cSNY1tLp3pDkqZt4IzBaECG+Vf5hEXaXN1lhkSbHGn4XqorSmyixnCvlW4eQhWOpylDOe1NmWI69BDc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860916; c=relaxed/simple; bh=XVSlSjIr4Gttwmw05dQ4lmSOcOfpA4Mq2j4Jr/d2kQ0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=CFvAOp3gmXIZHCpnZwByq3bnNT3Jdd/D166TcENi58oK3HbRvpbZOla6bml1tVAHC/c7wxlV6+oaZLpZcLfRlVk3wUJNb3XOlMPMpduwvB1XsOTof4qDcz98bhPRBwNj89B5yNuW5cNO53yyU/ji2cypKAXvgWNuvE8pl4NYMho= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CFFDC3858C2F Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id af7fba7e for ; Tue, 7 Oct 2025 18:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=albinoniA; bh=nm+0/hz Q/jKc0er7I4ELF/bHmco=; b=WxS57kgIeHLTCYfNbQDxkraKO65F1+XxjJszcTo t14TX2XbUUO/MstAXlYYu3vOqLkbYrWzodjuOMZfHW6ZbMHM13pCRS9XpCKqDZTY WNyMeN6cF0m+3i3DA8oNNB2pYFCrUwfO23csCYZvZ3u+8FtnozNEYF8LEB+MoSRp hniVtK0aphUYaqkwCPqVpeaQ7oQfvfIv6hDEQNq8NP3+J1XsMQ9ra9LRaUkpfL3u xhPcGd3HYRBSE2LMn80dc5jtBoOeqKlCwLARRClsMZxSt/q0WWQV98hegX4VJIDy div/p+SOOrcW75dV01Fdrr9NcK+hSPpxpSWnOSapHIf29XA== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id b6dc25eb (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:55 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 7/9] argp: do not display option name translations if __libc_enable_secure Date: Tue, 7 Oct 2025 20:13:31 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org --- argp/argp-help.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/argp/argp-help.c b/argp/argp-help.c index 08650ea5b1..2feb2a1ac6 100644 --- a/argp/argp-help.c +++ b/argp/argp-help.c @@ -1217,6 +1217,9 @@ canonical_option_translation (const char *option_name, size_t canonical_length; static const char *default_context = "command-line option\004"; *allocated = NULL; + if (__libc_enable_secure) + /* Translations are disabled. */ + return option_name; option_msgid = malloc (strlen (default_context) + strlen (option_name) + 1); all_names = NULL; if (option_msgid) From patchwork Tue Oct 7 18:13:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121439 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DE5F73856082 for ; Tue, 7 Oct 2025 18:18:17 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [IPv6:2a00:5881:4008:2810::309]) by sourceware.org (Postfix) with ESMTPS id EAD553858C31 for ; Tue, 7 Oct 2025 18:15:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org EAD553858C31 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org EAD553858C31 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:5881:4008:2810::309 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860916; cv=none; b=rZmCuOD4PDAlRMYFTOAYA0ZwAyJJXOEmk9O9LDOzywIrAywptPFco98ZdQW97I0gLP9Mz4XD0yD36A69cmvZxEr9Lq5nCk+d0fEgk3pYa9XR7SmeoIvFhL6DFlEohqJVvO9SOO3w0Seh1uhVutN4au3aBHjJdWiX5q3rlUMbzKI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860916; c=relaxed/simple; bh=Plmix1SlIKxDRg5fF8eb6DMGI0whnc0IdbJD/DQbgAY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=uhAxeG617pNZCPmh4jYRWu1F0RNVRN1K2ty5nHxtZMwbjHB+WslTiG34JmR/OztV8Sf6wpcA1GBufdMic239PtBH1Dwy5/hl0bZHRetW7mGJt/i6Nv3mIs+6CM4tIlTE6SlposZfTEHBUOQx/VrIHOd3CS7IgFFrVmGvKrw38Nw= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id f2e0b6e7 for ; Tue, 7 Oct 2025 18:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s= albinoniA; bh=I45pg+PN4oLXcXD0yaSk8pkSi+I=; b=cZSLS6DpgkXchF6kyC +6BfyBonikjcbd9z/iX0pq0uWOm958WogD8Z+t9Pr9uFy3CiQwsE2rBpahyzIBEL 8AysbIE5fyMMZW7vHjf5l55AbZBWLwBnezlSIK65tHavd3rOFB6fRMmvoRQi3z5B 0EvHiin5Y4Cnd9lYFi2RrLzS8IOAE8ZKTVyx+CyGKuaUsn8jIhOKRxWKl8H8WPhK SFbrCqbn0hYQ2ls+vP8lsed7KIvJ08zWppVlRs3B09jYD0dyDBw1WqQhpCizruEt 6fM1j0jtefMaIrjWt+ATnCCfJdD3gnhdoQo8LHbvWdgFq91IxGrr9lMoVESossTa hE7A== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id a37f8df0 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:55 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 8/9] posix: Add getopt_long_collision Date: Tue, 7 Oct 2025 20:13:32 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org This function is used before introducing a new option name with all known linguas to check that no translator has used the exact same name as a translation for a different option. It only checks for untranslated / translated collision, because: - translated / translated conflicts in the same language can be solved by the translator; - translated / translated conflicts in another language will not happen during a call to getopt_long. When a collision is detected, it only returns the untranslated side of the collision because the translator for the current locale knows which option conflicts with the untranslated one. It would maybe more useful for developers to have a maintainer script doing equivalent work, but this function serves as a way to remind them to check for collisions and discuss them with the translators before introducing a new option name. --- manual/getopt.texi | 22 +++++ posix/Makefile | 10 +++ posix/Versions | 2 +- posix/bits/getopt_ext.h | 5 ++ posix/getopt1.c | 49 +++++++++++ posix/tst-getopt_long_collision.c | 83 +++++++++++++++++++ posix/tst-getopt_long_collision.po | 22 +++++ sysdeps/mach/hurd/i386/libc.abilist | 1 + sysdeps/mach/hurd/x86_64/libc.abilist | 1 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arc/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 + sysdeps/unix/sysv/linux/csky/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + .../sysv/linux/loongarch/lp64/libc.abilist | 1 + .../sysv/linux/m68k/coldfire/libc.abilist | 1 + .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + .../sysv/linux/microblaze/be/libc.abilist | 1 + .../sysv/linux/microblaze/le/libc.abilist | 1 + .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 + .../sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 + .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../powerpc/powerpc32/nofpu/libc.abilist | 1 + .../linux/powerpc/powerpc64/be/libc.abilist | 1 + .../linux/powerpc/powerpc64/le/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv32/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 + .../sysv/linux/sparc/sparc32/libc.abilist | 1 + .../sysv/linux/sparc/sparc64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 41 files changed, 226 insertions(+), 1 deletion(-) 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 7834f1c2a3..e769b0ee70 100644 --- a/manual/getopt.texi +++ b/manual/getopt.texi @@ -383,6 +383,28 @@ not match a long option (or its abbreviation). @end deftypefun +It is possible for the programmer to introduce a new option name that +conflicts with the translation of an existing option name. Such a +case would disrupt the workflow of users as the new option would +replace the existing option. Before adding a new option to a program, +the developer should check for collisions with all known translations. + +@deftypefun int getopt_long_collision (const struct option *@var{longopts}, const char *@var{context}, const char *@var{domain}, const struct option **@var{first_collision}) + +Check whether there is a collision with any of the untranslated names +of @var{longopts} and any of the translated names in the current +locale. Translations are looked up with @var{context}, in +@var{domain}. Set @var{first_collision} to @code{NULL}, or to the +address of the first option whose untranslated name collides with +another option’s translated name. + +If the collision happens between two identical translations of +different options, it is not recognized, as it is simply a problem to +be solved by the translator. + +Return 0 if no collisions are detected, 1 if a collision is detected. +@end deftypefun + @node Getopt Long Option Example @subsection Example of Parsing Long Options with @code{getopt_long} diff --git a/posix/Makefile b/posix/Makefile index 1a2cdb053f..1bdb0b2585 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-tilde \ tst-glob_symlinks \ tst-gnuglob \ @@ -342,6 +343,15 @@ $(tstgetoptl_mo): tstgetoptl.po $(objpfx)tstgetoptl.out: $(tstgetoptl_mo) 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) +CFLAGS-tst-getopt_long_collision.c += -DOBJPFX=\"$(objpfx)\" + # Test for the glob symbol version that was replaced in glibc 2.27. ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes) tests += \ diff --git a/posix/Versions b/posix/Versions index d1c2cffcf9..5b4c2e753e 100644 --- a/posix/Versions +++ b/posix/Versions @@ -160,7 +160,7 @@ libc { posix_spawn_file_actions_addtcsetpgrp_np; } GLIBC_2.43 { - optctxt; opttextdomain; + optctxt; opttextdomain; getopt_long_collision; } GLIBC_PRIVATE { __libc_fork; __libc_pread; __libc_pwrite; diff --git a/posix/bits/getopt_ext.h b/posix/bits/getopt_ext.h index 6cd0932596..9c7f940d1f 100644 --- a/posix/bits/getopt_ext.h +++ b/posix/bits/getopt_ext.h @@ -84,6 +84,11 @@ extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv, const struct option *__longopts, int *__longind) __THROW __nonnull ((2, 3)); +extern int getopt_long_collision (const struct option *__longopts, + const char *__context, + const char *__domain, + const struct option **__first_collision); + __END_DECLS #endif /* getopt_ext.h */ diff --git a/posix/getopt1.c b/posix/getopt1.c index 48852dc692..1e1265c531 100644 --- a/posix/getopt1.c +++ b/posix/getopt1.c @@ -109,6 +109,55 @@ _getopt_long_only_r (int argc, char **argv, const char *options, 1, d, 0, do_translate); } +int +getopt_long_collision (const struct option *long_options, + const char *context, + const char *domain, + const struct option **first_collision) +{ + size_t n_options = 0; + size_t untranslated_option_index, translated_option_index; + const char *names_list; + const char *item_end; + size_t item_length; + const struct option *untranslated; + const struct option *translated; + + *first_collision = NULL; + for (n_options = 0; long_options[n_options].name; n_options++) + ; + for (untranslated_option_index = 0; + untranslated_option_index < n_options; + untranslated_option_index++) + for (translated_option_index = 0; + translated_option_index < n_options; + translated_option_index++) + if (translated_option_index != untranslated_option_index) + { + untranslated = &(long_options[untranslated_option_index]); + translated = &(long_options[translated_option_index]); + names_list = do_translate (domain, context, translated->name); + while (names_list) + { + item_length = strlen (names_list); + item_end = strchr (names_list, ' '); + if (item_end) + { + item_length = item_end - names_list; + item_end++; + } + if (item_length == strlen (untranslated->name) + && strncmp (untranslated->name, names_list, item_length) == 0) + { + *first_collision = untranslated; + return 1; + } + names_list = item_end; + } + } + return 0; +} + #ifdef TEST diff --git a/posix/tst-getopt_long_collision.c b/posix/tst-getopt_long_collision.c new file mode 100644 index 0000000000..82cd0083f6 --- /dev/null +++ b/posix/tst-getopt_long_collision.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +#define PN_(ctxt, str) (str) + +/* This checks that getopt_long_collision detects if the translation + of an option collides with an untranslated option name. Such a + conflict would be resolved by favoring the untranslated option by + the way. */ + +#define TRANSLATION_CONTEXT "command-line option" + +/* In this example, the French translator translated --instant by + --moment, but then the developer wants to introduce a new --moment + option... */ + +static const struct option options[] = + { + {PN_ ("command-line option", "instant"), no_argument, NULL, 'I'}, + {"moment", no_argument, NULL, 'M'}, + {NULL, 0, NULL, 0} + }; + +int +main (int argc, char **argv) +{ + (void) argc; + (void) argv; + const struct option *collision = NULL; + int has_collision; + unsetenv ("LANGUAGE"); + setlocale (LC_ALL, "fr_FR.UTF-8"); + if (bindtextdomain ("tst-getopt_long_collision", OBJPFX "domaindir") == NULL) + { + fprintf (stderr, "%s:%d: cannot call bindtextdomain.\n", __FILE__, __LINE__); + abort (); + } + /* Check that the catalog is OK: */ + if (strcmp (dgettext ("tst-getopt_long_collision", + TRANSLATION_CONTEXT "\004" "instant"), + "moment instant") != 0) + { + fprintf (stderr, "%s:%d: the mo file does not work.\n", __FILE__, __LINE__); + abort (); + } + has_collision = + getopt_long_collision (options, TRANSLATION_CONTEXT, + "tst-getopt_long_collision", &collision); + if (!has_collision) + { + fprintf (stderr, "%s:%d: collision not found.\n", __FILE__, __LINE__); + abort (); + } + if (strcmp (collision->name, "moment") != 0) + { + fprintf (stderr, "%s:%d: wrong collision detected, '%s' instead of 'moment'.\n", + __FILE__, __LINE__, collision->name); + abort (); + } + return 0; +} diff --git a/posix/tst-getopt_long_collision.po b/posix/tst-getopt_long_collision.po new file mode 100644 index 0000000000..9cd4a81861 --- /dev/null +++ b/posix/tst-getopt_long_collision.po @@ -0,0 +1,22 @@ +# French translations for tst-getopt_long_collision.c +# Copyright (C) 2025 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: French \n" +"Language: fr\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" + +# Oops, I first thought it would be translated as instant, but it’s moment in fact. +#: tst-getopt_long_collision.c:22 +msgctxt "command-line option" +msgid "instant" +msgstr "moment instant" diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist index d879f5a363..9952a339f1 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2663,6 +2663,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist index 4b6580b2cc..d27a434b8e 100644 --- a/sysdeps/mach/hurd/x86_64/libc.abilist +++ b/sysdeps/mach/hurd/x86_64/libc.abilist @@ -2344,6 +2344,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index 93730d969e..8e5627f2d5 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2768,6 +2768,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 06412be15c..95c82143c4 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -3115,6 +3115,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index e0c6c9f293..baa67af1f8 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2529,6 +2529,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index 7929ecb5ce..42b2843120 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2821,6 +2821,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index 4b7ca1bdf0..7f5772e6a6 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2818,6 +2818,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 326be1421c..07347bcaf9 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2805,6 +2805,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 31be97a20d..a104588ead 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2842,6 +2842,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index 3100d3720d..215f81f310 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -3025,6 +3025,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index 521343313d..c3ee573c25 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2289,6 +2289,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 974a643266..25328bcedf 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2801,6 +2801,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 474da3c6e6..cafd37e64e 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2968,6 +2968,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index 3772bbf961..0163585ba6 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2854,6 +2854,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 81fdbf5528..ed50cec614 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2851,6 +2851,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 8bf825fbd0..00f29bfb0c 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2931,6 +2931,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 3995eb7112..fadc850360 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2929,6 +2929,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index c7f9d75936..fb838cf6e0 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2937,6 +2937,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index fa4c0b6abb..db88142e10 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2839,6 +2839,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index 685e674205..a9da56876b 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2279,6 +2279,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index b739c5b3dd..fee1496cac 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -3158,6 +3158,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index 25a45c7596..6f6400c22d 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -3203,6 +3203,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index 88979415c3..e44a3b326c 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2912,6 +2912,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index f55d5abaa1..a11e6d406e 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2988,6 +2988,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index d644e2b658..2276defe21 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2532,6 +2532,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 8f90416e6f..c2e4d1c0d1 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2732,6 +2732,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 2eb7244ede..7aa56fc320 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -3156,6 +3156,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index 0418207b55..c6d5939ea7 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2949,6 +2949,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index c882ecd323..a82a82aaf0 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2848,6 +2848,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index d8ad0073b8..e49dbe47e1 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2845,6 +2845,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index fee6128da5..78f3d976ae 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3179,6 +3179,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index 78e1358a87..b06c012322 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2815,6 +2815,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 33afb283fa..3451a56e6d 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2764,6 +2764,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x8 GLIBC_2.43 opttextdomain D 0x8 diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 6bf8159064..1a85101261 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2783,6 +2783,7 @@ GLIBC_2.42 uimaxabs F GLIBC_2.42 ulabs F GLIBC_2.42 ullabs F GLIBC_2.43 __memset_explicit_chk F +GLIBC_2.43 getopt_long_collision F GLIBC_2.43 memset_explicit F GLIBC_2.43 optctxt D 0x4 GLIBC_2.43 opttextdomain D 0x4 From patchwork Tue Oct 7 18:13:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 121436 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 727183858425 for ; Tue, 7 Oct 2025 18:17:19 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from planete-kraus.eu (planete-kraus.eu [IPv6:2a00:5881:4008:2810::309]) by sourceware.org (Postfix) with ESMTPS id 5C2BA3858C83 for ; Tue, 7 Oct 2025 18:15:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5C2BA3858C83 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=planete-kraus.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=planete-kraus.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5C2BA3858C83 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:5881:4008:2810::309 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860917; cv=none; b=F0NXSUGuat+gxMx0hZXRroh+PGrzh9UQRhZ9WRekwSVTkWdLJjclyfiEOoCS7tGoCG1q8AOyAF5sCMOZXzdmTekODeFdsgVfTTpyYwWMA6zXWQ4pt/T7vEI6Fh7SAnH6M0NxDpgmm60I69Ss50jQgPf/RWEw5ZFAmZqgqGBN9IA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759860917; c=relaxed/simple; bh=fbOCmm8+rS0DhhYdXGW2RQ0+fpOuWnjpWtyeuALiUfs=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=C6pzzf9LAx7ag18YDbxiGhGCgbCO2B5Byqk8GNAnuSVQ5QlGIEAleBuXVXLBWsWb1vNd+FYVRzXtZBKhZon3/Amv6awuTrcPEA8rq+tsIIzBX8shmXhIWndaHNaJhv6njCLq0OlKpmvg0HEIBwsxztfxYx3E4mdotGUDUR/IIRo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5C2BA3858C83 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu header.a=rsa-sha1 header.s=albinoniA header.b=kdkdOVAa Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 81a931e8 for ; Tue, 7 Oct 2025 18:14:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s= albinoniA; bh=h3MRCnNi46+WKJjyyqqV8kgNhv0=; b=kdkdOVAajHy5alBLyO 8YLqvPlwm4qf/TEXO+3Hfm6VqCSS96Lgt0sPzbmQ2vjQ1adW32t3JK+B19frTmwk GAN6fYfw8Npf/nQO4IjGp/z6M/ZhEHTfNzBlc8fSGzFMNDr0z8qQdgY6yoKAl7og 8rLS6qT8G+nWyFq/2A7dyVJ9lT4nHxdb3KweOwKzttqH1IZvmXIAgtWuYoh+L+Q3 1a0fCfhkaaiQiGwEuZJCinHUZCxSp76IsEcIFW5mFoJ89zUqD62ip0dO1N2EjZam a0pG80ux3vcGZFiNG7GjjvVLd25Jya/S5HXqL5q+8fEzrfaenyHkEn5QrIW6c0cz aiBA== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 3458418c (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Tue, 7 Oct 2025 18:14:56 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v13 9/9] posix: Add a script for static validation of getopt_long PO files Date: Tue, 7 Oct 2025 20:13:33 +0200 Message-Id: <0e1b328a8d16ac2f508236196a6fa7a7cdd5e91c.1759860222.git.vivien@planete-kraus.eu> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org It is better to statically check the PO files on the developer’s side, because there is a chance to detect the problem early and not embarrass the translation team just before a release. This is a perl script that I made by adapting bits and pieces from mtrace.pl. On the test case, it should fail with the following output: ----- Translation toto is used for more than one option: - bar - foo bar is a translation of pub, but it is also a different option. There were 2 failures. ----- --- manual/getopt.texi | 10 + posix/Makefile | 17 ++ posix/check-getopt-translations.pl | 199 ++++++++++++++++++ .../standalone-multiple-getopt-collisions.po | 45 ++++ posix/tst-check-getopt-translations.sh | 59 ++++++ 5 files changed, 330 insertions(+) create mode 100644 posix/check-getopt-translations.pl create mode 100644 posix/standalone-multiple-getopt-collisions.po create mode 100644 posix/tst-check-getopt-translations.sh diff --git a/manual/getopt.texi b/manual/getopt.texi index e769b0ee70..3cb7eabf9f 100644 --- a/manual/getopt.texi +++ b/manual/getopt.texi @@ -388,6 +388,16 @@ conflicts with the translation of an existing option name. Such a case would disrupt the workflow of users as the new option would replace the existing option. Before adding a new option to a program, the developer should check for collisions with all known translations. +This can be done with the installed +@command{check-getopt-translations} script, by calling for each PO +file in the project: + +@smallexample +check-getopt-translations "context used for translations" @file{file.po} +@end smallexample + +Otherwise, you may repeatedly call the @command{getopt_long_collision} +function after setting the locale, for each known locale. @deftypefun int getopt_long_collision (const struct option *@var{longopts}, const char *@var{context}, const char *@var{domain}, const struct option **@var{first_collision}) diff --git a/posix/Makefile b/posix/Makefile index 1bdb0b2585..e6fa13404b 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -435,6 +435,9 @@ install-others-programs := \ $(inst_libexecdir)/getconf \ # install-others-programs +install-bin-scripts = check-getopt-translations +generated += check-getopt-translations + before-compile += \ $(objpfx)posix-conf-vars-def.h \ # before-compile @@ -449,6 +452,7 @@ generated += \ testcases.h \ tst-getconf.out \ wordexp-tst.out \ + tst-check-getopt-translations.out \ # generated ifeq ($(run-built-tests),yes) @@ -514,6 +518,7 @@ tests-special += \ $(objpfx)tst-pcre-mem.out \ $(objpfx)tst-rxspencer-no-utf8-mem.out \ $(objpfx)tst-vfork3-mem.out \ + $(objpfx)tst-check-getopt-translations.out \ # tests-special endif endif @@ -798,3 +803,15 @@ $(objpfx)posix-conf-vars-def.h: $(..)scripts/gen-posix-conf-vars.awk \ $(make-target-directory) $(AWK) -f $(filter-out Makefile, $^) > $@.tmp mv -f $@.tmp $@ + +$(objpfx)check-getopt-translations: check-getopt-translations.pl + rm -f $@.new + sed -e 's|@XXX@|$(address-width)|' \ + -e 's|@VERSION@|$(version)|' \ + -e 's|@PKGVERSION@|$(PKGVERSION)|' \ + -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|' $^ > $@.new \ + && rm -f $@ && mv $@.new $@ && chmod +x $@ + +$(objpfx)tst-check-getopt-translations.out: tst-check-getopt-translations.sh $(objpfx)check-getopt-translations standalone-multiple-getopt-collisions.po + $(SHELL) $^ $(common-objpfx)posix/tst-check-getopt-translations.out + $(evaluate-test) diff --git a/posix/check-getopt-translations.pl b/posix/check-getopt-translations.pl new file mode 100644 index 0000000000..58c4e087b3 --- /dev/null +++ b/posix/check-getopt-translations.pl @@ -0,0 +1,199 @@ +#! /usr/bin/perl + +# Copyright (C) 2025 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Based on the mtrace.awk script. + +# 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 +# . + +use strict; +use warnings; +use Data::Dumper; + +my $VERSION = "@VERSION@"; + +my $PKGVERSION = "@PKGVERSION@"; +my $REPORT_BUGS_TO = '@REPORT_BUGS_TO@'; +my $progname = $_; + +sub usage { + print "Usage: getopt-check [OPTION]... msgctxt lang.po\n"; + print " --help print this help, then exit\n"; + print " --version print version number, then exit\n"; + print "\n"; + print "For bug reporting instructions, please see:\n"; + print "$REPORT_BUGS_TO.\n"; + exit 0; +} + +sub fatal { + print STDERR "$_[0]\n"; + exit 1; +} + +# This script takes two positional arguments: the context for +# translated option names, and the PO file to check. Then, the PO file +# is parsed, looking at three things: +# 1. the msgctxt: it must be equal to the first positional argument, msgctxt; +# 2. the msgid; +# 3. the space-separated list msgstr. +# +# We are looking for two different problems: +# +# 1. Every translation element, current or obsolete, must be unique +# across all option names. +# 2. For every option name, for every translation, current or +# deprecated, if it doesn’t match the untranslated name, then it +# should not match any other untranslated option names. +# +# If we detect an example of the first case, it is a problem with the +# translator only. They have to remove one use of the word, preferably +# one that is deprecated. +# +# If we detect an example of the second case, then it is a problem +# with the developer: they want to introduce an option name that is +# already used for something else by users of this native language! If +# nothing is done, these users will be surprised that the same word +# now means another option, as the untranslated options have +# precedence over the translations. If the translated name is already +# deprecated, then the language team may agree to completely remove +# it. Otherwise, it may be better to find a new untranslated name. + +# This script uses the same format as mtrace.pl. + + arglist: while (@ARGV) { + if ($ARGV[0] eq "--v" || $ARGV[0] eq "--ve" || $ARGV[0] eq "--ver" || + $ARGV[0] eq "--vers" || $ARGV[0] eq "--versi" || + $ARGV[0] eq "--versio" || $ARGV[0] eq "--version") { + print "getopt-check $PKGVERSION$VERSION\n"; + print "Copyright (C) 2025 Free Software Foundation, Inc.\n"; + print "This is free software; see the source for copying conditions. There is NO\n"; + print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; + print "Written by Vivien Kraus \n"; + + exit 0; + } elsif ($ARGV[0] eq "--h" || $ARGV[0] eq "--he" || $ARGV[0] eq "--hel" || + $ARGV[0] eq "--help") { + &usage; + } elsif ($ARGV[0] =~ /^-/) { + print "$progname: unrecognized option `$ARGV[0]'\n"; + print "Try `$progname --help' for more information.\n"; + exit 1; + } else { + last arglist; + } +} + +if ($#ARGV != 1) { + fatal "You must provide two arguments: the msgctxt for option names, and the name of the PO file."; +} + +my $relevant_msgctxt = $ARGV[0]; +my $pofilename = $ARGV[1]; +my %translations; + +# %translation_used will be populated to detect multiple use of a +# %translation directly when we parse. + +my $entry_msgid; + +# The ad-hoc PO file parser has 3 states: 1. Wating for msgctxt; +# 2. Waiting for msgid; 3. Wating for msgstr. At the start, the state +# is 1. Then, if we find "msgctxt \"$relevant_msgctxt\"" in a single +# line, we jump to 2. Otherwise, if this is the end of the file, stop +# parsing. Otherwise, whatever the line, stay in 1. This includes: the +# empty line, meaning we are considering a new entry; or a comment, a +# #: location, or another relevant line. +# +# When we are in state 2., we are waiting for the msgid (untranslated +# option name). If we find an empty line, we jump back to 1. If we +# find a line starting with "msgid \"" and ending with a double quote, +# we store what is in the middle in $entry_msgid and jump to +# 3. Otherwise, we stay in state 2. +# +# When we are in state 3., we are waiting for msgstr (canonical and +# obsolete translations). If we find an empty line, drop $entry_msgid, +# and back to 1. If the line starts with "msgstr \"", we add a record +# to %translations: the key is $entry_msgid, and the value, what is +# between the detected prefix and the next space. Then, back to state +# 1. + +my $parser_state = 1; + +open (my $pofile, "<", $pofilename) || fatal "PO file name ${pofilename} cannot be read."; + +while (my $line = <$pofile>) { + chomp $line; + if ($parser_state == 1 && $line =~ /^msgctxt\s*"${relevant_msgctxt}"$/) { + $parser_state = 2; + } elsif ($parser_state == 2 && $line eq "") { + $parser_state = 1; + } elsif ($parser_state == 2 && $line =~ /^msgid\s*"([^"]+)"$/) { + $parser_state = 3; + $entry_msgid = $1; + } elsif ($parser_state == 3 && $line eq "") { + $parser_state = 1; + } elsif ($parser_state == 3 && $line =~ /^msgstr\s*"([^"]*)"$/) { + my @translations_for_this = split(/\s+/, $1); + $translations{$entry_msgid} = \@translations_for_this; + $parser_state = 1; + } +} + +my $number_of_errors = 0; + +# Verify that every option name is unique. +my %untranslated_name; +for my $option_name (keys %translations) { + for my $translation (@{$translations{$option_name}}) { + my @existing; + if (exists $untranslated_name{$translation}) { + @existing = @{$untranslated_name{$translation}}; + } + push(@existing, $option_name); + $untranslated_name{$translation} = \@existing; + } +} +for my $translation (keys %untranslated_name) { + my $names = $untranslated_name{$translation}; + if (@{$names} > 1) { + print STDERR "Translation ${translation} is used for more than one option:\n"; + for my $untranslated (@{$names}) { + print STDERR " - ${untranslated}\n"; + } + ++$number_of_errors; + } +} + +# Verify that every option translation does not match any other +# untranslated name. +for my $option_name (keys %translations) { + for my $other_option_name (keys %translations) { + if ($option_name ne $other_option_name) { + for my $translation (@{$translations{$option_name}}) { + if ($translation eq $other_option_name) { + print STDERR "${translation} is a translation of ${option_name}, but it is also a different option.\n"; + ++$number_of_errors; + } + } + } + } +} + +if ($number_of_errors eq 0) { + exit 0 +} +print STDERR "There were ${number_of_errors} failures.\n"; +exit 1 diff --git a/posix/standalone-multiple-getopt-collisions.po b/posix/standalone-multiple-getopt-collisions.po new file mode 100644 index 0000000000..479fdccf2c --- /dev/null +++ b/posix/standalone-multiple-getopt-collisions.po @@ -0,0 +1,45 @@ +# French translations for the getopt static checker +# Copyright (C) 2025 THE GNU C Library'S COPYRIGHT HOLDER +# This file is distributed under the same license as the GNU C Library. +# +# This has two errors: +# 1. "toto" is used both as a translation of "foo" and "bar"; +# 2. "bar" is used as a translation of "pub", but it is another option. +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: French \n" +"Language: fr\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" + +# This is not an option name, so it’s OK for it to clash with option +# names. +msgctxt "fish" +msgid "bass" +msgstr "bar" + +# This is the --foo option. +msgctxt "command-line option" +msgid "foo" +msgstr "tata toto" + +# This is the --bar option. Oops, I translated with toto here too. +msgctxt "command-line option" +msgid "bar" +msgstr "titi toto" + +# Let’s go to the --pub! +msgctxt "command-line option" +msgid "pub" +msgstr "bar club" + +# Wait, it’s OK if baz is translated to baz though. +msgctxt "command-line option" +msgid "baz" +msgstr "baz" diff --git a/posix/tst-check-getopt-translations.sh b/posix/tst-check-getopt-translations.sh new file mode 100644 index 0000000000..a9a905dbae --- /dev/null +++ b/posix/tst-check-getopt-translations.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# Test for check-getopt-translations. +# Copyright (C) 2025 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 +# . + +set -e + +check_getopt_translations_program=$1; shift +po_file=$1; shift +logfile=$1; shift + +rm -f $logfile +result=0 +expected_output="\ +Translation toto is used for more than one option: + - bar + - foo +bar is a translation of pub, but it is also a different option. +There were 2 failures." + +if output=$(${check_getopt_translations_program} "command-line option" ${po_file} 2>&1) ; then + echo "the errors were not caught." >> $logfile + echo "*** check-getopt-translations FAILED" >> $logfile + result=1 +fi + +if test "$output" != "$expected_output"; then + echo "Expected:" >> $logfile + echo "$expected_output" >> $logfile + echo "Actual:" >> $logfile + echo "$output" >> $logfile + echo "*** check-getopt-translations FAILED" >> $logfile + result=1 +fi + +exit $result + +# Preserve executable bits for this shell script. +Local Variables: +eval:(defun frobme () (set-file-modes buffer-file-name file-mode)) +eval:(make-local-variable 'file-mode) +eval:(setq file-mode (file-modes (buffer-file-name))) +eval:(make-local-variable 'after-save-hook) +eval:(add-hook 'after-save-hook 'frobme) +End: