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

Reply via email to