mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 13:02:11 +00:00
860 lines
36 KiB
Python
860 lines
36 KiB
Python
#!/usr/bin/python
|
|
# Copyright 2006 Rene Rivera
|
|
# Distributed under the Boost Software License, Version 1.0.
|
|
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
'''
|
|
Processing of Doxygen generated XML.
|
|
'''
|
|
|
|
import os
|
|
import os.path
|
|
import sys
|
|
import time
|
|
import string
|
|
import getopt
|
|
import glob
|
|
import re
|
|
import xml.dom.minidom
|
|
|
|
|
|
def usage():
|
|
print '''
|
|
Usage:
|
|
%s options
|
|
|
|
Options:
|
|
--xmldir Directory with the Doxygen xml result files.
|
|
--output Write the output BoostBook to the given location.
|
|
--id The ID of the top level BoostBook section.
|
|
--title The title of the top level BoostBook section.
|
|
--enable-index Generate additional index sections for classes and
|
|
types.
|
|
''' % ( sys.argv[0] )
|
|
|
|
|
|
def get_args( argv = sys.argv[1:] ):
|
|
spec = [
|
|
'xmldir=',
|
|
'output=',
|
|
'id=',
|
|
'title=',
|
|
'enable-index',
|
|
'help' ]
|
|
options = {
|
|
'--xmldir' : 'xml',
|
|
'--output' : None,
|
|
'--id' : 'dox',
|
|
'--title' : 'Doxygen'
|
|
}
|
|
( option_pairs, other ) = getopt.getopt( argv, '', spec )
|
|
map( lambda x: options.__setitem__( x[0], x[1] ), option_pairs )
|
|
|
|
if '--help' in options:
|
|
usage()
|
|
sys.exit(1)
|
|
|
|
return {
|
|
'xmldir' : options['--xmldir'],
|
|
'output' : options['--output'],
|
|
'id' : options['--id'],
|
|
'title' : options['--title'],
|
|
'index' : '--enable-index' in options
|
|
}
|
|
|
|
def if_attribute(node, attribute, true_value, false_value=None):
|
|
if node.getAttribute(attribute) == 'yes':
|
|
return true_value
|
|
else:
|
|
return false_value
|
|
|
|
class Doxygen2BoostBook:
|
|
|
|
def __init__( self, **kwargs ):
|
|
##
|
|
self.args = kwargs
|
|
self.args.setdefault('id','')
|
|
self.args.setdefault('title','')
|
|
self.args.setdefault('last_revision', time.asctime())
|
|
self.args.setdefault('index', False)
|
|
self.id = '%(id)s.reference' % self.args
|
|
self.args['id'] = self.id
|
|
#~ This is our template BoostBook document we insert the generated content into.
|
|
self.boostbook = xml.dom.minidom.parseString('''<?xml version="1.0" encoding="UTF-8"?>
|
|
<section id="%(id)s" name="%(title)s" last-revision="%(last_revision)s">
|
|
<title>%(title)s</title>
|
|
<library-reference id="%(id)s.headers">
|
|
<title>Headers</title>
|
|
</library-reference>
|
|
<index id="%(id)s.classes">
|
|
<title>Classes</title>
|
|
</index>
|
|
<index id="%(id)s.index">
|
|
<title>Index</title>
|
|
</index>
|
|
</section>
|
|
''' % self.args )
|
|
self.section = {
|
|
'headers' : self._getChild('library-reference',id='%(id)s.headers' % self.args),
|
|
'classes' : self._getChild('index',id='%(id)s.classes' % self.args),
|
|
'index' : self._getChild('index',id='%(id)s.index' % self.args)
|
|
}
|
|
#~ Remove the index sections if we aren't generating it.
|
|
if not self.args['index']:
|
|
self.section['classes'].parentNode.removeChild(self.section['classes'])
|
|
self.section['classes'].unlink()
|
|
del self.section['classes']
|
|
self.section['index'].parentNode.removeChild(self.section['index'])
|
|
self.section['index'].unlink()
|
|
del self.section['index']
|
|
#~ The symbols, per Doxygen notion, that we translated.
|
|
self.symbols = {}
|
|
#~ Map of Doxygen IDs and BoostBook IDs, so we can translate as needed.
|
|
self.idmap = {}
|
|
#~ Marks generation, to prevent redoing it.
|
|
self.generated = False
|
|
|
|
#~ Add an Doxygen generated XML document to the content we are translating.
|
|
def addDox( self, document ):
|
|
self._translateNode(document.documentElement)
|
|
|
|
#~ Turns the internal XML tree into an output UTF-8 string.
|
|
def tostring( self ):
|
|
self._generate()
|
|
#~ return self.boostbook.toprettyxml(' ')
|
|
return self.boostbook.toxml('utf-8')
|
|
|
|
#~ Does post-processing on the partial generated content to generate additional info
|
|
#~ now that we have the complete source documents.
|
|
def _generate( self ):
|
|
if not self.generated:
|
|
self.generated = True
|
|
symbols = self.symbols.keys()
|
|
symbols.sort()
|
|
#~ Populate the header section.
|
|
for symbol in symbols:
|
|
if self.symbols[symbol]['kind'] in ('header'):
|
|
self.section['headers'].appendChild(self.symbols[symbol]['dom'])
|
|
for symbol in symbols:
|
|
if self.symbols[symbol]['kind'] not in ('namespace', 'header'):
|
|
container = self._resolveContainer(self.symbols[symbol],
|
|
self.symbols[self.symbols[symbol]['header']]['dom'])
|
|
if container.nodeName != 'namespace':
|
|
## The current BoostBook to Docbook translation doesn't
|
|
## respect, nor assign, IDs to inner types of any kind.
|
|
## So nuke the ID entry so as not create bogus links.
|
|
del self.idmap[self.symbols[symbol]['id']]
|
|
container.appendChild(self.symbols[symbol]['dom'])
|
|
self._rewriteIDs(self.boostbook.documentElement)
|
|
|
|
#~ Rewrite the various IDs from Doxygen references to the newly created
|
|
#~ BoostBook references.
|
|
def _rewriteIDs( self, node ):
|
|
if node.nodeName in ('link'):
|
|
if node.getAttribute('linkend') in self.idmap:
|
|
#~ A link, and we have someplace to repoint it at.
|
|
node.setAttribute('linkend',self.idmap[node.getAttribute('linkend')])
|
|
else:
|
|
#~ A link, but we don't have a generated target for it.
|
|
node.removeAttribute('linkend')
|
|
elif hasattr(node,'hasAttribute') and node.hasAttribute('id') and node.getAttribute('id') in self.idmap:
|
|
#~ Simple ID, and we have a translation.
|
|
node.setAttribute('id',self.idmap[node.getAttribute('id')])
|
|
#~ Recurse, and iterate, depth-first traversal which turns out to be
|
|
#~ left-to-right and top-to-bottom for the document.
|
|
if node.firstChild:
|
|
self._rewriteIDs(node.firstChild)
|
|
if node.nextSibling:
|
|
self._rewriteIDs(node.nextSibling)
|
|
|
|
def _resolveContainer( self, cpp, root ):
|
|
container = root
|
|
for ns in cpp['namespace']:
|
|
node = self._getChild('namespace',name=ns,root=container)
|
|
if not node:
|
|
node = container.appendChild(
|
|
self._createNode('namespace',name=ns))
|
|
container = node
|
|
for inner in cpp['name'].split('::'):
|
|
node = self._getChild(name=inner,root=container)
|
|
if not node:
|
|
break
|
|
container = node
|
|
return container
|
|
|
|
def _setID( self, id, name ):
|
|
self.idmap[id] = name.replace('::','.').replace('/','.')
|
|
#~ print '--| setID:',id,'::',self.idmap[id]
|
|
|
|
#~ Translate a given node within a given context.
|
|
#~ The translation dispatches to a local method of the form
|
|
#~ "_translate[_context0,...,_contextN]", and the keyword args are
|
|
#~ passed along. If there is no translation handling method we
|
|
#~ return None.
|
|
def _translateNode( self, *context, **kwargs ):
|
|
node = None
|
|
names = [ ]
|
|
for c in context:
|
|
if c:
|
|
if not isinstance(c,xml.dom.Node):
|
|
suffix = '_'+c.replace('-','_')
|
|
else:
|
|
suffix = '_'+c.nodeName.replace('-','_')
|
|
node = c
|
|
names.append('_translate')
|
|
names = map(lambda x: x+suffix,names)
|
|
if node:
|
|
for name in names:
|
|
if hasattr(self,name):
|
|
return getattr(self,name)(node,**kwargs)
|
|
return None
|
|
|
|
#~ Translates the children of the given parent node, appending the results
|
|
#~ to the indicated target. For nodes not translated by the translation method
|
|
#~ it copies the child over and recurses on that child to translate any
|
|
#~ possible interior nodes. Hence this will translate the entire subtree.
|
|
def _translateChildren( self, parent, **kwargs ):
|
|
target = kwargs['target']
|
|
for n in parent.childNodes:
|
|
child = self._translateNode(n,target=target)
|
|
if child:
|
|
target.appendChild(child)
|
|
else:
|
|
child = n.cloneNode(False)
|
|
if hasattr(child,'data'):
|
|
child.data = re.sub(r'\s+',' ',child.data)
|
|
target.appendChild(child)
|
|
self._translateChildren(n,target=child)
|
|
|
|
#~ Translate the given node as a description, into the description subnode
|
|
#~ of the target. If no description subnode is present in the target it
|
|
#~ is created.
|
|
def _translateDescription( self, node, target=None, tag='description', **kwargs ):
|
|
description = self._getChild(tag,root=target)
|
|
if not description:
|
|
description = target.appendChild(self._createNode(tag))
|
|
self._translateChildren(node,target=description)
|
|
return description
|
|
|
|
#~ Top level translation of: <doxygen ...>...</doxygen>,
|
|
#~ translates the children.
|
|
def _translate_doxygen( self, node ):
|
|
#~ print '_translate_doxygen:', node.nodeName
|
|
result = []
|
|
for n in node.childNodes:
|
|
newNode = self._translateNode(n)
|
|
if newNode:
|
|
result.append(newNode)
|
|
return result
|
|
|
|
#~ Top level translation of:
|
|
#~ <doxygenindex ...>
|
|
#~ <compound ...>
|
|
#~ <member ...>
|
|
#~ <name>...</name>
|
|
#~ </member>
|
|
#~ ...
|
|
#~ </compound>
|
|
#~ ...
|
|
#~ </doxygenindex>
|
|
#~ builds the class and symbol sections, if requested.
|
|
def _translate_doxygenindex( self, node ):
|
|
#~ print '_translate_doxygenindex:', node.nodeName
|
|
if self.args['index']:
|
|
entries = []
|
|
classes = []
|
|
#~ Accumulate all the index entries we care about.
|
|
for n in node.childNodes:
|
|
if n.nodeName == 'compound':
|
|
if n.getAttribute('kind') not in ('file','dir','define'):
|
|
cpp = self._cppName(self._getChildData('name',root=n))
|
|
entry = {
|
|
'name' : cpp['name'],
|
|
'compoundname' : cpp['compoundname'],
|
|
'id' : n.getAttribute('refid')
|
|
}
|
|
if n.getAttribute('kind') in ('class','struct'):
|
|
classes.append(entry)
|
|
entries.append(entry)
|
|
for m in n.childNodes:
|
|
if m.nodeName == 'member':
|
|
cpp = self._cppName(self._getChildData('name',root=m))
|
|
entry = {
|
|
'name' : cpp['name'],
|
|
'compoundname' : cpp['compoundname'],
|
|
'id' : n.getAttribute('refid')
|
|
}
|
|
if hasattr(m,'getAttribute') and m.getAttribute('kind') in ('class','struct'):
|
|
classes.append(entry)
|
|
entries.append(entry)
|
|
#~ Put them in a sensible order.
|
|
entries.sort(lambda x,y: cmp(x['name'].lower(),y['name'].lower()))
|
|
classes.sort(lambda x,y: cmp(x['name'].lower(),y['name'].lower()))
|
|
#~ And generate the BoostBook for them.
|
|
self._translate_index_(entries,target=self.section['index'])
|
|
self._translate_index_(classes,target=self.section['classes'])
|
|
return None
|
|
|
|
#~ Translate a set of index entries in the BoostBook output. The output
|
|
#~ is grouped into groups of the first letter of the entry names.
|
|
def _translate_index_(self, entries, target=None, **kwargs ):
|
|
i = 0
|
|
targetID = target.getAttribute('id')
|
|
while i < len(entries):
|
|
dividerKey = entries[i]['name'][0].upper()
|
|
divider = target.appendChild(self._createNode('indexdiv',id=targetID+'.'+dividerKey))
|
|
divider.appendChild(self._createText('title',dividerKey))
|
|
while i < len(entries) and dividerKey == entries[i]['name'][0].upper():
|
|
iename = entries[i]['name']
|
|
ie = divider.appendChild(self._createNode('indexentry'))
|
|
ie = ie.appendChild(self._createText('primaryie',iename))
|
|
while i < len(entries) and entries[i]['name'] == iename:
|
|
ie.appendChild(self.boostbook.createTextNode(' ('))
|
|
ie.appendChild(self._createText(
|
|
'link',entries[i]['compoundname'],linkend=entries[i]['id']))
|
|
ie.appendChild(self.boostbook.createTextNode(')'))
|
|
i += 1
|
|
|
|
#~ Translate a <compounddef ...>...</compounddef>,
|
|
#~ by retranslating with the "kind" of compounddef.
|
|
def _translate_compounddef( self, node, target=None, **kwargs ):
|
|
return self._translateNode(node,node.getAttribute('kind'))
|
|
|
|
#~ Translate a <compounddef kind="namespace"...>...</compounddef>. For
|
|
#~ namespaces we just collect the information for later use as there is no
|
|
#~ currently namespaces are not included in the BoostBook format. In the future
|
|
#~ it might be good to generate a namespace index.
|
|
def _translate_compounddef_namespace( self, node, target=None, **kwargs ):
|
|
namespace = {
|
|
'id' : node.getAttribute('id'),
|
|
'kind' : 'namespace',
|
|
'name' : self._getChildData('compoundname',root=node),
|
|
'brief' : self._getChildData('briefdescription',root=node),
|
|
'detailed' : self._getChildData('detaileddescription',root=node),
|
|
'parsed' : False
|
|
}
|
|
if namespace['name'] in self.symbols:
|
|
if not self.symbols[namespace['name']]['parsed']:
|
|
self.symbols[namespace['name']]['parsed'] = True
|
|
#~ for n in node.childNodes:
|
|
#~ if hasattr(n,'getAttribute'):
|
|
#~ self._translateNode(n,n.getAttribute('kind'),target=target,**kwargs)
|
|
else:
|
|
self.symbols[namespace['name']] = namespace
|
|
#~ self._setID(namespace['id'],namespace['name'])
|
|
return None
|
|
|
|
#~ Translate a <compounddef kind="class"...>...</compounddef>, which
|
|
#~ forwards to the kind=struct as they are the same.
|
|
def _translate_compounddef_class( self, node, target=None, **kwargs ):
|
|
return self._translate_compounddef_struct(node,tag='class',target=target,**kwargs)
|
|
|
|
#~ Translate a <compounddef kind="struct"...>...</compounddef> into:
|
|
#~ <header id="?" name="?">
|
|
#~ <struct name="?">
|
|
#~ ...
|
|
#~ </struct>
|
|
#~ </header>
|
|
def _translate_compounddef_struct( self, node, tag='struct', target=None, **kwargs ):
|
|
result = None
|
|
includes = self._getChild('includes',root=node)
|
|
if includes:
|
|
## Add the header into the output table.
|
|
self._translate_compounddef_includes_(includes,includes,**kwargs)
|
|
## Compounds are the declared symbols, classes, types, etc.
|
|
## We add them to the symbol table, along with the partial DOM for them
|
|
## so that they can be organized into the output later.
|
|
compoundname = self._getChildData('compoundname',root=node)
|
|
compoundname = self._cppName(compoundname)
|
|
self._setID(node.getAttribute('id'),compoundname['compoundname'])
|
|
struct = self._createNode(tag,name=compoundname['name'].split('::')[-1])
|
|
self.symbols[compoundname['compoundname']] = {
|
|
'header' : includes.firstChild.data,
|
|
'namespace' : compoundname['namespace'],
|
|
'id' : node.getAttribute('id'),
|
|
'kind' : tag,
|
|
'name' : compoundname['name'],
|
|
'dom' : struct
|
|
}
|
|
## Add the children which will be the members of the struct.
|
|
for n in node.childNodes:
|
|
self._translateNode(n,target=struct,scope=compoundname['compoundname'])
|
|
result = struct
|
|
return result
|
|
|
|
#~ Translate a <compounddef ...><includes ...>...</includes></compounddef>,
|
|
def _translate_compounddef_includes_( self, node, target=None, **kwargs ):
|
|
name = node.firstChild.data
|
|
if name not in self.symbols:
|
|
self._setID(node.getAttribute('refid'),name)
|
|
self.symbols[name] = {
|
|
'kind' : 'header',
|
|
'id' : node.getAttribute('refid'),
|
|
'dom' : self._createNode('header',
|
|
id=node.getAttribute('refid'),
|
|
name=name)
|
|
}
|
|
return None
|
|
|
|
#~ Translate a <basecompoundref...>...</basecompoundref> into:
|
|
#~ <inherit access="?">
|
|
#~ ...
|
|
#~ </inherit>
|
|
def _translate_basecompoundref( self, ref, target=None, **kwargs ):
|
|
inherit = target.appendChild(self._createNode('inherit',
|
|
access=ref.getAttribute('prot')))
|
|
self._translateChildren(ref,target=inherit)
|
|
return
|
|
|
|
#~ Translate:
|
|
#~ <templateparamlist>
|
|
#~ <param>
|
|
#~ <type>...</type>
|
|
#~ <declname>...</declname>
|
|
#~ <defname>...</defname>
|
|
#~ <defval>...</defval>
|
|
#~ </param>
|
|
#~ ...
|
|
#~ </templateparamlist>
|
|
#~ Into:
|
|
#~ <template>
|
|
#~ <template-type-parameter name="?" />
|
|
#~ <template-nontype-parameter name="?">
|
|
#~ <type>?</type>
|
|
#~ <default>?</default>
|
|
#~ </template-nontype-parameter>
|
|
#~ </template>
|
|
def _translate_templateparamlist( self, templateparamlist, target=None, **kwargs ):
|
|
template = target.appendChild(self._createNode('template'))
|
|
for param in templateparamlist.childNodes:
|
|
if param.nodeName == 'param':
|
|
type = self._getChildData('type',root=param)
|
|
defval = self._getChild('defval',root=param)
|
|
paramKind = None
|
|
if type in ('class','typename'):
|
|
paramKind = 'template-type-parameter'
|
|
else:
|
|
paramKind = 'template-nontype-parameter'
|
|
templateParam = template.appendChild(
|
|
self._createNode(paramKind,
|
|
name=self._getChildData('declname',root=param)))
|
|
if paramKind == 'template-nontype-parameter':
|
|
template_type = templateParam.appendChild(self._createNode('type'))
|
|
self._translate_type(
|
|
self._getChild('type',root=param),target=template_type)
|
|
if defval:
|
|
value = self._getChildData('ref',root=defval.firstChild)
|
|
if not value:
|
|
value = self._getData(defval)
|
|
templateParam.appendChild(self._createText('default',value))
|
|
return template
|
|
|
|
#~ Translate:
|
|
#~ <briefdescription>...</briefdescription>
|
|
#~ Into:
|
|
#~ <purpose>...</purpose>
|
|
def _translate_briefdescription( self, brief, target=None, **kwargs ):
|
|
self._translateDescription(brief,target=target,**kwargs)
|
|
return self._translateDescription(brief,target=target,tag='purpose',**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <detaileddescription>...</detaileddescription>
|
|
#~ Into:
|
|
#~ <description>...</description>
|
|
def _translate_detaileddescription( self, detailed, target=None, **kwargs ):
|
|
return self._translateDescription(detailed,target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="?">...</sectiondef>
|
|
#~ With kind specific translation.
|
|
def _translate_sectiondef( self, sectiondef, target=None, **kwargs ):
|
|
self._translateNode(sectiondef,sectiondef.getAttribute('kind'),target=target,**kwargs)
|
|
|
|
#~ Translate non-function sections.
|
|
def _translate_sectiondef_x_( self, sectiondef, target=None, **kwargs ):
|
|
for n in sectiondef.childNodes:
|
|
if hasattr(n,'getAttribute'):
|
|
self._translateNode(n,n.getAttribute('kind'),target=target,**kwargs)
|
|
return None
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="public-type">...</sectiondef>
|
|
def _translate_sectiondef_public_type( self, sectiondef, target=None, **kwargs ):
|
|
return self._translate_sectiondef_x_(sectiondef,target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="public-sttrib">...</sectiondef>
|
|
def _translate_sectiondef_public_attrib( self, sectiondef, target=None, **kwargs):
|
|
return self._translate_sectiondef_x_(sectiondef,target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="?-func">...</sectiondef>
|
|
#~ All the various function group translations end up here for which
|
|
#~ they are translated into:
|
|
#~ <method-group name="?">
|
|
#~ ...
|
|
#~ </method-group>
|
|
def _translate_sectiondef_func_( self, sectiondef, name='functions', target=None, **kwargs ):
|
|
members = target.appendChild(self._createNode('method-group',name=name))
|
|
for n in sectiondef.childNodes:
|
|
if hasattr(n,'getAttribute'):
|
|
self._translateNode(n,n.getAttribute('kind'),target=members,**kwargs)
|
|
return members
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="public-func">...</sectiondef>
|
|
def _translate_sectiondef_public_func( self, sectiondef, target=None, **kwargs ):
|
|
return self._translate_sectiondef_func_(sectiondef,
|
|
name='public member functions',target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="public-static-func">...</sectiondef>
|
|
def _translate_sectiondef_public_static_func( self, sectiondef, target=None, **kwargs):
|
|
return self._translate_sectiondef_func_(sectiondef,
|
|
name='public static functions',target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="protected-func">...</sectiondef>
|
|
def _translate_sectiondef_protected_func( self, sectiondef, target=None, **kwargs ):
|
|
return self._translate_sectiondef_func_(sectiondef,
|
|
name='protected member functions',target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="private-static-func">...</sectiondef>
|
|
def _translate_sectiondef_private_static_func( self, sectiondef, target=None, **kwargs):
|
|
return self._translate_sectiondef_func_(sectiondef,
|
|
name='private static functions',target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="public-func">...</sectiondef>
|
|
def _translate_sectiondef_private_func( self, sectiondef, target=None, **kwargs ):
|
|
return self._translate_sectiondef_func_(sectiondef,
|
|
name='private member functions',target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <sectiondef kind="user-defined"><header>...</header>...</sectiondef>
|
|
def _translate_sectiondef_user_defined( self, sectiondef, target=None, **kwargs ):
|
|
return self._translate_sectiondef_func_(sectiondef,
|
|
name=self._getChildData('header', root=sectiondef),target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="typedef" id="?">
|
|
#~ <name>...</name>
|
|
#~ </memberdef>
|
|
#~ To:
|
|
#~ <typedef id="?" name="?">
|
|
#~ <type>...</type>
|
|
#~ </typedef>
|
|
def _translate_memberdef_typedef( self, memberdef, target=None, scope=None, **kwargs ):
|
|
self._setID(memberdef.getAttribute('id'),
|
|
scope+'::'+self._getChildData('name',root=memberdef))
|
|
typedef = target.appendChild(self._createNode('typedef',
|
|
id=memberdef.getAttribute('id'),
|
|
name=self._getChildData('name',root=memberdef)))
|
|
typedef_type = typedef.appendChild(self._createNode('type'))
|
|
self._translate_type(self._getChild('type',root=memberdef),target=typedef_type)
|
|
return typedef
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="function" id="?" const="?" static="?" explicit="?" inline="?">
|
|
#~ <name>...</name>
|
|
#~ </memberdef>
|
|
#~ To:
|
|
#~ <method name="?" cv="?" specifiers="?">
|
|
#~ ...
|
|
#~ </method>
|
|
def _translate_memberdef_function( self, memberdef, target=None, scope=None, **kwargs ):
|
|
name = self._getChildData('name',root=memberdef)
|
|
self._setID(memberdef.getAttribute('id'),scope+'::'+name)
|
|
## Check if we have some specific kind of method.
|
|
if name == scope.split('::')[-1]:
|
|
kind = 'constructor'
|
|
target = target.parentNode
|
|
elif name == '~'+scope.split('::')[-1]:
|
|
kind = 'destructor'
|
|
target = target.parentNode
|
|
elif name == 'operator=':
|
|
kind = 'copy-assignment'
|
|
target = target.parentNode
|
|
else:
|
|
kind = 'method'
|
|
method = target.appendChild(self._createNode(kind,
|
|
# id=memberdef.getAttribute('id'),
|
|
name=name,
|
|
cv=' '.join([
|
|
if_attribute(memberdef,'const','const','').strip()
|
|
]),
|
|
specifiers=' '.join([
|
|
if_attribute(memberdef,'static','static',''),
|
|
if_attribute(memberdef,'explicit','explicit',''),
|
|
if_attribute(memberdef,'inline','inline','')
|
|
]).strip()
|
|
))
|
|
## We iterate the children to translate each part of the function.
|
|
for n in memberdef.childNodes:
|
|
self._translateNode(memberdef,'function',n,target=method)
|
|
return method
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="function"...><templateparamlist>...</templateparamlist></memberdef>
|
|
def _translate_memberdef_function_templateparamlist(
|
|
self, templateparamlist, target=None, **kwargs ):
|
|
return self._translate_templateparamlist(templateparamlist,target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="function"...><type>...</type></memberdef>
|
|
#~ To:
|
|
#~ ...<type>?</type>
|
|
def _translate_memberdef_function_type( self, resultType, target=None, **kwargs ):
|
|
methodType = self._createNode('type')
|
|
self._translate_type(resultType,target=methodType)
|
|
if methodType.hasChildNodes():
|
|
target.appendChild(methodType)
|
|
return methodType
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="function"...><briefdescription>...</briefdescription></memberdef>
|
|
def _translate_memberdef_function_briefdescription( self, description, target=None, **kwargs ):
|
|
result = self._translateDescription(description,target=target,**kwargs)
|
|
## For functions if we translate the brief docs to the purpose they end up
|
|
## right above the regular description. And since we just added the brief to that
|
|
## on the previous line, don't bother with the repetition.
|
|
# result = self._translateDescription(description,target=target,tag='purpose',**kwargs)
|
|
return result
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="function"...><detaileddescription>...</detaileddescription></memberdef>
|
|
def _translate_memberdef_function_detaileddescription( self, description, target=None, **kwargs ):
|
|
return self._translateDescription(description,target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="function"...><inbodydescription>...</inbodydescription></memberdef>
|
|
def _translate_memberdef_function_inbodydescription( self, description, target=None, **kwargs ):
|
|
return self._translateDescription(description,target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="function"...><param>...</param></memberdef>
|
|
def _translate_memberdef_function_param( self, param, target=None, **kwargs ):
|
|
return self._translate_param(param,target=target,**kwargs)
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="variable" id="?">
|
|
#~ <name>...</name>
|
|
#~ <type>...</type>
|
|
#~ </memberdef>
|
|
#~ To:
|
|
#~ <data-member id="?" name="?">
|
|
#~ <type>...</type>
|
|
#~ </data-member>
|
|
def _translate_memberdef_variable( self, memberdef, target=None, scope=None, **kwargs ):
|
|
self._setID(memberdef.getAttribute('id'),
|
|
scope+'::'+self._getChildData('name',root=memberdef))
|
|
data_member = target.appendChild(self._createNode('data-member',
|
|
id=memberdef.getAttribute('id'),
|
|
name=self._getChildData('name',root=memberdef)))
|
|
data_member_type = data_member.appendChild(self._createNode('type'))
|
|
self._translate_type(self._getChild('type',root=memberdef),target=data_member_type)
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="enum" id="?">
|
|
#~ <name>...</name>
|
|
#~ ...
|
|
#~ </memberdef>
|
|
#~ To:
|
|
#~ <enum id="?" name="?">
|
|
#~ ...
|
|
#~ </enum>
|
|
def _translate_memberdef_enum( self, memberdef, target=None, scope=None, **kwargs ):
|
|
self._setID(memberdef.getAttribute('id'),
|
|
scope+'::'+self._getChildData('name',root=memberdef))
|
|
enum = target.appendChild(self._createNode('enum',
|
|
id=memberdef.getAttribute('id'),
|
|
name=self._getChildData('name',root=memberdef)))
|
|
for n in memberdef.childNodes:
|
|
self._translateNode(memberdef,'enum',n,target=enum,scope=scope,**kwargs)
|
|
return enum
|
|
|
|
#~ Translate:
|
|
#~ <memberdef kind="enum"...>
|
|
#~ <enumvalue id="?">
|
|
#~ <name>...</name>
|
|
#~ <initializer>...</initializer>
|
|
#~ </enumvalue>
|
|
#~ </memberdef>
|
|
#~ To:
|
|
#~ <enumvalue id="?" name="?">
|
|
#~ <default>...</default>
|
|
#~ </enumvalue>
|
|
def _translate_memberdef_enum_enumvalue( self, enumvalue, target=None, scope=None, **kwargs ):
|
|
self._setID(enumvalue.getAttribute('id'),
|
|
scope+'::'+self._getChildData('name',root=enumvalue))
|
|
value = target.appendChild(self._createNode('enumvalue',
|
|
id=enumvalue.getAttribute('id'),
|
|
name=self._getChildData('name',root=enumvalue)))
|
|
initializer = self._getChild('initializer',root=enumvalue)
|
|
if initializer:
|
|
self._translateChildren(initializer,
|
|
target=target.appendChild(self._createNode('default')))
|
|
return value
|
|
|
|
#~ Translate:
|
|
#~ <param>
|
|
#~ <type>...</type>
|
|
#~ <declname>...</declname>
|
|
#~ <defval>...</defval>
|
|
#~ </param>
|
|
#~ To:
|
|
#~ <parameter name="?">
|
|
#~ <paramtype>...</paramtype>
|
|
#~ ...
|
|
#~ </parameter>
|
|
def _translate_param( self, param, target=None, **kwargs):
|
|
parameter = target.appendChild(self._createNode('parameter',
|
|
name=self._getChildData('declname',root=param)))
|
|
paramtype = parameter.appendChild(self._createNode('paramtype'))
|
|
self._translate_type(self._getChild('type',root=param),target=paramtype)
|
|
defval = self._getChild('defval',root=param)
|
|
if defval:
|
|
self._translateChildren(self._getChild('defval',root=param),target=parameter)
|
|
return parameter
|
|
|
|
#~ Translate:
|
|
#~ <ref kindref="?" ...>...</ref>
|
|
def _translate_ref( self, ref, **kwargs ):
|
|
return self._translateNode(ref,ref.getAttribute('kindref'))
|
|
|
|
#~ Translate:
|
|
#~ <ref refid="?" kindref="compound">...</ref>
|
|
#~ To:
|
|
#~ <link linkend="?"><classname>...</classname></link>
|
|
def _translate_ref_compound( self, ref, **kwargs ):
|
|
result = self._createNode('link',linkend=ref.getAttribute('refid'))
|
|
classname = result.appendChild(self._createNode('classname'))
|
|
self._translateChildren(ref,target=classname)
|
|
return result
|
|
|
|
#~ Translate:
|
|
#~ <ref refid="?" kindref="member">...</ref>
|
|
#~ To:
|
|
#~ <link linkend="?">...</link>
|
|
def _translate_ref_member( self, ref, **kwargs ):
|
|
result = self._createNode('link',linkend=ref.getAttribute('refid'))
|
|
self._translateChildren(ref,target=result)
|
|
return result
|
|
|
|
#~ Translate:
|
|
#~ <type>...</type>
|
|
def _translate_type( self, type, target=None, **kwargs ):
|
|
result = self._translateChildren(type,target=target,**kwargs)
|
|
#~ Filter types to clean up various readability problems, most notably
|
|
#~ with really long types.
|
|
xml = target.toxml('utf-8');
|
|
if (
|
|
xml.startswith('<type>boost::mpl::') or
|
|
xml.startswith('<type>BOOST_PP_') or
|
|
re.match('<type>boost::(lazy_)?(enable|disable)_if',xml)
|
|
):
|
|
while target.firstChild:
|
|
target.removeChild(target.firstChild)
|
|
target.appendChild(self._createText('emphasis','unspecified'))
|
|
return result
|
|
|
|
def _getChild( self, tag = None, id = None, name = None, root = None ):
|
|
if not root:
|
|
root = self.boostbook.documentElement
|
|
for n in root.childNodes:
|
|
found = True
|
|
if tag and found:
|
|
found = found and tag == n.nodeName
|
|
if id and found:
|
|
if n.hasAttribute('id'):
|
|
found = found and n.getAttribute('id') == id
|
|
else:
|
|
found = found and n.hasAttribute('id') and n.getAttribute('id') == id
|
|
if name and found:
|
|
found = found and n.hasAttribute('name') and n.getAttribute('name') == name
|
|
if found:
|
|
#~ print '--|', n
|
|
return n
|
|
return None
|
|
|
|
def _getChildData( self, tag, **kwargs ):
|
|
return self._getData(self._getChild(tag,**kwargs),**kwargs)
|
|
|
|
def _getData( self, node, **kwargs ):
|
|
if node:
|
|
text = self._getChild('#text',root=node)
|
|
if text:
|
|
return text.data.strip()
|
|
return ''
|
|
|
|
def _cppName( self, type ):
|
|
parts = re.search('^([^<]+)[<]?(.*)[>]?$',type.strip().strip(':'))
|
|
result = {
|
|
'compoundname' : parts.group(1),
|
|
'namespace' : parts.group(1).split('::')[0:-1],
|
|
'name' : parts.group(1).split('::')[-1],
|
|
'specialization' : parts.group(2)
|
|
}
|
|
if result['namespace'] and len(result['namespace']) > 0:
|
|
namespace = '::'.join(result['namespace'])
|
|
while (
|
|
len(result['namespace']) > 0 and (
|
|
namespace not in self.symbols or
|
|
self.symbols[namespace]['kind'] != 'namespace')
|
|
):
|
|
result['name'] = result['namespace'].pop()+'::'+result['name']
|
|
namespace = '::'.join(result['namespace'])
|
|
return result
|
|
|
|
def _createNode( self, tag, **kwargs ):
|
|
result = self.boostbook.createElement(tag)
|
|
for k in kwargs.keys():
|
|
if kwargs[k] != '':
|
|
if k == 'id':
|
|
result.setAttribute('id',kwargs[k])
|
|
else:
|
|
result.setAttribute(k,kwargs[k])
|
|
return result
|
|
|
|
def _createText( self, tag, data, **kwargs ):
|
|
result = self._createNode(tag,**kwargs)
|
|
data = data.strip()
|
|
if len(data) > 0:
|
|
result.appendChild(self.boostbook.createTextNode(data))
|
|
return result
|
|
|
|
|
|
def main( xmldir=None, output=None, id=None, title=None, index=False ):
|
|
#~ print '--- main: xmldir = %s, output = %s' % (xmldir,output)
|
|
|
|
input = glob.glob( os.path.abspath( os.path.join( xmldir, "*.xml" ) ) )
|
|
input.sort
|
|
translator = Doxygen2BoostBook(id=id, title=title, index=index)
|
|
#~ Feed in the namespaces first to build up the set of namespaces
|
|
#~ and definitions so that lookup is unambiguous when reading in the definitions.
|
|
namespace_files = filter(
|
|
lambda x:
|
|
os.path.basename(x).startswith('namespace'),
|
|
input)
|
|
decl_files = filter(
|
|
lambda x:
|
|
not os.path.basename(x).startswith('namespace') and not os.path.basename(x).startswith('_'),
|
|
input)
|
|
for dox in namespace_files:
|
|
#~ print '--|',os.path.basename(dox)
|
|
translator.addDox(xml.dom.minidom.parse(dox))
|
|
for dox in decl_files:
|
|
#~ print '--|',os.path.basename(dox)
|
|
translator.addDox(xml.dom.minidom.parse(dox))
|
|
|
|
if output:
|
|
output = open(output,'w')
|
|
else:
|
|
output = sys.stdout
|
|
if output:
|
|
output.write(translator.tostring())
|
|
|
|
|
|
main( **get_args() )
|