1# dictfile.py 2# 3# Copyright 2009 Kristoffer Gronlund <kristoffer.gronlund@purplescout.se> 4 5""" Dictionary File 6 7Implements an iterable file format that handles the 8RADIUS $INCLUDE directives behind the scene. 9""" 10 11import os 12import six 13 14 15class _Node(object): 16 """Dictionary file node 17 18 A single dictionary file. 19 """ 20 __slots__ = ('name', 'lines', 'current', 'length', 'dir') 21 22 def __init__(self, fd, name, parentdir): 23 self.lines = fd.readlines() 24 self.length = len(self.lines) 25 self.current = 0 26 self.name = os.path.basename(name) 27 path = os.path.dirname(name) 28 if os.path.isabs(path): 29 self.dir = path 30 else: 31 self.dir = os.path.join(parentdir, path) 32 33 def Next(self): 34 if self.current >= self.length: 35 return None 36 self.current += 1 37 return self.lines[self.current - 1] 38 39 40class DictFile(object): 41 """Dictionary file class 42 43 An iterable file type that handles $INCLUDE 44 directives internally. 45 """ 46 __slots__ = ('stack') 47 48 def __init__(self, fil): 49 """ 50 @param fil: a dictionary file to parse 51 @type fil: string or file 52 """ 53 self.stack = [] 54 self.__ReadNode(fil) 55 56 def __ReadNode(self, fil): 57 node = None 58 parentdir = self.__CurDir() 59 if isinstance(fil, six.string_types): 60 fname = None 61 if os.path.isabs(fil): 62 fname = fil 63 else: 64 fname = os.path.join(parentdir, fil) 65 fd = open(fname, "rt") 66 node = _Node(fd, fil, parentdir) 67 fd.close() 68 else: 69 node = _Node(fil, '', parentdir) 70 self.stack.append(node) 71 72 def __CurDir(self): 73 if self.stack: 74 return self.stack[-1].dir 75 else: 76 return os.path.realpath(os.curdir) 77 78 def __GetInclude(self, line): 79 line = line.split("#", 1)[0].strip() 80 tokens = line.split() 81 if tokens and tokens[0].upper() == '$INCLUDE': 82 return " ".join(tokens[1:]) 83 else: 84 return None 85 86 def Line(self): 87 """Returns line number of current file 88 """ 89 if self.stack: 90 return self.stack[-1].current 91 else: 92 return -1 93 94 def File(self): 95 """Returns name of current file 96 """ 97 if self.stack: 98 return self.stack[-1].name 99 else: 100 return '' 101 102 def __iter__(self): 103 return self 104 105 def __next__(self): 106 while self.stack: 107 line = self.stack[-1].Next() 108 if line == None: 109 self.stack.pop() 110 else: 111 inc = self.__GetInclude(line) 112 if inc: 113 self.__ReadNode(inc) 114 else: 115 return line 116 raise StopIteration 117 next = __next__ # BBB for python <3 118