diff --git a/examples/dbusxml.cfg b/examples/dbusxml.cfg
new file mode 100644
index 0000000..e5f6b18
--- /dev/null
+++ b/examples/dbusxml.cfg
@@ -0,0 +1,10 @@
+PROJECT_NAME = "DBusXMLDocs"
+OUTPUT_DIRECTORY = dbusxml
+GENERATE_LATEX = NO
+GENERATE_MAN = NO
+GENERATE_RTF = NO
+CASE_SENSE_NAMES = NO
+INPUT = dbusxml.xml
+QUIET = NO
+JAVADOC_AUTOBRIEF = YES
+EXTRACT_ALL = YES
diff --git a/examples/dbusxml.xml b/examples/dbusxml.xml
new file mode 100644
index 0000000..d1f0c1f
--- /dev/null
+++ b/examples/dbusxml.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/dbusxmlscanner.cpp b/src/dbusxmlscanner.cpp
new file mode 100644
index 0000000..edd1d71
--- /dev/null
+++ b/src/dbusxmlscanner.cpp
@@ -0,0 +1,455 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 2009 by Tobias Hunger
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#include "dbusxmlscanner.h"
+
+#include "commentscan.h"
+#include "entry.h"
+
+#include
+#include
+#include
+
+#include "message.h"
+
+// -----------------------------------------------------------------------
+// DBusXMLHandler class
+// -----------------------------------------------------------------------
+
+class DBusXMLHandler : public QXmlDefaultHandler
+{
+public:
+ DBusXMLHandler(ParserInterface * parser,
+ QXmlSimpleReader * reader,
+ const char * file_name,
+ Entry * root) :
+ m_parser(parser),
+ m_locator(reader),
+ m_globalRoot(root),
+ m_currentInterface(0),
+ m_currentMethod(0),
+ m_currentArgument(0),
+ m_currentEntry(0),
+ m_fileName(file_name)
+ { setDocumentLocator(&m_locator); }
+
+ ~DBusXMLHandler()
+ { }
+
+ bool startElement(const QString &namespaceURI,
+ const QString &localName,
+ const QString &qName,
+ const QXmlAttributes &attributes)
+ {
+ //
+ msg("startElement: %d: %s, %s, %s.\n", lineNumber(), namespaceURI.ascii(), localName.ascii(), qName.ascii());
+ for(int i = 0; i < attributes.length(); ++i)
+ {
+ msg(" Attributes: %s, %s, %s, %s, %s\n",
+ attributes.uri(i).ascii(),
+ attributes.localName(i).ascii(),
+ attributes.qName(i).ascii(),
+ attributes.type(i).ascii(),
+ attributes.value(i).ascii());
+ }
+ //
+
+ // add to elements stack:
+ m_openElements.prepend(qName);
+
+ // First we need a node.
+ if (isDBusElement(namespaceURI, localName, qName, "node"))
+ {
+ if (!m_currentNode.isEmpty())
+ {
+ // node inside a node: not allowed.
+ return false;
+ }
+ const int idx(indexOf(attributes, "name"));
+ if (idx < 0) { return false; }
+
+ m_currentNode = attributes.value(idx);
+ // A node is actually of little interest, so do nothing here.
+ msg("**** Node name: %s.\n", m_currentNode.ascii());
+ return true;
+ }
+
+ // Then we need an interface.
+ if (isDBusElement(namespaceURI, localName, qName, "interface"))
+ {
+ // We need a nodeName for interfaces:
+ if (m_currentNode.isEmpty())
+ {
+ msg("*********** NO NODE **********\n");
+ return false;
+ }
+
+ if (m_currentInterface)
+ {
+ // interface within an interface: not allowed.
+ msg("*********** Interface inside another interface **********\n");
+ return false;
+ }
+ const int idx(indexOf(attributes, "name"));
+ if (idx < 0) { return false; }
+
+ // A interface is roughly equivalent to a class:
+ m_currentInterface = createEntry();
+
+ m_currentInterface->section = Entry::CLASS_SEC;
+ m_currentInterface->spec = Entry::DBusInterface;
+ m_currentInterface->type = "Interface";
+ m_currentInterface->name = attributes.value(idx);
+
+ msg("**** Interface name: %s.\n", m_currentInterface->name.data());
+
+ return true;
+ }
+
+ if (isDBusElement(namespaceURI, localName, qName, "method") ||
+ isDBusElement(namespaceURI, localName, qName, "signal"))
+ {
+ // We need a interfaceName for methods and signals:
+ if (!m_currentInterface)
+ {
+ msg("*********** NO INTERFACE **********\n");
+ return false;
+ }
+
+ if (m_currentMethod)
+ {
+ // method within a method: not allowed.
+ msg("*********** Method/signal inside another method/signal **********\n");
+ return false;
+ }
+ const int idx(indexOf(attributes, "name"));
+ if (idx < 0) { return false; }
+
+ m_currentMethod = createEntry();
+
+ m_currentMethod->section = Entry::FUNCTION_SEC;
+ m_currentMethod->spec = Entry::DBus;
+ m_currentMethod->name = attributes.value(idx);
+ m_currentMethod->mtype = Method;
+ m_currentMethod->type = "void";
+
+ if (isDBusElement(namespaceURI, localName, qName, "signal"))
+ { m_currentMethod->mtype = Signal; }
+ }
+
+ if (isDBusElement(namespaceURI, localName, qName, "arg"))
+ {
+ // We need a method for arguments:
+ if (!m_currentMethod)
+ {
+ msg("*********** NO METHOD **********\n");
+ return false;
+ }
+
+ if (m_currentArgument)
+ {
+ // method within a method: not allowed.
+ msg("*********** Argument inside another argument **********\n");
+ return false;
+ }
+ const int name_idx(indexOf(attributes, "name"));
+ if (name_idx < 0) { return false; }
+
+ const int type_idx(indexOf(attributes, "type"));
+ if (type_idx < 0) { return false; }
+
+ const int direction_idx(indexOf(attributes, "direction"));
+
+ if (m_currentMethod->mtype == Signal &&
+ direction_idx >= 0 &&
+ attributes.value(direction_idx) != "in")
+ {
+ msg("********** Invalid direction for argument to signal **********\n");
+ return false;
+ }
+
+ m_currentArgument = new Argument;
+ m_currentArgument->type = attributes.value(type_idx);
+ m_currentArgument->name = attributes.value(name_idx);
+ if (direction_idx >= 0)
+ { m_currentArgument->attrib = attributes.value(direction_idx); }
+ else
+ {
+ if (m_currentMethod->mtype == Signal)
+ { m_currentArgument->attrib = "in"; }
+ else
+ { m_currentArgument->attrib = "out"; }
+ }
+ }
+
+ return true;
+ }
+
+ bool endElement(const QString &namespaceURI,
+ const QString &localName,
+ const QString &qName)
+ {
+ //
+ msg("endElement: %d: %s, %s, %s.\n", lineNumber(), namespaceURI.ascii(), localName.ascii(), qName.ascii());
+ //
+
+ // Clean up elements stack:
+ // Since we made sure to get the elements in the proper order when
+ // adding we do not need to do so again here.
+ if (m_openElements.isEmpty() || m_openElements.first() != qName)
+ {
+ // Malformed XML:
+ msg("*********** MALFORMED XML **********\n");
+ return false;
+ }
+ m_openElements.remove(m_openElements.begin());
+
+ // Interface:
+ if (isDBusElement(namespaceURI, localName, qName, "interface"))
+ {
+ msg("**** Interface: CLOSED.\n");
+ m_currentInterface->endBodyLine = lineNumber();
+ m_globalRoot->addSubEntry(m_currentInterface);
+
+ m_currentInterface = 0;
+ }
+
+ if (isDBusElement(namespaceURI, localName, qName, "method") ||
+ isDBusElement(namespaceURI, localName, qName, "signal"))
+ {
+ msg("**** Method: CLOSED.\n");
+ m_currentMethod->endBodyLine = lineNumber();
+ m_currentInterface->addSubEntry(m_currentMethod);
+
+ m_currentMethod = 0;
+ }
+
+ if (isDBusElement(namespaceURI, localName, qName, "arg"))
+ {
+ m_currentMethod->argList->append(m_currentArgument);
+ m_currentArgument = 0;
+ }
+
+ return true;
+ }
+
+ bool characters(const QString & chars)
+ {
+ // msg("characters: %s.\n", str.ascii());
+ return true;
+ }
+
+ bool comment(const QString & comment_)
+ {
+ msg("**** Comment: %s.\n", comment_.utf8().data());
+ if (!m_comment.isEmpty())
+ {
+ handleComment();
+ }
+
+ m_commentIsJavaStyle = comment_.startsWith(QChar('*'));
+ m_commentIsQtStyle = comment_.startsWith(QChar('!'));
+
+ if (!m_commentIsJavaStyle && !m_commentIsQtStyle)
+ { return true; }
+
+ m_commentLine = lineNumber();
+
+ if (comment_.at(1) == QChar('<'))
+ {
+ msg("ADDING TO PREVIOUS NODE.");
+ m_comment = comment_.mid(2);
+ handleComment();
+ }
+ else
+ { m_comment = comment_.mid(1); }
+
+ return true;
+ }
+
+ void handleComment()
+ {
+ if (m_comment.isEmpty() ||
+ m_currentEntry == 0) { return; }
+
+ msg("**** adding comment %s to node %s.\n",
+ m_comment.utf8().data(),
+ m_currentEntry->name.data());
+
+ QCString text(m_comment);
+
+ m_currentEntry->docFile = m_fileName;
+ m_currentEntry->docLine = m_commentLine;
+
+ int position(0);
+ bool needs_entry(false);
+ bool brief(false);
+ Protection prot(Public);
+
+ while (parseCommentBlock(m_parser,
+ m_currentEntry,
+ text, m_fileName.utf8().data(), lineNumber(),
+ brief, m_commentIsJavaStyle,
+ false,
+ prot,
+ position,
+ needs_entry))
+ {
+ if (needs_entry) { createEntry(); }
+ }
+ if (needs_entry) { createEntry(); }
+
+ m_comment = "";
+ }
+
+ QXmlLocator * locator()
+ { return &m_locator; }
+
+ int lineNumber()
+ { return m_locator.lineNumber(); }
+
+ void setSection()
+ {
+ Entry * current = createEntry();
+ current->reset();
+
+ current->name = m_fileName.utf8();
+ current->section = Entry::SOURCE_SEC;
+ m_globalRoot->addSubEntry(current);
+ }
+
+private:
+ bool isDBusElement(const QString & namespaceURI,
+ const QString & localName,
+ const QString & qName,
+ const QString & element)
+ {
+ return (namespaceURI.isEmpty() && localName == element && qName == element) ||
+ (namespaceURI.isEmpty() && localName.isEmpty() && qName == element);
+ }
+
+ int indexOf(const QXmlAttributes & attributes, const QString & name,
+ const QString & type = "CDATA", const bool mandatory = true)
+ {
+ const int idx(attributes.index(name));
+ if (idx < 0 || idx > attributes.length()) { return -1; }
+ if (attributes.type(idx) != type) { return -1; }
+ if (mandatory && attributes.value(idx).isEmpty()) { return -1; }
+
+ return idx;
+ }
+
+ Entry * createEntry()
+ {
+ Entry * entry = new Entry();
+
+ entry->protection = Public ;
+ entry->virt = Normal;
+ entry->stat = false;
+ entry->objc = false;
+
+ entry->fileName = m_fileName;
+ entry->startLine = lineNumber();
+ entry->bodyLine = lineNumber();
+
+ entry->callGraph = false;
+ entry->callerGraph = false;
+
+ initGroupInfo(entry);
+
+ m_currentEntry = entry;
+
+ handleComment();
+
+ return entry;
+ }
+
+ ParserInterface * m_parser;
+ QXmlLocator m_locator;
+ QString m_currentNode;
+ QStringList m_openElements;
+
+ Entry * m_globalRoot;
+ Entry * m_currentInterface;
+ Entry * m_currentMethod;
+ Argument * m_currentArgument;
+ Entry * m_currentEntry;
+
+ QString m_fileName;
+
+ QString m_comment;
+ bool m_commentIsJavaStyle;
+ bool m_commentIsQtStyle;
+ int m_commentLine;
+};
+
+// -----------------------------------------------------------------------
+// DBusXMLScanner
+// -----------------------------------------------------------------------
+
+DBusXMLScanner::DBusXMLScanner()
+{ }
+
+DBusXMLScanner::~DBusXMLScanner()
+{ }
+
+void DBusXMLScanner::parseInput(const char *fileName,
+ const char *fileBuf,
+ Entry *root)
+{
+ QFile inputFile(fileName);
+
+ QXmlInputSource inputSource(inputFile);
+ QXmlSimpleReader reader;
+
+ DBusXMLHandler handler(this, &reader, fileName, root);
+ reader.setContentHandler(&handler);
+ reader.setErrorHandler(&handler);
+ reader.setLexicalHandler(&handler);
+
+ groupEnterFile(fileName, 1);
+ handler.setSection();
+ reader.parse(inputSource);
+ groupLeaveFile(fileName, 1);
+}
+
+bool DBusXMLScanner::needsPreprocessing(const QCString &extension)
+{ return (false); }
+
+void DBusXMLScanner::parseCode(CodeOutputInterface &codeOutIntf,
+ const char *scopeName,
+ const QCString &input,
+ bool isExampleBlock,
+ const char *exampleName,
+ FileDef *fileDef,
+ int startLine,
+ int endLine,
+ bool inlineFragment,
+ MemberDef *memberDef)
+{
+ msg("DBusXMLScanner::parseInput: parsing...\n");
+}
+
+void DBusXMLScanner::resetCodeParserState()
+{
+ msg("DBusXMLScanner::resetCodeParserState: Resetting...\n");
+}
+
+void DBusXMLScanner::parsePrototype(const char *text)
+{
+ msg("DBusXMLScanner::parsePrototype: parsing...\n");
+}
diff --git a/src/dbusxmlscanner.h b/src/dbusxmlscanner.h
new file mode 100644
index 0000000..3a4994e
--- /dev/null
+++ b/src/dbusxmlscanner.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 2009 by Tobias Hunger
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#ifndef SCANNER_DBUSXML_H
+#define SCANNER_DBUSXML_H
+
+#include "parserintf.h"
+
+/** \brief D-Bus XML parser.
+ *
+ * This is the D-Bus XML parser for doxygen.
+ */
+class DBusXMLScanner : public ParserInterface
+{
+public:
+ DBusXMLScanner();
+ virtual ~DBusXMLScanner();
+ void parseInput(const char *fileName,
+ const char *fileBuf,
+ Entry *root);
+
+ bool needsPreprocessing(const QCString &extension);
+
+ void parseCode(CodeOutputInterface &codeOutIntf,
+ const char *scopeName,
+ const QCString &input,
+ bool isExampleBlock,
+ const char *exampleName=0,
+ FileDef *fileDef=0,
+ int startLine=-1,
+ int endLine=-1,
+ bool inlineFragment=FALSE,
+ MemberDef *memberDef=0
+ );
+
+ void resetCodeParserState();
+
+ void parsePrototype(const char *text);
+
+private:
+};
+
+#endif
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 51bd291..44e010a 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -71,6 +71,7 @@
#include "htags.h"
#include "pyscanner.h"
#include "fortranscanner.h"
+#include "dbusxmlscanner.h"
#include "code.h"
#include "objcache.h"
#include "store.h"
@@ -9105,6 +9106,7 @@ void initDoxygen()
Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);
Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);
+ Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
// register any additional parsers here...
diff --git a/src/entry.h b/src/entry.h
index bf3ed40..2de442b 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -259,7 +259,8 @@ class Entry
NonAtomic = 0x040000,
Copy = 0x080000,
Retain = 0x100000,
- Assign = 0x200000
+ Assign = 0x200000,
+ DBus = 0x400000
};
enum ClassSpecifier
{
@@ -274,7 +275,8 @@ class Entry
Protocol = 0x0100,
Category = 0x0200,
SealedClass = 0x0400,
- AbstractClass = 0x0800
+ AbstractClass = 0x0800,
+ DBusInterface = 0x1000
};
enum GroupDocType
{
diff --git a/src/libdoxygen.pro.in b/src/libdoxygen.pro.in
index 2eabf69..ec2e93c 100644
--- a/src/libdoxygen.pro.in
+++ b/src/libdoxygen.pro.in
@@ -88,6 +88,7 @@ HEADERS = bufstr.h \
pyscanner.h \
fortrancode.h \
fortranscanner.h \
+ dbusxmlscanner.h \
qhp.h \
qhpxmlwriter.h \
qtbc.h \
@@ -229,6 +230,7 @@ SOURCES = ce_lex.cpp \
vhdlscanner.cpp \
xmldocvisitor.cpp \
xmlgen.cpp \
+ dbusxmlscanner.cpp \
win32:TMAKE_CXXFLAGS += -DQT_NODLL
win32-msvc:TMAKE_CXXFLAGS += -Zm200
diff --git a/src/util.cpp b/src/util.cpp
index 5072721..ef6131b 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -305,7 +305,8 @@ int guessSection(const char *name)
n.right(4)==".ixx" ||
n.right(4)==".ipp" ||
n.right(4)==".i++" ||
- n.right(4)==".inl"
+ n.right(4)==".inl" ||
+ n.right(4)==".xml"
) return Entry::SOURCE_SEC;
if (n.right(2)==".h" || // header
n.right(3)==".hh" ||
@@ -6443,6 +6444,7 @@ g_lang2extMap[] =
{ "python", "python", SrcLangExt_Python },
{ "fortran", "fortran", SrcLangExt_F90 },
{ "vhdl", "vhdl", SrcLangExt_VHDL },
+ { "dbusxml", "dbusxml", SrcLangExt_XML },
{ 0, 0, (SrcLangExt)0 }
};
@@ -6505,6 +6507,7 @@ void initDefaultExtensionMapping()
updateLanguageMapping(".f90", "fortran");
updateLanguageMapping(".vhd", "vhdl");
updateLanguageMapping(".vhdl", "vhdl");
+ updateLanguageMapping(".xml", "dbusxml");
}
SrcLangExt getLanguageFromFileName(const QCString fileName)
diff --git a/src/util.h b/src/util.h
index 2b248a3..1c56e90 100644
--- a/src/util.h
+++ b/src/util.h
@@ -95,7 +95,8 @@ enum SrcLangExt
SrcLangExt_JS = 0x0400,
SrcLangExt_Python = 0x0800,
SrcLangExt_F90 = 0x1000,
- SrcLangExt_VHDL = 0x2000
+ SrcLangExt_VHDL = 0x2000,
+ SrcLangExt_XML = 0x4000
};
//--------------------------------------------------------------------