Author: Matti Picus <[email protected]>
Branch: winconsoleio
Changeset: r98394:d199a8198079
Date: 2019-12-25 17:33 +0200
http://bitbucket.org/pypy/pypy/changeset/d199a8198079/

Log:    add a test, but it hangs trying to read from stdio, even after
        copying cpython

diff --git a/lib_pypy/_testconsole.py b/lib_pypy/_testconsole.py
--- a/lib_pypy/_testconsole.py
+++ b/lib_pypy/_testconsole.py
@@ -6,33 +6,35 @@
 
 from _pypy_winbase_cffi import ffi as _ffi
 _kernel32 = _ffi.dlopen('kernel32')
+import _io
 
 def write_input(module, file, s):
     
-    if not file is _WindowsConsoleIO:
-        raise TypeError("expected raw console object")
-        
-    p = _ffi.new("wchar_t[]", s)
-    size = len(s) / _ffi.sizeof("wchar_t")
+    # if not file is _io._WindowsConsoleIO:
+    #    raise TypeError("expected raw console object")
+    # Assume it is OK, for untranslated tests
+    handle = getattr(file, 'handle', file)    
+    size = len(s)
     
-    rec = _ffi.new("INPUT_RECORD", size)
+    rec = _ffi.new("INPUT_RECORD[%s]" % size)
     
     if not rec:
         return None
         
     for i in range(0,size):
-        rec[i].EventType = KEY_EVENT
-        rec[i].Event.KeyEvent.bKeyDown = true
+        rec[i].EventType = 1  # KEY_EVENT
+        rec[i].Event.KeyEvent.bKeyDown = True
         rec[i].Event.KeyEvent.wRepeatCount = 10
-        rec[i].Event.KeyEvent.uChar.UnicodeChar = p[i]
+        rec[i].Event.KeyEvent.uChar.UnicodeChar = s[i]
     
-    handle = file.handle
-    total = _ffi.new("DWORD", 0)
-    wrote = _ffi.new("DWORD", 0)
+    total = 0
+    wrote = _ffi.new("DWORD[1]")
+    phandle = _ffi.cast('void*', handle)
     while total < size:
-        if not _kernel32.WriteConsoleInputW(handle, rec[total[0]], size - 
total[0], wrote):
+        if not _kernel32.WriteConsoleInputW(phandle, rec + total, size - 
total, wrote):
             _winapi.SetFromWindowsErr(0)
-        total[0] += wrote[0]
+        print 'wrote', wrote[0], 'of', size-total
+        total += wrote[0]
 
 def read_output(module, file):
     return None
diff --git a/pypy/module/_io/interp_win32consoleio.py 
b/pypy/module/_io/interp_win32consoleio.py
--- a/pypy/module/_io/interp_win32consoleio.py
+++ b/pypy/module/_io/interp_win32consoleio.py
@@ -13,90 +13,88 @@
 from rpython.rlib import rwin32
 from rpython.rlib.runicode import WideCharToMultiByte, MultiByteToWideChar
 from rpython.rlib.rwin32file import make_win32_traits
+from rpython.rlib.buffer import ByteBuffer
 
 from rpython.rtyper.tool import rffi_platform as platform
 
 import unicodedata
 
+# SMALLBUF determines how many utf-8 characters will be
+# buffered within the stream, in order to support reads
+# of less than one character
 SMALLBUF = 4
+# BUFMAX determines how many bytes can be read in one go.
 BUFMAX = (32*1024*1024)
 BUFSIZ = platform.ConstantInteger("BUFSIZ")
 
 def err_closed(space):
