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>
35 #include "qdbusconnection.h" // for the Export* flags
36 #include <dbus/dbus.h> // for the XML DOCTYPE declaration
38 // in qdbusxmlgenerator.cpp
39 extern QDBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
40 const QMetaObject *base, int flags);
42 #define PROGRAMNAME "dbuscpp2xml"
43 #define PROGRAMVERSION "0.1"
44 #define PROGRAMCOPYRIGHT "Copyright (C) 2006 Trolltech AS. All rights reserved."
46 static const char cmdlineOptions[] = "psmaPSMAo:";
47 static const char *outputFile;
50 static const char help[] =
51 "Usage: " PROGRAMNAME " [options...] [files...]\n"
52 "Parses the C++ source or header file containing a QObject-derived class and\n"
53 "produces the D-Bus Introspection XML."
56 " -p|-s|-m Only parse scriptable Properties, Signals and Methods (slots)\n"
57 " -P|-S|-M Parse all Properties, Signals and Methods (slots)\n"
58 " -a Output all scriptable contents (equivalent to -psm)\n"
59 " -A Output all contents (equivalent to -PSM)\n"
60 " -o <filename> Write the output to file <filename>\n"
61 " -h Show this information\n"
62 " -V Show the program version and quit.\n"
68 QByteArray readLine();
69 void loadIntData(uint *&data);
70 void loadStringData(char *&stringdata);
77 void parse(const char *filename, QIODevice *input, int lineNumber = 0);
79 QList<QMetaObject> objects;
82 void MocParser::parseError()
84 fprintf(stderr, PROGRAMNAME ": error parsing input file '%s' line %d \n", filename, line);
88 QByteArray MocParser::readLine()
91 return input->readLine();
94 void MocParser::loadIntData(uint *&data)
96 data = 0; // initialise
97 QVarLengthArray<uint> array;
98 QRegExp rx("(\\d+|0x[0-9abcdef]+)", Qt::CaseInsensitive);
100 while (!input->atEnd()) {
101 QString line = QLatin1String(readLine());
102 int pos = line.indexOf("//");
104 line.truncate(pos); // drop comments
106 if (line == "};\n") {
108 data = new uint[array.count()];
109 memcpy(data, array.data(), array.count() * sizeof(*data));
114 while ((pos = rx.indexIn(line, pos)) != -1) {
115 QString num = rx.cap(1);
116 if (num.startsWith("0x"))
117 array.append(num.mid(2).toUInt(0, 16));
119 array.append(num.toUInt());
120 pos += rx.matchedLength();
127 void MocParser::loadStringData(char *&stringdata)
130 QVarLengthArray<char, 1024> array;
132 while (!input->atEnd()) {
133 QByteArray line = readLine();
134 if (line == "};\n") {
136 stringdata = new char[array.count()];
137 memcpy(stringdata, array.data(), array.count() * sizeof(*stringdata));
141 int start = line.indexOf('"');
145 int len = line.length() - 1;
146 line.truncate(len); // drop ending \n
147 if (line.at(len - 1) != '"')
152 for ( ; start < len; ++start)
153 if (line.at(start) == '\\') {
154 // parse escaped sequence
159 QChar c(QLatin1Char(line.at(start)));
161 switch (c.toLatin1()) {
187 array.append(c.toLatin1());
191 if (start + 2 <= len)
193 array.append(char(line.mid(start + 1, 2).toInt(0, 16)));
197 array.append(c.toLatin1());
198 fprintf(stderr, PROGRAMNAME ": warning: invalid escape sequence '\\%c' found in input",
203 QRegExp octal("([0-7]+)");
204 if (octal.indexIn(QLatin1String(line), start) == -1)
206 array.append(char(octal.cap(1).toInt(0, 8)));
209 array.append(line.at(start));
216 void MocParser::parse(const char *fname, QIODevice *io, int lineNumber)
222 while (!input->atEnd()) {
223 QByteArray line = readLine();
224 if (line.startsWith("static const uint qt_meta_data_")) {
225 // start of new class data
229 // find the start of the string data
234 } while (!line.startsWith("static const char qt_meta_stringdata_"));
237 loadStringData(stringdata);
240 mo.d.superdata = &QObject::staticMetaObject;
241 mo.d.stringdata = stringdata;
252 MocParser::~MocParser()
254 foreach (QMetaObject mo, objects) {
255 delete const_cast<char *>(mo.d.stringdata);
256 delete const_cast<uint *>(mo.d.data);
260 static void showHelp()
266 static void showVersion()
268 printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
269 printf("D-Bus QObject-to-XML converter\n");
273 static void parseCmdLine(int argc, char **argv)
277 while ((c = getopt(argc, argv, cmdlineOptions)) != -1)
281 flags |= QDBusConnection::ExportProperties;
285 flags |= QDBusConnection::ExportSignals;
289 flags |= QDBusConnection::ExportSlots;
293 flags |= QDBusConnection::ExportContents;
297 flags |= QDBusConnection::ExportAllProperties;
301 flags |= QDBusConnection::ExportAllSignals;
305 flags |= QDBusConnection::ExportAllSlots;
309 flags |= QDBusConnection::ExportAllContents;
331 flags = QDBusConnection::ExportAllContents;
334 int main(int argc, char **argv)
337 parseCmdLine(argc, argv);
339 for (int i = 1; i < argc; ++i) {
340 FILE *in = fopen(argv[i], "r");
342 fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n",
343 argv[i], strerror(errno));
348 f.open(in, QIODevice::ReadOnly);
351 QByteArray line = f.readLine();
352 if (line.contains("Meta object code from reading C++ file"))
353 // this is a moc-generated file
354 parser.parse(argv[i], &f, 3);
356 // run moc on this file
358 proc.start("moc", QStringList() << QFile::encodeName(argv[i]));
360 if (!proc.waitForStarted()) {
361 fprintf(stderr, PROGRAMNAME ": could not execute moc! Aborting.\n");
365 proc.closeWriteChannel();
367 if (!proc.waitForFinished() || proc.exitStatus() != QProcess::NormalExit ||
368 proc.exitCode() != 0) {
369 // output the moc errors:
370 fprintf(stderr, "%s", proc.readAllStandardError().constData());
371 fprintf(stderr, PROGRAMNAME ": exit code %d from moc. Aborting\n", proc.exitCode());
374 fprintf(stderr, "%s", proc.readAllStandardError().constData());
376 parser.parse(argv[i], &proc, 1);
383 FILE *output = stdout;
384 if (outputFile != 0) {
385 output = fopen(outputFile, "w");
387 fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s",
388 outputFile, strerror(errno));
393 fprintf(output, "%s<node>\n", DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
394 foreach (QMetaObject mo, parser.objects) {
395 QString xml = qDBusGenerateMetaObjectXml(QString(), &mo, &QObject::staticMetaObject,
397 fprintf(output, "%s", qPrintable(xml));
399 fprintf(output, "</node>\n");
401 if (output != stdout)