Merge "func_odbc: Add missing unlock's to acf_odbc_read."
[asterisk/asterisk.git] / build_tools / get_documentation.py
1 #! /usr/bin/env python
2 # vin: sw=3 et:
3 '''
4 Copyright (C) 2012, Digium, Inc.
5 Matt Jordan <mjordan@digium.com>
6
7 This program is free software, distributed under the terms of
8 the GNU General Public License Version 2.
9 '''
10
11 import sys
12 import xml.dom.minidom
13
14
15 def get_manager_event_method_type(candidate_string):
16     if "ast_manager_event_multichan" in candidate_string:
17         return "multichan"
18     elif "ast_manager_event" in candidate_string:
19         return "ast_manager_event"
20     elif "manager_event" in candidate_string:
21         return "manager_event"
22     return ""
23
24
25 def parse_manager_event_instance(xml_fragment):
26     ''' Parse the information for a manager event
27
28     Keyword Arguments:
29     xml_fragment    The XML fragment comment
30
31     Returns:
32     A well-formed XML fragment containing the comments passed in, as well as
33     information obtained from the manager_event macro calls
34     '''
35
36     def __node_contains_parameter(node, parameter):
37         ''' Return whether or not a node contains a given parameter name '''
38         return any([n for n in node.getElementsByTagName("parameter")
39                     if __node_contains_attribute(n, parameter)])
40
41     def __node_contains_attribute(node, attribute_name):
42         ''' Return whether or not a node contains a given attribute name '''
43         return any([attr for attr in node.attributes.items()
44                     if attr[1] == attribute_name])
45
46     candidate_lines = []
47     type = ""
48
49     # Read the manager_event method call, which should occur after
50     # the documentation block
51     for line in sys.stdin:
52         if len(line):
53             candidate_lines.append(line)
54         if ");" in line:
55             break
56
57     candidate_string = ''.join(candidate_lines)
58     type = get_manager_event_method_type(candidate_string)
59     if not type:
60         # Unknown, return what we have
61         return ''.join(xml_fragment)
62
63     # strip off the macro name
64     first_paren = candidate_string.index("(", 0)
65     last_paren = candidate_string.rindex(");")
66     candidate_string = candidate_string[first_paren + 1:last_paren]
67
68     # split into parameter tokens
69     func_parameter_tokens = candidate_string.split(',')
70
71     if type == "manager_event" or type == "multichan":
72         class_level = func_parameter_tokens[0].strip()
73         event_type = func_parameter_tokens[1].strip()
74     else:
75         class_level = func_parameter_tokens[1].strip()
76         event_type = func_parameter_tokens[2].strip()
77
78     if type == "manager_event":
79         event_parameters = func_parameter_tokens[2].strip()
80     elif type == "ast_manager_event":
81         event_parameters = func_parameter_tokens[3].strip()
82     else:
83         event_parameters = func_parameter_tokens[4].strip()
84
85     parameter_tokens = event_parameters.replace("\"", "").split('\\r\\n')
86
87     # Build the top level XML element information.  Note that we temporarily
88     # add the xi namespace in case any includes are used
89     node_text = '<managerEvent language=\"%s\" name=\"%s\" xmlns:xi=\"%s\">'
90     xml_fragment.insert(0, node_text % ('en_US',
91                                         event_type.strip().replace("\"", ""),
92                                         'http://www.w3.org/2001/XInclude'))
93     xml_fragment[1] = "<managerEventInstance class=\"%s\">" % (class_level)
94     xml_fragment.insert(len(xml_fragment), "</managerEvent>")
95
96     # Turn the XML into a DOM to manage the rest of the node manipulations
97     dom = xml.dom.minidom.parseString(''.join(xml_fragment))
98
99     # Get the syntax node if we have one; otherwise make one
100     instance = dom.getElementsByTagName("managerEventInstance")[0]
101     syntax = instance.getElementsByTagName("syntax")
102     if not syntax:
103         syntax = dom.createElement("syntax")
104         instance.appendChild(syntax)
105         # Move any existing parameter nodes over
106         for node in instance.getElementsByTagName("parameter"):
107             syntax.appendChild(node.cloneNode(True))
108             instance.removeChild(node)
109     else:
110         syntax = syntax[0]
111
112     # Add parameters found in the method invocation that were not previously
113     # documented
114     for parameter in parameter_tokens:
115         if not len(parameter):
116             continue
117         index = parameter.find(':')
118         if index < 0:
119             index = len(parameter)
120         parameter = (parameter[:index].strip().replace("\"", ""))
121         if ('%s' not in parameter and
122             not __node_contains_parameter(syntax, parameter)):
123             e = dom.createElement("parameter")
124             e.setAttribute('name', parameter)
125             syntax.appendChild(e)
126
127     return dom.toxml().replace("<?xml version=\"1.0\" ?>", "").replace(
128                'xmlns:xi="http://www.w3.org/2001/XInclude"', '')
129
130
131 def main(argv=None):
132
133     if argv is None:
134         argv = sys.argv
135
136     in_doc = False
137     xml_fragment = []
138     xml = []
139     line_number = 0
140
141     for line in sys.stdin:
142         # Note: multiple places may have to read a line, so iterating over
143         # readlines isn't possible.  Break when a null line is returned
144         line_number += 1
145         if not line:
146             break
147
148         line = line.strip()
149         if ("/*** DOCUMENTATION" in line):
150             in_doc = True
151         elif ("***/" in line and in_doc):
152             # Depending on what we're processing, determine if we need to do
153             # any additional work
154             in_doc = False
155             if not xml_fragment:
156                 # Nothing read, move along
157                 continue
158
159             if "<managerEventInstance>" in xml_fragment[0]:
160                 xml.append(parse_manager_event_instance(xml_fragment))
161             else:
162                 xml.append(''.join(xml_fragment))
163
164             xml_fragment = []
165         elif (in_doc):
166             xml_fragment.append("%s\n" % line)
167
168     sys.stdout.write(''.join(xml))
169     return 0
170
171 if __name__ == "__main__":
172     sys.exit(main() or 0)