-    raise oefmt(space.w_ValueError,
+    return oefmt(space.w_ValueError,
                 "I/O operation on closed file")
 
 def err_mode(space, state):
     # TODO sort out the state
-    raise oefmt(space.w_ValueError,
+    return oefmt(space.w_ValueError,
                 "I/O operation on closed file")
 
-def read_console_w(space, handle, maxlen, readlen):
+def read_console_wide(space, handle, maxlen):
+    """ 
+    Make a blocking call to ReadConsoleW
+    """
     err = 0
     sig = 0
-    buf = lltype.malloc(rffi.CWCHARP, maxlen, flavor='raw')
-
-    try:
-        if not buf:
-            return None
+    buf = ByteBuffer(maxlen + 1)
+    addr = buf.get_raw_address()
+    off = 0
+    readlen = 0
+    while off < maxlen:
+        with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as n:
+            neg_one = rffi.cast(rwin32.DWORD, -1)
+            n[0] = neg_one
+            len = min(maxlen - off, BUFSIZ)
+            rwin32.SetLastError_saved(0)
+            res = rwin32.ReadConsoleW(handle,
+                             rffi.cast(rwin32.LPVOID, rffi.ptradd(addr, off)),
+                             len, n, rffi.NULL)
+            err = rwin32.GetLastError_saved()
+            if not res:
+                break
+                
+            if n[0] == neg_one and err == rwin32.ERROR_OPERATION_ABORTED:
+                break
+                
+            if n[0] == 0:
+                if err != rwin32.ERROR_OPERATION_ABORTED:
+                    break
+                err = 0
+                hInterruptEvent = sigintevent()
+                if rwin32.WaitForSingleObject(hInterruptEvent, 100) == 
rwin32.WAIT_OBJECT_0:
+                    rwin32.ResetEvent(hInterruptEvent)
+                    space.getexecutioncontext().checksignals()
+            readlen += n[0]
+            
+            # We didn't manage to read the whole buffer
+            # don't try again as it will just block
+            if n[0] < len:
+                break
+                
+            # We read a new line
+            if buf[readlen -1] == u'\n':
+                break
+            
+            with lltype.scoped_alloc(rwin32.LPWORD.TO, 1) as char_type:
+                if off + BUFSIZ >= maxlen and \
+                    rwin32.GetStringTypeW(rwin32.CT_CTYPE3, buf[readlen - 1], 
1, char_type) and \
+                    char_type == rwin32.C3_HIGHSURROGATE:
+                    maxlen += 1
+                    off += n[0]
+                    continue
+                off += BUFSIZ
+    if err:
+        return None
         
-        off = 0
-        while off < maxlen:
-            with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as n:
-                n[0] = -1
-                len = min(maxlen - off, BUFSIZ)
-                rwin32.SetLastError_saved(0)
-                res = rwin32.ReadConsoleW(handle, buf[off], len, n, rffi.NULL)
-                err = rwin32.GetLastError_saved()
-                if not res:
-                    break
-                    
-                if n[0] == -1 and err == rwin32.ERROR_OPERATION_ABORTED:
-                    break
-                    
-                if n[0] == 0:
-                    if err != rwin32.ERROR_OPERATION_ABORTED:
-                        break
-                    err = 0
-                    hInterruptEvent = sigintevent()
-                    if rwin32.WaitForSingleObject(hInterruptEvent, 100) == 
rwin32.WAIT_OBJECT_0:
-                        rwin32.ResetEvent(hInterruptEvent)
-                        space.getexecutioncontext().checksignals()
-                
-                readlen += n[0]
-                
-                # We didn't manage to read the whole buffer
-                # don't try again as it will just block
-                if n[0] < len:
-                    break
-                    
-                # We read a new line
-                if buf[readlen -1] == u'\n':
-                    break
-                
-                with lltype.scoped_alloc(rwin32.LPWORD.TO, 1) as char_type:
-                    if off + BUFSIZ >= maxlen and \
-                        rwin32.GetStringTypeW(rwin32.CT_CTYPE3, buf[readlen - 
1], 1, char_type) and \
-                        char_type == rwin32.C3_HIGHSURROGATE:
-                        maxlen += 1
-                        newbuf = lltype.malloc(rffi.CWCHARP, maxlen, 
flavor='raw')
-                        lltype.free(buf, flavor='raw')
-                        buf = newbuf
-                        off += n[0]
-                        continue
-                    off += BUFSIZ
-        if err:
-            lltype.free(buf, flavor='raw')
-            return None
-            
-        if readlen > 0 and buf[0] == u'\x1a':
-            lltype.free(buf, flavor='raw')
-            buf = lltype.malloc(rffi.CWCHARP, 1, flavor='raw')
-            buf[0] = '\0'
-            readlen = 0
-        return buf
-    except:
-        lltype.free(buf, flavor='raw')
+    if readlen > 0 and buf[0] == u'\x1a':
+        readlen = 0
+    return buf.getslice(0, readlen, 1, readlen)
 
 
 def _get_console_type(handle):
@@ -166,21 +164,27 @@
         self.writable = False
         self.closehandle = False
         self.blksize = 0
+        self.buf = None
+
+    def _dealloc_warn_w(self, space, w_source):
+        buf = self.buf
+        if buf:
+            lltype.free(buf, flavor='raw')
         
-    def _copyfrombuf(self, buf, len):
+    def _copyfrombuf(self, buf, lgt):
         n = 0
-        while self.buf[0] and len:
+        while self.buf[0] != '\x00' and lgt > 0:
             buf[n] = self.buf[0]
             for i in range(1, SMALLBUF):
                 self.buf[i-1] = self.buf[i]
             self.buf[SMALLBUF-1] = rffi.cast(lltype.Char, 0)
-            len -= 1
+            lgt -= 1
             n += 1
         return n
         
     def _buflen(self):
         for i in range(len(SMALLBUF)):
-            if not self.buf[i]:
+            if self.buf[i] != '\x00':
                 return i
         return SMALLBUF
 
@@ -194,124 +198,120 @@
         self.blksize = 0
         rwa = False
         console_type = '\0'
-        self.buf = lltype.malloc(rffi.CCHARP.TO, SMALLBUF, flavor='raw')
+        self.buf = lltype.malloc(rffi.CCHARP.TO, SMALLBUF, flavor='raw', 
zero=True)
 
-        try:
-            if space.isinstance_w(w_nameobj, space.w_int): 
-                self.fd = space.int_w(w_nameobj)
-                if self.fd < 0:
+        if space.isinstance_w(w_nameobj, space.w_int): 
+            self.fd = space.int_w(w_nameobj)
+            if self.fd < 0:
+                raise oefmt(space.w_ValueError,
+                        "negative file descriptor")
+
+        # make the flow analysis happy,otherwise it thinks w_path
+        # is undefined later
+        w_path = w_nameobj
+        if self.fd < 0:
+            from pypy.module.posix.interp_posix import fspath
+            w_path = fspath(space, w_nameobj)
+            console_type = _pyio_get_console_type(space, w_path)
+            if not console_type:
+                raise oefmt(space.w_ValueError,
+                        "Invalid console type")
+            if console_type == '\0':
+                raise oefmt(space.w_ValueError,
+                        "Cannot open non-console file")
+        
+        for char in mode:
+            if char in "+abx":
+                # OK do nothing
+                pass
+            elif char == "r":
+                if rwa:
                     raise oefmt(space.w_ValueError,
-                            "negative file descriptor")
-
-            # make the flow analysis happy,otherwise it thinks w_path
-            # is undefined later
-            w_path = w_nameobj
-            if self.fd < 0:
-                from pypy.module.posix.interp_posix import fspath
-                w_path = fspath(space, w_nameobj)
-                console_type = _pyio_get_console_type(space, w_path)
-                if not console_type:
+                            "invalid mode: %s", mode)
+                rwa = True
+                self.readable = True
+                if console_type == "x":
+                    console_type = "r"
+            elif char == "w":
+                if rwa:
                     raise oefmt(space.w_ValueError,
-                            "Invalid console type")
-                if console_type == '\0':
-                    raise oefmt(space.w_ValueError,
-                            "Cannot open non-console file")
+                            "invalid mode: %s", mode)
+                rwa = True
+                self.writable = True
+                if console_type == 'x':
+                    console_type = 'w'
+            else:
+                raise oefmt(space.w_ValueError,
+                            "invalid mode: %s", mode)
+        if not rwa:
+            raise oefmt(space.w_ValueError,
+                        "Must have exactly one of read or write mode")
+        
+        if self.fd >= 0:
+            self.handle = rwin32.get_osfhandle(self.fd)
+            self.closehandle = False
+        else:
+            access = rwin32.GENERIC_READ
+            self.closehandle = True
+            if not closefd:
+                raise oefmt(space.w_ValueError,
+                        "Cannot use closefd=False with a file name")
+            if self.writable:
+                access = rwin32.GENERIC_WRITE
+        
+            traits = _preferred_traits(space.realunicode_w(w_path))
+            if not (traits.str is unicode):
+                raise oefmt(space.w_ValueError,
+                            "Non-unicode string name %s", traits.str)
+            win32traits = make_win32_traits(traits)
             
