mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
string: Fix split0 return status
It turns out that `string split0` didn't actually ever do any splitting. The arg_iterator_t already split stdin on NUL, and split0 just performed an additional search that could never succeed (since arguments from argv already can't contain NUL). Let the arg_iterator_t not perform any splitting if asked, and then let split0 split in 0. One slight wart is that split0 ignores a trailing NUL, which normal split doesn't. Fixes #5701.
This commit is contained in:
parent
ddc0e68f29
commit
47ff060b89
4 changed files with 21 additions and 8 deletions
|
@ -6,6 +6,7 @@
|
||||||
## Notable fixes and improvements
|
## Notable fixes and improvements
|
||||||
- Fixed infinite recursion triggered if a custom `fish_title` function calls `read` interactively
|
- Fixed infinite recursion triggered if a custom `fish_title` function calls `read` interactively
|
||||||
- Add `$pipestatus` support
|
- Add `$pipestatus` support
|
||||||
|
- `string split0` now returns 0 if it split something (#5701).
|
||||||
|
|
||||||
### Syntax changes and new commands
|
### Syntax changes and new commands
|
||||||
- None yet.
|
- None yet.
|
||||||
|
|
|
@ -75,8 +75,8 @@ class arg_iterator_t {
|
||||||
int argidx_;
|
int argidx_;
|
||||||
// If not using argv, a string to store bytes that have been read but not yet returned.
|
// If not using argv, a string to store bytes that have been read but not yet returned.
|
||||||
std::string buffer_;
|
std::string buffer_;
|
||||||
// If set, when reading from a stream, split on zeros instead of newlines.
|
// If set, when reading from a stream, split on newlines.
|
||||||
const bool split0_;
|
const bool split_;
|
||||||
// Backing storage for the next() string.
|
// Backing storage for the next() string.
|
||||||
wcstring storage_;
|
wcstring storage_;
|
||||||
const io_streams_t &streams_;
|
const io_streams_t &streams_;
|
||||||
|
@ -85,10 +85,9 @@ class arg_iterator_t {
|
||||||
/// not. On true, the string is stored in storage_.
|
/// not. On true, the string is stored in storage_.
|
||||||
bool get_arg_stdin() {
|
bool get_arg_stdin() {
|
||||||
assert(string_args_from_stdin(streams_) && "should not be reading from stdin");
|
assert(string_args_from_stdin(streams_) && "should not be reading from stdin");
|
||||||
// Read in chunks from fd until buffer has a line (or zero if split0_ is set).
|
// Read in chunks from fd until buffer has a line (or the end if split_ is unset).
|
||||||
const char sep = split0_ ? '\0' : '\n';
|
|
||||||
size_t pos;
|
size_t pos;
|
||||||
while ((pos = buffer_.find(sep)) == std::string::npos) {
|
while (!split_ || (pos = buffer_.find('\n')) == std::string::npos) {
|
||||||
char buf[STRING_CHUNK_SIZE];
|
char buf[STRING_CHUNK_SIZE];
|
||||||
long n = read_blocked(streams_.stdin_fd, buf, STRING_CHUNK_SIZE);
|
long n = read_blocked(streams_.stdin_fd, buf, STRING_CHUNK_SIZE);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
@ -118,8 +117,8 @@ class arg_iterator_t {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
arg_iterator_t(const wchar_t *const *argv, int argidx, const io_streams_t &streams,
|
arg_iterator_t(const wchar_t *const *argv, int argidx, const io_streams_t &streams,
|
||||||
bool split0 = false)
|
bool split = true)
|
||||||
: argv_(argv), argidx_(argidx), split0_(split0), streams_(streams) {}
|
: argv_(argv), argidx_(argidx), split_(split), streams_(streams) {}
|
||||||
|
|
||||||
const wcstring *nextstr() {
|
const wcstring *nextstr() {
|
||||||
if (string_args_from_stdin(streams_)) {
|
if (string_args_from_stdin(streams_)) {
|
||||||
|
@ -1073,7 +1072,7 @@ static int string_split_maybe0(parser_t &parser, io_streams_t &streams, int argc
|
||||||
|
|
||||||
wcstring_list_t splits;
|
wcstring_list_t splits;
|
||||||
size_t arg_count = 0;
|
size_t arg_count = 0;
|
||||||
arg_iterator_t aiter(argv, optind, streams, is_split0);
|
arg_iterator_t aiter(argv, optind, streams, !is_split0);
|
||||||
while (const wcstring *arg = aiter.nextstr()) {
|
while (const wcstring *arg = aiter.nextstr()) {
|
||||||
if (opts.right) {
|
if (opts.right) {
|
||||||
split_about(arg->rbegin(), arg->rend(), sep.rbegin(), sep.rend(), &splits, opts.max,
|
split_about(arg->rbegin(), arg->rend(), sep.rbegin(), sep.rend(), &splits, opts.max,
|
||||||
|
@ -1095,6 +1094,13 @@ static int string_split_maybe0(parser_t &parser, io_streams_t &streams, int argc
|
||||||
|
|
||||||
const size_t split_count = splits.size();
|
const size_t split_count = splits.size();
|
||||||
if (!opts.quiet) {
|
if (!opts.quiet) {
|
||||||
|
if (is_split0 && splits.size()) {
|
||||||
|
// split0 ignores a trailing \0, so a\0b\0 is two elements.
|
||||||
|
// In contrast to split, where a\nb\n is three - "a", "b" and "".
|
||||||
|
//
|
||||||
|
// Remove the last element if it is empty.
|
||||||
|
if (splits.back().empty()) splits.pop_back();
|
||||||
|
}
|
||||||
auto &buff = streams.out.buffer();
|
auto &buff = streams.out.buffer();
|
||||||
for (const wcstring &split : splits) {
|
for (const wcstring &split : splits) {
|
||||||
buff.append(split, separation_type_t::explicitly);
|
buff.append(split, separation_type_t::explicitly);
|
||||||
|
|
|
@ -368,6 +368,9 @@ count (echo -ne 'abc\x00def\x00ghi\x00\x00' | string split0)
|
||||||
count (echo -ne 'abc\x00def\x00ghi' | string split0)
|
count (echo -ne 'abc\x00def\x00ghi' | string split0)
|
||||||
count (echo -ne 'abc\ndef\x00ghi\x00' | string split0)
|
count (echo -ne 'abc\ndef\x00ghi\x00' | string split0)
|
||||||
count (echo -ne 'abc\ndef\nghi' | string split0)
|
count (echo -ne 'abc\ndef\nghi' | string split0)
|
||||||
|
# #5701 - split0 always returned 1
|
||||||
|
echo -ne 'a\x00b' | string split0
|
||||||
|
and echo Split something
|
||||||
|
|
||||||
logmsg string join0
|
logmsg string join0
|
||||||
set tmp beta alpha\ngamma
|
set tmp beta alpha\ngamma
|
||||||
|
|
|
@ -463,6 +463,9 @@ a\x00g
|
||||||
3
|
3
|
||||||
2
|
2
|
||||||
1
|
1
|
||||||
|
a
|
||||||
|
b
|
||||||
|
Split something
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# string join0
|
# string join0
|
||||||
|
|
Loading…
Reference in a new issue