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