Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / v9 / lib / python2.4 / multifile.py
CommitLineData
920dae64
AT
1"""A readline()-style interface to the parts of a multipart message.
2
3The MultiFile class makes each part of a multipart message "feel" like
4an ordinary file, as long as you use fp.readline(). Allows recursive
5use, for nested multipart messages. Probably best used together
6with module mimetools.
7
8Suggested use:
9
10real_fp = open(...)
11fp = MultiFile(real_fp)
12
13"read some lines from fp"
14fp.push(separator)
15while 1:
16 "read lines from fp until it returns an empty string" (A)
17 if not fp.next(): break
18fp.pop()
19"read remaining lines from fp until it returns an empty string"
20
21The latter sequence may be used recursively at (A).
22It is also allowed to use multiple push()...pop() sequences.
23
24If seekable is given as 0, the class code will not do the bookkeeping
25it normally attempts in order to make seeks relative to the beginning of the
26current file part. This may be useful when using MultiFile with a non-
27seekable stream object.
28"""
29
30__all__ = ["MultiFile","Error"]
31
32class Error(Exception):
33 pass
34
35class MultiFile:
36
37 seekable = 0
38
39 def __init__(self, fp, seekable=1):
40 self.fp = fp
41 self.stack = []
42 self.level = 0
43 self.last = 0
44 if seekable:
45 self.seekable = 1
46 self.start = self.fp.tell()
47 self.posstack = []
48
49 def tell(self):
50 if self.level > 0:
51 return self.lastpos
52 return self.fp.tell() - self.start
53
54 def seek(self, pos, whence=0):
55 here = self.tell()
56 if whence:
57 if whence == 1:
58 pos = pos + here
59 elif whence == 2:
60 if self.level > 0:
61 pos = pos + self.lastpos
62 else:
63 raise Error, "can't use whence=2 yet"
64 if not 0 <= pos <= here or \
65 self.level > 0 and pos > self.lastpos:
66 raise Error, 'bad MultiFile.seek() call'
67 self.fp.seek(pos + self.start)
68 self.level = 0
69 self.last = 0
70
71 def readline(self):
72 if self.level > 0:
73 return ''
74 line = self.fp.readline()
75 # Real EOF?
76 if not line:
77 self.level = len(self.stack)
78 self.last = (self.level > 0)
79 if self.last:
80 raise Error, 'sudden EOF in MultiFile.readline()'
81 return ''
82 assert self.level == 0
83 # Fast check to see if this is just data
84 if self.is_data(line):
85 return line
86 else:
87 # Ignore trailing whitespace on marker lines
88 marker = line.rstrip()
89 # No? OK, try to match a boundary.
90 # Return the line (unstripped) if we don't.
91 for i, sep in enumerate(reversed(self.stack)):
92 if marker == self.section_divider(sep):
93 self.last = 0
94 break
95 elif marker == self.end_marker(sep):
96 self.last = 1
97 break
98 else:
99 return line
100 # We only get here if we see a section divider or EOM line
101 if self.seekable:
102 self.lastpos = self.tell() - len(line)
103 self.level = i+1
104 if self.level > 1:
105 raise Error,'Missing endmarker in MultiFile.readline()'
106 return ''
107
108 def readlines(self):
109 list = []
110 while 1:
111 line = self.readline()
112 if not line: break
113 list.append(line)
114 return list
115
116 def read(self): # Note: no size argument -- read until EOF only!
117 return ''.join(self.readlines())
118
119 def next(self):
120 while self.readline(): pass
121 if self.level > 1 or self.last:
122 return 0
123 self.level = 0
124 self.last = 0
125 if self.seekable:
126 self.start = self.fp.tell()
127 return 1
128
129 def push(self, sep):
130 if self.level > 0:
131 raise Error, 'bad MultiFile.push() call'
132 self.stack.append(sep)
133 if self.seekable:
134 self.posstack.append(self.start)
135 self.start = self.fp.tell()
136
137 def pop(self):
138 if self.stack == []:
139 raise Error, 'bad MultiFile.pop() call'
140 if self.level <= 1:
141 self.last = 0
142 else:
143 abslastpos = self.lastpos + self.start
144 self.level = max(0, self.level - 1)
145 self.stack.pop()
146 if self.seekable:
147 self.start = self.posstack.pop()
148 if self.level > 0:
149 self.lastpos = abslastpos - self.start
150
151 def is_data(self, line):
152 return line[:2] != '--'
153
154 def section_divider(self, str):
155 return "--" + str
156
157 def end_marker(self, str):
158 return "--" + str + "--"