220 lines
6.7 KiB
Python
220 lines
6.7 KiB
Python
#
|
|
# 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
|