+++ /dev/null
-"""
-Name: doxymlparser.py
-Author: Kevin Ollivier
-License: wxWidgets License
-"""
-
-__description__ = """
-Takes the output of Doxygen XML and parses it to retrieve metadata about the classes and methods.
-
-To create the Doxygen XML files, from the wxWidgets/docs/doxygen directory, do:
-
-./regen.sh xml
-
-To see the results from parsing a particular class, do:
-
-python doxymlparser.py --report out/xml/classwx_<whatever>.xml
-"""
-
-#!/usr/bin/env python
-import optparse
-import os
-import string
-
-import sys
-import types
-from xml.dom import minidom
-
-option_dict = {
- "report" : (False, "Print out the classes and methods found by this script."),
- "verbose" : (False, "Provide status updates and other information."),
- }
-
-parser = optparse.OptionParser(usage="usage: %prog [options] <doxyml files to parse>\n" + __description__, version="%prog 1.0")
-
-for opt in option_dict:
- default = option_dict[opt][0]
-
- action = "store"
- if type(default) == types.BooleanType:
- action = "store_true"
- parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1])
-
-options, arguments = parser.parse_args()
-
-def get_first_value(alist):
- if len(alist) > 0:
- return alist[0]
- else:
- return ""
-
-class ClassDefinition:
- def __init__(self):
- self.name = ""
- self.constructors = []
- self.destructors = []
- self.methods = []
- self.brief_description = ""
- self.detailed_description = ""
- self.includes = []
- self.bases = []
- self.enums = {}
-
- def __str__(self):
- str_repr = """
-Class: %s
-Bases: %s
-Includes: %s
-Brief Description:
-%s
-
-Detailed Description:
-%s
-""" % (self.name, string.join(self.bases, ", "), self.includes, self.brief_description, self.detailed_description)
- str_repr += "Methods:\n"
-
- for method in self.methods:
- str_repr += str(method)
-
- return str_repr
-
-class MethodDefinition:
- def __init__(self):
- self.name = ""
- self.return_type = ""
- self.argsstring = ""
- self.definition = ""
- self.params = []
- self.brief_description = ""
- self.detailed_description = ""
-
- def __str__(self):
- str_repr = """
-Method: %s
-Return Type: %s
-Params: %r
-Prototype: %s
-Brief Description:
-%s
-
-Detailed Description:
-%s
-""" % (self.name, self.return_type, self.params, self.definition + self.argsstring, self.brief_description, self.detailed_description)
- return str_repr
-
-def getTextValue(node, recursive=False):
- text = ""
- for child in node.childNodes:
- if child.nodeType == child.ELEMENT_NODE and child.nodeName == "ref":
- text += getTextValue(child)
- if child.nodeType == child.TEXT_NODE:
- # Add a space to ensure we have a space between qualifiers and parameter names
- text += child.nodeValue.strip() + " "
-
- return text.strip()
-
-def doxyMLToText(node):
- return text
-
-class DoxyMLParser:
- def __init__(self):
- self.classes = []
-
- def find_class(self, name):
- for aclass in self.classes:
- if aclass.name == name:
- return aclass
-
- return None
-
- def get_enums_and_functions(self, filename, aclass):
- file_path = os.path.dirname(filename)
- enum_filename = os.path.join(file_path, aclass.name[2:] + "_8h.xml")
- if os.path.exists(enum_filename):
- root = minidom.parse(enum_filename).documentElement
- for method in root.getElementsByTagName("memberdef"):
- if method.getAttribute("kind") == "enum":
- self.parse_enum(aclass, method, root)
-
- def is_derived_from_base(self, aclass, abase):
- base = get_first_value(aclass.bases)
- while base and base != "":
-
- if base == abase:
- return True
-
- parentclass = self.find_class(base)
-
- if parentclass:
- base = get_first_value(parentclass.bases)
- else:
- base = None
-
- return False
-
- def parse(self, filename):
- self.xmldoc = minidom.parse(filename).documentElement
- for node in self.xmldoc.getElementsByTagName("compounddef"):
- new_class = self.parse_class(node)
- self.classes.append(new_class)
- self.get_enums_and_functions(filename, new_class)
-
- def parse_class(self, class_node):
- new_class = ClassDefinition()
- new_class.name = getTextValue(class_node.getElementsByTagName("compoundname")[0])
- for node in class_node.childNodes:
- if node.nodeName == "basecompoundref":
- new_class.bases.append(getTextValue(node))
- elif node.nodeName == "briefdescription":
- # let the post-processor determ
- new_class.brief_description = node.toxml()
- elif node.nodeName == "detaileddescription":
- new_class.detailed_description = node.toxml()
- elif node.nodeName == "includes":
- new_class.includes.append(getTextValue(node))
-
- self.parse_methods(new_class, class_node)
-
- return new_class
-
- def parse_enum(self, new_class, enum, root):
- enum_name = ""
- enum_values = []
-
- for node in enum.childNodes:
- if node.nodeName == "name":
- enum_name = getTextValue(node)
- elif node.nodeName == "enumvalue":
- enum_values.append(getTextValue(node.getElementsByTagName("name")[0]))
-
- new_class.enums[enum_name] = enum_values
-
- def parse_methods(self, new_class, root):
- for method in root.getElementsByTagName("memberdef"):
- new_method = MethodDefinition()
- for node in method.childNodes:
- if node.nodeName == "name":
- new_method.name = getTextValue(node)
- elif node.nodeName == "type":
- new_method.return_type = getTextValue(node)
- elif node.nodeName == "definition":
- new_method.definition = getTextValue(node)
- elif node.nodeName == "argsstring":
- new_method.argsstring = getTextValue(node)
- elif node.nodeName == "param":
- param = {}
- for child in node.childNodes:
- if child.nodeType == child.ELEMENT_NODE:
- param[child.nodeName] = getTextValue(child)
- new_method.params.append(param)
-
- if options.verbose:
- print "Adding %s" % (new_method.name + new_method.argsstring)
-
- if new_method.name == new_class.name:
- new_class.constructors.append(new_method)
- elif new_method.name == "~" + new_class.name:
- new_class.destructors.append(new_method)
- else:
- new_class.methods.append(new_method)
-
-if __name__ == "__main__":
- if len(arguments) < 1:
- parser.print_usage()
- sys.exit(1)
-
- doxyparse = DoxyMLParser()
- for arg in arguments:
- doxyparse.parse(arg)
-
- if options.report:
- for aclass in doxyparse.classes:
- print str(aclass)
-
--- /dev/null
+"""
+Name: doxymlparser.py
+Author: Kevin Ollivier
+License: wxWidgets License
+"""
+
+__description__ = """
+Takes the output of Doxygen XML and parses it to retrieve metadata about the classes and methods.
+
+To create the Doxygen XML files, from the wxWidgets/docs/doxygen directory, do:
+
+./regen.sh xml
+
+To see the results from parsing a particular class, do:
+
+python doxymlparser.py --report out/xml/classwx_<whatever>.xml
+"""
+
+#!/usr/bin/env python
+import optparse
+import os
+import string
+
+import sys
+import types
+from xml.dom import minidom
+
+option_dict = {
+ "report" : (False, "Print out the classes and methods found by this script."),
+ "verbose" : (False, "Provide status updates and other information."),
+ }
+
+parser = optparse.OptionParser(usage="usage: %prog [options] <doxyml files to parse>\n" + __description__, version="%prog 1.0")
+
+for opt in option_dict:
+ default = option_dict[opt][0]
+
+ action = "store"
+ if type(default) == types.BooleanType:
+ action = "store_true"
+ parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1])
+
+options, arguments = parser.parse_args()
+
+def get_first_value(alist):
+ if len(alist) > 0:
+ return alist[0]
+ else:
+ return ""
+
+class ClassDefinition:
+ def __init__(self):
+ self.name = ""
+ self.constructors = []
+ self.destructors = []
+ self.methods = []
+ self.brief_description = ""
+ self.detailed_description = ""
+ self.includes = []
+ self.bases = []
+ self.enums = {}
+
+ def __str__(self):
+ str_repr = """
+Class: %s
+Bases: %s
+Includes: %s
+Brief Description:
+%s
+
+Detailed Description:
+%s
+""" % (self.name, string.join(self.bases, ", "), self.includes, self.brief_description, self.detailed_description)
+ str_repr += "Methods:\n"
+
+ for method in self.methods:
+ str_repr += str(method)
+
+ return str_repr
+
+class MethodDefinition:
+ def __init__(self):
+ self.name = ""
+ self.return_type = ""
+ self.argsstring = ""
+ self.definition = ""
+ self.params = []
+ self.brief_description = ""
+ self.detailed_description = ""
+
+ def __str__(self):
+ str_repr = """
+Method: %s
+Return Type: %s
+Params: %r
+Prototype: %s
+Brief Description:
+%s
+
+Detailed Description:
+%s
+""" % (self.name, self.return_type, self.params, self.definition + self.argsstring, self.brief_description, self.detailed_description)
+ return str_repr
+
+def getTextValue(node, recursive=False):
+ text = ""
+ for child in node.childNodes:
+ if child.nodeType == child.ELEMENT_NODE and child.nodeName == "ref":
+ text += getTextValue(child)
+ if child.nodeType == child.TEXT_NODE:
+ # Add a space to ensure we have a space between qualifiers and parameter names
+ text += child.nodeValue.strip() + " "
+
+ return text.strip()
+
+def doxyMLToText(node):
+ return text
+
+class DoxyMLParser:
+ def __init__(self):
+ self.classes = []
+
+ def find_class(self, name):
+ for aclass in self.classes:
+ if aclass.name == name:
+ return aclass
+
+ return None
+
+ def get_enums_and_functions(self, filename, aclass):
+ file_path = os.path.dirname(filename)
+ enum_filename = os.path.join(file_path, aclass.name[2:] + "_8h.xml")
+ if os.path.exists(enum_filename):
+ root = minidom.parse(enum_filename).documentElement
+ for method in root.getElementsByTagName("memberdef"):
+ if method.getAttribute("kind") == "enum":
+ self.parse_enum(aclass, method, root)
+
+ def is_derived_from_base(self, aclass, abase):
+ base = get_first_value(aclass.bases)
+ while base and base != "":
+
+ if base == abase:
+ return True
+
+ parentclass = self.find_class(base)
+
+ if parentclass:
+ base = get_first_value(parentclass.bases)
+ else:
+ base = None
+
+ return False
+
+ def parse(self, filename):
+ self.xmldoc = minidom.parse(filename).documentElement
+ for node in self.xmldoc.getElementsByTagName("compounddef"):
+ new_class = self.parse_class(node)
+ self.classes.append(new_class)
+ self.get_enums_and_functions(filename, new_class)
+
+ def parse_class(self, class_node):
+ new_class = ClassDefinition()
+ new_class.name = getTextValue(class_node.getElementsByTagName("compoundname")[0])
+ for node in class_node.childNodes:
+ if node.nodeName == "basecompoundref":
+ new_class.bases.append(getTextValue(node))
+ elif node.nodeName == "briefdescription":
+ # let the post-processor determ
+ new_class.brief_description = node.toxml()
+ elif node.nodeName == "detaileddescription":
+ new_class.detailed_description = node.toxml()
+ elif node.nodeName == "includes":
+ new_class.includes.append(getTextValue(node))
+
+ self.parse_methods(new_class, class_node)
+
+ return new_class
+
+ def parse_enum(self, new_class, enum, root):
+ enum_name = ""
+ enum_values = []
+
+ for node in enum.childNodes:
+ if node.nodeName == "name":
+ enum_name = getTextValue(node)
+ elif node.nodeName == "enumvalue":
+ enum_values.append(getTextValue(node.getElementsByTagName("name")[0]))
+
+ new_class.enums[enum_name] = enum_values
+
+ def parse_methods(self, new_class, root):
+ for method in root.getElementsByTagName("memberdef"):
+ new_method = MethodDefinition()
+ for node in method.childNodes:
+ if node.nodeName == "name":
+ new_method.name = getTextValue(node)
+ elif node.nodeName == "type":
+ new_method.return_type = getTextValue(node)
+ elif node.nodeName == "definition":
+ new_method.definition = getTextValue(node)
+ elif node.nodeName == "argsstring":
+ new_method.argsstring = getTextValue(node)
+ elif node.nodeName == "param":
+ param = {}
+ for child in node.childNodes:
+ if child.nodeType == child.ELEMENT_NODE:
+ param[child.nodeName] = getTextValue(child)
+ new_method.params.append(param)
+
+ if options.verbose:
+ print "Adding %s" % (new_method.name + new_method.argsstring)
+
+ if new_method.name == new_class.name:
+ new_class.constructors.append(new_method)
+ elif new_method.name == "~" + new_class.name:
+ new_class.destructors.append(new_method)
+ else:
+ new_class.methods.append(new_method)
+
+if __name__ == "__main__":
+ if len(arguments) < 1:
+ parser.print_usage()
+ sys.exit(1)
+
+ doxyparse = DoxyMLParser()
+ for arg in arguments:
+ doxyparse.parse(arg)
+
+ if options.report:
+ for aclass in doxyparse.classes:
+ print str(aclass)
+
--- /dev/null
+import doxymlparser
+import optparse
+import sys
+import os
+import string
+import types
+
+option_dict = {
+ "output_dir" : ("output", "Directory to output bindings to"),
+ "sip" : (True, "Produce SIP bindings"),
+ "swig" : (True, "Produce SWIG bindings."),
+
+}
+
+# format: class : {method : (prototype1, prototype2)}
+# using a "*" means all prototypes
+ignored_methods = {
+ "wxIcon": {'wxIcon': (['const char', 'int', 'int'], )},
+
+}
+
+# these classes are either replaced by different data types in bindings, or have equivalent / better
+# functionality provided by the target language.
+excluded_classes = [
+ "wxArchiveClassFactory",
+ "wxArchiveEntry",
+ "wxArchiveInputStream",
+ "wxArchiveIterator",
+ "wxArchiveNotifier",
+ "wxArchiveOutputStream",
+ "wxArray< T >",
+ "wxArrayString",
+ "wxAutomationObject",
+ "wxBufferedInputStream",
+ "wxBufferedOutputStream",
+ "wxCharBuffer",
+ "wxCharTypeBuffer",
+ "wxClassInfo",
+ "wxCmdLineParser",
+ "wxCondition",
+ "wxConnection",
+ "wxConnectionBase",
+ "wxConvAuto",
+ "wxCountingOutputStream",
+ "wxCriticalSection",
+ "wxCriticalSectionLocker",
+ "wxCSConv",
+ "wxDatagramSocket",
+ "wxDataInputStream",
+ "wxDataOutputStream",
+ "wxDir",
+ "wxDirTraverser",
+ "wxFFile",
+ "wxFFileInputStream",
+ "wxFFileOutputStream",
+ "wxFile",
+ "wxFileInputStream",
+ "wxFileName",
+ "wxFileOutputStream",
+ "wxFileStream",
+ "wxFilterClassFactory",
+ "wxFilterInputStream",
+ "wxFilterOutputStream",
+ "wxFSFile",
+ "wxFSVolume",
+ "wxFTP",
+ "wxHashMap",
+ "wxHashSet",
+ "wxHashTable",
+ "wxHTTP",
+ "wxImage::HSVValue",
+ "wxImage::RGBValue",
+ "wxInputStream",
+ "wxIPAddress",
+ "wxIPV4Address",
+ "wxList< T >",
+ "wxLongLong",
+ "wxMBConv",
+ "wxMBConvFile",
+ "wxMBConvUTF7",
+ "wxMBConvUTF8",
+ "wxMBConvUTF16",
+ "wxMBConvUTF32",
+ "wxMemoryBuffer",
+ "wxMemoryFSHandler",
+ "wxMemoryInputStream",
+ "wxMemoryOutputStream",
+ "wxMessageQueue< T >",
+ "wxModule",
+ "wxMutex",
+ "wxMutexLocker",
+ "wxNode< T >",
+ "wxObjectDataPtr< T >",
+ "wxObjectRefData",
+ "wxOutputStream",
+ "wxProcess",
+ "wxProcessEvent",
+ "wxProtocol",
+ "wxProtocolLog",
+ "wxRecursionGuard",
+ "wxRecursionGuardFlag",
+ "wxRegKey",
+ "wxScopedArray",
+ "wxScopedCharTypeBuffer",
+ "wxScopedPtr",
+ "wxScopedPtr< T >",
+ "wxSharedPtr< T >",
+ "wxServer",
+ "wxSockAddress",
+ "wxSocketBase",
+ "wxSocketClient",
+ "wxSocketEvent",
+ "wxSocketInputStream",
+ "wxSocketOutputStream",
+ "wxSortedArrayString",
+ "wxStopWatch",
+ "wxStreamBase",
+ "wxStreamBuffer",
+ "wxStreamToTextRedirector",
+ "wxString",
+ "wxStringBuffer",
+ "wxStringBufferLength",
+ "wxStringClientData",
+ "wxStringInputStream",
+ "wxStringOutputStream",
+ "wxTarClassFactory",
+ "wxTarEntry",
+ "wxTarInputStream",
+ "wxTarOutputStream",
+ "wxTCPClient",
+ "wxTCPConnection",
+ "wxTCPServer",
+ "wxTempFile",
+ "wxTempFileOutputStream",
+ "wxTextInputStream",
+ "wxTextOutputStream",
+ "wxThread",
+ "wxThreadEvent",
+ "wxThreadHelper",
+ "wxULongLong",
+ "wxUniChar",
+ "wxUniCharRef",
+ "wxURI",
+ "wxURL",
+ "wxUString",
+ "wxVariant",
+ "wxVariantData",
+ "wxVector< T >",
+ "wxVector< T >::reverse_iterator",
+ "wxWCharBuffer",
+ "wxWeakRef< T >",
+ "wxWeakRefDynamic< T >",
+ "wxZipInputStream",
+ "wxZipOutputStream",
+ "wxZlibInputStream",
+ "wxZlibOutputStream",
+ ]
+
+
+parser = optparse.OptionParser(usage="usage: %prog <doxyml files to parse>\n" , version="%prog 1.0")
+
+for opt in option_dict:
+ default = option_dict[opt][0]
+
+ action = "store"
+ if type(default) == types.BooleanType:
+ action = "store_true"
+ parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1])
+
+options, arguments = parser.parse_args()
+
+def get_first_value(alist):
+ if len(alist) > 0:
+ return alist[0]
+ else:
+ return ""
+
+def make_enums(aclass):
+ retval = ""
+ for enum in aclass.enums:
+ retval += "enum %s {\n" % enum
+ num_values = len(aclass.enums[enum])
+ for value in aclass.enums[enum]:
+ retval += " %s" % value
+ if not value == aclass.enums[enum][-1]:
+ retval += ", "
+ retval += "\n"
+ retval += "};\n\n"
+
+ return retval
+
+class SIPBuilder:
+ def __init__(self, doxyparse, outputdir):
+ self.doxyparser = doxyparse
+ self.output_dir = outputdir
+
+ def make_bindings(self):
+ output_dir = os.path.abspath(os.path.join(self.output_dir, "sip"))
+ if not os.path.exists(output_dir):
+ os.makedirs(output_dir)
+
+ for aclass in self.doxyparser.classes:
+ if aclass.name in excluded_classes:
+ print "Skipping %s" % aclass.name
+ continue
+
+ header_name = aclass.name[2:].lower()
+ filename = os.path.join(output_dir, header_name + ".sip")
+ enums_text = make_enums(aclass)
+ method_text = self.make_sip_methods(aclass)
+ base_class = get_first_value(aclass.bases)
+ if base_class != "":
+ base_class = ": %s" % base_class
+
+ text = """
+%s
+class %s %s
+{
+%%TypeHeaderCode
+#include <%s>
+%%End
+
+public:
+%s
+};
+""" % (enums_text, aclass.name, base_class, get_first_value(aclass.includes), method_text)
+
+ afile = open(filename, "wb")
+ afile.write(text)
+ afile.close()
+
+
+ def make_sip_methods(self, aclass):
+ retval = ""
+
+ for amethod in aclass.constructors + aclass.methods:
+ transfer = ""
+
+ # we need to come up with a way of filtering the methods out by various criteria
+ # including parameters and method name, and how to deal with overloads
+ if aclass.name in ignored_methods:
+ should_ignore = False
+ for method in ignored_methods[aclass.name]:
+ print "method = %s" % method
+ if method == amethod.name:
+ params = ignored_methods[aclass.name][method]
+ should_ignore = True
+ for i in xrange(len(params)):
+ if i >= len(amethod.params):
+ should_ignore = False
+ break
+ elif amethod.params[i]["type"] != params[i]:
+ print "param type = %s, amethod.param type = %s" % (params[i], amethod.params[i]["type"])
+ should_ignore = False
+ break
+
+ if should_ignore:
+ print "Ignoring method %s..." % amethod.name
+ continue
+
+ if amethod in aclass.constructors and self.doxyparser.is_derived_from_base(aclass, "wxWindow"):
+ transfer = "/Transfer/"
+
+ if amethod.name.startswith("operator"):
+ continue
+
+ retval += " %s %s%s%s;\n\n" % (amethod.return_type.replace("virtual ", ""), amethod.name, amethod.argsstring, transfer)
+
+ return retval
+
+
+
+class SWIGBuilder:
+ def __init__(self, doxyparse, outputdir):
+ self.doxyparser = doxyparse
+ self.output_dir = outputdir
+
+ def make_bindings(self):
+ output_dir = os.path.abspath(os.path.join(self.output_dir, "swig"))
+ if not os.path.exists(output_dir):
+ os.makedirs(output_dir)
+
+ for aclass in self.doxyparser.classes:
+ header_name = aclass.name[2:].lower()
+ if aclass.name in excluded_classes:
+ #print "Skipping %s" % aclass.name
+ continue
+
+ filename = os.path.join(output_dir, header_name + ".i")
+ enums_text = make_enums(aclass)
+ method_text = self.make_swig_methods(aclass)
+ text = """
+%%newgroup
+
+%s
+class %s : publib %s
+{
+
+public:
+%s
+};
+""" % (enums_text, aclass.name, get_first_value(aclass.bases), method_text)
+
+ afile = open(filename, "wb")
+ afile.write(text)
+ afile.close()
+
+
+ def make_swig_methods(self, aclass):
+ retval = ""
+
+ retval += """
+ %%pythonAppend %s "self._setOORInfo(self)"
+ %%pythonAppend %s() ""
+ %%typemap(out) %s*; // turn off this typemap
+ """ % (aclass.name, aclass.name, aclass.name)
+
+ for amethod in aclass.constructors:
+ retval += " %s%s;\n\n" % (amethod.name, amethod.argsstring)
+
+ retval += """
+ // Turn it back on again
+ %%typemap(out) %s* { $result = wxPyMake_wxObject($1, $owner); }
+ """ % aclass.name
+
+ for amethod in aclass.methods:
+ retval += " %s %s%s;\n\n" % (amethod.return_type, amethod.name, amethod.argsstring)
+
+ return retval
+
+
+if __name__ == "__main__":
+ if len(arguments) < 1:
+ parser.print_usage()
+ sys.exit(1)
+
+ doxyparse = doxymlparser.DoxyMLParser()
+ for arg in arguments:
+ doxyparse.parse(arg)
+
+ if options.sip:
+ builder = SIPBuilder(doxyparse, options.output_dir)
+ builder.make_bindings()
+
+ if options.swig:
+ builder = SWIGBuilder(doxyparse, options.output_dir)
+ builder.make_bindings()