forked from Kistler-Group/sdbus-cpp
Move code generator to tools subdirectory for higher consistency with OSS standards
This commit is contained in:
52
tools/CMakeLists.txt
Normal file
52
tools/CMakeLists.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
#-------------------------------
|
||||
# PROJECT INFORMATION
|
||||
#-------------------------------
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(sdbus-c++-xml2cpp)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
#-------------------------------
|
||||
# PERFORMING CHECKS
|
||||
#-------------------------------
|
||||
|
||||
find_package(EXPAT REQUIRED)
|
||||
|
||||
#-------------------------------
|
||||
# SOURCE FILES CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(SDBUSCPP_XML2CPP_SRCS
|
||||
xml2cpp-codegen/xml2cpp.cpp
|
||||
xml2cpp-codegen/xml.h
|
||||
xml2cpp-codegen/xml.cpp
|
||||
xml2cpp-codegen/generator_utils.h
|
||||
xml2cpp-codegen/generator_utils.cpp
|
||||
xml2cpp-codegen/BaseGenerator.h
|
||||
xml2cpp-codegen/BaseGenerator.cpp
|
||||
xml2cpp-codegen/AdaptorGenerator.h
|
||||
xml2cpp-codegen/AdaptorGenerator.cpp
|
||||
xml2cpp-codegen/ProxyGenerator.h
|
||||
xml2cpp-codegen/ProxyGenerator.cpp)
|
||||
|
||||
#-------------------------------
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
#----------------------------------
|
||||
# EXECUTABLE BUILD INFORMATION
|
||||
#----------------------------------
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SDBUSCPP_XML2CPP_SRCS})
|
||||
|
||||
target_link_libraries (${PROJECT_NAME} ${EXPAT_LIBRARIES})
|
||||
|
||||
#----------------------------------
|
||||
# INSTALLATION
|
||||
#----------------------------------
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
371
tools/xml2cpp-codegen/AdaptorGenerator.cpp
Normal file
371
tools/xml2cpp-codegen/AdaptorGenerator.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file AdaptorGenerator.cpp
|
||||
*
|
||||
* Created on: Feb 1, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "generator_utils.h"
|
||||
#include "AdaptorGenerator.h"
|
||||
|
||||
// STL
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
using std::endl;
|
||||
|
||||
using sdbuscpp::xml::Document;
|
||||
using sdbuscpp::xml::Node;
|
||||
using sdbuscpp::xml::Nodes;
|
||||
|
||||
/**
|
||||
* Generate adaptor code - server glue
|
||||
*/
|
||||
int AdaptorGenerator::transformXmlToFileImpl(const Document& doc, const char* filename) const
|
||||
{
|
||||
Node &root = *(doc.root);
|
||||
Nodes interfaces = root["interface"];
|
||||
|
||||
std::ostringstream code;
|
||||
code << createHeader(filename, StubType::ADAPTOR);
|
||||
|
||||
for (const auto& interface : interfaces)
|
||||
{
|
||||
code << processInterface(*interface);
|
||||
}
|
||||
|
||||
code << "#endif" << endl;
|
||||
|
||||
return writeToFile(filename, code.str());
|
||||
}
|
||||
|
||||
|
||||
std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
{
|
||||
std::string ifaceName = interface.get("name");
|
||||
std::cout << "Generating adaptor code for interface " << ifaceName << endl;
|
||||
|
||||
unsigned int namespacesCount = 0;
|
||||
std::string namespacesStr;
|
||||
std::tie(namespacesCount, namespacesStr) = generateNamespaces(ifaceName);
|
||||
|
||||
std::ostringstream body;
|
||||
body << namespacesStr;
|
||||
|
||||
std::string className = ifaceName.substr(ifaceName.find_last_of(".") + 1)
|
||||
+ "_adaptor";
|
||||
|
||||
body << "class " << className << endl
|
||||
<< "{" << endl
|
||||
<< "public:" << endl
|
||||
<< tab << "static constexpr const char* interfaceName = \"" << ifaceName << "\";" << endl << endl
|
||||
<< "protected:" << endl
|
||||
<< tab << className << "(sdbus::IObject& object)" << endl
|
||||
<< tab << tab << ": object_(object)" << endl;
|
||||
|
||||
Nodes methods = interface["method"];
|
||||
Nodes signals = interface["signal"];
|
||||
Nodes properties = interface["property"];
|
||||
|
||||
auto annotations = getAnnotations(interface);
|
||||
std::string annotationRegistration;
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
const auto& annotationName = annotation.first;
|
||||
const auto& annotationValue = annotation.second;
|
||||
|
||||
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsDeprecated()";
|
||||
else if (annotationName == "org.freedesktop.systemd1.Privileged" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsPrivileged()";
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.EmitsChangedSignal")
|
||||
annotationRegistration += ".withPropertyUpdateBehavior(" + propertyAnnotationToFlag(annotationValue) + ")";
|
||||
else
|
||||
std::cerr << "Node: " << ifaceName << ": "
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
if(!annotationRegistration.empty())
|
||||
{
|
||||
std::stringstream str;
|
||||
str << tab << tab << "object_.setInterfaceFlags(interfaceName)" << annotationRegistration << ";" << endl;
|
||||
annotationRegistration = str.str();
|
||||
}
|
||||
|
||||
std::string methodRegistration, methodDeclaration;
|
||||
std::tie(methodRegistration, methodDeclaration) = processMethods(methods);
|
||||
|
||||
std::string signalRegistration, signalMethods;
|
||||
std::tie(signalRegistration, signalMethods) = processSignals(signals);
|
||||
|
||||
std::string propertyRegistration, propertyAccessorDeclaration;
|
||||
std::tie(propertyRegistration, propertyAccessorDeclaration) = processProperties(properties);
|
||||
|
||||
body << tab << "{" << endl
|
||||
<< annotationRegistration
|
||||
<< methodRegistration
|
||||
<< signalRegistration
|
||||
<< propertyRegistration
|
||||
<< tab << "}" << endl << endl;
|
||||
|
||||
if (!signalMethods.empty())
|
||||
{
|
||||
body << "public:" << endl << signalMethods;
|
||||
}
|
||||
|
||||
if (!methodDeclaration.empty())
|
||||
{
|
||||
body << "private:" << endl << methodDeclaration << endl;
|
||||
}
|
||||
|
||||
if (!propertyAccessorDeclaration.empty())
|
||||
{
|
||||
body << "private:" << endl << propertyAccessorDeclaration << endl;
|
||||
}
|
||||
|
||||
body << "private:" << endl
|
||||
<< tab << "sdbus::IObject& object_;" << endl
|
||||
<< "};" << endl << endl
|
||||
<< std::string(namespacesCount, '}') << " // namespaces" << endl << endl;
|
||||
|
||||
return body.str();
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Nodes& methods) const
|
||||
{
|
||||
std::ostringstream registrationSS, declarationSS;
|
||||
|
||||
for (const auto& method : methods)
|
||||
{
|
||||
auto methodName = method->get("name");
|
||||
|
||||
auto annotations = getAnnotations(*method);
|
||||
bool async{false};
|
||||
std::string annotationRegistration;
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
const auto& annotationName = annotation.first;
|
||||
const auto& annotationValue = annotation.second;
|
||||
|
||||
if (annotationName == "org.freedesktop.DBus.Deprecated")
|
||||
{
|
||||
if (annotationValue == "true")
|
||||
annotationRegistration += ".markAsDeprecated()";
|
||||
}
|
||||
else if (annotationName == "org.freedesktop.DBus.Method.NoReply")
|
||||
{
|
||||
if (annotationValue == "true")
|
||||
annotationRegistration += ".withNoReply()";
|
||||
}
|
||||
else if (annotationName == "org.freedesktop.DBus.Method.Async")
|
||||
{
|
||||
if (annotationValue == "server" || annotationValue == "clientserver")
|
||||
async = true;
|
||||
}
|
||||
else if (annotationName == "org.freedesktop.systemd1.Privileged")
|
||||
{
|
||||
if (annotationValue == "true")
|
||||
annotationRegistration += ".markAsPrivileged()";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Node: " << methodName << ": "
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Nodes args = (*method)["arg"];
|
||||
Nodes inArgs = args.select("direction" , "in");
|
||||
Nodes outArgs = args.select("direction" , "out");
|
||||
|
||||
std::string argStr, argTypeStr;
|
||||
std::tie(argStr, argTypeStr, std::ignore) = argsToNamesAndTypes(inArgs, async);
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
registrationSS << tab << tab << "object_.registerMethod(\""
|
||||
<< methodName << "\")"
|
||||
<< ".onInterface(interfaceName)"
|
||||
<< ".implementedAs("
|
||||
<< "[this]("
|
||||
<< (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + ">&& result" + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< argTypeStr
|
||||
<< "){ " << (async ? "" : "return ") << "this->" << methodName << "("
|
||||
<< (async ? "std::move(result)"s + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< argStr << "); })"
|
||||
<< annotationRegistration << ";" << endl;
|
||||
|
||||
declarationSS << tab
|
||||
<< "virtual "
|
||||
<< (async ? "void" : outArgsToType(outArgs))
|
||||
<< " " << methodName
|
||||
<< "("
|
||||
<< (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + ">&& result" + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< argTypeStr
|
||||
<< ") = 0;" << endl;
|
||||
}
|
||||
|
||||
return std::make_tuple(registrationSS.str(), declarationSS.str());
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Nodes& signals) const
|
||||
{
|
||||
std::ostringstream signalRegistrationSS, signalMethodSS;
|
||||
|
||||
for (const auto& signal : signals)
|
||||
{
|
||||
auto name = signal->get("name");
|
||||
|
||||
auto annotations = getAnnotations(*signal);
|
||||
std::string annotationRegistration;
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
const auto& annotationName = annotation.first;
|
||||
const auto& annotationValue = annotation.second;
|
||||
|
||||
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsDeprecated()";
|
||||
else
|
||||
std::cerr << "Node: " << name << ": "
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
|
||||
Nodes args = (*signal)["arg"];
|
||||
|
||||
std::string argStr, argTypeStr, typeStr;;
|
||||
std::tie(argStr, argTypeStr, typeStr) = argsToNamesAndTypes(args);
|
||||
|
||||
signalRegistrationSS << tab << tab
|
||||
<< "object_.registerSignal(\"" << name << "\")"
|
||||
".onInterface(interfaceName)";
|
||||
|
||||
if (args.size() > 0)
|
||||
{
|
||||
signalRegistrationSS << ".withParameters<" << typeStr << ">()";
|
||||
}
|
||||
|
||||
signalRegistrationSS << annotationRegistration;
|
||||
signalRegistrationSS << ";" << endl;
|
||||
|
||||
signalMethodSS << tab << "void " << name << "(" << argTypeStr << ")" << endl
|
||||
<< tab << "{" << endl
|
||||
<< tab << tab << "object_.emitSignal(\"" << name << "\")"
|
||||
".onInterface(interfaceName)";
|
||||
|
||||
if (!argStr.empty())
|
||||
{
|
||||
signalMethodSS << ".withArguments(" << argStr << ")";
|
||||
}
|
||||
|
||||
signalMethodSS << ";" << endl
|
||||
<< tab << "}" << endl << endl;
|
||||
}
|
||||
|
||||
return std::make_tuple(signalRegistrationSS.str(), signalMethodSS.str());
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const Nodes& properties) const
|
||||
{
|
||||
std::ostringstream registrationSS, declarationSS;
|
||||
|
||||
for (const auto& property : properties)
|
||||
{
|
||||
auto propertyName = property->get("name");
|
||||
auto propertyAccess = property->get("access");
|
||||
auto propertySignature = property->get("type");
|
||||
|
||||
auto propertyType = signature_to_type(propertySignature);
|
||||
auto propertyArg = std::string("value");
|
||||
auto propertyTypeArg = std::string("const ") + propertyType + "& " + propertyArg;
|
||||
|
||||
auto annotations = getAnnotations(*property);
|
||||
std::string annotationRegistration;
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
const auto& annotationName = annotation.first;
|
||||
const auto& annotationValue = annotation.second;
|
||||
|
||||
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsDeprecated()";
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.EmitsChangedSignal")
|
||||
annotationRegistration += ".withUpdateBehavior(" + propertyAnnotationToFlag(annotationValue) + ")";
|
||||
else if (annotationName == "org.freedesktop.systemd1.Privileged" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsPrivileged()";
|
||||
else
|
||||
std::cerr << "Node: " << propertyName << ": "
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
|
||||
registrationSS << tab << tab << "object_.registerProperty(\""
|
||||
<< propertyName << "\")"
|
||||
<< ".onInterface(interfaceName)";
|
||||
|
||||
if (propertyAccess == "read" || propertyAccess == "readwrite")
|
||||
{
|
||||
registrationSS << ".withGetter([this](){ return this->" << propertyName << "(); })";
|
||||
}
|
||||
|
||||
if (propertyAccess == "readwrite" || propertyAccess == "write")
|
||||
{
|
||||
registrationSS
|
||||
<< ".withSetter([this](" << propertyTypeArg << ")"
|
||||
"{ this->" << propertyName << "(" << propertyArg << "); })";
|
||||
}
|
||||
|
||||
registrationSS << annotationRegistration;
|
||||
registrationSS << ";" << endl;
|
||||
|
||||
if (propertyAccess == "read" || propertyAccess == "readwrite")
|
||||
declarationSS << tab << "virtual " << propertyType << " " << propertyName << "() = 0;" << endl;
|
||||
if (propertyAccess == "readwrite" || propertyAccess == "write")
|
||||
declarationSS << tab << "virtual void " << propertyName << "(" << propertyTypeArg << ") = 0;" << endl;
|
||||
}
|
||||
|
||||
return std::make_tuple(registrationSS.str(), declarationSS.str());
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> AdaptorGenerator::getAnnotations( sdbuscpp::xml::Node& node) const
|
||||
{
|
||||
std::map<std::string, std::string> result;
|
||||
|
||||
Nodes annotations = (node)["annotation"];
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
result[annotation->get("name")] = annotation->get("value");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string AdaptorGenerator::propertyAnnotationToFlag(const std::string& annotationValue) const
|
||||
{
|
||||
return annotationValue == "true" ? "sdbus::Flags::EMITS_CHANGE_SIGNAL"
|
||||
: annotationValue == "invalidates" ? "sdbus::Flags::EMITS_INVALIDATION_SIGNAL"
|
||||
: annotationValue == "const" ? "sdbus::Flags::CONST_PROPERTY_VALUE"
|
||||
: annotationValue == "false" ? "sdbus::Flags::EMITS_NO_SIGNAL"
|
||||
: "EMITS_CHANGE_SIGNAL"; // Default
|
||||
}
|
94
tools/xml2cpp-codegen/AdaptorGenerator.h
Normal file
94
tools/xml2cpp-codegen/AdaptorGenerator.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file AdaptorGenerator.h
|
||||
*
|
||||
* Created on: Feb 1, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SDBUSCPP_TOOLS_ADAPTOR_GENERATOR_H
|
||||
#define __SDBUSCPP_TOOLS_ADAPTOR_GENERATOR_H
|
||||
|
||||
// Own headers
|
||||
#include "xml.h"
|
||||
#include "BaseGenerator.h"
|
||||
|
||||
// STL
|
||||
#include <tuple>
|
||||
#include <set>
|
||||
|
||||
class AdaptorGenerator : public BaseGenerator
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* Transform xml to adaptor code
|
||||
* @param doc
|
||||
* @param filename
|
||||
* @return 0 if ok
|
||||
*/
|
||||
int transformXmlToFileImpl(const sdbuscpp::xml::Document& doc, const char* filename) const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Generate source code for interface
|
||||
* @param interface
|
||||
* @return source code
|
||||
*/
|
||||
std::string processInterface(sdbuscpp::xml::Node& interface) const;
|
||||
|
||||
/**
|
||||
* Generate source code for methods
|
||||
* @param methods
|
||||
* @return tuple: registration of methods, declaration of abstract methods
|
||||
*/
|
||||
std::tuple<std::string, std::string> processMethods(const sdbuscpp::xml::Nodes& methods) const;
|
||||
|
||||
/**
|
||||
* Generate source code for signals
|
||||
* @param signals
|
||||
* @return tuple: registration of signals, definition of signal methods
|
||||
*/
|
||||
std::tuple<std::string, std::string> processSignals(const sdbuscpp::xml::Nodes& signals) const;
|
||||
|
||||
/**
|
||||
* Generate source code for properties
|
||||
* @param properties
|
||||
* @return tuple: registration of properties, declaration of property accessor virtual methods
|
||||
*/
|
||||
std::tuple<std::string, std::string> processProperties(const sdbuscpp::xml::Nodes& properties) const;
|
||||
|
||||
/**
|
||||
* Get annotations listed for a given node
|
||||
* @param node
|
||||
* @return map of annotation names to their values
|
||||
*/
|
||||
std::map<std::string, std::string> getAnnotations(sdbuscpp::xml::Node& node) const;
|
||||
|
||||
/**
|
||||
* Get flag for property update behavior annotation value
|
||||
* @param annotationValue
|
||||
* @return flag
|
||||
*/
|
||||
std::string propertyAnnotationToFlag(const std::string& annotationValue) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //__SDBUSCPP_TOOLS_ADAPTOR_GENERATOR_H
|
180
tools/xml2cpp-codegen/BaseGenerator.cpp
Normal file
180
tools/xml2cpp-codegen/BaseGenerator.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file BaseGenerator.cpp
|
||||
*
|
||||
* Created on: Feb 1, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "generator_utils.h"
|
||||
#include "BaseGenerator.h"
|
||||
|
||||
// STL
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
using std::endl;
|
||||
|
||||
using sdbuscpp::xml::Document;
|
||||
using sdbuscpp::xml::Node;
|
||||
using sdbuscpp::xml::Nodes;
|
||||
|
||||
|
||||
int BaseGenerator::transformXmlToFile(const Document& doc, const char* filename) const
|
||||
{
|
||||
return transformXmlToFileImpl(doc, filename);
|
||||
}
|
||||
|
||||
|
||||
int BaseGenerator::writeToFile(const char* filename, const std::string& data) const
|
||||
{
|
||||
std::ofstream file(filename);
|
||||
if (file.bad())
|
||||
{
|
||||
std::cerr << "Unable to write file " << filename << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
file << data;
|
||||
file.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string BaseGenerator::createHeader(const char* filename, const StubType& stubType) const
|
||||
{
|
||||
std::ostringstream head;
|
||||
head << getHeaderComment();
|
||||
|
||||
std::string specialization = stubType == StubType::ADAPTOR ? "adaptor" : "proxy";
|
||||
|
||||
std::string cond_comp{"__sdbuscpp__" + underscorize(filename)
|
||||
+ "__" + specialization + "__H__"};
|
||||
|
||||
head << "#ifndef " << cond_comp << endl
|
||||
<< "#define " << cond_comp << endl << endl;
|
||||
|
||||
head << "#include <sdbus-c++/sdbus-c++.h>" << endl
|
||||
<< "#include <string>" << endl
|
||||
<< "#include <tuple>" << endl
|
||||
<< endl;
|
||||
|
||||
return head.str();
|
||||
}
|
||||
|
||||
std::tuple<unsigned, std::string> BaseGenerator::generateNamespaces(const std::string& ifaceName) const
|
||||
{
|
||||
std::stringstream ss{ifaceName};
|
||||
std::ostringstream body;
|
||||
unsigned count{0};
|
||||
|
||||
// prints the namespaces X and Y defined with <interface name="X.Y.Z">
|
||||
while (ss.str().find('.', ss.tellg()) != std::string::npos)
|
||||
{
|
||||
std::string nspace;
|
||||
getline(ss, nspace, '.');
|
||||
body << "namespace " << nspace << " {" << endl;
|
||||
++count;
|
||||
}
|
||||
body << endl;
|
||||
|
||||
return std::make_tuple(count, body.str());
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string, std::string> BaseGenerator::argsToNamesAndTypes(const Nodes& args, bool async) const
|
||||
{
|
||||
std::ostringstream argSS, argTypeSS, typeSS;
|
||||
|
||||
for (size_t i = 0; i < args.size(); ++i)
|
||||
{
|
||||
auto arg = args.at(i);
|
||||
if (i > 0)
|
||||
{
|
||||
argSS << ", ";
|
||||
argTypeSS << ", ";
|
||||
typeSS << ", ";
|
||||
}
|
||||
|
||||
auto argName = arg->get("name");
|
||||
if (argName.empty())
|
||||
{
|
||||
argName = "arg" + std::to_string(i);
|
||||
}
|
||||
auto type = signature_to_type(arg->get("type"));
|
||||
if (!async)
|
||||
{
|
||||
argSS << argName;
|
||||
argTypeSS << "const " << type << "& " << argName;
|
||||
}
|
||||
else
|
||||
{
|
||||
argSS << "std::move(" << argName << ")";
|
||||
argTypeSS << type << " " << argName;
|
||||
}
|
||||
typeSS << type;
|
||||
}
|
||||
|
||||
return std::make_tuple(argSS.str(), argTypeSS.str(), typeSS.str());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::string BaseGenerator::outArgsToType(const Nodes& args, bool bareList) const
|
||||
{
|
||||
std::ostringstream retTypeSS;
|
||||
|
||||
if (args.size() == 0)
|
||||
{
|
||||
if (bareList)
|
||||
return "";
|
||||
|
||||
retTypeSS << "void";
|
||||
}
|
||||
else if (args.size() == 1)
|
||||
{
|
||||
const auto& arg = *args.begin();
|
||||
retTypeSS << signature_to_type(arg->get("type"));
|
||||
}
|
||||
else if (args.size() >= 2)
|
||||
{
|
||||
if (!bareList)
|
||||
retTypeSS << "std::tuple<";
|
||||
|
||||
bool firstArg = true;
|
||||
for (const auto& arg : args)
|
||||
{
|
||||
if (firstArg) firstArg = false; else retTypeSS << ", ";
|
||||
retTypeSS << signature_to_type(arg->get("type"));
|
||||
}
|
||||
|
||||
if (!bareList)
|
||||
retTypeSS << ">";
|
||||
}
|
||||
|
||||
return retTypeSS.str();
|
||||
}
|
||||
|
103
tools/xml2cpp-codegen/BaseGenerator.h
Normal file
103
tools/xml2cpp-codegen/BaseGenerator.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file BaseGenerator.h
|
||||
*
|
||||
* Created on: Feb 1, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SDBUSCPP_TOOLS_BASE_GENERATOR_H
|
||||
#define __SDBUSCPP_TOOLS_BASE_GENERATOR_H
|
||||
|
||||
// Own headers
|
||||
#include "xml.h"
|
||||
|
||||
// STL
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
class BaseGenerator
|
||||
{
|
||||
|
||||
public:
|
||||
int transformXmlToFile(const sdbuscpp::xml::Document& doc, const char* filename) const;
|
||||
|
||||
protected:
|
||||
enum class StubType
|
||||
{
|
||||
ADAPTOR,
|
||||
PROXY
|
||||
};
|
||||
|
||||
constexpr static const char *tab = " ";
|
||||
|
||||
virtual ~BaseGenerator() {}
|
||||
|
||||
/**
|
||||
* Implementation of public function that is provided by inherited class
|
||||
* @param doc
|
||||
* @param filename
|
||||
* @return
|
||||
*/
|
||||
virtual int transformXmlToFileImpl(const sdbuscpp::xml::Document& doc, const char* filename) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Write data to file
|
||||
* @param filename Written file
|
||||
* @param data Data to write
|
||||
* @return 0 if ok
|
||||
*/
|
||||
int writeToFile(const char* filename, const std::string& data) const;
|
||||
|
||||
/**
|
||||
* Crete header of file - include guard, includes
|
||||
* @param filename
|
||||
* @param stubType
|
||||
* @return
|
||||
*/
|
||||
std::string createHeader(const char* filename, const StubType& stubType) const;
|
||||
|
||||
/**
|
||||
* Namespaces according to the interface name
|
||||
* @param ifaceName
|
||||
* @return tuple: count of namespaces, string with code
|
||||
*/
|
||||
std::tuple<unsigned, std::string> generateNamespaces(const std::string& ifaceName) const;
|
||||
|
||||
/**
|
||||
* Transform arguments into source code
|
||||
* @param args
|
||||
* @return tuple: argument names, argument types and names, argument types
|
||||
*/
|
||||
std::tuple<std::string, std::string, std::string> argsToNamesAndTypes(const sdbuscpp::xml::Nodes& args, bool async = false) const;
|
||||
|
||||
/**
|
||||
* Output arguments to return type
|
||||
* @param args
|
||||
* @return return type
|
||||
*/
|
||||
std::string outArgsToType(const sdbuscpp::xml::Nodes& args, bool bareList = false) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //__SDBUSCPP_TOOLS_BASE_GENERATOR_H
|
267
tools/xml2cpp-codegen/ProxyGenerator.cpp
Normal file
267
tools/xml2cpp-codegen/ProxyGenerator.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file ProxyGenerator.cpp
|
||||
*
|
||||
* Created on: Feb 1, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "generator_utils.h"
|
||||
#include "ProxyGenerator.h"
|
||||
|
||||
// STL
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
using std::endl;
|
||||
|
||||
using sdbuscpp::xml::Document;
|
||||
using sdbuscpp::xml::Node;
|
||||
using sdbuscpp::xml::Nodes;
|
||||
|
||||
/**
|
||||
* Generate proxy code - client glue
|
||||
*/
|
||||
int ProxyGenerator::transformXmlToFileImpl(const Document &doc, const char *filename) const
|
||||
{
|
||||
Node &root = *(doc.root);
|
||||
Nodes interfaces = root["interface"];
|
||||
|
||||
std::ostringstream code;
|
||||
code << createHeader(filename, StubType::PROXY);
|
||||
|
||||
for (const auto& interface : interfaces)
|
||||
{
|
||||
code << processInterface(*interface);
|
||||
}
|
||||
|
||||
code << "#endif" << endl;
|
||||
|
||||
return writeToFile(filename, code.str());
|
||||
}
|
||||
|
||||
|
||||
std::string ProxyGenerator::processInterface(Node& interface) const
|
||||
{
|
||||
std::string ifaceName = interface.get("name");
|
||||
std::cout << "Generating proxy code for interface " << ifaceName << endl;
|
||||
|
||||
unsigned int namespacesCount = 0;
|
||||
std::string namespacesStr;
|
||||
std::tie(namespacesCount, namespacesStr) = generateNamespaces(ifaceName);
|
||||
|
||||
std::ostringstream body;
|
||||
body << namespacesStr;
|
||||
|
||||
std::string className = ifaceName.substr(ifaceName.find_last_of(".") + 1)
|
||||
+ "_proxy";
|
||||
|
||||
body << "class " << className << endl
|
||||
<< "{" << endl
|
||||
<< "public:" << endl
|
||||
<< tab << "static constexpr const char* interfaceName = \"" << ifaceName << "\";" << endl << endl
|
||||
<< "protected:" << endl
|
||||
<< tab << className << "(sdbus::IProxy& proxy)" << endl
|
||||
<< tab << tab << ": proxy_(proxy)" << endl;
|
||||
|
||||
Nodes methods = interface["method"];
|
||||
Nodes signals = interface["signal"];
|
||||
Nodes properties = interface["property"];
|
||||
|
||||
std::string registration, declaration;
|
||||
std::tie(registration, declaration) = processSignals(signals);
|
||||
|
||||
body << tab << "{" << endl
|
||||
<< registration
|
||||
<< tab << "}" << endl << endl;
|
||||
if (!declaration.empty())
|
||||
body << declaration << endl;
|
||||
|
||||
std::string methodDefinitions, asyncDeclarations;
|
||||
std::tie(methodDefinitions, asyncDeclarations) = processMethods(methods);
|
||||
|
||||
if (!asyncDeclarations.empty())
|
||||
{
|
||||
body << asyncDeclarations << endl;
|
||||
}
|
||||
|
||||
if (!methodDefinitions.empty())
|
||||
{
|
||||
body << "public:" << endl << methodDefinitions;
|
||||
}
|
||||
|
||||
std::string propertyDefinitions = processProperties(properties);
|
||||
if (!propertyDefinitions.empty())
|
||||
{
|
||||
body << "public:" << endl << propertyDefinitions;
|
||||
}
|
||||
|
||||
body << "private:" << endl
|
||||
<< tab << "sdbus::IProxy& proxy_;" << endl
|
||||
<< "};" << endl << endl
|
||||
<< std::string(namespacesCount, '}') << " // namespaces" << endl << endl;
|
||||
|
||||
return body.str();
|
||||
}
|
||||
|
||||
std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes& methods) const
|
||||
{
|
||||
std::ostringstream definitionSS, asyncDeclarationSS;
|
||||
|
||||
for (const auto& method : methods)
|
||||
{
|
||||
auto name = method->get("name");
|
||||
Nodes args = (*method)["arg"];
|
||||
Nodes inArgs = args.select("direction" , "in");
|
||||
Nodes outArgs = args.select("direction" , "out");
|
||||
|
||||
bool dontExpectReply{false};
|
||||
bool async{false};
|
||||
Nodes annotations = (*method)["annotation"];
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
if (annotation->get("name") == "org.freedesktop.DBus.Method.NoReply" && annotation->get("value") == "true")
|
||||
dontExpectReply = true;
|
||||
else if (annotation->get("name") == "org.freedesktop.DBus.Method.Async"
|
||||
&& (annotation->get("value") == "client" || annotation->get("value") == "clientserver"))
|
||||
async = true;
|
||||
}
|
||||
if (dontExpectReply && outArgs.size() > 0)
|
||||
{
|
||||
std::cerr << "Function: " << name << ": ";
|
||||
std::cerr << "Option 'org.freedesktop.DBus.Method.NoReply' not allowed for methods with 'out' variables! Option ignored..." << std::endl;
|
||||
dontExpectReply = false;
|
||||
}
|
||||
|
||||
auto retType = outArgsToType(outArgs);
|
||||
std::string inArgStr, inArgTypeStr;
|
||||
std::tie(inArgStr, inArgTypeStr, std::ignore) = argsToNamesAndTypes(inArgs);
|
||||
std::string outArgStr, outArgTypeStr;
|
||||
std::tie(outArgStr, outArgTypeStr, std::ignore) = argsToNamesAndTypes(outArgs);
|
||||
|
||||
definitionSS << tab << (async ? "void" : retType) << " " << name << "(" << inArgTypeStr << ")" << endl
|
||||
<< tab << "{" << endl;
|
||||
|
||||
if (outArgs.size() > 0 && !async)
|
||||
{
|
||||
definitionSS << tab << tab << retType << " result;" << endl;
|
||||
}
|
||||
|
||||
definitionSS << tab << tab << "proxy_.callMethod" << (async ? "Async" : "") << "(\"" << name << "\")"
|
||||
".onInterface(interfaceName)";
|
||||
|
||||
if (inArgs.size() > 0)
|
||||
{
|
||||
definitionSS << ".withArguments(" << inArgStr << ")";
|
||||
}
|
||||
|
||||
if (async && !dontExpectReply)
|
||||
{
|
||||
auto nameBigFirst = name;
|
||||
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
|
||||
|
||||
definitionSS << ".uponReplyInvoke([this](const sdbus::Error* error" << (outArgTypeStr.empty() ? "" : ", ") << outArgTypeStr << ")"
|
||||
"{ this->on" << nameBigFirst << "Reply(" << outArgStr << (outArgStr.empty() ? "" : ", ") << "error); })";
|
||||
|
||||
asyncDeclarationSS << tab << "virtual void on" << nameBigFirst << "Reply("
|
||||
<< outArgTypeStr << (outArgTypeStr.empty() ? "" : ", ") << "const sdbus::Error* error) = 0;" << endl;
|
||||
}
|
||||
else if (outArgs.size() > 0)
|
||||
{
|
||||
definitionSS << ".storeResultsTo(result);" << endl
|
||||
<< tab << tab << "return result";
|
||||
}
|
||||
else if (dontExpectReply)
|
||||
{
|
||||
definitionSS << ".dontExpectReply()";
|
||||
}
|
||||
|
||||
definitionSS << ";" << endl << tab << "}" << endl << endl;
|
||||
}
|
||||
|
||||
return std::make_tuple(definitionSS.str(), asyncDeclarationSS.str());
|
||||
}
|
||||
|
||||
std::tuple<std::string, std::string> ProxyGenerator::processSignals(const Nodes& signals) const
|
||||
{
|
||||
std::ostringstream registrationSS, declarationSS;
|
||||
|
||||
for (const auto& signal : signals)
|
||||
{
|
||||
auto name = signal->get("name");
|
||||
Nodes args = (*signal)["arg"];
|
||||
|
||||
auto nameBigFirst = name;
|
||||
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
|
||||
|
||||
std::string argStr, argTypeStr;
|
||||
std::tie(argStr, argTypeStr, std::ignore) = argsToNamesAndTypes(args);
|
||||
|
||||
registrationSS << tab << tab << "proxy_"
|
||||
".uponSignal(\"" << name << "\")"
|
||||
".onInterface(interfaceName)"
|
||||
".call([this](" << argTypeStr << ")"
|
||||
"{ this->on" << nameBigFirst << "(" << argStr << "); });" << endl;
|
||||
|
||||
declarationSS << tab << "virtual void on" << nameBigFirst << "(" << argTypeStr << ") = 0;" << endl;
|
||||
}
|
||||
|
||||
return std::make_tuple(registrationSS.str(), declarationSS.str());
|
||||
}
|
||||
|
||||
std::string ProxyGenerator::processProperties(const Nodes& properties) const
|
||||
{
|
||||
std::ostringstream propertySS;
|
||||
for (const auto& property : properties)
|
||||
{
|
||||
auto propertyName = property->get("name");
|
||||
auto propertyAccess = property->get("access");
|
||||
auto propertySignature = property->get("type");
|
||||
|
||||
auto propertyType = signature_to_type(propertySignature);
|
||||
auto propertyArg = std::string("value");
|
||||
auto propertyTypeArg = std::string("const ") + propertyType + "& " + propertyArg;
|
||||
|
||||
if (propertyAccess == "read" || propertyAccess == "readwrite")
|
||||
{
|
||||
propertySS << tab << propertyType << " " << propertyName << "()" << endl
|
||||
<< tab << "{" << endl;
|
||||
propertySS << tab << tab << "return proxy_.getProperty(\"" << propertyName << "\")"
|
||||
".onInterface(interfaceName)";
|
||||
propertySS << ";" << endl << tab << "}" << endl << endl;
|
||||
}
|
||||
|
||||
if (propertyAccess == "readwrite" || propertyAccess == "write")
|
||||
{
|
||||
propertySS << tab << "void " << propertyName << "(" << propertyTypeArg << ")" << endl
|
||||
<< tab << "{" << endl;
|
||||
propertySS << tab << tab << "proxy_.setProperty(\"" << propertyName << "\")"
|
||||
".onInterface(interfaceName)"
|
||||
".toValue(" << propertyArg << ")";
|
||||
propertySS << ";" << endl << tab << "}" << endl << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return propertySS.str();
|
||||
}
|
81
tools/xml2cpp-codegen/ProxyGenerator.h
Normal file
81
tools/xml2cpp-codegen/ProxyGenerator.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file ProxyGenerator.h
|
||||
*
|
||||
* Created on: Feb 1, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SDBUSCPP_TOOLS_PROXY_GENERATOR_H
|
||||
#define __SDBUSCPP_TOOLS_PROXY_GENERATOR_H
|
||||
|
||||
// Own headers
|
||||
#include "xml.h"
|
||||
#include "BaseGenerator.h"
|
||||
|
||||
// STL
|
||||
#include <tuple>
|
||||
|
||||
class ProxyGenerator : public BaseGenerator
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* Transform xml to proxy code
|
||||
* @param doc
|
||||
* @param filename
|
||||
* @return 0 if ok
|
||||
*/
|
||||
int transformXmlToFileImpl(const sdbuscpp::xml::Document& doc, const char* filename) const override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Generate source code for interface
|
||||
* @param interface
|
||||
* @return source code
|
||||
*/
|
||||
std::string processInterface(sdbuscpp::xml::Node& interface) const;
|
||||
|
||||
/**
|
||||
* Generate method calls
|
||||
* @param methods
|
||||
* @return tuple: definition of methods, declaration of virtual async reply handlers
|
||||
*/
|
||||
std::tuple<std::string, std::string> processMethods(const sdbuscpp::xml::Nodes& methods) const;
|
||||
|
||||
/**
|
||||
* Generate code for handling signals
|
||||
* @param signals
|
||||
* @return tuple: registration, declaration of virtual methods
|
||||
*/
|
||||
std::tuple<std::string, std::string> processSignals(const sdbuscpp::xml::Nodes& signals) const;
|
||||
|
||||
/**
|
||||
* Generate calls for properties
|
||||
* @param properties
|
||||
* @return source code
|
||||
*/
|
||||
std::string processProperties(const sdbuscpp::xml::Nodes& properties) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //__SDBUSCPP_TOOLS_PROXY_GENERATOR_H
|
143
tools/xml2cpp-codegen/generator_utils.cpp
Normal file
143
tools/xml2cpp-codegen/generator_utils.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Inspired by: http://dbus-cplusplus.sourceforge.net/
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
|
||||
#include "generator_utils.h"
|
||||
|
||||
|
||||
std::string underscorize(const std::string& str)
|
||||
{
|
||||
std::string res = str;
|
||||
for (unsigned int i = 0; i < res.length(); ++i)
|
||||
{
|
||||
if (!isalpha(res[i]) && !isdigit(res[i]))
|
||||
{
|
||||
res[i] = '_';
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string stub_name(const std::string& name)
|
||||
{
|
||||
return "_" + underscorize(name) + "_stub";
|
||||
}
|
||||
|
||||
const char *atomic_type_to_string(char t)
|
||||
{
|
||||
static std::map<char, const char*> atos
|
||||
{
|
||||
{ 'y', "uint8_t" },
|
||||
{ 'b', "bool" },
|
||||
{ 'n', "int16_t" },
|
||||
{ 'q', "uint16_t" },
|
||||
{ 'i', "int32_t" },
|
||||
{ 'u', "uint32_t" },
|
||||
{ 'x', "int64_t" },
|
||||
{ 't', "uint64_t" },
|
||||
{ 'd', "double" },
|
||||
{ 's', "std::string" },
|
||||
{ 'o', "sdbus::ObjectPath" },
|
||||
{ 'g', "sdbus::Signature" },
|
||||
{ 'v', "sdbus::Variant" },
|
||||
{ '\0', "" }
|
||||
};
|
||||
|
||||
if (atos.count(t))
|
||||
{
|
||||
return atos[t];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void _parse_signature(const std::string &signature, std::string &type, unsigned int &i, bool only_once = false)
|
||||
{
|
||||
for (; i < signature.length(); ++i)
|
||||
{
|
||||
switch (signature[i])
|
||||
{
|
||||
case 'a':
|
||||
{
|
||||
switch (signature[++i])
|
||||
{
|
||||
case '{':
|
||||
{
|
||||
type += "std::map<";
|
||||
++i;
|
||||
_parse_signature(signature, type, i);
|
||||
type += ">";
|
||||
|
||||
break;
|
||||
}
|
||||
case '(':
|
||||
{
|
||||
type += "std::vector<sdbus::Struct<";
|
||||
++i;
|
||||
_parse_signature(signature, type, i);
|
||||
type += ">>";
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
type += "std::vector<";
|
||||
_parse_signature(signature, type, i, true);
|
||||
|
||||
type += ">";
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '(':
|
||||
{
|
||||
type += "sdbus::Struct<";
|
||||
++i;
|
||||
|
||||
_parse_signature(signature, type, i);
|
||||
|
||||
type += ">";
|
||||
break;
|
||||
}
|
||||
case ')':
|
||||
case '}':
|
||||
{
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
const char *atom = atomic_type_to_string(signature[i]);
|
||||
if (!atom)
|
||||
{
|
||||
std::cerr << "Invalid signature: " << signature << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
type += atom;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (only_once)
|
||||
return;
|
||||
|
||||
if (i + 1 < signature.length() && signature[i + 1] != ')' && signature[i + 1] != '}')
|
||||
{
|
||||
type += ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string signature_to_type(const std::string& signature)
|
||||
{
|
||||
std::string type;
|
||||
unsigned int i = 0;
|
||||
_parse_signature(signature, type, i);
|
||||
return type;
|
||||
}
|
22
tools/xml2cpp-codegen/generator_utils.h
Normal file
22
tools/xml2cpp-codegen/generator_utils.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Inspired by: http://dbus-cplusplus.sourceforge.net/
|
||||
*/
|
||||
|
||||
#ifndef __SDBUSCPP_TOOLS_GENERATOR_UTILS_H
|
||||
#define __SDBUSCPP_TOOLS_GENERATOR_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
const char *atomic_type_to_string(char t);
|
||||
|
||||
std::string stub_name(const std::string& name);
|
||||
|
||||
std::string signature_to_type(const std::string& signature);
|
||||
|
||||
std::string underscorize(const std::string& str);
|
||||
|
||||
constexpr const char* getHeaderComment() noexcept { return "\n/*\n * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!\n */\n\n"; }
|
||||
|
||||
#endif //__SDBUSCPP_TOOLS_GENERATOR_UTILS_H
|
309
tools/xml2cpp-codegen/xml.cpp
Normal file
309
tools/xml2cpp-codegen/xml.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* Inspired by: http://dbus-cplusplus.sourceforge.net/
|
||||
*/
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
#include <expat.h>
|
||||
|
||||
using namespace sdbuscpp::xml;
|
||||
|
||||
std::istream &operator >> (std::istream& in, Document& doc)
|
||||
{
|
||||
std::stringbuf xmlbuf;
|
||||
in.get(xmlbuf, '\0');
|
||||
doc.from_xml(xmlbuf.str());
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
std::ostream &operator << (std::ostream& out, const Document& doc)
|
||||
{
|
||||
return out << doc.to_xml();
|
||||
}
|
||||
|
||||
|
||||
Error::Error(const char *error, int line, int column)
|
||||
{
|
||||
std::ostringstream estream;
|
||||
|
||||
estream << "line " << line << ", column " << column << ": " << error;
|
||||
|
||||
m_error = estream.str();
|
||||
}
|
||||
|
||||
Node::Node(const char *n, const char **a)
|
||||
: name(n)
|
||||
{
|
||||
if (a)
|
||||
{
|
||||
for (int i = 0; a[i]; i += 2)
|
||||
{
|
||||
m_attrs[a[i]] = a[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Nodes Nodes::operator[](const std::string& key) const
|
||||
{
|
||||
Nodes result;
|
||||
|
||||
for (auto it = begin(), endIt = end(); it != endIt; ++it)
|
||||
{
|
||||
Nodes part = (**it)[key];
|
||||
|
||||
result.insert(result.end(), part.begin(), part.end());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Nodes Nodes::select(const std::string& attr, const std::string& value) const
|
||||
{
|
||||
Nodes result;
|
||||
|
||||
for (auto it = begin(), itEnd = end(); it != itEnd; ++it)
|
||||
{
|
||||
if ((*it)->get(attr) == value)
|
||||
{
|
||||
result.insert(result.end(), *it);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Nodes Node::operator[](const std::string& key)
|
||||
{
|
||||
Nodes result;
|
||||
|
||||
if (key.length() == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto it = children.begin(), itEnd = children.end(); it != itEnd; ++it)
|
||||
{
|
||||
if (it->name == key)
|
||||
{
|
||||
result.push_back(&(*it));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Node::get(const std::string& attribute) const
|
||||
{
|
||||
const auto it = m_attrs.find(attribute);
|
||||
if (it != m_attrs.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void Node::set(const std::string& attribute, std::string value)
|
||||
{
|
||||
if (value.length())
|
||||
{
|
||||
m_attrs[attribute] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_attrs.erase(value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Node::to_xml() const
|
||||
{
|
||||
std::string xml;
|
||||
int depth = 0;
|
||||
|
||||
_raw_xml(xml, depth);
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
void Node::_raw_xml(std::string& xml, int& depth) const
|
||||
{
|
||||
xml.append(depth * 2, ' ');
|
||||
xml.append("<" + name);
|
||||
|
||||
for (auto it = m_attrs.begin(), itEnd = m_attrs.end(); it != itEnd; ++it)
|
||||
{
|
||||
xml.append(" " + it->first + "=\"" + it->second + "\"");
|
||||
}
|
||||
|
||||
if (cdata.length() == 0 && children.size() == 0)
|
||||
{
|
||||
xml.append("/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
xml.append(">");
|
||||
|
||||
if (cdata.length())
|
||||
{
|
||||
xml.append(cdata);
|
||||
}
|
||||
|
||||
if (children.size())
|
||||
{
|
||||
xml.append("\n");
|
||||
++depth;
|
||||
|
||||
for (auto it = children.begin(), itEnd = children.end(); it != itEnd; ++it)
|
||||
{
|
||||
it->_raw_xml(xml, depth);
|
||||
}
|
||||
|
||||
--depth;
|
||||
xml.append(depth * 2, ' ');
|
||||
}
|
||||
|
||||
xml.append("</" + name + ">\n");
|
||||
}
|
||||
}
|
||||
|
||||
Document::Document() :
|
||||
root(nullptr),
|
||||
m_depth(0)
|
||||
{
|
||||
}
|
||||
|
||||
Document::Document(const std::string &xml) :
|
||||
root(nullptr),
|
||||
m_depth(0)
|
||||
{
|
||||
from_xml(xml);
|
||||
}
|
||||
|
||||
Document::~Document()
|
||||
{
|
||||
delete root;
|
||||
}
|
||||
|
||||
struct Document::Expat
|
||||
{
|
||||
static void start_doctype_decl_handler(
|
||||
void *data, const XML_Char *name, const XML_Char *sysid, const XML_Char *pubid, int has_internal_subset
|
||||
);
|
||||
static void end_doctype_decl_handler(void *data);
|
||||
static void start_element_handler(void *data, const XML_Char *name, const XML_Char **atts);
|
||||
static void character_data_handler(void *data, const XML_Char *chars, int len);
|
||||
static void end_element_handler(void *data, const XML_Char *name);
|
||||
};
|
||||
|
||||
void Document::from_xml(const std::string& xml)
|
||||
{
|
||||
m_depth = 0;
|
||||
if (root)
|
||||
{
|
||||
delete root;
|
||||
}
|
||||
root = nullptr;
|
||||
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
|
||||
XML_SetUserData(parser, this);
|
||||
|
||||
XML_SetDoctypeDeclHandler(
|
||||
parser,
|
||||
Document::Expat::start_doctype_decl_handler,
|
||||
Document::Expat::end_doctype_decl_handler
|
||||
);
|
||||
|
||||
XML_SetElementHandler(
|
||||
parser,
|
||||
Document::Expat::start_element_handler,
|
||||
Document::Expat::end_element_handler
|
||||
);
|
||||
|
||||
XML_SetCharacterDataHandler(
|
||||
parser,
|
||||
Document::Expat::character_data_handler
|
||||
);
|
||||
|
||||
XML_Status status = XML_Parse(parser, xml.c_str(), xml.length(), true);
|
||||
|
||||
if (status == XML_STATUS_ERROR)
|
||||
{
|
||||
const char* error = XML_ErrorString(XML_GetErrorCode(parser));
|
||||
int line = XML_GetCurrentLineNumber(parser);
|
||||
int column = XML_GetCurrentColumnNumber(parser);
|
||||
|
||||
XML_ParserFree(parser);
|
||||
|
||||
throw Error(error, line, column);
|
||||
}
|
||||
else
|
||||
{
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Document::to_xml() const
|
||||
{
|
||||
return root->to_xml();
|
||||
}
|
||||
|
||||
void Document::Expat::start_doctype_decl_handler(
|
||||
void* /*data*/,
|
||||
const XML_Char* /*name*/,
|
||||
const XML_Char* /*sysid*/,
|
||||
const XML_Char */*pubid*/,
|
||||
int /*has_internal_subset*/)
|
||||
{
|
||||
}
|
||||
|
||||
void Document::Expat::end_doctype_decl_handler(void* /*data*/)
|
||||
{
|
||||
}
|
||||
|
||||
void Document::Expat::start_element_handler(void* data, const XML_Char* name, const XML_Char** atts)
|
||||
{
|
||||
Document* doc = static_cast<Document*>(data);
|
||||
|
||||
if (!doc->root)
|
||||
{
|
||||
doc->root = new Node(name, atts);
|
||||
}
|
||||
else
|
||||
{
|
||||
Node::Children* cld = &(doc->root->children);
|
||||
|
||||
for (int i = 1; i < doc->m_depth; ++i)
|
||||
{
|
||||
cld = &(cld->back().children);
|
||||
}
|
||||
cld->push_back(Node(name, atts));
|
||||
|
||||
}
|
||||
doc->m_depth++;
|
||||
}
|
||||
|
||||
void Document::Expat::character_data_handler(void* data, const XML_Char* chars, int len)
|
||||
{
|
||||
Document* doc = static_cast<Document*>(data);
|
||||
|
||||
Node* nod = doc->root;
|
||||
|
||||
for (int i = 1; i < doc->m_depth; ++i)
|
||||
{
|
||||
nod = &(nod->children.back());
|
||||
}
|
||||
|
||||
int x = 0, y = len - 1;
|
||||
|
||||
while (isspace(chars[y]) && y > 0) --y;
|
||||
while (isspace(chars[x]) && x < y) ++x;
|
||||
|
||||
nod->cdata = std::string(chars, x, y + 1);
|
||||
}
|
||||
|
||||
void Document::Expat::end_element_handler(void* data, const XML_Char* /*name*/)
|
||||
{
|
||||
Document* doc = static_cast<Document*>(data);
|
||||
|
||||
doc->m_depth--;
|
||||
}
|
||||
|
113
tools/xml2cpp-codegen/xml.h
Normal file
113
tools/xml2cpp-codegen/xml.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Inspired by: http://dbus-cplusplus.sourceforge.net/
|
||||
*/
|
||||
|
||||
#ifndef __SDBUSCPP_TOOLS_XML_H
|
||||
#define __SDBUSCPP_TOOLS_XML_H
|
||||
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace sdbuscpp
|
||||
{
|
||||
namespace xml
|
||||
{
|
||||
|
||||
class Error : public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
Error(const char *error, int line, int column);
|
||||
|
||||
~Error() {}
|
||||
|
||||
const char *what() const noexcept { return m_error.c_str(); }
|
||||
|
||||
private:
|
||||
std::string m_error;
|
||||
};
|
||||
|
||||
|
||||
class Node;
|
||||
|
||||
class Nodes : public std::vector<Node *>
|
||||
{
|
||||
public:
|
||||
Nodes operator[](const std::string &key) const;
|
||||
Nodes select(const std::string &attr, const std::string &value) const;
|
||||
};
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
|
||||
using Attributes = std::map<std::string, std::string>;
|
||||
using Children = std::vector<Node>;
|
||||
|
||||
std::string name;
|
||||
std::string cdata;
|
||||
Children children;
|
||||
|
||||
Node(std::string n, Attributes a) :
|
||||
name(n),
|
||||
m_attrs(a)
|
||||
{}
|
||||
|
||||
Node(const char* n, const char** a = nullptr);
|
||||
|
||||
Nodes operator[](const std::string& key);
|
||||
|
||||
std::string get(const std::string& attribute) const;
|
||||
|
||||
void set(const std::string &attribute, std::string value);
|
||||
|
||||
std::string to_xml() const;
|
||||
|
||||
Node& add(Node child)
|
||||
{
|
||||
children.push_back(child);
|
||||
return children.back();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void _raw_xml(std::string& xml, int& depth) const;
|
||||
|
||||
Attributes m_attrs;
|
||||
};
|
||||
|
||||
class Document
|
||||
{
|
||||
public:
|
||||
struct Expat;
|
||||
|
||||
Node* root;
|
||||
|
||||
Document();
|
||||
~Document();
|
||||
|
||||
Document(const std::string& xml);
|
||||
|
||||
void from_xml(const std::string& xml);
|
||||
|
||||
std::string to_xml() const;
|
||||
|
||||
private:
|
||||
|
||||
int m_depth;
|
||||
};
|
||||
|
||||
} // namespace xml
|
||||
|
||||
} // namespace sdbuscpp
|
||||
|
||||
std::istream &operator >> (std::istream &, sdbuscpp::xml::Document &);
|
||||
std::ostream &operator << (std::ostream &, sdbuscpp::xml::Document &);
|
||||
|
||||
#endif//__SDBUSCPP_TOOLS_XML_H
|
202
tools/xml2cpp-codegen/xml2cpp.cpp
Normal file
202
tools/xml2cpp-codegen/xml2cpp.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file xml2cpp.cpp
|
||||
*
|
||||
* Created on: Feb 1, 2017
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "xml.h"
|
||||
#include "AdaptorGenerator.h"
|
||||
#include "ProxyGenerator.h"
|
||||
|
||||
// STL
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
using std::endl;
|
||||
using namespace sdbuscpp;
|
||||
|
||||
void usage(std::ostream& output, const char* programName)
|
||||
{
|
||||
output << "Usage: " << programName << " [OPTION]... [FILE]" << endl <<
|
||||
"Creates C++ stubs for DBus API for adaptor and/or client" << endl <<
|
||||
endl <<
|
||||
"Available options:" << endl <<
|
||||
" --proxy=FILE Generate header file FILE with proxy class (client)" << endl <<
|
||||
" --adaptor=FILE Generate header file FILE with stub class (server)" << endl <<
|
||||
" -h, --help " << endl <<
|
||||
" --verbose Explain what is being done" << endl <<
|
||||
endl <<
|
||||
"The stub generator takes an XML file describing DBus interface and creates" << endl <<
|
||||
"C++ header files to be used by C++ code wanting to cumminicate through that" << endl <<
|
||||
"interface. Clients of the interface (those making the calls) need header" << endl <<
|
||||
"created with the --proxy option as this header forwards the calls via DBus" << endl <<
|
||||
"to provider of the service and the returns the result to the caller. Server" << endl <<
|
||||
"implementing the service should derive from interface classes in header" << endl <<
|
||||
"generated for --adaptor option and implement their methods." << endl <<
|
||||
endl <<
|
||||
"When FILE is not specified, standard input is read. Exit status is 0 when" << endl <<
|
||||
"no error was encountered and all requested headers were sucessfully generated." << endl <<
|
||||
"Otherwise 1 is returned." << endl;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char* programName = argv[0];
|
||||
argv++;
|
||||
argc--;
|
||||
|
||||
const char* proxy = nullptr;
|
||||
const char* adaptor = nullptr;
|
||||
const char* xmlFile = nullptr;
|
||||
bool verbose = false;
|
||||
|
||||
while (argc > 0)
|
||||
{
|
||||
if (!strncmp(*argv, "--proxy=", 8))
|
||||
{
|
||||
if (proxy != nullptr)
|
||||
{
|
||||
std::cerr << "Multiple occurrencies of --proxy is not allowed" << endl;
|
||||
usage(std::cerr, programName);
|
||||
return 1;
|
||||
}
|
||||
proxy = *argv + 8;
|
||||
}
|
||||
else if (!strncmp(*argv, "--adaptor=", 10) || !strncmp(*argv, "--adapter=", 10))
|
||||
{
|
||||
if (adaptor != nullptr)
|
||||
{
|
||||
std::cerr << "Multiple occurrencies of --adaptor is not allowed" << endl;
|
||||
usage(std::cerr, programName);
|
||||
return 1;
|
||||
}
|
||||
adaptor = *argv + 10;
|
||||
}
|
||||
else if (!strcmp(*argv, "--help") || !strcmp(*argv, "-h"))
|
||||
{
|
||||
usage(std::cout, programName);
|
||||
return 0;
|
||||
}
|
||||
else if (!strcmp(*argv, "--verbose"))
|
||||
{
|
||||
verbose = true;
|
||||
}
|
||||
else if (**argv == '-')
|
||||
{
|
||||
std::cerr << "Unknown option " << *argv << endl;
|
||||
usage(std::cerr, programName);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xmlFile != nullptr)
|
||||
{
|
||||
std::cerr << "More than one input file specified: " << *argv << endl;
|
||||
usage(std::cerr, programName);
|
||||
return 1;
|
||||
}
|
||||
xmlFile = *argv;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (!proxy && !adaptor)
|
||||
{
|
||||
std::cerr << "Either --proxy or --adapter need to be specified" << endl;
|
||||
usage(std::cerr, programName);
|
||||
return 1;
|
||||
}
|
||||
|
||||
xml::Document doc;
|
||||
|
||||
try
|
||||
{
|
||||
if (xmlFile != nullptr)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
std::cerr << "Reading DBus interface from " << xmlFile << endl;
|
||||
}
|
||||
|
||||
std::ifstream input(xmlFile);
|
||||
|
||||
if (input.bad())
|
||||
{
|
||||
std::cerr << "Unable to open file " << xmlFile << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
input >> doc;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
std::cerr << "Reading DBus interface from standard input" << endl;
|
||||
}
|
||||
|
||||
std::cin >> doc;
|
||||
}
|
||||
}
|
||||
catch (const xml::Error& e)
|
||||
{
|
||||
std::cerr << "Parsing error: " << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!doc.root)
|
||||
{
|
||||
std::cerr << "Empty document" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (proxy)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
std::cerr << "Generating proxy header " << proxy << endl;
|
||||
}
|
||||
ProxyGenerator pg;
|
||||
pg.transformXmlToFile(doc, proxy);
|
||||
}
|
||||
|
||||
if (adaptor)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
std::cerr << "Generating adaptor header " << adaptor << endl;
|
||||
}
|
||||
AdaptorGenerator ag;
|
||||
ag.transformXmlToFile(doc, adaptor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user