]> git.ipfire.org Git - thirdparty/coreutils.git/log
thirdparty/coreutils.git
8 hours agotests: stat: ensure independence from /proc/ master
Pádraig Brady [Fri, 10 Apr 2026 13:55:07 +0000 (14:55 +0100)] 
tests: stat: ensure independence from /proc/

* tests/stat/stat-mount.sh: Ensure stat -c '%a'
is independent from /proc.
https://github.com/coreutils/coreutils/pull/250

11 hours agotests: cut: ensure separate read paths checked
Pádraig Brady [Fri, 10 Apr 2026 10:24:58 +0000 (11:24 +0100)] 
tests: cut: ensure separate read paths checked

* tests/misc/read-errors.sh: Use cut -b as that has a separate
read path to cut -c.

11 hours agotests: Avoid accidental matching of the vendor field of $host
Bruno Haible [Fri, 10 Apr 2026 06:13:24 +0000 (08:13 +0200)] 
tests: Avoid accidental matching of the vendor field of $host

* tests/chgrp/basic.sh: Test $host_os, not $host_triplet.
* tests/chown/separator.sh: Likewise.
* tests/rm/r-root.sh: Likewise.
* tests/tail/pipe-f.sh: Likewise.
* tests/tail/tail-c.sh: Likewise.
* tests/tee/tee.sh: Likewise.
* tests/touch/dangling-symlink.sh: Likewise.

17 hours agoenv: avoid locking standard output for each printed variable
Collin Funk [Fri, 10 Apr 2026 04:59:12 +0000 (21:59 -0700)] 
env: avoid locking standard output for each printed variable

* src/env.c (main): Use fputs and putchar instead of printf.

17 hours agoprintenv: avoid locking standard output for each printed variable
Collin Funk [Fri, 10 Apr 2026 04:53:28 +0000 (21:53 -0700)] 
printenv: avoid locking standard output for each printed variable

* src/printenv.c (main): Use fputs and putchar instead of printf.

25 hours agomaint: remove last remaining assert()
Pádraig Brady [Thu, 9 Apr 2026 20:36:12 +0000 (21:36 +0100)] 
maint: remove last remaining assert()

* src/split.c (bytes_chunk_extract): Prefer affirm to assert,
as it allows for better static checking when compiling with -DNDEBUG.

25 hours agomaint: move tty-eof.pl to misc directory
Pádraig Brady [Thu, 9 Apr 2026 15:30:13 +0000 (16:30 +0100)] 
maint: move tty-eof.pl to misc directory

* tests/tty/tty-eof.pl: Rename to ...
* tests/misc/tty-eof.pl: ... this more general directory.
* tests/local.mk: Adjust accordingly.

25 hours agotests: tty-eof.pl: address FIXME re hardcoded Ctrl-d
Pádraig Brady [Thu, 9 Apr 2026 15:09:38 +0000 (16:09 +0100)] 
tests: tty-eof.pl: address FIXME re hardcoded Ctrl-d

* tests/tty/tty-eof.pl: Try to explicitly set EOF char to Ctrl-d
in case it's different.

25 hours agotests: tty-eof.pl: make fully table driven
Pádraig Brady [Thu, 9 Apr 2026 14:32:29 +0000 (15:32 +0100)] 
tests: tty-eof.pl: make fully table driven

* tests/tty/tty-eof.pl: Remove command specific logic,
and adjust commands to support general input.
Also add cut -b, as cut_bytes has its own read loop.

25 hours agotests: all: check empty tty input is handled appropriately
Pádraig Brady [Thu, 9 Apr 2026 14:12:45 +0000 (15:12 +0100)] 
tests: all: check empty tty input is handled appropriately

* tests/tty/tty-eof.pl: Test all commands twice.
Once with input and once with empty input.

25 hours agomaint: cat: avoid coverity NULL dreference warning
Pádraig Brady [Thu, 9 Apr 2026 20:23:35 +0000 (21:23 +0100)] 
maint: cat: avoid coverity NULL dreference warning

* src/cat.c (ensure_buf_size): Affirm we won't return NULL;

30 hours agocat: avoid memory allocation per file
Pádraig Brady [Wed, 8 Apr 2026 12:20:12 +0000 (13:20 +0100)] 
cat: avoid memory allocation per file

* src/cat.c (main): Only resize the allocated buffer when needed,
which avoids per file heap manipulation and mmap/munmap syscalls.

30 hours agocat: fix splice() from empty input
Pádraig Brady [Thu, 9 Apr 2026 10:17:10 +0000 (11:17 +0100)] 
cat: fix splice() from empty input

* src/cat.c (splice_cat): Ensure we don't retry a read() after
splice() completes, as this is significant on a tty.

34 hours agotests: tee: ensure intermittent data is handled
oech3 [Thu, 9 Apr 2026 04:52:50 +0000 (13:52 +0900)] 
tests: tee: ensure intermittent data is handled

* tests/tee/tee.sh: Add test case for input from pipe containing sleep.
https://github.com/coreutils/coreutils/pull/247

40 hours agomaint: touch: prefer timespec_cmp
Collin Funk [Thu, 9 Apr 2026 05:34:13 +0000 (22:34 -0700)] 
maint: touch: prefer timespec_cmp

* src/touch.c (main): Use timespec_cmp instead of comparing each member
of the timespec.

2 days agotests: date: fix false failure on OpenBSD 7.8
Pádraig Brady [Tue, 7 Apr 2026 22:17:36 +0000 (23:17 +0100)] 
tests: date: fix false failure on OpenBSD 7.8

* tests/date/date.pl: Set the max supported year to INT_MAX.
Most systems support INT_MAX+1900, but mktime() on OpenBSD 7.8
limits the passed tm_year to INT_MAX.
Reported by Bruno Haible.

3 days agotests: numfmt: avoid false failure on systems without long double
Pádraig Brady [Tue, 7 Apr 2026 20:44:56 +0000 (21:44 +0100)] 
tests: numfmt: avoid false failure on systems without long double

* tests/numfmt/numfmt.pl: Move recently added test that depends
on long double support to the appropriately guarded set.
Also reduce the value to be in the definitely safe long double range.
Reported by Bruno Haible.

3 days agomaint: cut: avoid discarded-qualifiers warnings
Pádraig Brady [Tue, 7 Apr 2026 13:35:25 +0000 (14:35 +0100)] 
maint: cut: avoid discarded-qualifiers warnings

Seen on GCC 15.2.1 with GLIBC 2.43 on Arch
Not seen on GCC 15.2.1 on GLIBC 2.42 on Fedora

* src/cut.c (search_bytes): Cast the return from memchr()
to avoid const propagation.
(find_field_delim): Adjust the return from strstr() similarly.
https://github.com/coreutils/coreutils/issues/244

3 days agotests: cat: avoid false failure on systems without splice
Pádraig Brady [Tue, 7 Apr 2026 11:20:10 +0000 (12:20 +0100)] 
tests: cat: avoid false failure on systems without splice

* tests/cat/splice.sh: Ensure splice is called multiple times
before we check specific invocation counts.
On Linux kernel 5.10 for example, splice from /dev/zero
returns EINVAL.

3 days agocat: use splice if operating on pipes or if copy_file_range fails
Collin Funk [Sun, 29 Mar 2026 23:13:01 +0000 (16:13 -0700)] 
cat: use splice if operating on pipes or if copy_file_range fails

On a AMD Ryzen 7 3700X system:

    $ timeout 10 taskset 1 ./src/cat-prev /dev/zero \
        | taskset 2 pv -r > /dev/null
    [1.67GiB/s]
    $ timeout 10 taskset 1 ./src/cat /dev/zero \
        | taskset 2 pv -r > /dev/null
    [9.03GiB/s]

On a Power10 system:

    $ taskset 1 ./src/yes | timeout 10 taskset 2 ./src/cat-prev \
        | taskset 3 pv -r > /dev/null
    [12.9GiB/s]
    $ taskset 1 ./src/yes | timeout 10 taskset 2 ./src/cat \
            | taskset 3 pv -r > /dev/null
    [81.8GiB/s]

* NEWS: Mention the improvement.
* src/cat.c: Include isapipe.h, splice.h, and unistd--.h.
(splice_cat): New function.
(main): Use it.
* src/local.mk (noinst_HEADERS): Add src/splice.h.
* src/splice.h: New file, based on definitions from src/yes.c.
* src/yes.c: Include splice.h.
(pipe_splice_size): Use increase_pipe_size from src/splice.h.
(SPLICE_PIPE_SIZE): Remove definition, moved to src/splice.h.
* tests/cat/splice.sh: New file, based on some tests in
tests/misc/yes.sh.
* tests/local.mk (all_tests): Add the new test.

3 days agobuild: update gnulib submodule to latest
Collin Funk [Tue, 7 Apr 2026 00:00:19 +0000 (17:00 -0700)] 
build: update gnulib submodule to latest

For the Gnulib commit 2c480fa522 (mbrtowc, mbrtoc32: Silence -Wshadow
warnings (regr. 2026-04-02)., 2026-04-06).

4 days agobuild: cut: fix compilation error on non C23 compilers
Pádraig Brady [Mon, 6 Apr 2026 21:35:39 +0000 (22:35 +0100)] 
build: cut: fix compilation error on non C23 compilers

* src/cut.c (main): Add curly brackets around variable
declaration in case label.
Reported by Bruno Haible.

4 days agotests: date: add large year test
Sylvestre Ledru [Thu, 2 Apr 2026 11:10:13 +0000 (13:10 +0200)] 
tests: date: add large year test

* tests/date/date.pl: Add the test case.
Add test case for https://github.com/uutils/coreutils/issues/9774
to verify with large dates.
https://github.com/coreutils/coreutils/pull/237

4 days agomaint: revert “avoid pthread_sigmask lock”
Paul Eggert [Mon, 6 Apr 2026 18:12:46 +0000 (11:12 -0700)] 
maint: revert “avoid pthread_sigmask lock”

* configure.ac (GNULIB_SIGACTION_SINGLE_THREAD): Remove.
This never worked (it was a misspelling) and the properly-spelled
identifier (whose spelling has since been renamed) is useful
mostly for programs like gzip that do not need Gnulib’s ‘lock’ module.
For coreutils, which needs ‘lock’ for other reasons, it’s overkill.

maint: avoid pthread_sigmask lock overhead
This matters only for MS-Windows.
* configure.ac (GNULIB_PTHREAD_SIGMASK_SINGLE_THREAD):
Define this instead of defining GNULIB_SIGACTION_SINGLE_THREAD.
The latter was a typo, and Gnulib has evolved anyway.

4 days agomaint: simplify c32issep
Paul Eggert [Sun, 5 Apr 2026 22:51:36 +0000 (15:51 -0700)] 
maint: simplify c32issep

* src/system.h (c32issep): Avoid unnecessary ‘!!’.

4 days agotests: expr: add short-circuit tests with parenthesized branches
Sylvestre Ledru [Fri, 3 Apr 2026 10:07:44 +0000 (12:07 +0200)] 
tests: expr: add short-circuit tests with parenthesized branches

* tests/expr/expr.pl: Add tests to verify that short-circuit
evaluation of | and & correctly skips parenthesized dead branches,
including nested parenthesized expressions containing division by zero.
https://github.com/uutils/coreutils/pull/11395
https://github.com/coreutils/coreutils/pull/238

4 days agotests: split: verify non-UTF-8 bytes are preserved in filenames
Sylvestre Ledru [Fri, 3 Apr 2026 10:23:52 +0000 (12:23 +0200)] 
tests: split: verify non-UTF-8 bytes are preserved in filenames

* tests/split/non-utf8.sh: New test to ensure that non-UTF-8 bytes
in the prefix and --additional-suffix are preserved as-is in output
filenames, rather than being replaced by UTF-8 replacement characters.
* tests/local.mk: Register new test.
https://github.com/uutils/coreutils/pull/11397
https://github.com/coreutils/coreutils/pull/239

4 days agotests: ln: add test for non-UTF-8 source names in target-dir mode
Sylvestre Ledru [Fri, 3 Apr 2026 16:09:43 +0000 (18:09 +0200)] 
tests: ln: add test for non-UTF-8 source names in target-dir mode

* tests/ln/non-utf8-src.sh: New test ensuring ln handles source
filenames containing non-UTF-8 bytes when linking into a target
directory, for both hard links and symbolic links with -t.
* tests/local.mk: Register the new test.
https://github.com/uutils/coreutils/pull/11403
https://github.com/coreutils/coreutils/pull/240

4 days agotest: od: verify -t f defaults to double precision
Sylvestre Ledru [Mon, 6 Apr 2026 16:10:42 +0000 (17:10 +0100)] 
test: od: verify -t f defaults to double precision

* tests/od/od-float.sh: Add cases to ensure -t f = -t fD,
and also verify the resulting number.
https://github.com/uutils/coreutils/pull/11396
https://github.com/coreutils/coreutils/pull/241

4 days agotests: ls: add quoting-utf8 test for Unicode quotes in UTF-8 locales
Sylvestre Ledru [Mon, 6 Apr 2026 13:49:29 +0000 (15:49 +0200)] 
tests: ls: add quoting-utf8 test for Unicode quotes in UTF-8 locales

* tests/ls/quoting-utf8.sh: New test verifying that
--quoting-style=locale and --quoting-style=clocale use Unicode
left/right single quotation marks in UTF-8 locales, and that
embedded apostrophes and double quotes are not escaped when the
delimiters are different characters.
Also check C locale fallback to ASCII quotes.
* tests/local.mk: Reference the new test.
https://github.com/coreutils/coreutils/pull/243

