18 #include <boost/format.hpp>
19 #include <boost/algorithm/string/predicate.hpp>
20 #include <boost/scoped_ptr.hpp>
21 #include <boost/shared_ptr.hpp>
30 using std::unique_ptr;
33 using boost::algorithm::iequals;
34 using boost::shared_ptr;
46 InternalException(
const char* filename,
size_t line,
const char* what) :
47 Exception(filename, line, what)
82 const Name& zone_origin,
88 zone_origin_(zone_origin),
89 active_origin_(zone_origin),
90 zone_class_(zone_class),
91 callbacks_(callbacks),
92 add_callback_(add_callback),
94 master_file_(master_file),
98 previous_name_(false),
117 if (!lexer_.
pushSource(filename.c_str(), &error)) {
119 isc_throw(InternalException, error.c_str());
122 reportError(
"", 0, error);
127 include_info_.push_back(IncludeInfo(current_origin, last_name_));
129 previous_name_ =
false;
161 void reportError(
const std::string& filename,
size_t line,
162 const std::string& reason)
165 callbacks_.
error(filename, line, reason);
190 assert(!include_info_.empty());
191 const IncludeInfo& info(include_info_.back());
192 active_origin_ = info.first;
193 last_name_ = info.second;
194 include_info_.pop_back();
195 previous_name_ =
false;
200 const string getString() {
202 return (string_token_);
219 MasterToken handleInitialToken();
228 std::string generateForIter(
const std::string& str,
const int it);
236 void doOrigin(
bool is_optional) {
245 const MasterToken::StringRegion&
246 name_string(name_tok.getStringRegion());
247 active_origin_ = Name(name_string.beg, name_string.len,
249 if (name_string.len > 0 &&
250 name_string.beg[name_string.len - 1] !=
'.') {
253 "The new origin is relative, did you really"
254 " mean " + active_origin_.
toText() +
"?");
283 const Name current_origin = active_origin_;
299 RRType parseRRParams(
bool& explicit_ttl, MasterToken rrparam_token) {
309 if (setCurrentTTL(rrparam_token.getString())) {
317 boost::scoped_ptr<RRClass> rrclass
320 if (*rrclass != zone_class_) {
321 isc_throw(InternalException,
"Class mismatch: " << *rrclass <<
322 " vs. " << zone_class_);
329 if (!explicit_ttl && setCurrentTTL(rrparam_token.getString())) {
335 return (RRType(rrparam_token.getString()));
357 void limitTTL(RRTTL& ttl,
bool post_parsing) {
360 (post_parsing ? 1 : 0);
362 "TTL " + ttl.toText() +
" > MAXTTL, "
363 "setting to 0 per RFC2181");
373 void setDefaultTTL(
const RRTTL& ttl,
bool post_parsing) {
374 assignTTL(default_ttl_, ttl);
375 limitTTL(*default_ttl_, post_parsing);
387 bool setCurrentTTL(
const string& ttl_txt) {
393 current_ttl_.reset(rrttl);
394 limitTTL(*current_ttl_,
false);
409 const RRTTL& getCurrentTTL(
bool explicit_ttl,
const RRType& rrtype,
416 if (!current_ttl_ && !default_ttl_) {
420 "using SOA MINTTL instead");
421 const uint32_t ttl_val =
422 dynamic_cast<const rdata::generic::SOA&
>(*rdata).
424 setDefaultTTL(RRTTL(ttl_val),
true);
425 assignTTL(current_ttl_, *default_ttl_);
430 throw InternalException(__FILE__, __LINE__,
431 "no TTL specified; load rejected");
433 }
else if (!explicit_ttl && default_ttl_) {
434 assignTTL(current_ttl_, *default_ttl_);
439 "using RFC1035 TTL semantics; default to the "
440 "last explicitly stated TTL");
443 assert(current_ttl_);
444 return (*current_ttl_);
451 void handleDirective(
const char* directive,
size_t length) {
452 if (iequals(directive,
"INCLUDE")) {
454 }
else if (iequals(directive,
"ORIGIN")) {
457 }
else if (iequals(directive,
"GENERATE")) {
460 }
else if (iequals(directive,
"TTL")) {
461 setDefaultTTL(RRTTL(getString()),
false);
464 isc_throw(InternalException,
"Unknown directive '" <<
465 string(directive, directive + length) <<
"'");
470 void eatUntilEOL(
bool reportExtra) {
474 switch (token.getType()) {
478 "File does not end with newline");
492 "Extra tokens at the end of line");
502 static void assignTTL(boost::scoped_ptr<RRTTL>& left,
const RRTTL& right) {
504 left.reset(
new RRTTL(right));
512 const Name zone_origin_;
515 shared_ptr<Name> last_name_;
516 const RRClass zone_class_;
517 MasterLoaderCallbacks callbacks_;
519 boost::scoped_ptr<RRTTL> default_ttl_;
522 boost::scoped_ptr<RRTTL> current_ttl_;
527 const std::string master_file_;
528 std::string string_token_;
531 const bool many_errors_;
536 typedef pair<Name, shared_ptr<Name> > IncludeInfo;
537 vector<IncludeInfo> include_info_;
605 genNibbles(
int num,
unsigned int width,
bool uppercase) {
606 static const char *hex =
"0123456789abcdef0123456789ABCDEF";
610 char ch = hex[(num & 0x0f) + (
uppercase ? 16 : 0)];
621 if (width > 0 || num != 0) {
628 }
while ((num != 0) || (width > 0));
636 MasterLoader::MasterLoaderImpl::generateForIter(
const std::string& str,
641 for (std::string::const_iterator it = str.begin(); it != str.end();) {
648 if ((it != str.end()) && (*it ==
'$')) {
655 if ((it == str.end()) || (*it !=
'{')) {
662 const char* scan_str =
663 str.c_str() + std::distance(str.begin(), it);
666 char base[2] = {
'd', 0};
668 const int n = sscanf(scan_str,
"{%d,%u,%1[doxXnN]}",
669 &offset, &width, base);
681 const std::string fmt =
689 if ((base[0] ==
'n') || (base[0] ==
'N')) {
692 rstr += genNibbles(num + offset, width, (base[0] ==
'N'));
697 const std::string fmt =
706 "Invalid $GENERATE format modifiers");
712 while ((it != str.end()) && (*it !=
'}')) {
716 if (it != str.end()) {
729 if (it == str.end()) {
750 MasterLoader::MasterLoaderImpl::doGenerate() {
754 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
755 "Invalid $GENERATE syntax");
758 const std::string range = range_token.getString();
763 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
764 "Invalid $GENERATE syntax");
767 const std::string lhs = lhs_token.getString();
779 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
780 "Invalid $GENERATE syntax");
784 bool explicit_ttl =
false;
785 const RRType rrtype = parseRRParams(explicit_ttl, param_token);
792 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
793 "Invalid $GENERATE syntax");
796 const std::string rhs = rhs_token.getString();
805 const int n = sscanf(range.c_str(),
"%u-%u/%u", &start, &stop, &step);
806 if ((n < 2) || (stop < start)) {
807 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
808 "$GENERATE: invalid range: " + range);
817 for (
unsigned int i = start; i <= stop; i += step) {
820 const std::string generated_name = generateForIter(lhs, i);
821 const std::string generated_rdata = generateForIter(rhs, i);
822 if (generated_name.empty() || generated_rdata.empty()) {
825 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
836 (
new Name(Name(generated_name).concatenate(active_origin_)));
837 previous_name_ =
true;
845 add_callback_(*last_name_, zone_class_, rrtype,
846 getCurrentTTL(explicit_ttl, rrtype, rdata),
857 isc_throw(MasterLoaderError,
"Invalid RR data");
864 MasterLoader::MasterLoaderImpl::handleInitialToken() {
865 const MasterToken& initial_token =
871 const MasterToken& next_token = lexer_.getNextToken();
881 if (last_name_.get() == NULL) {
882 isc_throw(InternalException,
"No previous name to use in "
883 "place of initial whitespace");
884 }
else if (!previous_name_) {
885 callbacks_.warning(lexer_.getSourceName(), lexer_.getSourceLine(),
886 "Owner name omitted around $INCLUDE, the result "
887 "might not be as expected");
893 const MasterToken::StringRegion&
894 name_string(initial_token.getStringRegion());
896 if (name_string.len > 0 && name_string.beg[0] ==
'$') {
902 handleDirective(name_string.beg + 1, name_string.len - 1);
910 last_name_.reset(
new Name(name_string.beg, name_string.len,
912 previous_name_ =
true;
916 switch (initial_token.getType()) {
919 return (initial_token);
928 return (initial_token);
931 isc_throw(InternalException, initial_token.getErrorText());
934 isc_throw(InternalException,
"Parser got confused (unexpected "
935 "token " << initial_token.getType() <<
")");
941 if (count_limit == 0) {
946 "Trying to load when already loaded");
949 pushSource(master_file_, active_origin_);
952 while (ok_ && count < count_limit) {
954 const MasterToken next_token = handleInitialToken();
964 bool explicit_ttl =
false;
965 const RRType rrtype = parseRRParams(explicit_ttl, next_token);
970 &active_origin_, options_, callbacks_);
977 add_callback_(*last_name_, zone_class_, rrtype,
978 getCurrentTTL(explicit_ttl, rrtype, rdata),
994 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
998 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
1002 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
1005 }
catch (
const InternalException& e) {
1006 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
1016 const Name& zone_origin,
1022 if (add_callback.empty()) {
1026 zone_class, callbacks, add_callback, options);
1030 const Name& zone_origin,
1036 if (add_callback.empty()) {
1039 unique_ptr<MasterLoaderImpl>
1041 callbacks, add_callback, options));
1042 impl->pushStreamSource(stream);
1043 impl_ =
impl.release();