diff options
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_curses_panel.c | 122 | ||||
-rw-r--r-- | Modules/_decimal/libmpdec/mpdecimal.c | 16 | ||||
-rw-r--r-- | Modules/_elementtree.c | 364 | ||||
-rw-r--r-- | Modules/timemodule.c | 129 |
4 files changed, 421 insertions, 210 deletions
diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 8561a2e70c..1c7d0842e8 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -16,8 +16,37 @@ static char *PyCursesVersion = "2.1"; #include <panel.h> -static PyObject *PyCursesError; +typedef struct { + PyObject *PyCursesError; + PyObject *PyCursesPanel_Type; +} _curses_panelstate; + +#define _curses_panelstate(o) ((_curses_panelstate *)PyModule_GetState(o)) + +static int +_curses_panel_clear(PyObject *m) +{ + Py_CLEAR(_curses_panelstate(m)->PyCursesError); + return 0; +} + +static int +_curses_panel_traverse(PyObject *m, visitproc visit, void *arg) +{ + Py_VISIT(_curses_panelstate(m)->PyCursesError); + return 0; +} + +static void +_curses_panel_free(void *m) +{ + _curses_panel_clear((PyObject *) m); +} +static struct PyModuleDef _curses_panelmodule; + +#define _curses_panelstate_global \ +((_curses_panelstate *) PyModule_GetState(PyState_FindModule(&_curses_panelmodule))) /* Utility Functions */ @@ -34,9 +63,9 @@ PyCursesCheckERR(int code, char *fname) return Py_None; } else { if (fname == NULL) { - PyErr_SetString(PyCursesError, catchall_ERR); + PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_ERR); } else { - PyErr_Format(PyCursesError, "%s() returned ERR", fname); + PyErr_Format(_curses_panelstate_global->PyCursesError, "%s() returned ERR", fname); } return NULL; } @@ -54,9 +83,8 @@ typedef struct { PyCursesWindowObject *wo; /* for reference counts */ } PyCursesPanelObject; -PyTypeObject PyCursesPanel_Type; - -#define PyCursesPanel_Check(v) (Py_TYPE(v) == &PyCursesPanel_Type) +#define PyCursesPanel_Check(v) \ + (Py_TYPE(v) == _curses_panelstate_global->PyCursesPanel_Type) /* Some helper functions. The problem is that there's always a window associated with a panel. To ensure that Python's GC doesn't pull @@ -175,7 +203,8 @@ PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo) { PyCursesPanelObject *po; - po = PyObject_NEW(PyCursesPanelObject, &PyCursesPanel_Type); + po = PyObject_NEW(PyCursesPanelObject, + (PyTypeObject *)(_curses_panelstate_global)->PyCursesPanel_Type); if (po == NULL) return NULL; po->pan = pan; if (insert_lop(po) < 0) { @@ -280,7 +309,7 @@ PyCursesPanel_replace_panel(PyCursesPanelObject *self, PyObject *args) rtn = replace_panel(self->pan, temp->win); if (rtn == ERR) { - PyErr_SetString(PyCursesError, "replace_panel() returned ERR"); + PyErr_SetString(_curses_panelstate_global->PyCursesError, "replace_panel() returned ERR"); return NULL; } Py_DECREF(po->wo); @@ -305,7 +334,7 @@ PyCursesPanel_userptr(PyCursesPanelObject *self) PyCursesInitialised; obj = (PyObject *) panel_userptr(self->pan); if (obj == NULL) { - PyErr_SetString(PyCursesError, "no userptr set"); + PyErr_SetString(_curses_panelstate_global->PyCursesError, "no userptr set"); return NULL; } @@ -334,36 +363,18 @@ static PyMethodDef PyCursesPanel_Methods[] = { /* -------------------------------------------------------*/ -PyTypeObject PyCursesPanel_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_curses_panel.curses panel", /*tp_name*/ - sizeof(PyCursesPanelObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)PyCursesPanel_Dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 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*/ - PyCursesPanel_Methods, /*tp_methods*/ +static PyType_Slot PyCursesPanel_Type_slots[] = { + {Py_tp_dealloc, PyCursesPanel_Dealloc}, + {Py_tp_methods, PyCursesPanel_Methods}, + {0, 0}, +}; + +static PyType_Spec PyCursesPanel_Type_spec = { + "_curses_panel.curses panel", + sizeof(PyCursesPanelObject), + 0, + Py_TPFLAGS_DEFAULT, + PyCursesPanel_Type_slots }; /* Wrapper for panel_above(NULL). This function returns the bottom @@ -405,7 +416,7 @@ PyCurses_new_panel(PyObject *self, PyObject *args) return NULL; pan = new_panel(win->win); if (pan == NULL) { - PyErr_SetString(PyCursesError, catchall_NULL); + PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_NULL); return NULL; } return (PyObject *)PyCursesPanel_New(pan, win); @@ -467,12 +478,12 @@ static struct PyModuleDef _curses_panelmodule = { PyModuleDef_HEAD_INIT, "_curses_panel", NULL, - -1, + sizeof(_curses_panelstate), PyCurses_methods, NULL, - NULL, - NULL, - NULL + _curses_panel_traverse, + _curses_panel_clear, + _curses_panel_free }; PyMODINIT_FUNC @@ -480,21 +491,23 @@ PyInit__curses_panel(void) { PyObject *m, *d, *v; - /* Initialize object type */ - if (PyType_Ready(&PyCursesPanel_Type) < 0) - return NULL; - - import_curses(); - /* Create the module and add the functions */ m = PyModule_Create(&_curses_panelmodule); if (m == NULL) - return NULL; + goto fail; d = PyModule_GetDict(m); + /* Initialize object type */ + _curses_panelstate(m)->PyCursesPanel_Type = \ + PyType_FromSpec(&PyCursesPanel_Type_spec); + if (_curses_panelstate(m)->PyCursesPanel_Type == NULL) + goto fail; + + import_curses(); + /* For exception _curses_panel.error */ - PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL); - PyDict_SetItemString(d, "error", PyCursesError); + _curses_panelstate(m)->PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL); + PyDict_SetItemString(d, "error", _curses_panelstate(m)->PyCursesError); /* Make the version available */ v = PyUnicode_FromString(PyCursesVersion); @@ -502,4 +515,7 @@ PyInit__curses_panel(void) PyDict_SetItemString(d, "__version__", v); Py_DECREF(v); return m; + fail: + Py_XDECREF(m); + return NULL; } diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c index ff6d867e49..262e83495e 100644 --- a/Modules/_decimal/libmpdec/mpdecimal.c +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -107,8 +107,9 @@ static inline void _mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); static void _mpd_base_ndivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, uint32_t *status); -static inline void _mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, - uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status); +static inline void _mpd_qpow_uint(mpd_t *result, const mpd_t *base, + mpd_uint_t exp, uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status); mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n); @@ -5841,12 +5842,12 @@ mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, } /* - * Internal function: Integer power with mpd_uint_t exponent, base is modified! - * Function can fail with MPD_Malloc_error. + * Internal function: Integer power with mpd_uint_t exponent. The function + * can fail with MPD_Malloc_error. */ static inline void -_mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, uint8_t resultsign, - const mpd_context_t *ctx, uint32_t *status) +_mpd_qpow_uint(mpd_t *result, const mpd_t *base, mpd_uint_t exp, + uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status) { uint32_t workstatus = 0; mpd_uint_t n; @@ -5866,7 +5867,8 @@ _mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, uint8_t resultsign, if (exp & n) { mpd_qmul(result, result, base, ctx, &workstatus); } - if (workstatus & (MPD_Overflow|MPD_Clamped)) { + if (mpd_isspecial(result) || + (mpd_iszerocoeff(result) && (workstatus & MPD_Clamped))) { break; } } diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 103e778eea..cb84048580 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -103,8 +103,6 @@ do { memory -= size; printf("%8d - %s\n", memory, comment); } while (0) /* glue functions (see the init function for details) */ static PyObject* elementtree_parseerror_obj; static PyObject* elementtree_deepcopy_obj; -static PyObject* elementtree_iter_obj; -static PyObject* elementtree_itertext_obj; static PyObject* elementpath_obj; /* helpers */ @@ -1109,67 +1107,32 @@ element_getchildren(ElementObject* self, PyObject* args) return list; } -static PyObject* -element_iter(ElementObject* self, PyObject* args) -{ - PyObject* result; - PyObject* tag = Py_None; - if (!PyArg_ParseTuple(args, "|O:iter", &tag)) - return NULL; +static PyObject * +create_elementiter(ElementObject *self, PyObject *tag, int gettext); - if (!elementtree_iter_obj) { - PyErr_SetString( - PyExc_RuntimeError, - "iter helper not found" - ); - return NULL; - } - args = PyTuple_New(2); - if (!args) +static PyObject * +element_iter(ElementObject *self, PyObject *args) +{ + PyObject* tag = Py_None; + if (!PyArg_ParseTuple(args, "|O:iter", &tag)) return NULL; - Py_INCREF(self); PyTuple_SET_ITEM(args, 0, (PyObject*) self); - Py_INCREF(tag); PyTuple_SET_ITEM(args, 1, (PyObject*) tag); - - result = PyObject_CallObject(elementtree_iter_obj, args); - - Py_DECREF(args); - - return result; + return create_elementiter(self, tag, 0); } static PyObject* element_itertext(ElementObject* self, PyObject* args) { - PyObject* result; - if (!PyArg_ParseTuple(args, ":itertext")) return NULL; - if (!elementtree_itertext_obj) { - PyErr_SetString( - PyExc_RuntimeError, - "itertext helper not found" - ); - return NULL; - } - - args = PyTuple_New(1); - if (!args) - return NULL; - - Py_INCREF(self); PyTuple_SET_ITEM(args, 0, (PyObject*) self); - - result = PyObject_CallObject(elementtree_itertext_obj, args); - - Py_DECREF(args); - - return result; + return create_elementiter(self, Py_None, 1); } + static PyObject* element_getitem(PyObject* self_, Py_ssize_t index) { @@ -1790,6 +1753,269 @@ static PyTypeObject Element_Type = { 0, /* tp_free */ }; +/******************************* Element iterator ****************************/ + +/* ElementIterObject represents the iteration state over an XML element in + * pre-order traversal. To keep track of which sub-element should be returned + * next, a stack of parents is maintained. This is a standard stack-based + * iterative pre-order traversal of a tree. + * The stack is managed using a single-linked list starting at parent_stack. + * Each stack node contains the saved parent to which we should return after + * the current one is exhausted, and the next child to examine in that parent. + */ +typedef struct ParentLocator_t { + ElementObject *parent; + Py_ssize_t child_index; + struct ParentLocator_t *next; +} ParentLocator; + +typedef struct { + PyObject_HEAD + ParentLocator *parent_stack; + ElementObject *root_element; + PyObject *sought_tag; + int root_done; + int gettext; +} ElementIterObject; + + +static void +elementiter_dealloc(ElementIterObject *it) +{ + ParentLocator *p = it->parent_stack; + while (p) { + ParentLocator *temp = p; + Py_XDECREF(p->parent); + p = p->next; + PyObject_Free(temp); + } + + Py_XDECREF(it->sought_tag); + Py_XDECREF(it->root_element); + + PyObject_GC_UnTrack(it); + PyObject_GC_Del(it); +} + +static int +elementiter_traverse(ElementIterObject *it, visitproc visit, void *arg) +{ + ParentLocator *p = it->parent_stack; + while (p) { + Py_VISIT(p->parent); + p = p->next; + } + + Py_VISIT(it->root_element); + Py_VISIT(it->sought_tag); + return 0; +} + +/* Helper function for elementiter_next. Add a new parent to the parent stack. + */ +static ParentLocator * +parent_stack_push_new(ParentLocator *stack, ElementObject *parent) +{ + ParentLocator *new_node = PyObject_Malloc(sizeof(ParentLocator)); + if (new_node) { + new_node->parent = parent; + Py_INCREF(parent); + new_node->child_index = 0; + new_node->next = stack; + } + return new_node; +} + +static PyObject * +elementiter_next(ElementIterObject *it) +{ + /* Sub-element iterator. + * + * A short note on gettext: this function serves both the iter() and + * itertext() methods to avoid code duplication. However, there are a few + * small differences in the way these iterations work. Namely: + * - itertext() only yields text from nodes that have it, and continues + * iterating when a node doesn't have text (so it doesn't return any + * node like iter()) + * - itertext() also has to handle tail, after finishing with all the + * children of a node. + */ + ElementObject *cur_parent; + Py_ssize_t child_index; + + while (1) { + /* Handle the case reached in the beginning and end of iteration, where + * the parent stack is empty. The root_done flag gives us indication + * whether we've just started iterating (so root_done is 0), in which + * case the root is returned. If root_done is 1 and we're here, the + * iterator is exhausted. + */ + if (!it->parent_stack->parent) { + if (it->root_done) { + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } else { + it->parent_stack = parent_stack_push_new(it->parent_stack, + it->root_element); + if (!it->parent_stack) { + PyErr_NoMemory(); + return NULL; + } + + it->root_done = 1; + if (it->sought_tag == Py_None || + PyObject_RichCompareBool(it->root_element->tag, + it->sought_tag, Py_EQ) == 1) { + if (it->gettext) { + PyObject *text = JOIN_OBJ(it->root_element->text); + if (PyObject_IsTrue(text)) { + Py_INCREF(text); + return text; + } + } else { + Py_INCREF(it->root_element); + return (PyObject *)it->root_element; + } + } + } + } + + /* See if there are children left to traverse in the current parent. If + * yes, visit the next child. If not, pop the stack and try again. + */ + cur_parent = it->parent_stack->parent; + child_index = it->parent_stack->child_index; + if (cur_parent->extra && child_index < cur_parent->extra->length) { + ElementObject *child = (ElementObject *) + cur_parent->extra->children[child_index]; + it->parent_stack->child_index++; + it->parent_stack = parent_stack_push_new(it->parent_stack, + child); + if (!it->parent_stack) { + PyErr_NoMemory(); + return NULL; + } + + if (it->gettext) { + PyObject *text = JOIN_OBJ(child->text); + if (PyObject_IsTrue(text)) { + Py_INCREF(text); + return text; + } + } else if (it->sought_tag == Py_None || + PyObject_RichCompareBool(child->tag, + it->sought_tag, Py_EQ) == 1) { + Py_INCREF(child); + return (PyObject *)child; + } + else + continue; + } + else { + PyObject *tail = it->gettext ? JOIN_OBJ(cur_parent->tail) : Py_None; + ParentLocator *next = it->parent_stack->next; + Py_XDECREF(it->parent_stack->parent); + PyObject_Free(it->parent_stack); + it->parent_stack = next; + + /* Note that extra condition on it->parent_stack->parent here; + * this is because itertext() is supposed to only return *inner* + * text, not text following the element it began iteration with. + */ + if (it->parent_stack->parent && PyObject_IsTrue(tail)) { + Py_INCREF(tail); + return tail; + } + } + } + + return NULL; +} + + +static PyTypeObject ElementIter_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_elementtree._element_iterator", /* tp_name */ + sizeof(ElementIterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)elementiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 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 | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)elementiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)elementiter_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + + +static PyObject * +create_elementiter(ElementObject *self, PyObject *tag, int gettext) +{ + ElementIterObject *it; + PyObject *star = NULL; + + it = PyObject_GC_New(ElementIterObject, &ElementIter_Type); + if (!it) + return NULL; + if (!(it->parent_stack = PyObject_Malloc(sizeof(ParentLocator)))) { + PyObject_GC_Del(it); + return NULL; + } + + it->parent_stack->parent = NULL; + it->parent_stack->child_index = 0; + it->parent_stack->next = NULL; + + if (PyUnicode_Check(tag)) + star = PyUnicode_FromString("*"); + else if (PyBytes_Check(tag)) + star = PyBytes_FromString("*"); + + if (star && PyObject_RichCompareBool(tag, star, Py_EQ) == 1) + tag = Py_None; + + Py_XDECREF(star); + it->sought_tag = tag; + it->root_done = 0; + it->gettext = gettext; + it->root_element = self; + + Py_INCREF(self); + Py_INCREF(tag); + + PyObject_GC_Track(it); + return (PyObject *)it; +} + + /* ==================================================================== */ /* the tree builder type */ @@ -3238,8 +3464,7 @@ static struct PyModuleDef _elementtreemodule = { PyMODINIT_FUNC PyInit__elementtree(void) { - PyObject *m, *g, *temp; - char* bootstrap; + PyObject *m, *temp; /* Initialize object types */ if (PyType_Ready(&TreeBuilder_Type) < 0) @@ -3255,44 +3480,6 @@ PyInit__elementtree(void) if (!m) return NULL; - /* The code below requires that the module gets already added - to sys.modules. */ - PyDict_SetItemString(PyImport_GetModuleDict(), - _elementtreemodule.m_name, - m); - - /* python glue code */ - - g = PyDict_New(); - if (!g) - return NULL; - - PyDict_SetItemString(g, "__builtins__", PyEval_GetBuiltins()); - - bootstrap = ( - "def iter(node, tag=None):\n" /* helper */ - " if tag == '*':\n" - " tag = None\n" - " if tag is None or node.tag == tag:\n" - " yield node\n" - " for node in node:\n" - " for node in iter(node, tag):\n" - " yield node\n" - - "def itertext(node):\n" /* helper */ - " if node.text:\n" - " yield node.text\n" - " for e in node:\n" - " for s in e.itertext():\n" - " yield s\n" - " if e.tail:\n" - " yield e.tail\n" - - ); - - if (!PyRun_String(bootstrap, Py_file_input, g, NULL)) - return NULL; - if (!(temp = PyImport_ImportModule("copy"))) return NULL; elementtree_deepcopy_obj = PyObject_GetAttrString(temp, "deepcopy"); @@ -3301,9 +3488,6 @@ PyInit__elementtree(void) if (!(elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath"))) return NULL; - elementtree_iter_obj = PyDict_GetItemString(g, "iter"); - elementtree_itertext_obj = PyDict_GetItemString(g, "itertext"); - /* link against pyexpat */ expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0); if (expat_capi) { diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 5961ac9e49..161407de45 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -96,7 +96,7 @@ floatclock(_Py_clock_info_t *info) info->implementation = "clock()"; info->resolution = 1.0 / (double)CLOCKS_PER_SEC; info->monotonic = 1; - info->adjusted = 0; + info->adjustable = 0; } return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC); } @@ -132,7 +132,7 @@ win_perf_counter(_Py_clock_info_t *info, PyObject **result) info->implementation = "QueryPerformanceCounter()"; info->resolution = 1.0 / (double)cpu_frequency; info->monotonic = 1; - info->adjusted = 0; + info->adjustable = 0; } *result = PyFloat_FromDouble(diff / (double)cpu_frequency); return 0; @@ -275,6 +275,10 @@ static PyStructSequence_Field struct_time_type_fields[] = { {"tm_wday", "day of week, range [0, 6], Monday is 0"}, {"tm_yday", "day of year, range [1, 366]"}, {"tm_isdst", "1 if summer time is in effect, 0 if not, and -1 if unknown"}, +#ifdef HAVE_STRUCT_TM_TM_ZONE + {"tm_zone", "abbreviation of timezone name"}, + {"tm_gmtoff", "offset from UTC in seconds"}, +#endif /* HAVE_STRUCT_TM_TM_ZONE */ {0} }; @@ -294,6 +298,7 @@ static PyStructSequence_Desc struct_time_type_desc = { static int initialized; static PyTypeObject StructTimeType; + static PyObject * tmtotuple(struct tm *p) { @@ -312,6 +317,11 @@ tmtotuple(struct tm *p) SET(6, (p->tm_wday + 6) % 7); /* Want Monday == 0 */ SET(7, p->tm_yday + 1); /* Want January, 1 == 1 */ SET(8, p->tm_isdst); +#ifdef HAVE_STRUCT_TM_TM_ZONE + PyStructSequence_SET_ITEM(v, 9, + PyUnicode_DecodeLocale(p->tm_zone, "surrogateescape")); + SET(10, p->tm_gmtoff); +#endif /* HAVE_STRUCT_TM_TM_ZONE */ #undef SET if (PyErr_Occurred()) { Py_XDECREF(v); @@ -371,7 +381,10 @@ PyDoc_STRVAR(gmtime_doc, tm_sec, tm_wday, tm_yday, tm_isdst)\n\ \n\ Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.\n\ -GMT). When 'seconds' is not passed in, convert the current time instead."); +GMT). When 'seconds' is not passed in, convert the current time instead.\n\ +\n\ +If the platform supports the tm_gmtoff and tm_zone, they are available as\n\ +attributes only."); static int pylocaltime(time_t *timep, struct tm *result) @@ -401,7 +414,7 @@ time_localtime(PyObject *self, PyObject *args) if (!parse_time_t_args(args, "|O:localtime", &when)) return NULL; - if (pylocaltime(&when, &buf) == 1) + if (pylocaltime(&when, &buf) == -1) return NULL; return tmtotuple(&buf); } @@ -438,6 +451,17 @@ gettmarg(PyObject *args, struct tm *p) p->tm_mon--; p->tm_wday = (p->tm_wday + 1) % 7; p->tm_yday--; +#ifdef HAVE_STRUCT_TM_TM_ZONE + if (Py_TYPE(args) == &StructTimeType) { + PyObject *item; + item = PyTuple_GET_ITEM(args, 9); + p->tm_zone = item == Py_None ? NULL : _PyUnicode_AsString(item); + item = PyTuple_GET_ITEM(args, 10); + p->tm_gmtoff = item == Py_None ? 0 : PyLong_AsLong(item); + if (PyErr_Occurred()) + return 0; + } +#endif /* HAVE_STRUCT_TM_TM_ZONE */ return 1; } @@ -778,7 +802,10 @@ time_mktime(PyObject *self, PyObject *tup) PyDoc_STRVAR(mktime_doc, "mktime(tuple) -> floating point number\n\ \n\ -Convert a time tuple in local time to seconds since the Epoch."); +Convert a time tuple in local time to seconds since the Epoch.\n\ +Note that mktime(gmtime(0)) will not generally return zero for most\n\ +time zones; instead the returned value will either be equal to that\n\ +of the timezone or altzone attributes on the time module."); #endif /* HAVE_MKTIME */ #ifdef HAVE_WORKING_TZSET @@ -882,7 +909,7 @@ pymonotonic(_Py_clock_info_t *info) return NULL; } info->resolution = timeIncrement * 1e-7; - info->adjusted = 0; + info->adjustable = 0; } return PyFloat_FromDouble(result); @@ -903,7 +930,7 @@ pymonotonic(_Py_clock_info_t *info) info->implementation = "mach_absolute_time()"; info->resolution = (double)timebase.numer / timebase.denom * 1e-9; info->monotonic = 1; - info->adjusted = 0; + info->adjustable = 0; } return PyFloat_FromDouble(secs); @@ -926,13 +953,7 @@ pymonotonic(_Py_clock_info_t *info) struct timespec res; info->monotonic = 1; info->implementation = function; -#if (defined(linux) || defined(__linux) || defined(__linux__)) \ - && !defined(CLOCK_HIGHRES) - /* CLOCK_MONOTONIC is adjusted on Linux */ - info->adjusted = 1; -#else - info->adjusted = 0; -#endif + info->adjustable = 0; if (clock_getres(clk_id, &res) == 0) info->resolution = res.tv_sec + res.tv_nsec * 1e-9; else @@ -1024,7 +1045,7 @@ py_process_time(_Py_clock_info_t *info) info->implementation = "GetProcessTimes()"; info->resolution = 1e-7; info->monotonic = 1; - info->adjusted = 0; + info->adjustable = 0; } return PyFloat_FromDouble(total * 1e-7); #else @@ -1053,7 +1074,7 @@ py_process_time(_Py_clock_info_t *info) struct timespec res; info->implementation = function; info->monotonic = 1; - info->adjusted = 0; + info->adjustable = 0; if (clock_getres(clk_id, &res) == 0) info->resolution = res.tv_sec + res.tv_nsec * 1e-9; else @@ -1071,7 +1092,7 @@ py_process_time(_Py_clock_info_t *info) if (info) { info->implementation = "getrusage(RUSAGE_SELF)"; info->monotonic = 1; - info->adjusted = 0; + info->adjustable = 0; info->resolution = 1e-6; } return PyFloat_FromDouble(total); @@ -1100,7 +1121,7 @@ py_process_time(_Py_clock_info_t *info) if (info) { info->implementation = "times()"; info->monotonic = 1; - info->adjusted = 0; + info->adjustable = 0; info->resolution = 1.0 / ticks_per_second; } return PyFloat_FromDouble(total); @@ -1124,35 +1145,12 @@ PyDoc_STRVAR(process_time_doc, Process time for profiling: sum of the kernel and user-space CPU time."); -static PyTypeObject ClockInfoType; - -PyDoc_STRVAR(ClockInfo_docstring, - "Clock information"); - -static PyStructSequence_Field ClockInfo_fields[] = { - {"implementation", "name of the underlying C function " - "used to get the clock value"}, - {"monotonic", "True if the clock cannot go backward, False otherwise"}, - {"adjusted", "True if the clock can be adjusted " - "(e.g. by a NTP daemon), False otherwise"}, - {"resolution", "resolution of the clock in seconds"}, - {NULL, NULL} -}; - -static PyStructSequence_Desc ClockInfo_desc = { - "time.clock_info", - ClockInfo_docstring, - ClockInfo_fields, - 4, -}; - static PyObject * time_get_clock_info(PyObject *self, PyObject *args) { char *name; - PyObject *obj; _Py_clock_info_t info; - PyObject *result; + PyObject *obj = NULL, *dict, *ns; if (!PyArg_ParseTuple(args, "s:get_clock_info", &name)) return NULL; @@ -1160,12 +1158,12 @@ time_get_clock_info(PyObject *self, PyObject *args) #ifdef Py_DEBUG info.implementation = NULL; info.monotonic = -1; - info.adjusted = -1; + info.adjustable = -1; info.resolution = -1.0; #else info.implementation = ""; info.monotonic = 0; - info.adjusted = 0; + info.adjustable = 0; info.resolution = 1.0; #endif @@ -1191,39 +1189,50 @@ time_get_clock_info(PyObject *self, PyObject *args) return NULL; Py_DECREF(obj); - result = PyStructSequence_New(&ClockInfoType); - if (result == NULL) + dict = PyDict_New(); + if (dict == NULL) return NULL; assert(info.implementation != NULL); obj = PyUnicode_FromString(info.implementation); if (obj == NULL) goto error; - PyStructSequence_SET_ITEM(result, 0, obj); + if (PyDict_SetItemString(dict, "implementation", obj) == -1) + goto error; + Py_CLEAR(obj); assert(info.monotonic != -1); obj = PyBool_FromLong(info.monotonic); if (obj == NULL) goto error; - PyStructSequence_SET_ITEM(result, 1, obj); + if (PyDict_SetItemString(dict, "monotonic", obj) == -1) + goto error; + Py_CLEAR(obj); - assert(info.adjusted != -1); - obj = PyBool_FromLong(info.adjusted); + assert(info.adjustable != -1); + obj = PyBool_FromLong(info.adjustable); if (obj == NULL) goto error; - PyStructSequence_SET_ITEM(result, 2, obj); + if (PyDict_SetItemString(dict, "adjustable", obj) == -1) + goto error; + Py_CLEAR(obj); assert(info.resolution > 0.0); assert(info.resolution <= 1.0); obj = PyFloat_FromDouble(info.resolution); if (obj == NULL) goto error; - PyStructSequence_SET_ITEM(result, 3, obj); + if (PyDict_SetItemString(dict, "resolution", obj) == -1) + goto error; + Py_CLEAR(obj); - return result; + ns = _PyNamespace_New(dict); + Py_DECREF(dict); + return ns; error: - Py_DECREF(result); + Py_DECREF(dict); + Py_XDECREF(obj); return NULL; } @@ -1451,11 +1460,6 @@ PyInit_time(void) PyStructSequence_InitType(&StructTimeType, &struct_time_type_desc); - /* initialize ClockInfoType */ - PyStructSequence_InitType(&ClockInfoType, &ClockInfo_desc); - Py_INCREF(&ClockInfoType); - PyModule_AddObject(m, "clock_info", (PyObject*)&ClockInfoType); - #ifdef MS_WINDOWS winver.dwOSVersionInfoSize = sizeof(winver); if (!GetVersionEx((OSVERSIONINFO*)&winver)) { @@ -1466,6 +1470,11 @@ PyInit_time(void) #endif } Py_INCREF(&StructTimeType); +#ifdef HAVE_STRUCT_TM_TM_ZONE + PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 11); +#else + PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9); +#endif PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType); initialized = 1; return m; @@ -1488,7 +1497,7 @@ floattime(_Py_clock_info_t *info) struct timespec res; info->implementation = "clock_gettime(CLOCK_REALTIME)"; info->monotonic = 0; - info->adjusted = 1; + info->adjustable = 1; if (clock_getres(CLOCK_REALTIME, &res) == 0) info->resolution = res.tv_sec + res.tv_nsec * 1e-9; else |