Repository navigation
fold: parse the obsolete -WIDTH form the way GNU does - #14248
Conversation
|
Binary size comparison: |
|
GNU testsuite comparison: |
`handle_obsolete` scanned every argument for `-DIGITS` and pulled the
first match out, without checking whether that argument was already
spoken for. Five GNU incompatibilities followed:
fold -w -1 FILE reported FILE as the invalid width, not -1, because
-1 was taken as the obsolete form and -w then bound
to the file name. Same for -bw, -sw and --width.
fold -w3 -5 folded at 3; GNU folds at 5, since it reads options
left to right and the last width wins.
fold -3 -5 failed with "unexpected argument '-5'", as only the
first obsolete width was consumed.
fold -w 3 -w 5 failed with "cannot be used multiple times".
fold -- -3 read stdin, swallowing the width past the -- that
should have made it a file name.
Rewrite the obsolete form into --width=N in place instead, leaving the
order intact, and let clap pick the last one via args_override_self.
Arguments that are the value of -w/--width, and anything after --, are
no longer eligible.
The remaining difference on `fold -w 0` ("Result too large" against
GNU's "Numerical result out of range") is a separate wording issue and
is left alone.
61569ed to
17a7fe9
Compare
|
sorry, i broke it |
The underflow fixed in the previous commit had no test behind it. This pins `-` as an operand in each position, including as the value of -w where GNU rejects it as a width.
|
No apology needed — and thank you for pushing the fix rather than waiting on me. I've added a test on top so it stays fixed: 100 fold tests pass, Prepared with AI assistance (Claude Opus 5, via Claude Code); comparisons run locally against GNU coreutils 9.11. |
`takes_width_value` decided a trailing `w` by comparing `find('w')` to
`len().checked_sub(1)`. For a bare `-` (short = ""), both sides are
`None` -- "no 'w' found" and "length underflowed" are different reasons,
but the comparison can't tell them apart, so it reported a match:
$ fold - -5 <<< hello
error: unexpected argument '-5' found # uutils, before
hello # GNU, and uutils after
That made the `-` operand swallow whatever followed it as a width value
instead of leaving it for the obsolete-width scan, so `fold - -5` failed
to parse where GNU folds normally. `ends_with('w')` is false on an empty
string, so it doesn't share the bug.
Found while investigating an unrelated CI failure in this PR (a broken
pipe in test_dash_operand_reads_stdin, which turned out to be a flaky
cross-compiled job, not this) -- this bug doesn't explain that failure,
but turned up real and worth fixing while looking at this function.
|
Thanks! |
|
|
fold'shandle_obsoletescanned every argument for-DIGITSand pulled the first match out, without checking whether that argument was already spoken for. Five GNU incompatibilities followed from that one function.Found by differential testing against GNU coreutils 9.11; each row below was confirmed by running both binaries.
fold -w -1 FILEinvalid number of columns: '-1'invalid number of columns: 'FILE'fold -w3 -5fold -3 -5error: unexpected argument '-5' foundfold -w 3 -w 5error: ... cannot be used multiple timesfold -- -3fold: -3: No such file or directoryThe first row also applies to
-bw -1,-sw -1and--width -1:-1was taken as the obsolete form, so-wbound to the file name and reported that as the invalid width.Approach
Rather than lifting one width out of the argument list, the obsolete form is now rewritten into
--width=Nin place. That keeps the original left-to-right order, so clap can apply the same last-one-wins rule GNU gets from processing options in sequence — enabled here withargs_override_self(true), matching whatcutalready does.An argument is only eligible for that rewrite when it is not the value of
-w/--widthand has not been placed after a--terminator. Short clusters are handled by position:-swtakes the next argument, while-w3and-wbcarry their value inline.Testing
Three regression tests added. I verified they actually catch the bugs by reverting the change to
fold.rsalone — all three fail, then pass again with it restored.cargo test --features fold --no-default-features test_fold: 99 passed, 0 failed (96 pre-existing, 3 new)cargo fmt --checkandcargo clippy -p uu_fold --all-targets: cleanThe 2 that still differ are
fold -0/fold -w 0, where GNU saysNumerical result out of rangeand uutils saysResult too large. That is a pre-existing wording difference in the error string, unrelated to argument parsing, so I left it alone rather than widen this PR.Partially related to #5998 (allowing repeated flags), though this only changes
fold.Disclosure
Prepared with AI assistance (Claude Opus 5, via Claude Code), per the AI policy in CONTRIBUTING.md. On the GPL concern raised there specifically: the expected behavior was derived by running the installed GNU
foldbinary as a black box and recording its output. I did not read GNU coreutils source while writing this, and the implementation approach (rewrite-in-place +args_override_self) follows the existing pattern in this repo'scut, not anything from GNU. All testing above was run locally.