diff options
author | Guido van Rossum <guido@python.org> | 1992-07-13 14:40:45 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1992-07-13 14:40:45 (GMT) |
commit | 741c81a51f9762a9e61b900d78038d3380e51429 (patch) | |
tree | 6fccbd9e1b5e46bc2dca2126db647026b399e930 /Lib/multifile.py | |
parent | 01ca336ed101dc5dd8dcd6942df58740dbba81df (diff) | |
download | cpython-741c81a51f9762a9e61b900d78038d3380e51429.zip cpython-741c81a51f9762a9e61b900d78038d3380e51429.tar.gz cpython-741c81a51f9762a9e61b900d78038d3380e51429.tar.bz2 |
New module to support decoding multipart messages (also see mimetools).
Diffstat (limited to 'Lib/multifile.py')
-rw-r--r-- | Lib/multifile.py | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/Lib/multifile.py b/Lib/multifile.py new file mode 100644 index 0000000..4dd1b52 --- /dev/null +++ b/Lib/multifile.py @@ -0,0 +1,118 @@ +# 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().init(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 + return self + # + def tell(self): + if self.level > 0: + return self.lastpos + return self.fp.tell() - self.start + # + def seek(self, pos): + if not 0 <= pos <= self.tell() 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 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 + # |