aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2022-11-01 20:50:55 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2022-11-01 21:19:39 +0300
commitb99c6823a7f35b2914d52fdd435488ce2f40872a (patch)
tree6bbedf4eea6191ff508375098c5142303c23599f
parent3e346a2a845320c19beab6c281fe4b7c14b88a4a (diff)
Fix getline_non_blocking() and add test
-rw-r--r--libbutl/fdstream.cxx11
-rw-r--r--tests/fdstream/driver.cxx77
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<fdstreambuf*> (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<thread> 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.
//