From aa780963e018f3c8ba7409a25fd608854fec3d2e Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 19 Apr 2016 14:52:05 +1000 Subject: [PATCH] io: support piped streams in slurp --- io.cpp | 30 ++++++++++++++++++++++++------ io.hpp | 8 ++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/io.cpp b/io.cpp index c239db5e..f56931ba 100644 --- a/io.cpp +++ b/io.cpp @@ -82,16 +82,34 @@ util::slurp (FILE *stream) if (fstat (desc, &meta) < 0) errno_error::throw_code (); - // allocate a buffer we think is the correct size std::vector buf; - buf.resize (meta.st_size); - // read as much as possible, then resize to the actual length - auto res = fread (buf.data (), 1, meta.st_size, stream); - if (!ferror (stream)) + // we think we know the size, so try to do a simple read + if (meta.st_size) { + buf.resize (meta.st_size); + + // read as much as possible, then resize to the actual length + auto res = fread (buf.data (), 1, meta.st_size, stream); buf.resize (res); + } + + // try reading small chunks until we've hit the end. important for + // handling pipe streams (like from popen) which report a zero size. + constexpr size_t CHUNK_SIZE = 128; + size_t cursor = buf.size (); + + while (!feof (stream) && !ferror (stream)) { + auto oldsize = buf.size (); + buf.resize (oldsize + CHUNK_SIZE); + auto res = fread (buf.data () + cursor, 1, CHUNK_SIZE, stream); + + if (res != CHUNK_SIZE) + buf.resize (oldsize + res); + } + + if (ferror (stream)) + throw stream_error (); - CHECK (feof (stream)); return buf; } diff --git a/io.hpp b/io.hpp index 4241e6fa..a4e77b6c 100644 --- a/io.hpp +++ b/io.hpp @@ -142,6 +142,14 @@ namespace util { private: const boost::filesystem::path m_path; }; + + class stream_error : public std::exception { + public: + virtual ~stream_error () { ; } + + virtual const char* what (void) const noexcept + { return "error on C stream"; } + }; } #ifdef PLATFORM_WIN32