aboutsummaryrefslogtreecommitdiff
path: root/utils/python/doc_gen/doxygen_extractor.py
diff options
context:
space:
mode:
Diffstat (limited to 'utils/python/doc_gen/doxygen_extractor.py')
-rw-r--r--utils/python/doc_gen/doxygen_extractor.py242
1 files changed, 242 insertions, 0 deletions
diff --git a/utils/python/doc_gen/doxygen_extractor.py b/utils/python/doc_gen/doxygen_extractor.py
new file mode 100644
index 0000000..9207c9d
--- /dev/null
+++ b/utils/python/doc_gen/doxygen_extractor.py
@@ -0,0 +1,242 @@
+import os
+from system_utils import SystemUtils
+
+class DoxygenExtractor:
+
+ md_special_chars =[
+ {
+ "md_char": "*",
+ "replacement": "*"
+ },
+ {
+ "md_char": "#",
+ "replacement": "#"
+ },
+ {
+ "md_char": "`",
+ "replacement": "·"
+ }
+ ]
+
+ #constructor
+ def __init__(self, root, header_paths, working_dir = "./temp", doxygen_xml_dest = "./xml"):
+ os.chdir(root)
+ self.header_paths = header_paths
+ self.utils = SystemUtils()
+ self.doxygen_xml_dest = doxygen_xml_dest
+ self.working_dir = working_dir
+
+ ###
+ # this function copies headers recursively from a source director to a destination
+ # directory.
+ ###
+ def get_headers(self, from_dir, to_dir):
+ self.utils.copy_files(from_dir, to_dir, "*.h")
+
+ ###
+ # Strips out reserved characters used in markdown notation, and replaces them
+ # with html character codes.
+ #
+ # @param text the text to strip and replace the md special characters
+ #
+ # @return the stripped text.
+ ###
+ def escape_md_chars(self, text):
+ for char in self.md_special_chars:
+ text = text.replace(char['md_char'], "\\" + char['md_char'])
+ return text
+
+
+ ###
+ # this function extracts data from an element tag ignoring the tag 'ref', but
+ # obtains the textual data it has inside the ref tag.
+ #
+ # @param element the element to process
+ #
+ # @return a list of extracted strings.
+ ###
+ def extract_ignoring_refs(self, element):
+ list = []
+
+ if element.text is not None:
+ list.append(element.text)
+
+ for ref in element.iter(tag="ref"):
+ list.append(ref.text)
+
+ return list
+
+ ###
+ # this function extracts data from an element tag including all sub elements
+ # (recursive)
+ #
+ # @param element the element to process
+ #
+ # @return a list of extracted strings.
+ ###
+ def extract_with_subelements(self, element):
+ list = []
+
+ list.append(element.text or "")
+
+ #if element.text is not None:
+ #list.append(element.text)
+
+ for subelement in element:
+ if subelement is not None:
+ list = list + self.extract_with_subelements(subelement)
+
+ list.append(element.tail or "")
+
+ return list
+
+ ###
+ # this function was at one point intended to fetch a value of a default parameter
+ # it is now only used to fetch the default parameters' name.
+ #
+ # @param document_root the root of the entire document
+ # @param element the element containing the default parameter
+ #
+ # @return a dictionary containing:
+ # {
+ # 'name':'',
+ # 'value':''
+ # }
+ #
+ # @note this would be more useful if it return the value, it currently does not.
+ ###
+ def extract_default(self, element):
+ ref = element.find("ref")
+ return {'name':' '.join(element.itertext()), 'value':''}
+
+ ###
+ # extracts a member function form the xml document
+ #
+ # @param root the document root
+ # @param xml_element the member function xml element.
+ #
+ # @return a function dictionary:
+ # {
+ # 'short_name':"",
+ # 'name':"",
+ # 'return_type':"",
+ # 'params':[],
+ # 'description':[],
+ # 'returns':"",
+ # 'notes':"",
+ # 'examples':""
+ # }
+ ###
+ def extract_member_function(self, xml_element, function_filter = [], filter = True):
+
+ function = {
+ 'short_name':"",
+ 'name':"",
+ 'return_type':"",
+ 'params':[],
+ 'description':[],
+ 'returns':"",
+ 'notes':"",
+ 'examples':""
+ }
+
+ function['name'] = xml_element.find('definition').text
+ function['short_name'] = xml_element.find('name').text
+
+ if filter and any(filtered_func in function['short_name'] for filtered_func in function_filter):
+ print "Filtered out: " + function['short_name']
+ return
+
+ print "Generating documentation for: " + function['short_name']
+
+ if xml_element.find('type') is not None:
+ function['return_type'] = self.escape_md_chars(' '.join(self.extract_ignoring_refs(xml_element.find('type'))))
+
+ #extract our parameters for this member function
+ for parameter in xml_element.iter('param'):
+
+ type = ""
+ name = ""
+
+ if parameter.find('type') is not None:
+ type = self.escape_md_chars(' '.join(parameter.find('type').itertext()))
+
+ if parameter.find('declname') is not None:
+ name = ' '.join(self.extract_ignoring_refs(parameter.find('declname')))
+
+ param_object = {
+ 'type': type,
+ 'name': name,
+ 'default':{
+ 'name':"",
+ 'value':""
+ }
+ }
+
+ if parameter.find('defval') is not None:
+ extracted = self.extract_default(parameter.find('defval'))
+ param_object['default']['name'] = extracted['name']
+ param_object['default']['value'] = extracted['value']
+
+ function['params'].append(param_object)
+
+
+ detailed_description = xml_element.find('detaileddescription')
+
+ if len(detailed_description.findall("para")) is not 0:
+ for para in detailed_description.findall("para"):
+ if len(para.findall("programlisting")) is 0 and len(para.findall("simplesect")) is 0:
+ function['description'] = function['description'] + self.extract_with_subelements(para)
+
+ #para indicates a new paragraph - we should treat it as such... append \n!
+ function['description'] = function['description'] + ["\n\n"]
+
+ if len(detailed_description.findall("para/simplesect[@kind='return']/para")) is not 0:
+ return_section = detailed_description.findall("para/simplesect[@kind='return']/para")[0]
+ function['returns'] = ' '.join(return_section.itertext())
+
+ if len(detailed_description.findall("para/simplesect[@kind='note']/para")) is not 0:
+ return_section = detailed_description.findall("para/simplesect[@kind='note']/para")[0]
+ function['notes'] = ' '.join(return_section.itertext())
+
+ examples = detailed_description.find('para/programlisting')
+
+ if examples is not None:
+ function['examples'] = ''.join([('' if index is 0 else ' ')+word for index, word in enumerate(examples.itertext(),1) ])
+
+ param_list = detailed_description.findall('para/parameterlist')
+
+ if len(param_list) is not 0:
+ for parameter_desc in param_list[0].findall('parameteritem'):
+
+ param_descriptor = {
+ 'name':'',
+ 'description':''
+ }
+
+ param_name = parameter_desc.findall('parameternamelist/parametername')
+ additional = parameter_desc.findall('parameterdescription/para')
+
+ if len(param_name) is not 0:
+ param_descriptor['name'] = param_name[0].text
+
+ if len(additional) is not 0:
+ param_descriptor['description'] = ' '.join(additional[0].itertext())
+
+ for descriptor in function['params']:
+ if param_descriptor['name'] in descriptor['name']:
+ descriptor['description'] = param_descriptor['description']
+
+ return function
+
+ def generate_doxygen(self):
+ self.utils.mk_dir(self.working_dir)
+ self.utils.clean_dir(self.working_dir)
+
+ for path in self.header_paths:
+ self.get_headers(path, self.working_dir)
+
+ if os.path.exists(self.doxygen_xml_dest):
+ self.utils.clean_dir(self.doxygen_xml_dest)
+
+ os.system('doxygen doxy-config.cfg')