Parcourir la source

[2427] Handle the initial whitespace

Michal 'vorner' Vaner il y a 12 ans
Parent
commit
79b7e9ce53
1 fichiers modifiés avec 60 ajouts et 24 suppressions
  1. 60 24
      src/lib/dns/master_loader.cc

+ 60 - 24
src/lib/dns/master_loader.cc

@@ -56,6 +56,8 @@ public:
         lexer_(),
         zone_origin_(zone_origin),
         active_origin_(zone_origin),
+        last_name_(Name::ROOT_NAME()), // Initialize with something,
+                                       // we don't care
         zone_class_(zone_class),
         callbacks_(callbacks),
         add_callback_(add_callback),
@@ -64,6 +66,7 @@ public:
         initialized_(false),
         ok_(true),
         many_errors_((options & MANY_ERRORS) != 0),
+        seen_name_(false),
         complete_(false),
         seen_error_(false)
     {}
@@ -205,6 +208,7 @@ private:
     const Name zone_origin_;
     Name active_origin_; // The origin used during parsing
                          // (modifiable by $ORIGIN)
+    Name last_name_;     // Last seen name during the parsing.
     const RRClass zone_class_;
     MasterLoaderCallbacks callbacks_;
     AddRRCallback add_callback_;
@@ -215,6 +219,7 @@ private:
     bool ok_;                   // Is it OK to continue loading?
     const bool many_errors_;    // Are many errors allowed (or should we abort
                                 // on the first)
+    bool seen_name_;            // Did we parse at least one name?
 public:
     bool complete_;             // All work done.
     bool seen_error_;           // Was there at least one error during the
@@ -236,11 +241,26 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
     size_t count = 0;
     while (ok_ && count < count_limit) {
         try {
+            MasterToken initial_token(MasterToken::NO_TOKEN_PRODUCED);
             // Skip all EOLNs (empty lines) and finish on EOF
-            bool empty = true;
             do {
-                const MasterToken& empty_token(lexer_.getNextToken());
-                if (empty_token.getType() == MasterToken::END_OF_FILE) {
+                initial_token = lexer_.getNextToken(MasterLexer::QSTRING |
+                                                    MasterLexer::INITIAL_WS);
+                if (initial_token.getType() == MasterToken::INITIAL_WS) {
+                    // The INITIAL_WS is interesting only if something is
+                    // after it. So peek there and if there's EOLN or EOF,
+                    // ignore it.
+                    const MasterToken& peek_token(lexer_.getNextToken());
+                    if (peek_token.getType() == MasterToken::END_OF_LINE ||
+                        peek_token.getType() == MasterToken::END_OF_FILE) {
+                        initial_token = peek_token;
+                    } else {
+                        // It is something interesting. Return it back and
+                        // keep the whitespace.
+                        lexer_.ungetToken();
+                    }
+                }
+                if (initial_token.getType() == MasterToken::END_OF_FILE) {
                     if (!popSource()) {
                         return (true);
                     } else {
@@ -251,29 +271,45 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
                         continue;
                     }
                 }
-                empty = empty_token.getType() == MasterToken::END_OF_LINE;
-            } while (empty);
-            // Return the last token, as it was not empty
-            lexer_.ungetToken();
+            } while (initial_token.getType() == MasterToken::END_OF_LINE ||
+                     initial_token.getType() == MasterToken::END_OF_FILE);
+
+            if (initial_token.getType() == MasterToken::QSTRING ||
+                initial_token.getType() == MasterToken::STRING) {
+                // If it is name (or directive), handle it.
+                const MasterToken::StringRegion&
+                    name_string(initial_token.getStringRegion());
+
+                if (name_string.len > 0 && name_string.beg[0] == '$') {
+                    // This should have either thrown (and the error handler
+                    // will read up until the end of line) or read until the
+                    // end of line.
+
+                    // Exclude the $ from the string on this point.
+                    handleDirective(name_string.beg + 1, name_string.len - 1);
+                    // So, get to the next line, there's nothing more interesting
+                    // in this one.
+                    continue;
+                }
 
-            const MasterToken::StringRegion&
-                name_string(lexer_.getNextToken(MasterToken::QSTRING).
-                            getStringRegion());
-
-            if (name_string.len > 0 && name_string.beg[0] == '$') {
-                // This should have either thrown (and the error handler
-                // will read up until the end of line) or read until the
-                // end of line.
-
-                // Exclude the $ from the string on this point.
-                handleDirective(name_string.beg + 1, name_string.len - 1);
-                // So, get to the next line, there's nothing more interesting
-                // in this one.
-                continue;
+                last_name_ = Name(name_string.beg, name_string.len,
+                                  &active_origin_);
+                seen_name_ = true;
+            } else if (initial_token.getType() == MasterToken::INITIAL_WS) {
+                // This means the same name as previous.
+                if (!seen_name_) {
+                    isc_throw(InternalException, "No previous name to use in "
+                              "place of initial whitespace");
+                }
+            } else if (initial_token.getType() == MasterToken::ERROR) {
+                // Error token here.
+                isc_throw(InternalException, initial_token.getErrorText());
+            } else {
+                // Some other token (what could that be?)
+                isc_throw(InternalException, "Parser got confused (unexpected "
+                          "token " << initial_token.getType() << ")");
             }
 
-            const Name name(name_string.beg, name_string.len,
-                            &active_origin_);
             // TODO: Some more flexibility. We don't allow omitting
             // anything yet
 
@@ -301,7 +337,7 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
             // callbacks_ already. We need to decide if we want to continue
             // or not.
             if (data) {
-                add_callback_(name, rrclass, rrtype, ttl, data);
+                add_callback_(last_name_, rrclass, rrtype, ttl, data);
 
                 // Good, we loaded another one
                 ++count;