4 days agotests: numfmt: cover GNU/uutils compatibility edge cases
Sylvestre Ledru [Sun, 5 Apr 2026 22:14:25 +0000 (00:14 +0200)] 
tests: numfmt: cover GNU/uutils compatibility edge cases

* tests/numfmt/numfmt.pl: Add tests exercising corner cases around
negative-argument rejection, large integer precision, scientific
notation rejection, '--from-unit' fractional precision, zero-padded
format sign ordering, '--to-unit' prefix selection, and
'--format=%.0f' with '--to=<scale>'.
https://github.com/uutils/coreutils/pull/11668

4 days agodoc: document cut(1) multi-byte and interface consolidation
Pádraig Brady [Thu, 12 Mar 2026 17:49:27 +0000 (17:49 +0000)] 
doc: document cut(1) multi-byte and interface consolidation

This patch set updates cut(1) to be multi-byte aware.
It also reduces interface divergence across implementations.

multi-byte awareness was added to the existing -c, n, and -d options.
Also considered for compatibility are the -w, -F, and -O options,
as these are present on at least two other common implementations.

= Interface / New functionality =

    macOS,  i18n, uutils, Toybox, Busybox, GNU
-c    x      x       x      x        x      x
-n    x      x                              x
-w    x              x                      x
-F                          x        x      x
-O                          x        x      x

-c is needed anyway as specified by all, including POSIX.
-n is needed also as specified by i18n/macOS/POSIX
-w is somewhat less important, but seeing as it's
on two other common platforms (and its functionality is
provided on two more), providing it is worthwhile for compat.
-F and -O are really just aliases to other options
so trivial to add, and probably worthwhile for compatibility.

Interface / functionality notes:

There is a slight divergence between -n implementations.
There was already a difference between FreeBSD and i18n, and
we've aligned with the more sensible FreeBSD implementation.
Note the i18n -n implementation is otherwise buggy in any case,
so I doubt this will be a practical compatibility concern.
Actually -n is specified by POSIX, and it matches FreeBSD.
Specifically our -n will not output a character unless the
byte range encompasses _the end_ of the multi-byte character.
I.e. the -b is a limit that is not passed, and thus ensures
we don't output overlapping characters for separate cut
invocations that do not have overlapping byte ranges.

-d <regex> from toybox is not implemented.
That's edge case functionality IMHO and not well suited to cut(1).
This functionality is supported by awk, and regex functionality
is best restricted to awk I think.

cut is a significant part of the i18n patch, so it will be good
to avoid that downstream divergence.  Unfortunately there were
no tests with the cut i18n implementation.
Note the i18n cut implementation used fread() as so was
not reponsive to new data < BUFSIZ, whereas this implementation
uses read() and thus is responsive to data as it becomes available.

= Performance =

General performance notes:

We prefer byte searching (with -d) as that can be much faster
than character by character processing, and it's supported
on single byte and UTF-8 charsets.  We also use byte searching
with -w on uni-byte locales.
This was seen to give up to 100x perf increase over the i18n patch.

Where we do use per character processing, we avoid conversion to
wide char when processing ASCII data (mcel provides this optimization).
This was seen to give a 14x performance increase over the i18n patch.

We prefer memchr() and strstr() as these are tuned for specific
platforms on glibc, even if memchr2() or memmem()
are algorithmically better.

We maintain the important memory behavior
of only buffering when necessary.

Performance testing:

There are _lots_ of combinations and optimziation opportunities.
I performance tested this patch set with the following setup:

$ yes | head -n10M > sl.in
$ yes $(yes eeeaae | head -n10K | paste -s -d,) | head -n10K > ll.in
$ yes $(yes eeeaae | head -n9 | paste -s -d,) | head -n1M > as.in
$ yes $(yes éééááé | head -n9 | paste -s -d,) | head -n1M \
  > mb.in

$ for type in sl ll as mb; do
    cat $type.in >/dev/null;
    for imp in '' src/; do  # '' maps to the system i18n ver on Fedora
      echo ============ "${imp:-i18n}" $type ==============;
      for d in -d, -dc -d, -dç -w -b -c; do
        fields='-f1 -f10 -f100'
        test "$d" = "-b" && { fields='-b1 -b10 -b100'; d=''; }
        test "$d" = "-c" && { fields='-c1 -c10 -c100'; d=''; }
        for f in $fields; do
          for loc in C C.UTF-8; do
            # SKip -b for UTF-8 as no different
            test "$loc" = C.UTF-8 && echo "$f" | grep -q -- -b \
             && continue
            # Skip multi-byte delimiter for C and not allowed
            test "$loc" = C && test $(echo -n "$d" | wc -c) -ge 4 \
             && continue
            LC_ALL=$loc ${imp}cut $f $d /dev/null 2>/dev/null &&
            hyperfine -m2 -M4 \
             "LC_ALL=$loc ${imp}cut $f $d $type.in >/dev/null" ||
            printf 'Benchmark 1: %s\n  unsupported\n\n' \
             "LC_ALL=$loc ${imp}cut $f $d $type.in >/dev/null"
          done;
        done;
      done;
    done;
  done

After a little post-processing of the results, we get:

-- cut-i18n

