diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/qtwaylandscanner/qtwaylandscanner.cpp | 319 |
1 files changed, 191 insertions, 128 deletions
diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp index 1b884a42..bdcbffa0 100644 --- a/src/qtwaylandscanner/qtwaylandscanner.cpp +++ b/src/qtwaylandscanner/qtwaylandscanner.cpp @@ -41,92 +41,152 @@ #include <QFile> #include <QXmlStreamReader> -enum Option { - ClientHeader, - ServerHeader, - ClientCode, - ServerCode -} option; - -bool isServerSide() +class Scanner { - return option == ServerHeader || option == ServerCode; +public: + explicit Scanner() {} + ~Scanner() { delete m_xml; } + + bool parseArguments(int argc, char **argv); + void printUsage(); + bool process(); + void printErrors(); + +private: + struct WaylandEnumEntry { + QByteArray name; + QByteArray value; + QByteArray summary; + }; + + struct WaylandEnum { + QByteArray name; + + QList<WaylandEnumEntry> entries; + }; + + struct WaylandArgument { + QByteArray name; + QByteArray type; + QByteArray interface; + QByteArray summary; + bool allowNull; + }; + + struct WaylandEvent { + bool request; + QByteArray name; + QByteArray type; + QList<WaylandArgument> arguments; + }; + + struct WaylandInterface { + QByteArray name; + int version; + + QList<WaylandEnum> enums; + QList<WaylandEvent> events; + QList<WaylandEvent> requests; + }; + + bool isServerSide(); + bool parseOption(const char *str); + + QByteArray byteArrayValue(const QXmlStreamReader &xml, const char *name); + int intValue(const QXmlStreamReader &xml, const char *name, int defaultValue = 0); + bool boolValue(const QXmlStreamReader &xml, const char *name); + WaylandEvent readEvent(QXmlStreamReader &xml, bool request); + Scanner::WaylandEnum readEnum(QXmlStreamReader &xml); + Scanner::WaylandInterface readInterface(QXmlStreamReader &xml); + QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface); + QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray); + const Scanner::WaylandArgument *newIdArgument(const QList<WaylandArgument> &arguments); + + void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource = false); + void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent = true); + void printEnums(const QList<WaylandEnum> &enums); + + QByteArray stripInterfaceName(const QByteArray &name); + bool ignoreInterface(const QByteArray &name); + + enum Option { + ClientHeader, + ServerHeader, + ClientCode, + ServerCode + } m_option; + + QByteArray m_protocolName; + QByteArray m_protocolFilePath; + QByteArray m_scannerName; + QByteArray m_headerPath; + QByteArray m_prefix; + QXmlStreamReader *m_xml = nullptr; +}; + +bool Scanner::parseArguments(int argc, char **argv) +{ + QByteArray m_scannerName = argv[0]; + + if (argc <= 2 || !parseOption(argv[1])) + return false; + + m_protocolFilePath = QByteArray(argv[2]); + + if (argc >= 4) + m_headerPath = QByteArray(argv[3]); + if (argc == 5) + m_prefix = QByteArray(argv[4]); + + return true; } -QByteArray protocolName; +void Scanner::printUsage() +{ + fprintf(stderr, "Usage: %s [client-header|server-header|client-code|server-code] specfile [header-path] [prefix]\n", m_scannerName.constData()); +} -bool parseOption(const char *str, Option *option) +bool Scanner::isServerSide() +{ + return m_option == ServerHeader || m_option == ServerCode; +} + +bool Scanner::parseOption(const char *str) { if (str == QLatin1String("client-header")) - *option = ClientHeader; + m_option = ClientHeader; else if (str == QLatin1String("server-header")) - *option = ServerHeader; + m_option = ServerHeader; else if (str == QLatin1String("client-code")) - *option = ClientCode; + m_option = ClientCode; else if (str == QLatin1String("server-code")) - *option = ServerCode; + m_option = ServerCode; else return false; return true; } -struct WaylandEnumEntry { - QByteArray name; - QByteArray value; - QByteArray summary; -}; - -struct WaylandEnum { - QByteArray name; - - QList<WaylandEnumEntry> entries; -}; - -struct WaylandArgument { - QByteArray name; - QByteArray type; - QByteArray interface; - QByteArray summary; - bool allowNull; -}; - -struct WaylandEvent { - bool request; - QByteArray name; - QByteArray type; - QList<WaylandArgument> arguments; -}; - -struct WaylandInterface { - QByteArray name; - int version; - - QList<WaylandEnum> enums; - QList<WaylandEvent> events; - QList<WaylandEvent> requests; -}; - -QByteArray byteArrayValue(const QXmlStreamReader &xml, const char *name) +QByteArray Scanner::byteArrayValue(const QXmlStreamReader &xml, const char *name) { if (xml.attributes().hasAttribute(name)) return xml.attributes().value(name).toUtf8(); return QByteArray(); } -int intValue(const QXmlStreamReader &xml, const char *name, int defaultValue = 0) +int Scanner::intValue(const QXmlStreamReader &xml, const char *name, int defaultValue) { bool ok; int result = byteArrayValue(xml, name).toInt(&ok); return ok ? result : defaultValue; } -bool boolValue(const QXmlStreamReader &xml, const char *name) +bool Scanner::boolValue(const QXmlStreamReader &xml, const char *name) { return byteArrayValue(xml, name) == "true"; } -WaylandEvent readEvent(QXmlStreamReader &xml, bool request) +Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request) { WaylandEvent event; event.request = request; @@ -148,7 +208,7 @@ WaylandEvent readEvent(QXmlStreamReader &xml, bool request) return event; } -WaylandEnum readEnum(QXmlStreamReader &xml) +Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml) { WaylandEnum result; result.name = byteArrayValue(xml, "name"); @@ -168,7 +228,7 @@ WaylandEnum readEnum(QXmlStreamReader &xml) return result; } -WaylandInterface readInterface(QXmlStreamReader &xml) +Scanner::WaylandInterface Scanner::readInterface(QXmlStreamReader &xml) { WaylandInterface interface; interface.name = byteArrayValue(xml, "name"); @@ -188,7 +248,7 @@ WaylandInterface readInterface(QXmlStreamReader &xml) return interface; } -QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface) +QByteArray Scanner::waylandToCType(const QByteArray &waylandType, const QByteArray &interface) { if (waylandType == "string") return "const char *"; @@ -212,7 +272,7 @@ QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &inter return waylandType; } -QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray) +QByteArray Scanner::waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray) { if (waylandType == "string") return "const QString &"; @@ -222,7 +282,7 @@ QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &inte return waylandToCType(waylandType, interface); } -const WaylandArgument *newIdArgument(const QList<WaylandArgument> &arguments) +const Scanner::WaylandArgument *Scanner::newIdArgument(const QList<WaylandArgument> &arguments) { for (int i = 0; i < arguments.size(); ++i) { if (arguments.at(i).type == "new_id") @@ -231,7 +291,7 @@ const WaylandArgument *newIdArgument(const QList<WaylandArgument> &arguments) return nullptr; } -void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource = false) +void Scanner::printEvent(const WaylandEvent &e, bool omitNames, bool withResource) { printf("%s(", e.name.constData()); bool needsComma = false; @@ -274,7 +334,7 @@ void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource printf(")"); } -void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent = true) +void Scanner::printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent) { const char *indent = deepIndent ? " " : ""; printf("handle_%s(\n", e.name.constData()); @@ -299,7 +359,7 @@ void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName printf(")"); } -void printEnums(const QList<WaylandEnum> &enums) +void Scanner::printEnums(const QList<WaylandEnum> &enums) { for (int i = 0; i < enums.size(); ++i) { printf("\n"); @@ -318,66 +378,73 @@ void printEnums(const QList<WaylandEnum> &enums) } } -QByteArray stripInterfaceName(const QByteArray &name, const QByteArray &prefix) +QByteArray Scanner::stripInterfaceName(const QByteArray &name) { - if (!prefix.isEmpty() && name.startsWith(prefix)) - return name.mid(prefix.size()); + if (!m_prefix.isEmpty() && name.startsWith(m_prefix)) + return name.mid(m_prefix.size()); if (name.startsWith("qt_") || name.startsWith("wl_")) return name.mid(3); return name; } -bool ignoreInterface(const QByteArray &name) +bool Scanner::ignoreInterface(const QByteArray &name) { return name == "wl_display" || (isServerSide() && name == "wl_registry"); } -void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArray &prefix) +bool Scanner::process() { - if (!xml.readNextStartElement()) - return; + QFile file(m_protocolFilePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + fprintf(stderr, "Unable to open file %s\n", m_protocolFilePath.constData()); + return false; + } - if (xml.name() != "protocol") { - xml.raiseError(QStringLiteral("The file is not a wayland protocol file.")); - return; + m_xml = new QXmlStreamReader(&file); + if (!m_xml->readNextStartElement()) + return false; + + if (m_xml->name() != "protocol") { + m_xml->raiseError(QStringLiteral("The file is not a wayland protocol file.")); + return false; } - protocolName = byteArrayValue(xml, "name"); + m_protocolName = byteArrayValue(*m_xml, "name"); - if (protocolName.isEmpty()) { - xml.raiseError(QStringLiteral("Missing protocol name.")); - return; + if (m_protocolName.isEmpty()) { + m_xml->raiseError(QStringLiteral("Missing protocol name.")); + return false; } //We should convert - to _ so that the preprocessor wont generate code which will lead to unexpected behavior //However, the wayland-scanner doesn't do so we will do the same for now - //QByteArray preProcessorProtocolName = QByteArray(protocolName).replace('-', '_').toUpper(); - QByteArray preProcessorProtocolName = QByteArray(protocolName).toUpper(); + //QByteArray preProcessorProtocolName = QByteArray(m_protocolName).replace('-', '_').toUpper(); + QByteArray preProcessorProtocolName = QByteArray(m_protocolName).toUpper(); QList<WaylandInterface> interfaces; - while (xml.readNextStartElement()) { - if (xml.name() == "interface") - interfaces << readInterface(xml); + while (m_xml->readNextStartElement()) { + if (m_xml->name() == "interface") + interfaces << readInterface(*m_xml); else - xml.skipCurrentElement(); + m_xml->skipCurrentElement(); } - if (xml.hasError()) - return; + if (m_xml->hasError()) + return false; - if (option == ServerHeader) { + if (m_option == ServerHeader) { QByteArray inclusionGuard = QByteArray("QT_WAYLAND_SERVER_") + preProcessorProtocolName.constData(); printf("#ifndef %s\n", inclusionGuard.constData()); printf("#define %s\n", inclusionGuard.constData()); printf("\n"); printf("#include \"wayland-server.h\"\n"); - if (headerPath.isEmpty()) - printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); + if (m_headerPath.isEmpty()) + printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData()); else - printf("#include <%s/wayland-%s-server-protocol.h>\n", headerPath.constData(), QByteArray(protocolName).replace('_', '-').constData()); + printf("#include <%s/wayland-%s-server-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData()); printf("#include <QByteArray>\n"); printf("#include <QMultiMap>\n"); printf("#include <QString>\n"); @@ -396,7 +463,7 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n"); printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n"); QByteArray serverExport; - if (headerPath.size()) { + if (m_headerPath.size()) { serverExport = QByteArray("Q_WAYLAND_SERVER_") + preProcessorProtocolName + "_EXPORT"; printf("\n"); printf("#if !defined(%s)\n", serverExport.constData()); @@ -418,7 +485,7 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr const char *interfaceName = interface.name.constData(); - QByteArray stripped = stripInterfaceName(interface.name, prefix); + QByteArray stripped = stripInterfaceName(interface.name); const char *interfaceNameStripped = stripped.constData(); printf(" class %s %s\n {\n", serverExport.constData(), interfaceName); @@ -547,11 +614,11 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf("#endif\n"); } - if (option == ServerCode) { - if (headerPath.isEmpty()) - printf("#include \"qwayland-server-%s.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); + if (m_option == ServerCode) { + if (m_headerPath.isEmpty()) + printf("#include \"qwayland-server-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData()); else - printf("#include <%s/qwayland-server-%s.h>\n", headerPath.constData(), QByteArray(protocolName).replace('_', '-').constData()); + printf("#include <%s/qwayland-server-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData()); printf("\n"); printf("QT_BEGIN_NAMESPACE\n"); printf("QT_WARNING_PUSH\n"); @@ -573,7 +640,7 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr const char *interfaceName = interface.name.constData(); - QByteArray stripped = stripInterfaceName(interface.name, prefix); + QByteArray stripped = stripInterfaceName(interface.name); const char *interfaceNameStripped = stripped.constData(); printf(" %s::%s(struct ::wl_client *client, int id, int version)\n", interfaceName, interfaceName); @@ -860,15 +927,15 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf("QT_END_NAMESPACE\n"); } - if (option == ClientHeader) { + if (m_option == ClientHeader) { QByteArray inclusionGuard = QByteArray("QT_WAYLAND_") + preProcessorProtocolName.constData(); printf("#ifndef %s\n", inclusionGuard.constData()); printf("#define %s\n", inclusionGuard.constData()); printf("\n"); - if (headerPath.isEmpty()) - printf("#include \"wayland-%s-client-protocol.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); + if (m_headerPath.isEmpty()) + printf("#include \"wayland-%s-client-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData()); else - printf("#include <%s/wayland-%s-client-protocol.h>\n", headerPath.constData(), QByteArray(protocolName).replace('_', '-').constData()); + printf("#include <%s/wayland-%s-client-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData()); printf("#include <QByteArray>\n"); printf("#include <QString>\n"); printf("\n"); @@ -878,7 +945,7 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr QByteArray clientExport; - if (headerPath.size()) { + if (m_headerPath.size()) { clientExport = QByteArray("Q_WAYLAND_CLIENT_") + preProcessorProtocolName + "_EXPORT"; printf("\n"); printf("#if !defined(%s)\n", clientExport.constData()); @@ -899,7 +966,7 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr const char *interfaceName = interface.name.constData(); - QByteArray stripped = stripInterfaceName(interface.name, prefix); + QByteArray stripped = stripInterfaceName(interface.name); const char *interfaceNameStripped = stripped.constData(); printf(" class %s %s\n {\n", clientExport.constData(), interfaceName); @@ -978,11 +1045,11 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf("#endif\n"); } - if (option == ClientCode) { - if (headerPath.isEmpty()) - printf("#include \"qwayland-%s.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); + if (m_option == ClientCode) { + if (m_headerPath.isEmpty()) + printf("#include \"qwayland-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData()); else - printf("#include <%s/qwayland-%s.h>\n", headerPath.constData(), QByteArray(protocolName).replace('_', '-').constData()); + printf("#include <%s/qwayland-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData()); printf("\n"); printf("QT_BEGIN_NAMESPACE\n"); printf("QT_WARNING_PUSH\n"); @@ -997,7 +1064,7 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr const char *interfaceName = interface.name.constData(); - QByteArray stripped = stripInterfaceName(interface.name, prefix); + QByteArray stripped = stripInterfaceName(interface.name); const char *interfaceNameStripped = stripped.constData(); bool hasEvents = !interface.events.isEmpty(); @@ -1172,34 +1239,30 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf("QT_WARNING_POP\n"); printf("QT_END_NAMESPACE\n"); } + + return true; } -int main(int argc, char **argv) +void Scanner::printErrors() { - if (argc <= 2 || !parseOption(argv[1], &option)) { - fprintf(stderr, "Usage: %s [client-header|server-header|client-code|server-code] specfile [header-path] [prefix]\n", argv[0]); - return 1; - } + if (m_xml->hasError()) + fprintf(stderr, "XML error: %s\nLine %lld, column %lld\n", m_xml->errorString().toLocal8Bit().constData(), m_xml->lineNumber(), m_xml->columnNumber()); +} +int main(int argc, char **argv) +{ QCoreApplication app(argc, argv); + Scanner scanner; - QByteArray headerPath; - if (argc >= 4) - headerPath = QByteArray(argv[3]); - QByteArray prefix; - if (argc == 5) - prefix = QByteArray(argv[4]); - QFile file(argv[2]); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - fprintf(stderr, "Unable to open file %s\n", argv[2]); - return 1; + if (!scanner.parseArguments(argc, argv)) { + scanner.printUsage(); + return EXIT_FAILURE; } - QXmlStreamReader xml(&file); - process(xml, headerPath, prefix); - - if (xml.hasError()) { - fprintf(stderr, "XML error: %s\nLine %lld, column %lld\n", xml.errorString().toLocal8Bit().constData(), xml.lineNumber(), xml.columnNumber()); - return 1; + if (!scanner.process()) { + scanner.printErrors(); + return EXIT_FAILURE; } + + return EXIT_SUCCESS; } |