3 * Copyright (C) 2006 Trolltech AS. All rights reserved.
4 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <QVarLengthArray>
27 #include <QMetaObject>
36 #include "../src/qdbusconnection.h" // for the Export* flags
38 // copied from dbus-protocol.h:
39 static const char docTypeHeader[] =
40 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
41 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
43 // in qdbusxmlgenerator.cpp
44 extern QDBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
45 const QMetaObject *base, int flags);
47 #define PROGRAMNAME "dbuscpp2xml"
48 #define PROGRAMVERSION "0.1"
49 #define PROGRAMCOPYRIGHT "Copyright (C) 2006 Trolltech AS. All rights reserved."
51 static const char cmdlineOptions[] = "psmaPSMAo:hV";
52 static const char *outputFile;
55 static const char help[] =
56 "Usage: " PROGRAMNAME " [options...] [files...]\n"
57 "Parses the C++ source or header file containing a QObject-derived class and\n"
58 "produces the D-Bus Introspection XML."
61 " -p|-s|-m Only parse scriptable Properties, Signals and Methods (slots)\n"
62 " -P|-S|-M Parse all Properties, Signals and Methods (slots)\n"
63 " -a Output all scriptable contents (equivalent to -psm)\n"
64 " -A Output all contents (equivalent to -PSM)\n"
65 " -o <filename> Write the output to file <filename>\n"
66 " -h Show this information\n"
67 " -V Show the program version and quit.\n"
73 QByteArray readLine();
74 void loadIntData(uint *&data);
75 void loadStringData(char *&stringdata);
82 void parse(const char *filename, QIODevice *input, int lineNumber = 0);
84 QList<QMetaObject> objects;
87 void MocParser::parseError()
89 fprintf(stderr, PROGRAMNAME ": error parsing input file '%s' line %d \n", filename, line);
93 QByteArray MocParser::readLine()
96 return input->readLine();
99 void MocParser::loadIntData(uint *&data)
101 data = 0; // initialise
102 QVarLengthArray<uint> array;
103 QRegExp rx("(\\d+|0x[0-9abcdef]+)", Qt::CaseInsensitive);
105 while (!input->atEnd()) {
106 QString line = QLatin1String(readLine());
107 int pos = line.indexOf("//");
109 line.truncate(pos); // drop comments
111 if (line == "};\n") {
113 data = new uint[array.count()];
114 memcpy(data, array.data(), array.count() * sizeof(*data));
119 while ((pos = rx.indexIn(line, pos)) != -1) {
120 QString num = rx.cap(1);
121 if (num.startsWith("0x"))
122 array.append(num.mid(2).toUInt(0, 16));
124 array.append(num.toUInt());
125 pos += rx.matchedLength();
132 void MocParser::loadStringData(char *&stringdata)
135 QVarLengthArray<char, 1024> array;
137 while (!input->atEnd()) {
138 QByteArray line = readLine();
139 if (line == "};\n") {
141 stringdata = new char[array.count()];
142 memcpy(stringdata, array.data(), array.count() * sizeof(*stringdata));
146 int start = line.indexOf('"');
150 int len = line.length() - 1;
151 line.truncate(len); // drop ending \n
152 if (line.at(len - 1) != '"')
157 for ( ; start < len; ++start)
158 if (line.at(start) == '\\') {
159 // parse escaped sequence
164 QChar c(QLatin1Char(line.at(start)));
166 switch (c.toLatin1()) {
192 array.append(c.toLatin1());
196 if (start + 2 <= len)
198 array.append(char(line.mid(start + 1, 2).toInt(0, 16)));
202 array.append(c.toLatin1());
203 fprintf(stderr, PROGRAMNAME ": warning: invalid escape sequence '\\%c' found in input",
208 QRegExp octal("([0-7]+)");
209 if (octal.indexIn(QLatin1String(line), start) == -1)
211 array.append(char(octal.cap(1).toInt(0, 8)));
214 array.append(line.at(start));
221 void MocParser::parse(const char *fname, QIODevice *io, int lineNumber)
227 while (!input->atEnd()) {
228 QByteArray line = readLine();
229 if (line.startsWith("static const uint qt_meta_data_")) {
230 // start of new class data
234 // find the start of the string data
239 } while (!line.startsWith("static const char qt_meta_stringdata_"));
242 loadStringData(stringdata);
245 mo.d.superdata = &QObject::staticMetaObject;
246 mo.d.stringdata = stringdata;
257 MocParser::~MocParser()
259 foreach (QMetaObject mo, objects) {
260 delete const_cast<char *>(mo.d.stringdata);
261 delete const_cast<uint *>(mo.d.data);
265 static void showHelp()
271 static void showVersion()
273 printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
274 printf("D-Bus QObject-to-XML converter\n");
278 static void parseCmdLine(int argc, char **argv)
282 while ((c = getopt(argc, argv, cmdlineOptions)) != -1)
286 flags |= QDBusConnection::ExportProperties;
290 flags |= QDBusConnection::ExportSignals;
294 flags |= QDBusConnection::ExportSlots;
298 flags |= QDBusConnection::ExportContents;
302 flags |= QDBusConnection::ExportAllProperties;
306 flags |= QDBusConnection::ExportAllSignals;
310 flags |= QDBusConnection::ExportAllSlots;
314 flags |= QDBusConnection::ExportAllContents;
336 flags = QDBusConnection::ExportAllContents;
339 int main(int argc, char **argv)
342 parseCmdLine(argc, argv);
344 for (int i = optind; i < argc; ++i) {
345 FILE *in = fopen(argv[i], "r");
347 fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n",
348 argv[i], strerror(errno));
353 f.open(in, QIODevice::ReadOnly);
356 QByteArray line = f.readLine();
357 if (line.contains("Meta object code from reading C++ file"))
358 // this is a moc-generated file
359 parser.parse(argv[i], &f, 3);
361 // run moc on this file
363 proc.start("moc", QStringList() << QFile::encodeName(argv[i]));
365 if (!proc.waitForStarted()) {
366 fprintf(stderr, PROGRAMNAME ": could not execute moc! Aborting.\n");
370 proc.closeWriteChannel();
372 if (!proc.waitForFinished() || proc.exitStatus() != QProcess::NormalExit ||
373 proc.exitCode() != 0) {
374 // output the moc errors:
375 fprintf(stderr, "%s", proc.readAllStandardError().constData());
376 fprintf(stderr, PROGRAMNAME ": exit code %d from moc. Aborting\n", proc.exitCode());
379 fprintf(stderr, "%s", proc.readAllStandardError().constData());
381 parser.parse(argv[i], &proc, 1);
388 FILE *output = stdout;
389 if (outputFile != 0) {
390 output = fopen(outputFile, "w");
392 fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s",
393 outputFile, strerror(errno));
398 fprintf(output, "%s<node>\n", docTypeHeader);
399 foreach (QMetaObject mo, parser.objects) {
400 QString xml = qDBusGenerateMetaObjectXml(QString(), &mo, &QObject::staticMetaObject,
402 fprintf(output, "%s", qPrintable(xml));
404 fprintf(output, "</node>\n");
406 if (output != stdout)