libb10_dns___la_SOURCES += labelsequence.h labelsequence.cc
libb10_dns___la_SOURCES += masterload.h masterload.cc
libb10_dns___la_SOURCES += master_lexer.h master_lexer.cc
+libb10_dns___la_SOURCES += master_lexer_state.h
libb10_dns___la_SOURCES += message.h message.cc
libb10_dns___la_SOURCES += messagerenderer.h messagerenderer.cc
libb10_dns___la_SOURCES += name.h name.cc
#include <dns/master_lexer.h>
#include <dns/master_lexer_inputsource.h>
+#include <dns/master_lexer_state.h>
#include <boost/shared_ptr.hpp>
using namespace master_lexer_internal;
struct MasterLexer::MasterLexerImpl {
- MasterLexerImpl() : token_(Token::NOT_STARTED) {}
+ MasterLexerImpl() : source_(NULL), last_was_eol_(false),
+ token_(Token::NOT_STARTED)
+ {}
std::vector<InputSourcePtr> sources_;
+ InputSource* source_; // current source
+ bool last_was_eol_;
Token token_;
};
return (false);
}
+ impl_->sources_.push_back(InputSourcePtr(new InputSource(filename)));
+ impl_->source_ = impl_->sources_.back().get();
return (true);
}
void
MasterLexer::pushSource(std::istream& input) {
impl_->sources_.push_back(InputSourcePtr(new InputSource(input)));
+ impl_->source_ = impl_->sources_.back().get();
}
void
"MasterLexer::popSource on an empty source");
}
impl_->sources_.pop_back();
+ impl_->source_ = impl_->sources_.empty() ? NULL :
+ impl_->sources_.back().get();
}
std::string
return (error_text[val_.error_code_]);
}
+namespace master_lexer_internal {
+typedef MasterLexer::Token Token; // convenience shortcut
+
+bool
+State::wasLastEOL(MasterLexer& lexer) const {
+ return (lexer.impl_->last_was_eol_);
+}
+
+const MasterLexer::Token
+State::getToken(MasterLexer& lexer) const {
+ return (lexer.impl_->token_);
+}
+
+class Start : public State {
+public:
+ Start() {}
+ virtual const State* handle(MasterLexer& lexer) const {
+ const int c = getLexerImpl(lexer)->source_->getChar();
+ if (c < 0) {
+ // TODO: handle unbalance cases
+ getLexerImpl(lexer)->last_was_eol_ = false;
+ getLexerImpl(lexer)->token_ = Token(Token::END_OF_FILE);
+ return (NULL);
+ } else if (c == '\n') {
+ getLexerImpl(lexer)->last_was_eol_ = true;
+ getLexerImpl(lexer)->token_ = Token(Token::END_OF_LINE);
+ return (NULL);
+ }
+ return (&State::getInstance(State::CRLF)); // placeholder
+ }
+};
+
+class CRLF : public State {
+public:
+ CRLF() {}
+ virtual const State* handle(MasterLexer& /*lexer*/) const {
+ return (NULL);
+ }
+};
+
+namespace {
+const Start START_STATE;
+const CRLF CRLF_STARTE;
+}
+
+const State&
+State::getInstance(ID /*state_id*/) {
+ return (START_STATE);
+}
+
+
+} // namespace master_lexer_internal
+
} // end of namespace dns
} // end of namespace isc
namespace isc {
namespace dns {
+namespace master_lexer_internal {
+class State;
+}
/// \brief Tokenizer for parsing DNS master files.
///
/// specifically by the \c MasterLoader class and \c Rdata implementation
/// classes.
class MasterLexer {
+ friend class master_lexer_internal::State;
public:
class Token; // we define it separately for better readability
--- /dev/null
+// 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 MASTER_LEXER_STATE_H
+#define MASTER_LEXER_STATE_H 1
+
+#include <dns/master_lexer.h>
+
+namespace isc {
+namespace dns {
+
+namespace master_lexer_internal {
+class InputSource;
+
+class State {
+public:
+ enum ID {
+ Start, ///< TBD
+ CRLF,
+ EatLine
+ };
+ virtual const State* handle(MasterLexer& lexer) const = 0;
+
+ static const State& getInstance(ID state_id);
+
+ /// \name Read-only accessors for testing purposes.
+ bool wasLastEOL(MasterLexer& lexer) const;
+ const MasterLexer::Token getToken(MasterLexer& lexer) const;
+
+protected:
+ MasterLexer::MasterLexerImpl* getLexerImpl(MasterLexer& lexer) const {
+ return (lexer.impl_);
+ }
+};
+
+} // namespace master_lexer_internal
+} // namespace dns
+} // namespace isc
+#endif // MASTER_LEXER_STATE_H
+
+// Local Variables:
+// mode: c++
+// End:
run_unittests_SOURCES += messagerenderer_unittest.cc
run_unittests_SOURCES += master_lexer_token_unittest.cc
run_unittests_SOURCES += master_lexer_unittest.cc
+run_unittests_SOURCES += master_lexer_state_unittest.cc
run_unittests_SOURCES += name_unittest.cc
run_unittests_SOURCES += nsec3hash_unittest.cc
run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
--- /dev/null
+// 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 <dns/master_lexer.h>
+#include <dns/master_lexer_state.h>
+
+#include <gtest/gtest.h>
+
+#include <sstream>
+
+using namespace isc::dns;
+using namespace master_lexer_internal;
+
+namespace {
+typedef MasterLexer::Token Token; // shortcut
+
+class MasterLexerStateTest : public ::testing::Test {
+protected:
+ MasterLexerStateTest() : s_start(State::getInstance(State::Start)),
+ s_crlf(State::getInstance(State::CRLF))
+ {
+ lexer.open(ss);
+ }
+ const State& s_start;
+ const State& s_crlf;
+ MasterLexer lexer;
+ std::stringstream ss;
+};
+
+// Common check for the end-of-file condition.
+// Token is set to END_OF_FILE, and the lexer was NOT last eol state.
+// Passed state can be any valid one; they are stateless, just providing the
+// interface for inspection.
+void
+eofCheck(const State& state, MasterLexer& lexer) {
+ EXPECT_EQ(Token::END_OF_FILE, state.getToken(lexer).getType());
+ EXPECT_FALSE(state.wasLastEOL(lexer));
+}
+
+TEST_F(MasterLexerStateTest, startAndEnd) {
+ // A simple case: the input is empty, so we begin with start and
+ // are immediately done.
+ const State* s_next = s_start.handle(lexer);
+ EXPECT_EQ(static_cast<const State*>(NULL), s_next);
+ eofCheck(s_start, lexer);
+}
+
+TEST_F(MasterLexerStateTest, startToEOL) {
+ ss << "\n";
+ const State* s_next = s_start.handle(lexer);
+ EXPECT_EQ(static_cast<const State*>(NULL), s_next);
+ EXPECT_TRUE(s_start.wasLastEOL(lexer));
+ EXPECT_EQ(Token::END_OF_LINE, s_start.getToken(lexer).getType());
+
+ // The next lexer session will reach EOF. Same eof check should pass.
+ s_start.handle(lexer);
+ eofCheck(s_start, lexer);
+}
+
+}