1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2020 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <qbytearray.h> |
30 | #include <qcommandlineparser.h> |
31 | #include <qcoreapplication.h> |
32 | #include <qdebug.h> |
33 | #include <qfile.h> |
34 | #include <qfileinfo.h> |
35 | #include <qloggingcategory.h> |
36 | #include <qstring.h> |
37 | #include <qstringlist.h> |
38 | #include <qtextstream.h> |
39 | #include <qset.h> |
40 | |
41 | #include <qdbusmetatype.h> |
42 | #include <private/qdbusintrospection_p.h> |
43 | |
44 | #include <stdio.h> |
45 | #include <stdlib.h> |
46 | |
47 | #define PROGRAMNAME "qdbusxml2cpp" |
48 | #define PROGRAMVERSION "0.8" |
49 | #define PROGRAMCOPYRIGHT "Copyright (C) 2020 The Qt Company Ltd." |
50 | |
51 | #define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" |
52 | |
53 | static QString globalClassName; |
54 | static QString parentClassName; |
55 | static QString proxyFile; |
56 | static QString adaptorFile; |
57 | static QString inputFile; |
58 | static bool skipNamespaces; |
59 | static bool verbose; |
60 | static bool includeMocs; |
61 | static QString commandLine; |
62 | static QStringList includes; |
63 | static QStringList wantedInterfaces; |
64 | |
65 | static const char includeList[] = |
66 | "#include <QtCore/QByteArray>\n" |
67 | "#include <QtCore/QList>\n" |
68 | "#include <QtCore/QMap>\n" |
69 | "#include <QtCore/QString>\n" |
70 | "#include <QtCore/QStringList>\n" |
71 | "#include <QtCore/QVariant>\n" ; |
72 | |
73 | static const char forwardDeclarations[] = |
74 | "#include <QtCore/qcontainerfwd.h>\n" ; |
75 | |
76 | static QDBusIntrospection::Interfaces readInput() |
77 | { |
78 | QFile input(inputFile); |
79 | if (inputFile.isEmpty() || inputFile == QLatin1String("-" )) { |
80 | input.open(stdin, QIODevice::ReadOnly); |
81 | } else { |
82 | input.open(QIODevice::ReadOnly); |
83 | } |
84 | |
85 | QByteArray data = input.readAll(); |
86 | |
87 | // check if the input is already XML |
88 | data = data.trimmed(); |
89 | if (data.startsWith("<!DOCTYPE " ) || data.startsWith("<?xml" ) || |
90 | data.startsWith("<node" ) || data.startsWith("<interface" )) |
91 | // already XML |
92 | return QDBusIntrospection::parseInterfaces(QString::fromUtf8(data)); |
93 | |
94 | fprintf(stderr, "%s: Cannot process input: '%s'. Stop.\n" , |
95 | PROGRAMNAME, qPrintable(inputFile)); |
96 | exit(1); |
97 | } |
98 | |
99 | static void cleanInterfaces(QDBusIntrospection::Interfaces &interfaces) |
100 | { |
101 | if (!wantedInterfaces.isEmpty()) { |
102 | QDBusIntrospection::Interfaces::Iterator it = interfaces.begin(); |
103 | while (it != interfaces.end()) |
104 | if (!wantedInterfaces.contains(it.key())) |
105 | it = interfaces.erase(it); |
106 | else |
107 | ++it; |
108 | } |
109 | } |
110 | |
111 | // produce a header name from the file name |
112 | static QString (const QString &name) |
113 | { |
114 | QStringList parts = name.split(QLatin1Char(':')); |
115 | QString retval = parts.first(); |
116 | |
117 | if (retval.isEmpty() || retval == QLatin1String("-" )) |
118 | return retval; |
119 | |
120 | if (!retval.endsWith(QLatin1String(".h" )) && !retval.endsWith(QLatin1String(".cpp" )) && |
121 | !retval.endsWith(QLatin1String(".cc" ))) |
122 | retval.append(QLatin1String(".h" )); |
123 | |
124 | return retval; |
125 | } |
126 | |
127 | // produce a cpp name from the file name |
128 | static QString cpp(const QString &name) |
129 | { |
130 | QStringList parts = name.split(QLatin1Char(':')); |
131 | QString retval = parts.last(); |
132 | |
133 | if (retval.isEmpty() || retval == QLatin1String("-" )) |
134 | return retval; |
135 | |
136 | if (!retval.endsWith(QLatin1String(".h" )) && !retval.endsWith(QLatin1String(".cpp" )) && |
137 | !retval.endsWith(QLatin1String(".cc" ))) |
138 | retval.append(QLatin1String(".cpp" )); |
139 | |
140 | return retval; |
141 | } |
142 | |
143 | // produce a moc name from the file name |
144 | static QString moc(const QString &name) |
145 | { |
146 | QString retval = header(name); |
147 | if (retval.isEmpty()) |
148 | return retval; |
149 | |
150 | retval.truncate(retval.length() - 1); // drop the h in .h |
151 | retval += QLatin1String("moc" ); |
152 | return retval; |
153 | } |
154 | |
155 | static QTextStream &(QTextStream &ts, bool changesWillBeLost) |
156 | { |
157 | ts << "/*" << Qt::endl |
158 | << " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION << Qt::endl |
159 | << " * Command line was: " << commandLine << Qt::endl |
160 | << " *" << Qt::endl |
161 | << " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT << Qt::endl |
162 | << " *" << Qt::endl |
163 | << " * This is an auto-generated file." << Qt::endl; |
164 | |
165 | if (changesWillBeLost) |
166 | ts << " * Do not edit! All changes made to it will be lost." << Qt::endl; |
167 | else |
168 | ts << " * This file may have been hand-edited. Look for HAND-EDIT comments" << Qt::endl |
169 | << " * before re-generating it." << Qt::endl; |
170 | |
171 | ts << " */" << Qt::endl |
172 | << Qt::endl; |
173 | |
174 | return ts; |
175 | } |
176 | |
177 | enum ClassType { Proxy, Adaptor }; |
178 | static QString classNameForInterface(const QString &interface, ClassType classType) |
179 | { |
180 | if (!globalClassName.isEmpty()) |
181 | return globalClassName; |
182 | |
183 | const auto parts = QStringView{interface}.split(QLatin1Char('.')); |
184 | |
185 | QString retval; |
186 | if (classType == Proxy) { |
187 | for (const auto &part : parts) { |
188 | retval += part[0].toUpper(); |
189 | retval += part.mid(1); |
190 | } |
191 | } else { |
192 | retval += parts.last()[0].toUpper() + parts.last().mid(1); |
193 | } |
194 | |
195 | if (classType == Proxy) |
196 | retval += QLatin1String("Interface" ); |
197 | else |
198 | retval += QLatin1String("Adaptor" ); |
199 | |
200 | return retval; |
201 | } |
202 | |
203 | // ### Qt6 Remove the two isSignal ifs |
204 | // They are only here because before signal arguments where previously searched as "In" so to maintain compatibility |
205 | // we first search for "Out" and if not found we search for "In" |
206 | static QByteArray qtTypeName(const QString &signature, const QDBusIntrospection::Annotations &annotations, int paramId = -1, const char *direction = "Out" , bool isSignal = false) |
207 | { |
208 | int type = QDBusMetaType::signatureToMetaType(signature.toLatin1()).id(); |
209 | if (type == QMetaType::UnknownType) { |
210 | QString annotationName = QString::fromLatin1("org.qtproject.QtDBus.QtTypeName" ); |
211 | if (paramId >= 0) |
212 | annotationName += QString::fromLatin1(".%1%2" ).arg(QLatin1String(direction)).arg(paramId); |
213 | QString qttype = annotations.value(annotationName); |
214 | if (!qttype.isEmpty()) |
215 | return std::move(qttype).toLatin1(); |
216 | |
217 | QString oldAnnotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName" ); |
218 | if (paramId >= 0) |
219 | oldAnnotationName += QString::fromLatin1(".%1%2" ).arg(QLatin1String(direction)).arg(paramId); |
220 | qttype = annotations.value(oldAnnotationName); |
221 | |
222 | if (qttype.isEmpty()) { |
223 | if (!isSignal || qstrcmp(direction, "Out" ) == 0) { |
224 | fprintf(stderr, "%s: Got unknown type `%s' processing '%s'\n" , |
225 | PROGRAMNAME, qPrintable(signature), qPrintable(inputFile)); |
226 | fprintf(stderr, "You should add <annotation name=\"%s\" value=\"<type>\"/> to the XML description\n" , |
227 | qPrintable(annotationName)); |
228 | } |
229 | |
230 | if (isSignal) |
231 | return qtTypeName(signature, annotations, paramId, "In" , isSignal); |
232 | |
233 | exit(1); |
234 | } |
235 | |
236 | fprintf(stderr, "%s: Warning: deprecated annotation '%s' found while processing '%s'; " |
237 | "suggest updating to '%s'\n" , |
238 | PROGRAMNAME, qPrintable(oldAnnotationName), qPrintable(inputFile), |
239 | qPrintable(annotationName)); |
240 | return std::move(qttype).toLatin1(); |
241 | } |
242 | |
243 | return QMetaType(type).name(); |
244 | } |
245 | |
246 | static QString nonConstRefArg(const QByteArray &arg) |
247 | { |
248 | return QLatin1String(arg + " &" ); |
249 | } |
250 | |
251 | static QString templateArg(const QByteArray &arg) |
252 | { |
253 | if (!arg.endsWith('>')) |
254 | return QLatin1String(arg); |
255 | |
256 | return QLatin1String(arg + ' '); |
257 | } |
258 | |
259 | static QString constRefArg(const QByteArray &arg) |
260 | { |
261 | if (!arg.startsWith('Q')) |
262 | return QLatin1String(arg + ' '); |
263 | else |
264 | return QString( QLatin1String("const %1 &" ) ).arg( QLatin1String(arg) ); |
265 | } |
266 | |
267 | static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, |
268 | const QDBusIntrospection::Arguments &outputArgs = |
269 | QDBusIntrospection::Arguments()) |
270 | { |
271 | QStringList retval; |
272 | const int numInputArgs = inputArgs.count(); |
273 | const int numOutputArgs = outputArgs.count(); |
274 | retval.reserve(numInputArgs + numOutputArgs); |
275 | for (int i = 0; i < numInputArgs; ++i) { |
276 | const QDBusIntrospection::Argument &arg = inputArgs.at(i); |
277 | QString name = arg.name; |
278 | if (name.isEmpty()) |
279 | name = QString( QLatin1String("in%1" ) ).arg(i); |
280 | else |
281 | name.replace(QLatin1Char('-'), QLatin1Char('_')); |
282 | while (retval.contains(name)) |
283 | name += QLatin1String("_" ); |
284 | retval << name; |
285 | } |
286 | for (int i = 0; i < numOutputArgs; ++i) { |
287 | const QDBusIntrospection::Argument &arg = outputArgs.at(i); |
288 | QString name = arg.name; |
289 | if (name.isEmpty()) |
290 | name = QString( QLatin1String("out%1" ) ).arg(i); |
291 | else |
292 | name.replace(QLatin1Char('-'), QLatin1Char('_')); |
293 | while (retval.contains(name)) |
294 | name += QLatin1String("_" ); |
295 | retval << name; |
296 | } |
297 | return retval; |
298 | } |
299 | |
300 | static void writeArgList(QTextStream &ts, const QStringList &argNames, |
301 | const QDBusIntrospection::Annotations &annotations, |
302 | const QDBusIntrospection::Arguments &inputArgs, |
303 | const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments()) |
304 | { |
305 | // input args: |
306 | bool first = true; |
307 | int argPos = 0; |
308 | for (int i = 0; i < inputArgs.count(); ++i) { |
309 | const QDBusIntrospection::Argument &arg = inputArgs.at(i); |
310 | QString type = constRefArg(qtTypeName(arg.type, annotations, i, "In" )); |
311 | |
312 | if (!first) |
313 | ts << ", " ; |
314 | ts << type << argNames.at(argPos++); |
315 | first = false; |
316 | } |
317 | |
318 | argPos++; |
319 | |
320 | // output args |
321 | // yes, starting from 1 |
322 | for (int i = 1; i < outputArgs.count(); ++i) { |
323 | const QDBusIntrospection::Argument &arg = outputArgs.at(i); |
324 | |
325 | if (!first) |
326 | ts << ", " ; |
327 | ts << nonConstRefArg(qtTypeName(arg.type, annotations, i, "Out" )) |
328 | << argNames.at(argPos++); |
329 | first = false; |
330 | } |
331 | } |
332 | |
333 | static void writeSignalArgList(QTextStream &ts, const QStringList &argNames, |
334 | const QDBusIntrospection::Annotations &annotations, |
335 | const QDBusIntrospection::Arguments &outputArgs) |
336 | { |
337 | bool first = true; |
338 | int argPos = 0; |
339 | for (int i = 0; i < outputArgs.count(); ++i) { |
340 | const QDBusIntrospection::Argument &arg = outputArgs.at(i); |
341 | QString type = constRefArg(qtTypeName(arg.type, annotations, i, "Out" , true /* isSignal */)); |
342 | |
343 | if (!first) |
344 | ts << ", " ; |
345 | ts << type << argNames.at(argPos++); |
346 | first = false; |
347 | } |
348 | } |
349 | |
350 | static QString propertyGetter(const QDBusIntrospection::Property &property) |
351 | { |
352 | QString getter = property.annotations.value(QLatin1String("org.qtproject.QtDBus.PropertyGetter" )); |
353 | if (!getter.isEmpty()) |
354 | return getter; |
355 | |
356 | getter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertyGetter" )); |
357 | if (!getter.isEmpty()) { |
358 | fprintf(stderr, "%s: Warning: deprecated annotation 'com.trolltech.QtDBus.propertyGetter' found" |
359 | " while processing '%s';" |
360 | " suggest updating to 'org.qtproject.QtDBus.PropertyGetter'\n" , |
361 | PROGRAMNAME, qPrintable(inputFile)); |
362 | return getter; |
363 | } |
364 | |
365 | getter = property.name; |
366 | getter[0] = getter[0].toLower(); |
367 | return getter; |
368 | } |
369 | |
370 | static QString propertySetter(const QDBusIntrospection::Property &property) |
371 | { |
372 | QString setter = property.annotations.value(QLatin1String("org.qtproject.QtDBus.PropertySetter" )); |
373 | if (!setter.isEmpty()) |
374 | return setter; |
375 | |
376 | setter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertySetter" )); |
377 | if (!setter.isEmpty()) { |
378 | fprintf(stderr, "%s: Warning: deprecated annotation 'com.trolltech.QtDBus.propertySetter' found" |
379 | " while processing '%s';" |
380 | " suggest updating to 'org.qtproject.QtDBus.PropertySetter'\n" , |
381 | PROGRAMNAME, qPrintable(inputFile)); |
382 | return setter; |
383 | } |
384 | |
385 | setter = QLatin1String("set" ) + property.name; |
386 | setter[3] = setter[3].toUpper(); |
387 | return setter; |
388 | } |
389 | |
390 | static QString methodName(const QDBusIntrospection::Method &method) |
391 | { |
392 | QString name = method.annotations.value(QStringLiteral("org.qtproject.QtDBus.MethodName" )); |
393 | if (!name.isEmpty()) |
394 | return name; |
395 | |
396 | return method.name; |
397 | } |
398 | |
399 | static QString stringify(const QString &data) |
400 | { |
401 | QString retval; |
402 | int i; |
403 | for (i = 0; i < data.length(); ++i) { |
404 | retval += QLatin1Char('\"'); |
405 | for ( ; i < data.length() && data[i] != QLatin1Char('\n') && data[i] != QLatin1Char('\r'); ++i) |
406 | if (data[i] == QLatin1Char('\"')) |
407 | retval += QLatin1String("\\\"" ); |
408 | else |
409 | retval += data[i]; |
410 | if (i+1 < data.length() && data[i] == QLatin1Char('\r') && data[i+1] == QLatin1Char('\n')) |
411 | i++; |
412 | retval += QLatin1String("\\n\"\n" ); |
413 | } |
414 | return retval; |
415 | } |
416 | |
417 | static bool openFile(const QString &fileName, QFile &file) |
418 | { |
419 | if (fileName.isEmpty()) |
420 | return false; |
421 | |
422 | bool isOk = false; |
423 | if (fileName == QLatin1String("-" )) { |
424 | isOk = file.open(stdout, QIODevice::WriteOnly | QIODevice::Text); |
425 | } else { |
426 | file.setFileName(fileName); |
427 | isOk = file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); |
428 | } |
429 | |
430 | if (!isOk) |
431 | fprintf(stderr, "%s: Unable to open '%s': %s\n" , |
432 | PROGRAMNAME, qPrintable(fileName), qPrintable(file.errorString())); |
433 | return isOk; |
434 | } |
435 | |
436 | static void writeProxy(const QString &filename, const QDBusIntrospection::Interfaces &interfaces) |
437 | { |
438 | // open the file |
439 | QString = header(filename); |
440 | QByteArray ; |
441 | QTextStream hs(&headerData); |
442 | |
443 | QString cppName = cpp(filename); |
444 | QByteArray cppData; |
445 | QTextStream cs(&cppData); |
446 | |
447 | // write the header: |
448 | writeHeader(hs, true); |
449 | if (cppName != headerName) |
450 | writeHeader(cs, false); |
451 | |
452 | // include guards: |
453 | QString includeGuard; |
454 | if (!headerName.isEmpty() && headerName != QLatin1String("-" )) { |
455 | includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_')); |
456 | int pos = includeGuard.lastIndexOf(QLatin1Char('/')); |
457 | if (pos != -1) |
458 | includeGuard = includeGuard.mid(pos + 1); |
459 | } else { |
460 | includeGuard = QLatin1String("QDBUSXML2CPP_PROXY" ); |
461 | } |
462 | includeGuard = QString(QLatin1String("%1" )) |
463 | .arg(includeGuard); |
464 | hs << "#ifndef " << includeGuard << Qt::endl |
465 | << "#define " << includeGuard << Qt::endl |
466 | << Qt::endl; |
467 | |
468 | // include our stuff: |
469 | hs << "#include <QtCore/QObject>" << Qt::endl |
470 | << includeList |
471 | << "#include <QtDBus/QtDBus>" << Qt::endl; |
472 | |
473 | for (const QString &include : qAsConst(includes)) { |
474 | hs << "#include \"" << include << "\"" << Qt::endl; |
475 | if (headerName.isEmpty()) |
476 | cs << "#include \"" << include << "\"" << Qt::endl; |
477 | } |
478 | |
479 | hs << Qt::endl; |
480 | |
481 | if (cppName != headerName) { |
482 | if (!headerName.isEmpty() && headerName != QLatin1String("-" )) |
483 | cs << "#include \"" << headerName << "\"" << Qt::endl << Qt::endl; |
484 | } |
485 | |
486 | for (const QDBusIntrospection::Interface *interface : interfaces) { |
487 | QString className = classNameForInterface(interface->name, Proxy); |
488 | |
489 | // comment: |
490 | hs << "/*" << Qt::endl |
491 | << " * Proxy class for interface " << interface->name << Qt::endl |
492 | << " */" << Qt::endl; |
493 | cs << "/*" << Qt::endl |
494 | << " * Implementation of interface class " << className << Qt::endl |
495 | << " */" << Qt::endl |
496 | << Qt::endl; |
497 | |
498 | // class header: |
499 | hs << "class " << className << ": public QDBusAbstractInterface" << Qt::endl |
500 | << "{" << Qt::endl |
501 | << " Q_OBJECT" << Qt::endl; |
502 | |
503 | // the interface name |
504 | hs << "public:" << Qt::endl |
505 | << " static inline const char *staticInterfaceName()" << Qt::endl |
506 | << " { return \"" << interface->name << "\"; }" << Qt::endl |
507 | << Qt::endl; |
508 | |
509 | // constructors/destructors: |
510 | hs << "public:" << Qt::endl |
511 | << " " << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);" << Qt::endl |
512 | << Qt::endl |
513 | << " ~" << className << "();" << Qt::endl |
514 | << Qt::endl; |
515 | cs << className << "::" << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)" << Qt::endl |
516 | << " : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)" << Qt::endl |
517 | << "{" << Qt::endl |
518 | << "}" << Qt::endl |
519 | << Qt::endl |
520 | << className << "::~" << className << "()" << Qt::endl |
521 | << "{" << Qt::endl |
522 | << "}" << Qt::endl |
523 | << Qt::endl; |
524 | |
525 | // properties: |
526 | for (const QDBusIntrospection::Property &property : interface->properties) { |
527 | QByteArray type = qtTypeName(property.type, property.annotations); |
528 | QString getter = propertyGetter(property); |
529 | QString setter = propertySetter(property); |
530 | |
531 | hs << " Q_PROPERTY(" << type << " " << property.name; |
532 | |
533 | // getter: |
534 | if (property.access != QDBusIntrospection::Property::Write) |
535 | // it's readble |
536 | hs << " READ " << getter; |
537 | |
538 | // setter |
539 | if (property.access != QDBusIntrospection::Property::Read) |
540 | // it's writeable |
541 | hs << " WRITE " << setter; |
542 | |
543 | hs << ")" << Qt::endl; |
544 | |
545 | // getter: |
546 | if (property.access != QDBusIntrospection::Property::Write) { |
547 | hs << " inline " << type << " " << getter << "() const" << Qt::endl |
548 | << " { return qvariant_cast< " << type << " >(property(\"" |
549 | << property.name << "\")); }" << Qt::endl; |
550 | } |
551 | |
552 | // setter: |
553 | if (property.access != QDBusIntrospection::Property::Read) { |
554 | hs << " inline void " << setter << "(" << constRefArg(type) << "value)" << Qt::endl |
555 | << " { setProperty(\"" << property.name |
556 | << "\", QVariant::fromValue(value)); }" << Qt::endl; |
557 | } |
558 | |
559 | hs << Qt::endl; |
560 | } |
561 | |
562 | // methods: |
563 | hs << "public Q_SLOTS: // METHODS" << Qt::endl; |
564 | for (const QDBusIntrospection::Method &method : interface->methods) { |
565 | bool isDeprecated = method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated" )) == QLatin1String("true" ); |
566 | bool isNoReply = |
567 | method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true" ); |
568 | if (isNoReply && !method.outputArgs.isEmpty()) { |
569 | fprintf(stderr, "%s: warning while processing '%s': method %s in interface %s is marked 'no-reply' but has output arguments.\n" , |
570 | PROGRAMNAME, qPrintable(inputFile), qPrintable(method.name), |
571 | qPrintable(interface->name)); |
572 | continue; |
573 | } |
574 | |
575 | hs << " inline " |
576 | << (isDeprecated ? "Q_DECL_DEPRECATED " : "" ); |
577 | |
578 | if (isNoReply) { |
579 | hs << "Q_NOREPLY void " ; |
580 | } else { |
581 | hs << "QDBusPendingReply<" ; |
582 | for (int i = 0; i < method.outputArgs.count(); ++i) |
583 | hs << (i > 0 ? ", " : "" ) |
584 | << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out" )); |
585 | hs << "> " ; |
586 | } |
587 | |
588 | hs << methodName(method) << "(" ; |
589 | |
590 | QStringList argNames = makeArgNames(method.inputArgs); |
591 | writeArgList(hs, argNames, method.annotations, method.inputArgs); |
592 | |
593 | hs << ")" << Qt::endl |
594 | << " {" << Qt::endl |
595 | << " QList<QVariant> argumentList;" << Qt::endl; |
596 | |
597 | if (!method.inputArgs.isEmpty()) { |
598 | hs << " argumentList" ; |
599 | for (int argPos = 0; argPos < method.inputArgs.count(); ++argPos) |
600 | hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')'; |
601 | hs << ";" << Qt::endl; |
602 | } |
603 | |
604 | if (isNoReply) |
605 | hs << " callWithArgumentList(QDBus::NoBlock, " |
606 | << "QStringLiteral(\"" << method.name << "\"), argumentList);" << Qt::endl; |
607 | else |
608 | hs << " return asyncCallWithArgumentList(QStringLiteral(\"" |
609 | << method.name << "\"), argumentList);" << Qt::endl; |
610 | |
611 | // close the function: |
612 | hs << " }" << Qt::endl; |
613 | |
614 | if (method.outputArgs.count() > 1) { |
615 | // generate the old-form QDBusReply methods with multiple incoming parameters |
616 | hs << " inline " |
617 | << (isDeprecated ? "Q_DECL_DEPRECATED " : "" ) |
618 | << "QDBusReply<" |
619 | << templateArg(qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out" )) << "> " ; |
620 | hs << method.name << "(" ; |
621 | |
622 | QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); |
623 | writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); |
624 | |
625 | hs << ")" << Qt::endl |
626 | << " {" << Qt::endl |
627 | << " QList<QVariant> argumentList;" << Qt::endl; |
628 | |
629 | int argPos = 0; |
630 | if (!method.inputArgs.isEmpty()) { |
631 | hs << " argumentList" ; |
632 | for (argPos = 0; argPos < method.inputArgs.count(); ++argPos) |
633 | hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')'; |
634 | hs << ";" << Qt::endl; |
635 | } |
636 | |
637 | hs << " QDBusMessage reply = callWithArgumentList(QDBus::Block, " |
638 | << "QStringLiteral(\"" << method.name << "\"), argumentList);" << Qt::endl; |
639 | |
640 | argPos++; |
641 | hs << " if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == " |
642 | << method.outputArgs.count() << ") {" << Qt::endl; |
643 | |
644 | // yes, starting from 1 |
645 | for (int i = 1; i < method.outputArgs.count(); ++i) |
646 | hs << " " << argNames.at(argPos++) << " = qdbus_cast<" |
647 | << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out" )) |
648 | << ">(reply.arguments().at(" << i << "));" << Qt::endl; |
649 | hs << " }" << Qt::endl |
650 | << " return reply;" << Qt::endl |
651 | << " }" << Qt::endl; |
652 | } |
653 | |
654 | hs << Qt::endl; |
655 | } |
656 | |
657 | hs << "Q_SIGNALS: // SIGNALS" << Qt::endl; |
658 | for (const QDBusIntrospection::Signal &signal : interface->signals_) { |
659 | hs << " " ; |
660 | if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated" )) == |
661 | QLatin1String("true" )) |
662 | hs << "Q_DECL_DEPRECATED " ; |
663 | |
664 | hs << "void " << signal.name << "(" ; |
665 | |
666 | QStringList argNames = makeArgNames(signal.outputArgs); |
667 | writeSignalArgList(hs, argNames, signal.annotations, signal.outputArgs); |
668 | |
669 | hs << ");" << Qt::endl; // finished for header |
670 | } |
671 | |
672 | // close the class: |
673 | hs << "};" << Qt::endl |
674 | << Qt::endl; |
675 | } |
676 | |
677 | if (!skipNamespaces) { |
678 | QStringList last; |
679 | QDBusIntrospection::Interfaces::ConstIterator it = interfaces.constBegin(); |
680 | do |
681 | { |
682 | QStringList current; |
683 | QString name; |
684 | if (it != interfaces.constEnd()) { |
685 | current = it->constData()->name.split(QLatin1Char('.')); |
686 | name = current.takeLast(); |
687 | } |
688 | |
689 | int i = 0; |
690 | while (i < current.count() && i < last.count() && current.at(i) == last.at(i)) |
691 | ++i; |
692 | |
693 | // i parts matched |
694 | // close last.arguments().count() - i namespaces: |
695 | for (int j = i; j < last.count(); ++j) |
696 | hs << QString((last.count() - j - 1 + i) * 2, QLatin1Char(' ')) << "}" << Qt::endl; |
697 | |
698 | // open current.arguments().count() - i namespaces |
699 | for (int j = i; j < current.count(); ++j) |
700 | hs << QString(j * 2, QLatin1Char(' ')) << "namespace " << current.at(j) << " {" << Qt::endl; |
701 | |
702 | // add this class: |
703 | if (!name.isEmpty()) { |
704 | hs << QString(current.count() * 2, QLatin1Char(' ')) |
705 | << "typedef ::" << classNameForInterface(it->constData()->name, Proxy) |
706 | << " " << name << ";" << Qt::endl; |
707 | } |
708 | |
709 | if (it == interfaces.constEnd()) |
710 | break; |
711 | ++it; |
712 | last = current; |
713 | } while (true); |
714 | } |
715 | |
716 | // close the include guard |
717 | hs << "#endif" << Qt::endl; |
718 | |
719 | QString mocName = moc(filename); |
720 | if (includeMocs && !mocName.isEmpty()) |
721 | cs << Qt::endl |
722 | << "#include \"" << mocName << "\"" << Qt::endl; |
723 | |
724 | cs.flush(); |
725 | hs.flush(); |
726 | |
727 | QFile file; |
728 | const bool = openFile(headerName, file); |
729 | if (headerOpen) |
730 | file.write(headerData); |
731 | |
732 | if (headerName == cppName) { |
733 | if (headerOpen) |
734 | file.write(cppData); |
735 | } else { |
736 | QFile cppFile; |
737 | if (openFile(cppName, cppFile)) |
738 | cppFile.write(cppData); |
739 | } |
740 | } |
741 | |
742 | static void writeAdaptor(const QString &filename, const QDBusIntrospection::Interfaces &interfaces) |
743 | { |
744 | // open the file |
745 | QString = header(filename); |
746 | QByteArray ; |
747 | QTextStream hs(&headerData); |
748 | |
749 | QString cppName = cpp(filename); |
750 | QByteArray cppData; |
751 | QTextStream cs(&cppData); |
752 | |
753 | // write the headers |
754 | writeHeader(hs, false); |
755 | if (cppName != headerName) |
756 | writeHeader(cs, true); |
757 | |
758 | // include guards: |
759 | QString includeGuard; |
760 | if (!headerName.isEmpty() && headerName != QLatin1String("-" )) { |
761 | includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_')); |
762 | int pos = includeGuard.lastIndexOf(QLatin1Char('/')); |
763 | if (pos != -1) |
764 | includeGuard = includeGuard.mid(pos + 1); |
765 | } else { |
766 | includeGuard = QLatin1String("QDBUSXML2CPP_ADAPTOR" ); |
767 | } |
768 | includeGuard = QString(QLatin1String("%1" )) |
769 | .arg(includeGuard); |
770 | hs << "#ifndef " << includeGuard << Qt::endl |
771 | << "#define " << includeGuard << Qt::endl |
772 | << Qt::endl; |
773 | |
774 | // include our stuff: |
775 | hs << "#include <QtCore/QObject>" << Qt::endl; |
776 | if (cppName == headerName) |
777 | hs << "#include <QtCore/QMetaObject>" << Qt::endl |
778 | << "#include <QtCore/QVariant>" << Qt::endl; |
779 | hs << "#include <QtDBus/QtDBus>" << Qt::endl; |
780 | |
781 | for (const QString &include : qAsConst(includes)) { |
782 | hs << "#include \"" << include << "\"" << Qt::endl; |
783 | if (headerName.isEmpty()) |
784 | cs << "#include \"" << include << "\"" << Qt::endl; |
785 | } |
786 | |
787 | if (cppName != headerName) { |
788 | if (!headerName.isEmpty() && headerName != QLatin1String("-" )) |
789 | cs << "#include \"" << headerName << "\"" << Qt::endl; |
790 | |
791 | cs << "#include <QtCore/QMetaObject>" << Qt::endl |
792 | << includeList |
793 | << Qt::endl; |
794 | hs << forwardDeclarations; |
795 | } else { |
796 | hs << includeList; |
797 | } |
798 | |
799 | hs << Qt::endl; |
800 | |
801 | QString parent = parentClassName; |
802 | if (parentClassName.isEmpty()) |
803 | parent = QLatin1String("QObject" ); |
804 | |
805 | for (const QDBusIntrospection::Interface *interface : interfaces) { |
806 | QString className = classNameForInterface(interface->name, Adaptor); |
807 | |
808 | // comment: |
809 | hs << "/*" << Qt::endl |
810 | << " * Adaptor class for interface " << interface->name << Qt::endl |
811 | << " */" << Qt::endl; |
812 | cs << "/*" << Qt::endl |
813 | << " * Implementation of adaptor class " << className << Qt::endl |
814 | << " */" << Qt::endl |
815 | << Qt::endl; |
816 | |
817 | // class header: |
818 | hs << "class " << className << ": public QDBusAbstractAdaptor" << Qt::endl |
819 | << "{" << Qt::endl |
820 | << " Q_OBJECT" << Qt::endl |
821 | << " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface->name << "\")" << Qt::endl |
822 | << " Q_CLASSINFO(\"D-Bus Introspection\", \"\"" << Qt::endl |
823 | << stringify(interface->introspection) |
824 | << " \"\")" << Qt::endl |
825 | << "public:" << Qt::endl |
826 | << " " << className << "(" << parent << " *parent);" << Qt::endl |
827 | << " virtual ~" << className << "();" << Qt::endl |
828 | << Qt::endl; |
829 | |
830 | if (!parentClassName.isEmpty()) |
831 | hs << " inline " << parent << " *parent() const" << Qt::endl |
832 | << " { return static_cast<" << parent << " *>(QObject::parent()); }" << Qt::endl |
833 | << Qt::endl; |
834 | |
835 | // constructor/destructor |
836 | cs << className << "::" << className << "(" << parent << " *parent)" << Qt::endl |
837 | << " : QDBusAbstractAdaptor(parent)" << Qt::endl |
838 | << "{" << Qt::endl |
839 | << " // constructor" << Qt::endl |
840 | << " setAutoRelaySignals(true);" << Qt::endl |
841 | << "}" << Qt::endl |
842 | << Qt::endl |
843 | << className << "::~" << className << "()" << Qt::endl |
844 | << "{" << Qt::endl |
845 | << " // destructor" << Qt::endl |
846 | << "}" << Qt::endl |
847 | << Qt::endl; |
848 | |
849 | hs << "public: // PROPERTIES" << Qt::endl; |
850 | for (const QDBusIntrospection::Property &property : interface->properties) { |
851 | QByteArray type = qtTypeName(property.type, property.annotations); |
852 | QString constRefType = constRefArg(type); |
853 | QString getter = propertyGetter(property); |
854 | QString setter = propertySetter(property); |
855 | |
856 | hs << " Q_PROPERTY(" << type << " " << property.name; |
857 | if (property.access != QDBusIntrospection::Property::Write) |
858 | hs << " READ " << getter; |
859 | if (property.access != QDBusIntrospection::Property::Read) |
860 | hs << " WRITE " << setter; |
861 | hs << ")" << Qt::endl; |
862 | |
863 | // getter: |
864 | if (property.access != QDBusIntrospection::Property::Write) { |
865 | hs << " " << type << " " << getter << "() const;" << Qt::endl; |
866 | cs << type << " " |
867 | << className << "::" << getter << "() const" << Qt::endl |
868 | << "{" << Qt::endl |
869 | << " // get the value of property " << property.name << Qt::endl |
870 | << " return qvariant_cast< " << type <<" >(parent()->property(\"" << property.name << "\"));" << Qt::endl |
871 | << "}" << Qt::endl |
872 | << Qt::endl; |
873 | } |
874 | |
875 | // setter |
876 | if (property.access != QDBusIntrospection::Property::Read) { |
877 | hs << " void " << setter << "(" << constRefType << "value);" << Qt::endl; |
878 | cs << "void " << className << "::" << setter << "(" << constRefType << "value)" << Qt::endl |
879 | << "{" << Qt::endl |
880 | << " // set the value of property " << property.name << Qt::endl |
881 | << " parent()->setProperty(\"" << property.name << "\", QVariant::fromValue(value" ; |
882 | if (constRefType.contains(QLatin1String("QDBusVariant" ))) |
883 | cs << ".variant()" ; |
884 | cs << "));" << Qt::endl |
885 | << "}" << Qt::endl |
886 | << Qt::endl; |
887 | } |
888 | |
889 | hs << Qt::endl; |
890 | } |
891 | |
892 | hs << "public Q_SLOTS: // METHODS" << Qt::endl; |
893 | for (const QDBusIntrospection::Method &method : interface->methods) { |
894 | bool isNoReply = |
895 | method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true" ); |
896 | if (isNoReply && !method.outputArgs.isEmpty()) { |
897 | fprintf(stderr, "%s: warning while processing '%s': method %s in interface %s is marked 'no-reply' but has output arguments.\n" , |
898 | PROGRAMNAME, qPrintable(inputFile), qPrintable(method.name), qPrintable(interface->name)); |
899 | continue; |
900 | } |
901 | |
902 | hs << " " ; |
903 | if (method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated" )) == |
904 | QLatin1String("true" )) |
905 | hs << "Q_DECL_DEPRECATED " ; |
906 | |
907 | QByteArray returnType; |
908 | if (isNoReply) { |
909 | hs << "Q_NOREPLY void " ; |
910 | cs << "void " ; |
911 | } else if (method.outputArgs.isEmpty()) { |
912 | hs << "void " ; |
913 | cs << "void " ; |
914 | } else { |
915 | returnType = qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out" ); |
916 | hs << returnType << " " ; |
917 | cs << returnType << " " ; |
918 | } |
919 | |
920 | QString name = methodName(method); |
921 | hs << name << "(" ; |
922 | cs << className << "::" << name << "(" ; |
923 | |
924 | QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); |
925 | writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); |
926 | writeArgList(cs, argNames, method.annotations, method.inputArgs, method.outputArgs); |
927 | |
928 | hs << ");" << Qt::endl; // finished for header |
929 | cs << ")" << Qt::endl |
930 | << "{" << Qt::endl |
931 | << " // handle method call " << interface->name << "." << methodName(method) << Qt::endl; |
932 | |
933 | // make the call |
934 | bool usingInvokeMethod = false; |
935 | if (parentClassName.isEmpty() && method.inputArgs.count() <= 10 |
936 | && method.outputArgs.count() <= 1) |
937 | usingInvokeMethod = true; |
938 | |
939 | if (usingInvokeMethod) { |
940 | // we are using QMetaObject::invokeMethod |
941 | if (!returnType.isEmpty()) |
942 | cs << " " << returnType << " " << argNames.at(method.inputArgs.count()) |
943 | << ";" << Qt::endl; |
944 | |
945 | static const char invoke[] = " QMetaObject::invokeMethod(parent(), \"" ; |
946 | cs << invoke << name << "\"" ; |
947 | |
948 | if (!method.outputArgs.isEmpty()) |
949 | cs << ", Q_RETURN_ARG(" |
950 | << qtTypeName(method.outputArgs.at(0).type, method.annotations, |
951 | 0, "Out" ) |
952 | << ", " |
953 | << argNames.at(method.inputArgs.count()) |
954 | << ")" ; |
955 | |
956 | for (int i = 0; i < method.inputArgs.count(); ++i) |
957 | cs << ", Q_ARG(" |
958 | << qtTypeName(method.inputArgs.at(i).type, method.annotations, |
959 | i, "In" ) |
960 | << ", " |
961 | << argNames.at(i) |
962 | << ")" ; |
963 | |
964 | cs << ");" << Qt::endl; |
965 | |
966 | if (!returnType.isEmpty()) |
967 | cs << " return " << argNames.at(method.inputArgs.count()) << ";" << Qt::endl; |
968 | } else { |
969 | if (parentClassName.isEmpty()) |
970 | cs << " //" ; |
971 | else |
972 | cs << " " ; |
973 | |
974 | if (!method.outputArgs.isEmpty()) |
975 | cs << "return " ; |
976 | |
977 | if (parentClassName.isEmpty()) |
978 | cs << "static_cast<YourObjectType *>(parent())->" ; |
979 | else |
980 | cs << "parent()->" ; |
981 | cs << name << "(" ; |
982 | |
983 | int argPos = 0; |
984 | bool first = true; |
985 | for (int i = 0; i < method.inputArgs.count(); ++i) { |
986 | cs << (first ? "" : ", " ) << argNames.at(argPos++); |
987 | first = false; |
988 | } |
989 | ++argPos; // skip retval, if any |
990 | for (int i = 1; i < method.outputArgs.count(); ++i) { |
991 | cs << (first ? "" : ", " ) << argNames.at(argPos++); |
992 | first = false; |
993 | } |
994 | |
995 | cs << ");" << Qt::endl; |
996 | } |
997 | cs << "}" << Qt::endl |
998 | << Qt::endl; |
999 | } |
1000 | |
1001 | hs << "Q_SIGNALS: // SIGNALS" << Qt::endl; |
1002 | for (const QDBusIntrospection::Signal &signal : interface->signals_) { |
1003 | hs << " " ; |
1004 | if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated" )) == |
1005 | QLatin1String("true" )) |
1006 | hs << "Q_DECL_DEPRECATED " ; |
1007 | |
1008 | hs << "void " << signal.name << "(" ; |
1009 | |
1010 | QStringList argNames = makeArgNames(signal.outputArgs); |
1011 | writeSignalArgList(hs, argNames, signal.annotations, signal.outputArgs); |
1012 | |
1013 | hs << ");" << Qt::endl; // finished for header |
1014 | } |
1015 | |
1016 | // close the class: |
1017 | hs << "};" << Qt::endl |
1018 | << Qt::endl; |
1019 | } |
1020 | |
1021 | // close the include guard |
1022 | hs << "#endif" << Qt::endl; |
1023 | |
1024 | QString mocName = moc(filename); |
1025 | if (includeMocs && !mocName.isEmpty()) |
1026 | cs << Qt::endl |
1027 | << "#include \"" << mocName << "\"" << Qt::endl; |
1028 | |
1029 | cs.flush(); |
1030 | hs.flush(); |
1031 | |
1032 | QFile file; |
1033 | const bool = openFile(headerName, file); |
1034 | if (headerOpen) |
1035 | file.write(headerData); |
1036 | |
1037 | if (headerName == cppName) { |
1038 | if (headerOpen) |
1039 | file.write(cppData); |
1040 | } else { |
1041 | QFile cppFile; |
1042 | if (openFile(cppName, cppFile)) |
1043 | cppFile.write(cppData); |
1044 | } |
1045 | } |
1046 | |
1047 | int main(int argc, char **argv) |
1048 | { |
1049 | QCoreApplication app(argc, argv); |
1050 | QCoreApplication::setApplicationName(QStringLiteral(PROGRAMNAME)); |
1051 | QCoreApplication::setApplicationVersion(QStringLiteral(PROGRAMVERSION)); |
1052 | |
1053 | QCommandLineParser parser; |
1054 | parser.setApplicationDescription(QLatin1String( |
1055 | "Produces the C++ code to implement the interfaces defined in the input file.\n\n" |
1056 | "If the file name given to the options -a and -p does not end in .cpp or .h, the\n" |
1057 | "program will automatically append the suffixes and produce both files.\n" |
1058 | "You can also use a colon (:) to separate the header name from the source file\n" |
1059 | "name, as in '-a filename_p.h:filename.cpp'.\n\n" |
1060 | "If you pass a dash (-) as the argument to either -p or -a, the output is written\n" |
1061 | "to the standard output." )); |
1062 | |
1063 | parser.addHelpOption(); |
1064 | parser.addVersionOption(); |
1065 | parser.addPositionalArgument(QStringLiteral("xml-or-xml-file" ), QStringLiteral("XML file to use." )); |
1066 | parser.addPositionalArgument(QStringLiteral("interfaces" ), QStringLiteral("List of interfaces to use." ), |
1067 | QStringLiteral("[interfaces ...]" )); |
1068 | |
1069 | QCommandLineOption adapterCodeOption(QStringList() << QStringLiteral("a" ) << QStringLiteral("adaptor" ), |
1070 | QStringLiteral("Write the adaptor code to <filename>" ), QStringLiteral("filename" )); |
1071 | parser.addOption(adapterCodeOption); |
1072 | |
1073 | QCommandLineOption classNameOption(QStringList() << QStringLiteral("c" ) << QStringLiteral("classname" ), |
1074 | QStringLiteral("Use <classname> as the class name for the generated classes" ), QStringLiteral("classname" )); |
1075 | parser.addOption(classNameOption); |
1076 | |
1077 | QCommandLineOption addIncludeOption(QStringList() << QStringLiteral("i" ) << QStringLiteral("include" ), |
1078 | QStringLiteral("Add #include to the output" ), QStringLiteral("filename" )); |
1079 | parser.addOption(addIncludeOption); |
1080 | |
1081 | QCommandLineOption adapterParentOption(QStringLiteral("l" ), |
1082 | QStringLiteral("When generating an adaptor, use <classname> as the parent class" ), QStringLiteral("classname" )); |
1083 | parser.addOption(adapterParentOption); |
1084 | |
1085 | QCommandLineOption mocIncludeOption(QStringList() << QStringLiteral("m" ) << QStringLiteral("moc" ), |
1086 | QStringLiteral("Generate #include \"filename.moc\" statements in the .cpp files" )); |
1087 | parser.addOption(mocIncludeOption); |
1088 | |
1089 | QCommandLineOption noNamespaceOption(QStringList() << QStringLiteral("N" ) << QStringLiteral("no-namespaces" ), |
1090 | QStringLiteral("Don't use namespaces" )); |
1091 | parser.addOption(noNamespaceOption); |
1092 | |
1093 | QCommandLineOption proxyCodeOption(QStringList() << QStringLiteral("p" ) << QStringLiteral("proxy" ), |
1094 | QStringLiteral("Write the proxy code to <filename>" ), QStringLiteral("filename" )); |
1095 | parser.addOption(proxyCodeOption); |
1096 | |
1097 | QCommandLineOption verboseOption(QStringList() << QStringLiteral("V" ) << QStringLiteral("verbose" ), |
1098 | QStringLiteral("Be verbose." )); |
1099 | parser.addOption(verboseOption); |
1100 | |
1101 | parser.process(app); |
1102 | |
1103 | adaptorFile = parser.value(adapterCodeOption); |
1104 | globalClassName = parser.value(classNameOption); |
1105 | includes = parser.values(addIncludeOption); |
1106 | parentClassName = parser.value(adapterParentOption); |
1107 | includeMocs = parser.isSet(mocIncludeOption); |
1108 | skipNamespaces = parser.isSet(noNamespaceOption); |
1109 | proxyFile = parser.value(proxyCodeOption); |
1110 | verbose = parser.isSet(verboseOption); |
1111 | |
1112 | wantedInterfaces = parser.positionalArguments(); |
1113 | if (!wantedInterfaces.isEmpty()) { |
1114 | inputFile = wantedInterfaces.takeFirst(); |
1115 | |
1116 | QFileInfo inputInfo(inputFile); |
1117 | if (!inputInfo.exists() || !inputInfo.isFile() || !inputInfo.isReadable()) { |
1118 | qCritical("Error: Input %s is not a file or cannot be accessed\n" , qPrintable(inputFile)); |
1119 | return 1; |
1120 | } |
1121 | } |
1122 | |
1123 | if (verbose) |
1124 | QLoggingCategory::setFilterRules(QStringLiteral("dbus.parser.debug=true" )); |
1125 | |
1126 | QDBusIntrospection::Interfaces interfaces = readInput(); |
1127 | cleanInterfaces(interfaces); |
1128 | |
1129 | QStringList args = app.arguments(); |
1130 | args.removeFirst(); |
1131 | commandLine = QLatin1String(PROGRAMNAME " " ); |
1132 | commandLine += args.join(QLatin1Char(' ')); |
1133 | |
1134 | if (!proxyFile.isEmpty() || adaptorFile.isEmpty()) |
1135 | writeProxy(proxyFile, interfaces); |
1136 | |
1137 | if (!adaptorFile.isEmpty()) |
1138 | writeAdaptor(adaptorFile, interfaces); |
1139 | |
1140 | return 0; |
1141 | } |
1142 | |
1143 | |