24#include <boost/lexical_cast.hpp>
31const char*
const WHITESPACE =
" \b\f\n\r\t";
39 std::ostringstream ss;
196throwJSONError(
const std::string&
error,
const std::string& file,
int line,
198 std::stringstream ss;
199 ss <<
error <<
" in " + file +
":" << line <<
":" << pos;
206 return (out << e.
str());
252 return (
create(
static_cast<long long int>(i), pos));
257 return (
create(
static_cast<long long int>(i), pos));
262 return (
create(
static_cast<long long int>(i), pos));
282 return (
create(std::string(s), pos));
301charIn(
const int c,
const char* chars) {
302 const size_t chars_len = std::strlen(chars);
303 for (
size_t i = 0; i < chars_len; ++i) {
312skipChars(std::istream& in,
const char* chars,
int& line,
int& pos) {
314 while (charIn(c, chars) && c != EOF) {
332skipTo(std::istream& in,
const std::string& file,
int& line,
int& pos,
333 const char* chars,
const char* may_skip=
"") {
341 if (charIn(c, may_skip)) {
344 }
else if (charIn(c, chars)) {
345 while (charIn(in.peek(), may_skip)) {
346 if (in.peek() ==
'\n') {
356 throwJSONError(std::string(
"'") + std::string(1, c) +
"' read, one of \"" + chars +
"\" expected", file, line, pos);
359 throwJSONError(std::string(
"EOF read, one of \"") + chars +
"\" expected", file, line, pos);
366strFromStringstream(std::istream& in,
const std::string& file,
367 const int line,
int& pos) {
368 std::stringstream ss;
375 throwJSONError(
"String expected", file, line, pos);
378 while (c != EOF && c !=
'"') {
413 throwJSONError(
"Unsupported unicode escape", file, line, pos);
420 throwJSONError(
"Unsupported unicode escape", file, line, pos - 2);
426 if ((d >=
'0') && (d <=
'9')) {
428 }
else if ((d >=
'A') && (d <=
'F')) {
429 c = (d -
'A' + 10) << 4;
430 }
else if ((d >=
'a') && (d <=
'f')) {
431 c = (d -
'a' + 10) << 4;
433 throwJSONError(
"Not hexadecimal in unicode escape", file, line, pos - 3);
439 if ((d >=
'0') && (d <=
'9')) {
441 }
else if ((d >=
'A') && (d <=
'F')) {
443 }
else if ((d >=
'a') && (d <=
'f')) {
446 throwJSONError(
"Not hexadecimal in unicode escape", file, line, pos - 4);
450 throwJSONError(
"Bad escape", file, line, pos);
461 throwJSONError(
"Unterminated string", file, line, pos);
467wordFromStringstream(std::istream& in,
int& pos) {
468 std::stringstream ss;
469 while (isalpha(in.peek())) {
470 ss << (char) in.get();
472 pos += ss.str().size();
477numberFromStringstream(std::istream& in,
int& pos) {
478 std::stringstream ss;
479 while (isdigit(in.peek()) || in.peek() ==
'+' || in.peek() ==
'-' ||
480 in.peek() ==
'.' || in.peek() ==
'e' || in.peek() ==
'E') {
481 ss << (char) in.get();
483 pos += ss.str().size();
492fromStringstreamNumber(std::istream& in,
const std::string& file,
493 const int line,
int& pos) {
496 const uint32_t start_pos = pos;
498 const std::string number = numberFromStringstream(in, pos);
500 if (number.find_first_of(
".eE") < number.size()) {
503 Element::Position(file, line, start_pos)));
504 }
catch (
const boost::bad_lexical_cast&) {
505 throwJSONError(std::string(
"Number overflow: ") + number,
506 file, line, start_pos);
511 Element::Position(file, line, start_pos)));
512 }
catch (
const boost::bad_lexical_cast&) {
513 throwJSONError(std::string(
"Number overflow: ") + number, file,
521fromStringstreamBool(std::istream& in,
const std::string& file,
522 const int line,
int& pos) {
525 const uint32_t start_pos = pos;
527 const std::string word = wordFromStringstream(in, pos);
529 if (word ==
"true") {
532 }
else if (word ==
"false") {
536 throwJSONError(std::string(
"Bad boolean value: ") + word, file,
543fromStringstreamNull(std::istream& in,
const std::string& file,
544 const int line,
int& pos) {
547 const uint32_t start_pos = pos;
549 const std::string word = wordFromStringstream(in, pos);
550 if (word ==
"null") {
553 throwJSONError(std::string(
"Bad null value: ") + word, file,
560fromStringstreamString(std::istream& in,
const std::string& file,
int& line,
564 const uint32_t start_pos = pos;
566 const std::string string_value = strFromStringstream(in, file, line, pos);
572fromStringstreamList(std::istream& in,
const std::string& file,
int& line,
578 skipChars(in, WHITESPACE, line, pos);
579 while (c != EOF && c !=
']') {
580 if (in.peek() !=
']') {
582 list->add(cur_list_element);
583 c = skipTo(in, file, line, pos,
",]", WHITESPACE);
593fromStringstreamMap(std::istream& in,
const std::string& file,
int& line,
596 skipChars(in, WHITESPACE, line, pos);
599 throwJSONError(std::string(
"Unterminated map, <string> or } expected"), file, line, pos);
600 }
else if (c ==
'}') {
604 while (c != EOF && c !=
'}') {
605 std::string key = strFromStringstream(in, file, line, pos);
607 skipTo(in, file, line, pos,
":", WHITESPACE);
611 map->set(key, value);
613 c = skipTo(in, file, line, pos,
",}", WHITESPACE);
624 return (std::string(
"integer"));
626 return (std::string(
"real"));
628 return (std::string(
"boolean"));
630 return (std::string(
"string"));
632 return (std::string(
"list"));
634 return (std::string(
"map"));
636 return (std::string(
"null"));
638 return (std::string(
"any"));
640 return (std::string(
"unknown"));
646 if (type_name ==
"integer") {
648 }
else if (type_name ==
"real") {
650 }
else if (type_name ==
"boolean") {
652 }
else if (type_name ==
"string") {
654 }
else if (type_name ==
"list") {
656 }
else if (type_name ==
"map") {
658 }
else if (type_name ==
"named_set") {
660 }
else if (type_name ==
"null") {
662 }
else if (type_name ==
"any") {
672 int line = 1, pos = 1;
673 stringstream filtered;
685 int line = 1, pos = 1;
686 stringstream filtered;
690 return (
fromJSON(preproc ? filtered : in, file_name, line, pos));
698 bool el_read =
false;
699 skipChars(in, WHITESPACE, line, pos);
700 while (c != EOF && !el_read) {
719 element = fromStringstreamNumber(in, file, line, pos);
726 element = fromStringstreamBool(in, file, line, pos);
732 element = fromStringstreamNull(in, file, line, pos);
738 element = fromStringstreamString(in, file, line, pos);
742 element = fromStringstreamList(in, file, line, pos);
746 element = fromStringstreamMap(in, file, line, pos);
752 throwJSONError(std::string(
"error: unexpected character ") + std::string(1, c), file, line, pos);
765 std::stringstream ss;
768 int line = 1, pos = 1;
769 stringstream filtered;
774 skipChars(ss, WHITESPACE, line, pos);
776 if (ss.peek() != EOF) {
777 throwJSONError(
"Extra data",
"<string>", line, pos);
787 std::ifstream infile(file_name.c_str(), std::ios::in | std::ios::binary);
788 if (!infile.is_open()) {
789 const char*
error = strerror(errno);
794 return (
fromJSON(infile, file_name, preproc));
812 ostringstream val_ss;
815 if (val_ss.str().find_first_of(
'.') == string::npos) {
838 for (
size_t i = 0; i <
str.size(); ++i) {
839 const char c =
str[i];
866 if (((c >= 0) && (c < 0x20)) || (c < 0) || (c >= 0x7f)) {
867 std::ostringstream esc;
872 << (
static_cast<unsigned>(c) & 0xff);
886 const std::vector<ElementPtr>& v =
listValue();
887 for (
auto it = v.begin(); it != v.end(); ++it) {
888 if (it != v.begin()) {
900 const std::map<std::string, ConstElementPtr>& m =
mapValue();
901 for (
auto it = m.begin(); it != m.end(); ++it) {
902 if (it != m.begin()) {
905 ss <<
"\"" << (*it).first <<
"\": ";
907 (*it).second->toJSON(ss);
921 const size_t sep =
id.find(
'/');
922 if (sep == std::string::npos) {
928 if (sep + 1 !=
id.
size()) {
929 return (ce->find(
id.substr(sep + 1)));
941 std::stringstream ss;
943 int line = 0, pos = 0;
944 return (
fromJSON(ss,
"<wire>", line, pos));
959 int line = 0, pos = 0;
960 return (
fromJSON(in,
"<wire>", line, pos));
1014 const size_t s =
size();
1015 if (s != other.
size()) {
1018 for (
size_t i = 0; i < s; ++i) {
1035 int const t(l.at(0)->getType());
1038 if (index.empty()) {
1049 }
else if (t ==
list) {
1054 if (!index.empty()) {
1062 std::sort(l.begin(), l.end(), comparator);
1072 auto key = kv.first;
1105 for (
auto kv : b->mapValue()) {
1106 auto key = kv.first;
1107 if (a->contains(key)) {
1108 if (a->get(key)->equals(*b->get(key))) {
1127 for (
auto kv : a->mapValue()) {
1128 auto key = kv.first;
1129 if (!b->contains(key) ||
1130 !a->get(key)->equals(*b->get(key))) {
1131 result->set(key, kv.second);
1145 for (
auto kv : other->mapValue()) {
1146 auto key = kv.first;
1147 auto value = kv.second;
1149 element->set(key, value);
1150 }
else if (element->contains(key)) {
1151 element->remove(key);
1159 if (element->getType() != other->getType()) {
1167 for (
auto& right : other->listValue()) {
1170 auto f = hierarchy[idx].find(key);
1171 if (f != hierarchy[idx].end()) {
1173 ElementPtr mutable_right = boost::const_pointer_cast<Element>(right);
1174 for (
auto& left : element->listValue()) {
1175 ElementPtr mutable_left = boost::const_pointer_cast<Element>(left);
1178 if (f->second.match_(mutable_left, mutable_right)) {
1180 mergeDiffAdd(mutable_left, mutable_right, hierarchy, key, idx);
1184 new_elements->add(right);
1187 new_elements->add(right);
1191 for (
auto& right : new_elements->listValue()) {
1192 element->add(right);
1198 for (
auto kv : other->mapValue()) {
1199 auto current_key = kv.first;
1200 auto value = boost::const_pointer_cast<Element>(kv.second);
1202 if (element->contains(current_key) &&
1205 ElementPtr mutable_element = boost::const_pointer_cast<Element>(element->get(current_key));
1206 mergeDiffAdd(mutable_element, value, hierarchy, current_key, idx + 1);
1208 element->set(current_key, value);
1220 if (element->getType() != other->getType()) {
1225 for (
auto const& value : other->listValue()) {
1226 ElementPtr mutable_right = boost::const_pointer_cast<Element>(value);
1227 for (uint32_t iter = 0; iter < element->listValue().
size();) {
1228 bool removed =
false;
1231 auto f = hierarchy[idx].find(key);
1232 if (f != hierarchy[idx].end()) {
1233 ElementPtr mutable_left = boost::const_pointer_cast<Element>(element->listValue().at(iter));
1236 if (f->second.match_(mutable_left, mutable_right)) {
1240 if (f->second.no_data_(mutable_right)) {
1241 element->remove(iter);
1244 mergeDiffDel(mutable_left, mutable_right, hierarchy, key, idx);
1245 if (mutable_left->empty()) {
1246 element->remove(iter);
1251 }
else if (element->listValue().at(iter)->equals(*value)) {
1252 element->remove(iter);
1267 for (
auto kv : other->mapValue()) {
1268 auto current_key = kv.first;
1269 auto value = boost::const_pointer_cast<Element>(kv.second);
1271 if (element->contains(current_key)) {
1272 ElementPtr mutable_element = boost::const_pointer_cast<Element>(element->get(current_key));
1275 mergeDiffDel(mutable_element, value, hierarchy, current_key, idx + 1);
1276 if (mutable_element->empty()) {
1277 element->remove(current_key);
1282 auto f = hierarchy[idx].find(key);
1283 if (f != hierarchy[idx].end()) {
1286 if (f->second.is_key_(current_key)) {
1288 new_elements->set(current_key, mutable_element);
1291 element->remove(current_key);
1297 if (element->size()) {
1298 for (
auto kv : new_elements->mapValue()) {
1299 element->set(kv.first, kv.second);
1308extend(
const std::string& container,
const std::string& extension,
1310 std::string key,
size_t idx,
bool alter) {
1311 if (element->getType() != other->getType()) {
1316 for (
auto& right : other->listValue()) {
1319 auto f = hierarchy[idx].find(key);
1320 if (f != hierarchy[idx].end()) {
1321 ElementPtr mutable_right = boost::const_pointer_cast<Element>(right);
1322 for (
auto& left : element->listValue()) {
1323 ElementPtr mutable_left = boost::const_pointer_cast<Element>(left);
1324 if (container == key) {
1327 if (f->second.match_(mutable_left, mutable_right)) {
1328 extend(container, extension, mutable_left, mutable_right,
1329 hierarchy, key, idx, alter);
1338 for (
auto kv : other->mapValue()) {
1339 auto current_key = kv.first;
1340 auto value = boost::const_pointer_cast<Element>(kv.second);
1342 if (element->contains(current_key) &&
1345 ElementPtr mutable_element = boost::const_pointer_cast<Element>(element->get(current_key));
1346 if (container == key) {
1349 extend(container, extension, mutable_element, value, hierarchy, current_key, idx + 1, alter);
1350 }
else if (alter && current_key == extension) {
1351 element->set(current_key, value);
1364 int from_type = from->getType();
1377 for (
auto elem : from->listValue()) {
1381 result->add(
copy(elem, level - 1));
1387 for (
auto kv : from->mapValue()) {
1388 auto key = kv.first;
1389 auto value = kv.second;
1391 result->set(key, value);
1393 result->set(key,
copy(value, level - 1));
1410 "arguments include cycles");
1413 isc_throw(BadValue,
"isEquivalent got a null pointer");
1416 if (a->getType() != b->getType()) {
1422 return (b->empty());
1425 if (a->size() != b->size()) {
1430 const size_t s = a->size();
1431 std::list<ConstElementPtr> l;
1432 for (
size_t i = 0; i < s; ++i) {
1433 l.push_back(b->get(i));
1437 for (
size_t i = 0; i < s; ++i) {
1441 for (
auto it = l.begin(); it != l.end(); ++it) {
1443 if (isEquivalent0(item, *it, level - 1)) {
1457 isc_throw(Unexpected,
"isEquivalent internal error");
1462 if (a->size() != b->size()) {
1466 for (
auto kv : a->mapValue()) {
1469 if (!item || !isEquivalent0(kv.second, item, level - 1)) {
1475 return (a->equals(*b));
1483 return (isEquivalent0(a, b, 100));
1488 unsigned indent,
unsigned step) {
1494 if (element->empty()) {
1500 if (!element->get(0)) {
1503 int first_type = element->get(0)->getType();
1504 bool complex =
false;
1508 std::string separator = complex ?
",\n" :
", ";
1511 out <<
"[" << (complex ?
"\n" :
" ");
1514 const auto& l = element->listValue();
1515 for (
auto it = l.begin(); it != l.end(); ++it) {
1517 if (it != l.begin()) {
1522 out << std::string(indent + step,
' ');
1530 out <<
"\n" << std::string(indent,
' ');
1537 if (element->size() == 0) {
1546 const auto& m = element->mapValue();
1548 for (
auto it = m.begin(); it != m.end(); ++it) {
1556 out << std::string(indent + step,
' ');
1558 out <<
"\"" << it->first <<
"\": ";
1560 prettyPrint(it->second, out, indent + step, step);
1564 out <<
"\n" << std::string(indent,
' ') <<
"}";
1567 element->toJSON(out);
1573 std::stringstream ss;
1582 while (std::getline(in, line)) {
1585 if (!line.empty() && line[0] ==
'#') {
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown if a function is called in a prohibited way.
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
bool equals(const Element &other) const
bool equals(const Element &other) const
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
The Element class represents a piece of data, used by the command channel and configuration parts.
static ElementPtr create(const Position &pos=ZERO_POSITION())
virtual bool equals(const Element &other) const =0
virtual bool getValue(int64_t &t) const
static std::string typeToName(Element::types type)
Returns the name of the given type as a string.
virtual int64_t intValue() const
std::string str() const
Returns a string representing the Element and all its child elements; note that this is different fro...
virtual std::string stringValue() const
std::string toWire() const
Returns the wireformat for the Element and all its child elements.
static ElementPtr fromWire(std::stringstream &in, int length)
These function pparse the wireformat at the given stringstream (of the given length).
virtual bool setValue(const long long int v)
static ElementPtr fromJSONFile(const std::string &file_name, bool preproc=false)
Reads contents of specified file and interprets it as JSON.
virtual bool empty() const
Return true if there are no elements in the list.
virtual void remove(const int i)
Removes the element at the given position.
virtual bool contains(const std::string &name) const
Checks if there is data at the given key.
virtual ConstElementPtr find(const std::string &identifier) const
Recursively finds any data at the given identifier.
virtual size_t size() const
Returns the number of elements in the list.
virtual const std::map< std::string, ConstElementPtr > & mapValue() const
virtual void add(ElementPtr element)
Adds an ElementPtr to the list.
virtual const std::vector< ElementPtr > & listValue() const
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
virtual ConstElementPtr get(const int i) const
Returns the ElementPtr at the given index.
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
static Element::types nameToType(const std::string &type_name)
Converts the string to the corresponding type Throws a TypeError if the name is unknown.
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
virtual void toJSON(std::ostream &ss) const =0
Converts the Element to JSON format and appends it to the given stringstream.
virtual void set(const size_t i, ElementPtr element)
Sets the ElementPtr at the given index.
virtual double doubleValue() const
virtual bool boolValue() const
static void preprocess(std::istream &in, std::stringstream &out)
input text preprocessor
virtual ElementPtr getNonConst(const int i) const
returns element as non-const pointer
Notes: IntElement type is changed to int64_t.
bool equals(const Element &other) const
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
void sort(std::string const &index=std::string())
Sorts the elements inside the list.
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
bool equals(const Element &other) const
ConstElementPtr find(const std::string &id) const override
Recursively finds any data at the given identifier.
void set(const std::string &key, ConstElementPtr value) override
Sets the ElementPtr at the given key.
bool equals(const Element &other) const override
void toJSON(std::ostream &ss) const override
Converts the Element to JSON format and appends it to the given stringstream.
bool equals(const Element &other) const
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
void toJSON(std::ostream &ss) const
Converts the Element to JSON format and appends it to the given stringstream.
bool equals(const Element &other) const
A standard Data module exception that is thrown if a function is called for an Element that has a wro...
#define throwTypeError(error)
Add the position to a TypeError message should be used in place of isc_throw(TypeError,...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
bool operator==(const Element &a, const Element &b)
void mergeDiffAdd(ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx)
Merges the diff data by adding the missing elements from 'other' to 'element' (recursively).
void removeIdentical(ElementPtr a, ConstElementPtr b)
Remove all values from the first ElementPtr that are equal in the second.
void merge(ElementPtr element, ConstElementPtr other)
Merges the data from other into element.
void mergeDiffDel(ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx)
Merges the diff data by removing the data present in 'other' from 'element' (recursively).
bool operator<(Element const &a, Element const &b)
bool isEquivalent(ConstElementPtr a, ConstElementPtr b)
Compares the data with other using unordered lists.
void prettyPrint(ConstElementPtr element, std::ostream &out, unsigned indent, unsigned step)
Pretty prints the data into stream.
boost::shared_ptr< const Element > ConstElementPtr
void extend(const std::string &container, const std::string &extension, ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx, bool alter)
Extends data by adding the specified 'extension' elements from 'other' inside the 'container' element...
bool isNull(ConstElementPtr p)
Checks whether the given ElementPtr is a NULL pointer.
std::ostream & operator<<(std::ostream &out, const Element::Position &pos)
Insert Element::Position as a string into stream.
bool operator!=(const Element &a, const Element &b)
boost::shared_ptr< Element > ElementPtr
std::vector< FunctionMap > HierarchyDescriptor
Hierarchy descriptor of the containers in a specific Element hierarchy tree.
Defines the logger used by the top-level component of kea-lfc.
Represents the position of the data element within a configuration string.
uint32_t pos_
Position within the line.
std::string str() const
Returns the position in the textual format.
uint32_t line_
Line number.
std::string file_
File name.