55c7b7834d328dee2dc0c0e7280dbeb57cb2800a
[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
22 from grc_gnuradio.Constants import DOCS_DIR
23 from lxml import etree
24 import os
25
26 DOXYGEN_NAME_XPATH = '/doxygen/compounddef/compoundname'
27 DOXYGEN_BRIEFDESC_GR_XPATH = '/doxygen/compounddef/briefdescription'
28 DOXYGEN_DETAILDESC_GR_XPATH = '/doxygen/compounddef/detaileddescription'
29 DOXYGEN_BRIEFDESC_BLKS2_XPATH = '/doxygen/compounddef/sectiondef[@kind="public-func"]/memberdef/briefdescription'
30 DOXYGEN_DETAILDESC_BLKS2_XPATH = '/doxygen/compounddef/sectiondef[@kind="public-func"]/memberdef/detaileddescription'
31
32 def extract_txt(xml, parent_text=None):
33         """!
34         Recursivly pull the text out of an xml tree.
35         @param xml the xml tree
36         @param parent_text the text of the parent element
37         @return a string
38         """
39         text = xml.text or ''
40         tail = parent_text and xml.tail or ''
41         return text + ''.join(
42                 map(lambda x: extract_txt(x, text), xml)
43         ) + tail
44
45 def is_match(key, file):
46         """!
47         Is the block key a match for the given file name?
48         @param key block key
49         @param file the xml file name
50         @return true if matches
51         """
52         if not file.endswith('.xml'): return False
53         file = file.replace('.xml', '') #remove file ext
54         file = file.replace('__', '_') #doxygen xml files have 2 underscores
55         if key.startswith('gr_'):
56                 if not file.startswith('classgr_'): return False
57                 key = key.replace('gr_', 'classgr_')
58         elif key.startswith('trellis_'):
59                 if not file.startswith('classtrellis_'): return False
60                 key = key.replace('trellis_', 'classtrellis_')
61         elif key.startswith('blks2_'):
62                 if not file.startswith('classgnuradio_'): return False
63                 if 'blks2' not in file: return False
64                 file = file.replace('_1_1', '_') #weird blks2 doxygen syntax
65                 key = key.replace('blks2_', '')
66         else: return False
67         for k, f in zip(*map(reversed, map(lambda x: x.split('_'), [key, file]))):
68                 if k == f: continue
69                 ks = k.split('x')
70                 if len(ks) == 2 and f.startswith(ks[0]) and f.endswith(ks[1]): continue
71                 if len(ks) > 2 and all(ki in ('x', fi) for ki, fi in zip(k, f)): continue
72                 return False
73         return True
74
75 def extract(key):
76         """!
77         Extract the documentation from the doxygen generated xml files.
78         If multiple files match, combine the docs.
79         @param key the block key
80         @return a string with documentation
81         """
82         #get potential xml file matches for the key
83         if os.path.exists(DOCS_DIR) and os.path.isdir(DOCS_DIR):
84                 matches = filter(lambda f: is_match(key, f), os.listdir(DOCS_DIR))
85         else: matches = list()
86         #combine all matches
87         doc_strs = list()
88         for match in matches:
89                 try:
90                         xml_file = DOCS_DIR + '/' + match
91                         xml = etree.parse(xml_file)
92                         #extract descriptions
93                         comp_name = extract_txt(xml.xpath(DOXYGEN_NAME_XPATH)[0]).strip('\n')
94                         comp_name = '   ---   ' + comp_name + '   ---   '
95                         if key.startswith('gr_') or key.startswith('trellis_'):
96                                 brief_desc = extract_txt(xml.xpath(DOXYGEN_BRIEFDESC_GR_XPATH)[0]).strip('\n')
97                                 detailed_desc = extract_txt(xml.xpath(DOXYGEN_DETAILDESC_GR_XPATH)[0]).strip('\n')
98                         elif key.startswith('blks2_'):
99                                 brief_desc = extract_txt(xml.xpath(DOXYGEN_BRIEFDESC_BLKS2_XPATH)[0]).strip('\n')
100                                 detailed_desc = extract_txt(xml.xpath(DOXYGEN_DETAILDESC_BLKS2_XPATH)[0]).strip('\n')
101                         else:
102                                 brief_desc = ''
103                                 detailed_desc = ''
104                         #combine
105                         doc_strs.append('\n'.join([comp_name, brief_desc, detailed_desc]).strip('\n'))
106                 except IndexError: pass #bad format
107         return '\n\n'.join(doc_strs)
108
109 if __name__ == '__main__':
110         import sys
111         print extract(sys.argv[1])