-
Notifications
You must be signed in to change notification settings - Fork 4
/
contread.py
87 lines (78 loc) · 2.13 KB
/
contread.py
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
#
# This module supplies an interface to read from files with
# RFC822 style 'continued lines', with comments and blank lines
# excised.
import re
class StartingContinuedLine(Exception):
pass
# This skips lines that are entirely blank up to a comment start
# character.
skipre = re.compile('^\s*(#|$)')
class RFC822File(object):
def __init__(self, fp):
self._f = fp
self.closed = 0
# Lineno is the line number of the start of the possibly
# continued line. curln is the current true line number.
# accum is the accumulated line to date.
self._lineno = 0
self._curln = 0
self._accum = ''
def close(self):
self._f.close()
self._f = None
self.closed = 1
def _getline(self):
while True:
l = self._f.readline()
# Bail on EOF:
if not l:
break
# We must count even blanks and comments.
self._curln += 1
# Skip blanks and comments.
if skipre.match(l):
continue
# Is this a continued line, or not?
if self._accum and l[0] in ' \t':
self._accum = self._accum.rstrip() + \
' ' + l.lstrip()
elif l[0] in ' \t':
raise StartingContinuedLine("The first real line, at line number %d, is a continuation." % (self._curln,))
else:
res = None
# If accum is non-null, we have just finished
# off another (possibly continued) line and
# want to return it. Otherwise, this is the
# first real line in the file.
if self._accum:
res = (self._lineno, self._accum)
self._lineno = self._curln
self._accum = l
if res:
return res
# We have seen an EOF. Return anything accumulated,
# and set it so that we will continue to return EOF.
res = (self._lineno, self._accum)
self._accum = ''
return res
def readcontline(self):
return self._getline()[1]
def readcontline_ex(self):
res = self._getline()
if res[1] == '':
return ''
else:
return res
def __iter__(self):
while True:
l = self.readcontline()
if not l:
break
yield l
def fromfile(fp):
return RFC822File(fp)
# Note that only 'r' based modes make any sense: r, rb, U, Ur.
# Generally, don't do that.
def openfile(filename, mode = 'r'):
return RFC822File(open(filename, mode))