--- /dev/null
+'''
+Created on Nov 9, 2010
+
+@author: tsitkova
+'''
+import re
+
+from Cheetah.Template import Template
+
+class Attribute(object):
+ def __init__(self, **argkw):
+ self.name = argkw.get('name')
+ self.type = argkw.get('type')
+ self.typeId = argkw.get('typeId')
+ self.short_description = argkw.get('short_description')
+ self.long_description = argkw.get('long_description')
+ self.version = argkw.get('version')
+
+ def __repr__(self):
+ result = list()
+ for (attr,value) in self.__dict__.iteritems():
+ result.append('%s=%s' % (attr,value))
+ return 'Attribute: %s' % ','.join(result)
+
+
+class CompositeType():
+ def __init__(self, **argkw):
+ self.category = 'composite'
+ self.name = argkw.get('name')
+ self.Id = argkw.get('Id')
+ self.active = argkw.get('active', False)
+ self.version = argkw.get('version')
+ self.return_type = argkw.get('return_type')
+ self.short_description = argkw.get('short_description')
+ self.long_description = argkw.get('long_description')
+ self.friends = argkw.get('friends')
+ self.type = argkw.get('type')
+ self.attributes = self._setAttributes(argkw.get('attributes'))
+
+ def __repr__(self):
+ result = list()
+ for (attr,value) in self.__dict__.iteritems():
+ if attr == 'attributes':
+ if value is not None:
+ attributes = ['%s' % a for a in value]
+ value = '\n %s' % '\n '.join(attributes)
+
+ result.append('%s: %s' % (attr,value))
+ result = '\n'.join(result)
+
+ return result
+
+ def _setAttributes(self, attributes):
+ result = None
+ if attributes is not None:
+ result = list()
+ for a in attributes:
+ result.append(Attribute(**a))
+
+ return result
+
+ def struct_reference(self, name):
+ result = re.sub(r'_', '-', name)
+ result = '_%s-struct' % result
+
+ return result
+
+class Parameter(object):
+ def __init__(self, **argkw):
+ self.seqno = argkw.get('seqno')
+ self.name = argkw.get('name')
+ self.direction = argkw.get('direction')
+ self.type = argkw.get('type')
+ self.typeId = argkw.get('typeId')
+ self.description = argkw.get('description')
+ self.version = argkw.get('version')
+
+ def __repr__(self):
+ content = (self.name,self.direction,self.seqno,self.type,self.typeId,self.description)
+ return 'Parameter: name=%s,direction=%s,seqno=%s,type=%s,typeId=%s,descr=%s' % content
+
+class Function(object):
+ def __init__(self, **argkw):
+ self.category = 'function'
+ self.name = argkw.get('name')
+ self.Id = argkw.get('Id')
+ self.active = argkw.get('active', False)
+ self.version = argkw.get('version')
+ self.parameters = self._setParameters(argkw.get('parameters'))
+ self.return_type = argkw.get('return_type')
+ self.return_description = argkw.get('return_description')
+ self.retval_description = argkw.get('retval_description')
+ self.warn_description = argkw.get('warn_description')
+ self.sa_description = argkw.get('sa_description')
+ self.notes_description = argkw.get('notes_description')
+ self.short_description = argkw.get('short_description')
+ self.long_description = argkw.get('long_description')
+ self.deprecated_description = argkw.get('deprecated_description')
+ self.friends = argkw.get('friends')
+
+ def _setParameters(self, parameters):
+ result = None
+ if parameters is not None:
+ result = list()
+ for p in parameters:
+ result.append(Parameter(**p))
+
+ return result
+
+ def getObjectRow(self):
+ result = [str(self.Id),
+ self.name,
+ self.category]
+
+ return ','.join(result)
+
+ def getObjectDescriptionRow(self):
+ result = [self.Id,
+ self.active,
+ self.version,
+ self.short_description,
+ self.long_description]
+
+ return ','.join(result)
+
+ def getParameterRows(self):
+ result = list()
+ for p in self.parameters:
+ p_row = [self.Id,
+ p.name,
+ p.seqno,
+ p.type,
+ p.typeId,
+ p.description,
+ p.version]
+ result.append(','.join(p_row))
+
+ return '\n'.join(result)
+
+ def __repr__(self):
+ lines = list()
+ lines.append('Category: %s' % self.category)
+ lines.append('Function name: %s' % self.name)
+ lines.append('Function Id: %s' % self.Id)
+ parameters = [' %s' % p for p in self.parameters]
+ lines.append('Parameters:\n%s' % '\n'.join(parameters))
+ lines.append('Function return type: %s' % self.return_type)
+ lines.append('Function return type description:\n%s' % self.return_description)
+ lines.append('Function retval description:\n%s' % self.retval_description)
+ lines.append('Function short description:\n%s' % self.short_description)
+ lines.append('Function long description:\n%s' % self.long_description)
+ lines.append('Warning description:\n%s' % self.warn_description)
+ lines.append('See also description:\n%s' % self.sa_description)
+ lines.append('NOTE description:\n%s' % self.notes_description)
+ lines.append('Deprecated description:\n%s' % self.deprecated_description)
+ result = '\n'.join(lines)
+
+ return result
+
+
+class DocModel(object):
+ def __init__(self, **argkw):
+ if len(argkw):
+ self.name = argkw['name']
+ if argkw['category'] == 'function':
+ self.category = 'function'
+ self.function = Function(**argkw)
+ elif argkw['category'] == 'composite':
+ self.category = 'composite'
+ self.composite = CompositeType(**argkw)
+
+ def __repr__(self):
+ obj = getattr(self,self.category)
+ print type(obj)
+ return str(obj)
+
+ def signature(self):
+ param_list = list()
+ for p in self.function.parameters:
+ if p.type is "... " :
+ param_list.append('%s %s' % (p.type,' '))
+ else:
+ param_list.append('%s %s' % (p.type, p.name))
+ param_list = ', '.join(param_list)
+ result = '%s %s(%s)' % (self.function.return_type,
+ self.function.name, param_list)
+
+ return result
+
+ def save(self, path, template_path):
+ f = open(template_path, 'r')
+ t = Template(f.read(),self)
+ out = open(path, 'w')
+ out.write(str(t))
+ out.close()
+ f.close()
+
+
+class DocModelTest(DocModel):
+ def __init__(self):
+ doc_path = '../docutil/example.yml'
+ argkw = yaml.load(open(doc_path,'r'))
+ super(DocModelTest,self).__init__(**argkw)
+
+ def run_tests(self):
+ self.test_save()
+
+ def test_print(self):
+ print 'testing'
+ print self
+
+
+ def test_save(self):
+ template_path = '../docutil/function2edit.html'
+
+ path = '/var/tsitkova/Sources/v10/trunk/documentation/test_doc.html'
+
+ self.save(path, template_path)
+
+if __name__ == '__main__':
+ tester = DocModelTest()
+ tester.run_tests()
--- /dev/null
+'''
+ Copyright 2011 by the Massachusetts
+ Institute of Technology. All Rights Reserved.
+
+ Export of this software from the United States of America may
+ require a specific license from the United States Government.
+ It is the responsibility of any person or organization contemplating
+ export to obtain such a license before exporting.
+
+ WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ distribute this software and its documentation for any purpose and
+ without fee is hereby granted, provided that the above copyright
+ notice appear in all copies and that both that copyright notice and
+ this permission notice appear in supporting documentation, and that
+ the name of M.I.T. not be used in advertising or publicity pertaining
+ to distribution of the software without specific, written prior
+ permission. Furthermore if you modify this software you must label
+ your software as modified software and not distribute it in such a
+ fashion that it might be confused with the original M.I.T. software.
+ M.I.T. makes no representations about the suitability of
+ this software for any purpose. It is provided "as is" without express
+ or implied warranty.
+'''
+import sys
+import os
+import re
+from optparse import OptionParser
+
+
+from doxybuilder_types import *
+from doxybuilder_funcs import *
+
+
+def processOptions():
+ usage = "\n\t\t%prog -t type -i in_dir -o out_dir"
+ description = "Description:\n\tProcess doxygen output for c-types and/or functions"
+ parser = OptionParser(usage=usage, description=description)
+
+ parser.add_option("-t", "--type", type="string", dest="action_type", help="process typedef and/or function. Possible choices: typedef, func, all. Default: all.", default="all")
+ parser.add_option("-i", "--in", type="string", dest="in_dir", help="input directory")
+ parser.add_option("-o", "--out", type="string", dest= "out_dir", help="output directory. Note: The subdirectory ./types will be created for typedef")
+
+ (options, args) = parser.parse_args()
+ action = options.action_type
+ in_dir = options.in_dir
+ out_dir = options.out_dir
+
+
+ if in_dir is None or out_dir is None:
+ parser.error("Input and output directories are required")
+
+ if action == "all" or action == "typedef":
+ tester = DoxyTypesTest(in_dir, out_dir)
+ tester.run_tests()
+
+ if action == "all" or action == "func" or action == "function":
+ tester = DoxyFuncsTest(in_dir, out_dir)
+ tester.run_tests()
+
+
+if __name__ == '__main__':
+ parser = processOptions()
+
+
--- /dev/null
+'''
+ Copyright 2011 by the Massachusetts
+ Institute of Technology. All Rights Reserved.
+
+ Export of this software from the United States of America may
+ require a specific license from the United States Government.
+ It is the responsibility of any person or organization contemplating
+ export to obtain such a license before exporting.
+
+ WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ distribute this software and its documentation for any purpose and
+ without fee is hereby granted, provided that the above copyright
+ notice appear in all copies and that both that copyright notice and
+ this permission notice appear in supporting documentation, and that
+ the name of M.I.T. not be used in advertising or publicity pertaining
+ to distribution of the software without specific, written prior
+ permission. Furthermore if you modify this software you must label
+ your software as modified software and not distribute it in such a
+ fashion that it might be confused with the original M.I.T. software.
+ M.I.T. makes no representations about the suitability of
+ this software for any purpose. It is provided "as is" without express
+ or implied warranty.
+'''
+import sys
+import re
+
+from collections import defaultdict
+from xml.sax import make_parser
+from xml.sax.handler import ContentHandler
+from docmodel import *
+
+class DocNode(object):
+ """
+ Represents the structure of xml node.
+ """
+ def __init__(self, name):
+ """
+ @param node: name - the name of a node.
+ @param attributes: a dictionary populated with attributes of a node
+ @param children: a dictionary with lists of children nodes. Nodes
+ in lists are ordered as they appear in a document.
+ @param content: a content of xml node represented as a list of
+ tuples [(type,value)] with type = ['char'|'element'].
+ If type is 'char' then the value is a character string otherwise
+ it is a reference to a child node.
+ """
+ self.name = name
+ self.content = list()
+ self.attributes = dict()
+ self.children = defaultdict(list)
+
+ def walk(self, decorators, sub_ws, stack=[]):
+ result = list()
+ decorator = decorators.get(self.name, decorators['default'])
+ stack.append(decorators['default'])
+ decorators['default'] = decorator
+
+ for (obj_type,obj) in self.content:
+ if obj_type == 'char':
+ if obj != '':
+ result.append(obj)
+ else:
+ partial = obj.walk(decorators,1, stack)
+ if partial is not None:
+ result.append(' %s ' % partial)
+ decorators['default'] = stack.pop()
+ result = decorator(self, ''.join(result))
+ if result is not None:
+ if sub_ws == 1:
+ result = re.sub(r'[ ]+', r' ', result)
+ else:
+ result = result.strip()
+
+ return result
+
+ def getContent(self):
+ decorators = {'default': lambda node,value: value}
+ result = self.walk(decorators, 1)
+ if len(result) == 0:
+ result = None
+
+ return result
+
+ def __repr__(self):
+ result = ['Content: %s' % self.content]
+
+ for (key,value) in self.attributes.iteritems():
+ result.append('Attr: %s = %s' % (key,value))
+ for (key,value) in self.children.iteritems():
+ result.append('Child: %s,%i' % (key,len(value)))
+
+ return '\n'.join(result)
+
+class DoxyContenHandler(object, ContentHandler):
+ def __init__(self, builder):
+ self.builder = builder
+ self.counters = defaultdict(int)
+ self._nodes = None
+ self._current = None
+
+ def startDocument(self):
+ pass
+
+ def endDocument(self):
+ import sys
+
+ def startElement(self, name, attrs):
+ if name == self.builder.toplevel:
+ self._nodes = []
+
+ if name == 'memberdef':
+ kind = attrs.get('kind')
+ if kind is None:
+ raise ValueError('Kind is not defined')
+ self.counters[kind] += 1
+
+ if self._nodes is None:
+ return
+
+ node = DocNode(name)
+ for (key,value) in attrs.items():
+ node.attributes[key] = value
+ if self._current is not None:
+ self._current.children[name].append(node)
+ self._nodes.append(self._current)
+ self._current = node
+
+ def characters(self, content):
+
+ if self._current is not None:
+ self._current.content.append(('char',content.strip()))
+
+ def endElement(self, name):
+ if name == self.builder.toplevel:
+ assert(len(self._nodes) == 0)
+ self._nodes = None
+ self.builder.document.append(self._current)
+ self._current = None
+ else:
+ if self._nodes is not None:
+ node = self._current
+ self._current = self._nodes.pop()
+ self._current.content.append(('element',node))
+
+
+class XML2AST(object):
+ """
+ Translates XML document into Abstract Syntax Tree like representation
+ The content of document is stored in self.document
+ """
+ def __init__(self, xmlpath, toplevel='doxygen'):
+ self.document = list()
+ self.toplevel = toplevel
+ self.parser = make_parser()
+ handler = DoxyContenHandler(self)
+ self.parser.setContentHandler(handler)
+ filename = 'krb5_8hin.xml'
+ filepath = '%s/%s' % (xmlpath,filename)
+ self.parser.parse(open(filepath,'r'))
+
+
+class DoxyFuncs(XML2AST):
+ def __init__(self, path):
+ super(DoxyFuncs, self).__init__(path,toplevel='memberdef')
+ self.objects = list()
+
+ def run(self):
+ for node in self.document:
+ self.process(node)
+ print "\nnumber of functions processed ===> ",len(self.objects)
+
+ def process(self, node):
+ node_type = node.attributes['kind']
+ if node_type == 'function':
+ data = self._process_function_node(node)
+ else:
+ print 'not processing node: %s' % node_type
+ return
+
+ self.objects.append(DocModel(**data))
+
+ def save(self, templates, target_dir):
+ for obj in self.objects:
+ template_path = templates[obj.category]
+ outpath = '%s/%s.rst' % (target_dir,obj.name)
+ obj.save(outpath, template_path)
+
+
+ def _process_function_node(self, node):
+ f_name = node.children['name'][0].getContent()
+ print f_name
+ f_Id = node.attributes['id']
+ f_ret_type = self._process_type_node(node.children['type'][0])
+ f_brief = node.children['briefdescription'][0].getContent()
+ f_detailed = node.children['detaileddescription'][0]
+ detailed_description = self._process_description_node(f_detailed)
+ return_value_description = self._process_return_value_description(f_detailed)
+ retval_description = self._process_retval_description(f_detailed)
+ warning_description = self._process_warning_description(f_detailed)
+ seealso_description = self._process_seealso_description(f_detailed)
+ notes_description = self._process_notes_description(f_detailed)
+ deprecated_description = self._process_deprecated_description(f_detailed)
+ param_description_map = self.process_parameter_description(f_detailed)
+ f_definition = node.children['definition'][0].getContent()
+ f_argsstring = node.children['argsstring'][0].getContent()
+
+ function_descr = {'category': 'function',
+ 'name': f_name,
+ 'Id': f_Id,
+ 'return_type': f_ret_type[1],
+ 'return_description': return_value_description,
+ 'retval_description': retval_description,
+ 'sa_description': seealso_description,
+ 'warn_description': warning_description,
+ 'notes_description': notes_description,
+ 'short_description': f_brief,
+ 'long_description': detailed_description,
+ 'deprecated_description': deprecated_description,
+ 'parameters': list()}
+
+ parameters = function_descr['parameters']
+ for (i,p) in enumerate(node.children['param']):
+ type_node = p.children['type'][0]
+ p_type = self._process_type_node(type_node)
+ if p_type[1].find('...') > -1 :
+ p_name = ''
+ else:
+ p_name = None
+ p_name_node = p.children.get('declname')
+ if p_name_node is not None:
+ p_name = p_name_node[0].getContent()
+ (p_direction,p_descr) = param_description_map.get(p_name,(None,None))
+
+ param_descr = {'seqno': i,
+ 'name': p_name,
+ 'direction': p_direction,
+ 'type': p_type[1],
+ 'typeId': p_type[0],
+ 'description': p_descr}
+ parameters.append(param_descr)
+ result = Function(**function_descr)
+ print >> self.tmp, result
+
+ return function_descr
+
+ def _process_type_node(self, type_node):
+ """
+ Type node has form
+ <type>type_string</type>
+ for build in types and
+ <type>
+ <ref refid='reference',kindref='member|compound'>
+ 'type_name'
+ </ref></type>
+ postfix (ex. *, **m, etc.)
+ </type>
+ for user defined types.
+ """
+ type_ref_node = type_node.children.get('ref')
+ if type_ref_node is not None:
+ p_type_id = type_ref_node[0].attributes['refid']
+ else:
+ p_type_id = None
+ p_type = type_node.getContent()
+ # remove some macros
+ p_type = re.sub('KRB5_ATTR_DEPRECATED', '', p_type)
+ p_type = re.sub('KRB5_CALLCONV_C', '', p_type)
+ p_type = re.sub('KRB5_CALLCONV_WRONG', '', p_type)
+ p_type = re.sub('KRB5_CALLCONV', '', p_type)
+ p_type = p_type.strip()
+
+ return (p_type_id, p_type)
+
+ def _process_description_node(self, node):
+ """
+ Description node is comprised of <para>...</para> sections
+ """
+ para = node.children.get('para')
+ result = list()
+ if para is not None:
+ decorators = {'default': self.paragraph_content_decorator}
+ for e in para:
+ result.append(str(e.walk(decorators, 1)))
+ result.append('\n')
+ result = '\n'.join(result)
+
+ return result
+
+ def return_value_description_decorator(self, node, value):
+ if node.name == 'simplesect':
+ if node.attributes['kind'] == 'return':
+ cont = set()
+ cont = node.getContent()
+ return value
+ else:
+ return None
+
+ def paragraph_content_decorator(self, node, value):
+ if node.name == 'para':
+ return value + '\n'
+ elif node.name == 'simplesect':
+ if node.attributes['kind'] == 'return':
+ return None
+ elif node.name == 'ref':
+ return ':c:func:' + '`' + value + '`'
+ elif node.name == 'emphasis':
+ return '*' + value + '*'
+ elif node.name == 'itemizedlist':
+ return '\n' + value
+ elif node.name == 'listitem':
+ return '\n\t - ' + value + '\n'
+ elif node.name == 'computeroutput':
+ return '**' + value + '**'
+ else:
+ return None
+
+ def parameter_name_decorator(self, node, value):
+ if node.name == 'parametername':
+ direction = node.attributes.get('direction')
+ if direction is not None:
+ value = '%s:%s' % (value,direction)
+ return value
+
+ elif node.name == 'parameterdescription':
+ return None
+ else:
+ return value
+
+ def parameter_description_decorator(self, node, value):
+ if node.name == 'parameterdescription':
+ return value
+ elif node.name == 'parametername':
+ return None
+ else:
+ return value
+
+ def process_parameter_description(self, node):
+ """
+ Parameter descriptions reside inside detailed description section.
+ """
+ para = node.children.get('para')
+ result = dict()
+ if para is not None:
+ for e in para:
+
+ param_list = e.children.get('parameterlist')
+ if param_list is None:
+ continue
+ param_items = param_list[0].children.get('parameteritem')
+ if param_items is None:
+ continue
+ for it in param_items:
+ decorators = {'default': self.parameter_name_decorator}
+ direction = None
+ name = it.walk(decorators,0).split(':')
+ if len(name) == 2:
+ direction = name[1]
+
+ decorators = {'default': self.parameter_description_decorator,
+ 'para': self.paragraph_content_decorator}
+ description = it.walk(decorators, 0)
+ result[name[0]] = (direction,description)
+ return result
+
+
+ def _process_return_value_description(self, node):
+ result = None
+ ret = list()
+
+ para = node.children.get('para')
+ if para is not None:
+ for p in para:
+ simplesect_list = p.children.get('simplesect')
+ if simplesect_list is None:
+ continue
+ for it in simplesect_list:
+ decorators = {'default': self.return_value_description_decorator,
+ 'para': self.parameter_name_decorator}
+ result = it.walk(decorators, 1)
+ if result is not None:
+ ret.append(result)
+ return ret
+
+
+ def _process_retval_description(self, node):
+ """
+ retval descriptions reside inside detailed description section.
+ """
+ para = node.children.get('para')
+
+ result = None
+ ret = list()
+ if para is not None:
+
+ for e in para:
+ param_list = e.children.get('parameterlist')
+ if param_list is None:
+ continue
+ for p in param_list:
+ kind = p.attributes['kind']
+ if kind == 'retval':
+
+ param_items = p.children.get('parameteritem')
+ if param_items is None:
+ continue
+
+
+ for it in param_items:
+ param_descr = it.children.get('parameterdescription')
+ if param_descr is not None:
+ val = param_descr[0].children.get('para')
+
+ if val is not None:
+ val_descr = val[0].getContent()
+
+ else:
+ val_descr =''
+
+ decorators = {'default': self.parameter_name_decorator}
+
+ name = it.walk(decorators, 1).split(':')
+
+ val = name[0]
+ result = " %s %s" % (val, val_descr)
+ ret.append (result)
+ return ret
+
+ def return_warning_decorator(self, node, value):
+ if node.name == 'simplesect':
+ if node.attributes['kind'] == 'warning':
+ return value
+ else:
+ return None
+
+ def _process_warning_description(self, node):
+ result = None
+ para = node.children.get('para')
+ if para is not None:
+ for p in para:
+ simplesect_list = p.children.get('simplesect')
+ if simplesect_list is None:
+ continue
+ for it in simplesect_list:
+ decorators = {'default': self.return_warning_decorator,
+ 'para': self.paragraph_content_decorator}
+ result = it.walk(decorators, 1)
+ # Assuming that only one Warning per function
+ if result is not None:
+ return result
+ return result
+
+ def return_seealso_decorator(self, node, value):
+ if node.name == 'simplesect':
+ if node.attributes['kind'] == 'see':
+ return value
+ else:
+ return None
+
+ def _process_seealso_description(self, node):
+ result = None
+ para = node.children.get('para')
+ if para is not None:
+ for p in para:
+ simplesect_list = p.children.get('simplesect')
+ if simplesect_list is None:
+ continue
+ for it in simplesect_list:
+ decorators = {'default': self.return_seealso_decorator,
+ 'para': self.paragraph_content_decorator}
+ result = it.walk(decorators, 1)
+ return result
+
+ def return_notes_decorator(self, node, value):
+ if node.name == 'simplesect':
+ if node.attributes['kind'] == 'note':
+ return value
+ else:
+ return None
+
+ def _process_notes_description(self, node):
+ result = None
+ para = node.children.get('para')
+ if para is not None:
+ for p in para:
+ simplesect_list = p.children.get('simplesect')
+ if simplesect_list is None:
+ continue
+ for it in simplesect_list:
+ decorators = {'default': self.return_notes_decorator,
+ 'para': self.paragraph_content_decorator}
+ result = it.walk(decorators, 1)
+ if result is not None:
+ return result
+ return result
+
+ def return_deprecated_decorator(self, node, value):
+ if node.name == 'xrefsect':
+ if node.attributes['id'].find('deprecated_') > -1:
+ xreftitle = node.children.get('xreftitle')
+ if xreftitle[0] is not None:
+ xrefdescr = node.children.get('xrefdescription')
+ deprecated_descr = "DEPRECATED %s" % xrefdescr[0].getContent()
+ return deprecated_descr
+ else:
+ return None
+
+ def _process_deprecated_description(self, node):
+ result = None
+ para = node.children.get('para')
+ if para is not None:
+ for p in para:
+ xrefsect_list = p.children.get('xrefsect')
+ if xrefsect_list is None:
+ continue
+ for it in xrefsect_list:
+ decorators = {'default': self.return_deprecated_decorator,
+ 'para': self.paragraph_content_decorator}
+ result = it.walk(decorators, 1)
+ if result is not None:
+ return result
+ return result
+
+ def break_into_lines(self, value, linelen=82):
+ breaks = range(0,len(value),linelen) + [len(value)]
+ result = list()
+ for (start,end) in zip(breaks[:-1],breaks[1:]):
+ result.append(value[start:end])
+ result = '\n'.join(result)
+
+ return result
+
+ def _save(self, table, path = None):
+ if path is None:
+ f = sys.stdout
+ else:
+ f = open(path, 'w')
+ for l in table:
+ f.write('%s\n' % ','.join(l))
+ if path is not None:
+ f.close()
+
+
+
+class DoxyFuncsTest(DoxyFuncs):
+ def __init__(self, xmlpath, rstpath):
+ super(DoxyFuncsTest,self).__init__(xmlpath)
+ self.target_dir = rstpath
+ outfile = '%s/%s' % (self.target_dir, 'out.txt')
+ self.tmp = open(outfile, 'w')
+
+ def run_tests(self):
+ self.test_save()
+
+ def test_run(self):
+ self.run()
+
+ def test_save(self):
+ self.run()
+ templates = {'function': 'func_document.tmpl'}
+ self.save(templates, self.target_dir)
+
+if __name__ == '__main__':
+ tester = DoxyFuncsTest(xmlpath, rstpath)
+ tester.run_tests()
+
--- /dev/null
+'''
+ Copyright 2011 by the Massachusetts
+ Institute of Technology. All Rights Reserved.
+
+ Export of this software from the United States of America may
+ require a specific license from the United States Government.
+ It is the responsibility of any person or organization contemplating
+ export to obtain such a license before exporting.
+
+ WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ distribute this software and its documentation for any purpose and
+ without fee is hereby granted, provided that the above copyright
+ notice appear in all copies and that both that copyright notice and
+ this permission notice appear in supporting documentation, and that
+ the name of M.I.T. not be used in advertising or publicity pertaining
+ to distribution of the software without specific, written prior
+ permission. Furthermore if you modify this software you must label
+ your software as modified software and not distribute it in such a
+ fashion that it might be confused with the original M.I.T. software.
+ M.I.T. makes no representations about the suitability of
+ this software for any purpose. It is provided "as is" without express
+ or implied warranty.
+'''
+import sys
+import os
+import re
+
+from lxml import etree
+
+from docmodel import *
+
+
+class DoxyTypes(object):
+ def __init__(self, xmlpath):
+ self.xmlpath = xmlpath
+
+ def run_compound(self, filename, include=None):
+ path = '%s/%s' % (self.xmlpath,filename)
+ tree = etree.parse(path)
+ root = tree.getroot()
+
+ brief_node = root.xpath('./compounddef/briefdescription')[0]
+ brief_description = self._get_brief_description(brief_node)
+ details_node = root.xpath('./compounddef/detaileddescription')[0]
+ detailed_description = self._get_detailed_description(details_node)
+
+ fields = list()
+ for node in root.iterfind(".//memberdef[@kind]"):
+ data = {}
+ kind = node.attrib['kind']
+ if include is None or kind in include:
+ if kind == 'variable':
+ data = self._process_variable_node(node)
+ else:
+ pass
+ fields.append(data)
+
+ result = {'brief_description': brief_description,
+ 'detailed_description': detailed_description,
+ 'attributes': fields}
+
+ return result
+
+
+
+ def run(self, filename, include=None):
+ """
+ Parses xml file generated by doxygen.
+
+ @param filename: doxygen xml file name
+ @param include: members sections to include, in None -- include all
+ """
+ path = '%s/%s' % (self.xmlpath,filename)
+ tree = etree.parse(path)
+ root = tree.getroot()
+ result = list()
+ for node in root.iterfind(".//memberdef[@kind]"):
+ data = {}
+ kind = node.attrib['kind']
+ if include is None or kind in include:
+ if kind == 'typedef':
+ data = self._process_typedef_node(node)
+ elif kind == 'variable':
+ data = self._process_variable_node(node)
+ result.append(data)
+ print "\nnumber of types processed ==> " , len(result)
+ return result
+
+
+ def _process_typedef_node(self, node):
+ t_name = node.xpath('./name/text()')[0]
+
+ print t_name
+
+ t_Id = node.attrib['id']
+ t_definition = node.xpath('./definition/text()')[0]
+ t_type = self._process_type_node(node.xpath("./type")[0])
+ brief_node = node.xpath('./briefdescription')[0]
+ t_brief = self._get_brief_description(brief_node)
+ details_node = node.xpath('./detaileddescription')[0]
+ t_detailed = self._get_detailed_description(details_node)
+
+ typedef_descr = {'category': 'composite',
+ 'name': t_name,
+ 'Id': t_Id,
+ 'type': t_type[1],
+ 'short_description': t_brief,
+ 'long_description': t_detailed,
+ 'attributes': list()
+ }
+ if t_type[0] is not None :
+ filename = '%s.xml' % t_type[0]
+ path = '%s/%s' % (self.xmlpath,filename)
+ if not os.path.exists(path):
+ # nothing can be done
+ return typedef_descr
+
+ compound_info = self.run_compound(filename)
+ if compound_info is not None:
+ brief_description = compound_info.get('brief_description')
+ if brief_description is not None and len(brief_description):
+ # override brief description
+ typedef_descr['short_description'] = brief_description
+ detailed_description = compound_info.get('detailed_description')
+ if detailed_description is not None and len(detailed_description):
+ # check if this is not a duplicate
+ if detailed_description.find(t_detailed) < 0:
+ typedef_descr['long_description'] = '%s\n%s' % \
+ (detailed_description,
+ typedef_descr['long_description'])
+ typedef_descr['attributes'] = compound_info['attributes']
+ return typedef_descr
+
+ def _process_variable_node(self, node):
+ v_name = node.xpath('./name/text()')[0]
+ v_Id = node.attrib['id']
+ v_definition = node.xpath('./definition/text()')[0]
+ v_type = self._process_type_node(node.xpath("./type")[0])
+ brief_node = node.xpath('./briefdescription')[0]
+ v_brief = self._get_brief_description(brief_node)
+ details_node = node.xpath('./detaileddescription')[0]
+ detailed_description = self._get_detailed_description(details_node)
+
+ variable_descr = {'category': 'variable',
+ 'name': v_name,
+ 'Id': v_Id,
+ 'type': v_type[1],
+ 'short_description': v_brief,
+ 'long_description': detailed_description
+ }
+
+ return variable_descr
+
+
+ def _get_brief_description(self, node):
+ result = list()
+ for p in node.xpath("./para"):
+ x = self._process_paragraph_content(p)
+ if x is not None and len(x):
+ result.append(x)
+ result = '\n'.join(result)
+
+ return result
+
+
+ def _get_detailed_description(self, node):
+ """
+ Description node is comprised of <para>...</para> sections.
+ There are few types of these sections:
+ a) Content section
+ b) Return value section -- skip
+ c) Parameter list section -- skip
+ @param node: detailed description node
+ """
+ result = list()
+ for p in node.xpath("./para"):
+ if len(p.xpath("./simplesect[@kind='return']")):
+ continue
+ elif len(p.xpath("./parameterlist[@kind='param']")):
+ continue
+ else:
+ x = self._process_paragraph_content(p)
+ result.append(x)
+ result = '\n'.join(result)
+
+ return result
+
+ def _process_paragraph_content(self, node):
+
+ result = list()
+ content = node.xpath(".//text()")
+ for e in content:
+ if node is e.getparent():
+ result.append(e.strip())
+ elif e.getparent().tag == 'ref':
+ if e.is_tail:
+ result.append(e.strip())
+ else:
+ result.append(':c:type:`%s`' % e.strip())
+ elif e.getparent().tag == 'emphasis':
+ if e.is_tail:
+ result.append(e.strip())
+ else:
+ result.append('*%s*' % e.strip())
+ elif e.getparent().tag == 'computeroutput':
+ if e.is_tail:
+ result.append(e.strip())
+ else:
+ result.append('*%s*' % e.strip())
+ result = ' '.join(result)
+
+ return result
+
+ def _process_type_node(self, node):
+ """
+ Type node has form
+ <type>type_string</type>
+ for build in types and
+ <type>
+ <ref refid='reference',kindref='member|compound'>
+ 'type_name'
+ </ref></type>
+ postfix (ex. *, **m, etc.)
+ </type>
+ for user defined types.
+ """
+ p_id = node.xpath("./ref/@refid")
+ if len(p_id) == 1:
+ p_id = p_id[0]
+ elif len(p_id) == 0:
+ p_id = None
+ p_type = ' '.join(node.xpath(".//text()"))
+
+ # remove macros
+ p_type = re.sub('KRB5_CALLCONV_C', ' ', p_type)
+ p_type = re.sub('KRB5_CALLCONV', ' ', p_type)
+
+ return (p_id,p_type)
+
+ def save(self, obj, templates, target_dir):
+ template_path = templates[obj.category]
+ outpath = '%s/%s.rst' % (target_dir,obj.name)
+ obj.save(outpath, template_path)
+
+
+
+class DoxyTypesTest(DoxyTypes):
+ def __init__(self, xmlpath, rstpath):
+ self.templates = { 'composite': 'type_document.tmpl'}
+ self.target_dir = rstpath
+
+ super(DoxyTypesTest,self).__init__(xmlpath)
+
+ def run_tests(self):
+ self.test_process_typedef_node()
+
+ # TESTS
+
+ def test_run(self):
+ filename = 'krb5_8hin.xml'
+ self.run(filename)
+
+
+ def test_process_variable_node(self):
+ filename = 'struct__krb5__octet__data.xml'
+ result = self.run(filename, include=['variable'])
+
+ def test_process_typedef_node(self):
+ # run parser for typedefs
+ filename = 'krb5_8hin.xml'
+ result = self.run(filename, include=['typedef'])
+ target_dir = '%s/types' % (self.target_dir)
+ if not os.path.exists(target_dir):
+ os.makedirs(target_dir, 0755)
+ for t in result:
+ obj = DocModel(**t)
+ self.save(obj, self.templates, target_dir)
+
+ def test_run_compound(self):
+ filename = 'struct__krb5__context.xml'
+ result = self.run_compound(filename)
+
+if __name__ == '__main__':
+
+ tester = DoxyTypesTest( xml_inpath, rst_outpath)
+ tester.run_tests()
--- /dev/null
+#if $function.short_description is not None
+ #set $title = $function.name + ' - ' + $function.short_description
+#else
+ #set $title = $function.name
+#end if
+$title
+#echo ''.join(['=']*len($title)) #
+
+:polyvox:`Doxygen reference to $function.name <$function.name>`
+
+..
+
+.. c:function:: $signature
+
+..
+
+
+:param:
+
+#for $param in $function.parameters:
+ #if $param.name is ''
+ #continue
+ #end if
+ #if $param.direction is not None
+ #set name_description = '**[%s]** **%s**' % ($param.direction, $param.name)
+ #else
+ #set name_description = '**%s**' % $param.name
+ #end if
+ #if $param.description is not None
+ #set $description= ' - ' + $param.description
+ #else
+ #set $description=''
+ #end if
+ $name_description$description
+
+#end for
+
+..
+
+#if len($function.retval_description) > 0
+
+:retval:
+#for $retval in $function.retval_description:
+ - $retval
+#end for
+#end if
+
+#if len($function.return_description) > 0
+
+:return:
+#for $retval in $function.return_description:
+ - $retval
+#end for
+#end if
+
+..
+
+#if $function.deprecated_description is not None
+
+$function.deprecated_description
+#end if
+
+
+
+
+#if $function.long_description is not None
+
+
+$function.long_description
+
+#end if
+
+
+..
+
+#if $function.sa_description is not None
+.. seealso::
+ $function.sa_description
+#end if
+
+
+#if $function.warn_description is not None or $function.notes_description is not None
+
+
+#if $function.warn_description is not None
+.. warning::
+ $function.warn_description
+#end if
+
+#if $function.notes_description is not None
+.. note::
+ $function.notes_description
+#end if
+
+#end if
+
+
+
+Feedback
+------------------
+
+#set $msg_subject = 'Documentation___' + $function.name
+
+Please, provide your feedback on this document at krb5-bugs@mit.edu?subject=$msg_subject
+
--- /dev/null
+.. highlightlang:: c
+
+.. $composite.struct_reference($composite.name):
+
+
+
+#if $composite.short_description is not None and len($composite.short_description)
+ #set $title = $composite.name + ' - ' + $composite.short_description
+#else
+ #set $title = $composite.name
+#end if
+$title
+#echo ''.join(['=']*len($title)) #
+
+
+
+:polyvox:`Doxygen reference to $composite.name <$composite.name>`
+
+..
+.. c:type:: $composite.name
+..
+
+$composite.long_description
+
+
+#if $composite.Id is not None and $composite.name is not 'krb5_trace_callback'
+
+
+#if len($composite.attributes)
+
+Members
+---------
+
+#else
+
+#if $composite.type is not None
+typedef :c:type:`$composite.type` $composite.name
+#end if
+
+#end if
+
+#for $attr in $composite.attributes:
+#if $attr.name is not None
+.. c:member:: $attr.type $composite.name.$attr.name
+
+ $attr.short_description
+#if $attr.long_description is not None
+ $attr.long_description
+#end if
+
+#end if
+#end for
+#end if
+
+
+Feedback
+----------
+
+#set $msg_subject = 'Documentation___' + $composite.name
+
+Please, provide your feedback on this document at krb5-bugs@mit.edu?subject=$msg_subject
+