39
39
/* BUFMAX determines how many bytes can be read in one go. */
40
40
#define BUFMAX (32*1024*1024)
41
41
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
+
42
47
char _get_console_type (HANDLE handle ) {
43
48
DWORD mode , peek_count ;
44
49
@@ -125,7 +130,8 @@ typedef struct {
125
130
unsigned int blksize ;
126
131
PyObject * weakreflist ;
127
132
PyObject * dict ;
128
- char buf [4 ];
133
+ char buf [SMALLBUF ];
134
+ wchar_t wbuf ;
129
135
} winconsoleio ;
130
136
131
137
PyTypeObject PyWindowsConsoleIO_Type ;
@@ -500,11 +506,11 @@ _io__WindowsConsoleIO_writable_impl(winconsoleio *self)
500
506
static DWORD
501
507
_buflen (winconsoleio * self )
502
508
{
503
- for (DWORD i = 0 ; i < 4 ; ++ i ) {
509
+ for (DWORD i = 0 ; i < SMALLBUF ; ++ i ) {
504
510
if (!self -> buf [i ])
505
511
return i ;
506
512
}
507
- return 4 ;
513
+ return SMALLBUF ;
508
514
}
509
515
510
516
static DWORD
@@ -513,12 +519,10 @@ _copyfrombuf(winconsoleio *self, char *buf, DWORD len)
513
519
DWORD n = 0 ;
514
520
515
521
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 ;
522
526
}
523
527
524
528
return n ;
@@ -531,10 +535,13 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
531
535
wchar_t * buf = (wchar_t * )PyMem_Malloc (maxlen * sizeof (wchar_t ));
532
536
if (!buf )
533
537
goto error ;
538
+
534
539
* readlen = 0 ;
535
540
541
+ //DebugBreak();
536
542
Py_BEGIN_ALLOW_THREADS
537
- for (DWORD off = 0 ; off < maxlen ; off += BUFSIZ ) {
543
+ DWORD off = 0 ;
544
+ while (off < maxlen ) {
538
545
DWORD n , len = min (maxlen - off , BUFSIZ );
539
546
SetLastError (0 );
540
547
BOOL res = ReadConsoleW (handle , & buf [off ], len , & n , NULL );
@@ -550,7 +557,7 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
550
557
err = 0 ;
551
558
HANDLE hInterruptEvent = _PyOS_SigintEvent ();
552
559
if (WaitForSingleObjectEx (hInterruptEvent , 100 , FALSE)
553
- == WAIT_OBJECT_0 ) {
560
+ == WAIT_OBJECT_0 ) {
554
561
ResetEvent (hInterruptEvent );
555
562
Py_BLOCK_THREADS
556
563
sig = PyErr_CheckSignals ();
@@ -568,7 +575,30 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
568
575
/* If the buffer ended with a newline, break out */
569
576
if (buf [* readlen - 1 ] == '\n' )
570
577
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 ;
571
600
}
601
+
572
602
Py_END_ALLOW_THREADS
573
603
574
604
if (sig )
@@ -1110,4 +1140,6 @@ PyTypeObject PyWindowsConsoleIO_Type = {
1110
1140
0 , /* tp_finalize */
1111
1141
};
1112
1142
1143
+ PyAPI_DATA (PyObject * ) _PyWindowsConsoleIO_Type = (PyObject * )& PyWindowsConsoleIO_Type ;
1144
+
1113
1145
#endif /* MS_WINDOWS */
0 commit comments