Browse Source

[2369] Add InputSource helper class (work-in-progress)

Mukund Sivaraman 12 years ago
parent
commit
29ff6bebc9

+ 1 - 0
src/lib/dns/Makefile.am

@@ -93,6 +93,7 @@ libb10_dns___la_LDFLAGS = -no-undefined -version-info 2:0:0
 libb10_dns___la_SOURCES =
 libb10_dns___la_SOURCES += edns.h edns.cc
 libb10_dns___la_SOURCES += exceptions.h exceptions.cc
+libb10_dns___la_SOURCES += inputsource.h inputsource.cc
 libb10_dns___la_SOURCES += labelsequence.h labelsequence.cc
 libb10_dns___la_SOURCES += masterload.h masterload.cc
 libb10_dns___la_SOURCES += message.h message.cc

+ 74 - 0
src/lib/dns/inputsource.cc

@@ -0,0 +1,74 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/inputsource.h>
+#include <exceptions/exceptions.h>
+
+namespace isc {
+namespace dns {
+namespace master_lexer_internal {
+
+int
+InputSource::getChar() {
+    if (buffer_pos_ == buffer_.size()) {
+        // We may have reached EOF at the last call to
+        // getChar(). at_eof_ will be set then. We then simply return
+        // early.
+        if (at_eof_) {
+            return -1;
+        }
+        // We are not yet at EOF. Read from the stream.
+        int c = input_.get();
+        // Have we reached EOF now? If so, set at_eof_ and return early,
+        // but don't modify buffer_pos_ (which should still be equal to
+        // the size of buffer_).
+        if (!input_.good()) {
+            at_eof_ = true;
+            return -1;
+        }
+        buffer_.push_back(c);
+    }
+
+    int c = buffer_[buffer_pos_++];
+    if (c == '\n') {
+        line_++;
+    }
+
+    return (c);
+}
+
+void
+InputSource::ungetChar() {
+    if (at_eof_) {
+        at_eof_ = false;
+    } else if (buffer_pos_ == 0) {
+        isc_throw(OutOfRange, "Cannot skip before the start of buffer");
+    } else {
+        if (buffer_[buffer_pos_] == '\n') {
+            line_--;
+        }
+        buffer_pos_--;
+    }
+}
+
+void
+InputSource::ungetAll() {
+    buffer_pos_ = 0;
+    line_ = saved_line_;
+    at_eof_ = false;
+}
+
+} // namespace master_lexer_internal
+} // namespace dns
+} // namespace isc

+ 76 - 0
src/lib/dns/inputsource.h

@@ -0,0 +1,76 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DNS_INPUTSOURCE_H
+#define DNS_INPUTSOURCE_H 1
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dns {
+namespace master_lexer_internal {
+
+class InputSource {
+public:
+    InputSource(std::istream& input, const std::string& name) :
+        input_(input),
+        name_(name),
+        at_eof_(false),
+        line_(1),
+        saved_line_(line_),
+        buffer_pos_(buffer_.size())
+    {}
+
+    const std::string& getName() {
+        return (name_);
+    }
+
+    bool atEOF() const {
+        return (at_eof_);
+    }
+
+    size_t getCurrentLine() const {
+        return (line_);
+    }
+
+    void saveLine() {
+        saved_line_ = line_;
+    }
+
+    int getChar();
+    void ungetChar();
+    void ungetAll();
+
+private:
+    std::istream& input_;
+    const std::string name_;
+    bool at_eof_;
+    size_t line_;
+    size_t saved_line_;
+
+    std::vector<char> buffer_;
+    size_t buffer_pos_;
+};
+
+} // namespace master_lexer_internal
+} // namespace dns
+} // namespace isc
+
+#endif  // DNS_INPUTSOURCE_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 1 - 0
src/lib/dns/tests/Makefile.am

@@ -22,6 +22,7 @@ if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES = unittest_util.h unittest_util.cc
 run_unittests_SOURCES += edns_unittest.cc
+run_unittests_SOURCES += inputsource_unittest.cc
 run_unittests_SOURCES += labelsequence_unittest.cc
 run_unittests_SOURCES += messagerenderer_unittest.cc
 run_unittests_SOURCES += name_unittest.cc

+ 147 - 0
src/lib/dns/tests/inputsource_unittest.cc

@@ -0,0 +1,147 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/inputsource.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <string.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::master_lexer_internal;
+
+namespace {
+
+class InputSourceTest : public ::testing::Test {
+protected:
+    InputSourceTest() :
+        name_("a90wjer"),
+        str_("Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n"),
+        str_length_(strlen(str_)),
+        iss_(str_),
+        source_(iss_, name_)
+    {}
+
+    string name_;
+    const char* str_;
+    size_t str_length_;
+    stringstream iss_;
+    InputSource source_;
+};
+
+// Test the default return values set during InputSource construction.
+TEST_F(InputSourceTest, defaults) {
+    EXPECT_EQ(name_, source_.getName());
+    EXPECT_EQ(1, source_.getCurrentLine());
+    EXPECT_FALSE(source_.atEOF());
+}
+
+// getChar() should return characters from the input stream in
+// sequence. ungetChar() should skip backwards.
+TEST_F(InputSourceTest, getAndUngetChar) {
+    for (size_t i = 0; i < str_length_; i++) {
+        EXPECT_EQ(str_[i], source_.getChar());
+        EXPECT_FALSE(source_.atEOF());
+    }
+
+    // At this point, we still have not reached EOF.
+    EXPECT_FALSE(source_.atEOF());
+
+    // This should cause EOF to be set.
+    EXPECT_EQ(-1, source_.getChar());
+
+    // Now, EOF should be set.
+    EXPECT_TRUE(source_.atEOF());
+
+    // Now, let's go backwards. This should cause the EOF to be set to
+    // false.
+    source_.ungetChar();
+
+    // Now, EOF should be false.
+    EXPECT_FALSE(source_.atEOF());
+
+    // This should cause EOF to be set again.
+    EXPECT_EQ(-1, source_.getChar());
+
+    // Now, EOF should be set.
+    EXPECT_TRUE(source_.atEOF());
+
+    // Now, let's go backwards in a loop. Start by skipping the EOF.
+    source_.ungetChar();
+
+    for (size_t i = 0; i < str_length_; i++) {
+        size_t index = str_length_ - 1 - i;
+        // Skip one character.
+        source_.ungetChar();
+        EXPECT_EQ(str_[index], source_.getChar());
+        // Skip the character we received again.
+        source_.ungetChar();
+    }
+
+    // Skipping past the start of buffer should throw.
+    EXPECT_THROW(source_.ungetChar(), isc::OutOfRange);
+}
+
+// ungetAll() should skip back to the place where the InputSource
+// started at construction.
+TEST_F(InputSourceTest, ungetAll) {
+    while (!source_.atEOF()) {
+        source_.getChar();
+    }
+
+    // Now, we are at EOF.
+    EXPECT_TRUE(source_.atEOF());
+    EXPECT_EQ(4, source_.getCurrentLine());
+
+    source_.ungetAll();
+
+    // Now we are back to where we started.
+    EXPECT_EQ(1, source_.getCurrentLine());
+    EXPECT_FALSE(source_.atEOF());
+}
+
+
+// Test line counters.
+TEST_F(InputSourceTest, lines) {
+    size_t line = 1;
+    while (!source_.atEOF()) {
+        if (source_.getChar() == '\n') {
+            line++;
+        }
+        EXPECT_EQ(line, source_.getCurrentLine());
+    }
+
+    // Now, we are at EOF.
+    EXPECT_TRUE(source_.atEOF());
+    EXPECT_EQ(4, source_.getCurrentLine());
+
+    // Go backwards 1 character, skipping the last '\n'.
+    source_.ungetChar();
+    EXPECT_FALSE(source_.atEOF());
+    EXPECT_EQ(3, source_.getCurrentLine());
+
+    source_.ungetAll();
+
+    // Now we are back to where we started.
+    EXPECT_EQ(1, source_.getCurrentLine());
+    EXPECT_FALSE(source_.atEOF());
+}
+
+} // end namespace