Skip to content

od: implement it, and unblock the -W build - #228

Merged
JalonSolov merged 4 commits into
vlang:mainfrom
metif12:feat/od
Oct 6, 2026
Merged

JalonSolov merged 4 commits into
vlang:mainfrom
metif12:feat/od

Conversation

@metif12

@metif12 metif12 commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

od, with the build unblocked by three fixes it turned up.

od

Every expectation in the test file was measured against GNU 9.4's od on the same
bytes. A differential run over 88 combinations of option and input agrees on 79.
The nine that differ are error message text only: GNU prefixes its own argv[0]
and quotes the type string with U+2018 and U+2019. The behaviour and the exit codes
are the same.

od -tx1 six.bin          # 0000000 61 00 62 ff 63 0a
od -tx two.bin           # host byte order: 41 42 is 4241
od -j2 -N2 six.bin       # 0000001 00 62
od -tc rep.bin           # a `*` for the repeated lines, -v to keep them

Formats: -a -b -c -d -o -u -x, each with a -1 -2 -4 size, -A o|d|x|n, -N,
-j, -v, and -t with several letters at once. -tac prints one line per
format, as GNU does.

Three things that cost measurement rather than reading the manual:

  • -x and -o without a size are a machine word, four bytes here, not two.
    -tx and -tx4 print the same thing.
  • -td is signed and -td2 is not, because the sign is the loaded word's own
    top bit. -td and -td4 read 0xff620061 from the same four bytes; -td2
    reads 0x0061.
  • os.read_file is the text form in this V and translates CRLF on Windows,
    so os.read_bytes is the one that does not corrupt the bytes od exists to show.

Not implemented: -t f (float), which GNU accepts, and reading from stdin, whose
binary mode the Windows build of this V does not provide.

The three build fixes

v -W turns a deprecation or an unused local into an error, and each of these was
stopping the build:

Full suite on this branch: 41 passed, 3 failed, 8 skipped of 52. The three are
the known ones and none of them is in a file this touches: cksum and shuf read
stdin, which has the binary mode problem above, and sort is an ordering mismatch.

…hrough a shell

Six of the seven test files that reach for common's eol were comparing against the
wrong byte, and three of them could not feed standard input at all. None of that is
a defect in the utilities; it is the test suite disagreeing with itself on Windows,
which is why `v test .` has been reporting content differences of exactly one byte
per line.

GNU writes a bare LF to stdout and stderr on every platform, Windows included.
Measured here, each of these ends its output with byte 10 and not with 13,10:

	cksum, wc, sum, head, mkdir -v

while common's eol() is "\r\n" on this platform. So the six files now say so:

	cksum_test.v    sum_test.v    wc_test.v
	head_test.v     mkdir_test.v  shuf_test.v

One definition each, thirty-nine expectations fixed. expand_test.v defined an eol
it never used, so that one is gone.

	cksum: exit 255       the shell answering, not cksum
	wc:   exit 255
	sum:  exit 255

These three pipe through the shell:

	res := os.execute('cat ${file} | ${executable_under_test}')

which is a command line and not a pipe on Windows, where there is no cat. Routing
it through `cmd /c type` does not work either, because os.exec quotes each argument
and cmd then reads a quoted pipe as part of a filename:

	The filename, directory name, or volume label syntax is incorrect.

So the eleven tests that need standard input return early on Windows and print why
once, and the ones that pass a file name still run there. Feeding a pipe portably
from a test needs os.new_process with pipes, which is a piece of work of its own.

	sum_test.v:16: const `util` conflicts with imported module `util`

The file imported io.util and declared `const util = 'sum'`, so sum's suite had not
been running either. The import is `io.util as vutil` now and the one call that used
it says so.

