gh-153862: Fix curses window.inch() for non-ASCII characters on a wide build#153863
Open
serhiy-storchaka wants to merge 2 commits into
Open
gh-153862: Fix curses window.inch() for non-ASCII characters on a wide build#153863serhiy-storchaka wants to merge 2 commits into
serhiy-storchaka wants to merge 2 commits into
Conversation
… a wide build
On a wide build, winch() returns the low 8 bits of the character's code
point with no locale conversion, so inch()/mvinch() disagreed with instr()
for a non-ASCII character of an 8-bit locale ('€' under ISO-8859-15 gave
0xAC instead of 0xA4). Re-encode the cell to its locale byte via wctob(),
as ncurses does for getbkgd().
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Documentation build overview
|
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
vstinner
approved these changes
Jul 18, 2026
| if (curses_getcchar(cell, wstr, &attrs, &pair) == ERR | ||
| || wstr[0] == L'\0' || wstr[1] != L'\0') | ||
| { | ||
| return rtn; |
Member
There was a problem hiding this comment.
You may report the error to the caller. Something like:
Details
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index 1e874d65bfc..e9d8bbbc5d0 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -779,7 +779,8 @@ curses_getcchar(const cchar_t *wcval, wchar_t *wstr, attr_t *attrs, int *pair)
when the character maps to exactly one byte, keeping the attribute and color
bits in RTN. A character with no single-byte form is left to winch(). */
static chtype
-curses_cell_locale_byte(chtype rtn, const cchar_t *cell)
+curses_cell_locale_byte(PyCursesWindowObject *self, chtype rtn,
+ const cchar_t *cell, const char *funcname)
{
wchar_t wstr[CCHARW_MAX + 1];
attr_t attrs;
@@ -787,13 +788,15 @@ curses_cell_locale_byte(chtype rtn, const cchar_t *cell)
if (curses_getcchar(cell, wstr, &attrs, &pair) == ERR
|| wstr[0] == L'\0' || wstr[1] != L'\0')
{
- return rtn;
+ curses_window_set_error(self, "curses_getcchar", funcname);
+ return (chtype)ERR;
}
/* wctob() mirrors ncurses' own _nc_to_char(): the single-byte form, or EOF
when the character has none in this locale. */
int byte = wctob(wstr[0]);
if (byte != EOF) {
rtn = (rtn & ~(chtype)A_CHARTEXT) | (unsigned char)byte;
+ assert(rtn != (chtype)ERR);
}
return rtn;
}
@@ -3638,7 +3641,10 @@ _curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1,
if ((group_right_1 ? mvwin_wch(self->win, y, x, &cell)
: win_wch(self->win, &cell)) != ERR)
{
- rtn = curses_cell_locale_byte(rtn, &cell);
+ rtn = curses_cell_locale_byte(self, rtn, &cell, "inch");
+ if (rtn == (chtype)ERR) {
+ return NULL;
+ }
}
#endif
return PyLong_FromUnsignedLong(rtn);
Member
Author
There was a problem hiding this comment.
I do not know what is the good solution here. You still get correct attributes and color pair. getbkgd() returns default background (space) if background character cannot be encoded, but there is not good fallback for inch().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On a wide (
ncursesw) build,winch()returns the low 8 bits of the cell character's code point with no locale conversion, sowindow.inch()andwindow.mvinch()disagreed withinstr()for a non-ASCII character representable in an 8-bit locale — e.g.€under ISO-8859-15 gave0xACinstead of the locale byte0xA4.The fix re-encodes the cell to its locale byte via
wctob()when the character has a single-byte form, keepingwinch()'s value otherwise (combining cells and multibyte characters, whichin_wch()reads in full). This mirrors the conversion ncurses itself performs forgetbkgd()(_nc_to_char()), which is unaffected.The underlying ncurses behavior was reported upstream and is considered documented, so it is worked around on the CPython side.