diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3e55b3fa0f4734..db3a175d2d1e77 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1358,6 +1358,12 @@ New Features (Contributed by Eddie Elizondo in :gh:`84436`.) +* Convert the ``PyCurses_API`` C API (``_curses._C_API`` capsule) from a pointer + array to a structure(``PyCurses_C_API``) in pycore_curses.h. ``PyCursesWindow_Type``, + ``PyCursesSetupTermCalled``, ``PyCursesInitialised``, ``PyCursesInitialisedColor`` + be moved into internal APIs and the public API will be deprecated in 3.14. + (Contributed by Hai Shi in :gh:`87175`). + Porting to Python 3.12 ---------------------- diff --git a/Include/internal/pycore_curses.h b/Include/internal/pycore_curses.h new file mode 100644 index 00000000000000..1b8bc27740fcff --- /dev/null +++ b/Include/internal/pycore_curses.h @@ -0,0 +1,46 @@ +#ifndef Py_INTERNAL_CURSES_H +#define Py_INTERNAL_CURSES_H + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyTypeObject *window_type; + int (*setup_term_called)(void); + int (*initialized)(void); + int (*initialized_color)(void); +} PyCurses_CAPI; + +#ifdef CURSES_MODULE +/* This section is used when compiling _cursesmodule.c */ + +#else +/* This section is used in modules that use the _cursesmodule API */ + +static PyCurses_CAPI *PyCurses_C_API; + +#undef PyCursesWindow_Type +#undef PyCursesSetupTermCalled +#undef PyCursesInitialised +#undef PyCursesInitialisedColor +#define PyCursesWindow_Type (*PyCurses_C_API->window_type) +#define PyCursesSetupTermCalled {if (!PyCurses_C_API->setup_term_called()) return NULL;} +#define PyCursesInitialised {if (!PyCurses_C_API->initialized()) return NULL;} +#define PyCursesInitialisedColor {if (!PyCurses_C_API->initialized_color()) return NULL;} + +#undef import_curses +#define import_curses() \ + PyCurses_C_API = PyCapsule_Import(PyCurses_CAPSULE_NAME, 1); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_INTERNAL_CURSES_H */ diff --git a/Include/py_curses.h b/Include/py_curses.h index e46b08e9cc414e..d895431a39dcd6 100644 --- a/Include/py_curses.h +++ b/Include/py_curses.h @@ -75,8 +75,9 @@ typedef struct { #else /* This section is used in modules that use the _cursesmodule API */ -static void **PyCurses_API; +Py_DEPRECATED(3.14) static void **PyCurses_API; +/* Those macros will be deprecated in 3.14 and moved into internal APIs. */ #define PyCursesWindow_Type (*_PyType_CAST(PyCurses_API[0])) #define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;} #define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;} diff --git a/Makefile.pre.in b/Makefile.pre.in index da3a8f6c13f90b..cf75c8701d23d5 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1699,6 +1699,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_compile.h \ $(srcdir)/Include/internal/pycore_condvar.h \ $(srcdir)/Include/internal/pycore_context.h \ + $(srcdir)/Include/internal/pycore_curses.h \ $(srcdir)/Include/internal/pycore_dict.h \ $(srcdir)/Include/internal/pycore_dict_state.h \ $(srcdir)/Include/internal/pycore_descrobject.h \ diff --git a/Misc/NEWS.d/next/C API/2023-05-17-00-59-26.gh-issue-87175.VpxNNY.rst b/Misc/NEWS.d/next/C API/2023-05-17-00-59-26.gh-issue-87175.VpxNNY.rst new file mode 100644 index 00000000000000..fef9896c78ff55 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-05-17-00-59-26.gh-issue-87175.VpxNNY.rst @@ -0,0 +1,2 @@ +Convert the ``PyCurses_API`` C API (``_curses._C_API`` capsule) from a pointer array to a structure(``PyCurses_C_API``) in pycore_curses.h. +``PyCursesWindow_Type``, ``PyCursesSetupTermCalled``, ``PyCursesInitialised``, ``PyCursesInitialisedColor`` be moved into internal APIs and the public API will be deprecated in 3.14. diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index a3124ff80551e0..3efee47d790c69 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -10,9 +10,14 @@ static const char PyCursesVersion[] = "2.1"; /* Includes */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" #include "py_curses.h" +#include "pycore_curses.h" #include diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 5691a419a32f8e..ae1da9686ad184 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -116,6 +116,7 @@ static const char PyCursesVersion[] = "2.2"; #define CURSES_MODULE #include "py_curses.h" +#include "pycore_curses.h" #if defined(HAVE_TERM_H) || defined(__sgi) /* For termname, longname, putp, tigetflag, tigetnum, tigetstr, tparm @@ -4727,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); } @@ -4752,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; } diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 48cd4418f90fee..a37fa3c7811ef1 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -211,6 +211,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 5c8c1444e8100e..de28e7e109410d 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -537,6 +537,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 7ba116dcb171cf..df70683a2756af 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -583,6 +583,7 @@ Modules/_xxtestfuzz/fuzzer.c LLVMFuzzerTestOneInput AST_LITERAL_EVAL_INITIALIZED # XXX Fix the analyzer. ## forward/extern references +Include/internal/pycore_curses.h - PyCurses_C_API - Include/py_curses.h - PyCurses_API - Include/pydecimal.h - _decimal_api - Modules/_blake2/blake2module.c - blake2b_type_spec -