1 # A class that makes each part of a multipart message "feel" like an
2 # ordinary file, as long as you use fp.readline(). Allows recursive
3 # use, for nested multipart messages. Probably best used together
4 # with module mimetools.
9 # fp = MultiFile(real_fp)
11 # "read some lines from fp"
14 # "read lines from fp until it returns an empty string" (A)
15 # if not fp.next(): break
17 # "read remaining lines from fp until it returns an empty string"
19 # The latter sequence may be used recursively at (A).
20 # It is also allowed to use multiple push()...pop() sequences.
21 # Note that if a nested multipart message is terminated by a separator
22 # for an outer message, this is not reported, even though it is really
28 err
= sys
.stderr
.write
30 Error
= 'multifile.Error'
34 def __init__(self
, fp
):
36 self
.stack
= [] # Grows down
39 self
.start
= self
.fp
.tell()
40 self
.posstack
= [] # Grows down
45 return self
.fp
.tell() - self
.start
48 if not 0 <= pos
<= self
.tell() or \
49 self
.level
> 0 and pos
> self
.lastpos
:
50 raise Error
, 'bad MultiFile.seek() call'
51 self
.fp
.seek(pos
+ self
.start
)
56 if self
.level
> 0: return ''
57 line
= self
.fp
.readline()
59 self
.level
= len(self
.stack
)
60 self
.last
= (self
.level
> 0)
62 err('*** Sudden EOF in MultiFile.readline()\n')
64 if line
[:2] <> '--': return line
67 while k
> 0 and line
[k
-1] in string
.whitespace
: k
= k
-1
69 if mark
[-2:] == '--': mark1
= mark
[:-2]
71 for i
in range(len(self
.stack
)):
76 elif mark1
<> None and sep
== mark1
:
81 # Get here after break out of loop
82 self
.lastpos
= self
.tell() - len(line
)
85 err('*** Missing endmarker in MultiFile.readline()\n')
91 line
= self
.readline()
96 def read(self
): # Note: no size argument -- read until EOF only!
97 return string
.joinfields(self
.readlines(), '')
100 while self
.readline(): pass
101 if self
.level
> 1 or self
.last
:
105 self
.start
= self
.fp
.tell()
110 raise Error
, 'bad MultiFile.push() call'
111 self
.stack
.insert(0, sep
)
112 self
.posstack
.insert(0, self
.start
)
113 self
.start
= self
.fp
.tell()
117 raise Error
, 'bad MultiFile.pop() call'
121 abslastpos
= self
.lastpos
+ self
.start
122 self
.level
= max(0, self
.level
- 1)
124 self
.start
= self
.posstack
[0]
127 self
.lastpos
= abslastpos
- self
.start