-            for char in mode:
-                if char in "+abx":
-                    # OK do nothing
-                    pass
-                elif char == "r":
-                    if rwa:
-                        raise oefmt(space.w_ValueError,
-                                "invalid mode: %s", mode)
-                    rwa = True
-                    self.readable = True
-                    if console_type == "x":
-                        console_type = "r"
-                elif char == "w":
-                    if rwa:
-                        raise oefmt(space.w_ValueError,
-                                "invalid mode: %s", mode)
-                    rwa = True
-                    self.writable = True
-                    if console_type == 'x':
-                        console_type = 'w'
-                else:
-                    raise oefmt(space.w_ValueError,
-                                "invalid mode: %s", mode)
-            if not rwa:
-                raise oefmt(space.w_ValueError,
-                            "Must have exactly one of read or write mode")
-            
-            if self.fd >= 0:
-                self.handle = rwin32.get_osfhandle(self.fd)
-                self.closehandle = False
-            else:
-                access = rwin32.GENERIC_READ
-                self.closehandle = True
-                if not closefd:
-                    raise oefmt(space.w_ValueError,
-                            "Cannot use closefd=False with a file name")
-                if self.writable:
-                    access = rwin32.GENERIC_WRITE
-            
-                traits = _preferred_traits(space.realunicode_w(w_path))
-                if not (traits.str is unicode):
-                    raise oefmt(space.w_ValueError,
-                                "Non-unicode string name %s", traits.str)
-                win32traits = make_win32_traits(traits)
-                
-                pathlen = space.len_w(w_path)
-                name = rffi.utf82wcharp(space.utf8_w(w_path), pathlen)
+            pathlen = space.len_w(w_path)
+            name = rffi.utf82wcharp(space.utf8_w(w_path), pathlen)
+            self.handle = win32traits.CreateFile(name, 
+                rwin32.GENERIC_READ | rwin32.GENERIC_WRITE,
+                rwin32.FILE_SHARE_READ | rwin32.FILE_SHARE_WRITE,
+                rffi.NULL, win32traits.OPEN_EXISTING, 0, rffi.NULL)
+            if self.handle == rwin32.INVALID_HANDLE_VALUE:
                 self.handle = win32traits.CreateFile(name, 
-                    rwin32.GENERIC_READ | rwin32.GENERIC_WRITE,
+                    access,
                     rwin32.FILE_SHARE_READ | rwin32.FILE_SHARE_WRITE,
                     rffi.NULL, win32traits.OPEN_EXISTING, 0, rffi.NULL)
