You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
6.6 KiB
219 lines
6.6 KiB
# |
|
# Copyright 2010 Free Software Foundation, Inc. |
|
# |
|
# This file is part of GNU Radio |
|
# |
|
# GNU Radio is free software; you can redistribute it and/or modify |
|
# it under the terms of the GNU General Public License as published by |
|
# the Free Software Foundation; either version 3, or (at your option) |
|
# any later version. |
|
# |
|
# GNU Radio is distributed in the hope that it will be useful, |
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
# GNU General Public License for more details. |
|
# |
|
# You should have received a copy of the GNU General Public License |
|
# along with GNU Radio; see the file COPYING. If not, write to |
|
# the Free Software Foundation, Inc., 51 Franklin Street, |
|
# Boston, MA 02110-1301, USA. |
|
# |
|
""" |
|
A base class is created. |
|
|
|
Classes based upon this are used to make more user-friendly interfaces |
|
to the doxygen xml docs than the generated classes provide. |
|
""" |
|
|
|
import os |
|
import pdb |
|
|
|
from xml.parsers.expat import ExpatError |
|
|
|
from generated import compound |
|
|
|
|
|
class Base(object): |
|
|
|
class Duplicate(StandardError): |
|
pass |
|
|
|
class NoSuchMember(StandardError): |
|
pass |
|
|
|
class ParsingError(StandardError): |
|
pass |
|
|
|
def __init__(self, parse_data, top=None): |
|
self._parsed = False |
|
self._error = False |
|
self._parse_data = parse_data |
|
self._members = [] |
|
self._dict_members = {} |
|
self._in_category = {} |
|
self._data = {} |
|
if top is not None: |
|
self._xml_path = top._xml_path |
|
# Set up holder of references |
|
else: |
|
top = self |
|
self._refs = {} |
|
self._xml_path = parse_data |
|
self.top = top |
|
|
|
@classmethod |
|
def from_refid(cls, refid, top=None): |
|
""" Instantiate class from a refid rather than parsing object. """ |
|
# First check to see if its already been instantiated. |
|
if top is not None and refid in top._refs: |
|
return top._refs[refid] |
|
# Otherwise create a new instance and set refid. |
|
inst = cls(None, top=top) |
|
inst.refid = refid |
|
inst.add_ref(inst) |
|
return inst |
|
|
|
@classmethod |
|
def from_parse_data(cls, parse_data, top=None): |
|
refid = getattr(parse_data, 'refid', None) |
|
if refid is not None and top is not None and refid in top._refs: |
|
return top._refs[refid] |
|
inst = cls(parse_data, top=top) |
|
if refid is not None: |
|
inst.refid = refid |
|
inst.add_ref(inst) |
|
return inst |
|
|
|
def add_ref(self, obj): |
|
if hasattr(obj, 'refid'): |
|
self.top._refs[obj.refid] = obj |
|
|
|
mem_classes = [] |
|
|
|
def get_cls(self, mem): |
|
for cls in self.mem_classes: |
|
if cls.can_parse(mem): |
|
return cls |
|
raise StandardError(("Did not find a class for object '%s'." \ |
|
% (mem.get_name()))) |
|
|
|
def convert_mem(self, mem): |
|
try: |
|
cls = self.get_cls(mem) |
|
converted = cls.from_parse_data(mem, self.top) |
|
if converted is None: |
|
raise StandardError('No class matched this object.') |
|
self.add_ref(converted) |
|
return converted |
|
except StandardError, e: |
|
print e |
|
|
|
@classmethod |
|
def includes(cls, inst): |
|
return isinstance(inst, cls) |
|
|
|
@classmethod |
|
def can_parse(cls, obj): |
|
return False |
|
|
|
def _parse(self): |
|
self._parsed = True |
|
|
|
def _get_dict_members(self, cat=None): |
|
""" |
|
For given category a dictionary is returned mapping member names to |
|
members of that category. For names that are duplicated the name is |
|
mapped to None. |
|
""" |
|
self.confirm_no_error() |
|
if cat not in self._dict_members: |
|
new_dict = {} |
|
for mem in self.in_category(cat): |
|
if mem.name() not in new_dict: |
|
new_dict[mem.name()] = mem |
|
else: |
|
new_dict[mem.name()] = self.Duplicate |
|
self._dict_members[cat] = new_dict |
|
return self._dict_members[cat] |
|
|
|
def in_category(self, cat): |
|
self.confirm_no_error() |
|
if cat is None: |
|
return self._members |
|
if cat not in self._in_category: |
|
self._in_category[cat] = [mem for mem in self._members |
|
if cat.includes(mem)] |
|
return self._in_category[cat] |
|
|
|
def get_member(self, name, cat=None): |
|
self.confirm_no_error() |
|
# Check if it's in a namespace or class. |
|
bits = name.split('::') |
|
first = bits[0] |
|
rest = '::'.join(bits[1:]) |
|
member = self._get_dict_members(cat).get(first, self.NoSuchMember) |
|
# Raise any errors that are returned. |
|
if member in set([self.NoSuchMember, self.Duplicate]): |
|
raise member() |
|
if rest: |
|
return member.get_member(rest, cat=cat) |
|
return member |
|
|
|
def has_member(self, name, cat=None): |
|
try: |
|
mem = self.get_member(name, cat=cat) |
|
return True |
|
except self.NoSuchMember: |
|
return False |
|
|
|
def data(self): |
|
self.confirm_no_error() |
|
return self._data |
|
|
|
def members(self): |
|
self.confirm_no_error() |
|
return self._members |
|
|
|
def process_memberdefs(self): |
|
mdtss = [] |
|
for sec in self._retrieved_data.compounddef.sectiondef: |
|
mdtss += sec.memberdef |
|
# At the moment we lose all information associated with sections. |
|
# Sometimes a memberdef is in several sectiondef. |
|
# We make sure we don't get duplicates here. |
|
uniques = set([]) |
|
for mem in mdtss: |
|
converted = self.convert_mem(mem) |
|
pair = (mem.name, mem.__class__) |
|
if pair not in uniques: |
|
uniques.add(pair) |
|
self._members.append(converted) |
|
|
|
def retrieve_data(self): |
|
filename = os.path.join(self._xml_path, self.refid + '.xml') |
|
try: |
|
self._retrieved_data = compound.parse(filename) |
|
except ExpatError: |
|
print('Error in xml in file %s' % filename) |
|
self._error = True |
|
self._retrieved_data = None |
|
|
|
def check_parsed(self): |
|
if not self._parsed: |
|
self._parse() |
|
|
|
def confirm_no_error(self): |
|
self.check_parsed() |
|
if self._error: |
|
raise self.ParsingError() |
|
|
|
def error(self): |
|
self.check_parsed() |
|
return self._error |
|
|
|
def name(self): |
|
# first see if we can do it without processing. |
|
if self._parse_data is not None: |
|
return self._parse_data.name |
|
self.check_parsed() |
|
return self._retrieved_data.compounddef.name
|
|
|