diff -r ad81d3bf6c97 Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c Sat Jul 14 17:51:51 2012 +0200 +++ b/Modules/_cursesmodule.c Wed Jul 18 23:27:30 2012 +0200 @@ -134,37 +134,67 @@ #define STRICT_SYSV_CURSES #endif -/* Definition of exception curses.error */ - -static PyObject *PyCursesError; - -/* Tells whether setupterm() has been called to initialise terminfo. */ -static int initialised_setupterm = FALSE; - -/* Tells whether initscr() has been called to initialise curses. */ -static int initialised = FALSE; - -/* Tells whether start_color() has been called to initialise color usage. */ -static int initialisedcolors = FALSE; - -static char *screen_encoding = NULL; +typedef struct { + /* Definition of exception curses.error */ + PyObject *PyCursesError; + /* Tells whether setupterm() has been called to initialise terminfo. */ + int initialised_setupterm; + /* Tells whether initscr() has been called to initialise curses. */ + int initialised; + /* Tells whether start_color() has been called to initialise color usage.*/ + int initialisedcolors; + char *screen_encoding; + PyObject *PyCursesWindow_Type; + PyObject *ModDict; +} _cursesmodulestate; + +#define _cursesmodulestate(o) ((_cursesmodulestate *)PyModule_GetState(o)) + +static int +_cursesmodule_clear(PyObject *m) +{ + Py_CLEAR(_cursesmodulestate(m)->PyCursesError); + Py_CLEAR(_cursesmodulestate(m)->PyCursesWindow_Type); + Py_CLEAR(_cursesmodulestate(m)->ModDict); + return 0; +} + +static int +_cursesmodule_traverse(PyObject *m, visitproc visit, void *arg) +{ + Py_VISIT(_cursesmodulestate(m)->PyCursesError); + Py_VISIT(_cursesmodulestate(m)->PyCursesWindow_Type); + Py_VISIT(_cursesmodulestate(m)->ModDict); + return 0; +} + +static void +_cursesmodule_free(void *m) +{ + _cursesmodule_clear((PyObject *)m); +} + +static struct PyModuleDef _cursesmodule; + +#define _cursesmodulestate_global ((_cursesmodulestate *) \ + PyModule_GetState(PyState_FindModule(&_cursesmodule))) /* Utility Macros */ #define PyCursesSetupTermCalled \ - if (initialised_setupterm != TRUE) { \ - PyErr_SetString(PyCursesError, \ + if (_cursesmodulestate_global->initialised_setupterm != TRUE) { \ + PyErr_SetString(_cursesmodulestate_global->PyCursesError, \ "must call (at least) setupterm() first"); \ return 0; } #define PyCursesInitialised \ - if (initialised != TRUE) { \ - PyErr_SetString(PyCursesError, \ + if (_cursesmodulestate_global->initialised != TRUE) { \ + PyErr_SetString(_cursesmodulestate_global->PyCursesError, \ "must call initscr() first"); \ return 0; } #define PyCursesInitialisedColor \ - if (initialisedcolors != TRUE) { \ - PyErr_SetString(PyCursesError, \ + if (_cursesmodulestate_global->initialisedcolors != TRUE) { \ + PyErr_SetString(_cursesmodulestate_global->PyCursesError, \ "must call start_color() first"); \ return 0; } @@ -188,9 +218,9 @@ return Py_None; } else { if (fname == NULL) { - PyErr_SetString(PyCursesError, catchall_ERR); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, catchall_ERR); } else { - PyErr_Format(PyCursesError, "%s() returned ERR", fname); + PyErr_Format(_cursesmodulestate_global->PyCursesError, "%s() returned ERR", fname); } return NULL; } @@ -225,7 +255,7 @@ if (win) encoding = win->encoding; else - encoding = screen_encoding; + encoding = _cursesmodulestate_global->screen_encoding; bytes = PyUnicode_AsEncodedObject(obj, encoding, NULL); if (bytes == NULL) return 0; @@ -412,7 +442,7 @@ /* Definition of the window type */ -PyTypeObject PyCursesWindow_Type; +//PyTypeObject PyCursesWindow_Type; /* Function prototype macros for Window object @@ -550,11 +580,14 @@ encoding = "utf-8"; } - wo = PyObject_NEW(PyCursesWindowObject, &PyCursesWindow_Type); + wo = PyObject_NEW(PyCursesWindowObject, + (PyTypeObject *)_cursesmodulestate_global->PyCursesWindow_Type); if (wo == NULL) return NULL; + Py_INCREF(_cursesmodulestate_global->PyCursesWindow_Type); wo->win = win; wo->encoding = strdup(encoding); if (wo->encoding == NULL) { + Py_DECREF(_cursesmodulestate_global->PyCursesWindow_Type); Py_DECREF(wo); PyErr_NoMemory(); return NULL; @@ -568,6 +601,7 @@ if (wo->win != stdscr) delwin(wo->win); if (wo->encoding != NULL) free(wo->encoding); + Py_DECREF(Py_TYPE(wo)); PyObject_DEL(wo); } @@ -1044,7 +1078,7 @@ win = derwin(self->win,nlines,ncols,begin_y,begin_x); if (win == NULL) { - PyErr_SetString(PyCursesError, catchall_NULL); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, catchall_NULL); return NULL; } @@ -1158,7 +1192,7 @@ } if (rtn == ERR) { /* getch() returns ERR in nodelay mode */ - PyErr_SetString(PyCursesError, "no input"); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "no input"); return NULL; } else if (rtn<=255) { return Py_BuildValue("C", rtn); @@ -1200,7 +1234,7 @@ } if (ct == ERR) { /* get_wch() returns ERR in nodelay mode */ - PyErr_SetString(PyCursesError, "no input"); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "no input"); return NULL; } return PyLong_FromLong(rtn); @@ -1612,7 +1646,7 @@ Py_END_ALLOW_THREADS return PyCursesCheckERR(rtn, "pnoutrefresh"); default: - PyErr_SetString(PyCursesError, + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "noutrefresh() called for a pad " "requires 6 arguments"); return NULL; @@ -1639,13 +1673,14 @@ switch (PyTuple_Size(args)) { case 1: if (!PyArg_ParseTuple(args, "O!;window object", - &PyCursesWindow_Type, &temp)) + (PyTypeObject *)_cursesmodulestate_global->PyCursesWindow_Type, + &temp)) return NULL; break; case 7: if (!PyArg_ParseTuple(args, "O!iiiiii;window object, int, int, int, int, int, int", - &PyCursesWindow_Type, &temp, &sminrow, &smincol, - &dminrow, &dmincol, &dmaxrow, &dmaxcol)) + (PyTypeObject *)_cursesmodulestate_global->PyCursesWindow_Type, + &temp, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) return NULL; use_copywin = TRUE; break; @@ -1677,13 +1712,13 @@ switch (PyTuple_Size(args)) { case 1: if (!PyArg_ParseTuple(args, "O!;window object", - &PyCursesWindow_Type, &temp)) + (PyTypeObject *)_cursesmodulestate_global->PyCursesWindow_Type, &temp)) return NULL; break; case 7: if (!PyArg_ParseTuple(args, "O!iiiiii;window object, int, int, int, int, int, int", - &PyCursesWindow_Type, &temp, &sminrow, &smincol, - &dminrow, &dmincol, &dmaxrow, &dmaxcol)) + (PyTypeObject *)_cursesmodulestate_global->PyCursesWindow_Type, + &temp, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) return NULL; use_copywin = TRUE; break; @@ -1785,7 +1820,7 @@ Py_END_ALLOW_THREADS return PyCursesCheckERR(rtn, "prefresh"); default: - PyErr_SetString(PyCursesError, + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "refresh() for a pad requires 6 arguments"); return NULL; } @@ -1840,7 +1875,7 @@ win = subwin(self->win, nlines, ncols, begin_y, begin_x); if (win == NULL) { - PyErr_SetString(PyCursesError, catchall_NULL); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, catchall_NULL); return NULL; } @@ -2062,38 +2097,19 @@ /* -------------------------------------------------------*/ -PyTypeObject PyCursesWindow_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_curses.curses window", /*tp_name*/ - sizeof(PyCursesWindowObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)PyCursesWindow_Dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - (getattrfunc)0, /*tp_getattr*/ - (setattrfunc)0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - PyCursesWindow_Methods, /*tp_methods*/ - 0, /* tp_members */ - PyCursesWindow_getsets, /* tp_getset */ +static PyType_Slot PyCursesWindow_Type_slots[] = { + {Py_tp_dealloc, PyCursesWindow_Dealloc}, + {Py_tp_methods, PyCursesWindow_Methods}, + {Py_tp_getset, PyCursesWindow_getsets}, + {0, 0}, +}; + +static PyType_Spec PyCursesWindow_Type_spec = { + "_curses.curses window", + sizeof(PyCursesWindowObject), + 0, + Py_TPFLAGS_DEFAULT, + PyCursesWindow_Type_slots }; /********************************************************************* @@ -2157,7 +2173,7 @@ if (color_content(color, &r, &g, &b) != ERR) return Py_BuildValue("(iii)", r, g, b); else { - PyErr_SetString(PyCursesError, + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "Argument 1 was out of range. Check value of COLORS."); return NULL; } @@ -2238,7 +2254,7 @@ rtn = getmouse( &event ); if (rtn == ERR) { - PyErr_SetString(PyCursesError, "getmouse() returned ERR"); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "getmouse() returned ERR"); return NULL; } return Py_BuildValue("(hiiil)", @@ -2314,7 +2330,7 @@ fclose(fp); remove(fn); if (win == NULL) { - PyErr_SetString(PyCursesError, catchall_NULL); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, catchall_NULL); return NULL; } return PyCursesWindow_New(win, NULL); @@ -2389,15 +2405,13 @@ return PyCursesCheckERR(init_pair(pair, f, b), "init_pair"); } -static PyObject *ModDict; - static PyObject * PyCurses_InitScr(PyObject *self) { WINDOW *win; PyCursesWindowObject *winobj; - if (initialised == TRUE) { + if (_cursesmodulestate_global->initialised == TRUE) { wrefresh(stdscr); return (PyObject *)PyCursesWindow_New(stdscr, NULL); } @@ -2405,18 +2419,18 @@ win = initscr(); if (win == NULL) { - PyErr_SetString(PyCursesError, catchall_NULL); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, catchall_NULL); return NULL; } - initialised = initialised_setupterm = TRUE; + _cursesmodulestate_global->initialised = _cursesmodulestate_global->initialised_setupterm = TRUE; /* This was moved from initcurses() because it core dumped on SGI, where they're not defined until you've called initscr() */ #define SetDictInt(string,ch) \ do { \ PyObject *o = PyLong_FromLong((long) (ch)); \ - if (o && PyDict_SetItemString(ModDict, string, o) == 0) { \ + if (o && PyDict_SetItemString(_cursesmodulestate_global->ModDict, string, o) == 0) { \ Py_DECREF(o); \ } \ } while (0) @@ -2492,7 +2506,7 @@ SetDictInt("COLS", COLS); winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL); - screen_encoding = winobj->encoding; + _cursesmodulestate_global->screen_encoding = winobj->encoding; return (PyObject *)winobj; } @@ -2517,7 +2531,7 @@ if (sys_stdout == NULL || sys_stdout == Py_None) { PyErr_SetString( - PyCursesError, + _cursesmodulestate_global->PyCursesError, "lost sys.stdout"); return NULL; } @@ -2529,7 +2543,7 @@ } } - if (!initialised_setupterm && setupterm(termstr,fd,&err) == ERR) { + if (!_cursesmodulestate_global->initialised_setupterm && setupterm(termstr,fd,&err) == ERR) { char* s = "setupterm: unknown error"; if (err == 0) { @@ -2538,11 +2552,11 @@ s = "setupterm: could not find terminfo database"; } - PyErr_SetString(PyCursesError,s); + PyErr_SetString(_cursesmodulestate_global->PyCursesError,s); return NULL; } - initialised_setupterm = TRUE; + _cursesmodulestate_global->initialised_setupterm = TRUE; Py_INCREF(Py_None); return Py_None; @@ -2691,7 +2705,7 @@ win = newpad(nlines, ncols); if (win == NULL) { - PyErr_SetString(PyCursesError, catchall_NULL); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, catchall_NULL); return NULL; } @@ -2723,7 +2737,7 @@ win = newwin(nlines,ncols,begin_y,begin_x); if (win == NULL) { - PyErr_SetString(PyCursesError, catchall_NULL); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, catchall_NULL); return NULL; } @@ -2748,7 +2762,7 @@ } if (pair_content(pair, &f, &b)==ERR) { - PyErr_SetString(PyCursesError, + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "Argument 1 was out of range. (1..COLOR_PAIRS-1)"); return NULL; } @@ -2836,7 +2850,7 @@ return 0; } /* PyId_LINES.object will be initialized here. */ - if (PyDict_SetItem(ModDict, PyId_LINES.object, o)) { + if (PyDict_SetItem(_cursesmodulestate_global->ModDict, PyId_LINES.object, o)) { Py_DECREF(m); Py_DECREF(o); return 0; @@ -2852,7 +2866,7 @@ Py_DECREF(o); return 0; } - if (PyDict_SetItem(ModDict, PyId_COLS.object, o)) { + if (PyDict_SetItem(_cursesmodulestate_global->ModDict, PyId_COLS.object, o)) { Py_DECREF(m); Py_DECREF(o); return 0; @@ -2939,17 +2953,17 @@ code = start_color(); if (code != ERR) { - initialisedcolors = TRUE; + _cursesmodulestate_global->initialisedcolors = TRUE; c = PyLong_FromLong((long) COLORS); - PyDict_SetItemString(ModDict, "COLORS", c); + PyDict_SetItemString(_cursesmodulestate_global->ModDict, "COLORS", c); Py_DECREF(c); cp = PyLong_FromLong((long) COLOR_PAIRS); - PyDict_SetItemString(ModDict, "COLOR_PAIRS", cp); + PyDict_SetItemString(_cursesmodulestate_global->ModDict, "COLOR_PAIRS", cp); Py_DECREF(cp); Py_INCREF(Py_None); return Py_None; } else { - PyErr_SetString(PyCursesError, "start_color() returned ERR"); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "start_color() returned ERR"); return NULL; } } @@ -3015,7 +3029,7 @@ result = tparm(fmt,i1,i2,i3,i4,i5,i6,i7,i8,i9); if (!result) { - PyErr_SetString(PyCursesError, "tparm() returned NULL"); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "tparm() returned NULL"); return NULL; } @@ -3165,7 +3179,7 @@ Py_INCREF(Py_None); return Py_None; } else { - PyErr_SetString(PyCursesError, "use_default_colors() returned ERR"); + PyErr_SetString(_cursesmodulestate_global->PyCursesError, "use_default_colors() returned ERR"); return NULL; } } @@ -3276,12 +3290,12 @@ PyModuleDef_HEAD_INIT, "_curses", NULL, - -1, + sizeof(_cursesmodulestate), PyCurses_methods, NULL, - NULL, - NULL, - NULL + _cursesmodule_traverse, + _cursesmodule_clear, + _cursesmodule_free }; PyMODINIT_FUNC @@ -3290,26 +3304,38 @@ PyObject *m, *d, *v, *c_api_object; static void *PyCurses_API[PyCurses_API_pointers]; + /* Create the module and add the functions */ + m = PyModule_Create(&_cursesmodule); + if (m == NULL) + goto fail; + PyState_AddModule(m, &_cursesmodule); + /* Initialize object type */ - if (PyType_Ready(&PyCursesWindow_Type) < 0) - return NULL; + _cursesmodulestate(m)->PyCursesWindow_Type = + PyType_FromSpec(&PyCursesWindow_Type_spec); + if (_cursesmodulestate(m)->PyCursesWindow_Type == NULL) + goto fail; /* Initialize the C API pointer array */ - PyCurses_API[0] = (void *)&PyCursesWindow_Type; + PyCurses_API[0] = (void *)_cursesmodulestate(m)->PyCursesWindow_Type; PyCurses_API[1] = (void *)func_PyCursesSetupTermCalled; PyCurses_API[2] = (void *)func_PyCursesInitialised; PyCurses_API[3] = (void *)func_PyCursesInitialisedColor; - /* Create the module and add the functions */ - m = PyModule_Create(&_cursesmodule); - if (m == NULL) - return NULL; + _cursesmodulestate(m)->initialised_setupterm = FALSE; + + _cursesmodulestate(m)->initialised = FALSE; + + _cursesmodulestate(m)->initialisedcolors = FALSE; + + _cursesmodulestate(m)->screen_encoding = NULL; /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); if (d == NULL) - return NULL; - ModDict = d; /* For PyCurses_InitScr to use later */ + goto fail; + Py_INCREF(d); + _cursesmodulestate(m)->ModDict = d; /* For PyCurses_InitScr to use later */ /* Add a capsule for the C API */ c_api_object = PyCapsule_New(PyCurses_API, PyCurses_CAPSULE_NAME, NULL); @@ -3317,8 +3343,8 @@ Py_DECREF(c_api_object); /* For exception curses.error */ - PyCursesError = PyErr_NewException("_curses.error", NULL, NULL); - PyDict_SetItemString(d, "error", PyCursesError); + _cursesmodulestate(m)->PyCursesError = PyErr_NewException("_curses.error", NULL, NULL); + PyDict_SetItemString(d, "error", _cursesmodulestate(m)->PyCursesError); /* Make the version available */ v = PyBytes_FromString(PyCursesVersion); @@ -3447,4 +3473,8 @@ SetDictInt("KEY_MAX", KEY_MAX); } return m; + fail: + PyState_RemoveModule(&_cursesmodule); + Py_DECREF(m); + return NULL; }