xref: /freebsd/crypto/krb5/doc/tools/doxybuilder_funcs.py (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert'''
2*7f2fe78bSCy Schubert  Copyright 2011 by the Massachusetts
3*7f2fe78bSCy Schubert  Institute of Technology.  All Rights Reserved.
4*7f2fe78bSCy Schubert
5*7f2fe78bSCy Schubert  Export of this software from the United States of America may
6*7f2fe78bSCy Schubert  require a specific license from the United States Government.
7*7f2fe78bSCy Schubert  It is the responsibility of any person or organization contemplating
8*7f2fe78bSCy Schubert  export to obtain such a license before exporting.
9*7f2fe78bSCy Schubert
10*7f2fe78bSCy Schubert  WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11*7f2fe78bSCy Schubert  distribute this software and its documentation for any purpose and
12*7f2fe78bSCy Schubert  without fee is hereby granted, provided that the above copyright
13*7f2fe78bSCy Schubert  notice appear in all copies and that both that copyright notice and
14*7f2fe78bSCy Schubert  this permission notice appear in supporting documentation, and that
15*7f2fe78bSCy Schubert  the name of M.I.T. not be used in advertising or publicity pertaining
16*7f2fe78bSCy Schubert  to distribution of the software without specific, written prior
17*7f2fe78bSCy Schubert  permission.  Furthermore if you modify this software you must label
18*7f2fe78bSCy Schubert  your software as modified software and not distribute it in such a
19*7f2fe78bSCy Schubert  fashion that it might be confused with the original M.I.T. software.
20*7f2fe78bSCy Schubert  M.I.T. makes no representations about the suitability of
21*7f2fe78bSCy Schubert  this software for any purpose.  It is provided "as is" without express
22*7f2fe78bSCy Schubert  or implied warranty.
23*7f2fe78bSCy Schubert'''
24*7f2fe78bSCy Schubertimport sys
25*7f2fe78bSCy Schubertimport re
26*7f2fe78bSCy Schubert
27*7f2fe78bSCy Schubertfrom collections import defaultdict
28*7f2fe78bSCy Schubertfrom xml.sax import make_parser
29*7f2fe78bSCy Schubertfrom xml.sax.handler import ContentHandler
30*7f2fe78bSCy Schubertfrom docmodel import *
31*7f2fe78bSCy Schubert
32*7f2fe78bSCy Schubertexclude_funcs = ['krb5_free_octet_data']
33*7f2fe78bSCy Schubert
34*7f2fe78bSCy Schubertclass DocNode(object):
35*7f2fe78bSCy Schubert    """
36*7f2fe78bSCy Schubert    Represents the structure of xml node.
37*7f2fe78bSCy Schubert    """
38*7f2fe78bSCy Schubert    def __init__(self, name):
39*7f2fe78bSCy Schubert        """
40*7f2fe78bSCy Schubert        @param node: name - the name of a node.
41*7f2fe78bSCy Schubert        @param attributes: a dictionary populated with attributes of a node
42*7f2fe78bSCy Schubert        @param children: a dictionary with lists of children nodes. Nodes
43*7f2fe78bSCy Schubert            in lists are ordered as they appear in a document.
44*7f2fe78bSCy Schubert        @param content: a content of xml node represented as a list of
45*7f2fe78bSCy Schubert            tuples [(type,value)] with type = ['char'|'element'].
46*7f2fe78bSCy Schubert            If type is 'char' then the value is a character string otherwise
47*7f2fe78bSCy Schubert            it is a reference to a child node.
48*7f2fe78bSCy Schubert        """
49*7f2fe78bSCy Schubert        self.name = name
50*7f2fe78bSCy Schubert        self.content = list()
51*7f2fe78bSCy Schubert        self.attributes = dict()
52*7f2fe78bSCy Schubert        self.children = defaultdict(list)
53*7f2fe78bSCy Schubert
54*7f2fe78bSCy Schubert    def walk(self, decorators, sub_ws, stack=[]):
55*7f2fe78bSCy Schubert        result = list()
56*7f2fe78bSCy Schubert        decorator = decorators.get(self.name, decorators['default'])
57*7f2fe78bSCy Schubert        stack.append(decorators['default'])
58*7f2fe78bSCy Schubert        decorators['default'] = decorator
59*7f2fe78bSCy Schubert
60*7f2fe78bSCy Schubert        for (obj_type,obj) in self.content:
61*7f2fe78bSCy Schubert            if obj_type == 'char':
62*7f2fe78bSCy Schubert                if obj != '':
63*7f2fe78bSCy Schubert                    result.append(obj)
64*7f2fe78bSCy Schubert            else:
65*7f2fe78bSCy Schubert                partial = obj.walk(decorators,1, stack)
66*7f2fe78bSCy Schubert                if partial is not None:
67*7f2fe78bSCy Schubert                    result.append(' %s ' % partial)
68*7f2fe78bSCy Schubert        decorators['default'] = stack.pop()
69*7f2fe78bSCy Schubert        result = decorator(self, ''.join(result))
70*7f2fe78bSCy Schubert        if result is not None:
71*7f2fe78bSCy Schubert            if sub_ws == 1:
72*7f2fe78bSCy Schubert                result = re.sub(r'[ ]+', r' ', result)
73*7f2fe78bSCy Schubert            else:
74*7f2fe78bSCy Schubert                result = result.strip()
75*7f2fe78bSCy Schubert
76*7f2fe78bSCy Schubert        return result
77*7f2fe78bSCy Schubert
78*7f2fe78bSCy Schubert    def getContent(self):
79*7f2fe78bSCy Schubert        decorators = {'default': lambda node,value: value}
80*7f2fe78bSCy Schubert        result = self.walk(decorators, 1)
81*7f2fe78bSCy Schubert        if len(result) == 0:
82*7f2fe78bSCy Schubert            result = None
83*7f2fe78bSCy Schubert
84*7f2fe78bSCy Schubert        return result
85*7f2fe78bSCy Schubert
86*7f2fe78bSCy Schubert    def __repr__(self):
87*7f2fe78bSCy Schubert        result = ['Content: %s' % self.content]
88*7f2fe78bSCy Schubert
89*7f2fe78bSCy Schubert        for (key,value) in self.attributes.iteritems():
90*7f2fe78bSCy Schubert            result.append('Attr: %s = %s' % (key,value))
91*7f2fe78bSCy Schubert        for (key,value) in self.children.iteritems():
92*7f2fe78bSCy Schubert            result.append('Child: %s,%i' % (key,len(value)))
93*7f2fe78bSCy Schubert
94*7f2fe78bSCy Schubert        return '\n'.join(result)
95*7f2fe78bSCy Schubert
96*7f2fe78bSCy Schubertclass DoxyContenHandler(ContentHandler):
97*7f2fe78bSCy Schubert    def __init__(self, builder):
98*7f2fe78bSCy Schubert        self.builder = builder
99*7f2fe78bSCy Schubert        self.counters = defaultdict(int)
100*7f2fe78bSCy Schubert        self._nodes = None
101*7f2fe78bSCy Schubert        self._current = None
102*7f2fe78bSCy Schubert
103*7f2fe78bSCy Schubert    def startDocument(self):
104*7f2fe78bSCy Schubert        pass
105*7f2fe78bSCy Schubert
106*7f2fe78bSCy Schubert    def endDocument(self):
107*7f2fe78bSCy Schubert        import sys
108*7f2fe78bSCy Schubert
109*7f2fe78bSCy Schubert    def startElement(self, name, attrs):
110*7f2fe78bSCy Schubert        if name == self.builder.toplevel:
111*7f2fe78bSCy Schubert            self._nodes = []
112*7f2fe78bSCy Schubert
113*7f2fe78bSCy Schubert        if name == 'memberdef':
114*7f2fe78bSCy Schubert            kind = attrs.get('kind')
115*7f2fe78bSCy Schubert            if kind is None:
116*7f2fe78bSCy Schubert                raise ValueError('Kind is not defined')
117*7f2fe78bSCy Schubert            self.counters[kind] += 1
118*7f2fe78bSCy Schubert
119*7f2fe78bSCy Schubert        if self._nodes is None:
120*7f2fe78bSCy Schubert            return
121*7f2fe78bSCy Schubert
122*7f2fe78bSCy Schubert        node = DocNode(name)
123*7f2fe78bSCy Schubert        for (key,value) in attrs.items():
124*7f2fe78bSCy Schubert            node.attributes[key] = value
125*7f2fe78bSCy Schubert        if self._current is not None:
126*7f2fe78bSCy Schubert            self._current.children[name].append(node)
127*7f2fe78bSCy Schubert            self._nodes.append(self._current)
128*7f2fe78bSCy Schubert        self._current = node
129*7f2fe78bSCy Schubert
130*7f2fe78bSCy Schubert    def characters(self, content):
131*7f2fe78bSCy Schubert
132*7f2fe78bSCy Schubert        if self._current is not None:
133*7f2fe78bSCy Schubert            self._current.content.append(('char',content.strip()))
134*7f2fe78bSCy Schubert
135*7f2fe78bSCy Schubert    def endElement(self, name):
136*7f2fe78bSCy Schubert        if name == self.builder.toplevel:
137*7f2fe78bSCy Schubert            assert(len(self._nodes) == 0)
138*7f2fe78bSCy Schubert            self._nodes = None
139*7f2fe78bSCy Schubert            self.builder.document.append(self._current)
140*7f2fe78bSCy Schubert            self._current = None
141*7f2fe78bSCy Schubert        else:
142*7f2fe78bSCy Schubert            if self._nodes is not None:
143*7f2fe78bSCy Schubert                node = self._current
144*7f2fe78bSCy Schubert                self._current = self._nodes.pop()
145*7f2fe78bSCy Schubert                self._current.content.append(('element',node))
146*7f2fe78bSCy Schubert
147*7f2fe78bSCy Schubert
148*7f2fe78bSCy Schubertclass XML2AST(object):
149*7f2fe78bSCy Schubert    """
150*7f2fe78bSCy Schubert    Translates XML document into Abstract Syntax Tree like representation
151*7f2fe78bSCy Schubert    The content of document is stored in self.document
152*7f2fe78bSCy Schubert    """
153*7f2fe78bSCy Schubert    def __init__(self, xmlpath, toplevel='doxygen'):
154*7f2fe78bSCy Schubert        self.document = list()
155*7f2fe78bSCy Schubert        self.toplevel = toplevel
156*7f2fe78bSCy Schubert        self.parser = make_parser()
157*7f2fe78bSCy Schubert        handler = DoxyContenHandler(self)
158*7f2fe78bSCy Schubert        self.parser.setContentHandler(handler)
159*7f2fe78bSCy Schubert        filename = 'krb5_8hin.xml'
160*7f2fe78bSCy Schubert        filepath = '%s/%s' % (xmlpath,filename)
161*7f2fe78bSCy Schubert        self.parser.parse(open(filepath,'r'))
162*7f2fe78bSCy Schubert
163*7f2fe78bSCy Schubert
164*7f2fe78bSCy Schubertclass DoxyFuncs(XML2AST):
165*7f2fe78bSCy Schubert    def __init__(self, path):
166*7f2fe78bSCy Schubert        super(DoxyFuncs, self).__init__(path,toplevel='memberdef')
167*7f2fe78bSCy Schubert        self.objects = list()
168*7f2fe78bSCy Schubert
169*7f2fe78bSCy Schubert    def run(self):
170*7f2fe78bSCy Schubert        for node in self.document:
171*7f2fe78bSCy Schubert            self.process(node)
172*7f2fe78bSCy Schubert
173*7f2fe78bSCy Schubert    def process(self, node):
174*7f2fe78bSCy Schubert        node_type = node.attributes['kind']
175*7f2fe78bSCy Schubert        if node_type == 'function':
176*7f2fe78bSCy Schubert            data = self._process_function_node(node)
177*7f2fe78bSCy Schubert        else:
178*7f2fe78bSCy Schubert            return
179*7f2fe78bSCy Schubert
180*7f2fe78bSCy Schubert        if 'name' in data and data['name'] in exclude_funcs:
181*7f2fe78bSCy Schubert            return
182*7f2fe78bSCy Schubert        self.objects.append(DocModel(**data))
183*7f2fe78bSCy Schubert
184*7f2fe78bSCy Schubert    def save(self, templates, target_dir):
185*7f2fe78bSCy Schubert        for obj in self.objects:
186*7f2fe78bSCy Schubert            template_path = templates[obj.category]
187*7f2fe78bSCy Schubert            outpath = '%s/%s.rst' % (target_dir,obj.name)
188*7f2fe78bSCy Schubert            obj.save(outpath, template_path)
189*7f2fe78bSCy Schubert
190*7f2fe78bSCy Schubert
191*7f2fe78bSCy Schubert    def _process_function_node(self, node):
192*7f2fe78bSCy Schubert        f_name = node.children['name'][0].getContent()
193*7f2fe78bSCy Schubert        f_Id = node.attributes['id']
194*7f2fe78bSCy Schubert        f_ret_type = self._process_type_node(node.children['type'][0])
195*7f2fe78bSCy Schubert        f_brief = node.children['briefdescription'][0].getContent()
196*7f2fe78bSCy Schubert        f_detailed = node.children['detaileddescription'][0]
197*7f2fe78bSCy Schubert        detailed_description = self._process_description_node(f_detailed)
198*7f2fe78bSCy Schubert        return_value_description = self._process_return_value_description(f_detailed)
199*7f2fe78bSCy Schubert        retval_description = self._process_retval_description(f_detailed)
200*7f2fe78bSCy Schubert        warning_description = self._process_warning_description(f_detailed)
201*7f2fe78bSCy Schubert        seealso_description = self._process_seealso_description(f_detailed)
202*7f2fe78bSCy Schubert        notes_description = self._process_notes_description(f_detailed)
203*7f2fe78bSCy Schubert        f_version = self._process_version_description(f_detailed)
204*7f2fe78bSCy Schubert        deprecated_description = self._process_deprecated_description(f_detailed)
205*7f2fe78bSCy Schubert        param_description_map = self.process_parameter_description(f_detailed)
206*7f2fe78bSCy Schubert        f_definition = node.children['definition'][0].getContent()
207*7f2fe78bSCy Schubert        f_argsstring = node.children['argsstring'][0].getContent()
208*7f2fe78bSCy Schubert
209*7f2fe78bSCy Schubert        function_descr = {'category': 'function',
210*7f2fe78bSCy Schubert                          'name': f_name,
211*7f2fe78bSCy Schubert                          'Id': f_Id,
212*7f2fe78bSCy Schubert                          'return_type': f_ret_type[1],
213*7f2fe78bSCy Schubert                          'return_description': return_value_description,
214*7f2fe78bSCy Schubert                          'retval_description': retval_description,
215*7f2fe78bSCy Schubert                          'sa_description': seealso_description,
216*7f2fe78bSCy Schubert                          'warn_description': warning_description,
217*7f2fe78bSCy Schubert                          'notes_description': notes_description,
218*7f2fe78bSCy Schubert                          'short_description': f_brief,
219*7f2fe78bSCy Schubert                          'version_num': f_version,
220*7f2fe78bSCy Schubert                          'long_description': detailed_description,
221*7f2fe78bSCy Schubert                          'deprecated_description': deprecated_description,
222*7f2fe78bSCy Schubert                          'parameters': list()}
223*7f2fe78bSCy Schubert
224*7f2fe78bSCy Schubert        parameters = function_descr['parameters']
225*7f2fe78bSCy Schubert        for (i,p) in enumerate(node.children['param']):
226*7f2fe78bSCy Schubert            type_node = p.children['type'][0]
227*7f2fe78bSCy Schubert            p_type = self._process_type_node(type_node)
228*7f2fe78bSCy Schubert            if p_type[1].find('...') > -1 :
229*7f2fe78bSCy Schubert                p_name = ''
230*7f2fe78bSCy Schubert            else:
231*7f2fe78bSCy Schubert                p_name = None
232*7f2fe78bSCy Schubert            p_name_node = p.children.get('declname')
233*7f2fe78bSCy Schubert            if p_name_node is not None:
234*7f2fe78bSCy Schubert                p_name = p_name_node[0].getContent()
235*7f2fe78bSCy Schubert            (p_direction,p_descr) = param_description_map.get(p_name,(None,None))
236*7f2fe78bSCy Schubert
237*7f2fe78bSCy Schubert            param_descr = {'seqno': i,
238*7f2fe78bSCy Schubert                           'name': p_name,
239*7f2fe78bSCy Schubert                           'direction': p_direction,
240*7f2fe78bSCy Schubert                           'type': p_type[1],
241*7f2fe78bSCy Schubert                           'typeId': p_type[0],
242*7f2fe78bSCy Schubert                           'description': p_descr}
243*7f2fe78bSCy Schubert            parameters.append(param_descr)
244*7f2fe78bSCy Schubert        result = Function(**function_descr)
245*7f2fe78bSCy Schubert        print(result, file=self.tmp)
246*7f2fe78bSCy Schubert
247*7f2fe78bSCy Schubert        return function_descr
248*7f2fe78bSCy Schubert
249*7f2fe78bSCy Schubert    def _process_type_node(self, type_node):
250*7f2fe78bSCy Schubert        """
251*7f2fe78bSCy Schubert        Type node has form
252*7f2fe78bSCy Schubert            <type>type_string</type>
253*7f2fe78bSCy Schubert        for build in types and
254*7f2fe78bSCy Schubert            <type>
255*7f2fe78bSCy Schubert              <ref refid='reference',kindref='member|compound'>
256*7f2fe78bSCy Schubert                  'type_name'
257*7f2fe78bSCy Schubert              </ref></type>
258*7f2fe78bSCy Schubert              postfix (ex. *, **m, etc.)
259*7f2fe78bSCy Schubert            </type>
260*7f2fe78bSCy Schubert        for user defined types.
261*7f2fe78bSCy Schubert        """
262*7f2fe78bSCy Schubert        type_ref_node = type_node.children.get('ref')
263*7f2fe78bSCy Schubert        if type_ref_node is not None:
264*7f2fe78bSCy Schubert            p_type_id = type_ref_node[0].attributes['refid']
265*7f2fe78bSCy Schubert        else:
266*7f2fe78bSCy Schubert            p_type_id = None
267*7f2fe78bSCy Schubert        p_type = type_node.getContent()
268*7f2fe78bSCy Schubert        # remove some macros
269*7f2fe78bSCy Schubert        p_type = re.sub('KRB5_ATTR_DEPRECATED', '', p_type)
270*7f2fe78bSCy Schubert        p_type = re.sub('KRB5_CALLCONV_C', '', p_type)
271*7f2fe78bSCy Schubert        p_type = re.sub('KRB5_CALLCONV_WRONG', '', p_type)
272*7f2fe78bSCy Schubert        p_type = re.sub('KRB5_CALLCONV', '', p_type)
273*7f2fe78bSCy Schubert        p_type = p_type.strip()
274*7f2fe78bSCy Schubert
275*7f2fe78bSCy Schubert        return (p_type_id, p_type)
276*7f2fe78bSCy Schubert
277*7f2fe78bSCy Schubert    def _process_description_node(self, node):
278*7f2fe78bSCy Schubert        """
279*7f2fe78bSCy Schubert        Description node is comprised of <para>...</para> sections
280*7f2fe78bSCy Schubert        """
281*7f2fe78bSCy Schubert        para = node.children.get('para')
282*7f2fe78bSCy Schubert        result = list()
283*7f2fe78bSCy Schubert        if para is not None:
284*7f2fe78bSCy Schubert            decorators = {'default': self.paragraph_content_decorator}
285*7f2fe78bSCy Schubert            for e in para:
286*7f2fe78bSCy Schubert                result.append(str(e.walk(decorators, 1)))
287*7f2fe78bSCy Schubert                result.append('\n')
288*7f2fe78bSCy Schubert        result = '\n'.join(result)
289*7f2fe78bSCy Schubert
290*7f2fe78bSCy Schubert        return result
291*7f2fe78bSCy Schubert
292*7f2fe78bSCy Schubert    def return_value_description_decorator(self, node, value):
293*7f2fe78bSCy Schubert        if node.name == 'simplesect':
294*7f2fe78bSCy Schubert            if node.attributes['kind'] == 'return':
295*7f2fe78bSCy Schubert                cont = set()
296*7f2fe78bSCy Schubert                cont = node.getContent()
297*7f2fe78bSCy Schubert                return  value
298*7f2fe78bSCy Schubert        else:
299*7f2fe78bSCy Schubert            return None
300*7f2fe78bSCy Schubert
301*7f2fe78bSCy Schubert    def paragraph_content_decorator(self, node, value):
302*7f2fe78bSCy Schubert        if node.name == 'para':
303*7f2fe78bSCy Schubert            return value + '\n'
304*7f2fe78bSCy Schubert        elif node.name == 'simplesect':
305*7f2fe78bSCy Schubert            if node.attributes['kind'] == 'return':
306*7f2fe78bSCy Schubert                return None
307*7f2fe78bSCy Schubert        elif node.name == 'ref':
308*7f2fe78bSCy Schubert            if value.find('()') >= 0:
309*7f2fe78bSCy Schubert                # functions
310*7f2fe78bSCy Schubert                return ':c:func:' + '`' + value + '`'
311*7f2fe78bSCy Schubert            else:
312*7f2fe78bSCy Schubert                # macro's
313*7f2fe78bSCy Schubert                return ':data:' + '`' + value + '`'
314*7f2fe78bSCy Schubert        elif node.name == 'emphasis':
315*7f2fe78bSCy Schubert            return '*' + value + '*'
316*7f2fe78bSCy Schubert        elif node.name == 'itemizedlist':
317*7f2fe78bSCy Schubert            return '\n' + value
318*7f2fe78bSCy Schubert        elif node.name == 'listitem':
319*7f2fe78bSCy Schubert            return '\n\t - ' + value + '\n'
320*7f2fe78bSCy Schubert        elif node.name == 'computeroutput':
321*7f2fe78bSCy Schubert            return '**' + value + '**'
322*7f2fe78bSCy Schubert        else:
323*7f2fe78bSCy Schubert            return None
324*7f2fe78bSCy Schubert
325*7f2fe78bSCy Schubert    def parameter_name_decorator(self, node, value):
326*7f2fe78bSCy Schubert        if node.name == 'parametername':
327*7f2fe78bSCy Schubert            direction = node.attributes.get('direction')
328*7f2fe78bSCy Schubert            if direction is not None:
329*7f2fe78bSCy Schubert                value = '%s:%s' % (value,direction)
330*7f2fe78bSCy Schubert            return value
331*7f2fe78bSCy Schubert
332*7f2fe78bSCy Schubert        elif node.name == 'parameterdescription':
333*7f2fe78bSCy Schubert            return None
334*7f2fe78bSCy Schubert        else:
335*7f2fe78bSCy Schubert            return value
336*7f2fe78bSCy Schubert
337*7f2fe78bSCy Schubert    def parameter_description_decorator(self, node, value):
338*7f2fe78bSCy Schubert        if node.name == 'parameterdescription':
339*7f2fe78bSCy Schubert            return value
340*7f2fe78bSCy Schubert        elif node.name == 'parametername':
341*7f2fe78bSCy Schubert            return None
342*7f2fe78bSCy Schubert        else:
343*7f2fe78bSCy Schubert            return value
344*7f2fe78bSCy Schubert
345*7f2fe78bSCy Schubert    def process_parameter_description(self, node):
346*7f2fe78bSCy Schubert        """
347*7f2fe78bSCy Schubert        Parameter descriptions reside inside detailed description section.
348*7f2fe78bSCy Schubert        """
349*7f2fe78bSCy Schubert        para = node.children.get('para')
350*7f2fe78bSCy Schubert        result = dict()
351*7f2fe78bSCy Schubert        if para is not None:
352*7f2fe78bSCy Schubert            for e in para:
353*7f2fe78bSCy Schubert
354*7f2fe78bSCy Schubert                param_list = e.children.get('parameterlist')
355*7f2fe78bSCy Schubert                if param_list is None:
356*7f2fe78bSCy Schubert                    continue
357*7f2fe78bSCy Schubert                param_items = param_list[0].children.get('parameteritem')
358*7f2fe78bSCy Schubert                if param_items is None:
359*7f2fe78bSCy Schubert                    continue
360*7f2fe78bSCy Schubert                for it in param_items:
361*7f2fe78bSCy Schubert                    decorators = {'default': self.parameter_name_decorator}
362*7f2fe78bSCy Schubert                    direction = None
363*7f2fe78bSCy Schubert                    name = it.walk(decorators,0).split(':')
364*7f2fe78bSCy Schubert                    if len(name) == 2:
365*7f2fe78bSCy Schubert                        direction = name[1]
366*7f2fe78bSCy Schubert
367*7f2fe78bSCy Schubert                    decorators = {'default': self.parameter_description_decorator,
368*7f2fe78bSCy Schubert                                  'para': self.paragraph_content_decorator}
369*7f2fe78bSCy Schubert                    description = it.walk(decorators, 0)
370*7f2fe78bSCy Schubert                    result[name[0]] = (direction,description)
371*7f2fe78bSCy Schubert        return result
372*7f2fe78bSCy Schubert
373*7f2fe78bSCy Schubert
374*7f2fe78bSCy Schubert    def _process_return_value_description(self, node):
375*7f2fe78bSCy Schubert        result = None
376*7f2fe78bSCy Schubert        ret = list()
377*7f2fe78bSCy Schubert
378*7f2fe78bSCy Schubert        para = node.children.get('para')
379*7f2fe78bSCy Schubert        if para is not None:
380*7f2fe78bSCy Schubert            for p in para:
381*7f2fe78bSCy Schubert                simplesect_list = p.children.get('simplesect')
382*7f2fe78bSCy Schubert                if simplesect_list is None:
383*7f2fe78bSCy Schubert                    continue
384*7f2fe78bSCy Schubert                for it in simplesect_list:
385*7f2fe78bSCy Schubert                    decorators = {'default': self.return_value_description_decorator,
386*7f2fe78bSCy Schubert                                  'para': self.parameter_name_decorator}
387*7f2fe78bSCy Schubert                    result = it.walk(decorators, 1)
388*7f2fe78bSCy Schubert                    if result is not None:
389*7f2fe78bSCy Schubert                        ret.append(result)
390*7f2fe78bSCy Schubert        return ret
391*7f2fe78bSCy Schubert
392*7f2fe78bSCy Schubert
393*7f2fe78bSCy Schubert    def _process_retval_description(self, node):
394*7f2fe78bSCy Schubert        """
395*7f2fe78bSCy Schubert        retval descriptions reside inside detailed description section.
396*7f2fe78bSCy Schubert        """
397*7f2fe78bSCy Schubert        para = node.children.get('para')
398*7f2fe78bSCy Schubert
399*7f2fe78bSCy Schubert        result = None
400*7f2fe78bSCy Schubert        ret = list()
401*7f2fe78bSCy Schubert        if para is not None:
402*7f2fe78bSCy Schubert
403*7f2fe78bSCy Schubert            for e in para:
404*7f2fe78bSCy Schubert                param_list = e.children.get('parameterlist')
405*7f2fe78bSCy Schubert                if param_list is None:
406*7f2fe78bSCy Schubert                    continue
407*7f2fe78bSCy Schubert                for p in param_list:
408*7f2fe78bSCy Schubert                    kind = p.attributes['kind']
409*7f2fe78bSCy Schubert                    if kind == 'retval':
410*7f2fe78bSCy Schubert
411*7f2fe78bSCy Schubert                        param_items = p.children.get('parameteritem')
412*7f2fe78bSCy Schubert                        if param_items is None:
413*7f2fe78bSCy Schubert                            continue
414*7f2fe78bSCy Schubert
415*7f2fe78bSCy Schubert
416*7f2fe78bSCy Schubert                        for it in param_items:
417*7f2fe78bSCy Schubert                            param_descr = it.children.get('parameterdescription')
418*7f2fe78bSCy Schubert                            if param_descr is not None:
419*7f2fe78bSCy Schubert                                val = param_descr[0].children.get('para')
420*7f2fe78bSCy Schubert
421*7f2fe78bSCy Schubert                                if val is not None:
422*7f2fe78bSCy Schubert                                    val_descr = val[0].getContent()
423*7f2fe78bSCy Schubert
424*7f2fe78bSCy Schubert                                else:
425*7f2fe78bSCy Schubert                                    val_descr =''
426*7f2fe78bSCy Schubert
427*7f2fe78bSCy Schubert                            decorators = {'default': self.parameter_name_decorator}
428*7f2fe78bSCy Schubert
429*7f2fe78bSCy Schubert                            name = it.walk(decorators, 1).split(':')
430*7f2fe78bSCy Schubert
431*7f2fe78bSCy Schubert                            val = name[0]
432*7f2fe78bSCy Schubert                            result = " %s  %s" % (val, val_descr)
433*7f2fe78bSCy Schubert                            ret.append (result)
434*7f2fe78bSCy Schubert        return ret
435*7f2fe78bSCy Schubert
436*7f2fe78bSCy Schubert    def return_warning_decorator(self, node, value):
437*7f2fe78bSCy Schubert        if node.name == 'simplesect':
438*7f2fe78bSCy Schubert            if node.attributes['kind'] == 'warning':
439*7f2fe78bSCy Schubert                return value
440*7f2fe78bSCy Schubert        else:
441*7f2fe78bSCy Schubert            return None
442*7f2fe78bSCy Schubert
443*7f2fe78bSCy Schubert    def _process_warning_description(self, node):
444*7f2fe78bSCy Schubert        result = None
445*7f2fe78bSCy Schubert        para = node.children.get('para')
446*7f2fe78bSCy Schubert        if para is not None:
447*7f2fe78bSCy Schubert            for p in para:
448*7f2fe78bSCy Schubert                simplesect_list = p.children.get('simplesect')
449*7f2fe78bSCy Schubert                if simplesect_list is None:
450*7f2fe78bSCy Schubert                    continue
451*7f2fe78bSCy Schubert                for it in simplesect_list:
452*7f2fe78bSCy Schubert                    decorators = {'default': self.return_warning_decorator,
453*7f2fe78bSCy Schubert                                  'para': self.paragraph_content_decorator}
454*7f2fe78bSCy Schubert                    result = it.walk(decorators, 1)
455*7f2fe78bSCy Schubert                    # Assuming that only one Warning per function
456*7f2fe78bSCy Schubert                    if result is not None:
457*7f2fe78bSCy Schubert                        return result
458*7f2fe78bSCy Schubert        return result
459*7f2fe78bSCy Schubert
460*7f2fe78bSCy Schubert    def return_seealso_decorator(self, node, value):
461*7f2fe78bSCy Schubert        if node.name == 'simplesect':
462*7f2fe78bSCy Schubert            if node.attributes['kind'] == 'see':
463*7f2fe78bSCy Schubert                return value
464*7f2fe78bSCy Schubert        else:
465*7f2fe78bSCy Schubert            return None
466*7f2fe78bSCy Schubert
467*7f2fe78bSCy Schubert    def _process_seealso_description(self, node):
468*7f2fe78bSCy Schubert        result = None
469*7f2fe78bSCy Schubert        para = node.children.get('para')
470*7f2fe78bSCy Schubert        if para is not None:
471*7f2fe78bSCy Schubert            for p in para:
472*7f2fe78bSCy Schubert                simplesect_list = p.children.get('simplesect')
473*7f2fe78bSCy Schubert                if simplesect_list is None:
474*7f2fe78bSCy Schubert                    continue
475*7f2fe78bSCy Schubert                for it in simplesect_list:
476*7f2fe78bSCy Schubert                    decorators = {'default': self.return_seealso_decorator,
477*7f2fe78bSCy Schubert                                  'para': self.paragraph_content_decorator}
478*7f2fe78bSCy Schubert                    result = it.walk(decorators, 1)
479*7f2fe78bSCy Schubert        return result
480*7f2fe78bSCy Schubert
481*7f2fe78bSCy Schubert    def return_version_decorator(self, node, value):
482*7f2fe78bSCy Schubert        if node.name == 'simplesect':
483*7f2fe78bSCy Schubert            if node.attributes['kind'] == 'version':
484*7f2fe78bSCy Schubert                return value
485*7f2fe78bSCy Schubert        else:
486*7f2fe78bSCy Schubert            return None
487*7f2fe78bSCy Schubert
488*7f2fe78bSCy Schubert    def _process_version_description(self, node):
489*7f2fe78bSCy Schubert        result = None
490*7f2fe78bSCy Schubert        para = node.children.get('para')
491*7f2fe78bSCy Schubert        if para is not None:
492*7f2fe78bSCy Schubert            for p in para:
493*7f2fe78bSCy Schubert                simplesect_list = p.children.get('simplesect')
494*7f2fe78bSCy Schubert                if simplesect_list is None:
495*7f2fe78bSCy Schubert                    continue
496*7f2fe78bSCy Schubert                for it in simplesect_list:
497*7f2fe78bSCy Schubert                    decorators = {'default': self.return_version_decorator,
498*7f2fe78bSCy Schubert                                  'para': self.paragraph_content_decorator}
499*7f2fe78bSCy Schubert                    result = it.walk(decorators, 1)
500*7f2fe78bSCy Schubert                    if result is not None:
501*7f2fe78bSCy Schubert                        return result
502*7f2fe78bSCy Schubert        return result
503*7f2fe78bSCy Schubert
504*7f2fe78bSCy Schubert    def return_notes_decorator(self, node, value):
505*7f2fe78bSCy Schubert        if node.name == 'simplesect':
506*7f2fe78bSCy Schubert            if node.attributes['kind'] == 'note':
507*7f2fe78bSCy Schubert                # We indent notes with an extra tab.  Do it for all paragraphs.
508*7f2fe78bSCy Schubert                return value.replace("\n  ", "\n\n\t  ");
509*7f2fe78bSCy Schubert        else:
510*7f2fe78bSCy Schubert            return None
511*7f2fe78bSCy Schubert
512*7f2fe78bSCy Schubert    def _process_notes_description(self, node):
513*7f2fe78bSCy Schubert        result = None
514*7f2fe78bSCy Schubert        para = node.children.get('para')
515*7f2fe78bSCy Schubert        if para is not None:
516*7f2fe78bSCy Schubert            for p in para:
517*7f2fe78bSCy Schubert                simplesect_list = p.children.get('simplesect')
518*7f2fe78bSCy Schubert                if simplesect_list is None:
519*7f2fe78bSCy Schubert                    continue
520*7f2fe78bSCy Schubert                for it in simplesect_list:
521*7f2fe78bSCy Schubert                    decorators = {'default': self.return_notes_decorator,
522*7f2fe78bSCy Schubert                                  'para': self.paragraph_content_decorator}
523*7f2fe78bSCy Schubert                    result = it.walk(decorators, 1)
524*7f2fe78bSCy Schubert                    if result is not None:
525*7f2fe78bSCy Schubert                        return result
526*7f2fe78bSCy Schubert        return result
527*7f2fe78bSCy Schubert
528*7f2fe78bSCy Schubert    def return_deprecated_decorator(self, node, value):
529*7f2fe78bSCy Schubert        if node.name == 'xrefsect':
530*7f2fe78bSCy Schubert            if node.attributes['id'].find('deprecated_') > -1:
531*7f2fe78bSCy Schubert                xreftitle = node.children.get('xreftitle')
532*7f2fe78bSCy Schubert                if xreftitle[0] is not None:
533*7f2fe78bSCy Schubert                    xrefdescr = node.children.get('xrefdescription')
534*7f2fe78bSCy Schubert                    deprecated_descr = "DEPRECATED %s" % xrefdescr[0].getContent()
535*7f2fe78bSCy Schubert                    return deprecated_descr
536*7f2fe78bSCy Schubert        else:
537*7f2fe78bSCy Schubert            return None
538*7f2fe78bSCy Schubert
539*7f2fe78bSCy Schubert    def _process_deprecated_description(self, node):
540*7f2fe78bSCy Schubert        result = None
541*7f2fe78bSCy Schubert        para = node.children.get('para')
542*7f2fe78bSCy Schubert        if para is not None:
543*7f2fe78bSCy Schubert            for p in para:
544*7f2fe78bSCy Schubert                xrefsect_list = p.children.get('xrefsect')
545*7f2fe78bSCy Schubert                if xrefsect_list is None:
546*7f2fe78bSCy Schubert                    continue
547*7f2fe78bSCy Schubert                for it in xrefsect_list:
548*7f2fe78bSCy Schubert                    decorators = {'default': self.return_deprecated_decorator,
549*7f2fe78bSCy Schubert                                  'para': self.paragraph_content_decorator}
550*7f2fe78bSCy Schubert                    result = it.walk(decorators, 1)
551*7f2fe78bSCy Schubert                    if result is not None:
552*7f2fe78bSCy Schubert                        return result
553*7f2fe78bSCy Schubert        return result
554*7f2fe78bSCy Schubert
555*7f2fe78bSCy Schubert    def break_into_lines(self, value, linelen=82):
556*7f2fe78bSCy Schubert        breaks = range(0,len(value),linelen) + [len(value)]
557*7f2fe78bSCy Schubert        result = list()
558*7f2fe78bSCy Schubert        for (start,end) in zip(breaks[:-1],breaks[1:]):
559*7f2fe78bSCy Schubert            result.append(value[start:end])
560*7f2fe78bSCy Schubert        result = '\n'.join(result)
561*7f2fe78bSCy Schubert
562*7f2fe78bSCy Schubert        return result
563*7f2fe78bSCy Schubert
564*7f2fe78bSCy Schubert    def _save(self, table, path = None):
565*7f2fe78bSCy Schubert        if path is None:
566*7f2fe78bSCy Schubert            f = sys.stdout
567*7f2fe78bSCy Schubert        else:
568*7f2fe78bSCy Schubert            f = open(path, 'w')
569*7f2fe78bSCy Schubert        for l in table:
570*7f2fe78bSCy Schubert            f.write('%s\n' % ','.join(l))
571*7f2fe78bSCy Schubert        if path is not None:
572*7f2fe78bSCy Schubert            f.close()
573*7f2fe78bSCy Schubert
574*7f2fe78bSCy Schubert
575*7f2fe78bSCy Schubert
576*7f2fe78bSCy Schubertclass DoxyBuilderFuncs(DoxyFuncs):
577*7f2fe78bSCy Schubert    def __init__(self, xmlpath, rstpath):
578*7f2fe78bSCy Schubert        super(DoxyBuilderFuncs,self).__init__(xmlpath)
579*7f2fe78bSCy Schubert        self.target_dir = rstpath
580*7f2fe78bSCy Schubert        outfile = '%s/%s' % (self.target_dir, 'out.txt')
581*7f2fe78bSCy Schubert        self.tmp = open(outfile, 'w')
582*7f2fe78bSCy Schubert
583*7f2fe78bSCy Schubert    def run_all(self):
584*7f2fe78bSCy Schubert        self.run()
585*7f2fe78bSCy Schubert        templates = {'function': 'func_document.tmpl'}
586*7f2fe78bSCy Schubert        self.save(templates, self.target_dir)
587*7f2fe78bSCy Schubert
588*7f2fe78bSCy Schubert    def test_run(self):
589*7f2fe78bSCy Schubert        self.run()
590*7f2fe78bSCy Schubert
591*7f2fe78bSCy Schubertif __name__ == '__main__':
592*7f2fe78bSCy Schubert    builder = DoxyBuilderFuncs(xmlpath, rstpath)
593*7f2fe78bSCy Schubert    builder.run_all()
594*7f2fe78bSCy Schubert
595