-                if self.handle == rwin32.INVALID_HANDLE_VALUE:
-                    self.handle = win32traits.CreateFile(name, 
-                        access,
-                        rwin32.FILE_SHARE_READ | rwin32.FILE_SHARE_WRITE,
-                        rffi.NULL, win32traits.OPEN_EXISTING, 0, rffi.NULL)
-                lltype.free(name, flavor='raw')
-                
-                if self.handle == rwin32.INVALID_HANDLE_VALUE:
-                    raise WindowsError(rwin32.GetLastError_saved(),
-                                       "Failed to open handle")
+            lltype.free(name, flavor='raw')
             
-            if console_type == '\0':
-                console_type = _get_console_type(self.handle)
+            if self.handle == rwin32.INVALID_HANDLE_VALUE:
+                raise WindowsError(rwin32.GetLastError_saved(),
+                                   "Failed to open handle")
+        
+        if console_type == '\0':
+            console_type = _get_console_type(self.handle)
 
-            if console_type == '\0': 
-                raise oefmt(space.w_ValueError,
-                            "Cannot open non-console file")
-            
-            if self.writable and console_type != 'w':
-                raise oefmt(space.w_ValueError,
-                            "Cannot open input buffer for writing")
+        if console_type == '\0': 
+            raise oefmt(space.w_ValueError,
+                        "Cannot open non-console file")
+        
+        if self.writable and console_type != 'w':
+            raise oefmt(space.w_ValueError,
+                        "Cannot open input buffer for writing")
 
