aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2025-08-31 14:29:56 +0100
committerPádraig Brady <P@draigBrady.com>2025-08-31 19:25:38 +0100
commitebd670e7eb2d3e5c0dadac68efcf37f79958c4d5 (patch)
tree6530020dfe4bbd17c5c60271f22dddc9c8cf3652
parentb2sum: --length: fix upper bound check (diff)
downloadcoreutils-ebd670e7eb2d3e5c0dadac68efcf37f79958c4d5.tar.gz
coreutils-ebd670e7eb2d3e5c0dadac68efcf37f79958c4d5.zip
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
-rw-r--r--NEWS4
-rw-r--r--src/ls.c16
-rwxr-xr-xtests/ls/block-size.sh21
3 files changed, 35 insertions, 6 deletions
diff --git a/NEWS b/NEWS
index 988cb96a8..24430cedb 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 d9faddee4..d4aae25ca 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 9c092f037..501c7f82b 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