diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ add_definitions(-DQT_NO_FOREACH) # Subdirectories add_subdirectory(src) +add_subdirectory(tools/bluezapi2qt) if (BUILD_TESTING) add_subdirectory(tests) diff --git a/tools/bluezapi2qt/BluezApiParser.h b/tools/bluezapi2qt/BluezApiParser.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/BluezApiParser.h @@ -0,0 +1,45 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef PARSER_H +#define PARSER_H + +#include + +#include "Interface.h" + +class BluezApiParser +{ +public: + BluezApiParser(); + + bool parse(QTextStream &stream); + bool finalize(); + + std::list interfaces() const; + +private: + std::list m_interfaces; + Interface *m_currentInterface = nullptr; +}; + +#endif // PARSER_H diff --git a/tools/bluezapi2qt/BluezApiParser.cpp b/tools/bluezapi2qt/BluezApiParser.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/BluezApiParser.cpp @@ -0,0 +1,68 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "BluezApiParser.h" + +#include + +BluezApiParser::BluezApiParser() +{ +} + +bool BluezApiParser::parse(QTextStream &stream) +{ + while (!stream.atEnd()) { + // Get next line + auto line = stream.readLine(); + // Just look for section markers + if (line.startsWith(L'=')) { + m_interfaces.emplace_back(Interface()); + m_currentInterface = &m_interfaces.back(); + } else if (m_currentInterface) { + if (!m_currentInterface->parse(line)) { + m_currentInterface = nullptr; + } + } + } + + return true; +} + +bool BluezApiParser::finalize() +{ + bool success = true; + + m_interfaces.erase(std::remove_if(m_interfaces.begin(), m_interfaces.end(), [](const Interface &interface) { + return interface.methods().methods().empty() && interface.properties().properties().empty(); + }), m_interfaces.end()); + + for (auto &interface : m_interfaces) { + success &= interface.finalize(); + } + + return success; +} + +std::list BluezApiParser::interfaces() const +{ + return m_interfaces; +} diff --git a/tools/bluezapi2qt/CMakeLists.txt b/tools/bluezapi2qt/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/CMakeLists.txt @@ -0,0 +1,18 @@ +add_executable(bluezapi2qt + BluezApiParser.cpp + Comment.cpp + CppGenerator.cpp + Interface.cpp + Method.cpp + Methods.cpp + Parameter.cpp + Properties.cpp + Property.cpp + TypeAnnotation.cpp + XmlGenerator.cpp + main.cpp +) + +target_link_libraries(bluezapi2qt + Qt5::Core +) diff --git a/tools/bluezapi2qt/Comment.h b/tools/bluezapi2qt/Comment.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Comment.h @@ -0,0 +1,36 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef COMMENT_H +#define COMMENT_H + +#include + +class Comment : public QStringList +{ +public: + using QStringList::QStringList; + + bool finalize(); +}; + +#endif // COMMENT_H diff --git a/tools/bluezapi2qt/Comment.cpp b/tools/bluezapi2qt/Comment.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Comment.cpp @@ -0,0 +1,52 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "Comment.h" + +bool Comment::finalize() +{ + // Delete last empty lines from comment + while (last().isEmpty()) { + removeLast(); + } + + // Find indents + int indents = 255; + for (const auto &line : *this) { + if (line.isEmpty()) { + continue; + } + indents = std::min(indents, line.count(QStringLiteral("\t"))); + } + + // Remove indents + for (auto &line : *this) { + line.remove(0, indents); + } + + // Replace indents + for (auto &line : *this) { + line.replace(QStringLiteral("\t"), QStringLiteral(" ")); + } + + return true; +} diff --git a/tools/bluezapi2qt/CppGenerator.h b/tools/bluezapi2qt/CppGenerator.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/CppGenerator.h @@ -0,0 +1,65 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef CPPGENERATOR_H +#define CPPGENERATOR_H + +#include + +class BluezApiParser; +class Method; + +class CppGenerator +{ +public: + struct Config { + bool useOptional = false; + bool useDeprecated = false; + bool useExperimental = false; + bool useLowercaseFileNames = false; + QString author = QStringLiteral("John Doe "); + QString year = QStringLiteral("2019"); + }; + CppGenerator(const Config &config); + + bool generate(const BluezApiParser &parser); + +protected: + void writeAdaptorHeader(const BluezApiParser &parser); + void writeAdaptorSource(const BluezApiParser &parser); + + static QString interfaceToClassName(const QString &interface); + static QString lowerFirstChars(const QString &string); + static void writeFooter(QTextStream &stream); + static void writeInterface(QTextStream &stream, const QString &name); + static void closeInterface(QTextStream &stream); + static bool writeMethod(QTextStream &stream, const Method &method); + static bool writeArg(QTextStream &stream, const QString ¶m, const QString &dir); + static void writeAnnotation(QTextStream &stream, const QString ¶m, const QString &dir, int i); + + void writeCopyrightHeader(QTextStream &stream); + +private: + Config m_config; +}; + +#endif // CPPGENERATOR_H diff --git a/tools/bluezapi2qt/CppGenerator.cpp b/tools/bluezapi2qt/CppGenerator.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/CppGenerator.cpp @@ -0,0 +1,256 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "CppGenerator.h" + +#include +#include + +#include "BluezApiParser.h" +#include "TypeAnnotation.h" + +CppGenerator::CppGenerator(const Config &config) : + m_config(config) +{ +} + +bool CppGenerator::generate(const BluezApiParser &parser) +{ + writeAdaptorHeader(parser); + writeAdaptorSource(parser); + + return true; +} + +void CppGenerator::writeAdaptorHeader(const BluezApiParser &parser) +{ + // Iterate interfaces + for (const auto &interface : parser.interfaces()) { + auto className = interfaceToClassName(interface.name()); + + // Create file + QFile file(className.toLower() + QStringLiteral("adaptor.h")); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning() << "Error opening file for writing:" << file.fileName(); + return; + } + + // Write content + QTextStream stream(&file); + writeCopyrightHeader(stream); + stream << "#pragma once" << endl << endl; + stream << "#include " << endl << endl; + stream << "class QDBusObjectPath;" << endl << endl; + stream << "namespace BluezQt" << endl << "{" << endl << endl; + stream << "class " << className << ";" << endl << endl; + stream << "class " << className << "Adaptor : public QDBusAbstractAdaptor" << endl << "{" << endl; + stream << " Q_OBJECT " << endl; + stream << " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface.name() << "\")" << endl; + + // Write properties + for (const auto &property : interface.properties().properties()) { + // Respect config + if ((property.tags().isOptional && !m_config.useOptional) || + (property.tags().isExperimental && !m_config.useExperimental)) { + continue; + } + stream << " Q_PROPERTY(" << bluezToQt(property.type()) << " " << property.name() << " READ " << lowerFirstChars(property.name()); + if (!property.tags().isReadOnly) { + stream << " WRITE set" << property.name(); + } + stream << ")" << endl; + } + + stream << endl << "public:" << endl; + stream << " explicit " << className << "Adaptor(" << className << "* parent);" << endl << endl; + + // Write property accessors + for (const auto &property : interface.properties().properties()) { + // Respect config + if ((property.tags().isOptional && !m_config.useOptional) || + (property.tags().isExperimental && !m_config.useExperimental)) { + continue; + } + stream << " " << bluezToQt(property.type()) << " " << lowerFirstChars(property.name()) << "() const;" << endl; + if (!property.tags().isReadOnly) { + stream << " void set" << property.name() << "(const " << bluezToQt(property.type()) << " &" << lowerFirstChars(property.name()) << ");" << endl; + } + stream << endl; + } + + stream << "public Q_SLOTS:" << endl; + + // write Methods + for (const auto &method : interface.methods().methods()) { + // Respect config + if ((method.tags().isOptional && !m_config.useOptional) || + (method.tags().isExperimental && !m_config.useExperimental)) { + continue; + } + stream << " " << bluezToQt(method.outParameter().type()) << " " << method.name() << "("; + for (auto it = method.inParameters().begin(); + it != method.inParameters().end(); ++it) { + stream << "const " << bluezToQt(it->type()) << " &" << it->name(); + if (it != std::prev(method.inParameters().end())) { + stream << ", "; + } + } + stream << ");" << endl; + } + + // write private members + stream << endl << "private:" << endl; + stream << " " << className << " *m_" << lowerFirstChars(className) << ";" << endl; + stream << "};" << endl << endl << "} // namespace BluezQt" << endl; + + file.close(); + } +} + +void CppGenerator::writeAdaptorSource(const BluezApiParser &parser) +{ + // Iterate interfaces + for (const auto &interface : parser.interfaces()) { + auto className = interfaceToClassName(interface.name()); + + // Create file + QFile file(className.toLower() + QStringLiteral("adaptor.cpp")); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning() << "Error opening file for writing:" << file.fileName(); + return; + } + + // Write content + QTextStream stream(&file); + writeCopyrightHeader(stream); + stream << "#include \"" << className << "Adaptor.h\"" << endl << endl; + stream << "#include \"" << className << ".h\"" << endl << endl; + stream << "namespace BluezQt" << endl << "{" << endl << endl; + stream << className << "Adaptor::" << className << "Adaptor(" << className << " *parent)" << endl; + stream << " : QDBusAbstractAdaptor(parent)" << endl; + stream << " , m_" << lowerFirstChars(className) << "(parent)" << endl; + stream << "{" << endl << "}" << endl << endl; + + // Write property accessors + for (const auto &property : interface.properties().properties()) { + // Respect config + if ((property.tags().isOptional && !m_config.useOptional) || + (property.tags().isExperimental && !m_config.useExperimental)) { + continue; + } + stream << bluezToQt(property.type()) << " " << className << "Adaptor::" << lowerFirstChars(property.name()) << "() const" << endl; + stream << "{" << endl; + stream << " return m_" << lowerFirstChars(className) << "->" << lowerFirstChars(property.name()) << "();" << endl; + stream << "}" << endl << endl; + if (!property.tags().isReadOnly) { + stream << "void " << className << "Adaptor::set" << property.name() << "(const " << bluezToQt(property.type()) << " &" << lowerFirstChars(property.name()) << ");" << endl; + stream << "{" << endl; + stream << " m_" << lowerFirstChars(className) << "->set" << property.name() << "(" << lowerFirstChars(property.name()) << ");" << endl; + stream << "}" << endl << endl; + } + } + + // write Methods + for (const auto &method : interface.methods().methods()) { + // Respect config + if ((method.tags().isOptional && !m_config.useOptional) || + (method.tags().isExperimental && !m_config.useExperimental)) { + continue; + } + stream << bluezToQt(method.outParameter().type()) << " " << className << "Adaptor::" << method.name() << "("; + for (auto it = method.inParameters().begin(); + it != method.inParameters().end(); ++it) { + stream << "const " << bluezToQt(it->type()) << " &" << it->name(); + if (it != std::prev(method.inParameters().end())) { + stream << ", "; + } + } + stream << ")" << endl << "{" << endl; + stream << " return m_" << lowerFirstChars(className) << "->" << lowerFirstChars(method.name()) << "("; + for (auto it = method.inParameters().begin(); + it != method.inParameters().end(); ++it) { + stream << it->name(); + if (it != std::prev(method.inParameters().end())) { + stream << ", "; + } + } + stream << ");" << endl << "}" << endl << endl; + } + + stream << "} // namespace BluezQt" << endl; + + file.close(); + } +} + +QString CppGenerator::interfaceToClassName(const QString &interface) +{ + auto className = interface.mid(interface.lastIndexOf(QRegExp(QStringLiteral("\\.[A-Z]\\w+")))+1); + while (className.back() > L'0' && className.back() <= L'9') { + className.remove(className.size()-1, 1); + } + + return className; +} + +QString CppGenerator::lowerFirstChars(const QString &string) +{ + QString str(string); + //str.replace(0, 1, string.at(0).toLower()); + + QRegExp rx(QStringLiteral("^([A-Z]+)"), Qt::CaseSensitive, QRegExp::RegExp2); + if (rx.indexIn(string) != -1) { + QString caps = rx.capturedTexts().last(); + for (int i = 0; i < caps.size()-1; ++i) { + str.replace(i, 1, str.at(i).toLower()); + } + } + str.replace(0, 1, string.at(0).toLower()); + str.replace(string.size()-1, 1, string.at(string.size()-1).toLower()); + + return str; +} + +void CppGenerator::writeCopyrightHeader(QTextStream &stream) +{ + stream << "/*" << endl; + stream << " * BluezQt - Asynchronous Bluez wrapper library" << endl; + stream << " *" << endl; + stream << " * Copyright (C) " << m_config.year << " " << m_config.author << endl; + stream << " *" << endl; + stream << " * This library is free software; you can redistribute it and/or" << endl; + stream << " * modify it under the terms of the GNU Lesser General Public" << endl; + stream << " * License as published by the Free Software Foundation; either" << endl; + stream << " * version 2.1 of the License, or (at your option) version 3, or any" << endl; + stream << " * later version accepted by the membership of KDE e.V. (or its" << endl; + stream << " * successor approved by the membership of KDE e.V.), which shall" << endl; + stream << " * act as a proxy defined in Section 6 of version 3 of the license." << endl; + stream << " *" << endl; + stream << " * This library is distributed in the hope that it will be useful," << endl; + stream << " * but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl; + stream << " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU" << endl; + stream << " * Lesser General Public License for more details." << endl; + stream << " *" << endl; + stream << " * You should have received a copy of the GNU Lesser General Public" << endl; + stream << " * License along with this library. If not, see ." << endl; + stream << " */" << endl << endl; +} diff --git a/tools/bluezapi2qt/Interface.h b/tools/bluezapi2qt/Interface.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Interface.h @@ -0,0 +1,69 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef INTERFACE_H +#define INTERFACE_H + +#include "Methods.h" +#include "Properties.h" + +class Interface +{ +public: + Interface(); + + bool parse(const QString &line); + bool finalize(); + + QStringList comment() const; + QString service() const; + QString name() const; + QString objectPath() const; + Methods methods() const; + Properties properties() const; + +private: + enum class State { + Comment, + Service, + Interface, + ObjectPath, + Methods, + Properties + }; + + void parseComment(const QString &line); + void parseService(const QString &line); + void parseInterface(const QString &line); + void parseObjectPath(const QString &line); + + State m_state = State::Comment; + + QStringList m_comment; + QString m_service; + QString m_name; + QString m_objectPath; + Methods m_methods; + Properties m_properties; +}; + +#endif // INTERFACE_H diff --git a/tools/bluezapi2qt/Interface.cpp b/tools/bluezapi2qt/Interface.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Interface.cpp @@ -0,0 +1,147 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "Interface.h" + +Interface::Interface() +{ +} + +bool Interface::parse(const QString &line) +{ + if (line.startsWith(QStringLiteral("Service\t"))) { + m_state = State::Service; + } else if (line.startsWith(QStringLiteral("Interface\t"))) { + m_state = State::Interface; + } else if (line.startsWith(QStringLiteral("Object path\t"))) { + m_state = State::ObjectPath; + } else if (line.startsWith(QStringLiteral("Methods\t")) || Methods::isMethod(line)) { // Argh! AgentManager is missing the Methods keyword + m_state = State::Methods; + } else if (line.startsWith(QStringLiteral("Properties\t"))) { + m_state = State::Properties; + } else if (m_state != State::Comment && !line.isEmpty() && !line.startsWith(QStringLiteral("\t"))) { + // If we do not parse comment, but line starts with characters, we are done. + return false; + } + + switch (m_state) { + case State::Comment: + parseComment(line); + break; + case State::Service: + parseService(line); + break; + case State::Interface: + parseInterface(line); + break; + case State::ObjectPath: + parseObjectPath(line); + break; + case State::Methods: + m_methods.parse(line); + break; + case State::Properties: + m_properties.parse(line); + break; + } + + return true; +} + +bool Interface::finalize() +{ + bool success = true; + + success &= m_methods.finalize(); + success &= m_properties.finalize(); + + return success; +} + +QStringList Interface::comment() const +{ + return m_comment; +} +QString Interface::service() const +{ + return m_service; +} + +QString Interface::name() const +{ + return m_name; +} + +QString Interface::objectPath() const +{ + return m_objectPath; +} + +Methods Interface::methods() const +{ + return m_methods; +} + +Properties Interface::properties() const +{ + return m_properties; +} + +void Interface::parseComment(const QString &line) +{ + if (line.isEmpty()) { + m_comment.append(QString()); + return; + } else if (line.startsWith(QStringLiteral(" ")) || line.startsWith(QStringLiteral("\t"))) { + m_comment.append(QString()); + } + + if (!m_comment.last().isEmpty()) { + m_comment.last() += QStringLiteral(" "); + } + m_comment.last() += line; +} + +void Interface::parseService(const QString &line) +{ + QRegExp rx(QStringLiteral("Service\\t+(.+)"), Qt::CaseSensitive, QRegExp::RegExp2); + if (rx.indexIn(line) != -1) { + m_service = rx.capturedTexts().last(); + } +} + +void Interface::parseInterface(const QString &line) +{ + QRegExp rx(QStringLiteral("Interface\\t+(.+)"), Qt::CaseSensitive, QRegExp::RegExp2); + if (rx.indexIn(line) != -1) { + m_name = rx.capturedTexts().last(); + } +} + +void Interface::parseObjectPath(const QString &line) +{ + QRegExp rx(QStringLiteral("Object path\\t+(.+)"), Qt::CaseSensitive, QRegExp::RegExp2); + if (rx.indexIn(line) != -1) { + m_objectPath = rx.capturedTexts().last(); + } +} + diff --git a/tools/bluezapi2qt/Method.h b/tools/bluezapi2qt/Method.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Method.h @@ -0,0 +1,68 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef METHOD_H +#define METHOD_H + +#include "Comment.h" +#include "Parameter.h" + +class Method +{ +public: + struct Tags { + bool isOptional = false; + bool isDeprecated = false; + bool isExperimental = false; + }; + + Method(); + + bool finalize(); + + QString name() const; + QList inParameters() const; + QList outParameters() const; + Parameter outParameter() const; + Tags tags() const; + QStringList comment() const; + +private: + QString guessOutParameterName() const; + + QString m_name; + QStringList m_inParameterStrings; + QStringList m_outParameterStrings; + Parameter m_outParameter; + QStringList m_stringTags; + QString m_limitation; + Comment m_comment; + + // finalized members + Tags m_tags; + QList m_inParameters; + QList m_outParameters; + + friend class Methods; +}; + +#endif // METHOD_H diff --git a/tools/bluezapi2qt/Method.cpp b/tools/bluezapi2qt/Method.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Method.cpp @@ -0,0 +1,111 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "Method.h" + +Method::Method() +{ +} + +bool Method::finalize() +{ + for (const auto &tag : m_stringTags) { + m_tags.isOptional |= tag.contains(QStringLiteral("optional"), Qt::CaseInsensitive); + m_tags.isDeprecated |= tag.contains(QStringLiteral("deprecated"), Qt::CaseInsensitive); + m_tags.isExperimental |= tag.contains(QStringLiteral("experimental"), Qt::CaseInsensitive); + } + + bool success = true; + success &= m_comment.finalize(); + + for (const auto &inParam : m_inParameterStrings) { + m_inParameters.push_back(Parameter::fromString(inParam)); + } + + m_outParameterStrings.removeOne(QStringLiteral("void")); + if (m_outParameterStrings.isEmpty()) { + m_outParameter = Parameter::fromString(QStringLiteral("void unnamend")); + return true; + } + + // Guess out parameter name from method name + QString paramName = guessOutParameterName(); + if (!paramName.isEmpty()) { + m_outParameterStrings.front() += QStringLiteral(" ") + paramName; + m_outParameter = Parameter::fromString(m_outParameterStrings.front()); + } else { + for (int i = 0; i < m_outParameterStrings.size(); ++i) { + m_outParameterStrings[i] += QStringLiteral(" value") + QString::number(i); + } + } + + for (const auto &outParam : m_outParameterStrings) { + m_outParameters.push_back(Parameter::fromString(outParam)); + } + + return success; +} + +QString Method::name() const +{ + return m_name; +} + +QList Method::inParameters() const +{ + return m_inParameters; +} + +QList Method::outParameters() const +{ + return m_outParameters; +} + +Parameter Method::outParameter() const +{ + return m_outParameter; +} + +Method::Tags Method::tags() const +{ + return m_tags; +} + +QStringList Method::comment() const +{ + return m_comment; +} + +QString Method::guessOutParameterName() const +{ + if (m_outParameterStrings.size() != 1) { + return QString(); + } + + QRegExp rx(QStringLiteral("([A-Z][a-z0-9]+)+")); + if (rx.indexIn(m_name, 1) == -1) { + return QStringLiteral("value"); + } + + QStringList list = rx.capturedTexts(); + return list.last().toLower(); +} diff --git a/tools/bluezapi2qt/Methods.h b/tools/bluezapi2qt/Methods.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Methods.h @@ -0,0 +1,45 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef METHODS_H +#define METHODS_H + +#include "Method.h" + +class Methods +{ +public: + Methods(); + + static bool isMethod(const QString &line); + + void parse(const QString &line); + bool finalize(); + + std::list methods() const; + +private: + std::list m_methods; + Method *m_currentMethod = nullptr; +}; + +#endif // METHODS_H diff --git a/tools/bluezapi2qt/Methods.cpp b/tools/bluezapi2qt/Methods.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Methods.cpp @@ -0,0 +1,91 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "Methods.h" + +#include + +Methods::Methods() +{ +} + +bool Methods::isMethod(const QString &line) +{ + QRegExp rx(QStringLiteral( + "\\t+" // preceding tabs + "(?:(.+) )?" // return types - Argh! LE Advertising Manager does not specify return type + "([A-Z]\\w+)" // method name + "\\(([^\\)]*)\\)" // parameters + "(?: \\[(.*)\\])?" // tags + "(?: \\((.*)\\))?" // limitations + ), Qt::CaseInsensitive, QRegExp::RegExp2); + + // Check if we match a method + return (rx.indexIn(line) != -1); +} + +void Methods::parse(const QString &line) +{ + QRegExp rx(QStringLiteral( + "\\t+" // preceding tabs + "(?:(.+) )?" // return types - Argh! LE Advertising Manager does not specify return type + "([A-Z]\\w+)" // method name + "\\(([^\\)]*)\\)" // parameters + "(?: \\[(.*)\\])?" // tags + "(?: \\((.*)\\))?" // limitations + ), Qt::CaseInsensitive, QRegExp::RegExp2); + + // Check if we match a method + if (rx.indexIn(line) != -1) { + QStringList list = rx.capturedTexts(); + m_methods.emplace_back(Method()); + m_currentMethod = &m_methods.back(); + m_currentMethod->m_outParameterStrings = list.at(1).toLower().split(QStringLiteral(", "), QString::SkipEmptyParts); + m_currentMethod->m_name = list.at(2); + m_currentMethod->m_inParameterStrings = list.at(3).split(QStringLiteral(", "), QString::SkipEmptyParts); + m_currentMethod->m_stringTags = list.at(4).toLower().split(QStringLiteral(", "), QString::SkipEmptyParts); + m_currentMethod->m_limitation = list.at(5).toLower(); + } else if (m_currentMethod) { + // Skip first empty line + if (line.isEmpty() && m_currentMethod->m_comment.isEmpty()) { + return; + } + m_currentMethod->m_comment.append(line); + } +} + +bool Methods::finalize() +{ + bool success = true; + + for (auto &method : m_methods) { + success &= method.finalize(); + } + + return success; +} + + +std::list Methods::methods() const +{ + return m_methods; +} diff --git a/tools/bluezapi2qt/Parameter.h b/tools/bluezapi2qt/Parameter.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Parameter.h @@ -0,0 +1,38 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#pragma once + +#include + +class Parameter +{ +public: + static Parameter fromString(const QString &string); + + QString type() const; + QString name() const; + +private: + QString m_type; + QString m_name; +}; diff --git a/tools/bluezapi2qt/Parameter.cpp b/tools/bluezapi2qt/Parameter.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Parameter.cpp @@ -0,0 +1,47 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "Parameter.h" + +Parameter Parameter::fromString(const QString &string) +{ + Parameter param; + QStringList arg = string.split(QStringLiteral(" ")); + if (arg.size() != 2) { + return param; + } + + param.m_type = arg.first(); + param.m_name = arg.last(); + + return param; +} + +QString Parameter::type() const +{ + return m_type; +} + +QString Parameter::name() const +{ + return m_name; +} diff --git a/tools/bluezapi2qt/Properties.h b/tools/bluezapi2qt/Properties.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Properties.h @@ -0,0 +1,43 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef PROPERTIES_H +#define PROPERTIES_H + +#include "Property.h" + +class Properties +{ +public: + Properties(); + + void parse(const QString &line); + bool finalize(); + + std::list properties() const; + +private: + std::list m_properties; + Property *m_currentProperty = nullptr; +}; + +#endif // PROPERTIES_H diff --git a/tools/bluezapi2qt/Properties.cpp b/tools/bluezapi2qt/Properties.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Properties.cpp @@ -0,0 +1,77 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "Properties.h" + +#include +#include + +Properties::Properties() +{ +} + +void Properties::parse(const QString &line) +{ + QRegExp rx(QStringLiteral( + "(?:Properties|^)" // Properties keyword or start of line + "\\t{1,2}" // preceding tabs (max 2) + "([a-z1-6{}_]+)" // type name + " " // space + "([A-Z]\\w+)" // method name + "(?: \\[(.*)\\])?" // tags + "(?: \\((.*)\\))?" // limitations + ), Qt::CaseSensitive, QRegExp::RegExp2); + + // Check if we match a property + if (rx.indexIn(line) != -1) { + QStringList list = rx.capturedTexts(); + m_properties.emplace_back(Property()); + m_currentProperty = &m_properties.back(); + m_currentProperty->m_type = list.at(1).toLower(); + m_currentProperty->m_name = list.at(2); + m_currentProperty->m_stringTags = list.at(3).toLower().split(QStringLiteral(", "), QString::SkipEmptyParts); + m_currentProperty->m_limitation = list.at(4).toLower(); + } else if (m_currentProperty) { + // Skip first empty line + if (line.isEmpty() && m_currentProperty->m_comment.isEmpty()) { + return; + } + m_currentProperty->m_comment.append(line); + } +} + +bool Properties::finalize() +{ + bool success = true; + + for (auto &property : m_properties) { + success &= property.finalize(); + } + + return success; +} + + +std::list Properties::properties() const +{ + return m_properties; +} diff --git a/tools/bluezapi2qt/Property.h b/tools/bluezapi2qt/Property.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Property.h @@ -0,0 +1,57 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#pragma once + +#include "Comment.h" + +class Property +{ +public: + struct Tags { + bool isOptional = false; + bool isExperimental = false; + bool isReadOnly = false; + bool isServerOnly = false; + }; + + Property(); + + bool finalize(); + + QString name() const; + QString type() const; + Tags tags() const; + QStringList comment() const; + +private: + QString m_name; + QString m_type; + QStringList m_stringTags; + QString m_limitation; + Comment m_comment; + + // finalized members + Tags m_tags; + + friend class Properties; +}; diff --git a/tools/bluezapi2qt/Property.cpp b/tools/bluezapi2qt/Property.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/Property.cpp @@ -0,0 +1,63 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "Property.h" + +Property::Property() +{ +} + +bool Property::finalize() +{ + for (auto tag : m_stringTags) { + m_tags.isOptional |= tag.contains(QStringLiteral("optional"), Qt::CaseInsensitive); + m_tags.isExperimental |= tag.contains(QStringLiteral("experimental"), Qt::CaseInsensitive); + m_tags.isReadOnly |= tag.contains(QStringLiteral("read-only"), Qt::CaseInsensitive); + } + m_tags.isServerOnly = m_limitation.contains(QStringLiteral("server only"), Qt::CaseInsensitive); + + bool success = true; + success &= m_comment.finalize(); + + return success; +} + +QString Property::name() const +{ + return m_name; +} + +QString Property::type() const +{ + return m_type; +} + +Property::Tags Property::tags() const +{ + return m_tags; +} + +QStringList Property::comment() const +{ + return m_comment; +} + diff --git a/tools/bluezapi2qt/TODO b/tools/bluezapi2qt/TODO new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/TODO @@ -0,0 +1,2 @@ +- Finish C++ generators +- Add multiline method parsing diff --git a/tools/bluezapi2qt/TypeAnnotation.h b/tools/bluezapi2qt/TypeAnnotation.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/TypeAnnotation.h @@ -0,0 +1,37 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef TYPEANNOTATION_H +#define TYPEANNOTATION_H + +#include + +enum class AnnotationType { + Bluez = 0, + Dbus = 1, + Qt = 2 +}; +QString annotateType(AnnotationType from, AnnotationType to, const QString &type); + +QString bluezToQt(const QString &type); + +#endif // TYPEANNOTATION_H diff --git a/tools/bluezapi2qt/TypeAnnotation.cpp b/tools/bluezapi2qt/TypeAnnotation.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/TypeAnnotation.cpp @@ -0,0 +1,71 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "TypeAnnotation.h" + +#include + +QString annotateType(AnnotationType from, AnnotationType to, const QString &type) +{ + static const std::vector> table = { + {"boolean", "b", ""}, + //{{"fd"}, "", ""}, + {"object", "o", ""}, + {"string", "s", ""}, + //{{"uint16"}, "", ""}, + //{{"uint32"}, "", ""}, + {"dict", "a{sv}", "QVariantMap"}, + {"array{byte}", "ay", ""}, + {"array{dict}", "aa{sv}", "QVariantMapList"}, + {"array{string}", "as", ""}, + }; + + for (const auto &entry : table) { + if (entry.at(static_cast(from)) == type.toStdString()) { + return QString::fromStdString(entry.at(static_cast(to))); + } + } + + return QString(); +} + +QString bluezToQt(const QString &type) +{ + static const std::vector> table = { + {"boolean", "bool"}, + //{{"fd"}, ""}, + {"object", "QDBusObjectPath"}, + {"string", "QString"}, + {"dict", "QVariantMap"}, + {"array{byte}", "QByteArray"}, + {"array{dict}", "QVariantMapList"}, + {"array{string}", "QStringList"}, + }; + + for (const auto &entry : table) { + if (entry.front() == type.toStdString()) { + return QString::fromStdString(entry.back()); + } + } + + return type; +} diff --git a/tools/bluezapi2qt/XmlGenerator.h b/tools/bluezapi2qt/XmlGenerator.h new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/XmlGenerator.h @@ -0,0 +1,57 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#ifndef XMLGENERATOR_H +#define XMLGENERATOR_H + +class BluezApiParser; +class Method; +class Parameter; +class QString; +class QStringList; +class QTextStream; + +class XmlGenerator +{ +public: + struct Config { + bool useOptional = false; + bool useDeprecated = false; + bool useExperimental = false; + }; + XmlGenerator(const Config &config); + + bool generate(const BluezApiParser &parser); + +private: + static void writeHeader(QTextStream &stream); + static void writeFooter(QTextStream &stream); + static void writeInterface(QTextStream &stream, const QString &name); + static void closeInterface(QTextStream &stream); + static bool writeMethod(QTextStream &stream, const Method &method); + static bool writeArg(QTextStream &stream, const Parameter ¶m, const QString &dir); + static void writeAnnotation(QTextStream &stream, const Parameter ¶m, const QString &dir, int i); + + Config m_config; +}; + +#endif // XMLGENERATOR_H diff --git a/tools/bluezapi2qt/XmlGenerator.cpp b/tools/bluezapi2qt/XmlGenerator.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/XmlGenerator.cpp @@ -0,0 +1,155 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include "XmlGenerator.h" + +#include +#include + +#include "BluezApiParser.h" +#include "TypeAnnotation.h" + +XmlGenerator::XmlGenerator(const Config &config) : + m_config(config) +{ +} + +bool XmlGenerator::generate(const BluezApiParser &parser) +{ + // Iterate interfaces + for (const auto &interface : parser.interfaces()) { + // Only consider interfaces with methods + if (interface.methods().methods().empty()) { + continue; + } + + // Create file + QFile file(interface.name() + QStringLiteral(".xml")); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning() << "Error opening file for writing:" << file.fileName(); + return false; + } + + // Write content + QTextStream stream(&file); + writeHeader(stream); + writeInterface(stream, interface.name()); + + // Iterate methods + for (const auto &method : interface.methods().methods()) { + // Respect config + if ((method.tags().isDeprecated && !m_config.useDeprecated) || + (method.tags().isOptional && !m_config.useOptional) || + (method.tags().isExperimental && !m_config.useExperimental)) { + continue; + } + + writeMethod(stream, method); + } + + closeInterface(stream); + writeFooter(stream); + file.close(); + } + + return true; +} + +void XmlGenerator::writeHeader(QTextStream &stream) +{ + stream << "" << endl; + stream << "" << endl; + stream << "" << endl; +} + +void XmlGenerator::writeFooter(QTextStream &stream) +{ + stream << "" << endl; +} + +void XmlGenerator::writeInterface(QTextStream &stream, const QString &name) +{ + stream << " " << endl; +} + +void XmlGenerator::closeInterface(QTextStream &stream) +{ + stream << " " << endl; +} + +bool XmlGenerator::writeMethod(QTextStream &stream, const Method &method) +{ + stream << " " << endl; + return true; + } + + stream << ">" << endl; + + for (const auto ¶m : method.inParameters()) { + if (!writeArg(stream, param, QStringLiteral("in"))) { + return false; + } + } + for (const auto ¶m : method.outParameters()) { + if (!writeArg(stream, param, QStringLiteral("out"))) { + return false; + } + } + for (int i = 0; i < method.inParameters().size(); ++i) { + writeAnnotation(stream, method.inParameters().at(i), QStringLiteral("In"), i); + } + for (int i = 0; i < method.outParameters().size(); ++i) { + writeAnnotation(stream, method.outParameters().at(i), QStringLiteral("Out"), i); + } + + stream << " " << endl; + + return true; +} + +bool XmlGenerator::writeArg(QTextStream &stream, const Parameter ¶m, const QString &dir) +{ + auto dbusType = annotateType(AnnotationType::Bluez, AnnotationType::Dbus, param.type()); + if (dbusType.isEmpty()) { + return false; + } + stream << " " << endl; + + return true; +} + +void XmlGenerator::writeAnnotation(QTextStream &stream, const Parameter ¶m, const QString &dir, int i) +{ + auto qtType = annotateType(AnnotationType::Bluez, AnnotationType::Qt, param.type()); + if (qtType.isEmpty()) { + return; + } + stream << " " << endl; + + return; +} diff --git a/tools/bluezapi2qt/main.cpp b/tools/bluezapi2qt/main.cpp new file mode 100644 --- /dev/null +++ b/tools/bluezapi2qt/main.cpp @@ -0,0 +1,128 @@ +/* + * BluezQt - Asynchronous BlueZ wrapper library + * + * Copyright (C) 2019 Manuel Weichselbaumer + * + * This library 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) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "BluezApiParser.h" +#include "CppGenerator.h" +#include "XmlGenerator.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + QCoreApplication::setApplicationName(QStringLiteral("bluezapi2qt")); + QCoreApplication::setApplicationVersion(QStringLiteral("0.1")); + + // Add command line parsing + QCommandLineParser parser; + parser.setApplicationDescription(QStringLiteral("Generates D-BUS object introspection XML files out of BlueZ D-Bus API\n" + "description files (*-api.txt).")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument(QStringLiteral("-api.txt"), + QStringLiteral("BlueZ D-Bus API description file to use.")); + QCommandLineOption deprecatedOption(QStringList() << + QStringLiteral("d") << QStringLiteral("deprecated"), + QStringLiteral("Generate deprecated methods/properties")); + parser.addOption(deprecatedOption); + QCommandLineOption experimentalOption(QStringList() << + QStringLiteral("e") << QStringLiteral("experimental"), + QStringLiteral("Generate experimental methods/properties")); + parser.addOption(experimentalOption); + QCommandLineOption optionalOption(QStringList() << QStringLiteral("o") << QStringLiteral("optional"), + QStringLiteral("Generate optional methods/properties")); + parser.addOption(optionalOption); + QCommandLineOption xmlOption(QStringList() << QStringLiteral("x") << QStringLiteral("xml"), + QStringLiteral("Generate D-Bus object introspection XML files")); + parser.addOption(xmlOption); + QCommandLineOption cppOption(QStringList() << QStringLiteral("c") << QStringLiteral("cpp"), + QStringLiteral("Generate D-Bus interface adaptor C++ files")); + parser.addOption(cppOption); + QCommandLineOption authorOption(QStringList() << QStringLiteral("a") << QStringLiteral("author"), + QStringLiteral("Author for copyright header in C++ files"), QStringLiteral("author")); + parser.addOption(authorOption); + QCommandLineOption yearOption(QStringList() << QStringLiteral("y") << QStringLiteral("year"), + QStringLiteral("Year for copyright header in C++ files"), QStringLiteral("year")); + parser.addOption(yearOption); + parser.process(a); + + // Open file + auto positionalArgs = parser.positionalArguments(); + if (positionalArgs.isEmpty()) { + fputs(qPrintable(parser.helpText()), stderr); + return 1; + } + auto fileName = positionalArgs.takeFirst(); + QFileInfo inputInfo(fileName); + if (!inputInfo.exists() || !inputInfo.isFile() || !inputInfo.isReadable()) { + qCritical() << "Cannot open file" << fileName; + return 1; + } + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qCritical() << "Cannot open file" << file.fileName(); + return 1; + } + QTextStream stream(&file); + + // Parse file + BluezApiParser bluezParser; + if (!bluezParser.parse(stream)) { + qCritical() << "Error parsing file" << file.fileName(); + return 1; + } + if (!bluezParser.finalize()) { + qCritical() << "Error parsing file" << file.fileName(); + return 1; + } + + if (parser.isSet(xmlOption)) { + XmlGenerator::Config xmlConfig; + xmlConfig.useOptional = parser.isSet(optionalOption);; + xmlConfig.useDeprecated = parser.isSet(deprecatedOption);; + xmlConfig.useExperimental = parser.isSet(experimentalOption);; + XmlGenerator xmlGenerator(xmlConfig); + if (!xmlGenerator.generate(bluezParser)) { + qCritical() << "Error generating xml"; + return 1; + } + } + + if (parser.isSet(cppOption)) { + CppGenerator::Config cppConfig; + cppConfig.author = parser.value(authorOption); + cppConfig.year = parser.value(yearOption); + CppGenerator cppGenerator(cppConfig); + if (!cppGenerator.generate(bluezParser)) { + qCritical() << "Error generating C++ files"; + return 1; + } + } + + return 0; +}