-            if self.readable and console_type != 'r':
-                raise oefmt(space.w_ValueError,
-                            "Cannot open output buffer for reading")
+        if self.readable and console_type != 'r':
+            raise oefmt(space.w_ValueError,
+                        "Cannot open output buffer for reading")
 
-            self.blksize = DEFAULT_BUFFER_SIZE
-            rffi.c_memset(self.buf, 0, SMALLBUF)
-        finally:
-           lltype.free(self.buf, flavor='raw')
+        self.blksize = DEFAULT_BUFFER_SIZE
     
     def readable_w(self, space):
         if self.handle == rwin32.INVALID_HANDLE_VALUE:
-            return err_closed(space)
+            raise err_closed(space)
         return space.newbool(self.readable)
     
     def writable_w(self, space):
         if self.handle == rwin32.INVALID_HANDLE_VALUE:
-            return err_closed(space)
+            raise err_closed(space)
         return space.newbool(self.writable)
     
     def isatty_w(self, space):
         if self.handle == rwin32.INVALID_HANDLE_VALUE:
-            return err_closed(space)
+            raise err_closed(space)
         return space.newbool(True)
     
     def repr_w(self, space):
@@ -335,90 +335,93 @@
             else:
                 self.fd = rwin32.open_osfhandle(rffi.cast(rffi.INTP, 
self.handle), win32traits._O_RDONLY | win32traits._O_BINARY)
         if self.fd < 0:
-            return err_mode(space, "fileno")
+            raise err_mode(space, "fileno")
         return space.newint(self.fd)
         
     def readinto_w(self, space, w_buffer):
         rwbuffer = space.writebuf_w(w_buffer)
         length = rwbuffer.getlength()
+        return space.newint(self.readinto(space, rwbuffer, length))
+
+    def readinto(self, space, rwbuffer, length):
         
         if self.handle == rwin32.INVALID_HANDLE_VALUE:
-            return err_closed(space)
+            raise err_closed(space)
             
         if not self.readable:
-            err_mode(space, "reading")
+            raise err_mode(space, "reading")
             
         if not length:
-            return space.newint(0)
+            return 0
             
         if length > BUFMAX:
             raise oefmt(space.w_ValueError,
                         "cannot read more than %d bytes", BUFMAX)
                         
-        wlen = rffi.cast(rwin32.DWORD, length / 4)
-        if not wlen:
+        wlen = length / 4
+        if wlen < 1:
             wlen = 1
             
-        read_len = self._copyfrombuf(rwbuffer, rffi.cast(rwin32.DWORD, length))
-        if read_len:
-            rwbuffer.setslice(read_len, length)
+        read_len = self._copyfrombuf(rwbuffer, length)
+        if read_len > 0:
+            rwbuffer.delslice(read_len, rwbuffer.length())
             length = length - read_len
             wlen = wlen - 1
             
-        if length == read_len or not wlen:
-            return space.newint(read_len)
+        if length == read_len or wlen < 1:
+            return read_len
             
-        with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as n:
-            wbuf = read_console_w(space, self.handle, wlen , n)
+        wbuf = read_console_wide(space, self.handle, wlen)
             
-            if not wbuf:
-                return space.newint(-1)
-                
-            if n[0] == 0:
-                return space.newint(read_len)
-                
+        if not wbuf:
+            return -1
+        n = len(wbuf)
+        if len(wbuf) == 0: 
+            return read_len
+            
+        u8n = 0
+               
+        if length < 4:
+            if WideCharToMultiByte(rwin32.CP_UTF8,
+                                       0, wbuf, n, self.buf,
+                                       rffi.sizeof(self.buf)/ 
rffi.sizeof(self.buf[0]),
+                                       rffi.NULL, rffi.NULL):
+                u8n = self._copyfrombuf(rwbuffer, length)
+            else:
+                addr = rwbuffer.get_raw_address()
+                u8n = WideCharToMultiByte(rwin32.CP_UTF8,
+                                                0, wbuf, n, self.buf, length,
+                                                rffi.NULL, rffi.NULL)
+                                                
+        if u8n:
+            read_len += u8n
             u8n = 0
-               
-            if len < 4:
-                if WideCharToMultiByte(rwin32.CP_UTF8,
-                                           0, wbuf, n[0], self.buf,
-                                           rffi.sizeof(self.buf)/ 
rffi.sizeof(self.buf[0]),
-                                           rffi.NULL, rffi.NULL):
-                    u8n = self._copyfrombuf(rwbuffer, len)
-                else:
-                    u8n = WideCharToMultiByte(rwin32.CP_UTF8,
-                                                    0, wbuf, n[0], buf, len,
-                                                    rffi.NULL, rffi.NULL)
-                                                    
-            if u8n:
-                read_len += u8n
-                u8n = 0
-            else:
-                err = rwin32.GetLastError_saved()
-                if err == rwin32.ERROR_INSUFFICIENT_BUFFER:
-                    u8n = WideCharToMultiByte(rwin32.CP_UTF8, 0, wbuf,
-                                                     n, rffi.NULL, 0, 
rffi.NULL, rffi.NULL)
-                
-            if u8n:
-                raise oefmt(space.w_ValueError,
-                        "Buffer had room for %d bytes but %d bytes required",
-                        len, u8n)
-                        
-            if err:
-                raise oefmt(space.w_WindowsError,
-                        err)
+        else:
+            err = rwin32.GetLastError_saved()
+            if err == rwin32.ERROR_INSUFFICIENT_BUFFER:
+                u8n = WideCharToMultiByte(rwin32.CP_UTF8, 0, wbuf,
+                                                 n, rffi.NULL, 0, rffi.NULL, 
rffi.NULL)
             
-            if len < 0:
-                return None
-            
-            return space.newint(read_len)
+        if u8n:
+            raise oefmt(space.w_ValueError,
+                    "Buffer had room for %d bytes but %d bytes required",
+                    length, u8n)
+                    
+        if err:
+            raise oefmt(space.w_WindowsError,
+                    err)
+        
+        if length < 0:
+            return -1
+        
+        return read_len
             
     def read_w(self, space, w_size=None):
         size = convert_size(space, w_size)
         if self.handle == rwin32.INVALID_HANDLE_VALUE:
-            err_closed(space)
+            raise err_closed(space)
         if not self.readable:
-            return err_mode(space,"reading")
+            raise err_mode(space,"reading")
 
         if size < 0:
             return self.readall_w(space)
@@ -428,31 +431,30 @@
                         "Cannot read more than %d bytes",
                         BUFMAX)
 
-        w_buffer = space.call_function(space.w_bytearray, w_size)
-        w_bytes_size = self.readinto_w(space, w_buffer)
-        if w_bytes_size < 0:
-            return None
-        space.delslice(w_buffer, w_bytes_size, space.len(w_buffer))
-        
-        return space.w_bytes(w_buffer)
+        with lltype.scoped_alloc(rffi.CCHARP.TO, size) as buf:
+            bytes_read = self.readinto(space, buf, size)
+            if bytes_read < 0:
+                return space.newbytes('')
+            ret_str = space.charp2str(buf)
+            return space.newbytes(ret_str)
 
     def readall_w(self, space):
         if self.handle == rwin32.INVALID_HANDLE_VALUE:
-            err_closed(space)
+            raise err_closed(space)
 
         bufsize = BUFSIZ
         buf = lltype.malloc(rffi.CWCHARP.TO, bufsize + 1, flavor='raw')
-        len = 0
+        length = 0
         n = lltype.malloc(rwin32.LPDWORD.TO, 1, flavor='raw')
         n[0] = 0
 
         try:
             # Read the bytes from the console
             while True:
-                if len >= bufsize:
-                    if len > BUFMAX:
+                if length >= bufsize:
+                    if length > BUFMAX:
                         break
-                    newsize = len
+                    newsize = length
                     if newsize < bufsize:
                         raise oefmt(space.w_OverflowError,
                                     "unbounded read returned more bytes "
@@ -460,25 +462,24 @@
                     bufsize = newsize
                     lltype.free(buf, flavor='raw')
                     buf = lltype.malloc(rffi.CWCHARP.TO, bufsize + 1, 
flavor='raw')
-                    subbuf = read_console_w(self.handle, bufsize - len, n)
+                    subbuf = read_console_wide(space, self.handle, bufsize - 
length)
                     
-                    if n > 0:
-                        rwin32.wcsncpy_s(buf[len], bufsize - len +1, subbuf, n)
+                    if len(subbuf) > 0:
+                        rwin32.wcsncpy_s(buf[length], bufsize - length +1, 
subbuf, n)
+                        if n[0] == 0:
+                            break
+                    else:
+                        break 
+                        
+                    length += n
                     
-                    lltype.free(subbuf, flavor='raw')
-                    
-                    if n == 0:
-                        break
-                        
-                    len += n
-                    
-            if len == 0 and self._buflen() == 0:
+            if length == 0 and self._buflen() == 0:
                 return None
             
             # Compute the size for the destination buffer
-            if len:
+            if length:
                 bytes_size = WideCharToMultiByte(rwin32.CP_UTF8, 0, buf,
-                                     len, rffi.NULL, 0, rffi.NULL, rffi.NULL)
+                                     length, rffi.NULL, 0, rffi.NULL, 
rffi.NULL)
                  
                 if bytes_size:
                     err = rwin32.GetLastError_saved()
@@ -488,23 +489,22 @@
             bytes_size += self._buflen()
             
             # Create destination buffer and convert the bytes
-            bytes = lltype.malloc(rffi.CCHARP.TO, bytes_size, flavor='raw')
-            rn = self._copyfrombuf(bytes, bytes_size)
+            with lltype.scoped_alloc(rffi.CCHARP.TO, bytes_size) as ret_bytes:
+                rn = self._copyfrombuf(ret_bytes, bytes_size)
             
-            if len:
-                bytes_size = WideCharToMultiByte(rwin32.CP_UTF8, 0, buf, len,
-                             bytes[rn], bytes_size - rn, rffi.NULL, rffi.NULL)
+                if length:
+                    bytes_size = WideCharToMultiByte(rwin32.CP_UTF8, 0, buf, 
length,
+                             ret_bytes[rn], bytes_size - rn, rffi.NULL, 
rffi.NULL)
                              