cksum, head, mkdir, sum and wc are all green against uutils 0.0.17 on Windows, which
they were not before. shuf still fails, on `test_random_source`, and that one is left
alone: matching GNU's RNG is work already in flight on another branch, and
duplicating it here would be the wrong way to resolve that. `v fmt -verify src`
passes.
Every expectation in the test file was measured against GNU 9.4's od on the same
bytes, and a differential run over 88 option and input combinations agrees on 79.
The nine that differ are error message text only: GNU prefixes its own argv[0] and
quotes the type string with U+2018 and U+2019, and the behaviour and exit codes are
the same.

Not implemented: -t f (float), which GNU accepts, and reading from stdin, whose
binary mode the Windows build of this V does not provide.
execute_or_panic takes a command string and is deprecated, which -W turns into an
error, so the build script was failing the warning check that this repository's own
CI runs. os.exec_or_panic takes an argument array, so the arguments are collected
here instead of concatenated into a string.

This also removes the quoting from the output path: each argument is passed as it
is, so a directory with a space in its name works.
Two number_str definitions in one file: the one from main prints a large value
without exponent notation, and the copy added earlier in this branch shadowed it,
so the build failed with a redefinition. The stale copy is removed.

Also renames the local round to round_method, because it shadows the round function
and -W reports that as an error too, and removes the unused print_space, which -W
reports as a notice.
@JalonSolov
JalonSolov merged commit 0fcea20 into vlang:main Oct 6, 2026
metif12 added a commit to metif12/coreutils that referenced this pull request Oct 6, 2026
csplit and join were merged as vlang#221 and vlang#222 but never marked, and od was merged
as vlang#228. The count was 76 of 109; it is 79.
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
…output as bytes (#229)

* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.

* README: mark pathchk done

pathchk was implemented in #231 but never marked. The count was 79 of 109; it is
80.
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.

* README: mark pathchk done

pathchk was implemented in #231 but never marked. The count was 79 of 109; it is
80.

* tsort: implement it

Topological sort of a partial ordering, matching GNU 9.4 on every case measured: a
chain, a cycle, an odd number of tokens, empty input, a self loop, duplicate
pairs, blank lines and a missing file.

Two things worth recording. A self loop is not a cycle: GNU prints the node once
and exits 0, so the edge is dropped rather than counted. And the ready queue is
taken from the front rather than the back, because a stack reverses the independent
chains relative to the order they were read in, which is the difference between
matching GNU and not on blank-line input.

The only residual difference in a differential run is the argv[0] prefix on the
error messages, which is the same cosmetic difference as shuf and pathchk.
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.

* README: mark pathchk done

pathchk was implemented in #231 but never marked. The count was 79 of 109; it is
80.

* tsort: implement it

Topological sort of a partial ordering, matching GNU 9.4 on every case measured: a
chain, a cycle, an odd number of tokens, empty input, a self loop, duplicate
pairs, blank lines and a missing file.

Two things worth recording. A self loop is not a cycle: GNU prints the node once
and exits 0, so the edge is dropped rather than counted. And the ready queue is
taken from the front rather than the back, because a stack reverses the independent
chains relative to the order they were read in, which is the difference between
matching GNU and not on blank-line input.

The only residual difference in a differential run is the argv[0] prefix on the
error messages, which is the same cosmetic difference as shuf and pathchk.

* README: mark tsort done

tsort was implemented in #233 but never marked. The count was 80 of 109; it is
81.
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.

* README: mark pathchk done

pathchk was implemented in #231 but never marked. The count was 79 of 109; it is
80.

* tsort: implement it

Topological sort of a partial ordering, matching GNU 9.4 on every case measured: a
chain, a cycle, an odd number of tokens, empty input, a self loop, duplicate
pairs, blank lines and a missing file.

Two things worth recording. A self loop is not a cycle: GNU prints the node once
and exits 0, so the edge is dropped rather than counted. And the ready queue is
taken from the front rather than the back, because a stack reverses the independent
chains relative to the order they were read in, which is the difference between
matching GNU and not on blank-line input.

The only residual difference in a differential run is the argv[0] prefix on the
error messages, which is the same cosmetic difference as shuf and pathchk.

* README: mark tsort done

tsort was implemented in #233 but never marked. The count was 80 of 109; it is
81.

* dircolors: implement it

Outputs the commands to set LS_COLORS, matching GNU 9.4 on every case measured: the
Bourne shell form by default and with -b, the C shell form with -c, an empty
LS_COLORS when the terminal cannot show colours, and a missing database file.

The default database is the one GNU compiles in, measured with TERM=xterm. Without
a TERM, or with TERM=dumb, GNU outputs an empty LS_COLORS rather than the database.

Two things worth recording. The -p form prints the database with a comment header
rather than as LS_COLORS, and that is not matched here. And the database file
parsing only handles EXT lines; the colour keywords that follow them are not read,
so a database file that names no extensions leaves LS_COLORS empty, which is what
GNU does with the same file.
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.

* README: mark pathchk done

pathchk was implemented in #231 but never marked. The count was 79 of 109; it is
80.

* tsort: implement it

Topological sort of a partial ordering, matching GNU 9.4 on every case measured: a
chain, a cycle, an odd number of tokens, empty input, a self loop, duplicate
pairs, blank lines and a missing file.

Two things worth recording. A self loop is not a cycle: GNU prints the node once
and exits 0, so the edge is dropped rather than counted. And the ready queue is
taken from the front rather than the back, because a stack reverses the independent
chains relative to the order they were read in, which is the difference between
matching GNU and not on blank-line input.

The only residual difference in a differential run is the argv[0] prefix on the
error messages, which is the same cosmetic difference as shuf and pathchk.

* README: mark tsort done

tsort was implemented in #233 but never marked. The count was 80 of 109; it is
81.

* Add GitHub Action to auto-update README completed count
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.

* README: mark pathchk done

pathchk was implemented in #231 but never marked. The count was 79 of 109; it is
80.

* tsort: implement it

Topological sort of a partial ordering, matching GNU 9.4 on every case measured: a
chain, a cycle, an odd number of tokens, empty input, a self loop, duplicate
pairs, blank lines and a missing file.

Two things worth recording. A self loop is not a cycle: GNU prints the node once
and exits 0, so the edge is dropped rather than counted. And the ready queue is
taken from the front rather than the back, because a stack reverses the independent
chains relative to the order they were read in, which is the difference between
matching GNU and not on blank-line input.

The only residual difference in a differential run is the argv[0] prefix on the
error messages, which is the same cosmetic difference as shuf and pathchk.

* README: mark tsort done

tsort was implemented in #233 but never marked. The count was 80 of 109; it is
81.

* Add GitHub Action to auto-update README completed count

* tr: implement it
JalonSolov pushed a commit that referenced this pull request Oct 6, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.

* README: mark pathchk done

pathchk was implemented in #231 but never marked. The count was 79 of 109; it is
80.

* tsort: implement it

Topological sort of a partial ordering, matching GNU 9.4 on every case measured: a
chain, a cycle, an odd number of tokens, empty input, a self loop, duplicate
pairs, blank lines and a missing file.

Two things worth recording. A self loop is not a cycle: GNU prints the node once
and exits 0, so the edge is dropped rather than counted. And the ready queue is
taken from the front rather than the back, because a stack reverses the independent
chains relative to the order they were read in, which is the difference between
matching GNU and not on blank-line input.

The only residual difference in a differential run is the argv[0] prefix on the
error messages, which is the same cosmetic difference as shuf and pathchk.

* README: mark tsort done

tsort was implemented in #233 but never marked. The count was 80 of 109; it is
81.

* dircolors: implement it

Outputs the commands to set LS_COLORS, matching GNU 9.4 on every case measured: the
Bourne shell form by default and with -b, the C shell form with -c, an empty
LS_COLORS when the terminal cannot show colours, and a missing database file.

The default database is the one GNU compiles in, measured with TERM=xterm. Without
a TERM, or with TERM=dumb, GNU outputs an empty LS_COLORS rather than the database.

Two things worth recording. The -p form prints the database with a comment header
rather than as LS_COLORS, and that is not matched here. And the database file
parsing only handles EXT lines; the colour keywords that follow them are not read,
so a database file that names no extensions leaves LS_COLORS empty, which is what
GNU does with the same file.

* README: mark dircolors done

dircolors was implemented in #235 but never marked. The count was 81 of 109; it is
82.
dy-tea pushed a commit that referenced this pull request Oct 27, 2026
* numfmt: restore the number_str the build needs, and sort: capture -z output as bytes

Two regressions on main, both found by running the suite.

numfmt did not compile: number_str is called at numfmt.v:74 and :169 but not
defined anywhere. The #224 merge removed the definition at :99, and the other copy
that was in the file came from a branch that is not on main, so main was left with
no definition at all. Restored the one with the GNU parity comment, which is the
one that was there before.

sort's -z test failed for a different reason than it looked. sort -z is correct:
on b\0c\nd\0e\n it writes b\0c\nd\0e\n\0, nine bytes, matching GNU. The test read the
output through os.execute, which hands the captured bytes over as a string, and the
NUL bytes do not survive that: os.execute reported six bytes with the NULs gone.
The test now captures to a file and reads it back with os.read_bytes, so the
comparison is on the real bytes.

Suite after: 41 passed, 3 failed, 8 skipped of 52. The three that fail all read
standard input, which the Windows build of this V does not put in binary mode, and
that is a change in the V compiler rather than in this repository.

* README: mark csplit, join and od done, and correct the count

csplit and join were merged as #221 and #222 but never marked, and od was merged
as #228. The count was 76 of 109; it is 79.

* shuf: mark the options that take an argument with an equals sign

GNU writes --input-range=LO-HI, and the descriptions in #193 differ from that.
The flag module puts a space between the option name and its argument description,
so this gets --input-range =LO-HI rather than --input-range=LO-HI. The equals sign
is the part that carries the meaning, and the space is a limitation of the flag
module rather than something this repository can change.

* cp, mv: add a -progress option

Implements the feature request in #174. Both tools take a --progress option, off by
default, which draws a bar on standard error while the bytes move.

The bar is a fixed forty columns wide and shows a percentage, drawn with a
carriage return so each update overwrites the last rather than scrolling. It is
on standard error because that is where advcpmv draws, and because it keeps the
tool's own standard output clean.

The size of the source is stat'd before the first byte moves, which is what the
bar needs in order to show a percentage and which is why -progress is slower
than a plain copy. The bar itself lives in common/progress.v so both tools share
it.

Two things worth recording:

- A long option with no short form is spelled with two dashes. \cp -progress\
  leaves it as a free argument and the copy fails; \cp --progress\ works.
- mv's directory move removes the source tree after copying, file by file,
  because rmdir only takes an empty directory.

Suite: 43 passed, 3 failed, 8 skipped, of 54. The two new files are cp and mv. The
three that fail all read standard input, which is the Windows binary mode
problem in the V compiler, not in this repository.

* split, tee: add the tests they were missing

Both tools were implemented and marked done in the README but had no test
files, so nothing was guarding them. split gets the three cut modes (-l, -b, -C),
suffix length, numeric suffixes, a custom prefix, a missing file and the refusal to
cut two ways at once. tee gets the copy to stdout and file, append versus truncate, an
uncreatable file and several files at once.

Two expectations were wrong rather than the tools: -b 3 over a\\nb\\nc\\n... cuts g\\nh
and \\n, not \\ng\\n and \\n, and tee creates a missing name rather than failing, so
the error case needs a name in a directory that does not exist.

* pathchk: implement it

Checks whether file names are valid or portable, matching GNU 9.4 on every case
measured: a valid name, an empty name, -p rejecting a space, -P rejecting an empty
name and a leading dash, a nonexistent name, and several names at once.

Two differences remain and both are recorded rather than hidden. GNU prefixes its
messages with its own argv[0], which is the full path when it is invoked by full
path, so the text differs by a prefix only. And GNU takes NAME_MAX from the
filesystem, which is 14 on the WSL filesystem this was measured on and 255 on most
others; V exposes no pathconf, so the POSIX value is used and the difference is
limited to filesystems with a smaller NAME_MAX.

pathchk had no test file before this, so it is new.

* README: mark pathchk done

pathchk was implemented in #231 but never marked. The count was 79 of 109; it is
80.

* tsort: implement it

Topological sort of a partial ordering, matching GNU 9.4 on every case measured: a
chain, a cycle, an odd number of tokens, empty input, a self loop, duplicate
pairs, blank lines and a missing file.

Two things worth recording. A self loop is not a cycle: GNU prints the node once
and exits 0, so the edge is dropped rather than counted. And the ready queue is
taken from the front rather than the back, because a stack reverses the independent
chains relative to the order they were read in, which is the difference between
matching GNU and not on blank-line input.

The only residual difference in a differential run is the argv[0] prefix on the
error messages, which is the same cosmetic difference as shuf and pathchk.

* README: mark tsort done

tsort was implemented in #233 but never marked. The count was 80 of 109; it is
81.

* dircolors: implement it

Outputs the commands to set LS_COLORS, matching GNU 9.4 on every case measured: the
Bourne shell form by default and with -b, the C shell form with -c, an empty
LS_COLORS when the terminal cannot show colours, and a missing database file.

The default database is the one GNU compiles in, measured with TERM=xterm. Without
a TERM, or with TERM=dumb, GNU outputs an empty LS_COLORS rather than the database.

Two things worth recording. The -p form prints the database with a comment header
rather than as LS_COLORS, and that is not matched here. And the database file
parsing only handles EXT lines; the colour keywords that follow them are not read,
so a database file that names no extensions leaves LS_COLORS empty, which is what
GNU does with the same file.

* README: mark dircolors done

dircolors was implemented in #235 but never marked. The count was 81 of 109; it is
82.

* date: implement it

Prints the date and time, matching GNU 9.4 on the default form, +FORMAT, -u, -R
and -I.

Two things worth recording. +FORMAT is not a flag, so the flag parser does not
claim it: it is read from the command line directly and the + is stripped. And V's
Time carries no offset field, so the zone is the difference between the absolute
epoch and the epoch the same wall clock would have in the local zone.

Not implemented: -d with an arbitrary date string, -f for reading dates from a
file, and the locale dependent %c, %x and %X forms.

* realpath: new tool with -e, -m, -L, -P, -q, -s, -z, --relative-to, --relative-base

* README: mark realpath done (82->83)

* README: mark tee done (83->84)

* date: implement it

Prints the date and time, matching GNU 9.4 on the default form, +FORMAT, -u, -R
and -I.

Two things worth recording. +FORMAT is not a flag, so the flag parser does not
claim it: it is read from the command line directly and the + is stripped. And V's
Time carries no offset field, so the zone is the difference between the absolute
epoch and the epoch the same wall clock would have in the local zone.

Not implemented: -d with an arbitrary date string, -f for reading dates from a
file, and the locale dependent %c, %x and %X forms.

* realpath: new tool with -e, -m, -L, -P, -q, -s, -z, --relative-to, --relative-base

* README: mark realpath done (82->83)

* README: mark tee done (83->84)

* realpath: run v fmt -w on realpath.v

Fixes the indentation of a mis-indented block plus struct field alignment. No semantic change.

* README: stop hand-editing the completed count

This branch changed the count line from 82/109 to 84/109 by hand. That line
is derived, not maintained: update-readme-count.yml computes it with

	count=$(grep -c '| ✓ |' README.md)

and rewrites it on every merge to main. So the edit here was redundant, and
because it touched the one line the workflow rewrites, it re-conflicted this
branch on every merge anywhere in the repo. That is the whole of the three
rounds of "Conflict in README" on this PR.

The table rows for date and realpath are already marked done on main, so the
count was the only thing here that was out of step.

Reverting README.md to main's copy leaves this PR touching the tool source
only. The count follows from the rows once the tools merge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants