From patchwork Sat Jun 21 11:13:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114801 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 6C1493938586 for ; Sat, 21 Jun 2025 11:18:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6C1493938586 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=albinoniB header.b=WgC7tdhd 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 015AE3838A26 for ; Sat, 21 Jun 2025 11:15:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 015AE3838A26 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 015AE3838A26 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=1750504511; cv=none; b=T5k+2KDFeW5iq+nXIHs4jIagIE3F5EpSt6NSEqQsEoK0qy9zSK92Fdkx8pek9+YOeY1M+oXOhyK4zkcpceWj7HbaRck+HYrk3Er+AzbVXml7/HFpo/ebM3i+EhLq5OxiZqYlBsmAYtHL04VwMFgampHurMejwaMudOzUiYyIDLU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750504511; c=relaxed/simple; bh=GEvV5Fomt4W3jUlwYo7LjQ4+cD72grtbaW3ra5QnTqs=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=hAxslustlErSHrHO7AyMesCY73lugDXaJYTry9mc4IlnzfuRwm2YNE08wcwS8MzZejV2LvVpF7Pg2UEVRv83+AscwwtEmlOt0ZGkZU9IKBVbnyqUG7SADqMnz6ftMDUgfYyE7BCjCOkx4hiWNYj+mRoWkIB0uKkRtpcYny/1Atk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 015AE3838A26 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 062e5cba for ; Sat, 21 Jun 2025 11:15:07 +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=albinoniB; bh=dHij0ko ADn3pcm+YYHCM/TCQ8H4=; b=WgC7tdhdBiY7BDNSyHsrMLxAf5isJOGkKauni8G jEU+MphaKgE27CquZ02jJzs/fQfvIhKHgeyvhCe64i+XU4fJ74tmds2klMP7CD25 7q3D/G8yglbKRz292fe3e1MRbzB1d3YfxaoNy4oZt0cJ+AvWJZ3nmHYamSfs9xk6 8NvjB3v+kAx8OvTBjfn9QjNZ/F6+KNkMVjo8qc2ixg4/h6x4IaYgxQ6CFPjZL1ki N9pm3J3HJl+GFgHKB9/JmfDhWedEMaAWe8mI3DucXA+4b2w3S5FRItMrsGo+Rg6d mj4DqIhO3z+J92DJEVtlmMtP8sTI7p5tIFIJPaAMnmtRzhA== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id fdb9dfaa (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 11:14:59 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v7 1/8] posix: allow getopt_long to match translated option names Date: Sat, 21 Jun 2025 13:13:48 +0200 Message-ID: <068929f8685f7d07363d0627d100f378ab280f69.1750504345.git.vivien@planete-kraus.eu> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-13.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 by adding new option records with the translated names in the options array. However, it 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. Another argument to the _getopt_internal{_r} is added to avoid linking to gettext from the posix version of getopt. --- manual/getopt.texi | 25 ++++++++-- posix/Makefile | 13 +++++ posix/getopt.c | 97 ++++++++++++++++++++++++++++++------ posix/getopt1.c | 11 ++-- posix/getopt_int.h | 9 +++- posix/tstgetoptl.c | 119 ++++++++++++++++++++++++++++++++++++++++++++ posix/tstgetoptl.po | 25 ++++++++++ 7 files changed, 272 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 c0e224236a..587a03f318 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -327,8 +327,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 += \ @@ -599,6 +611,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..04b07093e4 --- /dev/null +++ b/posix/tstgetoptl.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include + +/* This is a modified copy of 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 Sat Jun 21 11:13:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114803 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 342BF3955CAB for ; Sat, 21 Jun 2025 11:26:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 342BF3955CAB 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=albinoniB header.b=BbYmsq/7 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 87C8D3830B4F for ; Sat, 21 Jun 2025 11:15:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 87C8D3830B4F 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 87C8D3830B4F 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=1750504513; cv=none; b=AX2HbFXftNkUxEJJHzHZFu6PbNyn4L8cGas66MeBYCIzCODPbvUxYmSnBBpeY0G8cHjjNqhHb5t9Y8wCCzHvcgqPQIKLn3dFaBD8if+1tIwbVLg/0qDSY4YTa65tZlKSkHVfhYMkG1Gr52O8nf36kIrQi+EOUvwWDQLzCegoum4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750504513; c=relaxed/simple; bh=HawMJQVwBNHAPubJ6FEwaZv0jte3PoNcHQE5tbKvhz4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=VKpRZgqZwv0gicbMS/p0BGFXImQGf0xdDkG8zfHdt/hbFudX07/4SNHdgQzhL+eUa3dPV9UecV1NHLB/yNhn0IB0vXlgqpKb/owSQBGbm4pmQYvYRAFENGEqJSxp77Cn9S7ivge3azNROr+axHvgy9Ne9dJcsDzlv/lUIjdwEsY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 87C8D3830B4F Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id d7f2174d for ; Sat, 21 Jun 2025 11:15:07 +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=albinoniB; bh=XfeCGPD wZAKqEf19SKHX/cvbX/Q=; b=BbYmsq/75alGM/UUHlMhBHZ9GmIQILpatTadogA LVqXRkRnPWPBBCb7k86onBZaJ3yKl31qNRcqnDvuMlo8Bcf9EMww4GdRU77/JG+q fmKcc/QgPYfx6ztb2nFGXSmu0e7Pf+XvCo9WYXh3h/muL2BWpPU+dmou0fHKG8sU cu5hiV2NkLJzErLaRc8YaA6jooVRDKkaLyQs5Wcf+A3ANq/jDDzk58dsFrhzgo5D 03v/bXL5YDqKczTOTWf9WOplrlP/R0W/TETr93jWrcGWuxX3M2/ZOZ4g8maIJjT6 EQOP2XXPLfITIjZL+elZTSezn2Yq9zfcA9faML4jWX3tU3w== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 4110321c (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 11:14:59 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v7 2/8] posix: let the getopt caller set the translation context Date: Sat, 21 Jun 2025 13:13:49 +0200 Message-ID: <4cfba094e913cf0fa67b0dd4734055ad9bc41ba3.1750504345.git.vivien@planete-kraus.eu> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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). The context is now mandatory. pgettext_expr is not available yet, so we use a custom function to combine the context and the long option name. This creates a new global variable / reentrant state field, optctxt, so that the caller can override it. --- 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/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/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 + .../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 + 27 files changed, 109 insertions(+), 18 deletions(-) diff --git a/manual/getopt.texi b/manual/getopt.texi index da9df5225a..dc5b16b605 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..76af54306e 100644 --- a/posix/Versions +++ b/posix/Versions @@ -159,6 +159,9 @@ libc { GLIBC_2.35 { posix_spawn_file_actions_addtcsetpgrp_np; } + GLIBC_2.42 { + 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 04b07093e4..bffd56f47d 100644 --- a/posix/tstgetoptl.c +++ b/posix/tstgetoptl.c @@ -15,6 +15,8 @@ precedence over translated options, by translated "optional" as "required". */ +#define TRANSLATION_CONTEXT "command-line option" + static int prepare_localedir (void) { @@ -31,7 +33,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; @@ -42,6 +44,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'}, @@ -68,6 +71,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 a0e686afc7..3df40e3b32 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2596,6 +2596,7 @@ GLIBC_2.42 cfgetobaud F GLIBC_2.42 cfsetbaud F GLIBC_2.42 cfsetibaud F GLIBC_2.42 cfsetobaud F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_barrier_destroy F GLIBC_2.42 pthread_barrier_init F GLIBC_2.42 pthread_barrier_wait F diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist index 8f9d6aa842..2a6d706f7f 100644 --- a/sysdeps/mach/hurd/x86_64/libc.abilist +++ b/sysdeps/mach/hurd/x86_64/libc.abilist @@ -2279,6 +2279,7 @@ GLIBC_2.42 cfgetobaud F GLIBC_2.42 cfsetbaud F GLIBC_2.42 cfsetibaud F GLIBC_2.42 cfsetobaud F +GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 pthread_barrier_destroy F GLIBC_2.42 pthread_barrier_init F GLIBC_2.42 pthread_barrier_wait F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index 959e44672f..ef3dcc3b40 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2815,6 +2815,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index a930d1a52b..3c1aa9ac36 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2812,6 +2812,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index a6cab9612a..a97a2f0078 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2283,6 +2283,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 7b7b72aa50..41f754a911 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2795,6 +2795,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index df398e43c6..e16695e723 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2962,6 +2962,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index ca8df6f4b0..d85379f1e8 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2848,6 +2848,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 9508154847..f92999dd38 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2845,6 +2845,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index 1771a2370c..a4c7176af9 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2526,6 +2526,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 4b48352fd9..6472c7c7ef 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2726,6 +2726,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index f0decc787b..b6eff3181d 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -3150,6 +3150,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index da8a2bfb74..1bf2c16614 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2943,6 +2943,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index fb30341894..eff7d65ec3 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2842,6 +2842,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index d716673432..b0da639eed 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2839,6 +2839,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 6deedf216d..7f37de7438 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3171,6 +3171,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 tcgetattr F GLIBC_2.42 tcsetattr F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index 1ce22bf036..8790e90516 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2807,6 +2807,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 tcgetattr F GLIBC_2.42 tcsetattr F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 564877250b..0bb3960c70 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2758,6 +2758,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 25a39d0943..4aea484908 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2777,6 +2777,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F From patchwork Sat Jun 21 11:13:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114805 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 700603954C57 for ; Sat, 21 Jun 2025 11:25:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 700603954C57 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=albinoniB header.b=hXrE09ai 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 F1293382E56A for ; Sat, 21 Jun 2025 11:15:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F1293382E56A 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 F1293382E56A 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=1750504514; cv=none; b=eHPrw1Av1Z/49CQzym9Pdmws43gWm0sNUiZQzPZx281tO3AZwR7H/dBBzuKHM9JYIdISEwDHHGsBdRjTdHYTAhR1g6mSzUuo51JUI3hH5g2gh8GhjGY9Np4u1ON/cnwIjHSXmLMoG1Ztbc9Y2LYfhync0OGKGJJ3Ad0lWco8djs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750504514; c=relaxed/simple; bh=sEHS1GxEr6dLfVP+dyZ0sBYWWAthEVIlzx/1hhaH3MM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=RziYK0QXQ2TBQd5TCt0Qm6pmPHTkAU6UmPHxG/VkZZxC/kt8t0jf7CgUfQ9sxtbSGWrBWQrxg/GJmC3SdFroBqi8boE5MsKW7FkmgWy6PbiFm7Ev2pb11XC6DgLmKnyogg4pLaOh1u7tBhtnvNfZUTWOglt0qR9Gx8C+LOfpBks= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F1293382E56A Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 5d6b4ad4 for ; Sat, 21 Jun 2025 11:15:07 +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= albinoniB; bh=fjvYAqamFVLHuwlkKh5sYyr1e0k=; b=hXrE09aiPK+isBhgSp ksynlCEgERszkvAmmVthwTNtDh+MuH0OU43WXAtVNlsMuhFLFflxmhjNL91U49QF p9qWLZnGLvqSXuDKo6J524v4q8WFtXcZo8UtYWxLskcMgLh0mFanKmLccwdaB00F hqToYZuvYkJdsZOMApSe/P1kgM0fpXmulG0ynrhi6VSWN4fHoLeHpRAvj8pIAUlP IDqWTVIlk3oHqgiT91J2Cwx7gMcTZJY8NZlPhqj7cTKxW8y7GkmInPYZ1F9RZbgk Y4JabJ+u13t2JiKNef3bCGIr10mi3Njg5FSNW5FpEGeVzRkOotBisOUFRhGAbc3w Ggow== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 69e45b6a (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 11:15:00 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v7 3/8] argp: document translated names in --help and --usage Date: Sat, 21 Jun 2025 13:13:50 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 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. 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 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 Sat Jun 21 11:13:51 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114802 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 50537393859E for ; Sat, 21 Jun 2025 11:18:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 50537393859E 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=albinoniB header.b=WjHS3kzV 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 413863823908 for ; Sat, 21 Jun 2025 11:15:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 413863823908 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 413863823908 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=1750504515; cv=none; b=iKcQDiCKl22EYpggcJooeXctOxOHiGcZLanJ8yY4grgW/mDt1gofFDs+VF2UvRjzPwntBIFjuT86sp/ra4HAME9NiHniWbj2MMZgfkwXUYdOu/1yzc9iNZATbx2CwFuehc38gJuW47+aeZvumtuq7dJz2TMYhsUviAzHdsVWKQo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750504515; c=relaxed/simple; bh=5JX5lJ+Pe/UPk+8hgKISpKLOEyEn+l7mmIV4agSL8bk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Eh2Hcnzhdm4UATd/Gvf6N90tAkamjMrvowOZZpUvXCdFOcozSfQ54VVo7r2zaxISGlfkvxBYKCuuQ7F8DpHH3sKOKQPfAGHdNULJbgDs7wdzAPr0djVg3eZARbr1+z4/FW4oDQGbhglvesAZXsk3co7Jo+9hjS8DZ5AUpggJDwg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 413863823908 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id dbe3da95 for ; Sat, 21 Jun 2025 11:15:07 +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=albinoniB; bh=cJLsJAt ZIaQmirWH+HVlB914LR4=; b=WjHS3kzVqmw8qWYKDlJsJm/GDWUeHnh/kpgexYl g2eWhYaGSAgCS8ZOknF+JGPymeoeDybYvalBs4h+InjO2Chn4tMPkt2cMFbZaT0O IrQ6LietAk1ySEuGSmjyQX8n3ALl5MiUWJY9yWv17/surs5maNVRNdWz6u36cev5 YmWPD/OV14W1Aur6jvRNXqLx6826UtJ57PIGxN/VrKqEd7ziASE5vab++/xpCD7D iqunawEa6R8ixwOMuR7mpGrSq4s63y1rsIFy7ZU0/8rjMcJ2L2x11qTRc5/7+XRl xhVuN0e7lAujZ4L2eKuswUV00zt3JOjly/7lLEgQ0Uzb1Mw== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 8a2d9b5f (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 11:15:00 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v7 4/8] posix: let the getopt caller choose the textdomain for translation Date: Sat, 21 Jun 2025 13:13:51 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 Using the same solution as for the option translation context, a new opttextdomain variable is defined. --- manual/argp.texi | 7 +++-- manual/getopt.texi | 11 +++++-- posix/Versions | 2 +- posix/bits/getopt_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/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/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 + .../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 + 27 files changed, 79 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 dc5b16b605..12522e390c 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 76af54306e..ae237ce9d4 100644 --- a/posix/Versions +++ b/posix/Versions @@ -160,7 +160,7 @@ libc { posix_spawn_file_actions_addtcsetpgrp_np; } GLIBC_2.42 { - 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 bffd56f47d..3580358a67 100644 --- a/posix/tstgetoptl.c +++ b/posix/tstgetoptl.c @@ -27,13 +27,8 @@ prepare_localedir (void) fputs ("Cannot call bindtextdomain.\n", stderr); return -1; } - if (textdomain ("tstgetoptl") == NULL) - { - fputs ("Cannot call textdomain.\n", stderr); - return -1; - } /* Check that the catalog is OK: */ - if (strcmp (gettext (TRANSLATION_CONTEXT "\004" "color"), "colour") != 0) + if (strcmp (dgettext ("tstgetoptl", TRANSLATION_CONTEXT "\004" "color"), "colour") != 0) { fputs ("The mo file does not work.\n", stderr); return -1; @@ -45,6 +40,7 @@ int main (int argc, char **argv) { static const char *translation_context = TRANSLATION_CONTEXT; + static const char *translation_textdomain = "tstgetoptl"; static const struct option options[] = { {"required", required_argument, NULL, 'r'}, @@ -72,6 +68,7 @@ main (int argc, char **argv) return 1; } optctxt = translation_context; + opttextdomain = translation_textdomain; while ((c = getopt_long (argc, argv, "abc:", options, NULL)) >= 0) switch (c) { diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist index 3df40e3b32..835af57863 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2597,6 +2597,7 @@ GLIBC_2.42 cfsetbaud F GLIBC_2.42 cfsetibaud F GLIBC_2.42 cfsetobaud F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_barrier_destroy F GLIBC_2.42 pthread_barrier_init F GLIBC_2.42 pthread_barrier_wait F diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist index 2a6d706f7f..ba9558da6f 100644 --- a/sysdeps/mach/hurd/x86_64/libc.abilist +++ b/sysdeps/mach/hurd/x86_64/libc.abilist @@ -2280,6 +2280,7 @@ GLIBC_2.42 cfsetbaud F GLIBC_2.42 cfsetibaud F GLIBC_2.42 cfsetobaud F GLIBC_2.42 optctxt D 0x8 +GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_barrier_destroy F GLIBC_2.42 pthread_barrier_init F GLIBC_2.42 pthread_barrier_wait F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index ef3dcc3b40..8f04b7ae8f 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2816,6 +2816,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index 3c1aa9ac36..be208a3db4 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2813,6 +2813,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index a97a2f0078..9807fd7689 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2284,6 +2284,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x8 +GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 41f754a911..cb00b1af8c 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2796,6 +2796,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index e16695e723..a45e55f2c2 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2963,6 +2963,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index d85379f1e8..b92e42b03f 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2849,6 +2849,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index f92999dd38..f92c9f1299 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2846,6 +2846,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index a4c7176af9..42ddd9ed3e 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2527,6 +2527,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 6472c7c7ef..82f7d36e01 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2727,6 +2727,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x8 +GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index b6eff3181d..5cb06233a2 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -3151,6 +3151,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index 1bf2c16614..32ec7f28b2 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2944,6 +2944,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x8 +GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index eff7d65ec3..1efe9aae8c 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2843,6 +2843,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index b0da639eed..13c1d88d1c 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2840,6 +2840,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 7f37de7438..c49edb2026 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3172,6 +3172,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 tcgetattr F GLIBC_2.42 tcsetattr F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index 8790e90516..a5a4263ddd 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2808,6 +2808,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x8 +GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 tcgetattr F GLIBC_2.42 tcsetattr F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 0bb3960c70..10d2ed46e4 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2759,6 +2759,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x8 +GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 4aea484908..ca5986772a 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2778,6 +2778,7 @@ GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F GLIBC_2.42 optctxt D 0x4 +GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F From patchwork Sat Jun 21 11:13:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114806 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 C0030398A47D for ; Sat, 21 Jun 2025 11:31:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C0030398A47D 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=albinoniB header.b=fIU1LD0z 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 ABEE638B7BC6 for ; Sat, 21 Jun 2025 11:15:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ABEE638B7BC6 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 ABEE638B7BC6 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=1750504525; cv=none; b=W18xEqLoVvqNWxClBBuwO47ITpXW05AR8cpO1CU562DL75iw8+FlahG4aqAcNqRnm/uN+j4qBMO5Y6M4PyTvnk7YlpUUXMrq4MmVGSxRd689P80IRGzKtLhAQZpXifjVFWXCFgFLC6zgu6Myp4ZiDp+Da6pQdDD8rcih33bGLqk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750504525; c=relaxed/simple; bh=jcD3xf3dLpQgHC9I5alwKLCwg6Rhp7J+2eAqYJUnj+I=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=I0Q56c1VRAqB88ze2RfgHOjCrNGwI4IeP9gdANMVsp5yqQF108VugwpZCn6caslVJEtWAFaAOmTUyEkNH93ztLlJCbJBZt3jMWIlJ69A6o1CXwJsqCEaB4HiR5Y3Tz6NXefA3MWanG9oWEkxDELuPcDT8h/1qrHpufvXEWP2bgk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ABEE638B7BC6 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 1dd19cea for ; Sat, 21 Jun 2025 11:15:07 +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=albinoniB; bh=YHx0NI2 +qDnghj4XyBnYQ6rhNh8=; b=fIU1LD0zDyitiWDkR944QyVBXDOy0RbuahkAMo0 K1beRGF0UVjUTvy9KnxQ1L7Cf3CuVj1rdbwTwKjolN/sdaoobwmlegO5acASpEfs ZVBxRSFNQ0Dd0mh8rxMjgDNY0bBNKWViiw2LiN1bV+yUyTciNUIjts4Qi4a99A/0 lVnKLwusJda/5+FjDAuuJ08bgk3jRfQ5E1rc41kWnbKvf9mJL1YoOq7xrZ5WGkJh d26h5Du2p+2VH/ofo36vO1bwi/Ib01lHH4JZbg8hWTZ/3HYiPknhkEnit6scHIrk X1+oqM13r9J28Psf5mRCemW31IQs/KDX/985ARzijcSGzhg== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 657f4aaa (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 11:15:00 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v7 5/8] posix: do not allow option name translations for secure programs Date: Sat, 21 Jun 2025 13:13:52 +0200 Message-ID: <214cae98711c74733d6f724116e13f80a83fc5c6.1750504345.git.vivien@planete-kraus.eu> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-13.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 Sat Jun 21 11:13:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114804 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 107A1395A400 for ; Sat, 21 Jun 2025 11:25:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 107A1395A400 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=albinoniB header.b=MYebyj88 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 DB30338B7FEC for ; Sat, 21 Jun 2025 11:15:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DB30338B7FEC 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 DB30338B7FEC 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=1750504520; cv=none; b=x57aw9fQLz0zi1BalJzREP5pXENr77XKrOUru/MIRnYqft9mTyytG1VIvjPAeixmUULIJM3p8m7S6o6r+1JIpQvgW6aRsCXfkbwqFmFxtzxLh6sp1emLZEOZwvfAZk5znY0hBp1N9pfX27t2UoErWr8AFdP71wqmtvM5xY4aenU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750504520; c=relaxed/simple; bh=llTFeO77/0H/wTVSq/doMdqCFP98Bw/zZSYZmZX3a7M=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=LTcNtsn7+Gwj3lX1CaRT3U6FNExvhoM9dJ2CRJCTnYWyCESv8pJNcaxKsCU1LtD3OXrSml7ALxnvAaBul8xZnHU+W5oDyOt7PdCPcx1nds3A/IEy74zEsHAm+QaMR9ieI6FMPhWX5DQHmzB1L+BnyfpbDvDgOI19VfNRHBOKS8o= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DB30338B7FEC Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 3bb93b42 for ; Sat, 21 Jun 2025 11:15:08 +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= albinoniB; bh=Kj/Aywu1QVnjVXdjYRsCeCH2hhw=; b=MYebyj88J5e/i80njD GTeh4SqT1XDwLhWfFsMG+B+Jf74v5pQEvUkfmSBqe8BEj+iLApjkQ2VtE9WkLg5q DWThdnYsFlBrf6t6s3C3oyUM06nhj9jFqbou5JL96nRHtfUtgLvnW00BC27BGSQp VNhBAhGF4LD9VWuijB0lnQUO9u4x4gvLaAR+lQDgbYhCEaSa2T3bMaExHff9tr2X q6S4dEwjQJDE3WnwP/TdrcfYszYdfBi20rUjFH1jCQ5Hsy3zwS0ZiVwcuMsfuM63 IIbFMV9/H9YirdJqE2prFRdc/HjyCFhV+qFum415qFHa8DA1CHFslzospabFnN6j qEkQ== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id a666c0a1 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 11:15:01 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v7 6/8] posix, argp: Support deprecation of long option name translations Date: Sat, 21 Jun 2025 13:13:53 +0200 Message-ID: <57d08c5c8b29376eab159a644cfb18200c28fe4c.1750504345.git.vivien@planete-kraus.eu> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 12522e390c..d8a18a8496 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 587a03f318..5b4a025004 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -611,7 +611,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 3580358a67..27b8f02417 100644 --- a/posix/tstgetoptl.c +++ b/posix/tstgetoptl.c @@ -10,8 +10,12 @@ 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". */ @@ -28,7 +32,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; @@ -47,11 +53,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; @@ -109,7 +116,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 Sat Jun 21 11:13:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114808 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 829E4398ABB2 for ; Sat, 21 Jun 2025 11:31:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 829E4398ABB2 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=albinoniB header.b=Et1N2mrL 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 F2D5338B83C8 for ; Sat, 21 Jun 2025 11:15:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F2D5338B83C8 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 F2D5338B83C8 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=1750504520; cv=none; b=YDDRvPMV699JV9l3lA3qw76/p362thCIZzIx/VxwYKdMdKtlXksXTSS325WQSP1YCpakXnPwtYMgTpTW62l2LFChDRvMqmtix4XEtbaV8uHKRkvHPrVZPgbUMuT710bySO2iuvqM6gtxIXrAAnhWLZJU+RWLCHqbjgJ+VoltwR8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750504520; c=relaxed/simple; bh=htGT2RMX5xAHEqTNWNem7RyUyUZ3/1eyF/yXoj/Raws=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=eBiSBxYyO65FsM9jEpGo1g67csp5BSMjCTJsUsTfTTLVZXEb/pufh/0HdsyIR6sUtA16iX0OnKw0Gv7qdq2OiGiQKIAKYavuLuYJVh4Lz4GpIyPcitMEhzqyXz+vpc9a/4tPyG7lCm+kQY4Ge4ioa3WnDDMhRwyf2XYvtJV8Mr4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F2D5338B83C8 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id f5cc623e for ; Sat, 21 Jun 2025 11:15:08 +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=albinoniB; bh=l/BvyIA y4B+rNDzRBgSzRLyTUhQ=; b=Et1N2mrLDwb40i/9Cy45svrgQm7kRVPu2wjk7DN k0lZxXX6LaveOrDTJYOUs+ybFJc/6hRTjADaC34SFtsPU+gCyMufBvi2JC3dMTl2 55nzcPi6BDyompUk2fbVSWw3UUUufYNW/mUufwsfWWVcH2sz/2MVgUOXlRGu3PWa UdWKedoRbirRdvR6bmjP9kwkmevpM78pCqWsavaYuxcBr7J4ksj1rlS64y6Mw+6n o8kIBWiL8Wxz8oNJLfkrUy2Mx6eLXHrsGkLYUsYdYamrjA5xDQ2oXT6NGa5IEMai 8SGEkNRIdcJ8mbWmAE8qGVNw5iAe9SWODXG4ck44lqYYd3A== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 2eb53334 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 11:15:01 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v7 7/8] argp: do not display option name translations if __libc_enable_secure Date: Sat, 21 Jun 2025 13:13:54 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 Sat Jun 21 11:13:55 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114807 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 0B6AD38CED16 for ; Sat, 21 Jun 2025 11:36:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0B6AD38CED16 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=albinoniB header.b=ZJ/2zjhf 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 64A8338BEC00 for ; Sat, 21 Jun 2025 11:15:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 64A8338BEC00 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 64A8338BEC00 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=1750504522; cv=none; b=aXYTzJPQsCscwyHIoDVYMq6obgnlUpqwpfLn9oa05LbNPjNVIUTmQZZftd3DIXC7wP5r5P2rWetUE9Qje9G3UDwrggdg+bnCmT3AWv/7Vphq3XoZKcGu6l4stTJI1nfBr6RH5sgXRhbJ5YAnjegF6OzvXlPQ28Lvd7BJ6nwh6Pg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750504522; c=relaxed/simple; bh=5NKE/o5ABGcufjxaBBaIMG2m7lDPk3WEGbXVSDEuMzk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=HoiNvZEHyKFhdx7xAG0KQuZ29NsiKBUN0YqrlSFNKCG9oZiWzUmz3lkbQ42R0C8pzLfoKwNAYzNy+WYdVb9XCH6ZKjwrntKHjV8tS+KDfjHVzq7LopXJhTt83RgK7lKZvKwnTw7X40hmfGVbsphWFsauJ1CWG8amWW+3XsSMzY0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 64A8338BEC00 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 16390a5c for ; Sat, 21 Jun 2025 11:15:08 +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= albinoniB; bh=EgHpCNumOGpo+z5BLdscZgmvJ2I=; b=ZJ/2zjhfM5mmuOSYTL XFKTKVduKvvWXlB/RIp0J6sV0AlZEUNpnNaaHDcjBO61SjH2Y/BCgfjnegejnahO kTIJ9pCECKFdWOgQncLsbxJGyby1kw3abZ7Zaj1cHmmQi2NdMxc981rAa/bso/Pe eQoX3y5mUSAsel2nT8l7vI/dC5BviclMKF9ny2QBrljzTW0JQ1ytDicDqeW8Xvoe DHIWMVtFpwvS7FCZ+ehKYe7/3AipDnK3BCLLfKUqY3PVgX+0vsuByM9XF9fdsprs LRGxTJn5ocxFkuZwkVllDM7D5xDQ1y8VxiR/l5C1xDe3ey1/uq1w8iAutr+58STI /wBw== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id d1847ce1 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 11:15:02 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v7 8/8] posix: Add getopt_long_collision Date: Sat, 21 Jun 2025 13:13:55 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 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 | 24 +++++++ posix/Makefile | 10 +++ posix/Versions | 2 +- posix/bits/getopt_ext.h | 5 ++ posix/getopt1.c | 49 ++++++++++++++ posix/tst-getopt_long_collision.c | 66 +++++++++++++++++++ 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, 211 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 d8a18a8496..e9e8a4e872 100644 --- a/manual/getopt.texi +++ b/manual/getopt.texi @@ -383,6 +383,30 @@ 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 5b4a025004..d975f8c092 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 \ @@ -341,6 +342,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 ae237ce9d4..351976fbe8 100644 --- a/posix/Versions +++ b/posix/Versions @@ -160,7 +160,7 @@ libc { posix_spawn_file_actions_addtcsetpgrp_np; } GLIBC_2.42 { - 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..4cd9447709 --- /dev/null +++ b/posix/tst-getopt_long_collision.c @@ -0,0 +1,66 @@ +#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 835af57863..59ac449552 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2596,6 +2596,7 @@ GLIBC_2.42 cfgetobaud F GLIBC_2.42 cfsetbaud F GLIBC_2.42 cfsetibaud F GLIBC_2.42 cfsetobaud F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_barrier_destroy F diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist index ba9558da6f..5cdb7b4e09 100644 --- a/sysdeps/mach/hurd/x86_64/libc.abilist +++ b/sysdeps/mach/hurd/x86_64/libc.abilist @@ -2279,6 +2279,7 @@ GLIBC_2.42 cfgetobaud F GLIBC_2.42 cfsetbaud F GLIBC_2.42 cfsetibaud F GLIBC_2.42 cfsetobaud F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_barrier_destroy F diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index a22e651432..80edfddd84 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2762,6 +2762,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 4b5736a3b6..dfd6163b53 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -3109,6 +3109,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index b8a44784bd..ada14f15e4 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2523,6 +2523,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index 8f04b7ae8f..a993bc3333 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2815,6 +2815,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index be208a3db4..f017d0374f 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2812,6 +2812,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 6325fc12c4..9d5371fe02 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2799,6 +2799,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 86b3fbdeec..189a1f09ea 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2836,6 +2836,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index 6555592d86..ccf82fc73f 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -3019,6 +3019,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index 9807fd7689..e9232f1886 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2283,6 +2283,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index cb00b1af8c..590e64361c 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2795,6 +2795,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index a45e55f2c2..6d7462bc13 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2962,6 +2962,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index b92e42b03f..54a0ff3809 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2848,6 +2848,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index f92c9f1299..7a521432f1 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2845,6 +2845,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 4d51cc428f..d16bf9cd3e 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2923,6 +2923,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 tcgetattr F GLIBC_2.42 tcsetattr F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 7f90fadc76..33068905f2 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2921,6 +2921,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 tcgetattr F GLIBC_2.42 tcsetattr F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index fc366d1bd0..846c383ad5 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2929,6 +2929,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 tcgetattr F GLIBC_2.42 tcsetattr F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index debd5c37c9..175ca766bb 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2831,6 +2831,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 tcgetattr F GLIBC_2.42 tcsetattr F diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index b62d59f1af..654d871139 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2273,6 +2273,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 883e66f3ae..5b824b51fb 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -3152,6 +3152,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index 84cd9e0e18..978479bba7 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -3197,6 +3197,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index 8832568ab3..cf76f9c74b 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2906,6 +2906,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index b6ff8016e4..bd3b2980bd 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2982,6 +2982,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 pthread_gettid_np F GLIBC_2.42 uabs F GLIBC_2.42 uimaxabs F diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index 42ddd9ed3e..48df6f7cde 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2526,6 +2526,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 82f7d36e01..0a0b32eaa9 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2726,6 +2726,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 5cb06233a2..7221d9ce78 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -3150,6 +3150,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index 32ec7f28b2..c5a333ea8f 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2943,6 +2943,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index 1efe9aae8c..b7252b22d9 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2842,6 +2842,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index 13c1d88d1c..ca461307de 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2839,6 +2839,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index c49edb2026..d42265fb28 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3171,6 +3171,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index a5a4263ddd..7433fea93a 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2807,6 +2807,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 10d2ed46e4..3294f6e63f 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2758,6 +2758,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x8 GLIBC_2.42 opttextdomain D 0x8 GLIBC_2.42 pthread_gettid_np F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index ca5986772a..cf5facf812 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2777,6 +2777,7 @@ GLIBC_2.42 cfsetispeed F GLIBC_2.42 cfsetobaud F GLIBC_2.42 cfsetospeed F GLIBC_2.42 cfsetspeed F +GLIBC_2.42 getopt_long_collision F GLIBC_2.42 optctxt D 0x4 GLIBC_2.42 opttextdomain D 0x4 GLIBC_2.42 pthread_gettid_np F