Issue #12567: The curses module uses Unicode functions for Unicode arguments

when it is linked to the ncurses library. It encodes also Unicode strings to
the locale encoding instead of UTF-8.
This commit is contained in:
Victor Stinner 2011-11-25 22:10:02 +01:00
parent c24847658f
commit 0fdfceb782
6 changed files with 521 additions and 122 deletions

View File

@ -653,7 +653,7 @@ Window Objects
--------------
Window objects, as returned by :func:`initscr` and :func:`newwin` above, have
the following methods:
the following methods and attributes:
.. method:: window.addch([y, x,] ch[, attr])
@ -834,6 +834,16 @@ the following methods:
event.
.. attribute:: window.encoding
Encoding used to encode method arguments (Unicode strings and characters).
The encoding attribute is inherited from by parent window when a subwindow
is created, for example with :meth:`window.subwin`. By default, the locale
encoding is used (see :func:`locale.getpreferredencoding`).
.. versionadded:: 3.3
.. method:: window.erase()
Clear the window.

View File

@ -333,6 +333,11 @@ function to the :mod:`crypt` module.
curses
------
* If the :mod:`curses` module is linked to the ncursesw library, use Unicode
functions when Unicode strings or characters are passed (e.g.
:c:func:`waddwstr`), and bytes functions otherwise (e.g. :c:func:`waddstr`).
* Use the locale encoding instead of ``utf-8`` to encode Unicode strings.
* :class:`curses.window` has a new :attr:`curses.window.encoding` attribute.
* The :class:`curses.window` class has a new :meth:`~curses.window.get_wch`
method to get a wide character
* The :mod:`curses` module has a new :meth:`~curses.unget_wch` function to

View File

