def read_console_wide(space, handle, maxlen): """ Make a blocking call to ReadConsoleW, returns wchar-encoded bytes """ err = 0 sig = 0 # Windows uses a 16-bit wchar_t, we mimic that with bytes buf = ByteBuffer((maxlen + 2) * 2) addr = buf.get_raw_address() off = 0 # offset from the beginning of buf, in wchar # readlen is in 16 bits, readlen_b is in 8-bit bytes readlen = readlen_b = 0 bufsize = BUFSIZ with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as n: while readlen_b < maxlen: neg_one = rffi.cast(rwin32.DWORD, -1) n[0] = neg_one length = min(maxlen - off, bufsize) rwin32.SetLastError_saved(0) res = rwin32.ReadConsoleW( handle, rffi.cast(rwin32.LPWSTR, rffi.ptradd(addr, readlen_b)), length, n, rffi.cast(rwin32.LPVOID, 0)) nread = intmask(n[0]) err = rwin32.GetLastError_saved() if not res: break if nread == -1 and err == rwin32.ERROR_OPERATION_ABORTED: break if nread == 0: if err != rwin32.ERROR_OPERATION_ABORTED: break err = 0 # This will only catch CTRL-C on the main thread sleep(space, space.newfloat(0.1)) continue readlen += nread readlen_b = 2 * readlen # We didn't manage to read the whole buffer # don't try again as it will just block if nread < length: break if buf.getitem(readlen_b - 2) == '\n': # We read a new line break # If the buffer ends with a high surrogate, take an extra character. if (readlen_b + 1) >= maxlen: with lltype.scoped_alloc(rwin32.LPWORD.TO, 1) as char_type: ptr = rffi.cast(rffi.CWCHARP, rffi.ptradd(addr, +1)) rwin32.GetStringTypeW(rwin32.CT_CTYPE3, ptr, 1, char_type) if intmask(char_type[0]) == intmask( rwin32.C3_HIGHSURROGATE): readlen_b += 2 break if err: raise OperationError(space.w_WindowsError, space.newint(err)) if readlen_b <= 0 or buf.getitem(0) == '\x1a': return '' else: return buf.getslice(0, 1, readlen_b)
def test_getslice_shortcut(self): buf = ByteBuffer(4) buf.setslice(0, b"data") buf.getitem = None assert buf.getslice(0, 2, 1, 2) == b"da" # no crash!