Root/
Source at commit 1322 created 12 years 8 months ago. By meklort, Add doxygen to utils folder | |
---|---|
1 | /******************************************************************************␊ |
2 | *␊ |
3 | *␊ |
4 | *␊ |
5 | * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com>␊ |
6 | *␊ |
7 | * Permission to use, copy, modify, and distribute this software and its␊ |
8 | * documentation under the terms of the GNU General Public License is hereby␊ |
9 | * granted. No representations are made about the suitability of this software␊ |
10 | * for any purpose. It is provided "as is" without express or implied warranty.␊ |
11 | * See the GNU General Public License for more details.␊ |
12 | *␊ |
13 | * Documents produced by Doxygen are derivative works derived from the␊ |
14 | * input used in their production; they are not affected by this license.␊ |
15 | *␊ |
16 | */␊ |
17 | ␊ |
18 | #include "dbusxmlscanner.h"␊ |
19 | ␊ |
20 | #include "commentscan.h"␊ |
21 | #include "entry.h"␊ |
22 | ␊ |
23 | #include <qfile.h>␊ |
24 | #include <qxml.h>␊ |
25 | #include <qstring.h>␊ |
26 | ␊ |
27 | #include "message.h"␊ |
28 | #include "util.h"␊ |
29 | ␊ |
30 | // -----------------------------------------------------------------------␊ |
31 | // Convenience defines:␊ |
32 | // -----------------------------------------------------------------------␊ |
33 | ␊ |
34 | #define CONDITION(cond, msg) \␊ |
35 | do {\␊ |
36 | if (cond)\␊ |
37 | {\␊ |
38 | if (m_errorString.isEmpty()) { m_errorString = msg; }\␊ |
39 | return false;\␊ |
40 | }\␊ |
41 | }\␊ |
42 | while (0)␊ |
43 | ␊ |
44 | #define DOC_ERROR(msg) \␊ |
45 | warn_doc_error(m_fileName.utf8().data(), lineNumber(), msg.utf8().data())␊ |
46 | ␊ |
47 | #define COND_DOC_ERROR(cond, msg) \␊ |
48 | do {\␊ |
49 | if (cond)\␊ |
50 | {\␊ |
51 | DOC_ERROR(msg);\␊ |
52 | return true;\␊ |
53 | }\␊ |
54 | }\␊ |
55 | while (0)␊ |
56 | ␊ |
57 | #define DBUS(name) isDBusElement(namespaceURI, localName, qName, name)␊ |
58 | #define EXTENSION(name) isExtensionElement(namespaceURI, localName, qName, name)␊ |
59 | ␊ |
60 | // -----------------------------------------------------------------------␊ |
61 | // DBusXMLHandler class␊ |
62 | // -----------------------------------------------------------------------␊ |
63 | ␊ |
64 | const QString EXTENSION_URI("http://psiamp.org/dtd/doxygen_dbusxml.dtd");␊ |
65 | ␊ |
66 | class DBusXMLHandler : public QXmlDefaultHandler␊ |
67 | {␊ |
68 | public:␊ |
69 | DBusXMLHandler(ParserInterface * parser,␊ |
70 | QXmlSimpleReader * reader,␊ |
71 | const char * file_name,␊ |
72 | Entry * root) :␊ |
73 | m_parser(parser),␊ |
74 | m_locator(reader),␊ |
75 | m_currentEntry(0),␊ |
76 | m_currentInterface(0),␊ |
77 | m_currentMethod(0),␊ |
78 | m_currentArgument(0),␊ |
79 | m_currentProperty(0),␊ |
80 | m_currentEnum(0),␊ |
81 | m_fileName(file_name),␊ |
82 | m_currentComment(0)␊ |
83 | {␊ |
84 | setDocumentLocator(&m_locator);␊ |
85 | ␊ |
86 | m_scopeCount = 0;␊ |
87 | ␊ |
88 | // Set up stack cleanup:␊ |
89 | m_structStack.setAutoDelete(TRUE);␊ |
90 | m_elementStack.setAutoDelete(TRUE);␊ |
91 | m_scopeStack.setAutoDelete(TRUE);␊ |
92 | ␊ |
93 | openScopes(root);␊ |
94 | }␊ |
95 | ␊ |
96 | ~DBusXMLHandler()␊ |
97 | { closeScopes(); }␊ |
98 | ␊ |
99 | QString errorString()␊ |
100 | { return m_errorString; }␊ |
101 | ␊ |
102 | bool startElement(const QString &namespaceURI,␊ |
103 | const QString &localName,␊ |
104 | const QString &qName,␊ |
105 | const QXmlAttributes &attributes)␊ |
106 | {␊ |
107 | // add to elements stack:␊ |
108 | m_elementStack.append(new ElementData(qName));␊ |
109 | ␊ |
110 | // First we need a node.␊ |
111 | if (DBUS("node"))␊ |
112 | {␊ |
113 | CONDITION(!m_currentNode.isEmpty(), "Node inside a node.");␊ |
114 | ␊ |
115 | const int idx(indexOf(attributes, "name"));␊ |
116 | COND_DOC_ERROR(idx < 0, QString("Anonymous node found."));␊ |
117 | ␊ |
118 | m_currentNode = attributes.value(idx);␊ |
119 | // A node is actually of little interest, so do nothing here.␊ |
120 | return true;␊ |
121 | }␊ |
122 | ␊ |
123 | // Then we need an interface.␊ |
124 | if (DBUS("interface"))␊ |
125 | {␊ |
126 | // We need a nodeName for interfaces:␊ |
127 | CONDITION(m_currentNode.isEmpty(), "Interface without a node.");␊ |
128 | CONDITION(m_currentInterface, "Interface within another interface.");␊ |
129 | ␊ |
130 | const int idx(indexOf(attributes, "name"));␊ |
131 | COND_DOC_ERROR(idx < 0, QString("Interface without a name found."));␊ |
132 | ␊ |
133 | // A interface is roughly equivalent to a class:␊ |
134 | m_currentInterface = createEntry();␊ |
135 | ␊ |
136 | m_currentInterface->section = Entry::CLASS_SEC;␊ |
137 | m_currentInterface->spec |= Entry::Interface;␊ |
138 | m_currentInterface->type = "Interface";␊ |
139 | m_currentInterface->name = substitute(attributes.value(idx), ".", "::");␊ |
140 | ␊ |
141 | openScopes(m_currentInterface);␊ |
142 | ␊ |
143 | return true;␊ |
144 | }␊ |
145 | ␊ |
146 | if (DBUS("method") || DBUS("signal"))␊ |
147 | {␊ |
148 | // We need a interfaceName for methods and signals:␊ |
149 | CONDITION(!m_currentInterface, "Method or signal found outside a interface.");␊ |
150 | CONDITION(m_currentMethod, "Method or signal found inside another method or signal.");␊ |
151 | CONDITION(m_currentProperty, "Methor or signal found inside a property.");␊ |
152 | CONDITION(!m_structStack.isEmpty(), "Method or signal found inside a struct.");␊ |
153 | CONDITION(m_currentEnum, "Methor or signal found inside a enum.");␊ |
154 | ␊ |
155 | const int idx(indexOf(attributes, "name"));␊ |
156 | COND_DOC_ERROR(idx < 0, QString("Method or signal without a name found."));␊ |
157 | ␊ |
158 | m_currentMethod = createEntry();␊ |
159 | ␊ |
160 | m_currentMethod->section = Entry::FUNCTION_SEC;␊ |
161 | m_currentMethod->name = attributes.value(idx);␊ |
162 | m_currentMethod->mtype = Method;␊ |
163 | m_currentMethod->type = "void";␊ |
164 | ␊ |
165 | if (DBUS("signal"))␊ |
166 | { m_currentMethod->mtype = Signal; }␊ |
167 | }␊ |
168 | ␊ |
169 | if (DBUS("arg"))␊ |
170 | {␊ |
171 | // We need a method for arguments:␊ |
172 | CONDITION(!m_currentMethod, "Argument found outside a method or signal.");␊ |
173 | CONDITION(m_currentArgument, "Argument found inside another argument.");␊ |
174 | ␊ |
175 | const int name_idx(indexOf(attributes, "name"));␊ |
176 | COND_DOC_ERROR(name_idx < 0, QString("Argument without a name found."));␊ |
177 | COND_DOC_ERROR(!hasType(attributes), QString("Argument without a type found."));␊ |
178 | ␊ |
179 | const int direction_idx(indexOf(attributes, "direction"));␊ |
180 | ␊ |
181 | if ((m_currentMethod->mtype == Signal &&␊ |
182 | direction_idx >= 0 &&␊ |
183 | attributes.value(direction_idx) != "in") ||␊ |
184 | (m_currentMethod->mtype == Method &&␊ |
185 | direction_idx >= 0 &&␊ |
186 | attributes.value(direction_idx) != "in" &&␊ |
187 | attributes.value(direction_idx) != "out"))␊ |
188 | {␊ |
189 | m_errorString = "Invalid direction found.";␊ |
190 | return false;␊ |
191 | }␊ |
192 | ␊ |
193 | m_currentArgument = new Argument;␊ |
194 | m_currentArgument->type = getType(attributes);␊ |
195 | m_currentArgument->name = attributes.value(name_idx);␊ |
196 | if (direction_idx >= 0)␊ |
197 | { m_currentArgument->attrib = attributes.value(direction_idx); }␊ |
198 | else␊ |
199 | {␊ |
200 | if (m_currentMethod->mtype == Signal)␊ |
201 | { m_currentArgument->attrib = "in"; }␊ |
202 | else␊ |
203 | { m_currentArgument->attrib = "out"; }␊ |
204 | }␊ |
205 | }␊ |
206 | ␊ |
207 | if (DBUS("property"))␊ |
208 | {␊ |
209 | CONDITION(m_currentMethod, "Property found inside a method or signal.");␊ |
210 | CONDITION(!m_currentInterface, "Property found outside an interface.");␊ |
211 | CONDITION(m_currentProperty, "Property found inside another property.");␊ |
212 | CONDITION(!m_structStack.isEmpty(), "Property found inside a struct.");␊ |
213 | CONDITION(m_currentEnum, "Property found inside a enum.");␊ |
214 | ␊ |
215 | const int name_idx(indexOf(attributes, "name"));␊ |
216 | COND_DOC_ERROR(name_idx < 0, QString("Anonymous property found."));␊ |
217 | COND_DOC_ERROR(!hasType(attributes), QString("Property without a type found."));␊ |
218 | ␊ |
219 | const int access_idx(indexOf(attributes, "access"));␊ |
220 | COND_DOC_ERROR(access_idx < 0, QString("Property without a access attribute found."));␊ |
221 | COND_DOC_ERROR(attributes.value(access_idx) != "read" &&␊ |
222 | attributes.value(access_idx) != "write" &&␊ |
223 | attributes.value(access_idx) != "readwrite",␊ |
224 | QString("Property with invalid access attribute \"%1\" found.").␊ |
225 | arg(attributes.value(access_idx)));␊ |
226 | ␊ |
227 | m_currentProperty = createEntry();␊ |
228 | ␊ |
229 | m_currentProperty->section = Entry::FUNCTION_SEC;␊ |
230 | ␊ |
231 | if (attributes.value(access_idx) == "read" ||␊ |
232 | attributes.value(access_idx) == "readwrite")␊ |
233 | { m_currentProperty->spec |= Entry::Readable; }␊ |
234 | ␊ |
235 | if (attributes.value(access_idx) == "write" ||␊ |
236 | attributes.value(access_idx) == "readwrite")␊ |
237 | { m_currentProperty->spec |= Entry::Writable; }␊ |
238 | ␊ |
239 | m_currentProperty->name = attributes.value(name_idx);␊ |
240 | m_currentProperty->mtype = Property;␊ |
241 | m_currentProperty->type = getType(attributes);␊ |
242 | }␊ |
243 | ␊ |
244 | if (EXTENSION("namespace"))␊ |
245 | {␊ |
246 | CONDITION(m_currentNode.isEmpty(), "Namespace found outside a node.");␊ |
247 | CONDITION(m_currentInterface, "Namespace found inside an interface.");␊ |
248 | ␊ |
249 | const int idx(indexOf(attributes, "name"));␊ |
250 | COND_DOC_ERROR(idx < 0, QString("Anonymous namespace found."));␊ |
251 | ␊ |
252 | m_namespaceStack.append(openNamespace(attributes.value(idx)));␊ |
253 | openScopes(m_namespaceStack.last());␊ |
254 | }␊ |
255 | ␊ |
256 | if (EXTENSION("struct"))␊ |
257 | {␊ |
258 | CONDITION(m_currentMethod, "Struct found inside a method or signal.");␊ |
259 | CONDITION(m_currentProperty, "Struct found inside a property.");␊ |
260 | CONDITION(m_currentEnum, "Struct found inside an enum.");␊ |
261 | ␊ |
262 | const int idx(indexOf(attributes, "name"));␊ |
263 | COND_DOC_ERROR(idx < 0, QString("Anonymous struct found."));␊ |
264 | ␊ |
265 | Entry * current_struct = createEntry();␊ |
266 | current_struct->section = Entry::CLASS_SEC;␊ |
267 | current_struct->spec = Entry::Struct;␊ |
268 | current_struct->name = attributes.value(idx);␊ |
269 | ␊ |
270 | openScopes(current_struct);␊ |
271 | ␊ |
272 | current_struct->type = current_struct->name + " struct";␊ |
273 | ␊ |
274 | m_structStack.append(new StructData(current_struct));␊ |
275 | }␊ |
276 | ␊ |
277 | if (EXTENSION("member"))␊ |
278 | {␊ |
279 | CONDITION(m_structStack.isEmpty(), "Member found outside of struct.");␊ |
280 | ␊ |
281 | const int name_idx(indexOf(attributes, "name"));␊ |
282 | COND_DOC_ERROR(name_idx < 0, QString("Anonymous member found."));␊ |
283 | COND_DOC_ERROR(!hasType(attributes), QString("Member without a type found."));␊ |
284 | ␊ |
285 | createEntry();␊ |
286 | ␊ |
287 | m_currentEntry->section = Entry::VARIABLE_SEC;␊ |
288 | m_currentEntry->name = attributes.value(name_idx);␊ |
289 | m_currentEntry->type = getType(attributes);␊ |
290 | ␊ |
291 | QString type(getDBusType(m_currentEntry->type));␊ |
292 | m_structStack.last()->type.append(type);␊ |
293 | }␊ |
294 | ␊ |
295 | if (EXTENSION("enum") || EXTENSION("flagset"))␊ |
296 | {␊ |
297 | CONDITION(m_currentMethod, "Enum found inside a method or signal.");␊ |
298 | CONDITION(m_currentProperty, "Enum found inside a property.");␊ |
299 | ␊ |
300 | const int name_idx(indexOf(attributes, "name"));␊ |
301 | COND_DOC_ERROR(name_idx < 0, QString("Anonymous enum found."));␊ |
302 | ␊ |
303 | const int type_idx(indexOf(attributes, "type"));␊ |
304 | QString type = "u";␊ |
305 | if (type_idx >= 0)␊ |
306 | { type = attributes.value(type_idx); }␊ |
307 | if (type != "y" && type != "q" && type != "u" && type != "t")␊ |
308 | { DOC_ERROR(QString("Invalid enum type \"%1\" found.").arg(type)); }␊ |
309 | ␊ |
310 | m_currentEnum = createEntry();␊ |
311 | m_currentEnum->section = Entry::ENUM_SEC;␊ |
312 | m_currentEnum->name = attributes.value(name_idx);␊ |
313 | ␊ |
314 | openScopes(m_currentEnum);␊ |
315 | ␊ |
316 | m_currentEnum->type = m_currentEntry->name + " enum";␊ |
317 | ␊ |
318 | addNamedType(type);␊ |
319 | }␊ |
320 | ␊ |
321 | if (EXTENSION("value"))␊ |
322 | {␊ |
323 | CONDITION(!m_currentEnum, "Value found outside an enum.");␊ |
324 | ␊ |
325 | const int name_idx(indexOf(attributes, "name"));␊ |
326 | COND_DOC_ERROR(name_idx < 0, QString("Anonymous value found."));␊ |
327 | ␊ |
328 | const int value_idx(indexOf(attributes, "value"));␊ |
329 | ␊ |
330 | createEntry();␊ |
331 | ␊ |
332 | m_currentEntry->section = Entry::VARIABLE_SEC;␊ |
333 | m_currentEntry->name = attributes.value(name_idx);␊ |
334 | m_currentEntry->type = m_currentEnum->name; // "@"; // enum marker!␊ |
335 | if (value_idx >= 0)␊ |
336 | { m_currentEntry->initializer = attributes.value(value_idx); }␊ |
337 | }␊ |
338 | ␊ |
339 | return true;␊ |
340 | }␊ |
341 | ␊ |
342 | bool endElement(const QString &namespaceURI,␊ |
343 | const QString &localName,␊ |
344 | const QString &qName)␊ |
345 | {␊ |
346 | // Clean up elements stack:␊ |
347 | // Since we made sure to get the elements in the proper order when␊ |
348 | // adding we do not need to do so again here.␊ |
349 | COND_DOC_ERROR(m_elementStack.last()->element != qName,␊ |
350 | QString("Malformed XML: Unexpected closing element found.").␊ |
351 | arg(m_elementStack.last()->element));␊ |
352 | m_elementStack.removeLast();␊ |
353 | ␊ |
354 | // Interface:␊ |
355 | if (DBUS("interface"))␊ |
356 | {␊ |
357 | CONDITION(m_currentInterface, "end of interface found without start.");␊ |
358 | m_currentInterface->endBodyLine = lineNumber();␊ |
359 | closeScopes();␊ |
360 | m_currentInterface = 0;␊ |
361 | }␊ |
362 | ␊ |
363 | if (DBUS("method") || DBUS("signal"))␊ |
364 | {␊ |
365 | CONDITION(m_currentMethod, "end of method found without start.");␊ |
366 | CONDITION(m_currentInterface, "end of method found outside interface.");␊ |
367 | m_currentMethod->endBodyLine = lineNumber();␊ |
368 | m_currentInterface->addSubEntry(m_currentMethod);␊ |
369 | m_currentMethod = 0;␊ |
370 | }␊ |
371 | ␊ |
372 | if (DBUS("property"))␊ |
373 | {␊ |
374 | CONDITION(m_currentMethod, "end of property found without start.");␊ |
375 | CONDITION(m_currentInterface, "end of property found outside interface.");␊ |
376 | m_currentProperty->endBodyLine = lineNumber();␊ |
377 | m_currentInterface->addSubEntry(m_currentProperty);␊ |
378 | m_currentProperty = 0;␊ |
379 | }␊ |
380 | ␊ |
381 | if (DBUS("arg"))␊ |
382 | {␊ |
383 | CONDITION(m_currentMethod, "end of arg found outside method.");␊ |
384 | m_currentMethod->argList->append(m_currentArgument);␊ |
385 | m_currentArgument = 0;␊ |
386 | }␊ |
387 | ␊ |
388 | if (EXTENSION("namespace"))␊ |
389 | {␊ |
390 | Entry * current = m_namespaceStack.last();␊ |
391 | CONDITION(current, "end of namespace without start.");␊ |
392 | m_namespaceStack.removeLast();␊ |
393 | ␊ |
394 | current->endBodyLine = lineNumber();␊ |
395 | closeScopes();␊ |
396 | }␊ |
397 | ␊ |
398 | if (EXTENSION("struct"))␊ |
399 | {␊ |
400 | StructData * data = m_structStack.last();␊ |
401 | CONDITION(data, "end of struct without start.");␊ |
402 | ␊ |
403 | data->entry->endBodyLine = lineNumber();␊ |
404 | ␊ |
405 | QString current_type;␊ |
406 | current_type.append(QString("("));␊ |
407 | current_type.append(data->type);␊ |
408 | current_type.append(QString(")"));␊ |
409 | ␊ |
410 | addNamedType(current_type);␊ |
411 | ␊ |
412 | closeScopes();␊ |
413 | ␊ |
414 | m_structStack.removeLast();␊ |
415 | }␊ |
416 | ␊ |
417 | if (EXTENSION("member"))␊ |
418 | {␊ |
419 | StructData * data = m_structStack.last();␊ |
420 | CONDITION(data, "end of struct without start");␊ |
421 | data->entry->addSubEntry(m_currentEntry);␊ |
422 | }␊ |
423 | ␊ |
424 | if (EXTENSION("enum") || EXTENSION("flagset"))␊ |
425 | {␊ |
426 | CONDITION(m_currentEnum, "end of enum without start");␊ |
427 | m_currentEnum->endBodyLine = lineNumber();␊ |
428 | closeScopes();␊ |
429 | ␊ |
430 | m_currentEnum = 0;␊ |
431 | }␊ |
432 | ␊ |
433 | if (EXTENSION("value"))␊ |
434 | {␊ |
435 | CONDITION(m_currentEntry, "end of value without start");␊ |
436 | m_currentEntry->endBodyLine = lineNumber();␊ |
437 | ␊ |
438 | m_currentEnum->addSubEntry(m_currentEntry);␊ |
439 | }␊ |
440 | ␊ |
441 | return true;␊ |
442 | }␊ |
443 | ␊ |
444 | bool characters(const QString & /*chars*/)␊ |
445 | { return true; }␊ |
446 | ␊ |
447 | bool comment(const QString & comment_)␊ |
448 | {␊ |
449 | if (m_currentComment)␊ |
450 | { handleComment(); }␊ |
451 | ␊ |
452 | m_currentComment = new CommentData(m_fileName, lineNumber(), comment_);␊ |
453 | ␊ |
454 | if (!m_currentComment->shouldIgnore)␊ |
455 | {␊ |
456 | delete m_currentComment;␊ |
457 | m_currentComment = 0;␊ |
458 | return true;␊ |
459 | }␊ |
460 | ␊ |
461 | if (m_currentComment->associateWithPrevious)␊ |
462 | { handleComment(); }␊ |
463 | ␊ |
464 | return true;␊ |
465 | }␊ |
466 | ␊ |
467 | void handleComment()␊ |
468 | {␊ |
469 | if (m_currentComment == 0 || m_currentEntry == 0)␊ |
470 | { return; }␊ |
471 | ␊ |
472 | QCString text(m_currentComment->text);␊ |
473 | ␊ |
474 | m_currentEntry->docFile = m_currentComment->fileName;␊ |
475 | m_currentEntry->docLine = m_currentComment->line;␊ |
476 | ␊ |
477 | int position(0);␊ |
478 | bool needs_entry(false);␊ |
479 | bool brief(false);␊ |
480 | Protection prot(Public);␊ |
481 | int lineNr = lineNumber();␊ |
482 | ␊ |
483 | while (parseCommentBlock(m_parser,␊ |
484 | m_currentEntry,␊ |
485 | text, m_fileName.utf8().data(), ␊ |
486 | lineNr,␊ |
487 | brief, m_currentComment->isJavaStyle,␊ |
488 | false,␊ |
489 | prot,␊ |
490 | position,␊ |
491 | needs_entry))␊ |
492 | {␊ |
493 | if (needs_entry) { createEntry(); }␊ |
494 | }␊ |
495 | if (needs_entry) { createEntry(); }␊ |
496 | ␊ |
497 | delete m_currentComment;␊ |
498 | m_currentComment = 0;␊ |
499 | }␊ |
500 | ␊ |
501 | QXmlLocator * locator()␊ |
502 | { return &m_locator; }␊ |
503 | ␊ |
504 | int lineNumber()␊ |
505 | { return m_locator.lineNumber(); }␊ |
506 | ␊ |
507 | void setSection()␊ |
508 | {␊ |
509 | Entry * current = createEntry();␊ |
510 | current->reset();␊ |
511 | ␊ |
512 | current->name = m_fileName.utf8();␊ |
513 | current->section = Entry::SOURCE_SEC;␊ |
514 | ␊ |
515 | // Open/Close the scope to do the bookkeeping:␊ |
516 | openScopes(current);␊ |
517 | closeScopes();␊ |
518 | }␊ |
519 | ␊ |
520 | private:␊ |
521 | bool isDBusElement(const QString & namespaceURI,␊ |
522 | const QString & localName,␊ |
523 | const QString & qName,␊ |
524 | const QString & element)␊ |
525 | {␊ |
526 | return (namespaceURI.isEmpty() && localName == element && qName == element) ||␊ |
527 | (namespaceURI.isEmpty() && localName.isEmpty() && qName == element);␊ |
528 | }␊ |
529 | ␊ |
530 | bool isExtensionElement(const QString & namespaceURI,␊ |
531 | const QString & localName,␊ |
532 | const QString & qName,␊ |
533 | const QString & element)␊ |
534 | {␊ |
535 | // isNull happens in startelement if no URI is used.␊ |
536 | if (namespaceURI.isNull())␊ |
537 | { return false; }␊ |
538 | ␊ |
539 | // We are in a endElement: URI is always empty there:-(␊ |
540 | if (namespaceURI.isEmpty())␊ |
541 | { return qName == m_scopeStack.last()->extensionPrefix + element; }␊ |
542 | ␊ |
543 | // startElemennt: We need to save the qName prefix␊ |
544 | // since endElement will forget about the namespaceURi:-(␊ |
545 | if (namespaceURI == EXTENSION_URI)␊ |
546 | {␊ |
547 | int pos = qName.find(':');␊ |
548 | m_scopeStack.last()->extensionPrefix = qName.left(pos + 1);␊ |
549 | }␊ |
550 | ␊ |
551 | return namespaceURI == EXTENSION_URI && localName == element;␊ |
552 | }␊ |
553 | ␊ |
554 | bool hasType(const QXmlAttributes & attributes)␊ |
555 | {␊ |
556 | const int type_idx(indexOf(attributes, "type"));␊ |
557 | const int named_type_idx(indexOf(attributes, "named-type"));␊ |
558 | ␊ |
559 | return named_type_idx >= 0 || type_idx >= 0;␊ |
560 | }␊ |
561 | ␊ |
562 | QString getType(const QXmlAttributes & attributes)␊ |
563 | {␊ |
564 | const int type_idx(indexOf(attributes, "type"));␊ |
565 | const int named_type_idx(indexOf(attributes, "named-type"));␊ |
566 | ␊ |
567 | QString type;␊ |
568 | ␊ |
569 | if (named_type_idx >= 0)␊ |
570 | {␊ |
571 | type = attributes.value(named_type_idx);␊ |
572 | if (!type.startsWith("::"))␊ |
573 | { type = getCurrentScope(attributes.value(named_type_idx)); }␊ |
574 | else␊ |
575 | { type = type.mid(2); }␊ |
576 | if (m_namedTypeMap.contains(type))␊ |
577 | {␊ |
578 | if (type_idx >= 0)␊ |
579 | {␊ |
580 | const QString dbus_type(attributes.value(type_idx));␊ |
581 | if (dbus_type != m_namedTypeMap[type])␊ |
582 | {␊ |
583 | DOC_ERROR(QString("Type \"%1\" does not match up with "␊ |
584 | "previous definition of named type \"%2\" (which was \"%3\".").␊ |
585 | arg(dbus_type).␊ |
586 | arg(type).␊ |
587 | arg(m_namedTypeMap[type]));␊ |
588 | }␊ |
589 | }␊ |
590 | return type;␊ |
591 | }␊ |
592 | ␊ |
593 | DOC_ERROR(QString("Undefined named type \"%1\" used.").arg(type));␊ |
594 | }␊ |
595 | ␊ |
596 | if (type_idx >= 0)␊ |
597 | {␊ |
598 | type = attributes.value(type_idx);␊ |
599 | ␊ |
600 | QRegExp reg_exp(QCString("(a?[ybnqiuxdtsogv]|a[{]sv[}])"));␊ |
601 | if (reg_exp.match(type.data()))␊ |
602 | { return type; }␊ |
603 | ␊ |
604 | DOC_ERROR(QString("Unnamed complex D-Bus type \"%1\" found.").arg(type));␊ |
605 | }␊ |
606 | ␊ |
607 | return QString();␊ |
608 | }␊ |
609 | ␊ |
610 | QString getDBusType(const QString & type)␊ |
611 | {␊ |
612 | QString scoped_type = type;␊ |
613 | if (!scoped_type.contains("::"))␊ |
614 | { scoped_type = getCurrentScope(type); }␊ |
615 | ␊ |
616 | if (m_namedTypeMap.contains(scoped_type))␊ |
617 | { return m_namedTypeMap[scoped_type]; }␊ |
618 | else␊ |
619 | { return type; }␊ |
620 | }␊ |
621 | ␊ |
622 | void addNamedType(const QString type)␊ |
623 | {␊ |
624 | QString scoped_name(getCurrentScope());␊ |
625 | ␊ |
626 | if (m_namedTypeMap.contains(scoped_name))␊ |
627 | {␊ |
628 | DOC_ERROR(QString("Named type \"%1\" is already defined.").arg(scoped_name));␊ |
629 | return;␊ |
630 | }␊ |
631 | ␊ |
632 | m_namedTypeMap.insert(scoped_name, type);␊ |
633 | }␊ |
634 | ␊ |
635 | QString getCurrentScope(const QString & type = QString())␊ |
636 | {␊ |
637 | QString scoped_name;␊ |
638 | if (!m_scopeStack.isEmpty())␊ |
639 | {␊ |
640 | scoped_name = m_scopeStack.last()->scope->name;␊ |
641 | scoped_name.append("::");␊ |
642 | }␊ |
643 | if (!type.isEmpty())␊ |
644 | { scoped_name.append(type); }␊ |
645 | else␊ |
646 | { scoped_name = scoped_name.left(scoped_name.length() - 2); }␊ |
647 | ␊ |
648 | return scoped_name;␊ |
649 | }␊ |
650 | ␊ |
651 | int indexOf(const QXmlAttributes & attributes, const QString & name,␊ |
652 | const QString & type = "CDATA", const bool mandatory = true)␊ |
653 | {␊ |
654 | const int idx(attributes.index(name));␊ |
655 | if (idx < 0 || idx > attributes.length()) { return -1; }␊ |
656 | if (attributes.type(idx) != type) { return -1; }␊ |
657 | if (mandatory && attributes.value(idx).isEmpty()) { return -1; }␊ |
658 | ␊ |
659 | return idx;␊ |
660 | }␊ |
661 | ␊ |
662 | Entry * createEntry()␊ |
663 | {␊ |
664 | Entry * entry = new Entry();␊ |
665 | ␊ |
666 | entry->protection = Public ;␊ |
667 | entry->virt = Normal;␊ |
668 | entry->stat = false;␊ |
669 | entry->lang = SrcLangExt_XML;␊ |
670 | entry->spec = 0;␊ |
671 | ␊ |
672 | entry->fileName = m_fileName;␊ |
673 | entry->startLine = lineNumber();␊ |
674 | entry->bodyLine = lineNumber();␊ |
675 | ␊ |
676 | entry->callGraph = false;␊ |
677 | entry->callerGraph = false;␊ |
678 | ␊ |
679 | initGroupInfo(entry);␊ |
680 | ␊ |
681 | m_currentEntry = entry;␊ |
682 | ␊ |
683 | handleComment();␊ |
684 | ␊ |
685 | return entry;␊ |
686 | }␊ |
687 | ␊ |
688 | void openScopes(Entry * object)␊ |
689 | {␊ |
690 | int cur_scope_separator_pos = 0;␊ |
691 | int last_scope_separator_pos = 0;␊ |
692 | while (0 <= (cur_scope_separator_pos = object->name.find("::", last_scope_separator_pos)))␊ |
693 | {␊ |
694 | QString scope = object->name.mid(last_scope_separator_pos,␊ |
695 | cur_scope_separator_pos - last_scope_separator_pos);␊ |
696 | last_scope_separator_pos = cur_scope_separator_pos + 2;␊ |
697 | ␊ |
698 | Entry * current_namespace = openNamespace(scope);␊ |
699 | ␊ |
700 | if (!m_scopeStack.isEmpty())␊ |
701 | { m_scopeStack.last()->scope->addSubEntry(current_namespace); }␊ |
702 | ␊ |
703 | m_scopeStack.append(new ScopeData(current_namespace, m_scopeCount));␊ |
704 | }␊ |
705 | ␊ |
706 | QString scoped_name(getCurrentScope());␊ |
707 | if (!scoped_name.isEmpty())␊ |
708 | { scoped_name.append("::"); }␊ |
709 | scoped_name.append(object->name.mid(last_scope_separator_pos));␊ |
710 | ␊ |
711 | object->name = scoped_name;␊ |
712 | ␊ |
713 | if (!m_scopeStack.isEmpty())␊ |
714 | { m_scopeStack.last()->scope->addSubEntry(object); }␊ |
715 | m_scopeStack.append(new ScopeData(object, m_scopeCount));␊ |
716 | ␊ |
717 | ++m_scopeCount;␊ |
718 | }␊ |
719 | ␊ |
720 | Entry * openNamespace(const QString & name)␊ |
721 | {␊ |
722 | Entry * current_namespace = createEntry();␊ |
723 | QString scoped_name(getCurrentScope());␊ |
724 | if (!scoped_name.isEmpty())␊ |
725 | { scoped_name.append("::"); }␊ |
726 | scoped_name.append(name);␊ |
727 | current_namespace->name = scoped_name;␊ |
728 | current_namespace->section = Entry::NAMESPACE_SEC;␊ |
729 | current_namespace->type = "namespace" ;␊ |
730 | ␊ |
731 | return current_namespace;␊ |
732 | }␊ |
733 | ␊ |
734 | void closeScopes()␊ |
735 | {␊ |
736 | const int current_scope_count(m_scopeStack.last()->count);␊ |
737 | ␊ |
738 | // Do not close the root scope.␊ |
739 | if (current_scope_count == 0)␊ |
740 | { return; }␊ |
741 | ␊ |
742 | while (current_scope_count == m_scopeStack.last()->count)␊ |
743 | { m_scopeStack.removeLast(); }␊ |
744 | }␊ |
745 | ␊ |
746 | ParserInterface * m_parser;␊ |
747 | ␊ |
748 | QXmlLocator m_locator;␊ |
749 | QString m_currentNode; // Nodes can not be nested, no entry necessary.␊ |
750 | ␊ |
751 | struct ElementData␊ |
752 | {␊ |
753 | ElementData(const QString & e) :␊ |
754 | element(e)␊ |
755 | { }␊ |
756 | ~ElementData() { }␊ |
757 | ␊ |
758 | QString element; //*< The element name␊ |
759 | QString extensionPrefix; //*< The prefix used for our extension.␊ |
760 | QString text; //*< The actual xml code.␊ |
761 | };␊ |
762 | QList<ElementData> m_elementStack;␊ |
763 | ␊ |
764 | Entry * m_currentEntry; // The currently open entry.␊ |
765 | ␊ |
766 | Entry * m_currentInterface; // Interfaces can not be nested.␊ |
767 | Entry * m_currentMethod; // Methods can not be nested.␊ |
768 | Argument * m_currentArgument; // Arguments can not be nested.␊ |
769 | Entry * m_currentProperty; // Properties can not be nested.␊ |
770 | Entry * m_currentEnum; // Enums can not be nested.␊ |
771 | QList<Entry> m_namespaceStack;␊ |
772 | ␊ |
773 | struct StructData␊ |
774 | {␊ |
775 | StructData(Entry * e) : entry(e) { }␊ |
776 | ~StructData() { }␊ |
777 | ␊ |
778 | QString type;␊ |
779 | Entry * entry;␊ |
780 | };␊ |
781 | QList<StructData> m_structStack; // Structs can be nested.␊ |
782 | ␊ |
783 | struct ScopeData␊ |
784 | {␊ |
785 | ScopeData(Entry * s, int c) :␊ |
786 | scope(s),␊ |
787 | count(c)␊ |
788 | { }␊ |
789 | ~ScopeData() { }␊ |
790 | ␊ |
791 | Entry * scope;␊ |
792 | QString extensionPrefix;␊ |
793 | int count;␊ |
794 | };␊ |
795 | QList<ScopeData> m_scopeStack; // Scopes are nested.␊ |
796 | ␊ |
797 | QString m_fileName;␊ |
798 | ␊ |
799 | struct CommentData␊ |
800 | {␊ |
801 | CommentData(const QString & f, const int l, const QString & t) :␊ |
802 | isJavaStyle(false),␊ |
803 | isQtStyle(false),␊ |
804 | line(l),␊ |
805 | fileName(f)␊ |
806 | {␊ |
807 | isJavaStyle = t.startsWith(QChar('*'));␊ |
808 | isQtStyle = t.startsWith(QChar('!'));␊ |
809 | shouldIgnore = (!isJavaStyle && !isQtStyle);␊ |
810 | associateWithPrevious = (t.at(1) == QChar('<'));␊ |
811 | if (associateWithPrevious)␊ |
812 | { text = t.mid(2); }␊ |
813 | else␊ |
814 | { text = t.mid(1); }␊ |
815 | }␊ |
816 | ~CommentData() { }␊ |
817 | ␊ |
818 | QString text;␊ |
819 | bool isJavaStyle;␊ |
820 | bool isQtStyle;␊ |
821 | bool shouldIgnore;␊ |
822 | bool associateWithPrevious;␊ |
823 | int line;␊ |
824 | QString fileName;␊ |
825 | };␊ |
826 | CommentData * m_currentComment;␊ |
827 | ␊ |
828 | int m_scopeCount; //*< unique scope id.␊ |
829 | ␊ |
830 | QString m_errorString;␊ |
831 | ␊ |
832 | QMap<QString, QString> m_namedTypeMap;␊ |
833 | };␊ |
834 | ␊ |
835 | // -----------------------------------------------------------------------␊ |
836 | // DBusXMLScanner␊ |
837 | // -----------------------------------------------------------------------␊ |
838 | ␊ |
839 | DBusXMLScanner::DBusXMLScanner()␊ |
840 | { }␊ |
841 | ␊ |
842 | DBusXMLScanner::~DBusXMLScanner()␊ |
843 | { }␊ |
844 | ␊ |
845 | void DBusXMLScanner::parseInput(const char * fileName,␊ |
846 | const char * /* fileBuf */,␊ |
847 | Entry * root)␊ |
848 | {␊ |
849 | err("Note that the dbusxml parser seems to be broken :-(\nPlease help me to fix it!\n");␊ |
850 | QFile inputFile(fileName);␊ |
851 | ␊ |
852 | QXmlInputSource inputSource(inputFile);␊ |
853 | QXmlSimpleReader reader;␊ |
854 | ␊ |
855 | DBusXMLHandler handler(this, &reader, fileName, root);␊ |
856 | reader.setContentHandler(&handler);␊ |
857 | reader.setErrorHandler(&handler);␊ |
858 | reader.setLexicalHandler(&handler);␊ |
859 | ␊ |
860 | groupEnterFile(fileName, 1);␊ |
861 | handler.setSection();␊ |
862 | reader.parse(inputSource);␊ |
863 | ␊ |
864 | if (handler.errorString())␊ |
865 | { err("DBus XML Parser: Error at line %d: %s\n", ␊ |
866 | handler.locator()->lineNumber(),handler.errorString().utf8().data()); }␊ |
867 | ␊ |
868 | groupLeaveFile(fileName, 1);␊ |
869 | }␊ |
870 | ␊ |
871 | bool DBusXMLScanner::needsPreprocessing(const QCString & /* extension */)␊ |
872 | { return (false); }␊ |
873 | ␊ |
874 | void DBusXMLScanner::parseCode(CodeOutputInterface & /* codeOutIntf */,␊ |
875 | const char * /* scopeName */,␊ |
876 | const QCString & /* input */,␊ |
877 | bool /* isExampleBlock */,␊ |
878 | const char * /* exampleName */,␊ |
879 | FileDef * /* fileDef */,␊ |
880 | int /* startLine */,␊ |
881 | int /* endLine */,␊ |
882 | bool /* inlineFragment */,␊ |
883 | MemberDef * /* memberDef */,␊ |
884 | bool /*showLineNumbers*/)␊ |
885 | { }␊ |
886 | ␊ |
887 | void DBusXMLScanner::resetCodeParserState()␊ |
888 | { }␊ |
889 | ␊ |
890 | void DBusXMLScanner::parsePrototype(const char * /* text */)␊ |
891 | { }␊ |
892 |