#! /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 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 = '<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)