summaryrefslogtreecommitdiffstats
path: root/src/tools/qdbuscpp2xml
diff options
context:
space:
mode:
authorStephen Kelly <stephen.kelly@kdab.com>2012-03-08 23:43:28 +0100
committerQt by Nokia <qt-info@nokia.com>2012-03-18 14:14:42 +0100
commit72367b1679f8176c8f8a2a424a1c9325433dd8cd (patch)
treee5df865b041b1a1841a816a54b6d1664ac7f7431 /src/tools/qdbuscpp2xml
parent0054505510b6f2bd20eb7648dbbcaa0e0a975d79 (diff)
Bootstrap qdbuscpp2xml.
This involves invoking the Moc classes directly and using the data structures it provides instead of invoking the moc exectutable and parsing the generated code. Change-Id: Ia5c654e8ef58d52d0d3376252c13e13885f80da3 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/tools/qdbuscpp2xml')
-rw-r--r--src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp431
-rw-r--r--src/tools/qdbuscpp2xml/qdbuscpp2xml.pro38
2 files changed, 252 insertions, 217 deletions
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
index 5814dc740b..2029147ecf 100644
--- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
+++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
@@ -43,12 +43,9 @@
#include <QString>
#include <QVarLengthArray>
#include <QFile>
-#include <QProcess>
-#include <QMetaObject>
#include <QList>
+#include <QBuffer>
#include <QRegExp>
-#include <QCoreApplication>
-#include <QLibraryInfo>
#include <stdio.h>
#include <stdlib.h>
@@ -56,20 +53,26 @@
#include <stdlib.h>
#include "qdbusconnection.h" // for the Export* flags
+#include "qdbusconnection_p.h" // for the qDBusCheckAsyncTag
// copied from dbus-protocol.h:
static const char docTypeHeader[] =
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
-// in qdbusxmlgenerator.cpp
-QT_BEGIN_NAMESPACE
-extern Q_DBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
- const QMetaObject *base, int flags);
-QT_END_NAMESPACE
+#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply"
+#define QCLASSINFO_DBUS_INTERFACE "D-Bus Interface"
+#define QCLASSINFO_DBUS_INTROSPECTION "D-Bus Introspection"
+
+#include "qdbusmetatype_p.h"
+#include "qdbusmetatype.h"
+#include "qdbusutil_p.h"
+
+#include "moc.h"
+#include "generator.h"
#define PROGRAMNAME "qdbuscpp2xml"
-#define PROGRAMVERSION "0.1"
+#define PROGRAMVERSION "0.2"
#define PROGRAMCOPYRIGHT "Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)."
static QString outputFile;
@@ -90,199 +93,218 @@ static const char help[] =
" -V Show the program version and quit.\n"
"\n";
-class MocParser
-{
- void parseError();
- QByteArray readLine();
- void loadIntData(uint *&data);
- void loadStringData(char *&stringdata);
-
- QIODevice *input;
- const char *filename;
- int lineNumber;
-public:
- ~MocParser();
- void parse(const char *filename, QIODevice *input, int lineNumber = 0);
-
- QList<QMetaObject> objects;
-};
-
-void MocParser::parseError()
+
+int qDBusParametersForMethod(const FunctionDef &mm, QList<int>& metaTypes)
{
- fprintf(stderr, PROGRAMNAME ": error parsing input file '%s' line %d \n", filename, lineNumber);
- exit(1);
+ QList<QByteArray> parameterTypes;
+
+ foreach (const ArgumentDef &arg, mm.arguments)
+ parameterTypes.append(arg.normalizedType);
+
+ return qDBusParametersForMethod(parameterTypes, metaTypes);
}
-QByteArray MocParser::readLine()
+
+static inline QString typeNameToXml(const char *typeName)
{
- ++lineNumber;
- return input->readLine();
+ QString plain = QLatin1String(typeName);
+ return plain.toHtmlEscaped();
}
-void MocParser::loadIntData(uint *&data)
-{
- data = 0; // initialise
- QVarLengthArray<uint> array;
- QRegExp rx(QLatin1String("(\\d+|0x[0-9abcdef]+)"), Qt::CaseInsensitive);
-
- while (!input->atEnd()) {
- QString line = QLatin1String(readLine());
- int pos = line.indexOf(QLatin1String("//"));
- if (pos != -1)
- line.truncate(pos); // drop comments
-
- if (line == QLatin1String("};\n")) {
- // end of data
- data = new uint[array.count()];
- memcpy(data, array.data(), array.count() * sizeof(*data));
- return;
+static QString addFunction(const FunctionDef &mm, bool isSignal = false) {
+
+ QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n")
+ .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
+ .arg(QLatin1String(mm.name));
+
+ // check the return type first
+ int typeId = QMetaType::type(mm.normalizedType.constData());
+ if (typeId != QMetaType::Void) {
+ if (typeId) {
+ const char *typeName = QDBusMetaType::typeToSignature(typeId);
+ if (typeName) {
+ xml += QString::fromLatin1(" <arg type=\"%1\" direction=\"out\"/>\n")
+ .arg(typeNameToXml(typeName));
+
+ // do we need to describe this argument?
+ if (QDBusMetaType::signatureToType(typeName) == QVariant::Invalid)
+ xml += QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n")
+ .arg(typeNameToXml(mm.normalizedType.constData()));
+ } else {
+ return QString();
+ }
+ } else if (!mm.normalizedType.isEmpty()) {
+ return QString(); // wasn't a valid type
+ }
+ }
+ QList<ArgumentDef> names = mm.arguments;
+ QList<int> types;
+ int inputCount = qDBusParametersForMethod(mm, types);
+ if (inputCount == -1)
+ return QString(); // invalid form
+ if (isSignal && inputCount + 1 != types.count())
+ return QString(); // signal with output arguments?
+ if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message)
+ return QString(); // signal with QDBusMessage argument?
+
+ bool isScriptable = mm.isScriptable;
+ for (int j = 1; j < types.count(); ++j) {
+ // input parameter for a slot or output for a signal
+ if (types.at(j) == QDBusMetaTypeId::message) {
+ isScriptable = true;
+ continue;
}
- pos = 0;
- while ((pos = rx.indexIn(line, pos)) != -1) {
- QString num = rx.cap(1);
- if (num.startsWith(QLatin1String("0x")))
- array.append(num.mid(2).toUInt(0, 16));
- else
- array.append(num.toUInt());
- pos += rx.matchedLength();
+ QString name;
+ if (!names.at(j - 1).name.isEmpty())
+ name = QString::fromLatin1("name=\"%1\" ").arg(QString::fromLatin1(names.at(j - 1).name));
+
+ bool isOutput = isSignal || j > inputCount;
+
+ const char *signature = QDBusMetaType::typeToSignature(types.at(j));
+ xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n")
+ .arg(name)
+ .arg(QLatin1String(signature))
+ .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
+
+ // do we need to describe this argument?
+ if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
+ const char *typeName = QMetaType::typeName(types.at(j));
+ xml += QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n")
+ .arg(isOutput ? QLatin1String("Out") : QLatin1String("In"))
+ .arg(isOutput && !isSignal ? j - inputCount : j - 1)
+ .arg(typeNameToXml(typeName));
}
}
- parseError();
+ int wantedMask;
+ if (isScriptable)
+ wantedMask = isSignal ? QDBusConnection::ExportScriptableSignals
+ : QDBusConnection::ExportScriptableSlots;
+ else
+ wantedMask = isSignal ? QDBusConnection::ExportNonScriptableSignals
+ : QDBusConnection::ExportNonScriptableSlots;
+ if ((flags & wantedMask) != wantedMask)
+ return QString();
+
+ if (qDBusCheckAsyncTag(mm.tag.constData()))
+ // add the no-reply annotation
+ xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\""
+ " value=\"true\"/>\n");
+
+ QString retval = xml;
+ retval += QString::fromLatin1(" </%1>\n")
+ .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"));
+
+ return retval;
}
-void MocParser::loadStringData(char *&stringdata)
-{
- stringdata = 0;
- QVarLengthArray<char, 1024> array;
-
- while (!input->atEnd()) {
- QByteArray line = readLine();
- if (line == "};\n") {
- // end of data
- stringdata = new char[array.count()];
- memcpy(stringdata, array.data(), array.count() * sizeof(*stringdata));
- return;
- }
- int start = line.indexOf('"');
- if (start == -1)
- parseError();
-
- int len = line.length() - 1;
- line.truncate(len); // drop ending \n
- if (line.at(len - 1) != '"')
- parseError();
-
- --len;
- ++start;
- for ( ; start < len; ++start)
- if (line.at(start) == '\\') {
- // parse escaped sequence
- ++start;
- if (start == len)
- parseError();
-
- QChar c(QLatin1Char(line.at(start)));
- if (!c.isDigit()) {
- switch (c.toLatin1()) {
- case 'a':
- array.append('\a');
- break;
- case 'b':
- array.append('\b');
- break;
- case 'f':
- array.append('\f');
- break;
- case 'n':
- array.append('\n');
- break;
- case 'r':
- array.append('\r');
- break;
- case 't':
- array.append('\t');
- break;
- case 'v':
- array.append('\v');
- break;
- case '\\':
- case '?':
- case '\'':
- case '"':
- array.append(c.toLatin1());
- break;
-
- case 'x':
- if (start + 2 <= len)
- parseError();
- array.append(char(line.mid(start + 1, 2).toInt(0, 16)));
- break;
-
- default:
- array.append(c.toLatin1());
- fprintf(stderr, PROGRAMNAME ": warning: invalid escape sequence '\\%c' found in input",
- c.toLatin1());
- }
- } else {
- // octal
- QRegExp octal(QLatin1String("([0-7]+)"));
- if (octal.indexIn(QLatin1String(line), start) == -1)
- parseError();
- array.append(char(octal.cap(1).toInt(0, 8)));
- }
+static QString generateInterfaceXml(const ClassDef *mo)
+{
+ QString retval;
+
+ // start with properties:
+ if (flags & (QDBusConnection::ExportScriptableProperties |
+ QDBusConnection::ExportNonScriptableProperties)) {
+ static const char *accessvalues[] = {0, "read", "write", "readwrite"};
+ foreach (const PropertyDef &mp, mo->propertyList) {
+ if (!((!mp.scriptable.isEmpty() && (flags & QDBusConnection::ExportScriptableProperties)) ||
+ (!mp.scriptable.isEmpty() && (flags & QDBusConnection::ExportNonScriptableProperties))))
+ continue;
+
+ int access = 0;
+ if (!mp.read.isEmpty())
+ access |= 1;
+ if (!mp.write.isEmpty())
+ access |= 2;
+
+ int typeId = QMetaType::type(mp.type.constData());
+ if (!typeId)
+ continue;
+ const char *signature = QDBusMetaType::typeToSignature(typeId);
+ if (!signature)
+ continue;
+
+ retval += QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"")
+ .arg(QLatin1String(mp.name))
+ .arg(QLatin1String(signature))
+ .arg(QLatin1String(accessvalues[access]));
+
+ if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
+ retval += QString::fromLatin1(">\n <annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n")
+ .arg(typeNameToXml(mp.type.constData()));
} else {
- array.append(line.at(start));
+ retval += QLatin1String("/>\n");
}
+ }
+ }
+
+ // now add methods:
+
+ if (flags & (QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals)) {
+ foreach (const FunctionDef &mm, mo->signalList) {
+ if (mm.wasCloned)
+ continue;
+
+ retval += addFunction(mm, true);
+ }
}
- parseError();
+ if (flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots)) {
+ foreach (const FunctionDef &slot, mo->slotList) {
+ if (slot.access == FunctionDef::Public)
+ retval += addFunction(slot);
+ }
+ foreach (const FunctionDef &method, mo->methodList) {
+ if (method.access == FunctionDef::Public)
+ retval += addFunction(method);
+ }
+ }
+ return retval;
}
-void MocParser::parse(const char *fname, QIODevice *io, int lineNum)
+QString qDBusInterfaceFromClassDef(const ClassDef *mo)
{
- filename = fname;
- input = io;
- lineNumber = lineNum;
-
- while (!input->atEnd()) {
- QByteArray line = readLine();
- if (line.startsWith("static const uint qt_meta_data_")) {
- // start of new class data
- uint *data;
- loadIntData(data);
-
- // find the start of the string data
- do {
- line = readLine();
- if (input->atEnd())
- parseError();
- } while (!line.startsWith("static const char qt_meta_stringdata_"));
-
- char *stringdata;
- loadStringData(stringdata);
-
- QMetaObject mo;
- mo.d.superdata = &QObject::staticMetaObject;
- mo.d.stringdata = stringdata;
- mo.d.data = data;
- mo.d.extradata = 0;
- objects.append(mo);
- }
+ QString interface;
+
+ foreach (ClassInfoDef cid, mo->classInfoList) {
+ if (cid.name == QCLASSINFO_DBUS_INTERFACE)
+ return QString::fromUtf8(cid.value);
+ }
+ interface = QLatin1String(mo->classname);
+ interface.replace(QLatin1String("::"), QLatin1String("."));
+
+ if (interface.startsWith(QLatin1String("QDBus"))) {
+ interface.prepend(QLatin1String("com.trolltech.QtDBus."));
+ } else if (interface.startsWith(QLatin1Char('Q')) &&
+ interface.length() >= 2 && interface.at(1).isUpper()) {
+ // assume it's Qt
+ interface.prepend(QLatin1String("local.com.trolltech.Qt."));
+ } else {
+ interface.prepend(QLatin1String("local."));
}
- fname = 0;
- input = 0;
+ return interface;
}
-MocParser::~MocParser()
+
+QString qDBusGenerateClassDefXml(const ClassDef *cdef)
{
- foreach (QMetaObject mo, objects) {
- delete const_cast<char *>(mo.d.stringdata);
- delete const_cast<uint *>(mo.d.data);
+ foreach (const ClassInfoDef &cid, cdef->classInfoList) {
+ if (cid.name == QCLASSINFO_DBUS_INTROSPECTION)
+ return QString::fromUtf8(cid.value);
}
+
+ // generate the interface name from the meta object
+ QString interface = qDBusInterfaceFromClassDef(cdef);
+
+ QString xml = generateInterfaceXml(cdef);
+
+ if (xml.isEmpty())
+ return QString(); // don't add an empty interface
+ return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n")
+ .arg(interface, xml);
}
static void showHelp()
@@ -300,7 +322,8 @@ static void showVersion()
static void parseCmdLine(QStringList &arguments)
{
- for (int i = 1; i < arguments.count(); ++i) {
+ flags = 0;
+ for (int i = 0; i < arguments.count(); ++i) {
const QString arg = arguments.at(i);
if (arg == QLatin1String("--help"))
@@ -369,14 +392,16 @@ static void parseCmdLine(QStringList &arguments)
int main(int argc, char **argv)
{
- QCoreApplication app(argc, argv);
- QStringList args = app.arguments();
-
- MocParser parser;
+ QStringList args;
+ for (int n = 1; n < argc; ++n)
+ args.append(QString::fromLocal8Bit(argv[n]));
parseCmdLine(args);
- for (int i = 1; i < args.count(); ++i) {
+ QList<ClassDef> classes;
+
+ for (int i = 0; i < args.count(); ++i) {
const QString arg = args.at(i);
+
if (arg.startsWith(QLatin1Char('-')))
continue;
@@ -387,35 +412,22 @@ int main(int argc, char **argv)
return 1;
}
- f.readLine();
+ Preprocessor pp;
+ Moc moc(pp);
+ pp.macros["Q_MOC_RUN"];
+ pp.macros["__cplusplus"];
- QByteArray line = f.readLine();
- if (line.contains("Meta object code from reading C++ file"))
- // this is a moc-generated file
- parser.parse(argv[i], &f, 3);
- else {
- // run moc on this file
- QProcess proc;
- proc.start(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/moc"), QStringList() << QFile::decodeName(argv[i]), QIODevice::ReadOnly | QIODevice::Text);
+ const QByteArray filename = QFile::decodeName(argv[i]).toLatin1();
- if (!proc.waitForStarted()) {
- fprintf(stderr, PROGRAMNAME ": could not execute moc! Aborting.\n");
- return 1;
- }
+ moc.filename = filename;
+ moc.currentFilenames.push(filename);
- proc.closeWriteChannel();
+ moc.symbols = pp.preprocessed(moc.filename, &f);
+ moc.parse();
- if (!proc.waitForFinished() || proc.exitStatus() != QProcess::NormalExit ||
- proc.exitCode() != 0) {
- // output the moc errors:
- fprintf(stderr, "%s", proc.readAllStandardError().constData());
- fprintf(stderr, PROGRAMNAME ": exit code %d from moc. Aborting\n", proc.exitCode());
- return 1;
- }
- fprintf(stderr, "%s", proc.readAllStandardError().constData());
-
- parser.parse(argv[i], &proc, 1);
- }
+ if (moc.classList.isEmpty())
+ return 0;
+ classes = moc.classList;
f.close();
}
@@ -434,9 +446,8 @@ int main(int argc, char **argv)
output.write(docTypeHeader);
output.write("<node>\n");
- foreach (QMetaObject mo, parser.objects) {
- QString xml = qDBusGenerateMetaObjectXml(QString(), &mo, &QObject::staticMetaObject,
- flags);
+ foreach (const ClassDef &cdef, classes) {
+ QString xml = qDBusGenerateClassDefXml(&cdef);
output.write(xml.toLocal8Bit());
}
output.write("</node>\n");
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro b/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro
index 4f5f826ce7..33f7937c5b 100644
--- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro
+++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro
@@ -1,10 +1,34 @@
-SOURCES = qdbuscpp2xml.cpp
-DESTDIR = $$QT.designer.bins
+
+TEMPLATE = app
TARGET = qdbuscpp2xml
-QT = core
-CONFIG += qdbus
-CONFIG -= app_bundle
-win32:CONFIG += console
-target.path=$$[QT_INSTALL_BINS]
+DESTDIR = ../../../bin
+
+include(../moc/moc.pri)
+
+INCLUDEPATH += .
+DEPENDPATH += .
+
+INCLUDEPATH += $$QT_BUILD_TREE/include \
+ $$QT_BUILD_TREE/include/QtDBus \
+ $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION \
+ $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION/QtDBus \
+ $$QT_SOURCE_TREE/src/dbus
+
+QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS
+
+SOURCES += qdbuscpp2xml.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusmetatype.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusutil.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusmisc.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusargument.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusmarshaller.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusextratypes.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbus_symbols.cpp \
+ $$QT_SOURCE_TREE/src/dbus/qdbusunixfiledescriptor.cpp
+
+include(../bootstrap/bootstrap.pri)
+
+target.path = $$[QT_HOST_BINS]
INSTALLS += target
+load(qt_targets)