#! /usr/bin/env python # vin: sw=3 et: ''' Copyright (C) 2012, Digium, Inc. Matt Jordan This program is free software, distributed under the terms of the GNU General Public License Version 2. ''' import sys import xml.dom.minidom 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 = '' xml_fragment.insert(0, node_text % ('en_US', event_type.strip().replace("\"", ""), 'http://www.w3.org/2001/XInclude')) xml_fragment[1] = "" % (class_level) xml_fragment.insert(len(xml_fragment), "") # 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("", "").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 "" 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)