gh-133579: correctly report C curses errors in _curses_panel (#134629)

This is a follow-up to ee36db5500.
This commit is contained in:
Bénédikt Tran 2025-06-08 09:10:52 +02:00 committed by GitHub
parent 8fdbbf8b18
commit d610f11d21
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 277 additions and 249 deletions

View file

@ -17,6 +17,7 @@ static const char PyCursesVersion[] = "2.1";
#include "Python.h" #include "Python.h"
#define CURSES_PANEL_MODULE
#include "py_curses.h" #include "py_curses.h"
#if defined(HAVE_NCURSESW_PANEL_H) #if defined(HAVE_NCURSESW_PANEL_H)
@ -28,10 +29,12 @@ static const char PyCursesVersion[] = "2.1";
#endif #endif
typedef struct { typedef struct {
PyObject *PyCursesError; PyObject *error;
PyTypeObject *PyCursesPanel_Type; PyTypeObject *PyCursesPanel_Type;
} _curses_panel_state; } _curses_panel_state;
typedef struct PyCursesPanelObject PyCursesPanelObject;
static inline _curses_panel_state * static inline _curses_panel_state *
get_curses_panel_state(PyObject *module) get_curses_panel_state(PyObject *module)
{ {
@ -40,11 +43,30 @@ get_curses_panel_state(PyObject *module)
return (_curses_panel_state *)state; return (_curses_panel_state *)state;
} }
static inline _curses_panel_state *
get_curses_panel_state_by_panel(PyCursesPanelObject *panel)
{
/*
* Note: 'state' may be NULL if Py_TYPE(panel) is not a heap
* type associated with this module, but the compiler would
* have likely already complained with an "invalid pointer
* type" at compile-time.
*
* To make it more robust, all functions recovering a module's
* state from an object should expect to return NULL with an
* exception set (in contrast to functions recovering a module's
* state from a module itself).
*/
void *state = PyType_GetModuleState(Py_TYPE(panel));
assert(state != NULL);
return (_curses_panel_state *)state;
}
static int static int
_curses_panel_clear(PyObject *mod) _curses_panel_clear(PyObject *mod)
{ {
_curses_panel_state *state = get_curses_panel_state(mod); _curses_panel_state *state = get_curses_panel_state(mod);
Py_CLEAR(state->PyCursesError); Py_CLEAR(state->error);
Py_CLEAR(state->PyCursesPanel_Type); Py_CLEAR(state->PyCursesPanel_Type);
return 0; return 0;
} }
@ -54,7 +76,7 @@ _curses_panel_traverse(PyObject *mod, visitproc visit, void *arg)
{ {
Py_VISIT(Py_TYPE(mod)); Py_VISIT(Py_TYPE(mod));
_curses_panel_state *state = get_curses_panel_state(mod); _curses_panel_state *state = get_curses_panel_state(mod);
Py_VISIT(state->PyCursesError); Py_VISIT(state->error);
Py_VISIT(state->PyCursesPanel_Type); Py_VISIT(state->PyCursesPanel_Type);
return 0; return 0;
} }
@ -65,28 +87,149 @@ _curses_panel_free(void *mod)
(void)_curses_panel_clear((PyObject *)mod); (void)_curses_panel_clear((PyObject *)mod);
} }
/* Utility Error Procedures
*
* The naming and implementations are identical to those in _cursesmodule.c.
* Functions that are not yet needed (for instance, reporting an ERR value
* from a module-wide function, namely curses_panel_set_error()) are
* omitted and should only be added if needed.
*/
static void
_curses_panel_format_error(_curses_panel_state *state,
const char *curses_funcname,
const char *python_funcname,
const char *return_value,
const char *default_message)
{
assert(!PyErr_Occurred());
if (python_funcname == NULL && curses_funcname == NULL) {
PyErr_SetString(state->error, default_message);
}
else if (python_funcname == NULL) {
(void)PyErr_Format(state->error, CURSES_ERROR_FORMAT,
curses_funcname, return_value);
}
else {
assert(python_funcname != NULL);
(void)PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT,
curses_funcname, python_funcname, return_value);
}
}
/*
* Format a curses error for a function that returned ERR.
*
* Specify a non-NULL 'python_funcname' when the latter differs from
* 'curses_funcname'. If both names are NULL, uses the 'catchall_ERR'
* message instead.
*/
static void
_curses_panel_set_error(_curses_panel_state *state,
const char *curses_funcname,
const char *python_funcname)
{
_curses_panel_format_error(state, curses_funcname, python_funcname,
"ERR", catchall_ERR);
}
/*
* Format a curses error for a function that returned NULL.
*
* Specify a non-NULL 'python_funcname' when the latter differs from
* 'curses_funcname'. If both names are NULL, uses the 'catchall_NULL'
* message instead.
*/
static void
_curses_panel_set_null_error(_curses_panel_state *state,
const char *curses_funcname,
const char *python_funcname)
{
_curses_panel_format_error(state, curses_funcname, python_funcname,
"NULL", catchall_NULL);
}
/* Same as _curses_panel_set_null_error() for a module object. */
static void
curses_panel_set_null_error(PyObject *module,
const char *curses_funcname,
const char *python_funcname)
{
_curses_panel_state *state = get_curses_panel_state(module);
_curses_panel_set_null_error(state, curses_funcname, python_funcname);
}
/* Same as _curses_panel_set_error() for a panel object. */
static void
curses_panel_panel_set_error(PyCursesPanelObject *panel,
const char *curses_funcname,
const char *python_funcname)
{
_curses_panel_state *state = get_curses_panel_state_by_panel(panel);
_curses_panel_set_error(state, curses_funcname, python_funcname);
}
/* Same as _curses_panel_set_null_error() for a panel object. */
static void
curses_panel_panel_set_null_error(PyCursesPanelObject *panel,
const char *curses_funcname,
const char *python_funcname)
{
_curses_panel_state *state = get_curses_panel_state_by_panel(panel);
_curses_panel_set_null_error(state, curses_funcname, python_funcname);
}
/*
* Indicate that a panel object couldn't be found.
*
* Use it for the following constructions:
*
* PROC caller_funcname:
* pan = called_funcname()
* find_po(panel)
*
* PROC caller_funcname:
* find_po(self->pan)
*/
static void
curses_panel_notfound_error(const char *called_funcname,
const char *caller_funcname)
{
assert(!(called_funcname == NULL && caller_funcname == NULL));
if (caller_funcname == NULL) {
(void)PyErr_Format(PyExc_RuntimeError,
"%s(): cannot find panel object",
called_funcname);
}
else {
(void)PyErr_Format(PyExc_RuntimeError,
"%s() (called by %s()): cannot find panel object",
called_funcname, caller_funcname);
}
}
/* Utility Functions */ /* Utility Functions */
/* /*
* Check the return code from a curses function and return None * Check the return code from a curses function, returning None
* or raise an exception as appropriate. * on success and setting an exception on error.
*/ */
/*
* Return None if 'code' is different from ERR (implementation-defined).
* Otherwise, set an exception using curses_panel_panel_set_error() and
* the remaining arguments, and return NULL.
*/
static PyObject * static PyObject *
PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname) curses_panel_panel_check_err(PyCursesPanelObject *panel, int code,
const char *curses_funcname,
const char *python_funcname)
{ {
if (code != ERR) { if (code != ERR) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
else { curses_panel_panel_set_error(panel, curses_funcname, python_funcname);
if (fname == NULL) { return NULL;
PyErr_SetString(state->PyCursesError, catchall_ERR);
}
else {
PyErr_Format(state->PyCursesError, "%s() returned ERR", fname);
}
return NULL;
}
} }
/***************************************************************************** /*****************************************************************************
@ -95,7 +238,7 @@ PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname)
/* Definition of the panel object and panel type */ /* Definition of the panel object and panel type */
typedef struct { typedef struct PyCursesPanelObject {
PyObject_HEAD PyObject_HEAD
PANEL *pan; PANEL *pan;
PyCursesWindowObject *wo; /* for reference counts */ PyCursesWindowObject *wo; /* for reference counts */
@ -144,8 +287,11 @@ insert_lop(PyCursesPanelObject *po)
return 0; return 0;
} }
/* Remove the panel object from lop */ /* Remove the panel object from lop.
static void *
* Return -1 on error but do NOT set an exception; otherwise return 0.
*/
static int
remove_lop(PyCursesPanelObject *po) remove_lop(PyCursesPanelObject *po)
{ {
list_of_panels *temp, *n; list_of_panels *temp, *n;
@ -154,25 +300,23 @@ remove_lop(PyCursesPanelObject *po)
if (temp->po == po) { if (temp->po == po) {
lop = temp->next; lop = temp->next;
PyMem_Free(temp); PyMem_Free(temp);
return; return 0;
} }
while (temp->next == NULL || temp->next->po != po) { while (temp->next == NULL || temp->next->po != po) {
if (temp->next == NULL) { if (temp->next == NULL) {
PyErr_SetString(PyExc_RuntimeError, return -1;
"remove_lop: can't find Panel Object");
return;
} }
temp = temp->next; temp = temp->next;
} }
n = temp->next->next; n = temp->next->next;
PyMem_Free(temp->next); PyMem_Free(temp->next);
temp->next = n; temp->next = n;
return; return 0;
} }
/* Return the panel object that corresponds to pan */ /* Return the panel object that corresponds to pan */
static PyCursesPanelObject * static PyCursesPanelObject *
find_po(PANEL *pan) find_po_impl(PANEL *pan)
{ {
list_of_panels *temp; list_of_panels *temp;
for (temp = lop; temp->po->pan != pan; temp = temp->next) for (temp = lop; temp->po->pan != pan; temp = temp->next)
@ -180,6 +324,17 @@ find_po(PANEL *pan)
return temp->po; return temp->po;
} }
/* Same as find_po_impl() but with caller context information. */
static PyCursesPanelObject *
find_po(PANEL *pan, const char *called_funcname, const char *caller_funcname)
{
PyCursesPanelObject *res = find_po_impl(pan);
if (res == NULL) {
curses_panel_notfound_error(called_funcname, caller_funcname);
}
return res;
}
/*[clinic input] /*[clinic input]
module _curses_panel module _curses_panel
class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type" class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type"
@ -193,67 +348,59 @@ class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type"
/*[clinic input] /*[clinic input]
_curses_panel.panel.bottom _curses_panel.panel.bottom
cls: defining_class
Push the panel to the bottom of the stack. Push the panel to the bottom of the stack.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls) _curses_panel_panel_bottom_impl(PyCursesPanelObject *self)
/*[clinic end generated code: output=8ec7fbbc08554021 input=6b7d2c0578b5a1c4]*/ /*[clinic end generated code: output=7aa7d14d7e1d1ce6 input=b6c920c071b61e2e]*/
{ {
_curses_panel_state *state = PyType_GetModuleState(cls); int rtn = bottom_panel(self->pan);
return PyCursesCheckERR(state, bottom_panel(self->pan), "bottom"); return curses_panel_panel_check_err(self, rtn, "bottom_panel", "bottom");
} }
/*[clinic input] /*[clinic input]
_curses_panel.panel.hide _curses_panel.panel.hide
cls: defining_class
Hide the panel. Hide the panel.
This does not delete the object, it just makes the window on screen invisible. This does not delete the object, it just makes the window on screen invisible.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls) _curses_panel_panel_hide_impl(PyCursesPanelObject *self)
/*[clinic end generated code: output=cc6ab7203cdc1450 input=1bfc741f473e6055]*/ /*[clinic end generated code: output=a7bbbd523e1eab49 input=f6ab884e99386118]*/
{ {
_curses_panel_state *state = PyType_GetModuleState(cls); int rtn = hide_panel(self->pan);
return PyCursesCheckERR(state, hide_panel(self->pan), "hide"); return curses_panel_panel_check_err(self, rtn, "hide_panel", "hide");
} }
/*[clinic input] /*[clinic input]
_curses_panel.panel.show _curses_panel.panel.show
cls: defining_class
Display the panel (which might have been hidden). Display the panel (which might have been hidden).
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls) _curses_panel_panel_show_impl(PyCursesPanelObject *self)
/*[clinic end generated code: output=dc3421de375f0409 input=8122e80151cb4379]*/ /*[clinic end generated code: output=6b4553ab45c97769 input=57b167bbefaa3755]*/
{ {
_curses_panel_state *state = PyType_GetModuleState(cls); int rtn = show_panel(self->pan);
return PyCursesCheckERR(state, show_panel(self->pan), "show"); return curses_panel_panel_check_err(self, rtn, "show_panel", "show");
} }
/*[clinic input] /*[clinic input]
_curses_panel.panel.top _curses_panel.panel.top
cls: defining_class
Push panel to the top of the stack. Push panel to the top of the stack.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls) _curses_panel_panel_top_impl(PyCursesPanelObject *self)
/*[clinic end generated code: output=10a072e511e873f7 input=1f372d597dda3379]*/ /*[clinic end generated code: output=0f5f2f8cdd2d1777 input=be33975ec3ca0e9a]*/
{ {
_curses_panel_state *state = PyType_GetModuleState(cls); int rtn = top_panel(self->pan);
return PyCursesCheckERR(state, top_panel(self->pan), "top"); return curses_panel_panel_check_err(self, rtn, "top_panel", "top");
} }
/* Allocation and deallocation of Panel Objects */ /* Allocation and deallocation of Panel Objects */
@ -287,13 +434,22 @@ PyCursesPanel_Dealloc(PyObject *self)
tp = (PyObject *) Py_TYPE(po); tp = (PyObject *) Py_TYPE(po);
obj = (PyObject *) panel_userptr(po->pan); obj = (PyObject *) panel_userptr(po->pan);
if (obj) { if (obj) {
(void)set_panel_userptr(po->pan, NULL);
Py_DECREF(obj); Py_DECREF(obj);
if (set_panel_userptr(po->pan, NULL) == ERR) {
curses_panel_panel_set_error(po, "set_panel_userptr", "__del__");
PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()");
}
}
if (del_panel(po->pan) == ERR && !PyErr_Occurred()) {
curses_panel_panel_set_error(po, "del_panel", "__del__");
PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()");
} }
(void)del_panel(po->pan);
if (po->wo != NULL) { if (po->wo != NULL) {
Py_DECREF(po->wo); Py_DECREF(po->wo);
remove_lop(po); if (remove_lop(po) < 0) {
PyErr_SetString(PyExc_RuntimeError, "__del__: no panel object to delete");
PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()");
}
} }
PyObject_Free(po); PyObject_Free(po);
Py_DECREF(tp); Py_DECREF(tp);
@ -315,18 +471,11 @@ _curses_panel_panel_above_impl(PyCursesPanelObject *self)
PyCursesPanelObject *po; PyCursesPanelObject *po;
pan = panel_above(self->pan); pan = panel_above(self->pan);
if (pan == NULL) { /* valid output: it means no panel exists yet */
if (pan == NULL) { /* valid output, it means the calling panel
is on top of the stack */
Py_RETURN_NONE; Py_RETURN_NONE;
} }
po = find_po(pan); po = find_po(pan, "panel_above", "above");
if (po == NULL) { return Py_XNewRef(po);
PyErr_SetString(PyExc_RuntimeError,
"panel_above: can't find Panel Object");
return NULL;
}
return Py_NewRef(po);
} }
/* panel_below(NULL) returns the top panel in the stack. To get /* panel_below(NULL) returns the top panel in the stack. To get
@ -345,18 +494,11 @@ _curses_panel_panel_below_impl(PyCursesPanelObject *self)
PyCursesPanelObject *po; PyCursesPanelObject *po;
pan = panel_below(self->pan); pan = panel_below(self->pan);
if (pan == NULL) { /* valid output: it means no panel exists yet */
if (pan == NULL) { /* valid output, it means the calling panel
is on the bottom of the stack */
Py_RETURN_NONE; Py_RETURN_NONE;
} }
po = find_po(pan); po = find_po(pan, "panel_below", "below");
if (po == NULL) { return Py_XNewRef(po);
PyErr_SetString(PyExc_RuntimeError,
"panel_below: can't find Panel Object");
return NULL;
}
return Py_NewRef(po);
} }
/*[clinic input] /*[clinic input]
@ -378,7 +520,6 @@ _curses_panel_panel_hidden_impl(PyCursesPanelObject *self)
/*[clinic input] /*[clinic input]
_curses_panel.panel.move _curses_panel.panel.move
cls: defining_class
y: int y: int
x: int x: int
/ /
@ -387,12 +528,11 @@ Move the panel to the screen coordinates (y, x).
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls, _curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x)
int y, int x) /*[clinic end generated code: output=d867535a89777415 input=e0b36b78acc03fba]*/
/*[clinic end generated code: output=ce546c93e56867da input=60a0e7912ff99849]*/
{ {
_curses_panel_state *state = PyType_GetModuleState(cls); int rtn = move_panel(self->pan, y, x);
return PyCursesCheckERR(state, move_panel(self->pan, y, x), "move_panel"); return curses_panel_panel_check_err(self, rtn, "move_panel", "move");
} }
/*[clinic input] /*[clinic input]
@ -411,7 +551,6 @@ _curses_panel_panel_window_impl(PyCursesPanelObject *self)
/*[clinic input] /*[clinic input]
_curses_panel.panel.replace _curses_panel.panel.replace
cls: defining_class
win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type") win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
/ /
@ -420,22 +559,17 @@ Change the window associated with the panel to the window win.
static PyObject * static PyObject *
_curses_panel_panel_replace_impl(PyCursesPanelObject *self, _curses_panel_panel_replace_impl(PyCursesPanelObject *self,
PyTypeObject *cls,
PyCursesWindowObject *win) PyCursesWindowObject *win)
/*[clinic end generated code: output=c71f95c212d58ae7 input=dbec7180ece41ff5]*/ /*[clinic end generated code: output=2253a95f7b287255 input=4b1c4283987d9dfa]*/
{ {
_curses_panel_state *state = PyType_GetModuleState(cls); PyCursesPanelObject *po = find_po(self->pan, "replace", NULL);
PyCursesPanelObject *po = find_po(self->pan);
if (po == NULL) { if (po == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"replace_panel: can't find Panel Object");
return NULL; return NULL;
} }
int rtn = replace_panel(self->pan, win->win); int rtn = replace_panel(self->pan, win->win);
if (rtn == ERR) { if (rtn == ERR) {
PyErr_SetString(state->PyCursesError, "replace_panel() returned ERR"); curses_panel_panel_set_error(self, "replace_panel", "replace");
return NULL; return NULL;
} }
Py_SETREF(po->wo, (PyCursesWindowObject*)Py_NewRef(win)); Py_SETREF(po->wo, (PyCursesWindowObject*)Py_NewRef(win));
@ -445,7 +579,6 @@ _curses_panel_panel_replace_impl(PyCursesPanelObject *self,
/*[clinic input] /*[clinic input]
_curses_panel.panel.set_userptr _curses_panel.panel.set_userptr
cls: defining_class
obj: object obj: object
/ /
@ -454,8 +587,8 @@ Set the panel's user pointer to obj.
static PyObject * static PyObject *
_curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self, _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self,
PyTypeObject *cls, PyObject *obj) PyObject *obj)
/*[clinic end generated code: output=db74f3db07b28080 input=e3fee2ff7b1b8e48]*/ /*[clinic end generated code: output=7fa1fd23f69db71e input=d2c6a9dbefabbf39]*/
{ {
PyCursesInitialised; PyCursesInitialised;
Py_INCREF(obj); Py_INCREF(obj);
@ -464,34 +597,27 @@ _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self,
if (rc == ERR) { if (rc == ERR) {
/* In case of an ncurses error, decref the new object again */ /* In case of an ncurses error, decref the new object again */
Py_DECREF(obj); Py_DECREF(obj);
curses_panel_panel_set_error(self, "set_panel_userptr", "set_userptr");
return NULL;
} }
else { Py_XDECREF(oldobj);
Py_XDECREF(oldobj); Py_RETURN_NONE;
}
_curses_panel_state *state = PyType_GetModuleState(cls);
return PyCursesCheckERR(state, rc, "set_panel_userptr");
} }
/*[clinic input] /*[clinic input]
_curses_panel.panel.userptr _curses_panel.panel.userptr
cls: defining_class
Return the user pointer for the panel. Return the user pointer for the panel.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_curses_panel_panel_userptr_impl(PyCursesPanelObject *self, _curses_panel_panel_userptr_impl(PyCursesPanelObject *self)
PyTypeObject *cls) /*[clinic end generated code: output=e849c307b5dc9237 input=f78b7a47aef0fd50]*/
/*[clinic end generated code: output=eea6e6f39ffc0179 input=f22ca4f115e30a80]*/
{ {
_curses_panel_state *state = PyType_GetModuleState(cls);
PyCursesInitialised; PyCursesInitialised;
PyObject *obj = (PyObject *) panel_userptr(self->pan); PyObject *obj = (PyObject *) panel_userptr(self->pan);
if (obj == NULL) { if (obj == NULL) {
PyErr_SetString(state->PyCursesError, "no userptr set"); curses_panel_panel_set_null_error(self, "panel_userptr", "userptr");
return NULL; return NULL;
} }
@ -552,18 +678,11 @@ _curses_panel_bottom_panel_impl(PyObject *module)
PyCursesInitialised; PyCursesInitialised;
pan = panel_above(NULL); pan = panel_above(NULL);
if (pan == NULL) { /* valid output: it means no panel exists yet */
if (pan == NULL) { /* valid output, it means
there's no panel at all */
Py_RETURN_NONE; Py_RETURN_NONE;
} }
po = find_po(pan); po = find_po(pan, "panel_above", "bottom_panel");
if (po == NULL) { return Py_XNewRef(po);
PyErr_SetString(PyExc_RuntimeError,
"panel_above: can't find Panel Object");
return NULL;
}
return Py_NewRef(po);
} }
/*[clinic input] /*[clinic input]
@ -579,14 +698,13 @@ static PyObject *
_curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win) _curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win)
/*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/ /*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/
{ {
_curses_panel_state *state = get_curses_panel_state(module);
PANEL *pan = new_panel(win->win); PANEL *pan = new_panel(win->win);
if (pan == NULL) { if (pan == NULL) {
PyErr_SetString(state->PyCursesError, catchall_NULL); curses_panel_set_null_error(module, "new_panel", NULL);
return NULL; return NULL;
} }
return (PyObject *)PyCursesPanel_New(state, pan, win); _curses_panel_state *state = get_curses_panel_state(module);
return PyCursesPanel_New(state, pan, win);
} }
@ -610,18 +728,11 @@ _curses_panel_top_panel_impl(PyObject *module)
PyCursesInitialised; PyCursesInitialised;
pan = panel_below(NULL); pan = panel_below(NULL);
if (pan == NULL) { /* valid output: it means no panel exists yet */
if (pan == NULL) { /* valid output, it means
there's no panel at all */
Py_RETURN_NONE; Py_RETURN_NONE;
} }
po = find_po(pan); po = find_po(pan, "panel_below", "top_panel");
if (po == NULL) { return Py_XNewRef(po);
PyErr_SetString(PyExc_RuntimeError,
"panel_below: can't find Panel Object");
return NULL;
}
return Py_NewRef(po);
} }
/*[clinic input] /*[clinic input]
@ -673,10 +784,10 @@ _curses_panel_exec(PyObject *mod)
} }
/* For exception _curses_panel.error */ /* For exception _curses_panel.error */
state->PyCursesError = PyErr_NewException( state->error = PyErr_NewException(
"_curses_panel.error", NULL, NULL); "_curses_panel.error", NULL, NULL);
if (PyModule_AddObjectRef(mod, "error", state->PyCursesError) < 0) { if (PyModule_AddObjectRef(mod, "error", state->error) < 0) {
return -1; return -1;
} }

View file

@ -2,10 +2,7 @@
preserve preserve
[clinic start generated code]*/ [clinic start generated code]*/
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #include "pycore_modsupport.h" // _PyArg_CheckPositional()
# include "pycore_runtime.h" // _Py_SINGLETON()
#endif
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(_curses_panel_panel_bottom__doc__, PyDoc_STRVAR(_curses_panel_panel_bottom__doc__,
"bottom($self, /)\n" "bottom($self, /)\n"
@ -14,19 +11,15 @@ PyDoc_STRVAR(_curses_panel_panel_bottom__doc__,
"Push the panel to the bottom of the stack."); "Push the panel to the bottom of the stack.");
#define _CURSES_PANEL_PANEL_BOTTOM_METHODDEF \ #define _CURSES_PANEL_PANEL_BOTTOM_METHODDEF \
{"bottom", _PyCFunction_CAST(_curses_panel_panel_bottom), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_bottom__doc__}, {"bottom", (PyCFunction)_curses_panel_panel_bottom, METH_NOARGS, _curses_panel_panel_bottom__doc__},
static PyObject * static PyObject *
_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls); _curses_panel_panel_bottom_impl(PyCursesPanelObject *self);
static PyObject * static PyObject *
_curses_panel_panel_bottom(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _curses_panel_panel_bottom(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self);
PyErr_SetString(PyExc_TypeError, "bottom() takes no arguments");
return NULL;
}
return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self, cls);
} }
PyDoc_STRVAR(_curses_panel_panel_hide__doc__, PyDoc_STRVAR(_curses_panel_panel_hide__doc__,
@ -38,19 +31,15 @@ PyDoc_STRVAR(_curses_panel_panel_hide__doc__,
"This does not delete the object, it just makes the window on screen invisible."); "This does not delete the object, it just makes the window on screen invisible.");
#define _CURSES_PANEL_PANEL_HIDE_METHODDEF \ #define _CURSES_PANEL_PANEL_HIDE_METHODDEF \
{"hide", _PyCFunction_CAST(_curses_panel_panel_hide), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_hide__doc__}, {"hide", (PyCFunction)_curses_panel_panel_hide, METH_NOARGS, _curses_panel_panel_hide__doc__},
static PyObject * static PyObject *
_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls); _curses_panel_panel_hide_impl(PyCursesPanelObject *self);
static PyObject * static PyObject *
_curses_panel_panel_hide(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _curses_panel_panel_hide(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self);
PyErr_SetString(PyExc_TypeError, "hide() takes no arguments");
return NULL;
}
return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self, cls);
} }
PyDoc_STRVAR(_curses_panel_panel_show__doc__, PyDoc_STRVAR(_curses_panel_panel_show__doc__,
@ -60,19 +49,15 @@ PyDoc_STRVAR(_curses_panel_panel_show__doc__,
"Display the panel (which might have been hidden)."); "Display the panel (which might have been hidden).");
#define _CURSES_PANEL_PANEL_SHOW_METHODDEF \ #define _CURSES_PANEL_PANEL_SHOW_METHODDEF \
{"show", _PyCFunction_CAST(_curses_panel_panel_show), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_show__doc__}, {"show", (PyCFunction)_curses_panel_panel_show, METH_NOARGS, _curses_panel_panel_show__doc__},
static PyObject * static PyObject *
_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls); _curses_panel_panel_show_impl(PyCursesPanelObject *self);
static PyObject * static PyObject *
_curses_panel_panel_show(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _curses_panel_panel_show(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { return _curses_panel_panel_show_impl((PyCursesPanelObject *)self);
PyErr_SetString(PyExc_TypeError, "show() takes no arguments");
return NULL;
}
return _curses_panel_panel_show_impl((PyCursesPanelObject *)self, cls);
} }
PyDoc_STRVAR(_curses_panel_panel_top__doc__, PyDoc_STRVAR(_curses_panel_panel_top__doc__,
@ -82,19 +67,15 @@ PyDoc_STRVAR(_curses_panel_panel_top__doc__,
"Push panel to the top of the stack."); "Push panel to the top of the stack.");
#define _CURSES_PANEL_PANEL_TOP_METHODDEF \ #define _CURSES_PANEL_PANEL_TOP_METHODDEF \
{"top", _PyCFunction_CAST(_curses_panel_panel_top), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_top__doc__}, {"top", (PyCFunction)_curses_panel_panel_top, METH_NOARGS, _curses_panel_panel_top__doc__},
static PyObject * static PyObject *
_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls); _curses_panel_panel_top_impl(PyCursesPanelObject *self);
static PyObject * static PyObject *
_curses_panel_panel_top(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _curses_panel_panel_top(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { return _curses_panel_panel_top_impl((PyCursesPanelObject *)self);
PyErr_SetString(PyExc_TypeError, "top() takes no arguments");
return NULL;
}
return _curses_panel_panel_top_impl((PyCursesPanelObject *)self, cls);
} }
PyDoc_STRVAR(_curses_panel_panel_above__doc__, PyDoc_STRVAR(_curses_panel_panel_above__doc__,
@ -158,36 +139,19 @@ PyDoc_STRVAR(_curses_panel_panel_move__doc__,
"Move the panel to the screen coordinates (y, x)."); "Move the panel to the screen coordinates (y, x).");
#define _CURSES_PANEL_PANEL_MOVE_METHODDEF \ #define _CURSES_PANEL_PANEL_MOVE_METHODDEF \
{"move", _PyCFunction_CAST(_curses_panel_panel_move), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_move__doc__}, {"move", _PyCFunction_CAST(_curses_panel_panel_move), METH_FASTCALL, _curses_panel_panel_move__doc__},
static PyObject * static PyObject *
_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls, _curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x);
int y, int x);
static PyObject * static PyObject *
_curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _curses_panel_panel_move(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
#else
# define KWTUPLE NULL
#endif
static const char * const _keywords[] = {"", "", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "move",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[2];
int y; int y;
int x; int x;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, if (!_PyArg_CheckPositional("move", nargs, 2, 2)) {
/*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit; goto exit;
} }
y = PyLong_AsInt(args[0]); y = PyLong_AsInt(args[0]);
@ -198,7 +162,7 @@ _curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *arg
if (x == -1 && PyErr_Occurred()) { if (x == -1 && PyErr_Occurred()) {
goto exit; goto exit;
} }
return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, cls, y, x); return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, y, x);
exit: exit:
return return_value; return return_value;
@ -229,44 +193,24 @@ PyDoc_STRVAR(_curses_panel_panel_replace__doc__,
"Change the window associated with the panel to the window win."); "Change the window associated with the panel to the window win.");
#define _CURSES_PANEL_PANEL_REPLACE_METHODDEF \ #define _CURSES_PANEL_PANEL_REPLACE_METHODDEF \
{"replace", _PyCFunction_CAST(_curses_panel_panel_replace), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_replace__doc__}, {"replace", (PyCFunction)_curses_panel_panel_replace, METH_O, _curses_panel_panel_replace__doc__},
static PyObject * static PyObject *
_curses_panel_panel_replace_impl(PyCursesPanelObject *self, _curses_panel_panel_replace_impl(PyCursesPanelObject *self,
PyTypeObject *cls,
PyCursesWindowObject *win); PyCursesWindowObject *win);
static PyObject * static PyObject *
_curses_panel_panel_replace(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _curses_panel_panel_replace(PyObject *self, PyObject *arg)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
#else
# define KWTUPLE NULL
#endif
static const char * const _keywords[] = {"", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "replace",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[1];
PyCursesWindowObject *win; PyCursesWindowObject *win;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, if (!PyObject_TypeCheck(arg, &PyCursesWindow_Type)) {
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); _PyArg_BadArgument("replace", "argument", (&PyCursesWindow_Type)->tp_name, arg);
if (!args) {
goto exit; goto exit;
} }
if (!PyObject_TypeCheck(args[0], &PyCursesWindow_Type)) { win = (PyCursesWindowObject *)arg;
_PyArg_BadArgument("replace", "argument 1", (&PyCursesWindow_Type)->tp_name, args[0]); return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, win);
goto exit;
}
win = (PyCursesWindowObject *)args[0];
return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, cls, win);
exit: exit:
return return_value; return return_value;
@ -279,41 +223,19 @@ PyDoc_STRVAR(_curses_panel_panel_set_userptr__doc__,
"Set the panel\'s user pointer to obj."); "Set the panel\'s user pointer to obj.");
#define _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF \ #define _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF \
{"set_userptr", _PyCFunction_CAST(_curses_panel_panel_set_userptr), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_set_userptr__doc__}, {"set_userptr", (PyCFunction)_curses_panel_panel_set_userptr, METH_O, _curses_panel_panel_set_userptr__doc__},
static PyObject * static PyObject *
_curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self, _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self,
PyTypeObject *cls, PyObject *obj); PyObject *obj);
static PyObject * static PyObject *
_curses_panel_panel_set_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _curses_panel_panel_set_userptr(PyObject *self, PyObject *obj)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
#else
# define KWTUPLE NULL
#endif
static const char * const _keywords[] = {"", NULL}; return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, obj);
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "set_userptr",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[1];
PyObject *obj;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
obj = args[0];
return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, cls, obj);
exit:
return return_value; return return_value;
} }
@ -324,20 +246,15 @@ PyDoc_STRVAR(_curses_panel_panel_userptr__doc__,
"Return the user pointer for the panel."); "Return the user pointer for the panel.");
#define _CURSES_PANEL_PANEL_USERPTR_METHODDEF \ #define _CURSES_PANEL_PANEL_USERPTR_METHODDEF \
{"userptr", _PyCFunction_CAST(_curses_panel_panel_userptr), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_userptr__doc__}, {"userptr", (PyCFunction)_curses_panel_panel_userptr, METH_NOARGS, _curses_panel_panel_userptr__doc__},
static PyObject * static PyObject *
_curses_panel_panel_userptr_impl(PyCursesPanelObject *self, _curses_panel_panel_userptr_impl(PyCursesPanelObject *self);
PyTypeObject *cls);
static PyObject * static PyObject *
_curses_panel_panel_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _curses_panel_panel_userptr(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self);
PyErr_SetString(PyExc_TypeError, "userptr() takes no arguments");
return NULL;
}
return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self, cls);
} }
PyDoc_STRVAR(_curses_panel_bottom_panel__doc__, PyDoc_STRVAR(_curses_panel_bottom_panel__doc__,
@ -424,4 +341,4 @@ _curses_panel_update_panels(PyObject *module, PyObject *Py_UNUSED(ignored))
{ {
return _curses_panel_update_panels_impl(module); return _curses_panel_update_panels_impl(module);
} }
/*[clinic end generated code: output=36853ecb4a979814 input=a9049054013a1b77]*/ /*[clinic end generated code: output=db2fe491582784aa input=a9049054013a1b77]*/