-                if not bytes_size:
-                    lltype.free(bytes, flavor='raw')
-                    err = rwin32.GetLastError_saved()
-                    raise WindowsError(err, "Failed to convert wide characters 
to multi byte string")
+                    if not bytes_size:
+                        err = rwin32.GetLastError_saved()
+                        raise WindowsError(err,
+                             "Failed to convert wide characters to multi byte 
string")
                     
-                bytes_size += rn
+                    bytes_size += rn
             
-            lltype.free(bytes, flavor='raw')
-            w_bytes = space.charp2str(bytes)
-            return space.newbytes(w_bytes)
+                ret_str = space.charp2str(bytes)
+                return space.newbytes(ret_str)
             
         finally:
             lltype.free(buf, flavor='raw')
@@ -515,10 +515,10 @@
         with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as n:
         
             if self.handle == rwin32.INVALID_HANDLE_VALUE:
-                return err_closed(space)
+                raise err_closed(space)
             
             if not self.writable:
-                return err_mode(space,"writing")
+                raise err_mode(space,"writing")
             
             if not len(buffer):
                 return space.newint(0)
@@ -578,7 +578,7 @@
     read     = interp2app(W_WinConsoleIO.read_w),
     readall  = interp2app(W_WinConsoleIO.readall_w),
     readinto = interp2app(W_WinConsoleIO.readinto_w),    
-    fileno = interp2app(W_WinConsoleIO.fileno_w),
-    write = interp2app(W_WinConsoleIO.write_w),   
+    fileno   = interp2app(W_WinConsoleIO.fileno_w),
+    write    = interp2app(W_WinConsoleIO.write_w),   
     _blksize = GetSetProperty(W_WinConsoleIO.get_blksize),
     )
diff --git a/pypy/module/_io/test/test_win32consoleio.py 
b/pypy/module/_io/test/test_win32consoleio.py
--- a/pypy/module/_io/test/test_win32consoleio.py
+++ b/pypy/module/_io/test/test_win32consoleio.py
@@ -1,18 +1,39 @@
 from rpython.tool.udir import udir
+from pypy.interpreter.gateway import interp2app
 from pypy.module._io import interp_win32consoleio
+from pypy.conftest import option
+from rpython.rtyper.lltypesystem import rffi
 import os
 
+if os.name != 'nt':
+    import pytest
+    pytest.skip('Windows only tests')
+
+try:
+    import _testconsole
+except ImportError:
+    from lib_pypy import _testconsole
+
 class AppTestWinConsoleIO:
-    spaceconfig = dict(usemodules=['_io'])
+    spaceconfig = dict(usemodules=['_io', '_cffi_backend'])
 
-    def setup_method(self, meth):
+    def setup_class(cls):
         tmpfile = udir.join('tmpfile')
         tmpfile.write("a\nb\nc", mode='wb')
-        self.w_tmpfile = self.space.wrap(str(tmpfile))   
-        self.w_posix = self.space.appexec([], """():
+        cls.w_tmpfile = cls.space.wrap(str(tmpfile))   
+        cls.w_posix = cls.space.appexec([], """():
             import %s as m;
-            return m""" % os.name)        
-        self.w_conout_path = self.space.wrap(str(udir.join('CONOUT$')))
+            return m""" % os.name)
+        cls.w_conout_path = cls.space.wrap(str(udir.join('CONOUT$')))
+        if option.runappdirect:
+            cls.w_write_input = _testconsole.write_input
+        else:
+            def cls_write_input(space, w_module, w_console, w_s):
+                module = space.unwrap(w_module)
+                handle = rffi.cast(rffi.INT_real, w_console.handle)
+                s = space.utf8_w(w_s).decode('utf-8')
+                return space.wrap(_testconsole.write_input(module, handle, s))
+            cls.w_write_input = cls.space.wrap(interp2app(cls_write_input))
 
     def test_open_fd(self):
         import _io
@@ -110,6 +131,22 @@
         with _io._WindowsConsoleIO('CONOUT$', 'w') as f:
             assert f.write(b'') == 0
             
+    def test_partial_reads(self):
+        import _io
+        source = b'abcedfg'
+        actual = b''
+        with open('CONIN$', 'rb', buffering=0) as stdin:
+            self.write_input(None, stdin, source)
+            while not actual.endswith(b'\n'):
+                b = stdin.read(len(source))
+                print('read', b)
+                if not b:
+                    break
+                actual += b
+
+        assert actual == source
+
+
             
 class TestGetConsoleType:
     def test_conout(self, space):
@@ -135,4 +172,4 @@
     def test_con2(self, space):
         w_file = space.newtext('\\\\?\\con')
         consoletype = interp_win32consoleio._pyio_get_console_type(space, 
w_file)
-        assert consoletype == 'x'
\ No newline at end of file
+        assert consoletype == 'x'
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to