summaryrefslogtreecommitdiff
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_curses_panel.c122
-rw-r--r--Modules/_decimal/libmpdec/mpdecimal.c16
-rw-r--r--Modules/_elementtree.c364
-rw-r--r--Modules/timemodule.c129
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