mirror of
https://github.com/python/cpython.git
synced 2025-11-20 02:50:14 +00:00
Backport of several functions from Python 3.0 to 2.6 including PyUnicode_FromString, PyUnicode_Format and PyLong_From/AsSsize_t. The functions are partly required for the backport of the bytearray type and _fileio module. They should also make it easier to port C to 3.0.
First chapter of the Python 3.0 io framework back port: _fileio The next step depends on a working bytearray type which itself depends on a backport of the nwe buffer API.
This commit is contained in:
parent
5f95a79b2b
commit
7f39c9fcbb
8 changed files with 1599 additions and 173 deletions
|
|
@ -24,11 +24,11 @@ typedef unsigned int wdigit; /* digit widened to parameter size */
|
||||||
typedef unsigned BASE_TWODIGITS_TYPE twodigits;
|
typedef unsigned BASE_TWODIGITS_TYPE twodigits;
|
||||||
typedef BASE_TWODIGITS_TYPE stwodigits; /* signed variant of twodigits */
|
typedef BASE_TWODIGITS_TYPE stwodigits; /* signed variant of twodigits */
|
||||||
|
|
||||||
#define SHIFT 15
|
#define PyLong_SHIFT 15
|
||||||
#define BASE ((digit)1 << SHIFT)
|
#define PyLong_BASE ((digit)1 << PyLong_SHIFT)
|
||||||
#define MASK ((int)(BASE - 1))
|
#define PyLong_MASK ((int)(PyLong_BASE - 1))
|
||||||
|
|
||||||
#if SHIFT % 5 != 0
|
#if PyLong_SHIFT % 5 != 0
|
||||||
#error "longobject.c requires that SHIFT be divisible by 5"
|
#error "longobject.c requires that SHIFT be divisible by 5"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,17 @@ PyAPI_DATA(PyTypeObject) PyLong_Type;
|
||||||
PyAPI_FUNC(PyObject *) PyLong_FromLong(long);
|
PyAPI_FUNC(PyObject *) PyLong_FromLong(long);
|
||||||
PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long);
|
PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long);
|
||||||
PyAPI_FUNC(PyObject *) PyLong_FromDouble(double);
|
PyAPI_FUNC(PyObject *) PyLong_FromDouble(double);
|
||||||
|
PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t);
|
||||||
|
PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t);
|
||||||
PyAPI_FUNC(long) PyLong_AsLong(PyObject *);
|
PyAPI_FUNC(long) PyLong_AsLong(PyObject *);
|
||||||
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
|
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
|
||||||
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
|
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
|
||||||
|
PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *);
|
||||||
|
|
||||||
/* For use by intobject.c only */
|
/* For use by intobject.c only */
|
||||||
PyAPI_FUNC(Py_ssize_t) _PyLong_AsSsize_t(PyObject *);
|
#define _PyLong_AsSsize_t PyLong_AsSsize_t
|
||||||
PyAPI_FUNC(PyObject *) _PyLong_FromSize_t(size_t);
|
#define _PyLong_FromSize_t PyLong_FromSize_t
|
||||||
PyAPI_FUNC(PyObject *) _PyLong_FromSsize_t(Py_ssize_t);
|
#define _PyLong_FromSsize_t PyLong_FromSsize_t
|
||||||
PyAPI_DATA(int) _PyLong_DigitValue[256];
|
PyAPI_DATA(int) _PyLong_DigitValue[256];
|
||||||
|
|
||||||
/* _PyLong_AsScaledDouble returns a double x and an exponent e such that
|
/* _PyLong_AsScaledDouble returns a double x and an exponent e such that
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,10 @@ typedef PY_UNICODE_TYPE Py_UNICODE;
|
||||||
# define PyUnicode_FromObject PyUnicodeUCS2_FromObject
|
# define PyUnicode_FromObject PyUnicodeUCS2_FromObject
|
||||||
# define PyUnicode_FromOrdinal PyUnicodeUCS2_FromOrdinal
|
# define PyUnicode_FromOrdinal PyUnicodeUCS2_FromOrdinal
|
||||||
# define PyUnicode_FromUnicode PyUnicodeUCS2_FromUnicode
|
# define PyUnicode_FromUnicode PyUnicodeUCS2_FromUnicode
|
||||||
|
# define PyUnicode_FromString PyUnicodeUCS2_FromString
|
||||||
|
# define PyUnicode_FromStringAndSize PyUnicodeUCS2_FromStringAndSize
|
||||||
|
# define PyUnicode_FromFormatV PyUnicodeUCS2_FromFormatV
|
||||||
|
# define PyUnicode_FromFormat PyUnicodeUCS2_FromFormat
|
||||||
# define PyUnicode_FromWideChar PyUnicodeUCS2_FromWideChar
|
# define PyUnicode_FromWideChar PyUnicodeUCS2_FromWideChar
|
||||||
# define PyUnicode_GetDefaultEncoding PyUnicodeUCS2_GetDefaultEncoding
|
# define PyUnicode_GetDefaultEncoding PyUnicodeUCS2_GetDefaultEncoding
|
||||||
# define PyUnicode_GetMax PyUnicodeUCS2_GetMax
|
# define PyUnicode_GetMax PyUnicodeUCS2_GetMax
|
||||||
|
|
@ -265,6 +269,10 @@ typedef PY_UNICODE_TYPE Py_UNICODE;
|
||||||
# define PyUnicode_FromObject PyUnicodeUCS4_FromObject
|
# define PyUnicode_FromObject PyUnicodeUCS4_FromObject
|
||||||
# define PyUnicode_FromOrdinal PyUnicodeUCS4_FromOrdinal
|
# define PyUnicode_FromOrdinal PyUnicodeUCS4_FromOrdinal
|
||||||
# define PyUnicode_FromUnicode PyUnicodeUCS4_FromUnicode
|
# define PyUnicode_FromUnicode PyUnicodeUCS4_FromUnicode
|
||||||
|
# define PyUnicode_FromString PyUnicodeUCS4_FromString
|
||||||
|
# define PyUnicode_FromStringAndSize PyUnicodeUCS4_FromStringAndSize
|
||||||
|
# define PyUnicode_FromFormatV PyUnicodeUCS4_FromFormatV
|
||||||
|
# define PyUnicode_FromFormat PyUnicodeUCS4_FromFormat
|
||||||
# define PyUnicode_FromWideChar PyUnicodeUCS4_FromWideChar
|
# define PyUnicode_FromWideChar PyUnicodeUCS4_FromWideChar
|
||||||
# define PyUnicode_GetDefaultEncoding PyUnicodeUCS4_GetDefaultEncoding
|
# define PyUnicode_GetDefaultEncoding PyUnicodeUCS4_GetDefaultEncoding
|
||||||
# define PyUnicode_GetMax PyUnicodeUCS4_GetMax
|
# define PyUnicode_GetMax PyUnicodeUCS4_GetMax
|
||||||
|
|
@ -442,6 +450,18 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromUnicode(
|
||||||
Py_ssize_t size /* size of buffer */
|
Py_ssize_t size /* size of buffer */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* Similar to PyUnicode_FromUnicode(), but u points to Latin-1 encoded bytes */
|
||||||
|
PyAPI_FUNC(PyObject*) PyUnicode_FromStringAndSize(
|
||||||
|
const char *u, /* char buffer */
|
||||||
|
Py_ssize_t size /* size of buffer */
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Similar to PyUnicode_FromUnicode(), but u points to null-terminated
|
||||||
|
Latin-1 encoded bytes */
|
||||||
|
PyAPI_FUNC(PyObject*) PyUnicode_FromString(
|
||||||
|
const char *u /* string */
|
||||||
|
);
|
||||||
|
|
||||||
/* Return a read-only pointer to the Unicode object's internal
|
/* Return a read-only pointer to the Unicode object's internal
|
||||||
Py_UNICODE buffer. */
|
Py_UNICODE buffer. */
|
||||||
|
|
||||||
|
|
@ -517,6 +537,9 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromObject(
|
||||||
register PyObject *obj /* Object */
|
register PyObject *obj /* Object */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyObject *) PyUnicode_FromFormatV(const char*, va_list);
|
||||||
|
PyAPI_FUNC(PyObject *) PyUnicode_FromFormat(const char*, ...);
|
||||||
|
|
||||||
/* --- wchar_t support for platforms which support it --------------------- */
|
/* --- wchar_t support for platforms which support it --------------------- */
|
||||||
|
|
||||||
#ifdef HAVE_WCHAR_H
|
#ifdef HAVE_WCHAR_H
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
+++++++++++
|
+++++++++++
|
||||||
Python News
|
Python News
|
||||||
+++++++++++
|
+++++++++++
|
||||||
|
|
||||||
|
|
@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 1?
|
||||||
Core and builtins
|
Core and builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Backport of PyUnicode_FromString(), _FromStringAndSize(), _Format and
|
||||||
|
_FormatV from Python 3.0. Made PyLong_AsSsize_t and PyLong_FromSsize_t
|
||||||
|
public functions.
|
||||||
|
|
||||||
- Issue #1920: "while 0" statements were completely removed by the compiler,
|
- Issue #1920: "while 0" statements were completely removed by the compiler,
|
||||||
even in the presence of an "else" clause, which is supposed to be run when
|
even in the presence of an "else" clause, which is supposed to be run when
|
||||||
the condition is false. Now the compiler correctly emits bytecode for the
|
the condition is false. Now the compiler correctly emits bytecode for the
|
||||||
|
|
@ -1102,6 +1106,8 @@ Library
|
||||||
Extension Modules
|
Extension Modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Backport of _fileio module from Python 3.0.
|
||||||
|
|
||||||
- #1087741: mmap.mmap is now a class, not a factory function. It is also
|
- #1087741: mmap.mmap is now a class, not a factory function. It is also
|
||||||
subclassable now.
|
subclassable now.
|
||||||
|
|
||||||
|
|
|
||||||
927
Modules/_fileio.c
Normal file
927
Modules/_fileio.c
Normal file
|
|
@ -0,0 +1,927 @@
|
||||||
|
/* Author: Daniel Stutzbach */
|
||||||
|
|
||||||
|
#define PY_SSIZE_T_CLEAN
|
||||||
|
#include "Python.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stddef.h> /* For offsetof */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Known likely problems:
|
||||||
|
*
|
||||||
|
* - Files larger then 2**32-1
|
||||||
|
* - Files with unicode filenames
|
||||||
|
* - Passing numbers greater than 2**32-1 when an integer is expected
|
||||||
|
* - Making it work on Windows and other oddball platforms
|
||||||
|
*
|
||||||
|
* To Do:
|
||||||
|
*
|
||||||
|
* - autoconfify header file inclusion
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
/* can simulate truncate with Win32 API functions; see file_truncate */
|
||||||
|
#define HAVE_FTRUNCATE
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
int fd;
|
||||||
|
unsigned readable : 1;
|
||||||
|
unsigned writable : 1;
|
||||||
|
int seekable : 2; /* -1 means unknown */
|
||||||
|
int closefd : 1;
|
||||||
|
PyObject *weakreflist;
|
||||||
|
} PyFileIOObject;
|
||||||
|
|
||||||
|
PyTypeObject PyFileIO_Type;
|
||||||
|
|
||||||
|
#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
|
||||||
|
|
||||||
|
/* Returns 0 on success, errno (which is < 0) on failure. */
|
||||||
|
static int
|
||||||
|
internal_close(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
int save_errno = 0;
|
||||||
|
if (self->fd >= 0) {
|
||||||
|
int fd = self->fd;
|
||||||
|
self->fd = -1;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
if (close(fd) < 0)
|
||||||
|
save_errno = errno;
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
|
return save_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_close(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
if (!self->closefd) {
|
||||||
|
if (PyErr_WarnEx(PyExc_RuntimeWarning,
|
||||||
|
"Trying to close unclosable fd!", 3) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
errno = internal_close(self);
|
||||||
|
if (errno < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_IOError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_new(PyTypeObject *type, PyObject *args, PyObject *kews)
|
||||||
|
{
|
||||||
|
PyFileIOObject *self;
|
||||||
|
|
||||||
|
assert(type != NULL && type->tp_alloc != NULL);
|
||||||
|
|
||||||
|
self = (PyFileIOObject *) type->tp_alloc(type, 0);
|
||||||
|
if (self != NULL) {
|
||||||
|
self->fd = -1;
|
||||||
|
self->weakreflist = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PyObject *) self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On Unix, open will succeed for directories.
|
||||||
|
In Python, there should be no file objects referring to
|
||||||
|
directories, so we need a check. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
dircheck(PyFileIOObject* self)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
|
||||||
|
struct stat buf;
|
||||||
|
if (self->fd < 0)
|
||||||
|
return 0;
|
||||||
|
if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
|
||||||
|
#ifdef HAVE_STRERROR
|
||||||
|
char *msg = strerror(EISDIR);
|
||||||
|
#else
|
||||||
|
char *msg = "Is a directory";
|
||||||
|
#endif
|
||||||
|
PyObject *exc;
|
||||||
|
internal_close(self);
|
||||||
|
|
||||||
|
exc = PyObject_CallFunction(PyExc_IOError, "(is)",
|
||||||
|
EISDIR, msg);
|
||||||
|
PyErr_SetObject(PyExc_IOError, exc);
|
||||||
|
Py_XDECREF(exc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
PyFileIOObject *self = (PyFileIOObject *) oself;
|
||||||
|
static char *kwlist[] = {"file", "mode", "closefd", NULL};
|
||||||
|
char *name = NULL;
|
||||||
|
char *mode = "r";
|
||||||
|
char *s;
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
Py_UNICODE *widename = NULL;
|
||||||
|
#endif
|
||||||
|
int ret = 0;
|
||||||
|
int rwa = 0, plus = 0, append = 0;
|
||||||
|
int flags = 0;
|
||||||
|
int fd = -1;
|
||||||
|
int closefd = 1;
|
||||||
|
|
||||||
|
assert(PyFileIO_Check(oself));
|
||||||
|
if (self->fd >= 0) {
|
||||||
|
/* Have to close the existing file first. */
|
||||||
|
if (internal_close(self) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyArg_ParseTupleAndKeywords(args, kwds, "i|si:fileio",
|
||||||
|
kwlist, &fd, &mode, &closefd)) {
|
||||||
|
if (fd < 0) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"Negative filedescriptor");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Clear();
|
||||||
|
|
||||||
|
#ifdef Py_WIN_WIDE_FILENAMES
|
||||||
|
if (GetVersion() < 0x80000000) {
|
||||||
|
/* On NT, so wide API available */
|
||||||
|
PyObject *po;
|
||||||
|
if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:fileio",
|
||||||
|
kwlist, &po, &mode, &closefd)
|
||||||
|
) {
|
||||||
|
widename = PyUnicode_AS_UNICODE(po);
|
||||||
|
} else {
|
||||||
|
/* Drop the argument parsing error as narrow
|
||||||
|
strings are also valid. */
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (widename == NULL)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:fileio",
|
||||||
|
kwlist,
|
||||||
|
Py_FileSystemDefaultEncoding,
|
||||||
|
&name, &mode, &closefd))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self->readable = self->writable = 0;
|
||||||
|
self->seekable = -1;
|
||||||
|
s = mode;
|
||||||
|
while (*s) {
|
||||||
|
switch (*s++) {
|
||||||
|
case 'r':
|
||||||
|
if (rwa) {
|
||||||
|
bad_mode:
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"Must have exactly one of read/write/append mode");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
rwa = 1;
|
||||||
|
self->readable = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
if (rwa)
|
||||||
|
goto bad_mode;
|
||||||
|
rwa = 1;
|
||||||
|
self->writable = 1;
|
||||||
|
flags |= O_CREAT | O_TRUNC;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
if (rwa)
|
||||||
|
goto bad_mode;
|
||||||
|
rwa = 1;
|
||||||
|
self->writable = 1;
|
||||||
|
flags |= O_CREAT;
|
||||||
|
append = 1;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
if (plus)
|
||||||
|
goto bad_mode;
|
||||||
|
self->readable = self->writable = 1;
|
||||||
|
plus = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"invalid mode: %.200s", mode);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rwa)
|
||||||
|
goto bad_mode;
|
||||||
|
|
||||||
|
if (self->readable && self->writable)
|
||||||
|
flags |= O_RDWR;
|
||||||
|
else if (self->readable)
|
||||||
|
flags |= O_RDONLY;
|
||||||
|
else
|
||||||
|
flags |= O_WRONLY;
|
||||||
|
|
||||||
|
#ifdef O_BINARY
|
||||||
|
flags |= O_BINARY;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef O_APPEND
|
||||||
|
if (append)
|
||||||
|
flags |= O_APPEND;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (fd >= 0) {
|
||||||
|
self->fd = fd;
|
||||||
|
self->closefd = closefd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self->closefd = 1;
|
||||||
|
if (!closefd) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"Cannot use closefd=True with file name");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
errno = 0;
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
if (widename != NULL)
|
||||||
|
self->fd = _wopen(widename, flags, 0666);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
self->fd = open(name, flags, 0666);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if (self->fd < 0 || dircheck(self) < 0) {
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);
|
||||||
|
#else
|
||||||
|
PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
error:
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
done:
|
||||||
|
PyMem_Free(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fileio_dealloc(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
if (self->weakreflist != NULL)
|
||||||
|
PyObject_ClearWeakRefs((PyObject *) self);
|
||||||
|
|
||||||
|
if (self->fd >= 0 && self->closefd) {
|
||||||
|
errno = internal_close(self);
|
||||||
|
if (errno < 0) {
|
||||||
|
#ifdef HAVE_STRERROR
|
||||||
|
PySys_WriteStderr("close failed: [Errno %d] %s\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
#else
|
||||||
|
PySys_WriteStderr("close failed: [Errno %d]\n", errno);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
err_closed(void)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
err_mode(char *action)
|
||||||
|
{
|
||||||
|
PyErr_Format(PyExc_ValueError, "File not open for %s", action);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_fileno(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
return PyInt_FromLong((long) self->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_readable(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
return PyBool_FromLong((long) self->readable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_writable(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
return PyBool_FromLong((long) self->writable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_seekable(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
if (self->seekable < 0) {
|
||||||
|
int ret;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
ret = lseek(self->fd, 0, SEEK_CUR);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if (ret < 0)
|
||||||
|
self->seekable = 0;
|
||||||
|
else
|
||||||
|
self->seekable = 1;
|
||||||
|
}
|
||||||
|
return PyBool_FromLong((long) self->seekable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_readinto(PyFileIOObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
Py_ssize_t n;
|
||||||
|
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
if (!self->readable)
|
||||||
|
return err_mode("reading");
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "w#", &ptr, &n))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
errno = 0;
|
||||||
|
n = read(self->fd, ptr, n);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
PyErr_SetFromErrno(PyExc_IOError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyLong_FromSsize_t(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFAULT_BUFFER_SIZE (8*1024)
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_readall(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
PyObject *result;
|
||||||
|
Py_ssize_t total = 0;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
result = PyString_FromStringAndSize(NULL, DEFAULT_BUFFER_SIZE);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
Py_ssize_t newsize = total + DEFAULT_BUFFER_SIZE;
|
||||||
|
if (PyString_GET_SIZE(result) < newsize) {
|
||||||
|
if (_PyString_Resize(&result, newsize) < 0) {
|
||||||
|
if (total == 0) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyErr_Clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
errno = 0;
|
||||||
|
n = read(self->fd,
|
||||||
|
PyString_AS_STRING(result) + total,
|
||||||
|
newsize - total);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if (n == 0)
|
||||||
|
break;
|
||||||
|
if (n < 0) {
|
||||||
|
if (total > 0)
|
||||||
|
break;
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
Py_DECREF(result);
|
||||||
|
PyErr_SetFromErrno(PyExc_IOError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
total += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyString_GET_SIZE(result) > total) {
|
||||||
|
if (_PyString_Resize(&result, total) < 0) {
|
||||||
|
/* This should never happen, but just in case */
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_read(PyFileIOObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
Py_ssize_t n;
|
||||||
|
Py_ssize_t size = -1;
|
||||||
|
PyObject *bytes;
|
||||||
|
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
if (!self->readable)
|
||||||
|
return err_mode("reading");
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "|n", &size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
return fileio_readall(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = PyString_FromStringAndSize(NULL, size);
|
||||||
|
if (bytes == NULL)
|
||||||
|
return NULL;
|
||||||
|
ptr = PyString_AS_STRING(bytes);
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
errno = 0;
|
||||||
|
n = read(self->fd, ptr, size);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
PyErr_SetFromErrno(PyExc_IOError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n != size) {
|
||||||
|
if (_PyString_Resize(&bytes, n) < 0) {
|
||||||
|
Py_DECREF(bytes);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PyObject *) bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_write(PyFileIOObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
Py_ssize_t n;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
if (!self->writable)
|
||||||
|
return err_mode("writing");
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s#", &ptr, &n))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
errno = 0;
|
||||||
|
n = write(self->fd, ptr, n);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
PyErr_SetFromErrno(PyExc_IOError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyLong_FromSsize_t(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX Windows support below is likely incomplete */
|
||||||
|
|
||||||
|
#if defined(MS_WIN64) || defined(MS_WINDOWS)
|
||||||
|
typedef PY_LONG_LONG Py_off_t;
|
||||||
|
#else
|
||||||
|
typedef off_t Py_off_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Cribbed from posix_lseek() */
|
||||||
|
static PyObject *
|
||||||
|
portable_lseek(int fd, PyObject *posobj, int whence)
|
||||||
|
{
|
||||||
|
Py_off_t pos, res;
|
||||||
|
|
||||||
|
#ifdef SEEK_SET
|
||||||
|
/* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
|
||||||
|
switch (whence) {
|
||||||
|
#if SEEK_SET != 0
|
||||||
|
case 0: whence = SEEK_SET; break;
|
||||||
|
#endif
|
||||||
|
#if SEEK_CUR != 1
|
||||||
|
case 1: whence = SEEK_CUR; break;
|
||||||
|
#endif
|
||||||
|
#if SEEL_END != 2
|
||||||
|
case 2: whence = SEEK_END; break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif /* SEEK_SET */
|
||||||
|
|
||||||
|
if (posobj == NULL)
|
||||||
|
pos = 0;
|
||||||
|
else {
|
||||||
|
if(PyFloat_Check(posobj)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "an integer is required");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#if !defined(HAVE_LARGEFILE_SUPPORT)
|
||||||
|
pos = PyLong_AsLong(posobj);
|
||||||
|
#else
|
||||||
|
pos = PyLong_Check(posobj) ?
|
||||||
|
PyLong_AsLongLong(posobj) : PyLong_AsLong(posobj);
|
||||||
|
#endif
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
#if defined(MS_WIN64) || defined(MS_WINDOWS)
|
||||||
|
res = _lseeki64(fd, pos, whence);
|
||||||
|
#else
|
||||||
|
res = lseek(fd, pos, whence);
|
||||||
|
#endif
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if (res < 0)
|
||||||
|
return PyErr_SetFromErrno(PyExc_IOError);
|
||||||
|
|
||||||
|
#if !defined(HAVE_LARGEFILE_SUPPORT)
|
||||||
|
return PyLong_FromLong(res);
|
||||||
|
#else
|
||||||
|
return PyLong_FromLongLong(res);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_seek(PyFileIOObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *posobj;
|
||||||
|
int whence = 0;
|
||||||
|
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return portable_lseek(self->fd, posobj, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_tell(PyFileIOObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
|
||||||
|
return portable_lseek(self->fd, NULL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_FTRUNCATE
|
||||||
|
static PyObject *
|
||||||
|
fileio_truncate(PyFileIOObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *posobj = NULL;
|
||||||
|
Py_off_t pos;
|
||||||
|
int ret;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = self->fd;
|
||||||
|
if (fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
if (!self->writable)
|
||||||
|
return err_mode("writing");
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "|O", &posobj))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (posobj == Py_None || posobj == NULL) {
|
||||||
|
posobj = portable_lseek(fd, NULL, 1);
|
||||||
|
if (posobj == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_INCREF(posobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(HAVE_LARGEFILE_SUPPORT)
|
||||||
|
pos = PyLong_AsLong(posobj);
|
||||||
|
#else
|
||||||
|
pos = PyLong_Check(posobj) ?
|
||||||
|
PyLong_AsLongLong(posobj) : PyLong_AsLong(posobj);
|
||||||
|
#endif
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
Py_DECREF(posobj);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
/* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
|
||||||
|
so don't even try using it. */
|
||||||
|
{
|
||||||
|
HANDLE hFile;
|
||||||
|
PyObject *pos2, *oldposobj;
|
||||||
|
|
||||||
|
/* store the current position */
|
||||||
|
oldposobj = portable_lseek(self->fd, NULL, 1);
|
||||||
|
if (oldposobj == NULL) {
|
||||||
|
Py_DECREF(posobj);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Have to move current pos to desired endpoint on Windows. */
|
||||||
|
errno = 0;
|
||||||
|
pos2 = portable_lseek(fd, posobj, SEEK_SET);
|
||||||
|
if (pos2 == NULL) {
|
||||||
|
Py_DECREF(posobj);
|
||||||
|
Py_DECREF(oldposobj);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_DECREF(pos2);
|
||||||
|
|
||||||
|
/* Truncate. Note that this may grow the file! */
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
errno = 0;
|
||||||
|
hFile = (HANDLE)_get_osfhandle(fd);
|
||||||
|
ret = hFile == (HANDLE)-1;
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = SetEndOfFile(hFile) == 0;
|
||||||
|
if (ret)
|
||||||
|
errno = EACCES;
|
||||||
|
}
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
/* Move to the previous position in the file */
|
||||||
|
pos2 = portable_lseek(fd, oldposobj, SEEK_SET);
|
||||||
|
if (pos2 == NULL) {
|
||||||
|
Py_DECREF(posobj);
|
||||||
|
Py_DECREF(oldposobj);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_DECREF(pos2);
|
||||||
|
Py_DECREF(oldposobj);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
errno = 0;
|
||||||
|
ret = ftruncate(fd, pos);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
#endif /* !MS_WINDOWS */
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
Py_DECREF(posobj);
|
||||||
|
PyErr_SetFromErrno(PyExc_IOError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return posobj;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char *
|
||||||
|
mode_string(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
if (self->readable) {
|
||||||
|
if (self->writable)
|
||||||
|
return "r+";
|
||||||
|
else
|
||||||
|
return "r";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "w";
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_repr(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
if (self->fd < 0)
|
||||||
|
return PyString_FromFormat("_fileio._FileIO(-1)");
|
||||||
|
|
||||||
|
return PyString_FromFormat("_fileio._FileIO(%d, '%s')",
|
||||||
|
self->fd, mode_string(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fileio_isatty(PyFileIOObject *self)
|
||||||
|
{
|
||||||
|
long res;
|
||||||
|
|
||||||
|
if (self->fd < 0)
|
||||||
|
return err_closed();
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
res = isatty(self->fd);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
return PyBool_FromLong(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyDoc_STRVAR(fileio_doc,
|
||||||
|
"file(name: str[, mode: str]) -> file IO object\n"
|
||||||
|
"\n"
|
||||||
|
"Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"
|
||||||
|
"writing or appending. The file will be created if it doesn't exist\n"
|
||||||
|
"when opened for writing or appending; it will be truncated when\n"
|
||||||
|
"opened for writing. Add a '+' to the mode to allow simultaneous\n"
|
||||||
|
"reading and writing.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(read_doc,
|
||||||
|
"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
|
||||||
|
"\n"
|
||||||
|
"Only makes one system call, so less data may be returned than requested\n"
|
||||||
|
"In non-blocking mode, returns None if no data is available.\n"
|
||||||
|
"On end-of-file, returns ''.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(readall_doc,
|
||||||
|
"readall() -> bytes. read all data from the file, returned as bytes.\n"
|
||||||
|
"\n"
|
||||||
|
"In non-blocking mode, returns as much as is immediately available,\n"
|
||||||
|
"or None if no data is available. On end-of-file, returns ''.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(write_doc,
|
||||||
|
"write(b: bytes) -> int. Write bytes b to file, return number written.\n"
|
||||||
|
"\n"
|
||||||
|
"Only makes one system call, so not all of the data may be written.\n"
|
||||||
|
"The number of bytes actually written is returned.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(fileno_doc,
|
||||||
|
"fileno() -> int. \"file descriptor\".\n"
|
||||||
|
"\n"
|
||||||
|
"This is needed for lower-level file interfaces, such the fcntl module.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(seek_doc,
|
||||||
|
"seek(offset: int[, whence: int]) -> None. Move to new file position.\n"
|
||||||
|
"\n"
|
||||||
|
"Argument offset is a byte count. Optional argument whence defaults to\n"
|
||||||
|
"0 (offset from start of file, offset should be >= 0); other values are 1\n"
|
||||||
|
"(move relative to current position, positive or negative), and 2 (move\n"
|
||||||
|
"relative to end of file, usually negative, although many platforms allow\n"
|
||||||
|
"seeking beyond the end of a file)."
|
||||||
|
"\n"
|
||||||
|
"Note that not all file objects are seekable.");
|
||||||
|
|
||||||
|
#ifdef HAVE_FTRUNCATE
|
||||||
|
PyDoc_STRVAR(truncate_doc,
|
||||||
|
"truncate([size: int]) -> None. Truncate the file to at most size bytes.\n"
|
||||||
|
"\n"
|
||||||
|
"Size defaults to the current file position, as returned by tell().");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PyDoc_STRVAR(tell_doc,
|
||||||
|
"tell() -> int. Current file position");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(readinto_doc,
|
||||||
|
"readinto() -> Undocumented. Don't use this; it may go away.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(close_doc,
|
||||||
|
"close() -> None. Close the file.\n"
|
||||||
|
"\n"
|
||||||
|
"A closed file cannot be used for further I/O operations. close() may be\n"
|
||||||
|
"called more than once without error. Changes the fileno to -1.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(isatty_doc,
|
||||||
|
"isatty() -> bool. True if the file is connected to a tty device.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(seekable_doc,
|
||||||
|
"seekable() -> bool. True if file supports random-access.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(readable_doc,
|
||||||
|
"readable() -> bool. True if file was opened in a read mode.");
|
||||||
|
|
||||||
|
PyDoc_STRVAR(writable_doc,
|
||||||
|
"writable() -> bool. True if file was opened in a write mode.");
|
||||||
|
|
||||||
|
static PyMethodDef fileio_methods[] = {
|
||||||
|
{"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},
|
||||||
|
{"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},
|
||||||
|
{"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
|
||||||
|
{"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},
|
||||||
|
{"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},
|
||||||
|
{"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},
|
||||||
|
#ifdef HAVE_FTRUNCATE
|
||||||
|
{"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
|
||||||
|
#endif
|
||||||
|
{"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},
|
||||||
|
{"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},
|
||||||
|
{"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},
|
||||||
|
{"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},
|
||||||
|
{"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},
|
||||||
|
{"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},
|
||||||
|
{NULL, NULL} /* sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
get_closed(PyFileIOObject *self, void *closure)
|
||||||
|
{
|
||||||
|
return PyBool_FromLong((long)(self->fd < 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
get_mode(PyFileIOObject *self, void *closure)
|
||||||
|
{
|
||||||
|
return PyString_FromString(mode_string(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyGetSetDef fileio_getsetlist[] = {
|
||||||
|
{"closed", (getter)get_closed, NULL, "True if the file is closed"},
|
||||||
|
{"mode", (getter)get_mode, NULL, "String giving the file mode"},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
|
||||||
|
PyTypeObject PyFileIO_Type = {
|
||||||
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
|
"_FileIO",
|
||||||
|
sizeof(PyFileIOObject),
|
||||||
|
0,
|
||||||
|
(destructor)fileio_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
(reprfunc)fileio_repr, /* 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 */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
|
fileio_doc, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
offsetof(PyFileIOObject, weakreflist), /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
fileio_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
fileio_getsetlist, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
fileio_init, /* tp_init */
|
||||||
|
PyType_GenericAlloc, /* tp_alloc */
|
||||||
|
fileio_new, /* tp_new */
|
||||||
|
PyObject_Del, /* tp_free */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyMethodDef module_methods[] = {
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
init_fileio(void)
|
||||||
|
{
|
||||||
|
PyObject *m; /* a module object */
|
||||||
|
|
||||||
|
m = Py_InitModule3("_fileio", module_methods,
|
||||||
|
"Fast implementation of io.FileIO.");
|
||||||
|
if (m == NULL)
|
||||||
|
return;
|
||||||
|
if (PyType_Ready(&PyFileIO_Type) < 0)
|
||||||
|
return;
|
||||||
|
Py_INCREF(&PyFileIO_Type);
|
||||||
|
PyModule_AddObject(m, "_FileIO", (PyObject *) &PyFileIO_Type);
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
/* For long multiplication, use the O(N**2) school algorithm unless
|
/* For long multiplication, use the O(N**2) school algorithm unless
|
||||||
* both operands contain more than KARATSUBA_CUTOFF digits (this
|
* both operands contain more than KARATSUBA_CUTOFF digits (this
|
||||||
* being an internal Python long digit, in base BASE).
|
* being an internal Python long digit, in base PyLong_BASE).
|
||||||
*/
|
*/
|
||||||
#define KARATSUBA_CUTOFF 70
|
#define KARATSUBA_CUTOFF 70
|
||||||
#define KARATSUBA_SQUARE_CUTOFF (2 * KARATSUBA_CUTOFF)
|
#define KARATSUBA_SQUARE_CUTOFF (2 * KARATSUBA_CUTOFF)
|
||||||
|
|
@ -115,7 +115,7 @@ PyLong_FromLong(long ival)
|
||||||
t = (unsigned long)ival;
|
t = (unsigned long)ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
++ndigits;
|
++ndigits;
|
||||||
t >>= SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
v = _PyLong_New(ndigits);
|
v = _PyLong_New(ndigits);
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
|
|
@ -123,8 +123,8 @@ PyLong_FromLong(long ival)
|
||||||
v->ob_size = negative ? -ndigits : ndigits;
|
v->ob_size = negative ? -ndigits : ndigits;
|
||||||
t = (unsigned long)ival;
|
t = (unsigned long)ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
*p++ = (digit)(t & MASK);
|
*p++ = (digit)(t & PyLong_MASK);
|
||||||
t >>= SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (PyObject *)v;
|
return (PyObject *)v;
|
||||||
|
|
@ -143,15 +143,15 @@ PyLong_FromUnsignedLong(unsigned long ival)
|
||||||
t = (unsigned long)ival;
|
t = (unsigned long)ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
++ndigits;
|
++ndigits;
|
||||||
t >>= SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
v = _PyLong_New(ndigits);
|
v = _PyLong_New(ndigits);
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
digit *p = v->ob_digit;
|
digit *p = v->ob_digit;
|
||||||
Py_SIZE(v) = ndigits;
|
Py_SIZE(v) = ndigits;
|
||||||
while (ival) {
|
while (ival) {
|
||||||
*p++ = (digit)(ival & MASK);
|
*p++ = (digit)(ival & PyLong_MASK);
|
||||||
ival >>= SHIFT;
|
ival >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (PyObject *)v;
|
return (PyObject *)v;
|
||||||
|
|
@ -181,16 +181,16 @@ PyLong_FromDouble(double dval)
|
||||||
frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */
|
frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */
|
||||||
if (expo <= 0)
|
if (expo <= 0)
|
||||||
return PyLong_FromLong(0L);
|
return PyLong_FromLong(0L);
|
||||||
ndig = (expo-1) / SHIFT + 1; /* Number of 'digits' in result */
|
ndig = (expo-1) / PyLong_SHIFT + 1; /* Number of 'digits' in result */
|
||||||
v = _PyLong_New(ndig);
|
v = _PyLong_New(ndig);
|
||||||
if (v == NULL)
|
if (v == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
frac = ldexp(frac, (expo-1) % SHIFT + 1);
|
frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1);
|
||||||
for (i = ndig; --i >= 0; ) {
|
for (i = ndig; --i >= 0; ) {
|
||||||
long bits = (long)frac;
|
long bits = (long)frac;
|
||||||
v->ob_digit[i] = (digit) bits;
|
v->ob_digit[i] = (digit) bits;
|
||||||
frac = frac - (double)bits;
|
frac = frac - (double)bits;
|
||||||
frac = ldexp(frac, SHIFT);
|
frac = ldexp(frac, PyLong_SHIFT);
|
||||||
}
|
}
|
||||||
if (neg)
|
if (neg)
|
||||||
Py_SIZE(v) = -(Py_SIZE(v));
|
Py_SIZE(v) = -(Py_SIZE(v));
|
||||||
|
|
@ -237,8 +237,8 @@ PyLong_AsLong(PyObject *vv)
|
||||||
}
|
}
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
prev = x;
|
prev = x;
|
||||||
x = (x << SHIFT) + v->ob_digit[i];
|
x = (x << PyLong_SHIFT) + v->ob_digit[i];
|
||||||
if ((x >> SHIFT) != prev)
|
if ((x >> PyLong_SHIFT) != prev)
|
||||||
goto overflow;
|
goto overflow;
|
||||||
}
|
}
|
||||||
/* Haven't lost any bits, but casting to long requires extra care
|
/* Haven't lost any bits, but casting to long requires extra care
|
||||||
|
|
@ -262,7 +262,7 @@ PyLong_AsLong(PyObject *vv)
|
||||||
Returns -1 and sets an error condition if overflow occurs. */
|
Returns -1 and sets an error condition if overflow occurs. */
|
||||||
|
|
||||||
Py_ssize_t
|
Py_ssize_t
|
||||||
_PyLong_AsSsize_t(PyObject *vv) {
|
PyLong_AsSsize_t(PyObject *vv) {
|
||||||
register PyLongObject *v;
|
register PyLongObject *v;
|
||||||
size_t x, prev;
|
size_t x, prev;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
|
|
@ -282,8 +282,8 @@ _PyLong_AsSsize_t(PyObject *vv) {
|
||||||
}
|
}
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
prev = x;
|
prev = x;
|
||||||
x = (x << SHIFT) + v->ob_digit[i];
|
x = (x << PyLong_SHIFT) + v->ob_digit[i];
|
||||||
if ((x >> SHIFT) != prev)
|
if ((x >> PyLong_SHIFT) != prev)
|
||||||
goto overflow;
|
goto overflow;
|
||||||
}
|
}
|
||||||
/* Haven't lost any bits, but casting to a signed type requires
|
/* Haven't lost any bits, but casting to a signed type requires
|
||||||
|
|
@ -336,8 +336,8 @@ PyLong_AsUnsignedLong(PyObject *vv)
|
||||||
}
|
}
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
prev = x;
|
prev = x;
|
||||||
x = (x << SHIFT) + v->ob_digit[i];
|
x = (x << PyLong_SHIFT) + v->ob_digit[i];
|
||||||
if ((x >> SHIFT) != prev) {
|
if ((x >> PyLong_SHIFT) != prev) {
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"long int too large to convert");
|
"long int too large to convert");
|
||||||
return (unsigned long) -1;
|
return (unsigned long) -1;
|
||||||
|
|
@ -372,7 +372,7 @@ PyLong_AsUnsignedLongMask(PyObject *vv)
|
||||||
i = -i;
|
i = -i;
|
||||||
}
|
}
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
x = (x << SHIFT) + v->ob_digit[i];
|
x = (x << PyLong_SHIFT) + v->ob_digit[i];
|
||||||
}
|
}
|
||||||
return x * sign;
|
return x * sign;
|
||||||
}
|
}
|
||||||
|
|
@ -402,8 +402,8 @@ _PyLong_NumBits(PyObject *vv)
|
||||||
if (ndigits > 0) {
|
if (ndigits > 0) {
|
||||||
digit msd = v->ob_digit[ndigits - 1];
|
digit msd = v->ob_digit[ndigits - 1];
|
||||||
|
|
||||||
result = (ndigits - 1) * SHIFT;
|
result = (ndigits - 1) * PyLong_SHIFT;
|
||||||
if (result / SHIFT != (size_t)(ndigits - 1))
|
if (result / PyLong_SHIFT != (size_t)(ndigits - 1))
|
||||||
goto Overflow;
|
goto Overflow;
|
||||||
do {
|
do {
|
||||||
++result;
|
++result;
|
||||||
|
|
@ -473,9 +473,9 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* How many Python long digits do we need? We have
|
/* How many Python long digits do we need? We have
|
||||||
8*numsignificantbytes bits, and each Python long digit has SHIFT
|
8*numsignificantbytes bits, and each Python long digit has PyLong_SHIFT
|
||||||
bits, so it's the ceiling of the quotient. */
|
bits, so it's the ceiling of the quotient. */
|
||||||
ndigits = (numsignificantbytes * 8 + SHIFT - 1) / SHIFT;
|
ndigits = (numsignificantbytes * 8 + PyLong_SHIFT - 1) / PyLong_SHIFT;
|
||||||
if (ndigits > (size_t)INT_MAX)
|
if (ndigits > (size_t)INT_MAX)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
v = _PyLong_New((int)ndigits);
|
v = _PyLong_New((int)ndigits);
|
||||||
|
|
@ -505,17 +505,17 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
|
||||||
so needs to be prepended to accum. */
|
so needs to be prepended to accum. */
|
||||||
accum |= thisbyte << accumbits;
|
accum |= thisbyte << accumbits;
|
||||||
accumbits += 8;
|
accumbits += 8;
|
||||||
if (accumbits >= SHIFT) {
|
if (accumbits >= PyLong_SHIFT) {
|
||||||
/* There's enough to fill a Python digit. */
|
/* There's enough to fill a Python digit. */
|
||||||
assert(idigit < (int)ndigits);
|
assert(idigit < (int)ndigits);
|
||||||
v->ob_digit[idigit] = (digit)(accum & MASK);
|
v->ob_digit[idigit] = (digit)(accum & PyLong_MASK);
|
||||||
++idigit;
|
++idigit;
|
||||||
accum >>= SHIFT;
|
accum >>= PyLong_SHIFT;
|
||||||
accumbits -= SHIFT;
|
accumbits -= PyLong_SHIFT;
|
||||||
assert(accumbits < SHIFT);
|
assert(accumbits < PyLong_SHIFT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(accumbits < SHIFT);
|
assert(accumbits < PyLong_SHIFT);
|
||||||
if (accumbits) {
|
if (accumbits) {
|
||||||
assert(idigit < (int)ndigits);
|
assert(idigit < (int)ndigits);
|
||||||
v->ob_digit[idigit] = (digit)accum;
|
v->ob_digit[idigit] = (digit)accum;
|
||||||
|
|
@ -569,7 +569,7 @@ _PyLong_AsByteArray(PyLongObject* v,
|
||||||
|
|
||||||
/* Copy over all the Python digits.
|
/* Copy over all the Python digits.
|
||||||
It's crucial that every Python digit except for the MSD contribute
|
It's crucial that every Python digit except for the MSD contribute
|
||||||
exactly SHIFT bits to the total, so first assert that the long is
|
exactly PyLong_SHIFT bits to the total, so first assert that the long is
|
||||||
normalized. */
|
normalized. */
|
||||||
assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0);
|
assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0);
|
||||||
j = 0;
|
j = 0;
|
||||||
|
|
@ -579,15 +579,15 @@ _PyLong_AsByteArray(PyLongObject* v,
|
||||||
for (i = 0; i < ndigits; ++i) {
|
for (i = 0; i < ndigits; ++i) {
|
||||||
twodigits thisdigit = v->ob_digit[i];
|
twodigits thisdigit = v->ob_digit[i];
|
||||||
if (do_twos_comp) {
|
if (do_twos_comp) {
|
||||||
thisdigit = (thisdigit ^ MASK) + carry;
|
thisdigit = (thisdigit ^ PyLong_MASK) + carry;
|
||||||
carry = thisdigit >> SHIFT;
|
carry = thisdigit >> PyLong_SHIFT;
|
||||||
thisdigit &= MASK;
|
thisdigit &= PyLong_MASK;
|
||||||
}
|
}
|
||||||
/* Because we're going LSB to MSB, thisdigit is more
|
/* Because we're going LSB to MSB, thisdigit is more
|
||||||
significant than what's already in accum, so needs to be
|
significant than what's already in accum, so needs to be
|
||||||
prepended to accum. */
|
prepended to accum. */
|
||||||
accum |= thisdigit << accumbits;
|
accum |= thisdigit << accumbits;
|
||||||
accumbits += SHIFT;
|
accumbits += PyLong_SHIFT;
|
||||||
|
|
||||||
/* The most-significant digit may be (probably is) at least
|
/* The most-significant digit may be (probably is) at least
|
||||||
partly empty. */
|
partly empty. */
|
||||||
|
|
@ -598,9 +598,9 @@ _PyLong_AsByteArray(PyLongObject* v,
|
||||||
* First shift conceptual sign bit to real sign bit.
|
* First shift conceptual sign bit to real sign bit.
|
||||||
*/
|
*/
|
||||||
stwodigits s = (stwodigits)(thisdigit <<
|
stwodigits s = (stwodigits)(thisdigit <<
|
||||||
(8*sizeof(stwodigits) - SHIFT));
|
(8*sizeof(stwodigits) - PyLong_SHIFT));
|
||||||
unsigned int nsignbits = 0;
|
unsigned int nsignbits = 0;
|
||||||
while ((s < 0) == do_twos_comp && nsignbits < SHIFT) {
|
while ((s < 0) == do_twos_comp && nsignbits < PyLong_SHIFT) {
|
||||||
++nsignbits;
|
++nsignbits;
|
||||||
s <<= 1;
|
s <<= 1;
|
||||||
}
|
}
|
||||||
|
|
@ -680,7 +680,7 @@ _PyLong_AsScaledDouble(PyObject *vv, int *exponent)
|
||||||
#define NBITS_WANTED 57
|
#define NBITS_WANTED 57
|
||||||
PyLongObject *v;
|
PyLongObject *v;
|
||||||
double x;
|
double x;
|
||||||
const double multiplier = (double)(1L << SHIFT);
|
const double multiplier = (double)(1L << PyLong_SHIFT);
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
int sign;
|
int sign;
|
||||||
int nbitsneeded;
|
int nbitsneeded;
|
||||||
|
|
@ -707,10 +707,10 @@ _PyLong_AsScaledDouble(PyObject *vv, int *exponent)
|
||||||
while (i > 0 && nbitsneeded > 0) {
|
while (i > 0 && nbitsneeded > 0) {
|
||||||
--i;
|
--i;
|
||||||
x = x * multiplier + (double)v->ob_digit[i];
|
x = x * multiplier + (double)v->ob_digit[i];
|
||||||
nbitsneeded -= SHIFT;
|
nbitsneeded -= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
/* There are i digits we didn't shift in. Pretending they're all
|
/* There are i digits we didn't shift in. Pretending they're all
|
||||||
zeroes, the true value is x * 2**(i*SHIFT). */
|
zeroes, the true value is x * 2**(i*PyLong_SHIFT). */
|
||||||
*exponent = i;
|
*exponent = i;
|
||||||
assert(x > 0.0);
|
assert(x > 0.0);
|
||||||
return x * sign;
|
return x * sign;
|
||||||
|
|
@ -735,10 +735,10 @@ PyLong_AsDouble(PyObject *vv)
|
||||||
/* 'e' initialized to -1 to silence gcc-4.0.x, but it should be
|
/* 'e' initialized to -1 to silence gcc-4.0.x, but it should be
|
||||||
set correctly after a successful _PyLong_AsScaledDouble() call */
|
set correctly after a successful _PyLong_AsScaledDouble() call */
|
||||||
assert(e >= 0);
|
assert(e >= 0);
|
||||||
if (e > INT_MAX / SHIFT)
|
if (e > INT_MAX / PyLong_SHIFT)
|
||||||
goto overflow;
|
goto overflow;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
x = ldexp(x, e * SHIFT);
|
x = ldexp(x, e * PyLong_SHIFT);
|
||||||
if (Py_OVERFLOWED(x))
|
if (Py_OVERFLOWED(x))
|
||||||
goto overflow;
|
goto overflow;
|
||||||
return x;
|
return x;
|
||||||
|
|
@ -846,7 +846,7 @@ PyLong_FromLongLong(PY_LONG_LONG ival)
|
||||||
t = (unsigned PY_LONG_LONG)ival;
|
t = (unsigned PY_LONG_LONG)ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
++ndigits;
|
++ndigits;
|
||||||
t >>= SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
v = _PyLong_New(ndigits);
|
v = _PyLong_New(ndigits);
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
|
|
@ -854,8 +854,8 @@ PyLong_FromLongLong(PY_LONG_LONG ival)
|
||||||
Py_SIZE(v) = negative ? -ndigits : ndigits;
|
Py_SIZE(v) = negative ? -ndigits : ndigits;
|
||||||
t = (unsigned PY_LONG_LONG)ival;
|
t = (unsigned PY_LONG_LONG)ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
*p++ = (digit)(t & MASK);
|
*p++ = (digit)(t & PyLong_MASK);
|
||||||
t >>= SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (PyObject *)v;
|
return (PyObject *)v;
|
||||||
|
|
@ -874,15 +874,15 @@ PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG ival)
|
||||||
t = (unsigned PY_LONG_LONG)ival;
|
t = (unsigned PY_LONG_LONG)ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
++ndigits;
|
++ndigits;
|
||||||
t >>= SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
v = _PyLong_New(ndigits);
|
v = _PyLong_New(ndigits);
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
digit *p = v->ob_digit;
|
digit *p = v->ob_digit;
|
||||||
Py_SIZE(v) = ndigits;
|
Py_SIZE(v) = ndigits;
|
||||||
while (ival) {
|
while (ival) {
|
||||||
*p++ = (digit)(ival & MASK);
|
*p++ = (digit)(ival & PyLong_MASK);
|
||||||
ival >>= SHIFT;
|
ival >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (PyObject *)v;
|
return (PyObject *)v;
|
||||||
|
|
@ -891,7 +891,7 @@ PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG ival)
|
||||||
/* Create a new long int object from a C Py_ssize_t. */
|
/* Create a new long int object from a C Py_ssize_t. */
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyLong_FromSsize_t(Py_ssize_t ival)
|
PyLong_FromSsize_t(Py_ssize_t ival)
|
||||||
{
|
{
|
||||||
Py_ssize_t bytes = ival;
|
Py_ssize_t bytes = ival;
|
||||||
int one = 1;
|
int one = 1;
|
||||||
|
|
@ -903,7 +903,7 @@ _PyLong_FromSsize_t(Py_ssize_t ival)
|
||||||
/* Create a new long int object from a C size_t. */
|
/* Create a new long int object from a C size_t. */
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyLong_FromSize_t(size_t ival)
|
PyLong_FromSize_t(size_t ival)
|
||||||
{
|
{
|
||||||
size_t bytes = ival;
|
size_t bytes = ival;
|
||||||
int one = 1;
|
int one = 1;
|
||||||
|
|
@ -1015,7 +1015,7 @@ PyLong_AsUnsignedLongLongMask(PyObject *vv)
|
||||||
i = -i;
|
i = -i;
|
||||||
}
|
}
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
x = (x << SHIFT) + v->ob_digit[i];
|
x = (x << PyLong_SHIFT) + v->ob_digit[i];
|
||||||
}
|
}
|
||||||
return x * sign;
|
return x * sign;
|
||||||
}
|
}
|
||||||
|
|
@ -1069,14 +1069,14 @@ v_iadd(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n)
|
||||||
assert(m >= n);
|
assert(m >= n);
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
carry += x[i] + y[i];
|
carry += x[i] + y[i];
|
||||||
x[i] = carry & MASK;
|
x[i] = carry & PyLong_MASK;
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
assert((carry & 1) == carry);
|
assert((carry & 1) == carry);
|
||||||
}
|
}
|
||||||
for (; carry && i < m; ++i) {
|
for (; carry && i < m; ++i) {
|
||||||
carry += x[i];
|
carry += x[i];
|
||||||
x[i] = carry & MASK;
|
x[i] = carry & PyLong_MASK;
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
assert((carry & 1) == carry);
|
assert((carry & 1) == carry);
|
||||||
}
|
}
|
||||||
return carry;
|
return carry;
|
||||||
|
|
@ -1095,14 +1095,14 @@ v_isub(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n)
|
||||||
assert(m >= n);
|
assert(m >= n);
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
borrow = x[i] - y[i] - borrow;
|
borrow = x[i] - y[i] - borrow;
|
||||||
x[i] = borrow & MASK;
|
x[i] = borrow & PyLong_MASK;
|
||||||
borrow >>= SHIFT;
|
borrow >>= PyLong_SHIFT;
|
||||||
borrow &= 1; /* keep only 1 sign bit */
|
borrow &= 1; /* keep only 1 sign bit */
|
||||||
}
|
}
|
||||||
for (; borrow && i < m; ++i) {
|
for (; borrow && i < m; ++i) {
|
||||||
borrow = x[i] - borrow;
|
borrow = x[i] - borrow;
|
||||||
x[i] = borrow & MASK;
|
x[i] = borrow & PyLong_MASK;
|
||||||
borrow >>= SHIFT;
|
borrow >>= PyLong_SHIFT;
|
||||||
borrow &= 1;
|
borrow &= 1;
|
||||||
}
|
}
|
||||||
return borrow;
|
return borrow;
|
||||||
|
|
@ -1130,8 +1130,8 @@ muladd1(PyLongObject *a, wdigit n, wdigit extra)
|
||||||
return NULL;
|
return NULL;
|
||||||
for (i = 0; i < size_a; ++i) {
|
for (i = 0; i < size_a; ++i) {
|
||||||
carry += (twodigits)a->ob_digit[i] * n;
|
carry += (twodigits)a->ob_digit[i] * n;
|
||||||
z->ob_digit[i] = (digit) (carry & MASK);
|
z->ob_digit[i] = (digit) (carry & PyLong_MASK);
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
z->ob_digit[i] = (digit) carry;
|
z->ob_digit[i] = (digit) carry;
|
||||||
return long_normalize(z);
|
return long_normalize(z);
|
||||||
|
|
@ -1148,12 +1148,12 @@ inplace_divrem1(digit *pout, digit *pin, Py_ssize_t size, digit n)
|
||||||
{
|
{
|
||||||
twodigits rem = 0;
|
twodigits rem = 0;
|
||||||
|
|
||||||
assert(n > 0 && n <= MASK);
|
assert(n > 0 && n <= PyLong_MASK);
|
||||||
pin += size;
|
pin += size;
|
||||||
pout += size;
|
pout += size;
|
||||||
while (--size >= 0) {
|
while (--size >= 0) {
|
||||||
digit hi;
|
digit hi;
|
||||||
rem = (rem << SHIFT) + *--pin;
|
rem = (rem << PyLong_SHIFT) + *--pin;
|
||||||
*--pout = hi = (digit)(rem / n);
|
*--pout = hi = (digit)(rem / n);
|
||||||
rem -= hi * n;
|
rem -= hi * n;
|
||||||
}
|
}
|
||||||
|
|
@ -1170,7 +1170,7 @@ divrem1(PyLongObject *a, digit n, digit *prem)
|
||||||
const Py_ssize_t size = ABS(Py_SIZE(a));
|
const Py_ssize_t size = ABS(Py_SIZE(a));
|
||||||
PyLongObject *z;
|
PyLongObject *z;
|
||||||
|
|
||||||
assert(n > 0 && n <= MASK);
|
assert(n > 0 && n <= PyLong_MASK);
|
||||||
z = _PyLong_New(size);
|
z = _PyLong_New(size);
|
||||||
if (z == NULL)
|
if (z == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -1208,9 +1208,9 @@ long_format(PyObject *aa, int base, int addL)
|
||||||
i >>= 1;
|
i >>= 1;
|
||||||
}
|
}
|
||||||
i = 5 + (addL ? 1 : 0);
|
i = 5 + (addL ? 1 : 0);
|
||||||
j = size_a*SHIFT + bits-1;
|
j = size_a*PyLong_SHIFT + bits-1;
|
||||||
sz = i + j / bits;
|
sz = i + j / bits;
|
||||||
if (j / SHIFT < size_a || sz < i) {
|
if (j / PyLong_SHIFT < size_a || sz < i) {
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"long is too large to format");
|
"long is too large to format");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -1239,7 +1239,7 @@ long_format(PyObject *aa, int base, int addL)
|
||||||
|
|
||||||
for (i = 0; i < size_a; ++i) {
|
for (i = 0; i < size_a; ++i) {
|
||||||
accum |= (twodigits)a->ob_digit[i] << accumbits;
|
accum |= (twodigits)a->ob_digit[i] << accumbits;
|
||||||
accumbits += SHIFT;
|
accumbits += PyLong_SHIFT;
|
||||||
assert(accumbits >= basebits);
|
assert(accumbits >= basebits);
|
||||||
do {
|
do {
|
||||||
char cdigit = (char)(accum & (base - 1));
|
char cdigit = (char)(accum & (base - 1));
|
||||||
|
|
@ -1264,7 +1264,7 @@ long_format(PyObject *aa, int base, int addL)
|
||||||
int power = 1;
|
int power = 1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
unsigned long newpow = powbase * (unsigned long)base;
|
unsigned long newpow = powbase * (unsigned long)base;
|
||||||
if (newpow >> SHIFT) /* doesn't fit in a digit */
|
if (newpow >> PyLong_SHIFT) /* doesn't fit in a digit */
|
||||||
break;
|
break;
|
||||||
powbase = (digit)newpow;
|
powbase = (digit)newpow;
|
||||||
++power;
|
++power;
|
||||||
|
|
@ -1390,14 +1390,14 @@ long_from_binary_base(char **str, int base)
|
||||||
while (_PyLong_DigitValue[Py_CHARMASK(*p)] < base)
|
while (_PyLong_DigitValue[Py_CHARMASK(*p)] < base)
|
||||||
++p;
|
++p;
|
||||||
*str = p;
|
*str = p;
|
||||||
/* n <- # of Python digits needed, = ceiling(n/SHIFT). */
|
/* n <- # of Python digits needed, = ceiling(n/PyLong_SHIFT). */
|
||||||
n = (p - start) * bits_per_char + SHIFT - 1;
|
n = (p - start) * bits_per_char + PyLong_SHIFT - 1;
|
||||||
if (n / bits_per_char < p - start) {
|
if (n / bits_per_char < p - start) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"long string too large to convert");
|
"long string too large to convert");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
n = n / SHIFT;
|
n = n / PyLong_SHIFT;
|
||||||
z = _PyLong_New(n);
|
z = _PyLong_New(n);
|
||||||
if (z == NULL)
|
if (z == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -1412,16 +1412,16 @@ long_from_binary_base(char **str, int base)
|
||||||
assert(k >= 0 && k < base);
|
assert(k >= 0 && k < base);
|
||||||
accum |= (twodigits)(k << bits_in_accum);
|
accum |= (twodigits)(k << bits_in_accum);
|
||||||
bits_in_accum += bits_per_char;
|
bits_in_accum += bits_per_char;
|
||||||
if (bits_in_accum >= SHIFT) {
|
if (bits_in_accum >= PyLong_SHIFT) {
|
||||||
*pdigit++ = (digit)(accum & MASK);
|
*pdigit++ = (digit)(accum & PyLong_MASK);
|
||||||
assert(pdigit - z->ob_digit <= (int)n);
|
assert(pdigit - z->ob_digit <= (int)n);
|
||||||
accum >>= SHIFT;
|
accum >>= PyLong_SHIFT;
|
||||||
bits_in_accum -= SHIFT;
|
bits_in_accum -= PyLong_SHIFT;
|
||||||
assert(bits_in_accum < SHIFT);
|
assert(bits_in_accum < PyLong_SHIFT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bits_in_accum) {
|
if (bits_in_accum) {
|
||||||
assert(bits_in_accum <= SHIFT);
|
assert(bits_in_accum <= PyLong_SHIFT);
|
||||||
*pdigit++ = (digit)accum;
|
*pdigit++ = (digit)accum;
|
||||||
assert(pdigit - z->ob_digit <= (int)n);
|
assert(pdigit - z->ob_digit <= (int)n);
|
||||||
}
|
}
|
||||||
|
|
@ -1478,18 +1478,18 @@ First some math: the largest integer that can be expressed in N base-B digits
|
||||||
is B**N-1. Consequently, if we have an N-digit input in base B, the worst-
|
is B**N-1. Consequently, if we have an N-digit input in base B, the worst-
|
||||||
case number of Python digits needed to hold it is the smallest integer n s.t.
|
case number of Python digits needed to hold it is the smallest integer n s.t.
|
||||||
|
|
||||||
BASE**n-1 >= B**N-1 [or, adding 1 to both sides]
|
PyLong_BASE**n-1 >= B**N-1 [or, adding 1 to both sides]
|
||||||
BASE**n >= B**N [taking logs to base BASE]
|
PyLong_BASE**n >= B**N [taking logs to base PyLong_BASE]
|
||||||
n >= log(B**N)/log(BASE) = N * log(B)/log(BASE)
|
n >= log(B**N)/log(PyLong_BASE) = N * log(B)/log(PyLong_BASE)
|
||||||
|
|
||||||
The static array log_base_BASE[base] == log(base)/log(BASE) so we can compute
|
The static array log_base_PyLong_BASE[base] == log(base)/log(PyLong_BASE) so we can compute
|
||||||
this quickly. A Python long with that much space is reserved near the start,
|
this quickly. A Python long with that much space is reserved near the start,
|
||||||
and the result is computed into it.
|
and the result is computed into it.
|
||||||
|
|
||||||
The input string is actually treated as being in base base**i (i.e., i digits
|
The input string is actually treated as being in base base**i (i.e., i digits
|
||||||
are processed at a time), where two more static arrays hold:
|
are processed at a time), where two more static arrays hold:
|
||||||
|
|
||||||
convwidth_base[base] = the largest integer i such that base**i <= BASE
|
convwidth_base[base] = the largest integer i such that base**i <= PyLong_BASE
|
||||||
convmultmax_base[base] = base ** convwidth_base[base]
|
convmultmax_base[base] = base ** convwidth_base[base]
|
||||||
|
|
||||||
The first of these is the largest i such that i consecutive input digits
|
The first of these is the largest i such that i consecutive input digits
|
||||||
|
|
@ -1506,37 +1506,37 @@ where B = convmultmax_base[base].
|
||||||
Error analysis: as above, the number of Python digits `n` needed is worst-
|
Error analysis: as above, the number of Python digits `n` needed is worst-
|
||||||
case
|
case
|
||||||
|
|
||||||
n >= N * log(B)/log(BASE)
|
n >= N * log(B)/log(PyLong_BASE)
|
||||||
|
|
||||||
where `N` is the number of input digits in base `B`. This is computed via
|
where `N` is the number of input digits in base `B`. This is computed via
|
||||||
|
|
||||||
size_z = (Py_ssize_t)((scan - str) * log_base_BASE[base]) + 1;
|
size_z = (Py_ssize_t)((scan - str) * log_base_PyLong_BASE[base]) + 1;
|
||||||
|
|
||||||
below. Two numeric concerns are how much space this can waste, and whether
|
below. Two numeric concerns are how much space this can waste, and whether
|
||||||
the computed result can be too small. To be concrete, assume BASE = 2**15,
|
the computed result can be too small. To be concrete, assume PyLong_BASE = 2**15,
|
||||||
which is the default (and it's unlikely anyone changes that).
|
which is the default (and it's unlikely anyone changes that).
|
||||||
|
|
||||||
Waste isn't a problem: provided the first input digit isn't 0, the difference
|
Waste isn't a problem: provided the first input digit isn't 0, the difference
|
||||||
between the worst-case input with N digits and the smallest input with N
|
between the worst-case input with N digits and the smallest input with N
|
||||||
digits is about a factor of B, but B is small compared to BASE so at most
|
digits is about a factor of B, but B is small compared to PyLong_BASE so at most
|
||||||
one allocated Python digit can remain unused on that count. If
|
one allocated Python digit can remain unused on that count. If
|
||||||
N*log(B)/log(BASE) is mathematically an exact integer, then truncating that
|
N*log(B)/log(PyLong_BASE) is mathematically an exact integer, then truncating that
|
||||||
and adding 1 returns a result 1 larger than necessary. However, that can't
|
and adding 1 returns a result 1 larger than necessary. However, that can't
|
||||||
happen: whenever B is a power of 2, long_from_binary_base() is called
|
happen: whenever B is a power of 2, long_from_binary_base() is called
|
||||||
instead, and it's impossible for B**i to be an integer power of 2**15 when
|
instead, and it's impossible for B**i to be an integer power of 2**15 when
|
||||||
B is not a power of 2 (i.e., it's impossible for N*log(B)/log(BASE) to be
|
B is not a power of 2 (i.e., it's impossible for N*log(B)/log(PyLong_BASE) to be
|
||||||
an exact integer when B is not a power of 2, since B**i has a prime factor
|
an exact integer when B is not a power of 2, since B**i has a prime factor
|
||||||
other than 2 in that case, but (2**15)**j's only prime factor is 2).
|
other than 2 in that case, but (2**15)**j's only prime factor is 2).
|
||||||
|
|
||||||
The computed result can be too small if the true value of N*log(B)/log(BASE)
|
The computed result can be too small if the true value of N*log(B)/log(PyLong_BASE)
|
||||||
is a little bit larger than an exact integer, but due to roundoff errors (in
|
is a little bit larger than an exact integer, but due to roundoff errors (in
|
||||||
computing log(B), log(BASE), their quotient, and/or multiplying that by N)
|
computing log(B), log(PyLong_BASE), their quotient, and/or multiplying that by N)
|
||||||
yields a numeric result a little less than that integer. Unfortunately, "how
|
yields a numeric result a little less than that integer. Unfortunately, "how
|
||||||
close can a transcendental function get to an integer over some range?"
|
close can a transcendental function get to an integer over some range?"
|
||||||
questions are generally theoretically intractable. Computer analysis via
|
questions are generally theoretically intractable. Computer analysis via
|
||||||
continued fractions is practical: expand log(B)/log(BASE) via continued
|
continued fractions is practical: expand log(B)/log(PyLong_BASE) via continued
|
||||||
fractions, giving a sequence i/j of "the best" rational approximations. Then
|
fractions, giving a sequence i/j of "the best" rational approximations. Then
|
||||||
j*log(B)/log(BASE) is approximately equal to (the integer) i. This shows that
|
j*log(B)/log(PyLong_BASE) is approximately equal to (the integer) i. This shows that
|
||||||
we can get very close to being in trouble, but very rarely. For example,
|
we can get very close to being in trouble, but very rarely. For example,
|
||||||
76573 is a denominator in one of the continued-fraction approximations to
|
76573 is a denominator in one of the continued-fraction approximations to
|
||||||
log(10)/log(2**15), and indeed:
|
log(10)/log(2**15), and indeed:
|
||||||
|
|
@ -1562,19 +1562,19 @@ digit beyond the first.
|
||||||
digit *pz, *pzstop;
|
digit *pz, *pzstop;
|
||||||
char* scan;
|
char* scan;
|
||||||
|
|
||||||
static double log_base_BASE[37] = {0.0e0,};
|
static double log_base_PyLong_BASE[37] = {0.0e0,};
|
||||||
static int convwidth_base[37] = {0,};
|
static int convwidth_base[37] = {0,};
|
||||||
static twodigits convmultmax_base[37] = {0,};
|
static twodigits convmultmax_base[37] = {0,};
|
||||||
|
|
||||||
if (log_base_BASE[base] == 0.0) {
|
if (log_base_PyLong_BASE[base] == 0.0) {
|
||||||
twodigits convmax = base;
|
twodigits convmax = base;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
log_base_BASE[base] = log((double)base) /
|
log_base_PyLong_BASE[base] = log((double)base) /
|
||||||
log((double)BASE);
|
log((double)PyLong_BASE);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
twodigits next = convmax * base;
|
twodigits next = convmax * base;
|
||||||
if (next > BASE)
|
if (next > PyLong_BASE)
|
||||||
break;
|
break;
|
||||||
convmax = next;
|
convmax = next;
|
||||||
++i;
|
++i;
|
||||||
|
|
@ -1594,7 +1594,7 @@ digit beyond the first.
|
||||||
* need to initialize z->ob_digit -- no slot is read up before
|
* need to initialize z->ob_digit -- no slot is read up before
|
||||||
* being stored into.
|
* being stored into.
|
||||||
*/
|
*/
|
||||||
size_z = (Py_ssize_t)((scan - str) * log_base_BASE[base]) + 1;
|
size_z = (Py_ssize_t)((scan - str) * log_base_PyLong_BASE[base]) + 1;
|
||||||
/* Uncomment next line to test exceedingly rare copy code */
|
/* Uncomment next line to test exceedingly rare copy code */
|
||||||
/* size_z = 1; */
|
/* size_z = 1; */
|
||||||
assert(size_z > 0);
|
assert(size_z > 0);
|
||||||
|
|
@ -1616,7 +1616,7 @@ digit beyond the first.
|
||||||
for (i = 1; i < convwidth && str != scan; ++i, ++str) {
|
for (i = 1; i < convwidth && str != scan; ++i, ++str) {
|
||||||
c = (twodigits)(c * base +
|
c = (twodigits)(c * base +
|
||||||
_PyLong_DigitValue[Py_CHARMASK(*str)]);
|
_PyLong_DigitValue[Py_CHARMASK(*str)]);
|
||||||
assert(c < BASE);
|
assert(c < PyLong_BASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
convmult = convmultmax;
|
convmult = convmultmax;
|
||||||
|
|
@ -1634,12 +1634,12 @@ digit beyond the first.
|
||||||
pzstop = pz + Py_SIZE(z);
|
pzstop = pz + Py_SIZE(z);
|
||||||
for (; pz < pzstop; ++pz) {
|
for (; pz < pzstop; ++pz) {
|
||||||
c += (twodigits)*pz * convmult;
|
c += (twodigits)*pz * convmult;
|
||||||
*pz = (digit)(c & MASK);
|
*pz = (digit)(c & PyLong_MASK);
|
||||||
c >>= SHIFT;
|
c >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
/* carry off the current end? */
|
/* carry off the current end? */
|
||||||
if (c) {
|
if (c) {
|
||||||
assert(c < BASE);
|
assert(c < PyLong_BASE);
|
||||||
if (Py_SIZE(z) < size_z) {
|
if (Py_SIZE(z) < size_z) {
|
||||||
*pz = (digit)c;
|
*pz = (digit)c;
|
||||||
++Py_SIZE(z);
|
++Py_SIZE(z);
|
||||||
|
|
@ -1783,7 +1783,7 @@ static PyLongObject *
|
||||||
x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
|
x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
|
||||||
{
|
{
|
||||||
Py_ssize_t size_v = ABS(Py_SIZE(v1)), size_w = ABS(Py_SIZE(w1));
|
Py_ssize_t size_v = ABS(Py_SIZE(v1)), size_w = ABS(Py_SIZE(w1));
|
||||||
digit d = (digit) ((twodigits)BASE / (w1->ob_digit[size_w-1] + 1));
|
digit d = (digit) ((twodigits)PyLong_BASE / (w1->ob_digit[size_w-1] + 1));
|
||||||
PyLongObject *v = mul1(v1, d);
|
PyLongObject *v = mul1(v1, d);
|
||||||
PyLongObject *w = mul1(w1, d);
|
PyLongObject *w = mul1(w1, d);
|
||||||
PyLongObject *a;
|
PyLongObject *a;
|
||||||
|
|
@ -1815,28 +1815,28 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
|
||||||
break;
|
break;
|
||||||
})
|
})
|
||||||
if (vj == w->ob_digit[size_w-1])
|
if (vj == w->ob_digit[size_w-1])
|
||||||
q = MASK;
|
q = PyLong_MASK;
|
||||||
else
|
else
|
||||||
q = (((twodigits)vj << SHIFT) + v->ob_digit[j-1]) /
|
q = (((twodigits)vj << PyLong_SHIFT) + v->ob_digit[j-1]) /
|
||||||
w->ob_digit[size_w-1];
|
w->ob_digit[size_w-1];
|
||||||
|
|
||||||
while (w->ob_digit[size_w-2]*q >
|
while (w->ob_digit[size_w-2]*q >
|
||||||
((
|
((
|
||||||
((twodigits)vj << SHIFT)
|
((twodigits)vj << PyLong_SHIFT)
|
||||||
+ v->ob_digit[j-1]
|
+ v->ob_digit[j-1]
|
||||||
- q*w->ob_digit[size_w-1]
|
- q*w->ob_digit[size_w-1]
|
||||||
) << SHIFT)
|
) << PyLong_SHIFT)
|
||||||
+ v->ob_digit[j-2])
|
+ v->ob_digit[j-2])
|
||||||
--q;
|
--q;
|
||||||
|
|
||||||
for (i = 0; i < size_w && i+k < size_v; ++i) {
|
for (i = 0; i < size_w && i+k < size_v; ++i) {
|
||||||
twodigits z = w->ob_digit[i] * q;
|
twodigits z = w->ob_digit[i] * q;
|
||||||
digit zz = (digit) (z >> SHIFT);
|
digit zz = (digit) (z >> PyLong_SHIFT);
|
||||||
carry += v->ob_digit[i+k] - z
|
carry += v->ob_digit[i+k] - z
|
||||||
+ ((twodigits)zz << SHIFT);
|
+ ((twodigits)zz << PyLong_SHIFT);
|
||||||
v->ob_digit[i+k] = (digit)(carry & MASK);
|
v->ob_digit[i+k] = (digit)(carry & PyLong_MASK);
|
||||||
carry = Py_ARITHMETIC_RIGHT_SHIFT(BASE_TWODIGITS_TYPE,
|
carry = Py_ARITHMETIC_RIGHT_SHIFT(PyLong_BASE_TWODIGITS_TYPE,
|
||||||
carry, SHIFT);
|
carry, PyLong_SHIFT);
|
||||||
carry -= zz;
|
carry -= zz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1853,10 +1853,10 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
|
||||||
carry = 0;
|
carry = 0;
|
||||||
for (i = 0; i < size_w && i+k < size_v; ++i) {
|
for (i = 0; i < size_w && i+k < size_v; ++i) {
|
||||||
carry += v->ob_digit[i+k] + w->ob_digit[i];
|
carry += v->ob_digit[i+k] + w->ob_digit[i];
|
||||||
v->ob_digit[i+k] = (digit)(carry & MASK);
|
v->ob_digit[i+k] = (digit)(carry & PyLong_MASK);
|
||||||
carry = Py_ARITHMETIC_RIGHT_SHIFT(
|
carry = Py_ARITHMETIC_RIGHT_SHIFT(
|
||||||
BASE_TWODIGITS_TYPE,
|
PyLong_BASE_TWODIGITS_TYPE,
|
||||||
carry, SHIFT);
|
carry, PyLong_SHIFT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} /* for j, k */
|
} /* for j, k */
|
||||||
|
|
@ -1940,13 +1940,13 @@ long_hash(PyLongObject *v)
|
||||||
sign = -1;
|
sign = -1;
|
||||||
i = -(i);
|
i = -(i);
|
||||||
}
|
}
|
||||||
#define LONG_BIT_SHIFT (8*sizeof(long) - SHIFT)
|
#define LONG_BIT_PyLong_SHIFT (8*sizeof(long) - PyLong_SHIFT)
|
||||||
/* The following loop produces a C long x such that (unsigned long)x
|
/* The following loop produces a C long x such that (unsigned long)x
|
||||||
is congruent to the absolute value of v modulo ULONG_MAX. The
|
is congruent to the absolute value of v modulo ULONG_MAX. The
|
||||||
resulting x is nonzero if and only if v is. */
|
resulting x is nonzero if and only if v is. */
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
/* Force a native long #-bits (32 or 64) circular shift */
|
/* Force a native long #-bits (32 or 64) circular shift */
|
||||||
x = ((x << SHIFT) & ~MASK) | ((x >> LONG_BIT_SHIFT) & MASK);
|
x = ((x << PyLong_SHIFT) & ~PyLong_MASK) | ((x >> LONG_BIT_PyLong_SHIFT) & PyLong_MASK);
|
||||||
x += v->ob_digit[i];
|
x += v->ob_digit[i];
|
||||||
/* If the addition above overflowed (thinking of x as
|
/* If the addition above overflowed (thinking of x as
|
||||||
unsigned), we compensate by incrementing. This preserves
|
unsigned), we compensate by incrementing. This preserves
|
||||||
|
|
@ -1954,7 +1954,7 @@ long_hash(PyLongObject *v)
|
||||||
if ((unsigned long)x < v->ob_digit[i])
|
if ((unsigned long)x < v->ob_digit[i])
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
#undef LONG_BIT_SHIFT
|
#undef LONG_BIT_PyLong_SHIFT
|
||||||
x = x * sign;
|
x = x * sign;
|
||||||
if (x == -1)
|
if (x == -1)
|
||||||
x = -2;
|
x = -2;
|
||||||
|
|
@ -1984,13 +1984,13 @@ x_add(PyLongObject *a, PyLongObject *b)
|
||||||
return NULL;
|
return NULL;
|
||||||
for (i = 0; i < size_b; ++i) {
|
for (i = 0; i < size_b; ++i) {
|
||||||
carry += a->ob_digit[i] + b->ob_digit[i];
|
carry += a->ob_digit[i] + b->ob_digit[i];
|
||||||
z->ob_digit[i] = carry & MASK;
|
z->ob_digit[i] = carry & PyLong_MASK;
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
for (; i < size_a; ++i) {
|
for (; i < size_a; ++i) {
|
||||||
carry += a->ob_digit[i];
|
carry += a->ob_digit[i];
|
||||||
z->ob_digit[i] = carry & MASK;
|
z->ob_digit[i] = carry & PyLong_MASK;
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
z->ob_digit[i] = carry;
|
z->ob_digit[i] = carry;
|
||||||
return long_normalize(z);
|
return long_normalize(z);
|
||||||
|
|
@ -2033,16 +2033,16 @@ x_sub(PyLongObject *a, PyLongObject *b)
|
||||||
return NULL;
|
return NULL;
|
||||||
for (i = 0; i < size_b; ++i) {
|
for (i = 0; i < size_b; ++i) {
|
||||||
/* The following assumes unsigned arithmetic
|
/* The following assumes unsigned arithmetic
|
||||||
works module 2**N for some N>SHIFT. */
|
works module 2**N for some N>PyLong_SHIFT. */
|
||||||
borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
|
borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
|
||||||
z->ob_digit[i] = borrow & MASK;
|
z->ob_digit[i] = borrow & PyLong_MASK;
|
||||||
borrow >>= SHIFT;
|
borrow >>= PyLong_SHIFT;
|
||||||
borrow &= 1; /* Keep only one sign bit */
|
borrow &= 1; /* Keep only one sign bit */
|
||||||
}
|
}
|
||||||
for (; i < size_a; ++i) {
|
for (; i < size_a; ++i) {
|
||||||
borrow = a->ob_digit[i] - borrow;
|
borrow = a->ob_digit[i] - borrow;
|
||||||
z->ob_digit[i] = borrow & MASK;
|
z->ob_digit[i] = borrow & PyLong_MASK;
|
||||||
borrow >>= SHIFT;
|
borrow >>= PyLong_SHIFT;
|
||||||
borrow &= 1; /* Keep only one sign bit */
|
borrow &= 1; /* Keep only one sign bit */
|
||||||
}
|
}
|
||||||
assert(borrow == 0);
|
assert(borrow == 0);
|
||||||
|
|
@ -2140,9 +2140,9 @@ x_mul(PyLongObject *a, PyLongObject *b)
|
||||||
})
|
})
|
||||||
|
|
||||||
carry = *pz + f * f;
|
carry = *pz + f * f;
|
||||||
*pz++ = (digit)(carry & MASK);
|
*pz++ = (digit)(carry & PyLong_MASK);
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
assert(carry <= MASK);
|
assert(carry <= PyLong_MASK);
|
||||||
|
|
||||||
/* Now f is added in twice in each column of the
|
/* Now f is added in twice in each column of the
|
||||||
* pyramid it appears. Same as adding f<<1 once.
|
* pyramid it appears. Same as adding f<<1 once.
|
||||||
|
|
@ -2150,18 +2150,18 @@ x_mul(PyLongObject *a, PyLongObject *b)
|
||||||
f <<= 1;
|
f <<= 1;
|
||||||
while (pa < paend) {
|
while (pa < paend) {
|
||||||
carry += *pz + *pa++ * f;
|
carry += *pz + *pa++ * f;
|
||||||
*pz++ = (digit)(carry & MASK);
|
*pz++ = (digit)(carry & PyLong_MASK);
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
assert(carry <= (MASK << 1));
|
assert(carry <= (PyLong_MASK << 1));
|
||||||
}
|
}
|
||||||
if (carry) {
|
if (carry) {
|
||||||
carry += *pz;
|
carry += *pz;
|
||||||
*pz++ = (digit)(carry & MASK);
|
*pz++ = (digit)(carry & PyLong_MASK);
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
if (carry)
|
if (carry)
|
||||||
*pz += (digit)(carry & MASK);
|
*pz += (digit)(carry & PyLong_MASK);
|
||||||
assert((carry >> SHIFT) == 0);
|
assert((carry >> PyLong_SHIFT) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { /* a is not the same as b -- gradeschool long mult */
|
else { /* a is not the same as b -- gradeschool long mult */
|
||||||
|
|
@ -2179,13 +2179,13 @@ x_mul(PyLongObject *a, PyLongObject *b)
|
||||||
|
|
||||||
while (pb < pbend) {
|
while (pb < pbend) {
|
||||||
carry += *pz + *pb++ * f;
|
carry += *pz + *pb++ * f;
|
||||||
*pz++ = (digit)(carry & MASK);
|
*pz++ = (digit)(carry & PyLong_MASK);
|
||||||
carry >>= SHIFT;
|
carry >>= PyLong_SHIFT;
|
||||||
assert(carry <= MASK);
|
assert(carry <= PyLong_MASK);
|
||||||
}
|
}
|
||||||
if (carry)
|
if (carry)
|
||||||
*pz += (digit)(carry & MASK);
|
*pz += (digit)(carry & PyLong_MASK);
|
||||||
assert((carry >> SHIFT) == 0);
|
assert((carry >> PyLong_SHIFT) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return long_normalize(z);
|
return long_normalize(z);
|
||||||
|
|
@ -2304,7 +2304,7 @@ k_mul(PyLongObject *a, PyLongObject *b)
|
||||||
* 4. Subtract al*bl from the result, starting at shift. This may
|
* 4. Subtract al*bl from the result, starting at shift. This may
|
||||||
* underflow (borrow out of the high digit), but we don't care:
|
* underflow (borrow out of the high digit), but we don't care:
|
||||||
* we're effectively doing unsigned arithmetic mod
|
* we're effectively doing unsigned arithmetic mod
|
||||||
* BASE**(sizea + sizeb), and so long as the *final* result fits,
|
* PyLong_BASE**(sizea + sizeb), and so long as the *final* result fits,
|
||||||
* borrows and carries out of the high digit can be ignored.
|
* borrows and carries out of the high digit can be ignored.
|
||||||
* 5. Subtract ah*bh from the result, starting at shift.
|
* 5. Subtract ah*bh from the result, starting at shift.
|
||||||
* 6. Compute (ah+al)*(bh+bl), and add it into the result starting
|
* 6. Compute (ah+al)*(bh+bl), and add it into the result starting
|
||||||
|
|
@ -2431,7 +2431,7 @@ the question reduces to whether asize digits is enough to hold
|
||||||
(asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits. If asize < bsize,
|
(asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits. If asize < bsize,
|
||||||
then we're asking whether asize digits >= f(bsize/2) digits + 2 bits. By #4,
|
then we're asking whether asize digits >= f(bsize/2) digits + 2 bits. By #4,
|
||||||
asize is at least f(bsize/2)+1 digits, so this in turn reduces to whether 1
|
asize is at least f(bsize/2)+1 digits, so this in turn reduces to whether 1
|
||||||
digit is enough to hold 2 bits. This is so since SHIFT=15 >= 2. If
|
digit is enough to hold 2 bits. This is so since PyLong_SHIFT=15 >= 2. If
|
||||||
asize == bsize, then we're asking whether bsize digits is enough to hold
|
asize == bsize, then we're asking whether bsize digits is enough to hold
|
||||||
c(bsize/2) digits + 2 bits, or equivalently (by #1) whether f(bsize/2) digits
|
c(bsize/2) digits + 2 bits, or equivalently (by #1) whether f(bsize/2) digits
|
||||||
is enough to hold 2 bits. This is so if bsize >= 2, which holds because
|
is enough to hold 2 bits. This is so if bsize >= 2, which holds because
|
||||||
|
|
@ -2643,15 +2643,15 @@ long_true_divide(PyObject *v, PyObject *w)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* True value is very close to ad/bd * 2**(SHIFT*(aexp-bexp)) */
|
/* True value is very close to ad/bd * 2**(PyLong_SHIFT*(aexp-bexp)) */
|
||||||
ad /= bd; /* overflow/underflow impossible here */
|
ad /= bd; /* overflow/underflow impossible here */
|
||||||
aexp -= bexp;
|
aexp -= bexp;
|
||||||
if (aexp > INT_MAX / SHIFT)
|
if (aexp > INT_MAX / PyLong_SHIFT)
|
||||||
goto overflow;
|
goto overflow;
|
||||||
else if (aexp < -(INT_MAX / SHIFT))
|
else if (aexp < -(INT_MAX / PyLong_SHIFT))
|
||||||
return PyFloat_FromDouble(0.0); /* underflow to 0 */
|
return PyFloat_FromDouble(0.0); /* underflow to 0 */
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ad = ldexp(ad, aexp * SHIFT);
|
ad = ldexp(ad, aexp * PyLong_SHIFT);
|
||||||
if (Py_OVERFLOWED(ad)) /* ignore underflow to 0.0 */
|
if (Py_OVERFLOWED(ad)) /* ignore underflow to 0.0 */
|
||||||
goto overflow;
|
goto overflow;
|
||||||
return PyFloat_FromDouble(ad);
|
return PyFloat_FromDouble(ad);
|
||||||
|
|
@ -2837,7 +2837,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x)
|
||||||
for (i = Py_SIZE(b) - 1; i >= 0; --i) {
|
for (i = Py_SIZE(b) - 1; i >= 0; --i) {
|
||||||
digit bi = b->ob_digit[i];
|
digit bi = b->ob_digit[i];
|
||||||
|
|
||||||
for (j = 1 << (SHIFT-1); j != 0; j >>= 1) {
|
for (j = 1 << (PyLong_SHIFT-1); j != 0; j >>= 1) {
|
||||||
MULT(z, z, z)
|
MULT(z, z, z)
|
||||||
if (bi & j)
|
if (bi & j)
|
||||||
MULT(z, a, z)
|
MULT(z, a, z)
|
||||||
|
|
@ -2854,7 +2854,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x)
|
||||||
for (i = Py_SIZE(b) - 1; i >= 0; --i) {
|
for (i = Py_SIZE(b) - 1; i >= 0; --i) {
|
||||||
const digit bi = b->ob_digit[i];
|
const digit bi = b->ob_digit[i];
|
||||||
|
|
||||||
for (j = SHIFT - 5; j >= 0; j -= 5) {
|
for (j = PyLong_SHIFT - 5; j >= 0; j -= 5) {
|
||||||
const int index = (bi >> j) & 0x1f;
|
const int index = (bi >> j) & 0x1f;
|
||||||
for (k = 0; k < 5; ++k)
|
for (k = 0; k < 5; ++k)
|
||||||
MULT(z, z, z)
|
MULT(z, z, z)
|
||||||
|
|
@ -2973,7 +2973,7 @@ long_rshift(PyLongObject *v, PyLongObject *w)
|
||||||
"negative shift count");
|
"negative shift count");
|
||||||
goto rshift_error;
|
goto rshift_error;
|
||||||
}
|
}
|
||||||
wordshift = shiftby / SHIFT;
|
wordshift = shiftby / PyLong_SHIFT;
|
||||||
newsize = ABS(Py_SIZE(a)) - wordshift;
|
newsize = ABS(Py_SIZE(a)) - wordshift;
|
||||||
if (newsize <= 0) {
|
if (newsize <= 0) {
|
||||||
z = _PyLong_New(0);
|
z = _PyLong_New(0);
|
||||||
|
|
@ -2981,10 +2981,10 @@ long_rshift(PyLongObject *v, PyLongObject *w)
|
||||||
Py_DECREF(b);
|
Py_DECREF(b);
|
||||||
return (PyObject *)z;
|
return (PyObject *)z;
|
||||||
}
|
}
|
||||||
loshift = shiftby % SHIFT;
|
loshift = shiftby % PyLong_SHIFT;
|
||||||
hishift = SHIFT - loshift;
|
hishift = PyLong_SHIFT - loshift;
|
||||||
lomask = ((digit)1 << hishift) - 1;
|
lomask = ((digit)1 << hishift) - 1;
|
||||||
himask = MASK ^ lomask;
|
himask = PyLong_MASK ^ lomask;
|
||||||
z = _PyLong_New(newsize);
|
z = _PyLong_New(newsize);
|
||||||
if (z == NULL)
|
if (z == NULL)
|
||||||
goto rshift_error;
|
goto rshift_error;
|
||||||
|
|
@ -3029,9 +3029,9 @@ long_lshift(PyObject *v, PyObject *w)
|
||||||
"outrageous left shift count");
|
"outrageous left shift count");
|
||||||
goto lshift_error;
|
goto lshift_error;
|
||||||
}
|
}
|
||||||
/* wordshift, remshift = divmod(shiftby, SHIFT) */
|
/* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */
|
||||||
wordshift = (int)shiftby / SHIFT;
|
wordshift = (int)shiftby / PyLong_SHIFT;
|
||||||
remshift = (int)shiftby - wordshift * SHIFT;
|
remshift = (int)shiftby - wordshift * PyLong_SHIFT;
|
||||||
|
|
||||||
oldsize = ABS(a->ob_size);
|
oldsize = ABS(a->ob_size);
|
||||||
newsize = oldsize + wordshift;
|
newsize = oldsize + wordshift;
|
||||||
|
|
@ -3047,8 +3047,8 @@ long_lshift(PyObject *v, PyObject *w)
|
||||||
accum = 0;
|
accum = 0;
|
||||||
for (i = wordshift, j = 0; j < oldsize; i++, j++) {
|
for (i = wordshift, j = 0; j < oldsize; i++, j++) {
|
||||||
accum |= (twodigits)a->ob_digit[j] << remshift;
|
accum |= (twodigits)a->ob_digit[j] << remshift;
|
||||||
z->ob_digit[i] = (digit)(accum & MASK);
|
z->ob_digit[i] = (digit)(accum & PyLong_MASK);
|
||||||
accum >>= SHIFT;
|
accum >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
if (remshift)
|
if (remshift)
|
||||||
z->ob_digit[newsize-1] = (digit)accum;
|
z->ob_digit[newsize-1] = (digit)accum;
|
||||||
|
|
@ -3069,7 +3069,7 @@ long_bitwise(PyLongObject *a,
|
||||||
int op, /* '&', '|', '^' */
|
int op, /* '&', '|', '^' */
|
||||||
PyLongObject *b)
|
PyLongObject *b)
|
||||||
{
|
{
|
||||||
digit maska, maskb; /* 0 or MASK */
|
digit maska, maskb; /* 0 or PyLong_MASK */
|
||||||
int negz;
|
int negz;
|
||||||
Py_ssize_t size_a, size_b, size_z;
|
Py_ssize_t size_a, size_b, size_z;
|
||||||
PyLongObject *z;
|
PyLongObject *z;
|
||||||
|
|
@ -3081,7 +3081,7 @@ long_bitwise(PyLongObject *a,
|
||||||
a = (PyLongObject *) long_invert(a);
|
a = (PyLongObject *) long_invert(a);
|
||||||
if (a == NULL)
|
if (a == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
maska = MASK;
|
maska = PyLong_MASK;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Py_INCREF(a);
|
Py_INCREF(a);
|
||||||
|
|
@ -3093,7 +3093,7 @@ long_bitwise(PyLongObject *a,
|
||||||
Py_DECREF(a);
|
Py_DECREF(a);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
maskb = MASK;
|
maskb = PyLong_MASK;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Py_INCREF(b);
|
Py_INCREF(b);
|
||||||
|
|
@ -3104,23 +3104,23 @@ long_bitwise(PyLongObject *a,
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case '^':
|
case '^':
|
||||||
if (maska != maskb) {
|
if (maska != maskb) {
|
||||||
maska ^= MASK;
|
maska ^= PyLong_MASK;
|
||||||
negz = -1;
|
negz = -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '&':
|
case '&':
|
||||||
if (maska && maskb) {
|
if (maska && maskb) {
|
||||||
op = '|';
|
op = '|';
|
||||||
maska ^= MASK;
|
maska ^= PyLong_MASK;
|
||||||
maskb ^= MASK;
|
maskb ^= PyLong_MASK;
|
||||||
negz = -1;
|
negz = -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '|':
|
case '|':
|
||||||
if (maska || maskb) {
|
if (maska || maskb) {
|
||||||
op = '&';
|
op = '&';
|
||||||
maska ^= MASK;
|
maska ^= PyLong_MASK;
|
||||||
maskb ^= MASK;
|
maskb ^= PyLong_MASK;
|
||||||
negz = -1;
|
negz = -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -397,6 +397,57 @@ PyObject *PyUnicode_FromUnicode(const Py_UNICODE *u,
|
||||||
return (PyObject *)unicode;
|
return (PyObject *)unicode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *PyUnicode_FromStringAndSize(const char *u, Py_ssize_t size)
|
||||||
|
{
|
||||||
|
PyUnicodeObject *unicode;
|
||||||
|
/* If the Unicode data is known at construction time, we can apply
|
||||||
|
some optimizations which share commonly used objects.
|
||||||
|
Also, this means the input must be UTF-8, so fall back to the
|
||||||
|
UTF-8 decoder at the end. */
|
||||||
|
if (u != NULL) {
|
||||||
|
|
||||||
|
/* Optimization for empty strings */
|
||||||
|
if (size == 0 && unicode_empty != NULL) {
|
||||||
|
Py_INCREF(unicode_empty);
|
||||||
|
return (PyObject *)unicode_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single characters are shared when using this constructor.
|
||||||
|
Restrict to ASCII, since the input must be UTF-8. */
|
||||||
|
if (size == 1 && Py_CHARMASK(*u) < 128) {
|
||||||
|
unicode = unicode_latin1[Py_CHARMASK(*u)];
|
||||||
|
if (!unicode) {
|
||||||
|
unicode = _PyUnicode_New(1);
|
||||||
|
if (!unicode)
|
||||||
|
return NULL;
|
||||||
|
unicode->str[0] = Py_CHARMASK(*u);
|
||||||
|
unicode_latin1[Py_CHARMASK(*u)] = unicode;
|
||||||
|
}
|
||||||
|
Py_INCREF(unicode);
|
||||||
|
return (PyObject *)unicode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyUnicode_DecodeUTF8(u, size, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
unicode = _PyUnicode_New(size);
|
||||||
|
if (!unicode)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (PyObject *)unicode;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *PyUnicode_FromString(const char *u)
|
||||||
|
{
|
||||||
|
size_t size = strlen(u);
|
||||||
|
if (size > PY_SSIZE_T_MAX) {
|
||||||
|
PyErr_SetString(PyExc_OverflowError, "input too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyUnicode_FromStringAndSize(u, size);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_WCHAR_H
|
#ifdef HAVE_WCHAR_H
|
||||||
|
|
||||||
PyObject *PyUnicode_FromWideChar(register const wchar_t *w,
|
PyObject *PyUnicode_FromWideChar(register const wchar_t *w,
|
||||||
|
|
@ -429,6 +480,420 @@ PyObject *PyUnicode_FromWideChar(register const wchar_t *w,
|
||||||
return (PyObject *)unicode;
|
return (PyObject *)unicode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
makefmt(char *fmt, int longflag, int size_tflag, int zeropad, int width, int precision, char c)
|
||||||
|
{
|
||||||
|
*fmt++ = '%';
|
||||||
|
if (width) {
|
||||||
|
if (zeropad)
|
||||||
|
*fmt++ = '0';
|
||||||
|
fmt += sprintf(fmt, "%d", width);
|
||||||
|
}
|
||||||
|
if (precision)
|
||||||
|
fmt += sprintf(fmt, ".%d", precision);
|
||||||
|
if (longflag)
|
||||||
|
*fmt++ = 'l';
|
||||||
|
else if (size_tflag) {
|
||||||
|
char *f = PY_FORMAT_SIZE_T;
|
||||||
|
while (*f)
|
||||||
|
*fmt++ = *f++;
|
||||||
|
}
|
||||||
|
*fmt++ = c;
|
||||||
|
*fmt = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
#define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyUnicode_FromFormatV(const char *format, va_list vargs)
|
||||||
|
{
|
||||||
|
va_list count;
|
||||||
|
Py_ssize_t callcount = 0;
|
||||||
|
PyObject **callresults = NULL;
|
||||||
|
PyObject **callresult = NULL;
|
||||||
|
Py_ssize_t n = 0;
|
||||||
|
int width = 0;
|
||||||
|
int precision = 0;
|
||||||
|
int zeropad;
|
||||||
|
const char* f;
|
||||||
|
Py_UNICODE *s;
|
||||||
|
PyObject *string;
|
||||||
|
/* used by sprintf */
|
||||||
|
char buffer[21];
|
||||||
|
/* use abuffer instead of buffer, if we need more space
|
||||||
|
* (which can happen if there's a format specifier with width). */
|
||||||
|
char *abuffer = NULL;
|
||||||
|
char *realbuffer;
|
||||||
|
Py_ssize_t abuffersize = 0;
|
||||||
|
char fmt[60]; /* should be enough for %0width.precisionld */
|
||||||
|
const char *copy;
|
||||||
|
|
||||||
|
#ifdef VA_LIST_IS_ARRAY
|
||||||
|
Py_MEMCPY(count, vargs, sizeof(va_list));
|
||||||
|
#else
|
||||||
|
#ifdef __va_copy
|
||||||
|
__va_copy(count, vargs);
|
||||||
|
#else
|
||||||
|
count = vargs;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
/* step 1: count the number of %S/%R format specifications
|
||||||
|
* (we call PyObject_Str()/PyObject_Repr() for these objects
|
||||||
|
* once during step 3 and put the result in an array) */
|
||||||
|
for (f = format; *f; f++) {
|
||||||
|
if (*f == '%' && (*(f+1)=='S' || *(f+1)=='R'))
|
||||||
|
++callcount;
|
||||||
|
}
|
||||||
|
/* step 2: allocate memory for the results of
|
||||||
|
* PyObject_Str()/PyObject_Repr() calls */
|
||||||
|
if (callcount) {
|
||||||
|
callresults = PyMem_Malloc(sizeof(PyObject *)*callcount);
|
||||||
|
if (!callresults) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
callresult = callresults;
|
||||||
|
}
|
||||||
|
/* step 3: figure out how large a buffer we need */
|
||||||
|
for (f = format; *f; f++) {
|
||||||
|
if (*f == '%') {
|
||||||
|
const char* p = f;
|
||||||
|
width = 0;
|
||||||
|
while (isdigit(*f))
|
||||||
|
width = (width*10) + *f++ - '0';
|
||||||
|
while (*++f && *f != '%' && !isalpha(*f))
|
||||||
|
;
|
||||||
|
|
||||||
|
/* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since
|
||||||
|
* they don't affect the amount of space we reserve.
|
||||||
|
*/
|
||||||
|
if ((*f == 'l' || *f == 'z') &&
|
||||||
|
(f[1] == 'd' || f[1] == 'u'))
|
||||||
|
++f;
|
||||||
|
|
||||||
|
switch (*f) {
|
||||||
|
case 'c':
|
||||||
|
(void)va_arg(count, int);
|
||||||
|
/* fall through... */
|
||||||
|
case '%':
|
||||||
|
n++;
|
||||||
|
break;
|
||||||
|
case 'd': case 'u': case 'i': case 'x':
|
||||||
|
(void) va_arg(count, int);
|
||||||
|
/* 20 bytes is enough to hold a 64-bit
|
||||||
|
integer. Decimal takes the most space.
|
||||||
|
This isn't enough for octal.
|
||||||
|
If a width is specified we need more
|
||||||
|
(which we allocate later). */
|
||||||
|
if (width < 20)
|
||||||
|
width = 20;
|
||||||
|
n += width;
|
||||||
|
if (abuffersize < width)
|
||||||
|
abuffersize = width;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
/* UTF-8 */
|
||||||
|
unsigned char*s;
|
||||||
|
s = va_arg(count, unsigned char*);
|
||||||
|
while (*s) {
|
||||||
|
if (*s < 128) {
|
||||||
|
n++; s++;
|
||||||
|
} else if (*s < 0xc0) {
|
||||||
|
/* invalid UTF-8 */
|
||||||
|
n++; s++;
|
||||||
|
} else if (*s < 0xc0) {
|
||||||
|
n++;
|
||||||
|
s++; if(!*s)break;
|
||||||
|
s++;
|
||||||
|
} else if (*s < 0xe0) {
|
||||||
|
n++;
|
||||||
|
s++; if(!*s)break;
|
||||||
|
s++; if(!*s)break;
|
||||||
|
s++;
|
||||||
|
} else {
|
||||||
|
#ifdef Py_UNICODE_WIDE
|
||||||
|
n++;
|
||||||
|
#else
|
||||||
|
n+=2;
|
||||||
|
#endif
|
||||||
|
s++; if(!*s)break;
|
||||||
|
s++; if(!*s)break;
|
||||||
|
s++; if(!*s)break;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'U':
|
||||||
|
{
|
||||||
|
PyObject *obj = va_arg(count, PyObject *);
|
||||||
|
assert(obj && PyUnicode_Check(obj));
|
||||||
|
n += PyUnicode_GET_SIZE(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'V':
|
||||||
|
{
|
||||||
|
PyObject *obj = va_arg(count, PyObject *);
|
||||||
|
const char *str = va_arg(count, const char *);
|
||||||
|
assert(obj || str);
|
||||||
|
assert(!obj || PyUnicode_Check(obj));
|
||||||
|
if (obj)
|
||||||
|
n += PyUnicode_GET_SIZE(obj);
|
||||||
|
else
|
||||||
|
n += strlen(str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'S':
|
||||||
|
{
|
||||||
|
PyObject *obj = va_arg(count, PyObject *);
|
||||||
|
PyObject *str;
|
||||||
|
assert(obj);
|
||||||
|
str = PyObject_Str(obj);
|
||||||
|
if (!str)
|
||||||
|
goto fail;
|
||||||
|
n += PyUnicode_GET_SIZE(str);
|
||||||
|
/* Remember the str and switch to the next slot */
|
||||||
|
*callresult++ = str;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'R':
|
||||||
|
{
|
||||||
|
PyObject *obj = va_arg(count, PyObject *);
|
||||||
|
PyObject *repr;
|
||||||
|
assert(obj);
|
||||||
|
repr = PyObject_Repr(obj);
|
||||||
|
if (!repr)
|
||||||
|
goto fail;
|
||||||
|
n += PyUnicode_GET_SIZE(repr);
|
||||||
|
/* Remember the repr and switch to the next slot */
|
||||||
|
*callresult++ = repr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'p':
|
||||||
|
(void) va_arg(count, int);
|
||||||
|
/* maximum 64-bit pointer representation:
|
||||||
|
* 0xffffffffffffffff
|
||||||
|
* so 19 characters is enough.
|
||||||
|
* XXX I count 18 -- what's the extra for?
|
||||||
|
*/
|
||||||
|
n += 19;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* if we stumble upon an unknown
|
||||||
|
formatting code, copy the rest of
|
||||||
|
the format string to the output
|
||||||
|
string. (we cannot just skip the
|
||||||
|
code, since there's no way to know
|
||||||
|
what's in the argument list) */
|
||||||
|
n += strlen(p);
|
||||||
|
goto expand;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
expand:
|
||||||
|
if (abuffersize > 20) {
|
||||||
|
abuffer = PyMem_Malloc(abuffersize);
|
||||||
|
if (!abuffer) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
realbuffer = abuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
realbuffer = buffer;
|
||||||
|
/* step 4: fill the buffer */
|
||||||
|
/* Since we've analyzed how much space we need for the worst case,
|
||||||
|
we don't have to resize the string.
|
||||||
|
There can be no errors beyond this point. */
|
||||||
|
string = PyUnicode_FromUnicode(NULL, n);
|
||||||
|
if (!string)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
s = PyUnicode_AS_UNICODE(string);
|
||||||
|
callresult = callresults;
|
||||||
|
|
||||||
|
for (f = format; *f; f++) {
|
||||||
|
if (*f == '%') {
|
||||||
|
const char* p = f++;
|
||||||
|
int longflag = 0;
|
||||||
|
int size_tflag = 0;
|
||||||
|
zeropad = (*f == '0');
|
||||||
|
/* parse the width.precision part */
|
||||||
|
width = 0;
|
||||||
|
while (isdigit(*f))
|
||||||
|
width = (width*10) + *f++ - '0';
|
||||||
|
precision = 0;
|
||||||
|
if (*f == '.') {
|
||||||
|
f++;
|
||||||
|
while (isdigit(*f))
|
||||||
|
precision = (precision*10) + *f++ - '0';
|
||||||
|
}
|
||||||
|
/* handle the long flag, but only for %ld and %lu.
|
||||||
|
others can be added when necessary. */
|
||||||
|
if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) {
|
||||||
|
longflag = 1;
|
||||||
|
++f;
|
||||||
|
}
|
||||||
|
/* handle the size_t flag. */
|
||||||
|
if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
|
||||||
|
size_tflag = 1;
|
||||||
|
++f;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*f) {
|
||||||
|
case 'c':
|
||||||
|
*s++ = va_arg(vargs, int);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'd');
|
||||||
|
if (longflag)
|
||||||
|
sprintf(realbuffer, fmt, va_arg(vargs, long));
|
||||||
|
else if (size_tflag)
|
||||||
|
sprintf(realbuffer, fmt, va_arg(vargs, Py_ssize_t));
|
||||||
|
else
|
||||||
|
sprintf(realbuffer, fmt, va_arg(vargs, int));
|
||||||
|
appendstring(realbuffer);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'u');
|
||||||
|
if (longflag)
|
||||||
|
sprintf(realbuffer, fmt, va_arg(vargs, unsigned long));
|
||||||
|
else if (size_tflag)
|
||||||
|
sprintf(realbuffer, fmt, va_arg(vargs, size_t));
|
||||||
|
else
|
||||||
|
sprintf(realbuffer, fmt, va_arg(vargs, unsigned int));
|
||||||
|
appendstring(realbuffer);
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
makefmt(fmt, 0, 0, zeropad, width, precision, 'i');
|
||||||
|
sprintf(realbuffer, fmt, va_arg(vargs, int));
|
||||||
|
appendstring(realbuffer);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
makefmt(fmt, 0, 0, zeropad, width, precision, 'x');
|
||||||
|
sprintf(realbuffer, fmt, va_arg(vargs, int));
|
||||||
|
appendstring(realbuffer);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
/* Parameter must be UTF-8 encoded.
|
||||||
|
In case of encoding errors, use
|
||||||
|
the replacement character. */
|
||||||
|
PyObject *u;
|
||||||
|
p = va_arg(vargs, char*);
|
||||||
|
u = PyUnicode_DecodeUTF8(p, strlen(p),
|
||||||
|
"replace");
|
||||||
|
if (!u)
|
||||||
|
goto fail;
|
||||||
|
Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(u),
|
||||||
|
PyUnicode_GET_SIZE(u));
|
||||||
|
s += PyUnicode_GET_SIZE(u);
|
||||||
|
Py_DECREF(u);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'U':
|
||||||
|
{
|
||||||
|
PyObject *obj = va_arg(vargs, PyObject *);
|
||||||
|
Py_ssize_t size = PyUnicode_GET_SIZE(obj);
|
||||||
|
Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(obj), size);
|
||||||
|
s += size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'V':
|
||||||
|
{
|
||||||
|
PyObject *obj = va_arg(vargs, PyObject *);
|
||||||
|
const char *str = va_arg(vargs, const char *);
|
||||||
|
if (obj) {
|
||||||
|
Py_ssize_t size = PyUnicode_GET_SIZE(obj);
|
||||||
|
Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(obj), size);
|
||||||
|
s += size;
|
||||||
|
} else {
|
||||||
|
appendstring(str);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'S':
|
||||||
|
case 'R':
|
||||||
|
{
|
||||||
|
Py_UNICODE *ucopy;
|
||||||
|
Py_ssize_t usize;
|
||||||
|
Py_ssize_t upos;
|
||||||
|
/* unused, since we already have the result */
|
||||||
|
(void) va_arg(vargs, PyObject *);
|
||||||
|
ucopy = PyUnicode_AS_UNICODE(*callresult);
|
||||||
|
usize = PyUnicode_GET_SIZE(*callresult);
|
||||||
|
for (upos = 0; upos<usize;)
|
||||||
|
*s++ = ucopy[upos++];
|
||||||
|
/* We're done with the unicode()/repr() => forget it */
|
||||||
|
Py_DECREF(*callresult);
|
||||||
|
/* switch to next unicode()/repr() result */
|
||||||
|
++callresult;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'p':
|
||||||
|
sprintf(buffer, "%p", va_arg(vargs, void*));
|
||||||
|
/* %p is ill-defined: ensure leading 0x. */
|
||||||
|
if (buffer[1] == 'X')
|
||||||
|
buffer[1] = 'x';
|
||||||
|
else if (buffer[1] != 'x') {
|
||||||
|
memmove(buffer+2, buffer, strlen(buffer)+1);
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = 'x';
|
||||||
|
}
|
||||||
|
appendstring(buffer);
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
*s++ = '%';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
appendstring(p);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
*s++ = *f;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (callresults)
|
||||||
|
PyMem_Free(callresults);
|
||||||
|
if (abuffer)
|
||||||
|
PyMem_Free(abuffer);
|
||||||
|
_PyUnicode_Resize(&string, s - PyUnicode_AS_UNICODE(string));
|
||||||
|
return string;
|
||||||
|
fail:
|
||||||
|
if (callresults) {
|
||||||
|
PyObject **callresult2 = callresults;
|
||||||
|
while (callresult2 < callresult) {
|
||||||
|
Py_DECREF(*callresult2);
|
||||||
|
++callresult2;
|
||||||
|
}
|
||||||
|
PyMem_Free(callresults);
|
||||||
|
}
|
||||||
|
if (abuffer)
|
||||||
|
PyMem_Free(abuffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef appendstring
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyUnicode_FromFormat(const char *format, ...)
|
||||||
|
{
|
||||||
|
PyObject* ret;
|
||||||
|
va_list vargs;
|
||||||
|
|
||||||
|
#ifdef HAVE_STDARG_PROTOTYPES
|
||||||
|
va_start(vargs, format);
|
||||||
|
#else
|
||||||
|
va_start(vargs);
|
||||||
|
#endif
|
||||||
|
ret = PyUnicode_FromFormatV(format, vargs);
|
||||||
|
va_end(vargs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Py_ssize_t PyUnicode_AsWideChar(PyUnicodeObject *unicode,
|
Py_ssize_t PyUnicode_AsWideChar(PyUnicodeObject *unicode,
|
||||||
wchar_t *w,
|
wchar_t *w,
|
||||||
Py_ssize_t size)
|
Py_ssize_t size)
|
||||||
|
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -420,6 +420,8 @@ class PyBuildExt(build_ext):
|
||||||
exts.append( Extension("_heapq", ["_heapqmodule.c"]) )
|
exts.append( Extension("_heapq", ["_heapqmodule.c"]) )
|
||||||
# operator.add() and similar goodies
|
# operator.add() and similar goodies
|
||||||
exts.append( Extension('operator', ['operator.c']) )
|
exts.append( Extension('operator', ['operator.c']) )
|
||||||
|
# Python 3.0 _fileio module
|
||||||
|
exts.append( Extension("_fileio", ["_fileio.c"]) )
|
||||||
# _functools
|
# _functools
|
||||||
exts.append( Extension("_functools", ["_functoolsmodule.c"]) )
|
exts.append( Extension("_functools", ["_functoolsmodule.c"]) )
|
||||||
# Python C API test module
|
# Python C API test module
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue