#include <dns/master_lexer_inputsource.h>
#include <dns/master_lexer.h>
+#include <istream>
+#include <iostream>
+#include <cassert>
#include <cerrno>
#include <cstring>
return (ss.str());
}
+size_t
+getStreamSize(std::istream& is) {
+ is.seekg(0, std::ios_base::end);
+ if (is.fail() || is.bad()) {
+ isc_throw(InputSource::OpenError,
+ "failed to seek end of input source");
+ }
+ 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()) {
+ isc_throw(InputSource::OpenError,
+ "failed to seek beginning of input source");
+ }
+ assert(len >= 0);
+ return (len);
+}
+
} // end of unnamed namespace
// Explicit definition of class static constant. The value is given in the
saved_line_(line_),
buffer_pos_(0),
name_(createStreamName(input_stream)),
- input_(input_stream)
+ input_(input_stream),
+ input_size_(getStreamSize(input_))
{}
-InputSource::InputSource(const char* filename) :
- at_eof_(false),
- line_(1),
- saved_line_(line_),
- buffer_pos_(0),
- name_(filename),
- input_(file_stream_)
-{
+namespace {
+// A helper to initialize InputSource::input_ in the member initialization
+// list.
+std::istream&
+openFileStream(std::ifstream& file_stream, const char* filename) {
errno = 0;
- file_stream_.open(filename);
- if (file_stream_.fail()) {
+ file_stream.open(filename);
+ if (file_stream.fail()) {
std::string error_txt("Error opening the input source file: ");
error_txt += filename;
if (errno != 0) {
error_txt += "; possible cause: ";
error_txt += std::strerror(errno);
}
- isc_throw(OpenError, error_txt);
+ isc_throw(InputSource::OpenError, error_txt);
}
+
+ return (file_stream);
+}
}
+InputSource::InputSource(const char* filename) :
+ at_eof_(false),
+ line_(1),
+ saved_line_(line_),
+ buffer_pos_(0),
+ name_(filename),
+ input_(openFileStream(file_stream_, filename)),
+ input_size_(getStreamSize(input_))
+{}
+
InputSource::~InputSource()
{
if (file_stream_.is_open()) {
return (name_);
}
+ /// \brief Returns the size of the input source in bytes.
+ ///
+ /// If the input source is a normal file, the return value should be
+ /// equal to the file size at the time of the source is created.
+ /// If the input source is other type of input stream, its the size of
+ /// the data available in the stream at the time of the construction of
+ /// the source.
+ ///
+ /// \throw None.
+ size_t getSize() const { return (input_size_); }
+
/// \brief Returns if the input source is at end of file.
bool atEOF() const {
return (at_eof_);
const std::string name_;
std::ifstream file_stream_;
std::istream& input_;
+ const size_t input_size_;
};
} // namespace master_lexer_internal
namespace {
+const char* const test_input =
+ "Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n";
+
class InputSourceTest : public ::testing::Test {
protected:
InputSourceTest() :
- str_("Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n"),
+ str_(test_input),
str_length_(strlen(str_)),
iss_(str_),
source_(iss_)
EXPECT_FALSE(source_.atEOF());
}
+TEST_F(InputSourceTest, getSize) {
+ // A simple case using string stream
+ EXPECT_EQ(strlen(test_input), source_.getSize());
+
+ // Check it works with an empty input
+ 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.
+ iss.setstate(std::ios_base::failbit);
+ EXPECT_THROW(InputSource isrc(iss), InputSource::OpenError);
+
+ // Check with input source from file name. We hardcode the file size
+ // for simplicity. It won't change too often.
+ EXPECT_EQ(143, InputSource(TEST_DATA_SRCDIR "/masterload.txt").getSize());
+}
+
} // end namespace