3939/* BUFMAX determines how many bytes can be read in one go. */
4040#define BUFMAX (32*1024*1024)
4141
42+ /* SMALLBUF determines how many utf-8 characters will be
43+ buffered within the stream, in order to support reads
44+ of less than one character */
45+ #define SMALLBUF 4
46+
4247char _get_console_type (HANDLE handle ) {
4348 DWORD mode , peek_count ;
4449
@@ -125,7 +130,8 @@ typedef struct {
125130 unsigned int blksize ;
126131 PyObject * weakreflist ;
127132 PyObject * dict ;
128- char buf [4 ];
133+ char buf [SMALLBUF ];
134+ wchar_t wbuf ;
129135} winconsoleio ;
130136
131137PyTypeObject PyWindowsConsoleIO_Type ;
@@ -500,11 +506,11 @@ _io__WindowsConsoleIO_writable_impl(winconsoleio *self)
500506static DWORD
501507_buflen (winconsoleio * self )
502508{
503- for (DWORD i = 0 ; i < 4 ; ++ i ) {
509+ for (DWORD i = 0 ; i < SMALLBUF ; ++ i ) {
504510 if (!self -> buf [i ])
505511 return i ;
506512 }
507- return 4 ;
513+ return SMALLBUF ;
508514}
509515
510516static DWORD
@@ -513,12 +519,10 @@ _copyfrombuf(winconsoleio *self, char *buf, DWORD len)
513519 DWORD n = 0 ;
514520
515521 while (self -> buf [0 ] && len -- ) {
516- n += 1 ;
517- buf [0 ] = self -> buf [0 ];
518- self -> buf [0 ] = self -> buf [1 ];
519- self -> buf [1 ] = self -> buf [2 ];
520- self -> buf [2 ] = self -> buf [3 ];
521- self -> buf [3 ] = 0 ;
522+ buf [n ++ ] = self -> buf [0 ];
523+ for (int i = 1 ; i < SMALLBUF ; ++ i )
524+ self -> buf [i - 1 ] = self -> buf [i ];
525+ self -> buf [SMALLBUF - 1 ] = 0 ;
522526 }
523527
524528 return n ;
@@ -531,10 +535,13 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
531535 wchar_t * buf = (wchar_t * )PyMem_Malloc (maxlen * sizeof (wchar_t ));
532536 if (!buf )
533537 goto error ;
538+
534539 * readlen = 0 ;
535540
541+ //DebugBreak();
536542 Py_BEGIN_ALLOW_THREADS
537- for (DWORD off = 0 ; off < maxlen ; off += BUFSIZ ) {
543+ DWORD off = 0 ;
544+ while (off < maxlen ) {
538545 DWORD n , len = min (maxlen - off , BUFSIZ );
539546 SetLastError (0 );
540547 BOOL res = ReadConsoleW (handle , & buf [off ], len , & n , NULL );
@@ -550,7 +557,7 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
550557 err = 0 ;
551558 HANDLE hInterruptEvent = _PyOS_SigintEvent ();
552559 if (WaitForSingleObjectEx (hInterruptEvent , 100 , FALSE)
553- == WAIT_OBJECT_0 ) {
560+ == WAIT_OBJECT_0 ) {
554561 ResetEvent (hInterruptEvent );
555562 Py_BLOCK_THREADS
556563 sig = PyErr_CheckSignals ();
@@ -568,7 +575,30 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
568575 /* If the buffer ended with a newline, break out */
569576 if (buf [* readlen - 1 ] == '\n' )
570577 break ;
578+ /* If the buffer ends with a high surrogate, expand the
579+ buffer and read an extra character. */
580+ WORD char_type ;
581+ if (off + BUFSIZ >= maxlen &&
582+ GetStringTypeW (CT_CTYPE3 , & buf [* readlen - 1 ], 1 , & char_type ) &&
583+ char_type == C3_HIGHSURROGATE ) {
584+ wchar_t * newbuf ;
585+ maxlen += 1 ;
586+ Py_BLOCK_THREADS
587+ newbuf = (wchar_t * )PyMem_Realloc (buf , maxlen * sizeof (wchar_t ));
588+ Py_UNBLOCK_THREADS
589+ if (!newbuf ) {
590+ sig = -1 ;
591+ break ;
592+ }
593+ buf = newbuf ;
594+ /* Only advance by n and not BUFSIZ in this case */
595+ off += n ;
596+ continue ;
597+ }
598+
599+ off += BUFSIZ ;
571600 }
601+
572602 Py_END_ALLOW_THREADS
573603
574604 if (sig )
@@ -1110,4 +1140,6 @@ PyTypeObject PyWindowsConsoleIO_Type = {
11101140 0 , /* tp_finalize */
11111141};
11121142
1143+ PyAPI_DATA (PyObject * ) _PyWindowsConsoleIO_Type = (PyObject * )& PyWindowsConsoleIO_Type ;
1144+
11131145#endif /* MS_WINDOWS */
0 commit comments