| command         |       sl |       ll |       as |       mb |
| --------------- | -------- | -------- | -------- | -------- |
| C -f1 -d,       |  66.3 ms |  1.605 s | 145.9 ms | 366.4 ms |
| UTF8 -f1 -d,    |  65.8 ms |  1.593 s | 145.8 ms | 370.0 ms |
| C -f10 -d,      | 301.4 ms |  1.590 s | 161.8 ms | 126.7 ms |
| UTF8 -f10 -d,   | 303.5 ms |  1.599 s | 161.8 ms | 124.6 ms |
| C -f100 -d,     | 300.6 ms |  1.596 s | 162.1 ms | 126.7 ms |
| UTF8 -f100 -d,  | 301.3 ms |  1.595 s | 162.0 ms | 124.9 ms |
| C -f1 -dc       |  66.6 ms |  1.845 s | 179.1 ms | 365.7 ms |
| UTF8 -f1 -dc    |  73.8 ms |  1.878 s | 179.1 ms | 363.1 ms |
| C -f10 -dc      | 300.7 ms | 349.8 ms |  76.0 ms | 125.3 ms |
| UTF8 -f10 -dc   | 300.4 ms | 347.2 ms |  75.7 ms | 124.8 ms |
| C -f100 -dc     | 300.1 ms | 348.1 ms |  76.5 ms | 125.5 ms |
| UTF8 -f100 -dc  | 300.8 ms | 348.7 ms |  76.4 ms | 125.8 ms |
| UTF8 -f1 -d,   | 563.5 ms | 21.775 s |  1.963 s |  1.665 s |
| UTF8 -f10 -d,  | 833.6 ms | 20.504 s |  2.022 s |  1.612 s |
| UTF8 -f100 -d, | 825.2 ms | 20.448 s |  2.009 s |  1.616 s |
| UTF8 -f1 -dç    | 563.7 ms | 21.827 s |  1.964 s |  2.319 s |
| UTF8 -f10 -dç   | 825.3 ms | 21.713 s |  2.011 s |  2.248 s |
| UTF8 -f100 -dç  | 831.6 ms | 20.505 s |  2.019 s |  2.276 s |
| C -f1 -w        |        - |        - |        - |        - |
| UTF8 -f1 -w     |        - |        - |        - |        - |
| C -f10 -w       |        - |        - |        - |        - |
| UTF8 -f10 -w    |        - |        - |        - |        - |
| C -f100 -w      |        - |        - |        - |        - |
| UTF8 -f100 -w   |        - |        - |        - |        - |
| C -b1           |  60.8 ms |  1.596 s | 154.8 ms | 313.7 ms |
| C -b10          |  51.6 ms |  1.594 s | 154.3 ms | 310.8 ms |
| C -b100         |  51.4 ms |  1.594 s | 153.0 ms | 312.2 ms |
| C -c1           |  60.7 ms |  1.597 s | 153.8 ms | 313.0 ms |
| UTF8 -c1        | 526.5 ms | 14.662 s |  1.362 s |  1.573 s |
| C -c10          |  51.8 ms |  1.591 s | 153.3 ms | 311.4 ms |
| UTF8 -c10       | 436.9 ms | 14.450 s |  1.336 s |  1.563 s |
| C -c100         |  51.0 ms |  1.593 s | 152.7 ms | 313.2 ms |
| UTF8 -c100      | 426.7 ms | 14.429 s |  1.344 s |  1.551 s |

-- src/cut

| command         |       sl |       ll |       as |       mb |
| --------------- | -------- | -------- | -------- | -------- |
| C -f1 -d,       |   4.6 ms | 108.2 ms |  45.4 ms |  24.2 ms |
| UTF8 -f1 -d,    |   4.8 ms | 108.4 ms |  45.4 ms |  24.5 ms |
| C -f10 -d,      |   4.5 ms | 109.3 ms | 123.7 ms |  24.3 ms |
| UTF8 -f10 -d,   |   4.9 ms | 114.1 ms | 124.1 ms |  24.5 ms |
| C -f100 -d,     |   4.7 ms | 119.2 ms | 124.1 ms |  24.5 ms |
| UTF8 -f100 -d,  |   4.8 ms | 120.0 ms | 125.1 ms |  24.5 ms |
| C -f1 -dc       |   4.4 ms | 120.5 ms |  11.9 ms |  24.1 ms |
| UTF8 -f1 -dc    |   4.9 ms | 120.5 ms |  12.1 ms |  24.6 ms |
| C -f10 -dc      |   4.7 ms | 125.3 ms |  11.8 ms |  24.1 ms |
| UTF8 -f10 -dc   |   4.8 ms | 126.7 ms |  12.0 ms |  24.4 ms |
| C -f100 -dc     |   4.6 ms | 127.0 ms |  11.9 ms |  24.3 ms |
| UTF8 -f100 -dc  |   4.7 ms | 126.4 ms |  12.0 ms |  24.4 ms |
| UTF8 -f1 -d,   |   6.0 ms | 169.4 ms |  15.6 ms |  67.4 ms |
| UTF8 -f10 -d,  |   6.1 ms | 173.9 ms |  15.6 ms | 237.2 ms |
| UTF8 -f100 -d, |   6.1 ms | 174.0 ms |  15.6 ms | 237.8 ms |
| UTF8 -f1 -dç    |   6.3 ms | 170.8 ms |  15.7 ms |  32.2 ms |
| UTF8 -f10 -dç   |   6.0 ms | 172.9 ms |  15.9 ms |  32.1 ms |
| UTF8 -f100 -dç  |   6.7 ms | 173.1 ms |  15.5 ms |  32.3 ms |
| C -f1 -w        | 159.6 ms | 170.1 ms |  69.1 ms |  98.9 ms |
| UTF8 -f1 -w     | 128.1 ms |  2.525 s | 246.5 ms |  1.086 s |
| C -f10 -w       | 183.3 ms | 199.2 ms |  74.6 ms | 105.0 ms |
| UTF8 -f10 -w    | 130.3 ms |  2.659 s | 276.5 ms |  1.099 s |
| C -f100 -w      | 183.8 ms | 202.5 ms |  74.1 ms | 103.6 ms |
| UTF8 -f100 -w   | 130.1 ms |  2.663 s | 276.6 ms |  1.097 s |
| C -b1           |  65.0 ms | 110.2 ms |  22.4 ms |  35.6 ms |
| C -b10          |  48.7 ms | 109.6 ms |  24.2 ms |  36.7 ms |
| C -b100         |  48.7 ms | 110.6 ms |  19.0 ms |  36.6 ms |
| C -c1           |  65.8 ms | 109.5 ms |  22.4 ms |  35.6 ms |
| UTF8 -c1        |  63.2 ms |  1.130 s | 116.9 ms | 610.2 ms |
| C -c10          |  48.7 ms | 109.8 ms |  24.3 ms |  36.8 ms |
| UTF8 -c10       |  39.7 ms |  1.133 s | 118.7 ms | 610.0 ms |
| C -c100         |  48.3 ms | 110.7 ms |  18.9 ms |  36.7 ms |
| UTF8 -c100      |  39.4 ms |  1.141 s | 115.0 ms | 598.8 ms |

In summary, compared to the i18n patch we're now as fast in all cases,
and much faster in most cases.

We can see the -f byte searching performing well,
being 120x faster in the no matching delimiter case,
to at least 3x faster in the matching delimiter case.

When we resort to per character processing we also compare well,
being 14x faster in the ASCII processing case
(due to mcel short-circuiting the wide char conversion).
Note the processing mb.in results above also show a 2x win
in per character processing cases, but the i18n patch would have
also picked that win up as it's achieved separately to this patch set:
https://lists.gnu.org/r/coreutils/2026-03/msg00117.html

4 days agotests: cut: add remaining tests to ensure 100% coverage
Pádraig Brady [Mon, 6 Apr 2026 13:36:28 +0000 (14:36 +0100)] 
tests: cut: add remaining tests to ensure 100% coverage

* tests/cut/cut.pl: Add new tests to ensure
`make coverage` shows 100% coverage for cut.c.

4 days agotests: cut: expand GB18030 tests
Pádraig Brady [Mon, 6 Apr 2026 12:44:30 +0000 (13:44 +0100)] 
tests: cut: expand GB18030 tests

* tests/cut/mb-non-utf8.sh: Add more test cases.

4 days agomaint: cut: refactor delimiter handling
Paul Eggert [Fri, 3 Apr 2026 20:01:44 +0000 (21:01 +0100)] 
maint: cut: refactor delimiter handling

