Author: Brian Kearns <bdkea...@gmail.com> 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit