void
MasterLoader::MasterLoaderImpl::doGenerate() {
+ // Parse the range token
const MasterToken& range_token = lexer_.getNextToken(MasterToken::STRING);
if (range_token.getType() != MasterToken::STRING) {
reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
}
const std::string range = range_token.getString();
+ // Parse the LHS token
const MasterToken& lhs_token = lexer_.getNextToken(MasterToken::STRING);
if (lhs_token.getType() != MasterToken::STRING) {
reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
}
const std::string lhs = lhs_token.getString();
+ // Parse the TTL, RR class and RR type tokens. Note that TTL and RR
+ // class may come in any order and may be missing. If TTL is
+ // missing, we expect that it was either specified explicitly using
+ // $TTL, or is implicitly known from a previous RR, or that this is
+ // the SOA RR from which the MINIMUM field is used. It's unlikely
+ // that $GENERATE will be used with an SOA RR, but it's
+ // possible. The parsing happens within the parseRRParams() helper
+ // method which is called below.
const MasterToken& param_token = lexer_.getNextToken(MasterToken::STRING);
if (param_token.getType() != MasterToken::STRING) {
reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
"Invalid $GENERATE syntax");
return;
}
+
bool explicit_ttl = false;
const RRType rrtype = parseRRParams(explicit_ttl, param_token);
+ // Parse the RHS token. It can be a quoted string.
const MasterToken& rhs_token = lexer_.getNextToken(MasterToken::QSTRING);
if ((rhs_token.getType() != MasterToken::QSTRING) &&
(rhs_token.getType() != MasterToken::STRING))
}
const std::string rhs = rhs_token.getString();
+ // Range can be one of two forms: start-stop or start-stop/step. If
+ // the first form is used, then step is set to 1. All of start, stop
+ // and step must be positive.
unsigned int start;
unsigned int stop;
unsigned int step;
-
const int n = sscanf(range.c_str(), "%u-%u/%u", &start, &stop, &step);
if ((n < 2) || (stop < start)) {
reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
step = 1;
}
+ // Generate and add the records.
for (int i = start; i <= stop; i += step) {
+ // Get generated strings for LHS and RHS. LHS goes to form the
+ // name, RHS goes to form the RDATA of the RR.
const std::string generated_name = generateForIter(lhs, i);
const std::string generated_rdata = generateForIter(rhs, i);
if (generated_name.empty() || generated_rdata.empty()) {
// generateForIter() can return a string with a trailing '.' in
// case of a nibble representation. So we cannot use the
- // relative Name constructor.
+ // relative Name constructor. We use concatenate() which is
+ // expensive, but keeps the generated LHS-based Name within the
+ // active origin.
last_name_.reset
(new Name(Name(generated_name).concatenate(active_origin_)));
previous_name_ = true;