blob: e8f026ab90a622aeb82de1d661a0a55af9fb1978 [file] [log] [blame]
piotr437f5462014-02-04 17:57:25 +01001#
2# Copyright 2010 Free Software Foundation, Inc.
3#
4# This file is part of GNU Radio
5#
6# GNU Radio is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3, or (at your option)
9# any later version.
10#
11# GNU Radio is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with GNU Radio; see the file COPYING. If not, write to
18# the Free Software Foundation, Inc., 51 Franklin Street,
19# Boston, MA 02110-1301, USA.
20#
21"""
22A base class is created.
23
24Classes based upon this are used to make more user-friendly interfaces
25to the doxygen xml docs than the generated classes provide.
26"""
27
28import os
29import pdb
30
31from xml.parsers.expat import ExpatError
32
33from generated import compound
34
35
36class Base(object):
37
38 class Duplicate(StandardError):
39 pass
40
41 class NoSuchMember(StandardError):
42 pass
43
44 class ParsingError(StandardError):
45 pass
46
47 def __init__(self, parse_data, top=None):
48 self._parsed = False
49 self._error = False
50 self._parse_data = parse_data
51 self._members = []
52 self._dict_members = {}
53 self._in_category = {}
54 self._data = {}
55 if top is not None:
56 self._xml_path = top._xml_path
57 # Set up holder of references
58 else:
59 top = self
60 self._refs = {}
61 self._xml_path = parse_data
62 self.top = top
63
64 @classmethod
65 def from_refid(cls, refid, top=None):
66 """ Instantiate class from a refid rather than parsing object. """
67 # First check to see if its already been instantiated.
68 if top is not None and refid in top._refs:
69 return top._refs[refid]
70 # Otherwise create a new instance and set refid.
71 inst = cls(None, top=top)
72 inst.refid = refid
73 inst.add_ref(inst)
74 return inst
75
76 @classmethod
77 def from_parse_data(cls, parse_data, top=None):
78 refid = getattr(parse_data, 'refid', None)
79 if refid is not None and top is not None and refid in top._refs:
80 return top._refs[refid]
81 inst = cls(parse_data, top=top)
82 if refid is not None:
83 inst.refid = refid
84 inst.add_ref(inst)
85 return inst
86
87 def add_ref(self, obj):
88 if hasattr(obj, 'refid'):
89 self.top._refs[obj.refid] = obj
90
91 mem_classes = []
92
93 def get_cls(self, mem):
94 for cls in self.mem_classes:
95 if cls.can_parse(mem):
96 return cls
97 raise StandardError(("Did not find a class for object '%s'." \
98 % (mem.get_name())))
99
100 def convert_mem(self, mem):
101 try:
102 cls = self.get_cls(mem)
103 converted = cls.from_parse_data(mem, self.top)
104 if converted is None:
105 raise StandardError('No class matched this object.')
106 self.add_ref(converted)
107 return converted
108 except StandardError, e:
109 print e
110
111 @classmethod
112 def includes(cls, inst):
113 return isinstance(inst, cls)
114
115 @classmethod
116 def can_parse(cls, obj):
117 return False
118
119 def _parse(self):
120 self._parsed = True
121
122 def _get_dict_members(self, cat=None):
123 """
124 For given category a dictionary is returned mapping member names to
125 members of that category. For names that are duplicated the name is
126 mapped to None.
127 """
128 self.confirm_no_error()
129 if cat not in self._dict_members:
130 new_dict = {}
131 for mem in self.in_category(cat):
132 if mem.name() not in new_dict:
133 new_dict[mem.name()] = mem
134 else:
135 new_dict[mem.name()] = self.Duplicate
136 self._dict_members[cat] = new_dict
137 return self._dict_members[cat]
138
139 def in_category(self, cat):
140 self.confirm_no_error()
141 if cat is None:
142 return self._members
143 if cat not in self._in_category:
144 self._in_category[cat] = [mem for mem in self._members
145 if cat.includes(mem)]
146 return self._in_category[cat]
147
148 def get_member(self, name, cat=None):
149 self.confirm_no_error()
150 # Check if it's in a namespace or class.
151 bits = name.split('::')
152 first = bits[0]
153 rest = '::'.join(bits[1:])
154 member = self._get_dict_members(cat).get(first, self.NoSuchMember)
155 # Raise any errors that are returned.
156 if member in set([self.NoSuchMember, self.Duplicate]):
157 raise member()
158 if rest:
159 return member.get_member(rest, cat=cat)
160 return member
161
162 def has_member(self, name, cat=None):
163 try:
164 mem = self.get_member(name, cat=cat)
165 return True
166 except self.NoSuchMember:
167 return False
168
169 def data(self):
170 self.confirm_no_error()
171 return self._data
172
173 def members(self):
174 self.confirm_no_error()
175 return self._members
176
177 def process_memberdefs(self):
178 mdtss = []
179 for sec in self._retrieved_data.compounddef.sectiondef:
180 mdtss += sec.memberdef
181 # At the moment we lose all information associated with sections.
182 # Sometimes a memberdef is in several sectiondef.
183 # We make sure we don't get duplicates here.
184 uniques = set([])
185 for mem in mdtss:
186 converted = self.convert_mem(mem)
187 pair = (mem.name, mem.__class__)
188 if pair not in uniques:
189 uniques.add(pair)
190 self._members.append(converted)
191
192 def retrieve_data(self):
193 filename = os.path.join(self._xml_path, self.refid + '.xml')
194 try:
195 self._retrieved_data = compound.parse(filename)
196 except ExpatError:
197 print('Error in xml in file %s' % filename)
198 self._error = True
199 self._retrieved_data = None
200
201 def check_parsed(self):
202 if not self._parsed:
203 self._parse()
204
205 def confirm_no_error(self):
206 self.check_parsed()
207 if self._error:
208 raise self.ParsingError()
209
210 def error(self):
211 self.check_parsed()
212 return self._error
213
214 def name(self):
215 # first see if we can do it without processing.
216 if self._parse_data is not None:
217 return self._parse_data.name
218 self.check_parsed()
219 return self._retrieved_data.compounddef.name