Changeset 85:8938c2bb579a in finroc_plugins_parameters
- Timestamp:
- 21.03.2020 16:20:12 (12 months ago)
- Branch:
- 17.03
- Children:
- 86:b177bc25e9c4, 87:495d52531f18
- Phase:
- public
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
tConfigFile.cpp
r81 r85 75 75 /*! Leaf name in XML */ 76 76 static const std::string cXML_LEAF_NAME("value"); 77 78 /*! Override attribute name in config files */ 79 static const std::string cXML_OVERRIDE_ATTRIBUTE_NAME("override"); 80 77 81 #endif 78 82 … … 159 163 } 160 164 161 162 #endif 163 164 } 165 166 tConfigFile::tConfigFile() : 167 #ifdef _LIB_RRLIB_XML_PRESENT_ 168 wrapped(), 169 #endif 170 filename(), 171 active(true) 172 { 173 #ifdef _LIB_RRLIB_XML_PRESENT_ 174 wrapped.AddRootNode(cXML_BRANCH_NAME); 175 #endif 176 } 177 178 tConfigFile::tConfigFile(const std::string& filename, bool optional) : 179 #ifdef _LIB_RRLIB_XML_PRESENT_ 180 wrapped(), 181 #endif 182 filename(filename), 183 active(true) 184 { 185 #ifdef _LIB_RRLIB_XML_PRESENT_ 186 if (core::FinrocFileExists(filename)) 187 { 188 try 189 { 190 wrapped = LoadConfigFile(filename); 191 return; 192 } 193 catch (const std::exception& e) 194 { 195 FINROC_LOG_PRINT(ERROR, e); 196 } 197 } 198 else if (!optional) 199 { 200 FINROC_LOG_PRINT(WARNING, "Specified config file not found: ", filename); 201 } 202 wrapped = rrlib::xml::tDocument(); 203 wrapped.AddRootNode(cXML_BRANCH_NAME); 204 #endif 205 } 206 207 void tConfigFile::Append(const std::string& filename) 208 { 209 #ifdef _LIB_RRLIB_XML_PRESENT_ 210 if (core::FinrocFileExists(filename)) 211 { 212 // merge entries into first document 213 auto document = LoadConfigFile(filename); 214 auto& root_node = document.RootNode(); 215 for (auto it = root_node.ChildrenBegin(); it != root_node.ChildrenEnd(); ++it) 216 { 217 this->wrapped.RootNode().AddChildNode(*it, true); // not using copy resulted in erroneous behavior 218 } 219 } 220 else 221 { 222 throw std::runtime_error("Specified config file not found: " + filename); 223 } 224 #endif 225 } 226 227 #ifdef _LIB_RRLIB_XML_PRESENT_ 228 rrlib::xml::tNode& tConfigFile::CreateEntry(const std::string& entry, bool leaf) 229 { 230 if (!leaf) 231 { 232 std::vector<rrlib::xml::tNode*> result; 233 GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 234 if (result.size() > 0) 235 { 236 // do we want to warn if node is a leaf node? - I currently do not think so 237 return *result[0]; 238 } 239 } 240 241 size_t slash_index = entry.rfind('/'); 242 tXMLNode& parent = (slash_index == std::string::npos || slash_index == 0) ? wrapped.RootNode() : CreateEntry(entry.substr(0, slash_index), false); 243 tXMLNode& created = parent.AddChildNode(leaf ? cXML_LEAF_NAME : cXML_BRANCH_NAME); 244 created.SetAttribute("name", (slash_index == std::string::npos) ? entry : entry.substr(slash_index + 1)); 245 return created; 246 } 247 #endif 248 249 tConfigFile* tConfigFile::Find(const core::tFrameworkElement& element) 250 { 251 tConfigFile* config_file = element.GetAnnotation<tConfigFile>(); 252 if (config_file && config_file->active == true) 253 { 254 return config_file; 255 } 256 core::tFrameworkElement* parent = element.GetParent(); 257 if (parent) 258 { 259 return Find(*parent); 260 } 261 return NULL; 262 } 263 264 #ifdef _LIB_RRLIB_XML_PRESENT_ 265 rrlib::xml::tNode& tConfigFile::GetEntry(const std::string& entry, bool create) 266 { 267 std::vector<rrlib::xml::tNode*> result; 268 GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 269 if (result.size() > 1) 270 { 271 FINROC_LOG_PRINT(WARNING, "There are ", result.size(), " entries in config file with the qualified name '", entry, "'. Using the first one."); 272 } 273 274 if (!create) 275 { 276 if (result.size() == 0) 277 { 278 throw std::runtime_error("Config node not found: " + entry); 279 } 280 if (result[0]->Name() != cXML_LEAF_NAME) 281 { 282 throw std::runtime_error("Config node is no leaf: " + entry); 283 } 284 return *result[0]; 285 } 286 287 // create node... 288 if (result.size() > 0) 289 { 290 // recreate existing node 291 std::string name = result[0]->GetStringAttribute("name"); 292 tXMLNode& parent = result[0]->Parent(); 293 tXMLNode& new_node = result[0]->AddNextSibling(cXML_LEAF_NAME); 294 new_node.SetAttribute("name", name); 295 parent.RemoveChildNode(*result[0]); 296 return new_node; 297 } 298 else 299 { 300 return CreateEntry(entry, true); 301 } 302 } 303 304 std::vector<std::string> tConfigFile::GetChildrenNames(const std::string &entry) 305 { 306 std::vector<rrlib::xml::tNode *> nodes; 307 this->GetEntryImplementation(nodes, entry, wrapped.RootNode(), 0); 308 if (nodes.size() > 1) 309 { 310 FINROC_LOG_PRINT(WARNING, "There are ", nodes.size(), " entries in config file with the qualified name '", entry, "'. Using the first one."); 311 } 312 313 if (nodes.size() == 0) 314 { 315 throw std::runtime_error("Config node not found: " + entry); 316 } 317 if (nodes[0]->Name() == cXML_LEAF_NAME) 318 { 319 throw std::runtime_error("Config node is a leaf: " + entry); 320 } 321 322 std::vector<std::string> result; 323 for (auto it = nodes.front()->ChildrenBegin(); it != nodes.front()->ChildrenEnd(); ++it) 324 { 325 result.push_back(it->GetStringAttribute("name")); 326 } 327 return result; 328 } 329 330 331 void tConfigFile::GetEntryImplementation(std::vector<rrlib::xml::tNode*>& result, const std::string& entry, rrlib::xml::tNode& node, size_t entry_string_index) 165 bool OverrideContext(rrlib::xml::tNode& node, bool in_override_context) 166 { 167 if (node.HasAttribute(cXML_OVERRIDE_ATTRIBUTE_NAME)) 168 { 169 return node.GetBoolAttribute(cXML_OVERRIDE_ATTRIBUTE_NAME); 170 } 171 return in_override_context; 172 } 173 174 /*! Result of GetEntryImplementation function */ 175 struct GetEntryImplementationResult 176 { 177 struct tEntry 178 { 179 rrlib::xml::tNode* node; 180 bool overrides; 181 }; 182 tEntry first_entry, last_override_entry; 183 size_t entry_count = 0, override_entry_count = 0; 184 }; 185 186 /*! 187 * Implementation of GetEntry() - called recursively 188 * 189 * \param result Object that will contain the result(s) as additional entry/entries after the call 190 * \param entry Entry 191 * \param node Current node 192 * \param entry_string_index Current index in entry string 193 * \param override_context Whether override="true" has been set in any parent now 194 */ 195 void GetEntryImplementation(GetEntryImplementationResult& result, const std::string& entry, rrlib::xml::tNode& node, size_t entry_string_index, bool override_context = false) 332 196 { 333 197 if (entry_string_index >= entry.length()) … … 341 205 if (entry_string_index > 0) 342 206 { 343 FINROC_LOG_PRINT (WARNING, "Entry '", entry, "' seems to be not clean (sequential slashes). Skipping one slash now, as this is typically intended. Please fix this!");207 FINROC_LOG_PRINT_STATIC(WARNING, "Entry '", entry, "' seems to be not clean (sequential slashes). Skipping one slash now, as this is typically intended. Please fix this!"); 344 208 } 345 209 entry_string_index++; … … 351 215 if (child->Name() == cXML_BRANCH_NAME || child->Name() == cXML_LEAF_NAME) 352 216 { 217 std::string name_attribute; 353 218 try 354 219 { 355 std::string name_attribute = child->GetStringAttribute("name"); 220 name_attribute = child->GetStringAttribute("name"); 221 } 222 catch (const std::exception& e) 223 { 224 FINROC_LOG_PRINT_STATIC(WARNING, "Encountered tree node without name"); 225 } 226 227 try 228 { 356 229 if (entry.compare(entry_string_index, name_attribute.length(), name_attribute) == 0) // starts_with name attribute? 357 230 { … … 362 235 { 363 236 new_entry_string_index++; 364 GetEntryImplementation(result, entry, *child, new_entry_string_index );237 GetEntryImplementation(result, entry, *child, new_entry_string_index, OverrideContext(*child, override_context)); 365 238 } 366 239 } 367 240 else 368 241 { 369 result.push_back(&(*child)); 242 // Entry found - include in result 243 GetEntryImplementationResult::tEntry new_entry = { &(*child), OverrideContext(*child, override_context) }; 244 if (!result.entry_count) 245 { 246 result.first_entry = new_entry; 247 if (new_entry.overrides) 248 { 249 FINROC_LOG_PRINT_STATIC(WARNING, "First config entry with path '", entry, "' marked 'override', but does not override."); 250 } 251 } 252 if (new_entry.overrides) 253 { 254 result.last_override_entry = new_entry; 255 } 256 result.entry_count++; 257 result.override_entry_count += (new_entry.overrides ? 1 : 0); 370 258 } 371 259 } … … 373 261 catch (const std::exception& e) 374 262 { 375 FINROC_LOG_PRINT(WARNING, "Encountered tree node without name"); 376 } 377 } 378 } 379 380 // Okay, we did not find any more 381 } 263 FINROC_LOG_PRINT_STATIC(ERROR, "Error looking for config entry with path '", entry, "'. Reason: ", e.what()); 264 } 265 } 266 } 267 } 268 269 rrlib::xml::tNode* ChooseNodeFromResult(GetEntryImplementationResult& result, const std::string& path) 270 { 271 if (result.entry_count > 1) 272 { 273 assert(result.entry_count >= result.override_entry_count); 274 if (!result.override_entry_count) 275 { 276 FINROC_LOG_PRINT_STATIC(WARNING, "There are ", result.entry_count, " entries in config file with the path '", path, "'. Using the first one. Hint: Add attribute 'override=\"true\"' to nodes and values if the later entries are intended be used. This will also remove any warning messages."); 277 } 278 else if (result.entry_count - result.override_entry_count > 1) 279 { 280 FINROC_LOG_PRINT_STATIC(WARNING, "There are ", result.entry_count, " entries in config file with the path '", path, "'. Only ", result.override_entry_count, " are marked 'override'. Using the last one marked 'override'."); 281 } 282 return result.override_entry_count ? result.last_override_entry.node : result.first_entry.node; 283 } 284 return result.entry_count ? result.first_entry.node : nullptr; 285 } 286 287 #endif 288 289 } 290 291 tConfigFile::tConfigFile() : 292 #ifdef _LIB_RRLIB_XML_PRESENT_ 293 wrapped(), 294 #endif 295 filename(), 296 active(true) 297 { 298 #ifdef _LIB_RRLIB_XML_PRESENT_ 299 wrapped.AddRootNode(cXML_BRANCH_NAME); 300 #endif 301 } 302 303 tConfigFile::tConfigFile(const std::string& filename, bool optional) : 304 #ifdef _LIB_RRLIB_XML_PRESENT_ 305 wrapped(), 306 #endif 307 filename(filename), 308 active(true) 309 { 310 #ifdef _LIB_RRLIB_XML_PRESENT_ 311 if (core::FinrocFileExists(filename)) 312 { 313 try 314 { 315 wrapped = LoadConfigFile(filename); 316 return; 317 } 318 catch (const std::exception& e) 319 { 320 FINROC_LOG_PRINT(ERROR, e); 321 } 322 } 323 else if (!optional) 324 { 325 FINROC_LOG_PRINT(WARNING, "Specified config file not found: ", filename); 326 } 327 wrapped = rrlib::xml::tDocument(); 328 wrapped.AddRootNode(cXML_BRANCH_NAME); 329 #endif 330 } 331 332 void tConfigFile::Append(const std::string& filename) 333 { 334 #ifdef _LIB_RRLIB_XML_PRESENT_ 335 if (core::FinrocFileExists(filename)) 336 { 337 // merge entries into first document 338 auto document = LoadConfigFile(filename); 339 auto& root_node = document.RootNode(); 340 for (auto it = root_node.ChildrenBegin(); it != root_node.ChildrenEnd(); ++it) 341 { 342 this->wrapped.RootNode().AddChildNode(*it, true); // not using copy resulted in erroneous behavior 343 } 344 } 345 else 346 { 347 throw std::runtime_error("Specified config file not found: " + filename); 348 } 349 #endif 350 } 351 352 #ifdef _LIB_RRLIB_XML_PRESENT_ 353 rrlib::xml::tNode& tConfigFile::CreateEntry(const std::string& entry, bool leaf) 354 { 355 if (!leaf) 356 { 357 GetEntryImplementationResult result; 358 GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 359 rrlib::xml::tNode* result_node = ChooseNodeFromResult(result, entry); 360 if (result_node) 361 { 362 // do we want to warn if node is a leaf node? - I currently do not think so 363 return *result_node; 364 } 365 } 366 367 size_t slash_index = entry.rfind('/'); 368 tXMLNode& parent = (slash_index == std::string::npos || slash_index == 0) ? wrapped.RootNode() : CreateEntry(entry.substr(0, slash_index), false); 369 tXMLNode& created = parent.AddChildNode(leaf ? cXML_LEAF_NAME : cXML_BRANCH_NAME); 370 created.SetAttribute("name", (slash_index == std::string::npos) ? entry : entry.substr(slash_index + 1)); 371 return created; 372 } 373 #endif 374 375 tConfigFile* tConfigFile::Find(const core::tFrameworkElement& element) 376 { 377 tConfigFile* config_file = element.GetAnnotation<tConfigFile>(); 378 if (config_file && config_file->active == true) 379 { 380 return config_file; 381 } 382 core::tFrameworkElement* parent = element.GetParent(); 383 if (parent) 384 { 385 return Find(*parent); 386 } 387 return NULL; 388 } 389 390 #ifdef _LIB_RRLIB_XML_PRESENT_ 391 rrlib::xml::tNode& tConfigFile::GetEntry(const std::string& entry, bool create) 392 { 393 GetEntryImplementationResult result; 394 GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 395 rrlib::xml::tNode* result_node = ChooseNodeFromResult(result, entry); 396 397 if (!create) 398 { 399 if (!result_node) 400 { 401 throw std::runtime_error("Config node not found: " + entry); 402 } 403 if (result_node->Name() != cXML_LEAF_NAME) 404 { 405 throw std::runtime_error("Config node is no leaf: " + entry); 406 } 407 return *result_node; 408 } 409 410 // create node... 411 if (result.entry_count > 0) 412 { 413 // recreate existing node 414 std::string name = result_node->GetStringAttribute("name"); 415 tXMLNode& parent = result_node->Parent(); 416 tXMLNode& new_node = result_node->AddNextSibling(cXML_LEAF_NAME); 417 new_node.SetAttribute("name", name); 418 parent.RemoveChildNode(*result_node); 419 return new_node; 420 } 421 else 422 { 423 return CreateEntry(entry, true); 424 } 425 } 426 427 std::vector<std::string> tConfigFile::GetChildrenNames(const std::string &entry) 428 { 429 GetEntryImplementationResult result; 430 GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 431 rrlib::xml::tNode* result_node = ChooseNodeFromResult(result, entry); 432 433 if (!result_node) 434 { 435 throw std::runtime_error("Config node not found: " + entry); 436 } 437 if (result_node->Name() == cXML_LEAF_NAME) 438 { 439 throw std::runtime_error("Config node is a leaf: " + entry); 440 } 441 442 std::vector<std::string> children_names; 443 for (auto it = result_node->ChildrenBegin(); it != result_node->ChildrenEnd(); ++it) 444 { 445 children_names.push_back(it->GetStringAttribute("name")); 446 } 447 return children_names; 448 } 449 382 450 #endif 383 451 -
tConfigFile.h
r80 r85 206 206 /*! (Wrapped) XML document */ 207 207 rrlib::xml::tDocument wrapped; 208 208 209 #endif 209 210 … … 221 222 */ 222 223 rrlib::xml::tNode& CreateEntry(const std::string& entry, bool leaf); 223 224 /*!225 * Implementation of GetEntry() - called recursively226 *227 * \param result List that will contain the result(s) as additional entry/entries after the call228 * \param entry Entry229 * \param node Current node230 * \param entry_string_index Current index in entry string231 */232 void GetEntryImplementation(std::vector<rrlib::xml::tNode*>& result, const std::string& entry, rrlib::xml::tNode& node, size_t entry_string_index);233 224 #endif 234 225
Note: See TracChangeset
for help on using the changeset viewer.