Fawkes API  Fawkes Development Version
yaml_node.h
1 
2 /***************************************************************************
3  * yaml_node.h - Utility class for internal YAML config handling
4  *
5  * Created: Thu Aug 09 14:08:18 2012
6  * Copyright 2006-2012 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #ifndef __CONFIG_YAML_NODE_H_
25 #define __CONFIG_YAML_NODE_H_
26 
27 #ifndef __CONFIG_YAML_H_
28 # error Do not include yaml_node.h directly
29 #endif
30 
31 #include <utils/misc/string_conversions.h>
32 #include <utils/misc/string_split.h>
33 #include <fstream>
34 #include <iostream>
35 #include <stack>
36 #include <cerrno>
37 #include <climits>
38 #include <unistd.h>
39 #include <algorithm>
40 #include <yaml-cpp/traits.h>
41 #include <limits>
42 
43 #ifndef HAVE_YAMLCPP_0_5
44 # ifdef HAVE_YAMLCPP_ATLEAST_0_3
45 // older versions of yaml-cpp had these functions in the
46 // YAML, rather than in the YAML::conversion namespace.
47 namespace YAML {
48  namespace conversion {
49  using YAML::IsInfinity;
50  using YAML::IsNegativeInfinity;
51  using YAML::IsNaN;
52  }
53 }
54 # else
55 // older versions do not have this at all
56 namespace YAML {
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";
60  }
61 
62  inline bool IsNegativeInfinity(const std::string& input) {
63  return input == "-.inf" || input == "-.Inf" || input == "-.INF";
64  }
65 
66  inline bool IsNaN(const std::string& input) {
67  return input == ".nan" || input == ".NaN" || input == ".NAN";
68  }
69  }
70 }
71 # endif
72 #endif
73 
74 namespace fawkes {
75 
76 /// @cond INTERNALS
77 
78  namespace yaml_utils {
79 
80  namespace detail {
81  // we're not gonna mess with the mess that is all the isupper/etc. functions
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; }
85 
86  inline std::string tolower(const std::string& str)
87  {
88  std::string s(str);
89  std::transform(s.begin(), s.end(), s.begin(), ToLower);
90  return s;
91  }
92 
93  template <typename T>
94  inline bool IsEntirely(const std::string& str, T func)
95  {
96  for(std::size_t i=0;i<str.size();i++)
97  if(!func(str[i]))
98  return false;
99 
100  return true;
101  }
102 
103  // IsFlexibleCase
104  // . Returns true if 'str' is:
105  // . UPPERCASE
106  // . lowercase
107  // . Capitalized
108  inline bool IsFlexibleCase(const std::string& str)
109  {
110  if(str.empty())
111  return true;
112 
113  if(IsEntirely(str, IsLower))
114  return true;
115 
116  bool firstcaps = IsUpper(str[0]);
117  std::string rest = str.substr(1);
118  return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper));
119  }
120  }
121 
122  inline bool convert(const std::string& input, std::string& output) {
123  output = input;
124  return true;
125  }
126 
127  inline bool convert(const std::string& input, bool& output)
128  {
129  // we can't use iostream bool extraction operators as they don't
130  // recognize all possible values in the table below (taken from
131  // http://yaml.org/type/bool.html)
132  static const struct {
133  std::string truename, falsename;
134  } names[] = {
135  { "y", "n" },
136  { "yes", "no" },
137  { "true", "false" },
138  { "on", "off" },
139  };
140 
141  if(! detail::IsFlexibleCase(input))
142  return false;
143 
144  for(unsigned i=0;i<sizeof(names)/sizeof(names[0]);i++) {
145  if(names[i].truename == detail::tolower(input)) {
146  output = true;
147  return true;
148  }
149 
150  if(names[i].falsename == detail::tolower(input)) {
151  output = false;
152  return true;
153  }
154  }
155 
156  return false;
157  }
158 
159  inline bool
160  convert(const std::string& input, YAML::_Null& output)
161  {
162  return input.empty() || input == "~" || input == "null" || input == "Null" || input == "NULL";
163  }
164 
165  inline bool convert(const std::string &input, unsigned int &rhs)
166  {
167  errno = 0;
168  char *endptr;
169  long int l = strtol(input.c_str(), &endptr, 0);
170 
171  if ((errno == ERANGE && (l == LONG_MAX || l == LONG_MIN)) || (errno != 0 && l == 0)) {
172  return false;
173  }
174  if (endptr == input.c_str()) return false;
175  if (*endptr != 0) return false;
176  if (l < 0) return false;
177 
178  rhs = (unsigned int)l;
179 
180  return true;
181  }
182 
183 
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)
187  {
188  std::stringstream stream(input);
189  stream.unsetf(std::ios::dec);
190  if((stream >> rhs) && (stream >> std::ws).eof())
191  return true;
192  else {
193  }
194  if(std::numeric_limits<T>::has_infinity) {
195  if(YAML::conversion::IsInfinity(input) || YAML::conversion::IsNegativeInfinity(input) )
196  {
197  rhs = std::numeric_limits<T>::infinity();
198  return true;
199  }
200  }
201 
202  if(std::numeric_limits<T>::has_quiet_NaN && YAML::conversion::IsNaN(input)) {
203  rhs = std::numeric_limits<T>::quiet_NaN();
204  return true;
205  }
206 
207  return false;
208  }
209  }
210 
211 class YamlConfigurationNode
212 {
213  public:
214  struct Type {
215  enum value { NONE, UINT32, INT32, FLOAT, BOOL, STRING, MAP, SEQUENCE, UNKNOWN };
216  static const char * to_string(value v) {
217  switch (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";
227  }
228  }
229  };
230 
231  YamlConfigurationNode() : name_("root"), type_(Type::UNKNOWN), is_default_(false) {}
232 
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_)
236  {}
237 
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_)
241  {}
242 
243  YamlConfigurationNode(std::string name, const YAML::Node &node)
244  : name_(name), type_(Type::UNKNOWN), is_default_(false)
245  {
246 #ifdef HAVE_YAMLCPP_0_5
247  scalar_value_ = node.Scalar();
248 #else
249  node.GetScalar(scalar_value_);
250 #endif
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;
256  default:
257  type_ = Type::UNKNOWN; break;
258  }
259  }
260 
261 
262  YamlConfigurationNode(std::string name)
263  : name_(name), type_(Type::NONE), is_default_(false) {}
264 
265  ~YamlConfigurationNode()
266  {
267  std::map<std::string, YamlConfigurationNode *>::iterator i;
268  for (i = children_.begin(); i != children_.end(); ++i) {
269  delete i->second;
270  }
271  }
272 
273  void add_child(std::string &p, YamlConfigurationNode *n) {
274  type_ = Type::MAP;
275  children_[p] = n;
276  }
277 
278  std::map<std::string, YamlConfigurationNode *>::iterator begin()
279  { return children_.begin(); }
280 
281  std::map<std::string, YamlConfigurationNode *>::iterator end()
282  { return children_.end(); }
283 
284  std::map<std::string, YamlConfigurationNode *>::size_type size() const
285  { return children_.size(); }
286 
287 
288  std::map<std::string, YamlConfigurationNode *>::const_iterator begin() const
289  { return children_.begin(); }
290 
291  std::map<std::string, YamlConfigurationNode *>::const_iterator end() const
292  { return children_.end(); }
293 
294  YamlConfigurationNode * find(std::queue<std::string> &q)
295  {
296 
297  YamlConfigurationNode *n = this;
298  std::string path;
299 
300  while (! q.empty()) {
301  std::string pel = q.front();
302 
303  path += "/" + pel;
304 
305  if (n->children_.find(pel) == n->children_.end()) {
306  throw ConfigEntryNotFoundException(path.c_str());
307  }
308  n = n->children_[pel];
309 
310  q.pop();
311  }
312 
313  return n;
314  }
315 
316  YamlConfigurationNode * find_or_insert(const char *path)
317  {
318  std::queue<std::string> q = str_split_to_queue(path);
319 
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));
325  }
326  n = n->children_[pel];
327  q.pop();
328  }
329 
330  return n;
331  }
332 
333  void erase(const char *path)
334  {
335  std::queue<std::string> q = str_split_to_queue(path);
336  std::stack<YamlConfigurationNode *> qs;
337  std::string full_path;
338 
339  YamlConfigurationNode *n = this;
340  while (! q.empty()) {
341 
342  std::string pel = q.front();
343  full_path += "/" + pel;
344 
345  if (n->children_.find(pel) == n->children_.end()) {
346  throw ConfigEntryNotFoundException(full_path.c_str());
347  }
348  qs.push(n);
349  n = n->children_[pel];
350 
351  q.pop();
352  }
353 
354  if (n->has_children()) {
355  throw Exception("YamlConfig: cannot erase non-leaf value");
356  }
357 
358  YamlConfigurationNode *child = n;
359  while (! qs.empty()) {
360  YamlConfigurationNode *en = qs.top();
361 
362  en->children_.erase(child->name());
363 
364  // The node had more nodes than just the child, stop erasing
365  if (en->has_children()) {
366  break;
367  }
368 
369  child = en;
370  qs.pop();
371  }
372  }
373 
374 
375 
376  YamlConfigurationNode * find(const char *path)
377  {
378  try {
379  std::queue<std::string> pel_q = str_split_to_queue(path);
380  return find(pel_q);
381  } catch (Exception &e) {
382  throw;
383  }
384  }
385 
386  void operator=(const YamlConfigurationNode &n)
387  {
388  name_ = n.name_;
389  type_ = n.type_;
390  children_ = n.children_;
391  list_values_ = n.list_values_;
392  }
393 
394  bool operator< (const YamlConfigurationNode &n) const
395  { return this->name_ < n.name_; }
396 
397  YamlConfigurationNode * operator[] (const std::string &p)
398  {
399  std::map<std::string, YamlConfigurationNode *>::iterator i;
400  if ((i = children_.find(p)) != children_.end()) {
401  return i->second;
402  } else {
403  return NULL;
404  }
405  }
406 
407  YamlConfigurationNode & operator+= (const YamlConfigurationNode *n)
408  {
409  if (! n) return *this;
410 
411  YamlConfigurationNode *add_to = this;
412 
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);
417  }
418  add_to = children_[n->name()];
419  }
420 
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());
425  }
426  add_to->set_scalar(n->get_scalar());
427  } else {
428 
429  std::map<std::string, YamlConfigurationNode *>::const_iterator i;
430  for (i = n->begin(); i != n->end(); ++i) {
431  *add_to += i->second;
432  }
433  }
434 
435  return *this;
436  }
437 
438  bool operator==(const YamlConfigurationNode &n) const
439  {
440  return (name_ == n.name_) && (type_ == n.type_) && (scalar_value_ == n.scalar_value_);
441  }
442 
443  bool operator!=(const YamlConfigurationNode &n) const
444  {
445  return (name_ != n.name_) || (type_ != n.type_) || (scalar_value_ != n.scalar_value_);
446  }
447 
448  /** Check for differences in two trees.
449  * This returns a list of all changes that have occured in b opposed
450  * to b. This means keys which have been added or changed in b compared to
451  * a. It also includes keys which have been removed from a, i.e. which exist
452  * in b but not in a.
453  * @param a root node of first tree
454  * @param b root node of second tree
455  * @return list of paths to leaf nodes that changed
456  */
457  static std::list<std::string> diff(const YamlConfigurationNode *a, const YamlConfigurationNode *b)
458  {
459  std::list<std::string> rv;
460 
461  std::map<std::string, YamlConfigurationNode *> na, nb;
462  a->enum_leafs(na);
463  b->enum_leafs(nb);
464 
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()) {
468  // this is a new key in a
469  // printf("A %s NOT in B\n", i->first.c_str());
470  rv.push_back(i->first);
471  } else if (*i->second != *nb[i->first]) {
472  // different values/types
473  // printf("A %s modified\n", i->first.c_str());
474  rv.push_back(i->first);
475  }
476  }
477 
478  for (i = nb.begin(); i != nb.end(); ++i) {
479  if (na.find(i->first) == na.end()) {
480  // this is a new key in b
481  // printf("B %s NOT in A\n", i->first.c_str());
482  rv.push_back(i->first);
483  }
484  }
485 
486  return rv;
487  }
488 
489  /** Retrieve value casted to given type T.
490  * @param path path to query
491  * @return value casted as desired
492  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
493  * a different type.
494  */
495  template<typename T>
496  T
497  get_value() const
498  {
499  if (type_ == Type::SEQUENCE) {
500  throw Exception("YamlConfiguration: value of %s is a list", name_.c_str());
501  }
502  T rv;
503  if (yaml_utils::convert(scalar_value_, rv)) {
504  return rv;
505  } else {
506  // might want to have custom exception here later
507  throw Exception("YamlConfig: value or type error on %s", name_.c_str());
508  }
509  }
510 
511  /** Get the list elements as string.
512  * The first element determines the type of the list.
513  * @return value string as list, i.e. as space-separated list of items
514  */
515  std::string
516  get_list_as_string() const
517  {
518  if (type_ != Type::SEQUENCE) {
519  throw fawkes::Exception("YamlConfiguration: value of %s is not a list", name_.c_str());
520  }
521  if (list_values_.empty()) return "";
522 
523  std::string rv = "";
524  bool is_string = (determine_scalar_type() == Type::STRING);
525  if (is_string) {
526  rv = " \"" + list_values_[0] + "\"";
527  for (size_t i = 1; i < list_values_.size(); ++i) {
528  rv += " \"" + list_values_[i] + "\"";
529  }
530  } else {
531  rv = list_values_[0];
532  for (size_t i = 1; i < list_values_.size(); ++i) {
533  rv += " " + list_values_[i];
534  }
535  }
536 
537  return rv;
538  }
539 
540  /** Retrieve value casted to given type T.
541  * @return value casted as desired
542  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
543  * a different type.
544  */
545  template<typename T>
546  std::vector<T>
547  get_list() const
548  {
549  if (type_ != Type::SEQUENCE) {
550  throw Exception("YamlConfiguration: value of %s is not a list", name_.c_str());
551  }
552  std::vector<T> rv;
553  const typename std::vector<T>::size_type N = list_values_.size();
554  rv.resize(N);
555  for (typename std::vector<T>::size_type i = 0; i < N; ++i) {
556  T t;
557  if (! yaml_utils::convert(list_values_[i], t)) {
558  // might want to have custom exception here later
559  throw Exception("YamlConfig: value or type error on %s[%zi]",
560  name_.c_str(), i);
561  }
562  rv[i] = t;
563  }
564  return rv;
565  }
566 
567  /** Retrieve list size.
568  * @return size of list
569  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
570  * a different type.
571  */
572  size_t
573  get_list_size() const
574  {
575  if (type_ != Type::SEQUENCE) {
576  throw Exception("YamlConfiguration: value of %s is not a list", name_.c_str());
577  }
578  return list_values_.size();
579  }
580 
581  /** Set value of given type T.
582  * @param path path to query
583  * @return value casted as desired
584  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
585  * a different type.
586  */
587  template<typename T>
588  void
589  set_value(const char *path, T t)
590  {
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);
594  }
595  n->set_scalar(StringConversions::to_string(t));
596  }
597 
598  /** Set list of given type T.
599  * @param path path to query
600  * @return value casted as desired
601  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
602  * a different type.
603  */
604  template<typename T>
605  void
606  set_list(const char *path, std::vector<T> &t)
607  {
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);
611  }
612  std::vector<std::string> v;
613  typename std::vector<T>::size_type N = t.size();
614  v.resize(N);
615  for (typename std::vector<T>::size_type i = 0; i < N; ++i) {
616  v[i] = StringConversions::to_string(t[i]);
617  }
618  n->set_scalar_list(v);
619  }
620 
621  /** Set value of given type T.
622  * @param path path to query
623  * @return value casted as desired
624  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
625  * a different type.
626  */
627  template<typename T>
628  void
629  set_value(T t)
630  {
631  if (has_children()) {
632  throw Exception("YamlConfig: cannot set value on non-leaf path node %s", name_.c_str());
633  }
634  set_scalar(StringConversions::to_string(t));
635  }
636 
637 
638  /** Set list of values of given type T.
639  * @param path path to query
640  * @return value casted as desired
641  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
642  * a different type.
643  */
644  template<typename T>
645  void
646  set_list(std::vector<T> &t)
647  {
648  if (has_children()) {
649  throw Exception("YamlConfig: cannot set value on non-leaf path node %s", name_.c_str());
650  }
651  std::vector<std::string> v;
652  typename std::vector<T>::size_type N = t.size();
653  v.resize(N);
654  for (typename std::vector<T>::size_type i = 0; i < N; ++i) {
655  v[i] = StringConversions::to_string(t[i]);
656  }
657  set_scalar_list(v);
658  }
659 
660  /** Check if value is of given type T.
661  * @param path path to query
662  * @return value casted as desired
663  * @throw YAML::ScalarInvalid thrown if value does not exist or is of
664  * a different type.
665  */
666  template<typename T>
667  bool
668  is_type() const
669  {
670  T rv;
671  if (type_ == Type::SEQUENCE) {
672  if (! list_values_.empty()) {
673  T rv;
674  return (yaml_utils::convert(list_values_[0], rv));
675  } else {
676  return true;
677  }
678  } else {
679  return (yaml_utils::convert(scalar_value_, rv));
680  }
681  }
682 
683  Type::value get_type() const
684  {
685  return type_;
686  }
687 
688  bool is_scalar() const
689  {
690  switch (type_) {
691  case Type::UINT32:
692  case Type::INT32:
693  case Type::FLOAT:
694  case Type::BOOL:
695  case Type::STRING:
696  return true;
697  default:
698  return false;
699  }
700  }
701 
702 
703  float get_float() const
704  {
705  return get_value<float>();
706  }
707 
708  unsigned int get_uint() const
709  {
710  return get_value<unsigned int>();
711  }
712 
713  int get_int() const
714  {
715  return get_value<int>();
716  }
717 
718  bool get_bool() const
719  {
720  return get_value<bool>();
721  }
722 
723  Type::value determine_scalar_type() const
724  {
725  if (is_type<unsigned int>()) {
726  try {
727  int v = get_int();
728  if (v >= 0) {
729  return Type::UINT32;
730  } else {
731  return Type::INT32;
732  }
733  } catch (Exception &e) {
734  // can happen if value > MAX_INT
735  return Type::UINT32;
736  }
737  } else if (is_type<int>()) {
738  return Type::INT32;
739  } else if (is_type<float>()) {
740  return Type::FLOAT;
741  } else if (is_type<bool>()) {
742  return Type::BOOL;
743  } else if (is_type<std::string>()) {
744  return Type::STRING;
745  } else {
746  return Type::UNKNOWN;
747  }
748  }
749 
750  std::string get_string() const
751  {
752  return get_value<std::string>();
753  }
754 
755  void set_scalar(const std::string &s) {
756  scalar_value_ = s;
757  type_ = determine_scalar_type();
758  }
759 
760  void set_scalar_list(const std::vector<std::string> &s) {
761  list_values_ = s;
762  type_ = Type::SEQUENCE;
763  }
764 
765  const std::string & get_scalar() const {
766  return scalar_value_;
767  }
768 
769  void set_sequence(const YAML::Node &n)
770  {
771  if (n.Type() != YAML::NodeType::Sequence) {
772  throw Exception("Cannot initialize list from non-sequence");
773  }
774  type_ = Type::SEQUENCE;
775  list_values_.resize(n.size());
776  unsigned int i = 0;
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>();
780 #else
781  for (YAML::Iterator it = n.begin(); it != n.end(); ++it) {
782  *it >> list_values_[i++];
783 #endif
784  }
785  }
786 
787  bool has_children() const
788  {
789  return ! children_.empty();
790  }
791 
792 
793  bool is_default() const
794  {
795  return is_default_;
796  }
797 
798  void set_default(const char *path, bool is_default)
799  {
800  YamlConfigurationNode *n = find(path);
801  n->set_default(is_default);
802  }
803 
804  void set_default(bool is_default)
805  {
806  is_default_ = is_default;
807  }
808 
809  void enum_leafs(std::map<std::string, YamlConfigurationNode *> &nodes,
810  std::string prefix = "") const
811  {
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);
817  } else {
818  nodes[path] = c->second;
819  }
820  }
821  }
822 
823  void print(std::string indent = "")
824  {
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 + " ");
831  }
832  } else {
833  std::cout << indent << scalar_value_ << " (" << Type::to_string(get_type()) << ")" << std::endl;
834  }
835  }
836 
837  private:
838  void emit(YAML::Emitter &ye) {
839  if (! children_.empty()) {
840  ye << YAML::BeginMap;
841 
842  std::map<std::string, YamlConfigurationNode *>::iterator c;
843  for (c = children_.begin(); c != children_.end(); ++c) {
844  if (c->second->has_children()) {
845  // recurse
846  ye << YAML::Key << c->first << YAML::Value;
847  c->second->emit(ye);
848  } else {
849  ye << YAML::Key << c->first
850  << YAML::Value << c->second->get_scalar();
851  }
852  }
853 
854  ye << YAML::EndMap;
855  }
856  }
857 
858  public:
859  void emit(std::string &filename)
860  {
861  if (access(filename.c_str(), W_OK) != 0) {
862  if (errno != ENOENT) {
863  throw Exception(errno, "YamlConfig: cannot write host file");
864  }
865  }
866 
867  std::ofstream fout(filename.c_str());
868  YAML::Emitter ye;
869  emit(ye);
870  fout << ye.c_str();
871  }
872 
873  const std::string &
874  name() const
875  { return name_; }
876 
877  private:
878 
879  std::string name_;
880  Type::value type_;
881  std::string scalar_value_;
882  std::map<std::string, YamlConfigurationNode *> children_;
883  std::vector<std::string> list_values_;
884  bool is_default_;
885 };
886 
887 /// @endcond
888 
889 } // end namespace fawkes
890 
891 #endif
Fawkes library namespace.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Definition: yaml_node.h:56