On Solaris OpenIndiana, there is one test failure: FAIL: tests/misc/numfmt Specifically, the tests lcl-fmt-2, lcl-fmt-3 fail. See the attached log file.
I can easily reproduce it: $ LC_ALL=fr_FR.UTF-8 src/numfmt --format "--%'10f--" 50000 --50�000-- whereas $ LC_ALL=en_US.UTF-8 src/numfmt --format "--%'10f--" 50000 -- 50,000-- What happens is that numfmt prepares a format string "%'.*Lf%s" and passes it to snprintf(), in the fr_FR.UTF-8 locale. Solaris 11 OpenIndiana and Solaris 11 OmniOS have a bug here: when the thousands-separator is a multibyte character, snprintf() takes only the first byte of it. This is not a problem on other platforms: A test program (attached) shows that: - on Solaris 11.4, the thousands-separator is U+0020 = SPACE, a single-byte character. - on glibc, it is U+202F NARROW NO-BREAK SPACE, and snprintf stores it entirely in the result string. - on Solaris 11 OpenIndiana / OmniOS, it is U+00A0 NO-BREAK SPACE = "\xc2\xa0", and snprintf() takes only the first byte. Later, the padding pass runs mbswidth() on the returned string, and due to this invalid byte sequence mbswidth() returns -1, and no padding characters are added. The fix belongs in Solaris 11 or Gnulib; the numfmt source code should not need any changes. I'll deal with that; this should not delay the coreutils release. Bruno
======================================================== GNU coreutils 9.6.53-14af8: ./tests/test-suite.log ======================================================== # TOTAL: 658 # PASS: 503 # SKIP: 154 # XFAIL: 0 # FAIL: 1 # XPASS: 0 # ERROR: 0 .. contents:: :depth: 2 FAIL: tests/misc/numfmt ======================= numfmt (GNU coreutils) 9.6.53-14af8 Copyright (C) 2025 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Assaf Gordon. 1... 2... 3... 4... 5... 5.1... 5.2... 6... 7... 7a... 8... 9... 10... 11... 12... 13... 14... 15... 16... 17... 18... 19... 20... 21... 22... 23... 24... 25... 26... 27... neg-1... neg-2... neg-3... neg-4... neg-5... neg-6... neg-7... float-1... float-2... float-3... unit-1... unit-2... unit-3... unit-4... unit-5... unit-6... unit-7... unit-7.1... unit-7.2... unit-7.3... unit-8... unit-9... unit-10... suf-1... suf-2... suf-2.1... suf-3... suf-4... suf-5... suf-6... suf-7... suf-8... suf-9... suf-10... suf-11... suf-12... suf-13... suf-14... suf-15... suf-16... suf-17... suf-18... suf-19... suf-20... grp-1... grp-2... pad-1... pad-2... pad-3... pad-3.1... pad-4... pad-5... pad-6... pad-7... pad-8... delim-1... delim-2... delim-3... delim-4... delim-5... delim-6... delim-err-1... field-1... field-2... field-3... field-4... field-5... field-6... field-8... field-range-1... field-range-2... field-range-3... field-range-4... field-range-5... field-range-6... field-range-7... field-range-8... field-range-9... field-range-10... field-range-11... field-range-12... field-range-13... field-range-14... field-range-15... field-range-16... field-range-17... field-range-18... field-range-19... all-fields-1... field-range-err-1... field-range-err-2... field-range-err-3... field-range-err-4... field-range-err-6... field-range-err-7... field-range-err-8... field-range-err-9... field-range-err-10... field-range-err-11... field-range-err-12... field-range-err-13... whitespace-1... whitespace-2... whitespace-3... whitespace-4... whitespace-5... whitespace-6... whitespace-7... whitespace-8... mix-1... mix-2... mix-3... mix-4... mix-5... mix-6... mix-7... mix-8... mix-10... mix-11... mix-12... mix-13... mix-14... header-1... header-2... header-3... header-4... header-5... header-6... header-7... header-8... header-9... strtod-1... strtod-2... strtod-5... strtod-6... strtod-6.1... strtod-9... strtod-10... strtod-11... dbl-to-human-1... dbl-to-human-2... dbl-to-human-2.1... dbl-to-human-2.2... dbl-to-human-2.3... dbl-to-human-2.4... dbl-to-human-2.5... dbl-to-human-2.6... dbl-to-human-2.7... dbl-to-human-2.8... dbl-to-human-3... dbl-to-human-3.1... dbl-to-human-4... dbl-to-human-5... dbl-to-human-6... dbl-to-human-7... dbl-to-human-8... dbl-to-human-9... dbl-to-human-10... dbl-to-human-11... dbl-to-human-12... dbl-to-human-13... dbl-to-human-14... dbl-to-human-15... dbl-to-human-16... dbl-to-human-17... dbl-to-human-18... dbl-to-human-19... dbl-to-human-20... dbl-to-human-21... dbl-to-human-22... dbl-to-human-23... dbl-to-human-24... dbl-to-human-25... dbl-to-human-25.1... dbl-to-human-26... dbl-to-human-27... dbl-to-human-28... dbl-to-human-29... dbl-to-human-30... dbl-to-human-31... dbl-to-human-32... dbl-to-human-33... round-1... round-2... round-3... round-4... round-5... round-1-up... round-2-up... round-3-up... round-4-up... round-5-up... round-1-down... round-2-down... round-3-down... round-4-down... round-5-down... round-1-to-zero... round-2-to-zero... round-3-to-zero... round-4-to-zero... round-5-to-zero... round-1-near... round-2-near... round-3-near... round-4-near... round-5-near... leading-1... leading-2... leading-3... leading-4... leading-5... precision-1... precision-2... precision-3... precision-4... precision-5... precision-6... precision-7... precision-8... precision-9... debug-1... debug-1.1... debug-2... devdebug-1... devdebug-2... devdebug-3... devdebug-4... devdebug-5... devdebug-6... devdebug-7... devdebug-9... devdebug-10... devdebug-11... help-1... fmt-err-1... fmt-err-2... fmt-err-3... fmt-err-4... fmt-err-5... fmt-err-6... fmt-err-9... fmt-err-10... fmt-err-11... fmt-1... fmt-2... fmt-3... fmt-4... fmt-5... fmt-6... fmt-7... fmt-8... fmt-9... fmt-10... fmt-11... fmt-12... fmt-13... fmt-14... fmt-15... fmt-16... fmt-17... fmt-18... fmt-22... fmt-23... ign-err-1... ign-err-2... ign-err-3... ign-err-4... ign-err-5... ign-err-7... ign-err-8... ign-err-9... ign-err-m1... ign-err-m1.1... ign-err-m1.3... ign-err-m2... ign-err-m2.1... ign-err-m2.2... ign-err-m3... ign-err-m3.1... large-1... large-2... large-3... large-4... large-3.1... large-3.2... large-3.3... large-3.4... large-3.5... large-3.6... large-3.7... large-3.8... large-3.9... large-3.10... large-3.11... large-3.12... large-3.13... large-3.14... large-3.15... large-3.16... large-3.17... large-3.18... large-3.19... large-3.20... large-3.21... large-3.22... large-3.23... large-3.24... large-3.25... large-3.26... large-3.27... large-3.28... large-3.29... large-3.30... large-3.31... large-3.32... large-3.33... large-3.34... large-4.1... large-4.2... large-4.3... large-4.4... large-4.5... large-4.6... large-4.7... large-4.8... large-4.9... large-4.10... large-4.11... large-4.12... large-4.13... large-4.14... large-4.15... large-4.16... large-4.17... large-4.18... large-4.19... large-4.20... large-4.21... large-5.1... large-5... large-6... large-7... large-8... large-10... large-11... large-12... large-13... large-13.1... large-14... large-14.1... large-14.2... large-15... large-16... strtod-3... strtod-7... debug-4... debug-5... ign-err-10... ign-err-11... lcl-grp-1... lcl-grp-2... lcl-grp-3... lcl-stdtod-1... lcl-dbl-to-human-1... lcl-fmt-1... lcl-fmt-2... numfmt.pl: test lcl-fmt-2: stdout mismatch, comparing lcl-fmt-2.1 (expected) and lcl-fmt-2.O (actual) *** lcl-fmt-2.1 Mon Apr 7 17:07:25 2025 --- lcl-fmt-2.O Mon Apr 7 17:07:25 2025 *************** *** 1 **** ! -- 50?1?7000-- --- 1 ---- ! --50?1?7000-- lcl-fmt-3... numfmt.pl: test lcl-fmt-3: stdout mismatch, comparing lcl-fmt-3.1 (expected) and lcl-fmt-3.O (actual) *** lcl-fmt-3.1 Mon Apr 7 17:07:25 2025 --- lcl-fmt-3.O Mon Apr 7 17:07:25 2025 *************** *** 1 **** ! --50?1?7000 -- --- 1 ---- ! --50?1?7000-- lcl-fmt-4... lcl-fmt-5... lcl-fmt-6... lcl-fmt-7... auto-suf-si-A... auto-suf-si-B... auto-suf-si-C... auto-suf-si-D... auto-suf-si-E... auto-suf-iec-E... auto-suf-auto-E... auto-suf-iec-to-ieci-E... auto-suf-ieci-to-iec-E... auto-suf-si-F... auto-suf-si-G... auto-suf-iec-G... auto-suf-auto-G... auto-suf-iec-to-ieci-G... auto-suf-ieci-to-iec-G... auto-suf-si-H... auto-suf-si-I... auto-suf-si-J... auto-suf-si-K... auto-suf-iec-K... auto-suf-auto-K... auto-suf-iec-to-ieci-K... auto-suf-ieci-to-iec-K... auto-suf-si-L... auto-suf-si-M... auto-suf-iec-M... auto-suf-auto-M... auto-suf-iec-to-ieci-M... auto-suf-ieci-to-iec-M... auto-suf-si-N... auto-suf-si-O... auto-suf-si-P... auto-suf-iec-P... auto-suf-auto-P... auto-suf-iec-to-ieci-P... auto-suf-ieci-to-iec-P... auto-suf-si-Q... auto-suf-iec-Q... auto-suf-auto-Q... auto-suf-iec-to-ieci-Q... auto-suf-ieci-to-iec-Q... auto-suf-si-R... auto-suf-iec-R... auto-suf-auto-R... auto-suf-iec-to-ieci-R... auto-suf-ieci-to-iec-R... auto-suf-si-S... auto-suf-si-T... auto-suf-iec-T... auto-suf-auto-T... auto-suf-iec-to-ieci-T... auto-suf-ieci-to-iec-T... auto-suf-si-U... auto-suf-si-V... auto-suf-si-W... auto-suf-si-X... auto-suf-si-Y... auto-suf-iec-Y... auto-suf-auto-Y... auto-suf-iec-to-ieci-Y... auto-suf-ieci-to-iec-Y... auto-suf-si-Z... auto-suf-iec-Z... auto-suf-auto-Z... auto-suf-iec-to-ieci-Z... auto-suf-ieci-to-iec-Z... auto-suf-si-a... auto-suf-si-b... auto-suf-si-c... auto-suf-si-d... auto-suf-si-e... auto-suf-si-f... auto-suf-si-g... auto-suf-si-h... auto-suf-si-i... auto-suf-si-j... auto-suf-si-k... auto-suf-iec-k... auto-suf-auto-k... auto-suf-iec-to-ieci-k... auto-suf-ieci-to-iec-k... auto-suf-si-l... auto-suf-si-m... auto-suf-si-n... auto-suf-si-o... auto-suf-si-p... auto-suf-si-q... auto-suf-si-r... auto-suf-si-s... auto-suf-si-t... auto-suf-si-u... auto-suf-si-v... auto-suf-si-w... auto-suf-si-x... auto-suf-si-y... auto-suf-si-z... z1... z3... z2... z4... z5... FAIL tests/misc/numfmt.pl (exit status: 1)
#include <langinfo.h> #include <locale.h> #include <stdio.h> #include <wchar.h> int main () { wchar_t wbuf[80]; setlocale (LC_ALL, "fr_FR.UTF-8"); printf ("thousands_sep = |%s| = |%s|\n", localeconv()->thousands_sep, nl_langinfo (THOUSEP)); printf ("%'.*f\n", 0, 50000.0); swprintf (wbuf, 80, L"%'.*f\n", 0, 50000.0); printf ("%ls", wbuf); }