From patchwork Sat Jun 21 16:41:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114810 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 351E33B1B461 for ; Sat, 21 Jun 2025 18:46:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 351E33B1B461 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=SvH+XQLP 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 8B8C53927E08 for ; Sat, 21 Jun 2025 16:42:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8B8C53927E08 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 8B8C53927E08 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=1750524174; cv=none; b=yDt5FL1Pvp0WVvZLKfUHPL1dSXSjzZ0vBF+PDP8n2666/RYzA8OJ+4tBjcJqsg3kPys66qklR6DMWCcZnz4iDTJb5KlkX6xVghOFPyvDeRFC1APCJiBGGVU8wSIeeDjtBF0s/1EqDypBoROrS1rCD/f/Y/C2RMxma3oaeLspWmo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750524174; c=relaxed/simple; bh=GEvV5Fomt4W3jUlwYo7LjQ4+cD72grtbaW3ra5QnTqs=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=E//Gj+mO6wbVbKny5AwGkLMfYNpKVS3mj9JupODEs14yywRL7zgcYheWHe/GKmorBXoLoowwC6F0UA4WEfNhsI2JqiMxedCSsNtYIPVM8jp/M6L9O539JSnIPlL3D9zopQLf7/n7bouRUmqTQ6DVi5hf5BUa9SHHs2w9LiBCqUc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8B8C53927E08 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 4d642783 for ; Sat, 21 Jun 2025 16:42:51 +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=SvH+XQLPFpR+hdYs5YLoNn774oxPexLKN9Te8Ns Zlk9b41ofur7u5sC/XBRbcyBOSa/6lpUuSXlL2d+4M+LPVjE+LY5ZCVkpd+4UIjg 2cCdFvj9jiHRxaKn4Vc+PDOV5Iy8hOvVAClS0Pz0HsSQA2wo0ouzIwbv/QbvKsrX ieu9+vVrG5d3kaCTA4ss4d1ysqPb/WXSSl/EIs40UUGxsvA10F8A5ERhipLT6vXI KDj4hJIslUea3AJ+OvtewoGdVLi5enWbQqdvIqYEa255/GLt8vsrpNmRdZxzFa04 673/duOs4erW3lCi8SIS5chiIngrKdy166IMAzAkGmaXa4g== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id cde73ec1 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 16:42:46 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v8 1/8] posix: allow getopt_long to match translated option names Date: Sat, 21 Jun 2025 18:41:35 +0200 Message-ID: <5258dc66f0e8b324434c5bf2d39f7d9e7892153f.1750519557.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.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 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 16:41:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114811 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 5AAED3B1B466 for ; Sat, 21 Jun 2025 18:46:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5AAED3B1B466 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=CK39/FnC 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 7C8E039D11ED for ; Sat, 21 Jun 2025 16:42:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7C8E039D11ED 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 7C8E039D11ED 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=1750524176; cv=none; b=m9P7qSWBoVxTZfY9FmFwMs2zM+lzDT+rBQ0d0VK63aeiJivr8pHToNMh+bQcGzoQJTo9e7Xsf1U/QdV5YaRcEY7/YPTl6X6OsJc4BmK8xaQqIALOkLLcKISP7sbP0kXElTHkmyskW/rzJLRgO1j9sK99bJ0VpsKyRBsV1fiGLWI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750524176; c=relaxed/simple; bh=HawMJQVwBNHAPubJ6FEwaZv0jte3PoNcHQE5tbKvhz4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Cq+8rfNzvZi7s9NENNunLf94/Wn2gk//2odNQ1+De0FyDZB6hCr3zwB6Z0Ae2yKgvn38e6SnvuI4fN6VIEzFEhoDAiYjAKCEMzL+JqllvYfWwBkRi9X+9Vy0yPMIMFvvkIJv1pHiliFlXC4hw9E7wePfNVQK5tVF0GWqQT0fNMc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7C8E039D11ED Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id e6961357 for ; Sat, 21 Jun 2025 16:42:51 +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=CK39/FnCnZeO/1DfROFJpPc0jRi97Q3Z0eqlrdo AHsd/MhkjoQR3XfJALovX/5a4nNW9YISm9+93mhdddtPdI6KvZH6ud86QJes0ai0 MCAtK2A/VMKIhwoTyLJSWYcciHS2ZF2MBL08jIy/YU3Zfl+HlFm2Akz/+WYq1IzY cVuwzEqRK2sI6domJwci2PHGet8mC1bCrol1AfLpxaiu2PfbodE4N/dVf/a7TsBC oFR+gnsW0cinLloj4pOx2XZ+jNUTyOO+EQRdatrbXD4xd2hOPn1u8Z/7GbAmU/Xq N0/51ogiy1YfW750g+IYe4FkuhW2m6LZrmhKKsbRb4g1qnA== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id cfa484c7 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 16:42:46 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v8 2/8] posix: let the getopt caller set the translation context Date: Sat, 21 Jun 2025 18:41:36 +0200 Message-ID: <96e995144ed09db85ace5b9ea761e958c05d6c96.1750519557.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 16:41:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114816 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 CB41039FAF44 for ; Sat, 21 Jun 2025 18:47:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CB41039FAF44 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=Avv3Ohiy 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 872C839280D5 for ; Sat, 21 Jun 2025 16:42:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 872C839280D5 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 872C839280D5 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=1750524177; cv=none; b=O0beY++TJnkI5sxra3RoA4+ZCOMDr/OpBOJh6TPtkEijFgWFkTBpJ2MFuZDySr8pXIZYLz53YBvgoE5rM5zd9ozOyEq1bdh7ZeK9SFuAbm28Fx1G4GZW9Q5Dnbqt2gdgflGOSdkOCeWm7P66+0fZj9gc1NE7XqiTx5FjCuxg86M= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750524177; c=relaxed/simple; bh=sEHS1GxEr6dLfVP+dyZ0sBYWWAthEVIlzx/1hhaH3MM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=PArdoHXoE+aSdG7UFCkLS6o85CCcCiExpIJZ82eG3SWzN0lm65ltJDJmMAk0U+JM4SvQ9IwpzSpbVSgo5beY++2qFT2XJmyko3ngc3P9v9a2hC0reKs2co3k+Hq2DszJcpOWqky2Om3p5NedGEE+BfYMBi005gTYQmnLwrAvO/E= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 872C839280D5 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id d6703a79 for ; Sat, 21 Jun 2025 16:42:51 +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=Avv3OhiyyD5xs9nqxp DbJyoUI7Tc6sJefWZT1kgwZZJQb4uVZ5EDYHeYhRzV/sn1dowGEH6IUyjoy9PRHg OXuIwe3/U5fl98RIxellON+bZ1kB5PYKzoSQ2K5SJ11gKuGyQH+PnpW/m54VIWc2 wVTUGpbm/bc4/ZexADrmA+LqqX/Hsr/1nYi7JEA9wVBIyGXEFZ4Hk8R9tkwUnWn+ SvbM3WjVcLKuBhngQsmIUZq3JDVkIRIZ3y0+rLyRS6t2Bsca6h4BmzA0u41eoyXw GsXb9cp68OkziCQXp7umiuepGzg5EMlOAeAHCEFaoeSfsZDVwm5SXhO1nGba4Gtn qdZA== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id a4247f4a (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 16:42:47 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v8 3/8] argp: document translated names in --help and --usage Date: Sat, 21 Jun 2025 18:41:37 +0200 Message-ID: <1f517432460aad6a944a0a09e211b8af9787efbf.1750519557.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, 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 16:41:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114814 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 B09F83B785C7 for ; Sat, 21 Jun 2025 18:54:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B09F83B785C7 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=PUrnUuK0 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 CB565396F288 for ; Sat, 21 Jun 2025 16:42:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CB565396F288 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 CB565396F288 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=1750524179; cv=none; b=C+RUEeq9NaaKlb4WfLR6K6s6zQnbUaOpezY7ZVAsnp63XXqc5dt/GjGI/ZMDezKzkLk+jrd3kfWhZfi81Xk4YF+HI1VFcZBPmbJ2j2JWaJp/UQrdcFpdWZJeBA5zJz1H0jF1uPd55bvRw5xPkf2jSFZzKI7Dy511TsjTelVdGkg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750524179; c=relaxed/simple; bh=5JX5lJ+Pe/UPk+8hgKISpKLOEyEn+l7mmIV4agSL8bk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=JWquvmQuWHbpJuGiAqc8x7S2FZfdKw6xvOXSG2MJU2OSEpqJpXroqzSB8J19OLgWVo18Gn2o/ILOKjpR6uHB3dwzIzUYCaNsJBtwu84ULHLCUWYFDrLDzFQ7pIDd8wzeWTjjH/hYYnBXsXJas3AnMPUL7hFV1OSJyHaZXqXC/II= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CB565396F288 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 8c010f90 for ; Sat, 21 Jun 2025 16:42:51 +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=PUrnUuK0UpFEvu5bOZdTSxO8sRrVLKsznHwHezS jJBV4vPDevGtW+y3TVkkjjNNbEaKVbS7a4DUOTbEBi2zmstED2CQSVXKh7jBC6Yg 0zlvP0pF4vCSilkN07LUd5oeGxehgYXtfwLtfZeVjWRWrKXk1IGhEcNS1rAJ3Fw2 mlfXjGUPhK5qn5L9K1HSDfrv42uaBEnnkCFZpxoZhKi6v8sVNNxeIRaZ4lC8xWU7 s1rwHBKqd6sCmVLZXJobfckK4Vr+C7/VU4ag4vG4e++Ur3dClkswAeVyVzLPybL4 ZV2xDmqZwqB97Wb8vtJLFiKQKh9zLZuB7KaXJn6P8MPl5Gg== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id c0c504dd (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 16:42:47 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v8 4/8] posix: let the getopt caller choose the textdomain for translation Date: Sat, 21 Jun 2025 18:41:38 +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 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 16:41:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114812 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 29ABC3B21665 for ; Sat, 21 Jun 2025 18:47:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 29ABC3B21665 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=YCfGsU5S 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 52B0C396F28B for ; Sat, 21 Jun 2025 16:43:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 52B0C396F28B 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 52B0C396F28B 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=1750524181; cv=none; b=IvCxjLwY3toF1yOI1cWwM8PZv9xRWx7Ue3g/sJNIXZPuYXJtx47kvxqMQKBojp37pljm+tn4HwM/rs5TqEtmQ2sHI9PtH39w2HDOR//cdkeosQLMgK606uqWoR5OvWAHWGJPLJu+U/70KIv/0AMe+7qhYyAaZ/PacL0sJYp/9iE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750524181; c=relaxed/simple; bh=jcD3xf3dLpQgHC9I5alwKLCwg6Rhp7J+2eAqYJUnj+I=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Q9dOzBEoR486V5HiWmsou4X7nh4InD0FqjT30wkXv//6EGw8z02DRhOpwJ3sYAn0AKCWsCDCHeQBaiJngCTOvUpdCvTmwea5SmHgfRhjrVhnIRn0uzfAuZMf2qhGiZi/CK9RGpJxskVV8+XlVHamJBOB96Q4jaFot6qyZgEwawo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 52B0C396F28B Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 9352a29d for ; Sat, 21 Jun 2025 16:42:51 +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=YCfGsU5SMHvePm2whvaZ0Jv//yPUcqgrSElPWxm 2mEH6aet8sZ2euiHwUSCR7/s+3n9fT8wZYFWSskAxgPm9Pj0hZDDOOzl52jviaXa 5QA4dxTZCAN24lWGv7o8bLAB78gj2JKJApXs4GNdoT8GUC5YHgx9DlYZ3EC+0MDG If9Qj7ze2KZ01zGXlgqIT++xtdB3KyLkYR/rWTDlUnVWm3iaRrLVlsw++sdPKXyT bnA7ZSbukj+hAK2ogcv8BO5bGv10lcalJs8UYUcKvk7FFHY4TIQdzRuQe+jejcMe rJVV8Qx1kNmsNFqyl53xHuKyI7Ny682bEw4UHb8prCRuhsg== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id afc3b9c3 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 16:42:47 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v8 5/8] posix: do not allow option name translations for secure programs Date: Sat, 21 Jun 2025 18:41:39 +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.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 16:41:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114815 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 E1F9F3B89483 for ; Sat, 21 Jun 2025 18:55:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E1F9F3B89483 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=UzCOrKOO 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 8367139EEBAF for ; Sat, 21 Jun 2025 16:43:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8367139EEBAF 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 8367139EEBAF 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=1750524181; cv=none; b=U7akXHXXIx1djBnPR7WfKR6IxVBK/Bh/JdbyJBOQr3xlp6vEXt+2lQpLSERS25MMuRkxPhgZ21i5msZvafK6dgVRZ44i6+hue2YuD7m+Q/wj1xVJjp8CnRt5YAHWUDLBmvsoC6BXudWGAGPVaqWvnLAvvNut8S+1tyWFhVItb8o= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750524181; c=relaxed/simple; bh=llTFeO77/0H/wTVSq/doMdqCFP98Bw/zZSYZmZX3a7M=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=RV1Jk27m11eGfiVFKB+Pq0gIi3vvjWGEbaMHP50vQl20qXuPW5O5Wv9KpEQl+TcaRTwmjpXxD/cb/gTpmXGlia+pZeixAP0tbs2z1XAkmi34Gr5D6aHMlH11N41WwvRKH/5kjO31WxNtkrGFUOX280ycb+J8pw02opvFult08Jo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8367139EEBAF Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id a029b464 for ; Sat, 21 Jun 2025 16:42:52 +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=UzCOrKOOPbD6xLDbzi +YiX1HQ2U7vYr0DHufFI+XYHBRh2ehmVA3wqS69HdWL6UJr6B5JWEwrBzv4x6oYw Lmoy+pBr+EalhPcLm5OaTyrqD4h5mUBvpBgDdpyf2hcrKvxKNdGzVel0IZ7q2xKJ 4Gjr4JmyGxmd/9qWexbrWo5A1D44GGy8SJrMLYKy6infswSxz/LD8JdtvIgPsTbC 8DouwCxOjPeUuG1yLVCqfo0AgCZuMAgrGHTcUSepmiF6kMn06jfHfAf4ybWpw+Yo 80w9j+CpQvwDAJCVh7ykoDUQi18ilgYSXTd3ogrS03/7tC3uwSR0n4nHlr8rmuCi 39XQ== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 11b4ae64 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 16:42:48 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v8 6/8] posix, argp: Support deprecation of long option name translations Date: Sat, 21 Jun 2025 18:41:40 +0200 Message-ID: <1969fd9c8c850b3520a3388c5310c0e35c95d5b8.1750519557.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 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 16:41:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114813 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 446AB3AA3E79 for ; Sat, 21 Jun 2025 18:52:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 446AB3AA3E79 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=cDcfe23a 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 4A50A3A4D6C6 for ; Sat, 21 Jun 2025 16:43:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4A50A3A4D6C6 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 4A50A3A4D6C6 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=1750524183; cv=none; b=DUvgtyNWid2oaZRu6kZVMHxFSVgNUhRnLGNwC934sY4kS52jKgXIGM875XQd7pMeAr3UYE/BWamnpGOpHbnaSCFTxodK1Cmf1jQ7Vcb/In+u/xIEUX/9Wzf8SgyWnlfV46a5kAvTw+P1TtP3Qs/5N7szCx08ETx7mzJ8cFSuVG0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750524183; c=relaxed/simple; bh=htGT2RMX5xAHEqTNWNem7RyUyUZ3/1eyF/yXoj/Raws=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=oV2FL8IAVbI5sCNEEtiPCuxuulyUBwwyEBaXZloH67tgUZ+RDxrGJLqiHGh5VmlQ+F3s9e+LsZtXGX6vryt5XKUVkKmddNUaXz63gVHb3mSfRANH6kf54tixWsBHwghUYjtQ7oDFyW4yXZE9/Yk9FNNuoV9+djfXmynHOCVquiA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4A50A3A4D6C6 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id 81eb2cde for ; Sat, 21 Jun 2025 16:42:52 +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=cDcfe23a6TLRo1hreQNo8ZnBXliJuTVWMoSXtWA iTAbcXSep4wVk+tV2tLfHoenDF1SfVBfkXzRynnbsBfPB/iqf5QsLYeVnCR5LoRj UbSkJjcfSKEPSRB+4g+E6HnpVDhanEP29bQ/ZDpMUu2M8oZUafW50SlKDKoWKE67 hopDxiyQqnefrej8YMORXT8BPSAhXVr1q3vMHi2B7lHjaTeg/u1gUZMhhO7/DroS DeIk7XKkL8KkhP5xRtkSvu2wHr4H2axfVEtYlnmXIAFYAhH2nvJXrQLlEVWc1ama K3yAiY2nxJgI9uy62BNiZp5JeO+H9DXtk76ERsfzkXWtZvw== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id afaf7977 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 16:42:48 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v8 7/8] argp: do not display option name translations if __libc_enable_secure Date: Sat, 21 Jun 2025 18:41:41 +0200 Message-ID: <3a0ad584c27068965632ce9cb8769b183493dd2f.1750519557.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.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 --- 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 16:41:42 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivien Kraus X-Patchwork-Id: 114817 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 9DC3E39D2430 for ; Sat, 21 Jun 2025 18:54:29 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9DC3E39D2430 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=SUlQoZ17 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 5A7483A50814 for ; Sat, 21 Jun 2025 16:43:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5A7483A50814 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 5A7483A50814 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=1750524183; cv=none; b=EReHRPkSDDnjZBfRQCPg1Q1FwdJMkNwdaIf1vSyJqzPmrC01zDZSram4mVh8U7MdOffLYbMSyS8kEE5RYWnq48fCCujo/0o+Dl/1zvFVdiGUbE2cJizDWE/XkcyO22ZwhwpN41mbwXYlc6FTpW1oYnAaVdED60Klfc39KN8ET2g= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750524183; c=relaxed/simple; bh=BzoJ8PTPI5WVzcVg4gjhy+fQfdX1srl3NX5zvaNYn/A=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=m6LqUdhFXQEANEeDdW5FDrnFN2KDaDXyza/lt07E9TNchh+VlFGOhe3J6iGlRPksR4AWQip1unNCTRpWBXDKFFbQyE+gqgWOeKecySRZ3JDIp+xF6dnMVpkMd9eBP0TJyvollfq+YYZC9/7DRhuPKr6N0AQV2VGO4UoegDpb5RA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5A7483A50814 Received: from planete-kraus.eu (localhost [127.0.0.1]) by planete-kraus.eu (OpenSMTPD) with ESMTP id be481453 for ; Sat, 21 Jun 2025 16:42:52 +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=GIBJ7ax6ugabrY/qDYP5bc2kz9A=; b=SUlQoZ177YyRL1gOEy SbwHwc6WzSuOVicVNJMt8+hRbhEGo1CjBjsryGEUEyr43xfktGKAoK60gs1/u5fQ BllgsTLs5cy9dCPFymUSCuPL6u3sP5EvGN+Ykh2S8utXxL0XoEHjiMRLAcnmSgdN 0nPM9wGLnppIB3lsITbIzHsAXbXLFN6eDFrUSRs4BFq/GuHByPTrHqJABqwZNwzh OG1Vhjh28RDDsP21nTMC0eVqQdzp+G+hYQkT7lndKCbIu0qyuyAtin7+gu6hr/1b 0kUu31WmDjiLoNL6RtgDhHTFfn4SW30argp/1NxLvmrfnVDHZOe0JffgthaST3/x pXiw== Received: by planete-kraus.eu (OpenSMTPD) with ESMTPSA id a39b61e2 (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO); Sat, 21 Jun 2025 16:42:49 +0000 (UTC) From: Vivien Kraus To: libc-alpha@sourceware.org Cc: Vivien Kraus Subject: [PATCH v8 8/8] posix: Add getopt_long_collision Date: Sat, 21 Jun 2025 18:41:42 +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.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 This function is used before introducing a new option name with all known linguas to check that no translator has used the exact same name as a translation for a different option. It only checks for untranslated / translated collision, because: - translated / translated conflicts in the same language can be solved by the translator; - translated / translated conflicts in another language will not happen during a call to getopt_long. When a collision is detected, it only returns the untranslated side of the collision because the translator for the current locale knows which option conflicts with the untranslated one. It would maybe more useful for developers to have a maintainer script doing equivalent work, but this function serves as a way to remind them to check for collisions and discuss them with the translators before introducing a new option name. --- manual/getopt.texi | 22 +++++++ posix/Makefile | 10 +++ posix/Versions | 2 +- posix/bits/getopt_ext.h | 5 ++ posix/getopt1.c | 49 ++++++++++++++ posix/tst-getopt_long_collision.c | 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, 209 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..24d47fd233 100644 --- a/manual/getopt.texi +++ b/manual/getopt.texi @@ -383,6 +383,28 @@ not match a long option (or its abbreviation). @end deftypefun +It is possible for the programmer to introduce a new option name that +conflicts with the translation of an existing option name. Such a +case would disrupt the workflow of users as the new option would +replace the existing option. Before adding a new option to a program, +the developer should check for collisions with all known translations. + +@deftypefun int getopt_long_collision (const struct option *@var{longopts}, const char *@var{context}, const char *@var{domain}, const struct option **@var{first_collision}) + +Check whether there is a collision with any of the untranslated names +of @var{longopts} and any of the translated names in the current +locale. Translations are looked up with @var{context}, in +@var{domain}. Set @var{first_collision} to @code{NULL}, or to the +address of the first option whose untranslated name collides with +another option’s translated name. + +If the collision happens between two identical translations of +different options, it is not recognized, as it is simply a problem to +be solved by the translator. + +Return 0 if no collisions are detected, 1 if a collision is detected. +@end deftypefun + @node Getopt Long Option Example @subsection Example of Parsing Long Options with @code{getopt_long} diff --git a/posix/Makefile b/posix/Makefile index 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