diff --git a/Include/py_curses.h b/Include/py_curses.h --- a/Include/py_curses.h +++ b/Include/py_curses.h @@ -76,6 +76,7 @@ extern "C" { typedef struct { PyObject_HEAD WINDOW *win; + char *encoding; } PyCursesWindowObject; #define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -121,6 +121,10 @@ extern int setupterm(char *,int,int *); #include #endif +#ifdef HAVE_LANGINFO_H +#include +#endif + #if !defined(HAVE_NCURSES_H) && (defined(sgi) || defined(__sun) || defined(SCO5)) #define STRICT_SYSV_CURSES /* Don't use ncurses extensions */ typedef chtype attr_t; /* No attr_t type is available */ @@ -143,6 +147,8 @@ static int initialised = FALSE; /* Tells whether start_color() has been called to initialise color usage. */ static int initialisedcolors = FALSE; +static char *screen_encoding = NULL; + /* Utility Macros */ #define PyCursesSetupTermCalled \ if (initialised_setupterm != TRUE) { \ @@ -175,7 +181,7 @@ static int initialisedcolors = FALSE; */ static PyObject * -PyCursesCheckERR(int code, char *fname) +PyCursesCheckERR(int code, const char *fname) { if (code != ERR) { Py_INCREF(Py_None); @@ -190,25 +196,195 @@ PyCursesCheckERR(int code, char *fname) } } +/* Convert an object to a byte (an integer of type chtype): + + - int + - bytes of length 1 + - str of length 1 + + Return 1 on success, 0 on error (invalid type or integer overflow). */ static int -PyCurses_ConvertToChtype(PyObject *obj, chtype *ch) +PyCurses_ConvertToChtype(PyCursesWindowObject *win, PyObject *obj, chtype *ch) { - if (PyLong_CheckExact(obj)) { - int overflow; - /* XXX should the truncation by the cast also be reported - as an error? */ - *ch = (chtype) PyLong_AsLongAndOverflow(obj, &overflow); - if (overflow) + long value; + if(PyBytes_Check(obj) && PyBytes_Size(obj) == 1) { + value = (unsigned char)PyBytes_AsString(obj)[0]; + } + else if (PyUnicode_Check(obj)) { + if (PyUnicode_GetSize(obj) != 1) { + PyErr_Format(PyExc_TypeError, + "expect bytes or str of length 1, or int, " + "got a str of length %zi", + PyUnicode_GET_SIZE(obj)); return 0; - } else if(PyBytes_Check(obj) - && (PyBytes_Size(obj) == 1)) { - *ch = (chtype) *PyBytes_AsString(obj); - } else if (PyUnicode_Check(obj) && PyUnicode_GetSize(obj) == 1) { - *ch = (chtype) *PyUnicode_AS_UNICODE(obj); - } else { + } + value = PyUnicode_AS_UNICODE(obj)[0]; + if (128 < value) { + PyObject *bytes; + const char *encoding; + if (win) + encoding = win->encoding; + else + encoding = screen_encoding; + bytes = PyUnicode_AsEncodedObject(obj, encoding, NULL); + if (bytes == NULL) + return 0; + if (PyBytes_GET_SIZE(bytes) == 1) + value = (unsigned char)PyBytes_AS_STRING(bytes)[0]; + else + value = -1; + Py_DECREF(bytes); + } + } + else if (PyLong_CheckExact(obj)) { + int long_overflow; + value = PyLong_AsLongAndOverflow(obj, &long_overflow); + if (long_overflow) + goto overflow; + } + else { + PyErr_Format(PyExc_TypeError, + "expect bytes or str of length 1, or int, got %s", + Py_TYPE(obj)->tp_name); return 0; } + if (value < 0 || value > 255) + goto overflow; + *ch = (chtype)value; + if ((wchar_t)*ch != value) + goto overflow; return 1; + +overflow: + PyErr_SetString(PyExc_OverflowError, + "byte doesn't fit in chtype"); + return 0; +} + +/* Convert an object to a byte (integer of type chtype) or a character + (cchar_t): + + - int + - bytes of length 1 + - str of length 1 + + Return: + + - 2 if obj is a character (written into *wch) + - 1 if obj is a byte (written into *ch) + - 0 on error: raise an exception */ +static int +PyCurses_ConvertToCchar_t(PyCursesWindowObject *win, PyObject *obj, + chtype *ch +#ifdef HAVE_NCURSESW + , cchar_t *wch +#endif + ) +{ + int ret = 0; + long value; +#ifdef HAVE_NCURSESW + wchar_t buffer[2]; +#endif + + if (PyUnicode_Check(obj)) { +#ifdef HAVE_NCURSESW + if (PyUnicode_AsWideChar(obj, buffer, 2) != 1) { + PyErr_Format(PyExc_TypeError, + "expect bytes or str of length 1, or int, " + "got a str of length %zi", + PyUnicode_GET_SIZE(obj)); + return 0; + } + value = PyUnicode_AS_UNICODE(obj)[0]; + + memset(wch->chars, 0, sizeof(wch->chars)); + wch->chars[0] = buffer[0]; + return 2; +#else + return PyCurses_ConvertToChtype(win, obj, ch); +#endif + } + else if(PyBytes_Check(obj) && PyBytes_Size(obj) == 1) { + value = (unsigned char)PyBytes_AsString(obj)[0]; + ret = 1; + } + else if (PyLong_CheckExact(obj)) { + int overflow; + value = PyLong_AsLongAndOverflow(obj, &overflow); + if (overflow) { + PyErr_SetString(PyExc_OverflowError, + "int doesn't fit in long"); + return 0; + } +#ifdef HAVE_NCURSESW + ret = 2; +#else + ret = 1; +#endif + } + else { + PyErr_Format(PyExc_TypeError, + "expect bytes or str of length 1, or int, got %s", + Py_TYPE(obj)->tp_name); + return 0; + } +#ifdef HAVE_NCURSESW + if (ret == 2) { + memset(wch->chars, 0, sizeof(wch->chars)); + wch->chars[0] = (wchar_t)value; + if ((long)wch->chars[0] != value) { + PyErr_Format(PyExc_OverflowError, + "character doesn't fit in wchar_t"); + return 0; + } + } + else +#endif + { + *ch = (chtype)value; + if ((long)*ch != value || value < 0 || value > 255) { + PyErr_Format(PyExc_OverflowError, + "byte doesn't fit in chtype"); + return 0; + } + } + return ret; +} + +/* Convert an object to a byte string (char*) or a wide character string + (wchar_t*). Return: + + - 2 if obj is a character string (written into *wch) + - 1 if obj is a byte string (written into *bytes) + - 0 on error: raise an exception */ +static int +PyCurses_ConvertToString(PyCursesWindowObject *win, PyObject *obj, + PyObject **bytes, wchar_t **wstr) +{ + if (PyUnicode_Check(obj)) { + if (wstr != NULL) { + *wstr = PyUnicode_AsWideCharString(obj, NULL); + if (*wstr == NULL) + return 0; + return 2; + } + else { + *bytes = PyUnicode_AsEncodedObject(obj, win->encoding, NULL); + if (*bytes == NULL) + return 0; + return 1; + } + } + else if (PyBytes_Check(obj)) { + Py_INCREF(obj); + *bytes = obj; + return 1; + } + + PyErr_Format(PyExc_TypeError, "expect bytes or str, got %s", + Py_TYPE(obj)->tp_name); + return 0; } /* Function versions of the 3 functions for testing whether curses has been @@ -354,13 +530,37 @@ Window_TwoArgNoReturnFunction(wresize, i /* Allocation and deallocation of Window Objects */ static PyObject * -PyCursesWindow_New(WINDOW *win) +PyCursesWindow_New(WINDOW *win, const char *encoding) { PyCursesWindowObject *wo; + if (encoding == NULL) { +#if defined(MS_WINDOWS) + char *buffer[100]; + UINT cp; + cp = GetConsoleOutputCP(); + if (cp != 0) { + PyOS_snprintf(buffer, sizeof(buffer), "cp%u", cp); + encoding = buffer; + } +#elif defined(CODESET) + const char *codeset = nl_langinfo(CODESET); + if (codeset != NULL && codeset[0] != 0) + encoding = codeset; +#endif + if (encoding == NULL) + encoding = "utf-8"; + } + wo = PyObject_NEW(PyCursesWindowObject, &PyCursesWindow_Type); if (wo == NULL) return NULL; wo->win = win; + wo->encoding = strdup(encoding); + if (wo->encoding == NULL) { + Py_DECREF(wo); + PyErr_NoMemory(); + return NULL; + } return (PyObject *)wo; } @@ -368,6 +568,8 @@ static void PyCursesWindow_Dealloc(PyCursesWindowObject *wo) { if (wo->win != stdscr) delwin(wo->win); + if (wo->encoding != NULL) + free(wo->encoding); PyObject_DEL(wo); } @@ -377,29 +579,34 @@ static PyObject * PyCursesWindow_AddCh(PyCursesWindowObject *self, PyObject *args) { int rtn, x, y, use_xy = FALSE; - PyObject *temp; - chtype ch = 0; + PyObject *chobj; + int type; + chtype ch; +#ifdef HAVE_NCURSESW + cchar_t wch; +#endif attr_t attr = A_NORMAL; long lattr; + const char *funcname; switch (PyTuple_Size(args)) { case 1: - if (!PyArg_ParseTuple(args, "O;ch or int", &temp)) + if (!PyArg_ParseTuple(args, "O;ch or int", &chobj)) return NULL; break; case 2: - if (!PyArg_ParseTuple(args, "Ol;ch or int,attr", &temp, &lattr)) + if (!PyArg_ParseTuple(args, "Ol;ch or int,attr", &chobj, &lattr)) return NULL; attr = lattr; break; case 3: - if (!PyArg_ParseTuple(args,"iiO;y,x,ch or int", &y, &x, &temp)) + if (!PyArg_ParseTuple(args,"iiO;y,x,ch or int", &y, &x, &chobj)) return NULL; use_xy = TRUE; break; case 4: if (!PyArg_ParseTuple(args,"iiOl;y,x,ch or int, attr", - &y, &x, &temp, &lattr)) + &y, &x, &chobj, &lattr)) return NULL; attr = lattr; use_xy = TRUE; @@ -409,17 +616,33 @@ PyCursesWindow_AddCh(PyCursesWindowObjec return NULL; } - if (!PyCurses_ConvertToChtype(temp, &ch)) { - PyErr_SetString(PyExc_TypeError, "argument 1 or 3 must be a ch or an int"); +#ifdef HAVE_NCURSESW + type = PyCurses_ConvertToCchar_t(self, chobj, &ch, &wch); + if (type == 2) { + funcname = "add_wch"; + wch.attr = attr; + if (use_xy == TRUE) + rtn = mvwadd_wch(self->win,y,x, &wch); + else { + rtn = wadd_wch(self->win, &wch); + } + } + else +#else + type = PyCurses_ConvertToCchar_t(self, chobj, &ch); +#endif + if (type == 1) { + funcname = "addch"; + if (use_xy == TRUE) + rtn = mvwaddch(self->win,y,x, ch | attr); + else { + rtn = waddch(self->win, ch | attr); + } + } + else { return NULL; } - - if (use_xy == TRUE) - rtn = mvwaddch(self->win,y,x, ch | attr); - else { - rtn = waddch(self->win, ch | attr); - } - return PyCursesCheckERR(rtn, "addch"); + return PyCursesCheckERR(rtn, funcname); } static PyObject * @@ -427,29 +650,34 @@ PyCursesWindow_AddStr(PyCursesWindowObje { int rtn; int x, y; - char *str; + int strtype; + PyObject *strobj, *bytesobj; +#ifdef HAVE_NCURSESW + wchar_t *wstr = NULL; +#endif attr_t attr = A_NORMAL , attr_old = A_NORMAL; long lattr; int use_xy = FALSE, use_attr = FALSE; + const char *funcname; switch (PyTuple_Size(args)) { case 1: - if (!PyArg_ParseTuple(args,"s;str", &str)) + if (!PyArg_ParseTuple(args,"O;str", &strobj)) return NULL; break; case 2: - if (!PyArg_ParseTuple(args,"sl;str,attr", &str, &lattr)) + if (!PyArg_ParseTuple(args,"Ol;str,attr", &strobj, &lattr)) return NULL; attr = lattr; use_attr = TRUE; break; case 3: - if (!PyArg_ParseTuple(args,"iis;int,int,str", &y, &x, &str)) + if (!PyArg_ParseTuple(args,"iiO;int,int,str", &y, &x, &strobj)) return NULL; use_xy = TRUE; break; case 4: - if (!PyArg_ParseTuple(args,"iisl;int,int,str,attr", &y, &x, &str, &lattr)) + if (!PyArg_ParseTuple(args,"iiOl;int,int,str,attr", &y, &x, &strobj, &lattr)) return NULL; attr = lattr; use_xy = use_attr = TRUE; @@ -458,47 +686,74 @@ PyCursesWindow_AddStr(PyCursesWindowObje PyErr_SetString(PyExc_TypeError, "addstr requires 1 to 4 arguments"); return NULL; } - +#ifdef HAVE_NCURSESW + strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, &wstr); +#else + strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, NULL); +#endif + if (strtype == 0) + return NULL; if (use_attr == TRUE) { attr_old = getattrs(self->win); (void)wattrset(self->win,attr); } - if (use_xy == TRUE) - rtn = mvwaddstr(self->win,y,x,str); +#ifdef HAVE_NCURSESW + if (strtype == 2) { + funcname = "addwstr"; + if (use_xy == TRUE) + rtn = mvwaddwstr(self->win,y,x,wstr); + else + rtn = waddwstr(self->win,wstr); + PyMem_Free(wstr); + } else - rtn = waddstr(self->win,str); +#endif + { + char *str = PyBytes_AS_STRING(bytesobj); + funcname = "addstr"; + if (use_xy == TRUE) + rtn = mvwaddstr(self->win,y,x,str); + else + rtn = waddstr(self->win,str); + Py_DECREF(bytesobj); + } if (use_attr == TRUE) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR(rtn, "addstr"); + return PyCursesCheckERR(rtn, funcname); } static PyObject * PyCursesWindow_AddNStr(PyCursesWindowObject *self, PyObject *args) { int rtn, x, y, n; - char *str; + int strtype; + PyObject *strobj, *bytesobj; +#ifdef HAVE_NCURSESW + wchar_t *wstr = NULL; +#endif attr_t attr = A_NORMAL , attr_old = A_NORMAL; long lattr; int use_xy = FALSE, use_attr = FALSE; + const char *funcname; switch (PyTuple_Size(args)) { case 2: - if (!PyArg_ParseTuple(args,"si;str,n", &str, &n)) + if (!PyArg_ParseTuple(args,"Oi;str,n", &strobj, &n)) return NULL; break; case 3: - if (!PyArg_ParseTuple(args,"sil;str,n,attr", &str, &n, &lattr)) + if (!PyArg_ParseTuple(args,"Oil;str,n,attr", &strobj, &n, &lattr)) return NULL; attr = lattr; use_attr = TRUE; break; case 4: - if (!PyArg_ParseTuple(args,"iisi;y,x,str,n", &y, &x, &str, &n)) + if (!PyArg_ParseTuple(args,"iiOi;y,x,str,n", &y, &x, &strobj, &n)) return NULL; use_xy = TRUE; break; case 5: - if (!PyArg_ParseTuple(args,"iisil;y,x,str,n,attr", &y, &x, &str, &n, &lattr)) + if (!PyArg_ParseTuple(args,"iiOil;y,x,str,n,attr", &y, &x, &strobj, &n, &lattr)) return NULL; attr = lattr; use_xy = use_attr = TRUE; @@ -507,18 +762,41 @@ PyCursesWindow_AddNStr(PyCursesWindowObj PyErr_SetString(PyExc_TypeError, "addnstr requires 2 to 5 arguments"); return NULL; } +#ifdef HAVE_NCURSESW + strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, &wstr); +#else + strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, NULL); +#endif + if (strtype == 0) + return NULL; if (use_attr == TRUE) { attr_old = getattrs(self->win); (void)wattrset(self->win,attr); } - if (use_xy == TRUE) - rtn = mvwaddnstr(self->win,y,x,str,n); +#ifdef HAVE_NCURSESW + if (strtype == 2) { + funcname = "addnwstr"; + if (use_xy == TRUE) + rtn = mvwaddnwstr(self->win,y,x,wstr,n); + else + rtn = waddnwstr(self->win,wstr,n); + PyMem_Free(wstr); + } else - rtn = waddnstr(self->win,str,n); +#endif + { + char *str = PyBytes_AS_STRING(bytesobj); + funcname = "addnstr"; + if (use_xy == TRUE) + rtn = mvwaddnstr(self->win,y,x,str,n); + else + rtn = waddnstr(self->win,str,n); + Py_DECREF(bytesobj); + } if (use_attr == TRUE) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR(rtn, "addnstr"); + return PyCursesCheckERR(rtn, funcname); } static PyObject * @@ -544,10 +822,8 @@ PyCursesWindow_Bkgd(PyCursesWindowObject return NULL; } - if (!PyCurses_ConvertToChtype(temp, &bkgd)) { - PyErr_SetString(PyExc_TypeError, "argument 1 or 3 must be a ch or an int"); + if (!PyCurses_ConvertToChtype(self, temp, &bkgd)) return NULL; - } return PyCursesCheckERR(wbkgd(self->win, bkgd | attr), "bkgd"); } @@ -602,10 +878,8 @@ PyCursesWindow_BkgdSet(PyCursesWindowObj return NULL; } - if (!PyCurses_ConvertToChtype(temp, &bkgd)) { - PyErr_SetString(PyExc_TypeError, "argument 1 must be a ch or an int"); + if (!PyCurses_ConvertToChtype(self, temp, &bkgd)) return NULL; - } wbkgdset(self->win, bkgd | attr); return PyCursesCheckERR(0, "bkgdset"); @@ -630,11 +904,8 @@ PyCursesWindow_Border(PyCursesWindowObje return NULL; for(i=0; i<8; i++) { - if (temp[i] != NULL && !PyCurses_ConvertToChtype(temp[i], &ch[i])) { - PyErr_Format(PyExc_TypeError, - "argument %i must be a ch or an int", i+1); + if (temp[i] != NULL && !PyCurses_ConvertToChtype(self, temp[i], &ch[i])) return NULL; - } } wborder(self->win, @@ -779,7 +1050,7 @@ PyCursesWindow_DerWin(PyCursesWindowObje return NULL; } - return (PyObject *)PyCursesWindow_New(win); + return (PyObject *)PyCursesWindow_New(win, NULL); } static PyObject * @@ -807,10 +1078,8 @@ PyCursesWindow_EchoChar(PyCursesWindowOb return NULL; } - if (!PyCurses_ConvertToChtype(temp, &ch)) { - PyErr_SetString(PyExc_TypeError, "argument 1 must be a ch or an int"); + if (!PyCurses_ConvertToChtype(self, temp, &ch)) return NULL; - } #ifdef WINDOW_HAS_FLAGS if (self->win->_flags & _ISPAD) @@ -1029,11 +1298,8 @@ PyCursesWindow_Hline(PyCursesWindowObjec } if (code != ERR) { - if (!PyCurses_ConvertToChtype(temp, &ch)) { - PyErr_SetString(PyExc_TypeError, - "argument 1 or 3 must be a ch or an int"); + if (!PyCurses_ConvertToChtype(self, temp, &ch)) return NULL; - } return PyCursesCheckERR(whline(self->win, ch | attr, n), "hline"); } else return PyCursesCheckERR(code, "wmove"); @@ -1074,11 +1340,8 @@ PyCursesWindow_InsCh(PyCursesWindowObjec return NULL; } - if (!PyCurses_ConvertToChtype(temp, &ch)) { - PyErr_SetString(PyExc_TypeError, - "argument 1 or 3 must be a ch or an int"); + if (!PyCurses_ConvertToChtype(self, temp, &ch)) return NULL; - } if (use_xy == TRUE) rtn = mvwinsch(self->win,y,x, ch | attr); @@ -1149,29 +1412,34 @@ PyCursesWindow_InsStr(PyCursesWindowObje { int rtn; int x, y; - char *str; + int strtype; + PyObject *strobj, *bytesobj; +#ifdef HAVE_NCURSESW + wchar_t *wstr = NULL; +#endif attr_t attr = A_NORMAL , attr_old = A_NORMAL; long lattr; int use_xy = FALSE, use_attr = FALSE; + const char *funcname; switch (PyTuple_Size(args)) { case 1: - if (!PyArg_ParseTuple(args,"s;str", &str)) + if (!PyArg_ParseTuple(args,"O;str", &strobj)) return NULL; break; case 2: - if (!PyArg_ParseTuple(args,"sl;str,attr", &str, &lattr)) + if (!PyArg_ParseTuple(args,"Ol;str,attr", &strobj, &lattr)) return NULL; attr = lattr; use_attr = TRUE; break; case 3: - if (!PyArg_ParseTuple(args,"iis;y,x,str", &y, &x, &str)) + if (!PyArg_ParseTuple(args,"iiO;y,x,str", &y, &x, &strobj)) return NULL; use_xy = TRUE; break; case 4: - if (!PyArg_ParseTuple(args,"iisl;y,x,str,attr", &y, &x, &str, &lattr)) + if (!PyArg_ParseTuple(args,"iiOl;y,x,str,attr", &y, &x, &strobj, &lattr)) return NULL; attr = lattr; use_xy = use_attr = TRUE; @@ -1181,46 +1449,75 @@ PyCursesWindow_InsStr(PyCursesWindowObje return NULL; } +#ifdef HAVE_NCURSESW + strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, &wstr); +#else + strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, NULL); +#endif + if (strtype == 0) + return NULL; + if (use_attr == TRUE) { attr_old = getattrs(self->win); (void)wattrset(self->win,attr); } - if (use_xy == TRUE) - rtn = mvwinsstr(self->win,y,x,str); +#ifdef HAVE_NCURSESW + if (strtype == 2) { + funcname = "inswstr"; + if (use_xy == TRUE) + rtn = mvwins_wstr(self->win,y,x,wstr); + else + rtn = wins_wstr(self->win,wstr); + PyMem_Free(wstr); + } else - rtn = winsstr(self->win,str); +#endif + { + char *str = PyBytes_AS_STRING(bytesobj); + funcname = "insstr"; + if (use_xy == TRUE) + rtn = mvwinsstr(self->win,y,x,str); + else + rtn = winsstr(self->win,str); + Py_DECREF(bytesobj); + } if (use_attr == TRUE) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR(rtn, "insstr"); + return PyCursesCheckERR(rtn, funcname); } static PyObject * PyCursesWindow_InsNStr(PyCursesWindowObject *self, PyObject *args) { int rtn, x, y, n; - char *str; + int strtype; + PyObject *strobj, *bytesobj; +#ifdef HAVE_NCURSESW + wchar_t *wstr = NULL; +#endif attr_t attr = A_NORMAL , attr_old = A_NORMAL; long lattr; int use_xy = FALSE, use_attr = FALSE; + const char *funcname; switch (PyTuple_Size(args)) { case 2: - if (!PyArg_ParseTuple(args,"si;str,n", &str, &n)) + if (!PyArg_ParseTuple(args,"Oi;str,n", &strobj, &n)) return NULL; break; case 3: - if (!PyArg_ParseTuple(args,"sil;str,n,attr", &str, &n, &lattr)) + if (!PyArg_ParseTuple(args,"Oil;str,n,attr", &strobj, &n, &lattr)) return NULL; attr = lattr; use_attr = TRUE; break; case 4: - if (!PyArg_ParseTuple(args,"iisi;y,x,str,n", &y, &x, &str, &n)) + if (!PyArg_ParseTuple(args,"iiOi;y,x,str,n", &y, &x, &strobj, &n)) return NULL; use_xy = TRUE; break; case 5: - if (!PyArg_ParseTuple(args,"iisil;y,x,str,n,attr", &y, &x, &str, &n, &lattr)) + if (!PyArg_ParseTuple(args,"iiOil;y,x,str,n,attr", &y, &x, &strobj, &n, &lattr)) return NULL; attr = lattr; use_xy = use_attr = TRUE; @@ -1230,17 +1527,41 @@ PyCursesWindow_InsNStr(PyCursesWindowObj return NULL; } +#ifdef HAVE_NCURSESW + strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, &wstr); +#else + strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, NULL); +#endif + if (strtype == 0) + return NULL; + if (use_attr == TRUE) { attr_old = getattrs(self->win); (void)wattrset(self->win,attr); } - if (use_xy == TRUE) - rtn = mvwinsnstr(self->win,y,x,str,n); +#ifdef HAVE_NCURSESW + if (strtype == 2) { + funcname = "insn_wstr"; + if (use_xy == TRUE) + rtn = mvwins_nwstr(self->win,y,x,wstr,n); + else + rtn = wins_nwstr(self->win,wstr,n); + PyMem_Free(wstr); + } else - rtn = winsnstr(self->win,str,n); +#endif + { + char *str = PyBytes_AS_STRING(bytesobj); + funcname = "insnstr"; + if (use_xy == TRUE) + rtn = mvwinsnstr(self->win,y,x,str,n); + else + rtn = winsnstr(self->win,str,n); + Py_DECREF(bytesobj); + } if (use_attr == TRUE) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR(rtn, "insnstr"); + return PyCursesCheckERR(rtn, funcname); } static PyObject * @@ -1521,7 +1842,7 @@ PyCursesWindow_SubWin(PyCursesWindowObje return NULL; } - return (PyObject *)PyCursesWindow_New(win); + return (PyObject *)PyCursesWindow_New(win, self->encoding); } static PyObject * @@ -1597,11 +1918,8 @@ PyCursesWindow_Vline(PyCursesWindowObjec } if (code != ERR) { - if (!PyCurses_ConvertToChtype(temp, &ch)) { - PyErr_SetString(PyExc_TypeError, - "argument 1 or 3 must be a ch or an int"); + if (!PyCurses_ConvertToChtype(self, temp, &ch)) return NULL; - } return PyCursesCheckERR(wvline(self->win, ch | attr, n), "vline"); } else return PyCursesCheckERR(code, "wmove"); @@ -1946,7 +2264,7 @@ PyCurses_GetWin(PyCursesWindowObject *se PyErr_SetString(PyCursesError, catchall_NULL); return NULL; } - return PyCursesWindow_New(win); + return PyCursesWindow_New(win, NULL); } static PyObject * @@ -2024,10 +2342,11 @@ static PyObject * PyCurses_InitScr(PyObject *self) { WINDOW *win; + PyCursesWindowObject *winobj; if (initialised == TRUE) { wrefresh(stdscr); - return (PyObject *)PyCursesWindow_New(stdscr); + return (PyObject *)PyCursesWindow_New(stdscr, NULL); } win = initscr(); @@ -2061,7 +2380,7 @@ PyCurses_InitScr(PyObject *self) SetDictInt("ACS_HLINE", (ACS_HLINE)); SetDictInt("ACS_VLINE", (ACS_VLINE)); SetDictInt("ACS_PLUS", (ACS_PLUS)); -#if !defined(__hpux) || defined(HAVE_NCURSES_H) +#if 1 /* On HP/UX 11, these are of type cchar_t, which is not an integral type. If this is a problem on more platforms, a configure test should be added to determine whether ACS_S1 @@ -2119,7 +2438,9 @@ PyCurses_InitScr(PyObject *self) SetDictInt("LINES", LINES); SetDictInt("COLS", COLS); - return (PyObject *)PyCursesWindow_New(win); + winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL); + screen_encoding = winobj->encoding; + return (PyObject *)winobj; } static PyObject * @@ -2321,7 +2642,7 @@ PyCurses_NewPad(PyObject *self, PyObject return NULL; } - return (PyObject *)PyCursesWindow_New(win); + return (PyObject *)PyCursesWindow_New(win, NULL); } static PyObject * @@ -2353,7 +2674,7 @@ PyCurses_NewWindow(PyObject *self, PyObj return NULL; } - return (PyObject *)PyCursesWindow_New(win); + return (PyObject *)PyCursesWindow_New(win, NULL); } static PyObject * @@ -2408,7 +2729,8 @@ PyCurses_Putp(PyObject *self, PyObject * { char *str; - if (!PyArg_ParseTuple(args,"s;str", &str)) return NULL; + if (!PyArg_ParseTuple(args,"s;str", &str)) + return NULL; return PyCursesCheckERR(putp(str), "putp"); } @@ -2666,10 +2988,8 @@ PyCurses_UnCtrl(PyObject *self, PyObject if (!PyArg_ParseTuple(args,"O;ch or int",&temp)) return NULL; - if (!PyCurses_ConvertToChtype(temp, &ch)) { - PyErr_SetString(PyExc_TypeError, "argument must be a ch or an int"); + if (!PyCurses_ConvertToChtype(NULL, temp, &ch)) return NULL; - } return PyBytes_FromString(unctrl(ch)); } @@ -2684,10 +3004,8 @@ PyCurses_UngetCh(PyObject *self, PyObjec if (!PyArg_ParseTuple(args,"O;ch or int",&temp)) return NULL; - if (!PyCurses_ConvertToChtype(temp, &ch)) { - PyErr_SetString(PyExc_TypeError, "argument must be a ch or an int"); + if (!PyCurses_ConvertToChtype(NULL, temp, &ch)) return NULL; - } return PyCursesCheckERR(ungetch(ch), "ungetch"); } diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1161,6 +1161,10 @@ class PyBuildExt(build_ext): else: missing.extend(['nis', 'resource', 'termios']) + curses_defines = [] + if curses_library == 'ncursesw': + curses_defines.append(('HAVE_NCURSESW', '1')) + # Curses support, requiring the System V version of curses, often # provided by the ncurses library. panel_library = 'panel' @@ -1171,6 +1175,7 @@ class PyBuildExt(build_ext): panel_library = 'panelw' curses_libs = [curses_library] exts.append( Extension('_curses', ['_cursesmodule.c'], + define_macros=curses_defines, libraries = curses_libs) ) elif curses_library == 'curses' and platform != 'darwin': # OSX has an old Berkeley curses, not good enough for @@ -1183,6 +1188,7 @@ class PyBuildExt(build_ext): curses_libs = ['curses'] exts.append( Extension('_curses', ['_cursesmodule.c'], + define_macros=curses_defines, libraries = curses_libs) ) else: missing.append('_curses')