diff options
author | olegts <olegts@yandex-team.ru> | 2022-02-10 16:48:22 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:48:22 +0300 |
commit | 30983fb2586f6904aaf6a5d6ef2b445cbaec1f44 (patch) | |
tree | 3e86334ffd140d7ccfa0aa79386a6cf51b5b1e46 /contrib/python/cffi/c | |
parent | 9525b12aeec0b37aae9be1712d3d1031a235118f (diff) | |
download | ydb-30983fb2586f6904aaf6a5d6ef2b445cbaec1f44.tar.gz |
Restoring authorship annotation for <olegts@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/cffi/c')
27 files changed, 17159 insertions, 17159 deletions
diff --git a/contrib/python/cffi/c/_cffi_backend.c b/contrib/python/cffi/c/_cffi_backend.c index a92402b6a2..32eb430d9b 100644 --- a/contrib/python/cffi/c/_cffi_backend.c +++ b/contrib/python/cffi/c/_cffi_backend.c @@ -1,66 +1,66 @@ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include "structmember.h" - +#define PY_SSIZE_T_CLEAN +#include <Python.h> +#include "structmember.h" + #define CFFI_VERSION "1.15.0" - -#ifdef MS_WIN32 -#include <windows.h> -#include "misc_win32.h" -#else -#include <stddef.h> -#include <stdint.h> -#include <dlfcn.h> -#include <errno.h> -#include <ffi.h> -#include <sys/mman.h> -#endif - -/* this block of #ifs should be kept exactly identical between - c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */ -#if defined(_MSC_VER) -# include <malloc.h> /* for alloca() */ -# if _MSC_VER < 1600 /* MSVC < 2010 */ - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - typedef __int8 int_least8_t; - typedef __int16 int_least16_t; - typedef __int32 int_least32_t; - typedef __int64 int_least64_t; - typedef unsigned __int8 uint_least8_t; - typedef unsigned __int16 uint_least16_t; - typedef unsigned __int32 uint_least32_t; - typedef unsigned __int64 uint_least64_t; - typedef __int8 int_fast8_t; - typedef __int16 int_fast16_t; - typedef __int32 int_fast32_t; - typedef __int64 int_fast64_t; - typedef unsigned __int8 uint_fast8_t; - typedef unsigned __int16 uint_fast16_t; - typedef unsigned __int32 uint_fast32_t; - typedef unsigned __int64 uint_fast64_t; - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; -# else -# include <stdint.h> -# endif -# if _MSC_VER < 1800 /* MSVC < 2013 */ - typedef unsigned char _Bool; -# endif -#else -# include <stdint.h> -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) -# include <alloca.h> -# endif -#endif - - + +#ifdef MS_WIN32 +#include <windows.h> +#include "misc_win32.h" +#else +#include <stddef.h> +#include <stdint.h> +#include <dlfcn.h> +#include <errno.h> +#include <ffi.h> +#include <sys/mman.h> +#endif + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */ +#if defined(_MSC_VER) +# include <malloc.h> /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include <stdint.h> +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ + typedef unsigned char _Bool; +# endif +#else +# include <stdint.h> +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include <alloca.h> +# endif +#endif + + /* Define the following macro ONLY if you trust libffi's version of * ffi_closure_alloc() more than the code in malloc_closure.h. * IMPORTANT: DO NOT ENABLE THIS ON LINUX, unless you understand exactly @@ -121,61 +121,61 @@ #include "malloc_closure.h" -#if PY_MAJOR_VERSION >= 3 -# define STR_OR_BYTES "bytes" -# define PyText_Type PyUnicode_Type -# define PyText_Check PyUnicode_Check -# define PyTextAny_Check PyUnicode_Check -# define PyText_FromFormat PyUnicode_FromFormat -# define PyText_AsUTF8 _PyUnicode_AsString /* PyUnicode_AsUTF8 in Py3.3 */ -# define PyText_AS_UTF8 _PyUnicode_AsString +#if PY_MAJOR_VERSION >= 3 +# define STR_OR_BYTES "bytes" +# define PyText_Type PyUnicode_Type +# define PyText_Check PyUnicode_Check +# define PyTextAny_Check PyUnicode_Check +# define PyText_FromFormat PyUnicode_FromFormat +# define PyText_AsUTF8 _PyUnicode_AsString /* PyUnicode_AsUTF8 in Py3.3 */ +# define PyText_AS_UTF8 _PyUnicode_AsString # if PY_VERSION_HEX >= 0x03030000 # define PyText_GetSize PyUnicode_GetLength # else # define PyText_GetSize PyUnicode_GetSize # endif -# define PyText_FromString PyUnicode_FromString -# define PyText_FromStringAndSize PyUnicode_FromStringAndSize -# define PyText_InternInPlace PyUnicode_InternInPlace -# define PyText_InternFromString PyUnicode_InternFromString -# define PyIntOrLong_Check PyLong_Check -#else -# define STR_OR_BYTES "str" -# define PyText_Type PyString_Type -# define PyText_Check PyString_Check -# define PyTextAny_Check(op) (PyString_Check(op) || PyUnicode_Check(op)) -# define PyText_FromFormat PyString_FromFormat -# define PyText_AsUTF8 PyString_AsString -# define PyText_AS_UTF8 PyString_AS_STRING -# define PyText_GetSize PyString_Size -# define PyText_FromString PyString_FromString -# define PyText_FromStringAndSize PyString_FromStringAndSize -# define PyText_InternInPlace PyString_InternInPlace -# define PyText_InternFromString PyString_InternFromString -# define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op)) -#endif - -#if PY_MAJOR_VERSION >= 3 -# define PyInt_FromLong PyLong_FromLong -# define PyInt_FromSsize_t PyLong_FromSsize_t -# define PyInt_AsSsize_t PyLong_AsSsize_t -# define PyInt_AsLong PyLong_AsLong -#endif - -#if PY_MAJOR_VERSION >= 3 -/* This is the default on Python3 and constant has been removed. */ -# define Py_TPFLAGS_CHECKTYPES 0 -#endif - -#if PY_MAJOR_VERSION < 3 -# undef PyCapsule_GetPointer -# undef PyCapsule_New -# define PyCapsule_GetPointer(capsule, name) \ - (PyCObject_AsVoidPtr(capsule)) -# define PyCapsule_New(pointer, name, destructor) \ - (PyCObject_FromVoidPtr(pointer, destructor)) -#endif - +# define PyText_FromString PyUnicode_FromString +# define PyText_FromStringAndSize PyUnicode_FromStringAndSize +# define PyText_InternInPlace PyUnicode_InternInPlace +# define PyText_InternFromString PyUnicode_InternFromString +# define PyIntOrLong_Check PyLong_Check +#else +# define STR_OR_BYTES "str" +# define PyText_Type PyString_Type +# define PyText_Check PyString_Check +# define PyTextAny_Check(op) (PyString_Check(op) || PyUnicode_Check(op)) +# define PyText_FromFormat PyString_FromFormat +# define PyText_AsUTF8 PyString_AsString +# define PyText_AS_UTF8 PyString_AS_STRING +# define PyText_GetSize PyString_Size +# define PyText_FromString PyString_FromString +# define PyText_FromStringAndSize PyString_FromStringAndSize +# define PyText_InternInPlace PyString_InternInPlace +# define PyText_InternFromString PyString_InternFromString +# define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op)) +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +# define PyInt_FromSsize_t PyLong_FromSsize_t +# define PyInt_AsSsize_t PyLong_AsSsize_t +# define PyInt_AsLong PyLong_AsLong +#endif + +#if PY_MAJOR_VERSION >= 3 +/* This is the default on Python3 and constant has been removed. */ +# define Py_TPFLAGS_CHECKTYPES 0 +#endif + +#if PY_MAJOR_VERSION < 3 +# undef PyCapsule_GetPointer +# undef PyCapsule_New +# define PyCapsule_GetPointer(capsule, name) \ + (PyCObject_AsVoidPtr(capsule)) +# define PyCapsule_New(pointer, name, destructor) \ + (PyCObject_FromVoidPtr(pointer, destructor)) +#endif + #if PY_VERSION_HEX < 0x030900a4 # define Py_SET_REFCNT(obj, val) (Py_REFCNT(obj) = (val)) #endif @@ -184,9 +184,9 @@ # define USE_WRITEUNRAISABLEMSG #endif -/************************************************************/ - -/* base type flag: exactly one of the following: */ +/************************************************************/ + +/* base type flag: exactly one of the following: */ #define CT_PRIMITIVE_SIGNED 0x001 /* signed integer */ #define CT_PRIMITIVE_UNSIGNED 0x002 /* unsigned integer */ #define CT_PRIMITIVE_CHAR 0x004 /* char, wchar_t, charN_t */ @@ -198,8 +198,8 @@ #define CT_FUNCTIONPTR 0x100 /* pointer to function */ #define CT_VOID 0x200 /* void */ #define CT_PRIMITIVE_COMPLEX 0x400 /* float _Complex, double _Complex */ - -/* other flags that may also be set in addition to the base flag: */ + +/* other flags that may also be set in addition to the base flag: */ #define CT_IS_VOIDCHAR_PTR 0x00001000 #define CT_PRIMITIVE_FITS_LONG 0x00002000 #define CT_IS_OPAQUE 0x00004000 @@ -215,720 +215,720 @@ #define CT_LAZY_FIELD_LIST 0x01000000 #define CT_WITH_PACKED_CHANGE 0x02000000 #define CT_IS_SIGNED_WCHAR 0x04000000 -#define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \ - CT_PRIMITIVE_UNSIGNED | \ - CT_PRIMITIVE_CHAR | \ +#define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \ + CT_PRIMITIVE_UNSIGNED | \ + CT_PRIMITIVE_CHAR | \ CT_PRIMITIVE_FLOAT | \ CT_PRIMITIVE_COMPLEX) - -typedef struct _ctypedescr { - PyObject_VAR_HEAD - - struct _ctypedescr *ct_itemdescr; /* ptrs and arrays: the item type */ - PyObject *ct_stuff; /* structs: dict of the fields - arrays: ctypedescr of the ptr type - function: tuple(abi, ctres, ctargs..) - enum: pair {"name":x},{x:"name"} - ptrs: lazily, ctypedescr of array */ - void *ct_extra; /* structs: first field (not a ref!) - function types: cif_description - primitives: prebuilt "cif" object */ - - PyObject *ct_weakreflist; /* weakref support */ - - PyObject *ct_unique_key; /* key in unique_cache (a string, but not - human-readable) */ - - Py_ssize_t ct_size; /* size of instances, or -1 if unknown */ - Py_ssize_t ct_length; /* length of arrays, or -1 if unknown; - or alignment of primitive and struct types; - always -1 for pointers */ - int ct_flags; /* CT_xxx flags */ - - int ct_name_position; /* index in ct_name of where to put a var name */ - char ct_name[1]; /* string, e.g. "int *" for pointers to ints */ -} CTypeDescrObject; - -typedef struct { - PyObject_HEAD - CTypeDescrObject *c_type; - char *c_data; - PyObject *c_weakreflist; -} CDataObject; - -typedef struct cfieldobject_s { - PyObject_HEAD - CTypeDescrObject *cf_type; - Py_ssize_t cf_offset; - short cf_bitshift; /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */ - short cf_bitsize; - unsigned char cf_flags; /* BF_... */ - struct cfieldobject_s *cf_next; -} CFieldObject; -#define BS_REGULAR (-1) /* a regular field, not with bitshift */ -#define BS_EMPTY_ARRAY (-2) /* a field declared 'type[0]' or 'type[]' */ -#define BF_IGNORE_IN_CTOR 0x01 /* union field not in the first place */ - -static PyTypeObject CTypeDescr_Type; -static PyTypeObject CField_Type; -static PyTypeObject CData_Type; -static PyTypeObject CDataOwning_Type; -static PyTypeObject CDataOwningGC_Type; + +typedef struct _ctypedescr { + PyObject_VAR_HEAD + + struct _ctypedescr *ct_itemdescr; /* ptrs and arrays: the item type */ + PyObject *ct_stuff; /* structs: dict of the fields + arrays: ctypedescr of the ptr type + function: tuple(abi, ctres, ctargs..) + enum: pair {"name":x},{x:"name"} + ptrs: lazily, ctypedescr of array */ + void *ct_extra; /* structs: first field (not a ref!) + function types: cif_description + primitives: prebuilt "cif" object */ + + PyObject *ct_weakreflist; /* weakref support */ + + PyObject *ct_unique_key; /* key in unique_cache (a string, but not + human-readable) */ + + Py_ssize_t ct_size; /* size of instances, or -1 if unknown */ + Py_ssize_t ct_length; /* length of arrays, or -1 if unknown; + or alignment of primitive and struct types; + always -1 for pointers */ + int ct_flags; /* CT_xxx flags */ + + int ct_name_position; /* index in ct_name of where to put a var name */ + char ct_name[1]; /* string, e.g. "int *" for pointers to ints */ +} CTypeDescrObject; + +typedef struct { + PyObject_HEAD + CTypeDescrObject *c_type; + char *c_data; + PyObject *c_weakreflist; +} CDataObject; + +typedef struct cfieldobject_s { + PyObject_HEAD + CTypeDescrObject *cf_type; + Py_ssize_t cf_offset; + short cf_bitshift; /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */ + short cf_bitsize; + unsigned char cf_flags; /* BF_... */ + struct cfieldobject_s *cf_next; +} CFieldObject; +#define BS_REGULAR (-1) /* a regular field, not with bitshift */ +#define BS_EMPTY_ARRAY (-2) /* a field declared 'type[0]' or 'type[]' */ +#define BF_IGNORE_IN_CTOR 0x01 /* union field not in the first place */ + +static PyTypeObject CTypeDescr_Type; +static PyTypeObject CField_Type; +static PyTypeObject CData_Type; +static PyTypeObject CDataOwning_Type; +static PyTypeObject CDataOwningGC_Type; static PyTypeObject CDataFromBuf_Type; -static PyTypeObject CDataGCP_Type; - -#define CTypeDescr_Check(ob) (Py_TYPE(ob) == &CTypeDescr_Type) -#define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \ - Py_TYPE(ob) == &CDataOwning_Type || \ - Py_TYPE(ob) == &CDataOwningGC_Type || \ +static PyTypeObject CDataGCP_Type; + +#define CTypeDescr_Check(ob) (Py_TYPE(ob) == &CTypeDescr_Type) +#define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \ + Py_TYPE(ob) == &CDataOwning_Type || \ + Py_TYPE(ob) == &CDataOwningGC_Type || \ Py_TYPE(ob) == &CDataFromBuf_Type || \ - Py_TYPE(ob) == &CDataGCP_Type) -#define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \ - Py_TYPE(ob) == &CDataOwningGC_Type) - -typedef union { - unsigned char m_char; - unsigned short m_short; - unsigned int m_int; - unsigned long m_long; - unsigned long long m_longlong; - float m_float; - double m_double; -} union_alignment; - -typedef struct { - CDataObject head; - union_alignment alignment; -} CDataObject_casted_primitive; - -typedef struct { - CDataObject head; - union_alignment alignment; -} CDataObject_own_nolength; - -typedef struct { - CDataObject head; - Py_ssize_t length; - union_alignment alignment; -} CDataObject_own_length; - -typedef struct { - CDataObject head; + Py_TYPE(ob) == &CDataGCP_Type) +#define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \ + Py_TYPE(ob) == &CDataOwningGC_Type) + +typedef union { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; +} union_alignment; + +typedef struct { + CDataObject head; + union_alignment alignment; +} CDataObject_casted_primitive; + +typedef struct { + CDataObject head; + union_alignment alignment; +} CDataObject_own_nolength; + +typedef struct { + CDataObject head; + Py_ssize_t length; + union_alignment alignment; +} CDataObject_own_length; + +typedef struct { + CDataObject head; PyObject *structobj; /* for ffi.new_handle() or ffi.new("struct *") */ -} CDataObject_own_structptr; - -typedef struct { - CDataObject head; - Py_ssize_t length; /* same as CDataObject_own_length up to here */ - Py_buffer *bufferview; +} CDataObject_own_structptr; + +typedef struct { + CDataObject head; + Py_ssize_t length; /* same as CDataObject_own_length up to here */ + Py_buffer *bufferview; } CDataObject_frombuf; - -typedef struct { - CDataObject head; - Py_ssize_t length; /* same as CDataObject_own_length up to here */ - PyObject *origobj; - PyObject *destructor; -} CDataObject_gcp; - -typedef struct { + +typedef struct { + CDataObject head; + Py_ssize_t length; /* same as CDataObject_own_length up to here */ + PyObject *origobj; + PyObject *destructor; +} CDataObject_gcp; + +typedef struct { CDataObject head; ffi_closure *closure; } CDataObject_closure; typedef struct { - ffi_cif cif; - /* the following information is used when doing the call: - - a buffer of size 'exchange_size' is malloced - - the arguments are converted from Python objects to raw data - - the i'th raw data is stored at 'buffer + exchange_offset_arg[1+i]' - - the call is done - - the result is read back from 'buffer + exchange_offset_arg[0]' */ - Py_ssize_t exchange_size; - Py_ssize_t exchange_offset_arg[1]; -} cif_description_t; - -#define ADD_WRAPAROUND(x, y) ((Py_ssize_t)(((size_t)(x)) + ((size_t)(y)))) -#define MUL_WRAPAROUND(x, y) ((Py_ssize_t)(((size_t)(x)) * ((size_t)(y)))) - - -/* whenever running Python code, the errno is saved in this thread-local - variable */ -#ifndef MS_WIN32 -# include "misc_thread_posix.h" -#endif - -#include "minibuffer.h" - -#if PY_MAJOR_VERSION >= 3 -# include "file_emulator.h" -#endif - + ffi_cif cif; + /* the following information is used when doing the call: + - a buffer of size 'exchange_size' is malloced + - the arguments are converted from Python objects to raw data + - the i'th raw data is stored at 'buffer + exchange_offset_arg[1+i]' + - the call is done + - the result is read back from 'buffer + exchange_offset_arg[0]' */ + Py_ssize_t exchange_size; + Py_ssize_t exchange_offset_arg[1]; +} cif_description_t; + +#define ADD_WRAPAROUND(x, y) ((Py_ssize_t)(((size_t)(x)) + ((size_t)(y)))) +#define MUL_WRAPAROUND(x, y) ((Py_ssize_t)(((size_t)(x)) * ((size_t)(y)))) + + +/* whenever running Python code, the errno is saved in this thread-local + variable */ +#ifndef MS_WIN32 +# include "misc_thread_posix.h" +#endif + +#include "minibuffer.h" + +#if PY_MAJOR_VERSION >= 3 +# include "file_emulator.h" +#endif + #ifdef PyUnicode_KIND /* Python >= 3.3 */ # include "wchar_helper_3.h" #else -# include "wchar_helper.h" -#endif - +# include "wchar_helper.h" +#endif + #include "../cffi/_cffi_errors.h" -typedef struct _cffi_allocator_s { - PyObject *ca_alloc, *ca_free; - int ca_dont_clear; -} cffi_allocator_t; -static const cffi_allocator_t default_allocator = { NULL, NULL, 0 }; -static PyObject *FFIError; -static PyObject *unique_cache; - -/************************************************************/ - -static CTypeDescrObject * -ctypedescr_new(int name_size) -{ - CTypeDescrObject *ct = PyObject_GC_NewVar(CTypeDescrObject, - &CTypeDescr_Type, - name_size); - if (ct == NULL) - return NULL; - - ct->ct_itemdescr = NULL; - ct->ct_stuff = NULL; - ct->ct_weakreflist = NULL; - ct->ct_unique_key = NULL; - PyObject_GC_Track(ct); - return ct; -} - -static CTypeDescrObject * -ctypedescr_new_on_top(CTypeDescrObject *ct_base, const char *extra_text, - int extra_position) -{ - int base_name_len = strlen(ct_base->ct_name); - int extra_name_len = strlen(extra_text); - CTypeDescrObject *ct = ctypedescr_new(base_name_len + extra_name_len + 1); - char *p; - if (ct == NULL) - return NULL; - - Py_INCREF(ct_base); - ct->ct_itemdescr = ct_base; - ct->ct_name_position = ct_base->ct_name_position + extra_position; - - p = ct->ct_name; - memcpy(p, ct_base->ct_name, ct_base->ct_name_position); - p += ct_base->ct_name_position; - memcpy(p, extra_text, extra_name_len); - p += extra_name_len; - memcpy(p, ct_base->ct_name + ct_base->ct_name_position, - base_name_len - ct_base->ct_name_position + 1); - - return ct; -} - -static PyObject * -ctypedescr_repr(CTypeDescrObject *ct) -{ - return PyText_FromFormat("<ctype '%s'>", ct->ct_name); -} - -static void -ctypedescr_dealloc(CTypeDescrObject *ct) -{ - PyObject_GC_UnTrack(ct); - if (ct->ct_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) ct); - - if (ct->ct_unique_key != NULL) { - /* revive dead object temporarily for DelItem */ +typedef struct _cffi_allocator_s { + PyObject *ca_alloc, *ca_free; + int ca_dont_clear; +} cffi_allocator_t; +static const cffi_allocator_t default_allocator = { NULL, NULL, 0 }; +static PyObject *FFIError; +static PyObject *unique_cache; + +/************************************************************/ + +static CTypeDescrObject * +ctypedescr_new(int name_size) +{ + CTypeDescrObject *ct = PyObject_GC_NewVar(CTypeDescrObject, + &CTypeDescr_Type, + name_size); + if (ct == NULL) + return NULL; + + ct->ct_itemdescr = NULL; + ct->ct_stuff = NULL; + ct->ct_weakreflist = NULL; + ct->ct_unique_key = NULL; + PyObject_GC_Track(ct); + return ct; +} + +static CTypeDescrObject * +ctypedescr_new_on_top(CTypeDescrObject *ct_base, const char *extra_text, + int extra_position) +{ + int base_name_len = strlen(ct_base->ct_name); + int extra_name_len = strlen(extra_text); + CTypeDescrObject *ct = ctypedescr_new(base_name_len + extra_name_len + 1); + char *p; + if (ct == NULL) + return NULL; + + Py_INCREF(ct_base); + ct->ct_itemdescr = ct_base; + ct->ct_name_position = ct_base->ct_name_position + extra_position; + + p = ct->ct_name; + memcpy(p, ct_base->ct_name, ct_base->ct_name_position); + p += ct_base->ct_name_position; + memcpy(p, extra_text, extra_name_len); + p += extra_name_len; + memcpy(p, ct_base->ct_name + ct_base->ct_name_position, + base_name_len - ct_base->ct_name_position + 1); + + return ct; +} + +static PyObject * +ctypedescr_repr(CTypeDescrObject *ct) +{ + return PyText_FromFormat("<ctype '%s'>", ct->ct_name); +} + +static void +ctypedescr_dealloc(CTypeDescrObject *ct) +{ + PyObject_GC_UnTrack(ct); + if (ct->ct_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) ct); + + if (ct->ct_unique_key != NULL) { + /* revive dead object temporarily for DelItem */ Py_SET_REFCNT(ct, 43); - PyDict_DelItem(unique_cache, ct->ct_unique_key); - assert(Py_REFCNT(ct) == 42); + PyDict_DelItem(unique_cache, ct->ct_unique_key); + assert(Py_REFCNT(ct) == 42); Py_SET_REFCNT(ct, 0); - Py_DECREF(ct->ct_unique_key); - } - Py_XDECREF(ct->ct_itemdescr); - Py_XDECREF(ct->ct_stuff); - if (ct->ct_flags & CT_FUNCTIONPTR) - PyObject_Free(ct->ct_extra); - Py_TYPE(ct)->tp_free((PyObject *)ct); -} - -static int -ctypedescr_traverse(CTypeDescrObject *ct, visitproc visit, void *arg) -{ - Py_VISIT(ct->ct_itemdescr); - Py_VISIT(ct->ct_stuff); - return 0; -} - -static int -ctypedescr_clear(CTypeDescrObject *ct) -{ - Py_CLEAR(ct->ct_itemdescr); - Py_CLEAR(ct->ct_stuff); - return 0; -} - - -static PyObject *nosuchattr(const char *attr) -{ - PyErr_SetString(PyExc_AttributeError, attr); - return NULL; -} - -static PyObject *ctypeget_kind(CTypeDescrObject *ct, void *context) -{ - char *result; - if (ct->ct_flags & CT_PRIMITIVE_ANY) { - if (ct->ct_flags & CT_IS_ENUM) - result = "enum"; - else - result = "primitive"; - } - else if (ct->ct_flags & CT_POINTER) { - result = "pointer"; - } - else if (ct->ct_flags & CT_ARRAY) { - result = "array"; - } - else if (ct->ct_flags & CT_VOID) { - result = "void"; - } - else if (ct->ct_flags & CT_STRUCT) { - result = "struct"; - } - else if (ct->ct_flags & CT_UNION) { - result = "union"; - } - else if (ct->ct_flags & CT_FUNCTIONPTR) { - result = "function"; - } - else - result = "?"; - - return PyText_FromString(result); -} - -static PyObject *ctypeget_cname(CTypeDescrObject *ct, void *context) -{ - return PyText_FromString(ct->ct_name); -} - -static PyObject *ctypeget_item(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & (CT_POINTER | CT_ARRAY)) { - Py_INCREF(ct->ct_itemdescr); - return (PyObject *)ct->ct_itemdescr; - } - return nosuchattr("item"); -} - -static PyObject *ctypeget_length(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_ARRAY) { - if (ct->ct_length >= 0) { - return PyInt_FromSsize_t(ct->ct_length); - } - else { - Py_INCREF(Py_None); - return Py_None; - } - } - return nosuchattr("length"); -} - -static PyObject * -get_field_name(CTypeDescrObject *ct, CFieldObject *cf); /* forward */ - + Py_DECREF(ct->ct_unique_key); + } + Py_XDECREF(ct->ct_itemdescr); + Py_XDECREF(ct->ct_stuff); + if (ct->ct_flags & CT_FUNCTIONPTR) + PyObject_Free(ct->ct_extra); + Py_TYPE(ct)->tp_free((PyObject *)ct); +} + +static int +ctypedescr_traverse(CTypeDescrObject *ct, visitproc visit, void *arg) +{ + Py_VISIT(ct->ct_itemdescr); + Py_VISIT(ct->ct_stuff); + return 0; +} + +static int +ctypedescr_clear(CTypeDescrObject *ct) +{ + Py_CLEAR(ct->ct_itemdescr); + Py_CLEAR(ct->ct_stuff); + return 0; +} + + +static PyObject *nosuchattr(const char *attr) +{ + PyErr_SetString(PyExc_AttributeError, attr); + return NULL; +} + +static PyObject *ctypeget_kind(CTypeDescrObject *ct, void *context) +{ + char *result; + if (ct->ct_flags & CT_PRIMITIVE_ANY) { + if (ct->ct_flags & CT_IS_ENUM) + result = "enum"; + else + result = "primitive"; + } + else if (ct->ct_flags & CT_POINTER) { + result = "pointer"; + } + else if (ct->ct_flags & CT_ARRAY) { + result = "array"; + } + else if (ct->ct_flags & CT_VOID) { + result = "void"; + } + else if (ct->ct_flags & CT_STRUCT) { + result = "struct"; + } + else if (ct->ct_flags & CT_UNION) { + result = "union"; + } + else if (ct->ct_flags & CT_FUNCTIONPTR) { + result = "function"; + } + else + result = "?"; + + return PyText_FromString(result); +} + +static PyObject *ctypeget_cname(CTypeDescrObject *ct, void *context) +{ + return PyText_FromString(ct->ct_name); +} + +static PyObject *ctypeget_item(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & (CT_POINTER | CT_ARRAY)) { + Py_INCREF(ct->ct_itemdescr); + return (PyObject *)ct->ct_itemdescr; + } + return nosuchattr("item"); +} + +static PyObject *ctypeget_length(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_ARRAY) { + if (ct->ct_length >= 0) { + return PyInt_FromSsize_t(ct->ct_length); + } + else { + Py_INCREF(Py_None); + return Py_None; + } + } + return nosuchattr("length"); +} + +static PyObject * +get_field_name(CTypeDescrObject *ct, CFieldObject *cf); /* forward */ + /* returns 0 if the struct ctype is opaque, 1 if it is not, or -1 if an exception occurs */ -#define force_lazy_struct(ct) \ - ((ct)->ct_stuff != NULL ? 1 : do_realize_lazy_struct(ct)) - -static int do_realize_lazy_struct(CTypeDescrObject *ct); -/* forward, implemented in realize_c_type.c */ - -static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & (CT_STRUCT | CT_UNION)) { - if (!(ct->ct_flags & CT_IS_OPAQUE)) { - CFieldObject *cf; - PyObject *res; - if (force_lazy_struct(ct) < 0) - return NULL; - res = PyList_New(0); - if (res == NULL) - return NULL; - for (cf = (CFieldObject *)ct->ct_extra; - cf != NULL; cf = cf->cf_next) { - PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf), - (PyObject *)cf); - int err = (o != NULL) ? PyList_Append(res, o) : -1; - Py_XDECREF(o); - if (err < 0) { - Py_DECREF(res); - return NULL; - } - } - return res; - } - else { - Py_INCREF(Py_None); - return Py_None; - } - } - return nosuchattr("fields"); -} - -static PyObject *ctypeget_args(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_FUNCTIONPTR) { - PyObject *t = ct->ct_stuff; - return PyTuple_GetSlice(t, 2, PyTuple_GET_SIZE(t)); - } - return nosuchattr("args"); -} - -static PyObject *ctypeget_result(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_FUNCTIONPTR) { - PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); - Py_XINCREF(res); - return res; - } - return nosuchattr("result"); -} - -static PyObject *ctypeget_ellipsis(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_FUNCTIONPTR) { - PyObject *res = ct->ct_extra ? Py_False : Py_True; - Py_INCREF(res); - return res; - } - return nosuchattr("ellipsis"); -} - -static PyObject *ctypeget_abi(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_FUNCTIONPTR) { - PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); - Py_XINCREF(res); - return res; - } - return nosuchattr("abi"); -} - -static PyObject *ctypeget_elements(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_IS_ENUM) { - PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); - if (res) res = PyDict_Copy(res); - return res; - } - return nosuchattr("elements"); -} - -static PyObject *ctypeget_relements(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_IS_ENUM) { - PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); - if (res) res = PyDict_Copy(res); - return res; - } - return nosuchattr("relements"); -} - -static PyGetSetDef ctypedescr_getsets[] = { - {"kind", (getter)ctypeget_kind, NULL, "kind"}, - {"cname", (getter)ctypeget_cname, NULL, "C name"}, - {"item", (getter)ctypeget_item, NULL, "pointer to, or array of"}, - {"length", (getter)ctypeget_length, NULL, "array length or None"}, - {"fields", (getter)ctypeget_fields, NULL, "struct or union fields"}, - {"args", (getter)ctypeget_args, NULL, "function argument types"}, - {"result", (getter)ctypeget_result, NULL, "function result type"}, - {"ellipsis", (getter)ctypeget_ellipsis, NULL, "function has '...'"}, - {"abi", (getter)ctypeget_abi, NULL, "function ABI"}, - {"elements", (getter)ctypeget_elements, NULL, "enum elements"}, - {"relements", (getter)ctypeget_relements, NULL, "enum elements, reverse"}, - {NULL} /* sentinel */ -}; - -static PyObject * -ctypedescr_dir(PyObject *ct, PyObject *noarg) -{ - int err; - struct PyGetSetDef *gsdef; - PyObject *res = PyList_New(0); - if (res == NULL) - return NULL; - - for (gsdef = ctypedescr_getsets; gsdef->name; gsdef++) { - PyObject *x = PyObject_GetAttrString(ct, gsdef->name); - if (x == NULL) { - PyErr_Clear(); - } - else { - Py_DECREF(x); - x = PyText_FromString(gsdef->name); - err = (x != NULL) ? PyList_Append(res, x) : -1; - Py_XDECREF(x); - if (err < 0) { - Py_DECREF(res); - return NULL; - } - } - } - return res; -} - -static PyMethodDef ctypedescr_methods[] = { - {"__dir__", ctypedescr_dir, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject CTypeDescr_Type = { - PyVarObject_HEAD_INIT(NULL, 0) +#define force_lazy_struct(ct) \ + ((ct)->ct_stuff != NULL ? 1 : do_realize_lazy_struct(ct)) + +static int do_realize_lazy_struct(CTypeDescrObject *ct); +/* forward, implemented in realize_c_type.c */ + +static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & (CT_STRUCT | CT_UNION)) { + if (!(ct->ct_flags & CT_IS_OPAQUE)) { + CFieldObject *cf; + PyObject *res; + if (force_lazy_struct(ct) < 0) + return NULL; + res = PyList_New(0); + if (res == NULL) + return NULL; + for (cf = (CFieldObject *)ct->ct_extra; + cf != NULL; cf = cf->cf_next) { + PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf), + (PyObject *)cf); + int err = (o != NULL) ? PyList_Append(res, o) : -1; + Py_XDECREF(o); + if (err < 0) { + Py_DECREF(res); + return NULL; + } + } + return res; + } + else { + Py_INCREF(Py_None); + return Py_None; + } + } + return nosuchattr("fields"); +} + +static PyObject *ctypeget_args(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTIONPTR) { + PyObject *t = ct->ct_stuff; + return PyTuple_GetSlice(t, 2, PyTuple_GET_SIZE(t)); + } + return nosuchattr("args"); +} + +static PyObject *ctypeget_result(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTIONPTR) { + PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); + Py_XINCREF(res); + return res; + } + return nosuchattr("result"); +} + +static PyObject *ctypeget_ellipsis(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTIONPTR) { + PyObject *res = ct->ct_extra ? Py_False : Py_True; + Py_INCREF(res); + return res; + } + return nosuchattr("ellipsis"); +} + +static PyObject *ctypeget_abi(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTIONPTR) { + PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); + Py_XINCREF(res); + return res; + } + return nosuchattr("abi"); +} + +static PyObject *ctypeget_elements(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_IS_ENUM) { + PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); + if (res) res = PyDict_Copy(res); + return res; + } + return nosuchattr("elements"); +} + +static PyObject *ctypeget_relements(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_IS_ENUM) { + PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); + if (res) res = PyDict_Copy(res); + return res; + } + return nosuchattr("relements"); +} + +static PyGetSetDef ctypedescr_getsets[] = { + {"kind", (getter)ctypeget_kind, NULL, "kind"}, + {"cname", (getter)ctypeget_cname, NULL, "C name"}, + {"item", (getter)ctypeget_item, NULL, "pointer to, or array of"}, + {"length", (getter)ctypeget_length, NULL, "array length or None"}, + {"fields", (getter)ctypeget_fields, NULL, "struct or union fields"}, + {"args", (getter)ctypeget_args, NULL, "function argument types"}, + {"result", (getter)ctypeget_result, NULL, "function result type"}, + {"ellipsis", (getter)ctypeget_ellipsis, NULL, "function has '...'"}, + {"abi", (getter)ctypeget_abi, NULL, "function ABI"}, + {"elements", (getter)ctypeget_elements, NULL, "enum elements"}, + {"relements", (getter)ctypeget_relements, NULL, "enum elements, reverse"}, + {NULL} /* sentinel */ +}; + +static PyObject * +ctypedescr_dir(PyObject *ct, PyObject *noarg) +{ + int err; + struct PyGetSetDef *gsdef; + PyObject *res = PyList_New(0); + if (res == NULL) + return NULL; + + for (gsdef = ctypedescr_getsets; gsdef->name; gsdef++) { + PyObject *x = PyObject_GetAttrString(ct, gsdef->name); + if (x == NULL) { + PyErr_Clear(); + } + else { + Py_DECREF(x); + x = PyText_FromString(gsdef->name); + err = (x != NULL) ? PyList_Append(res, x) : -1; + Py_XDECREF(x); + if (err < 0) { + Py_DECREF(res); + return NULL; + } + } + } + return res; +} + +static PyMethodDef ctypedescr_methods[] = { + {"__dir__", ctypedescr_dir, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject CTypeDescr_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CType", - offsetof(CTypeDescrObject, ct_name), - sizeof(char), - (destructor)ctypedescr_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)ctypedescr_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_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)ctypedescr_traverse, /* tp_traverse */ - (inquiry)ctypedescr_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(CTypeDescrObject, ct_weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ctypedescr_methods, /* tp_methods */ - 0, /* tp_members */ - ctypedescr_getsets, /* tp_getset */ -}; - -/************************************************************/ - -static PyObject * -get_field_name(CTypeDescrObject *ct, CFieldObject *cf) -{ - Py_ssize_t i = 0; - PyObject *d_key, *d_value; - while (PyDict_Next(ct->ct_stuff, &i, &d_key, &d_value)) { - if (d_value == (PyObject *)cf) - return d_key; - } - Py_FatalError("_cffi_backend: get_field_name()"); - return NULL; -} - -static void -cfield_dealloc(CFieldObject *cf) -{ - Py_DECREF(cf->cf_type); - PyObject_Del(cf); -} - -#undef OFF -#define OFF(x) offsetof(CFieldObject, x) - -static PyMemberDef cfield_members[] = { - {"type", T_OBJECT, OFF(cf_type), READONLY}, - {"offset", T_PYSSIZET, OFF(cf_offset), READONLY}, - {"bitshift", T_SHORT, OFF(cf_bitshift), READONLY}, - {"bitsize", T_SHORT, OFF(cf_bitsize), READONLY}, - {"flags", T_UBYTE, OFF(cf_flags), READONLY}, - {NULL} /* Sentinel */ -}; -#undef OFF - -static PyTypeObject CField_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.CField", - sizeof(CFieldObject), - 0, - (destructor)cfield_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - cfield_members, /* tp_members */ -}; - -/************************************************************/ - -static int -CDataObject_Or_PyFloat_Check(PyObject *ob) -{ - return (PyFloat_Check(ob) || - (CData_Check(ob) && - (((CDataObject *)ob)->c_type->ct_flags & CT_PRIMITIVE_FLOAT))); -} - -static PY_LONG_LONG -_my_PyLong_AsLongLong(PyObject *ob) -{ - /* (possibly) convert and cast a Python object to a long long. - Like PyLong_AsLongLong(), this version accepts a Python int too, and - does convertions from other types of objects. The difference is that - this version refuses floats. */ -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(ob)) { - return PyInt_AS_LONG(ob); - } + offsetof(CTypeDescrObject, ct_name), + sizeof(char), + (destructor)ctypedescr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)ctypedescr_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_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)ctypedescr_traverse, /* tp_traverse */ + (inquiry)ctypedescr_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(CTypeDescrObject, ct_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ctypedescr_methods, /* tp_methods */ + 0, /* tp_members */ + ctypedescr_getsets, /* tp_getset */ +}; + +/************************************************************/ + +static PyObject * +get_field_name(CTypeDescrObject *ct, CFieldObject *cf) +{ + Py_ssize_t i = 0; + PyObject *d_key, *d_value; + while (PyDict_Next(ct->ct_stuff, &i, &d_key, &d_value)) { + if (d_value == (PyObject *)cf) + return d_key; + } + Py_FatalError("_cffi_backend: get_field_name()"); + return NULL; +} + +static void +cfield_dealloc(CFieldObject *cf) +{ + Py_DECREF(cf->cf_type); + PyObject_Del(cf); +} + +#undef OFF +#define OFF(x) offsetof(CFieldObject, x) + +static PyMemberDef cfield_members[] = { + {"type", T_OBJECT, OFF(cf_type), READONLY}, + {"offset", T_PYSSIZET, OFF(cf_offset), READONLY}, + {"bitshift", T_SHORT, OFF(cf_bitshift), READONLY}, + {"bitsize", T_SHORT, OFF(cf_bitsize), READONLY}, + {"flags", T_UBYTE, OFF(cf_flags), READONLY}, + {NULL} /* Sentinel */ +}; +#undef OFF + +static PyTypeObject CField_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_cffi_backend.CField", + sizeof(CFieldObject), + 0, + (destructor)cfield_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + cfield_members, /* tp_members */ +}; + +/************************************************************/ + +static int +CDataObject_Or_PyFloat_Check(PyObject *ob) +{ + return (PyFloat_Check(ob) || + (CData_Check(ob) && + (((CDataObject *)ob)->c_type->ct_flags & CT_PRIMITIVE_FLOAT))); +} + +static PY_LONG_LONG +_my_PyLong_AsLongLong(PyObject *ob) +{ + /* (possibly) convert and cast a Python object to a long long. + Like PyLong_AsLongLong(), this version accepts a Python int too, and + does convertions from other types of objects. The difference is that + this version refuses floats. */ +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(ob)) { + return PyInt_AS_LONG(ob); + } + else +#endif + if (PyLong_Check(ob)) { + return PyLong_AsLongLong(ob); + } + else { + PyObject *io; + PY_LONG_LONG res; + PyNumberMethods *nb = ob->ob_type->tp_as_number; + + if (CDataObject_Or_PyFloat_Check(ob) || + nb == NULL || nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + io = (*nb->nb_int) (ob); + if (io == NULL) + return -1; + + if (PyIntOrLong_Check(io)) { + res = _my_PyLong_AsLongLong(io); + } + else { + PyErr_SetString(PyExc_TypeError, "integer conversion failed"); + res = -1; + } + Py_DECREF(io); + return res; + } +} + +static unsigned PY_LONG_LONG +_my_PyLong_AsUnsignedLongLong(PyObject *ob, int strict) +{ + /* (possibly) convert and cast a Python object to an unsigned long long. + Like PyLong_AsLongLong(), this version accepts a Python int too, and + does convertions from other types of objects. If 'strict', complains + with OverflowError and refuses floats. If '!strict', rounds floats + and masks the result. */ +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(ob)) { + long value1 = PyInt_AS_LONG(ob); + if (strict && value1 < 0) + goto negative; + return (unsigned PY_LONG_LONG)(PY_LONG_LONG)value1; + } else -#endif - if (PyLong_Check(ob)) { - return PyLong_AsLongLong(ob); - } - else { - PyObject *io; - PY_LONG_LONG res; - PyNumberMethods *nb = ob->ob_type->tp_as_number; - - if (CDataObject_Or_PyFloat_Check(ob) || - nb == NULL || nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return -1; - } - io = (*nb->nb_int) (ob); - if (io == NULL) - return -1; - - if (PyIntOrLong_Check(io)) { - res = _my_PyLong_AsLongLong(io); - } - else { - PyErr_SetString(PyExc_TypeError, "integer conversion failed"); - res = -1; - } - Py_DECREF(io); - return res; - } -} - -static unsigned PY_LONG_LONG -_my_PyLong_AsUnsignedLongLong(PyObject *ob, int strict) -{ - /* (possibly) convert and cast a Python object to an unsigned long long. - Like PyLong_AsLongLong(), this version accepts a Python int too, and - does convertions from other types of objects. If 'strict', complains - with OverflowError and refuses floats. If '!strict', rounds floats - and masks the result. */ -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(ob)) { - long value1 = PyInt_AS_LONG(ob); - if (strict && value1 < 0) - goto negative; - return (unsigned PY_LONG_LONG)(PY_LONG_LONG)value1; - } - else -#endif - if (PyLong_Check(ob)) { - if (strict) { - if (_PyLong_Sign(ob) < 0) - goto negative; - return PyLong_AsUnsignedLongLong(ob); - } - else { - return PyLong_AsUnsignedLongLongMask(ob); - } - } - else { - PyObject *io; - unsigned PY_LONG_LONG res; - PyNumberMethods *nb = ob->ob_type->tp_as_number; - - if ((strict && CDataObject_Or_PyFloat_Check(ob)) || - nb == NULL || nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return (unsigned PY_LONG_LONG)-1; - } - io = (*nb->nb_int) (ob); - if (io == NULL) - return (unsigned PY_LONG_LONG)-1; - - if (PyIntOrLong_Check(io)) { - res = _my_PyLong_AsUnsignedLongLong(io, strict); - } - else { - PyErr_SetString(PyExc_TypeError, "integer conversion failed"); - res = (unsigned PY_LONG_LONG)-1; - } - Py_DECREF(io); - return res; - } - - negative: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative number to unsigned"); - return (unsigned PY_LONG_LONG)-1; -} - -#define _read_raw_data(type) \ - do { \ - if (size == sizeof(type)) { \ - type r; \ - memcpy(&r, target, sizeof(type)); \ - return r; \ - } \ - } while(0) - -static PY_LONG_LONG -read_raw_signed_data(char *target, int size) -{ - _read_raw_data(signed char); - _read_raw_data(short); - _read_raw_data(int); - _read_raw_data(long); - _read_raw_data(PY_LONG_LONG); - Py_FatalError("read_raw_signed_data: bad integer size"); - return 0; -} - -static unsigned PY_LONG_LONG -read_raw_unsigned_data(char *target, int size) -{ - _read_raw_data(unsigned char); - _read_raw_data(unsigned short); - _read_raw_data(unsigned int); - _read_raw_data(unsigned long); - _read_raw_data(unsigned PY_LONG_LONG); - Py_FatalError("read_raw_unsigned_data: bad integer size"); - return 0; -} - +#endif + if (PyLong_Check(ob)) { + if (strict) { + if (_PyLong_Sign(ob) < 0) + goto negative; + return PyLong_AsUnsignedLongLong(ob); + } + else { + return PyLong_AsUnsignedLongLongMask(ob); + } + } + else { + PyObject *io; + unsigned PY_LONG_LONG res; + PyNumberMethods *nb = ob->ob_type->tp_as_number; + + if ((strict && CDataObject_Or_PyFloat_Check(ob)) || + nb == NULL || nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return (unsigned PY_LONG_LONG)-1; + } + io = (*nb->nb_int) (ob); + if (io == NULL) + return (unsigned PY_LONG_LONG)-1; + + if (PyIntOrLong_Check(io)) { + res = _my_PyLong_AsUnsignedLongLong(io, strict); + } + else { + PyErr_SetString(PyExc_TypeError, "integer conversion failed"); + res = (unsigned PY_LONG_LONG)-1; + } + Py_DECREF(io); + return res; + } + + negative: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative number to unsigned"); + return (unsigned PY_LONG_LONG)-1; +} + +#define _read_raw_data(type) \ + do { \ + if (size == sizeof(type)) { \ + type r; \ + memcpy(&r, target, sizeof(type)); \ + return r; \ + } \ + } while(0) + +static PY_LONG_LONG +read_raw_signed_data(char *target, int size) +{ + _read_raw_data(signed char); + _read_raw_data(short); + _read_raw_data(int); + _read_raw_data(long); + _read_raw_data(PY_LONG_LONG); + Py_FatalError("read_raw_signed_data: bad integer size"); + return 0; +} + +static unsigned PY_LONG_LONG +read_raw_unsigned_data(char *target, int size) +{ + _read_raw_data(unsigned char); + _read_raw_data(unsigned short); + _read_raw_data(unsigned int); + _read_raw_data(unsigned long); + _read_raw_data(unsigned PY_LONG_LONG); + Py_FatalError("read_raw_unsigned_data: bad integer size"); + return 0; +} + #ifdef __GNUC__ /* This is a workaround for what I think is a GCC bug on several platforms. See issue #378. */ @@ -939,44 +939,44 @@ void _cffi_memcpy(char *target, const void *src, size_t size) memcpy(target, src, size); } -#define _write_raw_data(type) \ - do { \ - if (size == sizeof(type)) { \ - type r = (type)source; \ +#define _write_raw_data(type) \ + do { \ + if (size == sizeof(type)) { \ + type r = (type)source; \ _cffi_memcpy(target, &r, sizeof(type)); \ - return; \ - } \ - } while(0) - -static void -write_raw_integer_data(char *target, unsigned PY_LONG_LONG source, int size) -{ - _write_raw_data(unsigned char); - _write_raw_data(unsigned short); - _write_raw_data(unsigned int); - _write_raw_data(unsigned long); - _write_raw_data(unsigned PY_LONG_LONG); - Py_FatalError("write_raw_integer_data: bad integer size"); -} - -static double -read_raw_float_data(char *target, int size) -{ - _read_raw_data(float); - _read_raw_data(double); - Py_FatalError("read_raw_float_data: bad float size"); - return 0; -} - -static long double -read_raw_longdouble_data(char *target) -{ - int size = sizeof(long double); - _read_raw_data(long double); - Py_FatalError("read_raw_longdouble_data: bad long double size"); - return 0; -} - + return; \ + } \ + } while(0) + +static void +write_raw_integer_data(char *target, unsigned PY_LONG_LONG source, int size) +{ + _write_raw_data(unsigned char); + _write_raw_data(unsigned short); + _write_raw_data(unsigned int); + _write_raw_data(unsigned long); + _write_raw_data(unsigned PY_LONG_LONG); + Py_FatalError("write_raw_integer_data: bad integer size"); +} + +static double +read_raw_float_data(char *target, int size) +{ + _read_raw_data(float); + _read_raw_data(double); + Py_FatalError("read_raw_float_data: bad float size"); + return 0; +} + +static long double +read_raw_longdouble_data(char *target) +{ + int size = sizeof(long double); + _read_raw_data(long double); + Py_FatalError("read_raw_longdouble_data: bad long double size"); + return 0; +} + static Py_complex read_raw_complex_data(char *target, int size) { @@ -997,21 +997,21 @@ read_raw_complex_data(char *target, int size) return r; } -static void -write_raw_float_data(char *target, double source, int size) -{ - _write_raw_data(float); - _write_raw_data(double); - Py_FatalError("write_raw_float_data: bad float size"); -} - -static void -write_raw_longdouble_data(char *target, long double source) -{ - int size = sizeof(long double); - _write_raw_data(long double); -} - +static void +write_raw_float_data(char *target, double source, int size) +{ + _write_raw_data(float); + _write_raw_data(double); + Py_FatalError("write_raw_float_data: bad float size"); +} + +static void +write_raw_longdouble_data(char *target, long double source) +{ + int size = sizeof(long double); + _write_raw_data(long double); +} + #define _write_raw_complex_data(type) \ do { \ if (size == 2*sizeof(type)) { \ @@ -1031,80 +1031,80 @@ write_raw_complex_data(char *target, Py_complex source, int size) Py_FatalError("write_raw_complex_data: bad complex size"); } -static PyObject * -new_simple_cdata(char *data, CTypeDescrObject *ct) -{ - CDataObject *cd = PyObject_New(CDataObject, &CData_Type); - if (cd == NULL) - return NULL; - Py_INCREF(ct); - cd->c_data = data; - cd->c_type = ct; - cd->c_weakreflist = NULL; - return (PyObject *)cd; -} - -static PyObject * -new_sized_cdata(char *data, CTypeDescrObject *ct, Py_ssize_t length) -{ - CDataObject_own_length *scd; - - scd = (CDataObject_own_length *)PyObject_Malloc( - offsetof(CDataObject_own_length, alignment)); - if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL) - return NULL; - Py_INCREF(ct); - scd->head.c_type = ct; - scd->head.c_data = data; - scd->head.c_weakreflist = NULL; - scd->length = length; - return (PyObject *)scd; -} - -static CDataObject *_new_casted_primitive(CTypeDescrObject *ct); /*forward*/ - -static PyObject * -convert_to_object(char *data, CTypeDescrObject *ct) -{ - if (!(ct->ct_flags & CT_PRIMITIVE_ANY)) { - /* non-primitive types (check done just for performance) */ - if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { - char *ptrdata = *(char **)data; - /*READ(data, sizeof(char *))*/ - return new_simple_cdata(ptrdata, ct); - } - else if (ct->ct_flags & CT_IS_OPAQUE) { - PyErr_Format(PyExc_TypeError, "cdata '%s' is opaque", - ct->ct_name); - return NULL; - } - else if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { - return new_simple_cdata(data, ct); - } - else if (ct->ct_flags & CT_ARRAY) { - if (ct->ct_length < 0) { - /* we can't return a <cdata 'int[]'> here, because we don't - know the length to give it. As a compromize, returns - <cdata 'int *'> in this case. */ - ct = (CTypeDescrObject *)ct->ct_stuff; - } - return new_simple_cdata(data, ct); - } - } - else if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { - PY_LONG_LONG value; - /*READ(data, ct->ct_size)*/ - value = read_raw_signed_data(data, ct->ct_size); - if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) - return PyInt_FromLong((long)value); - else - return PyLong_FromLongLong(value); - } - else if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { - unsigned PY_LONG_LONG value; - /*READ(data, ct->ct_size)*/ - value = read_raw_unsigned_data(data, ct->ct_size); - +static PyObject * +new_simple_cdata(char *data, CTypeDescrObject *ct) +{ + CDataObject *cd = PyObject_New(CDataObject, &CData_Type); + if (cd == NULL) + return NULL; + Py_INCREF(ct); + cd->c_data = data; + cd->c_type = ct; + cd->c_weakreflist = NULL; + return (PyObject *)cd; +} + +static PyObject * +new_sized_cdata(char *data, CTypeDescrObject *ct, Py_ssize_t length) +{ + CDataObject_own_length *scd; + + scd = (CDataObject_own_length *)PyObject_Malloc( + offsetof(CDataObject_own_length, alignment)); + if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL) + return NULL; + Py_INCREF(ct); + scd->head.c_type = ct; + scd->head.c_data = data; + scd->head.c_weakreflist = NULL; + scd->length = length; + return (PyObject *)scd; +} + +static CDataObject *_new_casted_primitive(CTypeDescrObject *ct); /*forward*/ + +static PyObject * +convert_to_object(char *data, CTypeDescrObject *ct) +{ + if (!(ct->ct_flags & CT_PRIMITIVE_ANY)) { + /* non-primitive types (check done just for performance) */ + if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { + char *ptrdata = *(char **)data; + /*READ(data, sizeof(char *))*/ + return new_simple_cdata(ptrdata, ct); + } + else if (ct->ct_flags & CT_IS_OPAQUE) { + PyErr_Format(PyExc_TypeError, "cdata '%s' is opaque", + ct->ct_name); + return NULL; + } + else if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { + return new_simple_cdata(data, ct); + } + else if (ct->ct_flags & CT_ARRAY) { + if (ct->ct_length < 0) { + /* we can't return a <cdata 'int[]'> here, because we don't + know the length to give it. As a compromize, returns + <cdata 'int *'> in this case. */ + ct = (CTypeDescrObject *)ct->ct_stuff; + } + return new_simple_cdata(data, ct); + } + } + else if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { + PY_LONG_LONG value; + /*READ(data, ct->ct_size)*/ + value = read_raw_signed_data(data, ct->ct_size); + if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) + return PyInt_FromLong((long)value); + else + return PyLong_FromLongLong(value); + } + else if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { + unsigned PY_LONG_LONG value; + /*READ(data, ct->ct_size)*/ + value = read_raw_unsigned_data(data, ct->ct_size); + if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) { if (ct->ct_flags & CT_IS_BOOL) { PyObject *x; @@ -1120,137 +1120,137 @@ convert_to_object(char *data, CTypeDescrObject *ct) Py_INCREF(x); return x; } - return PyInt_FromLong((long)value); - } - else - return PyLong_FromUnsignedLongLong(value); - } - else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { - /*READ(data, ct->ct_size)*/ - if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) { - double value = read_raw_float_data(data, ct->ct_size); - return PyFloat_FromDouble(value); - } - else { - long double value = read_raw_longdouble_data(data); - CDataObject *cd = _new_casted_primitive(ct); - if (cd != NULL) - write_raw_longdouble_data(cd->c_data, value); - return (PyObject *)cd; - } - } - else if (ct->ct_flags & CT_PRIMITIVE_CHAR) { - /*READ(data, ct->ct_size)*/ + return PyInt_FromLong((long)value); + } + else + return PyLong_FromUnsignedLongLong(value); + } + else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { + /*READ(data, ct->ct_size)*/ + if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) { + double value = read_raw_float_data(data, ct->ct_size); + return PyFloat_FromDouble(value); + } + else { + long double value = read_raw_longdouble_data(data); + CDataObject *cd = _new_casted_primitive(ct); + if (cd != NULL) + write_raw_longdouble_data(cd->c_data, value); + return (PyObject *)cd; + } + } + else if (ct->ct_flags & CT_PRIMITIVE_CHAR) { + /*READ(data, ct->ct_size)*/ switch (ct->ct_size) { case sizeof(char): - return PyBytes_FromStringAndSize(data, 1); + return PyBytes_FromStringAndSize(data, 1); case 2: return _my_PyUnicode_FromChar16((cffi_char16_t *)data, 1); case 4: return _my_PyUnicode_FromChar32((cffi_char32_t *)data, 1); } - } + } else if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { Py_complex value = read_raw_complex_data(data, ct->ct_size); return PyComplex_FromCComplex(value); } - - PyErr_Format(PyExc_SystemError, - "convert_to_object: '%s'", ct->ct_name); - return NULL; -} - -static PyObject * -convert_to_object_bitfield(char *data, CFieldObject *cf) -{ - CTypeDescrObject *ct = cf->cf_type; - /*READ(data, ct->ct_size)*/ - - if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { - unsigned PY_LONG_LONG value, valuemask, shiftforsign; - PY_LONG_LONG result; - - value = (unsigned PY_LONG_LONG)read_raw_signed_data(data, ct->ct_size); - valuemask = (1ULL << cf->cf_bitsize) - 1ULL; - shiftforsign = 1ULL << (cf->cf_bitsize - 1); - value = ((value >> cf->cf_bitshift) + shiftforsign) & valuemask; - result = ((PY_LONG_LONG)value) - (PY_LONG_LONG)shiftforsign; - - if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) - return PyInt_FromLong((long)result); - else - return PyLong_FromLongLong(result); - } - else { - unsigned PY_LONG_LONG value, valuemask; - - value = read_raw_unsigned_data(data, ct->ct_size); - valuemask = (1ULL << cf->cf_bitsize) - 1ULL; - value = (value >> cf->cf_bitshift) & valuemask; - - if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) - return PyInt_FromLong((long)value); - else - return PyLong_FromUnsignedLongLong(value); - } -} - -static int _convert_overflow(PyObject *init, const char *ct_name) -{ - PyObject *s; - if (PyErr_Occurred()) /* already an exception pending */ - return -1; - s = PyObject_Str(init); - if (s == NULL) - return -1; - PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'", - PyText_AS_UTF8(s), ct_name); - Py_DECREF(s); - return -1; -} - -static int _convert_to_char(PyObject *init) -{ - if (PyBytes_Check(init) && PyBytes_GET_SIZE(init) == 1) { - return (unsigned char)(PyBytes_AS_STRING(init)[0]); - } - if (CData_Check(init) && - (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && - (((CDataObject *)init)->c_type->ct_size == sizeof(char))) { - char *data = ((CDataObject *)init)->c_data; - /*READ(data, 1)*/ - return *(unsigned char *)data; - } - PyErr_Format(PyExc_TypeError, - "initializer for ctype 'char' must be a "STR_OR_BYTES - " of length 1, not %.200s", Py_TYPE(init)->tp_name); - return -1; -} - + + PyErr_Format(PyExc_SystemError, + "convert_to_object: '%s'", ct->ct_name); + return NULL; +} + +static PyObject * +convert_to_object_bitfield(char *data, CFieldObject *cf) +{ + CTypeDescrObject *ct = cf->cf_type; + /*READ(data, ct->ct_size)*/ + + if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { + unsigned PY_LONG_LONG value, valuemask, shiftforsign; + PY_LONG_LONG result; + + value = (unsigned PY_LONG_LONG)read_raw_signed_data(data, ct->ct_size); + valuemask = (1ULL << cf->cf_bitsize) - 1ULL; + shiftforsign = 1ULL << (cf->cf_bitsize - 1); + value = ((value >> cf->cf_bitshift) + shiftforsign) & valuemask; + result = ((PY_LONG_LONG)value) - (PY_LONG_LONG)shiftforsign; + + if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) + return PyInt_FromLong((long)result); + else + return PyLong_FromLongLong(result); + } + else { + unsigned PY_LONG_LONG value, valuemask; + + value = read_raw_unsigned_data(data, ct->ct_size); + valuemask = (1ULL << cf->cf_bitsize) - 1ULL; + value = (value >> cf->cf_bitshift) & valuemask; + + if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) + return PyInt_FromLong((long)value); + else + return PyLong_FromUnsignedLongLong(value); + } +} + +static int _convert_overflow(PyObject *init, const char *ct_name) +{ + PyObject *s; + if (PyErr_Occurred()) /* already an exception pending */ + return -1; + s = PyObject_Str(init); + if (s == NULL) + return -1; + PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'", + PyText_AS_UTF8(s), ct_name); + Py_DECREF(s); + return -1; +} + +static int _convert_to_char(PyObject *init) +{ + if (PyBytes_Check(init) && PyBytes_GET_SIZE(init) == 1) { + return (unsigned char)(PyBytes_AS_STRING(init)[0]); + } + if (CData_Check(init) && + (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && + (((CDataObject *)init)->c_type->ct_size == sizeof(char))) { + char *data = ((CDataObject *)init)->c_data; + /*READ(data, 1)*/ + return *(unsigned char *)data; + } + PyErr_Format(PyExc_TypeError, + "initializer for ctype 'char' must be a "STR_OR_BYTES + " of length 1, not %.200s", Py_TYPE(init)->tp_name); + return -1; +} + static cffi_char16_t _convert_to_char16_t(PyObject *init) -{ +{ char err_got[80]; err_got[0] = 0; - if (PyUnicode_Check(init)) { + if (PyUnicode_Check(init)) { cffi_char16_t ordinal; if (_my_PyUnicode_AsSingleChar16(init, &ordinal, err_got) == 0) - return ordinal; - } - if (CData_Check(init) && - (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && + return ordinal; + } + if (CData_Check(init) && + (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && (((CDataObject *)init)->c_type->ct_size == 2)) { - char *data = ((CDataObject *)init)->c_data; + char *data = ((CDataObject *)init)->c_data; /*READ(data, 2)*/ return *(cffi_char16_t *)data; - } - PyErr_Format(PyExc_TypeError, + } + PyErr_Format(PyExc_TypeError, "initializer for ctype 'char16_t' must be a unicode string " "of length 1, not %.200s", err_got[0] == 0 ? Py_TYPE(init)->tp_name : err_got); return (cffi_char16_t)-1; -} - +} + static cffi_char32_t _convert_to_char32_t(PyObject *init) { char err_got[80]; @@ -1276,26 +1276,26 @@ static cffi_char32_t _convert_to_char32_t(PyObject *init) } static int _convert_error(PyObject *init, CTypeDescrObject *ct, - const char *expected) -{ - if (CData_Check(init)) { + const char *expected) +{ + if (CData_Check(init)) { CTypeDescrObject *ct2 = ((CDataObject *)init)->c_type; if (strcmp(ct->ct_name, ct2->ct_name) != 0) - PyErr_Format(PyExc_TypeError, - "initializer for ctype '%s' must be a %s, " - "not cdata '%s'", + PyErr_Format(PyExc_TypeError, + "initializer for ctype '%s' must be a %s, " + "not cdata '%s'", ct->ct_name, expected, ct2->ct_name); else if (ct != ct2) { - /* in case we'd give the error message "initializer for - ctype 'A' must be a pointer to same type, not cdata - 'B'", but with A=B, then give instead a different error - message to try to clear up the confusion */ - PyErr_Format(PyExc_TypeError, - "initializer for ctype '%s' appears indeed to be '%s'," - " but the types are different (check that you are not" - " e.g. mixing up different ffi instances)", + /* in case we'd give the error message "initializer for + ctype 'A' must be a pointer to same type, not cdata + 'B'", but with A=B, then give instead a different error + message to try to clear up the confusion */ + PyErr_Format(PyExc_TypeError, + "initializer for ctype '%s' appears indeed to be '%s'," + " but the types are different (check that you are not" + " e.g. mixing up different ffi instances)", ct->ct_name, ct2->ct_name); - } + } else { PyErr_Format(PyExc_SystemError, @@ -1303,45 +1303,45 @@ static int _convert_error(PyObject *init, CTypeDescrObject *ct, "an internal mismatch--please report a bug", ct->ct_name); } - } - else - PyErr_Format(PyExc_TypeError, - "initializer for ctype '%s' must be a %s, " - "not %.200s", + } + else + PyErr_Format(PyExc_TypeError, + "initializer for ctype '%s' must be a %s, " + "not %.200s", ct->ct_name, expected, Py_TYPE(init)->tp_name); - return -1; -} - -static int /* forward */ -convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init); -static int /* forward */ -convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init); - -static Py_ssize_t + return -1; +} + +static int /* forward */ +convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init); +static int /* forward */ +convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init); + +static Py_ssize_t get_new_array_length(CTypeDescrObject *ctitem, PyObject **pvalue) -{ - PyObject *value = *pvalue; - - if (PyList_Check(value) || PyTuple_Check(value)) { - return PySequence_Fast_GET_SIZE(value); - } - else if (PyBytes_Check(value)) { - /* from a string, we add the null terminator */ - return PyBytes_GET_SIZE(value) + 1; - } - else if (PyUnicode_Check(value)) { - /* from a unicode, we add the null terminator */ +{ + PyObject *value = *pvalue; + + if (PyList_Check(value) || PyTuple_Check(value)) { + return PySequence_Fast_GET_SIZE(value); + } + else if (PyBytes_Check(value)) { + /* from a string, we add the null terminator */ + return PyBytes_GET_SIZE(value) + 1; + } + else if (PyUnicode_Check(value)) { + /* from a unicode, we add the null terminator */ int length; if (ctitem->ct_size == 2) length = _my_PyUnicode_SizeAsChar16(value); else length = _my_PyUnicode_SizeAsChar32(value); return length + 1; - } - else { - Py_ssize_t explicitlength; - explicitlength = PyNumber_AsSsize_t(value, PyExc_OverflowError); - if (explicitlength < 0) { + } + else { + Py_ssize_t explicitlength; + explicitlength = PyNumber_AsSsize_t(value, PyExc_OverflowError); + if (explicitlength < 0) { if (PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_TypeError)) PyErr_Format(PyExc_TypeError, @@ -1349,25 +1349,25 @@ get_new_array_length(CTypeDescrObject *ctitem, PyObject **pvalue) "not %.200s", Py_TYPE(value)->tp_name); } else - PyErr_SetString(PyExc_ValueError, "negative array length"); - return -1; - } - *pvalue = Py_None; - return explicitlength; - } -} - -static int -convert_field_from_object(char *data, CFieldObject *cf, PyObject *value) -{ - data += cf->cf_offset; - if (cf->cf_bitshift >= 0) - return convert_from_object_bitfield(data, cf, value); - else - return convert_from_object(data, cf->cf_type, value); -} - -static int + PyErr_SetString(PyExc_ValueError, "negative array length"); + return -1; + } + *pvalue = Py_None; + return explicitlength; + } +} + +static int +convert_field_from_object(char *data, CFieldObject *cf, PyObject *value) +{ + data += cf->cf_offset; + if (cf->cf_bitshift >= 0) + return convert_from_object_bitfield(data, cf, value); + else + return convert_from_object(data, cf->cf_type, value); +} + +static int add_varsize_length(Py_ssize_t offset, Py_ssize_t itemsize, Py_ssize_t varsizelength, Py_ssize_t *optvarsize) { @@ -1391,33 +1391,33 @@ convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init, Py_ssize_t *optvarsize); /* forward */ static int -convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value, - Py_ssize_t *optvarsize) -{ - /* a special case for var-sized C99 arrays */ - if ((cf->cf_type->ct_flags & CT_ARRAY) && cf->cf_type->ct_size < 0) { +convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value, + Py_ssize_t *optvarsize) +{ + /* a special case for var-sized C99 arrays */ + if ((cf->cf_type->ct_flags & CT_ARRAY) && cf->cf_type->ct_size < 0) { Py_ssize_t varsizelength = get_new_array_length( cf->cf_type->ct_itemdescr, &value); - if (varsizelength < 0) - return -1; - if (optvarsize != NULL) { - /* in this mode, the only purpose of this function is to compute - the real size of the structure from a var-sized C99 array */ - assert(data == NULL); + if (varsizelength < 0) + return -1; + if (optvarsize != NULL) { + /* in this mode, the only purpose of this function is to compute + the real size of the structure from a var-sized C99 array */ + assert(data == NULL); return add_varsize_length(cf->cf_offset, cf->cf_type->ct_itemdescr->ct_size, varsizelength, optvarsize); - } - /* if 'value' was only an integer, get_new_array_length() returns - it and convert 'value' to be None. Detect if this was the case, - and if so, stop here, leaving the content uninitialized - (it should be zero-initialized from somewhere else). */ - if (value == Py_None) - return 0; - } + } + /* if 'value' was only an integer, get_new_array_length() returns + it and convert 'value' to be None. Detect if this was the case, + and if so, stop here, leaving the content uninitialized + (it should be zero-initialized from somewhere else). */ + if (value == Py_None) + return 0; + } if (optvarsize == NULL) { - return convert_field_from_object(data, cf, value); + return convert_field_from_object(data, cf, value); } else if ((cf->cf_type->ct_flags & CT_WITH_VAR_ARRAY) != 0 && !CData_Check(value)) { @@ -1426,11 +1426,11 @@ convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value, return -1; return add_varsize_length(cf->cf_offset, 1, subsize, optvarsize); } - else - return 0; -} - -static int + else + return 0; +} + +static int must_be_array_of_zero_or_one(const char *data, Py_ssize_t n) { Py_ssize_t i; @@ -1454,90 +1454,90 @@ get_array_length(CDataObject *cd) } static int -convert_array_from_object(char *data, CTypeDescrObject *ct, PyObject *init) -{ - /* used by convert_from_object(), and also to decode lists/tuples/unicodes - passed as function arguments. 'ct' is an CT_ARRAY in the first case - and a CT_POINTER in the second case. */ - const char *expected; - CTypeDescrObject *ctitem = ct->ct_itemdescr; - - if (PyList_Check(init) || PyTuple_Check(init)) { - PyObject **items; - Py_ssize_t i, n; - n = PySequence_Fast_GET_SIZE(init); - if (ct->ct_length >= 0 && n > ct->ct_length) { - PyErr_Format(PyExc_IndexError, - "too many initializers for '%s' (got %zd)", - ct->ct_name, n); - return -1; - } - items = PySequence_Fast_ITEMS(init); - for (i=0; i<n; i++) { - if (convert_from_object(data, ctitem, items[i]) < 0) - return -1; - data += ctitem->ct_size; - } - return 0; - } - else if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) || - ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) - && (ctitem->ct_size == sizeof(char)))) { - if (ctitem->ct_size == sizeof(char)) { - char *srcdata; - Py_ssize_t n; - if (!PyBytes_Check(init)) { - expected = STR_OR_BYTES" or list or tuple"; - goto cannot_convert; - } - n = PyBytes_GET_SIZE(init); - if (ct->ct_length >= 0 && n > ct->ct_length) { - PyErr_Format(PyExc_IndexError, - "initializer "STR_OR_BYTES" is too long for '%s' " - "(got %zd characters)", ct->ct_name, n); - return -1; - } - if (n != ct->ct_length) - n++; - srcdata = PyBytes_AS_STRING(init); +convert_array_from_object(char *data, CTypeDescrObject *ct, PyObject *init) +{ + /* used by convert_from_object(), and also to decode lists/tuples/unicodes + passed as function arguments. 'ct' is an CT_ARRAY in the first case + and a CT_POINTER in the second case. */ + const char *expected; + CTypeDescrObject *ctitem = ct->ct_itemdescr; + + if (PyList_Check(init) || PyTuple_Check(init)) { + PyObject **items; + Py_ssize_t i, n; + n = PySequence_Fast_GET_SIZE(init); + if (ct->ct_length >= 0 && n > ct->ct_length) { + PyErr_Format(PyExc_IndexError, + "too many initializers for '%s' (got %zd)", + ct->ct_name, n); + return -1; + } + items = PySequence_Fast_ITEMS(init); + for (i=0; i<n; i++) { + if (convert_from_object(data, ctitem, items[i]) < 0) + return -1; + data += ctitem->ct_size; + } + return 0; + } + else if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) || + ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) + && (ctitem->ct_size == sizeof(char)))) { + if (ctitem->ct_size == sizeof(char)) { + char *srcdata; + Py_ssize_t n; + if (!PyBytes_Check(init)) { + expected = STR_OR_BYTES" or list or tuple"; + goto cannot_convert; + } + n = PyBytes_GET_SIZE(init); + if (ct->ct_length >= 0 && n > ct->ct_length) { + PyErr_Format(PyExc_IndexError, + "initializer "STR_OR_BYTES" is too long for '%s' " + "(got %zd characters)", ct->ct_name, n); + return -1; + } + if (n != ct->ct_length) + n++; + srcdata = PyBytes_AS_STRING(init); if (ctitem->ct_flags & CT_IS_BOOL) if (must_be_array_of_zero_or_one(srcdata, n) < 0) return -1; - memcpy(data, srcdata, n); - return 0; - } - else { - Py_ssize_t n; - if (!PyUnicode_Check(init)) { - expected = "unicode or list or tuple"; - goto cannot_convert; - } + memcpy(data, srcdata, n); + return 0; + } + else { + Py_ssize_t n; + if (!PyUnicode_Check(init)) { + expected = "unicode or list or tuple"; + goto cannot_convert; + } if (ctitem->ct_size == 4) n = _my_PyUnicode_SizeAsChar32(init); else n = _my_PyUnicode_SizeAsChar16(init); - if (ct->ct_length >= 0 && n > ct->ct_length) { - PyErr_Format(PyExc_IndexError, - "initializer unicode is too long for '%s' " - "(got %zd characters)", ct->ct_name, n); - return -1; - } - if (n != ct->ct_length) - n++; + if (ct->ct_length >= 0 && n > ct->ct_length) { + PyErr_Format(PyExc_IndexError, + "initializer unicode is too long for '%s' " + "(got %zd characters)", ct->ct_name, n); + return -1; + } + if (n != ct->ct_length) + n++; if (ctitem->ct_size == 4) return _my_PyUnicode_AsChar32(init, (cffi_char32_t *)data, n); else return _my_PyUnicode_AsChar16(init, (cffi_char16_t *)data, n); - } - } - else { - expected = "list or tuple"; - goto cannot_convert; - } - - cannot_convert: + } + } + else { + expected = "list or tuple"; + goto cannot_convert; + } + + cannot_convert: if ((ct->ct_flags & CT_ARRAY) && CData_Check(init)) { CDataObject *cd = (CDataObject *)init; @@ -1549,201 +1549,201 @@ convert_array_from_object(char *data, CTypeDescrObject *ct, PyObject *init) } } return _convert_error(init, ct, expected); -} - -static int -convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init, - Py_ssize_t *optvarsize) -{ +} + +static int +convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init, + Py_ssize_t *optvarsize) +{ /* does not accept 'init' being already a CData */ - const char *expected; - - if (force_lazy_struct(ct) <= 0) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_TypeError, "'%s' is opaque", ct->ct_name); - return -1; - } - - if (PyList_Check(init) || PyTuple_Check(init)) { - PyObject **items = PySequence_Fast_ITEMS(init); - Py_ssize_t i, n = PySequence_Fast_GET_SIZE(init); - CFieldObject *cf = (CFieldObject *)ct->ct_extra; - - for (i=0; i<n; i++) { - while (cf != NULL && (cf->cf_flags & BF_IGNORE_IN_CTOR)) - cf = cf->cf_next; - if (cf == NULL) { - PyErr_Format(PyExc_ValueError, - "too many initializers for '%s' (got %zd)", - ct->ct_name, n); - return -1; - } - if (convert_vfield_from_object(data, cf, items[i], optvarsize) < 0) - return -1; - cf = cf->cf_next; - } - return 0; - } - if (PyDict_Check(init)) { - PyObject *d_key, *d_value; - Py_ssize_t i = 0; - CFieldObject *cf; - - while (PyDict_Next(init, &i, &d_key, &d_value)) { - cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, d_key); - if (cf == NULL) { - PyErr_SetObject(PyExc_KeyError, d_key); - return -1; - } - if (convert_vfield_from_object(data, cf, d_value, optvarsize) < 0) - return -1; - } - return 0; - } - expected = optvarsize == NULL ? "list or tuple or dict or struct-cdata" - : "list or tuple or dict"; + const char *expected; + + if (force_lazy_struct(ct) <= 0) { + if (!PyErr_Occurred()) + PyErr_Format(PyExc_TypeError, "'%s' is opaque", ct->ct_name); + return -1; + } + + if (PyList_Check(init) || PyTuple_Check(init)) { + PyObject **items = PySequence_Fast_ITEMS(init); + Py_ssize_t i, n = PySequence_Fast_GET_SIZE(init); + CFieldObject *cf = (CFieldObject *)ct->ct_extra; + + for (i=0; i<n; i++) { + while (cf != NULL && (cf->cf_flags & BF_IGNORE_IN_CTOR)) + cf = cf->cf_next; + if (cf == NULL) { + PyErr_Format(PyExc_ValueError, + "too many initializers for '%s' (got %zd)", + ct->ct_name, n); + return -1; + } + if (convert_vfield_from_object(data, cf, items[i], optvarsize) < 0) + return -1; + cf = cf->cf_next; + } + return 0; + } + if (PyDict_Check(init)) { + PyObject *d_key, *d_value; + Py_ssize_t i = 0; + CFieldObject *cf; + + while (PyDict_Next(init, &i, &d_key, &d_value)) { + cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, d_key); + if (cf == NULL) { + PyErr_SetObject(PyExc_KeyError, d_key); + return -1; + } + if (convert_vfield_from_object(data, cf, d_value, optvarsize) < 0) + return -1; + } + return 0; + } + expected = optvarsize == NULL ? "list or tuple or dict or struct-cdata" + : "list or tuple or dict"; return _convert_error(init, ct, expected); -} - -#ifdef __GNUC__ -# if __GNUC__ >= 4 -/* Don't go inlining this huge function. Needed because occasionally - it gets inlined in places where is causes a warning: call to - __builtin___memcpy_chk will always overflow destination buffer - (which is places where the 'ct' should never represent such a large - primitive type anyway). */ -__attribute__((noinline)) -# endif -#endif -static int -convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init) -{ - const char *expected; - char buf[sizeof(PY_LONG_LONG)]; - - /*if (ct->ct_size > 0)*/ - /*WRITE(data, ct->ct_size)*/ - - if (ct->ct_flags & CT_ARRAY) { - return convert_array_from_object(data, ct, init); - } - if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { - char *ptrdata; - CTypeDescrObject *ctinit; - - if (!CData_Check(init)) { - expected = "cdata pointer"; - goto cannot_convert; - } - ctinit = ((CDataObject *)init)->c_type; - if (!(ctinit->ct_flags & (CT_POINTER|CT_FUNCTIONPTR))) { - if (ctinit->ct_flags & CT_ARRAY) - ctinit = (CTypeDescrObject *)ctinit->ct_stuff; - else { - expected = "pointer or array"; - goto cannot_convert; - } - } - if (ctinit != ct) { - int combined_flags = ct->ct_flags | ctinit->ct_flags; - if (combined_flags & CT_IS_VOID_PTR) - ; /* accept "void *" as either source or target */ - else if (combined_flags & CT_IS_VOIDCHAR_PTR) { - /* for backward compatibility, accept "char *" as either - source of target. This is not what C does, though, - so emit a warning that will eventually turn into an +} + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +/* Don't go inlining this huge function. Needed because occasionally + it gets inlined in places where is causes a warning: call to + __builtin___memcpy_chk will always overflow destination buffer + (which is places where the 'ct' should never represent such a large + primitive type anyway). */ +__attribute__((noinline)) +# endif +#endif +static int +convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init) +{ + const char *expected; + char buf[sizeof(PY_LONG_LONG)]; + + /*if (ct->ct_size > 0)*/ + /*WRITE(data, ct->ct_size)*/ + + if (ct->ct_flags & CT_ARRAY) { + return convert_array_from_object(data, ct, init); + } + if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { + char *ptrdata; + CTypeDescrObject *ctinit; + + if (!CData_Check(init)) { + expected = "cdata pointer"; + goto cannot_convert; + } + ctinit = ((CDataObject *)init)->c_type; + if (!(ctinit->ct_flags & (CT_POINTER|CT_FUNCTIONPTR))) { + if (ctinit->ct_flags & CT_ARRAY) + ctinit = (CTypeDescrObject *)ctinit->ct_stuff; + else { + expected = "pointer or array"; + goto cannot_convert; + } + } + if (ctinit != ct) { + int combined_flags = ct->ct_flags | ctinit->ct_flags; + if (combined_flags & CT_IS_VOID_PTR) + ; /* accept "void *" as either source or target */ + else if (combined_flags & CT_IS_VOIDCHAR_PTR) { + /* for backward compatibility, accept "char *" as either + source of target. This is not what C does, though, + so emit a warning that will eventually turn into an error. The warning is turned off if both types are pointers to single bytes. */ - char *msg = (ct->ct_flags & CT_IS_VOIDCHAR_PTR ? - "implicit cast to 'char *' from a different pointer type: " - "will be forbidden in the future (check that the types " - "are as you expect; use an explicit ffi.cast() if they " - "are correct)" : - "implicit cast from 'char *' to a different pointer type: " - "will be forbidden in the future (check that the types " - "are as you expect; use an explicit ffi.cast() if they " - "are correct)"); + char *msg = (ct->ct_flags & CT_IS_VOIDCHAR_PTR ? + "implicit cast to 'char *' from a different pointer type: " + "will be forbidden in the future (check that the types " + "are as you expect; use an explicit ffi.cast() if they " + "are correct)" : + "implicit cast from 'char *' to a different pointer type: " + "will be forbidden in the future (check that the types " + "are as you expect; use an explicit ffi.cast() if they " + "are correct)"); if ((ct->ct_flags & ctinit->ct_flags & CT_POINTER) && ct->ct_itemdescr->ct_size == 1 && ctinit->ct_itemdescr->ct_size == 1) { /* no warning */ } else if (PyErr_WarnEx(PyExc_UserWarning, msg, 1)) - return -1; - } - else { - expected = "pointer to same type"; - goto cannot_convert; - } - } - ptrdata = ((CDataObject *)init)->c_data; - - *(char **)data = ptrdata; - return 0; - } - if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { - PY_LONG_LONG value = _my_PyLong_AsLongLong(init); - if (value == -1 && PyErr_Occurred()) - return -1; - write_raw_integer_data(buf, value, ct->ct_size); - if (value != read_raw_signed_data(buf, ct->ct_size)) - goto overflow; - write_raw_integer_data(data, value, ct->ct_size); - return 0; - } - if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { - unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(init, 1); - if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) - return -1; + return -1; + } + else { + expected = "pointer to same type"; + goto cannot_convert; + } + } + ptrdata = ((CDataObject *)init)->c_data; + + *(char **)data = ptrdata; + return 0; + } + if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { + PY_LONG_LONG value = _my_PyLong_AsLongLong(init); + if (value == -1 && PyErr_Occurred()) + return -1; + write_raw_integer_data(buf, value, ct->ct_size); + if (value != read_raw_signed_data(buf, ct->ct_size)) + goto overflow; + write_raw_integer_data(data, value, ct->ct_size); + return 0; + } + if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { + unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(init, 1); + if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) + return -1; if (ct->ct_flags & CT_IS_BOOL) { if (value > 1ULL) /* value != 0 && value != 1 */ - goto overflow; + goto overflow; } else { write_raw_integer_data(buf, value, ct->ct_size); if (value != read_raw_unsigned_data(buf, ct->ct_size)) goto overflow; } - write_raw_integer_data(data, value, ct->ct_size); - return 0; - } - if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { - double value; - if ((ct->ct_flags & CT_IS_LONGDOUBLE) && - CData_Check(init) && - (((CDataObject *)init)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { - long double lvalue; - char *initdata = ((CDataObject *)init)->c_data; - /*READ(initdata, sizeof(long double))*/ - lvalue = read_raw_longdouble_data(initdata); - write_raw_longdouble_data(data, lvalue); - return 0; - } - value = PyFloat_AsDouble(init); - if (value == -1.0 && PyErr_Occurred()) - return -1; - if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) - write_raw_float_data(data, value, ct->ct_size); - else - write_raw_longdouble_data(data, (long double)value); - return 0; - } - if (ct->ct_flags & CT_PRIMITIVE_CHAR) { + write_raw_integer_data(data, value, ct->ct_size); + return 0; + } + if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { + double value; + if ((ct->ct_flags & CT_IS_LONGDOUBLE) && + CData_Check(init) && + (((CDataObject *)init)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { + long double lvalue; + char *initdata = ((CDataObject *)init)->c_data; + /*READ(initdata, sizeof(long double))*/ + lvalue = read_raw_longdouble_data(initdata); + write_raw_longdouble_data(data, lvalue); + return 0; + } + value = PyFloat_AsDouble(init); + if (value == -1.0 && PyErr_Occurred()) + return -1; + if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) + write_raw_float_data(data, value, ct->ct_size); + else + write_raw_longdouble_data(data, (long double)value); + return 0; + } + if (ct->ct_flags & CT_PRIMITIVE_CHAR) { switch (ct->ct_size) { case sizeof(char): { - int res = _convert_to_char(init); - if (res < 0) - return -1; - data[0] = res; - return 0; - } + int res = _convert_to_char(init); + if (res < 0) + return -1; + data[0] = res; + return 0; + } case 2: { cffi_char16_t res = _convert_to_char16_t(init); if (res == (cffi_char16_t)-1 && PyErr_Occurred()) - return -1; + return -1; *(cffi_char16_t *)data = res; - return 0; - } + return 0; + } case 4: { cffi_char32_t res = _convert_to_char32_t(init); if (res == (cffi_char32_t)-1 && PyErr_Occurred()) @@ -1752,17 +1752,17 @@ convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init) return 0; } } - } - if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { - - if (CData_Check(init)) { - if (((CDataObject *)init)->c_type == ct && ct->ct_size >= 0) { - memcpy(data, ((CDataObject *)init)->c_data, ct->ct_size); - return 0; - } - } - return convert_struct_from_object(data, ct, init, NULL); - } + } + if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { + + if (CData_Check(init)) { + if (((CDataObject *)init)->c_type == ct && ct->ct_size >= 0) { + memcpy(data, ((CDataObject *)init)->c_data, ct->ct_size); + return 0; + } + } + return convert_struct_from_object(data, ct, init, NULL); + } if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { Py_complex value = PyComplex_AsCComplex(init); if (PyErr_Occurred()) @@ -1770,170 +1770,170 @@ convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init) write_raw_complex_data(data, value, ct->ct_size); return 0; } - PyErr_Format(PyExc_SystemError, - "convert_from_object: '%s'", ct->ct_name); - return -1; - - overflow: - return _convert_overflow(init, ct->ct_name); - - cannot_convert: + PyErr_Format(PyExc_SystemError, + "convert_from_object: '%s'", ct->ct_name); + return -1; + + overflow: + return _convert_overflow(init, ct->ct_name); + + cannot_convert: return _convert_error(init, ct, expected); -} - -static int -convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init) -{ - CTypeDescrObject *ct = cf->cf_type; - PY_LONG_LONG fmin, fmax, value = PyLong_AsLongLong(init); - unsigned PY_LONG_LONG rawfielddata, rawvalue, rawmask; - if (value == -1 && PyErr_Occurred()) - return -1; - - if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { - fmin = -(1LL << (cf->cf_bitsize-1)); - fmax = (1LL << (cf->cf_bitsize-1)) - 1LL; - if (fmax == 0) - fmax = 1; /* special case to let "int x:1" receive "1" */ - } - else { - fmin = 0LL; - fmax = (PY_LONG_LONG)((1ULL << cf->cf_bitsize) - 1ULL); - } - if (value < fmin || value > fmax) { - /* phew, PyErr_Format does not support "%lld" in Python 2.6 */ - PyObject *svalue = NULL, *sfmin = NULL, *sfmax = NULL; - PyObject *lfmin = NULL, *lfmax = NULL; - svalue = PyObject_Str(init); - if (svalue == NULL) goto skip; - lfmin = PyLong_FromLongLong(fmin); - if (lfmin == NULL) goto skip; - sfmin = PyObject_Str(lfmin); - if (sfmin == NULL) goto skip; - lfmax = PyLong_FromLongLong(fmax); - if (lfmax == NULL) goto skip; - sfmax = PyObject_Str(lfmax); - if (sfmax == NULL) goto skip; - PyErr_Format(PyExc_OverflowError, - "value %s outside the range allowed by the " - "bit field width: %s <= x <= %s", - PyText_AS_UTF8(svalue), - PyText_AS_UTF8(sfmin), - PyText_AS_UTF8(sfmax)); - skip: - Py_XDECREF(svalue); - Py_XDECREF(sfmin); - Py_XDECREF(sfmax); - Py_XDECREF(lfmin); - Py_XDECREF(lfmax); - return -1; - } - - rawmask = ((1ULL << cf->cf_bitsize) - 1ULL) << cf->cf_bitshift; - rawvalue = ((unsigned PY_LONG_LONG)value) << cf->cf_bitshift; - /*WRITE(data, ct->ct_size)*/ - rawfielddata = read_raw_unsigned_data(data, ct->ct_size); - rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask); - write_raw_integer_data(data, rawfielddata, ct->ct_size); - return 0; -} - -static int -get_alignment(CTypeDescrObject *ct) -{ - int align; - retry: - if ((ct->ct_flags & (CT_PRIMITIVE_ANY|CT_STRUCT|CT_UNION)) && - !(ct->ct_flags & CT_IS_OPAQUE)) { - align = ct->ct_length; - if (align == -1 && (ct->ct_flags & CT_LAZY_FIELD_LIST)) { - force_lazy_struct(ct); - align = ct->ct_length; - } - } - else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { - struct aligncheck_ptr { char x; char *y; }; - align = offsetof(struct aligncheck_ptr, y); - } - else if (ct->ct_flags & CT_ARRAY) { - ct = ct->ct_itemdescr; - goto retry; - } - else { - PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown alignment", - ct->ct_name); - return -1; - } - - if ((align < 1) || (align & (align-1))) { - PyErr_Format(PyExc_SystemError, - "found for ctype '%s' bogus alignment '%d'", - ct->ct_name, align); - return -1; - } - return align; -} - -static void cdata_dealloc(CDataObject *cd) -{ - if (cd->c_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) cd); - - Py_DECREF(cd->c_type); -#ifndef CFFI_MEM_LEAK /* never release anything, tests only */ - Py_TYPE(cd)->tp_free((PyObject *)cd); -#endif -} - -static void cdataowning_dealloc(CDataObject *cd) -{ - assert(!(cd->c_type->ct_flags & (CT_IS_VOID_PTR | CT_FUNCTIONPTR))); - - if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { +} + +static int +convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init) +{ + CTypeDescrObject *ct = cf->cf_type; + PY_LONG_LONG fmin, fmax, value = PyLong_AsLongLong(init); + unsigned PY_LONG_LONG rawfielddata, rawvalue, rawmask; + if (value == -1 && PyErr_Occurred()) + return -1; + + if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { + fmin = -(1LL << (cf->cf_bitsize-1)); + fmax = (1LL << (cf->cf_bitsize-1)) - 1LL; + if (fmax == 0) + fmax = 1; /* special case to let "int x:1" receive "1" */ + } + else { + fmin = 0LL; + fmax = (PY_LONG_LONG)((1ULL << cf->cf_bitsize) - 1ULL); + } + if (value < fmin || value > fmax) { + /* phew, PyErr_Format does not support "%lld" in Python 2.6 */ + PyObject *svalue = NULL, *sfmin = NULL, *sfmax = NULL; + PyObject *lfmin = NULL, *lfmax = NULL; + svalue = PyObject_Str(init); + if (svalue == NULL) goto skip; + lfmin = PyLong_FromLongLong(fmin); + if (lfmin == NULL) goto skip; + sfmin = PyObject_Str(lfmin); + if (sfmin == NULL) goto skip; + lfmax = PyLong_FromLongLong(fmax); + if (lfmax == NULL) goto skip; + sfmax = PyObject_Str(lfmax); + if (sfmax == NULL) goto skip; + PyErr_Format(PyExc_OverflowError, + "value %s outside the range allowed by the " + "bit field width: %s <= x <= %s", + PyText_AS_UTF8(svalue), + PyText_AS_UTF8(sfmin), + PyText_AS_UTF8(sfmax)); + skip: + Py_XDECREF(svalue); + Py_XDECREF(sfmin); + Py_XDECREF(sfmax); + Py_XDECREF(lfmin); + Py_XDECREF(lfmax); + return -1; + } + + rawmask = ((1ULL << cf->cf_bitsize) - 1ULL) << cf->cf_bitshift; + rawvalue = ((unsigned PY_LONG_LONG)value) << cf->cf_bitshift; + /*WRITE(data, ct->ct_size)*/ + rawfielddata = read_raw_unsigned_data(data, ct->ct_size); + rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask); + write_raw_integer_data(data, rawfielddata, ct->ct_size); + return 0; +} + +static int +get_alignment(CTypeDescrObject *ct) +{ + int align; + retry: + if ((ct->ct_flags & (CT_PRIMITIVE_ANY|CT_STRUCT|CT_UNION)) && + !(ct->ct_flags & CT_IS_OPAQUE)) { + align = ct->ct_length; + if (align == -1 && (ct->ct_flags & CT_LAZY_FIELD_LIST)) { + force_lazy_struct(ct); + align = ct->ct_length; + } + } + else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { + struct aligncheck_ptr { char x; char *y; }; + align = offsetof(struct aligncheck_ptr, y); + } + else if (ct->ct_flags & CT_ARRAY) { + ct = ct->ct_itemdescr; + goto retry; + } + else { + PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown alignment", + ct->ct_name); + return -1; + } + + if ((align < 1) || (align & (align-1))) { + PyErr_Format(PyExc_SystemError, + "found for ctype '%s' bogus alignment '%d'", + ct->ct_name, align); + return -1; + } + return align; +} + +static void cdata_dealloc(CDataObject *cd) +{ + if (cd->c_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) cd); + + Py_DECREF(cd->c_type); +#ifndef CFFI_MEM_LEAK /* never release anything, tests only */ + Py_TYPE(cd)->tp_free((PyObject *)cd); +#endif +} + +static void cdataowning_dealloc(CDataObject *cd) +{ + assert(!(cd->c_type->ct_flags & (CT_IS_VOID_PTR | CT_FUNCTIONPTR))); + + if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { /* for ffi.new("struct *") */ - Py_DECREF(((CDataObject_own_structptr *)cd)->structobj); - } -#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) - if (cd->c_type->ct_flags & (CT_PRIMITIVE_ANY | CT_STRUCT | CT_UNION)) { - assert(cd->c_type->ct_size >= 0); - memset(cd->c_data, 0xDD, cd->c_type->ct_size); - } - else if (cd->c_type->ct_flags & CT_ARRAY) { - Py_ssize_t x = get_array_length(cd); - assert(x >= 0); - x *= cd->c_type->ct_itemdescr->ct_size; - assert(x >= 0); - memset(cd->c_data, 0xDD, x); - } -#endif - cdata_dealloc(cd); -} - -static void cdataowninggc_dealloc(CDataObject *cd) -{ - PyObject_GC_UnTrack(cd); - - if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ - PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; - Py_DECREF(x); - } - else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ + Py_DECREF(((CDataObject_own_structptr *)cd)->structobj); + } +#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) + if (cd->c_type->ct_flags & (CT_PRIMITIVE_ANY | CT_STRUCT | CT_UNION)) { + assert(cd->c_type->ct_size >= 0); + memset(cd->c_data, 0xDD, cd->c_type->ct_size); + } + else if (cd->c_type->ct_flags & CT_ARRAY) { + Py_ssize_t x = get_array_length(cd); + assert(x >= 0); + x *= cd->c_type->ct_itemdescr->ct_size; + assert(x >= 0); + memset(cd->c_data, 0xDD, x); + } +#endif + cdata_dealloc(cd); +} + +static void cdataowninggc_dealloc(CDataObject *cd) +{ + PyObject_GC_UnTrack(cd); + + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ + PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; + Py_DECREF(x); + } + else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = ((CDataObject_closure *)cd)->closure; - PyObject *args = (PyObject *)(closure->user_data); - Py_XDECREF(args); + PyObject *args = (PyObject *)(closure->user_data); + Py_XDECREF(args); #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { ffi_closure_free(closure); } else #endif cffi_closure_free(closure); - } + } else { Py_FatalError("cdata CDataOwningGC_Type with unexpected type flags"); - } - cdata_dealloc(cd); -} - + } + cdata_dealloc(cd); +} + static void cdatafrombuf_dealloc(CDataObject *cd) { Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; @@ -1943,20 +1943,20 @@ static void cdatafrombuf_dealloc(CDataObject *cd) PyObject_Free(view); } -static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg) -{ - if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ - PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; - Py_VISIT(x); - } - else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ +static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg) +{ + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ + PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; + Py_VISIT(x); + } + else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = ((CDataObject_closure *)cd)->closure; - PyObject *args = (PyObject *)(closure->user_data); - Py_VISIT(args); - } - return 0; -} - + PyObject *args = (PyObject *)(closure->user_data); + Py_VISIT(args); + } + return 0; +} + static int cdatafrombuf_traverse(CDataObject *cd, visitproc visit, void *arg) { Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; @@ -1964,24 +1964,24 @@ static int cdatafrombuf_traverse(CDataObject *cd, visitproc visit, void *arg) return 0; } -static int cdataowninggc_clear(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ - CDataObject_own_structptr *cd1 = (CDataObject_own_structptr *)cd; - PyObject *x = cd1->structobj; - Py_INCREF(Py_None); - cd1->structobj = Py_None; - Py_DECREF(x); - } - else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ +static int cdataowninggc_clear(CDataObject *cd) +{ + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ + CDataObject_own_structptr *cd1 = (CDataObject_own_structptr *)cd; + PyObject *x = cd1->structobj; + Py_INCREF(Py_None); + cd1->structobj = Py_None; + Py_DECREF(x); + } + else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = ((CDataObject_closure *)cd)->closure; - PyObject *args = (PyObject *)(closure->user_data); - closure->user_data = NULL; - Py_XDECREF(args); - } - return 0; -} - + PyObject *args = (PyObject *)(closure->user_data); + closure->user_data = NULL; + Py_XDECREF(args); + } + return 0; +} + static int cdatafrombuf_clear(CDataObject *cd) { Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; @@ -1989,28 +1989,28 @@ static int cdatafrombuf_clear(CDataObject *cd) return 0; } -/* forward */ +/* forward */ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, char *objdescr, PyObject *obj, - char *extra_error_line); - - -static void gcp_finalize(PyObject *destructor, PyObject *origobj) -{ - /* NOTE: this decrements the reference count of the two arguments */ - - if (destructor != NULL) { - PyObject *result; - PyObject *error_type, *error_value, *error_traceback; - - /* Save the current exception */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - result = PyObject_CallFunctionObjArgs(destructor, origobj, NULL); - if (result != NULL) { - Py_DECREF(result); - } - else { + char *extra_error_line); + + +static void gcp_finalize(PyObject *destructor, PyObject *origobj) +{ + /* NOTE: this decrements the reference count of the two arguments */ + + if (destructor != NULL) { + PyObject *result; + PyObject *error_type, *error_value, *error_traceback; + + /* Save the current exception */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + result = PyObject_CallFunctionObjArgs(destructor, origobj, NULL); + if (result != NULL) { + Py_DECREF(result); + } + else { PyObject *t, *v, *tb; PyErr_Fetch(&t, &v, &tb); /* Don't use error capture here, because it is very much @@ -2018,155 +2018,155 @@ static void gcp_finalize(PyObject *destructor, PyObject *origobj) * either */ /* ecap = _cffi_start_error_capture(); */ _my_PyErr_WriteUnraisable(t, v, tb, "From callback for ffi.gc ", - origobj, NULL); + origobj, NULL); /* _cffi_stop_error_capture(ecap); */ - } - Py_DECREF(destructor); - - /* Restore the saved exception */ - PyErr_Restore(error_type, error_value, error_traceback); - } - Py_XDECREF(origobj); -} - -static void cdatagcp_finalize(CDataObject_gcp *cd) -{ - PyObject *destructor = cd->destructor; - PyObject *origobj = cd->origobj; - cd->destructor = NULL; - cd->origobj = NULL; - gcp_finalize(destructor, origobj); -} - -static void cdatagcp_dealloc(CDataObject_gcp *cd) -{ - PyObject *destructor = cd->destructor; - PyObject *origobj = cd->origobj; - cdata_dealloc((CDataObject *)cd); - - gcp_finalize(destructor, origobj); -} - -static int cdatagcp_traverse(CDataObject_gcp *cd, visitproc visit, void *arg) -{ - Py_VISIT(cd->destructor); - Py_VISIT(cd->origobj); - return 0; -} - -static PyObject *cdata_float(CDataObject *cd); /*forward*/ - -static PyObject *convert_cdata_to_enum_string(CDataObject *cd, int both) -{ - PyObject *d_key, *d_value; - CTypeDescrObject *ct = cd->c_type; - - assert(ct->ct_flags & CT_IS_ENUM); - d_key = convert_to_object(cd->c_data, ct); - if (d_key == NULL) - return NULL; - - d_value = PyDict_GetItem(PyTuple_GET_ITEM(ct->ct_stuff, 1), d_key); - if (d_value != NULL) { - if (both) { - PyObject *o = PyObject_Str(d_key); - if (o == NULL) - d_value = NULL; - else { - d_value = PyText_FromFormat("%s: %s", - PyText_AS_UTF8(o), - PyText_AS_UTF8(d_value)); - Py_DECREF(o); - } - } - else - Py_INCREF(d_value); - } - else - d_value = PyObject_Str(d_key); - Py_DECREF(d_key); - return d_value; -} - -static PyObject *cdata_repr(CDataObject *cd) -{ - char *extra; - PyObject *result, *s; - - if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { - if (cd->c_type->ct_flags & CT_IS_ENUM) { - s = convert_cdata_to_enum_string(cd, 1); - } - else if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { - long double lvalue; - char buffer[128]; /* big enough */ - /*READ(cd->c_data, sizeof(long double)*/ - lvalue = read_raw_longdouble_data(cd->c_data); - sprintf(buffer, "%LE", lvalue); - s = PyText_FromString(buffer); - } - else { - PyObject *o = convert_to_object(cd->c_data, cd->c_type); - if (o == NULL) - return NULL; - s = PyObject_Repr(o); - Py_DECREF(o); - } - } - else if ((cd->c_type->ct_flags & CT_ARRAY) && cd->c_type->ct_length < 0) { - s = PyText_FromFormat("sliced length %zd", get_array_length(cd)); - } - else { - if (cd->c_data != NULL) { - s = PyText_FromFormat("%p", cd->c_data); - } - else - s = PyText_FromString("NULL"); - } - if (s == NULL) - return NULL; - /* it's slightly confusing to get "<cdata 'struct foo' 0x...>" because the - struct foo is not owned. Trying to make it clearer, write in this - case "<cdata 'struct foo &' 0x...>". */ - if (cd->c_type->ct_flags & (CT_STRUCT|CT_UNION)) - extra = " &"; - else - extra = ""; - result = PyText_FromFormat("<cdata '%s%s' %s>", - cd->c_type->ct_name, extra, - PyText_AsUTF8(s)); - Py_DECREF(s); - return result; -} - -static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x) -{ - PyObject *res, *s = PyObject_Repr(x); - if (s == NULL) - return NULL; - res = PyText_FromFormat("<cdata '%s' %s %s>", - cd->c_type->ct_name, text, PyText_AsUTF8(s)); - Py_DECREF(s); - return res; -} - -static Py_ssize_t _cdata_var_byte_size(CDataObject *cd) -{ - /* If 'cd' is a 'struct foo' or 'struct foo *' allocated with - ffi.new(), and if the struct foo contains a varsize array, - then return the real allocated size. Otherwise, return -1. */ - if (!CDataOwn_Check(cd)) - return -1; - - if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { - cd = (CDataObject *)((CDataObject_own_structptr *)cd)->structobj; - } - if (cd->c_type->ct_flags & CT_WITH_VAR_ARRAY) { - return ((CDataObject_own_length *)cd)->length; - } - return -1; -} - + } + Py_DECREF(destructor); + + /* Restore the saved exception */ + PyErr_Restore(error_type, error_value, error_traceback); + } + Py_XDECREF(origobj); +} + +static void cdatagcp_finalize(CDataObject_gcp *cd) +{ + PyObject *destructor = cd->destructor; + PyObject *origobj = cd->origobj; + cd->destructor = NULL; + cd->origobj = NULL; + gcp_finalize(destructor, origobj); +} + +static void cdatagcp_dealloc(CDataObject_gcp *cd) +{ + PyObject *destructor = cd->destructor; + PyObject *origobj = cd->origobj; + cdata_dealloc((CDataObject *)cd); + + gcp_finalize(destructor, origobj); +} + +static int cdatagcp_traverse(CDataObject_gcp *cd, visitproc visit, void *arg) +{ + Py_VISIT(cd->destructor); + Py_VISIT(cd->origobj); + return 0; +} + +static PyObject *cdata_float(CDataObject *cd); /*forward*/ + +static PyObject *convert_cdata_to_enum_string(CDataObject *cd, int both) +{ + PyObject *d_key, *d_value; + CTypeDescrObject *ct = cd->c_type; + + assert(ct->ct_flags & CT_IS_ENUM); + d_key = convert_to_object(cd->c_data, ct); + if (d_key == NULL) + return NULL; + + d_value = PyDict_GetItem(PyTuple_GET_ITEM(ct->ct_stuff, 1), d_key); + if (d_value != NULL) { + if (both) { + PyObject *o = PyObject_Str(d_key); + if (o == NULL) + d_value = NULL; + else { + d_value = PyText_FromFormat("%s: %s", + PyText_AS_UTF8(o), + PyText_AS_UTF8(d_value)); + Py_DECREF(o); + } + } + else + Py_INCREF(d_value); + } + else + d_value = PyObject_Str(d_key); + Py_DECREF(d_key); + return d_value; +} + +static PyObject *cdata_repr(CDataObject *cd) +{ + char *extra; + PyObject *result, *s; + + if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { + if (cd->c_type->ct_flags & CT_IS_ENUM) { + s = convert_cdata_to_enum_string(cd, 1); + } + else if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { + long double lvalue; + char buffer[128]; /* big enough */ + /*READ(cd->c_data, sizeof(long double)*/ + lvalue = read_raw_longdouble_data(cd->c_data); + sprintf(buffer, "%LE", lvalue); + s = PyText_FromString(buffer); + } + else { + PyObject *o = convert_to_object(cd->c_data, cd->c_type); + if (o == NULL) + return NULL; + s = PyObject_Repr(o); + Py_DECREF(o); + } + } + else if ((cd->c_type->ct_flags & CT_ARRAY) && cd->c_type->ct_length < 0) { + s = PyText_FromFormat("sliced length %zd", get_array_length(cd)); + } + else { + if (cd->c_data != NULL) { + s = PyText_FromFormat("%p", cd->c_data); + } + else + s = PyText_FromString("NULL"); + } + if (s == NULL) + return NULL; + /* it's slightly confusing to get "<cdata 'struct foo' 0x...>" because the + struct foo is not owned. Trying to make it clearer, write in this + case "<cdata 'struct foo &' 0x...>". */ + if (cd->c_type->ct_flags & (CT_STRUCT|CT_UNION)) + extra = " &"; + else + extra = ""; + result = PyText_FromFormat("<cdata '%s%s' %s>", + cd->c_type->ct_name, extra, + PyText_AsUTF8(s)); + Py_DECREF(s); + return result; +} + +static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x) +{ + PyObject *res, *s = PyObject_Repr(x); + if (s == NULL) + return NULL; + res = PyText_FromFormat("<cdata '%s' %s %s>", + cd->c_type->ct_name, text, PyText_AsUTF8(s)); + Py_DECREF(s); + return res; +} + +static Py_ssize_t _cdata_var_byte_size(CDataObject *cd) +{ + /* If 'cd' is a 'struct foo' or 'struct foo *' allocated with + ffi.new(), and if the struct foo contains a varsize array, + then return the real allocated size. Otherwise, return -1. */ + if (!CDataOwn_Check(cd)) + return -1; + + if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { + cd = (CDataObject *)((CDataObject_own_structptr *)cd)->structobj; + } + if (cd->c_type->ct_flags & CT_WITH_VAR_ARRAY) { + return ((CDataObject_own_length *)cd)->length; + } + return -1; +} + static PyObject *_frombuf_repr(CDataObject *cd, const char *cd_type_name) { Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; @@ -2196,87 +2196,87 @@ static PyObject *_frombuf_repr(CDataObject *cd, const char *cd_type_name) } } -static PyObject *cdataowning_repr(CDataObject *cd) -{ - Py_ssize_t size = _cdata_var_byte_size(cd); - if (size < 0) { - if (cd->c_type->ct_flags & CT_POINTER) - size = cd->c_type->ct_itemdescr->ct_size; - else if (cd->c_type->ct_flags & CT_ARRAY) - size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; - else - size = cd->c_type->ct_size; - } - return PyText_FromFormat("<cdata '%s' owning %zd bytes>", - cd->c_type->ct_name, size); -} - -static PyObject *cdataowninggc_repr(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ - PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; - return _cdata_repr2(cd, "handle to", x); - } - else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ +static PyObject *cdataowning_repr(CDataObject *cd) +{ + Py_ssize_t size = _cdata_var_byte_size(cd); + if (size < 0) { + if (cd->c_type->ct_flags & CT_POINTER) + size = cd->c_type->ct_itemdescr->ct_size; + else if (cd->c_type->ct_flags & CT_ARRAY) + size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; + else + size = cd->c_type->ct_size; + } + return PyText_FromFormat("<cdata '%s' owning %zd bytes>", + cd->c_type->ct_name, size); +} + +static PyObject *cdataowninggc_repr(CDataObject *cd) +{ + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ + PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; + return _cdata_repr2(cd, "handle to", x); + } + else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = ((CDataObject_closure *)cd)->closure; PyObject *args = (PyObject *)closure->user_data; - if (args == NULL) - return cdata_repr(cd); - else - return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1)); - } + if (args == NULL) + return cdata_repr(cd); + else + return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1)); + } return cdataowning_repr(cd); /* but should be unreachable */ -} - +} + static PyObject *cdatafrombuf_repr(CDataObject *cd) { return _frombuf_repr(cd, cd->c_type->ct_name); } -static int cdata_nonzero(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { - if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED | - CT_PRIMITIVE_CHAR)) - return read_raw_unsigned_data(cd->c_data, cd->c_type->ct_size) != 0; - - if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { - if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) - return read_raw_longdouble_data(cd->c_data) != 0.0; - return read_raw_float_data(cd->c_data, cd->c_type->ct_size) != 0.0; - } +static int cdata_nonzero(CDataObject *cd) +{ + if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { + if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED | + CT_PRIMITIVE_CHAR)) + return read_raw_unsigned_data(cd->c_data, cd->c_type->ct_size) != 0; + + if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { + if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) + return read_raw_longdouble_data(cd->c_data) != 0.0; + return read_raw_float_data(cd->c_data, cd->c_type->ct_size) != 0.0; + } if (cd->c_type->ct_flags & CT_PRIMITIVE_COMPLEX) { Py_complex value = read_raw_complex_data(cd->c_data, cd->c_type->ct_size); return value.real != 0.0 || value.imag != 0.0; } - } - return cd->c_data != NULL; -} - -static PyObject *cdata_int(CDataObject *cd) -{ - if ((cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) - == (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) { - /* this case is to handle enums, but also serves as a slight - performance improvement for some other primitive types */ - long value; - /*READ(cd->c_data, cd->c_type->ct_size)*/ - value = (long)read_raw_signed_data(cd->c_data, cd->c_type->ct_size); - return PyInt_FromLong(value); - } - if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) { + } + return cd->c_data != NULL; +} + +static PyObject *cdata_int(CDataObject *cd) +{ + if ((cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) + == (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) { + /* this case is to handle enums, but also serves as a slight + performance improvement for some other primitive types */ + long value; + /*READ(cd->c_data, cd->c_type->ct_size)*/ + value = (long)read_raw_signed_data(cd->c_data, cd->c_type->ct_size); + return PyInt_FromLong(value); + } + if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) { PyObject *result = convert_to_object(cd->c_data, cd->c_type); if (result != NULL && PyBool_Check(result)) result = PyInt_FromLong(PyInt_AsLong(result)); return result; - } - else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { - /*READ(cd->c_data, cd->c_type->ct_size)*/ + } + else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { + /*READ(cd->c_data, cd->c_type->ct_size)*/ switch (cd->c_type->ct_size) { case sizeof(char): - return PyInt_FromLong((unsigned char)cd->c_data[0]); + return PyInt_FromLong((unsigned char)cd->c_data[0]); case 2: return PyInt_FromLong((long)*(cffi_char16_t *)cd->c_data); case 4: @@ -2287,59 +2287,59 @@ static PyObject *cdata_int(CDataObject *cd) else return PyLong_FromUnsignedLong(*(uint32_t *)cd->c_data); } - } - else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { - PyObject *o = cdata_float(cd); -#if PY_MAJOR_VERSION < 3 - PyObject *r = o ? PyNumber_Int(o) : NULL; -#else - PyObject *r = o ? PyNumber_Long(o) : NULL; -#endif - Py_XDECREF(o); - return r; - } - PyErr_Format(PyExc_TypeError, "int() not supported on cdata '%s'", - cd->c_type->ct_name); - return NULL; -} - -#if PY_MAJOR_VERSION < 3 -static PyObject *cdata_long(CDataObject *cd) -{ - PyObject *res = cdata_int(cd); - if (res != NULL && PyInt_CheckExact(res)) { - PyObject *o = PyLong_FromLong(PyInt_AS_LONG(res)); - Py_DECREF(res); - res = o; - } - return res; -} -#endif - -static PyObject *cdata_float(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { - double value; - /*READ(cd->c_data, cd->c_type->ct_size)*/ - if (!(cd->c_type->ct_flags & CT_IS_LONGDOUBLE)) { - value = read_raw_float_data(cd->c_data, cd->c_type->ct_size); - } - else { - value = (double)read_raw_longdouble_data(cd->c_data); - } - return PyFloat_FromDouble(value); - } - PyErr_Format(PyExc_TypeError, "float() not supported on cdata '%s'", - cd->c_type->ct_name); - return NULL; -} - -static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op) -{ + } + else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { + PyObject *o = cdata_float(cd); +#if PY_MAJOR_VERSION < 3 + PyObject *r = o ? PyNumber_Int(o) : NULL; +#else + PyObject *r = o ? PyNumber_Long(o) : NULL; +#endif + Py_XDECREF(o); + return r; + } + PyErr_Format(PyExc_TypeError, "int() not supported on cdata '%s'", + cd->c_type->ct_name); + return NULL; +} + +#if PY_MAJOR_VERSION < 3 +static PyObject *cdata_long(CDataObject *cd) +{ + PyObject *res = cdata_int(cd); + if (res != NULL && PyInt_CheckExact(res)) { + PyObject *o = PyLong_FromLong(PyInt_AS_LONG(res)); + Py_DECREF(res); + res = o; + } + return res; +} +#endif + +static PyObject *cdata_float(CDataObject *cd) +{ + if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { + double value; + /*READ(cd->c_data, cd->c_type->ct_size)*/ + if (!(cd->c_type->ct_flags & CT_IS_LONGDOUBLE)) { + value = read_raw_float_data(cd->c_data, cd->c_type->ct_size); + } + else { + value = (double)read_raw_longdouble_data(cd->c_data); + } + return PyFloat_FromDouble(value); + } + PyErr_Format(PyExc_TypeError, "float() not supported on cdata '%s'", + cd->c_type->ct_name); + return NULL; +} + +static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op) +{ int v_is_ptr, w_is_ptr; - PyObject *pyres; - - assert(CData_Check(v)); + PyObject *pyres; + + assert(CData_Check(v)); /* Comparisons involving a primitive cdata work differently than * comparisons involving a struct/array/pointer. @@ -2373,16 +2373,16 @@ static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op) pyres = res ? Py_True : Py_False; } else if (v_is_ptr || w_is_ptr) { - pyres = Py_NotImplemented; - } + pyres = Py_NotImplemented; + } else { PyObject *aa[2]; int i; - + aa[0] = v; Py_INCREF(v); aa[1] = w; Py_INCREF(w); pyres = NULL; - + for (i = 0; i < 2; i++) { v = aa[i]; if (!CData_Check(v)) @@ -2407,17 +2407,17 @@ static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op) Py_DECREF(aa[0]); return pyres; } - - Py_INCREF(pyres); - return pyres; -} - + + Py_INCREF(pyres); + return pyres; +} + #if PY_MAJOR_VERSION < 3 typedef long Py_hash_t; #endif static Py_hash_t cdata_hash(PyObject *v) -{ +{ if (((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY) { PyObject *vv = convert_to_object(((CDataObject *)v)->c_data, ((CDataObject *)v)->c_type); @@ -2431,388 +2431,388 @@ static Py_hash_t cdata_hash(PyObject *v) Py_DECREF(vv); } return _Py_HashPointer(((CDataObject *)v)->c_data); -} - -static Py_ssize_t -cdata_length(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_ARRAY) { - return get_array_length(cd); - } - PyErr_Format(PyExc_TypeError, "cdata of type '%s' has no len()", - cd->c_type->ct_name); - return -1; -} - -static char * -_cdata_get_indexed_ptr(CDataObject *cd, PyObject *key) -{ - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - - if (cd->c_type->ct_flags & CT_POINTER) { - if (CDataOwn_Check(cd)) { - if (i != 0) { - PyErr_Format(PyExc_IndexError, - "cdata '%s' can only be indexed by 0", - cd->c_type->ct_name); - return NULL; - } - } - else { - if (cd->c_data == NULL) { - PyErr_Format(PyExc_RuntimeError, - "cannot dereference null pointer from cdata '%s'", - cd->c_type->ct_name); - return NULL; - } - } - } - else if (cd->c_type->ct_flags & CT_ARRAY) { - if (i < 0) { - PyErr_SetString(PyExc_IndexError, +} + +static Py_ssize_t +cdata_length(CDataObject *cd) +{ + if (cd->c_type->ct_flags & CT_ARRAY) { + return get_array_length(cd); + } + PyErr_Format(PyExc_TypeError, "cdata of type '%s' has no len()", + cd->c_type->ct_name); + return -1; +} + +static char * +_cdata_get_indexed_ptr(CDataObject *cd, PyObject *key) +{ + Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + + if (cd->c_type->ct_flags & CT_POINTER) { + if (CDataOwn_Check(cd)) { + if (i != 0) { + PyErr_Format(PyExc_IndexError, + "cdata '%s' can only be indexed by 0", + cd->c_type->ct_name); + return NULL; + } + } + else { + if (cd->c_data == NULL) { + PyErr_Format(PyExc_RuntimeError, + "cannot dereference null pointer from cdata '%s'", + cd->c_type->ct_name); + return NULL; + } + } + } + else if (cd->c_type->ct_flags & CT_ARRAY) { + if (i < 0) { + PyErr_SetString(PyExc_IndexError, "negative index"); - return NULL; - } - if (i >= get_array_length(cd)) { - PyErr_Format(PyExc_IndexError, - "index too large for cdata '%s' (expected %zd < %zd)", - cd->c_type->ct_name, - i, get_array_length(cd)); - return NULL; - } - } - else { - PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", - cd->c_type->ct_name); - return NULL; - } - return cd->c_data + i * cd->c_type->ct_itemdescr->ct_size; -} - -static PyObject * -new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length); /* forward */ - -static CTypeDescrObject * -_cdata_getslicearg(CDataObject *cd, PySliceObject *slice, Py_ssize_t bounds[]) -{ - Py_ssize_t start, stop; - CTypeDescrObject *ct; - - start = PyInt_AsSsize_t(slice->start); - if (start == -1 && PyErr_Occurred()) { - if (slice->start == Py_None) - PyErr_SetString(PyExc_IndexError, "slice start must be specified"); - return NULL; - } - stop = PyInt_AsSsize_t(slice->stop); - if (stop == -1 && PyErr_Occurred()) { - if (slice->stop == Py_None) - PyErr_SetString(PyExc_IndexError, "slice stop must be specified"); - return NULL; - } - if (slice->step != Py_None) { - PyErr_SetString(PyExc_IndexError, "slice with step not supported"); - return NULL; - } - if (start > stop) { - PyErr_SetString(PyExc_IndexError, "slice start > stop"); - return NULL; - } - - ct = cd->c_type; - if (ct->ct_flags & CT_ARRAY) { - if (start < 0) { - PyErr_SetString(PyExc_IndexError, + return NULL; + } + if (i >= get_array_length(cd)) { + PyErr_Format(PyExc_IndexError, + "index too large for cdata '%s' (expected %zd < %zd)", + cd->c_type->ct_name, + i, get_array_length(cd)); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", + cd->c_type->ct_name); + return NULL; + } + return cd->c_data + i * cd->c_type->ct_itemdescr->ct_size; +} + +static PyObject * +new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length); /* forward */ + +static CTypeDescrObject * +_cdata_getslicearg(CDataObject *cd, PySliceObject *slice, Py_ssize_t bounds[]) +{ + Py_ssize_t start, stop; + CTypeDescrObject *ct; + + start = PyInt_AsSsize_t(slice->start); + if (start == -1 && PyErr_Occurred()) { + if (slice->start == Py_None) + PyErr_SetString(PyExc_IndexError, "slice start must be specified"); + return NULL; + } + stop = PyInt_AsSsize_t(slice->stop); + if (stop == -1 && PyErr_Occurred()) { + if (slice->stop == Py_None) + PyErr_SetString(PyExc_IndexError, "slice stop must be specified"); + return NULL; + } + if (slice->step != Py_None) { + PyErr_SetString(PyExc_IndexError, "slice with step not supported"); + return NULL; + } + if (start > stop) { + PyErr_SetString(PyExc_IndexError, "slice start > stop"); + return NULL; + } + + ct = cd->c_type; + if (ct->ct_flags & CT_ARRAY) { + if (start < 0) { + PyErr_SetString(PyExc_IndexError, "negative index"); - return NULL; - } - if (stop > get_array_length(cd)) { - PyErr_Format(PyExc_IndexError, - "index too large (expected %zd <= %zd)", - stop, get_array_length(cd)); - return NULL; - } - ct = (CTypeDescrObject *)ct->ct_stuff; - } - else if (!(ct->ct_flags & CT_POINTER)) { - PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", - ct->ct_name); - return NULL; - } - - bounds[0] = start; - bounds[1] = stop - start; - return ct; -} - -static PyObject * -cdata_slice(CDataObject *cd, PySliceObject *slice) -{ - char *cdata; - Py_ssize_t bounds[2]; - CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); - if (ct == NULL) - return NULL; - - if (ct->ct_stuff == NULL) { - ct->ct_stuff = new_array_type(ct, -1); - if (ct->ct_stuff == NULL) - return NULL; - } - ct = (CTypeDescrObject *)ct->ct_stuff; - - cdata = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0]; - return new_sized_cdata(cdata, ct, bounds[1]); -} - -static int -cdata_ass_slice(CDataObject *cd, PySliceObject *slice, PyObject *v) -{ - Py_ssize_t bounds[2], i, length, itemsize; - PyObject *it, *item; - PyObject *(*iternext)(PyObject *); - char *cdata; - int err; - CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); - if (ct == NULL) - return -1; - ct = ct->ct_itemdescr; - itemsize = ct->ct_size; - cdata = cd->c_data + itemsize * bounds[0]; - length = bounds[1]; - - if (CData_Check(v)) { - CTypeDescrObject *ctv = ((CDataObject *)v)->c_type; - if ((ctv->ct_flags & CT_ARRAY) && (ctv->ct_itemdescr == ct) && - (get_array_length((CDataObject *)v) == length)) { - /* fast path: copying from exactly the correct type */ - memmove(cdata, ((CDataObject *)v)->c_data, itemsize * length); - return 0; - } - } - - /* A fast path for <char[]>[0:N] = b"somestring" or bytearray, which - also adds support for Python 3: otherwise, you get integers while - enumerating the string, and you can't set them to characters :-/ - */ - if ((ct->ct_flags & CT_PRIMITIVE_CHAR) && itemsize == sizeof(char)) { - char *src; - Py_ssize_t srclen; - if (PyBytes_Check(v)) { - srclen = PyBytes_GET_SIZE(v); - src = PyBytes_AS_STRING(v); - } - else if (PyByteArray_Check(v)) { - srclen = PyByteArray_GET_SIZE(v); - src = PyByteArray_AS_STRING(v); - } - else - goto other_types; - - if (srclen != length) { - PyErr_Format(PyExc_ValueError, - "need a string of length %zd, got %zd", - length, srclen); - return -1; - } - memcpy(cdata, src, length); - return 0; - } - other_types: - - it = PyObject_GetIter(v); - if (it == NULL) - return -1; - iternext = *it->ob_type->tp_iternext; - - for (i = 0; i < length; i++) { - item = iternext(it); - if (item == NULL) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_ValueError, - "need %zd values to unpack, got %zd", - length, i); - goto error; - } - err = convert_from_object(cdata, ct, item); - Py_DECREF(item); - if (err < 0) - goto error; - - cdata += itemsize; - } - item = iternext(it); - if (item != NULL) { - Py_DECREF(item); - PyErr_Format(PyExc_ValueError, - "got more than %zd values to unpack", length); - } - error: - Py_DECREF(it); - return PyErr_Occurred() ? -1 : 0; -} - -static PyObject * -cdataowning_subscript(CDataObject *cd, PyObject *key) -{ - char *c; - if (PySlice_Check(key)) - return cdata_slice(cd, (PySliceObject *)key); - - c = _cdata_get_indexed_ptr(cd, key); - /* use 'mp_subscript' instead of 'sq_item' because we don't want - negative indexes to be corrected automatically */ - if (c == NULL && PyErr_Occurred()) - return NULL; - - if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { - PyObject *res = ((CDataObject_own_structptr *)cd)->structobj; - Py_INCREF(res); - return res; - } - else { - return convert_to_object(c, cd->c_type->ct_itemdescr); - } -} - -static PyObject * -cdata_subscript(CDataObject *cd, PyObject *key) -{ - char *c; - if (PySlice_Check(key)) - return cdata_slice(cd, (PySliceObject *)key); - - c = _cdata_get_indexed_ptr(cd, key); - /* use 'mp_subscript' instead of 'sq_item' because we don't want - negative indexes to be corrected automatically */ - if (c == NULL && PyErr_Occurred()) - return NULL; - return convert_to_object(c, cd->c_type->ct_itemdescr); -} - -static int -cdata_ass_sub(CDataObject *cd, PyObject *key, PyObject *v) -{ - char *c; - CTypeDescrObject *ctitem; - if (PySlice_Check(key)) - return cdata_ass_slice(cd, (PySliceObject *)key, v); - - c = _cdata_get_indexed_ptr(cd, key); - ctitem = cd->c_type->ct_itemdescr; - /* use 'mp_ass_subscript' instead of 'sq_ass_item' because we don't want - negative indexes to be corrected automatically */ - if (c == NULL && PyErr_Occurred()) - return -1; - if (v == NULL) { - PyErr_SetString(PyExc_TypeError, - "'del x[n]' not supported for cdata objects"); - return -1; - } - return convert_from_object(c, ctitem, v); -} - -static PyObject * -_cdata_add_or_sub(PyObject *v, PyObject *w, int sign) -{ - Py_ssize_t i, itemsize; - CDataObject *cd; - CTypeDescrObject *ctptr; - - if (!CData_Check(v)) { - PyObject *swap; - assert(CData_Check(w)); - if (sign != 1) - goto not_implemented; - swap = v; - v = w; - w = swap; - } - - i = PyNumber_AsSsize_t(w, PyExc_OverflowError); - if (i == -1 && PyErr_Occurred()) - return NULL; - i *= sign; - - cd = (CDataObject *)v; - if (cd->c_type->ct_flags & CT_POINTER) - ctptr = cd->c_type; - else if (cd->c_type->ct_flags & CT_ARRAY) { - ctptr = (CTypeDescrObject *)cd->c_type->ct_stuff; - } - else { - PyErr_Format(PyExc_TypeError, "cannot add a cdata '%s' and a number", - cd->c_type->ct_name); - return NULL; - } - itemsize = ctptr->ct_itemdescr->ct_size; - if (itemsize < 0) { - if (ctptr->ct_flags & CT_IS_VOID_PTR) { - itemsize = 1; - } - else { - PyErr_Format(PyExc_TypeError, - "ctype '%s' points to items of unknown size", - cd->c_type->ct_name); - return NULL; - } - } - return new_simple_cdata(cd->c_data + i * itemsize, ctptr); - - not_implemented: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -static PyObject * -cdata_add(PyObject *v, PyObject *w) -{ - return _cdata_add_or_sub(v, w, +1); -} - -static PyObject * -cdata_sub(PyObject *v, PyObject *w) -{ - if (CData_Check(v) && CData_Check(w)) { - CDataObject *cdv = (CDataObject *)v; - CDataObject *cdw = (CDataObject *)w; - CTypeDescrObject *ct = cdw->c_type; - Py_ssize_t diff, itemsize; - - if (ct->ct_flags & CT_ARRAY) /* ptr_to_T - array_of_T: ok */ - ct = (CTypeDescrObject *)ct->ct_stuff; - - if (ct != cdv->c_type || !(ct->ct_flags & CT_POINTER) || - (ct->ct_itemdescr->ct_size <= 0 && - !(ct->ct_flags & CT_IS_VOID_PTR))) { - PyErr_Format(PyExc_TypeError, - "cannot subtract cdata '%s' and cdata '%s'", - cdv->c_type->ct_name, ct->ct_name); - return NULL; - } - itemsize = ct->ct_itemdescr->ct_size; - diff = cdv->c_data - cdw->c_data; - if (itemsize > 1) { - if (diff % itemsize) { - PyErr_SetString(PyExc_ValueError, - "pointer subtraction: the distance between the two " - "pointers is not a multiple of the item size"); - return NULL; - } - diff = diff / itemsize; - } -#if PY_MAJOR_VERSION < 3 - return PyInt_FromSsize_t(diff); -#else - return PyLong_FromSsize_t(diff); -#endif - } - - return _cdata_add_or_sub(v, w, -1); -} - + return NULL; + } + if (stop > get_array_length(cd)) { + PyErr_Format(PyExc_IndexError, + "index too large (expected %zd <= %zd)", + stop, get_array_length(cd)); + return NULL; + } + ct = (CTypeDescrObject *)ct->ct_stuff; + } + else if (!(ct->ct_flags & CT_POINTER)) { + PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", + ct->ct_name); + return NULL; + } + + bounds[0] = start; + bounds[1] = stop - start; + return ct; +} + +static PyObject * +cdata_slice(CDataObject *cd, PySliceObject *slice) +{ + char *cdata; + Py_ssize_t bounds[2]; + CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); + if (ct == NULL) + return NULL; + + if (ct->ct_stuff == NULL) { + ct->ct_stuff = new_array_type(ct, -1); + if (ct->ct_stuff == NULL) + return NULL; + } + ct = (CTypeDescrObject *)ct->ct_stuff; + + cdata = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0]; + return new_sized_cdata(cdata, ct, bounds[1]); +} + +static int +cdata_ass_slice(CDataObject *cd, PySliceObject *slice, PyObject *v) +{ + Py_ssize_t bounds[2], i, length, itemsize; + PyObject *it, *item; + PyObject *(*iternext)(PyObject *); + char *cdata; + int err; + CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); + if (ct == NULL) + return -1; + ct = ct->ct_itemdescr; + itemsize = ct->ct_size; + cdata = cd->c_data + itemsize * bounds[0]; + length = bounds[1]; + + if (CData_Check(v)) { + CTypeDescrObject *ctv = ((CDataObject *)v)->c_type; + if ((ctv->ct_flags & CT_ARRAY) && (ctv->ct_itemdescr == ct) && + (get_array_length((CDataObject *)v) == length)) { + /* fast path: copying from exactly the correct type */ + memmove(cdata, ((CDataObject *)v)->c_data, itemsize * length); + return 0; + } + } + + /* A fast path for <char[]>[0:N] = b"somestring" or bytearray, which + also adds support for Python 3: otherwise, you get integers while + enumerating the string, and you can't set them to characters :-/ + */ + if ((ct->ct_flags & CT_PRIMITIVE_CHAR) && itemsize == sizeof(char)) { + char *src; + Py_ssize_t srclen; + if (PyBytes_Check(v)) { + srclen = PyBytes_GET_SIZE(v); + src = PyBytes_AS_STRING(v); + } + else if (PyByteArray_Check(v)) { + srclen = PyByteArray_GET_SIZE(v); + src = PyByteArray_AS_STRING(v); + } + else + goto other_types; + + if (srclen != length) { + PyErr_Format(PyExc_ValueError, + "need a string of length %zd, got %zd", + length, srclen); + return -1; + } + memcpy(cdata, src, length); + return 0; + } + other_types: + + it = PyObject_GetIter(v); + if (it == NULL) + return -1; + iternext = *it->ob_type->tp_iternext; + + for (i = 0; i < length; i++) { + item = iternext(it); + if (item == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(PyExc_ValueError, + "need %zd values to unpack, got %zd", + length, i); + goto error; + } + err = convert_from_object(cdata, ct, item); + Py_DECREF(item); + if (err < 0) + goto error; + + cdata += itemsize; + } + item = iternext(it); + if (item != NULL) { + Py_DECREF(item); + PyErr_Format(PyExc_ValueError, + "got more than %zd values to unpack", length); + } + error: + Py_DECREF(it); + return PyErr_Occurred() ? -1 : 0; +} + +static PyObject * +cdataowning_subscript(CDataObject *cd, PyObject *key) +{ + char *c; + if (PySlice_Check(key)) + return cdata_slice(cd, (PySliceObject *)key); + + c = _cdata_get_indexed_ptr(cd, key); + /* use 'mp_subscript' instead of 'sq_item' because we don't want + negative indexes to be corrected automatically */ + if (c == NULL && PyErr_Occurred()) + return NULL; + + if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { + PyObject *res = ((CDataObject_own_structptr *)cd)->structobj; + Py_INCREF(res); + return res; + } + else { + return convert_to_object(c, cd->c_type->ct_itemdescr); + } +} + +static PyObject * +cdata_subscript(CDataObject *cd, PyObject *key) +{ + char *c; + if (PySlice_Check(key)) + return cdata_slice(cd, (PySliceObject *)key); + + c = _cdata_get_indexed_ptr(cd, key); + /* use 'mp_subscript' instead of 'sq_item' because we don't want + negative indexes to be corrected automatically */ + if (c == NULL && PyErr_Occurred()) + return NULL; + return convert_to_object(c, cd->c_type->ct_itemdescr); +} + +static int +cdata_ass_sub(CDataObject *cd, PyObject *key, PyObject *v) +{ + char *c; + CTypeDescrObject *ctitem; + if (PySlice_Check(key)) + return cdata_ass_slice(cd, (PySliceObject *)key, v); + + c = _cdata_get_indexed_ptr(cd, key); + ctitem = cd->c_type->ct_itemdescr; + /* use 'mp_ass_subscript' instead of 'sq_ass_item' because we don't want + negative indexes to be corrected automatically */ + if (c == NULL && PyErr_Occurred()) + return -1; + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "'del x[n]' not supported for cdata objects"); + return -1; + } + return convert_from_object(c, ctitem, v); +} + +static PyObject * +_cdata_add_or_sub(PyObject *v, PyObject *w, int sign) +{ + Py_ssize_t i, itemsize; + CDataObject *cd; + CTypeDescrObject *ctptr; + + if (!CData_Check(v)) { + PyObject *swap; + assert(CData_Check(w)); + if (sign != 1) + goto not_implemented; + swap = v; + v = w; + w = swap; + } + + i = PyNumber_AsSsize_t(w, PyExc_OverflowError); + if (i == -1 && PyErr_Occurred()) + return NULL; + i *= sign; + + cd = (CDataObject *)v; + if (cd->c_type->ct_flags & CT_POINTER) + ctptr = cd->c_type; + else if (cd->c_type->ct_flags & CT_ARRAY) { + ctptr = (CTypeDescrObject *)cd->c_type->ct_stuff; + } + else { + PyErr_Format(PyExc_TypeError, "cannot add a cdata '%s' and a number", + cd->c_type->ct_name); + return NULL; + } + itemsize = ctptr->ct_itemdescr->ct_size; + if (itemsize < 0) { + if (ctptr->ct_flags & CT_IS_VOID_PTR) { + itemsize = 1; + } + else { + PyErr_Format(PyExc_TypeError, + "ctype '%s' points to items of unknown size", + cd->c_type->ct_name); + return NULL; + } + } + return new_simple_cdata(cd->c_data + i * itemsize, ctptr); + + not_implemented: + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyObject * +cdata_add(PyObject *v, PyObject *w) +{ + return _cdata_add_or_sub(v, w, +1); +} + +static PyObject * +cdata_sub(PyObject *v, PyObject *w) +{ + if (CData_Check(v) && CData_Check(w)) { + CDataObject *cdv = (CDataObject *)v; + CDataObject *cdw = (CDataObject *)w; + CTypeDescrObject *ct = cdw->c_type; + Py_ssize_t diff, itemsize; + + if (ct->ct_flags & CT_ARRAY) /* ptr_to_T - array_of_T: ok */ + ct = (CTypeDescrObject *)ct->ct_stuff; + + if (ct != cdv->c_type || !(ct->ct_flags & CT_POINTER) || + (ct->ct_itemdescr->ct_size <= 0 && + !(ct->ct_flags & CT_IS_VOID_PTR))) { + PyErr_Format(PyExc_TypeError, + "cannot subtract cdata '%s' and cdata '%s'", + cdv->c_type->ct_name, ct->ct_name); + return NULL; + } + itemsize = ct->ct_itemdescr->ct_size; + diff = cdv->c_data - cdw->c_data; + if (itemsize > 1) { + if (diff % itemsize) { + PyErr_SetString(PyExc_ValueError, + "pointer subtraction: the distance between the two " + "pointers is not a multiple of the item size"); + return NULL; + } + diff = diff / itemsize; + } +#if PY_MAJOR_VERSION < 3 + return PyInt_FromSsize_t(diff); +#else + return PyLong_FromSsize_t(diff); +#endif + } + + return _cdata_add_or_sub(v, w, -1); +} + static void _cdata_attr_errmsg(char *errmsg, CDataObject *cd, PyObject *attr) { @@ -2826,332 +2826,332 @@ _cdata_attr_errmsg(char *errmsg, CDataObject *cd, PyObject *attr) PyErr_Format(PyExc_AttributeError, errmsg, cd->c_type->ct_name, text); } -static PyObject * -cdata_getattro(CDataObject *cd, PyObject *attr) -{ - CFieldObject *cf; - CTypeDescrObject *ct = cd->c_type; +static PyObject * +cdata_getattro(CDataObject *cd, PyObject *attr) +{ + CFieldObject *cf; + CTypeDescrObject *ct = cd->c_type; char *errmsg = "cdata '%s' has no attribute '%s'"; PyObject *x; - - if (ct->ct_flags & CT_POINTER) - ct = ct->ct_itemdescr; - - if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { - switch (force_lazy_struct(ct)) { - case 1: - cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); - if (cf != NULL) { - /* read the field 'cf' */ - char *data = cd->c_data + cf->cf_offset; - Py_ssize_t array_len, size; - - if (cf->cf_bitshift == BS_REGULAR) { - return convert_to_object(data, cf->cf_type); - } - else if (cf->cf_bitshift != BS_EMPTY_ARRAY) { - return convert_to_object_bitfield(data, cf); - } - - /* variable-length array: */ - /* if reading variable length array from variable length - struct, calculate array type from allocated length */ - size = _cdata_var_byte_size(cd) - cf->cf_offset; - if (size >= 0) { - array_len = size / cf->cf_type->ct_itemdescr->ct_size; - return new_sized_cdata(data, cf->cf_type, array_len); - } - return new_simple_cdata(data, - (CTypeDescrObject *)cf->cf_type->ct_stuff); - } + + if (ct->ct_flags & CT_POINTER) + ct = ct->ct_itemdescr; + + if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { + switch (force_lazy_struct(ct)) { + case 1: + cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); + if (cf != NULL) { + /* read the field 'cf' */ + char *data = cd->c_data + cf->cf_offset; + Py_ssize_t array_len, size; + + if (cf->cf_bitshift == BS_REGULAR) { + return convert_to_object(data, cf->cf_type); + } + else if (cf->cf_bitshift != BS_EMPTY_ARRAY) { + return convert_to_object_bitfield(data, cf); + } + + /* variable-length array: */ + /* if reading variable length array from variable length + struct, calculate array type from allocated length */ + size = _cdata_var_byte_size(cd) - cf->cf_offset; + if (size >= 0) { + array_len = size / cf->cf_type->ct_itemdescr->ct_size; + return new_sized_cdata(data, cf->cf_type, array_len); + } + return new_simple_cdata(data, + (CTypeDescrObject *)cf->cf_type->ct_stuff); + } errmsg = "cdata '%s' has no field '%s'"; - break; - case -1: - return NULL; - default: + break; + case -1: + return NULL; + default: errmsg = "cdata '%s' points to an opaque type: cannot read fields"; - break; - } - } + break; + } + } x = PyObject_GenericGetAttr((PyObject *)cd, attr); if (x == NULL) _cdata_attr_errmsg(errmsg, cd, attr); return x; -} - -static int -cdata_setattro(CDataObject *cd, PyObject *attr, PyObject *value) -{ - CFieldObject *cf; - CTypeDescrObject *ct = cd->c_type; +} + +static int +cdata_setattro(CDataObject *cd, PyObject *attr, PyObject *value) +{ + CFieldObject *cf; + CTypeDescrObject *ct = cd->c_type; char *errmsg = "cdata '%s' has no attribute '%s'"; int x; - - if (ct->ct_flags & CT_POINTER) - ct = ct->ct_itemdescr; - - if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { - switch (force_lazy_struct(ct)) { - case 1: - cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); - if (cf != NULL) { - /* write the field 'cf' */ - if (value != NULL) { - return convert_field_from_object(cd->c_data, cf, value); - } - else { - PyErr_SetString(PyExc_AttributeError, - "cannot delete struct field"); - return -1; - } - } + + if (ct->ct_flags & CT_POINTER) + ct = ct->ct_itemdescr; + + if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { + switch (force_lazy_struct(ct)) { + case 1: + cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); + if (cf != NULL) { + /* write the field 'cf' */ + if (value != NULL) { + return convert_field_from_object(cd->c_data, cf, value); + } + else { + PyErr_SetString(PyExc_AttributeError, + "cannot delete struct field"); + return -1; + } + } errmsg = "cdata '%s' has no field '%s'"; - break; - case -1: - return -1; - default: + break; + case -1: + return -1; + default: errmsg = "cdata '%s' points to an opaque type: cannot write fields"; - break; - } - } + break; + } + } x = PyObject_GenericSetAttr((PyObject *)cd, attr, value); if (x < 0) _cdata_attr_errmsg(errmsg, cd, attr); return x; -} - -static PyObject * -convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/ - -static cif_description_t * +} + +static PyObject * +convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/ + +static cif_description_t * fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, Py_ssize_t, ffi_abi); /*forward*/ - -static PyObject *new_primitive_type(const char *name); /*forward*/ - -static CTypeDescrObject *_get_ct_int(void) -{ - static CTypeDescrObject *ct_int = NULL; - if (ct_int == NULL) { - ct_int = (CTypeDescrObject *)new_primitive_type("int"); - } - return ct_int; -} - -static Py_ssize_t -_prepare_pointer_call_argument(CTypeDescrObject *ctptr, PyObject *init, - char **output_data) -{ - /* 'ctptr' is here a pointer type 'ITEM *'. Accept as argument an - initializer for an array 'ITEM[]'. This includes the case of - passing a Python byte string to a 'char *' argument. - - This function returns -1 if an error occurred, - 0 if conversion succeeded (into *output_data), - or N > 0 if conversion would require N bytes of storage. - */ - Py_ssize_t length, datasize; - CTypeDescrObject *ctitem; - - if (CData_Check(init)) - goto convert_default; - - ctitem = ctptr->ct_itemdescr; - /* XXX some code duplication, how to avoid it? */ - if (PyBytes_Check(init)) { - /* from a string: just returning the string here is fine. - We assume that the C code won't modify the 'char *' data. */ - if ((ctptr->ct_flags & CT_IS_VOIDCHAR_PTR) || - ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) - && (ctitem->ct_size == sizeof(char)))) { -#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) - length = PyBytes_GET_SIZE(init) + 1; -#else - *output_data = PyBytes_AS_STRING(init); + +static PyObject *new_primitive_type(const char *name); /*forward*/ + +static CTypeDescrObject *_get_ct_int(void) +{ + static CTypeDescrObject *ct_int = NULL; + if (ct_int == NULL) { + ct_int = (CTypeDescrObject *)new_primitive_type("int"); + } + return ct_int; +} + +static Py_ssize_t +_prepare_pointer_call_argument(CTypeDescrObject *ctptr, PyObject *init, + char **output_data) +{ + /* 'ctptr' is here a pointer type 'ITEM *'. Accept as argument an + initializer for an array 'ITEM[]'. This includes the case of + passing a Python byte string to a 'char *' argument. + + This function returns -1 if an error occurred, + 0 if conversion succeeded (into *output_data), + or N > 0 if conversion would require N bytes of storage. + */ + Py_ssize_t length, datasize; + CTypeDescrObject *ctitem; + + if (CData_Check(init)) + goto convert_default; + + ctitem = ctptr->ct_itemdescr; + /* XXX some code duplication, how to avoid it? */ + if (PyBytes_Check(init)) { + /* from a string: just returning the string here is fine. + We assume that the C code won't modify the 'char *' data. */ + if ((ctptr->ct_flags & CT_IS_VOIDCHAR_PTR) || + ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) + && (ctitem->ct_size == sizeof(char)))) { +#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) + length = PyBytes_GET_SIZE(init) + 1; +#else + *output_data = PyBytes_AS_STRING(init); if (ctitem->ct_flags & CT_IS_BOOL) if (must_be_array_of_zero_or_one(*output_data, PyBytes_GET_SIZE(init)) < 0) return -1; - return 0; -#endif - } - else - goto convert_default; - } - else if (PyList_Check(init) || PyTuple_Check(init)) { - length = PySequence_Fast_GET_SIZE(init); - } - else if (PyUnicode_Check(init)) { - /* from a unicode, we add the null terminator */ + return 0; +#endif + } + else + goto convert_default; + } + else if (PyList_Check(init) || PyTuple_Check(init)) { + length = PySequence_Fast_GET_SIZE(init); + } + else if (PyUnicode_Check(init)) { + /* from a unicode, we add the null terminator */ if (ctitem->ct_size == 2) length = _my_PyUnicode_SizeAsChar16(init); else length = _my_PyUnicode_SizeAsChar32(init); length += 1; - } - else if ((ctitem->ct_flags & CT_IS_FILE) && PyFile_Check(init)) { - *output_data = (char *)PyFile_AsFile(init); - if (*output_data == NULL && PyErr_Occurred()) - return -1; - return 0; - } - else { - /* refuse to receive just an integer (and interpret it - as the array size) */ - goto convert_default; - } - - if (ctitem->ct_size <= 0) - goto convert_default; - datasize = MUL_WRAPAROUND(length, ctitem->ct_size); - if ((datasize / ctitem->ct_size) != length) { - PyErr_SetString(PyExc_OverflowError, - "array size would overflow a Py_ssize_t"); - return -1; - } - if (datasize <= 0) - datasize = 1; - return datasize; - - convert_default: - return convert_from_object((char *)output_data, ctptr, init); -} - -static PyObject* -cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds) -{ - char *buffer; - void** buffer_array; - cif_description_t *cif_descr; - Py_ssize_t i, nargs, nargs_declared; - PyObject *signature, *res = NULL, *fvarargs; - CTypeDescrObject *fresult; - char *resultdata; - char *errormsg; + } + else if ((ctitem->ct_flags & CT_IS_FILE) && PyFile_Check(init)) { + *output_data = (char *)PyFile_AsFile(init); + if (*output_data == NULL && PyErr_Occurred()) + return -1; + return 0; + } + else { + /* refuse to receive just an integer (and interpret it + as the array size) */ + goto convert_default; + } + + if (ctitem->ct_size <= 0) + goto convert_default; + datasize = MUL_WRAPAROUND(length, ctitem->ct_size); + if ((datasize / ctitem->ct_size) != length) { + PyErr_SetString(PyExc_OverflowError, + "array size would overflow a Py_ssize_t"); + return -1; + } + if (datasize <= 0) + datasize = 1; + return datasize; + + convert_default: + return convert_from_object((char *)output_data, ctptr, init); +} + +static PyObject* +cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds) +{ + char *buffer; + void** buffer_array; + cif_description_t *cif_descr; + Py_ssize_t i, nargs, nargs_declared; + PyObject *signature, *res = NULL, *fvarargs; + CTypeDescrObject *fresult; + char *resultdata; + char *errormsg; struct freeme_s { struct freeme_s *next; union_alignment alignment; } *freeme = NULL; - - if (!(cd->c_type->ct_flags & CT_FUNCTIONPTR)) { - PyErr_Format(PyExc_TypeError, "cdata '%s' is not callable", - cd->c_type->ct_name); - return NULL; - } + + if (!(cd->c_type->ct_flags & CT_FUNCTIONPTR)) { + PyErr_Format(PyExc_TypeError, "cdata '%s' is not callable", + cd->c_type->ct_name); + return NULL; + } if (cd->c_data == NULL) { PyErr_Format(PyExc_RuntimeError, "cannot call null pointer pointer from cdata '%s'", cd->c_type->ct_name); return NULL; } - if (kwds != NULL && PyDict_Size(kwds) != 0) { - PyErr_SetString(PyExc_TypeError, - "a cdata function cannot be called with keyword arguments"); - return NULL; - } - signature = cd->c_type->ct_stuff; - nargs = PyTuple_Size(args); - if (nargs < 0) - return NULL; - nargs_declared = PyTuple_GET_SIZE(signature) - 2; - fresult = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 1); - fvarargs = NULL; - buffer = NULL; - - cif_descr = (cif_description_t *)cd->c_type->ct_extra; - - if (cif_descr != NULL) { - /* regular case: this function does not take '...' arguments */ - if (nargs != nargs_declared) { - errormsg = "'%s' expects %zd arguments, got %zd"; - bad_number_of_arguments: - PyErr_Format(PyExc_TypeError, errormsg, - cd->c_type->ct_name, nargs_declared, nargs); - goto error; - } - } - else { - /* call of a variadic function */ - ffi_abi fabi; - if (nargs < nargs_declared) { - errormsg = "'%s' expects at least %zd arguments, got %zd"; - goto bad_number_of_arguments; - } - fvarargs = PyTuple_New(nargs); - if (fvarargs == NULL) - goto error; - for (i = 0; i < nargs_declared; i++) { - PyObject *o = PyTuple_GET_ITEM(signature, 2 + i); - Py_INCREF(o); - PyTuple_SET_ITEM(fvarargs, i, o); - } - for (i = nargs_declared; i < nargs; i++) { - PyObject *obj = PyTuple_GET_ITEM(args, i); - CTypeDescrObject *ct; - - if (CData_Check(obj)) { - ct = ((CDataObject *)obj)->c_type; - if (ct->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_UNSIGNED | - CT_PRIMITIVE_SIGNED)) { - if (ct->ct_size < (Py_ssize_t)sizeof(int)) { - ct = _get_ct_int(); - if (ct == NULL) - goto error; - } - } - else if (ct->ct_flags & CT_ARRAY) { - ct = (CTypeDescrObject *)ct->ct_stuff; - } - Py_INCREF(ct); - } - else { - PyErr_Format(PyExc_TypeError, - "argument %zd passed in the variadic part " - "needs to be a cdata object (got %.200s)", - i + 1, Py_TYPE(obj)->tp_name); - goto error; - } - PyTuple_SET_ITEM(fvarargs, i, (PyObject *)ct); - } -#if PY_MAJOR_VERSION < 3 - fabi = PyInt_AS_LONG(PyTuple_GET_ITEM(signature, 0)); -#else - fabi = PyLong_AS_LONG(PyTuple_GET_ITEM(signature, 0)); -#endif + if (kwds != NULL && PyDict_Size(kwds) != 0) { + PyErr_SetString(PyExc_TypeError, + "a cdata function cannot be called with keyword arguments"); + return NULL; + } + signature = cd->c_type->ct_stuff; + nargs = PyTuple_Size(args); + if (nargs < 0) + return NULL; + nargs_declared = PyTuple_GET_SIZE(signature) - 2; + fresult = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 1); + fvarargs = NULL; + buffer = NULL; + + cif_descr = (cif_description_t *)cd->c_type->ct_extra; + + if (cif_descr != NULL) { + /* regular case: this function does not take '...' arguments */ + if (nargs != nargs_declared) { + errormsg = "'%s' expects %zd arguments, got %zd"; + bad_number_of_arguments: + PyErr_Format(PyExc_TypeError, errormsg, + cd->c_type->ct_name, nargs_declared, nargs); + goto error; + } + } + else { + /* call of a variadic function */ + ffi_abi fabi; + if (nargs < nargs_declared) { + errormsg = "'%s' expects at least %zd arguments, got %zd"; + goto bad_number_of_arguments; + } + fvarargs = PyTuple_New(nargs); + if (fvarargs == NULL) + goto error; + for (i = 0; i < nargs_declared; i++) { + PyObject *o = PyTuple_GET_ITEM(signature, 2 + i); + Py_INCREF(o); + PyTuple_SET_ITEM(fvarargs, i, o); + } + for (i = nargs_declared; i < nargs; i++) { + PyObject *obj = PyTuple_GET_ITEM(args, i); + CTypeDescrObject *ct; + + if (CData_Check(obj)) { + ct = ((CDataObject *)obj)->c_type; + if (ct->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_UNSIGNED | + CT_PRIMITIVE_SIGNED)) { + if (ct->ct_size < (Py_ssize_t)sizeof(int)) { + ct = _get_ct_int(); + if (ct == NULL) + goto error; + } + } + else if (ct->ct_flags & CT_ARRAY) { + ct = (CTypeDescrObject *)ct->ct_stuff; + } + Py_INCREF(ct); + } + else { + PyErr_Format(PyExc_TypeError, + "argument %zd passed in the variadic part " + "needs to be a cdata object (got %.200s)", + i + 1, Py_TYPE(obj)->tp_name); + goto error; + } + PyTuple_SET_ITEM(fvarargs, i, (PyObject *)ct); + } +#if PY_MAJOR_VERSION < 3 + fabi = PyInt_AS_LONG(PyTuple_GET_ITEM(signature, 0)); +#else + fabi = PyLong_AS_LONG(PyTuple_GET_ITEM(signature, 0)); +#endif cif_descr = fb_prepare_cif(fvarargs, fresult, nargs_declared, fabi); - if (cif_descr == NULL) - goto error; - } - - buffer = PyObject_Malloc(cif_descr->exchange_size); - if (buffer == NULL) { - PyErr_NoMemory(); - goto error; - } - - buffer_array = (void **)buffer; - - for (i=0; i<nargs; i++) { - CTypeDescrObject *argtype; - char *data = buffer + cif_descr->exchange_offset_arg[1 + i]; - PyObject *obj = PyTuple_GET_ITEM(args, i); - - buffer_array[i] = data; - - if (i < nargs_declared) - argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 2 + i); - else - argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(fvarargs, i); - - if (argtype->ct_flags & CT_POINTER) { - char *tmpbuf; - Py_ssize_t datasize = _prepare_pointer_call_argument( - argtype, obj, (char **)data); - if (datasize == 0) - ; /* successfully filled '*data' */ - else if (datasize < 0) - goto error; - else { + if (cif_descr == NULL) + goto error; + } + + buffer = PyObject_Malloc(cif_descr->exchange_size); + if (buffer == NULL) { + PyErr_NoMemory(); + goto error; + } + + buffer_array = (void **)buffer; + + for (i=0; i<nargs; i++) { + CTypeDescrObject *argtype; + char *data = buffer + cif_descr->exchange_offset_arg[1 + i]; + PyObject *obj = PyTuple_GET_ITEM(args, i); + + buffer_array[i] = data; + + if (i < nargs_declared) + argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 2 + i); + else + argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(fvarargs, i); + + if (argtype->ct_flags & CT_POINTER) { + char *tmpbuf; + Py_ssize_t datasize = _prepare_pointer_call_argument( + argtype, obj, (char **)data); + if (datasize == 0) + ; /* successfully filled '*data' */ + else if (datasize < 0) + goto error; + else { if (datasize <= 512) { tmpbuf = alloca(datasize); } @@ -3167,86 +3167,86 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds) freeme = fp; tmpbuf = (char *)&fp->alignment; } - memset(tmpbuf, 0, datasize); - *(char **)data = tmpbuf; - if (convert_array_from_object(tmpbuf, argtype, obj) < 0) - goto error; - } - } - else if (convert_from_object(data, argtype, obj) < 0) - goto error; - } - - resultdata = buffer + cif_descr->exchange_offset_arg[0]; - /*READ(cd->c_data, sizeof(void(*)(void)))*/ - - Py_BEGIN_ALLOW_THREADS - restore_errno(); - ffi_call(&cif_descr->cif, (void (*)(void))(cd->c_data), - resultdata, buffer_array); - save_errno(); - Py_END_ALLOW_THREADS - - if (fresult->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED)) { -#ifdef WORDS_BIGENDIAN - /* For results of precisely these types, libffi has a strange - rule that they will be returned as a whole 'ffi_arg' if they - are smaller. The difference only matters on big-endian. */ - if (fresult->ct_size < sizeof(ffi_arg)) - resultdata += (sizeof(ffi_arg) - fresult->ct_size); -#endif - res = convert_to_object(resultdata, fresult); - } - else if (fresult->ct_flags & CT_VOID) { - res = Py_None; - Py_INCREF(res); - } - else if (fresult->ct_flags & CT_STRUCT) { - res = convert_struct_to_owning_object(resultdata, fresult); - } - else { - res = convert_to_object(resultdata, fresult); - } - /* fall-through */ - - error: + memset(tmpbuf, 0, datasize); + *(char **)data = tmpbuf; + if (convert_array_from_object(tmpbuf, argtype, obj) < 0) + goto error; + } + } + else if (convert_from_object(data, argtype, obj) < 0) + goto error; + } + + resultdata = buffer + cif_descr->exchange_offset_arg[0]; + /*READ(cd->c_data, sizeof(void(*)(void)))*/ + + Py_BEGIN_ALLOW_THREADS + restore_errno(); + ffi_call(&cif_descr->cif, (void (*)(void))(cd->c_data), + resultdata, buffer_array); + save_errno(); + Py_END_ALLOW_THREADS + + if (fresult->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED)) { +#ifdef WORDS_BIGENDIAN + /* For results of precisely these types, libffi has a strange + rule that they will be returned as a whole 'ffi_arg' if they + are smaller. The difference only matters on big-endian. */ + if (fresult->ct_size < sizeof(ffi_arg)) + resultdata += (sizeof(ffi_arg) - fresult->ct_size); +#endif + res = convert_to_object(resultdata, fresult); + } + else if (fresult->ct_flags & CT_VOID) { + res = Py_None; + Py_INCREF(res); + } + else if (fresult->ct_flags & CT_STRUCT) { + res = convert_struct_to_owning_object(resultdata, fresult); + } + else { + res = convert_to_object(resultdata, fresult); + } + /* fall-through */ + + error: while (freeme != NULL) { void *p = (void *)freeme; freeme = freeme->next; PyObject_Free(p); } - if (buffer) - PyObject_Free(buffer); - if (fvarargs != NULL) { - Py_DECREF(fvarargs); - if (cif_descr != NULL) /* but only if fvarargs != NULL, if variadic */ - PyObject_Free(cif_descr); - } - return res; -} - -static PyObject *cdata_dir(PyObject *cd, PyObject *noarg) -{ - CTypeDescrObject *ct = ((CDataObject *)cd)->c_type; - - /* replace the type 'pointer-to-t' with just 't' */ - if (ct->ct_flags & CT_POINTER) { - ct = ct->ct_itemdescr; - } - if ((ct->ct_flags & (CT_STRUCT | CT_UNION)) && - !(ct->ct_flags & CT_IS_OPAQUE)) { - - /* for non-opaque structs or unions */ - if (force_lazy_struct(ct) < 0) - return NULL; - return PyDict_Keys(ct->ct_stuff); - } - else { - return PyList_New(0); /* empty list for the other cases */ - } -} - + if (buffer) + PyObject_Free(buffer); + if (fvarargs != NULL) { + Py_DECREF(fvarargs); + if (cif_descr != NULL) /* but only if fvarargs != NULL, if variadic */ + PyObject_Free(cif_descr); + } + return res; +} + +static PyObject *cdata_dir(PyObject *cd, PyObject *noarg) +{ + CTypeDescrObject *ct = ((CDataObject *)cd)->c_type; + + /* replace the type 'pointer-to-t' with just 't' */ + if (ct->ct_flags & CT_POINTER) { + ct = ct->ct_itemdescr; + } + if ((ct->ct_flags & (CT_STRUCT | CT_UNION)) && + !(ct->ct_flags & CT_IS_OPAQUE)) { + + /* for non-opaque structs or unions */ + if (force_lazy_struct(ct) < 0) + return NULL; + return PyDict_Keys(ct->ct_stuff); + } + else { + return PyList_New(0); /* empty list for the other cases */ + } +} + static PyObject *cdata_complex(PyObject *cd_, PyObject *noarg) { CDataObject *cd = (CDataObject *)cd_; @@ -3333,93 +3333,93 @@ static PyObject *cdata_exit(PyObject *cd, PyObject *args) return Py_None; } -static PyObject *cdata_iter(CDataObject *); - -static PyNumberMethods CData_as_number = { - (binaryfunc)cdata_add, /*nb_add*/ - (binaryfunc)cdata_sub, /*nb_subtract*/ - 0, /*nb_multiply*/ -#if PY_MAJOR_VERSION < 3 - 0, /*nb_divide*/ -#endif - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - (inquiry)cdata_nonzero, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ -#if PY_MAJOR_VERSION < 3 - 0, /*nb_coerce*/ -#endif - (unaryfunc)cdata_int, /*nb_int*/ -#if PY_MAJOR_VERSION < 3 - (unaryfunc)cdata_long, /*nb_long*/ -#else - 0, -#endif - (unaryfunc)cdata_float, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ -}; - -static PyMappingMethods CData_as_mapping = { - (lenfunc)cdata_length, /*mp_length*/ - (binaryfunc)cdata_subscript, /*mp_subscript*/ - (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ -}; - -static PyMappingMethods CDataOwn_as_mapping = { - (lenfunc)cdata_length, /*mp_length*/ - (binaryfunc)cdataowning_subscript, /*mp_subscript*/ - (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ -}; - -static PyMethodDef cdata_methods[] = { +static PyObject *cdata_iter(CDataObject *); + +static PyNumberMethods CData_as_number = { + (binaryfunc)cdata_add, /*nb_add*/ + (binaryfunc)cdata_sub, /*nb_subtract*/ + 0, /*nb_multiply*/ +#if PY_MAJOR_VERSION < 3 + 0, /*nb_divide*/ +#endif + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + 0, /*nb_negative*/ + 0, /*nb_positive*/ + 0, /*nb_absolute*/ + (inquiry)cdata_nonzero, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ +#if PY_MAJOR_VERSION < 3 + 0, /*nb_coerce*/ +#endif + (unaryfunc)cdata_int, /*nb_int*/ +#if PY_MAJOR_VERSION < 3 + (unaryfunc)cdata_long, /*nb_long*/ +#else + 0, +#endif + (unaryfunc)cdata_float, /*nb_float*/ + 0, /*nb_oct*/ + 0, /*nb_hex*/ +}; + +static PyMappingMethods CData_as_mapping = { + (lenfunc)cdata_length, /*mp_length*/ + (binaryfunc)cdata_subscript, /*mp_subscript*/ + (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ +}; + +static PyMappingMethods CDataOwn_as_mapping = { + (lenfunc)cdata_length, /*mp_length*/ + (binaryfunc)cdataowning_subscript, /*mp_subscript*/ + (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ +}; + +static PyMethodDef cdata_methods[] = { {"__dir__", cdata_dir, METH_NOARGS}, {"__complex__", cdata_complex, METH_NOARGS}, {"__enter__", cdata_enter, METH_NOARGS}, {"__exit__", cdata_exit, METH_VARARGS}, {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject CData_Type = { - PyVarObject_HEAD_INIT(NULL, 0) +}; + +static PyTypeObject CData_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend._CDataBase", - sizeof(CDataObject), - 0, - (destructor)cdata_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)cdata_repr, /* tp_repr */ - &CData_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - &CData_as_mapping, /* tp_as_mapping */ + sizeof(CDataObject), + 0, + (destructor)cdata_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)cdata_repr, /* tp_repr */ + &CData_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + &CData_as_mapping, /* tp_as_mapping */ cdata_hash, /* tp_hash */ - (ternaryfunc)cdata_call, /* tp_call */ - 0, /* tp_str */ - (getattrofunc)cdata_getattro, /* tp_getattro */ - (setattrofunc)cdata_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + (ternaryfunc)cdata_call, /* tp_call */ + 0, /* tp_str */ + (getattrofunc)cdata_getattro, /* tp_getattro */ + (setattrofunc)cdata_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ "The internal base type for CData objects. Use FFI.CData to access " "it. Always check with isinstance(): subtypes are sometimes returned " "on CPython, for performance reasons.", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - cdata_richcompare, /* tp_richcompare */ - offsetof(CDataObject, c_weakreflist), /* tp_weaklistoffset */ - (getiterfunc)cdata_iter, /* tp_iter */ - 0, /* tp_iternext */ - cdata_methods, /* tp_methods */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + cdata_richcompare, /* tp_richcompare */ + offsetof(CDataObject, c_weakreflist), /* tp_weaklistoffset */ + (getiterfunc)cdata_iter, /* tp_iter */ + 0, /* tp_iternext */ + cdata_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ @@ -3431,41 +3431,41 @@ static PyTypeObject CData_Type = { 0, /* tp_alloc */ 0, /* tp_new */ PyObject_Del, /* tp_free */ -}; - -static PyTypeObject CDataOwning_Type = { - PyVarObject_HEAD_INIT(NULL, 0) +}; + +static PyTypeObject CDataOwning_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.__CDataOwn", - sizeof(CDataObject), - 0, - (destructor)cdataowning_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)cdataowning_repr, /* tp_repr */ + sizeof(CDataObject), + 0, + (destructor)cdataowning_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)cdataowning_repr, /* tp_repr */ 0, /* inherited */ /* tp_as_number */ - 0, /* tp_as_sequence */ - &CDataOwn_as_mapping, /* tp_as_mapping */ + 0, /* tp_as_sequence */ + &CDataOwn_as_mapping, /* tp_as_mapping */ 0, /* inherited */ /* tp_hash */ 0, /* inherited */ /* tp_call */ - 0, /* tp_str */ + 0, /* tp_str */ 0, /* inherited */ /* tp_getattro */ 0, /* inherited */ /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ "This is an internal subtype of _CDataBase for performance only on " "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ + 0, /* tp_traverse */ + 0, /* tp_clear */ 0, /* inherited */ /* tp_richcompare */ 0, /* inherited */ /* tp_weaklistoffset */ 0, /* inherited */ /* tp_iter */ - 0, /* tp_iternext */ + 0, /* tp_iternext */ 0, /* inherited */ /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &CData_Type, /* tp_base */ + 0, /* tp_members */ + 0, /* tp_getset */ + &CData_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ @@ -3474,42 +3474,42 @@ static PyTypeObject CDataOwning_Type = { 0, /* tp_alloc */ 0, /* tp_new */ free, /* tp_free */ -}; - -static PyTypeObject CDataOwningGC_Type = { - PyVarObject_HEAD_INIT(NULL, 0) +}; + +static PyTypeObject CDataOwningGC_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.__CDataOwnGC", sizeof(CDataObject_own_structptr), - 0, - (destructor)cdataowninggc_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)cdataowninggc_repr, /* tp_repr */ + 0, + (destructor)cdataowninggc_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)cdataowninggc_repr, /* tp_repr */ 0, /* inherited */ /* tp_as_number */ - 0, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* inherited */ /* tp_as_mapping */ 0, /* inherited */ /* tp_hash */ 0, /* inherited */ /* tp_call */ - 0, /* tp_str */ + 0, /* tp_str */ 0, /* inherited */ /* tp_getattro */ 0, /* inherited */ /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ - | Py_TPFLAGS_HAVE_GC, + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ + | Py_TPFLAGS_HAVE_GC, "This is an internal subtype of _CDataBase for performance only on " "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ - (traverseproc)cdataowninggc_traverse, /* tp_traverse */ - (inquiry)cdataowninggc_clear, /* tp_clear */ + (traverseproc)cdataowninggc_traverse, /* tp_traverse */ + (inquiry)cdataowninggc_clear, /* tp_clear */ 0, /* inherited */ /* tp_richcompare */ 0, /* inherited */ /* tp_weaklistoffset */ 0, /* inherited */ /* tp_iter */ - 0, /* tp_iternext */ + 0, /* tp_iternext */ 0, /* inherited */ /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &CDataOwning_Type, /* tp_base */ + 0, /* tp_members */ + 0, /* tp_getset */ + &CDataOwning_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ @@ -3518,8 +3518,8 @@ static PyTypeObject CDataOwningGC_Type = { 0, /* tp_alloc */ 0, /* tp_new */ PyObject_GC_Del, /* tp_free */ -}; - +}; + static PyTypeObject CDataFromBuf_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.__CDataFromBuf", @@ -3564,484 +3564,484 @@ static PyTypeObject CDataFromBuf_Type = { PyObject_GC_Del, /* tp_free */ }; -static PyTypeObject CDataGCP_Type = { - PyVarObject_HEAD_INIT(NULL, 0) +static PyTypeObject CDataGCP_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.__CDataGCP", - sizeof(CDataObject_gcp), - 0, - (destructor)cdatagcp_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ + sizeof(CDataObject_gcp), + 0, + (destructor)cdatagcp_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ 0, /* inherited */ /* tp_repr */ 0, /* inherited */ /* tp_as_number */ - 0, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* inherited */ /* tp_as_mapping */ 0, /* inherited */ /* tp_hash */ 0, /* inherited */ /* tp_call */ - 0, /* tp_str */ + 0, /* tp_str */ 0, /* inherited */ /* tp_getattro */ 0, /* inherited */ /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ -#ifdef Py_TPFLAGS_HAVE_FINALIZE - | Py_TPFLAGS_HAVE_FINALIZE -#endif - | Py_TPFLAGS_HAVE_GC, + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ +#ifdef Py_TPFLAGS_HAVE_FINALIZE + | Py_TPFLAGS_HAVE_FINALIZE +#endif + | Py_TPFLAGS_HAVE_GC, "This is an internal subtype of _CDataBase for performance only on " "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ - (traverseproc)cdatagcp_traverse, /* tp_traverse */ - 0, /* tp_clear */ + (traverseproc)cdatagcp_traverse, /* tp_traverse */ + 0, /* tp_clear */ 0, /* inherited */ /* tp_richcompare */ 0, /* inherited */ /* tp_weaklistoffset */ 0, /* inherited */ /* tp_iter */ - 0, /* tp_iternext */ + 0, /* tp_iternext */ 0, /* inherited */ /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &CData_Type, /* tp_base */ -#ifdef Py_TPFLAGS_HAVE_FINALIZE /* CPython >= 3.4 */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ + 0, /* tp_members */ + 0, /* tp_getset */ + &CData_Type, /* tp_base */ +#ifdef Py_TPFLAGS_HAVE_FINALIZE /* CPython >= 3.4 */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ 0, /* inherited */ /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* version_tag */ - (destructor)cdatagcp_finalize, /* tp_finalize */ -#endif -}; - -/************************************************************/ - -typedef struct { - PyObject_HEAD - char *di_next, *di_stop; - CDataObject *di_object; - CTypeDescrObject *di_itemtype; -} CDataIterObject; - -static PyObject * -cdataiter_next(CDataIterObject *it) -{ - char *result = it->di_next; - if (result != it->di_stop) { - it->di_next = result + it->di_itemtype->ct_size; - return convert_to_object(result, it->di_itemtype); - } - return NULL; -} - -static void -cdataiter_dealloc(CDataIterObject *it) -{ - Py_DECREF(it->di_object); - PyObject_Del(it); -} - -static PyTypeObject CDataIter_Type = { - PyVarObject_HEAD_INIT(NULL, 0) + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* version_tag */ + (destructor)cdatagcp_finalize, /* tp_finalize */ +#endif +}; + +/************************************************************/ + +typedef struct { + PyObject_HEAD + char *di_next, *di_stop; + CDataObject *di_object; + CTypeDescrObject *di_itemtype; +} CDataIterObject; + +static PyObject * +cdataiter_next(CDataIterObject *it) +{ + char *result = it->di_next; + if (result != it->di_stop) { + it->di_next = result + it->di_itemtype->ct_size; + return convert_to_object(result, it->di_itemtype); + } + return NULL; +} + +static void +cdataiter_dealloc(CDataIterObject *it) +{ + Py_DECREF(it->di_object); + PyObject_Del(it); +} + +static PyTypeObject CDataIter_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.__CData_iterator", /* tp_name */ - sizeof(CDataIterObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)cdataiter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)cdataiter_next, /* tp_iternext */ -}; - -static PyObject * -cdata_iter(CDataObject *cd) -{ - CDataIterObject *it; - - if (!(cd->c_type->ct_flags & CT_ARRAY)) { - PyErr_Format(PyExc_TypeError, "cdata '%s' does not support iteration", - cd->c_type->ct_name); - return NULL; - } - - it = PyObject_New(CDataIterObject, &CDataIter_Type); - if (it == NULL) - return NULL; - - Py_INCREF(cd); - it->di_object = cd; - it->di_itemtype = cd->c_type->ct_itemdescr; - it->di_next = cd->c_data; - it->di_stop = cd->c_data + get_array_length(cd) * it->di_itemtype->ct_size; - return (PyObject *)it; -} - -/************************************************************/ - -static CDataObject *allocate_owning_object(Py_ssize_t size, + sizeof(CDataIterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)cdataiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)cdataiter_next, /* tp_iternext */ +}; + +static PyObject * +cdata_iter(CDataObject *cd) +{ + CDataIterObject *it; + + if (!(cd->c_type->ct_flags & CT_ARRAY)) { + PyErr_Format(PyExc_TypeError, "cdata '%s' does not support iteration", + cd->c_type->ct_name); + return NULL; + } + + it = PyObject_New(CDataIterObject, &CDataIter_Type); + if (it == NULL) + return NULL; + + Py_INCREF(cd); + it->di_object = cd; + it->di_itemtype = cd->c_type->ct_itemdescr; + it->di_next = cd->c_data; + it->di_stop = cd->c_data + get_array_length(cd) * it->di_itemtype->ct_size; + return (PyObject *)it; +} + +/************************************************************/ + +static CDataObject *allocate_owning_object(Py_ssize_t size, CTypeDescrObject *ct, int dont_clear) -{ +{ /* note: objects with &CDataOwning_Type are always allocated with either a plain malloc() or calloc(), and freed with free(). */ - CDataObject *cd; + CDataObject *cd; if (dont_clear) cd = malloc(size); else cd = calloc(size, 1); - if (PyObject_Init((PyObject *)cd, &CDataOwning_Type) == NULL) - return NULL; - - Py_INCREF(ct); - cd->c_type = ct; - cd->c_weakreflist = NULL; - return cd; -} - -static PyObject * -convert_struct_to_owning_object(char *data, CTypeDescrObject *ct) -{ - /* also accepts unions, for the API mode */ - CDataObject *cd; - Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment); - Py_ssize_t datasize = ct->ct_size; - - if (datasize < 0) { - PyErr_SetString(PyExc_TypeError, - "return type is an opaque structure or union"); - return NULL; - } - if (ct->ct_flags & CT_WITH_VAR_ARRAY) { - PyErr_SetString(PyExc_TypeError, - "return type is a struct/union with a varsize array member"); - return NULL; - } + if (PyObject_Init((PyObject *)cd, &CDataOwning_Type) == NULL) + return NULL; + + Py_INCREF(ct); + cd->c_type = ct; + cd->c_weakreflist = NULL; + return cd; +} + +static PyObject * +convert_struct_to_owning_object(char *data, CTypeDescrObject *ct) +{ + /* also accepts unions, for the API mode */ + CDataObject *cd; + Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment); + Py_ssize_t datasize = ct->ct_size; + + if (datasize < 0) { + PyErr_SetString(PyExc_TypeError, + "return type is an opaque structure or union"); + return NULL; + } + if (ct->ct_flags & CT_WITH_VAR_ARRAY) { + PyErr_SetString(PyExc_TypeError, + "return type is a struct/union with a varsize array member"); + return NULL; + } cd = allocate_owning_object(dataoffset + datasize, ct, /*dont_clear=*/1); - if (cd == NULL) - return NULL; - cd->c_data = ((char *)cd) + dataoffset; - - memcpy(cd->c_data, data, datasize); - return (PyObject *)cd; -} - -static CDataObject *allocate_gcp_object(CDataObject *origobj, - CTypeDescrObject *ct, - PyObject *destructor) -{ - CDataObject_gcp *cd = PyObject_GC_New(CDataObject_gcp, &CDataGCP_Type); - if (cd == NULL) - return NULL; - - Py_XINCREF(destructor); - Py_INCREF(origobj); - Py_INCREF(ct); - cd->head.c_data = origobj->c_data; - cd->head.c_type = ct; - cd->head.c_weakreflist = NULL; - cd->origobj = (PyObject *)origobj; - cd->destructor = destructor; - - PyObject_GC_Track(cd); - return (CDataObject *)cd; -} - -static CDataObject *allocate_with_allocator(Py_ssize_t basesize, - Py_ssize_t datasize, - CTypeDescrObject *ct, - const cffi_allocator_t *allocator) -{ - CDataObject *cd; - - if (allocator->ca_alloc == NULL) { + if (cd == NULL) + return NULL; + cd->c_data = ((char *)cd) + dataoffset; + + memcpy(cd->c_data, data, datasize); + return (PyObject *)cd; +} + +static CDataObject *allocate_gcp_object(CDataObject *origobj, + CTypeDescrObject *ct, + PyObject *destructor) +{ + CDataObject_gcp *cd = PyObject_GC_New(CDataObject_gcp, &CDataGCP_Type); + if (cd == NULL) + return NULL; + + Py_XINCREF(destructor); + Py_INCREF(origobj); + Py_INCREF(ct); + cd->head.c_data = origobj->c_data; + cd->head.c_type = ct; + cd->head.c_weakreflist = NULL; + cd->origobj = (PyObject *)origobj; + cd->destructor = destructor; + + PyObject_GC_Track(cd); + return (CDataObject *)cd; +} + +static CDataObject *allocate_with_allocator(Py_ssize_t basesize, + Py_ssize_t datasize, + CTypeDescrObject *ct, + const cffi_allocator_t *allocator) +{ + CDataObject *cd; + + if (allocator->ca_alloc == NULL) { cd = allocate_owning_object(basesize + datasize, ct, allocator->ca_dont_clear); - if (cd == NULL) - return NULL; - cd->c_data = ((char *)cd) + basesize; - } - else { - PyObject *res = PyObject_CallFunction(allocator->ca_alloc, "n", datasize); - if (res == NULL) - return NULL; - - if (!CData_Check(res)) { - PyErr_Format(PyExc_TypeError, - "alloc() must return a cdata object (got %.200s)", - Py_TYPE(res)->tp_name); - Py_DECREF(res); - return NULL; - } - cd = (CDataObject *)res; - if (!(cd->c_type->ct_flags & (CT_POINTER|CT_ARRAY))) { - PyErr_Format(PyExc_TypeError, - "alloc() must return a cdata pointer, not '%s'", - cd->c_type->ct_name); - Py_DECREF(res); - return NULL; - } - if (!cd->c_data) { - PyErr_SetString(PyExc_MemoryError, "alloc() returned NULL"); - Py_DECREF(res); - return NULL; - } - - cd = allocate_gcp_object(cd, ct, allocator->ca_free); - Py_DECREF(res); + if (cd == NULL) + return NULL; + cd->c_data = ((char *)cd) + basesize; + } + else { + PyObject *res = PyObject_CallFunction(allocator->ca_alloc, "n", datasize); + if (res == NULL) + return NULL; + + if (!CData_Check(res)) { + PyErr_Format(PyExc_TypeError, + "alloc() must return a cdata object (got %.200s)", + Py_TYPE(res)->tp_name); + Py_DECREF(res); + return NULL; + } + cd = (CDataObject *)res; + if (!(cd->c_type->ct_flags & (CT_POINTER|CT_ARRAY))) { + PyErr_Format(PyExc_TypeError, + "alloc() must return a cdata pointer, not '%s'", + cd->c_type->ct_name); + Py_DECREF(res); + return NULL; + } + if (!cd->c_data) { + PyErr_SetString(PyExc_MemoryError, "alloc() returned NULL"); + Py_DECREF(res); + return NULL; + } + + cd = allocate_gcp_object(cd, ct, allocator->ca_free); + Py_DECREF(res); if (!allocator->ca_dont_clear) memset(cd->c_data, 0, datasize); - } - return cd; -} - -static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init, - const cffi_allocator_t *allocator) -{ - CTypeDescrObject *ctitem; - CDataObject *cd; - Py_ssize_t dataoffset, datasize, explicitlength; - - explicitlength = -1; - if (ct->ct_flags & CT_POINTER) { - dataoffset = offsetof(CDataObject_own_nolength, alignment); - ctitem = ct->ct_itemdescr; - datasize = ctitem->ct_size; - if (datasize < 0) { - PyErr_Format(PyExc_TypeError, - "cannot instantiate ctype '%s' of unknown size", - ctitem->ct_name); - return NULL; - } - if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) - datasize *= 2; /* forcefully add another character: a null */ - - if (ctitem->ct_flags & (CT_STRUCT | CT_UNION)) { - if (force_lazy_struct(ctitem) < 0) /* for CT_WITH_VAR_ARRAY */ - return NULL; - - if (ctitem->ct_flags & CT_WITH_VAR_ARRAY) { - assert(ct->ct_flags & CT_IS_PTR_TO_OWNED); - dataoffset = offsetof(CDataObject_own_length, alignment); - - if (init != Py_None) { - Py_ssize_t optvarsize = datasize; - if (convert_struct_from_object(NULL, ctitem, init, - &optvarsize) < 0) - return NULL; - datasize = optvarsize; - } - } - } - } - else if (ct->ct_flags & CT_ARRAY) { - dataoffset = offsetof(CDataObject_own_nolength, alignment); - datasize = ct->ct_size; - if (datasize < 0) { + } + return cd; +} + +static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init, + const cffi_allocator_t *allocator) +{ + CTypeDescrObject *ctitem; + CDataObject *cd; + Py_ssize_t dataoffset, datasize, explicitlength; + + explicitlength = -1; + if (ct->ct_flags & CT_POINTER) { + dataoffset = offsetof(CDataObject_own_nolength, alignment); + ctitem = ct->ct_itemdescr; + datasize = ctitem->ct_size; + if (datasize < 0) { + PyErr_Format(PyExc_TypeError, + "cannot instantiate ctype '%s' of unknown size", + ctitem->ct_name); + return NULL; + } + if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) + datasize *= 2; /* forcefully add another character: a null */ + + if (ctitem->ct_flags & (CT_STRUCT | CT_UNION)) { + if (force_lazy_struct(ctitem) < 0) /* for CT_WITH_VAR_ARRAY */ + return NULL; + + if (ctitem->ct_flags & CT_WITH_VAR_ARRAY) { + assert(ct->ct_flags & CT_IS_PTR_TO_OWNED); + dataoffset = offsetof(CDataObject_own_length, alignment); + + if (init != Py_None) { + Py_ssize_t optvarsize = datasize; + if (convert_struct_from_object(NULL, ctitem, init, + &optvarsize) < 0) + return NULL; + datasize = optvarsize; + } + } + } + } + else if (ct->ct_flags & CT_ARRAY) { + dataoffset = offsetof(CDataObject_own_nolength, alignment); + datasize = ct->ct_size; + if (datasize < 0) { explicitlength = get_new_array_length(ct->ct_itemdescr, &init); - if (explicitlength < 0) - return NULL; - ctitem = ct->ct_itemdescr; - dataoffset = offsetof(CDataObject_own_length, alignment); - datasize = MUL_WRAPAROUND(explicitlength, ctitem->ct_size); - if (explicitlength > 0 && - (datasize / explicitlength) != ctitem->ct_size) { - PyErr_SetString(PyExc_OverflowError, - "array size would overflow a Py_ssize_t"); - return NULL; - } - } - } - else { - PyErr_Format(PyExc_TypeError, - "expected a pointer or array ctype, got '%s'", - ct->ct_name); - return NULL; - } - - if (ct->ct_flags & CT_IS_PTR_TO_OWNED) { - /* common case of ptr-to-struct (or ptr-to-union): for this case - we build two objects instead of one, with the memory-owning - one being really the struct (or union) and the returned one - having a strong reference to it */ - CDataObject *cds; - - cds = allocate_with_allocator(dataoffset, datasize, ct->ct_itemdescr, - allocator); - if (cds == NULL) - return NULL; - + if (explicitlength < 0) + return NULL; + ctitem = ct->ct_itemdescr; + dataoffset = offsetof(CDataObject_own_length, alignment); + datasize = MUL_WRAPAROUND(explicitlength, ctitem->ct_size); + if (explicitlength > 0 && + (datasize / explicitlength) != ctitem->ct_size) { + PyErr_SetString(PyExc_OverflowError, + "array size would overflow a Py_ssize_t"); + return NULL; + } + } + } + else { + PyErr_Format(PyExc_TypeError, + "expected a pointer or array ctype, got '%s'", + ct->ct_name); + return NULL; + } + + if (ct->ct_flags & CT_IS_PTR_TO_OWNED) { + /* common case of ptr-to-struct (or ptr-to-union): for this case + we build two objects instead of one, with the memory-owning + one being really the struct (or union) and the returned one + having a strong reference to it */ + CDataObject *cds; + + cds = allocate_with_allocator(dataoffset, datasize, ct->ct_itemdescr, + allocator); + if (cds == NULL) + return NULL; + cd = allocate_owning_object(sizeof(CDataObject_own_structptr), ct, /*dont_clear=*/1); - if (cd == NULL) { - Py_DECREF(cds); - return NULL; - } - /* store the only reference to cds into cd */ - ((CDataObject_own_structptr *)cd)->structobj = (PyObject *)cds; - /* store information about the allocated size of the struct */ - if (dataoffset == offsetof(CDataObject_own_length, alignment)) { - ((CDataObject_own_length *)cds)->length = datasize; - } - assert(explicitlength < 0); - - cd->c_data = cds->c_data; - } - else { - cd = allocate_with_allocator(dataoffset, datasize, ct, allocator); - if (cd == NULL) - return NULL; - - if (explicitlength >= 0) - ((CDataObject_own_length*)cd)->length = explicitlength; - } - - if (init != Py_None) { - if (convert_from_object(cd->c_data, - (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { - Py_DECREF(cd); - return NULL; - } - } - return (PyObject *)cd; -} - -static PyObject *b_newp(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *init = Py_None; - if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init)) - return NULL; - return direct_newp(ct, init, &default_allocator); -} - -static int -_my_PyObject_AsBool(PyObject *ob) -{ - /* convert and cast a Python object to a boolean. Accept an integer - or a float object, up to a CData 'long double'. */ - PyObject *io; - PyNumberMethods *nb; - int res; - -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(ob)) { - return PyInt_AS_LONG(ob) != 0; - } - else -#endif - if (PyLong_Check(ob)) { - return _PyLong_Sign(ob) != 0; - } - else if (PyFloat_Check(ob)) { - return PyFloat_AS_DOUBLE(ob) != 0.0; - } - else if (CData_Check(ob)) { - CDataObject *cd = (CDataObject *)ob; - if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { - /*READ(cd->c_data, cd->c_type->ct_size)*/ - if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { - /* 'long double' objects: return the answer directly */ - return read_raw_longdouble_data(cd->c_data) != 0.0; - } - else { - /* 'float'/'double' objects: return the answer directly */ - return read_raw_float_data(cd->c_data, - cd->c_type->ct_size) != 0.0; - } - } - } - nb = ob->ob_type->tp_as_number; - if (nb == NULL || (nb->nb_float == NULL && nb->nb_int == NULL)) { - PyErr_SetString(PyExc_TypeError, "integer/float expected"); - return -1; - } - if (nb->nb_float && !CData_Check(ob)) - io = (*nb->nb_float) (ob); - else - io = (*nb->nb_int) (ob); - if (io == NULL) - return -1; - - if (PyIntOrLong_Check(io) || PyFloat_Check(io)) { - res = _my_PyObject_AsBool(io); - } - else { - PyErr_SetString(PyExc_TypeError, "integer/float conversion failed"); - res = -1; - } - Py_DECREF(io); - return res; -} - -static CDataObject *_new_casted_primitive(CTypeDescrObject *ct) -{ - int dataoffset = offsetof(CDataObject_casted_primitive, alignment); - CDataObject *cd = (CDataObject *)PyObject_Malloc(dataoffset + ct->ct_size); - if (PyObject_Init((PyObject *)cd, &CData_Type) == NULL) - return NULL; - Py_INCREF(ct); - cd->c_type = ct; - cd->c_data = ((char*)cd) + dataoffset; - cd->c_weakreflist = NULL; - return cd; -} - -static CDataObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob) -{ - unsigned PY_LONG_LONG value; - CDataObject *cd; - - if (CData_Check(ob) && - ((CDataObject *)ob)->c_type->ct_flags & - (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) { - value = (Py_intptr_t)((CDataObject *)ob)->c_data; - } -#if PY_MAJOR_VERSION < 3 - else if (PyString_Check(ob)) { - if (PyString_GET_SIZE(ob) != 1) { - PyErr_Format(PyExc_TypeError, - "cannot cast string of length %zd to ctype '%s'", - PyString_GET_SIZE(ob), ct->ct_name); - return NULL; - } - value = (unsigned char)PyString_AS_STRING(ob)[0]; - } -#endif - else if (PyUnicode_Check(ob)) { + if (cd == NULL) { + Py_DECREF(cds); + return NULL; + } + /* store the only reference to cds into cd */ + ((CDataObject_own_structptr *)cd)->structobj = (PyObject *)cds; + /* store information about the allocated size of the struct */ + if (dataoffset == offsetof(CDataObject_own_length, alignment)) { + ((CDataObject_own_length *)cds)->length = datasize; + } + assert(explicitlength < 0); + + cd->c_data = cds->c_data; + } + else { + cd = allocate_with_allocator(dataoffset, datasize, ct, allocator); + if (cd == NULL) + return NULL; + + if (explicitlength >= 0) + ((CDataObject_own_length*)cd)->length = explicitlength; + } + + if (init != Py_None) { + if (convert_from_object(cd->c_data, + (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { + Py_DECREF(cd); + return NULL; + } + } + return (PyObject *)cd; +} + +static PyObject *b_newp(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + PyObject *init = Py_None; + if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init)) + return NULL; + return direct_newp(ct, init, &default_allocator); +} + +static int +_my_PyObject_AsBool(PyObject *ob) +{ + /* convert and cast a Python object to a boolean. Accept an integer + or a float object, up to a CData 'long double'. */ + PyObject *io; + PyNumberMethods *nb; + int res; + +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(ob)) { + return PyInt_AS_LONG(ob) != 0; + } + else +#endif + if (PyLong_Check(ob)) { + return _PyLong_Sign(ob) != 0; + } + else if (PyFloat_Check(ob)) { + return PyFloat_AS_DOUBLE(ob) != 0.0; + } + else if (CData_Check(ob)) { + CDataObject *cd = (CDataObject *)ob; + if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { + /*READ(cd->c_data, cd->c_type->ct_size)*/ + if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { + /* 'long double' objects: return the answer directly */ + return read_raw_longdouble_data(cd->c_data) != 0.0; + } + else { + /* 'float'/'double' objects: return the answer directly */ + return read_raw_float_data(cd->c_data, + cd->c_type->ct_size) != 0.0; + } + } + } + nb = ob->ob_type->tp_as_number; + if (nb == NULL || (nb->nb_float == NULL && nb->nb_int == NULL)) { + PyErr_SetString(PyExc_TypeError, "integer/float expected"); + return -1; + } + if (nb->nb_float && !CData_Check(ob)) + io = (*nb->nb_float) (ob); + else + io = (*nb->nb_int) (ob); + if (io == NULL) + return -1; + + if (PyIntOrLong_Check(io) || PyFloat_Check(io)) { + res = _my_PyObject_AsBool(io); + } + else { + PyErr_SetString(PyExc_TypeError, "integer/float conversion failed"); + res = -1; + } + Py_DECREF(io); + return res; +} + +static CDataObject *_new_casted_primitive(CTypeDescrObject *ct) +{ + int dataoffset = offsetof(CDataObject_casted_primitive, alignment); + CDataObject *cd = (CDataObject *)PyObject_Malloc(dataoffset + ct->ct_size); + if (PyObject_Init((PyObject *)cd, &CData_Type) == NULL) + return NULL; + Py_INCREF(ct); + cd->c_type = ct; + cd->c_data = ((char*)cd) + dataoffset; + cd->c_weakreflist = NULL; + return cd; +} + +static CDataObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob) +{ + unsigned PY_LONG_LONG value; + CDataObject *cd; + + if (CData_Check(ob) && + ((CDataObject *)ob)->c_type->ct_flags & + (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) { + value = (Py_intptr_t)((CDataObject *)ob)->c_data; + } +#if PY_MAJOR_VERSION < 3 + else if (PyString_Check(ob)) { + if (PyString_GET_SIZE(ob) != 1) { + PyErr_Format(PyExc_TypeError, + "cannot cast string of length %zd to ctype '%s'", + PyString_GET_SIZE(ob), ct->ct_name); + return NULL; + } + value = (unsigned char)PyString_AS_STRING(ob)[0]; + } +#endif + else if (PyUnicode_Check(ob)) { char err_buf[80]; cffi_char32_t ordinal; if (_my_PyUnicode_AsSingleChar32(ob, &ordinal, err_buf) < 0) { - PyErr_Format(PyExc_TypeError, + PyErr_Format(PyExc_TypeError, "cannot cast %s to ctype '%s'", err_buf, ct->ct_name); - return NULL; - } + return NULL; + } /* the types char16_t and char32_t are both unsigned. However, wchar_t might be signed. In theory it does not matter, because 'ordinal' comes from a regular Python unicode. */ @@ -4051,32 +4051,32 @@ static CDataObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob) else #endif value = ordinal; - } - else if (PyBytes_Check(ob)) { - int res = _convert_to_char(ob); - if (res < 0) - return NULL; - value = (unsigned char)res; - } - else if (ct->ct_flags & CT_IS_BOOL) { - int res = _my_PyObject_AsBool(ob); - if (res < 0) - return NULL; - value = res; - } - else { - value = _my_PyLong_AsUnsignedLongLong(ob, 0); - if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) - return NULL; - } - if (ct->ct_flags & CT_IS_BOOL) - value = !!value; - cd = _new_casted_primitive(ct); - if (cd != NULL) - write_raw_integer_data(cd->c_data, value, ct->ct_size); - return cd; -} - + } + else if (PyBytes_Check(ob)) { + int res = _convert_to_char(ob); + if (res < 0) + return NULL; + value = (unsigned char)res; + } + else if (ct->ct_flags & CT_IS_BOOL) { + int res = _my_PyObject_AsBool(ob); + if (res < 0) + return NULL; + value = res; + } + else { + value = _my_PyLong_AsUnsignedLongLong(ob, 0); + if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) + return NULL; + } + if (ct->ct_flags & CT_IS_BOOL) + value = !!value; + cd = _new_casted_primitive(ct); + if (cd != NULL) + write_raw_integer_data(cd->c_data, value, ct->ct_size); + return cd; +} + /* returns -1 if cannot cast, 0 if we don't get a value, 1 if we do */ static int check_bytes_for_float_compatible(PyObject *io, double *out_value) { @@ -4106,63 +4106,63 @@ static int check_bytes_for_float_compatible(PyObject *io, double *out_value) return -1; } -static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob) -{ - CDataObject *cd; - - if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY) && - ct->ct_size >= 0) { - /* cast to a pointer, to a funcptr, or to an array. - Note that casting to an array is an extension to the C language, - which seems to be necessary in order to sanely get a - <cdata 'int[3]'> at some address. */ - unsigned PY_LONG_LONG value; - - if (CData_Check(ob)) { - CDataObject *cdsrc = (CDataObject *)ob; - if (cdsrc->c_type->ct_flags & - (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) { - return new_simple_cdata(cdsrc->c_data, ct); - } - } - if ((ct->ct_flags & CT_POINTER) && - (ct->ct_itemdescr->ct_flags & CT_IS_FILE) && - PyFile_Check(ob)) { - FILE *f = PyFile_AsFile(ob); - if (f == NULL && PyErr_Occurred()) - return NULL; - return new_simple_cdata((char *)f, ct); - } - value = _my_PyLong_AsUnsignedLongLong(ob, 0); - if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) - return NULL; - return new_simple_cdata((char *)(Py_intptr_t)value, ct); - } - else if (ct->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED - |CT_PRIMITIVE_CHAR)) { - /* cast to an integer type or a char */ - return (PyObject *)cast_to_integer_or_char(ct, ob); - } - else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { - /* cast to a float */ - double value; - PyObject *io; +static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob) +{ + CDataObject *cd; + + if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY) && + ct->ct_size >= 0) { + /* cast to a pointer, to a funcptr, or to an array. + Note that casting to an array is an extension to the C language, + which seems to be necessary in order to sanely get a + <cdata 'int[3]'> at some address. */ + unsigned PY_LONG_LONG value; + + if (CData_Check(ob)) { + CDataObject *cdsrc = (CDataObject *)ob; + if (cdsrc->c_type->ct_flags & + (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) { + return new_simple_cdata(cdsrc->c_data, ct); + } + } + if ((ct->ct_flags & CT_POINTER) && + (ct->ct_itemdescr->ct_flags & CT_IS_FILE) && + PyFile_Check(ob)) { + FILE *f = PyFile_AsFile(ob); + if (f == NULL && PyErr_Occurred()) + return NULL; + return new_simple_cdata((char *)f, ct); + } + value = _my_PyLong_AsUnsignedLongLong(ob, 0); + if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) + return NULL; + return new_simple_cdata((char *)(Py_intptr_t)value, ct); + } + else if (ct->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED + |CT_PRIMITIVE_CHAR)) { + /* cast to an integer type or a char */ + return (PyObject *)cast_to_integer_or_char(ct, ob); + } + else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { + /* cast to a float */ + double value; + PyObject *io; int res; - - if (CData_Check(ob)) { - CDataObject *cdsrc = (CDataObject *)ob; - - if (!(cdsrc->c_type->ct_flags & CT_PRIMITIVE_ANY)) - goto cannot_cast; - io = convert_to_object(cdsrc->c_data, cdsrc->c_type); - if (io == NULL) - return NULL; - } - else { - io = ob; - Py_INCREF(io); - } - + + if (CData_Check(ob)) { + CDataObject *cdsrc = (CDataObject *)ob; + + if (!(cdsrc->c_type->ct_flags & CT_PRIMITIVE_ANY)) + goto cannot_cast; + io = convert_to_object(cdsrc->c_data, cdsrc->c_type); + if (io == NULL) + return NULL; + } + else { + io = ob; + Py_INCREF(io); + } + res = check_bytes_for_float_compatible(io, &value); if (res == -1) goto cannot_cast; @@ -4174,27 +4174,27 @@ static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob) char *data = ((CDataObject *)io)->c_data; /*READ(data, sizeof(long double)*/ lvalue = read_raw_longdouble_data(data); - Py_DECREF(io); + Py_DECREF(io); cd = _new_casted_primitive(ct); if (cd != NULL) write_raw_longdouble_data(cd->c_data, lvalue); return (PyObject *)cd; - } - value = PyFloat_AsDouble(io); - } - Py_DECREF(io); - if (value == -1.0 && PyErr_Occurred()) - return NULL; - - cd = _new_casted_primitive(ct); - if (cd != NULL) { - if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) - write_raw_float_data(cd->c_data, value, ct->ct_size); - else - write_raw_longdouble_data(cd->c_data, (long double)value); - } - return (PyObject *)cd; - } + } + value = PyFloat_AsDouble(io); + } + Py_DECREF(io); + if (value == -1.0 && PyErr_Occurred()) + return NULL; + + cd = _new_casted_primitive(ct); + if (cd != NULL) { + if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) + write_raw_float_data(cd->c_data, value, ct->ct_size); + else + write_raw_longdouble_data(cd->c_data, (long double)value); + } + return (PyObject *)cd; + } else if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { /* cast to a complex */ Py_complex value; @@ -4234,55 +4234,55 @@ static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob) } return (PyObject *)cd; } - else { - PyErr_Format(PyExc_TypeError, "cannot cast to ctype '%s'", - ct->ct_name); - return NULL; - } - - cannot_cast: - if (CData_Check(ob)) - PyErr_Format(PyExc_TypeError, "cannot cast ctype '%s' to ctype '%s'", - ((CDataObject *)ob)->c_type->ct_name, ct->ct_name); - else - PyErr_Format(PyExc_TypeError, - "cannot cast %.200s object to ctype '%s'", - Py_TYPE(ob)->tp_name, ct->ct_name); - return NULL; -} - -static PyObject *b_cast(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *ob; - if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob)) - return NULL; - - return do_cast(ct, ob); -} - -/************************************************************/ - -typedef struct { - PyObject_HEAD - void *dl_handle; - char *dl_name; + else { + PyErr_Format(PyExc_TypeError, "cannot cast to ctype '%s'", + ct->ct_name); + return NULL; + } + + cannot_cast: + if (CData_Check(ob)) + PyErr_Format(PyExc_TypeError, "cannot cast ctype '%s' to ctype '%s'", + ((CDataObject *)ob)->c_type->ct_name, ct->ct_name); + else + PyErr_Format(PyExc_TypeError, + "cannot cast %.200s object to ctype '%s'", + Py_TYPE(ob)->tp_name, ct->ct_name); + return NULL; +} + +static PyObject *b_cast(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + PyObject *ob; + if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob)) + return NULL; + + return do_cast(ct, ob); +} + +/************************************************************/ + +typedef struct { + PyObject_HEAD + void *dl_handle; + char *dl_name; int dl_auto_close; -} DynLibObject; - -static void dl_dealloc(DynLibObject *dlobj) -{ +} DynLibObject; + +static void dl_dealloc(DynLibObject *dlobj) +{ if (dlobj->dl_handle != NULL && dlobj->dl_auto_close) dlclose(dlobj->dl_handle); - free(dlobj->dl_name); - PyObject_Del(dlobj); -} - -static PyObject *dl_repr(DynLibObject *dlobj) -{ - return PyText_FromFormat("<clibrary '%s'>", dlobj->dl_name); -} - + free(dlobj->dl_name); + PyObject_Del(dlobj); +} + +static PyObject *dl_repr(DynLibObject *dlobj) +{ + return PyText_FromFormat("<clibrary '%s'>", dlobj->dl_name); +} + static int dl_check_closed(DynLibObject *dlobj) { if (dlobj->dl_handle == NULL) @@ -4294,97 +4294,97 @@ static int dl_check_closed(DynLibObject *dlobj) return 0; } -static PyObject *dl_load_function(DynLibObject *dlobj, PyObject *args) -{ - CTypeDescrObject *ct; - char *funcname; - void *funcptr; - - if (!PyArg_ParseTuple(args, "O!s:load_function", - &CTypeDescr_Type, &ct, &funcname)) - return NULL; - +static PyObject *dl_load_function(DynLibObject *dlobj, PyObject *args) +{ + CTypeDescrObject *ct; + char *funcname; + void *funcptr; + + if (!PyArg_ParseTuple(args, "O!s:load_function", + &CTypeDescr_Type, &ct, &funcname)) + return NULL; + if (dl_check_closed(dlobj) < 0) return NULL; if (!(ct->ct_flags & (CT_FUNCTIONPTR | CT_POINTER | CT_ARRAY))) { PyErr_Format(PyExc_TypeError, "function or pointer or array cdata expected, got '%s'", - ct->ct_name); - return NULL; - } - dlerror(); /* clear error condition */ - funcptr = dlsym(dlobj->dl_handle, funcname); - if (funcptr == NULL) { - const char *error = dlerror(); + ct->ct_name); + return NULL; + } + dlerror(); /* clear error condition */ + funcptr = dlsym(dlobj->dl_handle, funcname); + if (funcptr == NULL) { + const char *error = dlerror(); PyErr_Format(PyExc_AttributeError, "function/symbol '%s' not found in library '%s': %s", - funcname, dlobj->dl_name, error); - return NULL; - } - + funcname, dlobj->dl_name, error); + return NULL; + } + if ((ct->ct_flags & CT_ARRAY) && ct->ct_length < 0) { ct = (CTypeDescrObject *)ct->ct_stuff; } - return new_simple_cdata(funcptr, ct); -} - -static PyObject *dl_read_variable(DynLibObject *dlobj, PyObject *args) -{ - CTypeDescrObject *ct; - char *varname; - char *data; - - if (!PyArg_ParseTuple(args, "O!s:read_variable", - &CTypeDescr_Type, &ct, &varname)) - return NULL; - + return new_simple_cdata(funcptr, ct); +} + +static PyObject *dl_read_variable(DynLibObject *dlobj, PyObject *args) +{ + CTypeDescrObject *ct; + char *varname; + char *data; + + if (!PyArg_ParseTuple(args, "O!s:read_variable", + &CTypeDescr_Type, &ct, &varname)) + return NULL; + if (dl_check_closed(dlobj) < 0) return NULL; - dlerror(); /* clear error condition */ - data = dlsym(dlobj->dl_handle, varname); - if (data == NULL) { - const char *error = dlerror(); - if (error != NULL) { - PyErr_Format(PyExc_KeyError, - "variable '%s' not found in library '%s': %s", - varname, dlobj->dl_name, error); - return NULL; - } - } - return convert_to_object(data, ct); -} - -static PyObject *dl_write_variable(DynLibObject *dlobj, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *value; - char *varname; - char *data; - - if (!PyArg_ParseTuple(args, "O!sO:write_variable", - &CTypeDescr_Type, &ct, &varname, &value)) - return NULL; - + dlerror(); /* clear error condition */ + data = dlsym(dlobj->dl_handle, varname); + if (data == NULL) { + const char *error = dlerror(); + if (error != NULL) { + PyErr_Format(PyExc_KeyError, + "variable '%s' not found in library '%s': %s", + varname, dlobj->dl_name, error); + return NULL; + } + } + return convert_to_object(data, ct); +} + +static PyObject *dl_write_variable(DynLibObject *dlobj, PyObject *args) +{ + CTypeDescrObject *ct; + PyObject *value; + char *varname; + char *data; + + if (!PyArg_ParseTuple(args, "O!sO:write_variable", + &CTypeDescr_Type, &ct, &varname, &value)) + return NULL; + if (dl_check_closed(dlobj) < 0) return NULL; - dlerror(); /* clear error condition */ - data = dlsym(dlobj->dl_handle, varname); - if (data == NULL) { - const char *error = dlerror(); - PyErr_Format(PyExc_KeyError, - "variable '%s' not found in library '%s': %s", - varname, dlobj->dl_name, error); - return NULL; - } - if (convert_from_object(data, ct, value) < 0) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - + dlerror(); /* clear error condition */ + data = dlsym(dlobj->dl_handle, varname); + if (data == NULL) { + const char *error = dlerror(); + PyErr_Format(PyExc_KeyError, + "variable '%s' not found in library '%s': %s", + varname, dlobj->dl_name, error); + return NULL; + } + if (convert_from_object(data, ct, value) < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + static PyObject *dl_close_lib(DynLibObject *dlobj, PyObject *no_args) { if (dlobj->dl_handle != NULL) @@ -4396,68 +4396,68 @@ static PyObject *dl_close_lib(DynLibObject *dlobj, PyObject *no_args) return Py_None; } -static PyMethodDef dl_methods[] = { - {"load_function", (PyCFunction)dl_load_function, METH_VARARGS}, - {"read_variable", (PyCFunction)dl_read_variable, METH_VARARGS}, - {"write_variable", (PyCFunction)dl_write_variable, METH_VARARGS}, +static PyMethodDef dl_methods[] = { + {"load_function", (PyCFunction)dl_load_function, METH_VARARGS}, + {"read_variable", (PyCFunction)dl_read_variable, METH_VARARGS}, + {"write_variable", (PyCFunction)dl_write_variable, METH_VARARGS}, {"close_lib", (PyCFunction)dl_close_lib, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject dl_type = { - PyVarObject_HEAD_INIT(NULL, 0) + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject dl_type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CLibrary", /* tp_name */ - sizeof(DynLibObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dl_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)dl_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, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - dl_methods, /* tp_methods */ -}; - + sizeof(DynLibObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)dl_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)dl_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, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + dl_methods, /* tp_methods */ +}; + static void *b_do_dlopen(PyObject *args, const char **p_printable_filename, PyObject **p_temp, int *auto_close) -{ +{ /* Logic to call the correct version of dlopen(). Returns NULL in case of error. Otherwise, '*p_printable_filename' will point to a printable char version of the filename (maybe utf-8-encoded). '*p_temp' will be set either to NULL or to a temporary object that must be freed after looking at printable_filename. */ - void *handle; + void *handle; char *filename_or_null; - int flags = 0; + int flags = 0; *p_temp = NULL; *auto_close = 1; - if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) { - PyObject *dummy; - if (!PyArg_ParseTuple(args, "|Oi:load_library", - &dummy, &flags)) - return NULL; - filename_or_null = NULL; + if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) { + PyObject *dummy; + if (!PyArg_ParseTuple(args, "|Oi:load_library", + &dummy, &flags)) + return NULL; + filename_or_null = NULL; *p_printable_filename = "<None>"; - } + } else if (CData_Check(PyTuple_GET_ITEM(args, 0))) { CDataObject *cd; @@ -4498,7 +4498,7 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename, *p_printable_filename = PyText_AsUTF8(s); if (*p_printable_filename == NULL) return NULL; - + sz1 = PyUnicode_GetSize(filename_unicode) + 1; sz1 *= 2; /* should not be needed, but you never know */ w1 = alloca(sizeof(wchar_t) * sz1); @@ -4532,9 +4532,9 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename, return NULL; } } - if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0) - flags |= RTLD_NOW; - + if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0) + flags |= RTLD_NOW; + #ifdef MS_WIN32 if (filename_or_null == NULL) { PyErr_SetString(PyExc_OSError, "dlopen(None) not supported on Windows"); @@ -4542,21 +4542,21 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename, } #endif - handle = dlopen(filename_or_null, flags); + handle = dlopen(filename_or_null, flags); PyMem_Free(filename_or_null); #ifdef MS_WIN32 got_handle: #endif - if (handle == NULL) { - const char *error = dlerror(); + if (handle == NULL) { + const char *error = dlerror(); PyErr_Format(PyExc_OSError, "cannot load library '%s': %s", *p_printable_filename, error); - return NULL; - } + return NULL; + } return handle; } - + static PyObject *b_load_library(PyObject *self, PyObject *args) { const char *printable_filename; @@ -4569,216 +4569,216 @@ static PyObject *b_load_library(PyObject *self, PyObject *args) if (handle == NULL) goto error; - dlobj = PyObject_New(DynLibObject, &dl_type); - if (dlobj == NULL) { - dlclose(handle); + dlobj = PyObject_New(DynLibObject, &dl_type); + if (dlobj == NULL) { + dlclose(handle); goto error; - } - dlobj->dl_handle = handle; - dlobj->dl_name = strdup(printable_filename); + } + dlobj->dl_handle = handle; + dlobj->dl_name = strdup(printable_filename); dlobj->dl_auto_close = auto_close; error: Py_XDECREF(temp); - return (PyObject *)dlobj; -} - -/************************************************************/ - -static PyObject *get_unique_type(CTypeDescrObject *x, - const void *unique_key[], long keylength) -{ - /* Replace the CTypeDescrObject 'x' with a standardized one. - This either just returns x, or x is decrefed and a new reference - to the already-existing equivalent is returned. - - In this function, 'x' always contains a reference that must be - either decrefed or returned. - - Keys: - void ["void"] - primitive [&static_struct] - pointer [ctype] - array [ctype, length] - funcptr [ctresult, ellipsis+abi, num_args, ctargs...] - */ - PyObject *key, *y; - void *pkey; - - key = PyBytes_FromStringAndSize(NULL, keylength * sizeof(void *)); - if (key == NULL) - goto error; - - pkey = PyBytes_AS_STRING(key); - memcpy(pkey, unique_key, keylength * sizeof(void *)); - - y = PyDict_GetItem(unique_cache, key); - if (y != NULL) { - Py_DECREF(key); - Py_INCREF(y); - Py_DECREF(x); - return y; - } - if (PyDict_SetItem(unique_cache, key, (PyObject *)x) < 0) { - Py_DECREF(key); - goto error; - } - /* Haaaack for our reference count hack: gcmodule.c must not see this - dictionary. The problem is that any PyDict_SetItem() notices that - 'x' is tracked and re-tracks the unique_cache dictionary. So here - we re-untrack it again... */ - PyObject_GC_UnTrack(unique_cache); - - assert(x->ct_unique_key == NULL); - x->ct_unique_key = key; /* the key will be freed in ctypedescr_dealloc() */ + return (PyObject *)dlobj; +} + +/************************************************************/ + +static PyObject *get_unique_type(CTypeDescrObject *x, + const void *unique_key[], long keylength) +{ + /* Replace the CTypeDescrObject 'x' with a standardized one. + This either just returns x, or x is decrefed and a new reference + to the already-existing equivalent is returned. + + In this function, 'x' always contains a reference that must be + either decrefed or returned. + + Keys: + void ["void"] + primitive [&static_struct] + pointer [ctype] + array [ctype, length] + funcptr [ctresult, ellipsis+abi, num_args, ctargs...] + */ + PyObject *key, *y; + void *pkey; + + key = PyBytes_FromStringAndSize(NULL, keylength * sizeof(void *)); + if (key == NULL) + goto error; + + pkey = PyBytes_AS_STRING(key); + memcpy(pkey, unique_key, keylength * sizeof(void *)); + + y = PyDict_GetItem(unique_cache, key); + if (y != NULL) { + Py_DECREF(key); + Py_INCREF(y); + Py_DECREF(x); + return y; + } + if (PyDict_SetItem(unique_cache, key, (PyObject *)x) < 0) { + Py_DECREF(key); + goto error; + } + /* Haaaack for our reference count hack: gcmodule.c must not see this + dictionary. The problem is that any PyDict_SetItem() notices that + 'x' is tracked and re-tracks the unique_cache dictionary. So here + we re-untrack it again... */ + PyObject_GC_UnTrack(unique_cache); + + assert(x->ct_unique_key == NULL); + x->ct_unique_key = key; /* the key will be freed in ctypedescr_dealloc() */ /* the 'value' in unique_cache doesn't count as 1, but don't use Py_DECREF(x) here because it will confuse debug builds into thinking there was an extra DECREF in total. */ ((PyObject *)x)->ob_refcnt--; - return (PyObject *)x; - - error: - Py_DECREF(x); - return NULL; -} - + return (PyObject *)x; + + error: + Py_DECREF(x); + return NULL; +} + /* according to the C standard, these types should be equivalent to the _Complex types for the purposes of storage (not arguments in calls!) */ typedef float cffi_float_complex_t[2]; typedef double cffi_double_complex_t[2]; -static PyObject *new_primitive_type(const char *name) -{ -#define ENUM_PRIMITIVE_TYPES \ - EPTYPE(c, char, CT_PRIMITIVE_CHAR) \ - EPTYPE(s, short, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(i, int, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(l, long, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(ll, long long, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(sc, signed char, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(uc, unsigned char, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(us, unsigned short, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(ui, unsigned int, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(ul, unsigned long, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(ull, unsigned long long, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(f, float, CT_PRIMITIVE_FLOAT ) \ - EPTYPE(d, double, CT_PRIMITIVE_FLOAT ) \ - EPTYPE(ld, long double, CT_PRIMITIVE_FLOAT | CT_IS_LONGDOUBLE ) \ +static PyObject *new_primitive_type(const char *name) +{ +#define ENUM_PRIMITIVE_TYPES \ + EPTYPE(c, char, CT_PRIMITIVE_CHAR) \ + EPTYPE(s, short, CT_PRIMITIVE_SIGNED ) \ + EPTYPE(i, int, CT_PRIMITIVE_SIGNED ) \ + EPTYPE(l, long, CT_PRIMITIVE_SIGNED ) \ + EPTYPE(ll, long long, CT_PRIMITIVE_SIGNED ) \ + EPTYPE(sc, signed char, CT_PRIMITIVE_SIGNED ) \ + EPTYPE(uc, unsigned char, CT_PRIMITIVE_UNSIGNED ) \ + EPTYPE(us, unsigned short, CT_PRIMITIVE_UNSIGNED ) \ + EPTYPE(ui, unsigned int, CT_PRIMITIVE_UNSIGNED ) \ + EPTYPE(ul, unsigned long, CT_PRIMITIVE_UNSIGNED ) \ + EPTYPE(ull, unsigned long long, CT_PRIMITIVE_UNSIGNED ) \ + EPTYPE(f, float, CT_PRIMITIVE_FLOAT ) \ + EPTYPE(d, double, CT_PRIMITIVE_FLOAT ) \ + EPTYPE(ld, long double, CT_PRIMITIVE_FLOAT | CT_IS_LONGDOUBLE ) \ EPTYPE2(fc, "float _Complex", cffi_float_complex_t, CT_PRIMITIVE_COMPLEX ) \ EPTYPE2(dc, "double _Complex", cffi_double_complex_t, CT_PRIMITIVE_COMPLEX ) \ - ENUM_PRIMITIVE_TYPES_WCHAR \ + ENUM_PRIMITIVE_TYPES_WCHAR \ EPTYPE2(c16, "char16_t", cffi_char16_t, CT_PRIMITIVE_CHAR ) \ EPTYPE2(c32, "char32_t", cffi_char32_t, CT_PRIMITIVE_CHAR ) \ - EPTYPE(b, _Bool, CT_PRIMITIVE_UNSIGNED | CT_IS_BOOL ) \ - /* the following types are not primitive in the C sense */ \ - EPTYPE(i8, int8_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(u8, uint8_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(i16, int16_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(u16, uint16_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(i32, int32_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(u32, uint32_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(i64, int64_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(u64, uint64_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(il8, int_least8_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(ul8, uint_least8_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(il16, int_least16_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(ul16, uint_least16_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(il32, int_least32_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(ul32, uint_least32_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(il64, int_least64_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(ul64, uint_least64_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(if8, int_fast8_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(uf8, uint_fast8_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(if16, int_fast16_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(uf16, uint_fast16_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(if32, int_fast32_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(uf32, uint_fast32_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(if64, int_fast64_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(uf64, uint_fast64_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(ip, intptr_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(up, uintptr_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(im, intmax_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(um, uintmax_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(pd, ptrdiff_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(sz, size_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE2(ssz, "ssize_t", Py_ssize_t, CT_PRIMITIVE_SIGNED) - -#ifdef HAVE_WCHAR_H -# define ENUM_PRIMITIVE_TYPES_WCHAR \ + EPTYPE(b, _Bool, CT_PRIMITIVE_UNSIGNED | CT_IS_BOOL ) \ + /* the following types are not primitive in the C sense */ \ + EPTYPE(i8, int8_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(u8, uint8_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(i16, int16_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(u16, uint16_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(i32, int32_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(u32, uint32_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(i64, int64_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(u64, uint64_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(il8, int_least8_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(ul8, uint_least8_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(il16, int_least16_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(ul16, uint_least16_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(il32, int_least32_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(ul32, uint_least32_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(il64, int_least64_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(ul64, uint_least64_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(if8, int_fast8_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(uf8, uint_fast8_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(if16, int_fast16_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(uf16, uint_fast16_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(if32, int_fast32_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(uf32, uint_fast32_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(if64, int_fast64_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(uf64, uint_fast64_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(ip, intptr_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(up, uintptr_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(im, intmax_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(um, uintmax_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE(pd, ptrdiff_t, CT_PRIMITIVE_SIGNED) \ + EPTYPE(sz, size_t, CT_PRIMITIVE_UNSIGNED) \ + EPTYPE2(ssz, "ssize_t", Py_ssize_t, CT_PRIMITIVE_SIGNED) + +#ifdef HAVE_WCHAR_H +# define ENUM_PRIMITIVE_TYPES_WCHAR \ EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR | \ (((wchar_t)-1) > 0 ? 0 : CT_IS_SIGNED_WCHAR)) -#else -# define ENUM_PRIMITIVE_TYPES_WCHAR /* nothing */ -#endif - -#define EPTYPE(code, typename, flags) EPTYPE2(code, #typename, typename, flags) - -#define EPTYPE2(code, export_name, typename, flags) \ - struct aligncheck_##code { char x; typename y; }; - ENUM_PRIMITIVE_TYPES -#undef EPTYPE2 - - CTypeDescrObject *td; - static const struct descr_s { const char *name; int size, align, flags; } - types[] = { -#define EPTYPE2(code, export_name, typename, flags) \ - { export_name, \ - sizeof(typename), \ - offsetof(struct aligncheck_##code, y), \ - flags \ - }, - ENUM_PRIMITIVE_TYPES -#undef EPTYPE2 -#undef EPTYPE -#undef ENUM_PRIMITIVE_TYPES_WCHAR -#undef ENUM_PRIMITIVE_TYPES - { NULL } - }; - const struct descr_s *ptypes; - const void *unique_key[1]; - int name_size; - ffi_type *ffitype; - - for (ptypes=types; ; ptypes++) { - if (ptypes->name == NULL) { -#ifndef HAVE_WCHAR_H - if (strcmp(name, "wchar_t")) - PyErr_SetString(PyExc_NotImplementedError, name); - else -#endif - PyErr_SetString(PyExc_KeyError, name); - return NULL; - } - if (strcmp(name, ptypes->name) == 0) - break; - } - - if (ptypes->flags & CT_PRIMITIVE_SIGNED) { - switch (ptypes->size) { - case 1: ffitype = &ffi_type_sint8; break; - case 2: ffitype = &ffi_type_sint16; break; - case 4: ffitype = &ffi_type_sint32; break; - case 8: ffitype = &ffi_type_sint64; break; - default: goto bad_ffi_type; - } - } - else if (ptypes->flags & CT_PRIMITIVE_FLOAT) { - if (strcmp(ptypes->name, "float") == 0) - ffitype = &ffi_type_float; - else if (strcmp(ptypes->name, "double") == 0) - ffitype = &ffi_type_double; - else if (strcmp(ptypes->name, "long double") == 0) { - /* assume that if sizeof(double) == sizeof(long double), then - the two types are equivalent for C. libffi bugs on Win64 - if a function's return type is ffi_type_longdouble... */ - if (sizeof(double) == sizeof(long double)) - ffitype = &ffi_type_double; - else - ffitype = &ffi_type_longdouble; - } - else - goto bad_ffi_type; - } +#else +# define ENUM_PRIMITIVE_TYPES_WCHAR /* nothing */ +#endif + +#define EPTYPE(code, typename, flags) EPTYPE2(code, #typename, typename, flags) + +#define EPTYPE2(code, export_name, typename, flags) \ + struct aligncheck_##code { char x; typename y; }; + ENUM_PRIMITIVE_TYPES +#undef EPTYPE2 + + CTypeDescrObject *td; + static const struct descr_s { const char *name; int size, align, flags; } + types[] = { +#define EPTYPE2(code, export_name, typename, flags) \ + { export_name, \ + sizeof(typename), \ + offsetof(struct aligncheck_##code, y), \ + flags \ + }, + ENUM_PRIMITIVE_TYPES +#undef EPTYPE2 +#undef EPTYPE +#undef ENUM_PRIMITIVE_TYPES_WCHAR +#undef ENUM_PRIMITIVE_TYPES + { NULL } + }; + const struct descr_s *ptypes; + const void *unique_key[1]; + int name_size; + ffi_type *ffitype; + + for (ptypes=types; ; ptypes++) { + if (ptypes->name == NULL) { +#ifndef HAVE_WCHAR_H + if (strcmp(name, "wchar_t")) + PyErr_SetString(PyExc_NotImplementedError, name); + else +#endif + PyErr_SetString(PyExc_KeyError, name); + return NULL; + } + if (strcmp(name, ptypes->name) == 0) + break; + } + + if (ptypes->flags & CT_PRIMITIVE_SIGNED) { + switch (ptypes->size) { + case 1: ffitype = &ffi_type_sint8; break; + case 2: ffitype = &ffi_type_sint16; break; + case 4: ffitype = &ffi_type_sint32; break; + case 8: ffitype = &ffi_type_sint64; break; + default: goto bad_ffi_type; + } + } + else if (ptypes->flags & CT_PRIMITIVE_FLOAT) { + if (strcmp(ptypes->name, "float") == 0) + ffitype = &ffi_type_float; + else if (strcmp(ptypes->name, "double") == 0) + ffitype = &ffi_type_double; + else if (strcmp(ptypes->name, "long double") == 0) { + /* assume that if sizeof(double) == sizeof(long double), then + the two types are equivalent for C. libffi bugs on Win64 + if a function's return type is ffi_type_longdouble... */ + if (sizeof(double) == sizeof(long double)) + ffitype = &ffi_type_double; + else + ffitype = &ffi_type_longdouble; + } + else + goto bad_ffi_type; + } else if (ptypes->flags & CT_PRIMITIVE_COMPLEX) { /* As of March 2017, still no libffi support for complex. It fails silently if we try to use ffi_type_complex_float @@ -4786,411 +4786,411 @@ static PyObject *new_primitive_type(const char *name) */ ffitype = NULL; } - else { - switch (ptypes->size) { - case 1: ffitype = &ffi_type_uint8; break; - case 2: ffitype = &ffi_type_uint16; break; - case 4: ffitype = &ffi_type_uint32; break; - case 8: ffitype = &ffi_type_uint64; break; - default: goto bad_ffi_type; - } - } - - name_size = strlen(ptypes->name) + 1; - td = ctypedescr_new(name_size); - if (td == NULL) - return NULL; - - memcpy(td->ct_name, name, name_size); - td->ct_size = ptypes->size; - td->ct_length = ptypes->align; - td->ct_extra = ffitype; - td->ct_flags = ptypes->flags; - if (td->ct_flags & (CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_CHAR)) { - if (td->ct_size <= (Py_ssize_t)sizeof(long)) - td->ct_flags |= CT_PRIMITIVE_FITS_LONG; - } - else if (td->ct_flags & CT_PRIMITIVE_UNSIGNED) { - if (td->ct_size < (Py_ssize_t)sizeof(long)) - td->ct_flags |= CT_PRIMITIVE_FITS_LONG; - } - td->ct_name_position = strlen(td->ct_name); - unique_key[0] = ptypes; - return get_unique_type(td, unique_key, 1); - - bad_ffi_type: - PyErr_Format(PyExc_NotImplementedError, - "primitive type '%s' has size %d; " - "the supported sizes are 1, 2, 4, 8", - name, (int)ptypes->size); - return NULL; -} - -static PyObject *b_new_primitive_type(PyObject *self, PyObject *args) -{ - char *name; - if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name)) - return NULL; - return new_primitive_type(name); -} - -static PyObject *new_pointer_type(CTypeDescrObject *ctitem) -{ - CTypeDescrObject *td; - const char *extra; - const void *unique_key[1]; - - if (ctitem->ct_flags & CT_ARRAY) - extra = "(*)"; /* obscure case: see test_array_add */ - else - extra = " *"; - td = ctypedescr_new_on_top(ctitem, extra, 2); - if (td == NULL) - return NULL; - - td->ct_size = sizeof(void *); - td->ct_length = -1; - td->ct_flags = CT_POINTER; - if (ctitem->ct_flags & (CT_STRUCT|CT_UNION)) - td->ct_flags |= CT_IS_PTR_TO_OWNED; - if (ctitem->ct_flags & CT_VOID) - td->ct_flags |= CT_IS_VOID_PTR; - if ((ctitem->ct_flags & CT_VOID) || - ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) && - ctitem->ct_size == sizeof(char))) - td->ct_flags |= CT_IS_VOIDCHAR_PTR; /* 'void *' or 'char *' only */ - unique_key[0] = ctitem; - return get_unique_type(td, unique_key, 1); -} - -static PyObject *b_new_pointer_type(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ctitem; - if (!PyArg_ParseTuple(args, "O!:new_pointer_type", - &CTypeDescr_Type, &ctitem)) - return NULL; - return new_pointer_type(ctitem); -} - -static PyObject *b_new_array_type(PyObject *self, PyObject *args) -{ - PyObject *lengthobj; - Py_ssize_t length; - CTypeDescrObject *ctptr; - - if (!PyArg_ParseTuple(args, "O!O:new_array_type", - &CTypeDescr_Type, &ctptr, &lengthobj)) - return NULL; - - if (lengthobj == Py_None) { - length = -1; - } - else { - length = PyNumber_AsSsize_t(lengthobj, PyExc_OverflowError); - if (length < 0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_ValueError, "negative array length"); - return NULL; - } - } - return new_array_type(ctptr, length); -} - -static PyObject * -new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length) -{ - CTypeDescrObject *td, *ctitem; - char extra_text[32]; - Py_ssize_t arraysize; - int flags = CT_ARRAY; - const void *unique_key[2]; - - if (!(ctptr->ct_flags & CT_POINTER)) { - PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype"); - return NULL; - } - ctitem = ctptr->ct_itemdescr; - if (ctitem->ct_size < 0) { - PyErr_Format(PyExc_ValueError, "array item of unknown size: '%s'", - ctitem->ct_name); - return NULL; - } - - if (length < 0) { - sprintf(extra_text, "[]"); - length = -1; - arraysize = -1; - } - else { - sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length); - arraysize = MUL_WRAPAROUND(length, ctitem->ct_size); - if (length > 0 && (arraysize / length) != ctitem->ct_size) { - PyErr_SetString(PyExc_OverflowError, - "array size would overflow a Py_ssize_t"); - return NULL; - } - } - td = ctypedescr_new_on_top(ctitem, extra_text, 0); - if (td == NULL) - return NULL; - - Py_INCREF(ctptr); - td->ct_stuff = (PyObject *)ctptr; - td->ct_size = arraysize; - td->ct_length = length; - td->ct_flags = flags; - unique_key[0] = ctptr; - unique_key[1] = (void *)length; - return get_unique_type(td, unique_key, 2); -} - -static PyObject *new_void_type(void) -{ - int name_size = strlen("void") + 1; - const void *unique_key[1]; - CTypeDescrObject *td = ctypedescr_new(name_size); - if (td == NULL) - return NULL; - - memcpy(td->ct_name, "void", name_size); - td->ct_size = -1; - td->ct_flags = CT_VOID | CT_IS_OPAQUE; - td->ct_name_position = strlen("void"); - unique_key[0] = "void"; - return get_unique_type(td, unique_key, 1); -} - -static PyObject *b_new_void_type(PyObject *self, PyObject *args) -{ - return new_void_type(); -} - -static PyObject *new_struct_or_union_type(const char *name, int flag) -{ - int namelen = strlen(name); - CTypeDescrObject *td = ctypedescr_new(namelen + 1); - if (td == NULL) - return NULL; - - td->ct_size = -1; - td->ct_length = -1; - td->ct_flags = flag | CT_IS_OPAQUE; - td->ct_extra = NULL; - memcpy(td->ct_name, name, namelen + 1); - td->ct_name_position = namelen; - return (PyObject *)td; -} - -static PyObject *b_new_struct_type(PyObject *self, PyObject *args) -{ - char *name; - int flag; - if (!PyArg_ParseTuple(args, "s:new_struct_type", &name)) - return NULL; - - flag = CT_STRUCT; - if (strcmp(name, "struct _IO_FILE") == 0 || strcmp(name, "FILE") == 0) - flag |= CT_IS_FILE; - return new_struct_or_union_type(name, flag); -} - -static PyObject *b_new_union_type(PyObject *self, PyObject *args) -{ - char *name; - if (!PyArg_ParseTuple(args, "s:new_union_type", &name)) - return NULL; - return new_struct_or_union_type(name, CT_UNION); -} - -static CFieldObject * -_add_field(PyObject *interned_fields, PyObject *fname, CTypeDescrObject *ftype, - Py_ssize_t offset, int bitshift, int fbitsize, int flags) -{ - int err; - Py_ssize_t prev_size; - CFieldObject *cf = PyObject_New(CFieldObject, &CField_Type); - if (cf == NULL) - return NULL; - - Py_INCREF(ftype); - cf->cf_type = ftype; - cf->cf_offset = offset; - cf->cf_bitshift = bitshift; - cf->cf_bitsize = fbitsize; - cf->cf_flags = flags; - - Py_INCREF(fname); - PyText_InternInPlace(&fname); - prev_size = PyDict_Size(interned_fields); - err = PyDict_SetItem(interned_fields, fname, (PyObject *)cf); - Py_DECREF(fname); - Py_DECREF(cf); - if (err < 0) - return NULL; - - if (PyDict_Size(interned_fields) != prev_size + 1) { - PyErr_Format(PyExc_KeyError, "duplicate field name '%s'", - PyText_AS_UTF8(fname)); - return NULL; - } - return cf; /* borrowed reference */ -} - -#define SF_MSVC_BITFIELDS 0x01 -#define SF_GCC_ARM_BITFIELDS 0x02 -#define SF_GCC_X86_BITFIELDS 0x10 - -#define SF_GCC_BIG_ENDIAN 0x04 -#define SF_GCC_LITTLE_ENDIAN 0x40 - -#define SF_PACKED 0x08 -#define SF_STD_FIELD_POS 0x80 - + else { + switch (ptypes->size) { + case 1: ffitype = &ffi_type_uint8; break; + case 2: ffitype = &ffi_type_uint16; break; + case 4: ffitype = &ffi_type_uint32; break; + case 8: ffitype = &ffi_type_uint64; break; + default: goto bad_ffi_type; + } + } + + name_size = strlen(ptypes->name) + 1; + td = ctypedescr_new(name_size); + if (td == NULL) + return NULL; + + memcpy(td->ct_name, name, name_size); + td->ct_size = ptypes->size; + td->ct_length = ptypes->align; + td->ct_extra = ffitype; + td->ct_flags = ptypes->flags; + if (td->ct_flags & (CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_CHAR)) { + if (td->ct_size <= (Py_ssize_t)sizeof(long)) + td->ct_flags |= CT_PRIMITIVE_FITS_LONG; + } + else if (td->ct_flags & CT_PRIMITIVE_UNSIGNED) { + if (td->ct_size < (Py_ssize_t)sizeof(long)) + td->ct_flags |= CT_PRIMITIVE_FITS_LONG; + } + td->ct_name_position = strlen(td->ct_name); + unique_key[0] = ptypes; + return get_unique_type(td, unique_key, 1); + + bad_ffi_type: + PyErr_Format(PyExc_NotImplementedError, + "primitive type '%s' has size %d; " + "the supported sizes are 1, 2, 4, 8", + name, (int)ptypes->size); + return NULL; +} + +static PyObject *b_new_primitive_type(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name)) + return NULL; + return new_primitive_type(name); +} + +static PyObject *new_pointer_type(CTypeDescrObject *ctitem) +{ + CTypeDescrObject *td; + const char *extra; + const void *unique_key[1]; + + if (ctitem->ct_flags & CT_ARRAY) + extra = "(*)"; /* obscure case: see test_array_add */ + else + extra = " *"; + td = ctypedescr_new_on_top(ctitem, extra, 2); + if (td == NULL) + return NULL; + + td->ct_size = sizeof(void *); + td->ct_length = -1; + td->ct_flags = CT_POINTER; + if (ctitem->ct_flags & (CT_STRUCT|CT_UNION)) + td->ct_flags |= CT_IS_PTR_TO_OWNED; + if (ctitem->ct_flags & CT_VOID) + td->ct_flags |= CT_IS_VOID_PTR; + if ((ctitem->ct_flags & CT_VOID) || + ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) && + ctitem->ct_size == sizeof(char))) + td->ct_flags |= CT_IS_VOIDCHAR_PTR; /* 'void *' or 'char *' only */ + unique_key[0] = ctitem; + return get_unique_type(td, unique_key, 1); +} + +static PyObject *b_new_pointer_type(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ctitem; + if (!PyArg_ParseTuple(args, "O!:new_pointer_type", + &CTypeDescr_Type, &ctitem)) + return NULL; + return new_pointer_type(ctitem); +} + +static PyObject *b_new_array_type(PyObject *self, PyObject *args) +{ + PyObject *lengthobj; + Py_ssize_t length; + CTypeDescrObject *ctptr; + + if (!PyArg_ParseTuple(args, "O!O:new_array_type", + &CTypeDescr_Type, &ctptr, &lengthobj)) + return NULL; + + if (lengthobj == Py_None) { + length = -1; + } + else { + length = PyNumber_AsSsize_t(lengthobj, PyExc_OverflowError); + if (length < 0) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, "negative array length"); + return NULL; + } + } + return new_array_type(ctptr, length); +} + +static PyObject * +new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length) +{ + CTypeDescrObject *td, *ctitem; + char extra_text[32]; + Py_ssize_t arraysize; + int flags = CT_ARRAY; + const void *unique_key[2]; + + if (!(ctptr->ct_flags & CT_POINTER)) { + PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype"); + return NULL; + } + ctitem = ctptr->ct_itemdescr; + if (ctitem->ct_size < 0) { + PyErr_Format(PyExc_ValueError, "array item of unknown size: '%s'", + ctitem->ct_name); + return NULL; + } + + if (length < 0) { + sprintf(extra_text, "[]"); + length = -1; + arraysize = -1; + } + else { + sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length); + arraysize = MUL_WRAPAROUND(length, ctitem->ct_size); + if (length > 0 && (arraysize / length) != ctitem->ct_size) { + PyErr_SetString(PyExc_OverflowError, + "array size would overflow a Py_ssize_t"); + return NULL; + } + } + td = ctypedescr_new_on_top(ctitem, extra_text, 0); + if (td == NULL) + return NULL; + + Py_INCREF(ctptr); + td->ct_stuff = (PyObject *)ctptr; + td->ct_size = arraysize; + td->ct_length = length; + td->ct_flags = flags; + unique_key[0] = ctptr; + unique_key[1] = (void *)length; + return get_unique_type(td, unique_key, 2); +} + +static PyObject *new_void_type(void) +{ + int name_size = strlen("void") + 1; + const void *unique_key[1]; + CTypeDescrObject *td = ctypedescr_new(name_size); + if (td == NULL) + return NULL; + + memcpy(td->ct_name, "void", name_size); + td->ct_size = -1; + td->ct_flags = CT_VOID | CT_IS_OPAQUE; + td->ct_name_position = strlen("void"); + unique_key[0] = "void"; + return get_unique_type(td, unique_key, 1); +} + +static PyObject *b_new_void_type(PyObject *self, PyObject *args) +{ + return new_void_type(); +} + +static PyObject *new_struct_or_union_type(const char *name, int flag) +{ + int namelen = strlen(name); + CTypeDescrObject *td = ctypedescr_new(namelen + 1); + if (td == NULL) + return NULL; + + td->ct_size = -1; + td->ct_length = -1; + td->ct_flags = flag | CT_IS_OPAQUE; + td->ct_extra = NULL; + memcpy(td->ct_name, name, namelen + 1); + td->ct_name_position = namelen; + return (PyObject *)td; +} + +static PyObject *b_new_struct_type(PyObject *self, PyObject *args) +{ + char *name; + int flag; + if (!PyArg_ParseTuple(args, "s:new_struct_type", &name)) + return NULL; + + flag = CT_STRUCT; + if (strcmp(name, "struct _IO_FILE") == 0 || strcmp(name, "FILE") == 0) + flag |= CT_IS_FILE; + return new_struct_or_union_type(name, flag); +} + +static PyObject *b_new_union_type(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s:new_union_type", &name)) + return NULL; + return new_struct_or_union_type(name, CT_UNION); +} + +static CFieldObject * +_add_field(PyObject *interned_fields, PyObject *fname, CTypeDescrObject *ftype, + Py_ssize_t offset, int bitshift, int fbitsize, int flags) +{ + int err; + Py_ssize_t prev_size; + CFieldObject *cf = PyObject_New(CFieldObject, &CField_Type); + if (cf == NULL) + return NULL; + + Py_INCREF(ftype); + cf->cf_type = ftype; + cf->cf_offset = offset; + cf->cf_bitshift = bitshift; + cf->cf_bitsize = fbitsize; + cf->cf_flags = flags; + + Py_INCREF(fname); + PyText_InternInPlace(&fname); + prev_size = PyDict_Size(interned_fields); + err = PyDict_SetItem(interned_fields, fname, (PyObject *)cf); + Py_DECREF(fname); + Py_DECREF(cf); + if (err < 0) + return NULL; + + if (PyDict_Size(interned_fields) != prev_size + 1) { + PyErr_Format(PyExc_KeyError, "duplicate field name '%s'", + PyText_AS_UTF8(fname)); + return NULL; + } + return cf; /* borrowed reference */ +} + +#define SF_MSVC_BITFIELDS 0x01 +#define SF_GCC_ARM_BITFIELDS 0x02 +#define SF_GCC_X86_BITFIELDS 0x10 + +#define SF_GCC_BIG_ENDIAN 0x04 +#define SF_GCC_LITTLE_ENDIAN 0x40 + +#define SF_PACKED 0x08 +#define SF_STD_FIELD_POS 0x80 + #ifdef MS_WIN32 # define SF_DEFAULT_PACKING 8 #else # define SF_DEFAULT_PACKING 0x40000000 /* a huge power of two */ #endif -static int complete_sflags(int sflags) -{ - /* add one of the SF_xxx_BITFIELDS flags if none is specified */ - if (!(sflags & (SF_MSVC_BITFIELDS | SF_GCC_ARM_BITFIELDS | - SF_GCC_X86_BITFIELDS))) { -#ifdef MS_WIN32 - sflags |= SF_MSVC_BITFIELDS; -#else +static int complete_sflags(int sflags) +{ + /* add one of the SF_xxx_BITFIELDS flags if none is specified */ + if (!(sflags & (SF_MSVC_BITFIELDS | SF_GCC_ARM_BITFIELDS | + SF_GCC_X86_BITFIELDS))) { +#ifdef MS_WIN32 + sflags |= SF_MSVC_BITFIELDS; +#else # if defined(__APPLE__) && defined(__arm64__) sflags |= SF_GCC_X86_BITFIELDS; # elif defined(__arm__) || defined(__aarch64__) - sflags |= SF_GCC_ARM_BITFIELDS; -# else - sflags |= SF_GCC_X86_BITFIELDS; -# endif -#endif - } - /* add one of SF_GCC_xx_ENDIAN if none is specified */ - if (!(sflags & (SF_GCC_BIG_ENDIAN | SF_GCC_LITTLE_ENDIAN))) { - int _check_endian = 1; - if (*(char *)&_check_endian == 0) - sflags |= SF_GCC_BIG_ENDIAN; - else - sflags |= SF_GCC_LITTLE_ENDIAN; - } - return sflags; -} - -static int detect_custom_layout(CTypeDescrObject *ct, int sflags, - Py_ssize_t cdef_value, - Py_ssize_t compiler_value, - const char *msg1, const char *txt, - const char *msg2) -{ - if (compiler_value != cdef_value) { - if (sflags & SF_STD_FIELD_POS) { - PyErr_Format(FFIError, - "%s: %s%s%s (cdef says %zd, but C compiler says %zd)." + sflags |= SF_GCC_ARM_BITFIELDS; +# else + sflags |= SF_GCC_X86_BITFIELDS; +# endif +#endif + } + /* add one of SF_GCC_xx_ENDIAN if none is specified */ + if (!(sflags & (SF_GCC_BIG_ENDIAN | SF_GCC_LITTLE_ENDIAN))) { + int _check_endian = 1; + if (*(char *)&_check_endian == 0) + sflags |= SF_GCC_BIG_ENDIAN; + else + sflags |= SF_GCC_LITTLE_ENDIAN; + } + return sflags; +} + +static int detect_custom_layout(CTypeDescrObject *ct, int sflags, + Py_ssize_t cdef_value, + Py_ssize_t compiler_value, + const char *msg1, const char *txt, + const char *msg2) +{ + if (compiler_value != cdef_value) { + if (sflags & SF_STD_FIELD_POS) { + PyErr_Format(FFIError, + "%s: %s%s%s (cdef says %zd, but C compiler says %zd)." " fix it or use \"...;\" as the last field in the " "cdef for %s to make it flexible", - ct->ct_name, msg1, txt, msg2, - cdef_value, compiler_value, - ct->ct_name); - return -1; - } - ct->ct_flags |= CT_CUSTOM_FIELD_POS; - } - return 0; -} - + ct->ct_name, msg1, txt, msg2, + cdef_value, compiler_value, + ct->ct_name); + return -1; + } + ct->ct_flags |= CT_CUSTOM_FIELD_POS; + } + return 0; +} + #define ROUNDUP_BYTES(bytes, bits) ((bytes) + ((bits) > 0)) -static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *fields, *interned_fields, *ignored; - int is_union, alignment; +static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + PyObject *fields, *interned_fields, *ignored; + int is_union, alignment; Py_ssize_t byteoffset, i, nb_fields, byteoffsetmax, alignedsize; int bitoffset; Py_ssize_t byteoffsetorg; - Py_ssize_t totalsize = -1; - int totalalignment = -1; - CFieldObject **previous; - int prev_bitfield_size, prev_bitfield_free; - int sflags = 0, fflags; + Py_ssize_t totalsize = -1; + int totalalignment = -1; + CFieldObject **previous; + int prev_bitfield_size, prev_bitfield_free; + int sflags = 0, fflags; int pack = 0; - + if (!PyArg_ParseTuple(args, "O!O!|Oniii:complete_struct_or_union", - &CTypeDescr_Type, &ct, - &PyList_Type, &fields, + &CTypeDescr_Type, &ct, + &PyList_Type, &fields, &ignored, &totalsize, &totalalignment, &sflags, &pack)) - return NULL; - - sflags = complete_sflags(sflags); + return NULL; + + sflags = complete_sflags(sflags); if (sflags & SF_PACKED) pack = 1; else if (pack <= 0) pack = SF_DEFAULT_PACKING; else sflags |= SF_PACKED; - - if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) == - (CT_STRUCT|CT_IS_OPAQUE)) { - is_union = 0; - } - else if ((ct->ct_flags & (CT_UNION|CT_IS_OPAQUE)) == - (CT_UNION|CT_IS_OPAQUE)) { - is_union = 1; - } - else { - PyErr_SetString(PyExc_TypeError, - "first arg must be a non-initialized struct or union ctype"); - return NULL; - } + + if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) == + (CT_STRUCT|CT_IS_OPAQUE)) { + is_union = 0; + } + else if ((ct->ct_flags & (CT_UNION|CT_IS_OPAQUE)) == + (CT_UNION|CT_IS_OPAQUE)) { + is_union = 1; + } + else { + PyErr_SetString(PyExc_TypeError, + "first arg must be a non-initialized struct or union ctype"); + return NULL; + } ct->ct_flags &= ~(CT_CUSTOM_FIELD_POS | CT_WITH_PACKED_CHANGE); - - alignment = 1; + + alignment = 1; byteoffset = 0; /* the real value is 'byteoffset+bitoffset*8', which */ bitoffset = 0; /* counts the offset in bits */ byteoffsetmax = 0; /* the maximum value of byteoffset-rounded-up-to-byte */ - prev_bitfield_size = 0; - prev_bitfield_free = 0; - nb_fields = PyList_GET_SIZE(fields); - interned_fields = PyDict_New(); - if (interned_fields == NULL) - return NULL; - - previous = (CFieldObject **)&ct->ct_extra; - - for (i=0; i<nb_fields; i++) { - PyObject *fname; - CTypeDescrObject *ftype; + prev_bitfield_size = 0; + prev_bitfield_free = 0; + nb_fields = PyList_GET_SIZE(fields); + interned_fields = PyDict_New(); + if (interned_fields == NULL) + return NULL; + + previous = (CFieldObject **)&ct->ct_extra; + + for (i=0; i<nb_fields; i++) { + PyObject *fname; + CTypeDescrObject *ftype; int fbitsize = -1, falign, falignorg, do_align; - Py_ssize_t foffset = -1; - - if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|in:list item", - &PyText_Type, &fname, - &CTypeDescr_Type, &ftype, - &fbitsize, &foffset)) - goto error; - - if (ftype->ct_size < 0) { - if ((ftype->ct_flags & CT_ARRAY) && fbitsize < 0 - && (i == nb_fields - 1 || foffset != -1)) { - ct->ct_flags |= CT_WITH_VAR_ARRAY; - } - else { - PyErr_Format(PyExc_TypeError, - "field '%s.%s' has ctype '%s' of unknown size", - ct->ct_name, PyText_AS_UTF8(fname), - ftype->ct_name); - goto error; - } - } + Py_ssize_t foffset = -1; + + if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|in:list item", + &PyText_Type, &fname, + &CTypeDescr_Type, &ftype, + &fbitsize, &foffset)) + goto error; + + if (ftype->ct_size < 0) { + if ((ftype->ct_flags & CT_ARRAY) && fbitsize < 0 + && (i == nb_fields - 1 || foffset != -1)) { + ct->ct_flags |= CT_WITH_VAR_ARRAY; + } + else { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' has ctype '%s' of unknown size", + ct->ct_name, PyText_AS_UTF8(fname), + ftype->ct_name); + goto error; + } + } else if (ftype->ct_flags & (CT_STRUCT|CT_UNION)) { if (force_lazy_struct(ftype) < 0) /* for CT_WITH_VAR_ARRAY */ return NULL; - + /* GCC (or maybe C99) accepts var-sized struct fields that are not the last field of a larger struct. That's why there is no check here for "last field": we propagate the flag @@ -5201,43 +5201,43 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args) ct->ct_flags |= CT_WITH_VAR_ARRAY; } - if (is_union) + if (is_union) byteoffset = bitoffset = 0; /* reset each field at offset 0 */ - - /* update the total alignment requirement, but skip it if the - field is an anonymous bitfield or if SF_PACKED */ + + /* update the total alignment requirement, but skip it if the + field is an anonymous bitfield or if SF_PACKED */ falignorg = get_alignment(ftype); if (falignorg < 0) - goto error; + goto error; falign = (pack < falignorg) ? pack : falignorg; - - do_align = 1; - if (!(sflags & SF_GCC_ARM_BITFIELDS) && fbitsize >= 0) { - if (!(sflags & SF_MSVC_BITFIELDS)) { - /* GCC: anonymous bitfields (of any size) don't cause alignment */ - do_align = PyText_GetSize(fname) > 0; - } - else { - /* MSVC: zero-sized bitfields don't cause alignment */ - do_align = fbitsize > 0; - } - } - if (alignment < falign && do_align) - alignment = falign; - - fflags = (is_union && i > 0) ? BF_IGNORE_IN_CTOR : 0; - - if (fbitsize < 0) { - /* not a bitfield: common case */ - int bs_flag; - - if ((ftype->ct_flags & CT_ARRAY) && ftype->ct_length <= 0) - bs_flag = BS_EMPTY_ARRAY; - else - bs_flag = BS_REGULAR; - - /* align this field to its own 'falign' by inserting padding */ - + + do_align = 1; + if (!(sflags & SF_GCC_ARM_BITFIELDS) && fbitsize >= 0) { + if (!(sflags & SF_MSVC_BITFIELDS)) { + /* GCC: anonymous bitfields (of any size) don't cause alignment */ + do_align = PyText_GetSize(fname) > 0; + } + else { + /* MSVC: zero-sized bitfields don't cause alignment */ + do_align = fbitsize > 0; + } + } + if (alignment < falign && do_align) + alignment = falign; + + fflags = (is_union && i > 0) ? BF_IGNORE_IN_CTOR : 0; + + if (fbitsize < 0) { + /* not a bitfield: common case */ + int bs_flag; + + if ((ftype->ct_flags & CT_ARRAY) && ftype->ct_length <= 0) + bs_flag = BS_EMPTY_ARRAY; + else + bs_flag = BS_REGULAR; + + /* align this field to its own 'falign' by inserting padding */ + /* first, pad to the next byte, * then pad to 'falign' or 'falignorg' bytes */ byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset); @@ -5249,260 +5249,260 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args) ct->ct_flags |= CT_WITH_PACKED_CHANGE; } - if (foffset >= 0) { - /* a forced field position: ignore the offset just computed, - except to know if we must set CT_CUSTOM_FIELD_POS */ + if (foffset >= 0) { + /* a forced field position: ignore the offset just computed, + except to know if we must set CT_CUSTOM_FIELD_POS */ if (detect_custom_layout(ct, sflags, byteoffset, foffset, - "wrong offset for field '", - PyText_AS_UTF8(fname), "'") < 0) - goto error; + "wrong offset for field '", + PyText_AS_UTF8(fname), "'") < 0) + goto error; byteoffset = foffset; - } - - if (PyText_GetSize(fname) == 0 && - ftype->ct_flags & (CT_STRUCT|CT_UNION)) { - /* a nested anonymous struct or union */ - CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra; - for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) { - /* broken complexity in the call to get_field_name(), - but we'll assume you never do that with nested - anonymous structures with thousand of fields */ - *previous = _add_field(interned_fields, - get_field_name(ftype, cfsrc), - cfsrc->cf_type, + } + + if (PyText_GetSize(fname) == 0 && + ftype->ct_flags & (CT_STRUCT|CT_UNION)) { + /* a nested anonymous struct or union */ + CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra; + for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) { + /* broken complexity in the call to get_field_name(), + but we'll assume you never do that with nested + anonymous structures with thousand of fields */ + *previous = _add_field(interned_fields, + get_field_name(ftype, cfsrc), + cfsrc->cf_type, byteoffset + cfsrc->cf_offset, - cfsrc->cf_bitshift, - cfsrc->cf_bitsize, - cfsrc->cf_flags | fflags); - if (*previous == NULL) - goto error; - previous = &(*previous)->cf_next; - } - /* always forbid such structures from being passed by value */ - ct->ct_flags |= CT_CUSTOM_FIELD_POS; - } - else { - *previous = _add_field(interned_fields, fname, ftype, + cfsrc->cf_bitshift, + cfsrc->cf_bitsize, + cfsrc->cf_flags | fflags); + if (*previous == NULL) + goto error; + previous = &(*previous)->cf_next; + } + /* always forbid such structures from being passed by value */ + ct->ct_flags |= CT_CUSTOM_FIELD_POS; + } + else { + *previous = _add_field(interned_fields, fname, ftype, byteoffset, bs_flag, -1, fflags); - if (*previous == NULL) - goto error; - previous = &(*previous)->cf_next; - } - if (ftype->ct_size >= 0) + if (*previous == NULL) + goto error; + previous = &(*previous)->cf_next; + } + if (ftype->ct_size >= 0) byteoffset += ftype->ct_size; - prev_bitfield_size = 0; - } - else { - /* this is the case of a bitfield */ - Py_ssize_t field_offset_bytes; - int bits_already_occupied, bitshift; - - if (foffset >= 0) { - PyErr_Format(PyExc_TypeError, - "field '%s.%s' is a bitfield, " - "but a fixed offset is specified", - ct->ct_name, PyText_AS_UTF8(fname)); - goto error; - } - - if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED | - CT_PRIMITIVE_CHAR))) { - PyErr_Format(PyExc_TypeError, - "field '%s.%s' declared as '%s' cannot be a bit field", - ct->ct_name, PyText_AS_UTF8(fname), - ftype->ct_name); - goto error; - } - if (fbitsize > 8 * ftype->ct_size) { - PyErr_Format(PyExc_TypeError, - "bit field '%s.%s' is declared '%s:%d', which " - "exceeds the width of the type", - ct->ct_name, PyText_AS_UTF8(fname), - ftype->ct_name, fbitsize); - goto error; - } - - /* compute the starting position of the theoretical field - that covers a complete 'ftype', inside of which we will - locate the real bitfield */ + prev_bitfield_size = 0; + } + else { + /* this is the case of a bitfield */ + Py_ssize_t field_offset_bytes; + int bits_already_occupied, bitshift; + + if (foffset >= 0) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' is a bitfield, " + "but a fixed offset is specified", + ct->ct_name, PyText_AS_UTF8(fname)); + goto error; + } + + if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED | + CT_PRIMITIVE_CHAR))) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' declared as '%s' cannot be a bit field", + ct->ct_name, PyText_AS_UTF8(fname), + ftype->ct_name); + goto error; + } + if (fbitsize > 8 * ftype->ct_size) { + PyErr_Format(PyExc_TypeError, + "bit field '%s.%s' is declared '%s:%d', which " + "exceeds the width of the type", + ct->ct_name, PyText_AS_UTF8(fname), + ftype->ct_name, fbitsize); + goto error; + } + + /* compute the starting position of the theoretical field + that covers a complete 'ftype', inside of which we will + locate the real bitfield */ field_offset_bytes = byteoffset; - field_offset_bytes &= ~(falign - 1); - - if (fbitsize == 0) { - if (PyText_GetSize(fname) > 0) { - PyErr_Format(PyExc_TypeError, - "field '%s.%s' is declared with :0", - ct->ct_name, PyText_AS_UTF8(fname)); - goto error; - } - if (!(sflags & SF_MSVC_BITFIELDS)) { - /* GCC's notion of "ftype :0;" */ - + field_offset_bytes &= ~(falign - 1); + + if (fbitsize == 0) { + if (PyText_GetSize(fname) > 0) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' is declared with :0", + ct->ct_name, PyText_AS_UTF8(fname)); + goto error; + } + if (!(sflags & SF_MSVC_BITFIELDS)) { + /* GCC's notion of "ftype :0;" */ + /* pad byteoffset to a value aligned for "ftype" */ if (ROUNDUP_BYTES(byteoffset, bitoffset) > field_offset_bytes) { - field_offset_bytes += falign; + field_offset_bytes += falign; assert(byteoffset < field_offset_bytes); - } + } byteoffset = field_offset_bytes; bitoffset = 0; - } - else { - /* MSVC's notion of "ftype :0;" */ - - /* Mostly ignored. It seems they only serve as - separator between other bitfields, to force them - into separate words. */ - } - prev_bitfield_size = 0; - } - else { - if (!(sflags & SF_MSVC_BITFIELDS)) { - /* GCC's algorithm */ - - /* Can the field start at the offset given by 'boffset'? It - can if it would entirely fit into an aligned ftype field. */ + } + else { + /* MSVC's notion of "ftype :0;" */ + + /* Mostly ignored. It seems they only serve as + separator between other bitfields, to force them + into separate words. */ + } + prev_bitfield_size = 0; + } + else { + if (!(sflags & SF_MSVC_BITFIELDS)) { + /* GCC's algorithm */ + + /* Can the field start at the offset given by 'boffset'? It + can if it would entirely fit into an aligned ftype field. */ bits_already_occupied = (byteoffset-field_offset_bytes) * 8 + bitoffset; - - if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) { - /* it would not fit, we need to start at the next - allowed position */ - if ((sflags & SF_PACKED) && - (bits_already_occupied & 7)) { - PyErr_Format(PyExc_NotImplementedError, - "with 'packed', gcc would compile field " - "'%s.%s' to reuse some bits in the previous " - "field", ct->ct_name, PyText_AS_UTF8(fname)); - goto error; - } - field_offset_bytes += falign; + + if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) { + /* it would not fit, we need to start at the next + allowed position */ + if ((sflags & SF_PACKED) && + (bits_already_occupied & 7)) { + PyErr_Format(PyExc_NotImplementedError, + "with 'packed', gcc would compile field " + "'%s.%s' to reuse some bits in the previous " + "field", ct->ct_name, PyText_AS_UTF8(fname)); + goto error; + } + field_offset_bytes += falign; assert(byteoffset < field_offset_bytes); byteoffset = field_offset_bytes; bitoffset = 0; - bitshift = 0; - } - else { - bitshift = bits_already_occupied; - assert(bitshift >= 0); - } + bitshift = 0; + } + else { + bitshift = bits_already_occupied; + assert(bitshift >= 0); + } bitoffset += fbitsize; byteoffset += (bitoffset >> 3); bitoffset &= 7; - } - else { - /* MSVC's algorithm */ - - /* A bitfield is considered as taking the full width - of their declared type. It can share some bits - with the previous field only if it was also a - bitfield and used a type of the same size. */ - if (prev_bitfield_size == ftype->ct_size && - prev_bitfield_free >= fbitsize) { - /* yes: reuse */ - bitshift = 8 * prev_bitfield_size - prev_bitfield_free; - } - else { - /* no: start a new full field */ + } + else { + /* MSVC's algorithm */ + + /* A bitfield is considered as taking the full width + of their declared type. It can share some bits + with the previous field only if it was also a + bitfield and used a type of the same size. */ + if (prev_bitfield_size == ftype->ct_size && + prev_bitfield_free >= fbitsize) { + /* yes: reuse */ + bitshift = 8 * prev_bitfield_size - prev_bitfield_free; + } + else { + /* no: start a new full field */ byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset); bitoffset = 0; /* align */ byteoffset = (byteoffset + falign-1) & ~(falign-1); byteoffset += ftype->ct_size; - bitshift = 0; - prev_bitfield_size = ftype->ct_size; - prev_bitfield_free = 8 * prev_bitfield_size; - } - prev_bitfield_free -= fbitsize; + bitshift = 0; + prev_bitfield_size = ftype->ct_size; + prev_bitfield_free = 8 * prev_bitfield_size; + } + prev_bitfield_free -= fbitsize; field_offset_bytes = byteoffset - ftype->ct_size; - } - if (sflags & SF_GCC_BIG_ENDIAN) - bitshift = 8 * ftype->ct_size - fbitsize - bitshift; - + } + if (sflags & SF_GCC_BIG_ENDIAN) + bitshift = 8 * ftype->ct_size - fbitsize - bitshift; + if (PyText_GetSize(fname) > 0) { *previous = _add_field(interned_fields, fname, ftype, - field_offset_bytes, bitshift, fbitsize, - fflags); + field_offset_bytes, bitshift, fbitsize, + fflags); if (*previous == NULL) goto error; previous = &(*previous)->cf_next; } - } - } - + } + } + assert(bitoffset == (bitoffset & 7)); if (ROUNDUP_BYTES(byteoffset, bitoffset) > byteoffsetmax) byteoffsetmax = ROUNDUP_BYTES(byteoffset, bitoffset); - } - *previous = NULL; - - /* Like C, if the size of this structure would be zero, we compute it - as 1 instead. But for ctypes support, we allow the manually- - specified totalsize to be zero in this case. */ + } + *previous = NULL; + + /* Like C, if the size of this structure would be zero, we compute it + as 1 instead. But for ctypes support, we allow the manually- + specified totalsize to be zero in this case. */ alignedsize = (byteoffsetmax + alignment - 1) & ~(alignment-1); - if (alignedsize == 0) - alignedsize = 1; - - if (totalsize < 0) { - totalsize = alignedsize; - } - else { - if (detect_custom_layout(ct, sflags, alignedsize, - totalsize, "wrong total size", "", "") < 0) - goto error; + if (alignedsize == 0) + alignedsize = 1; + + if (totalsize < 0) { + totalsize = alignedsize; + } + else { + if (detect_custom_layout(ct, sflags, alignedsize, + totalsize, "wrong total size", "", "") < 0) + goto error; if (totalsize < byteoffsetmax) { - PyErr_Format(PyExc_TypeError, - "%s cannot be of size %zd: there are fields at least " + PyErr_Format(PyExc_TypeError, + "%s cannot be of size %zd: there are fields at least " "up to %zd", ct->ct_name, totalsize, byteoffsetmax); - goto error; - } - } - if (totalalignment < 0) { - totalalignment = alignment; - } - else { - if (detect_custom_layout(ct, sflags, alignment, totalalignment, - "wrong total alignment", "", "") < 0) - goto error; - } - - ct->ct_size = totalsize; - ct->ct_length = totalalignment; - ct->ct_stuff = interned_fields; - ct->ct_flags &= ~CT_IS_OPAQUE; - - Py_INCREF(Py_None); - return Py_None; - - error: - ct->ct_extra = NULL; - Py_DECREF(interned_fields); - return NULL; -} - -struct funcbuilder_s { - Py_ssize_t nb_bytes; - char *bufferp; - ffi_type **atypes; - ffi_type *rtype; - Py_ssize_t nargs; - CTypeDescrObject *fct; -}; - -static void *fb_alloc(struct funcbuilder_s *fb, Py_ssize_t size) -{ - if (fb->bufferp == NULL) { - fb->nb_bytes += size; - return NULL; - } - else { - char *result = fb->bufferp; - fb->bufferp += size; - return result; - } -} - + goto error; + } + } + if (totalalignment < 0) { + totalalignment = alignment; + } + else { + if (detect_custom_layout(ct, sflags, alignment, totalalignment, + "wrong total alignment", "", "") < 0) + goto error; + } + + ct->ct_size = totalsize; + ct->ct_length = totalalignment; + ct->ct_stuff = interned_fields; + ct->ct_flags &= ~CT_IS_OPAQUE; + + Py_INCREF(Py_None); + return Py_None; + + error: + ct->ct_extra = NULL; + Py_DECREF(interned_fields); + return NULL; +} + +struct funcbuilder_s { + Py_ssize_t nb_bytes; + char *bufferp; + ffi_type **atypes; + ffi_type *rtype; + Py_ssize_t nargs; + CTypeDescrObject *fct; +}; + +static void *fb_alloc(struct funcbuilder_s *fb, Py_ssize_t size) +{ + if (fb->bufferp == NULL) { + fb->nb_bytes += size; + return NULL; + } + else { + char *result = fb->bufferp; + fb->bufferp += size; + return result; + } +} + #define SUPPORTED_IN_API_MODE \ " are only supported as %s if the function is " \ "'API mode' and non-variadic (i.e. declared inside ffibuilder" \ @@ -5519,58 +5519,58 @@ static ffi_type *fb_unsupported(CTypeDescrObject *ct, const char *place, return NULL; } -static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, - int is_result_type) -{ - const char *place = is_result_type ? "return value" : "argument"; - +static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, + int is_result_type) +{ + const char *place = is_result_type ? "return value" : "argument"; + if (ct->ct_flags & (CT_PRIMITIVE_ANY & ~CT_PRIMITIVE_COMPLEX)) { - return (ffi_type *)ct->ct_extra; - } - else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { - return &ffi_type_pointer; - } - else if ((ct->ct_flags & CT_VOID) && is_result_type) { - return &ffi_type_void; - } - - if (ct->ct_size <= 0) { - PyErr_Format(PyExc_TypeError, - ct->ct_size < 0 ? "ctype '%s' has incomplete type" - : "ctype '%s' has size 0", - ct->ct_name); - return NULL; - } - if (ct->ct_flags & CT_STRUCT) { - ffi_type *ffistruct, *ffifield; - ffi_type **elements; - Py_ssize_t i, n, nflat; - CFieldObject *cf; - - /* We can't pass a struct that was completed by verify(). - Issue: assume verify() is given "struct { long b; ...; }". - Then it will complete it in the same way whether it is actually - "struct { long a, b; }" or "struct { double a; long b; }". - But on 64-bit UNIX, these two structs are passed by value - differently: e.g. on x86-64, "b" ends up in register "rsi" in - the first case and "rdi" in the second case. - - Another reason for CT_CUSTOM_FIELD_POS would be anonymous - nested structures: we lost the information about having it - here, so better safe (and forbid it) than sorry (and maybe + return (ffi_type *)ct->ct_extra; + } + else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { + return &ffi_type_pointer; + } + else if ((ct->ct_flags & CT_VOID) && is_result_type) { + return &ffi_type_void; + } + + if (ct->ct_size <= 0) { + PyErr_Format(PyExc_TypeError, + ct->ct_size < 0 ? "ctype '%s' has incomplete type" + : "ctype '%s' has size 0", + ct->ct_name); + return NULL; + } + if (ct->ct_flags & CT_STRUCT) { + ffi_type *ffistruct, *ffifield; + ffi_type **elements; + Py_ssize_t i, n, nflat; + CFieldObject *cf; + + /* We can't pass a struct that was completed by verify(). + Issue: assume verify() is given "struct { long b; ...; }". + Then it will complete it in the same way whether it is actually + "struct { long a, b; }" or "struct { double a; long b; }". + But on 64-bit UNIX, these two structs are passed by value + differently: e.g. on x86-64, "b" ends up in register "rsi" in + the first case and "rdi" in the second case. + + Another reason for CT_CUSTOM_FIELD_POS would be anonymous + nested structures: we lost the information about having it + here, so better safe (and forbid it) than sorry (and maybe crash). Note: it seems we only get in this case with ffi.verify(). - */ - if (force_lazy_struct(ct) < 0) - return NULL; - if (ct->ct_flags & CT_CUSTOM_FIELD_POS) { - /* these NotImplementedErrors may be caught and ignored until - a real call is made to a function of this type */ + */ + if (force_lazy_struct(ct) < 0) + return NULL; + if (ct->ct_flags & CT_CUSTOM_FIELD_POS) { + /* these NotImplementedErrors may be caught and ignored until + a real call is made to a function of this type */ return fb_unsupported(ct, place, "It is a struct declared with \"...;\", but the C " "calling convention may depend on the missing fields; " "or, it contains anonymous struct/unions"); - } + } /* Another reason: __attribute__((packed)) is not supported by libffi. */ if (ct->ct_flags & CT_WITH_PACKED_CHANGE) { @@ -5578,70 +5578,70 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, "It is a 'packed' structure, with a different layout than " "expected by libffi"); } - - n = PyDict_Size(ct->ct_stuff); - nflat = 0; - - /* walk the fields, expanding arrays into repetitions; first, - only count how many flattened fields there are */ - cf = (CFieldObject *)ct->ct_extra; - for (i=0; i<n; i++) { - Py_ssize_t flat; - CTypeDescrObject *ct1; - assert(cf != NULL); - if (cf->cf_bitshift >= 0) { + + n = PyDict_Size(ct->ct_stuff); + nflat = 0; + + /* walk the fields, expanding arrays into repetitions; first, + only count how many flattened fields there are */ + cf = (CFieldObject *)ct->ct_extra; + for (i=0; i<n; i++) { + Py_ssize_t flat; + CTypeDescrObject *ct1; + assert(cf != NULL); + if (cf->cf_bitshift >= 0) { return fb_unsupported(ct, place, "It is a struct with bit fields, which libffi does not " "support"); - } - flat = 1; - ct1 = cf->cf_type; - while (ct1->ct_flags & CT_ARRAY) { - flat *= ct1->ct_length; - ct1 = ct1->ct_itemdescr; - } - if (flat <= 0) { + } + flat = 1; + ct1 = cf->cf_type; + while (ct1->ct_flags & CT_ARRAY) { + flat *= ct1->ct_length; + ct1 = ct1->ct_itemdescr; + } + if (flat <= 0) { return fb_unsupported(ct, place, "It is a struct with a zero-length array, which libffi " "does not support"); - } - nflat += flat; - cf = cf->cf_next; - } - assert(cf == NULL); - - /* next, allocate and fill the flattened list */ - elements = fb_alloc(fb, (nflat + 1) * sizeof(ffi_type*)); - nflat = 0; - cf = (CFieldObject *)ct->ct_extra; - for (i=0; i<n; i++) { - Py_ssize_t j, flat = 1; - CTypeDescrObject *ct = cf->cf_type; - while (ct->ct_flags & CT_ARRAY) { - flat *= ct->ct_length; - ct = ct->ct_itemdescr; - } - ffifield = fb_fill_type(fb, ct, 0); - if (PyErr_Occurred()) - return NULL; - if (elements != NULL) { - for (j=0; j<flat; j++) - elements[nflat++] = ffifield; - } - cf = cf->cf_next; - } - - /* finally, allocate the FFI_TYPE_STRUCT */ - ffistruct = fb_alloc(fb, sizeof(ffi_type)); - if (ffistruct != NULL) { - elements[nflat] = NULL; - ffistruct->size = ct->ct_size; - ffistruct->alignment = ct->ct_length; - ffistruct->type = FFI_TYPE_STRUCT; - ffistruct->elements = elements; - } - return ffistruct; - } + } + nflat += flat; + cf = cf->cf_next; + } + assert(cf == NULL); + + /* next, allocate and fill the flattened list */ + elements = fb_alloc(fb, (nflat + 1) * sizeof(ffi_type*)); + nflat = 0; + cf = (CFieldObject *)ct->ct_extra; + for (i=0; i<n; i++) { + Py_ssize_t j, flat = 1; + CTypeDescrObject *ct = cf->cf_type; + while (ct->ct_flags & CT_ARRAY) { + flat *= ct->ct_length; + ct = ct->ct_itemdescr; + } + ffifield = fb_fill_type(fb, ct, 0); + if (PyErr_Occurred()) + return NULL; + if (elements != NULL) { + for (j=0; j<flat; j++) + elements[nflat++] = ffifield; + } + cf = cf->cf_next; + } + + /* finally, allocate the FFI_TYPE_STRUCT */ + ffistruct = fb_alloc(fb, sizeof(ffi_type)); + if (ffistruct != NULL) { + elements[nflat] = NULL; + ffistruct->size = ct->ct_size; + ffistruct->alignment = ct->ct_length; + ffistruct->type = FFI_TYPE_STRUCT; + ffistruct->elements = elements; + } + return ffistruct; + } else if (ct->ct_flags & CT_UNION) { PyErr_Format(PyExc_NotImplementedError, "ctype '%s' not supported as %s by libffi. " @@ -5649,7 +5649,7 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, ct->ct_name, place, place); return NULL; } - else { + else { char *extra = ""; if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) extra = " (the support for complex types inside libffi " @@ -5657,229 +5657,229 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, "supports complex types as arguments or return " "value in API-mode functions)"; - PyErr_Format(PyExc_NotImplementedError, + PyErr_Format(PyExc_NotImplementedError, "ctype '%s' (size %zd) not supported as %s%s", ct->ct_name, ct->ct_size, place, extra); - return NULL; - } -} - -#define ALIGN_ARG(n) ((n) + 7) & ~7 - -static int fb_build(struct funcbuilder_s *fb, PyObject *fargs, - CTypeDescrObject *fresult) -{ - Py_ssize_t i, nargs = PyTuple_GET_SIZE(fargs); - Py_ssize_t exchange_offset; - cif_description_t *cif_descr; - - /* ffi buffer: start with a cif_description */ - cif_descr = fb_alloc(fb, sizeof(cif_description_t) + - nargs * sizeof(Py_ssize_t)); - - /* ffi buffer: next comes an array of 'ffi_type*', one per argument */ - fb->atypes = fb_alloc(fb, nargs * sizeof(ffi_type*)); - fb->nargs = nargs; - - /* ffi buffer: next comes the result type */ - fb->rtype = fb_fill_type(fb, fresult, 1); - if (PyErr_Occurred()) - return -1; - if (cif_descr != NULL) { - /* exchange data size */ - /* first, enough room for an array of 'nargs' pointers */ - exchange_offset = nargs * sizeof(void*); - exchange_offset = ALIGN_ARG(exchange_offset); - cif_descr->exchange_offset_arg[0] = exchange_offset; - /* then enough room for the result --- which means at least - sizeof(ffi_arg), according to the ffi docs */ - i = fb->rtype->size; - if (i < (Py_ssize_t)sizeof(ffi_arg)) - i = sizeof(ffi_arg); - exchange_offset += i; - } - else - exchange_offset = 0; /* not used */ - - /* loop over the arguments */ - for (i=0; i<nargs; i++) { - CTypeDescrObject *farg; - ffi_type *atype; - - farg = (CTypeDescrObject *)PyTuple_GET_ITEM(fargs, i); - /* convert arrays to pointers */ - if (farg->ct_flags & CT_ARRAY) - farg = (CTypeDescrObject *)farg->ct_stuff; - - /* ffi buffer: fill in the ffi for the i'th argument */ - assert(farg != NULL); - atype = fb_fill_type(fb, farg, 0); - if (PyErr_Occurred()) - return -1; - - if (fb->atypes != NULL) { - fb->atypes[i] = atype; - /* exchange data size */ - exchange_offset = ALIGN_ARG(exchange_offset); - cif_descr->exchange_offset_arg[1 + i] = exchange_offset; - exchange_offset += atype->size; - } - } - - if (cif_descr != NULL) { - /* exchange data size */ - /* we also align it to the next multiple of 8, in an attempt to - work around bugs(?) of libffi like #241 */ - cif_descr->exchange_size = ALIGN_ARG(exchange_offset); - } - return 0; -} - -#undef ALIGN_ARG - -static void fb_cat_name(struct funcbuilder_s *fb, const char *piece, - int piecelen) -{ - if (fb->bufferp == NULL) { - fb->nb_bytes += piecelen; - } - else { - memcpy(fb->bufferp, piece, piecelen); - fb->bufferp += piecelen; - } -} - -static int fb_build_name(struct funcbuilder_s *fb, const char *repl, - CTypeDescrObject **pfargs, Py_ssize_t nargs, - CTypeDescrObject *fresult, int ellipsis) -{ - Py_ssize_t i; - fb->nargs = nargs; - - /* name: the function type name we build here is, like in C, made - as follows: - - RESULT_TYPE_HEAD (*)(ARG_1_TYPE, ARG_2_TYPE, etc) RESULT_TYPE_TAIL - */ - fb_cat_name(fb, fresult->ct_name, fresult->ct_name_position); - if (repl[0] != '(' && - fresult->ct_name[fresult->ct_name_position - 1] != '*') - fb_cat_name(fb, " ", 1); /* add a space */ - fb_cat_name(fb, repl, strlen(repl)); - if (fb->fct) { - i = strlen(repl) - 1; /* between '(*' and ')' */ - assert(repl[i] == ')'); - fb->fct->ct_name_position = fresult->ct_name_position + i; - } - fb_cat_name(fb, "(", 1); - - /* loop over the arguments */ - for (i=0; i<nargs; i++) { - CTypeDescrObject *farg; - - farg = pfargs[i]; - if (!CTypeDescr_Check(farg)) { - PyErr_SetString(PyExc_TypeError, "expected a tuple of ctypes"); - return -1; - } - /* name: concatenate the name of the i'th argument's type */ - if (i > 0) - fb_cat_name(fb, ", ", 2); - fb_cat_name(fb, farg->ct_name, strlen(farg->ct_name)); - } - - /* name: add the '...' if needed */ - if (ellipsis) { - if (nargs > 0) - fb_cat_name(fb, ", ", 2); - fb_cat_name(fb, "...", 3); - } - - /* name: concatenate the tail of the result type */ - fb_cat_name(fb, ")", 1); - fb_cat_name(fb, fresult->ct_name + fresult->ct_name_position, - strlen(fresult->ct_name) - fresult->ct_name_position + 1); - return 0; -} - -static CTypeDescrObject *fb_prepare_ctype(struct funcbuilder_s *fb, - PyObject *fargs, - CTypeDescrObject *fresult, - int ellipsis, int fabi) -{ - CTypeDescrObject *fct, **pfargs; - Py_ssize_t nargs; - char *repl = "(*)"; - - fb->nb_bytes = 0; - fb->bufferp = NULL; - fb->fct = NULL; - - pfargs = (CTypeDescrObject **)&PyTuple_GET_ITEM(fargs, 0); - nargs = PyTuple_GET_SIZE(fargs); -#if defined(MS_WIN32) && !defined(_WIN64) - if (fabi == FFI_STDCALL) - repl = "(__stdcall *)"; -#endif - - /* compute the total size needed for the name */ - if (fb_build_name(fb, repl, pfargs, nargs, fresult, ellipsis) < 0) - return NULL; - - /* allocate the function type */ - fct = ctypedescr_new(fb->nb_bytes); - if (fct == NULL) - return NULL; - fb->fct = fct; - - /* call again fb_build_name() to really build the ct_name */ - fb->bufferp = fct->ct_name; - if (fb_build_name(fb, repl, pfargs, nargs, fresult, ellipsis) < 0) - goto error; - assert(fb->bufferp == fct->ct_name + fb->nb_bytes); - - fct->ct_extra = NULL; - fct->ct_size = sizeof(void(*)(void)); - fct->ct_flags = CT_FUNCTIONPTR; - return fct; - - error: - Py_DECREF(fct); - return NULL; -} - -static cif_description_t *fb_prepare_cif(PyObject *fargs, - CTypeDescrObject *fresult, + return NULL; + } +} + +#define ALIGN_ARG(n) ((n) + 7) & ~7 + +static int fb_build(struct funcbuilder_s *fb, PyObject *fargs, + CTypeDescrObject *fresult) +{ + Py_ssize_t i, nargs = PyTuple_GET_SIZE(fargs); + Py_ssize_t exchange_offset; + cif_description_t *cif_descr; + + /* ffi buffer: start with a cif_description */ + cif_descr = fb_alloc(fb, sizeof(cif_description_t) + + nargs * sizeof(Py_ssize_t)); + + /* ffi buffer: next comes an array of 'ffi_type*', one per argument */ + fb->atypes = fb_alloc(fb, nargs * sizeof(ffi_type*)); + fb->nargs = nargs; + + /* ffi buffer: next comes the result type */ + fb->rtype = fb_fill_type(fb, fresult, 1); + if (PyErr_Occurred()) + return -1; + if (cif_descr != NULL) { + /* exchange data size */ + /* first, enough room for an array of 'nargs' pointers */ + exchange_offset = nargs * sizeof(void*); + exchange_offset = ALIGN_ARG(exchange_offset); + cif_descr->exchange_offset_arg[0] = exchange_offset; + /* then enough room for the result --- which means at least + sizeof(ffi_arg), according to the ffi docs */ + i = fb->rtype->size; + if (i < (Py_ssize_t)sizeof(ffi_arg)) + i = sizeof(ffi_arg); + exchange_offset += i; + } + else + exchange_offset = 0; /* not used */ + + /* loop over the arguments */ + for (i=0; i<nargs; i++) { + CTypeDescrObject *farg; + ffi_type *atype; + + farg = (CTypeDescrObject *)PyTuple_GET_ITEM(fargs, i); + /* convert arrays to pointers */ + if (farg->ct_flags & CT_ARRAY) + farg = (CTypeDescrObject *)farg->ct_stuff; + + /* ffi buffer: fill in the ffi for the i'th argument */ + assert(farg != NULL); + atype = fb_fill_type(fb, farg, 0); + if (PyErr_Occurred()) + return -1; + + if (fb->atypes != NULL) { + fb->atypes[i] = atype; + /* exchange data size */ + exchange_offset = ALIGN_ARG(exchange_offset); + cif_descr->exchange_offset_arg[1 + i] = exchange_offset; + exchange_offset += atype->size; + } + } + + if (cif_descr != NULL) { + /* exchange data size */ + /* we also align it to the next multiple of 8, in an attempt to + work around bugs(?) of libffi like #241 */ + cif_descr->exchange_size = ALIGN_ARG(exchange_offset); + } + return 0; +} + +#undef ALIGN_ARG + +static void fb_cat_name(struct funcbuilder_s *fb, const char *piece, + int piecelen) +{ + if (fb->bufferp == NULL) { + fb->nb_bytes += piecelen; + } + else { + memcpy(fb->bufferp, piece, piecelen); + fb->bufferp += piecelen; + } +} + +static int fb_build_name(struct funcbuilder_s *fb, const char *repl, + CTypeDescrObject **pfargs, Py_ssize_t nargs, + CTypeDescrObject *fresult, int ellipsis) +{ + Py_ssize_t i; + fb->nargs = nargs; + + /* name: the function type name we build here is, like in C, made + as follows: + + RESULT_TYPE_HEAD (*)(ARG_1_TYPE, ARG_2_TYPE, etc) RESULT_TYPE_TAIL + */ + fb_cat_name(fb, fresult->ct_name, fresult->ct_name_position); + if (repl[0] != '(' && + fresult->ct_name[fresult->ct_name_position - 1] != '*') + fb_cat_name(fb, " ", 1); /* add a space */ + fb_cat_name(fb, repl, strlen(repl)); + if (fb->fct) { + i = strlen(repl) - 1; /* between '(*' and ')' */ + assert(repl[i] == ')'); + fb->fct->ct_name_position = fresult->ct_name_position + i; + } + fb_cat_name(fb, "(", 1); + + /* loop over the arguments */ + for (i=0; i<nargs; i++) { + CTypeDescrObject *farg; + + farg = pfargs[i]; + if (!CTypeDescr_Check(farg)) { + PyErr_SetString(PyExc_TypeError, "expected a tuple of ctypes"); + return -1; + } + /* name: concatenate the name of the i'th argument's type */ + if (i > 0) + fb_cat_name(fb, ", ", 2); + fb_cat_name(fb, farg->ct_name, strlen(farg->ct_name)); + } + + /* name: add the '...' if needed */ + if (ellipsis) { + if (nargs > 0) + fb_cat_name(fb, ", ", 2); + fb_cat_name(fb, "...", 3); + } + + /* name: concatenate the tail of the result type */ + fb_cat_name(fb, ")", 1); + fb_cat_name(fb, fresult->ct_name + fresult->ct_name_position, + strlen(fresult->ct_name) - fresult->ct_name_position + 1); + return 0; +} + +static CTypeDescrObject *fb_prepare_ctype(struct funcbuilder_s *fb, + PyObject *fargs, + CTypeDescrObject *fresult, + int ellipsis, int fabi) +{ + CTypeDescrObject *fct, **pfargs; + Py_ssize_t nargs; + char *repl = "(*)"; + + fb->nb_bytes = 0; + fb->bufferp = NULL; + fb->fct = NULL; + + pfargs = (CTypeDescrObject **)&PyTuple_GET_ITEM(fargs, 0); + nargs = PyTuple_GET_SIZE(fargs); +#if defined(MS_WIN32) && !defined(_WIN64) + if (fabi == FFI_STDCALL) + repl = "(__stdcall *)"; +#endif + + /* compute the total size needed for the name */ + if (fb_build_name(fb, repl, pfargs, nargs, fresult, ellipsis) < 0) + return NULL; + + /* allocate the function type */ + fct = ctypedescr_new(fb->nb_bytes); + if (fct == NULL) + return NULL; + fb->fct = fct; + + /* call again fb_build_name() to really build the ct_name */ + fb->bufferp = fct->ct_name; + if (fb_build_name(fb, repl, pfargs, nargs, fresult, ellipsis) < 0) + goto error; + assert(fb->bufferp == fct->ct_name + fb->nb_bytes); + + fct->ct_extra = NULL; + fct->ct_size = sizeof(void(*)(void)); + fct->ct_flags = CT_FUNCTIONPTR; + return fct; + + error: + Py_DECREF(fct); + return NULL; +} + +static cif_description_t *fb_prepare_cif(PyObject *fargs, + CTypeDescrObject *fresult, Py_ssize_t variadic_nargs_declared, - ffi_abi fabi) + ffi_abi fabi) -{ - char *buffer; - cif_description_t *cif_descr; - struct funcbuilder_s funcbuffer; +{ + char *buffer; + cif_description_t *cif_descr; + struct funcbuilder_s funcbuffer; ffi_status status = (ffi_status)-1; - - funcbuffer.nb_bytes = 0; - funcbuffer.bufferp = NULL; - - /* compute the total size needed in the buffer for libffi */ - if (fb_build(&funcbuffer, fargs, fresult) < 0) - return NULL; - - /* allocate the buffer */ - buffer = PyObject_Malloc(funcbuffer.nb_bytes); - if (buffer == NULL) { - PyErr_NoMemory(); - return NULL; - } - - /* call again fb_build() to really build the libffi data structures */ - funcbuffer.bufferp = buffer; - if (fb_build(&funcbuffer, fargs, fresult) < 0) - goto error; - assert(funcbuffer.bufferp == buffer + funcbuffer.nb_bytes); - - cif_descr = (cif_description_t *)buffer; + + funcbuffer.nb_bytes = 0; + funcbuffer.bufferp = NULL; + + /* compute the total size needed in the buffer for libffi */ + if (fb_build(&funcbuffer, fargs, fresult) < 0) + return NULL; + + /* allocate the buffer */ + buffer = PyObject_Malloc(funcbuffer.nb_bytes); + if (buffer == NULL) { + PyErr_NoMemory(); + return NULL; + } + + /* call again fb_build() to really build the libffi data structures */ + funcbuffer.bufferp = buffer; + if (fb_build(&funcbuffer, fargs, fresult) < 0) + goto error; + assert(funcbuffer.bufferp == buffer + funcbuffer.nb_bytes); + + cif_descr = (cif_description_t *)buffer; /* use `ffi_prep_cif_var` if necessary and available */ #if CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE @@ -5898,177 +5898,177 @@ static cif_description_t *fb_prepare_cif(PyObject *fargs, } if (status != FFI_OK) { - PyErr_SetString(PyExc_SystemError, - "libffi failed to build this function type"); - goto error; - } - return cif_descr; - - error: - PyObject_Free(buffer); - return NULL; -} - -static PyObject *new_function_type(PyObject *fargs, /* tuple */ - CTypeDescrObject *fresult, - int ellipsis, int fabi) -{ - PyObject *fabiobj; - CTypeDescrObject *fct; - struct funcbuilder_s funcbuilder; - Py_ssize_t i; - const void **unique_key; - - if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) || - (fresult->ct_flags & CT_ARRAY)) { - char *msg; - if (fresult->ct_flags & CT_IS_OPAQUE) - msg = "result type '%s' is opaque"; - else - msg = "invalid result type: '%s'"; - PyErr_Format(PyExc_TypeError, msg, fresult->ct_name); - return NULL; - } - - fct = fb_prepare_ctype(&funcbuilder, fargs, fresult, ellipsis, fabi); - if (fct == NULL) - return NULL; - - if (!ellipsis) { - /* Functions with '...' varargs are stored without a cif_descr - at all. The cif is computed on every call from the actual - types passed in. For all other functions, the cif_descr - is computed here. */ - cif_description_t *cif_descr; - + PyErr_SetString(PyExc_SystemError, + "libffi failed to build this function type"); + goto error; + } + return cif_descr; + + error: + PyObject_Free(buffer); + return NULL; +} + +static PyObject *new_function_type(PyObject *fargs, /* tuple */ + CTypeDescrObject *fresult, + int ellipsis, int fabi) +{ + PyObject *fabiobj; + CTypeDescrObject *fct; + struct funcbuilder_s funcbuilder; + Py_ssize_t i; + const void **unique_key; + + if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) || + (fresult->ct_flags & CT_ARRAY)) { + char *msg; + if (fresult->ct_flags & CT_IS_OPAQUE) + msg = "result type '%s' is opaque"; + else + msg = "invalid result type: '%s'"; + PyErr_Format(PyExc_TypeError, msg, fresult->ct_name); + return NULL; + } + + fct = fb_prepare_ctype(&funcbuilder, fargs, fresult, ellipsis, fabi); + if (fct == NULL) + return NULL; + + if (!ellipsis) { + /* Functions with '...' varargs are stored without a cif_descr + at all. The cif is computed on every call from the actual + types passed in. For all other functions, the cif_descr + is computed here. */ + cif_description_t *cif_descr; + cif_descr = fb_prepare_cif(fargs, fresult, -1, fabi); - if (cif_descr == NULL) { - if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { - PyErr_Clear(); /* will get the exception if we see an - actual call */ - } - else - goto error; - } - - fct->ct_extra = (char *)cif_descr; - } - - /* build the signature, given by a tuple of ctype objects */ - fct->ct_stuff = PyTuple_New(2 + funcbuilder.nargs); - if (fct->ct_stuff == NULL) - goto error; - fabiobj = PyInt_FromLong(fabi); - if (fabiobj == NULL) - goto error; - PyTuple_SET_ITEM(fct->ct_stuff, 0, fabiobj); - - Py_INCREF(fresult); - PyTuple_SET_ITEM(fct->ct_stuff, 1, (PyObject *)fresult); - for (i=0; i<funcbuilder.nargs; i++) { - PyObject *o = PyTuple_GET_ITEM(fargs, i); - /* convert arrays into pointers */ - if (((CTypeDescrObject *)o)->ct_flags & CT_ARRAY) - o = ((CTypeDescrObject *)o)->ct_stuff; - Py_INCREF(o); - PyTuple_SET_ITEM(fct->ct_stuff, 2 + i, o); - } - - /* [ctresult, ellipsis+abi, num_args, ctargs...] */ - unique_key = alloca((3 + funcbuilder.nargs) * sizeof(void *)); - unique_key[0] = fresult; - unique_key[1] = (const void *)(Py_ssize_t)((fabi << 1) | !!ellipsis); - unique_key[2] = (const void *)(Py_ssize_t)(funcbuilder.nargs); - for (i=0; i<funcbuilder.nargs; i++) - unique_key[3 + i] = PyTuple_GET_ITEM(fct->ct_stuff, 2 + i); - return get_unique_type(fct, unique_key, 3 + funcbuilder.nargs); - - error: - Py_DECREF(fct); - return NULL; -} - -static PyObject *b_new_function_type(PyObject *self, PyObject *args) -{ - PyObject *fargs; - CTypeDescrObject *fresult; - int ellipsis = 0, fabi = FFI_DEFAULT_ABI; - - if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type", - &PyTuple_Type, &fargs, - &CTypeDescr_Type, &fresult, - &ellipsis, - &fabi)) - return NULL; - - return new_function_type(fargs, fresult, ellipsis, fabi); -} - -static int convert_from_object_fficallback(char *result, - CTypeDescrObject *ctype, - PyObject *pyobj, - int encode_result_for_libffi) -{ - /* work work work around a libffi irregularity: for integer return - types we have to fill at least a complete 'ffi_arg'-sized result - buffer. */ - if (ctype->ct_size < (Py_ssize_t)sizeof(ffi_arg)) { - if (ctype->ct_flags & CT_VOID) { - if (pyobj == Py_None) { - return 0; - } - else { - PyErr_SetString(PyExc_TypeError, - "callback with the return type 'void' must return None"); - return -1; - } - } - if (!encode_result_for_libffi) - goto skip; - if (ctype->ct_flags & CT_PRIMITIVE_SIGNED) { - PY_LONG_LONG value; - /* It's probably fine to always zero-extend, but you never - know: maybe some code somewhere expects a negative - 'short' result to be returned into EAX as a 32-bit - negative number. Better safe than sorry. This code - is about that case. Let's ignore this for enums. - */ - /* do a first conversion only to detect overflows. This - conversion produces stuff that is otherwise ignored. */ - if (convert_from_object(result, ctype, pyobj) < 0) - return -1; - /* manual inlining and tweaking of convert_from_object() - in order to write a whole 'ffi_arg'. */ - value = _my_PyLong_AsLongLong(pyobj); - if (value == -1 && PyErr_Occurred()) - return -1; - write_raw_integer_data(result, value, sizeof(ffi_arg)); - return 0; - } - else if (ctype->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | + if (cif_descr == NULL) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); /* will get the exception if we see an + actual call */ + } + else + goto error; + } + + fct->ct_extra = (char *)cif_descr; + } + + /* build the signature, given by a tuple of ctype objects */ + fct->ct_stuff = PyTuple_New(2 + funcbuilder.nargs); + if (fct->ct_stuff == NULL) + goto error; + fabiobj = PyInt_FromLong(fabi); + if (fabiobj == NULL) + goto error; + PyTuple_SET_ITEM(fct->ct_stuff, 0, fabiobj); + + Py_INCREF(fresult); + PyTuple_SET_ITEM(fct->ct_stuff, 1, (PyObject *)fresult); + for (i=0; i<funcbuilder.nargs; i++) { + PyObject *o = PyTuple_GET_ITEM(fargs, i); + /* convert arrays into pointers */ + if (((CTypeDescrObject *)o)->ct_flags & CT_ARRAY) + o = ((CTypeDescrObject *)o)->ct_stuff; + Py_INCREF(o); + PyTuple_SET_ITEM(fct->ct_stuff, 2 + i, o); + } + + /* [ctresult, ellipsis+abi, num_args, ctargs...] */ + unique_key = alloca((3 + funcbuilder.nargs) * sizeof(void *)); + unique_key[0] = fresult; + unique_key[1] = (const void *)(Py_ssize_t)((fabi << 1) | !!ellipsis); + unique_key[2] = (const void *)(Py_ssize_t)(funcbuilder.nargs); + for (i=0; i<funcbuilder.nargs; i++) + unique_key[3 + i] = PyTuple_GET_ITEM(fct->ct_stuff, 2 + i); + return get_unique_type(fct, unique_key, 3 + funcbuilder.nargs); + + error: + Py_DECREF(fct); + return NULL; +} + +static PyObject *b_new_function_type(PyObject *self, PyObject *args) +{ + PyObject *fargs; + CTypeDescrObject *fresult; + int ellipsis = 0, fabi = FFI_DEFAULT_ABI; + + if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type", + &PyTuple_Type, &fargs, + &CTypeDescr_Type, &fresult, + &ellipsis, + &fabi)) + return NULL; + + return new_function_type(fargs, fresult, ellipsis, fabi); +} + +static int convert_from_object_fficallback(char *result, + CTypeDescrObject *ctype, + PyObject *pyobj, + int encode_result_for_libffi) +{ + /* work work work around a libffi irregularity: for integer return + types we have to fill at least a complete 'ffi_arg'-sized result + buffer. */ + if (ctype->ct_size < (Py_ssize_t)sizeof(ffi_arg)) { + if (ctype->ct_flags & CT_VOID) { + if (pyobj == Py_None) { + return 0; + } + else { + PyErr_SetString(PyExc_TypeError, + "callback with the return type 'void' must return None"); + return -1; + } + } + if (!encode_result_for_libffi) + goto skip; + if (ctype->ct_flags & CT_PRIMITIVE_SIGNED) { + PY_LONG_LONG value; + /* It's probably fine to always zero-extend, but you never + know: maybe some code somewhere expects a negative + 'short' result to be returned into EAX as a 32-bit + negative number. Better safe than sorry. This code + is about that case. Let's ignore this for enums. + */ + /* do a first conversion only to detect overflows. This + conversion produces stuff that is otherwise ignored. */ + if (convert_from_object(result, ctype, pyobj) < 0) + return -1; + /* manual inlining and tweaking of convert_from_object() + in order to write a whole 'ffi_arg'. */ + value = _my_PyLong_AsLongLong(pyobj); + if (value == -1 && PyErr_Occurred()) + return -1; + write_raw_integer_data(result, value, sizeof(ffi_arg)); + return 0; + } + else if (ctype->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_UNSIGNED | CT_POINTER | CT_FUNCTIONPTR)) { - /* zero extension: fill the '*result' with zeros, and (on big- + /* zero extension: fill the '*result' with zeros, and (on big- endian machines) correct the 'result' pointer to write to. We also do that for pointers, even though we're normally not in this branch because ctype->ct_size == sizeof(ffi_arg) for pointers---except on some architectures like x32 (issue #372). */ - memset(result, 0, sizeof(ffi_arg)); -#ifdef WORDS_BIGENDIAN - result += (sizeof(ffi_arg) - ctype->ct_size); -#endif - } - } - skip: - return convert_from_object(result, ctype, pyobj); -} - + memset(result, 0, sizeof(ffi_arg)); +#ifdef WORDS_BIGENDIAN + result += (sizeof(ffi_arg) - ctype->ct_size); +#endif + } + } + skip: + return convert_from_object(result, ctype, pyobj); +} + static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, char *objdescr, PyObject *obj, - char *extra_error_line) -{ - /* like PyErr_WriteUnraisable(), but write a full traceback */ + char *extra_error_line) +{ + /* like PyErr_WriteUnraisable(), but write a full traceback */ #ifdef USE_WRITEUNRAISABLEMSG /* PyErr_WriteUnraisable actually writes the full traceback anyway @@ -6107,224 +6107,224 @@ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, /* version for Python 2.7 and < 3.8 */ PyObject *f; -#if PY_MAJOR_VERSION >= 3 - /* jump through hoops to ensure the tb is attached to v, on Python 3 */ - PyErr_NormalizeException(&t, &v, &tb); - if (tb == NULL) { - tb = Py_None; - Py_INCREF(tb); - } - PyException_SetTraceback(v, tb); -#endif - f = PySys_GetObject("stderr"); - if (f != NULL) { - if (obj != NULL) { - PyFile_WriteString(objdescr, f); - PyFile_WriteObject(obj, f, 0); - PyFile_WriteString(":\n", f); - } - if (extra_error_line != NULL) - PyFile_WriteString(extra_error_line, f); - PyErr_Display(t, v, tb); - } - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(tb); +#if PY_MAJOR_VERSION >= 3 + /* jump through hoops to ensure the tb is attached to v, on Python 3 */ + PyErr_NormalizeException(&t, &v, &tb); + if (tb == NULL) { + tb = Py_None; + Py_INCREF(tb); + } + PyException_SetTraceback(v, tb); +#endif + f = PySys_GetObject("stderr"); + if (f != NULL) { + if (obj != NULL) { + PyFile_WriteString(objdescr, f); + PyFile_WriteObject(obj, f, 0); + PyFile_WriteString(":\n", f); + } + if (extra_error_line != NULL) + PyFile_WriteString(extra_error_line, f); + PyErr_Display(t, v, tb); + } + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); #endif -} - -static void general_invoke_callback(int decode_args_from_libffi, - void *result, char *args, void *userdata) -{ - PyObject *cb_args = (PyObject *)userdata; - CTypeDescrObject *ct = (CTypeDescrObject *)PyTuple_GET_ITEM(cb_args, 0); - PyObject *signature = ct->ct_stuff; - PyObject *py_ob = PyTuple_GET_ITEM(cb_args, 1); - PyObject *py_args = NULL; - PyObject *py_res = NULL; - PyObject *py_rawerr; - PyObject *onerror_cb; - Py_ssize_t i, n; - char *extra_error_line = NULL; - -#define SIGNATURE(i) ((CTypeDescrObject *)PyTuple_GET_ITEM(signature, i)) - - Py_INCREF(cb_args); - - n = PyTuple_GET_SIZE(signature) - 2; - py_args = PyTuple_New(n); - if (py_args == NULL) - goto error; - - for (i=0; i<n; i++) { - char *a_src; - PyObject *a; - CTypeDescrObject *a_ct = SIGNATURE(2 + i); - - if (decode_args_from_libffi) { - a_src = ((void **)args)[i]; - } - else { - a_src = args + i * 8; - if (a_ct->ct_flags & (CT_IS_LONGDOUBLE | CT_STRUCT | CT_UNION)) - a_src = *(char **)a_src; - } - a = convert_to_object(a_src, a_ct); - if (a == NULL) - goto error; - PyTuple_SET_ITEM(py_args, i, a); - } - - py_res = PyObject_Call(py_ob, py_args, NULL); - if (py_res == NULL) - goto error; - if (convert_from_object_fficallback(result, SIGNATURE(1), py_res, - decode_args_from_libffi) < 0) { +} + +static void general_invoke_callback(int decode_args_from_libffi, + void *result, char *args, void *userdata) +{ + PyObject *cb_args = (PyObject *)userdata; + CTypeDescrObject *ct = (CTypeDescrObject *)PyTuple_GET_ITEM(cb_args, 0); + PyObject *signature = ct->ct_stuff; + PyObject *py_ob = PyTuple_GET_ITEM(cb_args, 1); + PyObject *py_args = NULL; + PyObject *py_res = NULL; + PyObject *py_rawerr; + PyObject *onerror_cb; + Py_ssize_t i, n; + char *extra_error_line = NULL; + +#define SIGNATURE(i) ((CTypeDescrObject *)PyTuple_GET_ITEM(signature, i)) + + Py_INCREF(cb_args); + + n = PyTuple_GET_SIZE(signature) - 2; + py_args = PyTuple_New(n); + if (py_args == NULL) + goto error; + + for (i=0; i<n; i++) { + char *a_src; + PyObject *a; + CTypeDescrObject *a_ct = SIGNATURE(2 + i); + + if (decode_args_from_libffi) { + a_src = ((void **)args)[i]; + } + else { + a_src = args + i * 8; + if (a_ct->ct_flags & (CT_IS_LONGDOUBLE | CT_STRUCT | CT_UNION)) + a_src = *(char **)a_src; + } + a = convert_to_object(a_src, a_ct); + if (a == NULL) + goto error; + PyTuple_SET_ITEM(py_args, i, a); + } + + py_res = PyObject_Call(py_ob, py_args, NULL); + if (py_res == NULL) + goto error; + if (convert_from_object_fficallback(result, SIGNATURE(1), py_res, + decode_args_from_libffi) < 0) { #ifdef USE_WRITEUNRAISABLEMSG extra_error_line = ", trying to convert the result back to C"; #else - extra_error_line = "Trying to convert the result back to C:\n"; + extra_error_line = "Trying to convert the result back to C:\n"; #endif - goto error; - } - done: - Py_XDECREF(py_args); - Py_XDECREF(py_res); - Py_DECREF(cb_args); - return; - - error: - if (SIGNATURE(1)->ct_size > 0) { - py_rawerr = PyTuple_GET_ITEM(cb_args, 2); - memcpy(result, PyBytes_AS_STRING(py_rawerr), - PyBytes_GET_SIZE(py_rawerr)); - } - onerror_cb = PyTuple_GET_ITEM(cb_args, 3); - if (onerror_cb == Py_None) { + goto error; + } + done: + Py_XDECREF(py_args); + Py_XDECREF(py_res); + Py_DECREF(cb_args); + return; + + error: + if (SIGNATURE(1)->ct_size > 0) { + py_rawerr = PyTuple_GET_ITEM(cb_args, 2); + memcpy(result, PyBytes_AS_STRING(py_rawerr), + PyBytes_GET_SIZE(py_rawerr)); + } + onerror_cb = PyTuple_GET_ITEM(cb_args, 3); + if (onerror_cb == Py_None) { PyObject *ecap, *t, *v, *tb; PyErr_Fetch(&t, &v, &tb); ecap = _cffi_start_error_capture(); _my_PyErr_WriteUnraisable(t, v, tb, "From cffi callback ", py_ob, - extra_error_line); + extra_error_line); _cffi_stop_error_capture(ecap); - } - else { - PyObject *exc1, *val1, *tb1, *res1, *exc2, *val2, *tb2; - PyErr_Fetch(&exc1, &val1, &tb1); - PyErr_NormalizeException(&exc1, &val1, &tb1); - res1 = PyObject_CallFunctionObjArgs(onerror_cb, - exc1 ? exc1 : Py_None, - val1 ? val1 : Py_None, - tb1 ? tb1 : Py_None, - NULL); - if (res1 != NULL) { - if (res1 != Py_None) - convert_from_object_fficallback(result, SIGNATURE(1), res1, - decode_args_from_libffi); - Py_DECREF(res1); - } - if (!PyErr_Occurred()) { - Py_XDECREF(exc1); - Py_XDECREF(val1); - Py_XDECREF(tb1); - } - else { - /* double exception! print a double-traceback... */ + } + else { + PyObject *exc1, *val1, *tb1, *res1, *exc2, *val2, *tb2; + PyErr_Fetch(&exc1, &val1, &tb1); + PyErr_NormalizeException(&exc1, &val1, &tb1); + res1 = PyObject_CallFunctionObjArgs(onerror_cb, + exc1 ? exc1 : Py_None, + val1 ? val1 : Py_None, + tb1 ? tb1 : Py_None, + NULL); + if (res1 != NULL) { + if (res1 != Py_None) + convert_from_object_fficallback(result, SIGNATURE(1), res1, + decode_args_from_libffi); + Py_DECREF(res1); + } + if (!PyErr_Occurred()) { + Py_XDECREF(exc1); + Py_XDECREF(val1); + Py_XDECREF(tb1); + } + else { + /* double exception! print a double-traceback... */ PyObject *ecap; - PyErr_Fetch(&exc2, &val2, &tb2); + PyErr_Fetch(&exc2, &val2, &tb2); ecap = _cffi_start_error_capture(); _my_PyErr_WriteUnraisable(exc1, val1, tb1, "From cffi callback ", py_ob, - extra_error_line); + extra_error_line); #ifdef USE_WRITEUNRAISABLEMSG _my_PyErr_WriteUnraisable(exc2, val2, tb2, "during handling of the above exception by 'onerror'", NULL, NULL); #else - extra_error_line = ("\nDuring the call to 'onerror', " - "another exception occurred:\n\n"); + extra_error_line = ("\nDuring the call to 'onerror', " + "another exception occurred:\n\n"); _my_PyErr_WriteUnraisable(exc2, val2, tb2, NULL, NULL, extra_error_line); #endif _cffi_stop_error_capture(ecap); - } - } - goto done; - -#undef SIGNATURE -} - -static void invoke_callback(ffi_cif *cif, void *result, void **args, - void *userdata) -{ - save_errno(); - { - PyGILState_STATE state = gil_ensure(); - general_invoke_callback(1, result, (char *)args, userdata); - gil_release(state); - } - restore_errno(); -} - -static PyObject *prepare_callback_info_tuple(CTypeDescrObject *ct, - PyObject *ob, - PyObject *error_ob, - PyObject *onerror_ob, - int decode_args_from_libffi) -{ - CTypeDescrObject *ctresult; - PyObject *py_rawerr, *infotuple; - Py_ssize_t size; - - if (!(ct->ct_flags & CT_FUNCTIONPTR)) { - PyErr_Format(PyExc_TypeError, "expected a function ctype, got '%s'", - ct->ct_name); - return NULL; - } - if (!PyCallable_Check(ob)) { - PyErr_Format(PyExc_TypeError, - "expected a callable object, not %.200s", - Py_TYPE(ob)->tp_name); - return NULL; - } - if (onerror_ob != Py_None && !PyCallable_Check(onerror_ob)) { - PyErr_Format(PyExc_TypeError, - "expected a callable object for 'onerror', not %.200s", - Py_TYPE(onerror_ob)->tp_name); - return NULL; - } - - ctresult = (CTypeDescrObject *)PyTuple_GET_ITEM(ct->ct_stuff, 1); - size = ctresult->ct_size; - if (size < (Py_ssize_t)sizeof(ffi_arg)) - size = sizeof(ffi_arg); - py_rawerr = PyBytes_FromStringAndSize(NULL, size); - if (py_rawerr == NULL) - return NULL; - memset(PyBytes_AS_STRING(py_rawerr), 0, size); - if (error_ob != Py_None) { - if (convert_from_object_fficallback( - PyBytes_AS_STRING(py_rawerr), ctresult, error_ob, - decode_args_from_libffi) < 0) { - Py_DECREF(py_rawerr); - return NULL; - } - } - infotuple = Py_BuildValue("OOOO", ct, ob, py_rawerr, onerror_ob); - Py_DECREF(py_rawerr); - + } + } + goto done; + +#undef SIGNATURE +} + +static void invoke_callback(ffi_cif *cif, void *result, void **args, + void *userdata) +{ + save_errno(); + { + PyGILState_STATE state = gil_ensure(); + general_invoke_callback(1, result, (char *)args, userdata); + gil_release(state); + } + restore_errno(); +} + +static PyObject *prepare_callback_info_tuple(CTypeDescrObject *ct, + PyObject *ob, + PyObject *error_ob, + PyObject *onerror_ob, + int decode_args_from_libffi) +{ + CTypeDescrObject *ctresult; + PyObject *py_rawerr, *infotuple; + Py_ssize_t size; + + if (!(ct->ct_flags & CT_FUNCTIONPTR)) { + PyErr_Format(PyExc_TypeError, "expected a function ctype, got '%s'", + ct->ct_name); + return NULL; + } + if (!PyCallable_Check(ob)) { + PyErr_Format(PyExc_TypeError, + "expected a callable object, not %.200s", + Py_TYPE(ob)->tp_name); + return NULL; + } + if (onerror_ob != Py_None && !PyCallable_Check(onerror_ob)) { + PyErr_Format(PyExc_TypeError, + "expected a callable object for 'onerror', not %.200s", + Py_TYPE(onerror_ob)->tp_name); + return NULL; + } + + ctresult = (CTypeDescrObject *)PyTuple_GET_ITEM(ct->ct_stuff, 1); + size = ctresult->ct_size; + if (size < (Py_ssize_t)sizeof(ffi_arg)) + size = sizeof(ffi_arg); + py_rawerr = PyBytes_FromStringAndSize(NULL, size); + if (py_rawerr == NULL) + return NULL; + memset(PyBytes_AS_STRING(py_rawerr), 0, size); + if (error_ob != Py_None) { + if (convert_from_object_fficallback( + PyBytes_AS_STRING(py_rawerr), ctresult, error_ob, + decode_args_from_libffi) < 0) { + Py_DECREF(py_rawerr); + return NULL; + } + } + infotuple = Py_BuildValue("OOOO", ct, ob, py_rawerr, onerror_ob); + Py_DECREF(py_rawerr); + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000 - /* We must setup the GIL here, in case the callback is invoked in + /* We must setup the GIL here, in case the callback is invoked in some other non-Pythonic thread. This is the same as ctypes. But PyEval_InitThreads() is always a no-op from CPython 3.7 (the call from ctypes was removed some time later I think). */ - PyEval_InitThreads(); -#endif - - return infotuple; -} - + PyEval_InitThreads(); +#endif + + return infotuple; +} + /* messily try to silence a gcc/clang deprecation warning for ffi_prep_closure. Don't miss the "pragma pop" after the function. This is done around the whole function because very old GCCs don't @@ -6336,25 +6336,25 @@ static PyObject *prepare_callback_info_tuple(CTypeDescrObject *ct, # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif -static PyObject *b_callback(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; +static PyObject *b_callback(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; CDataObject_closure *cd; - PyObject *ob, *error_ob = Py_None, *onerror_ob = Py_None; - PyObject *infotuple; - cif_description_t *cif_descr; - ffi_closure *closure; + PyObject *ob, *error_ob = Py_None, *onerror_ob = Py_None; + PyObject *infotuple; + cif_description_t *cif_descr; + ffi_closure *closure; ffi_status status; void *closure_exec; - - if (!PyArg_ParseTuple(args, "O!O|OO:callback", &CTypeDescr_Type, &ct, &ob, - &error_ob, &onerror_ob)) - return NULL; - - infotuple = prepare_callback_info_tuple(ct, ob, error_ob, onerror_ob, 1); - if (infotuple == NULL) - return NULL; - + + if (!PyArg_ParseTuple(args, "O!O|OO:callback", &CTypeDescr_Type, &ct, &ob, + &error_ob, &onerror_ob)) + return NULL; + + infotuple = prepare_callback_info_tuple(ct, ob, error_ob, onerror_ob, 1); + if (infotuple == NULL) + return NULL; + #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec); @@ -6375,22 +6375,22 @@ static PyObject *b_callback(PyObject *self, PyObject *args) return NULL; } cd = PyObject_GC_New(CDataObject_closure, &CDataOwningGC_Type); - if (cd == NULL) - goto error; - Py_INCREF(ct); + if (cd == NULL) + goto error; + Py_INCREF(ct); cd->head.c_type = ct; cd->head.c_data = (char *)closure_exec; cd->head.c_weakreflist = NULL; closure->user_data = NULL; cd->closure = closure; - - cif_descr = (cif_description_t *)ct->ct_extra; - if (cif_descr == NULL) { - PyErr_Format(PyExc_NotImplementedError, - "%s: callback with unsupported argument or " - "return type or with '...'", ct->ct_name); - goto error; - } + + cif_descr = (cif_description_t *)ct->ct_extra; + if (cif_descr == NULL) { + PyErr_Format(PyExc_NotImplementedError, + "%s: callback with unsupported argument or " + "return type or with '...'", ct->ct_name); + goto error; + } #if CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE if (CFFI_CHECK_FFI_PREP_CLOSURE_LOC) { @@ -6410,30 +6410,30 @@ static PyObject *b_callback(PyObject *self, PyObject *args) } if (status != FFI_OK) { - PyErr_SetString(PyExc_SystemError, - "libffi failed to build this callback"); - goto error; - } - - if (closure->user_data != infotuple) { - /* Issue #266. Should not occur, but could, if we are using - at runtime a version of libffi compiled with a different - 'ffi_closure' structure than the one we expect from ffi.h - (e.g. difference in details of the platform): a difference - in FFI_TRAMPOLINE_SIZE means that the 'user_data' field - ends up somewhere else, and so the test above fails. - */ - PyErr_SetString(PyExc_SystemError, - "ffi_prep_closure(): bad user_data (it seems that the " - "version of the libffi library seen at runtime is " - "different from the 'ffi.h' file seen at compile-time)"); - goto error; - } + PyErr_SetString(PyExc_SystemError, + "libffi failed to build this callback"); + goto error; + } + + if (closure->user_data != infotuple) { + /* Issue #266. Should not occur, but could, if we are using + at runtime a version of libffi compiled with a different + 'ffi_closure' structure than the one we expect from ffi.h + (e.g. difference in details of the platform): a difference + in FFI_TRAMPOLINE_SIZE means that the 'user_data' field + ends up somewhere else, and so the test above fails. + */ + PyErr_SetString(PyExc_SystemError, + "ffi_prep_closure(): bad user_data (it seems that the " + "version of the libffi library seen at runtime is " + "different from the 'ffi.h' file seen at compile-time)"); + goto error; + } PyObject_GC_Track(cd); - return (PyObject *)cd; - - error: - closure->user_data = NULL; + return (PyObject *)cd; + + error: + closure->user_data = NULL; if (cd == NULL) { #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { @@ -6443,354 +6443,354 @@ static PyObject *b_callback(PyObject *self, PyObject *args) #endif cffi_closure_free(closure); } - else - Py_DECREF(cd); - Py_XDECREF(infotuple); - return NULL; -} + else + Py_DECREF(cd); + Py_XDECREF(infotuple); + return NULL; +} #if defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) # pragma GCC diagnostic pop #endif - -static PyObject *b_new_enum_type(PyObject *self, PyObject *args) -{ - char *ename; - PyObject *enumerators, *enumvalues; - PyObject *dict1 = NULL, *dict2 = NULL, *combined = NULL, *tmpkey = NULL; - int name_size; - CTypeDescrObject *td, *basetd; - Py_ssize_t i, n; - - if (!PyArg_ParseTuple(args, "sO!O!O!:new_enum_type", - &ename, - &PyTuple_Type, &enumerators, - &PyTuple_Type, &enumvalues, - &CTypeDescr_Type, &basetd)) - return NULL; - - n = PyTuple_GET_SIZE(enumerators); - if (n != PyTuple_GET_SIZE(enumvalues)) { - PyErr_SetString(PyExc_ValueError, - "tuple args must have the same size"); - return NULL; - } - - if (!(basetd->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED))) { - PyErr_SetString(PyExc_TypeError, - "expected a primitive signed or unsigned base type"); - return NULL; - } - - dict1 = PyDict_New(); - if (dict1 == NULL) - goto error; - dict2 = PyDict_New(); - if (dict2 == NULL) - goto error; - - for (i=n; --i >= 0; ) { - long long lvalue; - PyObject *value = PyTuple_GET_ITEM(enumvalues, i); - tmpkey = PyTuple_GET_ITEM(enumerators, i); - Py_INCREF(tmpkey); - if (!PyText_Check(tmpkey)) { -#if PY_MAJOR_VERSION < 3 - if (PyUnicode_Check(tmpkey)) { + +static PyObject *b_new_enum_type(PyObject *self, PyObject *args) +{ + char *ename; + PyObject *enumerators, *enumvalues; + PyObject *dict1 = NULL, *dict2 = NULL, *combined = NULL, *tmpkey = NULL; + int name_size; + CTypeDescrObject *td, *basetd; + Py_ssize_t i, n; + + if (!PyArg_ParseTuple(args, "sO!O!O!:new_enum_type", + &ename, + &PyTuple_Type, &enumerators, + &PyTuple_Type, &enumvalues, + &CTypeDescr_Type, &basetd)) + return NULL; + + n = PyTuple_GET_SIZE(enumerators); + if (n != PyTuple_GET_SIZE(enumvalues)) { + PyErr_SetString(PyExc_ValueError, + "tuple args must have the same size"); + return NULL; + } + + if (!(basetd->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED))) { + PyErr_SetString(PyExc_TypeError, + "expected a primitive signed or unsigned base type"); + return NULL; + } + + dict1 = PyDict_New(); + if (dict1 == NULL) + goto error; + dict2 = PyDict_New(); + if (dict2 == NULL) + goto error; + + for (i=n; --i >= 0; ) { + long long lvalue; + PyObject *value = PyTuple_GET_ITEM(enumvalues, i); + tmpkey = PyTuple_GET_ITEM(enumerators, i); + Py_INCREF(tmpkey); + if (!PyText_Check(tmpkey)) { +#if PY_MAJOR_VERSION < 3 + if (PyUnicode_Check(tmpkey)) { const char *text = PyText_AsUTF8(tmpkey); - if (text == NULL) - goto error; - Py_DECREF(tmpkey); - tmpkey = PyString_FromString(text); - if (tmpkey == NULL) - goto error; - } - else -#endif - { - PyErr_SetString(PyExc_TypeError, - "enumerators must be a list of strings"); - goto error; - } - } - if (convert_from_object((char*)&lvalue, basetd, value) < 0) - goto error; /* out-of-range or badly typed 'value' */ - if (PyDict_SetItem(dict1, tmpkey, value) < 0) - goto error; - if (PyDict_SetItem(dict2, value, tmpkey) < 0) - goto error; - Py_DECREF(tmpkey); - tmpkey = NULL; - } - - combined = PyTuple_Pack(2, dict1, dict2); - if (combined == NULL) - goto error; - - Py_CLEAR(dict2); - Py_CLEAR(dict1); - - name_size = strlen(ename) + 1; - td = ctypedescr_new(name_size); - if (td == NULL) - goto error; - - memcpy(td->ct_name, ename, name_size); - td->ct_stuff = combined; - td->ct_size = basetd->ct_size; - td->ct_length = basetd->ct_length; /* alignment */ - td->ct_extra = basetd->ct_extra; /* ffi type */ - td->ct_flags = basetd->ct_flags | CT_IS_ENUM; - td->ct_name_position = name_size - 1; - return (PyObject *)td; - - error: - Py_XDECREF(tmpkey); - Py_XDECREF(combined); - Py_XDECREF(dict2); - Py_XDECREF(dict1); - return NULL; -} - -static PyObject *b_alignof(PyObject *self, PyObject *arg) -{ - int align; - if (!CTypeDescr_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "expected a 'ctype' object"); - return NULL; - } - align = get_alignment((CTypeDescrObject *)arg); - if (align < 0) - return NULL; - return PyInt_FromLong(align); -} - -static Py_ssize_t direct_sizeof_cdata(CDataObject *cd) -{ - Py_ssize_t size; - if (cd->c_type->ct_flags & CT_ARRAY) - size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; - else { - size = -1; - if (cd->c_type->ct_flags & (CT_STRUCT | CT_UNION)) - size = _cdata_var_byte_size(cd); - if (size < 0) - size = cd->c_type->ct_size; - } - return size; -} - -static PyObject *b_sizeof(PyObject *self, PyObject *arg) -{ - Py_ssize_t size; - - if (CData_Check(arg)) { - size = direct_sizeof_cdata((CDataObject *)arg); - } - else if (CTypeDescr_Check(arg)) { - size = ((CTypeDescrObject *)arg)->ct_size; - if (size < 0) { - PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown size", - ((CTypeDescrObject *)arg)->ct_name); - return NULL; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "expected a 'cdata' or 'ctype' object"); - return NULL; - } - return PyInt_FromSsize_t(size); -} - -static PyObject *b_typeof(PyObject *self, PyObject *arg) -{ - PyObject *res; - - if (!CData_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); - return NULL; - } - res = (PyObject *)((CDataObject *)arg)->c_type; - Py_INCREF(res); - return res; -} - -static CTypeDescrObject *direct_typeoffsetof(CTypeDescrObject *ct, - PyObject *fieldname, - int following, Py_ssize_t *offset) -{ - /* Does not return a new reference! */ - CTypeDescrObject *res; - CFieldObject *cf; - - if (PyTextAny_Check(fieldname)) { - if (!following && (ct->ct_flags & CT_POINTER)) - ct = ct->ct_itemdescr; - if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { - PyErr_SetString(PyExc_TypeError, - "with a field name argument, expected a " - "struct or union ctype"); - return NULL; - } - if (force_lazy_struct(ct) <= 0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, "struct/union is opaque"); - return NULL; - } - cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, fieldname); - if (cf == NULL) { - PyErr_SetObject(PyExc_KeyError, fieldname); - return NULL; - } - if (cf->cf_bitshift >= 0) { - PyErr_SetString(PyExc_TypeError, "not supported for bitfields"); - return NULL; - } - res = cf->cf_type; - *offset = cf->cf_offset; - } - else { - Py_ssize_t index = PyInt_AsSsize_t(fieldname); - if (index < 0 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "field name or array index expected"); - return NULL; - } - - if (!(ct->ct_flags & (CT_ARRAY|CT_POINTER)) || - ct->ct_itemdescr->ct_size < 0) { - PyErr_SetString(PyExc_TypeError, "with an integer argument, " - "expected an array ctype or a " - "pointer to non-opaque"); - return NULL; - } - res = ct->ct_itemdescr; - *offset = MUL_WRAPAROUND(index, ct->ct_itemdescr->ct_size); - if ((*offset / ct->ct_itemdescr->ct_size) != index) { - PyErr_SetString(PyExc_OverflowError, - "array offset would overflow a Py_ssize_t"); - return NULL; - } - } - return res; -} - -static PyObject *b_typeoffsetof(PyObject *self, PyObject *args) -{ - PyObject *res, *fieldname; - CTypeDescrObject *ct; - Py_ssize_t offset; - int following = 0; - - if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof", - &CTypeDescr_Type, &ct, &fieldname, &following)) - return NULL; - - res = (PyObject *)direct_typeoffsetof(ct, fieldname, following, &offset); - if (res == NULL) - return NULL; - - return Py_BuildValue("(On)", res, offset); -} - -static PyObject *b_rawaddressof(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - CDataObject *cd; - Py_ssize_t offset; - int accepted_flags; - - if (!PyArg_ParseTuple(args, "O!O!n:rawaddressof", - &CTypeDescr_Type, &ct, - &CData_Type, &cd, - &offset)) - return NULL; - - accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER; - if ((cd->c_type->ct_flags & accepted_flags) == 0) { - PyErr_SetString(PyExc_TypeError, - "expected a cdata struct/union/array/pointer object"); - return NULL; - } - if ((ct->ct_flags & CT_POINTER) == 0) { - PyErr_SetString(PyExc_TypeError, - "expected a pointer ctype"); - return NULL; - } - return new_simple_cdata(cd->c_data + offset, ct); -} - -static PyObject *b_getcname(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - char *replace_with, *p, *s; - Py_ssize_t namelen, replacelen; - - if (!PyArg_ParseTuple(args, "O!s:getcname", - &CTypeDescr_Type, &ct, &replace_with)) - return NULL; - - namelen = strlen(ct->ct_name); - replacelen = strlen(replace_with); - s = p = alloca(namelen + replacelen + 1); - memcpy(p, ct->ct_name, ct->ct_name_position); - p += ct->ct_name_position; - memcpy(p, replace_with, replacelen); - p += replacelen; - memcpy(p, ct->ct_name + ct->ct_name_position, - namelen - ct->ct_name_position); - - return PyText_FromStringAndSize(s, namelen + replacelen); -} - -static PyObject *b_string(PyObject *self, PyObject *args, PyObject *kwds) -{ - CDataObject *cd; - Py_ssize_t maxlen = -1; - static char *keywords[] = {"cdata", "maxlen", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:string", keywords, - &CData_Type, &cd, &maxlen)) - return NULL; - - if (cd->c_type->ct_itemdescr != NULL && - cd->c_type->ct_itemdescr->ct_flags & (CT_PRIMITIVE_CHAR | - CT_PRIMITIVE_SIGNED | + if (text == NULL) + goto error; + Py_DECREF(tmpkey); + tmpkey = PyString_FromString(text); + if (tmpkey == NULL) + goto error; + } + else +#endif + { + PyErr_SetString(PyExc_TypeError, + "enumerators must be a list of strings"); + goto error; + } + } + if (convert_from_object((char*)&lvalue, basetd, value) < 0) + goto error; /* out-of-range or badly typed 'value' */ + if (PyDict_SetItem(dict1, tmpkey, value) < 0) + goto error; + if (PyDict_SetItem(dict2, value, tmpkey) < 0) + goto error; + Py_DECREF(tmpkey); + tmpkey = NULL; + } + + combined = PyTuple_Pack(2, dict1, dict2); + if (combined == NULL) + goto error; + + Py_CLEAR(dict2); + Py_CLEAR(dict1); + + name_size = strlen(ename) + 1; + td = ctypedescr_new(name_size); + if (td == NULL) + goto error; + + memcpy(td->ct_name, ename, name_size); + td->ct_stuff = combined; + td->ct_size = basetd->ct_size; + td->ct_length = basetd->ct_length; /* alignment */ + td->ct_extra = basetd->ct_extra; /* ffi type */ + td->ct_flags = basetd->ct_flags | CT_IS_ENUM; + td->ct_name_position = name_size - 1; + return (PyObject *)td; + + error: + Py_XDECREF(tmpkey); + Py_XDECREF(combined); + Py_XDECREF(dict2); + Py_XDECREF(dict1); + return NULL; +} + +static PyObject *b_alignof(PyObject *self, PyObject *arg) +{ + int align; + if (!CTypeDescr_Check(arg)) { + PyErr_SetString(PyExc_TypeError, "expected a 'ctype' object"); + return NULL; + } + align = get_alignment((CTypeDescrObject *)arg); + if (align < 0) + return NULL; + return PyInt_FromLong(align); +} + +static Py_ssize_t direct_sizeof_cdata(CDataObject *cd) +{ + Py_ssize_t size; + if (cd->c_type->ct_flags & CT_ARRAY) + size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; + else { + size = -1; + if (cd->c_type->ct_flags & (CT_STRUCT | CT_UNION)) + size = _cdata_var_byte_size(cd); + if (size < 0) + size = cd->c_type->ct_size; + } + return size; +} + +static PyObject *b_sizeof(PyObject *self, PyObject *arg) +{ + Py_ssize_t size; + + if (CData_Check(arg)) { + size = direct_sizeof_cdata((CDataObject *)arg); + } + else if (CTypeDescr_Check(arg)) { + size = ((CTypeDescrObject *)arg)->ct_size; + if (size < 0) { + PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown size", + ((CTypeDescrObject *)arg)->ct_name); + return NULL; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "expected a 'cdata' or 'ctype' object"); + return NULL; + } + return PyInt_FromSsize_t(size); +} + +static PyObject *b_typeof(PyObject *self, PyObject *arg) +{ + PyObject *res; + + if (!CData_Check(arg)) { + PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); + return NULL; + } + res = (PyObject *)((CDataObject *)arg)->c_type; + Py_INCREF(res); + return res; +} + +static CTypeDescrObject *direct_typeoffsetof(CTypeDescrObject *ct, + PyObject *fieldname, + int following, Py_ssize_t *offset) +{ + /* Does not return a new reference! */ + CTypeDescrObject *res; + CFieldObject *cf; + + if (PyTextAny_Check(fieldname)) { + if (!following && (ct->ct_flags & CT_POINTER)) + ct = ct->ct_itemdescr; + if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { + PyErr_SetString(PyExc_TypeError, + "with a field name argument, expected a " + "struct or union ctype"); + return NULL; + } + if (force_lazy_struct(ct) <= 0) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, "struct/union is opaque"); + return NULL; + } + cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, fieldname); + if (cf == NULL) { + PyErr_SetObject(PyExc_KeyError, fieldname); + return NULL; + } + if (cf->cf_bitshift >= 0) { + PyErr_SetString(PyExc_TypeError, "not supported for bitfields"); + return NULL; + } + res = cf->cf_type; + *offset = cf->cf_offset; + } + else { + Py_ssize_t index = PyInt_AsSsize_t(fieldname); + if (index < 0 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "field name or array index expected"); + return NULL; + } + + if (!(ct->ct_flags & (CT_ARRAY|CT_POINTER)) || + ct->ct_itemdescr->ct_size < 0) { + PyErr_SetString(PyExc_TypeError, "with an integer argument, " + "expected an array ctype or a " + "pointer to non-opaque"); + return NULL; + } + res = ct->ct_itemdescr; + *offset = MUL_WRAPAROUND(index, ct->ct_itemdescr->ct_size); + if ((*offset / ct->ct_itemdescr->ct_size) != index) { + PyErr_SetString(PyExc_OverflowError, + "array offset would overflow a Py_ssize_t"); + return NULL; + } + } + return res; +} + +static PyObject *b_typeoffsetof(PyObject *self, PyObject *args) +{ + PyObject *res, *fieldname; + CTypeDescrObject *ct; + Py_ssize_t offset; + int following = 0; + + if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof", + &CTypeDescr_Type, &ct, &fieldname, &following)) + return NULL; + + res = (PyObject *)direct_typeoffsetof(ct, fieldname, following, &offset); + if (res == NULL) + return NULL; + + return Py_BuildValue("(On)", res, offset); +} + +static PyObject *b_rawaddressof(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + CDataObject *cd; + Py_ssize_t offset; + int accepted_flags; + + if (!PyArg_ParseTuple(args, "O!O!n:rawaddressof", + &CTypeDescr_Type, &ct, + &CData_Type, &cd, + &offset)) + return NULL; + + accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER; + if ((cd->c_type->ct_flags & accepted_flags) == 0) { + PyErr_SetString(PyExc_TypeError, + "expected a cdata struct/union/array/pointer object"); + return NULL; + } + if ((ct->ct_flags & CT_POINTER) == 0) { + PyErr_SetString(PyExc_TypeError, + "expected a pointer ctype"); + return NULL; + } + return new_simple_cdata(cd->c_data + offset, ct); +} + +static PyObject *b_getcname(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + char *replace_with, *p, *s; + Py_ssize_t namelen, replacelen; + + if (!PyArg_ParseTuple(args, "O!s:getcname", + &CTypeDescr_Type, &ct, &replace_with)) + return NULL; + + namelen = strlen(ct->ct_name); + replacelen = strlen(replace_with); + s = p = alloca(namelen + replacelen + 1); + memcpy(p, ct->ct_name, ct->ct_name_position); + p += ct->ct_name_position; + memcpy(p, replace_with, replacelen); + p += replacelen; + memcpy(p, ct->ct_name + ct->ct_name_position, + namelen - ct->ct_name_position); + + return PyText_FromStringAndSize(s, namelen + replacelen); +} + +static PyObject *b_string(PyObject *self, PyObject *args, PyObject *kwds) +{ + CDataObject *cd; + Py_ssize_t maxlen = -1; + static char *keywords[] = {"cdata", "maxlen", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:string", keywords, + &CData_Type, &cd, &maxlen)) + return NULL; + + if (cd->c_type->ct_itemdescr != NULL && + cd->c_type->ct_itemdescr->ct_flags & (CT_PRIMITIVE_CHAR | + CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_UNSIGNED) && !(cd->c_type->ct_itemdescr->ct_flags & CT_IS_BOOL)) { - Py_ssize_t length = maxlen; - if (cd->c_data == NULL) { - PyObject *s = cdata_repr(cd); - if (s != NULL) { - PyErr_Format(PyExc_RuntimeError, - "cannot use string() on %s", - PyText_AS_UTF8(s)); - Py_DECREF(s); - } - return NULL; - } - if (length < 0 && cd->c_type->ct_flags & CT_ARRAY) { - length = get_array_length(cd); - } - if (cd->c_type->ct_itemdescr->ct_size == sizeof(char)) { - const char *start = cd->c_data; - if (length < 0) { - /*READ(start, 1)*/ - length = strlen(start); - /*READ(start, length)*/ - } - else { - const char *end; - /*READ(start, length)*/ - end = (const char *)memchr(start, 0, length); - if (end != NULL) - length = end - start; - } - return PyBytes_FromStringAndSize(start, length); - } - else if (cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR) { + Py_ssize_t length = maxlen; + if (cd->c_data == NULL) { + PyObject *s = cdata_repr(cd); + if (s != NULL) { + PyErr_Format(PyExc_RuntimeError, + "cannot use string() on %s", + PyText_AS_UTF8(s)); + Py_DECREF(s); + } + return NULL; + } + if (length < 0 && cd->c_type->ct_flags & CT_ARRAY) { + length = get_array_length(cd); + } + if (cd->c_type->ct_itemdescr->ct_size == sizeof(char)) { + const char *start = cd->c_data; + if (length < 0) { + /*READ(start, 1)*/ + length = strlen(start); + /*READ(start, length)*/ + } + else { + const char *end; + /*READ(start, length)*/ + end = (const char *)memchr(start, 0, length); + if (end != NULL) + length = end - start; + } + return PyBytes_FromStringAndSize(start, length); + } + else if (cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR) { switch (cd->c_type->ct_itemdescr->ct_size) { case 2: { const cffi_char16_t *start = (cffi_char16_t *)cd->c_data; @@ -6809,7 +6809,7 @@ static PyObject *b_string(PyObject *self, PyObject *args, PyObject *kwds) length++; } return _my_PyUnicode_FromChar16(start, length); - } + } case 4: { const cffi_char32_t *start = (cffi_char32_t *)cd->c_data; if (length < 0) { @@ -6827,164 +6827,164 @@ static PyObject *b_string(PyObject *self, PyObject *args, PyObject *kwds) length++; } return _my_PyUnicode_FromChar32(start, length); + } } - } - } - } - else if (cd->c_type->ct_flags & CT_IS_ENUM) { - return convert_cdata_to_enum_string(cd, 0); - } - else if (cd->c_type->ct_flags & CT_IS_BOOL) { - /* fall through to TypeError */ - } - else if (cd->c_type->ct_flags & (CT_PRIMITIVE_CHAR | - CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED)) { - /*READ(cd->c_data, cd->c_type->ct_size)*/ - if (cd->c_type->ct_size == sizeof(char)) - return PyBytes_FromStringAndSize(cd->c_data, 1); - else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { + } + } + else if (cd->c_type->ct_flags & CT_IS_ENUM) { + return convert_cdata_to_enum_string(cd, 0); + } + else if (cd->c_type->ct_flags & CT_IS_BOOL) { + /* fall through to TypeError */ + } + else if (cd->c_type->ct_flags & (CT_PRIMITIVE_CHAR | + CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED)) { + /*READ(cd->c_data, cd->c_type->ct_size)*/ + if (cd->c_type->ct_size == sizeof(char)) + return PyBytes_FromStringAndSize(cd->c_data, 1); + else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { switch (cd->c_type->ct_size) { case 2: return _my_PyUnicode_FromChar16((cffi_char16_t *)cd->c_data, 1); case 4: return _my_PyUnicode_FromChar32((cffi_char32_t *)cd->c_data, 1); } - } - } - PyErr_Format(PyExc_TypeError, "string(): unexpected cdata '%s' argument", - cd->c_type->ct_name); - return NULL; -} - -static PyObject *b_unpack(PyObject *self, PyObject *args, PyObject *kwds) -{ - CDataObject *cd; - CTypeDescrObject *ctitem; - Py_ssize_t i, length, itemsize; - PyObject *result; - char *src; - int casenum; - static char *keywords[] = {"cdata", "length", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!n:unpack", keywords, - &CData_Type, &cd, &length)) - return NULL; - - if (!(cd->c_type->ct_flags & (CT_ARRAY|CT_POINTER))) { - PyErr_Format(PyExc_TypeError, - "expected a pointer or array, got '%s'", - cd->c_type->ct_name); - return NULL; - } - if (length < 0) { - PyErr_SetString(PyExc_ValueError, "'length' cannot be negative"); - return NULL; - } - if (cd->c_data == NULL) { - PyObject *s = cdata_repr(cd); - if (s != NULL) { - PyErr_Format(PyExc_RuntimeError, - "cannot use unpack() on %s", - PyText_AS_UTF8(s)); - Py_DECREF(s); - } - return NULL; - } - - /* byte- and unicode strings */ - ctitem = cd->c_type->ct_itemdescr; - if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) { + } + } + PyErr_Format(PyExc_TypeError, "string(): unexpected cdata '%s' argument", + cd->c_type->ct_name); + return NULL; +} + +static PyObject *b_unpack(PyObject *self, PyObject *args, PyObject *kwds) +{ + CDataObject *cd; + CTypeDescrObject *ctitem; + Py_ssize_t i, length, itemsize; + PyObject *result; + char *src; + int casenum; + static char *keywords[] = {"cdata", "length", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!n:unpack", keywords, + &CData_Type, &cd, &length)) + return NULL; + + if (!(cd->c_type->ct_flags & (CT_ARRAY|CT_POINTER))) { + PyErr_Format(PyExc_TypeError, + "expected a pointer or array, got '%s'", + cd->c_type->ct_name); + return NULL; + } + if (length < 0) { + PyErr_SetString(PyExc_ValueError, "'length' cannot be negative"); + return NULL; + } + if (cd->c_data == NULL) { + PyObject *s = cdata_repr(cd); + if (s != NULL) { + PyErr_Format(PyExc_RuntimeError, + "cannot use unpack() on %s", + PyText_AS_UTF8(s)); + Py_DECREF(s); + } + return NULL; + } + + /* byte- and unicode strings */ + ctitem = cd->c_type->ct_itemdescr; + if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) { switch (ctitem->ct_size) { case sizeof(char): - return PyBytes_FromStringAndSize(cd->c_data, length); + return PyBytes_FromStringAndSize(cd->c_data, length); case 2: return _my_PyUnicode_FromChar16((cffi_char16_t *)cd->c_data,length); case 4: return _my_PyUnicode_FromChar32((cffi_char32_t *)cd->c_data,length); } - } - - /* else, the result is a list. This implementation should be - equivalent to but much faster than '[p[i] for i in range(length)]'. - (Note that on PyPy, 'list(p[0:length])' should be equally fast, - but arguably, finding out that there *is* such an unexpected way - to write things down is the real problem.) - */ - result = PyList_New(length); - if (result == NULL) - return NULL; - - src = cd->c_data; - itemsize = ctitem->ct_size; - if (itemsize < 0) { + } + + /* else, the result is a list. This implementation should be + equivalent to but much faster than '[p[i] for i in range(length)]'. + (Note that on PyPy, 'list(p[0:length])' should be equally fast, + but arguably, finding out that there *is* such an unexpected way + to write things down is the real problem.) + */ + result = PyList_New(length); + if (result == NULL) + return NULL; + + src = cd->c_data; + itemsize = ctitem->ct_size; + if (itemsize < 0) { Py_DECREF(result); - PyErr_Format(PyExc_ValueError, "'%s' points to items of unknown size", - cd->c_type->ct_name); - return NULL; - } - - /* Determine some common fast-paths for the loop below. The case -1 - is the fall-back, which always gives the right answer. */ - -#define ALIGNMENT_CHECK(align) \ - (((align) & ((align) - 1)) == 0 && \ - (((uintptr_t)src) & ((align) - 1)) == 0) - - casenum = -1; - - if ((ctitem->ct_flags & CT_PRIMITIVE_ANY) && - ALIGNMENT_CHECK(ctitem->ct_length)) { - /* Source data is fully aligned; we can directly read without - memcpy(). The unaligned case is expected to be rare; in - this situation it is ok to fall back to the general - convert_to_object() in the loop. For now we also use this - fall-back for types that are too large. - */ - if (ctitem->ct_flags & CT_PRIMITIVE_SIGNED) { - if (itemsize == sizeof(long)) casenum = 3; - else if (itemsize == sizeof(int)) casenum = 2; - else if (itemsize == sizeof(short)) casenum = 1; - else if (itemsize == sizeof(signed char)) casenum = 0; - } - else if (ctitem->ct_flags & CT_PRIMITIVE_UNSIGNED) { - /* Note: we never pick case 6 if sizeof(int) == sizeof(long), - so that case 6 below can assume that the 'unsigned int' result - would always fit in a 'signed long'. */ + PyErr_Format(PyExc_ValueError, "'%s' points to items of unknown size", + cd->c_type->ct_name); + return NULL; + } + + /* Determine some common fast-paths for the loop below. The case -1 + is the fall-back, which always gives the right answer. */ + +#define ALIGNMENT_CHECK(align) \ + (((align) & ((align) - 1)) == 0 && \ + (((uintptr_t)src) & ((align) - 1)) == 0) + + casenum = -1; + + if ((ctitem->ct_flags & CT_PRIMITIVE_ANY) && + ALIGNMENT_CHECK(ctitem->ct_length)) { + /* Source data is fully aligned; we can directly read without + memcpy(). The unaligned case is expected to be rare; in + this situation it is ok to fall back to the general + convert_to_object() in the loop. For now we also use this + fall-back for types that are too large. + */ + if (ctitem->ct_flags & CT_PRIMITIVE_SIGNED) { + if (itemsize == sizeof(long)) casenum = 3; + else if (itemsize == sizeof(int)) casenum = 2; + else if (itemsize == sizeof(short)) casenum = 1; + else if (itemsize == sizeof(signed char)) casenum = 0; + } + else if (ctitem->ct_flags & CT_PRIMITIVE_UNSIGNED) { + /* Note: we never pick case 6 if sizeof(int) == sizeof(long), + so that case 6 below can assume that the 'unsigned int' result + would always fit in a 'signed long'. */ if (ctitem->ct_flags & CT_IS_BOOL) casenum = 11; else if (itemsize == sizeof(unsigned long)) casenum = 7; - else if (itemsize == sizeof(unsigned int)) casenum = 6; - else if (itemsize == sizeof(unsigned short)) casenum = 5; - else if (itemsize == sizeof(unsigned char)) casenum = 4; - } - else if (ctitem->ct_flags & CT_PRIMITIVE_FLOAT) { - if (itemsize == sizeof(double)) casenum = 9; - else if (itemsize == sizeof(float)) casenum = 8; - } - } - else if (ctitem->ct_flags & (CT_POINTER | CT_FUNCTIONPTR)) { - casenum = 10; /* any pointer */ - } -#undef ALIGNMENT_CHECK - - for (i = 0; i < length; i++) { - PyObject *x; - switch (casenum) { - /* general case */ - default: x = convert_to_object(src, ctitem); break; - - /* special cases for performance only */ - case 0: x = PyInt_FromLong(*(signed char *)src); break; - case 1: x = PyInt_FromLong(*(short *)src); break; - case 2: x = PyInt_FromLong(*(int *)src); break; - case 3: x = PyInt_FromLong(*(long *)src); break; - case 4: x = PyInt_FromLong(*(unsigned char *)src); break; - case 5: x = PyInt_FromLong(*(unsigned short *)src); break; - case 6: x = PyInt_FromLong((long)*(unsigned int *)src); break; - case 7: x = PyLong_FromUnsignedLong(*(unsigned long *)src); break; - case 8: x = PyFloat_FromDouble(*(float *)src); break; - case 9: x = PyFloat_FromDouble(*(double *)src); break; - case 10: x = new_simple_cdata(*(char **)src, ctitem); break; + else if (itemsize == sizeof(unsigned int)) casenum = 6; + else if (itemsize == sizeof(unsigned short)) casenum = 5; + else if (itemsize == sizeof(unsigned char)) casenum = 4; + } + else if (ctitem->ct_flags & CT_PRIMITIVE_FLOAT) { + if (itemsize == sizeof(double)) casenum = 9; + else if (itemsize == sizeof(float)) casenum = 8; + } + } + else if (ctitem->ct_flags & (CT_POINTER | CT_FUNCTIONPTR)) { + casenum = 10; /* any pointer */ + } +#undef ALIGNMENT_CHECK + + for (i = 0; i < length; i++) { + PyObject *x; + switch (casenum) { + /* general case */ + default: x = convert_to_object(src, ctitem); break; + + /* special cases for performance only */ + case 0: x = PyInt_FromLong(*(signed char *)src); break; + case 1: x = PyInt_FromLong(*(short *)src); break; + case 2: x = PyInt_FromLong(*(int *)src); break; + case 3: x = PyInt_FromLong(*(long *)src); break; + case 4: x = PyInt_FromLong(*(unsigned char *)src); break; + case 5: x = PyInt_FromLong(*(unsigned short *)src); break; + case 6: x = PyInt_FromLong((long)*(unsigned int *)src); break; + case 7: x = PyLong_FromUnsignedLong(*(unsigned long *)src); break; + case 8: x = PyFloat_FromDouble(*(float *)src); break; + case 9: x = PyFloat_FromDouble(*(double *)src); break; + case 10: x = new_simple_cdata(*(char **)src, ctitem); break; case 11: switch (*(unsigned char *)src) { case 0: x = Py_False; Py_INCREF(x); break; @@ -6992,233 +6992,233 @@ static PyObject *b_unpack(PyObject *self, PyObject *args, PyObject *kwds) default: x = convert_to_object(src, ctitem); /* error */ } break; - } - if (x == NULL) { - Py_DECREF(result); - return NULL; - } - PyList_SET_ITEM(result, i, x); - src += itemsize; - } - return result; -} - + } + if (x == NULL) { + Py_DECREF(result); + return NULL; + } + PyList_SET_ITEM(result, i, x); + src += itemsize; + } + return result; +} + static PyObject * b_buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ +{ /* this is the constructor of the type implemented in minibuffer.h */ - CDataObject *cd; - Py_ssize_t size = -1; - static char *keywords[] = {"cdata", "size", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:buffer", keywords, - &CData_Type, &cd, &size)) - return NULL; - - if (size < 0) - size = _cdata_var_byte_size(cd); - - if (cd->c_type->ct_flags & CT_POINTER) { - if (size < 0) - size = cd->c_type->ct_itemdescr->ct_size; - } - else if (cd->c_type->ct_flags & CT_ARRAY) { - if (size < 0) - size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; - } - else { - PyErr_Format(PyExc_TypeError, - "expected a pointer or array cdata, got '%s'", - cd->c_type->ct_name); - return NULL; - } - if (size < 0) { - PyErr_Format(PyExc_TypeError, - "don't know the size pointed to by '%s'", - cd->c_type->ct_name); - return NULL; - } - /*WRITE(cd->c_data, size)*/ - return minibuffer_new(cd->c_data, size, (PyObject *)cd); -} - -static PyObject *b_get_errno(PyObject *self, PyObject *noarg) -{ - int err; - restore_errno_only(); - err = errno; - errno = 0; - return PyInt_FromLong(err); -} - -static PyObject *b_set_errno(PyObject *self, PyObject *arg) -{ - long ival = PyInt_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) - return NULL; - else if (ival < INT_MIN || ival > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, "errno value too large"); - return NULL; - } - errno = (int)ival; - save_errno_only(); - errno = 0; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *newp_handle(CTypeDescrObject *ct_voidp, PyObject *x) -{ - CDataObject_own_structptr *cd; - cd = (CDataObject_own_structptr *)PyObject_GC_New(CDataObject_own_structptr, - &CDataOwningGC_Type); - if (cd == NULL) - return NULL; + CDataObject *cd; + Py_ssize_t size = -1; + static char *keywords[] = {"cdata", "size", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:buffer", keywords, + &CData_Type, &cd, &size)) + return NULL; + + if (size < 0) + size = _cdata_var_byte_size(cd); + + if (cd->c_type->ct_flags & CT_POINTER) { + if (size < 0) + size = cd->c_type->ct_itemdescr->ct_size; + } + else if (cd->c_type->ct_flags & CT_ARRAY) { + if (size < 0) + size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; + } + else { + PyErr_Format(PyExc_TypeError, + "expected a pointer or array cdata, got '%s'", + cd->c_type->ct_name); + return NULL; + } + if (size < 0) { + PyErr_Format(PyExc_TypeError, + "don't know the size pointed to by '%s'", + cd->c_type->ct_name); + return NULL; + } + /*WRITE(cd->c_data, size)*/ + return minibuffer_new(cd->c_data, size, (PyObject *)cd); +} + +static PyObject *b_get_errno(PyObject *self, PyObject *noarg) +{ + int err; + restore_errno_only(); + err = errno; + errno = 0; + return PyInt_FromLong(err); +} + +static PyObject *b_set_errno(PyObject *self, PyObject *arg) +{ + long ival = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return NULL; + else if (ival < INT_MIN || ival > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "errno value too large"); + return NULL; + } + errno = (int)ival; + save_errno_only(); + errno = 0; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *newp_handle(CTypeDescrObject *ct_voidp, PyObject *x) +{ + CDataObject_own_structptr *cd; + cd = (CDataObject_own_structptr *)PyObject_GC_New(CDataObject_own_structptr, + &CDataOwningGC_Type); + if (cd == NULL) + return NULL; Py_INCREF(ct_voidp); /* must be "void *" */ - cd->head.c_type = ct_voidp; - cd->head.c_data = (char *)cd; - cd->head.c_weakreflist = NULL; - Py_INCREF(x); - cd->structobj = x; - PyObject_GC_Track(cd); - return (PyObject *)cd; -} - -static PyObject *b_newp_handle(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *x; - if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x)) - return NULL; - - if (!(ct->ct_flags & CT_IS_VOID_PTR)) { - PyErr_Format(PyExc_TypeError, "needs 'void *', got '%s'", ct->ct_name); - return NULL; - } - - return newp_handle(ct, x); -} - -static PyObject *b_from_handle(PyObject *self, PyObject *arg) -{ - CTypeDescrObject *ct; - CDataObject_own_structptr *orgcd; - PyObject *x; - if (!CData_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); - return NULL; - } - ct = ((CDataObject *)arg)->c_type; - if (!(ct->ct_flags & CT_IS_VOIDCHAR_PTR)) { - PyErr_Format(PyExc_TypeError, - "expected a 'cdata' object with a 'void *' out of " - "new_handle(), got '%s'", ct->ct_name); - return NULL; - } - orgcd = (CDataObject_own_structptr *)((CDataObject *)arg)->c_data; - if (!orgcd) { - PyErr_SetString(PyExc_RuntimeError, - "cannot use from_handle() on NULL pointer"); - return NULL; - } - if (Py_REFCNT(orgcd) <= 0 || Py_TYPE(orgcd) != &CDataOwningGC_Type) { - Py_FatalError("ffi.from_handle() detected that the address passed " - "points to garbage. If it is really the result of " - "ffi.new_handle(), then the Python object has already " - "been garbage collected"); - } - x = orgcd->structobj; - Py_INCREF(x); - return x; -} - -static int _my_PyObject_GetContiguousBuffer(PyObject *x, Py_buffer *view, - int writable_only) -{ -#if PY_MAJOR_VERSION < 3 - /* Some objects only support the buffer interface and CPython doesn't - translate it into the memoryview interface, mess. Hack a very - minimal content for 'view'. Don't care if the other fields are - uninitialized: we only call PyBuffer_Release(), which only reads - 'view->obj'. */ - PyBufferProcs *pb = x->ob_type->tp_as_buffer; - if (pb && !pb->bf_releasebuffer) { - /* we used to try all three in some vaguely sensible order, - i.e. first the write. But trying to call the write on a - read-only buffer fails with TypeError. So we use a less- - sensible order now. See test_from_buffer_more_cases. - - If 'writable_only', we only try bf_getwritebuffer. - */ - readbufferproc proc = NULL; - if (!writable_only) { - proc = (readbufferproc)pb->bf_getreadbuffer; - if (!proc) - proc = (readbufferproc)pb->bf_getcharbuffer; - } - if (!proc) - proc = (readbufferproc)pb->bf_getwritebuffer; - - if (proc && pb->bf_getsegcount) { - if ((*pb->bf_getsegcount)(x, NULL) != 1) { - PyErr_SetString(PyExc_TypeError, - "expected a single-segment buffer object"); - return -1; - } - view->len = (*proc)(x, 0, &view->buf); - if (view->len < 0) - return -1; - view->obj = x; - Py_INCREF(x); - return 0; - } - } -#endif - - if (PyObject_GetBuffer(x, view, writable_only ? PyBUF_WRITABLE - : PyBUF_SIMPLE) < 0) - return -1; - - if (!PyBuffer_IsContiguous(view, 'A')) { - PyBuffer_Release(view); - PyErr_SetString(PyExc_TypeError, "contiguous buffer expected"); - return -1; - } - return 0; -} - + cd->head.c_type = ct_voidp; + cd->head.c_data = (char *)cd; + cd->head.c_weakreflist = NULL; + Py_INCREF(x); + cd->structobj = x; + PyObject_GC_Track(cd); + return (PyObject *)cd; +} + +static PyObject *b_newp_handle(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + PyObject *x; + if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x)) + return NULL; + + if (!(ct->ct_flags & CT_IS_VOID_PTR)) { + PyErr_Format(PyExc_TypeError, "needs 'void *', got '%s'", ct->ct_name); + return NULL; + } + + return newp_handle(ct, x); +} + +static PyObject *b_from_handle(PyObject *self, PyObject *arg) +{ + CTypeDescrObject *ct; + CDataObject_own_structptr *orgcd; + PyObject *x; + if (!CData_Check(arg)) { + PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); + return NULL; + } + ct = ((CDataObject *)arg)->c_type; + if (!(ct->ct_flags & CT_IS_VOIDCHAR_PTR)) { + PyErr_Format(PyExc_TypeError, + "expected a 'cdata' object with a 'void *' out of " + "new_handle(), got '%s'", ct->ct_name); + return NULL; + } + orgcd = (CDataObject_own_structptr *)((CDataObject *)arg)->c_data; + if (!orgcd) { + PyErr_SetString(PyExc_RuntimeError, + "cannot use from_handle() on NULL pointer"); + return NULL; + } + if (Py_REFCNT(orgcd) <= 0 || Py_TYPE(orgcd) != &CDataOwningGC_Type) { + Py_FatalError("ffi.from_handle() detected that the address passed " + "points to garbage. If it is really the result of " + "ffi.new_handle(), then the Python object has already " + "been garbage collected"); + } + x = orgcd->structobj; + Py_INCREF(x); + return x; +} + +static int _my_PyObject_GetContiguousBuffer(PyObject *x, Py_buffer *view, + int writable_only) +{ +#if PY_MAJOR_VERSION < 3 + /* Some objects only support the buffer interface and CPython doesn't + translate it into the memoryview interface, mess. Hack a very + minimal content for 'view'. Don't care if the other fields are + uninitialized: we only call PyBuffer_Release(), which only reads + 'view->obj'. */ + PyBufferProcs *pb = x->ob_type->tp_as_buffer; + if (pb && !pb->bf_releasebuffer) { + /* we used to try all three in some vaguely sensible order, + i.e. first the write. But trying to call the write on a + read-only buffer fails with TypeError. So we use a less- + sensible order now. See test_from_buffer_more_cases. + + If 'writable_only', we only try bf_getwritebuffer. + */ + readbufferproc proc = NULL; + if (!writable_only) { + proc = (readbufferproc)pb->bf_getreadbuffer; + if (!proc) + proc = (readbufferproc)pb->bf_getcharbuffer; + } + if (!proc) + proc = (readbufferproc)pb->bf_getwritebuffer; + + if (proc && pb->bf_getsegcount) { + if ((*pb->bf_getsegcount)(x, NULL) != 1) { + PyErr_SetString(PyExc_TypeError, + "expected a single-segment buffer object"); + return -1; + } + view->len = (*proc)(x, 0, &view->buf); + if (view->len < 0) + return -1; + view->obj = x; + Py_INCREF(x); + return 0; + } + } +#endif + + if (PyObject_GetBuffer(x, view, writable_only ? PyBUF_WRITABLE + : PyBUF_SIMPLE) < 0) + return -1; + + if (!PyBuffer_IsContiguous(view, 'A')) { + PyBuffer_Release(view); + PyErr_SetString(PyExc_TypeError, "contiguous buffer expected"); + return -1; + } + return 0; +} + static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x, int require_writable) -{ +{ CDataObject *cd; Py_buffer *view; Py_ssize_t arraylength, minimumlength = 0; - + if (!(ct->ct_flags & (CT_ARRAY | CT_POINTER))) { PyErr_Format(PyExc_TypeError, "expected a pointer or array ctype, got '%s'", ct->ct_name); return NULL; - } - + } + /* PyPy 5.7 can obtain buffers for string (python 2) or bytes (python 3). from_buffer(u"foo") is disallowed. */ if (PyUnicode_Check(x)) { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_TypeError, "from_buffer() cannot return the address " "of a unicode object"); - return NULL; - } - - view = PyObject_Malloc(sizeof(Py_buffer)); - if (view == NULL) { - PyErr_NoMemory(); - return NULL; - } + return NULL; + } + + view = PyObject_Malloc(sizeof(Py_buffer)); + if (view == NULL) { + PyErr_NoMemory(); + return NULL; + } if (_my_PyObject_GetContiguousBuffer(x, view, require_writable) < 0) - goto error1; - + goto error1; + if (ct->ct_flags & CT_POINTER) { arraylength = view->len; /* number of bytes, not used so far */ @@ -7264,125 +7264,125 @@ static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x, cd = (CDataObject *)PyObject_GC_New(CDataObject_frombuf, &CDataFromBuf_Type); - if (cd == NULL) - goto error2; - - Py_INCREF(ct); - cd->c_type = ct; - cd->c_data = view->buf; - cd->c_weakreflist = NULL; + if (cd == NULL) + goto error2; + + Py_INCREF(ct); + cd->c_type = ct; + cd->c_data = view->buf; + cd->c_weakreflist = NULL; ((CDataObject_frombuf *)cd)->length = arraylength; ((CDataObject_frombuf *)cd)->bufferview = view; - PyObject_GC_Track(cd); - return (PyObject *)cd; - - error2: - PyBuffer_Release(view); - error1: - PyObject_Free(view); - return NULL; -} - -static PyObject *b_from_buffer(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *x; + PyObject_GC_Track(cd); + return (PyObject *)cd; + + error2: + PyBuffer_Release(view); + error1: + PyObject_Free(view); + return NULL; +} + +static PyObject *b_from_buffer(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + PyObject *x; int require_writable = 0; - + if (!PyArg_ParseTuple(args, "O!O|i", &CTypeDescr_Type, &ct, &x, &require_writable)) - return NULL; - + return NULL; + return direct_from_buffer(ct, x, require_writable); -} - -static int _fetch_as_buffer(PyObject *x, Py_buffer *view, int writable_only) -{ - if (CData_Check(x)) { - CTypeDescrObject *ct = ((CDataObject *)x)->c_type; - if (!(ct->ct_flags & (CT_POINTER|CT_ARRAY))) { - PyErr_Format(PyExc_TypeError, - "expected a pointer or array ctype, got '%s'", - ct->ct_name); - return -1; - } - view->buf = ((CDataObject *)x)->c_data; - view->obj = NULL; - return 0; - } - else { - return _my_PyObject_GetContiguousBuffer(x, view, writable_only); - } -} - -static PyObject *b_memmove(PyObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *dest_obj, *src_obj; - Py_buffer dest_view, src_view; - Py_ssize_t n; - static char *keywords[] = {"dest", "src", "n", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOn", keywords, - &dest_obj, &src_obj, &n)) - return NULL; - if (n < 0) { - PyErr_SetString(PyExc_ValueError, "negative size"); - return NULL; - } - - if (_fetch_as_buffer(src_obj, &src_view, 0) < 0) { - return NULL; - } - if (_fetch_as_buffer(dest_obj, &dest_view, 1) < 0) { - PyBuffer_Release(&src_view); - return NULL; - } - - memmove(dest_view.buf, src_view.buf, n); - - PyBuffer_Release(&dest_view); - PyBuffer_Release(&src_view); - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *b__get_types(PyObject *self, PyObject *noarg) -{ - return PyTuple_Pack(2, (PyObject *)&CData_Type, - (PyObject *)&CTypeDescr_Type); -} - -/* forward, in commontypes.c */ -static PyObject *b__get_common_types(PyObject *self, PyObject *arg); - -static PyObject *b_gcp(PyObject *self, PyObject *args, PyObject *kwds) -{ - CDataObject *cd; - CDataObject *origobj; - PyObject *destructor; +} + +static int _fetch_as_buffer(PyObject *x, Py_buffer *view, int writable_only) +{ + if (CData_Check(x)) { + CTypeDescrObject *ct = ((CDataObject *)x)->c_type; + if (!(ct->ct_flags & (CT_POINTER|CT_ARRAY))) { + PyErr_Format(PyExc_TypeError, + "expected a pointer or array ctype, got '%s'", + ct->ct_name); + return -1; + } + view->buf = ((CDataObject *)x)->c_data; + view->obj = NULL; + return 0; + } + else { + return _my_PyObject_GetContiguousBuffer(x, view, writable_only); + } +} + +static PyObject *b_memmove(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *dest_obj, *src_obj; + Py_buffer dest_view, src_view; + Py_ssize_t n; + static char *keywords[] = {"dest", "src", "n", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOn", keywords, + &dest_obj, &src_obj, &n)) + return NULL; + if (n < 0) { + PyErr_SetString(PyExc_ValueError, "negative size"); + return NULL; + } + + if (_fetch_as_buffer(src_obj, &src_view, 0) < 0) { + return NULL; + } + if (_fetch_as_buffer(dest_obj, &dest_view, 1) < 0) { + PyBuffer_Release(&src_view); + return NULL; + } + + memmove(dest_view.buf, src_view.buf, n); + + PyBuffer_Release(&dest_view); + PyBuffer_Release(&src_view); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *b__get_types(PyObject *self, PyObject *noarg) +{ + return PyTuple_Pack(2, (PyObject *)&CData_Type, + (PyObject *)&CTypeDescr_Type); +} + +/* forward, in commontypes.c */ +static PyObject *b__get_common_types(PyObject *self, PyObject *arg); + +static PyObject *b_gcp(PyObject *self, PyObject *args, PyObject *kwds) +{ + CDataObject *cd; + CDataObject *origobj; + PyObject *destructor; Py_ssize_t ignored; /* for pypy */ static char *keywords[] = {"cdata", "destructor", "size", NULL}; - + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|n:gc", keywords, &CData_Type, &origobj, &destructor, &ignored)) - return NULL; - - if (destructor == Py_None) { - if (!PyObject_TypeCheck(origobj, &CDataGCP_Type)) { - PyErr_SetString(PyExc_TypeError, - "Can remove destructor only on a object " - "previously returned by ffi.gc()"); - return NULL; - } - Py_CLEAR(((CDataObject_gcp *)origobj)->destructor); - Py_RETURN_NONE; - } - - cd = allocate_gcp_object(origobj, origobj->c_type, destructor); - return (PyObject *)cd; -} - + return NULL; + + if (destructor == Py_None) { + if (!PyObject_TypeCheck(origobj, &CDataGCP_Type)) { + PyErr_SetString(PyExc_TypeError, + "Can remove destructor only on a object " + "previously returned by ffi.gc()"); + return NULL; + } + Py_CLEAR(((CDataObject_gcp *)origobj)->destructor); + Py_RETURN_NONE; + } + + cd = allocate_gcp_object(origobj, origobj->c_type, destructor); + return (PyObject *)cd; +} + static PyObject *b_release(PyObject *self, PyObject *arg) { if (!CData_Check(arg)) { @@ -7392,180 +7392,180 @@ static PyObject *b_release(PyObject *self, PyObject *arg) return cdata_exit(arg, NULL); } -/************************************************************/ - -static char _testfunc0(char a, char b) -{ - return a + b; -} -static long _testfunc1(int a, long b) -{ - return (long)a + b; -} -static PY_LONG_LONG _testfunc2(PY_LONG_LONG a, PY_LONG_LONG b) -{ - return a + b; -} -static double _testfunc3(float a, double b) -{ - return a + b; -} -static float _testfunc4(float a, double b) -{ - return (float)(a + b); -} -static void _testfunc5(void) -{ - errno = errno + 15; -} -static int *_testfunc6(int *x) -{ - static int y; - y = *x - 1000; - return &y; -} -struct _testfunc7_s { unsigned char a1; short a2; }; -static short _testfunc7(struct _testfunc7_s inlined) -{ - return inlined.a1 + inlined.a2; -} -static int _testfunc9(int num, ...) -{ - va_list vargs; - int i, total = 0; - va_start(vargs, num); - for (i=0; i<num; i++) { - int value = va_arg(vargs, int); - if (value == 0) - value = -66666666; - total += value; - } - va_end(vargs); - return total; -} - -static struct _testfunc7_s _testfunc10(int n) -{ - struct _testfunc7_s result; - result.a1 = n; - result.a2 = n * n; - return result; -} - -struct _testfunc11_s { int a1, a2; }; -static struct _testfunc11_s _testfunc11(int n) -{ - struct _testfunc11_s result; - result.a1 = n; - result.a2 = n * n; - return result; -} - -struct _testfunc12_s { double a1; }; -static struct _testfunc12_s _testfunc12(int n) -{ - struct _testfunc12_s result; - result.a1 = n; - return result; -} - -struct _testfunc13_s { int a1, a2, a3; }; -static struct _testfunc13_s _testfunc13(int n) -{ - struct _testfunc13_s result; - result.a1 = n; - result.a2 = n * n; - result.a3 = n * n * n; - return result; -} - -struct _testfunc14_s { float a1; }; -static struct _testfunc14_s _testfunc14(int n) -{ - struct _testfunc14_s result; - result.a1 = (float)n; - return result; -} - -struct _testfunc15_s { float a1; int a2; }; -static struct _testfunc15_s _testfunc15(int n) -{ - struct _testfunc15_s result; - result.a1 = (float)n; - result.a2 = n * n; - return result; -} - -struct _testfunc16_s { float a1, a2; }; -static struct _testfunc16_s _testfunc16(int n) -{ - struct _testfunc16_s result; - result.a1 = (float)n; - result.a2 = -(float)n; - return result; -} - -struct _testfunc17_s { int a1; float a2; }; -static struct _testfunc17_s _testfunc17(int n) -{ - struct _testfunc17_s result; - result.a1 = n; - result.a2 = (float)n * (float)n; - return result; -} - -static int _testfunc18(struct _testfunc17_s *ptr) -{ - return ptr->a1 + (int)ptr->a2; -} - -static long double _testfunc19(long double x, int count) -{ - int i; - for (i=0; i<count; i++) { - x = 4*x - x*x; - } - return x; -} - -static short _testfunc20(struct _testfunc7_s *ptr) -{ - return ptr->a1 + ptr->a2; -} - -struct _testfunc21_s { int a, b, c, d, e, f, g, h, i, j; }; -static int _testfunc21(struct _testfunc21_s inlined) -{ - return ((inlined.a << 0) + - (inlined.b << 1) + - (inlined.c << 2) + - (inlined.d << 3) + - (inlined.e << 4) + - (inlined.f << 5) + - (inlined.g << 6) + - (inlined.h << 7) + - (inlined.i << 8) + - (inlined.j << 9)); -} - -struct _testfunc22_s { int a[10]; }; -static struct _testfunc22_s _testfunc22(struct _testfunc22_s s1, - struct _testfunc22_s s2) -{ - struct _testfunc22_s result; - int i; - for (i=0; i<10; i++) - result.a[i] = s1.a[i] - s2.a[i]; - return result; -} - -static int _testfunc23(char *p) -{ - if (p) - return 1000 * p[0]; - return -42; -} - +/************************************************************/ + +static char _testfunc0(char a, char b) +{ + return a + b; +} +static long _testfunc1(int a, long b) +{ + return (long)a + b; +} +static PY_LONG_LONG _testfunc2(PY_LONG_LONG a, PY_LONG_LONG b) +{ + return a + b; +} +static double _testfunc3(float a, double b) +{ + return a + b; +} +static float _testfunc4(float a, double b) +{ + return (float)(a + b); +} +static void _testfunc5(void) +{ + errno = errno + 15; +} +static int *_testfunc6(int *x) +{ + static int y; + y = *x - 1000; + return &y; +} +struct _testfunc7_s { unsigned char a1; short a2; }; +static short _testfunc7(struct _testfunc7_s inlined) +{ + return inlined.a1 + inlined.a2; +} +static int _testfunc9(int num, ...) +{ + va_list vargs; + int i, total = 0; + va_start(vargs, num); + for (i=0; i<num; i++) { + int value = va_arg(vargs, int); + if (value == 0) + value = -66666666; + total += value; + } + va_end(vargs); + return total; +} + +static struct _testfunc7_s _testfunc10(int n) +{ + struct _testfunc7_s result; + result.a1 = n; + result.a2 = n * n; + return result; +} + +struct _testfunc11_s { int a1, a2; }; +static struct _testfunc11_s _testfunc11(int n) +{ + struct _testfunc11_s result; + result.a1 = n; + result.a2 = n * n; + return result; +} + +struct _testfunc12_s { double a1; }; +static struct _testfunc12_s _testfunc12(int n) +{ + struct _testfunc12_s result; + result.a1 = n; + return result; +} + +struct _testfunc13_s { int a1, a2, a3; }; +static struct _testfunc13_s _testfunc13(int n) +{ + struct _testfunc13_s result; + result.a1 = n; + result.a2 = n * n; + result.a3 = n * n * n; + return result; +} + +struct _testfunc14_s { float a1; }; +static struct _testfunc14_s _testfunc14(int n) +{ + struct _testfunc14_s result; + result.a1 = (float)n; + return result; +} + +struct _testfunc15_s { float a1; int a2; }; +static struct _testfunc15_s _testfunc15(int n) +{ + struct _testfunc15_s result; + result.a1 = (float)n; + result.a2 = n * n; + return result; +} + +struct _testfunc16_s { float a1, a2; }; +static struct _testfunc16_s _testfunc16(int n) +{ + struct _testfunc16_s result; + result.a1 = (float)n; + result.a2 = -(float)n; + return result; +} + +struct _testfunc17_s { int a1; float a2; }; +static struct _testfunc17_s _testfunc17(int n) +{ + struct _testfunc17_s result; + result.a1 = n; + result.a2 = (float)n * (float)n; + return result; +} + +static int _testfunc18(struct _testfunc17_s *ptr) +{ + return ptr->a1 + (int)ptr->a2; +} + +static long double _testfunc19(long double x, int count) +{ + int i; + for (i=0; i<count; i++) { + x = 4*x - x*x; + } + return x; +} + +static short _testfunc20(struct _testfunc7_s *ptr) +{ + return ptr->a1 + ptr->a2; +} + +struct _testfunc21_s { int a, b, c, d, e, f, g, h, i, j; }; +static int _testfunc21(struct _testfunc21_s inlined) +{ + return ((inlined.a << 0) + + (inlined.b << 1) + + (inlined.c << 2) + + (inlined.d << 3) + + (inlined.e << 4) + + (inlined.f << 5) + + (inlined.g << 6) + + (inlined.h << 7) + + (inlined.i << 8) + + (inlined.j << 9)); +} + +struct _testfunc22_s { int a[10]; }; +static struct _testfunc22_s _testfunc22(struct _testfunc22_s s1, + struct _testfunc22_s s2) +{ + struct _testfunc22_s result; + int i; + for (i=0; i<10; i++) + result.a[i] = s1.a[i] - s2.a[i]; + return result; +} + +static int _testfunc23(char *p) +{ + if (p) + return 1000 * p[0]; + return -42; +} + #if 0 /* libffi doesn't properly support complexes currently */ /* also, MSVC might not support _Complex... */ /* if this is enabled one day, remember to also add _Complex @@ -7580,268 +7580,268 @@ static double _Complex _testfunc25(double a, double b) } #endif -static PyObject *b__testfunc(PyObject *self, PyObject *args) -{ - /* for testing only */ - int i; - void *f; - if (!PyArg_ParseTuple(args, "i:_testfunc", &i)) - return NULL; - switch (i) { - case 0: f = &_testfunc0; break; - case 1: f = &_testfunc1; break; - case 2: f = &_testfunc2; break; - case 3: f = &_testfunc3; break; - case 4: f = &_testfunc4; break; - case 5: f = &_testfunc5; break; - case 6: f = &_testfunc6; break; - case 7: f = &_testfunc7; break; - case 8: f = stderr; break; - case 9: f = &_testfunc9; break; - case 10: f = &_testfunc10; break; - case 11: f = &_testfunc11; break; - case 12: f = &_testfunc12; break; - case 13: f = &_testfunc13; break; - case 14: f = &_testfunc14; break; - case 15: f = &_testfunc15; break; - case 16: f = &_testfunc16; break; - case 17: f = &_testfunc17; break; - case 18: f = &_testfunc18; break; - case 19: f = &_testfunc19; break; - case 20: f = &_testfunc20; break; - case 21: f = &_testfunc21; break; - case 22: f = &_testfunc22; break; - case 23: f = &_testfunc23; break; +static PyObject *b__testfunc(PyObject *self, PyObject *args) +{ + /* for testing only */ + int i; + void *f; + if (!PyArg_ParseTuple(args, "i:_testfunc", &i)) + return NULL; + switch (i) { + case 0: f = &_testfunc0; break; + case 1: f = &_testfunc1; break; + case 2: f = &_testfunc2; break; + case 3: f = &_testfunc3; break; + case 4: f = &_testfunc4; break; + case 5: f = &_testfunc5; break; + case 6: f = &_testfunc6; break; + case 7: f = &_testfunc7; break; + case 8: f = stderr; break; + case 9: f = &_testfunc9; break; + case 10: f = &_testfunc10; break; + case 11: f = &_testfunc11; break; + case 12: f = &_testfunc12; break; + case 13: f = &_testfunc13; break; + case 14: f = &_testfunc14; break; + case 15: f = &_testfunc15; break; + case 16: f = &_testfunc16; break; + case 17: f = &_testfunc17; break; + case 18: f = &_testfunc18; break; + case 19: f = &_testfunc19; break; + case 20: f = &_testfunc20; break; + case 21: f = &_testfunc21; break; + case 22: f = &_testfunc22; break; + case 23: f = &_testfunc23; break; #if 0 case 24: f = &_testfunc24; break; case 25: f = &_testfunc25; break; #endif - default: - PyErr_SetNone(PyExc_ValueError); - return NULL; - } - return PyLong_FromVoidPtr(f); -} - -#if PY_MAJOR_VERSION < 3 -static Py_ssize_t _test_segcountproc(PyObject *o, Py_ssize_t *ignored) -{ - return 1; -} -static Py_ssize_t _test_getreadbuf(PyObject *o, Py_ssize_t i, void **r) -{ - static char buf[] = "RDB"; - *r = buf; - return 3; -} -static Py_ssize_t _test_getwritebuf(PyObject *o, Py_ssize_t i, void **r) -{ - static char buf[] = "WRB"; - *r = buf; - return 3; -} -static Py_ssize_t _test_getcharbuf(PyObject *o, Py_ssize_t i, char **r) -{ - static char buf[] = "CHB"; - *r = buf; - return 3; -} -#endif -static int _test_getbuf(PyObject *self, Py_buffer *view, int flags) -{ - static char buf[] = "GTB"; - return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/0, flags); -} -static int _test_getbuf_ro(PyObject *self, Py_buffer *view, int flags) -{ - static char buf[] = "ROB"; - return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/1, flags); -} - - -static PyObject *b__testbuff(PyObject *self, PyObject *args) -{ - /* for testing only */ - int methods; - PyTypeObject *obj; - if (!PyArg_ParseTuple(args, "O!i|_testbuff", &PyType_Type, &obj, &methods)) - return NULL; - - assert(obj->tp_as_buffer != NULL); - -#if PY_MAJOR_VERSION < 3 - obj->tp_as_buffer->bf_getsegcount = &_test_segcountproc; - obj->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER; - obj->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; - if (methods & 1) obj->tp_as_buffer->bf_getreadbuffer = &_test_getreadbuf; - if (methods & 2) obj->tp_as_buffer->bf_getwritebuffer = &_test_getwritebuf; - if (methods & 4) obj->tp_as_buffer->bf_getcharbuffer = &_test_getcharbuf; -#endif - if (methods & 8) obj->tp_as_buffer->bf_getbuffer = &_test_getbuf; - if (methods & 16) obj->tp_as_buffer->bf_getbuffer = &_test_getbuf_ro; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *b_init_cffi_1_0_external_module(PyObject *, PyObject *); -/* forward, see cffi1_module.c */ - - -static PyMethodDef FFIBackendMethods[] = { - {"load_library", b_load_library, METH_VARARGS}, - {"new_primitive_type", b_new_primitive_type, METH_VARARGS}, - {"new_pointer_type", b_new_pointer_type, METH_VARARGS}, - {"new_array_type", b_new_array_type, METH_VARARGS}, - {"new_void_type", b_new_void_type, METH_NOARGS}, - {"new_struct_type", b_new_struct_type, METH_VARARGS}, - {"new_union_type", b_new_union_type, METH_VARARGS}, - {"complete_struct_or_union", b_complete_struct_or_union, METH_VARARGS}, - {"new_function_type", b_new_function_type, METH_VARARGS}, - {"new_enum_type", b_new_enum_type, METH_VARARGS}, - {"newp", b_newp, METH_VARARGS}, - {"cast", b_cast, METH_VARARGS}, - {"callback", b_callback, METH_VARARGS}, - {"alignof", b_alignof, METH_O}, - {"sizeof", b_sizeof, METH_O}, - {"typeof", b_typeof, METH_O}, - {"typeoffsetof", b_typeoffsetof, METH_VARARGS}, - {"rawaddressof", b_rawaddressof, METH_VARARGS}, - {"getcname", b_getcname, METH_VARARGS}, - {"string", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS}, - {"unpack", (PyCFunction)b_unpack, METH_VARARGS | METH_KEYWORDS}, - {"get_errno", b_get_errno, METH_NOARGS}, - {"set_errno", b_set_errno, METH_O}, - {"newp_handle", b_newp_handle, METH_VARARGS}, - {"from_handle", b_from_handle, METH_O}, - {"from_buffer", b_from_buffer, METH_VARARGS}, - {"memmove", (PyCFunction)b_memmove, METH_VARARGS | METH_KEYWORDS}, - {"gcp", (PyCFunction)b_gcp, METH_VARARGS | METH_KEYWORDS}, + default: + PyErr_SetNone(PyExc_ValueError); + return NULL; + } + return PyLong_FromVoidPtr(f); +} + +#if PY_MAJOR_VERSION < 3 +static Py_ssize_t _test_segcountproc(PyObject *o, Py_ssize_t *ignored) +{ + return 1; +} +static Py_ssize_t _test_getreadbuf(PyObject *o, Py_ssize_t i, void **r) +{ + static char buf[] = "RDB"; + *r = buf; + return 3; +} +static Py_ssize_t _test_getwritebuf(PyObject *o, Py_ssize_t i, void **r) +{ + static char buf[] = "WRB"; + *r = buf; + return 3; +} +static Py_ssize_t _test_getcharbuf(PyObject *o, Py_ssize_t i, char **r) +{ + static char buf[] = "CHB"; + *r = buf; + return 3; +} +#endif +static int _test_getbuf(PyObject *self, Py_buffer *view, int flags) +{ + static char buf[] = "GTB"; + return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/0, flags); +} +static int _test_getbuf_ro(PyObject *self, Py_buffer *view, int flags) +{ + static char buf[] = "ROB"; + return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/1, flags); +} + + +static PyObject *b__testbuff(PyObject *self, PyObject *args) +{ + /* for testing only */ + int methods; + PyTypeObject *obj; + if (!PyArg_ParseTuple(args, "O!i|_testbuff", &PyType_Type, &obj, &methods)) + return NULL; + + assert(obj->tp_as_buffer != NULL); + +#if PY_MAJOR_VERSION < 3 + obj->tp_as_buffer->bf_getsegcount = &_test_segcountproc; + obj->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER; + obj->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; + if (methods & 1) obj->tp_as_buffer->bf_getreadbuffer = &_test_getreadbuf; + if (methods & 2) obj->tp_as_buffer->bf_getwritebuffer = &_test_getwritebuf; + if (methods & 4) obj->tp_as_buffer->bf_getcharbuffer = &_test_getcharbuf; +#endif + if (methods & 8) obj->tp_as_buffer->bf_getbuffer = &_test_getbuf; + if (methods & 16) obj->tp_as_buffer->bf_getbuffer = &_test_getbuf_ro; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *b_init_cffi_1_0_external_module(PyObject *, PyObject *); +/* forward, see cffi1_module.c */ + + +static PyMethodDef FFIBackendMethods[] = { + {"load_library", b_load_library, METH_VARARGS}, + {"new_primitive_type", b_new_primitive_type, METH_VARARGS}, + {"new_pointer_type", b_new_pointer_type, METH_VARARGS}, + {"new_array_type", b_new_array_type, METH_VARARGS}, + {"new_void_type", b_new_void_type, METH_NOARGS}, + {"new_struct_type", b_new_struct_type, METH_VARARGS}, + {"new_union_type", b_new_union_type, METH_VARARGS}, + {"complete_struct_or_union", b_complete_struct_or_union, METH_VARARGS}, + {"new_function_type", b_new_function_type, METH_VARARGS}, + {"new_enum_type", b_new_enum_type, METH_VARARGS}, + {"newp", b_newp, METH_VARARGS}, + {"cast", b_cast, METH_VARARGS}, + {"callback", b_callback, METH_VARARGS}, + {"alignof", b_alignof, METH_O}, + {"sizeof", b_sizeof, METH_O}, + {"typeof", b_typeof, METH_O}, + {"typeoffsetof", b_typeoffsetof, METH_VARARGS}, + {"rawaddressof", b_rawaddressof, METH_VARARGS}, + {"getcname", b_getcname, METH_VARARGS}, + {"string", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS}, + {"unpack", (PyCFunction)b_unpack, METH_VARARGS | METH_KEYWORDS}, + {"get_errno", b_get_errno, METH_NOARGS}, + {"set_errno", b_set_errno, METH_O}, + {"newp_handle", b_newp_handle, METH_VARARGS}, + {"from_handle", b_from_handle, METH_O}, + {"from_buffer", b_from_buffer, METH_VARARGS}, + {"memmove", (PyCFunction)b_memmove, METH_VARARGS | METH_KEYWORDS}, + {"gcp", (PyCFunction)b_gcp, METH_VARARGS | METH_KEYWORDS}, {"release", b_release, METH_O}, -#ifdef MS_WIN32 - {"getwinerror", (PyCFunction)b_getwinerror, METH_VARARGS | METH_KEYWORDS}, -#endif - {"_get_types", b__get_types, METH_NOARGS}, - {"_get_common_types", b__get_common_types, METH_O}, - {"_testfunc", b__testfunc, METH_VARARGS}, - {"_testbuff", b__testbuff, METH_VARARGS}, - {"_init_cffi_1_0_external_module", b_init_cffi_1_0_external_module, METH_O}, - {NULL, NULL} /* Sentinel */ -}; - -/************************************************************/ -/* Functions used by '_cffi_N.so', the generated modules */ - -#define _cffi_to_c_SIGNED_FN(RETURNTYPE, SIZE) \ -static RETURNTYPE _cffi_to_c_i##SIZE(PyObject *obj) { \ - PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); \ - if ((tmp > (PY_LONG_LONG)((1ULL<<(SIZE-1)) - 1)) || \ - (tmp < (PY_LONG_LONG)(0ULL-(1ULL<<(SIZE-1))))) \ - if (!PyErr_Occurred()) \ - return (RETURNTYPE)_convert_overflow(obj, #SIZE "-bit int"); \ - return (RETURNTYPE)tmp; \ -} - -#define _cffi_to_c_UNSIGNED_FN(RETURNTYPE, SIZE) \ -static RETURNTYPE _cffi_to_c_u##SIZE(PyObject *obj) { \ - unsigned PY_LONG_LONG tmp = _my_PyLong_AsUnsignedLongLong(obj, 1); \ - if (tmp > ~(((unsigned PY_LONG_LONG)-2) << (SIZE-1))) \ - if (!PyErr_Occurred()) \ - return (RETURNTYPE)_convert_overflow(obj, \ - #SIZE "-bit unsigned int"); \ - return (RETURNTYPE)tmp; \ -} - -_cffi_to_c_SIGNED_FN(int, 8) -_cffi_to_c_SIGNED_FN(int, 16) -_cffi_to_c_SIGNED_FN(int, 32) -_cffi_to_c_SIGNED_FN(PY_LONG_LONG, 64) -_cffi_to_c_UNSIGNED_FN(int, 8) -_cffi_to_c_UNSIGNED_FN(int, 16) -_cffi_to_c_UNSIGNED_FN(unsigned int, 32) -_cffi_to_c_UNSIGNED_FN(unsigned PY_LONG_LONG, 64) - -static PyObject *_cffi_from_c_pointer(char *ptr, CTypeDescrObject *ct) -{ - return convert_to_object((char *)&ptr, ct); -} - -static char *_cffi_to_c_pointer(PyObject *obj, CTypeDescrObject *ct) -{ - char *result; - if (convert_from_object((char *)&result, ct, obj) < 0) { - if ((ct->ct_flags & CT_POINTER) && - (ct->ct_itemdescr->ct_flags & CT_IS_FILE) && - PyFile_Check(obj)) { - PyErr_Clear(); - return (char *)PyFile_AsFile(obj); - } - return NULL; - } - return result; -} - -static long double _cffi_to_c_long_double(PyObject *obj) -{ - if (CData_Check(obj) && - (((CDataObject *)obj)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { - char *data = ((CDataObject *)obj)->c_data; - /*READ(data, sizeof(long double))*/ - return read_raw_longdouble_data(data); - } - else - return PyFloat_AsDouble(obj); -} - -static _Bool _cffi_to_c__Bool(PyObject *obj) -{ - PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); - if (tmp == 0) - return 0; - else if (tmp == 1) - return 1; - else if (PyErr_Occurred()) - return (_Bool)-1; - else - return (_Bool)_convert_overflow(obj, "_Bool"); -} - -static PyObject *_cffi_get_struct_layout(Py_ssize_t nums[]) -{ - PyObject *result; - int count = 0; - while (nums[count] >= 0) - count++; - - result = PyList_New(count); - if (result == NULL) - return NULL; - - while (--count >= 0) { - PyObject *o = PyInt_FromSsize_t(nums[count]); - if (o == NULL) { - Py_DECREF(result); - return NULL; - } - PyList_SET_ITEM(result, count, o); - } - return result; -} - -static PyObject *_cffi_from_c_char(char x) { - return PyBytes_FromStringAndSize(&x, 1); -} - +#ifdef MS_WIN32 + {"getwinerror", (PyCFunction)b_getwinerror, METH_VARARGS | METH_KEYWORDS}, +#endif + {"_get_types", b__get_types, METH_NOARGS}, + {"_get_common_types", b__get_common_types, METH_O}, + {"_testfunc", b__testfunc, METH_VARARGS}, + {"_testbuff", b__testbuff, METH_VARARGS}, + {"_init_cffi_1_0_external_module", b_init_cffi_1_0_external_module, METH_O}, + {NULL, NULL} /* Sentinel */ +}; + +/************************************************************/ +/* Functions used by '_cffi_N.so', the generated modules */ + +#define _cffi_to_c_SIGNED_FN(RETURNTYPE, SIZE) \ +static RETURNTYPE _cffi_to_c_i##SIZE(PyObject *obj) { \ + PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); \ + if ((tmp > (PY_LONG_LONG)((1ULL<<(SIZE-1)) - 1)) || \ + (tmp < (PY_LONG_LONG)(0ULL-(1ULL<<(SIZE-1))))) \ + if (!PyErr_Occurred()) \ + return (RETURNTYPE)_convert_overflow(obj, #SIZE "-bit int"); \ + return (RETURNTYPE)tmp; \ +} + +#define _cffi_to_c_UNSIGNED_FN(RETURNTYPE, SIZE) \ +static RETURNTYPE _cffi_to_c_u##SIZE(PyObject *obj) { \ + unsigned PY_LONG_LONG tmp = _my_PyLong_AsUnsignedLongLong(obj, 1); \ + if (tmp > ~(((unsigned PY_LONG_LONG)-2) << (SIZE-1))) \ + if (!PyErr_Occurred()) \ + return (RETURNTYPE)_convert_overflow(obj, \ + #SIZE "-bit unsigned int"); \ + return (RETURNTYPE)tmp; \ +} + +_cffi_to_c_SIGNED_FN(int, 8) +_cffi_to_c_SIGNED_FN(int, 16) +_cffi_to_c_SIGNED_FN(int, 32) +_cffi_to_c_SIGNED_FN(PY_LONG_LONG, 64) +_cffi_to_c_UNSIGNED_FN(int, 8) +_cffi_to_c_UNSIGNED_FN(int, 16) +_cffi_to_c_UNSIGNED_FN(unsigned int, 32) +_cffi_to_c_UNSIGNED_FN(unsigned PY_LONG_LONG, 64) + +static PyObject *_cffi_from_c_pointer(char *ptr, CTypeDescrObject *ct) +{ + return convert_to_object((char *)&ptr, ct); +} + +static char *_cffi_to_c_pointer(PyObject *obj, CTypeDescrObject *ct) +{ + char *result; + if (convert_from_object((char *)&result, ct, obj) < 0) { + if ((ct->ct_flags & CT_POINTER) && + (ct->ct_itemdescr->ct_flags & CT_IS_FILE) && + PyFile_Check(obj)) { + PyErr_Clear(); + return (char *)PyFile_AsFile(obj); + } + return NULL; + } + return result; +} + +static long double _cffi_to_c_long_double(PyObject *obj) +{ + if (CData_Check(obj) && + (((CDataObject *)obj)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { + char *data = ((CDataObject *)obj)->c_data; + /*READ(data, sizeof(long double))*/ + return read_raw_longdouble_data(data); + } + else + return PyFloat_AsDouble(obj); +} + +static _Bool _cffi_to_c__Bool(PyObject *obj) +{ + PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); + if (tmp == 0) + return 0; + else if (tmp == 1) + return 1; + else if (PyErr_Occurred()) + return (_Bool)-1; + else + return (_Bool)_convert_overflow(obj, "_Bool"); +} + +static PyObject *_cffi_get_struct_layout(Py_ssize_t nums[]) +{ + PyObject *result; + int count = 0; + while (nums[count] >= 0) + count++; + + result = PyList_New(count); + if (result == NULL) + return NULL; + + while (--count >= 0) { + PyObject *o = PyInt_FromSsize_t(nums[count]); + if (o == NULL) { + Py_DECREF(result); + return NULL; + } + PyList_SET_ITEM(result, count, o); + } + return result; +} + +static PyObject *_cffi_from_c_char(char x) { + return PyBytes_FromStringAndSize(&x, 1); +} + /* backward-compatibility hack: instead of _cffi_to_c_char16_t() and * _cffi_to_c_char32_t(), we have _cffi_to_c_wchar_t() handling whatever * size is wchar_t, and _cffi_to_c_wchar3216_t() handling the opposite. */ -#ifdef HAVE_WCHAR_H +#ifdef HAVE_WCHAR_H typedef wchar_t cffi_wchar_t; #else typedef uint16_t cffi_wchar_t; /* random pick... */ -#endif - +#endif + static cffi_wchar_t _cffi_to_c_wchar_t(PyObject *init) { if (sizeof(cffi_wchar_t) == 2) @@ -7877,91 +7877,91 @@ static PyObject *_cffi_from_c_wchar3216_t(int x) { } } -struct _cffi_externpy_s; /* forward declaration */ -static void cffi_call_python(struct _cffi_externpy_s *, char *args); - -static void *cffi_exports[] = { - NULL, - _cffi_to_c_i8, - _cffi_to_c_u8, - _cffi_to_c_i16, - _cffi_to_c_u16, - _cffi_to_c_i32, - _cffi_to_c_u32, - _cffi_to_c_i64, - _cffi_to_c_u64, - _convert_to_char, - _cffi_from_c_pointer, - _cffi_to_c_pointer, - _cffi_get_struct_layout, - restore_errno, - save_errno, - _cffi_from_c_char, - convert_to_object, - convert_from_object, - convert_struct_to_owning_object, +struct _cffi_externpy_s; /* forward declaration */ +static void cffi_call_python(struct _cffi_externpy_s *, char *args); + +static void *cffi_exports[] = { + NULL, + _cffi_to_c_i8, + _cffi_to_c_u8, + _cffi_to_c_i16, + _cffi_to_c_u16, + _cffi_to_c_i32, + _cffi_to_c_u32, + _cffi_to_c_i64, + _cffi_to_c_u64, + _convert_to_char, + _cffi_from_c_pointer, + _cffi_to_c_pointer, + _cffi_get_struct_layout, + restore_errno, + save_errno, + _cffi_from_c_char, + convert_to_object, + convert_from_object, + convert_struct_to_owning_object, _cffi_to_c_wchar_t, - _cffi_from_c_wchar_t, - _cffi_to_c_long_double, - _cffi_to_c__Bool, - _prepare_pointer_call_argument, - convert_array_from_object, - cffi_call_python, + _cffi_from_c_wchar_t, + _cffi_to_c_long_double, + _cffi_to_c__Bool, + _prepare_pointer_call_argument, + convert_array_from_object, + cffi_call_python, _cffi_to_c_wchar3216_t, _cffi_from_c_wchar3216_t, -}; - -static struct { const char *name; int value; } all_dlopen_flags[] = { - { "RTLD_LAZY", RTLD_LAZY }, - { "RTLD_NOW", RTLD_NOW }, - { "RTLD_GLOBAL", RTLD_GLOBAL }, -#ifdef RTLD_LOCAL - { "RTLD_LOCAL", RTLD_LOCAL }, -#else - { "RTLD_LOCAL", 0 }, -#endif -#ifdef RTLD_NODELETE - { "RTLD_NODELETE", RTLD_NODELETE }, -#endif -#ifdef RTLD_NOLOAD - { "RTLD_NOLOAD", RTLD_NOLOAD }, -#endif -#ifdef RTLD_DEEPBIND - { "RTLD_DEEPBIND", RTLD_DEEPBIND }, -#endif - { NULL, 0 } -}; - - -/************************************************************/ - -#include "cffi1_module.c" - -/************************************************************/ - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef FFIBackendModuleDef = { - PyModuleDef_HEAD_INIT, - "_cffi_backend", - NULL, - -1, - FFIBackendMethods, - NULL, NULL, NULL, NULL -}; -#define INITERROR return NULL - -PyMODINIT_FUNC -PyInit__cffi_backend(void) -#else -#define INITERROR return - -PyMODINIT_FUNC -init_cffi_backend(void) -#endif -{ - PyObject *m, *v; - int i; - static char init_done = 0; +}; + +static struct { const char *name; int value; } all_dlopen_flags[] = { + { "RTLD_LAZY", RTLD_LAZY }, + { "RTLD_NOW", RTLD_NOW }, + { "RTLD_GLOBAL", RTLD_GLOBAL }, +#ifdef RTLD_LOCAL + { "RTLD_LOCAL", RTLD_LOCAL }, +#else + { "RTLD_LOCAL", 0 }, +#endif +#ifdef RTLD_NODELETE + { "RTLD_NODELETE", RTLD_NODELETE }, +#endif +#ifdef RTLD_NOLOAD + { "RTLD_NOLOAD", RTLD_NOLOAD }, +#endif +#ifdef RTLD_DEEPBIND + { "RTLD_DEEPBIND", RTLD_DEEPBIND }, +#endif + { NULL, 0 } +}; + + +/************************************************************/ + +#include "cffi1_module.c" + +/************************************************************/ + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef FFIBackendModuleDef = { + PyModuleDef_HEAD_INIT, + "_cffi_backend", + NULL, + -1, + FFIBackendMethods, + NULL, NULL, NULL, NULL +}; +#define INITERROR return NULL + +PyMODINIT_FUNC +PyInit__cffi_backend(void) +#else +#define INITERROR return + +PyMODINIT_FUNC +init_cffi_backend(void) +#endif +{ + PyObject *m, *v; + int i; + static char init_done = 0; static PyTypeObject *all_types[] = { &dl_type, &CTypeDescr_Type, @@ -7978,31 +7978,31 @@ init_cffi_backend(void) &GlobSupport_Type, NULL }; - - v = PySys_GetObject("version"); - if (v == NULL || !PyText_Check(v) || - strncmp(PyText_AS_UTF8(v), PY_VERSION, 3) != 0) { - PyErr_Format(PyExc_ImportError, - "this module was compiled for Python %c%c%c", - PY_VERSION[0], PY_VERSION[1], PY_VERSION[2]); - INITERROR; - } - -#if PY_MAJOR_VERSION >= 3 - m = PyModule_Create(&FFIBackendModuleDef); -#else - m = Py_InitModule("_cffi_backend", FFIBackendMethods); -#endif - - if (m == NULL) - INITERROR; - - if (unique_cache == NULL) { - unique_cache = PyDict_New(); - if (unique_cache == NULL) - INITERROR; - } - + + v = PySys_GetObject("version"); + if (v == NULL || !PyText_Check(v) || + strncmp(PyText_AS_UTF8(v), PY_VERSION, 3) != 0) { + PyErr_Format(PyExc_ImportError, + "this module was compiled for Python %c%c%c", + PY_VERSION[0], PY_VERSION[1], PY_VERSION[2]); + INITERROR; + } + +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&FFIBackendModuleDef); +#else + m = Py_InitModule("_cffi_backend", FFIBackendMethods); +#endif + + if (m == NULL) + INITERROR; + + if (unique_cache == NULL) { + unique_cache = PyDict_New(); + if (unique_cache == NULL) + INITERROR; + } + /* readify all types and add them to the module */ for (i = 0; all_types[i] != NULL; i++) { PyTypeObject *tp = all_types[i]; @@ -8014,69 +8014,69 @@ init_cffi_backend(void) } if (PyType_Ready(tp) < 0) INITERROR; - + Py_INCREF(tpo); if (PyModule_AddObject(m, tp->tp_name + 14, tpo) < 0) INITERROR; } - if (!init_done) { - v = PyText_FromString("_cffi_backend"); - if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, - "__module__", v) < 0) - INITERROR; - v = PyText_FromString("<cdata>"); - if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, - "__name__", v) < 0) - INITERROR; - init_done = 1; - } - - /* this is for backward compatibility only */ - v = PyCapsule_New((void *)cffi_exports, "cffi", NULL); - if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) - INITERROR; - - v = PyText_FromString(CFFI_VERSION); - if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0) - INITERROR; - - if (PyModule_AddIntConstant(m, "FFI_DEFAULT_ABI", FFI_DEFAULT_ABI) < 0 || -#if defined(MS_WIN32) && !defined(_WIN64) - PyModule_AddIntConstant(m, "FFI_STDCALL", FFI_STDCALL) < 0 || -#endif - PyModule_AddIntConstant(m, "FFI_CDECL", FFI_DEFAULT_ABI) < 0 || - -#ifdef MS_WIN32 -# ifdef _WIN64 - PyModule_AddIntConstant(m, "_WIN", 64) < 0 || /* win64 */ -# else - PyModule_AddIntConstant(m, "_WIN", 32) < 0 || /* win32 */ -# endif -#endif - 0) - INITERROR; - - for (i = 0; all_dlopen_flags[i].name != NULL; i++) { - if (PyModule_AddIntConstant(m, - all_dlopen_flags[i].name, - all_dlopen_flags[i].value) < 0) - INITERROR; - } - - init_cffi_tls(); - if (PyErr_Occurred()) - INITERROR; + if (!init_done) { + v = PyText_FromString("_cffi_backend"); + if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, + "__module__", v) < 0) + INITERROR; + v = PyText_FromString("<cdata>"); + if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, + "__name__", v) < 0) + INITERROR; + init_done = 1; + } + + /* this is for backward compatibility only */ + v = PyCapsule_New((void *)cffi_exports, "cffi", NULL); + if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) + INITERROR; + + v = PyText_FromString(CFFI_VERSION); + if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0) + INITERROR; + + if (PyModule_AddIntConstant(m, "FFI_DEFAULT_ABI", FFI_DEFAULT_ABI) < 0 || +#if defined(MS_WIN32) && !defined(_WIN64) + PyModule_AddIntConstant(m, "FFI_STDCALL", FFI_STDCALL) < 0 || +#endif + PyModule_AddIntConstant(m, "FFI_CDECL", FFI_DEFAULT_ABI) < 0 || + +#ifdef MS_WIN32 +# ifdef _WIN64 + PyModule_AddIntConstant(m, "_WIN", 64) < 0 || /* win64 */ +# else + PyModule_AddIntConstant(m, "_WIN", 32) < 0 || /* win32 */ +# endif +#endif + 0) + INITERROR; + + for (i = 0; all_dlopen_flags[i].name != NULL; i++) { + if (PyModule_AddIntConstant(m, + all_dlopen_flags[i].name, + all_dlopen_flags[i].value) < 0) + INITERROR; + } + + init_cffi_tls(); + if (PyErr_Occurred()) + INITERROR; init_cffi_tls_zombie(); if (PyErr_Occurred()) INITERROR; - - if (init_ffi_lib(m) < 0) - INITERROR; - -#if PY_MAJOR_VERSION >= 3 - if (init_file_emulator() < 0) - INITERROR; - return m; -#endif -} + + if (init_ffi_lib(m) < 0) + INITERROR; + +#if PY_MAJOR_VERSION >= 3 + if (init_file_emulator() < 0) + INITERROR; + return m; +#endif +} diff --git a/contrib/python/cffi/c/call_python.c b/contrib/python/cffi/c/call_python.c index d3d2e17810..de2c5328df 100644 --- a/contrib/python/cffi/c/call_python.c +++ b/contrib/python/cffi/c/call_python.c @@ -1,7 +1,7 @@ #if PY_VERSION_HEX >= 0x03080000 # define HAVE_PYINTERPSTATE_GETDICT #endif - + static PyObject *_current_interp_key(void) { @@ -13,25 +13,25 @@ static PyObject *_current_interp_key(void) #endif } -static PyObject *_get_interpstate_dict(void) -{ - /* Hack around to return a dict that is subinterpreter-local. - Does not return a new reference. Returns NULL in case of - error, but without setting any exception. (If called late - during shutdown, we *can't* set an exception!) - */ - static PyObject *attr_name = NULL; - PyThreadState *tstate; +static PyObject *_get_interpstate_dict(void) +{ + /* Hack around to return a dict that is subinterpreter-local. + Does not return a new reference. Returns NULL in case of + error, but without setting any exception. (If called late + during shutdown, we *can't* set an exception!) + */ + static PyObject *attr_name = NULL; + PyThreadState *tstate; PyObject *d, *interpdict; - int err; + int err; PyInterpreterState *interp; - - tstate = PyThreadState_GET(); - if (tstate == NULL) { - /* no thread state! */ - return NULL; - } - + + tstate = PyThreadState_GET(); + if (tstate == NULL) { + /* no thread state! */ + return NULL; + } + interp = tstate->interp; #ifdef HAVE_PYINTERPSTATE_GETDICT interpdict = PyInterpreterState_GetDict(interp); /* shared reference */ @@ -39,164 +39,164 @@ static PyObject *_get_interpstate_dict(void) interpdict = interp->builtins; #endif if (interpdict == NULL) { - /* subinterpreter was cleared already, or is being cleared right now, - to a point that is too much for us to continue */ - return NULL; - } - - /* from there on, we know the (sub-)interpreter is still valid */ - - if (attr_name == NULL) { - attr_name = PyText_InternFromString("__cffi_backend_extern_py"); - if (attr_name == NULL) - goto error; - } - + /* subinterpreter was cleared already, or is being cleared right now, + to a point that is too much for us to continue */ + return NULL; + } + + /* from there on, we know the (sub-)interpreter is still valid */ + + if (attr_name == NULL) { + attr_name = PyText_InternFromString("__cffi_backend_extern_py"); + if (attr_name == NULL) + goto error; + } + d = PyDict_GetItem(interpdict, attr_name); - if (d == NULL) { - d = PyDict_New(); - if (d == NULL) - goto error; + if (d == NULL) { + d = PyDict_New(); + if (d == NULL) + goto error; err = PyDict_SetItem(interpdict, attr_name, d); Py_DECREF(d); /* if successful, there is one ref left in interpdict */ - if (err < 0) - goto error; - } - return d; - - error: - PyErr_Clear(); /* typically a MemoryError */ - return NULL; -} - -static PyObject *_ffi_def_extern_decorator(PyObject *outer_args, PyObject *fn) -{ + if (err < 0) + goto error; + } + return d; + + error: + PyErr_Clear(); /* typically a MemoryError */ + return NULL; +} + +static PyObject *_ffi_def_extern_decorator(PyObject *outer_args, PyObject *fn) +{ const char *s; - PyObject *error, *onerror, *infotuple, *old1; - int index, err; - const struct _cffi_global_s *g; - struct _cffi_externpy_s *externpy; - CTypeDescrObject *ct; - FFIObject *ffi; - builder_c_t *types_builder; - PyObject *name = NULL; - PyObject *interpstate_dict; - PyObject *interpstate_key; - - if (!PyArg_ParseTuple(outer_args, "OzOO", &ffi, &s, &error, &onerror)) - return NULL; - - if (s == NULL) { - name = PyObject_GetAttrString(fn, "__name__"); - if (name == NULL) - return NULL; - s = PyText_AsUTF8(name); - if (s == NULL) { - Py_DECREF(name); - return NULL; - } - } - - types_builder = &ffi->types_builder; - index = search_in_globals(&types_builder->ctx, s, strlen(s)); - if (index < 0) - goto not_found; - g = &types_builder->ctx.globals[index]; - if (_CFFI_GETOP(g->type_op) != _CFFI_OP_EXTERN_PYTHON) - goto not_found; - Py_XDECREF(name); - - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - - infotuple = prepare_callback_info_tuple(ct, fn, error, onerror, 0); - Py_DECREF(ct); - if (infotuple == NULL) - return NULL; - - /* don't directly attach infotuple to externpy: in the presence of - subinterpreters, each time we switch to a different - subinterpreter and call the C function, it will notice the - change and look up infotuple from the interpstate_dict. - */ - interpstate_dict = _get_interpstate_dict(); - if (interpstate_dict == NULL) { - Py_DECREF(infotuple); - return PyErr_NoMemory(); - } - - externpy = (struct _cffi_externpy_s *)g->address; - interpstate_key = PyLong_FromVoidPtr((void *)externpy); - if (interpstate_key == NULL) { - Py_DECREF(infotuple); - return NULL; - } - - err = PyDict_SetItem(interpstate_dict, interpstate_key, infotuple); - Py_DECREF(interpstate_key); - Py_DECREF(infotuple); /* interpstate_dict owns the last ref */ - if (err < 0) - return NULL; - - /* force _update_cache_to_call_python() to be called the next time - the C function invokes cffi_call_python, to update the cache */ - old1 = externpy->reserved1; - externpy->reserved1 = Py_None; /* a non-NULL value */ - Py_INCREF(Py_None); - Py_XDECREF(old1); - - /* return the function object unmodified */ - Py_INCREF(fn); - return fn; - - not_found: - PyErr_Format(FFIError, "ffi.def_extern('%s'): no 'extern \"Python\"' " - "function with this name", s); - Py_XDECREF(name); - return NULL; -} - - -static int _update_cache_to_call_python(struct _cffi_externpy_s *externpy) -{ - PyObject *interpstate_dict, *interpstate_key, *infotuple, *old1, *new1; - PyObject *old2; - - interpstate_dict = _get_interpstate_dict(); - if (interpstate_dict == NULL) - return 4; /* oops, shutdown issue? */ - - interpstate_key = PyLong_FromVoidPtr((void *)externpy); - if (interpstate_key == NULL) - goto error; - - infotuple = PyDict_GetItem(interpstate_dict, interpstate_key); - Py_DECREF(interpstate_key); - if (infotuple == NULL) - return 3; /* no ffi.def_extern() from this subinterpreter */ - + PyObject *error, *onerror, *infotuple, *old1; + int index, err; + const struct _cffi_global_s *g; + struct _cffi_externpy_s *externpy; + CTypeDescrObject *ct; + FFIObject *ffi; + builder_c_t *types_builder; + PyObject *name = NULL; + PyObject *interpstate_dict; + PyObject *interpstate_key; + + if (!PyArg_ParseTuple(outer_args, "OzOO", &ffi, &s, &error, &onerror)) + return NULL; + + if (s == NULL) { + name = PyObject_GetAttrString(fn, "__name__"); + if (name == NULL) + return NULL; + s = PyText_AsUTF8(name); + if (s == NULL) { + Py_DECREF(name); + return NULL; + } + } + + types_builder = &ffi->types_builder; + index = search_in_globals(&types_builder->ctx, s, strlen(s)); + if (index < 0) + goto not_found; + g = &types_builder->ctx.globals[index]; + if (_CFFI_GETOP(g->type_op) != _CFFI_OP_EXTERN_PYTHON) + goto not_found; + Py_XDECREF(name); + + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + + infotuple = prepare_callback_info_tuple(ct, fn, error, onerror, 0); + Py_DECREF(ct); + if (infotuple == NULL) + return NULL; + + /* don't directly attach infotuple to externpy: in the presence of + subinterpreters, each time we switch to a different + subinterpreter and call the C function, it will notice the + change and look up infotuple from the interpstate_dict. + */ + interpstate_dict = _get_interpstate_dict(); + if (interpstate_dict == NULL) { + Py_DECREF(infotuple); + return PyErr_NoMemory(); + } + + externpy = (struct _cffi_externpy_s *)g->address; + interpstate_key = PyLong_FromVoidPtr((void *)externpy); + if (interpstate_key == NULL) { + Py_DECREF(infotuple); + return NULL; + } + + err = PyDict_SetItem(interpstate_dict, interpstate_key, infotuple); + Py_DECREF(interpstate_key); + Py_DECREF(infotuple); /* interpstate_dict owns the last ref */ + if (err < 0) + return NULL; + + /* force _update_cache_to_call_python() to be called the next time + the C function invokes cffi_call_python, to update the cache */ + old1 = externpy->reserved1; + externpy->reserved1 = Py_None; /* a non-NULL value */ + Py_INCREF(Py_None); + Py_XDECREF(old1); + + /* return the function object unmodified */ + Py_INCREF(fn); + return fn; + + not_found: + PyErr_Format(FFIError, "ffi.def_extern('%s'): no 'extern \"Python\"' " + "function with this name", s); + Py_XDECREF(name); + return NULL; +} + + +static int _update_cache_to_call_python(struct _cffi_externpy_s *externpy) +{ + PyObject *interpstate_dict, *interpstate_key, *infotuple, *old1, *new1; + PyObject *old2; + + interpstate_dict = _get_interpstate_dict(); + if (interpstate_dict == NULL) + return 4; /* oops, shutdown issue? */ + + interpstate_key = PyLong_FromVoidPtr((void *)externpy); + if (interpstate_key == NULL) + goto error; + + infotuple = PyDict_GetItem(interpstate_dict, interpstate_key); + Py_DECREF(interpstate_key); + if (infotuple == NULL) + return 3; /* no ffi.def_extern() from this subinterpreter */ + new1 = _current_interp_key(); - Py_INCREF(new1); - Py_INCREF(infotuple); - old1 = (PyObject *)externpy->reserved1; - old2 = (PyObject *)externpy->reserved2; - externpy->reserved1 = new1; /* holds a reference */ - externpy->reserved2 = infotuple; /* holds a reference (issue #246) */ - Py_XDECREF(old1); - Py_XDECREF(old2); - - return 0; /* no error */ - - error: - PyErr_Clear(); - return 2; /* out of memory? */ -} - -#if (defined(WITH_THREAD) && !defined(_MSC_VER) && \ - !defined(__amd64__) && !defined(__x86_64__) && \ - !defined(__i386__) && !defined(__i386)) + Py_INCREF(new1); + Py_INCREF(infotuple); + old1 = (PyObject *)externpy->reserved1; + old2 = (PyObject *)externpy->reserved2; + externpy->reserved1 = new1; /* holds a reference */ + externpy->reserved2 = infotuple; /* holds a reference (issue #246) */ + Py_XDECREF(old1); + Py_XDECREF(old2); + + return 0; /* no error */ + + error: + PyErr_Clear(); + return 2; /* out of memory? */ +} + +#if (defined(WITH_THREAD) && !defined(_MSC_VER) && \ + !defined(__amd64__) && !defined(__x86_64__) && \ + !defined(__i386__) && !defined(__i386)) # if defined(HAVE_SYNC_SYNCHRONIZE) # define read_barrier() __sync_synchronize() # elif defined(_AIX) @@ -211,82 +211,82 @@ static int _update_cache_to_call_python(struct _cffi_externpy_s *externpy) # warning "no definition for read_barrier(), missing synchronization for\ multi-thread initialization in embedded mode" # endif -#else -# define read_barrier() (void)0 -#endif - -static void cffi_call_python(struct _cffi_externpy_s *externpy, char *args) -{ - /* Invoked by the helpers generated from extern "Python" in the cdef. - - 'externpy' is a static structure that describes which of the - extern "Python" functions is called. It has got fields 'name' and - 'type_index' describing the function, and more reserved fields - that are initially zero. These reserved fields are set up by - ffi.def_extern(), which invokes _ffi_def_extern_decorator() above. - - 'args' is a pointer to an array of 8-byte entries. Each entry - contains an argument. If an argument is less than 8 bytes, only - the part at the beginning of the entry is initialized. If an - argument is 'long double' or a struct/union, then it is passed - by reference. - - 'args' is also used as the place to write the result to - (directly, even if more than 8 bytes). In all cases, 'args' is - at least 8 bytes in size. - */ - int err = 0; - - /* This read barrier is needed for _embedding.h. It is paired - with the write_barrier() there. Without this barrier, we can - in theory see the following situation: the Python - initialization code already ran (in another thread), and the - '_cffi_call_python' function pointer directed execution here; - but any number of other data could still be seen as - uninitialized below. For example, 'externpy' would still - contain NULLs even though it was correctly set up, or - 'interpreter_lock' (the GIL inside CPython) would still be seen - as NULL, or 'autoInterpreterState' (used by - PyGILState_Ensure()) would be NULL or contain bogus fields. - */ - read_barrier(); - - save_errno(); - - /* We need the infotuple here. We could always go through +#else +# define read_barrier() (void)0 +#endif + +static void cffi_call_python(struct _cffi_externpy_s *externpy, char *args) +{ + /* Invoked by the helpers generated from extern "Python" in the cdef. + + 'externpy' is a static structure that describes which of the + extern "Python" functions is called. It has got fields 'name' and + 'type_index' describing the function, and more reserved fields + that are initially zero. These reserved fields are set up by + ffi.def_extern(), which invokes _ffi_def_extern_decorator() above. + + 'args' is a pointer to an array of 8-byte entries. Each entry + contains an argument. If an argument is less than 8 bytes, only + the part at the beginning of the entry is initialized. If an + argument is 'long double' or a struct/union, then it is passed + by reference. + + 'args' is also used as the place to write the result to + (directly, even if more than 8 bytes). In all cases, 'args' is + at least 8 bytes in size. + */ + int err = 0; + + /* This read barrier is needed for _embedding.h. It is paired + with the write_barrier() there. Without this barrier, we can + in theory see the following situation: the Python + initialization code already ran (in another thread), and the + '_cffi_call_python' function pointer directed execution here; + but any number of other data could still be seen as + uninitialized below. For example, 'externpy' would still + contain NULLs even though it was correctly set up, or + 'interpreter_lock' (the GIL inside CPython) would still be seen + as NULL, or 'autoInterpreterState' (used by + PyGILState_Ensure()) would be NULL or contain bogus fields. + */ + read_barrier(); + + save_errno(); + + /* We need the infotuple here. We could always go through _update_cache_to_call_python(), but to avoid the extra dict - lookups, we cache in (reserved1, reserved2) the last seen pair + lookups, we cache in (reserved1, reserved2) the last seen pair (interp->modules, infotuple). The first item in this tuple is a random PyObject that identifies the subinterpreter. - */ - if (externpy->reserved1 == NULL) { - /* Not initialized! We didn't call @ffi.def_extern() on this - externpy object from any subinterpreter at all. */ - err = 1; - } - else { - PyGILState_STATE state = gil_ensure(); + */ + if (externpy->reserved1 == NULL) { + /* Not initialized! We didn't call @ffi.def_extern() on this + externpy object from any subinterpreter at all. */ + err = 1; + } + else { + PyGILState_STATE state = gil_ensure(); if (externpy->reserved1 != _current_interp_key()) { - /* Update the (reserved1, reserved2) cache. This will fail - if we didn't call @ffi.def_extern() in this particular - subinterpreter. */ - err = _update_cache_to_call_python(externpy); - } - if (!err) { - general_invoke_callback(0, args, args, externpy->reserved2); - } - gil_release(state); - } - if (err) { - static const char *msg[] = { - "no code was attached to it yet with @ffi.def_extern()", - "got internal exception (out of memory?)", - "@ffi.def_extern() was not called in the current subinterpreter", - "got internal exception (shutdown issue?)", - }; - fprintf(stderr, "extern \"Python\": function %s() called, " - "but %s. Returning 0.\n", externpy->name, msg[err-1]); - memset(args, 0, externpy->size_of_result); - } - restore_errno(); -} + /* Update the (reserved1, reserved2) cache. This will fail + if we didn't call @ffi.def_extern() in this particular + subinterpreter. */ + err = _update_cache_to_call_python(externpy); + } + if (!err) { + general_invoke_callback(0, args, args, externpy->reserved2); + } + gil_release(state); + } + if (err) { + static const char *msg[] = { + "no code was attached to it yet with @ffi.def_extern()", + "got internal exception (out of memory?)", + "@ffi.def_extern() was not called in the current subinterpreter", + "got internal exception (shutdown issue?)", + }; + fprintf(stderr, "extern \"Python\": function %s() called, " + "but %s. Returning 0.\n", externpy->name, msg[err-1]); + memset(args, 0, externpy->size_of_result); + } + restore_errno(); +} diff --git a/contrib/python/cffi/c/cdlopen.c b/contrib/python/cffi/c/cdlopen.c index 0ed319b8b5..f33ce1eada 100644 --- a/contrib/python/cffi/c/cdlopen.c +++ b/contrib/python/cffi/c/cdlopen.c @@ -1,362 +1,362 @@ -/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */ - +/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */ + static void *cdlopen_fetch(PyObject *libname, void *libhandle, const char *symbol) -{ - void *address; - - if (libhandle == NULL) { - PyErr_Format(FFIError, "library '%s' has been closed", - PyText_AS_UTF8(libname)); - return NULL; - } - - dlerror(); /* clear error condition */ - address = dlsym(libhandle, symbol); - if (address == NULL) { - const char *error = dlerror(); - PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s", - symbol, PyText_AS_UTF8(libname), error); - } - return address; -} - -static void cdlopen_close_ignore_errors(void *libhandle) -{ - if (libhandle != NULL) - dlclose(libhandle); -} - -static int cdlopen_close(PyObject *libname, void *libhandle) -{ - if (libhandle != NULL && dlclose(libhandle) != 0) { - const char *error = dlerror(); - PyErr_Format(FFIError, "closing library '%s': %s", - PyText_AS_UTF8(libname), error); - return -1; - } - return 0; -} - -static PyObject *ffi_dlopen(PyObject *self, PyObject *args) -{ +{ + void *address; + + if (libhandle == NULL) { + PyErr_Format(FFIError, "library '%s' has been closed", + PyText_AS_UTF8(libname)); + return NULL; + } + + dlerror(); /* clear error condition */ + address = dlsym(libhandle, symbol); + if (address == NULL) { + const char *error = dlerror(); + PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s", + symbol, PyText_AS_UTF8(libname), error); + } + return address; +} + +static void cdlopen_close_ignore_errors(void *libhandle) +{ + if (libhandle != NULL) + dlclose(libhandle); +} + +static int cdlopen_close(PyObject *libname, void *libhandle) +{ + if (libhandle != NULL && dlclose(libhandle) != 0) { + const char *error = dlerror(); + PyErr_Format(FFIError, "closing library '%s': %s", + PyText_AS_UTF8(libname), error); + return -1; + } + return 0; +} + +static PyObject *ffi_dlopen(PyObject *self, PyObject *args) +{ const char *modname; PyObject *temp, *result = NULL; - void *handle; + void *handle; int auto_close; - + handle = b_do_dlopen(args, &modname, &temp, &auto_close); if (handle != NULL) { result = (PyObject *)lib_internal_new((FFIObject *)self, modname, handle, auto_close); - } + } Py_XDECREF(temp); return result; -} - -static PyObject *ffi_dlclose(PyObject *self, PyObject *args) -{ - LibObject *lib; - void *libhandle; - if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib)) - return NULL; - - libhandle = lib->l_libhandle; +} + +static PyObject *ffi_dlclose(PyObject *self, PyObject *args) +{ + LibObject *lib; + void *libhandle; + if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib)) + return NULL; + + libhandle = lib->l_libhandle; if (libhandle != NULL) { lib->l_libhandle = NULL; - + /* Clear the dict to force further accesses to do cdlopen_fetch() again, and fail because the library was closed. */ PyDict_Clear(lib->l_dict); if (cdlopen_close(lib->l_libname, libhandle) < 0) return NULL; - } - Py_INCREF(Py_None); - return Py_None; -} - - -static Py_ssize_t cdl_4bytes(char *src) -{ - /* read 4 bytes in little-endian order; return it as a signed integer */ - signed char *ssrc = (signed char *)src; - unsigned char *usrc = (unsigned char *)src; - return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3]; -} - -static _cffi_opcode_t cdl_opcode(char *src) -{ - return (_cffi_opcode_t)cdl_4bytes(src); -} - -typedef struct { - unsigned long long value; - int neg; -} cdl_intconst_t; - -static int _cdl_realize_global_int(struct _cffi_getconst_s *gc) -{ - /* The 'address' field of 'struct _cffi_global_s' is set to point - to this function in case ffiobj_init() sees constant integers. - This fishes around after the 'ctx->globals' array, which is - initialized to contain another array, this time of - 'cdl_intconst_t' structures. We get the nth one and it tells - us what to return. - */ - cdl_intconst_t *ic; - ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals); - ic += gc->gindex; - gc->value = ic->value; - return ic->neg; -} - -static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - FFIObject *ffi; - static char *keywords[] = {"module_name", "_version", "_types", - "_globals", "_struct_unions", "_enums", - "_typenames", "_includes", NULL}; - char *ffiname = "?", *types = NULL, *building = NULL; - Py_ssize_t version = -1; - Py_ssize_t types_len = 0; - PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL; - PyObject *typenames = NULL, *includes = NULL; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "|sns#O!O!O!O!O!:FFI", keywords, - &ffiname, &version, &types, &types_len, - &PyTuple_Type, &globals, - &PyTuple_Type, &struct_unions, - &PyTuple_Type, &enums, - &PyTuple_Type, &typenames, - &PyTuple_Type, &includes)) - return -1; - - ffi = (FFIObject *)self; - if (ffi->ctx_is_nonempty) { - PyErr_SetString(PyExc_ValueError, - "cannot call FFI.__init__() more than once"); - return -1; - } - ffi->ctx_is_nonempty = 1; - - if (version == -1 && types_len == 0) - return 0; - if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) { - PyErr_Format(PyExc_ImportError, - "cffi out-of-line Python module '%s' has unknown " - "version %p", ffiname, (void *)version); - return -1; - } - - if (types_len > 0) { - /* unpack a string of 4-byte entries into an array of _cffi_opcode_t */ - _cffi_opcode_t *ntypes; - Py_ssize_t i, n = types_len / 4; - - building = PyMem_Malloc(n * sizeof(_cffi_opcode_t)); - if (building == NULL) - goto error; - ntypes = (_cffi_opcode_t *)building; - - for (i = 0; i < n; i++) { - ntypes[i] = cdl_opcode(types); - types += 4; - } - ffi->types_builder.ctx.types = ntypes; - ffi->types_builder.ctx.num_types = n; - building = NULL; - } - - if (globals != NULL) { - /* unpack a tuple alternating strings and ints, each two together - describing one global_s entry with no specified address or size. - The int is only used with integer constants. */ - struct _cffi_global_s *nglobs; - cdl_intconst_t *nintconsts; - Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2; - - i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t)); - building = PyMem_Malloc(i); - if (building == NULL) - goto error; - memset(building, 0, i); - nglobs = (struct _cffi_global_s *)building; - nintconsts = (cdl_intconst_t *)(nglobs + n); - - for (i = 0; i < n; i++) { - char *g = PyBytes_AS_STRING(PyTuple_GET_ITEM(globals, i * 2)); - nglobs[i].type_op = cdl_opcode(g); g += 4; - nglobs[i].name = g; - if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT || - _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) { - PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1); - nglobs[i].address = &_cdl_realize_global_int; -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(o)) { - nintconsts[i].neg = PyInt_AS_LONG(o) <= 0; - nintconsts[i].value = (long long)PyInt_AS_LONG(o); - } - else -#endif - { - nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False, - Py_LE); - nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o); - if (PyErr_Occurred()) - goto error; - } - } - } - ffi->types_builder.ctx.globals = nglobs; - ffi->types_builder.ctx.num_globals = n; - building = NULL; - } - - if (struct_unions != NULL) { - /* unpack a tuple of struct/unions, each described as a sub-tuple; - the item 0 of each sub-tuple describes the struct/union, and - the items 1..N-1 describe the fields, if any */ - struct _cffi_struct_union_s *nstructs; - struct _cffi_field_s *nfields; - Py_ssize_t i, n = PyTuple_GET_SIZE(struct_unions); - Py_ssize_t nf = 0; /* total number of fields */ - - for (i = 0; i < n; i++) { - nf += PyTuple_GET_SIZE(PyTuple_GET_ITEM(struct_unions, i)) - 1; - } - i = (n * sizeof(struct _cffi_struct_union_s) + - nf * sizeof(struct _cffi_field_s)); - building = PyMem_Malloc(i); - if (building == NULL) - goto error; - memset(building, 0, i); - nstructs = (struct _cffi_struct_union_s *)building; - nfields = (struct _cffi_field_s *)(nstructs + n); - nf = 0; - - for (i = 0; i < n; i++) { - /* 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) */ - PyObject *desc = PyTuple_GET_ITEM(struct_unions, i); - Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1; - char *s = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, 0)); - /* 's' is the first string, describing the struct/union */ - nstructs[i].type_index = cdl_4bytes(s); s += 4; - nstructs[i].flags = cdl_4bytes(s); s += 4; - nstructs[i].name = s; - if (nstructs[i].flags & (_CFFI_F_OPAQUE | _CFFI_F_EXTERNAL)) { - nstructs[i].size = (size_t)-1; - nstructs[i].alignment = -1; - nstructs[i].first_field_index = -1; - nstructs[i].num_fields = 0; - assert(nf1 == 0); - } - else { - nstructs[i].size = (size_t)-2; - nstructs[i].alignment = -2; - nstructs[i].first_field_index = nf; - nstructs[i].num_fields = nf1; - } - for (j = 0; j < nf1; j++) { - char *f = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, j + 1)); - /* 'f' is one of the other strings beyond the first one, - describing one field each */ - nfields[nf].field_type_op = cdl_opcode(f); f += 4; - nfields[nf].field_offset = (size_t)-1; - if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) { - nfields[nf].field_size = cdl_4bytes(f); f += 4; - } - else { - nfields[nf].field_size = (size_t)-1; - } - nfields[nf].name = f; - nf++; - } - } - ffi->types_builder.ctx.struct_unions = nstructs; - ffi->types_builder.ctx.fields = nfields; - ffi->types_builder.ctx.num_struct_unions = n; - building = NULL; - } - - if (enums != NULL) { - /* unpack a tuple of strings, each of which describes one enum_s - entry */ - struct _cffi_enum_s *nenums; - Py_ssize_t i, n = PyTuple_GET_SIZE(enums); - - i = n * sizeof(struct _cffi_enum_s); - building = PyMem_Malloc(i); - if (building == NULL) - goto error; - memset(building, 0, i); - nenums = (struct _cffi_enum_s *)building; - - for (i = 0; i < n; i++) { - char *e = PyBytes_AS_STRING(PyTuple_GET_ITEM(enums, i)); - /* 'e' is a string describing the enum */ - nenums[i].type_index = cdl_4bytes(e); e += 4; - nenums[i].type_prim = cdl_4bytes(e); e += 4; - nenums[i].name = e; e += strlen(e) + 1; - nenums[i].enumerators = e; - } - ffi->types_builder.ctx.enums = nenums; - ffi->types_builder.ctx.num_enums = n; - building = NULL; - } - - if (typenames != NULL) { - /* unpack a tuple of strings, each of which describes one typename_s - entry */ - struct _cffi_typename_s *ntypenames; - Py_ssize_t i, n = PyTuple_GET_SIZE(typenames); - - i = n * sizeof(struct _cffi_typename_s); - building = PyMem_Malloc(i); - if (building == NULL) - goto error; - memset(building, 0, i); - ntypenames = (struct _cffi_typename_s *)building; - - for (i = 0; i < n; i++) { - char *t = PyBytes_AS_STRING(PyTuple_GET_ITEM(typenames, i)); - /* 't' is a string describing the typename */ - ntypenames[i].type_index = cdl_4bytes(t); t += 4; - ntypenames[i].name = t; - } - ffi->types_builder.ctx.typenames = ntypenames; - ffi->types_builder.ctx.num_typenames = n; - building = NULL; - } - - if (includes != NULL) { - PyObject *included_libs; - - included_libs = PyTuple_New(PyTuple_GET_SIZE(includes)); - if (included_libs == NULL) - return -1; - - Py_INCREF(includes); - ffi->types_builder.included_ffis = includes; - ffi->types_builder.included_libs = included_libs; - } - - /* Above, we took directly some "char *" strings out of the strings, - typically from somewhere inside tuples. Keep them alive by - incref'ing the whole input arguments. */ - Py_INCREF(args); - Py_XINCREF(kwds); - ffi->types_builder._keepalive1 = args; - ffi->types_builder._keepalive2 = kwds; - return 0; - - error: - if (building != NULL) - PyMem_Free(building); - if (!PyErr_Occurred()) - PyErr_NoMemory(); - return -1; -} + } + Py_INCREF(Py_None); + return Py_None; +} + + +static Py_ssize_t cdl_4bytes(char *src) +{ + /* read 4 bytes in little-endian order; return it as a signed integer */ + signed char *ssrc = (signed char *)src; + unsigned char *usrc = (unsigned char *)src; + return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3]; +} + +static _cffi_opcode_t cdl_opcode(char *src) +{ + return (_cffi_opcode_t)cdl_4bytes(src); +} + +typedef struct { + unsigned long long value; + int neg; +} cdl_intconst_t; + +static int _cdl_realize_global_int(struct _cffi_getconst_s *gc) +{ + /* The 'address' field of 'struct _cffi_global_s' is set to point + to this function in case ffiobj_init() sees constant integers. + This fishes around after the 'ctx->globals' array, which is + initialized to contain another array, this time of + 'cdl_intconst_t' structures. We get the nth one and it tells + us what to return. + */ + cdl_intconst_t *ic; + ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals); + ic += gc->gindex; + gc->value = ic->value; + return ic->neg; +} + +static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + FFIObject *ffi; + static char *keywords[] = {"module_name", "_version", "_types", + "_globals", "_struct_unions", "_enums", + "_typenames", "_includes", NULL}; + char *ffiname = "?", *types = NULL, *building = NULL; + Py_ssize_t version = -1; + Py_ssize_t types_len = 0; + PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL; + PyObject *typenames = NULL, *includes = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "|sns#O!O!O!O!O!:FFI", keywords, + &ffiname, &version, &types, &types_len, + &PyTuple_Type, &globals, + &PyTuple_Type, &struct_unions, + &PyTuple_Type, &enums, + &PyTuple_Type, &typenames, + &PyTuple_Type, &includes)) + return -1; + + ffi = (FFIObject *)self; + if (ffi->ctx_is_nonempty) { + PyErr_SetString(PyExc_ValueError, + "cannot call FFI.__init__() more than once"); + return -1; + } + ffi->ctx_is_nonempty = 1; + + if (version == -1 && types_len == 0) + return 0; + if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) { + PyErr_Format(PyExc_ImportError, + "cffi out-of-line Python module '%s' has unknown " + "version %p", ffiname, (void *)version); + return -1; + } + + if (types_len > 0) { + /* unpack a string of 4-byte entries into an array of _cffi_opcode_t */ + _cffi_opcode_t *ntypes; + Py_ssize_t i, n = types_len / 4; + + building = PyMem_Malloc(n * sizeof(_cffi_opcode_t)); + if (building == NULL) + goto error; + ntypes = (_cffi_opcode_t *)building; + + for (i = 0; i < n; i++) { + ntypes[i] = cdl_opcode(types); + types += 4; + } + ffi->types_builder.ctx.types = ntypes; + ffi->types_builder.ctx.num_types = n; + building = NULL; + } + + if (globals != NULL) { + /* unpack a tuple alternating strings and ints, each two together + describing one global_s entry with no specified address or size. + The int is only used with integer constants. */ + struct _cffi_global_s *nglobs; + cdl_intconst_t *nintconsts; + Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2; + + i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t)); + building = PyMem_Malloc(i); + if (building == NULL) + goto error; + memset(building, 0, i); + nglobs = (struct _cffi_global_s *)building; + nintconsts = (cdl_intconst_t *)(nglobs + n); + + for (i = 0; i < n; i++) { + char *g = PyBytes_AS_STRING(PyTuple_GET_ITEM(globals, i * 2)); + nglobs[i].type_op = cdl_opcode(g); g += 4; + nglobs[i].name = g; + if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT || + _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) { + PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1); + nglobs[i].address = &_cdl_realize_global_int; +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(o)) { + nintconsts[i].neg = PyInt_AS_LONG(o) <= 0; + nintconsts[i].value = (long long)PyInt_AS_LONG(o); + } + else +#endif + { + nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False, + Py_LE); + nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o); + if (PyErr_Occurred()) + goto error; + } + } + } + ffi->types_builder.ctx.globals = nglobs; + ffi->types_builder.ctx.num_globals = n; + building = NULL; + } + + if (struct_unions != NULL) { + /* unpack a tuple of struct/unions, each described as a sub-tuple; + the item 0 of each sub-tuple describes the struct/union, and + the items 1..N-1 describe the fields, if any */ + struct _cffi_struct_union_s *nstructs; + struct _cffi_field_s *nfields; + Py_ssize_t i, n = PyTuple_GET_SIZE(struct_unions); + Py_ssize_t nf = 0; /* total number of fields */ + + for (i = 0; i < n; i++) { + nf += PyTuple_GET_SIZE(PyTuple_GET_ITEM(struct_unions, i)) - 1; + } + i = (n * sizeof(struct _cffi_struct_union_s) + + nf * sizeof(struct _cffi_field_s)); + building = PyMem_Malloc(i); + if (building == NULL) + goto error; + memset(building, 0, i); + nstructs = (struct _cffi_struct_union_s *)building; + nfields = (struct _cffi_field_s *)(nstructs + n); + nf = 0; + + for (i = 0; i < n; i++) { + /* 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) */ + PyObject *desc = PyTuple_GET_ITEM(struct_unions, i); + Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1; + char *s = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, 0)); + /* 's' is the first string, describing the struct/union */ + nstructs[i].type_index = cdl_4bytes(s); s += 4; + nstructs[i].flags = cdl_4bytes(s); s += 4; + nstructs[i].name = s; + if (nstructs[i].flags & (_CFFI_F_OPAQUE | _CFFI_F_EXTERNAL)) { + nstructs[i].size = (size_t)-1; + nstructs[i].alignment = -1; + nstructs[i].first_field_index = -1; + nstructs[i].num_fields = 0; + assert(nf1 == 0); + } + else { + nstructs[i].size = (size_t)-2; + nstructs[i].alignment = -2; + nstructs[i].first_field_index = nf; + nstructs[i].num_fields = nf1; + } + for (j = 0; j < nf1; j++) { + char *f = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, j + 1)); + /* 'f' is one of the other strings beyond the first one, + describing one field each */ + nfields[nf].field_type_op = cdl_opcode(f); f += 4; + nfields[nf].field_offset = (size_t)-1; + if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) { + nfields[nf].field_size = cdl_4bytes(f); f += 4; + } + else { + nfields[nf].field_size = (size_t)-1; + } + nfields[nf].name = f; + nf++; + } + } + ffi->types_builder.ctx.struct_unions = nstructs; + ffi->types_builder.ctx.fields = nfields; + ffi->types_builder.ctx.num_struct_unions = n; + building = NULL; + } + + if (enums != NULL) { + /* unpack a tuple of strings, each of which describes one enum_s + entry */ + struct _cffi_enum_s *nenums; + Py_ssize_t i, n = PyTuple_GET_SIZE(enums); + + i = n * sizeof(struct _cffi_enum_s); + building = PyMem_Malloc(i); + if (building == NULL) + goto error; + memset(building, 0, i); + nenums = (struct _cffi_enum_s *)building; + + for (i = 0; i < n; i++) { + char *e = PyBytes_AS_STRING(PyTuple_GET_ITEM(enums, i)); + /* 'e' is a string describing the enum */ + nenums[i].type_index = cdl_4bytes(e); e += 4; + nenums[i].type_prim = cdl_4bytes(e); e += 4; + nenums[i].name = e; e += strlen(e) + 1; + nenums[i].enumerators = e; + } + ffi->types_builder.ctx.enums = nenums; + ffi->types_builder.ctx.num_enums = n; + building = NULL; + } + + if (typenames != NULL) { + /* unpack a tuple of strings, each of which describes one typename_s + entry */ + struct _cffi_typename_s *ntypenames; + Py_ssize_t i, n = PyTuple_GET_SIZE(typenames); + + i = n * sizeof(struct _cffi_typename_s); + building = PyMem_Malloc(i); + if (building == NULL) + goto error; + memset(building, 0, i); + ntypenames = (struct _cffi_typename_s *)building; + + for (i = 0; i < n; i++) { + char *t = PyBytes_AS_STRING(PyTuple_GET_ITEM(typenames, i)); + /* 't' is a string describing the typename */ + ntypenames[i].type_index = cdl_4bytes(t); t += 4; + ntypenames[i].name = t; + } + ffi->types_builder.ctx.typenames = ntypenames; + ffi->types_builder.ctx.num_typenames = n; + building = NULL; + } + + if (includes != NULL) { + PyObject *included_libs; + + included_libs = PyTuple_New(PyTuple_GET_SIZE(includes)); + if (included_libs == NULL) + return -1; + + Py_INCREF(includes); + ffi->types_builder.included_ffis = includes; + ffi->types_builder.included_libs = included_libs; + } + + /* Above, we took directly some "char *" strings out of the strings, + typically from somewhere inside tuples. Keep them alive by + incref'ing the whole input arguments. */ + Py_INCREF(args); + Py_XINCREF(kwds); + ffi->types_builder._keepalive1 = args; + ffi->types_builder._keepalive2 = kwds; + return 0; + + error: + if (building != NULL) + PyMem_Free(building); + if (!PyErr_Occurred()) + PyErr_NoMemory(); + return -1; +} diff --git a/contrib/python/cffi/c/cffi1_module.c b/contrib/python/cffi/c/cffi1_module.c index 06a84fea37..f9975eca1f 100644 --- a/contrib/python/cffi/c/cffi1_module.c +++ b/contrib/python/cffi/c/cffi1_module.c @@ -1,216 +1,216 @@ - -#include "parse_c_type.c" -#include "realize_c_type.c" - + +#include "parse_c_type.c" +#include "realize_c_type.c" + #define CFFI_VERSION_MIN 0x2601 #define CFFI_VERSION_CHAR16CHAR32 0x2801 #define CFFI_VERSION_MAX 0x28FF - -typedef struct FFIObject_s FFIObject; -typedef struct LibObject_s LibObject; - -static PyTypeObject FFI_Type; /* forward */ -static PyTypeObject Lib_Type; /* forward */ - -#include "ffi_obj.c" -#include "cglob.c" -#include "lib_obj.c" -#include "cdlopen.c" -#include "commontypes.c" -#include "call_python.c" - - -static int init_ffi_lib(PyObject *m) -{ - PyObject *x; - int i, res; - static char init_done = 0; - - if (!init_done) { - if (init_global_types_dict(FFI_Type.tp_dict) < 0) - return -1; - - FFIError = PyErr_NewException("ffi.error", NULL, NULL); - if (FFIError == NULL) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "error", FFIError) < 0) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "CType", - (PyObject *)&CTypeDescr_Type) < 0) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "CData", - (PyObject *)&CData_Type) < 0) - return -1; + +typedef struct FFIObject_s FFIObject; +typedef struct LibObject_s LibObject; + +static PyTypeObject FFI_Type; /* forward */ +static PyTypeObject Lib_Type; /* forward */ + +#include "ffi_obj.c" +#include "cglob.c" +#include "lib_obj.c" +#include "cdlopen.c" +#include "commontypes.c" +#include "call_python.c" + + +static int init_ffi_lib(PyObject *m) +{ + PyObject *x; + int i, res; + static char init_done = 0; + + if (!init_done) { + if (init_global_types_dict(FFI_Type.tp_dict) < 0) + return -1; + + FFIError = PyErr_NewException("ffi.error", NULL, NULL); + if (FFIError == NULL) + return -1; + if (PyDict_SetItemString(FFI_Type.tp_dict, "error", FFIError) < 0) + return -1; + if (PyDict_SetItemString(FFI_Type.tp_dict, "CType", + (PyObject *)&CTypeDescr_Type) < 0) + return -1; + if (PyDict_SetItemString(FFI_Type.tp_dict, "CData", + (PyObject *)&CData_Type) < 0) + return -1; if (PyDict_SetItemString(FFI_Type.tp_dict, "buffer", (PyObject *)&MiniBuffer_Type) < 0) return -1; - - for (i = 0; all_dlopen_flags[i].name != NULL; i++) { - x = PyInt_FromLong(all_dlopen_flags[i].value); - if (x == NULL) - return -1; - res = PyDict_SetItemString(FFI_Type.tp_dict, - all_dlopen_flags[i].name, x); - Py_DECREF(x); - if (res < 0) - return -1; - } - init_done = 1; - } - return 0; -} - -static int make_included_tuples(char *module_name, - const char *const *ctx_includes, - PyObject **included_ffis, - PyObject **included_libs) -{ - Py_ssize_t num = 0; - const char *const *p_include; - - if (ctx_includes == NULL) - return 0; - - for (p_include = ctx_includes; *p_include; p_include++) { - num++; - } - *included_ffis = PyTuple_New(num); - *included_libs = PyTuple_New(num); - if (*included_ffis == NULL || *included_libs == NULL) - goto error; - - num = 0; - for (p_include = ctx_includes; *p_include; p_include++) { - PyObject *included_ffi, *included_lib; - PyObject *m = PyImport_ImportModule(*p_include); - if (m == NULL) - goto import_error; - - included_ffi = PyObject_GetAttrString(m, "ffi"); - PyTuple_SET_ITEM(*included_ffis, num, included_ffi); - - included_lib = (included_ffi == NULL) ? NULL : - PyObject_GetAttrString(m, "lib"); - PyTuple_SET_ITEM(*included_libs, num, included_lib); - - Py_DECREF(m); - if (included_lib == NULL) - goto import_error; - - if (!FFIObject_Check(included_ffi) || - !LibObject_Check(included_lib)) - goto import_error; - num++; - } - return 0; - - import_error: - PyErr_Format(PyExc_ImportError, - "while loading %.200s: failed to import ffi, lib from %.200s", - module_name, *p_include); - error: - Py_XDECREF(*included_ffis); *included_ffis = NULL; - Py_XDECREF(*included_libs); *included_libs = NULL; - return -1; -} - -static PyObject *_my_Py_InitModule(char *module_name) -{ -#if PY_MAJOR_VERSION >= 3 - struct PyModuleDef *module_def, local_module_def = { - PyModuleDef_HEAD_INIT, - module_name, - NULL, - -1, - NULL, NULL, NULL, NULL, NULL - }; - /* note: the 'module_def' is allocated dynamically and leaks, - but anyway the C extension module can never be unloaded */ - module_def = PyMem_Malloc(sizeof(struct PyModuleDef)); - if (module_def == NULL) - return PyErr_NoMemory(); - *module_def = local_module_def; - return PyModule_Create(module_def); -#else - return Py_InitModule(module_name, NULL); -#endif -} - -static PyObject *b_init_cffi_1_0_external_module(PyObject *self, PyObject *arg) -{ - PyObject *m, *modules_dict; - FFIObject *ffi; - LibObject *lib; - Py_ssize_t version, num_exports; - char *module_name, *exports, *module_name_with_lib; - void **raw; - const struct _cffi_type_context_s *ctx; - - raw = (void **)PyLong_AsVoidPtr(arg); - if (raw == NULL) - return NULL; - - module_name = (char *)raw[0]; - version = (Py_ssize_t)raw[1]; - exports = (char *)raw[2]; - ctx = (const struct _cffi_type_context_s *)raw[3]; - - if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_ImportError, - "cffi extension module '%s' uses an unknown version tag %p. " - "This module might need a more recent version of cffi " - "than the one currently installed, which is %s", - module_name, (void *)version, CFFI_VERSION); - return NULL; - } - - /* initialize the exports array */ - num_exports = 25; - if (ctx->flags & 1) /* set to mean that 'extern "Python"' is used */ - num_exports = 26; + + for (i = 0; all_dlopen_flags[i].name != NULL; i++) { + x = PyInt_FromLong(all_dlopen_flags[i].value); + if (x == NULL) + return -1; + res = PyDict_SetItemString(FFI_Type.tp_dict, + all_dlopen_flags[i].name, x); + Py_DECREF(x); + if (res < 0) + return -1; + } + init_done = 1; + } + return 0; +} + +static int make_included_tuples(char *module_name, + const char *const *ctx_includes, + PyObject **included_ffis, + PyObject **included_libs) +{ + Py_ssize_t num = 0; + const char *const *p_include; + + if (ctx_includes == NULL) + return 0; + + for (p_include = ctx_includes; *p_include; p_include++) { + num++; + } + *included_ffis = PyTuple_New(num); + *included_libs = PyTuple_New(num); + if (*included_ffis == NULL || *included_libs == NULL) + goto error; + + num = 0; + for (p_include = ctx_includes; *p_include; p_include++) { + PyObject *included_ffi, *included_lib; + PyObject *m = PyImport_ImportModule(*p_include); + if (m == NULL) + goto import_error; + + included_ffi = PyObject_GetAttrString(m, "ffi"); + PyTuple_SET_ITEM(*included_ffis, num, included_ffi); + + included_lib = (included_ffi == NULL) ? NULL : + PyObject_GetAttrString(m, "lib"); + PyTuple_SET_ITEM(*included_libs, num, included_lib); + + Py_DECREF(m); + if (included_lib == NULL) + goto import_error; + + if (!FFIObject_Check(included_ffi) || + !LibObject_Check(included_lib)) + goto import_error; + num++; + } + return 0; + + import_error: + PyErr_Format(PyExc_ImportError, + "while loading %.200s: failed to import ffi, lib from %.200s", + module_name, *p_include); + error: + Py_XDECREF(*included_ffis); *included_ffis = NULL; + Py_XDECREF(*included_libs); *included_libs = NULL; + return -1; +} + +static PyObject *_my_Py_InitModule(char *module_name) +{ +#if PY_MAJOR_VERSION >= 3 + struct PyModuleDef *module_def, local_module_def = { + PyModuleDef_HEAD_INIT, + module_name, + NULL, + -1, + NULL, NULL, NULL, NULL, NULL + }; + /* note: the 'module_def' is allocated dynamically and leaks, + but anyway the C extension module can never be unloaded */ + module_def = PyMem_Malloc(sizeof(struct PyModuleDef)); + if (module_def == NULL) + return PyErr_NoMemory(); + *module_def = local_module_def; + return PyModule_Create(module_def); +#else + return Py_InitModule(module_name, NULL); +#endif +} + +static PyObject *b_init_cffi_1_0_external_module(PyObject *self, PyObject *arg) +{ + PyObject *m, *modules_dict; + FFIObject *ffi; + LibObject *lib; + Py_ssize_t version, num_exports; + char *module_name, *exports, *module_name_with_lib; + void **raw; + const struct _cffi_type_context_s *ctx; + + raw = (void **)PyLong_AsVoidPtr(arg); + if (raw == NULL) + return NULL; + + module_name = (char *)raw[0]; + version = (Py_ssize_t)raw[1]; + exports = (char *)raw[2]; + ctx = (const struct _cffi_type_context_s *)raw[3]; + + if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) { + if (!PyErr_Occurred()) + PyErr_Format(PyExc_ImportError, + "cffi extension module '%s' uses an unknown version tag %p. " + "This module might need a more recent version of cffi " + "than the one currently installed, which is %s", + module_name, (void *)version, CFFI_VERSION); + return NULL; + } + + /* initialize the exports array */ + num_exports = 25; + if (ctx->flags & 1) /* set to mean that 'extern "Python"' is used */ + num_exports = 26; if (version >= CFFI_VERSION_CHAR16CHAR32) num_exports = 28; - memcpy(exports, (char *)cffi_exports, num_exports * sizeof(void *)); - - /* make the module object */ - m = _my_Py_InitModule(module_name); - if (m == NULL) - return NULL; - - /* build the FFI and Lib object inside this new module */ - ffi = ffi_internal_new(&FFI_Type, ctx); - Py_XINCREF(ffi); /* make the ffi object really immortal */ - if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0) - return NULL; - + memcpy(exports, (char *)cffi_exports, num_exports * sizeof(void *)); + + /* make the module object */ + m = _my_Py_InitModule(module_name); + if (m == NULL) + return NULL; + + /* build the FFI and Lib object inside this new module */ + ffi = ffi_internal_new(&FFI_Type, ctx); + Py_XINCREF(ffi); /* make the ffi object really immortal */ + if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0) + return NULL; + lib = lib_internal_new(ffi, module_name, NULL, 0); - if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0) - return NULL; - - if (make_included_tuples(module_name, ctx->includes, - &ffi->types_builder.included_ffis, - &lib->l_types_builder->included_libs) < 0) - return NULL; - - /* add manually 'module_name.lib' in sys.modules: - see test_import_from_lib */ - modules_dict = PySys_GetObject("modules"); - if (!modules_dict) - return NULL; - module_name_with_lib = alloca(strlen(module_name) + 5); - strcpy(module_name_with_lib, module_name); - strcat(module_name_with_lib, ".lib"); - if (PyDict_SetItemString(modules_dict, module_name_with_lib, - (PyObject *)lib) < 0) - return NULL; - -#if PY_MAJOR_VERSION >= 3 - /* add manually 'module_name' in sys.modules: it seems that - Py_InitModule() is not enough to do that */ - if (PyDict_SetItemString(modules_dict, module_name, m) < 0) - return NULL; -#endif - - return m; -} + if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0) + return NULL; + + if (make_included_tuples(module_name, ctx->includes, + &ffi->types_builder.included_ffis, + &lib->l_types_builder->included_libs) < 0) + return NULL; + + /* add manually 'module_name.lib' in sys.modules: + see test_import_from_lib */ + modules_dict = PySys_GetObject("modules"); + if (!modules_dict) + return NULL; + module_name_with_lib = alloca(strlen(module_name) + 5); + strcpy(module_name_with_lib, module_name); + strcat(module_name_with_lib, ".lib"); + if (PyDict_SetItemString(modules_dict, module_name_with_lib, + (PyObject *)lib) < 0) + return NULL; + +#if PY_MAJOR_VERSION >= 3 + /* add manually 'module_name' in sys.modules: it seems that + Py_InitModule() is not enough to do that */ + if (PyDict_SetItemString(modules_dict, module_name, m) < 0) + return NULL; +#endif + + return m; +} diff --git a/contrib/python/cffi/c/cglob.c b/contrib/python/cffi/c/cglob.c index e97767c9d7..04c3e8bbce 100644 --- a/contrib/python/cffi/c/cglob.c +++ b/contrib/python/cffi/c/cglob.c @@ -1,113 +1,113 @@ - -typedef void *(*gs_fetch_addr_fn)(void); - -typedef struct { - PyObject_HEAD - - PyObject *gs_name; - CTypeDescrObject *gs_type; - char *gs_data; - gs_fetch_addr_fn gs_fetch_addr; - -} GlobSupportObject; - -static void glob_support_dealloc(GlobSupportObject *gs) -{ - Py_DECREF(gs->gs_name); - Py_DECREF(gs->gs_type); - PyObject_Del(gs); -} - -static PyTypeObject GlobSupport_Type = { - PyVarObject_HEAD_INIT(NULL, 0) + +typedef void *(*gs_fetch_addr_fn)(void); + +typedef struct { + PyObject_HEAD + + PyObject *gs_name; + CTypeDescrObject *gs_type; + char *gs_data; + gs_fetch_addr_fn gs_fetch_addr; + +} GlobSupportObject; + +static void glob_support_dealloc(GlobSupportObject *gs) +{ + Py_DECREF(gs->gs_name); + Py_DECREF(gs->gs_type); + PyObject_Del(gs); +} + +static PyTypeObject GlobSupport_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.__FFIGlobSupport", - sizeof(GlobSupportObject), - 0, - (destructor)glob_support_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ -}; - -#define GlobSupport_Check(ob) (Py_TYPE(ob) == &GlobSupport_Type) - -static PyObject *make_global_var(PyObject *name, CTypeDescrObject *type, - char *addr, gs_fetch_addr_fn fetch_addr) -{ - GlobSupportObject *gs = PyObject_New(GlobSupportObject, &GlobSupport_Type); - if (gs == NULL) - return NULL; - - Py_INCREF(name); - Py_INCREF(type); - gs->gs_name = name; - gs->gs_type = type; - gs->gs_data = addr; - gs->gs_fetch_addr = fetch_addr; - return (PyObject *)gs; -} - -static void *fetch_global_var_addr(GlobSupportObject *gs) -{ - void *data; - if (gs->gs_data != NULL) { - data = gs->gs_data; - } - else { - Py_BEGIN_ALLOW_THREADS - restore_errno(); - data = gs->gs_fetch_addr(); - save_errno(); - Py_END_ALLOW_THREADS - } - if (data == NULL) { - PyErr_Format(FFIError, "global variable '%s' is at address NULL", - PyText_AS_UTF8(gs->gs_name)); - return NULL; - } - return data; -} - -static PyObject *read_global_var(GlobSupportObject *gs) -{ - void *data = fetch_global_var_addr(gs); - if (data == NULL) - return NULL; - return convert_to_object(data, gs->gs_type); -} - -static int write_global_var(GlobSupportObject *gs, PyObject *obj) -{ - void *data = fetch_global_var_addr(gs); - if (data == NULL) - return -1; - return convert_from_object(data, gs->gs_type, obj); -} - -static PyObject *cg_addressof_global_var(GlobSupportObject *gs) -{ - void *data; - PyObject *x, *ptrtype = new_pointer_type(gs->gs_type); - if (ptrtype == NULL) - return NULL; - - data = fetch_global_var_addr(gs); - if (data != NULL) - x = new_simple_cdata(data, (CTypeDescrObject *)ptrtype); - else - x = NULL; - Py_DECREF(ptrtype); - return x; -} + sizeof(GlobSupportObject), + 0, + (destructor)glob_support_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ +}; + +#define GlobSupport_Check(ob) (Py_TYPE(ob) == &GlobSupport_Type) + +static PyObject *make_global_var(PyObject *name, CTypeDescrObject *type, + char *addr, gs_fetch_addr_fn fetch_addr) +{ + GlobSupportObject *gs = PyObject_New(GlobSupportObject, &GlobSupport_Type); + if (gs == NULL) + return NULL; + + Py_INCREF(name); + Py_INCREF(type); + gs->gs_name = name; + gs->gs_type = type; + gs->gs_data = addr; + gs->gs_fetch_addr = fetch_addr; + return (PyObject *)gs; +} + +static void *fetch_global_var_addr(GlobSupportObject *gs) +{ + void *data; + if (gs->gs_data != NULL) { + data = gs->gs_data; + } + else { + Py_BEGIN_ALLOW_THREADS + restore_errno(); + data = gs->gs_fetch_addr(); + save_errno(); + Py_END_ALLOW_THREADS + } + if (data == NULL) { + PyErr_Format(FFIError, "global variable '%s' is at address NULL", + PyText_AS_UTF8(gs->gs_name)); + return NULL; + } + return data; +} + +static PyObject *read_global_var(GlobSupportObject *gs) +{ + void *data = fetch_global_var_addr(gs); + if (data == NULL) + return NULL; + return convert_to_object(data, gs->gs_type); +} + +static int write_global_var(GlobSupportObject *gs, PyObject *obj) +{ + void *data = fetch_global_var_addr(gs); + if (data == NULL) + return -1; + return convert_from_object(data, gs->gs_type, obj); +} + +static PyObject *cg_addressof_global_var(GlobSupportObject *gs) +{ + void *data; + PyObject *x, *ptrtype = new_pointer_type(gs->gs_type); + if (ptrtype == NULL) + return NULL; + + data = fetch_global_var_addr(gs); + if (data != NULL) + x = new_simple_cdata(data, (CTypeDescrObject *)ptrtype); + else + x = NULL; + Py_DECREF(ptrtype); + return x; +} diff --git a/contrib/python/cffi/c/commontypes.c b/contrib/python/cffi/c/commontypes.c index a41c2fdd2b..bd69132ff3 100644 --- a/contrib/python/cffi/c/commontypes.c +++ b/contrib/python/cffi/c/commontypes.c @@ -1,216 +1,216 @@ -/* This file must be kept in alphabetical order. See test_commontypes.py */ - -#define EQ(key, value) key "\0" value /* string concatenation */ -#ifdef _WIN64 -# define W32_64(X,Y) Y -# else -# define W32_64(X,Y) X -# endif - - -static const char *common_simple_types[] = { - -#ifdef MS_WIN32 /* Windows types */ - EQ("ATOM", "WORD"), - EQ("BOOL", "int"), - EQ("BOOLEAN", "BYTE"), - EQ("BYTE", "unsigned char"), - EQ("CCHAR", "char"), - EQ("CHAR", "char"), - EQ("COLORREF", "DWORD"), - EQ("DWORD", "unsigned long"), - EQ("DWORD32", "unsigned int"), - EQ("DWORD64", "unsigned long long"), - EQ("DWORDLONG", "ULONGLONG"), - EQ("DWORD_PTR", "ULONG_PTR"), -#endif - - EQ("FILE", "struct _IO_FILE"), - -#ifdef MS_WIN32 /* more Windows types */ - EQ("FLOAT", "float"), - EQ("HACCEL", "HANDLE"), - EQ("HALF_PTR", W32_64("short","int")), - EQ("HANDLE", "PVOID"), - EQ("HBITMAP", "HANDLE"), - EQ("HBRUSH", "HANDLE"), - EQ("HCOLORSPACE", "HANDLE"), - EQ("HCONV", "HANDLE"), - EQ("HCONVLIST", "HANDLE"), - EQ("HCURSOR", "HICON"), - EQ("HDC", "HANDLE"), - EQ("HDDEDATA", "HANDLE"), - EQ("HDESK", "HANDLE"), - EQ("HDROP", "HANDLE"), - EQ("HDWP", "HANDLE"), - EQ("HENHMETAFILE", "HANDLE"), - EQ("HFILE", "int"), - EQ("HFONT", "HANDLE"), - EQ("HGDIOBJ", "HANDLE"), - EQ("HGLOBAL", "HANDLE"), - EQ("HHOOK", "HANDLE"), - EQ("HICON", "HANDLE"), - EQ("HINSTANCE", "HANDLE"), - EQ("HKEY", "HANDLE"), - EQ("HKL", "HANDLE"), - EQ("HLOCAL", "HANDLE"), - EQ("HMENU", "HANDLE"), - EQ("HMETAFILE", "HANDLE"), - EQ("HMODULE", "HINSTANCE"), - EQ("HMONITOR", "HANDLE"), - EQ("HPALETTE", "HANDLE"), - EQ("HPEN", "HANDLE"), - EQ("HRESULT", "LONG"), - EQ("HRGN", "HANDLE"), - EQ("HRSRC", "HANDLE"), - EQ("HSZ", "HANDLE"), - EQ("HWND", "HANDLE"), - EQ("INT", "int"), - EQ("INT16", "short"), - EQ("INT32", "int"), - EQ("INT64", "long long"), - EQ("INT8", "signed char"), - EQ("INT_PTR", W32_64("int","long long")), - EQ("LANGID", "WORD"), - EQ("LCID", "DWORD"), - EQ("LCTYPE", "DWORD"), - EQ("LGRPID", "DWORD"), - EQ("LONG", "long"), - EQ("LONG32", "int"), - EQ("LONG64", "long long"), - EQ("LONGLONG", "long long"), - EQ("LONG_PTR", W32_64("long","long long")), - EQ("LPARAM", "LONG_PTR"), - EQ("LPBOOL", "BOOL *"), - EQ("LPBYTE", "BYTE *"), - EQ("LPCOLORREF", "DWORD *"), - EQ("LPCSTR", "const char *"), - EQ("LPCVOID", "const void *"), - EQ("LPCWSTR", "const WCHAR *"), - EQ("LPDWORD", "DWORD *"), - EQ("LPHANDLE", "HANDLE *"), - EQ("LPINT", "int *"), - EQ("LPLONG", "long *"), - EQ("LPSTR", "CHAR *"), - EQ("LPVOID", "void *"), - EQ("LPWORD", "WORD *"), - EQ("LPWSTR", "WCHAR *"), - EQ("LRESULT", "LONG_PTR"), - EQ("PBOOL", "BOOL *"), - EQ("PBOOLEAN", "BOOLEAN *"), - EQ("PBYTE", "BYTE *"), - EQ("PCHAR", "CHAR *"), - EQ("PCSTR", "const CHAR *"), - EQ("PCWSTR", "const WCHAR *"), - EQ("PDWORD", "DWORD *"), - EQ("PDWORD32", "DWORD32 *"), - EQ("PDWORD64", "DWORD64 *"), - EQ("PDWORDLONG", "DWORDLONG *"), - EQ("PDWORD_PTR", "DWORD_PTR *"), - EQ("PFLOAT", "FLOAT *"), - EQ("PHALF_PTR", "HALF_PTR *"), - EQ("PHANDLE", "HANDLE *"), - EQ("PHKEY", "HKEY *"), - EQ("PINT", "int *"), - EQ("PINT16", "INT16 *"), - EQ("PINT32", "INT32 *"), - EQ("PINT64", "INT64 *"), - EQ("PINT8", "INT8 *"), - EQ("PINT_PTR", "INT_PTR *"), - EQ("PLCID", "PDWORD"), - EQ("PLONG", "LONG *"), - EQ("PLONG32", "LONG32 *"), - EQ("PLONG64", "LONG64 *"), - EQ("PLONGLONG", "LONGLONG *"), - EQ("PLONG_PTR", "LONG_PTR *"), - EQ("PSHORT", "SHORT *"), - EQ("PSIZE_T", "SIZE_T *"), - EQ("PSSIZE_T", "SSIZE_T *"), - EQ("PSTR", "CHAR *"), - EQ("PUCHAR", "UCHAR *"), - EQ("PUHALF_PTR", "UHALF_PTR *"), - EQ("PUINT", "UINT *"), - EQ("PUINT16", "UINT16 *"), - EQ("PUINT32", "UINT32 *"), - EQ("PUINT64", "UINT64 *"), - EQ("PUINT8", "UINT8 *"), - EQ("PUINT_PTR", "UINT_PTR *"), - EQ("PULONG", "ULONG *"), - EQ("PULONG32", "ULONG32 *"), - EQ("PULONG64", "ULONG64 *"), - EQ("PULONGLONG", "ULONGLONG *"), - EQ("PULONG_PTR", "ULONG_PTR *"), - EQ("PUSHORT", "USHORT *"), - EQ("PVOID", "void *"), - EQ("PWCHAR", "WCHAR *"), - EQ("PWORD", "WORD *"), - EQ("PWSTR", "WCHAR *"), - EQ("QWORD", "unsigned long long"), - EQ("SC_HANDLE", "HANDLE"), - EQ("SC_LOCK", "LPVOID"), - EQ("SERVICE_STATUS_HANDLE", "HANDLE"), - EQ("SHORT", "short"), - EQ("SIZE_T", "ULONG_PTR"), - EQ("SSIZE_T", "LONG_PTR"), - EQ("UCHAR", "unsigned char"), - EQ("UHALF_PTR", W32_64("unsigned short","unsigned int")), - EQ("UINT", "unsigned int"), - EQ("UINT16", "unsigned short"), - EQ("UINT32", "unsigned int"), - EQ("UINT64", "unsigned long long"), - EQ("UINT8", "unsigned char"), - EQ("UINT_PTR", W32_64("unsigned int","unsigned long long")), - EQ("ULONG", "unsigned long"), - EQ("ULONG32", "unsigned int"), - EQ("ULONG64", "unsigned long long"), - EQ("ULONGLONG", "unsigned long long"), - EQ("ULONG_PTR", W32_64("unsigned long","unsigned long long")), - EQ("USHORT", "unsigned short"), - EQ("USN", "LONGLONG"), - EQ("VOID", "void"), - EQ("WCHAR", "wchar_t"), - EQ("WINSTA", "HANDLE"), - EQ("WORD", "unsigned short"), - EQ("WPARAM", "UINT_PTR"), -#endif - - EQ("bool", "_Bool"), -}; - - -#undef EQ -#undef W32_64 - -#define num_common_simple_types \ - (sizeof(common_simple_types) / sizeof(common_simple_types[0])) - - -static const char *get_common_type(const char *search, size_t search_len) -{ - const char *entry; - int index = search_sorted(common_simple_types, sizeof(const char *), - num_common_simple_types, search, search_len); - if (index < 0) - return NULL; - - entry = common_simple_types[index]; - return entry + strlen(entry) + 1; -} - -static PyObject *b__get_common_types(PyObject *self, PyObject *arg) -{ - int err; - size_t i; - for (i = 0; i < num_common_simple_types; i++) { - const char *s = common_simple_types[i]; - PyObject *o = PyText_FromString(s + strlen(s) + 1); - if (o == NULL) - return NULL; - err = PyDict_SetItemString(arg, s, o); - Py_DECREF(o); - if (err < 0) - return NULL; - } - Py_INCREF(Py_None); - return Py_None; -} +/* This file must be kept in alphabetical order. See test_commontypes.py */ + +#define EQ(key, value) key "\0" value /* string concatenation */ +#ifdef _WIN64 +# define W32_64(X,Y) Y +# else +# define W32_64(X,Y) X +# endif + + +static const char *common_simple_types[] = { + +#ifdef MS_WIN32 /* Windows types */ + EQ("ATOM", "WORD"), + EQ("BOOL", "int"), + EQ("BOOLEAN", "BYTE"), + EQ("BYTE", "unsigned char"), + EQ("CCHAR", "char"), + EQ("CHAR", "char"), + EQ("COLORREF", "DWORD"), + EQ("DWORD", "unsigned long"), + EQ("DWORD32", "unsigned int"), + EQ("DWORD64", "unsigned long long"), + EQ("DWORDLONG", "ULONGLONG"), + EQ("DWORD_PTR", "ULONG_PTR"), +#endif + + EQ("FILE", "struct _IO_FILE"), + +#ifdef MS_WIN32 /* more Windows types */ + EQ("FLOAT", "float"), + EQ("HACCEL", "HANDLE"), + EQ("HALF_PTR", W32_64("short","int")), + EQ("HANDLE", "PVOID"), + EQ("HBITMAP", "HANDLE"), + EQ("HBRUSH", "HANDLE"), + EQ("HCOLORSPACE", "HANDLE"), + EQ("HCONV", "HANDLE"), + EQ("HCONVLIST", "HANDLE"), + EQ("HCURSOR", "HICON"), + EQ("HDC", "HANDLE"), + EQ("HDDEDATA", "HANDLE"), + EQ("HDESK", "HANDLE"), + EQ("HDROP", "HANDLE"), + EQ("HDWP", "HANDLE"), + EQ("HENHMETAFILE", "HANDLE"), + EQ("HFILE", "int"), + EQ("HFONT", "HANDLE"), + EQ("HGDIOBJ", "HANDLE"), + EQ("HGLOBAL", "HANDLE"), + EQ("HHOOK", "HANDLE"), + EQ("HICON", "HANDLE"), + EQ("HINSTANCE", "HANDLE"), + EQ("HKEY", "HANDLE"), + EQ("HKL", "HANDLE"), + EQ("HLOCAL", "HANDLE"), + EQ("HMENU", "HANDLE"), + EQ("HMETAFILE", "HANDLE"), + EQ("HMODULE", "HINSTANCE"), + EQ("HMONITOR", "HANDLE"), + EQ("HPALETTE", "HANDLE"), + EQ("HPEN", "HANDLE"), + EQ("HRESULT", "LONG"), + EQ("HRGN", "HANDLE"), + EQ("HRSRC", "HANDLE"), + EQ("HSZ", "HANDLE"), + EQ("HWND", "HANDLE"), + EQ("INT", "int"), + EQ("INT16", "short"), + EQ("INT32", "int"), + EQ("INT64", "long long"), + EQ("INT8", "signed char"), + EQ("INT_PTR", W32_64("int","long long")), + EQ("LANGID", "WORD"), + EQ("LCID", "DWORD"), + EQ("LCTYPE", "DWORD"), + EQ("LGRPID", "DWORD"), + EQ("LONG", "long"), + EQ("LONG32", "int"), + EQ("LONG64", "long long"), + EQ("LONGLONG", "long long"), + EQ("LONG_PTR", W32_64("long","long long")), + EQ("LPARAM", "LONG_PTR"), + EQ("LPBOOL", "BOOL *"), + EQ("LPBYTE", "BYTE *"), + EQ("LPCOLORREF", "DWORD *"), + EQ("LPCSTR", "const char *"), + EQ("LPCVOID", "const void *"), + EQ("LPCWSTR", "const WCHAR *"), + EQ("LPDWORD", "DWORD *"), + EQ("LPHANDLE", "HANDLE *"), + EQ("LPINT", "int *"), + EQ("LPLONG", "long *"), + EQ("LPSTR", "CHAR *"), + EQ("LPVOID", "void *"), + EQ("LPWORD", "WORD *"), + EQ("LPWSTR", "WCHAR *"), + EQ("LRESULT", "LONG_PTR"), + EQ("PBOOL", "BOOL *"), + EQ("PBOOLEAN", "BOOLEAN *"), + EQ("PBYTE", "BYTE *"), + EQ("PCHAR", "CHAR *"), + EQ("PCSTR", "const CHAR *"), + EQ("PCWSTR", "const WCHAR *"), + EQ("PDWORD", "DWORD *"), + EQ("PDWORD32", "DWORD32 *"), + EQ("PDWORD64", "DWORD64 *"), + EQ("PDWORDLONG", "DWORDLONG *"), + EQ("PDWORD_PTR", "DWORD_PTR *"), + EQ("PFLOAT", "FLOAT *"), + EQ("PHALF_PTR", "HALF_PTR *"), + EQ("PHANDLE", "HANDLE *"), + EQ("PHKEY", "HKEY *"), + EQ("PINT", "int *"), + EQ("PINT16", "INT16 *"), + EQ("PINT32", "INT32 *"), + EQ("PINT64", "INT64 *"), + EQ("PINT8", "INT8 *"), + EQ("PINT_PTR", "INT_PTR *"), + EQ("PLCID", "PDWORD"), + EQ("PLONG", "LONG *"), + EQ("PLONG32", "LONG32 *"), + EQ("PLONG64", "LONG64 *"), + EQ("PLONGLONG", "LONGLONG *"), + EQ("PLONG_PTR", "LONG_PTR *"), + EQ("PSHORT", "SHORT *"), + EQ("PSIZE_T", "SIZE_T *"), + EQ("PSSIZE_T", "SSIZE_T *"), + EQ("PSTR", "CHAR *"), + EQ("PUCHAR", "UCHAR *"), + EQ("PUHALF_PTR", "UHALF_PTR *"), + EQ("PUINT", "UINT *"), + EQ("PUINT16", "UINT16 *"), + EQ("PUINT32", "UINT32 *"), + EQ("PUINT64", "UINT64 *"), + EQ("PUINT8", "UINT8 *"), + EQ("PUINT_PTR", "UINT_PTR *"), + EQ("PULONG", "ULONG *"), + EQ("PULONG32", "ULONG32 *"), + EQ("PULONG64", "ULONG64 *"), + EQ("PULONGLONG", "ULONGLONG *"), + EQ("PULONG_PTR", "ULONG_PTR *"), + EQ("PUSHORT", "USHORT *"), + EQ("PVOID", "void *"), + EQ("PWCHAR", "WCHAR *"), + EQ("PWORD", "WORD *"), + EQ("PWSTR", "WCHAR *"), + EQ("QWORD", "unsigned long long"), + EQ("SC_HANDLE", "HANDLE"), + EQ("SC_LOCK", "LPVOID"), + EQ("SERVICE_STATUS_HANDLE", "HANDLE"), + EQ("SHORT", "short"), + EQ("SIZE_T", "ULONG_PTR"), + EQ("SSIZE_T", "LONG_PTR"), + EQ("UCHAR", "unsigned char"), + EQ("UHALF_PTR", W32_64("unsigned short","unsigned int")), + EQ("UINT", "unsigned int"), + EQ("UINT16", "unsigned short"), + EQ("UINT32", "unsigned int"), + EQ("UINT64", "unsigned long long"), + EQ("UINT8", "unsigned char"), + EQ("UINT_PTR", W32_64("unsigned int","unsigned long long")), + EQ("ULONG", "unsigned long"), + EQ("ULONG32", "unsigned int"), + EQ("ULONG64", "unsigned long long"), + EQ("ULONGLONG", "unsigned long long"), + EQ("ULONG_PTR", W32_64("unsigned long","unsigned long long")), + EQ("USHORT", "unsigned short"), + EQ("USN", "LONGLONG"), + EQ("VOID", "void"), + EQ("WCHAR", "wchar_t"), + EQ("WINSTA", "HANDLE"), + EQ("WORD", "unsigned short"), + EQ("WPARAM", "UINT_PTR"), +#endif + + EQ("bool", "_Bool"), +}; + + +#undef EQ +#undef W32_64 + +#define num_common_simple_types \ + (sizeof(common_simple_types) / sizeof(common_simple_types[0])) + + +static const char *get_common_type(const char *search, size_t search_len) +{ + const char *entry; + int index = search_sorted(common_simple_types, sizeof(const char *), + num_common_simple_types, search, search_len); + if (index < 0) + return NULL; + + entry = common_simple_types[index]; + return entry + strlen(entry) + 1; +} + +static PyObject *b__get_common_types(PyObject *self, PyObject *arg) +{ + int err; + size_t i; + for (i = 0; i < num_common_simple_types; i++) { + const char *s = common_simple_types[i]; + PyObject *o = PyText_FromString(s + strlen(s) + 1); + if (o == NULL) + return NULL; + err = PyDict_SetItemString(arg, s, o); + Py_DECREF(o); + if (err < 0) + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} diff --git a/contrib/python/cffi/c/ffi_obj.c b/contrib/python/cffi/c/ffi_obj.c index f154146621..d3b29dbf88 100644 --- a/contrib/python/cffi/c/ffi_obj.c +++ b/contrib/python/cffi/c/ffi_obj.c @@ -1,705 +1,705 @@ - -/* An FFI object has methods like ffi.new(). It is also a container - for the type declarations (typedefs and structs) that you can use, - say in ffi.new(). - - CTypeDescrObjects are internally stored in the dict 'types_dict'. - The types_dict is lazily filled with CTypeDescrObjects made from - reading a _cffi_type_context_s structure. - - In "modern" mode, the FFI instance is made by the C extension - module originally created by recompile(). The _cffi_type_context_s - structure comes from global data in the C extension module. - - In "compatibility" mode, an FFI instance is created explicitly by - the user, and its _cffi_type_context_s is initially empty. You - need to call ffi.cdef() to add more information to it. -*/ - -#define FFI_COMPLEXITY_OUTPUT 1200 /* xxx should grow as needed */ - -#define FFIObject_Check(op) PyObject_TypeCheck(op, &FFI_Type) -#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type)) - -struct FFIObject_s { - PyObject_HEAD - PyObject *gc_wrefs, *gc_wrefs_freelist; - PyObject *init_once_cache; - struct _cffi_parse_info_s info; - char ctx_is_static, ctx_is_nonempty; - builder_c_t types_builder; -}; - -static FFIObject *ffi_internal_new(PyTypeObject *ffitype, - const struct _cffi_type_context_s *static_ctx) -{ - static _cffi_opcode_t internal_output[FFI_COMPLEXITY_OUTPUT]; - - FFIObject *ffi; - if (static_ctx != NULL) { - ffi = (FFIObject *)PyObject_GC_New(FFIObject, ffitype); - /* we don't call PyObject_GC_Track() here: from _cffi_init_module() - it is not needed, because in this case the ffi object is immortal */ - } - else { - ffi = (FFIObject *)ffitype->tp_alloc(ffitype, 0); - } - if (ffi == NULL) - return NULL; - - if (init_builder_c(&ffi->types_builder, static_ctx) < 0) { - Py_DECREF(ffi); - return NULL; - } - ffi->gc_wrefs = NULL; - ffi->gc_wrefs_freelist = NULL; - ffi->init_once_cache = NULL; - ffi->info.ctx = &ffi->types_builder.ctx; - ffi->info.output = internal_output; - ffi->info.output_size = FFI_COMPLEXITY_OUTPUT; - ffi->ctx_is_static = (static_ctx != NULL); - ffi->ctx_is_nonempty = (static_ctx != NULL); - return ffi; -} - -static void ffi_dealloc(FFIObject *ffi) -{ - PyObject_GC_UnTrack(ffi); - Py_XDECREF(ffi->gc_wrefs); - Py_XDECREF(ffi->gc_wrefs_freelist); - Py_XDECREF(ffi->init_once_cache); - - free_builder_c(&ffi->types_builder, ffi->ctx_is_static); - - Py_TYPE(ffi)->tp_free((PyObject *)ffi); -} - -static int ffi_traverse(FFIObject *ffi, visitproc visit, void *arg) -{ - Py_VISIT(ffi->types_builder.types_dict); - Py_VISIT(ffi->types_builder.included_ffis); - Py_VISIT(ffi->types_builder.included_libs); - Py_VISIT(ffi->gc_wrefs); - return 0; -} - -static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - /* user-facing initialization code, for explicit FFI() calls */ - return (PyObject *)ffi_internal_new(type, NULL); -} - -/* forward, declared in cdlopen.c because it's mostly useful for this case */ -static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds); - + +/* An FFI object has methods like ffi.new(). It is also a container + for the type declarations (typedefs and structs) that you can use, + say in ffi.new(). + + CTypeDescrObjects are internally stored in the dict 'types_dict'. + The types_dict is lazily filled with CTypeDescrObjects made from + reading a _cffi_type_context_s structure. + + In "modern" mode, the FFI instance is made by the C extension + module originally created by recompile(). The _cffi_type_context_s + structure comes from global data in the C extension module. + + In "compatibility" mode, an FFI instance is created explicitly by + the user, and its _cffi_type_context_s is initially empty. You + need to call ffi.cdef() to add more information to it. +*/ + +#define FFI_COMPLEXITY_OUTPUT 1200 /* xxx should grow as needed */ + +#define FFIObject_Check(op) PyObject_TypeCheck(op, &FFI_Type) +#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type)) + +struct FFIObject_s { + PyObject_HEAD + PyObject *gc_wrefs, *gc_wrefs_freelist; + PyObject *init_once_cache; + struct _cffi_parse_info_s info; + char ctx_is_static, ctx_is_nonempty; + builder_c_t types_builder; +}; + +static FFIObject *ffi_internal_new(PyTypeObject *ffitype, + const struct _cffi_type_context_s *static_ctx) +{ + static _cffi_opcode_t internal_output[FFI_COMPLEXITY_OUTPUT]; + + FFIObject *ffi; + if (static_ctx != NULL) { + ffi = (FFIObject *)PyObject_GC_New(FFIObject, ffitype); + /* we don't call PyObject_GC_Track() here: from _cffi_init_module() + it is not needed, because in this case the ffi object is immortal */ + } + else { + ffi = (FFIObject *)ffitype->tp_alloc(ffitype, 0); + } + if (ffi == NULL) + return NULL; + + if (init_builder_c(&ffi->types_builder, static_ctx) < 0) { + Py_DECREF(ffi); + return NULL; + } + ffi->gc_wrefs = NULL; + ffi->gc_wrefs_freelist = NULL; + ffi->init_once_cache = NULL; + ffi->info.ctx = &ffi->types_builder.ctx; + ffi->info.output = internal_output; + ffi->info.output_size = FFI_COMPLEXITY_OUTPUT; + ffi->ctx_is_static = (static_ctx != NULL); + ffi->ctx_is_nonempty = (static_ctx != NULL); + return ffi; +} + +static void ffi_dealloc(FFIObject *ffi) +{ + PyObject_GC_UnTrack(ffi); + Py_XDECREF(ffi->gc_wrefs); + Py_XDECREF(ffi->gc_wrefs_freelist); + Py_XDECREF(ffi->init_once_cache); + + free_builder_c(&ffi->types_builder, ffi->ctx_is_static); + + Py_TYPE(ffi)->tp_free((PyObject *)ffi); +} + +static int ffi_traverse(FFIObject *ffi, visitproc visit, void *arg) +{ + Py_VISIT(ffi->types_builder.types_dict); + Py_VISIT(ffi->types_builder.included_ffis); + Py_VISIT(ffi->types_builder.included_libs); + Py_VISIT(ffi->gc_wrefs); + return 0; +} + +static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + /* user-facing initialization code, for explicit FFI() calls */ + return (PyObject *)ffi_internal_new(type, NULL); +} + +/* forward, declared in cdlopen.c because it's mostly useful for this case */ +static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds); + static PyObject *ffi_fetch_int_constant(FFIObject *ffi, const char *name, - int recursion) -{ - int index; - - index = search_in_globals(&ffi->types_builder.ctx, name, strlen(name)); - if (index >= 0) { - const struct _cffi_global_s *g; - g = &ffi->types_builder.ctx.globals[index]; - - switch (_CFFI_GETOP(g->type_op)) { - case _CFFI_OP_CONSTANT_INT: - case _CFFI_OP_ENUM: - return realize_global_int(&ffi->types_builder, index); - - default: - PyErr_Format(FFIError, - "function, global variable or non-integer constant " - "'%.200s' must be fetched from its original 'lib' " - "object", name); - return NULL; - } - } - - if (ffi->types_builder.included_ffis != NULL) { - Py_ssize_t i; - PyObject *included_ffis = ffi->types_builder.included_ffis; - - if (recursion > 100) { - PyErr_SetString(PyExc_RuntimeError, - "recursion overflow in ffi.include() delegations"); - return NULL; - } - - for (i = 0; i < PyTuple_GET_SIZE(included_ffis); i++) { - FFIObject *ffi1; - PyObject *x; - - ffi1 = (FFIObject *)PyTuple_GET_ITEM(included_ffis, i); - x = ffi_fetch_int_constant(ffi1, name, recursion + 1); - if (x != NULL || PyErr_Occurred()) - return x; - } - } - return NULL; /* no exception set, means "not found" */ -} - -#define ACCEPT_STRING 1 -#define ACCEPT_CTYPE 2 -#define ACCEPT_CDATA 4 -#define ACCEPT_ALL (ACCEPT_STRING | ACCEPT_CTYPE | ACCEPT_CDATA) -#define CONSIDER_FN_AS_FNPTR 8 - + int recursion) +{ + int index; + + index = search_in_globals(&ffi->types_builder.ctx, name, strlen(name)); + if (index >= 0) { + const struct _cffi_global_s *g; + g = &ffi->types_builder.ctx.globals[index]; + + switch (_CFFI_GETOP(g->type_op)) { + case _CFFI_OP_CONSTANT_INT: + case _CFFI_OP_ENUM: + return realize_global_int(&ffi->types_builder, index); + + default: + PyErr_Format(FFIError, + "function, global variable or non-integer constant " + "'%.200s' must be fetched from its original 'lib' " + "object", name); + return NULL; + } + } + + if (ffi->types_builder.included_ffis != NULL) { + Py_ssize_t i; + PyObject *included_ffis = ffi->types_builder.included_ffis; + + if (recursion > 100) { + PyErr_SetString(PyExc_RuntimeError, + "recursion overflow in ffi.include() delegations"); + return NULL; + } + + for (i = 0; i < PyTuple_GET_SIZE(included_ffis); i++) { + FFIObject *ffi1; + PyObject *x; + + ffi1 = (FFIObject *)PyTuple_GET_ITEM(included_ffis, i); + x = ffi_fetch_int_constant(ffi1, name, recursion + 1); + if (x != NULL || PyErr_Occurred()) + return x; + } + } + return NULL; /* no exception set, means "not found" */ +} + +#define ACCEPT_STRING 1 +#define ACCEPT_CTYPE 2 +#define ACCEPT_CDATA 4 +#define ACCEPT_ALL (ACCEPT_STRING | ACCEPT_CTYPE | ACCEPT_CDATA) +#define CONSIDER_FN_AS_FNPTR 8 + static CTypeDescrObject *_ffi_bad_type(FFIObject *ffi, const char *input_text) -{ - size_t length = strlen(input_text); - char *extra; - - if (length > 500) { - extra = ""; - } - else { - char *p; - size_t i, num_spaces = ffi->info.error_location; - extra = alloca(length + num_spaces + 4); - p = extra; - *p++ = '\n'; - for (i = 0; i < length; i++) { - if (' ' <= input_text[i] && input_text[i] < 0x7f) - *p++ = input_text[i]; - else if (input_text[i] == '\t' || input_text[i] == '\n') - *p++ = ' '; - else - *p++ = '?'; - } - *p++ = '\n'; - memset(p, ' ', num_spaces); - p += num_spaces; - *p++ = '^'; - *p++ = 0; - } - PyErr_Format(FFIError, "%s%s", ffi->info.error_message, extra); - return NULL; -} - -static CTypeDescrObject *_ffi_type(FFIObject *ffi, PyObject *arg, - int accept) -{ - /* Returns the CTypeDescrObject from the user-supplied 'arg'. - Does not return a new reference! - */ - if ((accept & ACCEPT_STRING) && PyText_Check(arg)) { - PyObject *types_dict = ffi->types_builder.types_dict; - PyObject *x = PyDict_GetItem(types_dict, arg); - - if (x == NULL) { +{ + size_t length = strlen(input_text); + char *extra; + + if (length > 500) { + extra = ""; + } + else { + char *p; + size_t i, num_spaces = ffi->info.error_location; + extra = alloca(length + num_spaces + 4); + p = extra; + *p++ = '\n'; + for (i = 0; i < length; i++) { + if (' ' <= input_text[i] && input_text[i] < 0x7f) + *p++ = input_text[i]; + else if (input_text[i] == '\t' || input_text[i] == '\n') + *p++ = ' '; + else + *p++ = '?'; + } + *p++ = '\n'; + memset(p, ' ', num_spaces); + p += num_spaces; + *p++ = '^'; + *p++ = 0; + } + PyErr_Format(FFIError, "%s%s", ffi->info.error_message, extra); + return NULL; +} + +static CTypeDescrObject *_ffi_type(FFIObject *ffi, PyObject *arg, + int accept) +{ + /* Returns the CTypeDescrObject from the user-supplied 'arg'. + Does not return a new reference! + */ + if ((accept & ACCEPT_STRING) && PyText_Check(arg)) { + PyObject *types_dict = ffi->types_builder.types_dict; + PyObject *x = PyDict_GetItem(types_dict, arg); + + if (x == NULL) { const char *input_text = PyText_AS_UTF8(arg); - int err, index = parse_c_type(&ffi->info, input_text); - if (index < 0) - return _ffi_bad_type(ffi, input_text); - - x = realize_c_type_or_func(&ffi->types_builder, - ffi->info.output, index); - if (x == NULL) - return NULL; - - /* Cache under the name given by 'arg', in addition to the - fact that the same ct is probably already cached under - its standardized name. In a few cases, it is not, e.g. - if it is a primitive; for the purpose of this function, - the important point is the following line, which makes - sure that in any case the next _ffi_type() with the same - 'arg' will succeed early, in PyDict_GetItem() above. - */ - err = PyDict_SetItem(types_dict, arg, x); - Py_DECREF(x); /* we know it was written in types_dict (unless out - of mem), so there is at least that ref left */ - if (err < 0) - return NULL; - } - - if (CTypeDescr_Check(x)) - return (CTypeDescrObject *)x; - else if (accept & CONSIDER_FN_AS_FNPTR) - return unwrap_fn_as_fnptr(x); - else - return unexpected_fn_type(x); - } - else if ((accept & ACCEPT_CTYPE) && CTypeDescr_Check(arg)) { - return (CTypeDescrObject *)arg; - } - else if ((accept & ACCEPT_CDATA) && CData_Check(arg)) { - return ((CDataObject *)arg)->c_type; - } -#if PY_MAJOR_VERSION < 3 - else if (PyUnicode_Check(arg)) { - CTypeDescrObject *result; - arg = PyUnicode_AsASCIIString(arg); - if (arg == NULL) - return NULL; - result = _ffi_type(ffi, arg, accept); - Py_DECREF(arg); - return result; - } -#endif - else { - const char *m1 = (accept & ACCEPT_STRING) ? "string" : ""; - const char *m2 = (accept & ACCEPT_CTYPE) ? "ctype object" : ""; - const char *m3 = (accept & ACCEPT_CDATA) ? "cdata object" : ""; - const char *s12 = (*m1 && (*m2 || *m3)) ? " or " : ""; - const char *s23 = (*m2 && *m3) ? " or " : ""; - PyErr_Format(PyExc_TypeError, "expected a %s%s%s%s%s, got '%.200s'", - m1, s12, m2, s23, m3, - Py_TYPE(arg)->tp_name); - return NULL; - } -} - -PyDoc_STRVAR(ffi_sizeof_doc, -"Return the size in bytes of the argument.\n" -"It can be a string naming a C type, or a 'cdata' instance."); - -static PyObject *ffi_sizeof(FFIObject *self, PyObject *arg) -{ - Py_ssize_t size; - - if (CData_Check(arg)) { - size = direct_sizeof_cdata((CDataObject *)arg); - } - else { - CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL); - if (ct == NULL) - return NULL; - size = ct->ct_size; - if (size < 0) { - PyErr_Format(FFIError, "don't know the size of ctype '%s'", - ct->ct_name); - return NULL; - } - } - return PyInt_FromSsize_t(size); -} - -PyDoc_STRVAR(ffi_alignof_doc, -"Return the natural alignment size in bytes of the argument.\n" -"It can be a string naming a C type, or a 'cdata' instance."); - -static PyObject *ffi_alignof(FFIObject *self, PyObject *arg) -{ - int align; - CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL); - if (ct == NULL) - return NULL; - - align = get_alignment(ct); - if (align < 0) - return NULL; - return PyInt_FromLong(align); -} - -PyDoc_STRVAR(ffi_typeof_doc, -"Parse the C type given as a string and return the\n" -"corresponding <ctype> object.\n" -"It can also be used on 'cdata' instance to get its C type."); - -static PyObject *_cpyextfunc_type_index(PyObject *x); /* forward */ - -static PyObject *ffi_typeof(FFIObject *self, PyObject *arg) -{ - PyObject *x = (PyObject *)_ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CDATA); - if (x != NULL) { - Py_INCREF(x); - } - else { - x = _cpyextfunc_type_index(arg); - } - return x; -} - -PyDoc_STRVAR(ffi_new_doc, -"Allocate an instance according to the specified C type and return a\n" -"pointer to it. The specified C type must be either a pointer or an\n" -"array: ``new('X *')`` allocates an X and returns a pointer to it,\n" -"whereas ``new('X[n]')`` allocates an array of n X'es and returns an\n" -"array referencing it (which works mostly like a pointer, like in C).\n" -"You can also use ``new('X[]', n)`` to allocate an array of a\n" -"non-constant length n.\n" -"\n" -"The memory is initialized following the rules of declaring a global\n" -"variable in C: by default it is zero-initialized, but an explicit\n" -"initializer can be given which can be used to fill all or part of the\n" -"memory.\n" -"\n" -"When the returned <cdata> object goes out of scope, the memory is\n" -"freed. In other words the returned <cdata> object has ownership of\n" -"the value of type 'cdecl' that it points to. This means that the raw\n" -"data can be used as long as this object is kept alive, but must not be\n" -"used for a longer time. Be careful about that when copying the\n" -"pointer to the memory somewhere else, e.g. into another structure."); - -static PyObject *_ffi_new(FFIObject *self, PyObject *args, PyObject *kwds, - const cffi_allocator_t *allocator) -{ - CTypeDescrObject *ct; - PyObject *arg, *init = Py_None; - static char *keywords[] = {"cdecl", "init", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:new", keywords, - &arg, &init)) - return NULL; - - ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - - return direct_newp(ct, init, allocator); -} - -static PyObject *ffi_new(FFIObject *self, PyObject *args, PyObject *kwds) -{ - return _ffi_new(self, args, kwds, &default_allocator); -} - -static PyObject *_ffi_new_with_allocator(PyObject *allocator, PyObject *args, - PyObject *kwds) -{ - cffi_allocator_t alloc1; - PyObject *my_alloc, *my_free; - my_alloc = PyTuple_GET_ITEM(allocator, 1); - my_free = PyTuple_GET_ITEM(allocator, 2); - alloc1.ca_alloc = (my_alloc == Py_None ? NULL : my_alloc); - alloc1.ca_free = (my_free == Py_None ? NULL : my_free); - alloc1.ca_dont_clear = (PyTuple_GET_ITEM(allocator, 3) == Py_False); - - return _ffi_new((FFIObject *)PyTuple_GET_ITEM(allocator, 0), - args, kwds, &alloc1); -} - -PyDoc_STRVAR(ffi_new_allocator_doc, -"Return a new allocator, i.e. a function that behaves like ffi.new()\n" -"but uses the provided low-level 'alloc' and 'free' functions.\n" -"\n" -"'alloc' is called with the size as argument. If it returns NULL, a\n" -"MemoryError is raised. 'free' is called with the result of 'alloc'\n" -"as argument. Both can be either Python functions or directly C\n" -"functions. If 'free' is None, then no free function is called.\n" -"If both 'alloc' and 'free' are None, the default is used.\n" -"\n" -"If 'should_clear_after_alloc' is set to False, then the memory\n" -"returned by 'alloc' is assumed to be already cleared (or you are\n" -"fine with garbage); otherwise CFFI will clear it."); - -static PyObject *ffi_new_allocator(FFIObject *self, PyObject *args, - PyObject *kwds) -{ - PyObject *allocator, *result; - PyObject *my_alloc = Py_None, *my_free = Py_None; - int should_clear_after_alloc = 1; - static char *keywords[] = {"alloc", "free", "should_clear_after_alloc", - NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:new_allocator", keywords, - &my_alloc, &my_free, - &should_clear_after_alloc)) - return NULL; - - if (my_alloc == Py_None && my_free != Py_None) { - PyErr_SetString(PyExc_TypeError, "cannot pass 'free' without 'alloc'"); - return NULL; - } - - allocator = PyTuple_Pack(4, - (PyObject *)self, - my_alloc, - my_free, - PyBool_FromLong(should_clear_after_alloc)); - if (allocator == NULL) - return NULL; - - { - static PyMethodDef md = {"allocator", - (PyCFunction)_ffi_new_with_allocator, - METH_VARARGS | METH_KEYWORDS}; - result = PyCFunction_New(&md, allocator); - } - Py_DECREF(allocator); - return result; -} - -PyDoc_STRVAR(ffi_cast_doc, -"Similar to a C cast: returns an instance of the named C\n" -"type initialized with the given 'source'. The source is\n" -"casted between integers or pointers of any type."); - -static PyObject *ffi_cast(FFIObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *ob, *arg; - if (!PyArg_ParseTuple(args, "OO:cast", &arg, &ob)) - return NULL; - - ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - - return do_cast(ct, ob); -} - -PyDoc_STRVAR(ffi_string_doc, -"Return a Python string (or unicode string) from the 'cdata'. If\n" -"'cdata' is a pointer or array of characters or bytes, returns the\n" -"null-terminated string. The returned string extends until the first\n" -"null character, or at most 'maxlen' characters. If 'cdata' is an\n" -"array then 'maxlen' defaults to its length.\n" -"\n" -"If 'cdata' is a pointer or array of wchar_t, returns a unicode string\n" -"following the same rules.\n" -"\n" -"If 'cdata' is a single character or byte or a wchar_t, returns it as a\n" -"string or unicode string.\n" -"\n" -"If 'cdata' is an enum, returns the value of the enumerator as a\n" -"string, or 'NUMBER' if the value is out of range."); - -#define ffi_string b_string /* ffi_string() => b_string() - from _cffi_backend.c */ - -PyDoc_STRVAR(ffi_unpack_doc, -"Unpack an array of C data of the given length,\n" -"returning a Python string/unicode/list.\n" -"\n" -"If 'cdata' is a pointer to 'char', returns a byte string.\n" -"It does not stop at the first null. This is equivalent to:\n" -"ffi.buffer(cdata, length)[:]\n" -"\n" -"If 'cdata' is a pointer to 'wchar_t', returns a unicode string.\n" -"'length' is measured in wchar_t's; it is not the size in bytes.\n" -"\n" -"If 'cdata' is a pointer to anything else, returns a list of\n" -"'length' items. This is a faster equivalent to:\n" -"[cdata[i] for i in range(length)]"); - -#define ffi_unpack b_unpack /* ffi_unpack() => b_unpack() - from _cffi_backend.c */ - - -PyDoc_STRVAR(ffi_offsetof_doc, -"Return the offset of the named field inside the given structure or\n" -"array, which must be given as a C type name. You can give several\n" -"field names in case of nested structures. You can also give numeric\n" -"values which correspond to array items, in case of an array type."); - -static PyObject *ffi_offsetof(FFIObject *self, PyObject *args) -{ - PyObject *arg; - CTypeDescrObject *ct; - Py_ssize_t i, offset; - - if (PyTuple_Size(args) < 2) { - PyErr_SetString(PyExc_TypeError, - "offsetof() expects at least 2 arguments"); - return NULL; - } - - arg = PyTuple_GET_ITEM(args, 0); - ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - - offset = 0; - for (i = 1; i < PyTuple_GET_SIZE(args); i++) { - Py_ssize_t ofs1; - ct = direct_typeoffsetof(ct, PyTuple_GET_ITEM(args, i), i > 1, &ofs1); - if (ct == NULL) - return NULL; - offset += ofs1; - } - return PyInt_FromSsize_t(offset); -} - -PyDoc_STRVAR(ffi_addressof_doc, -"Limited equivalent to the '&' operator in C:\n" -"\n" -"1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a\n" -"pointer to this struct or union.\n" -"\n" -"2. ffi.addressof(<cdata>, field-or-index...) returns the address of a\n" -"field or array item inside the given structure or array, recursively\n" -"in case of nested structures or arrays.\n" -"\n" -"3. ffi.addressof(<library>, \"name\") returns the address of the named\n" -"function or global variable."); - -static PyObject *address_of_global_var(PyObject *args); /* forward */ - -static PyObject *ffi_addressof(FFIObject *self, PyObject *args) -{ - PyObject *arg, *z, *result; - CTypeDescrObject *ct; - Py_ssize_t i, offset = 0; - int accepted_flags; - - if (PyTuple_Size(args) < 1) { - PyErr_SetString(PyExc_TypeError, - "addressof() expects at least 1 argument"); - return NULL; - } - - arg = PyTuple_GET_ITEM(args, 0); - if (LibObject_Check(arg)) { - /* case 3 in the docstring */ - return address_of_global_var(args); - } - - ct = _ffi_type(self, arg, ACCEPT_CDATA); - if (ct == NULL) - return NULL; - - if (PyTuple_GET_SIZE(args) == 1) { - /* case 1 in the docstring */ - accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY; - if ((ct->ct_flags & accepted_flags) == 0) { - PyErr_SetString(PyExc_TypeError, - "expected a cdata struct/union/array object"); - return NULL; - } - } - else { - /* case 2 in the docstring */ - accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER; - if ((ct->ct_flags & accepted_flags) == 0) { - PyErr_SetString(PyExc_TypeError, - "expected a cdata struct/union/array/pointer object"); - return NULL; - } - for (i = 1; i < PyTuple_GET_SIZE(args); i++) { - Py_ssize_t ofs1; - ct = direct_typeoffsetof(ct, PyTuple_GET_ITEM(args, i), - i > 1, &ofs1); - if (ct == NULL) - return NULL; - offset += ofs1; - } - } - - z = new_pointer_type(ct); - if (z == NULL) - return NULL; - - result = new_simple_cdata(((CDataObject *)arg)->c_data + offset, - (CTypeDescrObject *)z); - Py_DECREF(z); - return result; -} - -static PyObject *_combine_type_name_l(CTypeDescrObject *ct, - size_t extra_text_len) -{ - size_t base_name_len; - PyObject *result; - char *p; - - base_name_len = strlen(ct->ct_name); - result = PyBytes_FromStringAndSize(NULL, base_name_len + extra_text_len); - if (result == NULL) - return NULL; - - p = PyBytes_AS_STRING(result); - memcpy(p, ct->ct_name, ct->ct_name_position); - p += ct->ct_name_position; - p += extra_text_len; - memcpy(p, ct->ct_name + ct->ct_name_position, - base_name_len - ct->ct_name_position); - return result; -} - -PyDoc_STRVAR(ffi_getctype_doc, -"Return a string giving the C type 'cdecl', which may be itself a\n" -"string or a <ctype> object. If 'replace_with' is given, it gives\n" -"extra text to append (or insert for more complicated C types), like a\n" -"variable name, or '*' to get actually the C type 'pointer-to-cdecl'."); - -static PyObject *ffi_getctype(FFIObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *c_decl, *res; - char *p, *replace_with = ""; - int add_paren, add_space; - CTypeDescrObject *ct; - size_t replace_with_len; - static char *keywords[] = {"cdecl", "replace_with", NULL}; -#if PY_MAJOR_VERSION >= 3 - PyObject *u; -#endif - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s:getctype", keywords, - &c_decl, &replace_with)) - return NULL; - - ct = _ffi_type(self, c_decl, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - - while (replace_with[0] != 0 && isspace(replace_with[0])) - replace_with++; - replace_with_len = strlen(replace_with); - while (replace_with_len > 0 && isspace(replace_with[replace_with_len - 1])) - replace_with_len--; - - add_paren = (replace_with[0] == '*' && - ((ct->ct_flags & CT_ARRAY) != 0)); - add_space = (!add_paren && replace_with_len > 0 && - replace_with[0] != '[' && replace_with[0] != '('); - - res = _combine_type_name_l(ct, replace_with_len + add_space + 2*add_paren); - if (res == NULL) - return NULL; - - p = PyBytes_AS_STRING(res) + ct->ct_name_position; - if (add_paren) - *p++ = '('; - if (add_space) - *p++ = ' '; - memcpy(p, replace_with, replace_with_len); - if (add_paren) - p[replace_with_len] = ')'; - -#if PY_MAJOR_VERSION >= 3 - /* bytes -> unicode string */ - u = PyUnicode_DecodeLatin1(PyBytes_AS_STRING(res), - PyBytes_GET_SIZE(res), - NULL); - Py_DECREF(res); - res = u; -#endif - - return res; -} - -PyDoc_STRVAR(ffi_new_handle_doc, -"Return a non-NULL cdata of type 'void *' that contains an opaque\n" -"reference to the argument, which can be any Python object. To cast it\n" -"back to the original object, use from_handle(). You must keep alive\n" -"the cdata object returned by new_handle()!"); - -static PyObject *ffi_new_handle(FFIObject *self, PyObject *arg) -{ - /* g_ct_voidp is equal to <ctype 'void *'> */ - return newp_handle(g_ct_voidp, arg); -} - -PyDoc_STRVAR(ffi_from_handle_doc, -"Cast a 'void *' back to a Python object. Must be used *only* on the\n" -"pointers returned by new_handle(), and *only* as long as the exact\n" -"cdata object returned by new_handle() is still alive (somewhere else\n" -"in the program). Failure to follow these rules will crash."); - -#define ffi_from_handle b_from_handle /* ffi_from_handle => b_from_handle - from _cffi_backend.c */ - -PyDoc_STRVAR(ffi_from_buffer_doc, -"Return a <cdata 'char[]'> that points to the data of the given Python\n" -"object, which must support the buffer interface. Note that this is\n" -"not meant to be used on the built-in types str or unicode\n" -"(you can build 'char[]' arrays explicitly) but only on objects\n" -"containing large quantities of raw data in some other format, like\n" -"'array.array' or numpy arrays."); - + int err, index = parse_c_type(&ffi->info, input_text); + if (index < 0) + return _ffi_bad_type(ffi, input_text); + + x = realize_c_type_or_func(&ffi->types_builder, + ffi->info.output, index); + if (x == NULL) + return NULL; + + /* Cache under the name given by 'arg', in addition to the + fact that the same ct is probably already cached under + its standardized name. In a few cases, it is not, e.g. + if it is a primitive; for the purpose of this function, + the important point is the following line, which makes + sure that in any case the next _ffi_type() with the same + 'arg' will succeed early, in PyDict_GetItem() above. + */ + err = PyDict_SetItem(types_dict, arg, x); + Py_DECREF(x); /* we know it was written in types_dict (unless out + of mem), so there is at least that ref left */ + if (err < 0) + return NULL; + } + + if (CTypeDescr_Check(x)) + return (CTypeDescrObject *)x; + else if (accept & CONSIDER_FN_AS_FNPTR) + return unwrap_fn_as_fnptr(x); + else + return unexpected_fn_type(x); + } + else if ((accept & ACCEPT_CTYPE) && CTypeDescr_Check(arg)) { + return (CTypeDescrObject *)arg; + } + else if ((accept & ACCEPT_CDATA) && CData_Check(arg)) { + return ((CDataObject *)arg)->c_type; + } +#if PY_MAJOR_VERSION < 3 + else if (PyUnicode_Check(arg)) { + CTypeDescrObject *result; + arg = PyUnicode_AsASCIIString(arg); + if (arg == NULL) + return NULL; + result = _ffi_type(ffi, arg, accept); + Py_DECREF(arg); + return result; + } +#endif + else { + const char *m1 = (accept & ACCEPT_STRING) ? "string" : ""; + const char *m2 = (accept & ACCEPT_CTYPE) ? "ctype object" : ""; + const char *m3 = (accept & ACCEPT_CDATA) ? "cdata object" : ""; + const char *s12 = (*m1 && (*m2 || *m3)) ? " or " : ""; + const char *s23 = (*m2 && *m3) ? " or " : ""; + PyErr_Format(PyExc_TypeError, "expected a %s%s%s%s%s, got '%.200s'", + m1, s12, m2, s23, m3, + Py_TYPE(arg)->tp_name); + return NULL; + } +} + +PyDoc_STRVAR(ffi_sizeof_doc, +"Return the size in bytes of the argument.\n" +"It can be a string naming a C type, or a 'cdata' instance."); + +static PyObject *ffi_sizeof(FFIObject *self, PyObject *arg) +{ + Py_ssize_t size; + + if (CData_Check(arg)) { + size = direct_sizeof_cdata((CDataObject *)arg); + } + else { + CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL); + if (ct == NULL) + return NULL; + size = ct->ct_size; + if (size < 0) { + PyErr_Format(FFIError, "don't know the size of ctype '%s'", + ct->ct_name); + return NULL; + } + } + return PyInt_FromSsize_t(size); +} + +PyDoc_STRVAR(ffi_alignof_doc, +"Return the natural alignment size in bytes of the argument.\n" +"It can be a string naming a C type, or a 'cdata' instance."); + +static PyObject *ffi_alignof(FFIObject *self, PyObject *arg) +{ + int align; + CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL); + if (ct == NULL) + return NULL; + + align = get_alignment(ct); + if (align < 0) + return NULL; + return PyInt_FromLong(align); +} + +PyDoc_STRVAR(ffi_typeof_doc, +"Parse the C type given as a string and return the\n" +"corresponding <ctype> object.\n" +"It can also be used on 'cdata' instance to get its C type."); + +static PyObject *_cpyextfunc_type_index(PyObject *x); /* forward */ + +static PyObject *ffi_typeof(FFIObject *self, PyObject *arg) +{ + PyObject *x = (PyObject *)_ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CDATA); + if (x != NULL) { + Py_INCREF(x); + } + else { + x = _cpyextfunc_type_index(arg); + } + return x; +} + +PyDoc_STRVAR(ffi_new_doc, +"Allocate an instance according to the specified C type and return a\n" +"pointer to it. The specified C type must be either a pointer or an\n" +"array: ``new('X *')`` allocates an X and returns a pointer to it,\n" +"whereas ``new('X[n]')`` allocates an array of n X'es and returns an\n" +"array referencing it (which works mostly like a pointer, like in C).\n" +"You can also use ``new('X[]', n)`` to allocate an array of a\n" +"non-constant length n.\n" +"\n" +"The memory is initialized following the rules of declaring a global\n" +"variable in C: by default it is zero-initialized, but an explicit\n" +"initializer can be given which can be used to fill all or part of the\n" +"memory.\n" +"\n" +"When the returned <cdata> object goes out of scope, the memory is\n" +"freed. In other words the returned <cdata> object has ownership of\n" +"the value of type 'cdecl' that it points to. This means that the raw\n" +"data can be used as long as this object is kept alive, but must not be\n" +"used for a longer time. Be careful about that when copying the\n" +"pointer to the memory somewhere else, e.g. into another structure."); + +static PyObject *_ffi_new(FFIObject *self, PyObject *args, PyObject *kwds, + const cffi_allocator_t *allocator) +{ + CTypeDescrObject *ct; + PyObject *arg, *init = Py_None; + static char *keywords[] = {"cdecl", "init", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:new", keywords, + &arg, &init)) + return NULL; + + ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); + if (ct == NULL) + return NULL; + + return direct_newp(ct, init, allocator); +} + +static PyObject *ffi_new(FFIObject *self, PyObject *args, PyObject *kwds) +{ + return _ffi_new(self, args, kwds, &default_allocator); +} + +static PyObject *_ffi_new_with_allocator(PyObject *allocator, PyObject *args, + PyObject *kwds) +{ + cffi_allocator_t alloc1; + PyObject *my_alloc, *my_free; + my_alloc = PyTuple_GET_ITEM(allocator, 1); + my_free = PyTuple_GET_ITEM(allocator, 2); + alloc1.ca_alloc = (my_alloc == Py_None ? NULL : my_alloc); + alloc1.ca_free = (my_free == Py_None ? NULL : my_free); + alloc1.ca_dont_clear = (PyTuple_GET_ITEM(allocator, 3) == Py_False); + + return _ffi_new((FFIObject *)PyTuple_GET_ITEM(allocator, 0), + args, kwds, &alloc1); +} + +PyDoc_STRVAR(ffi_new_allocator_doc, +"Return a new allocator, i.e. a function that behaves like ffi.new()\n" +"but uses the provided low-level 'alloc' and 'free' functions.\n" +"\n" +"'alloc' is called with the size as argument. If it returns NULL, a\n" +"MemoryError is raised. 'free' is called with the result of 'alloc'\n" +"as argument. Both can be either Python functions or directly C\n" +"functions. If 'free' is None, then no free function is called.\n" +"If both 'alloc' and 'free' are None, the default is used.\n" +"\n" +"If 'should_clear_after_alloc' is set to False, then the memory\n" +"returned by 'alloc' is assumed to be already cleared (or you are\n" +"fine with garbage); otherwise CFFI will clear it."); + +static PyObject *ffi_new_allocator(FFIObject *self, PyObject *args, + PyObject *kwds) +{ + PyObject *allocator, *result; + PyObject *my_alloc = Py_None, *my_free = Py_None; + int should_clear_after_alloc = 1; + static char *keywords[] = {"alloc", "free", "should_clear_after_alloc", + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:new_allocator", keywords, + &my_alloc, &my_free, + &should_clear_after_alloc)) + return NULL; + + if (my_alloc == Py_None && my_free != Py_None) { + PyErr_SetString(PyExc_TypeError, "cannot pass 'free' without 'alloc'"); + return NULL; + } + + allocator = PyTuple_Pack(4, + (PyObject *)self, + my_alloc, + my_free, + PyBool_FromLong(should_clear_after_alloc)); + if (allocator == NULL) + return NULL; + + { + static PyMethodDef md = {"allocator", + (PyCFunction)_ffi_new_with_allocator, + METH_VARARGS | METH_KEYWORDS}; + result = PyCFunction_New(&md, allocator); + } + Py_DECREF(allocator); + return result; +} + +PyDoc_STRVAR(ffi_cast_doc, +"Similar to a C cast: returns an instance of the named C\n" +"type initialized with the given 'source'. The source is\n" +"casted between integers or pointers of any type."); + +static PyObject *ffi_cast(FFIObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + PyObject *ob, *arg; + if (!PyArg_ParseTuple(args, "OO:cast", &arg, &ob)) + return NULL; + + ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); + if (ct == NULL) + return NULL; + + return do_cast(ct, ob); +} + +PyDoc_STRVAR(ffi_string_doc, +"Return a Python string (or unicode string) from the 'cdata'. If\n" +"'cdata' is a pointer or array of characters or bytes, returns the\n" +"null-terminated string. The returned string extends until the first\n" +"null character, or at most 'maxlen' characters. If 'cdata' is an\n" +"array then 'maxlen' defaults to its length.\n" +"\n" +"If 'cdata' is a pointer or array of wchar_t, returns a unicode string\n" +"following the same rules.\n" +"\n" +"If 'cdata' is a single character or byte or a wchar_t, returns it as a\n" +"string or unicode string.\n" +"\n" +"If 'cdata' is an enum, returns the value of the enumerator as a\n" +"string, or 'NUMBER' if the value is out of range."); + +#define ffi_string b_string /* ffi_string() => b_string() + from _cffi_backend.c */ + +PyDoc_STRVAR(ffi_unpack_doc, +"Unpack an array of C data of the given length,\n" +"returning a Python string/unicode/list.\n" +"\n" +"If 'cdata' is a pointer to 'char', returns a byte string.\n" +"It does not stop at the first null. This is equivalent to:\n" +"ffi.buffer(cdata, length)[:]\n" +"\n" +"If 'cdata' is a pointer to 'wchar_t', returns a unicode string.\n" +"'length' is measured in wchar_t's; it is not the size in bytes.\n" +"\n" +"If 'cdata' is a pointer to anything else, returns a list of\n" +"'length' items. This is a faster equivalent to:\n" +"[cdata[i] for i in range(length)]"); + +#define ffi_unpack b_unpack /* ffi_unpack() => b_unpack() + from _cffi_backend.c */ + + +PyDoc_STRVAR(ffi_offsetof_doc, +"Return the offset of the named field inside the given structure or\n" +"array, which must be given as a C type name. You can give several\n" +"field names in case of nested structures. You can also give numeric\n" +"values which correspond to array items, in case of an array type."); + +static PyObject *ffi_offsetof(FFIObject *self, PyObject *args) +{ + PyObject *arg; + CTypeDescrObject *ct; + Py_ssize_t i, offset; + + if (PyTuple_Size(args) < 2) { + PyErr_SetString(PyExc_TypeError, + "offsetof() expects at least 2 arguments"); + return NULL; + } + + arg = PyTuple_GET_ITEM(args, 0); + ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); + if (ct == NULL) + return NULL; + + offset = 0; + for (i = 1; i < PyTuple_GET_SIZE(args); i++) { + Py_ssize_t ofs1; + ct = direct_typeoffsetof(ct, PyTuple_GET_ITEM(args, i), i > 1, &ofs1); + if (ct == NULL) + return NULL; + offset += ofs1; + } + return PyInt_FromSsize_t(offset); +} + +PyDoc_STRVAR(ffi_addressof_doc, +"Limited equivalent to the '&' operator in C:\n" +"\n" +"1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a\n" +"pointer to this struct or union.\n" +"\n" +"2. ffi.addressof(<cdata>, field-or-index...) returns the address of a\n" +"field or array item inside the given structure or array, recursively\n" +"in case of nested structures or arrays.\n" +"\n" +"3. ffi.addressof(<library>, \"name\") returns the address of the named\n" +"function or global variable."); + +static PyObject *address_of_global_var(PyObject *args); /* forward */ + +static PyObject *ffi_addressof(FFIObject *self, PyObject *args) +{ + PyObject *arg, *z, *result; + CTypeDescrObject *ct; + Py_ssize_t i, offset = 0; + int accepted_flags; + + if (PyTuple_Size(args) < 1) { + PyErr_SetString(PyExc_TypeError, + "addressof() expects at least 1 argument"); + return NULL; + } + + arg = PyTuple_GET_ITEM(args, 0); + if (LibObject_Check(arg)) { + /* case 3 in the docstring */ + return address_of_global_var(args); + } + + ct = _ffi_type(self, arg, ACCEPT_CDATA); + if (ct == NULL) + return NULL; + + if (PyTuple_GET_SIZE(args) == 1) { + /* case 1 in the docstring */ + accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY; + if ((ct->ct_flags & accepted_flags) == 0) { + PyErr_SetString(PyExc_TypeError, + "expected a cdata struct/union/array object"); + return NULL; + } + } + else { + /* case 2 in the docstring */ + accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER; + if ((ct->ct_flags & accepted_flags) == 0) { + PyErr_SetString(PyExc_TypeError, + "expected a cdata struct/union/array/pointer object"); + return NULL; + } + for (i = 1; i < PyTuple_GET_SIZE(args); i++) { + Py_ssize_t ofs1; + ct = direct_typeoffsetof(ct, PyTuple_GET_ITEM(args, i), + i > 1, &ofs1); + if (ct == NULL) + return NULL; + offset += ofs1; + } + } + + z = new_pointer_type(ct); + if (z == NULL) + return NULL; + + result = new_simple_cdata(((CDataObject *)arg)->c_data + offset, + (CTypeDescrObject *)z); + Py_DECREF(z); + return result; +} + +static PyObject *_combine_type_name_l(CTypeDescrObject *ct, + size_t extra_text_len) +{ + size_t base_name_len; + PyObject *result; + char *p; + + base_name_len = strlen(ct->ct_name); + result = PyBytes_FromStringAndSize(NULL, base_name_len + extra_text_len); + if (result == NULL) + return NULL; + + p = PyBytes_AS_STRING(result); + memcpy(p, ct->ct_name, ct->ct_name_position); + p += ct->ct_name_position; + p += extra_text_len; + memcpy(p, ct->ct_name + ct->ct_name_position, + base_name_len - ct->ct_name_position); + return result; +} + +PyDoc_STRVAR(ffi_getctype_doc, +"Return a string giving the C type 'cdecl', which may be itself a\n" +"string or a <ctype> object. If 'replace_with' is given, it gives\n" +"extra text to append (or insert for more complicated C types), like a\n" +"variable name, or '*' to get actually the C type 'pointer-to-cdecl'."); + +static PyObject *ffi_getctype(FFIObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *c_decl, *res; + char *p, *replace_with = ""; + int add_paren, add_space; + CTypeDescrObject *ct; + size_t replace_with_len; + static char *keywords[] = {"cdecl", "replace_with", NULL}; +#if PY_MAJOR_VERSION >= 3 + PyObject *u; +#endif + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s:getctype", keywords, + &c_decl, &replace_with)) + return NULL; + + ct = _ffi_type(self, c_decl, ACCEPT_STRING|ACCEPT_CTYPE); + if (ct == NULL) + return NULL; + + while (replace_with[0] != 0 && isspace(replace_with[0])) + replace_with++; + replace_with_len = strlen(replace_with); + while (replace_with_len > 0 && isspace(replace_with[replace_with_len - 1])) + replace_with_len--; + + add_paren = (replace_with[0] == '*' && + ((ct->ct_flags & CT_ARRAY) != 0)); + add_space = (!add_paren && replace_with_len > 0 && + replace_with[0] != '[' && replace_with[0] != '('); + + res = _combine_type_name_l(ct, replace_with_len + add_space + 2*add_paren); + if (res == NULL) + return NULL; + + p = PyBytes_AS_STRING(res) + ct->ct_name_position; + if (add_paren) + *p++ = '('; + if (add_space) + *p++ = ' '; + memcpy(p, replace_with, replace_with_len); + if (add_paren) + p[replace_with_len] = ')'; + +#if PY_MAJOR_VERSION >= 3 + /* bytes -> unicode string */ + u = PyUnicode_DecodeLatin1(PyBytes_AS_STRING(res), + PyBytes_GET_SIZE(res), + NULL); + Py_DECREF(res); + res = u; +#endif + + return res; +} + +PyDoc_STRVAR(ffi_new_handle_doc, +"Return a non-NULL cdata of type 'void *' that contains an opaque\n" +"reference to the argument, which can be any Python object. To cast it\n" +"back to the original object, use from_handle(). You must keep alive\n" +"the cdata object returned by new_handle()!"); + +static PyObject *ffi_new_handle(FFIObject *self, PyObject *arg) +{ + /* g_ct_voidp is equal to <ctype 'void *'> */ + return newp_handle(g_ct_voidp, arg); +} + +PyDoc_STRVAR(ffi_from_handle_doc, +"Cast a 'void *' back to a Python object. Must be used *only* on the\n" +"pointers returned by new_handle(), and *only* as long as the exact\n" +"cdata object returned by new_handle() is still alive (somewhere else\n" +"in the program). Failure to follow these rules will crash."); + +#define ffi_from_handle b_from_handle /* ffi_from_handle => b_from_handle + from _cffi_backend.c */ + +PyDoc_STRVAR(ffi_from_buffer_doc, +"Return a <cdata 'char[]'> that points to the data of the given Python\n" +"object, which must support the buffer interface. Note that this is\n" +"not meant to be used on the built-in types str or unicode\n" +"(you can build 'char[]' arrays explicitly) but only on objects\n" +"containing large quantities of raw data in some other format, like\n" +"'array.array' or numpy arrays."); + static PyObject *ffi_from_buffer(FFIObject *self, PyObject *args, PyObject *kwds) -{ +{ PyObject *cdecl1, *python_buf = NULL; CTypeDescrObject *ct; int require_writable = 0; @@ -720,368 +720,368 @@ static PyObject *ffi_from_buffer(FFIObject *self, PyObject *args, return NULL; } return direct_from_buffer(ct, python_buf, require_writable); -} - -PyDoc_STRVAR(ffi_gc_doc, -"Return a new cdata object that points to the same data.\n" -"Later, when this new cdata object is garbage-collected,\n" +} + +PyDoc_STRVAR(ffi_gc_doc, +"Return a new cdata object that points to the same data.\n" +"Later, when this new cdata object is garbage-collected,\n" "'destructor(old_cdata_object)' will be called.\n" "\n" "The optional 'size' gives an estimate of the size, used to\n" "trigger the garbage collection more eagerly. So far only used\n" "on PyPy. It tells the GC that the returned object keeps alive\n" "roughly 'size' bytes of external memory."); - -#define ffi_gc b_gcp /* ffi_gc() => b_gcp() - from _cffi_backend.c */ - -PyDoc_STRVAR(ffi_def_extern_doc, -"A decorator. Attaches the decorated Python function to the C code\n" -"generated for the 'extern \"Python\"' function of the same name.\n" -"Calling the C function will then invoke the Python function.\n" -"\n" -"Optional arguments: 'name' is the name of the C function, if\n" -"different from the Python function; and 'error' and 'onerror'\n" -"handle what occurs if the Python function raises an exception\n" -"(see the docs for details)."); - -/* forward; see call_python.c */ -static PyObject *_ffi_def_extern_decorator(PyObject *, PyObject *); - -static PyObject *ffi_def_extern(FFIObject *self, PyObject *args, - PyObject *kwds) -{ - static PyMethodDef md = {"def_extern_decorator", - (PyCFunction)_ffi_def_extern_decorator, METH_O}; - PyObject *name = Py_None, *error = Py_None; - PyObject *res, *onerror = Py_None; - static char *keywords[] = {"name", "error", "onerror", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", keywords, - &name, &error, &onerror)) - return NULL; - - args = Py_BuildValue("(OOOO)", (PyObject *)self, name, error, onerror); - if (args == NULL) - return NULL; - - res = PyCFunction_New(&md, args); - Py_DECREF(args); - return res; -} - -PyDoc_STRVAR(ffi_callback_doc, -"Return a callback object or a decorator making such a callback object.\n" -"'cdecl' must name a C function pointer type. The callback invokes the\n" -"specified 'python_callable' (which may be provided either directly or\n" -"via a decorator). Important: the callback object must be manually\n" -"kept alive for as long as the callback may be invoked from the C code."); - -static PyObject *_ffi_callback_decorator(PyObject *outer_args, PyObject *fn) -{ - PyObject *res, *old; - - old = PyTuple_GET_ITEM(outer_args, 1); - PyTuple_SET_ITEM(outer_args, 1, fn); - res = b_callback(NULL, outer_args); - PyTuple_SET_ITEM(outer_args, 1, old); - return res; -} - -static PyObject *ffi_callback(FFIObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *c_decl, *python_callable = Py_None, *error = Py_None; - PyObject *res, *onerror = Py_None; - static char *keywords[] = {"cdecl", "python_callable", "error", - "onerror", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO", keywords, - &c_decl, &python_callable, &error, - &onerror)) - return NULL; - - c_decl = (PyObject *)_ffi_type(self, c_decl, ACCEPT_STRING | ACCEPT_CTYPE | - CONSIDER_FN_AS_FNPTR); - if (c_decl == NULL) - return NULL; - - args = Py_BuildValue("(OOOO)", c_decl, python_callable, error, onerror); - if (args == NULL) - return NULL; - - if (python_callable != Py_None) { - res = b_callback(NULL, args); - } - else { - static PyMethodDef md = {"callback_decorator", - (PyCFunction)_ffi_callback_decorator, METH_O}; - res = PyCFunction_New(&md, args); - } - Py_DECREF(args); - return res; -} - -#ifdef MS_WIN32 -PyDoc_STRVAR(ffi_getwinerror_doc, -"Return either the GetLastError() or the error number given by the\n" -"optional 'code' argument, as a tuple '(code, message)'."); - -#define ffi_getwinerror b_getwinerror /* ffi_getwinerror() => b_getwinerror() - from misc_win32.h */ -#endif - -PyDoc_STRVAR(ffi_errno_doc, "the value of 'errno' from/to the C calls"); - -static PyObject *ffi_get_errno(PyObject *self, void *closure) -{ - /* xxx maybe think about how to make the saved errno local - to an ffi instance */ - return b_get_errno(NULL, NULL); -} - -static int ffi_set_errno(PyObject *self, PyObject *newval, void *closure) -{ - PyObject *x = b_set_errno(NULL, newval); - if (x == NULL) - return -1; - Py_DECREF(x); - return 0; -} - -PyDoc_STRVAR(ffi_dlopen_doc, -"Load and return a dynamic library identified by 'name'. The standard\n" -"C library can be loaded by passing None.\n" -"\n" -"Note that functions and types declared with 'ffi.cdef()' are not\n" -"linked to a particular library, just like C headers. In the library\n" -"we only look for the actual (untyped) symbols at the time of their\n" -"first access."); - -PyDoc_STRVAR(ffi_dlclose_doc, -"Close a library obtained with ffi.dlopen(). After this call, access to\n" -"functions or variables from the library will fail (possibly with a\n" -"segmentation fault)."); - -static PyObject *ffi_dlopen(PyObject *self, PyObject *args); /* forward */ -static PyObject *ffi_dlclose(PyObject *self, PyObject *args); /* forward */ - -PyDoc_STRVAR(ffi_int_const_doc, -"Get the value of an integer constant.\n" -"\n" -"'ffi.integer_const(\"xxx\")' is equivalent to 'lib.xxx' if xxx names an\n" -"integer constant. The point of this function is limited to use cases\n" -"where you have an 'ffi' object but not any associated 'lib' object."); - -static PyObject *ffi_int_const(FFIObject *self, PyObject *args, PyObject *kwds) -{ - char *name; - PyObject *x; - static char *keywords[] = {"name", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", keywords, &name)) - return NULL; - - x = ffi_fetch_int_constant(self, name, 0); - - if (x == NULL && !PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, - "integer constant '%.200s' not found", name); - } - return x; -} - -PyDoc_STRVAR(ffi_list_types_doc, -"Returns the user type names known to this FFI instance.\n" -"This returns a tuple containing three lists of names:\n" -"(typedef_names, names_of_structs, names_of_unions)"); - -static PyObject *ffi_list_types(FFIObject *self, PyObject *noargs) -{ - Py_ssize_t i, n1 = self->types_builder.ctx.num_typenames; - Py_ssize_t n23 = self->types_builder.ctx.num_struct_unions; - PyObject *o, *lst[3] = {NULL, NULL, NULL}, *result = NULL; - - lst[0] = PyList_New(n1); - if (lst[0] == NULL) - goto error; - lst[1] = PyList_New(0); - if (lst[1] == NULL) - goto error; - lst[2] = PyList_New(0); - if (lst[2] == NULL) - goto error; - - for (i = 0; i < n1; i++) { - o = PyText_FromString(self->types_builder.ctx.typenames[i].name); - if (o == NULL) - goto error; - PyList_SET_ITEM(lst[0], i, o); - } - - for (i = 0; i < n23; i++) { - const struct _cffi_struct_union_s *s; - int err, index; - - s = &self->types_builder.ctx.struct_unions[i]; - if (s->name[0] == '$') - continue; - - o = PyText_FromString(s->name); - if (o == NULL) - goto error; - index = (s->flags & _CFFI_F_UNION) ? 2 : 1; - err = PyList_Append(lst[index], o); - Py_DECREF(o); - if (err < 0) - goto error; - } - result = PyTuple_Pack(3, lst[0], lst[1], lst[2]); - /* fall-through */ - error: - Py_XDECREF(lst[2]); - Py_XDECREF(lst[1]); - Py_XDECREF(lst[0]); - return result; -} - -PyDoc_STRVAR(ffi_memmove_doc, -"ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.\n" -"\n" -"Like the C function memmove(), the memory areas may overlap;\n" -"apart from that it behaves like the C function memcpy().\n" -"\n" -"'src' can be any cdata ptr or array, or any Python buffer object.\n" -"'dest' can be any cdata ptr or array, or a writable Python buffer\n" -"object. The size to copy, 'n', is always measured in bytes.\n" -"\n" -"Unlike other methods, this one supports all Python buffer including\n" -"byte strings and bytearrays---but it still does not support\n" -"non-contiguous buffers."); - -#define ffi_memmove b_memmove /* ffi_memmove() => b_memmove() - from _cffi_backend.c */ - -PyDoc_STRVAR(ffi_init_once_doc, -"init_once(function, tag): run function() once. More precisely,\n" -"'function()' is called the first time we see a given 'tag'.\n" -"\n" -"The return value of function() is remembered and returned by the current\n" -"and all future init_once() with the same tag. If init_once() is called\n" -"from multiple threads in parallel, all calls block until the execution\n" -"of function() is done. If function() raises an exception, it is\n" -"propagated and nothing is cached."); - -#if PY_MAJOR_VERSION < 3 -/* PyCapsule_New is redefined to be PyCObject_FromVoidPtr in _cffi_backend, - which gives 2.6 compatibility; but the destructor signature is different */ -static void _free_init_once_lock(void *lock) -{ - PyThread_free_lock((PyThread_type_lock)lock); -} -#else -static void _free_init_once_lock(PyObject *capsule) -{ - PyThread_type_lock lock; - lock = PyCapsule_GetPointer(capsule, "cffi_init_once_lock"); - if (lock != NULL) - PyThread_free_lock(lock); -} -#endif - -static PyObject *ffi_init_once(FFIObject *self, PyObject *args, PyObject *kwds) -{ - static char *keywords[] = {"func", "tag", NULL}; - PyObject *cache, *func, *tag, *tup, *res, *x, *lockobj; - PyThread_type_lock lock; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", keywords, &func, &tag)) - return NULL; - - /* a lot of fun with reference counting and error checking - in this function */ - - /* atomically get or create a new dict (no GIL release) */ - cache = self->init_once_cache; - if (cache == NULL) { - cache = PyDict_New(); - if (cache == NULL) - return NULL; - self->init_once_cache = cache; - } - - /* get the tuple from cache[tag], or make a new one: (False, lock) */ - tup = PyDict_GetItem(cache, tag); - if (tup == NULL) { - lock = PyThread_allocate_lock(); - if (lock == NULL) - return NULL; - x = PyCapsule_New(lock, "cffi_init_once_lock", _free_init_once_lock); - if (x == NULL) { - PyThread_free_lock(lock); - return NULL; - } - tup = PyTuple_Pack(2, Py_False, x); - Py_DECREF(x); - if (tup == NULL) - return NULL; - x = tup; - - /* Possible corner case if 'tag' is an object overriding __eq__ - in pure Python: the GIL may be released when we are running it. - We really need to call dict.setdefault(). */ - tup = PyObject_CallMethod(cache, "setdefault", "OO", tag, x); - Py_DECREF(x); - if (tup == NULL) - return NULL; - - Py_DECREF(tup); /* there is still a ref inside the dict */ - } - - res = PyTuple_GET_ITEM(tup, 1); - Py_INCREF(res); - - if (PyTuple_GET_ITEM(tup, 0) == Py_True) { - /* tup == (True, result): return the result. */ - return res; - } - - /* tup == (False, lock) */ - lockobj = res; - lock = (PyThread_type_lock)PyCapsule_GetPointer(lockobj, - "cffi_init_once_lock"); - if (lock == NULL) { - Py_DECREF(lockobj); - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(lock, WAIT_LOCK); - Py_END_ALLOW_THREADS - - x = PyDict_GetItem(cache, tag); - if (x != NULL && PyTuple_GET_ITEM(x, 0) == Py_True) { - /* the real result was put in the dict while we were waiting - for PyThread_acquire_lock() above */ - res = PyTuple_GET_ITEM(x, 1); - Py_INCREF(res); - } - else { - res = PyObject_CallFunction(func, ""); - if (res != NULL) { - tup = PyTuple_Pack(2, Py_True, res); - if (tup == NULL || PyDict_SetItem(cache, tag, tup) < 0) { - Py_DECREF(res); - res = NULL; - } + +#define ffi_gc b_gcp /* ffi_gc() => b_gcp() + from _cffi_backend.c */ + +PyDoc_STRVAR(ffi_def_extern_doc, +"A decorator. Attaches the decorated Python function to the C code\n" +"generated for the 'extern \"Python\"' function of the same name.\n" +"Calling the C function will then invoke the Python function.\n" +"\n" +"Optional arguments: 'name' is the name of the C function, if\n" +"different from the Python function; and 'error' and 'onerror'\n" +"handle what occurs if the Python function raises an exception\n" +"(see the docs for details)."); + +/* forward; see call_python.c */ +static PyObject *_ffi_def_extern_decorator(PyObject *, PyObject *); + +static PyObject *ffi_def_extern(FFIObject *self, PyObject *args, + PyObject *kwds) +{ + static PyMethodDef md = {"def_extern_decorator", + (PyCFunction)_ffi_def_extern_decorator, METH_O}; + PyObject *name = Py_None, *error = Py_None; + PyObject *res, *onerror = Py_None; + static char *keywords[] = {"name", "error", "onerror", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", keywords, + &name, &error, &onerror)) + return NULL; + + args = Py_BuildValue("(OOOO)", (PyObject *)self, name, error, onerror); + if (args == NULL) + return NULL; + + res = PyCFunction_New(&md, args); + Py_DECREF(args); + return res; +} + +PyDoc_STRVAR(ffi_callback_doc, +"Return a callback object or a decorator making such a callback object.\n" +"'cdecl' must name a C function pointer type. The callback invokes the\n" +"specified 'python_callable' (which may be provided either directly or\n" +"via a decorator). Important: the callback object must be manually\n" +"kept alive for as long as the callback may be invoked from the C code."); + +static PyObject *_ffi_callback_decorator(PyObject *outer_args, PyObject *fn) +{ + PyObject *res, *old; + + old = PyTuple_GET_ITEM(outer_args, 1); + PyTuple_SET_ITEM(outer_args, 1, fn); + res = b_callback(NULL, outer_args); + PyTuple_SET_ITEM(outer_args, 1, old); + return res; +} + +static PyObject *ffi_callback(FFIObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *c_decl, *python_callable = Py_None, *error = Py_None; + PyObject *res, *onerror = Py_None; + static char *keywords[] = {"cdecl", "python_callable", "error", + "onerror", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO", keywords, + &c_decl, &python_callable, &error, + &onerror)) + return NULL; + + c_decl = (PyObject *)_ffi_type(self, c_decl, ACCEPT_STRING | ACCEPT_CTYPE | + CONSIDER_FN_AS_FNPTR); + if (c_decl == NULL) + return NULL; + + args = Py_BuildValue("(OOOO)", c_decl, python_callable, error, onerror); + if (args == NULL) + return NULL; + + if (python_callable != Py_None) { + res = b_callback(NULL, args); + } + else { + static PyMethodDef md = {"callback_decorator", + (PyCFunction)_ffi_callback_decorator, METH_O}; + res = PyCFunction_New(&md, args); + } + Py_DECREF(args); + return res; +} + +#ifdef MS_WIN32 +PyDoc_STRVAR(ffi_getwinerror_doc, +"Return either the GetLastError() or the error number given by the\n" +"optional 'code' argument, as a tuple '(code, message)'."); + +#define ffi_getwinerror b_getwinerror /* ffi_getwinerror() => b_getwinerror() + from misc_win32.h */ +#endif + +PyDoc_STRVAR(ffi_errno_doc, "the value of 'errno' from/to the C calls"); + +static PyObject *ffi_get_errno(PyObject *self, void *closure) +{ + /* xxx maybe think about how to make the saved errno local + to an ffi instance */ + return b_get_errno(NULL, NULL); +} + +static int ffi_set_errno(PyObject *self, PyObject *newval, void *closure) +{ + PyObject *x = b_set_errno(NULL, newval); + if (x == NULL) + return -1; + Py_DECREF(x); + return 0; +} + +PyDoc_STRVAR(ffi_dlopen_doc, +"Load and return a dynamic library identified by 'name'. The standard\n" +"C library can be loaded by passing None.\n" +"\n" +"Note that functions and types declared with 'ffi.cdef()' are not\n" +"linked to a particular library, just like C headers. In the library\n" +"we only look for the actual (untyped) symbols at the time of their\n" +"first access."); + +PyDoc_STRVAR(ffi_dlclose_doc, +"Close a library obtained with ffi.dlopen(). After this call, access to\n" +"functions or variables from the library will fail (possibly with a\n" +"segmentation fault)."); + +static PyObject *ffi_dlopen(PyObject *self, PyObject *args); /* forward */ +static PyObject *ffi_dlclose(PyObject *self, PyObject *args); /* forward */ + +PyDoc_STRVAR(ffi_int_const_doc, +"Get the value of an integer constant.\n" +"\n" +"'ffi.integer_const(\"xxx\")' is equivalent to 'lib.xxx' if xxx names an\n" +"integer constant. The point of this function is limited to use cases\n" +"where you have an 'ffi' object but not any associated 'lib' object."); + +static PyObject *ffi_int_const(FFIObject *self, PyObject *args, PyObject *kwds) +{ + char *name; + PyObject *x; + static char *keywords[] = {"name", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", keywords, &name)) + return NULL; + + x = ffi_fetch_int_constant(self, name, 0); + + if (x == NULL && !PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, + "integer constant '%.200s' not found", name); + } + return x; +} + +PyDoc_STRVAR(ffi_list_types_doc, +"Returns the user type names known to this FFI instance.\n" +"This returns a tuple containing three lists of names:\n" +"(typedef_names, names_of_structs, names_of_unions)"); + +static PyObject *ffi_list_types(FFIObject *self, PyObject *noargs) +{ + Py_ssize_t i, n1 = self->types_builder.ctx.num_typenames; + Py_ssize_t n23 = self->types_builder.ctx.num_struct_unions; + PyObject *o, *lst[3] = {NULL, NULL, NULL}, *result = NULL; + + lst[0] = PyList_New(n1); + if (lst[0] == NULL) + goto error; + lst[1] = PyList_New(0); + if (lst[1] == NULL) + goto error; + lst[2] = PyList_New(0); + if (lst[2] == NULL) + goto error; + + for (i = 0; i < n1; i++) { + o = PyText_FromString(self->types_builder.ctx.typenames[i].name); + if (o == NULL) + goto error; + PyList_SET_ITEM(lst[0], i, o); + } + + for (i = 0; i < n23; i++) { + const struct _cffi_struct_union_s *s; + int err, index; + + s = &self->types_builder.ctx.struct_unions[i]; + if (s->name[0] == '$') + continue; + + o = PyText_FromString(s->name); + if (o == NULL) + goto error; + index = (s->flags & _CFFI_F_UNION) ? 2 : 1; + err = PyList_Append(lst[index], o); + Py_DECREF(o); + if (err < 0) + goto error; + } + result = PyTuple_Pack(3, lst[0], lst[1], lst[2]); + /* fall-through */ + error: + Py_XDECREF(lst[2]); + Py_XDECREF(lst[1]); + Py_XDECREF(lst[0]); + return result; +} + +PyDoc_STRVAR(ffi_memmove_doc, +"ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.\n" +"\n" +"Like the C function memmove(), the memory areas may overlap;\n" +"apart from that it behaves like the C function memcpy().\n" +"\n" +"'src' can be any cdata ptr or array, or any Python buffer object.\n" +"'dest' can be any cdata ptr or array, or a writable Python buffer\n" +"object. The size to copy, 'n', is always measured in bytes.\n" +"\n" +"Unlike other methods, this one supports all Python buffer including\n" +"byte strings and bytearrays---but it still does not support\n" +"non-contiguous buffers."); + +#define ffi_memmove b_memmove /* ffi_memmove() => b_memmove() + from _cffi_backend.c */ + +PyDoc_STRVAR(ffi_init_once_doc, +"init_once(function, tag): run function() once. More precisely,\n" +"'function()' is called the first time we see a given 'tag'.\n" +"\n" +"The return value of function() is remembered and returned by the current\n" +"and all future init_once() with the same tag. If init_once() is called\n" +"from multiple threads in parallel, all calls block until the execution\n" +"of function() is done. If function() raises an exception, it is\n" +"propagated and nothing is cached."); + +#if PY_MAJOR_VERSION < 3 +/* PyCapsule_New is redefined to be PyCObject_FromVoidPtr in _cffi_backend, + which gives 2.6 compatibility; but the destructor signature is different */ +static void _free_init_once_lock(void *lock) +{ + PyThread_free_lock((PyThread_type_lock)lock); +} +#else +static void _free_init_once_lock(PyObject *capsule) +{ + PyThread_type_lock lock; + lock = PyCapsule_GetPointer(capsule, "cffi_init_once_lock"); + if (lock != NULL) + PyThread_free_lock(lock); +} +#endif + +static PyObject *ffi_init_once(FFIObject *self, PyObject *args, PyObject *kwds) +{ + static char *keywords[] = {"func", "tag", NULL}; + PyObject *cache, *func, *tag, *tup, *res, *x, *lockobj; + PyThread_type_lock lock; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", keywords, &func, &tag)) + return NULL; + + /* a lot of fun with reference counting and error checking + in this function */ + + /* atomically get or create a new dict (no GIL release) */ + cache = self->init_once_cache; + if (cache == NULL) { + cache = PyDict_New(); + if (cache == NULL) + return NULL; + self->init_once_cache = cache; + } + + /* get the tuple from cache[tag], or make a new one: (False, lock) */ + tup = PyDict_GetItem(cache, tag); + if (tup == NULL) { + lock = PyThread_allocate_lock(); + if (lock == NULL) + return NULL; + x = PyCapsule_New(lock, "cffi_init_once_lock", _free_init_once_lock); + if (x == NULL) { + PyThread_free_lock(lock); + return NULL; + } + tup = PyTuple_Pack(2, Py_False, x); + Py_DECREF(x); + if (tup == NULL) + return NULL; + x = tup; + + /* Possible corner case if 'tag' is an object overriding __eq__ + in pure Python: the GIL may be released when we are running it. + We really need to call dict.setdefault(). */ + tup = PyObject_CallMethod(cache, "setdefault", "OO", tag, x); + Py_DECREF(x); + if (tup == NULL) + return NULL; + + Py_DECREF(tup); /* there is still a ref inside the dict */ + } + + res = PyTuple_GET_ITEM(tup, 1); + Py_INCREF(res); + + if (PyTuple_GET_ITEM(tup, 0) == Py_True) { + /* tup == (True, result): return the result. */ + return res; + } + + /* tup == (False, lock) */ + lockobj = res; + lock = (PyThread_type_lock)PyCapsule_GetPointer(lockobj, + "cffi_init_once_lock"); + if (lock == NULL) { + Py_DECREF(lockobj); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(lock, WAIT_LOCK); + Py_END_ALLOW_THREADS + + x = PyDict_GetItem(cache, tag); + if (x != NULL && PyTuple_GET_ITEM(x, 0) == Py_True) { + /* the real result was put in the dict while we were waiting + for PyThread_acquire_lock() above */ + res = PyTuple_GET_ITEM(x, 1); + Py_INCREF(res); + } + else { + res = PyObject_CallFunction(func, ""); + if (res != NULL) { + tup = PyTuple_Pack(2, Py_True, res); + if (tup == NULL || PyDict_SetItem(cache, tag, tup) < 0) { + Py_DECREF(res); + res = NULL; + } Py_XDECREF(tup); - } - } - - PyThread_release_lock(lock); - Py_DECREF(lockobj); - return res; -} - + } + } + + PyThread_release_lock(lock); + Py_DECREF(lockobj); + return res; +} + PyDoc_STRVAR(ffi_release_doc, "Release now the resources held by a 'cdata' object from ffi.new(),\n" "ffi.gc() or ffi.from_buffer(). The cdata object must not be used\n" @@ -1093,129 +1093,129 @@ PyDoc_STRVAR(ffi_release_doc, "returned by ffi.new(), because the memory is allocated inline with the\n" "cdata object and cannot be freed independently. It might be fixed in\n" "future releases of cffi."); - + #define ffi_release b_release /* ffi_release() => b_release() from _cffi_backend.c */ -#define METH_VKW (METH_VARARGS | METH_KEYWORDS) -static PyMethodDef ffi_methods[] = { - {"addressof", (PyCFunction)ffi_addressof, METH_VARARGS, ffi_addressof_doc}, - {"alignof", (PyCFunction)ffi_alignof, METH_O, ffi_alignof_doc}, - {"def_extern", (PyCFunction)ffi_def_extern, METH_VKW, ffi_def_extern_doc}, - {"callback", (PyCFunction)ffi_callback, METH_VKW, ffi_callback_doc}, - {"cast", (PyCFunction)ffi_cast, METH_VARARGS, ffi_cast_doc}, - {"dlclose", (PyCFunction)ffi_dlclose, METH_VARARGS, ffi_dlclose_doc}, - {"dlopen", (PyCFunction)ffi_dlopen, METH_VARARGS, ffi_dlopen_doc}, +#define METH_VKW (METH_VARARGS | METH_KEYWORDS) +static PyMethodDef ffi_methods[] = { + {"addressof", (PyCFunction)ffi_addressof, METH_VARARGS, ffi_addressof_doc}, + {"alignof", (PyCFunction)ffi_alignof, METH_O, ffi_alignof_doc}, + {"def_extern", (PyCFunction)ffi_def_extern, METH_VKW, ffi_def_extern_doc}, + {"callback", (PyCFunction)ffi_callback, METH_VKW, ffi_callback_doc}, + {"cast", (PyCFunction)ffi_cast, METH_VARARGS, ffi_cast_doc}, + {"dlclose", (PyCFunction)ffi_dlclose, METH_VARARGS, ffi_dlclose_doc}, + {"dlopen", (PyCFunction)ffi_dlopen, METH_VARARGS, ffi_dlopen_doc}, {"from_buffer",(PyCFunction)ffi_from_buffer,METH_VKW, ffi_from_buffer_doc}, - {"from_handle",(PyCFunction)ffi_from_handle,METH_O, ffi_from_handle_doc}, - {"gc", (PyCFunction)ffi_gc, METH_VKW, ffi_gc_doc}, - {"getctype", (PyCFunction)ffi_getctype, METH_VKW, ffi_getctype_doc}, -#ifdef MS_WIN32 - {"getwinerror",(PyCFunction)ffi_getwinerror,METH_VKW, ffi_getwinerror_doc}, -#endif - {"init_once", (PyCFunction)ffi_init_once, METH_VKW, ffi_init_once_doc}, - {"integer_const",(PyCFunction)ffi_int_const,METH_VKW, ffi_int_const_doc}, - {"list_types", (PyCFunction)ffi_list_types, METH_NOARGS, ffi_list_types_doc}, - {"memmove", (PyCFunction)ffi_memmove, METH_VKW, ffi_memmove_doc}, - {"new", (PyCFunction)ffi_new, METH_VKW, ffi_new_doc}, -{"new_allocator",(PyCFunction)ffi_new_allocator,METH_VKW,ffi_new_allocator_doc}, - {"new_handle", (PyCFunction)ffi_new_handle, METH_O, ffi_new_handle_doc}, - {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS, ffi_offsetof_doc}, + {"from_handle",(PyCFunction)ffi_from_handle,METH_O, ffi_from_handle_doc}, + {"gc", (PyCFunction)ffi_gc, METH_VKW, ffi_gc_doc}, + {"getctype", (PyCFunction)ffi_getctype, METH_VKW, ffi_getctype_doc}, +#ifdef MS_WIN32 + {"getwinerror",(PyCFunction)ffi_getwinerror,METH_VKW, ffi_getwinerror_doc}, +#endif + {"init_once", (PyCFunction)ffi_init_once, METH_VKW, ffi_init_once_doc}, + {"integer_const",(PyCFunction)ffi_int_const,METH_VKW, ffi_int_const_doc}, + {"list_types", (PyCFunction)ffi_list_types, METH_NOARGS, ffi_list_types_doc}, + {"memmove", (PyCFunction)ffi_memmove, METH_VKW, ffi_memmove_doc}, + {"new", (PyCFunction)ffi_new, METH_VKW, ffi_new_doc}, +{"new_allocator",(PyCFunction)ffi_new_allocator,METH_VKW,ffi_new_allocator_doc}, + {"new_handle", (PyCFunction)ffi_new_handle, METH_O, ffi_new_handle_doc}, + {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS, ffi_offsetof_doc}, {"release", (PyCFunction)ffi_release, METH_O, ffi_release_doc}, - {"sizeof", (PyCFunction)ffi_sizeof, METH_O, ffi_sizeof_doc}, - {"string", (PyCFunction)ffi_string, METH_VKW, ffi_string_doc}, - {"typeof", (PyCFunction)ffi_typeof, METH_O, ffi_typeof_doc}, - {"unpack", (PyCFunction)ffi_unpack, METH_VKW, ffi_unpack_doc}, - {NULL} -}; - -static PyGetSetDef ffi_getsets[] = { - {"errno", ffi_get_errno, ffi_set_errno, ffi_errno_doc}, - {NULL} -}; - -static PyTypeObject FFI_Type = { - PyVarObject_HEAD_INIT(NULL, 0) + {"sizeof", (PyCFunction)ffi_sizeof, METH_O, ffi_sizeof_doc}, + {"string", (PyCFunction)ffi_string, METH_VKW, ffi_string_doc}, + {"typeof", (PyCFunction)ffi_typeof, METH_O, ffi_typeof_doc}, + {"unpack", (PyCFunction)ffi_unpack, METH_VKW, ffi_unpack_doc}, + {NULL} +}; + +static PyGetSetDef ffi_getsets[] = { + {"errno", ffi_get_errno, ffi_set_errno, ffi_errno_doc}, + {NULL} +}; + +static PyTypeObject FFI_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.FFI", - sizeof(FFIObject), - 0, - (destructor)ffi_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)ffi_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ffi_methods, /* tp_methods */ - 0, /* tp_members */ - ffi_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - ffiobj_init, /* tp_init */ - 0, /* tp_alloc */ - ffiobj_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - - -static PyObject * -_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, - PyObject *included_ffis, int recursion) -{ - Py_ssize_t i; - - if (included_ffis == NULL) - return NULL; - - if (recursion > 100) { - PyErr_SetString(PyExc_RuntimeError, - "recursion overflow in ffi.include() delegations"); - return NULL; - } - - for (i = 0; i < PyTuple_GET_SIZE(included_ffis); i++) { - FFIObject *ffi1; - const struct _cffi_struct_union_s *s1; - int sindex; - PyObject *x; - - ffi1 = (FFIObject *)PyTuple_GET_ITEM(included_ffis, i); - sindex = search_in_struct_unions(&ffi1->types_builder.ctx, s->name, - strlen(s->name)); - if (sindex < 0) /* not found at all */ - continue; - s1 = &ffi1->types_builder.ctx.struct_unions[sindex]; - if ((s1->flags & (_CFFI_F_EXTERNAL | _CFFI_F_UNION)) - == (s->flags & _CFFI_F_UNION)) { - /* s1 is not external, and the same kind (struct or union) as s */ - return _realize_c_struct_or_union(&ffi1->types_builder, sindex); - } - /* not found, look more recursively */ - x = _fetch_external_struct_or_union( - s, ffi1->types_builder.included_ffis, recursion + 1); - if (x != NULL || PyErr_Occurred()) - return x; /* either found, or got an error */ - } - return NULL; /* not found at all, leave without an error */ -} + sizeof(FFIObject), + 0, + (destructor)ffi_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)ffi_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ffi_methods, /* tp_methods */ + 0, /* tp_members */ + ffi_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + ffiobj_init, /* tp_init */ + 0, /* tp_alloc */ + ffiobj_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +static PyObject * +_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, + PyObject *included_ffis, int recursion) +{ + Py_ssize_t i; + + if (included_ffis == NULL) + return NULL; + + if (recursion > 100) { + PyErr_SetString(PyExc_RuntimeError, + "recursion overflow in ffi.include() delegations"); + return NULL; + } + + for (i = 0; i < PyTuple_GET_SIZE(included_ffis); i++) { + FFIObject *ffi1; + const struct _cffi_struct_union_s *s1; + int sindex; + PyObject *x; + + ffi1 = (FFIObject *)PyTuple_GET_ITEM(included_ffis, i); + sindex = search_in_struct_unions(&ffi1->types_builder.ctx, s->name, + strlen(s->name)); + if (sindex < 0) /* not found at all */ + continue; + s1 = &ffi1->types_builder.ctx.struct_unions[sindex]; + if ((s1->flags & (_CFFI_F_EXTERNAL | _CFFI_F_UNION)) + == (s->flags & _CFFI_F_UNION)) { + /* s1 is not external, and the same kind (struct or union) as s */ + return _realize_c_struct_or_union(&ffi1->types_builder, sindex); + } + /* not found, look more recursively */ + x = _fetch_external_struct_or_union( + s, ffi1->types_builder.included_ffis, recursion + 1); + if (x != NULL || PyErr_Occurred()) + return x; /* either found, or got an error */ + } + return NULL; /* not found at all, leave without an error */ +} diff --git a/contrib/python/cffi/c/file_emulator.h b/contrib/python/cffi/c/file_emulator.h index 82a34c0c72..6102668de2 100644 --- a/contrib/python/cffi/c/file_emulator.h +++ b/contrib/python/cffi/c/file_emulator.h @@ -1,93 +1,93 @@ - -/* Emulation of PyFile_Check() and PyFile_AsFile() for Python 3. */ - -static PyObject *PyIOBase_TypeObj; - -static int init_file_emulator(void) -{ - if (PyIOBase_TypeObj == NULL) { - PyObject *io = PyImport_ImportModule("_io"); - if (io == NULL) - return -1; - PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase"); - if (PyIOBase_TypeObj == NULL) - return -1; - } - return 0; -} - - -#define PyFile_Check(p) PyObject_IsInstance(p, PyIOBase_TypeObj) - - -static void _close_file_capsule(PyObject *ob_capsule) -{ - FILE *f = (FILE *)PyCapsule_GetPointer(ob_capsule, "FILE"); - if (f != NULL) - fclose(f); -} - - -static FILE *PyFile_AsFile(PyObject *ob_file) -{ - PyObject *ob, *ob_capsule = NULL, *ob_mode = NULL; - FILE *f; - int fd; + +/* Emulation of PyFile_Check() and PyFile_AsFile() for Python 3. */ + +static PyObject *PyIOBase_TypeObj; + +static int init_file_emulator(void) +{ + if (PyIOBase_TypeObj == NULL) { + PyObject *io = PyImport_ImportModule("_io"); + if (io == NULL) + return -1; + PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase"); + if (PyIOBase_TypeObj == NULL) + return -1; + } + return 0; +} + + +#define PyFile_Check(p) PyObject_IsInstance(p, PyIOBase_TypeObj) + + +static void _close_file_capsule(PyObject *ob_capsule) +{ + FILE *f = (FILE *)PyCapsule_GetPointer(ob_capsule, "FILE"); + if (f != NULL) + fclose(f); +} + + +static FILE *PyFile_AsFile(PyObject *ob_file) +{ + PyObject *ob, *ob_capsule = NULL, *ob_mode = NULL; + FILE *f; + int fd; const char *mode; - - ob = PyObject_CallMethod(ob_file, "flush", NULL); - if (ob == NULL) - goto fail; - Py_DECREF(ob); - - ob_capsule = PyObject_GetAttrString(ob_file, "__cffi_FILE"); - if (ob_capsule == NULL) { - PyErr_Clear(); - - fd = PyObject_AsFileDescriptor(ob_file); - if (fd < 0) - goto fail; - - ob_mode = PyObject_GetAttrString(ob_file, "mode"); - if (ob_mode == NULL) - goto fail; - mode = PyText_AsUTF8(ob_mode); - if (mode == NULL) - goto fail; - - fd = dup(fd); - if (fd < 0) { - PyErr_SetFromErrno(PyExc_OSError); - goto fail; - } - - f = fdopen(fd, mode); - if (f == NULL) { - close(fd); - PyErr_SetFromErrno(PyExc_OSError); - goto fail; - } - setbuf(f, NULL); /* non-buffered */ - Py_DECREF(ob_mode); - ob_mode = NULL; - - ob_capsule = PyCapsule_New(f, "FILE", _close_file_capsule); - if (ob_capsule == NULL) { - fclose(f); - goto fail; - } - - if (PyObject_SetAttrString(ob_file, "__cffi_FILE", ob_capsule) < 0) - goto fail; - } - else { - f = PyCapsule_GetPointer(ob_capsule, "FILE"); - } - Py_DECREF(ob_capsule); /* assumes still at least one reference */ - return f; - - fail: - Py_XDECREF(ob_mode); - Py_XDECREF(ob_capsule); - return NULL; -} + + ob = PyObject_CallMethod(ob_file, "flush", NULL); + if (ob == NULL) + goto fail; + Py_DECREF(ob); + + ob_capsule = PyObject_GetAttrString(ob_file, "__cffi_FILE"); + if (ob_capsule == NULL) { + PyErr_Clear(); + + fd = PyObject_AsFileDescriptor(ob_file); + if (fd < 0) + goto fail; + + ob_mode = PyObject_GetAttrString(ob_file, "mode"); + if (ob_mode == NULL) + goto fail; + mode = PyText_AsUTF8(ob_mode); + if (mode == NULL) + goto fail; + + fd = dup(fd); + if (fd < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto fail; + } + + f = fdopen(fd, mode); + if (f == NULL) { + close(fd); + PyErr_SetFromErrno(PyExc_OSError); + goto fail; + } + setbuf(f, NULL); /* non-buffered */ + Py_DECREF(ob_mode); + ob_mode = NULL; + + ob_capsule = PyCapsule_New(f, "FILE", _close_file_capsule); + if (ob_capsule == NULL) { + fclose(f); + goto fail; + } + + if (PyObject_SetAttrString(ob_file, "__cffi_FILE", ob_capsule) < 0) + goto fail; + } + else { + f = PyCapsule_GetPointer(ob_capsule, "FILE"); + } + Py_DECREF(ob_capsule); /* assumes still at least one reference */ + return f; + + fail: + Py_XDECREF(ob_mode); + Py_XDECREF(ob_capsule); + return NULL; +} diff --git a/contrib/python/cffi/c/lib_obj.c b/contrib/python/cffi/c/lib_obj.c index 38bf3d5510..d253f5613a 100644 --- a/contrib/python/cffi/c/lib_obj.c +++ b/contrib/python/cffi/c/lib_obj.c @@ -1,166 +1,166 @@ - -/* A Lib object is what is in the "lib" attribute of a C extension - module originally created by recompile(). - - A Lib object is special in the sense that it has a custom - __getattr__ which returns C globals, functions and constants. The - original idea was to raise AttributeError for anything else, even - attrs like '__class__', but it breaks various things; now, standard - attrs are returned, but in the unlikely case where a user cdef()s - the same name, then the standard attr is hidden (and the various - things like introspection might break). - - A Lib object has got a reference to the _cffi_type_context_s - structure, which is used to create lazily the objects returned by - __getattr__. -*/ - -struct CPyExtFunc_s { - PyMethodDef md; - void *direct_fn; - int type_index; - char doc[1]; -}; - -struct LibObject_s { - PyObject_HEAD - builder_c_t *l_types_builder; /* same as the one on the ffi object */ - PyObject *l_dict; /* content, built lazily */ - PyObject *l_libname; /* some string that gives the name of the lib */ - FFIObject *l_ffi; /* reference back to the ffi object */ - void *l_libhandle; /* the dlopen()ed handle, if any */ + +/* A Lib object is what is in the "lib" attribute of a C extension + module originally created by recompile(). + + A Lib object is special in the sense that it has a custom + __getattr__ which returns C globals, functions and constants. The + original idea was to raise AttributeError for anything else, even + attrs like '__class__', but it breaks various things; now, standard + attrs are returned, but in the unlikely case where a user cdef()s + the same name, then the standard attr is hidden (and the various + things like introspection might break). + + A Lib object has got a reference to the _cffi_type_context_s + structure, which is used to create lazily the objects returned by + __getattr__. +*/ + +struct CPyExtFunc_s { + PyMethodDef md; + void *direct_fn; + int type_index; + char doc[1]; +}; + +struct LibObject_s { + PyObject_HEAD + builder_c_t *l_types_builder; /* same as the one on the ffi object */ + PyObject *l_dict; /* content, built lazily */ + PyObject *l_libname; /* some string that gives the name of the lib */ + FFIObject *l_ffi; /* reference back to the ffi object */ + void *l_libhandle; /* the dlopen()ed handle, if any */ int l_auto_close; /* if we must dlclose() this handle */ -}; - -static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x) -{ - PyObject *y; - LibObject *lo; - PyCFunctionObject *fo; - - if (!PyCFunction_Check(x)) - return NULL; - y = PyCFunction_GET_SELF(x); - if (!LibObject_Check(y)) - return NULL; - - fo = (PyCFunctionObject *)x; - lo = (LibObject *)y; - if (lo->l_libname != fo->m_module) - return NULL; - - return (struct CPyExtFunc_s *)(fo->m_ml); -} - -static PyObject *_cpyextfunc_type(LibObject *lib, struct CPyExtFunc_s *exf) -{ - PyObject *tuple, *result; - tuple = realize_c_type_or_func(lib->l_types_builder, - lib->l_types_builder->ctx.types, - exf->type_index); - if (tuple == NULL) - return NULL; - - /* 'tuple' is a tuple of length 1 containing the real CT_FUNCTIONPTR - object */ - result = PyTuple_GetItem(tuple, 0); - Py_XINCREF(result); - Py_DECREF(tuple); - return result; -} - -static PyObject *_cpyextfunc_type_index(PyObject *x) -{ - struct CPyExtFunc_s *exf; - LibObject *lib; - - assert(PyErr_Occurred()); - exf = _cpyextfunc_get(x); - if (exf == NULL) - return NULL; /* still the same exception is set */ - - PyErr_Clear(); - - lib = (LibObject *)PyCFunction_GET_SELF(x); - return _cpyextfunc_type(lib, exf); -} - -static void cdlopen_close_ignore_errors(void *libhandle); /* forward */ +}; + +static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x) +{ + PyObject *y; + LibObject *lo; + PyCFunctionObject *fo; + + if (!PyCFunction_Check(x)) + return NULL; + y = PyCFunction_GET_SELF(x); + if (!LibObject_Check(y)) + return NULL; + + fo = (PyCFunctionObject *)x; + lo = (LibObject *)y; + if (lo->l_libname != fo->m_module) + return NULL; + + return (struct CPyExtFunc_s *)(fo->m_ml); +} + +static PyObject *_cpyextfunc_type(LibObject *lib, struct CPyExtFunc_s *exf) +{ + PyObject *tuple, *result; + tuple = realize_c_type_or_func(lib->l_types_builder, + lib->l_types_builder->ctx.types, + exf->type_index); + if (tuple == NULL) + return NULL; + + /* 'tuple' is a tuple of length 1 containing the real CT_FUNCTIONPTR + object */ + result = PyTuple_GetItem(tuple, 0); + Py_XINCREF(result); + Py_DECREF(tuple); + return result; +} + +static PyObject *_cpyextfunc_type_index(PyObject *x) +{ + struct CPyExtFunc_s *exf; + LibObject *lib; + + assert(PyErr_Occurred()); + exf = _cpyextfunc_get(x); + if (exf == NULL) + return NULL; /* still the same exception is set */ + + PyErr_Clear(); + + lib = (LibObject *)PyCFunction_GET_SELF(x); + return _cpyextfunc_type(lib, exf); +} + +static void cdlopen_close_ignore_errors(void *libhandle); /* forward */ static void *cdlopen_fetch(PyObject *libname, void *libhandle, const char *symbol); - -static void lib_dealloc(LibObject *lib) -{ + +static void lib_dealloc(LibObject *lib) +{ PyObject_GC_UnTrack(lib); if (lib->l_auto_close) cdlopen_close_ignore_errors(lib->l_libhandle); - Py_DECREF(lib->l_dict); - Py_DECREF(lib->l_libname); - Py_DECREF(lib->l_ffi); - PyObject_GC_Del(lib); -} - -static int lib_traverse(LibObject *lib, visitproc visit, void *arg) -{ - Py_VISIT(lib->l_dict); - Py_VISIT(lib->l_libname); - Py_VISIT(lib->l_ffi); - return 0; -} - -static PyObject *lib_repr(LibObject *lib) -{ - return PyText_FromFormat("<Lib object for '%.200s'>", - PyText_AS_UTF8(lib->l_libname)); -} - -static PyObject *lib_build_cpython_func(LibObject *lib, - const struct _cffi_global_s *g, - const char *s, int flags) -{ - /* First make sure the argument types and return type are really - built. The C extension code can then assume that they are, - by calling _cffi_type(). - */ - PyObject *result = NULL; - CTypeDescrObject **pfargs = NULL; - CTypeDescrObject *fresult; - Py_ssize_t nargs = 0; - struct CPyExtFunc_s *xfunc; - int i, type_index = _CFFI_GETARG(g->type_op); - _cffi_opcode_t *opcodes = lib->l_types_builder->ctx.types; - static const char *const format = ";\n\nCFFI C function from %s.lib"; + Py_DECREF(lib->l_dict); + Py_DECREF(lib->l_libname); + Py_DECREF(lib->l_ffi); + PyObject_GC_Del(lib); +} + +static int lib_traverse(LibObject *lib, visitproc visit, void *arg) +{ + Py_VISIT(lib->l_dict); + Py_VISIT(lib->l_libname); + Py_VISIT(lib->l_ffi); + return 0; +} + +static PyObject *lib_repr(LibObject *lib) +{ + return PyText_FromFormat("<Lib object for '%.200s'>", + PyText_AS_UTF8(lib->l_libname)); +} + +static PyObject *lib_build_cpython_func(LibObject *lib, + const struct _cffi_global_s *g, + const char *s, int flags) +{ + /* First make sure the argument types and return type are really + built. The C extension code can then assume that they are, + by calling _cffi_type(). + */ + PyObject *result = NULL; + CTypeDescrObject **pfargs = NULL; + CTypeDescrObject *fresult; + Py_ssize_t nargs = 0; + struct CPyExtFunc_s *xfunc; + int i, type_index = _CFFI_GETARG(g->type_op); + _cffi_opcode_t *opcodes = lib->l_types_builder->ctx.types; + static const char *const format = ";\n\nCFFI C function from %s.lib"; const char *libname = PyText_AS_UTF8(lib->l_libname); - struct funcbuilder_s funcbuilder; - - /* return type: */ - fresult = realize_c_func_return_type(lib->l_types_builder, opcodes, - type_index); - if (fresult == NULL) - goto error; - - /* argument types: */ - /* note that if the arguments are already built, they have a - pointer in the 'opcodes' array, and GETOP() returns a - random even value. But OP_FUNCTION_END is odd, so the - condition below still works correctly. */ - i = type_index + 1; - while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) - i++; - pfargs = alloca(sizeof(CTypeDescrObject *) * (i - type_index - 1)); - i = type_index + 1; - while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) { - CTypeDescrObject *ct = realize_c_type(lib->l_types_builder, opcodes, i); - if (ct == NULL) - goto error; - pfargs[nargs++] = ct; - i++; - } - - memset(&funcbuilder, 0, sizeof(funcbuilder)); - if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) - goto error; - + struct funcbuilder_s funcbuilder; + + /* return type: */ + fresult = realize_c_func_return_type(lib->l_types_builder, opcodes, + type_index); + if (fresult == NULL) + goto error; + + /* argument types: */ + /* note that if the arguments are already built, they have a + pointer in the 'opcodes' array, and GETOP() returns a + random even value. But OP_FUNCTION_END is odd, so the + condition below still works correctly. */ + i = type_index + 1; + while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) + i++; + pfargs = alloca(sizeof(CTypeDescrObject *) * (i - type_index - 1)); + i = type_index + 1; + while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) { + CTypeDescrObject *ct = realize_c_type(lib->l_types_builder, opcodes, i); + if (ct == NULL) + goto error; + pfargs[nargs++] = ct; + i++; + } + + memset(&funcbuilder, 0, sizeof(funcbuilder)); + if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) + goto error; + /* The few bytes of memory we allocate here appear to leak, but this is not a real leak. Indeed, CPython never unloads its C extension modules. There is only one PyMem_Malloc() per real @@ -169,157 +169,157 @@ static PyObject *lib_build_cpython_func(LibObject *lib, global variable generated for each CPYTHON_BLTN defined in the C extension, and the effect would be the same (but a bit more complicated). - */ - xfunc = PyMem_Malloc(sizeof(struct CPyExtFunc_s) + - funcbuilder.nb_bytes + - strlen(format) + strlen(libname)); - if (xfunc == NULL) { - PyErr_NoMemory(); - goto error; - } - memset((char *)xfunc, 0, sizeof(struct CPyExtFunc_s)); - assert(g->address); - xfunc->md.ml_meth = (PyCFunction)g->address; - xfunc->md.ml_flags = flags; - xfunc->md.ml_name = g->name; - xfunc->md.ml_doc = xfunc->doc; - xfunc->direct_fn = g->size_or_direct_fn; - xfunc->type_index = type_index; - - /* build the docstring */ - funcbuilder.bufferp = xfunc->doc; - if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) - goto error; - sprintf(funcbuilder.bufferp - 1, format, libname); - /* done building the docstring */ - - result = PyCFunction_NewEx(&xfunc->md, (PyObject *)lib, lib->l_libname); - /* fall-through */ - error: - Py_XDECREF(fresult); - while (nargs > 0) { - --nargs; - Py_DECREF(pfargs[nargs]); - } - return result; -} - -static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name, - int recursion) -{ - /* does not return a new reference! */ - PyObject *x; - int index; - const struct _cffi_global_s *g; - CTypeDescrObject *ct; - builder_c_t *types_builder = lib->l_types_builder; + */ + xfunc = PyMem_Malloc(sizeof(struct CPyExtFunc_s) + + funcbuilder.nb_bytes + + strlen(format) + strlen(libname)); + if (xfunc == NULL) { + PyErr_NoMemory(); + goto error; + } + memset((char *)xfunc, 0, sizeof(struct CPyExtFunc_s)); + assert(g->address); + xfunc->md.ml_meth = (PyCFunction)g->address; + xfunc->md.ml_flags = flags; + xfunc->md.ml_name = g->name; + xfunc->md.ml_doc = xfunc->doc; + xfunc->direct_fn = g->size_or_direct_fn; + xfunc->type_index = type_index; + + /* build the docstring */ + funcbuilder.bufferp = xfunc->doc; + if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) + goto error; + sprintf(funcbuilder.bufferp - 1, format, libname); + /* done building the docstring */ + + result = PyCFunction_NewEx(&xfunc->md, (PyObject *)lib, lib->l_libname); + /* fall-through */ + error: + Py_XDECREF(fresult); + while (nargs > 0) { + --nargs; + Py_DECREF(pfargs[nargs]); + } + return result; +} + +static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name, + int recursion) +{ + /* does not return a new reference! */ + PyObject *x; + int index; + const struct _cffi_global_s *g; + CTypeDescrObject *ct; + builder_c_t *types_builder = lib->l_types_builder; const char *s = PyText_AsUTF8(name); - if (s == NULL) - return NULL; - - index = search_in_globals(&types_builder->ctx, s, strlen(s)); - if (index < 0) { - - if (types_builder->included_libs != NULL) { - Py_ssize_t i; - PyObject *included_ffis = types_builder->included_ffis; - PyObject *included_libs = types_builder->included_libs; - - if (recursion > 100) { - PyErr_SetString(PyExc_RuntimeError, - "recursion overflow in ffi.include() delegations"); - return NULL; - } - - for (i = 0; i < PyTuple_GET_SIZE(included_libs); i++) { - LibObject *lib1; - - lib1 = (LibObject *)PyTuple_GET_ITEM(included_libs, i); - if (lib1 != NULL) { - x = PyDict_GetItem(lib1->l_dict, name); - if (x != NULL) { - Py_INCREF(x); - goto found; - } - x = lib_build_and_cache_attr(lib1, name, recursion + 1); - if (x != NULL) { - Py_INCREF(x); - goto found; - } - } - else { - FFIObject *ffi1; - - ffi1 = (FFIObject *)PyTuple_GetItem(included_ffis, i); - if (ffi1 == NULL) - return NULL; - x = ffi_fetch_int_constant(ffi1, s, recursion + 1); - if (x != NULL) - goto found; - } - if (PyErr_Occurred()) - return NULL; - } - } - - if (recursion > 0) - return NULL; /* no error set, continue looking elsewhere */ - - PyErr_Format(PyExc_AttributeError, - "cffi library '%.200s' has no function, constant " - "or global variable named '%.200s'", - PyText_AS_UTF8(lib->l_libname), s); - return NULL; - } - - g = &types_builder->ctx.globals[index]; - - switch (_CFFI_GETOP(g->type_op)) { - - case _CFFI_OP_CPYTHON_BLTN_V: - x = lib_build_cpython_func(lib, g, s, METH_VARARGS); - break; - - case _CFFI_OP_CPYTHON_BLTN_N: - x = lib_build_cpython_func(lib, g, s, METH_NOARGS); - break; - - case _CFFI_OP_CPYTHON_BLTN_O: - x = lib_build_cpython_func(lib, g, s, METH_O); - break; - - case _CFFI_OP_CONSTANT_INT: - case _CFFI_OP_ENUM: - { - /* a constant integer whose value, in an "unsigned long long", - is obtained by calling the function at g->address */ - x = realize_global_int(types_builder, index); - break; - } - - case _CFFI_OP_CONSTANT: - case _CFFI_OP_DLOPEN_CONST: - { - /* a constant which is not of integer type */ - char *data; - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - - if (ct->ct_size <= 0) { - PyErr_Format(FFIError, "constant '%s' is of type '%s', " - "whose size is not known", s, ct->ct_name); - return NULL; - } - if (g->address == NULL) { - /* for dlopen() style */ - assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_DLOPEN_CONST); - data = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (data == NULL) - return NULL; - } - else { + if (s == NULL) + return NULL; + + index = search_in_globals(&types_builder->ctx, s, strlen(s)); + if (index < 0) { + + if (types_builder->included_libs != NULL) { + Py_ssize_t i; + PyObject *included_ffis = types_builder->included_ffis; + PyObject *included_libs = types_builder->included_libs; + + if (recursion > 100) { + PyErr_SetString(PyExc_RuntimeError, + "recursion overflow in ffi.include() delegations"); + return NULL; + } + + for (i = 0; i < PyTuple_GET_SIZE(included_libs); i++) { + LibObject *lib1; + + lib1 = (LibObject *)PyTuple_GET_ITEM(included_libs, i); + if (lib1 != NULL) { + x = PyDict_GetItem(lib1->l_dict, name); + if (x != NULL) { + Py_INCREF(x); + goto found; + } + x = lib_build_and_cache_attr(lib1, name, recursion + 1); + if (x != NULL) { + Py_INCREF(x); + goto found; + } + } + else { + FFIObject *ffi1; + + ffi1 = (FFIObject *)PyTuple_GetItem(included_ffis, i); + if (ffi1 == NULL) + return NULL; + x = ffi_fetch_int_constant(ffi1, s, recursion + 1); + if (x != NULL) + goto found; + } + if (PyErr_Occurred()) + return NULL; + } + } + + if (recursion > 0) + return NULL; /* no error set, continue looking elsewhere */ + + PyErr_Format(PyExc_AttributeError, + "cffi library '%.200s' has no function, constant " + "or global variable named '%.200s'", + PyText_AS_UTF8(lib->l_libname), s); + return NULL; + } + + g = &types_builder->ctx.globals[index]; + + switch (_CFFI_GETOP(g->type_op)) { + + case _CFFI_OP_CPYTHON_BLTN_V: + x = lib_build_cpython_func(lib, g, s, METH_VARARGS); + break; + + case _CFFI_OP_CPYTHON_BLTN_N: + x = lib_build_cpython_func(lib, g, s, METH_NOARGS); + break; + + case _CFFI_OP_CPYTHON_BLTN_O: + x = lib_build_cpython_func(lib, g, s, METH_O); + break; + + case _CFFI_OP_CONSTANT_INT: + case _CFFI_OP_ENUM: + { + /* a constant integer whose value, in an "unsigned long long", + is obtained by calling the function at g->address */ + x = realize_global_int(types_builder, index); + break; + } + + case _CFFI_OP_CONSTANT: + case _CFFI_OP_DLOPEN_CONST: + { + /* a constant which is not of integer type */ + char *data; + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + + if (ct->ct_size <= 0) { + PyErr_Format(FFIError, "constant '%s' is of type '%s', " + "whose size is not known", s, ct->ct_name); + return NULL; + } + if (g->address == NULL) { + /* for dlopen() style */ + assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_DLOPEN_CONST); + data = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); + if (data == NULL) + return NULL; + } + else { /* The few bytes of memory we allocate here appear to leak, but this is not a real leak. Indeed, CPython never unloads its C extension modules. There is only one PyMem_Malloc() per real @@ -334,218 +334,218 @@ static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name, cases; but there is no point and it only makes the remaining less-common cases more suspicious. */ - assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT); - data = PyMem_Malloc(ct->ct_size); - if (data == NULL) { - PyErr_NoMemory(); - return NULL; - } - ((void(*)(char*))g->address)(data); - } - x = convert_to_object(data, ct); - Py_DECREF(ct); - break; - } - - case _CFFI_OP_GLOBAL_VAR: - { - /* global variable of the exact type specified here - (nowadays, only used by the ABI mode or backward - compatibility; see _CFFI_OP_GLOBAL_VAR_F for the API mode) - */ - Py_ssize_t g_size = (Py_ssize_t)g->size_or_direct_fn; - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - if (g_size != ct->ct_size && g_size != 0 && ct->ct_size > 0) { - PyErr_Format(FFIError, - "global variable '%.200s' should be %zd bytes " - "according to the cdef, but is actually %zd", - s, ct->ct_size, g_size); - x = NULL; - } - else { - void *address = g->address; - if (address == NULL) { - /* for dlopen() style */ - address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (address == NULL) - return NULL; - } - x = make_global_var(name, ct, address, NULL); - } - Py_DECREF(ct); - break; - } - - case _CFFI_OP_GLOBAL_VAR_F: - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - x = make_global_var(name, ct, NULL, (gs_fetch_addr_fn)g->address); - Py_DECREF(ct); - break; - - case _CFFI_OP_DLOPEN_FUNC: - { - /* For dlopen(): the function of the given 'name'. We use - dlsym() to get the address of something in the dynamic - library, which we interpret as being exactly a function of - the specified type. - */ - PyObject *ct1; - void *address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (address == NULL) - return NULL; - - ct1 = realize_c_type_or_func(types_builder, - types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct1 == NULL) - return NULL; - - assert(!CTypeDescr_Check(ct1)); /* must be a function */ - x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1)); - - Py_DECREF(ct1); - break; - } - - case _CFFI_OP_EXTERN_PYTHON: - /* for reading 'lib.bar' where bar is declared with extern "Python" */ - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - x = convert_to_object((char *)&g->size_or_direct_fn, ct); - Py_DECREF(ct); - break; - - default: - PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d", - (int)_CFFI_GETOP(g->type_op)); - return NULL; - } - - found: - if (x != NULL) { - int err = PyDict_SetItem(lib->l_dict, name, x); - Py_DECREF(x); - if (err < 0) /* else there is still one ref left in the dict */ - return NULL; - } - return x; -} - -#define LIB_GET_OR_CACHE_ADDR(x, lib, name, error) \ - do { \ - x = PyDict_GetItem(lib->l_dict, name); \ - if (x == NULL) { \ - x = lib_build_and_cache_attr(lib, name, 0); \ - if (x == NULL) { \ - error; \ - } \ - } \ - } while (0) - -static PyObject *_lib_dir1(LibObject *lib, int ignore_global_vars) -{ - const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; - int i, count = 0, total = lib->l_types_builder->ctx.num_globals; - PyObject *s, *lst = PyList_New(total); - if (lst == NULL) - return NULL; - - for (i = 0; i < total; i++) { - if (ignore_global_vars) { - int op = _CFFI_GETOP(g[i].type_op); - if (op == _CFFI_OP_GLOBAL_VAR || op == _CFFI_OP_GLOBAL_VAR_F) - continue; - } - s = PyText_FromString(g[i].name); - if (s == NULL) - goto error; - PyList_SET_ITEM(lst, count, s); - count++; - } - if (PyList_SetSlice(lst, count, total, NULL) < 0) - goto error; - return lst; - - error: - Py_DECREF(lst); - return NULL; -} - -static PyObject *_lib_dict(LibObject *lib) -{ - const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; - int i, total = lib->l_types_builder->ctx.num_globals; - PyObject *name, *x, *d = PyDict_New(); - if (d == NULL) - return NULL; - - for (i = 0; i < total; i++) { - name = PyText_FromString(g[i].name); - if (name == NULL) - goto error; - - LIB_GET_OR_CACHE_ADDR(x, lib, name, goto error); - - if (PyDict_SetItem(d, name, x) < 0) - goto error; - Py_DECREF(name); - } - return d; - - error: - Py_XDECREF(name); - Py_DECREF(d); - return NULL; -} - -static PyObject *lib_getattr(LibObject *lib, PyObject *name) -{ + assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT); + data = PyMem_Malloc(ct->ct_size); + if (data == NULL) { + PyErr_NoMemory(); + return NULL; + } + ((void(*)(char*))g->address)(data); + } + x = convert_to_object(data, ct); + Py_DECREF(ct); + break; + } + + case _CFFI_OP_GLOBAL_VAR: + { + /* global variable of the exact type specified here + (nowadays, only used by the ABI mode or backward + compatibility; see _CFFI_OP_GLOBAL_VAR_F for the API mode) + */ + Py_ssize_t g_size = (Py_ssize_t)g->size_or_direct_fn; + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + if (g_size != ct->ct_size && g_size != 0 && ct->ct_size > 0) { + PyErr_Format(FFIError, + "global variable '%.200s' should be %zd bytes " + "according to the cdef, but is actually %zd", + s, ct->ct_size, g_size); + x = NULL; + } + else { + void *address = g->address; + if (address == NULL) { + /* for dlopen() style */ + address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); + if (address == NULL) + return NULL; + } + x = make_global_var(name, ct, address, NULL); + } + Py_DECREF(ct); + break; + } + + case _CFFI_OP_GLOBAL_VAR_F: + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + x = make_global_var(name, ct, NULL, (gs_fetch_addr_fn)g->address); + Py_DECREF(ct); + break; + + case _CFFI_OP_DLOPEN_FUNC: + { + /* For dlopen(): the function of the given 'name'. We use + dlsym() to get the address of something in the dynamic + library, which we interpret as being exactly a function of + the specified type. + */ + PyObject *ct1; + void *address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); + if (address == NULL) + return NULL; + + ct1 = realize_c_type_or_func(types_builder, + types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct1 == NULL) + return NULL; + + assert(!CTypeDescr_Check(ct1)); /* must be a function */ + x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1)); + + Py_DECREF(ct1); + break; + } + + case _CFFI_OP_EXTERN_PYTHON: + /* for reading 'lib.bar' where bar is declared with extern "Python" */ + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + x = convert_to_object((char *)&g->size_or_direct_fn, ct); + Py_DECREF(ct); + break; + + default: + PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d", + (int)_CFFI_GETOP(g->type_op)); + return NULL; + } + + found: + if (x != NULL) { + int err = PyDict_SetItem(lib->l_dict, name, x); + Py_DECREF(x); + if (err < 0) /* else there is still one ref left in the dict */ + return NULL; + } + return x; +} + +#define LIB_GET_OR_CACHE_ADDR(x, lib, name, error) \ + do { \ + x = PyDict_GetItem(lib->l_dict, name); \ + if (x == NULL) { \ + x = lib_build_and_cache_attr(lib, name, 0); \ + if (x == NULL) { \ + error; \ + } \ + } \ + } while (0) + +static PyObject *_lib_dir1(LibObject *lib, int ignore_global_vars) +{ + const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; + int i, count = 0, total = lib->l_types_builder->ctx.num_globals; + PyObject *s, *lst = PyList_New(total); + if (lst == NULL) + return NULL; + + for (i = 0; i < total; i++) { + if (ignore_global_vars) { + int op = _CFFI_GETOP(g[i].type_op); + if (op == _CFFI_OP_GLOBAL_VAR || op == _CFFI_OP_GLOBAL_VAR_F) + continue; + } + s = PyText_FromString(g[i].name); + if (s == NULL) + goto error; + PyList_SET_ITEM(lst, count, s); + count++; + } + if (PyList_SetSlice(lst, count, total, NULL) < 0) + goto error; + return lst; + + error: + Py_DECREF(lst); + return NULL; +} + +static PyObject *_lib_dict(LibObject *lib) +{ + const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; + int i, total = lib->l_types_builder->ctx.num_globals; + PyObject *name, *x, *d = PyDict_New(); + if (d == NULL) + return NULL; + + for (i = 0; i < total; i++) { + name = PyText_FromString(g[i].name); + if (name == NULL) + goto error; + + LIB_GET_OR_CACHE_ADDR(x, lib, name, goto error); + + if (PyDict_SetItem(d, name, x) < 0) + goto error; + Py_DECREF(name); + } + return d; + + error: + Py_XDECREF(name); + Py_DECREF(d); + return NULL; +} + +static PyObject *lib_getattr(LibObject *lib, PyObject *name) +{ const char *p; - PyObject *x; - LIB_GET_OR_CACHE_ADDR(x, lib, name, goto missing); - - if (GlobSupport_Check(x)) { - return read_global_var((GlobSupportObject *)x); - } - Py_INCREF(x); - return x; - - missing: + PyObject *x; + LIB_GET_OR_CACHE_ADDR(x, lib, name, goto missing); + + if (GlobSupport_Check(x)) { + return read_global_var((GlobSupportObject *)x); + } + Py_INCREF(x); + return x; + + missing: /*** ATTRIBUTEERROR IS SET HERE ***/ - p = PyText_AsUTF8(name); - if (p == NULL) - return NULL; - if (strcmp(p, "__all__") == 0) { - PyErr_Clear(); - return _lib_dir1(lib, 1); - } - if (strcmp(p, "__dict__") == 0) { - PyErr_Clear(); - return _lib_dict(lib); - } - if (strcmp(p, "__class__") == 0) { - PyErr_Clear(); - x = (PyObject *)&PyModule_Type; - /* ^^^ used to be Py_TYPE(lib). But HAAAAAACK! That makes - help() behave correctly. I couldn't find a more reasonable - way. Urgh. */ - Py_INCREF(x); - return x; - } - /* this hack is for Python 3.5, and also to give a more - module-like behavior */ - if (strcmp(p, "__name__") == 0) { - PyErr_Clear(); - return PyText_FromFormat("%s.lib", PyText_AS_UTF8(lib->l_libname)); - } + p = PyText_AsUTF8(name); + if (p == NULL) + return NULL; + if (strcmp(p, "__all__") == 0) { + PyErr_Clear(); + return _lib_dir1(lib, 1); + } + if (strcmp(p, "__dict__") == 0) { + PyErr_Clear(); + return _lib_dict(lib); + } + if (strcmp(p, "__class__") == 0) { + PyErr_Clear(); + x = (PyObject *)&PyModule_Type; + /* ^^^ used to be Py_TYPE(lib). But HAAAAAACK! That makes + help() behave correctly. I couldn't find a more reasonable + way. Urgh. */ + Py_INCREF(x); + return x; + } + /* this hack is for Python 3.5, and also to give a more + module-like behavior */ + if (strcmp(p, "__name__") == 0) { + PyErr_Clear(); + return PyText_FromFormat("%s.lib", PyText_AS_UTF8(lib->l_libname)); + } #if PY_MAJOR_VERSION >= 3 if (strcmp(p, "__loader__") == 0 || strcmp(p, "__spec__") == 0) { /* some more module-like behavior hacks */ @@ -554,163 +554,163 @@ static PyObject *lib_getattr(LibObject *lib, PyObject *name) return Py_None; } #endif - return NULL; -} - -static int lib_setattr(LibObject *lib, PyObject *name, PyObject *val) -{ - PyObject *x; - LIB_GET_OR_CACHE_ADDR(x, lib, name, return -1); - - if (val == NULL) { - PyErr_SetString(PyExc_AttributeError, "C attribute cannot be deleted"); - return -1; - } - - if (GlobSupport_Check(x)) { - return write_global_var((GlobSupportObject *)x, val); - } - - PyErr_Format(PyExc_AttributeError, - "cannot write to function or constant '%.200s'", - PyText_Check(name) ? PyText_AS_UTF8(name) : "?"); - return -1; -} - -static PyObject *lib_dir(PyObject *self, PyObject *noarg) -{ - return _lib_dir1((LibObject *)self, 0); -} - -static PyMethodDef lib_methods[] = { - {"__dir__", lib_dir, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject Lib_Type = { - PyVarObject_HEAD_INIT(NULL, 0) + return NULL; +} + +static int lib_setattr(LibObject *lib, PyObject *name, PyObject *val) +{ + PyObject *x; + LIB_GET_OR_CACHE_ADDR(x, lib, name, return -1); + + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, "C attribute cannot be deleted"); + return -1; + } + + if (GlobSupport_Check(x)) { + return write_global_var((GlobSupportObject *)x, val); + } + + PyErr_Format(PyExc_AttributeError, + "cannot write to function or constant '%.200s'", + PyText_Check(name) ? PyText_AS_UTF8(name) : "?"); + return -1; +} + +static PyObject *lib_dir(PyObject *self, PyObject *noarg) +{ + return _lib_dir1((LibObject *)self, 0); +} + +static PyMethodDef lib_methods[] = { + {"__dir__", lib_dir, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject Lib_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.Lib", - sizeof(LibObject), - 0, - (destructor)lib_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)lib_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc)lib_getattr, /* tp_getattro */ - (setattrofunc)lib_setattr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)lib_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - lib_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(LibObject, l_dict), /* tp_dictoffset */ -}; - + sizeof(LibObject), + 0, + (destructor)lib_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)lib_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + (getattrofunc)lib_getattr, /* tp_getattro */ + (setattrofunc)lib_setattr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)lib_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + lib_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(LibObject, l_dict), /* tp_dictoffset */ +}; + static LibObject *lib_internal_new(FFIObject *ffi, const char *module_name, void *dlopen_libhandle, int auto_close) -{ - LibObject *lib; - PyObject *libname, *dict; - - libname = PyText_FromString(module_name); - if (libname == NULL) - goto err1; - - dict = PyDict_New(); - if (dict == NULL) - goto err2; - - lib = (LibObject *)PyType_GenericAlloc(&Lib_Type, 0); - if (lib == NULL) - goto err3; - - lib->l_types_builder = &ffi->types_builder; - lib->l_dict = dict; - lib->l_libname = libname; - Py_INCREF(ffi); - lib->l_ffi = ffi; - lib->l_libhandle = dlopen_libhandle; +{ + LibObject *lib; + PyObject *libname, *dict; + + libname = PyText_FromString(module_name); + if (libname == NULL) + goto err1; + + dict = PyDict_New(); + if (dict == NULL) + goto err2; + + lib = (LibObject *)PyType_GenericAlloc(&Lib_Type, 0); + if (lib == NULL) + goto err3; + + lib->l_types_builder = &ffi->types_builder; + lib->l_dict = dict; + lib->l_libname = libname; + Py_INCREF(ffi); + lib->l_ffi = ffi; + lib->l_libhandle = dlopen_libhandle; lib->l_auto_close = auto_close; - return lib; - - err3: - Py_DECREF(dict); - err2: - Py_DECREF(libname); - err1: + return lib; + + err3: + Py_DECREF(dict); + err2: + Py_DECREF(libname); + err1: if (auto_close) cdlopen_close_ignore_errors(dlopen_libhandle); - return NULL; -} - -static PyObject *address_of_global_var(PyObject *args) -{ - LibObject *lib; - PyObject *x, *o_varname; - char *varname; - - if (!PyArg_ParseTuple(args, "O!s", &Lib_Type, &lib, &varname)) - return NULL; - - /* rebuild a string from 'varname', to do typechecks and to force - a unicode back to a plain string (on python 2) */ - o_varname = PyText_FromString(varname); - if (o_varname == NULL) - return NULL; - - LIB_GET_OR_CACHE_ADDR(x, lib, o_varname, goto error); - Py_DECREF(o_varname); - if (GlobSupport_Check(x)) { - return cg_addressof_global_var((GlobSupportObject *)x); - } - else { - struct CPyExtFunc_s *exf = _cpyextfunc_get(x); - if (exf != NULL) { /* an OP_CPYTHON_BLTN: '&func' returns a cdata */ - PyObject *ct; - if (exf->direct_fn == NULL) { - Py_INCREF(x); /* backward compatibility */ - return x; - } - ct = _cpyextfunc_type(lib, exf); - if (ct == NULL) - return NULL; - x = new_simple_cdata(exf->direct_fn, (CTypeDescrObject *)ct); - Py_DECREF(ct); - return x; - } - if (CData_Check(x) && /* a constant functionptr cdata: 'f == &f' */ - (((CDataObject *)x)->c_type->ct_flags & CT_FUNCTIONPTR) != 0) { - Py_INCREF(x); - return x; - } - else { - PyErr_Format(PyExc_AttributeError, - "cannot take the address of the constant '%.200s'", - varname); - return NULL; - } - } - - error: - Py_DECREF(o_varname); - return NULL; -} + return NULL; +} + +static PyObject *address_of_global_var(PyObject *args) +{ + LibObject *lib; + PyObject *x, *o_varname; + char *varname; + + if (!PyArg_ParseTuple(args, "O!s", &Lib_Type, &lib, &varname)) + return NULL; + + /* rebuild a string from 'varname', to do typechecks and to force + a unicode back to a plain string (on python 2) */ + o_varname = PyText_FromString(varname); + if (o_varname == NULL) + return NULL; + + LIB_GET_OR_CACHE_ADDR(x, lib, o_varname, goto error); + Py_DECREF(o_varname); + if (GlobSupport_Check(x)) { + return cg_addressof_global_var((GlobSupportObject *)x); + } + else { + struct CPyExtFunc_s *exf = _cpyextfunc_get(x); + if (exf != NULL) { /* an OP_CPYTHON_BLTN: '&func' returns a cdata */ + PyObject *ct; + if (exf->direct_fn == NULL) { + Py_INCREF(x); /* backward compatibility */ + return x; + } + ct = _cpyextfunc_type(lib, exf); + if (ct == NULL) + return NULL; + x = new_simple_cdata(exf->direct_fn, (CTypeDescrObject *)ct); + Py_DECREF(ct); + return x; + } + if (CData_Check(x) && /* a constant functionptr cdata: 'f == &f' */ + (((CDataObject *)x)->c_type->ct_flags & CT_FUNCTIONPTR) != 0) { + Py_INCREF(x); + return x; + } + else { + PyErr_Format(PyExc_AttributeError, + "cannot take the address of the constant '%.200s'", + varname); + return NULL; + } + } + + error: + Py_DECREF(o_varname); + return NULL; +} diff --git a/contrib/python/cffi/c/libffi_msvc/ffi.c b/contrib/python/cffi/c/libffi_msvc/ffi.c index 581d659982..72e67c5f24 100644 --- a/contrib/python/cffi/c/libffi_msvc/ffi.c +++ b/contrib/python/cffi/c/libffi_msvc/ffi.c @@ -1,495 +1,495 @@ -/* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. - Copyright (c) 2002 Ranjit Mathew - Copyright (c) 2002 Bo Thorsen - Copyright (c) 2002 Roger Sayle - - x86 Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#include <ffi.h> -#include <ffi_common.h> - -#include <stdlib.h> - -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -extern void Py_FatalError(const char *msg); - -/*@-exportheader@*/ -void ffi_prep_args(char *stack, extended_cif *ecif) -/*@=exportheader@*/ -{ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. + Copyright (c) 2002 Ranjit Mathew + Copyright (c) 2002 Bo Thorsen + Copyright (c) 2002 Roger Sayle + + x86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +extern void Py_FatalError(const char *msg); + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ unsigned int i; void **p_argv; char *argp; ffi_type **p_arg; - - argp = stack; - if (ecif->cif->flags == FFI_TYPE_STRUCT) - { - *(void **) argp = ecif->rvalue; - argp += sizeof(void *); - } - - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - i != 0; - i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(void *) - 1) & (size_t) argp) - argp = (char *) ALIGN(argp, sizeof(void *)); - - z = (*p_arg)->size; - if (z < sizeof(int)) - { - z = sizeof(int); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); - break; - - case FFI_TYPE_SINT32: - *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); - break; - - case FFI_TYPE_UINT32: - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); - break; - - case FFI_TYPE_STRUCT: - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); - break; - - default: - FFI_ASSERT(0); - } - } -#ifdef _WIN64 + + argp = stack; + if (ecif->cif->flags == FFI_TYPE_STRUCT) + { + *(void **) argp = ecif->rvalue; + argp += sizeof(void *); + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(void *) - 1) & (size_t) argp) + argp = (char *) ALIGN(argp, sizeof(void *)); + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } +#ifdef _WIN64 else if (z != 1 && z != 2 && z != 4 && z != 8) - { - /* On Win64, if a single argument takes more than 8 bytes, - then it is always passed by reference. */ - *(void **)argp = *p_argv; - z = 8; - } -#endif - else - { - memcpy(argp, *p_argv, z); - } - p_argv++; - argp += z; - } - - if (argp - stack > (long)ecif->cif->bytes) - { - Py_FatalError("FFI BUG: not enough stack space for arguments"); - } - return; -} - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif) -{ - /* Set the return type flag */ - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: - case FFI_TYPE_SINT64: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - case FFI_TYPE_LONGDOUBLE: - cif->flags = (unsigned) cif->rtype->type; - break; - - case FFI_TYPE_STRUCT: - /* MSVC returns small structures in registers. Put in cif->flags - the value FFI_TYPE_STRUCT only if the structure is big enough; - otherwise, put the 4- or 8-bytes integer type. */ + { + /* On Win64, if a single argument takes more than 8 bytes, + then it is always passed by reference. */ + *(void **)argp = *p_argv; + z = 8; + } +#endif + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } + + if (argp - stack > (long)ecif->cif->bytes) + { + Py_FatalError("FFI BUG: not enough stack space for arguments"); + } + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_STRUCT: + /* MSVC returns small structures in registers. Put in cif->flags + the value FFI_TYPE_STRUCT only if the structure is big enough; + otherwise, put the 4- or 8-bytes integer type. */ if (cif->rtype->size == 1 || cif->rtype->size == 2 || cif->rtype->size == 4) - cif->flags = FFI_TYPE_INT; + cif->flags = FFI_TYPE_INT; else if (cif->rtype->size == 8) - cif->flags = FFI_TYPE_SINT64; - else - cif->flags = FFI_TYPE_STRUCT; - break; - - case FFI_TYPE_UINT64: -#ifdef _WIN64 - case FFI_TYPE_POINTER: -#endif - cif->flags = FFI_TYPE_SINT64; - break; - - default: - cif->flags = FFI_TYPE_INT; - break; - } - - return FFI_OK; -} - -#ifdef _WIN32 -extern int -ffi_call_x86(void (*)(char *, extended_cif *), - /*@out@*/ extended_cif *, - unsigned, unsigned, - /*@out@*/ unsigned *, - void (*fn)()); -#endif - -#ifdef _WIN64 -extern int -ffi_call_AMD64(void (*)(char *, extended_cif *), - /*@out@*/ extended_cif *, - unsigned, unsigned, - /*@out@*/ unsigned *, - void (*fn)()); -#endif - -int -ffi_call(/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ void **avalue) -{ - extended_cif ecif; - - ecif.cif = cif; - ecif.avalue = avalue; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - - if ((rvalue == NULL) && - (cif->flags == FFI_TYPE_STRUCT)) - { - /*@-sysunrecog@*/ - ecif.rvalue = alloca(cif->rtype->size); - /*@=sysunrecog@*/ - } - else - ecif.rvalue = rvalue; - - - switch (cif->abi) - { -#if !defined(_WIN64) - case FFI_SYSV: - case FFI_STDCALL: - return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); - break; -#else - case FFI_SYSV: - /*@-usedef@*/ - return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); - /*@=usedef@*/ - break; -#endif - - default: - FFI_ASSERT(0); - break; - } - return -1; /* theller: Hrm. */ -} - - -/** private members **/ - -static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, - void** args, ffi_cif* cif); -/* This function is jumped to by the trampoline */ - -#ifdef _WIN64 -void * -#else -static void __fastcall -#endif -ffi_closure_SYSV (ffi_closure *closure, char *argp) -{ - // this is our return value storage - long double res; - - // our various things... - ffi_cif *cif; - void **arg_area; - unsigned short rtype; - void *resp = (void*)&res; - void *args = argp + sizeof(void *); - - cif = closure->cif; - arg_area = (void**) alloca (cif->nargs * sizeof (void*)); - - /* this call will initialize ARG_AREA, such that each - * element in that array points to the corresponding - * value on the stack; and if the function returns - * a structure, it will re-set RESP to point to the - * structure return address. */ - - ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif); - - (closure->fun) (cif, resp, arg_area, closure->user_data); - - rtype = cif->flags; - -#if defined(_WIN32) && !defined(_WIN64) -#ifdef _MSC_VER - /* now, do a generic return based on the value of rtype */ - if (rtype == FFI_TYPE_INT) - { - _asm mov eax, resp ; - _asm mov eax, [eax] ; - } - else if (rtype == FFI_TYPE_FLOAT) - { - _asm mov eax, resp ; - _asm fld DWORD PTR [eax] ; -// asm ("flds (%0)" : : "r" (resp) : "st" ); - } + cif->flags = FFI_TYPE_SINT64; + else + cif->flags = FFI_TYPE_STRUCT; + break; + + case FFI_TYPE_UINT64: +#ifdef _WIN64 + case FFI_TYPE_POINTER: +#endif + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +#ifdef _WIN32 +extern int +ffi_call_x86(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +#endif + +#ifdef _WIN64 +extern int +ffi_call_AMD64(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +#endif + +int +ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->flags == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { +#if !defined(_WIN64) + case FFI_SYSV: + case FFI_STDCALL: + return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; +#else + case FFI_SYSV: + /*@-usedef@*/ + return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#endif + + default: + FFI_ASSERT(0); + break; + } + return -1; /* theller: Hrm. */ +} + + +/** private members **/ + +static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, + void** args, ffi_cif* cif); +/* This function is jumped to by the trampoline */ + +#ifdef _WIN64 +void * +#else +static void __fastcall +#endif +ffi_closure_SYSV (ffi_closure *closure, char *argp) +{ + // this is our return value storage + long double res; + + // our various things... + ffi_cif *cif; + void **arg_area; + unsigned short rtype; + void *resp = (void*)&res; + void *args = argp + sizeof(void *); + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + rtype = cif->flags; + +#if defined(_WIN32) && !defined(_WIN64) +#ifdef _MSC_VER + /* now, do a generic return based on the value of rtype */ + if (rtype == FFI_TYPE_INT) + { + _asm mov eax, resp ; + _asm mov eax, [eax] ; + } + else if (rtype == FFI_TYPE_FLOAT) + { + _asm mov eax, resp ; + _asm fld DWORD PTR [eax] ; +// asm ("flds (%0)" : : "r" (resp) : "st" ); + } else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE) - { - _asm mov eax, resp ; - _asm fld QWORD PTR [eax] ; -// asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); - } - else if (rtype == FFI_TYPE_SINT64) - { - _asm mov edx, resp ; - _asm mov eax, [edx] ; - _asm mov edx, [edx + 4] ; -// asm ("movl 0(%0),%%eax;" -// "movl 4(%0),%%edx" -// : : "r"(resp) -// : "eax", "edx"); - } + { + _asm mov eax, resp ; + _asm fld QWORD PTR [eax] ; +// asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_SINT64) + { + _asm mov edx, resp ; + _asm mov eax, [edx] ; + _asm mov edx, [edx + 4] ; +// asm ("movl 0(%0),%%eax;" +// "movl 4(%0),%%edx" +// : : "r"(resp) +// : "eax", "edx"); + } else if (rtype == FFI_TYPE_STRUCT) { _asm mov eax, resp ; } -#else - /* now, do a generic return based on the value of rtype */ - if (rtype == FFI_TYPE_INT) - { - asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); - } - else if (rtype == FFI_TYPE_FLOAT) - { - asm ("flds (%0)" : : "r" (resp) : "st" ); - } +#else + /* now, do a generic return based on the value of rtype */ + if (rtype == FFI_TYPE_INT) + { + asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); + } + else if (rtype == FFI_TYPE_FLOAT) + { + asm ("flds (%0)" : : "r" (resp) : "st" ); + } else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE) - { - asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); - } - else if (rtype == FFI_TYPE_SINT64) - { - asm ("movl 0(%0),%%eax;" - "movl 4(%0),%%edx" - : : "r"(resp) - : "eax", "edx"); - } + { + asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_SINT64) + { + asm ("movl 0(%0),%%eax;" + "movl 4(%0),%%edx" + : : "r"(resp) + : "eax", "edx"); + } else if (rtype == FFI_TYPE_STRUCT) { asm ("movl %0,%%eax" : : "r" (resp) : "eax"); } -#endif -#endif - -#ifdef _WIN64 - /* The result is returned in rax. This does the right thing for - result types except for floats; we have to 'mov xmm0, rax' in the - caller to correct this. - */ +#endif +#endif + +#ifdef _WIN64 + /* The result is returned in rax. This does the right thing for + result types except for floats; we have to 'mov xmm0, rax' in the + caller to correct this. + */ if (rtype == FFI_TYPE_STRUCT) return resp; - return *(void **)resp; -#endif -} - -/*@-exportheader@*/ -static void -ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, - void **avalue, ffi_cif *cif) -/*@=exportheader@*/ -{ + return *(void **)resp; +#endif +} + +/*@-exportheader@*/ +static void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif) +/*@=exportheader@*/ +{ unsigned int i; void **p_argv; char *argp; ffi_type **p_arg; - - argp = stack; - - if ( cif->flags == FFI_TYPE_STRUCT ) { - *rvalue = *(void **) argp; - argp += 4; - } - - p_argv = avalue; - - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(char *) - 1) & (size_t) argp) { - argp = (char *) ALIGN(argp, sizeof(char*)); - } - - z = (*p_arg)->size; - - /* because we're little endian, this is what it turns into. */ - -#ifdef _WIN64 + + argp = stack; + + if ( cif->flags == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += 4; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(char *) - 1) & (size_t) argp) { + argp = (char *) ALIGN(argp, sizeof(char*)); + } + + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + +#ifdef _WIN64 if (z != 1 && z != 2 && z != 4 && z != 8) - { - /* On Win64, if a single argument takes more than 8 bytes, - then it is always passed by reference. */ - *p_argv = *((void**) argp); - z = 8; - } - else -#endif - *p_argv = (void*) argp; - - p_argv++; - argp += z; - } - - return; -} - -/* the cif must already be prep'ed */ -extern void ffi_closure_OUTER(); - -ffi_status -ffi_prep_closure_loc (ffi_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc) -{ - short bytes; - char *tramp; -#ifdef _WIN64 - int mask = 0; -#endif - FFI_ASSERT (cif->abi == FFI_SYSV); - - if (cif->abi == FFI_SYSV) - bytes = 0; -#if !defined(_WIN64) - else if (cif->abi == FFI_STDCALL) - bytes = cif->bytes; -#endif - else - return FFI_BAD_ABI; - - tramp = &closure->tramp[0]; - -#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1 -#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*) -#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short) -#define INT(x) *(int*)tramp = x, tramp += sizeof(int) - -#ifdef _WIN64 - if (cif->nargs >= 1 && - (cif->arg_types[0]->type == FFI_TYPE_FLOAT - || cif->arg_types[0]->type == FFI_TYPE_DOUBLE)) - mask |= 1; - if (cif->nargs >= 2 && - (cif->arg_types[1]->type == FFI_TYPE_FLOAT - || cif->arg_types[1]->type == FFI_TYPE_DOUBLE)) - mask |= 2; - if (cif->nargs >= 3 && - (cif->arg_types[2]->type == FFI_TYPE_FLOAT - || cif->arg_types[2]->type == FFI_TYPE_DOUBLE)) - mask |= 4; - if (cif->nargs >= 4 && - (cif->arg_types[3]->type == FFI_TYPE_FLOAT - || cif->arg_types[3]->type == FFI_TYPE_DOUBLE)) - mask |= 8; - + { + /* On Win64, if a single argument takes more than 8 bytes, + then it is always passed by reference. */ + *p_argv = *((void**) argp); + z = 8; + } + else +#endif + *p_argv = (void*) argp; + + p_argv++; + argp += z; + } + + return; +} + +/* the cif must already be prep'ed */ +extern void ffi_closure_OUTER(); + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + short bytes; + char *tramp; +#ifdef _WIN64 + int mask = 0; +#endif + FFI_ASSERT (cif->abi == FFI_SYSV); + + if (cif->abi == FFI_SYSV) + bytes = 0; +#if !defined(_WIN64) + else if (cif->abi == FFI_STDCALL) + bytes = cif->bytes; +#endif + else + return FFI_BAD_ABI; + + tramp = &closure->tramp[0]; + +#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1 +#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*) +#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short) +#define INT(x) *(int*)tramp = x, tramp += sizeof(int) + +#ifdef _WIN64 + if (cif->nargs >= 1 && + (cif->arg_types[0]->type == FFI_TYPE_FLOAT + || cif->arg_types[0]->type == FFI_TYPE_DOUBLE)) + mask |= 1; + if (cif->nargs >= 2 && + (cif->arg_types[1]->type == FFI_TYPE_FLOAT + || cif->arg_types[1]->type == FFI_TYPE_DOUBLE)) + mask |= 2; + if (cif->nargs >= 3 && + (cif->arg_types[2]->type == FFI_TYPE_FLOAT + || cif->arg_types[2]->type == FFI_TYPE_DOUBLE)) + mask |= 4; + if (cif->nargs >= 4 && + (cif->arg_types[3]->type == FFI_TYPE_FLOAT + || cif->arg_types[3]->type == FFI_TYPE_DOUBLE)) + mask |= 8; + /* if we return a non-small struct, then the first argument is a pointer * to the return area, and all real arguments are shifted by one */ if (cif->flags == FFI_TYPE_STRUCT) mask = (mask & ~8) << 1; - /* 41 BB ---- mov r11d,mask */ - BYTES("\x41\xBB"); INT(mask); - - /* 48 B8 -------- mov rax, closure */ - BYTES("\x48\xB8"); POINTER(closure); - - /* 49 BA -------- mov r10, ffi_closure_OUTER */ - BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER); - - /* 41 FF E2 jmp r10 */ - BYTES("\x41\xFF\xE2"); - -#else - - /* mov ecx, closure */ - BYTES("\xb9"); POINTER(closure); - - /* mov edx, esp */ - BYTES("\x8b\xd4"); - - /* call ffi_closure_SYSV */ - BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4)); - - /* ret bytes */ - BYTES("\xc2"); - SHORT(bytes); - -#endif - - if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE) - Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__); - - closure->cif = cif; - closure->user_data = user_data; - closure->fun = fun; - return FFI_OK; -} + /* 41 BB ---- mov r11d,mask */ + BYTES("\x41\xBB"); INT(mask); + + /* 48 B8 -------- mov rax, closure */ + BYTES("\x48\xB8"); POINTER(closure); + + /* 49 BA -------- mov r10, ffi_closure_OUTER */ + BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER); + + /* 41 FF E2 jmp r10 */ + BYTES("\x41\xFF\xE2"); + +#else + + /* mov ecx, closure */ + BYTES("\xb9"); POINTER(closure); + + /* mov edx, esp */ + BYTES("\x8b\xd4"); + + /* call ffi_closure_SYSV */ + BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4)); + + /* ret bytes */ + BYTES("\xc2"); + SHORT(bytes); + +#endif + + if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE) + Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + return FFI_OK; +} diff --git a/contrib/python/cffi/c/libffi_msvc/ffi.h b/contrib/python/cffi/c/libffi_msvc/ffi.h index 97cdb59aa8..eb8d78b944 100644 --- a/contrib/python/cffi/c/libffi_msvc/ffi.h +++ b/contrib/python/cffi/c/libffi_msvc/ffi.h @@ -1,322 +1,322 @@ -/* -----------------------------------------------------------------*-C-*- - libffi 2.00-beta - Copyright (c) 1996-2003 Red Hat, Inc. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - ----------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------- - The basic API is described in the README file. - - The raw API is designed to bypass some of the argument packing - and unpacking on architectures for which it can be avoided. - - The closure API allows interpreted functions to be packaged up - inside a C function pointer, so that they can be called as C functions, - with no understanding on the client side that they are interpreted. - It can also be used in other cases in which it is necessary to package - up a user specified parameter and a function pointer as a single - function pointer. - - The closure API must be implemented in order to get its functionality, - e.g. for use by gij. Routines are provided to emulate the raw API - if the underlying platform doesn't allow faster implementation. - - More details on the raw and cloure API can be found in: - - http://gcc.gnu.org/ml/java/1999-q3/msg00138.html - - and - - http://gcc.gnu.org/ml/java/1999-q3/msg00174.html - -------------------------------------------------------------------- */ - -#ifndef LIBFFI_H -#define LIBFFI_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Specify which architecture libffi is configured for. */ -//XXX #define X86 - -/* ---- System configuration information --------------------------------- */ - -#include <ffitarget.h> - -#ifndef LIBFFI_ASM - -#include <stddef.h> -#include <limits.h> - -/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). - But we can find it either under the correct ANSI name, or under GNU - C's internal name. */ -#ifdef LONG_LONG_MAX -# define FFI_LONG_LONG_MAX LONG_LONG_MAX -#else -# ifdef LLONG_MAX -# define FFI_LONG_LONG_MAX LLONG_MAX -# else -# ifdef __GNUC__ -# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ -# endif -# ifdef _MSC_VER -# define FFI_LONG_LONG_MAX _I64_MAX -# endif -# endif -#endif - -#if SCHAR_MAX == 127 -# define ffi_type_uchar ffi_type_uint8 -# define ffi_type_schar ffi_type_sint8 -#else - #error "char size not supported" -#endif - -#if SHRT_MAX == 32767 -# define ffi_type_ushort ffi_type_uint16 -# define ffi_type_sshort ffi_type_sint16 -#elif SHRT_MAX == 2147483647 -# define ffi_type_ushort ffi_type_uint32 -# define ffi_type_sshort ffi_type_sint32 -#else - #error "short size not supported" -#endif - -#if INT_MAX == 32767 -# define ffi_type_uint ffi_type_uint16 -# define ffi_type_sint ffi_type_sint16 -#elif INT_MAX == 2147483647 -# define ffi_type_uint ffi_type_uint32 -# define ffi_type_sint ffi_type_sint32 -#elif INT_MAX == 9223372036854775807 -# define ffi_type_uint ffi_type_uint64 -# define ffi_type_sint ffi_type_sint64 -#else - #error "int size not supported" -#endif - -#define ffi_type_ulong ffi_type_uint64 -#define ffi_type_slong ffi_type_sint64 -#if LONG_MAX == 2147483647 -# if FFI_LONG_LONG_MAX != 9223372036854775807 - #error "no 64-bit data type supported" -# endif -#elif LONG_MAX != 9223372036854775807 - #error "long size not supported" -#endif - -/* The closure code assumes that this works on pointers, i.e. a size_t */ -/* can hold a pointer. */ - -typedef struct _ffi_type -{ - size_t size; - unsigned short alignment; - unsigned short type; - /*@null@*/ struct _ffi_type **elements; -} ffi_type; - -/* These are defined in types.c */ -extern ffi_type ffi_type_void; -extern ffi_type ffi_type_uint8; -extern ffi_type ffi_type_sint8; -extern ffi_type ffi_type_uint16; -extern ffi_type ffi_type_sint16; -extern ffi_type ffi_type_uint32; -extern ffi_type ffi_type_sint32; -extern ffi_type ffi_type_uint64; -extern ffi_type ffi_type_sint64; -extern ffi_type ffi_type_float; -extern ffi_type ffi_type_double; -extern ffi_type ffi_type_longdouble; -extern ffi_type ffi_type_pointer; - - -typedef enum { - FFI_OK = 0, - FFI_BAD_TYPEDEF, - FFI_BAD_ABI -} ffi_status; - -typedef unsigned FFI_TYPE; - -typedef struct { - ffi_abi abi; - unsigned nargs; - /*@dependent@*/ ffi_type **arg_types; - /*@dependent@*/ ffi_type *rtype; - unsigned bytes; - unsigned flags; -#ifdef FFI_EXTRA_CIF_FIELDS - FFI_EXTRA_CIF_FIELDS; -#endif -} ffi_cif; - -/* ---- Definitions for the raw API -------------------------------------- */ - -#ifdef _WIN64 -#define FFI_SIZEOF_ARG 8 -#else -#define FFI_SIZEOF_ARG 4 -#endif - -typedef union { - ffi_sarg sint; - ffi_arg uint; - float flt; - char data[FFI_SIZEOF_ARG]; - void* ptr; -} ffi_raw; - -void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ ffi_raw *avalue); - -void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); -void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); -size_t ffi_raw_size (ffi_cif *cif); - -/* This is analogous to the raw API, except it uses Java parameter */ -/* packing, even on 64-bit machines. I.e. on 64-bit machines */ -/* longs and doubles are followed by an empty 64-bit word. */ - -void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ ffi_raw *avalue); - -void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); -void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); -size_t ffi_java_raw_size (ffi_cif *cif); - -/* ---- Definitions for closures ----------------------------------------- */ - -#if FFI_CLOSURES - -typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - ffi_cif *cif; - void (*fun)(ffi_cif*,void*,void**,void*); - void *user_data; -} ffi_closure; - -void ffi_closure_free(void *); -void *ffi_closure_alloc (size_t size, void **code); - -ffi_status -ffi_prep_closure_loc (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc); - -/* AR: for cffi we need the following API, and not the _loc version */ -#define ffi_prep_closure(a,b,c,d) ffi_prep_closure_loc(a,b,c,d,a) - -typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - - ffi_cif *cif; - -#if !FFI_NATIVE_RAW_API - - /* if this is enabled, then a raw closure has the same layout - as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ - - void (*translate_args)(ffi_cif*,void*,void**,void*); - void *this_closure; - -#endif - - void (*fun)(ffi_cif*,void*,ffi_raw*,void*); - void *user_data; - -} ffi_raw_closure; - -ffi_status -ffi_prep_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - -ffi_status -ffi_prep_java_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - -#endif /* FFI_CLOSURES */ - -/* ---- Public interface definition -------------------------------------- */ - -ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, - ffi_abi abi, - unsigned int nargs, - /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, - /*@dependent@*/ ffi_type **atypes); - -int -ffi_call(/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ void **avalue); - -/* Useful for eliminating compiler warnings */ -#define FFI_FN(f) ((void (*)())f) - -/* ---- Definitions shared with assembly code ---------------------------- */ - -#endif - -/* If these change, update src/mips/ffitarget.h. */ -#define FFI_TYPE_VOID 0 -#define FFI_TYPE_INT 1 -#define FFI_TYPE_FLOAT 2 -#define FFI_TYPE_DOUBLE 3 -#if 1 -#define FFI_TYPE_LONGDOUBLE 4 -#else -#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE -#endif -#define FFI_TYPE_UINT8 5 -#define FFI_TYPE_SINT8 6 -#define FFI_TYPE_UINT16 7 -#define FFI_TYPE_SINT16 8 -#define FFI_TYPE_UINT32 9 -#define FFI_TYPE_SINT32 10 -#define FFI_TYPE_UINT64 11 -#define FFI_TYPE_SINT64 12 -#define FFI_TYPE_STRUCT 13 -#define FFI_TYPE_POINTER 14 - -/* This should always refer to the last type code (for sanity checks) */ -#define FFI_TYPE_LAST FFI_TYPE_POINTER - -#ifdef __cplusplus -} -#endif - -#endif - +/* -----------------------------------------------------------------*-C-*- + libffi 2.00-beta - Copyright (c) 1996-2003 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------- + The basic API is described in the README file. + + The raw API is designed to bypass some of the argument packing + and unpacking on architectures for which it can be avoided. + + The closure API allows interpreted functions to be packaged up + inside a C function pointer, so that they can be called as C functions, + with no understanding on the client side that they are interpreted. + It can also be used in other cases in which it is necessary to package + up a user specified parameter and a function pointer as a single + function pointer. + + The closure API must be implemented in order to get its functionality, + e.g. for use by gij. Routines are provided to emulate the raw API + if the underlying platform doesn't allow faster implementation. + + More details on the raw and cloure API can be found in: + + http://gcc.gnu.org/ml/java/1999-q3/msg00138.html + + and + + http://gcc.gnu.org/ml/java/1999-q3/msg00174.html + -------------------------------------------------------------------- */ + +#ifndef LIBFFI_H +#define LIBFFI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Specify which architecture libffi is configured for. */ +//XXX #define X86 + +/* ---- System configuration information --------------------------------- */ + +#include <ffitarget.h> + +#ifndef LIBFFI_ASM + +#include <stddef.h> +#include <limits.h> + +/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). + But we can find it either under the correct ANSI name, or under GNU + C's internal name. */ +#ifdef LONG_LONG_MAX +# define FFI_LONG_LONG_MAX LONG_LONG_MAX +#else +# ifdef LLONG_MAX +# define FFI_LONG_LONG_MAX LLONG_MAX +# else +# ifdef __GNUC__ +# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ +# endif +# ifdef _MSC_VER +# define FFI_LONG_LONG_MAX _I64_MAX +# endif +# endif +#endif + +#if SCHAR_MAX == 127 +# define ffi_type_uchar ffi_type_uint8 +# define ffi_type_schar ffi_type_sint8 +#else + #error "char size not supported" +#endif + +#if SHRT_MAX == 32767 +# define ffi_type_ushort ffi_type_uint16 +# define ffi_type_sshort ffi_type_sint16 +#elif SHRT_MAX == 2147483647 +# define ffi_type_ushort ffi_type_uint32 +# define ffi_type_sshort ffi_type_sint32 +#else + #error "short size not supported" +#endif + +#if INT_MAX == 32767 +# define ffi_type_uint ffi_type_uint16 +# define ffi_type_sint ffi_type_sint16 +#elif INT_MAX == 2147483647 +# define ffi_type_uint ffi_type_uint32 +# define ffi_type_sint ffi_type_sint32 +#elif INT_MAX == 9223372036854775807 +# define ffi_type_uint ffi_type_uint64 +# define ffi_type_sint ffi_type_sint64 +#else + #error "int size not supported" +#endif + +#define ffi_type_ulong ffi_type_uint64 +#define ffi_type_slong ffi_type_sint64 +#if LONG_MAX == 2147483647 +# if FFI_LONG_LONG_MAX != 9223372036854775807 + #error "no 64-bit data type supported" +# endif +#elif LONG_MAX != 9223372036854775807 + #error "long size not supported" +#endif + +/* The closure code assumes that this works on pointers, i.e. a size_t */ +/* can hold a pointer. */ + +typedef struct _ffi_type +{ + size_t size; + unsigned short alignment; + unsigned short type; + /*@null@*/ struct _ffi_type **elements; +} ffi_type; + +/* These are defined in types.c */ +extern ffi_type ffi_type_void; +extern ffi_type ffi_type_uint8; +extern ffi_type ffi_type_sint8; +extern ffi_type ffi_type_uint16; +extern ffi_type ffi_type_sint16; +extern ffi_type ffi_type_uint32; +extern ffi_type ffi_type_sint32; +extern ffi_type ffi_type_uint64; +extern ffi_type ffi_type_sint64; +extern ffi_type ffi_type_float; +extern ffi_type ffi_type_double; +extern ffi_type ffi_type_longdouble; +extern ffi_type ffi_type_pointer; + + +typedef enum { + FFI_OK = 0, + FFI_BAD_TYPEDEF, + FFI_BAD_ABI +} ffi_status; + +typedef unsigned FFI_TYPE; + +typedef struct { + ffi_abi abi; + unsigned nargs; + /*@dependent@*/ ffi_type **arg_types; + /*@dependent@*/ ffi_type *rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; + +/* ---- Definitions for the raw API -------------------------------------- */ + +#ifdef _WIN64 +#define FFI_SIZEOF_ARG 8 +#else +#define FFI_SIZEOF_ARG 4 +#endif + +typedef union { + ffi_sarg sint; + ffi_arg uint; + float flt; + char data[FFI_SIZEOF_ARG]; + void* ptr; +} ffi_raw; + +void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *avalue); + +void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_raw_size (ffi_cif *cif); + +/* This is analogous to the raw API, except it uses Java parameter */ +/* packing, even on 64-bit machines. I.e. on 64-bit machines */ +/* longs and doubles are followed by an empty 64-bit word. */ + +void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *avalue); + +void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_java_raw_size (ffi_cif *cif); + +/* ---- Definitions for closures ----------------------------------------- */ + +#if FFI_CLOSURES + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + ffi_cif *cif; + void (*fun)(ffi_cif*,void*,void**,void*); + void *user_data; +} ffi_closure; + +void ffi_closure_free(void *); +void *ffi_closure_alloc (size_t size, void **code); + +ffi_status +ffi_prep_closure_loc (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc); + +/* AR: for cffi we need the following API, and not the _loc version */ +#define ffi_prep_closure(a,b,c,d) ffi_prep_closure_loc(a,b,c,d,a) + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + + ffi_cif *cif; + +#if !FFI_NATIVE_RAW_API + + /* if this is enabled, then a raw closure has the same layout + as a regular closure. We use this to install an intermediate + handler to do the transaltion, void** -> ffi_raw*. */ + + void (*translate_args)(ffi_cif*,void*,void**,void*); + void *this_closure; + +#endif + + void (*fun)(ffi_cif*,void*,ffi_raw*,void*); + void *user_data; + +} ffi_raw_closure; + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +ffi_status +ffi_prep_java_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +#endif /* FFI_CLOSURES */ + +/* ---- Public interface definition -------------------------------------- */ + +ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, + ffi_abi abi, + unsigned int nargs, + /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, + /*@dependent@*/ ffi_type **atypes); + +int +ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue); + +/* Useful for eliminating compiler warnings */ +#define FFI_FN(f) ((void (*)())f) + +/* ---- Definitions shared with assembly code ---------------------------- */ + +#endif + +/* If these change, update src/mips/ffitarget.h. */ +#define FFI_TYPE_VOID 0 +#define FFI_TYPE_INT 1 +#define FFI_TYPE_FLOAT 2 +#define FFI_TYPE_DOUBLE 3 +#if 1 +#define FFI_TYPE_LONGDOUBLE 4 +#else +#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE +#endif +#define FFI_TYPE_UINT8 5 +#define FFI_TYPE_SINT8 6 +#define FFI_TYPE_UINT16 7 +#define FFI_TYPE_SINT16 8 +#define FFI_TYPE_UINT32 9 +#define FFI_TYPE_SINT32 10 +#define FFI_TYPE_UINT64 11 +#define FFI_TYPE_SINT64 12 +#define FFI_TYPE_STRUCT 13 +#define FFI_TYPE_POINTER 14 + +/* This should always refer to the last type code (for sanity checks) */ +#define FFI_TYPE_LAST FFI_TYPE_POINTER + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/contrib/python/cffi/c/libffi_msvc/ffi_common.h b/contrib/python/cffi/c/libffi_msvc/ffi_common.h index 43fb83b481..5690e3e007 100644 --- a/contrib/python/cffi/c/libffi_msvc/ffi_common.h +++ b/contrib/python/cffi/c/libffi_msvc/ffi_common.h @@ -1,77 +1,77 @@ -/* ----------------------------------------------------------------------- - ffi_common.h - Copyright (c) 1996 Red Hat, Inc. - - Common internal definitions and macros. Only necessary for building - libffi. - ----------------------------------------------------------------------- */ - -#ifndef FFI_COMMON_H -#define FFI_COMMON_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <fficonfig.h> -#include <malloc.h> - -/* Check for the existence of memcpy. */ -#if STDC_HEADERS -# include <string.h> -#else -# ifndef HAVE_MEMCPY -# define memcpy(d, s, n) bcopy ((s), (d), (n)) -# endif -#endif - -#if defined(FFI_DEBUG) -#include <stdio.h> -#endif - -#ifdef FFI_DEBUG -/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); -void ffi_stop_here(void); -void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); - -#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) -#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) -#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) -#else -#define FFI_ASSERT(x) -#define FFI_ASSERT_AT(x, f, l) -#define FFI_ASSERT_VALID_TYPE(x) -#endif - -#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif); - -/* Extended cif, used in callback from assembly routine */ -typedef struct -{ - /*@dependent@*/ ffi_cif *cif; - /*@dependent@*/ void *rvalue; - /*@dependent@*/ void **avalue; -} extended_cif; - -/* Terse sized type definitions. */ -typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); -typedef signed int SINT8 __attribute__((__mode__(__QI__))); -typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); -typedef signed int SINT16 __attribute__((__mode__(__HI__))); -typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); -typedef signed int SINT32 __attribute__((__mode__(__SI__))); -typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); -typedef signed int SINT64 __attribute__((__mode__(__DI__))); - -typedef float FLOAT32; - - -#ifdef __cplusplus -} -#endif - -#endif - - +/* ----------------------------------------------------------------------- + ffi_common.h - Copyright (c) 1996 Red Hat, Inc. + + Common internal definitions and macros. Only necessary for building + libffi. + ----------------------------------------------------------------------- */ + +#ifndef FFI_COMMON_H +#define FFI_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <fficonfig.h> +#include <malloc.h> + +/* Check for the existence of memcpy. */ +#if STDC_HEADERS +# include <string.h> +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#if defined(FFI_DEBUG) +#include <stdio.h> +#endif + +#ifdef FFI_DEBUG +/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); +void ffi_stop_here(void); +void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); + +#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) +#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) +#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) +#else +#define FFI_ASSERT(x) +#define FFI_ASSERT_AT(x, f, l) +#define FFI_ASSERT_VALID_TYPE(x) +#endif + +#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif); + +/* Extended cif, used in callback from assembly routine */ +typedef struct +{ + /*@dependent@*/ ffi_cif *cif; + /*@dependent@*/ void *rvalue; + /*@dependent@*/ void **avalue; +} extended_cif; + +/* Terse sized type definitions. */ +typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); +typedef signed int SINT8 __attribute__((__mode__(__QI__))); +typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); +typedef signed int SINT16 __attribute__((__mode__(__HI__))); +typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); +typedef signed int SINT32 __attribute__((__mode__(__SI__))); +typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); +typedef signed int SINT64 __attribute__((__mode__(__DI__))); + +typedef float FLOAT32; + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/contrib/python/cffi/c/libffi_msvc/fficonfig.h b/contrib/python/cffi/c/libffi_msvc/fficonfig.h index c14f653ec8..c0cbe6929a 100644 --- a/contrib/python/cffi/c/libffi_msvc/fficonfig.h +++ b/contrib/python/cffi/c/libffi_msvc/fficonfig.h @@ -1,96 +1,96 @@ -/* fficonfig.h. Originally created by configure, now hand_maintained for MSVC. */ - -/* fficonfig.h. Generated automatically by configure. */ -/* fficonfig.h.in. Generated automatically from configure.in by autoheader. */ - -/* Define this for MSVC, but not for mingw32! */ -#ifdef _MSC_VER -#define __attribute__(x) /* */ -#endif -#define alloca _alloca - -/*----------------------------------------------------------------*/ - -/* Define if using alloca.c. */ -/* #undef C_ALLOCA */ - -/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. - This function is required for alloca.c support on those systems. */ -/* #undef CRAY_STACKSEG_END */ - -/* Define if you have alloca, as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ -/* #define HAVE_ALLOCA_H 1 */ - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown - */ -/* #undef STACK_DIRECTION */ - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you have the memcpy function. */ -#define HAVE_MEMCPY 1 - -/* Define if read-only mmap of a plain file works. */ -//#define HAVE_MMAP_FILE 1 - -/* Define if mmap of /dev/zero works. */ -//#define HAVE_MMAP_DEV_ZERO 1 - -/* Define if mmap with MAP_ANON(YMOUS) works. */ -//#define HAVE_MMAP_ANON 1 - -/* The number of bytes in type double */ -#define SIZEOF_DOUBLE 8 - -/* The number of bytes in type long double */ -#define SIZEOF_LONG_DOUBLE 12 - -/* Define if you have the long double type and it is bigger than a double */ -#define HAVE_LONG_DOUBLE 1 - -/* whether byteorder is bigendian */ -/* #undef WORDS_BIGENDIAN */ - -/* Define if the host machine stores words of multi-word integers in - big-endian order. */ -/* #undef HOST_WORDS_BIG_ENDIAN */ - -/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ -#define BYTEORDER 1234 - -/* Define if your assembler and linker support unaligned PC relative relocs. */ -/* #undef HAVE_AS_SPARC_UA_PCREL */ - -/* Define if your assembler supports .register. */ -/* #undef HAVE_AS_REGISTER_PSEUDO_OP */ - -/* Define if .eh_frame sections should be read-only. */ -/* #undef HAVE_RO_EH_FRAME */ - -/* Define to the flags needed for the .section .eh_frame directive. */ -/* #define EH_FRAME_FLAGS "aw" */ - -/* Define to the flags needed for the .section .eh_frame directive. */ -/* #define EH_FRAME_FLAGS "aw" */ - -/* Define this if you want extra debugging. */ -/* #undef FFI_DEBUG */ - -/* Define this is you do not want support for aggregate types. */ -/* #undef FFI_NO_STRUCTS */ - -/* Define this is you do not want support for the raw API. */ -/* #undef FFI_NO_RAW_API */ - -/* Define this if you are using Purify and want to suppress spurious messages. */ -/* #undef USING_PURIFY */ - +/* fficonfig.h. Originally created by configure, now hand_maintained for MSVC. */ + +/* fficonfig.h. Generated automatically by configure. */ +/* fficonfig.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define this for MSVC, but not for mingw32! */ +#ifdef _MSC_VER +#define __attribute__(x) /* */ +#endif +#define alloca _alloca + +/*----------------------------------------------------------------*/ + +/* Define if using alloca.c. */ +/* #undef C_ALLOCA */ + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +/* #undef CRAY_STACKSEG_END */ + +/* Define if you have alloca, as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ +/* #define HAVE_ALLOCA_H 1 */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +/* #undef STACK_DIRECTION */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you have the memcpy function. */ +#define HAVE_MEMCPY 1 + +/* Define if read-only mmap of a plain file works. */ +//#define HAVE_MMAP_FILE 1 + +/* Define if mmap of /dev/zero works. */ +//#define HAVE_MMAP_DEV_ZERO 1 + +/* Define if mmap with MAP_ANON(YMOUS) works. */ +//#define HAVE_MMAP_ANON 1 + +/* The number of bytes in type double */ +#define SIZEOF_DOUBLE 8 + +/* The number of bytes in type long double */ +#define SIZEOF_LONG_DOUBLE 12 + +/* Define if you have the long double type and it is bigger than a double */ +#define HAVE_LONG_DOUBLE 1 + +/* whether byteorder is bigendian */ +/* #undef WORDS_BIGENDIAN */ + +/* Define if the host machine stores words of multi-word integers in + big-endian order. */ +/* #undef HOST_WORDS_BIG_ENDIAN */ + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 1234 + +/* Define if your assembler and linker support unaligned PC relative relocs. */ +/* #undef HAVE_AS_SPARC_UA_PCREL */ + +/* Define if your assembler supports .register. */ +/* #undef HAVE_AS_REGISTER_PSEUDO_OP */ + +/* Define if .eh_frame sections should be read-only. */ +/* #undef HAVE_RO_EH_FRAME */ + +/* Define to the flags needed for the .section .eh_frame directive. */ +/* #define EH_FRAME_FLAGS "aw" */ + +/* Define to the flags needed for the .section .eh_frame directive. */ +/* #define EH_FRAME_FLAGS "aw" */ + +/* Define this if you want extra debugging. */ +/* #undef FFI_DEBUG */ + +/* Define this is you do not want support for aggregate types. */ +/* #undef FFI_NO_STRUCTS */ + +/* Define this is you do not want support for the raw API. */ +/* #undef FFI_NO_RAW_API */ + +/* Define this if you are using Purify and want to suppress spurious messages. */ +/* #undef USING_PURIFY */ + diff --git a/contrib/python/cffi/c/libffi_msvc/ffitarget.h b/contrib/python/cffi/c/libffi_msvc/ffitarget.h index 85f5ee81bb..ac3ea1458e 100644 --- a/contrib/python/cffi/c/libffi_msvc/ffitarget.h +++ b/contrib/python/cffi/c/libffi_msvc/ffitarget.h @@ -1,85 +1,85 @@ -/* -----------------------------------------------------------------*-C-*- - ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. - Target configuration macros for x86 and x86-64. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - ----------------------------------------------------------------------- */ - -#ifndef LIBFFI_TARGET_H -#define LIBFFI_TARGET_H - -/* ---- System specific configurations ----------------------------------- */ - -#if defined (X86_64) && defined (__i386__) -#undef X86_64 -#define X86 -#endif - -/* ---- Generic type definitions ----------------------------------------- */ - -#ifndef LIBFFI_ASM -#ifndef _WIN64 -typedef unsigned long ffi_arg; -#else -typedef unsigned __int64 ffi_arg; -#endif -typedef signed long ffi_sarg; - -typedef enum ffi_abi { - FFI_FIRST_ABI = 0, - - /* ---- Intel x86 Win32 ---------- */ - FFI_SYSV, -#ifndef _WIN64 - FFI_STDCALL, -#endif - /* TODO: Add fastcall support for the sake of completeness */ - FFI_DEFAULT_ABI = FFI_SYSV, - - /* ---- Intel x86 and AMD x86-64 - */ -/* #if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__)) */ -/* FFI_SYSV, */ -/* FFI_UNIX64,*/ /* Unix variants all use the same ABI for x86-64 */ -/* #ifdef __i386__ */ -/* FFI_DEFAULT_ABI = FFI_SYSV, */ -/* #else */ -/* FFI_DEFAULT_ABI = FFI_UNIX64, */ -/* #endif */ -/* #endif */ - - FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 -} ffi_abi; -#endif - -/* ---- Definitions for closures ----------------------------------------- */ - -#define FFI_CLOSURES 1 - -#ifdef _WIN64 -#define FFI_TRAMPOLINE_SIZE 29 -#define FFI_NATIVE_RAW_API 0 -#else -#define FFI_TRAMPOLINE_SIZE 15 -#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ -#endif - -#endif - +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for x86 and x86-64. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#if defined (X86_64) && defined (__i386__) +#undef X86_64 +#define X86 +#endif + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +#ifndef _WIN64 +typedef unsigned long ffi_arg; +#else +typedef unsigned __int64 ffi_arg; +#endif +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + + /* ---- Intel x86 Win32 ---------- */ + FFI_SYSV, +#ifndef _WIN64 + FFI_STDCALL, +#endif + /* TODO: Add fastcall support for the sake of completeness */ + FFI_DEFAULT_ABI = FFI_SYSV, + + /* ---- Intel x86 and AMD x86-64 - */ +/* #if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__)) */ +/* FFI_SYSV, */ +/* FFI_UNIX64,*/ /* Unix variants all use the same ABI for x86-64 */ +/* #ifdef __i386__ */ +/* FFI_DEFAULT_ABI = FFI_SYSV, */ +/* #else */ +/* FFI_DEFAULT_ABI = FFI_UNIX64, */ +/* #endif */ +/* #endif */ + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 + +#ifdef _WIN64 +#define FFI_TRAMPOLINE_SIZE 29 +#define FFI_NATIVE_RAW_API 0 +#else +#define FFI_TRAMPOLINE_SIZE 15 +#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ +#endif + +#endif + diff --git a/contrib/python/cffi/c/libffi_msvc/prep_cif.c b/contrib/python/cffi/c/libffi_msvc/prep_cif.c index df94a98875..73ef2b8bd2 100644 --- a/contrib/python/cffi/c/libffi_msvc/prep_cif.c +++ b/contrib/python/cffi/c/libffi_msvc/prep_cif.c @@ -1,184 +1,184 @@ -/* ----------------------------------------------------------------------- - prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#include <ffi.h> -#include <ffi_common.h> -#include <stdlib.h> - - -/* Round up to FFI_SIZEOF_ARG. */ - -#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) - -/* Perform machine independent initialization of aggregate type - specifications. */ - -static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) -{ +/* ----------------------------------------------------------------------- + prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> + + +/* Round up to FFI_SIZEOF_ARG. */ + +#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) + +/* Perform machine independent initialization of aggregate type + specifications. */ + +static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) +{ + ffi_type **ptr; + + FFI_ASSERT(arg != NULL); + + /*@-usedef@*/ + + FFI_ASSERT(arg->elements != NULL); + FFI_ASSERT(arg->size == 0); + FFI_ASSERT(arg->alignment == 0); + + ptr = &(arg->elements[0]); + + while ((*ptr) != NULL) + { + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type */ + FFI_ASSERT_VALID_TYPE(*ptr); + + arg->size = ALIGN(arg->size, (*ptr)->alignment); + arg->size += (*ptr)->size; + + arg->alignment = (arg->alignment > (*ptr)->alignment) ? + arg->alignment : (*ptr)->alignment; + + ptr++; + } + + /* Structure size includes tail padding. This is important for + structures that fit in one register on ABIs like the PowerPC64 + Linux ABI that right justify small structs in a register. + It's also needed for nested structure layout, for example + struct A { long a; char b; }; struct B { struct A x; char y; }; + should find y at an offset of 2*sizeof(long) and result in a + total size of 3*sizeof(long). */ + arg->size = ALIGN (arg->size, arg->alignment); + + if (arg->size == 0) + return FFI_BAD_TYPEDEF; + else + return FFI_OK; + + /*@=usedef@*/ +} + +/* Perform machine independent ffi_cif preparation, then call + machine dependent routine. */ + +ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, + ffi_abi abi, unsigned int nargs, + /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, + /*@dependent@*/ ffi_type **atypes) +{ + unsigned bytes = 0; + unsigned int i; ffi_type **ptr; - - FFI_ASSERT(arg != NULL); - - /*@-usedef@*/ - - FFI_ASSERT(arg->elements != NULL); - FFI_ASSERT(arg->size == 0); - FFI_ASSERT(arg->alignment == 0); - - ptr = &(arg->elements[0]); - - while ((*ptr) != NULL) - { - if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the argument type */ - FFI_ASSERT_VALID_TYPE(*ptr); - - arg->size = ALIGN(arg->size, (*ptr)->alignment); - arg->size += (*ptr)->size; - - arg->alignment = (arg->alignment > (*ptr)->alignment) ? - arg->alignment : (*ptr)->alignment; - - ptr++; - } - - /* Structure size includes tail padding. This is important for - structures that fit in one register on ABIs like the PowerPC64 - Linux ABI that right justify small structs in a register. - It's also needed for nested structure layout, for example - struct A { long a; char b; }; struct B { struct A x; char y; }; - should find y at an offset of 2*sizeof(long) and result in a - total size of 3*sizeof(long). */ - arg->size = ALIGN (arg->size, arg->alignment); - - if (arg->size == 0) - return FFI_BAD_TYPEDEF; - else - return FFI_OK; - - /*@=usedef@*/ -} - -/* Perform machine independent ffi_cif preparation, then call - machine dependent routine. */ - -ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, - ffi_abi abi, unsigned int nargs, - /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, - /*@dependent@*/ ffi_type **atypes) -{ - unsigned bytes = 0; - unsigned int i; - ffi_type **ptr; - - FFI_ASSERT(cif != NULL); - FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); - - cif->abi = abi; - cif->arg_types = atypes; - cif->nargs = nargs; - cif->rtype = rtype; - - cif->flags = 0; - - /* Initialize the return type if necessary */ - /*@-usedef@*/ - if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) - return FFI_BAD_TYPEDEF; - /*@=usedef@*/ - - /* Perform a sanity check on the return type */ - FFI_ASSERT_VALID_TYPE(cif->rtype); - - /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ -#if !defined M68K && !defined __x86_64__ && !defined S390 - /* Make space for the return structure pointer */ - if (cif->rtype->type == FFI_TYPE_STRUCT -#ifdef _WIN32 + + FFI_ASSERT(cif != NULL); + FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); + + cif->abi = abi; + cif->arg_types = atypes; + cif->nargs = nargs; + cif->rtype = rtype; + + cif->flags = 0; + + /* Initialize the return type if necessary */ + /*@-usedef@*/ + if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) + return FFI_BAD_TYPEDEF; + /*@=usedef@*/ + + /* Perform a sanity check on the return type */ + FFI_ASSERT_VALID_TYPE(cif->rtype); + + /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ +#if !defined M68K && !defined __x86_64__ && !defined S390 + /* Make space for the return structure pointer */ + if (cif->rtype->type == FFI_TYPE_STRUCT +#ifdef _WIN32 && (cif->rtype->size != 1) /* MSVC returns small structs in registers */ && (cif->rtype->size != 2) && (cif->rtype->size != 4) && (cif->rtype->size != 8) -#endif -#ifdef SPARC - && (cif->abi != FFI_V9 || cif->rtype->size > 32) -#endif - ) - bytes = STACK_ARG_SIZE(sizeof(void*)); -#endif - - for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) - { - - /* Initialize any uninitialized aggregate type definitions */ - if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the argument type, do this - check after the initialization. */ - FFI_ASSERT_VALID_TYPE(*ptr); - -#if !defined __x86_64__ && !defined S390 -#ifdef SPARC - if (((*ptr)->type == FFI_TYPE_STRUCT - && ((*ptr)->size > 16 || cif->abi != FFI_V9)) - || ((*ptr)->type == FFI_TYPE_LONGDOUBLE - && cif->abi != FFI_V9)) - bytes += sizeof(void*); - else -#endif - { -#if !defined(_MSC_VER) && !defined(__MINGW32__) - /* Don't know if this is a libffi bug or not. At least on - Windows with MSVC, function call parameters are *not* - aligned in the same way as structure fields are, they are - only aligned in integer boundaries. - - This doesn't do any harm for cdecl functions and closures, - since the caller cleans up the stack, but it is wrong for - stdcall functions where the callee cleans. - */ - - /* Add any padding if necessary */ - if (((*ptr)->alignment - 1) & bytes) - bytes = ALIGN(bytes, (*ptr)->alignment); - -#endif - bytes += STACK_ARG_SIZE((*ptr)->size); - } -#endif - } - -#ifdef _WIN64 - /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ - if (bytes < 40) - bytes = 40; -#endif - - cif->bytes = bytes; - - /* Perform machine dependent cif processing */ - return ffi_prep_cif_machdep(cif); -} +#endif +#ifdef SPARC + && (cif->abi != FFI_V9 || cif->rtype->size > 32) +#endif + ) + bytes = STACK_ARG_SIZE(sizeof(void*)); +#endif + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + + /* Initialize any uninitialized aggregate type definitions */ + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type, do this + check after the initialization. */ + FFI_ASSERT_VALID_TYPE(*ptr); + +#if !defined __x86_64__ && !defined S390 +#ifdef SPARC + if (((*ptr)->type == FFI_TYPE_STRUCT + && ((*ptr)->size > 16 || cif->abi != FFI_V9)) + || ((*ptr)->type == FFI_TYPE_LONGDOUBLE + && cif->abi != FFI_V9)) + bytes += sizeof(void*); + else +#endif + { +#if !defined(_MSC_VER) && !defined(__MINGW32__) + /* Don't know if this is a libffi bug or not. At least on + Windows with MSVC, function call parameters are *not* + aligned in the same way as structure fields are, they are + only aligned in integer boundaries. + + This doesn't do any harm for cdecl functions and closures, + since the caller cleans up the stack, but it is wrong for + stdcall functions where the callee cleans. + */ + + /* Add any padding if necessary */ + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN(bytes, (*ptr)->alignment); + +#endif + bytes += STACK_ARG_SIZE((*ptr)->size); + } +#endif + } + +#ifdef _WIN64 + /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ + if (bytes < 40) + bytes = 40; +#endif + + cif->bytes = bytes; + + /* Perform machine dependent cif processing */ + return ffi_prep_cif_machdep(cif); +} diff --git a/contrib/python/cffi/c/libffi_msvc/types.c b/contrib/python/cffi/c/libffi_msvc/types.c index 4433ac28c8..5ac550e2b4 100644 --- a/contrib/python/cffi/c/libffi_msvc/types.c +++ b/contrib/python/cffi/c/libffi_msvc/types.c @@ -1,104 +1,104 @@ -/* ----------------------------------------------------------------------- - types.c - Copyright (c) 1996, 1998 Red Hat, Inc. - - Predefined ffi_types needed by libffi. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#include <ffi.h> -#include <ffi_common.h> - -/* Type definitions */ - -#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL } -#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e } - -/* Size and alignment are fake here. They must not be 0. */ -FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID); - -FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8); -FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8); -FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16); -FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16); -FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); -FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); -FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); - -#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ - || defined IA64 || defined _WIN64 - -FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); - -#else - -FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); - -#endif - -#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#elif defined SH - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#else - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); - -#endif - - -#if defined X86 || defined X86_WIN32 || defined M68K - -FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); - -#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN - -FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); - -#elif defined SPARC - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -#ifdef SPARC64 -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); -#else -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); -#endif - -#elif defined X86_64 - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); - -#else - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE); - -#endif - +/* ----------------------------------------------------------------------- + types.c - Copyright (c) 1996, 1998 Red Hat, Inc. + + Predefined ffi_types needed by libffi. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +/* Type definitions */ + +#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL } +#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e } + +/* Size and alignment are fake here. They must not be 0. */ +FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID); + +FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8); +FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8); +FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16); +FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16); +FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); +FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); +FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); + +#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ + || defined IA64 || defined _WIN64 + +FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); + +#else + +FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); + +#endif + +#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K + +FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); + +#elif defined SH + +FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); + +#else + +FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); + +#endif + + +#if defined X86 || defined X86_WIN32 || defined M68K + +FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); + +#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN + +FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); + +#elif defined SPARC + +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +#ifdef SPARC64 +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); +#else +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); +#endif + +#elif defined X86_64 + +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); + +#else + +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE); + +#endif + diff --git a/contrib/python/cffi/c/libffi_msvc/win32.c b/contrib/python/cffi/c/libffi_msvc/win32.c index d1149a85eb..dacbbf6301 100644 --- a/contrib/python/cffi/c/libffi_msvc/win32.c +++ b/contrib/python/cffi/c/libffi_msvc/win32.c @@ -1,162 +1,162 @@ -/* ----------------------------------------------------------------------- - win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. - Copyright (c) 2001 John Beniton - Copyright (c) 2002 Ranjit Mathew - - - X86 Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -/* theller: almost verbatim translation from gas syntax to MSVC inline - assembler code. */ - -/* theller: ffi_call_x86 now returns an integer - the difference of the stack - pointer before and after the function call. If everything is ok, zero is - returned. If stdcall functions are passed the wrong number of arguments, - the difference will be nonzero. */ - -#include <ffi.h> -#include <ffi_common.h> - -__declspec(naked) int -ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */ - extended_cif *ecif, /* 12 */ - unsigned bytes, /* 16 */ - unsigned flags, /* 20 */ - unsigned *rvalue, /* 24 */ - void (*fn)()) /* 28 */ -{ - _asm { - push ebp - mov ebp, esp - - push esi // NEW: this register must be preserved across function calls -// XXX SAVE ESP NOW! - mov esi, esp // save stack pointer before the call - -// Make room for all of the new args. - mov ecx, [ebp+16] - sub esp, ecx // sub esp, bytes - - mov eax, esp - -// Place all of the ffi_prep_args in position - push [ebp + 12] // ecif - push eax - call [ebp + 8] // prepfunc - -// Return stack to previous state and call the function - add esp, 8 -// FIXME: Align the stack to a 128-bit boundary to avoid -// potential performance hits. - call [ebp + 28] - -// Load ecif->cif->abi - mov ecx, [ebp + 12] - mov ecx, [ecx]ecif.cif - mov ecx, [ecx]ecif.cif.abi - - cmp ecx, FFI_STDCALL - je noclean -// STDCALL: Remove the space we pushed for the args - mov ecx, [ebp + 16] - add esp, ecx -// CDECL: Caller has already cleaned the stack -noclean: -// Check that esp has the same value as before! - sub esi, esp - -// Load %ecx with the return type code - mov ecx, [ebp + 20] - -// If the return value pointer is NULL, assume no return value. -/* - Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, - otherwise only one BYTE will be compared (instead of a DWORD)! - */ - cmp DWORD PTR [ebp + 24], 0 - jne sc_retint - -// Even if there is no space for the return value, we are -// obliged to handle floating-point values. - cmp ecx, FFI_TYPE_FLOAT - jne sc_noretval -// fstp %st(0) - fstp st(0) - - jmp sc_epilogue - -sc_retint: - cmp ecx, FFI_TYPE_INT - jne sc_retfloat -// # Load %ecx with the pointer to storage for the return value - mov ecx, [ebp + 24] - mov [ecx + 0], eax - jmp sc_epilogue - -sc_retfloat: - cmp ecx, FFI_TYPE_FLOAT - jne sc_retdouble -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] -// fstps (%ecx) - fstp DWORD PTR [ecx] - jmp sc_epilogue - -sc_retdouble: - cmp ecx, FFI_TYPE_DOUBLE - jne sc_retlongdouble -// movl 24(%ebp),%ecx - mov ecx, [ebp+24] - fstp QWORD PTR [ecx] - jmp sc_epilogue - - jmp sc_retlongdouble // avoid warning about unused label -sc_retlongdouble: - cmp ecx, FFI_TYPE_LONGDOUBLE - jne sc_retint64 -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] -// fstpt (%ecx) - fstp QWORD PTR [ecx] /* XXX ??? */ - jmp sc_epilogue - -sc_retint64: - cmp ecx, FFI_TYPE_SINT64 - jne sc_retstruct -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] - mov [ecx+0], eax - mov [ecx+4], edx - -sc_retstruct: -// Nothing to do! - -sc_noretval: -sc_epilogue: - mov eax, esi - pop esi // NEW restore: must be preserved across function calls - mov esp, ebp - pop ebp - ret - } -} +/* ----------------------------------------------------------------------- + win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. + Copyright (c) 2001 John Beniton + Copyright (c) 2002 Ranjit Mathew + + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +/* theller: almost verbatim translation from gas syntax to MSVC inline + assembler code. */ + +/* theller: ffi_call_x86 now returns an integer - the difference of the stack + pointer before and after the function call. If everything is ok, zero is + returned. If stdcall functions are passed the wrong number of arguments, + the difference will be nonzero. */ + +#include <ffi.h> +#include <ffi_common.h> + +__declspec(naked) int +ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */ + extended_cif *ecif, /* 12 */ + unsigned bytes, /* 16 */ + unsigned flags, /* 20 */ + unsigned *rvalue, /* 24 */ + void (*fn)()) /* 28 */ +{ + _asm { + push ebp + mov ebp, esp + + push esi // NEW: this register must be preserved across function calls +// XXX SAVE ESP NOW! + mov esi, esp // save stack pointer before the call + +// Make room for all of the new args. + mov ecx, [ebp+16] + sub esp, ecx // sub esp, bytes + + mov eax, esp + +// Place all of the ffi_prep_args in position + push [ebp + 12] // ecif + push eax + call [ebp + 8] // prepfunc + +// Return stack to previous state and call the function + add esp, 8 +// FIXME: Align the stack to a 128-bit boundary to avoid +// potential performance hits. + call [ebp + 28] + +// Load ecif->cif->abi + mov ecx, [ebp + 12] + mov ecx, [ecx]ecif.cif + mov ecx, [ecx]ecif.cif.abi + + cmp ecx, FFI_STDCALL + je noclean +// STDCALL: Remove the space we pushed for the args + mov ecx, [ebp + 16] + add esp, ecx +// CDECL: Caller has already cleaned the stack +noclean: +// Check that esp has the same value as before! + sub esi, esp + +// Load %ecx with the return type code + mov ecx, [ebp + 20] + +// If the return value pointer is NULL, assume no return value. +/* + Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, + otherwise only one BYTE will be compared (instead of a DWORD)! + */ + cmp DWORD PTR [ebp + 24], 0 + jne sc_retint + +// Even if there is no space for the return value, we are +// obliged to handle floating-point values. + cmp ecx, FFI_TYPE_FLOAT + jne sc_noretval +// fstp %st(0) + fstp st(0) + + jmp sc_epilogue + +sc_retint: + cmp ecx, FFI_TYPE_INT + jne sc_retfloat +// # Load %ecx with the pointer to storage for the return value + mov ecx, [ebp + 24] + mov [ecx + 0], eax + jmp sc_epilogue + +sc_retfloat: + cmp ecx, FFI_TYPE_FLOAT + jne sc_retdouble +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] +// fstps (%ecx) + fstp DWORD PTR [ecx] + jmp sc_epilogue + +sc_retdouble: + cmp ecx, FFI_TYPE_DOUBLE + jne sc_retlongdouble +// movl 24(%ebp),%ecx + mov ecx, [ebp+24] + fstp QWORD PTR [ecx] + jmp sc_epilogue + + jmp sc_retlongdouble // avoid warning about unused label +sc_retlongdouble: + cmp ecx, FFI_TYPE_LONGDOUBLE + jne sc_retint64 +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] +// fstpt (%ecx) + fstp QWORD PTR [ecx] /* XXX ??? */ + jmp sc_epilogue + +sc_retint64: + cmp ecx, FFI_TYPE_SINT64 + jne sc_retstruct +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] + mov [ecx+0], eax + mov [ecx+4], edx + +sc_retstruct: +// Nothing to do! + +sc_noretval: +sc_epilogue: + mov eax, esi + pop esi // NEW restore: must be preserved across function calls + mov esp, ebp + pop ebp + ret + } +} diff --git a/contrib/python/cffi/c/libffi_msvc/win64.asm b/contrib/python/cffi/c/libffi_msvc/win64.asm index 301188bc9c..67e6cb8901 100644 --- a/contrib/python/cffi/c/libffi_msvc/win64.asm +++ b/contrib/python/cffi/c/libffi_msvc/win64.asm @@ -1,156 +1,156 @@ -PUBLIC ffi_call_AMD64 - -EXTRN __chkstk:NEAR -EXTRN ffi_closure_SYSV:NEAR - -_TEXT SEGMENT - -;;; ffi_closure_OUTER will be called with these registers set: -;;; rax points to 'closure' -;;; r11 contains a bit mask that specifies which of the -;;; first four parameters are float or double -;;; -;;; It must move the parameters passed in registers to their stack location, -;;; call ffi_closure_SYSV for the actual work, then return the result. +PUBLIC ffi_call_AMD64 + +EXTRN __chkstk:NEAR +EXTRN ffi_closure_SYSV:NEAR + +_TEXT SEGMENT + +;;; ffi_closure_OUTER will be called with these registers set: +;;; rax points to 'closure' +;;; r11 contains a bit mask that specifies which of the +;;; first four parameters are float or double ;;; -ffi_closure_OUTER PROC FRAME - ;; save actual arguments to their stack space. - test r11, 1 - jne first_is_float - mov QWORD PTR [rsp+8], rcx - jmp second -first_is_float: - movlpd QWORD PTR [rsp+8], xmm0 - -second: - test r11, 2 - jne second_is_float - mov QWORD PTR [rsp+16], rdx - jmp third -second_is_float: - movlpd QWORD PTR [rsp+16], xmm1 - -third: - test r11, 4 - jne third_is_float - mov QWORD PTR [rsp+24], r8 - jmp forth -third_is_float: - movlpd QWORD PTR [rsp+24], xmm2 - -forth: - test r11, 8 - jne forth_is_float - mov QWORD PTR [rsp+32], r9 - jmp done -forth_is_float: - movlpd QWORD PTR [rsp+32], xmm3 - -done: -.ALLOCSTACK 40 - sub rsp, 40 -.ENDPROLOG - mov rcx, rax ; context is first parameter - mov rdx, rsp ; stack is second parameter - add rdx, 40 ; correct our own area - mov rax, ffi_closure_SYSV - call rax ; call the real closure function - ;; Here, code is missing that handles float return values - add rsp, 40 - movd xmm0, rax ; In case the closure returned a float. - ret 0 -ffi_closure_OUTER ENDP - - -;;; ffi_call_AMD64 - -stack$ = 0 -prepfunc$ = 32 -ecif$ = 40 -bytes$ = 48 -flags$ = 56 -rvalue$ = 64 -fn$ = 72 - -ffi_call_AMD64 PROC FRAME - - mov QWORD PTR [rsp+32], r9 - mov QWORD PTR [rsp+24], r8 - mov QWORD PTR [rsp+16], rdx - mov QWORD PTR [rsp+8], rcx -.PUSHREG rbp - push rbp -.ALLOCSTACK 48 - sub rsp, 48 ; 00000030H -.SETFRAME rbp, 32 - lea rbp, QWORD PTR [rsp+32] -.ENDPROLOG - - mov eax, DWORD PTR bytes$[rbp] - add rax, 15 - and rax, -16 - call __chkstk - sub rsp, rax - lea rax, QWORD PTR [rsp+32] - mov QWORD PTR stack$[rbp], rax - - mov rdx, QWORD PTR ecif$[rbp] - mov rcx, QWORD PTR stack$[rbp] - call QWORD PTR prepfunc$[rbp] - - mov rsp, QWORD PTR stack$[rbp] - - movlpd xmm3, QWORD PTR [rsp+24] - movd r9, xmm3 - - movlpd xmm2, QWORD PTR [rsp+16] - movd r8, xmm2 - - movlpd xmm1, QWORD PTR [rsp+8] - movd rdx, xmm1 - - movlpd xmm0, QWORD PTR [rsp] - movd rcx, xmm0 - - call QWORD PTR fn$[rbp] -ret_int$: - cmp DWORD PTR flags$[rbp], 1 ; FFI_TYPE_INT - jne ret_float$ - - mov rcx, QWORD PTR rvalue$[rbp] - mov DWORD PTR [rcx], eax - jmp SHORT ret_nothing$ - -ret_float$: - cmp DWORD PTR flags$[rbp], 2 ; FFI_TYPE_FLOAT - jne SHORT ret_double$ - - mov rax, QWORD PTR rvalue$[rbp] - movlpd QWORD PTR [rax], xmm0 - jmp SHORT ret_nothing$ - -ret_double$: - cmp DWORD PTR flags$[rbp], 3 ; FFI_TYPE_DOUBLE - jne SHORT ret_int64$ - - mov rax, QWORD PTR rvalue$[rbp] - movlpd QWORD PTR [rax], xmm0 - jmp SHORT ret_nothing$ - -ret_int64$: - cmp DWORD PTR flags$[rbp], 12 ; FFI_TYPE_SINT64 - jne ret_nothing$ - - mov rcx, QWORD PTR rvalue$[rbp] - mov QWORD PTR [rcx], rax - jmp SHORT ret_nothing$ - -ret_nothing$: - xor eax, eax - - lea rsp, QWORD PTR [rbp+16] - pop rbp - ret 0 -ffi_call_AMD64 ENDP -_TEXT ENDS -END +;;; It must move the parameters passed in registers to their stack location, +;;; call ffi_closure_SYSV for the actual work, then return the result. +;;; +ffi_closure_OUTER PROC FRAME + ;; save actual arguments to their stack space. + test r11, 1 + jne first_is_float + mov QWORD PTR [rsp+8], rcx + jmp second +first_is_float: + movlpd QWORD PTR [rsp+8], xmm0 + +second: + test r11, 2 + jne second_is_float + mov QWORD PTR [rsp+16], rdx + jmp third +second_is_float: + movlpd QWORD PTR [rsp+16], xmm1 + +third: + test r11, 4 + jne third_is_float + mov QWORD PTR [rsp+24], r8 + jmp forth +third_is_float: + movlpd QWORD PTR [rsp+24], xmm2 + +forth: + test r11, 8 + jne forth_is_float + mov QWORD PTR [rsp+32], r9 + jmp done +forth_is_float: + movlpd QWORD PTR [rsp+32], xmm3 + +done: +.ALLOCSTACK 40 + sub rsp, 40 +.ENDPROLOG + mov rcx, rax ; context is first parameter + mov rdx, rsp ; stack is second parameter + add rdx, 40 ; correct our own area + mov rax, ffi_closure_SYSV + call rax ; call the real closure function + ;; Here, code is missing that handles float return values + add rsp, 40 + movd xmm0, rax ; In case the closure returned a float. + ret 0 +ffi_closure_OUTER ENDP + + +;;; ffi_call_AMD64 + +stack$ = 0 +prepfunc$ = 32 +ecif$ = 40 +bytes$ = 48 +flags$ = 56 +rvalue$ = 64 +fn$ = 72 + +ffi_call_AMD64 PROC FRAME + + mov QWORD PTR [rsp+32], r9 + mov QWORD PTR [rsp+24], r8 + mov QWORD PTR [rsp+16], rdx + mov QWORD PTR [rsp+8], rcx +.PUSHREG rbp + push rbp +.ALLOCSTACK 48 + sub rsp, 48 ; 00000030H +.SETFRAME rbp, 32 + lea rbp, QWORD PTR [rsp+32] +.ENDPROLOG + + mov eax, DWORD PTR bytes$[rbp] + add rax, 15 + and rax, -16 + call __chkstk + sub rsp, rax + lea rax, QWORD PTR [rsp+32] + mov QWORD PTR stack$[rbp], rax + + mov rdx, QWORD PTR ecif$[rbp] + mov rcx, QWORD PTR stack$[rbp] + call QWORD PTR prepfunc$[rbp] + + mov rsp, QWORD PTR stack$[rbp] + + movlpd xmm3, QWORD PTR [rsp+24] + movd r9, xmm3 + + movlpd xmm2, QWORD PTR [rsp+16] + movd r8, xmm2 + + movlpd xmm1, QWORD PTR [rsp+8] + movd rdx, xmm1 + + movlpd xmm0, QWORD PTR [rsp] + movd rcx, xmm0 + + call QWORD PTR fn$[rbp] +ret_int$: + cmp DWORD PTR flags$[rbp], 1 ; FFI_TYPE_INT + jne ret_float$ + + mov rcx, QWORD PTR rvalue$[rbp] + mov DWORD PTR [rcx], eax + jmp SHORT ret_nothing$ + +ret_float$: + cmp DWORD PTR flags$[rbp], 2 ; FFI_TYPE_FLOAT + jne SHORT ret_double$ + + mov rax, QWORD PTR rvalue$[rbp] + movlpd QWORD PTR [rax], xmm0 + jmp SHORT ret_nothing$ + +ret_double$: + cmp DWORD PTR flags$[rbp], 3 ; FFI_TYPE_DOUBLE + jne SHORT ret_int64$ + + mov rax, QWORD PTR rvalue$[rbp] + movlpd QWORD PTR [rax], xmm0 + jmp SHORT ret_nothing$ + +ret_int64$: + cmp DWORD PTR flags$[rbp], 12 ; FFI_TYPE_SINT64 + jne ret_nothing$ + + mov rcx, QWORD PTR rvalue$[rbp] + mov QWORD PTR [rcx], rax + jmp SHORT ret_nothing$ + +ret_nothing$: + xor eax, eax + + lea rsp, QWORD PTR [rbp+16] + pop rbp + ret 0 +ffi_call_AMD64 ENDP +_TEXT ENDS +END diff --git a/contrib/python/cffi/c/malloc_closure.h b/contrib/python/cffi/c/malloc_closure.h index bebb93dc15..c8945cec30 100644 --- a/contrib/python/cffi/c/malloc_closure.h +++ b/contrib/python/cffi/c/malloc_closure.h @@ -1,176 +1,176 @@ -/* - * This file is from CPython's Modules/_ctypes/malloc_closure.c - * and has received some edits. - */ - -#include <ffi.h> -#ifdef MS_WIN32 -#include <windows.h> -#else -#include <sys/mman.h> -#include <unistd.h> -# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -# define MAP_ANONYMOUS MAP_ANON -# endif -#endif - -/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. - - This is, apparently, an undocumented change to ffi_prep_closure(): - depending on the Linux kernel we're running on, we must give it a - mmap that is either PROT_READ|PROT_WRITE|PROT_EXEC or only - PROT_READ|PROT_WRITE. In the latter case, just trying to obtain a - mmap with PROT_READ|PROT_WRITE|PROT_EXEC would kill our process(!), - but in that situation libffi is fine with only PROT_READ|PROT_WRITE. - There is nothing in the libffi API to know that, though, so we have - to guess by parsing /proc/self/status. "Meh." - */ -#ifdef __linux__ -#include <stdlib.h> - -static int emutramp_enabled = -1; - -static int -emutramp_enabled_check (void) -{ - char *buf = NULL; - size_t len = 0; - FILE *f; - int ret; - f = fopen ("/proc/self/status", "r"); - if (f == NULL) - return 0; - ret = 0; - - while (getline (&buf, &len, f) != -1) - if (!strncmp (buf, "PaX:", 4)) - { - char emutramp; - if (sscanf (buf, "%*s %*c%c", &emutramp) == 1) - ret = (emutramp == 'E'); - break; - } - free (buf); - fclose (f); - return ret; -} - -#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \ - : (emutramp_enabled = emutramp_enabled_check ())) -#else -#define is_emutramp_enabled() 0 -#endif - - -/* 'allocate_num_pages' is dynamically adjusted starting from one - page. It grows by a factor of PAGE_ALLOCATION_GROWTH_RATE. This is - meant to handle both the common case of not needing a lot of pages, - and the rare case of needing many of them. Systems in general have a - limit of how many mmap'd blocks can be open. -*/ - -#define PAGE_ALLOCATION_GROWTH_RATE 1.3 - -static Py_ssize_t allocate_num_pages = 0; - -/* #define MALLOC_CLOSURE_DEBUG */ /* enable for some debugging output */ - -/******************************************************************/ - -union mmaped_block { - ffi_closure closure; - union mmaped_block *next; -}; - -static union mmaped_block *free_list = 0; -static Py_ssize_t _pagesize = 0; - -static void more_core(void) -{ - union mmaped_block *item; - Py_ssize_t count, i; - -/* determine the pagesize */ -#ifdef MS_WIN32 - if (!_pagesize) { - SYSTEM_INFO systeminfo; - GetSystemInfo(&systeminfo); - _pagesize = systeminfo.dwPageSize; - } -#else - if (!_pagesize) { -#ifdef _SC_PAGESIZE - _pagesize = sysconf(_SC_PAGESIZE); -#else - _pagesize = getpagesize(); -#endif - } -#endif - if (_pagesize <= 0) - _pagesize = 4096; - - /* bump 'allocate_num_pages' */ - allocate_num_pages = 1 + ( - (Py_ssize_t)(allocate_num_pages * PAGE_ALLOCATION_GROWTH_RATE)); - - /* calculate the number of mmaped_blocks to allocate */ - count = (allocate_num_pages * _pagesize) / sizeof(union mmaped_block); - - /* allocate a memory block */ -#ifdef MS_WIN32 - item = (union mmaped_block *)VirtualAlloc(NULL, - count * sizeof(union mmaped_block), - MEM_COMMIT, - PAGE_EXECUTE_READWRITE); - if (item == NULL) - return; -#else - { - int prot = PROT_READ | PROT_WRITE | PROT_EXEC; - if (is_emutramp_enabled ()) - prot &= ~PROT_EXEC; - item = (union mmaped_block *)mmap(NULL, - allocate_num_pages * _pagesize, - prot, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, - 0); - if (item == (void *)MAP_FAILED) - return; - } -#endif - -#ifdef MALLOC_CLOSURE_DEBUG - printf("block at %p allocated (%ld bytes), %ld mmaped_blocks\n", - item, (long)(allocate_num_pages * _pagesize), (long)count); -#endif - /* put them into the free list */ - for (i = 0; i < count; ++i) { - item->next = free_list; - free_list = item; - ++item; - } -} - -/******************************************************************/ - -/* put the item back into the free list */ -static void cffi_closure_free(ffi_closure *p) -{ - union mmaped_block *item = (union mmaped_block *)p; - item->next = free_list; - free_list = item; -} - -/* return one item from the free list, allocating more if needed */ -static ffi_closure *cffi_closure_alloc(void) -{ - union mmaped_block *item; - if (!free_list) - more_core(); - if (!free_list) - return NULL; - item = free_list; - free_list = item->next; - return &item->closure; -} +/* + * This file is from CPython's Modules/_ctypes/malloc_closure.c + * and has received some edits. + */ + +#include <ffi.h> +#ifdef MS_WIN32 +#include <windows.h> +#else +#include <sys/mman.h> +#include <unistd.h> +# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# endif +#endif + +/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. + + This is, apparently, an undocumented change to ffi_prep_closure(): + depending on the Linux kernel we're running on, we must give it a + mmap that is either PROT_READ|PROT_WRITE|PROT_EXEC or only + PROT_READ|PROT_WRITE. In the latter case, just trying to obtain a + mmap with PROT_READ|PROT_WRITE|PROT_EXEC would kill our process(!), + but in that situation libffi is fine with only PROT_READ|PROT_WRITE. + There is nothing in the libffi API to know that, though, so we have + to guess by parsing /proc/self/status. "Meh." + */ +#ifdef __linux__ +#include <stdlib.h> + +static int emutramp_enabled = -1; + +static int +emutramp_enabled_check (void) +{ + char *buf = NULL; + size_t len = 0; + FILE *f; + int ret; + f = fopen ("/proc/self/status", "r"); + if (f == NULL) + return 0; + ret = 0; + + while (getline (&buf, &len, f) != -1) + if (!strncmp (buf, "PaX:", 4)) + { + char emutramp; + if (sscanf (buf, "%*s %*c%c", &emutramp) == 1) + ret = (emutramp == 'E'); + break; + } + free (buf); + fclose (f); + return ret; +} + +#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \ + : (emutramp_enabled = emutramp_enabled_check ())) +#else +#define is_emutramp_enabled() 0 +#endif + + +/* 'allocate_num_pages' is dynamically adjusted starting from one + page. It grows by a factor of PAGE_ALLOCATION_GROWTH_RATE. This is + meant to handle both the common case of not needing a lot of pages, + and the rare case of needing many of them. Systems in general have a + limit of how many mmap'd blocks can be open. +*/ + +#define PAGE_ALLOCATION_GROWTH_RATE 1.3 + +static Py_ssize_t allocate_num_pages = 0; + +/* #define MALLOC_CLOSURE_DEBUG */ /* enable for some debugging output */ + +/******************************************************************/ + +union mmaped_block { + ffi_closure closure; + union mmaped_block *next; +}; + +static union mmaped_block *free_list = 0; +static Py_ssize_t _pagesize = 0; + +static void more_core(void) +{ + union mmaped_block *item; + Py_ssize_t count, i; + +/* determine the pagesize */ +#ifdef MS_WIN32 + if (!_pagesize) { + SYSTEM_INFO systeminfo; + GetSystemInfo(&systeminfo); + _pagesize = systeminfo.dwPageSize; + } +#else + if (!_pagesize) { +#ifdef _SC_PAGESIZE + _pagesize = sysconf(_SC_PAGESIZE); +#else + _pagesize = getpagesize(); +#endif + } +#endif + if (_pagesize <= 0) + _pagesize = 4096; + + /* bump 'allocate_num_pages' */ + allocate_num_pages = 1 + ( + (Py_ssize_t)(allocate_num_pages * PAGE_ALLOCATION_GROWTH_RATE)); + + /* calculate the number of mmaped_blocks to allocate */ + count = (allocate_num_pages * _pagesize) / sizeof(union mmaped_block); + + /* allocate a memory block */ +#ifdef MS_WIN32 + item = (union mmaped_block *)VirtualAlloc(NULL, + count * sizeof(union mmaped_block), + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (item == NULL) + return; +#else + { + int prot = PROT_READ | PROT_WRITE | PROT_EXEC; + if (is_emutramp_enabled ()) + prot &= ~PROT_EXEC; + item = (union mmaped_block *)mmap(NULL, + allocate_num_pages * _pagesize, + prot, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, + 0); + if (item == (void *)MAP_FAILED) + return; + } +#endif + +#ifdef MALLOC_CLOSURE_DEBUG + printf("block at %p allocated (%ld bytes), %ld mmaped_blocks\n", + item, (long)(allocate_num_pages * _pagesize), (long)count); +#endif + /* put them into the free list */ + for (i = 0; i < count; ++i) { + item->next = free_list; + free_list = item; + ++item; + } +} + +/******************************************************************/ + +/* put the item back into the free list */ +static void cffi_closure_free(ffi_closure *p) +{ + union mmaped_block *item = (union mmaped_block *)p; + item->next = free_list; + free_list = item; +} + +/* return one item from the free list, allocating more if needed */ +static ffi_closure *cffi_closure_alloc(void) +{ + union mmaped_block *item; + if (!free_list) + more_core(); + if (!free_list) + return NULL; + item = free_list; + free_list = item->next; + return &item->closure; +} diff --git a/contrib/python/cffi/c/minibuffer.h b/contrib/python/cffi/c/minibuffer.h index f3f5ca15c4..510ef85e0b 100644 --- a/contrib/python/cffi/c/minibuffer.h +++ b/contrib/python/cffi/c/minibuffer.h @@ -1,165 +1,165 @@ - -/* Implementation of a C object with the 'buffer' or 'memoryview' - * interface at C-level (as approriate for the version of Python we're - * compiling for), but only a minimal but *consistent* part of the - * 'buffer' interface at application level. - */ - -typedef struct { - PyObject_HEAD - char *mb_data; - Py_ssize_t mb_size; - PyObject *mb_keepalive; - PyObject *mb_weakreflist; /* weakref support */ -} MiniBufferObj; - -static Py_ssize_t mb_length(MiniBufferObj *self) -{ - return self->mb_size; -} - -static PyObject *mb_item(MiniBufferObj *self, Py_ssize_t idx) -{ - if (idx < 0 || idx >= self->mb_size ) { - PyErr_SetString(PyExc_IndexError, "buffer index out of range"); - return NULL; - } - return PyBytes_FromStringAndSize(self->mb_data + idx, 1); -} - -static PyObject *mb_slice(MiniBufferObj *self, - Py_ssize_t left, Py_ssize_t right) -{ - Py_ssize_t size = self->mb_size; - if (left < 0) left = 0; - if (right > size) right = size; - if (left > right) left = right; - return PyBytes_FromStringAndSize(self->mb_data + left, right - left); -} - -static int mb_ass_item(MiniBufferObj *self, Py_ssize_t idx, PyObject *other) -{ - if (idx < 0 || idx >= self->mb_size) { - PyErr_SetString(PyExc_IndexError, - "buffer assignment index out of range"); - return -1; - } - if (PyBytes_Check(other) && PyBytes_GET_SIZE(other) == 1) { - self->mb_data[idx] = PyBytes_AS_STRING(other)[0]; - return 0; - } - else { - PyErr_Format(PyExc_TypeError, - "must assign a "STR_OR_BYTES - " of length 1, not %.200s", Py_TYPE(other)->tp_name); - return -1; - } -} - + +/* Implementation of a C object with the 'buffer' or 'memoryview' + * interface at C-level (as approriate for the version of Python we're + * compiling for), but only a minimal but *consistent* part of the + * 'buffer' interface at application level. + */ + +typedef struct { + PyObject_HEAD + char *mb_data; + Py_ssize_t mb_size; + PyObject *mb_keepalive; + PyObject *mb_weakreflist; /* weakref support */ +} MiniBufferObj; + +static Py_ssize_t mb_length(MiniBufferObj *self) +{ + return self->mb_size; +} + +static PyObject *mb_item(MiniBufferObj *self, Py_ssize_t idx) +{ + if (idx < 0 || idx >= self->mb_size ) { + PyErr_SetString(PyExc_IndexError, "buffer index out of range"); + return NULL; + } + return PyBytes_FromStringAndSize(self->mb_data + idx, 1); +} + +static PyObject *mb_slice(MiniBufferObj *self, + Py_ssize_t left, Py_ssize_t right) +{ + Py_ssize_t size = self->mb_size; + if (left < 0) left = 0; + if (right > size) right = size; + if (left > right) left = right; + return PyBytes_FromStringAndSize(self->mb_data + left, right - left); +} + +static int mb_ass_item(MiniBufferObj *self, Py_ssize_t idx, PyObject *other) +{ + if (idx < 0 || idx >= self->mb_size) { + PyErr_SetString(PyExc_IndexError, + "buffer assignment index out of range"); + return -1; + } + if (PyBytes_Check(other) && PyBytes_GET_SIZE(other) == 1) { + self->mb_data[idx] = PyBytes_AS_STRING(other)[0]; + return 0; + } + else { + PyErr_Format(PyExc_TypeError, + "must assign a "STR_OR_BYTES + " of length 1, not %.200s", Py_TYPE(other)->tp_name); + return -1; + } +} + /* forward: from _cffi_backend.c */ static int _fetch_as_buffer(PyObject *x, Py_buffer *view, int writable_only); -static int mb_ass_slice(MiniBufferObj *self, - Py_ssize_t left, Py_ssize_t right, PyObject *other) -{ +static int mb_ass_slice(MiniBufferObj *self, + Py_ssize_t left, Py_ssize_t right, PyObject *other) +{ Py_ssize_t count; - Py_ssize_t size = self->mb_size; + Py_ssize_t size = self->mb_size; Py_buffer src_view; - + if (_fetch_as_buffer(other, &src_view, 0) < 0) - return -1; - - if (left < 0) left = 0; - if (right > size) right = size; - if (left > right) left = right; - - count = right - left; + return -1; + + if (left < 0) left = 0; + if (right > size) right = size; + if (left > right) left = right; + + count = right - left; if (count != src_view.len) { PyBuffer_Release(&src_view); - PyErr_SetString(PyExc_ValueError, - "right operand length must match slice length"); - return -1; - } + PyErr_SetString(PyExc_ValueError, + "right operand length must match slice length"); + return -1; + } memcpy(self->mb_data + left, src_view.buf, count); PyBuffer_Release(&src_view); - return 0; -} - -#if PY_MAJOR_VERSION < 3 -static Py_ssize_t mb_getdata(MiniBufferObj *self, Py_ssize_t idx, void **pp) -{ - *pp = self->mb_data; - return self->mb_size; -} - -static Py_ssize_t mb_getsegcount(MiniBufferObj *self, Py_ssize_t *lenp) -{ - if (lenp) - *lenp = self->mb_size; - return 1; -} - -static PyObject *mb_str(MiniBufferObj *self) -{ - /* Python 2: we want str(buffer) to behave like buffer[:], because - that's what bytes(buffer) does on Python 3 and there is no way - we can prevent this. */ - return PyString_FromStringAndSize(self->mb_data, self->mb_size); -} -#endif - -static int mb_getbuf(MiniBufferObj *self, Py_buffer *view, int flags) -{ - return PyBuffer_FillInfo(view, (PyObject *)self, - self->mb_data, self->mb_size, - /*readonly=*/0, flags); -} - -static PySequenceMethods mb_as_sequence = { - (lenfunc)mb_length, /*sq_length*/ - (binaryfunc)0, /*sq_concat*/ - (ssizeargfunc)0, /*sq_repeat*/ - (ssizeargfunc)mb_item, /*sq_item*/ - (ssizessizeargfunc)mb_slice, /*sq_slice*/ - (ssizeobjargproc)mb_ass_item, /*sq_ass_item*/ - (ssizessizeobjargproc)mb_ass_slice, /*sq_ass_slice*/ -}; - -static PyBufferProcs mb_as_buffer = { -#if PY_MAJOR_VERSION < 3 - (readbufferproc)mb_getdata, - (writebufferproc)mb_getdata, - (segcountproc)mb_getsegcount, - (charbufferproc)mb_getdata, -#endif - (getbufferproc)mb_getbuf, - (releasebufferproc)0, -}; - -static void -mb_dealloc(MiniBufferObj *ob) -{ - PyObject_GC_UnTrack(ob); - if (ob->mb_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *)ob); - Py_XDECREF(ob->mb_keepalive); - Py_TYPE(ob)->tp_free((PyObject *)ob); -} - -static int -mb_traverse(MiniBufferObj *ob, visitproc visit, void *arg) -{ - Py_VISIT(ob->mb_keepalive); - return 0; -} - -static int -mb_clear(MiniBufferObj *ob) -{ - Py_CLEAR(ob->mb_keepalive); - return 0; -} - + return 0; +} + +#if PY_MAJOR_VERSION < 3 +static Py_ssize_t mb_getdata(MiniBufferObj *self, Py_ssize_t idx, void **pp) +{ + *pp = self->mb_data; + return self->mb_size; +} + +static Py_ssize_t mb_getsegcount(MiniBufferObj *self, Py_ssize_t *lenp) +{ + if (lenp) + *lenp = self->mb_size; + return 1; +} + +static PyObject *mb_str(MiniBufferObj *self) +{ + /* Python 2: we want str(buffer) to behave like buffer[:], because + that's what bytes(buffer) does on Python 3 and there is no way + we can prevent this. */ + return PyString_FromStringAndSize(self->mb_data, self->mb_size); +} +#endif + +static int mb_getbuf(MiniBufferObj *self, Py_buffer *view, int flags) +{ + return PyBuffer_FillInfo(view, (PyObject *)self, + self->mb_data, self->mb_size, + /*readonly=*/0, flags); +} + +static PySequenceMethods mb_as_sequence = { + (lenfunc)mb_length, /*sq_length*/ + (binaryfunc)0, /*sq_concat*/ + (ssizeargfunc)0, /*sq_repeat*/ + (ssizeargfunc)mb_item, /*sq_item*/ + (ssizessizeargfunc)mb_slice, /*sq_slice*/ + (ssizeobjargproc)mb_ass_item, /*sq_ass_item*/ + (ssizessizeobjargproc)mb_ass_slice, /*sq_ass_slice*/ +}; + +static PyBufferProcs mb_as_buffer = { +#if PY_MAJOR_VERSION < 3 + (readbufferproc)mb_getdata, + (writebufferproc)mb_getdata, + (segcountproc)mb_getsegcount, + (charbufferproc)mb_getdata, +#endif + (getbufferproc)mb_getbuf, + (releasebufferproc)0, +}; + +static void +mb_dealloc(MiniBufferObj *ob) +{ + PyObject_GC_UnTrack(ob); + if (ob->mb_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *)ob); + Py_XDECREF(ob->mb_keepalive); + Py_TYPE(ob)->tp_free((PyObject *)ob); +} + +static int +mb_traverse(MiniBufferObj *ob, visitproc visit, void *arg) +{ + Py_VISIT(ob->mb_keepalive); + return 0; +} + +static int +mb_clear(MiniBufferObj *ob) +{ + Py_CLEAR(ob->mb_keepalive); + return 0; +} + static PyObject * mb_richcompare(PyObject *self, PyObject *other, int op) { @@ -235,8 +235,8 @@ mb_richcompare(PyObject *self, PyObject *other, int op) return res; } -#if PY_MAJOR_VERSION >= 3 -/* pfffffffffffff pages of copy-paste from listobject.c */ +#if PY_MAJOR_VERSION >= 3 +/* pfffffffffffff pages of copy-paste from listobject.c */ /* pfffffffffffff#2: the PySlice_GetIndicesEx() *macro* should not be called, because C extension modules compiled with it differ @@ -245,87 +245,87 @@ mb_richcompare(PyObject *self, PyObject *other, int op) #undef PySlice_GetIndicesEx #endif -static PyObject *mb_subscript(MiniBufferObj *self, PyObject *item) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i; - i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += self->mb_size; - return mb_item(self, i); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx(item, self->mb_size, - &start, &stop, &step, &slicelength) < 0) - return NULL; - - if (step == 1) - return mb_slice(self, start, stop); - else { - PyErr_SetString(PyExc_TypeError, - "buffer doesn't support slicing with step != 1"); - return NULL; - } - } - else { - PyErr_Format(PyExc_TypeError, - "buffer indices must be integers, not %.200s", - item->ob_type->tp_name); - return NULL; - } -} -static int -mb_ass_subscript(MiniBufferObj* self, PyObject* item, PyObject* value) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return -1; - if (i < 0) - i += self->mb_size; - return mb_ass_item(self, i, value); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx(item, self->mb_size, - &start, &stop, &step, &slicelength) < 0) { - return -1; - } - - if (step == 1) - return mb_ass_slice(self, start, stop, value); - else { - PyErr_SetString(PyExc_TypeError, - "buffer doesn't support slicing with step != 1"); - return -1; - } - } - else { - PyErr_Format(PyExc_TypeError, - "buffer indices must be integers, not %.200s", - item->ob_type->tp_name); - return -1; - } -} - -static PyMappingMethods mb_as_mapping = { - (lenfunc)mb_length, /*mp_length*/ - (binaryfunc)mb_subscript, /*mp_subscript*/ - (objobjargproc)mb_ass_subscript, /*mp_ass_subscript*/ -}; -#endif - -#if PY_MAJOR_VERSION >= 3 -# define MINIBUF_TPFLAGS 0 -#else -# define MINIBUF_TPFLAGS (Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER) -#endif - +static PyObject *mb_subscript(MiniBufferObj *self, PyObject *item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += self->mb_size; + return mb_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx(item, self->mb_size, + &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (step == 1) + return mb_slice(self, start, stop); + else { + PyErr_SetString(PyExc_TypeError, + "buffer doesn't support slicing with step != 1"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "buffer indices must be integers, not %.200s", + item->ob_type->tp_name); + return NULL; + } +} +static int +mb_ass_subscript(MiniBufferObj* self, PyObject* item, PyObject* value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += self->mb_size; + return mb_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx(item, self->mb_size, + &start, &stop, &step, &slicelength) < 0) { + return -1; + } + + if (step == 1) + return mb_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_TypeError, + "buffer doesn't support slicing with step != 1"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "buffer indices must be integers, not %.200s", + item->ob_type->tp_name); + return -1; + } +} + +static PyMappingMethods mb_as_mapping = { + (lenfunc)mb_length, /*mp_length*/ + (binaryfunc)mb_subscript, /*mp_subscript*/ + (objobjargproc)mb_ass_subscript, /*mp_ass_subscript*/ +}; +#endif + +#if PY_MAJOR_VERSION >= 3 +# define MINIBUF_TPFLAGS 0 +#else +# define MINIBUF_TPFLAGS (Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER) +#endif + PyDoc_STRVAR(ffi_buffer_doc, "ffi.buffer(cdata[, byte_size]):\n" "Return a read-write buffer object that references the raw C data\n" @@ -342,41 +342,41 @@ static PyObject * /* forward, implemented in _cffi_backend.c */ b_buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds); -static PyTypeObject MiniBuffer_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.buffer", - sizeof(MiniBufferObj), - 0, - (destructor)mb_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &mb_as_sequence, /* tp_as_sequence */ -#if PY_MAJOR_VERSION < 3 - 0, /* tp_as_mapping */ -#else - &mb_as_mapping, /* tp_as_mapping */ -#endif - 0, /* tp_hash */ - 0, /* tp_call */ -#if PY_MAJOR_VERSION < 3 - (reprfunc)mb_str, /* tp_str */ -#else - 0, /* tp_str */ -#endif - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - &mb_as_buffer, /* tp_as_buffer */ - (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - MINIBUF_TPFLAGS), /* tp_flags */ +static PyTypeObject MiniBuffer_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_cffi_backend.buffer", + sizeof(MiniBufferObj), + 0, + (destructor)mb_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &mb_as_sequence, /* tp_as_sequence */ +#if PY_MAJOR_VERSION < 3 + 0, /* tp_as_mapping */ +#else + &mb_as_mapping, /* tp_as_mapping */ +#endif + 0, /* tp_hash */ + 0, /* tp_call */ +#if PY_MAJOR_VERSION < 3 + (reprfunc)mb_str, /* tp_str */ +#else + 0, /* tp_str */ +#endif + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + &mb_as_buffer, /* tp_as_buffer */ + (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + MINIBUF_TPFLAGS), /* tp_flags */ ffi_buffer_doc, /* tp_doc */ - (traverseproc)mb_traverse, /* tp_traverse */ - (inquiry)mb_clear, /* tp_clear */ + (traverseproc)mb_traverse, /* tp_traverse */ + (inquiry)mb_clear, /* tp_clear */ (richcmpfunc)mb_richcompare, /* tp_richcompare */ - offsetof(MiniBufferObj, mb_weakreflist), /* tp_weaklistoffset */ + offsetof(MiniBufferObj, mb_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ @@ -391,18 +391,18 @@ static PyTypeObject MiniBuffer_Type = { 0, /* tp_alloc */ b_buffer_new, /* tp_new */ 0, /* tp_free */ -}; - -static PyObject *minibuffer_new(char *data, Py_ssize_t size, - PyObject *keepalive) -{ - MiniBufferObj *ob = PyObject_GC_New(MiniBufferObj, &MiniBuffer_Type); - if (ob != NULL) { - ob->mb_data = data; - ob->mb_size = size; - ob->mb_keepalive = keepalive; Py_INCREF(keepalive); - ob->mb_weakreflist = NULL; - PyObject_GC_Track(ob); - } - return (PyObject *)ob; -} +}; + +static PyObject *minibuffer_new(char *data, Py_ssize_t size, + PyObject *keepalive) +{ + MiniBufferObj *ob = PyObject_GC_New(MiniBufferObj, &MiniBuffer_Type); + if (ob != NULL) { + ob->mb_data = data; + ob->mb_size = size; + ob->mb_keepalive = keepalive; Py_INCREF(keepalive); + ob->mb_weakreflist = NULL; + PyObject_GC_Track(ob); + } + return (PyObject *)ob; +} diff --git a/contrib/python/cffi/c/misc_thread_common.h b/contrib/python/cffi/c/misc_thread_common.h index 66e283545b..04d4f93197 100644 --- a/contrib/python/cffi/c/misc_thread_common.h +++ b/contrib/python/cffi/c/misc_thread_common.h @@ -1,30 +1,30 @@ -#ifndef WITH_THREAD -# error "xxx no-thread configuration not tested, please report if you need that" -#endif +#ifndef WITH_THREAD +# error "xxx no-thread configuration not tested, please report if you need that" +#endif #include "pythread.h" - - -struct cffi_tls_s { + + +struct cffi_tls_s { /* The current thread's ThreadCanaryObj. This is only non-null in case cffi builds the thread state here. It remains null if this thread had already a thread state provided by CPython. */ struct thread_canary_s *local_thread_canary; - -#ifndef USE__THREAD - /* The saved errno. If the C compiler supports '__thread', then - we use that instead. */ - int saved_errno; -#endif - -#ifdef MS_WIN32 - /* The saved lasterror, on Windows. */ - int saved_lasterror; -#endif -}; - -static struct cffi_tls_s *get_cffi_tls(void); /* in misc_thread_posix.h - or misc_win32.h */ - + +#ifndef USE__THREAD + /* The saved errno. If the C compiler supports '__thread', then + we use that instead. */ + int saved_errno; +#endif + +#ifdef MS_WIN32 + /* The saved lasterror, on Windows. */ + int saved_lasterror; +#endif +}; + +static struct cffi_tls_s *get_cffi_tls(void); /* in misc_thread_posix.h + or misc_win32.h */ + /* We try to keep the PyThreadState around in a thread not started by * Python but where cffi callbacks occur. If we didn't do that, then @@ -251,52 +251,52 @@ static void init_cffi_tls_zombie(void) PyErr_SetString(PyExc_SystemError, "can't allocate cffi_zombie_lock"); } -static void cffi_thread_shutdown(void *p) -{ +static void cffi_thread_shutdown(void *p) +{ /* this function is called from misc_thread_posix or misc_win32 when a thread is about to end. */ - struct cffi_tls_s *tls = (struct cffi_tls_s *)p; - + struct cffi_tls_s *tls = (struct cffi_tls_s *)p; + /* thread-safety: this field 'local_thread_canary' can be reset to NULL in parallel, protected by TLS_ZOM_LOCK. */ TLS_ZOM_LOCK(); if (tls->local_thread_canary != NULL) { tls->local_thread_canary->tls = NULL; thread_canary_make_zombie(tls->local_thread_canary); - } + } TLS_ZOM_UNLOCK(); //fprintf(stderr, "thread_shutdown(%p)\n", tls); - free(tls); -} - -/* USE__THREAD is defined by setup.py if it finds that it is - syntactically valid to use "__thread" with this C compiler. */ -#ifdef USE__THREAD - -static __thread int cffi_saved_errno = 0; -static void save_errno_only(void) { cffi_saved_errno = errno; } -static void restore_errno_only(void) { errno = cffi_saved_errno; } - -#else - -static void save_errno_only(void) -{ - int saved = errno; - struct cffi_tls_s *tls = get_cffi_tls(); - if (tls != NULL) - tls->saved_errno = saved; -} - -static void restore_errno_only(void) -{ - struct cffi_tls_s *tls = get_cffi_tls(); - if (tls != NULL) - errno = tls->saved_errno; -} - -#endif - - + free(tls); +} + +/* USE__THREAD is defined by setup.py if it finds that it is + syntactically valid to use "__thread" with this C compiler. */ +#ifdef USE__THREAD + +static __thread int cffi_saved_errno = 0; +static void save_errno_only(void) { cffi_saved_errno = errno; } +static void restore_errno_only(void) { errno = cffi_saved_errno; } + +#else + +static void save_errno_only(void) +{ + int saved = errno; + struct cffi_tls_s *tls = get_cffi_tls(); + if (tls != NULL) + tls->saved_errno = saved; +} + +static void restore_errno_only(void) +{ + struct cffi_tls_s *tls = get_cffi_tls(); + if (tls != NULL) + errno = tls->saved_errno; +} + +#endif + + /* MESS. We can't use PyThreadState_GET(), because that calls PyThreadState_Get() which fails an assert if the result is NULL. @@ -314,58 +314,58 @@ static void restore_errno_only(void) */ #if PY_VERSION_HEX >= 0x03050100 && PY_VERSION_HEX < 0x03060000 PyAPI_DATA(void *volatile) _PyThreadState_Current; -#endif - -static PyThreadState *get_current_ts(void) -{ +#endif + +static PyThreadState *get_current_ts(void) +{ #if PY_VERSION_HEX >= 0x03060000 return _PyThreadState_UncheckedGet(); #elif defined(_Py_atomic_load_relaxed) - return (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); -#else + return (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); +#else return (PyThreadState*)_PyThreadState_Current; /* assume atomic read */ -#endif -} - -static PyGILState_STATE gil_ensure(void) -{ - /* Called at the start of a callback. Replacement for - PyGILState_Ensure(). - */ - PyGILState_STATE result; - PyThreadState *ts = PyGILState_GetThisThreadState(); - - if (ts != NULL) { - ts->gilstate_counter++; - if (ts != get_current_ts()) { - /* common case: 'ts' is our non-current thread state and - we have to make it current and acquire the GIL */ - PyEval_RestoreThread(ts); - return PyGILState_UNLOCKED; - } - else { - return PyGILState_LOCKED; - } - } - else { - /* no thread state here so far. */ - result = PyGILState_Ensure(); - assert(result == PyGILState_UNLOCKED); - - ts = PyGILState_GetThisThreadState(); - assert(ts != NULL); - assert(ts == get_current_ts()); - assert(ts->gilstate_counter >= 1); - +#endif +} + +static PyGILState_STATE gil_ensure(void) +{ + /* Called at the start of a callback. Replacement for + PyGILState_Ensure(). + */ + PyGILState_STATE result; + PyThreadState *ts = PyGILState_GetThisThreadState(); + + if (ts != NULL) { + ts->gilstate_counter++; + if (ts != get_current_ts()) { + /* common case: 'ts' is our non-current thread state and + we have to make it current and acquire the GIL */ + PyEval_RestoreThread(ts); + return PyGILState_UNLOCKED; + } + else { + return PyGILState_LOCKED; + } + } + else { + /* no thread state here so far. */ + result = PyGILState_Ensure(); + assert(result == PyGILState_UNLOCKED); + + ts = PyGILState_GetThisThreadState(); + assert(ts != NULL); + assert(ts == get_current_ts()); + assert(ts->gilstate_counter >= 1); + /* Use the ThreadCanary mechanism to keep 'ts' alive until the thread really shuts down */ thread_canary_register(ts); - - return result; - } -} - -static void gil_release(PyGILState_STATE oldstate) -{ - PyGILState_Release(oldstate); -} + + return result; + } +} + +static void gil_release(PyGILState_STATE oldstate) +{ + PyGILState_Release(oldstate); +} diff --git a/contrib/python/cffi/c/misc_thread_posix.h b/contrib/python/cffi/c/misc_thread_posix.h index bcc017737b..7adf63f0c5 100644 --- a/contrib/python/cffi/c/misc_thread_posix.h +++ b/contrib/python/cffi/c/misc_thread_posix.h @@ -1,49 +1,49 @@ -/* - Logic for a better replacement of PyGILState_Ensure(). - - This version is ready to handle the case of a non-Python-started - thread in which we do a large number of calls to CFFI callbacks. If - we were to rely on PyGILState_Ensure() for that, we would constantly - be creating and destroying PyThreadStates---it is slow, and - PyThreadState_Delete() will actually walk the list of all thread - states, making it O(n). :-( - - This version only creates one PyThreadState object the first time we - see a given thread, and keep it alive until the thread is really - shut down, using a destructor on the tls key. -*/ - -#include <pthread.h> -#include "misc_thread_common.h" - - -static pthread_key_t cffi_tls_key; - -static void init_cffi_tls(void) -{ - if (pthread_key_create(&cffi_tls_key, &cffi_thread_shutdown) != 0) - PyErr_SetString(PyExc_OSError, "pthread_key_create() failed"); -} - -static struct cffi_tls_s *_make_cffi_tls(void) -{ - void *p = calloc(1, sizeof(struct cffi_tls_s)); - if (p == NULL) - return NULL; - if (pthread_setspecific(cffi_tls_key, p) != 0) { - free(p); - return NULL; - } - return p; -} - -static struct cffi_tls_s *get_cffi_tls(void) -{ - void *p = pthread_getspecific(cffi_tls_key); - if (p == NULL) - p = _make_cffi_tls(); - return (struct cffi_tls_s *)p; -} - -#define save_errno save_errno_only -#define restore_errno restore_errno_only +/* + Logic for a better replacement of PyGILState_Ensure(). + + This version is ready to handle the case of a non-Python-started + thread in which we do a large number of calls to CFFI callbacks. If + we were to rely on PyGILState_Ensure() for that, we would constantly + be creating and destroying PyThreadStates---it is slow, and + PyThreadState_Delete() will actually walk the list of all thread + states, making it O(n). :-( + + This version only creates one PyThreadState object the first time we + see a given thread, and keep it alive until the thread is really + shut down, using a destructor on the tls key. +*/ + +#include <pthread.h> +#include "misc_thread_common.h" + + +static pthread_key_t cffi_tls_key; + +static void init_cffi_tls(void) +{ + if (pthread_key_create(&cffi_tls_key, &cffi_thread_shutdown) != 0) + PyErr_SetString(PyExc_OSError, "pthread_key_create() failed"); +} + +static struct cffi_tls_s *_make_cffi_tls(void) +{ + void *p = calloc(1, sizeof(struct cffi_tls_s)); + if (p == NULL) + return NULL; + if (pthread_setspecific(cffi_tls_key, p) != 0) { + free(p); + return NULL; + } + return p; +} + +static struct cffi_tls_s *get_cffi_tls(void) +{ + void *p = pthread_getspecific(cffi_tls_key); + if (p == NULL) + p = _make_cffi_tls(); + return (struct cffi_tls_s *)p; +} + +#define save_errno save_errno_only +#define restore_errno restore_errno_only diff --git a/contrib/python/cffi/c/misc_win32.h b/contrib/python/cffi/c/misc_win32.h index 2946721801..94f47d8884 100644 --- a/contrib/python/cffi/c/misc_win32.h +++ b/contrib/python/cffi/c/misc_win32.h @@ -1,218 +1,218 @@ -#include <malloc.h> /* for alloca() */ - - -/************************************************************/ -/* errno and GetLastError support */ - -#include "misc_thread_common.h" - -static DWORD cffi_tls_index = TLS_OUT_OF_INDEXES; - -static void init_cffi_tls(void) -{ - if (cffi_tls_index == TLS_OUT_OF_INDEXES) { - cffi_tls_index = TlsAlloc(); - if (cffi_tls_index == TLS_OUT_OF_INDEXES) - PyErr_SetString(PyExc_WindowsError, "TlsAlloc() failed"); - } -} - -static struct cffi_tls_s *get_cffi_tls(void) -{ - LPVOID p = TlsGetValue(cffi_tls_index); - - if (p == NULL) { - p = malloc(sizeof(struct cffi_tls_s)); - if (p == NULL) - return NULL; - memset(p, 0, sizeof(struct cffi_tls_s)); - TlsSetValue(cffi_tls_index, p); - } - return (struct cffi_tls_s *)p; -} - -#ifdef USE__THREAD -# error "unexpected USE__THREAD on Windows" -#endif - -static void save_errno(void) -{ - int current_err = errno; - int current_lasterr = GetLastError(); - struct cffi_tls_s *p = get_cffi_tls(); - if (p != NULL) { - p->saved_errno = current_err; - p->saved_lasterror = current_lasterr; - } - /* else: cannot report the error */ -} - -static void restore_errno(void) -{ - struct cffi_tls_s *p = get_cffi_tls(); - if (p != NULL) { - SetLastError(p->saved_lasterror); - errno = p->saved_errno; - } - /* else: cannot report the error */ -} - -/************************************************************/ - - -#if PY_MAJOR_VERSION >= 3 -static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) -{ - int err = -1; - int len; - WCHAR *s_buf = NULL; /* Free via LocalFree */ - PyObject *v, *message; - static char *keywords[] = {"code", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) - return NULL; - - if (err == -1) { - struct cffi_tls_s *p = get_cffi_tls(); - if (p == NULL) - return PyErr_NoMemory(); - err = p->saved_lasterror; - } - - len = FormatMessageW( - /* Error API error */ - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, /* no message source */ - err, - MAKELANGID(LANG_NEUTRAL, - SUBLANG_DEFAULT), /* Default language */ - (LPWSTR) &s_buf, - 0, /* size not used */ - NULL); /* no args */ - if (len==0) { - /* Only seen this in out of mem situations */ - message = PyUnicode_FromFormat("Windows Error 0x%X", err); - } else { - /* remove trailing cr/lf and dots */ - while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.')) - s_buf[--len] = L'\0'; - message = PyUnicode_FromWideChar(s_buf, len); - } +#include <malloc.h> /* for alloca() */ + + +/************************************************************/ +/* errno and GetLastError support */ + +#include "misc_thread_common.h" + +static DWORD cffi_tls_index = TLS_OUT_OF_INDEXES; + +static void init_cffi_tls(void) +{ + if (cffi_tls_index == TLS_OUT_OF_INDEXES) { + cffi_tls_index = TlsAlloc(); + if (cffi_tls_index == TLS_OUT_OF_INDEXES) + PyErr_SetString(PyExc_WindowsError, "TlsAlloc() failed"); + } +} + +static struct cffi_tls_s *get_cffi_tls(void) +{ + LPVOID p = TlsGetValue(cffi_tls_index); + + if (p == NULL) { + p = malloc(sizeof(struct cffi_tls_s)); + if (p == NULL) + return NULL; + memset(p, 0, sizeof(struct cffi_tls_s)); + TlsSetValue(cffi_tls_index, p); + } + return (struct cffi_tls_s *)p; +} + +#ifdef USE__THREAD +# error "unexpected USE__THREAD on Windows" +#endif + +static void save_errno(void) +{ + int current_err = errno; + int current_lasterr = GetLastError(); + struct cffi_tls_s *p = get_cffi_tls(); + if (p != NULL) { + p->saved_errno = current_err; + p->saved_lasterror = current_lasterr; + } + /* else: cannot report the error */ +} + +static void restore_errno(void) +{ + struct cffi_tls_s *p = get_cffi_tls(); + if (p != NULL) { + SetLastError(p->saved_lasterror); + errno = p->saved_errno; + } + /* else: cannot report the error */ +} + +/************************************************************/ + + +#if PY_MAJOR_VERSION >= 3 +static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) +{ + int err = -1; + int len; + WCHAR *s_buf = NULL; /* Free via LocalFree */ + PyObject *v, *message; + static char *keywords[] = {"code", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) + return NULL; + + if (err == -1) { + struct cffi_tls_s *p = get_cffi_tls(); + if (p == NULL) + return PyErr_NoMemory(); + err = p->saved_lasterror; + } + + len = FormatMessageW( + /* Error API error */ + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, /* no message source */ + err, + MAKELANGID(LANG_NEUTRAL, + SUBLANG_DEFAULT), /* Default language */ + (LPWSTR) &s_buf, + 0, /* size not used */ + NULL); /* no args */ + if (len==0) { + /* Only seen this in out of mem situations */ + message = PyUnicode_FromFormat("Windows Error 0x%X", err); + } else { + /* remove trailing cr/lf and dots */ + while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.')) + s_buf[--len] = L'\0'; + message = PyUnicode_FromWideChar(s_buf, len); + } if (message != NULL) { - v = Py_BuildValue("(iO)", err, message); + v = Py_BuildValue("(iO)", err, message); Py_DECREF(message); } - else - v = NULL; - LocalFree(s_buf); - return v; -} -#else -static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) -{ - int err = -1; - int len; - char *s; - char *s_buf = NULL; /* Free via LocalFree */ - char s_small_buf[40]; /* Room for "Windows Error 0xFFFFFFFFFFFFFFFF" */ - PyObject *v; - static char *keywords[] = {"code", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) - return NULL; - - if (err == -1) { - struct cffi_tls_s *p = get_cffi_tls(); - if (p == NULL) - return PyErr_NoMemory(); - err = p->saved_lasterror; - } - - len = FormatMessage( - /* Error API error */ - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, /* no message source */ - err, - MAKELANGID(LANG_NEUTRAL, - SUBLANG_DEFAULT), /* Default language */ - (LPTSTR) &s_buf, - 0, /* size not used */ - NULL); /* no args */ - if (len==0) { - /* Only seen this in out of mem situations */ - sprintf(s_small_buf, "Windows Error 0x%X", err); - s = s_small_buf; - } else { - s = s_buf; - /* remove trailing cr/lf and dots */ - while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.')) - s[--len] = '\0'; - } - v = Py_BuildValue("(is)", err, s); - LocalFree(s_buf); - return v; -} -#endif - - -/************************************************************/ -/* Emulate dlopen()&co. from the Windows API */ - -#define RTLD_LAZY 0 -#define RTLD_NOW 0 -#define RTLD_GLOBAL 0 -#define RTLD_LOCAL 0 - -static void *dlopen(const char *filename, int flag) -{ + else + v = NULL; + LocalFree(s_buf); + return v; +} +#else +static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) +{ + int err = -1; + int len; + char *s; + char *s_buf = NULL; /* Free via LocalFree */ + char s_small_buf[40]; /* Room for "Windows Error 0xFFFFFFFFFFFFFFFF" */ + PyObject *v; + static char *keywords[] = {"code", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) + return NULL; + + if (err == -1) { + struct cffi_tls_s *p = get_cffi_tls(); + if (p == NULL) + return PyErr_NoMemory(); + err = p->saved_lasterror; + } + + len = FormatMessage( + /* Error API error */ + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, /* no message source */ + err, + MAKELANGID(LANG_NEUTRAL, + SUBLANG_DEFAULT), /* Default language */ + (LPTSTR) &s_buf, + 0, /* size not used */ + NULL); /* no args */ + if (len==0) { + /* Only seen this in out of mem situations */ + sprintf(s_small_buf, "Windows Error 0x%X", err); + s = s_small_buf; + } else { + s = s_buf; + /* remove trailing cr/lf and dots */ + while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.')) + s[--len] = '\0'; + } + v = Py_BuildValue("(is)", err, s); + LocalFree(s_buf); + return v; +} +#endif + + +/************************************************************/ +/* Emulate dlopen()&co. from the Windows API */ + +#define RTLD_LAZY 0 +#define RTLD_NOW 0 +#define RTLD_GLOBAL 0 +#define RTLD_LOCAL 0 + +static void *dlopen(const char *filename, int flag) +{ return (void *)LoadLibraryA(filename); -} - +} + static void *dlopenW(const wchar_t *filename) { return (void *)LoadLibraryW(filename); } -static void *dlsym(void *handle, const char *symbol) -{ - void *address = GetProcAddress((HMODULE)handle, symbol); -#ifndef MS_WIN64 - if (!address) { - /* If 'symbol' is not found, then try '_symbol@N' for N in - (0, 4, 8, 12, ..., 124). Unlike ctypes, we try to do that - for any symbol, although in theory it should only be done - for __stdcall functions. - */ - int i; - char *mangled_name = alloca(1 + strlen(symbol) + 1 + 3 + 1); - if (!mangled_name) - return NULL; - for (i = 0; i < 32; i++) { - sprintf(mangled_name, "_%s@%d", symbol, i * 4); - address = GetProcAddress((HMODULE)handle, mangled_name); - if (address) - break; - } - } -#endif - return address; -} - -static int dlclose(void *handle) -{ - return FreeLibrary((HMODULE)handle) ? 0 : -1; -} - -static const char *dlerror(void) -{ - static char buf[32]; - DWORD dw = GetLastError(); - if (dw == 0) - return NULL; - sprintf(buf, "error 0x%x", (unsigned int)dw); - return buf; -} +static void *dlsym(void *handle, const char *symbol) +{ + void *address = GetProcAddress((HMODULE)handle, symbol); +#ifndef MS_WIN64 + if (!address) { + /* If 'symbol' is not found, then try '_symbol@N' for N in + (0, 4, 8, 12, ..., 124). Unlike ctypes, we try to do that + for any symbol, although in theory it should only be done + for __stdcall functions. + */ + int i; + char *mangled_name = alloca(1 + strlen(symbol) + 1 + 3 + 1); + if (!mangled_name) + return NULL; + for (i = 0; i < 32; i++) { + sprintf(mangled_name, "_%s@%d", symbol, i * 4); + address = GetProcAddress((HMODULE)handle, mangled_name); + if (address) + break; + } + } +#endif + return address; +} + +static int dlclose(void *handle) +{ + return FreeLibrary((HMODULE)handle) ? 0 : -1; +} + +static const char *dlerror(void) +{ + static char buf[32]; + DWORD dw = GetLastError(); + if (dw == 0) + return NULL; + sprintf(buf, "error 0x%x", (unsigned int)dw); + return buf; +} diff --git a/contrib/python/cffi/c/parse_c_type.c b/contrib/python/cffi/c/parse_c_type.c index 698ef6451e..2a8df1905f 100644 --- a/contrib/python/cffi/c/parse_c_type.c +++ b/contrib/python/cffi/c/parse_c_type.c @@ -1,802 +1,802 @@ -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <errno.h> - -#define _CFFI_INTERNAL -#include "../cffi/parse_c_type.h" - - -enum token_e { - TOK_STAR='*', - TOK_OPEN_PAREN='(', - TOK_CLOSE_PAREN=')', - TOK_OPEN_BRACKET='[', - TOK_CLOSE_BRACKET=']', - TOK_COMMA=',', - - TOK_START=256, - TOK_END, - TOK_ERROR, - TOK_IDENTIFIER, - TOK_INTEGER, - TOK_DOTDOTDOT, - - /* keywords */ - TOK__BOOL, - TOK_CHAR, +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#define _CFFI_INTERNAL +#include "../cffi/parse_c_type.h" + + +enum token_e { + TOK_STAR='*', + TOK_OPEN_PAREN='(', + TOK_CLOSE_PAREN=')', + TOK_OPEN_BRACKET='[', + TOK_CLOSE_BRACKET=']', + TOK_COMMA=',', + + TOK_START=256, + TOK_END, + TOK_ERROR, + TOK_IDENTIFIER, + TOK_INTEGER, + TOK_DOTDOTDOT, + + /* keywords */ + TOK__BOOL, + TOK_CHAR, TOK__COMPLEX, - TOK_CONST, - TOK_DOUBLE, - TOK_ENUM, - TOK_FLOAT, - //TOK__IMAGINARY, - TOK_INT, - TOK_LONG, - TOK_SHORT, - TOK_SIGNED, - TOK_STRUCT, - TOK_UNION, - TOK_UNSIGNED, - TOK_VOID, - TOK_VOLATILE, - - TOK_CDECL, - TOK_STDCALL, -}; - -typedef struct { - struct _cffi_parse_info_s *info; - const char *input, *p; - size_t size; // the next token is at 'p' and of length 'size' - enum token_e kind; - _cffi_opcode_t *output; - size_t output_index; -} token_t; - -static int is_space(char x) -{ - return (x == ' ' || x == '\f' || x == '\n' || x == '\r' || - x == '\t' || x == '\v'); -} - -static int is_ident_first(char x) -{ - return (('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z') || x == '_' || - x == '$'); /* '$' in names is supported here, for the struct - names invented by cparser */ -} - -static int is_digit(char x) -{ - return ('0' <= x && x <= '9'); -} - -static int is_hex_digit(char x) -{ - return (('0' <= x && x <= '9') || - ('A' <= x && x <= 'F') || - ('a' <= x && x <= 'f')); -} - -static int is_ident_next(char x) -{ - return (is_ident_first(x) || is_digit(x)); -} - -static char get_following_char(token_t *tok) -{ - const char *p = tok->p + tok->size; - if (tok->kind == TOK_ERROR) - return 0; - while (is_space(*p)) - p++; - return *p; -} - -static int number_of_commas(token_t *tok) -{ - const char *p = tok->p; - int result = 0; - int nesting = 0; - while (1) { - switch (*p++) { - case ',': result += !nesting; break; - case '(': nesting++; break; - case ')': if ((--nesting) < 0) return result; break; - case 0: return result; - default: break; - } - } -} - -static void next_token(token_t *tok) -{ - const char *p = tok->p + tok->size; - if (tok->kind == TOK_ERROR) - return; - while (!is_ident_first(*p)) { - if (is_space(*p)) { - p++; - } - else if (is_digit(*p)) { - tok->kind = TOK_INTEGER; - tok->p = p; - tok->size = 1; - if (p[1] == 'x' || p[1] == 'X') - tok->size = 2; - while (is_hex_digit(p[tok->size])) - tok->size++; - return; - } - else if (p[0] == '.' && p[1] == '.' && p[2] == '.') { - tok->kind = TOK_DOTDOTDOT; - tok->p = p; - tok->size = 3; - return; - } - else if (*p) { - tok->kind = *p; - tok->p = p; - tok->size = 1; - return; - } - else { - tok->kind = TOK_END; - tok->p = p; - tok->size = 0; - return; - } - } - tok->kind = TOK_IDENTIFIER; - tok->p = p; - tok->size = 1; - while (is_ident_next(p[tok->size])) - tok->size++; - - switch (*p) { - case '_': - if (tok->size == 5 && !memcmp(p, "_Bool", 5)) tok->kind = TOK__BOOL; - if (tok->size == 7 && !memcmp(p,"__cdecl",7)) tok->kind = TOK_CDECL; - if (tok->size == 9 && !memcmp(p,"__stdcall",9))tok->kind = TOK_STDCALL; + TOK_CONST, + TOK_DOUBLE, + TOK_ENUM, + TOK_FLOAT, + //TOK__IMAGINARY, + TOK_INT, + TOK_LONG, + TOK_SHORT, + TOK_SIGNED, + TOK_STRUCT, + TOK_UNION, + TOK_UNSIGNED, + TOK_VOID, + TOK_VOLATILE, + + TOK_CDECL, + TOK_STDCALL, +}; + +typedef struct { + struct _cffi_parse_info_s *info; + const char *input, *p; + size_t size; // the next token is at 'p' and of length 'size' + enum token_e kind; + _cffi_opcode_t *output; + size_t output_index; +} token_t; + +static int is_space(char x) +{ + return (x == ' ' || x == '\f' || x == '\n' || x == '\r' || + x == '\t' || x == '\v'); +} + +static int is_ident_first(char x) +{ + return (('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z') || x == '_' || + x == '$'); /* '$' in names is supported here, for the struct + names invented by cparser */ +} + +static int is_digit(char x) +{ + return ('0' <= x && x <= '9'); +} + +static int is_hex_digit(char x) +{ + return (('0' <= x && x <= '9') || + ('A' <= x && x <= 'F') || + ('a' <= x && x <= 'f')); +} + +static int is_ident_next(char x) +{ + return (is_ident_first(x) || is_digit(x)); +} + +static char get_following_char(token_t *tok) +{ + const char *p = tok->p + tok->size; + if (tok->kind == TOK_ERROR) + return 0; + while (is_space(*p)) + p++; + return *p; +} + +static int number_of_commas(token_t *tok) +{ + const char *p = tok->p; + int result = 0; + int nesting = 0; + while (1) { + switch (*p++) { + case ',': result += !nesting; break; + case '(': nesting++; break; + case ')': if ((--nesting) < 0) return result; break; + case 0: return result; + default: break; + } + } +} + +static void next_token(token_t *tok) +{ + const char *p = tok->p + tok->size; + if (tok->kind == TOK_ERROR) + return; + while (!is_ident_first(*p)) { + if (is_space(*p)) { + p++; + } + else if (is_digit(*p)) { + tok->kind = TOK_INTEGER; + tok->p = p; + tok->size = 1; + if (p[1] == 'x' || p[1] == 'X') + tok->size = 2; + while (is_hex_digit(p[tok->size])) + tok->size++; + return; + } + else if (p[0] == '.' && p[1] == '.' && p[2] == '.') { + tok->kind = TOK_DOTDOTDOT; + tok->p = p; + tok->size = 3; + return; + } + else if (*p) { + tok->kind = *p; + tok->p = p; + tok->size = 1; + return; + } + else { + tok->kind = TOK_END; + tok->p = p; + tok->size = 0; + return; + } + } + tok->kind = TOK_IDENTIFIER; + tok->p = p; + tok->size = 1; + while (is_ident_next(p[tok->size])) + tok->size++; + + switch (*p) { + case '_': + if (tok->size == 5 && !memcmp(p, "_Bool", 5)) tok->kind = TOK__BOOL; + if (tok->size == 7 && !memcmp(p,"__cdecl",7)) tok->kind = TOK_CDECL; + if (tok->size == 9 && !memcmp(p,"__stdcall",9))tok->kind = TOK_STDCALL; if (tok->size == 8 && !memcmp(p,"_Complex",8)) tok->kind = TOK__COMPLEX; - break; - case 'c': - if (tok->size == 4 && !memcmp(p, "char", 4)) tok->kind = TOK_CHAR; - if (tok->size == 5 && !memcmp(p, "const", 5)) tok->kind = TOK_CONST; - break; - case 'd': - if (tok->size == 6 && !memcmp(p, "double", 6)) tok->kind = TOK_DOUBLE; - break; - case 'e': - if (tok->size == 4 && !memcmp(p, "enum", 4)) tok->kind = TOK_ENUM; - break; - case 'f': - if (tok->size == 5 && !memcmp(p, "float", 5)) tok->kind = TOK_FLOAT; - break; - case 'i': - if (tok->size == 3 && !memcmp(p, "int", 3)) tok->kind = TOK_INT; - break; - case 'l': - if (tok->size == 4 && !memcmp(p, "long", 4)) tok->kind = TOK_LONG; - break; - case 's': - if (tok->size == 5 && !memcmp(p, "short", 5)) tok->kind = TOK_SHORT; - if (tok->size == 6 && !memcmp(p, "signed", 6)) tok->kind = TOK_SIGNED; - if (tok->size == 6 && !memcmp(p, "struct", 6)) tok->kind = TOK_STRUCT; - break; - case 'u': - if (tok->size == 5 && !memcmp(p, "union", 5)) tok->kind = TOK_UNION; - if (tok->size == 8 && !memcmp(p,"unsigned",8)) tok->kind = TOK_UNSIGNED; - break; - case 'v': - if (tok->size == 4 && !memcmp(p, "void", 4)) tok->kind = TOK_VOID; - if (tok->size == 8 && !memcmp(p,"volatile",8)) tok->kind = TOK_VOLATILE; - break; - } -} - -static int parse_error(token_t *tok, const char *msg) -{ - if (tok->kind != TOK_ERROR) { - tok->kind = TOK_ERROR; - tok->info->error_location = tok->p - tok->input; - tok->info->error_message = msg; - } - return -1; -} - -static int write_ds(token_t *tok, _cffi_opcode_t ds) -{ - size_t index = tok->output_index; - if (index >= tok->info->output_size) { - parse_error(tok, "internal type complexity limit reached"); - return -1; - } - tok->output[index] = ds; - tok->output_index = index + 1; - return index; -} - -#define MAX_SSIZE_T (((size_t)-1) >> 1) - -static int parse_complete(token_t *tok); -static const char *get_common_type(const char *search, size_t search_len); -static int parse_common_type_replacement(token_t *tok, const char *replacement); - -static int parse_sequel(token_t *tok, int outer) -{ - /* Emit opcodes for the "sequel", which is the optional part of a - type declaration that follows the type name, i.e. everything - with '*', '[ ]', '( )'. Returns the entry point index pointing - the innermost opcode (the one that corresponds to the complete - type). The 'outer' argument is the index of the opcode outside - this "sequel". - */ - int check_for_grouping, abi=0; - _cffi_opcode_t result, *p_current; - - header: - switch (tok->kind) { - case TOK_STAR: - outer = write_ds(tok, _CFFI_OP(_CFFI_OP_POINTER, outer)); - next_token(tok); - goto header; - case TOK_CONST: - /* ignored for now */ - next_token(tok); - goto header; - case TOK_VOLATILE: - /* ignored for now */ - next_token(tok); - goto header; - case TOK_CDECL: - case TOK_STDCALL: - /* must be in a function; checked below */ - abi = tok->kind; - next_token(tok); - goto header; - default: - break; - } - - check_for_grouping = 1; - if (tok->kind == TOK_IDENTIFIER) { - next_token(tok); /* skip a potential variable name */ - check_for_grouping = 0; - } - - result = 0; - p_current = &result; - - while (tok->kind == TOK_OPEN_PAREN) { - next_token(tok); - - if (tok->kind == TOK_CDECL || tok->kind == TOK_STDCALL) { - abi = tok->kind; - next_token(tok); - } - - if ((check_for_grouping--) == 1 && (tok->kind == TOK_STAR || - tok->kind == TOK_CONST || - tok->kind == TOK_VOLATILE || - tok->kind == TOK_OPEN_BRACKET)) { - /* just parentheses for grouping. Use a OP_NOOP to simplify */ - int x; - assert(p_current == &result); - x = tok->output_index; - p_current = tok->output + x; - - write_ds(tok, _CFFI_OP(_CFFI_OP_NOOP, 0)); - - x = parse_sequel(tok, x); - result = _CFFI_OP(_CFFI_GETOP(0), x); - } - else { - /* function type */ - int arg_total, base_index, arg_next, flags=0; - - if (abi == TOK_STDCALL) { - flags = 2; - /* note that an ellipsis below will overwrite this flags, - which is the goal: variadic functions are always cdecl */ - } - abi = 0; - - if (tok->kind == TOK_VOID && get_following_char(tok) == ')') { - next_token(tok); - } - - /* (over-)estimate 'arg_total'. May return 1 when it is really 0 */ - arg_total = number_of_commas(tok) + 1; - - *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index); - p_current = tok->output + tok->output_index; - - base_index = write_ds(tok, _CFFI_OP(_CFFI_OP_FUNCTION, 0)); - if (base_index < 0) - return -1; - /* reserve (arg_total + 1) slots for the arguments and the - final FUNCTION_END */ - for (arg_next = 0; arg_next <= arg_total; arg_next++) - if (write_ds(tok, _CFFI_OP(0, 0)) < 0) - return -1; - - arg_next = base_index + 1; - - if (tok->kind != TOK_CLOSE_PAREN) { - while (1) { - int arg; - _cffi_opcode_t oarg; - - if (tok->kind == TOK_DOTDOTDOT) { - flags = 1; /* ellipsis */ - next_token(tok); - break; - } - arg = parse_complete(tok); - switch (_CFFI_GETOP(tok->output[arg])) { - case _CFFI_OP_ARRAY: - case _CFFI_OP_OPEN_ARRAY: - arg = _CFFI_GETARG(tok->output[arg]); - /* fall-through */ - case _CFFI_OP_FUNCTION: - oarg = _CFFI_OP(_CFFI_OP_POINTER, arg); - break; - default: - oarg = _CFFI_OP(_CFFI_OP_NOOP, arg); - break; - } - assert(arg_next - base_index <= arg_total); - tok->output[arg_next++] = oarg; - if (tok->kind != TOK_COMMA) - break; - next_token(tok); - } - } - tok->output[arg_next] = _CFFI_OP(_CFFI_OP_FUNCTION_END, flags); - } - - if (tok->kind != TOK_CLOSE_PAREN) - return parse_error(tok, "expected ')'"); - next_token(tok); - } - - if (abi != 0) - return parse_error(tok, "expected '('"); - - while (tok->kind == TOK_OPEN_BRACKET) { - *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index); - p_current = tok->output + tok->output_index; - - next_token(tok); - if (tok->kind != TOK_CLOSE_BRACKET) { - size_t length; - int gindex; - char *endptr; - - switch (tok->kind) { - - case TOK_INTEGER: - errno = 0; - if (sizeof(length) > sizeof(unsigned long)) { -#ifdef MS_WIN32 -# ifdef _WIN64 - length = _strtoui64(tok->p, &endptr, 0); -# else - abort(); /* unreachable */ -# endif -#else - length = strtoull(tok->p, &endptr, 0); -#endif - } - else - length = strtoul(tok->p, &endptr, 0); - if (endptr != tok->p + tok->size) - return parse_error(tok, "invalid number"); - if (errno == ERANGE || length > MAX_SSIZE_T) - return parse_error(tok, "number too large"); - break; - - case TOK_IDENTIFIER: - gindex = search_in_globals(tok->info->ctx, tok->p, tok->size); - if (gindex >= 0) { - const struct _cffi_global_s *g; - g = &tok->info->ctx->globals[gindex]; - if (_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT_INT || - _CFFI_GETOP(g->type_op) == _CFFI_OP_ENUM) { - int neg; - struct _cffi_getconst_s gc; - gc.ctx = tok->info->ctx; - gc.gindex = gindex; - neg = ((int(*)(struct _cffi_getconst_s*))g->address) - (&gc); - if (neg == 0 && gc.value > MAX_SSIZE_T) - return parse_error(tok, - "integer constant too large"); - if (neg == 0 || gc.value == 0) { - length = (size_t)gc.value; - break; - } - if (neg != 1) - return parse_error(tok, "disagreement about" - " this constant's value"); - } - } - /* fall-through to the default case */ - default: - return parse_error(tok, "expected a positive integer constant"); - } - - next_token(tok); - - write_ds(tok, _CFFI_OP(_CFFI_OP_ARRAY, 0)); - write_ds(tok, (_cffi_opcode_t)length); - } - else - write_ds(tok, _CFFI_OP(_CFFI_OP_OPEN_ARRAY, 0)); - - if (tok->kind != TOK_CLOSE_BRACKET) - return parse_error(tok, "expected ']'"); - next_token(tok); - } - - *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), outer); - return _CFFI_GETARG(result); -} - -static int search_sorted(const char *const *base, - size_t item_size, int array_len, - const char *search, size_t search_len) -{ - int left = 0, right = array_len; - const char *baseptr = (const char *)base; - - while (left < right) { - int middle = (left + right) / 2; - const char *src = *(const char *const *)(baseptr + middle * item_size); - int diff = strncmp(src, search, search_len); - if (diff == 0 && src[search_len] == '\0') - return middle; - else if (diff >= 0) - right = middle; - else - left = middle + 1; - } - return -1; -} - -#define MAKE_SEARCH_FUNC(FIELD) \ - static \ - int search_in_##FIELD(const struct _cffi_type_context_s *ctx, \ - const char *search, size_t search_len) \ - { \ - return search_sorted(&ctx->FIELD->name, sizeof(*ctx->FIELD), \ - ctx->num_##FIELD, search, search_len); \ - } - -MAKE_SEARCH_FUNC(globals) -MAKE_SEARCH_FUNC(struct_unions) -MAKE_SEARCH_FUNC(typenames) -MAKE_SEARCH_FUNC(enums) - -#undef MAKE_SEARCH_FUNC - - -static -int search_standard_typename(const char *p, size_t size) -{ - if (size < 6 || p[size-2] != '_' || p[size-1] != 't') - return -1; - - switch (p[4]) { - - case '1': - if (size == 8 && !memcmp(p, "uint16", 6)) return _CFFI_PRIM_UINT16; + break; + case 'c': + if (tok->size == 4 && !memcmp(p, "char", 4)) tok->kind = TOK_CHAR; + if (tok->size == 5 && !memcmp(p, "const", 5)) tok->kind = TOK_CONST; + break; + case 'd': + if (tok->size == 6 && !memcmp(p, "double", 6)) tok->kind = TOK_DOUBLE; + break; + case 'e': + if (tok->size == 4 && !memcmp(p, "enum", 4)) tok->kind = TOK_ENUM; + break; + case 'f': + if (tok->size == 5 && !memcmp(p, "float", 5)) tok->kind = TOK_FLOAT; + break; + case 'i': + if (tok->size == 3 && !memcmp(p, "int", 3)) tok->kind = TOK_INT; + break; + case 'l': + if (tok->size == 4 && !memcmp(p, "long", 4)) tok->kind = TOK_LONG; + break; + case 's': + if (tok->size == 5 && !memcmp(p, "short", 5)) tok->kind = TOK_SHORT; + if (tok->size == 6 && !memcmp(p, "signed", 6)) tok->kind = TOK_SIGNED; + if (tok->size == 6 && !memcmp(p, "struct", 6)) tok->kind = TOK_STRUCT; + break; + case 'u': + if (tok->size == 5 && !memcmp(p, "union", 5)) tok->kind = TOK_UNION; + if (tok->size == 8 && !memcmp(p,"unsigned",8)) tok->kind = TOK_UNSIGNED; + break; + case 'v': + if (tok->size == 4 && !memcmp(p, "void", 4)) tok->kind = TOK_VOID; + if (tok->size == 8 && !memcmp(p,"volatile",8)) tok->kind = TOK_VOLATILE; + break; + } +} + +static int parse_error(token_t *tok, const char *msg) +{ + if (tok->kind != TOK_ERROR) { + tok->kind = TOK_ERROR; + tok->info->error_location = tok->p - tok->input; + tok->info->error_message = msg; + } + return -1; +} + +static int write_ds(token_t *tok, _cffi_opcode_t ds) +{ + size_t index = tok->output_index; + if (index >= tok->info->output_size) { + parse_error(tok, "internal type complexity limit reached"); + return -1; + } + tok->output[index] = ds; + tok->output_index = index + 1; + return index; +} + +#define MAX_SSIZE_T (((size_t)-1) >> 1) + +static int parse_complete(token_t *tok); +static const char *get_common_type(const char *search, size_t search_len); +static int parse_common_type_replacement(token_t *tok, const char *replacement); + +static int parse_sequel(token_t *tok, int outer) +{ + /* Emit opcodes for the "sequel", which is the optional part of a + type declaration that follows the type name, i.e. everything + with '*', '[ ]', '( )'. Returns the entry point index pointing + the innermost opcode (the one that corresponds to the complete + type). The 'outer' argument is the index of the opcode outside + this "sequel". + */ + int check_for_grouping, abi=0; + _cffi_opcode_t result, *p_current; + + header: + switch (tok->kind) { + case TOK_STAR: + outer = write_ds(tok, _CFFI_OP(_CFFI_OP_POINTER, outer)); + next_token(tok); + goto header; + case TOK_CONST: + /* ignored for now */ + next_token(tok); + goto header; + case TOK_VOLATILE: + /* ignored for now */ + next_token(tok); + goto header; + case TOK_CDECL: + case TOK_STDCALL: + /* must be in a function; checked below */ + abi = tok->kind; + next_token(tok); + goto header; + default: + break; + } + + check_for_grouping = 1; + if (tok->kind == TOK_IDENTIFIER) { + next_token(tok); /* skip a potential variable name */ + check_for_grouping = 0; + } + + result = 0; + p_current = &result; + + while (tok->kind == TOK_OPEN_PAREN) { + next_token(tok); + + if (tok->kind == TOK_CDECL || tok->kind == TOK_STDCALL) { + abi = tok->kind; + next_token(tok); + } + + if ((check_for_grouping--) == 1 && (tok->kind == TOK_STAR || + tok->kind == TOK_CONST || + tok->kind == TOK_VOLATILE || + tok->kind == TOK_OPEN_BRACKET)) { + /* just parentheses for grouping. Use a OP_NOOP to simplify */ + int x; + assert(p_current == &result); + x = tok->output_index; + p_current = tok->output + x; + + write_ds(tok, _CFFI_OP(_CFFI_OP_NOOP, 0)); + + x = parse_sequel(tok, x); + result = _CFFI_OP(_CFFI_GETOP(0), x); + } + else { + /* function type */ + int arg_total, base_index, arg_next, flags=0; + + if (abi == TOK_STDCALL) { + flags = 2; + /* note that an ellipsis below will overwrite this flags, + which is the goal: variadic functions are always cdecl */ + } + abi = 0; + + if (tok->kind == TOK_VOID && get_following_char(tok) == ')') { + next_token(tok); + } + + /* (over-)estimate 'arg_total'. May return 1 when it is really 0 */ + arg_total = number_of_commas(tok) + 1; + + *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index); + p_current = tok->output + tok->output_index; + + base_index = write_ds(tok, _CFFI_OP(_CFFI_OP_FUNCTION, 0)); + if (base_index < 0) + return -1; + /* reserve (arg_total + 1) slots for the arguments and the + final FUNCTION_END */ + for (arg_next = 0; arg_next <= arg_total; arg_next++) + if (write_ds(tok, _CFFI_OP(0, 0)) < 0) + return -1; + + arg_next = base_index + 1; + + if (tok->kind != TOK_CLOSE_PAREN) { + while (1) { + int arg; + _cffi_opcode_t oarg; + + if (tok->kind == TOK_DOTDOTDOT) { + flags = 1; /* ellipsis */ + next_token(tok); + break; + } + arg = parse_complete(tok); + switch (_CFFI_GETOP(tok->output[arg])) { + case _CFFI_OP_ARRAY: + case _CFFI_OP_OPEN_ARRAY: + arg = _CFFI_GETARG(tok->output[arg]); + /* fall-through */ + case _CFFI_OP_FUNCTION: + oarg = _CFFI_OP(_CFFI_OP_POINTER, arg); + break; + default: + oarg = _CFFI_OP(_CFFI_OP_NOOP, arg); + break; + } + assert(arg_next - base_index <= arg_total); + tok->output[arg_next++] = oarg; + if (tok->kind != TOK_COMMA) + break; + next_token(tok); + } + } + tok->output[arg_next] = _CFFI_OP(_CFFI_OP_FUNCTION_END, flags); + } + + if (tok->kind != TOK_CLOSE_PAREN) + return parse_error(tok, "expected ')'"); + next_token(tok); + } + + if (abi != 0) + return parse_error(tok, "expected '('"); + + while (tok->kind == TOK_OPEN_BRACKET) { + *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index); + p_current = tok->output + tok->output_index; + + next_token(tok); + if (tok->kind != TOK_CLOSE_BRACKET) { + size_t length; + int gindex; + char *endptr; + + switch (tok->kind) { + + case TOK_INTEGER: + errno = 0; + if (sizeof(length) > sizeof(unsigned long)) { +#ifdef MS_WIN32 +# ifdef _WIN64 + length = _strtoui64(tok->p, &endptr, 0); +# else + abort(); /* unreachable */ +# endif +#else + length = strtoull(tok->p, &endptr, 0); +#endif + } + else + length = strtoul(tok->p, &endptr, 0); + if (endptr != tok->p + tok->size) + return parse_error(tok, "invalid number"); + if (errno == ERANGE || length > MAX_SSIZE_T) + return parse_error(tok, "number too large"); + break; + + case TOK_IDENTIFIER: + gindex = search_in_globals(tok->info->ctx, tok->p, tok->size); + if (gindex >= 0) { + const struct _cffi_global_s *g; + g = &tok->info->ctx->globals[gindex]; + if (_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT_INT || + _CFFI_GETOP(g->type_op) == _CFFI_OP_ENUM) { + int neg; + struct _cffi_getconst_s gc; + gc.ctx = tok->info->ctx; + gc.gindex = gindex; + neg = ((int(*)(struct _cffi_getconst_s*))g->address) + (&gc); + if (neg == 0 && gc.value > MAX_SSIZE_T) + return parse_error(tok, + "integer constant too large"); + if (neg == 0 || gc.value == 0) { + length = (size_t)gc.value; + break; + } + if (neg != 1) + return parse_error(tok, "disagreement about" + " this constant's value"); + } + } + /* fall-through to the default case */ + default: + return parse_error(tok, "expected a positive integer constant"); + } + + next_token(tok); + + write_ds(tok, _CFFI_OP(_CFFI_OP_ARRAY, 0)); + write_ds(tok, (_cffi_opcode_t)length); + } + else + write_ds(tok, _CFFI_OP(_CFFI_OP_OPEN_ARRAY, 0)); + + if (tok->kind != TOK_CLOSE_BRACKET) + return parse_error(tok, "expected ']'"); + next_token(tok); + } + + *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), outer); + return _CFFI_GETARG(result); +} + +static int search_sorted(const char *const *base, + size_t item_size, int array_len, + const char *search, size_t search_len) +{ + int left = 0, right = array_len; + const char *baseptr = (const char *)base; + + while (left < right) { + int middle = (left + right) / 2; + const char *src = *(const char *const *)(baseptr + middle * item_size); + int diff = strncmp(src, search, search_len); + if (diff == 0 && src[search_len] == '\0') + return middle; + else if (diff >= 0) + right = middle; + else + left = middle + 1; + } + return -1; +} + +#define MAKE_SEARCH_FUNC(FIELD) \ + static \ + int search_in_##FIELD(const struct _cffi_type_context_s *ctx, \ + const char *search, size_t search_len) \ + { \ + return search_sorted(&ctx->FIELD->name, sizeof(*ctx->FIELD), \ + ctx->num_##FIELD, search, search_len); \ + } + +MAKE_SEARCH_FUNC(globals) +MAKE_SEARCH_FUNC(struct_unions) +MAKE_SEARCH_FUNC(typenames) +MAKE_SEARCH_FUNC(enums) + +#undef MAKE_SEARCH_FUNC + + +static +int search_standard_typename(const char *p, size_t size) +{ + if (size < 6 || p[size-2] != '_' || p[size-1] != 't') + return -1; + + switch (p[4]) { + + case '1': + if (size == 8 && !memcmp(p, "uint16", 6)) return _CFFI_PRIM_UINT16; if (size == 8 && !memcmp(p, "char16", 6)) return _CFFI_PRIM_CHAR16; - break; - - case '2': - if (size == 7 && !memcmp(p, "int32", 5)) return _CFFI_PRIM_INT32; - break; - - case '3': - if (size == 8 && !memcmp(p, "uint32", 6)) return _CFFI_PRIM_UINT32; + break; + + case '2': + if (size == 7 && !memcmp(p, "int32", 5)) return _CFFI_PRIM_INT32; + break; + + case '3': + if (size == 8 && !memcmp(p, "uint32", 6)) return _CFFI_PRIM_UINT32; if (size == 8 && !memcmp(p, "char32", 6)) return _CFFI_PRIM_CHAR32; - break; - - case '4': - if (size == 7 && !memcmp(p, "int64", 5)) return _CFFI_PRIM_INT64; - break; - - case '6': - if (size == 8 && !memcmp(p, "uint64", 6)) return _CFFI_PRIM_UINT64; - if (size == 7 && !memcmp(p, "int16", 5)) return _CFFI_PRIM_INT16; - break; - - case '8': - if (size == 7 && !memcmp(p, "uint8", 5)) return _CFFI_PRIM_UINT8; - break; - - case 'a': - if (size == 8 && !memcmp(p, "intmax", 6)) return _CFFI_PRIM_INTMAX; - break; - - case 'e': - if (size == 7 && !memcmp(p, "ssize", 5)) return _CFFI_PRIM_SSIZE; - break; - - case 'f': - if (size == 11 && !memcmp(p, "int_fast8", 9)) return _CFFI_PRIM_INT_FAST8; - if (size == 12 && !memcmp(p, "int_fast16", 10)) return _CFFI_PRIM_INT_FAST16; - if (size == 12 && !memcmp(p, "int_fast32", 10)) return _CFFI_PRIM_INT_FAST32; - if (size == 12 && !memcmp(p, "int_fast64", 10)) return _CFFI_PRIM_INT_FAST64; - break; - - case 'i': - if (size == 9 && !memcmp(p, "ptrdiff", 7)) return _CFFI_PRIM_PTRDIFF; - break; - - case 'l': - if (size == 12 && !memcmp(p, "int_least8", 10)) return _CFFI_PRIM_INT_LEAST8; - if (size == 13 && !memcmp(p, "int_least16", 11)) return _CFFI_PRIM_INT_LEAST16; - if (size == 13 && !memcmp(p, "int_least32", 11)) return _CFFI_PRIM_INT_LEAST32; - if (size == 13 && !memcmp(p, "int_least64", 11)) return _CFFI_PRIM_INT_LEAST64; - break; - - case 'm': - if (size == 9 && !memcmp(p, "uintmax", 7)) return _CFFI_PRIM_UINTMAX; - break; - - case 'p': - if (size == 9 && !memcmp(p, "uintptr", 7)) return _CFFI_PRIM_UINTPTR; - break; - - case 'r': - if (size == 7 && !memcmp(p, "wchar", 5)) return _CFFI_PRIM_WCHAR; - break; - - case 't': - if (size == 8 && !memcmp(p, "intptr", 6)) return _CFFI_PRIM_INTPTR; - break; - - case '_': - if (size == 6 && !memcmp(p, "size", 4)) return _CFFI_PRIM_SIZE; - if (size == 6 && !memcmp(p, "int8", 4)) return _CFFI_PRIM_INT8; - if (size >= 12) { - switch (p[10]) { - case '1': - if (size == 14 && !memcmp(p, "uint_least16", 12)) return _CFFI_PRIM_UINT_LEAST16; - break; - case '2': - if (size == 13 && !memcmp(p, "uint_fast32", 11)) return _CFFI_PRIM_UINT_FAST32; - break; - case '3': - if (size == 14 && !memcmp(p, "uint_least32", 12)) return _CFFI_PRIM_UINT_LEAST32; - break; - case '4': - if (size == 13 && !memcmp(p, "uint_fast64", 11)) return _CFFI_PRIM_UINT_FAST64; - break; - case '6': - if (size == 14 && !memcmp(p, "uint_least64", 12)) return _CFFI_PRIM_UINT_LEAST64; - if (size == 13 && !memcmp(p, "uint_fast16", 11)) return _CFFI_PRIM_UINT_FAST16; - break; - case '8': - if (size == 13 && !memcmp(p, "uint_least8", 11)) return _CFFI_PRIM_UINT_LEAST8; - break; - case '_': - if (size == 12 && !memcmp(p, "uint_fast8", 10)) return _CFFI_PRIM_UINT_FAST8; - break; - default: - break; - } - } - break; - - default: - break; - } - return -1; -} - - -static int parse_complete(token_t *tok) -{ - unsigned int t0; - _cffi_opcode_t t1; + break; + + case '4': + if (size == 7 && !memcmp(p, "int64", 5)) return _CFFI_PRIM_INT64; + break; + + case '6': + if (size == 8 && !memcmp(p, "uint64", 6)) return _CFFI_PRIM_UINT64; + if (size == 7 && !memcmp(p, "int16", 5)) return _CFFI_PRIM_INT16; + break; + + case '8': + if (size == 7 && !memcmp(p, "uint8", 5)) return _CFFI_PRIM_UINT8; + break; + + case 'a': + if (size == 8 && !memcmp(p, "intmax", 6)) return _CFFI_PRIM_INTMAX; + break; + + case 'e': + if (size == 7 && !memcmp(p, "ssize", 5)) return _CFFI_PRIM_SSIZE; + break; + + case 'f': + if (size == 11 && !memcmp(p, "int_fast8", 9)) return _CFFI_PRIM_INT_FAST8; + if (size == 12 && !memcmp(p, "int_fast16", 10)) return _CFFI_PRIM_INT_FAST16; + if (size == 12 && !memcmp(p, "int_fast32", 10)) return _CFFI_PRIM_INT_FAST32; + if (size == 12 && !memcmp(p, "int_fast64", 10)) return _CFFI_PRIM_INT_FAST64; + break; + + case 'i': + if (size == 9 && !memcmp(p, "ptrdiff", 7)) return _CFFI_PRIM_PTRDIFF; + break; + + case 'l': + if (size == 12 && !memcmp(p, "int_least8", 10)) return _CFFI_PRIM_INT_LEAST8; + if (size == 13 && !memcmp(p, "int_least16", 11)) return _CFFI_PRIM_INT_LEAST16; + if (size == 13 && !memcmp(p, "int_least32", 11)) return _CFFI_PRIM_INT_LEAST32; + if (size == 13 && !memcmp(p, "int_least64", 11)) return _CFFI_PRIM_INT_LEAST64; + break; + + case 'm': + if (size == 9 && !memcmp(p, "uintmax", 7)) return _CFFI_PRIM_UINTMAX; + break; + + case 'p': + if (size == 9 && !memcmp(p, "uintptr", 7)) return _CFFI_PRIM_UINTPTR; + break; + + case 'r': + if (size == 7 && !memcmp(p, "wchar", 5)) return _CFFI_PRIM_WCHAR; + break; + + case 't': + if (size == 8 && !memcmp(p, "intptr", 6)) return _CFFI_PRIM_INTPTR; + break; + + case '_': + if (size == 6 && !memcmp(p, "size", 4)) return _CFFI_PRIM_SIZE; + if (size == 6 && !memcmp(p, "int8", 4)) return _CFFI_PRIM_INT8; + if (size >= 12) { + switch (p[10]) { + case '1': + if (size == 14 && !memcmp(p, "uint_least16", 12)) return _CFFI_PRIM_UINT_LEAST16; + break; + case '2': + if (size == 13 && !memcmp(p, "uint_fast32", 11)) return _CFFI_PRIM_UINT_FAST32; + break; + case '3': + if (size == 14 && !memcmp(p, "uint_least32", 12)) return _CFFI_PRIM_UINT_LEAST32; + break; + case '4': + if (size == 13 && !memcmp(p, "uint_fast64", 11)) return _CFFI_PRIM_UINT_FAST64; + break; + case '6': + if (size == 14 && !memcmp(p, "uint_least64", 12)) return _CFFI_PRIM_UINT_LEAST64; + if (size == 13 && !memcmp(p, "uint_fast16", 11)) return _CFFI_PRIM_UINT_FAST16; + break; + case '8': + if (size == 13 && !memcmp(p, "uint_least8", 11)) return _CFFI_PRIM_UINT_LEAST8; + break; + case '_': + if (size == 12 && !memcmp(p, "uint_fast8", 10)) return _CFFI_PRIM_UINT_FAST8; + break; + default: + break; + } + } + break; + + default: + break; + } + return -1; +} + + +static int parse_complete(token_t *tok) +{ + unsigned int t0; + _cffi_opcode_t t1; _cffi_opcode_t t1complex; - int modifiers_length, modifiers_sign; - - qualifiers: - switch (tok->kind) { - case TOK_CONST: - /* ignored for now */ - next_token(tok); - goto qualifiers; - case TOK_VOLATILE: - /* ignored for now */ - next_token(tok); - goto qualifiers; - default: - ; - } - - modifiers_length = 0; - modifiers_sign = 0; - modifiers: - switch (tok->kind) { - - case TOK_SHORT: - if (modifiers_length != 0) - return parse_error(tok, "'short' after another 'short' or 'long'"); - modifiers_length--; - next_token(tok); - goto modifiers; - - case TOK_LONG: - if (modifiers_length < 0) - return parse_error(tok, "'long' after 'short'"); - if (modifiers_length >= 2) - return parse_error(tok, "'long long long' is too long"); - modifiers_length++; - next_token(tok); - goto modifiers; - - case TOK_SIGNED: - if (modifiers_sign) - return parse_error(tok, "multiple 'signed' or 'unsigned'"); - modifiers_sign++; - next_token(tok); - goto modifiers; - - case TOK_UNSIGNED: - if (modifiers_sign) - return parse_error(tok, "multiple 'signed' or 'unsigned'"); - modifiers_sign--; - next_token(tok); - goto modifiers; - - default: - break; - } - + int modifiers_length, modifiers_sign; + + qualifiers: + switch (tok->kind) { + case TOK_CONST: + /* ignored for now */ + next_token(tok); + goto qualifiers; + case TOK_VOLATILE: + /* ignored for now */ + next_token(tok); + goto qualifiers; + default: + ; + } + + modifiers_length = 0; + modifiers_sign = 0; + modifiers: + switch (tok->kind) { + + case TOK_SHORT: + if (modifiers_length != 0) + return parse_error(tok, "'short' after another 'short' or 'long'"); + modifiers_length--; + next_token(tok); + goto modifiers; + + case TOK_LONG: + if (modifiers_length < 0) + return parse_error(tok, "'long' after 'short'"); + if (modifiers_length >= 2) + return parse_error(tok, "'long long long' is too long"); + modifiers_length++; + next_token(tok); + goto modifiers; + + case TOK_SIGNED: + if (modifiers_sign) + return parse_error(tok, "multiple 'signed' or 'unsigned'"); + modifiers_sign++; + next_token(tok); + goto modifiers; + + case TOK_UNSIGNED: + if (modifiers_sign) + return parse_error(tok, "multiple 'signed' or 'unsigned'"); + modifiers_sign--; + next_token(tok); + goto modifiers; + + default: + break; + } + t1complex = 0; - if (modifiers_length || modifiers_sign) { - - switch (tok->kind) { - - case TOK_VOID: - case TOK__BOOL: - case TOK_FLOAT: - case TOK_STRUCT: - case TOK_UNION: - case TOK_ENUM: + if (modifiers_length || modifiers_sign) { + + switch (tok->kind) { + + case TOK_VOID: + case TOK__BOOL: + case TOK_FLOAT: + case TOK_STRUCT: + case TOK_UNION: + case TOK_ENUM: case TOK__COMPLEX: - return parse_error(tok, "invalid combination of types"); - - case TOK_DOUBLE: - if (modifiers_sign != 0 || modifiers_length != 1) - return parse_error(tok, "invalid combination of types"); - next_token(tok); - t0 = _CFFI_PRIM_LONGDOUBLE; - break; - - case TOK_CHAR: - if (modifiers_length != 0) - return parse_error(tok, "invalid combination of types"); - modifiers_length = -2; - /* fall-through */ - case TOK_INT: - next_token(tok); - /* fall-through */ - default: - if (modifiers_sign >= 0) - switch (modifiers_length) { - case -2: t0 = _CFFI_PRIM_SCHAR; break; - case -1: t0 = _CFFI_PRIM_SHORT; break; - case 1: t0 = _CFFI_PRIM_LONG; break; - case 2: t0 = _CFFI_PRIM_LONGLONG; break; - default: t0 = _CFFI_PRIM_INT; break; - } - else - switch (modifiers_length) { - case -2: t0 = _CFFI_PRIM_UCHAR; break; - case -1: t0 = _CFFI_PRIM_USHORT; break; - case 1: t0 = _CFFI_PRIM_ULONG; break; - case 2: t0 = _CFFI_PRIM_ULONGLONG; break; - default: t0 = _CFFI_PRIM_UINT; break; - } - } - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, t0); - } - else { - switch (tok->kind) { - case TOK_INT: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_INT); - break; - case TOK_CHAR: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_CHAR); - break; - case TOK_VOID: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_VOID); - break; - case TOK__BOOL: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_BOOL); - break; - case TOK_FLOAT: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOAT); + return parse_error(tok, "invalid combination of types"); + + case TOK_DOUBLE: + if (modifiers_sign != 0 || modifiers_length != 1) + return parse_error(tok, "invalid combination of types"); + next_token(tok); + t0 = _CFFI_PRIM_LONGDOUBLE; + break; + + case TOK_CHAR: + if (modifiers_length != 0) + return parse_error(tok, "invalid combination of types"); + modifiers_length = -2; + /* fall-through */ + case TOK_INT: + next_token(tok); + /* fall-through */ + default: + if (modifiers_sign >= 0) + switch (modifiers_length) { + case -2: t0 = _CFFI_PRIM_SCHAR; break; + case -1: t0 = _CFFI_PRIM_SHORT; break; + case 1: t0 = _CFFI_PRIM_LONG; break; + case 2: t0 = _CFFI_PRIM_LONGLONG; break; + default: t0 = _CFFI_PRIM_INT; break; + } + else + switch (modifiers_length) { + case -2: t0 = _CFFI_PRIM_UCHAR; break; + case -1: t0 = _CFFI_PRIM_USHORT; break; + case 1: t0 = _CFFI_PRIM_ULONG; break; + case 2: t0 = _CFFI_PRIM_ULONGLONG; break; + default: t0 = _CFFI_PRIM_UINT; break; + } + } + t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, t0); + } + else { + switch (tok->kind) { + case TOK_INT: + t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_INT); + break; + case TOK_CHAR: + t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_CHAR); + break; + case TOK_VOID: + t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_VOID); + break; + case TOK__BOOL: + t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_BOOL); + break; + case TOK_FLOAT: + t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOAT); t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOATCOMPLEX); - break; - case TOK_DOUBLE: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLE); + break; + case TOK_DOUBLE: + t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLE); t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLECOMPLEX); - break; - case TOK_IDENTIFIER: - { - const char *replacement; - int n = search_in_typenames(tok->info->ctx, tok->p, tok->size); - if (n >= 0) { - t1 = _CFFI_OP(_CFFI_OP_TYPENAME, n); - break; - } - n = search_standard_typename(tok->p, tok->size); - if (n >= 0) { - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, n); - break; - } - replacement = get_common_type(tok->p, tok->size); - if (replacement != NULL) { - n = parse_common_type_replacement(tok, replacement); - if (n < 0) - return parse_error(tok, "internal error, please report!"); - t1 = _CFFI_OP(_CFFI_OP_NOOP, n); - break; - } - return parse_error(tok, "undefined type name"); - } - case TOK_STRUCT: - case TOK_UNION: - { - int n, kind = tok->kind; - next_token(tok); - if (tok->kind != TOK_IDENTIFIER) - return parse_error(tok, "struct or union name expected"); - - n = search_in_struct_unions(tok->info->ctx, tok->p, tok->size); - if (n < 0) { - if (kind == TOK_STRUCT && tok->size == 8 && - !memcmp(tok->p, "_IO_FILE", 8)) - n = _CFFI__IO_FILE_STRUCT; - else - return parse_error(tok, "undefined struct/union name"); - } - else if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION) - != 0) ^ (kind == TOK_UNION)) - return parse_error(tok, "wrong kind of tag: struct vs union"); - - t1 = _CFFI_OP(_CFFI_OP_STRUCT_UNION, n); - break; - } - case TOK_ENUM: - { - int n; - next_token(tok); - if (tok->kind != TOK_IDENTIFIER) - return parse_error(tok, "enum name expected"); - - n = search_in_enums(tok->info->ctx, tok->p, tok->size); - if (n < 0) - return parse_error(tok, "undefined enum name"); - - t1 = _CFFI_OP(_CFFI_OP_ENUM, n); - break; - } - default: - return parse_error(tok, "identifier expected"); - } - next_token(tok); - } + break; + case TOK_IDENTIFIER: + { + const char *replacement; + int n = search_in_typenames(tok->info->ctx, tok->p, tok->size); + if (n >= 0) { + t1 = _CFFI_OP(_CFFI_OP_TYPENAME, n); + break; + } + n = search_standard_typename(tok->p, tok->size); + if (n >= 0) { + t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, n); + break; + } + replacement = get_common_type(tok->p, tok->size); + if (replacement != NULL) { + n = parse_common_type_replacement(tok, replacement); + if (n < 0) + return parse_error(tok, "internal error, please report!"); + t1 = _CFFI_OP(_CFFI_OP_NOOP, n); + break; + } + return parse_error(tok, "undefined type name"); + } + case TOK_STRUCT: + case TOK_UNION: + { + int n, kind = tok->kind; + next_token(tok); + if (tok->kind != TOK_IDENTIFIER) + return parse_error(tok, "struct or union name expected"); + + n = search_in_struct_unions(tok->info->ctx, tok->p, tok->size); + if (n < 0) { + if (kind == TOK_STRUCT && tok->size == 8 && + !memcmp(tok->p, "_IO_FILE", 8)) + n = _CFFI__IO_FILE_STRUCT; + else + return parse_error(tok, "undefined struct/union name"); + } + else if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION) + != 0) ^ (kind == TOK_UNION)) + return parse_error(tok, "wrong kind of tag: struct vs union"); + + t1 = _CFFI_OP(_CFFI_OP_STRUCT_UNION, n); + break; + } + case TOK_ENUM: + { + int n; + next_token(tok); + if (tok->kind != TOK_IDENTIFIER) + return parse_error(tok, "enum name expected"); + + n = search_in_enums(tok->info->ctx, tok->p, tok->size); + if (n < 0) + return parse_error(tok, "undefined enum name"); + + t1 = _CFFI_OP(_CFFI_OP_ENUM, n); + break; + } + default: + return parse_error(tok, "identifier expected"); + } + next_token(tok); + } if (tok->kind == TOK__COMPLEX) { if (t1complex == 0) @@ -804,44 +804,44 @@ static int parse_complete(token_t *tok) t1 = t1complex; next_token(tok); } - - return parse_sequel(tok, write_ds(tok, t1)); -} - - -static -int parse_c_type_from(struct _cffi_parse_info_s *info, size_t *output_index, - const char *input) -{ - int result; - token_t token; - - token.info = info; - token.kind = TOK_START; - token.input = input; - token.p = input; - token.size = 0; - token.output = info->output; - token.output_index = *output_index; - - next_token(&token); - result = parse_complete(&token); - - *output_index = token.output_index; - if (token.kind != TOK_END) - return parse_error(&token, "unexpected symbol"); - return result; -} - -static -int parse_c_type(struct _cffi_parse_info_s *info, const char *input) -{ - size_t output_index = 0; - return parse_c_type_from(info, &output_index, input); -} - -static -int parse_common_type_replacement(token_t *tok, const char *replacement) -{ - return parse_c_type_from(tok->info, &tok->output_index, replacement); -} + + return parse_sequel(tok, write_ds(tok, t1)); +} + + +static +int parse_c_type_from(struct _cffi_parse_info_s *info, size_t *output_index, + const char *input) +{ + int result; + token_t token; + + token.info = info; + token.kind = TOK_START; + token.input = input; + token.p = input; + token.size = 0; + token.output = info->output; + token.output_index = *output_index; + + next_token(&token); + result = parse_complete(&token); + + *output_index = token.output_index; + if (token.kind != TOK_END) + return parse_error(&token, "unexpected symbol"); + return result; +} + +static +int parse_c_type(struct _cffi_parse_info_s *info, const char *input) +{ + size_t output_index = 0; + return parse_c_type_from(info, &output_index, input); +} + +static +int parse_common_type_replacement(token_t *tok, const char *replacement) +{ + return parse_c_type_from(tok->info, &tok->output_index, replacement); +} diff --git a/contrib/python/cffi/c/realize_c_type.c b/contrib/python/cffi/c/realize_c_type.c index 82629b7ef1..f7ccfba763 100644 --- a/contrib/python/cffi/c/realize_c_type.c +++ b/contrib/python/cffi/c/realize_c_type.c @@ -1,641 +1,641 @@ - -typedef struct { - struct _cffi_type_context_s ctx; /* inlined substructure */ - PyObject *types_dict; - PyObject *included_ffis; - PyObject *included_libs; - PyObject *_keepalive1; - PyObject *_keepalive2; -} builder_c_t; - - -static PyObject *all_primitives[_CFFI__NUM_PRIM]; -static CTypeDescrObject *g_ct_voidp, *g_ct_chararray; - -static PyObject *build_primitive_type(int num); /* forward */ - -#define primitive_in_range(num) ((num) >= 0 && (num) < _CFFI__NUM_PRIM) -#define get_primitive_type(num) \ - ((primitive_in_range(num) && all_primitives[num] != NULL) ? \ - all_primitives[num] : build_primitive_type(num)) - -static int init_global_types_dict(PyObject *ffi_type_dict) -{ - int err; - PyObject *ct_void, *ct_char, *ct2, *pnull; - /* XXX some leaks in case these functions fail, but well, - MemoryErrors during importing an extension module are kind - of bad anyway */ - - ct_void = get_primitive_type(_CFFI_PRIM_VOID); // 'void' - if (ct_void == NULL) - return -1; - - ct2 = new_pointer_type((CTypeDescrObject *)ct_void); // 'void *' - if (ct2 == NULL) - return -1; - g_ct_voidp = (CTypeDescrObject *)ct2; - - ct_char = get_primitive_type(_CFFI_PRIM_CHAR); // 'char' - if (ct_char == NULL) - return -1; - - ct2 = new_pointer_type((CTypeDescrObject *)ct_char); // 'char *' - if (ct2 == NULL) - return -1; - - ct2 = new_array_type((CTypeDescrObject *)ct2, -1); // 'char[]' - if (ct2 == NULL) - return -1; - g_ct_chararray = (CTypeDescrObject *)ct2; - - pnull = new_simple_cdata(NULL, g_ct_voidp); - if (pnull == NULL) - return -1; - err = PyDict_SetItemString(ffi_type_dict, "NULL", pnull); - Py_DECREF(pnull); - return err; -} - -static void free_builder_c(builder_c_t *builder, int ctx_is_static) -{ - if (!ctx_is_static) { - size_t i; - const void *mem[] = {builder->ctx.types, - builder->ctx.globals, - builder->ctx.struct_unions, - //builder->ctx.fields: allocated with struct_unions - builder->ctx.enums, - builder->ctx.typenames}; - for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) { - if (mem[i] != NULL) - PyMem_Free((void *)mem[i]); - } - } - Py_XDECREF(builder->included_ffis); - Py_XDECREF(builder->included_libs); - Py_XDECREF(builder->types_dict); - Py_XDECREF(builder->_keepalive1); - Py_XDECREF(builder->_keepalive2); -} - -static int init_builder_c(builder_c_t *builder, - const struct _cffi_type_context_s *ctx) -{ - PyObject *ldict = PyDict_New(); - if (ldict == NULL) - return -1; - - if (ctx) - builder->ctx = *ctx; - else - memset(&builder->ctx, 0, sizeof(builder->ctx)); - - builder->types_dict = ldict; - builder->included_ffis = NULL; - builder->included_libs = NULL; - builder->_keepalive1 = NULL; - builder->_keepalive2 = NULL; - return 0; -} - -static PyObject *build_primitive_type(int num) -{ - /* XXX too many translations between here and new_primitive_type() */ - static const char *primitive_name[] = { - NULL, - "_Bool", - "char", - "signed char", - "unsigned char", - "short", - "unsigned short", - "int", - "unsigned int", - "long", - "unsigned long", - "long long", - "unsigned long long", - "float", - "double", - "long double", - "wchar_t", - "int8_t", - "uint8_t", - "int16_t", - "uint16_t", - "int32_t", - "uint32_t", - "int64_t", - "uint64_t", - "intptr_t", - "uintptr_t", - "ptrdiff_t", - "size_t", - "ssize_t", - "int_least8_t", - "uint_least8_t", - "int_least16_t", - "uint_least16_t", - "int_least32_t", - "uint_least32_t", - "int_least64_t", - "uint_least64_t", - "int_fast8_t", - "uint_fast8_t", - "int_fast16_t", - "uint_fast16_t", - "int_fast32_t", - "uint_fast32_t", - "int_fast64_t", - "uint_fast64_t", - "intmax_t", - "uintmax_t", + +typedef struct { + struct _cffi_type_context_s ctx; /* inlined substructure */ + PyObject *types_dict; + PyObject *included_ffis; + PyObject *included_libs; + PyObject *_keepalive1; + PyObject *_keepalive2; +} builder_c_t; + + +static PyObject *all_primitives[_CFFI__NUM_PRIM]; +static CTypeDescrObject *g_ct_voidp, *g_ct_chararray; + +static PyObject *build_primitive_type(int num); /* forward */ + +#define primitive_in_range(num) ((num) >= 0 && (num) < _CFFI__NUM_PRIM) +#define get_primitive_type(num) \ + ((primitive_in_range(num) && all_primitives[num] != NULL) ? \ + all_primitives[num] : build_primitive_type(num)) + +static int init_global_types_dict(PyObject *ffi_type_dict) +{ + int err; + PyObject *ct_void, *ct_char, *ct2, *pnull; + /* XXX some leaks in case these functions fail, but well, + MemoryErrors during importing an extension module are kind + of bad anyway */ + + ct_void = get_primitive_type(_CFFI_PRIM_VOID); // 'void' + if (ct_void == NULL) + return -1; + + ct2 = new_pointer_type((CTypeDescrObject *)ct_void); // 'void *' + if (ct2 == NULL) + return -1; + g_ct_voidp = (CTypeDescrObject *)ct2; + + ct_char = get_primitive_type(_CFFI_PRIM_CHAR); // 'char' + if (ct_char == NULL) + return -1; + + ct2 = new_pointer_type((CTypeDescrObject *)ct_char); // 'char *' + if (ct2 == NULL) + return -1; + + ct2 = new_array_type((CTypeDescrObject *)ct2, -1); // 'char[]' + if (ct2 == NULL) + return -1; + g_ct_chararray = (CTypeDescrObject *)ct2; + + pnull = new_simple_cdata(NULL, g_ct_voidp); + if (pnull == NULL) + return -1; + err = PyDict_SetItemString(ffi_type_dict, "NULL", pnull); + Py_DECREF(pnull); + return err; +} + +static void free_builder_c(builder_c_t *builder, int ctx_is_static) +{ + if (!ctx_is_static) { + size_t i; + const void *mem[] = {builder->ctx.types, + builder->ctx.globals, + builder->ctx.struct_unions, + //builder->ctx.fields: allocated with struct_unions + builder->ctx.enums, + builder->ctx.typenames}; + for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) { + if (mem[i] != NULL) + PyMem_Free((void *)mem[i]); + } + } + Py_XDECREF(builder->included_ffis); + Py_XDECREF(builder->included_libs); + Py_XDECREF(builder->types_dict); + Py_XDECREF(builder->_keepalive1); + Py_XDECREF(builder->_keepalive2); +} + +static int init_builder_c(builder_c_t *builder, + const struct _cffi_type_context_s *ctx) +{ + PyObject *ldict = PyDict_New(); + if (ldict == NULL) + return -1; + + if (ctx) + builder->ctx = *ctx; + else + memset(&builder->ctx, 0, sizeof(builder->ctx)); + + builder->types_dict = ldict; + builder->included_ffis = NULL; + builder->included_libs = NULL; + builder->_keepalive1 = NULL; + builder->_keepalive2 = NULL; + return 0; +} + +static PyObject *build_primitive_type(int num) +{ + /* XXX too many translations between here and new_primitive_type() */ + static const char *primitive_name[] = { + NULL, + "_Bool", + "char", + "signed char", + "unsigned char", + "short", + "unsigned short", + "int", + "unsigned int", + "long", + "unsigned long", + "long long", + "unsigned long long", + "float", + "double", + "long double", + "wchar_t", + "int8_t", + "uint8_t", + "int16_t", + "uint16_t", + "int32_t", + "uint32_t", + "int64_t", + "uint64_t", + "intptr_t", + "uintptr_t", + "ptrdiff_t", + "size_t", + "ssize_t", + "int_least8_t", + "uint_least8_t", + "int_least16_t", + "uint_least16_t", + "int_least32_t", + "uint_least32_t", + "int_least64_t", + "uint_least64_t", + "int_fast8_t", + "uint_fast8_t", + "int_fast16_t", + "uint_fast16_t", + "int_fast32_t", + "uint_fast32_t", + "int_fast64_t", + "uint_fast64_t", + "intmax_t", + "uintmax_t", "float _Complex", "double _Complex", "char16_t", "char32_t", - }; - PyObject *x; - - assert(sizeof(primitive_name) == sizeof(*primitive_name) * _CFFI__NUM_PRIM); - if (num == _CFFI_PRIM_VOID) { - x = new_void_type(); - } - else if (primitive_in_range(num) && primitive_name[num] != NULL) { - x = new_primitive_type(primitive_name[num]); - } - else if (num == _CFFI__UNKNOWN_PRIM) { - PyErr_SetString(FFIError, "primitive integer type with an unexpected " - "size (or not an integer type at all)"); - return NULL; - } - else if (num == _CFFI__UNKNOWN_FLOAT_PRIM) { - PyErr_SetString(FFIError, "primitive floating-point type with an " - "unexpected size (or not a float type at all)"); - return NULL; - } - else if (num == _CFFI__UNKNOWN_LONG_DOUBLE) { - PyErr_SetString(FFIError, "primitive floating-point type is " - "'long double', not supported for now with " - "the syntax 'typedef double... xxx;'"); - return NULL; - } - else { - PyErr_Format(PyExc_NotImplementedError, "prim=%d", num); - return NULL; - } - - all_primitives[num] = x; - return x; -} - -static PyObject *realize_global_int(builder_c_t *builder, int gindex) -{ - int neg; - char got[64]; - unsigned long long value; - struct _cffi_getconst_s gc; - const struct _cffi_global_s *g = &builder->ctx.globals[gindex]; - gc.ctx = &builder->ctx; - gc.gindex = gindex; - /* note: we cast g->address to this function type; we do the same - in parse_c_type:parse_sequel() too. Note that the called function - may be declared simply with "unsigned long long *" as argument, - which is fine as it is the first field in _cffi_getconst_s. */ - assert(&gc.value == (unsigned long long *)&gc); - neg = ((int(*)(struct _cffi_getconst_s *))g->address)(&gc); - value = gc.value; - - switch (neg) { - - case 0: - if (value <= (unsigned long long)LONG_MAX) - return PyInt_FromLong((long)value); - else - return PyLong_FromUnsignedLongLong(value); - - case 1: - if ((long long)value >= (long long)LONG_MIN) - return PyInt_FromLong((long)value); - else - return PyLong_FromLongLong((long long)value); - - default: - break; - } - if (neg == 2) - sprintf(got, "%llu (0x%llx)", value, value); - else - sprintf(got, "%lld", (long long)value); - PyErr_Format(FFIError, "the C compiler says '%.200s' is equal to %s, " - "but the cdef disagrees", g->name, got); - return NULL; -} - -static CTypeDescrObject * -unwrap_fn_as_fnptr(PyObject *x) -{ - assert(PyTuple_Check(x)); - return (CTypeDescrObject *)PyTuple_GET_ITEM(x, 0); -} - -static CTypeDescrObject * -unexpected_fn_type(PyObject *x) -{ - CTypeDescrObject *ct = unwrap_fn_as_fnptr(x); - char *text1 = ct->ct_name; - char *text2 = text1 + ct->ct_name_position + 1; - assert(text2[-3] == '('); - text2[-3] = '\0'; - PyErr_Format(FFIError, "the type '%s%s' is a function type, not a " - "pointer-to-function type", text1, text2); - text2[-3] = '('; - return NULL; -} - -static PyObject * -realize_c_type_or_func(builder_c_t *builder, - _cffi_opcode_t opcodes[], int index); /* forward */ - - -/* Interpret an opcodes[] array. If opcodes == ctx->types, store all - the intermediate types back in the opcodes[]. Returns a new - reference. -*/ -static CTypeDescrObject * -realize_c_type(builder_c_t *builder, _cffi_opcode_t opcodes[], int index) -{ - PyObject *x = realize_c_type_or_func(builder, opcodes, index); - if (x == NULL || CTypeDescr_Check(x)) - return (CTypeDescrObject *)x; + }; + PyObject *x; + + assert(sizeof(primitive_name) == sizeof(*primitive_name) * _CFFI__NUM_PRIM); + if (num == _CFFI_PRIM_VOID) { + x = new_void_type(); + } + else if (primitive_in_range(num) && primitive_name[num] != NULL) { + x = new_primitive_type(primitive_name[num]); + } + else if (num == _CFFI__UNKNOWN_PRIM) { + PyErr_SetString(FFIError, "primitive integer type with an unexpected " + "size (or not an integer type at all)"); + return NULL; + } + else if (num == _CFFI__UNKNOWN_FLOAT_PRIM) { + PyErr_SetString(FFIError, "primitive floating-point type with an " + "unexpected size (or not a float type at all)"); + return NULL; + } + else if (num == _CFFI__UNKNOWN_LONG_DOUBLE) { + PyErr_SetString(FFIError, "primitive floating-point type is " + "'long double', not supported for now with " + "the syntax 'typedef double... xxx;'"); + return NULL; + } + else { + PyErr_Format(PyExc_NotImplementedError, "prim=%d", num); + return NULL; + } + + all_primitives[num] = x; + return x; +} + +static PyObject *realize_global_int(builder_c_t *builder, int gindex) +{ + int neg; + char got[64]; + unsigned long long value; + struct _cffi_getconst_s gc; + const struct _cffi_global_s *g = &builder->ctx.globals[gindex]; + gc.ctx = &builder->ctx; + gc.gindex = gindex; + /* note: we cast g->address to this function type; we do the same + in parse_c_type:parse_sequel() too. Note that the called function + may be declared simply with "unsigned long long *" as argument, + which is fine as it is the first field in _cffi_getconst_s. */ + assert(&gc.value == (unsigned long long *)&gc); + neg = ((int(*)(struct _cffi_getconst_s *))g->address)(&gc); + value = gc.value; + + switch (neg) { + + case 0: + if (value <= (unsigned long long)LONG_MAX) + return PyInt_FromLong((long)value); + else + return PyLong_FromUnsignedLongLong(value); + + case 1: + if ((long long)value >= (long long)LONG_MIN) + return PyInt_FromLong((long)value); + else + return PyLong_FromLongLong((long long)value); + + default: + break; + } + if (neg == 2) + sprintf(got, "%llu (0x%llx)", value, value); + else + sprintf(got, "%lld", (long long)value); + PyErr_Format(FFIError, "the C compiler says '%.200s' is equal to %s, " + "but the cdef disagrees", g->name, got); + return NULL; +} + +static CTypeDescrObject * +unwrap_fn_as_fnptr(PyObject *x) +{ + assert(PyTuple_Check(x)); + return (CTypeDescrObject *)PyTuple_GET_ITEM(x, 0); +} + +static CTypeDescrObject * +unexpected_fn_type(PyObject *x) +{ + CTypeDescrObject *ct = unwrap_fn_as_fnptr(x); + char *text1 = ct->ct_name; + char *text2 = text1 + ct->ct_name_position + 1; + assert(text2[-3] == '('); + text2[-3] = '\0'; + PyErr_Format(FFIError, "the type '%s%s' is a function type, not a " + "pointer-to-function type", text1, text2); + text2[-3] = '('; + return NULL; +} + +static PyObject * +realize_c_type_or_func(builder_c_t *builder, + _cffi_opcode_t opcodes[], int index); /* forward */ + + +/* Interpret an opcodes[] array. If opcodes == ctx->types, store all + the intermediate types back in the opcodes[]. Returns a new + reference. +*/ +static CTypeDescrObject * +realize_c_type(builder_c_t *builder, _cffi_opcode_t opcodes[], int index) +{ + PyObject *x = realize_c_type_or_func(builder, opcodes, index); + if (x == NULL || CTypeDescr_Check(x)) + return (CTypeDescrObject *)x; else { unexpected_fn_type(x); Py_DECREF(x); return NULL; } -} - -static void _realize_name(char *target, const char *prefix, const char *srcname) -{ - /* "xyz" => "struct xyz" - "$xyz" => "xyz" - "$1" => "struct $1" - */ - if (srcname[0] == '$' && srcname[1] != '$' && - !('0' <= srcname[1] && srcname[1] <= '9')) { - strcpy(target, &srcname[1]); - } - else { - strcpy(target, prefix); - strcat(target, srcname); - } -} - -static void _unrealize_name(char *target, const char *srcname) -{ - /* reverse of _realize_name() */ - if (strncmp(srcname, "struct ", 7) == 0) { - strcpy(target, &srcname[7]); - } - else if (strncmp(srcname, "union ", 6) == 0) { - strcpy(target, &srcname[6]); - } - else if (strncmp(srcname, "enum ", 5) == 0) { - strcpy(target, &srcname[5]); - } - else { - strcpy(target, "$"); - strcat(target, srcname); - } -} - -static PyObject * /* forward */ -_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, - PyObject *included_ffis, int recursion); - -static PyObject * -_realize_c_struct_or_union(builder_c_t *builder, int sindex) -{ - PyObject *x; - _cffi_opcode_t op2; - const struct _cffi_struct_union_s *s; - - if (sindex == _CFFI__IO_FILE_STRUCT) { - /* returns a single global cached opaque type */ - static PyObject *file_struct = NULL; - if (file_struct == NULL) - file_struct = new_struct_or_union_type("FILE", - CT_STRUCT | CT_IS_FILE); - Py_XINCREF(file_struct); - return file_struct; - } - - s = &builder->ctx.struct_unions[sindex]; - op2 = builder->ctx.types[s->type_index]; - if ((((uintptr_t)op2) & 1) == 0) { - x = (PyObject *)op2; /* found already in the "primary" slot */ - Py_INCREF(x); - } - else { - CTypeDescrObject *ct = NULL; - - if (!(s->flags & _CFFI_F_EXTERNAL)) { - int flags = (s->flags & _CFFI_F_UNION) ? CT_UNION : CT_STRUCT; - char *name = alloca(8 + strlen(s->name)); - _realize_name(name, - (s->flags & _CFFI_F_UNION) ? "union " : "struct ", - s->name); - if (strcmp(name, "struct _IO_FILE") == 0) - x = _realize_c_struct_or_union(builder, _CFFI__IO_FILE_STRUCT); - else - x = new_struct_or_union_type(name, flags); - if (x == NULL) - return NULL; - - if (!(s->flags & _CFFI_F_OPAQUE)) { - assert(s->first_field_index >= 0); - ct = (CTypeDescrObject *)x; - ct->ct_size = (Py_ssize_t)s->size; - ct->ct_length = s->alignment; /* may be -1 */ - ct->ct_flags &= ~CT_IS_OPAQUE; - ct->ct_flags |= CT_LAZY_FIELD_LIST; - ct->ct_extra = builder; - } - else - assert(s->first_field_index < 0); - } - else { - assert(s->first_field_index < 0); - x = _fetch_external_struct_or_union(s, builder->included_ffis, 0); - if (x == NULL) { - if (!PyErr_Occurred()) - PyErr_Format(FFIError, "'%s %.200s' should come from " - "ffi.include() but was not found", - (s->flags & _CFFI_F_UNION) ? "union" - : "struct", s->name); - return NULL; - } - if (!(s->flags & _CFFI_F_OPAQUE)) { - if (((CTypeDescrObject *)x)->ct_flags & CT_IS_OPAQUE) { - const char *prefix = (s->flags & _CFFI_F_UNION) ? "union" - : "struct"; - PyErr_Format(PyExc_NotImplementedError, - "'%s %.200s' is opaque in the ffi.include(), " - "but no longer in the ffi doing the include " - "(workaround: don't use ffi.include() but " - "duplicate the declarations of everything " - "using %s %.200s)", - prefix, s->name, prefix, s->name); - Py_DECREF(x); - return NULL; - } - } - } - - /* Update the "primary" OP_STRUCT_UNION slot */ - assert((((uintptr_t)x) & 1) == 0); - assert(builder->ctx.types[s->type_index] == op2); - Py_INCREF(x); - builder->ctx.types[s->type_index] = x; - - if (ct != NULL && s->size == (size_t)-2) { - /* oops, this struct is unnamed and we couldn't generate - a C expression to get its size. We have to rely on - complete_struct_or_union() to compute it now. */ - if (do_realize_lazy_struct(ct) < 0) { - builder->ctx.types[s->type_index] = op2; - return NULL; - } - } - } - return x; -} - -static PyObject * +} + +static void _realize_name(char *target, const char *prefix, const char *srcname) +{ + /* "xyz" => "struct xyz" + "$xyz" => "xyz" + "$1" => "struct $1" + */ + if (srcname[0] == '$' && srcname[1] != '$' && + !('0' <= srcname[1] && srcname[1] <= '9')) { + strcpy(target, &srcname[1]); + } + else { + strcpy(target, prefix); + strcat(target, srcname); + } +} + +static void _unrealize_name(char *target, const char *srcname) +{ + /* reverse of _realize_name() */ + if (strncmp(srcname, "struct ", 7) == 0) { + strcpy(target, &srcname[7]); + } + else if (strncmp(srcname, "union ", 6) == 0) { + strcpy(target, &srcname[6]); + } + else if (strncmp(srcname, "enum ", 5) == 0) { + strcpy(target, &srcname[5]); + } + else { + strcpy(target, "$"); + strcat(target, srcname); + } +} + +static PyObject * /* forward */ +_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, + PyObject *included_ffis, int recursion); + +static PyObject * +_realize_c_struct_or_union(builder_c_t *builder, int sindex) +{ + PyObject *x; + _cffi_opcode_t op2; + const struct _cffi_struct_union_s *s; + + if (sindex == _CFFI__IO_FILE_STRUCT) { + /* returns a single global cached opaque type */ + static PyObject *file_struct = NULL; + if (file_struct == NULL) + file_struct = new_struct_or_union_type("FILE", + CT_STRUCT | CT_IS_FILE); + Py_XINCREF(file_struct); + return file_struct; + } + + s = &builder->ctx.struct_unions[sindex]; + op2 = builder->ctx.types[s->type_index]; + if ((((uintptr_t)op2) & 1) == 0) { + x = (PyObject *)op2; /* found already in the "primary" slot */ + Py_INCREF(x); + } + else { + CTypeDescrObject *ct = NULL; + + if (!(s->flags & _CFFI_F_EXTERNAL)) { + int flags = (s->flags & _CFFI_F_UNION) ? CT_UNION : CT_STRUCT; + char *name = alloca(8 + strlen(s->name)); + _realize_name(name, + (s->flags & _CFFI_F_UNION) ? "union " : "struct ", + s->name); + if (strcmp(name, "struct _IO_FILE") == 0) + x = _realize_c_struct_or_union(builder, _CFFI__IO_FILE_STRUCT); + else + x = new_struct_or_union_type(name, flags); + if (x == NULL) + return NULL; + + if (!(s->flags & _CFFI_F_OPAQUE)) { + assert(s->first_field_index >= 0); + ct = (CTypeDescrObject *)x; + ct->ct_size = (Py_ssize_t)s->size; + ct->ct_length = s->alignment; /* may be -1 */ + ct->ct_flags &= ~CT_IS_OPAQUE; + ct->ct_flags |= CT_LAZY_FIELD_LIST; + ct->ct_extra = builder; + } + else + assert(s->first_field_index < 0); + } + else { + assert(s->first_field_index < 0); + x = _fetch_external_struct_or_union(s, builder->included_ffis, 0); + if (x == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(FFIError, "'%s %.200s' should come from " + "ffi.include() but was not found", + (s->flags & _CFFI_F_UNION) ? "union" + : "struct", s->name); + return NULL; + } + if (!(s->flags & _CFFI_F_OPAQUE)) { + if (((CTypeDescrObject *)x)->ct_flags & CT_IS_OPAQUE) { + const char *prefix = (s->flags & _CFFI_F_UNION) ? "union" + : "struct"; + PyErr_Format(PyExc_NotImplementedError, + "'%s %.200s' is opaque in the ffi.include(), " + "but no longer in the ffi doing the include " + "(workaround: don't use ffi.include() but " + "duplicate the declarations of everything " + "using %s %.200s)", + prefix, s->name, prefix, s->name); + Py_DECREF(x); + return NULL; + } + } + } + + /* Update the "primary" OP_STRUCT_UNION slot */ + assert((((uintptr_t)x) & 1) == 0); + assert(builder->ctx.types[s->type_index] == op2); + Py_INCREF(x); + builder->ctx.types[s->type_index] = x; + + if (ct != NULL && s->size == (size_t)-2) { + /* oops, this struct is unnamed and we couldn't generate + a C expression to get its size. We have to rely on + complete_struct_or_union() to compute it now. */ + if (do_realize_lazy_struct(ct) < 0) { + builder->ctx.types[s->type_index] = op2; + return NULL; + } + } + } + return x; +} + +static PyObject * realize_c_type_or_func_now(builder_c_t *builder, _cffi_opcode_t op, _cffi_opcode_t opcodes[], int index) -{ - PyObject *x, *y, *z; - Py_ssize_t length = -1; - - switch (_CFFI_GETOP(op)) { - - case _CFFI_OP_PRIMITIVE: - x = get_primitive_type(_CFFI_GETARG(op)); - Py_XINCREF(x); - break; - - case _CFFI_OP_POINTER: - y = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op)); - if (y == NULL) - return NULL; - if (CTypeDescr_Check(y)) { - x = new_pointer_type((CTypeDescrObject *)y); - } - else { - assert(PyTuple_Check(y)); /* from _CFFI_OP_FUNCTION */ - x = PyTuple_GET_ITEM(y, 0); - Py_INCREF(x); - } - Py_DECREF(y); - break; - - case _CFFI_OP_ARRAY: - length = (Py_ssize_t)opcodes[index + 1]; - /* fall-through */ - case _CFFI_OP_OPEN_ARRAY: - y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op)); - if (y == NULL) - return NULL; - z = new_pointer_type((CTypeDescrObject *)y); - Py_DECREF(y); - if (z == NULL) - return NULL; - x = new_array_type((CTypeDescrObject *)z, length); - Py_DECREF(z); - break; - - case _CFFI_OP_STRUCT_UNION: - x = _realize_c_struct_or_union(builder, _CFFI_GETARG(op)); - break; - - case _CFFI_OP_ENUM: - { - const struct _cffi_enum_s *e; - _cffi_opcode_t op2; - - e = &builder->ctx.enums[_CFFI_GETARG(op)]; - op2 = builder->ctx.types[e->type_index]; - if ((((uintptr_t)op2) & 1) == 0) { - x = (PyObject *)op2; - Py_INCREF(x); - } - else { - PyObject *enumerators = NULL, *enumvalues = NULL, *tmp; - Py_ssize_t i, j, n = 0; - const char *p; - int gindex; - PyObject *args; - PyObject *basetd = get_primitive_type(e->type_prim); - if (basetd == NULL) - return NULL; - - if (*e->enumerators != '\0') { - n++; - for (p = e->enumerators; *p != '\0'; p++) - n += (*p == ','); - } - enumerators = PyTuple_New(n); - if (enumerators == NULL) - return NULL; - - enumvalues = PyTuple_New(n); - if (enumvalues == NULL) { - Py_DECREF(enumerators); - return NULL; - } - - p = e->enumerators; - for (i = 0; i < n; i++) { - j = 0; - while (p[j] != ',' && p[j] != '\0') - j++; - tmp = PyText_FromStringAndSize(p, j); - if (tmp == NULL) - break; - PyTuple_SET_ITEM(enumerators, i, tmp); - - gindex = search_in_globals(&builder->ctx, p, j); - assert(gindex >= 0); - assert(builder->ctx.globals[gindex].type_op == - _CFFI_OP(_CFFI_OP_ENUM, -1)); - - tmp = realize_global_int(builder, gindex); - if (tmp == NULL) - break; - PyTuple_SET_ITEM(enumvalues, i, tmp); - - p += j + 1; - } - - args = NULL; - if (!PyErr_Occurred()) { - char *name = alloca(6 + strlen(e->name)); - _realize_name(name, "enum ", e->name); - args = Py_BuildValue("(sOOO)", name, enumerators, - enumvalues, basetd); - } - Py_DECREF(enumerators); - Py_DECREF(enumvalues); - if (args == NULL) - return NULL; - - x = b_new_enum_type(NULL, args); - Py_DECREF(args); - if (x == NULL) - return NULL; - - /* Update the "primary" _CFFI_OP_ENUM slot, which - may be the same or a different slot than the "current" one */ - assert((((uintptr_t)x) & 1) == 0); - assert(builder->ctx.types[e->type_index] == op2); - Py_INCREF(x); - builder->ctx.types[e->type_index] = x; - - /* Done, leave without updating the "current" slot because - it may be done already above. If not, never mind, the - next call to realize_c_type() will do it. */ - return x; - } - break; - } - - case _CFFI_OP_FUNCTION: - { - PyObject *fargs; - int i, base_index, num_args, ellipsis, abi; - - y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op)); - if (y == NULL) - return NULL; - - base_index = index + 1; - num_args = 0; - /* note that if the arguments are already built, they have a - pointer in the 'opcodes' array, and GETOP() returns a - random even value. But OP_FUNCTION_END is odd, so the - condition below still works correctly. */ - while (_CFFI_GETOP(opcodes[base_index + num_args]) != - _CFFI_OP_FUNCTION_END) - num_args++; - - ellipsis = _CFFI_GETARG(opcodes[base_index + num_args]) & 0x01; - abi = _CFFI_GETARG(opcodes[base_index + num_args]) & 0xFE; - switch (abi) { - case 0: - abi = FFI_DEFAULT_ABI; - break; - case 2: -#if defined(MS_WIN32) && !defined(_WIN64) - abi = FFI_STDCALL; -#else - abi = FFI_DEFAULT_ABI; -#endif - break; - default: - PyErr_Format(FFIError, "abi number %d not supported", abi); - Py_DECREF(y); - return NULL; - } - - fargs = PyTuple_New(num_args); - if (fargs == NULL) { - Py_DECREF(y); - return NULL; - } - - for (i = 0; i < num_args; i++) { - z = (PyObject *)realize_c_type(builder, opcodes, base_index + i); - if (z == NULL) { - Py_DECREF(fargs); - Py_DECREF(y); - return NULL; - } - PyTuple_SET_ITEM(fargs, i, z); - } - - z = new_function_type(fargs, (CTypeDescrObject *)y, ellipsis, abi); - Py_DECREF(fargs); - Py_DECREF(y); - if (z == NULL) - return NULL; - - x = PyTuple_Pack(1, z); /* hack: hide the CT_FUNCTIONPTR. it will - be revealed again by the OP_POINTER */ - Py_DECREF(z); - break; - } - - case _CFFI_OP_NOOP: - x = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op)); - break; - - case _CFFI_OP_TYPENAME: - { - /* essential: the TYPENAME opcode resolves the type index looked - up in the 'ctx->typenames' array, but it does so in 'ctx->types' - instead of in 'opcodes'! */ - int type_index = builder->ctx.typenames[_CFFI_GETARG(op)].type_index; - x = realize_c_type_or_func(builder, builder->ctx.types, type_index); - break; - } - - default: - PyErr_Format(PyExc_NotImplementedError, "op=%d", (int)_CFFI_GETOP(op)); - return NULL; - } - +{ + PyObject *x, *y, *z; + Py_ssize_t length = -1; + + switch (_CFFI_GETOP(op)) { + + case _CFFI_OP_PRIMITIVE: + x = get_primitive_type(_CFFI_GETARG(op)); + Py_XINCREF(x); + break; + + case _CFFI_OP_POINTER: + y = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op)); + if (y == NULL) + return NULL; + if (CTypeDescr_Check(y)) { + x = new_pointer_type((CTypeDescrObject *)y); + } + else { + assert(PyTuple_Check(y)); /* from _CFFI_OP_FUNCTION */ + x = PyTuple_GET_ITEM(y, 0); + Py_INCREF(x); + } + Py_DECREF(y); + break; + + case _CFFI_OP_ARRAY: + length = (Py_ssize_t)opcodes[index + 1]; + /* fall-through */ + case _CFFI_OP_OPEN_ARRAY: + y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op)); + if (y == NULL) + return NULL; + z = new_pointer_type((CTypeDescrObject *)y); + Py_DECREF(y); + if (z == NULL) + return NULL; + x = new_array_type((CTypeDescrObject *)z, length); + Py_DECREF(z); + break; + + case _CFFI_OP_STRUCT_UNION: + x = _realize_c_struct_or_union(builder, _CFFI_GETARG(op)); + break; + + case _CFFI_OP_ENUM: + { + const struct _cffi_enum_s *e; + _cffi_opcode_t op2; + + e = &builder->ctx.enums[_CFFI_GETARG(op)]; + op2 = builder->ctx.types[e->type_index]; + if ((((uintptr_t)op2) & 1) == 0) { + x = (PyObject *)op2; + Py_INCREF(x); + } + else { + PyObject *enumerators = NULL, *enumvalues = NULL, *tmp; + Py_ssize_t i, j, n = 0; + const char *p; + int gindex; + PyObject *args; + PyObject *basetd = get_primitive_type(e->type_prim); + if (basetd == NULL) + return NULL; + + if (*e->enumerators != '\0') { + n++; + for (p = e->enumerators; *p != '\0'; p++) + n += (*p == ','); + } + enumerators = PyTuple_New(n); + if (enumerators == NULL) + return NULL; + + enumvalues = PyTuple_New(n); + if (enumvalues == NULL) { + Py_DECREF(enumerators); + return NULL; + } + + p = e->enumerators; + for (i = 0; i < n; i++) { + j = 0; + while (p[j] != ',' && p[j] != '\0') + j++; + tmp = PyText_FromStringAndSize(p, j); + if (tmp == NULL) + break; + PyTuple_SET_ITEM(enumerators, i, tmp); + + gindex = search_in_globals(&builder->ctx, p, j); + assert(gindex >= 0); + assert(builder->ctx.globals[gindex].type_op == + _CFFI_OP(_CFFI_OP_ENUM, -1)); + + tmp = realize_global_int(builder, gindex); + if (tmp == NULL) + break; + PyTuple_SET_ITEM(enumvalues, i, tmp); + + p += j + 1; + } + + args = NULL; + if (!PyErr_Occurred()) { + char *name = alloca(6 + strlen(e->name)); + _realize_name(name, "enum ", e->name); + args = Py_BuildValue("(sOOO)", name, enumerators, + enumvalues, basetd); + } + Py_DECREF(enumerators); + Py_DECREF(enumvalues); + if (args == NULL) + return NULL; + + x = b_new_enum_type(NULL, args); + Py_DECREF(args); + if (x == NULL) + return NULL; + + /* Update the "primary" _CFFI_OP_ENUM slot, which + may be the same or a different slot than the "current" one */ + assert((((uintptr_t)x) & 1) == 0); + assert(builder->ctx.types[e->type_index] == op2); + Py_INCREF(x); + builder->ctx.types[e->type_index] = x; + + /* Done, leave without updating the "current" slot because + it may be done already above. If not, never mind, the + next call to realize_c_type() will do it. */ + return x; + } + break; + } + + case _CFFI_OP_FUNCTION: + { + PyObject *fargs; + int i, base_index, num_args, ellipsis, abi; + + y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op)); + if (y == NULL) + return NULL; + + base_index = index + 1; + num_args = 0; + /* note that if the arguments are already built, they have a + pointer in the 'opcodes' array, and GETOP() returns a + random even value. But OP_FUNCTION_END is odd, so the + condition below still works correctly. */ + while (_CFFI_GETOP(opcodes[base_index + num_args]) != + _CFFI_OP_FUNCTION_END) + num_args++; + + ellipsis = _CFFI_GETARG(opcodes[base_index + num_args]) & 0x01; + abi = _CFFI_GETARG(opcodes[base_index + num_args]) & 0xFE; + switch (abi) { + case 0: + abi = FFI_DEFAULT_ABI; + break; + case 2: +#if defined(MS_WIN32) && !defined(_WIN64) + abi = FFI_STDCALL; +#else + abi = FFI_DEFAULT_ABI; +#endif + break; + default: + PyErr_Format(FFIError, "abi number %d not supported", abi); + Py_DECREF(y); + return NULL; + } + + fargs = PyTuple_New(num_args); + if (fargs == NULL) { + Py_DECREF(y); + return NULL; + } + + for (i = 0; i < num_args; i++) { + z = (PyObject *)realize_c_type(builder, opcodes, base_index + i); + if (z == NULL) { + Py_DECREF(fargs); + Py_DECREF(y); + return NULL; + } + PyTuple_SET_ITEM(fargs, i, z); + } + + z = new_function_type(fargs, (CTypeDescrObject *)y, ellipsis, abi); + Py_DECREF(fargs); + Py_DECREF(y); + if (z == NULL) + return NULL; + + x = PyTuple_Pack(1, z); /* hack: hide the CT_FUNCTIONPTR. it will + be revealed again by the OP_POINTER */ + Py_DECREF(z); + break; + } + + case _CFFI_OP_NOOP: + x = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op)); + break; + + case _CFFI_OP_TYPENAME: + { + /* essential: the TYPENAME opcode resolves the type index looked + up in the 'ctx->typenames' array, but it does so in 'ctx->types' + instead of in 'opcodes'! */ + int type_index = builder->ctx.typenames[_CFFI_GETARG(op)].type_index; + x = realize_c_type_or_func(builder, builder->ctx.types, type_index); + break; + } + + default: + PyErr_Format(PyExc_NotImplementedError, "op=%d", (int)_CFFI_GETOP(op)); + return NULL; + } + return x; } @@ -666,155 +666,155 @@ realize_c_type_or_func(builder_c_t *builder, x = realize_c_type_or_func_now(builder, op, opcodes, index); _realize_recursion_level--; - if (x != NULL && opcodes == builder->ctx.types && opcodes[index] != x) { - assert((((uintptr_t)x) & 1) == 0); - assert((((uintptr_t)opcodes[index]) & 1) == 1); - Py_INCREF(x); - opcodes[index] = x; - } - return x; -} - -static CTypeDescrObject * -realize_c_func_return_type(builder_c_t *builder, - _cffi_opcode_t opcodes[], int index) -{ - PyObject *x; - _cffi_opcode_t op = opcodes[index]; - - if ((((uintptr_t)op) & 1) == 0) { - /* already built: assert that it is a function and fish - for the return type */ - x = (PyObject *)op; - assert(PyTuple_Check(x)); /* from _CFFI_OP_FUNCTION */ - x = PyTuple_GET_ITEM(x, 0); - assert(CTypeDescr_Check(x)); - assert(((CTypeDescrObject *)x)->ct_flags & CT_FUNCTIONPTR); - x = PyTuple_GET_ITEM(((CTypeDescrObject *)x)->ct_stuff, 1); - assert(CTypeDescr_Check(x)); - Py_INCREF(x); - return (CTypeDescrObject *)x; - } - else { - assert(_CFFI_GETOP(op) == _CFFI_OP_FUNCTION); - return realize_c_type(builder, opcodes, _CFFI_GETARG(opcodes[index])); - } + if (x != NULL && opcodes == builder->ctx.types && opcodes[index] != x) { + assert((((uintptr_t)x) & 1) == 0); + assert((((uintptr_t)opcodes[index]) & 1) == 1); + Py_INCREF(x); + opcodes[index] = x; + } + return x; } - -static int do_realize_lazy_struct(CTypeDescrObject *ct) -{ - /* This is called by force_lazy_struct() in _cffi_backend.c */ - assert(ct->ct_flags & (CT_STRUCT | CT_UNION)); - - if (ct->ct_flags & CT_LAZY_FIELD_LIST) { - builder_c_t *builder; - char *p; - int n, i, sflags; - const struct _cffi_struct_union_s *s; - const struct _cffi_field_s *fld; - PyObject *fields, *args, *res; - - assert(!(ct->ct_flags & CT_IS_OPAQUE)); - - builder = ct->ct_extra; - assert(builder != NULL); - - p = alloca(2 + strlen(ct->ct_name)); - _unrealize_name(p, ct->ct_name); - - n = search_in_struct_unions(&builder->ctx, p, strlen(p)); - if (n < 0) - Py_FatalError("lost a struct/union!"); - - s = &builder->ctx.struct_unions[n]; - fld = &builder->ctx.fields[s->first_field_index]; - - /* XXX painfully build all the Python objects that are the args - to b_complete_struct_or_union() */ - - fields = PyList_New(s->num_fields); - if (fields == NULL) - return -1; - - for (i = 0; i < s->num_fields; i++, fld++) { - _cffi_opcode_t op = fld->field_type_op; - int fbitsize = -1; - PyObject *f; - CTypeDescrObject *ctf; - - switch (_CFFI_GETOP(op)) { - - case _CFFI_OP_BITFIELD: - assert(fld->field_size >= 0); - fbitsize = (int)fld->field_size; - /* fall-through */ - case _CFFI_OP_NOOP: - ctf = realize_c_type(builder, builder->ctx.types, - _CFFI_GETARG(op)); - break; - - default: - Py_DECREF(fields); - PyErr_Format(PyExc_NotImplementedError, "field op=%d", - (int)_CFFI_GETOP(op)); - return -1; - } - + +static CTypeDescrObject * +realize_c_func_return_type(builder_c_t *builder, + _cffi_opcode_t opcodes[], int index) +{ + PyObject *x; + _cffi_opcode_t op = opcodes[index]; + + if ((((uintptr_t)op) & 1) == 0) { + /* already built: assert that it is a function and fish + for the return type */ + x = (PyObject *)op; + assert(PyTuple_Check(x)); /* from _CFFI_OP_FUNCTION */ + x = PyTuple_GET_ITEM(x, 0); + assert(CTypeDescr_Check(x)); + assert(((CTypeDescrObject *)x)->ct_flags & CT_FUNCTIONPTR); + x = PyTuple_GET_ITEM(((CTypeDescrObject *)x)->ct_stuff, 1); + assert(CTypeDescr_Check(x)); + Py_INCREF(x); + return (CTypeDescrObject *)x; + } + else { + assert(_CFFI_GETOP(op) == _CFFI_OP_FUNCTION); + return realize_c_type(builder, opcodes, _CFFI_GETARG(opcodes[index])); + } +} + +static int do_realize_lazy_struct(CTypeDescrObject *ct) +{ + /* This is called by force_lazy_struct() in _cffi_backend.c */ + assert(ct->ct_flags & (CT_STRUCT | CT_UNION)); + + if (ct->ct_flags & CT_LAZY_FIELD_LIST) { + builder_c_t *builder; + char *p; + int n, i, sflags; + const struct _cffi_struct_union_s *s; + const struct _cffi_field_s *fld; + PyObject *fields, *args, *res; + + assert(!(ct->ct_flags & CT_IS_OPAQUE)); + + builder = ct->ct_extra; + assert(builder != NULL); + + p = alloca(2 + strlen(ct->ct_name)); + _unrealize_name(p, ct->ct_name); + + n = search_in_struct_unions(&builder->ctx, p, strlen(p)); + if (n < 0) + Py_FatalError("lost a struct/union!"); + + s = &builder->ctx.struct_unions[n]; + fld = &builder->ctx.fields[s->first_field_index]; + + /* XXX painfully build all the Python objects that are the args + to b_complete_struct_or_union() */ + + fields = PyList_New(s->num_fields); + if (fields == NULL) + return -1; + + for (i = 0; i < s->num_fields; i++, fld++) { + _cffi_opcode_t op = fld->field_type_op; + int fbitsize = -1; + PyObject *f; + CTypeDescrObject *ctf; + + switch (_CFFI_GETOP(op)) { + + case _CFFI_OP_BITFIELD: + assert(fld->field_size >= 0); + fbitsize = (int)fld->field_size; + /* fall-through */ + case _CFFI_OP_NOOP: + ctf = realize_c_type(builder, builder->ctx.types, + _CFFI_GETARG(op)); + break; + + default: + Py_DECREF(fields); + PyErr_Format(PyExc_NotImplementedError, "field op=%d", + (int)_CFFI_GETOP(op)); + return -1; + } + if (ctf != NULL && fld->field_offset == (size_t)-1) { - /* unnamed struct, with field positions and sizes entirely - determined by complete_struct_or_union() and not checked. - Or, bitfields (field_size >= 0), similarly not checked. */ - assert(fld->field_size == (size_t)-1 || fbitsize >= 0); - } + /* unnamed struct, with field positions and sizes entirely + determined by complete_struct_or_union() and not checked. + Or, bitfields (field_size >= 0), similarly not checked. */ + assert(fld->field_size == (size_t)-1 || fbitsize >= 0); + } else if (ctf == NULL || detect_custom_layout(ct, SF_STD_FIELD_POS, - ctf->ct_size, fld->field_size, - "wrong size for field '", - fld->name, "'") < 0) { - Py_DECREF(fields); - return -1; - } - - f = Py_BuildValue("(sOin)", fld->name, ctf, - fbitsize, (Py_ssize_t)fld->field_offset); - if (f == NULL) { - Py_DECREF(fields); - return -1; - } - PyList_SET_ITEM(fields, i, f); - } - - sflags = 0; - if (s->flags & _CFFI_F_CHECK_FIELDS) - sflags |= SF_STD_FIELD_POS; - if (s->flags & _CFFI_F_PACKED) - sflags |= SF_PACKED; - - args = Py_BuildValue("(OOOnii)", ct, fields, Py_None, - (Py_ssize_t)s->size, - s->alignment, - sflags); - Py_DECREF(fields); - if (args == NULL) - return -1; - - ct->ct_extra = NULL; - ct->ct_flags |= CT_IS_OPAQUE; - res = b_complete_struct_or_union(NULL, args); - ct->ct_flags &= ~CT_IS_OPAQUE; - Py_DECREF(args); - - if (res == NULL) { - ct->ct_extra = builder; - return -1; - } - - assert(ct->ct_stuff != NULL); - ct->ct_flags &= ~CT_LAZY_FIELD_LIST; - Py_DECREF(res); - return 1; - } - else { - assert(ct->ct_flags & CT_IS_OPAQUE); - return 0; - } -} + ctf->ct_size, fld->field_size, + "wrong size for field '", + fld->name, "'") < 0) { + Py_DECREF(fields); + return -1; + } + + f = Py_BuildValue("(sOin)", fld->name, ctf, + fbitsize, (Py_ssize_t)fld->field_offset); + if (f == NULL) { + Py_DECREF(fields); + return -1; + } + PyList_SET_ITEM(fields, i, f); + } + + sflags = 0; + if (s->flags & _CFFI_F_CHECK_FIELDS) + sflags |= SF_STD_FIELD_POS; + if (s->flags & _CFFI_F_PACKED) + sflags |= SF_PACKED; + + args = Py_BuildValue("(OOOnii)", ct, fields, Py_None, + (Py_ssize_t)s->size, + s->alignment, + sflags); + Py_DECREF(fields); + if (args == NULL) + return -1; + + ct->ct_extra = NULL; + ct->ct_flags |= CT_IS_OPAQUE; + res = b_complete_struct_or_union(NULL, args); + ct->ct_flags &= ~CT_IS_OPAQUE; + Py_DECREF(args); + + if (res == NULL) { + ct->ct_extra = builder; + return -1; + } + + assert(ct->ct_stuff != NULL); + ct->ct_flags &= ~CT_LAZY_FIELD_LIST; + Py_DECREF(res); + return 1; + } + else { + assert(ct->ct_flags & CT_IS_OPAQUE); + return 0; + } +} diff --git a/contrib/python/cffi/c/test_c.py b/contrib/python/cffi/c/test_c.py index 654584d924..04f91d6937 100644 --- a/contrib/python/cffi/c/test_c.py +++ b/contrib/python/cffi/c/test_c.py @@ -1,11 +1,11 @@ -import py +import py import pytest -def _setup_path(): - import os, sys - sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) -_setup_path() -from _cffi_backend import * +def _setup_path(): + import os, sys + sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) +_setup_path() +from _cffi_backend import * from _cffi_backend import _get_types, _get_common_types try: from _cffi_backend import _testfunc @@ -13,219 +13,219 @@ except ImportError: def _testfunc(num): pytest.skip("_testunc() not available") from _cffi_backend import __version__ - -# ____________________________________________________________ - -import sys + +# ____________________________________________________________ + +import sys assert __version__ == "1.15.0", ("This test_c.py file is for testing a version" " of cffi that differs from the one that we" " get from 'import _cffi_backend'") -if sys.version_info < (3,): - type_or_class = "type" - mandatory_b_prefix = '' - mandatory_u_prefix = 'u' - bytechr = chr - bitem2bchr = lambda x: x - class U(object): - def __add__(self, other): - return eval('u'+repr(other).replace(r'\\u', r'\u') - .replace(r'\\U', r'\U')) - u = U() - str2bytes = str +if sys.version_info < (3,): + type_or_class = "type" + mandatory_b_prefix = '' + mandatory_u_prefix = 'u' + bytechr = chr + bitem2bchr = lambda x: x + class U(object): + def __add__(self, other): + return eval('u'+repr(other).replace(r'\\u', r'\u') + .replace(r'\\U', r'\U')) + u = U() + str2bytes = str strict_compare = False -else: - type_or_class = "class" - long = int - unicode = str - unichr = chr - mandatory_b_prefix = 'b' - mandatory_u_prefix = '' - bytechr = lambda n: bytes([n]) - bitem2bchr = bytechr - u = "" - str2bytes = lambda s: bytes(s, "ascii") +else: + type_or_class = "class" + long = int + unicode = str + unichr = chr + mandatory_b_prefix = 'b' + mandatory_u_prefix = '' + bytechr = lambda n: bytes([n]) + bitem2bchr = bytechr + u = "" + str2bytes = lambda s: bytes(s, "ascii") strict_compare = True - -def size_of_int(): - BInt = new_primitive_type("int") - return sizeof(BInt) - -def size_of_long(): - BLong = new_primitive_type("long") - return sizeof(BLong) - -def size_of_ptr(): - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - return sizeof(BPtr) - - -def find_and_load_library(name, flags=RTLD_NOW): - import ctypes.util - if name is None: - path = None - else: - path = ctypes.util.find_library(name) + +def size_of_int(): + BInt = new_primitive_type("int") + return sizeof(BInt) + +def size_of_long(): + BLong = new_primitive_type("long") + return sizeof(BLong) + +def size_of_ptr(): + BInt = new_primitive_type("int") + BPtr = new_pointer_type(BInt) + return sizeof(BPtr) + + +def find_and_load_library(name, flags=RTLD_NOW): + import ctypes.util + if name is None: + path = None + else: + path = ctypes.util.find_library(name) if path is None and name == 'c': assert sys.platform == 'win32' assert (sys.version_info >= (3,) or '__pypy__' in sys.builtin_module_names) py.test.skip("dlopen(None) cannot work on Windows " "with PyPy or Python 3") - return load_library(path, flags) - -def test_load_library(): - x = find_and_load_library('c') - assert repr(x).startswith("<clibrary '") - x = find_and_load_library('c', RTLD_NOW | RTLD_GLOBAL) - assert repr(x).startswith("<clibrary '") - x = find_and_load_library('c', RTLD_LAZY) - assert repr(x).startswith("<clibrary '") - -def test_all_rtld_symbols(): - import sys - FFI_DEFAULT_ABI # these symbols must be defined - FFI_CDECL - RTLD_LAZY - RTLD_NOW - RTLD_GLOBAL - RTLD_LOCAL - if sys.platform.startswith("linux"): - RTLD_NODELETE - RTLD_NOLOAD - RTLD_DEEPBIND - -def test_new_primitive_type(): - py.test.raises(KeyError, new_primitive_type, "foo") - p = new_primitive_type("signed char") - assert repr(p) == "<ctype 'signed char'>" - -def check_dir(p, expected): - got = [name for name in dir(p) if not name.startswith('_')] - assert got == sorted(expected) - -def test_inspect_primitive_type(): - p = new_primitive_type("signed char") - assert p.kind == "primitive" - assert p.cname == "signed char" - check_dir(p, ['cname', 'kind']) - -def test_cast_to_signed_char(): - p = new_primitive_type("signed char") - x = cast(p, -65 + 17*256) - assert repr(x) == "<cdata 'signed char' -65>" + return load_library(path, flags) + +def test_load_library(): + x = find_and_load_library('c') + assert repr(x).startswith("<clibrary '") + x = find_and_load_library('c', RTLD_NOW | RTLD_GLOBAL) + assert repr(x).startswith("<clibrary '") + x = find_and_load_library('c', RTLD_LAZY) + assert repr(x).startswith("<clibrary '") + +def test_all_rtld_symbols(): + import sys + FFI_DEFAULT_ABI # these symbols must be defined + FFI_CDECL + RTLD_LAZY + RTLD_NOW + RTLD_GLOBAL + RTLD_LOCAL + if sys.platform.startswith("linux"): + RTLD_NODELETE + RTLD_NOLOAD + RTLD_DEEPBIND + +def test_new_primitive_type(): + py.test.raises(KeyError, new_primitive_type, "foo") + p = new_primitive_type("signed char") + assert repr(p) == "<ctype 'signed char'>" + +def check_dir(p, expected): + got = [name for name in dir(p) if not name.startswith('_')] + assert got == sorted(expected) + +def test_inspect_primitive_type(): + p = new_primitive_type("signed char") + assert p.kind == "primitive" + assert p.cname == "signed char" + check_dir(p, ['cname', 'kind']) + +def test_cast_to_signed_char(): + p = new_primitive_type("signed char") + x = cast(p, -65 + 17*256) + assert repr(x) == "<cdata 'signed char' -65>" assert repr(type(x)) == "<%s '_cffi_backend._CDataBase'>" % type_or_class - assert int(x) == -65 - x = cast(p, -66 + (1<<199)*256) - assert repr(x) == "<cdata 'signed char' -66>" - assert int(x) == -66 + assert int(x) == -65 + x = cast(p, -66 + (1<<199)*256) + assert repr(x) == "<cdata 'signed char' -66>" + assert int(x) == -66 assert (x == cast(p, -66)) is True assert (x != cast(p, -66)) is False - q = new_primitive_type("short") + q = new_primitive_type("short") assert (x == cast(q, -66)) is True assert (x != cast(q, -66)) is False - -def test_sizeof_type(): - py.test.raises(TypeError, sizeof, 42.5) - p = new_primitive_type("short") - assert sizeof(p) == 2 - -def test_integer_types(): - for name in ['signed char', 'short', 'int', 'long', 'long long']: - p = new_primitive_type(name) - size = sizeof(p) - min = -(1 << (8*size-1)) - max = (1 << (8*size-1)) - 1 - assert int(cast(p, min)) == min - assert int(cast(p, max)) == max - assert int(cast(p, min - 1)) == max - assert int(cast(p, max + 1)) == min - py.test.raises(TypeError, cast, p, None) - assert long(cast(p, min - 1)) == max - assert int(cast(p, b'\x08')) == 8 - assert int(cast(p, u+'\x08')) == 8 - for name in ['char', 'short', 'int', 'long', 'long long']: - p = new_primitive_type('unsigned ' + name) - size = sizeof(p) - max = (1 << (8*size)) - 1 - assert int(cast(p, 0)) == 0 - assert int(cast(p, max)) == max - assert int(cast(p, -1)) == max - assert int(cast(p, max + 1)) == 0 - assert long(cast(p, -1)) == max - assert int(cast(p, b'\xFE')) == 254 - assert int(cast(p, u+'\xFE')) == 254 - -def test_no_float_on_int_types(): - p = new_primitive_type('long') - py.test.raises(TypeError, float, cast(p, 42)) - py.test.raises(TypeError, complex, cast(p, 42)) - -def test_float_types(): - INF = 1E200 * 1E200 - for name in ["float", "double"]: - p = new_primitive_type(name) - assert bool(cast(p, 0)) is False # since 1.7 - assert bool(cast(p, -0.0)) is False # since 1.7 - assert bool(cast(p, 1e-42)) is True - assert bool(cast(p, -1e-42)) is True - assert bool(cast(p, INF)) - assert bool(cast(p, -INF)) - assert bool(cast(p, float("nan"))) - assert int(cast(p, -150)) == -150 - assert int(cast(p, 61.91)) == 61 - assert long(cast(p, 61.91)) == 61 - assert type(int(cast(p, 61.91))) is int - assert type(int(cast(p, 1E22))) is long - assert type(long(cast(p, 61.91))) is long - assert type(long(cast(p, 1E22))) is long - py.test.raises(OverflowError, int, cast(p, INF)) - py.test.raises(OverflowError, int, cast(p, -INF)) - assert float(cast(p, 1.25)) == 1.25 - assert float(cast(p, INF)) == INF - assert float(cast(p, -INF)) == -INF - if name == "float": - assert float(cast(p, 1.1)) != 1.1 # rounding error - assert float(cast(p, 1E200)) == INF # limited range - + +def test_sizeof_type(): + py.test.raises(TypeError, sizeof, 42.5) + p = new_primitive_type("short") + assert sizeof(p) == 2 + +def test_integer_types(): + for name in ['signed char', 'short', 'int', 'long', 'long long']: + p = new_primitive_type(name) + size = sizeof(p) + min = -(1 << (8*size-1)) + max = (1 << (8*size-1)) - 1 + assert int(cast(p, min)) == min + assert int(cast(p, max)) == max + assert int(cast(p, min - 1)) == max + assert int(cast(p, max + 1)) == min + py.test.raises(TypeError, cast, p, None) + assert long(cast(p, min - 1)) == max + assert int(cast(p, b'\x08')) == 8 + assert int(cast(p, u+'\x08')) == 8 + for name in ['char', 'short', 'int', 'long', 'long long']: + p = new_primitive_type('unsigned ' + name) + size = sizeof(p) + max = (1 << (8*size)) - 1 + assert int(cast(p, 0)) == 0 + assert int(cast(p, max)) == max + assert int(cast(p, -1)) == max + assert int(cast(p, max + 1)) == 0 + assert long(cast(p, -1)) == max + assert int(cast(p, b'\xFE')) == 254 + assert int(cast(p, u+'\xFE')) == 254 + +def test_no_float_on_int_types(): + p = new_primitive_type('long') + py.test.raises(TypeError, float, cast(p, 42)) + py.test.raises(TypeError, complex, cast(p, 42)) + +def test_float_types(): + INF = 1E200 * 1E200 + for name in ["float", "double"]: + p = new_primitive_type(name) + assert bool(cast(p, 0)) is False # since 1.7 + assert bool(cast(p, -0.0)) is False # since 1.7 + assert bool(cast(p, 1e-42)) is True + assert bool(cast(p, -1e-42)) is True + assert bool(cast(p, INF)) + assert bool(cast(p, -INF)) + assert bool(cast(p, float("nan"))) + assert int(cast(p, -150)) == -150 + assert int(cast(p, 61.91)) == 61 + assert long(cast(p, 61.91)) == 61 + assert type(int(cast(p, 61.91))) is int + assert type(int(cast(p, 1E22))) is long + assert type(long(cast(p, 61.91))) is long + assert type(long(cast(p, 1E22))) is long + py.test.raises(OverflowError, int, cast(p, INF)) + py.test.raises(OverflowError, int, cast(p, -INF)) + assert float(cast(p, 1.25)) == 1.25 + assert float(cast(p, INF)) == INF + assert float(cast(p, -INF)) == -INF + if name == "float": + assert float(cast(p, 1.1)) != 1.1 # rounding error + assert float(cast(p, 1E200)) == INF # limited range + assert cast(p, -1.1) == cast(p, -1.1) - assert repr(float(cast(p, -0.0))) == '-0.0' - assert float(cast(p, b'\x09')) == 9.0 - assert float(cast(p, u+'\x09')) == 9.0 - assert float(cast(p, True)) == 1.0 - py.test.raises(TypeError, cast, p, None) - -def test_complex_types(): - INF = 1E200 * 1E200 - for name in ["float", "double"]: + assert repr(float(cast(p, -0.0))) == '-0.0' + assert float(cast(p, b'\x09')) == 9.0 + assert float(cast(p, u+'\x09')) == 9.0 + assert float(cast(p, True)) == 1.0 + py.test.raises(TypeError, cast, p, None) + +def test_complex_types(): + INF = 1E200 * 1E200 + for name in ["float", "double"]: p = new_primitive_type(name + " _Complex") assert bool(cast(p, 0)) is False - assert bool(cast(p, INF)) - assert bool(cast(p, -INF)) + assert bool(cast(p, INF)) + assert bool(cast(p, -INF)) assert bool(cast(p, 0j)) is False - assert bool(cast(p, INF*1j)) - assert bool(cast(p, -INF*1j)) + assert bool(cast(p, INF*1j)) + assert bool(cast(p, -INF*1j)) # "can't convert complex to float", like CPython's "float(0j)" - py.test.raises(TypeError, int, cast(p, -150)) - py.test.raises(TypeError, long, cast(p, -150)) - py.test.raises(TypeError, float, cast(p, -150)) - assert complex(cast(p, 1.25)) == 1.25 - assert complex(cast(p, 1.25j)) == 1.25j + py.test.raises(TypeError, int, cast(p, -150)) + py.test.raises(TypeError, long, cast(p, -150)) + py.test.raises(TypeError, float, cast(p, -150)) + assert complex(cast(p, 1.25)) == 1.25 + assert complex(cast(p, 1.25j)) == 1.25j assert complex(cast(p, complex(0,INF))) == complex(0,INF) assert complex(cast(p, -INF)) == -INF - if name == "float": - assert complex(cast(p, 1.1j)) != 1.1j # rounding error - assert complex(cast(p, 1E200+3j)) == INF+3j # limited range + if name == "float": + assert complex(cast(p, 1.1j)) != 1.1j # rounding error + assert complex(cast(p, 1E200+3j)) == INF+3j # limited range assert complex(cast(p, complex(3,1E200))) == complex(3,INF) # limited range - + assert cast(p, -1.1j) == cast(p, -1.1j) - assert repr(complex(cast(p, -0.0)).real) == '-0.0' + assert repr(complex(cast(p, -0.0)).real) == '-0.0' #assert repr(complex(cast(p, -0j))) == '-0j' # http://bugs.python.org/issue29602 assert complex(cast(p, b'\x09')) == 9.0 + 0j assert complex(cast(p, u+'\x09')) == 9.0 + 0j assert complex(cast(p, True)) == 1.0 + 0j - py.test.raises(TypeError, cast, p, None) - # + py.test.raises(TypeError, cast, p, None) + # py.test.raises(TypeError, cast, new_primitive_type(name), 1+0j) # for basetype in ["char", "int", "uint64_t", "float", @@ -246,331 +246,331 @@ def test_complex_types(): assert complex(Foo()) == 2 + 3j assert complex(cast(p, Foo())) == 2 + 3j py.test.raises(TypeError, cast, new_primitive_type("int"), 1+0j) - -def test_character_type(): - p = new_primitive_type("char") - assert bool(cast(p, 'A')) is True - assert bool(cast(p, '\x00')) is False # since 1.7 + +def test_character_type(): + p = new_primitive_type("char") + assert bool(cast(p, 'A')) is True + assert bool(cast(p, '\x00')) is False # since 1.7 assert cast(p, '\x00') == cast(p, -17*256) - assert int(cast(p, 'A')) == 65 - assert long(cast(p, 'A')) == 65 - assert type(int(cast(p, 'A'))) is int - assert type(long(cast(p, 'A'))) is long - assert str(cast(p, 'A')) == repr(cast(p, 'A')) - assert repr(cast(p, 'A')) == "<cdata 'char' %s'A'>" % mandatory_b_prefix - assert repr(cast(p, 255)) == r"<cdata 'char' %s'\xff'>" % mandatory_b_prefix - assert repr(cast(p, 0)) == r"<cdata 'char' %s'\x00'>" % mandatory_b_prefix - -def test_pointer_type(): - p = new_primitive_type("int") - assert repr(p) == "<ctype 'int'>" - p = new_pointer_type(p) - assert repr(p) == "<ctype 'int *'>" - p = new_pointer_type(p) - assert repr(p) == "<ctype 'int * *'>" - p = new_pointer_type(p) - assert repr(p) == "<ctype 'int * * *'>" - -def test_inspect_pointer_type(): - p1 = new_primitive_type("int") - p2 = new_pointer_type(p1) - assert p2.kind == "pointer" - assert p2.cname == "int *" - assert p2.item is p1 - check_dir(p2, ['cname', 'kind', 'item']) - p3 = new_pointer_type(p2) - assert p3.item is p2 - -def test_pointer_to_int(): - BInt = new_primitive_type("int") - py.test.raises(TypeError, newp, BInt) - py.test.raises(TypeError, newp, BInt, None) - BPtr = new_pointer_type(BInt) - p = newp(BPtr) - assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() - p = newp(BPtr, None) - assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() - p = newp(BPtr, 5000) - assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() - q = cast(BPtr, p) - assert repr(q).startswith("<cdata 'int *' 0x") - assert p == q - assert hash(p) == hash(q) + assert int(cast(p, 'A')) == 65 + assert long(cast(p, 'A')) == 65 + assert type(int(cast(p, 'A'))) is int + assert type(long(cast(p, 'A'))) is long + assert str(cast(p, 'A')) == repr(cast(p, 'A')) + assert repr(cast(p, 'A')) == "<cdata 'char' %s'A'>" % mandatory_b_prefix + assert repr(cast(p, 255)) == r"<cdata 'char' %s'\xff'>" % mandatory_b_prefix + assert repr(cast(p, 0)) == r"<cdata 'char' %s'\x00'>" % mandatory_b_prefix + +def test_pointer_type(): + p = new_primitive_type("int") + assert repr(p) == "<ctype 'int'>" + p = new_pointer_type(p) + assert repr(p) == "<ctype 'int *'>" + p = new_pointer_type(p) + assert repr(p) == "<ctype 'int * *'>" + p = new_pointer_type(p) + assert repr(p) == "<ctype 'int * * *'>" + +def test_inspect_pointer_type(): + p1 = new_primitive_type("int") + p2 = new_pointer_type(p1) + assert p2.kind == "pointer" + assert p2.cname == "int *" + assert p2.item is p1 + check_dir(p2, ['cname', 'kind', 'item']) + p3 = new_pointer_type(p2) + assert p3.item is p2 + +def test_pointer_to_int(): + BInt = new_primitive_type("int") + py.test.raises(TypeError, newp, BInt) + py.test.raises(TypeError, newp, BInt, None) + BPtr = new_pointer_type(BInt) + p = newp(BPtr) + assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() + p = newp(BPtr, None) + assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() + p = newp(BPtr, 5000) + assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() + q = cast(BPtr, p) + assert repr(q).startswith("<cdata 'int *' 0x") + assert p == q + assert hash(p) == hash(q) e = py.test.raises(TypeError, newp, new_array_type(BPtr, None), None) assert str(e.value) == ( "expected new array length or list/tuple/str, not NoneType") - -def test_pointer_bool(): - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - p = cast(BPtr, 0) - assert bool(p) is False - p = cast(BPtr, 42) - assert bool(p) is True - -def test_pointer_to_pointer(): - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - BPtrPtr = new_pointer_type(BPtr) - p = newp(BPtrPtr, None) - assert repr(p) == "<cdata 'int * *' owning %d bytes>" % size_of_ptr() - -def test_reading_pointer_to_int(): - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - p = newp(BPtr, None) - assert p[0] == 0 - p = newp(BPtr, 5000) - assert p[0] == 5000 + +def test_pointer_bool(): + BInt = new_primitive_type("int") + BPtr = new_pointer_type(BInt) + p = cast(BPtr, 0) + assert bool(p) is False + p = cast(BPtr, 42) + assert bool(p) is True + +def test_pointer_to_pointer(): + BInt = new_primitive_type("int") + BPtr = new_pointer_type(BInt) + BPtrPtr = new_pointer_type(BPtr) + p = newp(BPtrPtr, None) + assert repr(p) == "<cdata 'int * *' owning %d bytes>" % size_of_ptr() + +def test_reading_pointer_to_int(): + BInt = new_primitive_type("int") + BPtr = new_pointer_type(BInt) + p = newp(BPtr, None) + assert p[0] == 0 + p = newp(BPtr, 5000) + assert p[0] == 5000 with pytest.raises(IndexError): p[1] with pytest.raises(IndexError): p[-1] - -def test_reading_pointer_to_float(): - BFloat = new_primitive_type("float") - py.test.raises(TypeError, newp, BFloat, None) - BPtr = new_pointer_type(BFloat) - p = newp(BPtr, None) - assert p[0] == 0.0 and type(p[0]) is float - p = newp(BPtr, 1.25) - assert p[0] == 1.25 and type(p[0]) is float - p = newp(BPtr, 1.1) - assert p[0] != 1.1 and abs(p[0] - 1.1) < 1E-5 # rounding errors - -def test_cast_float_to_int(): - for type in ["int", "unsigned int", "long", "unsigned long", - "long long", "unsigned long long"]: - p = new_primitive_type(type) - assert int(cast(p, 4.2)) == 4 - py.test.raises(TypeError, newp, new_pointer_type(p), 4.2) - -def test_newp_integer_types(): - for name in ['signed char', 'short', 'int', 'long', 'long long']: - p = new_primitive_type(name) - pp = new_pointer_type(p) - size = sizeof(p) - min = -(1 << (8*size-1)) - max = (1 << (8*size-1)) - 1 - assert newp(pp, min)[0] == min - assert newp(pp, max)[0] == max + +def test_reading_pointer_to_float(): + BFloat = new_primitive_type("float") + py.test.raises(TypeError, newp, BFloat, None) + BPtr = new_pointer_type(BFloat) + p = newp(BPtr, None) + assert p[0] == 0.0 and type(p[0]) is float + p = newp(BPtr, 1.25) + assert p[0] == 1.25 and type(p[0]) is float + p = newp(BPtr, 1.1) + assert p[0] != 1.1 and abs(p[0] - 1.1) < 1E-5 # rounding errors + +def test_cast_float_to_int(): + for type in ["int", "unsigned int", "long", "unsigned long", + "long long", "unsigned long long"]: + p = new_primitive_type(type) + assert int(cast(p, 4.2)) == 4 + py.test.raises(TypeError, newp, new_pointer_type(p), 4.2) + +def test_newp_integer_types(): + for name in ['signed char', 'short', 'int', 'long', 'long long']: + p = new_primitive_type(name) + pp = new_pointer_type(p) + size = sizeof(p) + min = -(1 << (8*size-1)) + max = (1 << (8*size-1)) - 1 + assert newp(pp, min)[0] == min + assert newp(pp, max)[0] == max py.test.raises(OverflowError, newp, pp, min - 2 ** 32) py.test.raises(OverflowError, newp, pp, min - 2 ** 64) py.test.raises(OverflowError, newp, pp, max + 2 ** 32) py.test.raises(OverflowError, newp, pp, max + 2 ** 64) - py.test.raises(OverflowError, newp, pp, min - 1) - py.test.raises(OverflowError, newp, pp, max + 1) + py.test.raises(OverflowError, newp, pp, min - 1) + py.test.raises(OverflowError, newp, pp, max + 1) py.test.raises(OverflowError, newp, pp, min - 1 - 2 ** 32) py.test.raises(OverflowError, newp, pp, min - 1 - 2 ** 64) py.test.raises(OverflowError, newp, pp, max + 1) py.test.raises(OverflowError, newp, pp, max + 1 + 2 ** 32) py.test.raises(OverflowError, newp, pp, max + 1 + 2 ** 64) py.test.raises(TypeError, newp, pp, 1.0) - for name in ['char', 'short', 'int', 'long', 'long long']: - p = new_primitive_type('unsigned ' + name) - pp = new_pointer_type(p) - size = sizeof(p) - max = (1 << (8*size)) - 1 - assert newp(pp, 0)[0] == 0 - assert newp(pp, max)[0] == max - py.test.raises(OverflowError, newp, pp, -1) - py.test.raises(OverflowError, newp, pp, max + 1) - -def test_reading_pointer_to_char(): - BChar = new_primitive_type("char") - py.test.raises(TypeError, newp, BChar, None) - BPtr = new_pointer_type(BChar) - p = newp(BPtr, None) - assert p[0] == b'\x00' - p = newp(BPtr, b'A') - assert p[0] == b'A' - py.test.raises(TypeError, newp, BPtr, 65) - py.test.raises(TypeError, newp, BPtr, b"foo") - py.test.raises(TypeError, newp, BPtr, u+"foo") - c = cast(BChar, b'A') - assert str(c) == repr(c) - assert int(c) == ord(b'A') - py.test.raises(TypeError, cast, BChar, b'foo') - py.test.raises(TypeError, cast, BChar, u+'foo') + for name in ['char', 'short', 'int', 'long', 'long long']: + p = new_primitive_type('unsigned ' + name) + pp = new_pointer_type(p) + size = sizeof(p) + max = (1 << (8*size)) - 1 + assert newp(pp, 0)[0] == 0 + assert newp(pp, max)[0] == max + py.test.raises(OverflowError, newp, pp, -1) + py.test.raises(OverflowError, newp, pp, max + 1) + +def test_reading_pointer_to_char(): + BChar = new_primitive_type("char") + py.test.raises(TypeError, newp, BChar, None) + BPtr = new_pointer_type(BChar) + p = newp(BPtr, None) + assert p[0] == b'\x00' + p = newp(BPtr, b'A') + assert p[0] == b'A' + py.test.raises(TypeError, newp, BPtr, 65) + py.test.raises(TypeError, newp, BPtr, b"foo") + py.test.raises(TypeError, newp, BPtr, u+"foo") + c = cast(BChar, b'A') + assert str(c) == repr(c) + assert int(c) == ord(b'A') + py.test.raises(TypeError, cast, BChar, b'foo') + py.test.raises(TypeError, cast, BChar, u+'foo') e = py.test.raises(TypeError, newp, new_array_type(BPtr, None), 12.3) assert str(e.value) == ( "expected new array length or list/tuple/str, not float") - -def test_reading_pointer_to_pointer(): - BVoidP = new_pointer_type(new_void_type()) - BCharP = new_pointer_type(new_primitive_type("char")) - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - BIntPtrPtr = new_pointer_type(BIntPtr) - q = newp(BIntPtr, 42) - assert q[0] == 42 - p = newp(BIntPtrPtr, None) - assert p[0] is not None - assert p[0] == cast(BVoidP, 0) - assert p[0] == cast(BCharP, 0) - assert p[0] != None - assert repr(p[0]) == "<cdata 'int *' NULL>" - p[0] = q - assert p[0] != cast(BVoidP, 0) - assert p[0] != cast(BCharP, 0) - assert p[0][0] == 42 - q[0] += 1 - assert p[0][0] == 43 - p = newp(BIntPtrPtr, q) - assert p[0][0] == 43 - -def test_load_standard_library(): - if sys.platform == "win32": - py.test.raises(OSError, find_and_load_library, None) - return - x = find_and_load_library(None) - BVoidP = new_pointer_type(new_void_type()) - assert x.load_function(BVoidP, 'strcpy') + +def test_reading_pointer_to_pointer(): + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + BInt = new_primitive_type("int") + BIntPtr = new_pointer_type(BInt) + BIntPtrPtr = new_pointer_type(BIntPtr) + q = newp(BIntPtr, 42) + assert q[0] == 42 + p = newp(BIntPtrPtr, None) + assert p[0] is not None + assert p[0] == cast(BVoidP, 0) + assert p[0] == cast(BCharP, 0) + assert p[0] != None + assert repr(p[0]) == "<cdata 'int *' NULL>" + p[0] = q + assert p[0] != cast(BVoidP, 0) + assert p[0] != cast(BCharP, 0) + assert p[0][0] == 42 + q[0] += 1 + assert p[0][0] == 43 + p = newp(BIntPtrPtr, q) + assert p[0][0] == 43 + +def test_load_standard_library(): + if sys.platform == "win32": + py.test.raises(OSError, find_and_load_library, None) + return + x = find_and_load_library(None) + BVoidP = new_pointer_type(new_void_type()) + assert x.load_function(BVoidP, 'strcpy') py.test.raises(AttributeError, x.load_function, - BVoidP, 'xxx_this_function_does_not_exist') - # the next one is from 'libm', not 'libc', but we assume - # that it is already loaded too, so it should work - assert x.load_function(BVoidP, 'sqrt') + BVoidP, 'xxx_this_function_does_not_exist') + # the next one is from 'libm', not 'libc', but we assume + # that it is already loaded too, so it should work + assert x.load_function(BVoidP, 'sqrt') # x.close_lib() py.test.raises(ValueError, x.load_function, BVoidP, 'sqrt') x.close_lib() - -def test_no_len_on_nonarray(): - p = new_primitive_type("int") - py.test.raises(TypeError, len, cast(p, 42)) - -def test_cmp_none(): - p = new_primitive_type("int") - x = cast(p, 42) - assert (x == None) is False - assert (x != None) is True - assert (x == ["hello"]) is False - assert (x != ["hello"]) is True - y = cast(p, 0) - assert (y == None) is False - -def test_invalid_indexing(): - p = new_primitive_type("int") - x = cast(p, 42) + +def test_no_len_on_nonarray(): + p = new_primitive_type("int") + py.test.raises(TypeError, len, cast(p, 42)) + +def test_cmp_none(): + p = new_primitive_type("int") + x = cast(p, 42) + assert (x == None) is False + assert (x != None) is True + assert (x == ["hello"]) is False + assert (x != ["hello"]) is True + y = cast(p, 0) + assert (y == None) is False + +def test_invalid_indexing(): + p = new_primitive_type("int") + x = cast(p, 42) with pytest.raises(TypeError): x[0] - -def test_default_str(): - BChar = new_primitive_type("char") - x = cast(BChar, 42) - assert str(x) == repr(x) - BInt = new_primitive_type("int") - x = cast(BInt, 42) - assert str(x) == repr(x) - BArray = new_array_type(new_pointer_type(BInt), 10) - x = newp(BArray, None) - assert str(x) == repr(x) - -def test_default_unicode(): - BInt = new_primitive_type("int") - x = cast(BInt, 42) - assert unicode(x) == unicode(repr(x)) - BArray = new_array_type(new_pointer_type(BInt), 10) - x = newp(BArray, None) - assert unicode(x) == unicode(repr(x)) - -def test_cast_from_cdataint(): - BInt = new_primitive_type("int") - x = cast(BInt, 0) - y = cast(new_pointer_type(BInt), x) - assert bool(y) is False - # - x = cast(BInt, 42) - y = cast(BInt, x) - assert int(y) == 42 - y = cast(new_primitive_type("char"), x) - assert int(y) == 42 - y = cast(new_primitive_type("float"), x) - assert float(y) == 42.0 - # - z = cast(BInt, 42.5) - assert int(z) == 42 - z = cast(BInt, y) - assert int(z) == 42 - -def test_void_type(): - p = new_void_type() - assert p.kind == "void" - assert p.cname == "void" - check_dir(p, ['kind', 'cname']) - -def test_array_type(): - p = new_primitive_type("int") - assert repr(p) == "<ctype 'int'>" - # - py.test.raises(TypeError, new_array_type, new_pointer_type(p), "foo") - py.test.raises(ValueError, new_array_type, new_pointer_type(p), -42) - # - p1 = new_array_type(new_pointer_type(p), None) - assert repr(p1) == "<ctype 'int[]'>" - py.test.raises(ValueError, new_array_type, new_pointer_type(p1), 42) - # - p1 = new_array_type(new_pointer_type(p), 42) - p2 = new_array_type(new_pointer_type(p1), 25) - assert repr(p2) == "<ctype 'int[25][42]'>" - p2 = new_array_type(new_pointer_type(p1), None) - assert repr(p2) == "<ctype 'int[][42]'>" - # - py.test.raises(OverflowError, - new_array_type, new_pointer_type(p), sys.maxsize+1) - py.test.raises(OverflowError, - new_array_type, new_pointer_type(p), sys.maxsize // 3) - -def test_inspect_array_type(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), None) - assert p1.kind == "array" - assert p1.cname == "int[]" - assert p1.item is p - assert p1.length is None - check_dir(p1, ['cname', 'kind', 'item', 'length']) - p1 = new_array_type(new_pointer_type(p), 42) - assert p1.kind == "array" - assert p1.cname == "int[42]" - assert p1.item is p - assert p1.length == 42 - check_dir(p1, ['cname', 'kind', 'item', 'length']) - -def test_array_instance(): - LENGTH = 1423 - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), LENGTH) - a = newp(p1, None) - assert repr(a) == "<cdata 'int[%d]' owning %d bytes>" % ( - LENGTH, LENGTH * size_of_int()) - assert len(a) == LENGTH - for i in range(LENGTH): - assert a[i] == 0 + +def test_default_str(): + BChar = new_primitive_type("char") + x = cast(BChar, 42) + assert str(x) == repr(x) + BInt = new_primitive_type("int") + x = cast(BInt, 42) + assert str(x) == repr(x) + BArray = new_array_type(new_pointer_type(BInt), 10) + x = newp(BArray, None) + assert str(x) == repr(x) + +def test_default_unicode(): + BInt = new_primitive_type("int") + x = cast(BInt, 42) + assert unicode(x) == unicode(repr(x)) + BArray = new_array_type(new_pointer_type(BInt), 10) + x = newp(BArray, None) + assert unicode(x) == unicode(repr(x)) + +def test_cast_from_cdataint(): + BInt = new_primitive_type("int") + x = cast(BInt, 0) + y = cast(new_pointer_type(BInt), x) + assert bool(y) is False + # + x = cast(BInt, 42) + y = cast(BInt, x) + assert int(y) == 42 + y = cast(new_primitive_type("char"), x) + assert int(y) == 42 + y = cast(new_primitive_type("float"), x) + assert float(y) == 42.0 + # + z = cast(BInt, 42.5) + assert int(z) == 42 + z = cast(BInt, y) + assert int(z) == 42 + +def test_void_type(): + p = new_void_type() + assert p.kind == "void" + assert p.cname == "void" + check_dir(p, ['kind', 'cname']) + +def test_array_type(): + p = new_primitive_type("int") + assert repr(p) == "<ctype 'int'>" + # + py.test.raises(TypeError, new_array_type, new_pointer_type(p), "foo") + py.test.raises(ValueError, new_array_type, new_pointer_type(p), -42) + # + p1 = new_array_type(new_pointer_type(p), None) + assert repr(p1) == "<ctype 'int[]'>" + py.test.raises(ValueError, new_array_type, new_pointer_type(p1), 42) + # + p1 = new_array_type(new_pointer_type(p), 42) + p2 = new_array_type(new_pointer_type(p1), 25) + assert repr(p2) == "<ctype 'int[25][42]'>" + p2 = new_array_type(new_pointer_type(p1), None) + assert repr(p2) == "<ctype 'int[][42]'>" + # + py.test.raises(OverflowError, + new_array_type, new_pointer_type(p), sys.maxsize+1) + py.test.raises(OverflowError, + new_array_type, new_pointer_type(p), sys.maxsize // 3) + +def test_inspect_array_type(): + p = new_primitive_type("int") + p1 = new_array_type(new_pointer_type(p), None) + assert p1.kind == "array" + assert p1.cname == "int[]" + assert p1.item is p + assert p1.length is None + check_dir(p1, ['cname', 'kind', 'item', 'length']) + p1 = new_array_type(new_pointer_type(p), 42) + assert p1.kind == "array" + assert p1.cname == "int[42]" + assert p1.item is p + assert p1.length == 42 + check_dir(p1, ['cname', 'kind', 'item', 'length']) + +def test_array_instance(): + LENGTH = 1423 + p = new_primitive_type("int") + p1 = new_array_type(new_pointer_type(p), LENGTH) + a = newp(p1, None) + assert repr(a) == "<cdata 'int[%d]' owning %d bytes>" % ( + LENGTH, LENGTH * size_of_int()) + assert len(a) == LENGTH + for i in range(LENGTH): + assert a[i] == 0 with pytest.raises(IndexError): a[LENGTH] with pytest.raises(IndexError): a[-1] - for i in range(LENGTH): - a[i] = i * i + 1 - for i in range(LENGTH): - assert a[i] == i * i + 1 + for i in range(LENGTH): + a[i] = i * i + 1 + for i in range(LENGTH): + assert a[i] == i * i + 1 with pytest.raises(IndexError) as e: a[LENGTH+100] = 500 - assert ('(expected %d < %d)' % (LENGTH+100, LENGTH)) in str(e.value) - py.test.raises(TypeError, int, a) - -def test_array_of_unknown_length_instance(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), None) - py.test.raises(TypeError, newp, p1, None) - py.test.raises(ValueError, newp, p1, -42) - a = newp(p1, 42) - assert len(a) == 42 - for i in range(42): - a[i] -= i - for i in range(42): - assert a[i] == -i + assert ('(expected %d < %d)' % (LENGTH+100, LENGTH)) in str(e.value) + py.test.raises(TypeError, int, a) + +def test_array_of_unknown_length_instance(): + p = new_primitive_type("int") + p1 = new_array_type(new_pointer_type(p), None) + py.test.raises(TypeError, newp, p1, None) + py.test.raises(ValueError, newp, p1, -42) + a = newp(p1, 42) + assert len(a) == 42 + for i in range(42): + a[i] -= i + for i in range(42): + assert a[i] == -i with pytest.raises(IndexError): a[42] with pytest.raises(IndexError): @@ -579,53 +579,53 @@ def test_array_of_unknown_length_instance(): a[42] = 123 with pytest.raises(IndexError): a[-1] = 456 - -def test_array_of_unknown_length_instance_with_initializer(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), None) - a = newp(p1, list(range(42))) - assert len(a) == 42 - a = newp(p1, tuple(range(142))) - assert len(a) == 142 - -def test_array_initializer(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), None) - a = newp(p1, list(range(100, 142))) - for i in range(42): - assert a[i] == 100 + i - # - p2 = new_array_type(new_pointer_type(p), 43) - a = newp(p2, tuple(range(100, 142))) - for i in range(42): - assert a[i] == 100 + i - assert a[42] == 0 # extra uninitialized item - -def test_array_add(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), 5) # int[5] - p2 = new_array_type(new_pointer_type(p1), 3) # int[3][5] - a = newp(p2, [list(range(n, n+5)) for n in [100, 200, 300]]) - assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % ( - 3*5*size_of_int(),) - assert repr(a + 0).startswith("<cdata 'int(*)[5]' 0x") - assert 0 + a == a + 0 != 1 + a == a + 1 - assert repr(a[0]).startswith("<cdata 'int[5]' 0x") - assert repr((a + 0)[0]).startswith("<cdata 'int[5]' 0x") - assert repr(a[0] + 0).startswith("<cdata 'int *' 0x") - assert type(a[0][0]) is int - assert type((a[0] + 0)[0]) is int - -def test_array_sub(): - BInt = new_primitive_type("int") - BArray = new_array_type(new_pointer_type(BInt), 5) # int[5] - a = newp(BArray, None) - p = a + 1 - assert p - a == 1 - assert p - (a+0) == 1 - assert a == (p - 1) - BPtr = new_pointer_type(new_primitive_type("short")) - q = newp(BPtr, None) + +def test_array_of_unknown_length_instance_with_initializer(): + p = new_primitive_type("int") + p1 = new_array_type(new_pointer_type(p), None) + a = newp(p1, list(range(42))) + assert len(a) == 42 + a = newp(p1, tuple(range(142))) + assert len(a) == 142 + +def test_array_initializer(): + p = new_primitive_type("int") + p1 = new_array_type(new_pointer_type(p), None) + a = newp(p1, list(range(100, 142))) + for i in range(42): + assert a[i] == 100 + i + # + p2 = new_array_type(new_pointer_type(p), 43) + a = newp(p2, tuple(range(100, 142))) + for i in range(42): + assert a[i] == 100 + i + assert a[42] == 0 # extra uninitialized item + +def test_array_add(): + p = new_primitive_type("int") + p1 = new_array_type(new_pointer_type(p), 5) # int[5] + p2 = new_array_type(new_pointer_type(p1), 3) # int[3][5] + a = newp(p2, [list(range(n, n+5)) for n in [100, 200, 300]]) + assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % ( + 3*5*size_of_int(),) + assert repr(a + 0).startswith("<cdata 'int(*)[5]' 0x") + assert 0 + a == a + 0 != 1 + a == a + 1 + assert repr(a[0]).startswith("<cdata 'int[5]' 0x") + assert repr((a + 0)[0]).startswith("<cdata 'int[5]' 0x") + assert repr(a[0] + 0).startswith("<cdata 'int *' 0x") + assert type(a[0][0]) is int + assert type((a[0] + 0)[0]) is int + +def test_array_sub(): + BInt = new_primitive_type("int") + BArray = new_array_type(new_pointer_type(BInt), 5) # int[5] + a = newp(BArray, None) + p = a + 1 + assert p - a == 1 + assert p - (a+0) == 1 + assert a == (p - 1) + BPtr = new_pointer_type(new_primitive_type("short")) + q = newp(BPtr, None) with pytest.raises(TypeError): p - q with pytest.raises(TypeError): @@ -634,171 +634,171 @@ def test_array_sub(): a - q with pytest.raises(TypeError) as e: q - a - assert str(e.value) == "cannot subtract cdata 'short *' and cdata 'int *'" - -def test_ptr_sub_unaligned(): - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - a = cast(BIntPtr, 1240) - for bi in range(1430, 1438): - b = cast(BIntPtr, bi) - if ((bi - 1240) % size_of_int()) == 0: - assert b - a == (bi - 1240) // size_of_int() - assert a - b == (1240 - bi) // size_of_int() - else: + assert str(e.value) == "cannot subtract cdata 'short *' and cdata 'int *'" + +def test_ptr_sub_unaligned(): + BInt = new_primitive_type("int") + BIntPtr = new_pointer_type(BInt) + a = cast(BIntPtr, 1240) + for bi in range(1430, 1438): + b = cast(BIntPtr, bi) + if ((bi - 1240) % size_of_int()) == 0: + assert b - a == (bi - 1240) // size_of_int() + assert a - b == (1240 - bi) // size_of_int() + else: with pytest.raises(ValueError): b - a with pytest.raises(ValueError): a - b - -def test_cast_primitive_from_cdata(): - p = new_primitive_type("int") - n = cast(p, cast(p, -42)) - assert int(n) == -42 - # - p = new_primitive_type("unsigned int") - n = cast(p, cast(p, 42)) - assert int(n) == 42 - # - p = new_primitive_type("long long") - n = cast(p, cast(p, -(1<<60))) - assert int(n) == -(1<<60) - # - p = new_primitive_type("unsigned long long") - n = cast(p, cast(p, 1<<63)) - assert int(n) == 1<<63 - # - p = new_primitive_type("float") - n = cast(p, cast(p, 42.5)) - assert float(n) == 42.5 - # - p = new_primitive_type("char") - n = cast(p, cast(p, "A")) - assert int(n) == ord("A") - -def test_new_primitive_from_cdata(): - p = new_primitive_type("int") - p1 = new_pointer_type(p) - n = newp(p1, cast(p, -42)) - assert n[0] == -42 - # - p = new_primitive_type("unsigned int") - p1 = new_pointer_type(p) - n = newp(p1, cast(p, 42)) - assert n[0] == 42 - # - p = new_primitive_type("float") - p1 = new_pointer_type(p) - n = newp(p1, cast(p, 42.5)) - assert n[0] == 42.5 - # - p = new_primitive_type("char") - p1 = new_pointer_type(p) - n = newp(p1, cast(p, "A")) - assert n[0] == b"A" - -def test_cast_between_pointers(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntA = new_array_type(BIntP, None) - a = newp(BIntA, [40, 41, 42, 43, 44]) - BShortP = new_pointer_type(new_primitive_type("short")) - b = cast(BShortP, a) - c = cast(BIntP, b) - assert c[3] == 43 - BLongLong = new_primitive_type("long long") - d = cast(BLongLong, c) - e = cast(BIntP, d) - assert e[3] == 43 - f = cast(BIntP, int(d)) - assert f[3] == 43 - # - b = cast(BShortP, 0) - assert not b - c = cast(BIntP, b) - assert not c - assert int(cast(BLongLong, c)) == 0 - -def test_alignof(): - BInt = new_primitive_type("int") - assert alignof(BInt) == sizeof(BInt) - BPtr = new_pointer_type(BInt) - assert alignof(BPtr) == sizeof(BPtr) - BArray = new_array_type(BPtr, None) - assert alignof(BArray) == alignof(BInt) - -def test_new_struct_type(): - BStruct = new_struct_type("foo") - assert repr(BStruct) == "<ctype 'foo'>" - BStruct = new_struct_type("struct foo") - assert repr(BStruct) == "<ctype 'struct foo'>" - BPtr = new_pointer_type(BStruct) - assert repr(BPtr) == "<ctype 'struct foo *'>" - py.test.raises(ValueError, sizeof, BStruct) - py.test.raises(ValueError, alignof, BStruct) - -def test_new_union_type(): - BUnion = new_union_type("union foo") - assert repr(BUnion) == "<ctype 'union foo'>" - BPtr = new_pointer_type(BUnion) - assert repr(BPtr) == "<ctype 'union foo *'>" - -def test_complete_struct(): - BLong = new_primitive_type("long") - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BStruct = new_struct_type("struct foo") - assert BStruct.kind == "struct" - assert BStruct.cname == "struct foo" - assert BStruct.fields is None - check_dir(BStruct, ['cname', 'kind', 'fields']) - # - complete_struct_or_union(BStruct, [('a1', BLong, -1), - ('a2', BChar, -1), - ('a3', BShort, -1)]) - d = BStruct.fields - assert len(d) == 3 - assert d[0][0] == 'a1' - assert d[0][1].type is BLong - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 - assert d[1][0] == 'a2' - assert d[1][1].type is BChar - assert d[1][1].offset == sizeof(BLong) - assert d[1][1].bitshift == -1 - assert d[1][1].bitsize == -1 - assert d[2][0] == 'a3' - assert d[2][1].type is BShort - assert d[2][1].offset == sizeof(BLong) + sizeof(BShort) - assert d[2][1].bitshift == -1 - assert d[2][1].bitsize == -1 - assert sizeof(BStruct) == 2 * sizeof(BLong) - assert alignof(BStruct) == alignof(BLong) - -def test_complete_union(): - BLong = new_primitive_type("long") - BChar = new_primitive_type("char") - BUnion = new_union_type("union foo") - assert BUnion.kind == "union" - assert BUnion.cname == "union foo" - assert BUnion.fields is None - complete_struct_or_union(BUnion, [('a1', BLong, -1), - ('a2', BChar, -1)]) - d = BUnion.fields - assert len(d) == 2 - assert d[0][0] == 'a1' - assert d[0][1].type is BLong - assert d[0][1].offset == 0 - assert d[1][0] == 'a2' - assert d[1][1].type is BChar - assert d[1][1].offset == 0 - assert sizeof(BUnion) == sizeof(BLong) - assert alignof(BUnion) == alignof(BLong) - -def test_struct_instance(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) + +def test_cast_primitive_from_cdata(): + p = new_primitive_type("int") + n = cast(p, cast(p, -42)) + assert int(n) == -42 + # + p = new_primitive_type("unsigned int") + n = cast(p, cast(p, 42)) + assert int(n) == 42 + # + p = new_primitive_type("long long") + n = cast(p, cast(p, -(1<<60))) + assert int(n) == -(1<<60) + # + p = new_primitive_type("unsigned long long") + n = cast(p, cast(p, 1<<63)) + assert int(n) == 1<<63 + # + p = new_primitive_type("float") + n = cast(p, cast(p, 42.5)) + assert float(n) == 42.5 + # + p = new_primitive_type("char") + n = cast(p, cast(p, "A")) + assert int(n) == ord("A") + +def test_new_primitive_from_cdata(): + p = new_primitive_type("int") + p1 = new_pointer_type(p) + n = newp(p1, cast(p, -42)) + assert n[0] == -42 + # + p = new_primitive_type("unsigned int") + p1 = new_pointer_type(p) + n = newp(p1, cast(p, 42)) + assert n[0] == 42 + # + p = new_primitive_type("float") + p1 = new_pointer_type(p) + n = newp(p1, cast(p, 42.5)) + assert n[0] == 42.5 + # + p = new_primitive_type("char") + p1 = new_pointer_type(p) + n = newp(p1, cast(p, "A")) + assert n[0] == b"A" + +def test_cast_between_pointers(): + BIntP = new_pointer_type(new_primitive_type("int")) + BIntA = new_array_type(BIntP, None) + a = newp(BIntA, [40, 41, 42, 43, 44]) + BShortP = new_pointer_type(new_primitive_type("short")) + b = cast(BShortP, a) + c = cast(BIntP, b) + assert c[3] == 43 + BLongLong = new_primitive_type("long long") + d = cast(BLongLong, c) + e = cast(BIntP, d) + assert e[3] == 43 + f = cast(BIntP, int(d)) + assert f[3] == 43 + # + b = cast(BShortP, 0) + assert not b + c = cast(BIntP, b) + assert not c + assert int(cast(BLongLong, c)) == 0 + +def test_alignof(): + BInt = new_primitive_type("int") + assert alignof(BInt) == sizeof(BInt) + BPtr = new_pointer_type(BInt) + assert alignof(BPtr) == sizeof(BPtr) + BArray = new_array_type(BPtr, None) + assert alignof(BArray) == alignof(BInt) + +def test_new_struct_type(): + BStruct = new_struct_type("foo") + assert repr(BStruct) == "<ctype 'foo'>" + BStruct = new_struct_type("struct foo") + assert repr(BStruct) == "<ctype 'struct foo'>" + BPtr = new_pointer_type(BStruct) + assert repr(BPtr) == "<ctype 'struct foo *'>" + py.test.raises(ValueError, sizeof, BStruct) + py.test.raises(ValueError, alignof, BStruct) + +def test_new_union_type(): + BUnion = new_union_type("union foo") + assert repr(BUnion) == "<ctype 'union foo'>" + BPtr = new_pointer_type(BUnion) + assert repr(BPtr) == "<ctype 'union foo *'>" + +def test_complete_struct(): + BLong = new_primitive_type("long") + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BStruct = new_struct_type("struct foo") + assert BStruct.kind == "struct" + assert BStruct.cname == "struct foo" + assert BStruct.fields is None + check_dir(BStruct, ['cname', 'kind', 'fields']) + # + complete_struct_or_union(BStruct, [('a1', BLong, -1), + ('a2', BChar, -1), + ('a3', BShort, -1)]) + d = BStruct.fields + assert len(d) == 3 + assert d[0][0] == 'a1' + assert d[0][1].type is BLong + assert d[0][1].offset == 0 + assert d[0][1].bitshift == -1 + assert d[0][1].bitsize == -1 + assert d[1][0] == 'a2' + assert d[1][1].type is BChar + assert d[1][1].offset == sizeof(BLong) + assert d[1][1].bitshift == -1 + assert d[1][1].bitsize == -1 + assert d[2][0] == 'a3' + assert d[2][1].type is BShort + assert d[2][1].offset == sizeof(BLong) + sizeof(BShort) + assert d[2][1].bitshift == -1 + assert d[2][1].bitsize == -1 + assert sizeof(BStruct) == 2 * sizeof(BLong) + assert alignof(BStruct) == alignof(BLong) + +def test_complete_union(): + BLong = new_primitive_type("long") + BChar = new_primitive_type("char") + BUnion = new_union_type("union foo") + assert BUnion.kind == "union" + assert BUnion.cname == "union foo" + assert BUnion.fields is None + complete_struct_or_union(BUnion, [('a1', BLong, -1), + ('a2', BChar, -1)]) + d = BUnion.fields + assert len(d) == 2 + assert d[0][0] == 'a1' + assert d[0][1].type is BLong + assert d[0][1].offset == 0 + assert d[1][0] == 'a2' + assert d[1][1].type is BChar + assert d[1][1].offset == 0 + assert sizeof(BUnion) == sizeof(BLong) + assert alignof(BUnion) == alignof(BLong) + +def test_struct_instance(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) p = cast(BStructPtr, 42) with pytest.raises(AttributeError) as e: p.a1 # opaque @@ -809,17 +809,17 @@ def test_struct_instance(): assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: " "cannot write fields") - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1)]) - p = newp(BStructPtr, None) - s = p[0] - assert s.a1 == 0 - s.a2 = 123 - assert s.a1 == 0 - assert s.a2 == 123 + complete_struct_or_union(BStruct, [('a1', BInt, -1), + ('a2', BInt, -1)]) + p = newp(BStructPtr, None) + s = p[0] + assert s.a1 == 0 + s.a2 = 123 + assert s.a1 == 0 + assert s.a2 == 123 with pytest.raises(OverflowError): s.a1 = sys.maxsize+1 - assert s.a1 == 0 + assert s.a1 == 0 with pytest.raises(AttributeError) as e: p.foobar assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'" @@ -853,140 +853,140 @@ def test_struct_instance(): with pytest.raises(AttributeError) as e: pp.a1 = 42 assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'" - -def test_union_instance(): - BInt = new_primitive_type("int") - BUInt = new_primitive_type("unsigned int") - BUnion = new_union_type("union bar") - complete_struct_or_union(BUnion, [('a1', BInt, -1), ('a2', BUInt, -1)]) - p = newp(new_pointer_type(BUnion), [-42]) - bigval = -42 + (1 << (8*size_of_int())) - assert p.a1 == -42 - assert p.a2 == bigval - p = newp(new_pointer_type(BUnion), {'a2': bigval}) - assert p.a1 == -42 - assert p.a2 == bigval - py.test.raises(OverflowError, newp, new_pointer_type(BUnion), - {'a1': bigval}) - p = newp(new_pointer_type(BUnion), []) - assert p.a1 == p.a2 == 0 - -def test_struct_pointer(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1)]) - p = newp(BStructPtr, None) - assert p.a1 == 0 # read/write via the pointer (C equivalent: '->') - p.a2 = 123 - assert p.a1 == 0 - assert p.a2 == 123 - -def test_struct_init_list(): - BVoidP = new_pointer_type(new_void_type()) - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1), - ('a3', BInt, -1), - ('p4', BIntPtr, -1)]) - s = newp(BStructPtr, [123, 456]) - assert s.a1 == 123 - assert s.a2 == 456 - assert s.a3 == 0 - assert s.p4 == cast(BVoidP, 0) - assert s.p4 != 0 - # - s = newp(BStructPtr, {'a2': 41122, 'a3': -123}) - assert s.a1 == 0 - assert s.a2 == 41122 - assert s.a3 == -123 - assert s.p4 == cast(BVoidP, 0) - # - py.test.raises(KeyError, newp, BStructPtr, {'foobar': 0}) - # - p = newp(BIntPtr, 14141) - s = newp(BStructPtr, [12, 34, 56, p]) - assert s.p4 == p - assert s.p4 - # - s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)]) - assert s.p4 == cast(BVoidP, 0) - assert not s.p4 - # - py.test.raises(TypeError, newp, BStructPtr, [12, 34, 56, None]) - -def test_array_in_struct(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BArrayInt5 = new_array_type(new_pointer_type(BInt), 5) - complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)]) - s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]]) - assert s.a1[2] == 27 - assert repr(s.a1).startswith("<cdata 'int[5]' 0x") - -def test_offsetof(): - def offsetof(BType, fieldname): - return typeoffsetof(BType, fieldname)[1] - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - py.test.raises(TypeError, offsetof, BInt, "abc") - py.test.raises(TypeError, offsetof, BStruct, "abc") - complete_struct_or_union(BStruct, [('abc', BInt, -1), ('def', BInt, -1)]) - assert offsetof(BStruct, 'abc') == 0 - assert offsetof(BStruct, 'def') == size_of_int() - py.test.raises(KeyError, offsetof, BStruct, "ghi") - assert offsetof(new_pointer_type(BStruct), "def") == size_of_int() - -def test_function_type(): - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt, BInt), BInt, False) - assert repr(BFunc) == "<ctype 'int(*)(int, int)'>" - BFunc2 = new_function_type((), BFunc, False) - assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>" - -def test_inspect_function_type(): - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt, BInt), BInt, False) - assert BFunc.kind == "function" - assert BFunc.cname == "int(*)(int, int)" - assert BFunc.args == (BInt, BInt) - assert BFunc.result is BInt - assert BFunc.ellipsis is False - assert BFunc.abi == FFI_DEFAULT_ABI - -def test_function_type_taking_struct(): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BShort, -1)]) - BFunc = new_function_type((BStruct,), BShort, False) - assert repr(BFunc) == "<ctype 'short(*)(struct foo)'>" - -def test_function_void_result(): - BVoid = new_void_type() - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt, BInt), BVoid, False) - assert repr(BFunc) == "<ctype 'void(*)(int, int)'>" - -def test_function_void_arg(): - BVoid = new_void_type() - BInt = new_primitive_type("int") - py.test.raises(TypeError, new_function_type, (BVoid,), BInt, False) - -def test_call_function_0(): - BSignedChar = new_primitive_type("signed char") - BFunc0 = new_function_type((BSignedChar, BSignedChar), BSignedChar, False) - f = cast(BFunc0, _testfunc(0)) - assert f(40, 2) == 42 - assert f(-100, -100) == -200 + 256 - py.test.raises(OverflowError, f, 128, 0) - py.test.raises(OverflowError, f, 0, 128) - + +def test_union_instance(): + BInt = new_primitive_type("int") + BUInt = new_primitive_type("unsigned int") + BUnion = new_union_type("union bar") + complete_struct_or_union(BUnion, [('a1', BInt, -1), ('a2', BUInt, -1)]) + p = newp(new_pointer_type(BUnion), [-42]) + bigval = -42 + (1 << (8*size_of_int())) + assert p.a1 == -42 + assert p.a2 == bigval + p = newp(new_pointer_type(BUnion), {'a2': bigval}) + assert p.a1 == -42 + assert p.a2 == bigval + py.test.raises(OverflowError, newp, new_pointer_type(BUnion), + {'a1': bigval}) + p = newp(new_pointer_type(BUnion), []) + assert p.a1 == p.a2 == 0 + +def test_struct_pointer(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BInt, -1), + ('a2', BInt, -1)]) + p = newp(BStructPtr, None) + assert p.a1 == 0 # read/write via the pointer (C equivalent: '->') + p.a2 = 123 + assert p.a1 == 0 + assert p.a2 == 123 + +def test_struct_init_list(): + BVoidP = new_pointer_type(new_void_type()) + BInt = new_primitive_type("int") + BIntPtr = new_pointer_type(BInt) + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BInt, -1), + ('a2', BInt, -1), + ('a3', BInt, -1), + ('p4', BIntPtr, -1)]) + s = newp(BStructPtr, [123, 456]) + assert s.a1 == 123 + assert s.a2 == 456 + assert s.a3 == 0 + assert s.p4 == cast(BVoidP, 0) + assert s.p4 != 0 + # + s = newp(BStructPtr, {'a2': 41122, 'a3': -123}) + assert s.a1 == 0 + assert s.a2 == 41122 + assert s.a3 == -123 + assert s.p4 == cast(BVoidP, 0) + # + py.test.raises(KeyError, newp, BStructPtr, {'foobar': 0}) + # + p = newp(BIntPtr, 14141) + s = newp(BStructPtr, [12, 34, 56, p]) + assert s.p4 == p + assert s.p4 + # + s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)]) + assert s.p4 == cast(BVoidP, 0) + assert not s.p4 + # + py.test.raises(TypeError, newp, BStructPtr, [12, 34, 56, None]) + +def test_array_in_struct(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + BArrayInt5 = new_array_type(new_pointer_type(BInt), 5) + complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)]) + s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]]) + assert s.a1[2] == 27 + assert repr(s.a1).startswith("<cdata 'int[5]' 0x") + +def test_offsetof(): + def offsetof(BType, fieldname): + return typeoffsetof(BType, fieldname)[1] + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + py.test.raises(TypeError, offsetof, BInt, "abc") + py.test.raises(TypeError, offsetof, BStruct, "abc") + complete_struct_or_union(BStruct, [('abc', BInt, -1), ('def', BInt, -1)]) + assert offsetof(BStruct, 'abc') == 0 + assert offsetof(BStruct, 'def') == size_of_int() + py.test.raises(KeyError, offsetof, BStruct, "ghi") + assert offsetof(new_pointer_type(BStruct), "def") == size_of_int() + +def test_function_type(): + BInt = new_primitive_type("int") + BFunc = new_function_type((BInt, BInt), BInt, False) + assert repr(BFunc) == "<ctype 'int(*)(int, int)'>" + BFunc2 = new_function_type((), BFunc, False) + assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>" + +def test_inspect_function_type(): + BInt = new_primitive_type("int") + BFunc = new_function_type((BInt, BInt), BInt, False) + assert BFunc.kind == "function" + assert BFunc.cname == "int(*)(int, int)" + assert BFunc.args == (BInt, BInt) + assert BFunc.result is BInt + assert BFunc.ellipsis is False + assert BFunc.abi == FFI_DEFAULT_ABI + +def test_function_type_taking_struct(): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, [('a1', BChar, -1), + ('a2', BShort, -1)]) + BFunc = new_function_type((BStruct,), BShort, False) + assert repr(BFunc) == "<ctype 'short(*)(struct foo)'>" + +def test_function_void_result(): + BVoid = new_void_type() + BInt = new_primitive_type("int") + BFunc = new_function_type((BInt, BInt), BVoid, False) + assert repr(BFunc) == "<ctype 'void(*)(int, int)'>" + +def test_function_void_arg(): + BVoid = new_void_type() + BInt = new_primitive_type("int") + py.test.raises(TypeError, new_function_type, (BVoid,), BInt, False) + +def test_call_function_0(): + BSignedChar = new_primitive_type("signed char") + BFunc0 = new_function_type((BSignedChar, BSignedChar), BSignedChar, False) + f = cast(BFunc0, _testfunc(0)) + assert f(40, 2) == 42 + assert f(-100, -100) == -200 + 256 + py.test.raises(OverflowError, f, 128, 0) + py.test.raises(OverflowError, f, 0, 128) + def test_call_function_0_pretend_bool_result(): BSignedChar = new_primitive_type("signed char") BBool = new_primitive_type("_Bool") @@ -996,168 +996,168 @@ def test_call_function_0_pretend_bool_result(): assert f(40, -40) is False py.test.raises(ValueError, f, 40, 2) -def test_call_function_1(): - BInt = new_primitive_type("int") - BLong = new_primitive_type("long") - BFunc1 = new_function_type((BInt, BLong), BLong, False) - f = cast(BFunc1, _testfunc(1)) - assert f(40, 2) == 42 - assert f(-100, -100) == -200 - int_max = (1 << (8*size_of_int()-1)) - 1 - long_max = (1 << (8*size_of_long()-1)) - 1 - if int_max == long_max: - assert f(int_max, 1) == - int_max - 1 - else: - assert f(int_max, 1) == int_max + 1 - -def test_call_function_2(): - BLongLong = new_primitive_type("long long") - BFunc2 = new_function_type((BLongLong, BLongLong), BLongLong, False) - f = cast(BFunc2, _testfunc(2)) - longlong_max = (1 << (8*sizeof(BLongLong)-1)) - 1 - assert f(longlong_max - 42, 42) == longlong_max - assert f(43, longlong_max - 42) == - longlong_max - 1 - -def test_call_function_3(): - BFloat = new_primitive_type("float") - BDouble = new_primitive_type("double") - BFunc3 = new_function_type((BFloat, BDouble), BDouble, False) - f = cast(BFunc3, _testfunc(3)) - assert f(1.25, 5.1) == 1.25 + 5.1 # exact - res = f(1.3, 5.1) - assert res != 6.4 and abs(res - 6.4) < 1E-5 # inexact - -def test_call_function_4(): - BFloat = new_primitive_type("float") - BDouble = new_primitive_type("double") - BFunc4 = new_function_type((BFloat, BDouble), BFloat, False) - f = cast(BFunc4, _testfunc(4)) - res = f(1.25, 5.1) - assert res != 6.35 and abs(res - 6.35) < 1E-5 # inexact - -def test_call_function_5(): - BVoid = new_void_type() - BFunc5 = new_function_type((), BVoid, False) - f = cast(BFunc5, _testfunc(5)) - f() # did not crash - -def test_call_function_6(): - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - BFunc6 = new_function_type((BIntPtr,), BIntPtr, False) - f = cast(BFunc6, _testfunc(6)) - x = newp(BIntPtr, 42) - res = f(x) - assert typeof(res) is BIntPtr - assert res[0] == 42 - 1000 - # - BIntArray = new_array_type(BIntPtr, None) - BFunc6bis = new_function_type((BIntArray,), BIntPtr, False) - f = cast(BFunc6bis, _testfunc(6)) - # - res = f([142]) - assert typeof(res) is BIntPtr - assert res[0] == 142 - 1000 - # - res = f((143,)) - assert typeof(res) is BIntPtr - assert res[0] == 143 - 1000 - # - x = newp(BIntArray, [242]) - res = f(x) - assert typeof(res) is BIntPtr - assert res[0] == 242 - 1000 - # - py.test.raises(TypeError, f, 123456) - py.test.raises(TypeError, f, "foo") - py.test.raises(TypeError, f, u+"bar") - -def test_call_function_7(): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BShort, -1)]) - BFunc7 = new_function_type((BStruct,), BShort, False) - f = cast(BFunc7, _testfunc(7)) - res = f({'a1': b'A', 'a2': -4042}) - assert res == -4042 + ord(b'A') - # - x = newp(BStructPtr, {'a1': b'A', 'a2': -4042}) - res = f(x[0]) - assert res == -4042 + ord(b'A') - -def test_call_function_20(): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BShort, -1)]) - BFunc20 = new_function_type((BStructPtr,), BShort, False) - f = cast(BFunc20, _testfunc(20)) - x = newp(BStructPtr, {'a1': b'A', 'a2': -4042}) - # can't pass a 'struct foo' - py.test.raises(TypeError, f, x[0]) - -def test_call_function_21(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a', BInt, -1), - ('b', BInt, -1), - ('c', BInt, -1), - ('d', BInt, -1), - ('e', BInt, -1), - ('f', BInt, -1), - ('g', BInt, -1), - ('h', BInt, -1), - ('i', BInt, -1), - ('j', BInt, -1)]) - BFunc21 = new_function_type((BStruct,), BInt, False) - f = cast(BFunc21, _testfunc(21)) - res = f(list(range(13, 3, -1))) - lst = [(n << i) for (i, n) in enumerate(range(13, 3, -1))] - assert res == sum(lst) - -def test_call_function_22(): - BInt = new_primitive_type("int") - BArray10 = new_array_type(new_pointer_type(BInt), 10) - BStruct = new_struct_type("struct foo") - BStructP = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BArray10, -1)]) - BFunc22 = new_function_type((BStruct, BStruct), BStruct, False) - f = cast(BFunc22, _testfunc(22)) - p1 = newp(BStructP, {'a': list(range(100, 110))}) - p2 = newp(BStructP, {'a': list(range(1000, 1100, 10))}) - res = f(p1[0], p2[0]) - for i in range(10): - assert res.a[i] == p1.a[i] - p2.a[i] - -def test_call_function_23(): - BVoid = new_void_type() # declaring the function as int(void*) - BVoidP = new_pointer_type(BVoid) - BInt = new_primitive_type("int") - BFunc23 = new_function_type((BVoidP,), BInt, False) - f = cast(BFunc23, _testfunc(23)) - res = f(b"foo") - assert res == 1000 * ord(b'f') - res = f(cast(BVoidP, 0)) # NULL - assert res == -42 - py.test.raises(TypeError, f, None) - py.test.raises(TypeError, f, 0) - py.test.raises(TypeError, f, 0.0) - -def test_call_function_23_bis(): - # declaring the function as int(unsigned char*) - BUChar = new_primitive_type("unsigned char") - BUCharP = new_pointer_type(BUChar) - BInt = new_primitive_type("int") - BFunc23 = new_function_type((BUCharP,), BInt, False) - f = cast(BFunc23, _testfunc(23)) - res = f(b"foo") - assert res == 1000 * ord(b'f') - +def test_call_function_1(): + BInt = new_primitive_type("int") + BLong = new_primitive_type("long") + BFunc1 = new_function_type((BInt, BLong), BLong, False) + f = cast(BFunc1, _testfunc(1)) + assert f(40, 2) == 42 + assert f(-100, -100) == -200 + int_max = (1 << (8*size_of_int()-1)) - 1 + long_max = (1 << (8*size_of_long()-1)) - 1 + if int_max == long_max: + assert f(int_max, 1) == - int_max - 1 + else: + assert f(int_max, 1) == int_max + 1 + +def test_call_function_2(): + BLongLong = new_primitive_type("long long") + BFunc2 = new_function_type((BLongLong, BLongLong), BLongLong, False) + f = cast(BFunc2, _testfunc(2)) + longlong_max = (1 << (8*sizeof(BLongLong)-1)) - 1 + assert f(longlong_max - 42, 42) == longlong_max + assert f(43, longlong_max - 42) == - longlong_max - 1 + +def test_call_function_3(): + BFloat = new_primitive_type("float") + BDouble = new_primitive_type("double") + BFunc3 = new_function_type((BFloat, BDouble), BDouble, False) + f = cast(BFunc3, _testfunc(3)) + assert f(1.25, 5.1) == 1.25 + 5.1 # exact + res = f(1.3, 5.1) + assert res != 6.4 and abs(res - 6.4) < 1E-5 # inexact + +def test_call_function_4(): + BFloat = new_primitive_type("float") + BDouble = new_primitive_type("double") + BFunc4 = new_function_type((BFloat, BDouble), BFloat, False) + f = cast(BFunc4, _testfunc(4)) + res = f(1.25, 5.1) + assert res != 6.35 and abs(res - 6.35) < 1E-5 # inexact + +def test_call_function_5(): + BVoid = new_void_type() + BFunc5 = new_function_type((), BVoid, False) + f = cast(BFunc5, _testfunc(5)) + f() # did not crash + +def test_call_function_6(): + BInt = new_primitive_type("int") + BIntPtr = new_pointer_type(BInt) + BFunc6 = new_function_type((BIntPtr,), BIntPtr, False) + f = cast(BFunc6, _testfunc(6)) + x = newp(BIntPtr, 42) + res = f(x) + assert typeof(res) is BIntPtr + assert res[0] == 42 - 1000 + # + BIntArray = new_array_type(BIntPtr, None) + BFunc6bis = new_function_type((BIntArray,), BIntPtr, False) + f = cast(BFunc6bis, _testfunc(6)) + # + res = f([142]) + assert typeof(res) is BIntPtr + assert res[0] == 142 - 1000 + # + res = f((143,)) + assert typeof(res) is BIntPtr + assert res[0] == 143 - 1000 + # + x = newp(BIntArray, [242]) + res = f(x) + assert typeof(res) is BIntPtr + assert res[0] == 242 - 1000 + # + py.test.raises(TypeError, f, 123456) + py.test.raises(TypeError, f, "foo") + py.test.raises(TypeError, f, u+"bar") + +def test_call_function_7(): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BChar, -1), + ('a2', BShort, -1)]) + BFunc7 = new_function_type((BStruct,), BShort, False) + f = cast(BFunc7, _testfunc(7)) + res = f({'a1': b'A', 'a2': -4042}) + assert res == -4042 + ord(b'A') + # + x = newp(BStructPtr, {'a1': b'A', 'a2': -4042}) + res = f(x[0]) + assert res == -4042 + ord(b'A') + +def test_call_function_20(): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BChar, -1), + ('a2', BShort, -1)]) + BFunc20 = new_function_type((BStructPtr,), BShort, False) + f = cast(BFunc20, _testfunc(20)) + x = newp(BStructPtr, {'a1': b'A', 'a2': -4042}) + # can't pass a 'struct foo' + py.test.raises(TypeError, f, x[0]) + +def test_call_function_21(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, [('a', BInt, -1), + ('b', BInt, -1), + ('c', BInt, -1), + ('d', BInt, -1), + ('e', BInt, -1), + ('f', BInt, -1), + ('g', BInt, -1), + ('h', BInt, -1), + ('i', BInt, -1), + ('j', BInt, -1)]) + BFunc21 = new_function_type((BStruct,), BInt, False) + f = cast(BFunc21, _testfunc(21)) + res = f(list(range(13, 3, -1))) + lst = [(n << i) for (i, n) in enumerate(range(13, 3, -1))] + assert res == sum(lst) + +def test_call_function_22(): + BInt = new_primitive_type("int") + BArray10 = new_array_type(new_pointer_type(BInt), 10) + BStruct = new_struct_type("struct foo") + BStructP = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a', BArray10, -1)]) + BFunc22 = new_function_type((BStruct, BStruct), BStruct, False) + f = cast(BFunc22, _testfunc(22)) + p1 = newp(BStructP, {'a': list(range(100, 110))}) + p2 = newp(BStructP, {'a': list(range(1000, 1100, 10))}) + res = f(p1[0], p2[0]) + for i in range(10): + assert res.a[i] == p1.a[i] - p2.a[i] + +def test_call_function_23(): + BVoid = new_void_type() # declaring the function as int(void*) + BVoidP = new_pointer_type(BVoid) + BInt = new_primitive_type("int") + BFunc23 = new_function_type((BVoidP,), BInt, False) + f = cast(BFunc23, _testfunc(23)) + res = f(b"foo") + assert res == 1000 * ord(b'f') + res = f(cast(BVoidP, 0)) # NULL + assert res == -42 + py.test.raises(TypeError, f, None) + py.test.raises(TypeError, f, 0) + py.test.raises(TypeError, f, 0.0) + +def test_call_function_23_bis(): + # declaring the function as int(unsigned char*) + BUChar = new_primitive_type("unsigned char") + BUCharP = new_pointer_type(BUChar) + BInt = new_primitive_type("int") + BFunc23 = new_function_type((BUCharP,), BInt, False) + f = cast(BFunc23, _testfunc(23)) + res = f(b"foo") + assert res == 1000 * ord(b'f') + def test_call_function_23_bool_array(): # declaring the function as int(_Bool*) BBool = new_primitive_type("_Bool") @@ -1169,32 +1169,32 @@ def test_call_function_23_bool_array(): assert res == 1000 py.test.raises(ValueError, f, b"\x02\x02") -def test_cannot_pass_struct_with_array_of_length_0(): - BInt = new_primitive_type("int") - BArray0 = new_array_type(new_pointer_type(BInt), 0) - BStruct = new_struct_type("struct foo") - BStructP = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BArray0)]) - BFunc = new_function_type((BStruct,), BInt, False) - py.test.raises(NotImplementedError, cast(BFunc, 123), cast(BStructP, 123)) - BFunc2 = new_function_type((BInt,), BStruct, False) - py.test.raises(NotImplementedError, cast(BFunc2, 123), 123) - -def test_call_function_9(): - BInt = new_primitive_type("int") - BFunc9 = new_function_type((BInt,), BInt, True) # vararg - f = cast(BFunc9, _testfunc(9)) - assert f(0) == 0 - assert f(1, cast(BInt, 42)) == 42 - assert f(2, cast(BInt, 40), cast(BInt, 2)) == 42 - py.test.raises(TypeError, f, 1, 42) - py.test.raises(TypeError, f, 2, None) - # promotion of chars and shorts to ints - BSChar = new_primitive_type("signed char") - BUChar = new_primitive_type("unsigned char") - BSShort = new_primitive_type("short") - assert f(3, cast(BSChar, -3), cast(BUChar, 200), cast(BSShort, -5)) == 192 - +def test_cannot_pass_struct_with_array_of_length_0(): + BInt = new_primitive_type("int") + BArray0 = new_array_type(new_pointer_type(BInt), 0) + BStruct = new_struct_type("struct foo") + BStructP = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a', BArray0)]) + BFunc = new_function_type((BStruct,), BInt, False) + py.test.raises(NotImplementedError, cast(BFunc, 123), cast(BStructP, 123)) + BFunc2 = new_function_type((BInt,), BStruct, False) + py.test.raises(NotImplementedError, cast(BFunc2, 123), 123) + +def test_call_function_9(): + BInt = new_primitive_type("int") + BFunc9 = new_function_type((BInt,), BInt, True) # vararg + f = cast(BFunc9, _testfunc(9)) + assert f(0) == 0 + assert f(1, cast(BInt, 42)) == 42 + assert f(2, cast(BInt, 40), cast(BInt, 2)) == 42 + py.test.raises(TypeError, f, 1, 42) + py.test.raises(TypeError, f, 2, None) + # promotion of chars and shorts to ints + BSChar = new_primitive_type("signed char") + BUChar = new_primitive_type("unsigned char") + BSShort = new_primitive_type("short") + assert f(3, cast(BSChar, -3), cast(BUChar, 200), cast(BSShort, -5)) == 192 + def test_call_function_24(): BFloat = new_primitive_type("float") BFloatComplex = new_primitive_type("float _Complex") @@ -1223,17 +1223,17 @@ def test_call_function_25(): f = cast(BFunc3, _testfunc(9)) py.test.raises(NotImplementedError, f, 12.3, 34.5) -def test_cannot_call_with_a_autocompleted_struct(): - BSChar = new_primitive_type("signed char") - BDouble = new_primitive_type("double") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('c', BDouble, -1, 8), - ('a', BSChar, -1, 2), - ('b', BSChar, -1, 0)]) - BFunc = new_function_type((BStruct,), BDouble) # internally not callable - dummy_func = cast(BFunc, 42) - e = py.test.raises(NotImplementedError, dummy_func, "?") +def test_cannot_call_with_a_autocompleted_struct(): + BSChar = new_primitive_type("signed char") + BDouble = new_primitive_type("double") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('c', BDouble, -1, 8), + ('a', BSChar, -1, 2), + ('b', BSChar, -1, 0)]) + BFunc = new_function_type((BStruct,), BDouble) # internally not callable + dummy_func = cast(BFunc, 42) + e = py.test.raises(NotImplementedError, dummy_func, "?") msg = ("ctype 'struct foo' not supported as argument. It is a struct " 'declared with "...;", but the C calling convention may depend ' "on the missing fields; or, it contains anonymous struct/unions. " @@ -1241,144 +1241,144 @@ def test_cannot_call_with_a_autocompleted_struct(): "'API mode' and non-variadic (i.e. declared inside ffibuilder." "cdef()+ffibuilder.set_source() and not taking a final '...' " "argument)") - assert str(e.value) == msg - -def test_new_charp(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - x = newp(BCharA, 42) - assert len(x) == 42 - x = newp(BCharA, b"foobar") - assert len(x) == 7 - -def test_load_and_call_function(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BLong = new_primitive_type("long") - BFunc = new_function_type((BCharP,), BLong, False) - ll = find_and_load_library('c') - strlen = ll.load_function(BFunc, "strlen") - input = newp(new_array_type(BCharP, None), b"foobar") - assert strlen(input) == 6 - # - assert strlen(b"foobarbaz") == 9 - # - BVoidP = new_pointer_type(new_void_type()) - strlenaddr = ll.load_function(BVoidP, "strlen") - assert strlenaddr == cast(BVoidP, strlen) - -def test_read_variable(): - ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard - ## https://bugs.pypy.org/issue1643 - if not sys.platform.startswith("linux"): - py.test.skip("untested") - BVoidP = new_pointer_type(new_void_type()) - ll = find_and_load_library('c') - stderr = ll.read_variable(BVoidP, "stderr") - assert stderr == cast(BVoidP, _testfunc(8)) + assert str(e.value) == msg + +def test_new_charp(): + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BCharA = new_array_type(BCharP, None) + x = newp(BCharA, 42) + assert len(x) == 42 + x = newp(BCharA, b"foobar") + assert len(x) == 7 + +def test_load_and_call_function(): + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BLong = new_primitive_type("long") + BFunc = new_function_type((BCharP,), BLong, False) + ll = find_and_load_library('c') + strlen = ll.load_function(BFunc, "strlen") + input = newp(new_array_type(BCharP, None), b"foobar") + assert strlen(input) == 6 + # + assert strlen(b"foobarbaz") == 9 + # + BVoidP = new_pointer_type(new_void_type()) + strlenaddr = ll.load_function(BVoidP, "strlen") + assert strlenaddr == cast(BVoidP, strlen) + +def test_read_variable(): + ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard + ## https://bugs.pypy.org/issue1643 + if not sys.platform.startswith("linux"): + py.test.skip("untested") + BVoidP = new_pointer_type(new_void_type()) + ll = find_and_load_library('c') + stderr = ll.read_variable(BVoidP, "stderr") + assert stderr == cast(BVoidP, _testfunc(8)) # ll.close_lib() py.test.raises(ValueError, ll.read_variable, BVoidP, "stderr") - -def test_read_variable_as_unknown_length_array(): - ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard - ## https://bugs.pypy.org/issue1643 - if not sys.platform.startswith("linux"): - py.test.skip("untested") - BCharP = new_pointer_type(new_primitive_type("char")) - BArray = new_array_type(BCharP, None) - ll = find_and_load_library('c') - stderr = ll.read_variable(BArray, "stderr") - assert repr(stderr).startswith("<cdata 'char *' 0x") - # ^^ and not 'char[]', which is basically not allowed and would crash - -def test_write_variable(): - ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard - ## https://bugs.pypy.org/issue1643 - if not sys.platform.startswith("linux"): - py.test.skip("untested") - BVoidP = new_pointer_type(new_void_type()) - ll = find_and_load_library('c') - stderr = ll.read_variable(BVoidP, "stderr") - ll.write_variable(BVoidP, "stderr", cast(BVoidP, 0)) - assert ll.read_variable(BVoidP, "stderr") is not None - assert not ll.read_variable(BVoidP, "stderr") - ll.write_variable(BVoidP, "stderr", stderr) - assert ll.read_variable(BVoidP, "stderr") == stderr + +def test_read_variable_as_unknown_length_array(): + ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard + ## https://bugs.pypy.org/issue1643 + if not sys.platform.startswith("linux"): + py.test.skip("untested") + BCharP = new_pointer_type(new_primitive_type("char")) + BArray = new_array_type(BCharP, None) + ll = find_and_load_library('c') + stderr = ll.read_variable(BArray, "stderr") + assert repr(stderr).startswith("<cdata 'char *' 0x") + # ^^ and not 'char[]', which is basically not allowed and would crash + +def test_write_variable(): + ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard + ## https://bugs.pypy.org/issue1643 + if not sys.platform.startswith("linux"): + py.test.skip("untested") + BVoidP = new_pointer_type(new_void_type()) + ll = find_and_load_library('c') + stderr = ll.read_variable(BVoidP, "stderr") + ll.write_variable(BVoidP, "stderr", cast(BVoidP, 0)) + assert ll.read_variable(BVoidP, "stderr") is not None + assert not ll.read_variable(BVoidP, "stderr") + ll.write_variable(BVoidP, "stderr", stderr) + assert ll.read_variable(BVoidP, "stderr") == stderr # ll.close_lib() py.test.raises(ValueError, ll.write_variable, BVoidP, "stderr", stderr) - -def test_callback(): - BInt = new_primitive_type("int") - def make_callback(): - def cb(n): - return n + 1 - BFunc = new_function_type((BInt,), BInt, False) - return callback(BFunc, cb, 42) # 'cb' and 'BFunc' go out of scope - f = make_callback() - assert f(-142) == -141 - assert repr(f).startswith( - "<cdata 'int(*)(int)' calling <function ") - assert "cb at 0x" in repr(f) - e = py.test.raises(TypeError, f) - assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0" - -def test_callback_exception(): - try: - import cStringIO - except ImportError: - import io as cStringIO # Python 3 - import linecache + +def test_callback(): + BInt = new_primitive_type("int") + def make_callback(): + def cb(n): + return n + 1 + BFunc = new_function_type((BInt,), BInt, False) + return callback(BFunc, cb, 42) # 'cb' and 'BFunc' go out of scope + f = make_callback() + assert f(-142) == -141 + assert repr(f).startswith( + "<cdata 'int(*)(int)' calling <function ") + assert "cb at 0x" in repr(f) + e = py.test.raises(TypeError, f) + assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0" + +def test_callback_exception(): + try: + import cStringIO + except ImportError: + import io as cStringIO # Python 3 + import linecache def matches(istr, ipattern, ipattern38): if sys.version_info >= (3, 8): ipattern = ipattern38 - str, pattern = istr, ipattern - while '$' in pattern: - i = pattern.index('$') - assert str[:i] == pattern[:i] - j = str.find(pattern[i+1], i) - assert i + 1 <= j <= str.find('\n', i) - str = str[j:] - pattern = pattern[i+1:] - assert str == pattern - return True - def check_value(x): - if x == 10000: - raise ValueError(42) - def Zcb1(x): - check_value(x) - return x * 3 - BShort = new_primitive_type("short") - BFunc = new_function_type((BShort,), BShort, False) - f = callback(BFunc, Zcb1, -42) - # - seen = [] - oops_result = None - def oops(*args): - seen.append(args) - return oops_result - ff = callback(BFunc, Zcb1, -42, oops) - # - orig_stderr = sys.stderr - orig_getline = linecache.getline - try: - linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests - sys.stderr = cStringIO.StringIO() + str, pattern = istr, ipattern + while '$' in pattern: + i = pattern.index('$') + assert str[:i] == pattern[:i] + j = str.find(pattern[i+1], i) + assert i + 1 <= j <= str.find('\n', i) + str = str[j:] + pattern = pattern[i+1:] + assert str == pattern + return True + def check_value(x): + if x == 10000: + raise ValueError(42) + def Zcb1(x): + check_value(x) + return x * 3 + BShort = new_primitive_type("short") + BFunc = new_function_type((BShort,), BShort, False) + f = callback(BFunc, Zcb1, -42) + # + seen = [] + oops_result = None + def oops(*args): + seen.append(args) + return oops_result + ff = callback(BFunc, Zcb1, -42, oops) + # + orig_stderr = sys.stderr + orig_getline = linecache.getline + try: + linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests + sys.stderr = cStringIO.StringIO() if hasattr(sys, '__unraisablehook__'): # work around pytest sys.unraisablehook = sys.__unraisablehook__ # on recent CPythons - assert f(100) == 300 - assert sys.stderr.getvalue() == '' - assert f(10000) == -42 - assert matches(sys.stderr.getvalue(), """\ -From cffi callback <function$Zcb1 at 0x$>: -Traceback (most recent call last): - File "$", line $, in Zcb1 - $ - File "$", line $, in check_value - $ -ValueError: 42 + assert f(100) == 300 + assert sys.stderr.getvalue() == '' + assert f(10000) == -42 + assert matches(sys.stderr.getvalue(), """\ +From cffi callback <function$Zcb1 at 0x$>: +Traceback (most recent call last): + File "$", line $, in Zcb1 + $ + File "$", line $, in check_value + $ +ValueError: 42 """, """\ Exception ignored from cffi callback <function$Zcb1 at 0x$>: Traceback (most recent call last): @@ -1387,57 +1387,57 @@ Traceback (most recent call last): File "$", line $, in check_value $ ValueError: 42 -""") - sys.stderr = cStringIO.StringIO() - bigvalue = 20000 - assert f(bigvalue) == -42 - assert matches(sys.stderr.getvalue(), """\ -From cffi callback <function$Zcb1 at 0x$>: -Trying to convert the result back to C: -OverflowError: integer 60000 does not fit 'short' +""") + sys.stderr = cStringIO.StringIO() + bigvalue = 20000 + assert f(bigvalue) == -42 + assert matches(sys.stderr.getvalue(), """\ +From cffi callback <function$Zcb1 at 0x$>: +Trying to convert the result back to C: +OverflowError: integer 60000 does not fit 'short' """, """\ Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: Traceback (most recent call last): File "$", line $, in test_callback_exception $ OverflowError: integer 60000 does not fit 'short' -""") - sys.stderr = cStringIO.StringIO() - bigvalue = 20000 - assert len(seen) == 0 - assert ff(bigvalue) == -42 - assert sys.stderr.getvalue() == "" - assert len(seen) == 1 - exc, val, tb = seen[0] - assert exc is OverflowError - assert str(val) == "integer 60000 does not fit 'short'" - # - sys.stderr = cStringIO.StringIO() - bigvalue = 20000 - del seen[:] - oops_result = 81 - assert ff(bigvalue) == 81 - oops_result = None - assert sys.stderr.getvalue() == "" - assert len(seen) == 1 - exc, val, tb = seen[0] - assert exc is OverflowError - assert str(val) == "integer 60000 does not fit 'short'" - # - sys.stderr = cStringIO.StringIO() - bigvalue = 20000 - del seen[:] - oops_result = "xy" # not None and not an int! - assert ff(bigvalue) == -42 - oops_result = None - assert matches(sys.stderr.getvalue(), """\ -From cffi callback <function$Zcb1 at 0x$>: -Trying to convert the result back to C: -OverflowError: integer 60000 does not fit 'short' - -During the call to 'onerror', another exception occurred: - -TypeError: $integer$ +""") + sys.stderr = cStringIO.StringIO() + bigvalue = 20000 + assert len(seen) == 0 + assert ff(bigvalue) == -42 + assert sys.stderr.getvalue() == "" + assert len(seen) == 1 + exc, val, tb = seen[0] + assert exc is OverflowError + assert str(val) == "integer 60000 does not fit 'short'" + # + sys.stderr = cStringIO.StringIO() + bigvalue = 20000 + del seen[:] + oops_result = 81 + assert ff(bigvalue) == 81 + oops_result = None + assert sys.stderr.getvalue() == "" + assert len(seen) == 1 + exc, val, tb = seen[0] + assert exc is OverflowError + assert str(val) == "integer 60000 does not fit 'short'" + # + sys.stderr = cStringIO.StringIO() + bigvalue = 20000 + del seen[:] + oops_result = "xy" # not None and not an int! + assert ff(bigvalue) == -42 + oops_result = None + assert matches(sys.stderr.getvalue(), """\ +From cffi callback <function$Zcb1 at 0x$>: +Trying to convert the result back to C: +OverflowError: integer 60000 does not fit 'short' + +During the call to 'onerror', another exception occurred: + +TypeError: $integer$ """, """\ Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: Traceback (most recent call last): @@ -1449,23 +1449,23 @@ Traceback (most recent call last): File "$", line $, in test_callback_exception $ TypeError: $integer$ -""") - # - sys.stderr = cStringIO.StringIO() - seen = "not a list" # this makes the oops() function crash - assert ff(bigvalue) == -42 +""") + # + sys.stderr = cStringIO.StringIO() + seen = "not a list" # this makes the oops() function crash + assert ff(bigvalue) == -42 # the $ after the AttributeError message are for the suggestions that # will be added in Python 3.10 - assert matches(sys.stderr.getvalue(), """\ -From cffi callback <function$Zcb1 at 0x$>: -Trying to convert the result back to C: -OverflowError: integer 60000 does not fit 'short' - -During the call to 'onerror', another exception occurred: - -Traceback (most recent call last): - File "$", line $, in oops - $ + assert matches(sys.stderr.getvalue(), """\ +From cffi callback <function$Zcb1 at 0x$>: +Trying to convert the result back to C: +OverflowError: integer 60000 does not fit 'short' + +During the call to 'onerror', another exception occurred: + +Traceback (most recent call last): + File "$", line $, in oops + $ AttributeError: 'str' object has no attribute 'append$ """, """\ Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: @@ -1478,747 +1478,747 @@ Traceback (most recent call last): File "$", line $, in oops $ AttributeError: 'str' object has no attribute 'append$ -""") - finally: - sys.stderr = orig_stderr - linecache.getline = orig_getline - -def test_callback_return_type(): - for rettype in ["signed char", "short", "int", "long", "long long", - "unsigned char", "unsigned short", "unsigned int", - "unsigned long", "unsigned long long"]: - BRet = new_primitive_type(rettype) - def cb(n): - return n + 1 - BFunc = new_function_type((BRet,), BRet) - f = callback(BFunc, cb, 42) - assert f(41) == 42 - if rettype.startswith("unsigned "): - min = 0 - max = (1 << (8*sizeof(BRet))) - 1 - else: - min = -(1 << (8*sizeof(BRet)-1)) - max = (1 << (8*sizeof(BRet)-1)) - 1 - assert f(min) == min + 1 - assert f(max - 1) == max - assert f(max) == 42 - -def test_a_lot_of_callbacks(): - BIGNUM = 10000 - if 'PY_DOT_PY' in globals(): BIGNUM = 100 # tests on py.py - # - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt,), BInt, False) - def make_callback(m): - def cb(n): - return n + m +""") + finally: + sys.stderr = orig_stderr + linecache.getline = orig_getline + +def test_callback_return_type(): + for rettype in ["signed char", "short", "int", "long", "long long", + "unsigned char", "unsigned short", "unsigned int", + "unsigned long", "unsigned long long"]: + BRet = new_primitive_type(rettype) + def cb(n): + return n + 1 + BFunc = new_function_type((BRet,), BRet) + f = callback(BFunc, cb, 42) + assert f(41) == 42 + if rettype.startswith("unsigned "): + min = 0 + max = (1 << (8*sizeof(BRet))) - 1 + else: + min = -(1 << (8*sizeof(BRet)-1)) + max = (1 << (8*sizeof(BRet)-1)) - 1 + assert f(min) == min + 1 + assert f(max - 1) == max + assert f(max) == 42 + +def test_a_lot_of_callbacks(): + BIGNUM = 10000 + if 'PY_DOT_PY' in globals(): BIGNUM = 100 # tests on py.py + # + BInt = new_primitive_type("int") + BFunc = new_function_type((BInt,), BInt, False) + def make_callback(m): + def cb(n): + return n + m return callback(BFunc, cb, 42) # 'cb' goes out of scope - # - flist = [make_callback(i) for i in range(BIGNUM)] - for i, f in enumerate(flist): - assert f(-142) == -142 + i - -def test_callback_receiving_tiny_struct(): - BSChar = new_primitive_type("signed char") - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BSChar, -1), - ('b', BSChar, -1)]) - def cb(s): - return s.a + 10 * s.b - BFunc = new_function_type((BStruct,), BInt) - f = callback(BFunc, cb) - p = newp(BStructPtr, [-2, -4]) - n = f(p[0]) - assert n == -42 - -def test_callback_returning_tiny_struct(): - BSChar = new_primitive_type("signed char") - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BSChar, -1), - ('b', BSChar, -1)]) - def cb(n): - return newp(BStructPtr, [-n, -3*n])[0] - BFunc = new_function_type((BInt,), BStruct) - f = callback(BFunc, cb) - s = f(10) - assert typeof(s) is BStruct - assert repr(s) == "<cdata 'struct foo' owning 2 bytes>" - assert s.a == -10 - assert s.b == -30 - -def test_callback_receiving_struct(): - BSChar = new_primitive_type("signed char") - BInt = new_primitive_type("int") - BDouble = new_primitive_type("double") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BSChar, -1), - ('b', BDouble, -1)]) - def cb(s): - return s.a + int(s.b) - BFunc = new_function_type((BStruct,), BInt) - f = callback(BFunc, cb) - p = newp(BStructPtr, [-2, 44.444]) - n = f(p[0]) - assert n == 42 - -def test_callback_returning_struct(): - BSChar = new_primitive_type("signed char") - BInt = new_primitive_type("int") - BDouble = new_primitive_type("double") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BSChar, -1), - ('b', BDouble, -1)]) - def cb(n): - return newp(BStructPtr, [-n, 1E-42])[0] - BFunc = new_function_type((BInt,), BStruct) - f = callback(BFunc, cb) - s = f(10) - assert typeof(s) is BStruct - assert repr(s) in ["<cdata 'struct foo' owning 12 bytes>", - "<cdata 'struct foo' owning 16 bytes>"] - assert s.a == -10 - assert s.b == 1E-42 - -def test_callback_receiving_big_struct(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BInt, -1), - ('b', BInt, -1), - ('c', BInt, -1), - ('d', BInt, -1), - ('e', BInt, -1), - ('f', BInt, -1), - ('g', BInt, -1), - ('h', BInt, -1), - ('i', BInt, -1), - ('j', BInt, -1)]) - def cb(s): - for i, name in enumerate("abcdefghij"): - assert getattr(s, name) == 13 - i - return 42 - BFunc = new_function_type((BStruct,), BInt) - f = callback(BFunc, cb) - p = newp(BStructPtr, list(range(13, 3, -1))) - n = f(p[0]) - assert n == 42 - -def test_callback_returning_big_struct(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BInt, -1), - ('b', BInt, -1), - ('c', BInt, -1), - ('d', BInt, -1), - ('e', BInt, -1), - ('f', BInt, -1), - ('g', BInt, -1), - ('h', BInt, -1), - ('i', BInt, -1), - ('j', BInt, -1)]) - def cb(): - return newp(BStructPtr, list(range(13, 3, -1)))[0] - BFunc = new_function_type((), BStruct) - f = callback(BFunc, cb) - s = f() - assert typeof(s) is BStruct - assert repr(s) in ["<cdata 'struct foo' owning 40 bytes>", - "<cdata 'struct foo' owning 80 bytes>"] - for i, name in enumerate("abcdefghij"): - assert getattr(s, name) == 13 - i - -def test_callback_returning_void(): - BVoid = new_void_type() - BFunc = new_function_type((), BVoid, False) - def cb(): - seen.append(42) - f = callback(BFunc, cb) - seen = [] - f() - assert seen == [42] - py.test.raises(TypeError, callback, BFunc, cb, -42) - -def test_enum_type(): - BUInt = new_primitive_type("unsigned int") - BEnum = new_enum_type("foo", (), (), BUInt) - assert repr(BEnum) == "<ctype 'foo'>" - assert BEnum.kind == "enum" - assert BEnum.cname == "foo" - assert BEnum.elements == {} - # - BInt = new_primitive_type("int") - BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) - assert BEnum.kind == "enum" - assert BEnum.cname == "enum foo" - assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'} - # 'elements' is not the real dict, but merely a copy - BEnum.elements[2] = '??' - assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'} - # - BEnum = new_enum_type("enum bar", ('ab', 'cd'), (5, 5), BUInt) - assert BEnum.elements == {5: 'ab'} - assert BEnum.relements == {'ab': 5, 'cd': 5} - -def test_cast_to_enum(): - BInt = new_primitive_type("int") - BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) - assert sizeof(BEnum) == sizeof(BInt) - e = cast(BEnum, 0) - assert repr(e) == "<cdata 'enum foo' 0: def>" - assert repr(cast(BEnum, -42)) == "<cdata 'enum foo' -42>" - assert repr(cast(BEnum, -20)) == "<cdata 'enum foo' -20: ab>" - assert string(e) == 'def' - assert string(cast(BEnum, -20)) == 'ab' - assert int(cast(BEnum, 1)) == 1 - assert int(cast(BEnum, 0)) == 0 - assert int(cast(BEnum, -242 + 2**128)) == -242 - assert string(cast(BEnum, -242 + 2**128)) == '-242' - # - BUInt = new_primitive_type("unsigned int") - BEnum = new_enum_type("enum bar", ('def', 'c', 'ab'), (0, 1, 20), BUInt) - e = cast(BEnum, -1) - assert repr(e) == "<cdata 'enum bar' 4294967295>" # unsigned int - # - BLong = new_primitive_type("long") - BEnum = new_enum_type("enum baz", (), (), BLong) - assert sizeof(BEnum) == sizeof(BLong) - e = cast(BEnum, -1) - assert repr(e) == "<cdata 'enum baz' -1>" - -def test_enum_with_non_injective_mapping(): - BInt = new_primitive_type("int") - BEnum = new_enum_type("enum foo", ('ab', 'cd'), (7, 7), BInt) - e = cast(BEnum, 7) - assert repr(e) == "<cdata 'enum foo' 7: ab>" - assert string(e) == 'ab' - -def test_enum_in_struct(): - BInt = new_primitive_type("int") - BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) - BStruct = new_struct_type("struct bar") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BEnum, -1)]) - p = newp(BStructPtr, [-20]) - assert p.a1 == -20 - p = newp(BStructPtr, [12]) - assert p.a1 == 12 - e = py.test.raises(TypeError, newp, BStructPtr, [None]) - msg = str(e.value) - assert ("an integer is required" in msg or # CPython - "unsupported operand type for int(): 'NoneType'" in msg or # old PyPys - "expected integer, got NoneType object" in msg) # newer PyPys + # + flist = [make_callback(i) for i in range(BIGNUM)] + for i, f in enumerate(flist): + assert f(-142) == -142 + i + +def test_callback_receiving_tiny_struct(): + BSChar = new_primitive_type("signed char") + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a', BSChar, -1), + ('b', BSChar, -1)]) + def cb(s): + return s.a + 10 * s.b + BFunc = new_function_type((BStruct,), BInt) + f = callback(BFunc, cb) + p = newp(BStructPtr, [-2, -4]) + n = f(p[0]) + assert n == -42 + +def test_callback_returning_tiny_struct(): + BSChar = new_primitive_type("signed char") + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a', BSChar, -1), + ('b', BSChar, -1)]) + def cb(n): + return newp(BStructPtr, [-n, -3*n])[0] + BFunc = new_function_type((BInt,), BStruct) + f = callback(BFunc, cb) + s = f(10) + assert typeof(s) is BStruct + assert repr(s) == "<cdata 'struct foo' owning 2 bytes>" + assert s.a == -10 + assert s.b == -30 + +def test_callback_receiving_struct(): + BSChar = new_primitive_type("signed char") + BInt = new_primitive_type("int") + BDouble = new_primitive_type("double") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a', BSChar, -1), + ('b', BDouble, -1)]) + def cb(s): + return s.a + int(s.b) + BFunc = new_function_type((BStruct,), BInt) + f = callback(BFunc, cb) + p = newp(BStructPtr, [-2, 44.444]) + n = f(p[0]) + assert n == 42 + +def test_callback_returning_struct(): + BSChar = new_primitive_type("signed char") + BInt = new_primitive_type("int") + BDouble = new_primitive_type("double") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a', BSChar, -1), + ('b', BDouble, -1)]) + def cb(n): + return newp(BStructPtr, [-n, 1E-42])[0] + BFunc = new_function_type((BInt,), BStruct) + f = callback(BFunc, cb) + s = f(10) + assert typeof(s) is BStruct + assert repr(s) in ["<cdata 'struct foo' owning 12 bytes>", + "<cdata 'struct foo' owning 16 bytes>"] + assert s.a == -10 + assert s.b == 1E-42 + +def test_callback_receiving_big_struct(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a', BInt, -1), + ('b', BInt, -1), + ('c', BInt, -1), + ('d', BInt, -1), + ('e', BInt, -1), + ('f', BInt, -1), + ('g', BInt, -1), + ('h', BInt, -1), + ('i', BInt, -1), + ('j', BInt, -1)]) + def cb(s): + for i, name in enumerate("abcdefghij"): + assert getattr(s, name) == 13 - i + return 42 + BFunc = new_function_type((BStruct,), BInt) + f = callback(BFunc, cb) + p = newp(BStructPtr, list(range(13, 3, -1))) + n = f(p[0]) + assert n == 42 + +def test_callback_returning_big_struct(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a', BInt, -1), + ('b', BInt, -1), + ('c', BInt, -1), + ('d', BInt, -1), + ('e', BInt, -1), + ('f', BInt, -1), + ('g', BInt, -1), + ('h', BInt, -1), + ('i', BInt, -1), + ('j', BInt, -1)]) + def cb(): + return newp(BStructPtr, list(range(13, 3, -1)))[0] + BFunc = new_function_type((), BStruct) + f = callback(BFunc, cb) + s = f() + assert typeof(s) is BStruct + assert repr(s) in ["<cdata 'struct foo' owning 40 bytes>", + "<cdata 'struct foo' owning 80 bytes>"] + for i, name in enumerate("abcdefghij"): + assert getattr(s, name) == 13 - i + +def test_callback_returning_void(): + BVoid = new_void_type() + BFunc = new_function_type((), BVoid, False) + def cb(): + seen.append(42) + f = callback(BFunc, cb) + seen = [] + f() + assert seen == [42] + py.test.raises(TypeError, callback, BFunc, cb, -42) + +def test_enum_type(): + BUInt = new_primitive_type("unsigned int") + BEnum = new_enum_type("foo", (), (), BUInt) + assert repr(BEnum) == "<ctype 'foo'>" + assert BEnum.kind == "enum" + assert BEnum.cname == "foo" + assert BEnum.elements == {} + # + BInt = new_primitive_type("int") + BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) + assert BEnum.kind == "enum" + assert BEnum.cname == "enum foo" + assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'} + # 'elements' is not the real dict, but merely a copy + BEnum.elements[2] = '??' + assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'} + # + BEnum = new_enum_type("enum bar", ('ab', 'cd'), (5, 5), BUInt) + assert BEnum.elements == {5: 'ab'} + assert BEnum.relements == {'ab': 5, 'cd': 5} + +def test_cast_to_enum(): + BInt = new_primitive_type("int") + BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) + assert sizeof(BEnum) == sizeof(BInt) + e = cast(BEnum, 0) + assert repr(e) == "<cdata 'enum foo' 0: def>" + assert repr(cast(BEnum, -42)) == "<cdata 'enum foo' -42>" + assert repr(cast(BEnum, -20)) == "<cdata 'enum foo' -20: ab>" + assert string(e) == 'def' + assert string(cast(BEnum, -20)) == 'ab' + assert int(cast(BEnum, 1)) == 1 + assert int(cast(BEnum, 0)) == 0 + assert int(cast(BEnum, -242 + 2**128)) == -242 + assert string(cast(BEnum, -242 + 2**128)) == '-242' + # + BUInt = new_primitive_type("unsigned int") + BEnum = new_enum_type("enum bar", ('def', 'c', 'ab'), (0, 1, 20), BUInt) + e = cast(BEnum, -1) + assert repr(e) == "<cdata 'enum bar' 4294967295>" # unsigned int + # + BLong = new_primitive_type("long") + BEnum = new_enum_type("enum baz", (), (), BLong) + assert sizeof(BEnum) == sizeof(BLong) + e = cast(BEnum, -1) + assert repr(e) == "<cdata 'enum baz' -1>" + +def test_enum_with_non_injective_mapping(): + BInt = new_primitive_type("int") + BEnum = new_enum_type("enum foo", ('ab', 'cd'), (7, 7), BInt) + e = cast(BEnum, 7) + assert repr(e) == "<cdata 'enum foo' 7: ab>" + assert string(e) == 'ab' + +def test_enum_in_struct(): + BInt = new_primitive_type("int") + BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) + BStruct = new_struct_type("struct bar") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BEnum, -1)]) + p = newp(BStructPtr, [-20]) + assert p.a1 == -20 + p = newp(BStructPtr, [12]) + assert p.a1 == 12 + e = py.test.raises(TypeError, newp, BStructPtr, [None]) + msg = str(e.value) + assert ("an integer is required" in msg or # CPython + "unsupported operand type for int(): 'NoneType'" in msg or # old PyPys + "expected integer, got NoneType object" in msg) # newer PyPys with pytest.raises(TypeError): p.a1 = "def" - if sys.version_info < (3,): - BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,), BInt) - assert string(cast(BEnum2, 5)) == 'abc' - assert type(string(cast(BEnum2, 5))) is str - -def test_enum_overflow(): - max_uint = 2 ** (size_of_int()*8) - 1 - max_int = max_uint // 2 - max_ulong = 2 ** (size_of_long()*8) - 1 - max_long = max_ulong // 2 - for BPrimitive in [new_primitive_type("int"), - new_primitive_type("unsigned int"), - new_primitive_type("long"), - new_primitive_type("unsigned long")]: - for x in [max_uint, max_int, max_ulong, max_long]: - for testcase in [x, x+1, -x-1, -x-2]: - if int(cast(BPrimitive, testcase)) == testcase: - # fits - BEnum = new_enum_type("foo", ("AA",), (testcase,), - BPrimitive) - assert int(cast(BEnum, testcase)) == testcase - else: - # overflows - py.test.raises(OverflowError, new_enum_type, - "foo", ("AA",), (testcase,), BPrimitive) - -def test_callback_returning_enum(): - BInt = new_primitive_type("int") - BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) - def cb(n): - if n & 1: - return cast(BEnum, n) - else: - return n - BFunc = new_function_type((BInt,), BEnum) - f = callback(BFunc, cb) - assert f(0) == 0 - assert f(1) == 1 - assert f(-20) == -20 - assert f(20) == 20 - assert f(21) == 21 - -def test_callback_returning_enum_unsigned(): - BInt = new_primitive_type("int") - BUInt = new_primitive_type("unsigned int") - BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, 20), BUInt) - def cb(n): - if n & 1: - return cast(BEnum, n) - else: - return n - BFunc = new_function_type((BInt,), BEnum) - f = callback(BFunc, cb) - assert f(0) == 0 - assert f(1) == 1 - assert f(-21) == 2**32 - 21 - assert f(20) == 20 - assert f(21) == 21 - -def test_callback_returning_char(): - BInt = new_primitive_type("int") - BChar = new_primitive_type("char") - def cb(n): - return bytechr(n) - BFunc = new_function_type((BInt,), BChar) - f = callback(BFunc, cb) - assert f(0) == b'\x00' - assert f(255) == b'\xFF' - -def _hacked_pypy_uni4(): - pyuni4 = {1: True, 2: False}[len(u+'\U00012345')] - return 'PY_DOT_PY' in globals() and not pyuni4 - -def test_callback_returning_wchar_t(): - BInt = new_primitive_type("int") - BWChar = new_primitive_type("wchar_t") - def cb(n): - if n == -1: - return u+'\U00012345' - if n == -2: - raise ValueError - return unichr(n) - BFunc = new_function_type((BInt,), BWChar) - f = callback(BFunc, cb) - assert f(0) == unichr(0) - assert f(255) == unichr(255) - assert f(0x1234) == u+'\u1234' - if sizeof(BWChar) == 4 and not _hacked_pypy_uni4(): - assert f(-1) == u+'\U00012345' - assert f(-2) == u+'\x00' # and an exception printed to stderr - -def test_struct_with_bitfields(): - BLong = new_primitive_type("long") - BStruct = new_struct_type("struct foo") - LONGBITS = 8 * sizeof(BLong) - complete_struct_or_union(BStruct, [('a1', BLong, 1), - ('a2', BLong, 2), - ('a3', BLong, 3), - ('a4', BLong, LONGBITS - 5)]) - d = BStruct.fields - assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0 - assert d[3][1].offset == sizeof(BLong) - def f(m, r): - if sys.byteorder == 'little': - return r - else: - return LONGBITS - m - r - assert d[0][1].bitshift == f(1, 0) - assert d[0][1].bitsize == 1 - assert d[1][1].bitshift == f(2, 1) - assert d[1][1].bitsize == 2 - assert d[2][1].bitshift == f(3, 3) - assert d[2][1].bitsize == 3 - assert d[3][1].bitshift == f(LONGBITS - 5, 0) - assert d[3][1].bitsize == LONGBITS - 5 - assert sizeof(BStruct) == 2 * sizeof(BLong) - assert alignof(BStruct) == alignof(BLong) - -def test_bitfield_instance(): - BInt = new_primitive_type("int") - BUnsignedInt = new_primitive_type("unsigned int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BInt, 1), - ('a2', BUnsignedInt, 2), - ('a3', BInt, 3)]) - p = newp(new_pointer_type(BStruct), None) - p.a1 = -1 - assert p.a1 == -1 - p.a1 = 0 + if sys.version_info < (3,): + BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,), BInt) + assert string(cast(BEnum2, 5)) == 'abc' + assert type(string(cast(BEnum2, 5))) is str + +def test_enum_overflow(): + max_uint = 2 ** (size_of_int()*8) - 1 + max_int = max_uint // 2 + max_ulong = 2 ** (size_of_long()*8) - 1 + max_long = max_ulong // 2 + for BPrimitive in [new_primitive_type("int"), + new_primitive_type("unsigned int"), + new_primitive_type("long"), + new_primitive_type("unsigned long")]: + for x in [max_uint, max_int, max_ulong, max_long]: + for testcase in [x, x+1, -x-1, -x-2]: + if int(cast(BPrimitive, testcase)) == testcase: + # fits + BEnum = new_enum_type("foo", ("AA",), (testcase,), + BPrimitive) + assert int(cast(BEnum, testcase)) == testcase + else: + # overflows + py.test.raises(OverflowError, new_enum_type, + "foo", ("AA",), (testcase,), BPrimitive) + +def test_callback_returning_enum(): + BInt = new_primitive_type("int") + BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) + def cb(n): + if n & 1: + return cast(BEnum, n) + else: + return n + BFunc = new_function_type((BInt,), BEnum) + f = callback(BFunc, cb) + assert f(0) == 0 + assert f(1) == 1 + assert f(-20) == -20 + assert f(20) == 20 + assert f(21) == 21 + +def test_callback_returning_enum_unsigned(): + BInt = new_primitive_type("int") + BUInt = new_primitive_type("unsigned int") + BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, 20), BUInt) + def cb(n): + if n & 1: + return cast(BEnum, n) + else: + return n + BFunc = new_function_type((BInt,), BEnum) + f = callback(BFunc, cb) + assert f(0) == 0 + assert f(1) == 1 + assert f(-21) == 2**32 - 21 + assert f(20) == 20 + assert f(21) == 21 + +def test_callback_returning_char(): + BInt = new_primitive_type("int") + BChar = new_primitive_type("char") + def cb(n): + return bytechr(n) + BFunc = new_function_type((BInt,), BChar) + f = callback(BFunc, cb) + assert f(0) == b'\x00' + assert f(255) == b'\xFF' + +def _hacked_pypy_uni4(): + pyuni4 = {1: True, 2: False}[len(u+'\U00012345')] + return 'PY_DOT_PY' in globals() and not pyuni4 + +def test_callback_returning_wchar_t(): + BInt = new_primitive_type("int") + BWChar = new_primitive_type("wchar_t") + def cb(n): + if n == -1: + return u+'\U00012345' + if n == -2: + raise ValueError + return unichr(n) + BFunc = new_function_type((BInt,), BWChar) + f = callback(BFunc, cb) + assert f(0) == unichr(0) + assert f(255) == unichr(255) + assert f(0x1234) == u+'\u1234' + if sizeof(BWChar) == 4 and not _hacked_pypy_uni4(): + assert f(-1) == u+'\U00012345' + assert f(-2) == u+'\x00' # and an exception printed to stderr + +def test_struct_with_bitfields(): + BLong = new_primitive_type("long") + BStruct = new_struct_type("struct foo") + LONGBITS = 8 * sizeof(BLong) + complete_struct_or_union(BStruct, [('a1', BLong, 1), + ('a2', BLong, 2), + ('a3', BLong, 3), + ('a4', BLong, LONGBITS - 5)]) + d = BStruct.fields + assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0 + assert d[3][1].offset == sizeof(BLong) + def f(m, r): + if sys.byteorder == 'little': + return r + else: + return LONGBITS - m - r + assert d[0][1].bitshift == f(1, 0) + assert d[0][1].bitsize == 1 + assert d[1][1].bitshift == f(2, 1) + assert d[1][1].bitsize == 2 + assert d[2][1].bitshift == f(3, 3) + assert d[2][1].bitsize == 3 + assert d[3][1].bitshift == f(LONGBITS - 5, 0) + assert d[3][1].bitsize == LONGBITS - 5 + assert sizeof(BStruct) == 2 * sizeof(BLong) + assert alignof(BStruct) == alignof(BLong) + +def test_bitfield_instance(): + BInt = new_primitive_type("int") + BUnsignedInt = new_primitive_type("unsigned int") + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, [('a1', BInt, 1), + ('a2', BUnsignedInt, 2), + ('a3', BInt, 3)]) + p = newp(new_pointer_type(BStruct), None) + p.a1 = -1 + assert p.a1 == -1 + p.a1 = 0 with pytest.raises(OverflowError): p.a1 = 2 - assert p.a1 == 0 - # - p.a1 = -1 - p.a2 = 3 - p.a3 = -4 + assert p.a1 == 0 + # + p.a1 = -1 + p.a2 = 3 + p.a3 = -4 with pytest.raises(OverflowError): p.a3 = 4 with pytest.raises(OverflowError) as e: p.a3 = -5 - assert str(e.value) == ("value -5 outside the range allowed by the " - "bit field width: -4 <= x <= 3") - assert p.a1 == -1 and p.a2 == 3 and p.a3 == -4 - # - # special case for convenience: "int x:1", while normally signed, - # allows also setting the value "1" (it still gets read back as -1) - p.a1 = 1 - assert p.a1 == -1 + assert str(e.value) == ("value -5 outside the range allowed by the " + "bit field width: -4 <= x <= 3") + assert p.a1 == -1 and p.a2 == 3 and p.a3 == -4 + # + # special case for convenience: "int x:1", while normally signed, + # allows also setting the value "1" (it still gets read back as -1) + p.a1 = 1 + assert p.a1 == -1 with pytest.raises(OverflowError) as e: p.a1 = -2 - assert str(e.value) == ("value -2 outside the range allowed by the " - "bit field width: -1 <= x <= 1") - -def test_bitfield_instance_init(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BInt, 1)]) - p = newp(new_pointer_type(BStruct), [-1]) - assert p.a1 == -1 - p = newp(new_pointer_type(BStruct), {'a1': -1}) - assert p.a1 == -1 - # - BUnion = new_union_type("union bar") - complete_struct_or_union(BUnion, [('a1', BInt, 1)]) - p = newp(new_pointer_type(BUnion), [-1]) - assert p.a1 == -1 - -def test_weakref(): - import _weakref - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - rlist = [_weakref.ref(BInt), - _weakref.ref(newp(BPtr, 42)), - _weakref.ref(cast(BPtr, 42)), - _weakref.ref(cast(BInt, 42)), - _weakref.ref(buffer(newp(BPtr, 42))), - ] - for i in range(5): - import gc; gc.collect() - if [r() for r in rlist] == [None for r in rlist]: - break - -def test_no_inheritance(): - BInt = new_primitive_type("int") - try: - class foo(type(BInt)): pass - except TypeError: - pass - else: - raise AssertionError - x = cast(BInt, 42) - try: - class foo(type(x)): pass - except TypeError: - pass - else: - raise AssertionError - -def test_assign_string(): - BChar = new_primitive_type("char") - BArray1 = new_array_type(new_pointer_type(BChar), 5) - BArray2 = new_array_type(new_pointer_type(BArray1), 5) - a = newp(BArray2, [b"abc", b"de", b"ghij"]) - assert string(a[1]) == b"de" - assert string(a[2]) == b"ghij" - a[2] = b"." - assert string(a[2]) == b"." - a[2] = b"12345" - assert string(a[2]) == b"12345" + assert str(e.value) == ("value -2 outside the range allowed by the " + "bit field width: -1 <= x <= 1") + +def test_bitfield_instance_init(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, [('a1', BInt, 1)]) + p = newp(new_pointer_type(BStruct), [-1]) + assert p.a1 == -1 + p = newp(new_pointer_type(BStruct), {'a1': -1}) + assert p.a1 == -1 + # + BUnion = new_union_type("union bar") + complete_struct_or_union(BUnion, [('a1', BInt, 1)]) + p = newp(new_pointer_type(BUnion), [-1]) + assert p.a1 == -1 + +def test_weakref(): + import _weakref + BInt = new_primitive_type("int") + BPtr = new_pointer_type(BInt) + rlist = [_weakref.ref(BInt), + _weakref.ref(newp(BPtr, 42)), + _weakref.ref(cast(BPtr, 42)), + _weakref.ref(cast(BInt, 42)), + _weakref.ref(buffer(newp(BPtr, 42))), + ] + for i in range(5): + import gc; gc.collect() + if [r() for r in rlist] == [None for r in rlist]: + break + +def test_no_inheritance(): + BInt = new_primitive_type("int") + try: + class foo(type(BInt)): pass + except TypeError: + pass + else: + raise AssertionError + x = cast(BInt, 42) + try: + class foo(type(x)): pass + except TypeError: + pass + else: + raise AssertionError + +def test_assign_string(): + BChar = new_primitive_type("char") + BArray1 = new_array_type(new_pointer_type(BChar), 5) + BArray2 = new_array_type(new_pointer_type(BArray1), 5) + a = newp(BArray2, [b"abc", b"de", b"ghij"]) + assert string(a[1]) == b"de" + assert string(a[2]) == b"ghij" + a[2] = b"." + assert string(a[2]) == b"." + a[2] = b"12345" + assert string(a[2]) == b"12345" with pytest.raises(IndexError) as e: a[2] = b"123456" - assert 'char[5]' in str(e.value) - assert 'got 6 characters' in str(e.value) - -def test_add_error(): - x = cast(new_primitive_type("int"), 42) + assert 'char[5]' in str(e.value) + assert 'got 6 characters' in str(e.value) + +def test_add_error(): + x = cast(new_primitive_type("int"), 42) with pytest.raises(TypeError): x + 1 with pytest.raises(TypeError): x - 1 - -def test_void_errors(): - py.test.raises(ValueError, alignof, new_void_type()) - py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None) - -def test_too_many_items(): - BChar = new_primitive_type("char") - BArray = new_array_type(new_pointer_type(BChar), 5) - py.test.raises(IndexError, newp, BArray, tuple(b'123456')) - py.test.raises(IndexError, newp, BArray, list(b'123456')) - py.test.raises(IndexError, newp, BArray, b'123456') - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, []) - py.test.raises(TypeError, newp, new_pointer_type(BStruct), b'') - py.test.raises(ValueError, newp, new_pointer_type(BStruct), [b'1']) - -def test_more_type_errors(): - BInt = new_primitive_type("int") - BChar = new_primitive_type("char") - BArray = new_array_type(new_pointer_type(BChar), 5) - py.test.raises(TypeError, newp, BArray, 12.34) - BArray = new_array_type(new_pointer_type(BInt), 5) - py.test.raises(TypeError, newp, BArray, 12.34) - BFloat = new_primitive_type("float") - py.test.raises(TypeError, cast, BFloat, newp(BArray, None)) - -def test_more_overflow_errors(): - BUInt = new_primitive_type("unsigned int") - py.test.raises(OverflowError, newp, new_pointer_type(BUInt), -1) - py.test.raises(OverflowError, newp, new_pointer_type(BUInt), 2**32) - -def test_newp_copying(): - """Test that we can do newp(<type>, <cdata of the given type>) for most + +def test_void_errors(): + py.test.raises(ValueError, alignof, new_void_type()) + py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None) + +def test_too_many_items(): + BChar = new_primitive_type("char") + BArray = new_array_type(new_pointer_type(BChar), 5) + py.test.raises(IndexError, newp, BArray, tuple(b'123456')) + py.test.raises(IndexError, newp, BArray, list(b'123456')) + py.test.raises(IndexError, newp, BArray, b'123456') + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, []) + py.test.raises(TypeError, newp, new_pointer_type(BStruct), b'') + py.test.raises(ValueError, newp, new_pointer_type(BStruct), [b'1']) + +def test_more_type_errors(): + BInt = new_primitive_type("int") + BChar = new_primitive_type("char") + BArray = new_array_type(new_pointer_type(BChar), 5) + py.test.raises(TypeError, newp, BArray, 12.34) + BArray = new_array_type(new_pointer_type(BInt), 5) + py.test.raises(TypeError, newp, BArray, 12.34) + BFloat = new_primitive_type("float") + py.test.raises(TypeError, cast, BFloat, newp(BArray, None)) + +def test_more_overflow_errors(): + BUInt = new_primitive_type("unsigned int") + py.test.raises(OverflowError, newp, new_pointer_type(BUInt), -1) + py.test.raises(OverflowError, newp, new_pointer_type(BUInt), 2**32) + +def test_newp_copying(): + """Test that we can do newp(<type>, <cdata of the given type>) for most types, including same-type arrays. - """ - BInt = new_primitive_type("int") - p = newp(new_pointer_type(BInt), cast(BInt, 42)) - assert p[0] == 42 - # - BUInt = new_primitive_type("unsigned int") - p = newp(new_pointer_type(BUInt), cast(BUInt, 42)) - assert p[0] == 42 - # - BChar = new_primitive_type("char") - p = newp(new_pointer_type(BChar), cast(BChar, '!')) - assert p[0] == b'!' - # - BFloat = new_primitive_type("float") - p = newp(new_pointer_type(BFloat), cast(BFloat, 12.25)) - assert p[0] == 12.25 - # - BStruct = new_struct_type("struct foo_s") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BInt, -1)]) - s1 = newp(BStructPtr, [42]) - p1 = newp(new_pointer_type(BStructPtr), s1) - assert p1[0] == s1 - # - BArray = new_array_type(new_pointer_type(BInt), None) - a1 = newp(BArray, [1, 2, 3, 4]) - py.test.raises(TypeError, newp, BArray, a1) - BArray6 = new_array_type(new_pointer_type(BInt), 6) + """ + BInt = new_primitive_type("int") + p = newp(new_pointer_type(BInt), cast(BInt, 42)) + assert p[0] == 42 + # + BUInt = new_primitive_type("unsigned int") + p = newp(new_pointer_type(BUInt), cast(BUInt, 42)) + assert p[0] == 42 + # + BChar = new_primitive_type("char") + p = newp(new_pointer_type(BChar), cast(BChar, '!')) + assert p[0] == b'!' + # + BFloat = new_primitive_type("float") + p = newp(new_pointer_type(BFloat), cast(BFloat, 12.25)) + assert p[0] == 12.25 + # + BStruct = new_struct_type("struct foo_s") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BInt, -1)]) + s1 = newp(BStructPtr, [42]) + p1 = newp(new_pointer_type(BStructPtr), s1) + assert p1[0] == s1 + # + BArray = new_array_type(new_pointer_type(BInt), None) + a1 = newp(BArray, [1, 2, 3, 4]) + py.test.raises(TypeError, newp, BArray, a1) + BArray6 = new_array_type(new_pointer_type(BInt), 6) a1 = newp(BArray6, [10, 20, 30]) a2 = newp(BArray6, a1) assert list(a2) == [10, 20, 30, 0, 0, 0] - # - s1 = newp(BStructPtr, [42]) - s2 = newp(BStructPtr, s1[0]) - assert s2.a1 == 42 - # - BUnion = new_union_type("union foo_u") - BUnionPtr = new_pointer_type(BUnion) - complete_struct_or_union(BUnion, [('a1', BInt, -1)]) - u1 = newp(BUnionPtr, [42]) - u2 = newp(BUnionPtr, u1[0]) - assert u2.a1 == 42 - # - BFunc = new_function_type((BInt,), BUInt) - p1 = cast(BFunc, 42) - p2 = newp(new_pointer_type(BFunc), p1) - assert p2[0] == p1 - -def test_string(): - BChar = new_primitive_type("char") - assert string(cast(BChar, 42)) == b'*' - assert string(cast(BChar, 0)) == b'\x00' - BCharP = new_pointer_type(BChar) - BArray = new_array_type(BCharP, 10) - a = newp(BArray, b"hello") - assert len(a) == 10 - assert string(a) == b"hello" - p = a + 2 - assert string(p) == b"llo" - assert string(newp(new_array_type(BCharP, 4), b"abcd")) == b"abcd" - py.test.raises(RuntimeError, string, cast(BCharP, 0)) - assert string(a, 4) == b"hell" - assert string(a, 5) == b"hello" - assert string(a, 6) == b"hello" - -def test_string_byte(): - BByte = new_primitive_type("signed char") - assert string(cast(BByte, 42)) == b'*' - assert string(cast(BByte, 0)) == b'\x00' - BArray = new_array_type(new_pointer_type(BByte), None) - a = newp(BArray, [65, 66, 67]) - assert type(string(a)) is bytes and string(a) == b'ABC' - # - BByte = new_primitive_type("unsigned char") - assert string(cast(BByte, 42)) == b'*' - assert string(cast(BByte, 0)) == b'\x00' - BArray = new_array_type(new_pointer_type(BByte), None) - a = newp(BArray, [65, 66, 67]) - assert type(string(a)) is bytes and string(a) == b'ABC' - if 'PY_DOT_PY' not in globals() and sys.version_info < (3,): - assert string(a, 8).startswith(b'ABC') # may contain additional garbage - -def test_string_wchar(): + # + s1 = newp(BStructPtr, [42]) + s2 = newp(BStructPtr, s1[0]) + assert s2.a1 == 42 + # + BUnion = new_union_type("union foo_u") + BUnionPtr = new_pointer_type(BUnion) + complete_struct_or_union(BUnion, [('a1', BInt, -1)]) + u1 = newp(BUnionPtr, [42]) + u2 = newp(BUnionPtr, u1[0]) + assert u2.a1 == 42 + # + BFunc = new_function_type((BInt,), BUInt) + p1 = cast(BFunc, 42) + p2 = newp(new_pointer_type(BFunc), p1) + assert p2[0] == p1 + +def test_string(): + BChar = new_primitive_type("char") + assert string(cast(BChar, 42)) == b'*' + assert string(cast(BChar, 0)) == b'\x00' + BCharP = new_pointer_type(BChar) + BArray = new_array_type(BCharP, 10) + a = newp(BArray, b"hello") + assert len(a) == 10 + assert string(a) == b"hello" + p = a + 2 + assert string(p) == b"llo" + assert string(newp(new_array_type(BCharP, 4), b"abcd")) == b"abcd" + py.test.raises(RuntimeError, string, cast(BCharP, 0)) + assert string(a, 4) == b"hell" + assert string(a, 5) == b"hello" + assert string(a, 6) == b"hello" + +def test_string_byte(): + BByte = new_primitive_type("signed char") + assert string(cast(BByte, 42)) == b'*' + assert string(cast(BByte, 0)) == b'\x00' + BArray = new_array_type(new_pointer_type(BByte), None) + a = newp(BArray, [65, 66, 67]) + assert type(string(a)) is bytes and string(a) == b'ABC' + # + BByte = new_primitive_type("unsigned char") + assert string(cast(BByte, 42)) == b'*' + assert string(cast(BByte, 0)) == b'\x00' + BArray = new_array_type(new_pointer_type(BByte), None) + a = newp(BArray, [65, 66, 67]) + assert type(string(a)) is bytes and string(a) == b'ABC' + if 'PY_DOT_PY' not in globals() and sys.version_info < (3,): + assert string(a, 8).startswith(b'ABC') # may contain additional garbage + +def test_string_wchar(): for typename in ["wchar_t", "char16_t", "char32_t"]: _test_string_wchar_variant(typename) def _test_string_wchar_variant(typename): BWChar = new_primitive_type(typename) - assert string(cast(BWChar, 42)) == u+'*' - assert string(cast(BWChar, 0x4253)) == u+'\u4253' - assert string(cast(BWChar, 0)) == u+'\x00' - BArray = new_array_type(new_pointer_type(BWChar), None) - a = newp(BArray, [u+'A', u+'B', u+'C']) - assert type(string(a)) is unicode and string(a) == u+'ABC' - if 'PY_DOT_PY' not in globals() and sys.version_info < (3,): - try: - # may contain additional garbage - assert string(a, 8).startswith(u+'ABC') - except ValueError: # garbage contains values > 0x10FFFF - assert sizeof(BWChar) == 4 - -def test_string_typeerror(): - BShort = new_primitive_type("short") - BArray = new_array_type(new_pointer_type(BShort), None) - a = newp(BArray, [65, 66, 67]) - py.test.raises(TypeError, string, a) - -def test_bug_convert_to_ptr(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BDouble = new_primitive_type("double") - x = cast(BDouble, 42) - py.test.raises(TypeError, newp, new_pointer_type(BCharP), x) - -def test_set_struct_fields(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharArray10 = new_array_type(BCharP, 10) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BCharArray10, -1)]) - p = newp(BStructPtr, None) - assert string(p.a1) == b'' - p.a1 = b'foo' - assert string(p.a1) == b'foo' - assert list(p.a1) == [b'f', b'o', b'o'] + [b'\x00'] * 7 - p.a1 = [b'x', b'y'] - assert string(p.a1) == b'xyo' - -def test_invalid_function_result_types(): - BFunc = new_function_type((), new_void_type()) - BArray = new_array_type(new_pointer_type(BFunc), 5) # works - new_function_type((), BFunc) # works - new_function_type((), new_primitive_type("int")) - new_function_type((), new_pointer_type(BFunc)) - BUnion = new_union_type("union foo_u") - complete_struct_or_union(BUnion, []) - BFunc = new_function_type((), BUnion) - py.test.raises(NotImplementedError, cast(BFunc, 123)) - py.test.raises(TypeError, new_function_type, (), BArray) - -def test_struct_return_in_func(): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BFloat = new_primitive_type("float") - BDouble = new_primitive_type("double") - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo_s") - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BShort, -1)]) - BFunc10 = new_function_type((BInt,), BStruct) - f = cast(BFunc10, _testfunc(10)) - s = f(40) - assert repr(s) == "<cdata 'struct foo_s' owning 4 bytes>" - assert s.a1 == bytechr(40) - assert s.a2 == 40 * 40 - # - BStruct11 = new_struct_type("struct test11") - complete_struct_or_union(BStruct11, [('a1', BInt, -1), - ('a2', BInt, -1)]) - BFunc11 = new_function_type((BInt,), BStruct11) - f = cast(BFunc11, _testfunc(11)) - s = f(40) - assert repr(s) == "<cdata 'struct test11' owning 8 bytes>" - assert s.a1 == 40 - assert s.a2 == 40 * 40 - # - BStruct12 = new_struct_type("struct test12") - complete_struct_or_union(BStruct12, [('a1', BDouble, -1), - ]) - BFunc12 = new_function_type((BInt,), BStruct12) - f = cast(BFunc12, _testfunc(12)) - s = f(40) - assert repr(s) == "<cdata 'struct test12' owning 8 bytes>" - assert s.a1 == 40.0 - # - BStruct13 = new_struct_type("struct test13") - complete_struct_or_union(BStruct13, [('a1', BInt, -1), - ('a2', BInt, -1), - ('a3', BInt, -1)]) - BFunc13 = new_function_type((BInt,), BStruct13) - f = cast(BFunc13, _testfunc(13)) - s = f(40) - assert repr(s) == "<cdata 'struct test13' owning 12 bytes>" - assert s.a1 == 40 - assert s.a2 == 40 * 40 - assert s.a3 == 40 * 40 * 40 - # - BStruct14 = new_struct_type("struct test14") - complete_struct_or_union(BStruct14, [('a1', BFloat, -1), - ]) - BFunc14 = new_function_type((BInt,), BStruct14) - f = cast(BFunc14, _testfunc(14)) - s = f(40) - assert repr(s) == "<cdata 'struct test14' owning 4 bytes>" - assert s.a1 == 40.0 - # - BStruct15 = new_struct_type("struct test15") - complete_struct_or_union(BStruct15, [('a1', BFloat, -1), - ('a2', BInt, -1)]) - BFunc15 = new_function_type((BInt,), BStruct15) - f = cast(BFunc15, _testfunc(15)) - s = f(40) - assert repr(s) == "<cdata 'struct test15' owning 8 bytes>" - assert s.a1 == 40.0 - assert s.a2 == 40 * 40 - # - BStruct16 = new_struct_type("struct test16") - complete_struct_or_union(BStruct16, [('a1', BFloat, -1), - ('a2', BFloat, -1)]) - BFunc16 = new_function_type((BInt,), BStruct16) - f = cast(BFunc16, _testfunc(16)) - s = f(40) - assert repr(s) == "<cdata 'struct test16' owning 8 bytes>" - assert s.a1 == 40.0 - assert s.a2 == -40.0 - # - BStruct17 = new_struct_type("struct test17") - complete_struct_or_union(BStruct17, [('a1', BInt, -1), - ('a2', BFloat, -1)]) - BFunc17 = new_function_type((BInt,), BStruct17) - f = cast(BFunc17, _testfunc(17)) - s = f(40) - assert repr(s) == "<cdata 'struct test17' owning 8 bytes>" - assert s.a1 == 40 - assert s.a2 == 40.0 * 40.0 - # - BStruct17Ptr = new_pointer_type(BStruct17) - BFunc18 = new_function_type((BStruct17Ptr,), BInt) - f = cast(BFunc18, _testfunc(18)) - x = f([[40, 2.5]]) - assert x == 42 - x = f([{'a2': 43.1}]) - assert x == 43 - -def test_cast_with_functionptr(): - BFunc = new_function_type((), new_void_type()) - BFunc2 = new_function_type((), new_primitive_type("short")) - BCharP = new_pointer_type(new_primitive_type("char")) - BIntP = new_pointer_type(new_primitive_type("int")) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BFunc, -1)]) - newp(BStructPtr, [cast(BFunc, 0)]) - newp(BStructPtr, [cast(BCharP, 0)]) - py.test.raises(TypeError, newp, BStructPtr, [cast(BIntP, 0)]) - py.test.raises(TypeError, newp, BStructPtr, [cast(BFunc2, 0)]) - -def test_wchar(): + assert string(cast(BWChar, 42)) == u+'*' + assert string(cast(BWChar, 0x4253)) == u+'\u4253' + assert string(cast(BWChar, 0)) == u+'\x00' + BArray = new_array_type(new_pointer_type(BWChar), None) + a = newp(BArray, [u+'A', u+'B', u+'C']) + assert type(string(a)) is unicode and string(a) == u+'ABC' + if 'PY_DOT_PY' not in globals() and sys.version_info < (3,): + try: + # may contain additional garbage + assert string(a, 8).startswith(u+'ABC') + except ValueError: # garbage contains values > 0x10FFFF + assert sizeof(BWChar) == 4 + +def test_string_typeerror(): + BShort = new_primitive_type("short") + BArray = new_array_type(new_pointer_type(BShort), None) + a = newp(BArray, [65, 66, 67]) + py.test.raises(TypeError, string, a) + +def test_bug_convert_to_ptr(): + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BDouble = new_primitive_type("double") + x = cast(BDouble, 42) + py.test.raises(TypeError, newp, new_pointer_type(BCharP), x) + +def test_set_struct_fields(): + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BCharArray10 = new_array_type(BCharP, 10) + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BCharArray10, -1)]) + p = newp(BStructPtr, None) + assert string(p.a1) == b'' + p.a1 = b'foo' + assert string(p.a1) == b'foo' + assert list(p.a1) == [b'f', b'o', b'o'] + [b'\x00'] * 7 + p.a1 = [b'x', b'y'] + assert string(p.a1) == b'xyo' + +def test_invalid_function_result_types(): + BFunc = new_function_type((), new_void_type()) + BArray = new_array_type(new_pointer_type(BFunc), 5) # works + new_function_type((), BFunc) # works + new_function_type((), new_primitive_type("int")) + new_function_type((), new_pointer_type(BFunc)) + BUnion = new_union_type("union foo_u") + complete_struct_or_union(BUnion, []) + BFunc = new_function_type((), BUnion) + py.test.raises(NotImplementedError, cast(BFunc, 123)) + py.test.raises(TypeError, new_function_type, (), BArray) + +def test_struct_return_in_func(): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BFloat = new_primitive_type("float") + BDouble = new_primitive_type("double") + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo_s") + complete_struct_or_union(BStruct, [('a1', BChar, -1), + ('a2', BShort, -1)]) + BFunc10 = new_function_type((BInt,), BStruct) + f = cast(BFunc10, _testfunc(10)) + s = f(40) + assert repr(s) == "<cdata 'struct foo_s' owning 4 bytes>" + assert s.a1 == bytechr(40) + assert s.a2 == 40 * 40 + # + BStruct11 = new_struct_type("struct test11") + complete_struct_or_union(BStruct11, [('a1', BInt, -1), + ('a2', BInt, -1)]) + BFunc11 = new_function_type((BInt,), BStruct11) + f = cast(BFunc11, _testfunc(11)) + s = f(40) + assert repr(s) == "<cdata 'struct test11' owning 8 bytes>" + assert s.a1 == 40 + assert s.a2 == 40 * 40 + # + BStruct12 = new_struct_type("struct test12") + complete_struct_or_union(BStruct12, [('a1', BDouble, -1), + ]) + BFunc12 = new_function_type((BInt,), BStruct12) + f = cast(BFunc12, _testfunc(12)) + s = f(40) + assert repr(s) == "<cdata 'struct test12' owning 8 bytes>" + assert s.a1 == 40.0 + # + BStruct13 = new_struct_type("struct test13") + complete_struct_or_union(BStruct13, [('a1', BInt, -1), + ('a2', BInt, -1), + ('a3', BInt, -1)]) + BFunc13 = new_function_type((BInt,), BStruct13) + f = cast(BFunc13, _testfunc(13)) + s = f(40) + assert repr(s) == "<cdata 'struct test13' owning 12 bytes>" + assert s.a1 == 40 + assert s.a2 == 40 * 40 + assert s.a3 == 40 * 40 * 40 + # + BStruct14 = new_struct_type("struct test14") + complete_struct_or_union(BStruct14, [('a1', BFloat, -1), + ]) + BFunc14 = new_function_type((BInt,), BStruct14) + f = cast(BFunc14, _testfunc(14)) + s = f(40) + assert repr(s) == "<cdata 'struct test14' owning 4 bytes>" + assert s.a1 == 40.0 + # + BStruct15 = new_struct_type("struct test15") + complete_struct_or_union(BStruct15, [('a1', BFloat, -1), + ('a2', BInt, -1)]) + BFunc15 = new_function_type((BInt,), BStruct15) + f = cast(BFunc15, _testfunc(15)) + s = f(40) + assert repr(s) == "<cdata 'struct test15' owning 8 bytes>" + assert s.a1 == 40.0 + assert s.a2 == 40 * 40 + # + BStruct16 = new_struct_type("struct test16") + complete_struct_or_union(BStruct16, [('a1', BFloat, -1), + ('a2', BFloat, -1)]) + BFunc16 = new_function_type((BInt,), BStruct16) + f = cast(BFunc16, _testfunc(16)) + s = f(40) + assert repr(s) == "<cdata 'struct test16' owning 8 bytes>" + assert s.a1 == 40.0 + assert s.a2 == -40.0 + # + BStruct17 = new_struct_type("struct test17") + complete_struct_or_union(BStruct17, [('a1', BInt, -1), + ('a2', BFloat, -1)]) + BFunc17 = new_function_type((BInt,), BStruct17) + f = cast(BFunc17, _testfunc(17)) + s = f(40) + assert repr(s) == "<cdata 'struct test17' owning 8 bytes>" + assert s.a1 == 40 + assert s.a2 == 40.0 * 40.0 + # + BStruct17Ptr = new_pointer_type(BStruct17) + BFunc18 = new_function_type((BStruct17Ptr,), BInt) + f = cast(BFunc18, _testfunc(18)) + x = f([[40, 2.5]]) + assert x == 42 + x = f([{'a2': 43.1}]) + assert x == 43 + +def test_cast_with_functionptr(): + BFunc = new_function_type((), new_void_type()) + BFunc2 = new_function_type((), new_primitive_type("short")) + BCharP = new_pointer_type(new_primitive_type("char")) + BIntP = new_pointer_type(new_primitive_type("int")) + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BFunc, -1)]) + newp(BStructPtr, [cast(BFunc, 0)]) + newp(BStructPtr, [cast(BCharP, 0)]) + py.test.raises(TypeError, newp, BStructPtr, [cast(BIntP, 0)]) + py.test.raises(TypeError, newp, BStructPtr, [cast(BFunc2, 0)]) + +def test_wchar(): _test_wchar_variant("wchar_t") if sys.platform.startswith("linux"): BWChar = new_primitive_type("wchar_t") @@ -2240,138 +2240,138 @@ def test_char32(): def _test_wchar_variant(typename): BWChar = new_primitive_type(typename) - BInt = new_primitive_type("int") - pyuni4 = {1: True, 2: False}[len(u+'\U00012345')] - wchar4 = {2: False, 4: True}[sizeof(BWChar)] + BInt = new_primitive_type("int") + pyuni4 = {1: True, 2: False}[len(u+'\U00012345')] + wchar4 = {2: False, 4: True}[sizeof(BWChar)] assert str(cast(BWChar, 0x45)) == "<cdata '%s' %s'E'>" % ( typename, mandatory_u_prefix) assert str(cast(BWChar, 0x1234)) == "<cdata '%s' %s'\u1234'>" % ( typename, mandatory_u_prefix) if not _hacked_pypy_uni4(): if wchar4: - x = cast(BWChar, 0x12345) + x = cast(BWChar, 0x12345) assert str(x) == "<cdata '%s' %s'\U00012345'>" % ( typename, mandatory_u_prefix) - assert int(x) == 0x12345 + assert int(x) == 0x12345 else: x = cast(BWChar, 0x18345) assert str(x) == "<cdata '%s' %s'\u8345'>" % ( typename, mandatory_u_prefix) assert int(x) == 0x8345 - # - BWCharP = new_pointer_type(BWChar) - BStruct = new_struct_type("struct foo_s") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BWChar, -1), - ('a2', BWCharP, -1)]) - s = newp(BStructPtr) - s.a1 = u+'\x00' - assert s.a1 == u+'\x00' + # + BWCharP = new_pointer_type(BWChar) + BStruct = new_struct_type("struct foo_s") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BWChar, -1), + ('a2', BWCharP, -1)]) + s = newp(BStructPtr) + s.a1 = u+'\x00' + assert s.a1 == u+'\x00' with pytest.raises(TypeError): s.a1 = b'a' with pytest.raises(TypeError): s.a1 = bytechr(0xFF) - s.a1 = u+'\u1234' - assert s.a1 == u+'\u1234' - if pyuni4: + s.a1 = u+'\u1234' + assert s.a1 == u+'\u1234' + if pyuni4: if wchar4: s.a1 = u+'\U00012345' assert s.a1 == u+'\U00012345' - elif wchar4: - if not _hacked_pypy_uni4(): - s.a1 = cast(BWChar, 0x12345) - assert s.a1 == u+'\ud808\udf45' - s.a1 = u+'\ud807\udf44' - assert s.a1 == u+'\U00011f44' - else: + elif wchar4: + if not _hacked_pypy_uni4(): + s.a1 = cast(BWChar, 0x12345) + assert s.a1 == u+'\ud808\udf45' + s.a1 = u+'\ud807\udf44' + assert s.a1 == u+'\U00011f44' + else: with pytest.raises(TypeError): s.a1 = u+'\U00012345' - # - BWCharArray = new_array_type(BWCharP, None) - a = newp(BWCharArray, u+'hello \u1234 world') - assert len(a) == 14 # including the final null - assert string(a) == u+'hello \u1234 world' - a[13] = u+'!' - assert string(a) == u+'hello \u1234 world!' - assert str(a) == repr(a) - assert a[6] == u+'\u1234' - a[6] = u+'-' - assert string(a) == u+'hello - world!' - assert str(a) == repr(a) - # - if wchar4 and not _hacked_pypy_uni4(): - u1 = u+'\U00012345\U00012346\U00012347' - a = newp(BWCharArray, u1) - assert len(a) == 4 - assert string(a) == u1 - assert len(list(a)) == 4 - expected = [u+'\U00012345', u+'\U00012346', u+'\U00012347', unichr(0)] - assert list(a) == expected - got = [a[i] for i in range(4)] - assert got == expected + # + BWCharArray = new_array_type(BWCharP, None) + a = newp(BWCharArray, u+'hello \u1234 world') + assert len(a) == 14 # including the final null + assert string(a) == u+'hello \u1234 world' + a[13] = u+'!' + assert string(a) == u+'hello \u1234 world!' + assert str(a) == repr(a) + assert a[6] == u+'\u1234' + a[6] = u+'-' + assert string(a) == u+'hello - world!' + assert str(a) == repr(a) + # + if wchar4 and not _hacked_pypy_uni4(): + u1 = u+'\U00012345\U00012346\U00012347' + a = newp(BWCharArray, u1) + assert len(a) == 4 + assert string(a) == u1 + assert len(list(a)) == 4 + expected = [u+'\U00012345', u+'\U00012346', u+'\U00012347', unichr(0)] + assert list(a) == expected + got = [a[i] for i in range(4)] + assert got == expected with pytest.raises(IndexError): a[4] - # - w = cast(BWChar, 'a') + # + w = cast(BWChar, 'a') assert repr(w) == "<cdata '%s' %s'a'>" % (typename, mandatory_u_prefix) - assert str(w) == repr(w) - assert string(w) == u+'a' - assert int(w) == ord('a') - w = cast(BWChar, 0x1234) + assert str(w) == repr(w) + assert string(w) == u+'a' + assert int(w) == ord('a') + w = cast(BWChar, 0x1234) assert repr(w) == "<cdata '%s' %s'\u1234'>" % (typename, mandatory_u_prefix) - assert str(w) == repr(w) - assert string(w) == u+'\u1234' - assert int(w) == 0x1234 - w = cast(BWChar, u+'\u8234') + assert str(w) == repr(w) + assert string(w) == u+'\u1234' + assert int(w) == 0x1234 + w = cast(BWChar, u+'\u8234') assert repr(w) == "<cdata '%s' %s'\u8234'>" % (typename, mandatory_u_prefix) - assert str(w) == repr(w) - assert string(w) == u+'\u8234' - assert int(w) == 0x8234 - w = cast(BInt, u+'\u1234') - assert repr(w) == "<cdata 'int' 4660>" - if wchar4 and not _hacked_pypy_uni4(): - w = cast(BWChar, u+'\U00012345') + assert str(w) == repr(w) + assert string(w) == u+'\u8234' + assert int(w) == 0x8234 + w = cast(BInt, u+'\u1234') + assert repr(w) == "<cdata 'int' 4660>" + if wchar4 and not _hacked_pypy_uni4(): + w = cast(BWChar, u+'\U00012345') assert repr(w) == "<cdata '%s' %s'\U00012345'>" % ( typename, mandatory_u_prefix) - assert str(w) == repr(w) - assert string(w) == u+'\U00012345' - assert int(w) == 0x12345 - w = cast(BInt, u+'\U00012345') - assert repr(w) == "<cdata 'int' 74565>" - py.test.raises(TypeError, cast, BInt, u+'') - py.test.raises(TypeError, cast, BInt, u+'XX') - assert int(cast(BInt, u+'a')) == ord('a') - # - a = newp(BWCharArray, u+'hello - world') - p = cast(BWCharP, a) - assert string(p) == u+'hello - world' - p[6] = u+'\u2345' - assert string(p) == u+'hello \u2345 world' - # - s = newp(BStructPtr, [u+'\u1234', p]) - assert s.a1 == u+'\u1234' - assert s.a2 == p - assert str(s.a2) == repr(s.a2) - assert string(s.a2) == u+'hello \u2345 world' - # - q = cast(BWCharP, 0) - assert str(q) == repr(q) - py.test.raises(RuntimeError, string, q) - # - def cb(p): + assert str(w) == repr(w) + assert string(w) == u+'\U00012345' + assert int(w) == 0x12345 + w = cast(BInt, u+'\U00012345') + assert repr(w) == "<cdata 'int' 74565>" + py.test.raises(TypeError, cast, BInt, u+'') + py.test.raises(TypeError, cast, BInt, u+'XX') + assert int(cast(BInt, u+'a')) == ord('a') + # + a = newp(BWCharArray, u+'hello - world') + p = cast(BWCharP, a) + assert string(p) == u+'hello - world' + p[6] = u+'\u2345' + assert string(p) == u+'hello \u2345 world' + # + s = newp(BStructPtr, [u+'\u1234', p]) + assert s.a1 == u+'\u1234' + assert s.a2 == p + assert str(s.a2) == repr(s.a2) + assert string(s.a2) == u+'hello \u2345 world' + # + q = cast(BWCharP, 0) + assert str(q) == repr(q) + py.test.raises(RuntimeError, string, q) + # + def cb(p): assert repr(p).startswith("<cdata '%s *' 0x" % typename) - return len(string(p)) - BFunc = new_function_type((BWCharP,), BInt, False) - f = callback(BFunc, cb, -42) - assert f(u+'a\u1234b') == 3 - # - if wchar4 and not pyuni4 and not _hacked_pypy_uni4(): - # try out-of-range wchar_t values - x = cast(BWChar, 1114112) - py.test.raises(ValueError, string, x) - x = cast(BWChar, -1) - py.test.raises(ValueError, string, x) - + return len(string(p)) + BFunc = new_function_type((BWCharP,), BInt, False) + f = callback(BFunc, cb, -42) + assert f(u+'a\u1234b') == 3 + # + if wchar4 and not pyuni4 and not _hacked_pypy_uni4(): + # try out-of-range wchar_t values + x = cast(BWChar, 1114112) + py.test.raises(ValueError, string, x) + x = cast(BWChar, -1) + py.test.raises(ValueError, string, x) + def test_wchar_variants_mix(): BWChar = new_primitive_type("wchar_t") BChar16 = new_primitive_type("char16_t") @@ -2393,79 +2393,79 @@ def test_wchar_variants_mix(): a = newp(BChar32A, u+'\U00012345') assert len(a) == 2 # even if the Python unicode string above is 2 chars -def test_keepalive_struct(): - # exception to the no-keepalive rule: p=newp(BStructPtr) returns a - # pointer owning the memory, and p[0] returns a pointer to the - # struct that *also* owns the memory - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1), - ('a2', new_primitive_type("int"), -1), - ('a3', new_primitive_type("int"), -1)]) - p = newp(BStructPtr) - assert repr(p) == "<cdata 'struct foo *' owning 12 bytes>" - q = p[0] - assert repr(q) == "<cdata 'struct foo' owning 12 bytes>" - q.a1 = 123456 - assert p.a1 == 123456 - r = cast(BStructPtr, p) - assert repr(r[0]).startswith("<cdata 'struct foo &' 0x") - del p - import gc; gc.collect() - assert q.a1 == 123456 - assert repr(q) == "<cdata 'struct foo' owning 12 bytes>" - assert q.a1 == 123456 - -def test_nokeepalive_struct(): - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - BStructPtrPtr = new_pointer_type(BStructPtr) - complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1)]) - p = newp(BStructPtr) - pp = newp(BStructPtrPtr) - pp[0] = p - s = pp[0][0] - assert repr(s).startswith("<cdata 'struct foo &' 0x") - -def test_owning_repr(): - BInt = new_primitive_type("int") - BArray = new_array_type(new_pointer_type(BInt), None) # int[] - p = newp(BArray, 7) - assert repr(p) == "<cdata 'int[]' owning 28 bytes>" - assert sizeof(p) == 28 - # - BArray = new_array_type(new_pointer_type(BInt), 7) # int[7] - p = newp(BArray, None) - assert repr(p) == "<cdata 'int[7]' owning 28 bytes>" - assert sizeof(p) == 28 - -def test_cannot_dereference_void(): - BVoidP = new_pointer_type(new_void_type()) - p = cast(BVoidP, 123456) +def test_keepalive_struct(): + # exception to the no-keepalive rule: p=newp(BStructPtr) returns a + # pointer owning the memory, and p[0] returns a pointer to the + # struct that *also* owns the memory + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1), + ('a2', new_primitive_type("int"), -1), + ('a3', new_primitive_type("int"), -1)]) + p = newp(BStructPtr) + assert repr(p) == "<cdata 'struct foo *' owning 12 bytes>" + q = p[0] + assert repr(q) == "<cdata 'struct foo' owning 12 bytes>" + q.a1 = 123456 + assert p.a1 == 123456 + r = cast(BStructPtr, p) + assert repr(r[0]).startswith("<cdata 'struct foo &' 0x") + del p + import gc; gc.collect() + assert q.a1 == 123456 + assert repr(q) == "<cdata 'struct foo' owning 12 bytes>" + assert q.a1 == 123456 + +def test_nokeepalive_struct(): + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + BStructPtrPtr = new_pointer_type(BStructPtr) + complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1)]) + p = newp(BStructPtr) + pp = newp(BStructPtrPtr) + pp[0] = p + s = pp[0][0] + assert repr(s).startswith("<cdata 'struct foo &' 0x") + +def test_owning_repr(): + BInt = new_primitive_type("int") + BArray = new_array_type(new_pointer_type(BInt), None) # int[] + p = newp(BArray, 7) + assert repr(p) == "<cdata 'int[]' owning 28 bytes>" + assert sizeof(p) == 28 + # + BArray = new_array_type(new_pointer_type(BInt), 7) # int[7] + p = newp(BArray, None) + assert repr(p) == "<cdata 'int[7]' owning 28 bytes>" + assert sizeof(p) == 28 + +def test_cannot_dereference_void(): + BVoidP = new_pointer_type(new_void_type()) + p = cast(BVoidP, 123456) with pytest.raises(TypeError): p[0] - p = cast(BVoidP, 0) + p = cast(BVoidP, 0) with pytest.raises((TypeError, RuntimeError)): p[0] - -def test_iter(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, None) # int[] - p = newp(BArray, 7) - assert list(p) == list(iter(p)) == [0] * 7 - # - py.test.raises(TypeError, iter, cast(BInt, 5)) - py.test.raises(TypeError, iter, cast(BIntP, 123456)) - -def test_cmp(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BVoidP = new_pointer_type(new_void_type()) - p = newp(BIntP, 123) - q = cast(BInt, 124) - assert (p == q) is False - assert (p != q) is True + +def test_iter(): + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BArray = new_array_type(BIntP, None) # int[] + p = newp(BArray, 7) + assert list(p) == list(iter(p)) == [0] * 7 + # + py.test.raises(TypeError, iter, cast(BInt, 5)) + py.test.raises(TypeError, iter, cast(BIntP, 123456)) + +def test_cmp(): + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BVoidP = new_pointer_type(new_void_type()) + p = newp(BIntP, 123) + q = cast(BInt, 124) + assert (p == q) is False + assert (p != q) is True assert (q == p) is False assert (q != p) is True if strict_compare: @@ -2475,437 +2475,437 @@ def test_cmp(): with pytest.raises(TypeError): q <= p with pytest.raises(TypeError): p > q with pytest.raises(TypeError): p >= q - r = cast(BVoidP, p) - assert (p < r) is False - assert (p <= r) is True - assert (p == r) is True - assert (p != r) is False - assert (p > r) is False - assert (p >= r) is True - s = newp(BIntP, 125) - assert (p == s) is False - assert (p != s) is True - assert (p < s) is (p <= s) is (s > p) is (s >= p) - assert (p > s) is (p >= s) is (s < p) is (s <= p) - assert (p < s) ^ (p > s) - -def test_buffer(): - try: - import __builtin__ - except ImportError: - import builtins as __builtin__ - BShort = new_primitive_type("short") - s = newp(new_pointer_type(BShort), 100) - assert sizeof(s) == size_of_ptr() - assert sizeof(BShort) == 2 - assert len(buffer(s)) == 2 - # - BChar = new_primitive_type("char") - BCharArray = new_array_type(new_pointer_type(BChar), None) - c = newp(BCharArray, b"hi there") - # - buf = buffer(c) - assert repr(buf).startswith('<_cffi_backend.buffer object at 0x') - assert bytes(buf) == b"hi there\x00" + r = cast(BVoidP, p) + assert (p < r) is False + assert (p <= r) is True + assert (p == r) is True + assert (p != r) is False + assert (p > r) is False + assert (p >= r) is True + s = newp(BIntP, 125) + assert (p == s) is False + assert (p != s) is True + assert (p < s) is (p <= s) is (s > p) is (s >= p) + assert (p > s) is (p >= s) is (s < p) is (s <= p) + assert (p < s) ^ (p > s) + +def test_buffer(): + try: + import __builtin__ + except ImportError: + import builtins as __builtin__ + BShort = new_primitive_type("short") + s = newp(new_pointer_type(BShort), 100) + assert sizeof(s) == size_of_ptr() + assert sizeof(BShort) == 2 + assert len(buffer(s)) == 2 + # + BChar = new_primitive_type("char") + BCharArray = new_array_type(new_pointer_type(BChar), None) + c = newp(BCharArray, b"hi there") + # + buf = buffer(c) + assert repr(buf).startswith('<_cffi_backend.buffer object at 0x') + assert bytes(buf) == b"hi there\x00" assert type(buf) is buffer - if sys.version_info < (3,): - assert str(buf) == "hi there\x00" - assert unicode(buf) == u+"hi there\x00" - else: - assert str(buf) == repr(buf) - # --mb_length-- - assert len(buf) == len(b"hi there\x00") - # --mb_item-- - for i in range(-12, 12): - try: - expected = b"hi there\x00"[i] - except IndexError: + if sys.version_info < (3,): + assert str(buf) == "hi there\x00" + assert unicode(buf) == u+"hi there\x00" + else: + assert str(buf) == repr(buf) + # --mb_length-- + assert len(buf) == len(b"hi there\x00") + # --mb_item-- + for i in range(-12, 12): + try: + expected = b"hi there\x00"[i] + except IndexError: with pytest.raises(IndexError): buf[i] - else: - assert buf[i] == bitem2bchr(expected) - # --mb_slice-- - assert buf[:] == b"hi there\x00" - for i in range(-12, 12): - assert buf[i:] == b"hi there\x00"[i:] - assert buf[:i] == b"hi there\x00"[:i] - for j in range(-12, 12): - assert buf[i:j] == b"hi there\x00"[i:j] - # --misc-- - assert list(buf) == list(map(bitem2bchr, b"hi there\x00")) - # --mb_as_buffer-- - if hasattr(__builtin__, 'buffer'): # Python <= 2.7 - py.test.raises(TypeError, __builtin__.buffer, c) - bf1 = __builtin__.buffer(buf) - assert len(bf1) == len(buf) and bf1[3] == "t" - if hasattr(__builtin__, 'memoryview'): # Python >= 2.7 - py.test.raises(TypeError, memoryview, c) - mv1 = memoryview(buf) - assert len(mv1) == len(buf) and mv1[3] in (b"t", ord(b"t")) - # --mb_ass_item-- - expected = list(map(bitem2bchr, b"hi there\x00")) - for i in range(-12, 12): - try: - expected[i] = bytechr(i & 0xff) - except IndexError: + else: + assert buf[i] == bitem2bchr(expected) + # --mb_slice-- + assert buf[:] == b"hi there\x00" + for i in range(-12, 12): + assert buf[i:] == b"hi there\x00"[i:] + assert buf[:i] == b"hi there\x00"[:i] + for j in range(-12, 12): + assert buf[i:j] == b"hi there\x00"[i:j] + # --misc-- + assert list(buf) == list(map(bitem2bchr, b"hi there\x00")) + # --mb_as_buffer-- + if hasattr(__builtin__, 'buffer'): # Python <= 2.7 + py.test.raises(TypeError, __builtin__.buffer, c) + bf1 = __builtin__.buffer(buf) + assert len(bf1) == len(buf) and bf1[3] == "t" + if hasattr(__builtin__, 'memoryview'): # Python >= 2.7 + py.test.raises(TypeError, memoryview, c) + mv1 = memoryview(buf) + assert len(mv1) == len(buf) and mv1[3] in (b"t", ord(b"t")) + # --mb_ass_item-- + expected = list(map(bitem2bchr, b"hi there\x00")) + for i in range(-12, 12): + try: + expected[i] = bytechr(i & 0xff) + except IndexError: with pytest.raises(IndexError): buf[i] = bytechr(i & 0xff) - else: - buf[i] = bytechr(i & 0xff) - assert list(buf) == expected - # --mb_ass_slice-- - buf[:] = b"hi there\x00" - assert list(buf) == list(c) == list(map(bitem2bchr, b"hi there\x00")) + else: + buf[i] = bytechr(i & 0xff) + assert list(buf) == expected + # --mb_ass_slice-- + buf[:] = b"hi there\x00" + assert list(buf) == list(c) == list(map(bitem2bchr, b"hi there\x00")) with pytest.raises(ValueError): buf[:] = b"shorter" with pytest.raises(ValueError): buf[:] = b"this is much too long!" - buf[4:2] = b"" # no effect, but should work - assert buf[:] == b"hi there\x00" - buf[:2] = b"HI" - assert buf[:] == b"HI there\x00" - buf[:2] = b"hi" - expected = list(map(bitem2bchr, b"hi there\x00")) - x = 0 - for i in range(-12, 12): - for j in range(-12, 12): - start = i if i >= 0 else i + len(buf) - stop = j if j >= 0 else j + len(buf) - start = max(0, min(len(buf), start)) - stop = max(0, min(len(buf), stop)) - sample = bytechr(x & 0xff) * (stop - start) - x += 1 - buf[i:j] = sample - expected[i:j] = map(bitem2bchr, sample) - assert list(buf) == expected - -def test_getcname(): - BUChar = new_primitive_type("unsigned char") - BArray = new_array_type(new_pointer_type(BUChar), 123) - assert getcname(BArray, "<-->") == "unsigned char<-->[123]" - -def test_errno(): - BVoid = new_void_type() - BFunc5 = new_function_type((), BVoid) - f = cast(BFunc5, _testfunc(5)) - set_errno(50) - f() - assert get_errno() == 65 - f(); f() - assert get_errno() == 95 - -def test_errno_callback(): + buf[4:2] = b"" # no effect, but should work + assert buf[:] == b"hi there\x00" + buf[:2] = b"HI" + assert buf[:] == b"HI there\x00" + buf[:2] = b"hi" + expected = list(map(bitem2bchr, b"hi there\x00")) + x = 0 + for i in range(-12, 12): + for j in range(-12, 12): + start = i if i >= 0 else i + len(buf) + stop = j if j >= 0 else j + len(buf) + start = max(0, min(len(buf), start)) + stop = max(0, min(len(buf), stop)) + sample = bytechr(x & 0xff) * (stop - start) + x += 1 + buf[i:j] = sample + expected[i:j] = map(bitem2bchr, sample) + assert list(buf) == expected + +def test_getcname(): + BUChar = new_primitive_type("unsigned char") + BArray = new_array_type(new_pointer_type(BUChar), 123) + assert getcname(BArray, "<-->") == "unsigned char<-->[123]" + +def test_errno(): + BVoid = new_void_type() + BFunc5 = new_function_type((), BVoid) + f = cast(BFunc5, _testfunc(5)) + set_errno(50) + f() + assert get_errno() == 65 + f(); f() + assert get_errno() == 95 + +def test_errno_callback(): if globals().get('PY_DOT_PY'): py.test.skip("cannot run this test on py.py (e.g. fails on Windows)") - set_errno(95) - def cb(): - e = get_errno() - set_errno(e - 6) - BVoid = new_void_type() - BFunc5 = new_function_type((), BVoid) - f = callback(BFunc5, cb) - f() - assert get_errno() == 89 - f(); f() - assert get_errno() == 77 - -def test_cast_to_array(): - # not valid in C! extension to get a non-owning <cdata 'int[3]'> - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, 3) - x = cast(BArray, 0) - assert repr(x) == "<cdata 'int[3]' NULL>" - -def test_cast_invalid(): - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, []) - p = cast(new_pointer_type(BStruct), 123456) - s = p[0] - py.test.raises(TypeError, cast, BStruct, s) - -def test_bug_float_convertion(): - BDouble = new_primitive_type("double") - BDoubleP = new_pointer_type(BDouble) - py.test.raises(TypeError, newp, BDoubleP, "foobar") - -def test_bug_delitem(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - x = newp(BCharP) + set_errno(95) + def cb(): + e = get_errno() + set_errno(e - 6) + BVoid = new_void_type() + BFunc5 = new_function_type((), BVoid) + f = callback(BFunc5, cb) + f() + assert get_errno() == 89 + f(); f() + assert get_errno() == 77 + +def test_cast_to_array(): + # not valid in C! extension to get a non-owning <cdata 'int[3]'> + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BArray = new_array_type(BIntP, 3) + x = cast(BArray, 0) + assert repr(x) == "<cdata 'int[3]' NULL>" + +def test_cast_invalid(): + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, []) + p = cast(new_pointer_type(BStruct), 123456) + s = p[0] + py.test.raises(TypeError, cast, BStruct, s) + +def test_bug_float_convertion(): + BDouble = new_primitive_type("double") + BDoubleP = new_pointer_type(BDouble) + py.test.raises(TypeError, newp, BDoubleP, "foobar") + +def test_bug_delitem(): + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + x = newp(BCharP) with pytest.raises(TypeError): del x[0] - -def test_bug_delattr(): - BLong = new_primitive_type("long") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BLong, -1)]) - x = newp(new_pointer_type(BStruct)) + +def test_bug_delattr(): + BLong = new_primitive_type("long") + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, [('a1', BLong, -1)]) + x = newp(new_pointer_type(BStruct)) with pytest.raises(AttributeError): del x.a1 - -def test_variable_length_struct(): - py.test.skip("later") - BLong = new_primitive_type("long") - BArray = new_array_type(new_pointer_type(BLong), None) - BStruct = new_struct_type("struct foo") - BStructP = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BLong, -1), - ('a2', BArray, -1)]) - assert sizeof(BStruct) == size_of_long() - assert alignof(BStruct) == alignof(BLong) - # - py.test.raises(TypeError, newp, BStructP, None) - x = newp(BStructP, 5) - assert sizeof(x) == 6 * size_of_long() - x[4] = 123 - assert x[4] == 123 + +def test_variable_length_struct(): + py.test.skip("later") + BLong = new_primitive_type("long") + BArray = new_array_type(new_pointer_type(BLong), None) + BStruct = new_struct_type("struct foo") + BStructP = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BLong, -1), + ('a2', BArray, -1)]) + assert sizeof(BStruct) == size_of_long() + assert alignof(BStruct) == alignof(BLong) + # + py.test.raises(TypeError, newp, BStructP, None) + x = newp(BStructP, 5) + assert sizeof(x) == 6 * size_of_long() + x[4] = 123 + assert x[4] == 123 with pytest.raises(IndexError): x[5] - assert len(x.a2) == 5 - # - py.test.raises(TypeError, newp, BStructP, [123]) - x = newp(BStructP, [123, 5]) - assert x.a1 == 123 - assert len(x.a2) == 5 - assert list(x.a2) == [0] * 5 - # - x = newp(BStructP, {'a2': 5}) - assert x.a1 == 0 - assert len(x.a2) == 5 - assert list(x.a2) == [0] * 5 - # - x = newp(BStructP, [123, (4, 5)]) - assert x.a1 == 123 - assert len(x.a2) == 2 - assert list(x.a2) == [4, 5] - # - x = newp(BStructP, {'a2': (4, 5)}) - assert x.a1 == 0 - assert len(x.a2) == 2 - assert list(x.a2) == [4, 5] - -def test_autocast_int(): - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - BLongLong = new_primitive_type("long long") - BULongLong = new_primitive_type("unsigned long long") - BULongLongPtr = new_pointer_type(BULongLong) - x = newp(BIntPtr, cast(BInt, 42)) - assert x[0] == 42 - x = newp(BIntPtr, cast(BLongLong, 42)) - assert x[0] == 42 - x = newp(BIntPtr, cast(BULongLong, 42)) - assert x[0] == 42 - x = newp(BULongLongPtr, cast(BInt, 42)) - assert x[0] == 42 - py.test.raises(OverflowError, newp, BULongLongPtr, cast(BInt, -42)) - x = cast(BInt, cast(BInt, 42)) - assert int(x) == 42 - x = cast(BInt, cast(BLongLong, 42)) - assert int(x) == 42 - x = cast(BInt, cast(BULongLong, 42)) - assert int(x) == 42 - x = cast(BULongLong, cast(BInt, 42)) - assert int(x) == 42 - x = cast(BULongLong, cast(BInt, -42)) - assert int(x) == 2 ** 64 - 42 - x = cast(BIntPtr, cast(BInt, 42)) - assert int(cast(BInt, x)) == 42 - -def test_autocast_float(): - BFloat = new_primitive_type("float") - BDouble = new_primitive_type("float") - BFloatPtr = new_pointer_type(BFloat) - x = newp(BFloatPtr, cast(BDouble, 12.5)) - assert x[0] == 12.5 - x = cast(BFloat, cast(BDouble, 12.5)) - assert float(x) == 12.5 - -def test_longdouble(): - py_py = 'PY_DOT_PY' in globals() - BInt = new_primitive_type("int") - BLongDouble = new_primitive_type("long double") - BLongDoublePtr = new_pointer_type(BLongDouble) - BLongDoubleArray = new_array_type(BLongDoublePtr, None) - a = newp(BLongDoubleArray, 1) - x = a[0] - if not py_py: - assert repr(x).startswith("<cdata 'long double' 0.0") - assert float(x) == 0.0 - assert int(x) == 0 - # - b = newp(BLongDoubleArray, [1.23]) - x = b[0] - if not py_py: - assert repr(x).startswith("<cdata 'long double' 1.23") - assert float(x) == 1.23 - assert int(x) == 1 - # - BFunc19 = new_function_type((BLongDouble, BInt), BLongDouble) - f = cast(BFunc19, _testfunc(19)) - start = lstart = 1.5 - for i in range(107): - start = 4 * start - start * start - lstart = f(lstart, 1) - lother = f(1.5, 107) - if not py_py: - assert float(lstart) == float(lother) - assert repr(lstart) == repr(lother) - if sizeof(BLongDouble) > sizeof(new_primitive_type("double")): - assert float(lstart) != start - assert repr(lstart).startswith("<cdata 'long double' ") - # - c = newp(BLongDoubleArray, [lstart]) - x = c[0] - assert float(f(lstart, 107)) == float(f(x, 107)) - -def test_get_array_of_length_zero(): - for length in [0, 5, 10]: - BLong = new_primitive_type("long") - BLongP = new_pointer_type(BLong) - BArray0 = new_array_type(BLongP, length) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BArray0, -1)]) - p = newp(BStructPtr, None) - if length == 0: - assert repr(p.a1).startswith("<cdata 'long *' 0x") - else: - assert repr(p.a1).startswith("<cdata 'long[%d]' 0x" % length) - -def test_nested_anonymous_struct(): - BInt = new_primitive_type("int") - BChar = new_primitive_type("char") - BStruct = new_struct_type("struct foo") - BInnerStruct = new_struct_type("struct foo") - complete_struct_or_union(BInnerStruct, [('a1', BInt, -1), - ('a2', BChar, -1)]) - complete_struct_or_union(BStruct, [('', BInnerStruct, -1), - ('a3', BChar, -1)]) - assert sizeof(BInnerStruct) == sizeof(BInt) * 2 # with alignment - assert sizeof(BStruct) == sizeof(BInt) * 3 # 'a3' is placed after - d = BStruct.fields - assert len(d) == 3 - assert d[0][0] == 'a1' - assert d[0][1].type is BInt - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 - assert d[1][0] == 'a2' - assert d[1][1].type is BChar - assert d[1][1].offset == sizeof(BInt) - assert d[1][1].bitshift == -1 - assert d[1][1].bitsize == -1 - assert d[2][0] == 'a3' - assert d[2][1].type is BChar - assert d[2][1].offset == sizeof(BInt) * 2 - assert d[2][1].bitshift == -1 - assert d[2][1].bitsize == -1 - -def test_nested_anonymous_struct_2(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BInnerUnion = new_union_type("union bar") - complete_struct_or_union(BInnerUnion, [('a1', BInt, -1), - ('a2', BInt, -1)]) - complete_struct_or_union(BStruct, [('b1', BInt, -1), - ('', BInnerUnion, -1), - ('b2', BInt, -1)]) - assert sizeof(BInnerUnion) == sizeof(BInt) - assert sizeof(BStruct) == sizeof(BInt) * 3 - fields = [(name, fld.offset, fld.flags) for (name, fld) in BStruct.fields] - assert fields == [ - ('b1', 0 * sizeof(BInt), 0), - ('a1', 1 * sizeof(BInt), 0), - ('a2', 1 * sizeof(BInt), 1), - ('b2', 2 * sizeof(BInt), 0), - ] - -def test_sizeof_union(): - # a union has the largest alignment of its members, and a total size - # that is the largest of its items *possibly further aligned* if - # another smaller item has a larger alignment... - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - assert sizeof(BShort) == alignof(BShort) == 2 - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BChar), - ('a2', BChar), - ('a3', BChar)]) - assert sizeof(BStruct) == 3 and alignof(BStruct) == 1 - BUnion = new_union_type("union u") - complete_struct_or_union(BUnion, [('s', BStruct), - ('i', BShort)]) - assert sizeof(BUnion) == 4 - assert alignof(BUnion) == 2 - -def test_unaligned_struct(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('b', BInt, -1, 1)], - None, 5, 1) - -def test_CData_CType(): - CData, CType = _get_types() - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - nullchr = cast(BChar, 0) - chrref = newp(BCharP, None) - assert isinstance(nullchr, CData) - assert isinstance(chrref, CData) - assert not isinstance(BChar, CData) - assert not isinstance(nullchr, CType) - assert not isinstance(chrref, CType) - assert isinstance(BChar, CType) - -def test_no_cdata_float(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BUInt = new_primitive_type("unsigned int") - BUIntP = new_pointer_type(BUInt) - BFloat = new_primitive_type("float") - py.test.raises(TypeError, newp, BIntP, cast(BFloat, 0.0)) - py.test.raises(TypeError, newp, BUIntP, cast(BFloat, 0.0)) - -def test_bool(): - BBool = new_primitive_type("_Bool") - BBoolP = new_pointer_type(BBool) - assert int(cast(BBool, False)) == 0 - assert int(cast(BBool, True)) == 1 - assert bool(cast(BBool, False)) is False # since 1.7 - assert bool(cast(BBool, True)) is True - assert int(cast(BBool, 3)) == 1 - assert int(cast(BBool, long(3))) == 1 - assert int(cast(BBool, long(10)**4000)) == 1 - assert int(cast(BBool, -0.1)) == 1 - assert int(cast(BBool, -0.0)) == 0 - assert int(cast(BBool, '\x00')) == 0 - assert int(cast(BBool, '\xff')) == 1 - assert newp(BBoolP, False)[0] == 0 - assert newp(BBoolP, True)[0] == 1 - assert newp(BBoolP, 0)[0] == 0 - assert newp(BBoolP, 1)[0] == 1 - py.test.raises(TypeError, newp, BBoolP, 1.0) - py.test.raises(TypeError, newp, BBoolP, '\x00') - py.test.raises(OverflowError, newp, BBoolP, 2) - py.test.raises(OverflowError, newp, BBoolP, -1) - BCharP = new_pointer_type(new_primitive_type("char")) + assert len(x.a2) == 5 + # + py.test.raises(TypeError, newp, BStructP, [123]) + x = newp(BStructP, [123, 5]) + assert x.a1 == 123 + assert len(x.a2) == 5 + assert list(x.a2) == [0] * 5 + # + x = newp(BStructP, {'a2': 5}) + assert x.a1 == 0 + assert len(x.a2) == 5 + assert list(x.a2) == [0] * 5 + # + x = newp(BStructP, [123, (4, 5)]) + assert x.a1 == 123 + assert len(x.a2) == 2 + assert list(x.a2) == [4, 5] + # + x = newp(BStructP, {'a2': (4, 5)}) + assert x.a1 == 0 + assert len(x.a2) == 2 + assert list(x.a2) == [4, 5] + +def test_autocast_int(): + BInt = new_primitive_type("int") + BIntPtr = new_pointer_type(BInt) + BLongLong = new_primitive_type("long long") + BULongLong = new_primitive_type("unsigned long long") + BULongLongPtr = new_pointer_type(BULongLong) + x = newp(BIntPtr, cast(BInt, 42)) + assert x[0] == 42 + x = newp(BIntPtr, cast(BLongLong, 42)) + assert x[0] == 42 + x = newp(BIntPtr, cast(BULongLong, 42)) + assert x[0] == 42 + x = newp(BULongLongPtr, cast(BInt, 42)) + assert x[0] == 42 + py.test.raises(OverflowError, newp, BULongLongPtr, cast(BInt, -42)) + x = cast(BInt, cast(BInt, 42)) + assert int(x) == 42 + x = cast(BInt, cast(BLongLong, 42)) + assert int(x) == 42 + x = cast(BInt, cast(BULongLong, 42)) + assert int(x) == 42 + x = cast(BULongLong, cast(BInt, 42)) + assert int(x) == 42 + x = cast(BULongLong, cast(BInt, -42)) + assert int(x) == 2 ** 64 - 42 + x = cast(BIntPtr, cast(BInt, 42)) + assert int(cast(BInt, x)) == 42 + +def test_autocast_float(): + BFloat = new_primitive_type("float") + BDouble = new_primitive_type("float") + BFloatPtr = new_pointer_type(BFloat) + x = newp(BFloatPtr, cast(BDouble, 12.5)) + assert x[0] == 12.5 + x = cast(BFloat, cast(BDouble, 12.5)) + assert float(x) == 12.5 + +def test_longdouble(): + py_py = 'PY_DOT_PY' in globals() + BInt = new_primitive_type("int") + BLongDouble = new_primitive_type("long double") + BLongDoublePtr = new_pointer_type(BLongDouble) + BLongDoubleArray = new_array_type(BLongDoublePtr, None) + a = newp(BLongDoubleArray, 1) + x = a[0] + if not py_py: + assert repr(x).startswith("<cdata 'long double' 0.0") + assert float(x) == 0.0 + assert int(x) == 0 + # + b = newp(BLongDoubleArray, [1.23]) + x = b[0] + if not py_py: + assert repr(x).startswith("<cdata 'long double' 1.23") + assert float(x) == 1.23 + assert int(x) == 1 + # + BFunc19 = new_function_type((BLongDouble, BInt), BLongDouble) + f = cast(BFunc19, _testfunc(19)) + start = lstart = 1.5 + for i in range(107): + start = 4 * start - start * start + lstart = f(lstart, 1) + lother = f(1.5, 107) + if not py_py: + assert float(lstart) == float(lother) + assert repr(lstart) == repr(lother) + if sizeof(BLongDouble) > sizeof(new_primitive_type("double")): + assert float(lstart) != start + assert repr(lstart).startswith("<cdata 'long double' ") + # + c = newp(BLongDoubleArray, [lstart]) + x = c[0] + assert float(f(lstart, 107)) == float(f(x, 107)) + +def test_get_array_of_length_zero(): + for length in [0, 5, 10]: + BLong = new_primitive_type("long") + BLongP = new_pointer_type(BLong) + BArray0 = new_array_type(BLongP, length) + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BArray0, -1)]) + p = newp(BStructPtr, None) + if length == 0: + assert repr(p.a1).startswith("<cdata 'long *' 0x") + else: + assert repr(p.a1).startswith("<cdata 'long[%d]' 0x" % length) + +def test_nested_anonymous_struct(): + BInt = new_primitive_type("int") + BChar = new_primitive_type("char") + BStruct = new_struct_type("struct foo") + BInnerStruct = new_struct_type("struct foo") + complete_struct_or_union(BInnerStruct, [('a1', BInt, -1), + ('a2', BChar, -1)]) + complete_struct_or_union(BStruct, [('', BInnerStruct, -1), + ('a3', BChar, -1)]) + assert sizeof(BInnerStruct) == sizeof(BInt) * 2 # with alignment + assert sizeof(BStruct) == sizeof(BInt) * 3 # 'a3' is placed after + d = BStruct.fields + assert len(d) == 3 + assert d[0][0] == 'a1' + assert d[0][1].type is BInt + assert d[0][1].offset == 0 + assert d[0][1].bitshift == -1 + assert d[0][1].bitsize == -1 + assert d[1][0] == 'a2' + assert d[1][1].type is BChar + assert d[1][1].offset == sizeof(BInt) + assert d[1][1].bitshift == -1 + assert d[1][1].bitsize == -1 + assert d[2][0] == 'a3' + assert d[2][1].type is BChar + assert d[2][1].offset == sizeof(BInt) * 2 + assert d[2][1].bitshift == -1 + assert d[2][1].bitsize == -1 + +def test_nested_anonymous_struct_2(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + BInnerUnion = new_union_type("union bar") + complete_struct_or_union(BInnerUnion, [('a1', BInt, -1), + ('a2', BInt, -1)]) + complete_struct_or_union(BStruct, [('b1', BInt, -1), + ('', BInnerUnion, -1), + ('b2', BInt, -1)]) + assert sizeof(BInnerUnion) == sizeof(BInt) + assert sizeof(BStruct) == sizeof(BInt) * 3 + fields = [(name, fld.offset, fld.flags) for (name, fld) in BStruct.fields] + assert fields == [ + ('b1', 0 * sizeof(BInt), 0), + ('a1', 1 * sizeof(BInt), 0), + ('a2', 1 * sizeof(BInt), 1), + ('b2', 2 * sizeof(BInt), 0), + ] + +def test_sizeof_union(): + # a union has the largest alignment of its members, and a total size + # that is the largest of its items *possibly further aligned* if + # another smaller item has a larger alignment... + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + assert sizeof(BShort) == alignof(BShort) == 2 + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, [('a1', BChar), + ('a2', BChar), + ('a3', BChar)]) + assert sizeof(BStruct) == 3 and alignof(BStruct) == 1 + BUnion = new_union_type("union u") + complete_struct_or_union(BUnion, [('s', BStruct), + ('i', BShort)]) + assert sizeof(BUnion) == 4 + assert alignof(BUnion) == 2 + +def test_unaligned_struct(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, [('b', BInt, -1, 1)], + None, 5, 1) + +def test_CData_CType(): + CData, CType = _get_types() + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + nullchr = cast(BChar, 0) + chrref = newp(BCharP, None) + assert isinstance(nullchr, CData) + assert isinstance(chrref, CData) + assert not isinstance(BChar, CData) + assert not isinstance(nullchr, CType) + assert not isinstance(chrref, CType) + assert isinstance(BChar, CType) + +def test_no_cdata_float(): + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BUInt = new_primitive_type("unsigned int") + BUIntP = new_pointer_type(BUInt) + BFloat = new_primitive_type("float") + py.test.raises(TypeError, newp, BIntP, cast(BFloat, 0.0)) + py.test.raises(TypeError, newp, BUIntP, cast(BFloat, 0.0)) + +def test_bool(): + BBool = new_primitive_type("_Bool") + BBoolP = new_pointer_type(BBool) + assert int(cast(BBool, False)) == 0 + assert int(cast(BBool, True)) == 1 + assert bool(cast(BBool, False)) is False # since 1.7 + assert bool(cast(BBool, True)) is True + assert int(cast(BBool, 3)) == 1 + assert int(cast(BBool, long(3))) == 1 + assert int(cast(BBool, long(10)**4000)) == 1 + assert int(cast(BBool, -0.1)) == 1 + assert int(cast(BBool, -0.0)) == 0 + assert int(cast(BBool, '\x00')) == 0 + assert int(cast(BBool, '\xff')) == 1 + assert newp(BBoolP, False)[0] == 0 + assert newp(BBoolP, True)[0] == 1 + assert newp(BBoolP, 0)[0] == 0 + assert newp(BBoolP, 1)[0] == 1 + py.test.raises(TypeError, newp, BBoolP, 1.0) + py.test.raises(TypeError, newp, BBoolP, '\x00') + py.test.raises(OverflowError, newp, BBoolP, 2) + py.test.raises(OverflowError, newp, BBoolP, -1) + BCharP = new_pointer_type(new_primitive_type("char")) p = newp(BCharP, b'\x01') - q = cast(BBoolP, p) + q = cast(BBoolP, p) assert q[0] is True p = newp(BCharP, b'\x00') q = cast(BBoolP, p) assert q[0] is False - py.test.raises(TypeError, string, cast(BBool, False)) - BDouble = new_primitive_type("double") - assert int(cast(BBool, cast(BDouble, 0.1))) == 1 - assert int(cast(BBool, cast(BDouble, 0.0))) == 0 + py.test.raises(TypeError, string, cast(BBool, False)) + BDouble = new_primitive_type("double") + assert int(cast(BBool, cast(BDouble, 0.1))) == 1 + assert int(cast(BBool, cast(BDouble, 0.0))) == 0 BBoolA = new_array_type(BBoolP, None) p = newp(BBoolA, b'\x01\x00') assert p[0] is True assert p[1] is False - + def test_bool_forbidden_cases(): BBool = new_primitive_type("_Bool") BBoolP = new_pointer_type(BBool) @@ -2925,619 +2925,619 @@ def test_bool_forbidden_cases(): py.test.raises(TypeError, string, newp(BBoolP, 1)) py.test.raises(TypeError, string, newp(BBoolA, [1])) -def test_typeoffsetof(): - BChar = new_primitive_type("char") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BChar, -1), - ('a3', BChar, -1)]) - py.test.raises(TypeError, typeoffsetof, BStructPtr, None) - py.test.raises(TypeError, typeoffsetof, BStruct, None) - assert typeoffsetof(BStructPtr, 'a1') == (BChar, 0) - assert typeoffsetof(BStruct, 'a1') == (BChar, 0) - assert typeoffsetof(BStructPtr, 'a2') == (BChar, 1) - assert typeoffsetof(BStruct, 'a3') == (BChar, 2) - assert typeoffsetof(BStructPtr, 'a2', 0) == (BChar, 1) - assert typeoffsetof(BStruct, u+'a3') == (BChar, 2) - py.test.raises(TypeError, typeoffsetof, BStructPtr, 'a2', 1) - py.test.raises(KeyError, typeoffsetof, BStructPtr, 'a4') - py.test.raises(KeyError, typeoffsetof, BStruct, 'a5') - py.test.raises(TypeError, typeoffsetof, BStruct, 42) - py.test.raises(TypeError, typeoffsetof, BChar, 'a1') - -def test_typeoffsetof_array(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, None) - py.test.raises(TypeError, typeoffsetof, BArray, None) - py.test.raises(TypeError, typeoffsetof, BArray, 'a1') - assert typeoffsetof(BArray, 51) == (BInt, 51 * size_of_int()) - assert typeoffsetof(BIntP, 51) == (BInt, 51 * size_of_int()) - assert typeoffsetof(BArray, -51) == (BInt, -51 * size_of_int()) - MAX = sys.maxsize // size_of_int() - assert typeoffsetof(BArray, MAX) == (BInt, MAX * size_of_int()) - assert typeoffsetof(BIntP, MAX) == (BInt, MAX * size_of_int()) - py.test.raises(OverflowError, typeoffsetof, BArray, MAX + 1) - -def test_typeoffsetof_no_bitfield(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BInt, 4)]) - py.test.raises(TypeError, typeoffsetof, BStruct, 'a1') - -def test_rawaddressof(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BChar, -1), - ('a3', BChar, -1)]) - p = newp(BStructPtr) - assert repr(p) == "<cdata 'struct foo *' owning 3 bytes>" - s = p[0] - assert repr(s) == "<cdata 'struct foo' owning 3 bytes>" - a = rawaddressof(BStructPtr, s, 0) - assert repr(a).startswith("<cdata 'struct foo *' 0x") - py.test.raises(TypeError, rawaddressof, BStruct, s, 0) - b = rawaddressof(BCharP, s, 0) - assert b == cast(BCharP, p) - c = rawaddressof(BStructPtr, a, 0) - assert c == a - py.test.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?'), 0) - # - d = rawaddressof(BCharP, s, 1) - assert d == cast(BCharP, p) + 1 - # - e = cast(BCharP, 109238) - f = rawaddressof(BCharP, e, 42) - assert f == e + 42 - # - BCharA = new_array_type(BCharP, None) - e = newp(BCharA, 50) - f = rawaddressof(BCharP, e, 42) - assert f == e + 42 - -def test_newp_signed_unsigned_char(): - BCharArray = new_array_type( - new_pointer_type(new_primitive_type("char")), None) - p = newp(BCharArray, b"foo") - assert len(p) == 4 - assert list(p) == [b"f", b"o", b"o", b"\x00"] - # - BUCharArray = new_array_type( - new_pointer_type(new_primitive_type("unsigned char")), None) - p = newp(BUCharArray, b"fo\xff") - assert len(p) == 4 - assert list(p) == [ord("f"), ord("o"), 0xff, 0] - # - BSCharArray = new_array_type( - new_pointer_type(new_primitive_type("signed char")), None) - p = newp(BSCharArray, b"fo\xff") - assert len(p) == 4 - assert list(p) == [ord("f"), ord("o"), -1, 0] - -def test_newp_from_bytearray_doesnt_work(): - BCharArray = new_array_type( - new_pointer_type(new_primitive_type("char")), None) - py.test.raises(TypeError, newp, BCharArray, bytearray(b"foo")) - p = newp(BCharArray, 5) - buffer(p)[:] = bytearray(b"foo.\x00") - assert len(p) == 5 - assert list(p) == [b"f", b"o", b"o", b".", b"\x00"] - p[1:3] = bytearray(b"XY") - assert list(p) == [b"f", b"X", b"Y", b".", b"\x00"] - -def test_string_assignment_to_byte_array(): - BByteArray = new_array_type( - new_pointer_type(new_primitive_type("unsigned char")), None) - p = newp(BByteArray, 5) - p[0:3] = bytearray(b"XYZ") - assert list(p) == [ord("X"), ord("Y"), ord("Z"), 0, 0] - -# XXX hack -if sys.version_info >= (3,): - try: - import posix, io - posix.fdopen = io.open - except ImportError: - pass # win32 - -def test_FILE(): - if sys.platform == "win32": - py.test.skip("testing FILE not implemented") - # - BFILE = new_struct_type("struct _IO_FILE") - BFILEP = new_pointer_type(BFILE) - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BInt = new_primitive_type("int") - BFunc = new_function_type((BCharP, BFILEP), BInt, False) - BFunc2 = new_function_type((BFILEP, BCharP), BInt, True) - ll = find_and_load_library('c') - fputs = ll.load_function(BFunc, "fputs") - fscanf = ll.load_function(BFunc2, "fscanf") - # - import posix - fdr, fdw = posix.pipe() - fr1 = posix.fdopen(fdr, 'rb', 256) - fw1 = posix.fdopen(fdw, 'wb', 256) - # - fw1.write(b"X") - res = fputs(b"hello world\n", fw1) - assert res >= 0 - fw1.flush() # should not be needed - # - p = newp(new_array_type(BCharP, 100), None) - res = fscanf(fr1, b"%s\n", p) - assert res == 1 - assert string(p) == b"Xhello" - fr1.close() - fw1.close() - -def test_FILE_only_for_FILE_arg(): - if sys.platform == "win32": - py.test.skip("testing FILE not implemented") - # - B_NOT_FILE = new_struct_type("struct NOT_FILE") - B_NOT_FILEP = new_pointer_type(B_NOT_FILE) - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BInt = new_primitive_type("int") - BFunc = new_function_type((BCharP, B_NOT_FILEP), BInt, False) - ll = find_and_load_library('c') - fputs = ll.load_function(BFunc, "fputs") - # - import posix - fdr, fdw = posix.pipe() - fr1 = posix.fdopen(fdr, 'r') - fw1 = posix.fdopen(fdw, 'w') - # - e = py.test.raises(TypeError, fputs, b"hello world\n", fw1) - assert str(e.value).startswith( - "initializer for ctype 'struct NOT_FILE *' must " - "be a cdata pointer, not ") - -def test_FILE_object(): - if sys.platform == "win32": - py.test.skip("testing FILE not implemented") - # - BFILE = new_struct_type("FILE") - BFILEP = new_pointer_type(BFILE) - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BInt = new_primitive_type("int") - BFunc = new_function_type((BCharP, BFILEP), BInt, False) - BFunc2 = new_function_type((BFILEP,), BInt, False) - ll = find_and_load_library('c') - fputs = ll.load_function(BFunc, "fputs") - fileno = ll.load_function(BFunc2, "fileno") - # - import posix - fdr, fdw = posix.pipe() - fw1 = posix.fdopen(fdw, 'wb', 256) - # - fw1p = cast(BFILEP, fw1) - fw1.write(b"X") - fw1.flush() - res = fputs(b"hello\n", fw1p) - assert res >= 0 - res = fileno(fw1p) - assert (res == fdw) == (sys.version_info < (3,)) - fw1.close() - # - data = posix.read(fdr, 256) - assert data == b"Xhello\n" - posix.close(fdr) - -def test_errno_saved(): - set_errno(42) - # a random function that will reset errno to 0 (at least on non-windows) - import os; os.stat('.') - # - res = get_errno() - assert res == 42 - -def test_GetLastError(): - if sys.platform != "win32": - py.test.skip("GetLastError(): only for Windows") - # - lib = find_and_load_library('KERNEL32.DLL') - BInt = new_primitive_type("int") - BVoid = new_void_type() - BFunc1 = new_function_type((BInt,), BVoid, False) - BFunc2 = new_function_type((), BInt, False) - SetLastError = lib.load_function(BFunc1, "SetLastError") - GetLastError = lib.load_function(BFunc2, "GetLastError") - # - SetLastError(42) - # a random function that will reset the real GetLastError() to 0 - import nt; nt.stat('.') - # - res = GetLastError() - assert res == 42 - # - SetLastError(2) - code, message = getwinerror() - assert code == 2 - assert message == "The system cannot find the file specified" - # - code, message = getwinerror(1155) - assert code == 1155 - assert message == ("No application is associated with the " - "specified file for this operation") - -def test_nonstandard_integer_types(): - for typename in ['int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t', - 'uint32_t', 'int64_t', 'uint64_t', 'intptr_t', - 'uintptr_t', 'ptrdiff_t', 'size_t', 'ssize_t', - 'int_least8_t', 'uint_least8_t', - 'int_least16_t', 'uint_least16_t', - 'int_least32_t', 'uint_least32_t', - 'int_least64_t', 'uint_least64_t', - 'int_fast8_t', 'uint_fast8_t', - 'int_fast16_t', 'uint_fast16_t', - 'int_fast32_t', 'uint_fast32_t', - 'int_fast64_t', 'uint_fast64_t', - 'intmax_t', 'uintmax_t']: - new_primitive_type(typename) # works - -def test_cannot_convert_unicode_to_charp(): - BCharP = new_pointer_type(new_primitive_type("char")) - BCharArray = new_array_type(BCharP, None) - py.test.raises(TypeError, newp, BCharArray, u+'foobar') - -def test_buffer_keepalive(): - BCharP = new_pointer_type(new_primitive_type("char")) - BCharArray = new_array_type(BCharP, None) - buflist = [] - for i in range(20): - c = newp(BCharArray, str2bytes("hi there %d" % i)) - buflist.append(buffer(c)) - import gc; gc.collect() - for i in range(20): - buf = buflist[i] - assert buf[:] == str2bytes("hi there %d\x00" % i) - -def test_slice(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - assert len(c) == 5 - assert repr(c) == "<cdata 'int[]' owning 20 bytes>" - d = c[1:4] - assert len(d) == 3 - assert repr(d) == "<cdata 'int[]' sliced length 3>" - d[0] = 123 - d[2] = 456 - assert c[1] == 123 - assert c[3] == 456 - assert d[2] == 456 +def test_typeoffsetof(): + BChar = new_primitive_type("char") + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BChar, -1), + ('a2', BChar, -1), + ('a3', BChar, -1)]) + py.test.raises(TypeError, typeoffsetof, BStructPtr, None) + py.test.raises(TypeError, typeoffsetof, BStruct, None) + assert typeoffsetof(BStructPtr, 'a1') == (BChar, 0) + assert typeoffsetof(BStruct, 'a1') == (BChar, 0) + assert typeoffsetof(BStructPtr, 'a2') == (BChar, 1) + assert typeoffsetof(BStruct, 'a3') == (BChar, 2) + assert typeoffsetof(BStructPtr, 'a2', 0) == (BChar, 1) + assert typeoffsetof(BStruct, u+'a3') == (BChar, 2) + py.test.raises(TypeError, typeoffsetof, BStructPtr, 'a2', 1) + py.test.raises(KeyError, typeoffsetof, BStructPtr, 'a4') + py.test.raises(KeyError, typeoffsetof, BStruct, 'a5') + py.test.raises(TypeError, typeoffsetof, BStruct, 42) + py.test.raises(TypeError, typeoffsetof, BChar, 'a1') + +def test_typeoffsetof_array(): + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BArray = new_array_type(BIntP, None) + py.test.raises(TypeError, typeoffsetof, BArray, None) + py.test.raises(TypeError, typeoffsetof, BArray, 'a1') + assert typeoffsetof(BArray, 51) == (BInt, 51 * size_of_int()) + assert typeoffsetof(BIntP, 51) == (BInt, 51 * size_of_int()) + assert typeoffsetof(BArray, -51) == (BInt, -51 * size_of_int()) + MAX = sys.maxsize // size_of_int() + assert typeoffsetof(BArray, MAX) == (BInt, MAX * size_of_int()) + assert typeoffsetof(BIntP, MAX) == (BInt, MAX * size_of_int()) + py.test.raises(OverflowError, typeoffsetof, BArray, MAX + 1) + +def test_typeoffsetof_no_bitfield(): + BInt = new_primitive_type("int") + BStruct = new_struct_type("struct foo") + complete_struct_or_union(BStruct, [('a1', BInt, 4)]) + py.test.raises(TypeError, typeoffsetof, BStruct, 'a1') + +def test_rawaddressof(): + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BStruct = new_struct_type("struct foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BChar, -1), + ('a2', BChar, -1), + ('a3', BChar, -1)]) + p = newp(BStructPtr) + assert repr(p) == "<cdata 'struct foo *' owning 3 bytes>" + s = p[0] + assert repr(s) == "<cdata 'struct foo' owning 3 bytes>" + a = rawaddressof(BStructPtr, s, 0) + assert repr(a).startswith("<cdata 'struct foo *' 0x") + py.test.raises(TypeError, rawaddressof, BStruct, s, 0) + b = rawaddressof(BCharP, s, 0) + assert b == cast(BCharP, p) + c = rawaddressof(BStructPtr, a, 0) + assert c == a + py.test.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?'), 0) + # + d = rawaddressof(BCharP, s, 1) + assert d == cast(BCharP, p) + 1 + # + e = cast(BCharP, 109238) + f = rawaddressof(BCharP, e, 42) + assert f == e + 42 + # + BCharA = new_array_type(BCharP, None) + e = newp(BCharA, 50) + f = rawaddressof(BCharP, e, 42) + assert f == e + 42 + +def test_newp_signed_unsigned_char(): + BCharArray = new_array_type( + new_pointer_type(new_primitive_type("char")), None) + p = newp(BCharArray, b"foo") + assert len(p) == 4 + assert list(p) == [b"f", b"o", b"o", b"\x00"] + # + BUCharArray = new_array_type( + new_pointer_type(new_primitive_type("unsigned char")), None) + p = newp(BUCharArray, b"fo\xff") + assert len(p) == 4 + assert list(p) == [ord("f"), ord("o"), 0xff, 0] + # + BSCharArray = new_array_type( + new_pointer_type(new_primitive_type("signed char")), None) + p = newp(BSCharArray, b"fo\xff") + assert len(p) == 4 + assert list(p) == [ord("f"), ord("o"), -1, 0] + +def test_newp_from_bytearray_doesnt_work(): + BCharArray = new_array_type( + new_pointer_type(new_primitive_type("char")), None) + py.test.raises(TypeError, newp, BCharArray, bytearray(b"foo")) + p = newp(BCharArray, 5) + buffer(p)[:] = bytearray(b"foo.\x00") + assert len(p) == 5 + assert list(p) == [b"f", b"o", b"o", b".", b"\x00"] + p[1:3] = bytearray(b"XY") + assert list(p) == [b"f", b"X", b"Y", b".", b"\x00"] + +def test_string_assignment_to_byte_array(): + BByteArray = new_array_type( + new_pointer_type(new_primitive_type("unsigned char")), None) + p = newp(BByteArray, 5) + p[0:3] = bytearray(b"XYZ") + assert list(p) == [ord("X"), ord("Y"), ord("Z"), 0, 0] + +# XXX hack +if sys.version_info >= (3,): + try: + import posix, io + posix.fdopen = io.open + except ImportError: + pass # win32 + +def test_FILE(): + if sys.platform == "win32": + py.test.skip("testing FILE not implemented") + # + BFILE = new_struct_type("struct _IO_FILE") + BFILEP = new_pointer_type(BFILE) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BInt = new_primitive_type("int") + BFunc = new_function_type((BCharP, BFILEP), BInt, False) + BFunc2 = new_function_type((BFILEP, BCharP), BInt, True) + ll = find_and_load_library('c') + fputs = ll.load_function(BFunc, "fputs") + fscanf = ll.load_function(BFunc2, "fscanf") + # + import posix + fdr, fdw = posix.pipe() + fr1 = posix.fdopen(fdr, 'rb', 256) + fw1 = posix.fdopen(fdw, 'wb', 256) + # + fw1.write(b"X") + res = fputs(b"hello world\n", fw1) + assert res >= 0 + fw1.flush() # should not be needed + # + p = newp(new_array_type(BCharP, 100), None) + res = fscanf(fr1, b"%s\n", p) + assert res == 1 + assert string(p) == b"Xhello" + fr1.close() + fw1.close() + +def test_FILE_only_for_FILE_arg(): + if sys.platform == "win32": + py.test.skip("testing FILE not implemented") + # + B_NOT_FILE = new_struct_type("struct NOT_FILE") + B_NOT_FILEP = new_pointer_type(B_NOT_FILE) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BInt = new_primitive_type("int") + BFunc = new_function_type((BCharP, B_NOT_FILEP), BInt, False) + ll = find_and_load_library('c') + fputs = ll.load_function(BFunc, "fputs") + # + import posix + fdr, fdw = posix.pipe() + fr1 = posix.fdopen(fdr, 'r') + fw1 = posix.fdopen(fdw, 'w') + # + e = py.test.raises(TypeError, fputs, b"hello world\n", fw1) + assert str(e.value).startswith( + "initializer for ctype 'struct NOT_FILE *' must " + "be a cdata pointer, not ") + +def test_FILE_object(): + if sys.platform == "win32": + py.test.skip("testing FILE not implemented") + # + BFILE = new_struct_type("FILE") + BFILEP = new_pointer_type(BFILE) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BInt = new_primitive_type("int") + BFunc = new_function_type((BCharP, BFILEP), BInt, False) + BFunc2 = new_function_type((BFILEP,), BInt, False) + ll = find_and_load_library('c') + fputs = ll.load_function(BFunc, "fputs") + fileno = ll.load_function(BFunc2, "fileno") + # + import posix + fdr, fdw = posix.pipe() + fw1 = posix.fdopen(fdw, 'wb', 256) + # + fw1p = cast(BFILEP, fw1) + fw1.write(b"X") + fw1.flush() + res = fputs(b"hello\n", fw1p) + assert res >= 0 + res = fileno(fw1p) + assert (res == fdw) == (sys.version_info < (3,)) + fw1.close() + # + data = posix.read(fdr, 256) + assert data == b"Xhello\n" + posix.close(fdr) + +def test_errno_saved(): + set_errno(42) + # a random function that will reset errno to 0 (at least on non-windows) + import os; os.stat('.') + # + res = get_errno() + assert res == 42 + +def test_GetLastError(): + if sys.platform != "win32": + py.test.skip("GetLastError(): only for Windows") + # + lib = find_and_load_library('KERNEL32.DLL') + BInt = new_primitive_type("int") + BVoid = new_void_type() + BFunc1 = new_function_type((BInt,), BVoid, False) + BFunc2 = new_function_type((), BInt, False) + SetLastError = lib.load_function(BFunc1, "SetLastError") + GetLastError = lib.load_function(BFunc2, "GetLastError") + # + SetLastError(42) + # a random function that will reset the real GetLastError() to 0 + import nt; nt.stat('.') + # + res = GetLastError() + assert res == 42 + # + SetLastError(2) + code, message = getwinerror() + assert code == 2 + assert message == "The system cannot find the file specified" + # + code, message = getwinerror(1155) + assert code == 1155 + assert message == ("No application is associated with the " + "specified file for this operation") + +def test_nonstandard_integer_types(): + for typename in ['int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t', + 'uint32_t', 'int64_t', 'uint64_t', 'intptr_t', + 'uintptr_t', 'ptrdiff_t', 'size_t', 'ssize_t', + 'int_least8_t', 'uint_least8_t', + 'int_least16_t', 'uint_least16_t', + 'int_least32_t', 'uint_least32_t', + 'int_least64_t', 'uint_least64_t', + 'int_fast8_t', 'uint_fast8_t', + 'int_fast16_t', 'uint_fast16_t', + 'int_fast32_t', 'uint_fast32_t', + 'int_fast64_t', 'uint_fast64_t', + 'intmax_t', 'uintmax_t']: + new_primitive_type(typename) # works + +def test_cannot_convert_unicode_to_charp(): + BCharP = new_pointer_type(new_primitive_type("char")) + BCharArray = new_array_type(BCharP, None) + py.test.raises(TypeError, newp, BCharArray, u+'foobar') + +def test_buffer_keepalive(): + BCharP = new_pointer_type(new_primitive_type("char")) + BCharArray = new_array_type(BCharP, None) + buflist = [] + for i in range(20): + c = newp(BCharArray, str2bytes("hi there %d" % i)) + buflist.append(buffer(c)) + import gc; gc.collect() + for i in range(20): + buf = buflist[i] + assert buf[:] == str2bytes("hi there %d\x00" % i) + +def test_slice(): + BIntP = new_pointer_type(new_primitive_type("int")) + BIntArray = new_array_type(BIntP, None) + c = newp(BIntArray, 5) + assert len(c) == 5 + assert repr(c) == "<cdata 'int[]' owning 20 bytes>" + d = c[1:4] + assert len(d) == 3 + assert repr(d) == "<cdata 'int[]' sliced length 3>" + d[0] = 123 + d[2] = 456 + assert c[1] == 123 + assert c[3] == 456 + assert d[2] == 456 with pytest.raises(IndexError): d[3] with pytest.raises(IndexError): d[-1] - -def test_slice_ptr(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - d = (c+1)[0:2] - assert len(d) == 2 - assert repr(d) == "<cdata 'int[]' sliced length 2>" - d[1] += 50 - assert c[2] == 50 - -def test_slice_array_checkbounds(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - c[0:5] - assert len(c[5:5]) == 0 + +def test_slice_ptr(): + BIntP = new_pointer_type(new_primitive_type("int")) + BIntArray = new_array_type(BIntP, None) + c = newp(BIntArray, 5) + d = (c+1)[0:2] + assert len(d) == 2 + assert repr(d) == "<cdata 'int[]' sliced length 2>" + d[1] += 50 + assert c[2] == 50 + +def test_slice_array_checkbounds(): + BIntP = new_pointer_type(new_primitive_type("int")) + BIntArray = new_array_type(BIntP, None) + c = newp(BIntArray, 5) + c[0:5] + assert len(c[5:5]) == 0 with pytest.raises(IndexError): c[-1:1] - cp = c + 0 - cp[-1:1] - -def test_nonstandard_slice(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) + cp = c + 0 + cp[-1:1] + +def test_nonstandard_slice(): + BIntP = new_pointer_type(new_primitive_type("int")) + BIntArray = new_array_type(BIntP, None) + c = newp(BIntArray, 5) with pytest.raises(IndexError) as e: c[:5] - assert str(e.value) == "slice start must be specified" + assert str(e.value) == "slice start must be specified" with pytest.raises(IndexError) as e: c[4:] - assert str(e.value) == "slice stop must be specified" + assert str(e.value) == "slice stop must be specified" with pytest.raises(IndexError) as e: c[1:2:3] - assert str(e.value) == "slice with step not supported" + assert str(e.value) == "slice with step not supported" with pytest.raises(IndexError) as e: c[1:2:1] - assert str(e.value) == "slice with step not supported" + assert str(e.value) == "slice with step not supported" with pytest.raises(IndexError) as e: c[4:2] - assert str(e.value) == "slice start > stop" + assert str(e.value) == "slice start > stop" with pytest.raises(IndexError) as e: c[6:6] - assert str(e.value) == "index too large (expected 6 <= 5)" - -def test_setslice(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - c[1:3] = [100, 200] - assert list(c) == [0, 100, 200, 0, 0] - cp = c + 3 - cp[-1:1] = [300, 400] - assert list(c) == [0, 100, 300, 400, 0] - cp[-1:1] = iter([500, 600]) - assert list(c) == [0, 100, 500, 600, 0] + assert str(e.value) == "index too large (expected 6 <= 5)" + +def test_setslice(): + BIntP = new_pointer_type(new_primitive_type("int")) + BIntArray = new_array_type(BIntP, None) + c = newp(BIntArray, 5) + c[1:3] = [100, 200] + assert list(c) == [0, 100, 200, 0, 0] + cp = c + 3 + cp[-1:1] = [300, 400] + assert list(c) == [0, 100, 300, 400, 0] + cp[-1:1] = iter([500, 600]) + assert list(c) == [0, 100, 500, 600, 0] with pytest.raises(ValueError): cp[-1:1] = [1000] - assert list(c) == [0, 100, 1000, 600, 0] + assert list(c) == [0, 100, 1000, 600, 0] with pytest.raises(ValueError): cp[-1:1] = (700, 800, 900) - assert list(c) == [0, 100, 700, 800, 0] - -def test_setslice_array(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - d = newp(BIntArray, [10, 20, 30]) - c[1:4] = d - assert list(c) == [0, 10, 20, 30, 0] - # - BShortP = new_pointer_type(new_primitive_type("short")) - BShortArray = new_array_type(BShortP, None) - d = newp(BShortArray, [40, 50]) - c[1:3] = d - assert list(c) == [0, 40, 50, 30, 0] - -def test_cdata_name_module_doc(): - p = new_primitive_type("signed char") - x = cast(p, 17) - assert x.__module__ == '_cffi_backend' - assert x.__name__ == '<cdata>' - assert hasattr(x, '__doc__') - -def test_different_types_of_ptr_equality(): - BVoidP = new_pointer_type(new_void_type()) - BIntP = new_pointer_type(new_primitive_type("int")) - x = cast(BVoidP, 12345) - assert x == cast(BIntP, 12345) - assert x != cast(BIntP, 12344) - assert hash(x) == hash(cast(BIntP, 12345)) - -def test_new_handle(): - import _weakref - BVoidP = new_pointer_type(new_void_type()) - BCharP = new_pointer_type(new_primitive_type("char")) - class mylist(list): - pass - o = mylist([2, 3, 4]) - x = newp_handle(BVoidP, o) - assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>" - assert x - assert from_handle(x) is o - assert from_handle(cast(BCharP, x)) is o - wr = _weakref.ref(o) - del o - import gc; gc.collect() - assert wr() is not None - assert from_handle(x) == list((2, 3, 4)) - assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) - del x - for i in range(3): - if wr() is not None: - import gc; gc.collect() - assert wr() is None - py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) - -def test_new_handle_cycle(): - import _weakref - BVoidP = new_pointer_type(new_void_type()) - class A(object): - pass - o = A() - o.cycle = newp_handle(BVoidP, o) - wr = _weakref.ref(o) - del o - for i in range(3): - if wr() is not None: - import gc; gc.collect() - assert wr() is None - -def _test_bitfield_details(flag): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BInt = new_primitive_type("int") - BUInt = new_primitive_type("unsigned int") - BStruct = new_struct_type("struct foo1") - complete_struct_or_union(BStruct, [('a', BChar, -1), - ('b1', BInt, 9), - ('b2', BUInt, 7), - ('c', BChar, -1)], -1, -1, -1, flag) - if not (flag & SF_MSVC_BITFIELDS): # gcc, any variant - assert typeoffsetof(BStruct, 'c') == (BChar, 3) - assert sizeof(BStruct) == 4 - else: # msvc - assert typeoffsetof(BStruct, 'c') == (BChar, 8) - assert sizeof(BStruct) == 12 - assert alignof(BStruct) == 4 - # - p = newp(new_pointer_type(BStruct), None) - p.a = b'A' - p.b1 = -201 - p.b2 = 99 - p.c = b'\x9D' - raw = buffer(p)[:] - if sys.byteorder == 'little': - if flag & SF_MSVC_BITFIELDS: - assert raw == b'A\x00\x00\x007\xC7\x00\x00\x9D\x00\x00\x00' - elif flag & SF_GCC_LITTLE_ENDIAN: - assert raw == b'A7\xC7\x9D' - elif flag & SF_GCC_BIG_ENDIAN: - assert raw == b'A\xE3\x9B\x9D' - else: - raise AssertionError("bad flag") - else: - if flag & SF_MSVC_BITFIELDS: - assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00' - elif flag & SF_GCC_LITTLE_ENDIAN: - assert raw == b'A\xC77\x9D' - elif flag & SF_GCC_BIG_ENDIAN: - assert raw == b'A\x9B\xE3\x9D' - else: - raise AssertionError("bad flag") - # - BStruct = new_struct_type("struct foo2") - complete_struct_or_union(BStruct, [('a', BChar, -1), - ('', BShort, 9), - ('c', BChar, -1)], -1, -1, -1, flag) - assert typeoffsetof(BStruct, 'c') == (BChar, 4) - if flag & SF_MSVC_BITFIELDS: - assert sizeof(BStruct) == 6 - assert alignof(BStruct) == 2 - elif flag & SF_GCC_X86_BITFIELDS: - assert sizeof(BStruct) == 5 - assert alignof(BStruct) == 1 - elif flag & SF_GCC_ARM_BITFIELDS: - assert sizeof(BStruct) == 6 - assert alignof(BStruct) == 2 - else: - raise AssertionError("bad flag") - # - BStruct = new_struct_type("struct foo2") - complete_struct_or_union(BStruct, [('a', BChar, -1), - ('', BInt, 0), - ('', BInt, 0), - ('c', BChar, -1)], -1, -1, -1, flag) - if flag & SF_MSVC_BITFIELDS: - assert typeoffsetof(BStruct, 'c') == (BChar, 1) - assert sizeof(BStruct) == 2 - assert alignof(BStruct) == 1 - elif flag & SF_GCC_X86_BITFIELDS: - assert typeoffsetof(BStruct, 'c') == (BChar, 4) - assert sizeof(BStruct) == 5 - assert alignof(BStruct) == 1 - elif flag & SF_GCC_ARM_BITFIELDS: - assert typeoffsetof(BStruct, 'c') == (BChar, 4) - assert sizeof(BStruct) == 8 - assert alignof(BStruct) == 4 - else: - raise AssertionError("bad flag") - - -SF_MSVC_BITFIELDS = 0x01 -SF_GCC_ARM_BITFIELDS = 0x02 -SF_GCC_X86_BITFIELDS = 0x10 - -SF_GCC_BIG_ENDIAN = 0x04 -SF_GCC_LITTLE_ENDIAN = 0x40 - -SF_PACKED = 0x08 - -def test_bitfield_as_x86_gcc(): - _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_LITTLE_ENDIAN) - -def test_bitfield_as_msvc(): - _test_bitfield_details(flag=SF_MSVC_BITFIELDS|SF_GCC_LITTLE_ENDIAN) - -def test_bitfield_as_arm_gcc(): - _test_bitfield_details(flag=SF_GCC_ARM_BITFIELDS|SF_GCC_LITTLE_ENDIAN) - -def test_bitfield_as_ppc_gcc(): - # PowerPC uses the same format as X86, but is big-endian - _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_BIG_ENDIAN) - - -def test_struct_array_no_length(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, None) - BStruct = new_struct_type("foo") - py.test.raises(TypeError, complete_struct_or_union, - BStruct, [('x', BArray), - ('y', BInt)]) - # - BStruct = new_struct_type("foo") - complete_struct_or_union(BStruct, [('x', BInt), - ('y', BArray)]) - assert sizeof(BStruct) == size_of_int() - d = BStruct.fields - assert len(d) == 2 - assert d[0][0] == 'x' - assert d[0][1].type is BInt - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 - assert d[1][0] == 'y' - assert d[1][1].type is BArray - assert d[1][1].offset == size_of_int() - assert d[1][1].bitshift == -2 - assert d[1][1].bitsize == -1 - # - p = newp(new_pointer_type(BStruct)) - p.x = 42 - assert p.x == 42 - assert typeof(p.y) is BArray - assert len(p.y) == 0 - assert p.y == cast(BIntP, p) + 1 - # - p = newp(new_pointer_type(BStruct), [100]) - assert p.x == 100 - assert len(p.y) == 0 - # - # Tests for - # ffi.new("struct_with_var_array *", [field.., [the_array_items..]]) - # ffi.new("struct_with_var_array *", [field.., array_size]) - plist = [] - for i in range(20): - if i % 2 == 0: - p = newp(new_pointer_type(BStruct), [100, [200, i, 400]]) - else: - p = newp(new_pointer_type(BStruct), [100, 3]) - p.y[1] = i - p.y[0] = 200 - assert p.y[2] == 0 - p.y[2] = 400 - assert len(p.y) == 3 - assert len(p[0].y) == 3 - assert len(buffer(p)) == sizeof(BInt) * 4 - assert sizeof(p[0]) == sizeof(BInt) * 4 - plist.append(p) - for i in range(20): - p = plist[i] - assert p.x == 100 - assert p.y[0] == 200 - assert p.y[1] == i - assert p.y[2] == 400 - assert list(p.y) == [200, i, 400] - # - # the following assignment works, as it normally would, for any array field - p.y = [501, 601] - assert list(p.y) == [501, 601, 400] - p[0].y = [500, 600] - assert list(p[0].y) == [500, 600, 400] - assert repr(p) == "<cdata 'foo *' owning %d bytes>" % ( - sizeof(BStruct) + 3 * sizeof(BInt),) - assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % ( - sizeof(BStruct) + 3 * sizeof(BInt),) - assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt) - # - # from a non-owning pointer, we can't get the length - q = cast(new_pointer_type(BStruct), p) - assert q.y[0] == 500 - assert q[0].y[0] == 500 - py.test.raises(TypeError, len, q.y) - py.test.raises(TypeError, len, q[0].y) - assert typeof(q.y) is BIntP - assert typeof(q[0].y) is BIntP - assert sizeof(q[0]) == sizeof(BStruct) - # - # error cases + assert list(c) == [0, 100, 700, 800, 0] + +def test_setslice_array(): + BIntP = new_pointer_type(new_primitive_type("int")) + BIntArray = new_array_type(BIntP, None) + c = newp(BIntArray, 5) + d = newp(BIntArray, [10, 20, 30]) + c[1:4] = d + assert list(c) == [0, 10, 20, 30, 0] + # + BShortP = new_pointer_type(new_primitive_type("short")) + BShortArray = new_array_type(BShortP, None) + d = newp(BShortArray, [40, 50]) + c[1:3] = d + assert list(c) == [0, 40, 50, 30, 0] + +def test_cdata_name_module_doc(): + p = new_primitive_type("signed char") + x = cast(p, 17) + assert x.__module__ == '_cffi_backend' + assert x.__name__ == '<cdata>' + assert hasattr(x, '__doc__') + +def test_different_types_of_ptr_equality(): + BVoidP = new_pointer_type(new_void_type()) + BIntP = new_pointer_type(new_primitive_type("int")) + x = cast(BVoidP, 12345) + assert x == cast(BIntP, 12345) + assert x != cast(BIntP, 12344) + assert hash(x) == hash(cast(BIntP, 12345)) + +def test_new_handle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + class mylist(list): + pass + o = mylist([2, 3, 4]) + x = newp_handle(BVoidP, o) + assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>" + assert x + assert from_handle(x) is o + assert from_handle(cast(BCharP, x)) is o + wr = _weakref.ref(o) + del o + import gc; gc.collect() + assert wr() is not None + assert from_handle(x) == list((2, 3, 4)) + assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) + del x + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) + +def test_new_handle_cycle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + class A(object): + pass + o = A() + o.cycle = newp_handle(BVoidP, o) + wr = _weakref.ref(o) + del o + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + +def _test_bitfield_details(flag): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BInt = new_primitive_type("int") + BUInt = new_primitive_type("unsigned int") + BStruct = new_struct_type("struct foo1") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('b1', BInt, 9), + ('b2', BUInt, 7), + ('c', BChar, -1)], -1, -1, -1, flag) + if not (flag & SF_MSVC_BITFIELDS): # gcc, any variant + assert typeoffsetof(BStruct, 'c') == (BChar, 3) + assert sizeof(BStruct) == 4 + else: # msvc + assert typeoffsetof(BStruct, 'c') == (BChar, 8) + assert sizeof(BStruct) == 12 + assert alignof(BStruct) == 4 + # + p = newp(new_pointer_type(BStruct), None) + p.a = b'A' + p.b1 = -201 + p.b2 = 99 + p.c = b'\x9D' + raw = buffer(p)[:] + if sys.byteorder == 'little': + if flag & SF_MSVC_BITFIELDS: + assert raw == b'A\x00\x00\x007\xC7\x00\x00\x9D\x00\x00\x00' + elif flag & SF_GCC_LITTLE_ENDIAN: + assert raw == b'A7\xC7\x9D' + elif flag & SF_GCC_BIG_ENDIAN: + assert raw == b'A\xE3\x9B\x9D' + else: + raise AssertionError("bad flag") + else: + if flag & SF_MSVC_BITFIELDS: + assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00' + elif flag & SF_GCC_LITTLE_ENDIAN: + assert raw == b'A\xC77\x9D' + elif flag & SF_GCC_BIG_ENDIAN: + assert raw == b'A\x9B\xE3\x9D' + else: + raise AssertionError("bad flag") + # + BStruct = new_struct_type("struct foo2") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('', BShort, 9), + ('c', BChar, -1)], -1, -1, -1, flag) + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + if flag & SF_MSVC_BITFIELDS: + assert sizeof(BStruct) == 6 + assert alignof(BStruct) == 2 + elif flag & SF_GCC_X86_BITFIELDS: + assert sizeof(BStruct) == 5 + assert alignof(BStruct) == 1 + elif flag & SF_GCC_ARM_BITFIELDS: + assert sizeof(BStruct) == 6 + assert alignof(BStruct) == 2 + else: + raise AssertionError("bad flag") + # + BStruct = new_struct_type("struct foo2") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('', BInt, 0), + ('', BInt, 0), + ('c', BChar, -1)], -1, -1, -1, flag) + if flag & SF_MSVC_BITFIELDS: + assert typeoffsetof(BStruct, 'c') == (BChar, 1) + assert sizeof(BStruct) == 2 + assert alignof(BStruct) == 1 + elif flag & SF_GCC_X86_BITFIELDS: + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + assert sizeof(BStruct) == 5 + assert alignof(BStruct) == 1 + elif flag & SF_GCC_ARM_BITFIELDS: + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + assert sizeof(BStruct) == 8 + assert alignof(BStruct) == 4 + else: + raise AssertionError("bad flag") + + +SF_MSVC_BITFIELDS = 0x01 +SF_GCC_ARM_BITFIELDS = 0x02 +SF_GCC_X86_BITFIELDS = 0x10 + +SF_GCC_BIG_ENDIAN = 0x04 +SF_GCC_LITTLE_ENDIAN = 0x40 + +SF_PACKED = 0x08 + +def test_bitfield_as_x86_gcc(): + _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_LITTLE_ENDIAN) + +def test_bitfield_as_msvc(): + _test_bitfield_details(flag=SF_MSVC_BITFIELDS|SF_GCC_LITTLE_ENDIAN) + +def test_bitfield_as_arm_gcc(): + _test_bitfield_details(flag=SF_GCC_ARM_BITFIELDS|SF_GCC_LITTLE_ENDIAN) + +def test_bitfield_as_ppc_gcc(): + # PowerPC uses the same format as X86, but is big-endian + _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_BIG_ENDIAN) + + +def test_struct_array_no_length(): + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BArray = new_array_type(BIntP, None) + BStruct = new_struct_type("foo") + py.test.raises(TypeError, complete_struct_or_union, + BStruct, [('x', BArray), + ('y', BInt)]) + # + BStruct = new_struct_type("foo") + complete_struct_or_union(BStruct, [('x', BInt), + ('y', BArray)]) + assert sizeof(BStruct) == size_of_int() + d = BStruct.fields + assert len(d) == 2 + assert d[0][0] == 'x' + assert d[0][1].type is BInt + assert d[0][1].offset == 0 + assert d[0][1].bitshift == -1 + assert d[0][1].bitsize == -1 + assert d[1][0] == 'y' + assert d[1][1].type is BArray + assert d[1][1].offset == size_of_int() + assert d[1][1].bitshift == -2 + assert d[1][1].bitsize == -1 + # + p = newp(new_pointer_type(BStruct)) + p.x = 42 + assert p.x == 42 + assert typeof(p.y) is BArray + assert len(p.y) == 0 + assert p.y == cast(BIntP, p) + 1 + # + p = newp(new_pointer_type(BStruct), [100]) + assert p.x == 100 + assert len(p.y) == 0 + # + # Tests for + # ffi.new("struct_with_var_array *", [field.., [the_array_items..]]) + # ffi.new("struct_with_var_array *", [field.., array_size]) + plist = [] + for i in range(20): + if i % 2 == 0: + p = newp(new_pointer_type(BStruct), [100, [200, i, 400]]) + else: + p = newp(new_pointer_type(BStruct), [100, 3]) + p.y[1] = i + p.y[0] = 200 + assert p.y[2] == 0 + p.y[2] = 400 + assert len(p.y) == 3 + assert len(p[0].y) == 3 + assert len(buffer(p)) == sizeof(BInt) * 4 + assert sizeof(p[0]) == sizeof(BInt) * 4 + plist.append(p) + for i in range(20): + p = plist[i] + assert p.x == 100 + assert p.y[0] == 200 + assert p.y[1] == i + assert p.y[2] == 400 + assert list(p.y) == [200, i, 400] + # + # the following assignment works, as it normally would, for any array field + p.y = [501, 601] + assert list(p.y) == [501, 601, 400] + p[0].y = [500, 600] + assert list(p[0].y) == [500, 600, 400] + assert repr(p) == "<cdata 'foo *' owning %d bytes>" % ( + sizeof(BStruct) + 3 * sizeof(BInt),) + assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % ( + sizeof(BStruct) + 3 * sizeof(BInt),) + assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt) + # + # from a non-owning pointer, we can't get the length + q = cast(new_pointer_type(BStruct), p) + assert q.y[0] == 500 + assert q[0].y[0] == 500 + py.test.raises(TypeError, len, q.y) + py.test.raises(TypeError, len, q[0].y) + assert typeof(q.y) is BIntP + assert typeof(q[0].y) is BIntP + assert sizeof(q[0]) == sizeof(BStruct) + # + # error cases with pytest.raises(IndexError): p.y[4] with pytest.raises(TypeError): @@ -3546,27 +3546,27 @@ def test_struct_array_no_length(): p.y = 15 with pytest.raises(TypeError): p.y = None - # - # accepting this may be specified by the C99 standard, - # or a GCC strangeness... - BStruct2 = new_struct_type("bar") - complete_struct_or_union(BStruct2, [('f', BStruct), - ('n', BInt)]) - p = newp(new_pointer_type(BStruct2), {'n': 42}) - assert p.n == 42 - # - # more error cases - py.test.raises(TypeError, newp, new_pointer_type(BStruct), [100, None]) - BArray4 = new_array_type(BIntP, 4) - BStruct4 = new_struct_type("test4") - complete_struct_or_union(BStruct4, [('a', BArray4)]) # not varsized - py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [None]) - py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [4]) - p = newp(new_pointer_type(BStruct4), [[10, 20, 30]]) - assert p.a[0] == 10 - assert p.a[1] == 20 - assert p.a[2] == 30 - assert p.a[3] == 0 + # + # accepting this may be specified by the C99 standard, + # or a GCC strangeness... + BStruct2 = new_struct_type("bar") + complete_struct_or_union(BStruct2, [('f', BStruct), + ('n', BInt)]) + p = newp(new_pointer_type(BStruct2), {'n': 42}) + assert p.n == 42 + # + # more error cases + py.test.raises(TypeError, newp, new_pointer_type(BStruct), [100, None]) + BArray4 = new_array_type(BIntP, 4) + BStruct4 = new_struct_type("test4") + complete_struct_or_union(BStruct4, [('a', BArray4)]) # not varsized + py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [None]) + py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [4]) + p = newp(new_pointer_type(BStruct4), [[10, 20, 30]]) + assert p.a[0] == 10 + assert p.a[1] == 20 + assert p.a[2] == 30 + assert p.a[3] == 0 # # struct of struct of varsized array BStruct2 = new_struct_type("bar") @@ -3575,86 +3575,86 @@ def test_struct_array_no_length(): for i in range(2): # try to detect heap overwrites p = newp(new_pointer_type(BStruct2), [100, [200, list(range(50))]]) assert p.tail.y[49] == 49 - - -def test_struct_array_no_length_explicit_position(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, None) - BStruct = new_struct_type("foo") - complete_struct_or_union(BStruct, [('x', BArray, -1, 0), # actually 3 items - ('y', BInt, -1, 12)]) - p = newp(new_pointer_type(BStruct), [[10, 20], 30]) - assert p.x[0] == 10 - assert p.x[1] == 20 - assert p.x[2] == 0 - assert p.y == 30 - p = newp(new_pointer_type(BStruct), {'x': [40], 'y': 50}) - assert p.x[0] == 40 - assert p.x[1] == 0 - assert p.x[2] == 0 - assert p.y == 50 - p = newp(new_pointer_type(BStruct), {'y': 60}) - assert p.x[0] == 0 - assert p.x[1] == 0 - assert p.x[2] == 0 - assert p.y == 60 - # - # This "should" work too, allocating a larger structure - # (a bit strange in this case, but useful in general) - plist = [] - for i in range(20): - p = newp(new_pointer_type(BStruct), [[10, 20, 30, 40, 50, 60, 70]]) - plist.append(p) - for i in range(20): - p = plist[i] - assert p.x[0] == 10 - assert p.x[1] == 20 - assert p.x[2] == 30 - assert p.x[3] == 40 == p.y - assert p.x[4] == 50 - assert p.x[5] == 60 - assert p.x[6] == 70 - -def test_struct_array_not_aligned(): - # struct a { int x; char y; char z[]; }; - # ends up of size 8, but 'z' is at offset 5 - BChar = new_primitive_type("char") - BInt = new_primitive_type("int") - BCharP = new_pointer_type(BChar) - BArray = new_array_type(BCharP, None) - BStruct = new_struct_type("foo") - complete_struct_or_union(BStruct, [('x', BInt), - ('y', BChar), - ('z', BArray)]) - assert sizeof(BStruct) == 2 * size_of_int() - def offsetof(BType, fieldname): - return typeoffsetof(BType, fieldname)[1] - base = offsetof(BStruct, 'z') - assert base == size_of_int() + 1 - # - p = newp(new_pointer_type(BStruct), {'z': 3}) - assert sizeof(p[0]) == base + 3 - q = newp(new_pointer_type(BStruct), {'z': size_of_int()}) - assert sizeof(q) == size_of_ptr() - assert sizeof(q[0]) == base + size_of_int() - assert len(p.z) == 3 - assert len(p[0].z) == 3 - assert len(q.z) == size_of_int() - assert len(q[0].z) == size_of_int() - -def test_ass_slice(): - BChar = new_primitive_type("char") - BArray = new_array_type(new_pointer_type(BChar), None) - p = newp(BArray, b"foobar") - p[2:5] = [b"*", b"Z", b"T"] - p[1:3] = b"XY" - assert list(p) == [b"f", b"X", b"Y", b"Z", b"T", b"r", b"\x00"] + + +def test_struct_array_no_length_explicit_position(): + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BArray = new_array_type(BIntP, None) + BStruct = new_struct_type("foo") + complete_struct_or_union(BStruct, [('x', BArray, -1, 0), # actually 3 items + ('y', BInt, -1, 12)]) + p = newp(new_pointer_type(BStruct), [[10, 20], 30]) + assert p.x[0] == 10 + assert p.x[1] == 20 + assert p.x[2] == 0 + assert p.y == 30 + p = newp(new_pointer_type(BStruct), {'x': [40], 'y': 50}) + assert p.x[0] == 40 + assert p.x[1] == 0 + assert p.x[2] == 0 + assert p.y == 50 + p = newp(new_pointer_type(BStruct), {'y': 60}) + assert p.x[0] == 0 + assert p.x[1] == 0 + assert p.x[2] == 0 + assert p.y == 60 + # + # This "should" work too, allocating a larger structure + # (a bit strange in this case, but useful in general) + plist = [] + for i in range(20): + p = newp(new_pointer_type(BStruct), [[10, 20, 30, 40, 50, 60, 70]]) + plist.append(p) + for i in range(20): + p = plist[i] + assert p.x[0] == 10 + assert p.x[1] == 20 + assert p.x[2] == 30 + assert p.x[3] == 40 == p.y + assert p.x[4] == 50 + assert p.x[5] == 60 + assert p.x[6] == 70 + +def test_struct_array_not_aligned(): + # struct a { int x; char y; char z[]; }; + # ends up of size 8, but 'z' is at offset 5 + BChar = new_primitive_type("char") + BInt = new_primitive_type("int") + BCharP = new_pointer_type(BChar) + BArray = new_array_type(BCharP, None) + BStruct = new_struct_type("foo") + complete_struct_or_union(BStruct, [('x', BInt), + ('y', BChar), + ('z', BArray)]) + assert sizeof(BStruct) == 2 * size_of_int() + def offsetof(BType, fieldname): + return typeoffsetof(BType, fieldname)[1] + base = offsetof(BStruct, 'z') + assert base == size_of_int() + 1 + # + p = newp(new_pointer_type(BStruct), {'z': 3}) + assert sizeof(p[0]) == base + 3 + q = newp(new_pointer_type(BStruct), {'z': size_of_int()}) + assert sizeof(q) == size_of_ptr() + assert sizeof(q[0]) == base + size_of_int() + assert len(p.z) == 3 + assert len(p[0].z) == 3 + assert len(q.z) == size_of_int() + assert len(q[0].z) == size_of_int() + +def test_ass_slice(): + BChar = new_primitive_type("char") + BArray = new_array_type(new_pointer_type(BChar), None) + p = newp(BArray, b"foobar") + p[2:5] = [b"*", b"Z", b"T"] + p[1:3] = b"XY" + assert list(p) == [b"f", b"X", b"Y", b"Z", b"T", b"r", b"\x00"] with pytest.raises(TypeError): p[1:5] = u+'XYZT' with pytest.raises(TypeError): p[1:5] = [1, 2, 3, 4] - # + # for typename in ["wchar_t", "char16_t", "char32_t"]: BUniChar = new_primitive_type(typename) BArray = new_array_type(new_pointer_type(BUniChar), None) @@ -3666,16 +3666,16 @@ def test_ass_slice(): p[1:5] = b'XYZT' with pytest.raises(TypeError): p[1:5] = [1, 2, 3, 4] - -def test_void_p_arithmetic(): - BVoid = new_void_type() - BInt = new_primitive_type("intptr_t") - p = cast(new_pointer_type(BVoid), 100000) - assert int(cast(BInt, p)) == 100000 - assert int(cast(BInt, p + 42)) == 100042 - assert int(cast(BInt, p - (-42))) == 100042 - assert (p + 42) - p == 42 - q = cast(new_pointer_type(new_primitive_type("char")), 100000) + +def test_void_p_arithmetic(): + BVoid = new_void_type() + BInt = new_primitive_type("intptr_t") + p = cast(new_pointer_type(BVoid), 100000) + assert int(cast(BInt, p)) == 100000 + assert int(cast(BInt, p + 42)) == 100042 + assert int(cast(BInt, p - (-42))) == 100042 + assert (p + 42) - p == 42 + q = cast(new_pointer_type(new_primitive_type("char")), 100000) with pytest.raises(TypeError): p - q with pytest.raises(TypeError): @@ -3684,17 +3684,17 @@ def test_void_p_arithmetic(): p + cast(new_primitive_type('int'), 42) with pytest.raises(TypeError): p - cast(new_primitive_type('int'), 42) - -def test_sizeof_sliced_array(): - BInt = new_primitive_type("int") - BArray = new_array_type(new_pointer_type(BInt), 10) - p = newp(BArray, None) - assert sizeof(p[2:9]) == 7 * sizeof(BInt) - -def test_packed(): - BLong = new_primitive_type("long") - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") + +def test_sizeof_sliced_array(): + BInt = new_primitive_type("int") + BArray = new_array_type(new_pointer_type(BInt), 10) + p = newp(BArray, None) + assert sizeof(p[2:9]) == 7 * sizeof(BInt) + +def test_packed(): + BLong = new_primitive_type("long") + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") for extra_args in [(SF_PACKED,), (0, 1)]: BStruct = new_struct_type("struct foo") complete_struct_or_union(BStruct, [('a1', BLong, -1), @@ -3729,57 +3729,57 @@ def test_packed(): assert len(d) == 2 assert d[0][0] == 'b1' assert d[0][1].type is BChar - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 + assert d[0][1].offset == 0 + assert d[0][1].bitshift == -1 + assert d[0][1].bitsize == -1 assert d[1][0] == 'b2' assert d[1][1].type is BLong assert d[1][1].offset == 2 - assert d[1][1].bitshift == -1 - assert d[1][1].bitsize == -1 + assert d[1][1].bitshift == -1 + assert d[1][1].bitsize == -1 assert sizeof(BStruct2) == 2 + sizeof(BLong) assert alignof(BStruct2) == 2 - -def test_packed_with_bitfields(): - if sys.platform == "win32": - py.test.skip("testing gcc behavior") - BLong = new_primitive_type("long") - BChar = new_primitive_type("char") - BStruct = new_struct_type("struct foo") - py.test.raises(NotImplementedError, - complete_struct_or_union, - BStruct, [('a1', BLong, 30), - ('a2', BChar, 5)], - None, -1, -1, SF_PACKED) - -def test_from_buffer(): - import array - a = array.array('H', [10000, 20000, 30000]) - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - c = from_buffer(BCharA, a) - assert typeof(c) is BCharA - assert len(c) == 6 - assert repr(c) == "<cdata 'char[]' buffer len 6 from 'array.array' object>" - p = new_pointer_type(new_primitive_type("unsigned short")) - cast(p, c)[1] += 500 - assert list(a) == [10000, 20500, 30000] - -def test_from_buffer_not_str_unicode(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - p1 = from_buffer(BCharA, b"foo") - assert p1 == from_buffer(BCharA, b"foo") - import gc; gc.collect() - assert p1 == from_buffer(BCharA, b"foo") - py.test.raises(TypeError, from_buffer, BCharA, u+"foo") - try: - from __builtin__ import buffer - except ImportError: - pass - else: + +def test_packed_with_bitfields(): + if sys.platform == "win32": + py.test.skip("testing gcc behavior") + BLong = new_primitive_type("long") + BChar = new_primitive_type("char") + BStruct = new_struct_type("struct foo") + py.test.raises(NotImplementedError, + complete_struct_or_union, + BStruct, [('a1', BLong, 30), + ('a2', BChar, 5)], + None, -1, -1, SF_PACKED) + +def test_from_buffer(): + import array + a = array.array('H', [10000, 20000, 30000]) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BCharA = new_array_type(BCharP, None) + c = from_buffer(BCharA, a) + assert typeof(c) is BCharA + assert len(c) == 6 + assert repr(c) == "<cdata 'char[]' buffer len 6 from 'array.array' object>" + p = new_pointer_type(new_primitive_type("unsigned short")) + cast(p, c)[1] += 500 + assert list(a) == [10000, 20500, 30000] + +def test_from_buffer_not_str_unicode(): + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BCharA = new_array_type(BCharP, None) + p1 = from_buffer(BCharA, b"foo") + assert p1 == from_buffer(BCharA, b"foo") + import gc; gc.collect() + assert p1 == from_buffer(BCharA, b"foo") + py.test.raises(TypeError, from_buffer, BCharA, u+"foo") + try: + from __builtin__ import buffer + except ImportError: + pass + else: # Python 2 only contents = from_buffer(BCharA, buffer(b"foo")) assert len(contents) == len(p1) @@ -3790,89 +3790,89 @@ def test_from_buffer_not_str_unicode(): assert len(contents) == len(p4) for i in range(len(contents)): assert contents[i] == p4[i] - try: - from __builtin__ import memoryview - except ImportError: - pass - else: + try: + from __builtin__ import memoryview + except ImportError: + pass + else: contents = from_buffer(BCharA, memoryview(b"foo")) assert len(contents) == len(p1) for i in range(len(contents)): assert contents[i] == p1[i] - - -def test_from_buffer_bytearray(): - a = bytearray(b"xyz") - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - p = from_buffer(BCharA, a) - assert typeof(p) is BCharA - assert len(p) == 3 - assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>" - assert p[2] == b"z" - p[2] = b"." - assert a[2] == ord(".") - a[2] = ord("?") - assert p[2] == b"?" - -def test_from_buffer_more_cases(): - try: - from _cffi_backend import _testbuff - except ImportError: - py.test.skip("not for pypy") - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - # - def check1(bufobj, expected): - c = from_buffer(BCharA, bufobj) - assert typeof(c) is BCharA - if sys.version_info >= (3,): - expected = [bytes(c, "ascii") for c in expected] - assert list(c) == list(expected) - # - def check(methods, expected, expected_for_memoryview=None): - if sys.version_info >= (3,): - if methods <= 7: - return - if expected_for_memoryview is not None: - expected = expected_for_memoryview - class X(object): - pass - _testbuff(X, methods) - bufobj = X() - check1(bufobj, expected) - try: - from __builtin__ import buffer - bufobjb = buffer(bufobj) - except (TypeError, ImportError): - pass - else: - check1(bufobjb, expected) - try: - bufobjm = memoryview(bufobj) - except (TypeError, NameError): - pass - else: - check1(bufobjm, expected_for_memoryview or expected) - # - check(1, "RDB") - check(2, "WRB") - check(4, "CHB") - check(8, "GTB") - check(16, "ROB") - # - check(1 | 2, "RDB") - check(1 | 4, "RDB") - check(2 | 4, "CHB") - check(1 | 8, "RDB", "GTB") - check(1 | 16, "RDB", "ROB") - check(2 | 8, "WRB", "GTB") - check(2 | 16, "WRB", "ROB") - check(4 | 8, "CHB", "GTB") - check(4 | 16, "CHB", "ROB") - + + +def test_from_buffer_bytearray(): + a = bytearray(b"xyz") + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BCharA = new_array_type(BCharP, None) + p = from_buffer(BCharA, a) + assert typeof(p) is BCharA + assert len(p) == 3 + assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>" + assert p[2] == b"z" + p[2] = b"." + assert a[2] == ord(".") + a[2] = ord("?") + assert p[2] == b"?" + +def test_from_buffer_more_cases(): + try: + from _cffi_backend import _testbuff + except ImportError: + py.test.skip("not for pypy") + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BCharA = new_array_type(BCharP, None) + # + def check1(bufobj, expected): + c = from_buffer(BCharA, bufobj) + assert typeof(c) is BCharA + if sys.version_info >= (3,): + expected = [bytes(c, "ascii") for c in expected] + assert list(c) == list(expected) + # + def check(methods, expected, expected_for_memoryview=None): + if sys.version_info >= (3,): + if methods <= 7: + return + if expected_for_memoryview is not None: + expected = expected_for_memoryview + class X(object): + pass + _testbuff(X, methods) + bufobj = X() + check1(bufobj, expected) + try: + from __builtin__ import buffer + bufobjb = buffer(bufobj) + except (TypeError, ImportError): + pass + else: + check1(bufobjb, expected) + try: + bufobjm = memoryview(bufobj) + except (TypeError, NameError): + pass + else: + check1(bufobjm, expected_for_memoryview or expected) + # + check(1, "RDB") + check(2, "WRB") + check(4, "CHB") + check(8, "GTB") + check(16, "ROB") + # + check(1 | 2, "RDB") + check(1 | 4, "RDB") + check(2 | 4, "CHB") + check(1 | 8, "RDB", "GTB") + check(1 | 16, "RDB", "ROB") + check(2 | 8, "WRB", "GTB") + check(2 | 16, "WRB", "ROB") + check(4 | 8, "CHB", "GTB") + check(4 | 16, "CHB", "ROB") + def test_from_buffer_require_writable(): BChar = new_primitive_type("char") BCharP = new_pointer_type(BChar) @@ -4030,82 +4030,82 @@ def test_issue483(): assert sizeof(p2) == size_of_ptr() assert len(buffer(p2)) == size_of_int() # first element only, by default -def test_memmove(): - Short = new_primitive_type("short") - ShortA = new_array_type(new_pointer_type(Short), None) - Char = new_primitive_type("char") - CharA = new_array_type(new_pointer_type(Char), None) - p = newp(ShortA, [-1234, -2345, -3456, -4567, -5678]) - memmove(p, p + 1, 4) - assert list(p) == [-2345, -3456, -3456, -4567, -5678] - p[2] = 999 - memmove(p + 2, p, 6) - assert list(p) == [-2345, -3456, -2345, -3456, 999] - memmove(p + 4, newp(CharA, b"\x71\x72"), 2) - if sys.byteorder == 'little': - assert list(p) == [-2345, -3456, -2345, -3456, 0x7271] - else: - assert list(p) == [-2345, -3456, -2345, -3456, 0x7172] - -def test_memmove_buffer(): - import array - Short = new_primitive_type("short") - ShortA = new_array_type(new_pointer_type(Short), None) - a = array.array('H', [10000, 20000, 30000]) - p = newp(ShortA, 5) - memmove(p, a, 6) - assert list(p) == [10000, 20000, 30000, 0, 0] - memmove(p + 1, a, 6) - assert list(p) == [10000, 10000, 20000, 30000, 0] - b = array.array('h', [-1000, -2000, -3000]) - memmove(b, a, 4) - assert b.tolist() == [10000, 20000, -3000] - assert a.tolist() == [10000, 20000, 30000] - p[0] = 999 - p[1] = 998 - p[2] = 997 - p[3] = 996 - p[4] = 995 - memmove(b, p, 2) - assert b.tolist() == [999, 20000, -3000] - memmove(b, p + 2, 4) - assert b.tolist() == [997, 996, -3000] - p[2] = -p[2] - p[3] = -p[3] - memmove(b, p + 2, 6) - assert b.tolist() == [-997, -996, 995] - -def test_memmove_readonly_readwrite(): - SignedChar = new_primitive_type("signed char") - SignedCharA = new_array_type(new_pointer_type(SignedChar), None) - p = newp(SignedCharA, 5) - memmove(p, b"abcde", 3) - assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0] - memmove(p, bytearray(b"ABCDE"), 2) - assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0] - py.test.raises((TypeError, BufferError), memmove, b"abcde", p, 3) - ba = bytearray(b"xxxxx") - memmove(dest=ba, src=p, n=3) - assert ba == bytearray(b"ABcxx") - memmove(ba, b"EFGH", 4) - assert ba == bytearray(b"EFGHx") - -def test_memmove_sign_check(): - SignedChar = new_primitive_type("signed char") - SignedCharA = new_array_type(new_pointer_type(SignedChar), None) - p = newp(SignedCharA, 5) - py.test.raises(ValueError, memmove, p, p + 1, -1) # not segfault - -def test_memmove_bad_cdata(): - BInt = new_primitive_type("int") - p = cast(BInt, 42) - py.test.raises(TypeError, memmove, p, bytearray(b'a'), 1) - py.test.raises(TypeError, memmove, bytearray(b'a'), p, 1) - -def test_dereference_null_ptr(): - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - p = cast(BIntPtr, 0) +def test_memmove(): + Short = new_primitive_type("short") + ShortA = new_array_type(new_pointer_type(Short), None) + Char = new_primitive_type("char") + CharA = new_array_type(new_pointer_type(Char), None) + p = newp(ShortA, [-1234, -2345, -3456, -4567, -5678]) + memmove(p, p + 1, 4) + assert list(p) == [-2345, -3456, -3456, -4567, -5678] + p[2] = 999 + memmove(p + 2, p, 6) + assert list(p) == [-2345, -3456, -2345, -3456, 999] + memmove(p + 4, newp(CharA, b"\x71\x72"), 2) + if sys.byteorder == 'little': + assert list(p) == [-2345, -3456, -2345, -3456, 0x7271] + else: + assert list(p) == [-2345, -3456, -2345, -3456, 0x7172] + +def test_memmove_buffer(): + import array + Short = new_primitive_type("short") + ShortA = new_array_type(new_pointer_type(Short), None) + a = array.array('H', [10000, 20000, 30000]) + p = newp(ShortA, 5) + memmove(p, a, 6) + assert list(p) == [10000, 20000, 30000, 0, 0] + memmove(p + 1, a, 6) + assert list(p) == [10000, 10000, 20000, 30000, 0] + b = array.array('h', [-1000, -2000, -3000]) + memmove(b, a, 4) + assert b.tolist() == [10000, 20000, -3000] + assert a.tolist() == [10000, 20000, 30000] + p[0] = 999 + p[1] = 998 + p[2] = 997 + p[3] = 996 + p[4] = 995 + memmove(b, p, 2) + assert b.tolist() == [999, 20000, -3000] + memmove(b, p + 2, 4) + assert b.tolist() == [997, 996, -3000] + p[2] = -p[2] + p[3] = -p[3] + memmove(b, p + 2, 6) + assert b.tolist() == [-997, -996, 995] + +def test_memmove_readonly_readwrite(): + SignedChar = new_primitive_type("signed char") + SignedCharA = new_array_type(new_pointer_type(SignedChar), None) + p = newp(SignedCharA, 5) + memmove(p, b"abcde", 3) + assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0] + memmove(p, bytearray(b"ABCDE"), 2) + assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0] + py.test.raises((TypeError, BufferError), memmove, b"abcde", p, 3) + ba = bytearray(b"xxxxx") + memmove(dest=ba, src=p, n=3) + assert ba == bytearray(b"ABcxx") + memmove(ba, b"EFGH", 4) + assert ba == bytearray(b"EFGHx") + +def test_memmove_sign_check(): + SignedChar = new_primitive_type("signed char") + SignedCharA = new_array_type(new_pointer_type(SignedChar), None) + p = newp(SignedCharA, 5) + py.test.raises(ValueError, memmove, p, p + 1, -1) # not segfault + +def test_memmove_bad_cdata(): + BInt = new_primitive_type("int") + p = cast(BInt, 42) + py.test.raises(TypeError, memmove, p, bytearray(b'a'), 1) + py.test.raises(TypeError, memmove, bytearray(b'a'), p, 1) + +def test_dereference_null_ptr(): + BInt = new_primitive_type("int") + BIntPtr = new_pointer_type(BInt) + p = cast(BIntPtr, 0) with pytest.raises(RuntimeError): p[0] with pytest.raises(RuntimeError): @@ -4114,176 +4114,176 @@ def test_dereference_null_ptr(): p[42] with pytest.raises(RuntimeError): p[42] = -1 - -def test_mixup(): - BStruct1 = new_struct_type("foo") - BStruct2 = new_struct_type("foo") # <= same name as BStruct1 - BStruct3 = new_struct_type("bar") - BStruct1Ptr = new_pointer_type(BStruct1) - BStruct2Ptr = new_pointer_type(BStruct2) - BStruct3Ptr = new_pointer_type(BStruct3) - BStruct1PtrPtr = new_pointer_type(BStruct1Ptr) - BStruct2PtrPtr = new_pointer_type(BStruct2Ptr) - BStruct3PtrPtr = new_pointer_type(BStruct3Ptr) - pp1 = newp(BStruct1PtrPtr) - pp2 = newp(BStruct2PtrPtr) - pp3 = newp(BStruct3PtrPtr) - pp1[0] = pp1[0] + +def test_mixup(): + BStruct1 = new_struct_type("foo") + BStruct2 = new_struct_type("foo") # <= same name as BStruct1 + BStruct3 = new_struct_type("bar") + BStruct1Ptr = new_pointer_type(BStruct1) + BStruct2Ptr = new_pointer_type(BStruct2) + BStruct3Ptr = new_pointer_type(BStruct3) + BStruct1PtrPtr = new_pointer_type(BStruct1Ptr) + BStruct2PtrPtr = new_pointer_type(BStruct2Ptr) + BStruct3PtrPtr = new_pointer_type(BStruct3Ptr) + pp1 = newp(BStruct1PtrPtr) + pp2 = newp(BStruct2PtrPtr) + pp3 = newp(BStruct3PtrPtr) + pp1[0] = pp1[0] with pytest.raises(TypeError) as e: pp3[0] = pp1[0] - assert str(e.value).startswith("initializer for ctype 'bar *' must be a ") - assert str(e.value).endswith(", not cdata 'foo *'") + assert str(e.value).startswith("initializer for ctype 'bar *' must be a ") + assert str(e.value).endswith(", not cdata 'foo *'") with pytest.raises(TypeError) as e: pp2[0] = pp1[0] - assert str(e.value) == ("initializer for ctype 'foo *' appears indeed to " - "be 'foo *', but the types are different (check " - "that you are not e.g. mixing up different ffi " - "instances)") - -def test_stdcall_function_type(): - assert FFI_CDECL == FFI_DEFAULT_ABI - try: - stdcall = FFI_STDCALL - except NameError: - stdcall = FFI_DEFAULT_ABI - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt, BInt), BInt, False, stdcall) - if stdcall != FFI_DEFAULT_ABI: - assert repr(BFunc) == "<ctype 'int(__stdcall *)(int, int)'>" - else: - assert repr(BFunc) == "<ctype 'int(*)(int, int)'>" - -def test_get_common_types(): - d = {} - _get_common_types(d) - assert d['bool'] == '_Bool' - -def test_unpack(): - BChar = new_primitive_type("char") - BArray = new_array_type(new_pointer_type(BChar), 10) # char[10] - p = newp(BArray, b"abc\x00def") - p0 = p - assert unpack(p, 10) == b"abc\x00def\x00\x00\x00" - assert unpack(p+1, 5) == b"bc\x00de" - + assert str(e.value) == ("initializer for ctype 'foo *' appears indeed to " + "be 'foo *', but the types are different (check " + "that you are not e.g. mixing up different ffi " + "instances)") + +def test_stdcall_function_type(): + assert FFI_CDECL == FFI_DEFAULT_ABI + try: + stdcall = FFI_STDCALL + except NameError: + stdcall = FFI_DEFAULT_ABI + BInt = new_primitive_type("int") + BFunc = new_function_type((BInt, BInt), BInt, False, stdcall) + if stdcall != FFI_DEFAULT_ABI: + assert repr(BFunc) == "<ctype 'int(__stdcall *)(int, int)'>" + else: + assert repr(BFunc) == "<ctype 'int(*)(int, int)'>" + +def test_get_common_types(): + d = {} + _get_common_types(d) + assert d['bool'] == '_Bool' + +def test_unpack(): + BChar = new_primitive_type("char") + BArray = new_array_type(new_pointer_type(BChar), 10) # char[10] + p = newp(BArray, b"abc\x00def") + p0 = p + assert unpack(p, 10) == b"abc\x00def\x00\x00\x00" + assert unpack(p+1, 5) == b"bc\x00de" + for typename in ["wchar_t", "char16_t", "char32_t"]: BWChar = new_primitive_type(typename) BArray = new_array_type(new_pointer_type(BWChar), 10) # wchar_t[10] p = newp(BArray, u"abc\x00def") assert unpack(p, 10) == u"abc\x00def\x00\x00\x00" - for typename, samples in [ - ("uint8_t", [0, 2**8-1]), - ("uint16_t", [0, 2**16-1]), - ("uint32_t", [0, 2**32-1]), - ("uint64_t", [0, 2**64-1]), - ("int8_t", [-2**7, 2**7-1]), - ("int16_t", [-2**15, 2**15-1]), - ("int32_t", [-2**31, 2**31-1]), - ("int64_t", [-2**63, 2**63-1]), + for typename, samples in [ + ("uint8_t", [0, 2**8-1]), + ("uint16_t", [0, 2**16-1]), + ("uint32_t", [0, 2**32-1]), + ("uint64_t", [0, 2**64-1]), + ("int8_t", [-2**7, 2**7-1]), + ("int16_t", [-2**15, 2**15-1]), + ("int32_t", [-2**31, 2**31-1]), + ("int64_t", [-2**63, 2**63-1]), ("_Bool", [False, True]), - ("float", [0.0, 10.5]), - ("double", [12.34, 56.78]), - ]: - BItem = new_primitive_type(typename) - BArray = new_array_type(new_pointer_type(BItem), 10) - p = newp(BArray, samples) - result = unpack(p, len(samples)) - assert result == samples - for i in range(len(samples)): - assert result[i] == p[i] and type(result[i]) is type(p[i]) + ("float", [0.0, 10.5]), + ("double", [12.34, 56.78]), + ]: + BItem = new_primitive_type(typename) + BArray = new_array_type(new_pointer_type(BItem), 10) + p = newp(BArray, samples) + result = unpack(p, len(samples)) + assert result == samples + for i in range(len(samples)): + assert result[i] == p[i] and type(result[i]) is type(p[i]) assert (type(result[i]) is bool) == (type(samples[i]) is bool) - # - BInt = new_primitive_type("int") - py.test.raises(TypeError, unpack, p) - py.test.raises(TypeError, unpack, b"foobar", 6) - py.test.raises(TypeError, unpack, cast(BInt, 42), 1) - # - BPtr = new_pointer_type(BInt) - random_ptr = cast(BPtr, -424344) - other_ptr = cast(BPtr, 54321) - BArray = new_array_type(new_pointer_type(BPtr), None) - lst = unpack(newp(BArray, [random_ptr, other_ptr]), 2) - assert lst == [random_ptr, other_ptr] - # - BFunc = new_function_type((BInt, BInt), BInt, False) - BFuncPtr = new_pointer_type(BFunc) - lst = unpack(newp(new_array_type(BFuncPtr, None), 2), 2) - assert len(lst) == 2 - assert not lst[0] and not lst[1] - assert typeof(lst[0]) is BFunc - # - BStruct = new_struct_type("foo") - BStructPtr = new_pointer_type(BStruct) - e = py.test.raises(ValueError, unpack, cast(BStructPtr, 42), 5) - assert str(e.value) == "'foo *' points to items of unknown size" - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1)]) - array_of_structs = newp(new_array_type(BStructPtr, None), [[4,5], [6,7]]) - lst = unpack(array_of_structs, 2) - assert typeof(lst[0]) is BStruct - assert lst[0].a1 == 4 and lst[1].a2 == 7 - # - py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 0) - py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 10) - # - py.test.raises(ValueError, unpack, p0, -1) - py.test.raises(ValueError, unpack, p, -1) - -def test_cdata_dir(): - BInt = new_primitive_type("int") - p = cast(BInt, 42) - check_dir(p, []) - p = newp(new_array_type(new_pointer_type(BInt), None), 5) - check_dir(p, []) - BStruct = new_struct_type("foo") - p = cast(new_pointer_type(BStruct), 0) - check_dir(p, []) # opaque - complete_struct_or_union(BStruct, [('a2', BInt, -1), - ('a1', BInt, -1)]) - check_dir(p, ['a1', 'a2']) # always sorted - p = newp(new_pointer_type(BStruct), None) - check_dir(p, ['a1', 'a2']) - check_dir(p[0], ['a1', 'a2']) - pp = newp(new_pointer_type(new_pointer_type(BStruct)), p) - check_dir(pp, []) - check_dir(pp[0], ['a1', 'a2']) - check_dir(pp[0][0], ['a1', 'a2']) - -def test_char_pointer_conversion(): - import warnings + # + BInt = new_primitive_type("int") + py.test.raises(TypeError, unpack, p) + py.test.raises(TypeError, unpack, b"foobar", 6) + py.test.raises(TypeError, unpack, cast(BInt, 42), 1) + # + BPtr = new_pointer_type(BInt) + random_ptr = cast(BPtr, -424344) + other_ptr = cast(BPtr, 54321) + BArray = new_array_type(new_pointer_type(BPtr), None) + lst = unpack(newp(BArray, [random_ptr, other_ptr]), 2) + assert lst == [random_ptr, other_ptr] + # + BFunc = new_function_type((BInt, BInt), BInt, False) + BFuncPtr = new_pointer_type(BFunc) + lst = unpack(newp(new_array_type(BFuncPtr, None), 2), 2) + assert len(lst) == 2 + assert not lst[0] and not lst[1] + assert typeof(lst[0]) is BFunc + # + BStruct = new_struct_type("foo") + BStructPtr = new_pointer_type(BStruct) + e = py.test.raises(ValueError, unpack, cast(BStructPtr, 42), 5) + assert str(e.value) == "'foo *' points to items of unknown size" + complete_struct_or_union(BStruct, [('a1', BInt, -1), + ('a2', BInt, -1)]) + array_of_structs = newp(new_array_type(BStructPtr, None), [[4,5], [6,7]]) + lst = unpack(array_of_structs, 2) + assert typeof(lst[0]) is BStruct + assert lst[0].a1 == 4 and lst[1].a2 == 7 + # + py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 0) + py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 10) + # + py.test.raises(ValueError, unpack, p0, -1) + py.test.raises(ValueError, unpack, p, -1) + +def test_cdata_dir(): + BInt = new_primitive_type("int") + p = cast(BInt, 42) + check_dir(p, []) + p = newp(new_array_type(new_pointer_type(BInt), None), 5) + check_dir(p, []) + BStruct = new_struct_type("foo") + p = cast(new_pointer_type(BStruct), 0) + check_dir(p, []) # opaque + complete_struct_or_union(BStruct, [('a2', BInt, -1), + ('a1', BInt, -1)]) + check_dir(p, ['a1', 'a2']) # always sorted + p = newp(new_pointer_type(BStruct), None) + check_dir(p, ['a1', 'a2']) + check_dir(p[0], ['a1', 'a2']) + pp = newp(new_pointer_type(new_pointer_type(BStruct)), p) + check_dir(pp, []) + check_dir(pp[0], ['a1', 'a2']) + check_dir(pp[0][0], ['a1', 'a2']) + +def test_char_pointer_conversion(): + import warnings assert __version__.startswith("1."), ( "the warning will be an error if we ever release cffi 2.x") - BCharP = new_pointer_type(new_primitive_type("char")) - BIntP = new_pointer_type(new_primitive_type("int")) - BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + BIntP = new_pointer_type(new_primitive_type("int")) + BVoidP = new_pointer_type(new_void_type()) BUCharP = new_pointer_type(new_primitive_type("unsigned char")) - z1 = cast(BCharP, 0) - z2 = cast(BIntP, 0) - z3 = cast(BVoidP, 0) + z1 = cast(BCharP, 0) + z2 = cast(BIntP, 0) + z3 = cast(BVoidP, 0) z4 = cast(BUCharP, 0) - with warnings.catch_warnings(record=True) as w: + with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") - newp(new_pointer_type(BIntP), z1) # warn - assert len(w) == 1 - newp(new_pointer_type(BVoidP), z1) # fine - assert len(w) == 1 - newp(new_pointer_type(BCharP), z2) # warn - assert len(w) == 2 - newp(new_pointer_type(BVoidP), z2) # fine - assert len(w) == 2 - newp(new_pointer_type(BCharP), z3) # fine - assert len(w) == 2 - newp(new_pointer_type(BIntP), z3) # fine - assert len(w) == 2 + newp(new_pointer_type(BIntP), z1) # warn + assert len(w) == 1 + newp(new_pointer_type(BVoidP), z1) # fine + assert len(w) == 1 + newp(new_pointer_type(BCharP), z2) # warn + assert len(w) == 2 + newp(new_pointer_type(BVoidP), z2) # fine + assert len(w) == 2 + newp(new_pointer_type(BCharP), z3) # fine + assert len(w) == 2 + newp(new_pointer_type(BIntP), z3) # fine + assert len(w) == 2 newp(new_pointer_type(BCharP), z4) # fine (ignore signedness here) assert len(w) == 2 newp(new_pointer_type(BUCharP), z1) # fine (ignore signedness here) assert len(w) == 2 newp(new_pointer_type(BUCharP), z3) # fine assert len(w) == 2 - # check that the warnings are associated with lines in this file - assert w[1].lineno == w[0].lineno + 4 + # check that the warnings are associated with lines in this file + assert w[1].lineno == w[0].lineno + 4 def test_primitive_comparison(): def assert_eq(a, b): diff --git a/contrib/python/cffi/c/wchar_helper.h b/contrib/python/cffi/c/wchar_helper.h index 399b55130b..e41e913c16 100644 --- a/contrib/python/cffi/c/wchar_helper.h +++ b/contrib/python/cffi/c/wchar_helper.h @@ -1,75 +1,75 @@ -/* - * wchar_t helpers - */ - +/* + * wchar_t helpers + */ + typedef uint16_t cffi_char16_t; typedef uint32_t cffi_char32_t; - - + + #if Py_UNICODE_SIZE == 2 - -/* Before Python 2.7, PyUnicode_FromWideChar is not able to convert - wchar_t values greater than 65535 into two-unicode-characters surrogates. - But even the Python 2.7 version doesn't detect wchar_t values that are - out of range(1114112), and just returns nonsense. + +/* Before Python 2.7, PyUnicode_FromWideChar is not able to convert + wchar_t values greater than 65535 into two-unicode-characters surrogates. + But even the Python 2.7 version doesn't detect wchar_t values that are + out of range(1114112), and just returns nonsense. From cffi 1.11 we can't use it anyway, because we need a version with char32_t input types. -*/ -static PyObject * +*/ +static PyObject * _my_PyUnicode_FromChar32(const cffi_char32_t *w, Py_ssize_t size) -{ - PyObject *unicode; +{ + PyObject *unicode; Py_ssize_t i; - Py_ssize_t alloc; + Py_ssize_t alloc; const cffi_char32_t *orig_w; - - alloc = size; - orig_w = w; - for (i = size; i > 0; i--) { - if (*w > 0xFFFF) - alloc++; - w++; - } - w = orig_w; - unicode = PyUnicode_FromUnicode(NULL, alloc); - if (!unicode) - return NULL; - - /* Copy the wchar_t data into the new object */ - { + + alloc = size; + orig_w = w; + for (i = size; i > 0; i--) { + if (*w > 0xFFFF) + alloc++; + w++; + } + w = orig_w; + unicode = PyUnicode_FromUnicode(NULL, alloc); + if (!unicode) + return NULL; + + /* Copy the wchar_t data into the new object */ + { Py_UNICODE *u; - u = PyUnicode_AS_UNICODE(unicode); - for (i = size; i > 0; i--) { + u = PyUnicode_AS_UNICODE(unicode); + for (i = size; i > 0; i--) { if (*w > 0xFFFF) { cffi_char32_t ordinal; if (*w > 0x10FFFF) { - PyErr_Format(PyExc_ValueError, + PyErr_Format(PyExc_ValueError, "char32_t out of range for " - "conversion to unicode: 0x%x", (int)*w); - Py_DECREF(unicode); - return NULL; - } - ordinal = *w++; - ordinal -= 0x10000; - *u++ = 0xD800 | (ordinal >> 10); - *u++ = 0xDC00 | (ordinal & 0x3FF); - } - else - *u++ = *w++; - } - } - return unicode; -} - + "conversion to unicode: 0x%x", (int)*w); + Py_DECREF(unicode); + return NULL; + } + ordinal = *w++; + ordinal -= 0x10000; + *u++ = 0xD800 | (ordinal >> 10); + *u++ = 0xDC00 | (ordinal & 0x3FF); + } + else + *u++ = *w++; + } + } + return unicode; +} + static PyObject * _my_PyUnicode_FromChar16(const cffi_char16_t *w, Py_ssize_t size) { return PyUnicode_FromUnicode((const Py_UNICODE *)w, size); } - + #else /* Py_UNICODE_SIZE == 4 */ - + static PyObject * _my_PyUnicode_FromChar32(const cffi_char32_t *w, Py_ssize_t size) { @@ -112,19 +112,19 @@ _my_PyUnicode_FromChar16(const cffi_char16_t *w, Py_ssize_t size) return result; } -#endif - - -#define IS_SURROGATE(u) (0xD800 <= (u)[0] && (u)[0] <= 0xDBFF && \ - 0xDC00 <= (u)[1] && (u)[1] <= 0xDFFF) -#define AS_SURROGATE(u) (0x10000 + (((u)[0] - 0xD800) << 10) + \ - ((u)[1] - 0xDC00)) - +#endif + + +#define IS_SURROGATE(u) (0xD800 <= (u)[0] && (u)[0] <= 0xDBFF && \ + 0xDC00 <= (u)[1] && (u)[1] <= 0xDFFF) +#define AS_SURROGATE(u) (0x10000 + (((u)[0] - 0xD800) << 10) + \ + ((u)[1] - 0xDC00)) + static int _my_PyUnicode_AsSingleChar16(PyObject *unicode, cffi_char16_t *result, char *err_got) -{ - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); +{ + Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); if (PyUnicode_GET_SIZE(unicode) != 1) { sprintf(err_got, "unicode string of length %zd", PyUnicode_GET_SIZE(unicode)); @@ -146,30 +146,30 @@ _my_PyUnicode_AsSingleChar32(PyObject *unicode, cffi_char32_t *result, char *err_got) { Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - if (PyUnicode_GET_SIZE(unicode) == 1) { + if (PyUnicode_GET_SIZE(unicode) == 1) { *result = (cffi_char32_t)u[0]; - return 0; - } + return 0; + } #if Py_UNICODE_SIZE == 2 - if (PyUnicode_GET_SIZE(unicode) == 2 && IS_SURROGATE(u)) { - *result = AS_SURROGATE(u); - return 0; - } -#endif + if (PyUnicode_GET_SIZE(unicode) == 2 && IS_SURROGATE(u)) { + *result = AS_SURROGATE(u); + return 0; + } +#endif sprintf(err_got, "unicode string of length %zd", PyUnicode_GET_SIZE(unicode)); - return -1; -} - + return -1; +} + static Py_ssize_t _my_PyUnicode_SizeAsChar16(PyObject *unicode) -{ - Py_ssize_t length = PyUnicode_GET_SIZE(unicode); - Py_ssize_t result = length; - +{ + Py_ssize_t length = PyUnicode_GET_SIZE(unicode); + Py_ssize_t result = length; + #if Py_UNICODE_SIZE == 4 - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - Py_ssize_t i; - + Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); + Py_ssize_t i; + for (i=0; i<length; i++) { if (u[i] > 0xFFFF) result++; @@ -187,21 +187,21 @@ static Py_ssize_t _my_PyUnicode_SizeAsChar32(PyObject *unicode) Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); Py_ssize_t i; - for (i=0; i<length-1; i++) { - if (IS_SURROGATE(u+i)) - result--; - } -#endif - return result; -} - + for (i=0; i<length-1; i++) { + if (IS_SURROGATE(u+i)) + result--; + } +#endif + return result; +} + static int _my_PyUnicode_AsChar16(PyObject *unicode, cffi_char16_t *result, Py_ssize_t resultlen) -{ +{ Py_ssize_t len = PyUnicode_GET_SIZE(unicode); - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - Py_ssize_t i; + Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); + Py_ssize_t i; for (i=0; i<len; i++) { #if Py_UNICODE_SIZE == 2 cffi_char16_t ordinal = u[i]; @@ -231,16 +231,16 @@ static int _my_PyUnicode_AsChar32(PyObject *unicode, { Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); Py_ssize_t i; - for (i=0; i<resultlen; i++) { + for (i=0; i<resultlen; i++) { cffi_char32_t ordinal = *u; #if Py_UNICODE_SIZE == 2 - if (IS_SURROGATE(u)) { - ordinal = AS_SURROGATE(u); - u++; - } -#endif - result[i] = ordinal; - u++; - } + if (IS_SURROGATE(u)) { + ordinal = AS_SURROGATE(u); + u++; + } +#endif + result[i] = ordinal; + u++; + } return 0; -} +} |