0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 |
** All rights reserved.
|
|
5 |
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
6 |
**
|
|
7 |
** This file is part of the tools applications of the Qt Toolkit.
|
|
8 |
**
|
|
9 |
** $QT_BEGIN_LICENSE:LGPL$
|
|
10 |
** No Commercial Usage
|
|
11 |
** This file contains pre-release code and may not be distributed.
|
|
12 |
** You may use this file in accordance with the terms and conditions
|
|
13 |
** contained in the Technology Preview License Agreement accompanying
|
|
14 |
** this package.
|
|
15 |
**
|
|
16 |
** GNU Lesser General Public License Usage
|
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
18 |
** General Public License version 2.1 as published by the Free Software
|
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
20 |
** packaging of this file. Please review the following information to
|
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
23 |
**
|
|
24 |
** In addition, as a special exception, Nokia gives you certain additional
|
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
27 |
**
|
|
28 |
** If you have questions regarding the use of this file, please contact
|
|
29 |
** Nokia at qt-info@nokia.com.
|
|
30 |
**
|
|
31 |
**
|
|
32 |
**
|
|
33 |
**
|
|
34 |
**
|
|
35 |
**
|
|
36 |
**
|
|
37 |
**
|
|
38 |
** $QT_END_LICENSE$
|
|
39 |
**
|
|
40 |
****************************************************************************/
|
|
41 |
|
|
42 |
#include "generator.h"
|
|
43 |
#include "outputrevision.h"
|
|
44 |
#include "utils.h"
|
|
45 |
#include <QtCore/qmetatype.h>
|
|
46 |
#include <stdio.h>
|
|
47 |
|
|
48 |
#include <private/qmetaobject_p.h> //for the flags.
|
|
49 |
|
|
50 |
QT_BEGIN_NAMESPACE
|
|
51 |
|
|
52 |
uint qvariant_nameToType(const char* name)
|
|
53 |
{
|
|
54 |
if (!name)
|
|
55 |
return 0;
|
|
56 |
|
|
57 |
if (strcmp(name, "QVariant") == 0)
|
|
58 |
return 0xffffffff;
|
|
59 |
if (strcmp(name, "QCString") == 0)
|
|
60 |
return QMetaType::QByteArray;
|
|
61 |
if (strcmp(name, "Q_LLONG") == 0)
|
|
62 |
return QMetaType::LongLong;
|
|
63 |
if (strcmp(name, "Q_ULLONG") == 0)
|
|
64 |
return QMetaType::ULongLong;
|
|
65 |
if (strcmp(name, "QIconSet") == 0)
|
|
66 |
return QMetaType::QIcon;
|
|
67 |
|
|
68 |
uint tp = QMetaType::type(name);
|
|
69 |
return tp < QMetaType::User ? tp : 0;
|
|
70 |
}
|
|
71 |
|
|
72 |
/*
|
|
73 |
Returns true if the type is a QVariant types.
|
|
74 |
*/
|
|
75 |
bool isVariantType(const char* type)
|
|
76 |
{
|
|
77 |
return qvariant_nameToType(type) != 0;
|
|
78 |
}
|
|
79 |
|
|
80 |
/*!
|
|
81 |
Returns true if the type is qreal.
|
|
82 |
*/
|
|
83 |
static bool isQRealType(const char *type)
|
|
84 |
{
|
|
85 |
return strcmp(type, "qreal") == 0;
|
|
86 |
}
|
|
87 |
|
|
88 |
Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile)
|
|
89 |
: out(outfile), cdef(classDef), metaTypes(metaTypes)
|
|
90 |
{
|
|
91 |
if (cdef->superclassList.size())
|
|
92 |
purestSuperClass = cdef->superclassList.first().first;
|
|
93 |
}
|
|
94 |
|
|
95 |
static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
|
|
96 |
{
|
|
97 |
if (s.at(i) != '\\' || i >= s.length() - 1)
|
|
98 |
return 1;
|
|
99 |
const int startPos = i;
|
|
100 |
++i;
|
|
101 |
char ch = s.at(i);
|
|
102 |
if (ch == 'x') {
|
|
103 |
++i;
|
|
104 |
while (i < s.length() && is_hex_char(s.at(i)))
|
|
105 |
++i;
|
|
106 |
} else if (is_octal_char(ch)) {
|
|
107 |
while (i < startPos + 4
|
|
108 |
&& i < s.length()
|
|
109 |
&& is_octal_char(s.at(i))) {
|
|
110 |
++i;
|
|
111 |
}
|
|
112 |
} else { // single character escape sequence
|
|
113 |
i = qMin(i + 1, s.length());
|
|
114 |
}
|
|
115 |
return i - startPos;
|
|
116 |
}
|
|
117 |
|
|
118 |
int Generator::strreg(const char *s)
|
|
119 |
{
|
|
120 |
int idx = 0;
|
|
121 |
if (!s)
|
|
122 |
s = "";
|
|
123 |
for (int i = 0; i < strings.size(); ++i) {
|
|
124 |
const QByteArray &str = strings.at(i);
|
|
125 |
if (str == s)
|
|
126 |
return idx;
|
|
127 |
idx += str.length() + 1;
|
|
128 |
for (int i = 0; i < str.length(); ++i) {
|
|
129 |
if (str.at(i) == '\\') {
|
|
130 |
int cnt = lengthOfEscapeSequence(str, i) - 1;
|
|
131 |
idx -= cnt;
|
|
132 |
i += cnt;
|
|
133 |
}
|
|
134 |
}
|
|
135 |
}
|
|
136 |
strings.append(s);
|
|
137 |
return idx;
|
|
138 |
}
|
|
139 |
|
|
140 |
void Generator::generateCode()
|
|
141 |
{
|
|
142 |
bool isQt = (cdef->classname == "Qt");
|
|
143 |
bool isQObject = (cdef->classname == "QObject");
|
|
144 |
bool isConstructible = !cdef->constructorList.isEmpty();
|
|
145 |
|
|
146 |
//
|
|
147 |
// build the data array
|
|
148 |
//
|
|
149 |
int i = 0;
|
|
150 |
|
|
151 |
|
|
152 |
// filter out undeclared enumerators and sets
|
|
153 |
{
|
|
154 |
QList<EnumDef> enumList;
|
|
155 |
for (i = 0; i < cdef->enumList.count(); ++i) {
|
|
156 |
EnumDef def = cdef->enumList.at(i);
|
|
157 |
if (cdef->enumDeclarations.contains(def.name)) {
|
|
158 |
enumList += def;
|
|
159 |
}
|
|
160 |
QByteArray alias = cdef->flagAliases.value(def.name);
|
|
161 |
if (cdef->enumDeclarations.contains(alias)) {
|
|
162 |
def.name = alias;
|
|
163 |
enumList += def;
|
|
164 |
}
|
|
165 |
}
|
|
166 |
cdef->enumList = enumList;
|
|
167 |
}
|
|
168 |
|
|
169 |
|
|
170 |
QByteArray qualifiedClassNameIdentifier = cdef->qualified;
|
|
171 |
qualifiedClassNameIdentifier.replace(':', '_');
|
|
172 |
|
|
173 |
int index = 14;
|
|
174 |
fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
|
|
175 |
fprintf(out, "\n // content:\n");
|
|
176 |
fprintf(out, " %4d, // revision\n", 4);
|
|
177 |
fprintf(out, " %4d, // classname\n", strreg(cdef->qualified));
|
|
178 |
fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
|
|
179 |
index += cdef->classInfoList.count() * 2;
|
|
180 |
|
|
181 |
int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count();
|
|
182 |
fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0);
|
|
183 |
index += methodCount * 5;
|
|
184 |
fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0);
|
|
185 |
index += cdef->propertyList.count() * 3;
|
|
186 |
if(cdef->notifyableProperties)
|
|
187 |
index += cdef->propertyList.count();
|
|
188 |
fprintf(out, " %4d, %4d, // enums/sets\n", cdef->enumList.count(), cdef->enumList.count() ? index : 0);
|
|
189 |
|
|
190 |
int enumsIndex = index;
|
|
191 |
for (i = 0; i < cdef->enumList.count(); ++i)
|
|
192 |
index += 4 + (cdef->enumList.at(i).values.count() * 2);
|
|
193 |
fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? cdef->constructorList.count() : 0,
|
|
194 |
isConstructible ? index : 0);
|
|
195 |
|
|
196 |
fprintf(out, " %4d, // flags\n", 0);
|
|
197 |
fprintf(out, " %4d, // signalCount\n", cdef->signalList.count());
|
|
198 |
|
|
199 |
|
|
200 |
//
|
|
201 |
// Build classinfo array
|
|
202 |
//
|
|
203 |
generateClassInfos();
|
|
204 |
|
|
205 |
//
|
|
206 |
// Build signals array first, otherwise the signal indices would be wrong
|
|
207 |
//
|
|
208 |
generateFunctions(cdef->signalList, "signal", MethodSignal);
|
|
209 |
|
|
210 |
//
|
|
211 |
// Build slots array
|
|
212 |
//
|
|
213 |
generateFunctions(cdef->slotList, "slot", MethodSlot);
|
|
214 |
|
|
215 |
//
|
|
216 |
// Build method array
|
|
217 |
//
|
|
218 |
generateFunctions(cdef->methodList, "method", MethodMethod);
|
|
219 |
|
|
220 |
|
|
221 |
//
|
|
222 |
// Build property array
|
|
223 |
//
|
|
224 |
generateProperties();
|
|
225 |
|
|
226 |
//
|
|
227 |
// Build enums array
|
|
228 |
//
|
|
229 |
generateEnums(enumsIndex);
|
|
230 |
|
|
231 |
//
|
|
232 |
// Build constructors array
|
|
233 |
//
|
|
234 |
if (isConstructible)
|
|
235 |
generateFunctions(cdef->constructorList, "constructor", MethodConstructor);
|
|
236 |
|
|
237 |
//
|
|
238 |
// Terminate data array
|
|
239 |
//
|
|
240 |
fprintf(out, "\n 0 // eod\n};\n\n");
|
|
241 |
|
|
242 |
//
|
|
243 |
// Build stringdata array
|
|
244 |
//
|
|
245 |
fprintf(out, "static const char qt_meta_stringdata_%s[] = {\n", qualifiedClassNameIdentifier.constData());
|
|
246 |
fprintf(out, " \"");
|
|
247 |
int col = 0;
|
|
248 |
int len = 0;
|
|
249 |
for (i = 0; i < strings.size(); ++i) {
|
|
250 |
QByteArray s = strings.at(i);
|
|
251 |
len = s.length();
|
|
252 |
if (col && col + len >= 72) {
|
|
253 |
fprintf(out, "\"\n \"");
|
|
254 |
col = 0;
|
|
255 |
} else if (len && s.at(0) >= '0' && s.at(0) <= '9') {
|
|
256 |
fprintf(out, "\"\"");
|
|
257 |
len += 2;
|
|
258 |
}
|
|
259 |
int idx = 0;
|
|
260 |
while (idx < s.length()) {
|
|
261 |
if (idx > 0) {
|
|
262 |
col = 0;
|
|
263 |
fprintf(out, "\"\n \"");
|
|
264 |
}
|
|
265 |
int spanLen = qMin(70, s.length() - idx);
|
|
266 |
// don't cut escape sequences at the end of a line
|
|
267 |
int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
|
|
268 |
if (backSlashPos >= idx) {
|
|
269 |
int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
|
|
270 |
spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx);
|
|
271 |
}
|
|
272 |
fwrite(s.constData() + idx, 1, spanLen, out);
|
|
273 |
idx += spanLen;
|
|
274 |
col += spanLen;
|
|
275 |
}
|
|
276 |
|
|
277 |
fputs("\\0", out);
|
|
278 |
col += len + 2;
|
|
279 |
}
|
|
280 |
fprintf(out, "\"\n};\n\n");
|
|
281 |
|
|
282 |
|
|
283 |
//
|
|
284 |
// Generate internal qt_static_metacall() function
|
|
285 |
//
|
|
286 |
if (isConstructible)
|
|
287 |
generateStaticMetacall(qualifiedClassNameIdentifier);
|
|
288 |
|
|
289 |
//
|
|
290 |
// Build extra array
|
|
291 |
//
|
|
292 |
QList<QByteArray> extraList;
|
|
293 |
for (int i = 0; i < cdef->propertyList.count(); ++i) {
|
|
294 |
const PropertyDef &p = cdef->propertyList.at(i);
|
|
295 |
if (!isVariantType(p.type) && !metaTypes.contains(p.type)) {
|
|
296 |
int s = p.type.lastIndexOf("::");
|
|
297 |
if (s > 0) {
|
|
298 |
QByteArray scope = p.type.left(s);
|
|
299 |
if (scope != "Qt" && scope != cdef->classname && !extraList.contains(scope))
|
|
300 |
extraList += scope;
|
|
301 |
}
|
|
302 |
}
|
|
303 |
}
|
|
304 |
if (!extraList.isEmpty()) {
|
|
305 |
fprintf(out, "#ifdef Q_NO_DATA_RELOCATION\n");
|
|
306 |
fprintf(out, "static const QMetaObjectAccessor qt_meta_extradata_%s[] = {\n ", qualifiedClassNameIdentifier.constData());
|
|
307 |
for (int i = 0; i < extraList.count(); ++i) {
|
|
308 |
fprintf(out, " %s::getStaticMetaObject,\n", extraList.at(i).constData());
|
|
309 |
}
|
|
310 |
fprintf(out, "#else\n");
|
|
311 |
fprintf(out, "static const QMetaObject *qt_meta_extradata_%s[] = {\n ", qualifiedClassNameIdentifier.constData());
|
|
312 |
for (int i = 0; i < extraList.count(); ++i) {
|
|
313 |
fprintf(out, " &%s::staticMetaObject,\n", extraList.at(i).constData());
|
|
314 |
}
|
|
315 |
fprintf(out, "#endif //Q_NO_DATA_RELOCATION\n");
|
|
316 |
fprintf(out, " 0\n};\n\n");
|
|
317 |
}
|
|
318 |
|
|
319 |
if (isConstructible || !extraList.isEmpty()) {
|
|
320 |
fprintf(out, "static const QMetaObjectExtraData qt_meta_extradata2_%s = {\n ",
|
|
321 |
qualifiedClassNameIdentifier.constData());
|
|
322 |
if (extraList.isEmpty())
|
|
323 |
fprintf(out, "0, ");
|
|
324 |
else
|
|
325 |
fprintf(out, "qt_meta_extradata_%s, ", qualifiedClassNameIdentifier.constData());
|
|
326 |
if (!isConstructible)
|
|
327 |
fprintf(out, "0");
|
|
328 |
else
|
|
329 |
fprintf(out, "%s_qt_static_metacall", qualifiedClassNameIdentifier.constData());
|
|
330 |
fprintf(out, " \n};\n\n");
|
|
331 |
}
|
|
332 |
|
|
333 |
//
|
|
334 |
// Finally create and initialize the static meta object
|
|
335 |
//
|
|
336 |
if (isQt)
|
|
337 |
fprintf(out, "const QMetaObject QObject::staticQtMetaObject = {\n");
|
|
338 |
else
|
|
339 |
fprintf(out, "const QMetaObject %s::staticMetaObject = {\n", cdef->qualified.constData());
|
|
340 |
|
|
341 |
if (isQObject)
|
|
342 |
fprintf(out, " { 0, ");
|
|
343 |
else if (cdef->superclassList.size())
|
|
344 |
fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData());
|
|
345 |
else
|
|
346 |
fprintf(out, " { 0, ");
|
|
347 |
fprintf(out, "qt_meta_stringdata_%s,\n qt_meta_data_%s, ",
|
|
348 |
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
|
|
349 |
if (!isConstructible && extraList.isEmpty())
|
|
350 |
fprintf(out, "0 }\n");
|
|
351 |
else
|
|
352 |
fprintf(out, "&qt_meta_extradata2_%s }\n", qualifiedClassNameIdentifier.constData());
|
|
353 |
fprintf(out, "};\n");
|
|
354 |
|
|
355 |
if(isQt)
|
|
356 |
return;
|
|
357 |
|
|
358 |
//
|
|
359 |
// Generate static meta object accessor (needed for symbian, because DLLs do not support data imports.
|
|
360 |
//
|
|
361 |
fprintf(out, "\n#ifdef Q_NO_DATA_RELOCATION\n");
|
|
362 |
fprintf(out, "const QMetaObject &%s::getStaticMetaObject() { return staticMetaObject; }\n", cdef->qualified.constData());
|
|
363 |
fprintf(out, "#endif //Q_NO_DATA_RELOCATION\n");
|
|
364 |
|
|
365 |
if (!cdef->hasQObject)
|
|
366 |
return;
|
|
367 |
|
|
368 |
fprintf(out, "\nconst QMetaObject *%s::metaObject() const\n{\n return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;\n}\n",
|
|
369 |
cdef->qualified.constData());
|
|
370 |
|
|
371 |
//
|
|
372 |
// Generate smart cast function
|
|
373 |
//
|
|
374 |
fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
|
|
375 |
fprintf(out, " if (!_clname) return 0;\n");
|
|
376 |
fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s))\n"
|
|
377 |
" return static_cast<void*>(const_cast< %s*>(this));\n",
|
|
378 |
qualifiedClassNameIdentifier.constData(), cdef->classname.constData());
|
|
379 |
for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one
|
|
380 |
if (cdef->superclassList.at(i).second == FunctionDef::Private)
|
|
381 |
continue;
|
|
382 |
const char *cname = cdef->superclassList.at(i).first;
|
|
383 |
fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(const_cast< %s*>(this));\n",
|
|
384 |
cname, cname, cdef->classname.constData());
|
|
385 |
}
|
|
386 |
for (int i = 0; i < cdef->interfaceList.size(); ++i) {
|
|
387 |
const QList<ClassDef::Interface> &iface = cdef->interfaceList.at(i);
|
|
388 |
for (int j = 0; j < iface.size(); ++j) {
|
|
389 |
fprintf(out, " if (!strcmp(_clname, %s))\n return ", iface.at(j).interfaceId.constData());
|
|
390 |
for (int k = j; k >= 0; --k)
|
|
391 |
fprintf(out, "static_cast< %s*>(", iface.at(k).className.constData());
|
|
392 |
fprintf(out, "const_cast< %s*>(this)%s;\n",
|
|
393 |
cdef->classname.constData(), QByteArray(j+1, ')').constData());
|
|
394 |
}
|
|
395 |
}
|
|
396 |
if (!purestSuperClass.isEmpty() && !isQObject) {
|
|
397 |
QByteArray superClass = purestSuperClass;
|
|
398 |
// workaround for VC6
|
|
399 |
if (superClass.contains("::")) {
|
|
400 |
fprintf(out, " typedef %s QMocSuperClass;\n", superClass.constData());
|
|
401 |
superClass = "QMocSuperClass";
|
|
402 |
}
|
|
403 |
fprintf(out, " return %s::qt_metacast(_clname);\n", superClass.constData());
|
|
404 |
} else {
|
|
405 |
fprintf(out, " return 0;\n");
|
|
406 |
}
|
|
407 |
fprintf(out, "}\n");
|
|
408 |
|
|
409 |
//
|
|
410 |
// Generate internal qt_metacall() function
|
|
411 |
//
|
|
412 |
generateMetacall();
|
|
413 |
|
|
414 |
//
|
|
415 |
// Generate internal signal functions
|
|
416 |
//
|
|
417 |
for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex)
|
|
418 |
generateSignal(&cdef->signalList[signalindex], signalindex);
|
|
419 |
}
|
|
420 |
|
|
421 |
|
|
422 |
void Generator::generateClassInfos()
|
|
423 |
{
|
|
424 |
if (cdef->classInfoList.isEmpty())
|
|
425 |
return;
|
|
426 |
|
|
427 |
fprintf(out, "\n // classinfo: key, value\n");
|
|
428 |
|
|
429 |
for (int i = 0; i < cdef->classInfoList.size(); ++i) {
|
|
430 |
const ClassInfoDef &c = cdef->classInfoList.at(i);
|
|
431 |
fprintf(out, " %4d, %4d,\n", strreg(c.name), strreg(c.value));
|
|
432 |
}
|
|
433 |
}
|
|
434 |
|
|
435 |
void Generator::generateFunctions(QList<FunctionDef>& list, const char *functype, int type)
|
|
436 |
{
|
|
437 |
if (list.isEmpty())
|
|
438 |
return;
|
|
439 |
fprintf(out, "\n // %ss: signature, parameters, type, tag, flags\n", functype);
|
|
440 |
|
|
441 |
for (int i = 0; i < list.count(); ++i) {
|
|
442 |
const FunctionDef &f = list.at(i);
|
|
443 |
|
|
444 |
QByteArray sig = f.name + '(';
|
|
445 |
QByteArray arguments;
|
|
446 |
|
|
447 |
for (int j = 0; j < f.arguments.count(); ++j) {
|
|
448 |
const ArgumentDef &a = f.arguments.at(j);
|
|
449 |
if (j) {
|
|
450 |
sig += ",";
|
|
451 |
arguments += ",";
|
|
452 |
}
|
|
453 |
sig += a.normalizedType;
|
|
454 |
arguments += a.name;
|
|
455 |
}
|
|
456 |
sig += ')';
|
|
457 |
|
|
458 |
char flags = type;
|
|
459 |
if (f.access == FunctionDef::Private)
|
|
460 |
flags |= AccessPrivate;
|
|
461 |
else if (f.access == FunctionDef::Public)
|
|
462 |
flags |= AccessPublic;
|
|
463 |
else if (f.access == FunctionDef::Protected)
|
|
464 |
flags |= AccessProtected;
|
|
465 |
if (f.access == FunctionDef::Private)
|
|
466 |
flags |= AccessPrivate;
|
|
467 |
else if (f.access == FunctionDef::Public)
|
|
468 |
flags |= AccessPublic;
|
|
469 |
else if (f.access == FunctionDef::Protected)
|
|
470 |
flags |= AccessProtected;
|
|
471 |
if (f.isCompat)
|
|
472 |
flags |= MethodCompatibility;
|
|
473 |
if (f.wasCloned)
|
|
474 |
flags |= MethodCloned;
|
|
475 |
if (f.isScriptable)
|
|
476 |
flags |= MethodScriptable;
|
|
477 |
fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", strreg(sig),
|
|
478 |
strreg(arguments), strreg(f.normalizedType), strreg(f.tag), flags);
|
|
479 |
}
|
|
480 |
}
|
|
481 |
|
|
482 |
void Generator::generateProperties()
|
|
483 |
{
|
|
484 |
//
|
|
485 |
// specify get function, for compatibiliy we accept functions
|
|
486 |
// returning pointers, or const char * for QByteArray.
|
|
487 |
//
|
|
488 |
for (int i = 0; i < cdef->propertyList.count(); ++i) {
|
|
489 |
PropertyDef &p = cdef->propertyList[i];
|
|
490 |
if (p.read.isEmpty())
|
|
491 |
continue;
|
|
492 |
for (int j = 0; j < cdef->publicList.count(); ++j) {
|
|
493 |
const FunctionDef &f = cdef->publicList.at(j);
|
|
494 |
if (f.name != p.read)
|
|
495 |
continue;
|
|
496 |
if (!f.isConst) // get functions must be const
|
|
497 |
continue;
|
|
498 |
if (f.arguments.size()) // and must not take any arguments
|
|
499 |
continue;
|
|
500 |
PropertyDef::Specification spec = PropertyDef::ValueSpec;
|
|
501 |
QByteArray tmp = f.normalizedType;
|
|
502 |
if (p.type == "QByteArray" && tmp == "const char *")
|
|
503 |
tmp = "QByteArray";
|
|
504 |
if (tmp.left(6) == "const ")
|
|
505 |
tmp = tmp.mid(6);
|
|
506 |
if (p.type != tmp && tmp.endsWith('*')) {
|
|
507 |
tmp.chop(1);
|
|
508 |
spec = PropertyDef::PointerSpec;
|
|
509 |
} else if (f.type.name.endsWith('&')) { // raw type, not normalized type
|
|
510 |
spec = PropertyDef::ReferenceSpec;
|
|
511 |
}
|
|
512 |
if (p.type != tmp)
|
|
513 |
continue;
|
|
514 |
p.gspec = spec;
|
|
515 |
break;
|
|
516 |
}
|
|
517 |
if(!p.notify.isEmpty()) {
|
|
518 |
int notifyId = -1;
|
|
519 |
for (int j = 0; j < cdef->signalList.count(); ++j) {
|
|
520 |
const FunctionDef &f = cdef->signalList.at(j);
|
|
521 |
if(f.name != p.notify) {
|
|
522 |
continue;
|
|
523 |
} else {
|
|
524 |
notifyId = j /* Signal indexes start from 0 */;
|
|
525 |
break;
|
|
526 |
}
|
|
527 |
}
|
|
528 |
p.notifyId = notifyId;
|
|
529 |
}
|
|
530 |
}
|
|
531 |
|
|
532 |
//
|
|
533 |
// Create meta data
|
|
534 |
//
|
|
535 |
|
|
536 |
if (cdef->propertyList.count())
|
|
537 |
fprintf(out, "\n // properties: name, type, flags\n");
|
|
538 |
for (int i = 0; i < cdef->propertyList.count(); ++i) {
|
|
539 |
const PropertyDef &p = cdef->propertyList.at(i);
|
|
540 |
uint flags = Invalid;
|
|
541 |
if (!isVariantType(p.type)) {
|
|
542 |
flags |= EnumOrFlag;
|
|
543 |
} else if (!isQRealType(p.type)) {
|
|
544 |
flags |= qvariant_nameToType(p.type) << 24;
|
|
545 |
}
|
|
546 |
if (!p.read.isEmpty())
|
|
547 |
flags |= Readable;
|
|
548 |
if (!p.write.isEmpty()) {
|
|
549 |
flags |= Writable;
|
|
550 |
if (p.stdCppSet())
|
|
551 |
flags |= StdCppSet;
|
|
552 |
}
|
|
553 |
if (!p.reset.isEmpty())
|
|
554 |
flags |= Resettable;
|
|
555 |
|
|
556 |
// if (p.override)
|
|
557 |
// flags |= Override;
|
|
558 |
|
|
559 |
if (p.designable.isEmpty())
|
|
560 |
flags |= ResolveDesignable;
|
|
561 |
else if (p.designable != "false")
|
|
562 |
flags |= Designable;
|
|
563 |
|
|
564 |
if (p.scriptable.isEmpty())
|
|
565 |
flags |= ResolveScriptable;
|
|
566 |
else if (p.scriptable != "false")
|
|
567 |
flags |= Scriptable;
|
|
568 |
|
|
569 |
if (p.stored.isEmpty())
|
|
570 |
flags |= ResolveStored;
|
|
571 |
else if (p.stored != "false")
|
|
572 |
flags |= Stored;
|
|
573 |
|
|
574 |
if (p.editable.isEmpty())
|
|
575 |
flags |= ResolveEditable;
|
|
576 |
else if (p.editable != "false")
|
|
577 |
flags |= Editable;
|
|
578 |
|
|
579 |
if (p.user.isEmpty())
|
|
580 |
flags |= ResolveUser;
|
|
581 |
else if (p.user != "false")
|
|
582 |
flags |= User;
|
|
583 |
|
|
584 |
if (p.notifyId != -1)
|
|
585 |
flags |= Notify;
|
|
586 |
|
|
587 |
if (p.constant)
|
|
588 |
flags |= Constant;
|
|
589 |
if (p.final)
|
|
590 |
flags |= Final;
|
|
591 |
|
|
592 |
fprintf(out, " %4d, %4d, ",
|
|
593 |
strreg(p.name),
|
|
594 |
strreg(p.type));
|
|
595 |
if (!(flags >> 24) && isQRealType(p.type))
|
|
596 |
fprintf(out, "(QMetaType::QReal << 24) | ");
|
|
597 |
fprintf(out, "0x%.8x,\n", flags);
|
|
598 |
}
|
|
599 |
|
|
600 |
if(cdef->notifyableProperties) {
|
|
601 |
fprintf(out, "\n // properties: notify_signal_id\n");
|
|
602 |
for (int i = 0; i < cdef->propertyList.count(); ++i) {
|
|
603 |
const PropertyDef &p = cdef->propertyList.at(i);
|
|
604 |
if(p.notifyId == -1)
|
|
605 |
fprintf(out, " %4d,\n",
|
|
606 |
0);
|
|
607 |
else
|
|
608 |
fprintf(out, " %4d,\n",
|
|
609 |
p.notifyId);
|
|
610 |
}
|
|
611 |
}
|
|
612 |
}
|
|
613 |
|
|
614 |
void Generator::generateEnums(int index)
|
|
615 |
{
|
|
616 |
if (cdef->enumDeclarations.isEmpty())
|
|
617 |
return;
|
|
618 |
|
|
619 |
fprintf(out, "\n // enums: name, flags, count, data\n");
|
|
620 |
index += 4 * cdef->enumList.count();
|
|
621 |
int i;
|
|
622 |
for (i = 0; i < cdef->enumList.count(); ++i) {
|
|
623 |
const EnumDef &e = cdef->enumList.at(i);
|
|
624 |
fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
|
|
625 |
strreg(e.name),
|
|
626 |
cdef->enumDeclarations.value(e.name) ? 1 : 0,
|
|
627 |
e.values.count(),
|
|
628 |
index);
|
|
629 |
index += e.values.count() * 2;
|
|
630 |
}
|
|
631 |
|
|
632 |
fprintf(out, "\n // enum data: key, value\n");
|
|
633 |
for (i = 0; i < cdef->enumList.count(); ++i) {
|
|
634 |
const EnumDef &e = cdef->enumList.at(i);
|
|
635 |
for (int j = 0; j < e.values.count(); ++j) {
|
|
636 |
const QByteArray &val = e.values.at(j);
|
|
637 |
fprintf(out, " %4d, uint(%s::%s),\n",
|
|
638 |
strreg(val),
|
|
639 |
cdef->qualified.constData(),
|
|
640 |
val.constData());
|
|
641 |
}
|
|
642 |
}
|
|
643 |
}
|
|
644 |
|
|
645 |
void Generator::generateMetacall()
|
|
646 |
{
|
|
647 |
bool isQObject = (cdef->classname == "QObject");
|
|
648 |
|
|
649 |
fprintf(out, "\nint %s::qt_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n",
|
|
650 |
cdef->qualified.constData());
|
|
651 |
|
|
652 |
if (!purestSuperClass.isEmpty() && !isQObject) {
|
|
653 |
QByteArray superClass = purestSuperClass;
|
|
654 |
// workaround for VC6
|
|
655 |
if (superClass.contains("::")) {
|
|
656 |
fprintf(out, " typedef %s QMocSuperClass;\n", superClass.constData());
|
|
657 |
superClass = "QMocSuperClass";
|
|
658 |
}
|
|
659 |
fprintf(out, " _id = %s::qt_metacall(_c, _id, _a);\n", superClass.constData());
|
|
660 |
}
|
|
661 |
|
|
662 |
fprintf(out, " if (_id < 0)\n return _id;\n");
|
|
663 |
fprintf(out, " ");
|
|
664 |
|
|
665 |
bool needElse = false;
|
|
666 |
QList<FunctionDef> methodList;
|
|
667 |
methodList += cdef->signalList;
|
|
668 |
methodList += cdef->slotList;
|
|
669 |
methodList += cdef->methodList;
|
|
670 |
|
|
671 |
if (methodList.size()) {
|
|
672 |
needElse = true;
|
|
673 |
fprintf(out, "if (_c == QMetaObject::InvokeMetaMethod) {\n ");
|
|
674 |
fprintf(out, "switch (_id) {\n");
|
|
675 |
for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
|
|
676 |
const FunctionDef &f = methodList.at(methodindex);
|
|
677 |
fprintf(out, " case %d: ", methodindex);
|
|
678 |
if (f.normalizedType.size())
|
|
679 |
fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
|
|
680 |
if (f.inPrivateClass.size())
|
|
681 |
fprintf(out, "%s->", f.inPrivateClass.constData());
|
|
682 |
fprintf(out, "%s(", f.name.constData());
|
|
683 |
int offset = 1;
|
|
684 |
for (int j = 0; j < f.arguments.count(); ++j) {
|
|
685 |
const ArgumentDef &a = f.arguments.at(j);
|
|
686 |
if (j)
|
|
687 |
fprintf(out, ",");
|
|
688 |
fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
|
|
689 |
}
|
|
690 |
fprintf(out, ");");
|
|
691 |
if (f.normalizedType.size())
|
|
692 |
fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
|
|
693 |
noRef(f.normalizedType).constData());
|
|
694 |
fprintf(out, " break;\n");
|
|
695 |
}
|
|
696 |
fprintf(out, " default: ;\n");
|
|
697 |
fprintf(out, " }\n");
|
|
698 |
}
|
|
699 |
if (methodList.size())
|
|
700 |
fprintf(out, " _id -= %d;\n }", methodList.size());
|
|
701 |
|
|
702 |
if (cdef->propertyList.size()) {
|
|
703 |
bool needGet = false;
|
|
704 |
bool needTempVarForGet = false;
|
|
705 |
bool needSet = false;
|
|
706 |
bool needReset = false;
|
|
707 |
bool needDesignable = false;
|
|
708 |
bool needScriptable = false;
|
|
709 |
bool needStored = false;
|
|
710 |
bool needEditable = false;
|
|
711 |
bool needUser = false;
|
|
712 |
for (int i = 0; i < cdef->propertyList.size(); ++i) {
|
|
713 |
const PropertyDef &p = cdef->propertyList.at(i);
|
|
714 |
needGet |= !p.read.isEmpty();
|
|
715 |
if (!p.read.isEmpty())
|
|
716 |
needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec
|
|
717 |
&& p.gspec != PropertyDef::ReferenceSpec);
|
|
718 |
|
|
719 |
needSet |= !p.write.isEmpty();
|
|
720 |
needReset |= !p.reset.isEmpty();
|
|
721 |
needDesignable |= p.designable.endsWith(')');
|
|
722 |
needScriptable |= p.scriptable.endsWith(')');
|
|
723 |
needStored |= p.stored.endsWith(')');
|
|
724 |
needEditable |= p.editable.endsWith(')');
|
|
725 |
needUser |= p.user.endsWith(')');
|
|
726 |
}
|
|
727 |
bool needAnything = needGet
|
|
728 |
| needSet
|
|
729 |
| needReset
|
|
730 |
| needDesignable
|
|
731 |
| needScriptable
|
|
732 |
| needStored
|
|
733 |
| needEditable
|
|
734 |
| needUser;
|
|
735 |
if (!needAnything)
|
|
736 |
goto skip_properties;
|
|
737 |
fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
|
|
738 |
|
|
739 |
if (needElse)
|
|
740 |
fprintf(out, " else ");
|
|
741 |
fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n");
|
|
742 |
if (needGet) {
|
|
743 |
if (needTempVarForGet)
|
|
744 |
fprintf(out, " void *_v = _a[0];\n");
|
|
745 |
fprintf(out, " switch (_id) {\n");
|
|
746 |
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
|
747 |
const PropertyDef &p = cdef->propertyList.at(propindex);
|
|
748 |
if (p.read.isEmpty())
|
|
749 |
continue;
|
|
750 |
if (p.gspec == PropertyDef::PointerSpec)
|
|
751 |
fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(%s())); break;\n",
|
|
752 |
propindex, p.read.constData());
|
|
753 |
else if (p.gspec == PropertyDef::ReferenceSpec)
|
|
754 |
fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(&%s())); break;\n",
|
|
755 |
propindex, p.read.constData());
|
|
756 |
else if (cdef->enumDeclarations.value(p.type, false))
|
|
757 |
fprintf(out, " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s()); break;\n",
|
|
758 |
propindex, p.read.constData());
|
|
759 |
else
|
|
760 |
fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s(); break;\n",
|
|
761 |
propindex, p.type.constData(), p.read.constData());
|
|
762 |
}
|
|
763 |
fprintf(out, " }\n");
|
|
764 |
}
|
|
765 |
|
|
766 |
fprintf(out,
|
|
767 |
" _id -= %d;\n"
|
|
768 |
" }", cdef->propertyList.count());
|
|
769 |
|
|
770 |
fprintf(out, " else ");
|
|
771 |
fprintf(out, "if (_c == QMetaObject::WriteProperty) {\n");
|
|
772 |
|
|
773 |
if (needSet) {
|
|
774 |
fprintf(out, " void *_v = _a[0];\n");
|
|
775 |
fprintf(out, " switch (_id) {\n");
|
|
776 |
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
|
777 |
const PropertyDef &p = cdef->propertyList.at(propindex);
|
|
778 |
if (p.write.isEmpty())
|
|
779 |
continue;
|
|
780 |
if (cdef->enumDeclarations.value(p.type, false)) {
|
|
781 |
fprintf(out, " case %d: %s(QFlag(*reinterpret_cast<int*>(_v))); break;\n",
|
|
782 |
propindex, p.write.constData());
|
|
783 |
} else {
|
|
784 |
fprintf(out, " case %d: %s(*reinterpret_cast< %s*>(_v)); break;\n",
|
|
785 |
propindex, p.write.constData(), p.type.constData());
|
|
786 |
}
|
|
787 |
}
|
|
788 |
fprintf(out, " }\n");
|
|
789 |
}
|
|
790 |
|
|
791 |
fprintf(out,
|
|
792 |
" _id -= %d;\n"
|
|
793 |
" }", cdef->propertyList.count());
|
|
794 |
|
|
795 |
fprintf(out, " else ");
|
|
796 |
fprintf(out, "if (_c == QMetaObject::ResetProperty) {\n");
|
|
797 |
if (needReset) {
|
|
798 |
fprintf(out, " switch (_id) {\n");
|
|
799 |
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
|
800 |
const PropertyDef &p = cdef->propertyList.at(propindex);
|
|
801 |
if (!p.reset.endsWith(')'))
|
|
802 |
continue;
|
|
803 |
fprintf(out, " case %d: %s; break;\n",
|
|
804 |
propindex, p.reset.constData());
|
|
805 |
}
|
|
806 |
fprintf(out, " }\n");
|
|
807 |
}
|
|
808 |
fprintf(out,
|
|
809 |
" _id -= %d;\n"
|
|
810 |
" }", cdef->propertyList.count());
|
|
811 |
|
|
812 |
fprintf(out, " else ");
|
|
813 |
fprintf(out, "if (_c == QMetaObject::QueryPropertyDesignable) {\n");
|
|
814 |
if (needDesignable) {
|
|
815 |
fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
|
|
816 |
fprintf(out, " switch (_id) {\n");
|
|
817 |
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
|
818 |
const PropertyDef &p = cdef->propertyList.at(propindex);
|
|
819 |
if (!p.designable.endsWith(')'))
|
|
820 |
continue;
|
|
821 |
fprintf(out, " case %d: *_b = %s; break;\n",
|
|
822 |
propindex, p.designable.constData());
|
|
823 |
}
|
|
824 |
fprintf(out, " }\n");
|
|
825 |
}
|
|
826 |
fprintf(out,
|
|
827 |
" _id -= %d;\n"
|
|
828 |
" }", cdef->propertyList.count());
|
|
829 |
|
|
830 |
fprintf(out, " else ");
|
|
831 |
fprintf(out, "if (_c == QMetaObject::QueryPropertyScriptable) {\n");
|
|
832 |
if (needScriptable) {
|
|
833 |
fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
|
|
834 |
fprintf(out, " switch (_id) {\n");
|
|
835 |
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
|
836 |
const PropertyDef &p = cdef->propertyList.at(propindex);
|
|
837 |
if (!p.scriptable.endsWith(')'))
|
|
838 |
continue;
|
|
839 |
fprintf(out, " case %d: *_b = %s; break;\n",
|
|
840 |
propindex, p.scriptable.constData());
|
|
841 |
}
|
|
842 |
fprintf(out, " }\n");
|
|
843 |
}
|
|
844 |
fprintf(out,
|
|
845 |
" _id -= %d;\n"
|
|
846 |
" }", cdef->propertyList.count());
|
|
847 |
|
|
848 |
fprintf(out, " else ");
|
|
849 |
fprintf(out, "if (_c == QMetaObject::QueryPropertyStored) {\n");
|
|
850 |
if (needStored) {
|
|
851 |
fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
|
|
852 |
fprintf(out, " switch (_id) {\n");
|
|
853 |
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
|
854 |
const PropertyDef &p = cdef->propertyList.at(propindex);
|
|
855 |
if (!p.stored.endsWith(')'))
|
|
856 |
continue;
|
|
857 |
fprintf(out, " case %d: *_b = %s; break;\n",
|
|
858 |
propindex, p.stored.constData());
|
|
859 |
}
|
|
860 |
fprintf(out, " }\n");
|
|
861 |
}
|
|
862 |
fprintf(out,
|
|
863 |
" _id -= %d;\n"
|
|
864 |
" }", cdef->propertyList.count());
|
|
865 |
|
|
866 |
fprintf(out, " else ");
|
|
867 |
fprintf(out, "if (_c == QMetaObject::QueryPropertyEditable) {\n");
|
|
868 |
if (needEditable) {
|
|
869 |
fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
|
|
870 |
fprintf(out, " switch (_id) {\n");
|
|
871 |
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
|
872 |
const PropertyDef &p = cdef->propertyList.at(propindex);
|
|
873 |
if (!p.editable.endsWith(')'))
|
|
874 |
continue;
|
|
875 |
fprintf(out, " case %d: *_b = %s; break;\n",
|
|
876 |
propindex, p.editable.constData());
|
|
877 |
}
|
|
878 |
fprintf(out, " }\n");
|
|
879 |
}
|
|
880 |
fprintf(out,
|
|
881 |
" _id -= %d;\n"
|
|
882 |
" }", cdef->propertyList.count());
|
|
883 |
|
|
884 |
|
|
885 |
fprintf(out, " else ");
|
|
886 |
fprintf(out, "if (_c == QMetaObject::QueryPropertyUser) {\n");
|
|
887 |
if (needUser) {
|
|
888 |
fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
|
|
889 |
fprintf(out, " switch (_id) {\n");
|
|
890 |
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
|
891 |
const PropertyDef &p = cdef->propertyList.at(propindex);
|
|
892 |
if (!p.user.endsWith(')'))
|
|
893 |
continue;
|
|
894 |
fprintf(out, " case %d: *_b = %s; break;\n",
|
|
895 |
propindex, p.user.constData());
|
|
896 |
}
|
|
897 |
fprintf(out, " }\n");
|
|
898 |
}
|
|
899 |
fprintf(out,
|
|
900 |
" _id -= %d;\n"
|
|
901 |
" }", cdef->propertyList.count());
|
|
902 |
|
|
903 |
|
|
904 |
fprintf(out, "\n#endif // QT_NO_PROPERTIES");
|
|
905 |
}
|
|
906 |
skip_properties:
|
|
907 |
if (methodList.size() || cdef->signalList.size() || cdef->propertyList.size())
|
|
908 |
fprintf(out, "\n ");
|
|
909 |
fprintf(out,"return _id;\n}\n");
|
|
910 |
}
|
|
911 |
|
|
912 |
void Generator::generateStaticMetacall(const QByteArray &prefix)
|
|
913 |
{
|
|
914 |
bool isQObject = (cdef->classname == "QObject");
|
|
915 |
|
|
916 |
fprintf(out, "static int %s_qt_static_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n",
|
|
917 |
prefix.constData());
|
|
918 |
|
|
919 |
fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n");
|
|
920 |
fprintf(out, " switch (_id) {\n");
|
|
921 |
for (int ctorindex = 0; ctorindex < cdef->constructorList.count(); ++ctorindex) {
|
|
922 |
fprintf(out, " case %d: { %s *_r = new %s(", ctorindex,
|
|
923 |
cdef->qualified.constData(), cdef->qualified.constData());
|
|
924 |
const FunctionDef &f = cdef->constructorList.at(ctorindex);
|
|
925 |
int offset = 1;
|
|
926 |
for (int j = 0; j < f.arguments.count(); ++j) {
|
|
927 |
const ArgumentDef &a = f.arguments.at(j);
|
|
928 |
if (j)
|
|
929 |
fprintf(out, ",");
|
|
930 |
fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))", a.typeNameForCast.constData(), offset++);
|
|
931 |
}
|
|
932 |
fprintf(out, ");\n");
|
|
933 |
fprintf(out, " if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;\n");
|
|
934 |
}
|
|
935 |
fprintf(out, " }\n");
|
|
936 |
fprintf(out, " _id -= %d;\n", cdef->constructorList.count());
|
|
937 |
fprintf(out, " return _id;\n");
|
|
938 |
fprintf(out, " }\n");
|
|
939 |
|
|
940 |
if (!isQObject)
|
|
941 |
fprintf(out, " _id = %s::staticMetaObject.superClass()->static_metacall(_c, _id, _a);\n", cdef->qualified.constData());
|
|
942 |
|
|
943 |
fprintf(out, " if (_id < 0)\n return _id;\n");
|
|
944 |
|
|
945 |
fprintf(out, " return _id;\n");
|
|
946 |
fprintf(out, "}\n\n");
|
|
947 |
}
|
|
948 |
|
|
949 |
void Generator::generateSignal(FunctionDef *def,int index)
|
|
950 |
{
|
|
951 |
if (def->wasCloned || def->isAbstract)
|
|
952 |
return;
|
|
953 |
fprintf(out, "\n// SIGNAL %d\n%s %s::%s(",
|
|
954 |
index, def->type.name.constData(), cdef->qualified.constData(), def->name.constData());
|
|
955 |
|
|
956 |
QByteArray thisPtr = "this";
|
|
957 |
const char *constQualifier = "";
|
|
958 |
|
|
959 |
if (def->isConst) {
|
|
960 |
thisPtr = "const_cast< ";
|
|
961 |
thisPtr += cdef->qualified;
|
|
962 |
thisPtr += " *>(this)";
|
|
963 |
constQualifier = "const";
|
|
964 |
}
|
|
965 |
|
|
966 |
if (def->arguments.isEmpty() && def->normalizedType.isEmpty()) {
|
|
967 |
fprintf(out, ")%s\n{\n"
|
|
968 |
" QMetaObject::activate(%s, &staticMetaObject, %d, 0);\n"
|
|
969 |
"}\n", constQualifier, thisPtr.constData(), index);
|
|
970 |
return;
|
|
971 |
}
|
|
972 |
|
|
973 |
int offset = 1;
|
|
974 |
for (int j = 0; j < def->arguments.count(); ++j) {
|
|
975 |
const ArgumentDef &a = def->arguments.at(j);
|
|
976 |
if (j)
|
|
977 |
fprintf(out, ", ");
|
|
978 |
fprintf(out, "%s _t%d%s", a.type.name.constData(), offset++, a.rightType.constData());
|
|
979 |
}
|
|
980 |
fprintf(out, ")%s\n{\n", constQualifier);
|
|
981 |
if (def->type.name.size() && def->normalizedType.size())
|
|
982 |
fprintf(out, " %s _t0;\n", noRef(def->normalizedType).constData());
|
|
983 |
|
|
984 |
fprintf(out, " void *_a[] = { ");
|
|
985 |
if (def->normalizedType.isEmpty()) {
|
|
986 |
fprintf(out, "0");
|
|
987 |
} else {
|
|
988 |
if (def->returnTypeIsVolatile)
|
|
989 |
fprintf(out, "const_cast<void*>(reinterpret_cast<const volatile void*>(&_t0))");
|
|
990 |
else
|
|
991 |
fprintf(out, "const_cast<void*>(reinterpret_cast<const void*>(&_t0))");
|
|
992 |
}
|
|
993 |
int i;
|
|
994 |
for (i = 1; i < offset; ++i)
|
|
995 |
if (def->arguments.at(i - 1).type.isVolatile)
|
|
996 |
fprintf(out, ", const_cast<void*>(reinterpret_cast<const volatile void*>(&_t%d))", i);
|
|
997 |
else
|
|
998 |
fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i);
|
|
999 |
fprintf(out, " };\n");
|
|
1000 |
fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index);
|
|
1001 |
if (def->normalizedType.size())
|
|
1002 |
fprintf(out, " return _t0;\n");
|
|
1003 |
fprintf(out, "}\n");
|
|
1004 |
}
|
|
1005 |
|
|
1006 |
//
|
|
1007 |
// Functions used when generating QMetaObject directly
|
|
1008 |
//
|
|
1009 |
// Much of this code is copied from the corresponding
|
|
1010 |
// C++ code-generating functions; we can change the
|
|
1011 |
// two generators so that more of the code is shared.
|
|
1012 |
// The key difference from the C++ code generator is
|
|
1013 |
// that instead of calling fprintf(), we append bytes
|
|
1014 |
// to a buffer.
|
|
1015 |
//
|
|
1016 |
|
|
1017 |
QMetaObject *Generator::generateMetaObject(bool ignoreProperties)
|
|
1018 |
{
|
|
1019 |
//
|
|
1020 |
// build the data array
|
|
1021 |
//
|
|
1022 |
|
|
1023 |
// filter out undeclared enumerators and sets
|
|
1024 |
{
|
|
1025 |
QList<EnumDef> enumList;
|
|
1026 |
for (int i = 0; i < cdef->enumList.count(); ++i) {
|
|
1027 |
EnumDef def = cdef->enumList.at(i);
|
|
1028 |
if (cdef->enumDeclarations.contains(def.name)) {
|
|
1029 |
enumList += def;
|
|
1030 |
}
|
|
1031 |
QByteArray alias = cdef->flagAliases.value(def.name);
|
|
1032 |
if (cdef->enumDeclarations.contains(alias)) {
|
|
1033 |
def.name = alias;
|
|
1034 |
enumList += def;
|
|
1035 |
}
|
|
1036 |
}
|
|
1037 |
cdef->enumList = enumList;
|
|
1038 |
}
|
|
1039 |
|
|
1040 |
int index = 10;
|
|
1041 |
meta_data
|
|
1042 |
<< 1 // revision
|
|
1043 |
<< strreg(cdef->qualified) // classname
|
|
1044 |
<< cdef->classInfoList.count() << (cdef->classInfoList.count() ? index : 0) // classinfo
|
|
1045 |
;
|
|
1046 |
index += cdef->classInfoList.count() * 2;
|
|
1047 |
|
|
1048 |
int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count();
|
|
1049 |
meta_data << methodCount << (methodCount ? index : 0); // methods
|
|
1050 |
index += methodCount * 5;
|
|
1051 |
if (!ignoreProperties) {
|
|
1052 |
meta_data << cdef->propertyList.count() << (cdef->propertyList.count() ? index : 0); // properties
|
|
1053 |
index += cdef->propertyList.count() * 3;
|
|
1054 |
} else {
|
|
1055 |
meta_data << 0 << 0; // properties
|
|
1056 |
}
|
|
1057 |
meta_data << cdef->enumList.count() << (cdef->enumList.count() ? index : 0); // enums/sets
|
|
1058 |
|
|
1059 |
//
|
|
1060 |
// Build classinfo array
|
|
1061 |
//
|
|
1062 |
_generateClassInfos();
|
|
1063 |
|
|
1064 |
//
|
|
1065 |
// Build signals array first, otherwise the signal indices would be wrong
|
|
1066 |
//
|
|
1067 |
_generateFunctions(cdef->signalList, MethodSignal);
|
|
1068 |
|
|
1069 |
//
|
|
1070 |
// Build slots array
|
|
1071 |
//
|
|
1072 |
_generateFunctions(cdef->slotList, MethodSlot);
|
|
1073 |
|
|
1074 |
//
|
|
1075 |
// Build method array
|
|
1076 |
//
|
|
1077 |
_generateFunctions(cdef->methodList, MethodMethod);
|
|
1078 |
|
|
1079 |
|
|
1080 |
//
|
|
1081 |
// Build property array
|
|
1082 |
//
|
|
1083 |
if (!ignoreProperties)
|
|
1084 |
_generateProperties();
|
|
1085 |
|
|
1086 |
//
|
|
1087 |
// Build enums array
|
|
1088 |
//
|
|
1089 |
_generateEnums(index);
|
|
1090 |
|
|
1091 |
//
|
|
1092 |
// Terminate data array
|
|
1093 |
//
|
|
1094 |
meta_data << 0;
|
|
1095 |
|
|
1096 |
//
|
|
1097 |
// Build stringdata array
|
|
1098 |
//
|
|
1099 |
QVector<char> string_data;
|
|
1100 |
for (int i = 0; i < strings.size(); ++i) {
|
|
1101 |
const char *s = strings.at(i).constData();
|
|
1102 |
char c;
|
|
1103 |
do {
|
|
1104 |
c = *(s++);
|
|
1105 |
string_data << c;
|
|
1106 |
} while (c != '\0');
|
|
1107 |
}
|
|
1108 |
|
|
1109 |
//
|
|
1110 |
// Finally create and initialize the static meta object
|
|
1111 |
//
|
|
1112 |
const int meta_object_offset = 0;
|
|
1113 |
const int meta_object_size = sizeof(QMetaObject);
|
|
1114 |
const int meta_data_offset = meta_object_offset + meta_object_size;
|
|
1115 |
const int meta_data_size = meta_data.count() * sizeof(uint);
|
|
1116 |
const int string_data_offset = meta_data_offset + meta_data_size;
|
|
1117 |
const int string_data_size = string_data.count();
|
|
1118 |
const int total_size = string_data_offset + string_data_size;
|
|
1119 |
|
|
1120 |
char *blob = new char[total_size];
|
|
1121 |
|
|
1122 |
char *string_data_output = blob + string_data_offset;
|
|
1123 |
const char *string_data_src = string_data.constData();
|
|
1124 |
for (int i = 0; i < string_data.count(); ++i)
|
|
1125 |
string_data_output[i] = string_data_src[i];
|
|
1126 |
|
|
1127 |
uint *meta_data_output = reinterpret_cast<uint *>(blob + meta_data_offset);
|
|
1128 |
const uint *meta_data_src = meta_data.constData();
|
|
1129 |
for (int i = 0; i < meta_data.count(); ++i)
|
|
1130 |
meta_data_output[i] = meta_data_src[i];
|
|
1131 |
|
|
1132 |
QMetaObject *meta_object = new (blob + meta_object_offset)QMetaObject;
|
|
1133 |
meta_object->d.superdata = 0;
|
|
1134 |
meta_object->d.stringdata = string_data_output;
|
|
1135 |
meta_object->d.data = meta_data_output;
|
|
1136 |
meta_object->d.extradata = 0;
|
|
1137 |
return meta_object;
|
|
1138 |
}
|
|
1139 |
|
|
1140 |
void Generator::_generateClassInfos()
|
|
1141 |
{
|
|
1142 |
for (int i = 0; i < cdef->classInfoList.size(); ++i) {
|
|
1143 |
const ClassInfoDef &c = cdef->classInfoList.at(i);
|
|
1144 |
meta_data << strreg(c.name) << strreg(c.value);
|
|
1145 |
}
|
|
1146 |
}
|
|
1147 |
|
|
1148 |
void Generator::_generateFunctions(QList<FunctionDef> &list, int type)
|
|
1149 |
{
|
|
1150 |
for (int i = 0; i < list.count(); ++i) {
|
|
1151 |
const FunctionDef &f = list.at(i);
|
|
1152 |
|
|
1153 |
QByteArray sig = f.name + '(';
|
|
1154 |
QByteArray arguments;
|
|
1155 |
|
|
1156 |
for (int j = 0; j < f.arguments.count(); ++j) {
|
|
1157 |
const ArgumentDef &a = f.arguments.at(j);
|
|
1158 |
if (j) {
|
|
1159 |
sig += ',';
|
|
1160 |
arguments += ',';
|
|
1161 |
}
|
|
1162 |
sig += a.normalizedType;
|
|
1163 |
arguments += a.name;
|
|
1164 |
}
|
|
1165 |
sig += ')';
|
|
1166 |
|
|
1167 |
char flags = type;
|
|
1168 |
if (f.access == FunctionDef::Private)
|
|
1169 |
flags |= AccessPrivate;
|
|
1170 |
else if (f.access == FunctionDef::Public)
|
|
1171 |
flags |= AccessPublic;
|
|
1172 |
else if (f.access == FunctionDef::Protected)
|
|
1173 |
flags |= AccessProtected;
|
|
1174 |
if (f.access == FunctionDef::Private)
|
|
1175 |
flags |= AccessPrivate;
|
|
1176 |
else if (f.access == FunctionDef::Public)
|
|
1177 |
flags |= AccessPublic;
|
|
1178 |
else if (f.access == FunctionDef::Protected)
|
|
1179 |
flags |= AccessProtected;
|
|
1180 |
if (f.isCompat)
|
|
1181 |
flags |= MethodCompatibility;
|
|
1182 |
if (f.wasCloned)
|
|
1183 |
flags |= MethodCloned;
|
|
1184 |
if (f.isScriptable)
|
|
1185 |
flags |= MethodScriptable;
|
|
1186 |
|
|
1187 |
meta_data << strreg(sig)
|
|
1188 |
<< strreg(arguments)
|
|
1189 |
<< strreg(f.normalizedType)
|
|
1190 |
<< strreg(f.tag)
|
|
1191 |
<< flags;
|
|
1192 |
}
|
|
1193 |
}
|
|
1194 |
|
|
1195 |
void Generator::_generateEnums(int index)
|
|
1196 |
{
|
|
1197 |
index += 4 * cdef->enumList.count();
|
|
1198 |
int i;
|
|
1199 |
for (i = 0; i < cdef->enumList.count(); ++i) {
|
|
1200 |
const EnumDef &e = cdef->enumList.at(i);
|
|
1201 |
meta_data << strreg(e.name) << (cdef->enumDeclarations.value(e.name) ? 1 : 0)
|
|
1202 |
<< e.values.count() << index;
|
|
1203 |
index += e.values.count() * 2;
|
|
1204 |
}
|
|
1205 |
|
|
1206 |
for (i = 0; i < cdef->enumList.count(); ++i) {
|
|
1207 |
const EnumDef &e = cdef->enumList.at(i);
|
|
1208 |
for (int j = 0; j < e.values.count(); ++j) {
|
|
1209 |
const QByteArray &val = e.values.at(j);
|
|
1210 |
meta_data << strreg(val) << 0; // we don't know the value itself
|
|
1211 |
}
|
|
1212 |
}
|
|
1213 |
}
|
|
1214 |
|
|
1215 |
void Generator::_generateProperties()
|
|
1216 |
{
|
|
1217 |
//
|
|
1218 |
// specify get function, for compatibiliy we accept functions
|
|
1219 |
// returning pointers, or const char * for QByteArray.
|
|
1220 |
//
|
|
1221 |
for (int i = 0; i < cdef->propertyList.count(); ++i) {
|
|
1222 |
PropertyDef &p = cdef->propertyList[i];
|
|
1223 |
if (p.read.isEmpty())
|
|
1224 |
continue;
|
|
1225 |
for (int j = 0; j < cdef->publicList.count(); ++j) {
|
|
1226 |
const FunctionDef &f = cdef->publicList.at(j);
|
|
1227 |
if (f.name != p.read)
|
|
1228 |
continue;
|
|
1229 |
if (!f.isConst) // get functions must be const
|
|
1230 |
continue;
|
|
1231 |
if (f.arguments.size()) // and must not take any arguments
|
|
1232 |
continue;
|
|
1233 |
PropertyDef::Specification spec = PropertyDef::ValueSpec;
|
|
1234 |
QByteArray tmp = f.normalizedType;
|
|
1235 |
if (p.type == "QByteArray" && tmp == "const char *")
|
|
1236 |
tmp = "QByteArray";
|
|
1237 |
if (tmp.left(6) == "const ")
|
|
1238 |
tmp = tmp.mid(6);
|
|
1239 |
if (p.type != tmp && tmp.endsWith('*')) {
|
|
1240 |
tmp.chop(1);
|
|
1241 |
spec = PropertyDef::PointerSpec;
|
|
1242 |
} else if (f.type.name.endsWith('&')) { // raw type, not normalized type
|
|
1243 |
spec = PropertyDef::ReferenceSpec;
|
|
1244 |
}
|
|
1245 |
if (p.type != tmp)
|
|
1246 |
continue;
|
|
1247 |
p.gspec = spec;
|
|
1248 |
break;
|
|
1249 |
}
|
|
1250 |
}
|
|
1251 |
|
|
1252 |
|
|
1253 |
//
|
|
1254 |
// Create meta data
|
|
1255 |
//
|
|
1256 |
|
|
1257 |
for (int i = 0; i < cdef->propertyList.count(); ++i) {
|
|
1258 |
const PropertyDef &p = cdef->propertyList.at(i);
|
|
1259 |
uint flags = Invalid;
|
|
1260 |
if (!isVariantType(p.type)) {
|
|
1261 |
flags |= EnumOrFlag;
|
|
1262 |
} else {
|
|
1263 |
flags |= qvariant_nameToType(p.type) << 24;
|
|
1264 |
}
|
|
1265 |
if (!p.read.isEmpty())
|
|
1266 |
flags |= Readable;
|
|
1267 |
if (!p.write.isEmpty()) {
|
|
1268 |
flags |= Writable;
|
|
1269 |
if (p.stdCppSet())
|
|
1270 |
flags |= StdCppSet;
|
|
1271 |
}
|
|
1272 |
if (!p.reset.isEmpty())
|
|
1273 |
flags |= Resettable;
|
|
1274 |
|
|
1275 |
// if (p.override)
|
|
1276 |
// flags |= Override;
|
|
1277 |
|
|
1278 |
if (p.designable.isEmpty())
|
|
1279 |
flags |= ResolveDesignable;
|
|
1280 |
else if (p.designable != "false")
|
|
1281 |
flags |= Designable;
|
|
1282 |
|
|
1283 |
if (p.scriptable.isEmpty())
|
|
1284 |
flags |= ResolveScriptable;
|
|
1285 |
else if (p.scriptable != "false")
|
|
1286 |
flags |= Scriptable;
|
|
1287 |
|
|
1288 |
if (p.stored.isEmpty())
|
|
1289 |
flags |= ResolveStored;
|
|
1290 |
else if (p.stored != "false")
|
|
1291 |
flags |= Stored;
|
|
1292 |
|
|
1293 |
if (p.editable.isEmpty())
|
|
1294 |
flags |= ResolveEditable;
|
|
1295 |
else if (p.editable != "false")
|
|
1296 |
flags |= Editable;
|
|
1297 |
|
|
1298 |
if (p.user.isEmpty())
|
|
1299 |
flags |= ResolveUser;
|
|
1300 |
else if (p.user != "false")
|
|
1301 |
flags |= User;
|
|
1302 |
|
|
1303 |
meta_data << strreg(p.name) << strreg(p.type) << flags;
|
|
1304 |
}
|
|
1305 |
}
|
|
1306 |
|
|
1307 |
QT_END_NAMESPACE
|