24 #ifndef __CONFIG_YAML_NODE_H_ 25 #define __CONFIG_YAML_NODE_H_ 27 #ifndef __CONFIG_YAML_H_ 28 # error Do not include yaml_node.h directly 31 #include <utils/misc/string_conversions.h> 32 #include <utils/misc/string_split.h> 40 #include <yaml-cpp/traits.h> 43 #ifndef HAVE_YAMLCPP_0_5 44 # ifdef HAVE_YAMLCPP_ATLEAST_0_3 48 namespace conversion {
49 using YAML::IsInfinity;
50 using YAML::IsNegativeInfinity;
57 namespace conversion {
58 inline bool IsInfinity(
const std::string& input) {
59 return input ==
".inf" || input ==
".Inf" || input ==
".INF" || input ==
"+.inf" || input ==
"+.Inf" || input ==
"+.INF";
62 inline bool IsNegativeInfinity(
const std::string& input) {
63 return input ==
"-.inf" || input ==
"-.Inf" || input ==
"-.INF";
66 inline bool IsNaN(
const std::string& input) {
67 return input ==
".nan" || input ==
".NaN" || input ==
".NAN";
78 namespace yaml_utils {
82 inline bool IsLower(
char ch) {
return 'a' <= ch && ch <=
'z'; }
83 inline bool IsUpper(
char ch) {
return 'A' <= ch && ch <=
'Z'; }
84 inline char ToLower(
char ch) {
return IsUpper(ch) ? ch +
'a' -
'A' : ch; }
86 inline std::string tolower(
const std::string& str)
89 std::transform(s.begin(), s.end(), s.begin(), ToLower);
94 inline bool IsEntirely(
const std::string& str, T func)
96 for(std::size_t i=0;i<str.size();i++)
108 inline bool IsFlexibleCase(
const std::string& str)
113 if(IsEntirely(str, IsLower))
116 bool firstcaps = IsUpper(str[0]);
117 std::string rest = str.substr(1);
118 return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper));
122 inline bool convert(
const std::string& input, std::string& output) {
127 inline bool convert(
const std::string& input,
bool& output)
132 static const struct {
133 std::string truename, falsename;
141 if(! detail::IsFlexibleCase(input))
144 for(
unsigned i=0;i<
sizeof(names)/
sizeof(names[0]);i++) {
145 if(names[i].truename == detail::tolower(input)) {
150 if(names[i].falsename == detail::tolower(input)) {
160 convert(
const std::string& input, YAML::_Null& output)
162 return input.empty() || input ==
"~" || input ==
"null" || input ==
"Null" || input ==
"NULL";
165 inline bool convert(
const std::string &input,
unsigned int &rhs)
169 long int l = strtol(input.c_str(), &endptr, 0);
171 if ((errno == ERANGE && (l == LONG_MAX || l == LONG_MIN)) || (errno != 0 && l == 0)) {
174 if (endptr == input.c_str())
return false;
175 if (*endptr != 0)
return false;
176 if (l < 0)
return false;
178 rhs = (
unsigned int)l;
184 template <
typename T>
185 inline bool convert(
const std::string &input, T &rhs,
186 typename YAML::enable_if<YAML::is_numeric<T> >::type * = 0)
188 std::stringstream stream(input);
189 stream.unsetf(std::ios::dec);
190 if((stream >> rhs) && (stream >> std::ws).eof())
194 if(std::numeric_limits<T>::has_infinity) {
195 if(YAML::conversion::IsInfinity(input) || YAML::conversion::IsNegativeInfinity(input) )
197 rhs = std::numeric_limits<T>::infinity();
202 if(std::numeric_limits<T>::has_quiet_NaN && YAML::conversion::IsNaN(input)) {
203 rhs = std::numeric_limits<T>::quiet_NaN();
211 class YamlConfigurationNode
215 enum value { NONE, UINT32, INT32, FLOAT, BOOL, STRING, MAP, SEQUENCE, UNKNOWN };
216 static const char * to_string(value v) {
218 case NONE:
return "NONE";
219 case UINT32:
return "unsigned int";
220 case INT32:
return "int";
221 case FLOAT:
return "float";
222 case BOOL:
return "bool";
223 case STRING:
return "string";
224 case SEQUENCE:
return "SEQUENCE";
225 case MAP:
return "MAP";
226 default:
return "UNKNOWN";
231 YamlConfigurationNode() : name_(
"root"), type_(Type::UNKNOWN), is_default_(false) {}
233 YamlConfigurationNode(
const YamlConfigurationNode &n)
234 : name_(n.name_), type_(n.type_), scalar_value_(n.scalar_value_),
235 list_values_(n.list_values_), is_default_(n.is_default_)
238 YamlConfigurationNode(
const YamlConfigurationNode *n)
239 : name_(n->name_), type_(n->type_), scalar_value_(n->scalar_value_),
240 list_values_(n->list_values_), is_default_(n->is_default_)
243 YamlConfigurationNode(std::string name,
const YAML::Node &node)
244 : name_(name), type_(Type::UNKNOWN), is_default_(false)
246 #ifdef HAVE_YAMLCPP_0_5 247 scalar_value_ = node.Scalar();
249 node.GetScalar(scalar_value_);
251 switch (node.Type()) {
252 case YAML::NodeType::Null: type_ = Type::NONE;
break;
253 case YAML::NodeType::Scalar: type_ = determine_scalar_type();
break;
254 case YAML::NodeType::Sequence: type_ = Type::SEQUENCE; set_sequence(node);
break;
255 case YAML::NodeType::Map: type_ = Type::MAP;
break;
257 type_ = Type::UNKNOWN;
break;
262 YamlConfigurationNode(std::string name)
263 : name_(name), type_(Type::NONE), is_default_(false) {}
265 ~YamlConfigurationNode()
267 std::map<std::string, YamlConfigurationNode *>::iterator i;
268 for (i = children_.begin(); i != children_.end(); ++i) {
273 void add_child(std::string &p, YamlConfigurationNode *n) {
278 std::map<std::string, YamlConfigurationNode *>::iterator begin()
279 {
return children_.begin(); }
281 std::map<std::string, YamlConfigurationNode *>::iterator end()
282 {
return children_.end(); }
284 std::map<std::string, YamlConfigurationNode *>::size_type size()
const 285 {
return children_.size(); }
288 std::map<std::string, YamlConfigurationNode *>::const_iterator begin()
const 289 {
return children_.begin(); }
291 std::map<std::string, YamlConfigurationNode *>::const_iterator end()
const 292 {
return children_.end(); }
294 YamlConfigurationNode * find(std::queue<std::string> &q)
297 YamlConfigurationNode *n =
this;
300 while (! q.empty()) {
301 std::string pel = q.front();
305 if (n->children_.find(pel) == n->children_.end()) {
306 throw ConfigEntryNotFoundException(path.c_str());
308 n = n->children_[pel];
316 YamlConfigurationNode * find_or_insert(
const char *path)
318 std::queue<std::string> q = str_split_to_queue(path);
320 YamlConfigurationNode *n =
this;
321 while (! q.empty()) {
322 std::string pel = q.front();
323 if (n->children_.find(pel) == n->children_.end()) {
324 n->add_child(pel,
new YamlConfigurationNode(pel));
326 n = n->children_[pel];
333 void erase(
const char *path)
335 std::queue<std::string> q = str_split_to_queue(path);
336 std::stack<YamlConfigurationNode *> qs;
337 std::string full_path;
339 YamlConfigurationNode *n =
this;
340 while (! q.empty()) {
342 std::string pel = q.front();
343 full_path +=
"/" + pel;
345 if (n->children_.find(pel) == n->children_.end()) {
346 throw ConfigEntryNotFoundException(full_path.c_str());
349 n = n->children_[pel];
354 if (n->has_children()) {
355 throw Exception(
"YamlConfig: cannot erase non-leaf value");
358 YamlConfigurationNode *child = n;
359 while (! qs.empty()) {
360 YamlConfigurationNode *en = qs.top();
362 en->children_.erase(child->name());
365 if (en->has_children()) {
376 YamlConfigurationNode * find(
const char *path)
379 std::queue<std::string> pel_q = str_split_to_queue(path);
381 }
catch (Exception &e) {
386 void operator=(
const YamlConfigurationNode &n)
390 children_ = n.children_;
391 list_values_ = n.list_values_;
394 bool operator< (
const YamlConfigurationNode &n)
const 395 {
return this->name_ < n.name_; }
397 YamlConfigurationNode * operator[] (
const std::string &p)
399 std::map<std::string, YamlConfigurationNode *>::iterator i;
400 if ((i = children_.find(p)) != children_.end()) {
407 YamlConfigurationNode & operator+= (
const YamlConfigurationNode *n)
409 if (! n)
return *
this;
411 YamlConfigurationNode *add_to =
this;
413 if (n->name() !=
"root") {
414 std::map<std::string, YamlConfigurationNode *>::iterator i;
415 if ((i = children_.find(n->name())) == children_.end()) {
416 children_[n->name()] =
new YamlConfigurationNode(n);
418 add_to = children_[n->name()];
421 if (add_to->is_scalar()) {
422 if (! n->is_scalar()) {
423 throw Exception(
"YamlConfig: cannot overwrite scalar value %s with non-scalar",
424 add_to->name().c_str());
426 add_to->set_scalar(n->get_scalar());
429 std::map<std::string, YamlConfigurationNode *>::const_iterator i;
430 for (i = n->begin(); i != n->end(); ++i) {
431 *add_to += i->second;
438 bool operator==(
const YamlConfigurationNode &n)
const 440 return (name_ == n.name_) && (type_ == n.type_) && (scalar_value_ == n.scalar_value_);
443 bool operator!=(
const YamlConfigurationNode &n)
const 445 return (name_ != n.name_) || (type_ != n.type_) || (scalar_value_ != n.scalar_value_);
457 static std::list<std::string> diff(
const YamlConfigurationNode *a,
const YamlConfigurationNode *b)
459 std::list<std::string> rv;
461 std::map<std::string, YamlConfigurationNode *> na, nb;
465 std::map<std::string, YamlConfigurationNode *>::iterator i;
466 for (i = na.begin(); i != na.end(); ++i) {
467 if (nb.find(i->first) == nb.end()) {
470 rv.push_back(i->first);
471 }
else if (*i->second != *nb[i->first]) {
474 rv.push_back(i->first);
478 for (i = nb.begin(); i != nb.end(); ++i) {
479 if (na.find(i->first) == na.end()) {
482 rv.push_back(i->first);
499 if (type_ == Type::SEQUENCE) {
500 throw Exception(
"YamlConfiguration: value of %s is a list", name_.c_str());
503 if (yaml_utils::convert(scalar_value_, rv)) {
507 throw Exception(
"YamlConfig: value or type error on %s", name_.c_str());
516 get_list_as_string()
const 518 if (type_ != Type::SEQUENCE) {
519 throw fawkes::Exception(
"YamlConfiguration: value of %s is not a list", name_.c_str());
521 if (list_values_.empty())
return "";
524 bool is_string = (determine_scalar_type() == Type::STRING);
526 rv =
" \"" + list_values_[0] +
"\"";
527 for (
size_t i = 1; i < list_values_.size(); ++i) {
528 rv +=
" \"" + list_values_[i] +
"\"";
531 rv = list_values_[0];
532 for (
size_t i = 1; i < list_values_.size(); ++i) {
533 rv +=
" " + list_values_[i];
549 if (type_ != Type::SEQUENCE) {
550 throw Exception(
"YamlConfiguration: value of %s is not a list", name_.c_str());
553 const typename std::vector<T>::size_type N = list_values_.size();
555 for (
typename std::vector<T>::size_type i = 0; i < N; ++i) {
557 if (! yaml_utils::convert(list_values_[i], t)) {
559 throw Exception(
"YamlConfig: value or type error on %s[%zi]",
573 get_list_size()
const 575 if (type_ != Type::SEQUENCE) {
576 throw Exception(
"YamlConfiguration: value of %s is not a list", name_.c_str());
578 return list_values_.size();
589 set_value(
const char *path, T t)
591 YamlConfigurationNode *n = find_or_insert(path);
592 if (n->has_children()) {
593 throw Exception(
"YamlConfig: cannot set value on non-leaf path node %s", path);
595 n->set_scalar(StringConversions::to_string(t));
606 set_list(
const char *path, std::vector<T> &t)
608 YamlConfigurationNode *n = find_or_insert(path);
609 if (n->has_children()) {
610 throw Exception(
"YamlConfig: cannot set value on non-leaf path node %s", path);
612 std::vector<std::string> v;
613 typename std::vector<T>::size_type N = t.size();
615 for (
typename std::vector<T>::size_type i = 0; i < N; ++i) {
616 v[i] = StringConversions::to_string(t[i]);
618 n->set_scalar_list(v);
631 if (has_children()) {
632 throw Exception(
"YamlConfig: cannot set value on non-leaf path node %s", name_.c_str());
634 set_scalar(StringConversions::to_string(t));
646 set_list(std::vector<T> &t)
648 if (has_children()) {
649 throw Exception(
"YamlConfig: cannot set value on non-leaf path node %s", name_.c_str());
651 std::vector<std::string> v;
652 typename std::vector<T>::size_type N = t.size();
654 for (
typename std::vector<T>::size_type i = 0; i < N; ++i) {
655 v[i] = StringConversions::to_string(t[i]);
671 if (type_ == Type::SEQUENCE) {
672 if (! list_values_.empty()) {
674 return (yaml_utils::convert(list_values_[0], rv));
679 return (yaml_utils::convert(scalar_value_, rv));
683 Type::value get_type()
const 688 bool is_scalar()
const 703 float get_float()
const 705 return get_value<float>();
708 unsigned int get_uint()
const 710 return get_value<unsigned int>();
715 return get_value<int>();
718 bool get_bool()
const 720 return get_value<bool>();
723 Type::value determine_scalar_type()
const 725 if (is_type<unsigned int>()) {
733 }
catch (Exception &e) {
737 }
else if (is_type<int>()) {
739 }
else if (is_type<float>()) {
741 }
else if (is_type<bool>()) {
743 }
else if (is_type<std::string>()) {
746 return Type::UNKNOWN;
750 std::string get_string()
const 752 return get_value<std::string>();
755 void set_scalar(
const std::string &s) {
757 type_ = determine_scalar_type();
760 void set_scalar_list(
const std::vector<std::string> &s) {
762 type_ = Type::SEQUENCE;
765 const std::string & get_scalar()
const {
766 return scalar_value_;
769 void set_sequence(
const YAML::Node &n)
771 if (n.Type() != YAML::NodeType::Sequence) {
772 throw Exception(
"Cannot initialize list from non-sequence");
774 type_ = Type::SEQUENCE;
775 list_values_.resize(n.size());
777 #ifdef HAVE_YAMLCPP_0_5 778 for (YAML::const_iterator it = n.begin(); it != n.end(); ++it) {
779 list_values_[i++] = it->as<std::string>();
781 for (YAML::Iterator it = n.begin(); it != n.end(); ++it) {
782 *it >> list_values_[i++];
787 bool has_children()
const 789 return ! children_.empty();
793 bool is_default()
const 798 void set_default(
const char *path,
bool is_default)
800 YamlConfigurationNode *n = find(path);
801 n->set_default(is_default);
804 void set_default(
bool is_default)
806 is_default_ = is_default;
809 void enum_leafs(std::map<std::string, YamlConfigurationNode *> &nodes,
810 std::string prefix =
"")
const 812 std::map<std::string, YamlConfigurationNode *>::const_iterator c;
813 for (c = children_.begin(); c != children_.end(); ++c) {
814 std::string path = prefix +
"/" + c->first;
815 if (c->second->has_children()) {
816 c->second->enum_leafs(nodes, path);
818 nodes[path] = c->second;
823 void print(std::string indent =
"")
825 std::cout << indent << name_ <<
" : ";
826 if (! children_.empty()) {
827 std::cout << std::endl;
828 std::map<std::string, YamlConfigurationNode *>::iterator c;
829 for (c = children_.begin(); c != children_.end(); ++c) {
830 c->second->print(indent +
" ");
833 std::cout << indent << scalar_value_ <<
" (" << Type::to_string(get_type()) <<
")" << std::endl;
838 void emit(YAML::Emitter &ye) {
839 if (! children_.empty()) {
840 ye << YAML::BeginMap;
842 std::map<std::string, YamlConfigurationNode *>::iterator c;
843 for (c = children_.begin(); c != children_.end(); ++c) {
844 if (c->second->has_children()) {
846 ye << YAML::Key << c->first << YAML::Value;
849 ye << YAML::Key << c->first
850 << YAML::Value << c->second->get_scalar();
859 void emit(std::string &filename)
861 if (access(filename.c_str(), W_OK) != 0) {
862 if (errno != ENOENT) {
863 throw Exception(errno,
"YamlConfig: cannot write host file");
867 std::ofstream fout(filename.c_str());
881 std::string scalar_value_;
882 std::map<std::string, YamlConfigurationNode *> children_;
883 std::vector<std::string> list_values_;
Fawkes library namespace.
Base class for exceptions in Fawkes.