mirror of https://github.com/python/cpython
gh-123961: Convert `curses.window` static type into a heap type (#124934)
This commit is contained in:
parent
5e9e50612e
commit
f66d785861
|
@ -0,0 +1,3 @@
|
|||
Convert the :ref:`curses.window <curses-window-objects>` static type exposed
|
||||
by the :c:macro:`!PyCursesWindow_Type` macro in ``Include/py_curses.h`` to a
|
||||
:ref:`heap type <heap-types>`. Patch by Bénédikt Tran.
|
|
@ -105,6 +105,7 @@ static const char PyCursesVersion[] = "2.2";
|
|||
#endif
|
||||
|
||||
#include "Python.h"
|
||||
#include "pycore_capsule.h" // _PyCapsule_SetTraverse()
|
||||
#include "pycore_long.h" // _PyLong_GetZero()
|
||||
#include "pycore_structseq.h" // _PyStructSequence_NewType()
|
||||
|
||||
|
@ -173,6 +174,12 @@ get_cursesmodule_state(PyObject *Py_UNUSED(module))
|
|||
return &curses_global_state;
|
||||
}
|
||||
|
||||
static inline _cursesmodule_state *
|
||||
get_cursesmodule_state_by_cls(PyTypeObject *Py_UNUSED(cls))
|
||||
{
|
||||
return &curses_global_state;
|
||||
}
|
||||
|
||||
static inline _cursesmodule_state *
|
||||
get_cursesmodule_state_by_win(PyCursesWindowObject *Py_UNUSED(win))
|
||||
{
|
||||
|
@ -181,9 +188,9 @@ get_cursesmodule_state_by_win(PyCursesWindowObject *Py_UNUSED(win))
|
|||
|
||||
/*[clinic input]
|
||||
module _curses
|
||||
class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type"
|
||||
class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type"
|
||||
[clinic start generated code]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=43265c372c2887d6]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/
|
||||
|
||||
/* Tells whether setupterm() has been called to initialise terminfo. */
|
||||
static int curses_setupterm_called = FALSE;
|
||||
|
@ -630,10 +637,6 @@ class component_converter(CConverter):
|
|||
The Window Object
|
||||
******************************************************************************/
|
||||
|
||||
/* Definition of the window type */
|
||||
|
||||
PyTypeObject PyCursesWindow_Type;
|
||||
|
||||
/* Function prototype macros for Window object
|
||||
|
||||
X - function name
|
||||
|
@ -743,10 +746,9 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns")
|
|||
/* Allocation and deallocation of Window Objects */
|
||||
|
||||
static PyObject *
|
||||
PyCursesWindow_New(WINDOW *win, const char *encoding)
|
||||
PyCursesWindow_New(_cursesmodule_state *state,
|
||||
WINDOW *win, const char *encoding)
|
||||
{
|
||||
PyCursesWindowObject *wo;
|
||||
|
||||
if (encoding == NULL) {
|
||||
#if defined(MS_WINDOWS)
|
||||
char *buffer[100];
|
||||
|
@ -758,15 +760,20 @@ PyCursesWindow_New(WINDOW *win, const char *encoding)
|
|||
}
|
||||
#elif defined(CODESET)
|
||||
const char *codeset = nl_langinfo(CODESET);
|
||||
if (codeset != NULL && codeset[0] != 0)
|
||||
if (codeset != NULL && codeset[0] != 0) {
|
||||
encoding = codeset;
|
||||
}
|
||||
#endif
|
||||
if (encoding == NULL)
|
||||
if (encoding == NULL) {
|
||||
encoding = "utf-8";
|
||||
}
|
||||
}
|
||||
|
||||
wo = PyObject_New(PyCursesWindowObject, &PyCursesWindow_Type);
|
||||
if (wo == NULL) return NULL;
|
||||
PyCursesWindowObject *wo = PyObject_GC_New(PyCursesWindowObject,
|
||||
state->window_type);
|
||||
if (wo == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
wo->win = win;
|
||||
wo->encoding = _PyMem_Strdup(encoding);
|
||||
if (wo->encoding == NULL) {
|
||||
|
@ -774,12 +781,16 @@ PyCursesWindow_New(WINDOW *win, const char *encoding)
|
|||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
PyObject_GC_Track((PyObject *)wo);
|
||||
return (PyObject *)wo;
|
||||
}
|
||||
|
||||
static void
|
||||
PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
|
||||
PyCursesWindow_dealloc(PyObject *self)
|
||||
{
|
||||
PyTypeObject *window_type = Py_TYPE(self);
|
||||
PyObject_GC_UnTrack(self);
|
||||
PyCursesWindowObject *wo = (PyCursesWindowObject *)self;
|
||||
if (wo->win != stdscr && wo->win != NULL) {
|
||||
// silently ignore errors in delwin(3)
|
||||
(void)delwin(wo->win);
|
||||
|
@ -787,7 +798,15 @@ PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
|
|||
if (wo->encoding != NULL) {
|
||||
PyMem_Free(wo->encoding);
|
||||
}
|
||||
PyObject_Free(wo);
|
||||
window_type->tp_free(self);
|
||||
Py_DECREF(window_type);
|
||||
}
|
||||
|
||||
static int
|
||||
PyCursesWindow_traverse(PyObject *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(Py_TYPE(self));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Addch, Addstr, Addnstr */
|
||||
|
@ -1391,7 +1410,8 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win, NULL);
|
||||
_cursesmodule_state *state = get_cursesmodule_state_by_win(self);
|
||||
return PyCursesWindow_New(state, win, NULL);
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
@ -2140,7 +2160,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self)
|
|||
/*[clinic input]
|
||||
_curses.window.overlay
|
||||
|
||||
destwin: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
|
||||
destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type")
|
||||
|
||||
[
|
||||
sminrow: int
|
||||
|
@ -2169,7 +2189,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self,
|
|||
PyCursesWindowObject *destwin, int group_right_1,
|
||||
int sminrow, int smincol, int dminrow,
|
||||
int dmincol, int dmaxrow, int dmaxcol)
|
||||
/*[clinic end generated code: output=82bb2c4cb443ca58 input=7edd23ad22cc1984]*/
|
||||
/*[clinic end generated code: output=82bb2c4cb443ca58 input=6e4b32a7c627a356]*/
|
||||
{
|
||||
int rtn;
|
||||
|
||||
|
@ -2187,7 +2207,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self,
|
|||
/*[clinic input]
|
||||
_curses.window.overwrite
|
||||
|
||||
destwin: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
|
||||
destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type")
|
||||
|
||||
[
|
||||
sminrow: int
|
||||
|
@ -2217,7 +2237,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self,
|
|||
int group_right_1, int sminrow, int smincol,
|
||||
int dminrow, int dmincol, int dmaxrow,
|
||||
int dmaxcol)
|
||||
/*[clinic end generated code: output=12ae007d1681be28 input=ea5de1b35cd948e0]*/
|
||||
/*[clinic end generated code: output=12ae007d1681be28 input=d83dd8b24ff2bcc9]*/
|
||||
{
|
||||
int rtn;
|
||||
|
||||
|
@ -2426,7 +2446,8 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win, self->encoding);
|
||||
_cursesmodule_state *state = get_cursesmodule_state_by_win(self);
|
||||
return PyCursesWindow_New(state, win, self->encoding);
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
@ -2564,9 +2585,11 @@ PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *P
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define clinic_state() (get_cursesmodule_state_by_cls(Py_TYPE(self)))
|
||||
#include "clinic/_cursesmodule.c.h"
|
||||
#undef clinic_state
|
||||
|
||||
static PyMethodDef PyCursesWindow_Methods[] = {
|
||||
static PyMethodDef PyCursesWindow_methods[] = {
|
||||
_CURSES_WINDOW_ADDCH_METHODDEF
|
||||
_CURSES_WINDOW_ADDNSTR_METHODDEF
|
||||
_CURSES_WINDOW_ADDSTR_METHODDEF
|
||||
|
@ -2660,42 +2683,27 @@ static PyGetSetDef PyCursesWindow_getsets[] = {
|
|||
{NULL, NULL, NULL, NULL } /* sentinel */
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------*/
|
||||
|
||||
PyTypeObject PyCursesWindow_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_curses.window", /*tp_name*/
|
||||
sizeof(PyCursesWindowObject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)PyCursesWindow_Dealloc, /*tp_dealloc*/
|
||||
0, /*tp_vectorcall_offset*/
|
||||
(getattrfunc)0, /*tp_getattr*/
|
||||
(setattrfunc)0, /*tp_setattr*/
|
||||
0, /*tp_as_async*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
0, /*tp_doc*/
|
||||
0, /*tp_traverse*/
|
||||
0, /*tp_clear*/
|
||||
0, /*tp_richcompare*/
|
||||
0, /*tp_weaklistoffset*/
|
||||
0, /*tp_iter*/
|
||||
0, /*tp_iternext*/
|
||||
PyCursesWindow_Methods, /*tp_methods*/
|
||||
0, /* tp_members */
|
||||
PyCursesWindow_getsets, /* tp_getset */
|
||||
static PyType_Slot PyCursesWindow_Type_slots[] = {
|
||||
{Py_tp_methods, PyCursesWindow_methods},
|
||||
{Py_tp_getset, PyCursesWindow_getsets},
|
||||
{Py_tp_dealloc, PyCursesWindow_dealloc},
|
||||
{Py_tp_traverse, PyCursesWindow_traverse},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static PyType_Spec PyCursesWindow_Type_spec = {
|
||||
.name = "_curses.window",
|
||||
.basicsize = sizeof(PyCursesWindowObject),
|
||||
.flags = Py_TPFLAGS_DEFAULT
|
||||
| Py_TPFLAGS_DISALLOW_INSTANTIATION
|
||||
| Py_TPFLAGS_IMMUTABLETYPE
|
||||
| Py_TPFLAGS_HEAPTYPE
|
||||
| Py_TPFLAGS_HAVE_GC,
|
||||
.slots = PyCursesWindow_Type_slots
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------*/
|
||||
|
||||
/* Function Body Macros - They are ugly but very, very useful. ;-)
|
||||
|
||||
X - function name
|
||||
|
@ -3177,7 +3185,8 @@ _curses_getwin(PyObject *module, PyObject *file)
|
|||
PyErr_SetString(state->error, catchall_NULL);
|
||||
goto error;
|
||||
}
|
||||
res = PyCursesWindow_New(win, NULL);
|
||||
_cursesmodule_state *state = get_cursesmodule_state(module);
|
||||
res = PyCursesWindow_New(state, win, NULL);
|
||||
|
||||
error:
|
||||
fclose(fp);
|
||||
|
@ -3349,7 +3358,8 @@ _curses_initscr_impl(PyObject *module)
|
|||
|
||||
if (curses_initscr_called) {
|
||||
wrefresh(stdscr);
|
||||
return (PyObject *)PyCursesWindow_New(stdscr, NULL);
|
||||
_cursesmodule_state *state = get_cursesmodule_state(module);
|
||||
return PyCursesWindow_New(state, stdscr, NULL);
|
||||
}
|
||||
|
||||
win = initscr();
|
||||
|
@ -3452,12 +3462,13 @@ _curses_initscr_impl(PyObject *module)
|
|||
SetDictInt("COLS", COLS);
|
||||
#undef SetDictInt
|
||||
|
||||
PyCursesWindowObject *winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL);
|
||||
_cursesmodule_state *state = get_cursesmodule_state(module);
|
||||
PyObject *winobj = PyCursesWindow_New(state, win, NULL);
|
||||
if (winobj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
curses_screen_encoding = winobj->encoding;
|
||||
return (PyObject *)winobj;
|
||||
curses_screen_encoding = ((PyCursesWindowObject *)winobj)->encoding;
|
||||
return winobj;
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
@ -3829,7 +3840,8 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win, NULL);
|
||||
_cursesmodule_state *state = get_cursesmodule_state(module);
|
||||
return PyCursesWindow_New(state, win, NULL);
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
@ -3869,7 +3881,8 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win, NULL);
|
||||
_cursesmodule_state *state = get_cursesmodule_state(module);
|
||||
return PyCursesWindow_New(state, win, NULL);
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
@ -4893,11 +4906,40 @@ curses_capi_capsule_destructor(PyObject *op)
|
|||
curses_capi_free(capi);
|
||||
}
|
||||
|
||||
static int
|
||||
curses_capi_capsule_traverse(PyObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
void **capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME);
|
||||
assert(capi_ptr != NULL);
|
||||
Py_VISIT(capi_ptr[0]); // visit curses window type
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
curses_capi_capsule_clear(PyObject *op)
|
||||
{
|
||||
void **capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME);
|
||||
assert(capi_ptr != NULL);
|
||||
Py_CLEAR(capi_ptr[0]); // clear curses window type
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
curses_capi_capsule_new(void *capi)
|
||||
{
|
||||
return PyCapsule_New(capi, PyCurses_CAPSULE_NAME,
|
||||
PyObject *capsule = PyCapsule_New(capi, PyCurses_CAPSULE_NAME,
|
||||
curses_capi_capsule_destructor);
|
||||
if (capsule == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyCapsule_SetTraverse(capsule,
|
||||
curses_capi_capsule_traverse,
|
||||
curses_capi_capsule_clear) < 0)
|
||||
{
|
||||
Py_DECREF(capsule);
|
||||
return NULL;
|
||||
}
|
||||
return capsule;
|
||||
}
|
||||
|
||||
/* Module initialization */
|
||||
|
@ -4907,13 +4949,14 @@ cursesmodule_exec(PyObject *module)
|
|||
{
|
||||
_cursesmodule_state *state = get_cursesmodule_state(module);
|
||||
/* Initialize object type */
|
||||
if (PyType_Ready(&PyCursesWindow_Type) < 0) {
|
||||
state->window_type = (PyTypeObject *)PyType_FromModuleAndSpec(
|
||||
module, &PyCursesWindow_Type_spec, NULL);
|
||||
if (state->window_type == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddType(module, &PyCursesWindow_Type) < 0) {
|
||||
if (PyModule_AddType(module, state->window_type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
state->window_type = &PyCursesWindow_Type;
|
||||
|
||||
/* Add some symbolic constants to the module */
|
||||
PyObject *module_dict = PyModule_GetDict(module);
|
||||
|
|
|
@ -1389,12 +1389,12 @@ _curses_window_overlay(PyCursesWindowObject *self, PyObject *args)
|
|||
|
||||
switch (PyTuple_GET_SIZE(args)) {
|
||||
case 1:
|
||||
if (!PyArg_ParseTuple(args, "O!:overlay", &PyCursesWindow_Type, &destwin)) {
|
||||
if (!PyArg_ParseTuple(args, "O!:overlay", clinic_state()->window_type, &destwin)) {
|
||||
goto exit;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (!PyArg_ParseTuple(args, "O!iiiiii:overlay", &PyCursesWindow_Type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) {
|
||||
if (!PyArg_ParseTuple(args, "O!iiiiii:overlay", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) {
|
||||
goto exit;
|
||||
}
|
||||
group_right_1 = 1;
|
||||
|
@ -1448,12 +1448,12 @@ _curses_window_overwrite(PyCursesWindowObject *self, PyObject *args)
|
|||
|
||||
switch (PyTuple_GET_SIZE(args)) {
|
||||
case 1:
|
||||
if (!PyArg_ParseTuple(args, "O!:overwrite", &PyCursesWindow_Type, &destwin)) {
|
||||
if (!PyArg_ParseTuple(args, "O!:overwrite", clinic_state()->window_type, &destwin)) {
|
||||
goto exit;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (!PyArg_ParseTuple(args, "O!iiiiii:overwrite", &PyCursesWindow_Type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) {
|
||||
if (!PyArg_ParseTuple(args, "O!iiiiii:overwrite", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) {
|
||||
goto exit;
|
||||
}
|
||||
group_right_1 = 1;
|
||||
|
@ -4378,4 +4378,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored
|
|||
#ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF
|
||||
#define _CURSES_USE_DEFAULT_COLORS_METHODDEF
|
||||
#endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */
|
||||
/*[clinic end generated code: output=8745c1562b537fb4 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=cd1273354b08948f input=a9049054013a1b77]*/
|
||||
|
|
Loading…
Reference in New Issue