Author: Armin Rigo <[email protected]>
Branch: fileops2
Changeset: r67207:3a0aea85c508
Date: 2013-10-08 16:55 +0200
http://bitbucket.org/pypy/pypy/changeset/3a0aea85c508/
Log: Finish the implementation of readline().
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -47,7 +47,7 @@
rffi.CCHARP)
BASE_BUF_SIZE = 4096
-BASE_LINE_SIZE = 1000
+BASE_LINE_SIZE = 100
def create_file(filename, mode="r", buffering=-1):
assert buffering == -1
@@ -194,35 +194,48 @@
def __del__(self):
self.close()
+ def _readline1(self, raw_buf):
+ result = c_fgets(raw_buf, BASE_LINE_SIZE, self.ll_file)
+ if not result:
+ if c_feof(self.ll_file): # ok
+ return 0
+ errno = c_ferror(self.ll_file)
+ raise OSError(errno, os.strerror(errno))
+ #
+ # Assume that fgets() works as documented, and additionally
+ # never writes beyond the final \0, which the CPython
+ # fileobject.c says appears to be the case everywhere.
+ # The only case where the buffer was not big enough is the
+ # case where the buffer is full, ends with \0, and doesn't
+ # end with \n\0.
+ strlen = 0
+ while raw_buf[strlen] != '\0':
+ strlen += 1
+ if (strlen == BASE_LINE_SIZE - 1 and
+ raw_buf[BASE_LINE_SIZE - 2] != '\n'):
+ return -1 # overflow!
+ # common case
+ return strlen
+
def readline(self):
if self.ll_file:
raw_buf, gc_buf = rffi.alloc_buffer(BASE_LINE_SIZE)
try:
- result = c_fgets(raw_buf, BASE_LINE_SIZE, self.ll_file)
- if not result:
- if c_feof(self.ll_file): # ok
- return ''
- errno = c_ferror(self.ll_file)
- raise OSError(errno, os.strerror(errno))
+ c = self._readline1(raw_buf)
+ if c >= 0:
+ return rffi.str_from_buffer(raw_buf, gc_buf,
+ BASE_LINE_SIZE, c)
#
- # Assume that fgets() works as documented, and additionally
- # never writes beyond the final \0, which the CPython
- # fileobject.c says appears to be the case everywhere.
- # The only case where the buffer was not big enough is the
- # case where the buffer is full, ends with \0, and doesn't
- # end with \n\0.
- strlen = 0
- while raw_buf[strlen] != '\0':
- strlen += 1
+ # this is the rare case: the line is longer than BASE_LINE_SIZE
+ s = StringBuilder()
+ while True:
+ s.append_charpsize(raw_buf, BASE_LINE_SIZE - 1)
+ c = self._readline1(raw_buf)
+ if c >= 0:
+ break
#
- if (strlen != BASE_LINE_SIZE - 1 or
- raw_buf[BASE_LINE_SIZE - 2] == '\n'):
- # common case
- return rffi.str_from_buffer(raw_buf, gc_buf,
- BASE_LINE_SIZE, strlen)
- #
- XXX
-
+ s.append_charpsize(raw_buf, c)
+ return s.build()
finally:
rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
raise ValueError("I/O operation on closed file")
diff --git a/rpython/rlib/test/test_rfile.py b/rpython/rlib/test/test_rfile.py
--- a/rpython/rlib/test/test_rfile.py
+++ b/rpython/rlib/test/test_rfile.py
@@ -147,15 +147,30 @@
j = 0
expected = []
with open(fname, 'w') as f:
- for i in range(50):
- s = ''.join([chr(32+(k&63)) for k in range(j, j + i*7)])
+ for i in range(150):
+ s = ''.join([chr(32+(k&63)) for k in range(j, j + i)])
+ j += 1
print >> f, s
- f.write('no newline')
expected = open(fname).readlines()
+ expected += ['', '']
+ assert len(expected) == 152
f = rfile.create_file(fname, 'r')
- got = []
- for j in range(53):
- got.append(f.readline())
+ for j in range(152):
+ got = f.readline()
+ assert got == expected[j]
f.close()
- assert got == expected + ['', '']
+
+ def test_readline_without_eol_at_the_end(self):
+ fname = str(self.tmpdir.join('file_readline_without_eol_at_the_end'))
+ for n in [1, 10, 97, 98, 99, 100, 101, 102, 103, 150]:
+ s = ''.join([chr(32+(k&63)) for k in range(n)])
+ with open(fname, 'wb') as f:
+ f.write(s)
+
+ f = rfile.create_file(fname, 'r')
+ got = f.readline()
+ assert got == s
+ got = f.readline()
+ assert got == ''
+ f.close()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit