1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
# A class that makes each part of a multipart message "feel" like an
# ordinary file, as long as you use fp.readline(). Allows recursive
# use, for nested multipart messages. Probably best used together
# with module mimetools.
#
# Suggested use:
#
# real_fp = open(...)
# fp = MultiFile(real_fp)
#
# "read some lines from fp"
# fp.push(separator)
# while 1:
# "read lines from fp until it returns an empty string" (A)
# if not fp.next(): break
# fp.pop()
# "read remaining lines from fp until it returns an empty string"
#
# The latter sequence may be used recursively at (A).
# It is also allowed to use multiple push()...pop() sequences.
# Note that if a nested multipart message is terminated by a separator
# for an outer message, this is not reported, even though it is really
# illegal input.
import sys
import string
err = sys.stderr.write
Error = 'multifile.Error'
class MultiFile:
#
def __init__(self, fp):
self.fp = fp
self.stack = [] # Grows down
self.level = 0
self.last = 0
self.start = self.fp.tell()
self.posstack = [] # Grows down
#
def tell(self):
if self.level > 0:
return self.lastpos
return self.fp.tell() - self.start
#
def seek(self, pos, whence=0):
here = self.tell()
if whence:
if whence == 1:
pos = pos + here
elif whence == 2:
if self.level > 0:
pos = pos + self.lastpos
else:
raise Error, "can't use whence=2 yet"
if not 0 <= pos <= here or \
self.level > 0 and pos > self.lastpos:
raise Error, 'bad MultiFile.seek() call'
self.fp.seek(pos + self.start)
self.level = 0
self.last = 0
#
def readline(self):
if self.level > 0: return ''
line = self.fp.readline()
if not line:
self.level = len(self.stack)
self.last = (self.level > 0)
if self.last:
err('*** Sudden EOF in MultiFile.readline()\n')
return ''
if line[:2] <> '--': return line
n = len(line)
k = n
while k > 0 and line[k-1] in string.whitespace: k = k-1
mark = line[2:k]
if mark[-2:] == '--': mark1 = mark[:-2]
else: mark1 = None
for i in range(len(self.stack)):
sep = self.stack[i]
if sep == mark:
self.last = 0
break
elif mark1 <> None and sep == mark1:
self.last = 1
break
else:
return line
# Get here after break out of loop
self.lastpos = self.tell() - len(line)
self.level = i+1
if self.level > 1:
err('*** Missing endmarker in MultiFile.readline()\n')
return ''
#
def readlines(self):
list = []
while 1:
line = self.readline()
if not line: break
list.append(line)
return list
#
def read(self): # Note: no size argument -- read until EOF only!
return string.joinfields(self.readlines(), '')
#
def next(self):
while self.readline(): pass
if self.level > 1 or self.last:
return 0
self.level = 0
self.last = 0
self.start = self.fp.tell()
return 1
#
def push(self, sep):
if self.level > 0:
raise Error, 'bad MultiFile.push() call'
self.stack.insert(0, sep)
self.posstack.insert(0, self.start)
self.start = self.fp.tell()
#
def pop(self):
if self.stack == []:
raise Error, 'bad MultiFile.pop() call'
if self.level <= 1:
self.last = 0
else:
abslastpos = self.lastpos + self.start
self.level = max(0, self.level - 1)
del self.stack[0]
self.start = self.posstack[0]
del self.posstack[0]
if self.level > 0:
self.lastpos = abslastpos - self.start
#
|