mirror of https://github.com/python/cpython
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:
parent
c24847658f
commit
0fdfceb782
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -76,6 +76,7 @@ extern "C" {
|
|||
typedef struct {
|
||||
PyObject_HEAD
|
||||
WINDOW *win;
|
||||
char *encoding;
|
||||
} PyCursesWindowObject;
|
||||
|
||||
#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type)
|
||||
|
|
|
@ -267,24 +267,42 @@ def test_issue6243(stdscr):
|
|||
def test_unget_wch(stdscr):
|
||||
if not hasattr(curses, 'unget_wch'):
|
||||
return
|
||||
ch = 'a'
|
||||
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)
|
||||
code = ord(ch)
|
||||
curses.unget_wch(code)
|
||||
read = stdscr.get_wch()
|
||||
if read != ch:
|
||||
raise AssertionError("%r != %r" % (read, ch))
|
||||
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()
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
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");
|
||||
return NULL;
|
||||
#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);
|
||||
}
|
||||
return PyCursesCheckERR(rtn, "addch");
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
}
|
||||
#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
|
||||
#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);
|
||||
}
|
||||
#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
|
||||
#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,12 +902,9 @@ 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,
|
||||
ch[0], ch[1], ch[2], ch[3],
|
||||
|
@ -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);
|
||||
}
|
||||
#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
|
||||
#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);
|
||||
}
|
||||
#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
|
||||
#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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue