Hello community, here is the log from the commit of package python3-cffi for openSUSE:Factory checked in at 2015-11-23 07:30:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python3-cffi (Old) and /work/SRC/openSUSE:Factory/.python3-cffi.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python3-cffi" Changes: -------- --- /work/SRC/openSUSE:Factory/python3-cffi/python3-cffi.changes 2015-11-02 12:55:50.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python3-cffi.new/python3-cffi.changes 2015-11-23 07:30:21.000000000 +0100 @@ -1,0 +2,15 @@ +Sun Nov 22 00:47:16 UTC 2015 - [email protected] + +- update to version 1.3.1: + * The optional typedefs (bool, FILE and all Windows types) were not + always available from out-of-line FFI objects. + * Opaque enums are phased out from the cdefs: they now give a + warning, instead of (possibly wrongly) being assumed equal to + unsigned int. Please report if you get a reasonable use case for + them. + * Some parsing details, notably volatile is passed along like const + and restrict. Also, older versions of pycparser mis-parse some + pointer-to-pointer types like char * const *: the “const” ends up + at the wrong place. Added a workaround. + +------------------------------------------------------------------- Old: ---- cffi-1.3.0.tar.gz New: ---- cffi-1.3.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python3-cffi.spec ++++++ --- /var/tmp/diff_new_pack.EwDMl6/_old 2015-11-23 07:30:22.000000000 +0100 +++ /var/tmp/diff_new_pack.EwDMl6/_new 2015-11-23 07:30:22.000000000 +0100 @@ -17,7 +17,7 @@ Name: python3-cffi -Version: 1.3.0 +Version: 1.3.1 Release: 0 Summary: Foreign Function Interface for Python calling C code License: MIT ++++++ cffi-1.3.0.tar.gz -> cffi-1.3.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/PKG-INFO new/cffi-1.3.1/PKG-INFO --- old/cffi-1.3.0/PKG-INFO 2015-10-21 12:53:31.000000000 +0200 +++ new/cffi-1.3.1/PKG-INFO 2015-11-18 16:54:20.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.3.0 +Version: 1.3.1 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/c/_cffi_backend.c new/cffi-1.3.1/c/_cffi_backend.c --- old/cffi-1.3.0/c/_cffi_backend.c 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/c/_cffi_backend.c 2015-11-18 15:47:13.000000000 +0100 @@ -5861,6 +5861,9 @@ (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; @@ -6187,6 +6190,7 @@ {"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}, @@ -6447,7 +6451,7 @@ if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) INITERROR; - v = PyText_FromString("1.3.0"); + v = PyText_FromString("1.3.1"); if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0) INITERROR; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/c/cffi1_module.c new/cffi-1.3.1/c/cffi1_module.c --- old/cffi-1.3.0/c/cffi1_module.c 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/c/cffi1_module.c 2015-11-18 15:47:13.000000000 +0100 @@ -15,6 +15,7 @@ #include "cglob.c" #include "lib_obj.c" #include "cdlopen.c" +#include "commontypes.c" static int init_ffi_lib(PyObject *m) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/c/commontypes.c new/cffi-1.3.1/c/commontypes.c --- old/cffi-1.3.0/c/commontypes.c 1970-01-01 01:00:00.000000000 +0100 +++ new/cffi-1.3.1/c/commontypes.c 2015-11-18 15:47:13.000000000 +0100 @@ -0,0 +1,215 @@ +/* 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 i, err; + 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/c/ffi_obj.c new/cffi-1.3.1/c/ffi_obj.c --- old/cffi-1.3.0/c/ffi_obj.c 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/c/ffi_obj.c 2015-11-18 15:47:13.000000000 +0100 @@ -361,7 +361,19 @@ &PyTuple_GET_ITEM(allocator, 1)); } -PyDoc_STRVAR(ffi_new_allocator_doc, "XXX"); +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) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/c/parse_c_type.c new/cffi-1.3.1/c/parse_c_type.c --- old/cffi-1.3.0/c/parse_c_type.c 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/c/parse_c_type.c 2015-11-18 15:47:13.000000000 +0100 @@ -220,6 +220,8 @@ #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) { @@ -442,26 +444,34 @@ 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) \ - { \ - int left = 0, right = ctx->num_##FIELD; \ - \ - while (left < right) { \ - int middle = (left + right) / 2; \ - const char *src = ctx->FIELD[middle].name; \ - 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) @@ -715,6 +725,7 @@ 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); @@ -725,6 +736,14 @@ 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: @@ -736,10 +755,15 @@ return parse_error(tok, "struct or union name expected"); n = search_in_struct_unions(tok->info->ctx, tok->p, tok->size); - if (n < 0) - return parse_error(tok, "undefined struct/union name"); - if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION) != 0) - ^ (kind == TOK_UNION)) + 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); @@ -770,7 +794,8 @@ static -int parse_c_type(struct _cffi_parse_info_s *info, const char *input) +int parse_c_type_from(struct _cffi_parse_info_s *info, size_t *output_index, + const char *input) { int result; token_t token; @@ -781,12 +806,26 @@ token.p = input; token.size = 0; token.output = info->output; - token.output_index = 0; + 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/c/realize_c_type.c new/cffi-1.3.1/c/realize_c_type.c --- old/cffi-1.3.0/c/realize_c_type.c 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/c/realize_c_type.c 2015-11-18 15:47:13.000000000 +0100 @@ -314,6 +314,16 @@ _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) { @@ -330,9 +340,9 @@ (s->flags & _CFFI_F_UNION) ? "union " : "struct ", s->name); if (strcmp(name, "struct _IO_FILE") == 0) - flags |= CT_IS_FILE; - - x = new_struct_or_union_type(name, flags); + 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; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/c/test_c.py new/cffi-1.3.1/c/test_c.py --- old/cffi-1.3.0/c/test_c.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/c/test_c.py 2015-11-18 15:47:13.000000000 +0100 @@ -7,12 +7,12 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) _setup_path() from _cffi_backend import * -from _cffi_backend import _testfunc, _get_types, __version__ +from _cffi_backend import _testfunc, _get_types, _get_common_types, __version__ # ____________________________________________________________ import sys -assert __version__ == "1.3.0", ("This test_c.py file is for testing a version" +assert __version__ == "1.3.1", ("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,): @@ -3520,3 +3520,8 @@ 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' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/cffi/__init__.py new/cffi-1.3.1/cffi/__init__.py --- old/cffi-1.3.0/cffi/__init__.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/cffi/__init__.py 2015-11-18 15:47:13.000000000 +0100 @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.3.0" -__version_info__ = (1, 3, 0) +__version__ = "1.3.1" +__version_info__ = (1, 3, 1) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/cffi/cffi_opcode.py new/cffi-1.3.1/cffi/cffi_opcode.py --- old/cffi-1.3.0/cffi/cffi_opcode.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/cffi/cffi_opcode.py 2015-11-18 15:47:13.000000000 +0100 @@ -110,6 +110,8 @@ _UNKNOWN_FLOAT_PRIM = -2 _UNKNOWN_LONG_DOUBLE = -3 +_IO_FILE_STRUCT = -1 + PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, 'short': PRIM_SHORT, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/cffi/commontypes.py new/cffi-1.3.1/cffi/commontypes.py --- old/cffi-1.3.0/cffi/commontypes.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/cffi/commontypes.py 2015-11-18 15:47:13.000000000 +0100 @@ -2,10 +2,17 @@ from . import api, model -COMMON_TYPES = { - 'FILE': model.unknown_type('FILE', '_IO_FILE'), - 'bool': '_Bool', - } +COMMON_TYPES = {} + +try: + # fetch "bool" and all simple Windows types + from _cffi_backend import _get_common_types + _get_common_types(COMMON_TYPES) +except ImportError: + pass + +COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE') +COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES: if _type.endswith('_t'): @@ -14,212 +21,35 @@ _CACHE = {} -def resolve_common_type(commontype): +def resolve_common_type(parser, commontype): try: return _CACHE[commontype] except KeyError: - result = COMMON_TYPES.get(commontype, commontype) - if not isinstance(result, str): - pass # result is already a BaseType - elif result.endswith(' *'): - if result.startswith('const '): - result = model.ConstPointerType( - resolve_common_type(result[6:-2])) - else: - result = model.PointerType(resolve_common_type(result[:-2])) - elif result in model.PrimitiveType.ALL_PRIMITIVE_TYPES: - result = model.PrimitiveType(result) - elif result == 'set-unicode-needed': + cdecl = COMMON_TYPES.get(commontype, commontype) + if not isinstance(cdecl, str): + result, quals = cdecl, 0 # cdecl is already a BaseType + elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + result, quals = model.PrimitiveType(cdecl), 0 + elif cdecl == 'set-unicode-needed': raise api.FFIError("The Windows type %r is only available after " "you call ffi.set_unicode()" % (commontype,)) else: - if commontype == result: + if commontype == cdecl: raise api.FFIError("Unsupported type: %r. Please file a bug " "if you think it should be." % (commontype,)) - result = resolve_common_type(result) # recursively + result, quals = parser.parse_type_and_quals(cdecl) # recursive + assert isinstance(result, model.BaseTypeByIdentity) - _CACHE[commontype] = result - return result + _CACHE[commontype] = result, quals + return result, quals # ____________________________________________________________ -# Windows common types +# extra types for Windows (most of them are in commontypes.c) -def win_common_types(maxsize): - result = {} - if maxsize < (1<<32): - result.update({ # Windows 32-bits - 'HALF_PTR': 'short', - 'INT_PTR': 'int', - 'LONG_PTR': 'long', - 'UHALF_PTR': 'unsigned short', - 'UINT_PTR': 'unsigned int', - 'ULONG_PTR': 'unsigned long', - }) - else: - result.update({ # Windows 64-bits - 'HALF_PTR': 'int', - 'INT_PTR': 'long long', - 'LONG_PTR': 'long long', - 'UHALF_PTR': 'unsigned int', - 'UINT_PTR': 'unsigned long long', - 'ULONG_PTR': 'unsigned long long', - }) - result.update({ - "BYTE": "unsigned char", - "BOOL": "int", - "CCHAR": "char", - "CHAR": "char", - "DWORD": "unsigned long", - "DWORD32": "unsigned int", - "DWORD64": "unsigned long long", - "FLOAT": "float", - "INT": "int", - "INT8": "signed char", - "INT16": "short", - "INT32": "int", - "INT64": "long long", - "LONG": "long", - "LONGLONG": "long long", - "LONG32": "int", - "LONG64": "long long", - "WORD": "unsigned short", - "PVOID": model.voidp_type, - "ULONGLONG": "unsigned long long", - "WCHAR": "wchar_t", - "SHORT": "short", - "UCHAR": "unsigned char", - "UINT": "unsigned int", - "UINT8": "unsigned char", - "UINT16": "unsigned short", - "UINT32": "unsigned int", - "UINT64": "unsigned long long", - "ULONG": "unsigned long", - "ULONG32": "unsigned int", - "ULONG64": "unsigned long long", - "USHORT": "unsigned short", - - "SIZE_T": "ULONG_PTR", - "SSIZE_T": "LONG_PTR", - "ATOM": "WORD", - "BOOLEAN": "BYTE", - "COLORREF": "DWORD", - - "HANDLE": "PVOID", - "DWORDLONG": "ULONGLONG", - "DWORD_PTR": "ULONG_PTR", - "HACCEL": "HANDLE", - - "HBITMAP": "HANDLE", - "HBRUSH": "HANDLE", - "HCOLORSPACE": "HANDLE", - "HCONV": "HANDLE", - "HCONVLIST": "HANDLE", - "HDC": "HANDLE", - "HDDEDATA": "HANDLE", - "HDESK": "HANDLE", - "HDROP": "HANDLE", - "HDWP": "HANDLE", - "HENHMETAFILE": "HANDLE", - "HFILE": "int", - "HFONT": "HANDLE", - "HGDIOBJ": "HANDLE", - "HGLOBAL": "HANDLE", - "HHOOK": "HANDLE", - "HICON": "HANDLE", - "HCURSOR": "HICON", - "HINSTANCE": "HANDLE", - "HKEY": "HANDLE", - "HKL": "HANDLE", - "HLOCAL": "HANDLE", - "HMENU": "HANDLE", - "HMETAFILE": "HANDLE", - "HMODULE": "HINSTANCE", - "HMONITOR": "HANDLE", - "HPALETTE": "HANDLE", - "HPEN": "HANDLE", - "HRESULT": "LONG", - "HRGN": "HANDLE", - "HRSRC": "HANDLE", - "HSZ": "HANDLE", - "WINSTA": "HANDLE", - "HWND": "HANDLE", - - "LANGID": "WORD", - "LCID": "DWORD", - "LCTYPE": "DWORD", - "LGRPID": "DWORD", - "LPARAM": "LONG_PTR", - "LPBOOL": "BOOL *", - "LPBYTE": "BYTE *", - "LPCOLORREF": "DWORD *", - "LPCSTR": "const char *", - - "LPCVOID": model.const_voidp_type, - "LPCWSTR": "const WCHAR *", - "LPDWORD": "DWORD *", - "LPHANDLE": "HANDLE *", - "LPINT": "int *", - "LPLONG": "long *", - "LPSTR": "CHAR *", - "LPWSTR": "WCHAR *", - "LPVOID": model.voidp_type, - "LPWORD": "WORD *", - "LRESULT": "LONG_PTR", - "PBOOL": "BOOL *", - "PBOOLEAN": "BOOLEAN *", - "PBYTE": "BYTE *", - "PCHAR": "CHAR *", - "PCSTR": "const CHAR *", - "PCWSTR": "const WCHAR *", - "PDWORD": "DWORD *", - "PDWORDLONG": "DWORDLONG *", - "PDWORD_PTR": "DWORD_PTR *", - "PDWORD32": "DWORD32 *", - "PDWORD64": "DWORD64 *", - "PFLOAT": "FLOAT *", - "PHALF_PTR": "HALF_PTR *", - "PHANDLE": "HANDLE *", - "PHKEY": "HKEY *", - "PINT": "int *", - "PINT_PTR": "INT_PTR *", - "PINT8": "INT8 *", - "PINT16": "INT16 *", - "PINT32": "INT32 *", - "PINT64": "INT64 *", - "PLCID": "PDWORD", - "PLONG": "LONG *", - "PLONGLONG": "LONGLONG *", - "PLONG_PTR": "LONG_PTR *", - "PLONG32": "LONG32 *", - "PLONG64": "LONG64 *", - "PSHORT": "SHORT *", - "PSIZE_T": "SIZE_T *", - "PSSIZE_T": "SSIZE_T *", - "PSTR": "CHAR *", - "PUCHAR": "UCHAR *", - "PUHALF_PTR": "UHALF_PTR *", - "PUINT": "UINT *", - "PUINT_PTR": "UINT_PTR *", - "PUINT8": "UINT8 *", - "PUINT16": "UINT16 *", - "PUINT32": "UINT32 *", - "PUINT64": "UINT64 *", - "PULONG": "ULONG *", - "PULONGLONG": "ULONGLONG *", - "PULONG_PTR": "ULONG_PTR *", - "PULONG32": "ULONG32 *", - "PULONG64": "ULONG64 *", - "PUSHORT": "USHORT *", - "PWCHAR": "WCHAR *", - "PWORD": "WORD *", - "PWSTR": "WCHAR *", - "QWORD": "unsigned long long", - "SC_HANDLE": "HANDLE", - "SC_LOCK": "LPVOID", - "SERVICE_STATUS_HANDLE": "HANDLE", - +def win_common_types(): + return { "UNICODE_STRING": model.StructType( "_UNICODE_STRING", ["Length", @@ -232,10 +62,6 @@ "PUNICODE_STRING": "UNICODE_STRING *", "PCUNICODE_STRING": "const UNICODE_STRING *", - "USN": "LONGLONG", - "VOID": model.void_type, - "WPARAM": "UINT_PTR", - "TBYTE": "set-unicode-needed", "TCHAR": "set-unicode-needed", "LPCTSTR": "set-unicode-needed", @@ -244,9 +70,7 @@ "PTSTR": "set-unicode-needed", "PTBYTE": "set-unicode-needed", "PTCHAR": "set-unicode-needed", - }) - return result - + } if sys.platform == 'win32': - COMMON_TYPES.update(win_common_types(sys.maxsize)) + COMMON_TYPES.update(win_common_types()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/cffi/cparser.py new/cffi-1.3.1/cffi/cparser.py --- old/cffi-1.3.0/cffi/cparser.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/cffi/cparser.py 2015-11-18 15:47:13.000000000 +0100 @@ -29,6 +29,8 @@ _r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") _r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") _r_cdecl = re.compile(r"\b__cdecl\b") +_r_star_const_space = re.compile( # matches "* const " + r"[*]\s*((const|volatile|restrict)\b\s*)+") def _get_parser(): global _parser_cache @@ -36,6 +38,48 @@ _parser_cache = pycparser.CParser() return _parser_cache +def _workaround_for_old_pycparser(csource): + # Workaround for a pycparser issue (fixed between pycparser 2.10 and + # 2.14): "char*const***" gives us a wrong syntax tree, the same as + # for "char***(*const)". This means we can't tell the difference + # afterwards. But "char(*const(***))" gives us the right syntax + # tree. The issue only occurs if there are several stars in + # sequence with no parenthesis inbetween, just possibly qualifiers. + # Attempt to fix it by adding some parentheses in the source: each + # time we see "* const" or "* const *", we add an opening + # parenthesis before each star---the hard part is figuring out where + # to close them. + parts = [] + while True: + match = _r_star_const_space.search(csource) + if not match: + break + #print repr(''.join(parts)+csource), '=>', + parts.append(csource[:match.start()]) + parts.append('('); closing = ')' + parts.append(match.group()) # e.g. "* const " + endpos = match.end() + if csource.startswith('*', endpos): + parts.append('('); closing += ')' + level = 0 + i = endpos + while i < len(csource): + c = csource[i] + if c == '(': + level += 1 + elif c == ')': + if level == 0: + break + level -= 1 + elif c in ',;=': + if level == 0: + break + i += 1 + csource = csource[endpos:i] + closing + csource[i:] + #print repr(''.join(parts)+csource) + parts.append(csource) + return ''.join(parts) + def _preprocess(csource): # Remove comments. NOTE: this only work because the cdef() section # should not contain any string literal! @@ -47,6 +91,10 @@ macrovalue = macrovalue.replace('\\\n', '').strip() macros[macroname] = macrovalue csource = _r_define.sub('', csource) + # + if pycparser.__version__ < '2.14': + csource = _workaround_for_old_pycparser(csource) + # # BIG HACK: replace WINAPI or __stdcall with "volatile const". # It doesn't make sense for the return type of a function to be # "volatile volatile const", so we abuse it to detect __stdcall... @@ -320,13 +368,15 @@ self._declare('variable ' + decl.name, tp, quals=quals) def parse_type(self, cdecl): + return self.parse_type_and_quals(cdecl)[0] + + def parse_type_and_quals(self, cdecl): ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] assert not macros exprnode = ast.ext[-1].type.args.params[0] if isinstance(exprnode, pycparser.c_ast.ID): raise api.CDefError("unknown identifier '%s'" % (exprnode.name,)) - tp, quals = self._get_type_and_quals(exprnode.type) - return tp + return self._get_type_and_quals(exprnode.type) def _declare(self, name, obj, included=False, quals=0): if name in self._declarations: @@ -348,6 +398,8 @@ pycparser.c_ast.PtrDecl)): if 'const' in type.quals: quals |= model.Q_CONST + if 'volatile' in type.quals: + quals |= model.Q_VOLATILE if 'restrict' in type.quals: quals |= model.Q_RESTRICT return quals @@ -422,7 +474,8 @@ if ident == '__dotdotdot__': raise api.FFIError(':%d: bad usage of "..."' % typenode.coord.line) - return resolve_common_type(ident), quals + tp0, quals0 = resolve_common_type(self, ident) + return tp0, (quals | quals0) # if isinstance(type, pycparser.c_ast.Struct): # 'struct foobar' @@ -456,6 +509,13 @@ def _parse_function_type(self, typenode, funcname=None): params = list(getattr(typenode.args, 'params', [])) + for i, arg in enumerate(params): + if not hasattr(arg, 'type'): + raise api.CDefError("%s arg %d: unknown type '%s'" + " (if you meant to use the old C syntax of giving" + " untyped arguments, it is not supported)" + % (funcname or 'in expression', i + 1, + getattr(arg, 'name', '?'))) ellipsis = ( len(params) > 0 and isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/cffi/model.py new/cffi-1.3.1/cffi/model.py --- old/cffi-1.3.0/cffi/model.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/cffi/model.py 2015-11-18 15:47:13.000000000 +0100 @@ -7,10 +7,13 @@ # type qualifiers Q_CONST = 0x01 Q_RESTRICT = 0x02 +Q_VOLATILE = 0x04 def qualify(quals, replace_with): if quals & Q_CONST: replace_with = ' const ' + replace_with.lstrip() + if quals & Q_VOLATILE: + replace_with = ' volatile ' + replace_with.lstrip() if quals & Q_RESTRICT: # It seems that __restrict is supported by gcc and msvc. # If you hit some different compiler, add a #define in @@ -511,12 +514,17 @@ if self.baseinttype is not None: return self.baseinttype.get_cached_btype(ffi, finishlist) # + from . import api if self.enumvalues: smallest_value = min(self.enumvalues) largest_value = max(self.enumvalues) else: - smallest_value = 0 - largest_value = 0 + import warnings + warnings.warn("%r has no values explicitly defined; next version " + "will refuse to guess which integer type it is " + "meant to be (unsigned/signed, int/long)" + % self._get_c_name()) + smallest_value = largest_value = 0 if smallest_value < 0: # needs a signed type sign = 1 candidate1 = PrimitiveType("int") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/cffi/parse_c_type.h new/cffi-1.3.1/cffi/parse_c_type.h --- old/cffi-1.3.0/cffi/parse_c_type.h 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/cffi/parse_c_type.h 2015-11-18 15:47:13.000000000 +0100 @@ -83,6 +83,8 @@ #define _CFFI__UNKNOWN_FLOAT_PRIM (-2) #define _CFFI__UNKNOWN_LONG_DOUBLE (-3) +#define _CFFI__IO_FILE_STRUCT (-1) + struct _cffi_global_s { const char *name; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/cffi.egg-info/PKG-INFO new/cffi-1.3.1/cffi.egg-info/PKG-INFO --- old/cffi-1.3.0/cffi.egg-info/PKG-INFO 2015-10-21 12:53:30.000000000 +0200 +++ new/cffi-1.3.1/cffi.egg-info/PKG-INFO 2015-11-18 16:54:20.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.3.0 +Version: 1.3.1 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/cffi.egg-info/SOURCES.txt new/cffi-1.3.1/cffi.egg-info/SOURCES.txt --- old/cffi-1.3.0/cffi.egg-info/SOURCES.txt 2015-10-21 12:53:31.000000000 +0200 +++ new/cffi-1.3.1/cffi.egg-info/SOURCES.txt 2015-11-18 16:54:20.000000000 +0100 @@ -7,6 +7,7 @@ c/cdlopen.c c/cffi1_module.c c/cglob.c +c/commontypes.c c/ffi_obj.c c/file_emulator.h c/lib_obj.c @@ -131,6 +132,7 @@ testing/cffi0/snippets/setuptools_package_2/snip_setuptools_verify2/__init__.py testing/cffi1/__init__.py testing/cffi1/test_cffi_binary.py +testing/cffi1/test_commontypes.py testing/cffi1/test_dlopen.py testing/cffi1/test_dlopen_unicode_literals.py testing/cffi1/test_ffi_obj.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/doc/source/cdef.rst new/cffi-1.3.1/doc/source/cdef.rst --- old/cffi-1.3.0/doc/source/cdef.rst 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/doc/source/cdef.rst 2015-11-18 15:47:13.000000000 +0100 @@ -253,7 +253,7 @@ Usually, the right thing to do is to call this method with True. Be aware (particularly on Python 2) that, afterwards, you need to pass unicode -strings as arguments instead of not byte strings. (Before cffi version 0.9, +strings as arguments instead of byte strings. (Before cffi version 0.9, ``TCHAR`` and friends where hard-coded as unicode, but ``UNICODE`` was, inconsistently, not defined by default.) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/doc/source/conf.py new/cffi-1.3.1/doc/source/conf.py --- old/cffi-1.3.0/doc/source/conf.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/doc/source/conf.py 2015-11-18 15:47:13.000000000 +0100 @@ -47,7 +47,7 @@ # The short X.Y version. version = '1.3' # The full version, including alpha/beta/rc tags. -release = '1.3.0' +release = '1.3.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/doc/source/installation.rst new/cffi-1.3.1/doc/source/installation.rst --- old/cffi-1.3.0/doc/source/installation.rst 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/doc/source/installation.rst 2015-11-18 15:47:13.000000000 +0100 @@ -51,7 +51,7 @@ Download and Installation: -* http://pypi.python.org/packages/source/c/cffi/cffi-1.3.0.tar.gz +* http://pypi.python.org/packages/source/c/cffi/cffi-1.3.1.tar.gz - MD5: ... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/doc/source/using.rst new/cffi-1.3.1/doc/source/using.rst --- old/cffi-1.3.0/doc/source/using.rst 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/doc/source/using.rst 2015-11-18 15:47:13.000000000 +0100 @@ -514,6 +514,16 @@ discouraged: using this a style, we are more likely to forget the callback object too early, when it is still in use. +.. warning:: + + **SELinux** requires that the setting ``deny_execmem`` is left to + its default setting of ``off`` to use callbacks. A fix in cffi was + attempted (see the ``ffi_closure_alloc`` branch), but this branch is + not merged because it creates potential memory corruption with + ``fork()``. For more information, `see here.`__ + +.. __: https://bugzilla.redhat.com/show_bug.cgi?id=1249685 + *New in version 1.2:* If you want to be sure to catch all exceptions, use ``ffi.callback(..., onerror=func)``. If an exception occurs and ``onerror`` is specified, then ``onerror(exception, exc_value, @@ -686,19 +696,22 @@ Python 2/3 compatibility note: you should avoid using ``str(buf)``, because it gives inconsistent results between Python 2 and Python 3. -This is similar to how ``str()`` gives inconsistent results on regular +(This is similar to how ``str()`` gives inconsistent results on regular byte strings). Use ``buf[:]`` instead. **ffi.from_buffer(python_buffer)**: return a ``<cdata 'char[]'>`` that points to the data of the given Python object, which must support the buffer interface. This is the opposite of ``ffi.buffer()``. It gives -a (read-write) reference to the existing data, not a copy; for this +a reference to the existing data, not a copy; for this reason, and for PyPy compatibility, it does not work with the built-in types str or unicode or bytearray (or buffers/memoryviews on them). It is meant to be used on objects containing large quantities of raw data, like ``array.array`` or numpy arrays. It supports both the old buffer API (in Python 2.x) and the -new memoryview API. The original object is kept alive (and, in case +new memoryview API. Note that if you pass a read-only buffer object, +you still get a regular ``<cdata 'char[]'>``; it is your responsibility +not to write there if the original buffer doesn't expect you to. +The original object is kept alive (and, in case of memoryview, locked) as long as the cdata object returned by ``ffi.from_buffer()`` is alive. *New in version 0.9.* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/doc/source/whatsnew.rst new/cffi-1.3.1/doc/source/whatsnew.rst --- old/cffi-1.3.0/doc/source/whatsnew.rst 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/doc/source/whatsnew.rst 2015-11-18 15:47:13.000000000 +0100 @@ -3,6 +3,22 @@ ====================== +v1.3.1 +====== + +* The optional typedefs (``bool``, ``FILE`` and all Windows types) were + not always available from out-of-line FFI objects. + +* Opaque enums are phased out from the cdefs: they now give a warning, + instead of (possibly wrongly) being assumed equal to ``unsigned int``. + Please report if you get a reasonable use case for them. + +* Some parsing details, notably ``volatile`` is passed along like + ``const`` and ``restrict``. Also, older versions of pycparser + mis-parse some pointer-to-pointer types like ``char * const *``: the + "const" ends up at the wrong place. Added a workaround. + + v1.3.0 ====== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/setup.py new/cffi-1.3.1/setup.py --- old/cffi-1.3.0/setup.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/setup.py 2015-11-18 15:47:13.000000000 +0100 @@ -144,7 +144,7 @@ `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ """, - version='1.3.0', + version='1.3.1', packages=['cffi'] if cpython else [], package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h']} if cpython else {}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi0/backend_tests.py new/cffi-1.3.1/testing/cffi0/backend_tests.py --- old/cffi-1.3.0/testing/cffi0/backend_tests.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/testing/cffi0/backend_tests.py 2015-11-18 15:47:13.000000000 +0100 @@ -756,10 +756,11 @@ p = ffi.cast("long long", ffi.cast("wchar_t", -1)) if SIZE_OF_WCHAR == 2: # 2 bytes, unsigned assert int(p) == 0xffff - elif platform.machine().startswith(('arm', 'aarch64')): - assert int(p) == 0xffffffff # 4 bytes, unsigned - else: # 4 bytes, signed + elif (sys.platform.startswith('linux') and + platform.machine().startswith('x86')): # known to be signed assert int(p) == -1 + else: # in general, it can be either signed or not + assert int(p) in [-1, 0xffffffff] # e.g. on arm, both cases occur p = ffi.cast("int", u+'\u1234') assert int(p) == 0x1234 @@ -1334,7 +1335,8 @@ # these depend on user-defined data, so should not be shared assert ffi1.typeof("struct foo") is not ffi2.typeof("struct foo") assert ffi1.typeof("union foo *") is not ffi2.typeof("union foo*") - assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo") + # the following test is an opaque enum, which we no longer support + #assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo") # sanity check: twice 'ffi1' assert ffi1.typeof("struct foo*") is ffi1.typeof("struct foo *") @@ -1346,6 +1348,17 @@ assert ffi.getctype("pe") == 'e *' assert ffi.getctype("e1*") == 'e1 *' + def test_opaque_enum(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef("enum foo;") + from cffi import __version_info__ + if __version_info__ < (1, 4): + py.test.skip("re-enable me in version 1.4") + e = py.test.raises(CDefError, ffi.cast, "enum foo", -1) + assert str(e.value) == ( + "'enum foo' has no values explicitly defined: refusing to guess " + "which integer type it is meant to be (unsigned/signed, int/long)") + def test_new_ctype(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int *") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi0/test_function.py new/cffi-1.3.1/testing/cffi0/test_function.py --- old/cffi-1.3.0/testing/cffi0/test_function.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/testing/cffi0/test_function.py 2015-11-18 15:47:13.000000000 +0100 @@ -486,7 +486,7 @@ ffi = FFI(backend=self.Backend()) ffi.cdef("double __stdcall sin(double x);") # stdcall ignored m = ffi.dlopen(lib_m) - if (sys.platform == 'win32' and sys.maxint < 2**32 and + if (sys.platform == 'win32' and sys.maxsize < 2**32 and self.Backend is not CTypesBackend): assert "double(__stdcall *)(double)" in str(ffi.typeof(m.sin)) else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi0/test_parsing.py new/cffi-1.3.1/testing/cffi0/test_parsing.py --- old/cffi-1.3.0/testing/cffi0/test_parsing.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/testing/cffi0/test_parsing.py 2015-11-18 15:47:13.000000000 +0100 @@ -261,7 +261,8 @@ ffi = FFI() ffi.cdef("typedef int bool, *FILE;") assert repr(ffi.cast("bool", 123)) == "<cdata 'int' 123>" - assert repr(ffi.cast("FILE", 123)) == "<cdata 'int *' 0x7b>" + assert re.match(r"<cdata 'int [*]' 0[xX]?0*7[bB]>", + repr(ffi.cast("FILE", 123))) ffi = FFI() ffi.cdef("typedef bool (*fn_t)(bool, bool);") # "bool," but within "( )" @@ -272,6 +273,13 @@ ffi = FFI() ffi.cdef("typedef _Bool bool; void f(bool);") +def test_unknown_argument_type(): + ffi = FFI() + e = py.test.raises(CDefError, ffi.cdef, "void f(foobarbazzz);") + assert str(e.value) == ("f arg 1: unknown type 'foobarbazzz' (if you meant" + " to use the old C syntax of giving untyped" + " arguments, it is not supported)") + def test_void_renamed_as_only_arg(): ffi = FFI() ffi.cdef("typedef void void_t1;" @@ -279,38 +287,16 @@ "typedef int (*func_t)(void_t);") assert ffi.typeof("func_t").args == () -def test_win_common_types(): - from cffi.commontypes import COMMON_TYPES, _CACHE - from cffi.commontypes import win_common_types, resolve_common_type - # - def clear_all(extra={}, old_dict=COMMON_TYPES.copy()): - COMMON_TYPES.clear() - COMMON_TYPES.update(old_dict) - COMMON_TYPES.update(extra) - _CACHE.clear() - # - for maxsize in [2**32-1, 2**64-1]: - ct = win_common_types(maxsize) - clear_all(ct) - for key in sorted(ct): - if ct[key] != 'set-unicode-needed': - resolve_common_type(key) - # assert did not crash - # now try to use e.g. WPARAM (-> UINT_PTR -> unsigned 32/64-bit) - for maxsize in [2**32-1, 2**64-1]: - ct = win_common_types(maxsize) - clear_all(ct) - ffi = FFI() - value = int(ffi.cast("WPARAM", -1)) - assert value == maxsize - # - clear_all() - def test_WPARAM_on_windows(): if sys.platform != 'win32': py.test.skip("Only for Windows") ffi = FFI() ffi.cdef("void f(WPARAM);") + # + # WPARAM -> UINT_PTR -> unsigned 32/64-bit integer + ffi = FFI() + value = int(ffi.cast("WPARAM", -42)) + assert value == sys.maxsize * 2 - 40 def test__is_constant_globalvar(): for input, expected_output in [ @@ -360,6 +346,41 @@ assert lst[0] == lst[2] assert lst[1] == lst[3] +def test_const_pointer_to_pointer(): + from cffi import model + ffi = FFI(backend=FakeBackend()) + # + tp, qual = ffi._parser.parse_type_and_quals("char * * (* const)") + assert (str(tp), qual) == ("<char * * *>", model.Q_CONST) + tp, qual = ffi._parser.parse_type_and_quals("char * (* const (*))") + assert (str(tp), qual) == ("<char * * const *>", 0) + tp, qual = ffi._parser.parse_type_and_quals("char (* const (* (*)))") + assert (str(tp), qual) == ("<char * const * *>", 0) + tp, qual = ffi._parser.parse_type_and_quals("char const * * *") + assert (str(tp), qual) == ("<char const * * *>", 0) + tp, qual = ffi._parser.parse_type_and_quals("const char * * *") + assert (str(tp), qual) == ("<char const * * *>", 0) + # + tp, qual = ffi._parser.parse_type_and_quals("char * * * const const") + assert (str(tp), qual) == ("<char * * *>", model.Q_CONST) + tp, qual = ffi._parser.parse_type_and_quals("char * * volatile *") + assert (str(tp), qual) == ("<char * * volatile *>", 0) + tp, qual = ffi._parser.parse_type_and_quals("char * volatile restrict * *") + assert (str(tp), qual) == ("<char * __restrict volatile * *>", 0) + tp, qual = ffi._parser.parse_type_and_quals("char const volatile * * *") + assert (str(tp), qual) == ("<char volatile const * * *>", 0) + tp, qual = ffi._parser.parse_type_and_quals("const char * * *") + assert (str(tp), qual) == ("<char const * * *>", 0) + # + tp, qual = ffi._parser.parse_type_and_quals( + "int(char*const*, short****const*)") + assert (str(tp), qual) == ( + "<int()(char * const *, short * * * * const *)>", 0) + tp, qual = ffi._parser.parse_type_and_quals( + "char*const*(short*const****)") + assert (str(tp), qual) == ( + "<char * const *()(short * const * * * *)>", 0) + def test_enum(): ffi = FFI() ffi.cdef(""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi1/test_commontypes.py new/cffi-1.3.1/testing/cffi1/test_commontypes.py --- old/cffi-1.3.0/testing/cffi1/test_commontypes.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cffi-1.3.1/testing/cffi1/test_commontypes.py 2015-11-18 15:47:13.000000000 +0100 @@ -0,0 +1,34 @@ +import py, os, cffi, re +import _cffi_backend + + +def getlines(): + try: + f = open(os.path.join(os.path.dirname(cffi.__file__), + '..', 'c', 'commontypes.c')) + except IOError: + py.test.skip("cannot find ../c/commontypes.c") + lines = [line for line in f.readlines() if line.strip().startswith('EQ(')] + f.close() + return lines + +def test_alphabetical_order(): + lines = getlines() + assert lines == sorted(lines) + +def test_dependencies(): + r = re.compile(r'EQ[(]"([^"]+)",(?:\s*"([A-Z0-9_]+)\s*[*]*"[)])?') + lines = getlines() + d = {} + for line in lines: + match = r.search(line) + if match is not None: + d[match.group(1)] = match.group(2) + for value in d.values(): + if value: + assert value in d + +def test_get_common_types(): + d = {} + _cffi_backend._get_common_types(d) + assert d["bool"] == "_Bool" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi1/test_ffi_obj.py new/cffi-1.3.1/testing/cffi1/test_ffi_obj.py --- old/cffi-1.3.0/testing/cffi1/test_ffi_obj.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/testing/cffi1/test_ffi_obj.py 2015-11-18 15:47:13.000000000 +0100 @@ -395,3 +395,23 @@ return ffi.NULL alloc5 = ffi.new_allocator(myalloc5) py.test.raises(MemoryError, alloc5, "int[5]") + +def test_bool_issue228(): + ffi = _cffi1_backend.FFI() + fntype = ffi.typeof("int(*callback)(bool is_valid)") + assert repr(fntype.args[0]) == "<ctype '_Bool'>" + +def test_FILE_issue228(): + fntype1 = _cffi1_backend.FFI().typeof("FILE *") + fntype2 = _cffi1_backend.FFI().typeof("FILE *") + assert repr(fntype1) == "<ctype 'FILE *'>" + assert fntype1 is fntype2 + +def test_cast_from_int_type_to_bool(): + ffi = _cffi1_backend.FFI() + for basetype in ['char', 'short', 'int', 'long', 'long long']: + for sign in ['signed', 'unsigned']: + type = '%s %s' % (sign, basetype) + assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1 + assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1 + assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi1/test_new_ffi_1.py new/cffi-1.3.1/testing/cffi1/test_new_ffi_1.py --- old/cffi-1.3.0/testing/cffi1/test_new_ffi_1.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/testing/cffi1/test_new_ffi_1.py 2015-11-18 15:47:13.000000000 +0100 @@ -781,10 +781,11 @@ p = ffi.cast("long long", ffi.cast("wchar_t", -1)) if SIZE_OF_WCHAR == 2: # 2 bytes, unsigned assert int(p) == 0xffff - elif platform.machine().startswith(('arm', 'aarch64')): - assert int(p) == 0xffffffff # 4 bytes, unsigned - else: # 4 bytes, signed + elif (sys.platform.startswith('linux') and + platform.machine().startswith('x86')): # known to be signed assert int(p) == -1 + else: # in general, it can be either signed or not + assert int(p) in [-1, 0xffffffff] # e.g. on arm, both cases occur p = ffi.cast("int", u+'\u1234') assert int(p) == 0x1234 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi1/test_parse_c_type.py new/cffi-1.3.1/testing/cffi1/test_parse_c_type.py --- old/cffi-1.3.0/testing/cffi1/test_parse_c_type.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/testing/cffi1/test_parse_c_type.py 2015-11-18 15:47:13.000000000 +0100 @@ -19,8 +19,11 @@ ffi.cdef(header) lib = ffi.verify( - open(os.path.join(cffi_dir, '..', 'c', 'parse_c_type.c')).read(), - include_dirs=[cffi_dir]) + open(os.path.join(cffi_dir, '..', 'c', 'parse_c_type.c')).read() + """ +static const char *get_common_type(const char *search, size_t search_len) { + return NULL; +} +""", include_dirs=[cffi_dir]) class ParseError(Exception): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi1/test_recompiler.py new/cffi-1.3.1/testing/cffi1/test_recompiler.py --- old/cffi-1.3.0/testing/cffi1/test_recompiler.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/testing/cffi1/test_recompiler.py 2015-11-18 15:47:13.000000000 +0100 @@ -1204,12 +1204,19 @@ assert foo_s.fields[1][1].type is ffi.typeof("void *") def test_restrict_fields(): - if sys.platform == 'win32': - py.test.skip("'__restrict__' probably not recognized") ffi = FFI() ffi.cdef("""struct foo_s { void * restrict b; };""") lib = verify(ffi, 'test_restrict_fields', """ - struct foo_s { void * __restrict__ b; };""") + struct foo_s { void * __restrict b; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'b' + assert foo_s.fields[0][1].type is ffi.typeof("void *") + +def test_volatile_fields(): + ffi = FFI() + ffi.cdef("""struct foo_s { void * volatile b; };""") + lib = verify(ffi, 'test_volatile_fields', """ + struct foo_s { void * volatile b; };""") foo_s = ffi.typeof("struct foo_s") assert foo_s.fields[0][0] == 'b' assert foo_s.fields[0][1].type is ffi.typeof("void *") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.3.0/testing/cffi1/test_verify1.py new/cffi-1.3.1/testing/cffi1/test_verify1.py --- old/cffi-1.3.0/testing/cffi1/test_verify1.py 2015-10-21 12:51:22.000000000 +0200 +++ new/cffi-1.3.1/testing/cffi1/test_verify1.py 2015-11-18 15:47:13.000000000 +0100 @@ -1494,15 +1494,6 @@ assert lib.foo(0) == 1 py.test.raises(TypeError, lib.foo, 0.0) -def test_cast_from_int_type_to_bool(): - ffi = FFI() - for basetype in ['char', 'short', 'int', 'long', 'long long']: - for sign in ['signed', 'unsigned']: - type = '%s %s' % (sign, basetype) - assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1 - assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1 - assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0 - def test_addressof(): ffi = FFI() ffi.cdef(""" @@ -2250,3 +2241,31 @@ assert p == lib.myarray + 4 p[1] = 82 assert lib.my_value == 82 # [5] + +def test_const_pointer_to_pointer(): + ffi = FFI() + ffi.cdef("struct s { char *const *a; };") + ffi.verify("struct s { char *const *a; };") + +def test_share_FILE(): + ffi1 = FFI() + ffi1.cdef("void do_stuff(FILE *);") + lib1 = ffi1.verify("void do_stuff(FILE *f) { (void)f; }") + ffi2 = FFI() + ffi2.cdef("FILE *barize(void);") + lib2 = ffi2.verify("FILE *barize(void) { return NULL; }") + lib1.do_stuff(lib2.barize()) + +def test_win_common_types(): + if sys.platform != 'win32': + py.test.skip("Windows only") + ffi = FFI() + ffi.set_unicode(True) + ffi.verify("") + assert ffi.typeof("PBYTE") is ffi.typeof("unsigned char *") + if sys.maxsize > 2**32: + expected = "unsigned long long" + else: + expected = "unsigned int" + assert ffi.typeof("UINT_PTR") is ffi.typeof(expected) + assert ffi.typeof("PTSTR") is ffi.typeof("wchar_t *")