@ -76,6 +76,7 @@ extern "C" {
typedef struct {
PyObject_HEAD
WINDOW *win;
char *encoding;
} PyCursesWindowObject;
#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type)

View File

@ -267,24 +267,42 @@ def test_issue6243(stdscr):
def test_unget_wch(stdscr):
if not hasattr(curses, 'unget_wch'):
return
ch = 'a'
curses.unget_wch(ch)
read = stdscr.get_wch()
read = chr(read)
if read != ch:
raise AssertionError("%r != %r" % (read, ch))
for ch in ('a', '\xe9', '\u20ac', '\U0010FFFF'):
curses.unget_wch(ch)
read = stdscr.get_wch()
read = chr(read)
if read != ch:
raise AssertionError("%r != %r" % (read, ch))
ch = ord('a')
curses.unget_wch(ch)
read = stdscr.get_wch()
if read != ch:
raise AssertionError("%r != %r" % (read, ch))
code = ord(ch)
curses.unget_wch(code)
read = stdscr.get_wch()
if read != code:
raise AssertionError("%r != %r" % (read, code))
def test_issue10570():
b = curses.tparm(curses.tigetstr("cup"), 5, 3)
assert type(b) is bytes
curses.putp(b)
def test_encoding(stdscr):
import codecs
encoding = stdscr.encoding
codecs.lookup(encoding)
try:
stdscr.encoding = 10
except TypeError:
pass
else:
raise AssertionError("TypeError not raised")
stdscr.encoding = encoding
try:
del stdscr.encoding
except TypeError:
pass
else:
raise AssertionError("TypeError not raised")
def main(stdscr):
curses.savetty()
try:
@ -295,6 +313,7 @@ def main(stdscr):
test_issue6243(stdscr)
test_unget_wch(stdscr)
test_issue10570()
test_encoding(stdscr)
finally:
curses.resetty()

View File

@ -395,6 +395,10 @@ Core and Builtins
Library
-------
- Issue #12567: The curses module uses Unicode functions for Unicode arguments
when it is linked to the ncurses library. It encodes also Unicode strings to
the locale encoding instead of UTF-8.
- Issue #12856: Ensure child processes do not inherit the parent's random
seed for filename generation in the tempfile module. Patch by Brian
Harring.

View File

@ -121,6 +121,10 @@ extern int setupterm(char *,int,int *);
#include <term.h>
#endif
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#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,28 +196,193 @@ 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_GetLength(obj) != 1) {
PyErr_Format(PyExc_TypeError,
"expect bytes or str of length 1, or int, "
"got a str of length %zi",
PyUnicode_GET_LENGTH(obj));
return 0;
} else if(PyBytes_Check(obj)
&& (PyBytes_Size(obj) == 1)) {
*ch = (chtype) *PyBytes_AsString(obj);
} else if (PyUnicode_Check(obj) && PyUnicode_GET_LENGTH(obj) == 1) {
Py_UCS4 ucs = PyUnicode_READ(PyUnicode_KIND(obj),
PyUnicode_DATA(obj),
0);
*ch = (chtype)ucs;
} else {
}
value = PyUnicode_READ_CHAR(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);
if (value < 0)
goto overflow;
}
}
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;
}
*ch = (chtype)value;
if ((long)*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 (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_LENGTH(obj));
return 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)) {
#ifdef HAVE_NCURSESW
assert (wstr != NULL);
*wstr = PyUnicode_AsWideCharString(obj, NULL);
if (*wstr == NULL)
return 0;
return 2;
#else
assert (wstr == NULL);
*bytes = PyUnicode_AsEncodedObject(obj, win->encoding, NULL);
if (*bytes == NULL)
return 0;
return 1;
#endif
}
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
@ -357,13 +528,37 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns")
/* 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;
}
@ -371,6 +566,8 @@ static void
PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
{
if (wo->win != stdscr) delwin(wo->win);
if (wo->encoding != NULL)
free(wo->encoding);
PyObject_DEL(wo);
}
@ -380,29 +577,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;
@ -412,17 +614,33 @@ PyCursesWindow_AddCh(PyCursesWindowObject *self, PyObject *args)
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 *
@ -430,29 +648,34 @@ PyCursesWindow_AddStr(PyCursesWindowObject *self, PyObject *args)
{
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;
@ -461,47 +684,74 @@ PyCursesWindow_AddStr(PyCursesWindowObject *self, PyObject *args)
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;
@ -510,18 +760,41 @@ PyCursesWindow_AddNStr(PyCursesWindowObject *self, PyObject *args)
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 *
@ -547,10 +820,8 @@ PyCursesWindow_Bkgd(PyCursesWindowObject *self, PyObject *args)
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");
}
@ -605,10 +876,8 @@ PyCursesWindow_BkgdSet(PyCursesWindowObject *self, PyObject *args)
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");
@ -633,11 +902,8 @@ PyCursesWindow_Border(PyCursesWindowObject *self, PyObject *args)
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,
@ -782,7 +1048,7 @@ PyCursesWindow_DerWin(PyCursesWindowObject *self, PyObject *args)
return NULL;
}
return (PyObject *)PyCursesWindow_New(win);
return (PyObject *)PyCursesWindow_New(win, NULL);
}
static PyObject *
@ -810,10 +1076,8 @@ PyCursesWindow_EchoChar(PyCursesWindowObject *self, PyObject *args)
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)
@ -1034,11 +1298,8 @@ PyCursesWindow_Hline(PyCursesWindowObject *self, PyObject *args)
}
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");
@ -1079,11 +1340,8 @@ PyCursesWindow_InsCh(PyCursesWindowObject *self, PyObject *args)
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);
@ -1154,29 +1412,34 @@ PyCursesWindow_InsStr(PyCursesWindowObject *self, PyObject *args)
{
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;
@ -1186,46 +1449,75 @@ PyCursesWindow_InsStr(PyCursesWindowObject *self, PyObject *args)
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;
@ -1235,17 +1527,41 @@ PyCursesWindow_InsNStr(PyCursesWindowObject *self, PyObject *args)
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 *
@ -1528,7 +1844,7 @@ PyCursesWindow_SubWin(PyCursesWindowObject *self, PyObject *args)
return NULL;
}
return (PyObject *)PyCursesWindow_New(win);
return (PyObject *)PyCursesWindow_New(win, self->encoding);
}
static PyObject *
@ -1604,16 +1920,51 @@ PyCursesWindow_Vline(PyCursesWindowObject *self, PyObject *args)
}
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");
}
static PyObject *
PyCursesWindow_get_encoding(PyCursesWindowObject *self, void *closure)
{
return PyUnicode_FromString(self->encoding);
}
static int
PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value)
{
PyObject *ascii;
char *encoding;
/* It is illegal to del win.encoding */
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
"encoding may not be deleted");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"setting encoding to a non-string");
return -1;
}
ascii = PyUnicode_AsASCIIString(value);
if (ascii == NULL)
return -1;
encoding = strdup(PyBytes_AS_STRING(ascii));
if (encoding == NULL) {
PyErr_NoMemory();
return -1;
}
free(self->encoding);
self->encoding = encoding;
return 0;
}
static PyMethodDef PyCursesWindow_Methods[] = {
{"addch", (PyCFunction)PyCursesWindow_AddCh, METH_VARARGS},
{"addnstr", (PyCFunction)PyCursesWindow_AddNStr, METH_VARARGS},
@ -1701,6 +2052,13 @@ static PyMethodDef PyCursesWindow_Methods[] = {
{NULL, NULL} /* sentinel */
};
static PyGetSetDef PyCursesWindow_getsets[] = {
{"encoding",
(getter)PyCursesWindow_get_encoding,
(setter)PyCursesWindow_set_encoding,
"the typecode character used to create the array"}
};
/* -------------------------------------------------------*/
PyTypeObject PyCursesWindow_Type = {
@ -1733,6 +2091,8 @@ PyTypeObject PyCursesWindow_Type = {
0, /*tp_iter*/
0, /*tp_iternext*/
PyCursesWindow_Methods, /*tp_methods*/
0, /* tp_members */
PyCursesWindow_getsets, /* tp_getset */
};
/*********************************************************************
@ -1956,7 +2316,7 @@ PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream)
PyErr_SetString(PyCursesError, catchall_NULL);
return NULL;
}
return PyCursesWindow_New(win);
return PyCursesWindow_New(win, NULL);
}
static PyObject *
@ -2034,10 +2394,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();
@ -2129,7 +2490,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 *
@ -2331,7 +2694,7 @@ PyCurses_NewPad(PyObject *self, PyObject *args)
return NULL;
}
return (PyObject *)PyCursesWindow_New(win);
return (PyObject *)PyCursesWindow_New(win, NULL);
}
static PyObject *
@ -2363,7 +2726,7 @@ PyCurses_NewWindow(PyObject *self, PyObject *args)
return NULL;
}
return (PyObject *)PyCursesWindow_New(win);
return (PyObject *)PyCursesWindow_New(win, NULL);
}
static PyObject *
@ -2680,10 +3043,8 @@ PyCurses_UnCtrl(PyObject *self, PyObject *args)
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));
}
@ -2696,12 +3057,11 @@ PyCurses_UngetCh(PyObject *self, PyObject *args)
PyCursesInitialised;
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 (!PyArg_ParseTuple(args,"O;ch or int",&temp))
return NULL;
if (!PyCurses_ConvertToChtype(NULL, temp, &ch))
return NULL;
}
return PyCursesCheckERR(ungetch(ch), "ungetch");
}