gnuradio-core/doc/Doxyfile \
gnuradio-core/doc/Makefile \
gnuradio-core/doc/other/Makefile \
- gnuradio-core/doc/xml/Makefile \
+ gnuradio-core/doc/xml-swig/Makefile \
gnuradio-core/src/Makefile \
gnuradio-core/src/gen_interpolator_taps/Makefile \
gnuradio-core/src/lib/Makefile \
include $(top_srcdir)/Makefile.common
-SUBDIRS = other xml
+SUBDIRS = other xml-swig
docdir = $(prefix)/share/doc/@PACKAGE@-@VERSION@
prep:
mkdir -p html
+ mkdir -p xml
install-data-local:
$(mkinstalldirs) $(DESTDIR)$(docdir)
--- /dev/null
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+EXTRA_DIST = README doxy2swig.py swig.xsl
+
+CLEANFILES = *.xml combine.xslt compound.xsd index.xsd
+
--- /dev/null
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+#
+# Generating Python docstrings from C++ code using doxygen
+#
+
+There are at least two strategies for this:
+ - use xsltproc as described below
+ - use doxy2swig.py (included in this directory)
+
+FIXME: get one of these working (probably doxy2swig since it doesn't
+add any additional dependencies).
+
+----------------------------------------------------------------
+
+Note: Robin's patch is in SWIG >= 1.3.23
+
+--------------------------------------------------------------------------------
+From: http://mailman.cs.uchicago.edu/pipermail/swig/2004-October/010604.html
+
+> I applied the docstring patch. '%feature("autodoc",1");' is working as
+> expected ...
+
+[problem solved. ...]
+
+> I can not agree more with the doxygen idea. I am using doxygen for
+> documentation and I have been trying to put doxygen output to the
+> python interface. Automatic generation of %feature("docstring") lines
+> from doxygen output is the closest solution I can think of but the
+> workload is still pretty big. How I wish this feature can be
+> implemented in the near future.
+
+I have successfully extracted function/class description from doxygen
+generated xml files, using an xslt script. To add doxygen generated
+description to each class/function, you will need to (tested under
+linux, note that this works only for Python, using Robin's docstring
+patch)
+
+1. download swig source, apply Robin's docstring patch from
+ https://sourceforge.net/tracker/index.php?func=detail&aid=1023309&group_id=1645&atid=301645
+ compile and install
+
+2. generate doxygen document with option "GENERATE_XML = YES"
+
+3. copy the attached script (save as swig.xsl) to the doc/xml directory
+ and run
+
+ > xsltproc swig.xsl index.xml > temp_doc.i
+ > cat temp_doc.i | sed 's/"/\\"/g' | sed 's/__QuOtE__/"/g' > swig_doc.i
+
+ you will get an interface file with lines like
+ %feature("docstring") class "class description";
+ %feature("docstring") class::function "member function
+ description";
+
+ the second step is necessary since there might be " in descriptions
+ and I need to backquote them before I replace __QuOtE__ by real
+ quotes. (xslt experts may know how to post-process <xsl:value-of> and
+ make the script easier to use.)
+
+4. in your interface file, add
+ %include "siwg_doc.i"
+ %feature("autodoc","1") ;
+
+Hope this helps.
+
+swig.xsl:
+=========================================================
+
+<!-- XSLT script to extract document for class/function for swig docstring
+ If you have xsltproc you could use:
+ xsltproc swig.xsl index.xml > swig_doc.i
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="text"/>
+ <xsl:template match="/">
+ <!-- process each compound -->
+ <xsl:for-each select="doxygenindex/compound">
+ <xsl:apply-templates select="document( concat( @refid, '.xml' ) )/*" />
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template match="doxygen">
+ <xsl:for-each select="compounddef[@kind='class']">
+ <xsl:text>%feature(__QuOtE__docstring__QuOtE__) </xsl:text>
+ <xsl:value-of select="compoundname"/>
+ <xsl:text> __QuOtE__ </xsl:text>
+ <xsl:value-of select="briefdescription"/><xsl:text>
+ </xsl:text>
+ <xsl:value-of select="detaileddescription"/>
+ <xsl:text> see also: </xsl:text>
+ <xsl:value-of select="includes"/>
+ <xsl:text>__QuOtE__; </xsl:text>
+
+ <!-- output for each function individually -->
+ <xsl:for-each select="*/memberdef[@kind='function' and not(starts-with(name,'operator'))]">
+ <xsl:text>%feature(__QuOtE__docstring__QuOtE__) </xsl:text><xsl:value-of select="../../compoundname"/>::<xsl:value-of select="name"/>
+ <xsl:text> __QuOtE__ </xsl:text>
+ <xsl:value-of select="definition"/> <xsl:value-of select="argsstring"/>
+ <xsl:text>
+ </xsl:text><xsl:value-of select="briefdescription"/><xsl:text>
+ </xsl:text><xsl:value-of select="detaileddescription"/>
+ <xsl:text>__QuOtE__; </xsl:text>
+ </xsl:for-each>
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>
+
+--
+Bo Peng
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python
+"""Doxygen XML to SWIG docstring converter.
+
+Converts Doxygen generated XML files into a file containing docstrings
+that can be used by SWIG-1.3.x. Note that you need to get SWIG
+version > 1.3.23 or use Robin Dunn's docstring patch to be able to use
+the resulting output.
+
+Usage:
+
+ doxy2swig.py input.xml output.i
+
+input.xml is your doxygen generated XML file and output.i is where the
+output will be written (the file will be clobbered).
+
+"""
+
+# This code is implemented using Mark Pilgrim's code as a guideline:
+# http://www.faqs.org/docs/diveintopython/kgp_divein.html
+#
+# Author: Prabhu Ramachandran
+# License: BSD style
+
+
+from xml.dom import minidom
+import re
+import textwrap
+import sys
+import types
+import os.path
+
+
+def my_open_read(source):
+ if hasattr(source, "read"):
+ return source
+ else:
+ return open(source)
+
+def my_open_write(dest):
+ if hasattr(dest, "write"):
+ return dest
+ else:
+ return open(dest, 'w')
+
+
+class Doxy2SWIG:
+ """Converts Doxygen generated XML files into a file containing
+ docstrings that can be used by SWIG-1.3.x that have support for
+ feature("docstring"). Once the data is parsed it is stored in
+ self.pieces.
+
+ """
+
+ def __init__(self, src):
+ """Initialize the instance given a source object (file or
+ filename).
+
+ """
+ f = my_open_read(src)
+ self.my_dir = os.path.dirname(f.name)
+ self.xmldoc = minidom.parse(f).documentElement
+ f.close()
+
+ self.pieces = []
+ self.pieces.append('\n// File: %s\n'%\
+ os.path.basename(f.name))
+
+ self.space_re = re.compile(r'\s+')
+ self.lead_spc = re.compile(r'^(%feature\S+\s+\S+\s*?)"\s+(\S)')
+ self.multi = 0
+ self.ignores = ('inheritancegraph', 'param', 'listofallmembers',
+ 'innerclass', 'name', 'declname', 'incdepgraph',
+ 'invincdepgraph', 'programlisting', 'type',
+ 'references', 'referencedby', 'location',
+ 'collaborationgraph', 'reimplements',
+ 'reimplementedby', 'derivedcompoundref',
+ 'basecompoundref')
+ #self.generics = []
+
+ def generate(self):
+ """Parses the file set in the initialization. The resulting
+ data is stored in `self.pieces`.
+
+ """
+ self.parse(self.xmldoc)
+
+ def parse(self, node):
+ """Parse a given node. This function in turn calls the
+ `parse_<nodeType>` functions which handle the respective
+ nodes.
+
+ """
+ pm = getattr(self, "parse_%s"%node.__class__.__name__)
+ pm(node)
+
+ def parse_Document(self, node):
+ self.parse(node.documentElement)
+
+ def parse_Text(self, node):
+ txt = node.data
+ txt = txt.replace('\\', r'\\\\')
+ txt = txt.replace('"', r'\"')
+ # ignore pure whitespace
+ m = self.space_re.match(txt)
+ if m and len(m.group()) == len(txt):
+ pass
+ else:
+ self.add_text(textwrap.fill(txt))
+
+ def parse_Element(self, node):
+ """Parse an `ELEMENT_NODE`. This calls specific
+ `do_<tagName>` handers for different elements. If no handler
+ is available the `generic_parse` method is called. All
+ tagNames specified in `self.ignores` are simply ignored.
+
+ """
+ name = node.tagName
+ ignores = self.ignores
+ if name in ignores:
+ return
+ attr = "do_%s" % name
+ if hasattr(self, attr):
+ handlerMethod = getattr(self, attr)
+ handlerMethod(node)
+ else:
+ self.generic_parse(node)
+ #if name not in self.generics: self.generics.append(name)
+
+ def add_text(self, value):
+ """Adds text corresponding to `value` into `self.pieces`."""
+ if type(value) in (types.ListType, types.TupleType):
+ self.pieces.extend(value)
+ else:
+ self.pieces.append(value)
+
+ def get_specific_nodes(self, node, names):
+ """Given a node and a sequence of strings in `names`, return a
+ dictionary containing the names as keys and child
+ `ELEMENT_NODEs`, that have a `tagName` equal to the name.
+
+ """
+ nodes = [(x.tagName, x) for x in node.childNodes \
+ if x.nodeType == x.ELEMENT_NODE and \
+ x.tagName in names]
+ return dict(nodes)
+
+ def generic_parse(self, node, pad=0):
+ """A Generic parser for arbitrary tags in a node.
+
+ Parameters:
+
+ - node: A node in the DOM.
+ - pad: `int` (default: 0)
+
+ If 0 the node data is not padded with newlines. If 1 it
+ appends a newline after parsing the childNodes. If 2 it
+ pads before and after the nodes are processed. Defaults to
+ 0.
+
+ """
+ npiece = 0
+ if pad:
+ npiece = len(self.pieces)
+ if pad == 2:
+ self.add_text('\n')
+ for n in node.childNodes:
+ self.parse(n)
+ if pad:
+ if len(self.pieces) > npiece:
+ self.add_text('\n')
+
+ def space_parse(self, node):
+ self.add_text(' ')
+ self.generic_parse(node)
+
+ do_ref = space_parse
+ do_emphasis = space_parse
+ do_bold = space_parse
+ do_computeroutput = space_parse
+ do_formula = space_parse
+
+ def do_compoundname(self, node):
+ self.add_text('\n\n')
+ data = node.firstChild.data
+ self.add_text('%%feature("docstring") %s "\n'%data)
+
+ def do_compounddef(self, node):
+ kind = node.attributes['kind'].value
+ if kind in ('class', 'struct'):
+ prot = node.attributes['prot'].value
+ if prot <> 'public':
+ return
+ names = ('compoundname', 'briefdescription',
+ 'detaileddescription', 'includes')
+ first = self.get_specific_nodes(node, names)
+ for n in names:
+ if first.has_key(n):
+ self.parse(first[n])
+ self.add_text(['";','\n'])
+ for n in node.childNodes:
+ if n not in first.values():
+ self.parse(n)
+ elif kind in ('file', 'namespace'):
+ nodes = node.getElementsByTagName('sectiondef')
+ for n in nodes:
+ self.parse(n)
+
+ def do_includes(self, node):
+ self.add_text('C++ includes: ')
+ self.generic_parse(node, pad=1)
+
+ def do_parameterlist(self, node):
+ self.add_text(['\n', '\n', 'Parameters:', '\n'])
+ self.generic_parse(node, pad=1)
+
+ def do_para(self, node):
+ self.add_text('\n')
+ self.generic_parse(node, pad=1)
+
+ def do_parametername(self, node):
+ self.add_text('\n')
+ self.add_text("%s: "%node.firstChild.data)
+
+ def do_parameterdefinition(self, node):
+ self.generic_parse(node, pad=1)
+
+ def do_detaileddescription(self, node):
+ self.generic_parse(node, pad=1)
+
+ def do_briefdescription(self, node):
+ self.generic_parse(node, pad=1)
+
+ 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
+
+ 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(' %s::%s "\n%s'%(ns, name, defn))
+ else:
+ self.add_text(' %s "\n%s'%(name, defn))
+ elif cdef_kind in ('class', 'struct'):
+ # Get the full function name.
+ anc_node = anc.getElementsByTagName('compoundname')
+ cname = anc_node[0].firstChild.data
+ self.add_text(' %s::%s "\n%s'%(cname, name, defn))
+
+ for n in node.childNodes:
+ if n not in first.values():
+ self.parse(n)
+ self.add_text(['";', '\n'])
+
+ def do_definition(self, node):
+ data = node.firstChild.data
+ self.add_text('%s "\n%s'%(data, data))
+
+ def do_sectiondef(self, node):
+ kind = node.attributes['kind'].value
+ if kind in ('public-func', 'func'):
+ self.generic_parse(node)
+
+ def do_simplesect(self, node):
+ kind = node.attributes['kind'].value
+ if kind in ('date', 'rcs', 'version'):
+ pass
+ elif kind == 'warning':
+ self.add_text(['\n', 'WARNING: '])
+ self.generic_parse(node)
+ elif kind == 'see':
+ self.add_text('\n')
+ self.add_text('See: ')
+ self.generic_parse(node)
+ else:
+ self.generic_parse(node)
+
+ def do_argsstring(self, node):
+ self.generic_parse(node, pad=1)
+
+ def do_member(self, node):
+ kind = node.attributes['kind'].value
+ refid = node.attributes['refid'].value
+ if kind == 'function' and refid[:9] == 'namespace':
+ self.generic_parse(node)
+
+ def do_doxygenindex(self, node):
+ self.multi = 1
+ comps = node.getElementsByTagName('compound')
+ for c in comps:
+ refid = c.attributes['refid'].value
+ fname = refid + '.xml'
+ if not os.path.exists(fname):
+ fname = os.path.join(self.my_dir, fname)
+ print "parsing file: %s"%fname
+ p = Doxy2SWIG(fname)
+ p.generate()
+ self.pieces.extend(self.clean_pieces(p.pieces))
+
+ def write(self, fname):
+ o = my_open_write(fname)
+ if self.multi:
+ o.write("".join(self.pieces))
+ else:
+ o.write("".join(self.clean_pieces(self.pieces)))
+ o.close()
+
+ def clean_pieces(self, pieces):
+ """Cleans the list of strings given as `pieces`. It replaces
+ multiple newlines by a maximum of 2 and returns a new list.
+ It also wraps the paragraphs nicely.
+
+ """
+ ret = []
+ count = 0
+ for i in pieces:
+ if i == '\n':
+ count = count + 1
+ else:
+ if i == '";':
+ if count:
+ ret.append('\n')
+ elif count > 2:
+ ret.append('\n\n')
+ elif count:
+ ret.append('\n'*count)
+ count = 0
+ ret.append(i)
+
+ _data = "".join(ret)
+ ret = []
+ for i in _data.split('\n\n'):
+ if i == 'Parameters:':
+ ret.extend(['Parameters:\n-----------', '\n\n'])
+ elif i.find('// File:') > -1: # leave comments alone.
+ ret.extend([i, '\n'])
+ else:
+ _tmp = textwrap.fill(i.strip())
+ _tmp = self.lead_spc.sub(r'\1"\2', _tmp)
+ ret.extend([_tmp, '\n\n'])
+ return ret
+
+
+def main(input, output):
+ p = Doxy2SWIG(input)
+ p.generate()
+ p.write(output)
+
+
+if __name__ == '__main__':
+ if len(sys.argv) != 3:
+ print __doc__
+ sys.exit(1)
+ main(sys.argv[1], sys.argv[2])
--- /dev/null
+<!-- XSLT script to extract document for class/function for swig docstring
+ If you have xsltproc you could use:
+ xsltproc swig.xsl index.xml > swig_doc.i
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="text"/>
+ <xsl:template match="/">
+ <!-- process each compound -->
+ <xsl:for-each select="doxygenindex/compound">
+ <xsl:apply-templates select="document( concat( @refid, '.xml' ) )/*" />
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template match="doxygen">
+ <xsl:for-each select="compounddef[@kind='class']">
+ <xsl:text>%feature(__QuOtE__docstring__QuOtE__) </xsl:text>
+ <xsl:value-of select="compoundname"/>
+ <xsl:text> __QuOtE__ </xsl:text>
+ <xsl:value-of select="briefdescription"/><xsl:text>
+ </xsl:text>
+ <xsl:value-of select="detaileddescription"/>
+ <xsl:text> see also: </xsl:text>
+ <xsl:value-of select="includes"/>
+ <xsl:text>__QuOtE__; </xsl:text>
+
+ <!-- output for each function individually -->
+ <xsl:for-each select="*/memberdef[@kind='function' and not(starts-with(name,'operator'))]">
+ <xsl:text>%feature(__QuOtE__docstring__QuOtE__) </xsl:text><xsl:value-of select="../../compoundname"/>::<xsl:value-of select="name"/>
+ <xsl:text> __QuOtE__ </xsl:text>
+ <xsl:value-of select="definition"/> <xsl:value-of select="argsstring"/>
+ <xsl:text>
+ </xsl:text><xsl:value-of select="briefdescription"/><xsl:text>
+ </xsl:text><xsl:value-of select="detaileddescription"/>
+ <xsl:text>__QuOtE__; </xsl:text>
+ </xsl:for-each>
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>
+++ /dev/null
-#
-# Copyright 2005 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-#
-
-EXTRA_DIST = README doxy2swig.py swig.xsl
-
-CLEANFILES = *.xml combine.xslt compound.xsd index.xsd
-
+++ /dev/null
-#
-# Copyright 2005 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-#
-
-#
-# Generating Python docstrings from C++ code using doxygen
-#
-
-There are at least two strategies for this:
- - use xsltproc as described below
- - use doxy2swig.py (included in this directory)
-
-FIXME: get one of these working (probably doxy2swig since it doesn't
-add any additional dependencies).
-
-----------------------------------------------------------------
-
-Note: Robin's patch is in SWIG >= 1.3.23
-
---------------------------------------------------------------------------------
-From: http://mailman.cs.uchicago.edu/pipermail/swig/2004-October/010604.html
-
-> I applied the docstring patch. '%feature("autodoc",1");' is working as
-> expected ...
-
-[problem solved. ...]
-
-> I can not agree more with the doxygen idea. I am using doxygen for
-> documentation and I have been trying to put doxygen output to the
-> python interface. Automatic generation of %feature("docstring") lines
-> from doxygen output is the closest solution I can think of but the
-> workload is still pretty big. How I wish this feature can be
-> implemented in the near future.
-
-I have successfully extracted function/class description from doxygen
-generated xml files, using an xslt script. To add doxygen generated
-description to each class/function, you will need to (tested under
-linux, note that this works only for Python, using Robin's docstring
-patch)
-
-1. download swig source, apply Robin's docstring patch from
- https://sourceforge.net/tracker/index.php?func=detail&aid=1023309&group_id=1645&atid=301645
- compile and install
-
-2. generate doxygen document with option "GENERATE_XML = YES"
-
-3. copy the attached script (save as swig.xsl) to the doc/xml directory
- and run
-
- > xsltproc swig.xsl index.xml > temp_doc.i
- > cat temp_doc.i | sed 's/"/\\"/g' | sed 's/__QuOtE__/"/g' > swig_doc.i
-
- you will get an interface file with lines like
- %feature("docstring") class "class description";
- %feature("docstring") class::function "member function
- description";
-
- the second step is necessary since there might be " in descriptions
- and I need to backquote them before I replace __QuOtE__ by real
- quotes. (xslt experts may know how to post-process <xsl:value-of> and
- make the script easier to use.)
-
-4. in your interface file, add
- %include "siwg_doc.i"
- %feature("autodoc","1") ;
-
-Hope this helps.
-
-swig.xsl:
-=========================================================
-
-<!-- XSLT script to extract document for class/function for swig docstring
- If you have xsltproc you could use:
- xsltproc swig.xsl index.xml > swig_doc.i
--->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
- <xsl:output method="text"/>
- <xsl:template match="/">
- <!-- process each compound -->
- <xsl:for-each select="doxygenindex/compound">
- <xsl:apply-templates select="document( concat( @refid, '.xml' ) )/*" />
- </xsl:for-each>
- </xsl:template>
-
- <xsl:template match="doxygen">
- <xsl:for-each select="compounddef[@kind='class']">
- <xsl:text>%feature(__QuOtE__docstring__QuOtE__) </xsl:text>
- <xsl:value-of select="compoundname"/>
- <xsl:text> __QuOtE__ </xsl:text>
- <xsl:value-of select="briefdescription"/><xsl:text>
- </xsl:text>
- <xsl:value-of select="detaileddescription"/>
- <xsl:text> see also: </xsl:text>
- <xsl:value-of select="includes"/>
- <xsl:text>__QuOtE__; </xsl:text>
-
- <!-- output for each function individually -->
- <xsl:for-each select="*/memberdef[@kind='function' and not(starts-with(name,'operator'))]">
- <xsl:text>%feature(__QuOtE__docstring__QuOtE__) </xsl:text><xsl:value-of select="../../compoundname"/>::<xsl:value-of select="name"/>
- <xsl:text> __QuOtE__ </xsl:text>
- <xsl:value-of select="definition"/> <xsl:value-of select="argsstring"/>
- <xsl:text>
- </xsl:text><xsl:value-of select="briefdescription"/><xsl:text>
- </xsl:text><xsl:value-of select="detaileddescription"/>
- <xsl:text>__QuOtE__; </xsl:text>
- </xsl:for-each>
- </xsl:for-each>
- </xsl:template>
-</xsl:stylesheet>
-
---
-Bo Peng
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-"""Doxygen XML to SWIG docstring converter.
-
-Converts Doxygen generated XML files into a file containing docstrings
-that can be used by SWIG-1.3.x. Note that you need to get SWIG
-version > 1.3.23 or use Robin Dunn's docstring patch to be able to use
-the resulting output.
-
-Usage:
-
- doxy2swig.py input.xml output.i
-
-input.xml is your doxygen generated XML file and output.i is where the
-output will be written (the file will be clobbered).
-
-"""
-
-# This code is implemented using Mark Pilgrim's code as a guideline:
-# http://www.faqs.org/docs/diveintopython/kgp_divein.html
-#
-# Author: Prabhu Ramachandran
-# License: BSD style
-
-
-from xml.dom import minidom
-import re
-import textwrap
-import sys
-import types
-import os.path
-
-
-def my_open_read(source):
- if hasattr(source, "read"):
- return source
- else:
- return open(source)
-
-def my_open_write(dest):
- if hasattr(dest, "write"):
- return dest
- else:
- return open(dest, 'w')
-
-
-class Doxy2SWIG:
- """Converts Doxygen generated XML files into a file containing
- docstrings that can be used by SWIG-1.3.x that have support for
- feature("docstring"). Once the data is parsed it is stored in
- self.pieces.
-
- """
-
- def __init__(self, src):
- """Initialize the instance given a source object (file or
- filename).
-
- """
- f = my_open_read(src)
- self.my_dir = os.path.dirname(f.name)
- self.xmldoc = minidom.parse(f).documentElement
- f.close()
-
- self.pieces = []
- self.pieces.append('\n// File: %s\n'%\
- os.path.basename(f.name))
-
- self.space_re = re.compile(r'\s+')
- self.lead_spc = re.compile(r'^(%feature\S+\s+\S+\s*?)"\s+(\S)')
- self.multi = 0
- self.ignores = ('inheritancegraph', 'param', 'listofallmembers',
- 'innerclass', 'name', 'declname', 'incdepgraph',
- 'invincdepgraph', 'programlisting', 'type',
- 'references', 'referencedby', 'location',
- 'collaborationgraph', 'reimplements',
- 'reimplementedby', 'derivedcompoundref',
- 'basecompoundref')
- #self.generics = []
-
- def generate(self):
- """Parses the file set in the initialization. The resulting
- data is stored in `self.pieces`.
-
- """
- self.parse(self.xmldoc)
-
- def parse(self, node):
- """Parse a given node. This function in turn calls the
- `parse_<nodeType>` functions which handle the respective
- nodes.
-
- """
- pm = getattr(self, "parse_%s"%node.__class__.__name__)
- pm(node)
-
- def parse_Document(self, node):
- self.parse(node.documentElement)
-
- def parse_Text(self, node):
- txt = node.data
- txt = txt.replace('\\', r'\\\\')
- txt = txt.replace('"', r'\"')
- # ignore pure whitespace
- m = self.space_re.match(txt)
- if m and len(m.group()) == len(txt):
- pass
- else:
- self.add_text(textwrap.fill(txt))
-
- def parse_Element(self, node):
- """Parse an `ELEMENT_NODE`. This calls specific
- `do_<tagName>` handers for different elements. If no handler
- is available the `generic_parse` method is called. All
- tagNames specified in `self.ignores` are simply ignored.
-
- """
- name = node.tagName
- ignores = self.ignores
- if name in ignores:
- return
- attr = "do_%s" % name
- if hasattr(self, attr):
- handlerMethod = getattr(self, attr)
- handlerMethod(node)
- else:
- self.generic_parse(node)
- #if name not in self.generics: self.generics.append(name)
-
- def add_text(self, value):
- """Adds text corresponding to `value` into `self.pieces`."""
- if type(value) in (types.ListType, types.TupleType):
- self.pieces.extend(value)
- else:
- self.pieces.append(value)
-
- def get_specific_nodes(self, node, names):
- """Given a node and a sequence of strings in `names`, return a
- dictionary containing the names as keys and child
- `ELEMENT_NODEs`, that have a `tagName` equal to the name.
-
- """
- nodes = [(x.tagName, x) for x in node.childNodes \
- if x.nodeType == x.ELEMENT_NODE and \
- x.tagName in names]
- return dict(nodes)
-
- def generic_parse(self, node, pad=0):
- """A Generic parser for arbitrary tags in a node.
-
- Parameters:
-
- - node: A node in the DOM.
- - pad: `int` (default: 0)
-
- If 0 the node data is not padded with newlines. If 1 it
- appends a newline after parsing the childNodes. If 2 it
- pads before and after the nodes are processed. Defaults to
- 0.
-
- """
- npiece = 0
- if pad:
- npiece = len(self.pieces)
- if pad == 2:
- self.add_text('\n')
- for n in node.childNodes:
- self.parse(n)
- if pad:
- if len(self.pieces) > npiece:
- self.add_text('\n')
-
- def space_parse(self, node):
- self.add_text(' ')
- self.generic_parse(node)
-
- do_ref = space_parse
- do_emphasis = space_parse
- do_bold = space_parse
- do_computeroutput = space_parse
- do_formula = space_parse
-
- def do_compoundname(self, node):
- self.add_text('\n\n')
- data = node.firstChild.data
- self.add_text('%%feature("docstring") %s "\n'%data)
-
- def do_compounddef(self, node):
- kind = node.attributes['kind'].value
- if kind in ('class', 'struct'):
- prot = node.attributes['prot'].value
- if prot <> 'public':
- return
- names = ('compoundname', 'briefdescription',
- 'detaileddescription', 'includes')
- first = self.get_specific_nodes(node, names)
- for n in names:
- if first.has_key(n):
- self.parse(first[n])
- self.add_text(['";','\n'])
- for n in node.childNodes:
- if n not in first.values():
- self.parse(n)
- elif kind in ('file', 'namespace'):
- nodes = node.getElementsByTagName('sectiondef')
- for n in nodes:
- self.parse(n)
-
- def do_includes(self, node):
- self.add_text('C++ includes: ')
- self.generic_parse(node, pad=1)
-
- def do_parameterlist(self, node):
- self.add_text(['\n', '\n', 'Parameters:', '\n'])
- self.generic_parse(node, pad=1)
-
- def do_para(self, node):
- self.add_text('\n')
- self.generic_parse(node, pad=1)
-
- def do_parametername(self, node):
- self.add_text('\n')
- self.add_text("%s: "%node.firstChild.data)
-
- def do_parameterdefinition(self, node):
- self.generic_parse(node, pad=1)
-
- def do_detaileddescription(self, node):
- self.generic_parse(node, pad=1)
-
- def do_briefdescription(self, node):
- self.generic_parse(node, pad=1)
-
- 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
-
- 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(' %s::%s "\n%s'%(ns, name, defn))
- else:
- self.add_text(' %s "\n%s'%(name, defn))
- elif cdef_kind in ('class', 'struct'):
- # Get the full function name.
- anc_node = anc.getElementsByTagName('compoundname')
- cname = anc_node[0].firstChild.data
- self.add_text(' %s::%s "\n%s'%(cname, name, defn))
-
- for n in node.childNodes:
- if n not in first.values():
- self.parse(n)
- self.add_text(['";', '\n'])
-
- def do_definition(self, node):
- data = node.firstChild.data
- self.add_text('%s "\n%s'%(data, data))
-
- def do_sectiondef(self, node):
- kind = node.attributes['kind'].value
- if kind in ('public-func', 'func'):
- self.generic_parse(node)
-
- def do_simplesect(self, node):
- kind = node.attributes['kind'].value
- if kind in ('date', 'rcs', 'version'):
- pass
- elif kind == 'warning':
- self.add_text(['\n', 'WARNING: '])
- self.generic_parse(node)
- elif kind == 'see':
- self.add_text('\n')
- self.add_text('See: ')
- self.generic_parse(node)
- else:
- self.generic_parse(node)
-
- def do_argsstring(self, node):
- self.generic_parse(node, pad=1)
-
- def do_member(self, node):
- kind = node.attributes['kind'].value
- refid = node.attributes['refid'].value
- if kind == 'function' and refid[:9] == 'namespace':
- self.generic_parse(node)
-
- def do_doxygenindex(self, node):
- self.multi = 1
- comps = node.getElementsByTagName('compound')
- for c in comps:
- refid = c.attributes['refid'].value
- fname = refid + '.xml'
- if not os.path.exists(fname):
- fname = os.path.join(self.my_dir, fname)
- print "parsing file: %s"%fname
- p = Doxy2SWIG(fname)
- p.generate()
- self.pieces.extend(self.clean_pieces(p.pieces))
-
- def write(self, fname):
- o = my_open_write(fname)
- if self.multi:
- o.write("".join(self.pieces))
- else:
- o.write("".join(self.clean_pieces(self.pieces)))
- o.close()
-
- def clean_pieces(self, pieces):
- """Cleans the list of strings given as `pieces`. It replaces
- multiple newlines by a maximum of 2 and returns a new list.
- It also wraps the paragraphs nicely.
-
- """
- ret = []
- count = 0
- for i in pieces:
- if i == '\n':
- count = count + 1
- else:
- if i == '";':
- if count:
- ret.append('\n')
- elif count > 2:
- ret.append('\n\n')
- elif count:
- ret.append('\n'*count)
- count = 0
- ret.append(i)
-
- _data = "".join(ret)
- ret = []
- for i in _data.split('\n\n'):
- if i == 'Parameters:':
- ret.extend(['Parameters:\n-----------', '\n\n'])
- elif i.find('// File:') > -1: # leave comments alone.
- ret.extend([i, '\n'])
- else:
- _tmp = textwrap.fill(i.strip())
- _tmp = self.lead_spc.sub(r'\1"\2', _tmp)
- ret.extend([_tmp, '\n\n'])
- return ret
-
-
-def main(input, output):
- p = Doxy2SWIG(input)
- p.generate()
- p.write(output)
-
-
-if __name__ == '__main__':
- if len(sys.argv) != 3:
- print __doc__
- sys.exit(1)
- main(sys.argv[1], sys.argv[2])
+++ /dev/null
-<!-- XSLT script to extract document for class/function for swig docstring
- If you have xsltproc you could use:
- xsltproc swig.xsl index.xml > swig_doc.i
--->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
- <xsl:output method="text"/>
- <xsl:template match="/">
- <!-- process each compound -->
- <xsl:for-each select="doxygenindex/compound">
- <xsl:apply-templates select="document( concat( @refid, '.xml' ) )/*" />
- </xsl:for-each>
- </xsl:template>
-
- <xsl:template match="doxygen">
- <xsl:for-each select="compounddef[@kind='class']">
- <xsl:text>%feature(__QuOtE__docstring__QuOtE__) </xsl:text>
- <xsl:value-of select="compoundname"/>
- <xsl:text> __QuOtE__ </xsl:text>
- <xsl:value-of select="briefdescription"/><xsl:text>
- </xsl:text>
- <xsl:value-of select="detaileddescription"/>
- <xsl:text> see also: </xsl:text>
- <xsl:value-of select="includes"/>
- <xsl:text>__QuOtE__; </xsl:text>
-
- <!-- output for each function individually -->
- <xsl:for-each select="*/memberdef[@kind='function' and not(starts-with(name,'operator'))]">
- <xsl:text>%feature(__QuOtE__docstring__QuOtE__) </xsl:text><xsl:value-of select="../../compoundname"/>::<xsl:value-of select="name"/>
- <xsl:text> __QuOtE__ </xsl:text>
- <xsl:value-of select="definition"/> <xsl:value-of select="argsstring"/>
- <xsl:text>
- </xsl:text><xsl:value-of select="briefdescription"/><xsl:text>
- </xsl:text><xsl:value-of select="detaileddescription"/>
- <xsl:text>__QuOtE__; </xsl:text>
- </xsl:for-each>
- </xsl:for-each>
- </xsl:template>
-</xsl:stylesheet>