* src/cut.c: Use mcel_scanz() to parse in all cases,
and avoid redundant storage of delimiter_length and
the single byte delim.

4 days agocut: -f: fix handling of multi-byte delimiters that span buffers
Pádraig Brady [Thu, 2 Apr 2026 20:56:23 +0000 (21:56 +0100)] 
cut: -f: fix handling of multi-byte delimiters that span buffers

* src/cut.c (cut_fields_bytesearch): Ensure up to delim_bytes -1
is left for the next refill.
* tests/cut/cut.pl: Add a test case.

4 days agocut,fold,expand,unexpand: ensure we process all available characters
Pádraig Brady [Thu, 2 Apr 2026 19:19:07 +0000 (20:19 +0100)] 
cut,fold,expand,unexpand: ensure we process all available characters

* gl/lib/mbbuf.h: Adjust mbbuf_fill() to process full characters
in the slop at the end of a read().  Previously valid characters
in the last MCEL_LEN_MAX bytes were ignored until the next read().
* src/cut.c (cut_fields_bytesearch): Adjust to the new naming.
* NEWS: Mention the fold(1) responsiveness fix, which was
improved with the change from fread() to read(),
and completed with this patch.

5 days agocut: -b: avoid function calls in hot loop
Pádraig Brady [Thu, 2 Apr 2026 16:24:32 +0000 (17:24 +0100)] 
cut: -b: avoid function calls in hot loop

  $ time LC_ALL=C src/cut-before -b1 sl.in >/dev/null
  real 0m0.115s

  $ time LC_ALL=C src/cut-after -b1 sl.in >/dev/null
  real 0m0.076s

* src/cut.c (cut_bytes): Hoist the fileno() invariant outside the loop.
Avoid memchr for very short lines.
(search_bytes): Similar to copy_bytes() and write_bytes() helpers.
Note adding code to probe 3 or 4 bytes resulted in worse register
allocation.  I.e. slower operation even if the input was only 2 bytes.

5 days agocut: fix logic issue with field delim in last byte of buffer
Pádraig Brady [Wed, 1 Apr 2026 19:43:00 +0000 (20:43 +0100)] 
cut: fix logic issue with field delim in last byte of buffer

With field delimiter = line delimiter we need to know
if there is any more data to be read, as field delimiter
in the last byte of the file is treated differently.
So reiterate the loop to ensure enough read()s to make
the appropriate determination.

5 days agocut: ensure responsive input processing
Pádraig Brady [Wed, 1 Apr 2026 18:37:10 +0000 (19:37 +0100)] 
cut: ensure responsive input processing

* gl/lib/mbbuf.h (fill_buf): Switch from fread() to read()
as the former retries read() internally to fill the buffer.
* src/cut.c: Adjust accordingly, and avoid getc() interface entirely.
* bootstrap.h: Depend explicitly on fseterr.  This is already depended
on transitively, so should not introduce new build portability issues.

5 days agomaint: cut: rename line_in to bytes_in
Pádraig Brady [Tue, 31 Mar 2026 15:26:49 +0000 (16:26 +0100)] 
maint: cut: rename line_in to bytes_in

* src/cut.c: We're not reading a line, rather a buffer of bytes.
Suggested by Collin Funk.

5 days agotests: cut: add more multi-byte tests
Pádraig Brady [Sun, 29 Mar 2026 14:15:57 +0000 (15:15 +0100)] 
tests: cut: add more multi-byte tests

* tests/cut/cut.pl: Add more multi-byte combinations.

5 days agocut: make the dependency on memchr2 explicit
Pádraig Brady [Sun, 29 Mar 2026 11:11:53 +0000 (12:11 +0100)] 
cut: make the dependency on memchr2 explicit

* bootstrap.conf: Remove now unused getndelim2, add memchr2.
* src/cut.c: Remove now unused getndelim2.h.

5 days agocut: combine cut_bytes_no_split and cut_characters
Pádraig Brady [Sat, 28 Mar 2026 18:33:42 +0000 (18:33 +0000)] 
cut: combine cut_bytes_no_split and cut_characters

per character based so merge.

5 days agodoc: cut: clarify that combining characters are not treated specially
Pádraig Brady [Sat, 28 Mar 2026 16:18:41 +0000 (16:18 +0000)] 
doc: cut: clarify that combining characters are not treated specially

This is for consistency with other implementations and since the
interface separates -b and -c it might in future support -g (graphemes).
Normalizing content with a filter seems like the most appropriate
approach anyway, as there are various normalizations possible including
case etc. rather than baking that into every tool

5 days agomaint: cut: various code cleanups and comments
Pádraig Brady [Sat, 28 Mar 2026 14:14:24 +0000 (14:14 +0000)] 
maint: cut: various code cleanups and comments

* src/cut.c: Document some functions, and remove extraneous
 abstractions.

5 days agocut: support no delimiter match fast path with -s
Pádraig Brady [Sat, 28 Mar 2026 09:34:33 +0000 (09:34 +0000)] 
cut: support no delimiter match fast path with -s

* src/cut.c (cut_fields_bytesearch): Just skip the data with -s.

5 days agodoc: cut: resintate and expand -d info
Pádraig Brady [Sat, 28 Mar 2026 09:12:39 +0000 (09:12 +0000)] 
doc: cut: resintate and expand -d info

* doc/coreutils.texi (cut invocation): Add back the -d description,
and adjust for multi-byte support, and expand on specifying a NUL
delimitier, and detail the behavior when the delimiter matches
the line delimiter.

5 days agomaint: cut: cleanup context management for byte search
Pádraig Brady [Fri, 27 Mar 2026 22:09:19 +0000 (22:09 +0000)] 
maint: cut: cleanup context management for byte search

* src/cut.c: Hoist at_eof into context so we're not
querying it multiple times.  Also add a helper
to explicitly init bytesearch_context.

5 days agocut: optimize UTF-8 input with 0xF5-0xFF delimiters
Pádraig Brady [Fri, 27 Mar 2026 18:59:01 +0000 (18:59 +0000)] 
cut: optimize UTF-8 input with 0xF5-0xFF delimiters

* src/cut.c (bytesearch_field_delim_ok): Expand the range
of bytes that can be simply searched for. 0xF5-0xFF can't
appear in valid UTF-8 characters, and so may be used as
delimiters in UTF-8 input, so it's worth optimizing for.
* tests/cut/cut.pl: Add a test case (mainly as documentation).

5 days agodoc: cut: clarify that -s suppressed lines with only trimmed spaces
Pádraig Brady [Fri, 27 Mar 2026 18:29:16 +0000 (18:29 +0000)] 
doc: cut: clarify that -s suppressed lines with only trimmed spaces

* doc/coreutils.texi (cut invocation): State explicitly that
-s --whitespace-delimited=trimmed will suppress lines that
do not have field separating blanks.

