From e6dd71da3acc21edcc205d024d18004c7a3c7f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:48:50 +0200 Subject: [PATCH] gh-123961: Clean up curses C API/capsule (#124907) --- Modules/_cursesmodule.c | 127 ++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 50 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 36f6c6c57f6..f13731f6f36 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -626,24 +626,6 @@ class component_converter(CConverter): [python start generated code]*/ /*[python end generated code: output=da39a3ee5e6b4b0d input=38e9be01d33927fb]*/ -/* Function versions of the 3 functions for testing whether curses has been - initialised or not. */ - -static int func_PyCursesSetupTermCalled(void) -{ - return _PyCursesCheckFunction(curses_setupterm_called, "setupterm"); -} - -static int func_PyCursesInitialised(void) -{ - return _PyCursesCheckFunction(curses_initscr_called, "initscr"); -} - -static int func_PyCursesInitialisedColor(void) -{ - return _PyCursesCheckFunction(curses_start_color_called, "start_color"); -} - /***************************************************************************** The Window Object ******************************************************************************/ @@ -4853,29 +4835,73 @@ static PyMethodDef PyCurses_methods[] = { {NULL, NULL} /* sentinel */ }; -/* Initialization function for the module */ +/* Module C API */ +/* Function versions of the 3 functions for testing whether curses has been + initialised or not. */ -static struct PyModuleDef _cursesmodule = { - PyModuleDef_HEAD_INIT, - "_curses", - NULL, - -1, - PyCurses_methods, - NULL, - NULL, - NULL, - NULL -}; +static inline int +curses_capi_setupterm_called(void) +{ + return _PyCursesCheckFunction(curses_setupterm_called, "setupterm"); +} + +static inline int +curses_capi_initscr_called(void) +{ + return _PyCursesCheckFunction(curses_initscr_called, "initscr"); +} + +static inline int +curses_capi_start_color_called(void) +{ + return _PyCursesCheckFunction(curses_start_color_called, "start_color"); +} + +static void * +curses_capi_new(_cursesmodule_state *state) +{ + assert(state->window_type != NULL); + void **capi = (void **)PyMem_Calloc(PyCurses_API_pointers, sizeof(void *)); + if (capi == NULL) { + PyErr_NoMemory(); + return NULL; + } + capi[0] = (void *)Py_NewRef(state->window_type); + capi[1] = curses_capi_setupterm_called; + capi[2] = curses_capi_initscr_called; + capi[3] = curses_capi_start_color_called; + return (void *)capi; +} static void -curses_destructor(PyObject *op) +curses_capi_free(void *capi) { - void *ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME); - Py_DECREF(*(void **)ptr); - PyMem_Free(ptr); + assert(capi != NULL); + void **capi_ptr = (void **)capi; + assert(capi_ptr[0] != NULL); + Py_DECREF(capi_ptr[0]); // decref curses window type + PyMem_Free(capi_ptr); } +/* Module C API Capsule */ + +static void +curses_capi_capsule_destructor(PyObject *op) +{ + void *capi = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME); + curses_capi_free(capi); +} + +static PyObject * +curses_capi_capsule_new(void *capi) +{ + return PyCapsule_New(capi, PyCurses_CAPSULE_NAME, + curses_capi_capsule_destructor); +} + +/* Module initialization */ + static int cursesmodule_exec(PyObject *module) { @@ -4895,27 +4921,19 @@ cursesmodule_exec(PyObject *module) return -1; } - void **PyCurses_API = PyMem_Calloc(PyCurses_API_pointers, sizeof(void *)); - if (PyCurses_API == NULL) { - PyErr_NoMemory(); + /* Create the C API object */ + void *capi = curses_capi_new(state); + if (capi == NULL) { return -1; } - /* 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; - /* Add a capsule for the C API */ - PyObject *c_api_object = PyCapsule_New(PyCurses_API, PyCurses_CAPSULE_NAME, - curses_destructor); - if (c_api_object == NULL) { - Py_DECREF(PyCurses_API[0]); - PyMem_Free(PyCurses_API); + PyObject *capi_capsule = curses_capi_capsule_new(capi); + if (capi_capsule == NULL) { + curses_capi_free(capi); return -1; } - int rc = PyDict_SetItemString(module_dict, "_C_API", c_api_object); - Py_DECREF(c_api_object); + int rc = PyDict_SetItemString(module_dict, "_C_API", capi_capsule); + Py_DECREF(capi_capsule); if (rc < 0) { return -1; } @@ -5118,6 +5136,15 @@ cursesmodule_exec(PyObject *module) return 0; } +/* Initialization function for the module */ + +static struct PyModuleDef _cursesmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "_curses", + .m_size = -1, + .m_methods = PyCurses_methods, +}; + PyMODINIT_FUNC PyInit__curses(void) {