From 360bb191d2036b3fa222d9848d5e0017f22aa05b Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher Date: Tue, 21 May 2019 13:37:44 -0700 Subject: [PATCH 01/30] bpo-36982, bpo-36630: replumb these curses module functions to support using the extended color functions in ncurses 6.1 when available. color_content color_number init_color init_pair --- Modules/_cursesmodule.c | 103 +++++++++++++++-- Modules/clinic/_cursesmodule.c.h | 186 ++++++++++++++++++++----------- 2 files changed, 216 insertions(+), 73 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index c70b0e2a19fadc..d89dba88803d7f 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2593,11 +2593,30 @@ Return the red, green, and blue (RGB) components of the specified color. A 3-tuple is returned, containing the R, G, B values for the given color, which will be between 0 (no component) and 1000 (maximum amount of component). -[clinic start generated code]*/ +*/ + +#ifdef _NCURSES_EXTENDED_COLOR_FUNCS +static PyObject * +_curses_extended_color_content_impl(PyObject *module, int color_number) +{ + int r,g,b; + + PyCursesInitialised; + PyCursesInitialisedColor; + + if (extended_color_content(color_number, &r, &g, &b) != ERR) + return Py_BuildValue("(iii)", r, g, b); + else { + PyErr_SetString(PyCursesError, + "Argument 1 was out of range. Check value of COLORS."); + return NULL; + } +} + +#else /* _NCURSES_EXTENDED_COLOR_FUNCS */ static PyObject * _curses_color_content_impl(PyObject *module, short color_number) -/*[clinic end generated code: output=cb15cf3120d4bfc1 input=5555abb1c11e11b7]*/ { short r,g,b; @@ -2612,6 +2631,7 @@ _curses_color_content_impl(PyObject *module, short color_number) return NULL; } } +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ /*[clinic input] _curses.color_pair @@ -2624,11 +2644,10 @@ Return the attribute value for displaying text in the specified color. This attribute value can be combined with A_STANDOUT, A_REVERSE, and the other A_* attributes. pair_number() is the counterpart to this function. -[clinic start generated code]*/ +*/ static PyObject * -_curses_color_pair_impl(PyObject *module, short color_number) -/*[clinic end generated code: output=6a84cb6b29ecaf9a input=a9d3eb6f50e4dc12]*/ +_curses_color_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number) { PyCursesInitialised; PyCursesInitialisedColor; @@ -3042,18 +3061,31 @@ Change the definition of a color. When init_color() is used, all occurrences of that color on the screen immediately change to the new definition. This function is a no-op on most terminals; it is active only if can_change_color() returns 1. -[clinic start generated code]*/ +*/ + +#ifdef _NCURSES_EXTENDED_COLOR_FUNCS +static PyObject * +_curses_init_extended_color_impl(PyObject *module, int color_number, int r, + int g, int b) +{ + PyCursesInitialised; + PyCursesInitialisedColor; + + return PyCursesCheckERR(init_extended_color(color_number, r, g, b), "init_extended_color"); +} + +#else /* _NCURSES_EXTENDED_COLOR_FUNCS */ static PyObject * _curses_init_color_impl(PyObject *module, short color_number, short r, short g, short b) -/*[clinic end generated code: output=280236f5efe9776a input=f3a05bd38f619175]*/ { PyCursesInitialised; PyCursesInitialisedColor; return PyCursesCheckERR(init_color(color_number, r, g, b), "init_color"); } +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ /*[clinic input] _curses.init_pair @@ -3070,7 +3102,37 @@ Change the definition of a color-pair. If the color-pair was previously initialized, the screen is refreshed and all occurrences of that color-pair are changed to the new definition. -[clinic start generated code]*/ +*/ + +/* +_curses._curses_init_extended_pair_impl + + pair_number: int + The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)). + fg: int + Foreground color number (0 - COLORS). + bg: int + Background color number (0 - COLORS). + / + +Change the definition of a color-pair. + +If the color-pair was previously initialized, the screen is refreshed and +all occurrences of that color-pair are changed to the new definition. +*/ + +#ifdef _NCURSES_EXTENDED_COLOR_FUNCS +static PyObject * +_curses_init_extended_pair_impl(PyObject *module, int pair_number, int fg, + int bg) +{ + PyCursesInitialised; + PyCursesInitialisedColor; + + return PyCursesCheckERR(init_extended_pair(pair_number, fg, bg), "init_extended_pair"); +} + +#else /* _NCURSES_EXTENDED_COLOR_FUNCS */ static PyObject * _curses_init_pair_impl(PyObject *module, short pair_number, short fg, @@ -3082,6 +3144,7 @@ _curses_init_pair_impl(PyObject *module, short pair_number, short fg, return PyCursesCheckERR(init_pair(pair_number, fg, bg), "init_pair"); } +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ static PyObject *ModDict; @@ -3702,11 +3765,30 @@ _curses.pair_content / Return a tuple (fg, bg) containing the colors for the requested color pair. -[clinic start generated code]*/ +*/ + +#ifdef _NCURSES_EXTENDED_COLOR_FUNCS +static PyObject * +_curses_extended_pair_content_impl(PyObject *module, int pair_number) +{ + int f, b; + + PyCursesInitialised; + PyCursesInitialisedColor; + + if (extended_pair_content(pair_number, &f, &b)!=ERR) { + PyErr_SetString(PyCursesError, + "Argument 1 was out of range. (1..COLOR_PAIRS-1)"); + return NULL; + } + + return Py_BuildValue("(ii)", f, b); +} + +#else /* _NCURSES_EXTENDED_COLOR_FUNCS */ static PyObject * _curses_pair_content_impl(PyObject *module, short pair_number) -/*[clinic end generated code: output=5a72aa1a28bbacf3 input=f4d7fec5643b976b]*/ { short f, b; @@ -3721,6 +3803,7 @@ _curses_pair_content_impl(PyObject *module, short pair_number) return Py_BuildValue("(ii)", f, b); } +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ /*[clinic input] _curses.pair_number diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index f686ded51976c6..2690ce7f3c7466 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1,3 +1,22 @@ + +#if defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) +#define _NCURSES_EXTENDED_COLOR_FUNCS 1 +#else +#define _NCURSES_EXTENDED_COLOR_FUNCS 0 +#endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */ + +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _NCURSES_COLOR_VAL_MAX INT_MAX +#define _NCURSES_COLOR_VAL_MIN INT_MIN +#define _NCURSES_COLOR_VAL_TYPE int +#define _NCURSES_COLOR_VAL_TYPE_STR "integer" +#else +#define _NCURSES_COLOR_VAL_MAX SHRT_MAX +#define _NCURSES_COLOR_VAL_MIN SHRT_MIN +#define _NCURSES_COLOR_VAL_TYPE short +#define _NCURSES_COLOR_VAL_TYPE_STR "short integer" +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + /*[clinic input] preserve [clinic start generated code]*/ @@ -1966,40 +1985,50 @@ PyDoc_STRVAR(_curses_color_content__doc__, #define _CURSES_COLOR_CONTENT_METHODDEF \ {"color_content", (PyCFunction)_curses_color_content, METH_O, _curses_color_content__doc__}, +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _CURSES_COLOR_CONTENT_IMPL_FUNC _curses_extended_color_content_impl +#else +#define _CURSES_COLOR_CONTENT_IMPL_FUNC _curses_color_content_impl +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + static PyObject * -_curses_color_content_impl(PyObject *module, short color_number); +_CURSES_COLOR_CONTENT_IMPL_FUNC(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); static PyObject * _curses_color_content(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - short color_number; + _NCURSES_COLOR_VAL_TYPE color_number; { long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); goto exit; } else { - color_number = (short) ival; + color_number = (_NCURSES_COLOR_VAL_TYPE) ival; } } - return_value = _curses_color_content_impl(module, color_number); + return_value = _CURSES_COLOR_CONTENT_IMPL_FUNC(module, color_number); exit: return return_value; } +#ifdef _CURSES_COLOR_CONTENT_IMPL_FUNC +#undef _CURSES_COLOR_CONTENT_IMPL_FUNC +#endif /* _CURSES_COLOR_CONTENT_IMPL_FUNC */ + PyDoc_STRVAR(_curses_color_pair__doc__, "color_pair($module, color_number, /)\n" "--\n" @@ -2016,31 +2045,31 @@ PyDoc_STRVAR(_curses_color_pair__doc__, {"color_pair", (PyCFunction)_curses_color_pair, METH_O, _curses_color_pair__doc__}, static PyObject * -_curses_color_pair_impl(PyObject *module, short color_number); +_curses_color_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); static PyObject * _curses_color_pair(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - short color_number; + _NCURSES_COLOR_VAL_TYPE color_number; { long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR "is greater than maximum"); goto exit; } else { - color_number = (short) ival; + color_number = (_NCURSES_COLOR_VAL_TYPE) ival; } } return_value = _curses_color_pair_impl(module, color_number); @@ -2589,18 +2618,25 @@ PyDoc_STRVAR(_curses_init_color__doc__, #define _CURSES_INIT_COLOR_METHODDEF \ {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__}, +#ifdef _NCURSES_EXTENDED_COLOR_FUNCS +#define _CURSES_INIT_COLOR_IMPL_FUNC _curses_init_extended_color_impl +#else +#define _CURSES_INIT_COLOR_IMPL_FUNC _curses_init_color_impl +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + static PyObject * -_curses_init_color_impl(PyObject *module, short color_number, short r, - short g, short b); +_CURSES_INIT_COLOR_IMPL_FUNC(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, + _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, + _NCURSES_COLOR_VAL_TYPE b); static PyObject * _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - short color_number; - short r; - short g; - short b; + _NCURSES_COLOR_VAL_TYPE color_number; + _NCURSES_COLOR_VAL_TYPE r; + _NCURSES_COLOR_VAL_TYPE g; + _NCURSES_COLOR_VAL_TYPE b; if (!_PyArg_CheckPositional("init_color", nargs, 4, 4)) { goto exit; @@ -2610,18 +2646,18 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, "signed short integer is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, "signed short integer is greater than maximum"); goto exit; } else { - color_number = (short) ival; + color_number = (_NCURSES_COLOR_VAL_TYPE) ival; } } { @@ -2629,18 +2665,18 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, "signed short integer is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, "signed short integer is greater than maximum"); goto exit; } else { - r = (short) ival; + r = (_NCURSES_COLOR_VAL_TYPE) ival; } } { @@ -2648,18 +2684,18 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, "signed short integer is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, "signed short integer is greater than maximum"); goto exit; } else { - g = (short) ival; + g = (_NCURSES_COLOR_VAL_TYPE) ival; } } { @@ -2667,26 +2703,30 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, "signed short integer is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, "signed short integer is greater than maximum"); goto exit; } else { - b = (short) ival; + b = (_NCURSES_COLOR_VAL_TYPE) ival; } } - return_value = _curses_init_color_impl(module, color_number, r, g, b); + return_value = _CURSES_INIT_COLOR_IMPL_FUNC(module, color_number, r, g, b); exit: return return_value; } +#ifdef _CURSES_INIT_COLOR_IMPL_FUNC +#undef _CURSES_INIT_COLOR_IMPL_FUNC +#endif /* _CURSES_INIT_COLOR_IMPL_FUNC */ + PyDoc_STRVAR(_curses_init_pair__doc__, "init_pair($module, pair_number, fg, bg, /)\n" "--\n" @@ -2706,17 +2746,23 @@ PyDoc_STRVAR(_curses_init_pair__doc__, #define _CURSES_INIT_PAIR_METHODDEF \ {"init_pair", (PyCFunction)(void(*)(void))_curses_init_pair, METH_FASTCALL, _curses_init_pair__doc__}, +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _CURSES_INIT_PAIR_IMPL_FUNC _curses_init_extended_pair_impl +#else +#define _CURSES_INIT_PAIR_IMPL_FUNC _curses_init_pair_impl +#endif + static PyObject * -_curses_init_pair_impl(PyObject *module, short pair_number, short fg, - short bg); +_CURSES_INIT_PAIR_IMPL_FUNC(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, + _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg); static PyObject * _curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - short pair_number; - short fg; - short bg; + _NCURSES_COLOR_VAL_TYPE pair_number; + _NCURSES_COLOR_VAL_TYPE fg; + _NCURSES_COLOR_VAL_TYPE bg; if (!_PyArg_CheckPositional("init_pair", nargs, 3, 3)) { goto exit; @@ -2726,18 +2772,18 @@ _curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); goto exit; } else { - pair_number = (short) ival; + pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; } } { @@ -2745,18 +2791,18 @@ _curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); goto exit; } else { - fg = (short) ival; + fg = (_NCURSES_COLOR_VAL_TYPE) ival; } } { @@ -2764,26 +2810,30 @@ _curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); goto exit; } else { - bg = (short) ival; + bg = (_NCURSES_COLOR_VAL_TYPE) ival; } } - return_value = _curses_init_pair_impl(module, pair_number, fg, bg); + return_value = _CURSES_INIT_PAIR_IMPL_FUNC(module, pair_number, fg, bg); exit: return return_value; } +#ifdef _CURSES_INIT_PAIR_IMPL_FUNC +#undef _CURSES_INIT_PAIR_IMPL_FUNC +#endif /* _CURSES_INIT_PAIR_IMPL_FUNC */ + PyDoc_STRVAR(_curses_initscr__doc__, "initscr($module, /)\n" "--\n" @@ -3553,40 +3603,50 @@ PyDoc_STRVAR(_curses_pair_content__doc__, #define _CURSES_PAIR_CONTENT_METHODDEF \ {"pair_content", (PyCFunction)_curses_pair_content, METH_O, _curses_pair_content__doc__}, +#ifdef _NCURSES_EXTENDED_COLOR_FUNCS +#define _CURSES_PAIR_CONTENT_IMPL_FUNC _curses_extended_pair_content_impl +#else +#define _CURSES_PAIR_CONTENT_IMPL_FUNC _curses_pair_content_impl +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + static PyObject * -_curses_pair_content_impl(PyObject *module, short pair_number); +_CURSES_PAIR_CONTENT_IMPL_FUNC(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number); static PyObject * _curses_pair_content(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - short pair_number; + _NCURSES_COLOR_VAL_TYPE pair_number; { long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) { goto exit; } - else if (ival < SHRT_MIN) { + else if (ival < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); goto exit; } - else if (ival > SHRT_MAX) { + else if (ival > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); goto exit; } else { - pair_number = (short) ival; + pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; } } - return_value = _curses_pair_content_impl(module, pair_number); + return_value = _CURSES_PAIR_CONTENT_IMPL_FUNC(module, pair_number); exit: return return_value; } +#ifdef _CURSES_PAIR_CONTENT_IMPL_FUNC +#undef _CURSES_PAIR_CONTENT_IMPL_FUNC +#endif /* _CURSES_PAIR_CONTENT_IMPL_FUNC */ + PyDoc_STRVAR(_curses_pair_number__doc__, "pair_number($module, attr, /)\n" "--\n" From 2be663b91b339ca204cfd3f5aa9ef7bc43707047 Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher Date: Wed, 22 May 2019 00:35:00 -0700 Subject: [PATCH 02/30] bpo-36982, bpo-36630: refactor the curses color implementation functions to make them simpler and more maintainable --- Modules/_cursesmodule.c | 137 ++++++++++--------------------- Modules/clinic/_cursesmodule.c.h | 65 +++++---------- 2 files changed, 65 insertions(+), 137 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index d89dba88803d7f..35b9f9f7c6f651 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -408,6 +408,10 @@ static int func_PyCursesInitialisedColor(void) return 1; } +/* _CURSES_FUNC_NAME_STR() is used by some of the */ +/* color functions that have extended color alternatives */ +#define _CURSES_FUNC_NAME_STR(s) #s + /***************************************************************************** The Window Object ******************************************************************************/ @@ -2595,35 +2599,21 @@ A 3-tuple is returned, containing the R, G, B values for the given color, which will be between 0 (no component) and 1000 (maximum amount of component). */ -#ifdef _NCURSES_EXTENDED_COLOR_FUNCS -static PyObject * -_curses_extended_color_content_impl(PyObject *module, int color_number) -{ - int r,g,b; - - PyCursesInitialised; - PyCursesInitialisedColor; - - if (extended_color_content(color_number, &r, &g, &b) != ERR) - return Py_BuildValue("(iii)", r, g, b); - else { - PyErr_SetString(PyCursesError, - "Argument 1 was out of range. Check value of COLORS."); - return NULL; - } -} - -#else /* _NCURSES_EXTENDED_COLOR_FUNCS */ +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _COLOR_CONTENT_FUNC extended_color_content +#else +#define _COLOR_CONTENT_FUNC color_content +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ static PyObject * -_curses_color_content_impl(PyObject *module, short color_number) +_curses_color_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number) { - short r,g,b; + _NCURSES_COLOR_VAL_TYPE r,g,b; PyCursesInitialised; PyCursesInitialisedColor; - if (color_content(color_number, &r, &g, &b) != ERR) + if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) != ERR) return Py_BuildValue("(iii)", r, g, b); else { PyErr_SetString(PyCursesError, @@ -2631,7 +2621,8 @@ _curses_color_content_impl(PyObject *module, short color_number) return NULL; } } -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + +#undef _COLOR_CONTENT_FUNC /*[clinic input] _curses.color_pair @@ -3064,28 +3055,26 @@ most terminals; it is active only if can_change_color() returns 1. */ #ifdef _NCURSES_EXTENDED_COLOR_FUNCS -static PyObject * -_curses_init_extended_color_impl(PyObject *module, int color_number, int r, - int g, int b) -{ - PyCursesInitialised; - PyCursesInitialisedColor; - - return PyCursesCheckERR(init_extended_color(color_number, r, g, b), "init_extended_color"); -} +#define _CURSES_INIT_COLOR_FUNC init_extended_color +#else +#define _CURSES_INIT_COLOR_FUNC init_color +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ -#else /* _NCURSES_EXTENDED_COLOR_FUNCS */ +#define _CURSES_INIT_COLOR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_COLOR_FUNC) static PyObject * -_curses_init_color_impl(PyObject *module, short color_number, short r, - short g, short b) +_curses_init_color_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, + _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, + _NCURSES_COLOR_VAL_TYPE b) { PyCursesInitialised; PyCursesInitialisedColor; - return PyCursesCheckERR(init_color(color_number, r, g, b), "init_color"); + return PyCursesCheckERR(_CURSES_INIT_COLOR_FUNC(color_number, r, g, b), _CURSES_INIT_COLOR_FUNC_NAME); } -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + +#undef _CURSES_INIT_COLOR_FUNC +#undef _CURSES_INIT_COLOR_FUNC_NAME /*[clinic input] _curses.init_pair @@ -3104,47 +3093,26 @@ If the color-pair was previously initialized, the screen is refreshed and all occurrences of that color-pair are changed to the new definition. */ -/* -_curses._curses_init_extended_pair_impl - - pair_number: int - The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)). - fg: int - Foreground color number (0 - COLORS). - bg: int - Background color number (0 - COLORS). - / - -Change the definition of a color-pair. - -If the color-pair was previously initialized, the screen is refreshed and -all occurrences of that color-pair are changed to the new definition. -*/ - #ifdef _NCURSES_EXTENDED_COLOR_FUNCS -static PyObject * -_curses_init_extended_pair_impl(PyObject *module, int pair_number, int fg, - int bg) -{ - PyCursesInitialised; - PyCursesInitialisedColor; - - return PyCursesCheckERR(init_extended_pair(pair_number, fg, bg), "init_extended_pair"); -} +#define _CURSES_INIT_PAIR_FUNC init_extended_pair +#else +#define _CURSES_INIT_PAIR_FUNC init_pair +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ -#else /* _NCURSES_EXTENDED_COLOR_FUNCS */ +#define _CURSES_INIT_PAIR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_PAIR_FUNC) static PyObject * -_curses_init_pair_impl(PyObject *module, short pair_number, short fg, - short bg) -/*[clinic end generated code: output=9c2ce39c22f376b6 input=c9f0b11b17a2ac6d]*/ +_curses_init_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, + _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg) { PyCursesInitialised; PyCursesInitialisedColor; - return PyCursesCheckERR(init_pair(pair_number, fg, bg), "init_pair"); + return PyCursesCheckERR(_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg), _CURSES_INIT_PAIR_FUNC_NAME); } -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + +#undef _CURSES_INIT_PAIR_FUNC +#undef _CURSES_INIT_PAIR_FUNC_NAME static PyObject *ModDict; @@ -3767,35 +3735,21 @@ _curses.pair_content Return a tuple (fg, bg) containing the colors for the requested color pair. */ -#ifdef _NCURSES_EXTENDED_COLOR_FUNCS -static PyObject * -_curses_extended_pair_content_impl(PyObject *module, int pair_number) -{ - int f, b; - - PyCursesInitialised; - PyCursesInitialisedColor; - - if (extended_pair_content(pair_number, &f, &b)!=ERR) { - PyErr_SetString(PyCursesError, - "Argument 1 was out of range. (1..COLOR_PAIRS-1)"); - return NULL; - } - - return Py_BuildValue("(ii)", f, b); -} - -#else /* _NCURSES_EXTENDED_COLOR_FUNCS */ +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _CURSES_PAIR_NUMBER_FUNC extended_pair_content +#else +#define _CURSES_PAIR_NUMBER_FUNC pair_content +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ static PyObject * -_curses_pair_content_impl(PyObject *module, short pair_number) +_curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number) { - short f, b; + _NCURSES_COLOR_VAL_TYPE f, b; PyCursesInitialised; PyCursesInitialisedColor; - if (pair_content(pair_number, &f, &b)==ERR) { + if (_CURSES_PAIR_NUMBER_FUNC(pair_number, &f, &b)==ERR) { PyErr_SetString(PyCursesError, "Argument 1 was out of range. (1..COLOR_PAIRS-1)"); return NULL; @@ -3803,7 +3757,6 @@ _curses_pair_content_impl(PyObject *module, short pair_number) return Py_BuildValue("(ii)", f, b); } -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ /*[clinic input] _curses.pair_number diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 2690ce7f3c7466..6a550191cae19f 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1,20 +1,19 @@ - #if defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) #define _NCURSES_EXTENDED_COLOR_FUNCS 1 #else #define _NCURSES_EXTENDED_COLOR_FUNCS 0 -#endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */ +#endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */ #if _NCURSES_EXTENDED_COLOR_FUNCS -#define _NCURSES_COLOR_VAL_MAX INT_MAX -#define _NCURSES_COLOR_VAL_MIN INT_MIN -#define _NCURSES_COLOR_VAL_TYPE int -#define _NCURSES_COLOR_VAL_TYPE_STR "integer" +#define _NCURSES_COLOR_VAL_MAX INT_MAX +#define _NCURSES_COLOR_VAL_MIN INT_MIN +#define _NCURSES_COLOR_VAL_TYPE int +#define _NCURSES_COLOR_VAL_TYPE_STR "integer" #else -#define _NCURSES_COLOR_VAL_MAX SHRT_MAX -#define _NCURSES_COLOR_VAL_MIN SHRT_MIN -#define _NCURSES_COLOR_VAL_TYPE short -#define _NCURSES_COLOR_VAL_TYPE_STR "short integer" +#define _NCURSES_COLOR_VAL_MAX SHRT_MAX +#define _NCURSES_COLOR_VAL_MIN SHRT_MIN +#define _NCURSES_COLOR_VAL_TYPE short +#define _NCURSES_COLOR_VAL_TYPE_STR "short integer" #endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ /*[clinic input] @@ -1985,14 +1984,8 @@ PyDoc_STRVAR(_curses_color_content__doc__, #define _CURSES_COLOR_CONTENT_METHODDEF \ {"color_content", (PyCFunction)_curses_color_content, METH_O, _curses_color_content__doc__}, -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_COLOR_CONTENT_IMPL_FUNC _curses_extended_color_content_impl -#else -#define _CURSES_COLOR_CONTENT_IMPL_FUNC _curses_color_content_impl -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - static PyObject * -_CURSES_COLOR_CONTENT_IMPL_FUNC(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); +_curses_color_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); static PyObject * _curses_color_content(PyObject *module, PyObject *arg) @@ -2019,7 +2012,7 @@ _curses_color_content(PyObject *module, PyObject *arg) color_number = (_NCURSES_COLOR_VAL_TYPE) ival; } } - return_value = _CURSES_COLOR_CONTENT_IMPL_FUNC(module, color_number); + return_value = _curses_color_content_impl(module, color_number); exit: return return_value; @@ -2618,16 +2611,10 @@ PyDoc_STRVAR(_curses_init_color__doc__, #define _CURSES_INIT_COLOR_METHODDEF \ {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__}, -#ifdef _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_INIT_COLOR_IMPL_FUNC _curses_init_extended_color_impl -#else -#define _CURSES_INIT_COLOR_IMPL_FUNC _curses_init_color_impl -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - static PyObject * -_CURSES_INIT_COLOR_IMPL_FUNC(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, - _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, - _NCURSES_COLOR_VAL_TYPE b); +_curses_init_color_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, + _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, + _NCURSES_COLOR_VAL_TYPE b); static PyObject * _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) @@ -2717,7 +2704,7 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) b = (_NCURSES_COLOR_VAL_TYPE) ival; } } - return_value = _CURSES_INIT_COLOR_IMPL_FUNC(module, color_number, r, g, b); + return_value = _curses_init_color_impl(module, color_number, r, g, b); exit: return return_value; @@ -2746,15 +2733,9 @@ PyDoc_STRVAR(_curses_init_pair__doc__, #define _CURSES_INIT_PAIR_METHODDEF \ {"init_pair", (PyCFunction)(void(*)(void))_curses_init_pair, METH_FASTCALL, _curses_init_pair__doc__}, -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_INIT_PAIR_IMPL_FUNC _curses_init_extended_pair_impl -#else -#define _CURSES_INIT_PAIR_IMPL_FUNC _curses_init_pair_impl -#endif - static PyObject * -_CURSES_INIT_PAIR_IMPL_FUNC(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, - _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg); +_curses_init_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, + _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg); static PyObject * _curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) @@ -2824,7 +2805,7 @@ _curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) bg = (_NCURSES_COLOR_VAL_TYPE) ival; } } - return_value = _CURSES_INIT_PAIR_IMPL_FUNC(module, pair_number, fg, bg); + return_value = _curses_init_pair_impl(module, pair_number, fg, bg); exit: return return_value; @@ -3603,14 +3584,8 @@ PyDoc_STRVAR(_curses_pair_content__doc__, #define _CURSES_PAIR_CONTENT_METHODDEF \ {"pair_content", (PyCFunction)_curses_pair_content, METH_O, _curses_pair_content__doc__}, -#ifdef _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_PAIR_CONTENT_IMPL_FUNC _curses_extended_pair_content_impl -#else -#define _CURSES_PAIR_CONTENT_IMPL_FUNC _curses_pair_content_impl -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - static PyObject * -_CURSES_PAIR_CONTENT_IMPL_FUNC(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number); +_curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number); static PyObject * _curses_pair_content(PyObject *module, PyObject *arg) @@ -3637,7 +3612,7 @@ _curses_pair_content(PyObject *module, PyObject *arg) pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; } } - return_value = _CURSES_PAIR_CONTENT_IMPL_FUNC(module, pair_number); + return_value = _curses_pair_content_impl(module, pair_number); exit: return return_value; From 6893bfe5ef3f7a10b8a852a391e067673377a1d4 Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher Date: Wed, 22 May 2019 17:37:41 -0700 Subject: [PATCH 03/30] bpo-36982, bpo-36630: _NCURSES_EXTENDED_COLOR_FUNCS is always defined, so use #if instead of #ifdef. --- Modules/_cursesmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 35b9f9f7c6f651..e55e2e3a9e8b9d 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3054,7 +3054,7 @@ immediately change to the new definition. This function is a no-op on most terminals; it is active only if can_change_color() returns 1. */ -#ifdef _NCURSES_EXTENDED_COLOR_FUNCS +#if _NCURSES_EXTENDED_COLOR_FUNCS #define _CURSES_INIT_COLOR_FUNC init_extended_color #else #define _CURSES_INIT_COLOR_FUNC init_color @@ -3093,7 +3093,7 @@ If the color-pair was previously initialized, the screen is refreshed and all occurrences of that color-pair are changed to the new definition. */ -#ifdef _NCURSES_EXTENDED_COLOR_FUNCS +#if _NCURSES_EXTENDED_COLOR_FUNCS #define _CURSES_INIT_PAIR_FUNC init_extended_pair #else #define _CURSES_INIT_PAIR_FUNC init_pair From fb6d81e495477248ddf3bc7eb25e651daa9f3a41 Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher Date: Thu, 23 May 2019 20:11:09 -0700 Subject: [PATCH 04/30] bpo-36982: add new function: curses.has_extended_color_support() to indicate whether extended colors are suported by the underlying ncurses library. --- Doc/whatsnew/3.8.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index b6ed2da36889a3..c93be3d22227aa 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -734,6 +734,13 @@ Added a new variable holding structured version information for the underlying ncurses library: :data:`~curses.ncurses_version`. (Contributed by Serhiy Storchaka in :issue:`31680`.) +The extended color functions added in ncurses 6.1 will be used transparently +by :func:`curses.color_content`, :func:`curses.init_color`, +:func:`curses.init_pair`, and :func:`curses.pair_content`. A new function, +:func:`curses.has_extended_color_support`, indicates whether extended color +support is provided by the underlying ncurses library. +(Contributed by Jeffrey Kintscher in :issue:`36982`.) + ctypes ------ From 3d4829928c8d88c3eac0699792482372551ca18a Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher Date: Thu, 23 May 2019 21:13:58 -0700 Subject: [PATCH 05/30] bpo-36982, bpo-36630: add test for curses.has_extended_color_support() --- Lib/test/test_curses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 5e619d13836d26..5456a9fb091e0e 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -231,7 +231,8 @@ def test_module_funcs(self): curses.nocbreak, curses.noecho, curses.nonl, curses.noqiflush, curses.noraw, curses.reset_prog_mode, curses.termattrs, - curses.termname, curses.erasechar]: + curses.termname, curses.erasechar, + curses.has_extended_color_support]: with self.subTest(func=func.__qualname__): func() if hasattr(curses, 'filter'): From 73374336268b1985f182650f425bfcfc09f9386d Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher Date: Fri, 24 May 2019 02:22:01 -0700 Subject: [PATCH 06/30] bpo-36982: reorganize new code to keep clinic happy --- Modules/_cursesmodule.c | 524 ++++++++++++++++++++++++++++--- Modules/clinic/_cursesmodule.c.h | 396 ----------------------- 2 files changed, 485 insertions(+), 435 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index e55e2e3a9e8b9d..dd6691b5d87ec5 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -134,6 +134,24 @@ typedef chtype attr_t; /* No attr_t type is available */ #define STRICT_SYSV_CURSES #endif +#if defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) +#define _NCURSES_EXTENDED_COLOR_FUNCS 1 +#else +#define _NCURSES_EXTENDED_COLOR_FUNCS 0 +#endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */ + +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _NCURSES_COLOR_VAL_MAX INT_MAX +#define _NCURSES_COLOR_VAL_MIN INT_MIN +#define _NCURSES_COLOR_VAL_TYPE int +#define _NCURSES_COLOR_VAL_TYPE_STR "integer" +#else +#define _NCURSES_COLOR_VAL_MAX SHRT_MAX +#define _NCURSES_COLOR_VAL_MIN SHRT_MIN +#define _NCURSES_COLOR_VAL_TYPE short +#define _NCURSES_COLOR_VAL_TYPE_STR "short integer" +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + /*[clinic input] module _curses class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type" @@ -2586,7 +2604,13 @@ _curses_cbreak_impl(PyObject *module, int flag) /*[clinic end generated code: output=9f9dee9664769751 input=150be619eb1f1458]*/ NoArgOrFlagNoReturnFunctionBody(cbreak, flag) -/*[clinic input] +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _COLOR_CONTENT_FUNC extended_color_content +#else +#define _COLOR_CONTENT_FUNC color_content +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + +/* _curses.color_content color_number: short @@ -2599,12 +2623,6 @@ A 3-tuple is returned, containing the R, G, B values for the given color, which will be between 0 (no component) and 1000 (maximum amount of component). */ -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _COLOR_CONTENT_FUNC extended_color_content -#else -#define _COLOR_CONTENT_FUNC color_content -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - static PyObject * _curses_color_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number) { @@ -2624,10 +2642,64 @@ _curses_color_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_numbe #undef _COLOR_CONTENT_FUNC -/*[clinic input] +PyDoc_STRVAR(_curses_color_content__doc__, +"color_content($module, color_number, /)\n" +"--\n" +"\n" +"Return the red, green, and blue (RGB) components of the specified color.\n" +"\n" +" color_number\n" +" The number of the color (0 - COLORS).\n" +"\n" +"A 3-tuple is returned, containing the R, G, B values for the given color,\n" +"which will be between 0 (no component) and 1000 (maximum amount of component)."); + +#define _CURSES_COLOR_CONTENT_METHODDEF \ + {"color_content", (PyCFunction)_curses_color_content, METH_O, _curses_color_content__doc__}, + +static PyObject * +_curses_color_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); + +static PyObject * +_curses_color_content(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + _NCURSES_COLOR_VAL_TYPE color_number; + + if (PyFloat_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + goto exit; + } + else { + color_number = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + return_value = _curses_color_content_impl(module, color_number); + +exit: + return return_value; +} + +/* _curses.color_pair - color_number: short + color_number: _NCURSES_COLOR_VAL_TYPE The number of the color (0 - COLORS). / @@ -2646,6 +2718,60 @@ _curses_color_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number) return PyLong_FromLong(color_pair_to_attr(color_number)); } +PyDoc_STRVAR(_curses_color_pair__doc__, +"color_pair($module, color_number, /)\n" +"--\n" +"\n" +"Return the attribute value for displaying text in the specified color.\n" +"\n" +" color_number\n" +" The number of the color (0 - COLORS).\n" +"\n" +"This attribute value can be combined with A_STANDOUT, A_REVERSE, and the\n" +"other A_* attributes. pair_number() is the counterpart to this function."); + +#define _CURSES_COLOR_PAIR_METHODDEF \ + {"color_pair", (PyCFunction)_curses_color_pair, METH_O, _curses_color_pair__doc__}, + +static PyObject * +_curses_color_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); + +static PyObject * +_curses_color_pair(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + _NCURSES_COLOR_VAL_TYPE color_number; + + if (PyFloat_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR "is greater than maximum"); + goto exit; + } + else { + color_number = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + return_value = _curses_color_pair_impl(module, color_number); + +exit: + return return_value; +} + /*[clinic input] _curses.curs_set @@ -3034,16 +3160,24 @@ _curses_has_key_impl(PyObject *module, int key) } #endif -/*[clinic input] +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _CURSES_INIT_COLOR_FUNC init_extended_color +#else +#define _CURSES_INIT_COLOR_FUNC init_color +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + +#define _CURSES_INIT_COLOR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_COLOR_FUNC) + +/* _curses.init_color - color_number: short + color_number: _NCURSES_COLOR_VAL_TYPE The number of the color to be changed (0 - COLORS). - r: short + r: _NCURSES_COLOR_VAL_TYPE Red component (0 - 1000). - g: short + g: _NCURSES_COLOR_VAL_TYPE Green component (0 - 1000). - b: short + b: _NCURSES_COLOR_VAL_TYPE Blue component (0 - 1000). / @@ -3054,14 +3188,6 @@ immediately change to the new definition. This function is a no-op on most terminals; it is active only if can_change_color() returns 1. */ -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_INIT_COLOR_FUNC init_extended_color -#else -#define _CURSES_INIT_COLOR_FUNC init_color -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - -#define _CURSES_INIT_COLOR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_COLOR_FUNC) - static PyObject * _curses_init_color_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, @@ -3076,7 +3202,156 @@ _curses_init_color_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, #undef _CURSES_INIT_COLOR_FUNC #undef _CURSES_INIT_COLOR_FUNC_NAME -/*[clinic input] +PyDoc_STRVAR(_curses_init_color__doc__, +"init_color($module, color_number, r, g, b, /)\n" +"--\n" +"\n" +"Change the definition of a color.\n" +"\n" +" color_number\n" +" The number of the color to be changed (0 - COLORS).\n" +" r\n" +" Red component (0 - 1000).\n" +" g\n" +" Green component (0 - 1000).\n" +" b\n" +" Blue component (0 - 1000).\n" +"\n" +"When init_color() is used, all occurrences of that color on the screen\n" +"immediately change to the new definition. This function is a no-op on\n" +"most terminals; it is active only if can_change_color() returns 1."); + +#define _CURSES_INIT_COLOR_METHODDEF \ + {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__}, + +static PyObject * +_curses_init_color_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, + _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, + _NCURSES_COLOR_VAL_TYPE b); + +static PyObject * +_curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + _NCURSES_COLOR_VAL_TYPE color_number; + _NCURSES_COLOR_VAL_TYPE r; + _NCURSES_COLOR_VAL_TYPE g; + _NCURSES_COLOR_VAL_TYPE b; + + if (!_PyArg_CheckPositional("init_color", nargs, 4, 4)) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(args[0]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + color_number = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + if (PyFloat_Check(args[1])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(args[1]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + r = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(args[2]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + g = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + if (PyFloat_Check(args[3])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(args[3]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + b = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + return_value = _curses_init_color_impl(module, color_number, r, g, b); + +exit: + return return_value; +} + +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _CURSES_INIT_PAIR_FUNC init_extended_pair +#else +#define _CURSES_INIT_PAIR_FUNC init_pair +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + +#define _CURSES_INIT_PAIR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_PAIR_FUNC) + +/* _curses.init_pair pair_number: short @@ -3093,14 +3368,6 @@ If the color-pair was previously initialized, the screen is refreshed and all occurrences of that color-pair are changed to the new definition. */ -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_INIT_PAIR_FUNC init_extended_pair -#else -#define _CURSES_INIT_PAIR_FUNC init_pair -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - -#define _CURSES_INIT_PAIR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_PAIR_FUNC) - static PyObject * _curses_init_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg) @@ -3114,6 +3381,118 @@ _curses_init_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, #undef _CURSES_INIT_PAIR_FUNC #undef _CURSES_INIT_PAIR_FUNC_NAME +PyDoc_STRVAR(_curses_init_pair__doc__, +"init_pair($module, pair_number, fg, bg, /)\n" +"--\n" +"\n" +"Change the definition of a color-pair.\n" +"\n" +" pair_number\n" +" The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)).\n" +" fg\n" +" Foreground color number (0 - COLORS).\n" +" bg\n" +" Background color number (0 - COLORS).\n" +"\n" +"If the color-pair was previously initialized, the screen is refreshed and\n" +"all occurrences of that color-pair are changed to the new definition."); + +#define _CURSES_INIT_PAIR_METHODDEF \ + {"init_pair", (PyCFunction)(void(*)(void))_curses_init_pair, METH_FASTCALL, _curses_init_pair__doc__}, + +static PyObject * +_curses_init_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, + _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg); + +static PyObject * +_curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + _NCURSES_COLOR_VAL_TYPE pair_number; + _NCURSES_COLOR_VAL_TYPE fg; + _NCURSES_COLOR_VAL_TYPE bg; + + if (!_PyArg_CheckPositional("init_pair", nargs, 3, 3)) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(args[0]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + goto exit; + } + else { + pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + if (PyFloat_Check(args[1])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(args[1]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + goto exit; + } + else { + fg = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(args[2]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + goto exit; + } + else { + bg = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + return_value = _curses_init_pair_impl(module, pair_number, fg, bg); + +exit: + return return_value; +} + static PyObject *ModDict; /*[clinic input] @@ -3725,22 +4104,22 @@ _curses_noraw_impl(PyObject *module) /*[clinic end generated code: output=39894e5524c430cc input=6ec86692096dffb5]*/ NoArgNoReturnFunctionBody(noraw) -/*[clinic input] +#if _NCURSES_EXTENDED_COLOR_FUNCS +#define _CURSES_PAIR_NUMBER_FUNC extended_pair_content +#else +#define _CURSES_PAIR_NUMBER_FUNC pair_content +#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ + +/* _curses.pair_content - pair_number: short + pair_number: _NCURSES_COLOR_VAL_TYPE The number of the color pair (1 - (COLOR_PAIRS-1)). / Return a tuple (fg, bg) containing the colors for the requested color pair. */ -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_PAIR_NUMBER_FUNC extended_pair_content -#else -#define _CURSES_PAIR_NUMBER_FUNC pair_content -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - static PyObject * _curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number) { @@ -3758,6 +4137,57 @@ _curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number) return Py_BuildValue("(ii)", f, b); } +PyDoc_STRVAR(_curses_pair_content__doc__, +"pair_content($module, pair_number, /)\n" +"--\n" +"\n" +"Return a tuple (fg, bg) containing the colors for the requested color pair.\n" +"\n" +" pair_number\n" +" The number of the color pair (1 - (COLOR_PAIRS-1))."); + +#define _CURSES_PAIR_CONTENT_METHODDEF \ + {"pair_content", (PyCFunction)_curses_pair_content, METH_O, _curses_pair_content__doc__}, + +static PyObject * +_curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number); + +static PyObject * +_curses_pair_content(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + _NCURSES_COLOR_VAL_TYPE pair_number; + + if (PyFloat_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + goto exit; + } + else { + pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + return_value = _curses_pair_content_impl(module, pair_number); + +exit: + return return_value; +} + /*[clinic input] _curses.pair_number @@ -4486,6 +4916,22 @@ make_ncurses_version(void) #endif /* NCURSES_VERSION */ +PyDoc_STRVAR(_curses_has_extended_color_support__doc__, +"has_extended_color_support($module, /)\n" +"--\n" +"\n" +"Return True if the module supports extended colors; otherwise, return\n" +"False. Extended color support allows more than 256 color-pairs for terminals\n" +"that support more than 16 colors (e.g. xterm-256color).\n"); + +#define _CURSES_HAS_EXTENDED_COLOR_SUPPORT_METHODDEF \ + {"has_extended_color_support", (PyCFunction)_curses_has_extended_color_support, METH_NOARGS, _curses_has_extended_color_support__doc__}, + +static PyObject * +_curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return PyBool_FromLong(_NCURSES_EXTENDED_COLOR_FUNCS); +} /* List of functions defined in the module */ diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 6a550191cae19f..cd075b351cb962 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1,21 +1,3 @@ -#if defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) -#define _NCURSES_EXTENDED_COLOR_FUNCS 1 -#else -#define _NCURSES_EXTENDED_COLOR_FUNCS 0 -#endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */ - -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _NCURSES_COLOR_VAL_MAX INT_MAX -#define _NCURSES_COLOR_VAL_MIN INT_MIN -#define _NCURSES_COLOR_VAL_TYPE int -#define _NCURSES_COLOR_VAL_TYPE_STR "integer" -#else -#define _NCURSES_COLOR_VAL_MAX SHRT_MAX -#define _NCURSES_COLOR_VAL_MIN SHRT_MIN -#define _NCURSES_COLOR_VAL_TYPE short -#define _NCURSES_COLOR_VAL_TYPE_STR "short integer" -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - /*[clinic input] preserve [clinic start generated code]*/ @@ -1969,108 +1951,6 @@ _curses_cbreak(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -PyDoc_STRVAR(_curses_color_content__doc__, -"color_content($module, color_number, /)\n" -"--\n" -"\n" -"Return the red, green, and blue (RGB) components of the specified color.\n" -"\n" -" color_number\n" -" The number of the color (0 - COLORS).\n" -"\n" -"A 3-tuple is returned, containing the R, G, B values for the given color,\n" -"which will be between 0 (no component) and 1000 (maximum amount of component)."); - -#define _CURSES_COLOR_CONTENT_METHODDEF \ - {"color_content", (PyCFunction)_curses_color_content, METH_O, _curses_color_content__doc__}, - -static PyObject * -_curses_color_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); - -static PyObject * -_curses_color_content(PyObject *module, PyObject *arg) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE color_number; - - { - long ival = PyLong_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - color_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - return_value = _curses_color_content_impl(module, color_number); - -exit: - return return_value; -} - -#ifdef _CURSES_COLOR_CONTENT_IMPL_FUNC -#undef _CURSES_COLOR_CONTENT_IMPL_FUNC -#endif /* _CURSES_COLOR_CONTENT_IMPL_FUNC */ - -PyDoc_STRVAR(_curses_color_pair__doc__, -"color_pair($module, color_number, /)\n" -"--\n" -"\n" -"Return the attribute value for displaying text in the specified color.\n" -"\n" -" color_number\n" -" The number of the color (0 - COLORS).\n" -"\n" -"This attribute value can be combined with A_STANDOUT, A_REVERSE, and the\n" -"other A_* attributes. pair_number() is the counterpart to this function."); - -#define _CURSES_COLOR_PAIR_METHODDEF \ - {"color_pair", (PyCFunction)_curses_color_pair, METH_O, _curses_color_pair__doc__}, - -static PyObject * -_curses_color_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); - -static PyObject * -_curses_color_pair(PyObject *module, PyObject *arg) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE color_number; - - { - long ival = PyLong_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR "is greater than maximum"); - goto exit; - } - else { - color_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - return_value = _curses_color_pair_impl(module, color_number); - -exit: - return return_value; -} - PyDoc_STRVAR(_curses_curs_set__doc__, "curs_set($module, visibility, /)\n" "--\n" @@ -2589,232 +2469,6 @@ _curses_has_key(PyObject *module, PyObject *arg) #endif /* defined(HAVE_CURSES_HAS_KEY) */ -PyDoc_STRVAR(_curses_init_color__doc__, -"init_color($module, color_number, r, g, b, /)\n" -"--\n" -"\n" -"Change the definition of a color.\n" -"\n" -" color_number\n" -" The number of the color to be changed (0 - COLORS).\n" -" r\n" -" Red component (0 - 1000).\n" -" g\n" -" Green component (0 - 1000).\n" -" b\n" -" Blue component (0 - 1000).\n" -"\n" -"When init_color() is used, all occurrences of that color on the screen\n" -"immediately change to the new definition. This function is a no-op on\n" -"most terminals; it is active only if can_change_color() returns 1."); - -#define _CURSES_INIT_COLOR_METHODDEF \ - {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__}, - -static PyObject * -_curses_init_color_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, - _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, - _NCURSES_COLOR_VAL_TYPE b); - -static PyObject * -_curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE color_number; - _NCURSES_COLOR_VAL_TYPE r; - _NCURSES_COLOR_VAL_TYPE g; - _NCURSES_COLOR_VAL_TYPE b; - - if (!_PyArg_CheckPositional("init_color", nargs, 4, 4)) { - goto exit; - } - { - long ival = PyLong_AsLong(args[0]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - color_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - { - long ival = PyLong_AsLong(args[1]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - r = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - { - long ival = PyLong_AsLong(args[2]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - g = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - { - long ival = PyLong_AsLong(args[3]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - b = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - return_value = _curses_init_color_impl(module, color_number, r, g, b); - -exit: - return return_value; -} - -#ifdef _CURSES_INIT_COLOR_IMPL_FUNC -#undef _CURSES_INIT_COLOR_IMPL_FUNC -#endif /* _CURSES_INIT_COLOR_IMPL_FUNC */ - -PyDoc_STRVAR(_curses_init_pair__doc__, -"init_pair($module, pair_number, fg, bg, /)\n" -"--\n" -"\n" -"Change the definition of a color-pair.\n" -"\n" -" pair_number\n" -" The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)).\n" -" fg\n" -" Foreground color number (0 - COLORS).\n" -" bg\n" -" Background color number (0 - COLORS).\n" -"\n" -"If the color-pair was previously initialized, the screen is refreshed and\n" -"all occurrences of that color-pair are changed to the new definition."); - -#define _CURSES_INIT_PAIR_METHODDEF \ - {"init_pair", (PyCFunction)(void(*)(void))_curses_init_pair, METH_FASTCALL, _curses_init_pair__doc__}, - -static PyObject * -_curses_init_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, - _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg); - -static PyObject * -_curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE pair_number; - _NCURSES_COLOR_VAL_TYPE fg; - _NCURSES_COLOR_VAL_TYPE bg; - - if (!_PyArg_CheckPositional("init_pair", nargs, 3, 3)) { - goto exit; - } - { - long ival = PyLong_AsLong(args[0]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - { - long ival = PyLong_AsLong(args[1]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - fg = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - { - long ival = PyLong_AsLong(args[2]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - bg = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - return_value = _curses_init_pair_impl(module, pair_number, fg, bg); - -exit: - return return_value; -} - -#ifdef _CURSES_INIT_PAIR_IMPL_FUNC -#undef _CURSES_INIT_PAIR_IMPL_FUNC -#endif /* _CURSES_INIT_PAIR_IMPL_FUNC */ - PyDoc_STRVAR(_curses_initscr__doc__, "initscr($module, /)\n" "--\n" @@ -3572,56 +3226,6 @@ _curses_noraw(PyObject *module, PyObject *Py_UNUSED(ignored)) return _curses_noraw_impl(module); } -PyDoc_STRVAR(_curses_pair_content__doc__, -"pair_content($module, pair_number, /)\n" -"--\n" -"\n" -"Return a tuple (fg, bg) containing the colors for the requested color pair.\n" -"\n" -" pair_number\n" -" The number of the color pair (1 - (COLOR_PAIRS-1))."); - -#define _CURSES_PAIR_CONTENT_METHODDEF \ - {"pair_content", (PyCFunction)_curses_pair_content, METH_O, _curses_pair_content__doc__}, - -static PyObject * -_curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number); - -static PyObject * -_curses_pair_content(PyObject *module, PyObject *arg) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE pair_number; - - { - long ival = PyLong_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - return_value = _curses_pair_content_impl(module, pair_number); - -exit: - return return_value; -} - -#ifdef _CURSES_PAIR_CONTENT_IMPL_FUNC -#undef _CURSES_PAIR_CONTENT_IMPL_FUNC -#endif /* _CURSES_PAIR_CONTENT_IMPL_FUNC */ - PyDoc_STRVAR(_curses_pair_number__doc__, "pair_number($module, attr, /)\n" "--\n" From de55056a19d6b7a9b74d1dae1d4506baf3b861ea Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" Date: Sat, 25 May 2019 05:27:39 +0000 Subject: [PATCH 07/30] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core and Builtins/2019-05-25-05-27-39.bpo-36982.0UHgfB.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-05-25-05-27-39.bpo-36982.0UHgfB.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-25-05-27-39.bpo-36982.0UHgfB.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-25-05-27-39.bpo-36982.0UHgfB.rst new file mode 100644 index 00000000000000..f105f1857d487f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-25-05-27-39.bpo-36982.0UHgfB.rst @@ -0,0 +1 @@ +Use ncurses extended color functions when available to support terminals with 256 colors, and add the new function :func:`curses.has_extended_color_support` to indicate whether extended color support is provided by the underlying ncurses library. \ No newline at end of file From a3827ec59d8a7494c934b5023d8aaab055308016 Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher Date: Wed, 29 May 2019 13:28:53 -0700 Subject: [PATCH 08/30] bpo-36982: refactor color-pair functions to use clinic --- Modules/_cursesmodule.c | 516 ++++++++----------------------- Modules/clinic/_cursesmodule.c.h | 245 +++++++++++++++ 2 files changed, 373 insertions(+), 388 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index dd6691b5d87ec5..4f6ad222431118 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2610,10 +2610,10 @@ NoArgOrFlagNoReturnFunctionBody(cbreak, flag) #define _COLOR_CONTENT_FUNC color_content #endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ -/* +/*[clinic input] _curses.color_content - color_number: short + color_number: int The number of the color (0 - COLORS). / @@ -2621,85 +2621,44 @@ Return the red, green, and blue (RGB) components of the specified color. A 3-tuple is returned, containing the R, G, B values for the given color, which will be between 0 (no component) and 1000 (maximum amount of component). -*/ +[clinic start generated code]*/ static PyObject * -_curses_color_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number) +_curses_color_content_impl(PyObject *module, int color_number) +/*[clinic end generated code: output=17b466df7054e0de input=badb7d68ffbb0e93]*/ { + PyObject *return_value = NULL; _NCURSES_COLOR_VAL_TYPE r,g,b; PyCursesInitialised; PyCursesInitialisedColor; + if (color_number < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + return NULL; + } + else if (color_number > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + return NULL; + } + if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) != ERR) - return Py_BuildValue("(iii)", r, g, b); - else { + return_value = Py_BuildValue("(iii)", r, g, b); + else PyErr_SetString(PyCursesError, "Argument 1 was out of range. Check value of COLORS."); - return NULL; - } -} - -#undef _COLOR_CONTENT_FUNC - -PyDoc_STRVAR(_curses_color_content__doc__, -"color_content($module, color_number, /)\n" -"--\n" -"\n" -"Return the red, green, and blue (RGB) components of the specified color.\n" -"\n" -" color_number\n" -" The number of the color (0 - COLORS).\n" -"\n" -"A 3-tuple is returned, containing the R, G, B values for the given color,\n" -"which will be between 0 (no component) and 1000 (maximum amount of component)."); - -#define _CURSES_COLOR_CONTENT_METHODDEF \ - {"color_content", (PyCFunction)_curses_color_content, METH_O, _curses_color_content__doc__}, - -static PyObject * -_curses_color_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); - -static PyObject * -_curses_color_content(PyObject *module, PyObject *arg) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE color_number; - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } - { - long ival = PyLong_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - color_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - return_value = _curses_color_content_impl(module, color_number); - -exit: return return_value; } -/* +#undef _COLOR_CONTENT_FUNC + +/*[clinic input] _curses.color_pair - color_number: _NCURSES_COLOR_VAL_TYPE + color_number: int The number of the color (0 - COLORS). / @@ -2707,69 +2666,27 @@ Return the attribute value for displaying text in the specified color. This attribute value can be combined with A_STANDOUT, A_REVERSE, and the other A_* attributes. pair_number() is the counterpart to this function. -*/ +[clinic start generated code]*/ static PyObject * -_curses_color_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number) +_curses_color_pair_impl(PyObject *module, int color_number) +/*[clinic end generated code: output=3fd752e8e24c93fb input=d4ed7238735f1647]*/ { PyCursesInitialised; PyCursesInitialisedColor; - return PyLong_FromLong(color_pair_to_attr(color_number)); -} - -PyDoc_STRVAR(_curses_color_pair__doc__, -"color_pair($module, color_number, /)\n" -"--\n" -"\n" -"Return the attribute value for displaying text in the specified color.\n" -"\n" -" color_number\n" -" The number of the color (0 - COLORS).\n" -"\n" -"This attribute value can be combined with A_STANDOUT, A_REVERSE, and the\n" -"other A_* attributes. pair_number() is the counterpart to this function."); - -#define _CURSES_COLOR_PAIR_METHODDEF \ - {"color_pair", (PyCFunction)_curses_color_pair, METH_O, _curses_color_pair__doc__}, - -static PyObject * -_curses_color_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number); - -static PyObject * -_curses_color_pair(PyObject *module, PyObject *arg) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE color_number; - - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; + if (color_number < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + return NULL; } - { - long ival = PyLong_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR "is greater than maximum"); - goto exit; - } - else { - color_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } + else if (color_number > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR "is greater than maximum"); + return NULL; } - return_value = _curses_color_pair_impl(module, color_number); -exit: - return return_value; + return PyLong_FromLong((long) (color_number << 8)); } /*[clinic input] @@ -3171,13 +3088,13 @@ _curses_has_key_impl(PyObject *module, int key) /* _curses.init_color - color_number: _NCURSES_COLOR_VAL_TYPE + color_number: int The number of the color to be changed (0 - COLORS). - r: _NCURSES_COLOR_VAL_TYPE + r: int Red component (0 - 1000). - g: _NCURSES_COLOR_VAL_TYPE + g: int Green component (0 - 1000). - b: _NCURSES_COLOR_VAL_TYPE + b: int Blue component (0 - 1000). / @@ -3186,163 +3103,66 @@ Change the definition of a color. When init_color() is used, all occurrences of that color on the screen immediately change to the new definition. This function is a no-op on most terminals; it is active only if can_change_color() returns 1. -*/ +[clinic start generated code]*/ static PyObject * -_curses_init_color_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, - _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, - _NCURSES_COLOR_VAL_TYPE b) +_curses_init_color_impl(PyObject *module, int color_number, int r, int g, + int b) +/*[clinic end generated code: output=3824cf242d9174fc input=3ba3d1700bff7a8a]*/ { PyCursesInitialised; PyCursesInitialisedColor; - return PyCursesCheckERR(_CURSES_INIT_COLOR_FUNC(color_number, r, g, b), _CURSES_INIT_COLOR_FUNC_NAME); -} - -#undef _CURSES_INIT_COLOR_FUNC -#undef _CURSES_INIT_COLOR_FUNC_NAME - -PyDoc_STRVAR(_curses_init_color__doc__, -"init_color($module, color_number, r, g, b, /)\n" -"--\n" -"\n" -"Change the definition of a color.\n" -"\n" -" color_number\n" -" The number of the color to be changed (0 - COLORS).\n" -" r\n" -" Red component (0 - 1000).\n" -" g\n" -" Green component (0 - 1000).\n" -" b\n" -" Blue component (0 - 1000).\n" -"\n" -"When init_color() is used, all occurrences of that color on the screen\n" -"immediately change to the new definition. This function is a no-op on\n" -"most terminals; it is active only if can_change_color() returns 1."); - -#define _CURSES_INIT_COLOR_METHODDEF \ - {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__}, - -static PyObject * -_curses_init_color_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE color_number, - _NCURSES_COLOR_VAL_TYPE r, _NCURSES_COLOR_VAL_TYPE g, - _NCURSES_COLOR_VAL_TYPE b); - -static PyObject * -_curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE color_number; - _NCURSES_COLOR_VAL_TYPE r; - _NCURSES_COLOR_VAL_TYPE g; - _NCURSES_COLOR_VAL_TYPE b; - - if (!_PyArg_CheckPositional("init_color", nargs, 4, 4)) { - goto exit; - } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; + if (color_number < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + return NULL; } - { - long ival = PyLong_AsLong(args[0]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - color_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } + else if (color_number > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + return NULL; } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; + + if (r < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + return NULL; } - { - long ival = PyLong_AsLong(args[1]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - r = (_NCURSES_COLOR_VAL_TYPE) ival; - } + else if (r > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + return NULL; } - if (PyFloat_Check(args[2])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; + + if (g < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + return NULL; } - { - long ival = PyLong_AsLong(args[2]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - g = (_NCURSES_COLOR_VAL_TYPE) ival; - } + else if (g > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + return NULL; } - if (PyFloat_Check(args[3])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; + + if (b < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + return NULL; } - { - long ival = PyLong_AsLong(args[3]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - b = (_NCURSES_COLOR_VAL_TYPE) ival; - } + else if (b > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + return NULL; } - return_value = _curses_init_color_impl(module, color_number, r, g, b); -exit: - return return_value; + return PyCursesCheckERR(_CURSES_INIT_COLOR_FUNC(color_number, r, g, b), _CURSES_INIT_COLOR_FUNC_NAME); } +#undef _CURSES_INIT_COLOR_FUNC +#undef _CURSES_INIT_COLOR_FUNC_NAME + #if _NCURSES_EXTENDED_COLOR_FUNCS #define _CURSES_INIT_PAIR_FUNC init_extended_pair #else @@ -3351,14 +3171,14 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) #define _CURSES_INIT_PAIR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_PAIR_FUNC) -/* +/*[clinic input] _curses.init_pair - pair_number: short + pair_number: int The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)). - fg: short + fg: int Foreground color number (0 - COLORS). - bg: short + bg: int Background color number (0 - COLORS). / @@ -3366,133 +3186,54 @@ Change the definition of a color-pair. If the color-pair was previously initialized, the screen is refreshed and all occurrences of that color-pair are changed to the new definition. -*/ +[clinic start generated code]*/ static PyObject * -_curses_init_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, - _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg) +_curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) +/*[clinic end generated code: output=a0bba03d2bbc3ee6 input=defd89de917781dc]*/ { PyCursesInitialised; PyCursesInitialisedColor; - return PyCursesCheckERR(_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg), _CURSES_INIT_PAIR_FUNC_NAME); -} - -#undef _CURSES_INIT_PAIR_FUNC -#undef _CURSES_INIT_PAIR_FUNC_NAME - -PyDoc_STRVAR(_curses_init_pair__doc__, -"init_pair($module, pair_number, fg, bg, /)\n" -"--\n" -"\n" -"Change the definition of a color-pair.\n" -"\n" -" pair_number\n" -" The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)).\n" -" fg\n" -" Foreground color number (0 - COLORS).\n" -" bg\n" -" Background color number (0 - COLORS).\n" -"\n" -"If the color-pair was previously initialized, the screen is refreshed and\n" -"all occurrences of that color-pair are changed to the new definition."); - -#define _CURSES_INIT_PAIR_METHODDEF \ - {"init_pair", (PyCFunction)(void(*)(void))_curses_init_pair, METH_FASTCALL, _curses_init_pair__doc__}, - -static PyObject * -_curses_init_pair_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number, - _NCURSES_COLOR_VAL_TYPE fg, _NCURSES_COLOR_VAL_TYPE bg); - -static PyObject * -_curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE pair_number; - _NCURSES_COLOR_VAL_TYPE fg; - _NCURSES_COLOR_VAL_TYPE bg; - - if (!_PyArg_CheckPositional("init_pair", nargs, 3, 3)) { - goto exit; - } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; + if (pair_number < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + return NULL; } - { - long ival = PyLong_AsLong(args[0]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } + else if (pair_number > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + return NULL; } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; + + if (fg < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + return NULL; } - { - long ival = PyLong_AsLong(args[1]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - fg = (_NCURSES_COLOR_VAL_TYPE) ival; - } + else if (fg > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + return NULL; } - if (PyFloat_Check(args[2])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; + + if (bg < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + return NULL; } - { - long ival = PyLong_AsLong(args[2]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - bg = (_NCURSES_COLOR_VAL_TYPE) ival; - } + else if (bg > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + return NULL; } - return_value = _curses_init_pair_impl(module, pair_number, fg, bg); -exit: - return return_value; + return PyCursesCheckERR(_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg), _CURSES_INIT_PAIR_FUNC_NAME); } +#undef _CURSES_INIT_PAIR_FUNC +#undef _CURSES_INIT_PAIR_FUNC_NAME + static PyObject *ModDict; /*[clinic input] @@ -4916,19 +4657,18 @@ make_ncurses_version(void) #endif /* NCURSES_VERSION */ -PyDoc_STRVAR(_curses_has_extended_color_support__doc__, -"has_extended_color_support($module, /)\n" -"--\n" -"\n" -"Return True if the module supports extended colors; otherwise, return\n" -"False. Extended color support allows more than 256 color-pairs for terminals\n" -"that support more than 16 colors (e.g. xterm-256color).\n"); +/*[clinic input] +_curses.has_extended_color_support -#define _CURSES_HAS_EXTENDED_COLOR_SUPPORT_METHODDEF \ - {"has_extended_color_support", (PyCFunction)_curses_has_extended_color_support, METH_NOARGS, _curses_has_extended_color_support__doc__}, +Return True if the module supports extended colors; otherwise, return False. + +Extended color support allows more than 256 color-pairs for terminals +that support more than 16 colors (e.g. xterm-256color). +[clinic start generated code]*/ static PyObject * -_curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored)) +_curses_has_extended_color_support_impl(PyObject *module) +/*[clinic end generated code: output=68f1be2b57d92e22 input=4b905f046e35ee9f]*/ { return PyBool_FromLong(_NCURSES_EXTENDED_COLOR_FUNCS); } diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index cd075b351cb962..6a49ff8735de54 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1951,6 +1951,84 @@ _curses_cbreak(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +PyDoc_STRVAR(_curses_color_content__doc__, +"color_content($module, color_number, /)\n" +"--\n" +"\n" +"Return the red, green, and blue (RGB) components of the specified color.\n" +"\n" +" color_number\n" +" The number of the color (0 - COLORS).\n" +"\n" +"A 3-tuple is returned, containing the R, G, B values for the given color,\n" +"which will be between 0 (no component) and 1000 (maximum amount of component)."); + +#define _CURSES_COLOR_CONTENT_METHODDEF \ + {"color_content", (PyCFunction)_curses_color_content, METH_O, _curses_color_content__doc__}, + +static PyObject * +_curses_color_content_impl(PyObject *module, int color_number); + +static PyObject * +_curses_color_content(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int color_number; + + if (PyFloat_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + color_number = _PyLong_AsInt(arg); + if (color_number == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _curses_color_content_impl(module, color_number); + +exit: + return return_value; +} + +PyDoc_STRVAR(_curses_color_pair__doc__, +"color_pair($module, color_number, /)\n" +"--\n" +"\n" +"Return the attribute value for displaying text in the specified color.\n" +"\n" +" color_number\n" +" The number of the color (0 - COLORS).\n" +"\n" +"This attribute value can be combined with A_STANDOUT, A_REVERSE, and the\n" +"other A_* attributes. pair_number() is the counterpart to this function."); + +#define _CURSES_COLOR_PAIR_METHODDEF \ + {"color_pair", (PyCFunction)_curses_color_pair, METH_O, _curses_color_pair__doc__}, + +static PyObject * +_curses_color_pair_impl(PyObject *module, int color_number); + +static PyObject * +_curses_color_pair(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int color_number; + + if (PyFloat_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + color_number = _PyLong_AsInt(arg); + if (color_number == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _curses_color_pair_impl(module, color_number); + +exit: + return return_value; +} + PyDoc_STRVAR(_curses_curs_set__doc__, "curs_set($module, visibility, /)\n" "--\n" @@ -2469,6 +2547,152 @@ _curses_has_key(PyObject *module, PyObject *arg) #endif /* defined(HAVE_CURSES_HAS_KEY) */ +PyDoc_STRVAR(_curses_init_color__doc__, +"init_color($module, color_number, r, g, b, /)\n" +"--\n" +"\n" +"Change the definition of a color.\n" +"\n" +" color_number\n" +" The number of the color to be changed (0 - COLORS).\n" +" r\n" +" Red component (0 - 1000).\n" +" g\n" +" Green component (0 - 1000).\n" +" b\n" +" Blue component (0 - 1000).\n" +"\n" +"When init_color() is used, all occurrences of that color on the screen\n" +"immediately change to the new definition. This function is a no-op on\n" +"most terminals; it is active only if can_change_color() returns 1."); + +#define _CURSES_INIT_COLOR_METHODDEF \ + {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__}, + +static PyObject * +_curses_init_color_impl(PyObject *module, int color_number, int r, int g, + int b); + +static PyObject * +_curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int color_number; + int r; + int g; + int b; + + if (!_PyArg_CheckPositional("init_color", nargs, 4, 4)) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + color_number = _PyLong_AsInt(args[0]); + if (color_number == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[1])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + r = _PyLong_AsInt(args[1]); + if (r == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + g = _PyLong_AsInt(args[2]); + if (g == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[3])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + b = _PyLong_AsInt(args[3]); + if (b == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _curses_init_color_impl(module, color_number, r, g, b); + +exit: + return return_value; +} + +PyDoc_STRVAR(_curses_init_pair__doc__, +"init_pair($module, pair_number, fg, bg, /)\n" +"--\n" +"\n" +"Change the definition of a color-pair.\n" +"\n" +" pair_number\n" +" The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)).\n" +" fg\n" +" Foreground color number (0 - COLORS).\n" +" bg\n" +" Background color number (0 - COLORS).\n" +"\n" +"If the color-pair was previously initialized, the screen is refreshed and\n" +"all occurrences of that color-pair are changed to the new definition."); + +#define _CURSES_INIT_PAIR_METHODDEF \ + {"init_pair", (PyCFunction)(void(*)(void))_curses_init_pair, METH_FASTCALL, _curses_init_pair__doc__}, + +static PyObject * +_curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg); + +static PyObject * +_curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int pair_number; + int fg; + int bg; + + if (!_PyArg_CheckPositional("init_pair", nargs, 3, 3)) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + pair_number = _PyLong_AsInt(args[0]); + if (pair_number == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[1])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + fg = _PyLong_AsInt(args[1]); + if (fg == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + bg = _PyLong_AsInt(args[2]); + if (bg == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _curses_init_pair_impl(module, pair_number, fg, bg); + +exit: + return return_value; +} + PyDoc_STRVAR(_curses_initscr__doc__, "initscr($module, /)\n" "--\n" @@ -3976,6 +4200,27 @@ _curses_use_default_colors(PyObject *module, PyObject *Py_UNUSED(ignored)) #endif /* !defined(STRICT_SYSV_CURSES) */ +PyDoc_STRVAR(_curses_has_extended_color_support__doc__, +"has_extended_color_support($module, /)\n" +"--\n" +"\n" +"Return True if the module supports extended colors; otherwise, return False.\n" +"\n" +"Extended color support allows more than 256 color-pairs for terminals\n" +"that support more than 16 colors (e.g. xterm-256color)."); + +#define _CURSES_HAS_EXTENDED_COLOR_SUPPORT_METHODDEF \ + {"has_extended_color_support", (PyCFunction)_curses_has_extended_color_support, METH_NOARGS, _curses_has_extended_color_support__doc__}, + +static PyObject * +_curses_has_extended_color_support_impl(PyObject *module); + +static PyObject * +_curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _curses_has_extended_color_support_impl(module); +} + #ifndef _CURSES_WINDOW_ENCLOSE_METHODDEF #define _CURSES_WINDOW_ENCLOSE_METHODDEF #endif /* !defined(_CURSES_WINDOW_ENCLOSE_METHODDEF) */ From 7de2eb02c2a0ff8f776aaf97161ab2d06d081e26 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Mon, 9 Dec 2019 17:48:21 +0100 Subject: [PATCH 09/30] bpo-36982: Add back has_extended_color_support() method lost during rebase --- Modules/_cursesmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 4f6ad222431118..645bcfe9110432 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -4698,6 +4698,7 @@ static PyMethodDef PyCurses_methods[] = { _CURSES_GETSYX_METHODDEF _CURSES_GETWIN_METHODDEF _CURSES_HAS_COLORS_METHODDEF + _CURSES_HAS_EXTENDED_COLOR_SUPPORT_METHODDEF _CURSES_HAS_IC_METHODDEF _CURSES_HAS_IL_METHODDEF _CURSES_HAS_KEY_METHODDEF From b07f1bd38004c64358d5953107a6b87ee8d7f70a Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Mon, 9 Dec 2019 18:25:51 +0100 Subject: [PATCH 10/30] bpo-36982: Add back init_color() to clinic input --- Modules/_cursesmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 645bcfe9110432..a85154ffacf689 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3085,7 +3085,7 @@ _curses_has_key_impl(PyObject *module, int key) #define _CURSES_INIT_COLOR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_COLOR_FUNC) -/* +/*[clinic input] _curses.init_color color_number: int From ec1aecd8baa261b45a9e29e7d1dd52f06961fa0f Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Tue, 5 May 2020 18:11:34 +0200 Subject: [PATCH 11/30] bpo-36982: Move the whatsnew entry forward to 3.9. --- Doc/whatsnew/3.8.rst | 7 ------- Doc/whatsnew/3.9.rst | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index c93be3d22227aa..b6ed2da36889a3 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -734,13 +734,6 @@ Added a new variable holding structured version information for the underlying ncurses library: :data:`~curses.ncurses_version`. (Contributed by Serhiy Storchaka in :issue:`31680`.) -The extended color functions added in ncurses 6.1 will be used transparently -by :func:`curses.color_content`, :func:`curses.init_color`, -:func:`curses.init_pair`, and :func:`curses.pair_content`. A new function, -:func:`curses.has_extended_color_support`, indicates whether extended color -support is provided by the underlying ncurses library. -(Contributed by Jeffrey Kintscher in :issue:`36982`.) - ctypes ------ diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 15fca8fa9d4c98..23f0eb3c5e495c 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -332,6 +332,13 @@ Add :func:`curses.get_escdelay`, :func:`curses.set_escdelay`, :func:`curses.get_tabsize`, and :func:`curses.set_tabsize` functions. (Contributed by Anthony Sottile in :issue:`38312`.) +The extended color functions added in ncurses 6.1 will be used transparently +by :func:`curses.color_content`, :func:`curses.init_color`, +:func:`curses.init_pair`, and :func:`curses.pair_content`. A new function, +:func:`curses.has_extended_color_support`, indicates whether extended color +support is provided by the underlying ncurses library. +(Contributed by Jeffrey Kintscher in :issue:`36982`.) + datetime -------- The :meth:`~datetime.date.isocalendar()` of :class:`datetime.date` From 95936851d3f42b2bd8eebc86a93646a8bc9f8123 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Tue, 5 May 2020 18:25:51 +0200 Subject: [PATCH 12/30] bpo-36982: Improve error messages and fix code formatting --- Modules/_cursesmodule.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index a85154ffacf689..97e5069f0d089a 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2635,13 +2635,15 @@ _curses_color_content_impl(PyObject *module, int color_number) if (color_number < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - return NULL; + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color number is less than minimum."); + return NULL; } else if (color_number > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - return NULL; + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color number is greater than maximum."); + return NULL; } if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) != ERR) @@ -2677,12 +2679,14 @@ _curses_color_pair_impl(PyObject *module, int color_number) if (color_number < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color number is less than minimum."); return NULL; } else if (color_number > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR "is greater than maximum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color number is greater than maximum."); return NULL; } From e8f678be1d8944349e0097078fd0e166090b578e Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Tue, 5 May 2020 18:33:30 +0200 Subject: [PATCH 13/30] bpo-36982: Move _curses_pair_content__doc__ back where it belongs --- Modules/_cursesmodule.c | 51 -------------------------------- Modules/clinic/_cursesmodule.c.h | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 97e5069f0d089a..a2c1daac1ac505 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3882,57 +3882,6 @@ _curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number) return Py_BuildValue("(ii)", f, b); } -PyDoc_STRVAR(_curses_pair_content__doc__, -"pair_content($module, pair_number, /)\n" -"--\n" -"\n" -"Return a tuple (fg, bg) containing the colors for the requested color pair.\n" -"\n" -" pair_number\n" -" The number of the color pair (1 - (COLOR_PAIRS-1))."); - -#define _CURSES_PAIR_CONTENT_METHODDEF \ - {"pair_content", (PyCFunction)_curses_pair_content, METH_O, _curses_pair_content__doc__}, - -static PyObject * -_curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number); - -static PyObject * -_curses_pair_content(PyObject *module, PyObject *arg) -{ - PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE pair_number; - - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } - { - long ival = PyLong_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } - } - return_value = _curses_pair_content_impl(module, pair_number); - -exit: - return return_value; -} - /*[clinic input] _curses.pair_number diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 6a49ff8735de54..43bec8198c51a2 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -3450,6 +3450,57 @@ _curses_noraw(PyObject *module, PyObject *Py_UNUSED(ignored)) return _curses_noraw_impl(module); } +PyDoc_STRVAR(_curses_pair_content__doc__, +"pair_content($module, pair_number, /)\n" +"--\n" +"\n" +"Return a tuple (fg, bg) containing the colors for the requested color pair.\n" +"\n" +" pair_number\n" +" The number of the color pair (1 - (COLOR_PAIRS-1))."); + +#define _CURSES_PAIR_CONTENT_METHODDEF \ + {"pair_content", (PyCFunction)_curses_pair_content, METH_O, _curses_pair_content__doc__}, + +static PyObject * +_curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number); + +static PyObject * +_curses_pair_content(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + _NCURSES_COLOR_VAL_TYPE pair_number; + + if (PyFloat_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + long ival = PyLong_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + goto exit; + } + else if (ival > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + goto exit; + } + else { + pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; + } + } + return_value = _curses_pair_content_impl(module, pair_number); + +exit: + return return_value; +} + PyDoc_STRVAR(_curses_pair_number__doc__, "pair_number($module, attr, /)\n" "--\n" From 2f8c724aeb607b2a4ad50fa2713447aecbd3b37b Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Tue, 5 May 2020 22:43:45 +0200 Subject: [PATCH 14/30] bpo-36982: Use a plain integer for color pair argument Use preconditions to ensure it's in range. --- Modules/_cursesmodule.c | 22 ++++++++++++++++++---- Modules/clinic/_cursesmodule.c.h | 25 +++++-------------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index a2c1daac1ac505..02c07d1e1bf2f0 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3855,24 +3855,38 @@ NoArgNoReturnFunctionBody(noraw) #define _CURSES_PAIR_NUMBER_FUNC pair_content #endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ -/* +/*[clinic input] _curses.pair_content - pair_number: _NCURSES_COLOR_VAL_TYPE + pair_number: int The number of the color pair (1 - (COLOR_PAIRS-1)). / Return a tuple (fg, bg) containing the colors for the requested color pair. -*/ +[clinic start generated code]*/ static PyObject * -_curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number) +_curses_pair_content_impl(PyObject *module, int pair_number) +/*[clinic end generated code: output=4a726dd0e6885f3f input=8adcfdbe1687095d]*/ { _NCURSES_COLOR_VAL_TYPE f, b; PyCursesInitialised; PyCursesInitialisedColor; + if (pair_number < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color pair is less than minimum."); + return NULL; + } + else if (pair_number > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color pair is greater than maximum."); + return NULL; + } + if (_CURSES_PAIR_NUMBER_FUNC(pair_number, &f, &b)==ERR) { PyErr_SetString(PyCursesError, "Argument 1 was out of range. (1..COLOR_PAIRS-1)"); diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 43bec8198c51a2..3de59c2636a22c 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -3463,37 +3463,22 @@ PyDoc_STRVAR(_curses_pair_content__doc__, {"pair_content", (PyCFunction)_curses_pair_content, METH_O, _curses_pair_content__doc__}, static PyObject * -_curses_pair_content_impl(PyObject *module, _NCURSES_COLOR_VAL_TYPE pair_number); +_curses_pair_content_impl(PyObject *module, int pair_number); static PyObject * _curses_pair_content(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - _NCURSES_COLOR_VAL_TYPE pair_number; + int pair_number; if (PyFloat_Check(arg)) { PyErr_SetString(PyExc_TypeError, "integer argument expected, got float" ); goto exit; } - { - long ival = PyLong_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); - goto exit; - } - else if (ival > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); - goto exit; - } - else { - pair_number = (_NCURSES_COLOR_VAL_TYPE) ival; - } + pair_number = _PyLong_AsInt(arg); + if (pair_number == -1 && PyErr_Occurred()) { + goto exit; } return_value = _curses_pair_content_impl(module, pair_number); From fd4c215f0d08b8e1b8dfe721e4fe349f380be596 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Tue, 5 May 2020 23:06:52 +0200 Subject: [PATCH 15/30] bpo-36982: Revert rgb values to short; they are in the 0-1000 range --- Modules/_cursesmodule.c | 42 +++++++++--------- Modules/clinic/_cursesmodule.c.h | 73 ++++++++++++++++++++++++++------ 2 files changed, 81 insertions(+), 34 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 02c07d1e1bf2f0..0896a59a4d89a1 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3094,11 +3094,11 @@ _curses.init_color color_number: int The number of the color to be changed (0 - COLORS). - r: int + r: short Red component (0 - 1000). - g: int + g: short Green component (0 - 1000). - b: int + b: short Blue component (0 - 1000). / @@ -3110,54 +3110,56 @@ most terminals; it is active only if can_change_color() returns 1. [clinic start generated code]*/ static PyObject * -_curses_init_color_impl(PyObject *module, int color_number, int r, int g, - int b) -/*[clinic end generated code: output=3824cf242d9174fc input=3ba3d1700bff7a8a]*/ +_curses_init_color_impl(PyObject *module, int color_number, short r, short g, + short b) +/*[clinic end generated code: output=d7ed71b2d818cdf2 input=c6359369570b9219]*/ { PyCursesInitialised; PyCursesInitialisedColor; if (color_number < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color number is less than minimum"); return NULL; } else if (color_number > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color number is greater than maximum"); return NULL; } - if (r < _NCURSES_COLOR_VAL_MIN) { + if (r < 0) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "Red value is less than minimum"); return NULL; } - else if (r > _NCURSES_COLOR_VAL_MAX) { + else if (r > 1000) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "Red value is greater than maximum"); return NULL; } - if (g < _NCURSES_COLOR_VAL_MIN) { + if (g < 0) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "Green value is less than minimum"); return NULL; } - else if (g > _NCURSES_COLOR_VAL_MAX) { + else if (g > 1000) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "Green value is greater than maximum"); return NULL; } - if (b < _NCURSES_COLOR_VAL_MIN) { + if (b < 0) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "Blue value is less than minimum"); return NULL; } - else if (b > _NCURSES_COLOR_VAL_MAX) { + else if (b > 1000) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "Blue value is greater than maximum"); return NULL; } diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 3de59c2636a22c..a79afb37e0be32 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -2570,17 +2570,17 @@ PyDoc_STRVAR(_curses_init_color__doc__, {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__}, static PyObject * -_curses_init_color_impl(PyObject *module, int color_number, int r, int g, - int b); +_curses_init_color_impl(PyObject *module, int color_number, short r, short g, + short b); static PyObject * _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int color_number; - int r; - int g; - int b; + short r; + short g; + short b; if (!_PyArg_CheckPositional("init_color", nargs, 4, 4)) { goto exit; @@ -2599,27 +2599,72 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) "integer argument expected, got float" ); goto exit; } - r = _PyLong_AsInt(args[1]); - if (r == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[1]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + r = (short) ival; + } } if (PyFloat_Check(args[2])) { PyErr_SetString(PyExc_TypeError, "integer argument expected, got float" ); goto exit; } - g = _PyLong_AsInt(args[2]); - if (g == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[2]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + g = (short) ival; + } } if (PyFloat_Check(args[3])) { PyErr_SetString(PyExc_TypeError, "integer argument expected, got float" ); goto exit; } - b = _PyLong_AsInt(args[3]); - if (b == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[3]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + b = (short) ival; + } } return_value = _curses_init_color_impl(module, color_number, r, g, b); From cd9b643206690f0b7c770ae7e1a378931980eab8 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Tue, 5 May 2020 23:08:35 +0200 Subject: [PATCH 16/30] bpo-36982: Improve error message specificity and formatting --- Modules/_cursesmodule.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 0896a59a4d89a1..a8d3fcc1fe1c2c 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2680,13 +2680,13 @@ _curses_color_pair_impl(PyObject *module, int color_number) if (color_number < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is less than minimum."); + " color number is less than minimum"); return NULL; } else if (color_number > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is greater than maximum."); + " color number is greater than maximum"); return NULL; } @@ -3203,34 +3203,40 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) if (pair_number < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color pair is less than minimum"); return NULL; } else if (pair_number > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color pair is greater than maximum"); return NULL; } if (fg < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " foreground color is less than minimum"); return NULL; } else if (fg > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " foreground color is greater than maximum"); return NULL; } if (bg < _NCURSES_COLOR_VAL_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is less than minimum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " background color is less than minimum"); return NULL; } else if (bg > _NCURSES_COLOR_VAL_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed " _NCURSES_COLOR_VAL_TYPE_STR " is greater than maximum"); + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " background color is greater than maximum"); return NULL; } From 8c89c23307dab9927ab10ba96972041015b12c7f Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Wed, 1 Jul 2020 22:09:34 +0200 Subject: [PATCH 17/30] bpo-36982: Let Clinic remove redundant calls to PyFloat_Check() --- Modules/clinic/_cursesmodule.c.h | 52 +------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index a79afb37e0be32..f2ae65052ab10a 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1975,11 +1975,6 @@ _curses_color_content(PyObject *module, PyObject *arg) PyObject *return_value = NULL; int color_number; - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } color_number = _PyLong_AsInt(arg); if (color_number == -1 && PyErr_Occurred()) { goto exit; @@ -2014,11 +2009,6 @@ _curses_color_pair(PyObject *module, PyObject *arg) PyObject *return_value = NULL; int color_number; - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } color_number = _PyLong_AsInt(arg); if (color_number == -1 && PyErr_Occurred()) { goto exit; @@ -2585,20 +2575,10 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("init_color", nargs, 4, 4)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } color_number = _PyLong_AsInt(args[0]); if (color_number == -1 && PyErr_Occurred()) { goto exit; } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { long ival = PyLong_AsLong(args[1]); if (ival == -1 && PyErr_Occurred()) { @@ -2618,11 +2598,6 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) r = (short) ival; } } - if (PyFloat_Check(args[2])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { long ival = PyLong_AsLong(args[2]); if (ival == -1 && PyErr_Occurred()) { @@ -2642,11 +2617,6 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) g = (short) ival; } } - if (PyFloat_Check(args[3])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { long ival = PyLong_AsLong(args[3]); if (ival == -1 && PyErr_Occurred()) { @@ -2705,29 +2675,14 @@ _curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("init_pair", nargs, 3, 3)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } pair_number = _PyLong_AsInt(args[0]); if (pair_number == -1 && PyErr_Occurred()) { goto exit; } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } fg = _PyLong_AsInt(args[1]); if (fg == -1 && PyErr_Occurred()) { goto exit; } - if (PyFloat_Check(args[2])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } bg = _PyLong_AsInt(args[2]); if (bg == -1 && PyErr_Occurred()) { goto exit; @@ -3516,11 +3471,6 @@ _curses_pair_content(PyObject *module, PyObject *arg) PyObject *return_value = NULL; int pair_number; - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } pair_number = _PyLong_AsInt(arg); if (pair_number == -1 && PyErr_Occurred()) { goto exit; @@ -4393,4 +4343,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=478d93f7692385eb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bdf5ab26fb756891 input=a9049054013a1b77]*/ From 023d41c4a51d3d8c983142113f3ba7ed8809c446 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Wed, 1 Jul 2020 23:05:10 +0200 Subject: [PATCH 18/30] bpo-36982: Move whatsnew entry forward from 3.9 to 3.10 --- Doc/whatsnew/3.10.rst | 10 ++++++++++ Doc/whatsnew/3.9.rst | 7 ------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index a3b53ba48e9b7c..4b48b8451125e5 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -103,6 +103,16 @@ New Modules Improved Modules ================ +curses +------ + +The extended color functions added in ncurses 6.1 will be used transparently +by :func:`curses.color_content`, :func:`curses.init_color`, +:func:`curses.init_pair`, and :func:`curses.pair_content`. A new function, +:func:`curses.has_extended_color_support`, indicates whether extended color +support is provided by the underlying ncurses library. +(Contributed by Jeffrey Kintscher in :issue:`36982`.) + glob ---- diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 23f0eb3c5e495c..15fca8fa9d4c98 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -332,13 +332,6 @@ Add :func:`curses.get_escdelay`, :func:`curses.set_escdelay`, :func:`curses.get_tabsize`, and :func:`curses.set_tabsize` functions. (Contributed by Anthony Sottile in :issue:`38312`.) -The extended color functions added in ncurses 6.1 will be used transparently -by :func:`curses.color_content`, :func:`curses.init_color`, -:func:`curses.init_pair`, and :func:`curses.pair_content`. A new function, -:func:`curses.has_extended_color_support`, indicates whether extended color -support is provided by the underlying ncurses library. -(Contributed by Jeffrey Kintscher in :issue:`36982`.) - datetime -------- The :meth:`~datetime.date.isocalendar()` of :class:`datetime.date` From b777e930ef224e826b4d91d80a19bf98eeb1a3b7 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Fri, 3 Jul 2020 22:31:59 +0200 Subject: [PATCH 19/30] bpo-36982: Use converters for color numbers and color pairs This eliminates repeated preconditions. --- Modules/_cursesmodule.c | 183 ++++++++++++++----------------- Modules/clinic/_cursesmodule.c.h | 23 ++-- 2 files changed, 88 insertions(+), 118 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index a8d3fcc1fe1c2c..49ada0975ab00d 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -405,6 +405,74 @@ PyCurses_ConvertToString(PyCursesWindowObject *win, PyObject *obj, return 0; } +static int +color_converter(PyObject *arg, void *ptr) +{ + long color_number; + int overflow; + + color_number = PyLong_AsLongAndOverflow(arg, &overflow); + if (PyErr_Occurred()) + return 0; + + if (color_number < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color number is less than minimum."); + return 0; + } + else if (color_number > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color number is greater than maximum."); + return 0; + } + + *(int *)ptr = (int)color_number; + return 1; +} + +/*[python input] +class color_converter(CConverter): + type = 'int' + converter = 'color_converter' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=4260d2b6e66b3709]*/ + +static int +pair_converter(PyObject *arg, void *ptr) +{ + long pair_number; + int overflow; + + pair_number = PyLong_AsLongAndOverflow(arg, &overflow); + if (PyErr_Occurred()) + return 0; + + if (pair_number < _NCURSES_COLOR_VAL_MIN) { + PyErr_SetString(PyExc_OverflowError, + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color pair is less than minimum."); + return 0; + } + else if (pair_number > _NCURSES_COLOR_VAL_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Signed " _NCURSES_COLOR_VAL_TYPE_STR + " color pair is greater than maximum."); + return 0; + } + + *(int *)ptr = (int)pair_number; + return 1; +} + +/*[python input] +class pair_converter(CConverter): + type = 'int' + converter = 'pair_converter' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=1a918ae6a1b32af7]*/ + /* Function versions of the 3 functions for testing whether curses has been initialised or not. */ @@ -2613,7 +2681,7 @@ NoArgOrFlagNoReturnFunctionBody(cbreak, flag) /*[clinic input] _curses.color_content - color_number: int + color_number: color The number of the color (0 - COLORS). / @@ -2625,7 +2693,7 @@ which will be between 0 (no component) and 1000 (maximum amount of component). static PyObject * _curses_color_content_impl(PyObject *module, int color_number) -/*[clinic end generated code: output=17b466df7054e0de input=badb7d68ffbb0e93]*/ +/*[clinic end generated code: output=17b466df7054e0de input=c10ef58f694b13ee]*/ { PyObject *return_value = NULL; _NCURSES_COLOR_VAL_TYPE r,g,b; @@ -2633,19 +2701,6 @@ _curses_color_content_impl(PyObject *module, int color_number) PyCursesInitialised; PyCursesInitialisedColor; - if (color_number < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is less than minimum."); - return NULL; - } - else if (color_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is greater than maximum."); - return NULL; - } - if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) != ERR) return_value = Py_BuildValue("(iii)", r, g, b); else @@ -2660,7 +2715,7 @@ _curses_color_content_impl(PyObject *module, int color_number) /*[clinic input] _curses.color_pair - color_number: int + color_number: color The number of the color (0 - COLORS). / @@ -2672,24 +2727,11 @@ other A_* attributes. pair_number() is the counterpart to this function. static PyObject * _curses_color_pair_impl(PyObject *module, int color_number) -/*[clinic end generated code: output=3fd752e8e24c93fb input=d4ed7238735f1647]*/ +/*[clinic end generated code: output=3fd752e8e24c93fb input=b049033819ab4ef5]*/ { PyCursesInitialised; PyCursesInitialisedColor; - if (color_number < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is less than minimum"); - return NULL; - } - else if (color_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is greater than maximum"); - return NULL; - } - return PyLong_FromLong((long) (color_number << 8)); } @@ -3092,7 +3134,7 @@ _curses_has_key_impl(PyObject *module, int key) /*[clinic input] _curses.init_color - color_number: int + color_number: color The number of the color to be changed (0 - COLORS). r: short Red component (0 - 1000). @@ -3112,24 +3154,11 @@ most terminals; it is active only if can_change_color() returns 1. static PyObject * _curses_init_color_impl(PyObject *module, int color_number, short r, short g, short b) -/*[clinic end generated code: output=d7ed71b2d818cdf2 input=c6359369570b9219]*/ +/*[clinic end generated code: output=d7ed71b2d818cdf2 input=62bbafc22a9a3c25]*/ { PyCursesInitialised; PyCursesInitialisedColor; - if (color_number < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is less than minimum"); - return NULL; - } - else if (color_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is greater than maximum"); - return NULL; - } - if (r < 0) { PyErr_SetString(PyExc_OverflowError, "Red value is less than minimum"); @@ -3180,11 +3209,11 @@ _curses_init_color_impl(PyObject *module, int color_number, short r, short g, /*[clinic input] _curses.init_pair - pair_number: int + pair_number: pair The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)). - fg: int + fg: color Foreground color number (0 - COLORS). - bg: int + bg: color Background color number (0 - COLORS). / @@ -3196,50 +3225,11 @@ all occurrences of that color-pair are changed to the new definition. static PyObject * _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) -/*[clinic end generated code: output=a0bba03d2bbc3ee6 input=defd89de917781dc]*/ +/*[clinic end generated code: output=a0bba03d2bbc3ee6 input=b865583a18061c1f]*/ { PyCursesInitialised; PyCursesInitialisedColor; - if (pair_number < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color pair is less than minimum"); - return NULL; - } - else if (pair_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color pair is greater than maximum"); - return NULL; - } - - if (fg < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " foreground color is less than minimum"); - return NULL; - } - else if (fg > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " foreground color is greater than maximum"); - return NULL; - } - - if (bg < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " background color is less than minimum"); - return NULL; - } - else if (bg > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " background color is greater than maximum"); - return NULL; - } - return PyCursesCheckERR(_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg), _CURSES_INIT_PAIR_FUNC_NAME); } @@ -3866,7 +3856,7 @@ NoArgNoReturnFunctionBody(noraw) /*[clinic input] _curses.pair_content - pair_number: int + pair_number: pair The number of the color pair (1 - (COLOR_PAIRS-1)). / @@ -3875,26 +3865,13 @@ Return a tuple (fg, bg) containing the colors for the requested color pair. static PyObject * _curses_pair_content_impl(PyObject *module, int pair_number) -/*[clinic end generated code: output=4a726dd0e6885f3f input=8adcfdbe1687095d]*/ +/*[clinic end generated code: output=4a726dd0e6885f3f input=b42eacf8a4103852]*/ { _NCURSES_COLOR_VAL_TYPE f, b; PyCursesInitialised; PyCursesInitialisedColor; - if (pair_number < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color pair is less than minimum."); - return NULL; - } - else if (pair_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color pair is greater than maximum."); - return NULL; - } - if (_CURSES_PAIR_NUMBER_FUNC(pair_number, &f, &b)==ERR) { PyErr_SetString(PyCursesError, "Argument 1 was out of range. (1..COLOR_PAIRS-1)"); diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index f2ae65052ab10a..b402b8ae1a24ef 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1975,8 +1975,7 @@ _curses_color_content(PyObject *module, PyObject *arg) PyObject *return_value = NULL; int color_number; - color_number = _PyLong_AsInt(arg); - if (color_number == -1 && PyErr_Occurred()) { + if (!color_converter(arg, &color_number)) { goto exit; } return_value = _curses_color_content_impl(module, color_number); @@ -2009,8 +2008,7 @@ _curses_color_pair(PyObject *module, PyObject *arg) PyObject *return_value = NULL; int color_number; - color_number = _PyLong_AsInt(arg); - if (color_number == -1 && PyErr_Occurred()) { + if (!color_converter(arg, &color_number)) { goto exit; } return_value = _curses_color_pair_impl(module, color_number); @@ -2575,8 +2573,7 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("init_color", nargs, 4, 4)) { goto exit; } - color_number = _PyLong_AsInt(args[0]); - if (color_number == -1 && PyErr_Occurred()) { + if (!color_converter(args[0], &color_number)) { goto exit; } { @@ -2675,16 +2672,13 @@ _curses_init_pair(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("init_pair", nargs, 3, 3)) { goto exit; } - pair_number = _PyLong_AsInt(args[0]); - if (pair_number == -1 && PyErr_Occurred()) { + if (!pair_converter(args[0], &pair_number)) { goto exit; } - fg = _PyLong_AsInt(args[1]); - if (fg == -1 && PyErr_Occurred()) { + if (!color_converter(args[1], &fg)) { goto exit; } - bg = _PyLong_AsInt(args[2]); - if (bg == -1 && PyErr_Occurred()) { + if (!color_converter(args[2], &bg)) { goto exit; } return_value = _curses_init_pair_impl(module, pair_number, fg, bg); @@ -3471,8 +3465,7 @@ _curses_pair_content(PyObject *module, PyObject *arg) PyObject *return_value = NULL; int pair_number; - pair_number = _PyLong_AsInt(arg); - if (pair_number == -1 && PyErr_Occurred()) { + if (!pair_converter(arg, &pair_number)) { goto exit; } return_value = _curses_pair_content_impl(module, pair_number); @@ -4343,4 +4336,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=bdf5ab26fb756891 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=956ae257b047d8eb input=a9049054013a1b77]*/ From 124221470073602b317cfc951b1cb73570d80e2d Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Fri, 3 Jul 2020 22:51:13 +0200 Subject: [PATCH 20/30] bpo-36982: Use converters for color components This eliminates repeated preconditions. --- Modules/_cursesmodule.c | 73 ++++++++++++++++---------------- Modules/clinic/_cursesmodule.c.h | 62 +++------------------------ 2 files changed, 43 insertions(+), 92 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 49ada0975ab00d..38ce2ee2a51153 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -473,6 +473,38 @@ class pair_converter(CConverter): [python start generated code]*/ /*[python end generated code: output=da39a3ee5e6b4b0d input=1a918ae6a1b32af7]*/ +static int +component_converter(PyObject *arg, void *ptr) +{ + long component; + int overflow; + + component = PyLong_AsLongAndOverflow(arg, &overflow); + if (PyErr_Occurred()) + return 0; + + if (component < 0) { + PyErr_SetString(PyExc_OverflowError, + "Color component is less than 0"); + return 0; + } + else if (component > 1000) { + PyErr_SetString(PyExc_OverflowError, + "Color component is greater than 1000"); + return 0; + } + + *(short *)ptr = (short)component; + return 1; +} + +/*[python input] +class component_converter(CConverter): + type = 'short' + converter = 'component_converter' +[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. */ @@ -3136,11 +3168,11 @@ _curses.init_color color_number: color The number of the color to be changed (0 - COLORS). - r: short + r: component Red component (0 - 1000). - g: short + g: component Green component (0 - 1000). - b: short + b: component Blue component (0 - 1000). / @@ -3154,44 +3186,11 @@ most terminals; it is active only if can_change_color() returns 1. static PyObject * _curses_init_color_impl(PyObject *module, int color_number, short r, short g, short b) -/*[clinic end generated code: output=d7ed71b2d818cdf2 input=62bbafc22a9a3c25]*/ +/*[clinic end generated code: output=d7ed71b2d818cdf2 input=8a2fe94ca9204aa5]*/ { PyCursesInitialised; PyCursesInitialisedColor; - if (r < 0) { - PyErr_SetString(PyExc_OverflowError, - "Red value is less than minimum"); - return NULL; - } - else if (r > 1000) { - PyErr_SetString(PyExc_OverflowError, - "Red value is greater than maximum"); - return NULL; - } - - if (g < 0) { - PyErr_SetString(PyExc_OverflowError, - "Green value is less than minimum"); - return NULL; - } - else if (g > 1000) { - PyErr_SetString(PyExc_OverflowError, - "Green value is greater than maximum"); - return NULL; - } - - if (b < 0) { - PyErr_SetString(PyExc_OverflowError, - "Blue value is less than minimum"); - return NULL; - } - else if (b > 1000) { - PyErr_SetString(PyExc_OverflowError, - "Blue value is greater than maximum"); - return NULL; - } - return PyCursesCheckERR(_CURSES_INIT_COLOR_FUNC(color_number, r, g, b), _CURSES_INIT_COLOR_FUNC_NAME); } diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index b402b8ae1a24ef..c4c2b71e4cc223 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -2576,62 +2576,14 @@ _curses_init_color(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!color_converter(args[0], &color_number)) { goto exit; } - { - long ival = PyLong_AsLong(args[1]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < SHRT_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > SHRT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - r = (short) ival; - } + if (!component_converter(args[1], &r)) { + goto exit; } - { - long ival = PyLong_AsLong(args[2]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < SHRT_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > SHRT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - g = (short) ival; - } + if (!component_converter(args[2], &g)) { + goto exit; } - { - long ival = PyLong_AsLong(args[3]); - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - else if (ival < SHRT_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - goto exit; - } - else if (ival > SHRT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - goto exit; - } - else { - b = (short) ival; - } + if (!component_converter(args[3], &b)) { + goto exit; } return_value = _curses_init_color_impl(module, color_number, r, g, b); @@ -4336,4 +4288,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=956ae257b047d8eb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=38b2531d17f119e1 input=a9049054013a1b77]*/ From eb61ff5080843b8dbc2ad518a04ea1c7825c8cfc Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Fri, 3 Jul 2020 22:52:34 +0200 Subject: [PATCH 21/30] bpo-36982: Throw ValueError instead of OverflowError if arg out of range --- Modules/_cursesmodule.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 38ce2ee2a51153..bddbbb260a219c 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -416,13 +416,13 @@ color_converter(PyObject *arg, void *ptr) return 0; if (color_number < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, + PyErr_SetString(PyExc_ValueError, "Signed " _NCURSES_COLOR_VAL_TYPE_STR " color number is less than minimum."); return 0; } else if (color_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, + PyErr_SetString(PyExc_ValueError, "Signed " _NCURSES_COLOR_VAL_TYPE_STR " color number is greater than maximum."); return 0; @@ -450,13 +450,13 @@ pair_converter(PyObject *arg, void *ptr) return 0; if (pair_number < _NCURSES_COLOR_VAL_MIN) { - PyErr_SetString(PyExc_OverflowError, + PyErr_SetString(PyExc_ValueError, "Signed " _NCURSES_COLOR_VAL_TYPE_STR " color pair is less than minimum."); return 0; } else if (pair_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_OverflowError, + PyErr_SetString(PyExc_ValueError, "Signed " _NCURSES_COLOR_VAL_TYPE_STR " color pair is greater than maximum."); return 0; @@ -484,12 +484,12 @@ component_converter(PyObject *arg, void *ptr) return 0; if (component < 0) { - PyErr_SetString(PyExc_OverflowError, + PyErr_SetString(PyExc_ValueError, "Color component is less than 0"); return 0; } else if (component > 1000) { - PyErr_SetString(PyExc_OverflowError, + PyErr_SetString(PyExc_ValueError, "Color component is greater than 1000"); return 0; } From 3fe7b1a9853b590d4cfef41b5a262e3da83a43e4 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Sat, 4 Jul 2020 00:10:24 +0200 Subject: [PATCH 22/30] bpo-36982: Improve error messages and tighten range checking --- Modules/_cursesmodule.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index bddbbb260a219c..5a5bd92c7406dd 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -415,16 +415,15 @@ color_converter(PyObject *arg, void *ptr) if (PyErr_Occurred()) return 0; - if (color_number < _NCURSES_COLOR_VAL_MIN) { + if (color_number < 0) { PyErr_SetString(PyExc_ValueError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is less than minimum."); + "Color number is less than 0."); return 0; } - else if (color_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_ValueError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color number is greater than maximum."); + else if (color_number > COLORS) { + PyErr_Format(PyExc_ValueError, + "Color number is greater than COLORS (%d).", + COLORS); return 0; } @@ -449,16 +448,15 @@ pair_converter(PyObject *arg, void *ptr) if (PyErr_Occurred()) return 0; - if (pair_number < _NCURSES_COLOR_VAL_MIN) { + if (pair_number < 1) { PyErr_SetString(PyExc_ValueError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color pair is less than minimum."); + "Color pair is less than 1."); return 0; } - else if (pair_number > _NCURSES_COLOR_VAL_MAX) { - PyErr_SetString(PyExc_ValueError, - "Signed " _NCURSES_COLOR_VAL_TYPE_STR - " color pair is greater than maximum."); + else if (pair_number > COLOR_PAIRS - 1) { + PyErr_Format(PyExc_ValueError, + "Color pair is greater than COLOR_PAIRS-1 (%d).", + COLOR_PAIRS - 1); return 0; } From 333f54d662bb79819fe0ac4d39de6da61de2034d Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Sat, 4 Jul 2020 00:10:36 +0200 Subject: [PATCH 23/30] bpo-36982: Remove unused defines --- Modules/_cursesmodule.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 5a5bd92c7406dd..09ec335b4b7354 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -141,15 +141,9 @@ typedef chtype attr_t; /* No attr_t type is available */ #endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */ #if _NCURSES_EXTENDED_COLOR_FUNCS -#define _NCURSES_COLOR_VAL_MAX INT_MAX -#define _NCURSES_COLOR_VAL_MIN INT_MIN #define _NCURSES_COLOR_VAL_TYPE int -#define _NCURSES_COLOR_VAL_TYPE_STR "integer" #else -#define _NCURSES_COLOR_VAL_MAX SHRT_MAX -#define _NCURSES_COLOR_VAL_MIN SHRT_MIN #define _NCURSES_COLOR_VAL_TYPE short -#define _NCURSES_COLOR_VAL_TYPE_STR "short integer" #endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ /*[clinic input] From 1749b1ed95c12e5b8ecd2866e9baa88c4a557497 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Sat, 4 Jul 2020 00:14:55 +0200 Subject: [PATCH 24/30] bpo-36982: Update accreditation --- Doc/whatsnew/3.10.rst | 2 +- Misc/ACKS | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 4b48b8451125e5..7f5f6f3b200e1a 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -111,7 +111,7 @@ by :func:`curses.color_content`, :func:`curses.init_color`, :func:`curses.init_pair`, and :func:`curses.pair_content`. A new function, :func:`curses.has_extended_color_support`, indicates whether extended color support is provided by the underlying ncurses library. -(Contributed by Jeffrey Kintscher in :issue:`36982`.) +(Contributed by Jeffrey Kintscher and Hans Petter Jansson in :issue:`36982`.) glob ---- diff --git a/Misc/ACKS b/Misc/ACKS index 641ef0cace00e2..fa16a35679a0da 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -798,6 +798,7 @@ Geert Jansen Jack Jansen Hans-Peter Jansen Bill Janssen +Hans Petter Jansson Jon Janzen Thomas Jarosch Juhana Jauhiainen @@ -882,6 +883,7 @@ Sam Kimbrel Tomohiko Kinebuchi James King W. Trevor King +Jeffrey Kintscher Paul Kippes Steve Kirsch Sebastian Kirsche From f5a9873431fe09f5e94d113febc1ef1f973db5c8 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Thu, 16 Jul 2020 19:54:56 +0200 Subject: [PATCH 25/30] bpo-36982: Properly check for overflow in converters --- Modules/_cursesmodule.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 09ec335b4b7354..491c37a2a33bf4 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -409,17 +409,17 @@ color_converter(PyObject *arg, void *ptr) if (PyErr_Occurred()) return 0; - if (color_number < 0) { - PyErr_SetString(PyExc_ValueError, - "Color number is less than 0."); - return 0; - } - else if (color_number > COLORS) { + if (overflow > 0 || color_number > COLORS) { PyErr_Format(PyExc_ValueError, "Color number is greater than COLORS (%d).", COLORS); return 0; } + else if (overflow < 0 || color_number < 0) { + PyErr_SetString(PyExc_ValueError, + "Color number is less than 0."); + return 0; + } *(int *)ptr = (int)color_number; return 1; @@ -442,17 +442,17 @@ pair_converter(PyObject *arg, void *ptr) if (PyErr_Occurred()) return 0; - if (pair_number < 1) { - PyErr_SetString(PyExc_ValueError, - "Color pair is less than 1."); - return 0; - } - else if (pair_number > COLOR_PAIRS - 1) { + if (overflow > 0 || pair_number > COLOR_PAIRS - 1) { PyErr_Format(PyExc_ValueError, "Color pair is greater than COLOR_PAIRS-1 (%d).", COLOR_PAIRS - 1); return 0; } + else if (overflow < 0 || pair_number < 1) { + PyErr_SetString(PyExc_ValueError, + "Color pair is less than 1."); + return 0; + } *(int *)ptr = (int)pair_number; return 1; @@ -475,14 +475,14 @@ component_converter(PyObject *arg, void *ptr) if (PyErr_Occurred()) return 0; - if (component < 0) { + if (overflow > 0 || component > 1000) { PyErr_SetString(PyExc_ValueError, - "Color component is less than 0"); + "Color component is greater than 1000"); return 0; } - else if (component > 1000) { + else if (overflow < 0 || component < 0) { PyErr_SetString(PyExc_ValueError, - "Color component is greater than 1000"); + "Color component is less than 0"); return 0; } From 9bad726f8511e3eb2aeb12ca3ea783c5b504d274 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Thu, 16 Jul 2020 19:57:56 +0200 Subject: [PATCH 26/30] bpo-36982: Shortcut error checking in converters This is a performance enhancement. --- Modules/_cursesmodule.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 491c37a2a33bf4..d0413dbd80b57d 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -406,7 +406,7 @@ color_converter(PyObject *arg, void *ptr) int overflow; color_number = PyLong_AsLongAndOverflow(arg, &overflow); - if (PyErr_Occurred()) + if (color_number == -1 && PyErr_Occurred()) return 0; if (overflow > 0 || color_number > COLORS) { @@ -439,7 +439,7 @@ pair_converter(PyObject *arg, void *ptr) int overflow; pair_number = PyLong_AsLongAndOverflow(arg, &overflow); - if (PyErr_Occurred()) + if (pair_number == -1 && PyErr_Occurred()) return 0; if (overflow > 0 || pair_number > COLOR_PAIRS - 1) { @@ -472,7 +472,7 @@ component_converter(PyObject *arg, void *ptr) int overflow; component = PyLong_AsLongAndOverflow(arg, &overflow); - if (PyErr_Occurred()) + if (component == -1 && PyErr_Occurred()) return 0; if (overflow > 0 || component > 1000) { From 29efcf344381c9b6f9a0535145daf4e512a044e3 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Thu, 16 Jul 2020 20:13:39 +0200 Subject: [PATCH 27/30] bpo-36982: Revert unrelated changes --- Modules/_cursesmodule.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index d0413dbd80b57d..a898d4a1c0fb78 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2719,19 +2719,18 @@ static PyObject * _curses_color_content_impl(PyObject *module, int color_number) /*[clinic end generated code: output=17b466df7054e0de input=c10ef58f694b13ee]*/ { - PyObject *return_value = NULL; _NCURSES_COLOR_VAL_TYPE r,g,b; PyCursesInitialised; PyCursesInitialisedColor; if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) != ERR) - return_value = Py_BuildValue("(iii)", r, g, b); - else + return Py_BuildValue("(iii)", r, g, b); + else { PyErr_SetString(PyCursesError, "Argument 1 was out of range. Check value of COLORS."); - - return return_value; + return NULL; + } } #undef _COLOR_CONTENT_FUNC @@ -2756,7 +2755,7 @@ _curses_color_pair_impl(PyObject *module, int color_number) PyCursesInitialised; PyCursesInitialisedColor; - return PyLong_FromLong((long) (color_number << 8)); + return PyLong_FromLong(color_pair_to_attr(color_number)); } /*[clinic input] From 81ad399ab3ec3193d8675565c3c972e84448acb9 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Thu, 16 Jul 2020 20:26:19 +0200 Subject: [PATCH 28/30] bpo-36982: Define extended color macros in single block for clarity --- Modules/_cursesmodule.c | 57 +++++++++++------------------------------ 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index a898d4a1c0fb78..34331017f85c7b 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -141,11 +141,24 @@ typedef chtype attr_t; /* No attr_t type is available */ #endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */ #if _NCURSES_EXTENDED_COLOR_FUNCS -#define _NCURSES_COLOR_VAL_TYPE int +#define _NCURSES_COLOR_VAL_TYPE int +#define _CURSES_INIT_COLOR_FUNC init_extended_color +#define _CURSES_INIT_PAIR_FUNC init_extended_pair +#define _COLOR_CONTENT_FUNC extended_color_content +#define _CURSES_PAIR_NUMBER_FUNC extended_pair_content #else -#define _NCURSES_COLOR_VAL_TYPE short +#define _NCURSES_COLOR_VAL_TYPE short +#define _CURSES_INIT_COLOR_FUNC init_color +#define _CURSES_INIT_PAIR_FUNC init_pair +#define _COLOR_CONTENT_FUNC color_content +#define _CURSES_PAIR_NUMBER_FUNC pair_content #endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ +#define _CURSES_FUNC_NAME_STR(s) #s + +#define _CURSES_INIT_COLOR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_COLOR_FUNC) +#define _CURSES_INIT_PAIR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_PAIR_FUNC) + /*[clinic input] module _curses class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type" @@ -518,10 +531,6 @@ static int func_PyCursesInitialisedColor(void) return 1; } -/* _CURSES_FUNC_NAME_STR() is used by some of the */ -/* color functions that have extended color alternatives */ -#define _CURSES_FUNC_NAME_STR(s) #s - /***************************************************************************** The Window Object ******************************************************************************/ @@ -2696,12 +2705,6 @@ _curses_cbreak_impl(PyObject *module, int flag) /*[clinic end generated code: output=9f9dee9664769751 input=150be619eb1f1458]*/ NoArgOrFlagNoReturnFunctionBody(cbreak, flag) -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _COLOR_CONTENT_FUNC extended_color_content -#else -#define _COLOR_CONTENT_FUNC color_content -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - /*[clinic input] _curses.color_content @@ -2733,8 +2736,6 @@ _curses_color_content_impl(PyObject *module, int color_number) } } -#undef _COLOR_CONTENT_FUNC - /*[clinic input] _curses.color_pair @@ -3146,14 +3147,6 @@ _curses_has_key_impl(PyObject *module, int key) } #endif -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_INIT_COLOR_FUNC init_extended_color -#else -#define _CURSES_INIT_COLOR_FUNC init_color -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - -#define _CURSES_INIT_COLOR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_COLOR_FUNC) - /*[clinic input] _curses.init_color @@ -3185,17 +3178,6 @@ _curses_init_color_impl(PyObject *module, int color_number, short r, short g, return PyCursesCheckERR(_CURSES_INIT_COLOR_FUNC(color_number, r, g, b), _CURSES_INIT_COLOR_FUNC_NAME); } -#undef _CURSES_INIT_COLOR_FUNC -#undef _CURSES_INIT_COLOR_FUNC_NAME - -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_INIT_PAIR_FUNC init_extended_pair -#else -#define _CURSES_INIT_PAIR_FUNC init_pair -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - -#define _CURSES_INIT_PAIR_FUNC_NAME _CURSES_FUNC_NAME_STR(_CURSES_INIT_PAIR_FUNC) - /*[clinic input] _curses.init_pair @@ -3223,9 +3205,6 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) return PyCursesCheckERR(_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg), _CURSES_INIT_PAIR_FUNC_NAME); } -#undef _CURSES_INIT_PAIR_FUNC -#undef _CURSES_INIT_PAIR_FUNC_NAME - static PyObject *ModDict; /*[clinic input] @@ -3837,12 +3816,6 @@ _curses_noraw_impl(PyObject *module) /*[clinic end generated code: output=39894e5524c430cc input=6ec86692096dffb5]*/ NoArgNoReturnFunctionBody(noraw) -#if _NCURSES_EXTENDED_COLOR_FUNCS -#define _CURSES_PAIR_NUMBER_FUNC extended_pair_content -#else -#define _CURSES_PAIR_NUMBER_FUNC pair_content -#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ - /*[clinic input] _curses.pair_content From 9ec614a9a8ac3998ebc0c9067c8f534b12e30225 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Thu, 16 Jul 2020 21:06:57 +0200 Subject: [PATCH 29/30] bpo-36982: Add ValueError tests for color and pair converters --- Lib/test/test_curses.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 5456a9fb091e0e..d9e980575c9e90 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -293,6 +293,19 @@ def test_colors_funcs(self): if hasattr(curses, 'use_default_colors'): curses.use_default_colors() + self.assertRaises(ValueError, curses.color_content, -1) + self.assertRaises(ValueError, curses.color_content, curses.COLORS + 1) + self.assertRaises(ValueError, curses.color_content, -2**31 - 1) + self.assertRaises(ValueError, curses.color_content, 2**31) + self.assertRaises(ValueError, curses.color_content, -2**63 - 1) + self.assertRaises(ValueError, curses.color_content, 2**63 - 1) + self.assertRaises(ValueError, curses.pair_content, -1) + self.assertRaises(ValueError, curses.pair_content, curses.COLOR_PAIRS) + self.assertRaises(ValueError, curses.pair_content, -2**31 - 1) + self.assertRaises(ValueError, curses.pair_content, 2**31) + self.assertRaises(ValueError, curses.pair_content, -2**63 - 1) + self.assertRaises(ValueError, curses.pair_content, 2**63 - 1) + @requires_curses_func('keyname') def test_keyname(self): curses.keyname(13) From 70fdaf35102e5ff093031847745015d9162cbeeb Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Wed, 29 Jul 2020 21:24:53 +0200 Subject: [PATCH 30/30] bpo-36982: Add back documentation for has_extended_color_support() This got lost during the rebase. Also change versionadded from 3.8 to 3.10. --- Doc/library/curses.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 1201e8972de63c..e4f7ca5fd7ae79 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -242,6 +242,15 @@ The module :mod:`curses` defines the following functions: Return ``True`` if the terminal can display colors; otherwise, return ``False``. +.. function:: has_extended_color_support() + + Return ``True`` if the module supports extended colors; otherwise, return + ``False``. Extended color support allows more than 256 color pairs for + terminals that support more than 16 colors (e.g. xterm-256color). + + Extended color support requires ncurses version 6.1 or later. + + .. versionadded:: 3.10 .. function:: has_ic()