5 days agodoc: cut: mention the default -O used with -w
Pádraig Brady [Fri, 27 Mar 2026 15:52:14 +0000 (15:52 +0000)] 
doc: cut: mention the default -O used with -w

* doc/coreutils.texi (cut invocation): Mention the default
--output-delimiter is a TAB when matching runs of blanks in the input.

5 days agomaint: cut: simplify mbbuf_fill
Pádraig Brady [Thu, 26 Mar 2026 16:52:56 +0000 (16:52 +0000)] 
maint: cut: simplify mbbuf_fill

We can only byte search with uni-byte or utf-8.
utf-8 implicitly can't false match a delimiter at buffer boundary.
So don't worry about finding the exact utf8 boundary at end of buffer,
rather just ensuring the buffer always starts with a valid character
(by ensuring MCEL_LEN_MAX-1 moved to start of buffer on each refill).

5 days agomaint: refactor is_utf8_charset helper to system.h
Pádraig Brady [Thu, 26 Mar 2026 15:09:15 +0000 (15:09 +0000)] 
maint: refactor is_utf8_charset helper to system.h

* src/cut.c: Move from here.
* src/numfmt.c: Likeise.
* src/system.h: To here.

5 days agocut: optimize per character memcpy
Pádraig Brady [Wed, 25 Mar 2026 19:11:35 +0000 (19:11 +0000)] 
cut: optimize per character memcpy

$ time src/cut-before -f10 -w ll.in >/dev/null
real 0m4.309s

$ time src/cut-after -f10 -w ll.in >/dev/null
real 0m3.136s

* src/cut.c (cut_bytes): Add a new helper that avoids
the memcpy call in the common case of adding characters to a buffer.

5 days agocut: refactor skip_line_remainder logic
Pádraig Brady [Wed, 25 Mar 2026 12:01:32 +0000 (12:01 +0000)] 
cut: refactor skip_line_remainder logic

Simplify and optimize field exhaustion logic:

$ time LC_ALL=C src/cut-before -f1 -dc as.in >/dev/null
real 0m0.057s

$ time LC_ALL=C src/cut-after -f1 -dc as.in >/dev/null
real 0m0.023s

* src/cut.c (cut_fields_bytesearch): Refactor.

5 days agomaint: cut simplify cut_fields_bytesearch
Pádraig Brady [Tue, 24 Mar 2026 19:25:28 +0000 (19:25 +0000)] 
maint: cut simplify cut_fields_bytesearch

refactor line delimiter output,
and resetting of parse record state.

5 days agocut: enable fast path for all delimiter lengths
Pádraig Brady [Tue, 24 Mar 2026 18:53:03 +0000 (18:53 +0000)] 
cut: enable fast path for all delimiter lengths

1. Removed !have_pending_line from the fast path condition.
This is safe because:
  - field_1_n_bytes == 0 already ensures we haven't started
    buffering field 1 content
  - The fast path correctly continues any pending partial line
    by writing raw bytes including the completing \n
2. Added have_pending_line = false after the fast path write,
since all lines up to the last \n are now complete.

$ time src/cut.before -f1 -dç sl.in >/dev/null
real 0m0.081s
$ time src/cut.after -f1 -dç sl.in >/dev/null
real 0m0.012s

$ time src/cut.before -f10 -dç sl.in >/dev/null
real 0m0.081s
$ time src/cut.after -f10 -dç sl.in >/dev/null
real 0m0.012s

5 days agocut: optimize -f with -d longer than lines
Pádraig Brady [Tue, 24 Mar 2026 16:35:00 +0000 (16:35 +0000)] 
cut: optimize -f with -d longer than lines

$ time src/cut.before -f1 -dç sl.in >/dev/null
real 0m0.157s

$ time src/cut.after -f1 -dç sl.in >/dev/null
real 0m0.084s

5 days agocut: optimize -b for short lines
Pádraig Brady [Tue, 24 Mar 2026 15:35:24 +0000 (15:35 +0000)] 
cut: optimize -b for short lines

For a 40% performance increase it's worth reinstating the simple
original cut_bytes() which avoids data copying and function calls.
Once a longer line is encountered we defer to the buffered variant.

$ time src/cut.before -b2 sl.in  >/dev/null
real 0m0.101s

$ time src/cut.after -b2 sl.in  >/dev/null
real 0m0.060s

5 days agocut: optimize per character field scanning
Pádraig Brady [Mon, 23 Mar 2026 20:59:48 +0000 (20:59 +0000)] 
cut: optimize per character field scanning

Use specialized loops rather than branching per character,
giving a 28% increase.

$ time src/cut -f1 -w ll.in >/dev/null
real 0m7.199s

$ time src/cut -f1 -w ll.in >/dev/null
real 0m5.204s

5 days agocut: prefer c_isblank() to c32issep()
Pádraig Brady [Mon, 23 Mar 2026 20:31:21 +0000 (20:31 +0000)] 
cut: prefer c_isblank() to c32issep()

12% perf increase with:

$ time src/cut -f2 -w ll.in >/dev/null
real 0m6.469s

$ time src/cut -f2 -w ll.in >/dev/null
real 0m5.689s

5 days agocut: avoid fwrite calls for smaller amounts of data
Pádraig Brady [Mon, 23 Mar 2026 17:42:27 +0000 (17:42 +0000)] 
cut: avoid fwrite calls for smaller amounts of data

This is quite significant:

yes abcdfeg | head -n1MB > big-file

$ time src/cut-before -b1,3 big-file >/dev/null
real 0m0.050s

$ time src/cut-after -b1,3 big-file >/dev/null
real 0m0.029s

5 days agocut: optimize -b by avoiding per byte iteration
Pádraig Brady [Sun, 22 Mar 2026 12:20:04 +0000 (12:20 +0000)] 
cut: optimize -b by avoiding per byte iteration

Always memchr(line_delim) which is fast and allows:

- skipping whole segments when the next selected byte is beyond them
- skipping unselected prefixes in bulk
- writing contiguous selected spans in bulk

This wins for lines >= 4 characters,
but is slower lines <= 3 characters, especially if selecting bytes 1-3.
That is unusual though.

5 days agocut: optimize when no delimiter in input
Pádraig Brady [Sat, 21 Mar 2026 14:15:48 +0000 (14:15 +0000)] 
cut: optimize when no delimiter in input

This is about 20x faster.
Note we only do the delimiter search once per chunk,
and it's usually quick as delimiters wouldn't be too far
into the a chunk if present, so we don't bother
to cache the found delimiter.

5 days agotests: cut: ensure multi-byte delimiter is rejected in uni-byte locales
Pádraig Brady [Fri, 20 Mar 2026 19:25:59 +0000 (19:25 +0000)] 
tests: cut: ensure multi-byte delimiter is rejected in uni-byte locales

