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