27#define SYNTAX_ERROR(line) yError() << "Syntax error while loading" << curr_filename << "at line" << line << "."
28#define SYNTAX_WARNING(line) yWarning() << "Invalid syntax while loading" << curr_filename << "at line" << line << "."
33#define TINYXML_UNSIGNED_INT_BUG 0
60 bool PerformInclusions(TiXmlNode* pParent,
const std::string& parent_fileName,
const std::string& current_path);
61 void ReplaceAllStrings(std::string& str,
const std::string& from,
const std::string& to);
92 yDebug() <<
"Reading file" << fileName.c_str();
93 auto* doc =
new TiXmlDocument(fileName.c_str());
94 if (!doc->LoadFile()) {
99 if (!doc->RootElement()) {
105 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
106 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
107 if (dtd.parse(childNode->ToUnknown(), curr_filename)) {
114 SYNTAX_WARNING(doc->Row()) <<
"No DTD found. Assuming version yarprobotinterfaceV1.0";
124 if (dtd.majorVersion != 1 || dtd.minorVersion != 0) {
125 SYNTAX_WARNING(doc->Row()) <<
"Only yarprobotinterface DTD version 1.0 is supported";
129 std::string current_path;
130 current_path = fileName.substr(0, fileName.find_last_of(
"\\/"));
131 std::string current_filename;
132 std::string log_filename;
133 current_filename = fileName.substr(fileName.find_last_of(
"\\/") + 1);
134 log_filename = current_filename.substr(0, current_filename.find(
".xml"));
135 log_filename +=
"_preprocessor_log.xml";
137 std::string enable_tags_string;
139 if (be) { enable_tags_string = be->
toString();}
141 std::string disable_tags_string;
143 if (bd) { disable_tags_string = bd->
toString();}
146 char* all_string = strdup(enable_tags_string.c_str());
148 char* token = strtok(all_string,
" ");
150 m_enabled_options_from_command_line.insert(token);
151 token = strtok(NULL,
" ");
156 char* all_string = strdup(disable_tags_string.c_str());
158 char* token = strtok(all_string,
" ");
160 m_disabled_options_from_command_line.insert(token);
161 token = strtok(NULL,
" ");
165 yInfo() <<
"Yarprobotinterface was started using the following enable_tags:"<< enable_tags_string;
166 yInfo() <<
"Yarprobotinterface was started using the following disable_tags:" << disable_tags_string;
169 PerformInclusions(doc->RootElement(), current_filename, current_path);
172 std::string all_enable_att_string =
"List of all enable attributes found in the include tags: ";
173 for (
auto it = m_enable_set_found_in_all_xml.begin(); it != m_enable_set_found_in_all_xml.end(); it++)
175 all_enable_att_string += (
" " + *it);
177 yDebug() << all_enable_att_string;
179 std::string all_disable_att_string =
"List of all disable attributes found in the include tags: ";
180 for (
auto it = m_disable_set_found_in_all_xml.begin(); it != m_disable_set_found_in_all_xml.end(); it++)
182 all_disable_att_string += (
" " + *it);
184 yDebug() << all_disable_att_string;
186 std::string full_log_withpath = current_path + std::string(
"\\") + log_filename;
187 std::replace(full_log_withpath.begin(), full_log_withpath.end(),
'\\',
'/');
188 yDebug() <<
"Preprocessor complete in: " << end_time - start_time <<
"s";
191 yDebug() <<
"Preprocessor output stored in: " << full_log_withpath;
192 doc->SaveFile(full_log_withpath);
205 curr_filename =
" XML runtime string ";
206 auto* doc =
new TiXmlDocument();
207 if (!doc->Parse(xmlString.c_str())) {
212 if (!doc->RootElement()) {
226 hrefxml_enable_tags_b.
fromString(hrefxml_enable_tags_s);
228 hrefxml_disable_tags_b.
fromString(hrefxml_disable_tags_s);
234 size_t hrefxml_enable_tags_b_size = hrefxml_enable_tags_b.
size();
235 if (hrefxml_enable_tags_b_size != 0)
240 for (
size_t i = 0; i < hrefxml_enable_tags_b_size; i++)
242 std::string s = hrefxml_enable_tags_b.
get(i).
asString();
243 m_enable_set_found_in_all_xml.insert(s);
244 if (m_enabled_options_from_command_line.find(s) != m_enabled_options_from_command_line.end() ||
245 m_enabled_options_from_command_line.find(
"enable_all") != m_enabled_options_from_command_line.end())
253 size_t hrefxml_disable_tags_b_size = hrefxml_disable_tags_b.
size();
254 for (
size_t i = 0; i < hrefxml_disable_tags_b_size; i++)
256 std::string s = hrefxml_disable_tags_b.
get(i).
asString();
257 m_disable_set_found_in_all_xml.insert(s);
258 if (m_disabled_options_from_command_line.find(s) != m_disabled_options_from_command_line.end())
270 for (TiXmlElement* childElem = pParent->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
273 if (childElem->FirstAttribute())
274 a = childElem->FirstAttribute()->Value();
275 yDebug() <<
"Parsing" << childElem->Value() << a;
277 std::string elemString = childElem->ValueStr();
278 if (elemString ==
"file") {
279 yFatal() <<
"'file' attribute is forbidden in yarprobotinterface DTD format 3.0. Error found in " << parent_fileName;
283 if (elemString ==
"xi:include")
285 std::string href_filename;
286 if (childElem->QueryStringAttribute(
"href", &href_filename) == TIXML_SUCCESS)
288 std::string href_enable_tags, href_disable_tags;
289 childElem->QueryStringAttribute(
"enabled_by", &href_enable_tags);
290 childElem->QueryStringAttribute(
"disabled_by", &href_disable_tags);
291 if (CheckIfIncludeSectionIsEnabled(href_enable_tags, href_disable_tags))
293 std::string included_path = std::string(current_path).append(
"\\").append(href_filename.substr(0, href_filename.find_last_of(
"\\/")));
294 std::string included_filename = href_filename.substr(href_filename.find_last_of(
"\\/") + 1);
295 std::string full_path_file = std::string(included_path).append(
"\\").append(included_filename);
296 TiXmlDocument included_file;
298 std::replace(full_path_file.begin(), full_path_file.end(),
'\\',
'/');
299 if (included_file.LoadFile(full_path_file))
301 PerformInclusions(included_file.RootElement(), included_filename, included_path);
303 included_file.RootElement()->RemoveAttribute(
"xmlns:xi");
304 if (pParent->ReplaceChild(childElem, *included_file.FirstChildElement()))
312 yFatal() <<
"Failed to include: " << included_filename <<
" in: " << parent_fileName;
319 yError() << included_file.ErrorDesc() <<
" file" << full_path_file <<
"included by " << parent_fileName <<
"at line" << childElem->Row();
320 yFatal() <<
"In file:" << included_filename <<
" included by: " << parent_fileName <<
" at line: " << childElem->Row();
326 yDebug() <<
"Skipping include section `" << href_filename <<
"` because is not enabled";
327 if (pParent->RemoveChild(childElem))
337 yFatal() <<
"Syntax error in: " << parent_fileName <<
" while searching for href attribute";
341 PerformInclusions(childElem, parent_fileName, current_path);
351 if (robotElem->ValueStr() !=
"robot") {
352 SYNTAX_ERROR(robotElem->Row()) <<
"Root element should be \"robot\". Found" << robotElem->ValueStr();
356 if (robotElem->QueryStringAttribute(
"name", &result.
robot.
name()) != TIXML_SUCCESS) {
357 SYNTAX_ERROR(robotElem->Row()) << R
"("robot" element should contain the "name" attribute)";
361#if TINYXML_UNSIGNED_INT_BUG
362 if (robotElem->QueryUnsignedAttribute(
"build", &result.
robot.
build()) != TIXML_SUCCESS) {
364 SYNTAX_WARNING(robotElem->Row()) <<
"\"robot\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
368 if (robotElem->QueryIntAttribute(
"build", &tmp) != TIXML_SUCCESS || tmp < 0) {
370 SYNTAX_WARNING(robotElem->Row()) << R
"("robot" element should contain the "build" attribute [unsigned int]. Assuming 0)";
373 result.robot.build() = static_cast<unsigned>(tmp);
377 if (!config.check(
"portprefix"))
379 if (robotElem->QueryStringAttribute(
"portprefix", &result.
robot.
portprefix()) != TIXML_SUCCESS) {
380 SYNTAX_WARNING(robotElem->Row()) << R
"("robot" element should contain the "portprefix" attribute. Using "name" attribute)";
389 bool reverse =
false;
390 if (robotElem->QueryBoolAttribute(
"reverse-shutdown-action-order", &reverse) == TIXML_WRONG_TYPE) {
391 SYNTAX_ERROR(robotElem->Row()) << R
"(The "reverse-shutdown-action-order" attribute in the "robot" element should be a bool.)";
398 for (TiXmlElement* childElem = robotElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
399 std::string elemString = childElem->ValueStr();
400 if (elemString ==
"device" || elemString ==
"devices") {
401 for (
const auto& childDevice : readDevices(childElem, result)) {
405 for (
const auto& childParam : readParams(childElem, result)) {
418 const std::string& valueStr = devicesElem->ValueStr();
420 if (valueStr ==
"device") {
423 deviceList.push_back(readDeviceTag(devicesElem, result));
426 if (valueStr ==
"devices") {
428 return readDevicesTag(devicesElem, result);
431 SYNTAX_ERROR(devicesElem->Row()) << R
"(Expected "device" or "devices". Found)" << valueStr;
439 const std::string& valueStr = deviceElem->ValueStr();
441 if (valueStr !=
"device") {
442 SYNTAX_ERROR(deviceElem->Row()) <<
"Expected \"device\". Found" << valueStr;
449 if (deviceElem->QueryStringAttribute(
"name", &device.
name()) != TIXML_SUCCESS) {
450 SYNTAX_ERROR(deviceElem->Row()) << R
"("device" element should contain the "name" attribute)";
457 if (deviceElem->QueryStringAttribute(
"type", &device.
type()) != TIXML_SUCCESS) {
458 SYNTAX_ERROR(deviceElem->Row()) << R
"("device" element should contain the "type" attribute)";
465 for (TiXmlElement* childElem = deviceElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
466 if (childElem->ValueStr() ==
"action" || childElem->ValueStr() ==
"actions") {
467 for (
const auto& childAction : readActions(childElem, result)) {
468 device.
actions().push_back(childAction);
471 for (
const auto& childParam : readParams(childElem, result)) {
472 device.
params().push_back(childParam);
489 for (TiXmlElement* childElem = devicesElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
490 if (childElem->ValueStr() ==
"param" || childElem->ValueStr() ==
"group" || childElem->ValueStr() ==
"paramlist" || childElem->ValueStr() ==
"params") {
491 for (
const auto& childParam : readParams(childElem, result)) {
492 params.push_back(childParam);
495 for (
const auto& childDevice : readDevices(childElem, result)) {
496 devices.push_back(childDevice);
502 for (
auto& device : devices) {
503 device.
params().insert(device.params().begin(), params.begin(), params.end());
512 const std::string& valueStr = paramsElem->ValueStr();
514 if (valueStr ==
"param") {
516 params.push_back(readParamTag(paramsElem, result));
519 if (valueStr ==
"group") {
521 params.push_back(readGroupTag(paramsElem, result));
524 if (valueStr ==
"paramlist") {
525 return readParamListTag(paramsElem, result);
527 if (valueStr ==
"params") {
528 return readParamsTag(paramsElem, result);
531 SYNTAX_ERROR(paramsElem->Row()) << R
"(Expected "param", "group", "paramlist", or "params". Found)" << valueStr;
540 size_t start_pos = 0;
541 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
542 str.replace(start_pos, from.length(), to);
543 start_pos += to.length();
551 if (paramElem->ValueStr() !=
"param") {
552 SYNTAX_ERROR(paramElem->Row()) <<
"Expected \"param\". Found" << paramElem->ValueStr();
559 if (paramElem->QueryStringAttribute(
"name", ¶m.
name()) != TIXML_SUCCESS) {
560 SYNTAX_ERROR(paramElem->Row()) << R
"("param" element should contain the "name" attribute)";
567 const char* valueText = paramElem->GetText();
569 SYNTAX_ERROR(paramElem->Row()) << R
"("param" element should have a value [ "name" = )" << param.name() << "]";
575 std::string extern_name;
576 if (paramElem->QueryStringAttribute(
"extern-name", &extern_name) == TIXML_SUCCESS && config.check(extern_name)) {
578 if (config.find(extern_name).isList())
580 param.
value() =
"(" + config.find(extern_name).asList()->toString() +
")";
584 param.
value() = config.find(extern_name).toString();
587 param.
value() = valueText;
591 std::string paramValueBefore = param.
value();
592 std::string paramValueAfter = paramValueBefore;
593 std::string portprefix = config.find(
"portprefix").toString();
594 ReplaceAllStrings(paramValueAfter,
"${portprefix}", portprefix);
595 param.
value() = paramValueAfter;
606 if (groupElem->ValueStr() !=
"group") {
607 SYNTAX_ERROR(groupElem->Row()) <<
"Expected \"group\". Found" << groupElem->ValueStr();
614 if (groupElem->QueryStringAttribute(
"name", &group.
name()) != TIXML_SUCCESS) {
615 SYNTAX_ERROR(groupElem->Row()) << R
"("group" element should contain the "name" attribute)";
623 for (TiXmlElement* childElem = groupElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
624 for (
const auto& childParam : readParams(childElem, result)) {
625 params.push_back(childParam);
628 if (params.empty()) {
629 SYNTAX_ERROR(groupElem->Row()) <<
"\"group\" cannot be empty";
634 std::string groupString;
635 for (
auto& param : params) {
636 if (!groupString.empty()) {
639 groupString +=
"(" + param.name() +
" " + param.value() +
")";
642 group.
value() = groupString;
650 if (paramListElem->ValueStr() !=
"paramlist") {
651 SYNTAX_ERROR(paramListElem->Row()) <<
"Expected \"paramlist\". Found" << paramListElem->ValueStr();
659 if (paramListElem->QueryStringAttribute(
"name", &mainparam.
name()) != TIXML_SUCCESS) {
660 SYNTAX_ERROR(paramListElem->Row()) << R
"("paramlist" element should contain the "name" attribute)";
665 params.push_back(mainparam);
669 for (TiXmlElement* childElem = paramListElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
670 if (childElem->ValueStr() !=
"elem") {
671 SYNTAX_ERROR(childElem->Row()) <<
"Expected \"elem\". Found" << childElem->ValueStr();
678 if (childElem->QueryStringAttribute(
"name", &childParam.
name()) != TIXML_SUCCESS) {
679 SYNTAX_ERROR(childElem->Row()) << R
"("elem" element should contain the "name" attribute)";
684 const char* valueText = childElem->GetText();
686 SYNTAX_ERROR(childElem->Row()) << R
"("elem" element should have a value [ "name" = )" << childParam.name() << "]";
690 childParam.
value() = valueText;
692 params.push_back(childParam);
695 if (params.empty()) {
696 SYNTAX_ERROR(paramListElem->Row()) <<
"\"paramlist\" cannot be empty";
702 for (
auto it = params.begin() + 1; it != params.end(); ++it) {
704 params.at(0).
value() += (params.at(0).value().empty() ?
"(" :
" ") + param.
name();
706 params.at(0).value() +=
")";
718 for (TiXmlElement* childElem = paramsElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
719 for (
const auto & childParam : readParams(childElem, result)) {
720 params.push_back(childParam);
730 const std::string& valueStr = actionsElem->ValueStr();
732 if (valueStr !=
"action" && valueStr !=
"actions") {
733 SYNTAX_ERROR(actionsElem->Row()) << R
"(Expected "action" or "actions". Found)" << valueStr;
736 if (valueStr ==
"action") {
738 actionList.push_back(readActionTag(actionsElem, result));
742 return readActionsTag(actionsElem, result);
748 if (actionElem->ValueStr() !=
"action") {
749 SYNTAX_ERROR(actionElem->Row()) <<
"Expected \"action\". Found" << actionElem->ValueStr();
757 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "phase" attribute [startup|interrupt{1,2,3}|shutdown])";
764 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "type" attribute [configure|calibrate|attach|abort|detach|park|custom])";
771#if TINYXML_UNSIGNED_INT_BUG
772 if (actionElem->QueryUnsignedAttribute(
"level", &action.
level()) != TIXML_SUCCESS) {
773 SYNTAX_ERROR(actionElem->Row()) <<
"\"action\" element should contain the \"level\" attribute [unsigned int]";
777 if (actionElem->QueryIntAttribute(
"level", &tmp) != TIXML_SUCCESS || tmp < 0) {
778 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "level" attribute [unsigned int])";
782 action.
level() =
static_cast<unsigned>(tmp);
785 for (TiXmlElement* childElem = actionElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
786 for (
const auto& childParam : readParams(childElem, result)) {
787 action.
params().push_back(childParam);
800 std::string robotName;
801 if (actionsElem->QueryStringAttribute(
"robot", &robotName) != TIXML_SUCCESS) {
802 SYNTAX_WARNING(actionsElem->Row()) << R
"("actions" element should contain the "robot" attribute)";
806 SYNTAX_WARNING(actionsElem->Row()) <<
"Trying to import a file for the wrong robot. Found" << robotName <<
"instead of" << result.
robot.
name();
810#if TINYXML_UNSIGNED_INT_BUG
811 if (actionsElem->QueryUnsignedAttribute(
"build", &build()) != TIXML_SUCCESS) {
813 SYNTAX_WARNING(actionsElem->Row()) <<
"\"actions\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
817 if (actionsElem->QueryIntAttribute(
"build", &tmp) != TIXML_SUCCESS || tmp < 0) {
819 SYNTAX_WARNING(actionsElem->Row()) << R
"("actions" element should contain the "build" attribute [unsigned int]. Assuming 0)";
822 build = static_cast<unsigned>(tmp);
826 SYNTAX_WARNING(actionsElem->Row()) <<
"Import a file for a different robot build. Found" << build <<
"instead of" << result.
robot.
build();
830 for (TiXmlElement* childElem = actionsElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
831 for (
const auto & childAction : readActions(childElem, result)) {
832 actions.push_back(childAction);
#define SYNTAX_ERROR(line)
#define SYNTAX_WARNING(line)
A simple collection of objects that can be described and transmitted in a portable way.
void fromString(const std::string &text)
Initializes bottle from a string.
size_type size() const
Gets the number of elements in the bottle.
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
A class for storing options and configuration information.
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
void clear()
Remove all associations.
A base class for nested structures that can be searched.
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
virtual Bottle * asList() const
Get list value.
virtual std::string asString() const
Get string value.
std::string & portprefix()
void setReverseShutdownActionOrder(bool reverseShutdownActionOrder)
Result of the parsing of yarp::robotinterface::XMLReader.
bool parsingIsSuccessful
True if the parsing was successful, false otherwise.
Robot robot
If parsingIsSuccessful is true, contains a valid robot instance.
static XMLReaderResult ParsingFailed()
unsigned int majorVersion
yarp::os::Property config
void ReplaceAllStrings(std::string &str, const std::string &from, const std::string &to)
yarp::robotinterface::Device readDeviceTag(TiXmlElement *deviceElem, yarp::robotinterface::XMLReaderResult &result)
unsigned int minorVersion
yarp::robotinterface::Param readParamTag(TiXmlElement *paramElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult readRobotFromString(const std::string &xmlString)
std::set< std::string > m_disabled_options_from_command_line
yarp::robotinterface::ActionList readActionsTag(TiXmlElement *actionsElem, yarp::robotinterface::XMLReaderResult &result)
Private(XMLReaderFileV3 *parent)
yarp::robotinterface::DeviceList readDevices(TiXmlElement *devicesElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParamListTag(TiXmlElement *paramListElem, yarp::robotinterface::XMLReaderResult &result)
bool PerformInclusions(TiXmlNode *pParent, const std::string &parent_fileName, const std::string ¤t_path)
yarp::robotinterface::XMLReaderResult readRobotTag(TiXmlElement *robotElem)
bool CheckIfIncludeSectionIsEnabled(const std::string &href_enable_tags, const std::string &href_disable_tags)
yarp::robotinterface::Param readGroupTag(TiXmlElement *groupElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParams(TiXmlElement *paramsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::DeviceList readDevicesTag(TiXmlElement *devicesElem, yarp::robotinterface::XMLReaderResult &result)
std::set< std::string > m_disable_set_found_in_all_xml
yarp::robotinterface::ActionList readActions(TiXmlElement *actionsElem, yarp::robotinterface::XMLReaderResult &result)
XMLReaderFileV3 *const parent
yarp::robotinterface::Action readActionTag(TiXmlElement *actionElem, yarp::robotinterface::XMLReaderResult &result)
std::string curr_filename
std::set< std::string > m_enabled_options_from_command_line
yarp::robotinterface::ParamList readParamsTag(TiXmlElement *paramsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult readRobotFromFile(const std::string &fileName)
std::set< std::string > m_enable_set_found_in_all_xml
yarp::robotinterface::XMLReaderResult getRobotFromString(const std::string &xmlString, const yarp::os::Searchable &config, bool verbose=false) override
yarp::robotinterface::XMLReaderResult getRobotFromFile(const std::string &filename, const yarp::os::Searchable &config, bool verbose=false) override
~XMLReaderFileV3() override
double now()
Return the current time in seconds, relative to an arbitrary starting point.
std::string DocTypeToString(RobotInterfaceDTD::DocType doctype)
std::vector< robotinterface::Action > ActionList
std::vector< robotinterface::Param > ParamList
std::vector< robotinterface::Device > DeviceList