Author: Brian Kearns <[email protected]>
Branch: use-file-star-for-file
Changeset: r73389:2c58cdc115fd
Date: 2014-09-08 19:12 -0400
http://bitbucket.org/pypy/pypy/changeset/2c58cdc115fd/
Log: merge default
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -47,6 +47,11 @@
BASE_BUF_SIZE = 4096
BASE_LINE_SIZE = 100
+NEWLINE_UNKNOWN = 0
+NEWLINE_CR = 1
+NEWLINE_LF = 2
+NEWLINE_CRLF = 4
+
def llexternal(*args, **kwargs):
return rffi.llexternal(*args, compilation_info=eci, **kwargs)
@@ -128,10 +133,10 @@
def create_file(filename, mode="r", buffering=-1):
- mode = _sanitize_mode(mode)
+ newmode = _sanitize_mode(mode)
ll_name = rffi.str2charp(filename)
try:
- ll_mode = rffi.str2charp(mode)
+ ll_mode = rffi.str2charp(newmode)
try:
ll_file = c_fopen(ll_name, ll_mode)
if not ll_file:
@@ -154,10 +159,10 @@
def create_fdopen_rfile(fd, mode="r"):
- mode = _sanitize_mode(mode)
+ newmode = _sanitize_mode(mode)
fd = rffi.cast(rffi.INT, fd)
rposix.validate_fd(fd)
- ll_mode = rffi.str2charp(mode)
+ ll_mode = rffi.str2charp(newmode)
try:
ll_file = c_fdopen(fd, ll_mode)
if not ll_file:
@@ -194,17 +199,14 @@
class RFile(object):
- _readable = False
- _writable = False
+ _univ_newline = False
+ _newlinetypes = NEWLINE_UNKNOWN
+ _skipnextlf = False
- def __init__(self, ll_file, mode='+', close2=_fclose2):
+ def __init__(self, ll_file, mode=None, close2=_fclose2):
self._ll_file = ll_file
- if 'r' in mode:
- self._readable = True
- if 'w' in mode or 'a' in mode:
- self._writable = True
- if '+' in mode:
- self._readable = self._writable = True
+ if mode is not None:
+ self._univ_newline = 'U' in mode
self._close2 = close2
def __del__(self):
@@ -241,18 +243,55 @@
if not self._ll_file:
raise ValueError("I/O operation on closed file")
- def _check_reading(self):
- if not self._readable:
- raise IOError(0, "File not open for reading")
+ def _fread(self, buf, n, stream):
+ if not self._univ_newline:
+ return c_fread(buf, 1, n, stream)
- def _check_writing(self):
- if not self._writable:
- raise IOError(0, "File not open for writing")
+ i = 0
+ dst = buf
+ newlinetypes = self._newlinetypes
+ skipnextlf = self._skipnextlf
+ while n:
+ nread = c_fread(dst, 1, n, stream)
+ if nread == 0:
+ break
+
+ src = dst
+ n -= nread
+ shortread = n != 0
+ while nread:
+ nread -= 1
+ c = src[0]
+ src = rffi.ptradd(src, 1)
+ if c == '\r':
+ dst[0] = '\n'
+ dst = rffi.ptradd(dst, 1)
+ i += 1
+ skipnextlf = True
+ elif skipnextlf and c == '\n':
+ skipnextlf = False
+ newlinetypes |= NEWLINE_CRLF
+ n += 1
+ else:
+ if c == '\n':
+ newlinetypes |= NEWLINE_LF
+ elif skipnextlf:
+ newlinetypes |= NEWLINE_CR
+ dst[0] = c
+ dst = rffi.ptradd(dst, 1)
+ i += 1
+ skipnextlf = False
+ if shortread:
+ if skipnextlf and c_feof(stream):
+ newlinetypes |= NEWLINE_CR
+ break
+ self._newlinetypes = newlinetypes
+ self._skipnextlf = skipnextlf
+ return i
def read(self, size=-1):
# XXX CPython uses a more delicate logic here
self._check_closed()
- self._check_reading()
ll_file = self._ll_file
if size == 0:
return ""
@@ -262,7 +301,7 @@
try:
s = StringBuilder()
while True:
- returned_size = c_fread(buf, 1, BASE_BUF_SIZE, ll_file)
+ returned_size = self._fread(buf, BASE_BUF_SIZE, ll_file)
returned_size = intmask(returned_size) # is between 0 and
BASE_BUF_SIZE
if returned_size == 0:
if c_feof(ll_file):
@@ -274,7 +313,7 @@
lltype.free(buf, flavor='raw')
else: # size > 0
with rffi.scoped_alloc_buffer(size) as buf:
- returned_size = c_fread(buf.raw, 1, size, ll_file)
+ returned_size = self._fread(buf.raw, size, ll_file)
returned_size = intmask(returned_size) # is between 0 and size
if returned_size == 0:
if not c_feof(ll_file):
@@ -318,10 +357,9 @@
def readline(self, size=-1):
self._check_closed()
- self._check_reading()
if size == 0:
return ""
- elif size < 0:
+ elif size < 0 and not self._univ_newline:
with rffi.scoped_alloc_buffer(BASE_LINE_SIZE) as buf:
c = self._readline1(buf.raw)
if c >= 0:
@@ -336,25 +374,55 @@
break
s.append_charpsize(buf.raw, c)
return s.build()
- else: # size > 0
+ else: # size > 0 or self._univ_newline
ll_file = self._ll_file
+ c = 0
s = StringBuilder()
- while s.getlength() < size:
- c = c_getc(ll_file)
+ if self._univ_newline:
+ newlinetypes = self._newlinetypes
+ skipnextlf = self._skipnextlf
+ while size < 0 or s.getlength() < size:
+ c = c_getc(ll_file)
+ if c == EOF:
+ break
+ if skipnextlf:
+ skipnextlf = False
+ if c == ord('\n'):
+ newlinetypes |= NEWLINE_CRLF
+ c = c_getc(ll_file)
+ if c == EOF:
+ break
+ else:
+ newlinetypes |= NEWLINE_CR
+ if c == ord('\r'):
+ skipnextlf = True
+ c = ord('\n')
+ elif c == ord('\n'):
+ newlinetypes |= NEWLINE_LF
+ s.append(chr(c))
+ if c == ord('\n'):
+ break
if c == EOF:
- if c_ferror(ll_file):
- raise _error(ll_file)
- break
- c = chr(c)
- s.append(c)
- if c == '\n':
- break
+ if skipnextlf:
+ newlinetypes |= NEWLINE_CR
+ self._newlinetypes = newlinetypes
+ self._skipnextlf = skipnextlf
+ else:
+ while s.getlength() < size:
+ c = c_getc(ll_file)
+ if c == EOF:
+ break
+ s.append(chr(c))
+ if c == ord('\n'):
+ break
+ if c == EOF:
+ if c_ferror(ll_file):
+ raise _error(ll_file)
return s.build()
@enforceargs(None, str)
def write(self, value):
self._check_closed()
- self._check_writing()
ll_value = rffi.get_nonmovingbuffer(value)
try:
# note that since we got a nonmoving buffer, it is either raw
@@ -363,6 +431,7 @@
bytes = c_fwrite(ll_value, 1, length, self._ll_file)
if bytes != length:
errno = rposix.get_errno()
+ c_clearerr(self._ll_file)
raise IOError(errno, os.strerror(errno))
finally:
rffi.free_nonmovingbuffer(value, ll_value)
@@ -376,7 +445,6 @@
def truncate(self, arg=-1):
self._check_closed()
- self._check_writing()
if arg == -1:
arg = self.tell()
self.flush()
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
@@ -129,13 +129,13 @@
try:
f.read()
except IOError as e:
- assert not e.errno
+ pass
else:
assert False
try:
f.readline()
except IOError as e:
- assert not e.errno
+ pass
else:
assert False
f.write("dupa\x00dupb")
@@ -143,9 +143,9 @@
for mode in ['r', 'U']:
f2 = open(fname, mode)
try:
- f2.write('')
+ f2.write('z')
except IOError as e:
- assert not e.errno
+ pass
else:
assert False
dupa = f2.read(0)
@@ -189,6 +189,29 @@
f()
self.interpret(f, [])
+ def test_read_universal(self):
+ fname = self.tmpdir.join('read_univ')
+ fname.write("dupa\ndupb\r\ndupc")
+ fname = str(fname)
+
+ def f():
+ f = open(fname, 'U')
+ assert f.read() == "dupa\ndupb\ndupc"
+ assert f.read() == ""
+ f.seek(0)
+ assert f.read(9) == "dupa\ndupb"
+ assert f.read(42) == "\ndupc"
+ assert f.read(1) == ""
+ f.seek(0)
+ assert f.readline() == "dupa\n"
+ assert f.readline() == "dupb\n"
+ assert f.readline() == "dupc"
+ assert f.readline() == ""
+ f.close()
+
+ f()
+ self.interpret(f, [])
+
def test_seek(self):
fname = str(self.tmpdir.join('file_4'))
@@ -230,7 +253,7 @@
try:
f2.read()
except IOError as e:
- assert not e.errno
+ pass
else:
assert False
f2.write("xxx")
@@ -303,7 +326,7 @@
try:
f.truncate()
except IOError as e:
- assert not e.errno
+ pass
else:
assert False
f.close()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit