diff options
Diffstat (limited to 'build_tools/get_documentation.py')
-rw-r--r-- | build_tools/get_documentation.py | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/build_tools/get_documentation.py b/build_tools/get_documentation.py new file mode 100644 index 000000000..2ff4cb2b9 --- /dev/null +++ b/build_tools/get_documentation.py @@ -0,0 +1,175 @@ +#! /usr/bin/env python +# vin: sw=3 et: +''' +Copyright (C) 2012, Digium, Inc. +Matt Jordan <mjordan@digium.com> + +This program is free software, distributed under the terms of +the GNU General Public License Version 2. +''' + +import sys +import os +import xml.dom.minidom + +from xml.dom.minidom import Element + + +def get_manager_event_method_type(candidate_string): + if "ast_manager_event_multichan" in candidate_string: + return "multichan" + elif "ast_manager_event" in candidate_string: + return "ast_manager_event" + elif "manager_event" in candidate_string: + return "manager_event" + return "" + + +def parse_manager_event_instance(xml_fragment): + ''' Parse the information for a manager event + + Keyword Arguments: + xml_fragment The XML fragment comment + + Returns: + A well-formed XML fragment containing the comments passed in, as well as + information obtained from the manager_event macro calls + ''' + + def __node_contains_parameter(node, parameter): + ''' Return whether or not a node contains a given parameter name ''' + return any([n for n in node.getElementsByTagName("parameter") + if __node_contains_attribute(n, parameter)]) + + def __node_contains_attribute(node, attribute_name): + ''' Return whether or not a node contains a given attribute name ''' + return any([attr for attr in node.attributes.items() + if attr[1] == attribute_name]) + + candidate_lines = [] + type = "" + + # Read the manager_event method call, which should occur after + # the documentation block + for line in sys.stdin: + if len(line): + candidate_lines.append(line) + if ");" in line: + break + + candidate_string = ''.join(candidate_lines) + type = get_manager_event_method_type(candidate_string) + if not type: + # Unknown, return what we have + return ''.join(xml_fragment) + + # strip off the macro name + first_paren = candidate_string.index("(", 0) + last_paren = candidate_string.rindex(");") + candidate_string = candidate_string[first_paren + 1:last_paren] + + # split into parameter tokens + func_parameter_tokens = candidate_string.split(',') + + if type == "manager_event" or type == "multichan": + class_level = func_parameter_tokens[0].strip() + event_type = func_parameter_tokens[1].strip() + else: + class_level = func_parameter_tokens[1].strip() + event_type = func_parameter_tokens[2].strip() + + if type == "manager_event": + event_parameters = func_parameter_tokens[2].strip() + elif type == "ast_manager_event": + event_parameters = func_parameter_tokens[3].strip() + else: + event_parameters = func_parameter_tokens[4].strip() + + parameter_tokens = event_parameters.replace("\"", "").split('\\r\\n') + + # Build the top level XML element information. Note that we temporarily + # add the xi namespace in case any includes are used + node_text = '<managerEvent language=\"%s\" name=\"%s\" xmlns:xi=\"%s\">' + xml_fragment.insert(0, node_text % ('en_US', + event_type.strip().replace("\"", ""), + 'http://www.w3.org/2001/XInclude')) + xml_fragment[1] = "<managerEventInstance class=\"%s\">" % (class_level) + xml_fragment.insert(len(xml_fragment), "</managerEvent>") + + # Turn the XML into a DOM to manage the rest of the node manipulations + dom = xml.dom.minidom.parseString(''.join(xml_fragment)) + + # Get the syntax node if we have one; otherwise make one + instance = dom.getElementsByTagName("managerEventInstance")[0] + syntax = instance.getElementsByTagName("syntax") + if not syntax: + syntax = dom.createElement("syntax") + instance.appendChild(syntax) + # Move any existing parameter nodes over + for node in instance.getElementsByTagName("parameter"): + syntax.appendChild(node.cloneNode(True)) + instance.removeChild(node) + else: + syntax = syntax[0] + + # Add parameters found in the method invocation that were not previously + # documented + for parameter in parameter_tokens: + if not len(parameter): + continue + index = parameter.find(':') + if index < 0: + index = len(parameter) + parameter = (parameter[:index].strip().replace("\"", "")) + if ('%s' not in parameter and + not __node_contains_parameter(syntax, parameter)): + e = dom.createElement("parameter") + e.setAttribute('name', parameter) + syntax.appendChild(e) + + return dom.toxml().replace("<?xml version=\"1.0\" ?>", "").replace( + 'xmlns:xi="http://www.w3.org/2001/XInclude"', '') + + +def main(argv=None): + + if argv is None: + argv = sys.argv + + in_doc = False + xml_fragment = [] + xml = [] + line_number = 0 + + for line in sys.stdin: + # Note: multiple places may have to read a line, so iterating over + # readlines isn't possible. Break when a null line is returned + line_number += 1 + if not line: + break + + line = line.strip() + if ("/*** DOCUMENTATION" in line): + in_doc = True + elif ("***/" in line and in_doc): + # Depending on what we're processing, determine if we need to do + # any additional work + in_doc = False + if not xml_fragment: + # Nothing read, move along + continue + + if "<managerEventInstance>" in xml_fragment[0]: + xml.append(parse_manager_event_instance(xml_fragment)) + else: + xml.append(''.join(xml_fragment)) + + xml_fragment = [] + elif (in_doc): + xml_fragment.append("%s\n" % line) + + sys.stdout.write(''.join(xml)) + return 0 + +if __name__ == "__main__": + sys.exit(main() or 0) |