bug#79497: fmt breaks lines when it does not need to
Pádraig Brady <[email protected]> Wed, 7 Jan 2026 17:22:13 +0000
| Newsgroups | gmane.comp.gnu.core-utils.bugs |
|---|---|
| Message-ID | <[email protected]> |
On 23/09/2025 18:00, Bruno Haible wrote: > Hi Pádraig, > > Thanks for answering. So, we have the multibyte problem and the > newline-included problem. > > Pádraig Brady wrote: >> The code seems to follow the man page and includes the \n in the char count. >> Note fold -w does not count the newline which is what I'd expect. > > I ran this test case with various 'fmt' implementations: > > $ echo 'Hello world' | fmt -w 11 > Hello > world > $ echo 'Hello world' | fmt -w 12 > Hello world > > The minimum -w option that produces a single line: > > GNU 12 > macOS, FreeBSD 11 > NetBSD 11 (-g 10 -w 11) > OpenBSD 11 > AIX, Solaris 12 > > So, the BSD implementations don't count the newline. The attached aligns the -w interpretation with fold(1), and BSD fmt(1). Not closing this bug until we get full multi-byte support. cheers, Padraig
fmt-w-inclusive.patch
(text/x-patch, 3.3 KB)
From 83390333864b79b9885c22c9c6e9a776c52eeed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]> Date: Wed, 7 Jan 2026 17:15:28 +0000 Subject: [PATCH] fmt: interpret -w as an inclusive maximum This aligns with `fold -w` and BSD `fmt` implementations. * src/fmt.c (fmt_paragraph): Check len <= max_width. * tests/fmt/width.sh: Add a new test. * tests/local.mk: Reference the new test. * NEWS: Mention the change in behavior. Addresses part of https://bugs.gnu.org/79497 --- NEWS | 3 +++ src/fmt.c | 2 +- tests/fmt/width.sh | 40 ++++++++++++++++++++++++++++++++++++++++ tests/local.mk | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100755 tests/fmt/width.sh diff --git a/NEWS b/NEWS index eb9c5e2c4..240edc562 100644 --- a/NEWS +++ b/NEWS @@ -53,6 +53,9 @@ GNU coreutils NEWS -*- outline -*- ** Changes in behavior + 'fmt' -w,--width no longer includes '\n' in the width of a line. + I.e., the specified width is interpreted to be an _inclusive_ maximum. + 'ptx' -t is no longer a no-op, and now sets the default width to 100 columns. 'timeout' now honors ignored signals and will not propagate them. E.g., diff --git a/src/fmt.c b/src/fmt.c index 127e7ba4b..ae689ec28 100644 --- a/src/fmt.c +++ b/src/fmt.c @@ -908,7 +908,7 @@ fmt_paragraph (void) len += (w - 1)->space + w->length; /* w > start >= word */ } - while (len < max_width); + while (len <= max_width); start->best_cost = best + base_cost (start); } diff --git a/tests/fmt/width.sh b/tests/fmt/width.sh new file mode 100755 index 000000000..981ca9666 --- /dev/null +++ b/tests/fmt/width.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Exercise the fmt -w option. + +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ fmt + +# Ensure width is max display width. +# Before v9.10, width incorrectly included the \n character +printf 'aa bb cc dd ee' | fmt -w 8 > out || fail=1 +cat <<\_EOF_ > exp || framework_failure_ +aa bb cc +dd ee +_EOF_ +compare exp out || fail=1 + +printf 'aa bb cc dd ee' | fmt -w 7 > out || fail=1 +cat <<\_EOF_ > exp || framework_failure_ +aa +bb cc +dd ee +_EOF_ +compare exp out || fail=1 + + +Exit $fail diff --git a/tests/local.mk b/tests/local.mk index 5547a3f9a..58301bec3 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -251,6 +251,7 @@ all_tests = \ tests/fmt/goal-option.sh \ tests/fmt/long-line.sh \ tests/fmt/non-space.sh \ + tests/fmt/width.sh \ tests/misc/echo.sh \ tests/env/env.sh \ tests/env/env-signal-handler.sh \ -- 2.52.0