#!/usr/bin/env python """Doxygen XML to SWIG docstring converter for ITK classes. Usage: itk_doxy2swig.py [input directory name] [output swing interface file name] """ import sys import os import glob from doxy2swig import * from io import StringIO class itkDoxy2SWIG(Doxy2SWIG): def __init__(self, src, cpp_name="", swig_name=""): Doxy2SWIG.__init__(self, src) self.cpp_name = cpp_name self.swig_name = swig_name def write_to_file(self, file): if self.multi: file.write("".join(self.pieces)) else: file.write("".join(self.clean_pieces(self.pieces))) def cpp_to_swig_name(self, cpp_name): if self.cpp_name == cpp_name: return self.swig_name return cpp_name def do_compoundname(self, node): self.add_text("\n\n") data = self.cpp_to_swig_name(node.firstChild.data) # print("=================", data) self.add_text('%%feature("docstring") %s "\n' % data) def do_memberdef(self, node): prot = node.attributes["prot"].value id = node.attributes["id"].value kind = node.attributes["kind"].value tmp = node.parentNode.parentNode.parentNode compdef = tmp.getElementsByTagName("compounddef")[0] cdef_kind = compdef.attributes["kind"].value if prot == "public": first = self.get_specific_nodes(node, ("definition", "name")) name = first["name"].firstChild.data if name[:8] == "operator": # Don't handle operators yet. return # store self.pieces to be able to restore it if the docstring is empty. pieces_backup = list(self.pieces) defn = first["definition"].firstChild.data self.add_text("\n") self.add_text('%feature("docstring") ') anc = node.parentNode.parentNode if cdef_kind in ("file", "namespace"): ns_node = anc.getElementsByTagName("innernamespace") if not ns_node and cdef_kind == "namespace": ns_node = anc.getElementsByTagName("compoundname") if ns_node: ns = ns_node[0].firstChild.data self.add_text(f' {ns}::{name} "\n{defn}') else: self.add_text(f' {name} "\n{defn}') elif cdef_kind in ("class", "struct"): # Get the full function name. anc_node = anc.getElementsByTagName("compoundname") cname = self.cpp_to_swig_name(anc_node[0].firstChild.data) # self.add_text(' %s::%s "\n%s'%(cname, name, defn)) self.add_text(f' {cname}::{name} "') # print("***", name, defn) # make sure that the docstring won't be empty before writing any text current_length = len(self.pieces) for n in node.childNodes: # if n not in first.values(): if n not in first.values() and ( n.__class__.__name__ != "Element" or "description" in n.tagName ): self.parse(n) # make sure that the docstring won't be empty before writing any text if current_length == len(self.pieces): # restore the old self.pieces self.pieces = pieces_backup else: self.add_text(['";', "\n"]) def d2s_dir(in_dir_name, out_swig_i): with open(in_dir_name) as conffile: output = StringIO() for l in conffile: l = l.strip() if l != "": ls = l.split("\t") xfn = ls[0] if os.path.isfile(xfn): # make sure the assumed file exists cpp_name = ls[1] # print("-- Doxygen to SWIG: " + cpp_name) output2 = StringIO() d2s = itkDoxy2SWIG(xfn, cpp_name, "@[{(]})@") d2s.generate() d2s.write_to_file(output2) tpl = output2.getvalue() output2.close() for swig_name in ls[2:]: output.write(tpl.replace("@[{(]})@", swig_name)) else: print(f"Warning: {xfn} does not exist. Ignore it.", file=sys.stderr) with open(out_swig_i, "w") as f: f.write(output.getvalue()) f.close() def main(in_dir_name, out_swig_i): d2s_dir(in_dir_name, out_swig_i) if __name__ == "__main__": if len(sys.argv) != 3: print(__doc__) sys.exit(1) main(sys.argv[1], sys.argv[2])