Convert qtwaylandscanner into a class

Encapsulate what the scanner needs of functions and state into a class,
Scanner, instead of keeping everything in the global namespace.

Change-Id: Idd4b412bb7f709f24c86abe82b135c09b7985878
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
This commit is contained in:
Johan Klokkhammer Helsing 2018-08-06 17:30:26 +02:00 committed by Johan Helsing
parent 0f9595ae09
commit 83abc8bf60

View File

@ -41,36 +41,18 @@
#include <QFile> #include <QFile>
#include <QXmlStreamReader> #include <QXmlStreamReader>
enum Option { class Scanner
ClientHeader,
ServerHeader,
ClientCode,
ServerCode
} option;
bool isServerSide()
{ {
return option == ServerHeader || option == ServerCode; public:
} explicit Scanner() {}
~Scanner() { delete m_xml; }
QByteArray protocolName; bool parseArguments(int argc, char **argv);
void printUsage();
bool parseOption(const char *str, Option *option) bool process();
{ void printErrors();
if (str == QLatin1String("client-header"))
*option = ClientHeader;
else if (str == QLatin1String("server-header"))
*option = ServerHeader;
else if (str == QLatin1String("client-code"))
*option = ClientCode;
else if (str == QLatin1String("server-code"))
*option = ServerCode;
else
return false;
return true;
}
private:
struct WaylandEnumEntry { struct WaylandEnumEntry {
QByteArray name; QByteArray name;
QByteArray value; QByteArray value;
@ -107,26 +89,104 @@ struct WaylandInterface {
QList<WaylandEvent> requests; QList<WaylandEvent> requests;
}; };
QByteArray byteArrayValue(const QXmlStreamReader &xml, const char *name) 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;
}
void Scanner::printUsage()
{
fprintf(stderr, "Usage: %s [client-header|server-header|client-code|server-code] specfile [header-path] [prefix]\n", m_scannerName.constData());
}
bool Scanner::isServerSide()
{
return m_option == ServerHeader || m_option == ServerCode;
}
bool Scanner::parseOption(const char *str)
{
if (str == QLatin1String("client-header"))
m_option = ClientHeader;
else if (str == QLatin1String("server-header"))
m_option = ServerHeader;
else if (str == QLatin1String("client-code"))
m_option = ClientCode;
else if (str == QLatin1String("server-code"))
m_option = ServerCode;
else
return false;
return true;
}
QByteArray Scanner::byteArrayValue(const QXmlStreamReader &xml, const char *name)
{ {
if (xml.attributes().hasAttribute(name)) if (xml.attributes().hasAttribute(name))
return xml.attributes().value(name).toUtf8(); return xml.attributes().value(name).toUtf8();
return QByteArray(); 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; bool ok;
int result = byteArrayValue(xml, name).toInt(&ok); int result = byteArrayValue(xml, name).toInt(&ok);
return ok ? result : defaultValue; 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"; return byteArrayValue(xml, name) == "true";
} }
WaylandEvent readEvent(QXmlStreamReader &xml, bool request) Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request)
{ {
WaylandEvent event; WaylandEvent event;
event.request = request; event.request = request;
@ -148,7 +208,7 @@ WaylandEvent readEvent(QXmlStreamReader &xml, bool request)
return event; return event;
} }
WaylandEnum readEnum(QXmlStreamReader &xml) Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml)
{ {
WaylandEnum result; WaylandEnum result;
result.name = byteArrayValue(xml, "name"); result.name = byteArrayValue(xml, "name");
@ -168,7 +228,7 @@ WaylandEnum readEnum(QXmlStreamReader &xml)
return result; return result;
} }
WaylandInterface readInterface(QXmlStreamReader &xml) Scanner::WaylandInterface Scanner::readInterface(QXmlStreamReader &xml)
{ {
WaylandInterface interface; WaylandInterface interface;
interface.name = byteArrayValue(xml, "name"); interface.name = byteArrayValue(xml, "name");
@ -188,7 +248,7 @@ WaylandInterface readInterface(QXmlStreamReader &xml)
return interface; return interface;
} }
QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface) QByteArray Scanner::waylandToCType(const QByteArray &waylandType, const QByteArray &interface)
{ {
if (waylandType == "string") if (waylandType == "string")
return "const char *"; return "const char *";
@ -212,7 +272,7 @@ QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &inter
return waylandType; 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") if (waylandType == "string")
return "const QString &"; return "const QString &";
@ -222,7 +282,7 @@ QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &inte
return waylandToCType(waylandType, interface); 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) { for (int i = 0; i < arguments.size(); ++i) {
if (arguments.at(i).type == "new_id") if (arguments.at(i).type == "new_id")
@ -231,7 +291,7 @@ const WaylandArgument *newIdArgument(const QList<WaylandArgument> &arguments)
return nullptr; 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()); printf("%s(", e.name.constData());
bool needsComma = false; bool needsComma = false;
@ -274,7 +334,7 @@ void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource
printf(")"); 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 ? " " : ""; const char *indent = deepIndent ? " " : "";
printf("handle_%s(\n", e.name.constData()); printf("handle_%s(\n", e.name.constData());
@ -299,7 +359,7 @@ void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName
printf(")"); printf(")");
} }
void printEnums(const QList<WaylandEnum> &enums) void Scanner::printEnums(const QList<WaylandEnum> &enums)
{ {
for (int i = 0; i < enums.size(); ++i) { for (int i = 0; i < enums.size(); ++i) {
printf("\n"); 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)) if (!m_prefix.isEmpty() && name.startsWith(m_prefix))
return name.mid(prefix.size()); return name.mid(m_prefix.size());
if (name.startsWith("qt_") || name.startsWith("wl_")) if (name.startsWith("qt_") || name.startsWith("wl_"))
return name.mid(3); return name.mid(3);
return name; return name;
} }
bool ignoreInterface(const QByteArray &name) bool Scanner::ignoreInterface(const QByteArray &name)
{ {
return name == "wl_display" return name == "wl_display"
|| (isServerSide() && name == "wl_registry"); || (isServerSide() && name == "wl_registry");
} }
void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArray &prefix) bool Scanner::process()
{ {
if (!xml.readNextStartElement()) QFile file(m_protocolFilePath);
return; if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
fprintf(stderr, "Unable to open file %s\n", m_protocolFilePath.constData());
if (xml.name() != "protocol") { return false;
xml.raiseError(QStringLiteral("The file is not a wayland protocol file."));
return;
} }
protocolName = byteArrayValue(xml, "name"); m_xml = new QXmlStreamReader(&file);
if (!m_xml->readNextStartElement())
return false;
if (protocolName.isEmpty()) { if (m_xml->name() != "protocol") {
xml.raiseError(QStringLiteral("Missing protocol name.")); m_xml->raiseError(QStringLiteral("The file is not a wayland protocol file."));
return; return false;
}
m_protocolName = byteArrayValue(*m_xml, "name");
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 //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 //However, the wayland-scanner doesn't do so we will do the same for now
//QByteArray preProcessorProtocolName = QByteArray(protocolName).replace('-', '_').toUpper(); //QByteArray preProcessorProtocolName = QByteArray(m_protocolName).replace('-', '_').toUpper();
QByteArray preProcessorProtocolName = QByteArray(protocolName).toUpper(); QByteArray preProcessorProtocolName = QByteArray(m_protocolName).toUpper();
QList<WaylandInterface> interfaces; QList<WaylandInterface> interfaces;
while (xml.readNextStartElement()) { while (m_xml->readNextStartElement()) {
if (xml.name() == "interface") if (m_xml->name() == "interface")
interfaces << readInterface(xml); interfaces << readInterface(*m_xml);
else else
xml.skipCurrentElement(); m_xml->skipCurrentElement();
} }
if (xml.hasError()) if (m_xml->hasError())
return; return false;
if (option == ServerHeader) { if (m_option == ServerHeader) {
QByteArray inclusionGuard = QByteArray("QT_WAYLAND_SERVER_") + preProcessorProtocolName.constData(); QByteArray inclusionGuard = QByteArray("QT_WAYLAND_SERVER_") + preProcessorProtocolName.constData();
printf("#ifndef %s\n", inclusionGuard.constData()); printf("#ifndef %s\n", inclusionGuard.constData());
printf("#define %s\n", inclusionGuard.constData()); printf("#define %s\n", inclusionGuard.constData());
printf("\n"); printf("\n");
printf("#include \"wayland-server.h\"\n"); printf("#include \"wayland-server.h\"\n");
if (headerPath.isEmpty()) if (m_headerPath.isEmpty())
printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
else 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 <QByteArray>\n");
printf("#include <QMultiMap>\n"); printf("#include <QMultiMap>\n");
printf("#include <QString>\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_GCC(\"-Wmissing-field-initializers\")\n");
printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n"); printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n");
QByteArray serverExport; QByteArray serverExport;
if (headerPath.size()) { if (m_headerPath.size()) {
serverExport = QByteArray("Q_WAYLAND_SERVER_") + preProcessorProtocolName + "_EXPORT"; serverExport = QByteArray("Q_WAYLAND_SERVER_") + preProcessorProtocolName + "_EXPORT";
printf("\n"); printf("\n");
printf("#if !defined(%s)\n", serverExport.constData()); 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(); const char *interfaceName = interface.name.constData();
QByteArray stripped = stripInterfaceName(interface.name, prefix); QByteArray stripped = stripInterfaceName(interface.name);
const char *interfaceNameStripped = stripped.constData(); const char *interfaceNameStripped = stripped.constData();
printf(" class %s %s\n {\n", serverExport.constData(), interfaceName); 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"); printf("#endif\n");
} }
if (option == ServerCode) { if (m_option == ServerCode) {
if (headerPath.isEmpty()) if (m_headerPath.isEmpty())
printf("#include \"qwayland-server-%s.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); printf("#include \"qwayland-server-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
else 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("\n");
printf("QT_BEGIN_NAMESPACE\n"); printf("QT_BEGIN_NAMESPACE\n");
printf("QT_WARNING_PUSH\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(); const char *interfaceName = interface.name.constData();
QByteArray stripped = stripInterfaceName(interface.name, prefix); QByteArray stripped = stripInterfaceName(interface.name);
const char *interfaceNameStripped = stripped.constData(); const char *interfaceNameStripped = stripped.constData();
printf(" %s::%s(struct ::wl_client *client, int id, int version)\n", interfaceName, interfaceName); 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"); printf("QT_END_NAMESPACE\n");
} }
if (option == ClientHeader) { if (m_option == ClientHeader) {
QByteArray inclusionGuard = QByteArray("QT_WAYLAND_") + preProcessorProtocolName.constData(); QByteArray inclusionGuard = QByteArray("QT_WAYLAND_") + preProcessorProtocolName.constData();
printf("#ifndef %s\n", inclusionGuard.constData()); printf("#ifndef %s\n", inclusionGuard.constData());
printf("#define %s\n", inclusionGuard.constData()); printf("#define %s\n", inclusionGuard.constData());
printf("\n"); printf("\n");
if (headerPath.isEmpty()) if (m_headerPath.isEmpty())
printf("#include \"wayland-%s-client-protocol.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); printf("#include \"wayland-%s-client-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
else 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 <QByteArray>\n");
printf("#include <QString>\n"); printf("#include <QString>\n");
printf("\n"); printf("\n");
@ -878,7 +945,7 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr
QByteArray clientExport; QByteArray clientExport;
if (headerPath.size()) { if (m_headerPath.size()) {
clientExport = QByteArray("Q_WAYLAND_CLIENT_") + preProcessorProtocolName + "_EXPORT"; clientExport = QByteArray("Q_WAYLAND_CLIENT_") + preProcessorProtocolName + "_EXPORT";
printf("\n"); printf("\n");
printf("#if !defined(%s)\n", clientExport.constData()); 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(); const char *interfaceName = interface.name.constData();
QByteArray stripped = stripInterfaceName(interface.name, prefix); QByteArray stripped = stripInterfaceName(interface.name);
const char *interfaceNameStripped = stripped.constData(); const char *interfaceNameStripped = stripped.constData();
printf(" class %s %s\n {\n", clientExport.constData(), interfaceName); 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"); printf("#endif\n");
} }
if (option == ClientCode) { if (m_option == ClientCode) {
if (headerPath.isEmpty()) if (m_headerPath.isEmpty())
printf("#include \"qwayland-%s.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); printf("#include \"qwayland-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
else 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("\n");
printf("QT_BEGIN_NAMESPACE\n"); printf("QT_BEGIN_NAMESPACE\n");
printf("QT_WARNING_PUSH\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(); const char *interfaceName = interface.name.constData();
QByteArray stripped = stripInterfaceName(interface.name, prefix); QByteArray stripped = stripInterfaceName(interface.name);
const char *interfaceNameStripped = stripped.constData(); const char *interfaceNameStripped = stripped.constData();
bool hasEvents = !interface.events.isEmpty(); 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_WARNING_POP\n");
printf("QT_END_NAMESPACE\n"); printf("QT_END_NAMESPACE\n");
} }
return true;
}
void Scanner::printErrors()
{
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) int main(int argc, char **argv)
{ {
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;
}
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
Scanner scanner;
QByteArray headerPath; if (!scanner.parseArguments(argc, argv)) {
if (argc >= 4) scanner.printUsage();
headerPath = QByteArray(argv[3]); return EXIT_FAILURE;
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;
} }
QXmlStreamReader xml(&file); if (!scanner.process()) {
process(xml, headerPath, prefix); scanner.printErrors();
return EXIT_FAILURE;
}
if (xml.hasError()) { return EXIT_SUCCESS;
fprintf(stderr, "XML error: %s\nLine %lld, column %lld\n", xml.errorString().toLocal8Bit().constData(), xml.lineNumber(), xml.columnNumber());
return 1;
}
} }