summaryrefslogtreecommitdiff
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@haypocalc.com>2011-05-02 01:14:55 +0200
committerVictor Stinner <victor.stinner@haypocalc.com>2011-05-02 01:14:55 +0200
commit96182ca49f43fb8d8dd899fdb5c10ed473ea6109 (patch)
tree8cbc9b2cdd3ac2d222c07b87a00a12a648466ac5 /Modules
parent083a65c28ff2a293af13bcc02fe6b2fb3d9c3f73 (diff)
parent8f7814437f9e61d08d7fbccae2f2938dc58b7ee0 (diff)
downloadcpython-96182ca49f43fb8d8dd899fdb5c10ed473ea6109.tar.gz
(Merge 3.2) Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X
to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/Setup.dist5
-rw-r--r--Modules/_bz2module.c598
-rw-r--r--Modules/_collectionsmodule.c16
-rw-r--r--Modules/_cryptmodule.c (renamed from Modules/cryptmodule.c)4
-rw-r--r--Modules/_ctypes/_ctypes.c2
-rw-r--r--Modules/_ctypes/cfield.c3
-rw-r--r--Modules/_cursesmodule.c4
-rw-r--r--Modules/_datetimemodule.c11
-rw-r--r--Modules/_dbmmodule.c2
-rw-r--r--Modules/_elementtree.c50
-rw-r--r--Modules/_functoolsmodule.c172
-rw-r--r--Modules/_io/bytesio.c2
-rw-r--r--Modules/_io/textio.c135
-rw-r--r--Modules/_json.c67
-rw-r--r--Modules/_multiprocessing/multiprocessing.h2
-rw-r--r--Modules/_pickle.c51
-rw-r--r--Modules/_sqlite/connection.c65
-rw-r--r--Modules/_sqlite/cursor.c8
-rw-r--r--Modules/_sqlite/statement.c4
-rw-r--r--Modules/_ssl.c3
-rw-r--r--Modules/_testcapimodule.c15
-rw-r--r--Modules/_testembed.c6
-rw-r--r--Modules/_threadmodule.c22
-rw-r--r--Modules/_tkinter.c11
-rw-r--r--Modules/arraymodule.c1
-rw-r--r--Modules/audioop.c4
-rw-r--r--Modules/bz2module.c2180
-rw-r--r--Modules/cjkcodecs/_codecs_iso2022.c2
-rw-r--r--Modules/cjkcodecs/multibytecodec.c1
-rw-r--r--Modules/faulthandler.c1106
-rw-r--r--Modules/fpectlmodule.c11
-rw-r--r--Modules/gcmodule.c4
-rw-r--r--Modules/getbuildinfo.c18
-rw-r--r--Modules/itertoolsmodule.c24
-rw-r--r--Modules/main.c5
-rw-r--r--Modules/mathmodule.c5
-rw-r--r--Modules/parsermodule.c1
-rw-r--r--Modules/posixmodule.c1916
-rw-r--r--Modules/pyexpat.c13
-rw-r--r--Modules/readline.c13
-rw-r--r--Modules/selectmodule.c5
-rw-r--r--Modules/signalmodule.c139
-rw-r--r--Modules/socketmodule.c39
-rw-r--r--Modules/termios.c5
-rw-r--r--Modules/timemodule.c29
-rw-r--r--Modules/zipimport.c303
46 files changed, 4358 insertions, 2724 deletions
diff --git a/Modules/Setup.dist b/Modules/Setup.dist
index e1c8fe48f8..2859fa58bc 100644
--- a/Modules/Setup.dist
+++ b/Modules/Setup.dist
@@ -127,6 +127,9 @@ _io -I$(srcdir)/Modules/_io _io/_iomodule.c _io/iobase.c _io/fileio.c _io/bytesi
# builtin module avoids some bootstrapping problems and reduces overhead.
zipimport zipimport.c
+# faulthandler module
+faulthandler faulthandler.c
+
# The rest of the modules listed in this file are all commented out by
# default. Usually they can be detected and built as dynamically
# loaded modules by the new setup.py script added in Python 2.1. If
@@ -207,7 +210,7 @@ _symtable symtablemodule.c
#
# First, look at Setup.config; configure may have set this for you.
-#crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems
+#_crypt _cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems
# Some more UNIX dependent modules -- off by default, since these
diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c
new file mode 100644
index 0000000000..d329c14626
--- /dev/null
+++ b/Modules/_bz2module.c
@@ -0,0 +1,598 @@
+/* _bz2 - Low-level Python interface to libbzip2. */
+
+#define PY_SSIZE_T_CLEAN
+
+#include "Python.h"
+#include "structmember.h"
+
+#ifdef WITH_THREAD
+#include "pythread.h"
+#endif
+
+#include <bzlib.h>
+#include <stdio.h>
+
+
+#ifndef BZ_CONFIG_ERROR
+#define BZ2_bzCompress bzCompress
+#define BZ2_bzCompressInit bzCompressInit
+#define BZ2_bzCompressEnd bzCompressEnd
+#define BZ2_bzDecompress bzDecompress
+#define BZ2_bzDecompressInit bzDecompressInit
+#define BZ2_bzDecompressEnd bzDecompressEnd
+#endif /* ! BZ_CONFIG_ERROR */
+
+
+#ifdef WITH_THREAD
+#define ACQUIRE_LOCK(obj) do { \
+ if (!PyThread_acquire_lock((obj)->lock, 0)) { \
+ Py_BEGIN_ALLOW_THREADS \
+ PyThread_acquire_lock((obj)->lock, 1); \
+ Py_END_ALLOW_THREADS \
+ } } while (0)
+#define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock)
+#else
+#define ACQUIRE_LOCK(obj)
+#define RELEASE_LOCK(obj)
+#endif
+
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+
+
+typedef struct {
+ PyObject_HEAD
+ bz_stream bzs;
+ int flushed;
+#ifdef WITH_THREAD
+ PyThread_type_lock lock;
+#endif
+} BZ2Compressor;
+
+typedef struct {
+ PyObject_HEAD
+ bz_stream bzs;
+ char eof; /* T_BOOL expects a char */
+ PyObject *unused_data;
+#ifdef WITH_THREAD
+ PyThread_type_lock lock;
+#endif
+} BZ2Decompressor;
+
+
+/* Helper functions. */
+
+static int
+catch_bz2_error(int bzerror)
+{
+ switch(bzerror) {
+ case BZ_OK:
+ case BZ_RUN_OK:
+ case BZ_FLUSH_OK:
+ case BZ_FINISH_OK:
+ case BZ_STREAM_END:
+ return 0;
+
+#ifdef BZ_CONFIG_ERROR
+ case BZ_CONFIG_ERROR:
+ PyErr_SetString(PyExc_SystemError,
+ "libbzip2 was not compiled correctly");
+ return 1;
+#endif
+ case BZ_PARAM_ERROR:
+ PyErr_SetString(PyExc_ValueError,
+ "Internal error - "
+ "invalid parameters passed to libbzip2");
+ return 1;
+ case BZ_MEM_ERROR:
+ PyErr_NoMemory();
+ return 1;
+ case BZ_DATA_ERROR:
+ case BZ_DATA_ERROR_MAGIC:
+ PyErr_SetString(PyExc_IOError, "Invalid data stream");
+ return 1;
+ case BZ_IO_ERROR:
+ PyErr_SetString(PyExc_IOError, "Unknown I/O error");
+ return 1;
+ case BZ_UNEXPECTED_EOF:
+ PyErr_SetString(PyExc_EOFError,
+ "Compressed file ended before the logical "
+ "end-of-stream was detected");
+ return 1;
+ case BZ_SEQUENCE_ERROR:
+ PyErr_SetString(PyExc_RuntimeError,
+ "Internal error - "
+ "Invalid sequence of commands sent to libbzip2");
+ return 1;
+ default:
+ PyErr_Format(PyExc_IOError,
+ "Unrecognized error from libbzip2: %d", bzerror);
+ return 1;
+ }
+}
+
+#if BUFSIZ < 8192
+#define SMALLCHUNK 8192
+#else
+#define SMALLCHUNK BUFSIZ
+#endif
+
+#if SIZEOF_INT < 4
+#define BIGCHUNK (512 * 32)
+#else
+#define BIGCHUNK (512 * 1024)
+#endif
+
+static int
+grow_buffer(PyObject **buf)
+{
+ size_t size = PyBytes_GET_SIZE(*buf);
+ if (size <= SMALLCHUNK)
+ return _PyBytes_Resize(buf, size + SMALLCHUNK);
+ else if (size <= BIGCHUNK)
+ return _PyBytes_Resize(buf, size * 2);
+ else
+ return _PyBytes_Resize(buf, size + BIGCHUNK);
+}
+
+
+/* BZ2Compressor class. */
+
+static PyObject *
+compress(BZ2Compressor *c, char *data, size_t len, int action)
+{
+ size_t data_size = 0;
+ PyObject *result;
+
+ result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
+ if (result == NULL)
+ return NULL;
+ c->bzs.next_in = data;
+ /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
+ Do compression in chunks of no more than UINT_MAX bytes each. */
+ c->bzs.avail_in = MIN(len, UINT_MAX);
+ len -= c->bzs.avail_in;
+ c->bzs.next_out = PyBytes_AS_STRING(result);
+ c->bzs.avail_out = PyBytes_GET_SIZE(result);
+ for (;;) {
+ char *this_out;
+ int bzerror;
+
+ Py_BEGIN_ALLOW_THREADS
+ this_out = c->bzs.next_out;
+ bzerror = BZ2_bzCompress(&c->bzs, action);
+ data_size += c->bzs.next_out - this_out;
+ Py_END_ALLOW_THREADS
+ if (catch_bz2_error(bzerror))
+ goto error;
+
+ if (c->bzs.avail_in == 0 && len > 0) {
+ c->bzs.avail_in = MIN(len, UINT_MAX);
+ len -= c->bzs.avail_in;
+ }
+
+ /* In regular compression mode, stop when input data is exhausted.
+ In flushing mode, stop when all buffered data has been flushed. */
+ if ((action == BZ_RUN && c->bzs.avail_in == 0) ||
+ (action == BZ_FINISH && bzerror == BZ_STREAM_END))
+ break;
+
+ if (c->bzs.avail_out == 0) {
+ if (grow_buffer(&result) < 0)
+ goto error;
+ c->bzs.next_out = PyBytes_AS_STRING(result) + data_size;
+ c->bzs.avail_out = PyBytes_GET_SIZE(result) - data_size;
+ }
+ }
+ if (data_size != PyBytes_GET_SIZE(result))
+ if (_PyBytes_Resize(&result, data_size) < 0)
+ goto error;
+ return result;
+
+error:
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyDoc_STRVAR(BZ2Compressor_compress__doc__,
+"compress(data) -> bytes\n"
+"\n"
+"Provide data to the compressor object. Returns a chunk of\n"
+"compressed data if possible, or b'' otherwise.\n"
+"\n"
+"When you have finished providing data to the compressor, call the\n"
+"flush() method to finish the compression process.\n");
+
+static PyObject *
+BZ2Compressor_compress(BZ2Compressor *self, PyObject *args)
+{
+ Py_buffer buffer;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTuple(args, "y*:compress", &buffer))
+ return NULL;
+
+ ACQUIRE_LOCK(self);
+ if (self->flushed)
+ PyErr_SetString(PyExc_ValueError, "Compressor has been flushed");
+ else
+ result = compress(self, buffer.buf, buffer.len, BZ_RUN);
+ RELEASE_LOCK(self);
+ PyBuffer_Release(&buffer);
+ return result;
+}
+
+PyDoc_STRVAR(BZ2Compressor_flush__doc__,
+"flush() -> bytes\n"
+"\n"
+"Finish the compression process. Returns the compressed data left\n"
+"in internal buffers.\n"
+"\n"
+"The compressor object may not be used after this method is called.\n");
+
+static PyObject *
+BZ2Compressor_flush(BZ2Compressor *self, PyObject *noargs)
+{
+ PyObject *result = NULL;
+
+ ACQUIRE_LOCK(self);
+ if (self->flushed)
+ PyErr_SetString(PyExc_ValueError, "Repeated call to flush()");
+ else {
+ self->flushed = 1;
+ result = compress(self, NULL, 0, BZ_FINISH);
+ }
+ RELEASE_LOCK(self);
+ return result;
+}
+
+static int
+BZ2Compressor_init(BZ2Compressor *self, PyObject *args, PyObject *kwargs)
+{
+ int compresslevel = 9;
+ int bzerror;
+
+ if (!PyArg_ParseTuple(args, "|i:BZ2Compressor", &compresslevel))
+ return -1;
+ if (!(1 <= compresslevel && compresslevel <= 9)) {
+ PyErr_SetString(PyExc_ValueError,
+ "compresslevel must be between 1 and 9");
+ return -1;
+ }
+
+#ifdef WITH_THREAD
+ self->lock = PyThread_allocate_lock();
+ if (self->lock == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
+ return -1;
+ }
+#endif
+
+ bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0);
+ if (catch_bz2_error(bzerror))
+ goto error;
+
+ return 0;
+
+error:
+#ifdef WITH_THREAD
+ PyThread_free_lock(self->lock);
+ self->lock = NULL;
+#endif
+ return -1;
+}
+
+static void
+BZ2Compressor_dealloc(BZ2Compressor *self)
+{
+ BZ2_bzCompressEnd(&self->bzs);
+#ifdef WITH_THREAD
+ if (self->lock != NULL)
+ PyThread_free_lock(self->lock);
+#endif
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyMethodDef BZ2Compressor_methods[] = {
+ {"compress", (PyCFunction)BZ2Compressor_compress, METH_VARARGS,
+ BZ2Compressor_compress__doc__},
+ {"flush", (PyCFunction)BZ2Compressor_flush, METH_NOARGS,
+ BZ2Compressor_flush__doc__},
+ {NULL}
+};
+
+PyDoc_STRVAR(BZ2Compressor__doc__,
+"BZ2Compressor(compresslevel=9)\n"
+"\n"
+"Create a compressor object for compressing data incrementally.\n"
+"\n"
+"compresslevel, if given, must be a number between 1 and 9.\n"
+"\n"
+"For one-shot compression, use the compress() function instead.\n");
+
+static PyTypeObject BZ2Compressor_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_bz2.BZ2Compressor", /* tp_name */
+ sizeof(BZ2Compressor), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BZ2Compressor_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 */
+ BZ2Compressor__doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BZ2Compressor_methods, /* 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 */
+ (initproc)BZ2Compressor_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+
+/* BZ2Decompressor class. */
+
+static PyObject *
+decompress(BZ2Decompressor *d, char *data, size_t len)
+{
+ size_t data_size = 0;
+ PyObject *result;
+
+ result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
+ if (result == NULL)
+ return result;
+ d->bzs.next_in = data;
+ /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
+ Do decompression in chunks of no more than UINT_MAX bytes each. */
+ d->bzs.avail_in = MIN(len, UINT_MAX);
+ len -= d->bzs.avail_in;
+ d->bzs.next_out = PyBytes_AS_STRING(result);
+ d->bzs.avail_out = PyBytes_GET_SIZE(result);
+ for (;;) {
+ char *this_out;
+ int bzerror;
+
+ Py_BEGIN_ALLOW_THREADS
+ this_out = d->bzs.next_out;
+ bzerror = BZ2_bzDecompress(&d->bzs);
+ data_size += d->bzs.next_out - this_out;
+ Py_END_ALLOW_THREADS
+ if (catch_bz2_error(bzerror))
+ goto error;
+ if (bzerror == BZ_STREAM_END) {
+ d->eof = 1;
+ len += d->bzs.avail_in;
+ if (len > 0) { /* Save leftover input to unused_data */
+ Py_CLEAR(d->unused_data);
+ d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, len);
+ if (d->unused_data == NULL)
+ goto error;
+ }
+ break;
+ }
+ if (d->bzs.avail_in == 0) {
+ if (len == 0)
+ break;
+ d->bzs.avail_in = MIN(len, UINT_MAX);
+ len -= d->bzs.avail_in;
+ }
+ if (d->bzs.avail_out == 0) {
+ if (grow_buffer(&result) < 0)
+ goto error;
+ d->bzs.next_out = PyBytes_AS_STRING(result) + data_size;
+ d->bzs.avail_out = PyBytes_GET_SIZE(result) - data_size;
+ }
+ }
+ if (data_size != PyBytes_GET_SIZE(result))
+ if (_PyBytes_Resize(&result, data_size) < 0)
+ goto error;
+ return result;
+
+error:
+ Py_XDECREF(result);
+ return NULL;
+}
+
+PyDoc_STRVAR(BZ2Decompressor_decompress__doc__,
+"decompress(data) -> bytes\n"
+"\n"
+"Provide data to the decompressor object. Returns a chunk of\n"
+"decompressed data if possible, or b'' otherwise.\n"
+"\n"
+"Attempting to decompress data after the end of stream is reached\n"
+"raises an EOFError. Any data found after the end of the stream\n"
+"is ignored and saved in the unused_data attribute.\n");
+
+static PyObject *
+BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args)
+{
+ Py_buffer buffer;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTuple(args, "y*:decompress", &buffer))
+ return NULL;
+
+ ACQUIRE_LOCK(self);
+ if (self->eof)
+ PyErr_SetString(PyExc_EOFError, "End of stream already reached");
+ else
+ result = decompress(self, buffer.buf, buffer.len);
+ RELEASE_LOCK(self);
+ PyBuffer_Release(&buffer);
+ return result;
+}
+
+static int
+BZ2Decompressor_init(BZ2Decompressor *self, PyObject *args, PyObject *kwargs)
+{
+ int bzerror;
+
+ if (!PyArg_ParseTuple(args, ":BZ2Decompressor"))
+ return -1;
+
+#ifdef WITH_THREAD
+ self->lock = PyThread_allocate_lock();
+ if (self->lock == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
+ return -1;
+ }
+#endif
+
+ self->unused_data = PyBytes_FromStringAndSize("", 0);
+ if (self->unused_data == NULL)
+ goto error;
+
+ bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0);
+ if (catch_bz2_error(bzerror))
+ goto error;
+
+ return 0;
+
+error:
+ Py_CLEAR(self->unused_data);
+#ifdef WITH_THREAD
+ PyThread_free_lock(self->lock);
+ self->lock = NULL;
+#endif
+ return -1;
+}
+
+static void
+BZ2Decompressor_dealloc(BZ2Decompressor *self)
+{
+ BZ2_bzDecompressEnd(&self->bzs);
+ Py_CLEAR(self->unused_data);
+#ifdef WITH_THREAD
+ if (self->lock != NULL)
+ PyThread_free_lock(self->lock);
+#endif
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyMethodDef BZ2Decompressor_methods[] = {
+ {"decompress", (PyCFunction)BZ2Decompressor_decompress, METH_VARARGS,
+ BZ2Decompressor_decompress__doc__},
+ {NULL}
+};
+
+PyDoc_STRVAR(BZ2Decompressor_eof__doc__,
+"True if the end-of-stream marker has been reached.");
+
+PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__,
+"Data found after the end of the compressed stream.");
+
+static PyMemberDef BZ2Decompressor_members[] = {
+ {"eof", T_BOOL, offsetof(BZ2Decompressor, eof),
+ READONLY, BZ2Decompressor_eof__doc__},
+ {"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data),
+ READONLY, BZ2Decompressor_unused_data__doc__},
+ {NULL}
+};
+
+PyDoc_STRVAR(BZ2Decompressor__doc__,
+"BZ2Decompressor()\n"
+"\n"
+"Create a decompressor object for decompressing data incrementally.\n"
+"\n"
+"For one-shot decompression, use the decompress() function instead.\n");
+
+static PyTypeObject BZ2Decompressor_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_bz2.BZ2Decompressor", /* tp_name */
+ sizeof(BZ2Decompressor), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BZ2Decompressor_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 */
+ BZ2Decompressor__doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BZ2Decompressor_methods, /* tp_methods */
+ BZ2Decompressor_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BZ2Decompressor_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+
+/* Module initialization. */
+
+static struct PyModuleDef _bz2module = {
+ PyModuleDef_HEAD_INIT,
+ "_bz2",
+ NULL,
+ -1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+PyMODINIT_FUNC
+PyInit__bz2(void)
+{
+ PyObject *m;
+
+ if (PyType_Ready(&BZ2Compressor_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&BZ2Decompressor_Type) < 0)
+ return NULL;
+
+ m = PyModule_Create(&_bz2module);
+ if (m == NULL)
+ return NULL;
+
+ Py_INCREF(&BZ2Compressor_Type);
+ PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Compressor_Type);
+
+ Py_INCREF(&BZ2Decompressor_Type);
+ PyModule_AddObject(m, "BZ2Decompressor",
+ (PyObject *)&BZ2Decompressor_Type);
+
+ return m;
+}
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index 5545d1eff2..8743408d8c 100644
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -1552,12 +1552,8 @@ _count_elements(PyObject *self, PyObject *args)
if (PyDict_CheckExact(mapping)) {
while (1) {
key = PyIter_Next(it);
- if (key == NULL) {
- if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
- PyErr_Clear();
- else
- break;
- }
+ if (key == NULL)
+ break;
oldval = PyDict_GetItem(mapping, key);
if (oldval == NULL) {
if (PyDict_SetItem(mapping, key, one) == -1)
@@ -1575,12 +1571,8 @@ _count_elements(PyObject *self, PyObject *args)
} else {
while (1) {
key = PyIter_Next(it);
- if (key == NULL) {
- if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
- PyErr_Clear();
- else
- break;
- }
+ if (key == NULL)
+ break;
oldval = PyObject_GetItem(mapping, key);
if (oldval == NULL) {
if (!PyErr_Occurred() || !PyErr_ExceptionMatches(PyExc_KeyError))
diff --git a/Modules/cryptmodule.c b/Modules/_cryptmodule.c
index d5a42ff951..51007889bf 100644
--- a/Modules/cryptmodule.c
+++ b/Modules/_cryptmodule.c
@@ -45,7 +45,7 @@ static PyMethodDef crypt_methods[] = {
static struct PyModuleDef cryptmodule = {
PyModuleDef_HEAD_INIT,
- "crypt",
+ "_crypt",
NULL,
-1,
crypt_methods,
@@ -56,7 +56,7 @@ static struct PyModuleDef cryptmodule = {
};
PyMODINIT_FUNC
-PyInit_crypt(void)
+PyInit__crypt(void)
{
return PyModule_Create(&cryptmodule);
}
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 8e8598002d..79c86637f6 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -1844,7 +1844,7 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
if (PyUnicode_Check(proto)) {
- PyObject *v = _PyUnicode_AsDefaultEncodedString(proto, NULL);
+ PyObject *v = _PyUnicode_AsDefaultEncodedString(proto);
if (!v)
goto error;
proto_str = PyBytes_AS_STRING(v);
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index ccaa3c9d70..0aa9f0b5bc 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -52,7 +52,7 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
{
CFieldObject *self;
PyObject *proto;
- Py_ssize_t size, align, length;
+ Py_ssize_t size, align;
SETFUNC setfunc = NULL;
GETFUNC getfunc = NULL;
StgDictObject *dict;
@@ -106,7 +106,6 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
}
size = dict->size;
- length = dict->length;
proto = desc;
/* Field descriptors for 'c_char * n' are be scpecial cased to
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index 092fb69fb2..9b3b8cde0e 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -105,10 +105,6 @@ char *PyCursesVersion = "2.2";
#include "Python.h"
-#ifdef __osf__
-#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */
-#endif
-
#ifdef __hpux
#define STRICT_SYSV_CURSES
#endif
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index 6ee531768a..a19c0c355b 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -766,7 +766,7 @@ typedef struct
PyObject *name;
} PyDateTime_TimeZone;
-/* The interned UTC timezone instance */
+/* The interned UTC timezone instance */
static PyObject *PyDateTime_TimeZone_UTC;
/* Create new timezone instance checking offset range. This
@@ -1461,7 +1461,7 @@ delta_to_microseconds(PyDateTime_Delta *self)
goto Done;
Py_DECREF(x1);
Py_DECREF(x2);
- x1 = x2 = NULL;
+ /* x1 = */ x2 = NULL;
/* x3 has days+seconds in seconds */
x1 = PyNumber_Multiply(x3, us_per_second); /* us */
@@ -3288,7 +3288,6 @@ timezone_repr(PyDateTime_TimeZone *self)
static PyObject *
timezone_str(PyDateTime_TimeZone *self)
{
- char buf[10];
int hours, minutes, seconds;
PyObject *offset;
char sign;
@@ -3314,11 +3313,9 @@ timezone_str(PyDateTime_TimeZone *self)
Py_DECREF(offset);
minutes = divmod(seconds, 60, &seconds);
hours = divmod(minutes, 60, &minutes);
- assert(seconds == 0);
/* XXX ignore sub-minute data, curently not allowed. */
- PyOS_snprintf(buf, sizeof(buf), "UTC%c%02d:%02d", sign, hours, minutes);
-
- return PyUnicode_FromString(buf);
+ assert(seconds == 0);
+ return PyUnicode_FromFormat("UTC%c%02d:%02d", sign, hours, minutes);
}
static PyObject *
diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c
index 827acce895..69a7112e7d 100644
--- a/Modules/_dbmmodule.c
+++ b/Modules/_dbmmodule.c
@@ -219,7 +219,7 @@ dbm_contains(PyObject *self, PyObject *arg)
return -1;
}
if (PyUnicode_Check(arg)) {
- arg = _PyUnicode_AsDefaultEncodedString(arg, NULL);
+ arg = _PyUnicode_AsDefaultEncodedString(arg);
if (arg == NULL)
return -1;
}
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index 3061d8eaf3..6373c4848f 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -226,7 +226,7 @@ typedef struct {
PyObject* *children;
PyObject* _children[STATIC_CHILDREN];
-
+
} ElementObjectExtra;
typedef struct {
@@ -354,14 +354,14 @@ element_resize(ElementObject* self, int extra)
/* use Python 2.4's list growth strategy */
size = (size >> 3) + (size < 9 ? 3 : 6) + size;
/* Coverity CID #182 size_error: Allocating 1 bytes to pointer "children"
- * which needs at least 4 bytes.
- * Although it's a false alarm always assume at least one child to
+ * which needs at least 4 bytes.
+ * Although it's a false alarm always assume at least one child to
* be safe.
*/
size = size ? size : 1;
if (self->extra->children != self->extra->_children) {
/* Coverity CID #182 size_error: Allocating 1 bytes to pointer
- * "children", which needs at least 4 bytes. Although it's a
+ * "children", which needs at least 4 bytes. Although it's a
* false alarm always assume at least one child to be safe.
*/
children = PyObject_Realloc(self->extra->children,
@@ -606,7 +606,7 @@ element_copy(ElementObject* self, PyObject* args)
Py_INCREF(JOIN_OBJ(element->tail));
if (self->extra) {
-
+
if (element_resize(element, self->extra->length) < 0) {
Py_DECREF(element);
return NULL;
@@ -618,7 +618,7 @@ element_copy(ElementObject* self, PyObject* args)
}
element->extra->length = self->extra->length;
-
+
}
return (PyObject*) element;
@@ -661,7 +661,7 @@ element_deepcopy(ElementObject* self, PyObject* args)
if (!element)
return NULL;
-
+
text = deepcopy(JOIN_OBJ(self->text), memo);
if (!text)
goto error;
@@ -675,7 +675,7 @@ element_deepcopy(ElementObject* self, PyObject* args)
element->tail = JOIN_SET(tail, JOIN_GET(self->tail));
if (self->extra) {
-
+
if (element_resize(element, self->extra->length) < 0)
goto error;
@@ -689,7 +689,7 @@ element_deepcopy(ElementObject* self, PyObject* args)
}
element->extra->length = self->extra->length;
-
+
}
/* add object to memo dictionary (so deepcopy won't visit it again) */
@@ -800,7 +800,7 @@ element_find(ElementObject* self, PyObject* args)
if (!self->extra)
Py_RETURN_NONE;
-
+
for (i = 0; i < self->extra->length; i++) {
PyObject* item = self->extra->children[i];
if (Element_CheckExact(item) &&
@@ -953,7 +953,7 @@ static PyObject*
element_iter(ElementObject* self, PyObject* args)
{
PyObject* result;
-
+
PyObject* tag = Py_None;
if (!PyArg_ParseTuple(args, "|O:iter", &tag))
return NULL;
@@ -985,7 +985,7 @@ static PyObject*
element_itertext(ElementObject* self, PyObject* args)
{
PyObject* result;
-
+
if (!PyArg_ParseTuple(args, ":itertext"))
return NULL;
@@ -1483,7 +1483,7 @@ element_getattro(ElementObject* self, PyObject* nameobj)
if (PyUnicode_Check(nameobj))
name = _PyUnicode_AsString(nameobj);
-
+
if (name == NULL)
return NULL;
@@ -2113,7 +2113,7 @@ makeuniversal(XMLParserObject* self, const char* string)
Py_INCREF(key);
tag = key;
}
-
+
/* decode universal name */
p = PyBytes_AS_STRING(tag);
value = PyUnicode_DecodeUTF8(p, size, "strict");
@@ -2138,13 +2138,15 @@ makeuniversal(XMLParserObject* self, const char* string)
static void
expat_set_error(const char* message, int line, int column)
{
- PyObject *error;
- PyObject *position;
- char buffer[256];
+ PyObject *errmsg, *error, *position;
- sprintf(buffer, "%.100s: line %d, column %d", message, line, column);
+ errmsg = PyUnicode_FromFormat("%s: line %d, column %d",
+ message, line, column);
+ if (errmsg == NULL)
+ return;
- error = PyObject_CallFunction(elementtree_parseerror_obj, "s", buffer);
+ error = PyObject_CallFunction(elementtree_parseerror_obj, "O", errmsg);
+ Py_DECREF(errmsg);
if (!error)
return;
@@ -2407,7 +2409,7 @@ expat_unknown_encoding_handler(XMLParserObject *self, const XML_Char *name,
for (i = 0; i < 256; i++)
s[i] = i;
-
+
u = PyUnicode_Decode((char*) s, 256, name, "replace");
if (!u)
return XML_STATUS_ERROR;
@@ -2466,7 +2468,7 @@ xmlparser(PyObject* self_, PyObject* args, PyObject* kw)
PyObject_Del(self);
return NULL;
}
-
+
self->names = PyDict_New();
if (!self->names) {
PyObject_Del(self->entity);
@@ -2645,7 +2647,7 @@ xmlparser_parse(XMLParserObject* self, PyObject* args)
reader = PyObject_GetAttrString(fileobj, "read");
if (!reader)
return NULL;
-
+
/* read from open file object */
for (;;) {
@@ -2796,7 +2798,7 @@ static PyMethodDef xmlparser_methods[] = {
{NULL, NULL}
};
-static PyObject*
+static PyObject*
xmlparser_getattro(XMLParserObject* self, PyObject* nameobj)
{
if (PyUnicode_Check(nameobj)) {
@@ -2957,7 +2959,7 @@ PyInit__elementtree(void)
" break\n"
" parser.feed(data)\n"
" self._root = parser.close()\n"
- " else:\n"
+ " else:\n"
" parser = cElementTree.XMLParser()\n"
" self._root = parser._parse(source)\n"
" return self._root\n"
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index d8a283bcec..0882d368d1 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -330,6 +330,176 @@ static PyTypeObject partial_type = {
};
+/* cmp_to_key ***************************************************************/
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *cmp;
+ PyObject *object;
+} keyobject;
+
+static void
+keyobject_dealloc(keyobject *ko)
+{
+ Py_DECREF(ko->cmp);
+ Py_XDECREF(ko->object);
+ PyObject_FREE(ko);
+}
+
+static int
+keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
+{
+ Py_VISIT(ko->cmp);
+ if (ko->object)
+ Py_VISIT(ko->object);
+ return 0;
+}
+
+static int
+keyobject_clear(keyobject *ko)
+{
+ Py_CLEAR(ko->cmp);
+ if (ko->object)
+ Py_CLEAR(ko->object);
+ return 0;
+}
+
+static PyMemberDef keyobject_members[] = {
+ {"obj", T_OBJECT,
+ offsetof(keyobject, object), 0,
+ PyDoc_STR("Value wrapped by a key function.")},
+ {NULL}
+};
+
+static PyObject *
+keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
+
+static PyObject *
+keyobject_richcompare(PyObject *ko, PyObject *other, int op);
+
+static PyTypeObject keyobject_type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "functools.KeyWrapper", /* tp_name */
+ sizeof(keyobject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)keyobject_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 */
+ (ternaryfunc)keyobject_call, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ (traverseproc)keyobject_traverse, /* tp_traverse */
+ (inquiry)keyobject_clear, /* tp_clear */
+ keyobject_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ keyobject_members, /* tp_members */
+ 0, /* tp_getset */
+};
+
+static PyObject *
+keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
+{
+ PyObject *object;
+ keyobject *result;
+ static char *kwargs[] = {"obj", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
+ return NULL;
+ result = PyObject_New(keyobject, &keyobject_type);
+ if (!result)
+ return NULL;
+ Py_INCREF(ko->cmp);
+ result->cmp = ko->cmp;
+ Py_INCREF(object);
+ result->object = object;
+ return (PyObject *)result;
+}
+
+static PyObject *
+keyobject_richcompare(PyObject *ko, PyObject *other, int op)
+{
+ PyObject *res;
+ PyObject *args;
+ PyObject *x;
+ PyObject *y;
+ PyObject *compare;
+ PyObject *answer;
+ static PyObject *zero;
+
+ if (zero == NULL) {
+ zero = PyLong_FromLong(0);
+ if (!zero)
+ return NULL;
+ }
+
+ if (Py_TYPE(other) != &keyobject_type){
+ PyErr_Format(PyExc_TypeError, "other argument must be K instance");
+ return NULL;
+ }
+ compare = ((keyobject *) ko)->cmp;
+ assert(compare != NULL);
+ x = ((keyobject *) ko)->object;
+ y = ((keyobject *) other)->object;
+ if (!x || !y){
+ PyErr_Format(PyExc_AttributeError, "object");
+ return NULL;
+ }
+
+ /* Call the user's comparison function and translate the 3-way
+ * result into true or false (or error).
+ */
+ args = PyTuple_New(2);
+ if (args == NULL)
+ return NULL;
+ Py_INCREF(x);
+ Py_INCREF(y);
+ PyTuple_SET_ITEM(args, 0, x);
+ PyTuple_SET_ITEM(args, 1, y);
+ res = PyObject_Call(compare, args, NULL);
+ Py_DECREF(args);
+ if (res == NULL)
+ return NULL;
+ answer = PyObject_RichCompare(res, zero, op);
+ Py_DECREF(res);
+ return answer;
+}
+
+static PyObject *
+functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *cmp;
+ static char *kwargs[] = {"mycmp", NULL};
+ keyobject *object;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
+ return NULL;
+ object = PyObject_New(keyobject, &keyobject_type);
+ if (!object)
+ return NULL;
+ Py_INCREF(cmp);
+ object->cmp = cmp;
+ object->object = NULL;
+ return (PyObject *)object;
+}
+
+PyDoc_STRVAR(functools_cmp_to_key_doc,
+"Convert a cmp= function into a key= function.");
+
/* reduce (used to be a builtin) ********************************************/
static PyObject *
@@ -413,6 +583,8 @@ PyDoc_STRVAR(module_doc,
static PyMethodDef module_methods[] = {
{"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
+ {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
+ METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c
index b40513f7a7..65ec93124a 100644
--- a/Modules/_io/bytesio.c
+++ b/Modules/_io/bytesio.c
@@ -938,13 +938,11 @@ static int
bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags)
{
int ret;
- void *ptr;
bytesio *b = (bytesio *) obj->source;
if (view == NULL) {
b->exports++;
return 0;
}
- ptr = (void *) obj;
ret = PyBuffer_FillInfo(view, (PyObject*)obj, b->buf, b->string_size,
0, flags);
if (ret >= 0) {
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 73d83a1c0b..35bd922b8e 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -678,12 +678,16 @@ typedef struct
PyObject *pending_bytes; /* list of bytes objects waiting to be
written, or NULL */
Py_ssize_t pending_bytes_count;
- PyObject *snapshot;
+
/* snapshot is either None, or a tuple (dec_flags, next_input) where
* dec_flags is the second (integer) item of the decoder state and
* next_input is the chunk of input bytes that comes next after the
* snapshot point. We use this to reconstruct decoder states in tell().
*/
+ PyObject *snapshot;
+ /* Bytes-to-characters ratio for the current chunk. Serves as input for
+ the heuristic in tell(). */
+ double b2cratio;
/* Cache raw object if it's a FileIO object */
PyObject *raw;
@@ -850,6 +854,7 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds)
self->decoded_chars_used = 0;
self->pending_bytes_count = 0;
self->encodefunc = NULL;
+ self->b2cratio = 0.0;
if (encoding == NULL) {
/* Try os.device_encoding(fileno) */
@@ -1390,6 +1395,7 @@ textiowrapper_read_chunk(textio *self)
PyObject *dec_flags = NULL;
PyObject *input_chunk = NULL;
PyObject *decoded_chars, *chunk_size;
+ Py_ssize_t nbytes, nchars;
int eof;
/* The return value is True unless EOF was reached. The decoded string is
@@ -1435,7 +1441,8 @@ textiowrapper_read_chunk(textio *self)
goto fail;
assert(PyBytes_Check(input_chunk));
- eof = (PyBytes_Size(input_chunk) == 0);
+ nbytes = PyBytes_Size(input_chunk);
+ eof = (nbytes == 0);
if (Py_TYPE(self->decoder) == &PyIncrementalNewlineDecoder_Type) {
decoded_chars = _PyIncrementalNewlineDecoder_decode(
@@ -1450,7 +1457,12 @@ textiowrapper_read_chunk(textio *self)
if (decoded_chars == NULL)
goto fail;
textiowrapper_set_decoded_chars(self, decoded_chars);
- if (PyUnicode_GET_SIZE(decoded_chars) > 0)
+ nchars = PyUnicode_GET_SIZE(decoded_chars);
+ if (nchars > 0)
+ self->b2cratio = (double) nbytes / nchars;
+ else
+ self->b2cratio = 0.0;
+ if (nchars > 0)
eof = 0;
if (self->telling) {
@@ -2139,8 +2151,12 @@ textiowrapper_tell(textio *self, PyObject *args)
cookie_type cookie = {0,0,0,0,0};
PyObject *next_input;
Py_ssize_t chars_to_skip, chars_decoded;
+ Py_ssize_t skip_bytes, skip_back;
PyObject *saved_state = NULL;
char *input, *input_end;
+ char *dec_buffer;
+ Py_ssize_t dec_buffer_len;
+ int dec_flags;
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
@@ -2176,6 +2192,7 @@ textiowrapper_tell(textio *self, PyObject *args)
#else
cookie.start_pos = PyLong_AsLong(posobj);
#endif
+ Py_DECREF(posobj);
if (PyErr_Occurred())
goto fail;
@@ -2190,57 +2207,99 @@ textiowrapper_tell(textio *self, PyObject *args)
/* How many decoded characters have been used up since the snapshot? */
if (self->decoded_chars_used == 0) {
/* We haven't moved from the snapshot point. */
- Py_DECREF(posobj);
return textiowrapper_build_cookie(&cookie);
}
chars_to_skip = self->decoded_chars_used;
- /* Starting from the snapshot position, we will walk the decoder
- * forward until it gives us enough decoded characters.
- */
+ /* Decoder state will be restored at the end */
saved_state = PyObject_CallMethodObjArgs(self->decoder,
_PyIO_str_getstate, NULL);
if (saved_state == NULL)
goto fail;
- /* Note our initial start point. */
- if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
- goto fail;
+#define DECODER_GETSTATE() do { \
+ PyObject *_state = PyObject_CallMethodObjArgs(self->decoder, \
+ _PyIO_str_getstate, NULL); \
+ if (_state == NULL) \
+ goto fail; \
+ if (!PyArg_Parse(_state, "(y#i)", &dec_buffer, &dec_buffer_len, &dec_flags)) { \
+ Py_DECREF(_state); \
+ goto fail; \
+ } \
+ Py_DECREF(_state); \
+ } while (0)
+
+ /* TODO: replace assert with exception */
+#define DECODER_DECODE(start, len, res) do { \
+ PyObject *_decoded = PyObject_CallMethod( \
+ self->decoder, "decode", "y#", start, len); \
+ if (_decoded == NULL) \
+ goto fail; \
+ assert (PyUnicode_Check(_decoded)); \
+ res = PyUnicode_GET_SIZE(_decoded); \
+ Py_DECREF(_decoded); \
+ } while (0)
+
+ /* Fast search for an acceptable start point, close to our
+ current pos */
+ skip_bytes = (Py_ssize_t) (self->b2cratio * chars_to_skip);
+ skip_back = 1;
+ assert(skip_back <= PyBytes_GET_SIZE(next_input));
+ input = PyBytes_AS_STRING(next_input);
+ while (skip_bytes > 0) {
+ /* Decode up to temptative start point */
+ if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
+ goto fail;
+ DECODER_DECODE(input, skip_bytes, chars_decoded);
+ if (chars_decoded <= chars_to_skip) {
+ DECODER_GETSTATE();
+ if (dec_buffer_len == 0) {
+ /* Before pos and no bytes buffered in decoder => OK */
+ cookie.dec_flags = dec_flags;
+ chars_to_skip -= chars_decoded;
+ break;
+ }
+ /* Skip back by buffered amount and reset heuristic */
+ skip_bytes -= dec_buffer_len;
+ skip_back = 1;
+ }
+ else {
+ /* We're too far ahead, skip back a bit */
+ skip_bytes -= skip_back;
+ skip_back *= 2;
+ }
+ }
+ if (skip_bytes <= 0) {
+ skip_bytes = 0;
+ if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
+ goto fail;
+ }
- /* Feed the decoder one byte at a time. As we go, note the
- * nearest "safe start point" before the current location
- * (a point where the decoder has nothing buffered, so seek()
+ /* Note our initial start point. */
+ cookie.start_pos += skip_bytes;
+ cookie.chars_to_skip = chars_to_skip;
+ if (chars_to_skip == 0)
+ goto finally;
+
+ /* We should be close to the desired position. Now feed the decoder one
+ * byte at a time until we reach the `chars_to_skip` target.
+ * As we go, note the nearest "safe start point" before the current
+ * location (a point where the decoder has nothing buffered, so seek()
* can safely start from there and advance to this location).
*/
chars_decoded = 0;
input = PyBytes_AS_STRING(next_input);
input_end = input + PyBytes_GET_SIZE(next_input);
+ input += skip_bytes;
while (input < input_end) {
- PyObject *state;
- char *dec_buffer;
- Py_ssize_t dec_buffer_len;
- int dec_flags;
-
- PyObject *decoded = PyObject_CallMethod(
- self->decoder, "decode", "y#", input, 1);
- if (decoded == NULL)
- goto fail;
- assert (PyUnicode_Check(decoded));
- chars_decoded += PyUnicode_GET_SIZE(decoded);
- Py_DECREF(decoded);
+ Py_ssize_t n;
+ DECODER_DECODE(input, 1, n);
+ /* We got n chars for 1 byte */
+ chars_decoded += n;
cookie.bytes_to_feed += 1;
-
- state = PyObject_CallMethodObjArgs(self->decoder,
- _PyIO_str_getstate, NULL);
- if (state == NULL)
- goto fail;
- if (!PyArg_Parse(state, "(y#i)", &dec_buffer, &dec_buffer_len, &dec_flags)) {
- Py_DECREF(state);
- goto fail;
- }
- Py_DECREF(state);
+ DECODER_GETSTATE();
if (dec_buffer_len == 0 && chars_decoded <= chars_to_skip) {
/* Decoder buffer is empty, so this is a safe start point. */
@@ -2272,8 +2331,7 @@ textiowrapper_tell(textio *self, PyObject *args)
}
}
- /* finally */
- Py_XDECREF(posobj);
+finally:
res = PyObject_CallMethod(self->decoder, "setstate", "(O)", saved_state);
Py_DECREF(saved_state);
if (res == NULL)
@@ -2284,8 +2342,7 @@ textiowrapper_tell(textio *self, PyObject *args)
cookie.chars_to_skip = Py_SAFE_DOWNCAST(chars_to_skip, Py_ssize_t, int);
return textiowrapper_build_cookie(&cookie);
- fail:
- Py_XDECREF(posobj);
+fail:
if (saved_state) {
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);
diff --git a/Modules/_json.c b/Modules/_json.c
index 75b14ee827..917709429b 100644
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -335,7 +335,7 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
PyObject *rval = NULL;
Py_ssize_t len = PyUnicode_GET_SIZE(pystr);
Py_ssize_t begin = end - 1;
- Py_ssize_t next = begin;
+ Py_ssize_t next /* = begin */;
const Py_UNICODE *buf = PyUnicode_AS_UNICODE(pystr);
PyObject *chunks = NULL;
PyObject *chunk = NULL;
@@ -842,7 +842,8 @@ _match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_
Py_ssize_t idx = start;
int is_float = 0;
PyObject *rval;
- PyObject *numstr;
+ PyObject *numstr = NULL;
+ PyObject *custom_func;
/* read a sign if it's there, make sure it's not the end of the string */
if (str[idx] == '-') {
@@ -895,22 +896,37 @@ _match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_
}
}
- /* copy the section we determined to be a number */
- numstr = PyUnicode_FromUnicode(&str[start], idx - start);
- if (numstr == NULL)
- return NULL;
- if (is_float) {
- /* parse as a float using a fast path if available, otherwise call user defined method */
- if (s->parse_float != (PyObject *)&PyFloat_Type) {
- rval = PyObject_CallFunctionObjArgs(s->parse_float, numstr, NULL);
- }
- else {
- rval = PyFloat_FromString(numstr);
- }
+ if (is_float && s->parse_float != (PyObject *)&PyFloat_Type)
+ custom_func = s->parse_float;
+ else if (!is_float && s->parse_int != (PyObject *) &PyLong_Type)
+ custom_func = s->parse_int;
+ else
+ custom_func = NULL;
+
+ if (custom_func) {
+ /* copy the section we determined to be a number */
+ numstr = PyUnicode_FromUnicode(&str[start], idx - start);
+ if (numstr == NULL)
+ return NULL;
+ rval = PyObject_CallFunctionObjArgs(custom_func, numstr, NULL);
}
else {
- /* no fast path for unicode -> int, just call */
- rval = PyObject_CallFunctionObjArgs(s->parse_int, numstr, NULL);
+ Py_ssize_t i, n;
+ char *buf;
+ /* Straight conversion to ASCII, to avoid costly conversion of
+ decimal unicode digits (which cannot appear here) */
+ n = idx - start;
+ numstr = PyBytes_FromStringAndSize(NULL, n);
+ if (numstr == NULL)
+ return NULL;
+ buf = PyBytes_AS_STRING(numstr);
+ for (i = 0; i < n; i++) {
+ buf[i] = (char) str[i + start];
+ }
+ if (is_float)
+ rval = PyFloat_FromString(numstr);
+ else
+ rval = PyLong_FromString(buf, NULL, 10);
}
Py_DECREF(numstr);
*next_idx_ptr = idx;
@@ -1532,13 +1548,12 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
goto bail;
Py_CLEAR(ident);
}
+ /* TODO DOES NOT RUN; dead code
if (s->indent != Py_None) {
- /* TODO: DOES NOT RUN */
indent_level -= 1;
- /*
- yield '\n' + (' ' * (_indent * _current_indent_level))
- */
- }
+
+ yield '\n' + (' ' * (_indent * _current_indent_level))
+ }*/
if (PyList_Append(rval, close_dict))
goto bail;
return 0;
@@ -1624,13 +1639,13 @@ encoder_listencode_list(PyEncoderObject *s, PyObject *rval, PyObject *seq, Py_ss
goto bail;
Py_CLEAR(ident);
}
+
+ /* TODO: DOES NOT RUN
if (s->indent != Py_None) {
- /* TODO: DOES NOT RUN */
indent_level -= 1;
- /*
- yield '\n' + (' ' * (_indent * _current_indent_level))
- */
- }
+
+ yield '\n' + (' ' * (_indent * _current_indent_level))
+ }*/
if (PyList_Append(rval, close_array))
goto bail;
Py_DECREF(s_fast);
diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h
index 14425de821..b9917c3ee6 100644
--- a/Modules/_multiprocessing/multiprocessing.h
+++ b/Modules/_multiprocessing/multiprocessing.h
@@ -4,7 +4,7 @@
#define PY_SSIZE_T_CLEAN
#ifdef __sun
-/* The control message API is only available on Solaris
+/* The control message API is only available on Solaris
if XPG 4.2 or later is requested. */
#define _XOPEN_SOURCE 500
#endif
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
index e13d8742ca..822d03c49a 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -2842,6 +2842,28 @@ save_pers(PicklerObject *self, PyObject *obj, PyObject *func)
return status;
}
+static PyObject *
+get_class(PyObject *obj)
+{
+ PyObject *cls;
+ static PyObject *str_class;
+
+ if (str_class == NULL) {
+ str_class = PyUnicode_InternFromString("__class__");
+ if (str_class == NULL)
+ return NULL;
+ }
+ cls = PyObject_GetAttr(obj, str_class);
+ if (cls == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ cls = (PyObject *) Py_TYPE(obj);
+ Py_INCREF(cls);
+ }
+ }
+ return cls;
+}
+
/* We're saving obj, and args is the 2-thru-5 tuple returned by the
* appropriate __reduce__ method for obj.
*/
@@ -2907,17 +2929,18 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj)
/* Protocol 2 special case: if callable's name is __newobj__, use
NEWOBJ. */
if (use_newobj) {
- static PyObject *newobj_str = NULL;
- PyObject *name_str;
+ static PyObject *newobj_str = NULL, *name_str = NULL;
+ PyObject *name;
if (newobj_str == NULL) {
newobj_str = PyUnicode_InternFromString("__newobj__");
- if (newobj_str == NULL)
+ name_str = PyUnicode_InternFromString("__name__");
+ if (newobj_str == NULL || name_str == NULL)
return -1;
}
- name_str = PyObject_GetAttrString(callable, "__name__");
- if (name_str == NULL) {
+ name = PyObject_GetAttr(callable, name_str);
+ if (name == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError))
PyErr_Clear();
else
@@ -2925,9 +2948,9 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj)
use_newobj = 0;
}
else {
- use_newobj = PyUnicode_Check(name_str) &&
- PyUnicode_Compare(name_str, newobj_str) == 0;
- Py_DECREF(name_str);
+ use_newobj = PyUnicode_Check(name) &&
+ PyUnicode_Compare(name, newobj_str) == 0;
+ Py_DECREF(name);
}
}
if (use_newobj) {
@@ -2943,20 +2966,14 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj)
}
cls = PyTuple_GET_ITEM(argtup, 0);
- if (!PyObject_HasAttrString(cls, "__new__")) {
+ if (!PyType_Check(cls)) {
PyErr_SetString(PicklingError, "args[0] from "
- "__newobj__ args has no __new__");
+ "__newobj__ args is not a type");
return -1;
}
if (obj != NULL) {
- obj_class = PyObject_GetAttrString(obj, "__class__");
- if (obj_class == NULL) {
- if (PyErr_ExceptionMatches(PyExc_AttributeError))
- PyErr_Clear();
- else
- return -1;
- }
+ obj_class = get_class(obj);
p = obj_class != cls; /* true iff a problem */
Py_DECREF(obj_class);
if (p) {
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index e4969e36a3..76d635a8fd 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -673,7 +673,6 @@ void _pysqlite_final_callback(sqlite3_context* context)
{
PyObject* function_result = NULL;
PyObject** aggregate_instance;
- PyObject* aggregate_class;
#ifdef WITH_THREAD
PyGILState_STATE threadstate;
@@ -681,8 +680,6 @@ void _pysqlite_final_callback(sqlite3_context* context)
threadstate = PyGILState_Ensure();
#endif
- aggregate_class = (PyObject*)sqlite3_user_data(context);
-
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
if (!*aggregate_instance) {
/* this branch is executed if there was an exception in the aggregate's
@@ -907,6 +904,38 @@ static int _progress_handler(void* user_arg)
return rc;
}
+static void _trace_callback(void* user_arg, const char* statement_string)
+{
+ PyObject *py_statement = NULL;
+ PyObject *ret = NULL;
+
+#ifdef WITH_THREAD
+ PyGILState_STATE gilstate;
+
+ gilstate = PyGILState_Ensure();
+#endif
+ py_statement = PyUnicode_DecodeUTF8(statement_string,
+ strlen(statement_string), "replace");
+ if (py_statement) {
+ ret = PyObject_CallFunctionObjArgs((PyObject*)user_arg, py_statement, NULL);
+ Py_DECREF(py_statement);
+ }
+
+ if (ret) {
+ Py_DECREF(ret);
+ } else {
+ if (_enable_callback_tracebacks) {
+ PyErr_Print();
+ } else {
+ PyErr_Clear();
+ }
+ }
+
+#ifdef WITH_THREAD
+ PyGILState_Release(gilstate);
+#endif
+}
+
static PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
{
PyObject* authorizer_cb;
@@ -966,6 +995,34 @@ static PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* s
return Py_None;
}
+static PyObject* pysqlite_connection_set_trace_callback(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* trace_callback;
+
+ static char *kwlist[] = { "trace_callback", NULL };
+
+ if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+ return NULL;
+ }
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_trace_callback",
+ kwlist, &trace_callback)) {
+ return NULL;
+ }
+
+ if (trace_callback == Py_None) {
+ /* None clears the trace callback previously set */
+ sqlite3_trace(self->db, 0, (void*)0);
+ } else {
+ if (PyDict_SetItem(self->function_pinboard, trace_callback, Py_None) == -1)
+ return NULL;
+ sqlite3_trace(self->db, _trace_callback, trace_callback);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
#ifdef HAVE_LOAD_EXTENSION
static PyObject* pysqlite_enable_load_extension(pysqlite_Connection* self, PyObject* args)
{
@@ -1519,6 +1576,8 @@ static PyMethodDef connection_methods[] = {
#endif
{"set_progress_handler", (PyCFunction)pysqlite_connection_set_progress_handler, METH_VARARGS|METH_KEYWORDS,
PyDoc_STR("Sets progress handler callback. Non-standard.")},
+ {"set_trace_callback", (PyCFunction)pysqlite_connection_set_trace_callback, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("Sets a trace callback called for each SQL statement (passed as unicode). Non-standard.")},
{"execute", (PyCFunction)pysqlite_connection_execute, METH_VARARGS,
PyDoc_STR("Executes a SQL statement. Non-standard.")},
{"executemany", (PyCFunction)pysqlite_connection_executemany, METH_VARARGS,
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index 97908a3093..eb099c44e5 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -126,11 +126,9 @@ static int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject*
static void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
{
- int rc;
-
/* Reset the statement if the user has not closed the cursor */
if (self->statement) {
- rc = pysqlite_statement_reset(self->statement);
+ pysqlite_statement_reset(self->statement);
Py_DECREF(self->statement);
}
@@ -529,7 +527,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
if (self->statement != NULL) {
/* There is an active statement */
- rc = pysqlite_statement_reset(self->statement);
+ pysqlite_statement_reset(self->statement);
}
operation_cstr = _PyUnicode_AsStringAndSize(operation, &operation_len);
@@ -734,7 +732,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
}
if (multiple) {
- rc = pysqlite_statement_reset(self->statement);
+ pysqlite_statement_reset(self->statement);
}
Py_XDECREF(parameters);
}
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index f89fc9abf1..4e039c1985 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -369,11 +369,9 @@ void pysqlite_statement_mark_dirty(pysqlite_Statement* self)
void pysqlite_statement_dealloc(pysqlite_Statement* self)
{
- int rc;
-
if (self->st) {
Py_BEGIN_ALLOW_THREADS
- rc = sqlite3_finalize(self->st);
+ sqlite3_finalize(self->st);
Py_END_ALLOW_THREADS
}
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index e49426464e..0ae02a146d 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -354,7 +354,6 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
/* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
- sockstate = 0;
do {
PySSL_BEGIN_ALLOW_THREADS
ret = SSL_do_handshake(self->ssl);
@@ -1090,7 +1089,6 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
goto error;
}
do {
- err = 0;
PySSL_BEGIN_ALLOW_THREADS
len = SSL_write(self->ssl, buf.buf, buf.len);
err = SSL_get_error(self->ssl, len);
@@ -1226,7 +1224,6 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args)
}
}
do {
- err = 0;
PySSL_BEGIN_ALLOW_THREADS
count = SSL_read(self->ssl, mem, len);
err = SSL_get_error(self->ssl, count);
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index f19d0df594..35d25e6489 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -22,14 +22,7 @@ static PyObject *TestError; /* set to exception object in init */
static PyObject *
raiseTestError(const char* test_name, const char* msg)
{
- char buf[2048];
-
- if (strlen(test_name) + strlen(msg) > sizeof(buf) - 50)
- PyErr_SetString(TestError, "internal error msg too large");
- else {
- PyOS_snprintf(buf, sizeof(buf), "%s: %s", test_name, msg);
- PyErr_SetString(TestError, buf);
- }
+ PyErr_Format(TestError, "%s: %s", test_name, msg);
return NULL;
}
@@ -43,11 +36,9 @@ static PyObject*
sizeof_error(const char* fatname, const char* typname,
int expected, int got)
{
- char buf[1024];
- PyOS_snprintf(buf, sizeof(buf),
- "%.200s #define == %d but sizeof(%.200s) == %d",
+ PyErr_Format(TestError,
+ "%s #define == %d but sizeof(%s) == %d",
fatname, expected, typname, got);
- PyErr_SetString(TestError, buf);
return (PyObject*)NULL;
}
diff --git a/Modules/_testembed.c b/Modules/_testembed.c
index 0df5ede6e4..51b439f480 100644
--- a/Modules/_testembed.c
+++ b/Modules/_testembed.c
@@ -17,7 +17,9 @@ void print_subinterp(void)
int main(int argc, char *argv[])
{
PyThreadState *mainstate, *substate;
+#ifdef WITH_THREAD
PyGILState_STATE gilstate;
+#endif
int i, j;
for (i=0; i<3; i++) {
@@ -28,10 +30,12 @@ int main(int argc, char *argv[])
Py_Initialize();
mainstate = PyThreadState_Get();
+#ifdef WITH_THREAD
PyEval_InitThreads();
PyEval_ReleaseThread(mainstate);
gilstate = PyGILState_Ensure();
+#endif
print_subinterp();
PyThreadState_Swap(NULL);
@@ -43,7 +47,9 @@ int main(int argc, char *argv[])
PyThreadState_Swap(mainstate);
print_subinterp();
+#ifdef WITH_THREAD
PyGILState_Release(gilstate);
+#endif
PyEval_RestoreThread(mainstate);
Py_Finalize();
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index d91c99a4a7..8881427269 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -53,6 +53,7 @@ acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds)
_PyTime_timeval curtime;
_PyTime_timeval endtime;
+
if (microseconds > 0) {
_PyTime_gettimeofday(&endtime);
endtime.tv_sec += microseconds / (1000 * 1000);
@@ -75,7 +76,7 @@ acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds)
/* If we're using a timeout, recompute the timeout after processing
* signals, since those can take time. */
- if (microseconds >= 0) {
+ if (microseconds > 0) {
_PyTime_gettimeofday(&curtime);
microseconds = ((endtime.tv_sec - curtime.tv_sec) * 1000000 +
(endtime.tv_usec - curtime.tv_usec));
@@ -413,6 +414,12 @@ rlock_release_save(rlockobject *self)
long owner;
unsigned long count;
+ if (self->rlock_count == 0) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "cannot release un-acquired lock");
+ return NULL;
+ }
+
owner = self->rlock_owner;
count = self->rlock_count;
self->rlock_count = 0;
@@ -1222,11 +1229,9 @@ the suggested approach in the absence of more specific information).");
static PyMethodDef thread_methods[] = {
{"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
- METH_VARARGS,
- start_new_doc},
+ METH_VARARGS, start_new_doc},
{"start_new", (PyCFunction)thread_PyThread_start_new_thread,
- METH_VARARGS,
- start_new_doc},
+ METH_VARARGS, start_new_doc},
{"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
METH_NOARGS, allocate_doc},
{"allocate", (PyCFunction)thread_PyThread_allocate_lock,
@@ -1242,8 +1247,7 @@ static PyMethodDef thread_methods[] = {
{"_count", (PyCFunction)thread__count,
METH_NOARGS, _count_doc},
{"stack_size", (PyCFunction)thread_stack_size,
- METH_VARARGS,
- stack_size_doc},
+ METH_VARARGS, stack_size_doc},
{NULL, NULL} /* sentinel */
};
@@ -1307,7 +1311,9 @@ PyInit__thread(void)
/* Add a symbolic constant */
d = PyModule_GetDict(m);
- ThreadError = PyErr_NewException("_thread.error", NULL, NULL);
+ ThreadError = PyExc_RuntimeError;
+ Py_INCREF(ThreadError);
+
PyDict_SetItemString(d, "error", ThreadError);
Locktype.tp_doc = lock_doc;
Py_INCREF(&Locktype);
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index c7c1530545..91b1b53ae8 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -2005,7 +2005,7 @@ static int
PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
{
PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
- PyObject *self, *func, *arg, *res;
+ PyObject *func, *arg, *res;
int i, rv;
Tcl_Obj *obj_res;
@@ -2014,7 +2014,6 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
/* TBD: no error checking here since we know, via the
* Tkapp_CreateCommand() that the client data is a two-tuple
*/
- self = data->self;
func = data->func;
/* Create argument list (argv1, ..., argvN) */
@@ -2401,11 +2400,9 @@ static PyObject *
Tktt_Repr(PyObject *self)
{
TkttObject *v = (TkttObject *)self;
- char buf[100];
-
- PyOS_snprintf(buf, sizeof(buf), "<tktimertoken at %p%s>", v,
- v->func == NULL ? ", handler deleted" : "");
- return PyUnicode_FromString(buf);
+ return PyUnicode_FromFormat("<tktimertoken at %p%s>",
+ v,
+ v->func == NULL ? ", handler deleted" : "");
}
static PyTypeObject Tktt_Type =
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index fe6106c9a4..533f404f91 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -876,7 +876,6 @@ array_inplace_repeat(arrayobject *self, Py_ssize_t n)
if (Py_SIZE(self) > 0) {
if (n < 0)
n = 0;
- items = self->ob_item;
if ((self->ob_descr->itemsize != 0) &&
(Py_SIZE(self) > PY_SSIZE_T_MAX / self->ob_descr->itemsize)) {
return PyErr_NoMemory();
diff --git a/Modules/audioop.c b/Modules/audioop.c
index a031d42b0f..daf70dcf9c 100644
--- a/Modules/audioop.c
+++ b/Modules/audioop.c
@@ -513,7 +513,6 @@ audioop_findfit(PyObject *self, PyObject *args)
best_result = result;
best_j = 0;
- j = 0;
for ( j=1; j<=len1-len2; j++) {
aj_m1 = (double)cp1[j-1];
@@ -599,7 +598,6 @@ audioop_findmax(PyObject *self, PyObject *args)
best_result = result;
best_j = 0;
- j = 0;
for ( j=1; j<=len1-len2; j++) {
aj_m1 = (double)cp1[j-1];
@@ -1433,7 +1431,6 @@ audioop_lin2adpcm(PyObject *self, PyObject *args)
if ( state == Py_None ) {
/* First time, it seems. Set defaults */
valpred = 0;
- step = 7;
index = 0;
} else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) )
return 0;
@@ -1534,7 +1531,6 @@ audioop_adpcm2lin(PyObject *self, PyObject *args)
if ( state == Py_None ) {
/* First time, it seems. Set defaults */
valpred = 0;
- step = 7;
index = 0;
} else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) )
return 0;
diff --git a/Modules/bz2module.c b/Modules/bz2module.c
deleted file mode 100644
index 3e55202bd8..0000000000
--- a/Modules/bz2module.c
+++ /dev/null
@@ -1,2180 +0,0 @@
-/*
-
-python-bz2 - python bz2 library interface
-
-Copyright (c) 2002 Gustavo Niemeyer <niemeyer@conectiva.com>
-Copyright (c) 2002 Python Software Foundation; All Rights Reserved
-
-*/
-
-#include "Python.h"
-#include <stdio.h>
-#include <bzlib.h>
-#include "structmember.h"
-
-#ifdef WITH_THREAD
-#include "pythread.h"
-#endif
-
-static char __author__[] =
-"The bz2 python module was written by:\n\
-\n\
- Gustavo Niemeyer <niemeyer@conectiva.com>\n\
-";
-
-/* Our very own off_t-like type, 64-bit if possible */
-/* copied from Objects/fileobject.c */
-#if !defined(HAVE_LARGEFILE_SUPPORT)
-typedef off_t Py_off_t;
-#elif SIZEOF_OFF_T >= 8
-typedef off_t Py_off_t;
-#elif SIZEOF_FPOS_T >= 8
-typedef fpos_t Py_off_t;
-#else
-#error "Large file support, but neither off_t nor fpos_t is large enough."
-#endif
-
-#define BUF(v) PyBytes_AS_STRING(v)
-
-#define MODE_CLOSED 0
-#define MODE_READ 1
-#define MODE_READ_EOF 2
-#define MODE_WRITE 3
-
-#define BZ2FileObject_Check(v) (Py_TYPE(v) == &BZ2File_Type)
-
-
-#ifdef BZ_CONFIG_ERROR
-
-#if SIZEOF_LONG >= 8
-#define BZS_TOTAL_OUT(bzs) \
- (((long)bzs->total_out_hi32 << 32) + bzs->total_out_lo32)
-#elif SIZEOF_LONG_LONG >= 8
-#define BZS_TOTAL_OUT(bzs) \
- (((PY_LONG_LONG)bzs->total_out_hi32 << 32) + bzs->total_out_lo32)
-#else
-#define BZS_TOTAL_OUT(bzs) \
- bzs->total_out_lo32
-#endif
-
-#else /* ! BZ_CONFIG_ERROR */
-
-#define BZ2_bzRead bzRead
-#define BZ2_bzReadOpen bzReadOpen
-#define BZ2_bzReadClose bzReadClose
-#define BZ2_bzWrite bzWrite
-#define BZ2_bzWriteOpen bzWriteOpen
-#define BZ2_bzWriteClose bzWriteClose
-#define BZ2_bzCompress bzCompress
-#define BZ2_bzCompressInit bzCompressInit
-#define BZ2_bzCompressEnd bzCompressEnd
-#define BZ2_bzDecompress bzDecompress
-#define BZ2_bzDecompressInit bzDecompressInit
-#define BZ2_bzDecompressEnd bzDecompressEnd
-
-#define BZS_TOTAL_OUT(bzs) bzs->total_out
-
-#endif /* ! BZ_CONFIG_ERROR */
-
-
-#ifdef WITH_THREAD
-#define ACQUIRE_LOCK(obj) do { \
- if (!PyThread_acquire_lock(obj->lock, 0)) { \
- Py_BEGIN_ALLOW_THREADS \
- PyThread_acquire_lock(obj->lock, 1); \
- Py_END_ALLOW_THREADS \
- } } while(0)
-#define RELEASE_LOCK(obj) PyThread_release_lock(obj->lock)
-#else
-#define ACQUIRE_LOCK(obj)
-#define RELEASE_LOCK(obj)
-#endif
-
-/* Bits in f_newlinetypes */
-#define NEWLINE_UNKNOWN 0 /* No newline seen, yet */
-#define NEWLINE_CR 1 /* \r newline seen */
-#define NEWLINE_LF 2 /* \n newline seen */
-#define NEWLINE_CRLF 4 /* \r\n newline seen */
-
-/* ===================================================================== */
-/* Structure definitions. */
-
-typedef struct {
- PyObject_HEAD
- FILE *rawfp;
-
- char* f_buf; /* Allocated readahead buffer */
- char* f_bufend; /* Points after last occupied position */
- char* f_bufptr; /* Current buffer position */
-
- BZFILE *fp;
- int mode;
- Py_off_t pos;
- Py_off_t size;
-#ifdef WITH_THREAD
- PyThread_type_lock lock;
-#endif
-} BZ2FileObject;
-
-typedef struct {
- PyObject_HEAD
- bz_stream bzs;
- int running;
-#ifdef WITH_THREAD
- PyThread_type_lock lock;
-#endif
-} BZ2CompObject;
-
-typedef struct {
- PyObject_HEAD
- bz_stream bzs;
- int running;
- PyObject *unused_data;
-#ifdef WITH_THREAD
- PyThread_type_lock lock;
-#endif
-} BZ2DecompObject;
-
-/* ===================================================================== */
-/* Utility functions. */
-
-/* Refuse regular I/O if there's data in the iteration-buffer.
- * Mixing them would cause data to arrive out of order, as the read*
- * methods don't use the iteration buffer. */
-static int
-check_iterbuffered(BZ2FileObject *f)
-{
- if (f->f_buf != NULL &&
- (f->f_bufend - f->f_bufptr) > 0 &&
- f->f_buf[0] != '\0') {
- PyErr_SetString(PyExc_ValueError,
- "Mixing iteration and read methods would lose data");
- return -1;
- }
- return 0;
-}
-
-static int
-Util_CatchBZ2Error(int bzerror)
-{
- int ret = 0;
- switch(bzerror) {
- case BZ_OK:
- case BZ_STREAM_END:
- break;
-
-#ifdef BZ_CONFIG_ERROR
- case BZ_CONFIG_ERROR:
- PyErr_SetString(PyExc_SystemError,
- "the bz2 library was not compiled "
- "correctly");
- ret = 1;
- break;
-#endif
-
- case BZ_PARAM_ERROR:
- PyErr_SetString(PyExc_ValueError,
- "the bz2 library has received wrong "
- "parameters");
- ret = 1;
- break;
-
- case BZ_MEM_ERROR:
- PyErr_NoMemory();
- ret = 1;
- break;
-
- case BZ_DATA_ERROR:
- case BZ_DATA_ERROR_MAGIC:
- PyErr_SetString(PyExc_IOError, "invalid data stream");
- ret = 1;
- break;
-
- case BZ_IO_ERROR:
- PyErr_SetString(PyExc_IOError, "unknown IO error");
- ret = 1;
- break;
-
- case BZ_UNEXPECTED_EOF:
- PyErr_SetString(PyExc_EOFError,
- "compressed file ended before the "
- "logical end-of-stream was detected");
- ret = 1;
- break;
-
- case BZ_SEQUENCE_ERROR:
- PyErr_SetString(PyExc_RuntimeError,
- "wrong sequence of bz2 library "
- "commands used");
- ret = 1;
- break;
- }
- return ret;
-}
-
-#if BUFSIZ < 8192
-#define SMALLCHUNK 8192
-#else
-#define SMALLCHUNK BUFSIZ
-#endif
-
-#if SIZEOF_INT < 4
-#define BIGCHUNK (512 * 32)
-#else
-#define BIGCHUNK (512 * 1024)
-#endif
-
-/* This is a hacked version of Python's fileobject.c:new_buffersize(). */
-static size_t
-Util_NewBufferSize(size_t currentsize)
-{
- if (currentsize > SMALLCHUNK) {
- /* Keep doubling until we reach BIGCHUNK;
- then keep adding BIGCHUNK. */
- if (currentsize <= BIGCHUNK)
- return currentsize + currentsize;
- else
- return currentsize + BIGCHUNK;
- }
- return currentsize + SMALLCHUNK;
-}
-
-/* This is a hacked version of Python's fileobject.c:get_line(). */
-static PyObject *
-Util_GetLine(BZ2FileObject *f, int n)
-{
- char c;
- char *buf, *end;
- size_t total_v_size; /* total # of slots in buffer */
- size_t used_v_size; /* # used slots in buffer */
- size_t increment; /* amount to increment the buffer */
- PyObject *v;
- int bzerror;
- int bytes_read;
-
- total_v_size = n > 0 ? n : 100;
- v = PyBytes_FromStringAndSize((char *)NULL, total_v_size);
- if (v == NULL)
- return NULL;
-
- buf = BUF(v);
- end = buf + total_v_size;
-
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- do {
- bytes_read = BZ2_bzRead(&bzerror, f->fp, &c, 1);
- f->pos++;
- if (bytes_read == 0)
- break;
- *buf++ = c;
- } while (bzerror == BZ_OK && c != '\n' && buf != end);
- Py_END_ALLOW_THREADS
- if (bzerror == BZ_STREAM_END) {
- f->size = f->pos;
- f->mode = MODE_READ_EOF;
- break;
- } else if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- Py_DECREF(v);
- return NULL;
- }
- if (c == '\n')
- break;
- /* Must be because buf == end */
- if (n > 0)
- break;
- used_v_size = total_v_size;
- increment = total_v_size >> 2; /* mild exponential growth */
- total_v_size += increment;
- if (total_v_size > INT_MAX) {
- PyErr_SetString(PyExc_OverflowError,
- "line is longer than a Python string can hold");
- Py_DECREF(v);
- return NULL;
- }
- if (_PyBytes_Resize(&v, total_v_size) < 0) {
- return NULL;
- }
- buf = BUF(v) + used_v_size;
- end = BUF(v) + total_v_size;
- }
-
- used_v_size = buf - BUF(v);
- if (used_v_size != total_v_size) {
- if (_PyBytes_Resize(&v, used_v_size) < 0) {
- v = NULL;
- }
- }
- return v;
-}
-
-/* This is a hacked version of Python's fileobject.c:drop_readahead(). */
-static void
-Util_DropReadAhead(BZ2FileObject *f)
-{
- if (f->f_buf != NULL) {
- PyMem_Free(f->f_buf);
- f->f_buf = NULL;
- }
-}
-
-/* This is a hacked version of Python's fileobject.c:readahead(). */
-static int
-Util_ReadAhead(BZ2FileObject *f, int bufsize)
-{
- int chunksize;
- int bzerror;
-
- if (f->f_buf != NULL) {
- if((f->f_bufend - f->f_bufptr) >= 1)
- return 0;
- else
- Util_DropReadAhead(f);
- }
- if (f->mode == MODE_READ_EOF) {
- f->f_bufptr = f->f_buf;
- f->f_bufend = f->f_buf;
- return 0;
- }
- if ((f->f_buf = PyMem_Malloc(bufsize)) == NULL) {
- PyErr_NoMemory();
- return -1;
- }
- Py_BEGIN_ALLOW_THREADS
- chunksize = BZ2_bzRead(&bzerror, f->fp, f->f_buf, bufsize);
- Py_END_ALLOW_THREADS
- f->pos += chunksize;
- if (bzerror == BZ_STREAM_END) {
- f->size = f->pos;
- f->mode = MODE_READ_EOF;
- } else if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- Util_DropReadAhead(f);
- return -1;
- }
- f->f_bufptr = f->f_buf;
- f->f_bufend = f->f_buf + chunksize;
- return 0;
-}
-
-/* This is a hacked version of Python's
- * fileobject.c:readahead_get_line_skip(). */
-static PyBytesObject *
-Util_ReadAheadGetLineSkip(BZ2FileObject *f, int skip, int bufsize)
-{
- PyBytesObject* s;
- char *bufptr;
- char *buf;
- int len;
-
- if (f->f_buf == NULL)
- if (Util_ReadAhead(f, bufsize) < 0)
- return NULL;
-
- len = f->f_bufend - f->f_bufptr;
- if (len == 0)
- return (PyBytesObject *)
- PyBytes_FromStringAndSize(NULL, skip);
- bufptr = memchr(f->f_bufptr, '\n', len);
- if (bufptr != NULL) {
- bufptr++; /* Count the '\n' */
- len = bufptr - f->f_bufptr;
- s = (PyBytesObject *)
- PyBytes_FromStringAndSize(NULL, skip+len);
- if (s == NULL)
- return NULL;
- memcpy(PyBytes_AS_STRING(s)+skip, f->f_bufptr, len);
- f->f_bufptr = bufptr;
- if (bufptr == f->f_bufend)
- Util_DropReadAhead(f);
- } else {
- bufptr = f->f_bufptr;
- buf = f->f_buf;
- f->f_buf = NULL; /* Force new readahead buffer */
- s = Util_ReadAheadGetLineSkip(f, skip+len,
- bufsize + (bufsize>>2));
- if (s == NULL) {
- PyMem_Free(buf);
- return NULL;
- }
- memcpy(PyBytes_AS_STRING(s)+skip, bufptr, len);
- PyMem_Free(buf);
- }
- return s;
-}
-
-/* ===================================================================== */
-/* Methods of BZ2File. */
-
-PyDoc_STRVAR(BZ2File_read__doc__,
-"read([size]) -> string\n\
-\n\
-Read at most size uncompressed bytes, returned as a string. If the size\n\
-argument is negative or omitted, read until EOF is reached.\n\
-");
-
-/* This is a hacked version of Python's fileobject.c:file_read(). */
-static PyObject *
-BZ2File_read(BZ2FileObject *self, PyObject *args)
-{
- long bytesrequested = -1;
- size_t bytesread, buffersize, chunksize;
- int bzerror;
- PyObject *ret = NULL;
-
- if (!PyArg_ParseTuple(args, "|l:read", &bytesrequested))
- return NULL;
-
- ACQUIRE_LOCK(self);
- switch (self->mode) {
- case MODE_READ:
- break;
- case MODE_READ_EOF:
- ret = PyBytes_FromStringAndSize("", 0);
- goto cleanup;
- case MODE_CLOSED:
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- goto cleanup;
- default:
- PyErr_SetString(PyExc_IOError,
- "file is not ready for reading");
- goto cleanup;
- }
-
- /* refuse to mix with f.next() */
- if (check_iterbuffered(self))
- goto cleanup;
-
- if (bytesrequested < 0)
- buffersize = Util_NewBufferSize((size_t)0);
- else
- buffersize = bytesrequested;
- if (buffersize > INT_MAX) {
- PyErr_SetString(PyExc_OverflowError,
- "requested number of bytes is "
- "more than a Python string can hold");
- goto cleanup;
- }
- ret = PyBytes_FromStringAndSize((char *)NULL, buffersize);
- if (ret == NULL || buffersize == 0)
- goto cleanup;
- bytesread = 0;
-
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- chunksize = BZ2_bzRead(&bzerror, self->fp,
- BUF(ret)+bytesread,
- buffersize-bytesread);
- self->pos += chunksize;
- Py_END_ALLOW_THREADS
- bytesread += chunksize;
- if (bzerror == BZ_STREAM_END) {
- self->size = self->pos;
- self->mode = MODE_READ_EOF;
- break;
- } else if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- Py_DECREF(ret);
- ret = NULL;
- goto cleanup;
- }
- if (bytesrequested < 0) {
- buffersize = Util_NewBufferSize(buffersize);
- if (_PyBytes_Resize(&ret, buffersize) < 0) {
- ret = NULL;
- goto cleanup;
- }
- } else {
- break;
- }
- }
- if (bytesread != buffersize) {
- if (_PyBytes_Resize(&ret, bytesread) < 0) {
- ret = NULL;
- }
- }
-
-cleanup:
- RELEASE_LOCK(self);
- return ret;
-}
-
-PyDoc_STRVAR(BZ2File_readline__doc__,
-"readline([size]) -> string\n\
-\n\
-Return the next line from the file, as a string, retaining newline.\n\
-A non-negative size argument will limit the maximum number of bytes to\n\
-return (an incomplete line may be returned then). Return an empty\n\
-string at EOF.\n\
-");
-
-static PyObject *
-BZ2File_readline(BZ2FileObject *self, PyObject *args)
-{
- PyObject *ret = NULL;
- int sizehint = -1;
-
- if (!PyArg_ParseTuple(args, "|i:readline", &sizehint))
- return NULL;
-
- ACQUIRE_LOCK(self);
- switch (self->mode) {
- case MODE_READ:
- break;
- case MODE_READ_EOF:
- ret = PyBytes_FromStringAndSize("", 0);
- goto cleanup;
- case MODE_CLOSED:
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- goto cleanup;
- default:
- PyErr_SetString(PyExc_IOError,
- "file is not ready for reading");
- goto cleanup;
- }
-
- /* refuse to mix with f.next() */
- if (check_iterbuffered(self))
- goto cleanup;
-
- if (sizehint == 0)
- ret = PyBytes_FromStringAndSize("", 0);
- else
- ret = Util_GetLine(self, (sizehint < 0) ? 0 : sizehint);
-
-cleanup:
- RELEASE_LOCK(self);
- return ret;
-}
-
-PyDoc_STRVAR(BZ2File_readlines__doc__,
-"readlines([size]) -> list\n\
-\n\
-Call readline() repeatedly and return a list of lines read.\n\
-The optional size argument, if given, is an approximate bound on the\n\
-total number of bytes in the lines returned.\n\
-");
-
-/* This is a hacked version of Python's fileobject.c:file_readlines(). */
-static PyObject *
-BZ2File_readlines(BZ2FileObject *self, PyObject *args)
-{
- long sizehint = 0;
- PyObject *list = NULL;
- PyObject *line;
- char small_buffer[SMALLCHUNK];
- char *buffer = small_buffer;
- size_t buffersize = SMALLCHUNK;
- PyObject *big_buffer = NULL;
- size_t nfilled = 0;
- size_t nread;
- size_t totalread = 0;
- char *p, *q, *end;
- int err;
- int shortread = 0;
- int bzerror;
-
- if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint))
- return NULL;
-
- ACQUIRE_LOCK(self);
- switch (self->mode) {
- case MODE_READ:
- break;
- case MODE_READ_EOF:
- list = PyList_New(0);
- goto cleanup;
- case MODE_CLOSED:
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- goto cleanup;
- default:
- PyErr_SetString(PyExc_IOError,
- "file is not ready for reading");
- goto cleanup;
- }
-
- /* refuse to mix with f.next() */
- if (check_iterbuffered(self))
- goto cleanup;
-
- if ((list = PyList_New(0)) == NULL)
- goto cleanup;
-
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- nread = BZ2_bzRead(&bzerror, self->fp,
- buffer+nfilled, buffersize-nfilled);
- self->pos += nread;
- Py_END_ALLOW_THREADS
- if (bzerror == BZ_STREAM_END) {
- self->size = self->pos;
- self->mode = MODE_READ_EOF;
- if (nread == 0) {
- sizehint = 0;
- break;
- }
- shortread = 1;
- } else if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- error:
- Py_DECREF(list);
- list = NULL;
- goto cleanup;
- }
- totalread += nread;
- p = memchr(buffer+nfilled, '\n', nread);
- if (!shortread && p == NULL) {
- /* Need a larger buffer to fit this line */
- nfilled += nread;
- buffersize *= 2;
- if (buffersize > INT_MAX) {
- PyErr_SetString(PyExc_OverflowError,
- "line is longer than a Python string can hold");
- goto error;
- }
- if (big_buffer == NULL) {
- /* Create the big buffer */
- big_buffer = PyBytes_FromStringAndSize(
- NULL, buffersize);
- if (big_buffer == NULL)
- goto error;
- buffer = PyBytes_AS_STRING(big_buffer);
- memcpy(buffer, small_buffer, nfilled);
- }
- else {
- /* Grow the big buffer */
- if (_PyBytes_Resize(&big_buffer, buffersize) < 0){
- big_buffer = NULL;
- goto error;
- }
- buffer = PyBytes_AS_STRING(big_buffer);
- }
- continue;
- }
- end = buffer+nfilled+nread;
- q = buffer;
- while (p != NULL) {
- /* Process complete lines */
- p++;
- line = PyBytes_FromStringAndSize(q, p-q);
- if (line == NULL)
- goto error;
- err = PyList_Append(list, line);
- Py_DECREF(line);
- if (err != 0)
- goto error;
- q = p;
- p = memchr(q, '\n', end-q);
- }
- /* Move the remaining incomplete line to the start */
- nfilled = end-q;
- memmove(buffer, q, nfilled);
- if (sizehint > 0)
- if (totalread >= (size_t)sizehint)
- break;
- if (shortread) {
- sizehint = 0;
- break;
- }
- }
- if (nfilled != 0) {
- /* Partial last line */
- line = PyBytes_FromStringAndSize(buffer, nfilled);
- if (line == NULL)
- goto error;
- if (sizehint > 0) {
- /* Need to complete the last line */
- PyObject *rest = Util_GetLine(self, 0);
- if (rest == NULL) {
- Py_DECREF(line);
- goto error;
- }
- PyBytes_Concat(&line, rest);
- Py_DECREF(rest);
- if (line == NULL)
- goto error;
- }
- err = PyList_Append(list, line);
- Py_DECREF(line);
- if (err != 0)
- goto error;
- }
-
- cleanup:
- RELEASE_LOCK(self);
- if (big_buffer) {
- Py_DECREF(big_buffer);
- }
- return list;
-}
-
-PyDoc_STRVAR(BZ2File_write__doc__,
-"write(data) -> None\n\
-\n\
-Write the 'data' string to file. Note that due to buffering, close() may\n\
-be needed before the file on disk reflects the data written.\n\
-");
-
-/* This is a hacked version of Python's fileobject.c:file_write(). */
-static PyObject *
-BZ2File_write(BZ2FileObject *self, PyObject *args)
-{
- PyObject *ret = NULL;
- Py_buffer pbuf;
- char *buf;
- int len;
- int bzerror;
-
- if (!PyArg_ParseTuple(args, "y*:write", &pbuf))
- return NULL;
- buf = pbuf.buf;
- len = pbuf.len;
-
- ACQUIRE_LOCK(self);
- switch (self->mode) {
- case MODE_WRITE:
- break;
-
- case MODE_CLOSED:
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- goto cleanup;
-
- default:
- PyErr_SetString(PyExc_IOError,
- "file is not ready for writing");
- goto cleanup;
- }
-
- Py_BEGIN_ALLOW_THREADS
- BZ2_bzWrite (&bzerror, self->fp, buf, len);
- self->pos += len;
- Py_END_ALLOW_THREADS
-
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto cleanup;
- }
-
- Py_INCREF(Py_None);
- ret = Py_None;
-
-cleanup:
- PyBuffer_Release(&pbuf);
- RELEASE_LOCK(self);
- return ret;
-}
-
-PyDoc_STRVAR(BZ2File_writelines__doc__,
-"writelines(sequence_of_strings) -> None\n\
-\n\
-Write the sequence of strings to the file. Note that newlines are not\n\
-added. The sequence can be any iterable object producing strings. This is\n\
-equivalent to calling write() for each string.\n\
-");
-
-/* This is a hacked version of Python's fileobject.c:file_writelines(). */
-static PyObject *
-BZ2File_writelines(BZ2FileObject *self, PyObject *seq)
-{
-#define CHUNKSIZE 1000
- PyObject *list = NULL;
- PyObject *iter = NULL;
- PyObject *ret = NULL;
- PyObject *line;
- int i, j, index, len, islist;
- int bzerror;
-
- ACQUIRE_LOCK(self);
- switch (self->mode) {
- case MODE_WRITE:
- break;
-
- case MODE_CLOSED:
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- goto error;
-
- default:
- PyErr_SetString(PyExc_IOError,
- "file is not ready for writing");
- goto error;
- }
-
- islist = PyList_Check(seq);
- if (!islist) {
- iter = PyObject_GetIter(seq);
- if (iter == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "writelines() requires an iterable argument");
- goto error;
- }
- list = PyList_New(CHUNKSIZE);
- if (list == NULL)
- goto error;
- }
-
- /* Strategy: slurp CHUNKSIZE lines into a private list,
- checking that they are all strings, then write that list
- without holding the interpreter lock, then come back for more. */
- for (index = 0; ; index += CHUNKSIZE) {
- if (islist) {
- Py_XDECREF(list);
- list = PyList_GetSlice(seq, index, index+CHUNKSIZE);
- if (list == NULL)
- goto error;
- j = PyList_GET_SIZE(list);
- }
- else {
- for (j = 0; j < CHUNKSIZE; j++) {
- line = PyIter_Next(iter);
- if (line == NULL) {
- if (PyErr_Occurred())
- goto error;
- break;
- }
- PyList_SetItem(list, j, line);
- }
- }
- if (j == 0)
- break;
-
- /* Check that all entries are indeed byte strings. If not,
- apply the same rules as for file.write() and
- convert the rets to strings. This is slow, but
- seems to be the only way since all conversion APIs
- could potentially execute Python code. */
- for (i = 0; i < j; i++) {
- PyObject *v = PyList_GET_ITEM(list, i);
- if (!PyBytes_Check(v)) {
- const char *buffer;
- Py_ssize_t len;
- if (PyObject_AsCharBuffer(v, &buffer, &len)) {
- PyErr_SetString(PyExc_TypeError,
- "writelines() "
- "argument must be "
- "a sequence of "
- "bytes objects");
- goto error;
- }
- line = PyBytes_FromStringAndSize(buffer,
- len);
- if (line == NULL)
- goto error;
- Py_DECREF(v);
- PyList_SET_ITEM(list, i, line);
- }
- }
-
- /* Since we are releasing the global lock, the
- following code may *not* execute Python code. */
- Py_BEGIN_ALLOW_THREADS
- for (i = 0; i < j; i++) {
- line = PyList_GET_ITEM(list, i);
- len = PyBytes_GET_SIZE(line);
- BZ2_bzWrite (&bzerror, self->fp,
- PyBytes_AS_STRING(line), len);
- if (bzerror != BZ_OK) {
- Py_BLOCK_THREADS
- Util_CatchBZ2Error(bzerror);
- goto error;
- }
- }
- Py_END_ALLOW_THREADS
-
- if (j < CHUNKSIZE)
- break;
- }
-
- Py_INCREF(Py_None);
- ret = Py_None;
-
- error:
- RELEASE_LOCK(self);
- Py_XDECREF(list);
- Py_XDECREF(iter);
- return ret;
-#undef CHUNKSIZE
-}
-
-PyDoc_STRVAR(BZ2File_seek__doc__,
-"seek(offset [, whence]) -> None\n\
-\n\
-Move to new file position. Argument offset is a byte count. Optional\n\
-argument whence defaults to 0 (offset from start of file, offset\n\
-should be >= 0); other values are 1 (move relative to current position,\n\
-positive or negative), and 2 (move relative to end of file, usually\n\
-negative, although many platforms allow seeking beyond the end of a file).\n\
-\n\
-Note that seeking of bz2 files is emulated, and depending on the parameters\n\
-the operation may be extremely slow.\n\
-");
-
-static PyObject *
-BZ2File_seek(BZ2FileObject *self, PyObject *args)
-{
- int where = 0;
- PyObject *offobj;
- Py_off_t offset;
- char small_buffer[SMALLCHUNK];
- char *buffer = small_buffer;
- size_t buffersize = SMALLCHUNK;
- Py_off_t bytesread = 0;
- size_t readsize;
- int chunksize;
- int bzerror;
- PyObject *ret = NULL;
-
- if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &where))
- return NULL;
-#if !defined(HAVE_LARGEFILE_SUPPORT)
- offset = PyLong_AsLong(offobj);
-#else
- offset = PyLong_Check(offobj) ?
- PyLong_AsLongLong(offobj) : PyLong_AsLong(offobj);
-#endif
- if (PyErr_Occurred())
- return NULL;
-
- ACQUIRE_LOCK(self);
- Util_DropReadAhead(self);
- switch (self->mode) {
- case MODE_READ:
- case MODE_READ_EOF:
- break;
-
- case MODE_CLOSED:
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- goto cleanup;
-
- default:
- PyErr_SetString(PyExc_IOError,
- "seek works only while reading");
- goto cleanup;
- }
-
- if (where == 2) {
- if (self->size == -1) {
- assert(self->mode != MODE_READ_EOF);
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- chunksize = BZ2_bzRead(&bzerror, self->fp,
- buffer, buffersize);
- self->pos += chunksize;
- Py_END_ALLOW_THREADS
-
- bytesread += chunksize;
- if (bzerror == BZ_STREAM_END) {
- break;
- } else if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto cleanup;
- }
- }
- self->mode = MODE_READ_EOF;
- self->size = self->pos;
- bytesread = 0;
- }
- offset = self->size + offset;
- } else if (where == 1) {
- offset = self->pos + offset;
- }
-
- /* Before getting here, offset must be the absolute position the file
- * pointer should be set to. */
-
- if (offset >= self->pos) {
- /* we can move forward */
- offset -= self->pos;
- } else {
- /* we cannot move back, so rewind the stream */
- BZ2_bzReadClose(&bzerror, self->fp);
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto cleanup;
- }
- rewind(self->rawfp);
- self->pos = 0;
- self->fp = BZ2_bzReadOpen(&bzerror, self->rawfp,
- 0, 0, NULL, 0);
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto cleanup;
- }
- self->mode = MODE_READ;
- }
-
- if (offset <= 0 || self->mode == MODE_READ_EOF)
- goto exit;
-
- /* Before getting here, offset must be set to the number of bytes
- * to walk forward. */
- for (;;) {
- if (offset-bytesread > buffersize)
- readsize = buffersize;
- else
- /* offset might be wider that readsize, but the result
- * of the subtraction is bound by buffersize (see the
- * condition above). buffersize is 8192. */
- readsize = (size_t)(offset-bytesread);
- Py_BEGIN_ALLOW_THREADS
- chunksize = BZ2_bzRead(&bzerror, self->fp, buffer, readsize);
- self->pos += chunksize;
- Py_END_ALLOW_THREADS
- bytesread += chunksize;
- if (bzerror == BZ_STREAM_END) {
- self->size = self->pos;
- self->mode = MODE_READ_EOF;
- break;
- } else if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto cleanup;
- }
- if (bytesread == offset)
- break;
- }
-
-exit:
- Py_INCREF(Py_None);
- ret = Py_None;
-
-cleanup:
- RELEASE_LOCK(self);
- return ret;
-}
-
-PyDoc_STRVAR(BZ2File_tell__doc__,
-"tell() -> int\n\
-\n\
-Return the current file position, an integer (may be a long integer).\n\
-");
-
-static PyObject *
-BZ2File_tell(BZ2FileObject *self, PyObject *args)
-{
- PyObject *ret = NULL;
-
- if (self->mode == MODE_CLOSED) {
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- goto cleanup;
- }
-
-#if !defined(HAVE_LARGEFILE_SUPPORT)
- ret = PyLong_FromLong(self->pos);
-#else
- ret = PyLong_FromLongLong(self->pos);
-#endif
-
-cleanup:
- return ret;
-}
-
-PyDoc_STRVAR(BZ2File_close__doc__,
-"close() -> None or (perhaps) an integer\n\
-\n\
-Close the file. Sets data attribute .closed to true. A closed file\n\
-cannot be used for further I/O operations. close() may be called more\n\
-than once without error.\n\
-");
-
-static PyObject *
-BZ2File_close(BZ2FileObject *self)
-{
- PyObject *ret = NULL;
- int bzerror = BZ_OK;
-
- if (self->mode == MODE_CLOSED) {
- Py_RETURN_NONE;
- }
-
- ACQUIRE_LOCK(self);
- switch (self->mode) {
- case MODE_READ:
- case MODE_READ_EOF:
- BZ2_bzReadClose(&bzerror, self->fp);
- break;
- case MODE_WRITE:
- BZ2_bzWriteClose(&bzerror, self->fp,
- 0, NULL, NULL);
- break;
- }
- self->mode = MODE_CLOSED;
- fclose(self->rawfp);
- self->rawfp = NULL;
- if (bzerror == BZ_OK) {
- Py_INCREF(Py_None);
- ret = Py_None;
- }
- else {
- Util_CatchBZ2Error(bzerror);
- }
-
- RELEASE_LOCK(self);
- return ret;
-}
-
-PyDoc_STRVAR(BZ2File_enter_doc,
-"__enter__() -> self.");
-
-static PyObject *
-BZ2File_enter(BZ2FileObject *self)
-{
- if (self->mode == MODE_CLOSED) {
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- return NULL;
- }
- Py_INCREF(self);
- return (PyObject *) self;
-}
-
-PyDoc_STRVAR(BZ2File_exit_doc,
-"__exit__(*excinfo) -> None. Closes the file.");
-
-static PyObject *
-BZ2File_exit(BZ2FileObject *self, PyObject *args)
-{
- PyObject *ret = PyObject_CallMethod((PyObject *) self, "close", NULL);
- if (!ret)
- /* If error occurred, pass through */
- return NULL;
- Py_DECREF(ret);
- Py_RETURN_NONE;
-}
-
-
-static PyObject *BZ2File_getiter(BZ2FileObject *self);
-
-static PyMethodDef BZ2File_methods[] = {
- {"read", (PyCFunction)BZ2File_read, METH_VARARGS, BZ2File_read__doc__},
- {"readline", (PyCFunction)BZ2File_readline, METH_VARARGS, BZ2File_readline__doc__},
- {"readlines", (PyCFunction)BZ2File_readlines, METH_VARARGS, BZ2File_readlines__doc__},
- {"write", (PyCFunction)BZ2File_write, METH_VARARGS, BZ2File_write__doc__},
- {"writelines", (PyCFunction)BZ2File_writelines, METH_O, BZ2File_writelines__doc__},
- {"seek", (PyCFunction)BZ2File_seek, METH_VARARGS, BZ2File_seek__doc__},
- {"tell", (PyCFunction)BZ2File_tell, METH_NOARGS, BZ2File_tell__doc__},
- {"close", (PyCFunction)BZ2File_close, METH_NOARGS, BZ2File_close__doc__},
- {"__enter__", (PyCFunction)BZ2File_enter, METH_NOARGS, BZ2File_enter_doc},
- {"__exit__", (PyCFunction)BZ2File_exit, METH_VARARGS, BZ2File_exit_doc},
- {NULL, NULL} /* sentinel */
-};
-
-
-/* ===================================================================== */
-/* Getters and setters of BZ2File. */
-
-static PyObject *
-BZ2File_get_closed(BZ2FileObject *self, void *closure)
-{
- return PyLong_FromLong(self->mode == MODE_CLOSED);
-}
-
-static PyGetSetDef BZ2File_getset[] = {
- {"closed", (getter)BZ2File_get_closed, NULL,
- "True if the file is closed"},
- {NULL} /* Sentinel */
-};
-
-
-/* ===================================================================== */
-/* Slot definitions for BZ2File_Type. */
-
-static int
-BZ2File_init(BZ2FileObject *self, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = {"filename", "mode", "buffering",
- "compresslevel", 0};
- PyObject *name_obj = NULL;
- char *name;
- char *mode = "r";
- int buffering = -1;
- int compresslevel = 9;
- int bzerror;
- int mode_char = 0;
-
- self->size = -1;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|sii:BZ2File",
- kwlist, PyUnicode_FSConverter, &name_obj,
- &mode, &buffering,
- &compresslevel))
- return -1;
-
- name = PyBytes_AsString(name_obj);
- if (compresslevel < 1 || compresslevel > 9) {
- PyErr_SetString(PyExc_ValueError,
- "compresslevel must be between 1 and 9");
- Py_DECREF(name_obj);
- return -1;
- }
-
- for (;;) {
- int error = 0;
- switch (*mode) {
- case 'r':
- case 'w':
- if (mode_char)
- error = 1;
- mode_char = *mode;
- break;
-
- case 'b':
- break;
-
- default:
- error = 1;
- break;
- }
- if (error) {
- PyErr_Format(PyExc_ValueError,
- "invalid mode char %c", *mode);
- Py_DECREF(name_obj);
- return -1;
- }
- mode++;
- if (*mode == '\0')
- break;
- }
-
- if (mode_char == 0) {
- mode_char = 'r';
- }
-
- mode = (mode_char == 'r') ? "rb" : "wb";
-
- self->rawfp = fopen(name, mode);
- Py_DECREF(name_obj);
- if (self->rawfp == NULL) {
- PyErr_SetFromErrno(PyExc_IOError);
- return -1;
- }
- /* XXX Ignore buffering */
-
- /* From now on, we have stuff to dealloc, so jump to error label
- * instead of returning */
-
-#ifdef WITH_THREAD
- self->lock = PyThread_allocate_lock();
- if (!self->lock) {
- PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
- goto error;
- }
-#endif
-
- if (mode_char == 'r')
- self->fp = BZ2_bzReadOpen(&bzerror, self->rawfp,
- 0, 0, NULL, 0);
- else
- self->fp = BZ2_bzWriteOpen(&bzerror, self->rawfp,
- compresslevel, 0, 0);
-
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto error;
- }
-
- self->mode = (mode_char == 'r') ? MODE_READ : MODE_WRITE;
-
- return 0;
-
-error:
- fclose(self->rawfp);
- self->rawfp = NULL;
-#ifdef WITH_THREAD
- if (self->lock) {
- PyThread_free_lock(self->lock);
- self->lock = NULL;
- }
-#endif
- return -1;
-}
-
-static void
-BZ2File_dealloc(BZ2FileObject *self)
-{
- int bzerror;
-#ifdef WITH_THREAD
- if (self->lock)
- PyThread_free_lock(self->lock);
-#endif
- switch (self->mode) {
- case MODE_READ:
- case MODE_READ_EOF:
- BZ2_bzReadClose(&bzerror, self->fp);
- break;
- case MODE_WRITE:
- BZ2_bzWriteClose(&bzerror, self->fp,
- 0, NULL, NULL);
- break;
- }
- Util_DropReadAhead(self);
- if (self->rawfp != NULL)
- fclose(self->rawfp);
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-/* This is a hacked version of Python's fileobject.c:file_getiter(). */
-static PyObject *
-BZ2File_getiter(BZ2FileObject *self)
-{
- if (self->mode == MODE_CLOSED) {
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- return NULL;
- }
- Py_INCREF((PyObject*)self);
- return (PyObject *)self;
-}
-
-/* This is a hacked version of Python's fileobject.c:file_iternext(). */
-#define READAHEAD_BUFSIZE 8192
-static PyObject *
-BZ2File_iternext(BZ2FileObject *self)
-{
- PyBytesObject* ret;
- ACQUIRE_LOCK(self);
- if (self->mode == MODE_CLOSED) {
- RELEASE_LOCK(self);
- PyErr_SetString(PyExc_ValueError,
- "I/O operation on closed file");
- return NULL;
- }
- ret = Util_ReadAheadGetLineSkip(self, 0, READAHEAD_BUFSIZE);
- RELEASE_LOCK(self);
- if (ret == NULL || PyBytes_GET_SIZE(ret) == 0) {
- Py_XDECREF(ret);
- return NULL;
- }
- return (PyObject *)ret;
-}
-
-/* ===================================================================== */
-/* BZ2File_Type definition. */
-
-PyDoc_VAR(BZ2File__doc__) =
-PyDoc_STR(
-"BZ2File(name [, mode='r', buffering=0, compresslevel=9]) -> file object\n\
-\n\
-Open a bz2 file. The mode can be 'r' or 'w', for reading (default) or\n\
-writing. When opened for writing, the file will be created if it doesn't\n\
-exist, and truncated otherwise. If the buffering argument is given, 0 means\n\
-unbuffered, and larger numbers specify the buffer size. If compresslevel\n\
-is given, must be a number between 1 and 9.\n\
-Data read is always returned in bytes; data written ought to be bytes.\n\
-");
-
-static PyTypeObject BZ2File_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "bz2.BZ2File", /*tp_name*/
- sizeof(BZ2FileObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)BZ2File_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*/
- PyObject_GenericGetAttr,/*tp_getattro*/
- PyObject_GenericSetAttr,/*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
- BZ2File__doc__, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- (getiterfunc)BZ2File_getiter, /*tp_iter*/
- (iternextfunc)BZ2File_iternext, /*tp_iternext*/
- BZ2File_methods, /*tp_methods*/
- 0, /*tp_members*/
- BZ2File_getset, /*tp_getset*/
- 0, /*tp_base*/
- 0, /*tp_dict*/
- 0, /*tp_descr_get*/
- 0, /*tp_descr_set*/
- 0, /*tp_dictoffset*/
- (initproc)BZ2File_init, /*tp_init*/
- PyType_GenericAlloc, /*tp_alloc*/
- PyType_GenericNew, /*tp_new*/
- PyObject_Free, /*tp_free*/
- 0, /*tp_is_gc*/
-};
-
-
-/* ===================================================================== */
-/* Methods of BZ2Comp. */
-
-PyDoc_STRVAR(BZ2Comp_compress__doc__,
-"compress(data) -> string\n\
-\n\
-Provide more data to the compressor object. It will return chunks of\n\
-compressed data whenever possible. When you've finished providing data\n\
-to compress, call the flush() method to finish the compression process,\n\
-and return what is left in the internal buffers.\n\
-");
-
-static PyObject *
-BZ2Comp_compress(BZ2CompObject *self, PyObject *args)
-{
- Py_buffer pdata;
- char *data;
- int datasize;
- int bufsize = SMALLCHUNK;
- PY_LONG_LONG totalout;
- PyObject *ret = NULL;
- bz_stream *bzs = &self->bzs;
- int bzerror;
-
- if (!PyArg_ParseTuple(args, "y*:compress", &pdata))
- return NULL;
- data = pdata.buf;
- datasize = pdata.len;
-
- if (datasize == 0) {
- PyBuffer_Release(&pdata);
- return PyBytes_FromStringAndSize("", 0);
- }
-
- ACQUIRE_LOCK(self);
- if (!self->running) {
- PyErr_SetString(PyExc_ValueError,
- "this object was already flushed");
- goto error;
- }
-
- ret = PyBytes_FromStringAndSize(NULL, bufsize);
- if (!ret)
- goto error;
-
- bzs->next_in = data;
- bzs->avail_in = datasize;
- bzs->next_out = BUF(ret);
- bzs->avail_out = bufsize;
-
- totalout = BZS_TOTAL_OUT(bzs);
-
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- bzerror = BZ2_bzCompress(bzs, BZ_RUN);
- Py_END_ALLOW_THREADS
- if (bzerror != BZ_RUN_OK) {
- Util_CatchBZ2Error(bzerror);
- goto error;
- }
- if (bzs->avail_in == 0)
- break; /* no more input data */
- if (bzs->avail_out == 0) {
- bufsize = Util_NewBufferSize(bufsize);
- if (_PyBytes_Resize(&ret, bufsize) < 0) {
- BZ2_bzCompressEnd(bzs);
- goto error;
- }
- bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs)
- - totalout);
- bzs->avail_out = bufsize - (bzs->next_out - BUF(ret));
- }
- }
-
- if (_PyBytes_Resize(&ret,
- (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)) < 0)
- goto error;
-
- RELEASE_LOCK(self);
- PyBuffer_Release(&pdata);
- return ret;
-
-error:
- RELEASE_LOCK(self);
- PyBuffer_Release(&pdata);
- Py_XDECREF(ret);
- return NULL;
-}
-
-PyDoc_STRVAR(BZ2Comp_flush__doc__,
-"flush() -> string\n\
-\n\
-Finish the compression process and return what is left in internal buffers.\n\
-You must not use the compressor object after calling this method.\n\
-");
-
-static PyObject *
-BZ2Comp_flush(BZ2CompObject *self)
-{
- int bufsize = SMALLCHUNK;
- PyObject *ret = NULL;
- bz_stream *bzs = &self->bzs;
- PY_LONG_LONG totalout;
- int bzerror;
-
- ACQUIRE_LOCK(self);
- if (!self->running) {
- PyErr_SetString(PyExc_ValueError, "object was already "
- "flushed");
- goto error;
- }
- self->running = 0;
-
- ret = PyBytes_FromStringAndSize(NULL, bufsize);
- if (!ret)
- goto error;
-
- bzs->next_out = BUF(ret);
- bzs->avail_out = bufsize;
-
- totalout = BZS_TOTAL_OUT(bzs);
-
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- bzerror = BZ2_bzCompress(bzs, BZ_FINISH);
- Py_END_ALLOW_THREADS
- if (bzerror == BZ_STREAM_END) {
- break;
- } else if (bzerror != BZ_FINISH_OK) {
- Util_CatchBZ2Error(bzerror);
- goto error;
- }
- if (bzs->avail_out == 0) {
- bufsize = Util_NewBufferSize(bufsize);
- if (_PyBytes_Resize(&ret, bufsize) < 0)
- goto error;
- bzs->next_out = BUF(ret);
- bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs)
- - totalout);
- bzs->avail_out = bufsize - (bzs->next_out - BUF(ret));
- }
- }
-
- if (bzs->avail_out != 0) {
- if (_PyBytes_Resize(&ret,
- (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)) < 0)
- goto error;
- }
-
- RELEASE_LOCK(self);
- return ret;
-
-error:
- RELEASE_LOCK(self);
- Py_XDECREF(ret);
- return NULL;
-}
-
-static PyMethodDef BZ2Comp_methods[] = {
- {"compress", (PyCFunction)BZ2Comp_compress, METH_VARARGS,
- BZ2Comp_compress__doc__},
- {"flush", (PyCFunction)BZ2Comp_flush, METH_NOARGS,
- BZ2Comp_flush__doc__},
- {NULL, NULL} /* sentinel */
-};
-
-
-/* ===================================================================== */
-/* Slot definitions for BZ2Comp_Type. */
-
-static int
-BZ2Comp_init(BZ2CompObject *self, PyObject *args, PyObject *kwargs)
-{
- int compresslevel = 9;
- int bzerror;
- static char *kwlist[] = {"compresslevel", 0};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:BZ2Compressor",
- kwlist, &compresslevel))
- return -1;
-
- if (compresslevel < 1 || compresslevel > 9) {
- PyErr_SetString(PyExc_ValueError,
- "compresslevel must be between 1 and 9");
- goto error;
- }
-
-#ifdef WITH_THREAD
- self->lock = PyThread_allocate_lock();
- if (!self->lock) {
- PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
- goto error;
- }
-#endif
-
- memset(&self->bzs, 0, sizeof(bz_stream));
- bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0);
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto error;
- }
-
- self->running = 1;
-
- return 0;
-error:
-#ifdef WITH_THREAD
- if (self->lock) {
- PyThread_free_lock(self->lock);
- self->lock = NULL;
- }
-#endif
- return -1;
-}
-
-static void
-BZ2Comp_dealloc(BZ2CompObject *self)
-{
-#ifdef WITH_THREAD
- if (self->lock)
- PyThread_free_lock(self->lock);
-#endif
- BZ2_bzCompressEnd(&self->bzs);
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-
-/* ===================================================================== */
-/* BZ2Comp_Type definition. */
-
-PyDoc_STRVAR(BZ2Comp__doc__,
-"BZ2Compressor([compresslevel=9]) -> compressor object\n\
-\n\
-Create a new compressor object. This object may be used to compress\n\
-data sequentially. If you want to compress data in one shot, use the\n\
-compress() function instead. The compresslevel parameter, if given,\n\
-must be a number between 1 and 9.\n\
-");
-
-static PyTypeObject BZ2Comp_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "bz2.BZ2Compressor", /*tp_name*/
- sizeof(BZ2CompObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)BZ2Comp_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*/
- PyObject_GenericGetAttr,/*tp_getattro*/
- PyObject_GenericSetAttr,/*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
- BZ2Comp__doc__, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- BZ2Comp_methods, /*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*/
- (initproc)BZ2Comp_init, /*tp_init*/
- PyType_GenericAlloc, /*tp_alloc*/
- PyType_GenericNew, /*tp_new*/
- PyObject_Free, /*tp_free*/
- 0, /*tp_is_gc*/
-};
-
-
-/* ===================================================================== */
-/* Members of BZ2Decomp. */
-
-#undef OFF
-#define OFF(x) offsetof(BZ2DecompObject, x)
-
-static PyMemberDef BZ2Decomp_members[] = {
- {"unused_data", T_OBJECT, OFF(unused_data), READONLY},
- {NULL} /* Sentinel */
-};
-
-
-/* ===================================================================== */
-/* Methods of BZ2Decomp. */
-
-PyDoc_STRVAR(BZ2Decomp_decompress__doc__,
-"decompress(data) -> string\n\
-\n\
-Provide more data to the decompressor object. It will return chunks\n\
-of decompressed data whenever possible. If you try to decompress data\n\
-after the end of stream is found, EOFError will be raised. If any data\n\
-was found after the end of stream, it'll be ignored and saved in\n\
-unused_data attribute.\n\
-");
-
-static PyObject *
-BZ2Decomp_decompress(BZ2DecompObject *self, PyObject *args)
-{
- Py_buffer pdata;
- char *data;
- int datasize;
- int bufsize = SMALLCHUNK;
- PY_LONG_LONG totalout;
- PyObject *ret = NULL;
- bz_stream *bzs = &self->bzs;
- int bzerror;
-
- if (!PyArg_ParseTuple(args, "y*:decompress", &pdata))
- return NULL;
- data = pdata.buf;
- datasize = pdata.len;
-
- ACQUIRE_LOCK(self);
- if (!self->running) {
- PyErr_SetString(PyExc_EOFError, "end of stream was "
- "already found");
- goto error;
- }
-
- ret = PyBytes_FromStringAndSize(NULL, bufsize);
- if (!ret)
- goto error;
-
- bzs->next_in = data;
- bzs->avail_in = datasize;
- bzs->next_out = BUF(ret);
- bzs->avail_out = bufsize;
-
- totalout = BZS_TOTAL_OUT(bzs);
-
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- bzerror = BZ2_bzDecompress(bzs);
- Py_END_ALLOW_THREADS
- if (bzerror == BZ_STREAM_END) {
- if (bzs->avail_in != 0) {
- Py_DECREF(self->unused_data);
- self->unused_data =
- PyBytes_FromStringAndSize(bzs->next_in,
- bzs->avail_in);
- }
- self->running = 0;
- break;
- }
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto error;
- }
- if (bzs->avail_in == 0)
- break; /* no more input data */
- if (bzs->avail_out == 0) {
- bufsize = Util_NewBufferSize(bufsize);
- if (_PyBytes_Resize(&ret, bufsize) < 0) {
- BZ2_bzDecompressEnd(bzs);
- goto error;
- }
- bzs->next_out = BUF(ret);
- bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs)
- - totalout);
- bzs->avail_out = bufsize - (bzs->next_out - BUF(ret));
- }
- }
-
- if (bzs->avail_out != 0) {
- if (_PyBytes_Resize(&ret,
- (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)) < 0)
- goto error;
- }
-
- RELEASE_LOCK(self);
- PyBuffer_Release(&pdata);
- return ret;
-
-error:
- RELEASE_LOCK(self);
- PyBuffer_Release(&pdata);
- Py_XDECREF(ret);
- return NULL;
-}
-
-static PyMethodDef BZ2Decomp_methods[] = {
- {"decompress", (PyCFunction)BZ2Decomp_decompress, METH_VARARGS, BZ2Decomp_decompress__doc__},
- {NULL, NULL} /* sentinel */
-};
-
-
-/* ===================================================================== */
-/* Slot definitions for BZ2Decomp_Type. */
-
-static int
-BZ2Decomp_init(BZ2DecompObject *self, PyObject *args, PyObject *kwargs)
-{
- int bzerror;
-
- if (!PyArg_ParseTuple(args, ":BZ2Decompressor"))
- return -1;
-
-#ifdef WITH_THREAD
- self->lock = PyThread_allocate_lock();
- if (!self->lock) {
- PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
- goto error;
- }
-#endif
-
- self->unused_data = PyBytes_FromStringAndSize("", 0);
- if (!self->unused_data)
- goto error;
-
- memset(&self->bzs, 0, sizeof(bz_stream));
- bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0);
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- goto error;
- }
-
- self->running = 1;
-
- return 0;
-
-error:
-#ifdef WITH_THREAD
- if (self->lock) {
- PyThread_free_lock(self->lock);
- self->lock = NULL;
- }
-#endif
- Py_CLEAR(self->unused_data);
- return -1;
-}
-
-static void
-BZ2Decomp_dealloc(BZ2DecompObject *self)
-{
-#ifdef WITH_THREAD
- if (self->lock)
- PyThread_free_lock(self->lock);
-#endif
- Py_XDECREF(self->unused_data);
- BZ2_bzDecompressEnd(&self->bzs);
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-
-/* ===================================================================== */
-/* BZ2Decomp_Type definition. */
-
-PyDoc_STRVAR(BZ2Decomp__doc__,
-"BZ2Decompressor() -> decompressor object\n\
-\n\
-Create a new decompressor object. This object may be used to decompress\n\
-data sequentially. If you want to decompress data in one shot, use the\n\
-decompress() function instead.\n\
-");
-
-static PyTypeObject BZ2Decomp_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "bz2.BZ2Decompressor", /*tp_name*/
- sizeof(BZ2DecompObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)BZ2Decomp_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*/
- PyObject_GenericGetAttr,/*tp_getattro*/
- PyObject_GenericSetAttr,/*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
- BZ2Decomp__doc__, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- BZ2Decomp_methods, /*tp_methods*/
- BZ2Decomp_members, /*tp_members*/
- 0, /*tp_getset*/
- 0, /*tp_base*/
- 0, /*tp_dict*/
- 0, /*tp_descr_get*/
- 0, /*tp_descr_set*/
- 0, /*tp_dictoffset*/
- (initproc)BZ2Decomp_init, /*tp_init*/
- PyType_GenericAlloc, /*tp_alloc*/
- PyType_GenericNew, /*tp_new*/
- PyObject_Free, /*tp_free*/
- 0, /*tp_is_gc*/
-};
-
-
-/* ===================================================================== */
-/* Module functions. */
-
-PyDoc_STRVAR(bz2_compress__doc__,
-"compress(data [, compresslevel=9]) -> string\n\
-\n\
-Compress data in one shot. If you want to compress data sequentially,\n\
-use an instance of BZ2Compressor instead. The compresslevel parameter, if\n\
-given, must be a number between 1 and 9.\n\
-");
-
-static PyObject *
-bz2_compress(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- int compresslevel=9;
- Py_buffer pdata;
- char *data;
- int datasize;
- int bufsize;
- PyObject *ret = NULL;
- bz_stream _bzs;
- bz_stream *bzs = &_bzs;
- int bzerror;
- static char *kwlist[] = {"data", "compresslevel", 0};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|i",
- kwlist, &pdata,
- &compresslevel))
- return NULL;
- data = pdata.buf;
- datasize = pdata.len;
-
- if (compresslevel < 1 || compresslevel > 9) {
- PyErr_SetString(PyExc_ValueError,
- "compresslevel must be between 1 and 9");
- PyBuffer_Release(&pdata);
- return NULL;
- }
-
- /* Conforming to bz2 manual, this is large enough to fit compressed
- * data in one shot. We will check it later anyway. */
- bufsize = datasize + (datasize/100+1) + 600;
-
- ret = PyBytes_FromStringAndSize(NULL, bufsize);
- if (!ret) {
- PyBuffer_Release(&pdata);
- return NULL;
- }
-
- memset(bzs, 0, sizeof(bz_stream));
-
- bzs->next_in = data;
- bzs->avail_in = datasize;
- bzs->next_out = BUF(ret);
- bzs->avail_out = bufsize;
-
- bzerror = BZ2_bzCompressInit(bzs, compresslevel, 0, 0);
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- PyBuffer_Release(&pdata);
- Py_DECREF(ret);
- return NULL;
- }
-
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- bzerror = BZ2_bzCompress(bzs, BZ_FINISH);
- Py_END_ALLOW_THREADS
- if (bzerror == BZ_STREAM_END) {
- break;
- } else if (bzerror != BZ_FINISH_OK) {
- BZ2_bzCompressEnd(bzs);
- Util_CatchBZ2Error(bzerror);
- PyBuffer_Release(&pdata);
- Py_DECREF(ret);
- return NULL;
- }
- if (bzs->avail_out == 0) {
- bufsize = Util_NewBufferSize(bufsize);
- if (_PyBytes_Resize(&ret, bufsize) < 0) {
- BZ2_bzCompressEnd(bzs);
- PyBuffer_Release(&pdata);
- return NULL;
- }
- bzs->next_out = BUF(ret) + BZS_TOTAL_OUT(bzs);
- bzs->avail_out = bufsize - (bzs->next_out - BUF(ret));
- }
- }
-
- if (bzs->avail_out != 0) {
- if (_PyBytes_Resize(&ret, (Py_ssize_t)BZS_TOTAL_OUT(bzs)) < 0) {
- ret = NULL;
- }
- }
- BZ2_bzCompressEnd(bzs);
-
- PyBuffer_Release(&pdata);
- return ret;
-}
-
-PyDoc_STRVAR(bz2_decompress__doc__,
-"decompress(data) -> decompressed data\n\
-\n\
-Decompress data in one shot. If you want to decompress data sequentially,\n\
-use an instance of BZ2Decompressor instead.\n\
-");
-
-static PyObject *
-bz2_decompress(PyObject *self, PyObject *args)
-{
- Py_buffer pdata;
- char *data;
- int datasize;
- int bufsize = SMALLCHUNK;
- PyObject *ret;
- bz_stream _bzs;
- bz_stream *bzs = &_bzs;
- int bzerror;
-
- if (!PyArg_ParseTuple(args, "y*:decompress", &pdata))
- return NULL;
- data = pdata.buf;
- datasize = pdata.len;
-
- if (datasize == 0) {
- PyBuffer_Release(&pdata);
- return PyBytes_FromStringAndSize("", 0);
- }
-
- ret = PyBytes_FromStringAndSize(NULL, bufsize);
- if (!ret) {
- PyBuffer_Release(&pdata);
- return NULL;
- }
-
- memset(bzs, 0, sizeof(bz_stream));
-
- bzs->next_in = data;
- bzs->avail_in = datasize;
- bzs->next_out = BUF(ret);
- bzs->avail_out = bufsize;
-
- bzerror = BZ2_bzDecompressInit(bzs, 0, 0);
- if (bzerror != BZ_OK) {
- Util_CatchBZ2Error(bzerror);
- Py_DECREF(ret);
- PyBuffer_Release(&pdata);
- return NULL;
- }
-
- for (;;) {
- Py_BEGIN_ALLOW_THREADS
- bzerror = BZ2_bzDecompress(bzs);
- Py_END_ALLOW_THREADS
- if (bzerror == BZ_STREAM_END) {
- break;
- } else if (bzerror != BZ_OK) {
- BZ2_bzDecompressEnd(bzs);
- Util_CatchBZ2Error(bzerror);
- PyBuffer_Release(&pdata);
- Py_DECREF(ret);
- return NULL;
- }
- if (bzs->avail_in == 0) {
- BZ2_bzDecompressEnd(bzs);
- PyErr_SetString(PyExc_ValueError,
- "couldn't find end of stream");
- PyBuffer_Release(&pdata);
- Py_DECREF(ret);
- return NULL;
- }
- if (bzs->avail_out == 0) {
- bufsize = Util_NewBufferSize(bufsize);
- if (_PyBytes_Resize(&ret, bufsize) < 0) {
- BZ2_bzDecompressEnd(bzs);
- PyBuffer_Release(&pdata);
- return NULL;
- }
- bzs->next_out = BUF(ret) + BZS_TOTAL_OUT(bzs);
- bzs->avail_out = bufsize - (bzs->next_out - BUF(ret));
- }
- }
-
- if (bzs->avail_out != 0) {
- if (_PyBytes_Resize(&ret, (Py_ssize_t)BZS_TOTAL_OUT(bzs)) < 0) {
- ret = NULL;
- }
- }
- BZ2_bzDecompressEnd(bzs);
- PyBuffer_Release(&pdata);
-
- return ret;
-}
-
-static PyMethodDef bz2_methods[] = {
- {"compress", (PyCFunction) bz2_compress, METH_VARARGS|METH_KEYWORDS,
- bz2_compress__doc__},
- {"decompress", (PyCFunction) bz2_decompress, METH_VARARGS,
- bz2_decompress__doc__},
- {NULL, NULL} /* sentinel */
-};
-
-/* ===================================================================== */
-/* Initialization function. */
-
-PyDoc_STRVAR(bz2__doc__,
-"The python bz2 module provides a comprehensive interface for\n\
-the bz2 compression library. It implements a complete file\n\
-interface, one shot (de)compression functions, and types for\n\
-sequential (de)compression.\n\
-");
-
-
-static struct PyModuleDef bz2module = {
- PyModuleDef_HEAD_INIT,
- "bz2",
- bz2__doc__,
- -1,
- bz2_methods,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-PyMODINIT_FUNC
-PyInit_bz2(void)
-{
- PyObject *m;
-
- if (PyType_Ready(&BZ2File_Type) < 0)
- return NULL;
- if (PyType_Ready(&BZ2Comp_Type) < 0)
- return NULL;
- if (PyType_Ready(&BZ2Decomp_Type) < 0)
- return NULL;
-
- m = PyModule_Create(&bz2module);
- if (m == NULL)
- return NULL;
-
- PyModule_AddObject(m, "__author__", PyUnicode_FromString(__author__));
-
- Py_INCREF(&BZ2File_Type);
- PyModule_AddObject(m, "BZ2File", (PyObject *)&BZ2File_Type);
-
- Py_INCREF(&BZ2Comp_Type);
- PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Comp_Type);
-
- Py_INCREF(&BZ2Decomp_Type);
- PyModule_AddObject(m, "BZ2Decompressor", (PyObject *)&BZ2Decomp_Type);
- return m;
-}
diff --git a/Modules/cjkcodecs/_codecs_iso2022.c b/Modules/cjkcodecs/_codecs_iso2022.c
index 25c1a361da..cbc1542922 100644
--- a/Modules/cjkcodecs/_codecs_iso2022.c
+++ b/Modules/cjkcodecs/_codecs_iso2022.c
@@ -123,7 +123,7 @@ struct iso2022_config {
CODEC_INIT(iso2022)
{
- const struct iso2022_designation *desig = CONFIG_DESIGNATIONS;
+ const struct iso2022_designation *desig;
for (desig = CONFIG_DESIGNATIONS; desig->mark; desig++)
if (desig->initializer != NULL && desig->initializer() != 0)
return -1;
diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c
index af7ea5b83a..e137ff6bc4 100644
--- a/Modules/cjkcodecs/multibytecodec.c
+++ b/Modules/cjkcodecs/multibytecodec.c
@@ -483,6 +483,7 @@ multibytecodec_encode(MultibyteCodec *codec,
return PyBytes_FromStringAndSize(NULL, 0);
buf.excobj = NULL;
+ buf.outobj = NULL;
buf.inbuf = buf.inbuf_top = *data;
buf.inbuf_end = buf.inbuf_top + datalen;
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
new file mode 100644
index 0000000000..48c43912ce
--- /dev/null
+++ b/Modules/faulthandler.c
@@ -0,0 +1,1106 @@
+#include "Python.h"
+#include "pythread.h"
+#include <signal.h>
+#include <object.h>
+#include <frameobject.h>
+#include <signal.h>
+
+/* Allocate at maximum 100 MB of the stack to raise the stack overflow */
+#define STACK_OVERFLOW_MAX_SIZE (100*1024*1024)
+
+#ifdef WITH_THREAD
+# define FAULTHANDLER_LATER
+#endif
+
+#ifndef MS_WINDOWS
+ /* register() is useless on Windows, because only SIGSEGV, SIGABRT and
+ SIGILL can be handled by the process, and these signals can only be used
+ with enable(), not using register() */
+# define FAULTHANDLER_USER
+#endif
+
+#define PUTS(fd, str) write(fd, str, strlen(str))
+
+#ifdef HAVE_SIGACTION
+typedef struct sigaction _Py_sighandler_t;
+#else
+typedef PyOS_sighandler_t _Py_sighandler_t;
+#endif
+
+typedef struct {
+ int signum;
+ int enabled;
+ const char* name;
+ _Py_sighandler_t previous;
+ int all_threads;
+} fault_handler_t;
+
+static struct {
+ int enabled;
+ PyObject *file;
+ int fd;
+ int all_threads;
+ PyInterpreterState *interp;
+} fatal_error = {0, NULL, -1, 0};
+
+#ifdef FAULTHANDLER_LATER
+static struct {
+ PyObject *file;
+ int fd;
+ PY_TIMEOUT_T timeout_us; /* timeout in microseconds */
+ int repeat;
+ PyInterpreterState *interp;
+ int exit;
+ char *header;
+ size_t header_len;
+ /* The main thread always hold this lock. It is only released when
+ faulthandler_thread() is interrupted until this thread exits, or at
+ Python exit. */
+ PyThread_type_lock cancel_event;
+ /* released by child thread when joined */
+ PyThread_type_lock running;
+} thread;
+#endif
+
+#ifdef FAULTHANDLER_USER
+typedef struct {
+ int enabled;
+ PyObject *file;
+ int fd;
+ int all_threads;
+ _Py_sighandler_t previous;
+ PyInterpreterState *interp;
+} user_signal_t;
+
+static user_signal_t *user_signals;
+
+/* the following macros come from Python: Modules/signalmodule.c */
+#if defined(PYOS_OS2) && !defined(PYCC_GCC)
+#define NSIG 12
+#endif
+#ifndef NSIG
+# if defined(_NSIG)
+# define NSIG _NSIG /* For BSD/SysV */
+# elif defined(_SIGMAX)
+# define NSIG (_SIGMAX + 1) /* For QNX */
+# elif defined(SIGMAX)
+# define NSIG (SIGMAX + 1) /* For djgpp */
+# else
+# define NSIG 64 /* Use a reasonable default value */
+# endif
+#endif
+
+#endif /* FAULTHANDLER_USER */
+
+
+static fault_handler_t faulthandler_handlers[] = {
+#ifdef SIGBUS
+ {SIGBUS, 0, "Bus error", },
+#endif
+#ifdef SIGILL
+ {SIGILL, 0, "Illegal instruction", },
+#endif
+ {SIGFPE, 0, "Floating point exception", },
+ {SIGABRT, 0, "Aborted", },
+ /* define SIGSEGV at the end to make it the default choice if searching the
+ handler fails in faulthandler_fatal_error() */
+ {SIGSEGV, 0, "Segmentation fault", }
+};
+static const unsigned char faulthandler_nsignals = \
+ sizeof(faulthandler_handlers) / sizeof(faulthandler_handlers[0]);
+
+#ifdef HAVE_SIGALTSTACK
+static stack_t stack;
+#endif
+
+
+/* Get the file descriptor of a file by calling its fileno() method and then
+ call its flush() method.
+
+ If file is NULL or Py_None, use sys.stderr as the new file.
+
+ On success, return the new file and write the file descriptor into *p_fd.
+ On error, return NULL. */
+
+static PyObject*
+faulthandler_get_fileno(PyObject *file, int *p_fd)
+{
+ PyObject *result;
+ long fd_long;
+ int fd;
+
+ if (file == NULL || file == Py_None) {
+ file = PySys_GetObject("stderr");
+ if (file == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr");
+ return NULL;
+ }
+ }
+
+ result = PyObject_CallMethod(file, "fileno", "");
+ if (result == NULL)
+ return NULL;
+
+ fd = -1;
+ if (PyLong_Check(result)) {
+ fd_long = PyLong_AsLong(result);
+ if (0 <= fd_long && fd_long < INT_MAX)
+ fd = (int)fd_long;
+ }
+ Py_DECREF(result);
+
+ if (fd == -1) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "file.fileno() is not a valid file descriptor");
+ return NULL;
+ }
+
+ result = PyObject_CallMethod(file, "flush", "");
+ if (result != NULL)
+ Py_DECREF(result);
+ else {
+ /* ignore flush() error */
+ PyErr_Clear();
+ }
+ *p_fd = fd;
+ return file;
+}
+
+/* Get the state of the current thread: only call this function if the current
+ thread holds the GIL. Raise an exception on error. */
+static PyThreadState*
+get_thread_state(void)
+{
+ PyThreadState *tstate = PyThreadState_Get();
+ if (tstate == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "unable to get the current thread state");
+ return NULL;
+ }
+ return tstate;
+}
+
+static PyObject*
+faulthandler_dump_traceback_py(PyObject *self,
+ PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"file", "all_threads", NULL};
+ PyObject *file = NULL;
+ int all_threads = 0;
+ PyThreadState *tstate;
+ const char *errmsg;
+ int fd;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "|Oi:dump_traceback", kwlist,
+ &file, &all_threads))
+ return NULL;
+
+ file = faulthandler_get_fileno(file, &fd);
+ if (file == NULL)
+ return NULL;
+
+ tstate = get_thread_state();
+ if (tstate == NULL)
+ return NULL;
+
+ if (all_threads) {
+ errmsg = _Py_DumpTracebackThreads(fd, tstate->interp, tstate);
+ if (errmsg != NULL) {
+ PyErr_SetString(PyExc_RuntimeError, errmsg);
+ return NULL;
+ }
+ }
+ else {
+ _Py_DumpTraceback(fd, tstate);
+ }
+ Py_RETURN_NONE;
+}
+
+
+/* Handler of SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals.
+
+ Display the current Python traceback, restore the previous handler and call
+ the previous handler.
+
+ On Windows, don't call explictly the previous handler, because Windows
+ signal handler would not be called (for an unknown reason). The execution of
+ the program continues at faulthandler_fatal_error() exit, but the same
+ instruction will raise the same fault (signal), and so the previous handler
+ will be called.
+
+ This function is signal safe and should only call signal safe functions. */
+
+static void
+faulthandler_fatal_error(int signum)
+{
+ const int fd = fatal_error.fd;
+ unsigned int i;
+ fault_handler_t *handler = NULL;
+ PyThreadState *tstate;
+
+ if (!fatal_error.enabled)
+ return;
+
+ for (i=0; i < faulthandler_nsignals; i++) {
+ handler = &faulthandler_handlers[i];
+ if (handler->signum == signum)
+ break;
+ }
+ if (handler == NULL) {
+ /* faulthandler_nsignals == 0 (unlikely) */
+ return;
+ }
+
+ /* restore the previous handler */
+#ifdef HAVE_SIGACTION
+ (void)sigaction(handler->signum, &handler->previous, NULL);
+#else
+ (void)signal(handler->signum, handler->previous);
+#endif
+ handler->enabled = 0;
+
+ PUTS(fd, "Fatal Python error: ");
+ PUTS(fd, handler->name);
+ PUTS(fd, "\n\n");
+
+#ifdef WITH_THREAD
+ /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and
+ so are delivered to the thread that caused the fault. Get the Python
+ thread state of the current thread.
+
+ PyThreadState_Get() doesn't give the state of the thread that caused the
+ fault if the thread released the GIL, and so this function cannot be
+ used. Read the thread local storage (TLS) instead: call
+ PyGILState_GetThisThreadState(). */
+ tstate = PyGILState_GetThisThreadState();
+#else
+ tstate = PyThreadState_Get();
+#endif
+
+ if (fatal_error.all_threads)
+ _Py_DumpTracebackThreads(fd, fatal_error.interp, tstate);
+ else {
+ if (tstate != NULL)
+ _Py_DumpTraceback(fd, tstate);
+ }
+
+#ifdef MS_WINDOWS
+ if (signum == SIGSEGV) {
+ /* don't call explictly the previous handler for SIGSEGV in this signal
+ handler, because the Windows signal handler would not be called */
+ return;
+ }
+#endif
+ /* call the previous signal handler: it is called immediatly if we use
+ sigaction() thanks to SA_NODEFER flag, otherwise it is deferred */
+ raise(signum);
+}
+
+/* Install the handler for fatal signals, faulthandler_fatal_error(). */
+
+static PyObject*
+faulthandler_enable(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"file", "all_threads", NULL};
+ PyObject *file = NULL;
+ int all_threads = 0;
+ unsigned int i;
+ fault_handler_t *handler;
+#ifdef HAVE_SIGACTION
+ struct sigaction action;
+#endif
+ int err;
+ int fd;
+ PyThreadState *tstate;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "|Oi:enable", kwlist, &file, &all_threads))
+ return NULL;
+
+ file = faulthandler_get_fileno(file, &fd);
+ if (file == NULL)
+ return NULL;
+
+ tstate = get_thread_state();
+ if (tstate == NULL)
+ return NULL;
+
+ Py_XDECREF(fatal_error.file);
+ Py_INCREF(file);
+ fatal_error.file = file;
+ fatal_error.fd = fd;
+ fatal_error.all_threads = all_threads;
+ fatal_error.interp = tstate->interp;
+
+ if (!fatal_error.enabled) {
+ fatal_error.enabled = 1;
+
+ for (i=0; i < faulthandler_nsignals; i++) {
+ handler = &faulthandler_handlers[i];
+#ifdef HAVE_SIGACTION
+ action.sa_handler = faulthandler_fatal_error;
+ sigemptyset(&action.sa_mask);
+ /* Do not prevent the signal from being received from within
+ its own signal handler */
+ action.sa_flags = SA_NODEFER;
+#ifdef HAVE_SIGALTSTACK
+ if (stack.ss_sp != NULL) {
+ /* Call the signal handler on an alternate signal stack
+ provided by sigaltstack() */
+ action.sa_flags |= SA_ONSTACK;
+ }
+#endif
+ err = sigaction(handler->signum, &action, &handler->previous);
+#else
+ handler->previous = signal(handler->signum,
+ faulthandler_fatal_error);
+ err = (handler->previous == SIG_ERR);
+#endif
+ if (err) {
+ PyErr_SetFromErrno(PyExc_RuntimeError);
+ return NULL;
+ }
+ handler->enabled = 1;
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+static void
+faulthandler_disable(void)
+{
+ unsigned int i;
+ fault_handler_t *handler;
+
+ if (fatal_error.enabled) {
+ fatal_error.enabled = 0;
+ for (i=0; i < faulthandler_nsignals; i++) {
+ handler = &faulthandler_handlers[i];
+ if (!handler->enabled)
+ continue;
+#ifdef HAVE_SIGACTION
+ (void)sigaction(handler->signum, &handler->previous, NULL);
+#else
+ (void)signal(handler->signum, handler->previous);
+#endif
+ handler->enabled = 0;
+ }
+ }
+
+ Py_CLEAR(fatal_error.file);
+}
+
+static PyObject*
+faulthandler_disable_py(PyObject *self)
+{
+ if (!fatal_error.enabled) {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+ faulthandler_disable();
+ Py_INCREF(Py_True);
+ return Py_True;
+}
+
+static PyObject*
+faulthandler_is_enabled(PyObject *self)
+{
+ return PyBool_FromLong(fatal_error.enabled);
+}
+
+#ifdef FAULTHANDLER_LATER
+
+static void
+faulthandler_thread(void *unused)
+{
+ PyLockStatus st;
+ const char* errmsg;
+ PyThreadState *current;
+ int ok;
+#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
+ sigset_t set;
+
+ /* we don't want to receive any signal */
+ sigfillset(&set);
+ pthread_sigmask(SIG_SETMASK, &set, NULL);
+#endif
+
+ do {
+ st = PyThread_acquire_lock_timed(thread.cancel_event,
+ thread.timeout_us, 0);
+ if (st == PY_LOCK_ACQUIRED) {
+ PyThread_release_lock(thread.cancel_event);
+ break;
+ }
+ /* Timeout => dump traceback */
+ assert(st == PY_LOCK_FAILURE);
+
+ /* get the thread holding the GIL, NULL if no thread hold the GIL */
+ current = _Py_atomic_load_relaxed(&_PyThreadState_Current);
+
+ write(thread.fd, thread.header, thread.header_len);
+
+ errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current);
+ ok = (errmsg == NULL);
+
+ if (thread.exit)
+ _exit(1);
+ } while (ok && thread.repeat);
+
+ /* The only way out */
+ PyThread_release_lock(thread.running);
+}
+
+static void
+cancel_dump_tracebacks_later(void)
+{
+ /* notify cancellation */
+ PyThread_release_lock(thread.cancel_event);
+
+ /* Wait for thread to join */
+ PyThread_acquire_lock(thread.running, 1);
+ PyThread_release_lock(thread.running);
+
+ /* The main thread should always hold the cancel_event lock */
+ PyThread_acquire_lock(thread.cancel_event, 1);
+
+ Py_CLEAR(thread.file);
+ if (thread.header) {
+ free(thread.header);
+ thread.header = NULL;
+ }
+}
+
+static char*
+format_timeout(double timeout)
+{
+ unsigned long us, sec, min, hour;
+ double intpart, fracpart;
+ char buffer[100];
+
+ fracpart = modf(timeout, &intpart);
+ sec = (unsigned long)intpart;
+ us = (unsigned long)(fracpart * 1e6);
+ min = sec / 60;
+ sec %= 60;
+ hour = min / 60;
+ min %= 60;
+
+ if (us != 0)
+ PyOS_snprintf(buffer, sizeof(buffer),
+ "Timeout (%lu:%02lu:%02lu.%06lu)!\n",
+ hour, min, sec, us);
+ else
+ PyOS_snprintf(buffer, sizeof(buffer),
+ "Timeout (%lu:%02lu:%02lu)!\n",
+ hour, min, sec);
+
+ return strdup(buffer);
+}
+
+static PyObject*
+faulthandler_dump_tracebacks_later(PyObject *self,
+ PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL};
+ double timeout;
+ PY_TIMEOUT_T timeout_us;
+ int repeat = 0;
+ PyObject *file = NULL;
+ int fd;
+ int exit = 0;
+ PyThreadState *tstate;
+ char *header;
+ size_t header_len;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "d|iOi:dump_tracebacks_later", kwlist,
+ &timeout, &repeat, &file, &exit))
+ return NULL;
+ if ((timeout * 1e6) >= (double) PY_TIMEOUT_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "timeout value is too large");
+ return NULL;
+ }
+ timeout_us = (PY_TIMEOUT_T)(timeout * 1e6);
+ if (timeout_us <= 0) {
+ PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
+ return NULL;
+ }
+
+ tstate = get_thread_state();
+ if (tstate == NULL)
+ return NULL;
+
+ file = faulthandler_get_fileno(file, &fd);
+ if (file == NULL)
+ return NULL;
+
+ /* format the timeout */
+ header = format_timeout(timeout);
+ if (header == NULL)
+ return PyErr_NoMemory();
+ header_len = strlen(header);
+
+ /* Cancel previous thread, if running */
+ cancel_dump_tracebacks_later();
+
+ Py_XDECREF(thread.file);
+ Py_INCREF(file);
+ thread.file = file;
+ thread.fd = fd;
+ thread.timeout_us = timeout_us;
+ thread.repeat = repeat;
+ thread.interp = tstate->interp;
+ thread.exit = exit;
+ thread.header = header;
+ thread.header_len = header_len;
+
+ /* Arm these locks to serve as events when released */
+ PyThread_acquire_lock(thread.running, 1);
+
+ if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) {
+ PyThread_release_lock(thread.running);
+ Py_CLEAR(thread.file);
+ free(header);
+ thread.header = NULL;
+ PyErr_SetString(PyExc_RuntimeError,
+ "unable to start watchdog thread");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+faulthandler_cancel_dump_tracebacks_later_py(PyObject *self)
+{
+ cancel_dump_tracebacks_later();
+ Py_RETURN_NONE;
+}
+#endif /* FAULTHANDLER_LATER */
+
+#ifdef FAULTHANDLER_USER
+/* Handler of user signals (e.g. SIGUSR1).
+
+ Dump the traceback of the current thread, or of all threads if
+ thread.all_threads is true.
+
+ This function is signal safe and should only call signal safe functions. */
+
+static void
+faulthandler_user(int signum)
+{
+ user_signal_t *user;
+ PyThreadState *tstate;
+
+ user = &user_signals[signum];
+ if (!user->enabled)
+ return;
+
+#ifdef WITH_THREAD
+ /* PyThreadState_Get() doesn't give the state of the current thread if
+ the thread doesn't hold the GIL. Read the thread local storage (TLS)
+ instead: call PyGILState_GetThisThreadState(). */
+ tstate = PyGILState_GetThisThreadState();
+#else
+ tstate = PyThreadState_Get();
+#endif
+
+ if (user->all_threads)
+ _Py_DumpTracebackThreads(user->fd, user->interp, tstate);
+ else {
+ if (tstate == NULL)
+ return;
+ _Py_DumpTraceback(user->fd, tstate);
+ }
+}
+
+static int
+check_signum(int signum)
+{
+ unsigned int i;
+
+ for (i=0; i < faulthandler_nsignals; i++) {
+ if (faulthandler_handlers[i].signum == signum) {
+ PyErr_Format(PyExc_RuntimeError,
+ "signal %i cannot be registered, "
+ "use enable() instead",
+ signum);
+ return 0;
+ }
+ }
+ if (signum < 1 || NSIG <= signum) {
+ PyErr_SetString(PyExc_ValueError, "signal number out of range");
+ return 0;
+ }
+ return 1;
+}
+
+static PyObject*
+faulthandler_register(PyObject *self,
+ PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"signum", "file", "all_threads", NULL};
+ int signum;
+ PyObject *file = NULL;
+ int all_threads = 0;
+ int fd;
+ user_signal_t *user;
+ _Py_sighandler_t previous;
+#ifdef HAVE_SIGACTION
+ struct sigaction action;
+#endif
+ PyThreadState *tstate;
+ int err;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "i|Oi:register", kwlist,
+ &signum, &file, &all_threads))
+ return NULL;
+
+ if (!check_signum(signum))
+ return NULL;
+
+ tstate = get_thread_state();
+ if (tstate == NULL)
+ return NULL;
+
+ file = faulthandler_get_fileno(file, &fd);
+ if (file == NULL)
+ return NULL;
+
+ if (user_signals == NULL) {
+ user_signals = calloc(NSIG, sizeof(user_signal_t));
+ if (user_signals == NULL)
+ return PyErr_NoMemory();
+ }
+ user = &user_signals[signum];
+
+ if (!user->enabled) {
+#ifdef HAVE_SIGACTION
+ action.sa_handler = faulthandler_user;
+ sigemptyset(&action.sa_mask);
+ /* if the signal is received while the kernel is executing a system
+ call, try to restart the system call instead of interrupting it and
+ return EINTR */
+ action.sa_flags = SA_RESTART;
+#ifdef HAVE_SIGALTSTACK
+ if (stack.ss_sp != NULL) {
+ /* Call the signal handler on an alternate signal stack
+ provided by sigaltstack() */
+ action.sa_flags |= SA_ONSTACK;
+ }
+#endif
+ err = sigaction(signum, &action, &previous);
+#else
+ previous = signal(signum, faulthandler_user);
+ err = (previous == SIG_ERR);
+#endif
+ if (err) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+ }
+
+ Py_XDECREF(user->file);
+ Py_INCREF(file);
+ user->file = file;
+ user->fd = fd;
+ user->all_threads = all_threads;
+ user->previous = previous;
+ user->interp = tstate->interp;
+ user->enabled = 1;
+
+ Py_RETURN_NONE;
+}
+
+static int
+faulthandler_unregister(user_signal_t *user, int signum)
+{
+ if (!user->enabled)
+ return 0;
+ user->enabled = 0;
+#ifdef HAVE_SIGACTION
+ (void)sigaction(signum, &user->previous, NULL);
+#else
+ (void)signal(signum, user->previous);
+#endif
+ Py_CLEAR(user->file);
+ user->fd = -1;
+ return 1;
+}
+
+static PyObject*
+faulthandler_unregister_py(PyObject *self, PyObject *args)
+{
+ int signum;
+ user_signal_t *user;
+ int change;
+
+ if (!PyArg_ParseTuple(args, "i:unregister", &signum))
+ return NULL;
+
+ if (!check_signum(signum))
+ return NULL;
+
+ if (user_signals == NULL)
+ Py_RETURN_FALSE;
+
+ user = &user_signals[signum];
+ change = faulthandler_unregister(user, signum);
+ return PyBool_FromLong(change);
+}
+#endif /* FAULTHANDLER_USER */
+
+
+static PyObject *
+faulthandler_read_null(PyObject *self, PyObject *args)
+{
+ int *x = NULL, y;
+ int release_gil = 0;
+ if (!PyArg_ParseTuple(args, "|i:_read_null", &release_gil))
+ return NULL;
+ if (release_gil) {
+ Py_BEGIN_ALLOW_THREADS
+ y = *x;
+ Py_END_ALLOW_THREADS
+ } else
+ y = *x;
+ return PyLong_FromLong(y);
+
+}
+
+static PyObject *
+faulthandler_sigsegv(PyObject *self, PyObject *args)
+{
+#if defined(MS_WINDOWS)
+ /* For SIGSEGV, faulthandler_fatal_error() restores the previous signal
+ handler and then gives back the execution flow to the program (without
+ calling explicitly the previous error handler). In a normal case, the
+ SIGSEGV was raised by the kernel because of a fault, and so if the
+ program retries to execute the same instruction, the fault will be
+ raised again.
+
+ Here the fault is simulated by a fake SIGSEGV signal raised by the
+ application. We have to raise SIGSEGV at lease twice: once for
+ faulthandler_fatal_error(), and one more time for the previous signal
+ handler. */
+ while(1)
+ raise(SIGSEGV);
+#else
+ raise(SIGSEGV);
+#endif
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+faulthandler_sigfpe(PyObject *self, PyObject *args)
+{
+ /* Do an integer division by zero: raise a SIGFPE on Intel CPU, but not on
+ PowerPC. Use volatile to disable compile-time optimizations. */
+ volatile int x = 1, y = 0, z;
+ z = x / y;
+ /* if the division by zero didn't raise a SIGFPE, raise it manually */
+ raise(SIGFPE);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+faulthandler_sigabrt(PyObject *self, PyObject *args)
+{
+#if _MSC_VER
+ /* If Python is compiled in debug mode with Visual Studio, abort() opens
+ a popup asking the user how to handle the assertion. Use raise(SIGABRT)
+ instead. */
+ raise(SIGABRT);
+#else
+ abort();
+#endif
+ Py_RETURN_NONE;
+}
+
+#ifdef SIGBUS
+static PyObject *
+faulthandler_sigbus(PyObject *self, PyObject *args)
+{
+ raise(SIGBUS);
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef SIGILL
+static PyObject *
+faulthandler_sigill(PyObject *self, PyObject *args)
+{
+ raise(SIGILL);
+ Py_RETURN_NONE;
+}
+#endif
+
+static PyObject *
+faulthandler_fatal_error_py(PyObject *self, PyObject *args)
+{
+ char *message;
+ if (!PyArg_ParseTuple(args, "y:fatal_error", &message))
+ return NULL;
+ Py_FatalError(message);
+ Py_RETURN_NONE;
+}
+
+#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
+void*
+stack_overflow(void *min_sp, void *max_sp, size_t *depth)
+{
+ /* allocate 4096 bytes on the stack at each call */
+ unsigned char buffer[4096];
+ void *sp = &buffer;
+ *depth += 1;
+ if (sp < min_sp || max_sp < sp)
+ return sp;
+ buffer[0] = 1;
+ buffer[4095] = 0;
+ return stack_overflow(min_sp, max_sp, depth);
+}
+
+static PyObject *
+faulthandler_stack_overflow(PyObject *self)
+{
+ size_t depth, size;
+ void *sp = &depth, *stop;
+
+ depth = 0;
+ stop = stack_overflow(sp - STACK_OVERFLOW_MAX_SIZE,
+ sp + STACK_OVERFLOW_MAX_SIZE,
+ &depth);
+ if (sp < stop)
+ size = stop - sp;
+ else
+ size = sp - stop;
+ PyErr_Format(PyExc_RuntimeError,
+ "unable to raise a stack overflow (allocated %zu bytes "
+ "on the stack, %zu recursive calls)",
+ size, depth);
+ return NULL;
+}
+#endif
+
+
+static int
+faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
+{
+#ifdef FAULTHANDLER_USER
+ unsigned int signum;
+#endif
+
+#ifdef FAULTHANDLER_LATER
+ Py_VISIT(thread.file);
+#endif
+#ifdef FAULTHANDLER_USER
+ if (user_signals != NULL) {
+ for (signum=0; signum < NSIG; signum++)
+ Py_VISIT(user_signals[signum].file);
+ }
+#endif
+ Py_VISIT(fatal_error.file);
+ return 0;
+}
+
+PyDoc_STRVAR(module_doc,
+"faulthandler module.");
+
+static PyMethodDef module_methods[] = {
+ {"enable",
+ (PyCFunction)faulthandler_enable, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("enable(file=sys.stderr, all_threads=False): "
+ "enable the fault handler")},
+ {"disable", (PyCFunction)faulthandler_disable_py, METH_NOARGS,
+ PyDoc_STR("disable(): disable the fault handler")},
+ {"is_enabled", (PyCFunction)faulthandler_is_enabled, METH_NOARGS,
+ PyDoc_STR("is_enabled()->bool: check if the handler is enabled")},
+ {"dump_traceback",
+ (PyCFunction)faulthandler_dump_traceback_py, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("dump_traceback(file=sys.stderr, all_threads=False): "
+ "dump the traceback of the current thread, or of all threads "
+ "if all_threads is True, into file")},
+#ifdef FAULTHANDLER_LATER
+ {"dump_tracebacks_later",
+ (PyCFunction)faulthandler_dump_tracebacks_later, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("dump_tracebacks_later(timeout, repeat=False, file=sys.stderrn, exit=False):\n"
+ "dump the traceback of all threads in timeout seconds,\n"
+ "or each timeout seconds if repeat is True. If exit is True, "
+ "call _exit(1) which is not safe.")},
+ {"cancel_dump_tracebacks_later",
+ (PyCFunction)faulthandler_cancel_dump_tracebacks_later_py, METH_NOARGS,
+ PyDoc_STR("cancel_dump_tracebacks_later():\ncancel the previous call "
+ "to dump_tracebacks_later().")},
+#endif
+
+#ifdef FAULTHANDLER_USER
+ {"register",
+ (PyCFunction)faulthandler_register, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("register(signum, file=sys.stderr, all_threads=False): "
+ "register an handler for the signal 'signum': dump the "
+ "traceback of the current thread, or of all threads if "
+ "all_threads is True, into file")},
+ {"unregister",
+ faulthandler_unregister_py, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("unregister(signum): unregister the handler of the signal "
+ "'signum' registered by register()")},
+#endif
+
+ {"_read_null", faulthandler_read_null, METH_VARARGS,
+ PyDoc_STR("_read_null(release_gil=False): read from NULL, raise "
+ "a SIGSEGV or SIGBUS signal depending on the platform")},
+ {"_sigsegv", faulthandler_sigsegv, METH_VARARGS,
+ PyDoc_STR("_sigsegv(): raise a SIGSEGV signal")},
+ {"_sigabrt", faulthandler_sigabrt, METH_VARARGS,
+ PyDoc_STR("_sigabrt(): raise a SIGABRT signal")},
+ {"_sigfpe", (PyCFunction)faulthandler_sigfpe, METH_NOARGS,
+ PyDoc_STR("_sigfpe(): raise a SIGFPE signal")},
+#ifdef SIGBUS
+ {"_sigbus", (PyCFunction)faulthandler_sigbus, METH_NOARGS,
+ PyDoc_STR("_sigbus(): raise a SIGBUS signal")},
+#endif
+#ifdef SIGILL
+ {"_sigill", (PyCFunction)faulthandler_sigill, METH_NOARGS,
+ PyDoc_STR("_sigill(): raise a SIGILL signal")},
+#endif
+ {"_fatal_error", faulthandler_fatal_error_py, METH_VARARGS,
+ PyDoc_STR("_fatal_error(message): call Py_FatalError(message)")},
+#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
+ {"_stack_overflow", (PyCFunction)faulthandler_stack_overflow, METH_NOARGS,
+ PyDoc_STR("_stack_overflow(): recursive call to raise a stack overflow")},
+#endif
+ {NULL, NULL} /* terminator */
+};
+
+static struct PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ "faulthandler",
+ module_doc,
+ 0, /* non negative size to be able to unload the module */
+ module_methods,
+ NULL,
+ faulthandler_traverse,
+ NULL,
+ NULL
+};
+
+PyMODINIT_FUNC
+PyInit_faulthandler(void)
+{
+ return PyModule_Create(&module_def);
+}
+
+/* Call faulthandler.enable() if PYTHONFAULTHANDLER environment variable is
+ defined, or if sys._xoptions has a 'faulthandler' key. */
+
+static int
+faulthandler_env_options(void)
+{
+ PyObject *xoptions, *key, *module, *res;
+ int enable;
+
+ if (!Py_GETENV("PYTHONFAULTHANDLER")) {
+ xoptions = PySys_GetXOptions();
+ if (xoptions == NULL)
+ return -1;
+
+ key = PyUnicode_FromString("faulthandler");
+ if (key == NULL)
+ return -1;
+
+ enable = PyDict_Contains(xoptions, key);
+ Py_DECREF(key);
+ if (!enable)
+ return 0;
+ }
+ else
+ enable = 1;
+
+ module = PyImport_ImportModule("faulthandler");
+ if (module == NULL) {
+ return -1;
+ }
+ res = PyObject_CallMethod(module, "enable", "");
+ Py_DECREF(module);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+int _PyFaulthandler_Init(void)
+{
+#ifdef HAVE_SIGALTSTACK
+ int err;
+
+ /* Try to allocate an alternate stack for faulthandler() signal handler to
+ * be able to allocate memory on the stack, even on a stack overflow. If it
+ * fails, ignore the error. */
+ stack.ss_flags = 0;
+ stack.ss_size = SIGSTKSZ;
+ stack.ss_sp = PyMem_Malloc(stack.ss_size);
+ if (stack.ss_sp != NULL) {
+ err = sigaltstack(&stack, NULL);
+ if (err) {
+ PyMem_Free(stack.ss_sp);
+ stack.ss_sp = NULL;
+ }
+ }
+#endif
+#ifdef FAULTHANDLER_LATER
+ thread.file = NULL;
+ thread.cancel_event = PyThread_allocate_lock();
+ thread.running = PyThread_allocate_lock();
+ if (!thread.cancel_event || !thread.running) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "could not allocate locks for faulthandler");
+ return -1;
+ }
+ PyThread_acquire_lock(thread.cancel_event, 1);
+#endif
+
+ return faulthandler_env_options();
+}
+
+void _PyFaulthandler_Fini(void)
+{
+#ifdef FAULTHANDLER_USER
+ unsigned int signum;
+#endif
+
+#ifdef FAULTHANDLER_LATER
+ /* later */
+ cancel_dump_tracebacks_later();
+ if (thread.cancel_event) {
+ PyThread_release_lock(thread.cancel_event);
+ PyThread_free_lock(thread.cancel_event);
+ thread.cancel_event = NULL;
+ }
+ if (thread.running) {
+ PyThread_free_lock(thread.running);
+ thread.running = NULL;
+ }
+#endif
+
+#ifdef FAULTHANDLER_USER
+ /* user */
+ if (user_signals != NULL) {
+ for (signum=0; signum < NSIG; signum++)
+ faulthandler_unregister(&user_signals[signum], signum);
+ free(user_signals);
+ user_signals = NULL;
+ }
+#endif
+
+ /* fatal */
+ faulthandler_disable();
+#ifdef HAVE_SIGALTSTACK
+ if (stack.ss_sp != NULL) {
+ PyMem_Free(stack.ss_sp);
+ stack.ss_sp = NULL;
+ }
+#endif
+}
diff --git a/Modules/fpectlmodule.c b/Modules/fpectlmodule.c
index 1bb51cf7e3..6af2f82f70 100644
--- a/Modules/fpectlmodule.c
+++ b/Modules/fpectlmodule.c
@@ -174,17 +174,6 @@ static void fpe_reset(Sigfunc *handler)
fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
PyOS_setsig(SIGFPE, handler);
-/*-- DEC ALPHA OSF --------------------------------------------------------*/
-#elif defined(__alpha) && defined(__osf__)
- /* References: exception_intro, ieee man pages */
- /* cc -c -I/usr/local/python/include fpectlmodule.c */
- /* ld -shared -o fpectlmodule.so fpectlmodule.o */
-#include <machine/fpu.h>
- unsigned long fp_control =
- IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE | IEEE_TRAP_ENABLE_OVF;
- ieee_set_fp_control(fp_control);
- PyOS_setsig(SIGFPE, handler);
-
/*-- DEC ALPHA LINUX ------------------------------------------------------*/
#elif defined(__alpha) && defined(linux)
#include <asm/fpu.h>
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 10a4ed7f6a..b05675c84a 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -680,8 +680,8 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
static void
debug_cycle(char *msg, PyObject *op)
{
- PySys_WriteStderr("gc: %.100s <%.100s %p>\n",
- msg, Py_TYPE(op)->tp_name, op);
+ PySys_FormatStderr("gc: %s <%s %p>\n",
+ msg, Py_TYPE(op)->tp_name, op);
}
/* Handle uncollectable garbage (cycles with finalizers, and stuff reachable
diff --git a/Modules/getbuildinfo.c b/Modules/getbuildinfo.c
index 7069b6e202..0971a64fcc 100644
--- a/Modules/getbuildinfo.c
+++ b/Modules/getbuildinfo.c
@@ -20,14 +20,6 @@
#endif
#endif
-/* on unix, SVNVERSION is passed on the command line.
- * on Windows, the string is interpolated using
- * subwcrev.exe
- */
-#ifndef SVNVERSION
-#define SVNVERSION "$WCRANGE$$WCMODS?M:$"
-#endif
-
/* XXX Only unix build process has been tested */
#ifndef HGVERSION
#define HGVERSION ""
@@ -57,16 +49,6 @@ Py_GetBuildInfo(void)
}
const char *
-_Py_svnversion(void)
-{
- /* the following string can be modified by subwcrev.exe */
- static const char svnversion[] = SVNVERSION;
- if (svnversion[0] != '$')
- return svnversion; /* it was interpolated, or passed on command line */
- return "Unversioned directory";
-}
-
-const char *
_Py_hgversion(void)
{
return HGVERSION;
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index 71d5bb646c..ad22ec790c 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -2590,6 +2590,7 @@ typedef struct {
PyObject_HEAD
PyObject *total;
PyObject *it;
+ PyObject *binop;
} accumulateobject;
static PyTypeObject accumulate_type;
@@ -2597,12 +2598,14 @@ static PyTypeObject accumulate_type;
static PyObject *
accumulate_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
- static char *kwargs[] = {"iterable", NULL};
+ static char *kwargs[] = {"iterable", "func", NULL};
PyObject *iterable;
PyObject *it;
+ PyObject *binop = NULL;
accumulateobject *lz;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:accumulate", kwargs, &iterable))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:accumulate",
+ kwargs, &iterable, &binop))
return NULL;
/* Get iterator. */
@@ -2617,6 +2620,8 @@ accumulate_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
+ Py_XINCREF(binop);
+ lz->binop = binop;
lz->total = NULL;
lz->it = it;
return (PyObject *)lz;
@@ -2626,6 +2631,7 @@ static void
accumulate_dealloc(accumulateobject *lz)
{
PyObject_GC_UnTrack(lz);
+ Py_XDECREF(lz->binop);
Py_XDECREF(lz->total);
Py_XDECREF(lz->it);
Py_TYPE(lz)->tp_free(lz);
@@ -2634,6 +2640,7 @@ accumulate_dealloc(accumulateobject *lz)
static int
accumulate_traverse(accumulateobject *lz, visitproc visit, void *arg)
{
+ Py_VISIT(lz->binop);
Py_VISIT(lz->it);
Py_VISIT(lz->total);
return 0;
@@ -2653,8 +2660,11 @@ accumulate_next(accumulateobject *lz)
lz->total = val;
return lz->total;
}
-
- newtotal = PyNumber_Add(lz->total, val);
+
+ if (lz->binop == NULL)
+ newtotal = PyNumber_Add(lz->total, val);
+ else
+ newtotal = PyObject_CallFunctionObjArgs(lz->binop, lz->total, val, NULL);
Py_DECREF(val);
if (newtotal == NULL)
return NULL;
@@ -2668,9 +2678,9 @@ accumulate_next(accumulateobject *lz)
}
PyDoc_STRVAR(accumulate_doc,
-"accumulate(iterable) --> accumulate object\n\
+"accumulate(iterable[, func]) --> accumulate object\n\
\n\
-Return series of accumulated sums.");
+Return series of accumulated sums (or other binary function results).");
static PyTypeObject accumulate_type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -3631,7 +3641,7 @@ cycle(p) --> p0, p1, ... plast, p0, p1, ...\n\
repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\
\n\
Iterators terminating on the shortest input sequence:\n\
-accumulate(p, start=0) --> p0, p0+p1, p0+p1+p2\n\
+accumulate(p[, func]) --> p0, p0+p1, p0+p1+p2\n\
chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ... \n\
compress(data, selectors) --> (d[0] if s[0]), (d[1] if s[1]), ...\n\
dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails\n\
diff --git a/Modules/main.c b/Modules/main.c
index fcd9330e41..747c12f938 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -6,6 +6,7 @@
#include <locale.h>
#ifdef __VMS
+#error "PEP 11: VMS is now unsupported, code will be removed in Python 3.4"
#include <unixlib.h>
#endif
@@ -100,6 +101,7 @@ static char *usage_5 =
" The default module search path uses %s.\n"
"PYTHONCASEOK : ignore case in 'import' statements (Windows).\n"
"PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n"
+"PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.\n"
;
static int
@@ -577,7 +579,6 @@ Py_Main(int argc, wchar_t **argv)
if ((p = Py_GETENV("PYTHONEXECUTABLE")) && *p != '\0') {
wchar_t* buffer;
size_t len = strlen(p);
- size_t r;
buffer = malloc(len * sizeof(wchar_t));
if (buffer == NULL) {
@@ -585,7 +586,7 @@ Py_Main(int argc, wchar_t **argv)
"not enough memory to copy PYTHONEXECUTABLE");
}
- r = mbstowcs(buffer, p, len);
+ mbstowcs(buffer, p, len);
Py_SetProgramName(buffer);
/* buffer is now handed off - do not free */
} else {
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 29c32a30d8..d173bff5c6 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -55,11 +55,6 @@ raised for division by zero and mod by zero.
#include "Python.h"
#include "_math.h"
-#ifdef _OSF_SOURCE
-/* OSF1 5.1 doesn't make this available with XOPEN_SOURCE_EXTENDED defined */
-extern double copysign(double, double);
-#endif
-
/*
sin(pi*x), giving accurate results for all finite x (especially x
integral or close to an integer). This is here for use in the
diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c
index 3cdf1359a6..e5b4e55943 100644
--- a/Modules/parsermodule.c
+++ b/Modules/parsermodule.c
@@ -584,6 +584,7 @@ parser_do_parse(PyObject *args, PyObject *kw, char *argspec, int type)
else
PyParser_SetError(&err);
}
+ PyParser_ClearError(&err);
return (res);
}
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 89d3f2f2d0..396243e0a5 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -30,6 +30,7 @@
#include "Python.h"
#if defined(__VMS)
+# error "PEP 11: VMS is now unsupported, code will be removed in Python 3.4"
# include <unixio.h>
#endif /* defined(__VMS) */
@@ -45,6 +46,7 @@ corresponding Unix manual entries for more information on calls.");
#if defined(PYOS_OS2)
+#error "PEP 11: OS/2 is now unsupported, code will be removed in Python 3.4"
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
@@ -59,6 +61,10 @@ corresponding Unix manual entries for more information on calls.");
#include "osdefs.h"
#endif
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */
@@ -95,6 +101,16 @@ corresponding Unix manual entries for more information on calls.");
#include <langinfo.h>
#endif
+#ifdef HAVE_SYS_SENDFILE_H
+#include <sys/sendfile.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#endif
+
/* Various compilers have only certain posix functions */
/* XXX Gosh I wish these were all moved into pyconfig.h */
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
@@ -121,7 +137,7 @@ corresponding Unix manual entries for more information on calls.");
#ifdef _MSC_VER /* Microsoft compiler */
#define HAVE_GETCWD 1
#define HAVE_GETPPID 1
-#define HAVE_GETLOGIN 1
+#define HAVE_GETLOGIN 1
#define HAVE_SPAWNV 1
#define HAVE_EXECV 1
#define HAVE_PIPE 1
@@ -349,6 +365,19 @@ static int win32_can_symlink = 0;
#endif
#endif
+static int
+_parse_off_t(PyObject* arg, void* addr)
+{
+#if !defined(HAVE_LARGEFILE_SUPPORT)
+ *((off_t*)addr) = PyLong_AsLong(arg);
+#else
+ *((off_t*)addr) = PyLong_AsLongLong(arg);
+#endif
+ if (PyErr_Occurred())
+ return 0;
+ return 1;
+}
+
#if defined _MSC_VER && _MSC_VER >= 1400
/* Microsoft CRT in VS2005 and higher will verify that a filehandle is
* valid and throw an assertion if it isn't.
@@ -1283,7 +1312,7 @@ win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse)
The _w represent Unicode equivalents of the aforementioned ANSI functions. */
-static int
+static int
win32_lstat(const char* path, struct win32_stat *result)
{
return win32_xstat(path, result, FALSE);
@@ -1301,7 +1330,7 @@ win32_stat(const char* path, struct win32_stat *result)
return win32_xstat(path, result, TRUE);
}
-static int
+static int
win32_stat_w(const wchar_t* path, struct win32_stat *result)
{
return win32_xstat_w(path, result, TRUE);
@@ -1476,6 +1505,33 @@ static PyStructSequence_Desc statvfs_result_desc = {
10
};
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+PyDoc_STRVAR(waitid_result__doc__,
+"waitid_result: Result from waitid.\n\n\
+This object may be accessed either as a tuple of\n\
+ (si_pid, si_uid, si_signo, si_status, si_code),\n\
+or via the attributes si_pid, si_uid, and so on.\n\
+\n\
+See os.waitid for more information.");
+
+static PyStructSequence_Field waitid_result_fields[] = {
+ {"si_pid", },
+ {"si_uid", },
+ {"si_signo", },
+ {"si_status", },
+ {"si_code", },
+ {0}
+};
+
+static PyStructSequence_Desc waitid_result_desc = {
+ "waitid_result", /* name */
+ waitid_result__doc__, /* doc */
+ waitid_result_fields,
+ 5
+};
+static PyTypeObject WaitidResultType;
+#endif
+
static int initialized;
static PyTypeObject StatResultType;
static PyTypeObject StatVFSResultType;
@@ -2075,6 +2131,21 @@ posix_fsync(PyObject *self, PyObject *fdobj)
}
#endif /* HAVE_FSYNC */
+#ifdef HAVE_SYNC
+PyDoc_STRVAR(posix_sync__doc__,
+"sync()\n\n\
+Force write of everything to disk.");
+
+static PyObject *
+posix_sync(PyObject *self, PyObject *noargs)
+{
+ Py_BEGIN_ALLOW_THREADS
+ sync();
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+#endif
+
#ifdef HAVE_FDATASYNC
#ifdef __hpux
@@ -2339,7 +2410,7 @@ posix_listdir(PyObject *self, PyObject *args)
if (PyArg_ParseTuple(args, "|U:listdir", &po)) {
WIN32_FIND_DATAW wFileData;
Py_UNICODE *wnamebuf, *po_wchars;
-
+
if (po == NULL) { /* Default arg: "." */
po_wchars = L".";
len = 1;
@@ -2650,6 +2721,76 @@ posix_listdir(PyObject *self, PyObject *args)
#endif /* which OS */
} /* end of posix_listdir */
+#ifdef HAVE_FDOPENDIR
+PyDoc_STRVAR(posix_fdlistdir__doc__,
+"fdlistdir(fd) -> list_of_strings\n\n\
+Like listdir(), but uses a file descriptor instead.\n\
+After succesful execution of this function, fd will be closed.");
+
+static PyObject *
+posix_fdlistdir(PyObject *self, PyObject *args)
+{
+ PyObject *d, *v;
+ DIR *dirp;
+ struct dirent *ep;
+ int fd;
+
+ errno = 0;
+ if (!PyArg_ParseTuple(args, "i:fdlistdir", &fd))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ dirp = fdopendir(fd);
+ Py_END_ALLOW_THREADS
+ if (dirp == NULL) {
+ close(fd);
+ return posix_error();
+ }
+ if ((d = PyList_New(0)) == NULL) {
+ Py_BEGIN_ALLOW_THREADS
+ closedir(dirp);
+ Py_END_ALLOW_THREADS
+ return NULL;
+ }
+ for (;;) {
+ errno = 0;
+ Py_BEGIN_ALLOW_THREADS
+ ep = readdir(dirp);
+ Py_END_ALLOW_THREADS
+ if (ep == NULL) {
+ if (errno == 0) {
+ break;
+ } else {
+ Py_BEGIN_ALLOW_THREADS
+ closedir(dirp);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(d);
+ return posix_error();
+ }
+ }
+ if (ep->d_name[0] == '.' &&
+ (NAMLEN(ep) == 1 ||
+ (ep->d_name[1] == '.' && NAMLEN(ep) == 2)))
+ continue;
+ v = PyUnicode_DecodeFSDefaultAndSize(ep->d_name, NAMLEN(ep));
+ if (v == NULL) {
+ Py_CLEAR(d);
+ break;
+ }
+ if (PyList_Append(d, v) != 0) {
+ Py_DECREF(v);
+ Py_CLEAR(d);
+ break;
+ }
+ Py_DECREF(v);
+ }
+ Py_BEGIN_ALLOW_THREADS
+ closedir(dirp);
+ Py_END_ALLOW_THREADS
+
+ return d;
+}
+#endif
+
#ifdef MS_WINDOWS
/* A helper function for abspath on win32 */
static PyObject *
@@ -2741,7 +2882,7 @@ posix__getfinalpathname(PyObject *self, PyObject *args)
int result_length;
PyObject *result;
wchar_t *path;
-
+
if (!PyArg_ParseTuple(args, "u|:_getfinalpathname", &path)) {
return NULL;
}
@@ -2762,7 +2903,7 @@ posix__getfinalpathname(PyObject *self, PyObject *args)
/* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
-
+
if(hFile == INVALID_HANDLE_VALUE) {
return win32_error_unicode("GetFinalPathNamyByHandle", path);
return PyErr_Format(PyExc_RuntimeError,
@@ -2930,6 +3071,48 @@ posix_nice(PyObject *self, PyObject *args)
}
#endif /* HAVE_NICE */
+
+#ifdef HAVE_GETPRIORITY
+PyDoc_STRVAR(posix_getpriority__doc__,
+"getpriority(which, who) -> current_priority\n\n\
+Get program scheduling priority.");
+
+static PyObject *
+posix_getpriority(PyObject *self, PyObject *args)
+{
+ int which, who, retval;
+
+ if (!PyArg_ParseTuple(args, "ii", &which, &who))
+ return NULL;
+ errno = 0;
+ retval = getpriority(which, who);
+ if (errno != 0)
+ return posix_error();
+ return PyLong_FromLong((long)retval);
+}
+#endif /* HAVE_GETPRIORITY */
+
+
+#ifdef HAVE_SETPRIORITY
+PyDoc_STRVAR(posix_setpriority__doc__,
+"setpriority(which, who, prio) -> None\n\n\
+Set program scheduling priority.");
+
+static PyObject *
+posix_setpriority(PyObject *self, PyObject *args)
+{
+ int which, who, prio, retval;
+
+ if (!PyArg_ParseTuple(args, "iii", &which, &who, &prio))
+ return NULL;
+ retval = setpriority(which, who, prio);
+ if (retval == -1)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif /* HAVE_SETPRIORITY */
+
+
PyDoc_STRVAR(posix_rename__doc__,
"rename(old, new)\n\n\
Rename a file or directory.");
@@ -3072,7 +3255,7 @@ BOOL WINAPI Py_DeleteFileW(LPCWSTR lpFileName)
if (GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &info)) {
is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
-
+
/* Get WIN32_FIND_DATA structure for the path to determine if
it is a symlink */
if(is_directory &&
@@ -3345,6 +3528,167 @@ done:
#endif /* MS_WINDOWS */
}
+#ifdef HAVE_FUTIMES
+PyDoc_STRVAR(posix_futimes__doc__,
+"futimes(fd, (atime, mtime))\n\
+futimes(fd, None)\n\n\
+Set the access and modified time of the file specified by the file\n\
+descriptor fd to the given values. If the second form is used, set the\n\
+access and modified times to the current time.");
+
+static PyObject *
+posix_futimes(PyObject *self, PyObject *args)
+{
+ int res, fd;
+ PyObject* arg;
+ struct timeval buf[2];
+ long ausec, musec;
+
+ if (!PyArg_ParseTuple(args, "iO:futimes", &fd, &arg))
+ return NULL;
+
+ if (arg == Py_None) {
+ /* optional time values not given */
+ Py_BEGIN_ALLOW_THREADS
+ res = futimes(fd, NULL);
+ Py_END_ALLOW_THREADS
+ }
+ else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "futimes() arg 2 must be a tuple (atime, mtime)");
+ return NULL;
+ }
+ else {
+ if (extract_time(PyTuple_GET_ITEM(arg, 0),
+ &(buf[0].tv_sec), &ausec) == -1) {
+ return NULL;
+ }
+ if (extract_time(PyTuple_GET_ITEM(arg, 1),
+ &(buf[1].tv_sec), &musec) == -1) {
+ return NULL;
+ }
+ buf[0].tv_usec = ausec;
+ buf[1].tv_usec = musec;
+ Py_BEGIN_ALLOW_THREADS
+ res = futimes(fd, buf);
+ Py_END_ALLOW_THREADS
+ }
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_LUTIMES
+PyDoc_STRVAR(posix_lutimes__doc__,
+"lutimes(path, (atime, mtime))\n\
+lutimes(path, None)\n\n\
+Like utime(), but if path is a symbolic link, it is not dereferenced.");
+
+static PyObject *
+posix_lutimes(PyObject *self, PyObject *args)
+{
+ PyObject *opath, *arg;
+ const char *path;
+ int res;
+ struct timeval buf[2];
+ long ausec, musec;
+
+ if (!PyArg_ParseTuple(args, "O&O:lutimes",
+ PyUnicode_FSConverter, &opath, &arg))
+ return NULL;
+ path = PyBytes_AsString(opath);
+ if (arg == Py_None) {
+ /* optional time values not given */
+ Py_BEGIN_ALLOW_THREADS
+ res = lutimes(path, NULL);
+ Py_END_ALLOW_THREADS
+ }
+ else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "lutimes() arg 2 must be a tuple (atime, mtime)");
+ Py_DECREF(opath);
+ return NULL;
+ }
+ else {
+ if (extract_time(PyTuple_GET_ITEM(arg, 0),
+ &(buf[0].tv_sec), &ausec) == -1) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+ if (extract_time(PyTuple_GET_ITEM(arg, 1),
+ &(buf[1].tv_sec), &musec) == -1) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+ buf[0].tv_usec = ausec;
+ buf[1].tv_usec = musec;
+ Py_BEGIN_ALLOW_THREADS
+ res = lutimes(path, buf);
+ Py_END_ALLOW_THREADS
+ }
+ Py_DECREF(opath);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_FUTIMENS
+PyDoc_STRVAR(posix_futimens__doc__,
+"futimens(fd, (atime_sec, atime_nsec), (mtime_sec, mtime_nsec))\n\
+futimens(fd, None, None)\n\n\
+Updates the timestamps of a file specified by the file descriptor fd, with\n\
+nanosecond precision.\n\
+The second form sets atime and mtime to the current time.\n\
+If *_nsec is specified as UTIME_NOW, the timestamp is updated to the\n\
+current time.\n\
+If *_nsec is specified as UTIME_OMIT, the timestamp is not updated.");
+
+static PyObject *
+posix_futimens(PyObject *self, PyObject *args)
+{
+ int res, fd;
+ PyObject *atime, *mtime;
+ struct timespec buf[2];
+
+ if (!PyArg_ParseTuple(args, "iOO:futimens",
+ &fd, &atime, &mtime))
+ return NULL;
+ if (atime == Py_None && mtime == Py_None) {
+ /* optional time values not given */
+ Py_BEGIN_ALLOW_THREADS
+ res = futimens(fd, NULL);
+ Py_END_ALLOW_THREADS
+ }
+ else if (!PyTuple_Check(atime) || PyTuple_Size(atime) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "futimens() arg 2 must be a tuple (atime_sec, atime_nsec)");
+ return NULL;
+ }
+ else if (!PyTuple_Check(mtime) || PyTuple_Size(mtime) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "futimens() arg 3 must be a tuple (mtime_sec, mtime_nsec)");
+ return NULL;
+ }
+ else {
+ if (!PyArg_ParseTuple(atime, "ll:futimens",
+ &(buf[0].tv_sec), &(buf[0].tv_nsec))) {
+ return NULL;
+ }
+ if (!PyArg_ParseTuple(mtime, "ll:futimens",
+ &(buf[1].tv_sec), &(buf[1].tv_nsec))) {
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS
+ res = futimens(fd, buf);
+ Py_END_ALLOW_THREADS
+ }
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
/* Process operations */
@@ -3389,79 +3733,7 @@ int fsconvert_strdup(PyObject *o, char**out)
}
#endif
-
-#ifdef HAVE_EXECV
-PyDoc_STRVAR(posix_execv__doc__,
-"execv(path, args)\n\n\
-Execute an executable path with arguments, replacing current process.\n\
-\n\
- path: path of executable file\n\
- args: tuple or list of strings");
-
-static PyObject *
-posix_execv(PyObject *self, PyObject *args)
-{
- PyObject *opath;
- char *path;
- PyObject *argv;
- char **argvlist;
- Py_ssize_t i, argc;
- PyObject *(*getitem)(PyObject *, Py_ssize_t);
-
- /* execv has two arguments: (path, argv), where
- argv is a list or tuple of strings. */
-
- if (!PyArg_ParseTuple(args, "O&O:execv",
- PyUnicode_FSConverter,
- &opath, &argv))
- return NULL;
- path = PyBytes_AsString(opath);
- if (PyList_Check(argv)) {
- argc = PyList_Size(argv);
- getitem = PyList_GetItem;
- }
- else if (PyTuple_Check(argv)) {
- argc = PyTuple_Size(argv);
- getitem = PyTuple_GetItem;
- }
- else {
- PyErr_SetString(PyExc_TypeError, "execv() arg 2 must be a tuple or list");
- Py_DECREF(opath);
- return NULL;
- }
- if (argc < 1) {
- PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty");
- Py_DECREF(opath);
- return NULL;
- }
-
- argvlist = PyMem_NEW(char *, argc+1);
- if (argvlist == NULL) {
- Py_DECREF(opath);
- return PyErr_NoMemory();
- }
- for (i = 0; i < argc; i++) {
- if (!fsconvert_strdup((*getitem)(argv, i),
- &argvlist[i])) {
- free_string_array(argvlist, i);
- PyErr_SetString(PyExc_TypeError,
- "execv() arg 2 must contain only strings");
- Py_DECREF(opath);
- return NULL;
-
- }
- }
- argvlist[argc] = NULL;
-
- execv(path, argvlist);
-
- /* If we get here it's definitely an error */
-
- free_string_array(argvlist, argc);
- Py_DECREF(opath);
- return posix_error();
-}
-
+#if defined(HAVE_EXECV) || defined (HAVE_FEXECVE)
static char**
parse_envlist(PyObject* env, Py_ssize_t *envc_ptr)
{
@@ -3543,6 +3815,87 @@ error:
return NULL;
}
+static char**
+parse_arglist(PyObject* argv, Py_ssize_t *argc)
+{
+ int i;
+ char **argvlist = PyMem_NEW(char *, *argc+1);
+ if (argvlist == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (i = 0; i < *argc; i++) {
+ PyObject* item = PySequence_ITEM(argv, i);
+ if (item == NULL)
+ goto fail;
+ if (!fsconvert_strdup(item, &argvlist[i])) {
+ Py_DECREF(item);
+ goto fail;
+ }
+ Py_DECREF(item);
+ }
+ argvlist[*argc] = NULL;
+ return argvlist;
+fail:
+ *argc = i;
+ free_string_array(argvlist, *argc);
+ return NULL;
+}
+#endif
+
+#ifdef HAVE_EXECV
+PyDoc_STRVAR(posix_execv__doc__,
+"execv(path, args)\n\n\
+Execute an executable path with arguments, replacing current process.\n\
+\n\
+ path: path of executable file\n\
+ args: tuple or list of strings");
+
+static PyObject *
+posix_execv(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ char *path;
+ PyObject *argv;
+ char **argvlist;
+ Py_ssize_t argc;
+
+ /* execv has two arguments: (path, argv), where
+ argv is a list or tuple of strings. */
+
+ if (!PyArg_ParseTuple(args, "O&O:execv",
+ PyUnicode_FSConverter,
+ &opath, &argv))
+ return NULL;
+ path = PyBytes_AsString(opath);
+ if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
+ PyErr_SetString(PyExc_TypeError,
+ "execv() arg 2 must be a tuple or list");
+ Py_DECREF(opath);
+ return NULL;
+ }
+ argc = PySequence_Size(argv);
+ if (argc < 1) {
+ PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty");
+ Py_DECREF(opath);
+ return NULL;
+ }
+
+ argvlist = parse_arglist(argv, &argc);
+ if (argvlist == NULL) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+
+ execv(path, argvlist);
+
+ /* If we get here it's definitely an error */
+
+ free_string_array(argvlist, argc);
+ Py_DECREF(opath);
+ return posix_error();
+}
+
PyDoc_STRVAR(posix_execve__doc__,
"execve(path, args, env)\n\n\
Execute a path with arguments and environment, replacing current process.\n\
@@ -3559,9 +3912,7 @@ posix_execve(PyObject *self, PyObject *args)
PyObject *argv, *env;
char **argvlist;
char **envlist;
- Py_ssize_t i, argc, envc;
- PyObject *(*getitem)(PyObject *, Py_ssize_t);
- Py_ssize_t lastarg = 0;
+ Py_ssize_t argc, envc;
/* execve has three arguments: (path, argv, env), where
argv is a list or tuple of strings and env is a dictionary
@@ -3572,40 +3923,22 @@ posix_execve(PyObject *self, PyObject *args)
&opath, &argv, &env))
return NULL;
path = PyBytes_AsString(opath);
- if (PyList_Check(argv)) {
- argc = PyList_Size(argv);
- getitem = PyList_GetItem;
- }
- else if (PyTuple_Check(argv)) {
- argc = PyTuple_Size(argv);
- getitem = PyTuple_GetItem;
- }
- else {
+ if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
PyErr_SetString(PyExc_TypeError,
"execve() arg 2 must be a tuple or list");
goto fail_0;
}
+ argc = PySequence_Size(argv);
if (!PyMapping_Check(env)) {
PyErr_SetString(PyExc_TypeError,
"execve() arg 3 must be a mapping object");
goto fail_0;
}
- argvlist = PyMem_NEW(char *, argc+1);
+ argvlist = parse_arglist(argv, &argc);
if (argvlist == NULL) {
- PyErr_NoMemory();
goto fail_0;
}
- for (i = 0; i < argc; i++) {
- if (!fsconvert_strdup((*getitem)(argv, i),
- &argvlist[i]))
- {
- lastarg = i;
- goto fail_1;
- }
- }
- lastarg = argc;
- argvlist[argc] = NULL;
envlist = parse_envlist(env, &envc);
if (envlist == NULL)
@@ -3621,13 +3954,69 @@ posix_execve(PyObject *self, PyObject *args)
PyMem_DEL(envlist[envc]);
PyMem_DEL(envlist);
fail_1:
- free_string_array(argvlist, lastarg);
+ free_string_array(argvlist, argc);
fail_0:
Py_DECREF(opath);
return NULL;
}
#endif /* HAVE_EXECV */
+#ifdef HAVE_FEXECVE
+PyDoc_STRVAR(posix_fexecve__doc__,
+"fexecve(fd, args, env)\n\n\
+Execute the program specified by a file descriptor with arguments and\n\
+environment, replacing the current process.\n\
+\n\
+ fd: file descriptor of executable\n\
+ args: tuple or list of arguments\n\
+ env: dictionary of strings mapping to strings");
+
+static PyObject *
+posix_fexecve(PyObject *self, PyObject *args)
+{
+ int fd;
+ PyObject *argv, *env;
+ char **argvlist;
+ char **envlist;
+ Py_ssize_t argc, envc;
+
+ if (!PyArg_ParseTuple(args, "iOO:fexecve",
+ &fd, &argv, &env))
+ return NULL;
+ if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
+ PyErr_SetString(PyExc_TypeError,
+ "fexecve() arg 2 must be a tuple or list");
+ return NULL;
+ }
+ argc = PySequence_Size(argv);
+ if (!PyMapping_Check(env)) {
+ PyErr_SetString(PyExc_TypeError,
+ "fexecve() arg 3 must be a mapping object");
+ return NULL;
+ }
+
+ argvlist = parse_arglist(argv, &argc);
+ if (argvlist == NULL)
+ return NULL;
+
+ envlist = parse_envlist(env, &envc);
+ if (envlist == NULL)
+ goto fail;
+
+ fexecve(fd, argvlist, envlist);
+
+ /* If we get here it's definitely an error */
+
+ (void) posix_error();
+
+ while (--envc >= 0)
+ PyMem_DEL(envlist[envc]);
+ PyMem_DEL(envlist);
+ fail:
+ free_string_array(argvlist, argc);
+ return NULL;
+}
+#endif /* HAVE_FEXECVE */
#ifdef HAVE_SPAWNV
PyDoc_STRVAR(posix_spawnv__doc__,
@@ -4194,6 +4583,7 @@ posix_forkpty(PyObject *self, PyObject *noargs)
}
#endif
+
#ifdef HAVE_GETEGID
PyDoc_STRVAR(posix_getegid__doc__,
"getegid() -> egid\n\n\
@@ -4262,7 +4652,7 @@ posix_getgroups(PyObject *self, PyObject *noargs)
#endif
gid_t grouplist[MAX_GROUPS];
- /* On MacOSX getgroups(2) can return more than MAX_GROUPS results
+ /* On MacOSX getgroups(2) can return more than MAX_GROUPS results
* This is a helper variable to store the intermediate result when
* that happens.
*
@@ -4478,15 +4868,15 @@ static PyObject *
posix_getlogin(PyObject *self, PyObject *noargs)
{
PyObject *result = NULL;
-#ifdef MS_WINDOWS
+#ifdef MS_WINDOWS
wchar_t user_name[UNLEN + 1];
DWORD num_chars = sizeof(user_name)/sizeof(user_name[0]);
if (GetUserNameW(user_name, &num_chars)) {
/* num_chars is the number of unicode chars plus null terminator */
result = PyUnicode_FromWideChar(user_name, num_chars - 1);
- }
- else
+ }
+ else
result = PyErr_SetFromWindowsErr(GetLastError());
#else
char *name;
@@ -4984,6 +5374,55 @@ posix_wait4(PyObject *self, PyObject *args)
}
#endif /* HAVE_WAIT4 */
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+PyDoc_STRVAR(posix_waitid__doc__,
+"waitid(idtype, id, options) -> waitid_result\n\n\
+Wait for the completion of one or more child processes.\n\n\
+idtype can be P_PID, P_PGID or P_ALL.\n\
+id specifies the pid to wait on.\n\
+options is constructed from the ORing of one or more of WEXITED, WSTOPPED\n\
+or WCONTINUED and additionally may be ORed with WNOHANG or WNOWAIT.\n\
+Returns either waitid_result or None if WNOHANG is specified and there are\n\
+no children in a waitable state.");
+
+static PyObject *
+posix_waitid(PyObject *self, PyObject *args)
+{
+ PyObject *result;
+ idtype_t idtype;
+ id_t id;
+ int options, res;
+ siginfo_t si;
+ si.si_pid = 0;
+ if (!PyArg_ParseTuple(args, "i" _Py_PARSE_PID "i:waitid", &idtype, &id, &options))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ res = waitid(idtype, id, &si, options);
+ Py_END_ALLOW_THREADS
+ if (res == -1)
+ return posix_error();
+
+ if (si.si_pid == 0)
+ Py_RETURN_NONE;
+
+ result = PyStructSequence_New(&WaitidResultType);
+ if (!result)
+ return NULL;
+
+ PyStructSequence_SET_ITEM(result, 0, PyLong_FromPid(si.si_pid));
+ PyStructSequence_SET_ITEM(result, 1, PyLong_FromPid(si.si_uid));
+ PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong((long)(si.si_signo)));
+ PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong((long)(si.si_status)));
+ PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong((long)(si.si_code)));
+ if (PyErr_Occurred()) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+#endif
+
#ifdef HAVE_WAITPID
PyDoc_STRVAR(posix_waitpid__doc__,
"waitpid(pid, options) -> (pid, status)\n\n\
@@ -5170,12 +5609,12 @@ win_readlink(PyObject *self, PyObject *args)
FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS,
0);
Py_END_ALLOW_THREADS
-
+
if (reparse_point_handle==INVALID_HANDLE_VALUE)
{
return win32_error_unicode("readlink", path);
}
-
+
Py_BEGIN_ALLOW_THREADS
/* New call DeviceIoControl to read the reparse point */
io_result = DeviceIoControl(
@@ -5246,7 +5685,7 @@ win_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
int target_is_directory = 0;
DWORD res;
WIN32_FILE_ATTRIBUTE_DATA src_info;
-
+
if (!check_CreateSymbolicLinkW())
{
/* raise NotImplementedError */
@@ -5265,7 +5704,7 @@ win_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
Py_DECREF(src);
return NULL;
}
-
+
/* if src is a directory, ensure target_is_directory==1 */
if(
GetFileAttributesExW(
@@ -5288,7 +5727,7 @@ win_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
{
return win32_error_unicode("symlink", PyUnicode_AsUnicode(src));
}
-
+
Py_INCREF(Py_None);
return Py_None;
}
@@ -5569,9 +6008,7 @@ posix_dup(PyObject *self, PyObject *args)
return NULL;
if (!_PyVerify_fd(fd))
return posix_error();
- Py_BEGIN_ALLOW_THREADS
fd = dup(fd);
- Py_END_ALLOW_THREADS
if (fd < 0)
return posix_error();
return PyLong_FromLong((long)fd);
@@ -5590,15 +6027,42 @@ posix_dup2(PyObject *self, PyObject *args)
return NULL;
if (!_PyVerify_fd_dup2(fd, fd2))
return posix_error();
- Py_BEGIN_ALLOW_THREADS
res = dup2(fd, fd2);
- Py_END_ALLOW_THREADS
if (res < 0)
return posix_error();
Py_INCREF(Py_None);
return Py_None;
}
+#ifdef HAVE_LOCKF
+PyDoc_STRVAR(posix_lockf__doc__,
+"lockf(fd, cmd, len)\n\n\
+Apply, test or remove a POSIX lock on an open file descriptor.\n\n\
+fd is an open file descriptor.\n\
+cmd specifies the command to use - one of F_LOCK, F_TLOCK, F_ULOCK or\n\
+F_TEST.\n\
+len specifies the section of the file to lock.");
+
+static PyObject *
+posix_lockf(PyObject *self, PyObject *args)
+{
+ int fd, cmd, res;
+ off_t len;
+ if (!PyArg_ParseTuple(args, "iiO&:lockf",
+ &fd, &cmd, _parse_off_t, &len))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ res = lockf(fd, cmd, len);
+ Py_END_ALLOW_THREADS
+
+ if (res < 0)
+ return posix_error();
+
+ Py_RETURN_NONE;
+}
+#endif
+
PyDoc_STRVAR(posix_lseek__doc__,
"lseek(fd, pos, how) -> newpos\n\n\
@@ -5628,8 +6092,7 @@ posix_lseek(PyObject *self, PyObject *args)
#if !defined(HAVE_LARGEFILE_SUPPORT)
pos = PyLong_AsLong(posobj);
#else
- pos = PyLong_Check(posobj) ?
- PyLong_AsLongLong(posobj) : PyLong_AsLong(posobj);
+ pos = PyLong_AsLongLong(posobj);
#endif
if (PyErr_Occurred())
return NULL;
@@ -5689,6 +6152,140 @@ posix_read(PyObject *self, PyObject *args)
return buffer;
}
+#if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
+ || defined(__APPLE__))) || defined(HAVE_READV) || defined(HAVE_WRITEV)
+static Py_ssize_t
+iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, int cnt, int type)
+{
+ int i, j;
+ Py_ssize_t blen, total = 0;
+
+ *iov = PyMem_New(struct iovec, cnt);
+ if (*iov == NULL) {
+ PyErr_NoMemory();
+ return total;
+ }
+
+ *buf = PyMem_New(Py_buffer, cnt);
+ if (*buf == NULL) {
+ PyMem_Del(*iov);
+ PyErr_NoMemory();
+ return total;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ PyObject *item = PySequence_GetItem(seq, i);
+ if (item == NULL)
+ goto fail;
+ if (PyObject_GetBuffer(item, &(*buf)[i], type) == -1) {
+ Py_DECREF(item);
+ goto fail;
+ }
+ Py_DECREF(item);
+ (*iov)[i].iov_base = (*buf)[i].buf;
+ blen = (*buf)[i].len;
+ (*iov)[i].iov_len = blen;
+ total += blen;
+ }
+ return total;
+
+fail:
+ PyMem_Del(*iov);
+ for (j = 0; j < i; j++) {
+ PyBuffer_Release(&(*buf)[j]);
+ }
+ PyMem_Del(*buf);
+ return 0;
+}
+
+static void
+iov_cleanup(struct iovec *iov, Py_buffer *buf, int cnt)
+{
+ int i;
+ PyMem_Del(iov);
+ for (i = 0; i < cnt; i++) {
+ PyBuffer_Release(&buf[i]);
+ }
+ PyMem_Del(buf);
+}
+#endif
+
+#ifdef HAVE_READV
+PyDoc_STRVAR(posix_readv__doc__,
+"readv(fd, buffers) -> bytesread\n\n\
+Read from a file descriptor into a number of writable buffers. buffers\n\
+is an arbitrary sequence of writable buffers.\n\
+Returns the total number of bytes read.");
+
+static PyObject *
+posix_readv(PyObject *self, PyObject *args)
+{
+ int fd, cnt;
+ Py_ssize_t n;
+ PyObject *seq;
+ struct iovec *iov;
+ Py_buffer *buf;
+
+ if (!PyArg_ParseTuple(args, "iO:readv", &fd, &seq))
+ return NULL;
+ if (!PySequence_Check(seq)) {
+ PyErr_SetString(PyExc_TypeError,
+ "readv() arg 2 must be a sequence");
+ return NULL;
+ }
+ cnt = PySequence_Size(seq);
+
+ if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ n = readv(fd, iov, cnt);
+ Py_END_ALLOW_THREADS
+
+ iov_cleanup(iov, buf, cnt);
+ return PyLong_FromSsize_t(n);
+}
+#endif
+
+#ifdef HAVE_PREAD
+PyDoc_STRVAR(posix_pread__doc__,
+"pread(fd, buffersize, offset) -> string\n\n\
+Read from a file descriptor, fd, at a position of offset. It will read up\n\
+to buffersize number of bytes. The file offset remains unchanged.");
+
+static PyObject *
+posix_pread(PyObject *self, PyObject *args)
+{
+ int fd, size;
+ off_t offset;
+ Py_ssize_t n;
+ PyObject *buffer;
+ if (!PyArg_ParseTuple(args, "iiO&:pread", &fd, &size, _parse_off_t, &offset))
+ return NULL;
+
+ if (size < 0) {
+ errno = EINVAL;
+ return posix_error();
+ }
+ buffer = PyBytes_FromStringAndSize((char *)NULL, size);
+ if (buffer == NULL)
+ return NULL;
+ if (!_PyVerify_fd(fd)) {
+ Py_DECREF(buffer);
+ return posix_error();
+ }
+ Py_BEGIN_ALLOW_THREADS
+ n = pread(fd, PyBytes_AS_STRING(buffer), size, offset);
+ Py_END_ALLOW_THREADS
+ if (n < 0) {
+ Py_DECREF(buffer);
+ return posix_error();
+ }
+ if (n != size)
+ _PyBytes_Resize(&buffer, n);
+ return buffer;
+}
+#endif
PyDoc_STRVAR(posix_write__doc__,
"write(fd, string) -> byteswritten\n\n\
@@ -5723,6 +6320,144 @@ posix_write(PyObject *self, PyObject *args)
return PyLong_FromSsize_t(size);
}
+#ifdef HAVE_SENDFILE
+PyDoc_STRVAR(posix_sendfile__doc__,
+"sendfile(out, in, offset, nbytes) -> byteswritten\n\
+sendfile(out, in, offset, nbytes, headers=None, trailers=None, flags=0)\n\
+ -> byteswritten\n\
+Copy nbytes bytes from file descriptor in to file descriptor out.");
+
+static PyObject *
+posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
+{
+ int in, out;
+ Py_ssize_t ret;
+ off_t offset;
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
+#ifndef __APPLE__
+ Py_ssize_t len;
+#endif
+ PyObject *headers = NULL, *trailers = NULL;
+ Py_buffer *hbuf, *tbuf;
+ off_t sbytes;
+ struct sf_hdtr sf;
+ int flags = 0;
+ sf.headers = NULL;
+ sf.trailers = NULL;
+ static char *keywords[] = {"out", "in",
+ "offset", "count",
+ "headers", "trailers", "flags", NULL};
+
+#ifdef __APPLE__
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiO&O&|OOi:sendfile",
+ keywords, &out, &in, _parse_off_t, &offset, _parse_off_t, &sbytes,
+#else
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiO&n|OOi:sendfile",
+ keywords, &out, &in, _parse_off_t, &offset, &len,
+#endif
+ &headers, &trailers, &flags))
+ return NULL;
+ if (headers != NULL) {
+ if (!PySequence_Check(headers)) {
+ PyErr_SetString(PyExc_TypeError,
+ "sendfile() headers must be a sequence or None");
+ return NULL;
+ } else {
+ Py_ssize_t i = 0; /* Avoid uninitialized warning */
+ sf.hdr_cnt = PySequence_Size(headers);
+ if (sf.hdr_cnt > 0 &&
+ !(i = iov_setup(&(sf.headers), &hbuf,
+ headers, sf.hdr_cnt, PyBUF_SIMPLE)))
+ return NULL;
+#ifdef __APPLE__
+ sbytes += i;
+#endif
+ }
+ }
+ if (trailers != NULL) {
+ if (!PySequence_Check(trailers)) {
+ PyErr_SetString(PyExc_TypeError,
+ "sendfile() trailers must be a sequence or None");
+ return NULL;
+ } else {
+ Py_ssize_t i = 0; /* Avoid uninitialized warning */
+ sf.trl_cnt = PySequence_Size(trailers);
+ if (sf.trl_cnt > 0 &&
+ !(i = iov_setup(&(sf.trailers), &tbuf,
+ trailers, sf.trl_cnt, PyBUF_SIMPLE)))
+ return NULL;
+#ifdef __APPLE__
+ sbytes += i;
+#endif
+ }
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+#ifdef __APPLE__
+ ret = sendfile(in, out, offset, &sbytes, &sf, flags);
+#else
+ ret = sendfile(in, out, offset, len, &sf, &sbytes, flags);
+#endif
+ Py_END_ALLOW_THREADS
+
+ if (sf.headers != NULL)
+ iov_cleanup(sf.headers, hbuf, sf.hdr_cnt);
+ if (sf.trailers != NULL)
+ iov_cleanup(sf.trailers, tbuf, sf.trl_cnt);
+
+ if (ret < 0) {
+ if ((errno == EAGAIN) || (errno == EBUSY)) {
+ if (sbytes != 0) {
+ // some data has been sent
+ goto done;
+ }
+ else {
+ // no data has been sent; upper application is supposed
+ // to retry on EAGAIN or EBUSY
+ return posix_error();
+ }
+ }
+ return posix_error();
+ }
+ goto done;
+
+done:
+ #if !defined(HAVE_LARGEFILE_SUPPORT)
+ return Py_BuildValue("l", sbytes);
+ #else
+ return Py_BuildValue("L", sbytes);
+ #endif
+
+#else
+ Py_ssize_t count;
+ PyObject *offobj;
+ static char *keywords[] = {"out", "in",
+ "offset", "count", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiOn:sendfile",
+ keywords, &out, &in, &offobj, &count))
+ return NULL;
+#ifdef linux
+ if (offobj == Py_None) {
+ Py_BEGIN_ALLOW_THREADS
+ ret = sendfile(out, in, NULL, count);
+ Py_END_ALLOW_THREADS
+ if (ret < 0)
+ return posix_error();
+ return Py_BuildValue("n", ret);
+ }
+#endif
+ if (!_parse_off_t(offobj, &offset))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ ret = sendfile(out, in, &offset, count);
+ Py_END_ALLOW_THREADS
+ if (ret < 0)
+ return posix_error();
+ return Py_BuildValue("n", ret);
+#endif
+}
+#endif
PyDoc_STRVAR(posix_fstat__doc__,
"fstat(fd) -> stat result\n\n\
@@ -5784,9 +6519,7 @@ posix_pipe(PyObject *self, PyObject *noargs)
HFILE read, write;
APIRET rc;
- Py_BEGIN_ALLOW_THREADS
rc = DosCreatePipe( &read, &write, 4096);
- Py_END_ALLOW_THREADS
if (rc != NO_ERROR)
return os2_error(rc);
@@ -5795,9 +6528,7 @@ posix_pipe(PyObject *self, PyObject *noargs)
#if !defined(MS_WINDOWS)
int fds[2];
int res;
- Py_BEGIN_ALLOW_THREADS
res = pipe(fds);
- Py_END_ALLOW_THREADS
if (res != 0)
return posix_error();
return Py_BuildValue("(ii)", fds[0], fds[1]);
@@ -5805,9 +6536,7 @@ posix_pipe(PyObject *self, PyObject *noargs)
HANDLE read, write;
int read_fd, write_fd;
BOOL ok;
- Py_BEGIN_ALLOW_THREADS
ok = CreatePipe(&read, &write, NULL, 0);
- Py_END_ALLOW_THREADS
if (!ok)
return win32_error("CreatePipe", NULL);
read_fd = _open_osfhandle((Py_intptr_t)read, 0);
@@ -5818,6 +6547,73 @@ posix_pipe(PyObject *self, PyObject *noargs)
}
#endif /* HAVE_PIPE */
+#ifdef HAVE_WRITEV
+PyDoc_STRVAR(posix_writev__doc__,
+"writev(fd, buffers) -> byteswritten\n\n\
+Write the contents of buffers to a file descriptor, where buffers is an\n\
+arbitrary sequence of buffers.\n\
+Returns the total bytes written.");
+
+static PyObject *
+posix_writev(PyObject *self, PyObject *args)
+{
+ int fd, cnt;
+ Py_ssize_t res;
+ PyObject *seq;
+ struct iovec *iov;
+ Py_buffer *buf;
+ if (!PyArg_ParseTuple(args, "iO:writev", &fd, &seq))
+ return NULL;
+ if (!PySequence_Check(seq)) {
+ PyErr_SetString(PyExc_TypeError,
+ "writev() arg 2 must be a sequence");
+ return NULL;
+ }
+ cnt = PySequence_Size(seq);
+
+ if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ res = writev(fd, iov, cnt);
+ Py_END_ALLOW_THREADS
+
+ iov_cleanup(iov, buf, cnt);
+ return PyLong_FromSsize_t(res);
+}
+#endif
+
+#ifdef HAVE_PWRITE
+PyDoc_STRVAR(posix_pwrite__doc__,
+"pwrite(fd, string, offset) -> byteswritten\n\n\
+Write string to a file descriptor, fd, from offset, leaving the file\n\
+offset unchanged.");
+
+static PyObject *
+posix_pwrite(PyObject *self, PyObject *args)
+{
+ Py_buffer pbuf;
+ int fd;
+ off_t offset;
+ Py_ssize_t size;
+
+ if (!PyArg_ParseTuple(args, "iy*O&:pwrite", &fd, &pbuf, _parse_off_t, &offset))
+ return NULL;
+
+ if (!_PyVerify_fd(fd)) {
+ PyBuffer_Release(&pbuf);
+ return posix_error();
+ }
+ Py_BEGIN_ALLOW_THREADS
+ size = pwrite(fd, pbuf.buf, (size_t)pbuf.len, offset);
+ Py_END_ALLOW_THREADS
+ PyBuffer_Release(&pbuf);
+ if (size < 0)
+ return posix_error();
+ return PyLong_FromSsize_t(size);
+}
+#endif
#ifdef HAVE_MKFIFO
PyDoc_STRVAR(posix_mkfifo__doc__,
@@ -5934,18 +6730,8 @@ posix_ftruncate(PyObject *self, PyObject *args)
int fd;
off_t length;
int res;
- PyObject *lenobj;
- if (!PyArg_ParseTuple(args, "iO:ftruncate", &fd, &lenobj))
- return NULL;
-
-#if !defined(HAVE_LARGEFILE_SUPPORT)
- length = PyLong_AsLong(lenobj);
-#else
- length = PyLong_Check(lenobj) ?
- PyLong_AsLongLong(lenobj) : PyLong_AsLong(lenobj);
-#endif
- if (PyErr_Occurred())
+ if (!PyArg_ParseTuple(args, "iO&:ftruncate", &fd, _parse_off_t, &length))
return NULL;
Py_BEGIN_ALLOW_THREADS
@@ -5958,6 +6744,93 @@ posix_ftruncate(PyObject *self, PyObject *args)
}
#endif
+#ifdef HAVE_TRUNCATE
+PyDoc_STRVAR(posix_truncate__doc__,
+"truncate(path, length)\n\n\
+Truncate the file given by path to length bytes.");
+
+static PyObject *
+posix_truncate(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ const char *path;
+ off_t length;
+ int res;
+
+ if (!PyArg_ParseTuple(args, "O&O&:truncate",
+ PyUnicode_FSConverter, &opath, _parse_off_t, &length))
+ return NULL;
+ path = PyBytes_AsString(opath);
+
+ Py_BEGIN_ALLOW_THREADS
+ res = truncate(path, length);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_POSIX_FALLOCATE
+PyDoc_STRVAR(posix_posix_fallocate__doc__,
+"posix_fallocate(fd, offset, len)\n\n\
+Ensures that enough disk space is allocated for the file specified by fd\n\
+starting from offset and continuing for len bytes.");
+
+static PyObject *
+posix_posix_fallocate(PyObject *self, PyObject *args)
+{
+ off_t len, offset;
+ int res, fd;
+
+ if (!PyArg_ParseTuple(args, "iO&O&:posix_fallocate",
+ &fd, _parse_off_t, &offset, _parse_off_t, &len))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ res = posix_fallocate(fd, offset, len);
+ Py_END_ALLOW_THREADS
+ if (res != 0) {
+ errno = res;
+ return posix_error();
+ }
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_POSIX_FADVISE
+PyDoc_STRVAR(posix_posix_fadvise__doc__,
+"posix_fadvise(fd, offset, len, advice)\n\n\
+Announces an intention to access data in a specific pattern thus allowing\n\
+the kernel to make optimizations.\n\
+The advice applies to the region of the file specified by fd starting at\n\
+offset and continuing for len bytes.\n\
+advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL,\n\
+POSIX_FADV_RANDOM, POSIX_FADV_NOREUSE, POSIX_FADV_WILLNEED or\n\
+POSIX_FADV_DONTNEED.");
+
+static PyObject *
+posix_posix_fadvise(PyObject *self, PyObject *args)
+{
+ off_t len, offset;
+ int res, fd, advice;
+
+ if (!PyArg_ParseTuple(args, "iO&O&i:posix_fadvise",
+ &fd, _parse_off_t, &offset, _parse_off_t, &len, &advice))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ res = posix_fadvise(fd, offset, len, advice);
+ Py_END_ALLOW_THREADS
+ if (res != 0) {
+ errno = res;
+ return posix_error();
+ }
+ Py_RETURN_NONE;
+}
+#endif
+
#ifdef HAVE_PUTENV
PyDoc_STRVAR(posix_putenv__doc__,
"putenv(key, value)\n\n\
@@ -7762,6 +8635,552 @@ posix_getresgid (PyObject *self, PyObject *noargs)
}
#endif
+/* Posix *at family of functions:
+ faccessat, fchmodat, fchownat, fstatat, futimesat,
+ linkat, mkdirat, mknodat, openat, readlinkat, renameat, symlinkat,
+ unlinkat, utimensat, mkfifoat */
+
+#ifdef HAVE_FACCESSAT
+PyDoc_STRVAR(posix_faccessat__doc__,
+"faccessat(dirfd, path, mode, flags=0) -> True if granted, False otherwise\n\n\
+Like access() but if path is relative, it is taken as relative to dirfd.\n\
+flags is optional and can be constructed by ORing together zero or more\n\
+of these values: AT_SYMLINK_NOFOLLOW, AT_EACCESS.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_faccessat(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ char *path;
+ int mode;
+ int res;
+ int dirfd, flags = 0;
+ if (!PyArg_ParseTuple(args, "iO&i|i:faccessat",
+ &dirfd, PyUnicode_FSConverter, &opath, &mode, &flags))
+ return NULL;
+ path = PyBytes_AsString(opath);
+ Py_BEGIN_ALLOW_THREADS
+ res = faccessat(dirfd, path, mode, flags);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ return PyBool_FromLong(res == 0);
+}
+#endif
+
+#ifdef HAVE_FCHMODAT
+PyDoc_STRVAR(posix_fchmodat__doc__,
+"fchmodat(dirfd, path, mode, flags=0)\n\n\
+Like chmod() but if path is relative, it is taken as relative to dirfd.\n\
+flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_fchmodat(PyObject *self, PyObject *args)
+{
+ int dirfd, mode, res;
+ int flags = 0;
+ PyObject *opath;
+ char *path;
+
+ if (!PyArg_ParseTuple(args, "iO&i|i:fchmodat",
+ &dirfd, PyUnicode_FSConverter, &opath, &mode, &flags))
+ return NULL;
+
+ path = PyBytes_AsString(opath);
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fchmodat(dirfd, path, mode, flags);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif /* HAVE_FCHMODAT */
+
+#ifdef HAVE_FCHOWNAT
+PyDoc_STRVAR(posix_fchownat__doc__,
+"fchownat(dirfd, path, uid, gid, flags=0)\n\n\
+Like chown() but if path is relative, it is taken as relative to dirfd.\n\
+flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_fchownat(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ int dirfd, res;
+ long uid, gid;
+ int flags = 0;
+ char *path;
+
+ if (!PyArg_ParseTuple(args, "iO&ll|i:fchownat",
+ &dirfd, PyUnicode_FSConverter, &opath, &uid, &gid, &flags))
+ return NULL;
+
+ path = PyBytes_AsString(opath);
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fchownat(dirfd, path, (uid_t) uid, (gid_t) gid, flags);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif /* HAVE_FCHOWNAT */
+
+#ifdef HAVE_FSTATAT
+PyDoc_STRVAR(posix_fstatat__doc__,
+"fstatat(dirfd, path, flags=0) -> stat result\n\n\
+Like stat() but if path is relative, it is taken as relative to dirfd.\n\
+flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_fstatat(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ char *path;
+ STRUCT_STAT st;
+ int dirfd, res, flags = 0;
+
+ if (!PyArg_ParseTuple(args, "iO&|i:fstatat",
+ &dirfd, PyUnicode_FSConverter, &opath, &flags))
+ return NULL;
+ path = PyBytes_AsString(opath);
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fstatat(dirfd, path, &st, flags);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (res != 0)
+ return posix_error();
+
+ return _pystat_fromstructstat(&st);
+}
+#endif
+
+#ifdef HAVE_FUTIMESAT
+PyDoc_STRVAR(posix_futimesat__doc__,
+"futimesat(dirfd, path, (atime, mtime))\n\
+futimesat(dirfd, path, None)\n\n\
+Like utime() but if path is relative, it is taken as relative to dirfd.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_futimesat(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ char *path;
+ int res, dirfd;
+ PyObject* arg;
+
+ struct timeval buf[2];
+
+ if (!PyArg_ParseTuple(args, "iO&O:futimesat",
+ &dirfd, PyUnicode_FSConverter, &opath, &arg))
+ return NULL;
+ path = PyBytes_AsString(opath);
+ if (arg == Py_None) {
+ /* optional time values not given */
+ Py_BEGIN_ALLOW_THREADS
+ res = futimesat(dirfd, path, NULL);
+ Py_END_ALLOW_THREADS
+ }
+ else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "futimesat() arg 3 must be a tuple (atime, mtime)");
+ Py_DECREF(opath);
+ return NULL;
+ }
+ else {
+ if (extract_time(PyTuple_GET_ITEM(arg, 0),
+ &(buf[0].tv_sec), &(buf[0].tv_usec)) == -1) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+ if (extract_time(PyTuple_GET_ITEM(arg, 1),
+ &(buf[1].tv_sec), &(buf[1].tv_usec)) == -1) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS
+ res = futimesat(dirfd, path, buf);
+ Py_END_ALLOW_THREADS
+ }
+ Py_DECREF(opath);
+ if (res < 0) {
+ return posix_error();
+ }
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_LINKAT
+PyDoc_STRVAR(posix_linkat__doc__,
+"linkat(srcfd, srcpath, dstfd, dstpath, flags=0)\n\n\
+Like link() but if srcpath is relative, it is taken as relative to srcfd\n\
+and if dstpath is relative, it is taken as relative to dstfd.\n\
+flags is optional and may be 0 or AT_SYMLINK_FOLLOW.\n\
+If srcpath is relative and srcfd is the special value AT_FDCWD, then\n\
+srcpath is interpreted relative to the current working directory. This\n\
+also applies for dstpath.");
+
+static PyObject *
+posix_linkat(PyObject *self, PyObject *args)
+{
+ PyObject *osrc, *odst;
+ char *src, *dst;
+ int res, srcfd, dstfd;
+ int flags = 0;
+
+ if (!PyArg_ParseTuple(args, "iO&iO&|i:linkat",
+ &srcfd, PyUnicode_FSConverter, &osrc, &dstfd, PyUnicode_FSConverter, &odst, &flags))
+ return NULL;
+ src = PyBytes_AsString(osrc);
+ dst = PyBytes_AsString(odst);
+ Py_BEGIN_ALLOW_THREADS
+ res = linkat(srcfd, src, dstfd, dst, flags);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(osrc);
+ Py_DECREF(odst);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif /* HAVE_LINKAT */
+
+#ifdef HAVE_MKDIRAT
+PyDoc_STRVAR(posix_mkdirat__doc__,
+"mkdirat(dirfd, path, mode=0o777)\n\n\
+Like mkdir() but if path is relative, it is taken as relative to dirfd.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_mkdirat(PyObject *self, PyObject *args)
+{
+ int res, dirfd;
+ PyObject *opath;
+ char *path;
+ int mode = 0777;
+
+ if (!PyArg_ParseTuple(args, "iO&|i:mkdirat",
+ &dirfd, PyUnicode_FSConverter, &opath, &mode))
+ return NULL;
+ path = PyBytes_AsString(opath);
+ Py_BEGIN_ALLOW_THREADS
+ res = mkdirat(dirfd, path, mode);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#if defined(HAVE_MKNODAT) && defined(HAVE_MAKEDEV)
+PyDoc_STRVAR(posix_mknodat__doc__,
+"mknodat(dirfd, path, mode=0o600, device=0)\n\n\
+Like mknod() but if path is relative, it is taken as relative to dirfd.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_mknodat(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ char *filename;
+ int mode = 0600;
+ int device = 0;
+ int res, dirfd;
+ if (!PyArg_ParseTuple(args, "iO&|ii:mknodat", &dirfd,
+ PyUnicode_FSConverter, &opath, &mode, &device))
+ return NULL;
+ filename = PyBytes_AS_STRING(opath);
+ Py_BEGIN_ALLOW_THREADS
+ res = mknodat(dirfd, filename, mode, device);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_OPENAT
+PyDoc_STRVAR(posix_openat__doc__,
+"openat(dirfd, path, flag, mode=0o777) -> fd\n\n\
+Like open() but if path is relative, it is taken as relative to dirfd.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_openat(PyObject *self, PyObject *args)
+{
+ PyObject *ofile;
+ char *file;
+ int flag, dirfd, fd;
+ int mode = 0777;
+
+ if (!PyArg_ParseTuple(args, "iO&i|i:openat",
+ &dirfd, PyUnicode_FSConverter, &ofile,
+ &flag, &mode))
+ return NULL;
+ file = PyBytes_AsString(ofile);
+ Py_BEGIN_ALLOW_THREADS
+ fd = openat(dirfd, file, flag, mode);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(ofile);
+ if (fd < 0)
+ return posix_error();
+ return PyLong_FromLong((long)fd);
+}
+#endif
+
+#ifdef HAVE_READLINKAT
+PyDoc_STRVAR(posix_readlinkat__doc__,
+"readlinkat(dirfd, path) -> path\n\n\
+Like readlink() but if path is relative, it is taken as relative to dirfd.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_readlinkat(PyObject *self, PyObject *args)
+{
+ PyObject *v, *opath;
+ char buf[MAXPATHLEN];
+ char *path;
+ int n, dirfd;
+ int arg_is_unicode = 0;
+
+ if (!PyArg_ParseTuple(args, "iO&:readlinkat",
+ &dirfd, PyUnicode_FSConverter, &opath))
+ return NULL;
+ path = PyBytes_AsString(opath);
+ v = PySequence_GetItem(args, 1);
+ if (v == NULL) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+
+ if (PyUnicode_Check(v)) {
+ arg_is_unicode = 1;
+ }
+ Py_DECREF(v);
+
+ Py_BEGIN_ALLOW_THREADS
+ n = readlinkat(dirfd, path, buf, (int) sizeof buf);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (n < 0)
+ return posix_error();
+
+ if (arg_is_unicode)
+ return PyUnicode_DecodeFSDefaultAndSize(buf, n);
+ else
+ return PyBytes_FromStringAndSize(buf, n);
+}
+#endif /* HAVE_READLINKAT */
+
+#ifdef HAVE_RENAMEAT
+PyDoc_STRVAR(posix_renameat__doc__,
+"renameat(olddirfd, oldpath, newdirfd, newpath)\n\n\
+Like rename() but if oldpath is relative, it is taken as relative to\n\
+olddirfd and if newpath is relative, it is taken as relative to newdirfd.\n\
+If oldpath is relative and olddirfd is the special value AT_FDCWD, then\n\
+oldpath is interpreted relative to the current working directory. This\n\
+also applies for newpath.");
+
+static PyObject *
+posix_renameat(PyObject *self, PyObject *args)
+{
+ int res;
+ PyObject *opathold, *opathnew;
+ char *opath, *npath;
+ int oldfd, newfd;
+
+ if (!PyArg_ParseTuple(args, "iO&iO&:renameat",
+ &oldfd, PyUnicode_FSConverter, &opathold, &newfd, PyUnicode_FSConverter, &opathnew))
+ return NULL;
+ opath = PyBytes_AsString(opathold);
+ npath = PyBytes_AsString(opathnew);
+ Py_BEGIN_ALLOW_THREADS
+ res = renameat(oldfd, opath, newfd, npath);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opathold);
+ Py_DECREF(opathnew);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#if HAVE_SYMLINKAT
+PyDoc_STRVAR(posix_symlinkat__doc__,
+"symlinkat(src, dstfd, dst)\n\n\
+Like symlink() but if dst is relative, it is taken as relative to dstfd.\n\
+If dst is relative and dstfd is the special value AT_FDCWD, then dst\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_symlinkat(PyObject *self, PyObject *args)
+{
+ int res, dstfd;
+ PyObject *osrc, *odst;
+ char *src, *dst;
+
+ if (!PyArg_ParseTuple(args, "O&iO&:symlinkat",
+ PyUnicode_FSConverter, &osrc, &dstfd, PyUnicode_FSConverter, &odst))
+ return NULL;
+ src = PyBytes_AsString(osrc);
+ dst = PyBytes_AsString(odst);
+ Py_BEGIN_ALLOW_THREADS
+ res = symlinkat(src, dstfd, dst);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(osrc);
+ Py_DECREF(odst);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif /* HAVE_SYMLINKAT */
+
+#ifdef HAVE_UNLINKAT
+PyDoc_STRVAR(posix_unlinkat__doc__,
+"unlinkat(dirfd, path, flags=0)\n\n\
+Like unlink() but if path is relative, it is taken as relative to dirfd.\n\
+flags is optional and may be 0 or AT_REMOVEDIR. If AT_REMOVEDIR is\n\
+specified, unlinkat() behaves like rmdir().\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_unlinkat(PyObject *self, PyObject *args)
+{
+ int dirfd, res, flags = 0;
+ PyObject *opath;
+ char *path;
+
+ if (!PyArg_ParseTuple(args, "iO&|i:unlinkat",
+ &dirfd, PyUnicode_FSConverter, &opath, &flags))
+ return NULL;
+ path = PyBytes_AsString(opath);
+ Py_BEGIN_ALLOW_THREADS
+ res = unlinkat(dirfd, path, flags);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_UTIMENSAT
+PyDoc_STRVAR(posix_utimensat__doc__,
+"utimensat(dirfd, path, (atime_sec, atime_nsec),\n\
+ (mtime_sec, mtime_nsec), flags)\n\
+utimensat(dirfd, path, None, None, flags)\n\n\
+Updates the timestamps of a file with nanosecond precision. If path is\n\
+relative, it is taken as relative to dirfd.\n\
+The second form sets atime and mtime to the current time.\n\
+flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.\n\
+If *_nsec is specified as UTIME_NOW, the timestamp is updated to the\n\
+current time.\n\
+If *_nsec is specified as UTIME_OMIT, the timestamp is not updated.");
+
+static PyObject *
+posix_utimensat(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ char *path;
+ int res, dirfd, flags = 0;
+ PyObject *atime, *mtime;
+
+ struct timespec buf[2];
+
+ if (!PyArg_ParseTuple(args, "iO&OO|i:utimensat",
+ &dirfd, PyUnicode_FSConverter, &opath, &atime, &mtime, &flags))
+ return NULL;
+ path = PyBytes_AsString(opath);
+ if (atime == Py_None && mtime == Py_None) {
+ /* optional time values not given */
+ Py_BEGIN_ALLOW_THREADS
+ res = utimensat(dirfd, path, NULL, flags);
+ Py_END_ALLOW_THREADS
+ }
+ else if (!PyTuple_Check(atime) || PyTuple_Size(atime) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "utimensat() arg 3 must be a tuple (atime_sec, atime_nsec)");
+ Py_DECREF(opath);
+ return NULL;
+ }
+ else if (!PyTuple_Check(mtime) || PyTuple_Size(mtime) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "utimensat() arg 4 must be a tuple (mtime_sec, mtime_nsec)");
+ Py_DECREF(opath);
+ return NULL;
+ }
+ else {
+ if (!PyArg_ParseTuple(atime, "ll:utimensat",
+ &(buf[0].tv_sec), &(buf[0].tv_nsec))) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+ if (!PyArg_ParseTuple(mtime, "ll:utimensat",
+ &(buf[1].tv_sec), &(buf[1].tv_nsec))) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS
+ res = utimensat(dirfd, path, buf, flags);
+ Py_END_ALLOW_THREADS
+ }
+ Py_DECREF(opath);
+ if (res < 0) {
+ return posix_error();
+ }
+ Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_MKFIFOAT
+PyDoc_STRVAR(posix_mkfifoat__doc__,
+"mkfifoat(dirfd, path, mode=0o666)\n\n\
+Like mkfifo() but if path is relative, it is taken as relative to dirfd.\n\
+If path is relative and dirfd is the special value AT_FDCWD, then path\n\
+is interpreted relative to the current working directory.");
+
+static PyObject *
+posix_mkfifoat(PyObject *self, PyObject *args)
+{
+ PyObject *opath;
+ char *filename;
+ int mode = 0666;
+ int res, dirfd;
+ if (!PyArg_ParseTuple(args, "iO&|i:mkfifoat",
+ &dirfd, PyUnicode_FSConverter, &opath, &mode))
+ return NULL;
+ filename = PyBytes_AS_STRING(opath);
+ Py_BEGIN_ALLOW_THREADS
+ res = mkfifoat(dirfd, filename, mode);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(opath);
+ if (res < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
static PyMethodDef posix_methods[] = {
{"access", posix_access, METH_VARARGS, posix_access__doc__},
#ifdef HAVE_TTYNAME
@@ -7806,11 +9225,20 @@ static PyMethodDef posix_methods[] = {
{"link", posix_link, METH_VARARGS, posix_link__doc__},
#endif /* HAVE_LINK */
{"listdir", posix_listdir, METH_VARARGS, posix_listdir__doc__},
+#ifdef HAVE_FDOPENDIR
+ {"fdlistdir", posix_fdlistdir, METH_VARARGS, posix_fdlistdir__doc__},
+#endif
{"lstat", posix_lstat, METH_VARARGS, posix_lstat__doc__},
{"mkdir", posix_mkdir, METH_VARARGS, posix_mkdir__doc__},
#ifdef HAVE_NICE
{"nice", posix_nice, METH_VARARGS, posix_nice__doc__},
#endif /* HAVE_NICE */
+#ifdef HAVE_GETPRIORITY
+ {"getpriority", posix_getpriority, METH_VARARGS, posix_getpriority__doc__},
+#endif /* HAVE_GETPRIORITY */
+#ifdef HAVE_SETPRIORITY
+ {"setpriority", posix_setpriority, METH_VARARGS, posix_setpriority__doc__},
+#endif /* HAVE_SETPRIORITY */
#ifdef HAVE_READLINK
{"readlink", posix_readlink, METH_VARARGS, posix_readlink__doc__},
#endif /* HAVE_READLINK */
@@ -7838,6 +9266,15 @@ static PyMethodDef posix_methods[] = {
{"unlink", posix_unlink, METH_VARARGS, posix_unlink__doc__},
{"remove", posix_unlink, METH_VARARGS, posix_remove__doc__},
{"utime", posix_utime, METH_VARARGS, posix_utime__doc__},
+#ifdef HAVE_FUTIMES
+ {"futimes", posix_futimes, METH_VARARGS, posix_futimes__doc__},
+#endif
+#ifdef HAVE_LUTIMES
+ {"lutimes", posix_lutimes, METH_VARARGS, posix_lutimes__doc__},
+#endif
+#ifdef HAVE_FUTIMENS
+ {"futimens", posix_futimens, METH_VARARGS, posix_futimens__doc__},
+#endif
#ifdef HAVE_TIMES
{"times", posix_times, METH_NOARGS, posix_times__doc__},
#endif /* HAVE_TIMES */
@@ -7846,6 +9283,9 @@ static PyMethodDef posix_methods[] = {
{"execv", posix_execv, METH_VARARGS, posix_execv__doc__},
{"execve", posix_execve, METH_VARARGS, posix_execve__doc__},
#endif /* HAVE_EXECV */
+#ifdef HAVE_FEXECVE
+ {"fexecve", posix_fexecve, METH_VARARGS, posix_fexecve__doc__},
+#endif
#ifdef HAVE_SPAWNV
{"spawnv", posix_spawnv, METH_VARARGS, posix_spawnv__doc__},
{"spawnve", posix_spawnve, METH_VARARGS, posix_spawnve__doc__},
@@ -7944,6 +9384,9 @@ static PyMethodDef posix_methods[] = {
#ifdef HAVE_WAIT4
{"wait4", posix_wait4, METH_VARARGS, posix_wait4__doc__},
#endif /* HAVE_WAIT4 */
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+ {"waitid", posix_waitid, METH_VARARGS, posix_waitid__doc__},
+#endif
#if defined(HAVE_WAITPID) || defined(HAVE_CWAIT)
{"waitpid", posix_waitpid, METH_VARARGS, posix_waitpid__doc__},
#endif /* HAVE_WAITPID */
@@ -7968,9 +9411,28 @@ static PyMethodDef posix_methods[] = {
{"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__},
{"dup", posix_dup, METH_VARARGS, posix_dup__doc__},
{"dup2", posix_dup2, METH_VARARGS, posix_dup2__doc__},
+#ifdef HAVE_LOCKF
+ {"lockf", posix_lockf, METH_VARARGS, posix_lockf__doc__},
+#endif
{"lseek", posix_lseek, METH_VARARGS, posix_lseek__doc__},
{"read", posix_read, METH_VARARGS, posix_read__doc__},
+#ifdef HAVE_READV
+ {"readv", posix_readv, METH_VARARGS, posix_readv__doc__},
+#endif
+#ifdef HAVE_PREAD
+ {"pread", posix_pread, METH_VARARGS, posix_pread__doc__},
+#endif
{"write", posix_write, METH_VARARGS, posix_write__doc__},
+#ifdef HAVE_WRITEV
+ {"writev", posix_writev, METH_VARARGS, posix_writev__doc__},
+#endif
+#ifdef HAVE_PWRITE
+ {"pwrite", posix_pwrite, METH_VARARGS, posix_pwrite__doc__},
+#endif
+#ifdef HAVE_SENDFILE
+ {"sendfile", (PyCFunction)posix_sendfile, METH_VARARGS | METH_KEYWORDS,
+ posix_sendfile__doc__},
+#endif
{"fstat", posix_fstat, METH_VARARGS, posix_fstat__doc__},
{"isatty", posix_isatty, METH_VARARGS, posix_isatty__doc__},
#ifdef HAVE_PIPE
@@ -7990,6 +9452,15 @@ static PyMethodDef posix_methods[] = {
#ifdef HAVE_FTRUNCATE
{"ftruncate", posix_ftruncate, METH_VARARGS, posix_ftruncate__doc__},
#endif
+#ifdef HAVE_TRUNCATE
+ {"truncate", posix_truncate, METH_VARARGS, posix_truncate__doc__},
+#endif
+#ifdef HAVE_POSIX_FALLOCATE
+ {"posix_fallocate", posix_posix_fallocate, METH_VARARGS, posix_posix_fallocate__doc__},
+#endif
+#ifdef HAVE_POSIX_FADVISE
+ {"posix_fadvise", posix_posix_fadvise, METH_VARARGS, posix_posix_fadvise__doc__},
+#endif
#ifdef HAVE_PUTENV
{"putenv", posix_putenv, METH_VARARGS, posix_putenv__doc__},
#endif
@@ -8003,6 +9474,9 @@ static PyMethodDef posix_methods[] = {
#ifdef HAVE_FSYNC
{"fsync", posix_fsync, METH_O, posix_fsync__doc__},
#endif
+#ifdef HAVE_SYNC
+ {"sync", posix_sync, METH_NOARGS, posix_sync__doc__},
+#endif
#ifdef HAVE_FDATASYNC
{"fdatasync", posix_fdatasync, METH_O, posix_fdatasync__doc__},
#endif
@@ -8078,6 +9552,52 @@ static PyMethodDef posix_methods[] = {
{"getresgid", posix_getresgid, METH_NOARGS, posix_getresgid__doc__},
#endif
+/* posix *at family of functions */
+#ifdef HAVE_FACCESSAT
+ {"faccessat", posix_faccessat, METH_VARARGS, posix_faccessat__doc__},
+#endif
+#ifdef HAVE_FCHMODAT
+ {"fchmodat", posix_fchmodat, METH_VARARGS, posix_fchmodat__doc__},
+#endif /* HAVE_FCHMODAT */
+#ifdef HAVE_FCHOWNAT
+ {"fchownat", posix_fchownat, METH_VARARGS, posix_fchownat__doc__},
+#endif /* HAVE_FCHOWNAT */
+#ifdef HAVE_FSTATAT
+ {"fstatat", posix_fstatat, METH_VARARGS, posix_fstatat__doc__},
+#endif
+#ifdef HAVE_FUTIMESAT
+ {"futimesat", posix_futimesat, METH_VARARGS, posix_futimesat__doc__},
+#endif
+#ifdef HAVE_LINKAT
+ {"linkat", posix_linkat, METH_VARARGS, posix_linkat__doc__},
+#endif /* HAVE_LINKAT */
+#ifdef HAVE_MKDIRAT
+ {"mkdirat", posix_mkdirat, METH_VARARGS, posix_mkdirat__doc__},
+#endif
+#if defined(HAVE_MKNODAT) && defined(HAVE_MAKEDEV)
+ {"mknodat", posix_mknodat, METH_VARARGS, posix_mknodat__doc__},
+#endif
+#ifdef HAVE_OPENAT
+ {"openat", posix_openat, METH_VARARGS, posix_openat__doc__},
+#endif
+#ifdef HAVE_READLINKAT
+ {"readlinkat", posix_readlinkat, METH_VARARGS, posix_readlinkat__doc__},
+#endif /* HAVE_READLINKAT */
+#ifdef HAVE_RENAMEAT
+ {"renameat", posix_renameat, METH_VARARGS, posix_renameat__doc__},
+#endif
+#if HAVE_SYMLINKAT
+ {"symlinkat", posix_symlinkat, METH_VARARGS, posix_symlinkat__doc__},
+#endif /* HAVE_SYMLINKAT */
+#ifdef HAVE_UNLINKAT
+ {"unlinkat", posix_unlinkat, METH_VARARGS, posix_unlinkat__doc__},
+#endif
+#ifdef HAVE_UTIMENSAT
+ {"utimensat", posix_utimensat, METH_VARARGS, posix_utimensat__doc__},
+#endif
+#ifdef HAVE_MKFIFOAT
+ {"mkfifoat", posix_mkfifoat, METH_VARARGS, posix_mkfifoat__doc__},
+#endif
{NULL, NULL} /* Sentinel */
};
@@ -8254,6 +9774,38 @@ all_ins(PyObject *d)
#ifdef O_EXLOCK
if (ins(d, "O_EXLOCK", (long)O_EXLOCK)) return -1;
#endif
+#ifdef PRIO_PROCESS
+ if (ins(d, "PRIO_PROCESS", (long)PRIO_PROCESS)) return -1;
+#endif
+#ifdef PRIO_PGRP
+ if (ins(d, "PRIO_PGRP", (long)PRIO_PGRP)) return -1;
+#endif
+#ifdef PRIO_USER
+ if (ins(d, "PRIO_USER", (long)PRIO_USER)) return -1;
+#endif
+/* posix - constants for *at functions */
+#ifdef AT_SYMLINK_NOFOLLOW
+ if (ins(d, "AT_SYMLINK_NOFOLLOW", (long)AT_SYMLINK_NOFOLLOW)) return -1;
+#endif
+#ifdef AT_EACCESS
+ if (ins(d, "AT_EACCESS", (long)AT_EACCESS)) return -1;
+#endif
+#ifdef AT_FDCWD
+ if (ins(d, "AT_FDCWD", (long)AT_FDCWD)) return -1;
+#endif
+#ifdef AT_REMOVEDIR
+ if (ins(d, "AT_REMOVEDIR", (long)AT_REMOVEDIR)) return -1;
+#endif
+#ifdef AT_SYMLINK_FOLLOW
+ if (ins(d, "AT_SYMLINK_FOLLOW", (long)AT_SYMLINK_FOLLOW)) return -1;
+#endif
+#ifdef UTIME_NOW
+ if (ins(d, "UTIME_NOW", (long)UTIME_NOW)) return -1;
+#endif
+#ifdef UTIME_OMIT
+ if (ins(d, "UTIME_OMIT", (long)UTIME_OMIT)) return -1;
+#endif
+
/* MS Windows */
#ifdef O_NOINHERIT
@@ -8362,6 +9914,87 @@ all_ins(PyObject *d)
if (ins(d, "ST_NOSUID", (long)ST_NOSUID)) return -1;
#endif /* ST_NOSUID */
+ /* FreeBSD sendfile() constants */
+#ifdef SF_NODISKIO
+ if (ins(d, "SF_NODISKIO", (long)SF_NODISKIO)) return -1;
+#endif
+#ifdef SF_MNOWAIT
+ if (ins(d, "SF_MNOWAIT", (long)SF_MNOWAIT)) return -1;
+#endif
+#ifdef SF_SYNC
+ if (ins(d, "SF_SYNC", (long)SF_SYNC)) return -1;
+#endif
+
+ /* constants for posix_fadvise */
+#ifdef POSIX_FADV_NORMAL
+ if (ins(d, "POSIX_FADV_NORMAL", (long)POSIX_FADV_NORMAL)) return -1;
+#endif
+#ifdef POSIX_FADV_SEQUENTIAL
+ if (ins(d, "POSIX_FADV_SEQUENTIAL", (long)POSIX_FADV_SEQUENTIAL)) return -1;
+#endif
+#ifdef POSIX_FADV_RANDOM
+ if (ins(d, "POSIX_FADV_RANDOM", (long)POSIX_FADV_RANDOM)) return -1;
+#endif
+#ifdef POSIX_FADV_NOREUSE
+ if (ins(d, "POSIX_FADV_NOREUSE", (long)POSIX_FADV_NOREUSE)) return -1;
+#endif
+#ifdef POSIX_FADV_WILLNEED
+ if (ins(d, "POSIX_FADV_WILLNEED", (long)POSIX_FADV_WILLNEED)) return -1;
+#endif
+#ifdef POSIX_FADV_DONTNEED
+ if (ins(d, "POSIX_FADV_DONTNEED", (long)POSIX_FADV_DONTNEED)) return -1;
+#endif
+
+ /* constants for waitid */
+#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_WAITID)
+ if (ins(d, "P_PID", (long)P_PID)) return -1;
+ if (ins(d, "P_PGID", (long)P_PGID)) return -1;
+ if (ins(d, "P_ALL", (long)P_ALL)) return -1;
+#endif
+#ifdef WEXITED
+ if (ins(d, "WEXITED", (long)WEXITED)) return -1;
+#endif
+#ifdef WNOWAIT
+ if (ins(d, "WNOWAIT", (long)WNOWAIT)) return -1;
+#endif
+#ifdef WSTOPPED
+ if (ins(d, "WSTOPPED", (long)WSTOPPED)) return -1;
+#endif
+#ifdef CLD_EXITED
+ if (ins(d, "CLD_EXITED", (long)CLD_EXITED)) return -1;
+#endif
+#ifdef CLD_DUMPED
+ if (ins(d, "CLD_DUMPED", (long)CLD_DUMPED)) return -1;
+#endif
+#ifdef CLD_TRAPPED
+ if (ins(d, "CLD_TRAPPED", (long)CLD_TRAPPED)) return -1;
+#endif
+#ifdef CLD_CONTINUED
+ if (ins(d, "CLD_CONTINUED", (long)CLD_CONTINUED)) return -1;
+#endif
+
+ /* constants for lockf */
+#ifdef F_LOCK
+ if (ins(d, "F_LOCK", (long)F_LOCK)) return -1;
+#endif
+#ifdef F_TLOCK
+ if (ins(d, "F_TLOCK", (long)F_TLOCK)) return -1;
+#endif
+#ifdef F_ULOCK
+ if (ins(d, "F_ULOCK", (long)F_ULOCK)) return -1;
+#endif
+#ifdef F_TEST
+ if (ins(d, "F_TEST", (long)F_TEST)) return -1;
+#endif
+
+ /* constants for futimens */
+#ifdef UTIME_NOW
+ if (ins(d, "UTIME_NOW", (long)UTIME_NOW)) return -1;
+#endif
+#ifdef UTIME_OMIT
+ if (ins(d, "UTIME_OMIT", (long)UTIME_OMIT)) return -1;
+#endif
+
#ifdef HAVE_SPAWNV
#if defined(PYOS_OS2) && defined(PYCC_GCC)
if (ins(d, "P_WAIT", (long)P_WAIT)) return -1;
@@ -8461,6 +10094,11 @@ INITFUNC(void)
#endif
if (!initialized) {
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+ waitid_result_desc.name = MODNAME ".waitid_result";
+ PyStructSequence_InitType(&WaitidResultType, &waitid_result_desc);
+#endif
+
stat_result_desc.name = MODNAME ".stat_result";
stat_result_desc.fields[7].name = PyStructSequence_UnnamedField;
stat_result_desc.fields[8].name = PyStructSequence_UnnamedField;
@@ -8481,6 +10119,10 @@ INITFUNC(void)
# endif
#endif
}
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+ Py_INCREF((PyObject*) &WaitidResultType);
+ PyModule_AddObject(m, "waitid_result", (PyObject*) &WaitidResultType);
+#endif
Py_INCREF((PyObject*) &StatResultType);
PyModule_AddObject(m, "stat_result", (PyObject*) &StatResultType);
Py_INCREF((PyObject*) &StatVFSResultType);
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index 40d93246fc..4ef09de1ba 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -100,16 +100,17 @@ static PyObject *
set_error(xmlparseobject *self, enum XML_Error code)
{
PyObject *err;
- char buffer[256];
+ PyObject *buffer;
XML_Parser parser = self->itself;
int lineno = XML_GetErrorLineNumber(parser);
int column = XML_GetErrorColumnNumber(parser);
- /* There is no risk of overflowing this buffer, since
- even for 64-bit integers, there is sufficient space. */
- sprintf(buffer, "%.200s: line %i, column %i",
- XML_ErrorString(code), lineno, column);
- err = PyObject_CallFunction(ErrorObject, "s", buffer);
+ buffer = PyUnicode_FromFormat("%s: line %i, column %i",
+ XML_ErrorString(code), lineno, column);
+ if (buffer == NULL)
+ return NULL;
+ err = PyObject_CallFunction(ErrorObject, "O", buffer);
+ Py_DECREF(buffer);
if ( err != NULL
&& set_error_attr(err, "code", code)
&& set_error_attr(err, "offset", column)
diff --git a/Modules/readline.c b/Modules/readline.c
index 8337956648..a5e48ab70c 100644
--- a/Modules/readline.c
+++ b/Modules/readline.c
@@ -233,10 +233,9 @@ set_hook(const char *funcname, PyObject **hook_var, PyObject *args)
Py_XDECREF(tmp);
}
else {
- PyOS_snprintf(buf, sizeof(buf),
- "set_%.50s(func): argument not callable",
- funcname);
- PyErr_SetString(PyExc_TypeError, buf);
+ PyErr_Format(PyExc_TypeError,
+ "set_%.50s(func): argument not callable",
+ funcname);
return NULL;
}
Py_RETURN_NONE;
@@ -890,7 +889,7 @@ setup_readline(void)
#endif
#ifdef __APPLE__
- /* the libedit readline emulation resets key bindings etc
+ /* the libedit readline emulation resets key bindings etc
* when calling rl_initialize. So call it upfront
*/
if (using_libedit_emulation)
@@ -930,11 +929,11 @@ setup_readline(void)
*/
#ifdef __APPLE__
if (using_libedit_emulation)
- rl_read_init_file(NULL);
+ rl_read_init_file(NULL);
else
#endif /* __APPLE__ */
rl_initialize();
-
+
RESTORE_LOCALE(saved_locale)
}
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index 65e1826eba..5aa67ddffa 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -234,6 +234,11 @@ select_select(PyObject *self, PyObject *args)
"timeout period too long");
return NULL;
}
+ if (timeout < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "timeout must be non-negative");
+ return NULL;
+ }
seconds = (long)timeout;
timeout = timeout - (double)seconds;
tv.tv_sec = seconds;
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 00a83b497c..305261cb01 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -22,6 +22,14 @@
#include <sys/time.h>
#endif
+#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
+# define PYPTHREAD_SIGMASK
+#endif
+
+#if defined(PYPTHREAD_SIGMASK) && defined(HAVE_PTHREAD_H)
+# include <pthread.h>
+#endif
+
#ifndef SIG_ERR
#define SIG_ERR ((PyOS_sighandler_t)(-1))
#endif
@@ -495,6 +503,110 @@ PyDoc_STRVAR(getitimer_doc,
Returns current value of given itimer.");
#endif
+#ifdef PYPTHREAD_SIGMASK
+/* Convert an iterable to a sigset.
+ Return 0 on success, return -1 and raise an exception on error. */
+
+static int
+iterable_to_sigset(PyObject *iterable, sigset_t *mask)
+{
+ int result = -1;
+ PyObject *iterator, *item;
+ long signum;
+ int err;
+
+ sigemptyset(mask);
+
+ iterator = PyObject_GetIter(iterable);
+ if (iterator == NULL)
+ goto error;
+
+ while (1)
+ {
+ item = PyIter_Next(iterator);
+ if (item == NULL) {
+ if (PyErr_Occurred())
+ goto error;
+ else
+ break;
+ }
+
+ signum = PyLong_AsLong(item);
+ Py_DECREF(item);
+ if (signum == -1 && PyErr_Occurred())
+ goto error;
+ if (0 < signum && signum < NSIG)
+ err = sigaddset(mask, (int)signum);
+ else
+ err = 1;
+ if (err) {
+ PyErr_Format(PyExc_ValueError,
+ "signal number %ld out of range", signum);
+ goto error;
+ }
+ }
+ result = 0;
+
+error:
+ Py_XDECREF(iterator);
+ return result;
+}
+
+static PyObject *
+signal_pthread_sigmask(PyObject *self, PyObject *args)
+{
+ int how, sig;
+ PyObject *signals, *result, *signum;
+ sigset_t mask, previous;
+ int err;
+
+ if (!PyArg_ParseTuple(args, "iO:pthread_sigmask", &how, &signals))
+ return NULL;
+
+ if (iterable_to_sigset(signals, &mask))
+ return NULL;
+
+ err = pthread_sigmask(how, &mask, &previous);
+ if (err != 0) {
+ errno = err;
+ PyErr_SetFromErrno(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ result = PyList_New(0);
+ if (result == NULL)
+ return NULL;
+
+ for (sig = 1; sig < NSIG; sig++) {
+ if (sigismember(&previous, sig) != 1)
+ continue;
+
+ /* Handle the case where it is a member by adding the signal to
+ the result list. Ignore the other cases because they mean the
+ signal isn't a member of the mask or the signal was invalid,
+ and an invalid signal must have been our fault in constructing
+ the loop boundaries. */
+ signum = PyLong_FromLong(sig);
+ if (signum == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ if (PyList_Append(result, signum) == -1) {
+ Py_DECREF(signum);
+ Py_DECREF(result);
+ return NULL;
+ }
+ Py_DECREF(signum);
+ }
+ return result;
+}
+
+PyDoc_STRVAR(signal_pthread_sigmask_doc,
+"pthread_sigmask(how, mask) -> old mask\n\
+\n\
+Fetch and/or change the signal mask of the calling thread.");
+#endif /* #ifdef PYPTHREAD_SIGMASK */
+
/* List of functions defined in the module */
static PyMethodDef signal_methods[] = {
@@ -515,10 +627,14 @@ static PyMethodDef signal_methods[] = {
#endif
#ifdef HAVE_PAUSE
{"pause", (PyCFunction)signal_pause,
- METH_NOARGS,pause_doc},
+ METH_NOARGS, pause_doc},
#endif
{"default_int_handler", signal_default_int_handler,
METH_VARARGS, default_int_handler_doc},
+#ifdef PYPTHREAD_SIGMASK
+ {"pthread_sigmask", (PyCFunction)signal_pthread_sigmask,
+ METH_VARARGS, signal_pthread_sigmask_doc},
+#endif
{NULL, NULL} /* sentinel */
};
@@ -603,6 +719,27 @@ PyInit_signal(void)
goto finally;
Py_DECREF(x);
+#ifdef SIG_BLOCK
+ x = PyLong_FromLong(SIG_BLOCK);
+ if (!x || PyDict_SetItemString(d, "SIG_BLOCK", x) < 0)
+ goto finally;
+ Py_DECREF(x);
+#endif
+
+#ifdef SIG_UNBLOCK
+ x = PyLong_FromLong(SIG_UNBLOCK);
+ if (!x || PyDict_SetItemString(d, "SIG_UNBLOCK", x) < 0)
+ goto finally;
+ Py_DECREF(x);
+#endif
+
+#ifdef SIG_SETMASK
+ x = PyLong_FromLong(SIG_SETMASK);
+ if (!x || PyDict_SetItemString(d, "SIG_SETMASK", x) < 0)
+ goto finally;
+ Py_DECREF(x);
+#endif
+
x = IntHandler = PyDict_GetItemString(d, "default_int_handler");
if (!x)
goto finally;
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index e2fdb5e12e..1631363739 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -155,7 +155,7 @@ shutdown(how) -- shut down traffic in one or both directions\n\
#endif
#ifdef HAVE_GETHOSTBYNAME_R
-# if defined(_AIX) || defined(__osf__)
+# if defined(_AIX)
# define HAVE_GETHOSTBYNAME_R_3_ARG
# elif defined(__sun) || defined(__sgi)
# define HAVE_GETHOSTBYNAME_R_5_ARG
@@ -3146,6 +3146,37 @@ PyDoc_STRVAR(gethostname_doc,
\n\
Return the current host name.");
+#ifdef HAVE_SETHOSTNAME
+PyDoc_STRVAR(sethostname_doc,
+"sethostname(name)\n\n\
+Sets the hostname to name.");
+
+static PyObject *
+socket_sethostname(PyObject *self, PyObject *args)
+{
+ PyObject *hnobj;
+ Py_buffer buf;
+ int res, flag = 0;
+
+ if (!PyArg_ParseTuple(args, "S:sethostname", &hnobj)) {
+ PyErr_Clear();
+ if (!PyArg_ParseTuple(args, "O&:sethostname",
+ PyUnicode_FSConverter, &hnobj))
+ return NULL;
+ flag = 1;
+ }
+ res = PyObject_GetBuffer(hnobj, &buf, PyBUF_SIMPLE);
+ if (!res) {
+ res = sethostname(buf.buf, buf.len);
+ PyBuffer_Release(&buf);
+ }
+ if (flag)
+ Py_DECREF(hnobj);
+ if (res)
+ return set_error();
+ Py_RETURN_NONE;
+}
+#endif
/* Python interface to gethostbyname(name). */
@@ -3418,7 +3449,7 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
goto finally;
af = sa->sa_family;
ap = NULL;
- al = 0;
+ /* al = 0; */
switch (af) {
case AF_INET:
ap = (char *)&((struct sockaddr_in *)sa)->sin_addr;
@@ -4244,6 +4275,10 @@ static PyMethodDef socket_methods[] = {
METH_VARARGS, gethostbyaddr_doc},
{"gethostname", socket_gethostname,
METH_NOARGS, gethostname_doc},
+#ifdef HAVE_SETHOSTNAME
+ {"sethostname", socket_sethostname,
+ METH_VARARGS, sethostname_doc},
+#endif
{"getservbyname", socket_getservbyname,
METH_VARARGS, getservbyname_doc},
{"getservbyport", socket_getservbyport,
diff --git a/Modules/termios.c b/Modules/termios.c
index edeb6f5c45..b78d33e688 100644
--- a/Modules/termios.c
+++ b/Modules/termios.c
@@ -9,11 +9,6 @@
#endif
#include <termios.h>
-#ifdef __osf__
-/* On OSF, sys/ioctl.h requires that struct termio already be defined,
- * so this needs to be included first on that platform. */
-#include <termio.h>
-#endif
#include <sys/ioctl.h>
/* HP-UX requires that this be included to pick up MDCD, MCTS, MDSR,
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 3af041a2b6..4303232128 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -601,31 +601,20 @@ _asctime(struct tm *timeptr)
{
/* Inspired by Open Group reference implementation available at
* http://pubs.opengroup.org/onlinepubs/009695399/functions/asctime.html */
- static char wday_name[7][3] = {
+ static char wday_name[7][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
- static char mon_name[12][3] = {
+ static char mon_name[12][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
- char buf[20]; /* 'Sun Sep 16 01:03:52\0' */
- int n;
-
- n = PyOS_snprintf(buf, sizeof(buf), "%.3s %.3s%3d %.2d:%.2d:%.2d",
- wday_name[timeptr->tm_wday],
- mon_name[timeptr->tm_mon],
- timeptr->tm_mday, timeptr->tm_hour,
- timeptr->tm_min, timeptr->tm_sec);
- /* XXX: since the fields used by snprintf above are validated in checktm,
- * the following condition should never trigger. We keep the check because
- * historically fixed size buffer used in asctime was the source of
- * crashes. */
- if (n + 1 != sizeof(buf)) {
- PyErr_SetString(PyExc_ValueError, "unconvertible time");
- return NULL;
- }
-
- return PyUnicode_FromFormat("%s %d", buf, 1900 + timeptr->tm_year);
+ return PyUnicode_FromFormat(
+ "%s %s%3d %.2d:%.2d:%.2d %d",
+ wday_name[timeptr->tm_wday],
+ mon_name[timeptr->tm_mon],
+ timeptr->tm_mday, timeptr->tm_hour,
+ timeptr->tm_min, timeptr->tm_sec,
+ 1900 + timeptr->tm_year);
}
static PyObject *
diff --git a/Modules/zipimport.c b/Modules/zipimport.c
index 88a27c1d10..407926171b 100644
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -49,7 +49,7 @@ static PyObject *zip_directory_cache = NULL;
/* forward decls */
static PyObject *read_directory(PyObject *archive);
static PyObject *get_data(PyObject *archive, PyObject *toc_entry);
-static PyObject *get_module_code(ZipImporter *self, char *fullname,
+static PyObject *get_module_code(ZipImporter *self, PyObject *fullname,
int *p_ispackage, PyObject **p_modpath);
@@ -202,49 +202,50 @@ zipimporter_repr(ZipImporter *self)
}
/* return fullname.split(".")[-1] */
-static char *
-get_subname(char *fullname)
+static PyObject *
+get_subname(PyObject *fullname)
{
- char *subname = strrchr(fullname, '.');
- if (subname == NULL)
- subname = fullname;
- else
+ Py_ssize_t len;
+ Py_UNICODE *subname;
+ subname = Py_UNICODE_strrchr(PyUnicode_AS_UNICODE(fullname), '.');
+ if (subname == NULL) {
+ Py_INCREF(fullname);
+ return fullname;
+ } else {
subname++;
- return subname;
+ len = PyUnicode_GET_SIZE(fullname);
+ len -= subname - PyUnicode_AS_UNICODE(fullname);
+ return PyUnicode_FromUnicode(subname, len);
+ }
}
/* Given a (sub)modulename, write the potential file path in the
archive (without extension) to the path buffer. Return the
- length of the resulting string. */
-static int
-make_filename(PyObject *prefix_obj, char *name, char *path, size_t pathsize)
+ length of the resulting string.
+
+ return self.prefix + name.replace('.', os.sep) */
+static PyObject*
+make_filename(PyObject *prefix, PyObject *name)
{
- size_t len;
- char *p;
- PyObject *prefix;
+ PyObject *pathobj;
+ Py_UNICODE *p;
- prefix = PyUnicode_EncodeFSDefault(prefix_obj);
- if (prefix == NULL)
- return -1;
- len = PyBytes_GET_SIZE(prefix);
+ pathobj = PyUnicode_FromUnicode(NULL,
+ PyUnicode_GET_SIZE(prefix)
+ + PyUnicode_GET_SIZE(name));
+ if (pathobj == NULL)
+ return NULL;
- /* self.prefix + name [+ SEP + "__init__"] + ".py[co]" */
- if (len + strlen(name) + 13 >= pathsize - 1) {
- PyErr_SetString(ZipImportError, "path too long");
- Py_DECREF(prefix);
- return -1;
- }
+ p = PyUnicode_AS_UNICODE(pathobj);
- strcpy(path, PyBytes_AS_STRING(prefix));
- Py_DECREF(prefix);
- strcpy(path + len, name);
- for (p = path + len; *p; p++) {
+ Py_UNICODE_strcpy(p, PyUnicode_AS_UNICODE(prefix));
+ p += PyUnicode_GET_SIZE(prefix);
+ Py_UNICODE_strcpy(p, PyUnicode_AS_UNICODE(name));
+ for (; *p; p++) {
if (*p == '.')
*p = SEP;
}
- len += strlen(name);
- assert(len < INT_MAX);
- return (int)len;
+ return pathobj;
}
enum zi_module_info {
@@ -256,27 +257,38 @@ enum zi_module_info {
/* Return some information about a module. */
static enum zi_module_info
-get_module_info(ZipImporter *self, char *fullname)
+get_module_info(ZipImporter *self, PyObject *fullname)
{
- char *subname, path[MAXPATHLEN + 1];
- int len;
+ PyObject *subname;
+ PyObject *path, *fullpath, *item;
struct st_zip_searchorder *zso;
subname = get_subname(fullname);
+ if (subname == NULL)
+ return MI_ERROR;
- len = make_filename(self->prefix, subname, path, sizeof(path));
- if (len < 0)
+ path = make_filename(self->prefix, subname);
+ Py_DECREF(subname);
+ if (path == NULL)
return MI_ERROR;
for (zso = zip_searchorder; *zso->suffix; zso++) {
- strcpy(path + len, zso->suffix);
- if (PyDict_GetItemString(self->files, path) != NULL) {
+ fullpath = PyUnicode_FromFormat("%U%s", path, zso->suffix);
+ if (fullpath == NULL) {
+ Py_DECREF(path);
+ return MI_ERROR;
+ }
+ item = PyDict_GetItem(self->files, fullpath);
+ Py_DECREF(fullpath);
+ if (item != NULL) {
+ Py_DECREF(path);
if (zso->type & IS_PACKAGE)
return MI_PACKAGE;
else
return MI_MODULE;
}
}
+ Py_DECREF(path);
return MI_NOT_FOUND;
}
@@ -287,10 +299,10 @@ zipimporter_find_module(PyObject *obj, PyObject *args)
{
ZipImporter *self = (ZipImporter *)obj;
PyObject *path = NULL;
- char *fullname;
+ PyObject *fullname;
enum zi_module_info mi;
- if (!PyArg_ParseTuple(args, "s|O:zipimporter.find_module",
+ if (!PyArg_ParseTuple(args, "U|O:zipimporter.find_module",
&fullname, &path))
return NULL;
@@ -311,11 +323,11 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
{
ZipImporter *self = (ZipImporter *)obj;
PyObject *code = NULL, *mod, *dict;
- char *fullname;
- PyObject *modpath = NULL, *modpath_bytes;
+ PyObject *fullname;
+ PyObject *modpath = NULL;
int ispackage;
- if (!PyArg_ParseTuple(args, "s:zipimporter.load_module",
+ if (!PyArg_ParseTuple(args, "U:zipimporter.load_module",
&fullname))
return NULL;
@@ -323,7 +335,7 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
if (code == NULL)
goto error;
- mod = PyImport_AddModule(fullname);
+ mod = PyImport_AddModuleObject(fullname);
if (mod == NULL)
goto error;
dict = PyModule_GetDict(mod);
@@ -336,17 +348,17 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
/* add __path__ to the module *before* the code gets
executed */
PyObject *pkgpath, *fullpath;
- char *subname = get_subname(fullname);
+ PyObject *subname = get_subname(fullname);
int err;
- fullpath = PyUnicode_FromFormat("%U%c%U%s",
+ fullpath = PyUnicode_FromFormat("%U%c%U%U",
self->archive, SEP,
self->prefix, subname);
+ Py_DECREF(subname);
if (fullpath == NULL)
goto error;
- pkgpath = Py_BuildValue("[O]", fullpath);
- Py_DECREF(fullpath);
+ pkgpath = Py_BuildValue("[N]", fullpath);
if (pkgpath == NULL)
goto error;
err = PyDict_SetItemString(dict, "__path__", pkgpath);
@@ -354,18 +366,13 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
if (err != 0)
goto error;
}
- modpath_bytes = PyUnicode_EncodeFSDefault(modpath);
- if (modpath_bytes == NULL)
- goto error;
- mod = PyImport_ExecCodeModuleEx(fullname, code,
- PyBytes_AS_STRING(modpath_bytes));
- Py_DECREF(modpath_bytes);
+ mod = PyImport_ExecCodeModuleObject(fullname, code, modpath, NULL);
Py_CLEAR(code);
if (mod == NULL)
goto error;
if (Py_VerboseFlag)
- PySys_FormatStderr("import %s # loaded from Zip %U\n",
+ PySys_FormatStderr("import %U # loaded from Zip %U\n",
fullname, modpath);
Py_DECREF(modpath);
return mod;
@@ -380,12 +387,10 @@ static PyObject *
zipimporter_get_filename(PyObject *obj, PyObject *args)
{
ZipImporter *self = (ZipImporter *)obj;
- PyObject *code;
- char *fullname;
- PyObject *modpath;
+ PyObject *fullname, *code, *modpath;
int ispackage;
- if (!PyArg_ParseTuple(args, "s:zipimporter.get_filename",
+ if (!PyArg_ParseTuple(args, "U:zipimporter.get_filename",
&fullname))
return NULL;
@@ -404,10 +409,10 @@ static PyObject *
zipimporter_is_package(PyObject *obj, PyObject *args)
{
ZipImporter *self = (ZipImporter *)obj;
- char *fullname;
+ PyObject *fullname;
enum zi_module_info mi;
- if (!PyArg_ParseTuple(args, "s:zipimporter.is_package",
+ if (!PyArg_ParseTuple(args, "U:zipimporter.is_package",
&fullname))
return NULL;
@@ -415,7 +420,7 @@ zipimporter_is_package(PyObject *obj, PyObject *args)
if (mi == MI_ERROR)
return NULL;
if (mi == MI_NOT_FOUND) {
- PyErr_Format(ZipImportError, "can't find module '%s'", fullname);
+ PyErr_Format(ZipImportError, "can't find module %R", fullname);
return NULL;
}
return PyBool_FromLong(mi == MI_PACKAGE);
@@ -477,9 +482,9 @@ static PyObject *
zipimporter_get_code(PyObject *obj, PyObject *args)
{
ZipImporter *self = (ZipImporter *)obj;
- char *fullname;
+ PyObject *fullname;
- if (!PyArg_ParseTuple(args, "s:zipimporter.get_code", &fullname))
+ if (!PyArg_ParseTuple(args, "U:zipimporter.get_code", &fullname))
return NULL;
return get_module_code(self, fullname, NULL, NULL);
@@ -490,34 +495,39 @@ zipimporter_get_source(PyObject *obj, PyObject *args)
{
ZipImporter *self = (ZipImporter *)obj;
PyObject *toc_entry;
- char *fullname, *subname, path[MAXPATHLEN+1];
- int len;
+ PyObject *fullname, *subname, *path, *fullpath;
enum zi_module_info mi;
- if (!PyArg_ParseTuple(args, "s:zipimporter.get_source", &fullname))
+ if (!PyArg_ParseTuple(args, "U:zipimporter.get_source", &fullname))
return NULL;
mi = get_module_info(self, fullname);
if (mi == MI_ERROR)
return NULL;
if (mi == MI_NOT_FOUND) {
- PyErr_Format(ZipImportError, "can't find module '%s'", fullname);
+ PyErr_Format(ZipImportError, "can't find module %R", fullname);
return NULL;
}
+
subname = get_subname(fullname);
+ if (subname == NULL)
+ return NULL;
- len = make_filename(self->prefix, subname, path, sizeof(path));
- if (len < 0)
+ path = make_filename(self->prefix, subname);
+ Py_DECREF(subname);
+ if (path == NULL)
return NULL;
- if (mi == MI_PACKAGE) {
- path[len] = SEP;
- strcpy(path + len + 1, "__init__.py");
- }
+ if (mi == MI_PACKAGE)
+ fullpath = PyUnicode_FromFormat("%U%c__init__.py", path, SEP);
else
- strcpy(path + len, ".py");
+ fullpath = PyUnicode_FromFormat("%U.py", path);
+ Py_DECREF(path);
+ if (fullpath == NULL)
+ return NULL;
- toc_entry = PyDict_GetItemString(self->files, path);
+ toc_entry = PyDict_GetItem(self->files, fullpath);
+ Py_DECREF(fullpath);
if (toc_entry != NULL) {
PyObject *res, *bytes;
bytes = get_data(self->archive, toc_entry);
@@ -708,9 +718,8 @@ get_long(unsigned char *buf) {
data_size and file_offset are 0.
*/
static PyObject *
-read_directory(PyObject *archive_obj)
+read_directory(PyObject *archive)
{
- /* FIXME: work on Py_UNICODE* instead of char* */
PyObject *files = NULL;
FILE *fp;
unsigned short flags;
@@ -727,29 +736,29 @@ read_directory(PyObject *archive_obj)
const char *charset;
int bootstrap;
- if (PyUnicode_GET_SIZE(archive_obj) > MAXPATHLEN) {
+ if (PyUnicode_GET_SIZE(archive) > MAXPATHLEN) {
PyErr_SetString(PyExc_OverflowError,
"Zip path name is too long");
return NULL;
}
- Py_UNICODE_strcpy(path, PyUnicode_AS_UNICODE(archive_obj));
+ Py_UNICODE_strcpy(path, PyUnicode_AS_UNICODE(archive));
- fp = _Py_fopen(archive_obj, "rb");
+ fp = _Py_fopen(archive, "rb");
if (fp == NULL) {
- PyErr_Format(ZipImportError, "can't open Zip file: '%U'", archive_obj);
+ PyErr_Format(ZipImportError, "can't open Zip file: %R", archive);
return NULL;
}
fseek(fp, -22, SEEK_END);
header_position = ftell(fp);
if (fread(endof_central_dir, 1, 22, fp) != 22) {
fclose(fp);
- PyErr_Format(ZipImportError, "can't read Zip file: '%U'", archive_obj);
+ PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
return NULL;
}
if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) {
/* Bad: End of Central Dir signature */
fclose(fp);
- PyErr_Format(ZipImportError, "not a Zip file: '%U'", archive_obj);
+ PyErr_Format(ZipImportError, "not a Zip file: %R", archive);
return NULL;
}
@@ -826,7 +835,9 @@ read_directory(PyObject *archive_obj)
PY_MAJOR_VERSION, PY_MINOR_VERSION);
goto error;
}
- Py_UNICODE_strncpy(path + length + 1, PyUnicode_AS_UNICODE(nameobj), MAXPATHLEN - length - 1);
+ Py_UNICODE_strncpy(path + length + 1,
+ PyUnicode_AS_UNICODE(nameobj),
+ MAXPATHLEN - length - 1);
pathobj = PyUnicode_FromUnicode(path, Py_UNICODE_strlen(path));
if (pathobj == NULL)
@@ -844,8 +855,8 @@ read_directory(PyObject *archive_obj)
}
fclose(fp);
if (Py_VerboseFlag)
- PySys_FormatStderr("# zipimport: found %ld names in %U\n",
- count, archive_obj);
+ PySys_FormatStderr("# zipimport: found %ld names in %R\n",
+ count, archive);
return files;
error:
fclose(fp);
@@ -999,7 +1010,7 @@ eq_mtime(time_t t1, time_t t2)
to .py if available and we don't want to mask other errors).
Returns a new reference. */
static PyObject *
-unmarshal_code(char *pathname, PyObject *data, time_t mtime)
+unmarshal_code(PyObject *pathname, PyObject *data, time_t mtime)
{
PyObject *code;
char *buf = PyBytes_AsString(data);
@@ -1013,8 +1024,8 @@ unmarshal_code(char *pathname, PyObject *data, time_t mtime)
if (get_long((unsigned char *)buf) != PyImport_GetMagicNumber()) {
if (Py_VerboseFlag)
- PySys_WriteStderr("# %s has bad magic\n",
- pathname);
+ PySys_FormatStderr("# %R has bad magic\n",
+ pathname);
Py_INCREF(Py_None);
return Py_None; /* signal caller to try alternative */
}
@@ -1022,8 +1033,8 @@ unmarshal_code(char *pathname, PyObject *data, time_t mtime)
if (mtime != 0 && !eq_mtime(get_long((unsigned char *)buf + 4),
mtime)) {
if (Py_VerboseFlag)
- PySys_WriteStderr("# %s has bad mtime\n",
- pathname);
+ PySys_FormatStderr("# %R has bad mtime\n",
+ pathname);
Py_INCREF(Py_None);
return Py_None; /* signal caller to try alternative */
}
@@ -1034,7 +1045,7 @@ unmarshal_code(char *pathname, PyObject *data, time_t mtime)
if (!PyCode_Check(code)) {
Py_DECREF(code);
PyErr_Format(PyExc_TypeError,
- "compiled module %s is not a code object",
+ "compiled module %R is not a code object",
pathname);
return NULL;
}
@@ -1048,11 +1059,12 @@ unmarshal_code(char *pathname, PyObject *data, time_t mtime)
static PyObject *
normalize_line_endings(PyObject *source)
{
- char *buf, *q, *p = PyBytes_AsString(source);
+ char *buf, *q, *p;
PyObject *fixed_source;
int len = 0;
- if (!p) {
+ p = PyBytes_AsString(source);
+ if (p == NULL) {
return PyBytes_FromStringAndSize("\n\0", 2);
}
@@ -1085,16 +1097,24 @@ normalize_line_endings(PyObject *source)
/* Given a string buffer containing Python source code, compile it
return and return a code object as a new reference. */
static PyObject *
-compile_source(char *pathname, PyObject *source)
+compile_source(PyObject *pathname, PyObject *source)
{
- PyObject *code, *fixed_source;
+ PyObject *code, *fixed_source, *pathbytes;
+
+ pathbytes = PyUnicode_EncodeFSDefault(pathname);
+ if (pathbytes == NULL)
+ return NULL;
fixed_source = normalize_line_endings(source);
- if (fixed_source == NULL)
+ if (fixed_source == NULL) {
+ Py_DECREF(pathbytes);
return NULL;
+ }
- code = Py_CompileString(PyBytes_AsString(fixed_source), pathname,
+ code = Py_CompileString(PyBytes_AsString(fixed_source),
+ PyBytes_AsString(pathbytes),
Py_file_input);
+ Py_DECREF(pathbytes);
Py_DECREF(fixed_source);
return code;
}
@@ -1123,14 +1143,19 @@ parse_dostime(int dostime, int dosdate)
modification time of the matching .py file, or 0 if no source
is available. */
static time_t
-get_mtime_of_source(ZipImporter *self, char *path)
+get_mtime_of_source(ZipImporter *self, PyObject *path)
{
- PyObject *toc_entry;
- time_t mtime = 0;
- Py_ssize_t lastchar = strlen(path) - 1;
- char savechar = path[lastchar];
- path[lastchar] = '\0'; /* strip 'c' or 'o' from *.py[co] */
- toc_entry = PyDict_GetItemString(self->files, path);
+ PyObject *toc_entry, *stripped;
+ time_t mtime;
+
+ /* strip 'c' or 'o' from *.py[co] */
+ stripped = PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(path),
+ PyUnicode_GET_SIZE(path) - 1);
+ if (stripped == NULL)
+ return (time_t)-1;
+
+ toc_entry = PyDict_GetItem(self->files, stripped);
+ Py_DECREF(stripped);
if (toc_entry != NULL && PyTuple_Check(toc_entry) &&
PyTuple_Size(toc_entry) == 8) {
/* fetch the time stamp of the .py file for comparison
@@ -1139,8 +1164,8 @@ get_mtime_of_source(ZipImporter *self, char *path)
time = PyLong_AsLong(PyTuple_GetItem(toc_entry, 5));
date = PyLong_AsLong(PyTuple_GetItem(toc_entry, 6));
mtime = parse_dostime(time, date);
- }
- path[lastchar] = savechar;
+ } else
+ mtime = 0;
return mtime;
}
@@ -1150,24 +1175,17 @@ static PyObject *
get_code_from_data(ZipImporter *self, int ispackage, int isbytecode,
time_t mtime, PyObject *toc_entry)
{
- PyObject *data, *code;
- PyObject *modpath;
+ PyObject *data, *modpath, *code;
data = get_data(self->archive, toc_entry);
if (data == NULL)
return NULL;
- modpath = PyUnicode_EncodeFSDefault(PyTuple_GetItem(toc_entry, 0));
- if (modpath == NULL) {
- Py_DECREF(data);
- return NULL;
- }
-
+ modpath = PyTuple_GetItem(toc_entry, 0);
if (isbytecode)
- code = unmarshal_code(PyBytes_AS_STRING(modpath), data, mtime);
+ code = unmarshal_code(modpath, data, mtime);
else
- code = compile_source(PyBytes_AS_STRING(modpath), data);
- Py_DECREF(modpath);
+ code = compile_source(modpath, data);
Py_DECREF(data);
return code;
}
@@ -1175,35 +1193,45 @@ get_code_from_data(ZipImporter *self, int ispackage, int isbytecode,
/* Get the code object associated with the module specified by
'fullname'. */
static PyObject *
-get_module_code(ZipImporter *self, char *fullname,
+get_module_code(ZipImporter *self, PyObject *fullname,
int *p_ispackage, PyObject **p_modpath)
{
- PyObject *toc_entry;
- char *subname, path[MAXPATHLEN + 1];
- int len;
+ PyObject *code, *toc_entry, *subname;
+ PyObject *path, *fullpath;
struct st_zip_searchorder *zso;
subname = get_subname(fullname);
+ if (subname == NULL)
+ return NULL;
- len = make_filename(self->prefix, subname, path, sizeof(path));
- if (len < 0)
+ path = make_filename(self->prefix, subname);
+ Py_DECREF(subname);
+ if (path == NULL)
return NULL;
for (zso = zip_searchorder; *zso->suffix; zso++) {
- PyObject *code = NULL;
+ code = NULL;
+
+ fullpath = PyUnicode_FromFormat("%U%s", path, zso->suffix);
+ if (fullpath == NULL)
+ goto exit;
- strcpy(path + len, zso->suffix);
if (Py_VerboseFlag > 1)
- PySys_FormatStderr("# trying %U%c%s\n",
- self->archive, (int)SEP, path);
- toc_entry = PyDict_GetItemString(self->files, path);
+ PySys_FormatStderr("# trying %U%c%U\n",
+ self->archive, (int)SEP, fullpath);
+ toc_entry = PyDict_GetItem(self->files, fullpath);
if (toc_entry != NULL) {
time_t mtime = 0;
int ispackage = zso->type & IS_PACKAGE;
int isbytecode = zso->type & IS_BYTECODE;
- if (isbytecode)
- mtime = get_mtime_of_source(self, path);
+ if (isbytecode) {
+ mtime = get_mtime_of_source(self, fullpath);
+ if (mtime == (time_t)-1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ Py_CLEAR(fullpath);
if (p_ispackage != NULL)
*p_ispackage = ispackage;
code = get_code_from_data(self, ispackage,
@@ -1219,11 +1247,16 @@ get_module_code(ZipImporter *self, char *fullname,
*p_modpath = PyTuple_GetItem(toc_entry, 0);
Py_INCREF(*p_modpath);
}
- return code;
+ goto exit;
}
+ else
+ Py_CLEAR(fullpath);
}
- PyErr_Format(ZipImportError, "can't find module '%s'", fullname);
- return NULL;
+ PyErr_Format(ZipImportError, "can't find module %R", fullname);
+exit:
+ Py_DECREF(path);
+ Py_XDECREF(fullpath);
+ return code;
}