tests/cut/cut.pl: Check the appropriate diagnostic is presented.

5 days agocut: optimize -w for uni-byte case
Pádraig Brady [Fri, 20 Mar 2026 17:43:20 +0000 (17:43 +0000)] 
cut: optimize -w for uni-byte case

* src/cut.c: Limit search to SPACE and TAB

5 days agodoc: cut: reorder -s in texi
Pádraig Brady [Fri, 20 Mar 2026 17:08:59 +0000 (17:08 +0000)] 
doc: cut: reorder -s in texi

Keep in alphabetical order.

5 days agodoc: cut: document the -w option
Pádraig Brady [Fri, 20 Mar 2026 17:07:18 +0000 (17:07 +0000)] 
doc: cut: document the -w option

* src/cut.c (usage): Mention blank characters are used to separate.
* doc/coreutils.texi (cut invocation): Likewise.  Also describe
the 'trimmed' argument and the relation to -F.

5 days agocut: refactor find_bytesearch_field_terminator to be stateful
Pádraig Brady [Fri, 20 Mar 2026 14:49:44 +0000 (14:49 +0000)] 
cut: refactor find_bytesearch_field_terminator to be stateful

Allows better/simpler avoidance of repeated line/delim scans

TODO: speed up our really slow cut_fields_mb_any.
Compare for example:
  time src/cut -w  -f1 ll.in >/dev/null #14s
  time src/cut -d, -f1 ll.in >/dev/null #.1s
Could adjust so that LC_ALL=C does memchr2(space,tab) ?

5 days agocut: avoid repeated searchs for line_delim in the multi-byte delim case
Pádraig Brady [Fri, 20 Mar 2026 14:21:27 +0000 (14:21 +0000)] 
cut: avoid repeated searchs for line_delim in the multi-byte delim case

TODO: Refactor all this into find_bytesearch_field_terminator.
Also handle in the delim_length==1 case.

5 days agocut: refactor all byte search to find_bytesearch_field_terminator
Pádraig Brady [Fri, 20 Mar 2026 13:52:37 +0000 (13:52 +0000)] 
cut: refactor all byte search to find_bytesearch_field_terminator

TODO: Perhaps also add search only fields mode
to avoid rescans of very long lines

5 days agocut: optimize -f when finished processing fields for a line
Pádraig Brady [Fri, 20 Mar 2026 13:42:43 +0000 (13:42 +0000)] 
cut: optimize -f when finished processing fields for a line

TODO: simplify and compare perf

5 days agocut: optimize -f for fhe common case of single byte delimiters
Pádraig Brady [Fri, 20 Mar 2026 13:41:37 +0000 (13:41 +0000)] 
cut: optimize -f for fhe common case of single byte delimiters

* TODO: perf comparison

5 days agocut: optimize -d '?' in UTF-8 case
Pádraig Brady [Tue, 17 Mar 2026 14:17:06 +0000 (14:17 +0000)] 
cut: optimize -d '?' in UTF-8 case

ensure all ascii delims are processed with byte search in UTF-8

5 days agocut: merge cut_fields and cut_fields_bytesearch
Pádraig Brady [Tue, 17 Mar 2026 13:30:36 +0000 (13:30 +0000)] 
cut: merge cut_fields and cut_fields_bytesearch

TODO: See why this is much slower:
time LC_ALL=C.UTF-8 src/cut -f1 -dc as.in > /dev/null

5 days agocut: refactor -f to byte search and character processing
Pádraig Brady [Mon, 16 Mar 2026 22:23:02 +0000 (22:23 +0000)] 
cut: refactor -f to byte search and character processing

Not sure about this at all.
Only worthwhile if can also remove cut_fields_line_delim.

Refactored src/cut.c so the old UTF-8 byte-search path is now the
general byte-search field engine for all safe byte-search cases:
ordinary single-byte delimiters and valid UTF-8 delimiters. The old
cut_fields path did not go away completely; it is now
cut_fields_line_delim and is used only when the field delimiter equals
the record delimiter, because -d $'\n' and -z -d '' have different
semantics from normal line-based field splitting.

As part of that, I also folded the duplicated “start selected field”
logic into a shared helper, and renamed the byte-search helpers to match
their broader use. The current dispatcher in src/cut.c is now:
whitespace parser, then line- delimiter field mode, then byte-search
field mode, then the decoded multibyte parser.

5 days agocut: fix 25% perf regression mentioned in previous change
Pádraig Brady [Mon, 16 Mar 2026 20:47:23 +0000 (20:47 +0000)] 
cut: fix 25% perf regression mentioned in previous change

* src/cut.c: Prefer strstr() over memmem() as the former is
optimized per platforma on GLIBC, where as the latter is only
optimized for S390 as of glibc-2.42

TODO: look at merging cut_fields and cut_fields_mb_utf8
as they're both byte search

5 days agocut: use bounded memory in utf8 mode when possible
Pádraig Brady [Mon, 16 Mar 2026 14:11:08 +0000 (14:11 +0000)] 
cut: use bounded memory in utf8 mode when possible

TODO: See why a bit slower than old code

$ time src/cut.old -f1 -dç mb.in >/dev/null
real 0m0.136s
user 0m0.096s
sys 0m0.039s

$ time src/cut.new -f1 -dç mb.in >/dev/null
real 0m0.170s
user 0m0.139s
sys 0m0.030s

5 days agocut: add utf8 helper to mbbuf
Pádraig Brady [Mon, 16 Mar 2026 12:45:59 +0000 (12:45 +0000)] 
cut: add utf8 helper to mbbuf

* gl/lib/mbbuf.h: To safely search a bounded buffer,
without needed to have unbounded memory with getndelim2.

TODO: rename mbbuf_utf8_safe_prefix to mbbuf_fill_utf8

5 days agocut: faster utf8 processing
Pádraig Brady [Mon, 16 Mar 2026 11:11:59 +0000 (11:11 +0000)] 
cut: faster utf8 processing

TODO: improve to use bounded memory where possible

5 days agocut: support -F as an alias for -f -w -O ' '
Pádraig Brady [Fri, 13 Mar 2026 19:48:05 +0000 (19:48 +0000)] 
cut: support -F as an alias for -f -w -O ' '

To improve compatibility with toybox/busybox scripts.

5 days agomaint: cut: refactor buffered and ordinary field scanning
Pádraig Brady [Fri, 13 Mar 2026 15:08:34 +0000 (15:08 +0000)] 
maint: cut: refactor buffered and ordinary field scanning

* src/cut.c: Merge scan_mb_field and read_mb_field_to_buffer

5 days agocut: support --whitespace-delimited=trimmed
Pádraig Brady [Fri, 13 Mar 2026 14:57:42 +0000 (14:57 +0000)] 
cut: support --whitespace-delimited=trimmed

Support ignoring leading and trailing whitespace.
E.g. this matches awk's default field splitting mode.

