@@ -309,6 +309,14 @@ curses_window_set_null_error(PyCursesWindowObject *win,
309309 _curses_set_null_error (state , curses_funcname , python_funcname );
310310}
311311
312+ /* ncurses and PDCurses store n characters and add a terminator; NetBSD
313+ curses counts the terminator in n. Ask an unknown library for one more. */
314+ #if defined(NCURSES_VERSION ) || defined(PDCURSES )
315+ # define CURSES_STR_EXTRA 0
316+ #else
317+ # define CURSES_STR_EXTRA 1
318+ #endif
319+
312320/* Utility Checking Procedures */
313321
314322/*
@@ -3826,25 +3834,33 @@ curses_window_instr_bytes(PyCursesWindowObject *self, int use_xy,
38263834 int rtn ;
38273835 unsigned int max_buf_size = 2048 ;
38283836
3829- n = Py_MIN (n , max_buf_size - 1 );
3837+ n = Py_MIN (n , max_buf_size - 1 - CURSES_STR_EXTRA );
3838+ n += CURSES_STR_EXTRA ;
38303839 PyBytesWriter * writer = PyBytesWriter_Create (n + 1 );
38313840 if (writer == NULL ) {
38323841 return NULL ;
38333842 }
38343843 char * buf = PyBytesWriter_GetData (writer );
38353844
3836- if (use_xy ) {
3837- rtn = mvwinnstr (self -> win , y , x , buf , n );
3838- }
3839- else {
3840- rtn = winnstr (self -> win , buf , n );
3845+ /* Read again if the library stored more than asked: truncating could
3846+ split a multibyte character. */
3847+ for (unsigned int want = n - CURSES_STR_EXTRA ; ; n = want ) {
3848+ if (use_xy ) {
3849+ rtn = mvwinnstr (self -> win , y , x , buf , n );
3850+ }
3851+ else {
3852+ rtn = winnstr (self -> win , buf , n );
3853+ }
3854+ if (rtn == ERR || (unsigned int )rtn <= want ) {
3855+ break ;
3856+ }
38413857 }
38423858
38433859 if (rtn == ERR ) {
38443860 PyBytesWriter_Discard (writer );
38453861 return Py_GetConstant (Py_CONSTANT_EMPTY_BYTES );
38463862 }
3847- return PyBytesWriter_FinishWithSize (writer , strlen ( buf ) );
3863+ return PyBytesWriter_FinishWithSize (writer , rtn );
38483864}
38493865
38503866/*[clinic input]
@@ -3992,17 +4008,25 @@ _curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_left_1,
39924008 int rtn ;
39934009 unsigned int max_buf_size = 2048 ;
39944010
3995- n = Py_MIN (n , max_buf_size - 1 );
4011+ n = Py_MIN (n , max_buf_size - 1 - CURSES_STR_EXTRA );
4012+ n += CURSES_STR_EXTRA ;
39964013 wchar_t * buf = PyMem_New (wchar_t , n + 1 );
39974014 if (buf == NULL ) {
39984015 return PyErr_NoMemory ();
39994016 }
40004017
4001- if (group_left_1 ) {
4002- rtn = mvwinnwstr (self -> win , y , x , buf , n );
4003- }
4004- else {
4005- rtn = winnwstr (self -> win , buf , n );
4018+ /* Read again if the library stored more than asked: truncating could
4019+ separate a combining character from its base. */
4020+ for (unsigned int want = n - CURSES_STR_EXTRA ; ; n = want ) {
4021+ if (group_left_1 ) {
4022+ rtn = mvwinnwstr (self -> win , y , x , buf , n );
4023+ }
4024+ else {
4025+ rtn = winnwstr (self -> win , buf , n );
4026+ }
4027+ if (rtn == ERR || (unsigned int )rtn <= want ) {
4028+ break ;
4029+ }
40064030 }
40074031
40084032 if (rtn == ERR ) {
@@ -4056,7 +4080,8 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1,
40564080 int rtn ;
40574081 unsigned int max_buf_size = 2048 ;
40584082
4059- n = Py_MIN (n , max_buf_size - 1 );
4083+ n = Py_MIN (n , max_buf_size - 1 - CURSES_STR_EXTRA );
4084+ n += CURSES_STR_EXTRA ;
40604085 cursesmodule_state * state = get_cursesmodule_state_by_win (self );
40614086 /* Zero the cells: reading a cell back through getcchar() relies on the
40624087 cchar_t text array being NUL-terminated, which some curses libraries
@@ -4079,6 +4104,7 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1,
40794104 return PyCursesComplexStr_New (state , NULL , 0 );
40804105 }
40814106
4107+ n -= CURSES_STR_EXTRA ;
40824108 /* win_wchnstr() stores at most n cells and zero-terminates the array at
40834109 the actual count; every real cell holds at least a space, so the first
40844110 empty cell marks the end of the run. */
@@ -4111,6 +4137,7 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1,
41114137 return PyCursesComplexStr_New (state , NULL , 0 );
41124138 }
41134139
4140+ n -= CURSES_STR_EXTRA ;
41144141 Py_ssize_t count = 0 ;
41154142 while (count < (Py_ssize_t )n && buf [count ] != 0 ) {
41164143 count ++ ;
0 commit comments