diff options
Diffstat (limited to 'jam-files/boost-build/tools/doxproc.py')
-rw-r--r-- | jam-files/boost-build/tools/doxproc.py | 859 |
1 files changed, 859 insertions, 0 deletions
diff --git a/jam-files/boost-build/tools/doxproc.py b/jam-files/boost-build/tools/doxproc.py new file mode 100644 index 00000000..4cbd5edd --- /dev/null +++ b/jam-files/boost-build/tools/doxproc.py @@ -0,0 +1,859 @@ +#!/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 options.has_key( '--help' ): + usage() + sys.exit(1) + + return { + 'xmldir' : options['--xmldir'], + 'output' : options['--output'], + 'id' : options['--id'], + 'title' : options['--title'], + 'index' : options.has_key('--enable-index') + } + +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 (self.idmap.has_key(node.getAttribute('linkend'))): + #~ 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 self.idmap.has_key(node.getAttribute('id')): + #~ 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 self.symbols.has_key(namespace['name']): + 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 not self.symbols.has_key(name): + 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 ( + not self.symbols.has_key(namespace) 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() ) |