summaryrefslogtreecommitdiffstats
path: root/qt/tools/dbuscpp2xml.cpp
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/dbuscpp2xml.cpp
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/dbuscpp2xml.cpp')
-rw-r--r--qt/tools/dbuscpp2xml.cpp409
1 files changed, 409 insertions, 0 deletions
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);
+}
+