Skip to content
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,11 @@ Porting to Python 3.10
bugs like ``if (PyList_SET_ITEM (a, b, c) < 0) ...`` test.
(Contributed by Zackery Spytz and Victor Stinner in :issue:`30459`.)

* Convert the ``PyCurses_API`` C API (``_curses._C_API`` capsule) from
a pointer array to a structure and remove the ``PyCurses_API_pointers``
macro.
(Contributed by Hai Shi in :issue:`43009`.)

Deprecated
----------

Expand Down
21 changes: 13 additions & 8 deletions Include/py_curses.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@
extern "C" {
#endif

#define PyCurses_API_pointers 4

/* Type declarations */

typedef struct {
Expand All @@ -64,6 +62,13 @@ typedef struct {
char *encoding;
} PyCursesWindowObject;

typedef struct {
PyTypeObject *window_type;
int (*setup_term_called)(void);
int (*initialized)(void);
int (*initialized_color)(void);
} PyCurses_CAPI;

#define PyCursesWindow_Check(v) Py_IS_TYPE(v, &PyCursesWindow_Type)

#define PyCurses_CAPSULE_NAME "_curses._C_API"
Expand All @@ -75,15 +80,15 @@ typedef struct {
#else
/* This section is used in modules that use the _cursesmodule API */

static void **PyCurses_API;
static PyCurses_CAPI *PyCurses_API;

#define PyCursesWindow_Type (*(PyTypeObject *) PyCurses_API[0])
#define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;}
#define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;}
#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;}
#define PyCursesWindow_Type (*PyCurses_API->window_type)
#define PyCursesSetupTermCalled {if (!PyCurses_API->setup_term_called()) return NULL;}
#define PyCursesInitialised {if (!PyCurses_API->initialized()) return NULL;}
#define PyCursesInitialisedColor {if (!PyCurses_API->initialized_color()) return NULL;}

#define import_curses() \
PyCurses_API = (void **)PyCapsule_Import(PyCurses_CAPSULE_NAME, 1);
PyCurses_API = PyCapsule_Import(PyCurses_CAPSULE_NAME, 1);

#endif

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Convert the ``PyCurses_API`` C API (``_curses._C_API`` capsule) from
a pointer array to a structure and remove the ``PyCurses_API_pointers``
macro.
19 changes: 10 additions & 9 deletions Modules/_cursesmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -4728,8 +4728,8 @@ static struct PyModuleDef _cursesmodule = {
static void
curses_destructor(PyObject *op)
{
void *ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME);
Py_DECREF(*(void **)ptr);
PyCurses_CAPI *ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME);
Py_DECREF(ptr->window_type);
PyMem_Free(ptr);
}

Expand All @@ -4753,22 +4753,23 @@ PyInit__curses(void)
return NULL;
ModDict = d; /* For PyCurses_InitScr to use later */

void **PyCurses_API = PyMem_Calloc(PyCurses_API_pointers, sizeof(void *));
PyCurses_CAPI *PyCurses_API = PyMem_Malloc(sizeof(PyCurses_CAPI));
if (PyCurses_API == NULL) {
PyErr_NoMemory();
return NULL;
}
/* Initialize the C API pointer array */
PyCurses_API[0] = (void *)Py_NewRef(&PyCursesWindow_Type);
PyCurses_API[1] = (void *)func_PyCursesSetupTermCalled;
PyCurses_API[2] = (void *)func_PyCursesInitialised;
PyCurses_API[3] = (void *)func_PyCursesInitialisedColor;
/* Initialize the C API struct */
PyCurses_API->window_type = (PyTypeObject *)Py_NewRef(
&PyCursesWindow_Type);
PyCurses_API->setup_term_called = func_PyCursesSetupTermCalled;
PyCurses_API->initialized = func_PyCursesInitialised;
PyCurses_API->initialized_color = func_PyCursesInitialisedColor;

/* Add a capsule for the C API */
c_api_object = PyCapsule_New(PyCurses_API, PyCurses_CAPSULE_NAME,
curses_destructor);
if (c_api_object == NULL) {
Py_DECREF(PyCurses_API[0]);
Py_DECREF(PyCurses_API->window_type);
PyMem_Free(PyCurses_API);
return NULL;
}
Expand Down