From: Pádraig Brady
Date: Sun, 31 Aug 2025 13:29:56 +0000 (+0100) Subject: ls: fix alignment with locale formatted --size X-Git-Tag: v9.8~84 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ebd670e7eb2d3e5c0dadac68efcf37f79958c4d5;p=thirdparty%2Fcoreutils.git ls: fix alignment with locale formatted --size Fix allocated size alignment in locales with multi-byte grouping chars. Tested with: LC_ALL=sv_SE.utf8 ls --size --block-size=\'k * src/ls.c (print_file_name_and_frills): Don't rely on printf("%*s", width, string) to pad multi-byte strings appropriately. Instead work out the padding required and use: printf("%*s%s", padding, "", string) to pad multi-byte appropriately. * tests/ls/block-size.sh: Add a test case. * NEWS: Mention the bug fix. Fixes https://bugs.gnu.org/79347 --- diff --git a/NEWS b/NEWS index 988cb96a88..24430cedbe 100644 --- a/NEWS +++ b/NEWS @@ -35,6 +35,10 @@ GNU coreutils NEWS -*- outline -*- a confusing error about changing permissions. [This bug was present in "the beginning".] + "ls --size --block-size=\'k" could misalign output in locales + with multi-byte thousands grouping characters. + [This bug was present in "the beginning".] + 'od --strings' with '-N' now works correctly. Previously od might write a NUL byte after a heap buffer, or output invalid addresses. [These bugs were present in "the beginning".] diff --git a/src/ls.c b/src/ls.c index d9faddee41..d4aae25ca8 100644 --- a/src/ls.c +++ b/src/ls.c @@ -4869,10 +4869,18 @@ print_file_name_and_frills (const struct fileinfo *f, size_t start_col) format_inode (buf, f)); if (print_block_size) - printf ("%*s ", format == with_commas ? 0 : block_size_width, - ! f->stat_ok ? "?" - : human_readable (STP_NBLOCKS (&f->stat), buf, human_output_opts, - ST_NBLOCKSIZE, output_block_size)); + { + char const *blocks = + (! f->stat_ok + ? "?" + : human_readable (STP_NBLOCKS (&f->stat), buf, human_output_opts, + ST_NBLOCKSIZE, output_block_size)); + int blocks_width = mbswidth (blocks, MBSWIDTH_FLAGS); + int pad = 0; + if (0 <= blocks_width && block_size_width && format != with_commas) + pad = block_size_width - blocks_width; + printf ("%*s%s ", pad, "", blocks); + } if (print_scontext) printf ("%*s ", format == with_commas ? 0 : scontext_width, f->scontext); diff --git a/tests/ls/block-size.sh b/tests/ls/block-size.sh index 9c092f0378..501c7f82be 100755 --- a/tests/ls/block-size.sh +++ b/tests/ls/block-size.sh @@ -26,9 +26,9 @@ mkdir sub cd sub for size in 1024 4096 262144; do - echo foo | dd conv=sync bs=$size >file$size || fail=1 + echo foo | dd conv=sync bs=$size >file$size || framework_failure_ done -touch -d '2001-01-01 00:00' file* || fail=1 +touch -d '2001-01-01 00:00' file* || framework_failure_ size_etc='s/[^ ]* *[^ ]* *//' @@ -183,4 +183,21 @@ EOF compare exp out || fail=1 +# Ensure --size alignment with multi-byte grouping chars +# which wasn't the case before coreutils v9.8 +cd sub +for sizem in 1 10; do + echo foo | + dd conv=sync bs=$((sizem*1024*1024)) >file${sizem}M || framework_failure_ +done + +# If any of these unavailable, the C fallback should also be aligned +for loc in sv_SE.UTF-8 $LOCALE_FR_UTF8; do + test $(LC_ALL=$loc ls -s1 --block-size=\'k | + tail -n+2 | cut -dK -f1 | + while IFS= read size; do + printf '%s\n' "$size" | LC_ALL=$loc wc -L + done | uniq | wc -l) = 1 || fail=1 +done + Exit $fail