BIND 10 trac2430, updated. 734c918dd9a93c4d69e060bd6d81fa53967b0067 [2430] Support $GENERATE format modifiers

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Feb 3 07:55:45 UTC 2014


The branch, trac2430 has been updated
       via  734c918dd9a93c4d69e060bd6d81fa53967b0067 (commit)
      from  981f0d20d284b83e4d5d624d0120954d341e865a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 734c918dd9a93c4d69e060bd6d81fa53967b0067
Author: Mukund Sivaraman <muks at isc.org>
Date:   Mon Feb 3 13:08:51 2014 +0530

    [2430] Support $GENERATE format modifiers
    
    Supports everything except nibble mode. Nibble mode will come soon.

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dns/master_loader.cc                |   61 ++++++++++++++++++-
 src/lib/dns/tests/master_loader_unittest.cc |   87 +++++++++++++++++++++++++++
 2 files changed, 145 insertions(+), 3 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/lib/dns/master_loader.cc b/src/lib/dns/master_loader.cc
index f8035df..bfb5ec0 100644
--- a/src/lib/dns/master_loader.cc
+++ b/src/lib/dns/master_loader.cc
@@ -452,7 +452,7 @@ MasterLoader::MasterLoaderImpl::generateForIter(const std::string& str,
 
   for (std::string::const_iterator it = str.begin(); it != str.end();) {
       switch (*it) {
-      case '$':
+      case '$': {
           ++it;
           if ((it != str.end()) && (*it == '$')) {
               rstr.push_back('$');
@@ -460,9 +460,56 @@ MasterLoader::MasterLoaderImpl::generateForIter(const std::string& str,
               continue;
           }
 
-          // TODO: This doesn't handle format specifiers in {} yet.
-          rstr += boost::str(boost::format("%d") % i);
+          bool nibble_mode = false;
+          bool nibble_uppercase = false;
+          std::string fmt("%d");
+          int delta = 0;
+
+          if (*it == '{') {
+              const char* scan_str =
+                  str.c_str() + std::distance(str.begin(), it);
+              unsigned int width;
+              char mode[2] = {'d', 0}; // char plus null byte
+              const int n = sscanf(scan_str, "{%d,%u,%1[doxXnN]}",
+                                   &delta, &width, mode);
+              switch (n) {
+              case 1:
+                  break;
+
+              case 2:
+                  fmt = boost::str(boost::format("%%0%ud") % width);
+                  break;
+
+              case 3:
+                  if ((mode[0] == 'n') || (mode[0] == 'N')) {
+                      nibble_mode = true;
+                      nibble_uppercase = (mode[0] == 'N');
+                  }
+                  fmt = boost::str(boost::format("%%0%u%c") % width % mode[0]);
+                  break;
+
+              default:
+                  reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
+                              "Invalid $GENERATE format modifiers");
+                  return ("");
+              }
+
+              /* Skip past closing brace. */
+              while ((it != str.end()) && (*it != '}')) {
+                  ++it;
+              }
+              if (it != str.end()) {
+                  ++it;
+              }
+          }
+
+          // TODO: Handle nibble mode
+          assert(!nibble_mode);
+          nibble_uppercase = nibble_uppercase;
+
+          rstr += boost::str(boost::format(fmt) % (i + delta));
           break;
+      }
 
       case '\\':
           rstr.push_back(*it);
@@ -539,6 +586,14 @@ MasterLoader::MasterLoaderImpl::doGenerate() {
     for (int i = start; i <= stop; i += step) {
         const std::string generated_name = generateForIter(lhs, i);
         const std::string generated_rdata = generateForIter(rhs, i);
+        if (generated_name.empty() || generated_rdata.empty()) {
+            // The error should have been sent to the callbacks already
+            // by generateForIter().
+            reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
+                        "$GENERATE error");
+            return;
+        }
+
         const size_t name_length = generated_name.size();
         last_name_.reset(new Name(generated_name.c_str(), name_length,
                                   &active_origin_));
diff --git a/src/lib/dns/tests/master_loader_unittest.cc b/src/lib/dns/tests/master_loader_unittest.cc
index eedb130..1bbfde7 100644
--- a/src/lib/dns/tests/master_loader_unittest.cc
+++ b/src/lib/dns/tests/master_loader_unittest.cc
@@ -502,6 +502,93 @@ TEST_F(MasterLoaderTest, generateWithStep) {
     checkRR("host31.example.org", RRType::A(), "192.0.2.31");
 }
 
+TEST_F(MasterLoaderTest, generateWithModifiers) {
+    const string input =
+        "$ORIGIN example.org.\n"
+        "$TTL 3600\n"
+        "$GENERATE 2-9/2 host${1} A 192.0.2.${-1}\n"
+        "$GENERATE 10-12 host${0,4} A 192.0.2.$\n"
+        "$GENERATE 14-15 host${0,4,d} A 192.0.2.$\n"
+        "$GENERATE 30-31 host${0,4,x} A 192.0.2.$\n"
+        // Names are case-insensitive, so we use TXT's RDATA to check
+        // case.
+        "$GENERATE 42-43 host$ TXT \"Value ${0,4,X}\"\n"
+        "$GENERATE 45-46 host${0,4,o} A 192.0.2.$\n"
+        // Junk type will not parse and 'd' is assumed.
+        "$GENERATE 100-101 host${0,4,j} A 192.0.2.$\n";
+    stringstream ss(input);
+    setLoader(ss, Name("example.org."), RRClass::IN(),
+              MasterLoader::MANY_ERRORS);
+
+    loader_->load();
+    EXPECT_TRUE(loader_->loadedSucessfully());
+    EXPECT_TRUE(errors_.empty());
+
+    checkRR("host3.example.org", RRType::A(), "192.0.2.1");
+    checkRR("host5.example.org", RRType::A(), "192.0.2.3");
+    checkRR("host7.example.org", RRType::A(), "192.0.2.5");
+    checkRR("host9.example.org", RRType::A(), "192.0.2.7");
+
+    checkRR("host0010.example.org", RRType::A(), "192.0.2.10");
+    checkRR("host0011.example.org", RRType::A(), "192.0.2.11");
+    checkRR("host0012.example.org", RRType::A(), "192.0.2.12");
+
+    checkRR("host0014.example.org", RRType::A(), "192.0.2.14");
+    checkRR("host0015.example.org", RRType::A(), "192.0.2.15");
+
+    checkRR("host001e.example.org", RRType::A(), "192.0.2.30");
+    checkRR("host001f.example.org", RRType::A(), "192.0.2.31");
+
+    checkRR("host42.example.org", RRType::TXT(), "Value 002A");
+    checkRR("host43.example.org", RRType::TXT(), "Value 002B");
+
+    checkRR("host0055.example.org", RRType::A(), "192.0.2.45");
+    checkRR("host0056.example.org", RRType::A(), "192.0.2.46");
+
+    checkRR("host0100.example.org", RRType::A(), "192.0.2.100");
+    checkRR("host0101.example.org", RRType::A(), "192.0.2.101");
+}
+
+TEST_F(MasterLoaderTest, generateWithNoModifiers) {
+    const string input =
+        "$ORIGIN example.org.\n"
+        "$TTL 3600\n"
+        "$GENERATE 10-12 host${} A 192.0.2.$\n";
+    stringstream ss(input);
+    setLoader(ss, Name("example.org."), RRClass::IN(),
+              MasterLoader::MANY_ERRORS);
+
+    loader_->load();
+    EXPECT_FALSE(loader_->loadedSucessfully());
+    ASSERT_EQ(2, errors_.size()); // For the broken GENERATE
+    EXPECT_TRUE(warnings_.empty());
+
+    checkCallbackMessage(errors_.at(0),
+                         "Invalid $GENERATE format modifiers", 3);
+    checkCallbackMessage(errors_.at(1),
+                         "$GENERATE error", 3);
+}
+
+TEST_F(MasterLoaderTest, generateWithBadModifiers) {
+    const string input =
+        "$ORIGIN example.org.\n"
+        "$TTL 3600\n"
+        "$GENERATE 10-12 host${GARBAGE} A 192.0.2.$\n";
+    stringstream ss(input);
+    setLoader(ss, Name("example.org."), RRClass::IN(),
+              MasterLoader::MANY_ERRORS);
+
+    loader_->load();
+    EXPECT_FALSE(loader_->loadedSucessfully());
+    ASSERT_EQ(2, errors_.size()); // For the broken GENERATE
+    EXPECT_TRUE(warnings_.empty());
+
+    checkCallbackMessage(errors_.at(0),
+                         "Invalid $GENERATE format modifiers", 3);
+    checkCallbackMessage(errors_.at(1),
+                         "$GENERATE error", 3);
+}
+
 TEST_F(MasterLoaderTest, generateMissingRange) {
     const string input =
         "$ORIGIN example.org.\n"



More information about the bind10-changes mailing list