* src/cut.c
* tests/cut/cut.pl: Add test cases.

5 days agocut: support -O as an alias for --output-delimiter
Pádraig Brady [Fri, 13 Mar 2026 11:05:40 +0000 (11:05 +0000)] 
cut: support -O as an alias for --output-delimiter

To improve compatibility with toybox/busybox scripts.

* doc/coreutils.texi (cut invocation): Add -O description.
* src/cut.c: Support -O as well as --output-delimiter
* tests/cut/cut.pl: Adjust one case to use -O.

5 days agodoc: cut: adjust for multi-byte support
Pádraig Brady [Wed, 11 Mar 2026 22:15:38 +0000 (22:15 +0000)] 
doc: cut: adjust for multi-byte support

* doc/coreutils.texi (cut invocation): Remove the note about
-c being the same as -b.

5 days agocut: refactor multi-byte updates
Pádraig Brady [Thu, 12 Mar 2026 18:58:46 +0000 (18:58 +0000)] 
cut: refactor multi-byte updates

* src/cut.c: 160 fewer lines

Helpers extracted (replacing repeated inline patterns):
- write_line_delim(), write_pending_line_delim(), reset_item_line()
  - line boundary code used by cut_bytes{,no_split}, cut_characters
- write_selected_item()
  - output-delimiter + write logic used by all three byte/char functions
- reset_field_line()
  - field line reset used by cut_fields_mb_any

Field functions unified via cut_fields_mb_any(stream, whitespace_mode):
- struct mbfield_parser encapsulates the whitespace vs.
  fixed-delimiter state (saved char, mode flag)
- mbfield_get_char() - dispatches to saved-char or direct read
- mbfield_terminator()
  - returns FIELD_{DATA,DELIMETER,LINE_DELIMITER} based on mode
- read_mb_field_to_buffer()
  - replaces the two duplicated first-field buffering loops
- scan_mb_field(mbbuf, parser, pending, write_field)
  - replaces the four duplicated field scan loops
  (print+skip × two modes) with a single function and a write_field bool
- cut_fields_mb and cut_fields_ws are now trivial wrappers

5 days agocut: implement -n to avoid outputting partial characters
Pádraig Brady [Thu, 12 Mar 2026 17:27:00 +0000 (17:27 +0000)] 
cut: implement -n to avoid outputting partial characters

Both the i18n patch and FreeBSD/macOS support this option.
They do differ in behavior somewhat as the i18n patch
may output more bytes than requested.

  $ printf '\xc3\xa9b\n' | i18n-cut -n -b1
  é

There is also a bug in the i18n patch with multi-byte
at the start of a line:

  $ printf '\xc3\xa9b\n' | i18n-cut -n -b1-2
  éb

We follow the FreeBSD behavior since it seems more
useful to have -b be a hard limit, rather than a soft limit.
This also reduces the possibility of duplicate character output
with separate cut invocations with non overlapping byte ranges.

* src/cut.c (cut_bytes_no_split): A new function
similar to cut_characters, to handle multi-byte characters
with byte limit semantics.
* tests/cut/cut.pl: Add test cases.

5 days agotests: cut: add a test for divergence from i18n patch
Pádraig Brady [Thu, 12 Mar 2026 16:09:39 +0000 (16:09 +0000)] 
tests: cut: add a test for divergence from i18n patch

* tests/cut/cut.pl: We don't fall back to byte mode
upon invalid uni-byte delimiter.

5 days agotests: cut: add case currently failing for coreutils-i18n patch
Pádraig Brady [Thu, 12 Mar 2026 15:50:04 +0000 (15:50 +0000)] 
tests: cut: add case currently failing for coreutils-i18n patch

* tests/cut/cut.pl: Test for extraneous character output with:
printf 'aéb\n' | cut -s -d 'é' -f1 | od -tx1

5 days agotests: cut: check multi-byte output delimiter
Pádraig Brady [Thu, 12 Mar 2026 15:04:29 +0000 (15:04 +0000)] 
tests: cut: check multi-byte output delimiter

* tests/cut/cut.pl: Add a test case.

5 days agocut: adjust error message to be less specific
Pádraig Brady [Thu, 12 Mar 2026 18:36:27 +0000 (18:36 +0000)] 
cut: adjust error message to be less specific

* src/cut.c (main): Cater for both misplaced -w and -d.

5 days agocut: implement -w,--whitespace-delimited
Pádraig Brady [Wed, 11 Mar 2026 22:42:45 +0000 (22:42 +0000)] 
cut: implement -w,--whitespace-delimited

* src/cut.c (cut_fields_ws): A new function handling both
uni-byte and multi-byte cases.
* tests/cut/cut.pl: Add a test cases.

5 days agocut: support single byte -d with GB18030 input
Pádraig Brady [Wed, 11 Mar 2026 22:06:43 +0000 (22:06 +0000)] 
cut: support single byte -d with GB18030 input

* src/cut.c
* tests/cut/mb-non-utf8.sh
* tests/local.mk

5 days agocut: support single byte -d that may be part of multi-byte
Pádraig Brady [Wed, 11 Mar 2026 21:23:24 +0000 (21:23 +0000)] 
cut: support single byte -d that may be part of multi-byte

Note this is a slight divergence from the i18n patch
as that switched to uni-byte for any single byte delimiter
that is not valid multi-byte.

That results in possibly splitting in the middle of
a valid multi-byte character.

Instead we only split on a single byte when they're
not part of a multi-byte character.

* src/cut.c

5 days agocut: support multi-byte field delimiters
Pádraig Brady [Wed, 11 Mar 2026 21:12:04 +0000 (21:12 +0000)] 
cut: support multi-byte field delimiters

* src/cut.c
* tests/cut/cut.pl

5 days agocut: support multi-byte input with -c
Pádraig Brady [Wed, 11 Mar 2026 20:50:23 +0000 (20:50 +0000)] 
cut: support multi-byte input with -c

* src/cut.c
* tests/cut/cut.pl

5 days agomaint: cut: refactor output calls
Pádraig Brady [Fri, 13 Mar 2026 15:43:21 +0000 (15:43 +0000)] 
maint: cut: refactor output calls

* src/cut.c (cut_fields): Refactor calls to fwrite() and putchar()

5 days agotests: cut: ensure no unecessary buffering
Pádraig Brady [Sat, 21 Mar 2026 18:53:24 +0000 (18:53 +0000)] 
tests: cut: ensure no unecessary buffering

* tests/misc/write-errors.sh: Ensure we write output when possible.

5 days agodoc: cut: reorder --complement alphabetically in help
Pádraig Brady [Fri, 13 Mar 2026 11:58:24 +0000 (11:58 +0000)] 
doc: cut: reorder --complement alphabetically in help

* src/cut.c (usage): Move placement of --comlement description.
* doc/coreutils.texi (cut invocation): Likewise.