summaryrefslogtreecommitdiffstats
path: root/qt/tools
diff options
context:
space:
mode:
authorThiago Macieira <thiago@kde.org>2006-06-04 15:52:05 +0000
committerThiago Macieira <thiago@kde.org>2006-06-04 15:52:05 +0000
commitedbf2bfc109ce94b2604ea20328fda25542e4383 (patch)
tree3281d191fa9dde9f1f26b947b145d02373f031b0 /qt/tools
parent435c7af9b605c3ffc8641142b6d7add18bf7080b (diff)
* qt/: Update to Subversion r548032.
This includes a big reorganisation of the files inside the subdir. We really need a version control system that supports moving of files. I'm not bothering with history anyways anymore, since the bindings will be moved out to git. The history should be restored from Subversion when that happens.
Diffstat (limited to 'qt/tools')
-rw-r--r--qt/tools/.cvsignore11
-rw-r--r--qt/tools/Makefile.am10
-rw-r--r--qt/tools/dbuscpp2xml.cpp409
-rw-r--r--qt/tools/dbusidl2cpp.cpp960
4 files changed, 1390 insertions, 0 deletions
diff --git a/qt/tools/.cvsignore b/qt/tools/.cvsignore
new file mode 100644
index 00000000..f6454f28
--- /dev/null
+++ b/qt/tools/.cvsignore
@@ -0,0 +1,11 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.lo
+*.la
+*.bb
+*.bbg
+*.da
+*.gcov
+*.moc
diff --git a/qt/tools/Makefile.am b/qt/tools/Makefile.am
new file mode 100644
index 00000000..a79aafd6
--- /dev/null
+++ b/qt/tools/Makefile.am
@@ -0,0 +1,10 @@
+INCLUDES=-I$(top_srcdir)/qt $(DBUS_CLIENT_CFLAGS) $(DBUS_QT_CFLAGS) -DDBUS_COMPILATION
+bin_PROGRAMS = dbusidl2cpp dbuscpp2xml
+
+dbusidl2cpp_SOURCES = dbusidl2cpp.cpp
+dbusidl2cpp_LDFLAGS = -no-undefined
+dbusidl2cpp_LDADD = $(DBUS_QT_LIBS) ../src/libdbus-qt4-1.la
+
+dbuscpp2xml_SOURCES = dbuscpp2xml.cpp
+dbuscpp2xml_LDFLAGS = -no-undefined
+dbuscpp2xml_LDADD = $(DBUS_QT_LIBS) ../src/libdbus-qt4-1.la
diff --git a/qt/tools/dbuscpp2xml.cpp b/qt/tools/dbuscpp2xml.cpp
new file mode 100644
index 00000000..dd08b5fd
--- /dev/null
+++ b/qt/tools/dbuscpp2xml.cpp
@@ -0,0 +1,409 @@
+/* -*- C++ -*-
+ *
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira@trolltech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <QByteArray>
+#include <QString>
+#include <QVarLengthArray>
+#include <QFile>
+#include <QProcess>
+#include <QMetaObject>
+#include <QList>
+#include <QRegExp>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "../src/qdbusconnection.h" // for the Export* flags
+
+// 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
+extern QDBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+ const QMetaObject *base, int flags);
+
+#define PROGRAMNAME "dbuscpp2xml"
+#define PROGRAMVERSION "0.1"
+#define PROGRAMCOPYRIGHT "Copyright (C) 2006 Trolltech AS. All rights reserved."
+
+static const char cmdlineOptions[] = "psmaPSMAo:hV";
+static const char *outputFile;
+static int flags;
+
+static const char help[] =
+ "Usage: " PROGRAMNAME " [options...] [files...]\n"
+ "Parses the C++ source or header file containing a QObject-derived class and\n"
+ "produces the D-Bus Introspection XML."
+ "\n"
+ "Options:\n"
+ " -p|-s|-m Only parse scriptable Properties, Signals and Methods (slots)\n"
+ " -P|-S|-M Parse all Properties, Signals and Methods (slots)\n"
+ " -a Output all scriptable contents (equivalent to -psm)\n"
+ " -A Output all contents (equivalent to -PSM)\n"
+ " -o <filename> Write the output to file <filename>\n"
+ " -h Show this information\n"
+ " -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 line;
+public:
+ ~MocParser();
+ void parse(const char *filename, QIODevice *input, int lineNumber = 0);
+
+ QList<QMetaObject> objects;
+};
+
+void MocParser::parseError()
+{
+ fprintf(stderr, PROGRAMNAME ": error parsing input file '%s' line %d \n", filename, line);
+ exit(1);
+}
+
+QByteArray MocParser::readLine()
+{
+ ++line;
+ return input->readLine();
+}
+
+void MocParser::loadIntData(uint *&data)
+{
+ data = 0; // initialise
+ QVarLengthArray<uint> array;
+ QRegExp rx("(\\d+|0x[0-9abcdef]+)", Qt::CaseInsensitive);
+
+ while (!input->atEnd()) {
+ QString line = QLatin1String(readLine());
+ int pos = line.indexOf("//");
+ if (pos != -1)
+ line.truncate(pos); // drop comments
+
+ if (line == "};\n") {
+ // end of data
+ data = new uint[array.count()];
+ memcpy(data, array.data(), array.count() * sizeof(*data));
+ return;
+ }
+
+ pos = 0;
+ while ((pos = rx.indexIn(line, pos)) != -1) {
+ QString num = rx.cap(1);
+ if (num.startsWith("0x"))
+ array.append(num.mid(2).toUInt(0, 16));
+ else
+ array.append(num.toUInt());
+ pos += rx.matchedLength();
+ }
+ }
+
+ parseError();
+}
+
+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("([0-7]+)");
+ if (octal.indexIn(QLatin1String(line), start) == -1)
+ parseError();
+ array.append(char(octal.cap(1).toInt(0, 8)));
+ }
+ } else {
+ array.append(line.at(start));
+ }
+ }
+
+ parseError();
+}
+
+void MocParser::parse(const char *fname, QIODevice *io, int lineNumber)
+{
+ filename = fname;
+ input = io;
+ line = lineNumber;
+
+ 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);
+ }
+ }
+
+ fname = 0;
+ input = 0;
+}
+
+MocParser::~MocParser()
+{
+ foreach (QMetaObject mo, objects) {
+ delete const_cast<char *>(mo.d.stringdata);
+ delete const_cast<uint *>(mo.d.data);
+ }
+}
+
+static void showHelp()
+{
+ printf("%s", help);
+ exit(0);
+}
+
+static void showVersion()
+{
+ printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
+ printf("D-Bus QObject-to-XML converter\n");
+ exit(0);
+}
+
+static void parseCmdLine(int argc, char **argv)
+{
+ int c;
+ opterr = true;
+ while ((c = getopt(argc, argv, cmdlineOptions)) != -1)
+ switch (c)
+ {
+ case 'p':
+ flags |= QDBusConnection::ExportProperties;
+ break;
+
+ case 's':
+ flags |= QDBusConnection::ExportSignals;
+ break;
+
+ case 'm':
+ flags |= QDBusConnection::ExportSlots;
+ break;
+
+ case 'a':
+ flags |= QDBusConnection::ExportContents;
+ break;
+
+ case 'P':
+ flags |= QDBusConnection::ExportAllProperties;
+ break;
+
+ case 'S':
+ flags |= QDBusConnection::ExportAllSignals;
+ break;
+
+ case 'M':
+ flags |= QDBusConnection::ExportAllSlots;
+ break;
+
+ case 'A':
+ flags |= QDBusConnection::ExportAllContents;
+ break;
+
+ case 'o':
+ outputFile = optarg;
+ break;
+
+ case 'h':
+ showHelp();
+ break;
+
+ case 'V':
+ showVersion();
+ break;
+
+ case '?':
+ exit(1);
+ default:
+ abort();
+ }
+
+ if (flags == 0)
+ flags = QDBusConnection::ExportAllContents;
+}
+
+int main(int argc, char **argv)
+{
+ MocParser parser;
+ parseCmdLine(argc, argv);
+
+ for (int i = optind; i < argc; ++i) {
+ FILE *in = fopen(argv[i], "r");
+ if (in == 0) {
+ fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n",
+ argv[i], strerror(errno));
+ return 1;
+ }
+
+ QFile f;
+ f.open(in, QIODevice::ReadOnly);
+ f.readLine();
+
+ 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("moc", QStringList() << QFile::encodeName(argv[i]));
+
+ if (!proc.waitForStarted()) {
+ fprintf(stderr, PROGRAMNAME ": could not execute moc! Aborting.\n");
+ return 1;
+ }
+
+ proc.closeWriteChannel();
+
+ 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);
+ }
+
+ f.close();
+ fclose(in);
+ }
+
+ FILE *output = stdout;
+ if (outputFile != 0) {
+ output = fopen(outputFile, "w");
+ if (output == 0) {
+ fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s",
+ outputFile, strerror(errno));
+ return 1;
+ }
+ }
+
+ fprintf(output, "%s<node>\n", docTypeHeader);
+ foreach (QMetaObject mo, parser.objects) {
+ QString xml = qDBusGenerateMetaObjectXml(QString(), &mo, &QObject::staticMetaObject,
+ flags);
+ fprintf(output, "%s", qPrintable(xml));
+ }
+ fprintf(output, "</node>\n");
+
+ if (output != stdout)
+ fclose(output);
+}
+
diff --git a/qt/tools/dbusidl2cpp.cpp b/qt/tools/dbusidl2cpp.cpp
new file mode 100644
index 00000000..091685b4
--- /dev/null
+++ b/qt/tools/dbusidl2cpp.cpp
@@ -0,0 +1,960 @@
+/* -*- C++ -*-
+ *
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira@trolltech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qset.h>
+
+#include <dbus/qdbus.h>
+#include "../src/qdbusmetaobject_p.h"
+#include "../src/qdbusintrospection_p.h"
+
+#define PROGRAMNAME "dbusidl2cpp"
+#define PROGRAMVERSION "0.4"
+#define PROGRAMCOPYRIGHT "Copyright (C) 2006 Trolltech AS. All rights reserved."
+
+#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply"
+
+static const char cmdlineOptions[] = "a:c:hmNp:vV";
+static const char *globalClassName;
+static const char *proxyFile;
+static const char *adaptorFile;
+static const char *inputFile;
+static bool skipNamespaces;
+static bool verbose;
+static bool includeMocs;
+static QStringList wantedInterfaces;
+
+static const char help[] =
+ "Usage: " PROGRAMNAME " [options...] [idl-or-xml-file] [interfaces...]\n"
+ "Produces the C++ code to implement the interfaces defined in the input file.\n"
+ "If no options are given, the code is written to the standard output.\n"
+ "\n"
+ "Options:\n"
+ " -a <filename> Write the adaptor code to <filename>\n"
+ " -c <classname> Use <classname> as the class name for the generated classes\n"
+ " -h Show this information\n"
+ " -m Generate #include \"filename.moc\" statements in the .cpp files\n"
+ " -N Don't use namespaces\n"
+ " -p <filename> Write the proxy code to <filename>\n"
+ " -v Be verbose.\n"
+ " -V Show the program version and quit.\n"
+ "\n"
+ "If the file name given to the options -a and -p does not end in .cpp or .h, the\n"
+ "program will automatically append the suffixes and produce both files.\n";
+
+static const char includeList[] =
+ "#include <QtCore/QByteArray>\n"
+ "#include <QtCore/QList>\n"
+ "#include <QtCore/QMap>\n"
+ "#include <QtCore/QString>\n"
+ "#include <QtCore/QStringList>\n"
+ "#include <QtCore/QVariant>\n";
+
+static const char forwardDeclarations[] =
+ "class QByteArray;\n"
+ "template<class T> class QList;\n"
+ "template<class Key, class Value> class QMap;\n"
+ "class QString;\n"
+ "class QStringList;\n"
+ "class QVariant;\n";
+
+static void showHelp()
+{
+ printf("%s", help);
+ exit(0);
+}
+
+static void showVersion()
+{
+ printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
+ printf("D-Bus binding tool for Qt\n");
+ exit(0);
+}
+
+static void parseCmdLine(int argc, char **argv)
+{
+ int c;
+ opterr = true;
+ while ((c = getopt(argc, argv, cmdlineOptions)) != -1)
+ switch (c)
+ {
+ case 'a':
+ adaptorFile = optarg;
+ break;
+
+ case 'c':
+ globalClassName = optarg;
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ case 'm':
+ includeMocs = true;
+ break;
+
+ case 'N':
+ skipNamespaces = true;
+ break;
+
+ case 'h':
+ showHelp();
+ break;
+
+ case 'V':
+ showVersion();
+ break;
+
+ case 'p':
+ proxyFile = optarg;
+ break;
+
+ case '?':
+ exit(1);
+ default:
+ abort();
+ }
+
+ if (optind != argc)
+ inputFile = argv[optind++];
+
+ while (optind != argc)
+ wantedInterfaces << QString::fromLocal8Bit(argv[optind++]);
+}
+
+static QDBusIntrospection::Interfaces readInput()
+{
+ QFile input(QFile::decodeName(inputFile));
+ if (inputFile && QLatin1String("-") != inputFile)
+ input.open(QIODevice::ReadOnly);
+ else
+ input.open(stdin, QIODevice::ReadOnly);
+
+ QByteArray data = input.readAll();
+
+ // check if the input is already XML
+ data = data.trimmed();
+ if (data.startsWith("<!DOCTYPE ") || data.startsWith("<?xml") ||
+ data.startsWith("<node") || data.startsWith("<interface"))
+ // already XML
+ return QDBusIntrospection::parseInterfaces(QString::fromUtf8(data));
+
+ fprintf(stderr, "Cannot process input. Stop.\n");
+ exit(1);
+}
+
+static void cleanInterfaces(QDBusIntrospection::Interfaces &interfaces)
+{
+ if (!wantedInterfaces.isEmpty()) {
+ QDBusIntrospection::Interfaces::Iterator it = interfaces.begin();
+ while (it != interfaces.end())
+ if (!wantedInterfaces.contains(it.key()))
+ it = interfaces.erase(it);
+ else
+ ++it;
+ }
+}
+
+// produce a header name from the file name
+static QString header(const char *name)
+{
+ if (!name || (name[0] == '-' && name[1] == '\0'))
+ return QString();
+
+ QString retval = QFile::decodeName(name);
+ if (!retval.endsWith(".h") && !retval.endsWith(".cpp") && !retval.endsWith(".cc"))
+ retval.append(".h");
+
+ return retval;
+}
+
+// produce a cpp name from the file name
+static QString cpp(const char *name)
+{
+ if (!name || (name[0] == '-' && name[1] == '\0'))
+ return QString();
+
+ QString retval = QFile::decodeName(name);
+ if (!retval.endsWith(".h") && !retval.endsWith(".cpp") && !retval.endsWith(".cc"))
+ retval.append(".cpp");
+
+ return retval;
+}
+
+static QTextStream &writeHeader(QTextStream &ts, bool changesWillBeLost)
+{
+ ts << "/*" << endl
+ << " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION << endl
+ << " * when processing input file " << (inputFile ? inputFile : "<stdin>") << endl
+ << " *" << endl
+ << " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT << endl
+ << " *" << endl
+ << " * This is an auto-generated file." << endl;
+
+ if (changesWillBeLost)
+ ts << " * Do not edit! All changes made to it will be lost." << endl;
+
+ ts << " */" << endl
+ << endl;
+
+ return ts;
+}
+
+enum ClassType { Proxy, Adaptor };
+static QString classNameForInterface(const QString &interface, ClassType classType)
+{
+ if (globalClassName)
+ return QLatin1String(globalClassName);
+
+ QStringList parts = interface.split('.');
+
+ QString retval;
+ if (classType == Proxy)
+ foreach (QString part, parts) {
+ part[0] = part[0].toUpper();
+ retval += part;
+ }
+ else {
+ retval = parts.last();
+ retval[0] = retval[0].toUpper();
+ }
+
+ if (classType == Proxy)
+ retval += "Interface";
+ else
+ retval += "Adaptor";
+
+ return retval;
+}
+
+static QByteArray qtTypeName(const QString &signature)
+{
+ QVariant::Type type = QDBusUtil::signatureToType(signature);
+ if (type == QVariant::Invalid)
+ qFatal("Got unknown type `%s'", qPrintable(signature));
+
+ return QVariant::typeToName(type);
+}
+
+static QString nonConstRefArg(const QByteArray &arg)
+{
+ return QLatin1String(arg + " &");
+}
+
+static QString templateArg(const QByteArray &arg)
+{
+ if (!arg.endsWith('>'))
+ return QLatin1String(arg);
+
+ return QLatin1String(arg + ' ');
+}
+
+static QString constRefArg(const QByteArray &arg)
+{
+ if (!arg.startsWith('Q'))
+ return QLatin1String(arg + ' ');
+ else
+ return QString("const %1 &").arg( QLatin1String(arg) );
+}
+
+static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs,
+ const QDBusIntrospection::Arguments &outputArgs =
+ QDBusIntrospection::Arguments())
+{
+ QStringList retval;
+ for (int i = 0; i < inputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = inputArgs.at(i);
+ QString name = arg.name;
+ if (name.isEmpty())
+ name = QString("in%1").arg(i);
+ while (retval.contains(name))
+ name += "_";
+ retval << name;
+ }
+ for (int i = 0; i < outputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = outputArgs.at(i);
+ QString name = arg.name;
+ if (name.isEmpty())
+ name = QString("out%1").arg(i);
+ while (retval.contains(name))
+ name += "_";
+ retval << name;
+ }
+ return retval;
+}
+
+static void writeArgList(QTextStream &ts, const QStringList &argNames,
+ const QDBusIntrospection::Arguments &inputArgs,
+ const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments())
+{
+ // input args:
+ bool first = true;
+ int argPos = 0;
+ for (int i = 0; i < inputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = inputArgs.at(i);
+ QString type = constRefArg(qtTypeName(arg.type));
+
+ if (!first)
+ ts << ", ";
+ ts << type << argNames.at(argPos++);
+ first = false;
+ }
+
+ argPos++;
+
+ // output args
+ // yes, starting from 1
+ for (int i = 1; i < outputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = outputArgs.at(i);
+ QString name = arg.name;
+
+ if (!first)
+ ts << ", ";
+ ts << nonConstRefArg(qtTypeName(arg.type)) << argNames.at(argPos++);
+ first = false;
+ }
+}
+
+static QString propertyGetter(const QDBusIntrospection::Property &property)
+{
+ QString getter = property.annotations.value("com.trolltech.QtDBus.propertyGetter");
+ if (getter.isEmpty()) {
+ getter = property.name;
+ getter[0] = getter[0].toLower();
+ }
+ return getter;
+}
+
+static QString propertySetter(const QDBusIntrospection::Property &property)
+{
+ QString setter = property.annotations.value("com.trolltech.QtDBus.propertySetter");
+ if (setter.isEmpty()) {
+ setter = "set" + property.name;
+ setter[3] = setter[3].toUpper();
+ }
+ return setter;
+}
+
+static QString stringify(const QString &data)
+{
+ QString retval;
+ int i;
+ for (i = 0; i < data.length(); ++i) {
+ retval += '\"';
+ for ( ; i < data.length() && data[i] != QChar('\n'); ++i)
+ if (data[i] == '\"')
+ retval += "\\\"";
+ else
+ retval += data[i];
+ retval += "\\n\"\n";
+ }
+ return retval;
+}
+
+static void writeProxy(const char *proxyFile, const QDBusIntrospection::Interfaces &interfaces)
+{
+ // open the file
+ QString headerName = header(proxyFile);
+ QFile file(headerName);
+ if (!headerName.isEmpty())
+ file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
+ else
+ file.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
+ QTextStream hs(&file);
+
+ QString cppName = cpp(proxyFile);
+ QByteArray cppData;
+ QTextStream cs(&cppData);
+
+ // write the header:
+ writeHeader(hs, true);
+
+ // include guards:
+ QString includeGuard;
+ if (!headerName.isEmpty()) {
+ includeGuard = headerName.toUpper().replace(QChar('.'), QChar('_'));
+ int pos = includeGuard.lastIndexOf('/');
+ if (pos != -1)
+ includeGuard = includeGuard.mid(pos + 1);
+ } else {
+ includeGuard = QString("QDBUSIDL2CPP_PROXY");
+ }
+ includeGuard = QString("%1_%2%3")
+ .arg(includeGuard)
+ .arg(getpid())
+ .arg(QDateTime::currentDateTime().toTime_t());
+ hs << "#ifndef " << includeGuard << endl
+ << "#define " << includeGuard << endl
+ << endl;
+
+ // include our stuff:
+ hs << "#include <QtCore/QObject>" << endl
+ << includeList
+ << "#include <dbus/qdbus.h>" << endl
+ << endl;
+
+ if (cppName != headerName) {
+ writeHeader(cs, false);
+ cs << "#include \"" << headerName << "\"" << endl
+ << endl;
+ }
+
+ foreach (const QDBusIntrospection::Interface *interface, interfaces) {
+ QString className = classNameForInterface(interface->name, Proxy);
+
+ // comment:
+ hs << "/*" << endl
+ << " * Proxy class for interface " << interface->name << endl
+ << " */" << endl;
+ cs << "/*" << endl
+ << " * Implementation of interface class " << className << endl
+ << " */" << endl
+ << endl;
+
+ // class header:
+ hs << "class " << className << ": public QDBusAbstractInterface" << endl
+ << "{" << endl
+ << " Q_OBJECT" << endl;
+
+ // the interface name
+ hs << "public:" << endl
+ << " static inline const char *staticInterfaceName()" << endl
+ << " { return \"" << interface->name << "\"; }" << endl
+ << endl;
+
+ // constructors/destructors:
+ hs << "public:" << endl
+ << " explicit " << className << "(QDBusAbstractInterfacePrivate *p);" << endl
+ << endl
+ << " ~" << className << "();" << endl
+ << endl;
+ cs << className << "::" << className << "(QDBusAbstractInterfacePrivate *p)" << endl
+ << " : QDBusAbstractInterface(p)" << endl
+ << "{" << endl
+ << "}" << endl
+ << endl
+ << className << "::~" << className << "()" << endl
+ << "{" << endl
+ << "}" << endl
+ << endl;
+
+ // properties:
+ foreach (const QDBusIntrospection::Property &property, interface->properties) {
+ QByteArray type = qtTypeName(property.type);
+ QString templateType = templateArg(type);
+ QString constRefType = constRefArg(type);
+ QString getter = propertyGetter(property);
+ QString setter = propertySetter(property);
+
+ hs << " Q_PROPERTY(" << type << " " << property.name;
+
+ // getter:
+ if (property.access != QDBusIntrospection::Property::Write)
+ // it's readble
+ hs << " READ " << getter;
+
+ // setter
+ if (property.access != QDBusIntrospection::Property::Read)
+ // it's writeable
+ hs << " WRITE " << setter;
+
+ hs << ")" << endl;
+
+ // getter:
+ if (property.access != QDBusIntrospection::Property::Write) {
+ hs << " inline " << type << " " << getter << "() const" << endl;
+ if (type != "QVariant")
+ hs << " { return qvariant_cast< " << type << " >(internalPropGet(\""
+ << property.name << "\")); }" << endl;
+ else
+ hs << " { return internalPropGet(\"" << property.name << "\"); }" << endl;
+ }
+
+ // setter:
+ if (property.access != QDBusIntrospection::Property::Read) {
+ hs << " inline void " << setter << "(" << constRefArg(type) << "value)" << endl
+ << " { internalPropSet(\"" << property.name
+ << "\", qVariantFromValue(value)); }" << endl;
+ }
+
+ hs << endl;
+ }
+
+ // methods:
+ hs << "public Q_SLOTS: // METHODS" << endl;
+ foreach (const QDBusIntrospection::Method &method, interface->methods) {
+ bool isAsync = method.annotations.value(ANNOTATION_NO_WAIT) == "true";
+ if (isAsync && !method.outputArgs.isEmpty()) {
+ fprintf(stderr, "warning: method %s in interface %s is marked 'async' but has output arguments.\n",
+ qPrintable(method.name), qPrintable(interface->name));
+ continue;
+ }
+
+ hs << " inline ";
+
+ if (method.annotations.value("org.freedesktop.DBus.Deprecated") == "true")
+ hs << "Q_DECL_DEPRECATED ";
+
+ if (isAsync)
+ hs << "Q_ASYNC void ";
+ else if (method.outputArgs.isEmpty())
+ hs << "QDBusReply<void> ";
+ else {
+ hs << "QDBusReply<" << templateArg(qtTypeName(method.outputArgs.first().type)) << "> ";
+ }
+
+ hs << method.name << "(";
+
+ QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs);
+ writeArgList(hs, argNames, method.inputArgs, method.outputArgs);
+
+ hs << ")" << endl
+ << " {" << endl;
+
+ if (method.outputArgs.count() > 1)
+ hs << " QDBusMessage reply = call(QLatin1String(\"";
+ else if (!isAsync)
+ hs << " return call(QLatin1String(\"";
+ else
+ hs << " call(NoWaitForReply, QLatin1String(\"";
+
+ // rebuild the method input signature:
+ QString signature = QChar('.');
+ foreach (const QDBusIntrospection::Argument &arg, method.inputArgs)
+ signature += arg.type;
+ if (signature.length() == 1)
+ signature.clear();
+ hs << method.name << signature << "\")";
+
+ int argPos = 0;
+ for (int i = 0; i < method.inputArgs.count(); ++i)
+ hs << ", " << argNames.at(argPos++);
+
+ // close the QDBusIntrospection::call call
+ hs << ");" << endl;
+
+ argPos++;
+ if (method.outputArgs.count() > 1) {
+ hs << " if (reply.type() == QDBusMessage::ReplyMessage) {" << endl;
+
+ // yes, starting from 1
+ for (int i = 1; i < method.outputArgs.count(); ++i)
+ hs << " " << argNames.at(argPos++) << " = qvariant_cast<"
+ << templateArg(qtTypeName(method.outputArgs.at(i).type))
+ << ">(reply.at(" << i << "));" << endl;
+ hs << " }" << endl
+ << " return reply;" << endl;
+ }
+
+ // close the function:
+ hs << " }" << endl
+ << endl;
+ }
+
+ hs << "Q_SIGNALS: // SIGNALS" << endl;
+ foreach (const QDBusIntrospection::Signal &signal, interface->signals_) {
+ hs << " ";
+ if (signal.annotations.value("org.freedesktop.DBus.Deprecated") == "true")
+ hs << "Q_DECL_DEPRECATED ";
+
+ hs << "void " << signal.name << "(";
+
+ QStringList argNames = makeArgNames(signal.outputArgs);
+ writeArgList(hs, argNames, signal.outputArgs);
+
+ hs << ");" << endl; // finished for header
+ }
+
+ // close the class:
+ hs << "};" << endl
+ << endl;
+ }
+
+ if (!skipNamespaces) {
+ QStringList last;
+ QDBusIntrospection::Interfaces::ConstIterator it = interfaces.constBegin();
+ do
+ {
+ QStringList current;
+ QString name;
+ if (it != interfaces.constEnd()) {
+ current = it->constData()->name.split('.');
+ name = current.takeLast();
+ }
+
+ int i = 0;
+ while (i < current.count() && i < last.count() && current.at(i) == last.at(i))
+ ++i;
+
+ // i parts matched
+ // close last.count() - i namespaces:
+ for (int j = i; j < last.count(); ++j)
+ hs << QString((last.count() - j - 1 + i) * 2, ' ') << "}" << endl;
+
+ // open current.count() - i namespaces
+ for (int j = i; j < current.count(); ++j)
+ hs << QString(j * 2, ' ') << "namespace " << current.at(j) << " {" << endl;
+
+ // add this class:
+ if (!name.isEmpty()) {
+ hs << QString(current.count() * 2, ' ')
+ << "typedef ::" << classNameForInterface(it->constData()->name, Proxy)
+ << " " << name << ";" << endl;
+ }
+
+ if (it == interfaces.constEnd())
+ break;
+ ++it;
+ last = current;
+ } while (true);
+ }
+
+ // close the include guard
+ hs << "#endif" << endl;
+
+ if (includeMocs)
+ cs << endl
+ << "#include \"" << proxyFile << ".moc\"" << endl;
+
+ cs.flush();
+ hs.flush();
+ if (headerName == cppName)
+ file.write(cppData);
+ else {
+ // write to cpp file
+ QFile f(cppName);
+ f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
+ f.write(cppData);
+ }
+}
+
+static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Interfaces &interfaces)
+{
+ // open the file
+ QString headerName = header(adaptorFile);
+ QFile file(headerName);
+ if (!headerName.isEmpty())
+ file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
+ else
+ file.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
+ QTextStream hs(&file);
+
+ QString cppName = cpp(adaptorFile);
+ QByteArray cppData;
+ QTextStream cs(&cppData);
+
+ // write the headers
+ writeHeader(hs, false);
+
+ // include guards:
+ QString includeGuard;
+ if (!headerName.isEmpty()) {
+ includeGuard = headerName.toUpper().replace(QChar('.'), QChar('_'));
+ int pos = includeGuard.lastIndexOf('/');
+ if (pos != -1)
+ includeGuard = includeGuard.mid(pos + 1);
+ } else {
+ includeGuard = QString("QDBUSIDL2CPP_ADAPTOR");
+ }
+ includeGuard = QString("%1_%2%3")
+ .arg(includeGuard)
+ .arg(getpid())
+ .arg(QDateTime::currentDateTime().toTime_t());
+ hs << "#ifndef " << includeGuard << endl
+ << "#define " << includeGuard << endl
+ << endl;
+
+ // include our stuff:
+ hs << "#include <QtCore/QObject>" << endl;
+ if (cppName == headerName)
+ hs << "#include <QtCore/QMetaObject>" << endl
+ << "#include <QtCore/QVariant>" << endl;
+ hs << "#include <dbus/qdbus.h>" << endl;
+
+ if (cppName != headerName) {
+ writeHeader(cs, false);
+ cs << "#include \"" << headerName << "\"" << endl
+ << "#include <QtCore/QMetaObject>" << endl
+ << includeList
+ << endl;
+ hs << forwardDeclarations;
+ } else {
+ hs << includeList;
+ }
+
+ hs << endl;
+
+ foreach (const QDBusIntrospection::Interface *interface, interfaces) {
+ QString className = classNameForInterface(interface->name, Adaptor);
+
+ // comment:
+ hs << "/*" << endl
+ << " * Adaptor class for interface " << interface->name << endl
+ << " */" << endl;
+ cs << "/*" << endl
+ << " * Implementation of adaptor class " << className << endl
+ << " */" << endl
+ << endl;
+
+ // class header:
+ hs << "class " << className << ": public QDBusAbstractAdaptor" << endl
+ << "{" << endl
+ << " Q_OBJECT" << endl
+ << " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface->name << "\")" << endl
+ << " Q_CLASSINFO(\"D-Bus Introspection\", \"\"" << endl
+ << stringify(interface->introspection)
+ << " \"\")" << endl
+ << "public:" << endl
+ << " " << className << "(QObject *parent);" << endl
+ << " virtual ~" << className << "();" << endl
+ << endl;
+
+ // constructor/destructor
+ cs << className << "::" << className << "(QObject *parent)" << endl
+ << " : QDBusAbstractAdaptor(parent)" << endl
+ << "{" << endl
+ << " // constructor" << endl
+ << " setAutoRelaySignals(true);" << endl
+ << "}" << endl
+ << endl
+ << className << "::~" << className << "()" << endl
+ << "{" << endl
+ << " // destructor" << endl
+ << "}" << endl
+ << endl;
+
+ hs << "public: // PROPERTIES" << endl;
+ foreach (const QDBusIntrospection::Property &property, interface->properties) {
+ QByteArray type = qtTypeName(property.type);
+ QString constRefType = constRefArg(type);
+ QString getter = propertyGetter(property);
+ QString setter = propertySetter(property);
+
+ hs << " Q_PROPERTY(" << type << " " << property.name;
+ if (property.access != QDBusIntrospection::Property::Write)
+ hs << " READ " << getter;
+ if (property.access != QDBusIntrospection::Property::Read)
+ hs << " WRITE " << setter;
+ hs << ")" << endl;
+
+ // getter:
+ if (property.access != QDBusIntrospection::Property::Write) {
+ hs << " " << type << " " << getter << "() const;" << endl;
+ cs << type << " "
+ << className << "::" << getter << "() const" << endl
+ << "{" << endl
+ << " // get the value of property " << property.name << endl
+ << " return qvariant_cast< " << type <<" >(parent()->property(\"" << property.name << "\"));" << endl
+ << "}" << endl
+ << endl;
+ }
+
+ // setter
+ if (property.access != QDBusIntrospection::Property::Read) {
+ hs << " void " << setter << "(" << constRefType << "value);" << endl;
+ cs << "void " << className << "::" << setter << "(" << constRefType << "value)" << endl
+ << "{" << endl
+ << " // set the value of property " << property.name << endl
+ << " parent()->setProperty(\"" << property.name << "\", value);" << endl
+ << "}" << endl
+ << endl;
+ }
+
+ hs << endl;
+ }
+
+ hs << "public Q_SLOTS: // METHODS" << endl;
+ foreach (const QDBusIntrospection::Method &method, interface->methods) {
+ bool isAsync = method.annotations.value(ANNOTATION_NO_WAIT) == "true";
+ if (isAsync && !method.outputArgs.isEmpty()) {
+ fprintf(stderr, "warning: method %s in interface %s is marked 'async' but has output arguments.\n",
+ qPrintable(method.name), qPrintable(interface->name));
+ continue;
+ }
+
+ hs << " ";
+ if (method.annotations.value("org.freedesktop.DBus.Deprecated") == "true")
+ hs << "Q_DECL_DEPRECATED ";
+
+ QByteArray returnType;
+ if (isAsync) {
+ hs << "Q_ASYNC void ";
+ cs << "void ";
+ } else if (method.outputArgs.isEmpty()) {
+ hs << "void ";
+ cs << "void ";
+ } else {
+ returnType = qtTypeName(method.outputArgs.first().type);
+ hs << returnType << " ";
+ cs << returnType << " ";
+ }
+
+ QString name = method.name;
+ hs << name << "(";
+ cs << className << "::" << name << "(";
+
+ QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs);
+ writeArgList(hs, argNames, method.inputArgs, method.outputArgs);
+ writeArgList(cs, argNames, method.inputArgs, method.outputArgs);
+
+ hs << ");" << endl; // finished for header
+ cs << ")" << endl
+ << "{" << endl
+ << " // handle method call " << interface->name << "." << method.name << endl;
+
+ // create the return type
+ int j = method.inputArgs.count();
+ if (!returnType.isEmpty())
+ cs << " " << returnType << " " << argNames.at(j) << ";" << endl;
+
+ // make the call
+ if (method.inputArgs.count() <= 10 && method.outputArgs.count() <= 1) {
+ // we can use QMetaObject::invokeMethod
+ static const char invoke[] = " QMetaObject::invokeMethod(parent(), \"";
+ cs << invoke << name << "\"";
+
+ if (!method.outputArgs.isEmpty())
+ cs << ", Q_RETURN_ARG("
+ << qtTypeName(method.outputArgs.at(0).type)
+ << ", "
+ << argNames.at(method.inputArgs.count())
+ << ")";
+
+ for (int i = 0; i < method.inputArgs.count(); ++i)
+ cs << ", Q_ARG("
+ << qtTypeName(method.inputArgs.at(i).type)
+ << ", "
+ << argNames.at(i)
+ << ")";
+
+ cs << ");" << endl;
+ }
+
+ cs << endl
+ << " // Alternative:" << endl
+ << " //";
+ if (!method.outputArgs.isEmpty())
+ cs << argNames.at(method.inputArgs.count()) << " = ";
+ cs << "static_cast<YourObjectType *>(parent())->" << name << "(";
+
+ int argPos = 0;
+ bool first = true;
+ for (int i = 0; i < method.inputArgs.count(); ++i) {
+ cs << (first ? "" : ", ") << argNames.at(argPos++);
+ first = false;
+ }
+ ++argPos; // skip retval, if any
+ for (int i = 1; i < method.outputArgs.count(); ++i) {
+ cs << (first ? "" : ", ") << argNames.at(argPos++);
+ first = false;
+ }
+
+ cs << ");" << endl;
+ if (!method.outputArgs.isEmpty())
+ cs << " return " << argNames.at(method.inputArgs.count()) << ";" << endl;
+ cs << "}" << endl
+ << endl;
+ }
+
+ hs << "Q_SIGNALS: // SIGNALS" << endl;
+ foreach (const QDBusIntrospection::Signal &signal, interface->signals_) {
+ hs << " ";
+ if (signal.annotations.value("org.freedesktop.DBus.Deprecated") == "true")
+ hs << "Q_DECL_DEPRECATED ";
+
+ hs << "void " << signal.name << "(";
+
+ QStringList argNames = makeArgNames(signal.outputArgs);
+ writeArgList(hs, argNames, signal.outputArgs);
+
+ hs << ");" << endl; // finished for header
+ }
+
+ // close the class:
+ hs << "};" << endl
+ << endl;
+ }
+
+ // close the include guard
+ hs << "#endif" << endl;
+
+ if (includeMocs)
+ cs << endl
+ << "#include \"" << adaptorFile << ".moc\"" << endl;
+
+ cs.flush();
+ hs.flush();
+ if (headerName == cppName)
+ file.write(cppData);
+ else {
+ // write to cpp file
+ QFile f(cppName);
+ f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
+ f.write(cppData);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ parseCmdLine(argc, argv);
+
+ QDBusIntrospection::Interfaces interfaces = readInput();
+ cleanInterfaces(interfaces);
+
+ writeProxy(proxyFile, interfaces);
+
+ if (adaptorFile)
+ writeAdaptor(adaptorFile, interfaces);
+
+ return 0;
+}
+
+/*!
+ \page dbusidl2cpp.html
+ \title QtDBus IDL compiler (dbusidl2cpp)
+
+ The QtDBus IDL compiler is a tool that can be used to parse interface descriptions and produce
+ static code representing those interfaces, which can then be used to make calls to remote
+ objects or implement said interfaces.
+
+ \c dbusidl2dcpp has two modes of operation, that correspond to the two possible outputs it can
+ produce: the interface (proxy) class or the adaptor class.The latter consists of both a C++
+ header and a source file, which are meant to be edited and adapted to your needs.
+
+ The \c dbusidl2dcpp tool is not meant to be run every time you compile your
+ application. Instead, it's meant to be used when developing the code or when the interface
+ changes.
+
+ The adaptor classes generated by \c dbusidl2cpp are just a skeleton that must be completed. It
+ generates, by default, calls to slots with the same name on the object the adaptor is attached
+ to. However, you may modify those slots or the property accessor functions to suit your needs.
+*/