]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
ls: fix alignment with locale formatted --size
authorPádraig Brady <P@draigBrady.com>
Sun, 31 Aug 2025 13:29:56 +0000 (14:29 +0100)
committerPádraig Brady <P@draigBrady.com>
Sun, 31 Aug 2025 18:25:38 +0000 (19:25 +0100)
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

NEWS
src/ls.c
tests/ls/block-size.sh

diff --git a/NEWS b/NEWS
index 988cb96a889c9e60a09ef1ffb17aeb7614508732..24430cedbea560548ebed33ece288a1f5e231b63 100644 (file)
--- 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".]
index d9faddee41cff27c2db712a6a30dd52b592eb5af..d4aae25ca8a6aff0884bd6c8e4b3696db572e586 100644 (file)
--- 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);
index 9c092f03783f7e68e8b3180224ef91bfa57c7cd1..501c7f82be323b4b395e099b9d028b15cc7193d3 100755 (executable)
@@ -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