From 4baf3a4dcacaa5d2fe57dba1a8cb1eee68cd0f21 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Thu, 10 Jan 2013 15:23:29 -0800 Subject: [PATCH] [2572] introduced a special source size of "unknown". this will help handle special cases like using the lexer with stdin associated with a pipe. --- src/lib/dns/master_lexer.cc | 10 ++++++++++ src/lib/dns/master_lexer.h | 16 ++++++++++++++++ src/lib/dns/master_lexer_inputsource.cc | 15 +++++++++++++-- src/lib/dns/master_lexer_inputsource.h | 4 +++- .../tests/master_lexer_inputsource_unittest.cc | 12 ++++++++++-- 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/lib/dns/master_lexer.cc b/src/lib/dns/master_lexer.cc index b3a618f7d2..710f349c76 100644 --- a/src/lib/dns/master_lexer.cc +++ b/src/lib/dns/master_lexer.cc @@ -24,12 +24,22 @@ #include #include +#include #include #include namespace isc { namespace dns { +// The definition of SOURCE_SIZE_UNKNOWN. Note that we initialize it using +// a method of another library. Technically, this could trigger a static +// initialization fiasco. But in this particular usage it's very unlikely +// to happen because this value is expected to be used only as a return +// value of a MasterLexer's method, and its constructor needs definitions +// here. +const size_t MasterLexer::SOURCE_SIZE_UNKNOWN = + std::numeric_limits::max(); + namespace { typedef boost::shared_ptr InputSourcePtr; } // end unnamed namespace diff --git a/src/lib/dns/master_lexer.h b/src/lib/dns/master_lexer.h index cf46c53bc0..6f6ce7dadb 100644 --- a/src/lib/dns/master_lexer.h +++ b/src/lib/dns/master_lexer.h @@ -331,6 +331,16 @@ public: const MasterToken token_; }; + /// \brief Special value for input source size meaning "unknown". + /// + /// This constant value will be used as a return value of + /// \c getTotalSourceSize() when the size of one of the pushed sources + /// is unknown. Note that this value itself is a valid integer in the + /// range of the type, so there's still a small possibility of + /// ambiguity. In practice, however, the value should be sufficiently + /// large that should eliminate the possibility. + static const size_t SOURCE_SIZE_UNKNOWN; + /// \brief Options for getNextToken. /// /// A compound option, indicating multiple options are set, can be @@ -458,6 +468,12 @@ public: /// the size of the data available in the stream at the time of the /// source is pushed. /// + /// In some special cases, it's possible that the size of the file or + /// stream is unknown. It happens, for example, if the standard input + /// is associated with a pipe from the output of another process and it's + /// specified as an input source. If the size of some of the pushed + /// pushed source is unknown, this method returns SOURCE_SIZE_UNKNOWN. + /// /// If there is no source pushed in the lexer, it returns 0. /// /// \throw None diff --git a/src/lib/dns/master_lexer_inputsource.cc b/src/lib/dns/master_lexer_inputsource.cc index 10d637f585..335a0dd6dd 100644 --- a/src/lib/dns/master_lexer_inputsource.cc +++ b/src/lib/dns/master_lexer_inputsource.cc @@ -37,16 +37,27 @@ createStreamName(const std::istream& input_stream) { size_t getStreamSize(std::istream& is) { is.seekg(0, std::ios_base::end); - if (is.fail() || is.bad()) { + if (is.bad()) { + // This means the istream has an integrity error. It doesn't make + // sense to continue from this point, so we treat it as a fatal error. isc_throw(InputSource::OpenError, "failed to seek end of input source"); + } else if (is.fail()) { + // This is an error specific to seekg(). There can be several + // reasons, but the most likely cause in this context is that the + // stream is associated with a special type of file such as a pipe. + // In this case, it's more likely that other main operations of + // the input source work fine, so we continue with just setting + // the stream size to "unknown". + is.clear(); // clear this error not to confuse later ops. + return (MasterLexer::SOURCE_SIZE_UNKNOWN); } const std::streampos len = is.tellg(); if (len == -1) { isc_throw(InputSource::OpenError, "failed to get input size"); } is.seekg(0, std::ios::beg); - if (is.fail() || is.bad()) { + if (is.fail()) { isc_throw(InputSource::OpenError, "failed to seek beginning of input source"); } diff --git a/src/lib/dns/master_lexer_inputsource.h b/src/lib/dns/master_lexer_inputsource.h index 793505954d..2ad0100b6e 100644 --- a/src/lib/dns/master_lexer_inputsource.h +++ b/src/lib/dns/master_lexer_inputsource.h @@ -89,8 +89,10 @@ public: /// \brief Returns the size of the input source in bytes. /// + /// If the size is unknown, it returns \c MasterLexer::SOURCE_SIZE_UNKNOWN. + /// /// See \c MasterLexer::getTotalSourceSize() for the definition of - /// the size of sources. + /// the size of sources and for when the size can be unknown. /// /// \throw None size_t getSize() const { return (input_size_); } diff --git a/src/lib/dns/tests/master_lexer_inputsource_unittest.cc b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc index 1dc3408f3b..a26b02ca14 100644 --- a/src/lib/dns/tests/master_lexer_inputsource_unittest.cc +++ b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc @@ -13,6 +13,7 @@ // PERFORMANCE OF THIS SOFTWARE. #include +#include #include #include @@ -346,9 +347,16 @@ TEST_F(InputSourceTest, getSize) { istringstream iss(""); EXPECT_EQ(0, InputSource(iss).getSize()); - // Pretend there's an error in the stream. The constructor will throw - // in the attempt of getting the input size. + // Pretend there's an error in seeking in the stream. It will be + // considered a seek specific error, and getSize() returns "unknown". iss.setstate(std::ios_base::failbit); + EXPECT_EQ(MasterLexer::SOURCE_SIZE_UNKNOWN, InputSource(iss).getSize()); + // The fail bit should have been cleared. + EXPECT_FALSE(iss.fail()); + + // Pretend there's a *critical* error in the stream. The constructor will + // throw in the attempt of getting the input size. + iss.setstate(std::ios_base::badbit); EXPECT_THROW(InputSource isrc(iss), InputSource::OpenError); // Check with input source from file name. We hardcode the file size