When input ended with a blank immediately before its final newline,
xargs passed one extra empty argument to the command:
$ printf 'aaa \nbbb \n' | xargs printf '[%s]'
[aaa][bbb][] # was
[aaa][bbb] # GNU findutils 4.10.0, and now
WhitespaceDelimitedArgumentReader::next used one `result.is_empty()`
check to answer two different questions. The whitespace branch broke out
of the loop only if `result` was non-empty, so a delimiter seen before
any token was skipped -- correct for blanks, but it left "we are
mid-token" indistinguishable from "we have not started one". The EOF
branch then used `i == 0` as a proxy for "nothing was consumed", which
is false for a final call that consumes only the trailing newline, so it
flushed a zero-length token. Input ending without a newline happened to
work because nothing was left to consume.
Track that state explicitly with an `in_argument` flag, mirroring
`seen_arg` in GNU's read_line, and test `result.is_empty()` at EOF. A
delimiter now ends an argument only when we are inside one, and EOF
flushes only a non-empty buffer.
This also fixes a second symptom of the same conflation: quoted empty
arguments were dropped mid-stream, since quotes start an argument
without contributing any bytes. `printf '"" x\n'` gave [x] and now gives
[][x], again matching GNU. An unterminated `x ''` at end of input still
yields just [x], as GNU's `if (p == linebuf) return -1` does.
-I/-i is unaffected: with a replace string and no explicit delimiter,
xargs uses the newline-delimited reader instead.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
GNU xargs treats the arguments to -I, -E, and -e as values even when
they begin with a hyphen. Clap was parsing those strings as options
instead, so invocations like 'xargs -I -_' failed before xargs could
process input.
Allow hyphen-leading values for those options and add regression
coverage for replacement and EOF markers that start with '-'.