bug#79347: Bad formatting for ls with block-size 'k

Pádraig Brady <[email protected]>
Newsgroups gmane.comp.gnu.core-utils.bugs
Message-ID <[email protected]>
On 30/08/2025 09:15, Peter Laan wrote:
> Hi,
> 
> I'm a GNU/Linux noob so maybe I'm doing something wrong. But see the
> attached image for badly formatted output from ls -s1 --block-size=\'k. The
> columns are not always aligned. This only happens when you have large files
> in the directory. Everything looks fine with --block-size=k.
> 
> I'm running Arch with the latest updates. ls version 9.7.

The issue is that printf("*s", width, multi_byte_string) doesn't count
width appropriately. In your sv_SE.UTF-8 locale, the number grouping
character is 3 UTF8 bytes which messes up the alignment.

The attached should address this,
which I'll push later today.

Marking this as done.

thanks,
Padraig
ls-block-align.patch (text/x-patch, 2.4 KB)
From 673ffd38184cd21e04e56f4b0ead2b6ef74c9f2f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Sun, 31 Aug 2025 14:29:56 +0100
Subject: [PATCH] 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.
* NEWS: Mention the bug fix.
---
 NEWS     |  4 ++++
 src/ls.c | 16 ++++++++++++----
 2 files changed, 16 insertions(+), 4 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..882752fe1 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 && 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);
-- 
2.50.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.