source: trunk/tools/qdbus/qdbuscpp2xml/qdbuscpp2xml.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 13.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QByteArray>
43#include <QString>
44#include <QVarLengthArray>
45#include <QFile>
46#include <QProcess>
47#include <QMetaObject>
48#include <QList>
49#include <QRegExp>
50#include <QCoreApplication>
51#include <QLibraryInfo>
52
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <stdlib.h>
57
58#include "qdbusconnection.h" // for the Export* flags
59
60// copied from dbus-protocol.h:
61static const char docTypeHeader[] =
62 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
63 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
64
65// in qdbusxmlgenerator.cpp
66QT_BEGIN_NAMESPACE
67extern QDBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
68 const QMetaObject *base, int flags);
69QT_END_NAMESPACE
70
71#define PROGRAMNAME "qdbuscpp2xml"
72#define PROGRAMVERSION "0.1"
73#define PROGRAMCOPYRIGHT "Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)."
74
75static QString outputFile;
76static int flags;
77
78static const char help[] =
79 "Usage: " PROGRAMNAME " [options...] [files...]\n"
80 "Parses the C++ source or header file containing a QObject-derived class and\n"
81 "produces the D-Bus Introspection XML."
82 "\n"
83 "Options:\n"
84 " -p|-s|-m Only parse scriptable Properties, Signals and Methods (slots)\n"
85 " -P|-S|-M Parse all Properties, Signals and Methods (slots)\n"
86 " -a Output all scriptable contents (equivalent to -psm)\n"
87 " -A Output all contents (equivalent to -PSM)\n"
88 " -o <filename> Write the output to file <filename>\n"
89 " -h Show this information\n"
90 " -V Show the program version and quit.\n"
91 "\n";
92
93class MocParser
94{
95 void parseError();
96 QByteArray readLine();
97 void loadIntData(uint *&data);
98 void loadStringData(char *&stringdata);
99
100 QIODevice *input;
101 const char *filename;
102 int lineNumber;
103public:
104 ~MocParser();
105 void parse(const char *filename, QIODevice *input, int lineNumber = 0);
106
107 QList<QMetaObject> objects;
108};
109
110void MocParser::parseError()
111{
112 fprintf(stderr, PROGRAMNAME ": error parsing input file '%s' line %d \n", filename, lineNumber);
113 exit(1);
114}
115
116QByteArray MocParser::readLine()
117{
118 ++lineNumber;
119 return input->readLine();
120}
121
122void MocParser::loadIntData(uint *&data)
123{
124 data = 0; // initialise
125 QVarLengthArray<uint> array;
126 QRegExp rx(QLatin1String("(\\d+|0x[0-9abcdef]+)"), Qt::CaseInsensitive);
127
128 while (!input->atEnd()) {
129 QString line = QLatin1String(readLine());
130 int pos = line.indexOf(QLatin1String("//"));
131 if (pos != -1)
132 line.truncate(pos); // drop comments
133
134 if (line == QLatin1String("};\n")) {
135 // end of data
136 data = new uint[array.count()];
137 memcpy(data, array.data(), array.count() * sizeof(*data));
138 return;
139 }
140
141 pos = 0;
142 while ((pos = rx.indexIn(line, pos)) != -1) {
143 QString num = rx.cap(1);
144 if (num.startsWith(QLatin1String("0x")))
145 array.append(num.mid(2).toUInt(0, 16));
146 else
147 array.append(num.toUInt());
148 pos += rx.matchedLength();
149 }
150 }
151
152 parseError();
153}
154
155void MocParser::loadStringData(char *&stringdata)
156{
157 stringdata = 0;
158 QVarLengthArray<char, 1024> array;
159
160 while (!input->atEnd()) {
161 QByteArray line = readLine();
162 if (line == "};\n") {
163 // end of data
164 stringdata = new char[array.count()];
165 memcpy(stringdata, array.data(), array.count() * sizeof(*stringdata));
166 return;
167 }
168
169 int start = line.indexOf('"');
170 if (start == -1)
171 parseError();
172
173 int len = line.length() - 1;
174 line.truncate(len); // drop ending \n
175 if (line.at(len - 1) != '"')
176 parseError();
177
178 --len;
179 ++start;
180 for ( ; start < len; ++start)
181 if (line.at(start) == '\\') {
182 // parse escaped sequence
183 ++start;
184 if (start == len)
185 parseError();
186
187 QChar c(QLatin1Char(line.at(start)));
188 if (!c.isDigit()) {
189 switch (c.toLatin1()) {
190 case 'a':
191 array.append('\a');
192 break;
193 case 'b':
194 array.append('\b');
195 break;
196 case 'f':
197 array.append('\f');
198 break;
199 case 'n':
200 array.append('\n');
201 break;
202 case 'r':
203 array.append('\r');
204 break;
205 case 't':
206 array.append('\t');
207 break;
208 case 'v':
209 array.append('\v');
210 break;
211 case '\\':
212 case '?':
213 case '\'':
214 case '"':
215 array.append(c.toLatin1());
216 break;
217
218 case 'x':
219 if (start + 2 <= len)
220 parseError();
221 array.append(char(line.mid(start + 1, 2).toInt(0, 16)));
222 break;
223
224 default:
225 array.append(c.toLatin1());
226 fprintf(stderr, PROGRAMNAME ": warning: invalid escape sequence '\\%c' found in input",
227 c.toLatin1());
228 }
229 } else {
230 // octal
231 QRegExp octal(QLatin1String("([0-7]+)"));
232 if (octal.indexIn(QLatin1String(line), start) == -1)
233 parseError();
234 array.append(char(octal.cap(1).toInt(0, 8)));
235 }
236 } else {
237 array.append(line.at(start));
238 }
239 }
240
241 parseError();
242}
243
244void MocParser::parse(const char *fname, QIODevice *io, int lineNum)
245{
246 filename = fname;
247 input = io;
248 lineNumber = lineNum;
249
250 while (!input->atEnd()) {
251 QByteArray line = readLine();
252 if (line.startsWith("static const uint qt_meta_data_")) {
253 // start of new class data
254 uint *data;
255 loadIntData(data);
256
257 // find the start of the string data
258 do {
259 line = readLine();
260 if (input->atEnd())
261 parseError();
262 } while (!line.startsWith("static const char qt_meta_stringdata_"));
263
264 char *stringdata;
265 loadStringData(stringdata);
266
267 QMetaObject mo;
268 mo.d.superdata = &QObject::staticMetaObject;
269 mo.d.stringdata = stringdata;
270 mo.d.data = data;
271 mo.d.extradata = 0;
272 objects.append(mo);
273 }
274 }
275
276 fname = 0;
277 input = 0;
278}
279
280MocParser::~MocParser()
281{
282 foreach (QMetaObject mo, objects) {
283 delete const_cast<char *>(mo.d.stringdata);
284 delete const_cast<uint *>(mo.d.data);
285 }
286}
287
288static void showHelp()
289{
290 printf("%s", help);
291 exit(0);
292}
293
294static void showVersion()
295{
296 printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
297 printf("D-Bus QObject-to-XML converter\n");
298 exit(0);
299}
300
301static void parseCmdLine(QStringList &arguments)
302{
303 for (int i = 1; i < arguments.count(); ++i) {
304 const QString arg = arguments.at(i);
305
306 if (arg == QLatin1String("--help"))
307 showHelp();
308
309 if (!arg.startsWith(QLatin1Char('-')))
310 continue;
311
312 char c = arg.count() == 2 ? arg.at(1).toLatin1() : char(0);
313 switch (c) {
314 case 'P':
315 flags |= QDBusConnection::ExportNonScriptableProperties;
316 // fall through
317 case 'p':
318 flags |= QDBusConnection::ExportScriptableProperties;
319 break;
320
321 case 'S':
322 flags |= QDBusConnection::ExportNonScriptableSignals;
323 // fall through
324 case 's':
325 flags |= QDBusConnection::ExportScriptableSignals;
326 break;
327
328 case 'M':
329 flags |= QDBusConnection::ExportNonScriptableSlots;
330 // fall through
331 case 'm':
332 flags |= QDBusConnection::ExportScriptableSlots;
333 break;
334
335 case 'A':
336 flags |= QDBusConnection::ExportNonScriptableContents;
337 // fall through
338 case 'a':
339 flags |= QDBusConnection::ExportScriptableContents;
340 break;
341
342 case 'o':
343 if (arguments.count() < i + 2 || arguments.at(i + 1).startsWith(QLatin1Char('-'))) {
344 printf("-o expects a filename\n");
345 exit(1);
346 }
347 outputFile = arguments.takeAt(i + 1);
348 break;
349
350 case 'h':
351 case '?':
352 showHelp();
353 break;
354
355 case 'V':
356 showVersion();
357 break;
358
359 default:
360 printf("unknown option: \"%s\"\n", qPrintable(arg));
361 exit(1);
362 }
363 }
364
365 if (flags == 0)
366 flags = QDBusConnection::ExportScriptableContents
367 | QDBusConnection::ExportNonScriptableContents;
368}
369
370int main(int argc, char **argv)
371{
372 QCoreApplication app(argc, argv);
373 QStringList args = app.arguments();
374
375 MocParser parser;
376 parseCmdLine(args);
377
378 for (int i = 1; i < args.count(); ++i) {
379 const QString arg = args.at(i);
380 if (arg.startsWith(QLatin1Char('-')))
381 continue;
382
383 QFile f(arg);
384 if (!f.open(QIODevice::ReadOnly|QIODevice::Text)) {
385 fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n",
386 qPrintable(arg), qPrintable(f.errorString()));
387 return 1;
388 }
389
390 f.readLine();
391
392 QByteArray line = f.readLine();
393 if (line.contains("Meta object code from reading C++ file"))
394 // this is a moc-generated file
395 parser.parse(argv[i], &f, 3);
396 else {
397 // run moc on this file
398 QProcess proc;
399 proc.start(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/moc"), QStringList() << QFile::decodeName(argv[i]), QIODevice::ReadOnly | QIODevice::Text);
400
401 if (!proc.waitForStarted()) {
402 fprintf(stderr, PROGRAMNAME ": could not execute moc! Aborting.\n");
403 return 1;
404 }
405
406 proc.closeWriteChannel();
407
408 if (!proc.waitForFinished() || proc.exitStatus() != QProcess::NormalExit ||
409 proc.exitCode() != 0) {
410 // output the moc errors:
411 fprintf(stderr, "%s", proc.readAllStandardError().constData());
412 fprintf(stderr, PROGRAMNAME ": exit code %d from moc. Aborting\n", proc.exitCode());
413 return 1;
414 }
415 fprintf(stderr, "%s", proc.readAllStandardError().constData());
416
417 parser.parse(argv[i], &proc, 1);
418 }
419
420 f.close();
421 }
422
423 QFile output;
424 if (outputFile.isEmpty()) {
425 output.open(stdout, QIODevice::WriteOnly);
426 } else {
427 output.setFileName(outputFile);
428 if (!output.open(QIODevice::WriteOnly)) {
429 fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s",
430 qPrintable(outputFile), qPrintable(output.errorString()));
431 return 1;
432 }
433 }
434
435 output.write(docTypeHeader);
436 output.write("<node>\n");
437 foreach (QMetaObject mo, parser.objects) {
438 QString xml = qDBusGenerateMetaObjectXml(QString(), &mo, &QObject::staticMetaObject,
439 flags);
440 output.write(xml.toLocal8Bit());
441 }
442 output.write("</node>\n");
443
444 return 0;
445}
446
Note: See TracBrowser for help on using the repository browser.