From b99c6823a7f35b2914d52fdd435488ce2f40872a Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 1 Nov 2022 20:50:55 +0300 Subject: Fix getline_non_blocking() and add test --- libbutl/fdstream.cxx | 11 ++++--- tests/fdstream/driver.cxx | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/libbutl/fdstream.cxx b/libbutl/fdstream.cxx index b4fe4b6..809178a 100644 --- a/libbutl/fdstream.cxx +++ b/libbutl/fdstream.cxx @@ -877,9 +877,9 @@ namespace butl } bool - getline_non_blocking (ifdstream& is, std::string& l, char delim) + getline_non_blocking (ifdstream& is, string& l, char delim) { - assert (!is.blocking () && (is.exceptions () &ifdstream::badbit) != 0); + assert (!is.blocking () && (is.exceptions () & ifdstream::badbit) != 0); fdstreambuf& sb (*static_cast (is.rdbuf ())); @@ -914,12 +914,15 @@ namespace butl // 0 -- blocked before encountering delimiter/EOF. // >0 -- encountered the delimiter. // - if (s == -1 && l.empty ()) + if (s == -1) { + is.setstate (ifdstream::eofbit); + // If we couldn't extract anything, not even the delimiter, then this is // a failure per the getline() interface. // - is.setstate (ifdstream::failbit); + if (l.empty ()) + is.setstate (ifdstream::failbit); } return s != 0; diff --git a/tests/fdstream/driver.cxx b/tests/fdstream/driver.cxx index 0b66574..c07c7c0 100644 --- a/tests/fdstream/driver.cxx +++ b/tests/fdstream/driver.cxx @@ -568,6 +568,83 @@ main (int argc, const char* argv[]) t.join (); } + // Test (non-blocking) reading with getline_non_blocking(). + // + { + const string ln ( + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + + string s; + for (size_t i (0); i < 300; ++i) + { + s += ln; + s += '\n'; + } + + const char* args[] = {argv[0], "-c", nullptr}; + + auto test_read = [&args, &s, &ln] () + { + try + { + process pr (args, -1, -1); + ofdstream os (move (pr.out_fd)); + + ifdstream is (move (pr.in_ofd), + fdstream_mode::non_blocking, + ios_base::badbit); + + os << s; + os.close (); + + fdselect_set fds {is.fd ()}; + fdselect_state& ist (fds[0]); + + string r; + for (string l; ist.fd != nullfd; ) + { + if (ist.fd != nullfd && getline_non_blocking (is, l)) + { + if (eof (is)) + ist.fd = nullfd; + else + { + assert (l == ln); + + r += l; + r += '\n'; + + l.clear (); + } + + continue; + } + + ifdselect (fds); + } + + is.close (); + + assert (r == s); + } + catch (const ios::failure&) + { + assert (false); + } + catch (const process_error&) + { + assert (false); + } + }; + + vector threads; + for (size_t i (0); i < 20; ++i) + threads.emplace_back (test_read); + + for (thread& t: threads) + t.join (); + } + // Test setting and getting position via the non-standard fdstreambuf // interface. // -- cgit v1.1