tue_config
yaml.cpp
Go to the documentation of this file.
2 
4 #include "resolve_functions.h"
5 #include "loader_functions.h"
6 
7 #include <tue/filesystem/path.h>
8 
9 // YAML parsing
10 #include <fstream>
11 
12 #include "yaml-cpp/yaml.h"
13 
14 #include <iostream>
15 #include <stdlib.h>
16 
17 namespace tue
18 {
19 
20 namespace config
21 {
22 
23 // ----------------------------------------------------------------------------------------------------
24 
25 bool yamlScalarToVariant(const std::string& key, const YAML::Node& n, ReaderWriter& config, const ResolveConfig& resolve_config)
26 {
27  std::string s;
28 
29  s = n.as<std::string>();
30 
31  if (key == "include")
32  {
33  std::string filename;
34  if (s.substr(0) == "/")
35  filename = s;
36  else
37  {
39  filename = filepath.parentPath().join(s).string();
40  }
41 
42  return loadFromYAMLFile(filename, config, resolve_config);
43  }
44 
45  // Check and resolve possible resolve functions ( "$( ... )" )
46  std::string s_resolved;
47  std::stringstream s_error;
48  if (!resolve(s, config.source(), s_resolved, s_error, resolve_config))
49  {
50  config.addError("While reading key '" + key +"': Could not resolve: " + s_error.str());
51  return false;
52  }
53 
54  // Make sure that empty strings("") are set as string
55  if (s_resolved.empty())
56  {
57  config.setValue(key, s_resolved);
58  return true;
59  }
60 
61  char* pEnd;
62  int i = (int) std::strtol(s_resolved.c_str(), &pEnd, 10);
63  if (pEnd[0] == 0)
64  {
65  config.setValue(key, i);
66  return true;
67  }
68 
69  double d = std::strtod(s_resolved.c_str(), &pEnd);
70  if (pEnd[0] == 0)
71  {
72  config.setValue(key, d);
73  return true;
74  }
75 
76  bool b;
77  if (strToBool(s_resolved, b))
78  {
79  config.setValue(key, b);
80  return true;
81  }
82 
83  config.setValue(key, s_resolved);
84  return true;
85 }
86 
87 // ----------------------------------------------------------------------------------------------------
88 
89 bool loadFromYAMLNode(const YAML::Node& node, ReaderWriter& config, const ResolveConfig& resolve_config)
90 {
91  bool success = true;
92  for(YAML::const_iterator it = node.begin(); it != node.end(); ++it)
93  {
94  std::string key = it->first.as<std::string>();
95  const YAML::Node& n = it->second;
96 
97  switch (n.Type())
98  {
99  case YAML::NodeType::Scalar:
100  {
101  if (!yamlScalarToVariant(key, n, config, resolve_config))
102  success = false;
103  break;
104  }
105  case YAML::NodeType::Sequence:
106  {
107  config.writeArray(key);
108 
109  /*
110  * Need to use index iteration instead of iterator for sequences, because it goes behind the end.
111  * See https://github.com/jbeder/yaml-cpp/issues/833
112  */
113  for(std::size_t i = 0; i < n.size(); ++i)
114  {
115  const YAML::Node& n2 = n[i];
116  if (n2.Type() != YAML::NodeType::Map)
117  {
118  config.addError("Sequences must only contains maps");
119  return false;
120  }
121  else
122  {
124  loadFromYAMLNode(n2, config, resolve_config);
126  }
127  }
128 
129  config.endArray();
130 
131  break;
132  }
133  case YAML::NodeType::Map:
134  config.writeGroup(key);
135  loadFromYAMLNode(n, config, resolve_config);
136  config.endGroup();
137  break;
138  case YAML::NodeType::Undefined:
139  case YAML::NodeType::Null:
140  break;
141  }
142  }
143 
144  return success;
145 }
146 
147 // ----------------------------------------------------------------------------------------------------
148 
149 bool loadFromYAMLStream(std::istream& stream, ReaderWriter& config, const ResolveConfig& resolve_config)
150 {
151  try
152  {
153 
154  YAML::Node doc = YAML::Load(stream);
155 
156  if (doc.Type() != YAML::NodeType::Map)
157  {
158  config.addError("Root of the config file must be a map.");
159  return false;
160  }
161 
162  if (!loadFromYAMLNode(doc, config, resolve_config))
163  return false;
164  }
165  catch(YAML::Exception& e)
166  {
167  config.addError(e.what());
168  return false;
169  }
170 
171  return true;
172 }
173 
174 // ----------------------------------------------------------------------------------------------------
175 
176 bool loadFromYAMLString(const std::string& string, ReaderWriter& config, const ResolveConfig& resolve_config)
177 {
179  ss << string;
180  return loadFromYAMLStream(ss, config, resolve_config);
181 }
182 
183 // ----------------------------------------------------------------------------------------------------
184 
185 bool loadFromYAMLFile(const std::string& filename, ReaderWriter& config, const ResolveConfig& resolve_config)
186 {
187  // Remove possible previous errors (TODO)
188 // config.data_->error.clear();
189 
190  // Reset head (TODO)
191 // config.head_ = scope_;
192 
193  config.setSource(filename);
194 
195  std::ifstream fin(filename.c_str());
196  if (fin.fail())
197  {
198  config.addError("No such file: '" + filename + "'.");
199  return false;
200  }
201 
202  if (!loadFromYAMLStream(fin, config, resolve_config))
203  return false;
204 
205  // TODO:
206 // filename_ = filename;
207 // source_last_write_time_ = tue::filesystem::Path(filename_).lastWriteTime();
208 
209  return true;
210 }
211 
212 }
213 
214 }
std::strtol
T strtol(T... args)
fstream
std::string
tue::config::ReaderWriter::setSource
void setSource(const std::string &source)
setSource set the source file of the data in this object
Definition: reader_writer.h:193
tue::config::ReaderWriter::source
const std::string & source() const
source get the source file of the data in this object
Definition: reader_writer.h:130
tue::config::ReaderWriter::endArrayItem
bool endArrayItem()
endArrayItem go back to the array level
Definition: reader_writer.cpp:245
tue::filesystem::Path
std::stringstream
tue::config::strToBool
bool strToBool(std::string s, bool &rhs)
strToBool Converts a string to a boolean of matches one of the following: y, n, yes,...
Definition: loader_functions.cpp:10
tue::config::ReaderWriter::writeArray
bool writeArray(const std::string &name)
writeArray starts writing an array. Or start extending it, if it already exists.
Definition: reader_writer.cpp:202
iostream
tue::config::ReaderWriter::writeGroup
bool writeGroup(const std::string &name)
writeGroup starts writing a group. Or start extending it, if it already exists.
Definition: reader_writer.cpp:181
tue::config::ReaderWriter::addArrayItem
bool addArrayItem()
addArrayItem create a new item in the array
Definition: reader_writer.cpp:223
tue::config::loadFromYAMLString
bool loadFromYAMLString(const std::string &string, ReaderWriter &config, const ResolveConfig &resolve_config=ResolveConfig::defaultConfig())
loadFromYAMLString loads a yaml string into a ReaderWriter class
Definition: yaml.cpp:176
tue::config::ReaderWriter
Definition: reader_writer.h:26
tue::config::loadFromYAMLFile
bool loadFromYAMLFile(const std::string &filename, ReaderWriter &config, const ResolveConfig &resolve_config=ResolveConfig::defaultConfig())
loadFromYAMLFile loads a yaml file into a ReaderWriter class
Definition: yaml.cpp:185
loader_functions.h
std::string::c_str
T c_str(T... args)
tue::config::ReaderWriter::endGroup
bool endGroup()
endGroup go to the parrent of current group, wrapping end() for readbility
Definition: reader_writer.h:104
yaml.h
tue::config::resolve
bool resolve(const std::string &str, const std::string &source, std::string &result, std::stringstream &error, const ResolveConfig &config)
Definition: resolve_functions.cpp:185
tue::config::loadFromYAMLStream
bool loadFromYAMLStream(std::istream &stream, ReaderWriter &config, const ResolveConfig &resolve_config=ResolveConfig::defaultConfig())
loadFromYAMLStream loads a yaml stream into a ReaderWriter class
Definition: yaml.cpp:149
tue::config::loadFromYAMLNode
bool loadFromYAMLNode(const YAML::Node &node, ReaderWriter &config, const ResolveConfig &resolve_config)
Definition: yaml.cpp:89
tue::config::ReaderWriter::endArray
bool endArray()
endArray go to parrent of current array, wrapping end() for readibility
Definition: reader_writer.h:98
std::string::substr
T substr(T... args)
tue::config::ReaderWriter::addError
void addError(const std::string &msg)
Definition: reader_writer.cpp:136
std::ifstream::fail
T fail(T... args)
path.h
tue::config::ReaderWriter::setValue
void setValue(const std::string &name, const T &value)
setValue set child value with key 'name' and value 'value'
Definition: reader_writer.h:155
tue::config::yamlScalarToVariant
bool yamlScalarToVariant(const std::string &key, const YAML::Node &n, ReaderWriter &config, const ResolveConfig &resolve_config)
Definition: yaml.cpp:25
std::strtod
T strtod(T... args)
configuration.h
tue::config::success
@ success
Definition: resolve_functions.cpp:21
std::string::empty
T empty(T... args)
std::stringstream::str
T str(T... args)
tue::filesystem::Path::string
const std::string & string() const
std::size_t
tue::config::ResolveConfig
Class to config the resolve behaviour of a loader.
Definition: resolve_config.h:16
tue::filesystem::Path::parentPath
Path parentPath() const
std::istream
tue
tue::filesystem::Path::join
Path join(const Path &path) const
resolve_functions.h
std::ifstream
config
tue::config::ReaderWriter config
Definition: sdf_gtest.cpp:9