bc0dcd446d43063992007b964bee0adcf37ca594
[debian/gnuradio] / grc / src / grc_gnuradio / 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 ##@package grc_gnuradio.utils.extract_docs
20 #Extract documentation from the gnuradio doxygen files.
21 #@author Josh Blum
22
23 from grc_gnuradio.Constants import *
24 from lxml import etree
25 import os
26
27 DOXYGEN_NAME_XPATH = '/doxygen/compounddef/compoundname'
28 DOXYGEN_BRIEFDESC_GR_XPATH = '/doxygen/compounddef/briefdescription'
29 DOXYGEN_DETAILDESC_GR_XPATH = '/doxygen/compounddef/detaileddescription'
30 DOXYGEN_BRIEFDESC_BLKS2_XPATH = '/doxygen/compounddef/sectiondef[@kind="public-func"]/memberdef/briefdescription'
31 DOXYGEN_DETAILDESC_BLKS2_XPATH = '/doxygen/compounddef/sectiondef[@kind="public-func"]/memberdef/detaileddescription'
32
33 def extract_txt(xml):
34         """!
35         Recursivly pull the text out of an xml tree.
36         @param xml the xml tree
37         @return a string
38         """
39         text = xml.text or ''
40         if not len(xml): return text
41         return ''.join([text] + map(extract_txt, xml))
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])