Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c6f9b2b

Browse files
committed
Issue #28162: Fixes Ctrl+Z handling in console readall()
1 parent ea200db commit c6f9b2b

2 files changed

Lines changed: 51 additions & 36 deletions

File tree

Lib/test/test_winconsoleio.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,15 @@ def test_partial_reads(self):
107107
source = 'ϼўТλФЙ\r\n'.encode('utf-16-le')
108108
expected = 'ϼўТλФЙ\r\n'.encode('utf-8')
109109
for read_count in range(1, 16):
110-
stdin = open('CONIN$', 'rb', buffering=0)
111-
write_input(stdin, source)
110+
with open('CONIN$', 'rb', buffering=0) as stdin:
111+
write_input(stdin, source)
112112

113-
actual = b''
114-
while not actual.endswith(b'\n'):
115-
b = stdin.read(read_count)
116-
actual += b
113+
actual = b''
114+
while not actual.endswith(b'\n'):
115+
b = stdin.read(read_count)
116+
actual += b
117117

118-
self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count))
119-
stdin.close()
118+
self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count))
120119

121120
def test_partial_surrogate_reads(self):
122121
# Test that reading less than 1 full character works when stdin
@@ -125,17 +124,24 @@ def test_partial_surrogate_reads(self):
125124
source = '\U00101FFF\U00101001\r\n'.encode('utf-16-le')
126125
expected = '\U00101FFF\U00101001\r\n'.encode('utf-8')
127126
for read_count in range(1, 16):
128-
stdin = open('CONIN$', 'rb', buffering=0)
129-
write_input(stdin, source)
127+
with open('CONIN$', 'rb', buffering=0) as stdin:
128+
write_input(stdin, source)
130129

131-
actual = b''
132-
while not actual.endswith(b'\n'):
133-
b = stdin.read(read_count)
134-
actual += b
130+
actual = b''
131+
while not actual.endswith(b'\n'):
132+
b = stdin.read(read_count)
133+
actual += b
135134

136-
self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count))
137-
stdin.close()
135+
self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count))
138136

137+
def test_ctrl_z(self):
138+
with open('CONIN$', 'rb', buffering=0) as stdin:
139+
source = '\xC4\x1A\r\n'.encode('utf-16-le')
140+
expected = '\xC4'.encode('utf-8')
141+
write_input(stdin, source)
142+
a, b = stdin.read(1), stdin.readall()
143+
self.assertEqual(expected[0:1], a)
144+
self.assertEqual(expected[1:], b)
139145

140146
if __name__ == "__main__":
141147
unittest.main()

Modules/_io/winconsoleio.c

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -816,44 +816,53 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self)
816816

817817
PyMem_Free(subbuf);
818818

819-
/* when the read starts with ^Z or is empty we break */
820-
if (n == 0 || buf[len] == '\x1a')
819+
/* when the read is empty we break */
820+
if (n == 0)
821821
break;
822822

823823
len += n;
824824
}
825825

826-
if (len == 0 || buf[0] == '\x1a' && _buflen(self) == 0) {
826+
if (len == 0 && _buflen(self) == 0) {
827827
/* when the result starts with ^Z we return an empty buffer */
828828
PyMem_Free(buf);
829829
return PyBytes_FromStringAndSize(NULL, 0);
830830
}
831831

832-
Py_BEGIN_ALLOW_THREADS
833-
bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len,
834-
NULL, 0, NULL, NULL);
835-
Py_END_ALLOW_THREADS
832+
if (len) {
833+
Py_BEGIN_ALLOW_THREADS
834+
bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len,
835+
NULL, 0, NULL, NULL);
836+
Py_END_ALLOW_THREADS
836837

837-
if (!bytes_size) {
838-
DWORD err = GetLastError();
839-
PyMem_Free(buf);
840-
return PyErr_SetFromWindowsErr(err);
838+
if (!bytes_size) {
839+
DWORD err = GetLastError();
840+
PyMem_Free(buf);
841+
return PyErr_SetFromWindowsErr(err);
842+
}
843+
} else {
844+
bytes_size = 0;
841845
}
842846

843847
bytes_size += _buflen(self);
844848
bytes = PyBytes_FromStringAndSize(NULL, bytes_size);
845849
rn = _copyfrombuf(self, PyBytes_AS_STRING(bytes), bytes_size);
846850

847-
Py_BEGIN_ALLOW_THREADS
848-
bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len,
849-
&PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL);
850-
Py_END_ALLOW_THREADS
851+
if (len) {
852+
Py_BEGIN_ALLOW_THREADS
853+
bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len,
854+
&PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL);
855+
Py_END_ALLOW_THREADS
851856

852-
if (!bytes_size) {
853-
DWORD err = GetLastError();
854-
PyMem_Free(buf);
855-
Py_CLEAR(bytes);
856-
return PyErr_SetFromWindowsErr(err);
857+
if (!bytes_size) {
858+
DWORD err = GetLastError();
859+
PyMem_Free(buf);
860+
Py_CLEAR(bytes);
861+
return PyErr_SetFromWindowsErr(err);
862+
}
863+
864+
/* add back the number of preserved bytes */
865+
bytes_size += rn;
857866
}
858867

859868
PyMem_Free(buf);

0 commit comments

Comments
 (0)