Merged r9481:9518 on jblum/grc_reorganize into trunk. Reorganized grc source under...
[debian/gnuradio] / grc / src / platforms / python / utils / extract_docs.py
1 """
2 Copyright 2008 Free Software Foundation, Inc.
3 This file is part of GNU Radio
4
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18 """
19
20 from .. Constants import DOCS_DIR
21 from lxml import etree
22 import os
23
24 DOXYGEN_NAME_XPATH = '/doxygen/compounddef/compoundname'
25 DOXYGEN_BRIEFDESC_GR_XPATH = '/doxygen/compounddef/briefdescription'
26 DOXYGEN_DETAILDESC_GR_XPATH = '/doxygen/compounddef/detaileddescription'
27 DOXYGEN_BRIEFDESC_BLKS2_XPATH = '/doxygen/compounddef/sectiondef[@kind="public-func"]/memberdef/briefdescription'
28 DOXYGEN_DETAILDESC_BLKS2_XPATH = '/doxygen/compounddef/sectiondef[@kind="public-func"]/memberdef/detaileddescription'
29
30 def extract_txt(xml, parent_text=None):
31         """
32         Recursivly pull the text out of an xml tree.
33         @param xml the xml tree
34         @param parent_text the text of the parent element
35         @return a string
36         """
37         text = xml.text or ''
38         tail = parent_text and xml.tail or ''
39         return text + ''.join(
40                 map(lambda x: extract_txt(x, text), xml)
41         ) + tail
42
43 def is_match(key, file):
44         """
45         Is the block key a match for the given file name?
46         @param key block key
47         @param file the xml file name
48         @return true if matches
49         """
50         if not file.endswith('.xml'): return False
51         file = file.replace('.xml', '') #remove file ext
52         file = file.replace('__', '_') #doxygen xml files have 2 underscores
53         if key.startswith('gr_'):
54                 if not file.startswith('classgr_'): return False
55                 key = key.replace('gr_', 'classgr_')
56         elif key.startswith('trellis_'):
57                 if not file.startswith('classtrellis_'): return False
58                 key = key.replace('trellis_', 'classtrellis_')
59         elif key.startswith('blks2_'):
60                 if not file.startswith('classgnuradio_'): return False
61                 if 'blks2' not in file: return False
62                 file = file.replace('_1_1', '_') #weird blks2 doxygen syntax
63                 key = key.replace('blks2_', '')
64         else: return False
65         for k, f in zip(*map(reversed, map(lambda x: x.split('_'), [key, file]))):
66                 if k == f: continue
67                 ks = k.split('x')
68                 if len(ks) == 2 and f.startswith(ks[0]) and f.endswith(ks[1]): continue
69                 if len(ks) > 2 and all(ki in ('x', fi) for ki, fi in zip(k, f)): continue
70                 return False
71         return True
72
73 def extract(key):
74         """
75         Extract the documentation from the doxygen generated xml files.
76         If multiple files match, combine the docs.
77         @param key the block key
78         @return a string with documentation
79         """
80         #get potential xml file matches for the key
81         if os.path.exists(DOCS_DIR) and os.path.isdir(DOCS_DIR):
82                 matches = filter(lambda f: is_match(key, f), os.listdir(DOCS_DIR))
83         else: matches = list()
84         #combine all matches
85         doc_strs = list()
86         for match in matches:
87                 try:
88                         xml_file = DOCS_DIR + '/' + match
89                         xml = etree.parse(xml_file)
90                         #extract descriptions
91                         comp_name = extract_txt(xml.xpath(DOXYGEN_NAME_XPATH)[0]).strip('\n')
92                         comp_name = '   ---   ' + comp_name + '   ---   '
93                         if key.startswith('gr_') or key.startswith('trellis_'):
94                                 brief_desc = extract_txt(xml.xpath(DOXYGEN_BRIEFDESC_GR_XPATH)[0]).strip('\n')
95                                 detailed_desc = extract_txt(xml.xpath(DOXYGEN_DETAILDESC_GR_XPATH)[0]).strip('\n')
96                         elif key.startswith('blks2_'):
97                                 brief_desc = extract_txt(xml.xpath(DOXYGEN_BRIEFDESC_BLKS2_XPATH)[0]).strip('\n')
98                                 detailed_desc = extract_txt(xml.xpath(DOXYGEN_DETAILDESC_BLKS2_XPATH)[0]).strip('\n')
99                         else:
100                                 brief_desc = ''
101                                 detailed_desc = ''
102                         #combine
103                         doc_strs.append('\n'.join([comp_name, brief_desc, detailed_desc]).strip('\n'))
104                 except IndexError: pass #bad format
105         return '\n\n'.join(doc_strs)
106
107 if __name__ == '__main__':
108         import sys
109         print extract(sys.argv[1])