summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiƩbaud Weksteen <tweek@google.com>2024-03-01 00:12:59 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2024-03-01 00:12:59 +0000
commitab2762e31007956116589194dda10bf081519be3 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904
parente4ad7f6c2e347100129583e177d33e02a31afb78 (diff)
parentde77edbe02d4cc29c5f218144e41d4e708244566 (diff)
downloadcffi-main.tar.gz
Empty external/python/cffi am: de77edbe02HEADmastermain
Original change: https://android-review.googlesource.com/c/platform/external/python/cffi/+/2984152 Change-Id: Iac23460dbd403e2c877c2706a29e394d2ddc9361 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--AUTHORS8
-rw-r--r--Android.bp31
-rw-r--r--LICENSE26
-rw-r--r--MANIFEST.in6
-rw-r--r--METADATA17
-rw-r--r--MODULE_LICENSE_MIT0
-rw-r--r--README.md30
-rwxr-xr-xc/.libs_cffi_backend/libffi-9c61262e.so.8.1.0bin63080 -> 0 bytes
-rw-r--r--c/Android.bp44
-rw-r--r--c/_cffi_backend.c8083
-rwxr-xr-xc/_cffi_backend.sobin791800 -> 0 bytes
-rw-r--r--c/_dummy_file_cffi_backend.py0
-rw-r--r--c/_dummy_file_libffi.py0
-rw-r--r--c/call_python.c292
-rw-r--r--c/cdlopen.c362
-rw-r--r--c/cffi1_module.c216
-rw-r--r--c/cglob.c113
-rw-r--r--c/commontypes.c216
-rw-r--r--c/ffi_obj.c1221
-rw-r--r--c/file_emulator.h93
-rw-r--r--c/lib_obj.c716
-rw-r--r--c/libffi_arm64/README5
-rw-r--r--c/libffi_arm64/ffi.libbin7872 -> 0 bytes
-rw-r--r--c/libffi_arm64/include/ffi.h515
-rw-r--r--c/libffi_arm64/include/fficonfig.h215
-rw-r--r--c/libffi_arm64/include/ffitarget.h92
-rw-r--r--c/libffi_x86_x64/LICENSE20
-rw-r--r--c/libffi_x86_x64/README502
-rw-r--r--c/libffi_x86_x64/README.ctypes7
-rw-r--r--c/libffi_x86_x64/ffi.c495
-rw-r--r--c/libffi_x86_x64/ffi.h322
-rw-r--r--c/libffi_x86_x64/ffi_common.h77
-rw-r--r--c/libffi_x86_x64/fficonfig.h96
-rw-r--r--c/libffi_x86_x64/ffitarget.h85
-rw-r--r--c/libffi_x86_x64/prep_cif.c184
-rw-r--r--c/libffi_x86_x64/types.c104
-rw-r--r--c/libffi_x86_x64/win32.c162
-rw-r--r--c/libffi_x86_x64/win64.asm156
-rw-r--r--c/libffi_x86_x64/win64.objbin1176 -> 0 bytes
-rw-r--r--c/malloc_closure.h176
-rw-r--r--c/minibuffer.h408
-rw-r--r--c/misc_thread_common.h371
-rw-r--r--c/misc_thread_posix.h49
-rw-r--r--c/misc_win32.h242
-rw-r--r--c/parse_c_type.c847
-rw-r--r--c/realize_c_type.c820
-rw-r--r--c/test_c.py4575
-rw-r--r--c/wchar_helper.h246
-rw-r--r--c/wchar_helper_3.h149
-rw-r--r--cffi/Android.bp45
-rw-r--r--cffi/__init__.py14
-rw-r--r--cffi/_cffi_errors.h149
-rw-r--r--cffi/_cffi_include.h385
-rw-r--r--cffi/_embedding.h527
-rw-r--r--cffi/api.py965
-rw-r--r--cffi/backend_ctypes.py1121
-rw-r--r--cffi/cffi_opcode.py187
-rw-r--r--cffi/commontypes.py80
-rw-r--r--cffi/cparser.py1006
-rw-r--r--cffi/error.py31
-rw-r--r--cffi/ffiplatform.py127
-rw-r--r--cffi/lock.py30
-rw-r--r--cffi/model.py617
-rw-r--r--cffi/parse_c_type.h181
-rw-r--r--cffi/pkgconfig.py121
-rw-r--r--cffi/recompiler.py1581
-rw-r--r--cffi/setuptools_ext.py219
-rw-r--r--cffi/vengine_cpy.py1076
-rw-r--r--cffi/vengine_gen.py675
-rw-r--r--cffi/verifier.py307
-rw-r--r--demo/_curses.py1075
-rw-r--r--demo/_curses_build.py327
-rw-r--r--demo/_curses_setup.py13
-rw-r--r--demo/api.py62
-rw-r--r--demo/bsdopendirtype.py48
-rw-r--r--demo/bsdopendirtype_build.py23
-rw-r--r--demo/bsdopendirtype_setup.py13
-rw-r--r--demo/btrfs-snap.py52
-rw-r--r--demo/cffi-cocoa.py102
-rw-r--r--demo/embedding.py21
-rw-r--r--demo/embedding_test.c43
-rw-r--r--demo/extern_python.py26
-rw-r--r--demo/extern_python_varargs.py61
-rw-r--r--demo/fastcsv.py266
-rw-r--r--demo/gmp.py33
-rw-r--r--demo/gmp_build.py26
-rw-r--r--demo/manual.c166
-rw-r--r--demo/manual2.py34
-rw-r--r--demo/pwuid.py7
-rw-r--r--demo/pwuid_build.py18
-rwxr-xr-xdemo/py.cleanup31
-rw-r--r--demo/pyobj.py124
-rw-r--r--demo/readdir.py35
-rw-r--r--demo/readdir2.py35
-rw-r--r--demo/readdir2_build.py36
-rw-r--r--demo/readdir2_setup.py9
-rw-r--r--demo/readdir_build.py33
-rw-r--r--demo/readdir_ctypes.py69
-rw-r--r--demo/readdir_setup.py11
-rw-r--r--demo/recopendirtype.py50
-rw-r--r--demo/recopendirtype_build.py19
-rw-r--r--demo/setup_manual.py5
-rw-r--r--demo/winclipboard.py40
-rw-r--r--demo/winclipboard_build.py36
-rw-r--r--demo/xclient.py27
-rw-r--r--demo/xclient_build.py25
-rw-r--r--doc/Makefile89
-rw-r--r--doc/make.bat113
-rw-r--r--doc/misc/design.rst51
-rw-r--r--doc/misc/grant-cffi-1.0.rst124
-rw-r--r--doc/misc/parse_c_type.rst72
-rw-r--r--doc/source/cdef.rst1012
-rw-r--r--doc/source/conf.py194
-rw-r--r--doc/source/embedding.rst531
-rw-r--r--doc/source/goals.rst69
-rw-r--r--doc/source/index.rst19
-rw-r--r--doc/source/installation.rst190
-rw-r--r--doc/source/overview.rst651
-rw-r--r--doc/source/ref.rst1028
-rw-r--r--doc/source/using.rst1043
-rw-r--r--doc/source/whatsnew.rst887
-rw-r--r--requirements.txt2
-rw-r--r--setup.cfg2
-rw-r--r--setup.py238
-rw-r--r--setup_base.py23
-rw-r--r--testing/__init__.py0
-rw-r--r--testing/cffi0/__init__.py0
-rw-r--r--testing/cffi0/backend_tests.py2027
-rw-r--r--testing/cffi0/callback_in_thread.py42
-rw-r--r--testing/cffi0/snippets/distutils_module/setup.py7
-rw-r--r--testing/cffi0/snippets/distutils_module/snip_basic_verify.py17
-rw-r--r--testing/cffi0/snippets/distutils_package_1/setup.py7
-rw-r--r--testing/cffi0/snippets/distutils_package_1/snip_basic_verify1/__init__.py17
-rw-r--r--testing/cffi0/snippets/distutils_package_2/setup.py8
-rw-r--r--testing/cffi0/snippets/distutils_package_2/snip_basic_verify2/__init__.py18
-rw-r--r--testing/cffi0/snippets/infrastructure/setup.py5
-rw-r--r--testing/cffi0/snippets/infrastructure/snip_infrastructure/__init__.py3
-rw-r--r--testing/cffi0/snippets/setuptools_module/setup.py8
-rw-r--r--testing/cffi0/snippets/setuptools_module/snip_setuptools_verify.py17
-rw-r--r--testing/cffi0/snippets/setuptools_package_1/setup.py8
-rw-r--r--testing/cffi0/snippets/setuptools_package_1/snip_setuptools_verify1/__init__.py17
-rw-r--r--testing/cffi0/snippets/setuptools_package_2/setup.py9
-rw-r--r--testing/cffi0/snippets/setuptools_package_2/snip_setuptools_verify2/__init__.py18
-rw-r--r--testing/cffi0/test_cdata.py41
-rw-r--r--testing/cffi0/test_ctypes.py43
-rw-r--r--testing/cffi0/test_ffi_backend.py620
-rw-r--r--testing/cffi0/test_function.py548
-rw-r--r--testing/cffi0/test_model.py111
-rw-r--r--testing/cffi0/test_ownlib.py431
-rw-r--r--testing/cffi0/test_parsing.py610
-rw-r--r--testing/cffi0/test_platform.py25
-rw-r--r--testing/cffi0/test_unicode_literals.py79
-rw-r--r--testing/cffi0/test_verify.py2562
-rw-r--r--testing/cffi0/test_verify2.py9
-rw-r--r--testing/cffi0/test_version.py68
-rw-r--r--testing/cffi0/test_vgen.py12
-rw-r--r--testing/cffi0/test_vgen2.py13
-rw-r--r--testing/cffi0/test_zdistutils.py288
-rw-r--r--testing/cffi0/test_zintegration.py181
-rw-r--r--testing/cffi1/__init__.py0
-rw-r--r--testing/cffi1/test_cffi_binary.py22
-rw-r--r--testing/cffi1/test_commontypes.py34
-rw-r--r--testing/cffi1/test_dlopen.py225
-rw-r--r--testing/cffi1/test_dlopen_unicode_literals.py9
-rw-r--r--testing/cffi1/test_ffi_obj.py536
-rw-r--r--testing/cffi1/test_function_args.py208
-rw-r--r--testing/cffi1/test_new_ffi_1.py1831
-rw-r--r--testing/cffi1/test_parse_c_type.py372
-rw-r--r--testing/cffi1/test_pkgconfig.py94
-rw-r--r--testing/cffi1/test_re_python.py288
-rw-r--r--testing/cffi1/test_realize_c_type.py73
-rw-r--r--testing/cffi1/test_recompiler.py2495
-rw-r--r--testing/cffi1/test_unicode_literals.py43
-rw-r--r--testing/cffi1/test_verify1.py2359
-rw-r--r--testing/cffi1/test_zdist.py426
-rw-r--r--testing/embedding/__init__.py0
-rw-r--r--testing/embedding/add1-test.c21
-rw-r--r--testing/embedding/add1.py37
-rw-r--r--testing/embedding/add2-test.c14
-rw-r--r--testing/embedding/add2.py29
-rw-r--r--testing/embedding/add3.py24
-rw-r--r--testing/embedding/add_recursive-test.c27
-rw-r--r--testing/embedding/add_recursive.py33
-rw-r--r--testing/embedding/empty.py10
-rw-r--r--testing/embedding/initerror.py18
-rw-r--r--testing/embedding/perf-test.c90
-rw-r--r--testing/embedding/perf.py21
-rw-r--r--testing/embedding/test_basic.py214
-rw-r--r--testing/embedding/test_performance.py52
-rw-r--r--testing/embedding/test_recursive.py15
-rw-r--r--testing/embedding/test_thread.py65
-rw-r--r--testing/embedding/test_tlocal.py10
-rw-r--r--testing/embedding/thread-test.h96
-rw-r--r--testing/embedding/thread1-test.c43
-rw-r--r--testing/embedding/thread2-test.c57
-rw-r--r--testing/embedding/thread3-test.c56
-rw-r--r--testing/embedding/tlocal-test.c47
-rw-r--r--testing/embedding/tlocal.py33
-rw-r--r--testing/embedding/withunicode.py26
-rw-r--r--testing/support.py119
-rw-r--r--testing/udir.py140
201 files changed, 0 insertions, 59358 deletions
diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index 370a25d..0000000
--- a/AUTHORS
+++ /dev/null
@@ -1,8 +0,0 @@
-This package has been mostly done by Armin Rigo with help from
-Maciej Fijałkowski. The idea is heavily based (although not directly
-copied) from LuaJIT ffi by Mike Pall.
-
-
-Other contributors:
-
- Google Inc.
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index 13f23dd..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["external_python_cffi_license"],
-}
-
-// Added automatically by a large-scale-change
-// See: http://go/android-license-faq
-license {
- name: "external_python_cffi_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-MIT",
- ],
- license_text: [
- "LICENSE",
- ],
-}
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 29225ee..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,26 +0,0 @@
-
-Except when otherwise stated (look for LICENSE files in directories or
-information at the beginning of each file) all software and
-documentation is licensed as follows:
-
- The MIT License
-
- 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
- THE AUTHORS OR COPYRIGHT HOLDERS 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.
-
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index b8ca2e0..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,6 +0,0 @@
-recursive-include cffi *.py *.h
-recursive-include c *.c *.h *.asm *.py win64.obj ffi.lib
-recursive-include testing *.py *.c *.h
-recursive-include doc *.py *.rst Makefile *.bat
-recursive-include demo py.cleanup *.py embedding_test.c manual.c
-include AUTHORS LICENSE setup.py setup_base.py
diff --git a/METADATA b/METADATA
deleted file mode 100644
index db9d268..0000000
--- a/METADATA
+++ /dev/null
@@ -1,17 +0,0 @@
-name: "cffi"
-description:
- "Foreign Function Interface for Python calling C code."
-
-third_party {
- url {
- type: HOMEPAGE
- value: "https://bitbucket.org/cffi/cffi"
- }
- url {
- type: HG
- value: "https://bitbucket.org/cffi/cffi/src"
- }
- version: "1.15.0"
- last_upgrade_date { year: 2020 month: 11 day: 8 }
- license_type: NOTICE
-}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
deleted file mode 100644
index e69de29..0000000
--- a/MODULE_LICENSE_MIT
+++ /dev/null
diff --git a/README.md b/README.md
deleted file mode 100644
index a68639e..0000000
--- a/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-CFFI
-====
-
-Foreign Function Interface for Python calling C code.
-Please see the [Documentation](http://cffi.readthedocs.org/) or uncompiled
-in the doc/ subdirectory.
-
-Download
---------
-
-[Download page](https://foss.heptapod.net/pypy/cffi/-/tags)
-
-Contact
--------
-
-[Mailing list](https://groups.google.com/forum/#!forum/python-cffi)
-
-Testing/development tips
-------------------------
-
-To run tests under CPython, run::
-
- pip install pytest # if you don't have py.test already
- pip install pycparser
- python setup.py build_ext -f -i
- py.test c/ testing/
-
-If you run in another directory (either the tests or another program),
-you should use the environment variable ``PYTHONPATH=/path`` to point
-to the location that contains the ``_cffi_backend.so`` just compiled.
diff --git a/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0 b/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0
deleted file mode 100755
index 82b4232..0000000
--- a/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0
+++ /dev/null
Binary files differ
diff --git a/c/Android.bp b/c/Android.bp
deleted file mode 100644
index 96565df..0000000
--- a/c/Android.bp
+++ /dev/null
@@ -1,44 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "external_python_cffi_license"
- // to get the below license kinds:
- // SPDX-license-identifier-MIT
- default_applicable_licenses: ["external_python_cffi_license"],
-}
-
-python_library {
- name: "py-cffi-backend",
- host_supported: true,
- srcs: [
- "_dummy_file_cffi_backend.py",
- ],
- data: [
- ":py-cffi-backend-files"
- ],
-}
-
-filegroup {
- name: "py-cffi-backend-files",
- srcs: [
- "_cffi_backend.so",
- ],
-}
-
-python_library {
- name: "py-cffi-backend-libffi",
- host_supported: true,
- srcs: [
- "_dummy_file_libffi.py",
- ],
- data: [
- ":py-cffi-backend-libffi-files"
- ],
-}
-
-filegroup {
- name: "py-cffi-backend-libffi-files",
- srcs: [
- ".libs_cffi_backend/libffi-9c61262e.so.8.1.0",
- ],
-}
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
deleted file mode 100644
index ffecbf9..0000000
--- a/c/_cffi_backend.c
+++ /dev/null
@@ -1,8083 +0,0 @@
-#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
-
-
-/* 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
- * why I recommend against it and decide that you trust it more than my
- * analysis below.
- *
- * There are two versions of this code: one inside libffi itself, and
- * one inside malloc_closure.h here. Both should be fine as long as the
- * Linux distribution does _not_ enable extra security features. If it
- * does, then the code in malloc_closure.h will cleanly crash because
- * there is no reasonable way to obtain a read-write-execute memory
- * page. On the other hand, the code in libffi will appear to
- * work---but will actually randomly crash after a fork() if the child
- * does not immediately call exec(). This second crash is of the kind
- * that can be turned into an attack vector by a motivated attacker.
- * So, _enabling_ extra security features _opens_ an attack vector.
- * That sounds like a horribly bad idea to me, and is the reason for why
- * I prefer CFFI crashing cleanly.
- *
- * Currently, we use libffi's ffi_closure_alloc() on NetBSD. It is
- * known that on the NetBSD kernel, a different strategy is used which
- * should not be open to the fork() bug.
- *
- * This is also used on macOS, provided we are executing on macOS 10.15 or
- * above. It's a mess because it needs runtime checks in that case.
- */
-#ifdef __NetBSD__
-
-# define CFFI_CHECK_FFI_CLOSURE_ALLOC 1
-# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1
-# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 1
-# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1
-# define CFFI_CHECK_FFI_PREP_CIF_VAR 0
-# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0
-
-#elif defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE)
-
-# define CFFI_CHECK_FFI_CLOSURE_ALLOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)
-# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1
-# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)
-# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1
-# define CFFI_CHECK_FFI_PREP_CIF_VAR __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)
-# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 1
-
-#else
-
-# define CFFI_CHECK_FFI_CLOSURE_ALLOC 0
-# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 0
-# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 0
-# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 0
-# define CFFI_CHECK_FFI_PREP_CIF_VAR 0
-# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0
-
-#endif
-
-/* always includes this, even if it turns out not to be used on NetBSD
- because calls are behind "if (0)" */
-#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_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
-
-#if PY_VERSION_HEX < 0x030900a4
-# define Py_SET_REFCNT(obj, val) (Py_REFCNT(obj) = (val))
-#endif
-
-#if PY_VERSION_HEX >= 0x03080000
-# define USE_WRITEUNRAISABLEMSG
-#endif
-
-/************************************************************/
-
-/* 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 */
-#define CT_PRIMITIVE_FLOAT 0x008 /* float, double, long double */
-#define CT_POINTER 0x010 /* pointer, excluding ptr-to-func */
-#define CT_ARRAY 0x020 /* array */
-#define CT_STRUCT 0x040 /* struct */
-#define CT_UNION 0x080 /* union */
-#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: */
-#define CT_IS_VOIDCHAR_PTR 0x00001000
-#define CT_PRIMITIVE_FITS_LONG 0x00002000
-#define CT_IS_OPAQUE 0x00004000
-#define CT_IS_ENUM 0x00008000
-#define CT_IS_PTR_TO_OWNED 0x00010000 /* only owned if CDataOwning_Type */
-#define CT_CUSTOM_FIELD_POS 0x00020000
-#define CT_IS_LONGDOUBLE 0x00040000
-#define CT_IS_BOOL 0x00080000
-#define CT_IS_FILE 0x00100000
-#define CT_IS_VOID_PTR 0x00200000
-#define CT_WITH_VAR_ARRAY 0x00400000 /* with open-ended array, anywhere */
-/* unused 0x00800000 */
-#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 | \
- 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;
-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 || \
- 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;
- long double m_longdouble;
-} 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_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 {
- 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
-
-#ifdef PyUnicode_KIND /* Python >= 3.3 */
-# include "wchar_helper_3.h"
-#else
-# 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 */
- Py_SET_REFCNT(ct, 43);
- 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 */
-
-/* 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)
- "_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);
- }
- 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;
-}
-
-#ifdef __GNUC__
-/* This is a workaround for what I think is a GCC bug on several
- platforms. See issue #378. */
-__attribute__((noinline))
-#endif
-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; \
- _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;
-}
-
-static Py_complex
-read_raw_complex_data(char *target, int size)
-{
- Py_complex r = {0.0, 0.0};
- if (size == 2*sizeof(float)) {
- float real_part, imag_part;
- memcpy(&real_part, target + 0, sizeof(float));
- memcpy(&imag_part, target + sizeof(float), sizeof(float));
- r.real = real_part;
- r.imag = imag_part;
- return r;
- }
- if (size == 2*sizeof(double)) {
- memcpy(&r, target, 2*sizeof(double));
- return r;
- }
- Py_FatalError("read_raw_complex_data: bad complex 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);
-}
-
-#define _write_raw_complex_data(type) \
- do { \
- if (size == 2*sizeof(type)) { \
- type r = (type)source.real; \
- type i = (type)source.imag; \
- _cffi_memcpy(target, &r, sizeof(type)); \
- _cffi_memcpy(target+sizeof(type), &i, sizeof(type)); \
- return; \
- } \
- } while(0)
-
-static void
-write_raw_complex_data(char *target, Py_complex source, int size)
-{
- _write_raw_complex_data(float);
- _write_raw_complex_data(double);
- 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);
-
- if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) {
- if (ct->ct_flags & CT_IS_BOOL) {
- PyObject *x;
- switch ((int)value) {
- case 0: x = Py_False; break;
- case 1: x = Py_True; break;
- default:
- PyErr_Format(PyExc_ValueError,
- "got a _Bool of value %d, expected 0 or 1",
- (int)value);
- return NULL;
- }
- 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)*/
- switch (ct->ct_size) {
- case sizeof(char):
- 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;
-}
-
-static cffi_char16_t _convert_to_char16_t(PyObject *init)
-{
- char err_got[80];
- err_got[0] = 0;
-
- 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) &&
- (((CDataObject *)init)->c_type->ct_size == 2)) {
- char *data = ((CDataObject *)init)->c_data;
- /*READ(data, 2)*/
- return *(cffi_char16_t *)data;
- }
- 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];
- err_got[0] = 0;
-
- if (PyUnicode_Check(init)) {
- cffi_char32_t ordinal;
- if (_my_PyUnicode_AsSingleChar32(init, &ordinal, err_got) == 0)
- return ordinal;
- }
- if (CData_Check(init) &&
- (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) &&
- (((CDataObject *)init)->c_type->ct_size == 4)) {
- char *data = ((CDataObject *)init)->c_data;
- /*READ(data, 4)*/
- return *(cffi_char32_t *)data;
- }
- PyErr_Format(PyExc_TypeError,
- "initializer for ctype 'char32_t' must be a unicode string "
- "of length 1, not %.200s",
- err_got[0] == 0 ? Py_TYPE(init)->tp_name : err_got);
- return (cffi_char32_t)-1;
-}
-
-static int _convert_error(PyObject *init, CTypeDescrObject *ct,
- 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'",
- 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)",
- ct->ct_name, ct2->ct_name);
- }
- else
- {
- PyErr_Format(PyExc_SystemError,
- "initializer for ctype '%s' is correct, but we get "
- "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",
- 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
-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 */
- 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) {
- if (PyErr_Occurred()) {
- if (PyErr_ExceptionMatches(PyExc_TypeError))
- PyErr_Format(PyExc_TypeError,
- "expected new array length or list/tuple/str, "
- "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
-add_varsize_length(Py_ssize_t offset, Py_ssize_t itemsize,
- Py_ssize_t varsizelength, Py_ssize_t *optvarsize)
-{
- /* update '*optvarsize' to account for an array of 'varsizelength'
- elements, each of size 'itemsize', that starts at 'offset'. */
- Py_ssize_t size = ADD_WRAPAROUND(offset,
- MUL_WRAPAROUND(itemsize, varsizelength));
- if (size < 0 ||
- ((size - offset) / itemsize) != varsizelength) {
- PyErr_SetString(PyExc_OverflowError,
- "array size would overflow a Py_ssize_t");
- return -1;
- }
- if (size > *optvarsize)
- *optvarsize = size;
- return 0;
-}
-
-static int
-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) {
- 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);
- 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 (optvarsize == NULL) {
- return convert_field_from_object(data, cf, value);
- }
- else if ((cf->cf_type->ct_flags & CT_WITH_VAR_ARRAY) != 0 &&
- !CData_Check(value)) {
- Py_ssize_t subsize = cf->cf_type->ct_size;
- if (convert_struct_from_object(NULL, cf->cf_type, value, &subsize) < 0)
- return -1;
- return add_varsize_length(cf->cf_offset, 1, subsize, optvarsize);
- }
- else
- return 0;
-}
-
-static int
-must_be_array_of_zero_or_one(const char *data, Py_ssize_t n)
-{
- Py_ssize_t i;
- for (i = 0; i < n; i++) {
- if (((unsigned char)data[i]) > 1) {
- PyErr_SetString(PyExc_ValueError,
- "an array of _Bool can only contain \\x00 or \\x01");
- return -1;
- }
- }
- return 0;
-}
-
-static Py_ssize_t
-get_array_length(CDataObject *cd)
-{
- if (cd->c_type->ct_length < 0)
- return ((CDataObject_own_length *)cd)->length;
- else
- return cd->c_type->ct_length;
-}
-
-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);
- 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;
- }
-
- 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 (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:
- if ((ct->ct_flags & CT_ARRAY) && CData_Check(init))
- {
- CDataObject *cd = (CDataObject *)init;
- if (cd->c_type == ct)
- {
- Py_ssize_t n = get_array_length(cd);
- memcpy(data, cd->c_data, n * ctitem->ct_size);
- return 0;
- }
- }
- return _convert_error(init, ct, expected);
-}
-
-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";
- 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
- 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)");
- 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;
- if (ct->ct_flags & CT_IS_BOOL) {
- if (value > 1ULL) /* value != 0 && value != 1 */
- 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) {
- switch (ct->ct_size) {
- case sizeof(char): {
- 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;
- *(cffi_char16_t *)data = res;
- return 0;
- }
- case 4: {
- cffi_char32_t res = _convert_to_char32_t(init);
- if (res == (cffi_char32_t)-1 && PyErr_Occurred())
- return -1;
- *(cffi_char32_t *)data = res;
- 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_PRIMITIVE_COMPLEX) {
- Py_complex value = PyComplex_AsCComplex(init);
- if (PyErr_Occurred())
- return -1;
- 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:
- 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) {
- /* 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 */
- ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
- 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);
-}
-
-static void cdatafrombuf_dealloc(CDataObject *cd)
-{
- Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
- cdata_dealloc(cd);
-
- PyBuffer_Release(view);
- 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 */
- ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
- 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;
- Py_VISIT(view->obj);
- 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 */
- ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
- 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;
- PyBuffer_Release(view);
- return 0;
-}
-
-/* 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 {
- PyObject *t, *v, *tb;
- PyErr_Fetch(&t, &v, &tb);
- /* Don't use error capture here, because it is very much
- * like errors at __del__(), and these ones are not captured
- * either */
- /* ecap = _cffi_start_error_capture(); */
- _my_PyErr_WriteUnraisable(t, v, tb, "From callback for ffi.gc ",
- 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;
-}
-
-static PyObject *_frombuf_repr(CDataObject *cd, const char *cd_type_name)
-{
- Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
- const char *obj_tp_name;
- if (view->obj == NULL) {
- return PyText_FromFormat(
- "<cdata '%s' buffer RELEASED>",
- cd_type_name);
- }
-
- obj_tp_name = Py_TYPE(view->obj)->tp_name;
- if (cd->c_type->ct_flags & CT_ARRAY)
- {
- Py_ssize_t buflen = get_array_length(cd);
- return PyText_FromFormat(
- "<cdata '%s' buffer len %zd from '%.200s' object>",
- cd_type_name,
- buflen,
- obj_tp_name);
- }
- else
- {
- return PyText_FromFormat(
- "<cdata '%s' buffer from '%.200s' object>",
- cd_type_name,
- obj_tp_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 */
- 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));
- }
- 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;
- }
- 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)) {
- 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)*/
- switch (cd->c_type->ct_size) {
- case sizeof(char):
- return PyInt_FromLong((unsigned char)cd->c_data[0]);
- case 2:
- return PyInt_FromLong((long)*(cffi_char16_t *)cd->c_data);
- case 4:
- if (cd->c_type->ct_flags & CT_IS_SIGNED_WCHAR)
- return PyInt_FromLong((long)*(int32_t *)cd->c_data);
- else if (sizeof(long) > 4)
- return PyInt_FromLong(*(uint32_t *)cd->c_data);
- 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)
-{
- int v_is_ptr, w_is_ptr;
- PyObject *pyres;
-
- assert(CData_Check(v));
-
- /* Comparisons involving a primitive cdata work differently than
- * comparisons involving a struct/array/pointer.
- *
- * If v or w is a struct/array/pointer, then the other must be too
- * (otherwise we return NotImplemented and leave the case to
- * Python). If both are, then we compare the addresses.
- *
- * If v and/or w is a primitive cdata, then we convert the cdata(s)
- * to regular Python objects and redo the comparison there.
- */
-
- v_is_ptr = !(((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY);
- w_is_ptr = CData_Check(w) &&
- !(((CDataObject *)w)->c_type->ct_flags & CT_PRIMITIVE_ANY);
-
- if (v_is_ptr && w_is_ptr) {
- int res;
- char *v_cdata = ((CDataObject *)v)->c_data;
- char *w_cdata = ((CDataObject *)w)->c_data;
-
- switch (op) {
- case Py_EQ: res = (v_cdata == w_cdata); break;
- case Py_NE: res = (v_cdata != w_cdata); break;
- case Py_LT: res = (v_cdata < w_cdata); break;
- case Py_LE: res = (v_cdata <= w_cdata); break;
- case Py_GT: res = (v_cdata > w_cdata); break;
- case Py_GE: res = (v_cdata >= w_cdata); break;
- default: res = -1;
- }
- pyres = res ? Py_True : Py_False;
- }
- else if (v_is_ptr || w_is_ptr) {
- 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))
- continue;
- w = convert_to_object(((CDataObject *)v)->c_data,
- ((CDataObject *)v)->c_type);
- if (w == NULL)
- goto error;
- if (CData_Check(w)) {
- Py_DECREF(w);
- PyErr_Format(PyExc_NotImplementedError,
- "cannot use <cdata '%s'> in a comparison",
- ((CDataObject *)v)->c_type->ct_name);
- goto error;
- }
- aa[i] = w;
- Py_DECREF(v);
- }
- pyres = PyObject_RichCompare(aa[0], aa[1], op);
- error:
- Py_DECREF(aa[1]);
- Py_DECREF(aa[0]);
- 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);
- if (vv == NULL)
- return -1;
- if (!CData_Check(vv)) {
- Py_hash_t hash = PyObject_Hash(vv);
- Py_DECREF(vv);
- return hash;
- }
- 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,
- "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,
- "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);
-}
-
-static void
-_cdata_attr_errmsg(char *errmsg, CDataObject *cd, PyObject *attr)
-{
- const char *text;
- if (!PyErr_ExceptionMatches(PyExc_AttributeError))
- return;
- PyErr_Clear();
- text = PyText_AsUTF8(attr);
- if (text == NULL)
- return;
- 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;
- 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);
- }
- errmsg = "cdata '%s' has no field '%s'";
- break;
- case -1:
- return NULL;
- default:
- errmsg = "cdata '%s' points to an opaque type: cannot read fields";
- 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;
- 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;
- }
- }
- errmsg = "cdata '%s' has no field '%s'";
- break;
- case -1:
- return -1;
- default:
- errmsg = "cdata '%s' points to an opaque type: cannot write fields";
- 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 *
-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);
- 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 */
- 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;
- 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_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
- 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 (datasize <= 512) {
- tmpbuf = alloca(datasize);
- }
- else {
- struct freeme_s *fp = (struct freeme_s *)PyObject_Malloc(
- offsetof(struct freeme_s, alignment) +
- (size_t)datasize);
- if (fp == NULL) {
- PyErr_NoMemory();
- goto error;
- }
- fp->next = freeme;
- 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:
- 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 */
- }
-}
-
-static PyObject *cdata_complex(PyObject *cd_, PyObject *noarg)
-{
- CDataObject *cd = (CDataObject *)cd_;
-
- if (cd->c_type->ct_flags & CT_PRIMITIVE_COMPLEX) {
- Py_complex value = read_raw_complex_data(cd->c_data, cd->c_type->ct_size);
- PyObject *op = PyComplex_FromCComplex(value);
- return op;
- }
- /* <cdata 'float'> or <cdata 'int'> cannot be directly converted by
- calling complex(), just like <cdata 'int'> cannot be directly
- converted by calling float() */
-
- PyErr_Format(PyExc_TypeError, "complex() not supported on cdata '%s'",
- cd->c_type->ct_name);
- return NULL;
-}
-
-static int explicit_release_case(PyObject *cd)
-{
- CTypeDescrObject *ct = ((CDataObject *)cd)->c_type;
- if (Py_TYPE(cd) == &CDataOwning_Type) {
- if ((ct->ct_flags & (CT_POINTER | CT_ARRAY)) != 0) /* ffi.new() */
- return 0;
- }
- else if (Py_TYPE(cd) == &CDataFromBuf_Type) {
- return 1; /* ffi.from_buffer() */
- }
- else if (Py_TYPE(cd) == &CDataGCP_Type) {
- return 2; /* ffi.gc() */
- }
- PyErr_SetString(PyExc_ValueError,
- "only 'cdata' object from ffi.new(), ffi.gc(), ffi.from_buffer() "
- "or ffi.new_allocator()() can be used with the 'with' keyword or "
- "ffi.release()");
- return -1;
-}
-
-static PyObject *cdata_enter(PyObject *cd, PyObject *noarg)
-{
- if (explicit_release_case(cd) < 0) /* only to check the ctype */
- return NULL;
- Py_INCREF(cd);
- return cd;
-}
-
-static PyObject *cdata_exit(PyObject *cd, PyObject *args)
-{
- /* 'args' ignored */
- CTypeDescrObject *ct;
- Py_buffer *view;
- switch (explicit_release_case(cd))
- {
- case 0: /* ffi.new() */
- /* no effect on CPython: raw memory is allocated with the
- same malloc() as the object itself, so it can't be
- released independently. If we use a custom allocator,
- then it's implemented with ffi.gc(). */
- ct = ((CDataObject *)cd)->c_type;
- if (ct->ct_flags & CT_IS_PTR_TO_OWNED) {
- PyObject *x = ((CDataObject_own_structptr *)cd)->structobj;
- if (Py_TYPE(x) == &CDataGCP_Type) {
- /* this is a special case for
- ffi.new_allocator()("struct-or-union *") */
- cdatagcp_finalize((CDataObject_gcp *)x);
- }
- }
- break;
-
- case 1: /* ffi.from_buffer() */
- view = ((CDataObject_frombuf *)cd)->bufferview;
- PyBuffer_Release(view);
- break;
-
- case 2: /* ffi.gc() or ffi.new_allocator()("not-struct-nor-union") */
- /* call the destructor immediately */
- cdatagcp_finalize((CDataObject_gcp *)cd);
- break;
-
- default:
- return NULL;
- }
- Py_INCREF(Py_None);
- 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[] = {
- {"__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)
- "_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 */
- 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 */
- "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_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- PyObject_Del, /* tp_free */
-};
-
-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 */
- 0, /* inherited */ /* tp_as_number */
- 0, /* tp_as_sequence */
- &CDataOwn_as_mapping, /* tp_as_mapping */
- 0, /* inherited */ /* tp_hash */
- 0, /* inherited */ /* tp_call */
- 0, /* tp_str */
- 0, /* inherited */ /* tp_getattro */
- 0, /* inherited */ /* tp_setattro */
- 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, /* inherited */ /* tp_richcompare */
- 0, /* inherited */ /* tp_weaklistoffset */
- 0, /* inherited */ /* tp_iter */
- 0, /* tp_iternext */
- 0, /* inherited */ /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &CData_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- free, /* tp_free */
-};
-
-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, /* inherited */ /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* inherited */ /* tp_as_mapping */
- 0, /* inherited */ /* tp_hash */
- 0, /* inherited */ /* tp_call */
- 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,
- "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 */
- 0, /* inherited */ /* tp_richcompare */
- 0, /* inherited */ /* tp_weaklistoffset */
- 0, /* inherited */ /* tp_iter */
- 0, /* tp_iternext */
- 0, /* inherited */ /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &CDataOwning_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- PyObject_GC_Del, /* tp_free */
-};
-
-static PyTypeObject CDataFromBuf_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.__CDataFromBuf",
- sizeof(CDataObject_frombuf),
- 0,
- (destructor)cdatafrombuf_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- (reprfunc)cdatafrombuf_repr, /* tp_repr */
- 0, /* inherited */ /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* inherited */ /* tp_as_mapping */
- 0, /* inherited */ /* tp_hash */
- 0, /* inherited */ /* tp_call */
- 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,
- "This is an internal subtype of _CDataBase for performance only on "
- "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */
- (traverseproc)cdatafrombuf_traverse, /* tp_traverse */
- (inquiry)cdatafrombuf_clear, /* tp_clear */
- 0, /* inherited */ /* tp_richcompare */
- 0, /* inherited */ /* tp_weaklistoffset */
- 0, /* inherited */ /* tp_iter */
- 0, /* tp_iternext */
- 0, /* inherited */ /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &CData_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- PyObject_GC_Del, /* tp_free */
-};
-
-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 */
- 0, /* inherited */ /* tp_repr */
- 0, /* inherited */ /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* inherited */ /* tp_as_mapping */
- 0, /* inherited */ /* tp_hash */
- 0, /* inherited */ /* tp_call */
- 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,
- "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 */
- 0, /* inherited */ /* tp_richcompare */
- 0, /* inherited */ /* tp_weaklistoffset */
- 0, /* inherited */ /* tp_iter */
- 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, /* 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)
- "_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,
- 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;
- 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;
- }
- 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) {
- 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 (!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) {
- 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;
-
- 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)) {
- char err_buf[80];
- cffi_char32_t ordinal;
- if (_my_PyUnicode_AsSingleChar32(ob, &ordinal, err_buf) < 0) {
- PyErr_Format(PyExc_TypeError,
- "cannot cast %s to ctype '%s'", err_buf, ct->ct_name);
- 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. */
-#ifdef HAVE_WCHAR_H
- if (ct->ct_flags & CT_IS_SIGNED_WCHAR)
- value = (wchar_t)ordinal;
- 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;
-}
-
-/* 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)
-{
- if (PyBytes_Check(io)) {
- if (PyBytes_GET_SIZE(io) != 1)
- goto error;
- *out_value = (unsigned char)PyBytes_AS_STRING(io)[0];
- return 1;
- }
- else if (PyUnicode_Check(io)) {
- char ignored[80];
- cffi_char32_t ordinal;
- if (_my_PyUnicode_AsSingleChar32(io, &ordinal, ignored) < 0)
- goto error;
- /* the signness of the 32-bit version of wide chars should not
- * matter here, because 'ordinal' comes from a normal Python
- * unicode string */
- *out_value = ordinal;
- return 1;
- }
- *out_value = 0; /* silence a gcc warning if this function is inlined */
- return 0;
-
- error:
- Py_DECREF(io);
- *out_value = 0; /* silence a gcc warning if this function is inlined */
- 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;
- 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);
- }
-
- res = check_bytes_for_float_compatible(io, &value);
- if (res == -1)
- goto cannot_cast;
- if (res == 0) {
- if ((ct->ct_flags & CT_IS_LONGDOUBLE) &&
- CData_Check(io) &&
- (((CDataObject *)io)->c_type->ct_flags & CT_IS_LONGDOUBLE)) {
- long double lvalue;
- char *data = ((CDataObject *)io)->c_data;
- /*READ(data, sizeof(long double)*/
- lvalue = read_raw_longdouble_data(data);
- 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;
- }
- else if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) {
- /* cast to a complex */
- Py_complex 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);
- }
-
- res = check_bytes_for_float_compatible(io, &value.real);
- if (res == -1)
- goto cannot_cast;
- if (res == 1) {
- // got it from string
- value.imag = 0.0;
- } else {
- value = PyComplex_AsCComplex(io);
- }
- Py_DECREF(io);
- if (PyErr_Occurred()) {
- return NULL;
- }
- cd = _new_casted_primitive(ct);
- if (cd != NULL) {
- write_raw_complex_data(cd->c_data, value, ct->ct_size);
- }
- 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;
- int dl_auto_close;
-} 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);
-}
-
-static int dl_check_closed(DynLibObject *dlobj)
-{
- if (dlobj->dl_handle == NULL)
- {
- PyErr_Format(PyExc_ValueError, "library '%s' has already been closed",
- dlobj->dl_name);
- return -1;
- }
- 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;
-
- 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();
- PyErr_Format(PyExc_AttributeError,
- "function/symbol '%s' not found in library '%s': %s",
- 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;
-
- 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;
-
- 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;
-}
-
-static PyObject *dl_close_lib(DynLibObject *dlobj, PyObject *no_args)
-{
- if (dlobj->dl_handle != NULL)
- {
- dlclose(dlobj->dl_handle);
- dlobj->dl_handle = NULL;
- }
- Py_INCREF(Py_None);
- 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},
- {"close_lib", (PyCFunction)dl_close_lib, METH_NOARGS},
- {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 */
-};
-
-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;
- char *filename_or_null;
- 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;
- *p_printable_filename = "<None>";
- }
- else if (CData_Check(PyTuple_GET_ITEM(args, 0)))
- {
- CDataObject *cd;
- if (!PyArg_ParseTuple(args, "O|i:load_library", &cd, &flags))
- return NULL;
- /* 'flags' is accepted but ignored in this case */
- if ((cd->c_type->ct_flags & CT_IS_VOID_PTR) == 0) {
- PyErr_Format(PyExc_TypeError,
- "dlopen() takes a file name or 'void *' handle, not '%s'",
- cd->c_type->ct_name);
- return NULL;
- }
- handle = cd->c_data;
- if (handle == NULL) {
- PyErr_Format(PyExc_RuntimeError, "cannot call dlopen(NULL)");
- return NULL;
- }
- *p_temp = PyText_FromFormat("%p", handle);
- *p_printable_filename = PyText_AsUTF8(*p_temp);
- *auto_close = 0;
- return handle;
- }
- else
- {
- PyObject *s = PyTuple_GET_ITEM(args, 0);
-#ifdef MS_WIN32
- PyObject *filename_unicode;
- if (PyArg_ParseTuple(args, "U|i:load_library", &filename_unicode, &flags))
- {
- Py_ssize_t sz1;
- wchar_t *w1;
-#if PY_MAJOR_VERSION < 3
- s = PyUnicode_AsUTF8String(s);
- if (s == NULL)
- return NULL;
- *p_temp = s;
-#endif
- *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);
- sz1 = PyUnicode_AsWideChar((PyUnicodeObject *)filename_unicode,
- w1, sz1 - 1);
- if (sz1 < 0)
- return NULL;
- w1[sz1] = 0;
- handle = dlopenW(w1);
- goto got_handle;
- }
- PyErr_Clear();
-#endif
- if (!PyArg_ParseTuple(args, "et|i:load_library",
- Py_FileSystemDefaultEncoding, &filename_or_null, &flags))
- return NULL;
-#if PY_MAJOR_VERSION < 3
- if (PyUnicode_Check(s))
- {
- s = PyUnicode_AsUTF8String(s);
- if (s == NULL) {
- PyMem_Free(filename_or_null);
- return NULL;
- }
- *p_temp = s;
- }
-#endif
- *p_printable_filename = PyText_AsUTF8(s);
- if (*p_printable_filename == NULL) {
- PyMem_Free(filename_or_null);
- return NULL;
- }
- }
- 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");
- return NULL;
- }
-#endif
-
- handle = dlopen(filename_or_null, flags);
- PyMem_Free(filename_or_null);
-
-#ifdef MS_WIN32
- got_handle:
-#endif
- if (handle == NULL) {
- const char *error = dlerror();
- PyErr_Format(PyExc_OSError, "cannot load library '%s': %s",
- *p_printable_filename, error);
- return NULL;
- }
- return handle;
-}
-
-static PyObject *b_load_library(PyObject *self, PyObject *args)
-{
- const char *printable_filename;
- PyObject *temp;
- void *handle;
- DynLibObject *dlobj = NULL;
- int auto_close;
-
- handle = b_do_dlopen(args, &printable_filename, &temp, &auto_close);
- if (handle == NULL)
- goto error;
-
- 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_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() */
- /* 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;
-}
-
-/* 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 ) \
- 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 \
- 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(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 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
- or ffi_type_complex_double. Better not use it at all.
- */
- 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
-
-#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
-# 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)."
- " 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;
-}
-
-#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;
- 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;
- int pack = 0;
-
- if (!PyArg_ParseTuple(args, "O!O!|Oniii:complete_struct_or_union",
- &CTypeDescr_Type, &ct,
- &PyList_Type, &fields,
- &ignored, &totalsize, &totalalignment, &sflags,
- &pack))
- 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;
- }
- ct->ct_flags &= ~(CT_CUSTOM_FIELD_POS | CT_WITH_PACKED_CHANGE);
-
- 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;
- 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;
- }
- }
- 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
- CT_WITH_VAR_ARRAY to any struct that contains either an open-
- ended array or another struct that recursively contains an
- open-ended array. */
- if (ftype->ct_flags & CT_WITH_VAR_ARRAY)
- ct->ct_flags |= CT_WITH_VAR_ARRAY;
- }
-
- 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 */
- falignorg = get_alignment(ftype);
- if (falignorg < 0)
- 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 */
-
- /* first, pad to the next byte,
- * then pad to 'falign' or 'falignorg' bytes */
- byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset);
- bitoffset = 0;
- byteoffsetorg = (byteoffset + falignorg-1) & ~(falignorg-1);
- byteoffset = (byteoffset + falign-1) & ~(falign-1);
-
- if (byteoffsetorg != byteoffset) {
- 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 (detect_custom_layout(ct, sflags, byteoffset, foffset,
- "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,
- 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,
- byteoffset, bs_flag, -1, fflags);
- 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 */
- 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;" */
-
- /* pad byteoffset to a value aligned for "ftype" */
- if (ROUNDUP_BYTES(byteoffset, bitoffset) > field_offset_bytes) {
- 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. */
- 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;
- assert(byteoffset < field_offset_bytes);
- byteoffset = field_offset_bytes;
- bitoffset = 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 */
- 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;
- field_offset_bytes = byteoffset - ftype->ct_size;
- }
- 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);
- 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. */
- 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 (totalsize < byteoffsetmax) {
- 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;
- }
-}
-
-#define SUPPORTED_IN_API_MODE \
- " are only supported as %s if the function is " \
- "'API mode' and non-variadic (i.e. declared inside ffibuilder" \
- ".cdef()+ffibuilder.set_source() and not taking a final '...' " \
- "argument)"
-
-static ffi_type *fb_unsupported(CTypeDescrObject *ct, const char *place,
- const char *detail)
-{
- PyErr_Format(PyExc_NotImplementedError,
- "ctype '%s' not supported as %s. %s. "
- "Such structs" SUPPORTED_IN_API_MODE,
- ct->ct_name, place, detail, 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";
-
- 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
- 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 */
- 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) {
- return fb_unsupported(ct, place,
- "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) {
- 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) {
- 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;
- }
- else if (ct->ct_flags & CT_UNION) {
- PyErr_Format(PyExc_NotImplementedError,
- "ctype '%s' not supported as %s by libffi. "
- "Unions" SUPPORTED_IN_API_MODE,
- ct->ct_name, place, place);
- return NULL;
- }
- else {
- char *extra = "";
- if (ct->ct_flags & CT_PRIMITIVE_COMPLEX)
- extra = " (the support for complex types inside libffi "
- "is mostly missing at this point, so CFFI only "
- "supports complex types as arguments or return "
- "value in API-mode functions)";
-
- 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,
- Py_ssize_t variadic_nargs_declared,
- ffi_abi fabi)
-
-{
- 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;
-
- /* use `ffi_prep_cif_var` if necessary and available */
-#if CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE
- if (variadic_nargs_declared >= 0) {
- if (CFFI_CHECK_FFI_PREP_CIF_VAR) {
- status = ffi_prep_cif_var(&cif_descr->cif, fabi,
- variadic_nargs_declared, funcbuffer.nargs,
- funcbuffer.rtype, funcbuffer.atypes);
- }
- }
-#endif
-
- if (status == (ffi_status)-1) {
- status = ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs,
- funcbuffer.rtype, funcbuffer.atypes);
- }
-
- 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;
-
- 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 |
- CT_PRIMITIVE_UNSIGNED |
- CT_POINTER | CT_FUNCTIONPTR)) {
- /* 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);
-}
-
-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 */
-#ifdef USE_WRITEUNRAISABLEMSG
-
- /* PyErr_WriteUnraisable actually writes the full traceback anyway
- from Python 3.4, but we can't really get the formatting of the
- custom text to be what we want. We can do better from Python
- 3.8 by calling the new _PyErr_WriteUnraisableMsg().
- Luckily it's also Python 3.8 that adds new functionality that
- people might want: the new sys.unraisablehook().
- */
- PyObject *s;
- int first_char;
- assert(objdescr != NULL && objdescr[0] != 0); /* non-empty */
- first_char = objdescr[0];
- if (first_char >= 'A' && first_char <= 'Z')
- first_char += 'a' - 'A'; /* lower() the very first character */
- if (extra_error_line == NULL)
- extra_error_line = "";
-
- if (obj != NULL)
- s = PyUnicode_FromFormat("%c%s%R%s",
- first_char, objdescr + 1, obj, extra_error_line);
- else
- s = PyUnicode_FromFormat("%c%s%s",
- first_char, objdescr + 1, extra_error_line);
-
- PyErr_Restore(t, v, tb);
- if (s != NULL) {
- _PyErr_WriteUnraisableMsg(PyText_AS_UTF8(s), NULL);
- Py_DECREF(s);
- }
- else
- PyErr_WriteUnraisable(obj); /* best effort */
- PyErr_Clear();
-
-#else
-
- /* 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);
-
-#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) {
-#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";
-#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) {
- 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);
- _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... */
- PyObject *ecap;
- PyErr_Fetch(&exc2, &val2, &tb2);
- ecap = _cffi_start_error_capture();
- _my_PyErr_WriteUnraisable(exc1, val1, tb1,
- "From cffi callback ", py_ob,
- 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");
- _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);
-
-#if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000
- /* 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;
-}
-
-/* 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
- support it inside a function. */
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#elif defined(__GNUC__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-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;
- 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 CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE
- if (CFFI_CHECK_FFI_CLOSURE_ALLOC) {
- closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec);
- } else
-#endif
- {
- closure = cffi_closure_alloc();
- closure_exec = closure;
- }
-
- if (closure == NULL) {
- Py_DECREF(infotuple);
- PyErr_SetString(PyExc_MemoryError,
- "Cannot allocate write+execute memory for ffi.callback(). "
- "You might be running on a system that prevents this. "
- "For more information, see "
- "https://cffi.readthedocs.io/en/latest/using.html#callbacks");
- return NULL;
- }
- cd = PyObject_GC_New(CDataObject_closure, &CDataOwningGC_Type);
- 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;
- }
-
-#if CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE
- if (CFFI_CHECK_FFI_PREP_CLOSURE_LOC) {
- status = ffi_prep_closure_loc(closure, &cif_descr->cif,
- invoke_callback, infotuple, closure_exec);
- }
- else
-#endif
- {
-#if defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE) && !FFI_LEGACY_CLOSURE_API
- PyErr_Format(PyExc_SystemError, "ffi_prep_closure_loc() is missing");
- goto error;
-#else
- status = ffi_prep_closure(closure, &cif_descr->cif,
- invoke_callback, infotuple);
-#endif
- }
-
- 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;
- }
- PyObject_GC_Track(cd);
- return (PyObject *)cd;
-
- error:
- closure->user_data = NULL;
- if (cd == NULL) {
-#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_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)) {
- 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 |
- 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) {
- switch (cd->c_type->ct_itemdescr->ct_size) {
- case 2: {
- const cffi_char16_t *start = (cffi_char16_t *)cd->c_data;
- if (length < 0) {
- /*READ(start, 2)*/
- length = 0;
- while (start[length])
- length++;
- /*READ(start, 2 * length)*/
- }
- else {
- /*READ(start, 2 * length)*/
- maxlen = length;
- length = 0;
- while (length < maxlen && start[length])
- length++;
- }
- return _my_PyUnicode_FromChar16(start, length);
- }
- case 4: {
- const cffi_char32_t *start = (cffi_char32_t *)cd->c_data;
- if (length < 0) {
- /*READ(start, 4)*/
- length = 0;
- while (start[length])
- length++;
- /*READ(start, 4 * length)*/
- }
- else {
- /*READ(start, 4 * length)*/
- maxlen = length;
- length = 0;
- while (length < maxlen && start[length])
- 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) {
- 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) {
- switch (ctitem->ct_size) {
- case sizeof(char):
- 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) {
- 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'. */
- 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;
- case 11:
- switch (*(unsigned char *)src) {
- case 0: x = Py_False; Py_INCREF(x); break;
- case 1: x = Py_True; Py_INCREF(x); break;
- 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;
-}
-
-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;
- 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;
-}
-
-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,
- "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;
- }
- if (_my_PyObject_GetContiguousBuffer(x, view, require_writable) < 0)
- goto error1;
-
- if (ct->ct_flags & CT_POINTER)
- {
- arraylength = view->len; /* number of bytes, not used so far */
- }
- else {
- /* ct->ct_flags & CT_ARRAY */
- if (ct->ct_length >= 0) {
- /* it's an array with a fixed length; make sure that the
- buffer contains enough bytes. */
- minimumlength = ct->ct_size;
- arraylength = ct->ct_length;
- }
- else {
- /* it's an open 'array[]' */
- if (ct->ct_itemdescr->ct_size == 1) {
- /* fast path, performance only */
- arraylength = view->len;
- }
- else if (ct->ct_itemdescr->ct_size > 0) {
- /* give it as many items as fit the buffer. Ignore a
- partial last element. */
- arraylength = view->len / ct->ct_itemdescr->ct_size;
- }
- else {
- /* it's an array 'empty[]'. Unsupported obscure case:
- the problem is that setting the length of the result
- to anything large (like SSIZE_T_MAX) is dangerous,
- because if someone tries to loop over it, it will
- turn effectively into an infinite loop. */
- PyErr_Format(PyExc_ZeroDivisionError,
- "from_buffer('%s', ..): the actual length of the array "
- "cannot be computed", ct->ct_name);
- goto error2;
- }
- }
- }
- if (view->len < minimumlength) {
- PyErr_Format(PyExc_ValueError,
- "buffer is too small (%zd bytes) for '%s' (%zd bytes)",
- view->len, ct->ct_name, minimumlength);
- goto error2;
- }
-
- 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;
- ((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;
- int require_writable = 0;
-
- if (!PyArg_ParseTuple(args, "O!O|i", &CTypeDescr_Type, &ct, &x,
- &require_writable))
- 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;
- 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;
-}
-
-static PyObject *b_release(PyObject *self, PyObject *arg)
-{
- if (!CData_Check(arg)) {
- PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object");
- return NULL;
- }
- 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;
-}
-
-#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
- * arguments in addition to return values. */
-static float _Complex _testfunc24(float a, float b)
-{
- return a + I*2.0*b;
-}
-static double _Complex _testfunc25(double a, double b)
-{
- return a + I*2.0*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;
-#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},
- {"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);
-}
-
-/* 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
-typedef wchar_t cffi_wchar_t;
-#else
-typedef uint16_t cffi_wchar_t; /* random pick... */
-#endif
-
-static cffi_wchar_t _cffi_to_c_wchar_t(PyObject *init)
-{
- if (sizeof(cffi_wchar_t) == 2)
- return (cffi_wchar_t)_convert_to_char16_t(init);
- else
- return (cffi_wchar_t)_convert_to_char32_t(init);
-}
-static PyObject *_cffi_from_c_wchar_t(cffi_wchar_t x) {
- if (sizeof(cffi_wchar_t) == 2) {
- cffi_char16_t input = x;
- return _my_PyUnicode_FromChar16(&input, 1);
- }
- else {
- cffi_char32_t input = x;
- return _my_PyUnicode_FromChar32(&input, 1);
- }
-}
-static int _cffi_to_c_wchar3216_t(PyObject *init)
-{
- if (sizeof(cffi_wchar_t) == 4)
- return (int)_convert_to_char16_t(init);
- else
- return (int)_convert_to_char32_t(init);
-}
-static PyObject *_cffi_from_c_wchar3216_t(int x) {
- if (sizeof(cffi_wchar_t) == 4) {
- cffi_char16_t input = x;
- return _my_PyUnicode_FromChar16(&input, 1);
- }
- else {
- cffi_char32_t input = x;
- return _my_PyUnicode_FromChar32(&input, 1);
- }
-}
-
-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_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 PyTypeObject *all_types[] = {
- &dl_type,
- &CTypeDescr_Type,
- &CField_Type,
- &CData_Type,
- &CDataOwning_Type,
- &CDataOwningGC_Type,
- &CDataFromBuf_Type,
- &CDataGCP_Type,
- &CDataIter_Type,
- &MiniBuffer_Type,
- &FFI_Type,
- &Lib_Type,
- &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;
- }
-
- /* readify all types and add them to the module */
- for (i = 0; all_types[i] != NULL; i++) {
- PyTypeObject *tp = all_types[i];
- PyObject *tpo = (PyObject *)tp;
- if (strncmp(tp->tp_name, "_cffi_backend.", 14) != 0) {
- PyErr_Format(PyExc_ImportError,
- "'%s' is an ill-formed type name", tp->tp_name);
- INITERROR;
- }
- 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;
- 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
-}
diff --git a/c/_cffi_backend.so b/c/_cffi_backend.so
deleted file mode 100755
index 31f7528..0000000
--- a/c/_cffi_backend.so
+++ /dev/null
Binary files differ
diff --git a/c/_dummy_file_cffi_backend.py b/c/_dummy_file_cffi_backend.py
deleted file mode 100644
index e69de29..0000000
--- a/c/_dummy_file_cffi_backend.py
+++ /dev/null
diff --git a/c/_dummy_file_libffi.py b/c/_dummy_file_libffi.py
deleted file mode 100644
index e69de29..0000000
--- a/c/_dummy_file_libffi.py
+++ /dev/null
diff --git a/c/call_python.c b/c/call_python.c
deleted file mode 100644
index d3d2e17..0000000
--- a/c/call_python.c
+++ /dev/null
@@ -1,292 +0,0 @@
-#if PY_VERSION_HEX >= 0x03080000
-# define HAVE_PYINTERPSTATE_GETDICT
-#endif
-
-
-static PyObject *_current_interp_key(void)
-{
- PyInterpreterState *interp = PyThreadState_GET()->interp;
-#ifdef HAVE_PYINTERPSTATE_GETDICT
- return PyInterpreterState_GetDict(interp); /* shared reference */
-#else
- return interp->modules;
-#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;
- PyObject *d, *interpdict;
- int err;
- PyInterpreterState *interp;
-
- tstate = PyThreadState_GET();
- if (tstate == NULL) {
- /* no thread state! */
- return NULL;
- }
-
- interp = tstate->interp;
-#ifdef HAVE_PYINTERPSTATE_GETDICT
- interpdict = PyInterpreterState_GetDict(interp); /* shared reference */
-#else
- 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;
- }
-
- d = PyDict_GetItem(interpdict, attr_name);
- 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)
-{
- 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 */
-
- 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))
-# if defined(HAVE_SYNC_SYNCHRONIZE)
-# define read_barrier() __sync_synchronize()
-# elif defined(_AIX)
-# define read_barrier() __lwsync()
-# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-# include <mbarrier.h>
-# define read_barrier() __compiler_barrier()
-# elif defined(__hpux)
-# define read_barrier() _Asm_mf()
-# else
-# define read_barrier() /* missing */
-# 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
- _update_cache_to_call_python(), but to avoid the extra dict
- 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 != _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();
-}
diff --git a/c/cdlopen.c b/c/cdlopen.c
deleted file mode 100644
index 0ed319b..0000000
--- a/c/cdlopen.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/* 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)
-{
- const char *modname;
- PyObject *temp, *result = NULL;
- 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;
- 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;
-}
diff --git a/c/cffi1_module.c b/c/cffi1_module.c
deleted file mode 100644
index 06a84fe..0000000
--- a/c/cffi1_module.c
+++ /dev/null
@@ -1,216 +0,0 @@
-
-#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;
- 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;
- 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;
-
- 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;
-}
diff --git a/c/cglob.c b/c/cglob.c
deleted file mode 100644
index e97767c..0000000
--- a/c/cglob.c
+++ /dev/null
@@ -1,113 +0,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;
-}
diff --git a/c/commontypes.c b/c/commontypes.c
deleted file mode 100644
index a41c2fd..0000000
--- a/c/commontypes.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/* 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/c/ffi_obj.c b/c/ffi_obj.c
deleted file mode 100644
index f154146..0000000
--- a/c/ffi_obj.c
+++ /dev/null
@@ -1,1221 +0,0 @@
-
-/* 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
-
-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) {
- 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.");
-
-static PyObject *ffi_from_buffer(FFIObject *self, PyObject *args,
- PyObject *kwds)
-{
- PyObject *cdecl1, *python_buf = NULL;
- CTypeDescrObject *ct;
- int require_writable = 0;
- static char *keywords[] = {"cdecl", "python_buffer",
- "require_writable", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oi:from_buffer", keywords,
- &cdecl1, &python_buf, &require_writable))
- return NULL;
-
- if (python_buf == NULL) {
- python_buf = cdecl1;
- ct = g_ct_chararray;
- }
- else {
- ct = _ffi_type(self, cdecl1, ACCEPT_STRING|ACCEPT_CTYPE);
- if (ct == NULL)
- 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"
-"'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;
- }
- Py_XDECREF(tup);
- }
- }
-
- 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"
-"afterwards.\n"
-"\n"
-"'ffi.release(cdata)' is equivalent to 'cdata.__exit__()'.\n"
-"\n"
-"Note that on CPython this method has no effect (so far) on objects\n"
-"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},
- {"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},
- {"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)
- "_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 */
-}
diff --git a/c/file_emulator.h b/c/file_emulator.h
deleted file mode 100644
index 82a34c0..0000000
--- a/c/file_emulator.h
+++ /dev/null
@@ -1,93 +0,0 @@
-
-/* 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;
-}
diff --git a/c/lib_obj.c b/c/lib_obj.c
deleted file mode 100644
index 38bf3d5..0000000
--- a/c/lib_obj.c
+++ /dev/null
@@ -1,716 +0,0 @@
-
-/* 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 void *cdlopen_fetch(PyObject *libname, void *libhandle,
- const char *symbol);
-
-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";
- 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;
-
- /* 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
- C function in a CFFI C extension module. That means that this
- PyMem_Malloc() could also have been written with a static
- 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;
- 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 {
- /* 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
- non-integer C constant in a CFFI C extension module. That
- means that this PyMem_Malloc() could also have been written
- with a static global variable generated for each OP_CONSTANT
- defined in the C extension, and the effect would be the same
- (but a bit more complicated).
-
- Note that we used to do alloca(), but see issue #198. We
- could still do alloca(), or explicit PyMem_Free(), in some
- 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)
-{
- 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:
- /*** 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));
- }
-#if PY_MAJOR_VERSION >= 3
- if (strcmp(p, "__loader__") == 0 || strcmp(p, "__spec__") == 0) {
- /* some more module-like behavior hacks */
- PyErr_Clear();
- Py_INCREF(Py_None);
- 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)
- "_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 */
-};
-
-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;
- lib->l_auto_close = auto_close;
- 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;
-}
diff --git a/c/libffi_arm64/README b/c/libffi_arm64/README
deleted file mode 100644
index 3b8f133..0000000
--- a/c/libffi_arm64/README
+++ /dev/null
@@ -1,5 +0,0 @@
-Libffi package for ARM64 is copied from cpython binary dependencies
-
-https://github.com/python/cpython-bin-deps/archive/libffi.zip
-
-The library file has been renamed from libffi-7.lib to ffi.lib to avoid special casing \ No newline at end of file
diff --git a/c/libffi_arm64/ffi.lib b/c/libffi_arm64/ffi.lib
deleted file mode 100644
index 4a8b84b..0000000
--- a/c/libffi_arm64/ffi.lib
+++ /dev/null
Binary files differ
diff --git a/c/libffi_arm64/include/ffi.h b/c/libffi_arm64/include/ffi.h
deleted file mode 100644
index d91c3e1..0000000
--- a/c/libffi_arm64/include/ffi.h
+++ /dev/null
@@ -1,515 +0,0 @@
-/* -----------------------------------------------------------------*-C-*-
- libffi 3.3-rc0 - Copyright (c) 2011, 2014 Anthony Green
- - Copyright (c) 1996-2003, 2007, 2008 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 THE AUTHORS OR COPYRIGHT
- HOLDERS 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.
-
- ----------------------------------------------------------------------- */
-
-/* -------------------------------------------------------------------
- Most of the API is documented in doc/libffi.texi.
-
- The raw API is designed to bypass some of the argument packing and
- unpacking on architectures for which it can be avoided. Routines
- are provided to emulate the raw API if the underlying platform
- doesn't allow faster implementation.
-
- More details on the raw 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. */
-#ifndef ARM_WIN64
-#define ARM_WIN64
-#endif
-
-/* ---- System configuration information --------------------------------- */
-
-#include <ffitarget.h>
-
-#ifndef LIBFFI_ASM
-
-#if defined(_MSC_VER) && !defined(__clang__)
-#define __attribute__(X)
-#endif
-
-#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. */
-
-#define FFI_64_BIT_MAX 9223372036854775807
-
-#ifdef LONG_LONG_MAX
-# define FFI_LONG_LONG_MAX LONG_LONG_MAX
-#else
-# ifdef LLONG_MAX
-# define FFI_LONG_LONG_MAX LLONG_MAX
-# ifdef _AIX52 /* or newer has C99 LLONG_MAX */
-# undef FFI_64_BIT_MAX
-# define FFI_64_BIT_MAX 9223372036854775807LL
-# endif /* _AIX52 or newer */
-# else
-# ifdef __GNUC__
-# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__
-# endif
-# ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */
-# ifndef __PPC64__
-# if defined (__IBMC__) || defined (__IBMCPP__)
-# define FFI_LONG_LONG_MAX LONGLONG_MAX
-# endif
-# endif /* __PPC64__ */
-# undef FFI_64_BIT_MAX
-# define FFI_64_BIT_MAX 9223372036854775807LL
-# endif
-# endif
-#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;
- struct _ffi_type **elements;
-} ffi_type;
-
-/* Need minimal decorations for DLLs to work on Windows. GCC has
- autoimport and autoexport. Always mark externally visible symbols
- as dllimport for MSVC clients, even if it means an extra indirection
- when using the static version of the library.
- Besides, as a workaround, they can define FFI_BUILDING if they
- *know* they are going to link with the static library. */
-#if defined _MSC_VER
-# if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */
-# define FFI_API __declspec(dllexport)
-# elif !defined FFI_BUILDING /* Importing libffi.DLL */
-# define FFI_API __declspec(dllimport)
-# else /* Building/linking static library */
-# define FFI_API
-# endif
-#else
-# define FFI_API
-#endif
-
-/* The externally visible type declarations also need the MSVC DLL
- decorations, or they will not be exported from the object file. */
-#if defined LIBFFI_HIDE_BASIC_TYPES
-# define FFI_EXTERN FFI_API
-#else
-# define FFI_EXTERN extern FFI_API
-#endif
-
-#ifndef LIBFFI_HIDE_BASIC_TYPES
-#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
-
-#if LONG_MAX == 2147483647
-# if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX
- #error "no 64-bit data type supported"
-# endif
-#elif LONG_MAX != FFI_64_BIT_MAX
- #error "long size not supported"
-#endif
-
-#if LONG_MAX == 2147483647
-# define ffi_type_ulong ffi_type_uint32
-# define ffi_type_slong ffi_type_sint32
-#elif LONG_MAX == FFI_64_BIT_MAX
-# define ffi_type_ulong ffi_type_uint64
-# define ffi_type_slong ffi_type_sint64
-#else
- #error "long size not supported"
-#endif
-
-/* These are defined in types.c. */
-FFI_EXTERN ffi_type ffi_type_void;
-FFI_EXTERN ffi_type ffi_type_uint8;
-FFI_EXTERN ffi_type ffi_type_sint8;
-FFI_EXTERN ffi_type ffi_type_uint16;
-FFI_EXTERN ffi_type ffi_type_sint16;
-FFI_EXTERN ffi_type ffi_type_uint32;
-FFI_EXTERN ffi_type ffi_type_sint32;
-FFI_EXTERN ffi_type ffi_type_uint64;
-FFI_EXTERN ffi_type ffi_type_sint64;
-FFI_EXTERN ffi_type ffi_type_float;
-FFI_EXTERN ffi_type ffi_type_double;
-FFI_EXTERN ffi_type ffi_type_pointer;
-
-#if 0
-FFI_EXTERN ffi_type ffi_type_longdouble;
-#else
-#define ffi_type_longdouble ffi_type_double
-#endif
-
-#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
-FFI_EXTERN ffi_type ffi_type_complex_float;
-FFI_EXTERN ffi_type ffi_type_complex_double;
-#if 0
-FFI_EXTERN ffi_type ffi_type_complex_longdouble;
-#else
-#define ffi_type_complex_longdouble ffi_type_complex_double
-#endif
-#endif
-#endif /* LIBFFI_HIDE_BASIC_TYPES */
-
-typedef enum {
- FFI_OK = 0,
- FFI_BAD_TYPEDEF,
- FFI_BAD_ABI
-} ffi_status;
-
-typedef struct {
- ffi_abi abi;
- unsigned nargs;
- ffi_type **arg_types;
- ffi_type *rtype;
- unsigned bytes;
- unsigned flags;
-#ifdef FFI_EXTRA_CIF_FIELDS
- FFI_EXTRA_CIF_FIELDS;
-#endif
-} ffi_cif;
-
-/* ---- Definitions for the raw API -------------------------------------- */
-
-#ifndef FFI_SIZEOF_ARG
-# if LONG_MAX == 2147483647
-# define FFI_SIZEOF_ARG 4
-# elif LONG_MAX == FFI_64_BIT_MAX
-# define FFI_SIZEOF_ARG 8
-# endif
-#endif
-
-#ifndef FFI_SIZEOF_JAVA_RAW
-# define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG
-#endif
-
-typedef union {
- ffi_sarg sint;
- ffi_arg uint;
- float flt;
- char data[FFI_SIZEOF_ARG];
- void* ptr;
-} ffi_raw;
-
-#if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8
-/* This is a special case for mips64/n32 ABI (and perhaps others) where
- sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */
-typedef union {
- signed int sint;
- unsigned int uint;
- float flt;
- char data[FFI_SIZEOF_JAVA_RAW];
- void* ptr;
-} ffi_java_raw;
-#else
-typedef ffi_raw ffi_java_raw;
-#endif
-
-
-FFI_API
-void ffi_raw_call (ffi_cif *cif,
- void (*fn)(void),
- void *rvalue,
- ffi_raw *avalue);
-
-FFI_API void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
-FFI_API void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
-FFI_API 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. */
-
-#if !FFI_NATIVE_RAW_API
-FFI_API
-void ffi_java_raw_call (ffi_cif *cif,
- void (*fn)(void),
- void *rvalue,
- ffi_java_raw *avalue);
-#endif
-
-FFI_API
-void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw);
-FFI_API
-void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args);
-FFI_API
-size_t ffi_java_raw_size (ffi_cif *cif);
-
-/* ---- Definitions for closures ----------------------------------------- */
-
-#if FFI_CLOSURES
-
-#ifdef _MSC_VER
-__declspec(align(8))
-#endif
-typedef struct {
-#if 0
- void *trampoline_table;
- void *trampoline_table_entry;
-#else
- char tramp[FFI_TRAMPOLINE_SIZE];
-#endif
- ffi_cif *cif;
- void (*fun)(ffi_cif*,void*,void**,void*);
- void *user_data;
-} ffi_closure
-#ifdef __GNUC__
- __attribute__((aligned (8)))
-#endif
- ;
-
-#ifndef __GNUC__
-# ifdef __sgi
-# pragma pack 0
-# endif
-#endif
-
-FFI_API void *ffi_closure_alloc (size_t size, void **code);
-FFI_API void ffi_closure_free (void *);
-
-FFI_API ffi_status
-ffi_prep_closure (ffi_closure*,
- ffi_cif *,
- void (*fun)(ffi_cif*,void*,void**,void*),
- void *user_data)
-#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 405)
- __attribute__((deprecated ("use ffi_prep_closure_loc instead")))
-#elif defined(__GNUC__) && __GNUC__ >= 3
- __attribute__((deprecated))
-#endif
- ;
-
-FFI_API ffi_status
-ffi_prep_closure_loc (ffi_closure*,
- ffi_cif *,
- void (*fun)(ffi_cif*,void*,void**,void*),
- void *user_data,
- void*codeloc);
-
-#ifdef __sgi
-# pragma pack 8
-#endif
-typedef struct {
-#if 0
- void *trampoline_table;
- void *trampoline_table_entry;
-#else
- char tramp[FFI_TRAMPOLINE_SIZE];
-#endif
- 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;
-
-typedef struct {
-#if 0
- void *trampoline_table;
- void *trampoline_table_entry;
-#else
- char tramp[FFI_TRAMPOLINE_SIZE];
-#endif
-
- 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 translation, void** -> ffi_raw*. */
-
- void (*translate_args)(ffi_cif*,void*,void**,void*);
- void *this_closure;
-
-#endif
-
- void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*);
- void *user_data;
-
-} ffi_java_raw_closure;
-
-FFI_API ffi_status
-ffi_prep_raw_closure (ffi_raw_closure*,
- ffi_cif *cif,
- void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
- void *user_data);
-
-FFI_API ffi_status
-ffi_prep_raw_closure_loc (ffi_raw_closure*,
- ffi_cif *cif,
- void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
- void *user_data,
- void *codeloc);
-
-#if !FFI_NATIVE_RAW_API
-FFI_API ffi_status
-ffi_prep_java_raw_closure (ffi_java_raw_closure*,
- ffi_cif *cif,
- void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
- void *user_data);
-
-FFI_API ffi_status
-ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
- ffi_cif *cif,
- void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
- void *user_data,
- void *codeloc);
-#endif
-
-#endif /* FFI_CLOSURES */
-
-#if FFI_GO_CLOSURES
-
-typedef struct {
- void *tramp;
- ffi_cif *cif;
- void (*fun)(ffi_cif*,void*,void**,void*);
-} ffi_go_closure;
-
-FFI_API ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
- void (*fun)(ffi_cif*,void*,void**,void*));
-
-FFI_API void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
- void **avalue, void *closure);
-
-#endif /* FFI_GO_CLOSURES */
-
-/* ---- Public interface definition -------------------------------------- */
-
-FFI_API
-ffi_status ffi_prep_cif(ffi_cif *cif,
- ffi_abi abi,
- unsigned int nargs,
- ffi_type *rtype,
- ffi_type **atypes);
-
-FFI_API
-ffi_status ffi_prep_cif_var(ffi_cif *cif,
- ffi_abi abi,
- unsigned int nfixedargs,
- unsigned int ntotalargs,
- ffi_type *rtype,
- ffi_type **atypes);
-
-FFI_API
-void ffi_call(ffi_cif *cif,
- void (*fn)(void),
- void *rvalue,
- void **avalue);
-
-FFI_API
-ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
- size_t *offsets);
-
-/* Useful for eliminating compiler warnings. */
-#define FFI_FN(f) ((void (*)(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 0
-#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
-#define FFI_TYPE_COMPLEX 15
-
-/* This should always refer to the last type code (for sanity checks). */
-#define FFI_TYPE_LAST FFI_TYPE_COMPLEX
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/c/libffi_arm64/include/fficonfig.h b/c/libffi_arm64/include/fficonfig.h
deleted file mode 100644
index 5768c29..0000000
--- a/c/libffi_arm64/include/fficonfig.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/* fficonfig.h. Generated from fficonfig.h.in by configure. */
-/* fficonfig.h.in. Generated from configure.ac by autoheader. */
-
-/* Define if building universal (internal helper macro) */
-/* #undef AC_APPLE_UNIVERSAL_BUILD */
-
-/* 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 to 1 if using `alloca.c'. */
-/* #undef C_ALLOCA */
-
-/* Define to the flags needed for the .section .eh_frame directive. */
-/* #undef EH_FRAME_FLAGS */
-
-/* Define this if you want extra debugging. */
-/* #undef FFI_DEBUG */
-
-/* Cannot use PROT_EXEC on this target, so, we revert to alternative means */
-/* #undef FFI_EXEC_TRAMPOLINE_TABLE */
-
-/* Define this if you want to enable pax emulated trampolines */
-/* #undef FFI_MMAP_EXEC_EMUTRAMP_PAX */
-
-/* Cannot use malloc on this target, so, we revert to alternative means */
-/* #undef FFI_MMAP_EXEC_WRIT */
-
-/* Define this if you do not want support for the raw API. */
-/* #undef FFI_NO_RAW_API */
-
-/* Define this if you do not want support for aggregate types. */
-/* #undef FFI_NO_STRUCTS */
-
-/* Define to 1 if you have `alloca', as a function or macro. */
-#define HAVE_ALLOCA 1
-
-/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
- */
-/* #undef HAVE_ALLOCA_H */
-
-/* Define if your assembler supports .cfi_* directives. */
-/* #undef HAVE_AS_CFI_PSEUDO_OP */
-
-/* Define if your assembler supports .register. */
-/* #undef HAVE_AS_REGISTER_PSEUDO_OP */
-
-/* Define if the compiler uses zarch features. */
-/* #undef HAVE_AS_S390_ZARCH */
-
-/* Define if your assembler and linker support unaligned PC relative relocs.
- */
-/* #undef HAVE_AS_SPARC_UA_PCREL */
-
-/* Define if your assembler supports unwind section type. */
-/* #undef HAVE_AS_X86_64_UNWIND_SECTION_TYPE */
-
-/* Define if your assembler supports PC relative relocs. */
-/* #undef HAVE_AS_X86_PCREL */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-/* #undef HAVE_DLFCN_H */
-
-/* Define if __attribute__((visibility("hidden"))) is supported. */
-/* #undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE */
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define if you have the long double type and it is bigger than a double */
-/* #undef HAVE_LONG_DOUBLE */
-
-/* Define if you support more than one size of the long double type */
-/* #undef HAVE_LONG_DOUBLE_VARIANT */
-
-/* Define to 1 if you have the `memcpy' function. */
-/* #undef HAVE_MEMCPY */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the `mkostemp' function. */
-/* #undef HAVE_MKOSTEMP */
-
-/* Define to 1 if you have the `mmap' function. */
-/* #undef HAVE_MMAP */
-
-/* Define if mmap with MAP_ANON(YMOUS) works. */
-/* #undef HAVE_MMAP_ANON */
-
-/* Define if mmap of /dev/zero works. */
-/* #undef HAVE_MMAP_DEV_ZERO */
-
-/* Define if read-only mmap of a plain file works. */
-/* #undef HAVE_MMAP_FILE */
-
-/* Define if .eh_frame sections should be read-only. */
-/* #undef HAVE_RO_EH_FRAME */
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-/* #undef HAVE_STRINGS_H */
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the <sys/mman.h> header file. */
-/* #undef HAVE_SYS_MMAN_H */
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-/* #undef HAVE_UNISTD_H */
-
-/* Define to 1 if GNU symbol versioning is used for libatomic. */
-/* #undef LIBFFI_GNU_SYMBOL_VERSIONING */
-
-/* Define to the sub-directory where libtool stores uninstalled libraries. */
-#define LT_OBJDIR ".libs/"
-
-/* Name of package */
-#define PACKAGE "libffi"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "http://github.com/libffi/libffi/issues"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "libffi"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libffi 3.3-rc0"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "libffi"
-
-/* Define to the home page for this package. */
-#define PACKAGE_URL ""
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "3.3-rc0"
-
-/* The size of `double', as computed by sizeof. */
-#define SIZEOF_DOUBLE 8
-
-/* The size of `long double', as computed by sizeof. */
-#define SIZEOF_LONG_DOUBLE 8
-
-/* The size of `size_t', as computed by sizeof. */
-#define SIZEOF_SIZE_T 8
-
-/* 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 runtime.
- 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 to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Define if symbols are underscored. */
-/* #undef SYMBOL_UNDERSCORE */
-
-/* Define this if you are using Purify and want to suppress spurious messages.
- */
-/* #undef USING_PURIFY */
-
-/* Version number of package */
-#define VERSION "3.3-rc0"
-
-/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
- significant byte first (like Motorola and SPARC, unlike Intel). */
-#if defined AC_APPLE_UNIVERSAL_BUILD
-# if defined __BIG_ENDIAN__
-# define WORDS_BIGENDIAN 1
-# endif
-#else
-# ifndef WORDS_BIGENDIAN
-/* # undef WORDS_BIGENDIAN */
-# endif
-#endif
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef size_t */
-
-
-#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
-#ifdef LIBFFI_ASM
-#ifdef __APPLE__
-#define FFI_HIDDEN(name) .private_extern name
-#else
-#define FFI_HIDDEN(name) .hidden name
-#endif
-#else
-#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
-#endif
-#else
-#ifdef LIBFFI_ASM
-#define FFI_HIDDEN(name)
-#else
-#define FFI_HIDDEN
-#endif
-#endif
-
diff --git a/c/libffi_arm64/include/ffitarget.h b/c/libffi_arm64/include/ffitarget.h
deleted file mode 100644
index ecb6d2d..0000000
--- a/c/libffi_arm64/include/ffitarget.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
-
-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 THE AUTHORS OR COPYRIGHT HOLDERS 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
-
-#ifndef LIBFFI_H
-#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
-#endif
-
-#ifndef LIBFFI_ASM
-#ifdef __ILP32__
-#define FFI_SIZEOF_ARG 8
-#define FFI_SIZEOF_JAVA_RAW 4
-typedef unsigned long long ffi_arg;
-typedef signed long long ffi_sarg;
-#elif defined(_M_ARM64)
-#define FFI_SIZEOF_ARG 8
-typedef unsigned long long ffi_arg;
-typedef signed long long ffi_sarg;
-#else
-typedef unsigned long ffi_arg;
-typedef signed long ffi_sarg;
-#endif
-
-typedef enum ffi_abi
- {
- FFI_FIRST_ABI = 0,
- FFI_SYSV,
- FFI_LAST_ABI,
- FFI_DEFAULT_ABI = FFI_SYSV
- } ffi_abi;
-#endif
-
-/* ---- Definitions for closures ----------------------------------------- */
-
-#define FFI_CLOSURES 1
-#define FFI_NATIVE_RAW_API 0
-
-#if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE
-
-#ifdef __MACH__
-#define FFI_TRAMPOLINE_SIZE 16
-#define FFI_TRAMPOLINE_CLOSURE_OFFSET 16
-#else
-#error "No trampoline table implementation"
-#endif
-
-#else
-#define FFI_TRAMPOLINE_SIZE 24
-#define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE
-#endif
-
-#ifdef _M_ARM64
-#define FFI_EXTRA_CIF_FIELDS unsigned is_variadic
-#endif
-
-/* ---- Internal ---- */
-
-#if defined (__APPLE__)
-#define FFI_TARGET_SPECIFIC_VARIADIC
-#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs
-#elif !defined(_M_ARM64)
-/* iOS and Windows reserve x18 for the system. Disable Go closures until
- a new static chain is chosen. */
-#define FFI_GO_CLOSURES 1
-#endif
-
-#ifndef _M_ARM64
-/* No complex type on Windows */
-#define FFI_TARGET_HAS_COMPLEX_TYPE
-#endif
-
-#endif
diff --git a/c/libffi_x86_x64/LICENSE b/c/libffi_x86_x64/LICENSE
deleted file mode 100644
index f591795..0000000
--- a/c/libffi_x86_x64/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-libffi - 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.
diff --git a/c/libffi_x86_x64/README b/c/libffi_x86_x64/README
deleted file mode 100644
index 97a12cf..0000000
--- a/c/libffi_x86_x64/README
+++ /dev/null
@@ -1,502 +0,0 @@
-This directory contains the libffi package, which is not part of GCC but
-shipped with GCC as convenience.
-
-Copied without changes from CPython 2.7 head (e04e1f253ed8).
-
-Status
-======
-
-libffi-2.00 has not been released yet! This is a development snapshot!
-
-libffi-1.20 was released on October 5, 1998. Check the libffi web
-page for updates: <URL:http://sources.redhat.com/libffi/>.
-
-
-What is libffi?
-===============
-
-Compilers for high level languages generate code that follow certain
-conventions. These conventions are necessary, in part, for separate
-compilation to work. One such convention is the "calling
-convention". The "calling convention" is essentially a set of
-assumptions made by the compiler about where function arguments will
-be found on entry to a function. A "calling convention" also specifies
-where the return value for a function is found.
-
-Some programs may not know at the time of compilation what arguments
-are to be passed to a function. For instance, an interpreter may be
-told at run-time about the number and types of arguments used to call
-a given function. Libffi can be used in such programs to provide a
-bridge from the interpreter program to compiled code.
-
-The libffi library provides a portable, high level programming
-interface to various calling conventions. This allows a programmer to
-call any function specified by a call interface description at run
-time.
-
-Ffi stands for Foreign Function Interface. A foreign function
-interface is the popular name for the interface that allows code
-written in one language to call code written in another language. The
-libffi library really only provides the lowest, machine dependent
-layer of a fully featured foreign function interface. A layer must
-exist above libffi that handles type conversions for values passed
-between the two languages.
-
-
-Supported Platforms and Prerequisites
-=====================================
-
-Libffi has been ported to:
-
- SunOS 4.1.3 & Solaris 2.x (SPARC-V8, SPARC-V9)
-
- Irix 5.3 & 6.2 (System V/o32 & n32)
-
- Intel x86 - Linux (System V ABI)
-
- Alpha - Linux and OSF/1
-
- m68k - Linux (System V ABI)
-
- PowerPC - Linux (System V ABI, Darwin, AIX)
-
- ARM - Linux (System V ABI)
-
-Libffi has been tested with the egcs 1.0.2 gcc compiler. Chances are
-that other versions will work. Libffi has also been built and tested
-with the SGI compiler tools.
-
-On PowerPC, the tests failed (see the note below).
-
-You must use GNU make to build libffi. SGI's make will not work.
-Sun's probably won't either.
-
-If you port libffi to another platform, please let me know! I assume
-that some will be easy (x86 NetBSD), and others will be more difficult
-(HP).
-
-
-Installing libffi
-=================
-
-[Note: before actually performing any of these installation steps,
- you may wish to read the "Platform Specific Notes" below.]
-
-First you must configure the distribution for your particular
-system. Go to the directory you wish to build libffi in and run the
-"configure" program found in the root directory of the libffi source
-distribution.
-
-You may want to tell configure where to install the libffi library and
-header files. To do that, use the --prefix configure switch. Libffi
-will install under /usr/local by default.
-
-If you want to enable extra run-time debugging checks use the the
---enable-debug configure switch. This is useful when your program dies
-mysteriously while using libffi.
-
-Another useful configure switch is --enable-purify-safety. Using this
-will add some extra code which will suppress certain warnings when you
-are using Purify with libffi. Only use this switch when using
-Purify, as it will slow down the library.
-
-Configure has many other options. Use "configure --help" to see them all.
-
-Once configure has finished, type "make". Note that you must be using
-GNU make. SGI's make will not work. Sun's probably won't either.
-You can ftp GNU make from prep.ai.mit.edu:/pub/gnu.
-
-To ensure that libffi is working as advertised, type "make test".
-
-To install the library and header files, type "make install".
-
-
-Using libffi
-============
-
- The Basics
- ----------
-
-Libffi assumes that you have a pointer to the function you wish to
-call and that you know the number and types of arguments to pass it,
-as well as the return type of the function.
-
-The first thing you must do is create an ffi_cif object that matches
-the signature of the function you wish to call. The cif in ffi_cif
-stands for Call InterFace. To prepare a call interface object, use the
-following function:
-
-ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi,
- unsigned int nargs,
- ffi_type *rtype, ffi_type **atypes);
-
- CIF is a pointer to the call interface object you wish
- to initialize.
-
- ABI is an enum that specifies the calling convention
- to use for the call. FFI_DEFAULT_ABI defaults
- to the system's native calling convention. Other
- ABI's may be used with care. They are system
- specific.
-
- NARGS is the number of arguments this function accepts.
- libffi does not yet support vararg functions.
-
- RTYPE is a pointer to an ffi_type structure that represents
- the return type of the function. Ffi_type objects
- describe the types of values. libffi provides
- ffi_type objects for many of the native C types:
- signed int, unsigned int, signed char, unsigned char,
- etc. There is also a pointer ffi_type object and
- a void ffi_type. Use &ffi_type_void for functions that
- don't return values.
-
- ATYPES is a vector of ffi_type pointers. ARGS must be NARGS long.
- If NARGS is 0, this is ignored.
-
-
-ffi_prep_cif will return a status code that you are responsible
-for checking. It will be one of the following:
-
- FFI_OK - All is good.
-
- FFI_BAD_TYPEDEF - One of the ffi_type objects that ffi_prep_cif
- came across is bad.
-
-
-Before making the call, the VALUES vector should be initialized
-with pointers to the appropriate argument values.
-
-To call the the function using the initialized ffi_cif, use the
-ffi_call function:
-
-void ffi_call(ffi_cif *cif, void *fn, void *rvalue, void **avalues);
-
- CIF is a pointer to the ffi_cif initialized specifically
- for this function.
-
- FN is a pointer to the function you want to call.
-
- RVALUE is a pointer to a chunk of memory that is to hold the
- result of the function call. Currently, it must be
- at least one word in size (except for the n32 version
- under Irix 6.x, which must be a pointer to an 8 byte
- aligned value (a long long). It must also be at least
- word aligned (depending on the return type, and the
- system's alignment requirements). If RTYPE is
- &ffi_type_void, this is ignored. If RVALUE is NULL,
- the return value is discarded.
-
- AVALUES is a vector of void* that point to the memory locations
- holding the argument values for a call.
- If NARGS is 0, this is ignored.
-
-
-If you are expecting a return value from FN it will have been stored
-at RVALUE.
-
-
-
- An Example
- ----------
-
-Here is a trivial example that calls puts() a few times.
-
- #include <stdio.h>
- #include <ffi.h>
-
- int main()
- {
- ffi_cif cif;
- ffi_type *args[1];
- void *values[1];
- char *s;
- int rc;
-
- /* Initialize the argument info vectors */
- args[0] = &ffi_type_uint;
- values[0] = &s;
-
- /* Initialize the cif */
- if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
- &ffi_type_uint, args) == FFI_OK)
- {
- s = "Hello World!";
- ffi_call(&cif, puts, &rc, values);
- /* rc now holds the result of the call to puts */
-
- /* values holds a pointer to the function's arg, so to
- call puts() again all we need to do is change the
- value of s */
- s = "This is cool!";
- ffi_call(&cif, puts, &rc, values);
- }
-
- return 0;
- }
-
-
-
- Aggregate Types
- ---------------
-
-Although libffi has no special support for unions or bit-fields, it is
-perfectly happy passing structures back and forth. You must first
-describe the structure to libffi by creating a new ffi_type object
-for it. Here is the definition of ffi_type:
-
- typedef struct _ffi_type
- {
- unsigned size;
- short alignment;
- short type;
- struct _ffi_type **elements;
- } ffi_type;
-
-All structures must have type set to FFI_TYPE_STRUCT. You may set
-size and alignment to 0. These will be calculated and reset to the
-appropriate values by ffi_prep_cif().
-
-elements is a NULL terminated array of pointers to ffi_type objects
-that describe the type of the structure elements. These may, in turn,
-be structure elements.
-
-The following example initializes a ffi_type object representing the
-tm struct from Linux's time.h:
-
- struct tm {
- int tm_sec;
- int tm_min;
- int tm_hour;
- int tm_mday;
- int tm_mon;
- int tm_year;
- int tm_wday;
- int tm_yday;
- int tm_isdst;
- /* Those are for future use. */
- long int __tm_gmtoff__;
- __const char *__tm_zone__;
- };
-
- {
- ffi_type tm_type;
- ffi_type *tm_type_elements[12];
- int i;
-
- tm_type.size = tm_type.alignment = 0;
- tm_type.elements = &tm_type_elements;
-
- for (i = 0; i < 9; i++)
- tm_type_elements[i] = &ffi_type_sint;
-
- tm_type_elements[9] = &ffi_type_slong;
- tm_type_elements[10] = &ffi_type_pointer;
- tm_type_elements[11] = NULL;
-
- /* tm_type can now be used to represent tm argument types and
- return types for ffi_prep_cif() */
- }
-
-
-
-Platform Specific Notes
-=======================
-
- Intel x86
- ---------
-
-There are no known problems with the x86 port.
-
- Sun SPARC - SunOS 4.1.3 & Solaris 2.x
- -------------------------------------
-
-You must use GNU Make to build libffi on Sun platforms.
-
- MIPS - Irix 5.3 & 6.x
- ---------------------
-
-Irix 6.2 and better supports three different calling conventions: o32,
-n32 and n64. Currently, libffi only supports both o32 and n32 under
-Irix 6.x, but only o32 under Irix 5.3. Libffi will automatically be
-configured for whichever calling convention it was built for.
-
-By default, the configure script will try to build libffi with the GNU
-development tools. To build libffi with the SGI development tools, set
-the environment variable CC to either "cc -32" or "cc -n32" before
-running configure under Irix 6.x (depending on whether you want an o32
-or n32 library), or just "cc" for Irix 5.3.
-
-With the n32 calling convention, when returning structures smaller
-than 16 bytes, be sure to provide an RVALUE that is 8 byte aligned.
-Here's one way of forcing this:
-
- double struct_storage[2];
- my_small_struct *s = (my_small_struct *) struct_storage;
- /* Use s for RVALUE */
-
-If you don't do this you are liable to get spurious bus errors.
-
-"long long" values are not supported yet.
-
-You must use GNU Make to build libffi on SGI platforms.
-
- ARM - System V ABI
- ------------------
-
-The ARM port was performed on a NetWinder running ARM Linux ELF
-(2.0.31) and gcc 2.8.1.
-
-
-
- PowerPC System V ABI
- --------------------
-
-There are two `System V ABI's which libffi implements for PowerPC.
-They differ only in how small structures are returned from functions.
-
-In the FFI_SYSV version, structures that are 8 bytes or smaller are
-returned in registers. This is what GCC does when it is configured
-for solaris, and is what the System V ABI I have (dated September
-1995) says.
-
-In the FFI_GCC_SYSV version, all structures are returned the same way:
-by passing a pointer as the first argument to the function. This is
-what GCC does when it is configured for linux or a generic sysv
-target.
-
-EGCS 1.0.1 (and probably other versions of EGCS/GCC) also has a
-inconsistency with the SysV ABI: When a procedure is called with many
-floating-point arguments, some of them get put on the stack. They are
-all supposed to be stored in double-precision format, even if they are
-only single-precision, but EGCS stores single-precision arguments as
-single-precision anyway. This causes one test to fail (the `many
-arguments' test).
-
-
-What's With The Crazy Comments?
-===============================
-
-You might notice a number of cryptic comments in the code, delimited
-by /*@ and @*/. These are annotations read by the program LCLint, a
-tool for statically checking C programs. You can read all about it at
-<http://larch-www.lcs.mit.edu:8001/larch/lclint/index.html>.
-
-
-History
-=======
-
-1.20 Oct-5-98
- Raffaele Sena produces ARM port.
-
-1.19 Oct-5-98
- Fixed x86 long double and long long return support.
- m68k bug fixes from Andreas Schwab.
- Patch for DU assembler compatibility for the Alpha from Richard
- Henderson.
-
-1.18 Apr-17-98
- Bug fixes and MIPS configuration changes.
-
-1.17 Feb-24-98
- Bug fixes and m68k port from Andreas Schwab. PowerPC port from
- Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes.
-
-1.16 Feb-11-98
- Richard Henderson produces Alpha port.
-
-1.15 Dec-4-97
- Fixed an n32 ABI bug. New libtool, auto* support.
-
-1.14 May-13-97
- libtool is now used to generate shared and static libraries.
- Fixed a minor portability problem reported by Russ McManus
- <mcmanr@eq.gs.com>.
-
-1.13 Dec-2-96
- Added --enable-purify-safety to keep Purify from complaining
- about certain low level code.
- Sparc fix for calling functions with < 6 args.
- Linux x86 a.out fix.
-
-1.12 Nov-22-96
- Added missing ffi_type_void, needed for supporting void return
- types. Fixed test case for non MIPS machines. Cygnus Support
- is now Cygnus Solutions.
-
-1.11 Oct-30-96
- Added notes about GNU make.
-
-1.10 Oct-29-96
- Added configuration fix for non GNU compilers.
-
-1.09 Oct-29-96
- Added --enable-debug configure switch. Clean-ups based on LCLint
- feedback. ffi_mips.h is always installed. Many configuration
- fixes. Fixed ffitest.c for sparc builds.
-
-1.08 Oct-15-96
- Fixed n32 problem. Many clean-ups.
-
-1.07 Oct-14-96
- Gordon Irlam rewrites v8.S again. Bug fixes.
-
-1.06 Oct-14-96
- Gordon Irlam improved the sparc port.
-
-1.05 Oct-14-96
- Interface changes based on feedback.
-
-1.04 Oct-11-96
- Sparc port complete (modulo struct passing bug).
-
-1.03 Oct-10-96
- Passing struct args, and returning struct values works for
- all architectures/calling conventions. Expanded tests.
-
-1.02 Oct-9-96
- Added SGI n32 support. Fixed bugs in both o32 and Linux support.
- Added "make test".
-
-1.01 Oct-8-96
- Fixed float passing bug in mips version. Restructured some
- of the code. Builds cleanly with SGI tools.
-
-1.00 Oct-7-96
- First release. No public announcement.
-
-
-Authors & Credits
-=================
-
-libffi was written by Anthony Green <green@cygnus.com>.
-
-Portions of libffi were derived from Gianni Mariani's free gencall
-library for Silicon Graphics machines.
-
-The closure mechanism was designed and implemented by Kresten Krab
-Thorup.
-
-The Sparc port was derived from code contributed by the fine folks at
-Visible Decisions Inc <http://www.vdi.com>. Further enhancements were
-made by Gordon Irlam at Cygnus Solutions <http://www.cygnus.com>.
-
-The Alpha port was written by Richard Henderson at Cygnus Solutions.
-
-Andreas Schwab ported libffi to m68k Linux and provided a number of
-bug fixes.
-
-Geoffrey Keating ported libffi to the PowerPC.
-
-Raffaele Sena ported libffi to the ARM.
-
-Jesper Skov and Andrew Haley both did more than their fair share of
-stepping through the code and tracking down bugs.
-
-Thanks also to Tom Tromey for bug fixes and configuration help.
-
-Thanks to Jim Blandy, who provided some useful feedback on the libffi
-interface.
-
-If you have a problem, or have found a bug, please send a note to
-green@cygnus.com.
diff --git a/c/libffi_x86_x64/README.ctypes b/c/libffi_x86_x64/README.ctypes
deleted file mode 100644
index 17e8a40..0000000
--- a/c/libffi_x86_x64/README.ctypes
+++ /dev/null
@@ -1,7 +0,0 @@
-The purpose is to hack the libffi sources so that they can be compiled
-with MSVC, and to extend them so that they have the features I need
-for ctypes.
-
-I retrieved the libffi sources from the gcc cvs repository on
-2004-01-27. Then I did 'configure' in a 'build' subdirectory on a x86
-linux system, and copied the files I found useful.
diff --git a/c/libffi_x86_x64/ffi.c b/c/libffi_x86_x64/ffi.c
deleted file mode 100644
index b9e324f..0000000
--- a/c/libffi_x86_x64/ffi.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/* -----------------------------------------------------------------------
- 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@*/
-{
- register unsigned int i;
- register void **p_argv;
- register char *argp;
- register 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
- 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. */
- if (cif->rtype->size == 1 ||
- cif->rtype->size == 2 ||
- cif->rtype->size == 4)
- 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" );
- }
- 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");
- }
- 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 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");
- }
- 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.
- */
- 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@*/
-{
- register unsigned int i;
- register void **p_argv;
- register char *argp;
- register 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
- 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;
-
- /* 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;
-}
diff --git a/c/libffi_x86_x64/ffi.h b/c/libffi_x86_x64/ffi.h
deleted file mode 100644
index 97cdb59..0000000
--- a/c/libffi_x86_x64/ffi.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/* -----------------------------------------------------------------*-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/c/libffi_x86_x64/ffi_common.h b/c/libffi_x86_x64/ffi_common.h
deleted file mode 100644
index 43fb83b..0000000
--- a/c/libffi_x86_x64/ffi_common.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -----------------------------------------------------------------------
- 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/c/libffi_x86_x64/fficonfig.h b/c/libffi_x86_x64/fficonfig.h
deleted file mode 100644
index c14f653..0000000
--- a/c/libffi_x86_x64/fficonfig.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* 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/c/libffi_x86_x64/ffitarget.h b/c/libffi_x86_x64/ffitarget.h
deleted file mode 100644
index 85f5ee8..0000000
--- a/c/libffi_x86_x64/ffitarget.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -----------------------------------------------------------------*-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/c/libffi_x86_x64/prep_cif.c b/c/libffi_x86_x64/prep_cif.c
deleted file mode 100644
index df94a98..0000000
--- a/c/libffi_x86_x64/prep_cif.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* -----------------------------------------------------------------------
- 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(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);
-}
diff --git a/c/libffi_x86_x64/types.c b/c/libffi_x86_x64/types.c
deleted file mode 100644
index 4433ac2..0000000
--- a/c/libffi_x86_x64/types.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -----------------------------------------------------------------------
- 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/c/libffi_x86_x64/win32.c b/c/libffi_x86_x64/win32.c
deleted file mode 100644
index d1149a8..0000000
--- a/c/libffi_x86_x64/win32.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/* -----------------------------------------------------------------------
- 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/c/libffi_x86_x64/win64.asm b/c/libffi_x86_x64/win64.asm
deleted file mode 100644
index 301188b..0000000
--- a/c/libffi_x86_x64/win64.asm
+++ /dev/null
@@ -1,156 +0,0 @@
-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.
-;;;
-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/c/libffi_x86_x64/win64.obj b/c/libffi_x86_x64/win64.obj
deleted file mode 100644
index 38d3cd1..0000000
--- a/c/libffi_x86_x64/win64.obj
+++ /dev/null
Binary files differ
diff --git a/c/malloc_closure.h b/c/malloc_closure.h
deleted file mode 100644
index bebb93d..0000000
--- a/c/malloc_closure.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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/c/minibuffer.h b/c/minibuffer.h
deleted file mode 100644
index f3f5ca1..0000000
--- a/c/minibuffer.h
+++ /dev/null
@@ -1,408 +0,0 @@
-
-/* 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)
-{
- Py_ssize_t count;
- 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;
- if (count != src_view.len) {
- PyBuffer_Release(&src_view);
- 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;
-}
-
-static PyObject *
-mb_richcompare(PyObject *self, PyObject *other, int op)
-{
- Py_ssize_t self_size, other_size;
- Py_buffer self_bytes, other_bytes;
- PyObject *res;
- Py_ssize_t minsize;
- int cmp, rc;
-
- /* Bytes can be compared to anything that supports the (binary)
- buffer API. Except that a comparison with Unicode is always an
- error, even if the comparison is for equality. */
- rc = PyObject_IsInstance(self, (PyObject*)&PyUnicode_Type);
- if (!rc)
- rc = PyObject_IsInstance(other, (PyObject*)&PyUnicode_Type);
- if (rc < 0)
- return NULL;
- if (rc) {
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
- }
-
- if (PyObject_GetBuffer(self, &self_bytes, PyBUF_SIMPLE) != 0) {
- PyErr_Clear();
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
-
- }
- self_size = self_bytes.len;
-
- if (PyObject_GetBuffer(other, &other_bytes, PyBUF_SIMPLE) != 0) {
- PyErr_Clear();
- PyBuffer_Release(&self_bytes);
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
-
- }
- other_size = other_bytes.len;
-
- if (self_size != other_size && (op == Py_EQ || op == Py_NE)) {
- /* Shortcut: if the lengths differ, the objects differ */
- cmp = (op == Py_NE);
- }
- else {
- minsize = self_size;
- if (other_size < minsize)
- minsize = other_size;
-
- cmp = memcmp(self_bytes.buf, other_bytes.buf, minsize);
- /* In ISO C, memcmp() guarantees to use unsigned bytes! */
-
- if (cmp == 0) {
- if (self_size < other_size)
- cmp = -1;
- else if (self_size > other_size)
- cmp = 1;
- }
-
- switch (op) {
- case Py_LT: cmp = cmp < 0; break;
- case Py_LE: cmp = cmp <= 0; break;
- case Py_EQ: cmp = cmp == 0; break;
- case Py_NE: cmp = cmp != 0; break;
- case Py_GT: cmp = cmp > 0; break;
- case Py_GE: cmp = cmp >= 0; break;
- }
- }
-
- res = cmp ? Py_True : Py_False;
- PyBuffer_Release(&self_bytes);
- PyBuffer_Release(&other_bytes);
- Py_INCREF(res);
- return res;
-}
-
-#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
- on ABI between 3.6.0, 3.6.1 and 3.6.2. */
-#if PY_VERSION_HEX < 0x03070000 && defined(PySlice_GetIndicesEx) && !defined(PYPY_VERSION)
-#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
-
-PyDoc_STRVAR(ffi_buffer_doc,
-"ffi.buffer(cdata[, byte_size]):\n"
-"Return a read-write buffer object that references the raw C data\n"
-"pointed to by the given 'cdata'. The 'cdata' must be a pointer or an\n"
-"array. Can be passed to functions expecting a buffer, or directly\n"
-"manipulated with:\n"
-"\n"
-" buf[:] get a copy of it in a regular string, or\n"
-" buf[idx] as a single character\n"
-" buf[:] = ...\n"
-" buf[idx] = ... change the content");
-
-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 */
- ffi_buffer_doc, /* tp_doc */
- (traverseproc)mb_traverse, /* tp_traverse */
- (inquiry)mb_clear, /* tp_clear */
- (richcmpfunc)mb_richcompare, /* tp_richcompare */
- offsetof(MiniBufferObj, mb_weakreflist), /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 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;
-}
diff --git a/c/misc_thread_common.h b/c/misc_thread_common.h
deleted file mode 100644
index 66e2835..0000000
--- a/c/misc_thread_common.h
+++ /dev/null
@@ -1,371 +0,0 @@
-#ifndef WITH_THREAD
-# error "xxx no-thread configuration not tested, please report if you need that"
-#endif
-#include "pythread.h"
-
-
-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 */
-
-
-/* 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
- * the standard logic in PyGILState_Ensure() and PyGILState_Release()
- * would create a new PyThreadState and completely free it for every
- * single call. For some applications, this is a huge slow-down.
- *
- * As shown by issue #362, it is quite messy to do. The current
- * solution is to keep the PyThreadState alive by incrementing its
- * 'gilstate_counter'. We detect thread shut-down, and we put the
- * PyThreadState inside a list of zombies (we can't free it
- * immediately because we don't have the GIL at that point in time).
- * We also detect other pieces of code (notably Py_Finalize()) which
- * clear and free PyThreadStates under our feet, using ThreadCanaryObj.
- */
-
-#define TLS_ZOM_LOCK() PyThread_acquire_lock(cffi_zombie_lock, WAIT_LOCK)
-#define TLS_ZOM_UNLOCK() PyThread_release_lock(cffi_zombie_lock)
-static PyThread_type_lock cffi_zombie_lock = NULL;
-
-
-/* A 'canary' object is created in a thread when there is a callback
- invoked, and that thread has no PyThreadState so far. It is an
- object of reference count equal to 1, which is stored in the
- PyThreadState->dict. Two things can occur then:
-
- 1. The PyThreadState can be forcefully cleared by Py_Finalize().
- Then thread_canary_dealloc() is called, and we have to cancel
- the hacks we did to keep the PyThreadState alive.
-
- 2. The thread finishes. In that case, we put the canary in a list
- of zombies, and at some convenient time later when we have the
- GIL, we free all PyThreadStates in the zombie list.
-
- Some more fun comes from the fact that thread_canary_dealloc() can
- be called at a point where the canary is in the zombie list already.
- Also, the various pieces are freed at specific points in time, and
- we must make sure not to access already-freed structures:
-
- - the struct cffi_tls_s is valid until the thread shuts down, and
- then it is freed by cffi_thread_shutdown().
-
- - the canary is a normal Python object, but we have a borrowed
- reference to it from cffi_tls_s.local_thread_canary.
- */
-
-typedef struct thread_canary_s {
- PyObject_HEAD
- struct thread_canary_s *zombie_prev, *zombie_next;
- PyThreadState *tstate;
- struct cffi_tls_s *tls;
-} ThreadCanaryObj;
-
-static PyTypeObject ThreadCanary_Type; /* forward */
-static ThreadCanaryObj cffi_zombie_head;
-
-static void
-_thread_canary_detach_with_lock(ThreadCanaryObj *ob)
-{
- /* must be called with both the GIL and TLS_ZOM_LOCK. */
- ThreadCanaryObj *p, *n;
- p = ob->zombie_prev;
- n = ob->zombie_next;
- p->zombie_next = n;
- n->zombie_prev = p;
- ob->zombie_prev = NULL;
- ob->zombie_next = NULL;
-}
-
-static void
-thread_canary_dealloc(ThreadCanaryObj *ob)
-{
- /* this ThreadCanaryObj is being freed: if it is in the zombie
- chained list, remove it. Thread-safety: 'zombie_next' amd
- 'local_thread_canary' accesses need to be protected with
- the TLS_ZOM_LOCK.
- */
- TLS_ZOM_LOCK();
- if (ob->zombie_next != NULL) {
- //fprintf(stderr, "thread_canary_dealloc(%p): ZOMBIE\n", ob);
- _thread_canary_detach_with_lock(ob);
- }
- else {
- //fprintf(stderr, "thread_canary_dealloc(%p): not a zombie\n", ob);
- }
-
- if (ob->tls != NULL) {
- //fprintf(stderr, "thread_canary_dealloc(%p): was local_thread_canary\n", ob);
- assert(ob->tls->local_thread_canary == ob);
- ob->tls->local_thread_canary = NULL;
- }
- TLS_ZOM_UNLOCK();
-
- PyObject_Del((PyObject *)ob);
-}
-
-static void
-thread_canary_make_zombie(ThreadCanaryObj *ob)
-{
- /* This must be called without the GIL, but with the TLS_ZOM_LOCK.
- It must be called at most once for a given ThreadCanaryObj. */
- ThreadCanaryObj *last;
-
- //fprintf(stderr, "thread_canary_make_zombie(%p)\n", ob);
- if (ob->zombie_next)
- Py_FatalError("cffi: ThreadCanaryObj is already a zombie");
- last = cffi_zombie_head.zombie_prev;
- ob->zombie_next = &cffi_zombie_head;
- ob->zombie_prev = last;
- last->zombie_next = ob;
- cffi_zombie_head.zombie_prev = ob;
-}
-
-static void
-thread_canary_free_zombies(void)
-{
- /* This must be called with the GIL. */
- if (cffi_zombie_head.zombie_next == &cffi_zombie_head)
- return; /* fast path */
-
- while (1) {
- ThreadCanaryObj *ob;
- PyThreadState *tstate = NULL;
-
- TLS_ZOM_LOCK();
- ob = cffi_zombie_head.zombie_next;
- if (ob != &cffi_zombie_head) {
- tstate = ob->tstate;
- //fprintf(stderr, "thread_canary_free_zombie(%p) tstate=%p\n", ob, tstate);
- _thread_canary_detach_with_lock(ob);
- if (tstate == NULL)
- Py_FatalError("cffi: invalid ThreadCanaryObj->tstate");
- }
- TLS_ZOM_UNLOCK();
-
- if (tstate == NULL)
- break;
- PyThreadState_Clear(tstate); /* calls thread_canary_dealloc on 'ob',
- but now ob->zombie_next == NULL. */
- PyThreadState_Delete(tstate);
- //fprintf(stderr, "thread_canary_free_zombie: cleared and deleted tstate=%p\n", tstate);
- }
- //fprintf(stderr, "thread_canary_free_zombie: end\n");
-}
-
-static void
-thread_canary_register(PyThreadState *tstate)
-{
- /* called with the GIL; 'tstate' is the current PyThreadState. */
- ThreadCanaryObj *canary;
- PyObject *tdict;
- struct cffi_tls_s *tls;
- int err;
-
- /* first free the zombies, if any */
- thread_canary_free_zombies();
-
- tls = get_cffi_tls();
- if (tls == NULL)
- goto ignore_error;
-
- tdict = PyThreadState_GetDict();
- if (tdict == NULL)
- goto ignore_error;
-
- canary = PyObject_New(ThreadCanaryObj, &ThreadCanary_Type);
- //fprintf(stderr, "thread_canary_register(%p): tstate=%p tls=%p\n", canary, tstate, tls);
- if (canary == NULL)
- goto ignore_error;
- canary->zombie_prev = NULL;
- canary->zombie_next = NULL;
- canary->tstate = tstate;
- canary->tls = tls;
-
- err = PyDict_SetItemString(tdict, "cffi.thread.canary", (PyObject *)canary);
- Py_DECREF(canary);
- if (err < 0)
- goto ignore_error;
-
- /* thread-safety: we have the GIL here, and 'tstate' is the one that
- corresponds to our own thread. We are allocating a new 'canary'
- and setting it up for our own thread, both in 'tdict' (which owns
- the reference) and in 'tls->local_thread_canary' (which doesn't). */
- assert(Py_REFCNT(canary) == 1);
- tls->local_thread_canary = canary;
- tstate->gilstate_counter++;
- /* ^^^ this means 'tstate' will never be automatically freed by
- PyGILState_Release() */
- return;
-
- ignore_error:
- PyErr_Clear();
-}
-
-static PyTypeObject ThreadCanary_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.thread_canary",
- sizeof(ThreadCanaryObj),
- 0,
- (destructor)thread_canary_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 */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
-};
-
-static void init_cffi_tls_zombie(void)
-{
- cffi_zombie_head.zombie_next = &cffi_zombie_head;
- cffi_zombie_head.zombie_prev = &cffi_zombie_head;
- cffi_zombie_lock = PyThread_allocate_lock();
- if (cffi_zombie_lock == NULL)
- PyErr_SetString(PyExc_SystemError, "can't allocate cffi_zombie_lock");
-}
-
-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;
-
- /* 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
-
-
-/* MESS. We can't use PyThreadState_GET(), because that calls
- PyThreadState_Get() which fails an assert if the result is NULL.
-
- * in Python 2.7 and <= 3.4, the variable _PyThreadState_Current
- is directly available, so use that.
-
- * in Python 3.5, the variable is available too, but it might be
- the case that the headers don't define it (this changed in 3.5.1).
- In case we're compiling with 3.5.x with x >= 1, we need to
- manually define this variable.
-
- * in Python >= 3.6 there is _PyThreadState_UncheckedGet().
- It was added in 3.5.2 but should never be used in 3.5.x
- because it is not available in 3.5.0 or 3.5.1.
-*/
-#if PY_VERSION_HEX >= 0x03050100 && PY_VERSION_HEX < 0x03060000
-PyAPI_DATA(void *volatile) _PyThreadState_Current;
-#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*)_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);
-
- /* 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);
-}
diff --git a/c/misc_thread_posix.h b/c/misc_thread_posix.h
deleted file mode 100644
index bcc0177..0000000
--- a/c/misc_thread_posix.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- 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/c/misc_win32.h b/c/misc_win32.h
deleted file mode 100644
index 156cf5d..0000000
--- a/c/misc_win32.h
+++ /dev/null
@@ -1,242 +0,0 @@
-#include <malloc.h> /* for alloca() */
-
-
-/************************************************************/
-/* errno and GetLastError support */
-
-#include "misc_thread_common.h"
-
-static DWORD cffi_tls_index = TLS_OUT_OF_INDEXES;
-
-BOOL WINAPI DllMain(HINSTANCE hinstDLL,
- DWORD reason_for_call,
- LPVOID reserved)
-{
- LPVOID p;
-
- switch (reason_for_call) {
-
- case DLL_THREAD_DETACH:
- if (cffi_tls_index != TLS_OUT_OF_INDEXES) {
- p = TlsGetValue(cffi_tls_index);
- if (p != NULL) {
- TlsSetValue(cffi_tls_index, NULL);
- cffi_thread_shutdown(p);
- }
- }
- break;
-
- default:
- break;
- }
- return TRUE;
-}
-
-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);
- 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)
-{
- 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;
-}
diff --git a/c/parse_c_type.c b/c/parse_c_type.c
deleted file mode 100644
index 698ef64..0000000
--- a/c/parse_c_type.c
+++ /dev/null
@@ -1,847 +0,0 @@
-#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;
- 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;
- 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;
- 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;
- _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;
- }
-
- 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:
- 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);
- t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOATCOMPLEX);
- 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);
- }
- if (tok->kind == TOK__COMPLEX)
- {
- if (t1complex == 0)
- return parse_error(tok, "_Complex type combination unsupported");
- 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);
-}
diff --git a/c/realize_c_type.c b/c/realize_c_type.c
deleted file mode 100644
index 82629b7..0000000
--- a/c/realize_c_type.c
+++ /dev/null
@@ -1,820 +0,0 @@
-
-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;
- 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 *
-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;
- }
-
- return x;
-}
-
-static int _realize_recursion_level;
-
-static PyObject *
-realize_c_type_or_func(builder_c_t *builder,
- _cffi_opcode_t opcodes[], int index)
-{
- PyObject *x;
- _cffi_opcode_t op = opcodes[index];
-
- if ((((uintptr_t)op) & 1) == 0) {
- x = (PyObject *)op;
- Py_INCREF(x);
- return x;
- }
-
- if (_realize_recursion_level >= 1000) {
- PyErr_Format(PyExc_RuntimeError,
- "type-building recursion too deep or infinite. "
- "This is known to occur e.g. in ``struct s { void(*callable)"
- "(struct s); }''. Please report if you get this error and "
- "really need support for your case.");
- return NULL;
- }
- _realize_recursion_level++;
- 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]));
- }
-}
-
-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);
- }
- 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;
- }
-}
diff --git a/c/test_c.py b/c/test_c.py
deleted file mode 100644
index 654584d..0000000
--- a/c/test_c.py
+++ /dev/null
@@ -1,4575 +0,0 @@
-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 *
-from _cffi_backend import _get_types, _get_common_types
-try:
- from _cffi_backend import _testfunc
-except ImportError:
- def _testfunc(num):
- pytest.skip("_testunc() not available")
-from _cffi_backend import __version__
-
-# ____________________________________________________________
-
-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
- 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")
- 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)
- 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>"
- 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 (x == cast(p, -66)) is True
- assert (x != cast(p, -66)) is False
- 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
-
- 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"]:
- 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, 0j)) is False
- 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
- 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
- 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, -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, new_primitive_type(name), 1+0j)
- #
- for basetype in ["char", "int", "uint64_t", "float",
- "double", "long double"]:
- baseobj = cast(new_primitive_type(basetype), 65)
- py.test.raises(TypeError, complex, baseobj)
- #
- BArray = new_array_type(new_pointer_type(p), 10)
- x = newp(BArray, None)
- x[5] = 12.34 + 56.78j
- assert type(x[5]) is complex
- assert abs(x[5] - (12.34 + 56.78j)) < 1e-5
- assert (x[5] == 12.34 + 56.78j) == (name == "double") # rounding error
- #
- class Foo:
- def __complex__(self):
- return 2 + 3j
- 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
- 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)
- 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
- 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
- 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 - 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')
- 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')
- 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')
- #
- 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)
- 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
- 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
- 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
- with pytest.raises(IndexError):
- a[42]
- with pytest.raises(IndexError):
- a[-1]
- with pytest.raises(IndexError):
- 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)
- with pytest.raises(TypeError):
- p - q
- with pytest.raises(TypeError):
- q - p
- with pytest.raises(TypeError):
- 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:
- 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)
- p = cast(BStructPtr, 42)
- with pytest.raises(AttributeError) as e:
- p.a1 # opaque
- assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
- "cannot read fields")
- with pytest.raises(AttributeError) as e:
- p.a1 = 10 # opaque
- 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
- with pytest.raises(OverflowError):
- s.a1 = sys.maxsize+1
- assert s.a1 == 0
- with pytest.raises(AttributeError) as e:
- p.foobar
- assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
- with pytest.raises(AttributeError) as e:
- p.foobar = 42
- assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
- with pytest.raises(AttributeError) as e:
- s.foobar
- assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
- with pytest.raises(AttributeError) as e:
- s.foobar = 42
- assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
- j = cast(BInt, 42)
- with pytest.raises(AttributeError) as e:
- j.foobar
- assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
- with pytest.raises(AttributeError) as e:
- j.foobar = 42
- assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
- j = cast(new_pointer_type(BInt), 42)
- with pytest.raises(AttributeError) as e:
- j.foobar
- assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
- with pytest.raises(AttributeError) as e:
- j.foobar = 42
- assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
- pp = newp(new_pointer_type(BStructPtr), p)
- with pytest.raises(AttributeError) as e:
- pp.a1
- assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
- 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_call_function_0_pretend_bool_result():
- BSignedChar = new_primitive_type("signed char")
- BBool = new_primitive_type("_Bool")
- BFunc0 = new_function_type((BSignedChar, BSignedChar), BBool, False)
- f = cast(BFunc0, _testfunc(0))
- assert f(40, -39) is True
- 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_23_bool_array():
- # declaring the function as int(_Bool*)
- BBool = new_primitive_type("_Bool")
- BBoolP = new_pointer_type(BBool)
- BInt = new_primitive_type("int")
- BFunc23 = new_function_type((BBoolP,), BInt, False)
- f = cast(BFunc23, _testfunc(23))
- res = f(b"\x01\x01")
- 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_call_function_24():
- BFloat = new_primitive_type("float")
- BFloatComplex = new_primitive_type("float _Complex")
- BFunc3 = new_function_type((BFloat, BFloat), BFloatComplex, False)
- if 0: # libffi returning nonsense silently, so logic disabled for now
- f = cast(BFunc3, _testfunc(24))
- result = f(1.25, 5.1)
- assert type(result) == complex
- assert result.real == 1.25 # exact
- assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact
- else:
- f = cast(BFunc3, _testfunc(9))
- py.test.raises(NotImplementedError, f, 12.3, 34.5)
-
-def test_call_function_25():
- BDouble = new_primitive_type("double")
- BDoubleComplex = new_primitive_type("double _Complex")
- BFunc3 = new_function_type((BDouble, BDouble), BDoubleComplex, False)
- if 0: # libffi returning nonsense silently, so logic disabled for now
- f = cast(BFunc3, _testfunc(25))
- result = f(1.25, 5.1)
- assert type(result) == complex
- assert result.real == 1.25 # exact
- assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-10) # inexact
- else:
- 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, "?")
- 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. "
- "Such structs are only supported as argument if the function is "
- "'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))
- #
- 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
- #
- 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 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()
- 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
-""", """\
-Exception ignored from cffi callback <function$Zcb1 at 0x$>:
-Traceback (most recent call last):
- File "$", line $, in Zcb1
- $
- 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'
-""", """\
-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$
-""", """\
-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'
-Exception ignored during handling of the above exception by 'onerror':
-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
- # 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
- $
-AttributeError: 'str' object has no attribute 'append$
-""", """\
-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'
-Exception ignored during handling of the above exception by 'onerror':
-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
- 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
- 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
- with pytest.raises(OverflowError):
- p.a1 = 2
- 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
- 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"
- 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)
- 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
- 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)
- 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():
- 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():
- _test_wchar_variant("wchar_t")
- if sys.platform.startswith("linux"):
- BWChar = new_primitive_type("wchar_t")
- assert sizeof(BWChar) == 4
- # wchar_t is often signed on Linux, but not always (e.g. on ARM)
- assert int(cast(BWChar, -1)) in (-1, 4294967295)
-
-def test_char16():
- BChar16 = new_primitive_type("char16_t")
- assert sizeof(BChar16) == 2
- _test_wchar_variant("char16_t")
- assert int(cast(BChar16, -1)) == 0xffff # always unsigned
-
-def test_char32():
- BChar32 = new_primitive_type("char32_t")
- assert sizeof(BChar32) == 4
- _test_wchar_variant("char32_t")
- assert int(cast(BChar32, -1)) == 0xffffffff # always unsigned
-
-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)]
- 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)
- assert str(x) == "<cdata '%s' %s'\U00012345'>" % (
- typename, mandatory_u_prefix)
- 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'
- 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:
- 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:
- 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
- with pytest.raises(IndexError):
- a[4]
- #
- 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 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 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 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 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)
-
-def test_wchar_variants_mix():
- BWChar = new_primitive_type("wchar_t")
- BChar16 = new_primitive_type("char16_t")
- BChar32 = new_primitive_type("char32_t")
- assert int(cast(BChar32, cast(BChar16, -2))) == 0xfffe
- assert int(cast(BWChar, cast(BChar16, -2))) == 0xfffe
- assert int(cast(BChar16, cast(BChar32, 0x0001f345))) == 0xf345
- assert int(cast(BChar16, cast(BWChar, 0x0001f345))) == 0xf345
- #
- BChar16A = new_array_type(new_pointer_type(BChar16), None)
- BChar32A = new_array_type(new_pointer_type(BChar32), None)
- x = cast(BChar32, 'A')
- py.test.raises(TypeError, newp, BChar16A, [x])
- x = cast(BChar16, 'A')
- py.test.raises(TypeError, newp, BChar32A, [x])
- #
- a = newp(BChar16A, u+'\U00012345')
- assert len(a) == 3
- 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)
- with pytest.raises(TypeError):
- p[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
- assert (q == p) is False
- assert (q != p) is True
- if strict_compare:
- with pytest.raises(TypeError): p < q
- with pytest.raises(TypeError): p <= q
- with pytest.raises(TypeError): q < p
- 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"
- 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:
- 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:
- 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"))
- 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():
- 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)
- 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))
- 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
- 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"))
- p = newp(BCharP, b'\x01')
- 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
- 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)
- BBoolA = new_array_type(BBoolP, None)
- BCharP = new_pointer_type(new_primitive_type("char"))
- p = newp(BCharP, b'X')
- q = cast(BBoolP, p)
- with pytest.raises(ValueError):
- q[0]
- py.test.raises(TypeError, newp, BBoolP, b'\x00')
- assert newp(BBoolP, 0)[0] is False
- assert newp(BBoolP, 1)[0] is True
- py.test.raises(OverflowError, newp, BBoolP, 2)
- py.test.raises(OverflowError, newp, BBoolP, -1)
- py.test.raises(ValueError, newp, BBoolA, b'\x00\x01\x02')
- py.test.raises(OverflowError, newp, BBoolA, [0, 1, 2])
- 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
- 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
- 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)
- with pytest.raises(IndexError) as e:
- c[:5]
- 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"
- with pytest.raises(IndexError) as e:
- c[1:2:3]
- 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"
- with pytest.raises(IndexError) as e:
- c[4:2]
- 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]
- with pytest.raises(ValueError):
- cp[-1:1] = [1000]
- 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
- with pytest.raises(IndexError):
- p.y[4]
- with pytest.raises(TypeError):
- p.y = cast(BIntP, 0)
- with pytest.raises(TypeError):
- 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
- #
- # struct of struct of varsized array
- BStruct2 = new_struct_type("bar")
- complete_struct_or_union(BStruct2, [('head', BInt),
- ('tail', BStruct)])
- 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"]
- 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)
- p = newp(BArray, u+"foobar")
- p[2:5] = [u+"*", u+"Z", u+"T"]
- p[1:3] = u+"XY"
- assert list(p) == [u+"f", u+"X", u+"Y", u+"Z", u+"T", u+"r", u+"\x00"]
- with pytest.raises(TypeError):
- 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)
- with pytest.raises(TypeError):
- p - q
- with pytest.raises(TypeError):
- q - p
- with pytest.raises(TypeError):
- 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")
- for extra_args in [(SF_PACKED,), (0, 1)]:
- BStruct = new_struct_type("struct foo")
- complete_struct_or_union(BStruct, [('a1', BLong, -1),
- ('a2', BChar, -1),
- ('a3', BShort, -1)],
- None, -1, -1, *extra_args)
- 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(BChar)
- assert d[2][1].bitshift == -1
- assert d[2][1].bitsize == -1
- assert sizeof(BStruct) == sizeof(BLong) + sizeof(BChar) + sizeof(BShort)
- assert alignof(BStruct) == 1
- #
- BStruct2 = new_struct_type("struct foo")
- complete_struct_or_union(BStruct2, [('b1', BChar, -1),
- ('b2', BLong, -1)],
- None, -1, -1, 0, 2)
- d = BStruct2.fields
- 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[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 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:
- # Python 2 only
- contents = from_buffer(BCharA, buffer(b"foo"))
- assert len(contents) == len(p1)
- for i in range(len(contents)):
- assert contents[i] == p1[i]
- p4 = buffer(u+"foo")
- contents = from_buffer(BCharA, buffer(u+"foo"))
- 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:
- 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_require_writable():
- BChar = new_primitive_type("char")
- BCharP = new_pointer_type(BChar)
- BCharA = new_array_type(BCharP, None)
- p1 = from_buffer(BCharA, b"foo", False)
- assert p1 == from_buffer(BCharA, b"foo", False)
- py.test.raises((TypeError, BufferError), from_buffer, BCharA, b"foo", True)
- ba = bytearray(b"foo")
- p1 = from_buffer(BCharA, ba, True)
- p1[0] = b"g"
- assert ba == b"goo"
-
-def test_from_buffer_types():
- BInt = new_primitive_type("int")
- BIntP = new_pointer_type(BInt)
- BIntA = new_array_type(BIntP, None)
- lst = [-12345678, 87654321, 489148]
- bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ')
- lst2 = lst + [42, -999999999]
- bytestring2 = bytearray(buffer(newp(BIntA, lst2))[:] + b'XYZ')
- #
- p1 = from_buffer(BIntA, bytestring) # int[]
- assert typeof(p1) is BIntA
- assert len(p1) == 3
- assert p1[0] == lst[0]
- assert p1[1] == lst[1]
- assert p1[2] == lst[2]
- with pytest.raises(IndexError):
- p1[3]
- with pytest.raises(IndexError):
- p1[-1]
- #
- py.test.raises(TypeError, from_buffer, BInt, bytestring)
- #
- p2 = from_buffer(BIntP, bytestring) # int *
- assert p2 == p1 or 'PY_DOT_PY' in globals()
- # note: on py.py ^^^, bytearray buffers are not emulated well enough
- assert typeof(p2) is BIntP
- assert p2[0] == lst[0]
- assert p2[1] == lst[1]
- assert p2[2] == lst[2]
- # hopefully does not crash, but doesn't raise an exception:
- p2[3]
- p2[-1]
- # not enough data even for one, but this is not enforced:
- from_buffer(BIntP, b"")
- #
- BIntA2 = new_array_type(BIntP, 2)
- p2 = from_buffer(BIntA2, bytestring) # int[2]
- assert typeof(p2) is BIntA2
- assert len(p2) == 2
- assert p2[0] == lst[0]
- assert p2[1] == lst[1]
- with pytest.raises(IndexError):
- p2[2]
- with pytest.raises(IndexError):
- p2[-1]
- assert p2 == p1 or 'PY_DOT_PY' in globals()
- #
- BIntA4 = new_array_type(BIntP, 4) # int[4]: too big
- py.test.raises(ValueError, from_buffer, BIntA4, bytestring)
- #
- BStruct = new_struct_type("foo")
- complete_struct_or_union(BStruct, [('a1', BInt, -1),
- ('a2', BInt, -1)])
- BStructP = new_pointer_type(BStruct)
- BStructA = new_array_type(BStructP, None)
- p1 = from_buffer(BStructA, bytestring2) # struct[]
- assert len(p1) == 2
- assert typeof(p1) is BStructA
- assert p1[0].a1 == lst2[0]
- assert p1[0].a2 == lst2[1]
- assert p1[1].a1 == lst2[2]
- assert p1[1].a2 == lst2[3]
- with pytest.raises(IndexError):
- p1[2]
- with pytest.raises(IndexError):
- p1[-1]
- assert repr(p1) == "<cdata 'foo[]' buffer len 2 from 'bytearray' object>"
- #
- p2 = from_buffer(BStructP, bytestring2) # 'struct *'
- assert p2 == p1 or 'PY_DOT_PY' in globals()
- assert typeof(p2) is BStructP
- assert p2.a1 == lst2[0]
- assert p2.a2 == lst2[1]
- assert p2[0].a1 == lst2[0]
- assert p2[0].a2 == lst2[1]
- assert p2[1].a1 == lst2[2]
- assert p2[1].a2 == lst2[3]
- # does not crash:
- p2[2]
- p2[-1]
- # not enough data even for one, but this is not enforced:
- from_buffer(BStructP, b"")
- from_buffer(BStructP, b"1234567")
- #
- release(p1)
- assert repr(p1) == "<cdata 'foo[]' buffer RELEASED>"
- #
- BEmptyStruct = new_struct_type("empty")
- complete_struct_or_union(BEmptyStruct, [], Ellipsis, 0)
- assert sizeof(BEmptyStruct) == 0
- BEmptyStructP = new_pointer_type(BEmptyStruct)
- BEmptyStructA = new_array_type(BEmptyStructP, None)
- py.test.raises(ZeroDivisionError, from_buffer, # empty[]
- BEmptyStructA, bytestring)
- #
- BEmptyStructA5 = new_array_type(BEmptyStructP, 5)
- p1 = from_buffer(BEmptyStructA5, bytestring) # struct empty[5]
- assert typeof(p1) is BEmptyStructA5
- assert len(p1) == 5
- assert (cast(BIntP, p1) == from_buffer(BIntA, bytestring)
- or 'PY_DOT_PY' in globals())
- #
- BVarStruct = new_struct_type("varfoo")
- BVarStructP = new_pointer_type(BVarStruct)
- complete_struct_or_union(BVarStruct, [('a1', BInt, -1),
- ('va', BIntA, -1)])
- with pytest.raises(TypeError):
- from_buffer(BVarStruct, bytestring)
- pv = from_buffer(BVarStructP, bytestring) # varfoo *
- assert pv.a1 == lst[0]
- assert pv.va[0] == lst[1]
- assert pv.va[1] == lst[2]
- assert sizeof(pv[0]) == 1 * size_of_int()
- with pytest.raises(TypeError):
- len(pv.va)
- # hopefully does not crash, but doesn't raise an exception:
- pv.va[2]
- pv.va[-1]
- # not enough data even for one, but this is not enforced:
- from_buffer(BVarStructP, b"")
- assert repr(pv) == "<cdata 'varfoo *' buffer from 'bytearray' object>"
- assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
- #
- release(pv)
- assert repr(pv) == "<cdata 'varfoo *' buffer RELEASED>"
- assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
- #
- pv = from_buffer(BVarStructP, bytestring) # make a fresh one
- with pytest.raises(ValueError):
- release(pv[0])
-
-def test_issue483():
- BInt = new_primitive_type("int")
- BIntP = new_pointer_type(BInt)
- BIntA = new_array_type(BIntP, None)
- lst = list(range(25))
- bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ')
- p1 = from_buffer(BIntA, bytestring) # int[]
- assert len(buffer(p1)) == 25 * size_of_int()
- assert sizeof(p1) == 25 * size_of_int()
- #
- p2 = from_buffer(BIntP, bytestring)
- 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)
- with pytest.raises(RuntimeError):
- p[0]
- with pytest.raises(RuntimeError):
- p[0] = 42
- with pytest.raises(RuntimeError):
- 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]
- 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 *'")
- 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"
-
- 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]),
- ("_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])
- 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
- 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())
- BUCharP = new_pointer_type(new_primitive_type("unsigned char"))
- z1 = cast(BCharP, 0)
- z2 = cast(BIntP, 0)
- z3 = cast(BVoidP, 0)
- z4 = cast(BUCharP, 0)
- 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(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
-
-def test_primitive_comparison():
- def assert_eq(a, b):
- assert (a == b) is True
- assert (b == a) is True
- assert (a != b) is False
- assert (b != a) is False
- assert (a < b) is False
- assert (a <= b) is True
- assert (a > b) is False
- assert (a >= b) is True
- assert (b < a) is False
- assert (b <= a) is True
- assert (b > a) is False
- assert (b >= a) is True
- assert hash(a) == hash(b)
- def assert_lt(a, b, check_hash=True):
- assert (a == b) is False
- assert (b == a) is False
- assert (a != b) is True
- assert (b != a) is True
- assert (a < b) is True
- assert (a <= b) is True
- assert (a > b) is False
- assert (a >= b) is False
- assert (b < a) is False
- assert (b <= a) is False
- assert (b > a) is True
- assert (b >= a) is True
- if check_hash:
- assert hash(a) != hash(b) # (or at least, it is unlikely)
- def assert_gt(a, b, check_hash=True):
- assert_lt(b, a, check_hash)
- def assert_ne(a, b):
- assert (a == b) is False
- assert (b == a) is False
- assert (a != b) is True
- assert (b != a) is True
- if strict_compare:
- with pytest.raises(TypeError): a < b
- with pytest.raises(TypeError): a <= b
- with pytest.raises(TypeError): a > b
- with pytest.raises(TypeError): a >= b
- with pytest.raises(TypeError): b < a
- with pytest.raises(TypeError): b <= a
- with pytest.raises(TypeError): b > a
- with pytest.raises(TypeError): b >= a
- elif a < b:
- assert_lt(a, b)
- else:
- assert_lt(b, a)
- assert_eq(5, 5)
- assert_lt(3, 5)
- assert_ne('5', 5)
- #
- t1 = new_primitive_type("char")
- t2 = new_primitive_type("int")
- t3 = new_primitive_type("unsigned char")
- t4 = new_primitive_type("unsigned int")
- t5 = new_primitive_type("float")
- t6 = new_primitive_type("double")
- assert_eq(cast(t1, 65), b'A')
- assert_lt(cast(t1, 64), b'\x99')
- assert_gt(cast(t1, 200), b'A')
- assert_ne(cast(t1, 65), 65)
- assert_eq(cast(t2, -25), -25)
- assert_lt(cast(t2, -25), -24)
- assert_gt(cast(t2, -25), -26)
- assert_eq(cast(t3, 65), 65)
- assert_ne(cast(t3, 65), b'A')
- assert_ne(cast(t3, 65), cast(t1, 65))
- assert_gt(cast(t4, -1), -1, check_hash=False)
- assert_gt(cast(t4, -1), cast(t2, -1), check_hash=False)
- assert_gt(cast(t4, -1), 99999)
- assert_eq(cast(t4, -1), 256 ** size_of_int() - 1)
- assert_eq(cast(t5, 3.0), 3)
- assert_eq(cast(t5, 3.5), 3.5)
- assert_lt(cast(t5, 3.3), 3.3) # imperfect rounding
- assert_eq(cast(t6, 3.3), 3.3)
- assert_eq(cast(t5, 3.5), cast(t6, 3.5))
- assert_lt(cast(t5, 3.1), cast(t6, 3.1)) # imperfect rounding
- assert_eq(cast(t5, 7.0), cast(t3, 7))
- assert_lt(cast(t5, 3.1), 3.101)
- assert_gt(cast(t5, 3.1), 3)
-
-def test_explicit_release_new():
- # release() on a ffi.new() object has no effect on CPython, but
- # really releases memory on PyPy. We can't test that effect
- # though, because a released cdata is not marked.
- BIntP = new_pointer_type(new_primitive_type("int"))
- p = newp(BIntP)
- p[0] = 42
- with pytest.raises(IndexError):
- p[1]
- release(p)
- # here, reading p[0] might give garbage or segfault...
- release(p) # no effect
- #
- BStruct = new_struct_type("struct foo")
- BStructP = new_pointer_type(BStruct)
- complete_struct_or_union(BStruct, [('p', BIntP, -1)])
- pstruct = newp(BStructP)
- assert pstruct.p == cast(BIntP, 0)
- release(pstruct)
- # here, reading pstruct.p might give garbage or segfault...
- release(pstruct) # no effect
-
-def test_explicit_release_new_contextmgr():
- BIntP = new_pointer_type(new_primitive_type("int"))
- with newp(BIntP) as p:
- p[0] = 42
- assert p[0] == 42
- # here, reading p[0] might give garbage or segfault...
- release(p) # no effect
-
-def test_explicit_release_badtype():
- BIntP = new_pointer_type(new_primitive_type("int"))
- p = cast(BIntP, 12345)
- py.test.raises(ValueError, release, p)
- py.test.raises(ValueError, release, p)
- BStruct = new_struct_type("struct foo")
- BStructP = new_pointer_type(BStruct)
- complete_struct_or_union(BStruct, [('p', BIntP, -1)])
- pstruct = newp(BStructP)
- py.test.raises(ValueError, release, pstruct[0])
-
-def test_explicit_release_badtype_contextmgr():
- BIntP = new_pointer_type(new_primitive_type("int"))
- p = cast(BIntP, 12345)
- with pytest.raises(ValueError):
- with p:
- pass
- with pytest.raises(ValueError):
- with p:
- pass
-
-def test_explicit_release_gc():
- BIntP = new_pointer_type(new_primitive_type("int"))
- seen = []
- intp1 = newp(BIntP, 12345)
- p1 = cast(BIntP, intp1)
- p = gcp(p1, seen.append)
- assert seen == []
- release(p)
- assert seen == [p1]
- assert p1[0] == 12345
- assert p[0] == 12345 # true so far, but might change to raise RuntimeError
- release(p) # no effect
-
-def test_explicit_release_gc_contextmgr():
- BIntP = new_pointer_type(new_primitive_type("int"))
- seen = []
- intp1 = newp(BIntP, 12345)
- p1 = cast(BIntP, intp1)
- p = gcp(p1, seen.append)
- with p:
- assert p[0] == 12345
- assert seen == []
- assert seen == [p1]
- assert p1[0] == 12345
- assert p[0] == 12345 # true so far, but might change to raise RuntimeError
- release(p) # no effect
-
-def test_explicit_release_from_buffer():
- 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 p[2] == b"z"
- assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
- release(p)
- assert p[2] == b"z" # true so far, but might change to raise RuntimeError
- assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
- release(p) # no effect
-
-def test_explicit_release_from_buffer_contextmgr():
- 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)
- with p:
- assert p[2] == b"z"
- assert p[2] == b"z" # true so far, but might change to raise RuntimeError
- assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
- release(p) # no effect
-
-def test_explicit_release_bytearray_on_cpython():
- if '__pypy__' in sys.builtin_module_names:
- py.test.skip("pypy's bytearray are never locked")
- a = bytearray(b"xyz")
- BChar = new_primitive_type("char")
- BCharP = new_pointer_type(BChar)
- BCharA = new_array_type(BCharP, None)
- a += b't' * 10
- p = from_buffer(BCharA, a)
- with pytest.raises(BufferError):
- a += b'u' * 100
- release(p)
- a += b'v' * 100
- release(p) # no effect
- a += b'w' * 1000
- assert a == bytearray(b"xyz" + b't' * 10 + b'v' * 100 + b'w' * 1000)
-
-def test_int_doesnt_give_bool():
- BBool = new_primitive_type("_Bool")
- x = int(cast(BBool, 42))
- assert type(x) is int and x == 1
- x = long(cast(BBool, 42))
- assert type(x) is long and x == 1
- with pytest.raises(TypeError):
- float(cast(BBool, 42))
- with pytest.raises(TypeError):
- complex(cast(BBool, 42))
-
-def test_cannot_call_null_function_pointer():
- BInt = new_primitive_type("int")
- BFunc = new_function_type((BInt, BInt), BInt, False)
- f = cast(BFunc, 0)
- with pytest.raises(RuntimeError):
- f(40, 2)
-
-def test_huge_structure():
- BChar = new_primitive_type("char")
- BArray = new_array_type(new_pointer_type(BChar), sys.maxsize)
- assert sizeof(BArray) == sys.maxsize
- BStruct = new_struct_type("struct foo")
- complete_struct_or_union(BStruct, [('a1', BArray, -1)])
- assert sizeof(BStruct) == sys.maxsize
-
-def test_get_types():
- import _cffi_backend
- CData, CType = _get_types()
- assert CData is _cffi_backend._CDataBase
- assert CType is _cffi_backend.CType
-
-def test_type_available_with_correct_names():
- import _cffi_backend
- check_names = [
- 'CType',
- 'CField',
- 'CLibrary',
- '_CDataBase',
- 'FFI',
- 'Lib',
- 'buffer',
- ]
- if '__pypy__' in sys.builtin_module_names:
- check_names += [
- '__CData_iterator',
- '__FFIGlobSupport',
- '__FFIAllocator',
- '__FFIFunctionWrapper',
- ]
- else:
- check_names += [
- '__CDataOwn',
- '__CDataOwnGC',
- '__CDataFromBuf',
- '__CDataGCP',
- '__CData_iterator',
- '__FFIGlobSupport',
- ]
- for name in check_names:
- tp = getattr(_cffi_backend, name)
- assert isinstance(tp, type)
- assert (tp.__module__, tp.__name__) == ('_cffi_backend', name)
-
-def test_unaligned_types():
- BByteArray = new_array_type(
- new_pointer_type(new_primitive_type("unsigned char")), None)
- pbuf = newp(BByteArray, 40)
- buf = buffer(pbuf)
- #
- for name in ['short', 'int', 'long', 'long long', 'float', 'double',
- 'float _Complex', 'double _Complex']:
- p = new_primitive_type(name)
- if name.endswith(' _Complex'):
- num = cast(p, 1.23 - 4.56j)
- else:
- num = cast(p, 0x0123456789abcdef)
- size = sizeof(p)
- buf[0:40] = b"\x00" * 40
- pbuf1 = cast(new_pointer_type(p), pbuf + 1)
- pbuf1[0] = num
- assert pbuf1[0] == num
- assert buf[0] == b'\x00'
- assert buf[1 + size] == b'\x00'
diff --git a/c/wchar_helper.h b/c/wchar_helper.h
deleted file mode 100644
index 8e6ea58..0000000
--- a/c/wchar_helper.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * 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.
-
- From cffi 1.11 we can't use it anyway, because we need a version
- with char32_t input types.
-*/
-static PyObject *
-_my_PyUnicode_FromChar32(const cffi_char32_t *w, Py_ssize_t size)
-{
- PyObject *unicode;
- register Py_ssize_t i;
- 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 */
- {
- register Py_UNICODE *u;
- 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,
- "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;
-}
-
-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)
-{
- return PyUnicode_FromUnicode((const Py_UNICODE *)w, size);
-}
-
-static PyObject *
-_my_PyUnicode_FromChar16(const cffi_char16_t *w, Py_ssize_t size)
-{
- /* 'size' is the length of the 'w' array */
- PyObject *result = PyUnicode_FromUnicode(NULL, size);
-
- if (result != NULL) {
- Py_UNICODE *u_base = PyUnicode_AS_UNICODE(result);
- Py_UNICODE *u = u_base;
-
- if (size == 1) { /* performance only */
- *u = (cffi_char32_t)*w;
- }
- else {
- while (size > 0) {
- cffi_char32_t ch = *w++;
- size--;
- if (0xD800 <= ch && ch <= 0xDBFF && size > 0) {
- cffi_char32_t ch2 = *w;
- if (0xDC00 <= ch2 && ch2 <= 0xDFFF) {
- ch = (((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x10000;
- w++;
- size--;
- }
- }
- *u++ = ch;
- }
- if (PyUnicode_Resize(&result, u - u_base) < 0) {
- Py_DECREF(result);
- return NULL;
- }
- }
- }
- 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))
-
-static int
-_my_PyUnicode_AsSingleChar16(PyObject *unicode, cffi_char16_t *result,
- char *err_got)
-{
- 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));
- return -1;
- }
-#if Py_UNICODE_SIZE == 4
- if (((unsigned int)u[0]) > 0xFFFF)
- {
- sprintf(err_got, "larger-than-0xFFFF character");
- return -1;
- }
-#endif
- *result = (cffi_char16_t)u[0];
- return 0;
-}
-
-static int
-_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) {
- *result = (cffi_char32_t)u[0];
- return 0;
- }
-#if Py_UNICODE_SIZE == 2
- 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;
-}
-
-static Py_ssize_t _my_PyUnicode_SizeAsChar16(PyObject *unicode)
-{
- 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;
-
- for (i=0; i<length; i++) {
- if (u[i] > 0xFFFF)
- result++;
- }
-#endif
- return result;
-}
-
-static Py_ssize_t _my_PyUnicode_SizeAsChar32(PyObject *unicode)
-{
- Py_ssize_t length = PyUnicode_GET_SIZE(unicode);
- Py_ssize_t result = length;
-
-#if Py_UNICODE_SIZE == 2
- 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;
-}
-
-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;
- for (i=0; i<len; i++) {
-#if Py_UNICODE_SIZE == 2
- cffi_char16_t ordinal = u[i];
-#else
- cffi_char32_t ordinal = u[i];
- if (ordinal > 0xFFFF) {
- if (ordinal > 0x10FFFF) {
- PyErr_Format(PyExc_ValueError,
- "unicode character out of range for "
- "conversion to char16_t: 0x%x", (int)ordinal);
- return -1;
- }
- ordinal -= 0x10000;
- *result++ = 0xD800 | (ordinal >> 10);
- *result++ = 0xDC00 | (ordinal & 0x3FF);
- continue;
- }
-#endif
- *result++ = ordinal;
- }
- return 0;
-}
-
-static int _my_PyUnicode_AsChar32(PyObject *unicode,
- cffi_char32_t *result,
- Py_ssize_t resultlen)
-{
- Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode);
- Py_ssize_t 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++;
- }
- return 0;
-}
diff --git a/c/wchar_helper_3.h b/c/wchar_helper_3.h
deleted file mode 100644
index f15464e..0000000
--- a/c/wchar_helper_3.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * wchar_t helpers, version CPython >= 3.3.
- *
- * CPython 3.3 added support for sys.maxunicode == 0x10FFFF on all
- * platforms, even ones with wchar_t limited to 2 bytes. As such,
- * this code here works from the outside like wchar_helper.h in the
- * case Py_UNICODE_SIZE == 4, but the implementation is very different.
- */
-
-typedef uint16_t cffi_char16_t;
-typedef uint32_t cffi_char32_t;
-
-
-static PyObject *
-_my_PyUnicode_FromChar32(const cffi_char32_t *w, Py_ssize_t size)
-{
- return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, w, size);
-}
-
-static PyObject *
-_my_PyUnicode_FromChar16(const cffi_char16_t *w, Py_ssize_t size)
-{
- /* are there any surrogate pairs, and if so, how many? */
- Py_ssize_t i, count_surrogates = 0;
- for (i = 0; i < size - 1; i++) {
- if (0xD800 <= w[i] && w[i] <= 0xDBFF &&
- 0xDC00 <= w[i+1] && w[i+1] <= 0xDFFF)
- count_surrogates++;
- }
- if (count_surrogates == 0) {
- /* no, fast path */
- return PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, w, size);
- }
- else
- {
- PyObject *result = PyUnicode_New(size - count_surrogates, 0x10FFFF);
- Py_UCS4 *data;
- assert(PyUnicode_KIND(result) == PyUnicode_4BYTE_KIND);
- data = PyUnicode_4BYTE_DATA(result);
-
- for (i = 0; i < size; i++)
- {
- cffi_char32_t ch = w[i];
- if (0xD800 <= ch && ch <= 0xDBFF && i < size - 1) {
- cffi_char32_t ch2 = w[i + 1];
- if (0xDC00 <= ch2 && ch2 <= 0xDFFF) {
- ch = (((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x10000;
- i++;
- }
- }
- *data++ = ch;
- }
- return result;
- }
-}
-
-static int
-_my_PyUnicode_AsSingleChar16(PyObject *unicode, cffi_char16_t *result,
- char *err_got)
-{
- cffi_char32_t ch;
- if (PyUnicode_GET_LENGTH(unicode) != 1) {
- sprintf(err_got, "unicode string of length %zd",
- PyUnicode_GET_LENGTH(unicode));
- return -1;
- }
- ch = PyUnicode_READ_CHAR(unicode, 0);
-
- if (ch > 0xFFFF)
- {
- sprintf(err_got, "larger-than-0xFFFF character");
- return -1;
- }
- *result = (cffi_char16_t)ch;
- return 0;
-}
-
-static int
-_my_PyUnicode_AsSingleChar32(PyObject *unicode, cffi_char32_t *result,
- char *err_got)
-{
- if (PyUnicode_GET_LENGTH(unicode) != 1) {
- sprintf(err_got, "unicode string of length %zd",
- PyUnicode_GET_LENGTH(unicode));
- return -1;
- }
- *result = PyUnicode_READ_CHAR(unicode, 0);
- return 0;
-}
-
-static Py_ssize_t _my_PyUnicode_SizeAsChar16(PyObject *unicode)
-{
- Py_ssize_t length = PyUnicode_GET_LENGTH(unicode);
- Py_ssize_t result = length;
- unsigned int kind = PyUnicode_KIND(unicode);
-
- if (kind == PyUnicode_4BYTE_KIND)
- {
- Py_UCS4 *data = PyUnicode_4BYTE_DATA(unicode);
- Py_ssize_t i;
- for (i = 0; i < length; i++) {
- if (data[i] > 0xFFFF)
- result++;
- }
- }
- return result;
-}
-
-static Py_ssize_t _my_PyUnicode_SizeAsChar32(PyObject *unicode)
-{
- return PyUnicode_GET_LENGTH(unicode);
-}
-
-static int _my_PyUnicode_AsChar16(PyObject *unicode,
- cffi_char16_t *result,
- Py_ssize_t resultlen)
-{
- Py_ssize_t len = PyUnicode_GET_LENGTH(unicode);
- unsigned int kind = PyUnicode_KIND(unicode);
- void *data = PyUnicode_DATA(unicode);
- Py_ssize_t i;
-
- for (i = 0; i < len; i++) {
- cffi_char32_t ordinal = PyUnicode_READ(kind, data, i);
- if (ordinal > 0xFFFF) {
- if (ordinal > 0x10FFFF) {
- PyErr_Format(PyExc_ValueError,
- "unicode character out of range for "
- "conversion to char16_t: 0x%x", (int)ordinal);
- return -1;
- }
- ordinal -= 0x10000;
- *result++ = 0xD800 | (ordinal >> 10);
- *result++ = 0xDC00 | (ordinal & 0x3FF);
- }
- else
- *result++ = ordinal;
- }
- return 0;
-}
-
-static int _my_PyUnicode_AsChar32(PyObject *unicode,
- cffi_char32_t *result,
- Py_ssize_t resultlen)
-{
- if (PyUnicode_AsUCS4(unicode, (Py_UCS4 *)result, resultlen, 0) == NULL)
- return -1;
- return 0;
-}
diff --git a/cffi/Android.bp b/cffi/Android.bp
deleted file mode 100644
index 2664d94..0000000
--- a/cffi/Android.bp
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "external_python_cffi_license"
- // to get the below license kinds:
- // SPDX-license-identifier-MIT
- default_applicable_licenses: ["external_python_cffi_license"],
-}
-
-python_library {
- name: "py-cffi",
- host_supported: true,
- srcs: [
- "*.py",
- ],
- data: [
- ":py-cffi-headers",
- ],
- libs: [
- "py-cffi-backend",
- "py-cffi-backend-libffi",
- "py-pycparser",
- ],
- pkg_path: "cffi",
-}
-
-filegroup {
- name: "py-cffi-headers",
- srcs: [
- "*.h",
- ],
-}
diff --git a/cffi/__init__.py b/cffi/__init__.py
deleted file mode 100644
index 82a9618..0000000
--- a/cffi/__init__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
- 'FFIError']
-
-from .api import FFI
-from .error import CDefError, FFIError, VerificationError, VerificationMissing
-from .error import PkgConfigError
-
-__version__ = "1.15.0"
-__version_info__ = (1, 15, 0)
-
-# 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__
-# if nothing is clearly incompatible.
-__version_verifier_modules__ = "0.8.6"
diff --git a/cffi/_cffi_errors.h b/cffi/_cffi_errors.h
deleted file mode 100644
index 158e059..0000000
--- a/cffi/_cffi_errors.h
+++ /dev/null
@@ -1,149 +0,0 @@
-#ifndef CFFI_MESSAGEBOX
-# ifdef _MSC_VER
-# define CFFI_MESSAGEBOX 1
-# else
-# define CFFI_MESSAGEBOX 0
-# endif
-#endif
-
-
-#if CFFI_MESSAGEBOX
-/* Windows only: logic to take the Python-CFFI embedding logic
- initialization errors and display them in a background thread
- with MessageBox. The idea is that if the whole program closes
- as a result of this problem, then likely it is already a console
- program and you can read the stderr output in the console too.
- If it is not a console program, then it will likely show its own
- dialog to complain, or generally not abruptly close, and for this
- case the background thread should stay alive.
-*/
-static void *volatile _cffi_bootstrap_text;
-
-static PyObject *_cffi_start_error_capture(void)
-{
- PyObject *result = NULL;
- PyObject *x, *m, *bi;
-
- if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text,
- (void *)1, NULL) != NULL)
- return (PyObject *)1;
-
- m = PyImport_AddModule("_cffi_error_capture");
- if (m == NULL)
- goto error;
-
- result = PyModule_GetDict(m);
- if (result == NULL)
- goto error;
-
-#if PY_MAJOR_VERSION >= 3
- bi = PyImport_ImportModule("builtins");
-#else
- bi = PyImport_ImportModule("__builtin__");
-#endif
- if (bi == NULL)
- goto error;
- PyDict_SetItemString(result, "__builtins__", bi);
- Py_DECREF(bi);
-
- x = PyRun_String(
- "import sys\n"
- "class FileLike:\n"
- " def write(self, x):\n"
- " try:\n"
- " of.write(x)\n"
- " except: pass\n"
- " self.buf += x\n"
- " def flush(self):\n"
- " pass\n"
- "fl = FileLike()\n"
- "fl.buf = ''\n"
- "of = sys.stderr\n"
- "sys.stderr = fl\n"
- "def done():\n"
- " sys.stderr = of\n"
- " return fl.buf\n", /* make sure the returned value stays alive */
- Py_file_input,
- result, result);
- Py_XDECREF(x);
-
- error:
- if (PyErr_Occurred())
- {
- PyErr_WriteUnraisable(Py_None);
- PyErr_Clear();
- }
- return result;
-}
-
-#pragma comment(lib, "user32.lib")
-
-static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored)
-{
- Sleep(666); /* may be interrupted if the whole process is closing */
-#if PY_MAJOR_VERSION >= 3
- MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text,
- L"Python-CFFI error",
- MB_OK | MB_ICONERROR);
-#else
- MessageBoxA(NULL, (char *)_cffi_bootstrap_text,
- "Python-CFFI error",
- MB_OK | MB_ICONERROR);
-#endif
- _cffi_bootstrap_text = NULL;
- return 0;
-}
-
-static void _cffi_stop_error_capture(PyObject *ecap)
-{
- PyObject *s;
- void *text;
-
- if (ecap == (PyObject *)1)
- return;
-
- if (ecap == NULL)
- goto error;
-
- s = PyRun_String("done()", Py_eval_input, ecap, ecap);
- if (s == NULL)
- goto error;
-
- /* Show a dialog box, but in a background thread, and
- never show multiple dialog boxes at once. */
-#if PY_MAJOR_VERSION >= 3
- text = PyUnicode_AsWideCharString(s, NULL);
-#else
- text = PyString_AsString(s);
-#endif
-
- _cffi_bootstrap_text = text;
-
- if (text != NULL)
- {
- HANDLE h;
- h = CreateThread(NULL, 0, _cffi_bootstrap_dialog,
- NULL, 0, NULL);
- if (h != NULL)
- CloseHandle(h);
- }
- /* decref the string, but it should stay alive as 'fl.buf'
- in the small module above. It will really be freed only if
- we later get another similar error. So it's a leak of at
- most one copy of the small module. That's fine for this
- situation which is usually a "fatal error" anyway. */
- Py_DECREF(s);
- PyErr_Clear();
- return;
-
- error:
- _cffi_bootstrap_text = NULL;
- PyErr_Clear();
-}
-
-#else
-
-static PyObject *_cffi_start_error_capture(void) { return NULL; }
-static void _cffi_stop_error_capture(PyObject *ecap) { }
-
-#endif
diff --git a/cffi/_cffi_include.h b/cffi/_cffi_include.h
deleted file mode 100644
index e4c0a67..0000000
--- a/cffi/_cffi_include.h
+++ /dev/null
@@ -1,385 +0,0 @@
-#define _CFFI_
-
-/* We try to define Py_LIMITED_API before including Python.h.
-
- Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and
- Py_REF_DEBUG are not defined. This is a best-effort approximation:
- we can learn about Py_DEBUG from pyconfig.h, but it is unclear if
- the same works for the other two macros. Py_DEBUG implies them,
- but not the other way around.
-
- The implementation is messy (issue #350): on Windows, with _MSC_VER,
- we have to define Py_LIMITED_API even before including pyconfig.h.
- In that case, we guess what pyconfig.h will do to the macros above,
- and check our guess after the #include.
-
- Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv
- version >= 16.0.0. With older versions of either, you don't get a
- copy of PYTHON3.DLL in the virtualenv. We can't check the version of
- CPython *before* we even include pyconfig.h. ffi.set_source() puts
- a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is
- running on Windows < 3.5, as an attempt at fixing it, but that's
- arguably wrong because it may not be the target version of Python.
- Still better than nothing I guess. As another workaround, you can
- remove the definition of Py_LIMITED_API here.
-
- See also 'py_limited_api' in cffi/setuptools_ext.py.
-*/
-#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API)
-# ifdef _MSC_VER
-# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API)
-# define Py_LIMITED_API
-# endif
-# include <pyconfig.h>
- /* sanity-check: Py_LIMITED_API will cause crashes if any of these
- are also defined. Normally, the Python file PC/pyconfig.h does not
- cause any of these to be defined, with the exception that _DEBUG
- causes Py_DEBUG. Double-check that. */
-# ifdef Py_LIMITED_API
-# if defined(Py_DEBUG)
-# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set"
-# endif
-# if defined(Py_TRACE_REFS)
-# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set"
-# endif
-# if defined(Py_REF_DEBUG)
-# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set"
-# endif
-# endif
-# else
-# include <pyconfig.h>
-# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API)
-# define Py_LIMITED_API
-# endif
-# endif
-#endif
-
-#include <Python.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include <stddef.h>
-#include "parse_c_type.h"
-
-/* this block of #ifs should be kept exactly identical between
- c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
- and cffi/_cffi_include.h */
-#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 */
-# ifndef __cplusplus
- typedef unsigned char _Bool;
-# endif
-# endif
-#else
-# include <stdint.h>
-# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
-# include <alloca.h>
-# endif
-#endif
-
-#ifdef __GNUC__
-# define _CFFI_UNUSED_FN __attribute__((unused))
-#else
-# define _CFFI_UNUSED_FN /* nothing */
-#endif
-
-#ifdef __cplusplus
-# ifndef _Bool
- typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */
-# endif
-#endif
-
-/********** CPython-specific section **********/
-#ifndef PYPY_VERSION
-
-
-#if PY_MAJOR_VERSION >= 3
-# define PyInt_FromLong PyLong_FromLong
-#endif
-
-#define _cffi_from_c_double PyFloat_FromDouble
-#define _cffi_from_c_float PyFloat_FromDouble
-#define _cffi_from_c_long PyInt_FromLong
-#define _cffi_from_c_ulong PyLong_FromUnsignedLong
-#define _cffi_from_c_longlong PyLong_FromLongLong
-#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
-#define _cffi_from_c__Bool PyBool_FromLong
-
-#define _cffi_to_c_double PyFloat_AsDouble
-#define _cffi_to_c_float PyFloat_AsDouble
-
-#define _cffi_from_c_int(x, type) \
- (((type)-1) > 0 ? /* unsigned */ \
- (sizeof(type) < sizeof(long) ? \
- PyInt_FromLong((long)x) : \
- sizeof(type) == sizeof(long) ? \
- PyLong_FromUnsignedLong((unsigned long)x) : \
- PyLong_FromUnsignedLongLong((unsigned long long)x)) : \
- (sizeof(type) <= sizeof(long) ? \
- PyInt_FromLong((long)x) : \
- PyLong_FromLongLong((long long)x)))
-
-#define _cffi_to_c_int(o, type) \
- ((type)( \
- sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
- : (type)_cffi_to_c_i8(o)) : \
- sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \
- : (type)_cffi_to_c_i16(o)) : \
- sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \
- : (type)_cffi_to_c_i32(o)) : \
- sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \
- : (type)_cffi_to_c_i64(o)) : \
- (Py_FatalError("unsupported size for type " #type), (type)0)))
-
-#define _cffi_to_c_i8 \
- ((int(*)(PyObject *))_cffi_exports[1])
-#define _cffi_to_c_u8 \
- ((int(*)(PyObject *))_cffi_exports[2])
-#define _cffi_to_c_i16 \
- ((int(*)(PyObject *))_cffi_exports[3])
-#define _cffi_to_c_u16 \
- ((int(*)(PyObject *))_cffi_exports[4])
-#define _cffi_to_c_i32 \
- ((int(*)(PyObject *))_cffi_exports[5])
-#define _cffi_to_c_u32 \
- ((unsigned int(*)(PyObject *))_cffi_exports[6])
-#define _cffi_to_c_i64 \
- ((long long(*)(PyObject *))_cffi_exports[7])
-#define _cffi_to_c_u64 \
- ((unsigned long long(*)(PyObject *))_cffi_exports[8])
-#define _cffi_to_c_char \
- ((int(*)(PyObject *))_cffi_exports[9])
-#define _cffi_from_c_pointer \
- ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10])
-#define _cffi_to_c_pointer \
- ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11])
-#define _cffi_get_struct_layout \
- not used any more
-#define _cffi_restore_errno \
- ((void(*)(void))_cffi_exports[13])
-#define _cffi_save_errno \
- ((void(*)(void))_cffi_exports[14])
-#define _cffi_from_c_char \
- ((PyObject *(*)(char))_cffi_exports[15])
-#define _cffi_from_c_deref \
- ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16])
-#define _cffi_to_c \
- ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17])
-#define _cffi_from_c_struct \
- ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18])
-#define _cffi_to_c_wchar_t \
- ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19])
-#define _cffi_from_c_wchar_t \
- ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20])
-#define _cffi_to_c_long_double \
- ((long double(*)(PyObject *))_cffi_exports[21])
-#define _cffi_to_c__Bool \
- ((_Bool(*)(PyObject *))_cffi_exports[22])
-#define _cffi_prepare_pointer_call_argument \
- ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \
- PyObject *, char **))_cffi_exports[23])
-#define _cffi_convert_array_from_object \
- ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24])
-#define _CFFI_CPIDX 25
-#define _cffi_call_python \
- ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX])
-#define _cffi_to_c_wchar3216_t \
- ((int(*)(PyObject *))_cffi_exports[26])
-#define _cffi_from_c_wchar3216_t \
- ((PyObject *(*)(int))_cffi_exports[27])
-#define _CFFI_NUM_EXPORTS 28
-
-struct _cffi_ctypedescr;
-
-static void *_cffi_exports[_CFFI_NUM_EXPORTS];
-
-#define _cffi_type(index) ( \
- assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \
- (struct _cffi_ctypedescr *)_cffi_types[index])
-
-static PyObject *_cffi_init(const char *module_name, Py_ssize_t version,
- const struct _cffi_type_context_s *ctx)
-{
- PyObject *module, *o_arg, *new_module;
- void *raw[] = {
- (void *)module_name,
- (void *)version,
- (void *)_cffi_exports,
- (void *)ctx,
- };
-
- module = PyImport_ImportModule("_cffi_backend");
- if (module == NULL)
- goto failure;
-
- o_arg = PyLong_FromVoidPtr((void *)raw);
- if (o_arg == NULL)
- goto failure;
-
- new_module = PyObject_CallMethod(
- module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg);
-
- Py_DECREF(o_arg);
- Py_DECREF(module);
- return new_module;
-
- failure:
- Py_XDECREF(module);
- return NULL;
-}
-
-
-#ifdef HAVE_WCHAR_H
-typedef wchar_t _cffi_wchar_t;
-#else
-typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */
-#endif
-
-_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o)
-{
- if (sizeof(_cffi_wchar_t) == 2)
- return (uint16_t)_cffi_to_c_wchar_t(o);
- else
- return (uint16_t)_cffi_to_c_wchar3216_t(o);
-}
-
-_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x)
-{
- if (sizeof(_cffi_wchar_t) == 2)
- return _cffi_from_c_wchar_t((_cffi_wchar_t)x);
- else
- return _cffi_from_c_wchar3216_t((int)x);
-}
-
-_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o)
-{
- if (sizeof(_cffi_wchar_t) == 4)
- return (int)_cffi_to_c_wchar_t(o);
- else
- return (int)_cffi_to_c_wchar3216_t(o);
-}
-
-_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x)
-{
- if (sizeof(_cffi_wchar_t) == 4)
- return _cffi_from_c_wchar_t((_cffi_wchar_t)x);
- else
- return _cffi_from_c_wchar3216_t((int)x);
-}
-
-union _cffi_union_alignment_u {
- 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;
- long double m_longdouble;
-};
-
-struct _cffi_freeme_s {
- struct _cffi_freeme_s *next;
- union _cffi_union_alignment_u alignment;
-};
-
-_CFFI_UNUSED_FN static int
-_cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg,
- char **output_data, Py_ssize_t datasize,
- struct _cffi_freeme_s **freeme)
-{
- char *p;
- if (datasize < 0)
- return -1;
-
- p = *output_data;
- if (p == NULL) {
- struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc(
- offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize);
- if (fp == NULL)
- return -1;
- fp->next = *freeme;
- *freeme = fp;
- p = *output_data = (char *)&fp->alignment;
- }
- memset((void *)p, 0, (size_t)datasize);
- return _cffi_convert_array_from_object(p, ctptr, arg);
-}
-
-_CFFI_UNUSED_FN static void
-_cffi_free_array_arguments(struct _cffi_freeme_s *freeme)
-{
- do {
- void *p = (void *)freeme;
- freeme = freeme->next;
- PyObject_Free(p);
- } while (freeme != NULL);
-}
-
-/********** end CPython-specific section **********/
-#else
-_CFFI_UNUSED_FN
-static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *);
-# define _cffi_call_python _cffi_call_python_org
-#endif
-
-
-#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0]))
-
-#define _cffi_prim_int(size, sign) \
- ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \
- (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \
- (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \
- (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \
- _CFFI__UNKNOWN_PRIM)
-
-#define _cffi_prim_float(size) \
- ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \
- (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \
- (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \
- _CFFI__UNKNOWN_FLOAT_PRIM)
-
-#define _cffi_check_int(got, got_nonpos, expected) \
- ((got_nonpos) == (expected <= 0) && \
- (got) == (unsigned long long)expected)
-
-#ifdef MS_WIN32
-# define _cffi_stdcall __stdcall
-#else
-# define _cffi_stdcall /* nothing */
-#endif
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/cffi/_embedding.h b/cffi/_embedding.h
deleted file mode 100644
index e863d85..0000000
--- a/cffi/_embedding.h
+++ /dev/null
@@ -1,527 +0,0 @@
-
-/***** Support code for embedding *****/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#if defined(_WIN32)
-# define CFFI_DLLEXPORT __declspec(dllexport)
-#elif defined(__GNUC__)
-# define CFFI_DLLEXPORT __attribute__((visibility("default")))
-#else
-# define CFFI_DLLEXPORT /* nothing */
-#endif
-
-
-/* There are two global variables of type _cffi_call_python_fnptr:
-
- * _cffi_call_python, which we declare just below, is the one called
- by ``extern "Python"`` implementations.
-
- * _cffi_call_python_org, which on CPython is actually part of the
- _cffi_exports[] array, is the function pointer copied from
- _cffi_backend.
-
- After initialization is complete, both are equal. However, the
- first one remains equal to &_cffi_start_and_call_python until the
- very end of initialization, when we are (or should be) sure that
- concurrent threads also see a completely initialized world, and
- only then is it changed.
-*/
-#undef _cffi_call_python
-typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *);
-static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *);
-static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python;
-
-
-#ifndef _MSC_VER
- /* --- Assuming a GCC not infinitely old --- */
-# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n)
-# define cffi_write_barrier() __sync_synchronize()
-# if !defined(__amd64__) && !defined(__x86_64__) && \
- !defined(__i386__) && !defined(__i386)
-# define cffi_read_barrier() __sync_synchronize()
-# else
-# define cffi_read_barrier() (void)0
-# endif
-#else
- /* --- Windows threads version --- */
-# include <Windows.h>
-# define cffi_compare_and_swap(l,o,n) \
- (InterlockedCompareExchangePointer(l,n,o) == (o))
-# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0)
-# define cffi_read_barrier() (void)0
-static volatile LONG _cffi_dummy;
-#endif
-
-#ifdef WITH_THREAD
-# ifndef _MSC_VER
-# include <pthread.h>
- static pthread_mutex_t _cffi_embed_startup_lock;
-# else
- static CRITICAL_SECTION _cffi_embed_startup_lock;
-# endif
- static char _cffi_embed_startup_lock_ready = 0;
-#endif
-
-static void _cffi_acquire_reentrant_mutex(void)
-{
- static void *volatile lock = NULL;
-
- while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) {
- /* should ideally do a spin loop instruction here, but
- hard to do it portably and doesn't really matter I
- think: pthread_mutex_init() should be very fast, and
- this is only run at start-up anyway. */
- }
-
-#ifdef WITH_THREAD
- if (!_cffi_embed_startup_lock_ready) {
-# ifndef _MSC_VER
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&_cffi_embed_startup_lock, &attr);
-# else
- InitializeCriticalSection(&_cffi_embed_startup_lock);
-# endif
- _cffi_embed_startup_lock_ready = 1;
- }
-#endif
-
- while (!cffi_compare_and_swap(&lock, (void *)1, NULL))
- ;
-
-#ifndef _MSC_VER
- pthread_mutex_lock(&_cffi_embed_startup_lock);
-#else
- EnterCriticalSection(&_cffi_embed_startup_lock);
-#endif
-}
-
-static void _cffi_release_reentrant_mutex(void)
-{
-#ifndef _MSC_VER
- pthread_mutex_unlock(&_cffi_embed_startup_lock);
-#else
- LeaveCriticalSection(&_cffi_embed_startup_lock);
-#endif
-}
-
-
-/********** CPython-specific section **********/
-#ifndef PYPY_VERSION
-
-#include "_cffi_errors.h"
-
-
-#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX]
-
-PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */
-
-static void _cffi_py_initialize(void)
-{
- /* XXX use initsigs=0, which "skips initialization registration of
- signal handlers, which might be useful when Python is
- embedded" according to the Python docs. But review and think
- if it should be a user-controllable setting.
-
- XXX we should also give a way to write errors to a buffer
- instead of to stderr.
-
- XXX if importing 'site' fails, CPython (any version) calls
- exit(). Should we try to work around this behavior here?
- */
- Py_InitializeEx(0);
-}
-
-static int _cffi_initialize_python(void)
-{
- /* This initializes Python, imports _cffi_backend, and then the
- present .dll/.so is set up as a CPython C extension module.
- */
- int result;
- PyGILState_STATE state;
- PyObject *pycode=NULL, *global_dict=NULL, *x;
- PyObject *builtins;
-
- state = PyGILState_Ensure();
-
- /* Call the initxxx() function from the present module. It will
- create and initialize us as a CPython extension module, instead
- of letting the startup Python code do it---it might reimport
- the same .dll/.so and get maybe confused on some platforms.
- It might also have troubles locating the .dll/.so again for all
- I know.
- */
- (void)_CFFI_PYTHON_STARTUP_FUNC();
- if (PyErr_Occurred())
- goto error;
-
- /* Now run the Python code provided to ffi.embedding_init_code().
- */
- pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE,
- "<init code for '" _CFFI_MODULE_NAME "'>",
- Py_file_input);
- if (pycode == NULL)
- goto error;
- global_dict = PyDict_New();
- if (global_dict == NULL)
- goto error;
- builtins = PyEval_GetBuiltins();
- if (builtins == NULL)
- goto error;
- if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0)
- goto error;
- x = PyEval_EvalCode(
-#if PY_MAJOR_VERSION < 3
- (PyCodeObject *)
-#endif
- pycode, global_dict, global_dict);
- if (x == NULL)
- goto error;
- Py_DECREF(x);
-
- /* Done! Now if we've been called from
- _cffi_start_and_call_python() in an ``extern "Python"``, we can
- only hope that the Python code did correctly set up the
- corresponding @ffi.def_extern() function. Otherwise, the
- general logic of ``extern "Python"`` functions (inside the
- _cffi_backend module) will find that the reference is still
- missing and print an error.
- */
- result = 0;
- done:
- Py_XDECREF(pycode);
- Py_XDECREF(global_dict);
- PyGILState_Release(state);
- return result;
-
- error:;
- {
- /* Print as much information as potentially useful.
- Debugging load-time failures with embedding is not fun
- */
- PyObject *ecap;
- PyObject *exception, *v, *tb, *f, *modules, *mod;
- PyErr_Fetch(&exception, &v, &tb);
- ecap = _cffi_start_error_capture();
- f = PySys_GetObject((char *)"stderr");
- if (f != NULL && f != Py_None) {
- PyFile_WriteString(
- "Failed to initialize the Python-CFFI embedding logic:\n\n", f);
- }
-
- if (exception != NULL) {
- PyErr_NormalizeException(&exception, &v, &tb);
- PyErr_Display(exception, v, tb);
- }
- Py_XDECREF(exception);
- Py_XDECREF(v);
- Py_XDECREF(tb);
-
- if (f != NULL && f != Py_None) {
- PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
- "\ncompiled with cffi version: 1.15.0"
- "\n_cffi_backend module: ", f);
- modules = PyImport_GetModuleDict();
- mod = PyDict_GetItemString(modules, "_cffi_backend");
- if (mod == NULL) {
- PyFile_WriteString("not loaded", f);
- }
- else {
- v = PyObject_GetAttrString(mod, "__file__");
- PyFile_WriteObject(v, f, 0);
- Py_XDECREF(v);
- }
- PyFile_WriteString("\nsys.path: ", f);
- PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0);
- PyFile_WriteString("\n\n", f);
- }
- _cffi_stop_error_capture(ecap);
- }
- result = -1;
- goto done;
-}
-
-#if PY_VERSION_HEX < 0x03080000
-PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */
-#endif
-
-static int _cffi_carefully_make_gil(void)
-{
- /* This does the basic initialization of Python. It can be called
- completely concurrently from unrelated threads. It assumes
- that we don't hold the GIL before (if it exists), and we don't
- hold it afterwards.
-
- (What it really does used to be completely different in Python 2
- and Python 3, with the Python 2 solution avoiding the spin-lock
- around the Py_InitializeEx() call. However, after recent changes
- to CPython 2.7 (issue #358) it no longer works. So we use the
- Python 3 solution everywhere.)
-
- This initializes Python by calling Py_InitializeEx().
- Important: this must not be called concurrently at all.
- So we use a global variable as a simple spin lock. This global
- variable must be from 'libpythonX.Y.so', not from this
- cffi-based extension module, because it must be shared from
- different cffi-based extension modules.
-
- In Python < 3.8, we choose
- _PyParser_TokenNames[0] as a completely arbitrary pointer value
- that is never written to. The default is to point to the
- string "ENDMARKER". We change it temporarily to point to the
- next character in that string. (Yes, I know it's REALLY
- obscure.)
-
- In Python >= 3.8, this string array is no longer writable, so
- instead we pick PyCapsuleType.tp_version_tag. We can't change
- Python < 3.8 because someone might use a mixture of cffi
- embedded modules, some of which were compiled before this file
- changed.
- */
-
-#ifdef WITH_THREAD
-# if PY_VERSION_HEX < 0x03080000
- char *volatile *lock = (char *volatile *)_PyParser_TokenNames;
- char *old_value, *locked_value;
-
- while (1) { /* spin loop */
- old_value = *lock;
- locked_value = old_value + 1;
- if (old_value[0] == 'E') {
- assert(old_value[1] == 'N');
- if (cffi_compare_and_swap(lock, old_value, locked_value))
- break;
- }
- else {
- assert(old_value[0] == 'N');
- /* should ideally do a spin loop instruction here, but
- hard to do it portably and doesn't really matter I
- think: PyEval_InitThreads() should be very fast, and
- this is only run at start-up anyway. */
- }
- }
-# else
- int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag;
- int old_value, locked_value;
- assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG));
-
- while (1) { /* spin loop */
- old_value = *lock;
- locked_value = -42;
- if (old_value == 0) {
- if (cffi_compare_and_swap(lock, old_value, locked_value))
- break;
- }
- else {
- assert(old_value == locked_value);
- /* should ideally do a spin loop instruction here, but
- hard to do it portably and doesn't really matter I
- think: PyEval_InitThreads() should be very fast, and
- this is only run at start-up anyway. */
- }
- }
-# endif
-#endif
-
- /* call Py_InitializeEx() */
- if (!Py_IsInitialized()) {
- _cffi_py_initialize();
-#if PY_VERSION_HEX < 0x03070000
- PyEval_InitThreads();
-#endif
- PyEval_SaveThread(); /* release the GIL */
- /* the returned tstate must be the one that has been stored into the
- autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */
- }
- else {
-#if PY_VERSION_HEX < 0x03070000
- /* PyEval_InitThreads() is always a no-op from CPython 3.7 */
- PyGILState_STATE state = PyGILState_Ensure();
- PyEval_InitThreads();
- PyGILState_Release(state);
-#endif
- }
-
-#ifdef WITH_THREAD
- /* release the lock */
- while (!cffi_compare_and_swap(lock, locked_value, old_value))
- ;
-#endif
-
- return 0;
-}
-
-/********** end CPython-specific section **********/
-
-
-#else
-
-
-/********** PyPy-specific section **********/
-
-PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */
-
-static struct _cffi_pypy_init_s {
- const char *name;
- void *func; /* function pointer */
- const char *code;
-} _cffi_pypy_init = {
- _CFFI_MODULE_NAME,
- _CFFI_PYTHON_STARTUP_FUNC,
- _CFFI_PYTHON_STARTUP_CODE,
-};
-
-extern int pypy_carefully_make_gil(const char *);
-extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *);
-
-static int _cffi_carefully_make_gil(void)
-{
- return pypy_carefully_make_gil(_CFFI_MODULE_NAME);
-}
-
-static int _cffi_initialize_python(void)
-{
- return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init);
-}
-
-/********** end PyPy-specific section **********/
-
-
-#endif
-
-
-#ifdef __GNUC__
-__attribute__((noinline))
-#endif
-static _cffi_call_python_fnptr _cffi_start_python(void)
-{
- /* Delicate logic to initialize Python. This function can be
- called multiple times concurrently, e.g. when the process calls
- its first ``extern "Python"`` functions in multiple threads at
- once. It can also be called recursively, in which case we must
- ignore it. We also have to consider what occurs if several
- different cffi-based extensions reach this code in parallel
- threads---it is a different copy of the code, then, and we
- can't have any shared global variable unless it comes from
- 'libpythonX.Y.so'.
-
- Idea:
-
- * _cffi_carefully_make_gil(): "carefully" call
- PyEval_InitThreads() (possibly with Py_InitializeEx() first).
-
- * then we use a (local) custom lock to make sure that a call to this
- cffi-based extension will wait if another call to the *same*
- extension is running the initialization in another thread.
- It is reentrant, so that a recursive call will not block, but
- only one from a different thread.
-
- * then we grab the GIL and (Python 2) we call Py_InitializeEx().
- At this point, concurrent calls to Py_InitializeEx() are not
- possible: we have the GIL.
-
- * do the rest of the specific initialization, which may
- temporarily release the GIL but not the custom lock.
- Only release the custom lock when we are done.
- */
- static char called = 0;
-
- if (_cffi_carefully_make_gil() != 0)
- return NULL;
-
- _cffi_acquire_reentrant_mutex();
-
- /* Here the GIL exists, but we don't have it. We're only protected
- from concurrency by the reentrant mutex. */
-
- /* This file only initializes the embedded module once, the first
- time this is called, even if there are subinterpreters. */
- if (!called) {
- called = 1; /* invoke _cffi_initialize_python() only once,
- but don't set '_cffi_call_python' right now,
- otherwise concurrent threads won't call
- this function at all (we need them to wait) */
- if (_cffi_initialize_python() == 0) {
- /* now initialization is finished. Switch to the fast-path. */
-
- /* We would like nobody to see the new value of
- '_cffi_call_python' without also seeing the rest of the
- data initialized. However, this is not possible. But
- the new value of '_cffi_call_python' is the function
- 'cffi_call_python()' from _cffi_backend. So: */
- cffi_write_barrier();
- /* ^^^ we put a write barrier here, and a corresponding
- read barrier at the start of cffi_call_python(). This
- ensures that after that read barrier, we see everything
- done here before the write barrier.
- */
-
- assert(_cffi_call_python_org != NULL);
- _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org;
- }
- else {
- /* initialization failed. Reset this to NULL, even if it was
- already set to some other value. Future calls to
- _cffi_start_python() are still forced to occur, and will
- always return NULL from now on. */
- _cffi_call_python_org = NULL;
- }
- }
-
- _cffi_release_reentrant_mutex();
-
- return (_cffi_call_python_fnptr)_cffi_call_python_org;
-}
-
-static
-void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args)
-{
- _cffi_call_python_fnptr fnptr;
- int current_err = errno;
-#ifdef _MSC_VER
- int current_lasterr = GetLastError();
-#endif
- fnptr = _cffi_start_python();
- if (fnptr == NULL) {
- fprintf(stderr, "function %s() called, but initialization code "
- "failed. Returning 0.\n", externpy->name);
- memset(args, 0, externpy->size_of_result);
- }
-#ifdef _MSC_VER
- SetLastError(current_lasterr);
-#endif
- errno = current_err;
-
- if (fnptr != NULL)
- fnptr(externpy, args);
-}
-
-
-/* The cffi_start_python() function makes sure Python is initialized
- and our cffi module is set up. It can be called manually from the
- user C code. The same effect is obtained automatically from any
- dll-exported ``extern "Python"`` function. This function returns
- -1 if initialization failed, 0 if all is OK. */
-_CFFI_UNUSED_FN
-static int cffi_start_python(void)
-{
- if (_cffi_call_python == &_cffi_start_and_call_python) {
- if (_cffi_start_python() == NULL)
- return -1;
- }
- cffi_read_barrier();
- return 0;
-}
-
-#undef cffi_compare_and_swap
-#undef cffi_write_barrier
-#undef cffi_read_barrier
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/cffi/api.py b/cffi/api.py
deleted file mode 100644
index 999a8ae..0000000
--- a/cffi/api.py
+++ /dev/null
@@ -1,965 +0,0 @@
-import sys, types
-from .lock import allocate_lock
-from .error import CDefError
-from . import model
-
-try:
- callable
-except NameError:
- # Python 3.1
- from collections import Callable
- callable = lambda x: isinstance(x, Callable)
-
-try:
- basestring
-except NameError:
- # Python 3.x
- basestring = str
-
-_unspecified = object()
-
-
-
-class FFI(object):
- r'''
- The main top-level class that you instantiate once, or once per module.
-
- Example usage:
-
- ffi = FFI()
- ffi.cdef("""
- int printf(const char *, ...);
- """)
-
- C = ffi.dlopen(None) # standard library
- -or-
- C = ffi.verify() # use a C compiler: verify the decl above is right
-
- C.printf("hello, %s!\n", ffi.new("char[]", "world"))
- '''
-
- def __init__(self, backend=None):
- """Create an FFI instance. The 'backend' argument is used to
- select a non-default backend, mostly for tests.
- """
- if backend is None:
- # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with
- # _cffi_backend.so compiled.
- import _cffi_backend as backend
- from . import __version__
- if backend.__version__ != __version__:
- # bad version! Try to be as explicit as possible.
- if hasattr(backend, '__file__'):
- # CPython
- raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % (
- __version__, __file__,
- backend.__version__, backend.__file__))
- else:
- # PyPy
- raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % (
- __version__, __file__, backend.__version__))
- # (If you insist you can also try to pass the option
- # 'backend=backend_ctypes.CTypesBackend()', but don't
- # rely on it! It's probably not going to work well.)
-
- from . import cparser
- self._backend = backend
- self._lock = allocate_lock()
- self._parser = cparser.Parser()
- self._cached_btypes = {}
- self._parsed_types = types.ModuleType('parsed_types').__dict__
- self._new_types = types.ModuleType('new_types').__dict__
- self._function_caches = []
- self._libraries = []
- self._cdefsources = []
- self._included_ffis = []
- self._windows_unicode = None
- self._init_once_cache = {}
- self._cdef_version = None
- self._embedding = None
- self._typecache = model.get_typecache(backend)
- if hasattr(backend, 'set_ffi'):
- backend.set_ffi(self)
- for name in list(backend.__dict__):
- if name.startswith('RTLD_'):
- setattr(self, name, getattr(backend, name))
- #
- with self._lock:
- self.BVoidP = self._get_cached_btype(model.voidp_type)
- self.BCharA = self._get_cached_btype(model.char_array_type)
- if isinstance(backend, types.ModuleType):
- # _cffi_backend: attach these constants to the class
- if not hasattr(FFI, 'NULL'):
- FFI.NULL = self.cast(self.BVoidP, 0)
- FFI.CData, FFI.CType = backend._get_types()
- else:
- # ctypes backend: attach these constants to the instance
- self.NULL = self.cast(self.BVoidP, 0)
- self.CData, self.CType = backend._get_types()
- self.buffer = backend.buffer
-
- def cdef(self, csource, override=False, packed=False, pack=None):
- """Parse the given C source. This registers all declared functions,
- types, and global variables. The functions and global variables can
- then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'.
- The types can be used in 'ffi.new()' and other functions.
- If 'packed' is specified as True, all structs declared inside this
- cdef are packed, i.e. laid out without any field alignment at all.
- Alternatively, 'pack' can be a small integer, and requests for
- alignment greater than that are ignored (pack=1 is equivalent to
- packed=True).
- """
- self._cdef(csource, override=override, packed=packed, pack=pack)
-
- def embedding_api(self, csource, packed=False, pack=None):
- self._cdef(csource, packed=packed, pack=pack, dllexport=True)
- if self._embedding is None:
- self._embedding = ''
-
- def _cdef(self, csource, override=False, **options):
- if not isinstance(csource, str): # unicode, on Python 2
- if not isinstance(csource, basestring):
- raise TypeError("cdef() argument must be a string")
- csource = csource.encode('ascii')
- with self._lock:
- self._cdef_version = object()
- self._parser.parse(csource, override=override, **options)
- self._cdefsources.append(csource)
- if override:
- for cache in self._function_caches:
- cache.clear()
- finishlist = self._parser._recomplete
- if finishlist:
- self._parser._recomplete = []
- for tp in finishlist:
- tp.finish_backend_type(self, finishlist)
-
- def dlopen(self, name, flags=0):
- """Load and return a dynamic library identified by 'name'.
- The standard C library can be loaded by passing None.
- Note that functions and types declared by 'ffi.cdef()' are not
- linked to a particular library, just like C headers; in the
- library we only look for the actual (untyped) symbols.
- """
- if not (isinstance(name, basestring) or
- name is None or
- isinstance(name, self.CData)):
- raise TypeError("dlopen(name): name must be a file name, None, "
- "or an already-opened 'void *' handle")
- with self._lock:
- lib, function_cache = _make_ffi_library(self, name, flags)
- self._function_caches.append(function_cache)
- self._libraries.append(lib)
- return lib
-
- def dlclose(self, lib):
- """Close a library obtained with ffi.dlopen(). After this call,
- access to functions or variables from the library will fail
- (possibly with a segmentation fault).
- """
- type(lib).__cffi_close__(lib)
-
- def _typeof_locked(self, cdecl):
- # call me with the lock!
- key = cdecl
- if key in self._parsed_types:
- return self._parsed_types[key]
- #
- if not isinstance(cdecl, str): # unicode, on Python 2
- cdecl = cdecl.encode('ascii')
- #
- type = self._parser.parse_type(cdecl)
- really_a_function_type = type.is_raw_function
- if really_a_function_type:
- type = type.as_function_pointer()
- btype = self._get_cached_btype(type)
- result = btype, really_a_function_type
- self._parsed_types[key] = result
- return result
-
- def _typeof(self, cdecl, consider_function_as_funcptr=False):
- # string -> ctype object
- try:
- result = self._parsed_types[cdecl]
- except KeyError:
- with self._lock:
- result = self._typeof_locked(cdecl)
- #
- btype, really_a_function_type = result
- if really_a_function_type and not consider_function_as_funcptr:
- raise CDefError("the type %r is a function type, not a "
- "pointer-to-function type" % (cdecl,))
- return btype
-
- def typeof(self, cdecl):
- """Parse the C type given as a string and return the
- corresponding <ctype> object.
- It can also be used on 'cdata' instance to get its C type.
- """
- if isinstance(cdecl, basestring):
- return self._typeof(cdecl)
- if isinstance(cdecl, self.CData):
- return self._backend.typeof(cdecl)
- if isinstance(cdecl, types.BuiltinFunctionType):
- res = _builtin_function_type(cdecl)
- if res is not None:
- return res
- if (isinstance(cdecl, types.FunctionType)
- and hasattr(cdecl, '_cffi_base_type')):
- with self._lock:
- return self._get_cached_btype(cdecl._cffi_base_type)
- raise TypeError(type(cdecl))
-
- def sizeof(self, cdecl):
- """Return the size in bytes of the argument. It can be a
- string naming a C type, or a 'cdata' instance.
- """
- if isinstance(cdecl, basestring):
- BType = self._typeof(cdecl)
- return self._backend.sizeof(BType)
- else:
- return self._backend.sizeof(cdecl)
-
- def alignof(self, cdecl):
- """Return the natural alignment size in bytes of the C type
- given as a string.
- """
- if isinstance(cdecl, basestring):
- cdecl = self._typeof(cdecl)
- return self._backend.alignof(cdecl)
-
- def offsetof(self, cdecl, *fields_or_indexes):
- """Return the offset of the named field inside the given
- structure or array, which must be given as a C type name.
- You can give several field names in case of nested structures.
- You can also give numeric values which correspond to array
- items, in case of an array type.
- """
- if isinstance(cdecl, basestring):
- cdecl = self._typeof(cdecl)
- return self._typeoffsetof(cdecl, *fields_or_indexes)[1]
-
- def new(self, cdecl, init=None):
- """Allocate an instance according to the specified C type and
- return a pointer to it. The specified C type must be either a
- pointer or an array: ``new('X *')`` allocates an X and returns
- a pointer to it, whereas ``new('X[n]')`` allocates an array of
- n X'es and returns an array referencing it (which works
- mostly like a pointer, like in C). You can also use
- ``new('X[]', n)`` to allocate an array of a non-constant
- length n.
-
- The memory is initialized following the rules of declaring a
- global variable in C: by default it is zero-initialized, but
- an explicit initializer can be given which can be used to
- fill all or part of the memory.
-
- When the returned <cdata> object goes out of scope, the memory
- is freed. In other words the returned <cdata> object has
- ownership of the value of type 'cdecl' that it points to. This
- means that the raw data can be used as long as this object is
- kept alive, but must not be used for a longer time. Be careful
- about that when copying the pointer to the memory somewhere
- else, e.g. into another structure.
- """
- if isinstance(cdecl, basestring):
- cdecl = self._typeof(cdecl)
- return self._backend.newp(cdecl, init)
-
- def new_allocator(self, alloc=None, free=None,
- should_clear_after_alloc=True):
- """Return a new allocator, i.e. a function that behaves like ffi.new()
- but uses the provided low-level 'alloc' and 'free' functions.
-
- 'alloc' is called with the size as argument. If it returns NULL, a
- MemoryError is raised. 'free' is called with the result of 'alloc'
- as argument. Both can be either Python function or directly C
- functions. If 'free' is None, then no free function is called.
- If both 'alloc' and 'free' are None, the default is used.
-
- If 'should_clear_after_alloc' is set to False, then the memory
- returned by 'alloc' is assumed to be already cleared (or you are
- fine with garbage); otherwise CFFI will clear it.
- """
- compiled_ffi = self._backend.FFI()
- allocator = compiled_ffi.new_allocator(alloc, free,
- should_clear_after_alloc)
- def allocate(cdecl, init=None):
- if isinstance(cdecl, basestring):
- cdecl = self._typeof(cdecl)
- return allocator(cdecl, init)
- return allocate
-
- def cast(self, cdecl, source):
- """Similar to a C cast: returns an instance of the named C
- type initialized with the given 'source'. The source is
- casted between integers or pointers of any type.
- """
- if isinstance(cdecl, basestring):
- cdecl = self._typeof(cdecl)
- return self._backend.cast(cdecl, source)
-
- def string(self, cdata, maxlen=-1):
- """Return a Python string (or unicode string) from the 'cdata'.
- If 'cdata' is a pointer or array of characters or bytes, returns
- the null-terminated string. The returned string extends until
- the first null character, or at most 'maxlen' characters. If
- 'cdata' is an array then 'maxlen' defaults to its length.
-
- If 'cdata' is a pointer or array of wchar_t, returns a unicode
- string following the same rules.
-
- If 'cdata' is a single character or byte or a wchar_t, returns
- it as a string or unicode string.
-
- If 'cdata' is an enum, returns the value of the enumerator as a
- string, or 'NUMBER' if the value is out of range.
- """
- return self._backend.string(cdata, maxlen)
-
- def unpack(self, cdata, length):
- """Unpack an array of C data of the given length,
- returning a Python string/unicode/list.
-
- If 'cdata' is a pointer to 'char', returns a byte string.
- It does not stop at the first null. This is equivalent to:
- ffi.buffer(cdata, length)[:]
-
- If 'cdata' is a pointer to 'wchar_t', returns a unicode string.
- 'length' is measured in wchar_t's; it is not the size in bytes.
-
- If 'cdata' is a pointer to anything else, returns a list of
- 'length' items. This is a faster equivalent to:
- [cdata[i] for i in range(length)]
- """
- return self._backend.unpack(cdata, length)
-
- #def buffer(self, cdata, size=-1):
- # """Return a read-write buffer object that references the raw C data
- # pointed to by the given 'cdata'. The 'cdata' must be a pointer or
- # an array. Can be passed to functions expecting a buffer, or directly
- # manipulated with:
- #
- # buf[:] get a copy of it in a regular string, or
- # buf[idx] as a single character
- # buf[:] = ...
- # buf[idx] = ... change the content
- # """
- # note that 'buffer' is a type, set on this instance by __init__
-
- def from_buffer(self, cdecl, python_buffer=_unspecified,
- require_writable=False):
- """Return a cdata of the given type pointing to the data of the
- given Python object, which must support the buffer interface.
- Note that this is not meant to be used on the built-in types
- str or unicode (you can build 'char[]' arrays explicitly)
- but only on objects containing large quantities of raw data
- in some other format, like 'array.array' or numpy arrays.
-
- The first argument is optional and default to 'char[]'.
- """
- if python_buffer is _unspecified:
- cdecl, python_buffer = self.BCharA, cdecl
- elif isinstance(cdecl, basestring):
- cdecl = self._typeof(cdecl)
- return self._backend.from_buffer(cdecl, python_buffer,
- require_writable)
-
- def memmove(self, dest, src, n):
- """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.
-
- Like the C function memmove(), the memory areas may overlap;
- apart from that it behaves like the C function memcpy().
-
- 'src' can be any cdata ptr or array, or any Python buffer object.
- 'dest' can be any cdata ptr or array, or a writable Python buffer
- object. The size to copy, 'n', is always measured in bytes.
-
- Unlike other methods, this one supports all Python buffer including
- byte strings and bytearrays---but it still does not support
- non-contiguous buffers.
- """
- return self._backend.memmove(dest, src, n)
-
- def callback(self, cdecl, python_callable=None, error=None, onerror=None):
- """Return a callback object or a decorator making such a
- callback object. 'cdecl' must name a C function pointer type.
- The callback invokes the specified 'python_callable' (which may
- be provided either directly or via a decorator). Important: the
- callback object must be manually kept alive for as long as the
- callback may be invoked from the C level.
- """
- def callback_decorator_wrap(python_callable):
- if not callable(python_callable):
- raise TypeError("the 'python_callable' argument "
- "is not callable")
- return self._backend.callback(cdecl, python_callable,
- error, onerror)
- if isinstance(cdecl, basestring):
- cdecl = self._typeof(cdecl, consider_function_as_funcptr=True)
- if python_callable is None:
- return callback_decorator_wrap # decorator mode
- else:
- return callback_decorator_wrap(python_callable) # direct mode
-
- def getctype(self, cdecl, replace_with=''):
- """Return a string giving the C type 'cdecl', which may be itself
- a string or a <ctype> object. If 'replace_with' is given, it gives
- extra text to append (or insert for more complicated C types), like
- a variable name, or '*' to get actually the C type 'pointer-to-cdecl'.
- """
- if isinstance(cdecl, basestring):
- cdecl = self._typeof(cdecl)
- replace_with = replace_with.strip()
- if (replace_with.startswith('*')
- and '&[' in self._backend.getcname(cdecl, '&')):
- replace_with = '(%s)' % replace_with
- elif replace_with and not replace_with[0] in '[(':
- replace_with = ' ' + replace_with
- return self._backend.getcname(cdecl, replace_with)
-
- def gc(self, cdata, destructor, size=0):
- """Return a new cdata object that points to the same
- data. Later, when this new cdata object is garbage-collected,
- 'destructor(old_cdata_object)' will be called.
-
- The optional 'size' gives an estimate of the size, used to
- trigger the garbage collection more eagerly. So far only used
- on PyPy. It tells the GC that the returned object keeps alive
- roughly 'size' bytes of external memory.
- """
- return self._backend.gcp(cdata, destructor, size)
-
- def _get_cached_btype(self, type):
- assert self._lock.acquire(False) is False
- # call me with the lock!
- try:
- BType = self._cached_btypes[type]
- except KeyError:
- finishlist = []
- BType = type.get_cached_btype(self, finishlist)
- for type in finishlist:
- type.finish_backend_type(self, finishlist)
- return BType
-
- def verify(self, source='', tmpdir=None, **kwargs):
- """Verify that the current ffi signatures compile on this
- machine, and return a dynamic library object. The dynamic
- library can be used to call functions and access global
- variables declared in this 'ffi'. The library is compiled
- by the C compiler: it gives you C-level API compatibility
- (including calling macros). This is unlike 'ffi.dlopen()',
- which requires binary compatibility in the signatures.
- """
- from .verifier import Verifier, _caller_dir_pycache
- #
- # If set_unicode(True) was called, insert the UNICODE and
- # _UNICODE macro declarations
- if self._windows_unicode:
- self._apply_windows_unicode(kwargs)
- #
- # Set the tmpdir here, and not in Verifier.__init__: it picks
- # up the caller's directory, which we want to be the caller of
- # ffi.verify(), as opposed to the caller of Veritier().
- tmpdir = tmpdir or _caller_dir_pycache()
- #
- # Make a Verifier() and use it to load the library.
- self.verifier = Verifier(self, source, tmpdir, **kwargs)
- lib = self.verifier.load_library()
- #
- # Save the loaded library for keep-alive purposes, even
- # if the caller doesn't keep it alive itself (it should).
- self._libraries.append(lib)
- return lib
-
- def _get_errno(self):
- return self._backend.get_errno()
- def _set_errno(self, errno):
- self._backend.set_errno(errno)
- errno = property(_get_errno, _set_errno, None,
- "the value of 'errno' from/to the C calls")
-
- def getwinerror(self, code=-1):
- return self._backend.getwinerror(code)
-
- def _pointer_to(self, ctype):
- with self._lock:
- return model.pointer_cache(self, ctype)
-
- def addressof(self, cdata, *fields_or_indexes):
- """Return the address of a <cdata 'struct-or-union'>.
- If 'fields_or_indexes' are given, returns the address of that
- field or array item in the structure or array, recursively in
- case of nested structures.
- """
- try:
- ctype = self._backend.typeof(cdata)
- except TypeError:
- if '__addressof__' in type(cdata).__dict__:
- return type(cdata).__addressof__(cdata, *fields_or_indexes)
- raise
- if fields_or_indexes:
- ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes)
- else:
- if ctype.kind == "pointer":
- raise TypeError("addressof(pointer)")
- offset = 0
- ctypeptr = self._pointer_to(ctype)
- return self._backend.rawaddressof(ctypeptr, cdata, offset)
-
- def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes):
- ctype, offset = self._backend.typeoffsetof(ctype, field_or_index)
- for field1 in fields_or_indexes:
- ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1)
- offset += offset1
- return ctype, offset
-
- def include(self, ffi_to_include):
- """Includes the typedefs, structs, unions and enums defined
- in another FFI instance. Usage is similar to a #include in C,
- where a part of the program might include types defined in
- another part for its own usage. Note that the include()
- method has no effect on functions, constants and global
- variables, which must anyway be accessed directly from the
- lib object returned by the original FFI instance.
- """
- if not isinstance(ffi_to_include, FFI):
- raise TypeError("ffi.include() expects an argument that is also of"
- " type cffi.FFI, not %r" % (
- type(ffi_to_include).__name__,))
- if ffi_to_include is self:
- raise ValueError("self.include(self)")
- with ffi_to_include._lock:
- with self._lock:
- self._parser.include(ffi_to_include._parser)
- self._cdefsources.append('[')
- self._cdefsources.extend(ffi_to_include._cdefsources)
- self._cdefsources.append(']')
- self._included_ffis.append(ffi_to_include)
-
- def new_handle(self, x):
- return self._backend.newp_handle(self.BVoidP, x)
-
- def from_handle(self, x):
- return self._backend.from_handle(x)
-
- def release(self, x):
- self._backend.release(x)
-
- def set_unicode(self, enabled_flag):
- """Windows: if 'enabled_flag' is True, enable the UNICODE and
- _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR
- to be (pointers to) wchar_t. If 'enabled_flag' is False,
- declare these types to be (pointers to) plain 8-bit characters.
- This is mostly for backward compatibility; you usually want True.
- """
- if self._windows_unicode is not None:
- raise ValueError("set_unicode() can only be called once")
- enabled_flag = bool(enabled_flag)
- if enabled_flag:
- self.cdef("typedef wchar_t TBYTE;"
- "typedef wchar_t TCHAR;"
- "typedef const wchar_t *LPCTSTR;"
- "typedef const wchar_t *PCTSTR;"
- "typedef wchar_t *LPTSTR;"
- "typedef wchar_t *PTSTR;"
- "typedef TBYTE *PTBYTE;"
- "typedef TCHAR *PTCHAR;")
- else:
- self.cdef("typedef char TBYTE;"
- "typedef char TCHAR;"
- "typedef const char *LPCTSTR;"
- "typedef const char *PCTSTR;"
- "typedef char *LPTSTR;"
- "typedef char *PTSTR;"
- "typedef TBYTE *PTBYTE;"
- "typedef TCHAR *PTCHAR;")
- self._windows_unicode = enabled_flag
-
- def _apply_windows_unicode(self, kwds):
- defmacros = kwds.get('define_macros', ())
- if not isinstance(defmacros, (list, tuple)):
- raise TypeError("'define_macros' must be a list or tuple")
- defmacros = list(defmacros) + [('UNICODE', '1'),
- ('_UNICODE', '1')]
- kwds['define_macros'] = defmacros
-
- def _apply_embedding_fix(self, kwds):
- # must include an argument like "-lpython2.7" for the compiler
- def ensure(key, value):
- lst = kwds.setdefault(key, [])
- if value not in lst:
- lst.append(value)
- #
- if '__pypy__' in sys.builtin_module_names:
- import os
- if sys.platform == "win32":
- # we need 'libpypy-c.lib'. Current distributions of
- # pypy (>= 4.1) contain it as 'libs/python27.lib'.
- pythonlib = "python{0[0]}{0[1]}".format(sys.version_info)
- if hasattr(sys, 'prefix'):
- ensure('library_dirs', os.path.join(sys.prefix, 'libs'))
- else:
- # we need 'libpypy-c.{so,dylib}', which should be by
- # default located in 'sys.prefix/bin' for installed
- # systems.
- if sys.version_info < (3,):
- pythonlib = "pypy-c"
- else:
- pythonlib = "pypy3-c"
- if hasattr(sys, 'prefix'):
- ensure('library_dirs', os.path.join(sys.prefix, 'bin'))
- # On uninstalled pypy's, the libpypy-c is typically found in
- # .../pypy/goal/.
- if hasattr(sys, 'prefix'):
- ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal'))
- else:
- if sys.platform == "win32":
- template = "python%d%d"
- if hasattr(sys, 'gettotalrefcount'):
- template += '_d'
- else:
- try:
- import sysconfig
- except ImportError: # 2.6
- from distutils import sysconfig
- template = "python%d.%d"
- if sysconfig.get_config_var('DEBUG_EXT'):
- template += sysconfig.get_config_var('DEBUG_EXT')
- pythonlib = (template %
- (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
- if hasattr(sys, 'abiflags'):
- pythonlib += sys.abiflags
- ensure('libraries', pythonlib)
- if sys.platform == "win32":
- ensure('extra_link_args', '/MANIFEST')
-
- def set_source(self, module_name, source, source_extension='.c', **kwds):
- import os
- if hasattr(self, '_assigned_source'):
- raise ValueError("set_source() cannot be called several times "
- "per ffi object")
- if not isinstance(module_name, basestring):
- raise TypeError("'module_name' must be a string")
- if os.sep in module_name or (os.altsep and os.altsep in module_name):
- raise ValueError("'module_name' must not contain '/': use a dotted "
- "name to make a 'package.module' location")
- self._assigned_source = (str(module_name), source,
- source_extension, kwds)
-
- def set_source_pkgconfig(self, module_name, pkgconfig_libs, source,
- source_extension='.c', **kwds):
- from . import pkgconfig
- if not isinstance(pkgconfig_libs, list):
- raise TypeError("the pkgconfig_libs argument must be a list "
- "of package names")
- kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs)
- pkgconfig.merge_flags(kwds, kwds2)
- self.set_source(module_name, source, source_extension, **kwds)
-
- def distutils_extension(self, tmpdir='build', verbose=True):
- from distutils.dir_util import mkpath
- from .recompiler import recompile
- #
- if not hasattr(self, '_assigned_source'):
- if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored
- return self.verifier.get_extension()
- raise ValueError("set_source() must be called before"
- " distutils_extension()")
- module_name, source, source_extension, kwds = self._assigned_source
- if source is None:
- raise TypeError("distutils_extension() is only for C extension "
- "modules, not for dlopen()-style pure Python "
- "modules")
- mkpath(tmpdir)
- ext, updated = recompile(self, module_name,
- source, tmpdir=tmpdir, extradir=tmpdir,
- source_extension=source_extension,
- call_c_compiler=False, **kwds)
- if verbose:
- if updated:
- sys.stderr.write("regenerated: %r\n" % (ext.sources[0],))
- else:
- sys.stderr.write("not modified: %r\n" % (ext.sources[0],))
- return ext
-
- def emit_c_code(self, filename):
- from .recompiler import recompile
- #
- if not hasattr(self, '_assigned_source'):
- raise ValueError("set_source() must be called before emit_c_code()")
- module_name, source, source_extension, kwds = self._assigned_source
- if source is None:
- raise TypeError("emit_c_code() is only for C extension modules, "
- "not for dlopen()-style pure Python modules")
- recompile(self, module_name, source,
- c_file=filename, call_c_compiler=False, **kwds)
-
- def emit_python_code(self, filename):
- from .recompiler import recompile
- #
- if not hasattr(self, '_assigned_source'):
- raise ValueError("set_source() must be called before emit_c_code()")
- module_name, source, source_extension, kwds = self._assigned_source
- if source is not None:
- raise TypeError("emit_python_code() is only for dlopen()-style "
- "pure Python modules, not for C extension modules")
- recompile(self, module_name, source,
- c_file=filename, call_c_compiler=False, **kwds)
-
- def compile(self, tmpdir='.', verbose=0, target=None, debug=None):
- """The 'target' argument gives the final file name of the
- compiled DLL. Use '*' to force distutils' choice, suitable for
- regular CPython C API modules. Use a file name ending in '.*'
- to ask for the system's default extension for dynamic libraries
- (.so/.dll/.dylib).
-
- The default is '*' when building a non-embedded C API extension,
- and (module_name + '.*') when building an embedded library.
- """
- from .recompiler import recompile
- #
- if not hasattr(self, '_assigned_source'):
- raise ValueError("set_source() must be called before compile()")
- module_name, source, source_extension, kwds = self._assigned_source
- return recompile(self, module_name, source, tmpdir=tmpdir,
- target=target, source_extension=source_extension,
- compiler_verbose=verbose, debug=debug, **kwds)
-
- def init_once(self, func, tag):
- # Read _init_once_cache[tag], which is either (False, lock) if
- # we're calling the function now in some thread, or (True, result).
- # Don't call setdefault() in most cases, to avoid allocating and
- # immediately freeing a lock; but still use setdefaut() to avoid
- # races.
- try:
- x = self._init_once_cache[tag]
- except KeyError:
- x = self._init_once_cache.setdefault(tag, (False, allocate_lock()))
- # Common case: we got (True, result), so we return the result.
- if x[0]:
- return x[1]
- # Else, it's a lock. Acquire it to serialize the following tests.
- with x[1]:
- # Read again from _init_once_cache the current status.
- x = self._init_once_cache[tag]
- if x[0]:
- return x[1]
- # Call the function and store the result back.
- result = func()
- self._init_once_cache[tag] = (True, result)
- return result
-
- def embedding_init_code(self, pysource):
- if self._embedding:
- raise ValueError("embedding_init_code() can only be called once")
- # fix 'pysource' before it gets dumped into the C file:
- # - remove empty lines at the beginning, so it starts at "line 1"
- # - dedent, if all non-empty lines are indented
- # - check for SyntaxErrors
- import re
- match = re.match(r'\s*\n', pysource)
- if match:
- pysource = pysource[match.end():]
- lines = pysource.splitlines() or ['']
- prefix = re.match(r'\s*', lines[0]).group()
- for i in range(1, len(lines)):
- line = lines[i]
- if line.rstrip():
- while not line.startswith(prefix):
- prefix = prefix[:-1]
- i = len(prefix)
- lines = [line[i:]+'\n' for line in lines]
- pysource = ''.join(lines)
- #
- compile(pysource, "cffi_init", "exec")
- #
- self._embedding = pysource
-
- def def_extern(self, *args, **kwds):
- raise ValueError("ffi.def_extern() is only available on API-mode FFI "
- "objects")
-
- def list_types(self):
- """Returns the user type names known to this FFI instance.
- This returns a tuple containing three lists of names:
- (typedef_names, names_of_structs, names_of_unions)
- """
- typedefs = []
- structs = []
- unions = []
- for key in self._parser._declarations:
- if key.startswith('typedef '):
- typedefs.append(key[8:])
- elif key.startswith('struct '):
- structs.append(key[7:])
- elif key.startswith('union '):
- unions.append(key[6:])
- typedefs.sort()
- structs.sort()
- unions.sort()
- return (typedefs, structs, unions)
-
-
-def _load_backend_lib(backend, name, flags):
- import os
- if not isinstance(name, basestring):
- if sys.platform != "win32" or name is not None:
- return backend.load_library(name, flags)
- name = "c" # Windows: load_library(None) fails, but this works
- # on Python 2 (backward compatibility hack only)
- first_error = None
- if '.' in name or '/' in name or os.sep in name:
- try:
- return backend.load_library(name, flags)
- except OSError as e:
- first_error = e
- import ctypes.util
- path = ctypes.util.find_library(name)
- if path is None:
- if name == "c" and sys.platform == "win32" and sys.version_info >= (3,):
- raise OSError("dlopen(None) cannot work on Windows for Python 3 "
- "(see http://bugs.python.org/issue23606)")
- msg = ("ctypes.util.find_library() did not manage "
- "to locate a library called %r" % (name,))
- if first_error is not None:
- msg = "%s. Additionally, %s" % (first_error, msg)
- raise OSError(msg)
- return backend.load_library(path, flags)
-
-def _make_ffi_library(ffi, libname, flags):
- backend = ffi._backend
- backendlib = _load_backend_lib(backend, libname, flags)
- #
- def accessor_function(name):
- key = 'function ' + name
- tp, _ = ffi._parser._declarations[key]
- BType = ffi._get_cached_btype(tp)
- value = backendlib.load_function(BType, name)
- library.__dict__[name] = value
- #
- def accessor_variable(name):
- key = 'variable ' + name
- tp, _ = ffi._parser._declarations[key]
- BType = ffi._get_cached_btype(tp)
- read_variable = backendlib.read_variable
- write_variable = backendlib.write_variable
- setattr(FFILibrary, name, property(
- lambda self: read_variable(BType, name),
- lambda self, value: write_variable(BType, name, value)))
- #
- def addressof_var(name):
- try:
- return addr_variables[name]
- except KeyError:
- with ffi._lock:
- if name not in addr_variables:
- key = 'variable ' + name
- tp, _ = ffi._parser._declarations[key]
- BType = ffi._get_cached_btype(tp)
- if BType.kind != 'array':
- BType = model.pointer_cache(ffi, BType)
- p = backendlib.load_function(BType, name)
- addr_variables[name] = p
- return addr_variables[name]
- #
- def accessor_constant(name):
- raise NotImplementedError("non-integer constant '%s' cannot be "
- "accessed from a dlopen() library" % (name,))
- #
- def accessor_int_constant(name):
- library.__dict__[name] = ffi._parser._int_constants[name]
- #
- accessors = {}
- accessors_version = [False]
- addr_variables = {}
- #
- def update_accessors():
- if accessors_version[0] is ffi._cdef_version:
- return
- #
- for key, (tp, _) in ffi._parser._declarations.items():
- if not isinstance(tp, model.EnumType):
- tag, name = key.split(' ', 1)
- if tag == 'function':
- accessors[name] = accessor_function
- elif tag == 'variable':
- accessors[name] = accessor_variable
- elif tag == 'constant':
- accessors[name] = accessor_constant
- else:
- for i, enumname in enumerate(tp.enumerators):
- def accessor_enum(name, tp=tp, i=i):
- tp.check_not_partial()
- library.__dict__[name] = tp.enumvalues[i]
- accessors[enumname] = accessor_enum
- for name in ffi._parser._int_constants:
- accessors.setdefault(name, accessor_int_constant)
- accessors_version[0] = ffi._cdef_version
- #
- def make_accessor(name):
- with ffi._lock:
- if name in library.__dict__ or name in FFILibrary.__dict__:
- return # added by another thread while waiting for the lock
- if name not in accessors:
- update_accessors()
- if name not in accessors:
- raise AttributeError(name)
- accessors[name](name)
- #
- class FFILibrary(object):
- def __getattr__(self, name):
- make_accessor(name)
- return getattr(self, name)
- def __setattr__(self, name, value):
- try:
- property = getattr(self.__class__, name)
- except AttributeError:
- make_accessor(name)
- setattr(self, name, value)
- else:
- property.__set__(self, value)
- def __dir__(self):
- with ffi._lock:
- update_accessors()
- return accessors.keys()
- def __addressof__(self, name):
- if name in library.__dict__:
- return library.__dict__[name]
- if name in FFILibrary.__dict__:
- return addressof_var(name)
- make_accessor(name)
- if name in library.__dict__:
- return library.__dict__[name]
- if name in FFILibrary.__dict__:
- return addressof_var(name)
- raise AttributeError("cffi library has no function or "
- "global variable named '%s'" % (name,))
- def __cffi_close__(self):
- backendlib.close_lib()
- self.__dict__.clear()
- #
- if isinstance(libname, basestring):
- try:
- if not isinstance(libname, str): # unicode, on Python 2
- libname = libname.encode('utf-8')
- FFILibrary.__name__ = 'FFILibrary_%s' % libname
- except UnicodeError:
- pass
- library = FFILibrary()
- return library, library.__dict__
-
-def _builtin_function_type(func):
- # a hack to make at least ffi.typeof(builtin_function) work,
- # if the builtin function was obtained by 'vengine_cpy'.
- import sys
- try:
- module = sys.modules[func.__module__]
- ffi = module._cffi_original_ffi
- types_of_builtin_funcs = module._cffi_types_of_builtin_funcs
- tp = types_of_builtin_funcs[func]
- except (KeyError, AttributeError, TypeError):
- return None
- else:
- with ffi._lock:
- return ffi._get_cached_btype(tp)
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
deleted file mode 100644
index e7956a7..0000000
--- a/cffi/backend_ctypes.py
+++ /dev/null
@@ -1,1121 +0,0 @@
-import ctypes, ctypes.util, operator, sys
-from . import model
-
-if sys.version_info < (3,):
- bytechr = chr
-else:
- unicode = str
- long = int
- xrange = range
- bytechr = lambda num: bytes([num])
-
-class CTypesType(type):
- pass
-
-class CTypesData(object):
- __metaclass__ = CTypesType
- __slots__ = ['__weakref__']
- __name__ = '<cdata>'
-
- def __init__(self, *args):
- raise TypeError("cannot instantiate %r" % (self.__class__,))
-
- @classmethod
- def _newp(cls, init):
- raise TypeError("expected a pointer or array ctype, got '%s'"
- % (cls._get_c_name(),))
-
- @staticmethod
- def _to_ctypes(value):
- raise TypeError
-
- @classmethod
- def _arg_to_ctypes(cls, *value):
- try:
- ctype = cls._ctype
- except AttributeError:
- raise TypeError("cannot create an instance of %r" % (cls,))
- if value:
- res = cls._to_ctypes(*value)
- if not isinstance(res, ctype):
- res = cls._ctype(res)
- else:
- res = cls._ctype()
- return res
-
- @classmethod
- def _create_ctype_obj(cls, init):
- if init is None:
- return cls._arg_to_ctypes()
- else:
- return cls._arg_to_ctypes(init)
-
- @staticmethod
- def _from_ctypes(ctypes_value):
- raise TypeError
-
- @classmethod
- def _get_c_name(cls, replace_with=''):
- return cls._reftypename.replace(' &', replace_with)
-
- @classmethod
- def _fix_class(cls):
- cls.__name__ = 'CData<%s>' % (cls._get_c_name(),)
- cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),)
- cls.__module__ = 'ffi'
-
- def _get_own_repr(self):
- raise NotImplementedError
-
- def _addr_repr(self, address):
- if address == 0:
- return 'NULL'
- else:
- if address < 0:
- address += 1 << (8*ctypes.sizeof(ctypes.c_void_p))
- return '0x%x' % address
-
- def __repr__(self, c_name=None):
- own = self._get_own_repr()
- return '<cdata %r %s>' % (c_name or self._get_c_name(), own)
-
- def _convert_to_address(self, BClass):
- if BClass is None:
- raise TypeError("cannot convert %r to an address" % (
- self._get_c_name(),))
- else:
- raise TypeError("cannot convert %r to %r" % (
- self._get_c_name(), BClass._get_c_name()))
-
- @classmethod
- def _get_size(cls):
- return ctypes.sizeof(cls._ctype)
-
- def _get_size_of_instance(self):
- return ctypes.sizeof(self._ctype)
-
- @classmethod
- def _cast_from(cls, source):
- raise TypeError("cannot cast to %r" % (cls._get_c_name(),))
-
- def _cast_to_integer(self):
- return self._convert_to_address(None)
-
- @classmethod
- def _alignment(cls):
- return ctypes.alignment(cls._ctype)
-
- def __iter__(self):
- raise TypeError("cdata %r does not support iteration" % (
- self._get_c_name()),)
-
- def _make_cmp(name):
- cmpfunc = getattr(operator, name)
- def cmp(self, other):
- v_is_ptr = not isinstance(self, CTypesGenericPrimitive)
- w_is_ptr = (isinstance(other, CTypesData) and
- not isinstance(other, CTypesGenericPrimitive))
- if v_is_ptr and w_is_ptr:
- return cmpfunc(self._convert_to_address(None),
- other._convert_to_address(None))
- elif v_is_ptr or w_is_ptr:
- return NotImplemented
- else:
- if isinstance(self, CTypesGenericPrimitive):
- self = self._value
- if isinstance(other, CTypesGenericPrimitive):
- other = other._value
- return cmpfunc(self, other)
- cmp.func_name = name
- return cmp
-
- __eq__ = _make_cmp('__eq__')
- __ne__ = _make_cmp('__ne__')
- __lt__ = _make_cmp('__lt__')
- __le__ = _make_cmp('__le__')
- __gt__ = _make_cmp('__gt__')
- __ge__ = _make_cmp('__ge__')
-
- def __hash__(self):
- return hash(self._convert_to_address(None))
-
- def _to_string(self, maxlen):
- raise TypeError("string(): %r" % (self,))
-
-
-class CTypesGenericPrimitive(CTypesData):
- __slots__ = []
-
- def __hash__(self):
- return hash(self._value)
-
- def _get_own_repr(self):
- return repr(self._from_ctypes(self._value))
-
-
-class CTypesGenericArray(CTypesData):
- __slots__ = []
-
- @classmethod
- def _newp(cls, init):
- return cls(init)
-
- def __iter__(self):
- for i in xrange(len(self)):
- yield self[i]
-
- def _get_own_repr(self):
- return self._addr_repr(ctypes.addressof(self._blob))
-
-
-class CTypesGenericPtr(CTypesData):
- __slots__ = ['_address', '_as_ctype_ptr']
- _automatic_casts = False
- kind = "pointer"
-
- @classmethod
- def _newp(cls, init):
- return cls(init)
-
- @classmethod
- def _cast_from(cls, source):
- if source is None:
- address = 0
- elif isinstance(source, CTypesData):
- address = source._cast_to_integer()
- elif isinstance(source, (int, long)):
- address = source
- else:
- raise TypeError("bad type for cast to %r: %r" %
- (cls, type(source).__name__))
- return cls._new_pointer_at(address)
-
- @classmethod
- def _new_pointer_at(cls, address):
- self = cls.__new__(cls)
- self._address = address
- self._as_ctype_ptr = ctypes.cast(address, cls._ctype)
- return self
-
- def _get_own_repr(self):
- try:
- return self._addr_repr(self._address)
- except AttributeError:
- return '???'
-
- def _cast_to_integer(self):
- return self._address
-
- def __nonzero__(self):
- return bool(self._address)
- __bool__ = __nonzero__
-
- @classmethod
- def _to_ctypes(cls, value):
- if not isinstance(value, CTypesData):
- raise TypeError("unexpected %s object" % type(value).__name__)
- address = value._convert_to_address(cls)
- return ctypes.cast(address, cls._ctype)
-
- @classmethod
- def _from_ctypes(cls, ctypes_ptr):
- address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0
- return cls._new_pointer_at(address)
-
- @classmethod
- def _initialize(cls, ctypes_ptr, value):
- if value:
- ctypes_ptr.contents = cls._to_ctypes(value).contents
-
- def _convert_to_address(self, BClass):
- if (BClass in (self.__class__, None) or BClass._automatic_casts
- or self._automatic_casts):
- return self._address
- else:
- return CTypesData._convert_to_address(self, BClass)
-
-
-class CTypesBaseStructOrUnion(CTypesData):
- __slots__ = ['_blob']
-
- @classmethod
- def _create_ctype_obj(cls, init):
- # may be overridden
- raise TypeError("cannot instantiate opaque type %s" % (cls,))
-
- def _get_own_repr(self):
- return self._addr_repr(ctypes.addressof(self._blob))
-
- @classmethod
- def _offsetof(cls, fieldname):
- return getattr(cls._ctype, fieldname).offset
-
- def _convert_to_address(self, BClass):
- if getattr(BClass, '_BItem', None) is self.__class__:
- return ctypes.addressof(self._blob)
- else:
- return CTypesData._convert_to_address(self, BClass)
-
- @classmethod
- def _from_ctypes(cls, ctypes_struct_or_union):
- self = cls.__new__(cls)
- self._blob = ctypes_struct_or_union
- return self
-
- @classmethod
- def _to_ctypes(cls, value):
- return value._blob
-
- def __repr__(self, c_name=None):
- return CTypesData.__repr__(self, c_name or self._get_c_name(' &'))
-
-
-class CTypesBackend(object):
-
- PRIMITIVE_TYPES = {
- 'char': ctypes.c_char,
- 'short': ctypes.c_short,
- 'int': ctypes.c_int,
- 'long': ctypes.c_long,
- 'long long': ctypes.c_longlong,
- 'signed char': ctypes.c_byte,
- 'unsigned char': ctypes.c_ubyte,
- 'unsigned short': ctypes.c_ushort,
- 'unsigned int': ctypes.c_uint,
- 'unsigned long': ctypes.c_ulong,
- 'unsigned long long': ctypes.c_ulonglong,
- 'float': ctypes.c_float,
- 'double': ctypes.c_double,
- '_Bool': ctypes.c_bool,
- }
-
- for _name in ['unsigned long long', 'unsigned long',
- 'unsigned int', 'unsigned short', 'unsigned char']:
- _size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
- PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
- if _size == ctypes.sizeof(ctypes.c_void_p):
- PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name]
- if _size == ctypes.sizeof(ctypes.c_size_t):
- PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name]
-
- for _name in ['long long', 'long', 'int', 'short', 'signed char']:
- _size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
- PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
- if _size == ctypes.sizeof(ctypes.c_void_p):
- PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name]
- PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name]
- if _size == ctypes.sizeof(ctypes.c_size_t):
- PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name]
-
-
- def __init__(self):
- self.RTLD_LAZY = 0 # not supported anyway by ctypes
- self.RTLD_NOW = 0
- self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL
- self.RTLD_LOCAL = ctypes.RTLD_LOCAL
-
- def set_ffi(self, ffi):
- self.ffi = ffi
-
- def _get_types(self):
- return CTypesData, CTypesType
-
- def load_library(self, path, flags=0):
- cdll = ctypes.CDLL(path, flags)
- return CTypesLibrary(self, cdll)
-
- def new_void_type(self):
- class CTypesVoid(CTypesData):
- __slots__ = []
- _reftypename = 'void &'
- @staticmethod
- def _from_ctypes(novalue):
- return None
- @staticmethod
- def _to_ctypes(novalue):
- if novalue is not None:
- raise TypeError("None expected, got %s object" %
- (type(novalue).__name__,))
- return None
- CTypesVoid._fix_class()
- return CTypesVoid
-
- def new_primitive_type(self, name):
- if name == 'wchar_t':
- raise NotImplementedError(name)
- ctype = self.PRIMITIVE_TYPES[name]
- if name == 'char':
- kind = 'char'
- elif name in ('float', 'double'):
- kind = 'float'
- else:
- if name in ('signed char', 'unsigned char'):
- kind = 'byte'
- elif name == '_Bool':
- kind = 'bool'
- else:
- kind = 'int'
- is_signed = (ctype(-1).value == -1)
- #
- def _cast_source_to_int(source):
- if isinstance(source, (int, long, float)):
- source = int(source)
- elif isinstance(source, CTypesData):
- source = source._cast_to_integer()
- elif isinstance(source, bytes):
- source = ord(source)
- elif source is None:
- source = 0
- else:
- raise TypeError("bad type for cast to %r: %r" %
- (CTypesPrimitive, type(source).__name__))
- return source
- #
- kind1 = kind
- class CTypesPrimitive(CTypesGenericPrimitive):
- __slots__ = ['_value']
- _ctype = ctype
- _reftypename = '%s &' % name
- kind = kind1
-
- def __init__(self, value):
- self._value = value
-
- @staticmethod
- def _create_ctype_obj(init):
- if init is None:
- return ctype()
- return ctype(CTypesPrimitive._to_ctypes(init))
-
- if kind == 'int' or kind == 'byte':
- @classmethod
- def _cast_from(cls, source):
- source = _cast_source_to_int(source)
- source = ctype(source).value # cast within range
- return cls(source)
- def __int__(self):
- return self._value
-
- if kind == 'bool':
- @classmethod
- def _cast_from(cls, source):
- if not isinstance(source, (int, long, float)):
- source = _cast_source_to_int(source)
- return cls(bool(source))
- def __int__(self):
- return int(self._value)
-
- if kind == 'char':
- @classmethod
- def _cast_from(cls, source):
- source = _cast_source_to_int(source)
- source = bytechr(source & 0xFF)
- return cls(source)
- def __int__(self):
- return ord(self._value)
-
- if kind == 'float':
- @classmethod
- def _cast_from(cls, source):
- if isinstance(source, float):
- pass
- elif isinstance(source, CTypesGenericPrimitive):
- if hasattr(source, '__float__'):
- source = float(source)
- else:
- source = int(source)
- else:
- source = _cast_source_to_int(source)
- source = ctype(source).value # fix precision
- return cls(source)
- def __int__(self):
- return int(self._value)
- def __float__(self):
- return self._value
-
- _cast_to_integer = __int__
-
- if kind == 'int' or kind == 'byte' or kind == 'bool':
- @staticmethod
- def _to_ctypes(x):
- if not isinstance(x, (int, long)):
- if isinstance(x, CTypesData):
- x = int(x)
- else:
- raise TypeError("integer expected, got %s" %
- type(x).__name__)
- if ctype(x).value != x:
- if not is_signed and x < 0:
- raise OverflowError("%s: negative integer" % name)
- else:
- raise OverflowError("%s: integer out of bounds"
- % name)
- return x
-
- if kind == 'char':
- @staticmethod
- def _to_ctypes(x):
- if isinstance(x, bytes) and len(x) == 1:
- return x
- if isinstance(x, CTypesPrimitive): # <CData <char>>
- return x._value
- raise TypeError("character expected, got %s" %
- type(x).__name__)
- def __nonzero__(self):
- return ord(self._value) != 0
- else:
- def __nonzero__(self):
- return self._value != 0
- __bool__ = __nonzero__
-
- if kind == 'float':
- @staticmethod
- def _to_ctypes(x):
- if not isinstance(x, (int, long, float, CTypesData)):
- raise TypeError("float expected, got %s" %
- type(x).__name__)
- return ctype(x).value
-
- @staticmethod
- def _from_ctypes(value):
- return getattr(value, 'value', value)
-
- @staticmethod
- def _initialize(blob, init):
- blob.value = CTypesPrimitive._to_ctypes(init)
-
- if kind == 'char':
- def _to_string(self, maxlen):
- return self._value
- if kind == 'byte':
- def _to_string(self, maxlen):
- return chr(self._value & 0xff)
- #
- CTypesPrimitive._fix_class()
- return CTypesPrimitive
-
- def new_pointer_type(self, BItem):
- getbtype = self.ffi._get_cached_btype
- if BItem is getbtype(model.PrimitiveType('char')):
- kind = 'charp'
- elif BItem in (getbtype(model.PrimitiveType('signed char')),
- getbtype(model.PrimitiveType('unsigned char'))):
- kind = 'bytep'
- elif BItem is getbtype(model.void_type):
- kind = 'voidp'
- else:
- kind = 'generic'
- #
- class CTypesPtr(CTypesGenericPtr):
- __slots__ = ['_own']
- if kind == 'charp':
- __slots__ += ['__as_strbuf']
- _BItem = BItem
- if hasattr(BItem, '_ctype'):
- _ctype = ctypes.POINTER(BItem._ctype)
- _bitem_size = ctypes.sizeof(BItem._ctype)
- else:
- _ctype = ctypes.c_void_p
- if issubclass(BItem, CTypesGenericArray):
- _reftypename = BItem._get_c_name('(* &)')
- else:
- _reftypename = BItem._get_c_name(' * &')
-
- def __init__(self, init):
- ctypeobj = BItem._create_ctype_obj(init)
- if kind == 'charp':
- self.__as_strbuf = ctypes.create_string_buffer(
- ctypeobj.value + b'\x00')
- self._as_ctype_ptr = ctypes.cast(
- self.__as_strbuf, self._ctype)
- else:
- self._as_ctype_ptr = ctypes.pointer(ctypeobj)
- self._address = ctypes.cast(self._as_ctype_ptr,
- ctypes.c_void_p).value
- self._own = True
-
- def __add__(self, other):
- if isinstance(other, (int, long)):
- return self._new_pointer_at(self._address +
- other * self._bitem_size)
- else:
- return NotImplemented
-
- def __sub__(self, other):
- if isinstance(other, (int, long)):
- return self._new_pointer_at(self._address -
- other * self._bitem_size)
- elif type(self) is type(other):
- return (self._address - other._address) // self._bitem_size
- else:
- return NotImplemented
-
- def __getitem__(self, index):
- if getattr(self, '_own', False) and index != 0:
- raise IndexError
- return BItem._from_ctypes(self._as_ctype_ptr[index])
-
- def __setitem__(self, index, value):
- self._as_ctype_ptr[index] = BItem._to_ctypes(value)
-
- if kind == 'charp' or kind == 'voidp':
- @classmethod
- def _arg_to_ctypes(cls, *value):
- if value and isinstance(value[0], bytes):
- return ctypes.c_char_p(value[0])
- else:
- return super(CTypesPtr, cls)._arg_to_ctypes(*value)
-
- if kind == 'charp' or kind == 'bytep':
- def _to_string(self, maxlen):
- if maxlen < 0:
- maxlen = sys.maxsize
- p = ctypes.cast(self._as_ctype_ptr,
- ctypes.POINTER(ctypes.c_char))
- n = 0
- while n < maxlen and p[n] != b'\x00':
- n += 1
- return b''.join([p[i] for i in range(n)])
-
- def _get_own_repr(self):
- if getattr(self, '_own', False):
- return 'owning %d bytes' % (
- ctypes.sizeof(self._as_ctype_ptr.contents),)
- return super(CTypesPtr, self)._get_own_repr()
- #
- if (BItem is self.ffi._get_cached_btype(model.void_type) or
- BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))):
- CTypesPtr._automatic_casts = True
- #
- CTypesPtr._fix_class()
- return CTypesPtr
-
- def new_array_type(self, CTypesPtr, length):
- if length is None:
- brackets = ' &[]'
- else:
- brackets = ' &[%d]' % length
- BItem = CTypesPtr._BItem
- getbtype = self.ffi._get_cached_btype
- if BItem is getbtype(model.PrimitiveType('char')):
- kind = 'char'
- elif BItem in (getbtype(model.PrimitiveType('signed char')),
- getbtype(model.PrimitiveType('unsigned char'))):
- kind = 'byte'
- else:
- kind = 'generic'
- #
- class CTypesArray(CTypesGenericArray):
- __slots__ = ['_blob', '_own']
- if length is not None:
- _ctype = BItem._ctype * length
- else:
- __slots__.append('_ctype')
- _reftypename = BItem._get_c_name(brackets)
- _declared_length = length
- _CTPtr = CTypesPtr
-
- def __init__(self, init):
- if length is None:
- if isinstance(init, (int, long)):
- len1 = init
- init = None
- elif kind == 'char' and isinstance(init, bytes):
- len1 = len(init) + 1 # extra null
- else:
- init = tuple(init)
- len1 = len(init)
- self._ctype = BItem._ctype * len1
- self._blob = self._ctype()
- self._own = True
- if init is not None:
- self._initialize(self._blob, init)
-
- @staticmethod
- def _initialize(blob, init):
- if isinstance(init, bytes):
- init = [init[i:i+1] for i in range(len(init))]
- else:
- if isinstance(init, CTypesGenericArray):
- if (len(init) != len(blob) or
- not isinstance(init, CTypesArray)):
- raise TypeError("length/type mismatch: %s" % (init,))
- init = tuple(init)
- if len(init) > len(blob):
- raise IndexError("too many initializers")
- addr = ctypes.cast(blob, ctypes.c_void_p).value
- PTR = ctypes.POINTER(BItem._ctype)
- itemsize = ctypes.sizeof(BItem._ctype)
- for i, value in enumerate(init):
- p = ctypes.cast(addr + i * itemsize, PTR)
- BItem._initialize(p.contents, value)
-
- def __len__(self):
- return len(self._blob)
-
- def __getitem__(self, index):
- if not (0 <= index < len(self._blob)):
- raise IndexError
- return BItem._from_ctypes(self._blob[index])
-
- def __setitem__(self, index, value):
- if not (0 <= index < len(self._blob)):
- raise IndexError
- self._blob[index] = BItem._to_ctypes(value)
-
- if kind == 'char' or kind == 'byte':
- def _to_string(self, maxlen):
- if maxlen < 0:
- maxlen = len(self._blob)
- p = ctypes.cast(self._blob,
- ctypes.POINTER(ctypes.c_char))
- n = 0
- while n < maxlen and p[n] != b'\x00':
- n += 1
- return b''.join([p[i] for i in range(n)])
-
- def _get_own_repr(self):
- if getattr(self, '_own', False):
- return 'owning %d bytes' % (ctypes.sizeof(self._blob),)
- return super(CTypesArray, self)._get_own_repr()
-
- def _convert_to_address(self, BClass):
- if BClass in (CTypesPtr, None) or BClass._automatic_casts:
- return ctypes.addressof(self._blob)
- else:
- return CTypesData._convert_to_address(self, BClass)
-
- @staticmethod
- def _from_ctypes(ctypes_array):
- self = CTypesArray.__new__(CTypesArray)
- self._blob = ctypes_array
- return self
-
- @staticmethod
- def _arg_to_ctypes(value):
- return CTypesPtr._arg_to_ctypes(value)
-
- def __add__(self, other):
- if isinstance(other, (int, long)):
- return CTypesPtr._new_pointer_at(
- ctypes.addressof(self._blob) +
- other * ctypes.sizeof(BItem._ctype))
- else:
- return NotImplemented
-
- @classmethod
- def _cast_from(cls, source):
- raise NotImplementedError("casting to %r" % (
- cls._get_c_name(),))
- #
- CTypesArray._fix_class()
- return CTypesArray
-
- def _new_struct_or_union(self, kind, name, base_ctypes_class):
- #
- class struct_or_union(base_ctypes_class):
- pass
- struct_or_union.__name__ = '%s_%s' % (kind, name)
- kind1 = kind
- #
- class CTypesStructOrUnion(CTypesBaseStructOrUnion):
- __slots__ = ['_blob']
- _ctype = struct_or_union
- _reftypename = '%s &' % (name,)
- _kind = kind = kind1
- #
- CTypesStructOrUnion._fix_class()
- return CTypesStructOrUnion
-
- def new_struct_type(self, name):
- return self._new_struct_or_union('struct', name, ctypes.Structure)
-
- def new_union_type(self, name):
- return self._new_struct_or_union('union', name, ctypes.Union)
-
- def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp,
- totalsize=-1, totalalignment=-1, sflags=0,
- pack=0):
- if totalsize >= 0 or totalalignment >= 0:
- raise NotImplementedError("the ctypes backend of CFFI does not support "
- "structures completed by verify(); please "
- "compile and install the _cffi_backend module.")
- struct_or_union = CTypesStructOrUnion._ctype
- fnames = [fname for (fname, BField, bitsize) in fields]
- btypes = [BField for (fname, BField, bitsize) in fields]
- bitfields = [bitsize for (fname, BField, bitsize) in fields]
- #
- bfield_types = {}
- cfields = []
- for (fname, BField, bitsize) in fields:
- if bitsize < 0:
- cfields.append((fname, BField._ctype))
- bfield_types[fname] = BField
- else:
- cfields.append((fname, BField._ctype, bitsize))
- bfield_types[fname] = Ellipsis
- if sflags & 8:
- struct_or_union._pack_ = 1
- elif pack:
- struct_or_union._pack_ = pack
- struct_or_union._fields_ = cfields
- CTypesStructOrUnion._bfield_types = bfield_types
- #
- @staticmethod
- def _create_ctype_obj(init):
- result = struct_or_union()
- if init is not None:
- initialize(result, init)
- return result
- CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj
- #
- def initialize(blob, init):
- if is_union:
- if len(init) > 1:
- raise ValueError("union initializer: %d items given, but "
- "only one supported (use a dict if needed)"
- % (len(init),))
- if not isinstance(init, dict):
- if isinstance(init, (bytes, unicode)):
- raise TypeError("union initializer: got a str")
- init = tuple(init)
- if len(init) > len(fnames):
- raise ValueError("too many values for %s initializer" %
- CTypesStructOrUnion._get_c_name())
- init = dict(zip(fnames, init))
- addr = ctypes.addressof(blob)
- for fname, value in init.items():
- BField, bitsize = name2fieldtype[fname]
- assert bitsize < 0, \
- "not implemented: initializer with bit fields"
- offset = CTypesStructOrUnion._offsetof(fname)
- PTR = ctypes.POINTER(BField._ctype)
- p = ctypes.cast(addr + offset, PTR)
- BField._initialize(p.contents, value)
- is_union = CTypesStructOrUnion._kind == 'union'
- name2fieldtype = dict(zip(fnames, zip(btypes, bitfields)))
- #
- for fname, BField, bitsize in fields:
- if fname == '':
- raise NotImplementedError("nested anonymous structs/unions")
- if hasattr(CTypesStructOrUnion, fname):
- raise ValueError("the field name %r conflicts in "
- "the ctypes backend" % fname)
- if bitsize < 0:
- def getter(self, fname=fname, BField=BField,
- offset=CTypesStructOrUnion._offsetof(fname),
- PTR=ctypes.POINTER(BField._ctype)):
- addr = ctypes.addressof(self._blob)
- p = ctypes.cast(addr + offset, PTR)
- return BField._from_ctypes(p.contents)
- def setter(self, value, fname=fname, BField=BField):
- setattr(self._blob, fname, BField._to_ctypes(value))
- #
- if issubclass(BField, CTypesGenericArray):
- setter = None
- if BField._declared_length == 0:
- def getter(self, fname=fname, BFieldPtr=BField._CTPtr,
- offset=CTypesStructOrUnion._offsetof(fname),
- PTR=ctypes.POINTER(BField._ctype)):
- addr = ctypes.addressof(self._blob)
- p = ctypes.cast(addr + offset, PTR)
- return BFieldPtr._from_ctypes(p)
- #
- else:
- def getter(self, fname=fname, BField=BField):
- return BField._from_ctypes(getattr(self._blob, fname))
- def setter(self, value, fname=fname, BField=BField):
- # xxx obscure workaround
- value = BField._to_ctypes(value)
- oldvalue = getattr(self._blob, fname)
- setattr(self._blob, fname, value)
- if value != getattr(self._blob, fname):
- setattr(self._blob, fname, oldvalue)
- raise OverflowError("value too large for bitfield")
- setattr(CTypesStructOrUnion, fname, property(getter, setter))
- #
- CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp))
- for fname in fnames:
- if hasattr(CTypesPtr, fname):
- raise ValueError("the field name %r conflicts in "
- "the ctypes backend" % fname)
- def getter(self, fname=fname):
- return getattr(self[0], fname)
- def setter(self, value, fname=fname):
- setattr(self[0], fname, value)
- setattr(CTypesPtr, fname, property(getter, setter))
-
- def new_function_type(self, BArgs, BResult, has_varargs):
- nameargs = [BArg._get_c_name() for BArg in BArgs]
- if has_varargs:
- nameargs.append('...')
- nameargs = ', '.join(nameargs)
- #
- class CTypesFunctionPtr(CTypesGenericPtr):
- __slots__ = ['_own_callback', '_name']
- _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None),
- *[BArg._ctype for BArg in BArgs],
- use_errno=True)
- _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,))
-
- def __init__(self, init, error=None):
- # create a callback to the Python callable init()
- import traceback
- assert not has_varargs, "varargs not supported for callbacks"
- if getattr(BResult, '_ctype', None) is not None:
- error = BResult._from_ctypes(
- BResult._create_ctype_obj(error))
- else:
- error = None
- def callback(*args):
- args2 = []
- for arg, BArg in zip(args, BArgs):
- args2.append(BArg._from_ctypes(arg))
- try:
- res2 = init(*args2)
- res2 = BResult._to_ctypes(res2)
- except:
- traceback.print_exc()
- res2 = error
- if issubclass(BResult, CTypesGenericPtr):
- if res2:
- res2 = ctypes.cast(res2, ctypes.c_void_p).value
- # .value: http://bugs.python.org/issue1574593
- else:
- res2 = None
- #print repr(res2)
- return res2
- if issubclass(BResult, CTypesGenericPtr):
- # The only pointers callbacks can return are void*s:
- # http://bugs.python.org/issue5710
- callback_ctype = ctypes.CFUNCTYPE(
- ctypes.c_void_p,
- *[BArg._ctype for BArg in BArgs],
- use_errno=True)
- else:
- callback_ctype = CTypesFunctionPtr._ctype
- self._as_ctype_ptr = callback_ctype(callback)
- self._address = ctypes.cast(self._as_ctype_ptr,
- ctypes.c_void_p).value
- self._own_callback = init
-
- @staticmethod
- def _initialize(ctypes_ptr, value):
- if value:
- raise NotImplementedError("ctypes backend: not supported: "
- "initializers for function pointers")
-
- def __repr__(self):
- c_name = getattr(self, '_name', None)
- if c_name:
- i = self._reftypename.index('(* &)')
- if self._reftypename[i-1] not in ' )*':
- c_name = ' ' + c_name
- c_name = self._reftypename.replace('(* &)', c_name)
- return CTypesData.__repr__(self, c_name)
-
- def _get_own_repr(self):
- if getattr(self, '_own_callback', None) is not None:
- return 'calling %r' % (self._own_callback,)
- return super(CTypesFunctionPtr, self)._get_own_repr()
-
- def __call__(self, *args):
- if has_varargs:
- assert len(args) >= len(BArgs)
- extraargs = args[len(BArgs):]
- args = args[:len(BArgs)]
- else:
- assert len(args) == len(BArgs)
- ctypes_args = []
- for arg, BArg in zip(args, BArgs):
- ctypes_args.append(BArg._arg_to_ctypes(arg))
- if has_varargs:
- for i, arg in enumerate(extraargs):
- if arg is None:
- ctypes_args.append(ctypes.c_void_p(0)) # NULL
- continue
- if not isinstance(arg, CTypesData):
- raise TypeError(
- "argument %d passed in the variadic part "
- "needs to be a cdata object (got %s)" %
- (1 + len(BArgs) + i, type(arg).__name__))
- ctypes_args.append(arg._arg_to_ctypes(arg))
- result = self._as_ctype_ptr(*ctypes_args)
- return BResult._from_ctypes(result)
- #
- CTypesFunctionPtr._fix_class()
- return CTypesFunctionPtr
-
- def new_enum_type(self, name, enumerators, enumvalues, CTypesInt):
- assert isinstance(name, str)
- reverse_mapping = dict(zip(reversed(enumvalues),
- reversed(enumerators)))
- #
- class CTypesEnum(CTypesInt):
- __slots__ = []
- _reftypename = '%s &' % name
-
- def _get_own_repr(self):
- value = self._value
- try:
- return '%d: %s' % (value, reverse_mapping[value])
- except KeyError:
- return str(value)
-
- def _to_string(self, maxlen):
- value = self._value
- try:
- return reverse_mapping[value]
- except KeyError:
- return str(value)
- #
- CTypesEnum._fix_class()
- return CTypesEnum
-
- def get_errno(self):
- return ctypes.get_errno()
-
- def set_errno(self, value):
- ctypes.set_errno(value)
-
- def string(self, b, maxlen=-1):
- return b._to_string(maxlen)
-
- def buffer(self, bptr, size=-1):
- raise NotImplementedError("buffer() with ctypes backend")
-
- def sizeof(self, cdata_or_BType):
- if isinstance(cdata_or_BType, CTypesData):
- return cdata_or_BType._get_size_of_instance()
- else:
- assert issubclass(cdata_or_BType, CTypesData)
- return cdata_or_BType._get_size()
-
- def alignof(self, BType):
- assert issubclass(BType, CTypesData)
- return BType._alignment()
-
- def newp(self, BType, source):
- if not issubclass(BType, CTypesData):
- raise TypeError
- return BType._newp(source)
-
- def cast(self, BType, source):
- return BType._cast_from(source)
-
- def callback(self, BType, source, error, onerror):
- assert onerror is None # XXX not implemented
- return BType(source, error)
-
- _weakref_cache_ref = None
-
- def gcp(self, cdata, destructor, size=0):
- if self._weakref_cache_ref is None:
- import weakref
- class MyRef(weakref.ref):
- def __eq__(self, other):
- myref = self()
- return self is other or (
- myref is not None and myref is other())
- def __ne__(self, other):
- return not (self == other)
- def __hash__(self):
- try:
- return self._hash
- except AttributeError:
- self._hash = hash(self())
- return self._hash
- self._weakref_cache_ref = {}, MyRef
- weak_cache, MyRef = self._weakref_cache_ref
-
- if destructor is None:
- try:
- del weak_cache[MyRef(cdata)]
- except KeyError:
- raise TypeError("Can remove destructor only on a object "
- "previously returned by ffi.gc()")
- return None
-
- def remove(k):
- cdata, destructor = weak_cache.pop(k, (None, None))
- if destructor is not None:
- destructor(cdata)
-
- new_cdata = self.cast(self.typeof(cdata), cdata)
- assert new_cdata is not cdata
- weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor)
- return new_cdata
-
- typeof = type
-
- def getcname(self, BType, replace_with):
- return BType._get_c_name(replace_with)
-
- def typeoffsetof(self, BType, fieldname, num=0):
- if isinstance(fieldname, str):
- if num == 0 and issubclass(BType, CTypesGenericPtr):
- BType = BType._BItem
- if not issubclass(BType, CTypesBaseStructOrUnion):
- raise TypeError("expected a struct or union ctype")
- BField = BType._bfield_types[fieldname]
- if BField is Ellipsis:
- raise TypeError("not supported for bitfields")
- return (BField, BType._offsetof(fieldname))
- elif isinstance(fieldname, (int, long)):
- if issubclass(BType, CTypesGenericArray):
- BType = BType._CTPtr
- if not issubclass(BType, CTypesGenericPtr):
- raise TypeError("expected an array or ptr ctype")
- BItem = BType._BItem
- offset = BItem._get_size() * fieldname
- if offset > sys.maxsize:
- raise OverflowError
- return (BItem, offset)
- else:
- raise TypeError(type(fieldname))
-
- def rawaddressof(self, BTypePtr, cdata, offset=None):
- if isinstance(cdata, CTypesBaseStructOrUnion):
- ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata))
- elif isinstance(cdata, CTypesGenericPtr):
- if offset is None or not issubclass(type(cdata)._BItem,
- CTypesBaseStructOrUnion):
- raise TypeError("unexpected cdata type")
- ptr = type(cdata)._to_ctypes(cdata)
- elif isinstance(cdata, CTypesGenericArray):
- ptr = type(cdata)._to_ctypes(cdata)
- else:
- raise TypeError("expected a <cdata 'struct-or-union'>")
- if offset:
- ptr = ctypes.cast(
- ctypes.c_void_p(
- ctypes.cast(ptr, ctypes.c_void_p).value + offset),
- type(ptr))
- return BTypePtr._from_ctypes(ptr)
-
-
-class CTypesLibrary(object):
-
- def __init__(self, backend, cdll):
- self.backend = backend
- self.cdll = cdll
-
- def load_function(self, BType, name):
- c_func = getattr(self.cdll, name)
- funcobj = BType._from_ctypes(c_func)
- funcobj._name = name
- return funcobj
-
- def read_variable(self, BType, name):
- try:
- ctypes_obj = BType._ctype.in_dll(self.cdll, name)
- except AttributeError as e:
- raise NotImplementedError(e)
- return BType._from_ctypes(ctypes_obj)
-
- def write_variable(self, BType, name, value):
- new_ctypes_obj = BType._to_ctypes(value)
- ctypes_obj = BType._ctype.in_dll(self.cdll, name)
- ctypes.memmove(ctypes.addressof(ctypes_obj),
- ctypes.addressof(new_ctypes_obj),
- ctypes.sizeof(BType._ctype))
diff --git a/cffi/cffi_opcode.py b/cffi/cffi_opcode.py
deleted file mode 100644
index a0df98d..0000000
--- a/cffi/cffi_opcode.py
+++ /dev/null
@@ -1,187 +0,0 @@
-from .error import VerificationError
-
-class CffiOp(object):
- def __init__(self, op, arg):
- self.op = op
- self.arg = arg
-
- def as_c_expr(self):
- if self.op is None:
- assert isinstance(self.arg, str)
- return '(_cffi_opcode_t)(%s)' % (self.arg,)
- classname = CLASS_NAME[self.op]
- return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg)
-
- def as_python_bytes(self):
- if self.op is None and self.arg.isdigit():
- value = int(self.arg) # non-negative: '-' not in self.arg
- if value >= 2**31:
- raise OverflowError("cannot emit %r: limited to 2**31-1"
- % (self.arg,))
- return format_four_bytes(value)
- if isinstance(self.arg, str):
- raise VerificationError("cannot emit to Python: %r" % (self.arg,))
- return format_four_bytes((self.arg << 8) | self.op)
-
- def __str__(self):
- classname = CLASS_NAME.get(self.op, self.op)
- return '(%s %s)' % (classname, self.arg)
-
-def format_four_bytes(num):
- return '\\x%02X\\x%02X\\x%02X\\x%02X' % (
- (num >> 24) & 0xFF,
- (num >> 16) & 0xFF,
- (num >> 8) & 0xFF,
- (num ) & 0xFF)
-
-OP_PRIMITIVE = 1
-OP_POINTER = 3
-OP_ARRAY = 5
-OP_OPEN_ARRAY = 7
-OP_STRUCT_UNION = 9
-OP_ENUM = 11
-OP_FUNCTION = 13
-OP_FUNCTION_END = 15
-OP_NOOP = 17
-OP_BITFIELD = 19
-OP_TYPENAME = 21
-OP_CPYTHON_BLTN_V = 23 # varargs
-OP_CPYTHON_BLTN_N = 25 # noargs
-OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg)
-OP_CONSTANT = 29
-OP_CONSTANT_INT = 31
-OP_GLOBAL_VAR = 33
-OP_DLOPEN_FUNC = 35
-OP_DLOPEN_CONST = 37
-OP_GLOBAL_VAR_F = 39
-OP_EXTERN_PYTHON = 41
-
-PRIM_VOID = 0
-PRIM_BOOL = 1
-PRIM_CHAR = 2
-PRIM_SCHAR = 3
-PRIM_UCHAR = 4
-PRIM_SHORT = 5
-PRIM_USHORT = 6
-PRIM_INT = 7
-PRIM_UINT = 8
-PRIM_LONG = 9
-PRIM_ULONG = 10
-PRIM_LONGLONG = 11
-PRIM_ULONGLONG = 12
-PRIM_FLOAT = 13
-PRIM_DOUBLE = 14
-PRIM_LONGDOUBLE = 15
-
-PRIM_WCHAR = 16
-PRIM_INT8 = 17
-PRIM_UINT8 = 18
-PRIM_INT16 = 19
-PRIM_UINT16 = 20
-PRIM_INT32 = 21
-PRIM_UINT32 = 22
-PRIM_INT64 = 23
-PRIM_UINT64 = 24
-PRIM_INTPTR = 25
-PRIM_UINTPTR = 26
-PRIM_PTRDIFF = 27
-PRIM_SIZE = 28
-PRIM_SSIZE = 29
-PRIM_INT_LEAST8 = 30
-PRIM_UINT_LEAST8 = 31
-PRIM_INT_LEAST16 = 32
-PRIM_UINT_LEAST16 = 33
-PRIM_INT_LEAST32 = 34
-PRIM_UINT_LEAST32 = 35
-PRIM_INT_LEAST64 = 36
-PRIM_UINT_LEAST64 = 37
-PRIM_INT_FAST8 = 38
-PRIM_UINT_FAST8 = 39
-PRIM_INT_FAST16 = 40
-PRIM_UINT_FAST16 = 41
-PRIM_INT_FAST32 = 42
-PRIM_UINT_FAST32 = 43
-PRIM_INT_FAST64 = 44
-PRIM_UINT_FAST64 = 45
-PRIM_INTMAX = 46
-PRIM_UINTMAX = 47
-PRIM_FLOATCOMPLEX = 48
-PRIM_DOUBLECOMPLEX = 49
-PRIM_CHAR16 = 50
-PRIM_CHAR32 = 51
-
-_NUM_PRIM = 52
-_UNKNOWN_PRIM = -1
-_UNKNOWN_FLOAT_PRIM = -2
-_UNKNOWN_LONG_DOUBLE = -3
-
-_IO_FILE_STRUCT = -1
-
-PRIMITIVE_TO_INDEX = {
- 'char': PRIM_CHAR,
- 'short': PRIM_SHORT,
- 'int': PRIM_INT,
- 'long': PRIM_LONG,
- 'long long': PRIM_LONGLONG,
- 'signed char': PRIM_SCHAR,
- 'unsigned char': PRIM_UCHAR,
- 'unsigned short': PRIM_USHORT,
- 'unsigned int': PRIM_UINT,
- 'unsigned long': PRIM_ULONG,
- 'unsigned long long': PRIM_ULONGLONG,
- 'float': PRIM_FLOAT,
- 'double': PRIM_DOUBLE,
- 'long double': PRIM_LONGDOUBLE,
- 'float _Complex': PRIM_FLOATCOMPLEX,
- 'double _Complex': PRIM_DOUBLECOMPLEX,
- '_Bool': PRIM_BOOL,
- 'wchar_t': PRIM_WCHAR,
- 'char16_t': PRIM_CHAR16,
- 'char32_t': PRIM_CHAR32,
- 'int8_t': PRIM_INT8,
- 'uint8_t': PRIM_UINT8,
- 'int16_t': PRIM_INT16,
- 'uint16_t': PRIM_UINT16,
- 'int32_t': PRIM_INT32,
- 'uint32_t': PRIM_UINT32,
- 'int64_t': PRIM_INT64,
- 'uint64_t': PRIM_UINT64,
- 'intptr_t': PRIM_INTPTR,
- 'uintptr_t': PRIM_UINTPTR,
- 'ptrdiff_t': PRIM_PTRDIFF,
- 'size_t': PRIM_SIZE,
- 'ssize_t': PRIM_SSIZE,
- 'int_least8_t': PRIM_INT_LEAST8,
- 'uint_least8_t': PRIM_UINT_LEAST8,
- 'int_least16_t': PRIM_INT_LEAST16,
- 'uint_least16_t': PRIM_UINT_LEAST16,
- 'int_least32_t': PRIM_INT_LEAST32,
- 'uint_least32_t': PRIM_UINT_LEAST32,
- 'int_least64_t': PRIM_INT_LEAST64,
- 'uint_least64_t': PRIM_UINT_LEAST64,
- 'int_fast8_t': PRIM_INT_FAST8,
- 'uint_fast8_t': PRIM_UINT_FAST8,
- 'int_fast16_t': PRIM_INT_FAST16,
- 'uint_fast16_t': PRIM_UINT_FAST16,
- 'int_fast32_t': PRIM_INT_FAST32,
- 'uint_fast32_t': PRIM_UINT_FAST32,
- 'int_fast64_t': PRIM_INT_FAST64,
- 'uint_fast64_t': PRIM_UINT_FAST64,
- 'intmax_t': PRIM_INTMAX,
- 'uintmax_t': PRIM_UINTMAX,
- }
-
-F_UNION = 0x01
-F_CHECK_FIELDS = 0x02
-F_PACKED = 0x04
-F_EXTERNAL = 0x08
-F_OPAQUE = 0x10
-
-G_FLAGS = dict([('_CFFI_' + _key, globals()[_key])
- for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED',
- 'F_EXTERNAL', 'F_OPAQUE']])
-
-CLASS_NAME = {}
-for _name, _value in list(globals().items()):
- if _name.startswith('OP_') and isinstance(_value, int):
- CLASS_NAME[_value] = _name[3:]
diff --git a/cffi/commontypes.py b/cffi/commontypes.py
deleted file mode 100644
index 8ec97c7..0000000
--- a/cffi/commontypes.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import sys
-from . import model
-from .error import FFIError
-
-
-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'):
- COMMON_TYPES[_type] = _type
-del _type
-
-_CACHE = {}
-
-def resolve_common_type(parser, commontype):
- try:
- return _CACHE[commontype]
- except KeyError:
- 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 FFIError("The Windows type %r is only available after "
- "you call ffi.set_unicode()" % (commontype,))
- else:
- if commontype == cdecl:
- raise FFIError(
- "Unsupported type: %r. Please look at "
- "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations "
- "and file an issue if you think this type should really "
- "be supported." % (commontype,))
- result, quals = parser.parse_type_and_quals(cdecl) # recursive
-
- assert isinstance(result, model.BaseTypeByIdentity)
- _CACHE[commontype] = result, quals
- return result, quals
-
-
-# ____________________________________________________________
-# extra types for Windows (most of them are in commontypes.c)
-
-
-def win_common_types():
- return {
- "UNICODE_STRING": model.StructType(
- "_UNICODE_STRING",
- ["Length",
- "MaximumLength",
- "Buffer"],
- [model.PrimitiveType("unsigned short"),
- model.PrimitiveType("unsigned short"),
- model.PointerType(model.PrimitiveType("wchar_t"))],
- [-1, -1, -1]),
- "PUNICODE_STRING": "UNICODE_STRING *",
- "PCUNICODE_STRING": "const UNICODE_STRING *",
-
- "TBYTE": "set-unicode-needed",
- "TCHAR": "set-unicode-needed",
- "LPCTSTR": "set-unicode-needed",
- "PCTSTR": "set-unicode-needed",
- "LPTSTR": "set-unicode-needed",
- "PTSTR": "set-unicode-needed",
- "PTBYTE": "set-unicode-needed",
- "PTCHAR": "set-unicode-needed",
- }
-
-if sys.platform == 'win32':
- COMMON_TYPES.update(win_common_types())
diff --git a/cffi/cparser.py b/cffi/cparser.py
deleted file mode 100644
index 74830e9..0000000
--- a/cffi/cparser.py
+++ /dev/null
@@ -1,1006 +0,0 @@
-from . import model
-from .commontypes import COMMON_TYPES, resolve_common_type
-from .error import FFIError, CDefError
-try:
- from . import _pycparser as pycparser
-except ImportError:
- import pycparser
-import weakref, re, sys
-
-try:
- if sys.version_info < (3,):
- import thread as _thread
- else:
- import _thread
- lock = _thread.allocate_lock()
-except ImportError:
- lock = None
-
-def _workaround_for_static_import_finders():
- # Issue #392: packaging tools like cx_Freeze can not find these
- # because pycparser uses exec dynamic import. This is an obscure
- # workaround. This function is never called.
- import pycparser.yacctab
- import pycparser.lextab
-
-CDEF_SOURCE_STRING = "<cdef source string>"
-_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$",
- re.DOTALL | re.MULTILINE)
-_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)"
- r"\b((?:[^\n\\]|\\.)*?)$",
- re.DOTALL | re.MULTILINE)
-_r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE)
-_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}")
-_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
-_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
-_r_words = re.compile(r"\w+|\S")
-_parser_cache = None
-_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE)
-_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_extern_python = re.compile(r'\bextern\s*"'
- r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.')
-_r_star_const_space = re.compile( # matches "* const "
- r"[*]\s*((const|volatile|restrict)\b\s*)+")
-_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+"
- r"\.\.\.")
-_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.")
-
-def _get_parser():
- global _parser_cache
- if _parser_cache is None:
- _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_extern_python(csource):
- # input: `extern "Python" int foo(int);` or
- # `extern "Python" { int foo(int); }`
- # output:
- # void __cffi_extern_python_start;
- # int foo(int);
- # void __cffi_extern_python_stop;
- #
- # input: `extern "Python+C" int foo(int);`
- # output:
- # void __cffi_extern_python_plus_c_start;
- # int foo(int);
- # void __cffi_extern_python_stop;
- parts = []
- while True:
- match = _r_extern_python.search(csource)
- if not match:
- break
- endpos = match.end() - 1
- #print
- #print ''.join(parts)+csource
- #print '=>'
- parts.append(csource[:match.start()])
- if 'C' in match.group(1):
- parts.append('void __cffi_extern_python_plus_c_start; ')
- else:
- parts.append('void __cffi_extern_python_start; ')
- if csource[endpos] == '{':
- # grouping variant
- closing = csource.find('}', endpos)
- if closing < 0:
- raise CDefError("'extern \"Python\" {': no '}' found")
- if csource.find('{', endpos + 1, closing) >= 0:
- raise NotImplementedError("cannot use { } inside a block "
- "'extern \"Python\" { ... }'")
- parts.append(csource[endpos+1:closing])
- csource = csource[closing+1:]
- else:
- # non-grouping variant
- semicolon = csource.find(';', endpos)
- if semicolon < 0:
- raise CDefError("'extern \"Python\": no ';' found")
- parts.append(csource[endpos:semicolon+1])
- csource = csource[semicolon+1:]
- parts.append(' void __cffi_extern_python_stop;')
- #print ''.join(parts)+csource
- #print
- parts.append(csource)
- return ''.join(parts)
-
-def _warn_for_string_literal(csource):
- if '"' not in csource:
- return
- for line in csource.splitlines():
- if '"' in line and not line.lstrip().startswith('#'):
- import warnings
- warnings.warn("String literal found in cdef() or type source. "
- "String literals are ignored here, but you should "
- "remove them anyway because some character sequences "
- "confuse pre-parsing.")
- break
-
-def _warn_for_non_extern_non_static_global_variable(decl):
- if not decl.storage:
- import warnings
- warnings.warn("Global variable '%s' in cdef(): for consistency "
- "with C it should have a storage class specifier "
- "(usually 'extern')" % (decl.name,))
-
-def _remove_line_directives(csource):
- # _r_line_directive matches whole lines, without the final \n, if they
- # start with '#line' with some spacing allowed, or '#NUMBER'. This
- # function stores them away and replaces them with exactly the string
- # '#line@N', where N is the index in the list 'line_directives'.
- line_directives = []
- def replace(m):
- i = len(line_directives)
- line_directives.append(m.group())
- return '#line@%d' % i
- csource = _r_line_directive.sub(replace, csource)
- return csource, line_directives
-
-def _put_back_line_directives(csource, line_directives):
- def replace(m):
- s = m.group()
- if not s.startswith('#line@'):
- raise AssertionError("unexpected #line directive "
- "(should have been processed and removed")
- return line_directives[int(s[6:])]
- return _r_line_directive.sub(replace, csource)
-
-def _preprocess(csource):
- # First, remove the lines of the form '#line N "filename"' because
- # the "filename" part could confuse the rest
- csource, line_directives = _remove_line_directives(csource)
- # Remove comments. NOTE: this only work because the cdef() section
- # should not contain any string literals (except in line directives)!
- def replace_keeping_newlines(m):
- return ' ' + m.group().count('\n') * '\n'
- csource = _r_comment.sub(replace_keeping_newlines, csource)
- # Remove the "#define FOO x" lines
- macros = {}
- for match in _r_define.finditer(csource):
- macroname, macrovalue = match.groups()
- 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...
- # Hack number 2 is that "int(volatile *fptr)();" is not valid C
- # syntax, so we place the "volatile" before the opening parenthesis.
- csource = _r_stdcall2.sub(' volatile volatile const(', csource)
- csource = _r_stdcall1.sub(' volatile volatile const ', csource)
- csource = _r_cdecl.sub(' ', csource)
- #
- # Replace `extern "Python"` with start/end markers
- csource = _preprocess_extern_python(csource)
- #
- # Now there should not be any string literal left; warn if we get one
- _warn_for_string_literal(csource)
- #
- # Replace "[...]" with "[__dotdotdotarray__]"
- csource = _r_partial_array.sub('[__dotdotdotarray__]', csource)
- #
- # Replace "...}" with "__dotdotdotNUM__}". This construction should
- # occur only at the end of enums; at the end of structs we have "...;}"
- # and at the end of vararg functions "...);". Also replace "=...[,}]"
- # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when
- # giving an unknown value.
- matches = list(_r_partial_enum.finditer(csource))
- for number, match in enumerate(reversed(matches)):
- p = match.start()
- if csource[p] == '=':
- p2 = csource.find('...', p, match.end())
- assert p2 > p
- csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number,
- csource[p2+3:])
- else:
- assert csource[p:p+3] == '...'
- csource = '%s __dotdotdot%d__ %s' % (csource[:p], number,
- csource[p+3:])
- # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__"
- csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource)
- # Replace "float ..." or "double..." with "__dotdotdotfloat__"
- csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource)
- # Replace all remaining "..." with the same name, "__dotdotdot__",
- # which is declared with a typedef for the purpose of C parsing.
- csource = csource.replace('...', ' __dotdotdot__ ')
- # Finally, put back the line directives
- csource = _put_back_line_directives(csource, line_directives)
- return csource, macros
-
-def _common_type_names(csource):
- # Look in the source for what looks like usages of types from the
- # list of common types. A "usage" is approximated here as the
- # appearance of the word, minus a "definition" of the type, which
- # is the last word in a "typedef" statement. Approximative only
- # but should be fine for all the common types.
- look_for_words = set(COMMON_TYPES)
- look_for_words.add(';')
- look_for_words.add(',')
- look_for_words.add('(')
- look_for_words.add(')')
- look_for_words.add('typedef')
- words_used = set()
- is_typedef = False
- paren = 0
- previous_word = ''
- for word in _r_words.findall(csource):
- if word in look_for_words:
- if word == ';':
- if is_typedef:
- words_used.discard(previous_word)
- look_for_words.discard(previous_word)
- is_typedef = False
- elif word == 'typedef':
- is_typedef = True
- paren = 0
- elif word == '(':
- paren += 1
- elif word == ')':
- paren -= 1
- elif word == ',':
- if is_typedef and paren == 0:
- words_used.discard(previous_word)
- look_for_words.discard(previous_word)
- else: # word in COMMON_TYPES
- words_used.add(word)
- previous_word = word
- return words_used
-
-
-class Parser(object):
-
- def __init__(self):
- self._declarations = {}
- self._included_declarations = set()
- self._anonymous_counter = 0
- self._structnode2type = weakref.WeakKeyDictionary()
- self._options = {}
- self._int_constants = {}
- self._recomplete = []
- self._uses_new_feature = None
-
- def _parse(self, csource):
- csource, macros = _preprocess(csource)
- # XXX: for more efficiency we would need to poke into the
- # internals of CParser... the following registers the
- # typedefs, because their presence or absence influences the
- # parsing itself (but what they are typedef'ed to plays no role)
- ctn = _common_type_names(csource)
- typenames = []
- for name in sorted(self._declarations):
- if name.startswith('typedef '):
- name = name[8:]
- typenames.append(name)
- ctn.discard(name)
- typenames += sorted(ctn)
- #
- csourcelines = []
- csourcelines.append('# 1 "<cdef automatic initialization code>"')
- for typename in typenames:
- csourcelines.append('typedef int %s;' % typename)
- csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,'
- ' __dotdotdot__;')
- # this forces pycparser to consider the following in the file
- # called <cdef source string> from line 1
- csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,))
- csourcelines.append(csource)
- fullcsource = '\n'.join(csourcelines)
- if lock is not None:
- lock.acquire() # pycparser is not thread-safe...
- try:
- ast = _get_parser().parse(fullcsource)
- except pycparser.c_parser.ParseError as e:
- self.convert_pycparser_error(e, csource)
- finally:
- if lock is not None:
- lock.release()
- # csource will be used to find buggy source text
- return ast, macros, csource
-
- def _convert_pycparser_error(self, e, csource):
- # xxx look for "<cdef source string>:NUM:" at the start of str(e)
- # and interpret that as a line number. This will not work if
- # the user gives explicit ``# NUM "FILE"`` directives.
- line = None
- msg = str(e)
- match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg)
- if match:
- linenum = int(match.group(1), 10)
- csourcelines = csource.splitlines()
- if 1 <= linenum <= len(csourcelines):
- line = csourcelines[linenum-1]
- return line
-
- def convert_pycparser_error(self, e, csource):
- line = self._convert_pycparser_error(e, csource)
-
- msg = str(e)
- if line:
- msg = 'cannot parse "%s"\n%s' % (line.strip(), msg)
- else:
- msg = 'parse error\n%s' % (msg,)
- raise CDefError(msg)
-
- def parse(self, csource, override=False, packed=False, pack=None,
- dllexport=False):
- if packed:
- if packed != True:
- raise ValueError("'packed' should be False or True; use "
- "'pack' to give another value")
- if pack:
- raise ValueError("cannot give both 'pack' and 'packed'")
- pack = 1
- elif pack:
- if pack & (pack - 1):
- raise ValueError("'pack' must be a power of two, not %r" %
- (pack,))
- else:
- pack = 0
- prev_options = self._options
- try:
- self._options = {'override': override,
- 'packed': pack,
- 'dllexport': dllexport}
- self._internal_parse(csource)
- finally:
- self._options = prev_options
-
- def _internal_parse(self, csource):
- ast, macros, csource = self._parse(csource)
- # add the macros
- self._process_macros(macros)
- # find the first "__dotdotdot__" and use that as a separator
- # between the repeated typedefs and the real csource
- iterator = iter(ast.ext)
- for decl in iterator:
- if decl.name == '__dotdotdot__':
- break
- else:
- assert 0
- current_decl = None
- #
- try:
- self._inside_extern_python = '__cffi_extern_python_stop'
- for decl in iterator:
- current_decl = decl
- if isinstance(decl, pycparser.c_ast.Decl):
- self._parse_decl(decl)
- elif isinstance(decl, pycparser.c_ast.Typedef):
- if not decl.name:
- raise CDefError("typedef does not declare any name",
- decl)
- quals = 0
- if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and
- decl.type.type.names[-1].startswith('__dotdotdot')):
- realtype = self._get_unknown_type(decl)
- elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and
- isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and
- isinstance(decl.type.type.type,
- pycparser.c_ast.IdentifierType) and
- decl.type.type.type.names[-1].startswith('__dotdotdot')):
- realtype = self._get_unknown_ptr_type(decl)
- else:
- realtype, quals = self._get_type_and_quals(
- decl.type, name=decl.name, partial_length_ok=True,
- typedef_example="*(%s *)0" % (decl.name,))
- self._declare('typedef ' + decl.name, realtype, quals=quals)
- elif decl.__class__.__name__ == 'Pragma':
- pass # skip pragma, only in pycparser 2.15
- else:
- raise CDefError("unexpected <%s>: this construct is valid "
- "C but not valid in cdef()" %
- decl.__class__.__name__, decl)
- except CDefError as e:
- if len(e.args) == 1:
- e.args = e.args + (current_decl,)
- raise
- except FFIError as e:
- msg = self._convert_pycparser_error(e, csource)
- if msg:
- e.args = (e.args[0] + "\n *** Err: %s" % msg,)
- raise
-
- def _add_constants(self, key, val):
- if key in self._int_constants:
- if self._int_constants[key] == val:
- return # ignore identical double declarations
- raise FFIError(
- "multiple declarations of constant: %s" % (key,))
- self._int_constants[key] = val
-
- def _add_integer_constant(self, name, int_str):
- int_str = int_str.lower().rstrip("ul")
- neg = int_str.startswith('-')
- if neg:
- int_str = int_str[1:]
- # "010" is not valid oct in py3
- if (int_str.startswith("0") and int_str != '0'
- and not int_str.startswith("0x")):
- int_str = "0o" + int_str[1:]
- pyvalue = int(int_str, 0)
- if neg:
- pyvalue = -pyvalue
- self._add_constants(name, pyvalue)
- self._declare('macro ' + name, pyvalue)
-
- def _process_macros(self, macros):
- for key, value in macros.items():
- value = value.strip()
- if _r_int_literal.match(value):
- self._add_integer_constant(key, value)
- elif value == '...':
- self._declare('macro ' + key, value)
- else:
- raise CDefError(
- 'only supports one of the following syntax:\n'
- ' #define %s ... (literally dot-dot-dot)\n'
- ' #define %s NUMBER (with NUMBER an integer'
- ' constant, decimal/hex/octal)\n'
- 'got:\n'
- ' #define %s %s'
- % (key, key, key, value))
-
- def _declare_function(self, tp, quals, decl):
- tp = self._get_type_pointer(tp, quals)
- if self._options.get('dllexport'):
- tag = 'dllexport_python '
- elif self._inside_extern_python == '__cffi_extern_python_start':
- tag = 'extern_python '
- elif self._inside_extern_python == '__cffi_extern_python_plus_c_start':
- tag = 'extern_python_plus_c '
- else:
- tag = 'function '
- self._declare(tag + decl.name, tp)
-
- def _parse_decl(self, decl):
- node = decl.type
- if isinstance(node, pycparser.c_ast.FuncDecl):
- tp, quals = self._get_type_and_quals(node, name=decl.name)
- assert isinstance(tp, model.RawFunctionType)
- self._declare_function(tp, quals, decl)
- else:
- if isinstance(node, pycparser.c_ast.Struct):
- self._get_struct_union_enum_type('struct', node)
- elif isinstance(node, pycparser.c_ast.Union):
- self._get_struct_union_enum_type('union', node)
- elif isinstance(node, pycparser.c_ast.Enum):
- self._get_struct_union_enum_type('enum', node)
- elif not decl.name:
- raise CDefError("construct does not declare any variable",
- decl)
- #
- if decl.name:
- tp, quals = self._get_type_and_quals(node,
- partial_length_ok=True)
- if tp.is_raw_function:
- self._declare_function(tp, quals, decl)
- elif (tp.is_integer_type() and
- hasattr(decl, 'init') and
- hasattr(decl.init, 'value') and
- _r_int_literal.match(decl.init.value)):
- self._add_integer_constant(decl.name, decl.init.value)
- elif (tp.is_integer_type() and
- isinstance(decl.init, pycparser.c_ast.UnaryOp) and
- decl.init.op == '-' and
- hasattr(decl.init.expr, 'value') and
- _r_int_literal.match(decl.init.expr.value)):
- self._add_integer_constant(decl.name,
- '-' + decl.init.expr.value)
- elif (tp is model.void_type and
- decl.name.startswith('__cffi_extern_python_')):
- # hack: `extern "Python"` in the C source is replaced
- # with "void __cffi_extern_python_start;" and
- # "void __cffi_extern_python_stop;"
- self._inside_extern_python = decl.name
- else:
- if self._inside_extern_python !='__cffi_extern_python_stop':
- raise CDefError(
- "cannot declare constants or "
- "variables with 'extern \"Python\"'")
- if (quals & model.Q_CONST) and not tp.is_array_type:
- self._declare('constant ' + decl.name, tp, quals=quals)
- else:
- _warn_for_non_extern_non_static_global_variable(decl)
- 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 CDefError("unknown identifier '%s'" % (exprnode.name,))
- return self._get_type_and_quals(exprnode.type)
-
- def _declare(self, name, obj, included=False, quals=0):
- if name in self._declarations:
- prevobj, prevquals = self._declarations[name]
- if prevobj is obj and prevquals == quals:
- return
- if not self._options.get('override'):
- raise FFIError(
- "multiple declarations of %s (for interactive usage, "
- "try cdef(xx, override=True))" % (name,))
- assert '__dotdotdot__' not in name.split()
- self._declarations[name] = (obj, quals)
- if included:
- self._included_declarations.add(obj)
-
- def _extract_quals(self, type):
- quals = 0
- if isinstance(type, (pycparser.c_ast.TypeDecl,
- 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
-
- def _get_type_pointer(self, type, quals, declname=None):
- if isinstance(type, model.RawFunctionType):
- return type.as_function_pointer()
- if (isinstance(type, model.StructOrUnionOrEnum) and
- type.name.startswith('$') and type.name[1:].isdigit() and
- type.forcename is None and declname is not None):
- return model.NamedPointerType(type, declname, quals)
- return model.PointerType(type, quals)
-
- def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False,
- typedef_example=None):
- # first, dereference typedefs, if we have it already parsed, we're good
- if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
- isinstance(typenode.type, pycparser.c_ast.IdentifierType) and
- len(typenode.type.names) == 1 and
- ('typedef ' + typenode.type.names[0]) in self._declarations):
- tp, quals = self._declarations['typedef ' + typenode.type.names[0]]
- quals |= self._extract_quals(typenode)
- return tp, quals
- #
- if isinstance(typenode, pycparser.c_ast.ArrayDecl):
- # array type
- if typenode.dim is None:
- length = None
- else:
- length = self._parse_constant(
- typenode.dim, partial_length_ok=partial_length_ok)
- # a hack: in 'typedef int foo_t[...][...];', don't use '...' as
- # the length but use directly the C expression that would be
- # generated by recompiler.py. This lets the typedef be used in
- # many more places within recompiler.py
- if typedef_example is not None:
- if length == '...':
- length = '_cffi_array_len(%s)' % (typedef_example,)
- typedef_example = "*" + typedef_example
- #
- tp, quals = self._get_type_and_quals(typenode.type,
- partial_length_ok=partial_length_ok,
- typedef_example=typedef_example)
- return model.ArrayType(tp, length), quals
- #
- if isinstance(typenode, pycparser.c_ast.PtrDecl):
- # pointer type
- itemtype, itemquals = self._get_type_and_quals(typenode.type)
- tp = self._get_type_pointer(itemtype, itemquals, declname=name)
- quals = self._extract_quals(typenode)
- return tp, quals
- #
- if isinstance(typenode, pycparser.c_ast.TypeDecl):
- quals = self._extract_quals(typenode)
- type = typenode.type
- if isinstance(type, pycparser.c_ast.IdentifierType):
- # assume a primitive type. get it from .names, but reduce
- # synonyms to a single chosen combination
- names = list(type.names)
- if names != ['signed', 'char']: # keep this unmodified
- prefixes = {}
- while names:
- name = names[0]
- if name in ('short', 'long', 'signed', 'unsigned'):
- prefixes[name] = prefixes.get(name, 0) + 1
- del names[0]
- else:
- break
- # ignore the 'signed' prefix below, and reorder the others
- newnames = []
- for prefix in ('unsigned', 'short', 'long'):
- for i in range(prefixes.get(prefix, 0)):
- newnames.append(prefix)
- if not names:
- names = ['int'] # implicitly
- if names == ['int']: # but kill it if 'short' or 'long'
- if 'short' in prefixes or 'long' in prefixes:
- names = []
- names = newnames + names
- ident = ' '.join(names)
- if ident == 'void':
- return model.void_type, quals
- if ident == '__dotdotdot__':
- raise FFIError(':%d: bad usage of "..."' %
- typenode.coord.line)
- tp0, quals0 = resolve_common_type(self, ident)
- return tp0, (quals | quals0)
- #
- if isinstance(type, pycparser.c_ast.Struct):
- # 'struct foobar'
- tp = self._get_struct_union_enum_type('struct', type, name)
- return tp, quals
- #
- if isinstance(type, pycparser.c_ast.Union):
- # 'union foobar'
- tp = self._get_struct_union_enum_type('union', type, name)
- return tp, quals
- #
- if isinstance(type, pycparser.c_ast.Enum):
- # 'enum foobar'
- tp = self._get_struct_union_enum_type('enum', type, name)
- return tp, quals
- #
- if isinstance(typenode, pycparser.c_ast.FuncDecl):
- # a function type
- return self._parse_function_type(typenode, name), 0
- #
- # nested anonymous structs or unions end up here
- if isinstance(typenode, pycparser.c_ast.Struct):
- return self._get_struct_union_enum_type('struct', typenode, name,
- nested=True), 0
- if isinstance(typenode, pycparser.c_ast.Union):
- return self._get_struct_union_enum_type('union', typenode, name,
- nested=True), 0
- #
- raise FFIError(":%d: bad or unsupported type declaration" %
- typenode.coord.line)
-
- 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 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
- isinstance(params[-1].type.type,
- pycparser.c_ast.IdentifierType) and
- params[-1].type.type.names == ['__dotdotdot__'])
- if ellipsis:
- params.pop()
- if not params:
- raise CDefError(
- "%s: a function with only '(...)' as argument"
- " is not correct C" % (funcname or 'in expression'))
- args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type))
- for argdeclnode in params]
- if not ellipsis and args == [model.void_type]:
- args = []
- result, quals = self._get_type_and_quals(typenode.type)
- # the 'quals' on the result type are ignored. HACK: we absure them
- # to detect __stdcall functions: we textually replace "__stdcall"
- # with "volatile volatile const" above.
- abi = None
- if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway
- if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']:
- abi = '__stdcall'
- return model.RawFunctionType(tuple(args), result, ellipsis, abi)
-
- def _as_func_arg(self, type, quals):
- if isinstance(type, model.ArrayType):
- return model.PointerType(type.item, quals)
- elif isinstance(type, model.RawFunctionType):
- return type.as_function_pointer()
- else:
- return type
-
- def _get_struct_union_enum_type(self, kind, type, name=None, nested=False):
- # First, a level of caching on the exact 'type' node of the AST.
- # This is obscure, but needed because pycparser "unrolls" declarations
- # such as "typedef struct { } foo_t, *foo_p" and we end up with
- # an AST that is not a tree, but a DAG, with the "type" node of the
- # two branches foo_t and foo_p of the trees being the same node.
- # It's a bit silly but detecting "DAG-ness" in the AST tree seems
- # to be the only way to distinguish this case from two independent
- # structs. See test_struct_with_two_usages.
- try:
- return self._structnode2type[type]
- except KeyError:
- pass
- #
- # Note that this must handle parsing "struct foo" any number of
- # times and always return the same StructType object. Additionally,
- # one of these times (not necessarily the first), the fields of
- # the struct can be specified with "struct foo { ...fields... }".
- # If no name is given, then we have to create a new anonymous struct
- # with no caching; in this case, the fields are either specified
- # right now or never.
- #
- force_name = name
- name = type.name
- #
- # get the type or create it if needed
- if name is None:
- # 'force_name' is used to guess a more readable name for
- # anonymous structs, for the common case "typedef struct { } foo".
- if force_name is not None:
- explicit_name = '$%s' % force_name
- else:
- self._anonymous_counter += 1
- explicit_name = '$%d' % self._anonymous_counter
- tp = None
- else:
- explicit_name = name
- key = '%s %s' % (kind, name)
- tp, _ = self._declarations.get(key, (None, None))
- #
- if tp is None:
- if kind == 'struct':
- tp = model.StructType(explicit_name, None, None, None)
- elif kind == 'union':
- tp = model.UnionType(explicit_name, None, None, None)
- elif kind == 'enum':
- if explicit_name == '__dotdotdot__':
- raise CDefError("Enums cannot be declared with ...")
- tp = self._build_enum_type(explicit_name, type.values)
- else:
- raise AssertionError("kind = %r" % (kind,))
- if name is not None:
- self._declare(key, tp)
- else:
- if kind == 'enum' and type.values is not None:
- raise NotImplementedError(
- "enum %s: the '{}' declaration should appear on the first "
- "time the enum is mentioned, not later" % explicit_name)
- if not tp.forcename:
- tp.force_the_name(force_name)
- if tp.forcename and '$' in tp.name:
- self._declare('anonymous %s' % tp.forcename, tp)
- #
- self._structnode2type[type] = tp
- #
- # enums: done here
- if kind == 'enum':
- return tp
- #
- # is there a 'type.decls'? If yes, then this is the place in the
- # C sources that declare the fields. If no, then just return the
- # existing type, possibly still incomplete.
- if type.decls is None:
- return tp
- #
- if tp.fldnames is not None:
- raise CDefError("duplicate declaration of struct %s" % name)
- fldnames = []
- fldtypes = []
- fldbitsize = []
- fldquals = []
- for decl in type.decls:
- if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and
- ''.join(decl.type.names) == '__dotdotdot__'):
- # XXX pycparser is inconsistent: 'names' should be a list
- # of strings, but is sometimes just one string. Use
- # str.join() as a way to cope with both.
- self._make_partial(tp, nested)
- continue
- if decl.bitsize is None:
- bitsize = -1
- else:
- bitsize = self._parse_constant(decl.bitsize)
- self._partial_length = False
- type, fqual = self._get_type_and_quals(decl.type,
- partial_length_ok=True)
- if self._partial_length:
- self._make_partial(tp, nested)
- if isinstance(type, model.StructType) and type.partial:
- self._make_partial(tp, nested)
- fldnames.append(decl.name or '')
- fldtypes.append(type)
- fldbitsize.append(bitsize)
- fldquals.append(fqual)
- tp.fldnames = tuple(fldnames)
- tp.fldtypes = tuple(fldtypes)
- tp.fldbitsize = tuple(fldbitsize)
- tp.fldquals = tuple(fldquals)
- if fldbitsize != [-1] * len(fldbitsize):
- if isinstance(tp, model.StructType) and tp.partial:
- raise NotImplementedError("%s: using both bitfields and '...;'"
- % (tp,))
- tp.packed = self._options.get('packed')
- if tp.completed: # must be re-completed: it is not opaque any more
- tp.completed = 0
- self._recomplete.append(tp)
- return tp
-
- def _make_partial(self, tp, nested):
- if not isinstance(tp, model.StructOrUnion):
- raise CDefError("%s cannot be partial" % (tp,))
- if not tp.has_c_name() and not nested:
- raise NotImplementedError("%s is partial but has no C name" %(tp,))
- tp.partial = True
-
- def _parse_constant(self, exprnode, partial_length_ok=False):
- # for now, limited to expressions that are an immediate number
- # or positive/negative number
- if isinstance(exprnode, pycparser.c_ast.Constant):
- s = exprnode.value
- if '0' <= s[0] <= '9':
- s = s.rstrip('uUlL')
- try:
- if s.startswith('0'):
- return int(s, 8)
- else:
- return int(s, 10)
- except ValueError:
- if len(s) > 1:
- if s.lower()[0:2] == '0x':
- return int(s, 16)
- elif s.lower()[0:2] == '0b':
- return int(s, 2)
- raise CDefError("invalid constant %r" % (s,))
- elif s[0] == "'" and s[-1] == "'" and (
- len(s) == 3 or (len(s) == 4 and s[1] == "\\")):
- return ord(s[-2])
- else:
- raise CDefError("invalid constant %r" % (s,))
- #
- if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
- exprnode.op == '+'):
- return self._parse_constant(exprnode.expr)
- #
- if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
- exprnode.op == '-'):
- return -self._parse_constant(exprnode.expr)
- # load previously defined int constant
- if (isinstance(exprnode, pycparser.c_ast.ID) and
- exprnode.name in self._int_constants):
- return self._int_constants[exprnode.name]
- #
- if (isinstance(exprnode, pycparser.c_ast.ID) and
- exprnode.name == '__dotdotdotarray__'):
- if partial_length_ok:
- self._partial_length = True
- return '...'
- raise FFIError(":%d: unsupported '[...]' here, cannot derive "
- "the actual array length in this context"
- % exprnode.coord.line)
- #
- if isinstance(exprnode, pycparser.c_ast.BinaryOp):
- left = self._parse_constant(exprnode.left)
- right = self._parse_constant(exprnode.right)
- if exprnode.op == '+':
- return left + right
- elif exprnode.op == '-':
- return left - right
- elif exprnode.op == '*':
- return left * right
- elif exprnode.op == '/':
- return self._c_div(left, right)
- elif exprnode.op == '%':
- return left - self._c_div(left, right) * right
- elif exprnode.op == '<<':
- return left << right
- elif exprnode.op == '>>':
- return left >> right
- elif exprnode.op == '&':
- return left & right
- elif exprnode.op == '|':
- return left | right
- elif exprnode.op == '^':
- return left ^ right
- #
- raise FFIError(":%d: unsupported expression: expected a "
- "simple numeric constant" % exprnode.coord.line)
-
- def _c_div(self, a, b):
- result = a // b
- if ((a < 0) ^ (b < 0)) and (a % b) != 0:
- result += 1
- return result
-
- def _build_enum_type(self, explicit_name, decls):
- if decls is not None:
- partial = False
- enumerators = []
- enumvalues = []
- nextenumvalue = 0
- for enum in decls.enumerators:
- if _r_enum_dotdotdot.match(enum.name):
- partial = True
- continue
- if enum.value is not None:
- nextenumvalue = self._parse_constant(enum.value)
- enumerators.append(enum.name)
- enumvalues.append(nextenumvalue)
- self._add_constants(enum.name, nextenumvalue)
- nextenumvalue += 1
- enumerators = tuple(enumerators)
- enumvalues = tuple(enumvalues)
- tp = model.EnumType(explicit_name, enumerators, enumvalues)
- tp.partial = partial
- else: # opaque enum
- tp = model.EnumType(explicit_name, (), ())
- return tp
-
- def include(self, other):
- for name, (tp, quals) in other._declarations.items():
- if name.startswith('anonymous $enum_$'):
- continue # fix for test_anonymous_enum_include
- kind = name.split(' ', 1)[0]
- if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'):
- self._declare(name, tp, included=True, quals=quals)
- for k, v in other._int_constants.items():
- self._add_constants(k, v)
-
- def _get_unknown_type(self, decl):
- typenames = decl.type.type.names
- if typenames == ['__dotdotdot__']:
- return model.unknown_type(decl.name)
-
- if typenames == ['__dotdotdotint__']:
- if self._uses_new_feature is None:
- self._uses_new_feature = "'typedef int... %s'" % decl.name
- return model.UnknownIntegerType(decl.name)
-
- if typenames == ['__dotdotdotfloat__']:
- # note: not for 'long double' so far
- if self._uses_new_feature is None:
- self._uses_new_feature = "'typedef float... %s'" % decl.name
- return model.UnknownFloatType(decl.name)
-
- raise FFIError(':%d: unsupported usage of "..." in typedef'
- % decl.coord.line)
-
- def _get_unknown_ptr_type(self, decl):
- if decl.type.type.type.names == ['__dotdotdot__']:
- return model.unknown_ptr_type(decl.name)
- raise FFIError(':%d: unsupported usage of "..." in typedef'
- % decl.coord.line)
diff --git a/cffi/error.py b/cffi/error.py
deleted file mode 100644
index 0a27247..0000000
--- a/cffi/error.py
+++ /dev/null
@@ -1,31 +0,0 @@
-
-class FFIError(Exception):
- __module__ = 'cffi'
-
-class CDefError(Exception):
- __module__ = 'cffi'
- def __str__(self):
- try:
- current_decl = self.args[1]
- filename = current_decl.coord.file
- linenum = current_decl.coord.line
- prefix = '%s:%d: ' % (filename, linenum)
- except (AttributeError, TypeError, IndexError):
- prefix = ''
- return '%s%s' % (prefix, self.args[0])
-
-class VerificationError(Exception):
- """ An error raised when verification fails
- """
- __module__ = 'cffi'
-
-class VerificationMissing(Exception):
- """ An error raised when incomplete structures are passed into
- cdef, but no verification has been done
- """
- __module__ = 'cffi'
-
-class PkgConfigError(Exception):
- """ An error raised for missing modules in pkg-config
- """
- __module__ = 'cffi'
diff --git a/cffi/ffiplatform.py b/cffi/ffiplatform.py
deleted file mode 100644
index 8531346..0000000
--- a/cffi/ffiplatform.py
+++ /dev/null
@@ -1,127 +0,0 @@
-import sys, os
-from .error import VerificationError
-
-
-LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs',
- 'extra_objects', 'depends']
-
-def get_extension(srcfilename, modname, sources=(), **kwds):
- _hack_at_distutils()
- from distutils.core import Extension
- allsources = [srcfilename]
- for src in sources:
- allsources.append(os.path.normpath(src))
- return Extension(name=modname, sources=allsources, **kwds)
-
-def compile(tmpdir, ext, compiler_verbose=0, debug=None):
- """Compile a C extension module using distutils."""
-
- _hack_at_distutils()
- saved_environ = os.environ.copy()
- try:
- outputfilename = _build(tmpdir, ext, compiler_verbose, debug)
- outputfilename = os.path.abspath(outputfilename)
- finally:
- # workaround for a distutils bugs where some env vars can
- # become longer and longer every time it is used
- for key, value in saved_environ.items():
- if os.environ.get(key) != value:
- os.environ[key] = value
- return outputfilename
-
-def _build(tmpdir, ext, compiler_verbose=0, debug=None):
- # XXX compact but horrible :-(
- from distutils.core import Distribution
- import distutils.errors, distutils.log
- #
- dist = Distribution({'ext_modules': [ext]})
- dist.parse_config_files()
- options = dist.get_option_dict('build_ext')
- if debug is None:
- debug = sys.flags.debug
- options['debug'] = ('ffiplatform', debug)
- options['force'] = ('ffiplatform', True)
- options['build_lib'] = ('ffiplatform', tmpdir)
- options['build_temp'] = ('ffiplatform', tmpdir)
- #
- try:
- old_level = distutils.log.set_threshold(0) or 0
- try:
- distutils.log.set_verbosity(compiler_verbose)
- dist.run_command('build_ext')
- cmd_obj = dist.get_command_obj('build_ext')
- [soname] = cmd_obj.get_outputs()
- finally:
- distutils.log.set_threshold(old_level)
- except (distutils.errors.CompileError,
- distutils.errors.LinkError) as e:
- raise VerificationError('%s: %s' % (e.__class__.__name__, e))
- #
- return soname
-
-try:
- from os.path import samefile
-except ImportError:
- def samefile(f1, f2):
- return os.path.abspath(f1) == os.path.abspath(f2)
-
-def maybe_relative_path(path):
- if not os.path.isabs(path):
- return path # already relative
- dir = path
- names = []
- while True:
- prevdir = dir
- dir, name = os.path.split(prevdir)
- if dir == prevdir or not dir:
- return path # failed to make it relative
- names.append(name)
- try:
- if samefile(dir, os.curdir):
- names.reverse()
- return os.path.join(*names)
- except OSError:
- pass
-
-# ____________________________________________________________
-
-try:
- int_or_long = (int, long)
- import cStringIO
-except NameError:
- int_or_long = int # Python 3
- import io as cStringIO
-
-def _flatten(x, f):
- if isinstance(x, str):
- f.write('%ds%s' % (len(x), x))
- elif isinstance(x, dict):
- keys = sorted(x.keys())
- f.write('%dd' % len(keys))
- for key in keys:
- _flatten(key, f)
- _flatten(x[key], f)
- elif isinstance(x, (list, tuple)):
- f.write('%dl' % len(x))
- for value in x:
- _flatten(value, f)
- elif isinstance(x, int_or_long):
- f.write('%di' % (x,))
- else:
- raise TypeError(
- "the keywords to verify() contains unsupported object %r" % (x,))
-
-def flatten(x):
- f = cStringIO.StringIO()
- _flatten(x, f)
- return f.getvalue()
-
-def _hack_at_distutils():
- # Windows-only workaround for some configurations: see
- # https://bugs.python.org/issue23246 (Python 2.7 with
- # a specific MS compiler suite download)
- if sys.platform == "win32":
- try:
- import setuptools # for side-effects, patches distutils
- except ImportError:
- pass
diff --git a/cffi/lock.py b/cffi/lock.py
deleted file mode 100644
index db91b71..0000000
--- a/cffi/lock.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import sys
-
-if sys.version_info < (3,):
- try:
- from thread import allocate_lock
- except ImportError:
- from dummy_thread import allocate_lock
-else:
- try:
- from _thread import allocate_lock
- except ImportError:
- from _dummy_thread import allocate_lock
-
-
-##import sys
-##l1 = allocate_lock
-
-##class allocate_lock(object):
-## def __init__(self):
-## self._real = l1()
-## def __enter__(self):
-## for i in range(4, 0, -1):
-## print sys._getframe(i).f_code
-## print
-## return self._real.__enter__()
-## def __exit__(self, *args):
-## return self._real.__exit__(*args)
-## def acquire(self, f):
-## assert f is False
-## return self._real.acquire(f)
diff --git a/cffi/model.py b/cffi/model.py
deleted file mode 100644
index ad1c176..0000000
--- a/cffi/model.py
+++ /dev/null
@@ -1,617 +0,0 @@
-import types
-import weakref
-
-from .lock import allocate_lock
-from .error import CDefError, VerificationError, VerificationMissing
-
-# 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
- # _cffi_include.h for it (and in its copies, documented there)
- replace_with = ' __restrict ' + replace_with.lstrip()
- return replace_with
-
-
-class BaseTypeByIdentity(object):
- is_array_type = False
- is_raw_function = False
-
- def get_c_name(self, replace_with='', context='a C file', quals=0):
- result = self.c_name_with_marker
- assert result.count('&') == 1
- # some logic duplication with ffi.getctype()... :-(
- replace_with = replace_with.strip()
- if replace_with:
- if replace_with.startswith('*') and '&[' in result:
- replace_with = '(%s)' % replace_with
- elif not replace_with[0] in '[(':
- replace_with = ' ' + replace_with
- replace_with = qualify(quals, replace_with)
- result = result.replace('&', replace_with)
- if '$' in result:
- raise VerificationError(
- "cannot generate '%s' in %s: unknown type name"
- % (self._get_c_name(), context))
- return result
-
- def _get_c_name(self):
- return self.c_name_with_marker.replace('&', '')
-
- def has_c_name(self):
- return '$' not in self._get_c_name()
-
- def is_integer_type(self):
- return False
-
- def get_cached_btype(self, ffi, finishlist, can_delay=False):
- try:
- BType = ffi._cached_btypes[self]
- except KeyError:
- BType = self.build_backend_type(ffi, finishlist)
- BType2 = ffi._cached_btypes.setdefault(self, BType)
- assert BType2 is BType
- return BType
-
- def __repr__(self):
- return '<%s>' % (self._get_c_name(),)
-
- def _get_items(self):
- return [(name, getattr(self, name)) for name in self._attrs_]
-
-
-class BaseType(BaseTypeByIdentity):
-
- def __eq__(self, other):
- return (self.__class__ == other.__class__ and
- self._get_items() == other._get_items())
-
- def __ne__(self, other):
- return not self == other
-
- def __hash__(self):
- return hash((self.__class__, tuple(self._get_items())))
-
-
-class VoidType(BaseType):
- _attrs_ = ()
-
- def __init__(self):
- self.c_name_with_marker = 'void&'
-
- def build_backend_type(self, ffi, finishlist):
- return global_cache(self, ffi, 'new_void_type')
-
-void_type = VoidType()
-
-
-class BasePrimitiveType(BaseType):
- def is_complex_type(self):
- return False
-
-
-class PrimitiveType(BasePrimitiveType):
- _attrs_ = ('name',)
-
- ALL_PRIMITIVE_TYPES = {
- 'char': 'c',
- 'short': 'i',
- 'int': 'i',
- 'long': 'i',
- 'long long': 'i',
- 'signed char': 'i',
- 'unsigned char': 'i',
- 'unsigned short': 'i',
- 'unsigned int': 'i',
- 'unsigned long': 'i',
- 'unsigned long long': 'i',
- 'float': 'f',
- 'double': 'f',
- 'long double': 'f',
- 'float _Complex': 'j',
- 'double _Complex': 'j',
- '_Bool': 'i',
- # the following types are not primitive in the C sense
- 'wchar_t': 'c',
- 'char16_t': 'c',
- 'char32_t': 'c',
- 'int8_t': 'i',
- 'uint8_t': 'i',
- 'int16_t': 'i',
- 'uint16_t': 'i',
- 'int32_t': 'i',
- 'uint32_t': 'i',
- 'int64_t': 'i',
- 'uint64_t': 'i',
- 'int_least8_t': 'i',
- 'uint_least8_t': 'i',
- 'int_least16_t': 'i',
- 'uint_least16_t': 'i',
- 'int_least32_t': 'i',
- 'uint_least32_t': 'i',
- 'int_least64_t': 'i',
- 'uint_least64_t': 'i',
- 'int_fast8_t': 'i',
- 'uint_fast8_t': 'i',
- 'int_fast16_t': 'i',
- 'uint_fast16_t': 'i',
- 'int_fast32_t': 'i',
- 'uint_fast32_t': 'i',
- 'int_fast64_t': 'i',
- 'uint_fast64_t': 'i',
- 'intptr_t': 'i',
- 'uintptr_t': 'i',
- 'intmax_t': 'i',
- 'uintmax_t': 'i',
- 'ptrdiff_t': 'i',
- 'size_t': 'i',
- 'ssize_t': 'i',
- }
-
- def __init__(self, name):
- assert name in self.ALL_PRIMITIVE_TYPES
- self.name = name
- self.c_name_with_marker = name + '&'
-
- def is_char_type(self):
- return self.ALL_PRIMITIVE_TYPES[self.name] == 'c'
- def is_integer_type(self):
- return self.ALL_PRIMITIVE_TYPES[self.name] == 'i'
- def is_float_type(self):
- return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
- def is_complex_type(self):
- return self.ALL_PRIMITIVE_TYPES[self.name] == 'j'
-
- def build_backend_type(self, ffi, finishlist):
- return global_cache(self, ffi, 'new_primitive_type', self.name)
-
-
-class UnknownIntegerType(BasePrimitiveType):
- _attrs_ = ('name',)
-
- def __init__(self, name):
- self.name = name
- self.c_name_with_marker = name + '&'
-
- def is_integer_type(self):
- return True
-
- def build_backend_type(self, ffi, finishlist):
- raise NotImplementedError("integer type '%s' can only be used after "
- "compilation" % self.name)
-
-class UnknownFloatType(BasePrimitiveType):
- _attrs_ = ('name', )
-
- def __init__(self, name):
- self.name = name
- self.c_name_with_marker = name + '&'
-
- def build_backend_type(self, ffi, finishlist):
- raise NotImplementedError("float type '%s' can only be used after "
- "compilation" % self.name)
-
-
-class BaseFunctionType(BaseType):
- _attrs_ = ('args', 'result', 'ellipsis', 'abi')
-
- def __init__(self, args, result, ellipsis, abi=None):
- self.args = args
- self.result = result
- self.ellipsis = ellipsis
- self.abi = abi
- #
- reprargs = [arg._get_c_name() for arg in self.args]
- if self.ellipsis:
- reprargs.append('...')
- reprargs = reprargs or ['void']
- replace_with = self._base_pattern % (', '.join(reprargs),)
- if abi is not None:
- replace_with = replace_with[:1] + abi + ' ' + replace_with[1:]
- self.c_name_with_marker = (
- self.result.c_name_with_marker.replace('&', replace_with))
-
-
-class RawFunctionType(BaseFunctionType):
- # Corresponds to a C type like 'int(int)', which is the C type of
- # a function, but not a pointer-to-function. The backend has no
- # notion of such a type; it's used temporarily by parsing.
- _base_pattern = '(&)(%s)'
- is_raw_function = True
-
- def build_backend_type(self, ffi, finishlist):
- raise CDefError("cannot render the type %r: it is a function "
- "type, not a pointer-to-function type" % (self,))
-
- def as_function_pointer(self):
- return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi)
-
-
-class FunctionPtrType(BaseFunctionType):
- _base_pattern = '(*&)(%s)'
-
- def build_backend_type(self, ffi, finishlist):
- result = self.result.get_cached_btype(ffi, finishlist)
- args = []
- for tp in self.args:
- args.append(tp.get_cached_btype(ffi, finishlist))
- abi_args = ()
- if self.abi == "__stdcall":
- if not self.ellipsis: # __stdcall ignored for variadic funcs
- try:
- abi_args = (ffi._backend.FFI_STDCALL,)
- except AttributeError:
- pass
- return global_cache(self, ffi, 'new_function_type',
- tuple(args), result, self.ellipsis, *abi_args)
-
- def as_raw_function(self):
- return RawFunctionType(self.args, self.result, self.ellipsis, self.abi)
-
-
-class PointerType(BaseType):
- _attrs_ = ('totype', 'quals')
-
- def __init__(self, totype, quals=0):
- self.totype = totype
- self.quals = quals
- extra = qualify(quals, " *&")
- if totype.is_array_type:
- extra = "(%s)" % (extra.lstrip(),)
- self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)
-
- def build_backend_type(self, ffi, finishlist):
- BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True)
- return global_cache(self, ffi, 'new_pointer_type', BItem)
-
-voidp_type = PointerType(void_type)
-
-def ConstPointerType(totype):
- return PointerType(totype, Q_CONST)
-
-const_voidp_type = ConstPointerType(void_type)
-
-
-class NamedPointerType(PointerType):
- _attrs_ = ('totype', 'name')
-
- def __init__(self, totype, name, quals=0):
- PointerType.__init__(self, totype, quals)
- self.name = name
- self.c_name_with_marker = name + '&'
-
-
-class ArrayType(BaseType):
- _attrs_ = ('item', 'length')
- is_array_type = True
-
- def __init__(self, item, length):
- self.item = item
- self.length = length
- #
- if length is None:
- brackets = '&[]'
- elif length == '...':
- brackets = '&[/*...*/]'
- else:
- brackets = '&[%s]' % length
- self.c_name_with_marker = (
- self.item.c_name_with_marker.replace('&', brackets))
-
- def length_is_unknown(self):
- return isinstance(self.length, str)
-
- def resolve_length(self, newlength):
- return ArrayType(self.item, newlength)
-
- def build_backend_type(self, ffi, finishlist):
- if self.length_is_unknown():
- raise CDefError("cannot render the type %r: unknown length" %
- (self,))
- self.item.get_cached_btype(ffi, finishlist) # force the item BType
- BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist)
- return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length)
-
-char_array_type = ArrayType(PrimitiveType('char'), None)
-
-
-class StructOrUnionOrEnum(BaseTypeByIdentity):
- _attrs_ = ('name',)
- forcename = None
-
- def build_c_name_with_marker(self):
- name = self.forcename or '%s %s' % (self.kind, self.name)
- self.c_name_with_marker = name + '&'
-
- def force_the_name(self, forcename):
- self.forcename = forcename
- self.build_c_name_with_marker()
-
- def get_official_name(self):
- assert self.c_name_with_marker.endswith('&')
- return self.c_name_with_marker[:-1]
-
-
-class StructOrUnion(StructOrUnionOrEnum):
- fixedlayout = None
- completed = 0
- partial = False
- packed = 0
-
- def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None):
- self.name = name
- self.fldnames = fldnames
- self.fldtypes = fldtypes
- self.fldbitsize = fldbitsize
- self.fldquals = fldquals
- self.build_c_name_with_marker()
-
- def anonymous_struct_fields(self):
- if self.fldtypes is not None:
- for name, type in zip(self.fldnames, self.fldtypes):
- if name == '' and isinstance(type, StructOrUnion):
- yield type
-
- def enumfields(self, expand_anonymous_struct_union=True):
- fldquals = self.fldquals
- if fldquals is None:
- fldquals = (0,) * len(self.fldnames)
- for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes,
- self.fldbitsize, fldquals):
- if (name == '' and isinstance(type, StructOrUnion)
- and expand_anonymous_struct_union):
- # nested anonymous struct/union
- for result in type.enumfields():
- yield result
- else:
- yield (name, type, bitsize, quals)
-
- def force_flatten(self):
- # force the struct or union to have a declaration that lists
- # directly all fields returned by enumfields(), flattening
- # nested anonymous structs/unions.
- names = []
- types = []
- bitsizes = []
- fldquals = []
- for name, type, bitsize, quals in self.enumfields():
- names.append(name)
- types.append(type)
- bitsizes.append(bitsize)
- fldquals.append(quals)
- self.fldnames = tuple(names)
- self.fldtypes = tuple(types)
- self.fldbitsize = tuple(bitsizes)
- self.fldquals = tuple(fldquals)
-
- def get_cached_btype(self, ffi, finishlist, can_delay=False):
- BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist,
- can_delay)
- if not can_delay:
- self.finish_backend_type(ffi, finishlist)
- return BType
-
- def finish_backend_type(self, ffi, finishlist):
- if self.completed:
- if self.completed != 2:
- raise NotImplementedError("recursive structure declaration "
- "for '%s'" % (self.name,))
- return
- BType = ffi._cached_btypes[self]
- #
- self.completed = 1
- #
- if self.fldtypes is None:
- pass # not completing it: it's an opaque struct
- #
- elif self.fixedlayout is None:
- fldtypes = [tp.get_cached_btype(ffi, finishlist)
- for tp in self.fldtypes]
- lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
- extra_flags = ()
- if self.packed:
- if self.packed == 1:
- extra_flags = (8,) # SF_PACKED
- else:
- extra_flags = (0, self.packed)
- ffi._backend.complete_struct_or_union(BType, lst, self,
- -1, -1, *extra_flags)
- #
- else:
- fldtypes = []
- fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout
- for i in range(len(self.fldnames)):
- fsize = fieldsize[i]
- ftype = self.fldtypes[i]
- #
- if isinstance(ftype, ArrayType) and ftype.length_is_unknown():
- # fix the length to match the total size
- BItemType = ftype.item.get_cached_btype(ffi, finishlist)
- nlen, nrest = divmod(fsize, ffi.sizeof(BItemType))
- if nrest != 0:
- self._verification_error(
- "field '%s.%s' has a bogus size?" % (
- self.name, self.fldnames[i] or '{}'))
- ftype = ftype.resolve_length(nlen)
- self.fldtypes = (self.fldtypes[:i] + (ftype,) +
- self.fldtypes[i+1:])
- #
- BFieldType = ftype.get_cached_btype(ffi, finishlist)
- if isinstance(ftype, ArrayType) and ftype.length is None:
- assert fsize == 0
- else:
- bitemsize = ffi.sizeof(BFieldType)
- if bitemsize != fsize:
- self._verification_error(
- "field '%s.%s' is declared as %d bytes, but is "
- "really %d bytes" % (self.name,
- self.fldnames[i] or '{}',
- bitemsize, fsize))
- fldtypes.append(BFieldType)
- #
- lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs))
- ffi._backend.complete_struct_or_union(BType, lst, self,
- totalsize, totalalignment)
- self.completed = 2
-
- def _verification_error(self, msg):
- raise VerificationError(msg)
-
- def check_not_partial(self):
- if self.partial and self.fixedlayout is None:
- raise VerificationMissing(self._get_c_name())
-
- def build_backend_type(self, ffi, finishlist):
- self.check_not_partial()
- finishlist.append(self)
- #
- return global_cache(self, ffi, 'new_%s_type' % self.kind,
- self.get_official_name(), key=self)
-
-
-class StructType(StructOrUnion):
- kind = 'struct'
-
-
-class UnionType(StructOrUnion):
- kind = 'union'
-
-
-class EnumType(StructOrUnionOrEnum):
- kind = 'enum'
- partial = False
- partial_resolved = False
-
- def __init__(self, name, enumerators, enumvalues, baseinttype=None):
- self.name = name
- self.enumerators = enumerators
- self.enumvalues = enumvalues
- self.baseinttype = baseinttype
- self.build_c_name_with_marker()
-
- def force_the_name(self, forcename):
- StructOrUnionOrEnum.force_the_name(self, forcename)
- if self.forcename is None:
- name = self.get_official_name()
- self.forcename = '$' + name.replace(' ', '_')
-
- def check_not_partial(self):
- if self.partial and not self.partial_resolved:
- raise VerificationMissing(self._get_c_name())
-
- def build_backend_type(self, ffi, finishlist):
- self.check_not_partial()
- base_btype = self.build_baseinttype(ffi, finishlist)
- return global_cache(self, ffi, 'new_enum_type',
- self.get_official_name(),
- self.enumerators, self.enumvalues,
- base_btype, key=self)
-
- def build_baseinttype(self, ffi, finishlist):
- if self.baseinttype is not None:
- return self.baseinttype.get_cached_btype(ffi, finishlist)
- #
- if self.enumvalues:
- smallest_value = min(self.enumvalues)
- largest_value = max(self.enumvalues)
- else:
- import warnings
- try:
- # XXX! The goal is to ensure that the warnings.warn()
- # will not suppress the warning. We want to get it
- # several times if we reach this point several times.
- __warningregistry__.clear()
- except NameError:
- pass
- warnings.warn("%r has no values explicitly defined; "
- "guessing that it is equivalent to 'unsigned int'"
- % self._get_c_name())
- smallest_value = largest_value = 0
- if smallest_value < 0: # needs a signed type
- sign = 1
- candidate1 = PrimitiveType("int")
- candidate2 = PrimitiveType("long")
- else:
- sign = 0
- candidate1 = PrimitiveType("unsigned int")
- candidate2 = PrimitiveType("unsigned long")
- btype1 = candidate1.get_cached_btype(ffi, finishlist)
- btype2 = candidate2.get_cached_btype(ffi, finishlist)
- size1 = ffi.sizeof(btype1)
- size2 = ffi.sizeof(btype2)
- if (smallest_value >= ((-1) << (8*size1-1)) and
- largest_value < (1 << (8*size1-sign))):
- return btype1
- if (smallest_value >= ((-1) << (8*size2-1)) and
- largest_value < (1 << (8*size2-sign))):
- return btype2
- raise CDefError("%s values don't all fit into either 'long' "
- "or 'unsigned long'" % self._get_c_name())
-
-def unknown_type(name, structname=None):
- if structname is None:
- structname = '$%s' % name
- tp = StructType(structname, None, None, None)
- tp.force_the_name(name)
- tp.origin = "unknown_type"
- return tp
-
-def unknown_ptr_type(name, structname=None):
- if structname is None:
- structname = '$$%s' % name
- tp = StructType(structname, None, None, None)
- return NamedPointerType(tp, name)
-
-
-global_lock = allocate_lock()
-_typecache_cffi_backend = weakref.WeakValueDictionary()
-
-def get_typecache(backend):
- # returns _typecache_cffi_backend if backend is the _cffi_backend
- # module, or type(backend).__typecache if backend is an instance of
- # CTypesBackend (or some FakeBackend class during tests)
- if isinstance(backend, types.ModuleType):
- return _typecache_cffi_backend
- with global_lock:
- if not hasattr(type(backend), '__typecache'):
- type(backend).__typecache = weakref.WeakValueDictionary()
- return type(backend).__typecache
-
-def global_cache(srctype, ffi, funcname, *args, **kwds):
- key = kwds.pop('key', (funcname, args))
- assert not kwds
- try:
- return ffi._typecache[key]
- except KeyError:
- pass
- try:
- res = getattr(ffi._backend, funcname)(*args)
- except NotImplementedError as e:
- raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e))
- # note that setdefault() on WeakValueDictionary is not atomic
- # and contains a rare bug (http://bugs.python.org/issue19542);
- # we have to use a lock and do it ourselves
- cache = ffi._typecache
- with global_lock:
- res1 = cache.get(key)
- if res1 is None:
- cache[key] = res
- return res
- else:
- return res1
-
-def pointer_cache(ffi, BType):
- return global_cache('?', ffi, 'new_pointer_type', BType)
-
-def attach_exception_info(e, name):
- if e.args and type(e.args[0]) is str:
- e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:]
diff --git a/cffi/parse_c_type.h b/cffi/parse_c_type.h
deleted file mode 100644
index 84e4ef8..0000000
--- a/cffi/parse_c_type.h
+++ /dev/null
@@ -1,181 +0,0 @@
-
-/* This part is from file 'cffi/parse_c_type.h'. It is copied at the
- beginning of C sources generated by CFFI's ffi.set_source(). */
-
-typedef void *_cffi_opcode_t;
-
-#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8))
-#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode)
-#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8)
-
-#define _CFFI_OP_PRIMITIVE 1
-#define _CFFI_OP_POINTER 3
-#define _CFFI_OP_ARRAY 5
-#define _CFFI_OP_OPEN_ARRAY 7
-#define _CFFI_OP_STRUCT_UNION 9
-#define _CFFI_OP_ENUM 11
-#define _CFFI_OP_FUNCTION 13
-#define _CFFI_OP_FUNCTION_END 15
-#define _CFFI_OP_NOOP 17
-#define _CFFI_OP_BITFIELD 19
-#define _CFFI_OP_TYPENAME 21
-#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs
-#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs
-#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg)
-#define _CFFI_OP_CONSTANT 29
-#define _CFFI_OP_CONSTANT_INT 31
-#define _CFFI_OP_GLOBAL_VAR 33
-#define _CFFI_OP_DLOPEN_FUNC 35
-#define _CFFI_OP_DLOPEN_CONST 37
-#define _CFFI_OP_GLOBAL_VAR_F 39
-#define _CFFI_OP_EXTERN_PYTHON 41
-
-#define _CFFI_PRIM_VOID 0
-#define _CFFI_PRIM_BOOL 1
-#define _CFFI_PRIM_CHAR 2
-#define _CFFI_PRIM_SCHAR 3
-#define _CFFI_PRIM_UCHAR 4
-#define _CFFI_PRIM_SHORT 5
-#define _CFFI_PRIM_USHORT 6
-#define _CFFI_PRIM_INT 7
-#define _CFFI_PRIM_UINT 8
-#define _CFFI_PRIM_LONG 9
-#define _CFFI_PRIM_ULONG 10
-#define _CFFI_PRIM_LONGLONG 11
-#define _CFFI_PRIM_ULONGLONG 12
-#define _CFFI_PRIM_FLOAT 13
-#define _CFFI_PRIM_DOUBLE 14
-#define _CFFI_PRIM_LONGDOUBLE 15
-
-#define _CFFI_PRIM_WCHAR 16
-#define _CFFI_PRIM_INT8 17
-#define _CFFI_PRIM_UINT8 18
-#define _CFFI_PRIM_INT16 19
-#define _CFFI_PRIM_UINT16 20
-#define _CFFI_PRIM_INT32 21
-#define _CFFI_PRIM_UINT32 22
-#define _CFFI_PRIM_INT64 23
-#define _CFFI_PRIM_UINT64 24
-#define _CFFI_PRIM_INTPTR 25
-#define _CFFI_PRIM_UINTPTR 26
-#define _CFFI_PRIM_PTRDIFF 27
-#define _CFFI_PRIM_SIZE 28
-#define _CFFI_PRIM_SSIZE 29
-#define _CFFI_PRIM_INT_LEAST8 30
-#define _CFFI_PRIM_UINT_LEAST8 31
-#define _CFFI_PRIM_INT_LEAST16 32
-#define _CFFI_PRIM_UINT_LEAST16 33
-#define _CFFI_PRIM_INT_LEAST32 34
-#define _CFFI_PRIM_UINT_LEAST32 35
-#define _CFFI_PRIM_INT_LEAST64 36
-#define _CFFI_PRIM_UINT_LEAST64 37
-#define _CFFI_PRIM_INT_FAST8 38
-#define _CFFI_PRIM_UINT_FAST8 39
-#define _CFFI_PRIM_INT_FAST16 40
-#define _CFFI_PRIM_UINT_FAST16 41
-#define _CFFI_PRIM_INT_FAST32 42
-#define _CFFI_PRIM_UINT_FAST32 43
-#define _CFFI_PRIM_INT_FAST64 44
-#define _CFFI_PRIM_UINT_FAST64 45
-#define _CFFI_PRIM_INTMAX 46
-#define _CFFI_PRIM_UINTMAX 47
-#define _CFFI_PRIM_FLOATCOMPLEX 48
-#define _CFFI_PRIM_DOUBLECOMPLEX 49
-#define _CFFI_PRIM_CHAR16 50
-#define _CFFI_PRIM_CHAR32 51
-
-#define _CFFI__NUM_PRIM 52
-#define _CFFI__UNKNOWN_PRIM (-1)
-#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;
- void *address;
- _cffi_opcode_t type_op;
- void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown
- // OP_CPYTHON_BLTN_*: addr of direct function
-};
-
-struct _cffi_getconst_s {
- unsigned long long value;
- const struct _cffi_type_context_s *ctx;
- int gindex;
-};
-
-struct _cffi_struct_union_s {
- const char *name;
- int type_index; // -> _cffi_types, on a OP_STRUCT_UNION
- int flags; // _CFFI_F_* flags below
- size_t size;
- int alignment;
- int first_field_index; // -> _cffi_fields array
- int num_fields;
-};
-#define _CFFI_F_UNION 0x01 // is a union, not a struct
-#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the
- // "standard layout" or if some are missing
-#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct
-#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include()
-#define _CFFI_F_OPAQUE 0x10 // opaque
-
-struct _cffi_field_s {
- const char *name;
- size_t field_offset;
- size_t field_size;
- _cffi_opcode_t field_type_op;
-};
-
-struct _cffi_enum_s {
- const char *name;
- int type_index; // -> _cffi_types, on a OP_ENUM
- int type_prim; // _CFFI_PRIM_xxx
- const char *enumerators; // comma-delimited string
-};
-
-struct _cffi_typename_s {
- const char *name;
- int type_index; /* if opaque, points to a possibly artificial
- OP_STRUCT which is itself opaque */
-};
-
-struct _cffi_type_context_s {
- _cffi_opcode_t *types;
- const struct _cffi_global_s *globals;
- const struct _cffi_field_s *fields;
- const struct _cffi_struct_union_s *struct_unions;
- const struct _cffi_enum_s *enums;
- const struct _cffi_typename_s *typenames;
- int num_globals;
- int num_struct_unions;
- int num_enums;
- int num_typenames;
- const char *const *includes;
- int num_types;
- int flags; /* future extension */
-};
-
-struct _cffi_parse_info_s {
- const struct _cffi_type_context_s *ctx;
- _cffi_opcode_t *output;
- unsigned int output_size;
- size_t error_location;
- const char *error_message;
-};
-
-struct _cffi_externpy_s {
- const char *name;
- size_t size_of_result;
- void *reserved1, *reserved2;
-};
-
-#ifdef _CFFI_INTERNAL
-static int parse_c_type(struct _cffi_parse_info_s *info, const char *input);
-static int search_in_globals(const struct _cffi_type_context_s *ctx,
- const char *search, size_t search_len);
-static int search_in_struct_unions(const struct _cffi_type_context_s *ctx,
- const char *search, size_t search_len);
-#endif
diff --git a/cffi/pkgconfig.py b/cffi/pkgconfig.py
deleted file mode 100644
index 5c93f15..0000000
--- a/cffi/pkgconfig.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi
-import sys, os, subprocess
-
-from .error import PkgConfigError
-
-
-def merge_flags(cfg1, cfg2):
- """Merge values from cffi config flags cfg2 to cf1
-
- Example:
- merge_flags({"libraries": ["one"]}, {"libraries": ["two"]})
- {"libraries": ["one", "two"]}
- """
- for key, value in cfg2.items():
- if key not in cfg1:
- cfg1[key] = value
- else:
- if not isinstance(cfg1[key], list):
- raise TypeError("cfg1[%r] should be a list of strings" % (key,))
- if not isinstance(value, list):
- raise TypeError("cfg2[%r] should be a list of strings" % (key,))
- cfg1[key].extend(value)
- return cfg1
-
-
-def call(libname, flag, encoding=sys.getfilesystemencoding()):
- """Calls pkg-config and returns the output if found
- """
- a = ["pkg-config", "--print-errors"]
- a.append(flag)
- a.append(libname)
- try:
- pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- except EnvironmentError as e:
- raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),))
-
- bout, berr = pc.communicate()
- if pc.returncode != 0:
- try:
- berr = berr.decode(encoding)
- except Exception:
- pass
- raise PkgConfigError(berr.strip())
-
- if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x
- try:
- bout = bout.decode(encoding)
- except UnicodeDecodeError:
- raise PkgConfigError("pkg-config %s %s returned bytes that cannot "
- "be decoded with encoding %r:\n%r" %
- (flag, libname, encoding, bout))
-
- if os.altsep != '\\' and '\\' in bout:
- raise PkgConfigError("pkg-config %s %s returned an unsupported "
- "backslash-escaped output:\n%r" %
- (flag, libname, bout))
- return bout
-
-
-def flags_from_pkgconfig(libs):
- r"""Return compiler line flags for FFI.set_source based on pkg-config output
-
- Usage
- ...
- ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"])
-
- If pkg-config is installed on build machine, then arguments include_dirs,
- library_dirs, libraries, define_macros, extra_compile_args and
- extra_link_args are extended with an output of pkg-config for libfoo and
- libbar.
-
- Raises PkgConfigError in case the pkg-config call fails.
- """
-
- def get_include_dirs(string):
- return [x[2:] for x in string.split() if x.startswith("-I")]
-
- def get_library_dirs(string):
- return [x[2:] for x in string.split() if x.startswith("-L")]
-
- def get_libraries(string):
- return [x[2:] for x in string.split() if x.startswith("-l")]
-
- # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils
- def get_macros(string):
- def _macro(x):
- x = x[2:] # drop "-D"
- if '=' in x:
- return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar")
- else:
- return (x, None) # "-Dfoo" => ("foo", None)
- return [_macro(x) for x in string.split() if x.startswith("-D")]
-
- def get_other_cflags(string):
- return [x for x in string.split() if not x.startswith("-I") and
- not x.startswith("-D")]
-
- def get_other_libs(string):
- return [x for x in string.split() if not x.startswith("-L") and
- not x.startswith("-l")]
-
- # return kwargs for given libname
- def kwargs(libname):
- fse = sys.getfilesystemencoding()
- all_cflags = call(libname, "--cflags")
- all_libs = call(libname, "--libs")
- return {
- "include_dirs": get_include_dirs(all_cflags),
- "library_dirs": get_library_dirs(all_libs),
- "libraries": get_libraries(all_libs),
- "define_macros": get_macros(all_cflags),
- "extra_compile_args": get_other_cflags(all_cflags),
- "extra_link_args": get_other_libs(all_libs),
- }
-
- # merge all arguments together
- ret = {}
- for libname in libs:
- lib_flags = kwargs(libname)
- merge_flags(ret, lib_flags)
- return ret
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
deleted file mode 100644
index 86b37d7..0000000
--- a/cffi/recompiler.py
+++ /dev/null
@@ -1,1581 +0,0 @@
-import os, sys, io
-from . import ffiplatform, model
-from .error import VerificationError
-from .cffi_opcode import *
-
-VERSION_BASE = 0x2601
-VERSION_EMBEDDED = 0x2701
-VERSION_CHAR16CHAR32 = 0x2801
-
-USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or
- sys.version_info >= (3, 5))
-
-
-class GlobalExpr:
- def __init__(self, name, address, type_op, size=0, check_value=0):
- self.name = name
- self.address = address
- self.type_op = type_op
- self.size = size
- self.check_value = check_value
-
- def as_c_expr(self):
- return ' { "%s", (void *)%s, %s, (void *)%s },' % (
- self.name, self.address, self.type_op.as_c_expr(), self.size)
-
- def as_python_expr(self):
- return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name,
- self.check_value)
-
-class FieldExpr:
- def __init__(self, name, field_offset, field_size, fbitsize, field_type_op):
- self.name = name
- self.field_offset = field_offset
- self.field_size = field_size
- self.fbitsize = fbitsize
- self.field_type_op = field_type_op
-
- def as_c_expr(self):
- spaces = " " * len(self.name)
- return (' { "%s", %s,\n' % (self.name, self.field_offset) +
- ' %s %s,\n' % (spaces, self.field_size) +
- ' %s %s },' % (spaces, self.field_type_op.as_c_expr()))
-
- def as_python_expr(self):
- raise NotImplementedError
-
- def as_field_python_expr(self):
- if self.field_type_op.op == OP_NOOP:
- size_expr = ''
- elif self.field_type_op.op == OP_BITFIELD:
- size_expr = format_four_bytes(self.fbitsize)
- else:
- raise NotImplementedError
- return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(),
- size_expr,
- self.name)
-
-class StructUnionExpr:
- def __init__(self, name, type_index, flags, size, alignment, comment,
- first_field_index, c_fields):
- self.name = name
- self.type_index = type_index
- self.flags = flags
- self.size = size
- self.alignment = alignment
- self.comment = comment
- self.first_field_index = first_field_index
- self.c_fields = c_fields
-
- def as_c_expr(self):
- return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags)
- + '\n %s, %s, ' % (self.size, self.alignment)
- + '%d, %d ' % (self.first_field_index, len(self.c_fields))
- + ('/* %s */ ' % self.comment if self.comment else '')
- + '},')
-
- def as_python_expr(self):
- flags = eval(self.flags, G_FLAGS)
- fields_expr = [c_field.as_field_python_expr()
- for c_field in self.c_fields]
- return "(b'%s%s%s',%s)" % (
- format_four_bytes(self.type_index),
- format_four_bytes(flags),
- self.name,
- ','.join(fields_expr))
-
-class EnumExpr:
- def __init__(self, name, type_index, size, signed, allenums):
- self.name = name
- self.type_index = type_index
- self.size = size
- self.signed = signed
- self.allenums = allenums
-
- def as_c_expr(self):
- return (' { "%s", %d, _cffi_prim_int(%s, %s),\n'
- ' "%s" },' % (self.name, self.type_index,
- self.size, self.signed, self.allenums))
-
- def as_python_expr(self):
- prim_index = {
- (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8,
- (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16,
- (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32,
- (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64,
- }[self.size, self.signed]
- return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index),
- format_four_bytes(prim_index),
- self.name, self.allenums)
-
-class TypenameExpr:
- def __init__(self, name, type_index):
- self.name = name
- self.type_index = type_index
-
- def as_c_expr(self):
- return ' { "%s", %d },' % (self.name, self.type_index)
-
- def as_python_expr(self):
- return "b'%s%s'" % (format_four_bytes(self.type_index), self.name)
-
-
-# ____________________________________________________________
-
-
-class Recompiler:
- _num_externpy = 0
-
- def __init__(self, ffi, module_name, target_is_python=False):
- self.ffi = ffi
- self.module_name = module_name
- self.target_is_python = target_is_python
- self._version = VERSION_BASE
-
- def needs_version(self, ver):
- self._version = max(self._version, ver)
-
- def collect_type_table(self):
- self._typesdict = {}
- self._generate("collecttype")
- #
- all_decls = sorted(self._typesdict, key=str)
- #
- # prepare all FUNCTION bytecode sequences first
- self.cffi_types = []
- for tp in all_decls:
- if tp.is_raw_function:
- assert self._typesdict[tp] is None
- self._typesdict[tp] = len(self.cffi_types)
- self.cffi_types.append(tp) # placeholder
- for tp1 in tp.args:
- assert isinstance(tp1, (model.VoidType,
- model.BasePrimitiveType,
- model.PointerType,
- model.StructOrUnionOrEnum,
- model.FunctionPtrType))
- if self._typesdict[tp1] is None:
- self._typesdict[tp1] = len(self.cffi_types)
- self.cffi_types.append(tp1) # placeholder
- self.cffi_types.append('END') # placeholder
- #
- # prepare all OTHER bytecode sequences
- for tp in all_decls:
- if not tp.is_raw_function and self._typesdict[tp] is None:
- self._typesdict[tp] = len(self.cffi_types)
- self.cffi_types.append(tp) # placeholder
- if tp.is_array_type and tp.length is not None:
- self.cffi_types.append('LEN') # placeholder
- assert None not in self._typesdict.values()
- #
- # collect all structs and unions and enums
- self._struct_unions = {}
- self._enums = {}
- for tp in all_decls:
- if isinstance(tp, model.StructOrUnion):
- self._struct_unions[tp] = None
- elif isinstance(tp, model.EnumType):
- self._enums[tp] = None
- for i, tp in enumerate(sorted(self._struct_unions,
- key=lambda tp: tp.name)):
- self._struct_unions[tp] = i
- for i, tp in enumerate(sorted(self._enums,
- key=lambda tp: tp.name)):
- self._enums[tp] = i
- #
- # emit all bytecode sequences now
- for tp in all_decls:
- method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__)
- method(tp, self._typesdict[tp])
- #
- # consistency check
- for op in self.cffi_types:
- assert isinstance(op, CffiOp)
- self.cffi_types = tuple(self.cffi_types) # don't change any more
-
- def _enum_fields(self, tp):
- # When producing C, expand all anonymous struct/union fields.
- # That's necessary to have C code checking the offsets of the
- # individual fields contained in them. When producing Python,
- # don't do it and instead write it like it is, with the
- # corresponding fields having an empty name. Empty names are
- # recognized at runtime when we import the generated Python
- # file.
- expand_anonymous_struct_union = not self.target_is_python
- return tp.enumfields(expand_anonymous_struct_union)
-
- def _do_collect_type(self, tp):
- if not isinstance(tp, model.BaseTypeByIdentity):
- if isinstance(tp, tuple):
- for x in tp:
- self._do_collect_type(x)
- return
- if tp not in self._typesdict:
- self._typesdict[tp] = None
- if isinstance(tp, model.FunctionPtrType):
- self._do_collect_type(tp.as_raw_function())
- elif isinstance(tp, model.StructOrUnion):
- if tp.fldtypes is not None and (
- tp not in self.ffi._parser._included_declarations):
- for name1, tp1, _, _ in self._enum_fields(tp):
- self._do_collect_type(self._field_type(tp, name1, tp1))
- else:
- for _, x in tp._get_items():
- self._do_collect_type(x)
-
- def _generate(self, step_name):
- lst = self.ffi._parser._declarations.items()
- for name, (tp, quals) in sorted(lst):
- kind, realname = name.split(' ', 1)
- try:
- method = getattr(self, '_generate_cpy_%s_%s' % (kind,
- step_name))
- except AttributeError:
- raise VerificationError(
- "not implemented in recompile(): %r" % name)
- try:
- self._current_quals = quals
- method(tp, realname)
- except Exception as e:
- model.attach_exception_info(e, name)
- raise
-
- # ----------
-
- ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"]
-
- def collect_step_tables(self):
- # collect the declarations for '_cffi_globals', '_cffi_typenames', etc.
- self._lsts = {}
- for step_name in self.ALL_STEPS:
- self._lsts[step_name] = []
- self._seen_struct_unions = set()
- self._generate("ctx")
- self._add_missing_struct_unions()
- #
- for step_name in self.ALL_STEPS:
- lst = self._lsts[step_name]
- if step_name != "field":
- lst.sort(key=lambda entry: entry.name)
- self._lsts[step_name] = tuple(lst) # don't change any more
- #
- # check for a possible internal inconsistency: _cffi_struct_unions
- # should have been generated with exactly self._struct_unions
- lst = self._lsts["struct_union"]
- for tp, i in self._struct_unions.items():
- assert i < len(lst)
- assert lst[i].name == tp.name
- assert len(lst) == len(self._struct_unions)
- # same with enums
- lst = self._lsts["enum"]
- for tp, i in self._enums.items():
- assert i < len(lst)
- assert lst[i].name == tp.name
- assert len(lst) == len(self._enums)
-
- # ----------
-
- def _prnt(self, what=''):
- self._f.write(what + '\n')
-
- def write_source_to_f(self, f, preamble):
- if self.target_is_python:
- assert preamble is None
- self.write_py_source_to_f(f)
- else:
- assert preamble is not None
- self.write_c_source_to_f(f, preamble)
-
- def _rel_readlines(self, filename):
- g = open(os.path.join(os.path.dirname(__file__), filename), 'r')
- lines = g.readlines()
- g.close()
- return lines
-
- def write_c_source_to_f(self, f, preamble):
- self._f = f
- prnt = self._prnt
- if self.ffi._embedding is not None:
- prnt('#define _CFFI_USE_EMBEDDING')
- if not USE_LIMITED_API:
- prnt('#define _CFFI_NO_LIMITED_API')
- #
- # first the '#include' (actually done by inlining the file's content)
- lines = self._rel_readlines('_cffi_include.h')
- i = lines.index('#include "parse_c_type.h"\n')
- lines[i:i+1] = self._rel_readlines('parse_c_type.h')
- prnt(''.join(lines))
- #
- # if we have ffi._embedding != None, we give it here as a macro
- # and include an extra file
- base_module_name = self.module_name.split('.')[-1]
- if self.ffi._embedding is not None:
- prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,))
- prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {')
- self._print_string_literal_in_array(self.ffi._embedding)
- prnt('0 };')
- prnt('#ifdef PYPY_VERSION')
- prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % (
- base_module_name,))
- prnt('#elif PY_MAJOR_VERSION >= 3')
- prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % (
- base_module_name,))
- prnt('#else')
- prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % (
- base_module_name,))
- prnt('#endif')
- lines = self._rel_readlines('_embedding.h')
- i = lines.index('#include "_cffi_errors.h"\n')
- lines[i:i+1] = self._rel_readlines('_cffi_errors.h')
- prnt(''.join(lines))
- self.needs_version(VERSION_EMBEDDED)
- #
- # then paste the C source given by the user, verbatim.
- prnt('/************************************************************/')
- prnt()
- prnt(preamble)
- prnt()
- prnt('/************************************************************/')
- prnt()
- #
- # the declaration of '_cffi_types'
- prnt('static void *_cffi_types[] = {')
- typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
- for i, op in enumerate(self.cffi_types):
- comment = ''
- if i in typeindex2type:
- comment = ' // ' + typeindex2type[i]._get_c_name()
- prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment))
- if not self.cffi_types:
- prnt(' 0')
- prnt('};')
- prnt()
- #
- # call generate_cpy_xxx_decl(), for every xxx found from
- # ffi._parser._declarations. This generates all the functions.
- self._seen_constants = set()
- self._generate("decl")
- #
- # the declaration of '_cffi_globals' and '_cffi_typenames'
- nums = {}
- for step_name in self.ALL_STEPS:
- lst = self._lsts[step_name]
- nums[step_name] = len(lst)
- if nums[step_name] > 0:
- prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % (
- step_name, step_name))
- for entry in lst:
- prnt(entry.as_c_expr())
- prnt('};')
- prnt()
- #
- # the declaration of '_cffi_includes'
- if self.ffi._included_ffis:
- prnt('static const char * const _cffi_includes[] = {')
- for ffi_to_include in self.ffi._included_ffis:
- try:
- included_module_name, included_source = (
- ffi_to_include._assigned_source[:2])
- except AttributeError:
- raise VerificationError(
- "ffi object %r includes %r, but the latter has not "
- "been prepared with set_source()" % (
- self.ffi, ffi_to_include,))
- if included_source is None:
- raise VerificationError(
- "not implemented yet: ffi.include() of a Python-based "
- "ffi inside a C-based ffi")
- prnt(' "%s",' % (included_module_name,))
- prnt(' NULL')
- prnt('};')
- prnt()
- #
- # the declaration of '_cffi_type_context'
- prnt('static const struct _cffi_type_context_s _cffi_type_context = {')
- prnt(' _cffi_types,')
- for step_name in self.ALL_STEPS:
- if nums[step_name] > 0:
- prnt(' _cffi_%ss,' % step_name)
- else:
- prnt(' NULL, /* no %ss */' % step_name)
- for step_name in self.ALL_STEPS:
- if step_name != "field":
- prnt(' %d, /* num_%ss */' % (nums[step_name], step_name))
- if self.ffi._included_ffis:
- prnt(' _cffi_includes,')
- else:
- prnt(' NULL, /* no includes */')
- prnt(' %d, /* num_types */' % (len(self.cffi_types),))
- flags = 0
- if self._num_externpy:
- flags |= 1 # set to mean that we use extern "Python"
- prnt(' %d, /* flags */' % flags)
- prnt('};')
- prnt()
- #
- # the init function
- prnt('#ifdef __GNUC__')
- prnt('# pragma GCC visibility push(default) /* for -fvisibility= */')
- prnt('#endif')
- prnt()
- prnt('#ifdef PYPY_VERSION')
- prnt('PyMODINIT_FUNC')
- prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,))
- prnt('{')
- if self._num_externpy:
- prnt(' if (((intptr_t)p[0]) >= 0x0A03) {')
- prnt(' _cffi_call_python_org = '
- '(void(*)(struct _cffi_externpy_s *, char *))p[1];')
- prnt(' }')
- prnt(' p[0] = (const void *)0x%x;' % self._version)
- prnt(' p[1] = &_cffi_type_context;')
- prnt('#if PY_MAJOR_VERSION >= 3')
- prnt(' return NULL;')
- prnt('#endif')
- prnt('}')
- # on Windows, distutils insists on putting init_cffi_xyz in
- # 'export_symbols', so instead of fighting it, just give up and
- # give it one
- prnt('# ifdef _MSC_VER')
- prnt(' PyMODINIT_FUNC')
- prnt('# if PY_MAJOR_VERSION >= 3')
- prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,))
- prnt('# else')
- prnt(' init%s(void) { }' % (base_module_name,))
- prnt('# endif')
- prnt('# endif')
- prnt('#elif PY_MAJOR_VERSION >= 3')
- prnt('PyMODINIT_FUNC')
- prnt('PyInit_%s(void)' % (base_module_name,))
- prnt('{')
- prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
- self.module_name, self._version))
- prnt('}')
- prnt('#else')
- prnt('PyMODINIT_FUNC')
- prnt('init%s(void)' % (base_module_name,))
- prnt('{')
- prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
- self.module_name, self._version))
- prnt('}')
- prnt('#endif')
- prnt()
- prnt('#ifdef __GNUC__')
- prnt('# pragma GCC visibility pop')
- prnt('#endif')
- self._version = None
-
- def _to_py(self, x):
- if isinstance(x, str):
- return "b'%s'" % (x,)
- if isinstance(x, (list, tuple)):
- rep = [self._to_py(item) for item in x]
- if len(rep) == 1:
- rep.append('')
- return "(%s)" % (','.join(rep),)
- return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp.
-
- def write_py_source_to_f(self, f):
- self._f = f
- prnt = self._prnt
- #
- # header
- prnt("# auto-generated file")
- prnt("import _cffi_backend")
- #
- # the 'import' of the included ffis
- num_includes = len(self.ffi._included_ffis or ())
- for i in range(num_includes):
- ffi_to_include = self.ffi._included_ffis[i]
- try:
- included_module_name, included_source = (
- ffi_to_include._assigned_source[:2])
- except AttributeError:
- raise VerificationError(
- "ffi object %r includes %r, but the latter has not "
- "been prepared with set_source()" % (
- self.ffi, ffi_to_include,))
- if included_source is not None:
- raise VerificationError(
- "not implemented yet: ffi.include() of a C-based "
- "ffi inside a Python-based ffi")
- prnt('from %s import ffi as _ffi%d' % (included_module_name, i))
- prnt()
- prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,))
- prnt(" _version = 0x%x," % (self._version,))
- self._version = None
- #
- # the '_types' keyword argument
- self.cffi_types = tuple(self.cffi_types) # don't change any more
- types_lst = [op.as_python_bytes() for op in self.cffi_types]
- prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),))
- typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
- #
- # the keyword arguments from ALL_STEPS
- for step_name in self.ALL_STEPS:
- lst = self._lsts[step_name]
- if len(lst) > 0 and step_name != "field":
- prnt(' _%ss = %s,' % (step_name, self._to_py(lst)))
- #
- # the '_includes' keyword argument
- if num_includes > 0:
- prnt(' _includes = (%s,),' % (
- ', '.join(['_ffi%d' % i for i in range(num_includes)]),))
- #
- # the footer
- prnt(')')
-
- # ----------
-
- def _gettypenum(self, type):
- # a KeyError here is a bug. please report it! :-)
- return self._typesdict[type]
-
- def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
- extraarg = ''
- if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type():
- if tp.is_integer_type() and tp.name != '_Bool':
- converter = '_cffi_to_c_int'
- extraarg = ', %s' % tp.name
- elif isinstance(tp, model.UnknownFloatType):
- # don't check with is_float_type(): it may be a 'long
- # double' here, and _cffi_to_c_double would loose precision
- converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),)
- else:
- cname = tp.get_c_name('')
- converter = '(%s)_cffi_to_c_%s' % (cname,
- tp.name.replace(' ', '_'))
- if cname in ('char16_t', 'char32_t'):
- self.needs_version(VERSION_CHAR16CHAR32)
- errvalue = '-1'
- #
- elif isinstance(tp, model.PointerType):
- self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
- tovar, errcode)
- return
- #
- elif (isinstance(tp, model.StructOrUnionOrEnum) or
- isinstance(tp, model.BasePrimitiveType)):
- # a struct (not a struct pointer) as a function argument;
- # or, a complex (the same code works)
- self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
- % (tovar, self._gettypenum(tp), fromvar))
- self._prnt(' %s;' % errcode)
- return
- #
- elif isinstance(tp, model.FunctionPtrType):
- converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
- extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
- errvalue = 'NULL'
- #
- else:
- raise NotImplementedError(tp)
- #
- self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
- self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % (
- tovar, tp.get_c_name(''), errvalue))
- self._prnt(' %s;' % errcode)
-
- def _extra_local_variables(self, tp, localvars, freelines):
- if isinstance(tp, model.PointerType):
- localvars.add('Py_ssize_t datasize')
- localvars.add('struct _cffi_freeme_s *large_args_free = NULL')
- freelines.add('if (large_args_free != NULL)'
- ' _cffi_free_array_arguments(large_args_free);')
-
- def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
- self._prnt(' datasize = _cffi_prepare_pointer_call_argument(')
- self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % (
- self._gettypenum(tp), fromvar, tovar))
- self._prnt(' if (datasize != 0) {')
- self._prnt(' %s = ((size_t)datasize) <= 640 ? '
- '(%s)alloca((size_t)datasize) : NULL;' % (
- tovar, tp.get_c_name('')))
- self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, '
- '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar))
- self._prnt(' datasize, &large_args_free) < 0)')
- self._prnt(' %s;' % errcode)
- self._prnt(' }')
-
- def _convert_expr_from_c(self, tp, var, context):
- if isinstance(tp, model.BasePrimitiveType):
- if tp.is_integer_type() and tp.name != '_Bool':
- return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
- elif isinstance(tp, model.UnknownFloatType):
- return '_cffi_from_c_double(%s)' % (var,)
- elif tp.name != 'long double' and not tp.is_complex_type():
- cname = tp.name.replace(' ', '_')
- if cname in ('char16_t', 'char32_t'):
- self.needs_version(VERSION_CHAR16CHAR32)
- return '_cffi_from_c_%s(%s)' % (cname, var)
- else:
- return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
- var, self._gettypenum(tp))
- elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
- return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
- var, self._gettypenum(tp))
- elif isinstance(tp, model.ArrayType):
- return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
- var, self._gettypenum(model.PointerType(tp.item)))
- elif isinstance(tp, model.StructOrUnion):
- if tp.fldnames is None:
- raise TypeError("'%s' is used as %s, but is opaque" % (
- tp._get_c_name(), context))
- return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
- var, self._gettypenum(tp))
- elif isinstance(tp, model.EnumType):
- return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
- var, self._gettypenum(tp))
- else:
- raise NotImplementedError(tp)
-
- # ----------
- # typedefs
-
- def _typedef_type(self, tp, name):
- return self._global_type(tp, "(*(%s *)0)" % (name,))
-
- def _generate_cpy_typedef_collecttype(self, tp, name):
- self._do_collect_type(self._typedef_type(tp, name))
-
- def _generate_cpy_typedef_decl(self, tp, name):
- pass
-
- def _typedef_ctx(self, tp, name):
- type_index = self._typesdict[tp]
- self._lsts["typename"].append(TypenameExpr(name, type_index))
-
- def _generate_cpy_typedef_ctx(self, tp, name):
- tp = self._typedef_type(tp, name)
- self._typedef_ctx(tp, name)
- if getattr(tp, "origin", None) == "unknown_type":
- self._struct_ctx(tp, tp.name, approxname=None)
- elif isinstance(tp, model.NamedPointerType):
- self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name,
- named_ptr=tp)
-
- # ----------
- # function declarations
-
- def _generate_cpy_function_collecttype(self, tp, name):
- self._do_collect_type(tp.as_raw_function())
- if tp.ellipsis and not self.target_is_python:
- self._do_collect_type(tp)
-
- def _generate_cpy_function_decl(self, tp, name):
- assert not self.target_is_python
- assert isinstance(tp, model.FunctionPtrType)
- if tp.ellipsis:
- # cannot support vararg functions better than this: check for its
- # exact type (including the fixed arguments), and build it as a
- # constant function pointer (no CPython wrapper)
- self._generate_cpy_constant_decl(tp, name)
- return
- prnt = self._prnt
- numargs = len(tp.args)
- if numargs == 0:
- argname = 'noarg'
- elif numargs == 1:
- argname = 'arg0'
- else:
- argname = 'args'
- #
- # ------------------------------
- # the 'd' version of the function, only for addressof(lib, 'func')
- arguments = []
- call_arguments = []
- context = 'argument of %s' % name
- for i, type in enumerate(tp.args):
- arguments.append(type.get_c_name(' x%d' % i, context))
- call_arguments.append('x%d' % i)
- repr_arguments = ', '.join(arguments)
- repr_arguments = repr_arguments or 'void'
- if tp.abi:
- abi = tp.abi + ' '
- else:
- abi = ''
- name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments)
- prnt('static %s' % (tp.result.get_c_name(name_and_arguments),))
- prnt('{')
- call_arguments = ', '.join(call_arguments)
- result_code = 'return '
- if isinstance(tp.result, model.VoidType):
- result_code = ''
- prnt(' %s%s(%s);' % (result_code, name, call_arguments))
- prnt('}')
- #
- prnt('#ifndef PYPY_VERSION') # ------------------------------
- #
- prnt('static PyObject *')
- prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
- prnt('{')
- #
- context = 'argument of %s' % name
- for i, type in enumerate(tp.args):
- arg = type.get_c_name(' x%d' % i, context)
- prnt(' %s;' % arg)
- #
- localvars = set()
- freelines = set()
- for type in tp.args:
- self._extra_local_variables(type, localvars, freelines)
- for decl in sorted(localvars):
- prnt(' %s;' % (decl,))
- #
- if not isinstance(tp.result, model.VoidType):
- result_code = 'result = '
- context = 'result of %s' % name
- result_decl = ' %s;' % tp.result.get_c_name(' result', context)
- prnt(result_decl)
- prnt(' PyObject *pyresult;')
- else:
- result_decl = None
- result_code = ''
- #
- if len(tp.args) > 1:
- rng = range(len(tp.args))
- for i in rng:
- prnt(' PyObject *arg%d;' % i)
- prnt()
- prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % (
- name, len(rng), len(rng),
- ', '.join(['&arg%d' % i for i in rng])))
- prnt(' return NULL;')
- prnt()
- #
- for i, type in enumerate(tp.args):
- self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
- 'return NULL')
- prnt()
- #
- prnt(' Py_BEGIN_ALLOW_THREADS')
- prnt(' _cffi_restore_errno();')
- call_arguments = ['x%d' % i for i in range(len(tp.args))]
- call_arguments = ', '.join(call_arguments)
- prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
- prnt(' _cffi_save_errno();')
- prnt(' Py_END_ALLOW_THREADS')
- prnt()
- #
- prnt(' (void)self; /* unused */')
- if numargs == 0:
- prnt(' (void)noarg; /* unused */')
- if result_code:
- prnt(' pyresult = %s;' %
- self._convert_expr_from_c(tp.result, 'result', 'result type'))
- for freeline in freelines:
- prnt(' ' + freeline)
- prnt(' return pyresult;')
- else:
- for freeline in freelines:
- prnt(' ' + freeline)
- prnt(' Py_INCREF(Py_None);')
- prnt(' return Py_None;')
- prnt('}')
- #
- prnt('#else') # ------------------------------
- #
- # the PyPy version: need to replace struct/union arguments with
- # pointers, and if the result is a struct/union, insert a first
- # arg that is a pointer to the result. We also do that for
- # complex args and return type.
- def need_indirection(type):
- return (isinstance(type, model.StructOrUnion) or
- (isinstance(type, model.PrimitiveType) and
- type.is_complex_type()))
- difference = False
- arguments = []
- call_arguments = []
- context = 'argument of %s' % name
- for i, type in enumerate(tp.args):
- indirection = ''
- if need_indirection(type):
- indirection = '*'
- difference = True
- arg = type.get_c_name(' %sx%d' % (indirection, i), context)
- arguments.append(arg)
- call_arguments.append('%sx%d' % (indirection, i))
- tp_result = tp.result
- if need_indirection(tp_result):
- context = 'result of %s' % name
- arg = tp_result.get_c_name(' *result', context)
- arguments.insert(0, arg)
- tp_result = model.void_type
- result_decl = None
- result_code = '*result = '
- difference = True
- if difference:
- repr_arguments = ', '.join(arguments)
- repr_arguments = repr_arguments or 'void'
- name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name,
- repr_arguments)
- prnt('static %s' % (tp_result.get_c_name(name_and_arguments),))
- prnt('{')
- if result_decl:
- prnt(result_decl)
- call_arguments = ', '.join(call_arguments)
- prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
- if result_decl:
- prnt(' return result;')
- prnt('}')
- else:
- prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name))
- #
- prnt('#endif') # ------------------------------
- prnt()
-
- def _generate_cpy_function_ctx(self, tp, name):
- if tp.ellipsis and not self.target_is_python:
- self._generate_cpy_constant_ctx(tp, name)
- return
- type_index = self._typesdict[tp.as_raw_function()]
- numargs = len(tp.args)
- if self.target_is_python:
- meth_kind = OP_DLOPEN_FUNC
- elif numargs == 0:
- meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS'
- elif numargs == 1:
- meth_kind = OP_CPYTHON_BLTN_O # 'METH_O'
- else:
- meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS'
- self._lsts["global"].append(
- GlobalExpr(name, '_cffi_f_%s' % name,
- CffiOp(meth_kind, type_index),
- size='_cffi_d_%s' % name))
-
- # ----------
- # named structs or unions
-
- def _field_type(self, tp_struct, field_name, tp_field):
- if isinstance(tp_field, model.ArrayType):
- actual_length = tp_field.length
- if actual_length == '...':
- ptr_struct_name = tp_struct.get_c_name('*')
- actual_length = '_cffi_array_len(((%s)0)->%s)' % (
- ptr_struct_name, field_name)
- tp_item = self._field_type(tp_struct, '%s[0]' % field_name,
- tp_field.item)
- tp_field = model.ArrayType(tp_item, actual_length)
- return tp_field
-
- def _struct_collecttype(self, tp):
- self._do_collect_type(tp)
- if self.target_is_python:
- # also requires nested anon struct/unions in ABI mode, recursively
- for fldtype in tp.anonymous_struct_fields():
- self._struct_collecttype(fldtype)
-
- def _struct_decl(self, tp, cname, approxname):
- if tp.fldtypes is None:
- return
- prnt = self._prnt
- checkfuncname = '_cffi_checkfld_%s' % (approxname,)
- prnt('_CFFI_UNUSED_FN')
- prnt('static void %s(%s *p)' % (checkfuncname, cname))
- prnt('{')
- prnt(' /* only to generate compile-time warnings or errors */')
- prnt(' (void)p;')
- for fname, ftype, fbitsize, fqual in self._enum_fields(tp):
- try:
- if ftype.is_integer_type() or fbitsize >= 0:
- # accept all integers, but complain on float or double
- if fname != '':
- prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is "
- "an integer */" % (fname, cname, fname))
- continue
- # only accept exactly the type declared, except that '[]'
- # is interpreted as a '*' and so will match any array length.
- # (It would also match '*', but that's harder to detect...)
- while (isinstance(ftype, model.ArrayType)
- and (ftype.length is None or ftype.length == '...')):
- ftype = ftype.item
- fname = fname + '[0]'
- prnt(' { %s = &p->%s; (void)tmp; }' % (
- ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
- fname))
- except VerificationError as e:
- prnt(' /* %s */' % str(e)) # cannot verify it, ignore
- prnt('}')
- prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname))
- prnt()
-
- def _struct_ctx(self, tp, cname, approxname, named_ptr=None):
- type_index = self._typesdict[tp]
- reason_for_not_expanding = None
- flags = []
- if isinstance(tp, model.UnionType):
- flags.append("_CFFI_F_UNION")
- if tp.fldtypes is None:
- flags.append("_CFFI_F_OPAQUE")
- reason_for_not_expanding = "opaque"
- if (tp not in self.ffi._parser._included_declarations and
- (named_ptr is None or
- named_ptr not in self.ffi._parser._included_declarations)):
- if tp.fldtypes is None:
- pass # opaque
- elif tp.partial or any(tp.anonymous_struct_fields()):
- pass # field layout obtained silently from the C compiler
- else:
- flags.append("_CFFI_F_CHECK_FIELDS")
- if tp.packed:
- if tp.packed > 1:
- raise NotImplementedError(
- "%r is declared with 'pack=%r'; only 0 or 1 are "
- "supported in API mode (try to use \"...;\", which "
- "does not require a 'pack' declaration)" %
- (tp, tp.packed))
- flags.append("_CFFI_F_PACKED")
- else:
- flags.append("_CFFI_F_EXTERNAL")
- reason_for_not_expanding = "external"
- flags = '|'.join(flags) or '0'
- c_fields = []
- if reason_for_not_expanding is None:
- enumfields = list(self._enum_fields(tp))
- for fldname, fldtype, fbitsize, fqual in enumfields:
- fldtype = self._field_type(tp, fldname, fldtype)
- self._check_not_opaque(fldtype,
- "field '%s.%s'" % (tp.name, fldname))
- # cname is None for _add_missing_struct_unions() only
- op = OP_NOOP
- if fbitsize >= 0:
- op = OP_BITFIELD
- size = '%d /* bits */' % fbitsize
- elif cname is None or (
- isinstance(fldtype, model.ArrayType) and
- fldtype.length is None):
- size = '(size_t)-1'
- else:
- size = 'sizeof(((%s)0)->%s)' % (
- tp.get_c_name('*') if named_ptr is None
- else named_ptr.name,
- fldname)
- if cname is None or fbitsize >= 0:
- offset = '(size_t)-1'
- elif named_ptr is not None:
- offset = '((char *)&((%s)0)->%s) - (char *)0' % (
- named_ptr.name, fldname)
- else:
- offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname)
- c_fields.append(
- FieldExpr(fldname, offset, size, fbitsize,
- CffiOp(op, self._typesdict[fldtype])))
- first_field_index = len(self._lsts["field"])
- self._lsts["field"].extend(c_fields)
- #
- if cname is None: # unknown name, for _add_missing_struct_unions
- size = '(size_t)-2'
- align = -2
- comment = "unnamed"
- else:
- if named_ptr is not None:
- size = 'sizeof(*(%s)0)' % (named_ptr.name,)
- align = '-1 /* unknown alignment */'
- else:
- size = 'sizeof(%s)' % (cname,)
- align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,)
- comment = None
- else:
- size = '(size_t)-1'
- align = -1
- first_field_index = -1
- comment = reason_for_not_expanding
- self._lsts["struct_union"].append(
- StructUnionExpr(tp.name, type_index, flags, size, align, comment,
- first_field_index, c_fields))
- self._seen_struct_unions.add(tp)
-
- def _check_not_opaque(self, tp, location):
- while isinstance(tp, model.ArrayType):
- tp = tp.item
- if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None:
- raise TypeError(
- "%s is of an opaque type (not declared in cdef())" % location)
-
- def _add_missing_struct_unions(self):
- # not very nice, but some struct declarations might be missing
- # because they don't have any known C name. Check that they are
- # not partial (we can't complete or verify them!) and emit them
- # anonymously.
- lst = list(self._struct_unions.items())
- lst.sort(key=lambda tp_order: tp_order[1])
- for tp, order in lst:
- if tp not in self._seen_struct_unions:
- if tp.partial:
- raise NotImplementedError("internal inconsistency: %r is "
- "partial but was not seen at "
- "this point" % (tp,))
- if tp.name.startswith('$') and tp.name[1:].isdigit():
- approxname = tp.name[1:]
- elif tp.name == '_IO_FILE' and tp.forcename == 'FILE':
- approxname = 'FILE'
- self._typedef_ctx(tp, 'FILE')
- else:
- raise NotImplementedError("internal inconsistency: %r" %
- (tp,))
- self._struct_ctx(tp, None, approxname)
-
- def _generate_cpy_struct_collecttype(self, tp, name):
- self._struct_collecttype(tp)
- _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype
-
- def _struct_names(self, tp):
- cname = tp.get_c_name('')
- if ' ' in cname:
- return cname, cname.replace(' ', '_')
- else:
- return cname, '_' + cname
-
- def _generate_cpy_struct_decl(self, tp, name):
- self._struct_decl(tp, *self._struct_names(tp))
- _generate_cpy_union_decl = _generate_cpy_struct_decl
-
- def _generate_cpy_struct_ctx(self, tp, name):
- self._struct_ctx(tp, *self._struct_names(tp))
- _generate_cpy_union_ctx = _generate_cpy_struct_ctx
-
- # ----------
- # 'anonymous' declarations. These are produced for anonymous structs
- # or unions; the 'name' is obtained by a typedef.
-
- def _generate_cpy_anonymous_collecttype(self, tp, name):
- if isinstance(tp, model.EnumType):
- self._generate_cpy_enum_collecttype(tp, name)
- else:
- self._struct_collecttype(tp)
-
- def _generate_cpy_anonymous_decl(self, tp, name):
- if isinstance(tp, model.EnumType):
- self._generate_cpy_enum_decl(tp)
- else:
- self._struct_decl(tp, name, 'typedef_' + name)
-
- def _generate_cpy_anonymous_ctx(self, tp, name):
- if isinstance(tp, model.EnumType):
- self._enum_ctx(tp, name)
- else:
- self._struct_ctx(tp, name, 'typedef_' + name)
-
- # ----------
- # constants, declared with "static const ..."
-
- def _generate_cpy_const(self, is_int, name, tp=None, category='const',
- check_value=None):
- if (category, name) in self._seen_constants:
- raise VerificationError(
- "duplicate declaration of %s '%s'" % (category, name))
- self._seen_constants.add((category, name))
- #
- prnt = self._prnt
- funcname = '_cffi_%s_%s' % (category, name)
- if is_int:
- prnt('static int %s(unsigned long long *o)' % funcname)
- prnt('{')
- prnt(' int n = (%s) <= 0;' % (name,))
- prnt(' *o = (unsigned long long)((%s) | 0);'
- ' /* check that %s is an integer */' % (name, name))
- if check_value is not None:
- if check_value > 0:
- check_value = '%dU' % (check_value,)
- prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,))
- prnt(' n |= 2;')
- prnt(' return n;')
- prnt('}')
- else:
- assert check_value is None
- prnt('static void %s(char *o)' % funcname)
- prnt('{')
- prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name))
- prnt('}')
- prnt()
-
- def _generate_cpy_constant_collecttype(self, tp, name):
- is_int = tp.is_integer_type()
- if not is_int or self.target_is_python:
- self._do_collect_type(tp)
-
- def _generate_cpy_constant_decl(self, tp, name):
- is_int = tp.is_integer_type()
- self._generate_cpy_const(is_int, name, tp)
-
- def _generate_cpy_constant_ctx(self, tp, name):
- if not self.target_is_python and tp.is_integer_type():
- type_op = CffiOp(OP_CONSTANT_INT, -1)
- else:
- if self.target_is_python:
- const_kind = OP_DLOPEN_CONST
- else:
- const_kind = OP_CONSTANT
- type_index = self._typesdict[tp]
- type_op = CffiOp(const_kind, type_index)
- self._lsts["global"].append(
- GlobalExpr(name, '_cffi_const_%s' % name, type_op))
-
- # ----------
- # enums
-
- def _generate_cpy_enum_collecttype(self, tp, name):
- self._do_collect_type(tp)
-
- def _generate_cpy_enum_decl(self, tp, name=None):
- for enumerator in tp.enumerators:
- self._generate_cpy_const(True, enumerator)
-
- def _enum_ctx(self, tp, cname):
- type_index = self._typesdict[tp]
- type_op = CffiOp(OP_ENUM, -1)
- if self.target_is_python:
- tp.check_not_partial()
- for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
- self._lsts["global"].append(
- GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op,
- check_value=enumvalue))
- #
- if cname is not None and '$' not in cname and not self.target_is_python:
- size = "sizeof(%s)" % cname
- signed = "((%s)-1) <= 0" % cname
- else:
- basetp = tp.build_baseinttype(self.ffi, [])
- size = self.ffi.sizeof(basetp)
- signed = int(int(self.ffi.cast(basetp, -1)) < 0)
- allenums = ",".join(tp.enumerators)
- self._lsts["enum"].append(
- EnumExpr(tp.name, type_index, size, signed, allenums))
-
- def _generate_cpy_enum_ctx(self, tp, name):
- self._enum_ctx(tp, tp._get_c_name())
-
- # ----------
- # macros: for now only for integers
-
- def _generate_cpy_macro_collecttype(self, tp, name):
- pass
-
- def _generate_cpy_macro_decl(self, tp, name):
- if tp == '...':
- check_value = None
- else:
- check_value = tp # an integer
- self._generate_cpy_const(True, name, check_value=check_value)
-
- def _generate_cpy_macro_ctx(self, tp, name):
- if tp == '...':
- if self.target_is_python:
- raise VerificationError(
- "cannot use the syntax '...' in '#define %s ...' when "
- "using the ABI mode" % (name,))
- check_value = None
- else:
- check_value = tp # an integer
- type_op = CffiOp(OP_CONSTANT_INT, -1)
- self._lsts["global"].append(
- GlobalExpr(name, '_cffi_const_%s' % name, type_op,
- check_value=check_value))
-
- # ----------
- # global variables
-
- def _global_type(self, tp, global_name):
- if isinstance(tp, model.ArrayType):
- actual_length = tp.length
- if actual_length == '...':
- actual_length = '_cffi_array_len(%s)' % (global_name,)
- tp_item = self._global_type(tp.item, '%s[0]' % global_name)
- tp = model.ArrayType(tp_item, actual_length)
- return tp
-
- def _generate_cpy_variable_collecttype(self, tp, name):
- self._do_collect_type(self._global_type(tp, name))
-
- def _generate_cpy_variable_decl(self, tp, name):
- prnt = self._prnt
- tp = self._global_type(tp, name)
- if isinstance(tp, model.ArrayType) and tp.length is None:
- tp = tp.item
- ampersand = ''
- else:
- ampersand = '&'
- # This code assumes that casts from "tp *" to "void *" is a
- # no-op, i.e. a function that returns a "tp *" can be called
- # as if it returned a "void *". This should be generally true
- # on any modern machine. The only exception to that rule (on
- # uncommon architectures, and as far as I can tell) might be
- # if 'tp' were a function type, but that is not possible here.
- # (If 'tp' is a function _pointer_ type, then casts from "fn_t
- # **" to "void *" are again no-ops, as far as I can tell.)
- decl = '*_cffi_var_%s(void)' % (name,)
- prnt('static ' + tp.get_c_name(decl, quals=self._current_quals))
- prnt('{')
- prnt(' return %s(%s);' % (ampersand, name))
- prnt('}')
- prnt()
-
- def _generate_cpy_variable_ctx(self, tp, name):
- tp = self._global_type(tp, name)
- type_index = self._typesdict[tp]
- if self.target_is_python:
- op = OP_GLOBAL_VAR
- else:
- op = OP_GLOBAL_VAR_F
- self._lsts["global"].append(
- GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index)))
-
- # ----------
- # extern "Python"
-
- def _generate_cpy_extern_python_collecttype(self, tp, name):
- assert isinstance(tp, model.FunctionPtrType)
- self._do_collect_type(tp)
- _generate_cpy_dllexport_python_collecttype = \
- _generate_cpy_extern_python_plus_c_collecttype = \
- _generate_cpy_extern_python_collecttype
-
- def _extern_python_decl(self, tp, name, tag_and_space):
- prnt = self._prnt
- if isinstance(tp.result, model.VoidType):
- size_of_result = '0'
- else:
- context = 'result of %s' % name
- size_of_result = '(int)sizeof(%s)' % (
- tp.result.get_c_name('', context),)
- prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name)
- prnt(' { "%s.%s", %s, 0, 0 };' % (
- self.module_name, name, size_of_result))
- prnt()
- #
- arguments = []
- context = 'argument of %s' % name
- for i, type in enumerate(tp.args):
- arg = type.get_c_name(' a%d' % i, context)
- arguments.append(arg)
- #
- repr_arguments = ', '.join(arguments)
- repr_arguments = repr_arguments or 'void'
- name_and_arguments = '%s(%s)' % (name, repr_arguments)
- if tp.abi == "__stdcall":
- name_and_arguments = '_cffi_stdcall ' + name_and_arguments
- #
- def may_need_128_bits(tp):
- return (isinstance(tp, model.PrimitiveType) and
- tp.name == 'long double')
- #
- size_of_a = max(len(tp.args)*8, 8)
- if may_need_128_bits(tp.result):
- size_of_a = max(size_of_a, 16)
- if isinstance(tp.result, model.StructOrUnion):
- size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % (
- tp.result.get_c_name(''), size_of_a,
- tp.result.get_c_name(''), size_of_a)
- prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments)))
- prnt('{')
- prnt(' char a[%s];' % size_of_a)
- prnt(' char *p = a;')
- for i, type in enumerate(tp.args):
- arg = 'a%d' % i
- if (isinstance(type, model.StructOrUnion) or
- may_need_128_bits(type)):
- arg = '&' + arg
- type = model.PointerType(type)
- prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg))
- prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name)
- if not isinstance(tp.result, model.VoidType):
- prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),))
- prnt('}')
- prnt()
- self._num_externpy += 1
-
- def _generate_cpy_extern_python_decl(self, tp, name):
- self._extern_python_decl(tp, name, 'static ')
-
- def _generate_cpy_dllexport_python_decl(self, tp, name):
- self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ')
-
- def _generate_cpy_extern_python_plus_c_decl(self, tp, name):
- self._extern_python_decl(tp, name, '')
-
- def _generate_cpy_extern_python_ctx(self, tp, name):
- if self.target_is_python:
- raise VerificationError(
- "cannot use 'extern \"Python\"' in the ABI mode")
- if tp.ellipsis:
- raise NotImplementedError("a vararg function is extern \"Python\"")
- type_index = self._typesdict[tp]
- type_op = CffiOp(OP_EXTERN_PYTHON, type_index)
- self._lsts["global"].append(
- GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name))
-
- _generate_cpy_dllexport_python_ctx = \
- _generate_cpy_extern_python_plus_c_ctx = \
- _generate_cpy_extern_python_ctx
-
- def _print_string_literal_in_array(self, s):
- prnt = self._prnt
- prnt('// # NB. this is not a string because of a size limit in MSVC')
- if not isinstance(s, bytes): # unicode
- s = s.encode('utf-8') # -> bytes
- else:
- s.decode('utf-8') # got bytes, check for valid utf-8
- try:
- s.decode('ascii')
- except UnicodeDecodeError:
- s = b'# -*- encoding: utf8 -*-\n' + s
- for line in s.splitlines(True):
- comment = line
- if type('//') is bytes: # python2
- line = map(ord, line) # make a list of integers
- else: # python3
- # type(line) is bytes, which enumerates like a list of integers
- comment = ascii(comment)[1:-1]
- prnt(('// ' + comment).rstrip())
- printed_line = ''
- for c in line:
- if len(printed_line) >= 76:
- prnt(printed_line)
- printed_line = ''
- printed_line += '%d,' % (c,)
- prnt(printed_line)
-
- # ----------
- # emitting the opcodes for individual types
-
- def _emit_bytecode_VoidType(self, tp, index):
- self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID)
-
- def _emit_bytecode_PrimitiveType(self, tp, index):
- prim_index = PRIMITIVE_TO_INDEX[tp.name]
- self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index)
-
- def _emit_bytecode_UnknownIntegerType(self, tp, index):
- s = ('_cffi_prim_int(sizeof(%s), (\n'
- ' ((%s)-1) | 0 /* check that %s is an integer type */\n'
- ' ) <= 0)' % (tp.name, tp.name, tp.name))
- self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
-
- def _emit_bytecode_UnknownFloatType(self, tp, index):
- s = ('_cffi_prim_float(sizeof(%s) *\n'
- ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n'
- ' )' % (tp.name, tp.name))
- self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
-
- def _emit_bytecode_RawFunctionType(self, tp, index):
- self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result])
- index += 1
- for tp1 in tp.args:
- realindex = self._typesdict[tp1]
- if index != realindex:
- if isinstance(tp1, model.PrimitiveType):
- self._emit_bytecode_PrimitiveType(tp1, index)
- else:
- self.cffi_types[index] = CffiOp(OP_NOOP, realindex)
- index += 1
- flags = int(tp.ellipsis)
- if tp.abi is not None:
- if tp.abi == '__stdcall':
- flags |= 2
- else:
- raise NotImplementedError("abi=%r" % (tp.abi,))
- self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags)
-
- def _emit_bytecode_PointerType(self, tp, index):
- self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype])
-
- _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType
- _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType
-
- def _emit_bytecode_FunctionPtrType(self, tp, index):
- raw = tp.as_raw_function()
- self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw])
-
- def _emit_bytecode_ArrayType(self, tp, index):
- item_index = self._typesdict[tp.item]
- if tp.length is None:
- self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index)
- elif tp.length == '...':
- raise VerificationError(
- "type %s badly placed: the '...' array length can only be "
- "used on global arrays or on fields of structures" % (
- str(tp).replace('/*...*/', '...'),))
- else:
- assert self.cffi_types[index + 1] == 'LEN'
- self.cffi_types[index] = CffiOp(OP_ARRAY, item_index)
- self.cffi_types[index + 1] = CffiOp(None, str(tp.length))
-
- def _emit_bytecode_StructType(self, tp, index):
- struct_index = self._struct_unions[tp]
- self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index)
- _emit_bytecode_UnionType = _emit_bytecode_StructType
-
- def _emit_bytecode_EnumType(self, tp, index):
- enum_index = self._enums[tp]
- self.cffi_types[index] = CffiOp(OP_ENUM, enum_index)
-
-
-if sys.version_info >= (3,):
- NativeIO = io.StringIO
-else:
- class NativeIO(io.BytesIO):
- def write(self, s):
- if isinstance(s, unicode):
- s = s.encode('ascii')
- super(NativeIO, self).write(s)
-
-def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose):
- if verbose:
- print("generating %s" % (target_file,))
- recompiler = Recompiler(ffi, module_name,
- target_is_python=(preamble is None))
- recompiler.collect_type_table()
- recompiler.collect_step_tables()
- f = NativeIO()
- recompiler.write_source_to_f(f, preamble)
- output = f.getvalue()
- try:
- with open(target_file, 'r') as f1:
- if f1.read(len(output) + 1) != output:
- raise IOError
- if verbose:
- print("(already up-to-date)")
- return False # already up-to-date
- except IOError:
- tmp_file = '%s.~%d' % (target_file, os.getpid())
- with open(tmp_file, 'w') as f1:
- f1.write(output)
- try:
- os.rename(tmp_file, target_file)
- except OSError:
- os.unlink(target_file)
- os.rename(tmp_file, target_file)
- return True
-
-def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False):
- assert preamble is not None
- return _make_c_or_py_source(ffi, module_name, preamble, target_c_file,
- verbose)
-
-def make_py_source(ffi, module_name, target_py_file, verbose=False):
- return _make_c_or_py_source(ffi, module_name, None, target_py_file,
- verbose)
-
-def _modname_to_file(outputdir, modname, extension):
- parts = modname.split('.')
- try:
- os.makedirs(os.path.join(outputdir, *parts[:-1]))
- except OSError:
- pass
- parts[-1] += extension
- return os.path.join(outputdir, *parts), parts
-
-
-# Aaargh. Distutils is not tested at all for the purpose of compiling
-# DLLs that are not extension modules. Here are some hacks to work
-# around that, in the _patch_for_*() functions...
-
-def _patch_meth(patchlist, cls, name, new_meth):
- old = getattr(cls, name)
- patchlist.append((cls, name, old))
- setattr(cls, name, new_meth)
- return old
-
-def _unpatch_meths(patchlist):
- for cls, name, old_meth in reversed(patchlist):
- setattr(cls, name, old_meth)
-
-def _patch_for_embedding(patchlist):
- if sys.platform == 'win32':
- # we must not remove the manifest when building for embedding!
- from distutils.msvc9compiler import MSVCCompiler
- _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref',
- lambda self, manifest_file: manifest_file)
-
- if sys.platform == 'darwin':
- # we must not make a '-bundle', but a '-dynamiclib' instead
- from distutils.ccompiler import CCompiler
- def my_link_shared_object(self, *args, **kwds):
- if '-bundle' in self.linker_so:
- self.linker_so = list(self.linker_so)
- i = self.linker_so.index('-bundle')
- self.linker_so[i] = '-dynamiclib'
- return old_link_shared_object(self, *args, **kwds)
- old_link_shared_object = _patch_meth(patchlist, CCompiler,
- 'link_shared_object',
- my_link_shared_object)
-
-def _patch_for_target(patchlist, target):
- from distutils.command.build_ext import build_ext
- # if 'target' is different from '*', we need to patch some internal
- # method to just return this 'target' value, instead of having it
- # built from module_name
- if target.endswith('.*'):
- target = target[:-2]
- if sys.platform == 'win32':
- target += '.dll'
- elif sys.platform == 'darwin':
- target += '.dylib'
- else:
- target += '.so'
- _patch_meth(patchlist, build_ext, 'get_ext_filename',
- lambda self, ext_name: target)
-
-
-def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
- c_file=None, source_extension='.c', extradir=None,
- compiler_verbose=1, target=None, debug=None, **kwds):
- if not isinstance(module_name, str):
- module_name = module_name.encode('ascii')
- if ffi._windows_unicode:
- ffi._apply_windows_unicode(kwds)
- if preamble is not None:
- embedding = (ffi._embedding is not None)
- if embedding:
- ffi._apply_embedding_fix(kwds)
- if c_file is None:
- c_file, parts = _modname_to_file(tmpdir, module_name,
- source_extension)
- if extradir:
- parts = [extradir] + parts
- ext_c_file = os.path.join(*parts)
- else:
- ext_c_file = c_file
- #
- if target is None:
- if embedding:
- target = '%s.*' % module_name
- else:
- target = '*'
- #
- ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
- updated = make_c_source(ffi, module_name, preamble, c_file,
- verbose=compiler_verbose)
- if call_c_compiler:
- patchlist = []
- cwd = os.getcwd()
- try:
- if embedding:
- _patch_for_embedding(patchlist)
- if target != '*':
- _patch_for_target(patchlist, target)
- if compiler_verbose:
- if tmpdir == '.':
- msg = 'the current directory is'
- else:
- msg = 'setting the current directory to'
- print('%s %r' % (msg, os.path.abspath(tmpdir)))
- os.chdir(tmpdir)
- outputfilename = ffiplatform.compile('.', ext,
- compiler_verbose, debug)
- finally:
- os.chdir(cwd)
- _unpatch_meths(patchlist)
- return outputfilename
- else:
- return ext, updated
- else:
- if c_file is None:
- c_file, _ = _modname_to_file(tmpdir, module_name, '.py')
- updated = make_py_source(ffi, module_name, c_file,
- verbose=compiler_verbose)
- if call_c_compiler:
- return c_file
- else:
- return None, updated
-
diff --git a/cffi/setuptools_ext.py b/cffi/setuptools_ext.py
deleted file mode 100644
index 8fe3614..0000000
--- a/cffi/setuptools_ext.py
+++ /dev/null
@@ -1,219 +0,0 @@
-import os
-import sys
-
-try:
- basestring
-except NameError:
- # Python 3.x
- basestring = str
-
-def error(msg):
- from distutils.errors import DistutilsSetupError
- raise DistutilsSetupError(msg)
-
-
-def execfile(filename, glob):
- # We use execfile() (here rewritten for Python 3) instead of
- # __import__() to load the build script. The problem with
- # a normal import is that in some packages, the intermediate
- # __init__.py files may already try to import the file that
- # we are generating.
- with open(filename) as f:
- src = f.read()
- src += '\n' # Python 2.6 compatibility
- code = compile(src, filename, 'exec')
- exec(code, glob, glob)
-
-
-def add_cffi_module(dist, mod_spec):
- from cffi.api import FFI
-
- if not isinstance(mod_spec, basestring):
- error("argument to 'cffi_modules=...' must be a str or a list of str,"
- " not %r" % (type(mod_spec).__name__,))
- mod_spec = str(mod_spec)
- try:
- build_file_name, ffi_var_name = mod_spec.split(':')
- except ValueError:
- error("%r must be of the form 'path/build.py:ffi_variable'" %
- (mod_spec,))
- if not os.path.exists(build_file_name):
- ext = ''
- rewritten = build_file_name.replace('.', '/') + '.py'
- if os.path.exists(rewritten):
- ext = ' (rewrite cffi_modules to [%r])' % (
- rewritten + ':' + ffi_var_name,)
- error("%r does not name an existing file%s" % (build_file_name, ext))
-
- mod_vars = {'__name__': '__cffi__', '__file__': build_file_name}
- execfile(build_file_name, mod_vars)
-
- try:
- ffi = mod_vars[ffi_var_name]
- except KeyError:
- error("%r: object %r not found in module" % (mod_spec,
- ffi_var_name))
- if not isinstance(ffi, FFI):
- ffi = ffi() # maybe it's a function instead of directly an ffi
- if not isinstance(ffi, FFI):
- error("%r is not an FFI instance (got %r)" % (mod_spec,
- type(ffi).__name__))
- if not hasattr(ffi, '_assigned_source'):
- error("%r: the set_source() method was not called" % (mod_spec,))
- module_name, source, source_extension, kwds = ffi._assigned_source
- if ffi._windows_unicode:
- kwds = kwds.copy()
- ffi._apply_windows_unicode(kwds)
-
- if source is None:
- _add_py_module(dist, ffi, module_name)
- else:
- _add_c_module(dist, ffi, module_name, source, source_extension, kwds)
-
-def _set_py_limited_api(Extension, kwds):
- """
- Add py_limited_api to kwds if setuptools >= 26 is in use.
- Do not alter the setting if it already exists.
- Setuptools takes care of ignoring the flag on Python 2 and PyPy.
-
- CPython itself should ignore the flag in a debugging version
- (by not listing .abi3.so in the extensions it supports), but
- it doesn't so far, creating troubles. That's why we check
- for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent
- of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401)
-
- On Windows, with CPython <= 3.4, it's better not to use py_limited_api
- because virtualenv *still* doesn't copy PYTHON3.DLL on these versions.
- Recently (2020) we started shipping only >= 3.5 wheels, though. So
- we'll give it another try and set py_limited_api on Windows >= 3.5.
- """
- from cffi import recompiler
-
- if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount')
- and recompiler.USE_LIMITED_API):
- import setuptools
- try:
- setuptools_major_version = int(setuptools.__version__.partition('.')[0])
- if setuptools_major_version >= 26:
- kwds['py_limited_api'] = True
- except ValueError: # certain development versions of setuptools
- # If we don't know the version number of setuptools, we
- # try to set 'py_limited_api' anyway. At worst, we get a
- # warning.
- kwds['py_limited_api'] = True
- return kwds
-
-def _add_c_module(dist, ffi, module_name, source, source_extension, kwds):
- from distutils.core import Extension
- # We are a setuptools extension. Need this build_ext for py_limited_api.
- from setuptools.command.build_ext import build_ext
- from distutils.dir_util import mkpath
- from distutils import log
- from cffi import recompiler
-
- allsources = ['$PLACEHOLDER']
- allsources.extend(kwds.pop('sources', []))
- kwds = _set_py_limited_api(Extension, kwds)
- ext = Extension(name=module_name, sources=allsources, **kwds)
-
- def make_mod(tmpdir, pre_run=None):
- c_file = os.path.join(tmpdir, module_name + source_extension)
- log.info("generating cffi module %r" % c_file)
- mkpath(tmpdir)
- # a setuptools-only, API-only hook: called with the "ext" and "ffi"
- # arguments just before we turn the ffi into C code. To use it,
- # subclass the 'distutils.command.build_ext.build_ext' class and
- # add a method 'def pre_run(self, ext, ffi)'.
- if pre_run is not None:
- pre_run(ext, ffi)
- updated = recompiler.make_c_source(ffi, module_name, source, c_file)
- if not updated:
- log.info("already up-to-date")
- return c_file
-
- if dist.ext_modules is None:
- dist.ext_modules = []
- dist.ext_modules.append(ext)
-
- base_class = dist.cmdclass.get('build_ext', build_ext)
- class build_ext_make_mod(base_class):
- def run(self):
- if ext.sources[0] == '$PLACEHOLDER':
- pre_run = getattr(self, 'pre_run', None)
- ext.sources[0] = make_mod(self.build_temp, pre_run)
- base_class.run(self)
- dist.cmdclass['build_ext'] = build_ext_make_mod
- # NB. multiple runs here will create multiple 'build_ext_make_mod'
- # classes. Even in this case the 'build_ext' command should be
- # run once; but just in case, the logic above does nothing if
- # called again.
-
-
-def _add_py_module(dist, ffi, module_name):
- from distutils.dir_util import mkpath
- from setuptools.command.build_py import build_py
- from setuptools.command.build_ext import build_ext
- from distutils import log
- from cffi import recompiler
-
- def generate_mod(py_file):
- log.info("generating cffi module %r" % py_file)
- mkpath(os.path.dirname(py_file))
- updated = recompiler.make_py_source(ffi, module_name, py_file)
- if not updated:
- log.info("already up-to-date")
-
- base_class = dist.cmdclass.get('build_py', build_py)
- class build_py_make_mod(base_class):
- def run(self):
- base_class.run(self)
- module_path = module_name.split('.')
- module_path[-1] += '.py'
- generate_mod(os.path.join(self.build_lib, *module_path))
- def get_source_files(self):
- # This is called from 'setup.py sdist' only. Exclude
- # the generate .py module in this case.
- saved_py_modules = self.py_modules
- try:
- if saved_py_modules:
- self.py_modules = [m for m in saved_py_modules
- if m != module_name]
- return base_class.get_source_files(self)
- finally:
- self.py_modules = saved_py_modules
- dist.cmdclass['build_py'] = build_py_make_mod
-
- # distutils and setuptools have no notion I could find of a
- # generated python module. If we don't add module_name to
- # dist.py_modules, then things mostly work but there are some
- # combination of options (--root and --record) that will miss
- # the module. So we add it here, which gives a few apparently
- # harmless warnings about not finding the file outside the
- # build directory.
- # Then we need to hack more in get_source_files(); see above.
- if dist.py_modules is None:
- dist.py_modules = []
- dist.py_modules.append(module_name)
-
- # the following is only for "build_ext -i"
- base_class_2 = dist.cmdclass.get('build_ext', build_ext)
- class build_ext_make_mod(base_class_2):
- def run(self):
- base_class_2.run(self)
- if self.inplace:
- # from get_ext_fullpath() in distutils/command/build_ext.py
- module_path = module_name.split('.')
- package = '.'.join(module_path[:-1])
- build_py = self.get_finalized_command('build_py')
- package_dir = build_py.get_package_dir(package)
- file_name = module_path[-1] + '.py'
- generate_mod(os.path.join(package_dir, file_name))
- dist.cmdclass['build_ext'] = build_ext_make_mod
-
-def cffi_modules(dist, attr, value):
- assert attr == 'cffi_modules'
- if isinstance(value, basestring):
- value = [value]
-
- for cffi_module in value:
- add_cffi_module(dist, cffi_module)
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
deleted file mode 100644
index 6de0df0..0000000
--- a/cffi/vengine_cpy.py
+++ /dev/null
@@ -1,1076 +0,0 @@
-#
-# DEPRECATED: implementation for ffi.verify()
-#
-import sys, imp
-from . import model
-from .error import VerificationError
-
-
-class VCPythonEngine(object):
- _class_key = 'x'
- _gen_python_module = True
-
- def __init__(self, verifier):
- self.verifier = verifier
- self.ffi = verifier.ffi
- self._struct_pending_verification = {}
- self._types_of_builtin_functions = {}
-
- def patch_extension_kwds(self, kwds):
- pass
-
- def find_module(self, module_name, path, so_suffixes):
- try:
- f, filename, descr = imp.find_module(module_name, path)
- except ImportError:
- return None
- if f is not None:
- f.close()
- # Note that after a setuptools installation, there are both .py
- # and .so files with the same basename. The code here relies on
- # imp.find_module() locating the .so in priority.
- if descr[0] not in so_suffixes:
- return None
- return filename
-
- def collect_types(self):
- self._typesdict = {}
- self._generate("collecttype")
-
- def _prnt(self, what=''):
- self._f.write(what + '\n')
-
- def _gettypenum(self, type):
- # a KeyError here is a bug. please report it! :-)
- return self._typesdict[type]
-
- def _do_collect_type(self, tp):
- if ((not isinstance(tp, model.PrimitiveType)
- or tp.name == 'long double')
- and tp not in self._typesdict):
- num = len(self._typesdict)
- self._typesdict[tp] = num
-
- def write_source_to_f(self):
- self.collect_types()
- #
- # The new module will have a _cffi_setup() function that receives
- # objects from the ffi world, and that calls some setup code in
- # the module. This setup code is split in several independent
- # functions, e.g. one per constant. The functions are "chained"
- # by ending in a tail call to each other.
- #
- # This is further split in two chained lists, depending on if we
- # can do it at import-time or if we must wait for _cffi_setup() to
- # provide us with the <ctype> objects. This is needed because we
- # need the values of the enum constants in order to build the
- # <ctype 'enum'> that we may have to pass to _cffi_setup().
- #
- # The following two 'chained_list_constants' items contains
- # the head of these two chained lists, as a string that gives the
- # call to do, if any.
- self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)']
- #
- prnt = self._prnt
- # first paste some standard set of lines that are mostly '#define'
- prnt(cffimod_header)
- prnt()
- # then paste the C source given by the user, verbatim.
- prnt(self.verifier.preamble)
- prnt()
- #
- # call generate_cpy_xxx_decl(), for every xxx found from
- # ffi._parser._declarations. This generates all the functions.
- self._generate("decl")
- #
- # implement the function _cffi_setup_custom() as calling the
- # head of the chained list.
- self._generate_setup_custom()
- prnt()
- #
- # produce the method table, including the entries for the
- # generated Python->C function wrappers, which are done
- # by generate_cpy_function_method().
- prnt('static PyMethodDef _cffi_methods[] = {')
- self._generate("method")
- prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},')
- prnt(' {NULL, NULL, 0, NULL} /* Sentinel */')
- prnt('};')
- prnt()
- #
- # standard init.
- modname = self.verifier.get_module_name()
- constants = self._chained_list_constants[False]
- prnt('#if PY_MAJOR_VERSION >= 3')
- prnt()
- prnt('static struct PyModuleDef _cffi_module_def = {')
- prnt(' PyModuleDef_HEAD_INIT,')
- prnt(' "%s",' % modname)
- prnt(' NULL,')
- prnt(' -1,')
- prnt(' _cffi_methods,')
- prnt(' NULL, NULL, NULL, NULL')
- prnt('};')
- prnt()
- prnt('PyMODINIT_FUNC')
- prnt('PyInit_%s(void)' % modname)
- prnt('{')
- prnt(' PyObject *lib;')
- prnt(' lib = PyModule_Create(&_cffi_module_def);')
- prnt(' if (lib == NULL)')
- prnt(' return NULL;')
- prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,))
- prnt(' Py_DECREF(lib);')
- prnt(' return NULL;')
- prnt(' }')
- prnt(' return lib;')
- prnt('}')
- prnt()
- prnt('#else')
- prnt()
- prnt('PyMODINIT_FUNC')
- prnt('init%s(void)' % modname)
- prnt('{')
- prnt(' PyObject *lib;')
- prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname)
- prnt(' if (lib == NULL)')
- prnt(' return;')
- prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,))
- prnt(' return;')
- prnt(' return;')
- prnt('}')
- prnt()
- prnt('#endif')
-
- def load_library(self, flags=None):
- # XXX review all usages of 'self' here!
- # import it as a new extension module
- imp.acquire_lock()
- try:
- if hasattr(sys, "getdlopenflags"):
- previous_flags = sys.getdlopenflags()
- try:
- if hasattr(sys, "setdlopenflags") and flags is not None:
- sys.setdlopenflags(flags)
- module = imp.load_dynamic(self.verifier.get_module_name(),
- self.verifier.modulefilename)
- except ImportError as e:
- error = "importing %r: %s" % (self.verifier.modulefilename, e)
- raise VerificationError(error)
- finally:
- if hasattr(sys, "setdlopenflags"):
- sys.setdlopenflags(previous_flags)
- finally:
- imp.release_lock()
- #
- # call loading_cpy_struct() to get the struct layout inferred by
- # the C compiler
- self._load(module, 'loading')
- #
- # the C code will need the <ctype> objects. Collect them in
- # order in a list.
- revmapping = dict([(value, key)
- for (key, value) in self._typesdict.items()])
- lst = [revmapping[i] for i in range(len(revmapping))]
- lst = list(map(self.ffi._get_cached_btype, lst))
- #
- # build the FFILibrary class and instance and call _cffi_setup().
- # this will set up some fields like '_cffi_types', and only then
- # it will invoke the chained list of functions that will really
- # build (notably) the constant objects, as <cdata> if they are
- # pointers, and store them as attributes on the 'library' object.
- class FFILibrary(object):
- _cffi_python_module = module
- _cffi_ffi = self.ffi
- _cffi_dir = []
- def __dir__(self):
- return FFILibrary._cffi_dir + list(self.__dict__)
- library = FFILibrary()
- if module._cffi_setup(lst, VerificationError, library):
- import warnings
- warnings.warn("reimporting %r might overwrite older definitions"
- % (self.verifier.get_module_name()))
- #
- # finally, call the loaded_cpy_xxx() functions. This will perform
- # the final adjustments, like copying the Python->C wrapper
- # functions from the module to the 'library' object, and setting
- # up the FFILibrary class with properties for the global C variables.
- self._load(module, 'loaded', library=library)
- module._cffi_original_ffi = self.ffi
- module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions
- return library
-
- def _get_declarations(self):
- lst = [(key, tp) for (key, (tp, qual)) in
- self.ffi._parser._declarations.items()]
- lst.sort()
- return lst
-
- def _generate(self, step_name):
- for name, tp in self._get_declarations():
- kind, realname = name.split(' ', 1)
- try:
- method = getattr(self, '_generate_cpy_%s_%s' % (kind,
- step_name))
- except AttributeError:
- raise VerificationError(
- "not implemented in verify(): %r" % name)
- try:
- method(tp, realname)
- except Exception as e:
- model.attach_exception_info(e, name)
- raise
-
- def _load(self, module, step_name, **kwds):
- for name, tp in self._get_declarations():
- kind, realname = name.split(' ', 1)
- method = getattr(self, '_%s_cpy_%s' % (step_name, kind))
- try:
- method(tp, realname, module, **kwds)
- except Exception as e:
- model.attach_exception_info(e, name)
- raise
-
- def _generate_nothing(self, tp, name):
- pass
-
- def _loaded_noop(self, tp, name, module, **kwds):
- pass
-
- # ----------
-
- def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
- extraarg = ''
- if isinstance(tp, model.PrimitiveType):
- if tp.is_integer_type() and tp.name != '_Bool':
- converter = '_cffi_to_c_int'
- extraarg = ', %s' % tp.name
- else:
- converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''),
- tp.name.replace(' ', '_'))
- errvalue = '-1'
- #
- elif isinstance(tp, model.PointerType):
- self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
- tovar, errcode)
- return
- #
- elif isinstance(tp, (model.StructOrUnion, model.EnumType)):
- # a struct (not a struct pointer) as a function argument
- self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
- % (tovar, self._gettypenum(tp), fromvar))
- self._prnt(' %s;' % errcode)
- return
- #
- elif isinstance(tp, model.FunctionPtrType):
- converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
- extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
- errvalue = 'NULL'
- #
- else:
- raise NotImplementedError(tp)
- #
- self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
- self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % (
- tovar, tp.get_c_name(''), errvalue))
- self._prnt(' %s;' % errcode)
-
- def _extra_local_variables(self, tp, localvars, freelines):
- if isinstance(tp, model.PointerType):
- localvars.add('Py_ssize_t datasize')
- localvars.add('struct _cffi_freeme_s *large_args_free = NULL')
- freelines.add('if (large_args_free != NULL)'
- ' _cffi_free_array_arguments(large_args_free);')
-
- def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
- self._prnt(' datasize = _cffi_prepare_pointer_call_argument(')
- self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % (
- self._gettypenum(tp), fromvar, tovar))
- self._prnt(' if (datasize != 0) {')
- self._prnt(' %s = ((size_t)datasize) <= 640 ? '
- 'alloca((size_t)datasize) : NULL;' % (tovar,))
- self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, '
- '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar))
- self._prnt(' datasize, &large_args_free) < 0)')
- self._prnt(' %s;' % errcode)
- self._prnt(' }')
-
- def _convert_expr_from_c(self, tp, var, context):
- if isinstance(tp, model.PrimitiveType):
- if tp.is_integer_type() and tp.name != '_Bool':
- return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
- elif tp.name != 'long double':
- return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
- else:
- return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
- var, self._gettypenum(tp))
- elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
- return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
- var, self._gettypenum(tp))
- elif isinstance(tp, model.ArrayType):
- return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
- var, self._gettypenum(model.PointerType(tp.item)))
- elif isinstance(tp, model.StructOrUnion):
- if tp.fldnames is None:
- raise TypeError("'%s' is used as %s, but is opaque" % (
- tp._get_c_name(), context))
- return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
- var, self._gettypenum(tp))
- elif isinstance(tp, model.EnumType):
- return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
- var, self._gettypenum(tp))
- else:
- raise NotImplementedError(tp)
-
- # ----------
- # typedefs: generates no code so far
-
- _generate_cpy_typedef_collecttype = _generate_nothing
- _generate_cpy_typedef_decl = _generate_nothing
- _generate_cpy_typedef_method = _generate_nothing
- _loading_cpy_typedef = _loaded_noop
- _loaded_cpy_typedef = _loaded_noop
-
- # ----------
- # function declarations
-
- def _generate_cpy_function_collecttype(self, tp, name):
- assert isinstance(tp, model.FunctionPtrType)
- if tp.ellipsis:
- self._do_collect_type(tp)
- else:
- # don't call _do_collect_type(tp) in this common case,
- # otherwise test_autofilled_struct_as_argument fails
- for type in tp.args:
- self._do_collect_type(type)
- self._do_collect_type(tp.result)
-
- def _generate_cpy_function_decl(self, tp, name):
- assert isinstance(tp, model.FunctionPtrType)
- if tp.ellipsis:
- # cannot support vararg functions better than this: check for its
- # exact type (including the fixed arguments), and build it as a
- # constant function pointer (no CPython wrapper)
- self._generate_cpy_const(False, name, tp)
- return
- prnt = self._prnt
- numargs = len(tp.args)
- if numargs == 0:
- argname = 'noarg'
- elif numargs == 1:
- argname = 'arg0'
- else:
- argname = 'args'
- prnt('static PyObject *')
- prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
- prnt('{')
- #
- context = 'argument of %s' % name
- for i, type in enumerate(tp.args):
- prnt(' %s;' % type.get_c_name(' x%d' % i, context))
- #
- localvars = set()
- freelines = set()
- for type in tp.args:
- self._extra_local_variables(type, localvars, freelines)
- for decl in sorted(localvars):
- prnt(' %s;' % (decl,))
- #
- if not isinstance(tp.result, model.VoidType):
- result_code = 'result = '
- context = 'result of %s' % name
- prnt(' %s;' % tp.result.get_c_name(' result', context))
- prnt(' PyObject *pyresult;')
- else:
- result_code = ''
- #
- if len(tp.args) > 1:
- rng = range(len(tp.args))
- for i in rng:
- prnt(' PyObject *arg%d;' % i)
- prnt()
- prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
- 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng])))
- prnt(' return NULL;')
- prnt()
- #
- for i, type in enumerate(tp.args):
- self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
- 'return NULL')
- prnt()
- #
- prnt(' Py_BEGIN_ALLOW_THREADS')
- prnt(' _cffi_restore_errno();')
- prnt(' { %s%s(%s); }' % (
- result_code, name,
- ', '.join(['x%d' % i for i in range(len(tp.args))])))
- prnt(' _cffi_save_errno();')
- prnt(' Py_END_ALLOW_THREADS')
- prnt()
- #
- prnt(' (void)self; /* unused */')
- if numargs == 0:
- prnt(' (void)noarg; /* unused */')
- if result_code:
- prnt(' pyresult = %s;' %
- self._convert_expr_from_c(tp.result, 'result', 'result type'))
- for freeline in freelines:
- prnt(' ' + freeline)
- prnt(' return pyresult;')
- else:
- for freeline in freelines:
- prnt(' ' + freeline)
- prnt(' Py_INCREF(Py_None);')
- prnt(' return Py_None;')
- prnt('}')
- prnt()
-
- def _generate_cpy_function_method(self, tp, name):
- if tp.ellipsis:
- return
- numargs = len(tp.args)
- if numargs == 0:
- meth = 'METH_NOARGS'
- elif numargs == 1:
- meth = 'METH_O'
- else:
- meth = 'METH_VARARGS'
- self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth))
-
- _loading_cpy_function = _loaded_noop
-
- def _loaded_cpy_function(self, tp, name, module, library):
- if tp.ellipsis:
- return
- func = getattr(module, name)
- setattr(library, name, func)
- self._types_of_builtin_functions[func] = tp
-
- # ----------
- # named structs
-
- _generate_cpy_struct_collecttype = _generate_nothing
- def _generate_cpy_struct_decl(self, tp, name):
- assert name == tp.name
- self._generate_struct_or_union_decl(tp, 'struct', name)
- def _generate_cpy_struct_method(self, tp, name):
- self._generate_struct_or_union_method(tp, 'struct', name)
- def _loading_cpy_struct(self, tp, name, module):
- self._loading_struct_or_union(tp, 'struct', name, module)
- def _loaded_cpy_struct(self, tp, name, module, **kwds):
- self._loaded_struct_or_union(tp)
-
- _generate_cpy_union_collecttype = _generate_nothing
- def _generate_cpy_union_decl(self, tp, name):
- assert name == tp.name
- self._generate_struct_or_union_decl(tp, 'union', name)
- def _generate_cpy_union_method(self, tp, name):
- self._generate_struct_or_union_method(tp, 'union', name)
- def _loading_cpy_union(self, tp, name, module):
- self._loading_struct_or_union(tp, 'union', name, module)
- def _loaded_cpy_union(self, tp, name, module, **kwds):
- self._loaded_struct_or_union(tp)
-
- def _generate_struct_or_union_decl(self, tp, prefix, name):
- if tp.fldnames is None:
- return # nothing to do with opaque structs
- checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
- layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
- cname = ('%s %s' % (prefix, name)).strip()
- #
- prnt = self._prnt
- prnt('static void %s(%s *p)' % (checkfuncname, cname))
- prnt('{')
- prnt(' /* only to generate compile-time warnings or errors */')
- prnt(' (void)p;')
- for fname, ftype, fbitsize, fqual in tp.enumfields():
- if (isinstance(ftype, model.PrimitiveType)
- and ftype.is_integer_type()) or fbitsize >= 0:
- # accept all integers, but complain on float or double
- prnt(' (void)((p->%s) << 1);' % fname)
- else:
- # only accept exactly the type declared.
- try:
- prnt(' { %s = &p->%s; (void)tmp; }' % (
- ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
- fname))
- except VerificationError as e:
- prnt(' /* %s */' % str(e)) # cannot verify it, ignore
- prnt('}')
- prnt('static PyObject *')
- prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
- prnt('{')
- prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname)
- prnt(' static Py_ssize_t nums[] = {')
- prnt(' sizeof(%s),' % cname)
- prnt(' offsetof(struct _cffi_aligncheck, y),')
- for fname, ftype, fbitsize, fqual in tp.enumfields():
- if fbitsize >= 0:
- continue # xxx ignore fbitsize for now
- prnt(' offsetof(%s, %s),' % (cname, fname))
- if isinstance(ftype, model.ArrayType) and ftype.length is None:
- prnt(' 0, /* %s */' % ftype._get_c_name())
- else:
- prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
- prnt(' -1')
- prnt(' };')
- prnt(' (void)self; /* unused */')
- prnt(' (void)noarg; /* unused */')
- prnt(' return _cffi_get_struct_layout(nums);')
- prnt(' /* the next line is not executed, but compiled */')
- prnt(' %s(0);' % (checkfuncname,))
- prnt('}')
- prnt()
-
- def _generate_struct_or_union_method(self, tp, prefix, name):
- if tp.fldnames is None:
- return # nothing to do with opaque structs
- layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
- self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname,
- layoutfuncname))
-
- def _loading_struct_or_union(self, tp, prefix, name, module):
- if tp.fldnames is None:
- return # nothing to do with opaque structs
- layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
- #
- function = getattr(module, layoutfuncname)
- layout = function()
- if isinstance(tp, model.StructOrUnion) and tp.partial:
- # use the function()'s sizes and offsets to guide the
- # layout of the struct
- totalsize = layout[0]
- totalalignment = layout[1]
- fieldofs = layout[2::2]
- fieldsize = layout[3::2]
- tp.force_flatten()
- assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
- tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
- else:
- cname = ('%s %s' % (prefix, name)).strip()
- self._struct_pending_verification[tp] = layout, cname
-
- def _loaded_struct_or_union(self, tp):
- if tp.fldnames is None:
- return # nothing to do with opaque structs
- self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered
-
- if tp in self._struct_pending_verification:
- # check that the layout sizes and offsets match the real ones
- def check(realvalue, expectedvalue, msg):
- if realvalue != expectedvalue:
- raise VerificationError(
- "%s (we have %d, but C compiler says %d)"
- % (msg, expectedvalue, realvalue))
- ffi = self.ffi
- BStruct = ffi._get_cached_btype(tp)
- layout, cname = self._struct_pending_verification.pop(tp)
- check(layout[0], ffi.sizeof(BStruct), "wrong total size")
- check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
- i = 2
- for fname, ftype, fbitsize, fqual in tp.enumfields():
- if fbitsize >= 0:
- continue # xxx ignore fbitsize for now
- check(layout[i], ffi.offsetof(BStruct, fname),
- "wrong offset for field %r" % (fname,))
- if layout[i+1] != 0:
- BField = ffi._get_cached_btype(ftype)
- check(layout[i+1], ffi.sizeof(BField),
- "wrong size for field %r" % (fname,))
- i += 2
- assert i == len(layout)
-
- # ----------
- # 'anonymous' declarations. These are produced for anonymous structs
- # or unions; the 'name' is obtained by a typedef.
-
- _generate_cpy_anonymous_collecttype = _generate_nothing
-
- def _generate_cpy_anonymous_decl(self, tp, name):
- if isinstance(tp, model.EnumType):
- self._generate_cpy_enum_decl(tp, name, '')
- else:
- self._generate_struct_or_union_decl(tp, '', name)
-
- def _generate_cpy_anonymous_method(self, tp, name):
- if not isinstance(tp, model.EnumType):
- self._generate_struct_or_union_method(tp, '', name)
-
- def _loading_cpy_anonymous(self, tp, name, module):
- if isinstance(tp, model.EnumType):
- self._loading_cpy_enum(tp, name, module)
- else:
- self._loading_struct_or_union(tp, '', name, module)
-
- def _loaded_cpy_anonymous(self, tp, name, module, **kwds):
- if isinstance(tp, model.EnumType):
- self._loaded_cpy_enum(tp, name, module, **kwds)
- else:
- self._loaded_struct_or_union(tp)
-
- # ----------
- # constants, likely declared with '#define'
-
- def _generate_cpy_const(self, is_int, name, tp=None, category='const',
- vartp=None, delayed=True, size_too=False,
- check_value=None):
- prnt = self._prnt
- funcname = '_cffi_%s_%s' % (category, name)
- prnt('static int %s(PyObject *lib)' % funcname)
- prnt('{')
- prnt(' PyObject *o;')
- prnt(' int res;')
- if not is_int:
- prnt(' %s;' % (vartp or tp).get_c_name(' i', name))
- else:
- assert category == 'const'
- #
- if check_value is not None:
- self._check_int_constant_value(name, check_value)
- #
- if not is_int:
- if category == 'var':
- realexpr = '&' + name
- else:
- realexpr = name
- prnt(' i = (%s);' % (realexpr,))
- prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i',
- 'variable type'),))
- assert delayed
- else:
- prnt(' o = _cffi_from_c_int_const(%s);' % name)
- prnt(' if (o == NULL)')
- prnt(' return -1;')
- if size_too:
- prnt(' {')
- prnt(' PyObject *o1 = o;')
- prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));'
- % (name,))
- prnt(' Py_DECREF(o1);')
- prnt(' if (o == NULL)')
- prnt(' return -1;')
- prnt(' }')
- prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name)
- prnt(' Py_DECREF(o);')
- prnt(' if (res < 0)')
- prnt(' return -1;')
- prnt(' return %s;' % self._chained_list_constants[delayed])
- self._chained_list_constants[delayed] = funcname + '(lib)'
- prnt('}')
- prnt()
-
- def _generate_cpy_constant_collecttype(self, tp, name):
- is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
- if not is_int:
- self._do_collect_type(tp)
-
- def _generate_cpy_constant_decl(self, tp, name):
- is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
- self._generate_cpy_const(is_int, name, tp)
-
- _generate_cpy_constant_method = _generate_nothing
- _loading_cpy_constant = _loaded_noop
- _loaded_cpy_constant = _loaded_noop
-
- # ----------
- # enums
-
- def _check_int_constant_value(self, name, value, err_prefix=''):
- prnt = self._prnt
- if value <= 0:
- prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % (
- name, name, value))
- else:
- prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
- name, name, value))
- prnt(' char buf[64];')
- prnt(' if ((%s) <= 0)' % name)
- prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name)
- prnt(' else')
- prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
- name)
- prnt(' PyErr_Format(_cffi_VerificationError,')
- prnt(' "%s%s has the real value %s, not %s",')
- prnt(' "%s", "%s", buf, "%d");' % (
- err_prefix, name, value))
- prnt(' return -1;')
- prnt(' }')
-
- def _enum_funcname(self, prefix, name):
- # "$enum_$1" => "___D_enum____D_1"
- name = name.replace('$', '___D_')
- return '_cffi_e_%s_%s' % (prefix, name)
-
- def _generate_cpy_enum_decl(self, tp, name, prefix='enum'):
- if tp.partial:
- for enumerator in tp.enumerators:
- self._generate_cpy_const(True, enumerator, delayed=False)
- return
- #
- funcname = self._enum_funcname(prefix, name)
- prnt = self._prnt
- prnt('static int %s(PyObject *lib)' % funcname)
- prnt('{')
- for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
- self._check_int_constant_value(enumerator, enumvalue,
- "enum %s: " % name)
- prnt(' return %s;' % self._chained_list_constants[True])
- self._chained_list_constants[True] = funcname + '(lib)'
- prnt('}')
- prnt()
-
- _generate_cpy_enum_collecttype = _generate_nothing
- _generate_cpy_enum_method = _generate_nothing
-
- def _loading_cpy_enum(self, tp, name, module):
- if tp.partial:
- enumvalues = [getattr(module, enumerator)
- for enumerator in tp.enumerators]
- tp.enumvalues = tuple(enumvalues)
- tp.partial_resolved = True
-
- def _loaded_cpy_enum(self, tp, name, module, library):
- for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
- setattr(library, enumerator, enumvalue)
-
- # ----------
- # macros: for now only for integers
-
- def _generate_cpy_macro_decl(self, tp, name):
- if tp == '...':
- check_value = None
- else:
- check_value = tp # an integer
- self._generate_cpy_const(True, name, check_value=check_value)
-
- _generate_cpy_macro_collecttype = _generate_nothing
- _generate_cpy_macro_method = _generate_nothing
- _loading_cpy_macro = _loaded_noop
- _loaded_cpy_macro = _loaded_noop
-
- # ----------
- # global variables
-
- def _generate_cpy_variable_collecttype(self, tp, name):
- if isinstance(tp, model.ArrayType):
- tp_ptr = model.PointerType(tp.item)
- else:
- tp_ptr = model.PointerType(tp)
- self._do_collect_type(tp_ptr)
-
- def _generate_cpy_variable_decl(self, tp, name):
- if isinstance(tp, model.ArrayType):
- tp_ptr = model.PointerType(tp.item)
- self._generate_cpy_const(False, name, tp, vartp=tp_ptr,
- size_too = tp.length_is_unknown())
- else:
- tp_ptr = model.PointerType(tp)
- self._generate_cpy_const(False, name, tp_ptr, category='var')
-
- _generate_cpy_variable_method = _generate_nothing
- _loading_cpy_variable = _loaded_noop
-
- def _loaded_cpy_variable(self, tp, name, module, library):
- value = getattr(library, name)
- if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the
- # sense that "a=..." is forbidden
- if tp.length_is_unknown():
- assert isinstance(value, tuple)
- (value, size) = value
- BItemType = self.ffi._get_cached_btype(tp.item)
- length, rest = divmod(size, self.ffi.sizeof(BItemType))
- if rest != 0:
- raise VerificationError(
- "bad size: %r does not seem to be an array of %s" %
- (name, tp.item))
- tp = tp.resolve_length(length)
- # 'value' is a <cdata 'type *'> which we have to replace with
- # a <cdata 'type[N]'> if the N is actually known
- if tp.length is not None:
- BArray = self.ffi._get_cached_btype(tp)
- value = self.ffi.cast(BArray, value)
- setattr(library, name, value)
- return
- # remove ptr=<cdata 'int *'> from the library instance, and replace
- # it by a property on the class, which reads/writes into ptr[0].
- ptr = value
- delattr(library, name)
- def getter(library):
- return ptr[0]
- def setter(library, value):
- ptr[0] = value
- setattr(type(library), name, property(getter, setter))
- type(library)._cffi_dir.append(name)
-
- # ----------
-
- def _generate_setup_custom(self):
- prnt = self._prnt
- prnt('static int _cffi_setup_custom(PyObject *lib)')
- prnt('{')
- prnt(' return %s;' % self._chained_list_constants[True])
- prnt('}')
-
-cffimod_header = r'''
-#include <Python.h>
-#include <stddef.h>
-
-/* this block of #ifs should be kept exactly identical between
- c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
- and cffi/_cffi_include.h */
-#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 */
-# ifndef __cplusplus
- typedef unsigned char _Bool;
-# endif
-# endif
-#else
-# include <stdint.h>
-# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
-# include <alloca.h>
-# endif
-#endif
-
-#if PY_MAJOR_VERSION < 3
-# undef PyCapsule_CheckExact
-# undef PyCapsule_GetPointer
-# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))
-# define PyCapsule_GetPointer(capsule, name) \
- (PyCObject_AsVoidPtr(capsule))
-#endif
-
-#if PY_MAJOR_VERSION >= 3
-# define PyInt_FromLong PyLong_FromLong
-#endif
-
-#define _cffi_from_c_double PyFloat_FromDouble
-#define _cffi_from_c_float PyFloat_FromDouble
-#define _cffi_from_c_long PyInt_FromLong
-#define _cffi_from_c_ulong PyLong_FromUnsignedLong
-#define _cffi_from_c_longlong PyLong_FromLongLong
-#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
-#define _cffi_from_c__Bool PyBool_FromLong
-
-#define _cffi_to_c_double PyFloat_AsDouble
-#define _cffi_to_c_float PyFloat_AsDouble
-
-#define _cffi_from_c_int_const(x) \
- (((x) > 0) ? \
- ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \
- PyInt_FromLong((long)(x)) : \
- PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \
- ((long long)(x) >= (long long)LONG_MIN) ? \
- PyInt_FromLong((long)(x)) : \
- PyLong_FromLongLong((long long)(x)))
-
-#define _cffi_from_c_int(x, type) \
- (((type)-1) > 0 ? /* unsigned */ \
- (sizeof(type) < sizeof(long) ? \
- PyInt_FromLong((long)x) : \
- sizeof(type) == sizeof(long) ? \
- PyLong_FromUnsignedLong((unsigned long)x) : \
- PyLong_FromUnsignedLongLong((unsigned long long)x)) : \
- (sizeof(type) <= sizeof(long) ? \
- PyInt_FromLong((long)x) : \
- PyLong_FromLongLong((long long)x)))
-
-#define _cffi_to_c_int(o, type) \
- ((type)( \
- sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
- : (type)_cffi_to_c_i8(o)) : \
- sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \
- : (type)_cffi_to_c_i16(o)) : \
- sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \
- : (type)_cffi_to_c_i32(o)) : \
- sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \
- : (type)_cffi_to_c_i64(o)) : \
- (Py_FatalError("unsupported size for type " #type), (type)0)))
-
-#define _cffi_to_c_i8 \
- ((int(*)(PyObject *))_cffi_exports[1])
-#define _cffi_to_c_u8 \
- ((int(*)(PyObject *))_cffi_exports[2])
-#define _cffi_to_c_i16 \
- ((int(*)(PyObject *))_cffi_exports[3])
-#define _cffi_to_c_u16 \
- ((int(*)(PyObject *))_cffi_exports[4])
-#define _cffi_to_c_i32 \
- ((int(*)(PyObject *))_cffi_exports[5])
-#define _cffi_to_c_u32 \
- ((unsigned int(*)(PyObject *))_cffi_exports[6])
-#define _cffi_to_c_i64 \
- ((long long(*)(PyObject *))_cffi_exports[7])
-#define _cffi_to_c_u64 \
- ((unsigned long long(*)(PyObject *))_cffi_exports[8])
-#define _cffi_to_c_char \
- ((int(*)(PyObject *))_cffi_exports[9])
-#define _cffi_from_c_pointer \
- ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
-#define _cffi_to_c_pointer \
- ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
-#define _cffi_get_struct_layout \
- ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12])
-#define _cffi_restore_errno \
- ((void(*)(void))_cffi_exports[13])
-#define _cffi_save_errno \
- ((void(*)(void))_cffi_exports[14])
-#define _cffi_from_c_char \
- ((PyObject *(*)(char))_cffi_exports[15])
-#define _cffi_from_c_deref \
- ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16])
-#define _cffi_to_c \
- ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17])
-#define _cffi_from_c_struct \
- ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18])
-#define _cffi_to_c_wchar_t \
- ((wchar_t(*)(PyObject *))_cffi_exports[19])
-#define _cffi_from_c_wchar_t \
- ((PyObject *(*)(wchar_t))_cffi_exports[20])
-#define _cffi_to_c_long_double \
- ((long double(*)(PyObject *))_cffi_exports[21])
-#define _cffi_to_c__Bool \
- ((_Bool(*)(PyObject *))_cffi_exports[22])
-#define _cffi_prepare_pointer_call_argument \
- ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23])
-#define _cffi_convert_array_from_object \
- ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24])
-#define _CFFI_NUM_EXPORTS 25
-
-typedef struct _ctypedescr CTypeDescrObject;
-
-static void *_cffi_exports[_CFFI_NUM_EXPORTS];
-static PyObject *_cffi_types, *_cffi_VerificationError;
-
-static int _cffi_setup_custom(PyObject *lib); /* forward */
-
-static PyObject *_cffi_setup(PyObject *self, PyObject *args)
-{
- PyObject *library;
- int was_alive = (_cffi_types != NULL);
- (void)self; /* unused */
- if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError,
- &library))
- return NULL;
- Py_INCREF(_cffi_types);
- Py_INCREF(_cffi_VerificationError);
- if (_cffi_setup_custom(library) < 0)
- return NULL;
- return PyBool_FromLong(was_alive);
-}
-
-union _cffi_union_alignment_u {
- 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;
- long double m_longdouble;
-};
-
-struct _cffi_freeme_s {
- struct _cffi_freeme_s *next;
- union _cffi_union_alignment_u alignment;
-};
-
-#ifdef __GNUC__
- __attribute__((unused))
-#endif
-static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg,
- char **output_data, Py_ssize_t datasize,
- struct _cffi_freeme_s **freeme)
-{
- char *p;
- if (datasize < 0)
- return -1;
-
- p = *output_data;
- if (p == NULL) {
- struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc(
- offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize);
- if (fp == NULL)
- return -1;
- fp->next = *freeme;
- *freeme = fp;
- p = *output_data = (char *)&fp->alignment;
- }
- memset((void *)p, 0, (size_t)datasize);
- return _cffi_convert_array_from_object(p, ctptr, arg);
-}
-
-#ifdef __GNUC__
- __attribute__((unused))
-#endif
-static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme)
-{
- do {
- void *p = (void *)freeme;
- freeme = freeme->next;
- PyObject_Free(p);
- } while (freeme != NULL);
-}
-
-static int _cffi_init(void)
-{
- PyObject *module, *c_api_object = NULL;
-
- module = PyImport_ImportModule("_cffi_backend");
- if (module == NULL)
- goto failure;
-
- c_api_object = PyObject_GetAttrString(module, "_C_API");
- if (c_api_object == NULL)
- goto failure;
- if (!PyCapsule_CheckExact(c_api_object)) {
- PyErr_SetNone(PyExc_ImportError);
- goto failure;
- }
- memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"),
- _CFFI_NUM_EXPORTS * sizeof(void *));
-
- Py_DECREF(module);
- Py_DECREF(c_api_object);
- return 0;
-
- failure:
- Py_XDECREF(module);
- Py_XDECREF(c_api_object);
- return -1;
-}
-
-#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))
-
-/**********/
-'''
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
deleted file mode 100644
index 2642152..0000000
--- a/cffi/vengine_gen.py
+++ /dev/null
@@ -1,675 +0,0 @@
-#
-# DEPRECATED: implementation for ffi.verify()
-#
-import sys, os
-import types
-
-from . import model
-from .error import VerificationError
-
-
-class VGenericEngine(object):
- _class_key = 'g'
- _gen_python_module = False
-
- def __init__(self, verifier):
- self.verifier = verifier
- self.ffi = verifier.ffi
- self.export_symbols = []
- self._struct_pending_verification = {}
-
- def patch_extension_kwds(self, kwds):
- # add 'export_symbols' to the dictionary. Note that we add the
- # list before filling it. When we fill it, it will thus also show
- # up in kwds['export_symbols'].
- kwds.setdefault('export_symbols', self.export_symbols)
-
- def find_module(self, module_name, path, so_suffixes):
- for so_suffix in so_suffixes:
- basename = module_name + so_suffix
- if path is None:
- path = sys.path
- for dirname in path:
- filename = os.path.join(dirname, basename)
- if os.path.isfile(filename):
- return filename
-
- def collect_types(self):
- pass # not needed in the generic engine
-
- def _prnt(self, what=''):
- self._f.write(what + '\n')
-
- def write_source_to_f(self):
- prnt = self._prnt
- # first paste some standard set of lines that are mostly '#include'
- prnt(cffimod_header)
- # then paste the C source given by the user, verbatim.
- prnt(self.verifier.preamble)
- #
- # call generate_gen_xxx_decl(), for every xxx found from
- # ffi._parser._declarations. This generates all the functions.
- self._generate('decl')
- #
- # on Windows, distutils insists on putting init_cffi_xyz in
- # 'export_symbols', so instead of fighting it, just give up and
- # give it one
- if sys.platform == 'win32':
- if sys.version_info >= (3,):
- prefix = 'PyInit_'
- else:
- prefix = 'init'
- modname = self.verifier.get_module_name()
- prnt("void %s%s(void) { }\n" % (prefix, modname))
-
- def load_library(self, flags=0):
- # import it with the CFFI backend
- backend = self.ffi._backend
- # needs to make a path that contains '/', on Posix
- filename = os.path.join(os.curdir, self.verifier.modulefilename)
- module = backend.load_library(filename, flags)
- #
- # call loading_gen_struct() to get the struct layout inferred by
- # the C compiler
- self._load(module, 'loading')
-
- # build the FFILibrary class and instance, this is a module subclass
- # because modules are expected to have usually-constant-attributes and
- # in PyPy this means the JIT is able to treat attributes as constant,
- # which we want.
- class FFILibrary(types.ModuleType):
- _cffi_generic_module = module
- _cffi_ffi = self.ffi
- _cffi_dir = []
- def __dir__(self):
- return FFILibrary._cffi_dir
- library = FFILibrary("")
- #
- # finally, call the loaded_gen_xxx() functions. This will set
- # up the 'library' object.
- self._load(module, 'loaded', library=library)
- return library
-
- def _get_declarations(self):
- lst = [(key, tp) for (key, (tp, qual)) in
- self.ffi._parser._declarations.items()]
- lst.sort()
- return lst
-
- def _generate(self, step_name):
- for name, tp in self._get_declarations():
- kind, realname = name.split(' ', 1)
- try:
- method = getattr(self, '_generate_gen_%s_%s' % (kind,
- step_name))
- except AttributeError:
- raise VerificationError(
- "not implemented in verify(): %r" % name)
- try:
- method(tp, realname)
- except Exception as e:
- model.attach_exception_info(e, name)
- raise
-
- def _load(self, module, step_name, **kwds):
- for name, tp in self._get_declarations():
- kind, realname = name.split(' ', 1)
- method = getattr(self, '_%s_gen_%s' % (step_name, kind))
- try:
- method(tp, realname, module, **kwds)
- except Exception as e:
- model.attach_exception_info(e, name)
- raise
-
- def _generate_nothing(self, tp, name):
- pass
-
- def _loaded_noop(self, tp, name, module, **kwds):
- pass
-
- # ----------
- # typedefs: generates no code so far
-
- _generate_gen_typedef_decl = _generate_nothing
- _loading_gen_typedef = _loaded_noop
- _loaded_gen_typedef = _loaded_noop
-
- # ----------
- # function declarations
-
- def _generate_gen_function_decl(self, tp, name):
- assert isinstance(tp, model.FunctionPtrType)
- if tp.ellipsis:
- # cannot support vararg functions better than this: check for its
- # exact type (including the fixed arguments), and build it as a
- # constant function pointer (no _cffi_f_%s wrapper)
- self._generate_gen_const(False, name, tp)
- return
- prnt = self._prnt
- numargs = len(tp.args)
- argnames = []
- for i, type in enumerate(tp.args):
- indirection = ''
- if isinstance(type, model.StructOrUnion):
- indirection = '*'
- argnames.append('%sx%d' % (indirection, i))
- context = 'argument of %s' % name
- arglist = [type.get_c_name(' %s' % arg, context)
- for type, arg in zip(tp.args, argnames)]
- tpresult = tp.result
- if isinstance(tpresult, model.StructOrUnion):
- arglist.insert(0, tpresult.get_c_name(' *r', context))
- tpresult = model.void_type
- arglist = ', '.join(arglist) or 'void'
- wrappername = '_cffi_f_%s' % name
- self.export_symbols.append(wrappername)
- if tp.abi:
- abi = tp.abi + ' '
- else:
- abi = ''
- funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist)
- context = 'result of %s' % name
- prnt(tpresult.get_c_name(funcdecl, context))
- prnt('{')
- #
- if isinstance(tp.result, model.StructOrUnion):
- result_code = '*r = '
- elif not isinstance(tp.result, model.VoidType):
- result_code = 'return '
- else:
- result_code = ''
- prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames)))
- prnt('}')
- prnt()
-
- _loading_gen_function = _loaded_noop
-
- def _loaded_gen_function(self, tp, name, module, library):
- assert isinstance(tp, model.FunctionPtrType)
- if tp.ellipsis:
- newfunction = self._load_constant(False, tp, name, module)
- else:
- indirections = []
- base_tp = tp
- if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args)
- or isinstance(tp.result, model.StructOrUnion)):
- indirect_args = []
- for i, typ in enumerate(tp.args):
- if isinstance(typ, model.StructOrUnion):
- typ = model.PointerType(typ)
- indirections.append((i, typ))
- indirect_args.append(typ)
- indirect_result = tp.result
- if isinstance(indirect_result, model.StructOrUnion):
- if indirect_result.fldtypes is None:
- raise TypeError("'%s' is used as result type, "
- "but is opaque" % (
- indirect_result._get_c_name(),))
- indirect_result = model.PointerType(indirect_result)
- indirect_args.insert(0, indirect_result)
- indirections.insert(0, ("result", indirect_result))
- indirect_result = model.void_type
- tp = model.FunctionPtrType(tuple(indirect_args),
- indirect_result, tp.ellipsis)
- BFunc = self.ffi._get_cached_btype(tp)
- wrappername = '_cffi_f_%s' % name
- newfunction = module.load_function(BFunc, wrappername)
- for i, typ in indirections:
- newfunction = self._make_struct_wrapper(newfunction, i, typ,
- base_tp)
- setattr(library, name, newfunction)
- type(library)._cffi_dir.append(name)
-
- def _make_struct_wrapper(self, oldfunc, i, tp, base_tp):
- backend = self.ffi._backend
- BType = self.ffi._get_cached_btype(tp)
- if i == "result":
- ffi = self.ffi
- def newfunc(*args):
- res = ffi.new(BType)
- oldfunc(res, *args)
- return res[0]
- else:
- def newfunc(*args):
- args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]
- return oldfunc(*args)
- newfunc._cffi_base_type = base_tp
- return newfunc
-
- # ----------
- # named structs
-
- def _generate_gen_struct_decl(self, tp, name):
- assert name == tp.name
- self._generate_struct_or_union_decl(tp, 'struct', name)
-
- def _loading_gen_struct(self, tp, name, module):
- self._loading_struct_or_union(tp, 'struct', name, module)
-
- def _loaded_gen_struct(self, tp, name, module, **kwds):
- self._loaded_struct_or_union(tp)
-
- def _generate_gen_union_decl(self, tp, name):
- assert name == tp.name
- self._generate_struct_or_union_decl(tp, 'union', name)
-
- def _loading_gen_union(self, tp, name, module):
- self._loading_struct_or_union(tp, 'union', name, module)
-
- def _loaded_gen_union(self, tp, name, module, **kwds):
- self._loaded_struct_or_union(tp)
-
- def _generate_struct_or_union_decl(self, tp, prefix, name):
- if tp.fldnames is None:
- return # nothing to do with opaque structs
- checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
- layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
- cname = ('%s %s' % (prefix, name)).strip()
- #
- prnt = self._prnt
- prnt('static void %s(%s *p)' % (checkfuncname, cname))
- prnt('{')
- prnt(' /* only to generate compile-time warnings or errors */')
- prnt(' (void)p;')
- for fname, ftype, fbitsize, fqual in tp.enumfields():
- if (isinstance(ftype, model.PrimitiveType)
- and ftype.is_integer_type()) or fbitsize >= 0:
- # accept all integers, but complain on float or double
- prnt(' (void)((p->%s) << 1);' % fname)
- else:
- # only accept exactly the type declared.
- try:
- prnt(' { %s = &p->%s; (void)tmp; }' % (
- ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
- fname))
- except VerificationError as e:
- prnt(' /* %s */' % str(e)) # cannot verify it, ignore
- prnt('}')
- self.export_symbols.append(layoutfuncname)
- prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,))
- prnt('{')
- prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname)
- prnt(' static intptr_t nums[] = {')
- prnt(' sizeof(%s),' % cname)
- prnt(' offsetof(struct _cffi_aligncheck, y),')
- for fname, ftype, fbitsize, fqual in tp.enumfields():
- if fbitsize >= 0:
- continue # xxx ignore fbitsize for now
- prnt(' offsetof(%s, %s),' % (cname, fname))
- if isinstance(ftype, model.ArrayType) and ftype.length is None:
- prnt(' 0, /* %s */' % ftype._get_c_name())
- else:
- prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
- prnt(' -1')
- prnt(' };')
- prnt(' return nums[i];')
- prnt(' /* the next line is not executed, but compiled */')
- prnt(' %s(0);' % (checkfuncname,))
- prnt('}')
- prnt()
-
- def _loading_struct_or_union(self, tp, prefix, name, module):
- if tp.fldnames is None:
- return # nothing to do with opaque structs
- layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
- #
- BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0]
- function = module.load_function(BFunc, layoutfuncname)
- layout = []
- num = 0
- while True:
- x = function(num)
- if x < 0: break
- layout.append(x)
- num += 1
- if isinstance(tp, model.StructOrUnion) and tp.partial:
- # use the function()'s sizes and offsets to guide the
- # layout of the struct
- totalsize = layout[0]
- totalalignment = layout[1]
- fieldofs = layout[2::2]
- fieldsize = layout[3::2]
- tp.force_flatten()
- assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
- tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
- else:
- cname = ('%s %s' % (prefix, name)).strip()
- self._struct_pending_verification[tp] = layout, cname
-
- def _loaded_struct_or_union(self, tp):
- if tp.fldnames is None:
- return # nothing to do with opaque structs
- self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered
-
- if tp in self._struct_pending_verification:
- # check that the layout sizes and offsets match the real ones
- def check(realvalue, expectedvalue, msg):
- if realvalue != expectedvalue:
- raise VerificationError(
- "%s (we have %d, but C compiler says %d)"
- % (msg, expectedvalue, realvalue))
- ffi = self.ffi
- BStruct = ffi._get_cached_btype(tp)
- layout, cname = self._struct_pending_verification.pop(tp)
- check(layout[0], ffi.sizeof(BStruct), "wrong total size")
- check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
- i = 2
- for fname, ftype, fbitsize, fqual in tp.enumfields():
- if fbitsize >= 0:
- continue # xxx ignore fbitsize for now
- check(layout[i], ffi.offsetof(BStruct, fname),
- "wrong offset for field %r" % (fname,))
- if layout[i+1] != 0:
- BField = ffi._get_cached_btype(ftype)
- check(layout[i+1], ffi.sizeof(BField),
- "wrong size for field %r" % (fname,))
- i += 2
- assert i == len(layout)
-
- # ----------
- # 'anonymous' declarations. These are produced for anonymous structs
- # or unions; the 'name' is obtained by a typedef.
-
- def _generate_gen_anonymous_decl(self, tp, name):
- if isinstance(tp, model.EnumType):
- self._generate_gen_enum_decl(tp, name, '')
- else:
- self._generate_struct_or_union_decl(tp, '', name)
-
- def _loading_gen_anonymous(self, tp, name, module):
- if isinstance(tp, model.EnumType):
- self._loading_gen_enum(tp, name, module, '')
- else:
- self._loading_struct_or_union(tp, '', name, module)
-
- def _loaded_gen_anonymous(self, tp, name, module, **kwds):
- if isinstance(tp, model.EnumType):
- self._loaded_gen_enum(tp, name, module, **kwds)
- else:
- self._loaded_struct_or_union(tp)
-
- # ----------
- # constants, likely declared with '#define'
-
- def _generate_gen_const(self, is_int, name, tp=None, category='const',
- check_value=None):
- prnt = self._prnt
- funcname = '_cffi_%s_%s' % (category, name)
- self.export_symbols.append(funcname)
- if check_value is not None:
- assert is_int
- assert category == 'const'
- prnt('int %s(char *out_error)' % funcname)
- prnt('{')
- self._check_int_constant_value(name, check_value)
- prnt(' return 0;')
- prnt('}')
- elif is_int:
- assert category == 'const'
- prnt('int %s(long long *out_value)' % funcname)
- prnt('{')
- prnt(' *out_value = (long long)(%s);' % (name,))
- prnt(' return (%s) <= 0;' % (name,))
- prnt('}')
- else:
- assert tp is not None
- assert check_value is None
- if category == 'var':
- ampersand = '&'
- else:
- ampersand = ''
- extra = ''
- if category == 'const' and isinstance(tp, model.StructOrUnion):
- extra = 'const *'
- ampersand = '&'
- prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name))
- prnt('{')
- prnt(' return (%s%s);' % (ampersand, name))
- prnt('}')
- prnt()
-
- def _generate_gen_constant_decl(self, tp, name):
- is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
- self._generate_gen_const(is_int, name, tp)
-
- _loading_gen_constant = _loaded_noop
-
- def _load_constant(self, is_int, tp, name, module, check_value=None):
- funcname = '_cffi_const_%s' % name
- if check_value is not None:
- assert is_int
- self._load_known_int_constant(module, funcname)
- value = check_value
- elif is_int:
- BType = self.ffi._typeof_locked("long long*")[0]
- BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0]
- function = module.load_function(BFunc, funcname)
- p = self.ffi.new(BType)
- negative = function(p)
- value = int(p[0])
- if value < 0 and not negative:
- BLongLong = self.ffi._typeof_locked("long long")[0]
- value += (1 << (8*self.ffi.sizeof(BLongLong)))
- else:
- assert check_value is None
- fntypeextra = '(*)(void)'
- if isinstance(tp, model.StructOrUnion):
- fntypeextra = '*' + fntypeextra
- BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0]
- function = module.load_function(BFunc, funcname)
- value = function()
- if isinstance(tp, model.StructOrUnion):
- value = value[0]
- return value
-
- def _loaded_gen_constant(self, tp, name, module, library):
- is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
- value = self._load_constant(is_int, tp, name, module)
- setattr(library, name, value)
- type(library)._cffi_dir.append(name)
-
- # ----------
- # enums
-
- def _check_int_constant_value(self, name, value):
- prnt = self._prnt
- if value <= 0:
- prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % (
- name, name, value))
- else:
- prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
- name, name, value))
- prnt(' char buf[64];')
- prnt(' if ((%s) <= 0)' % name)
- prnt(' sprintf(buf, "%%ld", (long)(%s));' % name)
- prnt(' else')
- prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' %
- name)
- prnt(' sprintf(out_error, "%s has the real value %s, not %s",')
- prnt(' "%s", buf, "%d");' % (name[:100], value))
- prnt(' return -1;')
- prnt(' }')
-
- def _load_known_int_constant(self, module, funcname):
- BType = self.ffi._typeof_locked("char[]")[0]
- BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]
- function = module.load_function(BFunc, funcname)
- p = self.ffi.new(BType, 256)
- if function(p) < 0:
- error = self.ffi.string(p)
- if sys.version_info >= (3,):
- error = str(error, 'utf-8')
- raise VerificationError(error)
-
- def _enum_funcname(self, prefix, name):
- # "$enum_$1" => "___D_enum____D_1"
- name = name.replace('$', '___D_')
- return '_cffi_e_%s_%s' % (prefix, name)
-
- def _generate_gen_enum_decl(self, tp, name, prefix='enum'):
- if tp.partial:
- for enumerator in tp.enumerators:
- self._generate_gen_const(True, enumerator)
- return
- #
- funcname = self._enum_funcname(prefix, name)
- self.export_symbols.append(funcname)
- prnt = self._prnt
- prnt('int %s(char *out_error)' % funcname)
- prnt('{')
- for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
- self._check_int_constant_value(enumerator, enumvalue)
- prnt(' return 0;')
- prnt('}')
- prnt()
-
- def _loading_gen_enum(self, tp, name, module, prefix='enum'):
- if tp.partial:
- enumvalues = [self._load_constant(True, tp, enumerator, module)
- for enumerator in tp.enumerators]
- tp.enumvalues = tuple(enumvalues)
- tp.partial_resolved = True
- else:
- funcname = self._enum_funcname(prefix, name)
- self._load_known_int_constant(module, funcname)
-
- def _loaded_gen_enum(self, tp, name, module, library):
- for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
- setattr(library, enumerator, enumvalue)
- type(library)._cffi_dir.append(enumerator)
-
- # ----------
- # macros: for now only for integers
-
- def _generate_gen_macro_decl(self, tp, name):
- if tp == '...':
- check_value = None
- else:
- check_value = tp # an integer
- self._generate_gen_const(True, name, check_value=check_value)
-
- _loading_gen_macro = _loaded_noop
-
- def _loaded_gen_macro(self, tp, name, module, library):
- if tp == '...':
- check_value = None
- else:
- check_value = tp # an integer
- value = self._load_constant(True, tp, name, module,
- check_value=check_value)
- setattr(library, name, value)
- type(library)._cffi_dir.append(name)
-
- # ----------
- # global variables
-
- def _generate_gen_variable_decl(self, tp, name):
- if isinstance(tp, model.ArrayType):
- if tp.length_is_unknown():
- prnt = self._prnt
- funcname = '_cffi_sizeof_%s' % (name,)
- self.export_symbols.append(funcname)
- prnt("size_t %s(void)" % funcname)
- prnt("{")
- prnt(" return sizeof(%s);" % (name,))
- prnt("}")
- tp_ptr = model.PointerType(tp.item)
- self._generate_gen_const(False, name, tp_ptr)
- else:
- tp_ptr = model.PointerType(tp)
- self._generate_gen_const(False, name, tp_ptr, category='var')
-
- _loading_gen_variable = _loaded_noop
-
- def _loaded_gen_variable(self, tp, name, module, library):
- if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the
- # sense that "a=..." is forbidden
- if tp.length_is_unknown():
- funcname = '_cffi_sizeof_%s' % (name,)
- BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0]
- function = module.load_function(BFunc, funcname)
- size = function()
- BItemType = self.ffi._get_cached_btype(tp.item)
- length, rest = divmod(size, self.ffi.sizeof(BItemType))
- if rest != 0:
- raise VerificationError(
- "bad size: %r does not seem to be an array of %s" %
- (name, tp.item))
- tp = tp.resolve_length(length)
- tp_ptr = model.PointerType(tp.item)
- value = self._load_constant(False, tp_ptr, name, module)
- # 'value' is a <cdata 'type *'> which we have to replace with
- # a <cdata 'type[N]'> if the N is actually known
- if tp.length is not None:
- BArray = self.ffi._get_cached_btype(tp)
- value = self.ffi.cast(BArray, value)
- setattr(library, name, value)
- type(library)._cffi_dir.append(name)
- return
- # remove ptr=<cdata 'int *'> from the library instance, and replace
- # it by a property on the class, which reads/writes into ptr[0].
- funcname = '_cffi_var_%s' % name
- BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0]
- function = module.load_function(BFunc, funcname)
- ptr = function()
- def getter(library):
- return ptr[0]
- def setter(library, value):
- ptr[0] = value
- setattr(type(library), name, property(getter, setter))
- type(library)._cffi_dir.append(name)
-
-cffimod_header = r'''
-#include <stdio.h>
-#include <stddef.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <sys/types.h> /* XXX for ssize_t on some platforms */
-
-/* this block of #ifs should be kept exactly identical between
- c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
- and cffi/_cffi_include.h */
-#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 */
-# ifndef __cplusplus
- typedef unsigned char _Bool;
-# endif
-# endif
-#else
-# include <stdint.h>
-# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
-# include <alloca.h>
-# endif
-#endif
-'''
diff --git a/cffi/verifier.py b/cffi/verifier.py
deleted file mode 100644
index a500c78..0000000
--- a/cffi/verifier.py
+++ /dev/null
@@ -1,307 +0,0 @@
-#
-# DEPRECATED: implementation for ffi.verify()
-#
-import sys, os, binascii, shutil, io
-from . import __version_verifier_modules__
-from . import ffiplatform
-from .error import VerificationError
-
-if sys.version_info >= (3, 3):
- import importlib.machinery
- def _extension_suffixes():
- return importlib.machinery.EXTENSION_SUFFIXES[:]
-else:
- import imp
- def _extension_suffixes():
- return [suffix for suffix, _, type in imp.get_suffixes()
- if type == imp.C_EXTENSION]
-
-
-if sys.version_info >= (3,):
- NativeIO = io.StringIO
-else:
- class NativeIO(io.BytesIO):
- def write(self, s):
- if isinstance(s, unicode):
- s = s.encode('ascii')
- super(NativeIO, self).write(s)
-
-
-class Verifier(object):
-
- def __init__(self, ffi, preamble, tmpdir=None, modulename=None,
- ext_package=None, tag='', force_generic_engine=False,
- source_extension='.c', flags=None, relative_to=None, **kwds):
- if ffi._parser._uses_new_feature:
- raise VerificationError(
- "feature not supported with ffi.verify(), but only "
- "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,))
- self.ffi = ffi
- self.preamble = preamble
- if not modulename:
- flattened_kwds = ffiplatform.flatten(kwds)
- vengine_class = _locate_engine_class(ffi, force_generic_engine)
- self._vengine = vengine_class(self)
- self._vengine.patch_extension_kwds(kwds)
- self.flags = flags
- self.kwds = self.make_relative_to(kwds, relative_to)
- #
- if modulename:
- if tag:
- raise TypeError("can't specify both 'modulename' and 'tag'")
- else:
- key = '\x00'.join(['%d.%d' % sys.version_info[:2],
- __version_verifier_modules__,
- preamble, flattened_kwds] +
- ffi._cdefsources)
- if sys.version_info >= (3,):
- key = key.encode('utf-8')
- k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff)
- k1 = k1.lstrip('0x').rstrip('L')
- k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff)
- k2 = k2.lstrip('0').rstrip('L')
- modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key,
- k1, k2)
- suffix = _get_so_suffixes()[0]
- self.tmpdir = tmpdir or _caller_dir_pycache()
- self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension)
- self.modulefilename = os.path.join(self.tmpdir, modulename + suffix)
- self.ext_package = ext_package
- self._has_source = False
- self._has_module = False
-
- def write_source(self, file=None):
- """Write the C source code. It is produced in 'self.sourcefilename',
- which can be tweaked beforehand."""
- with self.ffi._lock:
- if self._has_source and file is None:
- raise VerificationError(
- "source code already written")
- self._write_source(file)
-
- def compile_module(self):
- """Write the C source code (if not done already) and compile it.
- This produces a dynamic link library in 'self.modulefilename'."""
- with self.ffi._lock:
- if self._has_module:
- raise VerificationError("module already compiled")
- if not self._has_source:
- self._write_source()
- self._compile_module()
-
- def load_library(self):
- """Get a C module from this Verifier instance.
- Returns an instance of a FFILibrary class that behaves like the
- objects returned by ffi.dlopen(), but that delegates all
- operations to the C module. If necessary, the C code is written
- and compiled first.
- """
- with self.ffi._lock:
- if not self._has_module:
- self._locate_module()
- if not self._has_module:
- if not self._has_source:
- self._write_source()
- self._compile_module()
- return self._load_library()
-
- def get_module_name(self):
- basename = os.path.basename(self.modulefilename)
- # kill both the .so extension and the other .'s, as introduced
- # by Python 3: 'basename.cpython-33m.so'
- basename = basename.split('.', 1)[0]
- # and the _d added in Python 2 debug builds --- but try to be
- # conservative and not kill a legitimate _d
- if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'):
- basename = basename[:-2]
- return basename
-
- def get_extension(self):
- ffiplatform._hack_at_distutils() # backward compatibility hack
- if not self._has_source:
- with self.ffi._lock:
- if not self._has_source:
- self._write_source()
- sourcename = ffiplatform.maybe_relative_path(self.sourcefilename)
- modname = self.get_module_name()
- return ffiplatform.get_extension(sourcename, modname, **self.kwds)
-
- def generates_python_module(self):
- return self._vengine._gen_python_module
-
- def make_relative_to(self, kwds, relative_to):
- if relative_to and os.path.dirname(relative_to):
- dirname = os.path.dirname(relative_to)
- kwds = kwds.copy()
- for key in ffiplatform.LIST_OF_FILE_NAMES:
- if key in kwds:
- lst = kwds[key]
- if not isinstance(lst, (list, tuple)):
- raise TypeError("keyword '%s' should be a list or tuple"
- % (key,))
- lst = [os.path.join(dirname, fn) for fn in lst]
- kwds[key] = lst
- return kwds
-
- # ----------
-
- def _locate_module(self):
- if not os.path.isfile(self.modulefilename):
- if self.ext_package:
- try:
- pkg = __import__(self.ext_package, None, None, ['__doc__'])
- except ImportError:
- return # cannot import the package itself, give up
- # (e.g. it might be called differently before installation)
- path = pkg.__path__
- else:
- path = None
- filename = self._vengine.find_module(self.get_module_name(), path,
- _get_so_suffixes())
- if filename is None:
- return
- self.modulefilename = filename
- self._vengine.collect_types()
- self._has_module = True
-
- def _write_source_to(self, file):
- self._vengine._f = file
- try:
- self._vengine.write_source_to_f()
- finally:
- del self._vengine._f
-
- def _write_source(self, file=None):
- if file is not None:
- self._write_source_to(file)
- else:
- # Write our source file to an in memory file.
- f = NativeIO()
- self._write_source_to(f)
- source_data = f.getvalue()
-
- # Determine if this matches the current file
- if os.path.exists(self.sourcefilename):
- with open(self.sourcefilename, "r") as fp:
- needs_written = not (fp.read() == source_data)
- else:
- needs_written = True
-
- # Actually write the file out if it doesn't match
- if needs_written:
- _ensure_dir(self.sourcefilename)
- with open(self.sourcefilename, "w") as fp:
- fp.write(source_data)
-
- # Set this flag
- self._has_source = True
-
- def _compile_module(self):
- # compile this C source
- tmpdir = os.path.dirname(self.sourcefilename)
- outputfilename = ffiplatform.compile(tmpdir, self.get_extension())
- try:
- same = ffiplatform.samefile(outputfilename, self.modulefilename)
- except OSError:
- same = False
- if not same:
- _ensure_dir(self.modulefilename)
- shutil.move(outputfilename, self.modulefilename)
- self._has_module = True
-
- def _load_library(self):
- assert self._has_module
- if self.flags is not None:
- return self._vengine.load_library(self.flags)
- else:
- return self._vengine.load_library()
-
-# ____________________________________________________________
-
-_FORCE_GENERIC_ENGINE = False # for tests
-
-def _locate_engine_class(ffi, force_generic_engine):
- if _FORCE_GENERIC_ENGINE:
- force_generic_engine = True
- if not force_generic_engine:
- if '__pypy__' in sys.builtin_module_names:
- force_generic_engine = True
- else:
- try:
- import _cffi_backend
- except ImportError:
- _cffi_backend = '?'
- if ffi._backend is not _cffi_backend:
- force_generic_engine = True
- if force_generic_engine:
- from . import vengine_gen
- return vengine_gen.VGenericEngine
- else:
- from . import vengine_cpy
- return vengine_cpy.VCPythonEngine
-
-# ____________________________________________________________
-
-_TMPDIR = None
-
-def _caller_dir_pycache():
- if _TMPDIR:
- return _TMPDIR
- result = os.environ.get('CFFI_TMPDIR')
- if result:
- return result
- filename = sys._getframe(2).f_code.co_filename
- return os.path.abspath(os.path.join(os.path.dirname(filename),
- '__pycache__'))
-
-def set_tmpdir(dirname):
- """Set the temporary directory to use instead of __pycache__."""
- global _TMPDIR
- _TMPDIR = dirname
-
-def cleanup_tmpdir(tmpdir=None, keep_so=False):
- """Clean up the temporary directory by removing all files in it
- called `_cffi_*.{c,so}` as well as the `build` subdirectory."""
- tmpdir = tmpdir or _caller_dir_pycache()
- try:
- filelist = os.listdir(tmpdir)
- except OSError:
- return
- if keep_so:
- suffix = '.c' # only remove .c files
- else:
- suffix = _get_so_suffixes()[0].lower()
- for fn in filelist:
- if fn.lower().startswith('_cffi_') and (
- fn.lower().endswith(suffix) or fn.lower().endswith('.c')):
- try:
- os.unlink(os.path.join(tmpdir, fn))
- except OSError:
- pass
- clean_dir = [os.path.join(tmpdir, 'build')]
- for dir in clean_dir:
- try:
- for fn in os.listdir(dir):
- fn = os.path.join(dir, fn)
- if os.path.isdir(fn):
- clean_dir.append(fn)
- else:
- os.unlink(fn)
- except OSError:
- pass
-
-def _get_so_suffixes():
- suffixes = _extension_suffixes()
- if not suffixes:
- # bah, no C_EXTENSION available. Occurs on pypy without cpyext
- if sys.platform == 'win32':
- suffixes = [".pyd"]
- else:
- suffixes = [".so"]
-
- return suffixes
-
-def _ensure_dir(filename):
- dirname = os.path.dirname(filename)
- if dirname and not os.path.isdir(dirname):
- os.makedirs(dirname)
diff --git a/demo/_curses.py b/demo/_curses.py
deleted file mode 100644
index 46443c2..0000000
--- a/demo/_curses.py
+++ /dev/null
@@ -1,1075 +0,0 @@
-"""Reimplementation of the standard extension module '_curses' using cffi."""
-
-import sys
-from functools import wraps
-
-from _curses_cffi import ffi, lib
-
-
-def _copy_to_globals(name):
- globals()[name] = getattr(lib, name)
-
-
-def _setup():
- for name in ['ERR', 'OK', 'KEY_MIN', 'KEY_MAX',
- 'A_ATTRIBUTES', 'A_NORMAL', 'A_STANDOUT', 'A_UNDERLINE',
- 'A_REVERSE', 'A_BLINK', 'A_DIM', 'A_BOLD', 'A_ALTCHARSET',
- 'A_PROTECT', 'A_CHARTEXT', 'A_COLOR',
- 'COLOR_BLACK', 'COLOR_RED', 'COLOR_GREEN', 'COLOR_YELLOW',
- 'COLOR_BLUE', 'COLOR_MAGENTA', 'COLOR_CYAN', 'COLOR_WHITE',
- ]:
- _copy_to_globals(name)
-
- if not lib._m_NetBSD:
- _copy_to_globals('A_INVIS')
-
- for name in ['A_HORIZONTAL', 'A_LEFT', 'A_LOW', 'A_RIGHT', 'A_TOP',
- 'A_VERTICAL',
- ]:
- if hasattr(lib, name):
- _copy_to_globals(name)
-
- if lib._m_NCURSES_MOUSE_VERSION:
- for name in ["BUTTON1_PRESSED", "BUTTON1_RELEASED", "BUTTON1_CLICKED",
- "BUTTON1_DOUBLE_CLICKED", "BUTTON1_TRIPLE_CLICKED",
- "BUTTON2_PRESSED", "BUTTON2_RELEASED", "BUTTON2_CLICKED",
- "BUTTON2_DOUBLE_CLICKED", "BUTTON2_TRIPLE_CLICKED",
- "BUTTON3_PRESSED", "BUTTON3_RELEASED", "BUTTON3_CLICKED",
- "BUTTON3_DOUBLE_CLICKED", "BUTTON3_TRIPLE_CLICKED",
- "BUTTON4_PRESSED", "BUTTON4_RELEASED", "BUTTON4_CLICKED",
- "BUTTON4_DOUBLE_CLICKED", "BUTTON4_TRIPLE_CLICKED",
- "BUTTON_SHIFT", "BUTTON_CTRL", "BUTTON_ALT",
- "ALL_MOUSE_EVENTS", "REPORT_MOUSE_POSITION",
- ]:
- _copy_to_globals(name)
-
- if not lib._m_NetBSD:
- for key in range(lib.KEY_MIN, lib.KEY_MAX):
- key_n = lib.keyname(key)
- if key_n == ffi.NULL:
- continue
- key_n = ffi.string(key_n)
- if key_n == b"UNKNOWN KEY":
- continue
- if not isinstance(key_n, str): # python 3
- key_n = key_n.decode()
- key_n = key_n.replace('(', '').replace(')', '')
- globals()[key_n] = key
-
-_setup()
-
-# Do we want this?
-# version = "2.2"
-# __version__ = "2.2"
-
-
-# ____________________________________________________________
-
-
-_initialised_setupterm = False
-_initialised = False
-_initialised_color = False
-
-
-def _ensure_initialised_setupterm():
- if not _initialised_setupterm:
- raise error("must call (at least) setupterm() first")
-
-
-def _ensure_initialised():
- if not _initialised:
- raise error("must call initscr() first")
-
-
-def _ensure_initialised_color():
- if not _initialised and _initialised_color:
- raise error("must call start_color() first")
-
-
-def _check_ERR(code, fname):
- if code != lib.ERR:
- return None
- elif fname is None:
- raise error("curses function returned ERR")
- else:
- raise error("%s() returned ERR" % (fname,))
-
-
-def _check_NULL(rval):
- if rval == ffi.NULL:
- raise error("curses function returned NULL")
- return rval
-
-
-def _call_lib(method_name, *args):
- return getattr(lib, method_name)(*args)
-
-
-def _call_lib_check_ERR(method_name, *args):
- return _check_ERR(_call_lib(method_name, *args), method_name)
-
-
-def _mk_no_return(method_name):
- def _execute():
- _ensure_initialised()
- return _call_lib_check_ERR(method_name)
- _execute.__name__ = method_name
- return _execute
-
-
-def _mk_flag_func(method_name):
- # This is in the CPython implementation, but not documented anywhere.
- # We have to support it, though, even if it make me sad.
- def _execute(flag=True):
- _ensure_initialised()
- if flag:
- return _call_lib_check_ERR(method_name)
- else:
- return _call_lib_check_ERR('no' + method_name)
- _execute.__name__ = method_name
- return _execute
-
-
-def _mk_return_val(method_name):
- def _execute():
- return _call_lib(method_name)
- _execute.__name__ = method_name
- return _execute
-
-
-def _mk_w_getyx(method_name):
- def _execute(self):
- y = _call_lib(method_name + 'y', self._win)
- x = _call_lib(method_name + 'x', self._win)
- return (y, x)
- _execute.__name__ = method_name
- return _execute
-
-
-def _mk_w_no_return(method_name):
- def _execute(self, *args):
- return _call_lib_check_ERR(method_name, self._win, *args)
- _execute.__name__ = method_name
- return _execute
-
-
-def _mk_w_return_val(method_name):
- def _execute(self, *args):
- return _call_lib(method_name, self._win, *args)
- _execute.__name__ = method_name
- return _execute
-
-
-def _chtype(ch):
- return int(ffi.cast("chtype", ch))
-
-def _texttype(text):
- if isinstance(text, str):
- return text
- elif isinstance(text, unicode):
- return str(text) # default encoding
- else:
- raise TypeError("str or unicode expected, got a '%s' object"
- % (type(text).__name__,))
-
-
-def _extract_yx(args):
- if len(args) >= 2:
- return (args[0], args[1], args[2:])
- return (None, None, args)
-
-
-def _process_args(funcname, args, count, optcount, frontopt=0):
- outargs = []
- if frontopt:
- if len(args) > count + optcount:
- # We have the front optional args here.
- outargs.extend(args[:frontopt])
- args = args[frontopt:]
- else:
- # No front optional args, so make them None.
- outargs.extend([None] * frontopt)
- if (len(args) < count) or (len(args) > count + optcount):
- raise error("%s requires %s to %s arguments" % (
- funcname, count, count + optcount + frontopt))
- outargs.extend(args)
- return outargs
-
-
-def _argspec(count, optcount=0, frontopt=0):
- def _argspec_deco(func):
- @wraps(func)
- def _wrapped(self, *args):
- outargs = _process_args(
- func.__name__, args, count, optcount, frontopt)
- return func(self, *outargs)
- return _wrapped
- return _argspec_deco
-
-
-# ____________________________________________________________
-
-
-class error(Exception):
- pass
-
-
-class Window(object):
- def __init__(self, window):
- self._win = window
-
- def __del__(self):
- if self._win != lib.stdscr:
- lib.delwin(self._win)
-
- untouchwin = _mk_w_no_return("untouchwin")
- touchwin = _mk_w_no_return("touchwin")
- redrawwin = _mk_w_no_return("redrawwin")
- insertln = _mk_w_no_return("winsertln")
- erase = _mk_w_no_return("werase")
- deleteln = _mk_w_no_return("wdeleteln")
-
- is_wintouched = _mk_w_return_val("is_wintouched")
-
- syncdown = _mk_w_return_val("wsyncdown")
- syncup = _mk_w_return_val("wsyncup")
- standend = _mk_w_return_val("wstandend")
- standout = _mk_w_return_val("wstandout")
- cursyncup = _mk_w_return_val("wcursyncup")
- clrtoeol = _mk_w_return_val("wclrtoeol")
- clrtobot = _mk_w_return_val("wclrtobot")
- clear = _mk_w_return_val("wclear")
-
- idcok = _mk_w_no_return("idcok")
- immedok = _mk_w_no_return("immedok")
- timeout = _mk_w_no_return("wtimeout")
-
- getyx = _mk_w_getyx("getcur")
- getbegyx = _mk_w_getyx("getbeg")
- getmaxyx = _mk_w_getyx("getmax")
- getparyx = _mk_w_getyx("getpar")
-
- clearok = _mk_w_no_return("clearok")
- idlok = _mk_w_no_return("idlok")
- leaveok = _mk_w_no_return("leaveok")
- notimeout = _mk_w_no_return("notimeout")
- scrollok = _mk_w_no_return("scrollok")
- insdelln = _mk_w_no_return("winsdelln")
- syncok = _mk_w_no_return("syncok")
-
- mvwin = _mk_w_no_return("mvwin")
- mvderwin = _mk_w_no_return("mvderwin")
- move = _mk_w_no_return("wmove")
-
- if not lib._m_STRICT_SYSV_CURSES:
- resize = _mk_w_no_return("wresize")
-
- if lib._m_NetBSD:
- keypad = _mk_w_return_val("keypad")
- nodelay = _mk_w_return_val("nodelay")
- else:
- keypad = _mk_w_no_return("keypad")
- nodelay = _mk_w_no_return("nodelay")
-
- @_argspec(1, 1, 2)
- def addch(self, y, x, ch, attr=None):
- if attr is None:
- attr = lib.A_NORMAL
- ch = _chtype(ch)
-
- if y is not None:
- code = lib.mvwaddch(self._win, y, x, ch | attr)
- else:
- code = lib.waddch(self._win, ch | attr)
- return _check_ERR(code, "addch")
-
- @_argspec(1, 1, 2)
- def addstr(self, y, x, text, attr=None):
- text = _texttype(text)
- if attr is not None:
- attr_old = lib.getattrs(self._win)
- lib.wattrset(self._win, attr)
- if y is not None:
- code = lib.mvwaddstr(self._win, y, x, text)
- else:
- code = lib.waddstr(self._win, text)
- if attr is not None:
- lib.wattrset(self._win, attr_old)
- return _check_ERR(code, "addstr")
-
- @_argspec(2, 1, 2)
- def addnstr(self, y, x, text, n, attr=None):
- text = _texttype(text)
- if attr is not None:
- attr_old = lib.getattrs(self._win)
- lib.wattrset(self._win, attr)
- if y is not None:
- code = lib.mvwaddnstr(self._win, y, x, text, n)
- else:
- code = lib.waddnstr(self._win, text, n)
- if attr is not None:
- lib.wattrset(self._win, attr_old)
- return _check_ERR(code, "addnstr")
-
- def bkgd(self, ch, attr=None):
- if attr is None:
- attr = lib.A_NORMAL
- return _check_ERR(lib.wbkgd(self._win, _chtype(ch) | attr), "bkgd")
-
- attroff = _mk_w_no_return("wattroff")
- attron = _mk_w_no_return("wattron")
- attrset = _mk_w_no_return("wattrset")
-
- def bkgdset(self, ch, attr=None):
- if attr is None:
- attr = lib.A_NORMAL
- lib.wbkgdset(self._win, _chtype(ch) | attr)
- return None
-
- def border(self, ls=0, rs=0, ts=0, bs=0, tl=0, tr=0, bl=0, br=0):
- lib.wborder(self._win,
- _chtype(ls), _chtype(rs), _chtype(ts), _chtype(bs),
- _chtype(tl), _chtype(tr), _chtype(bl), _chtype(br))
- return None
-
- def box(self, vertint=0, horint=0):
- lib.box(self._win, vertint, horint)
- return None
-
- @_argspec(1, 1, 2)
- def chgat(self, y, x, num, attr=None):
- # These optional args are in a weird order.
- if attr is None:
- attr = num
- num = -1
-
- color = ((attr >> 8) & 0xff)
- attr = attr - (color << 8)
-
- if y is not None:
- code = lib.mvwchgat(self._win, y, x, num, attr, color, ffi.NULL)
- lib.touchline(self._win, y, 1)
- else:
- yy, _ = self.getyx()
- code = lib.wchgat(self._win, num, attr, color, ffi.NULL)
- lib.touchline(self._win, yy, 1)
- return _check_ERR(code, "chgat")
-
- def delch(self, *args):
- if len(args) == 0:
- code = lib.wdelch(self._win)
- elif len(args) == 2:
- code = lib.mvwdelch(self._win, *args)
- else:
- raise error("delch requires 0 or 2 arguments")
- return _check_ERR(code, "[mv]wdelch")
-
- def derwin(self, *args):
- nlines = 0
- ncols = 0
- if len(args) == 2:
- begin_y, begin_x = args
- elif len(args) == 4:
- nlines, ncols, begin_y, begin_x = args
- else:
- raise error("derwin requires 2 or 4 arguments")
-
- win = lib.derwin(self._win, nlines, ncols, begin_y, begin_x)
- return Window(_check_NULL(win))
-
- def echochar(self, ch, attr=None):
- if attr is None:
- attr = lib.A_NORMAL
- ch = _chtype(ch)
-
- if lib._m_ispad(self._win):
- code = lib.pechochar(self._win, ch | attr)
- else:
- code = lib.wechochar(self._win, ch | attr)
- return _check_ERR(code, "echochar")
-
- if lib._m_NCURSES_MOUSE_VERSION:
- enclose = _mk_w_return_val("wenclose")
-
- getbkgd = _mk_w_return_val("getbkgd")
-
- def getch(self, *args):
- if len(args) == 0:
- val = lib.wgetch(self._win)
- elif len(args) == 2:
- val = lib.mvwgetch(self._win, *args)
- else:
- raise error("getch requires 0 or 2 arguments")
- return val
-
- def getkey(self, *args):
- if len(args) == 0:
- val = lib.wgetch(self._win)
- elif len(args) == 2:
- val = lib.mvwgetch(self._win, *args)
- else:
- raise error("getkey requires 0 or 2 arguments")
-
- if val == lib.ERR:
- raise error("no input")
- elif val <= 255:
- return chr(val)
- else:
- # XXX: The following line is different if `__NetBSD__` is defined.
- val = lib.keyname(val)
- if val == ffi.NULL:
- return ""
- return ffi.string(val)
-
- @_argspec(0, 1, 2)
- def getstr(self, y, x, n=1023):
- n = min(n, 1023)
- buf = ffi.new("char[1024]") # /* This should be big enough.. I hope */
-
- if y is None:
- val = lib.wgetnstr(self._win, buf, n)
- else:
- val = lib.mvwgetnstr(self._win, y, x, buf, n)
-
- if val == lib.ERR:
- return ""
- return ffi.string(buf)
-
- @_argspec(2, 1, 2)
- def hline(self, y, x, ch, n, attr=None):
- ch = _chtype(ch)
- if attr is None:
- attr = lib.A_NORMAL
- if y is not None:
- _check_ERR(lib.wmove(self._win, y, x), "wmove")
- return _check_ERR(lib.whline(self._win, ch | attr, n), "hline")
-
- @_argspec(1, 1, 2)
- def insch(self, y, x, ch, attr=None):
- ch = _chtype(ch)
- if attr is None:
- attr = lib.A_NORMAL
- if y is not None:
- code = lib.mvwinsch(self._win, y, x, ch | attr)
- else:
- code = lib.winsch(self._win, ch | attr)
- return _check_ERR(code, "insch")
-
- def inch(self, *args):
- if len(args) == 0:
- return lib.winch(self._win)
- elif len(args) == 2:
- return lib.mvwinch(self._win, *args)
- else:
- raise error("inch requires 0 or 2 arguments")
-
- @_argspec(0, 1, 2)
- def instr(self, y, x, n=1023):
- n = min(n, 1023)
- buf = ffi.new("char[1024]") # /* This should be big enough.. I hope */
- if y is None:
- code = lib.winnstr(self._win, buf, n)
- else:
- code = lib.mvwinnstr(self._win, y, x, buf, n)
-
- if code == lib.ERR:
- return ""
- return ffi.string(buf)
-
- @_argspec(1, 1, 2)
- def insstr(self, y, x, text, attr=None):
- text = _texttype(text)
- if attr is not None:
- attr_old = lib.getattrs(self._win)
- lib.wattrset(self._win, attr)
- if y is not None:
- code = lib.mvwinsstr(self._win, y, x, text)
- else:
- code = lib.winsstr(self._win, text)
- if attr is not None:
- lib.wattrset(self._win, attr_old)
- return _check_ERR(code, "insstr")
-
- @_argspec(2, 1, 2)
- def insnstr(self, y, x, text, n, attr=None):
- text = _texttype(text)
- if attr is not None:
- attr_old = lib.getattrs(self._win)
- lib.wattrset(self._win, attr)
- if y is not None:
- code = lib.mvwinsnstr(self._win, y, x, text, n)
- else:
- code = lib.winsnstr(self._win, text, n)
- if attr is not None:
- lib.wattrset(self._win, attr_old)
- return _check_ERR(code, "insnstr")
-
- def is_linetouched(self, line):
- code = lib.is_linetouched(self._win, line)
- if code == lib.ERR:
- raise error("is_linetouched: line number outside of boundaries")
- if code == lib.FALSE:
- return False
- return True
-
- def noutrefresh(self, *args):
- if lib._m_ispad(self._win):
- if len(args) != 6:
- raise error(
- "noutrefresh() called for a pad requires 6 arguments")
- return _check_ERR(lib.pnoutrefresh(self._win, *args),
- "pnoutrefresh")
- else:
- # XXX: Better args check here? We need zero args.
- return _check_ERR(lib.wnoutrefresh(self._win, *args),
- "wnoutrefresh")
-
- nooutrefresh = noutrefresh # "to be removed in 2.3", but in 2.7, 3.x.
-
- def _copywin(self, dstwin, overlay,
- sminr, sminc, dminr, dminc, dmaxr, dmaxc):
- return _check_ERR(lib.copywin(self._win, dstwin._win,
- sminr, sminc, dminr, dminc, dmaxr, dmaxc,
- overlay), "copywin")
-
- def overlay(self, dstwin, *args):
- if len(args) == 6:
- return self._copywin(dstwin, True, *args)
- elif len(args) == 0:
- return _check_ERR(lib.overlay(self._win, dstwin._win), "overlay")
- else:
- raise error("overlay requires one or seven arguments")
-
- def overwrite(self, dstwin, *args):
- if len(args) == 6:
- return self._copywin(dstwin, False, *args)
- elif len(args) == 0:
- return _check_ERR(lib.overwrite(self._win, dstwin._win),
- "overwrite")
- else:
- raise error("overwrite requires one or seven arguments")
-
- def putwin(self, filep):
- # filestar = ffi.new("FILE *", filep)
- return _check_ERR(lib.putwin(self._win, filep), "putwin")
-
- def redrawln(self, beg, num):
- return _check_ERR(lib.wredrawln(self._win, beg, num), "redrawln")
-
- def refresh(self, *args):
- if lib._m_ispad(self._win):
- if len(args) != 6:
- raise error(
- "noutrefresh() called for a pad requires 6 arguments")
- return _check_ERR(lib.prefresh(self._win, *args), "prefresh")
- else:
- # XXX: Better args check here? We need zero args.
- return _check_ERR(lib.wrefresh(self._win, *args), "wrefresh")
-
- def setscrreg(self, y, x):
- return _check_ERR(lib.wsetscrreg(self._win, y, x), "wsetscrreg")
-
- def subwin(self, *args):
- nlines = 0
- ncols = 0
- if len(args) == 2:
- begin_y, begin_x = args
- elif len(args) == 4:
- nlines, ncols, begin_y, begin_x = args
- else:
- raise error("subwin requires 2 or 4 arguments")
-
- if lib._m_ispad(self._win):
- win = lib.subpad(self._win, nlines, ncols, begin_y, begin_x)
- else:
- win = lib.subwin(self._win, nlines, ncols, begin_y, begin_x)
- return Window(_check_NULL(win))
-
- def scroll(self, nlines=None):
- if nlines is None:
- return _check_ERR(lib.scroll(self._win), "scroll")
- else:
- return _check_ERR(lib.wscrl(self._win, nlines), "scroll")
-
- def touchline(self, st, cnt, val=None):
- if val is None:
- return _check_ERR(lib.touchline(self._win, st, cnt), "touchline")
- else:
- return _check_ERR(lib.wtouchln(self._win, st, cnt, val),
- "touchline")
-
- @_argspec(2, 1, 2)
- def vline(self, y, x, ch, n, attr=None):
- ch = _chtype(ch)
- if attr is None:
- attr = lib.A_NORMAL
- if y is not None:
- _check_ERR(lib.wmove(self._win, y, x), "wmove")
- return _check_ERR(lib.wvline(self._win, ch | attr, n), "vline")
-
-
-beep = _mk_no_return("beep")
-def_prog_mode = _mk_no_return("def_prog_mode")
-def_shell_mode = _mk_no_return("def_shell_mode")
-doupdate = _mk_no_return("doupdate")
-endwin = _mk_no_return("endwin")
-flash = _mk_no_return("flash")
-nocbreak = _mk_no_return("nocbreak")
-noecho = _mk_no_return("noecho")
-nonl = _mk_no_return("nonl")
-noraw = _mk_no_return("noraw")
-reset_prog_mode = _mk_no_return("reset_prog_mode")
-reset_shell_mode = _mk_no_return("reset_shell_mode")
-resetty = _mk_no_return("resetty")
-savetty = _mk_no_return("savetty")
-
-cbreak = _mk_flag_func("cbreak")
-echo = _mk_flag_func("echo")
-nl = _mk_flag_func("nl")
-raw = _mk_flag_func("raw")
-
-baudrate = _mk_return_val("baudrate")
-termattrs = _mk_return_val("termattrs")
-
-termname = _mk_return_val("termname")
-longname = _mk_return_val("longname")
-
-can_change_color = _mk_return_val("can_change_color")
-has_colors = _mk_return_val("has_colors")
-has_ic = _mk_return_val("has_ic")
-has_il = _mk_return_val("has_il")
-isendwin = _mk_return_val("isendwin")
-flushinp = _mk_return_val("flushinp")
-noqiflush = _mk_return_val("noqiflush")
-
-
-def filter():
- lib.filter()
- return None
-
-
-def color_content(color):
- _ensure_initialised_color()
- r, g, b = ffi.new("short *"), ffi.new("short *"), ffi.new("short *")
- if lib.color_content(color, r, g, b) == lib.ERR:
- raise error("Argument 1 was out of range. Check value of COLORS.")
- return (r[0], g[0], b[0])
-
-
-def color_pair(n):
- _ensure_initialised_color()
- return (n << 8)
-
-
-def curs_set(vis):
- _ensure_initialised()
- val = lib.curs_set(vis)
- _check_ERR(val, "curs_set")
- return val
-
-
-def delay_output(ms):
- _ensure_initialised()
- return _check_ERR(lib.delay_output(ms), "delay_output")
-
-
-def erasechar():
- _ensure_initialised()
- return lib.erasechar()
-
-
-def getsyx():
- _ensure_initialised()
- yx = ffi.new("int[2]")
- lib._m_getsyx(yx)
- return (yx[0], yx[1])
-
-
-if lib._m_NCURSES_MOUSE_VERSION:
-
- def getmouse():
- _ensure_initialised()
- mevent = ffi.new("MEVENT *")
- _check_ERR(lib.getmouse(mevent), "getmouse")
- return (mevent.id, mevent.x, mevent.y, mevent.z, mevent.bstate)
-
- def ungetmouse(id, x, y, z, bstate):
- _ensure_initialised()
- mevent = ffi.new("MEVENT *")
- mevent.id, mevent.x, mevent.y, mevent.z, mevent.bstate = (
- id, x, y, z, bstate)
- return _check_ERR(lib.ungetmouse(mevent), "ungetmouse")
-
-
-def getwin(filep):
- return Window(_check_NULL(lib.getwin(filep)))
-
-
-def halfdelay(tenths):
- _ensure_initialised()
- return _check_ERR(lib.halfdelay(tenths), "halfdelay")
-
-
-if not lib._m_STRICT_SYSV_CURSES:
- def has_key(ch):
- _ensure_initialised()
- return lib.has_key(ch)
-
-
-def init_color(color, r, g, b):
- _ensure_initialised_color()
- return _check_ERR(lib.init_color(color, r, g, b), "init_color")
-
-
-def init_pair(pair, f, b):
- _ensure_initialised_color()
- return _check_ERR(lib.init_pair(pair, f, b), "init_pair")
-
-
-def _mk_acs(name, ichar):
- if len(ichar) == 1:
- globals()[name] = lib.acs_map[ord(ichar)]
- else:
- globals()[name] = globals()[ichar]
-
-
-def _map_acs():
- _mk_acs("ACS_ULCORNER", 'l')
- _mk_acs("ACS_LLCORNER", 'm')
- _mk_acs("ACS_URCORNER", 'k')
- _mk_acs("ACS_LRCORNER", 'j')
- _mk_acs("ACS_LTEE", 't')
- _mk_acs("ACS_RTEE", 'u')
- _mk_acs("ACS_BTEE", 'v')
- _mk_acs("ACS_TTEE", 'w')
- _mk_acs("ACS_HLINE", 'q')
- _mk_acs("ACS_VLINE", 'x')
- _mk_acs("ACS_PLUS", 'n')
- _mk_acs("ACS_S1", 'o')
- _mk_acs("ACS_S9", 's')
- _mk_acs("ACS_DIAMOND", '`')
- _mk_acs("ACS_CKBOARD", 'a')
- _mk_acs("ACS_DEGREE", 'f')
- _mk_acs("ACS_PLMINUS", 'g')
- _mk_acs("ACS_BULLET", '~')
- _mk_acs("ACS_LARROW", ',')
- _mk_acs("ACS_RARROW", '+')
- _mk_acs("ACS_DARROW", '.')
- _mk_acs("ACS_UARROW", '-')
- _mk_acs("ACS_BOARD", 'h')
- _mk_acs("ACS_LANTERN", 'i')
- _mk_acs("ACS_BLOCK", '0')
- _mk_acs("ACS_S3", 'p')
- _mk_acs("ACS_S7", 'r')
- _mk_acs("ACS_LEQUAL", 'y')
- _mk_acs("ACS_GEQUAL", 'z')
- _mk_acs("ACS_PI", '{')
- _mk_acs("ACS_NEQUAL", '|')
- _mk_acs("ACS_STERLING", '}')
- _mk_acs("ACS_BSSB", "ACS_ULCORNER")
- _mk_acs("ACS_SSBB", "ACS_LLCORNER")
- _mk_acs("ACS_BBSS", "ACS_URCORNER")
- _mk_acs("ACS_SBBS", "ACS_LRCORNER")
- _mk_acs("ACS_SBSS", "ACS_RTEE")
- _mk_acs("ACS_SSSB", "ACS_LTEE")
- _mk_acs("ACS_SSBS", "ACS_BTEE")
- _mk_acs("ACS_BSSS", "ACS_TTEE")
- _mk_acs("ACS_BSBS", "ACS_HLINE")
- _mk_acs("ACS_SBSB", "ACS_VLINE")
- _mk_acs("ACS_SSSS", "ACS_PLUS")
-
-
-def initscr():
- if _initialised:
- lib.wrefresh(lib.stdscr)
- return Window(lib.stdscr)
-
- win = _check_NULL(lib.initscr())
- globals()['_initialised_setupterm'] = True
- globals()['_initialised'] = True
-
- _map_acs()
-
- globals()["LINES"] = lib.LINES
- globals()["COLS"] = lib.COLS
-
- return Window(win)
-
-
-def setupterm(term=None, fd=-1):
- if fd == -1:
- # XXX: Check for missing stdout here?
- fd = sys.stdout.fileno()
-
- if _initialised_setupterm:
- return None
-
- if term is None:
- term = ffi.NULL
- err = ffi.new("int *")
- if lib.setupterm(term, fd, err) == lib.ERR:
- err = err[0]
- if err == 0:
- raise error("setupterm: could not find terminal")
- elif err == -1:
- raise error("setupterm: could not find terminfo database")
- else:
- raise error("setupterm: unknown error")
-
- globals()["_initialised_setupterm"] = True
- return None
-
-
-def intrflush(ch):
- _ensure_initialised()
- return _check_ERR(lib.intrflush(ffi.NULL, ch), "intrflush")
-
-
-# XXX: #ifdef HAVE_CURSES_IS_TERM_RESIZED
-def is_term_resized(lines, columns):
- _ensure_initialised()
- return lib.is_term_resized(lines, columns)
-
-
-if not lib._m_NetBSD:
- def keyname(ch):
- _ensure_initialised()
- if ch < 0:
- raise error("invalid key number")
- knp = lib.keyname(ch)
- if knp == ffi.NULL:
- return ""
- return ffi.string(knp)
-
-
-def killchar():
- return lib.killchar()
-
-
-def meta(ch):
- return _check_ERR(lib.meta(lib.stdscr, ch), "meta")
-
-
-if lib._m_NCURSES_MOUSE_VERSION:
-
- def mouseinterval(interval):
- _ensure_initialised()
- return _check_ERR(lib.mouseinterval(interval), "mouseinterval")
-
- def mousemask(newmask):
- _ensure_initialised()
- oldmask = ffi.new("mmask_t *")
- availmask = lib.mousemask(newmask, oldmask)
- return (availmask, oldmask)
-
-
-def napms(ms):
- _ensure_initialised()
- return lib.napms(ms)
-
-
-def newpad(nlines, ncols):
- _ensure_initialised()
- return Window(_check_NULL(lib.newpad(nlines, ncols)))
-
-
-def newwin(nlines, ncols, begin_y=None, begin_x=None):
- _ensure_initialised()
- if begin_x is None:
- if begin_y is not None:
- raise error("newwin requires 2 or 4 arguments")
- begin_y = begin_x = 0
-
- return Window(_check_NULL(lib.newwin(nlines, ncols, begin_y, begin_x)))
-
-
-def pair_content(pair):
- _ensure_initialised_color()
- f = ffi.new("short *")
- b = ffi.new("short *")
- if lib.pair_content(pair, f, b) == lib.ERR:
- raise error("Argument 1 was out of range. (1..COLOR_PAIRS-1)")
- return (f, b)
-
-
-def pair_number(pairvalue):
- _ensure_initialised_color()
- return (pairvalue & lib.A_COLOR) >> 8
-
-
-def putp(text):
- text = _texttype(text)
- return _check_ERR(lib.putp(text), "putp")
-
-
-def qiflush(flag=True):
- _ensure_initialised()
- if flag:
- lib.qiflush()
- else:
- lib.noqiflush()
- return None
-
-
-# XXX: Do something about the following?
-# /* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES
-# * and _curses.COLS */
-# #if defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM)
-# static int
-# update_lines_cols(void)
-# {
-# PyObject *o;
-# PyObject *m = PyImport_ImportModuleNoBlock("curses");
-
-# if (!m)
-# return 0;
-
-# o = PyInt_FromLong(LINES);
-# if (!o) {
-# Py_DECREF(m);
-# return 0;
-# }
-# if (PyObject_SetAttrString(m, "LINES", o)) {
-# Py_DECREF(m);
-# Py_DECREF(o);
-# return 0;
-# }
-# if (PyDict_SetItemString(ModDict, "LINES", o)) {
-# Py_DECREF(m);
-# Py_DECREF(o);
-# return 0;
-# }
-# Py_DECREF(o);
-# o = PyInt_FromLong(COLS);
-# if (!o) {
-# Py_DECREF(m);
-# return 0;
-# }
-# if (PyObject_SetAttrString(m, "COLS", o)) {
-# Py_DECREF(m);
-# Py_DECREF(o);
-# return 0;
-# }
-# if (PyDict_SetItemString(ModDict, "COLS", o)) {
-# Py_DECREF(m);
-# Py_DECREF(o);
-# return 0;
-# }
-# Py_DECREF(o);
-# Py_DECREF(m);
-# return 1;
-# }
-# #endif
-
-# #ifdef HAVE_CURSES_RESIZETERM
-# static PyObject *
-# PyCurses_ResizeTerm(PyObject *self, PyObject *args)
-# {
-# int lines;
-# int columns;
-# PyObject *result;
-
-# PyCursesInitialised;
-
-# if (!PyArg_ParseTuple(args,"ii:resizeterm", &lines, &columns))
-# return NULL;
-
-# result = PyCursesCheckERR(resizeterm(lines, columns), "resizeterm");
-# if (!result)
-# return NULL;
-# if (!update_lines_cols())
-# return NULL;
-# return result;
-# }
-
-# #endif
-
-# #ifdef HAVE_CURSES_RESIZE_TERM
-# static PyObject *
-# PyCurses_Resize_Term(PyObject *self, PyObject *args)
-# {
-# int lines;
-# int columns;
-
-# PyObject *result;
-
-# PyCursesInitialised;
-
-# if (!PyArg_ParseTuple(args,"ii:resize_term", &lines, &columns))
-# return NULL;
-
-# result = PyCursesCheckERR(resize_term(lines, columns), "resize_term");
-# if (!result)
-# return NULL;
-# if (!update_lines_cols())
-# return NULL;
-# return result;
-# }
-# #endif /* HAVE_CURSES_RESIZE_TERM */
-
-
-def setsyx(y, x):
- _ensure_initialised()
- lib.setsyx(y, x)
- return None
-
-
-def start_color():
- _check_ERR(lib.start_color(), "start_color")
- globals()["COLORS"] = lib.COLORS
- globals()["COLOR_PAIRS"] = lib.COLOR_PAIRS
- globals()["_initialised_color"] = True
- return None
-
-
-def tigetflag(capname):
- _ensure_initialised_setupterm()
- return lib.tigetflag(capname)
-
-
-def tigetnum(capname):
- _ensure_initialised_setupterm()
- return lib.tigetnum(capname)
-
-
-def tigetstr(capname):
- _ensure_initialised_setupterm()
- val = lib.tigetstr(capname)
- if int(ffi.cast("intptr_t", val)) in (0, -1):
- return None
- return ffi.string(val)
-
-
-def tparm(fmt, i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0):
- args = [ffi.cast("int", i) for i in (i1, i2, i3, i4, i5, i6, i7, i8, i9)]
- result = lib.tparm(fmt, *args)
- if result == ffi.NULL:
- raise error("tparm() returned NULL")
- return ffi.string(result)
-
-
-def typeahead(fd):
- _ensure_initialised()
- return _check_ERR(lib.typeahead(fd), "typeahead")
-
-
-def unctrl(ch):
- _ensure_initialised()
- return lib.unctrl(_chtype(ch))
-
-
-def ungetch(ch):
- _ensure_initialised()
- return _check_ERR(lib.ungetch(_chtype(ch)), "ungetch")
-
-
-def use_env(flag):
- lib.use_env(flag)
- return None
-
-
-if not lib._m_STRICT_SYSV_CURSES:
-
- def use_default_colors():
- _ensure_initialised_color()
- return _check_ERR(lib.use_default_colors(), "use_default_colors")
diff --git a/demo/_curses_build.py b/demo/_curses_build.py
deleted file mode 100644
index 1a1a3ec..0000000
--- a/demo/_curses_build.py
+++ /dev/null
@@ -1,327 +0,0 @@
-import sys
-if sys.platform == 'win32':
- #This module does not exist in windows
- raise ImportError('No module named _curses')
-
-from cffi import FFI
-
-ffi = FFI()
-
-ffi.cdef("""
-typedef ... WINDOW;
-typedef ... SCREEN;
-typedef unsigned long... mmask_t;
-typedef unsigned char bool;
-typedef unsigned long... chtype;
-typedef chtype attr_t;
-
-typedef struct
-{
- short id; /* ID to distinguish multiple devices */
- int x, y, z; /* event coordinates (character-cell) */
- mmask_t bstate; /* button state bits */
-}
-MEVENT;
-
-static const int ERR, OK;
-static const int TRUE, FALSE;
-static const int KEY_MIN, KEY_MAX;
-
-static const int COLOR_BLACK;
-static const int COLOR_RED;
-static const int COLOR_GREEN;
-static const int COLOR_YELLOW;
-static const int COLOR_BLUE;
-static const int COLOR_MAGENTA;
-static const int COLOR_CYAN;
-static const int COLOR_WHITE;
-
-static const chtype A_ATTRIBUTES;
-static const chtype A_NORMAL;
-static const chtype A_STANDOUT;
-static const chtype A_UNDERLINE;
-static const chtype A_REVERSE;
-static const chtype A_BLINK;
-static const chtype A_DIM;
-static const chtype A_BOLD;
-static const chtype A_ALTCHARSET;
-static const chtype A_INVIS;
-static const chtype A_PROTECT;
-static const chtype A_CHARTEXT;
-static const chtype A_COLOR;
-
-static const int BUTTON1_RELEASED;
-static const int BUTTON1_PRESSED;
-static const int BUTTON1_CLICKED;
-static const int BUTTON1_DOUBLE_CLICKED;
-static const int BUTTON1_TRIPLE_CLICKED;
-static const int BUTTON2_RELEASED;
-static const int BUTTON2_PRESSED;
-static const int BUTTON2_CLICKED;
-static const int BUTTON2_DOUBLE_CLICKED;
-static const int BUTTON2_TRIPLE_CLICKED;
-static const int BUTTON3_RELEASED;
-static const int BUTTON3_PRESSED;
-static const int BUTTON3_CLICKED;
-static const int BUTTON3_DOUBLE_CLICKED;
-static const int BUTTON3_TRIPLE_CLICKED;
-static const int BUTTON4_RELEASED;
-static const int BUTTON4_PRESSED;
-static const int BUTTON4_CLICKED;
-static const int BUTTON4_DOUBLE_CLICKED;
-static const int BUTTON4_TRIPLE_CLICKED;
-static const int BUTTON_SHIFT;
-static const int BUTTON_CTRL;
-static const int BUTTON_ALT;
-static const int ALL_MOUSE_EVENTS;
-static const int REPORT_MOUSE_POSITION;
-
-int setupterm(char *, int, int *);
-
-WINDOW *stdscr;
-int COLORS;
-int COLOR_PAIRS;
-int COLS;
-int LINES;
-
-int baudrate(void);
-int beep(void);
-int box(WINDOW *, chtype, chtype);
-bool can_change_color(void);
-int cbreak(void);
-int clearok(WINDOW *, bool);
-int color_content(short, short*, short*, short*);
-int copywin(const WINDOW*, WINDOW*, int, int, int, int, int, int, int);
-int curs_set(int);
-int def_prog_mode(void);
-int def_shell_mode(void);
-int delay_output(int);
-int delwin(WINDOW *);
-WINDOW * derwin(WINDOW *, int, int, int, int);
-int doupdate(void);
-int echo(void);
-int endwin(void);
-char erasechar(void);
-void filter(void);
-int flash(void);
-int flushinp(void);
-chtype getbkgd(WINDOW *);
-WINDOW * getwin(FILE *);
-int halfdelay(int);
-bool has_colors(void);
-bool has_ic(void);
-bool has_il(void);
-void idcok(WINDOW *, bool);
-int idlok(WINDOW *, bool);
-void immedok(WINDOW *, bool);
-WINDOW * initscr(void);
-int init_color(short, short, short, short);
-int init_pair(short, short, short);
-int intrflush(WINDOW *, bool);
-bool isendwin(void);
-bool is_linetouched(WINDOW *, int);
-bool is_wintouched(WINDOW *);
-const char * keyname(int);
-int keypad(WINDOW *, bool);
-char killchar(void);
-int leaveok(WINDOW *, bool);
-char * longname(void);
-int meta(WINDOW *, bool);
-int mvderwin(WINDOW *, int, int);
-int mvwaddch(WINDOW *, int, int, const chtype);
-int mvwaddnstr(WINDOW *, int, int, const char *, int);
-int mvwaddstr(WINDOW *, int, int, const char *);
-int mvwchgat(WINDOW *, int, int, int, attr_t, short, const void *);
-int mvwdelch(WINDOW *, int, int);
-int mvwgetch(WINDOW *, int, int);
-int mvwgetnstr(WINDOW *, int, int, char *, int);
-int mvwin(WINDOW *, int, int);
-chtype mvwinch(WINDOW *, int, int);
-int mvwinnstr(WINDOW *, int, int, char *, int);
-int mvwinsch(WINDOW *, int, int, chtype);
-int mvwinsnstr(WINDOW *, int, int, const char *, int);
-int mvwinsstr(WINDOW *, int, int, const char *);
-int napms(int);
-WINDOW * newpad(int, int);
-WINDOW * newwin(int, int, int, int);
-int nl(void);
-int nocbreak(void);
-int nodelay(WINDOW *, bool);
-int noecho(void);
-int nonl(void);
-void noqiflush(void);
-int noraw(void);
-int notimeout(WINDOW *, bool);
-int overlay(const WINDOW*, WINDOW *);
-int overwrite(const WINDOW*, WINDOW *);
-int pair_content(short, short*, short*);
-int pechochar(WINDOW *, const chtype);
-int pnoutrefresh(WINDOW*, int, int, int, int, int, int);
-int prefresh(WINDOW *, int, int, int, int, int, int);
-int putwin(WINDOW *, FILE *);
-void qiflush(void);
-int raw(void);
-int redrawwin(WINDOW *);
-int resetty(void);
-int reset_prog_mode(void);
-int reset_shell_mode(void);
-int savetty(void);
-int scroll(WINDOW *);
-int scrollok(WINDOW *, bool);
-int start_color(void);
-WINDOW * subpad(WINDOW *, int, int, int, int);
-WINDOW * subwin(WINDOW *, int, int, int, int);
-int syncok(WINDOW *, bool);
-chtype termattrs(void);
-char * termname(void);
-int touchline(WINDOW *, int, int);
-int touchwin(WINDOW *);
-int typeahead(int);
-int ungetch(int);
-int untouchwin(WINDOW *);
-void use_env(bool);
-int waddch(WINDOW *, const chtype);
-int waddnstr(WINDOW *, const char *, int);
-int waddstr(WINDOW *, const char *);
-int wattron(WINDOW *, int);
-int wattroff(WINDOW *, int);
-int wattrset(WINDOW *, int);
-int wbkgd(WINDOW *, chtype);
-void wbkgdset(WINDOW *, chtype);
-int wborder(WINDOW *, chtype, chtype, chtype, chtype,
- chtype, chtype, chtype, chtype);
-int wchgat(WINDOW *, int, attr_t, short, const void *);
-int wclear(WINDOW *);
-int wclrtobot(WINDOW *);
-int wclrtoeol(WINDOW *);
-void wcursyncup(WINDOW *);
-int wdelch(WINDOW *);
-int wdeleteln(WINDOW *);
-int wechochar(WINDOW *, const chtype);
-int werase(WINDOW *);
-int wgetch(WINDOW *);
-int wgetnstr(WINDOW *, char *, int);
-int whline(WINDOW *, chtype, int);
-chtype winch(WINDOW *);
-int winnstr(WINDOW *, char *, int);
-int winsch(WINDOW *, chtype);
-int winsdelln(WINDOW *, int);
-int winsertln(WINDOW *);
-int winsnstr(WINDOW *, const char *, int);
-int winsstr(WINDOW *, const char *);
-int wmove(WINDOW *, int, int);
-int wresize(WINDOW *, int, int);
-int wnoutrefresh(WINDOW *);
-int wredrawln(WINDOW *, int, int);
-int wrefresh(WINDOW *);
-int wscrl(WINDOW *, int);
-int wsetscrreg(WINDOW *, int, int);
-int wstandout(WINDOW *);
-int wstandend(WINDOW *);
-void wsyncdown(WINDOW *);
-void wsyncup(WINDOW *);
-void wtimeout(WINDOW *, int);
-int wtouchln(WINDOW *, int, int, int);
-int wvline(WINDOW *, chtype, int);
-int tigetflag(char *);
-int tigetnum(char *);
-char * tigetstr(char *);
-int putp(const char *);
-char * tparm(const char *, ...);
-int getattrs(const WINDOW *);
-int getcurx(const WINDOW *);
-int getcury(const WINDOW *);
-int getbegx(const WINDOW *);
-int getbegy(const WINDOW *);
-int getmaxx(const WINDOW *);
-int getmaxy(const WINDOW *);
-int getparx(const WINDOW *);
-int getpary(const WINDOW *);
-
-int getmouse(MEVENT *);
-int ungetmouse(MEVENT *);
-mmask_t mousemask(mmask_t, mmask_t *);
-bool wenclose(const WINDOW *, int, int);
-int mouseinterval(int);
-
-void setsyx(int y, int x);
-const char *unctrl(chtype);
-int use_default_colors(void);
-
-int has_key(int);
-bool is_term_resized(int, int);
-
-#define _m_STRICT_SYSV_CURSES ...
-#define _m_NCURSES_MOUSE_VERSION ...
-#define _m_NetBSD ...
-int _m_ispad(WINDOW *);
-
-chtype acs_map[];
-
-// For _curses_panel:
-
-typedef ... PANEL;
-
-WINDOW *panel_window(const PANEL *);
-void update_panels(void);
-int hide_panel(PANEL *);
-int show_panel(PANEL *);
-int del_panel(PANEL *);
-int top_panel(PANEL *);
-int bottom_panel(PANEL *);
-PANEL *new_panel(WINDOW *);
-PANEL *panel_above(const PANEL *);
-PANEL *panel_below(const PANEL *);
-int set_panel_userptr(PANEL *, void *);
-const void *panel_userptr(const PANEL *);
-int move_panel(PANEL *, int, int);
-int replace_panel(PANEL *,WINDOW *);
-int panel_hidden(const PANEL *);
-
-void _m_getsyx(int *yx);
-""")
-
-
-ffi.set_source("_curses_cffi", """
-#ifdef __APPLE__
-/* the following define is necessary for OS X 10.6+; without it, the
- Apple-supplied ncurses.h sets NCURSES_OPAQUE to 1, and then Python
- can't get at the WINDOW flags field. */
-#define NCURSES_OPAQUE 0
-#endif
-
-#include <ncurses.h>
-#include <panel.h>
-#include <term.h>
-
-#if defined STRICT_SYSV_CURSES
-#define _m_STRICT_SYSV_CURSES TRUE
-#else
-#define _m_STRICT_SYSV_CURSES FALSE
-#endif
-
-#if defined NCURSES_MOUSE_VERSION
-#define _m_NCURSES_MOUSE_VERSION TRUE
-#else
-#define _m_NCURSES_MOUSE_VERSION FALSE
-#endif
-
-#if defined __NetBSD__
-#define _m_NetBSD TRUE
-#else
-#define _m_NetBSD FALSE
-#endif
-
-int _m_ispad(WINDOW *win) {
- // <curses.h> may not have _flags (and possibly _ISPAD),
- // but for now let's assume that <ncurses.h> always has it
- return (win->_flags & _ISPAD);
-}
-
-void _m_getsyx(int *yx) {
- getsyx(yx[0], yx[1]);
-}
-""", libraries=['ncurses', 'panel'])
-
-if __name__ == '__main__':
- ffi.compile()
diff --git a/demo/_curses_setup.py b/demo/_curses_setup.py
deleted file mode 100644
index ec3d20e..0000000
--- a/demo/_curses_setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from setuptools import setup
-
-setup(
- name="_curses",
- version="0.1",
- py_modules=["_curses"],
- setup_requires=["cffi>=1.0.dev0"],
- cffi_modules=[
- "_curses_build.py:ffi",
- ],
- install_requires=["cffi>=1.0.dev0"], # should maybe be "cffi-backend" only?
- zip_safe=False,
-)
diff --git a/demo/api.py b/demo/api.py
deleted file mode 100644
index 8cc6407..0000000
--- a/demo/api.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import cffi
-from cffi import FFI
-
-class PythonFFI(FFI):
-
- def __init__(self, backend=None):
- FFI.__init__(self, backend=backend)
- self._pyexports = {}
-
- def pyexport(self, signature):
- tp = self._typeof(signature, consider_function_as_funcptr=True)
- def decorator(func):
- name = func.__name__
- if name in self._pyexports:
- raise cffi.CDefError("duplicate pyexport'ed function %r"
- % (name,))
- callback_var = self.getctype(tp, name)
- self.cdef("%s;" % callback_var)
- self._pyexports[name] = _PyExport(tp, func)
- return decorator
-
- def verify(self, source='', **kwargs):
- extras = []
- pyexports = sorted(self._pyexports.items())
- for name, export in pyexports:
- callback_var = self.getctype(export.tp, name)
- extras.append("%s;" % callback_var)
- extras.append(source)
- source = '\n'.join(extras)
- lib = FFI.verify(self, source, **kwargs)
- for name, export in pyexports:
- cb = self.callback(export.tp, export.func)
- export.cb = cb
- setattr(lib, name, cb)
- return lib
-
-
-class _PyExport(object):
- def __init__(self, tp, func):
- self.tp = tp
- self.func = func
-
-
-if __name__ == '__main__':
- ffi = PythonFFI()
-
- @ffi.pyexport("int(int)")
- def add1(n):
- print n
- return n + 1
-
- ffi.cdef("""
- int f(int);
- """)
-
- lib = ffi.verify("""
- int f(int x) {
- return add1(add1(x));
- }
- """)
-
- assert lib.f(5) == 7
diff --git a/demo/bsdopendirtype.py b/demo/bsdopendirtype.py
deleted file mode 100644
index 75a996a..0000000
--- a/demo/bsdopendirtype.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from _bsdopendirtype import ffi, lib
-
-
-def _posix_error():
- raise OSError(ffi.errno, os.strerror(ffi.errno))
-
-_dtype_to_smode = {
- lib.DT_BLK: 0o060000,
- lib.DT_CHR: 0o020000,
- lib.DT_DIR: 0o040000,
- lib.DT_FIFO: 0o010000,
- lib.DT_LNK: 0o120000,
- lib.DT_REG: 0o100000,
- lib.DT_SOCK: 0o140000,
-}
-
-def opendir(dir):
- if len(dir) == 0:
- dir = b'.'
- dirname = dir
- if not dirname.endswith(b'/'):
- dirname += b'/'
- dirp = lib.opendir(dir)
- if dirp == ffi.NULL:
- raise _posix_error()
- try:
- while True:
- ffi.errno = 0
- dirent = lib.readdir(dirp)
- if dirent == ffi.NULL:
- if ffi.errno != 0:
- raise _posix_error()
- return
- name = ffi.string(dirent.d_name)
- if name == b'.' or name == b'..':
- continue
- name = dirname + name
- try:
- smode = _dtype_to_smode[dirent.d_type]
- except KeyError:
- smode = os.lstat(name).st_mode
- yield name, smode
- finally:
- lib.closedir(dirp)
-
-if __name__ == '__main__':
- for name, smode in opendir(b'/tmp'):
- print(hex(smode), name)
diff --git a/demo/bsdopendirtype_build.py b/demo/bsdopendirtype_build.py
deleted file mode 100644
index 3c5bb0b..0000000
--- a/demo/bsdopendirtype_build.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from cffi import FFI
-
-ffibuilder = FFI()
-ffibuilder.cdef("""
- typedef ... DIR;
- struct dirent {
- unsigned char d_type; /* type of file */
- char d_name[]; /* filename */
- ...;
- };
- DIR *opendir(const char *name);
- int closedir(DIR *dirp);
- struct dirent *readdir(DIR *dirp);
- static const int DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK;
-""")
-
-ffibuilder.set_source("_bsdopendirtype", """
- #include <sys/types.h>
- #include <dirent.h>
-""")
-
-if __name__ == '__main__':
- ffibuilder.compile(verbose=True)
diff --git a/demo/bsdopendirtype_setup.py b/demo/bsdopendirtype_setup.py
deleted file mode 100644
index 30a6cfb..0000000
--- a/demo/bsdopendirtype_setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from setuptools import setup
-
-setup(
- name="example",
- version="0.1",
- py_modules=["bsdopendirtype"],
- setup_requires=["cffi>=1.0.dev0"],
- cffi_modules=[
- "bsdopendirtype_build.py:ffibuilder",
- ],
- install_requires=["cffi>=1.0.dev0"], # should maybe be "cffi-backend" only?
- zip_safe=False,
-)
diff --git a/demo/btrfs-snap.py b/demo/btrfs-snap.py
deleted file mode 100644
index fceeaa1..0000000
--- a/demo/btrfs-snap.py
+++ /dev/null
@@ -1,52 +0,0 @@
-"""
-btrfs-snap.py: source target newname
-
-creates a exactly named snapshots and bails out if they exist
-"""
-
-import argparse
-import fcntl
-import os
-import sys
-
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.cdef("""
- #define BTRFS_IOC_SNAP_CREATE_V2 ...
- struct btrfs_ioctl_vol_args_v2 {
- int64_t fd;
- char name[];
- ...;
- };
-""")
-
-ffi.set_source("_btrfs_cffi", "#include <btrfs/ioctl.h>")
-ffi.compile()
-
-# ____________________________________________________________
-
-
-from _btrfs_cffi import ffi, lib
-
-parser = argparse.ArgumentParser(usage=__doc__.strip())
-parser.add_argument('source', help='source subvolume')
-parser.add_argument('target', help='target directory')
-parser.add_argument('newname', help='name of the new snapshot')
-opts = parser.parse_args()
-
-source = os.open(opts.source, os.O_DIRECTORY)
-target = os.open(opts.target, os.O_DIRECTORY)
-
-
-args = ffi.new('struct btrfs_ioctl_vol_args_v2 *')
-args.name = opts.newname
-args.fd = source
-args_buffer = ffi.buffer(args)
-try:
- fcntl.ioctl(target, lib.BTRFS_IOC_SNAP_CREATE_V2, args_buffer)
-except IOError as e:
- print e
- sys.exit(1)
-
diff --git a/demo/cffi-cocoa.py b/demo/cffi-cocoa.py
deleted file mode 100644
index 9e86d99..0000000
--- a/demo/cffi-cocoa.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Based on http://cocoawithlove.com/2010/09/minimalist-cocoa-programming.html
-# by Juraj Sukop. This demo was eventually expanded into a more complete
-# Cocoa library available at https://bitbucket.org/sukop/nspython .
-
-from cffi import FFI
-
-ffi = FFI()
-ffi.cdef('''
-
- typedef signed char BOOL;
-
- typedef long NSInteger;
- typedef unsigned long NSUInteger;
- typedef NSInteger NSApplicationActivationPolicy;
- typedef NSUInteger NSBackingStoreType;
- typedef NSUInteger NSStringEncoding;
-
- typedef double CGFloat;
- struct CGPoint {
- CGFloat x;
- CGFloat y;
- };
- typedef struct CGPoint CGPoint;
- struct CGSize {
- CGFloat width;
- CGFloat height;
- };
- typedef struct CGSize CGSize;
- struct CGRect {
- CGPoint origin;
- CGSize size;
- };
- typedef struct CGRect CGRect;
-
- typedef CGPoint NSPoint;
- typedef CGSize NSSize;
- typedef CGRect NSRect;
-
- typedef struct objc_class *Class;
- typedef struct objc_object {
- Class isa;
- } *id;
- typedef struct objc_selector *SEL;
-
- SEL sel_registerName(const char *str);
- id objc_getClass(const char *name);
- id objc_msgSend(id theReceiver, SEL theSelector, ...);
-
-''')
-
-objc = ffi.dlopen('objc')
-appkit = ffi.dlopen('AppKit')
-
-nil = ffi.NULL
-YES = ffi.cast('BOOL', 1)
-NO = ffi.cast('BOOL', 0)
-
-NSASCIIStringEncoding = ffi.cast('NSStringEncoding', 1)
-NSApplicationActivationPolicyRegular = ffi.cast('NSApplicationActivationPolicy', 0)
-NSTitledWindowMask = ffi.cast('NSUInteger', 1)
-NSBackingStoreBuffered = ffi.cast('NSBackingStoreType', 2)
-
-NSMakePoint = lambda x, y: ffi.new('NSPoint *', (x, y))[0]
-NSMakeRect = lambda x, y, w, h: ffi.new('NSRect *', ((x, y), (w, h)))[0]
-
-get, send, sel = objc.objc_getClass, objc.objc_msgSend, objc.sel_registerName
-at = lambda s: send(
- get('NSString'),
- sel('stringWithCString:encoding:'),
- ffi.new('char[]', s), NSASCIIStringEncoding)
-
-send(get('NSAutoreleasePool'), sel('new'))
-app = send(get('NSApplication'), sel('sharedApplication'))
-send(app, sel('setActivationPolicy:'), NSApplicationActivationPolicyRegular)
-
-menubar = send(send(get('NSMenu'), sel('new')), sel('autorelease'))
-appMenuItem = send(send(get('NSMenuItem'), sel('new')), sel('autorelease'))
-send(menubar, sel('addItem:'), appMenuItem)
-send(app, sel('setMainMenu:'), menubar)
-
-appMenu = send(send(get('NSMenu'), sel('new')), sel('autorelease'))
-appName = send(send(get('NSProcessInfo'), sel('processInfo')), sel('processName'))
-quitTitle = send(at('Quit '), sel('stringByAppendingString:'), appName)
-quitMenuItem = send(send(send(
- get('NSMenuItem'), sel('alloc')),
- sel('initWithTitle:action:keyEquivalent:'),
- quitTitle, sel('terminate:'), at('q')),
- sel('autorelease'))
-send(appMenu, sel('addItem:'), quitMenuItem)
-send(appMenuItem, sel('setSubmenu:'), appMenu)
-
-window = send(send(send(
- get('NSWindow'), sel('alloc')),
- sel('initWithContentRect:styleMask:backing:defer:'),
- NSMakeRect(0, 0, 200, 200), NSTitledWindowMask, NSBackingStoreBuffered, NO),
- sel('autorelease'))
-send(window, sel('cascadeTopLeftFromPoint:'), NSMakePoint(20, 20))
-send(window, sel('setTitle:'), appName)
-send(window, sel('makeKeyAndOrderFront:'), nil)
-
-send(app, sel('activateIgnoringOtherApps:'), YES)
-send(app, sel('run'))
diff --git a/demo/embedding.py b/demo/embedding.py
deleted file mode 100644
index b15c050..0000000
--- a/demo/embedding.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import cffi
-
-ffibuilder = cffi.FFI()
-
-ffibuilder.embedding_api("""
- int add(int, int);
-""")
-
-ffibuilder.embedding_init_code("""
- from _embedding_cffi import ffi
- print("preparing") # printed once
-
- @ffi.def_extern()
- def add(x, y):
- print("adding %d and %d" % (x, y))
- return x + y
-""")
-
-ffibuilder.set_source("_embedding_cffi", "")
-
-ffibuilder.compile(verbose=True)
diff --git a/demo/embedding_test.c b/demo/embedding_test.c
deleted file mode 100644
index ede8cb9..0000000
--- a/demo/embedding_test.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/* There are two options:
-
- =====1=====
-
- Link this program with _embedding_test.so.
- E.g. with gcc:
-
- gcc -o embedding_test embedding_test.c _embedding_cffi*.so
-
- You must then run the executable with the right command
- (LD_LIBRARY_PATH on Linux), otherwise it won't find the
- _embedding_cffi*.so:
-
- LD_LIBRARY_PATH=. ./embedding_test
-
- There are platform-specific options to gcc to avoid needing
- that, too. Linux:
-
- gcc -o embedding_test embedding_test.c _embedding_cffi*.so \
- -Wl,-rpath=\$ORIGIN/
-
- =====2=====
-
- Compile and link the _embedding_test.c source code together with
- this example (e.g. with PyPy):
-
- gcc -o embedding_test embedding_test.c _embedding_cffi.c \
- -I/opt/pypy/include -pthread -lpypy-c
-*/
-
-#include <stdio.h>
-
-extern int add(int x, int y);
-
-
-int main(void)
-{
- int res = add(40, 2);
- printf("result: %d\n", res);
- res = add(100, -5);
- printf("result: %d\n", res);
- return 0;
-}
diff --git a/demo/extern_python.py b/demo/extern_python.py
deleted file mode 100644
index f315cc5..0000000
--- a/demo/extern_python.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.cdef("""int my_algo(int); extern "Python" int f(int);""")
-
-ffi.set_source("_extern_python_cffi", """
- static int f(int);
- static int my_algo(int n) {
- int i, sum = 0;
- for (i = 0; i < n; i++)
- sum += f(i);
- return sum;
- }
-""")
-
-ffi.compile()
-
-
-from _extern_python_cffi import ffi, lib
-
-@ffi.def_extern()
-def f(n):
- return n * n
-
-assert lib.my_algo(10) == 0+1+4+9+16+25+36+49+64+81
diff --git a/demo/extern_python_varargs.py b/demo/extern_python_varargs.py
deleted file mode 100644
index ee78079..0000000
--- a/demo/extern_python_varargs.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.cdef("""
- int my_algo(int);
- typedef ... va_list;
- extern "Python" int f(int, va_list *);
-
- int fetch_int(va_list *);
- double fetch_double(va_list *);
- void *fetch_ptr(va_list *);
-""")
-
-ffi.set_source("_extern_python_cffi", """
- #include <stdarg.h>
-
- static int f(int, va_list *);
-
- static int f1(int n, ...)
- {
- va_list ap;
- va_start(ap, n);
- int res = f(n, &ap);
- va_end(ap);
- return res;
- }
-
- static int fetch_int(va_list *va) { return va_arg((*va), int); }
- static double fetch_double(va_list *va) { return va_arg((*va), double); }
- static void * fetch_ptr(va_list *va) { return va_arg((*va), void *); }
-
- static int my_algo(int n) {
- return f1(3, n, n+1, n+2) + f1(1, &n) + f1(2, 12.3, 45.6);
- }
-""")
-
-ffi.compile()
-
-
-from _extern_python_cffi import ffi, lib
-
-@ffi.def_extern()
-def f(n, va):
- if n == 3:
- x = lib.fetch_int(va)
- y = lib.fetch_int(va)
- z = lib.fetch_int(va)
- print (x, y, z)
- elif n == 1:
- ptr = lib.fetch_ptr(va)
- print 'ptr to:', ffi.cast("int *", ptr)[0]
- elif n == 2:
- x = lib.fetch_double(va)
- y = lib.fetch_double(va)
- print (x, y)
- else:
- raise AssertionError(n)
- return 14
-
-print lib.my_algo(10)
diff --git a/demo/fastcsv.py b/demo/fastcsv.py
deleted file mode 100644
index 6b8d0b4..0000000
--- a/demo/fastcsv.py
+++ /dev/null
@@ -1,266 +0,0 @@
-import csv
-import cffi
-
-# IN-PROGRESS. See the demo at the end of the file
-
-
-def _make_ffi_from_dialect(dialect_name):
- dialect = csv.get_dialect(dialect_name)
-
- ffi = cffi.FFI()
-
- ffi.cdef("""
- long parse_line(char *rawline, long inputlength);
- """)
-
- d = {'quotechar': ord(dialect.quotechar),
- 'quoting': int(dialect.quoting),
- 'skipinitialspace': int(dialect.skipinitialspace),
- 'delimiter': ord(dialect.delimiter),
- 'doublequote': int(dialect.doublequote),
- 'strict': int(dialect.strict),
- }
- if dialect.escapechar is not None:
- d['is_escape_char'] = '== %d' % ord(dialect.escapechar)
- else:
- d['is_escape_char'] = '&& 0'
-
- ffi.set_source('_fastcsv_' + dialect_name, r'''
-
- typedef enum {
- START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD,
- IN_QUOTED_FIELD, ESCAPE_IN_QUOTED_FIELD, QUOTE_IN_QUOTED_FIELD,
- EAT_CRNL
- } ParserState;
-
- typedef enum {
- QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE
- } QuoteStyle;
-
- typedef struct {
- ParserState state; /* current CSV parse state */
- char *field; /* build current field in here */
- int field_size; /* size of allocated buffer */
- int field_len; /* length of current field */
- int numeric_field; /* treat field as numeric */
- } ReaderObj;
-
- static void
- parse_add_char(ReaderObj *self, char c)
- {
- *self->field++ = c;
- }
-
- static void
- parse_save_field(ReaderObj *self)
- {
- *self->field++ = 0;
- }
-
- static int
- parse_process_char(ReaderObj *self, char c)
- {
- switch (self->state) {
- case START_RECORD:
- /* start of record */
- if (c == '\0')
- /* empty line - return [] */
- break;
- else if (c == '\n' || c == '\r') {
- self->state = EAT_CRNL;
- break;
- }
- /* normal character - handle as START_FIELD */
- self->state = START_FIELD;
- /* fallthru */
- case START_FIELD:
- /* expecting field */
- if (c == '\n' || c == '\r' || c == '\0') {
- /* save empty field - return [fields] */
- parse_save_field(self);
- self->state = (c == '\0' ? START_RECORD : EAT_CRNL);
- }
- else if (c == %(quotechar)d &&
- %(quoting)d != QUOTE_NONE) {
- /* start quoted field */
- self->state = IN_QUOTED_FIELD;
- }
- else if (c %(is_escape_char)s) {
- /* possible escaped character */
- self->state = ESCAPED_CHAR;
- }
- else if (c == ' ' && %(skipinitialspace)d)
- /* ignore space at start of field */
- ;
- else if (c == %(delimiter)d) {
- /* save empty field */
- parse_save_field(self);
- }
- else {
- /* begin new unquoted field */
- if (%(quoting)d == QUOTE_NONNUMERIC)
- self->numeric_field = 1;
- parse_add_char(self, c);
- self->state = IN_FIELD;
- }
- break;
-
- case ESCAPED_CHAR:
- if (c == '\0')
- c = '\n';
- parse_add_char(self, c);
- self->state = IN_FIELD;
- break;
-
- case IN_FIELD:
- /* in unquoted field */
- if (c == '\n' || c == '\r' || c == '\0') {
- /* end of line - return [fields] */
- parse_save_field(self);
- self->state = (c == '\0' ? START_RECORD : EAT_CRNL);
- }
- else if (c %(is_escape_char)s) {
- /* possible escaped character */
- self->state = ESCAPED_CHAR;
- }
- else if (c == %(delimiter)d) {
- /* save field - wait for new field */
- parse_save_field(self);
- self->state = START_FIELD;
- }
- else {
- /* normal character - save in field */
- parse_add_char(self, c);
- }
- break;
-
- case IN_QUOTED_FIELD:
- /* in quoted field */
- if (c == '\0')
- ;
- else if (c %(is_escape_char)s) {
- /* Possible escape character */
- self->state = ESCAPE_IN_QUOTED_FIELD;
- }
- else if (c == %(quotechar)d &&
- %(quoting)d != QUOTE_NONE) {
- if (%(doublequote)d) {
- /* doublequote; " represented by "" */
- self->state = QUOTE_IN_QUOTED_FIELD;
- }
- else {
- /* end of quote part of field */
- self->state = IN_FIELD;
- }
- }
- else {
- /* normal character - save in field */
- parse_add_char(self, c);
- }
- break;
-
- case ESCAPE_IN_QUOTED_FIELD:
- if (c == '\0')
- c = '\n';
- parse_add_char(self, c);
- self->state = IN_QUOTED_FIELD;
- break;
-
- case QUOTE_IN_QUOTED_FIELD:
- /* doublequote - seen a quote in an quoted field */
- if (%(quoting)d != QUOTE_NONE &&
- c == %(quotechar)d) {
- /* save "" as " */
- parse_add_char(self, c);
- self->state = IN_QUOTED_FIELD;
- }
- else if (c == %(delimiter)d) {
- /* save field - wait for new field */
- parse_save_field(self);
- self->state = START_FIELD;
- }
- else if (c == '\n' || c == '\r' || c == '\0') {
- /* end of line - return [fields] */
- parse_save_field(self);
- self->state = (c == '\0' ? START_RECORD : EAT_CRNL);
- }
- else if (!%(strict)d) {
- parse_add_char(self, c);
- self->state = IN_FIELD;
- }
- else {
- /* illegal */
- /*PyErr_Format(error_obj, "'%%c' expected after '%%c'",
- dialect->delimiter,
- dialect->quotechar);*/
- return -1;
- }
- break;
-
- case EAT_CRNL:
- if (c == '\n' || c == '\r')
- ;
- else if (c == '\0')
- self->state = START_RECORD;
- else {
- /*PyErr_Format(error_obj, "new-line character seen in unquoted field - do you need to open the file in universal-newline mode?");*/
- return -1;
- }
- break;
-
- }
- return 0;
- }
-
- static void
- parse_reset(ReaderObj *self, char *rawline)
- {
- self->field = rawline;
- self->state = START_RECORD;
- self->numeric_field = 0;
- }
-
- long parse_line(char *rawline, long inputlength)
- {
- char *p;
- ReaderObj reader;
- parse_reset(&reader, rawline);
-
- for (p=rawline; inputlength > 0; inputlength--, p++) {
- if (parse_process_char(&reader, *p) < 0)
- return -1;
- }
- if (parse_process_char(&reader, 0) < 0)
- return -1;
- return reader.field - rawline - 1;
- }
- ''' % d)
-
- ffi.compile()
-
-
-def fastcsv_reader(f, dialect_name):
- try:
- module = __import__('_fastcsv_' + dialect_name)
- except ImportError:
- _make_ffi_from_dialect(dialect_name)
- module = __import__('_fastcsv_' + dialect_name)
- ffi, lib = module.ffi, module.lib
- #
- linelen = -1
- for line in f:
- if linelen <= len(line):
- linelen = 2 * len(line)
- rawline = ffi.new("char[]", linelen)
- ffi.buffer(rawline, len(line))[:] = line
- n = lib.parse_line(rawline, len(line))
- assert n >= 0
- yield ffi.buffer(rawline, n)[:].split('\x00')
-
-
-if __name__ == '__main__':
- csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
- with open('/etc/passwd', 'rb') as f:
- reader = fastcsv_reader(f, 'unixpwd')
- for row in reader:
- print row
diff --git a/demo/gmp.py b/demo/gmp.py
deleted file mode 100644
index 44f233c..0000000
--- a/demo/gmp.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import sys
-#
-# This is only a demo based on the GMP library.
-# There is a rather more complete (but perhaps outdated) version available at:
-# http://bazaar.launchpad.net/~tolot-solar-empire/+junk/gmpy_cffi/files
-#
-
-try:
- from _gmp_cffi import ffi, lib
-except ImportError:
- print 'run gmp_build first, then make sure the shared object is on sys.path'
- sys.exit(1)
-
-# ffi "knows" about the declared variables and functions from the
-# cdef parts of the module created from gmp_build
-# lib "knows" how to call the functions from the set_source parts
-# of the module.
-
-# ____________________________________________________________
-
-a = ffi.new("mpz_t")
-b = ffi.new("mpz_t")
-
-if len(sys.argv) < 3:
- print 'call as %s bigint1, bigint2' % sys.argv[0]
- sys.exit(2)
-
-lib.mpz_init_set_str(a, sys.argv[1], 10) # Assume decimal integers
-lib.mpz_init_set_str(b, sys.argv[2], 10) # Assume decimal integers
-lib.mpz_add(a, a, b) # a=a+b
-
-s = lib.mpz_get_str(ffi.NULL, 10, a)
-print ffi.string(s)
diff --git a/demo/gmp_build.py b/demo/gmp_build.py
deleted file mode 100644
index e1a6000..0000000
--- a/demo/gmp_build.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import cffi
-
-#
-# This is only a demo based on the GMP library.
-# There is a rather more complete (but perhaps outdated) version available at:
-# http://bazaar.launchpad.net/~tolot-solar-empire/+junk/gmpy_cffi/files
-#
-
-ffibuilder = cffi.FFI()
-
-ffibuilder.cdef("""
-
- typedef struct { ...; } MP_INT;
- typedef MP_INT mpz_t[1];
-
- int mpz_init_set_str (MP_INT *dest_integer, char *src_cstring, int base);
- void mpz_add (MP_INT *sum, MP_INT *addend1, MP_INT *addend2);
- char * mpz_get_str (char *string, int base, MP_INT *integer);
-
-""")
-
-ffibuilder.set_source('_gmp_cffi', "#include <gmp.h>",
- libraries=['gmp', 'm'])
-
-if __name__ == '__main__':
- ffibuilder.compile(verbose=True)
diff --git a/demo/manual.c b/demo/manual.c
deleted file mode 100644
index 5b360e8..0000000
--- a/demo/manual.c
+++ /dev/null
@@ -1,166 +0,0 @@
-#include "_cffi_include.h"
-
-
-#define AA (42)
-#define BB (&bb)
-static int bb = 16261;
-
-int foo42(int a, int *b)
-{
- return a - *b;
-}
-
-int foo64(int a)
-{
- return ~a;
-}
-
-struct foo_s {
- int a;
-};
-
-/************************************************************/
-
-static void *_cffi_types[] = {
- _CFFI_OP(_CFFI_OP_FUNCTION, 1),
- _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_INT),
- _CFFI_OP(_CFFI_OP_POINTER, 1),
- _CFFI_OP(_CFFI_OP_FUNCTION_END, 0),
- _CFFI_OP(_CFFI_OP_FUNCTION, 1),
- _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_INT),
- _CFFI_OP(_CFFI_OP_FUNCTION_END, 0),
- _CFFI_OP(_CFFI_OP_STRUCT_UNION, 0),
-};
-
-#ifndef PYPY_VERSION
-static PyObject *
-_cffi_f_foo42(PyObject *self, PyObject *args)
-{
- int x0;
- int * x1;
- Py_ssize_t datasize;
- int result;
- PyObject *arg0;
- PyObject *arg1;
-
- if (!PyArg_ParseTuple(args, "OO:foo42", &arg0, &arg1))
- return NULL;
-
- x0 = _cffi_to_c_int(arg0, int);
- if (x0 == (int)-1 && PyErr_Occurred())
- return NULL;
-
- datasize = _cffi_prepare_pointer_call_argument(
- _cffi_types[1], arg1, (char **)&x1);
- if (datasize != 0) {
- if (datasize < 0)
- return NULL;
- x1 = alloca(datasize);
- memset((void *)x1, 0, datasize);
- if (_cffi_convert_array_from_object((char *)x1, _cffi_types[1], arg1) < 0)
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- _cffi_restore_errno();
- { result = foo42(x0, x1); }
- _cffi_save_errno();
- Py_END_ALLOW_THREADS
-
- return _cffi_from_c_int(result, int);
-}
-#else
-static int _cffi_f_foo42(int x0, int *x1)
-{
- return foo42(x0, x1);
-}
-#endif
-
-#ifndef PYPY_VERSION
-static PyObject *
-_cffi_f_foo64(PyObject *self, PyObject *arg0)
-{
- int x0;
- int result;
-
- x0 = _cffi_to_c_int(arg0, int);
- if (x0 == (int)-1 && PyErr_Occurred())
- return NULL;
-
- Py_BEGIN_ALLOW_THREADS
- _cffi_restore_errno();
- { result = foo64(x0); }
- _cffi_save_errno();
- Py_END_ALLOW_THREADS
-
- return _cffi_from_c_int(result, int);
-}
-#else
-static int _cffi_f_foo64(int x0)
-{
- return foo64(x0);
-}
-#endif
-
-static int _cffi_const_AA(unsigned long long *output)
-{
- *output = (unsigned long long)((AA) << 0); // integer
- return (AA) <= 0;
-}
-
-static void _cffi_const_BB(char *output)
-{
- *(int **)output = BB;
-}
-
-static const struct _cffi_global_s _cffi_globals[] = {
- { "AA", &_cffi_const_AA, _CFFI_OP(_CFFI_OP_CONSTANT_INT, 0) },
- { "BB", &_cffi_const_BB, _CFFI_OP(_CFFI_OP_CONSTANT, 2) },
- { "bb", &bb, _CFFI_OP(_CFFI_OP_GLOBAL_VAR, 1) },
- { "foo42", &_cffi_f_foo42, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_V, 0) },
- { "foo64", &_cffi_f_foo64, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_O, 4) },
-};
-
-struct _cffi_align_foo_s { char x; struct foo_s y; };
-
-static const struct _cffi_struct_union_s _cffi_struct_unions[] = {
- { "foo_s", 7, 0,
- sizeof(struct foo_s),
- offsetof(struct _cffi_align_foo_s, y),
- 1, 0 },
-};
-
-static const struct _cffi_field_s _cffi_fields[] = {
- { "a", offsetof(struct foo_s, a), sizeof(((struct foo_s *)0)->a),
- _CFFI_OP(_CFFI_OP_NOOP, 1) },
-};
-
-static const struct _cffi_type_context_s _cffi_type_context = {
- _cffi_types,
- _cffi_globals,
- _cffi_fields,
- _cffi_struct_unions,
- NULL,
- NULL,
- 5, /* num_globals */
- 1, /* num_struct_unions */
- 0,
- 0,
- NULL,
- 8, /* num_types */
-};
-
-#ifndef PYPY_VERSION
-PyMODINIT_FUNC
-initmanual(void)
-{
- _cffi_init("manual", 0x2601, &_cffi_type_context);
-}
-#else
-PyMODINIT_FUNC
-_cffi_pypyinit_manual(const void *p[])
-{
- p[0] = (const void *)0x2601;
- p[1] = &_cffi_type_context;
-}
-#endif
diff --git a/demo/manual2.py b/demo/manual2.py
deleted file mode 100644
index 2986244..0000000
--- a/demo/manual2.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import _cffi_backend
-
-ffi = _cffi_backend.FFI(b"manual2",
- _version = 0x2601,
- _types = b'\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x00\x09\x00\x00\x00\x0B\x00\x00\x01\x03',
- _globals = (b'\xff\xff\xff\x0bAA',0,b'\xff\xff\xff\x0bBB',-1,b'\xff\xff\xff\x0bCC',2,b'\xff\xff\xff\x1fFOO',0x9999999999999999,b'\x00\x00\x00#close',0,b'\x00\x00\x05#stdout',0),
- _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x00point_s',b'\x00\x00\x01\x11\xff\xff\xff\xffx',b'\x00\x00\x01\x11\xff\xff\xff\xffy'),),
- _enums = (b'\x00\x00\x00\x04\x00\x00\x00\x07myenum_e\x00AA,BB,CC',),
- _typenames = (b'\x00\x00\x00\x01myint_t',),
-)
-
-
-
-# trying it out
-lib = ffi.dlopen(None)
-assert lib.AA == 0
-assert lib.BB == -1
-assert lib.FOO == 0x9999999999999999
-x = lib.close(-42)
-assert x == -1
-
-print lib.stdout
-
-print ffi.new("struct point_s *")
-print ffi.offsetof("struct point_s", "x")
-print ffi.offsetof("struct point_s", "y")
-print ffi.new("struct point_s[CC]")
-assert ffi.sizeof("struct point_s[CC]") == 2 * ffi.sizeof("struct point_s")
-
-print ffi.cast("enum myenum_e", 2)
-print ffi.cast("myint_t", -2)
-assert ffi.typeof("myint_t") == ffi.typeof("int")
-
-del ffi, lib
diff --git a/demo/pwuid.py b/demo/pwuid.py
deleted file mode 100644
index dda9299..0000000
--- a/demo/pwuid.py
+++ /dev/null
@@ -1,7 +0,0 @@
-import sys, os
-
-# run pwuid_build first, then make sure the shared object is on sys.path
-from _pwuid_cffi import ffi, lib
-
-
-print ffi.string(lib.getpwuid(0).pw_name)
diff --git a/demo/pwuid_build.py b/demo/pwuid_build.py
deleted file mode 100644
index 7ef0d76..0000000
--- a/demo/pwuid_build.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from cffi import FFI
-ffi = FFI()
-ffi.cdef(""" // some declarations from the man page
- struct passwd {
- char *pw_name;
- ...;
- };
- struct passwd *getpwuid(int uid);
-""")
-
-ffi.set_source('_pwuid_cffi', """ // passed to the real C compiler
-#include <sys/types.h>
-#include <pwd.h>
-""")
-
-
-if __name__ == '__main__':
- ffi.compile()
diff --git a/demo/py.cleanup b/demo/py.cleanup
deleted file mode 100755
index 512389f..0000000
--- a/demo/py.cleanup
+++ /dev/null
@@ -1,31 +0,0 @@
-#! /usr/bin/env python
-import sys, os, stat
-from bsdopendirtype import opendir
-
-def clean(path):
- global count
- try:
- content = opendir(path)
- except OSError:
- print >> sys.stderr, "skipping", path
- return
- for filename, smode in content:
- if stat.S_ISDIR(smode):
- clean(filename)
- if filename.endswith('/__pycache__'):
- try:
- os.rmdir(filename)
- except OSError:
- pass
- elif (filename.endswith('.pyc') or filename.endswith('.pyo') or
- filename.endswith('.pyc~') or filename.endswith('.pyo~')):
- os.unlink(filename)
- count += 1
-
-count = 0
-
-for arg in sys.argv[1:] or ['.']:
- print "cleaning path", arg, "of .pyc/.pyo/__pycache__ files"
- clean(arg)
-
-print "%d files removed" % (count,)
diff --git a/demo/pyobj.py b/demo/pyobj.py
deleted file mode 100644
index b40343a..0000000
--- a/demo/pyobj.py
+++ /dev/null
@@ -1,124 +0,0 @@
-
-referents = [] # list "object descriptor -> python object"
-freelist = None
-
-def store(x):
- "Store the object 'x' and returns a new object descriptor for it."
- global freelist
- p = freelist
- if p is None:
- p = len(referents)
- referents.append(x)
- else:
- freelist = referents[p]
- referents[p] = x
- return p
-
-def discard(p):
- """Discard (i.e. close) the object descriptor 'p'.
- Return the original object that was attached to 'p'."""
- global freelist
- x = referents[p]
- referents[p] = freelist
- freelist = p
- return x
-
-class Ref(object):
- """For use in 'with Ref(x) as ob': open an object descriptor
- and returns it in 'ob', and close it automatically when the
- 'with' statement finishes."""
- def __init__(self, x):
- self.x = x
- def __enter__(self):
- self.p = p = store(self.x)
- return p
- def __exit__(self, *args):
- discard(self.p)
-
-def count_pyobj_alive():
- result = len(referents)
- p = freelist
- while p is not None:
- assert result > 0
- result -= 1
- p = referents[p]
- return result
-
-# ------------------------------------------------------------
-
-if __name__ == '__main__':
- import api
-
- ffi = api.PythonFFI()
-
- ffi.cdef("""
- typedef int pyobj_t;
- int sum_integers(pyobj_t p_list);
- pyobj_t sum_objects(pyobj_t p_list, pyobj_t p_initial);
- """)
-
- @ffi.pyexport("int(pyobj_t)")
- def length(p_list):
- list = referents[p_list]
- return len(list)
-
- @ffi.pyexport("int(pyobj_t, int)")
- def getitem(p_list, index):
- list = referents[p_list]
- return list[index]
-
- @ffi.pyexport("pyobj_t(pyobj_t)")
- def pyobj_dup(p):
- return store(referents[p])
-
- @ffi.pyexport("void(pyobj_t)")
- def pyobj_close(p):
- discard(p)
-
- @ffi.pyexport("pyobj_t(pyobj_t, int)")
- def pyobj_getitem(p_list, index):
- list = referents[p_list]
- return store(list[index])
-
- @ffi.pyexport("pyobj_t(pyobj_t, pyobj_t)")
- def pyobj_add(p1, p2):
- return store(referents[p1] + referents[p2])
-
- lib = ffi.verify("""
- typedef int pyobj_t; /* an "object descriptor" number */
-
- int sum_integers(pyobj_t p_list) {
- /* this a demo function written in C, using the API
- defined above: length() and getitem(). */
- int i, result = 0;
- int count = length(p_list);
- for (i=0; i<count; i++) {
- int n = getitem(p_list, i);
- result += n;
- }
- return result;
- }
-
- pyobj_t sum_objects(pyobj_t p_list, pyobj_t p_initial) {
- /* same as above, but keeps all additions as Python objects */
- int i;
- int count = length(p_list);
- pyobj_t p1 = pyobj_dup(p_initial);
- for (i=0; i<count; i++) {
- pyobj_t p2 = pyobj_getitem(p_list, i);
- pyobj_t p3 = pyobj_add(p1, p2);
- pyobj_close(p2);
- pyobj_close(p1);
- p1 = p3;
- }
- return p1;
- }
- """)
-
- with Ref([10, 20, 30, 40]) as p_list:
- print lib.sum_integers(p_list)
- with Ref(5) as p_initial:
- result = discard(lib.sum_objects(p_list, p_initial))
- print result
-
- assert count_pyobj_alive() == 0
diff --git a/demo/readdir.py b/demo/readdir.py
deleted file mode 100644
index b966246..0000000
--- a/demo/readdir.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# A Linux-only demo
-#
-import sys
-
-if not sys.platform.startswith('linux'):
- raise Exception("Linux-only demo")
-
-from _readdir import ffi
-lib = ffi.dlopen(None)
-
-
-def walk(basefd, path):
- print '{', path
- dirfd = lib.openat(basefd, path, 0)
- if dirfd < 0:
- # error in openat()
- return
- dir = lib.fdopendir(dirfd)
- dirent = ffi.new("struct dirent *")
- result = ffi.new("struct dirent **")
- while True:
- if lib.readdir_r(dir, dirent, result):
- # error in readdir_r()
- break
- if result[0] == ffi.NULL:
- break
- name = ffi.string(dirent.d_name)
- print '%3d %s' % (dirent.d_type, name)
- if dirent.d_type == 4 and name != '.' and name != '..':
- walk(dirfd, name)
- lib.closedir(dir)
- print '}'
-
-
-walk(-1, "/tmp")
diff --git a/demo/readdir2.py b/demo/readdir2.py
deleted file mode 100644
index b564b51..0000000
--- a/demo/readdir2.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# A Linux-only demo, using set_source() instead of hard-coding the exact layouts
-#
-import sys
-
-if not sys.platform.startswith('linux'):
- raise Exception("Linux-only demo")
-
-# run readdir2_build first, then make sure the shared object is on sys.path
-from _readdir2_cffi import ffi, lib
-
-
-def walk(basefd, path):
- print '{', path
- dirfd = lib.openat(basefd, path, 0)
- if dirfd < 0:
- # error in openat()
- return
- dir = lib.fdopendir(dirfd)
- dirent = ffi.new("struct dirent *")
- result = ffi.new("struct dirent **")
- while True:
- if lib.readdir_r(dir, dirent, result):
- # error in readdir_r()
- break
- if result[0] == ffi.NULL:
- break
- name = ffi.string(dirent.d_name)
- print '%3d %s' % (dirent.d_type, name)
- if dirent.d_type == lib.DT_DIR and name != '.' and name != '..':
- walk(dirfd, name)
- lib.closedir(dir)
- print '}'
-
-
-walk(-1, "/tmp")
diff --git a/demo/readdir2_build.py b/demo/readdir2_build.py
deleted file mode 100644
index 5cfd872..0000000
--- a/demo/readdir2_build.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from cffi import FFI
-
-ffi = FFI()
-ffi.cdef("""
-
- typedef ... DIR;
-
- struct dirent {
- unsigned char d_type; /* type of file; not supported
- by all file system types */
- char d_name[...]; /* filename */
- ...;
- };
-
- int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
- int openat(int dirfd, const char *pathname, int flags);
- DIR *fdopendir(int fd);
- int closedir(DIR *dirp);
-
- static const int DT_DIR;
-
-""")
-ffi.set_source("_readdir2_cffi", """
-#ifndef _ATFILE_SOURCE
-# define _ATFILE_SOURCE
-#endif
-#ifndef _BSD_SOURCE
-# define _BSD_SOURCE
-#endif
-#include <fcntl.h>
-#include <sys/types.h>
-#include <dirent.h>
-""")
-
-if __name__ == '__main__':
- ffi.compile()
diff --git a/demo/readdir2_setup.py b/demo/readdir2_setup.py
deleted file mode 100644
index bd8c19f..0000000
--- a/demo/readdir2_setup.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from distutils.core import setup
-import readdir2_build
-
-setup(
- name="readdir2",
- version="0.1",
- py_modules=["readdir2"],
- ext_modules=[readdir2_build.ffi.distutils_extension('build')],
-)
diff --git a/demo/readdir_build.py b/demo/readdir_build.py
deleted file mode 100644
index f97f404..0000000
--- a/demo/readdir_build.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import sys
-from cffi import FFI
-
-if not sys.platform.startswith('linux'):
- raise Exception("Linux-only demo")
-
-
-ffi = FFI()
-ffi.cdef("""
-
- typedef void DIR;
- typedef long ino_t;
- typedef long off_t;
-
- struct dirent {
- ino_t d_ino; /* inode number */
- off_t d_off; /* offset to the next dirent */
- unsigned short d_reclen; /* length of this record */
- unsigned char d_type; /* type of file; not supported
- by all file system types */
- char d_name[256]; /* filename */
- };
-
- int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
- int openat(int dirfd, const char *pathname, int flags);
- DIR *fdopendir(int fd);
- int closedir(DIR *dirp);
-
-""")
-ffi.set_source("_readdir", None)
-
-if __name__ == '__main__':
- ffi.compile()
diff --git a/demo/readdir_ctypes.py b/demo/readdir_ctypes.py
deleted file mode 100644
index 4fd1d17..0000000
--- a/demo/readdir_ctypes.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# A Linux-only demo
-#
-# For comparison purposes, this is a ctypes version of readdir.py.
-import sys
-import ctypes
-
-if not sys.platform.startswith('linux'):
- raise Exception("Linux-only demo")
-
-
-DIR_p = ctypes.c_void_p
-ino_t = ctypes.c_long
-off_t = ctypes.c_long
-
-class DIRENT(ctypes.Structure):
- _fields_ = [
- ('d_ino', ino_t), # inode number
- ('d_off', off_t), # offset to the next dirent
- ('d_reclen', ctypes.c_ushort), # length of this record
- ('d_type', ctypes.c_ubyte), # type of file; not supported
- # by all file system types
- ('d_name', ctypes.c_char * 256), # filename
- ]
-DIRENT_p = ctypes.POINTER(DIRENT)
-DIRENT_pp = ctypes.POINTER(DIRENT_p)
-
-C = ctypes.CDLL(None)
-
-readdir_r = C.readdir_r
-readdir_r.argtypes = [DIR_p, DIRENT_p, DIRENT_pp]
-readdir_r.restype = ctypes.c_int
-
-openat = C.openat
-openat.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int]
-openat.restype = ctypes.c_int
-
-fdopendir = C.fdopendir
-fdopendir.argtypes = [ctypes.c_int]
-fdopendir.restype = DIR_p
-
-closedir = C.closedir
-closedir.argtypes = [DIR_p]
-closedir.restype = ctypes.c_int
-
-
-def walk(basefd, path):
- print '{', path
- dirfd = openat(basefd, path, 0)
- if dirfd < 0:
- # error in openat()
- return
- dir = fdopendir(dirfd)
- dirent = DIRENT()
- result = DIRENT_p()
- while True:
- if readdir_r(dir, dirent, result):
- # error in readdir_r()
- break
- if not result:
- break
- name = dirent.d_name
- print '%3d %s' % (dirent.d_type, name)
- if dirent.d_type == 4 and name != '.' and name != '..':
- walk(dirfd, name)
- closedir(dir)
- print '}'
-
-
-walk(-1, "/tmp")
diff --git a/demo/readdir_setup.py b/demo/readdir_setup.py
deleted file mode 100644
index c8abdcb..0000000
--- a/demo/readdir_setup.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from setuptools import setup
-
-setup(
- name="example",
- version="0.1",
- py_modules=["readdir"],
- setup_requires=["cffi>=1.0.dev0"],
- cffi_modules=["readdir_build.py:ffi"],
- install_requires=["cffi>=1.0.dev0"],
- zip_safe=False,
-)
diff --git a/demo/recopendirtype.py b/demo/recopendirtype.py
deleted file mode 100644
index 768318b..0000000
--- a/demo/recopendirtype.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from _recopendirtype import ffi, lib
-
-
-def _posix_error():
- raise OSError(ffi.errno, os.strerror(ffi.errno))
-
-_dtype_to_smode = {
- lib.DT_BLK: 0o060000,
- lib.DT_CHR: 0o020000,
- lib.DT_DIR: 0o040000,
- lib.DT_FIFO: 0o010000,
- lib.DT_LNK: 0o120000,
- lib.DT_REG: 0o100000,
- lib.DT_SOCK: 0o140000,
-}
-
-def opendir(dir):
- if len(dir) == 0:
- dir = b'.'
- dirname = dir
- if not dirname.endswith(b'/'):
- dirname += b'/'
- dirp = lib.opendir(dir)
- if dirp == ffi.NULL:
- raise _posix_error()
- dirent = ffi.new("struct dirent *")
- result = ffi.new("struct dirent **")
- try:
- while True:
- ffi.errno = 0
- err = lib.readdir_r(dirp, dirent, result)
- if err: # really got an error
- raise OSError(err, os.strerror(err))
- if result[0] == ffi.NULL:
- return #
- name = ffi.string(dirent.d_name)
- if name == b'.' or name == b'..':
- continue
- name = dirname + name
- try:
- smode = _dtype_to_smode[dirent.d_type]
- except KeyError:
- smode = os.lstat(name).st_mode
- yield name, smode
- finally:
- lib.closedir(dirp)
-
-if __name__ == '__main__':
- for name, smode in opendir(b'/tmp'):
- print(hex(smode), name)
diff --git a/demo/recopendirtype_build.py b/demo/recopendirtype_build.py
deleted file mode 100644
index fa62a05..0000000
--- a/demo/recopendirtype_build.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from cffi import FFI
-import bsdopendirtype_build
-
-ffi = FFI()
-
-# ========== This is a demo of ffi.include() ==========
-ffi.include(bsdopendirtype_build.ffi)
-
-ffi.cdef("""
- int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
-""")
-
-ffi.set_source("_recopendirtype", """
- #include <sys/types.h>
- #include <dirent.h>
-""")
-
-if __name__ == '__main__':
- ffi.compile()
diff --git a/demo/setup_manual.py b/demo/setup_manual.py
deleted file mode 100644
index 2569bb4..0000000
--- a/demo/setup_manual.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from distutils.core import setup
-from distutils.extension import Extension
-setup(name='manual',
- ext_modules=[Extension(name='manual',
- sources=['manual.c'])])
diff --git a/demo/winclipboard.py b/demo/winclipboard.py
deleted file mode 100644
index 5278cd0..0000000
--- a/demo/winclipboard.py
+++ /dev/null
@@ -1,40 +0,0 @@
-__author__ = "Israel Fruchter <israel.fruchter@gmail.com>"
-
-import sys, os
-
-if not sys.platform == 'win32':
- raise Exception("Windows-only demo")
-
-try:
- from _winclipboard_cffi import ffi, lib
-except ImportError:
- print 'run winclipboard_build first, then make sure the shared object is on sys.path'
- sys.exit(1)
-
-# ffi "knows" about the declared variables and functions from the
-# cdef parts of the module _winclipboard_cffi created,
-# lib "knows" how to call the functions from the set_source parts
-# of the module.
-
-def CopyToClipboard(string):
- '''
- use win32 api to copy `string` to the clipboard
- '''
- hWnd = lib.GetConsoleWindow()
-
- if lib.OpenClipboard(hWnd):
- cstring = ffi.new("char[]", string)
- size = ffi.sizeof(cstring)
-
- # make it a moveable memory for other processes
- hGlobal = lib.GlobalAlloc(lib.GMEM_MOVEABLE, size)
- buffer = lib.GlobalLock(hGlobal)
- lib.memcpy(buffer, cstring, size)
- lib.GlobalUnlock(hGlobal)
-
- res = lib.EmptyClipboard()
- res = lib.SetClipboardData(lib.CF_TEXT, buffer)
-
- lib.CloseClipboard()
-
-CopyToClipboard("hello world from cffi")
diff --git a/demo/winclipboard_build.py b/demo/winclipboard_build.py
deleted file mode 100644
index 1a510eb..0000000
--- a/demo/winclipboard_build.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from cffi import FFI
-
-ffi = FFI()
-ffi.cdef('''
- typedef void * HANDLE;
- typedef HANDLE HWND;
- typedef int BOOL;
- typedef unsigned int UINT;
- typedef int SIZE_T;
- typedef char * LPTSTR;
- typedef HANDLE HGLOBAL;
- typedef HANDLE LPVOID;
-
- HWND GetConsoleWindow(void);
-
- LPVOID GlobalLock( HGLOBAL hMem );
- BOOL GlobalUnlock( HGLOBAL hMem );
- HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes);
-
- BOOL OpenClipboard(HWND hWndNewOwner);
- BOOL CloseClipboard(void);
- BOOL EmptyClipboard(void);
- HANDLE SetClipboardData(UINT uFormat, HANDLE hMem);
-
- #define CF_TEXT ...
- #define GMEM_MOVEABLE ...
-
- void * memcpy(void * s1, void * s2, int n);
- ''')
-
-ffi.set_source('_winclipboard_cffi', '''
- #include <windows.h>
-''', libraries=["user32"])
-
-if __name__ == '__main__':
- ffi.compile()
diff --git a/demo/xclient.py b/demo/xclient.py
deleted file mode 100644
index e4b3dd2..0000000
--- a/demo/xclient.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import sys, os
-
-# run xclient_build first, then make sure the shared object is on sys.path
-from _xclient_cffi import ffi, lib
-
-
-# ffi "knows" about the declared variables and functions from the
-# cdef parts of the module xclient_build created,
-# lib "knows" how to call the functions from the set_source parts
-# of the module.
-
-
-class XError(Exception):
- pass
-
-def main():
- display = lib.XOpenDisplay(ffi.NULL)
- if display == ffi.NULL:
- raise XError("cannot open display")
- w = lib.XCreateSimpleWindow(display, lib.DefaultRootWindow(display),
- 10, 10, 500, 350, 0, 0, 0)
- lib.XMapRaised(display, w)
- event = ffi.new("XEvent *")
- lib.XNextEvent(display, event)
-
-if __name__ == '__main__':
- main()
diff --git a/demo/xclient_build.py b/demo/xclient_build.py
deleted file mode 100644
index d6ce9da..0000000
--- a/demo/xclient_build.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from cffi import FFI
-ffi = FFI()
-ffi.cdef("""
-
-typedef ... Display;
-typedef struct { ...; } Window;
-
-typedef struct { int type; ...; } XEvent;
-
-Display *XOpenDisplay(char *display_name);
-Window DefaultRootWindow(Display *display);
-int XMapRaised(Display *display, Window w);
-Window XCreateSimpleWindow(Display *display, Window parent, int x, int y,
- unsigned int width, unsigned int height,
- unsigned int border_width, unsigned long border,
- unsigned long background);
-int XNextEvent(Display *display, XEvent *event_return);
-""")
-
-ffi.set_source('_xclient_cffi', """
- #include <X11/Xlib.h>
-""", libraries=['X11'])
-
-if __name__ == '__main__':
- ffi.compile(verbose=True)
diff --git a/doc/Makefile b/doc/Makefile
deleted file mode 100644
index 285361c..0000000
--- a/doc/Makefile
+++ /dev/null
@@ -1,89 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = build
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
-
-.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
-
-clean:
- -rm -rf $(BUILDDIR)/*
-
-html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/CFFI.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/CFFI.qhc"
-
-latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
- "run these through (pdf)latex."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/make.bat b/doc/make.bat
deleted file mode 100644
index 5daa6b5..0000000
--- a/doc/make.bat
+++ /dev/null
@@ -1,113 +0,0 @@
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-set SPHINXBUILD=sphinx-build
-set BUILDDIR=build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. changes to make an overview over all changed/added/deprecated items
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\CFFI.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\CFFI.ghc
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-:end
diff --git a/doc/misc/design.rst b/doc/misc/design.rst
deleted file mode 100644
index 390049c..0000000
--- a/doc/misc/design.rst
+++ /dev/null
@@ -1,51 +0,0 @@
-================
-Design decisions
-================
-
-* Generally follow LuaJIT's ffi: http://luajit.org/ext_ffi.html
-
-* Be explicit: almost no automatic conversions. Here is the set
- of automatic conversions: the various C integer types are
- automatically wrapped and unwrapped to regular applevel integers. The
- type ``char`` might correspond to single-character strings instead;
- for integer correspondance you would use ``signed char`` or ``unsigned
- char``. We might also decide that ``const char *`` automatically maps
- to strings; for cases where you don't want that, use ``char *``.
-
-* Integers are not automatically converted when passed as vararg
- arguments. You have to use explicitly ``ffi.new("int", 42)`` or
- ``ffi.new("long", 42)`` to resolve the ambiguity. Floats would be
- fine (varargs in C can only accept ``double``, not ``float``), but
- there is again ambiguity between characters and strings. Even with
- floats the result is a bit strange because passing a float works
- but passing an integer not. I would fix this once and for all by
- saying that varargs must *always* be a cdata (from ``ffi.new()``).
- The possibly acceptable exception would be None (for ``NULL``).
-
-* The internal class ``blob`` is used for raw-malloced data. You only
- get a class that has internally a ``blob`` instance (or maybe is a
- subclass of ``blob``) by calling ``ffi.new(struct-or-array-type)``.
- The other cases, namely the cases where the type is a pointer or a
- primitive, don't need a blob because it's not possible to take their
- raw address.
-
-* It would be possible to add a debug mode: when we cast ``struct foo``
- to ``struct foo *`` or store it in some other struct, then we would
- additionally record a weakref to the original ``struct foo`` blob.
- If later we try to access the ``struct foo *`` but the weakref shows
- that the blob was freed, we complain. This is a difference with
- ctypes, which in these cases would store a strong reference and
- keep the blob alive. "Explicit is better than implicit", so we ask
- the user to keep a reference to the original blob alive as long as
- it may be used (instead of doing the right things in 90% of the cases
- but still crashing in the remaining 10%).
-
-* LuaJIT uses ``struct foo &`` for a number of things, like for ``p[0]``
- if ``p`` is a ``struct foo *``. I suppose it's not a bad idea at least
- to have internally such types, even if you can't specify them through
- pycparser. Basically ``struct foo &`` is a type that doesn't own a
- blob, whereas ``struct foo`` is the type that does.
-
-* LuaJIT uses ``int[?]`` which pycparser doesn't accept. I propose
- instead to use ``int[]`` for the same purpose (its use is anyway quite
- close to the C standard's use of ``int[]``).
diff --git a/doc/misc/grant-cffi-1.0.rst b/doc/misc/grant-cffi-1.0.rst
deleted file mode 100644
index b026209..0000000
--- a/doc/misc/grant-cffi-1.0.rst
+++ /dev/null
@@ -1,124 +0,0 @@
-
-===========================
-Grant Proposal for CFFI 1.0
-===========================
-
-*Accepted by the PSF board on April 4, 2015*
-
-This Grant Proposal is to give a boost towards "CFFI 1.0". Two main
-issues with the current CFFI need to be solved: the difficulties of
-installation, and the potentially large time taken at import.
-
-1. The difficulties of installation can be seen from outside by looking
-at various workarounds and 3rd-party documentation that have grown into
-existence. For example, the `setup.py` of projects like cryptography,
-PyNaCl and bcrypt deploys workarounds that are explicitly documented in
-https://caremad.io/2014/11/distributing-a-cffi-project/.
-
-2. The time taken at import is excessive in some cases. For example,
-importing `pygame-cffi` on a Raspberry Pi ARM board takes on the order
-of 10 to 20 seconds (and this is the "fast" case where the compiler
-doesn't need to be invoked any more).
-
-
-Technical Overview
-------------------
-
-"CFFI" is an existing Python project which complements the ctypes,
-SWIG and Cython approaches to ease writing C Extension Modules for
-Python. It has several advantages over the previous approaches, which
-are presented at the start of the documentation at
-http://cffi.readthedocs.org/en/latest/ . It has been very successful
-so far: http://pypi-ranking.info/alltime records almost 7 million
-downloads (for comparison, the #1 of all packages has almost 36
-million downloads). CFFI works on any Python >= 2.6, including 3.x,
-as well as on PyPy.
-
-One problem is that while getting started with CFFI is very easy, the
-installation process of a package that uses CFFI has got its rough
-edges. CFFI (at least in its "verify()" mode) is based on calling the
-C compiler to get information about the exact C types, structures,
-argument types to functions, and so on. The C compiler is invoked
-transparently at run-time, and the results cached. A
-correctly-installed package using CFFI should cache the results at
-installation time, but it can be difficult to ensure that no more
-run-time compiler invocation is needed; doing so requires following
-some extra guidelines or understanding some internal details. (The
-problem is particularly acute on Windows where a typical user might
-not have a proper C compiler installed.)
-
-To fix this, we have in mind adding a different CFFI mode (replacing
-"verify()"), while keeping the access to the underlying C library
-unmodified. In this mode, the code containing the cdef() and verify()
-invocations would be moved to a separate Python source file. Running
-that Python file would produce a dynamically-linked library. There
-would be no caching logic involved; you would need to run it
-explicitly during development whenever you made changes to it, to
-re-generate and re-compile the dynamically-linked library.
-
-When distributed, the same file would be run (once) during
-installation. This can be fully automated in setuptools-based
-setup.py files; alternatively, it can be done in distutils-based
-setup.py files by requiring prior manual installation of CFFI itself.
-
-A major difference with the existing verify() approach would be that
-the ``.so/.dll/.dylib`` file would not be immediately loaded into the
-process; you would load it only from the installed program at
-run-time, and get the ``ffi`` and ``lib`` objects in this way (these
-are the two objects that you use so far to access a C library with
-verify()).
-
-Additionally, this would solve another issue: every import of a large
-CFFI-using package takes a while so far. This is caused by CFFI
-needing to parse again the C source code given in the cdef() (adding a
-run-time dependency to the ``pycparser`` and ``ply`` packages). CFFI
-also computes a CRC to know if it can reuse its cache. In the
-proposed change, all the cdef() code would be pre-parsed and stored in
-the dynamically-linked library, and no CRC would be needed. This
-would massively reduce the import times.
-
-
-Grant objective
----------------
-
-The objective is to give a boost towards "CFFI 1.0", which needs to have
-the functionalities described above in order to solve the two main
-issues with the current CFFI: the difficulties of installation, and the
-time taken at import.
-
-Included in the objective: the internal refactorings of CFFI that are
-needed to get it done cleanly. The goal is to avoid simply adding
-another layer on top of the old unchanged CFFI.
-
-This work may happen eventually in any case, but support from the PSF
-would help make it happen sooner rather than later.
-
-
-Grant size
-----------
-
-2'500 US$ for supporting the development time. This would cover 2.5
-weeks of full-time work at the part-time cost of 25 US$ per hour.
-
-The estimated work time until the CFFI 1.0 release is a bit larger
-than that (I estimate it at roughly 4 weeks), but 2.5 weeks should
-cover all the basics. An extended grant size of 4'000 US$ would be
-appreciated but not required ``:-)``
-
-
-Grant beneficiaries
--------------------
-
-Armin Rigo, main author of CFFI, committing 2.5 weeks of full-time
-work.
-
-
-Grant follow-up
----------------
-
-I will report on the success of the grant on the CFFI mailing list and
-on the blog I usually post to (the PyPy blog) and mention the PSF as
-providing the grant. The PSF will receive an email pointing to these
-postings once they are out. Moreover a full CFFI 1.0 release should
-follow (likely starting with beta versions); the PSF will receive
-another email pointing to it.
diff --git a/doc/misc/parse_c_type.rst b/doc/misc/parse_c_type.rst
deleted file mode 100644
index 1d1029d..0000000
--- a/doc/misc/parse_c_type.rst
+++ /dev/null
@@ -1,72 +0,0 @@
-==================================================
-CPython C extension module produced by recompile()
-==================================================
-
-Global variable::
-
- _cffi_opcode_t _cffi_types[];
-
-Every _cffi_types entry is initially an odd integer. At runtime, it
-is fixed to be a `CTypeDescrObject *` when the odd integer is
-interpreted and turned into a real <ctype> object.
-
-The generated C functions are listed in _cffi_globals, a sorted array
-of entries which get turned lazily into real <builtin function
-objects>. Each entry in this array has an index in the _cffi_types
-array, which describe the function type (OP_FUNCTION opcode, see
-below). We turn the odd integers describing argument and return types
-into real CTypeDescrObjects at the point where the entry is turned
-into a real builtin function object.
-
-The odd integers are "opcodes" that contain a type info in the lowest
-byte. The remaining high bytes of the integer is an "arg" that depends
-on the type info:
-
-OP_PRIMITIVE
- the arg tells which primitive type it is (an index in some list)
-
-OP_POINTER
- the arg is the index of the item type in the _cffi_types array.
-
-OP_ARRAY
- the arg is the index of the item type in the _cffi_types array.
- followed by another opcode that contains (uintptr_t)length_of_array.
-
-OP_OPEN_ARRAY
- for syntax like "int[]". same as OP_ARRAY but without the length
-
-OP_STRUCT_UNION
- the arg is the index of the struct/union in _cffi_structs_unions
-
-OP_ENUM
- the arg is the index of the enum in _cffi_enums
-
-OP_TYPENAME
- the arg is the index of the typename in _cffi_typenames
-
-OP_FUNCTION
- the arg is the index of the result type in _cffi_types.
- followed by other opcodes for the arguments.
- terminated by OP_FUNCTION_END.
-
-OP_FUNCTION_END
- the arg's lowest bit is set if there is a "..." argument.
-
-OP_NOOP
- simple indirection: the arg is the index to look further in
-
-There are other opcodes, used not inside _cffi_types but in other
-individual ``type_op`` fields. Most importantly, these are used
-on _cffi_globals entries:
-
-OP_CPYTHON_BLTN_*
- declare a function
-
-OP_CONSTANT
- declare a non-integral constant
-
-OP_CONSTANT_INT
- declare an int constant
-
-OP_GLOBAL_VAR
- declare a global var
diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst
deleted file mode 100644
index 0662668..0000000
--- a/doc/source/cdef.rst
+++ /dev/null
@@ -1,1012 +0,0 @@
-======================================
-Preparing and Distributing modules
-======================================
-
-.. contents::
-
-There are three or four different ways to use CFFI in a project.
-In order of complexity:
-
-* The **"in-line", "ABI mode"**:
-
- .. code-block:: python
-
- import cffi
-
- ffi = cffi.FFI()
- ffi.cdef("C-like declarations")
- lib = ffi.dlopen("libpath")
-
- # use ffi and lib here
-
-.. _out-of-line-abi:
-
-* The **"out-of-line",** but still **"ABI mode",** useful to organize
- the code and reduce the import time:
-
- .. code-block:: python
-
- # in a separate file "package/foo_build.py"
- import cffi
-
- ffibuilder = cffi.FFI()
- ffibuilder.set_source("package._foo", None)
- ffibuilder.cdef("C-like declarations")
-
- if __name__ == "__main__":
- ffibuilder.compile()
-
- Running ``python foo_build.py`` produces a file ``_foo.py``, which
- can then be imported in the main program:
-
- .. code-block:: python
-
- from package._foo import ffi
- lib = ffi.dlopen("libpath")
-
- # use ffi and lib here
-
-.. _out-of-line-api:
-
-* The **"out-of-line", "API mode"** gives you the most flexibility
- and speed to access a C library at the level of C, instead of at the
- binary level:
-
- .. code-block:: python
-
- # in a separate file "package/foo_build.py"
- import cffi
-
- ffibuilder = cffi.FFI()
- ffibuilder.set_source("package._foo", r"""real C code""") # <=
- ffibuilder.cdef("C-like declarations with '...'")
-
- if __name__ == "__main__":
- ffibuilder.compile(verbose=True)
-
- Running ``python foo_build.py`` produces a file ``_foo.c`` and
- invokes the C compiler to turn it into a file ``_foo.so`` (or
- ``_foo.pyd`` or ``_foo.dylib``). It is a C extension module which
- can be imported in the main program:
-
- .. code-block:: python
-
- from package._foo import ffi, lib
- # no ffi.dlopen()
-
- # use ffi and lib here
-
-.. _distutils-setuptools:
-
-* Finally, you can (but don't have to) use CFFI's **Distutils** or
- **Setuptools integration** when writing a ``setup.py``. For
- Distutils (only in out-of-line API mode):
-
- .. code-block:: python
-
- # setup.py (requires CFFI to be installed first)
- from distutils.core import setup
-
- import foo_build # possibly with sys.path tricks to find it
-
- setup(
- ...,
- ext_modules=[foo_build.ffibuilder.distutils_extension()],
- )
-
- For Setuptools (out-of-line, but works in ABI or API mode;
- recommended):
-
- .. code-block:: python
-
- # setup.py (with automatic dependency tracking)
- from setuptools import setup
-
- setup(
- ...,
- setup_requires=["cffi>=1.0.0"],
- cffi_modules=["package/foo_build.py:ffibuilder"],
- install_requires=["cffi>=1.0.0"],
- )
-
- Note again that the ``foo_build.py`` example contains the following
- lines, which mean that the ``ffibuilder`` is not actually compiled
- when ``package.foo_build`` is merely imported---it will be compiled
- independently by the Setuptools logic, using compilation parameters
- provided by Setuptools:
-
- .. code-block:: python
-
- if __name__ == "__main__": # not when running with setuptools
- ffibuilder.compile(verbose=True)
-
-* Note that some bundler tools that try to find all modules used by a
- project, like PyInstaller, will miss ``_cffi_backend`` in the
- out-of-line mode because your program contains no explicit ``import
- cffi`` or ``import _cffi_backend``. You need to add
- ``_cffi_backend`` explicitly (as a "hidden import" in PyInstaller,
- but it can also be done more generally by adding the line ``import
- _cffi_backend`` in your main program).
-
-Note that CFFI actually contains two different ``FFI`` classes. The
-page `Using the ffi/lib objects`_ describes the common functionality.
-It is what you get in the ``from package._foo import ffi`` lines above.
-On the other hand, the extended ``FFI`` class is the one you get from
-``import cffi; ffi_or_ffibuilder = cffi.FFI()``. It has the same
-functionality (for in-line use), but also the extra methods described
-below (to prepare the FFI). NOTE: We use the name ``ffibuilder``
-instead of ``ffi`` in the out-of-line context, when the code is about
-producing a ``_foo.so`` file; this is an attempt to distinguish it
-from the different ``ffi`` object that you get by later saying
-``from _foo import ffi``.
-
-.. _`Using the ffi/lib objects`: using.html
-
-The reason for this split of functionality is that a regular program
-using CFFI out-of-line does not need to import the ``cffi`` pure
-Python package at all. (Internally it still needs ``_cffi_backend``,
-a C extension module that comes with CFFI; this is why CFFI is also
-listed in ``install_requires=..`` above. In the future this might be
-split into a different PyPI package that only installs
-``_cffi_backend``.)
-
-Note that a few small differences do exist: notably, ``from _foo import
-ffi`` returns an object of a type written in C, which does not let you
-add random attributes to it (nor does it have all the
-underscore-prefixed internal attributes of the Python version).
-Similarly, the ``lib`` objects returned by the C version are read-only,
-apart from writes to global variables. Also, ``lib.__dict__`` does
-not work before version 1.2 or if ``lib`` happens to declare a name
-called ``__dict__`` (use instead ``dir(lib)``). The same is true
-for ``lib.__class__``, ``lib.__all__`` and ``lib.__name__`` added
-in successive versions.
-
-
-.. _cdef:
-
-ffi/ffibuilder.cdef(): declaring types and functions
-----------------------------------------------------
-
-**ffi/ffibuilder.cdef(source)**: parses the given C source.
-It registers all the functions, types, constants and global variables in
-the C source. The types can be used immediately in ``ffi.new()`` and
-other functions. Before you can access the functions and global
-variables, you need to give ``ffi`` another piece of information: where
-they actually come from (which you do with either ``ffi.dlopen()`` or
-``ffi.set_source()``).
-
-.. _`all types listed above`:
-
-The C source is parsed internally (using ``pycparser``). This code
-cannot contain ``#include``. It should typically be a self-contained
-piece of declarations extracted from a man page. The only things it
-can assume to exist are the standard types:
-
-* char, short, int, long, long long (both signed and unsigned)
-
-* float, double, long double
-
-* intN_t, uintN_t (for N=8,16,32,64), intptr_t, uintptr_t, ptrdiff_t,
- size_t, ssize_t
-
-* wchar_t (if supported by the backend). *New in version 1.11:*
- char16_t and char32_t.
-
-* _Bool and bool (equivalent). If not directly supported by the C
- compiler, this is declared with the size of ``unsigned char``.
-
-* FILE. `See here.`__
-
-* all `common Windows types`_ are defined if you run
- on Windows (``DWORD``, ``LPARAM``, etc.). Exception:
- ``TBYTE TCHAR LPCTSTR PCTSTR LPTSTR PTSTR PTBYTE PTCHAR`` are
- not automatically defined; see `ffi.set_unicode()`_.
-
-* the other standard integer types from
- stdint.h, like ``intmax_t``, as long as they map to integers of 1,
- 2, 4 or 8 bytes. Larger integers are not supported.
-
-.. __: ref.html#file
-.. _`common Windows types`: http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx
-
-The declarations can also contain "``...``" at various places; these are
-placeholders that will be completed by the compiler. More information
-about it below in `Letting the C compiler fill the gaps`_.
-
-Note that all standard type names listed above are handled as
-*defaults* only (apart from the ones that are keywords in the C
-language). If your ``cdef`` contains an explicit typedef that
-redefines one of the types above, then the default described above is
-ignored. (This is a bit hard to implement cleanly, so in some corner
-cases it might fail, notably with the error ``Multiple type specifiers
-with a type tag``. Please report it as a bug if it does.)
-
-Multiple calls to ``ffi.cdef()`` are possible. Beware that it can be
-slow to call ``ffi.cdef()`` a lot of times, a consideration that is
-important mainly in in-line mode.
-
-The ``ffi.cdef()`` call optionally takes an extra argument: either
-``packed`` or ``pack``. If you pass ``packed=True``,
-then all structs declared within
-this cdef are "packed". (If you need both packed and non-packed
-structs, use several cdefs in sequence.) This
-has a meaning similar to ``__attribute__((packed))`` in GCC. It
-specifies that all structure fields should have an alignment of one
-byte. (Note that the packed attribute has no effect on bit fields so
-far, which mean that they may be packed differently than on GCC.
-Also, this has no effect on structs declared with ``"...;"``---more
-about it later in `Letting the C compiler fill the gaps`_. In
-particular, if your C source uses other attributes like
-``__attribute__((aligned(16)))``, there is no way to declare this fact
-in the ``cdef()``, but you can generally just declare the struct with
-``"...;"`` as the last field.)
-
-*New in version 1.12:* In ABI mode, you can also pass ``pack=n``,
-with an integer ``n`` which must be a power of two. Then the
-alignment of any field is limited to ``n`` if it would otherwise be
-greater than ``n``. Passing ``pack=1`` is equivalent to passing
-``packed=True``. This is meant to emulate ``#pragma pack(n)`` from
-the MSVC compiler. On Windows, the default is ``pack=8`` (from cffi
-1.12 onwards); on other platforms, the default is ``pack=None``.
-
-Note that you can use the type-qualifiers ``const`` and ``restrict``
-(but not ``__restrict`` or ``__restrict__``) in the ``cdef()``, but
-this has no effect on the cdata objects that you get at run-time (they
-are never ``const``). The effect is limited to knowing if a global
-variable is meant to be a constant or not. Also, *new in version
-1.3:* when using ``set_source()`` or ``verify()``, these two
-qualifiers are copied from the cdef to the generated C code; this
-fixes warnings by the C compiler.
-
-Note a trick if you copy-paste code from sources in which there are
-extra macros (for example, the Windows documentation uses SAL
-annotations like ``_In_`` or ``_Out_``). These hints must be removed
-in the string given to cdef(), but it can be done programmatically
-like this::
-
- ffi.cdef(re.sub(r"\b(_In_|_Inout_|_Out_|_Outptr_)(opt_)?\b", " ",
- """
- DWORD WINAPI GetModuleFileName(
- _In_opt_ HMODULE hModule,
- _Out_ LPTSTR lpFilename,
- _In_ DWORD nSize
- );
- """))
-
-Note also that pycparser, the underlying C parser, recognizes
-preprocessor-like directives in the following format: ``# NUMBER
-"FILE"``. For example, if you put ``# 42 "foo.h"`` in the middle of the
-string passed to ``cdef()`` and there is an error two lines later, then
-it is reported with an error message that starts with ``foo.h:43:`` (the
-line which is given the number 42 is the line immediately after the
-directive). *New in version 1.10.1:* CFFI automatically puts the line
-``# 1 "<cdef source string>"`` just before the string you give to
-``cdef()``.
-
-
-.. _`ffi.set_unicode()`:
-
-**ffi.set_unicode(enabled_flag)**: Windows: if ``enabled_flag`` is
-True, enable the ``UNICODE`` and ``_UNICODE`` defines in C, and
-declare the types ``TBYTE TCHAR LPCTSTR PCTSTR LPTSTR PTSTR PTBYTE
-PTCHAR`` to be (pointers to) ``wchar_t``. If ``enabled_flag`` is
-False, declare these types to be (pointers to) plain 8-bit characters.
-(These types are not predeclared at all if you don't call
-``set_unicode()``.)
-
-The reason behind this method is that a lot of standard functions have
-two versions, like ``MessageBoxA()`` and ``MessageBoxW()``. The
-official interface is ``MessageBox()`` with arguments like
-``LPTCSTR``. Depending on whether ``UNICODE`` is defined or not, the
-standard header renames the generic function name to one of the two
-specialized versions, and declares the correct (unicode or not) types.
-
-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 byte strings.
-
-
-.. _loading-libraries:
-.. _dlopen:
-
-ffi.dlopen(): loading libraries in ABI mode
--------------------------------------------
-
-``ffi.dlopen(libpath, [flags])``: this function opens a shared library and
-returns a module-like library object. Use this when you are fine with
-the limitations of ABI-level access to the system (dependency on ABI
-details, getting crashes instead of C compiler errors/warnings, and
-higher overhead to call the C functions). In case of doubt, read again
-`ABI versus API`_ in the overview.
-
-.. _`ABI versus API`: overview.html#abi-versus-api
-
-You can use the library object to call the functions previously
-declared by ``ffi.cdef()``, to read constants, and to read or write
-global variables. Note that you can use a single ``cdef()`` to
-declare functions from multiple libraries, as long as you load each of
-them with ``dlopen()`` and access the functions from the correct one.
-
-The ``libpath`` is the file name of the shared library, which can
-contain a full path or not (in which case it is searched in standard
-locations, as described in ``man dlopen``), with extensions or not.
-Alternatively, if ``libpath`` is None, it returns the standard C library
-(which can be used to access the functions of glibc, on Linux). Note
-that ``libpath`` `cannot be None`__ on Windows with Python 3.
-
-.. __: http://bugs.python.org/issue23606
-
-Let me state it again: this gives ABI-level access to the library, so
-you need to have all types declared manually exactly as they were
-while the library was made. No checking is done. Mismatches can
-cause random crashes. API-level access, on the other hand, is safer.
-Speed-wise, API-level access is much faster (it is common to have
-the opposite misconception about performance).
-
-Note that only functions and global variables live in library objects;
-the types exist in the ``ffi`` instance independently of library objects.
-This is due to the C model: the types you declare in C are not tied to a
-particular library, as long as you ``#include`` their headers; but you
-cannot call functions from a library without linking it in your program,
-as ``dlopen()`` does dynamically in C.
-
-For the optional ``flags`` argument, see ``man dlopen`` (ignored on
-Windows). It defaults to ``ffi.RTLD_NOW``.
-
-This function returns a "library" object that gets closed when it goes
-out of scope. Make sure you keep the library object around as long as
-needed. (Alternatively, the out-of-line FFIs have a method
-``ffi.dlclose(lib)``.)
-
-.. _dlopen-note:
-
-Note: the old version of ``ffi.dlopen()`` from the in-line ABI mode
-tries to use ``ctypes.util.find_library()`` if it cannot directly find
-the library. The newer out-of-line ``ffi.dlopen()`` no longer does it
-automatically; it simply passes the argument it receives to the
-underlying ``dlopen()`` or ``LoadLibrary()`` function. If needed, it
-is up to you to use ``ctypes.util.find_library()`` or any other way to
-look for the library's filename. This also means that
-``ffi.dlopen(None)`` no longer work on Windows; try instead
-``ffi.dlopen(ctypes.util.find_library('c'))``.
-
-*New in version 1.14:* ``ffi.dlopen(handle)``: instead of a file path,
-you can give an already-opened library handle, as a cdata of type
-``void *``. Such a call converts this handle into a regular FFI object
-with the functions and global variables declared by ``ffi.cdef()``.
-Useful if you have special needs (e.g. you need the GNU extension
-``dlmopen()``, which you can itself declare and call using a different
-``ffi`` object). Note that in this variant, ``dlclose()`` is not called
-automatically if the FFI object is garbage-collected (but you can still
-call ``ffi.dlclose()`` explicitly if needed).
-
-
-.. _set_source:
-
-ffibuilder.set_source(): preparing out-of-line modules
-------------------------------------------------------
-
-**ffibuilder.set_source(module_name, c_header_source, [\*\*keywords...])**:
-prepare the ffi for producing out-of-line an external module called
-``module_name``.
-
-``ffibuilder.set_source()`` by itself does not write any file, but merely
-records its arguments for later. It can therefore be called before or
-after ``ffibuilder.cdef()``.
-
-In **ABI mode,** you call ``ffibuilder.set_source(module_name, None)``. The
-argument is the name (or dotted name inside a package) of the Python
-module to generate. In this mode, no C compiler is called.
-
-In **API mode,** the ``c_header_source`` argument is a string that
-will be pasted into the .c file generated. Typically, it is specified as
-``r""" ...multiple lines of C code... """`` (the ``r`` prefix allows these
-lines to contain a literal ``\n``, for example). This piece of C code
-typically contains some ``#include``, but may also contain more,
-like definitions for custom "wrapper" C functions. The goal is that
-the .c file can be generated like this::
-
- // C file "module_name.c"
- #include <Python.h>
-
- ...c_header_source...
-
- ...magic code...
-
-where the "magic code" is automatically generated from the ``cdef()``.
-For example, if the ``cdef()`` contains ``int foo(int x);`` then the
-magic code will contain logic to call the function ``foo()`` with an
-integer argument, itself wrapped inside some CPython or PyPy-specific
-code.
-
-The keywords arguments to ``set_source()`` control how the C compiler
-will be called. They are passed directly to distutils_ or setuptools_
-and include at least ``sources``, ``include_dirs``, ``define_macros``,
-``undef_macros``, ``libraries``, ``library_dirs``, ``extra_objects``,
-``extra_compile_args`` and ``extra_link_args``. You typically need at
-least ``libraries=['foo']`` in order to link with ``libfoo.so`` or
-``libfoo.so.X.Y``, or ``foo.dll`` on Windows. The ``sources`` is a
-list of extra .c files compiled and linked together (the file
-``module_name.c`` shown above is always generated and automatically added as the
-first argument to ``sources``). See the distutils documentations for
-`more information about the other arguments`__.
-
-.. __: http://docs.python.org/distutils/setupscript.html#library-options
-.. _distutils: http://docs.python.org/distutils/setupscript.html#describing-extension-modules
-.. _setuptools: https://pythonhosted.org/setuptools/setuptools.html
-
-An extra keyword argument processed internally is
-``source_extension``, defaulting to ``".c"``. The file generated will
-be actually called ``module_name + source_extension``. Example for
-C++ (but note that there are still a few known issues of C-versus-C++
-compatibility):
-
-.. code-block:: python
-
- ffibuilder.set_source("mymodule", r'''
- extern "C" {
- int somefunc(int somearg) { return real_cpp_func(somearg); }
- }
- ''', source_extension='.cpp')
-
-.. _pkgconfig:
-
-**ffibuilder.set_source_pkgconfig(module_name, pkgconfig_libs,
-c_header_source, [\*\*keywords...])**:
-
-*New in version 1.12.* This is equivalent to ``set_source()`` but it
-first calls the system utility ``pkg-config`` with the package names
-given in the list ``pkgconfig_libs``. It collects the information
-obtained in this way and adds it to the explicitly-provided
-``**keywords`` (if any). This should probably not be used on Windows.
-
-If the ``pkg-config`` program is not installed or does not know about
-the requested library, the call fails with ``cffi.PkgConfigError``. If
-necessary, you can catch this error and try to call ``set_source()``
-directly. (Ideally, you should also do that if the ``ffibuilder``
-instance has no method ``set_source_pkgconfig()``, to support older
-versions of cffi.)
-
-
-Letting the C compiler fill the gaps
-------------------------------------
-
-If you are using a C compiler ("API mode"), then:
-
-* functions taking or returning integer or float-point arguments can be
- misdeclared: if e.g. a function is declared by ``cdef()`` as taking a
- ``int``, but actually takes a ``long``, then the C compiler handles the
- difference.
-
-* other arguments are checked: you get a compilation warning or error
- if you pass a ``int *`` argument to a function expecting a ``long *``.
-
-* similarly, most other things declared in the ``cdef()`` are checked,
- to the best we implemented so far; mistakes give compilation
- warnings or errors.
-
-Moreover, you can use "``...``" (literally, dot-dot-dot) in the
-``cdef()`` at various places, in order to ask the C compiler to fill
-in the details. These places are:
-
-* structure declarations: any ``struct { }`` or ``union { }`` that ends
- with "``...;``" as the last "field" is partial: it may be missing
- fields, have them declared out of order, use non-standard alignment,
- etc. Precisely, the field offsets, total struct size, and total
- struct alignment deduced by looking at the ``cdef`` are not relied
- upon and will instead be corrected by the compiler. (But note that you
- can only access fields that you declared, not others.) Any ``struct``
- declaration which doesn't use "``...``" is assumed to be exact, but this is
- checked: you get an error if it is not correct.
-
-* integer types: the syntax "``typedef
- int... foo_t;``" declares the type ``foo_t`` as an integer type
- whose exact size and signedness is not specified. The compiler will
- figure it out. (Note that this requires ``set_source()``; it does
- not work with ``verify()``.) The ``int...`` can be replaced with
- ``long...`` or ``unsigned long long...`` or any other primitive
- integer type, with no effect. The type will always map to one of
- ``(u)int(8,16,32,64)_t`` in Python, but in the generated C code,
- only ``foo_t`` is used.
-
-* *New in version 1.3:* floating-point types: "``typedef
- float... foo_t;``" (or equivalently "``typedef double... foo_t;``")
- declares ``foo_t`` as a-float-or-a-double; the compiler will figure
- out which it is. Note that if the actual C type is even larger
- (``long double`` on some platforms), then compilation will fail.
- The problem is that the Python "float" type cannot be used to store
- the extra precision. (Use the non-dot-dot-dot syntax ``typedef long
- double foo_t;`` as usual, which returns values that are not Python
- floats at all but cdata "long double" objects.)
-
-* unknown types: the syntax "``typedef ... foo_t;``" declares the type
- ``foo_t`` as opaque. Useful mainly for when the API takes and returns
- ``foo_t *`` without you needing to look inside the ``foo_t``. Also
- works with "``typedef ... *foo_p;``" which declares the pointer type
- ``foo_p`` without giving a name to the opaque type itself. Note that
- such an opaque struct has no known size, which prevents some operations
- from working (mostly like in C). *You cannot use this syntax to
- declare a specific type, like an integer type! It declares opaque
- struct-like types only.* In some cases you need to say that
- ``foo_t`` is not opaque, but just a struct where you don't know any
- field; then you would use "``typedef struct { ...; } foo_t;``".
-
-* array lengths: when used as structure fields or in global variables,
- arrays can have an unspecified length, as in "``extern int n[...];``". The
- length is completed by the C compiler.
- This is slightly different from "``extern int n[];``", because the latter
- means that the length is not known even to the C compiler, and thus
- no attempt is made to complete it. This supports
- multidimensional arrays: "``extern int n[...][...];``".
-
- *New in version 1.2:* "``extern int m[][...];``", i.e. ``...`` can be used
- in the innermost dimensions without being also used in the outermost
- dimension. In the example given, the length of the ``m`` array is
- assumed not to be known to the C compiler, but the length of every
- item (like the sub-array ``m[0]``) is always known the C compiler.
- In other words, only the outermost dimension can be specified as
- ``[]``, both in C and in CFFI, but any dimension can be given as
- ``[...]`` in CFFI.
-
-* enums: if you don't know the exact order (or values) of the declared
- constants, then use this syntax: "``enum foo { A, B, C, ... };``"
- (with a trailing "``...``"). The C compiler will be used to figure
- out the exact values of the constants. An alternative syntax is
- "``enum foo { A=..., B, C };``" or even
- "``enum foo { A=..., B=..., C=... };``". Like
- with structs, an ``enum`` without "``...``" is assumed to
- be exact, and this is checked.
-
-* integer constants and macros: you can write in the ``cdef`` the line
- "``#define FOO ...``", with any macro name FOO but with ``...`` as
- a value. Provided the macro
- is defined to be an integer value, this value will be available via
- an attribute of the library object. The
- same effect can be achieved by writing a declaration
- ``static const int FOO;``. The latter is more general because it
- supports other types than integer types (note: the C syntax is then
- to write the ``const`` together with the variable name, as in
- ``static char *const FOO;``).
-
-Currently, it is not supported to find automatically which of the
-various integer or float types you need at which place---except in the
-following case: if such a type is explicitly named. For an integer
-type, use ``typedef int... the_type_name;``, or another type like
-``typedef unsigned long... the_type_name;``. Both are equivalent and
-replaced by the real C type, which must be an integer type.
-Similarly, for floating-point types, use ``typedef float...
-the_type_name;`` or equivalently ``typedef double... the_type_name;``.
-Note that ``long double`` cannot be detected this way.
-
-In the case of function arguments or return types, when it is a simple
-integer/float type, you can simply misdeclare it. If you misdeclare a
-function ``void f(long)`` as ``void f(int)``, it still works (but you
-have to call it with arguments that fit an int). It works because the C
-compiler will do the casting for us. This C-level casting of arguments
-and return types only works for regular function, and not for function
-pointer types; currently, it also does not work for variadic functions.
-
-For more complex types, you have no choice but be precise. For example,
-you cannot misdeclare a ``int *`` argument as ``long *``, or a global
-array ``extern int a[5];`` as ``extern long a[5];``. CFFI considers `all types listed
-above`_ as primitive (so ``extern long long a[5];`` and ``extern int64_t a[5]`` are
-different declarations). The reason for that is detailed in `a comment
-about an issue.`__
-
-.. __: https://foss.heptapod.net/pypy/cffi/-/issues/265#note_50393
-
-
-ffibuilder.compile() etc.: compiling out-of-line modules
---------------------------------------------------------
-
-You can use one of the following functions to actually generate the
-.py or .c file prepared with ``ffibuilder.set_source()`` and
-``ffibuilder.cdef()``.
-
-Note that these function won't overwrite a .py/.c file with exactly
-the same content, to preserve the mtime. In some cases where you need
-the mtime to be updated anyway, delete the file before calling the
-functions.
-
-*New in version 1.8:* the C code produced by ``emit_c_code()`` or
-``compile()`` contains ``#define Py_LIMITED_API``. This means that on
-CPython >= 3.2, compiling this source produces a binary .so/.dll that
-should work for any version of CPython >= 3.2 (as opposed to only for
-the same version of CPython x.y). However, the standard ``distutils``
-package will still produce a file called e.g.
-``NAME.cpython-35m-x86_64-linux-gnu.so``. You can manually rename it to
-``NAME.abi3.so``, or use setuptools version 26 or later. Also, note
-that compiling with a debug version of Python will not actually define
-``Py_LIMITED_API``, as doing so makes ``Python.h`` unhappy.
-
-*New in version 1.12:* ``Py_LIMITED_API`` is now defined on Windows too.
-If you use ``virtualenv``, you need a recent version of it: versions
-older than 16.0.0 forgot to copy ``python3.dll`` into the virtual
-environment. In case upgrading ``virtualenv`` is a real problem, you
-can manually edit the C code to remove the first line ``# define
-Py_LIMITED_API``.
-
-**ffibuilder.compile(tmpdir='.', verbose=False, debug=None):**
-explicitly generate the .py or .c file,
-and (if .c) compile it. The output file is (or are) put in the
-directory given by ``tmpdir``. In the examples given here, we use
-``if __name__ == "__main__": ffibuilder.compile()`` in the build scripts---if
-they are directly executed, this makes them rebuild the .py/.c file in
-the current directory. (Note: if a package is specified in the call
-to ``set_source()``, then a corresponding subdirectory of the ``tmpdir``
-is used.)
-
-*New in version 1.4:* ``verbose`` argument. If True, it prints the
-usual distutils output, including the command lines that call the
-compiler. (This parameter might be changed to True by default in a
-future release.)
-
-*New in version 1.8.1:* ``debug`` argument. If set to a bool, it
-controls whether the C code is compiled in debug mode or not. The
-default None means to use the host Python's ``sys.flags.debug``.
-Starting with version 1.8.1, if you are running a debug-mode Python, the
-C code is thus compiled in debug mode by default (note that it is anyway
-necessary to do so on Windows).
-
-**ffibuilder.emit_python_code(filename):** generate the given .py file (same
-as ``ffibuilder.compile()`` for ABI mode, with an explicitly-named file to
-write). If you choose, you can include this .py file pre-packaged in
-your own distributions: it is identical for any Python version (2 or
-3).
-
-**ffibuilder.emit_c_code(filename):** generate the given .c file (for API
-mode) without compiling it. Can be used if you have some other method
-to compile it, e.g. if you want to integrate with some larger build
-system that will compile this file for you. You can also distribute
-the .c file: unless the build script you used depends on the OS or
-platform, the .c file itself is generic (it would be exactly the same
-if produced on a different OS, with a different version of CPython, or
-with PyPy; it is done with generating the appropriate ``#ifdef``).
-
-**ffibuilder.distutils_extension(tmpdir='build', verbose=True):** for
-distutils-based ``setup.py`` files. Calling this creates the .c file
-if needed in the given ``tmpdir``, and returns a
-``distutils.core.Extension`` instance.
-
-For Setuptools, you use instead the line
-``cffi_modules=["path/to/foo_build.py:ffibuilder"]`` in ``setup.py``. This
-line asks Setuptools to import and use a helper provided by CFFI,
-which in turn executes the file ``path/to/foo_build.py`` (as with
-``execfile()``) and looks up its global variable called ``ffibuilder``. You
-can also say ``cffi_modules=["path/to/foo_build.py:maker"]``, where
-``maker`` names a global function; it is called with no argument and
-is supposed to return a ``FFI`` object.
-
-
-ffi/ffibuilder.include(): combining multiple CFFI interfaces
-------------------------------------------------------------
-
-**ffi/ffibuilder.include(other_ffi)**: includes the typedefs, structs, unions,
-enums and constants defined in another FFI instance. This is meant
-for large projects where one CFFI-based interface depends on some
-types declared in a different CFFI-based interface.
-
-*Note that you should only use one ffi object per library; the intended
-usage of ffi.include() is if you want to interface with several
-inter-dependent libraries.* For only one library, make one ``ffi``
-object. (You can write several ``cdef()`` calls over the same ``ffi``
-from several Python files, if one file would be too large.)
-
-For out-of-line modules, the ``ffibuilder.include(other_ffibuilder)``
-line should
-occur in the build script, and the ``other_ffibuilder`` argument should be
-another FFI instance that comes from another build script. When the two build
-scripts are turned into generated files, say ``_ffi.so`` and
-``_other_ffi.so``, then importing ``_ffi.so`` will internally cause
-``_other_ffi.so`` to be imported. At that point, the real
-declarations from ``_other_ffi.so`` are combined with the real
-declarations from ``_ffi.so``.
-
-The usage of ``ffi.include()`` is the cdef-level equivalent of a
-``#include`` in C, where a part of the program might include types and
-functions defined in another part for its own usage. You can see on
-the ``ffi`` object (and associated ``lib`` objects on the *including*
-side) the types and constants declared on the included side. In API
-mode, you can also see the functions and global variables directly.
-In ABI mode, these must be accessed via the original ``other_lib``
-object returned by the ``dlopen()`` method on ``other_ffi``.
-
-
-ffi.cdef() limitations
-----------------------
-
-All of the ANSI C *declarations* should be supported in ``cdef()``,
-and some of C99. (This excludes any ``#include`` or ``#ifdef``.)
-Known missing features that are either in C99, or are GCC or MSVC
-extensions:
-
-* Any ``__attribute__`` or ``#pragma pack(n)``
-
-* Additional types: special-size floating and fixed
- point types, vector types, and so on.
-
-* The C99 types ``float _Complex`` and ``double _Complex`` are supported
- by cffi since version 1.11, but not libffi: you cannot call C
- functions with complex arguments or return value, except if they are
- directly API-mode functions. The type ``long double _Complex`` is not
- supported at all (declare and use it as if it were an array of two
- ``long double``, and write wrapper functions in C with set_source()).
-
-* ``__restrict__`` or ``__restrict`` are extensions of, respectively,
- GCC and MSVC. They are not recognized. But ``restrict`` is a C
- keyword and is accepted (and ignored).
-
-Note that declarations like ``int field[];`` in
-structures are interpreted as variable-length structures. Declarations
-like ``int field[...];`` on the other hand are arrays whose length is
-going to be completed by the compiler. You can use ``int field[];``
-for array fields that are not, in fact, variable-length; it works too,
-but in this case, as CFFI
-believes it cannot ask the C compiler for the length of the array, you
-get reduced safety checks: for example, you risk overwriting the
-following fields by passing too many array items in the constructor.
-
-*New in version 1.2:*
-Thread-local variables (``__thread``) can be accessed, as well as
-variables defined as dynamic macros (``#define myvar (*fetchme())``).
-Before version 1.2, you need to write getter/setter functions.
-
-Note that if you declare a variable in ``cdef()`` without using
-``const``, CFFI assumes it is a read-write variable and generates two
-pieces of code, one to read it and one to write it. If the variable
-cannot in fact be written to in C code, for one reason or another, it
-will not compile. In this case, you can declare it as a constant: for
-example, instead of ``foo_t *myglob;`` you would use ``foo_t *const
-myglob;``. Note also that ``const foo_t *myglob;`` is a *variable;* it
-contains a variable pointer to a constant ``foo_t``.
-
-
-Debugging dlopen'ed C libraries
--------------------------------
-
-A few C libraries are actually hard to use correctly in a ``dlopen()``
-setting. This is because most C libraries are intended for, and tested
-with, a situation where they are *linked* with another program, using
-either static linking or dynamic linking --- but from a program written
-in C, at start-up, using the linker's capabilities instead of
-``dlopen()``.
-
-This can occasionally create issues. You would have the same issues in
-another setting than CFFI, like with ``ctypes`` or even plain C code that
-calls ``dlopen()``. This section contains a few generally useful
-environment variables (on Linux) that can help when debugging these
-issues.
-
-**export LD_TRACE_LOADED_OBJECTS=all**
-
- provides a lot of information, sometimes too much depending on the
- setting. Output verbose debugging information about the dynamic
- linker. If set to ``all`` prints all debugging information it has, if
- set to ``help`` prints a help message about which categories can be
- specified in this environment variable
-
-**export LD_VERBOSE=1**
-
- (glibc since 2.1) If set to a nonempty string, output symbol
- versioning information about the program if querying information
- about the program (i.e., either ``LD_TRACE_LOADED_OBJECTS`` has been set,
- or ``--list`` or ``--verify`` options have been given to the dynamic
- linker).
-
-**export LD_WARN=1**
-
- (ELF only)(glibc since 2.1.3) If set to a nonempty string, warn
- about unresolved symbols.
-
-
-ffi.verify(): in-line API-mode
-------------------------------
-
-**ffi.verify()** is supported for backward compatibility, but is
-deprecated. ``ffi.verify(c_header_source, tmpdir=.., ext_package=..,
-modulename=.., flags=.., **kwargs)`` makes and compiles a C file from
-the ``ffi.cdef()``, like ``ffi.set_source()`` in API mode, and then
-immediately loads and returns the dynamic library object. Some
-non-trivial logic is used to decide if the dynamic library must be
-recompiled or not; see below for ways to control it.
-
-The ``c_header_source`` and the extra keyword arguments have the
-same meaning as in ``ffi.set_source()``.
-
-One remaining use case for ``ffi.verify()`` would be the following
-hack to find explicitly the size of any type, in bytes, and have it
-available in Python immediately (e.g. because it is needed in order to
-write the rest of the build script):
-
-.. code-block:: python
-
- ffi = cffi.FFI()
- ffi.cdef("const int mysize;")
- lib = ffi.verify("const int mysize = sizeof(THE_TYPE);")
- print lib.mysize
-
-Extra arguments to ``ffi.verify()``:
-
-* ``tmpdir`` controls where the C
- files are created and compiled. Unless the ``CFFI_TMPDIR`` environment
- variable is set, the default is
- ``directory_containing_the_py_file/__pycache__`` using the
- directory name of the .py file that contains the actual call to
- ``ffi.verify()``. (This is a bit of a hack but is generally
- consistent with the location of the .pyc files for your library.
- The name ``__pycache__`` itself comes from Python 3.)
-
-* ``ext_package`` controls in which package the
- compiled extension module should be looked from. This is
- only useful after distributing ffi.verify()-based modules.
-
-* The ``tag`` argument gives an extra string inserted in the
- middle of the extension module's name: ``_cffi_<tag>_<hash>``.
- Useful to give a bit more context, e.g. when debugging.
-
-* The ``modulename`` argument can be used to force a specific module
- name, overriding the name ``_cffi_<tag>_<hash>``. Use with care,
- e.g. if you are passing variable information to ``verify()`` but
- still want the module name to be always the same (e.g. absolute
- paths to local files). In this case, no hash is computed and if
- the module name already exists it will be reused without further
- check. Be sure to have other means of clearing the ``tmpdir``
- whenever you change your sources.
-
-* ``source_extension`` has the same meaning as in ``ffibuilder.set_source()``.
-
-* The optional ``flags`` argument (ignored on Windows) defaults to
- ``ffi.RTLD_NOW``; see ``man dlopen``. (With
- ``ffibuilder.set_source()``, you would use ``sys.setdlopenflags()``.)
-
-* The optional ``relative_to`` argument is useful if you need to list
- local files passed to the C compiler::
-
- ext = ffi.verify(..., sources=['foo.c'], relative_to=__file__)
-
- The line above is roughly the same as::
-
- ext = ffi.verify(..., sources=['/path/to/this/file/foo.c'])
-
- except that the default name of the produced library is built from
- the CRC checkum of the argument ``sources``, as well as most other
- arguments you give to ``ffi.verify()`` -- but not ``relative_to``.
- So if you used the second line, it would stop finding the
- already-compiled library after your project is installed, because
- the ``'/path/to/this/file'`` suddenly changed. The first line does
- not have this problem.
-
-Note that during development, every time you change the C sources that
-you pass to ``cdef()`` or ``verify()``, then the latter will create a
-new module file name, based on two CRC32 hashes computed from these
-strings. This creates more and more files in the ``__pycache__``
-directory. It is recommended that you clean it up from time to time.
-A nice way to do that is to add, in your test suite, a call to
-``cffi.verifier.cleanup_tmpdir()``. Alternatively, you can manually
-remove the whole ``__pycache__`` directory.
-
-An alternative cache directory can be given as the ``tmpdir`` argument
-to ``verify()``, via the environment variable ``CFFI_TMPDIR``, or by
-calling ``cffi.verifier.set_tmpdir(path)`` prior to calling
-``verify``.
-
-
-Upgrading from CFFI 0.9 to CFFI 1.0
------------------------------------
-
-CFFI 1.0 is backward-compatible, but it is still a good idea to
-consider moving to the out-of-line approach new in 1.0. Here are the
-steps.
-
-**ABI mode** if your CFFI project uses ``ffi.dlopen()``:
-
-.. code-block:: python
-
- import cffi
-
- ffi = cffi.FFI()
- ffi.cdef("stuff")
- lib = ffi.dlopen("libpath")
-
-and *if* the "stuff" part is big enough that import time is a concern,
-then rewrite it as described in `the out-of-line but still ABI mode`__
-above. Optionally, see also the `setuptools integration`__ paragraph.
-
-.. __: out-of-line-abi_
-.. __: distutils-setuptools_
-
-
-**API mode** if your CFFI project uses ``ffi.verify()``:
-
-.. code-block:: python
-
- import cffi
-
- ffi = cffi.FFI()
- ffi.cdef("stuff")
- lib = ffi.verify("real C code")
-
-then you should really rewrite it as described in `the out-of-line,
-API mode`__ above. It avoids a number of issues that have caused
-``ffi.verify()`` to grow a number of extra arguments over time. Then
-see the `distutils or setuptools`__ paragraph. Also, remember to
-remove the ``ext_package=".."`` from your ``setup.py``, which was
-sometimes needed with ``verify()`` but is just creating confusion with
-``set_source()``.
-
-.. __: out-of-line-api_
-.. __: distutils-setuptools_
-
-The following example should work both with old (pre-1.0) and new
-versions of CFFI---supporting both is important to run on old
-versions of PyPy (CFFI 1.0 does not work in PyPy < 2.6):
-
-.. code-block:: python
-
- # in a separate file "package/foo_build.py"
- import cffi
-
- ffi = cffi.FFI()
- C_HEADER_SRC = r'''
- #include "somelib.h"
- '''
- C_KEYWORDS = dict(libraries=['somelib'])
-
- if hasattr(ffi, 'set_source'):
- ffi.set_source("package._foo", C_HEADER_SRC, **C_KEYWORDS)
-
- ffi.cdef('''
- int foo(int);
- ''')
-
- if __name__ == "__main__":
- ffi.compile()
-
-And in the main program:
-
-.. code-block:: python
-
- try:
- from package._foo import ffi, lib
- except ImportError:
- from package.foo_build import ffi, C_HEADER_SRC, C_KEYWORDS
- lib = ffi.verify(C_HEADER_SRC, **C_KEYWORDS)
-
-(FWIW, this latest trick can be used more generally to allow the
-import to "work" even if the ``_foo`` module was not generated.)
-
-Writing a ``setup.py`` script that works both with CFFI 0.9 and 1.0
-requires explicitly checking the version of CFFI that we can have---it
-is hard-coded as a built-in module in PyPy:
-
-.. code-block:: python
-
- if '_cffi_backend' in sys.builtin_module_names: # PyPy
- import _cffi_backend
- requires_cffi = "cffi==" + _cffi_backend.__version__
- else:
- requires_cffi = "cffi>=1.0.0"
-
-Then we use the ``requires_cffi`` variable to give different arguments to
-``setup()`` as needed, e.g.:
-
-.. code-block:: python
-
- if requires_cffi.startswith("cffi==0."):
- # backward compatibility: we have "cffi==0.*"
- from package.foo_build import ffi
- extra_args = dict(
- ext_modules=[ffi.verifier.get_extension()],
- ext_package="...", # if needed
- )
- else:
- extra_args = dict(
- setup_requires=[requires_cffi],
- cffi_modules=['package/foo_build.py:ffi'],
- )
- setup(
- name=...,
- ...,
- install_requires=[requires_cffi],
- **extra_args
- )
diff --git a/doc/source/conf.py b/doc/source/conf.py
deleted file mode 100644
index 33e8c11..0000000
--- a/doc/source/conf.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# CFFI documentation build configuration file, created by
-# sphinx-quickstart on Thu Jun 14 16:37:47 2012.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.append(os.path.abspath('.'))
-
-# -- General configuration -----------------------------------------------------
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'CFFI'
-copyright = u'2012-2018, Armin Rigo, Maciej Fijalkowski'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '1.15'
-# The full version, including alpha/beta/rc tags.
-release = '1.15.0'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of documents that shouldn't be included in the build.
-#unused_docs = []
-
-# List of directories, relative to source directory, that shouldn't be searched
-# for source files.
-exclude_trees = []
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. Major themes that come with
-# Sphinx are currently 'default' and 'sphinxdoc'.
-#html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-#html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_use_modindex = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = ''
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'CFFIdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'CFFI.tex', u'CFFI Documentation',
- u'Armin Rigo, Maciej Fijalkowski', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_use_modindex = True
diff --git a/doc/source/embedding.rst b/doc/source/embedding.rst
deleted file mode 100644
index 8020f21..0000000
--- a/doc/source/embedding.rst
+++ /dev/null
@@ -1,531 +0,0 @@
-================================
-Using CFFI for embedding
-================================
-
-.. contents::
-
-You can use CFFI to generate C code which exports the API of your choice
-to any C application that wants to link with this C code. This API,
-which you define yourself, ends up as the API of a ``.so/.dll/.dylib``
-library---or you can statically link it within a larger application.
-
-Possible use cases:
-
-* Exposing a library written in Python directly to C/C++ programs.
-
-* Using Python to make a "plug-in" for an existing C/C++ program that is
- already written to load them.
-
-* Using Python to implement part of a larger C/C++ application (with
- static linking).
-
-* Writing a small C/C++ wrapper around Python, hiding the fact that the
- application is actually written in Python (to make a custom
- command-line interface; for distribution purposes; or simply to make
- it a bit harder to reverse-engineer the application).
-
-The general idea is as follows:
-
-* You write and execute a Python script, which produces a ``.c`` file
- with the API of your choice (and optionally compile it into a
- ``.so/.dll/.dylib``). The script also gives some Python code to be
- "frozen" inside the ``.so``.
-
-* At runtime, the C application loads this ``.so/.dll/.dylib`` (or is
- statically linked with the ``.c`` source) without having to know that
- it was produced from Python and CFFI.
-
-* The first time a C function is called, Python is initialized and
- the frozen Python code is executed.
-
-* The frozen Python code defines more Python functions that implement the
- C functions of your API, which are then used for all subsequent C
- function calls.
-
-One of the goals of this approach is to be entirely independent from
-the CPython C API: no ``Py_Initialize()`` nor ``PyRun_SimpleString()``
-nor even ``PyObject``. It works identically on CPython and PyPy.
-
-This is entirely *new in version 1.5.* (PyPy contains CFFI 1.5 since
-release 5.0.)
-
-
-Usage
------
-
-.. __: overview.html#embedding
-
-See the `paragraph in the overview page`__ for a quick introduction.
-In this section, we explain every step in more details. We will use
-here this slightly expanded example:
-
-.. code-block:: c
-
- /* file plugin.h */
- typedef struct { int x, y; } point_t;
- extern int do_stuff(point_t *);
-
-.. code-block:: c
-
- /* file plugin.h, Windows-friendly version */
- typedef struct { int x, y; } point_t;
-
- /* When including this file from ffibuilder.set_source(), the
- following macro is defined to '__declspec(dllexport)'. When
- including this file directly from your C program, we define
- it to 'extern __declspec(dllimport)' instead.
-
- With non-MSVC compilers we simply define it to 'extern'.
- (The 'extern' is needed for sharing global variables;
- functions would be fine without it. The macros always
- include 'extern': you must not repeat it when using the
- macros later.)
- */
- #ifndef CFFI_DLLEXPORT
- # if defined(_MSC_VER)
- # define CFFI_DLLEXPORT extern __declspec(dllimport)
- # else
- # define CFFI_DLLEXPORT extern
- # endif
- #endif
-
- CFFI_DLLEXPORT int do_stuff(point_t *);
-
-.. code-block:: python
-
- # file plugin_build.py
- import cffi
- ffibuilder = cffi.FFI()
-
- with open('plugin.h') as f:
- # read plugin.h and pass it to embedding_api(), manually
- # removing the '#' directives and the CFFI_DLLEXPORT
- data = ''.join([line for line in f if not line.startswith('#')])
- data = data.replace('CFFI_DLLEXPORT', '')
- ffibuilder.embedding_api(data)
-
- ffibuilder.set_source("my_plugin", r'''
- #include "plugin.h"
- ''')
-
- ffibuilder.embedding_init_code("""
- from my_plugin import ffi
-
- @ffi.def_extern()
- def do_stuff(p):
- print("adding %d and %d" % (p.x, p.y))
- return p.x + p.y
- """)
-
- ffibuilder.compile(target="plugin-1.5.*", verbose=True)
- # or: ffibuilder.emit_c_code("my_plugin.c")
-
-Running the code above produces a *DLL*, i,e, a dynamically-loadable
-library. It is a file with the extension ``.dll`` on Windows,
-``.dylib`` on Mac OS/X, or ``.so`` on other platforms. As usual, it
-is produced by generating some intermediate ``.c`` code and then
-calling the regular platform-specific C compiler. See below__ for
-some pointers to C-level issues with using the produced library.
-
-.. __: `Issues about using the .so`_
-
-Here are some details about the methods used above:
-
-* **ffibuilder.embedding_api(source):** parses the given C source, which
- declares functions that you want to be exported by the DLL. It can
- also declare types, constants and global variables that are part of
- the C-level API of your DLL.
-
- The functions that are found in ``source`` will be automatically
- defined in the ``.c`` file: they will contain code that initializes
- the Python interpreter the first time any of them is called,
- followed by code to call the attached Python function (with
- ``@ffi.def_extern()``, see next point).
-
- The global variables, on the other hand, are not automatically
- produced. You have to write their definition explicitly in
- ``ffibuilder.set_source()``, as regular C code (see the point after next).
-
-* **ffibuilder.embedding_init_code(python_code):** this gives
- initialization-time Python source code. This code is copied
- ("frozen") inside the DLL. At runtime, the code is executed when
- the DLL is first initialized, just after Python itself is
- initialized. This newly initialized Python interpreter has got an
- extra "built-in" module that can be loaded magically without
- accessing any files, with a line like "``from my_plugin import ffi,
- lib``". The name ``my_plugin`` comes from the first argument to
- ``ffibuilder.set_source()``. This module represents "the caller's C world"
- from the point of view of Python.
-
- The initialization-time Python code can import other modules or
- packages as usual. You may have typical Python issues like needing
- to set up ``sys.path`` somehow manually first.
-
- For every function declared within ``ffibuilder.embedding_api()``, the
- initialization-time Python code or one of the modules it imports
- should use the decorator ``@ffi.def_extern()`` to attach a
- corresponding Python function to it.
-
- If the initialization-time Python code fails with an exception, then
- you get a traceback printed to stderr, along with more information
- to help you identify problems like wrong ``sys.path``. If some
- function remains unattached at the time where the C code tries to
- call it, an error message is also printed to stderr and the function
- returns zero/null.
-
- Note that the CFFI module never calls ``exit()``, but CPython itself
- contains code that calls ``exit()``, for example if importing
- ``site`` fails. This may be worked around in the future.
-
-* **ffibuilder.set_source(c_module_name, c_code):** set the name of the
- module from Python's point of view. It also gives more C code which
- will be included in the generated C code. In trivial examples it
- can be an empty string. It is where you would ``#include`` some
- other files, define global variables, and so on. The macro
- ``CFFI_DLLEXPORT`` is available to this C code: it expands to the
- platform-specific way of saying "the following declaration should be
- exported from the DLL". For example, you would put "``extern int
- my_glob;``" in ``ffibuilder.embedding_api()`` and "``CFFI_DLLEXPORT int
- my_glob = 42;``" in ``ffibuilder.set_source()``.
-
- Currently, any *type* declared in ``ffibuilder.embedding_api()`` must also
- be present in the ``c_code``. This is automatic if this code
- contains a line like ``#include "plugin.h"`` in the example above.
-
-* **ffibuilder.compile([target=...] [, verbose=True]):** make the C code and
- compile it. By default, it produces a file called
- ``c_module_name.dll``, ``c_module_name.dylib`` or
- ``c_module_name.so``, but the default can be changed with the
- optional ``target`` keyword argument. You can use
- ``target="foo.*"`` with a literal ``*`` to ask for a file called
- ``foo.dll`` on Windows, ``foo.dylib`` on OS/X and ``foo.so``
- elsewhere. One reason for specifying an alternate ``target`` is to
- include characters not usually allowed in Python module names, like
- "``plugin-1.5.*``".
-
- For more complicated cases, you can call instead
- ``ffibuilder.emit_c_code("foo.c")`` and compile the resulting ``foo.c``
- file using other means. CFFI's compilation logic is based on the
- standard library ``distutils`` package, which is really developed
- and tested for the purpose of making CPython extension modules; it
- might not always be appropriate for making general DLLs. Also, just
- getting the C code is what you need if you do not want to make a
- stand-alone ``.so/.dll/.dylib`` file: this C file can be compiled
- and statically linked as part of a larger application.
-
-
-More reading
-------------
-
-If you're reading this page about embedding and you are not familiar
-with CFFI already, here are a few pointers to what you could read
-next:
-
-* For the ``@ffi.def_extern()`` functions, integer C types are passed
- simply as Python integers; and simple pointers-to-struct and basic
- arrays are all straightforward enough. However, sooner or later you
- will need to read about this topic in more details here__.
-
-* ``@ffi.def_extern()``: see `documentation here,`__ notably on what
- happens if the Python function raises an exception.
-
-* To create Python objects attached to C data, one common solution is
- to use ``ffi.new_handle()``. See documentation here__.
-
-* In embedding mode, the major direction is C code that calls Python
- functions. This is the opposite of the regular extending mode of
- CFFI, in which the major direction is Python code calling C. That's
- why the page `Using the ffi/lib objects`_ talks first about the
- latter, and why the direction "C code that calls Python" is
- generally referred to as "callbacks" in that page. If you also
- need to have your Python code call C code, read more about
- `Embedding and Extending`_ below.
-
-* ``ffibuilder.embedding_api(source)``: follows the same syntax as
- ``ffibuilder.cdef()``, `documented here.`__ You can use the "``...``"
- syntax as well, although in practice it may be less useful than it
- is for ``cdef()``. On the other hand, it is expected that often the
- C sources that you need to give to ``ffibuilder.embedding_api()`` would be
- exactly the same as the content of some ``.h`` file that you want to
- give to users of your DLL. That's why the example above does this::
-
- with open('foo.h') as f:
- ffibuilder.embedding_api(f.read())
-
- Note that a drawback of this approach is that ``ffibuilder.embedding_api()``
- doesn't support ``#ifdef`` directives. You may have to use a more
- convoluted expression like::
-
- with open('foo.h') as f:
- lines = [line for line in f if not line.startswith('#')]
- ffibuilder.embedding_api(''.join(lines))
-
- As in the example above, you can also use the same ``foo.h`` from
- ``ffibuilder.set_source()``::
-
- ffibuilder.set_source('module_name', r'''
- #include "foo.h"
- ''')
-
-
-.. __: using.html#working
-.. __: using.html#def-extern
-.. __: ref.html#ffi-new-handle
-.. __: cdef.html#cdef
-
-.. _`Using the ffi/lib objects`: using.html
-
-
-Troubleshooting
----------------
-
-* The error message
-
- cffi extension module 'c_module_name' has unknown version 0x2701
-
- means that the running Python interpreter located a CFFI version older
- than 1.5. CFFI 1.5 or newer must be installed in the running Python.
-
-* On PyPy, the error message
-
- debug: pypy_setup_home: directories 'lib-python' and 'lib_pypy' not
- found in pypy's shared library location or in any parent directory
-
- means that the ``libpypy-c.so`` file was found, but the standard library
- was not found from this location. This occurs at least on some Linux
- distributions, because they put ``libpypy-c.so`` inside ``/usr/lib/``,
- instead of the way we recommend, which is: keep that file inside
- ``/opt/pypy/bin/`` and put a symlink to there from ``/usr/lib/``.
- The quickest fix is to do that change manually.
-
-
-Issues about using the .so
---------------------------
-
-This paragraph describes issues that are not necessarily specific to
-CFFI. It assumes that you have obtained the ``.so/.dylib/.dll`` file as
-described above, but that you have troubles using it. (In summary: it
-is a mess. This is my own experience, slowly built by using Google and
-by listening to reports from various platforms. Please report any
-inaccuracies in this paragraph or better ways to do things.)
-
-* The file produced by CFFI should follow this naming pattern:
- ``libmy_plugin.so`` on Linux, ``libmy_plugin.dylib`` on Mac, or
- ``my_plugin.dll`` on Windows (no ``lib`` prefix on Windows).
-
-* First note that this file does not contain the Python interpreter
- nor the standard library of Python. You still need it to be
- somewhere. There are ways to compact it to a smaller number of files,
- but this is outside the scope of CFFI (please report if you used some
- of these ways successfully so that I can add some links here).
-
-* In what we'll call the "main program", the ``.so`` can be either
- used dynamically (e.g. by calling ``dlopen()`` or ``LoadLibrary()``
- inside the main program), or at compile-time (e.g. by compiling it
- with ``gcc -lmy_plugin``). The former case is always used if you're
- building a plugin for a program, and the program itself doesn't need
- to be recompiled. The latter case is for making a CFFI library that
- is more tightly integrated inside the main program.
-
-* In the case of compile-time usage: you can add the gcc
- option ``-Lsome/path/`` before ``-lmy_plugin`` to describe where the
- ``libmy_plugin.so`` is. On some platforms, notably Linux, ``gcc``
- will complain if it can find ``libmy_plugin.so`` but not
- ``libpython27.so`` or ``libpypy-c.so``. To fix it, you need to call
- ``LD_LIBRARY_PATH=/some/path/to/libpypy gcc``.
-
-* When actually executing the main program, it needs to find the
- ``libmy_plugin.so`` but also ``libpython27.so`` or ``libpypy-c.so``.
- For PyPy, unpack a PyPy distribution and you get a full directory
- structure with ``libpypy-c.so`` inside a ``bin`` subdirectory, or on
- Windows ``pypy-c.dll`` inside the top directory; you must not move
- this file around, but just point to it. One way to point to it is by
- running the main program with some environment variable:
- ``LD_LIBRARY_PATH=/some/path/to/libpypy`` on Linux,
- ``DYLD_LIBRARY_PATH=/some/path/to/libpypy`` on OS/X.
-
-* You can avoid the ``LD_LIBRARY_PATH`` issue if you compile
- ``libmy_plugin.so`` with the path hard-coded inside in the first
- place. On Linux, this is done by ``gcc -Wl,-rpath=/some/path``. You
- would put this option in ``ffibuilder.set_source("my_plugin", ...,
- extra_link_args=['-Wl,-rpath=/some/path/to/libpypy'])``. The path can
- start with ``$ORIGIN`` to mean "the directory where
- ``libmy_plugin.so`` is". You can then specify a path relative to that
- place, like ``extra_link_args=['-Wl,-rpath=$ORIGIN/../venv/bin']``.
- Use ``ldd libmy_plugin.so`` to look at what path is currently compiled
- in after the expansion of ``$ORIGIN``.)
-
- After this, you don't need ``LD_LIBRARY_PATH`` any more to locate
- ``libpython27.so`` or ``libpypy-c.so`` at runtime. In theory it
- should also cover the call to ``gcc`` for the main program. I wasn't
- able to make ``gcc`` happy without ``LD_LIBRARY_PATH`` on Linux if
- the rpath starts with ``$ORIGIN``, though.
-
-* The same rpath trick might be used to let the main program find
- ``libmy_plugin.so`` in the first place without ``LD_LIBRARY_PATH``.
- (This doesn't apply if the main program uses ``dlopen()`` to load it
- as a dynamic plugin.) You'd make the main program with ``gcc
- -Wl,-rpath=/path/to/libmyplugin``, possibly with ``$ORIGIN``. The
- ``$`` in ``$ORIGIN`` causes various shell problems on its own: if
- using a common shell you need to say ``gcc
- -Wl,-rpath=\$ORIGIN``. From a Makefile, you need to say
- something like ``gcc -Wl,-rpath=\$$ORIGIN``.
-
-* On some Linux distributions, notably Debian, the ``.so`` files of
- CPython C extension modules may be compiled without saying that they
- depend on ``libpythonX.Y.so``. This makes such Python systems
- unsuitable for embedding if the embedder uses ``dlopen(...,
- RTLD_LOCAL)``. You get an ``undefined symbol`` error. See
- `issue #264`__. A workaround is to first call
- ``dlopen("libpythonX.Y.so", RTLD_LAZY|RTLD_GLOBAL)``, which will
- force ``libpythonX.Y.so`` to be loaded first.
-
-.. __: https://foss.heptapod.net/pypy/cffi/-/issues/264
-
-
-Using multiple CFFI-made DLLs
------------------------------
-
-Multiple CFFI-made DLLs can be used by the same process.
-
-Note that all CFFI-made DLLs in a process share a single Python
-interpreter. The effect is the same as the one you get by trying to
-build a large Python application by assembling a lot of unrelated
-packages. Some of these might be libraries that monkey-patch some
-functions from the standard library, for example, which might be
-unexpected from other parts.
-
-
-Multithreading
---------------
-
-Multithreading should work transparently, based on Python's standard
-Global Interpreter Lock.
-
-If two threads both try to call a C function when Python is not yet
-initialized, then locking occurs. One thread proceeds with
-initialization and blocks the other thread. The other thread will be
-allowed to continue only when the execution of the initialization-time
-Python code is done.
-
-If the two threads call two *different* CFFI-made DLLs, the Python
-initialization itself will still be serialized, but the two pieces of
-initialization-time Python code will not. The idea is that there is a
-priori no reason for one DLL to wait for initialization of the other
-DLL to be complete.
-
-After initialization, Python's standard Global Interpreter Lock kicks
-in. The end result is that when one CPU progresses on executing
-Python code, no other CPU can progress on executing more Python code
-from another thread of the same process. At regular intervals, the
-lock switches to a different thread, so that no single thread should
-appear to block indefinitely.
-
-
-Testing
--------
-
-For testing purposes, a CFFI-made DLL can be imported in a running
-Python interpreter instead of being loaded like a C shared library.
-
-You might have some issues with the file name: for example, on
-Windows, Python expects the file to be called ``c_module_name.pyd``,
-but the CFFI-made DLL is called ``target.dll`` instead. The base name
-``target`` is the one specified in ``ffibuilder.compile()``, and on Windows
-the extension is ``.dll`` instead of ``.pyd``. You have to rename or
-copy the file, or on POSIX use a symlink.
-
-The module then works like a regular CFFI extension module. It is
-imported with "``from c_module_name import ffi, lib``" and exposes on
-the ``lib`` object all C functions. You can test it by calling these
-C functions. The initialization-time Python code frozen inside the
-DLL is executed the first time such a call is done.
-
-
-Embedding and Extending
------------------------
-
-The embedding mode is not incompatible with the non-embedding mode of
-CFFI.
-
-You can use *both* ``ffibuilder.embedding_api()`` and
-``ffibuilder.cdef()`` in the
-same build script. You put in the former the declarations you want to
-be exported by the DLL; you put in the latter only the C functions and
-types that you want to share between C and Python, but not export from
-the DLL.
-
-As an example of that, consider the case where you would like to have
-a DLL-exported C function written in C directly, maybe to handle some
-cases before calling Python functions. To do that, you must *not* put
-the function's signature in ``ffibuilder.embedding_api()``. (Note that this
-requires more hacks if you use ``ffibuilder.embedding_api(f.read())``.)
-You must only write the custom function definition in
-``ffibuilder.set_source()``, and prefix it with the macro CFFI_DLLEXPORT:
-
-.. code-block:: c
-
- CFFI_DLLEXPORT int myfunc(int a, int b)
- {
- /* implementation here */
- }
-
-This function can, if it wants, invoke Python functions using the
-general mechanism of "callbacks"---called this way because it is a
-call from C to Python, although in this case it is not calling
-anything back:
-
-.. code-block:: python
-
- ffibuilder.cdef("""
- extern "Python" int mycb(int);
- """)
-
- ffibuilder.set_source("my_plugin", r"""
-
- static int mycb(int); /* the callback: forward declaration, to make
- it accessible from the C code that follows */
-
- CFFI_DLLEXPORT int myfunc(int a, int b)
- {
- int product = a * b; /* some custom C code */
- return mycb(product);
- }
- """)
-
-and then the Python initialization code needs to contain the lines:
-
-.. code-block:: python
-
- @ffi.def_extern()
- def mycb(x):
- print "hi, I'm called with x =", x
- return x * 10
-
-This ``@ffi.def_extern`` is attaching a Python function to the C
-callback ``mycb()``, which in this case is not exported from the DLL.
-Nevertheless, the automatic initialization of Python occurs when
-``mycb()`` is called, if it happens to be the first function called
-from C. More precisely, it does not happen when ``myfunc()`` is
-called: this is just a C function, with no extra code magically
-inserted around it. It only happens when ``myfunc()`` calls
-``mycb()``.
-
-As the above explanation hints, this is how ``ffibuilder.embedding_api()``
-actually implements function calls that directly invoke Python code;
-here, we have merely decomposed it explicitly, in order to add some
-custom C code in the middle.
-
-In case you need to force, from C code, Python to be initialized
-before the first ``@ffi.def_extern()`` is called, you can do so by
-calling the C function ``cffi_start_python()`` with no argument. It
-returns an integer, 0 or -1, to tell if the initialization succeeded
-or not. Currently there is no way to prevent a failing initialization
-from also dumping a traceback and more information to stderr.
-Note that the function ``cffi_start_python()`` is static: it must be
-called from C source written inside ``ffibuilder.set_source()``. To
-call it from somewhere else, you need to make a function (with a
-different non-static name) in the ``ffibuilder.set_source()`` that just
-calls ``cffi_start_python()``. The reason it is static is to avoid
-naming conflicts in case you are ultimately trying to link a large C
-program with more than one cffi embedded module in it.
diff --git a/doc/source/goals.rst b/doc/source/goals.rst
deleted file mode 100644
index df4877c..0000000
--- a/doc/source/goals.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-Goals
------
-
-The interface is based on `LuaJIT's FFI`_, and follows a few principles:
-
-* The goal is to call C code from Python without learning a 3rd language:
- existing alternatives require users to learn domain specific language
- (Cython_, SWIG_) or API (ctypes_). The CFFI design requires users to know
- only C and Python, minimizing the extra bits of API that need to be learned.
-
-* Keep all the Python-related logic in Python so that you don't need to
- write much C code (unlike `CPython native C extensions`_).
-
-* The preferred way is to work at the level of the API (Application
- Programming Interface): the C compiler is called from the declarations
- you write to validate and link to the C language constructs.
- Alternatively, it is also possible to work at the ABI level
- (Application Binary Interface), the way ctypes_ work.
- However, on non-Windows platforms, C libraries typically
- have a specified C API but not an ABI (e.g. they may
- document a "struct" as having at least these fields, but maybe more).
-
-* Try to be complete. For now some C99 constructs are not supported,
- but all C89 should be, including macros (and including macro "abuses",
- which you can `manually wrap`_ in saner-looking C functions).
-
-* Attempt to support both PyPy and CPython, with a reasonable path
- for other Python implementations like IronPython and Jython.
-
-* Note that this project is **not** about embedding executable C code in
- Python, unlike `Weave`_. This is about calling existing C libraries
- from Python.
-
-* There is no C++ support. Sometimes, it is reasonable to write a C
- wrapper around the C++ code and then call this C API with CFFI.
- Otherwise, look at other projects. I would recommend cppyy_, which
- has got some similarities (and also works efficiently on both CPython
- and PyPy).
-
-.. _`LuaJIT's FFI`: http://luajit.org/ext_ffi.html
-.. _`Cython`: http://www.cython.org
-.. _`SWIG`: http://www.swig.org/
-.. _`CPython native C extensions`: http://docs.python.org/extending/extending.html
-.. _`native C extensions`: http://docs.python.org/extending/extending.html
-.. _`ctypes`: http://docs.python.org/library/ctypes.html
-.. _`Weave`: http://wiki.scipy.org/Weave
-.. _`cppyy`: http://cppyy.readthedocs.io/en/latest/
-.. _`manually wrap`: overview.html#abi-versus-api
-
-Get started by reading `the overview`__.
-
-.. __: overview.html
-
-
-Comments and bugs
------------------
-
-The best way to contact us is on the IRC ``#cffi`` or ``#pypy`` channels of
-``irc.libera.chat``. Feel free to discuss matters either there or in
-the `mailing list`_. Please report to the `issue tracker`_ any bugs.
-
-As a general rule, when there is a design issue to resolve, we pick the
-solution that is the "most C-like". We hope that this module has got
-everything you need to access C code and nothing more.
-
---- the authors, Armin Rigo and Maciej Fijalkowski
-
-.. _`issue tracker`: https://foss.heptapod.net/pypy/cffi/issues
-.. _`mailing list`: https://groups.google.com/forum/#!forum/python-cffi
diff --git a/doc/source/index.rst b/doc/source/index.rst
deleted file mode 100644
index 54934f2..0000000
--- a/doc/source/index.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-================================
-CFFI documentation
-================================
-
-C Foreign Function Interface for Python. Interact with almost any C
-code from Python, based on C-like declarations that you can often
-copy-paste from header files or documentation.
-
-.. toctree::
- :maxdepth: 2
-
- goals
- whatsnew
- installation
- overview
- using
- ref
- cdef
- embedding
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
deleted file mode 100644
index 6d55eb5..0000000
--- a/doc/source/installation.rst
+++ /dev/null
@@ -1,190 +0,0 @@
-=======================================================
-Installation and Status
-=======================================================
-
-Quick installation for CPython (cffi is distributed with PyPy):
-
-* ``pip install cffi``
-
-* or get the source code via the `Python Package Index`__.
-
-.. __: http://pypi.python.org/pypi/cffi
-
-In more details:
-
-This code has been developed on Linux, but should work on any POSIX
-platform as well as on Windows 32 and 64. (It relies occasionally on
-libffi, so it depends on libffi being bug-free; this may not be fully
-the case on some of the more exotic platforms.)
-
-CFFI supports CPython 2.7, 3.x (tested with 3.6 to 3.9); and is
-distributed with PyPy (CFFI 1.0 is distributed with and requires
-PyPy 2.6).
-
-The core speed of CFFI is better than ctypes, with import times being
-either lower if you use the post-1.0 features, or much higher if you
-don't. The wrapper Python code you typically need to write around the
-raw CFFI interface slows things down on CPython, but not unreasonably
-so. On PyPy, this wrapper code has a minimal impact thanks to the JIT
-compiler. This makes CFFI the recommended way to interface with C
-libraries on PyPy.
-
-Requirements:
-
-* CPython 2.7 or 3.x, or PyPy (PyPy 2.0 for the earliest
- versions of CFFI; or PyPy 2.6 for CFFI 1.0).
-
-* in some cases you need to be able to compile C extension modules.
- On non-Windows platforms, this usually means installing the package
- ``python-dev``. Refer to the appropriate docs for your OS.
-
-* on CPython, on non-Windows platforms, you also need to install
- ``libffi-dev`` in order to compile CFFI itself.
-
-* pycparser >= 2.06: https://github.com/eliben/pycparser (automatically
- tracked by ``pip install cffi``).
-
-* `py.test`_ is needed to run the tests of CFFI itself.
-
-.. _`py.test`: http://pypi.python.org/pypi/pytest
-
-Download and Installation:
-
-* https://pypi.python.org/pypi/cffi
-
-* Checksums of the "source" package version 1.15.0:
-
- - MD5: f3a3f26cd3335fc597479c9475da0a0b
-
- - SHA1: 9c51c29e35510adf7f94542e1f8e05611930b07b
-
- - SHA256: 920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954
-
-* Or grab the most current version from the `Heptapod page`_:
- ``hg clone https://foss.heptapod.net/pypy/cffi``
-
-* ``python setup.py install`` or ``python setup_base.py install``
- (should work out of the box on Linux or Windows; see below for
- `MacOS X`_.)
-
-* running the tests: ``py.test c/ testing/`` (if you didn't
- install cffi yet, you need first ``python setup_base.py build_ext -f
- -i``)
-
-.. _`Heptapod page`: https://foss.heptapod.net/pypy/cffi
-
-Demos:
-
-* The `demo`_ directory contains a number of small and large demos
- of using ``cffi``.
-
-* The documentation below might be sketchy on details; for now the
- ultimate reference is given by the tests, notably
- `testing/cffi1/test_verify1.py`_ and `testing/cffi0/backend_tests.py`_.
-
-.. _`demo`: https://foss.heptapod.net/pypy/cffi/-/tree/branch/default/demo
-.. _`testing/cffi1/test_verify1.py`: https://foss.heptapod.net/pypy/cffi/-/blob/branch/default/testing/cffi1/test_verify1.py
-.. _`testing/cffi0/backend_tests.py`: https://foss.heptapod.net/pypy/cffi/-/blob/branch/default/testing/cffi0/backend_tests.py
-
-
-Platform-specific instructions
-------------------------------
-
-``libffi`` is notoriously messy to install and use --- to the point that
-CPython includes its own copy to avoid relying on external packages.
-CFFI does the same for Windows, but not for other platforms (which should
-have their own working libffi's).
-Modern Linuxes work out of the box thanks to ``pkg-config``. Here are some
-(user-supplied) instructions for other platforms.
-
-
-MacOS X
-+++++++
-
-**Homebrew** (Thanks David Griffin for this)
-
-1) Install homebrew: http://brew.sh
-
-2) Run the following commands in a terminal
-
-::
-
- brew install pkg-config libffi
- PKG_CONFIG_PATH=/usr/local/opt/libffi/lib/pkgconfig pip install cffi
-
-
-Alternatively, **on OS/X 10.6** (Thanks Juraj Sukop for this)
-
-For building libffi you can use the default install path, but then, in
-``setup.py`` you need to change::
-
- include_dirs = []
-
-to::
-
- include_dirs = ['/usr/local/lib/libffi-3.0.11/include']
-
-Then running ``python setup.py build`` complains about "fatal error: error writing to -: Broken pipe", which can be fixed by running::
-
- ARCHFLAGS="-arch i386 -arch x86_64" python setup.py build
-
-as described here_.
-
-.. _here: http://superuser.com/questions/259278/python-2-6-1-pycrypto-2-3-pypi-package-broken-pipe-during-build
-
-
-Windows (32/64-bit)
-+++++++++++++++++++
-
-Win32 and Win64 work and are tested at least each official release.
-
-The recommended C compiler compatible with Python 2.7 is this one:
-http://www.microsoft.com/en-us/download/details.aspx?id=44266
-There is a known problem with distutils on Python 2.7, as
-explained in https://bugs.python.org/issue23246, and the same
-problem applies whenever you want to run compile() to build a dll with
-this specific compiler suite download.
-``import setuptools`` might help, but YMMV
-
-For Python 3.4 and beyond:
-https://www.visualstudio.com/en-us/downloads/visual-studio-2015-ctp-vs
-
-
-Linux and OS/X: UCS2 versus UCS4
-++++++++++++++++++++++++++++++++
-
-This is about getting an ImportError about ``_cffi_backend.so`` with a
-message like ``Symbol not found: _PyUnicodeUCS2_AsASCIIString``. This
-error occurs in Python 2 as soon as you mix "ucs2" and "ucs4" builds of
-Python. It means that you are now running a Python compiled with
-"ucs4", but the extension module ``_cffi_backend.so`` was compiled by a
-different Python: one that was running "ucs2". (If the opposite problem
-occurs, you get an error about ``_PyUnicodeUCS4_AsASCIIString``
-instead.)
-
-If you are using ``pyenv``, then see
-https://github.com/yyuu/pyenv/issues/257.
-
-More generally, the solution that should always work is to download the
-sources of CFFI (instead of a prebuilt binary) and make sure that you
-build it with the same version of Python than the one that will use it.
-For example, with virtualenv:
-
-* ``virtualenv ~/venv``
-
-* ``cd ~/path/to/sources/of/cffi``
-
-* ``~/venv/bin/python setup.py build --force`` # forcing a rebuild to
- make sure
-
-* ``~/venv/bin/python setup.py install``
-
-This will compile and install CFFI in this virtualenv, using the
-Python from this virtualenv.
-
-
-NetBSD
-++++++
-
-You need to make sure you have an up-to-date version of libffi, which
-fixes some bugs.
diff --git a/doc/source/overview.rst b/doc/source/overview.rst
deleted file mode 100644
index dbc3540..0000000
--- a/doc/source/overview.rst
+++ /dev/null
@@ -1,651 +0,0 @@
-=======================================================
-Overview
-=======================================================
-
-.. contents::
-
-
-The first section presents a simple working
-example of using CFFI to call a C function in a compiled shared object
-(DLL) from Python. CFFI is
-flexible and covers several other use cases presented in the second
-section. The third section shows how to export Python functions
-to a Python interpreter embedded in a C or C++ application. The last
-two sections delve deeper in the CFFI library.
-
-Make sure you have `cffi installed`__.
-
-.. __: installation.html
-
-.. _out-of-line-api-level:
-.. _real-example:
-
-
-Main mode of usage
-------------------
-
-The main way to use CFFI is as an interface to some already-compiled
-shared object which is provided by other means. Imagine that you have a
-system-installed shared object called ``piapprox.dll`` (Windows) or
-``libpiapprox.so`` (Linux and others) or ``libpiapprox.dylib`` (OS X),
-exporting a function ``float pi_approx(int n);`` that computes some
-approximation of pi given a number of iterations. You want to call
-this function from Python. Note this method works equally well with a
-static library ``piapprox.lib`` (Windows) or ``libpiapprox.a``.
-
-Create the file ``piapprox_build.py``:
-
-.. code-block:: python
-
- from cffi import FFI
- ffibuilder = FFI()
-
- # cdef() expects a single string declaring the C types, functions and
- # globals needed to use the shared object. It must be in valid C syntax.
- ffibuilder.cdef("""
- float pi_approx(int n);
- """)
-
- # set_source() gives the name of the python extension module to
- # produce, and some C source code as a string. This C code needs
- # to make the declarated functions, types and globals available,
- # so it is often just the "#include".
- ffibuilder.set_source("_pi_cffi",
- """
- #include "pi.h" // the C header of the library
- """,
- libraries=['piapprox']) # library name, for the linker
-
- if __name__ == "__main__":
- ffibuilder.compile(verbose=True)
-
-Execute this script. If everything is OK, it should produce
-``_pi_cffi.c``, and then invoke the compiler on it. The produced
-``_pi_cffi.c`` contains a copy of the string given in :ref:`set_source() <set_source>`,
-in this example the ``#include "pi.h"``. Afterwards, it contains glue code
-for all the functions, types and globals declared in the :ref:`cdef() <cdef>` above.
-
-At runtime, you use the extension module like this:
-
-.. code-block:: python
-
- from _pi_cffi import ffi, lib
- print(lib.pi_approx(5000))
-
-That's all! In the rest of this page, we describe some more advanced
-examples and other CFFI modes. In particular, there is a complete
-example `if you don't have an already-installed C library to call`_.
-
-For more information about the ``cdef()`` and ``set_source()`` methods
-of the ``FFI`` class, see `Preparing and Distributing modules`__.
-
-.. __: cdef.html
-
-When your example works, a common alternative to running the build
-script manually is to have it run as part of a ``setup.py``. Here is
-an example using the Setuptools distribution:
-
-.. code-block:: python
-
- from setuptools import setup
-
- setup(
- ...
- setup_requires=["cffi>=1.0.0"],
- cffi_modules=["piapprox_build:ffibuilder"], # "filename:global"
- install_requires=["cffi>=1.0.0"],
- )
-
-
-Other CFFI modes
-----------------
-
-CFFI can be used in one of four modes: "ABI" versus "API" level,
-each with "in-line" or "out-of-line" preparation (or compilation).
-
-The **ABI mode** accesses libraries at the binary level, whereas the
-faster **API mode** accesses them with a C compiler. We explain the
-difference in more details below__.
-
-.. __: `abi-versus-api`_
-
-In the **in-line mode,** everything is set up every time you import
-your Python code. In the **out-of-line mode,** you have a separate
-step of preparation (and possibly C compilation) that produces a
-module which your main program can then import.
-
-
-Simple example (ABI level, in-line)
-+++++++++++++++++++++++++++++++++++
-
-May look familiar to those who have used ctypes_.
-
-.. code-block:: python
-
- >>> from cffi import FFI
- >>> ffi = FFI()
- >>> ffi.cdef("""
- ... int printf(const char *format, ...); // copy-pasted from the man page
- ... """)
- >>> C = ffi.dlopen(None) # loads the entire C namespace
- >>> arg = ffi.new("char[]", b"world") # equivalent to C code: char arg[] = "world";
- >>> C.printf(b"hi there, %s.\n", arg) # call printf
- hi there, world.
- 17 # this is the return value
- >>>
-
-Note that ``char *`` arguments expect a ``bytes`` object. If you have a
-``str`` (or a ``unicode`` on Python 2) you need to encode it explicitly
-with ``somestring.encode(myencoding)``.
-
-*Python 3 on Windows:* :ref:`ffi.dlopen(None) <dlopen>` does not work. This problem
-is messy and not really fixable. The problem does not occur if you try
-to call a function from a specific DLL that exists on your system: then
-you use ``ffi.dlopen("path.dll")``.
-
-*This example does not call any C compiler. It works in the so-called
-ABI mode, which means that it will crash if you call some function or
-access some fields of a structure that was slightly misdeclared in the
-cdef().*
-
-If using a C compiler to install your module is an option, it is highly
-recommended to use the API mode instead. (It is also faster.)
-
-
-Struct/Array Example (minimal, in-line)
-+++++++++++++++++++++++++++++++++++++++
-
-.. code-block:: python
-
- from cffi import FFI
- ffi = FFI()
- ffi.cdef("""
- typedef struct {
- unsigned char r, g, b;
- } pixel_t;
- """)
- image = ffi.new("pixel_t[]", 800*600)
-
- f = open('data', 'rb') # binary mode -- important
- f.readinto(ffi.buffer(image))
- f.close()
-
- image[100].r = 255
- image[100].g = 192
- image[100].b = 128
-
- f = open('data', 'wb')
- f.write(ffi.buffer(image))
- f.close()
-
-This can be used as a more flexible replacement of the struct_ and
-array_ modules, and replaces ctypes_. You could also call :ref:`ffi.new("pixel_t[600][800]") <new>`
-and get a two-dimensional array.
-
-.. _struct: http://docs.python.org/library/struct.html
-.. _array: http://docs.python.org/library/array.html
-.. _ctypes: http://docs.python.org/library/ctypes.html
-
-*This example does not call any C compiler.*
-
-This example also admits an out-of-line equivalent. It is similar to
-the first example `Main mode of usage`_ above,
-but passing ``None`` as the second argument to
-:ref:`ffibuilder.set_source() <set_source>`. Then in the main program you write
-``from _simple_example import ffi`` and then the same content as the
-in-line example above starting from the line ``image =
-ffi.new("pixel_t[]", 800*600)``.
-
-
-API Mode, calling the C standard library
-++++++++++++++++++++++++++++++++++++++++
-
-.. code-block:: python
-
- # file "example_build.py"
-
- # Note: we instantiate the same 'cffi.FFI' class as in the previous
- # example, but call the result 'ffibuilder' now instead of 'ffi';
- # this is to avoid confusion with the other 'ffi' object you get below
-
- from cffi import FFI
- ffibuilder = FFI()
-
- ffibuilder.set_source("_example",
- r""" // passed to the real C compiler,
- // contains implementation of things declared in cdef()
- #include <sys/types.h>
- #include <pwd.h>
-
- // We can also define custom wrappers or other functions
- // here (this is an example only):
- static struct passwd *get_pw_for_root(void) {
- return getpwuid(0);
- }
- """,
- libraries=[]) # or a list of libraries to link with
- # (more arguments like setup.py's Extension class:
- # include_dirs=[..], extra_objects=[..], and so on)
-
- ffibuilder.cdef("""
- // declarations that are shared between Python and C
- struct passwd {
- char *pw_name;
- ...; // literally dot-dot-dot
- };
- struct passwd *getpwuid(int uid); // defined in <pwd.h>
- struct passwd *get_pw_for_root(void); // defined in set_source()
- """)
-
- if __name__ == "__main__":
- ffibuilder.compile(verbose=True)
-
-You need to run the ``example_build.py`` script once to generate
-"source code" into the file ``_example.c`` and compile this to a
-regular C extension module. (CFFI selects either Python or C for the
-module to generate based on whether the second argument to
-:ref:`set_source() <set_source>` is ``None`` or not.)
-
-*You need a C compiler for this single step. It produces a file called
-e.g. _example.so or _example.pyd. If needed, it can be distributed in
-precompiled form like any other extension module.*
-
-Then, in your main program, you use:
-
-.. code-block:: python
-
- from _example import ffi, lib
-
- p = lib.getpwuid(0)
- assert ffi.string(p.pw_name) == b'root'
- p = lib.get_pw_for_root()
- assert ffi.string(p.pw_name) == b'root'
-
-Note that this works independently of the exact C layout of ``struct
-passwd`` (it is "API level", as opposed to "ABI level"). It requires
-a C compiler in order to run ``example_build.py``, but it is much more
-portable than trying to get the details of the fields of ``struct
-passwd`` exactly right. Similarly, in the :ref:`cdef() <cdef>` we declared
-``getpwuid()`` as taking an ``int`` argument; on some platforms this
-might be slightly incorrect---but it does not matter.
-
-Note also that at runtime, the API mode is faster than the ABI mode.
-
-To integrate it inside a ``setup.py`` distribution with Setuptools:
-
-.. code-block:: python
-
- from setuptools import setup
-
- setup(
- ...
- setup_requires=["cffi>=1.0.0"],
- cffi_modules=["example_build.py:ffibuilder"],
- install_requires=["cffi>=1.0.0"],
- )
-
-
-.. _`if you don't have an already-installed C library to call`:
-
-API Mode, calling C sources instead of a compiled library
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-If you want to call some library that is not precompiled, but for which
-you have C sources, then the easiest solution is to make a single
-extension module that is compiled from both the C sources of this
-library, and the additional CFFI wrappers. For example, say you start
-with the files ``pi.c`` and ``pi.h``:
-
- .. code-block:: C
-
- /* filename: pi.c*/
- # include <stdlib.h>
- # include <math.h>
-
- /* Returns a very crude approximation of Pi
- given a int: a number of iteration */
- float pi_approx(int n){
-
- double i,x,y,sum=0;
-
- for(i=0;i<n;i++){
-
- x=rand();
- y=rand();
-
- if (sqrt(x*x+y*y) < sqrt((double)RAND_MAX*RAND_MAX))
- sum++; }
-
- return 4*(float)sum/(float)n; }
-
- .. code-block:: C
-
- /* filename: pi.h*/
- float pi_approx(int n);
-
-Create a script named ``pi_extension_build.py``, building
-the C extension:
-
- .. code-block:: python
-
- from cffi import FFI
- ffibuilder = FFI()
-
- ffibuilder.cdef("float pi_approx(int n);")
-
- ffibuilder.set_source("_pi", # name of the output C extension
- """
- #include "pi.h"
- """,
- sources=['pi.c'], # includes pi.c as additional sources
- libraries=['m']) # on Unix, link with the math library
-
- if __name__ == "__main__":
- ffibuilder.compile(verbose=True)
-
-Build the extension:
-
- .. code-block:: shell
-
- python pi_extension_build.py
-
-Observe, in the working directory, the generated output files:
-``_pi.c``, ``_pi.o`` and the compiled C extension (called ``_pi.so`` on
-Linux for example). It can be called from Python:
-
- .. code-block:: python
-
- from _pi.lib import pi_approx
-
- approx = pi_approx(10)
- assert str(approx).startswith("3.")
-
- approx = pi_approx(10000)
- assert str(approx).startswith("3.1")
-
-
-.. _performance:
-
-Purely for performance (API level, out-of-line)
-+++++++++++++++++++++++++++++++++++++++++++++++
-
-A variant of the `section above`__ where the goal is not to call an
-existing C library, but to compile and call some C function written
-directly in the build script:
-
-.. __: real-example_
-
-.. code-block:: python
-
- # file "example_build.py"
-
- from cffi import FFI
- ffibuilder = FFI()
-
- ffibuilder.cdef("int foo(int *, int *, int);")
-
- ffibuilder.set_source("_example",
- r"""
- static int foo(int *buffer_in, int *buffer_out, int x)
- {
- /* some algorithm that is seriously faster in C than in Python */
- }
- """)
-
- if __name__ == "__main__":
- ffibuilder.compile(verbose=True)
-
-.. code-block:: python
-
- # file "example.py"
-
- from _example import ffi, lib
-
- buffer_in = ffi.new("int[]", 1000)
- # initialize buffer_in here...
-
- # easier to do all buffer allocations in Python and pass them to C,
- # even for output-only arguments
- buffer_out = ffi.new("int[]", 1000)
-
- result = lib.foo(buffer_in, buffer_out, 1000)
-
-*You need a C compiler to run example_build.py, once. It produces a
-file called e.g. _example.so or _example.pyd. If needed, it can be
-distributed in precompiled form like any other extension module.*
-
-
-.. _out-of-line-abi-level:
-
-Out-of-line, ABI level
-++++++++++++++++++++++
-
-The out-of-line ABI mode is a mixture of the regular (API) out-of-line
-mode and the in-line ABI mode. It lets you use the ABI mode, with its
-advantages (not requiring a C compiler) and problems (crashes more
-easily).
-
-This mixture mode lets you massively reduces the import times, because
-it is slow to parse a large C header. It also allows you to do more
-detailed checkings during build-time without worrying about performance
-(e.g. calling :ref:`cdef() <cdef>` many times with small pieces of declarations,
-based on the version of libraries detected on the system).
-
-.. code-block:: python
-
- # file "simple_example_build.py"
-
- from cffi import FFI
-
- ffibuilder = FFI()
- # Note that the actual source is None
- ffibuilder.set_source("_simple_example", None)
- ffibuilder.cdef("""
- int printf(const char *format, ...);
- """)
-
- if __name__ == "__main__":
- ffibuilder.compile(verbose=True)
-
-Running it once produces ``_simple_example.py``. Your main program
-only imports this generated module, not ``simple_example_build.py``
-any more:
-
-.. code-block:: python
-
- from _simple_example import ffi
-
- lib = ffi.dlopen(None) # Unix: open the standard C library
- #import ctypes.util # or, try this on Windows:
- #lib = ffi.dlopen(ctypes.util.find_library("c"))
-
- lib.printf(b"hi there, number %d\n", ffi.cast("int", 2))
-
-Note that this :ref:`ffi.dlopen() <dlopen>`, unlike the one from in-line mode,
-does not invoke any additional magic to locate the library: it must be
-a path name (with or without a directory), as required by the C
-``dlopen()`` or ``LoadLibrary()`` functions. This means that
-``ffi.dlopen("libfoo.so")`` is ok, but ``ffi.dlopen("foo")`` is not.
-In the latter case, you could replace it with
-``ffi.dlopen(ctypes.util.find_library("foo"))``. Also, None is only
-recognized on Unix to open the standard C library.
-
-For distribution purposes, remember that there is a new
-``_simple_example.py`` file generated. You can either include it
-statically within your project's source files, or, with Setuptools,
-you can say in the ``setup.py``:
-
-.. code-block:: python
-
- from setuptools import setup
-
- setup(
- ...
- setup_requires=["cffi>=1.0.0"],
- cffi_modules=["simple_example_build.py:ffibuilder"],
- install_requires=["cffi>=1.0.0"],
- )
-
-In summary, this mode is useful when you wish to declare many C structures but
-do not need fast interaction with a shared object. It is useful for parsing
-binary files, for instance.
-
-
-In-line, API level
-++++++++++++++++++
-
-The "API level + in-line" mode combination exists but is long
-deprecated. It used to be done with ``lib = ffi.verify("C header")``.
-The out-of-line variant with :ref:`set_source("modname", "C header") <set_source>` is
-preferred and avoids a number of problems when the project grows in
-size.
-
-
-.. _embedding:
-
-Embedding
----------
-
-*New in version 1.5.*
-
-CFFI can be used for embedding__: creating a standard
-dynamically-linked library (``.dll`` under Windows, ``.so`` elsewhere)
-which can be used from a C application.
-
-.. code-block:: python
-
- import cffi
- ffibuilder = cffi.FFI()
-
- ffibuilder.embedding_api("""
- int do_stuff(int, int);
- """)
-
- ffibuilder.set_source("my_plugin", "")
-
- ffibuilder.embedding_init_code("""
- from my_plugin import ffi
-
- @ffi.def_extern()
- def do_stuff(x, y):
- print("adding %d and %d" % (x, y))
- return x + y
- """)
-
- ffibuilder.compile(target="plugin-1.5.*", verbose=True)
-
-This simple example creates ``plugin-1.5.dll`` or ``plugin-1.5.so`` as
-a DLL with a single exported function, ``do_stuff()``. You execute
-the script above once, with the interpreter you want to have
-internally used; it can be CPython 2.x or 3.x or PyPy. This DLL can
-then be used "as usual" from an application; the application doesn't
-need to know that it is talking with a library made with Python and
-CFFI. At runtime, when the application calls ``int do_stuff(int,
-int)``, the Python interpreter is automatically initialized and ``def
-do_stuff(x, y):`` gets called. `See the details in the documentation
-about embedding.`__
-
-.. __: embedding.html
-.. __: embedding.html
-
-
-What actually happened?
------------------------
-
-The CFFI interface operates on the same level as C - you declare types
-and functions using the same syntax as you would define them in C. This
-means that most of the documentation or examples can be copied straight
-from the man pages.
-
-The declarations can contain **types, functions, constants**
-and **global variables.** What you pass to the :ref:`cdef() <cdef>` must not
-contain more than that; in particular, ``#ifdef`` or ``#include``
-directives are not supported. The cdef in the above examples are just
-that - they declared "there is a function in the C level with this
-given signature", or "there is a struct type with this shape".
-
-In the ABI examples, the :ref:`dlopen() <dlopen>` calls load libraries manually.
-At the binary level, a program is split into multiple namespaces---a
-global one (on some platforms), plus one namespace per library. So
-``dlopen()`` returns a ``<FFILibrary>`` object, and this object has
-got as attributes all function, constant and variable symbols that are
-coming from this library and that have been declared in the
-``cdef()``. If you have several interdependent libraries to load,
-you would call ``cdef()`` only once but ``dlopen()`` several times.
-
-By opposition, the API mode works more closely like a C program: the C
-linker (static or dynamic) is responsible for finding any symbol used.
-You name the libraries in the ``libraries`` keyword argument to
-:ref:`set_source() <set_source>`, but never need to say which symbol comes
-from which library.
-Other common arguments to ``set_source()`` include ``library_dirs`` and
-``include_dirs``; all these arguments are passed to the standard
-distutils/setuptools.
-
-The :ref:`ffi.new() <new>` lines allocate C objects. They are filled
-with zeroes initially, unless the optional second argument is used.
-If specified, this argument gives an "initializer", like you can use
-with C code to initialize global variables.
-
-The actual ``lib.*()`` function calls should be obvious: it's like C.
-
-
-.. _abi-versus-api:
-
-ABI versus API
---------------
-
-Accessing the C library at the binary level ("ABI") is fraught
-with problems, particularly on non-Windows platforms.
-
-The most immediate drawback of the ABI level is that calling functions
-needs to go through the very general *libffi* library, which is slow
-(and not always perfectly tested on non-standard platforms). The API
-mode instead compiles a CPython C wrapper that directly invokes the
-target function. It can be massively faster (and works
-better than libffi ever will).
-
-The more fundamental reason to prefer the API mode is that *the C
-libraries are typically meant to be used with a C compiler.* You are not
-supposed to do things like guess where fields are in the structures.
-The "real example" above shows how CFFI uses a C compiler under the
-hood: this example uses :ref:`set_source(..., "C source...") <set_source>` and never
-:ref:`dlopen() <dlopen>`. When using this approach,
-we have the advantage that we can use literally "``...``" at various places in
-the :ref:`cdef() <cdef>`, and the missing information will be completed with the
-help of the C compiler. CFFI will turn this into a single C source file,
-which contains the "C source" part unmodified, followed by some
-"magic" C code and declarations derived from the ``cdef()``. When
-this C file is compiled, the resulting C extension module will contain
-all the information we need---or the C compiler will give warnings or
-errors, as usual e.g. if we misdeclare some function's signature.
-
-Note that the "C source" part from ``set_source()`` can contain
-arbitrary C code. You can use this to declare some
-more helper functions written in C. To export
-these helpers to Python, put their signature in the ``cdef()`` too.
-(You can use the ``static`` C keyword in the "C source" part,
-as in ``static int myhelper(int x) { return x * 42; }``,
-because these helpers are only
-referenced from the "magic" C code that is generated afterwards in the
-same C file.)
-
-This can be used for example to wrap "crazy" macros into more standard
-C functions. The extra layer of C can be useful for other reasons
-too, like calling functions that expect some complicated argument
-structures that you prefer to build in C rather than in Python. (On
-the other hand, if all you need is to call "function-like" macros,
-then you can directly declare them in the ``cdef()`` as if they were
-functions.)
-
-The generated piece of C code should be the same independently on the
-platform on which you run it (or the Python version), so in simple cases
-you can directly distribute the pre-generated C code and treat it as a
-regular C extension module (which depends on the ``_cffi_backend``
-module, on CPython). The special Setuptools lines in the `example
-above`__ are meant for the more complicated cases where we need to
-regenerate the C sources as well---e.g. because the Python script that
-regenerates this file will itself look around the system to know what it
-should include or not.
-
-.. __: real-example_
diff --git a/doc/source/ref.rst b/doc/source/ref.rst
deleted file mode 100644
index 05c0f7c..0000000
--- a/doc/source/ref.rst
+++ /dev/null
@@ -1,1028 +0,0 @@
-================================
-CFFI Reference
-================================
-
-.. contents::
-
-
-FFI Interface
--------------
-
-*This page documents the runtime interface of the two types "FFI" and
-"CompiledFFI". These two types are very similar to each other. You get
-a CompiledFFI object if you import an out-of-line module. You get a FFI
-object from explicitly writing cffi.FFI(). Unlike CompiledFFI, the type
-FFI has also got additional methods documented on the* `next page`__.
-
-.. __: cdef.html
-
-
-ffi.NULL
-++++++++
-
-**ffi.NULL**: a constant NULL of type ``<cdata 'void *'>``.
-
-
-ffi.error
-+++++++++
-
-**ffi.error**: the Python exception raised in various cases. (Don't
-confuse it with ``ffi.errno``.)
-
-
-.. _new:
-
-ffi.new()
-+++++++++
-
-**ffi.new(cdecl, init=None)**:
-allocate an instance according to the specified C type and return a
-pointer to it. The specified C type must be either a pointer or an
-array: ``new('X *')`` allocates an X and returns a pointer to it,
-whereas ``new('X[10]')`` allocates an array of 10 X'es and returns an
-array referencing it (which works mostly like a pointer, like in C).
-You can also use ``new('X[]', n)`` to allocate an array of a
-non-constant length n. See the `detailed documentation`__ for other
-valid initializers.
-
-.. __: using.html#working
-
-When the returned ``<cdata>`` object goes out of scope, the memory is
-freed. In other words the returned ``<cdata>`` object has ownership of
-the value of type ``cdecl`` that it points to. This means that the raw
-data can be used as long as this object is kept alive, but must not be
-used for a longer time. Be careful about that when copying the
-pointer to the memory somewhere else, e.g. into another structure.
-Also, this means that a line like ``x = ffi.cast("B *", ffi.new("A *"))``
-or ``x = ffi.new("struct s[1]")[0]`` is wrong: the newly allocated object
-goes out of scope instantly, and so is freed immediately, and ``x`` is
-garbage. The only case where this is fine comes from a special case for
-pointers-to-struct and pointers-to-union types: after
-``p = ffi.new("struct-or-union *", ..)``, then either ``p`` or ``p[0]``
-keeps the memory alive.
-
-The returned memory is initially cleared (filled with zeroes), before
-the optional initializer is applied. For performance, see
-`ffi.new_allocator()`_ for a way to allocate non-zero-initialized
-memory.
-
-*New in version 1.12:* see also ``ffi.release()``.
-
-
-ffi.cast()
-++++++++++
-
-**ffi.cast("C type", value)**: similar to a C cast: returns an
-instance of the named C type initialized with the given value. The
-value is casted between integers or pointers of any type.
-
-
-.. _ffi-errno:
-.. _ffi-getwinerror:
-
-ffi.errno, ffi.getwinerror()
-++++++++++++++++++++++++++++
-
-**ffi.errno**: the value of ``errno`` received from the most recent C call
-in this thread, and passed to the following C call. (This is a thread-local
-read-write property.)
-
-**ffi.getwinerror(code=-1)**: on Windows, in addition to ``errno`` we
-also save and restore the ``GetLastError()`` value across function
-calls. This function returns this error code as a tuple ``(code,
-message)``, adding a readable message like Python does when raising
-WindowsError. If the argument ``code`` is given, format that code into
-a message instead of using ``GetLastError()``.
-(Note that it is also possible to declare and call the ``GetLastError()``
-function as usual.)
-
-
-.. _ffi-string:
-.. _ffi-unpack:
-
-ffi.string(), ffi.unpack()
-++++++++++++++++++++++++++
-
-**ffi.string(cdata, [maxlen])**: return a Python string (or unicode
-string) from the 'cdata'.
-
-- If 'cdata' is a pointer or array of characters or bytes, returns the
- null-terminated string. The returned string extends until the first
- null character. The 'maxlen' argument limits how far we look for a
- null character. If 'cdata' is an
- array then 'maxlen' defaults to its length. See ``ffi.unpack()`` below
- for a way to continue past the first null character. *Python 3:* this
- returns a ``bytes``, not a ``str``.
-
-- If 'cdata' is a pointer or array of wchar_t, returns a unicode string
- following the same rules. *New in version 1.11:* can also be
- char16_t or char32_t.
-
-- If 'cdata' is a single character or byte or a wchar_t or charN_t,
- returns it as a byte string or unicode string. (Note that in some
- situation a single wchar_t or char32_t may require a Python unicode
- string of length 2.)
-
-- If 'cdata' is an enum, returns the value of the enumerator as a string.
- If the value is out of range, it is simply returned as the stringified
- integer.
-
-**ffi.unpack(cdata, length)**: unpacks an array of C data of the given
-length, returning a Python string/unicode/list. The 'cdata' should be
-a pointer; if it is an array it is first converted to the pointer
-type. *New in version 1.6.*
-
-- If 'cdata' is a pointer to 'char', returns a byte string. It does
- not stop at the first null. (An equivalent way to do that is
- ``ffi.buffer(cdata, length)[:]``.)
-
-- If 'cdata' is a pointer to 'wchar_t', returns a unicode string.
- ('length' is measured in number of wchar_t; it is not the size in
- bytes.) *New in version 1.11:* can also be char16_t or char32_t.
-
-- If 'cdata' is a pointer to anything else, returns a list, of the
- given 'length'. (A slower way to do that is ``[cdata[i] for i in
- range(length)]``.)
-
-
-.. _ffi-buffer:
-.. _ffi-from-buffer:
-
-ffi.buffer(), ffi.from_buffer()
-+++++++++++++++++++++++++++++++
-
-**ffi.buffer(cdata, [size])**: return a buffer object that references
-the raw C data pointed to by the given 'cdata', of 'size' bytes. What
-Python calls "a buffer", or more precisely "an object supporting the
-buffer interface", is an object that represents some raw memory and
-that can be passed around to various built-in or extension functions;
-these built-in functions read from or write to the raw memory directly,
-without needing an extra copy.
-
-The 'cdata' argument
-must be a pointer or an array. If unspecified, the size of the
-buffer is either the size of what ``cdata`` points to, or the whole size
-of the array.
-
-Here are a few examples of where buffer() would be useful:
-
-- use ``file.write()`` and ``file.readinto()`` with
- such a buffer (for files opened in binary mode)
-
-- overwrite the content of a struct: if ``p`` is a cdata pointing to
- it, use ``ffi.buffer(p)[:] = newcontent``, where ``newcontent`` is
- a bytes object (``str`` in Python 2).
-
-Remember that like in C, you can use ``array + index`` to get the pointer
-to the index'th item of an array. (In C you might more naturally write
-``&array[index]``, but that is equivalent.)
-
-The returned object's type is not the builtin ``buffer`` nor ``memoryview``
-types, because these types' API changes too much across Python versions.
-Instead it has the following Python API (a subset of Python 2's ``buffer``)
-in addition to supporting the buffer interface:
-
-- ``buf[:]`` or ``bytes(buf)``: copy data out of the buffer, returning a
- regular byte string (or ``buf[start:end]`` for a part)
-
-- ``buf[:] = newstr``: copy data into the buffer (or ``buf[start:end]
- = newstr``)
-
-- ``len(buf)``, ``buf[index]``, ``buf[index] = newchar``: access as a sequence
- of characters.
-
-The buffer object returned by ``ffi.buffer(cdata)`` keeps alive the
-``cdata`` object: if it was originally an owning cdata, then its
-owned memory will not be freed as long as the buffer is alive.
-
-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
-byte strings). Use ``buf[:]`` instead.
-
-*New in version 1.10:* ``ffi.buffer`` is now the type of the returned
-buffer objects; ``ffi.buffer()`` actually calls the constructor.
-
-**ffi.from_buffer([cdecl,] python_buffer, require_writable=False)**:
-return an array cdata (by default a ``<cdata 'char[]'>``) that
-points to the data of the given Python object, which must support the
-buffer interface. Note that ``ffi.from_buffer()`` turns a generic
-Python buffer object into a cdata object, whereas ``ffi.buffer()`` does
-the opposite conversion. Both calls don't actually copy any data.
-
-``ffi.from_buffer()`` is meant to be used on objects
-containing large quantities of raw data, like bytearrays
-or ``array.array`` or numpy
-arrays. It supports both the old *buffer* API (in Python 2.x) and the
-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.
-*In particular, never modify byte strings!*
-
-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.
-
-A common use case is calling a C function with some ``char *`` that
-points to the internal buffer of a Python object; for this case you
-can directly pass ``ffi.from_buffer(python_buffer)`` as argument to
-the call.
-
-*New in version 1.10:* the ``python_buffer`` can be anything supporting
-the buffer/memoryview interface (except unicode strings). Previously,
-bytearray objects were supported in version 1.7 onwards (careful, if you
-resize the bytearray, the ``<cdata>`` object will point to freed
-memory); and byte strings were supported in version 1.8 onwards.
-
-*New in version 1.12:* added the optional *first* argument ``cdecl``, and
-the keyword argument ``require_writable``:
-
-* ``cdecl`` defaults to ``"char[]"``, but a different array
- or (from version 1.13) pointer type can be
- specified for the result. A value like ``"int[]"`` will return an array of
- ints instead of chars, and its length will be set to the number of ints
- that fit in the buffer (rounded down if the division is not exact). Values
- like ``"int[42]"`` or ``"int[2][3]"`` will return an array of exactly 42
- (resp. 2-by-3) ints, raising a ValueError if the buffer is too small. The
- difference between specifying ``"int[]"`` and using the older code ``p1 =
- ffi.from_buffer(x); p2 = ffi.cast("int *", p1)`` is that the older code
- needs to keep ``p1`` alive as long as ``p2`` is in use, because only ``p1``
- keeps the underlying Python object alive and locked. (In addition,
- ``ffi.from_buffer("int[]", x)`` gives better array bound checking.)
-
- *New in version 1.13:* ``cdecl`` can be a pointer type. If it points
- to a struct or union, you can, as usual, write ``p.field`` instead of
- ``p[0].field``. You can also access ``p[n]``; note that CFFI does not
- perform any bounds checking in this case. Note also that ``p[0]`` cannot
- be used to keep the buffer alive (unlike what occurs with ``ffi.new()``).
-
-* if ``require_writable`` is set to True, the function fails if the buffer
- obtained from ``python_buffer`` is read-only (e.g. if ``python_buffer`` is
- a byte string). The exact exception is raised by the object itself, and
- for things like bytes it varies with the Python version, so don't rely on
- it. (Before version 1.12, the same effect can be achieved with a hack:
- call ``ffi.memmove(python_buffer, b"", 0)``. This has no effect if the
- object is writable, but fails if it is read-only.) Please keep in mind
- that CFFI does not implement the C keyword ``const``: even if you set
- ``require_writable`` to False explicitly, you still get a regular
- read-write cdata pointer.
-
-*New in version 1.12:* see also ``ffi.release()``.
-
-
-ffi.memmove()
-+++++++++++++
-
-**ffi.memmove(dest, src, n)**: copy ``n`` bytes from memory area
-``src`` to memory area ``dest``. See examples below. Inspired by the
-C functions ``memcpy()`` and ``memmove()``---like the latter, the
-areas can overlap. Each of ``dest`` and ``src`` can be either a cdata
-pointer or a Python object supporting the buffer/memoryview interface.
-In the case of ``dest``, the buffer/memoryview must be writable.
-*New in version 1.3.* Examples:
-
-* ``ffi.memmove(myptr, b"hello", 5)`` copies the 5 bytes of
- ``b"hello"`` to the area that ``myptr`` points to.
-
-* ``ba = bytearray(100); ffi.memmove(ba, myptr, 100)`` copies 100
- bytes from ``myptr`` into the bytearray ``ba``.
-
-* ``ffi.memmove(myptr + 1, myptr, 100)`` shifts 100 bytes from
- the memory at ``myptr`` to the memory at ``myptr + 1``.
-
-In versions before 1.10, ``ffi.from_buffer()`` had restrictions on the
-type of buffer, which made ``ffi.memmove()`` more general.
-
-.. _ffi-typeof:
-.. _ffi-sizeof:
-.. _ffi-alignof:
-
-ffi.typeof(), ffi.sizeof(), ffi.alignof()
-+++++++++++++++++++++++++++++++++++++++++
-
-**ffi.typeof("C type" or cdata object)**: return an object of type
-``<ctype>`` corresponding to the parsed string, or to the C type of the
-cdata instance. Usually you don't need to call this function or to
-explicitly manipulate ``<ctype>`` objects in your code: any place that
-accepts a C type can receive either a string or a pre-parsed ``ctype``
-object (and because of caching of the string, there is no real
-performance difference). It can still be useful in writing typechecks,
-e.g.:
-
-.. code-block:: python
-
- def myfunction(ptr):
- assert ffi.typeof(ptr) is ffi.typeof("foo_t*")
- ...
-
-Note also that the mapping from strings like ``"foo_t*"`` to the
-``<ctype>`` objects is stored in some internal dictionary. This
-guarantees that there is only one ``<ctype 'foo_t *'>`` object, so you
-can use the ``is`` operator to compare it. The downside is that the
-dictionary entries are immortal for now. In the future, we may add
-transparent reclamation of old, unused entries. In the meantime, note
-that using strings like ``"int[%d]" % length`` to name a type will
-create many immortal cached entries if called with many different
-lengths.
-
-**ffi.sizeof("C type" or cdata object)**: return the size of the
-argument in bytes. The argument can be either a C type, or a cdata object,
-like in the equivalent ``sizeof`` operator in C.
-
-For ``array = ffi.new("T[]", n)``, then ``ffi.sizeof(array)`` returns
-``n * ffi.sizeof("T")``. *New in version 1.9:* Similar rules apply for
-structures with a variable-sized array at the end. More precisely, if
-``p`` was returned by ``ffi.new("struct foo *", ...)``, then
-``ffi.sizeof(p[0])`` now returns the total allocated size. In previous
-versions, it used to just return ``ffi.sizeof(ffi.typeof(p[0]))``, which
-is the size of the structure ignoring the variable-sized part. (Note
-that due to alignment, it is possible for ``ffi.sizeof(p[0])`` to return
-a value smaller than ``ffi.sizeof(ffi.typeof(p[0]))``.)
-
-**ffi.alignof("C type")**: return the natural alignment size in bytes of
-the argument. Corresponds to the ``__alignof__`` operator in GCC.
-
-
-.. _ffi-offsetof:
-.. _ffi-addressof:
-
-ffi.offsetof(), ffi.addressof()
-+++++++++++++++++++++++++++++++
-
-**ffi.offsetof("C struct or array type", \*fields_or_indexes)**: return the
-offset within the struct of the given field. Corresponds to ``offsetof()``
-in C.
-
-You can give several field names in case of nested structures. You
-can also give numeric values which correspond to array items, in case
-of a pointer or array type. For example, ``ffi.offsetof("int[5]", 2)``
-is equal to the size of two integers, as is ``ffi.offsetof("int *", 2)``.
-
-
-**ffi.addressof(cdata, \*fields_or_indexes)**: limited equivalent to
-the '&' operator in C:
-
-1. ``ffi.addressof(<cdata 'struct-or-union'>)`` returns a cdata that
-is a pointer to this struct or union. The returned pointer is only
-valid as long as the original ``cdata`` object is; be sure to keep it
-alive if it was obtained directly from ``ffi.new()``.
-
-2. ``ffi.addressof(<cdata>, field-or-index...)`` returns the address
-of a field or array item inside the given structure or array. In case
-of nested structures or arrays, you can give more than one field or
-index to look recursively. Note that ``ffi.addressof(array, index)``
-can also be expressed as ``array + index``: this is true both in CFFI
-and in C, where ``&array[index]`` is just ``array + index``.
-
-3. ``ffi.addressof(<library>, "name")`` returns the address of the
-named function or global variable from the given library object.
-For functions, it returns a regular cdata
-object containing a pointer to the function.
-
-Note that the case 1. cannot be used to take the address of a
-primitive or pointer, but only a struct or union. It would be
-difficult to implement because only structs and unions are internally
-stored as an indirect pointer to the data. If you need a C int whose
-address can be taken, use ``ffi.new("int[1]")`` in the first place;
-similarly, for a pointer, use ``ffi.new("foo_t *[1]")``.
-
-
-.. _ffi-cdata:
-.. _ffi-ctype:
-
-ffi.CData, ffi.CType
-++++++++++++++++++++
-
-**ffi.CData, ffi.CType**: the Python type of the objects referred to
-as ``<cdata>`` and ``<ctype>`` in the rest of this document. Note
-that some cdata objects may be actually of a subclass of
-``ffi.CData``, and similarly with ctype, so you should check with
-``if isinstance(x, ffi.CData)``. Also, ``<ctype>`` objects have
-a number of attributes for introspection: ``kind`` and ``cname`` are
-always present, and depending on the kind they may also have
-``item``, ``length``, ``fields``, ``args``, ``result``, ``ellipsis``,
-``abi``, ``elements`` and ``relements``.
-
-*New in version 1.10:* ``ffi.buffer`` is now `a type`__ as well.
-
-.. __: #ffi-buffer
-
-
-.. _ffi-gc:
-
-ffi.gc()
-++++++++
-
-**ffi.gc(cdata, destructor, size=0)**:
-return a new cdata object that points to the
-same data. Later, when this new cdata object is garbage-collected,
-``destructor(old_cdata_object)`` will be called. Example of usage:
-``ptr = ffi.gc(lib.custom_malloc(42), lib.custom_free)``.
-Note that like objects
-returned by ``ffi.new()``, the returned pointer objects have *ownership*,
-which means the destructor is called as soon as *this* exact returned
-object is garbage-collected.
-
-*New in version 1.12:* see also ``ffi.release()``.
-
-**ffi.gc(ptr, None, size=0)**:
-removes the ownership on a object returned by a
-regular call to ``ffi.gc``, and no destructor will be called when it
-is garbage-collected. The object is modified in-place, and the
-function returns ``None``. *New in version 1.7: ffi.gc(ptr, None)*
-
-Note that ``ffi.gc()`` should be avoided for limited resources, or (with
-cffi below 1.11) for large memory allocations. This is particularly
-true on PyPy: its GC does not know how much memory or how many resources
-the returned ``ptr`` holds. It will only run its GC when enough memory
-it knows about has been allocated (and thus run the destructor possibly
-later than you would expect). Moreover, the destructor is called in
-whatever thread PyPy is at that moment, which might be a problem for
-some C libraries. In these cases, consider writing a wrapper class with
-custom ``__enter__()`` and ``__exit__()`` methods, allocating and
-freeing the C data at known points in time, and using it in a ``with``
-statement. In cffi 1.12, see also ``ffi.release()``.
-
-*New in version 1.11:* the ``size`` argument. If given, this should be
-an estimate of the size (in bytes) that ``ptr`` keeps alive. This
-information is passed on to the garbage collector, fixing part of the
-problem described above. The ``size`` argument is most important on
-PyPy; on CPython, it is ignored so far, but in the future it could be
-used to trigger more eagerly the cyclic reference GC, too (see CPython
-`issue 31105`__).
-
-The form ``ffi.gc(ptr, None, size=0)`` can be called with a negative
-``size``, to cancel the estimate. It is not mandatory, though:
-nothing gets out of sync if the size estimates do not match. It only
-makes the next GC start more or less early.
-
-Note that if you have several ``ffi.gc()`` objects, the corresponding
-destructors will be called in a random order. If you need a particular
-order, see the discussion in `issue 340`__.
-
-.. __: http://bugs.python.org/issue31105
-.. __: https://foss.heptapod.net/pypy/cffi/-/issues/340
-
-
-.. _ffi-new-handle:
-.. _ffi-from-handle:
-
-ffi.new_handle(), ffi.from_handle()
-+++++++++++++++++++++++++++++++++++
-
-**ffi.new_handle(python_object)**: return a non-NULL cdata of type
-``void *`` that contains an opaque reference to ``python_object``. You
-can pass it around to C functions or store it into C structures. Later,
-you can use **ffi.from_handle(p)** to retrieve the original
-``python_object`` from a value with the same ``void *`` pointer.
-*Calling ffi.from_handle(p) is invalid and will likely crash if
-the cdata object returned by new_handle() is not kept alive!*
-
-See a `typical usage example`_ below.
-
-(In case you are wondering, this ``void *`` is not the ``PyObject *``
-pointer. This wouldn't make sense on PyPy anyway.)
-
-The ``ffi.new_handle()/from_handle()`` functions *conceptually* work
-like this:
-
-* ``new_handle()`` returns cdata objects that contains references to
- the Python objects; we call them collectively the "handle" cdata
- objects. The ``void *`` value in these handle cdata objects are
- random but unique.
-
-* ``from_handle(p)`` searches all live "handle" cdata objects for the
- one that has the same value ``p`` as its ``void *`` value. It then
- returns the Python object referenced by that handle cdata object.
- If none is found, you get "undefined behavior" (i.e. crashes).
-
-The "handle" cdata object keeps the Python object alive, similar to
-how ``ffi.new()`` returns a cdata object that keeps a piece of memory
-alive. If the handle cdata object *itself* is not alive any more,
-then the association ``void * -> python_object`` is dead and
-``from_handle()`` will crash.
-
-*New in version 1.4:* two calls to ``new_handle(x)`` are guaranteed to
-return cdata objects with different ``void *`` values, even with the
-same ``x``. This is a useful feature that avoids issues with unexpected
-duplicates in the following trick: if you need to keep alive the
-"handle" until explicitly asked to free it, but don't have a natural
-Python-side place to attach it to, then the easiest is to ``add()`` it
-to a global set. It can later be removed from the set by
-``global_set.discard(p)``, with ``p`` any cdata object whose ``void *``
-value compares equal.
-
-.. _`typical usage example`:
-
-Usage example: suppose you have a C library where you must call a
-``lib.process_document()`` function which invokes some callback. The
-``process_document()`` function receives a pointer to a callback and a
-``void *`` argument. The callback is then invoked with the ``void
-*data`` argument that is equal to the provided value. In this typical
-case, you can implement it like this (out-of-line API mode)::
-
- class MyDocument:
- ...
-
- def process(self):
- h = ffi.new_handle(self)
- lib.process_document(lib.my_callback, # the callback
- h, # 'void *data'
- args...)
- # 'h' stays alive until here, which means that the
- # ffi.from_handle() done in my_callback() during
- # the call to process_document() is safe
-
- def callback(self, arg1, arg2):
- ...
-
- # the actual callback is this one-liner global function:
- @ffi.def_extern()
- def my_callback(arg1, arg2, data):
- return ffi.from_handle(data).callback(arg1, arg2)
-
-
-.. _ffi-dlopen:
-.. _ffi-dlclose:
-
-ffi.dlopen(), ffi.dlclose()
-+++++++++++++++++++++++++++
-
-**ffi.dlopen(libpath, [flags])**: opens and returns a "handle" to a
-dynamic library, as a ``<lib>`` object. See `Preparing and
-Distributing modules`_.
-
-**ffi.dlclose(lib)**: explicitly closes a ``<lib>`` object returned
-by ``ffi.dlopen()``.
-
-**ffi.RLTD_...**: constants: flags for ``ffi.dlopen()``.
-
-
-ffi.new_allocator()
-+++++++++++++++++++
-
-**ffi.new_allocator(alloc=None, free=None, should_clear_after_alloc=True)**:
-returns a new allocator. An "allocator" is a callable that behaves like
-``ffi.new()`` but uses the provided low-level ``alloc`` and ``free``
-functions. *New in version 1.2.*
-
-``alloc()`` is invoked with the size as sole argument. If it returns
-NULL, a MemoryError is raised. Later, if ``free`` is not None, it will
-be called with the result of ``alloc()`` as argument. Both can be either
-Python function or directly C functions. If only ``free`` is None, then no
-free function is called. If both ``alloc`` and ``free`` are None, the
-default alloc/free combination is used. (In other words, the call
-``ffi.new(*args)`` is equivalent to ``ffi.new_allocator()(*args)``.)
-
-If ``should_clear_after_alloc`` is set to False, then the memory
-returned by ``alloc()`` is assumed to be already cleared (or you are
-fine with garbage); otherwise CFFI will clear it. Example: for
-performance, if you are using ``ffi.new()`` to allocate large chunks of
-memory where the initial content can be left uninitialized, you can do::
-
- # at module level
- new_nonzero = ffi.new_allocator(should_clear_after_alloc=False)
-
- # then replace `p = ffi.new("char[]", bigsize)` with:
- p = new_nonzero("char[]", bigsize)
-
-**NOTE:** the following is a general warning that applies particularly
-(but not only) to PyPy versions 5.6 or older (PyPy > 5.6 attempts to
-account for the memory returned by ``ffi.new()`` or a custom allocator;
-and CPython uses reference counting). If you do large allocations, then
-there is no hard guarantee about when the memory will be freed. You
-should avoid both ``new()`` and ``new_allocator()()`` if you want to be
-sure that the memory is promptly released, e.g. before you allocate more
-of it.
-
-An alternative is to declare and call the C ``malloc()`` and ``free()``
-functions, or some variant like ``mmap()`` and ``munmap()``. Then you
-control exactly when the memory is allocated and freed. For example,
-add these two lines to your existing ``ffibuilder.cdef()``::
-
- void *malloc(size_t size);
- void free(void *ptr);
-
-and then call these two functions manually::
-
- p = lib.malloc(n * ffi.sizeof("int"))
- try:
- my_array = ffi.cast("int *", p)
- ...
- finally:
- lib.free(p)
-
-In cffi version 1.12 you can indeed use ``ffi.new_allocator()`` but use the
-``with`` statement (see ``ffi.release()``) to force the free function to be
-called at a known point. The above is equivalent to this code::
-
- my_new = ffi.new_allocator(lib.malloc, lib.free) # at global level
- ...
- with my_new("int[]", n) as my_array:
- ...
-
-**Warning:** due to a bug, ``p = ffi.new_allocator(..)("struct-or-union *")``
-might not follow the rule that either ``p`` or ``p[0]`` keeps the memory
-alive, which holds for the normal ``ffi.new("struct-or-union *")`` allocator.
-It may sometimes be the case that if there is only a reference to ``p[0]``,
-the memory is freed. The cause is that the rule doesn't hold for
-``ffi.gc()``, which is sometimes used in the implementation of
-``ffi.new_allocator()()``; this might be fixed in a future release.
-
-
-.. _ffi-release:
-
-ffi.release() and the context manager
-+++++++++++++++++++++++++++++++++++++
-
-**ffi.release(cdata)**: release the resources held by a cdata object from
-``ffi.new()``, ``ffi.gc()``, ``ffi.from_buffer()`` or
-``ffi.new_allocator()()``. The cdata object must not be used afterwards.
-The normal Python destructor of the cdata object releases the same resources,
-but this allows the releasing to occur at a known time, as opposed as at an
-unspecified point in the future.
-*New in version 1.12.*
-
-``ffi.release(cdata)`` is equivalent to ``cdata.__exit__()``, which means that
-you can use the ``with`` statement to ensure that the cdata is released at the
-end of a block (in version 1.12 and above)::
-
- with ffi.from_buffer(...) as p:
- do something with p
-
-The effect is more precisely as follows:
-
-* on an object returned from ``ffi.gc(destructor)``, ``ffi.release()`` will
- cause the ``destructor`` to be called immediately.
-
-* on an object returned from a custom allocator, the custom free function
- is called immediately.
-
-* on CPython, ``ffi.from_buffer(buf)`` locks the buffer, so ``ffi.release()``
- can be used to unlock it at a known time. On PyPy, there is no locking
- (so far); the effect of ``ffi.release()`` is limited to removing the link,
- allowing the original buffer object to be garbage-collected even if the
- cdata object stays alive.
-
-* on CPython this method has no effect (so far) on objects returned by
- ``ffi.new()``, because the memory is allocated inline with the cdata object
- and cannot be freed independently. It might be fixed in future releases of
- cffi.
-
-* on PyPy, ``ffi.release()`` frees the ``ffi.new()`` memory immediately. It is
- useful because otherwise the memory is kept alive until the next GC occurs.
- If you allocate large amounts of memory with ``ffi.new()`` and don't free
- them with ``ffi.release()``, PyPy (>= 5.7) runs its GC more often to
- compensate, so the total memory allocated should be kept within bounds
- anyway; but calling ``ffi.release()`` explicitly should improve performance
- by reducing the frequency of GC runs.
-
-After ``ffi.release(x)``, do not use anything pointed to by ``x`` any longer.
-As an exception to this rule, you can call ``ffi.release(x)`` several times
-for the exact same cdata object ``x``; the calls after the first one are
-ignored.
-
-
-ffi.init_once()
-+++++++++++++++
-
-**ffi.init_once(function, tag)**: run ``function()`` once. The
-``tag`` should be a primitive object, like a string, that identifies
-the function: ``function()`` is only called the first time we see the
-``tag``. The return value of ``function()`` is remembered and
-returned by the current and all future ``init_once()`` with the same
-tag. If ``init_once()`` is called from multiple threads in parallel,
-all calls block until the execution of ``function()`` is done. If
-``function()`` raises an exception, it is propagated and nothing is
-cached (i.e. ``function()`` will be called again, in case we catch the
-exception and try ``init_once()`` again). *New in version 1.4.*
-
-Example::
-
- from _xyz_cffi import ffi, lib
-
- def initlib():
- lib.init_my_library()
-
- def make_new_foo():
- ffi.init_once(initlib, "init")
- return lib.make_foo()
-
-``init_once()`` is optimized to run very quickly if ``function()`` has
-already been called. (On PyPy, the cost is zero---the JIT usually
-removes everything in the machine code it produces.)
-
-*Note:* one motivation__ for ``init_once()`` is the CPython notion of
-"subinterpreters" in the embedded case. If you are using the
-out-of-line API mode, ``function()`` is called only once even in the
-presence of multiple subinterpreters, and its return value is shared
-among all subinterpreters. The goal is to mimic the way traditional
-CPython C extension modules have their init code executed only once in
-total even if there are subinterpreters. In the example above, the C
-function ``init_my_library()`` is called once in total, not once per
-subinterpreter. For this reason, avoid Python-level side-effects in
-``function()`` (as they will only be applied in the first
-subinterpreter to run); instead, return a value, as in the following
-example::
-
- def init_get_max():
- return lib.initialize_once_and_get_some_maximum_number()
-
- def process(i):
- if i > ffi.init_once(init_get_max, "max"):
- raise IndexError("index too large!")
- ...
-
-.. __: https://foss.heptapod.net/pypy/cffi/-/issues/233
-
-
-.. _ffi-getctype:
-.. _ffi-list-types:
-
-ffi.getctype(), ffi.list_types()
-++++++++++++++++++++++++++++++++
-
-**ffi.getctype("C type" or <ctype>, extra="")**: return the string
-representation of the given C type. If non-empty, the "extra" string is
-appended (or inserted at the right place in more complicated cases); it
-can be the name of a variable to declare, or an extra part of the type
-like ``"*"`` or ``"[5]"``. For example
-``ffi.getctype(ffi.typeof(x), "*")`` returns the string representation
-of the C type "pointer to the same type than x"; and
-``ffi.getctype("char[80]", "a") == "char a[80]"``.
-
-**ffi.list_types()**: Returns the user type names known to this FFI
-instance. This returns a tuple containing three lists of names:
-``(typedef_names, names_of_structs, names_of_unions)``. *New in
-version 1.6.*
-
-
-.. _`Preparing and Distributing modules`: cdef.html#loading-libraries
-
-
-Conversions
------------
-
-This section documents all the conversions that are allowed when
-*writing into* a C data structure (or passing arguments to a function
-call), and *reading from* a C data structure (or getting the result of a
-function call). The last column gives the type-specific operations
-allowed.
-
-+---------------+------------------------+------------------+----------------+
-| C type | writing into | reading from |other operations|
-+===============+========================+==================+================+
-| integers | an integer or anything | a Python int or | int(), bool() |
-| and enums | on which int() works | long, depending | `[6]`, |
-| `[5]` | (but not a float!). | on the type | ``<`` |
-| | Must be within range. | (ver. 1.10: or a | |
-| | | bool) | |
-+---------------+------------------------+------------------+----------------+
-| ``char`` | a string of length 1 | a string of | int(), bool(), |
-| | or another <cdata char>| length 1 | ``<`` |
-+---------------+------------------------+------------------+----------------+
-| ``wchar_t``, | a unicode of length 1 | a unicode of | |
-| ``char16_t``, | (or maybe 2 if | length 1 | int(), |
-| ``char32_t`` | surrogates) or | (or maybe 2 if | bool(), ``<`` |
-| `[8]` | another similar <cdata>| surrogates) | |
-+---------------+------------------------+------------------+----------------+
-| ``float``, | a float or anything on | a Python float | float(), int(),|
-| ``double`` | which float() works | | bool(), ``<`` |
-+---------------+------------------------+------------------+----------------+
-|``long double``| another <cdata> with | a <cdata>, to | float(), int(),|
-| | a ``long double``, or | avoid loosing | bool() |
-| | anything on which | precision `[3]` | |
-| | float() works | | |
-+---------------+------------------------+------------------+----------------+
-| ``float`` | a complex number | a Python complex | complex(), |
-| ``_Complex``, | or anything on which | number | bool() |
-| ``double`` | complex() works | | `[7]` |
-| ``_Complex`` | | | |
-+---------------+------------------------+------------------+----------------+
-| pointers | another <cdata> with | a <cdata> |``[]`` `[4]`, |
-| | a compatible type (i.e.| |``+``, ``-``, |
-| | same type | |bool() |
-| | or ``void*``, or as an | | |
-| | array instead) `[1]` | | |
-+---------------+------------------------+ | |
-| ``void *`` | another <cdata> with | | |
-| | any pointer or array | | |
-| | type | | |
-+---------------+------------------------+ +----------------+
-| pointers to | same as pointers | | ``[]``, ``+``, |
-| structure or | | | ``-``, bool(), |
-| union | | | and read/write |
-| | | | struct fields |
-+---------------+------------------------+ +----------------+
-| function | same as pointers | | bool(), |
-| pointers | | | call `[2]` |
-+---------------+------------------------+------------------+----------------+
-| arrays | a list or tuple of | a <cdata> |len(), iter(), |
-| | items | |``[]`` `[4]`, |
-| | | |``+``, ``-`` |
-+---------------+------------------------+ +----------------+
-| ``char[]``, | same as arrays, or a | | len(), iter(), |
-| ``un/signed`` | Python byte string | | ``[]``, ``+``, |
-| ``char[]``, | | | ``-`` |
-| ``_Bool[]`` | | | |
-+---------------+------------------------+ +----------------+
-|``wchar_t[]``, | same as arrays, or a | | len(), iter(), |
-|``char16_t[]``,| Python unicode string | | ``[]``, |
-|``char32_t[]`` | | | ``+``, ``-`` |
-| | | | |
-+---------------+------------------------+------------------+----------------+
-| structure | a list or tuple or | a <cdata> | read/write |
-| | dict of the field | | fields |
-| | values, or a same-type | | |
-| | <cdata> | | |
-+---------------+------------------------+ +----------------+
-| union | same as struct, but | | read/write |
-| | with at most one field | | fields |
-+---------------+------------------------+------------------+----------------+
-
-`[1]` ``item *`` is ``item[]`` in function arguments:
-
- In a function declaration, as per the C standard, a ``item *``
- argument is identical to a ``item[]`` argument (and ``ffi.cdef()``
- doesn't record the difference). So when you call such a function,
- you can pass an argument that is accepted by either C type, like
- for example passing a Python string to a ``char *`` argument
- (because it works for ``char[]`` arguments) or a list of integers
- to a ``int *`` argument (it works for ``int[]`` arguments). Note
- that even if you want to pass a single ``item``, you need to
- specify it in a list of length 1; for example, a ``struct point_s
- *`` argument might be passed as ``[[x, y]]`` or ``[{'x': 5, 'y':
- 10}]``.
-
- As an optimization, CFFI assumes that a
- function with a ``char *`` argument to which you pass a Python
- string will not actually modify the array of characters passed in,
- and so passes directly a pointer inside the Python string object.
- (On PyPy, this optimization is only available since PyPy 5.4
- with CFFI 1.8.)
-
-`[2]` C function calls are done with the GIL released.
-
- Note that we assume that the called functions are *not* using the
- Python API from Python.h. For example, we don't check afterwards
- if they set a Python exception. You may work around it, but mixing
- CFFI with ``Python.h`` is not recommended. (If you do that, on
- PyPy and on some platforms like Windows, you may need to explicitly
- link to ``libpypy-c.dll`` to access the CPython C API compatibility
- layer; indeed, CFFI-generated modules on PyPy don't link to
- ``libpypy-c.dll`` on their own. But really, don't do that in the
- first place.)
-
-`[3]` ``long double`` support:
-
- We keep ``long double`` values inside a cdata object to avoid
- loosing precision. Normal Python floating-point numbers only
- contain enough precision for a ``double``. If you really want to
- convert such an object to a regular Python float (i.e. a C
- ``double``), call ``float()``. If you need to do arithmetic on
- such numbers without any precision loss, you need instead to define
- and use a family of C functions like ``long double add(long double
- a, long double b);``.
-
-`[4]` Slicing with ``x[start:stop]``:
-
- Slicing is allowed, as long as you specify explicitly both ``start``
- and ``stop`` (and don't give any ``step``). It gives a cdata
- object that is a "view" of all items from ``start`` to ``stop``.
- It is a cdata of type "array" (so e.g. passing it as an argument to a
- C function would just convert it to a pointer to the ``start`` item).
- As with indexing, negative bounds mean really negative indices, like in
- C. As for slice assignment, it accepts any iterable, including a list
- of items or another array-like cdata object, but the length must match.
- (Note that this behavior differs from initialization: e.g. you can
- say ``chararray[10:15] = "hello"``, but the assigned string must be of
- exactly the correct length; no implicit null character is added.)
-
-`[5]` Enums are handled like ints:
-
- Like C, enum types are mostly int types (unsigned or signed, int or
- long; note that GCC's first choice is unsigned). Reading an enum
- field of a structure, for example, returns you an integer. To
- compare their value symbolically, use code like ``if x.field ==
- lib.FOO``. If you really want to get their value as a string, use
- ``ffi.string(ffi.cast("the_enum_type", x.field))``.
-
-`[6]` bool() on a primitive cdata:
-
- *New in version 1.7.* In previous versions, it only worked on
- pointers; for primitives it always returned True.
-
- *New in version 1.10:* The C type ``_Bool`` or ``bool`` converts to
- Python booleans now. You get an exception if a C ``_Bool`` happens
- to contain a value different from 0 and 1 (this case triggers
- undefined behavior in C; if you really have to interface with a
- library relying on this, don't use ``_Bool`` in the CFFI side).
- Also, when converting from a byte string to a ``_Bool[]``, only the
- bytes ``\x00`` and ``\x01`` are accepted.
-
-`[7]` libffi does not support complex numbers:
-
- *New in version 1.11:* CFFI now supports complex numbers directly.
- Note however that libffi does not. This means that C functions that
- take directly as argument types or return type a complex type cannot
- be called by CFFI, unless they are directly using the API mode.
-
-`[8]` ``wchar_t``, ``char16_t`` and ``char32_t``
-
- See `Unicode character types`_ below.
-
-
-.. _file:
-
-Support for FILE
-++++++++++++++++
-
-You can declare C functions taking a ``FILE *`` argument and
-call them with a Python file object. If needed, you can also do ``c_f
-= ffi.cast("FILE *", fileobj)`` and then pass around ``c_f``.
-
-Note, however, that CFFI does this by a best-effort approach. If you
-need finer control over buffering, flushing, and timely closing of the
-``FILE *``, then you should not use this special support for ``FILE *``.
-Instead, you can handle regular ``FILE *`` cdata objects that you
-explicitly make using fdopen(), like this:
-
-.. code-block:: python
-
- ffi.cdef('''
- FILE *fdopen(int, const char *); // from the C <stdio.h>
- int fclose(FILE *);
- ''')
-
- myfile.flush() # make sure the file is flushed
- newfd = os.dup(myfile.fileno()) # make a copy of the file descriptor
- fp = lib.fdopen(newfd, "w") # make a cdata 'FILE *' around newfd
- lib.write_stuff_to_file(fp) # invoke the external function
- lib.fclose(fp) # when you're done, close fp (and newfd)
-
-The special support for ``FILE *`` is anyway implemented in a similar manner
-on CPython 3.x and on PyPy, because these Python implementations' files are
-not natively based on ``FILE *``. Doing it explicity offers more control.
-
-
-.. _unichar:
-
-Unicode character types
-+++++++++++++++++++++++
-
-The ``wchar_t`` type has the same signedness as the underlying
-platform's. For example, on Linux, it is a signed 32-bit integer.
-However, the types ``char16_t`` and ``char32_t`` (*new in version 1.11*)
-are always unsigned.
-
-Note that CFFI assumes that these types are meant to contain UTF-16 or
-UTF-32 characters in the native endianness. More precisely:
-
-* ``char32_t`` is assumed to contain UTF-32, or UCS4, which is just the
- unicode codepoint;
-
-* ``char16_t`` is assumed to contain UTF-16, i.e. UCS2 plus surrogates;
-
-* ``wchar_t`` is assumed to contain either UTF-32 or UTF-16 based on its
- actual platform-defined size of 4 or 2 bytes.
-
-Whether this assumption is true or not is unspecified by the C language.
-In theory, the C library you are interfacing with could use one of these
-types with a different meaning. You would then need to handle it
-yourself---for example, by using ``uint32_t`` instead of ``char32_t`` in
-the ``cdef()``, and building the expected arrays of ``uint32_t``
-manually.
-
-Python itself can be compiled with ``sys.maxunicode == 65535`` or
-``sys.maxunicode == 1114111`` (Python >= 3.3 is always 1114111). This
-changes the handling of surrogates (which are pairs of 16-bit
-"characters" which actually stand for a single codepoint whose value is
-greater than 65535). If your Python is ``sys.maxunicode == 1114111``,
-then it can store arbitrary unicode codepoints; surrogates are
-automatically inserted when converting from Python unicodes to UTF-16,
-and automatically removed when converting back. On the other hand, if
-your Python is ``sys.maxunicode == 65535``, then it is the other way
-around: surrogates are removed when converting from Python unicodes
-to UTF-32, and added when converting back. In other words, surrogate
-conversion is done only when there is a size mismatch.
-
-Note that Python's internal representations is not specified. For
-example, on CPython >= 3.3, it will use 1- or 2- or 4-bytes arrays
-depending on what the string actually contains. With CFFI, when you
-pass a Python byte string to a C function expecting a ``char*``, then
-we pass directly a pointer to the existing data without needing a
-temporary buffer; however, the same cannot cleanly be done with
-*unicode* string arguments and the ``wchar_t*`` / ``char16_t*`` /
-``char32_t*`` types, because of the changing internal
-representation. As a result, and for consistency, CFFI always allocates
-a temporary buffer for unicode strings.
-
-**Warning:** for now, if you use ``char16_t`` and ``char32_t`` with
-``set_source()``, you have to make sure yourself that the types are
-declared by the C source you provide to ``set_source()``. They would be
-declared if you ``#include`` a library that explicitly uses them, for
-example, or when using C++11. Otherwise, you need ``#include
-<uchar.h>`` on Linux, or more generally something like ``typedef
-uint16_t char16_t;``. This is not done automatically by CFFI because
-``uchar.h`` is not standard across platforms, and writing a ``typedef``
-like above would crash if the type happens to be already defined.
diff --git a/doc/source/using.rst b/doc/source/using.rst
deleted file mode 100644
index 38c96ba..0000000
--- a/doc/source/using.rst
+++ /dev/null
@@ -1,1043 +0,0 @@
-================================
-Using the ffi/lib objects
-================================
-
-.. contents::
-
-Keep this page under your pillow.
-
-
-.. _working:
-
-Working with pointers, structures and arrays
---------------------------------------------
-
-The C code's integers and floating-point values are mapped to Python's
-regular ``int``, ``long`` and ``float``. Moreover, the C type ``char``
-corresponds to single-character strings in Python. (If you want it to
-map to small integers, use either ``signed char`` or ``unsigned char``.)
-
-Similarly, the C type ``wchar_t`` corresponds to single-character
-unicode strings. Note that in some situations (a narrow Python build
-with an underlying 4-bytes wchar_t type), a single wchar_t character
-may correspond to a pair of surrogates, which is represented as a
-unicode string of length 2. If you need to convert such a 2-chars
-unicode string to an integer, ``ord(x)`` does not work; use instead
-``int(ffi.cast('wchar_t', x))``.
-
-*New in version 1.11:* in addition to ``wchar_t``, the C types
-``char16_t`` and ``char32_t`` work the same but with a known fixed size.
-In previous versions, this could be achieved using ``uint16_t`` and
-``int32_t`` but without automatic conversion to Python unicodes.
-
-Pointers, structures and arrays are more complex: they don't have an
-obvious Python equivalent. Thus, they correspond to objects of type
-``cdata``, which are printed for example as
-``<cdata 'struct foo_s *' 0xa3290d8>``.
-
-``ffi.new(ctype, [initializer])``: this function builds and returns a
-new cdata object of the given ``ctype``. The ctype is usually some
-constant string describing the C type. It must be a pointer or array
-type. If it is a pointer, e.g. ``"int *"`` or ``struct foo *``, then
-it allocates the memory for one ``int`` or ``struct foo``. If it is
-an array, e.g. ``int[10]``, then it allocates the memory for ten
-``int``. In both cases the returned cdata is of type ``ctype``.
-
-The memory is initially filled with zeros. An initializer can be given
-too, as described later.
-
-Example::
-
- >>> ffi.new("int *")
- <cdata 'int *' owning 4 bytes>
- >>> ffi.new("int[10]")
- <cdata 'int[10]' owning 40 bytes>
-
- >>> ffi.new("char *") # allocates only one char---not a C string!
- <cdata 'char *' owning 1 bytes>
- >>> ffi.new("char[]", "foobar") # this allocates a C string, ending in \0
- <cdata 'char[]' owning 7 bytes>
-
-Unlike C, the returned pointer object has *ownership* on the allocated
-memory: when this exact object is garbage-collected, then the memory is
-freed. If, at the level of C, you store a pointer to the memory
-somewhere else, then make sure you also keep the object alive for as
-long as needed. (This also applies if you immediately cast the returned
-pointer to a pointer of a different type: only the original object has
-ownership, so you must keep it alive. As soon as you forget it, then
-the casted pointer will point to garbage! In other words, the ownership
-rules are attached to the *wrapper* cdata objects: they are not, and
-cannot, be attached to the underlying raw memory.) Example:
-
-.. code-block:: python
-
- global_weakkeydict = weakref.WeakKeyDictionary()
-
- def make_foo():
- s1 = ffi.new("struct foo *")
- fld1 = ffi.new("struct bar *")
- fld2 = ffi.new("struct bar *")
- s1.thefield1 = fld1
- s1.thefield2 = fld2
- # here the 'fld1' and 'fld2' object must not go away,
- # otherwise 's1.thefield1/2' will point to garbage!
- global_weakkeydict[s1] = (fld1, fld2)
- # now 's1' keeps alive 'fld1' and 'fld2'. When 's1' goes
- # away, then the weak dictionary entry will be removed.
- return s1
-
-Usually you don't need a weak dict: for example, to call a function with
-a ``char * *`` argument that contains a pointer to a ``char *`` pointer,
-it is enough to do this:
-
-.. code-block:: python
-
- p = ffi.new("char[]", "hello, world") # p is a 'char *'
- q = ffi.new("char **", p) # q is a 'char **'
- lib.myfunction(q)
- # p is alive at least until here, so that's fine
-
-However, this is always wrong (usage of freed memory):
-
-.. code-block:: python
-
- p = ffi.new("char **", ffi.new("char[]", "hello, world"))
- # WRONG! as soon as p is built, the inner ffi.new() gets freed!
-
-This is wrong too, for the same reason:
-
-.. code-block:: python
-
- p = ffi.new("struct my_stuff")
- p.foo = ffi.new("char[]", "hello, world")
- # WRONG! as soon as p.foo is set, the ffi.new() gets freed!
-
-
-The cdata objects support mostly the same operations as in C: you can
-read or write from pointers, arrays and structures. Dereferencing a
-pointer is done usually in C with the syntax ``*p``, which is not valid
-Python, so instead you have to use the alternative syntax ``p[0]``
-(which is also valid C). Additionally, the ``p.x`` and ``p->x``
-syntaxes in C both become ``p.x`` in Python.
-
-We have ``ffi.NULL`` to use in the same places as the C ``NULL``.
-Like the latter, it is actually defined to be ``ffi.cast("void *",
-0)``. For example, reading a NULL pointer returns a ``<cdata 'type *'
-NULL>``, which you can check for e.g. by comparing it with
-``ffi.NULL``.
-
-There is no general equivalent to the ``&`` operator in C (because it
-would not fit nicely in the model, and it does not seem to be needed
-here). There is `ffi.addressof()`__, but only for some cases. You
-cannot take the "address" of a number in Python, for example; similarly,
-you cannot take the address of a CFFI pointer. If you have this kind
-of C code::
-
- int x, y;
- fetch_size(&x, &y);
-
- opaque_t *handle; // some opaque pointer
- init_stuff(&handle); // initializes the variable 'handle'
- more_stuff(handle); // pass the handle around to more functions
-
-then you need to rewrite it like this, replacing the variables in C
-with what is logically pointers to the variables:
-
-.. code-block:: python
-
- px = ffi.new("int *")
- py = ffi.new("int *") arr = ffi.new("int[2]")
- lib.fetch_size(px, py) -OR- lib.fetch_size(arr, arr + 1)
- x = px[0] x = arr[0]
- y = py[0] y = arr[1]
-
- p_handle = ffi.new("opaque_t **")
- lib.init_stuff(p_handle) # pass the pointer to the 'handle' pointer
- handle = p_handle[0] # now we can read 'handle' out of 'p_handle'
- lib.more_stuff(handle)
-
-.. __: ref.html#ffi-addressof
-
-
-Any operation that would in C return a pointer or array or struct type
-gives you a fresh cdata object. Unlike the "original" one, these fresh
-cdata objects don't have ownership: they are merely references to
-existing memory.
-
-As an exception to the above rule, dereferencing a pointer that owns a
-*struct* or *union* object returns a cdata struct or union object
-that "co-owns" the same memory. Thus in this case there are two
-objects that can keep the same memory alive. This is done for cases where
-you really want to have a struct object but don't have any convenient
-place to keep alive the original pointer object (returned by
-``ffi.new()``).
-
-Example:
-
-.. code-block:: python
-
- # void somefunction(int *);
-
- x = ffi.new("int *") # allocate one int, and return a pointer to it
- x[0] = 42 # fill it
- lib.somefunction(x) # call the C function
- print x[0] # read the possibly-changed value
-
-The equivalent of C casts are provided with ``ffi.cast("type", value)``.
-They should work in the same cases as they do in C. Additionally, this
-is the only way to get cdata objects of integer or floating-point type::
-
- >>> x = ffi.cast("int", 42)
- >>> x
- <cdata 'int' 42>
- >>> int(x)
- 42
-
-To cast a pointer to an int, cast it to ``intptr_t`` or ``uintptr_t``,
-which are defined by C to be large enough integer types (example on 32
-bits)::
-
- >>> int(ffi.cast("intptr_t", pointer_cdata)) # signed
- -1340782304
- >>> int(ffi.cast("uintptr_t", pointer_cdata)) # unsigned
- 2954184992L
-
-The initializer given as the optional second argument to ``ffi.new()``
-can be mostly anything that you would use as an initializer for C code,
-with lists or tuples instead of using the C syntax ``{ .., .., .. }``.
-Example::
-
- typedef struct { int x, y; } foo_t;
-
- foo_t v = { 1, 2 }; // C syntax
- v = ffi.new("foo_t *", [1, 2]) # CFFI equivalent
-
- foo_t v = { .y=1, .x=2 }; // C99 syntax
- v = ffi.new("foo_t *", {'y': 1, 'x': 2}) # CFFI equivalent
-
-Like C, arrays of chars can also be initialized from a string, in
-which case a terminating null character is appended implicitly::
-
- >>> x = ffi.new("char[]", "hello")
- >>> x
- <cdata 'char[]' owning 6 bytes>
- >>> len(x) # the actual size of the array
- 6
- >>> x[5] # the last item in the array
- '\x00'
- >>> x[0] = 'H' # change the first item
- >>> ffi.string(x) # interpret 'x' as a regular null-terminated string
- 'Hello'
-
-Similarly, arrays of wchar_t or char16_t or char32_t can be initialized
-from a unicode string,
-and calling ``ffi.string()`` on the cdata object returns the current unicode
-string stored in the source array (adding surrogates if necessary).
-See the `Unicode character types`__ section for more details.
-
-.. __: ref.html#unichar
-
-Note that unlike Python lists or tuples, but like C, you *cannot* index in
-a C array from the end using negative numbers.
-
-More generally, the C array types can have their length unspecified in C
-types, as long as their length can be derived from the initializer, like
-in C::
-
- int array[] = { 1, 2, 3, 4 }; // C syntax
- array = ffi.new("int[]", [1, 2, 3, 4]) # CFFI equivalent
-
-As an extension, the initializer can also be just a number, giving
-the length (in case you just want zero-initialization)::
-
- int array[1000]; // C syntax
- array = ffi.new("int[1000]") # CFFI 1st equivalent
- array = ffi.new("int[]", 1000) # CFFI 2nd equivalent
-
-This is useful if the length is not actually a constant, to avoid things
-like ``ffi.new("int[%d]" % x)``. Indeed, this is not recommended:
-``ffi`` normally caches the string ``"int[]"`` to not need to re-parse
-it all the time.
-
-The C99 variable-sized structures are supported too, as long as the
-initializer says how long the array should be:
-
-.. code-block:: python
-
- # typedef struct { int x; int y[]; } foo_t;
-
- p = ffi.new("foo_t *", [5, [6, 7, 8]]) # length 3
- p = ffi.new("foo_t *", [5, 3]) # length 3 with 0 in the array
- p = ffi.new("foo_t *", {'y': 3}) # length 3 with 0 everywhere
-
-Finally, note that any Python object used as initializer can also be
-used directly without ``ffi.new()`` in assignments to array items or
-struct fields. In fact, ``p = ffi.new("T*", initializer)`` is
-equivalent to ``p = ffi.new("T*"); p[0] = initializer``. Examples:
-
-.. code-block:: python
-
- # if 'p' is a <cdata 'int[5][5]'>
- p[2] = [10, 20] # writes to p[2][0] and p[2][1]
-
- # if 'p' is a <cdata 'foo_t *'>, and foo_t has fields x, y and z
- p[0] = {'x': 10, 'z': 20} # writes to p.x and p.z; p.y unmodified
-
- # if, on the other hand, foo_t has a field 'char a[5]':
- p.a = "abc" # writes 'a', 'b', 'c' and '\0'; p.a[4] unmodified
-
-In function calls, when passing arguments, these rules can be used too;
-see `Function calls`_.
-
-
-Python 3 support
-----------------
-
-Python 3 is supported, but the main point to note is that the ``char`` C
-type corresponds to the ``bytes`` Python type, and not ``str``. It is
-your responsibility to encode/decode all Python strings to bytes when
-passing them to or receiving them from CFFI.
-
-This only concerns the ``char`` type and derivative types; other parts
-of the API that accept strings in Python 2 continue to accept strings in
-Python 3.
-
-
-An example of calling a main-like thing
----------------------------------------
-
-Imagine we have something like this:
-
-.. code-block:: python
-
- from cffi import FFI
- ffi = FFI()
- ffi.cdef("""
- int main_like(int argv, char *argv[]);
- """)
- lib = ffi.dlopen("some_library.so")
-
-Now, everything is simple, except, how do we create the ``char**`` argument
-here?
-The first idea:
-
-.. code-block:: python
-
- lib.main_like(2, ["arg0", "arg1"])
-
-does not work, because the initializer receives two Python ``str`` objects
-where it was expecting ``<cdata 'char *'>`` objects. You need to use
-``ffi.new()`` explicitly to make these objects:
-
-.. code-block:: python
-
- lib.main_like(2, [ffi.new("char[]", "arg0"),
- ffi.new("char[]", "arg1")])
-
-Note that the two ``<cdata 'char[]'>`` objects are kept alive for the
-duration of the call: they are only freed when the list itself is freed,
-and the list is only freed when the call returns.
-
-If you want instead to build an "argv" variable that you want to reuse,
-then more care is needed:
-
-.. code-block:: python
-
- # DOES NOT WORK!
- argv = ffi.new("char *[]", [ffi.new("char[]", "arg0"),
- ffi.new("char[]", "arg1")])
-
-In the above example, the inner "arg0" string is deallocated as soon
-as "argv" is built. You have to make sure that you keep a reference
-to the inner "char[]" objects, either directly or by keeping the list
-alive like this:
-
-.. code-block:: python
-
- argv_keepalive = [ffi.new("char[]", "arg0"),
- ffi.new("char[]", "arg1")]
- argv = ffi.new("char *[]", argv_keepalive)
-
-
-Function calls
---------------
-
-When calling C functions, passing arguments follows mostly the same
-rules as assigning to structure fields, and the return value follows the
-same rules as reading a structure field. For example:
-
-.. code-block:: python
-
- # int foo(short a, int b);
-
- n = lib.foo(2, 3) # returns a normal integer
- lib.foo(40000, 3) # raises OverflowError
-
-You can pass to ``char *`` arguments a normal Python string (but don't
-pass a normal Python string to functions that take a ``char *``
-argument and may mutate it!):
-
-.. code-block:: python
-
- # size_t strlen(const char *);
-
- assert lib.strlen("hello") == 5
-
-You can also pass unicode strings as ``wchar_t *`` or ``char16_t *`` or
-``char32_t *`` arguments. Note that
-the C language makes no difference between argument declarations that
-use ``type *`` or ``type[]``. For example, ``int *`` is fully
-equivalent to ``int[]`` (or even ``int[5]``; the 5 is ignored). For CFFI,
-this means that you can always pass arguments that can be converted to
-either ``int *`` or ``int[]``. For example:
-
-.. code-block:: python
-
- # void do_something_with_array(int *array);
-
- lib.do_something_with_array([1, 2, 3, 4, 5]) # works for int[]
-
-See `Reference: conversions`__ for a similar way to pass ``struct foo_s
-*`` arguments---but in general, it is clearer in this case to pass
-``ffi.new('struct foo_s *', initializer)``.
-
-__ ref.html#conversions
-
-CFFI supports passing and returning structs and unions to functions and
-callbacks. Example:
-
-.. code-block:: python
-
- # struct foo_s { int a, b; };
- # struct foo_s function_returning_a_struct(void);
-
- myfoo = lib.function_returning_a_struct()
- # `myfoo`: <cdata 'struct foo_s' owning 8 bytes>
-
-For performance, non-variadic API-level functions that you get by
-writing ``lib.some_function`` are not ``<cdata>``
-objects, but an object of a different type (on CPython, ``<built-in
-function>``). This means you cannot pass them directly to some other C
-function expecting a function pointer argument. Only ``ffi.typeof()``
-works on them. To get a cdata containing a regular function pointer,
-use ``ffi.addressof(lib, "name")``.
-
-There are a few (obscure) limitations to the supported argument and
-return types. These limitations come from libffi and apply only to
-calling ``<cdata>`` function pointers; in other words, they don't
-apply to non-variadic ``cdef()``-declared functions if you are using
-the API mode. The limitations are that you cannot pass directly as
-argument or return type:
-
-* a union (but a *pointer* to a union is fine);
-
-* a struct which uses bitfields (but a *pointer* to such a struct is
- fine);
-
-* a struct that was declared with "``...``" in the ``cdef()``.
-
-In API mode, you can work around these limitations: for example, if you
-need to call such a function pointer from Python, you can instead write
-a custom C function that accepts the function pointer and the real
-arguments and that does the call from C. Then declare that custom C
-function in the ``cdef()`` and use it from Python.
-
-
-Variadic function calls
------------------------
-
-Variadic functions in C (which end with "``...``" as their last
-argument) can be declared and called normally, with the exception that
-all the arguments passed in the variable part *must* be cdata objects.
-This is because it would not be possible to guess, if you wrote this::
-
- lib.printf("hello, %d\n", 42) # doesn't work!
-
-that you really meant the 42 to be passed as a C ``int``, and not a
-``long`` or ``long long``. The same issue occurs with ``float`` versus
-``double``. So you have to force cdata objects of the C type you want,
-if necessary with ``ffi.cast()``:
-
-.. code-block:: python
-
- lib.printf("hello, %d\n", ffi.cast("int", 42))
- lib.printf("hello, %ld\n", ffi.cast("long", 42))
- lib.printf("hello, %f\n", ffi.cast("double", 42))
-
-But of course:
-
-.. code-block:: python
-
- lib.printf("hello, %s\n", ffi.new("char[]", "world"))
-
-Note that if you are using ``dlopen()``, the function declaration in the
-``cdef()`` must match the original one in C exactly, as usual --- in
-particular, if this function is variadic in C, then its ``cdef()``
-declaration must also be variadic. You cannot declare it in the
-``cdef()`` with fixed arguments instead, even if you plan to only call
-it with these argument types. The reason is that some architectures
-have a different calling convention depending on whether the function
-signature is fixed or not. (On x86-64, the difference can sometimes be
-seen in PyPy's JIT-generated code if some arguments are ``double``.)
-
-Note that the function signature ``int foo();`` is interpreted by CFFI
-as equivalent to ``int foo(void);``. This differs from the C standard,
-in which ``int foo();`` is really like ``int foo(...);`` and can be
-called with any arguments. (This feature of C is a pre-C89 relic: the
-arguments cannot be accessed at all in the body of ``foo()`` without
-relying on compiler-specific extensions. Nowadays virtually all code
-with ``int foo();`` really means ``int foo(void);``.)
-
-
-Memory pressure (PyPy)
-----------------------
-
-This paragraph applies only to PyPy, because its garbage collector (GC)
-is different from CPython's. It is very common in C code to have pairs
-of functions, one which performs memory allocations or acquires other
-resources, and the other which frees them again. Depending on how you
-structure your Python code, the freeing function is only called when the
-GC decides a particular (Python) object can be freed. This occurs
-notably in these cases:
-
-* If you use a ``__del__()`` method to call the freeing function.
-
-* If you use ``ffi.gc()`` without also using ``ffi.release()``.
-
-* This does not occur if you call the freeing function at a
- deterministic time, like in a regular ``try: finally:`` block. It
- does however occur *inside a generator---* if the generator is not
- explicitly exhausted but forgotten at a ``yield`` point, then the code
- in the enclosing ``finally`` block is only invoked at the next GC.
-
-In these cases, you may have to use the built-in function
-``__pypy__.add_memory_pressure(n)``. Its argument ``n`` is an estimate
-of how much memory pressure to add. For example, if the pair of C
-functions that we are talking about is ``malloc(n)`` and ``free()`` or
-similar, you would call ``__pypy__.add_memory_pressure(n)`` after
-``malloc(n)``. Doing so is not always a complete answer to the problem,
-but it makes the next GC occur earlier, which is often enough.
-
-The same applies if the memory allocations are indirect, e.g. the C
-function allocates some internal data structures. In that case, call
-``__pypy__.add_memory_pressure(n)`` with an argument ``n`` that is an
-rough estimation. Knowing the exact size is not important, and memory
-pressure doesn't have to be manually brought down again after calling
-the freeing function. If you are writing wrappers for the allocating /
-freeing pair of functions, you should probably call
-``__pypy__.add_memory_pressure()`` in the former even if the user may
-invoke the latter at a known point with a ``finally:`` block.
-
-In case this solution is not sufficient, or if the acquired resource is
-not memory but something else more limited (like file descriptors), then
-there is no better way than restructuring your code to make sure the
-freeing function is called at a known point and not indirectly by the
-GC.
-
-Note that in PyPy <= 5.6 the discussion above also applies to
-``ffi.new()``. In more recent versions of PyPy, both ``ffi.new()`` and
-``ffi.new_allocator()()`` automatically account for the memory pressure
-they create. (In case you need to support both older and newer PyPy's,
-try calling ``__pypy__.add_memory_pressure()`` anyway; it is better to
-overestimate than not account for the memory pressure.)
-
-
-.. _extern-python:
-.. _`extern "Python"`:
-
-Extern "Python" (new-style callbacks)
--------------------------------------
-
-When the C code needs a pointer to a function which invokes back a
-Python function of your choice, here is how you do it in the
-out-of-line API mode. The next section about Callbacks_ describes the
-ABI-mode solution.
-
-This is *new in version 1.4.* Use old-style Callbacks_ if backward
-compatibility is an issue. (The original callbacks are slower to
-invoke and have the same issue as libffi's callbacks; notably, see the
-warning__. The new style described in the present section does not
-use libffi's callbacks at all.)
-
-.. __: Callbacks_
-
-In the builder script, declare in the cdef a function prefixed with
-``extern "Python"``::
-
- ffibuilder.cdef("""
- extern "Python" int my_callback(int, int);
-
- void library_function(int(*callback)(int, int));
- """)
- ffibuilder.set_source("_my_example", r"""
- #include <some_library.h>
- """)
-
-The function ``my_callback()`` is then implemented in Python inside
-your application's code::
-
- from _my_example import ffi, lib
-
- @ffi.def_extern()
- def my_callback(x, y):
- return 42
-
-You obtain a ``<cdata>`` pointer-to-function object by getting
-``lib.my_callback``. This ``<cdata>`` can be passed to C code and
-then works like a callback: when the C code calls this function
-pointer, the Python function ``my_callback`` is called. (You need
-to pass ``lib.my_callback`` to C code, and not ``my_callback``: the
-latter is just the Python function above, which cannot be passed to C.)
-
-CFFI implements this by defining ``my_callback`` as a static C
-function, written after the ``set_source()`` code. The ``<cdata>``
-then points to this function. What this function does is invoke the
-Python function object that is, at runtime, attached with
-``@ffi.def_extern()``.
-
-The ``@ffi.def_extern()`` decorator should be applied to **global
-functions,** one for each ``extern "Python"`` function of the same
-name.
-
-To support some corner cases, it is possible to redefine the attached
-Python function by calling ``@ffi.def_extern()`` again for the same
-name---but this is not recommended! Better attach a single global
-Python function for this name, and write it more flexibly in the first
-place. This is because each ``extern "Python"`` function turns into
-only one C function. Calling ``@ffi.def_extern()`` again changes this
-function's C logic to call the new Python function; the old Python
-function is not callable any more. The C function pointer you get
-from ``lib.my_function`` is always this C function's address, i.e. it
-remains the same.
-
-Extern "Python" and ``void *`` arguments
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-As described just before, you cannot use ``extern "Python"`` to make a
-variable number of C function pointers. However, achieving that
-result is not possible in pure C code either. For this reason, it is
-usual for C to define callbacks with a ``void *data`` argument. You
-can use ``ffi.new_handle()`` and ``ffi.from_handle()`` to pass a
-Python object through this ``void *`` argument. For example, if the C
-type of the callbacks is::
-
- typedef void (*event_cb_t)(event_t *evt, void *userdata);
-
-and you register events by calling this function::
-
- void event_cb_register(event_cb_t cb, void *userdata);
-
-Then you would write this in the build script::
-
- ffibuilder.cdef("""
- typedef ... event_t;
- typedef void (*event_cb_t)(event_t *evt, void *userdata);
- void event_cb_register(event_cb_t cb, void *userdata);
-
- extern "Python" void my_event_callback(event_t *, void *);
- """)
- ffibuilder.set_source("_demo_cffi", r"""
- #include <the_event_library.h>
- """)
-
-and in your main application you register events like this::
-
- from _demo_cffi import ffi, lib
-
- class Widget(object):
- def __init__(self):
- userdata = ffi.new_handle(self)
- self._userdata = userdata # must keep this alive!
- lib.event_cb_register(lib.my_event_callback, userdata)
-
- def process_event(self, evt):
- print "got event!"
-
- @ffi.def_extern()
- def my_event_callback(evt, userdata):
- widget = ffi.from_handle(userdata)
- widget.process_event(evt)
-
-Some other libraries don't have an explicit ``void *`` argument, but
-let you attach the ``void *`` to an existing structure. For example,
-the library might say that ``widget->userdata`` is a generic field
-reserved for the application. If the event's signature is now this::
-
- typedef void (*event_cb_t)(widget_t *w, event_t *evt);
-
-Then you can use the ``void *`` field in the low-level
-``widget_t *`` like this::
-
- from _demo_cffi import ffi, lib
-
- class Widget(object):
- def __init__(self):
- ll_widget = lib.new_widget(500, 500)
- self.ll_widget = ll_widget # <cdata 'struct widget *'>
- userdata = ffi.new_handle(self)
- self._userdata = userdata # must still keep this alive!
- ll_widget.userdata = userdata # this makes a copy of the "void *"
- lib.event_cb_register(ll_widget, lib.my_event_callback)
-
- def process_event(self, evt):
- print "got event!"
-
- @ffi.def_extern()
- def my_event_callback(ll_widget, evt):
- widget = ffi.from_handle(ll_widget.userdata)
- widget.process_event(evt)
-
-Extern "Python" accessed from C directly
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In case you want to access some ``extern "Python"`` function directly
-from the C code written in ``set_source()``, you need to write a
-forward declaration. (By default it needs to be static, but see
-`next paragraph`__.) The real implementation of this function
-is added by CFFI *after* the C code---this is needed because the
-declaration might use types defined by ``set_source()``
-(e.g. ``event_t`` above, from the ``#include``), so it cannot be
-generated before.
-
-.. __: `extern-python-c`_
-
-::
-
- ffibuilder.set_source("_demo_cffi", r"""
- #include <the_event_library.h>
-
- static void my_event_callback(widget_t *, event_t *);
-
- /* here you can write C code which uses '&my_event_callback' */
- """)
-
-This can also be used to write custom C code which calls Python
-directly. Here is an example (inefficient in this case, but might be
-useful if the logic in ``my_algo()`` is much more complex)::
-
- ffibuilder.cdef("""
- extern "Python" int f(int);
- int my_algo(int);
- """)
- ffibuilder.set_source("_example_cffi", r"""
- static int f(int); /* the forward declaration */
-
- static int my_algo(int n) {
- int i, sum = 0;
- for (i = 0; i < n; i++)
- sum += f(i); /* call f() here */
- return sum;
- }
- """)
-
-.. _extern-python-c:
-
-Extern "Python+C"
-~~~~~~~~~~~~~~~~~
-
-Functions declared with ``extern "Python"`` are generated as
-``static`` functions in the C source. However, in some cases it is
-convenient to make them non-static, typically when you want to make
-them directly callable from other C source files. To do that, you can
-say ``extern "Python+C"`` instead of just ``extern "Python"``. *New
-in version 1.6.*
-
-+------------------------------------+--------------------------------------+
-| if the cdef contains | then CFFI generates |
-+------------------------------------+--------------------------------------+
-| ``extern "Python" int f(int);`` | ``static int f(int) { /* code */ }`` |
-+------------------------------------+--------------------------------------+
-| ``extern "Python+C" int f(int);`` | ``int f(int) { /* code */ }`` |
-+------------------------------------+--------------------------------------+
-
-The name ``extern "Python+C"`` comes from the fact that we want an
-extern function in both senses: as an ``extern "Python"``, and as a
-C function that is not static.
-
-You cannot make CFFI generate additional macros or other
-compiler-specific stuff like the GCC ``__attribute__``. You can only
-control whether the function should be ``static`` or not. But often,
-these attributes must be written alongside the function *header*, and
-it is fine if the function *implementation* does not repeat them::
-
- ffibuilder.cdef("""
- extern "Python+C" int f(int); /* not static */
- """)
- ffibuilder.set_source("_example_cffi", r"""
- /* the forward declaration, setting a gcc attribute
- (this line could also be in some .h file, to be included
- both here and in the other C files of the project) */
- int f(int) __attribute__((visibility("hidden")));
- """)
-
-
-Extern "Python": reference
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``extern "Python"`` must appear in the cdef(). Like the C++ ``extern
-"C"`` syntax, it can also be used with braces around a group of
-functions::
-
- extern "Python" {
- int foo(int);
- int bar(int);
- }
-
-The ``extern "Python"`` functions cannot be variadic for now. This
-may be implemented in the future. (`This demo`__ shows how to do it
-anyway, but it is a bit lengthy.)
-
-.. __: https://foss.heptapod.net/pypy/cffi/-/blob/branch/default/demo/extern_python_varargs.py
-
-Each corresponding Python callback function is defined with the
-``@ffi.def_extern()`` decorator. Be careful when writing this
-function: if it raises an exception, or tries to return an object of
-the wrong type, then the exception cannot be propagated. Instead, the
-exception is printed to stderr and the C-level callback is made to
-return a default value. This can be controlled with ``error`` and
-``onerror``, described below.
-
-.. _def-extern:
-
-The ``@ffi.def_extern()`` decorator takes these optional arguments:
-
-* ``name``: the name of the function as written in the cdef. By default
- it is taken from the name of the Python function you decorate.
-
-.. _error_onerror:
-
-* ``error``: the returned value in case the Python function raises an
- exception. It is 0 or null by default. The exception is still
- printed to stderr, so this should be used only as a last-resort
- solution.
-
-* ``onerror``: if you want to be sure to catch all exceptions, use
- ``@ffi.def_extern(onerror=my_handler)``. If an exception occurs and
- ``onerror`` is specified, then ``onerror(exception, exc_value,
- traceback)`` is called. This is useful in some situations where you
- cannot simply write ``try: except:`` in the main callback function,
- because it might not catch exceptions raised by signal handlers: if
- a signal occurs while in C, the Python signal handler is called as
- soon as possible, which is after entering the callback function but
- *before* executing even the ``try:``. If the signal handler raises,
- we are not in the ``try: except:`` yet.
-
- If ``onerror`` is called and returns normally, then it is assumed
- that it handled the exception on its own and nothing is printed to
- stderr. If ``onerror`` raises, then both tracebacks are printed.
- Finally, ``onerror`` can itself provide the result value of the
- callback in C, but doesn't have to: if it simply returns None---or
- if ``onerror`` itself fails---then the value of ``error`` will be
- used, if any.
-
- Note the following hack: in ``onerror``, you can access the original
- callback arguments as follows. First check if ``traceback`` is not
- None (it is None e.g. if the whole function ran successfully but
- there was an error converting the value returned: this occurs after
- the call). If ``traceback`` is not None, then
- ``traceback.tb_frame`` is the frame of the outermost function,
- i.e. directly the frame of the function decorated with
- ``@ffi.def_extern()``. So you can get the value of ``argname`` in
- that frame by reading ``traceback.tb_frame.f_locals['argname']``.
-
-
-.. _Callbacks:
-
-Callbacks (old style)
----------------------
-
-Here is how to make a new ``<cdata>`` object that contains a pointer
-to a function, where that function invokes back a Python function of
-your choice::
-
- >>> @ffi.callback("int(int, int)")
- >>> def myfunc(x, y):
- ... return x + y
- ...
- >>> myfunc
- <cdata 'int(*)(int, int)' calling <function myfunc at 0xf757bbc4>>
-
-Note that ``"int(*)(int, int)"`` is a C *function pointer* type, whereas
-``"int(int, int)"`` is a C *function* type. Either can be specified to
-ffi.callback() and the result is the same.
-
-.. warning::
-
- Callbacks are provided for the ABI mode or for backward
- compatibility. If you are using the out-of-line API mode, it is
- recommended to use the `extern "Python"`_ mechanism instead of
- callbacks: it gives faster and cleaner code. It also avoids several
- issues with old-style callbacks:
-
- - On less common architecture, libffi is more likely to crash on
- callbacks (`e.g. on NetBSD`__);
-
- - On hardened systems like PAX and SELinux, the extra memory
- protections can interfere (for example, on SELinux you need to
- run with ``deny_execmem`` set to ``off``).
-
- - `On Mac OS X,`__ you need to give your application the entitlement
- ``com.apple.security.cs.allow-unsigned-executable-memory``.
-
- Note also that a cffi fix for this issue was attempted---see
- the ``ffi_closure_alloc`` branch---but was not merged because it
- creates potential `memory corruption`__ with ``fork()``.
-
- In other words: yes, it is dangerous to allow write+execute memory in your
- program; that's why the various "hardening" options above exist. But at
- the same time, these options open wide the door to another attack: if the
- program forks and then attempts to call any of the ``ffi.callback()``, then
- this immediately results in a crash---or, with a minimal amount of work
- from an attacker, arbitrary code execution. To me it sounds even more
- dangerous than the original problem, and that's why cffi is not playing
- along.
-
- To fix the issue once and for all on the affected platforms, you need
- to refactor the involved code so that it no longer uses ``ffi.callback()``.
-
-.. __: https://github.com/pyca/pyopenssl/issues/596
-.. __: https://foss.heptapod.net/pypy/cffi/-/issues/391
-.. __: https://bugzilla.redhat.com/show_bug.cgi?id=1249685
-
-Warning: like ffi.new(), ffi.callback() returns a cdata that has
-ownership of its C data. (In this case, the necessary C data contains
-the libffi data structures to do a callback.) This means that the
-callback can only be invoked as long as this cdata object is alive.
-If you store the function pointer into C code, then make sure you also
-keep this object alive for as long as the callback may be invoked.
-The easiest way to do that is to always use ``@ffi.callback()`` at
-module-level only, and to pass "context" information around with
-`ffi.new_handle()`__, if possible. Example:
-
-.. __: ref.html#new-handle
-
-.. code-block:: python
-
- # a good way to use this decorator is once at global level
- @ffi.callback("int(int, void *)")
- def my_global_callback(x, handle):
- return ffi.from_handle(handle).some_method(x)
-
-
- class Foo(object):
-
- def __init__(self):
- handle = ffi.new_handle(self)
- self._handle = handle # must be kept alive
- lib.register_stuff_with_callback_and_voidp_arg(my_global_callback, handle)
-
- def some_method(self, x):
- print "method called!"
-
-(See also the section about `extern "Python"`_ above, where the same
-general style is used.)
-
-Note that callbacks of a variadic function type are not supported. A
-workaround is to add custom C code. In the following example, a
-callback gets a first argument that counts how many extra ``int``
-arguments are passed:
-
-.. code-block:: python
-
- # file "example_build.py"
-
- import cffi
-
- ffibuilder = cffi.FFI()
- ffibuilder.cdef("""
- int (*python_callback)(int how_many, int *values);
- void *const c_callback; /* pass this const ptr to C routines */
- """)
- ffibuilder.set_source("_example", r"""
- #include <stdarg.h>
- #include <alloca.h>
- static int (*python_callback)(int how_many, int *values);
- static int c_callback(int how_many, ...) {
- va_list ap;
- /* collect the "..." arguments into the values[] array */
- int i, *values = alloca(how_many * sizeof(int));
- va_start(ap, how_many);
- for (i=0; i<how_many; i++)
- values[i] = va_arg(ap, int);
- va_end(ap);
- return python_callback(how_many, values);
- }
- """)
- ffibuilder.compile(verbose=True)
-
-.. code-block:: python
-
- # file "example.py"
-
- from _example import ffi, lib
-
- @ffi.callback("int(int, int *)")
- def python_callback(how_many, values):
- print ffi.unpack(values, how_many)
- return 0
- lib.python_callback = python_callback
-
-Deprecated: you can also use ``ffi.callback()`` not as a decorator but
-directly as ``ffi.callback("int(int, int)", myfunc)``. This is
-discouraged: using this a style, we are more likely to forget the
-callback object too early, when it is still in use.
-
-The ``ffi.callback()`` decorator also accepts the optional argument
-``error``, and from CFFI version 1.2 the optional argument ``onerror``.
-These two work in the same way as `described above for extern "Python".`__
-
-.. __: error_onerror_
-
-
-
-Windows: calling conventions
-----------------------------
-
-On Win32, functions can have two main calling conventions: either
-"cdecl" (the default), or "stdcall" (also known as "WINAPI"). There
-are also other rare calling conventions, but these are not supported.
-*New in version 1.3.*
-
-When you issue calls from Python to C, the implementation is such that
-it works with any of these two main calling conventions; you don't
-have to specify it. However, if you manipulate variables of type
-"function pointer" or declare callbacks, then the calling convention
-must be correct. This is done by writing ``__cdecl`` or ``__stdcall``
-in the type, like in C::
-
- @ffi.callback("int __stdcall(int, int)")
- def AddNumbers(x, y):
- return x + y
-
-or::
-
- ffibuilder.cdef("""
- struct foo_s {
- int (__stdcall *MyFuncPtr)(int, int);
- };
- """)
-
-``__cdecl`` is supported but is always the default so it can be left
-out. In the ``cdef()``, you can also use ``WINAPI`` as equivalent to
-``__stdcall``. As mentioned above, it is mostly not needed (but doesn't
-hurt) to say ``WINAPI`` or ``__stdcall`` when declaring a plain
-function in the ``cdef()``. (The difference can still be seen if you
-take explicitly a pointer to this function with ``ffi.addressof()``,
-or if the function is ``extern "Python"``.)
-
-These calling convention specifiers are accepted but ignored on any
-platform other than 32-bit Windows.
-
-In CFFI versions before 1.3, the calling convention specifiers are not
-recognized. In API mode, you could work around it by using an
-indirection, like in the example in the section about Callbacks_
-(``"example_build.py"``). There was no way to use stdcall callbacks
-in ABI mode.
-
-
-FFI Interface
--------------
-
-(The reference for the FFI interface has been moved to the `next page`__.)
-
-.. __: ref.html
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
deleted file mode 100644
index aa7f2fe..0000000
--- a/doc/source/whatsnew.rst
+++ /dev/null
@@ -1,887 +0,0 @@
-======================
-What's New
-======================
-
-v1.15.0
-=======
-
-* Fixed MANIFEST.in to include missing file for Windows arm64 support
-
-* Fixed Linux wheel build to use gcc default ISA for libffi
-
-* Updated setup.py Python trove specifiers to currently-tested Python versions
-
-* CPython 3.10 support (including wheels)
-
-* MacOS arm64 support (including wheels)
-
-* Initial Windows arm64 support
-
-* Misc. doc and test updates
-
-v1.14.6
-=======
-
-* Test fixes for CPython 3.10.0b3
-
-* Support for `sys.unraisablehook()` on Python >= 3.8
-
-* Fix two minor memory leaks (thanks Sebastian!)
-
-* Like many projects that had an IRC channel on freenode, we moved it to
- ``irc.libera.chat``.
-
-v1.14.5
-=======
-
-* Source fix for old gcc versions
-
-* This and future releases should include wheels on more platforms,
- thanks to our new release managers Matt and Matt!
-
-v1.14.4
-=======
-
-Release done for pip reasons.
-
-v1.14.3
-=======
-
-Release done for pip reasons.
-
-v1.14.2
-=======
-
-* CPython 3 on Windows: we again try to compile with ``Py_LIMITED_API``
- by default. This flag is not added if you run the compilation with
- CPython 3.4, as it only works with CPython >= 3.5, but by now this
- version of Python is quite old (and we no longer distribute cffi
- wheels for it).
-
- This may require that you upgrade ``virtualenv`` (requires version 16
- or newer) or at least copy manually ``python3.dll`` into your existing
- virtualenvs. For distributing wheels with your cffi modules, you may
- also need to upgrade ``wheel`` to the just-released version 0.35.
-
- You can manually disable ``Py_LIMITED_API`` by calling
- ``ffi.set_source(..., py_limited_api=False)``.
-
-
-v1.14.1
-=======
-
-* CFFI source code is now `hosted on Heptapod`_.
-
-* Improved support for ``typedef int my_array_t[...];`` with an explicit
- dot-dot-dot in API mode (`issue #453`_)
-
-* Windows (32 and 64 bits): multiple fixes for ABI-mode call to functions
- that return a structure.
-
-* Experimental support for MacOS 11 on aarch64.
-
-* and a few other minor changes and bug fixes.
-
-.. _`hosted on Heptapod`: https://foss.heptapod.net/pypy/cffi/
-.. _`issue #453`: https://foss.heptapod.net/pypy/cffi/issues/453
-
-
-v1.14
-=====
-
-* ``ffi.dlopen()`` can now be called with a handle (as a ``void *``) to an
- already-opened C library.
-
-* CPython only: fixed a stack overflow issue for calls like
- ``lib.myfunc([large list])``. If the function is declared as taking a
- ``float *`` argument, for example, then the array is temporarily converted
- into a C array of floats---however, the code used to use ``alloca()`` for
- this temporary storage, no matter how large. This is now fixed.
-
- The fix concerns all modes: in-line/out-of-line API/ABI. Also note that your
- API-mode C extension modules need to be regenerated with cffi 1.14 in order
- to get the fix; i.e. for API mode, the fix is in the generated C sources.
- (The C sources generated from cffi 1.14 should also work when running in
- a different environment in which we have an older version of cffi. Also,
- this change makes no difference on PyPy.)
-
- As a workaround that works on all versions of cffi, you can write
- ``lib.myfunc(ffi.new("float[]", [large list]))``, which is
- equivalent but explicity builds the intermediate array as a regular
- Python object on the heap.
-
-* fixed a memory leak inside ``ffi.getwinerror()`` on CPython 3.x.
-
-
-v1.13.2
-=======
-
-* re-release because the Linux wheels came with an attached version of libffi
- that was very old and buggy (`issue #432`_).
-
-.. _`issue #432`: https://foss.heptapod.net/pypy/cffi/-/issues/432
-
-
-
-v1.13.1
-=======
-
-* deprecate the way to declare in ``cdef()`` a global variable with only
- ``void *foo;``. You should always use a storage class, like ``extern void
- *foo;`` or maybe ``static void *foo;``. These are all equivalent for
- the purposes of ``cdef()``, but the reason for deprecating the bare version
- is that (as far as I know) it would always be mistake in a real C header.
-
-* fix the regression ``RuntimeError: found a situation in which we try
- to build a type recursively`` (`issue #429`_).
-
-* fixed `issue #427`_ where a multithreading mistake in the embedding logic
- initialization code would cause deadlocks on CPython 3.7.
-
-.. _`issue #429`: https://foss.heptapod.net/pypy/cffi/-/issues/429
-.. _`issue #427`: https://foss.heptapod.net/pypy/cffi/-/issues/427
-
-
-v1.13
-=====
-
-* ``ffi.from_buffer("type *", ..)`` is now supported, in addition to
- ``"type[]"``. You can then write ``p.field`` to access the items, instead
- of only ``p[0].field``. Be careful that no bounds checking is performed, so
- ``p[n]`` might access data out of bounds.
-
-* fix for structs containing unnamed bitfields like ``int : 1;``.
-
-* when calling cdata of "function pointer" type, give a RuntimeError instead
- of a crash if the pointer happens to be NULL
-
-* support some more binary operations between constants in enum definitions
- (PR #96)
-
-* silence a warning incorrectly emitted if you use a quote in a preprocessor
- line
-
-* detect a corner case that would throw the C code into an infinite
- recursion, with ``ffi.cdef("""struct X { void(*fnptr)(struct X); };""")``
-
-
-Older Versions
-==============
-
-v1.12.3
--------
-
-* Fix for nested struct types that end in a var-sized array (#405).
-
-* Add support for using ``U`` and ``L`` characters at the end of integer
- constants in ``ffi.cdef()`` (thanks Guillaume).
-
-* More 3.8 fixes.
-
-
-v1.12.2
--------
-
-* Added temporary workaround to compile on CPython 3.8.0a2.
-
-
-v1.12.1
--------
-
-* CPython 3 on Windows: we again no longer compile with ``Py_LIMITED_API``
- by default because such modules *still* cannot be used with virtualenv.
- The problem is that it doesn't work in CPython <= 3.4, and for
- technical reason we can't enable this flag automatically based on the
- version of Python.
-
- Like before, `Issue #350`_ mentions a workaround if you still want
- the ``Py_LIMITED_API`` flag and *either* you are not concerned about
- virtualenv *or* you are sure your module will not be used on CPython
- <= 3.4: pass ``define_macros=[("Py_LIMITED_API", None)]`` as a keyword to the
- ``ffibuilder.set_source()`` call.
-
-
-v1.12
------
-
-* `Direct support for pkg-config`__.
-
-* ``ffi.from_buffer()`` takes a new optional *first* argument that gives
- the array type of the result. It also takes an optional keyword argument
- ``require_writable`` to refuse read-only Python buffers.
-
-* ``ffi.new()``, ``ffi.gc()`` or ``ffi.from_buffer()`` cdata objects
- can now be released at known times, either by using the ``with``
- keyword or by calling the new ``ffi.release()``.
-
-* Windows, CPython 3.x: cffi modules are linked with ``python3.dll``
- again. This makes them independant on the exact CPython version,
- like they are on other platforms. **It requires virtualenv 16.0.0.**
-
-* Accept an expression like ``ffi.new("int[4]", p)`` if ``p`` is itself
- another cdata ``int[4]``.
-
-* CPython 2.x: ``ffi.dlopen()`` failed with non-ascii file names on Posix
-
-* CPython: if a thread is started from C and then runs Python code (with
- callbacks or with the embedding solution), then previous versions of
- cffi would contain possible crashes and/or memory leaks. Hopefully,
- this has been fixed (see `issue #362`_).
-
-* Support for ``ffi.cdef(..., pack=N)`` where N is a power of two.
- Means to emulate ``#pragma pack(N)`` on MSVC. Also, the default on
- Windows is now ``pack=8``, like on MSVC. This might make a difference
- in corner cases, although I can't think of one in the context of CFFI.
- The old way ``ffi.cdef(..., packed=True)`` remains and is equivalent
- to ``pack=1`` (saying e.g. that fields like ``int`` should be aligned
- to 1 byte instead of 4).
-
-.. __: cdef.html#pkgconfig
-.. _`issue #362`: https://foss.heptapod.net/pypy/cffi/-/issues/362
-
-
-v1.11.5
--------
-
-* `Issue #357`_: fix ``ffi.emit_python_code()`` which generated a buggy
- Python file if you are using a ``struct`` with an anonymous ``union``
- field or vice-versa.
-
-* Windows: ``ffi.dlopen()`` should now handle unicode filenames.
-
-* ABI mode: implemented ``ffi.dlclose()`` for the in-line case (it used
- to be present only in the out-of-line case).
-
-* Fixed a corner case for ``setup.py install --record=xx --root=yy``
- with an out-of-line ABI module. Also fixed `Issue #345`_.
-
-* More hacks on Windows for running CFFI's own ``setup.py``.
-
-* `Issue #358`_: in embedding, to protect against (the rare case of)
- Python initialization from several threads in parallel, we have to use
- a spin-lock. On CPython 3 it is worse because it might spin-lock for
- a long time (execution of ``Py_InitializeEx()``). Sadly, recent
- changes to CPython make that solution needed on CPython 2 too.
-
-* CPython 3 on Windows: we no longer compile with ``Py_LIMITED_API``
- by default because such modules cannot be used with virtualenv.
- `Issue #350`_ mentions a workaround if you still want that and are not
- concerned about virtualenv: pass ``define_macros=[("Py_LIMITED_API",
- None)]`` as a keyword to the ``ffibuilder.set_source()`` call.
-
-.. _`Issue #345`: https://foss.heptapod.net/pypy/cffi/-/issues/345
-.. _`Issue #350`: https://foss.heptapod.net/pypy/cffi/-/issues/350
-.. _`Issue #358`: https://foss.heptapod.net/pypy/cffi/-/issues/358
-.. _`Issue #357`: https://foss.heptapod.net/pypy/cffi/-/issues/357
-
-
-v1.11.4
--------
-
-* Windows: reverted linking with ``python3.dll``, because
- virtualenv does not make this DLL available to virtual environments
- for now. See `Issue #355`_. On Windows only, the C extension
- modules created by cffi follow for now the standard naming scheme
- ``foo.cp36-win32.pyd``, to make it clear that they are regular
- CPython modules depending on ``python36.dll``.
-
-.. _`Issue #355`: https://foss.heptapod.net/pypy/cffi/-/issues/355
-
-
-v1.11.3
--------
-
-* Fix on CPython 3.x: reading the attributes ``__loader__`` or
- ``__spec__`` from the cffi-generated lib modules gave a buggy
- SystemError. (These attributes are always None, and provided only to
- help compatibility with tools that expect them in all modules.)
-
-* More Windows fixes: workaround for MSVC not supporting large
- literal strings in C code (from
- ``ffi.embedding_init_code(large_string)``); and an issue with
- ``Py_LIMITED_API`` linking with ``python35.dll/python36.dll`` instead
- of ``python3.dll``.
-
-* Small documentation improvements.
-
-
-v1.11.2
--------
-
-* Fix Windows issue with managing the thread-state on CPython 3.0 to 3.5
-
-
-v1.11.1
--------
-
-* Fix tests, remove deprecated C API usage
-
-* Fix (hack) for 3.6.0/3.6.1/3.6.2 giving incompatible binary extensions
- (cpython issue `#29943`_)
-
-* Fix for 3.7.0a1+
-
-.. _`#29943`: https://bugs.python.org/issue29943
-
-
-v1.11
------
-
-* Support the modern standard types ``char16_t`` and ``char32_t``.
- These work like ``wchar_t``: they represent one unicode character, or
- when used as ``charN_t *`` or ``charN_t[]`` they represent a unicode
- string. The difference with ``wchar_t`` is that they have a known,
- fixed size. They should work at all places that used to work with
- ``wchar_t`` (please report an issue if I missed something). Note
- that with ``set_source()``, you need to make sure that these types are
- actually defined by the C source you provide (if used in ``cdef()``).
-
-* Support the C99 types ``float _Complex`` and ``double _Complex``.
- Note that libffi doesn't support them, which means that in the ABI
- mode you still cannot call C functions that take complex numbers
- directly as arguments or return type.
-
-* Fixed a rare race condition when creating multiple ``FFI`` instances
- from multiple threads. (Note that you aren't meant to create many
- ``FFI`` instances: in inline mode, you should write ``ffi =
- cffi.FFI()`` at module level just after ``import cffi``; and in
- out-of-line mode you don't instantiate ``FFI`` explicitly at all.)
-
-* Windows: using callbacks can be messy because the CFFI internal error
- messages show up to stderr---but stderr goes nowhere in many
- applications. This makes it particularly hard to get started with the
- embedding mode. (Once you get started, you can at least use
- ``@ffi.def_extern(onerror=...)`` and send the error logs where it
- makes sense for your application, or record them in log files, and so
- on.) So what is new in CFFI is that now, on Windows CFFI will try to
- open a non-modal MessageBox (in addition to sending raw messages to
- stderr). The MessageBox is only visible if the process stays alive:
- typically, console applications that crash close immediately, but that
- is also the situation where stderr should be visible anyway.
-
-* Progress on support for `callbacks in NetBSD`__.
-
-* Functions returning booleans would in some case still return 0 or 1
- instead of False or True. Fixed.
-
-* `ffi.gc()`__ now takes an optional third parameter, which gives an
- estimate of the size (in bytes) of the object. So far, this is only
- used by PyPy, to make the next GC occur more quickly (`issue #320`__).
- In the future, this might have an effect on CPython too (provided
- the CPython `issue 31105`__ is addressed).
-
-* Add a note to the documentation: the ABI mode gives function objects
- that are *slower* to call than the API mode does. For some reason it
- is often thought to be faster. It is not!
-
-.. __: https://foss.heptapod.net/pypy/cffi/-/issues/321
-.. __: ref.html#ffi-gc
-.. __: https://foss.heptapod.net/pypy/cffi/-/issues/320
-.. __: http://bugs.python.org/issue31105
-
-
-v1.10.1
--------
-
-(only released inside PyPy 5.8.0)
-
-* Fixed the line numbers reported in case of ``cdef()`` errors.
- Also, I just noticed, but pycparser always supported the preprocessor
- directive ``# 42 "foo.h"`` to mean "from the next line, we're in file
- foo.h starting from line 42", which it puts in the error messages.
-
-
-v1.10
------
-
-* Issue #295: use calloc() directly instead of
- PyObject_Malloc()+memset() to handle ffi.new() with a default
- allocator. Speeds up ``ffi.new(large-array)`` where most of the time
- you never touch most of the array.
-
-* Some OS/X build fixes ("only with Xcode but without CLT").
-
-* Improve a couple of error messages: when getting mismatched versions
- of cffi and its backend; and when calling functions which cannot be
- called with libffi because an argument is a struct that is "too
- complicated" (and not a struct *pointer*, which always works).
-
-* Add support for some unusual compilers (non-msvc, non-gcc, non-icc,
- non-clang)
-
-* Implemented the remaining cases for ``ffi.from_buffer``. Now all
- buffer/memoryview objects can be passed. The one remaining check is
- against passing unicode strings in Python 2. (They support the buffer
- interface, but that gives the raw bytes behind the UTF16/UCS4 storage,
- which is most of the times not what you expect. In Python 3 this has
- been fixed and the unicode strings don't support the memoryview
- interface any more.)
-
-* The C type ``_Bool`` or ``bool`` now converts to a Python boolean
- when reading, instead of the content of the byte as an integer. The
- potential incompatibility here is what occurs if the byte contains a
- value different from 0 and 1. Previously, it would just return it;
- with this change, CFFI raises an exception in this case. But this
- case means "undefined behavior" in C; if you really have to interface
- with a library relying on this, don't use ``bool`` in the CFFI side.
- Also, it is still valid to use a byte string as initializer for a
- ``bool[]``, but now it must only contain ``\x00`` or ``\x01``. As an
- aside, ``ffi.string()`` no longer works on ``bool[]`` (but it never
- made much sense, as this function stops at the first zero).
-
-* ``ffi.buffer`` is now the name of cffi's buffer type, and
- ``ffi.buffer()`` works like before but is the constructor of that type.
-
-* ``ffi.addressof(lib, "name")`` now works also in in-line mode, not
- only in out-of-line mode. This is useful for taking the address of
- global variables.
-
-* Issue #255: ``cdata`` objects of a primitive type (integers, floats,
- char) are now compared and ordered by value. For example, ``<cdata
- 'int' 42>`` compares equal to ``42`` and ``<cdata 'char' b'A'>``
- compares equal to ``b'A'``. Unlike C, ``<cdata 'int' -1>`` does not
- compare equal to ``ffi.cast("unsigned int", -1)``: it compares
- smaller, because ``-1 < 4294967295``.
-
-* PyPy: ``ffi.new()`` and ``ffi.new_allocator()()`` did not record
- "memory pressure", causing the GC to run too infrequently if you call
- ``ffi.new()`` very often and/or with large arrays. Fixed in PyPy 5.7.
-
-* Support in ``ffi.cdef()`` for numeric expressions with ``+`` or
- ``-``. Assumes that there is no overflow; it should be fixed first
- before we add more general support for arbitrary arithmetic on
- constants.
-
-
-v1.9
-----
-
-* Structs with variable-sized arrays as their last field: now we track
- the length of the array after ``ffi.new()`` is called, just like we
- always tracked the length of ``ffi.new("int[]", 42)``. This lets us
- detect out-of-range accesses to array items. This also lets us
- display a better ``repr()``, and have the total size returned by
- ``ffi.sizeof()`` and ``ffi.buffer()``. Previously both functions
- would return a result based on the size of the declared structure
- type, with an assumed empty array. (Thanks andrew for starting this
- refactoring.)
-
-* Add support in ``cdef()/set_source()`` for unspecified-length arrays
- in typedefs: ``typedef int foo_t[...];``. It was already supported
- for global variables or structure fields.
-
-* I turned in v1.8 a warning from ``cffi/model.py`` into an error:
- ``'enum xxx' has no values explicitly defined: refusing to guess which
- integer type it is meant to be (unsigned/signed, int/long)``. Now I'm
- turning it back to a warning again; it seems that guessing that the
- enum has size ``int`` is a 99%-safe bet. (But not 100%, so it stays
- as a warning.)
-
-* Fix leaks in the code handling ``FILE *`` arguments. In CPython 3
- there is a remaining issue that is hard to fix: if you pass a Python
- file object to a ``FILE *`` argument, then ``os.dup()`` is used and
- the new file descriptor is only closed when the GC reclaims the Python
- file object---and not at the earlier time when you call ``close()``,
- which only closes the original file descriptor. If this is an issue,
- you should avoid this automatic convertion of Python file objects:
- instead, explicitly manipulate file descriptors and call ``fdopen()``
- from C (...via cffi).
-
-
-v1.8.3
-------
-
-* When passing a ``void *`` argument to a function with a different
- pointer type, or vice-versa, the cast occurs automatically, like in C.
- The same occurs for initialization with ``ffi.new()`` and a few other
- places. However, I thought that ``char *`` had the same
- property---but I was mistaken. In C you get the usual warning if you
- try to give a ``char *`` to a ``char **`` argument, for example.
- Sorry about the confusion. This has been fixed in CFFI by giving for
- now a warning, too. It will turn into an error in a future version.
-
-
-v1.8.2
-------
-
-* Issue #283: fixed ``ffi.new()`` on structures/unions with nested
- anonymous structures/unions, when there is at least one union in
- the mix. When initialized with a list or a dict, it should now
- behave more closely like the ``{ }`` syntax does in GCC.
-
-
-v1.8.1
-------
-
-* CPython 3.x: experimental: the generated C extension modules now use
- the "limited API", which means that, as a compiled .so/.dll, it should
- work directly on any version of CPython >= 3.2. The name produced by
- distutils is still version-specific. To get the version-independent
- name, you can rename it manually to ``NAME.abi3.so``, or use the very
- recent setuptools 26.
-
-* Added ``ffi.compile(debug=...)``, similar to ``python setup.py build
- --debug`` but defaulting to True if we are running a debugging
- version of Python itself.
-
-
-v1.8
-----
-
-* Removed the restriction that ``ffi.from_buffer()`` cannot be used on
- byte strings. Now you can get a ``char *`` out of a byte string,
- which is valid as long as the string object is kept alive. (But
- don't use it to *modify* the string object! If you need this, use
- ``bytearray`` or other official techniques.)
-
-* PyPy 5.4 can now pass a byte string directly to a ``char *``
- argument (in older versions, a copy would be made). This used to be
- a CPython-only optimization.
-
-
-v1.7
-----
-
-* ``ffi.gc(p, None)`` removes the destructor on an object previously
- created by another call to ``ffi.gc()``
-
-* ``bool(ffi.cast("primitive type", x))`` now returns False if the
- value is zero (including ``-0.0``), and True otherwise. Previously
- this would only return False for cdata objects of a pointer type when
- the pointer is NULL.
-
-* bytearrays: ``ffi.from_buffer(bytearray-object)`` is now supported.
- (The reason it was not supported was that it was hard to do in PyPy,
- but it works since PyPy 5.3.) To call a C function with a ``char *``
- argument from a buffer object---now including bytearrays---you write
- ``lib.foo(ffi.from_buffer(x))``. Additionally, this is now supported:
- ``p[0:length] = bytearray-object``. The problem with this was that a
- iterating over bytearrays gives *numbers* instead of *characters*.
- (Now it is implemented with just a memcpy, of course, not actually
- iterating over the characters.)
-
-* C++: compiling the generated C code with C++ was supposed to work,
- but failed if you make use the ``bool`` type (because that is rendered
- as the C ``_Bool`` type, which doesn't exist in C++).
-
-* ``help(lib)`` and ``help(lib.myfunc)`` now give useful information,
- as well as ``dir(p)`` where ``p`` is a struct or pointer-to-struct.
-
-
-v1.6
-----
-
-* `ffi.list_types()`_
-
-* `ffi.unpack()`_
-
-* `extern "Python+C"`_
-
-* in API mode, ``lib.foo.__doc__`` contains the C signature now. On
- CPython you can say ``help(lib.foo)``, but for some reason
- ``help(lib)`` (or ``help(lib.foo)`` on PyPy) is still useless; I
- haven't yet figured out the hacks needed to convince ``pydoc`` to
- show more. (You can use ``dir(lib)`` but it is not most helpful.)
-
-* Yet another attempt at robustness of ``ffi.def_extern()`` against
- CPython's interpreter shutdown logic.
-
-.. _`ffi.list_types()`: ref.html#ffi-list-types
-.. _`ffi.unpack()`: ref.html#ffi-unpack
-.. _`extern "Python+C"`: using.html#extern-python-c
-
-
-v1.5.2
-------
-
-* Fix 1.5.1 for Python 2.6.
-
-
-v1.5.1
-------
-
-* A few installation-time tweaks (thanks Stefano!)
-
-* Issue #245: Win32: ``__stdcall`` was never generated for
- ``extern "Python"`` functions
-
-* Issue #246: trying to be more robust against CPython's fragile
- interpreter shutdown logic
-
-
-v1.5.0
-------
-
-* Support for `using CFFI for embedding`__.
-
-.. __: embedding.html
-
-
-v1.4.2
-------
-
-Nothing changed from v1.4.1.
-
-
-v1.4.1
-------
-
-* Fix the compilation failure of cffi on CPython 3.5.0. (3.5.1 works;
- some detail changed that makes some underscore-starting macros
- disappear from view of extension modules, and I worked around it,
- thinking it changed in all 3.5 versions---but no: it was only in
- 3.5.1.)
-
-
-v1.4.0
-------
-
-* A `better way to do callbacks`__ has been added (faster and more
- portable, and usually cleaner). It is a mechanism for the
- out-of-line API mode that replaces the dynamic creation of callback
- objects (i.e. C functions that invoke Python) with the static
- declaration in ``cdef()`` of which callbacks are needed. This is
- more C-like, in that you have to structure your code around the idea
- that you get a fixed number of function pointers, instead of
- creating them on-the-fly.
-
-* ``ffi.compile()`` now takes an optional ``verbose`` argument. When
- ``True``, distutils prints the calls to the compiler.
-
-* ``ffi.compile()`` used to fail if given ``sources`` with a path that
- includes ``".."``. Fixed.
-
-* ``ffi.init_once()`` added. See docs__.
-
-* ``dir(lib)`` now works on libs returned by ``ffi.dlopen()`` too.
-
-* Cleaned up and modernized the content of the ``demo`` subdirectory
- in the sources (thanks matti!).
-
-* ``ffi.new_handle()`` is now guaranteed to return unique ``void *``
- values, even if called twice on the same object. Previously, in
- that case, CPython would return two ``cdata`` objects with the same
- ``void *`` value. This change is useful to add and remove handles
- from a global dict (or set) without worrying about duplicates.
- It already used to work like that on PyPy.
- *This change can break code that used to work on CPython by relying
- on the object to be kept alive by other means than keeping the
- result of ffi.new_handle() alive.* (The corresponding `warning in
- the docs`__ of ``ffi.new_handle()`` has been here since v0.8!)
-
-.. __: using.html#extern-python
-.. __: ref.html#ffi-init-once
-.. __: ref.html#ffi-new-handle
-
-
-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
-------
-
-* Added `ffi.memmove()`_.
-
-* Pull request #64: out-of-line API mode: we can now declare
- floating-point types with ``typedef float... foo_t;``. This only
- works if ``foo_t`` is a float or a double, not ``long double``.
-
-* Issue #217: fix possible unaligned pointer manipulation, which crashes
- on some architectures (64-bit, non-x86).
-
-* Issues #64 and #126: when using ``set_source()`` or ``verify()``,
- the ``const`` and ``restrict`` keywords are copied from the cdef
- to the generated C code; this fixes warnings by the C compiler.
- It also fixes corner cases like ``typedef const int T; T a;``
- which would previously not consider ``a`` as a constant. (The
- cdata objects themselves are never ``const``.)
-
-* Win32: support for ``__stdcall``. For callbacks and function
- pointers; regular C functions still don't need to have their `calling
- convention`_ declared.
-
-* Windows: CPython 2.7 distutils doesn't work with Microsoft's official
- Visual Studio for Python, and I'm told this is `not a bug`__. For
- ffi.compile(), we `removed a workaround`__ that was inside cffi but
- which had unwanted side-effects. Try saying ``import setuptools``
- first, which patches distutils...
-
-.. _`ffi.memmove()`: ref.html#ffi-memmove
-.. __: https://bugs.python.org/issue23246
-.. __: https://bitbucket.org/cffi/cffi/pull-requests/65/remove-_hack_at_distutils-which-imports/diff
-.. _`calling convention`: using.html#windows-calling-conventions
-
-
-v1.2.1
-------
-
-Nothing changed from v1.2.0.
-
-
-v1.2.0
-------
-
-* Out-of-line mode: ``int a[][...];`` can be used to declare a structure
- field or global variable which is, simultaneously, of total length
- unknown to the C compiler (the ``a[]`` part) and each element is
- itself an array of N integers, where the value of N *is* known to the
- C compiler (the ``int`` and ``[...]`` parts around it). Similarly,
- ``int a[5][...];`` is supported (but probably less useful: remember
- that in C it means ``int (a[5])[...];``).
-
-* PyPy: the ``lib.some_function`` objects were missing the attributes
- ``__name__``, ``__module__`` and ``__doc__`` that are expected e.g. by
- some decorators-management functions from ``functools``.
-
-* Out-of-line API mode: you can now do ``from _example.lib import x``
- to import the name ``x`` from ``_example.lib``, even though the
- ``lib`` object is not a standard module object. (Also works in ``from
- _example.lib import *``, but this is even more of a hack and will fail
- if ``lib`` happens to declare a name called ``__all__``. Note that
- ``*`` excludes the global variables; only the functions and constants
- make sense to import like this.)
-
-* ``lib.__dict__`` works again and gives you a copy of the
- dict---assuming that ``lib`` has got no symbol called precisely
- ``__dict__``. (In general, it is safer to use ``dir(lib)``.)
-
-* Out-of-line API mode: global variables are now fetched on demand at
- every access. It fixes issue #212 (Windows DLL variables), and also
- allows variables that are defined as dynamic macros (like ``errno``)
- or ``__thread`` -local variables. (This change might also tighten
- the C compiler's check on the variables' type.)
-
-* Issue #209: dereferencing NULL pointers now raises RuntimeError
- instead of segfaulting. Meant as a debugging aid. The check is
- only for NULL: if you dereference random or dead pointers you might
- still get segfaults.
-
-* Issue #152: callbacks__: added an argument ``ffi.callback(...,
- onerror=...)``. If the main callback function raises an exception
- and ``onerror`` is provided, then ``onerror(exception, exc_value,
- traceback)`` is called. This is similar to writing a ``try:
- except:`` in the main callback function, but in some cases (e.g. a
- signal) an exception can occur at the very start of the callback
- function---before it had time to enter the ``try: except:`` block.
-
-* Issue #115: added ``ffi.new_allocator()``, which officializes
- support for `alternative allocators`__.
-
-.. __: using.html#callbacks
-.. __: ref.html#ffi-new-allocator
-
-
-v1.1.2
-------
-
-* ``ffi.gc()``: fixed a race condition in multithreaded programs
- introduced in 1.1.1
-
-
-v1.1.1
-------
-
-* Out-of-line mode: ``ffi.string()``, ``ffi.buffer()`` and
- ``ffi.getwinerror()`` didn't accept their arguments as keyword
- arguments, unlike their in-line mode equivalent. (It worked in PyPy.)
-
-* Out-of-line ABI mode: documented a restriction__ of ``ffi.dlopen()``
- when compared to the in-line mode.
-
-* ``ffi.gc()``: when called several times with equal pointers, it was
- accidentally registering only the last destructor, or even none at
- all depending on details. (It was correctly registering all of them
- only in PyPy, and only with the out-of-line FFIs.)
-
-.. __: cdef.html#dlopen-note
-
-
-v1.1.0
-------
-
-* Out-of-line API mode: we can now declare integer types with
- ``typedef int... foo_t;``. The exact size and signedness of ``foo_t``
- is figured out by the compiler.
-
-* Out-of-line API mode: we can now declare multidimensional arrays
- (as fields or as globals) with ``int n[...][...]``. Before, only the
- outermost dimension would support the ``...`` syntax.
-
-* Out-of-line ABI mode: we now support any constant declaration,
- instead of only integers whose value is given in the cdef. Such "new"
- constants, i.e. either non-integers or without a value given in the
- cdef, must correspond to actual symbols in the lib. At runtime they
- are looked up the first time we access them. This is useful if the
- library defines ``extern const sometype somename;``.
-
-* ``ffi.addressof(lib, "func_name")`` now returns a regular cdata object
- of type "pointer to function". You can use it on any function from a
- library in API mode (in ABI mode, all functions are already regular
- cdata objects). To support this, you need to recompile your cffi
- modules.
-
-* Issue #198: in API mode, if you declare constants of a ``struct``
- type, what you saw from lib.CONSTANT was corrupted.
-
-* Issue #196: ``ffi.set_source("package._ffi", None)`` would
- incorrectly generate the Python source to ``package._ffi.py`` instead
- of ``package/_ffi.py``. Also fixed: in some cases, if the C file was
- in ``build/foo.c``, the .o file would be put in ``build/build/foo.o``.
-
-
-v1.0.3
-------
-
-* Same as 1.0.2, apart from doc and test fixes on some platforms.
-
-
-v1.0.2
-------
-
-* Variadic C functions (ending in a "..." argument) were not supported
- in the out-of-line ABI mode. This was a bug---there was even a
- (non-working) example__ doing exactly that!
-
-.. __: overview.html#out-of-line-abi-level
-
-
-v1.0.1
-------
-
-* ``ffi.set_source()`` crashed if passed a ``sources=[..]`` argument.
- Fixed by chrippa on pull request #60.
-
-* Issue #193: if we use a struct between the first cdef() where it is
- declared and another cdef() where its fields are defined, then this
- definition was ignored.
-
-* Enums were buggy if you used too many "..." in their definition.
-
-
-v1.0.0
-------
-
-* The main news item is out-of-line module generation:
-
- * `for ABI level`_, with ``ffi.dlopen()``
-
- * `for API level`_, which used to be with ``ffi.verify()``, now deprecated
-
-* (this page will list what is new from all versions from 1.0.0
- forward.)
-
-.. _`for ABI level`: overview.html#out-of-line-abi-level
-.. _`for API level`: overview.html#out-of-line-api-level
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index a97f028..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-pycparser
-pytest
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 0c9e0fc..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[metadata]
-license_file = LICENSE
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 5fd1a1c..0000000
--- a/setup.py
+++ /dev/null
@@ -1,238 +0,0 @@
-import sys, os, platform
-import subprocess
-import errno
-
-# on Windows we give up and always import setuptools early to fix things for us
-if sys.platform == "win32":
- import setuptools
-
-
-sources = ['c/_cffi_backend.c']
-libraries = ['ffi']
-include_dirs = ['/usr/include/ffi',
- '/usr/include/libffi'] # may be changed by pkg-config
-define_macros = []
-library_dirs = []
-extra_compile_args = []
-extra_link_args = []
-
-
-def _ask_pkg_config(resultlist, option, result_prefix='', sysroot=False):
- pkg_config = os.environ.get('PKG_CONFIG','pkg-config')
- try:
- p = subprocess.Popen([pkg_config, option, 'libffi'],
- stdout=subprocess.PIPE)
- except OSError as e:
- if e.errno not in [errno.ENOENT, errno.EACCES]:
- raise
- else:
- t = p.stdout.read().decode().strip()
- p.stdout.close()
- if p.wait() == 0:
- res = t.split()
- # '-I/usr/...' -> '/usr/...'
- for x in res:
- assert x.startswith(result_prefix)
- res = [x[len(result_prefix):] for x in res]
- #print 'PKG_CONFIG:', option, res
- #
- sysroot = sysroot and os.environ.get('PKG_CONFIG_SYSROOT_DIR', '')
- if sysroot:
- # old versions of pkg-config don't support this env var,
- # so here we emulate its effect if needed
- res = [path if path.startswith(sysroot)
- else sysroot + path
- for path in res]
- #
- resultlist[:] = res
-
-no_compiler_found = False
-def no_working_compiler_found():
- sys.stderr.write("""
- No working compiler found, or bogus compiler options passed to
- the compiler from Python's standard "distutils" module. See
- the error messages above. Likely, the problem is not related
- to CFFI but generic to the setup.py of any Python package that
- tries to compile C code. (Hints: on OS/X 10.8, for errors about
- -mno-fused-madd see http://stackoverflow.com/questions/22313407/
- Otherwise, see https://wiki.python.org/moin/CompLangPython or
- the IRC channel #python on irc.libera.chat.)
-
- Trying to continue anyway. If you are trying to install CFFI from
- a build done in a different context, you can ignore this warning.
- \n""")
- global no_compiler_found
- no_compiler_found = True
-
-def get_config():
- from distutils.core import Distribution
- from distutils.sysconfig import get_config_vars
- get_config_vars() # workaround for a bug of distutils, e.g. on OS/X
- config = Distribution().get_command_obj('config')
- return config
-
-def ask_supports_thread():
- config = get_config()
- ok = (sys.platform != 'win32' and
- config.try_compile('__thread int some_threadlocal_variable_42;'))
- if ok:
- define_macros.append(('USE__THREAD', None))
- else:
- ok1 = config.try_compile('int some_regular_variable_42;')
- if not ok1:
- no_working_compiler_found()
- else:
- sys.stderr.write("Note: will not use '__thread' in the C code\n")
- _safe_to_ignore()
-
-def ask_supports_sync_synchronize():
- if sys.platform == 'win32' or no_compiler_found:
- return
- config = get_config()
- ok = config.try_link('int main(void) { __sync_synchronize(); return 0; }')
- if ok:
- define_macros.append(('HAVE_SYNC_SYNCHRONIZE', None))
- else:
- sys.stderr.write("Note: will not use '__sync_synchronize()'"
- " in the C code\n")
- _safe_to_ignore()
-
-def _safe_to_ignore():
- sys.stderr.write("***** The above error message can be safely ignored.\n\n")
-
-def uses_msvc():
- config = get_config()
- return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif')
-
-def use_pkg_config():
- if sys.platform == 'darwin' and os.path.exists('/usr/local/bin/brew'):
- use_homebrew_for_libffi()
-
- _ask_pkg_config(include_dirs, '--cflags-only-I', '-I', sysroot=True)
- _ask_pkg_config(extra_compile_args, '--cflags-only-other')
- _ask_pkg_config(library_dirs, '--libs-only-L', '-L', sysroot=True)
- _ask_pkg_config(extra_link_args, '--libs-only-other')
- _ask_pkg_config(libraries, '--libs-only-l', '-l')
-
-def use_homebrew_for_libffi():
- # We can build by setting:
- # PKG_CONFIG_PATH = $(brew --prefix libffi)/lib/pkgconfig
- with os.popen('brew --prefix libffi') as brew_prefix_cmd:
- prefix = brew_prefix_cmd.read().strip()
- pkgconfig = os.path.join(prefix, 'lib', 'pkgconfig')
- os.environ['PKG_CONFIG_PATH'] = (
- os.environ.get('PKG_CONFIG_PATH', '') + ':' + pkgconfig)
-
-if sys.platform == "win32" and uses_msvc():
- if platform.machine() == "ARM64":
- include_dirs.append(os.path.join("c/libffi_arm64/include"))
- library_dirs.append(os.path.join("c/libffi_arm64"))
- else:
- COMPILE_LIBFFI = 'c/libffi_x86_x64' # from the CPython distribution
- assert os.path.isdir(COMPILE_LIBFFI), "directory not found!"
- include_dirs[:] = [COMPILE_LIBFFI]
- libraries[:] = []
- _filenames = [filename.lower() for filename in os.listdir(COMPILE_LIBFFI)]
- _filenames = [filename for filename in _filenames
- if filename.endswith('.c')]
- if sys.maxsize > 2**32:
- # 64-bit: unlist win32.c, and add instead win64.obj. If the obj
- # happens to get outdated at some point in the future, you need to
- # rebuild it manually from win64.asm.
- _filenames.remove('win32.c')
- extra_link_args.append(os.path.join(COMPILE_LIBFFI, 'win64.obj'))
- sources.extend(os.path.join(COMPILE_LIBFFI, filename)
- for filename in _filenames)
-else:
- use_pkg_config()
- ask_supports_thread()
- ask_supports_sync_synchronize()
-
-if 'darwin' in sys.platform:
- # priority is given to `pkg_config`, but always fall back on SDK's libffi.
- extra_compile_args += ['-iwithsysroot/usr/include/ffi']
-
-if 'freebsd' in sys.platform:
- include_dirs.append('/usr/local/include')
- library_dirs.append('/usr/local/lib')
-
-if __name__ == '__main__':
- from setuptools import setup, Distribution, Extension
-
- class CFFIDistribution(Distribution):
- def has_ext_modules(self):
- # Event if we don't have extension modules (e.g. on PyPy) we want to
- # claim that we do so that wheels get properly tagged as Python
- # specific. (thanks dstufft!)
- return True
-
- # On PyPy, cffi is preinstalled and it is not possible, at least for now,
- # to install a different version. We work around it by making the setup()
- # arguments mostly empty in this case.
- cpython = ('_cffi_backend' not in sys.builtin_module_names)
-
- setup(
- name='cffi',
- description='Foreign Function Interface for Python calling C code.',
- long_description="""
-CFFI
-====
-
-Foreign Function Interface for Python calling C code.
-Please see the `Documentation <http://cffi.readthedocs.org/>`_.
-
-Contact
--------
-
-`Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
-""",
- version='1.15.0',
- packages=['cffi'] if cpython else [],
- package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h',
- '_embedding.h', '_cffi_errors.h']}
- if cpython else {},
- zip_safe=False,
-
- url='http://cffi.readthedocs.org',
- author='Armin Rigo, Maciej Fijalkowski',
- author_email='python-cffi@googlegroups.com',
-
- license='MIT',
-
- distclass=CFFIDistribution,
- ext_modules=[Extension(
- name='_cffi_backend',
- include_dirs=include_dirs,
- sources=sources,
- libraries=libraries,
- define_macros=define_macros,
- library_dirs=library_dirs,
- extra_compile_args=extra_compile_args,
- extra_link_args=extra_link_args,
- )] if cpython else [],
-
- install_requires=[
- 'pycparser' if sys.version_info >= (2, 7) else 'pycparser<2.19',
- ] if cpython else [],
-
- entry_points = {
- "distutils.setup_keywords": [
- "cffi_modules = cffi.setuptools_ext:cffi_modules",
- ],
- },
-
- classifiers=[
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
- 'Programming Language :: Python :: 3.10',
- 'Programming Language :: Python :: Implementation :: CPython',
- 'Programming Language :: Python :: Implementation :: PyPy',
- 'License :: OSI Approved :: MIT License',
- ],
- )
diff --git a/setup_base.py b/setup_base.py
deleted file mode 100644
index 4cf6ea5..0000000
--- a/setup_base.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import sys, os
-
-
-from setup import include_dirs, sources, libraries, define_macros
-from setup import library_dirs, extra_compile_args, extra_link_args
-
-
-if __name__ == '__main__':
- from distutils.core import setup
- from distutils.extension import Extension
-
- standard = '__pypy__' not in sys.builtin_module_names
- setup(packages=['cffi'],
- requires=['pycparser'],
- ext_modules=[Extension(name = '_cffi_backend',
- include_dirs=include_dirs,
- sources=sources,
- libraries=libraries,
- define_macros=define_macros,
- library_dirs=library_dirs,
- extra_compile_args=extra_compile_args,
- extra_link_args=extra_link_args,
- )] * standard)
diff --git a/testing/__init__.py b/testing/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/testing/__init__.py
+++ /dev/null
diff --git a/testing/cffi0/__init__.py b/testing/cffi0/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/testing/cffi0/__init__.py
+++ /dev/null
diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py
deleted file mode 100644
index ab013a1..0000000
--- a/testing/cffi0/backend_tests.py
+++ /dev/null
@@ -1,2027 +0,0 @@
-import py
-import pytest
-import platform
-import sys, ctypes, ctypes.util
-from cffi import FFI, CDefError, FFIError, VerificationMissing
-from testing.support import *
-
-SIZE_OF_INT = ctypes.sizeof(ctypes.c_int)
-SIZE_OF_LONG = ctypes.sizeof(ctypes.c_long)
-SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short)
-SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p)
-SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
-
-def needs_dlopen_none():
- if sys.platform == 'win32' and not ctypes.util.find_library('c'):
- py.test.skip("dlopen(None) cannot work on Windows with this runtime")
-
-
-class BackendTests:
-
- def test_integer_ranges(self):
- ffi = FFI(backend=self.Backend())
- for (c_type, size) in [('char', 1),
- ('short', 2),
- ('short int', 2),
- ('', 4),
- ('int', 4),
- ('long', SIZE_OF_LONG),
- ('long int', SIZE_OF_LONG),
- ('long long', 8),
- ('long long int', 8),
- ]:
- for unsigned in [None, False, True]:
- c_decl = {None: '',
- False: 'signed ',
- True: 'unsigned '}[unsigned] + c_type
- if c_decl == 'char' or c_decl == '':
- continue
- self._test_int_type(ffi, c_decl, size, unsigned)
-
- def test_fixedsize_int(self):
- ffi = FFI(backend=self.Backend())
- for size in [1, 2, 4, 8]:
- self._test_int_type(ffi, 'int%d_t' % (8*size), size, False)
- self._test_int_type(ffi, 'uint%d_t' % (8*size), size, True)
- self._test_int_type(ffi, 'intptr_t', SIZE_OF_PTR, False)
- self._test_int_type(ffi, 'uintptr_t', SIZE_OF_PTR, True)
- self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False)
- self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True)
- self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False)
-
- def _test_int_type(self, ffi, c_decl, size, unsigned):
- if unsigned:
- min = 0
- max = (1 << (8*size)) - 1
- else:
- min = -(1 << (8*size-1))
- max = (1 << (8*size-1)) - 1
- min = int(min)
- max = int(max)
- p = ffi.cast(c_decl, min)
- assert p == min
- assert hash(p) == hash(min)
- assert bool(p) is bool(min)
- assert int(p) == min
- p = ffi.cast(c_decl, max)
- assert int(p) == max
- p = ffi.cast(c_decl, long(max))
- assert int(p) == max
- q = ffi.cast(c_decl, min - 1)
- assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
- q = ffi.cast(c_decl, long(min - 1))
- assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
- assert q == p
- assert int(q) == int(p)
- assert hash(q) == hash(p)
- c_decl_ptr = '%s *' % c_decl
- py.test.raises(OverflowError, ffi.new, c_decl_ptr, min - 1)
- py.test.raises(OverflowError, ffi.new, c_decl_ptr, max + 1)
- py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1))
- py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1))
- assert ffi.new(c_decl_ptr, min)[0] == min
- assert ffi.new(c_decl_ptr, max)[0] == max
- assert ffi.new(c_decl_ptr, long(min))[0] == min
- assert ffi.new(c_decl_ptr, long(max))[0] == max
-
- def test_new_unsupported_type(self):
- ffi = FFI(backend=self.Backend())
- e = py.test.raises(TypeError, ffi.new, "int")
- assert str(e.value) == "expected a pointer or array ctype, got 'int'"
-
- def test_new_single_integer(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int *") # similar to ffi.new("int[1]")
- assert p[0] == 0
- p[0] = -123
- assert p[0] == -123
- p = ffi.new("int *", -42)
- assert p[0] == -42
- assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT
-
- def test_new_array_no_arg(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int[10]")
- # the object was zero-initialized:
- for i in range(10):
- assert p[i] == 0
-
- def test_array_indexing(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int[10]")
- p[0] = 42
- p[9] = 43
- assert p[0] == 42
- assert p[9] == 43
- with pytest.raises(IndexError):
- p[10]
- with pytest.raises(IndexError):
- p[10] = 44
- with pytest.raises(IndexError):
- p[-1]
- with pytest.raises(IndexError):
- p[-1] = 44
-
- def test_new_array_args(self):
- ffi = FFI(backend=self.Backend())
- # this tries to be closer to C: where we say "int x[5] = {10, 20, ..}"
- # then here we must enclose the items in a list
- p = ffi.new("int[5]", [10, 20, 30, 40, 50])
- assert p[0] == 10
- assert p[1] == 20
- assert p[2] == 30
- assert p[3] == 40
- assert p[4] == 50
- p = ffi.new("int[4]", [25])
- assert p[0] == 25
- assert p[1] == 0 # follow C convention rather than LuaJIT's
- assert p[2] == 0
- assert p[3] == 0
- p = ffi.new("int[4]", [ffi.cast("int", -5)])
- assert p[0] == -5
- assert repr(p) == "<cdata 'int[4]' owning %d bytes>" % (4*SIZE_OF_INT)
-
- def test_new_array_varsize(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int[]", 10) # a single integer is the length
- assert p[9] == 0
- with pytest.raises(IndexError):
- p[10]
- #
- py.test.raises(TypeError, ffi.new, "int[]")
- #
- p = ffi.new("int[]", [-6, -7]) # a list is all the items, like C
- assert p[0] == -6
- assert p[1] == -7
- with pytest.raises(IndexError):
- p[2]
- assert repr(p) == "<cdata 'int[]' owning %d bytes>" % (2*SIZE_OF_INT)
- #
- p = ffi.new("int[]", 0)
- with pytest.raises(IndexError):
- p[0]
- py.test.raises(ValueError, ffi.new, "int[]", -1)
- assert repr(p) == "<cdata 'int[]' owning 0 bytes>"
-
- def test_pointer_init(self):
- ffi = FFI(backend=self.Backend())
- n = ffi.new("int *", 24)
- a = ffi.new("int *[10]", [ffi.NULL, ffi.NULL, n, n, ffi.NULL])
- for i in range(10):
- if i not in (2, 3):
- assert a[i] == ffi.NULL
- assert a[2] == a[3] == n
-
- def test_cannot_cast(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("short int[10]")
- e = py.test.raises(TypeError, ffi.new, "long int **", a)
- msg = str(e.value)
- assert "'short[10]'" in msg and "'long *'" in msg
-
- def test_new_pointer_to_array(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("int[4]", [100, 102, 104, 106])
- p = ffi.new("int **", a)
- assert p[0] == ffi.cast("int *", a)
- assert p[0][2] == 104
- p = ffi.cast("int *", a)
- assert p[0] == 100
- assert p[1] == 102
- assert p[2] == 104
- assert p[3] == 106
- # keepalive: a
-
- def test_pointer_direct(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.cast("int*", 0)
- assert p is not None
- assert bool(p) is False
- assert p == ffi.cast("int*", 0)
- assert p != None
- assert repr(p) == "<cdata 'int *' NULL>"
- a = ffi.new("int[]", [123, 456])
- p = ffi.cast("int*", a)
- assert bool(p) is True
- assert p == ffi.cast("int*", a)
- assert p != ffi.cast("int*", 0)
- assert p[0] == 123
- assert p[1] == 456
-
- def test_repr(self):
- typerepr = self.TypeRepr
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { short a, b, c; };")
- p = ffi.cast("short unsigned int", 0)
- assert repr(p) == "<cdata 'unsigned short' 0>"
- assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
- p = ffi.cast("unsigned short int", 0)
- assert repr(p) == "<cdata 'unsigned short' 0>"
- assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
- p = ffi.cast("int*", 0)
- assert repr(p) == "<cdata 'int *' NULL>"
- assert repr(ffi.typeof(p)) == typerepr % "int *"
- #
- p = ffi.new("int*")
- assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT
- assert repr(ffi.typeof(p)) == typerepr % "int *"
- p = ffi.new("int**")
- assert repr(p) == "<cdata 'int * *' owning %d bytes>" % SIZE_OF_PTR
- assert repr(ffi.typeof(p)) == typerepr % "int * *"
- p = ffi.new("int [2]")
- assert repr(p) == "<cdata 'int[2]' owning %d bytes>" % (2*SIZE_OF_INT)
- assert repr(ffi.typeof(p)) == typerepr % "int[2]"
- p = ffi.new("int*[2][3]")
- assert repr(p) == "<cdata 'int *[2][3]' owning %d bytes>" % (
- 6*SIZE_OF_PTR)
- assert repr(ffi.typeof(p)) == typerepr % "int *[2][3]"
- p = ffi.new("struct foo *")
- assert repr(p) == "<cdata 'struct foo *' owning %d bytes>" % (
- 3*SIZE_OF_SHORT)
- assert repr(ffi.typeof(p)) == typerepr % "struct foo *"
- #
- q = ffi.cast("short", -123)
- assert repr(q) == "<cdata 'short' -123>"
- assert repr(ffi.typeof(q)) == typerepr % "short"
- p = ffi.new("int*")
- q = ffi.cast("short*", p)
- assert repr(q).startswith("<cdata 'short *' 0x")
- assert repr(ffi.typeof(q)) == typerepr % "short *"
- p = ffi.new("int [2]")
- q = ffi.cast("int*", p)
- assert repr(q).startswith("<cdata 'int *' 0x")
- assert repr(ffi.typeof(q)) == typerepr % "int *"
- p = ffi.new("struct foo*")
- q = ffi.cast("struct foo *", p)
- assert repr(q).startswith("<cdata 'struct foo *' 0x")
- assert repr(ffi.typeof(q)) == typerepr % "struct foo *"
- prevrepr = repr(q)
- q = q[0]
- assert repr(q) == prevrepr.replace(' *', ' &')
- assert repr(ffi.typeof(q)) == typerepr % "struct foo"
-
- def test_new_array_of_array(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int[3][4]")
- p[0][0] = 10
- p[2][3] = 33
- assert p[0][0] == 10
- assert p[2][3] == 33
- with pytest.raises(IndexError):
- p[1][-1]
-
- def test_constructor_array_of_array(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int[3][2]", [[10, 11], [12, 13], [14, 15]])
- assert p[2][1] == 15
-
- def test_new_array_of_pointer_1(self):
- ffi = FFI(backend=self.Backend())
- n = ffi.new("int*", 99)
- p = ffi.new("int*[4]")
- p[3] = n
- a = p[3]
- assert repr(a).startswith("<cdata 'int *' 0x")
- assert a[0] == 99
-
- def test_new_array_of_pointer_2(self):
- ffi = FFI(backend=self.Backend())
- n = ffi.new("int[1]", [99])
- p = ffi.new("int*[4]")
- p[3] = n
- a = p[3]
- assert repr(a).startswith("<cdata 'int *' 0x")
- assert a[0] == 99
-
- def test_char(self):
- ffi = FFI(backend=self.Backend())
- assert ffi.new("char*", b"\xff")[0] == b'\xff'
- assert ffi.new("char*")[0] == b'\x00'
- assert int(ffi.cast("char", 300)) == 300 - 256
- assert not bool(ffi.cast("char", 0))
- assert bool(ffi.cast("char", 1))
- assert bool(ffi.cast("char", 255))
- py.test.raises(TypeError, ffi.new, "char*", 32)
- py.test.raises(TypeError, ffi.new, "char*", u+"x")
- py.test.raises(TypeError, ffi.new, "char*", b"foo")
- #
- p = ffi.new("char[]", [b'a', b'b', b'\x9c'])
- assert len(p) == 3
- assert p[0] == b'a'
- assert p[1] == b'b'
- assert p[2] == b'\x9c'
- p[0] = b'\xff'
- assert p[0] == b'\xff'
- p = ffi.new("char[]", b"abcd")
- assert len(p) == 5
- assert p[4] == b'\x00' # like in C, with: char[] p = "abcd";
- #
- p = ffi.new("char[4]", b"ab")
- assert len(p) == 4
- assert [p[i] for i in range(4)] == [b'a', b'b', b'\x00', b'\x00']
- p = ffi.new("char[2]", b"ab")
- assert len(p) == 2
- assert [p[i] for i in range(2)] == [b'a', b'b']
- py.test.raises(IndexError, ffi.new, "char[2]", b"abc")
-
- def check_wchar_t(self, ffi):
- try:
- ffi.cast("wchar_t", 0)
- except NotImplementedError:
- py.test.skip("NotImplementedError: wchar_t")
-
- def test_wchar_t(self):
- ffi = FFI(backend=self.Backend())
- self.check_wchar_t(ffi)
- assert ffi.new("wchar_t*", u+'x')[0] == u+'x'
- assert ffi.new("wchar_t*", u+'\u1234')[0] == u+'\u1234'
- if SIZE_OF_WCHAR > 2:
- assert ffi.new("wchar_t*", u+'\U00012345')[0] == u+'\U00012345'
- else:
- py.test.raises(TypeError, ffi.new, "wchar_t*", u+'\U00012345')
- assert ffi.new("wchar_t*")[0] == u+'\x00'
- assert int(ffi.cast("wchar_t", 300)) == 300
- assert not bool(ffi.cast("wchar_t", 0))
- assert bool(ffi.cast("wchar_t", 1))
- assert bool(ffi.cast("wchar_t", 65535))
- if SIZE_OF_WCHAR > 2:
- assert bool(ffi.cast("wchar_t", 65536))
- py.test.raises(TypeError, ffi.new, "wchar_t*", 32)
- py.test.raises(TypeError, ffi.new, "wchar_t*", "foo")
- #
- p = ffi.new("wchar_t[]", [u+'a', u+'b', u+'\u1234'])
- assert len(p) == 3
- assert p[0] == u+'a'
- assert p[1] == u+'b' and type(p[1]) is unicode
- assert p[2] == u+'\u1234'
- p[0] = u+'x'
- assert p[0] == u+'x' and type(p[0]) is unicode
- p[1] = u+'\u1357'
- assert p[1] == u+'\u1357'
- p = ffi.new("wchar_t[]", u+"abcd")
- assert len(p) == 5
- assert p[4] == u+'\x00'
- p = ffi.new("wchar_t[]", u+"a\u1234b")
- assert len(p) == 4
- assert p[1] == u+'\u1234'
- #
- p = ffi.new("wchar_t[]", u+'\U00023456')
- if SIZE_OF_WCHAR == 2:
- assert len(p) == 3
- assert p[0] == u+'\ud84d'
- assert p[1] == u+'\udc56'
- assert p[2] == u+'\x00'
- else:
- assert len(p) == 2
- assert p[0] == u+'\U00023456'
- assert p[1] == u+'\x00'
- #
- p = ffi.new("wchar_t[4]", u+"ab")
- assert len(p) == 4
- assert [p[i] for i in range(4)] == [u+'a', u+'b', u+'\x00', u+'\x00']
- p = ffi.new("wchar_t[2]", u+"ab")
- assert len(p) == 2
- assert [p[i] for i in range(2)] == [u+'a', u+'b']
- py.test.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc")
-
- def test_none_as_null_doesnt_work(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int*[1]")
- assert p[0] is not None
- assert p[0] != None
- assert p[0] == ffi.NULL
- assert repr(p[0]) == "<cdata 'int *' NULL>"
- #
- n = ffi.new("int*", 99)
- p = ffi.new("int*[]", [n])
- assert p[0][0] == 99
- with pytest.raises(TypeError):
- p[0] = None
- p[0] = ffi.NULL
- assert p[0] == ffi.NULL
-
- def test_float(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("float[]", [-2, -2.5])
- assert p[0] == -2.0
- assert p[1] == -2.5
- p[1] += 17.75
- assert p[1] == 15.25
- #
- p = ffi.new("float*", 15.75)
- assert p[0] == 15.75
- py.test.raises(TypeError, int, p)
- py.test.raises(TypeError, float, p)
- p[0] = 0.0
- assert bool(p) is True
- #
- p = ffi.new("float*", 1.1)
- f = p[0]
- assert f != 1.1 # because of rounding effect
- assert abs(f - 1.1) < 1E-7
- #
- INF = 1E200 * 1E200
- assert 1E200 != INF
- p[0] = 1E200
- assert p[0] == INF # infinite, not enough precision
-
- def test_struct_simple(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a; short b, c; };")
- s = ffi.new("struct foo*")
- assert s.a == s.b == s.c == 0
- s.b = -23
- assert s.b == -23
- with pytest.raises(OverflowError):
- s.b = 32768
- #
- s = ffi.new("struct foo*", [-2, -3])
- assert s.a == -2
- assert s.b == -3
- assert s.c == 0
- with pytest.raises((AttributeError, TypeError)):
- del s.a
- assert repr(s) == "<cdata 'struct foo *' owning %d bytes>" % (
- SIZE_OF_INT + 2 * SIZE_OF_SHORT)
- #
- py.test.raises(ValueError, ffi.new, "struct foo*", [1, 2, 3, 4])
-
- def test_constructor_struct_from_dict(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a; short b, c; };")
- s = ffi.new("struct foo*", {'b': 123, 'c': 456})
- assert s.a == 0
- assert s.b == 123
- assert s.c == 456
- py.test.raises(KeyError, ffi.new, "struct foo*", {'d': 456})
-
- def test_struct_pointer(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a; short b, c; };")
- s = ffi.new("struct foo*")
- assert s[0].a == s[0].b == s[0].c == 0
- s[0].b = -23
- assert s[0].b == s.b == -23
- with pytest.raises(OverflowError):
- s[0].b = -32769
- with pytest.raises(IndexError):
- s[1]
-
- def test_struct_opaque(self):
- ffi = FFI(backend=self.Backend())
- py.test.raises(TypeError, ffi.new, "struct baz*")
- p = ffi.new("struct baz **") # this works
- assert p[0] == ffi.NULL
-
- def test_pointer_to_struct(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a; short b, c; };")
- s = ffi.new("struct foo *")
- s.a = -42
- assert s[0].a == -42
- p = ffi.new("struct foo **", s)
- assert p[0].a == -42
- assert p[0][0].a == -42
- p[0].a = -43
- assert s.a == -43
- assert s[0].a == -43
- p[0][0].a = -44
- assert s.a == -44
- assert s[0].a == -44
- s.a = -45
- assert p[0].a == -45
- assert p[0][0].a == -45
- s[0].a = -46
- assert p[0].a == -46
- assert p[0][0].a == -46
-
- def test_constructor_struct_of_array(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a[2]; char b[3]; };")
- s = ffi.new("struct foo *", [[10, 11], [b'a', b'b', b'c']])
- assert s.a[1] == 11
- assert s.b[2] == b'c'
- s.b[1] = b'X'
- assert s.b[0] == b'a'
- assert s.b[1] == b'X'
- assert s.b[2] == b'c'
-
- def test_recursive_struct(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int value; struct foo *next; };")
- s = ffi.new("struct foo*")
- t = ffi.new("struct foo*")
- s.value = 123
- s.next = t
- t.value = 456
- assert s.value == 123
- assert s.next.value == 456
-
- def test_union_simple(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("union foo { int a; short b, c; };")
- u = ffi.new("union foo*")
- assert u.a == u.b == u.c == 0
- u.b = -23
- assert u.b == -23
- assert u.a != 0
- with pytest.raises(OverflowError):
- u.b = 32768
- #
- u = ffi.new("union foo*", [-2])
- assert u.a == -2
- with pytest.raises((AttributeError, TypeError)):
- del u.a
- assert repr(u) == "<cdata 'union foo *' owning %d bytes>" % SIZE_OF_INT
-
- def test_union_opaque(self):
- ffi = FFI(backend=self.Backend())
- py.test.raises(TypeError, ffi.new, "union baz *")
- u = ffi.new("union baz **") # this works
- assert u[0] == ffi.NULL
-
- def test_union_initializer(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("union foo { char a; int b; };")
- py.test.raises(TypeError, ffi.new, "union foo*", b'A')
- py.test.raises(TypeError, ffi.new, "union foo*", 5)
- py.test.raises(ValueError, ffi.new, "union foo*", [b'A', 5])
- u = ffi.new("union foo*", [b'A'])
- assert u.a == b'A'
- py.test.raises(TypeError, ffi.new, "union foo*", [1005])
- u = ffi.new("union foo*", {'b': 12345})
- assert u.b == 12345
- u = ffi.new("union foo*", [])
- assert u.a == b'\x00'
- assert u.b == 0
-
- def test_sizeof_type(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct foo { int a; short b, c, d; };
- union foo { int a; short b, c, d; };
- """)
- for c_type, expected_size in [
- ('char', 1),
- ('unsigned int', 4),
- ('char *', SIZE_OF_PTR),
- ('int[5]', 20),
- ('struct foo', 12),
- ('union foo', 4),
- ]:
- size = ffi.sizeof(c_type)
- assert size == expected_size, (size, expected_size, ctype)
-
- def test_sizeof_cdata(self):
- ffi = FFI(backend=self.Backend())
- assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR
- assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT
- #
- a = ffi.new("int[]", [10, 11, 12, 13, 14])
- assert len(a) == 5
- assert ffi.sizeof(a) == 5 * SIZE_OF_INT
-
- def test_string_from_char_pointer(self):
- ffi = FFI(backend=self.Backend())
- x = ffi.new("char*", b"x")
- assert str(x) == repr(x)
- assert ffi.string(x) == b"x"
- assert ffi.string(ffi.new("char*", b"\x00")) == b""
- py.test.raises(TypeError, ffi.new, "char*", unicode("foo"))
-
- def test_unicode_from_wchar_pointer(self):
- ffi = FFI(backend=self.Backend())
- self.check_wchar_t(ffi)
- x = ffi.new("wchar_t*", u+"x")
- assert unicode(x) == unicode(repr(x))
- assert ffi.string(x) == u+"x"
- assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+""
-
- def test_string_from_char_array(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("char[]", b"hello.")
- p[5] = b'!'
- assert ffi.string(p) == b"hello!"
- p[6] = b'?'
- assert ffi.string(p) == b"hello!?"
- p[3] = b'\x00'
- assert ffi.string(p) == b"hel"
- assert ffi.string(p, 2) == b"he"
- with pytest.raises(IndexError):
- p[7] = b'X'
- #
- a = ffi.new("char[]", b"hello\x00world")
- assert len(a) == 12
- p = ffi.cast("char *", a)
- assert ffi.string(p) == b'hello'
-
- def test_string_from_wchar_array(self):
- ffi = FFI(backend=self.Backend())
- self.check_wchar_t(ffi)
- assert ffi.string(ffi.cast("wchar_t", "x")) == u+"x"
- assert ffi.string(ffi.cast("wchar_t", u+"x")) == u+"x"
- x = ffi.cast("wchar_t", "x")
- assert str(x) == repr(x)
- assert ffi.string(x) == u+"x"
- #
- p = ffi.new("wchar_t[]", u+"hello.")
- p[5] = u+'!'
- assert ffi.string(p) == u+"hello!"
- p[6] = u+'\u04d2'
- assert ffi.string(p) == u+"hello!\u04d2"
- p[3] = u+'\x00'
- assert ffi.string(p) == u+"hel"
- assert ffi.string(p, 123) == u+"hel"
- with pytest.raises(IndexError):
- p[7] = u+'X'
- #
- a = ffi.new("wchar_t[]", u+"hello\x00world")
- assert len(a) == 12
- p = ffi.cast("wchar_t *", a)
- assert ffi.string(p) == u+'hello'
- assert ffi.string(p, 123) == u+'hello'
- assert ffi.string(p, 5) == u+'hello'
- assert ffi.string(p, 2) == u+'he'
-
- def test_fetch_const_char_p_field(self):
- # 'const' is ignored so far
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { const char *name; };")
- t = ffi.new("const char[]", b"testing")
- s = ffi.new("struct foo*", [t])
- assert type(s.name) not in (bytes, str, unicode)
- assert ffi.string(s.name) == b"testing"
- with pytest.raises(TypeError):
- s.name = None
- s.name = ffi.NULL
- assert s.name == ffi.NULL
-
- def test_fetch_const_wchar_p_field(self):
- # 'const' is ignored so far
- ffi = FFI(backend=self.Backend())
- self.check_wchar_t(ffi)
- ffi.cdef("struct foo { const wchar_t *name; };")
- t = ffi.new("const wchar_t[]", u+"testing")
- s = ffi.new("struct foo*", [t])
- assert type(s.name) not in (bytes, str, unicode)
- assert ffi.string(s.name) == u+"testing"
- s.name = ffi.NULL
- assert s.name == ffi.NULL
-
- def test_voidp(self):
- ffi = FFI(backend=self.Backend())
- py.test.raises(TypeError, ffi.new, "void*")
- p = ffi.new("void **")
- assert p[0] == ffi.NULL
- a = ffi.new("int[]", [10, 11, 12])
- p = ffi.new("void **", a)
- vp = p[0]
- with pytest.raises(TypeError):
- vp[0]
- py.test.raises(TypeError, ffi.new, "short **", a)
- #
- ffi.cdef("struct foo { void *p; int *q; short *r; };")
- s = ffi.new("struct foo *")
- s.p = a # works
- s.q = a # works
- with pytest.raises(TypeError):
- s.r = a # fails
- b = ffi.cast("int *", a)
- s.p = b # works
- s.q = b # works
- with pytest.raises(TypeError):
- s.r = b # fails
-
- def test_functionptr_simple(self):
- ffi = FFI(backend=self.Backend())
- py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0)
- def cb(n):
- return n + 1
- cb.__qualname__ = 'cb'
- p = ffi.callback("int(*)(int)", cb)
- res = p(41) # calling an 'int(*)(int)', i.e. a function pointer
- assert res == 42 and type(res) is int
- res = p(ffi.cast("int", -41))
- assert res == -40 and type(res) is int
- assert repr(p).startswith(
- "<cdata 'int(*)(int)' calling <function cb at 0x")
- assert ffi.typeof(p) is ffi.typeof("int(*)(int)")
- q = ffi.new("int(**)(int)", p)
- assert repr(q) == "<cdata 'int(* *)(int)' owning %d bytes>" % (
- SIZE_OF_PTR)
- with pytest.raises(TypeError):
- q(43)
- res = q[0](43)
- assert res == 44
- q = ffi.cast("int(*)(int)", p)
- assert repr(q).startswith("<cdata 'int(*)(int)' 0x")
- res = q(45)
- assert res == 46
-
- def test_functionptr_advanced(self):
- ffi = FFI(backend=self.Backend())
- t = ffi.typeof("int(*(*)(int))(int)")
- assert repr(t) == self.TypeRepr % "int(*(*)(int))(int)"
-
- def test_functionptr_voidptr_return(self):
- ffi = FFI(backend=self.Backend())
- def cb():
- return ffi.NULL
- p = ffi.callback("void*(*)()", cb)
- res = p()
- assert res is not None
- assert res == ffi.NULL
- int_ptr = ffi.new('int*')
- void_ptr = ffi.cast('void*', int_ptr)
- def cb():
- return void_ptr
- p = ffi.callback("void*(*)()", cb)
- res = p()
- assert res == void_ptr
-
- def test_functionptr_intptr_return(self):
- ffi = FFI(backend=self.Backend())
- def cb():
- return ffi.NULL
- p = ffi.callback("int*(*)()", cb)
- res = p()
- assert res == ffi.NULL
- int_ptr = ffi.new('int*')
- def cb():
- return int_ptr
- p = ffi.callback("int*(*)()", cb)
- res = p()
- assert repr(res).startswith("<cdata 'int *' 0x")
- assert res == int_ptr
- int_array_ptr = ffi.new('int[1]')
- def cb():
- return int_array_ptr
- p = ffi.callback("int*(*)()", cb)
- res = p()
- assert repr(res).startswith("<cdata 'int *' 0x")
- assert res == int_array_ptr
-
- def test_functionptr_void_return(self):
- ffi = FFI(backend=self.Backend())
- def foo():
- pass
- foo_cb = ffi.callback("void foo()", foo)
- result = foo_cb()
- assert result is None
-
- def test_char_cast(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.cast("int", b'\x01')
- assert ffi.typeof(p) is ffi.typeof("int")
- assert int(p) == 1
- p = ffi.cast("int", ffi.cast("char", b"a"))
- assert int(p) == ord("a")
- p = ffi.cast("int", ffi.cast("char", b"\x80"))
- assert int(p) == 0x80 # "char" is considered unsigned in this case
- p = ffi.cast("int", b"\x81")
- assert int(p) == 0x81
-
- def test_wchar_cast(self):
- ffi = FFI(backend=self.Backend())
- self.check_wchar_t(ffi)
- p = ffi.cast("int", ffi.cast("wchar_t", u+'\u1234'))
- assert int(p) == 0x1234
- p = ffi.cast("long long", ffi.cast("wchar_t", -1))
- if SIZE_OF_WCHAR == 2: # 2 bytes, unsigned
- assert int(p) == 0xffff
- 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
-
- def test_cast_array_to_charp(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("short int[]", [0x1234, 0x5678])
- p = ffi.cast("char*", a)
- data = b''.join([p[i] for i in range(4)])
- if sys.byteorder == 'little':
- assert data == b'\x34\x12\x78\x56'
- else:
- assert data == b'\x12\x34\x56\x78'
-
- def test_cast_between_pointers(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("short int[]", [0x1234, 0x5678])
- p = ffi.cast("short*", a)
- p2 = ffi.cast("int*", p)
- q = ffi.cast("char*", p2)
- data = b''.join([q[i] for i in range(4)])
- if sys.byteorder == 'little':
- assert data == b'\x34\x12\x78\x56'
- else:
- assert data == b'\x12\x34\x56\x78'
-
- def test_cast_pointer_and_int(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("short int[]", [0x1234, 0x5678])
- l1 = ffi.cast("intptr_t", a)
- p = ffi.cast("short*", a)
- l2 = ffi.cast("intptr_t", p)
- assert int(l1) == int(l2) != 0
- q = ffi.cast("short*", l1)
- assert q == ffi.cast("short*", int(l1))
- assert q[0] == 0x1234
- assert int(ffi.cast("intptr_t", ffi.NULL)) == 0
-
- def test_cast_functionptr_and_int(self):
- ffi = FFI(backend=self.Backend())
- def cb(n):
- return n + 1
- a = ffi.callback("int(*)(int)", cb)
- p = ffi.cast("void *", a)
- assert p
- b = ffi.cast("int(*)(int)", p)
- assert b(41) == 42
- assert a == b
- assert hash(a) == hash(b)
-
- def test_callback_crash(self):
- ffi = FFI(backend=self.Backend())
- def cb(n):
- raise Exception
- a = ffi.callback("int(*)(int)", cb, error=42)
- res = a(1) # and the error reported to stderr
- assert res == 42
-
- def test_structptr_argument(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int a, b; };")
- def cb(p):
- return p[0].a * 1000 + p[0].b * 100 + p[1].a * 10 + p[1].b
- a = ffi.callback("int(*)(struct foo_s[])", cb)
- res = a([[5, 6], {'a': 7, 'b': 8}])
- assert res == 5678
- res = a([[5], {'b': 8}])
- assert res == 5008
-
- def test_array_argument_as_list(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int a, b; };")
- seen = []
- def cb(argv):
- seen.append(ffi.string(argv[0]))
- seen.append(ffi.string(argv[1]))
- a = ffi.callback("void(*)(char *[])", cb)
- a([ffi.new("char[]", b"foobar"), ffi.new("char[]", b"baz")])
- assert seen == [b"foobar", b"baz"]
-
- def test_cast_float(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.cast("float", 12)
- assert float(a) == 12.0
- a = ffi.cast("float", 12.5)
- assert float(a) == 12.5
- a = ffi.cast("float", b"A")
- assert float(a) == ord("A")
- a = ffi.cast("int", 12.9)
- assert int(a) == 12
- a = ffi.cast("char", 66.9 + 256)
- assert ffi.string(a) == b"B"
- #
- a = ffi.cast("float", ffi.cast("int", 12))
- assert float(a) == 12.0
- a = ffi.cast("float", ffi.cast("double", 12.5))
- assert float(a) == 12.5
- a = ffi.cast("float", ffi.cast("char", b"A"))
- assert float(a) == ord("A")
- a = ffi.cast("int", ffi.cast("double", 12.9))
- assert int(a) == 12
- a = ffi.cast("char", ffi.cast("double", 66.9 + 256))
- assert ffi.string(a) == b"B"
-
- def test_enum(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("enum foo { A0, B0, CC0, D0 };")
- assert ffi.string(ffi.cast("enum foo", 0)) == "A0"
- assert ffi.string(ffi.cast("enum foo", 2)) == "CC0"
- assert ffi.string(ffi.cast("enum foo", 3)) == "D0"
- assert ffi.string(ffi.cast("enum foo", 4)) == "4"
- ffi.cdef("enum bar { A1, B1=-2, CC1, D1, E1 };")
- assert ffi.string(ffi.cast("enum bar", 0)) == "A1"
- assert ffi.string(ffi.cast("enum bar", -2)) == "B1"
- assert ffi.string(ffi.cast("enum bar", -1)) == "CC1"
- assert ffi.string(ffi.cast("enum bar", 1)) == "E1"
- assert ffi.cast("enum bar", -2) == ffi.cast("enum bar", -2)
- assert ffi.cast("enum foo", 0) == ffi.cast("enum bar", 0)
- assert ffi.cast("enum bar", 0) == ffi.cast("int", 0)
- assert repr(ffi.cast("enum bar", -1)) == "<cdata 'enum bar' -1: CC1>"
- assert repr(ffi.cast("enum foo", -1)) == ( # enums are unsigned, if
- "<cdata 'enum foo' 4294967295>") # they contain no neg value
- ffi.cdef("enum baz { A2=0x1000, B2=0x2000 };")
- assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2"
- assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2"
-
- def test_enum_in_struct(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("enum foo { A, B, C, D }; struct bar { enum foo e; };")
- s = ffi.new("struct bar *")
- s.e = 0
- assert s.e == 0
- s.e = 3
- assert s.e == 3
- assert s[0].e == 3
- s[0].e = 2
- assert s.e == 2
- assert s[0].e == 2
- s.e = ffi.cast("enum foo", -1)
- assert s.e == 4294967295
- assert s[0].e == 4294967295
- s.e = s.e
- with pytest.raises(TypeError):
- s.e = 'B'
- with pytest.raises(TypeError):
- s.e = '2'
- with pytest.raises(TypeError):
- s.e = '#2'
- with pytest.raises(TypeError):
- s.e = '#7'
-
- def test_enum_non_contiguous(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("enum foo { A, B=42, C };")
- assert ffi.string(ffi.cast("enum foo", 0)) == "A"
- assert ffi.string(ffi.cast("enum foo", 42)) == "B"
- assert ffi.string(ffi.cast("enum foo", 43)) == "C"
- invalid_value = ffi.cast("enum foo", 2)
- assert int(invalid_value) == 2
- assert ffi.string(invalid_value) == "2"
-
- def test_enum_char_hex_oct(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef(r"enum foo{A='!', B='\'', C=0x10, D=010, E=- 0x10, F=-010};")
- assert ffi.string(ffi.cast("enum foo", ord('!'))) == "A"
- assert ffi.string(ffi.cast("enum foo", ord("'"))) == "B"
- assert ffi.string(ffi.cast("enum foo", 16)) == "C"
- assert ffi.string(ffi.cast("enum foo", 8)) == "D"
- assert ffi.string(ffi.cast("enum foo", -16)) == "E"
- assert ffi.string(ffi.cast("enum foo", -8)) == "F"
-
- def test_enum_partial(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };")
- needs_dlopen_none()
- lib = ffi.dlopen(None)
- assert lib.B == 0
- py.test.raises(VerificationMissing, getattr, lib, "A")
- assert lib.C == 1
-
- def test_array_of_struct(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a, b; };")
- s = ffi.new("struct foo[1]")
- with pytest.raises(AttributeError):
- s.b
- with pytest.raises(AttributeError):
- s.b = 412
- s[0].b = 412
- assert s[0].b == 412
- with pytest.raises(IndexError):
- s[1]
-
- def test_pointer_to_array(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int(**)[5]")
- assert repr(p) == "<cdata 'int(* *)[5]' owning %d bytes>" % SIZE_OF_PTR
-
- def test_iterate_array(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("char[]", b"hello")
- assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
- assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
- #
- py.test.raises(TypeError, iter, ffi.cast("char *", a))
- py.test.raises(TypeError, list, ffi.cast("char *", a))
- py.test.raises(TypeError, iter, ffi.new("int *"))
- py.test.raises(TypeError, list, ffi.new("int *"))
-
- def test_offsetof(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a, b, c; };")
- assert ffi.offsetof("struct foo", "a") == 0
- assert ffi.offsetof("struct foo", "b") == 4
- assert ffi.offsetof("struct foo", "c") == 8
-
- def test_offsetof_nested(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a, b, c; };"
- "struct bar { struct foo d, e; };")
- assert ffi.offsetof("struct bar", "e") == 12
- py.test.raises(KeyError, ffi.offsetof, "struct bar", "e.a")
- assert ffi.offsetof("struct bar", "e", "a") == 12
- assert ffi.offsetof("struct bar", "e", "b") == 16
- assert ffi.offsetof("struct bar", "e", "c") == 20
-
- def test_offsetof_array(self):
- ffi = FFI(backend=self.Backend())
- assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int")
- assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int")
- ffi.cdef("struct bar { int a, b; int c[99]; };")
- assert ffi.offsetof("struct bar", "c") == 2 * ffi.sizeof("int")
- assert ffi.offsetof("struct bar", "c", 0) == 2 * ffi.sizeof("int")
- assert ffi.offsetof("struct bar", "c", 51) == 53 * ffi.sizeof("int")
-
- def test_alignof(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { char a; short b; char c; };")
- assert ffi.alignof("int") == 4
- assert ffi.alignof("double") in (4, 8)
- assert ffi.alignof("struct foo") == 2
-
- def test_bitfield(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo { int a:10, b:20, c:3; };")
- assert ffi.sizeof("struct foo") == 8
- s = ffi.new("struct foo *")
- s.a = 511
- with pytest.raises(OverflowError):
- s.a = 512
- with pytest.raises(OverflowError):
- s[0].a = 512
- assert s.a == 511
- s.a = -512
- with pytest.raises(OverflowError):
- s.a = -513
- with pytest.raises(OverflowError):
- s[0].a = -513
- assert s.a == -512
- s.c = 3
- assert s.c == 3
- with pytest.raises(OverflowError):
- s.c = 4
- with pytest.raises(OverflowError):
- s[0].c = 4
- s.c = -4
- assert s.c == -4
-
- def test_bitfield_enum(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- typedef enum { AA, BB, CC } foo_e;
- typedef struct { foo_e f:2; } foo_s;
- """)
- s = ffi.new("foo_s *")
- s.f = 2
- assert s.f == 2
-
- def test_anonymous_struct(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("typedef struct { int a; } foo_t;")
- ffi.cdef("typedef struct { char b, c; } bar_t;")
- f = ffi.new("foo_t *", [12345])
- b = ffi.new("bar_t *", [b"B", b"C"])
- assert f.a == 12345
- assert b.b == b"B"
- assert b.c == b"C"
- assert repr(b).startswith("<cdata 'bar_t *'")
-
- def test_struct_with_two_usages(self):
- for name in ['foo_s', '']: # anonymous or not
- ffi = FFI(backend=self.Backend())
- ffi.cdef("typedef struct %s { int a; } foo_t, *foo_p;" % name)
- f = ffi.new("foo_t *", [12345])
- ps = ffi.new("foo_p[]", [f])
-
- def test_pointer_arithmetic(self):
- ffi = FFI(backend=self.Backend())
- s = ffi.new("short[]", list(range(100, 110)))
- p = ffi.cast("short *", s)
- assert p[2] == 102
- assert p+1 == p+1
- assert p+1 != p+0
- assert p == p+0 == p-0
- assert (p+1)[0] == 101
- assert (p+19)[-10] == 109
- assert (p+5) - (p+1) == 4
- assert p == s+0
- assert p+1 == s+1
-
- def test_pointer_comparison(self):
- ffi = FFI(backend=self.Backend())
- s = ffi.new("short[]", list(range(100)))
- p = ffi.cast("short *", s)
- assert (p < s) is False
- assert (p <= s) is True
- assert (p == s) is True
- assert (p != s) is False
- assert (p > s) is False
- assert (p >= s) is True
- assert (s < p) is False
- assert (s <= p) is True
- assert (s == p) is True
- assert (s != p) is False
- assert (s > p) is False
- assert (s >= p) is True
- q = p + 1
- assert (q < s) is False
- assert (q <= s) is False
- assert (q == s) is False
- assert (q != s) is True
- assert (q > s) is True
- assert (q >= s) is True
- assert (s < q) is True
- assert (s <= q) is True
- assert (s == q) is False
- assert (s != q) is True
- assert (s > q) is False
- assert (s >= q) is False
- assert (q < p) is False
- assert (q <= p) is False
- assert (q == p) is False
- assert (q != p) is True
- assert (q > p) is True
- assert (q >= p) is True
- assert (p < q) is True
- assert (p <= q) is True
- assert (p == q) is False
- assert (p != q) is True
- assert (p > q) is False
- assert (p >= q) is False
- #
- assert (None == s) is False
- assert (None != s) is True
- assert (s == None) is False
- assert (s != None) is True
- assert (None == q) is False
- assert (None != q) is True
- assert (q == None) is False
- assert (q != None) is True
-
- def test_integer_comparison(self):
- ffi = FFI(backend=self.Backend())
- x = ffi.cast("int", 123)
- y = ffi.cast("int", 456)
- assert x < y
- #
- z = ffi.cast("double", 78.9)
- assert x > z
- assert y > z
-
- def test_ffi_buffer_ptr(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("short *", 100)
- try:
- b = ffi.buffer(a)
- except NotImplementedError as e:
- py.test.skip(str(e))
- assert type(b) is ffi.buffer
- content = b[:]
- assert len(content) == len(b) == 2
- if sys.byteorder == 'little':
- assert content == b'\x64\x00'
- assert b[0] == b'\x64'
- b[0] = b'\x65'
- else:
- assert content == b'\x00\x64'
- assert b[1] == b'\x64'
- b[1] = b'\x65'
- assert a[0] == 101
-
- def test_ffi_buffer_array(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("int[]", list(range(100, 110)))
- try:
- b = ffi.buffer(a)
- except NotImplementedError as e:
- py.test.skip(str(e))
- content = b[:]
- if sys.byteorder == 'little':
- assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00')
- b[4] = b'\x45'
- else:
- assert content.startswith(b'\x00\x00\x00\x64\x00\x00\x00\x65')
- b[7] = b'\x45'
- assert len(content) == 4 * 10
- assert a[1] == 0x45
-
- def test_ffi_buffer_ptr_size(self):
- ffi = FFI(backend=self.Backend())
- a = ffi.new("short *", 0x4243)
- try:
- b = ffi.buffer(a, 1)
- except NotImplementedError as e:
- py.test.skip(str(e))
- content = b[:]
- assert len(content) == 1
- if sys.byteorder == 'little':
- assert content == b'\x43'
- b[0] = b'\x62'
- assert a[0] == 0x4262
- else:
- assert content == b'\x42'
- b[0] = b'\x63'
- assert a[0] == 0x6343
-
- def test_ffi_buffer_array_size(self):
- ffi = FFI(backend=self.Backend())
- a1 = ffi.new("int[]", list(range(100, 110)))
- a2 = ffi.new("int[]", list(range(100, 115)))
- try:
- ffi.buffer(a1)
- except NotImplementedError as e:
- py.test.skip(str(e))
- assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:]
-
- def test_ffi_buffer_with_file(self):
- ffi = FFI(backend=self.Backend())
- import tempfile, os, array
- fd, filename = tempfile.mkstemp()
- f = os.fdopen(fd, 'r+b')
- a = ffi.new("int[]", list(range(1005)))
- try:
- ffi.buffer(a, 512)
- except NotImplementedError as e:
- py.test.skip(str(e))
- f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
- f.seek(0)
- assert f.read() == arraytostring(array.array('i', range(1000)))
- f.seek(0)
- b = ffi.new("int[]", 1005)
- f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
- assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
- f.close()
- os.unlink(filename)
-
- def test_ffi_buffer_with_io(self):
- ffi = FFI(backend=self.Backend())
- import io, array
- f = io.BytesIO()
- a = ffi.new("int[]", list(range(1005)))
- try:
- ffi.buffer(a, 512)
- except NotImplementedError as e:
- py.test.skip(str(e))
- f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
- f.seek(0)
- assert f.read() == arraytostring(array.array('i', range(1000)))
- f.seek(0)
- b = ffi.new("int[]", 1005)
- f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
- assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
- f.close()
-
- def test_ffi_buffer_comparisons(self):
- ffi = FFI(backend=self.Backend())
- ba = bytearray(range(100, 110))
- if sys.version_info >= (2, 7):
- assert ba == memoryview(ba) # justification for the following
- a = ffi.new("uint8_t[]", list(ba))
- c = ffi.new("uint8_t[]", [99] + list(ba))
- try:
- b_full = ffi.buffer(a)
- b_short = ffi.buffer(a, 3)
- b_mid = ffi.buffer(a, 6)
- b_other = ffi.buffer(c, 6)
- except NotImplementedError as e:
- py.test.skip(str(e))
- else:
- content = b_full[:]
- assert content == b_full == ba
- assert b_other < b_short < b_mid < b_full
- assert ba > b_mid > ba[0:2]
- assert b_short != ba[1:4]
-
- def test_array_in_struct(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int len; short data[5]; };")
- p = ffi.new("struct foo_s *")
- p.data[3] = 5
- assert p.data[3] == 5
- assert repr(p.data).startswith("<cdata 'short[5]' 0x")
-
- def test_struct_containing_array_varsize_workaround(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int len; short data[0]; };")
- p = ffi.new("char[]", ffi.sizeof("struct foo_s") + 7 * SIZE_OF_SHORT)
- q = ffi.cast("struct foo_s *", p)
- assert q.len == 0
- # 'q.data' gets not a 'short[0]', but just a 'short *' instead
- assert repr(q.data).startswith("<cdata 'short *' 0x")
- assert q.data[6] == 0
- q.data[6] = 15
- assert q.data[6] == 15
-
- def test_new_struct_containing_array_varsize(self):
- py.test.skip("later?")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int len; short data[]; };")
- p = ffi.new("struct foo_s *", 10) # a single integer is the length
- assert p.len == 0
- assert p.data[9] == 0
- with pytest.raises(IndexError):
- p.data[10]
-
- def test_ffi_typeof_getcname(self):
- ffi = FFI(backend=self.Backend())
- assert ffi.getctype("int") == "int"
- assert ffi.getctype("int", 'x') == "int x"
- assert ffi.getctype("int*") == "int *"
- assert ffi.getctype("int*", '') == "int *"
- assert ffi.getctype("int*", 'x') == "int * x"
- assert ffi.getctype("int", '*') == "int *"
- assert ffi.getctype("int", ' * x ') == "int * x"
- assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *"
- assert ffi.getctype("int", '[5]') == "int[5]"
- assert ffi.getctype("int[5]", '[6]') == "int[6][5]"
- assert ffi.getctype("int[5]", '(*)') == "int(*)[5]"
- # special-case for convenience: automatically put '()' around '*'
- assert ffi.getctype("int[5]", '*') == "int(*)[5]"
- assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]"
- assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"
-
- def test_array_of_func_ptr(self):
- ffi = FFI(backend=self.Backend())
- f = ffi.cast("int(*)(int)", 42)
- assert f != ffi.NULL
- py.test.raises(CDefError, ffi.cast, "int(int)", 42)
- py.test.raises(CDefError, ffi.new, "int([5])(int)")
- a = ffi.new("int(*[5])(int)", [f])
- assert ffi.getctype(ffi.typeof(a)) == "int(*[5])(int)"
- assert len(a) == 5
- assert a[0] == f
- assert a[1] == ffi.NULL
- py.test.raises(TypeError, ffi.cast, "int(*)(int)[5]", 0)
- #
- def cb(n):
- return n + 1
- f = ffi.callback("int(*)(int)", cb)
- a = ffi.new("int(*[5])(int)", [f, f])
- assert a[1](42) == 43
-
- def test_callback_as_function_argument(self):
- # In C, function arguments can be declared with a function type,
- # which is automatically replaced with the ptr-to-function type.
- ffi = FFI(backend=self.Backend())
- def cb(a, b):
- return chr(ord(a) + ord(b)).encode()
- f = ffi.callback("char cb(char, char)", cb)
- assert f(b'A', b'\x01') == b'B'
- def g(callback):
- return callback(b'A', b'\x01')
- g = ffi.callback("char g(char cb(char, char))", g)
- assert g(f) == b'B'
-
- def test_vararg_callback(self):
- py.test.skip("callback with '...'")
- ffi = FFI(backend=self.Backend())
- def cb(i, va_list):
- j = ffi.va_arg(va_list, "int")
- k = ffi.va_arg(va_list, "long long")
- return i * 2 + j * 3 + k * 5
- f = ffi.callback("long long cb(long i, ...)", cb)
- res = f(10, ffi.cast("int", 100), ffi.cast("long long", 1000))
- assert res == 20 + 300 + 5000
-
- def test_callback_decorator(self):
- ffi = FFI(backend=self.Backend())
- #
- @ffi.callback("long(long, long)", error=42)
- def cb(a, b):
- return a - b
- #
- assert cb(-100, -10) == -90
- sz = ffi.sizeof("long")
- assert cb((1 << (sz*8-1)) - 1, -10) == 42
-
- def test_unique_types(self):
- ffi1 = FFI(backend=self.Backend())
- ffi2 = FFI(backend=self.Backend())
- assert ffi1.typeof("char") is ffi2.typeof("char ")
- assert ffi1.typeof("long") is ffi2.typeof("signed long int")
- assert ffi1.typeof("double *") is ffi2.typeof("double*")
- assert ffi1.typeof("int ***") is ffi2.typeof(" int * * *")
- assert ffi1.typeof("int[]") is ffi2.typeof("signed int[]")
- assert ffi1.typeof("signed int*[17]") is ffi2.typeof("int *[17]")
- assert ffi1.typeof("void") is ffi2.typeof("void")
- assert ffi1.typeof("int(*)(int,int)") is ffi2.typeof("int(*)(int,int)")
- #
- # 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*")
- # 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 *")
-
- def test_anonymous_enum(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("typedef enum { Value0 = 0 } e, *pe;\n"
- "typedef enum { Value1 = 1 } e1;")
- assert ffi.getctype("e*") == 'e *'
- assert ffi.getctype("pe") == 'e *'
- assert ffi.getctype("e1*") == 'e1 *'
-
- def test_opaque_enum(self):
- import warnings
- ffi = FFI(backend=self.Backend())
- ffi.cdef("enum foo;")
- with warnings.catch_warnings(record=True) as log:
- warnings.simplefilter("always")
- n = ffi.cast("enum foo", -1)
- assert int(n) == 0xffffffff
- assert str(log[0].message) == (
- "'enum foo' has no values explicitly defined; "
- "guessing that it is equivalent to 'unsigned int'")
-
- def test_new_ctype(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int *")
- py.test.raises(TypeError, ffi.new, p)
- p = ffi.new(ffi.typeof("int *"), 42)
- assert p[0] == 42
-
- def test_enum_with_non_injective_mapping(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("enum e { AA=0, BB=0, CC=0, DD=0 };")
- e = ffi.cast("enum e", 0)
- assert ffi.string(e) == "AA" # pick the first one arbitrarily
-
- def test_enum_refer_previous_enum_value(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("enum e { AA, BB=2, CC=4, DD=BB, EE, FF=CC, GG=FF };")
- assert ffi.string(ffi.cast("enum e", 2)) == "BB"
- assert ffi.string(ffi.cast("enum e", 3)) == "EE"
- assert ffi.sizeof("char[DD]") == 2
- assert ffi.sizeof("char[EE]") == 3
- assert ffi.sizeof("char[FF]") == 4
- assert ffi.sizeof("char[GG]") == 4
-
- def test_nested_anonymous_struct(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct foo_s {
- struct { int a, b; };
- union { int c, d; };
- };
- """)
- assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
- p = ffi.new("struct foo_s *", [1, 2, 3])
- assert p.a == 1
- assert p.b == 2
- assert p.c == 3
- assert p.d == 3
- p.d = 17
- assert p.c == 17
- p.b = 19
- assert p.a == 1
- assert p.b == 19
- assert p.c == 17
- assert p.d == 17
- p = ffi.new("struct foo_s *", {'b': 12, 'd': 14})
- assert p.a == 0
- assert p.b == 12
- assert p.c == 14
- assert p.d == 14
- py.test.raises(ValueError, ffi.new, "struct foo_s *", [0, 0, 0, 0])
-
- def test_nested_field_offset_align(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct foo_s {
- struct { int a; char b; };
- union { char c; };
- };
- """)
- assert ffi.offsetof("struct foo_s", "c") == 2 * SIZE_OF_INT
- assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
-
- def test_nested_anonymous_union(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- union foo_u {
- struct { int a, b; };
- union { int c, d; };
- };
- """)
- assert ffi.sizeof("union foo_u") == 2 * SIZE_OF_INT
- p = ffi.new("union foo_u *", [5])
- assert p.a == 5
- assert p.b == 0
- assert p.c == 5
- assert p.d == 5
- p.d = 17
- assert p.c == 17
- assert p.a == 17
- p.b = 19
- assert p.a == 17
- assert p.b == 19
- assert p.c == 17
- assert p.d == 17
- p = ffi.new("union foo_u *", {'d': 14})
- assert p.a == 14
- assert p.b == 0
- assert p.c == 14
- assert p.d == 14
- p = ffi.new("union foo_u *", {'a': -63, 'b': 12})
- assert p.a == -63
- assert p.b == 12
- assert p.c == -63
- assert p.d == -63
- p = ffi.new("union foo_u *", [123, 456])
- assert p.a == 123
- assert p.b == 456
- assert p.c == 123
- assert p.d == 123
- py.test.raises(ValueError, ffi.new, "union foo_u *", [0, 0, 0])
-
- def test_nested_anonymous_struct_2(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct foo_s {
- int a;
- union { int b; union { int c, d; }; };
- int e;
- };
- """)
- assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
- p = ffi.new("struct foo_s *", [11, 22, 33])
- assert p.a == 11
- assert p.b == p.c == p.d == 22
- assert p.e == 33
- py.test.raises(ValueError, ffi.new, "struct foo_s *", [11, 22, 33, 44])
- FOO = ffi.typeof("struct foo_s")
- fields = [(name, fld.offset, fld.flags) for (name, fld) in FOO.fields]
- assert fields == [
- ('a', 0 * SIZE_OF_INT, 0),
- ('b', 1 * SIZE_OF_INT, 0),
- ('c', 1 * SIZE_OF_INT, 1),
- ('d', 1 * SIZE_OF_INT, 1),
- ('e', 2 * SIZE_OF_INT, 0),
- ]
-
- def test_cast_to_array_type(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int[4]", [-5])
- q = ffi.cast("int[3]", p)
- assert q[0] == -5
- assert repr(q).startswith("<cdata 'int[3]' 0x")
-
- def test_gc(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int *", 123)
- seen = []
- def destructor(p1):
- assert p1 is p
- assert p1[0] == 123
- seen.append(1)
- q = ffi.gc(p, destructor)
- assert ffi.typeof(q) is ffi.typeof(p)
- import gc; gc.collect()
- assert seen == []
- del q
- import gc; gc.collect(); gc.collect(); gc.collect()
- assert seen == [1]
-
- def test_gc_2(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int *", 123)
- seen = []
- q1 = ffi.gc(p, lambda p: seen.append(1))
- q2 = ffi.gc(q1, lambda p: seen.append(2))
- import gc; gc.collect()
- assert seen == []
- del q1, q2
- import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
- assert seen == [2, 1]
-
- def test_gc_3(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int *", 123)
- r = ffi.new("int *", 123)
- seen = []
- seen_r = []
- q1 = ffi.gc(p, lambda p: seen.append(1))
- s1 = ffi.gc(r, lambda r: seen_r.append(4))
- q2 = ffi.gc(q1, lambda p: seen.append(2))
- s2 = ffi.gc(s1, lambda r: seen_r.append(5))
- q3 = ffi.gc(q2, lambda p: seen.append(3))
- import gc; gc.collect()
- assert seen == []
- assert seen_r == []
- del q1, q2, q3, s2, s1
- import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
- assert seen == [3, 2, 1]
- assert seen_r == [5, 4]
-
- def test_gc_4(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int *", 123)
- seen = []
- q1 = ffi.gc(p, lambda p: seen.append(1))
- q2 = ffi.gc(q1, lambda p: seen.append(2))
- q3 = ffi.gc(q2, lambda p: seen.append(3))
- import gc; gc.collect()
- assert seen == []
- del q1, q3 # q2 remains, and has a hard ref to q1
- import gc; gc.collect(); gc.collect(); gc.collect()
- assert seen == [3]
-
- def test_gc_disable(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int *", 123)
- py.test.raises(TypeError, ffi.gc, p, None)
- seen = []
- q1 = ffi.gc(p, lambda p: seen.append(1))
- q2 = ffi.gc(q1, lambda p: seen.append(2))
- import gc; gc.collect()
- assert seen == []
- assert ffi.gc(q1, None) is None
- del q1, q2
- import gc; gc.collect(); gc.collect(); gc.collect()
- assert seen == [2]
-
- def test_gc_finite_list(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int *", 123)
- keepalive = []
- for i in range(10):
- keepalive.append(ffi.gc(p, lambda p: None))
- del keepalive[:]
- import gc; gc.collect(); gc.collect()
- for i in range(10):
- keepalive.append(ffi.gc(p, lambda p: None))
-
- def test_CData_CType(self):
- ffi = FFI(backend=self.Backend())
- assert isinstance(ffi.cast("int", 0), ffi.CData)
- assert isinstance(ffi.new("int *"), ffi.CData)
- assert not isinstance(ffi.typeof("int"), ffi.CData)
- assert not isinstance(ffi.cast("int", 0), ffi.CType)
- assert not isinstance(ffi.new("int *"), ffi.CType)
-
- def test_CData_CType_2(self):
- ffi = FFI(backend=self.Backend())
- assert isinstance(ffi.typeof("int"), ffi.CType)
-
- def test_bool(self):
- ffi = FFI(backend=self.Backend())
- assert int(ffi.cast("_Bool", 0.1)) == 1
- assert int(ffi.cast("_Bool", -0.0)) == 0
- assert int(ffi.cast("_Bool", b'\x02')) == 1
- assert int(ffi.cast("_Bool", b'\x00')) == 0
- assert int(ffi.cast("_Bool", b'\x80')) == 1
- assert ffi.new("_Bool *", False)[0] == 0
- assert ffi.new("_Bool *", 1)[0] == 1
- py.test.raises(OverflowError, ffi.new, "_Bool *", 2)
- py.test.raises(TypeError, ffi.string, ffi.cast("_Bool", 2))
-
- def test_use_own_bool(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""typedef int bool;""")
-
- def test_ordering_bug1(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct foo_s {
- struct bar_s *p;
- };
- struct bar_s {
- struct foo_s foo;
- };
- """)
- q = ffi.new("struct foo_s *")
- bar = ffi.new("struct bar_s *")
- q.p = bar
- assert q.p.foo.p == ffi.NULL
-
- def test_ordering_bug2(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct bar_s;
-
- struct foo_s {
- void (*foo)(struct bar_s[]);
- };
-
- struct bar_s {
- struct foo_s foo;
- };
- """)
- q = ffi.new("struct foo_s *")
-
- def test_addressof(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int x, y; };")
- p = ffi.new("struct foo_s *")
- a = ffi.addressof(p[0])
- assert repr(a).startswith("<cdata 'struct foo_s *' 0x")
- assert a == p
- py.test.raises(TypeError, ffi.addressof, p)
- py.test.raises((AttributeError, TypeError), ffi.addressof, 5)
- py.test.raises(TypeError, ffi.addressof, ffi.cast("int", 5))
-
- def test_addressof_field(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int x, y; };")
- p = ffi.new("struct foo_s *")
- a = ffi.addressof(p[0], 'y')
- assert repr(a).startswith("<cdata 'int *' 0x")
- assert int(ffi.cast("uintptr_t", a)) == (
- int(ffi.cast("uintptr_t", p)) + ffi.sizeof("int"))
- assert a == ffi.addressof(p, 'y')
- assert a != ffi.addressof(p, 'x')
-
- def test_addressof_field_nested(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int x, y; };"
- "struct bar_s { struct foo_s a, b; };")
- p = ffi.new("struct bar_s *")
- py.test.raises(KeyError, ffi.addressof, p[0], 'b.y')
- a = ffi.addressof(p[0], 'b', 'y')
- assert int(ffi.cast("uintptr_t", a)) == (
- int(ffi.cast("uintptr_t", p)) +
- ffi.sizeof("struct foo_s") + ffi.sizeof("int"))
-
- def test_addressof_anonymous_struct(self):
- ffi = FFI()
- ffi.cdef("typedef struct { int x; } foo_t;")
- p = ffi.new("foo_t *")
- a = ffi.addressof(p[0])
- assert a == p
-
- def test_addressof_array(self):
- ffi = FFI()
- p = ffi.new("int[52]")
- p0 = ffi.addressof(p)
- assert p0 == p
- assert ffi.typeof(p0) is ffi.typeof("int(*)[52]")
- py.test.raises(TypeError, ffi.addressof, p0)
- #
- p1 = ffi.addressof(p, 25)
- assert ffi.typeof(p1) is ffi.typeof("int *")
- assert (p1 - p) == 25
- assert ffi.addressof(p, 0) == p
-
- def test_addressof_pointer(self):
- ffi = FFI()
- array = ffi.new("int[50]")
- p = ffi.cast("int *", array)
- py.test.raises(TypeError, ffi.addressof, p)
- assert ffi.addressof(p, 0) == p
- assert ffi.addressof(p, 25) == p + 25
- assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)
- #
- ffi.cdef("struct foo { int a, b; };")
- array = ffi.new("struct foo[50]")
- p = ffi.cast("int *", array)
- py.test.raises(TypeError, ffi.addressof, p)
- assert ffi.addressof(p, 0) == p
- assert ffi.addressof(p, 25) == p + 25
- assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)
-
- def test_addressof_array_in_struct(self):
- ffi = FFI()
- ffi.cdef("struct foo { int a, b; int c[50]; };")
- p = ffi.new("struct foo *")
- p1 = ffi.addressof(p, "c", 25)
- assert ffi.typeof(p1) is ffi.typeof("int *")
- assert p1 == ffi.cast("int *", p) + 27
- assert ffi.addressof(p, "c") == ffi.cast("int *", p) + 2
- assert ffi.addressof(p, "c", 0) == ffi.cast("int *", p) + 2
- p2 = ffi.addressof(p, 1)
- assert ffi.typeof(p2) is ffi.typeof("struct foo *")
- assert p2 == p + 1
-
- def test_multiple_independent_structs(self):
- ffi1 = FFI(); ffi1.cdef("struct foo { int x; };")
- ffi2 = FFI(); ffi2.cdef("struct foo { int y, z; };")
- foo1 = ffi1.new("struct foo *", [10])
- foo2 = ffi2.new("struct foo *", [20, 30])
- assert foo1.x == 10
- assert foo2.y == 20
- assert foo2.z == 30
-
- def test_missing_include(self):
- backend = self.Backend()
- ffi1 = FFI(backend=backend)
- ffi2 = FFI(backend=backend)
- ffi1.cdef("typedef signed char schar_t;")
- py.test.raises(CDefError, ffi2.cast, "schar_t", 142)
-
- def test_include_typedef(self):
- backend = self.Backend()
- ffi1 = FFI(backend=backend)
- ffi2 = FFI(backend=backend)
- ffi1.cdef("typedef signed char schar_t;")
- ffi2.include(ffi1)
- p = ffi2.cast("schar_t", 142)
- assert int(p) == 142 - 256
-
- def test_include_struct(self):
- backend = self.Backend()
- ffi1 = FFI(backend=backend)
- ffi2 = FFI(backend=backend)
- ffi1.cdef("struct foo { int x; };")
- ffi2.include(ffi1)
- p = ffi2.new("struct foo *", [142])
- assert p.x == 142
-
- def test_include_union(self):
- backend = self.Backend()
- ffi1 = FFI(backend=backend)
- ffi2 = FFI(backend=backend)
- ffi1.cdef("union foo { int x; };")
- ffi2.include(ffi1)
- p = ffi2.new("union foo *", [142])
- assert p.x == 142
-
- def test_include_enum(self):
- backend = self.Backend()
- ffi1 = FFI(backend=backend)
- ffi2 = FFI(backend=backend)
- ffi1.cdef("enum foo { FA, FB, FC };")
- ffi2.include(ffi1)
- p = ffi2.cast("enum foo", 1)
- assert ffi2.string(p) == "FB"
- assert ffi2.sizeof("char[FC]") == 2
-
- def test_include_typedef_2(self):
- backend = self.Backend()
- ffi1 = FFI(backend=backend)
- ffi2 = FFI(backend=backend)
- ffi1.cdef("typedef struct { int x; } *foo_p;")
- ffi2.include(ffi1)
- p = ffi2.new("foo_p", [142])
- assert p.x == 142
-
- def test_ignore_multiple_declarations_of_constant(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("#define FOO 42")
- ffi.cdef("#define FOO 42")
- py.test.raises(FFIError, ffi.cdef, "#define FOO 43")
-
- def test_struct_packed(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct nonpacked { char a; int b; };")
- ffi.cdef("struct is_packed { char a; int b; };", packed=True)
- ffi.cdef("struct is_packed1 { char a; int b; };", pack=1)
- ffi.cdef("struct is_packed2 { char a; int b; };", pack=2)
- ffi.cdef("struct is_packed4 { char a; int b; };", pack=4)
- ffi.cdef("struct is_packed8 { char a; int b; };", pack=8)
- assert ffi.sizeof("struct nonpacked") == 8
- assert ffi.sizeof("struct is_packed") == 5
- assert ffi.sizeof("struct is_packed1") == 5
- assert ffi.sizeof("struct is_packed2") == 6
- assert ffi.sizeof("struct is_packed4") == 8
- assert ffi.sizeof("struct is_packed8") == 8
- assert ffi.alignof("struct nonpacked") == 4
- assert ffi.alignof("struct is_packed") == 1
- assert ffi.alignof("struct is_packed1") == 1
- assert ffi.alignof("struct is_packed2") == 2
- assert ffi.alignof("struct is_packed4") == 4
- assert ffi.alignof("struct is_packed8") == 4
- for name in ['is_packed', 'is_packed1', 'is_packed2',
- 'is_packed4', 'is_packed8']:
- s = ffi.new("struct %s[2]" % name)
- s[0].b = 42623381
- s[0].a = b'X'
- s[1].b = -4892220
- s[1].a = b'Y'
- assert s[0].b == 42623381
- assert s[0].a == b'X'
- assert s[1].b == -4892220
- assert s[1].a == b'Y'
-
- def test_pack_valueerror(self):
- ffi = FFI(backend=self.Backend())
- py.test.raises(ValueError, ffi.cdef, "", pack=3)
- py.test.raises(ValueError, ffi.cdef, "", packed=2)
- py.test.raises(ValueError, ffi.cdef, "", packed=True, pack=1)
-
- def test_define_integer_constant(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- #define DOT_0 0
- #define DOT 100
- #define DOT_OCT 0100l
- #define DOT_HEX 0x100u
- #define DOT_HEX2 0X10
- #define DOT_UL 1000UL
- enum foo {AA, BB=DOT, CC};
- """)
- needs_dlopen_none()
- lib = ffi.dlopen(None)
- assert ffi.string(ffi.cast("enum foo", 100)) == "BB"
- assert lib.DOT_0 == 0
- assert lib.DOT == 100
- assert lib.DOT_OCT == 0o100
- assert lib.DOT_HEX == 0x100
- assert lib.DOT_HEX2 == 0x10
- assert lib.DOT_UL == 1000
-
- def test_opaque_struct_becomes_nonopaque(self):
- # Issue #193: if we use a struct between the first cdef() where it is
- # declared and another cdef() where its fields are defined, then the
- # definition was ignored.
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s;")
- py.test.raises(TypeError, ffi.new, "struct foo_s *")
- ffi.cdef("struct foo_s { int x; };")
- ffi.new("struct foo_s *")
-
- def test_ffi_self_include(self):
- ffi = FFI(backend=self.Backend())
- py.test.raises(ValueError, ffi.include, ffi)
-
- def test_anonymous_enum_include(self):
- ffi1 = FFI()
- ffi1.cdef("enum { EE1 };")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("enum { EE2, EE3 };")
- needs_dlopen_none()
- lib = ffi.dlopen(None)
- assert lib.EE1 == 0
- assert lib.EE2 == 0
- assert lib.EE3 == 1
-
- def test_init_once(self):
- def do_init():
- seen.append(1)
- return 42
- ffi = FFI()
- seen = []
- for i in range(3):
- res = ffi.init_once(do_init, "tag1")
- assert res == 42
- assert seen == [1]
- for i in range(3):
- res = ffi.init_once(do_init, "tag2")
- assert res == 42
- assert seen == [1, 1]
-
- def test_init_once_multithread(self):
- import sys, time
- if sys.version_info < (3,):
- import thread
- else:
- import _thread as thread
- #
- def do_init():
- seen.append('init!')
- time.sleep(1)
- seen.append('init done')
- return 7
- ffi = FFI()
- seen = []
- for i in range(6):
- def f():
- res = ffi.init_once(do_init, "tag")
- seen.append(res)
- thread.start_new_thread(f, ())
- time.sleep(1.5)
- assert seen == ['init!', 'init done'] + 6 * [7]
-
- def test_sizeof_struct_directly(self):
- # only works with the Python FFI instances
- ffi = FFI(backend=self.Backend())
- assert ffi.sizeof("struct{int a;}") == ffi.sizeof("int")
-
- def test_callback_large_struct(self):
- ffi = FFI(backend=self.Backend())
- # more than 8 bytes
- ffi.cdef("struct foo_s { unsigned long a, b, c; };")
- #
- @ffi.callback("void(struct foo_s)")
- def cb(s):
- seen.append(ffi.typeof(s))
- s.a += 1
- s.b += 2
- s.c += 3
- seen.append(s.a)
- seen.append(s.b)
- seen.append(s.c)
- #
- s1 = ffi.new("struct foo_s *", {'a': 100, 'b': 200, 'c': 300})
- seen = []
- cb(s1[0])
- assert len(seen) == 4
- assert s1.a == 100 # unmodified
- assert s1.b == 200
- assert s1.c == 300
- assert seen[0] == ffi.typeof("struct foo_s")
- assert seen[1] == 101
- assert seen[2] == 202
- assert seen[3] == 303
-
- def test_ffi_array_as_init(self):
- ffi = FFI(backend=self.Backend())
- p = ffi.new("int[4]", [10, 20, 30, 400])
- q = ffi.new("int[4]", p)
- assert list(q) == [10, 20, 30, 400]
- py.test.raises(TypeError, ffi.new, "int[3]", p)
- py.test.raises(TypeError, ffi.new, "int[5]", p)
- py.test.raises(TypeError, ffi.new, "int16_t[4]", p)
- s = ffi.new("struct {int i[4];}*", {'i': p})
- assert list(s.i) == [10, 20, 30, 400]
-
- def test_too_many_initializers(self):
- ffi = FFI(backend=self.Backend())
- py.test.raises(IndexError, ffi.new, "int[4]", [10, 20, 30, 40, 50])
diff --git a/testing/cffi0/callback_in_thread.py b/testing/cffi0/callback_in_thread.py
deleted file mode 100644
index c98605c..0000000
--- a/testing/cffi0/callback_in_thread.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import sys, time
-sys.path.insert(0, sys.argv[1])
-from cffi import FFI
-
-def _run_callback_in_thread():
- ffi = FFI()
- ffi.cdef("""
- typedef int (*mycallback_func_t)(int, int);
- int threaded_ballback_test(mycallback_func_t mycb);
- """)
- lib = ffi.verify("""
- #include <pthread.h>
- typedef int (*mycallback_func_t)(int, int);
- void *my_wait_function(void *ptr) {
- mycallback_func_t cbfunc = (mycallback_func_t)ptr;
- cbfunc(10, 10);
- cbfunc(12, 15);
- return NULL;
- }
- int threaded_ballback_test(mycallback_func_t mycb) {
- pthread_t thread;
- pthread_create(&thread, NULL, my_wait_function, (void*)mycb);
- return 0;
- }
- """, extra_compile_args=['-pthread'])
- seen = []
- @ffi.callback('int(*)(int,int)')
- def mycallback(x, y):
- time.sleep(0.022)
- seen.append((x, y))
- return 0
- lib.threaded_ballback_test(mycallback)
- count = 300
- while len(seen) != 2:
- time.sleep(0.01)
- count -= 1
- assert count > 0, "timeout"
- assert seen == [(10, 10), (12, 15)]
-
-print('STARTING')
-_run_callback_in_thread()
-print('DONE')
diff --git a/testing/cffi0/snippets/distutils_module/setup.py b/testing/cffi0/snippets/distutils_module/setup.py
deleted file mode 100644
index a4d5551..0000000
--- a/testing/cffi0/snippets/distutils_module/setup.py
+++ /dev/null
@@ -1,7 +0,0 @@
-
-from distutils.core import setup
-import snip_basic_verify
-
-setup(
- py_modules=['snip_basic_verify'],
- ext_modules=[snip_basic_verify.ffi.verifier.get_extension()])
diff --git a/testing/cffi0/snippets/distutils_module/snip_basic_verify.py b/testing/cffi0/snippets/distutils_module/snip_basic_verify.py
deleted file mode 100644
index e8a867e..0000000
--- a/testing/cffi0/snippets/distutils_module/snip_basic_verify.py
+++ /dev/null
@@ -1,17 +0,0 @@
-
-from cffi import FFI
-import sys
-
-ffi = FFI()
-ffi.cdef(""" // some declarations from the man page
- struct passwd {
- char *pw_name;
- ...;
- };
- struct passwd *getpwuid(int uid);
-""")
-C = ffi.verify(""" // passed to the real C compiler
-#include <sys/types.h>
-#include <pwd.h>
-""", libraries=[], # or a list of libraries to link with
- force_generic_engine=hasattr(sys, '_force_generic_engine_'))
diff --git a/testing/cffi0/snippets/distutils_package_1/setup.py b/testing/cffi0/snippets/distutils_package_1/setup.py
deleted file mode 100644
index e3d28a5..0000000
--- a/testing/cffi0/snippets/distutils_package_1/setup.py
+++ /dev/null
@@ -1,7 +0,0 @@
-
-from distutils.core import setup
-import snip_basic_verify1
-
-setup(
- packages=['snip_basic_verify1'],
- ext_modules=[snip_basic_verify1.ffi.verifier.get_extension()])
diff --git a/testing/cffi0/snippets/distutils_package_1/snip_basic_verify1/__init__.py b/testing/cffi0/snippets/distutils_package_1/snip_basic_verify1/__init__.py
deleted file mode 100644
index e8a867e..0000000
--- a/testing/cffi0/snippets/distutils_package_1/snip_basic_verify1/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-
-from cffi import FFI
-import sys
-
-ffi = FFI()
-ffi.cdef(""" // some declarations from the man page
- struct passwd {
- char *pw_name;
- ...;
- };
- struct passwd *getpwuid(int uid);
-""")
-C = ffi.verify(""" // passed to the real C compiler
-#include <sys/types.h>
-#include <pwd.h>
-""", libraries=[], # or a list of libraries to link with
- force_generic_engine=hasattr(sys, '_force_generic_engine_'))
diff --git a/testing/cffi0/snippets/distutils_package_2/setup.py b/testing/cffi0/snippets/distutils_package_2/setup.py
deleted file mode 100644
index 6d8f72a..0000000
--- a/testing/cffi0/snippets/distutils_package_2/setup.py
+++ /dev/null
@@ -1,8 +0,0 @@
-
-from distutils.core import setup
-import snip_basic_verify2
-
-setup(
- packages=['snip_basic_verify2'],
- ext_package='snip_basic_verify2',
- ext_modules=[snip_basic_verify2.ffi.verifier.get_extension()])
diff --git a/testing/cffi0/snippets/distutils_package_2/snip_basic_verify2/__init__.py b/testing/cffi0/snippets/distutils_package_2/snip_basic_verify2/__init__.py
deleted file mode 100644
index b4ee686..0000000
--- a/testing/cffi0/snippets/distutils_package_2/snip_basic_verify2/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-
-from cffi import FFI
-import sys
-
-ffi = FFI()
-ffi.cdef(""" // some declarations from the man page
- struct passwd {
- char *pw_name;
- ...;
- };
- struct passwd *getpwuid(int uid);
-""")
-C = ffi.verify(""" // passed to the real C compiler
-#include <sys/types.h>
-#include <pwd.h>
-""", libraries=[], # or a list of libraries to link with
- ext_package='snip_basic_verify2',
- force_generic_engine=hasattr(sys, '_force_generic_engine_'))
diff --git a/testing/cffi0/snippets/infrastructure/setup.py b/testing/cffi0/snippets/infrastructure/setup.py
deleted file mode 100644
index ea89f50..0000000
--- a/testing/cffi0/snippets/infrastructure/setup.py
+++ /dev/null
@@ -1,5 +0,0 @@
-
-from distutils.core import setup
-
-setup(packages=['snip_infrastructure'],
- requires=['cffi'])
diff --git a/testing/cffi0/snippets/infrastructure/snip_infrastructure/__init__.py b/testing/cffi0/snippets/infrastructure/snip_infrastructure/__init__.py
deleted file mode 100644
index dad950d..0000000
--- a/testing/cffi0/snippets/infrastructure/snip_infrastructure/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-def func():
- return 42
diff --git a/testing/cffi0/snippets/setuptools_module/setup.py b/testing/cffi0/snippets/setuptools_module/setup.py
deleted file mode 100644
index 30f2e04..0000000
--- a/testing/cffi0/snippets/setuptools_module/setup.py
+++ /dev/null
@@ -1,8 +0,0 @@
-
-from setuptools import setup
-import snip_setuptools_verify
-
-setup(
- zip_safe=False,
- py_modules=['snip_setuptools_verify'],
- ext_modules=[snip_setuptools_verify.ffi.verifier.get_extension()])
diff --git a/testing/cffi0/snippets/setuptools_module/snip_setuptools_verify.py b/testing/cffi0/snippets/setuptools_module/snip_setuptools_verify.py
deleted file mode 100644
index e8a867e..0000000
--- a/testing/cffi0/snippets/setuptools_module/snip_setuptools_verify.py
+++ /dev/null
@@ -1,17 +0,0 @@
-
-from cffi import FFI
-import sys
-
-ffi = FFI()
-ffi.cdef(""" // some declarations from the man page
- struct passwd {
- char *pw_name;
- ...;
- };
- struct passwd *getpwuid(int uid);
-""")
-C = ffi.verify(""" // passed to the real C compiler
-#include <sys/types.h>
-#include <pwd.h>
-""", libraries=[], # or a list of libraries to link with
- force_generic_engine=hasattr(sys, '_force_generic_engine_'))
diff --git a/testing/cffi0/snippets/setuptools_package_1/setup.py b/testing/cffi0/snippets/setuptools_package_1/setup.py
deleted file mode 100644
index 18ea3f6..0000000
--- a/testing/cffi0/snippets/setuptools_package_1/setup.py
+++ /dev/null
@@ -1,8 +0,0 @@
-
-from setuptools import setup
-import snip_setuptools_verify1
-
-setup(
- zip_safe=False,
- packages=['snip_setuptools_verify1'],
- ext_modules=[snip_setuptools_verify1.ffi.verifier.get_extension()])
diff --git a/testing/cffi0/snippets/setuptools_package_1/snip_setuptools_verify1/__init__.py b/testing/cffi0/snippets/setuptools_package_1/snip_setuptools_verify1/__init__.py
deleted file mode 100644
index e8a867e..0000000
--- a/testing/cffi0/snippets/setuptools_package_1/snip_setuptools_verify1/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-
-from cffi import FFI
-import sys
-
-ffi = FFI()
-ffi.cdef(""" // some declarations from the man page
- struct passwd {
- char *pw_name;
- ...;
- };
- struct passwd *getpwuid(int uid);
-""")
-C = ffi.verify(""" // passed to the real C compiler
-#include <sys/types.h>
-#include <pwd.h>
-""", libraries=[], # or a list of libraries to link with
- force_generic_engine=hasattr(sys, '_force_generic_engine_'))
diff --git a/testing/cffi0/snippets/setuptools_package_2/setup.py b/testing/cffi0/snippets/setuptools_package_2/setup.py
deleted file mode 100644
index 87fb22b..0000000
--- a/testing/cffi0/snippets/setuptools_package_2/setup.py
+++ /dev/null
@@ -1,9 +0,0 @@
-
-from setuptools import setup
-import snip_setuptools_verify2
-
-setup(
- zip_safe=False,
- packages=['snip_setuptools_verify2'],
- ext_package='snip_setuptools_verify2',
- ext_modules=[snip_setuptools_verify2.ffi.verifier.get_extension()])
diff --git a/testing/cffi0/snippets/setuptools_package_2/snip_setuptools_verify2/__init__.py b/testing/cffi0/snippets/setuptools_package_2/snip_setuptools_verify2/__init__.py
deleted file mode 100644
index 5f4bd13..0000000
--- a/testing/cffi0/snippets/setuptools_package_2/snip_setuptools_verify2/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-
-from cffi import FFI
-import sys
-
-ffi = FFI()
-ffi.cdef(""" // some declarations from the man page
- struct passwd {
- char *pw_name;
- ...;
- };
- struct passwd *getpwuid(int uid);
-""")
-C = ffi.verify(""" // passed to the real C compiler
-#include <sys/types.h>
-#include <pwd.h>
-""", libraries=[], # or a list of libraries to link with
- ext_package='snip_setuptools_verify2',
- force_generic_engine=hasattr(sys, '_force_generic_engine_'))
diff --git a/testing/cffi0/test_cdata.py b/testing/cffi0/test_cdata.py
deleted file mode 100644
index 23989ab..0000000
--- a/testing/cffi0/test_cdata.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import py
-from cffi import FFI
-
-class FakeBackend(object):
-
- def nonstandard_integer_types(self):
- return {}
-
- def sizeof(self, name):
- return 1
-
- def load_library(self, path):
- return "fake library"
-
- def new_primitive_type(self, name):
- return FakeType("primitive " + name)
-
- def new_void_type(self):
- return FakeType("void")
- def new_pointer_type(self, x):
- return FakeType('ptr-to-%r' % (x,))
- def new_array_type(self, x, y):
- return FakeType('array-from-%r-len-%r' % (x, y))
- def cast(self, x, y):
- return 'casted!'
- def _get_types(self):
- return "CData", "CType"
-
- buffer = "buffer type"
-
-
-class FakeType(object):
- def __init__(self, cdecl):
- self.cdecl = cdecl
-
-
-def test_typeof():
- ffi = FFI(backend=FakeBackend())
- clong = ffi.typeof("signed long int")
- assert isinstance(clong, FakeType)
- assert clong.cdecl == 'primitive long'
diff --git a/testing/cffi0/test_ctypes.py b/testing/cffi0/test_ctypes.py
deleted file mode 100644
index a70c8f0..0000000
--- a/testing/cffi0/test_ctypes.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import py, sys
-from testing.cffi0 import backend_tests
-from cffi.backend_ctypes import CTypesBackend
-
-
-class TestCTypes(backend_tests.BackendTests):
- # for individual tests see
- # ====> backend_tests.py
-
- Backend = CTypesBackend
- TypeRepr = "<class 'ffi.CData<%s>'>"
-
- def test_array_of_func_ptr(self):
- py.test.skip("ctypes backend: not supported: "
- "initializers for function pointers")
-
- def test_structptr_argument(self):
- py.test.skip("ctypes backend: not supported: passing a list "
- "for a pointer argument")
-
- def test_array_argument_as_list(self):
- py.test.skip("ctypes backend: not supported: passing a list "
- "for a pointer argument")
-
- def test_cast_to_array_type(self):
- py.test.skip("ctypes backend: not supported: casting to array")
-
- def test_nested_anonymous_struct(self):
- py.test.skip("ctypes backend: not supported: nested anonymous struct")
-
- def test_nested_field_offset_align(self):
- py.test.skip("ctypes backend: not supported: nested anonymous struct")
-
- def test_nested_anonymous_union(self):
- py.test.skip("ctypes backend: not supported: nested anonymous union")
-
- def test_nested_anonymous_struct_2(self):
- py.test.skip("ctypes backend: not supported: nested anonymous union")
-
- def test_CData_CType_2(self):
- if sys.version_info >= (3,):
- py.test.skip("ctypes backend: not supported in Python 3: CType")
- backend_tests.BackendTests.test_CData_CType_2(self)
diff --git a/testing/cffi0/test_ffi_backend.py b/testing/cffi0/test_ffi_backend.py
deleted file mode 100644
index 8e29bc4..0000000
--- a/testing/cffi0/test_ffi_backend.py
+++ /dev/null
@@ -1,620 +0,0 @@
-import py, sys, platform
-import pytest
-from testing.cffi0 import backend_tests, test_function, test_ownlib
-from testing.support import u
-from cffi import FFI
-import _cffi_backend
-
-
-class TestFFI(backend_tests.BackendTests,
- test_function.TestFunction,
- test_ownlib.TestOwnLib):
- TypeRepr = "<ctype '%s'>"
-
- @staticmethod
- def Backend():
- return _cffi_backend
-
- def test_not_supported_bitfield_in_result(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("struct foo_s { int a,b,c,d,e; int x:1; };")
- e = py.test.raises(NotImplementedError, ffi.callback,
- "struct foo_s foo(void)", lambda: 42)
- assert str(e.value) == ("struct foo_s(*)(): "
- "callback with unsupported argument or return type or with '...'")
-
- def test_inspecttype(self):
- ffi = FFI(backend=self.Backend())
- assert ffi.typeof("long").kind == "primitive"
- assert ffi.typeof("long(*)(long, long**, ...)").cname == (
- "long(*)(long, long * *, ...)")
- assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True
-
- def test_new_handle(self):
- ffi = FFI(backend=self.Backend())
- o = [2, 3, 4]
- p = ffi.new_handle(o)
- assert ffi.typeof(p) == ffi.typeof("void *")
- assert ffi.from_handle(p) is o
- assert ffi.from_handle(ffi.cast("char *", p)) is o
- py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
-
- def test_callback_onerror(self):
- ffi = FFI(backend=self.Backend())
- seen = []
- def oops(*args):
- seen.append(args)
- def otherfunc():
- raise LookupError
- def cb(n):
- otherfunc()
- a = ffi.callback("int(*)(int)", cb, error=42, onerror=oops)
- res = a(234)
- assert res == 42
- assert len(seen) == 1
- exc, val, tb = seen[0]
- assert exc is LookupError
- assert isinstance(val, LookupError)
- assert tb.tb_frame.f_code.co_name == 'cb'
- assert tb.tb_frame.f_locals['n'] == 234
-
- def test_ffi_new_allocator_2(self):
- ffi = FFI(backend=self.Backend())
- seen = []
- def myalloc(size):
- seen.append(size)
- return ffi.new("char[]", b"X" * size)
- def myfree(raw):
- seen.append(raw)
- alloc1 = ffi.new_allocator(myalloc, myfree)
- alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree,
- should_clear_after_alloc=False)
- p1 = alloc1("int[10]")
- p2 = alloc2("int[]", 10)
- assert seen == [40, 40]
- assert ffi.typeof(p1) == ffi.typeof("int[10]")
- assert ffi.sizeof(p1) == 40
- assert ffi.typeof(p2) == ffi.typeof("int[]")
- assert ffi.sizeof(p2) == 40
- assert p1[5] == 0
- assert p2[6] == ord('X') * 0x01010101
- raw1 = ffi.cast("char *", p1)
- raw2 = ffi.cast("char *", p2)
- del p1, p2
- retries = 0
- while len(seen) != 4:
- retries += 1
- assert retries <= 5
- import gc; gc.collect()
- assert seen == [40, 40, raw1, raw2]
- assert repr(seen[2]) == "<cdata 'char[]' owning 41 bytes>"
- assert repr(seen[3]) == "<cdata 'char[]' owning 41 bytes>"
-
- def test_ffi_new_allocator_3(self):
- ffi = FFI(backend=self.Backend())
- seen = []
- def myalloc(size):
- seen.append(size)
- return ffi.new("char[]", b"X" * size)
- alloc1 = ffi.new_allocator(myalloc) # no 'free'
- p1 = alloc1("int[10]")
- assert seen == [40]
- assert ffi.typeof(p1) == ffi.typeof("int[10]")
- assert ffi.sizeof(p1) == 40
- assert p1[5] == 0
-
- def test_ffi_new_allocator_4(self):
- ffi = FFI(backend=self.Backend())
- py.test.raises(TypeError, ffi.new_allocator, free=lambda x: None)
- #
- def myalloc2(size):
- raise LookupError
- alloc2 = ffi.new_allocator(myalloc2)
- py.test.raises(LookupError, alloc2, "int[5]")
- #
- def myalloc3(size):
- return 42
- alloc3 = ffi.new_allocator(myalloc3)
- e = py.test.raises(TypeError, alloc3, "int[5]")
- assert str(e.value) == "alloc() must return a cdata object (got int)"
- #
- def myalloc4(size):
- return ffi.cast("int", 42)
- alloc4 = ffi.new_allocator(myalloc4)
- e = py.test.raises(TypeError, alloc4, "int[5]")
- assert str(e.value) == "alloc() must return a cdata pointer, not 'int'"
- #
- def myalloc5(size):
- return ffi.NULL
- alloc5 = ffi.new_allocator(myalloc5)
- py.test.raises(MemoryError, alloc5, "int[5]")
-
- def test_new_struct_containing_struct_containing_array_varsize(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct foo_s { int len[100]; short data[]; };
- struct bar_s { int abc[100]; struct foo_s tail; };
- """)
- # loop to try to detect heap overwrites, if the size allocated
- # is too small
- for i in range(1, 501, 100):
- p = ffi.new("struct bar_s *", [[10], [[20], [3,4,5,6,7,8,9] * i]])
- assert p.abc[0] == 10
- assert p.tail.len[0] == 20
- assert p.tail.data[0] == 3
- assert p.tail.data[6] == 9
- assert p.tail.data[7 * i - 1] == 9
-
- def test_bogus_struct_containing_struct_containing_array_varsize(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct foo_s { signed char len; signed char data[]; };
- struct bar_s { struct foo_s foo; int bcd; };
- """)
- p = ffi.new("struct bar_s *", [[123, [45, 56, 67, 78]], 9999999])
- assert p.foo.len == 123
- assert p.foo.data[0] == 45
- assert p.foo.data[1] == 56
- assert p.foo.data[2] == 67
- assert p.bcd == 9999999
- assert p.foo.data[3] != 78 # has been overwritten with 9999999
-
-
-class TestBitfield:
- def check(self, source, expected_ofs_y, expected_align, expected_size):
- # NOTE: 'expected_*' is the numbers expected from GCC.
- # The numbers expected from MSVC are not explicitly written
- # in this file, and will just be taken from the compiler.
- ffi = FFI()
- ffi.cdef("struct s1 { %s };" % source)
- ctype = ffi.typeof("struct s1")
- # verify the information with gcc
- ffi1 = FFI()
- ffi1.cdef("""
- static const int Gofs_y, Galign, Gsize;
- struct s1 *try_with_value(int fieldnum, long long value);
- """)
- fnames = [name for name, cfield in ctype.fields
- if name and cfield.bitsize > 0]
- setters = ['case %d: s.%s = value; break;' % iname
- for iname in enumerate(fnames)]
- lib = ffi1.verify("""
- #include <string.h>
- struct s1 { %s };
- struct sa { char a; struct s1 b; };
- #define Gofs_y offsetof(struct s1, y)
- #define Galign offsetof(struct sa, b)
- #define Gsize sizeof(struct s1)
- struct s1 *try_with_value(int fieldnum, long long value)
- {
- static struct s1 s;
- memset(&s, 0, sizeof(s));
- switch (fieldnum) { %s }
- return &s;
- }
- """ % (source, ' '.join(setters)))
- if sys.platform == 'win32':
- expected_ofs_y = lib.Gofs_y
- expected_align = lib.Galign
- expected_size = lib.Gsize
- else:
- assert (lib.Gofs_y, lib.Galign, lib.Gsize) == (
- expected_ofs_y, expected_align, expected_size)
- # the real test follows
- assert ffi.offsetof("struct s1", "y") == expected_ofs_y
- assert ffi.alignof("struct s1") == expected_align
- assert ffi.sizeof("struct s1") == expected_size
- # compare the actual storage of the two
- for name, cfield in ctype.fields:
- if cfield.bitsize < 0 or not name:
- continue
- if int(ffi.cast(cfield.type, -1)) == -1: # signed
- min_value = -(1 << (cfield.bitsize-1))
- max_value = (1 << (cfield.bitsize-1)) - 1
- else:
- min_value = 0
- max_value = (1 << cfield.bitsize) - 1
- for t in [1, 2, 4, 8, 16, 128, 2813, 89728, 981729,
- -1,-2,-4,-8,-16,-128,-2813,-89728,-981729]:
- if min_value <= t <= max_value:
- self._fieldcheck(ffi, lib, fnames, name, t)
-
- def _fieldcheck(self, ffi, lib, fnames, name, value):
- s = ffi.new("struct s1 *")
- setattr(s, name, value)
- assert getattr(s, name) == value
- raw1 = ffi.buffer(s)[:]
- buff1 = ffi.buffer(s)
- t = lib.try_with_value(fnames.index(name), value)
- raw2 = ffi.buffer(t, len(raw1))[:]
- assert raw1 == raw2
- buff2 = ffi.buffer(t, len(buff1))
- assert buff1 == buff2
-
- def test_bitfield_basic(self):
- self.check("int a; int b:9; int c:20; int y;", 8, 4, 12)
- self.check("int a; short b:9; short c:7; int y;", 8, 4, 12)
- self.check("int a; short b:9; short c:9; int y;", 8, 4, 12)
-
- def test_bitfield_reuse_if_enough_space(self):
- self.check("int a:2; char y;", 1, 4, 4)
- self.check("int a:1; char b ; int c:1; char y;", 3, 4, 4)
- self.check("int a:1; char b:8; int c:1; char y;", 3, 4, 4)
- self.check("char a; int b:9; char y;", 3, 4, 4)
- self.check("char a; short b:9; char y;", 4, 2, 6)
- self.check("int a:2; char b:6; char y;", 1, 4, 4)
- self.check("int a:2; char b:7; char y;", 2, 4, 4)
- self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8)
- self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4)
-
- @pytest.mark.skipif(
- "not (sys.platform == 'darwin' and platform.machine() == 'arm64')"
- " and "
- "platform.machine().startswith(('arm', 'aarch64'))")
- def test_bitfield_anonymous_no_align(self):
- L = FFI().alignof("long long")
- self.check("char y; int :1;", 0, 1, 2)
- self.check("char x; int z:1; char y;", 2, 4, 4)
- self.check("char x; int :1; char y;", 2, 1, 3)
- self.check("char x; long long z:48; char y;", 7, L, 8)
- self.check("char x; long long :48; char y;", 7, 1, 8)
- self.check("char x; long long z:56; char y;", 8, L, 8 + L)
- self.check("char x; long long :56; char y;", 8, 1, 9)
- self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L)
- self.check("char x; long long :57; char y;", L + 8, 1, L + 9)
-
- @pytest.mark.skipif(
- "(sys.platform == 'darwin' and platform.machine() == 'arm64')"
- " or "
- "not platform.machine().startswith(('arm', 'aarch64'))")
- def test_bitfield_anonymous_align_arm(self):
- L = FFI().alignof("long long")
- self.check("char y; int :1;", 0, 4, 4)
- self.check("char x; int z:1; char y;", 2, 4, 4)
- self.check("char x; int :1; char y;", 2, 4, 4)
- self.check("char x; long long z:48; char y;", 7, L, 8)
- self.check("char x; long long :48; char y;", 7, 8, 8)
- self.check("char x; long long z:56; char y;", 8, L, 8 + L)
- self.check("char x; long long :56; char y;", 8, L, 8 + L)
- self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L)
- self.check("char x; long long :57; char y;", L + 8, L, L + 8 + L)
-
- @pytest.mark.skipif(
- "not (sys.platform == 'darwin' and platform.machine() == 'arm64')"
- " and "
- "platform.machine().startswith(('arm', 'aarch64'))")
- def test_bitfield_zero(self):
- L = FFI().alignof("long long")
- self.check("char y; int :0;", 0, 1, 4)
- self.check("char x; int :0; char y;", 4, 1, 5)
- self.check("char x; int :0; int :0; char y;", 4, 1, 5)
- self.check("char x; long long :0; char y;", L, 1, L + 1)
- self.check("short x, y; int :0; int :0;", 2, 2, 4)
- self.check("char x; int :0; short b:1; char y;", 5, 2, 6)
- self.check("int a:1; int :0; int b:1; char y;", 5, 4, 8)
-
- @pytest.mark.skipif(
- "(sys.platform == 'darwin' and platform.machine() == 'arm64')"
- " or "
- "not platform.machine().startswith(('arm', 'aarch64'))")
- def test_bitfield_zero_arm(self):
- L = FFI().alignof("long long")
- self.check("char y; int :0;", 0, 4, 4)
- self.check("char x; int :0; char y;", 4, 4, 8)
- self.check("char x; int :0; int :0; char y;", 4, 4, 8)
- self.check("char x; long long :0; char y;", L, 8, L + 8)
- self.check("short x, y; int :0; int :0;", 2, 4, 4)
- self.check("char x; int :0; short b:1; char y;", 5, 4, 8)
- self.check("int a:1; int :0; int b:1; char y;", 5, 4, 8)
-
- def test_error_cases(self):
- ffi = FFI()
- ffi.cdef("struct s1 { float x:1; };")
- with pytest.raises(TypeError):
- ffi.new("struct s1 *")
- ffi.cdef("struct s2 { char x:0; };")
- with pytest.raises(TypeError):
- ffi.new("struct s2 *")
- ffi.cdef("struct s3 { char x:9; };")
- with pytest.raises(TypeError):
- ffi.new("struct s3 *")
-
- def test_struct_with_typedef(self):
- ffi = FFI()
- ffi.cdef("typedef struct { float x; } foo_t;")
- p = ffi.new("foo_t *", [5.2])
- assert repr(p).startswith("<cdata 'foo_t *' ")
-
- def test_struct_array_no_length(self):
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; int a[]; };")
- p = ffi.new("struct foo_s *", [100, [200, 300, 400]])
- assert p.x == 100
- assert ffi.typeof(p.a) is ffi.typeof("int[]")
- assert len(p.a) == 3 # length recorded
- assert p.a[0] == 200
- assert p.a[1] == 300
- assert p.a[2] == 400
- assert list(p.a) == [200, 300, 400]
- q = ffi.cast("struct foo_s *", p)
- assert q.x == 100
- assert ffi.typeof(q.a) is ffi.typeof("int *") # no length recorded
- py.test.raises(TypeError, len, q.a)
- assert q.a[0] == 200
- assert q.a[1] == 300
- assert q.a[2] == 400
- py.test.raises(TypeError, list, q.a)
-
- @pytest.mark.skipif("sys.platform != 'win32'")
- def test_getwinerror(self):
- ffi = FFI()
- code, message = ffi.getwinerror(1155)
- assert code == 1155
- assert message == ("No application is associated with the "
- "specified file for this operation")
- ffi.cdef("void SetLastError(int);")
- lib = ffi.dlopen("Kernel32.dll")
- lib.SetLastError(2)
- code, message = ffi.getwinerror()
- assert code == 2
- assert message == "The system cannot find the file specified"
- code, message = ffi.getwinerror(-1)
- assert code == 2
- assert message == "The system cannot find the file specified"
-
- def test_from_buffer(self):
- import array
- ffi = FFI()
- a = array.array('H', [10000, 20000, 30000])
- c = ffi.from_buffer(a)
- assert ffi.typeof(c) is ffi.typeof("char[]")
- assert len(c) == 6
- ffi.cast("unsigned short *", c)[1] += 500
- assert list(a) == [10000, 20500, 30000]
- assert c == ffi.from_buffer("char[]", a, True)
- assert c == ffi.from_buffer(a, require_writable=True)
- #
- c = ffi.from_buffer("unsigned short[]", a)
- assert len(c) == 3
- assert c[1] == 20500
- #
- p = ffi.from_buffer(b"abcd")
- assert p[2] == b"c"
- #
- assert p == ffi.from_buffer(b"abcd", require_writable=False)
- py.test.raises((TypeError, BufferError), ffi.from_buffer,
- "char[]", b"abcd", True)
- py.test.raises((TypeError, BufferError), ffi.from_buffer, b"abcd",
- require_writable=True)
-
- def test_release(self):
- ffi = FFI()
- p = ffi.new("int[]", 123)
- ffi.release(p)
- # here, reading p[0] might give garbage or segfault...
- ffi.release(p) # no effect
-
- def test_memmove(self):
- ffi = FFI()
- p = ffi.new("short[]", [-1234, -2345, -3456, -4567, -5678])
- ffi.memmove(p, p + 1, 4)
- assert list(p) == [-2345, -3456, -3456, -4567, -5678]
- p[2] = 999
- ffi.memmove(p + 2, p, 6)
- assert list(p) == [-2345, -3456, -2345, -3456, 999]
- ffi.memmove(p + 4, ffi.new("char[]", 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(self):
- import array
- ffi = FFI()
- a = array.array('H', [10000, 20000, 30000])
- p = ffi.new("short[]", 5)
- ffi.memmove(p, a, 6)
- assert list(p) == [10000, 20000, 30000, 0, 0]
- ffi.memmove(p + 1, a, 6)
- assert list(p) == [10000, 10000, 20000, 30000, 0]
- b = array.array('h', [-1000, -2000, -3000])
- ffi.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
- ffi.memmove(b, p, 2)
- assert b.tolist() == [999, 20000, -3000]
- ffi.memmove(b, p + 2, 4)
- assert b.tolist() == [997, 996, -3000]
- p[2] = -p[2]
- p[3] = -p[3]
- ffi.memmove(b, p + 2, 6)
- assert b.tolist() == [-997, -996, 995]
-
- def test_memmove_readonly_readwrite(self):
- ffi = FFI()
- p = ffi.new("signed char[]", 5)
- ffi.memmove(p, b"abcde", 3)
- assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0]
- ffi.memmove(p, bytearray(b"ABCDE"), 2)
- assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0]
- py.test.raises((TypeError, BufferError), ffi.memmove, b"abcde", p, 3)
- ba = bytearray(b"xxxxx")
- ffi.memmove(dest=ba, src=p, n=3)
- assert ba == bytearray(b"ABcxx")
-
- def test_all_primitives(self):
- ffi = FFI()
- for name in [
- "char",
- "short",
- "int",
- "long",
- "long long",
- "signed char",
- "unsigned char",
- "unsigned short",
- "unsigned int",
- "unsigned long",
- "unsigned long long",
- "float",
- "double",
- "long double",
- "wchar_t",
- "char16_t",
- "char32_t",
- "_Bool",
- "int8_t",
- "uint8_t",
- "int16_t",
- "uint16_t",
- "int32_t",
- "uint32_t",
- "int64_t",
- "uint64_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",
- "intptr_t",
- "uintptr_t",
- "intmax_t",
- "uintmax_t",
- "ptrdiff_t",
- "size_t",
- "ssize_t",
- ]:
- x = ffi.sizeof(name)
- assert 1 <= x <= 16
-
- def test_ffi_def_extern(self):
- ffi = FFI()
- py.test.raises(ValueError, ffi.def_extern)
-
- def test_introspect_typedef(self):
- ffi = FFI()
- ffi.cdef("typedef int foo_t;")
- assert ffi.list_types() == (['foo_t'], [], [])
- assert ffi.typeof('foo_t').kind == 'primitive'
- assert ffi.typeof('foo_t').cname == 'int'
- #
- ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;")
- assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'foo_t', 'g_t'],
- [], [])
-
- def test_introspect_struct(self):
- ffi = FFI()
- ffi.cdef("struct foo_s { int a; };")
- assert ffi.list_types() == ([], ['foo_s'], [])
- assert ffi.typeof('struct foo_s').kind == 'struct'
- assert ffi.typeof('struct foo_s').cname == 'struct foo_s'
-
- def test_introspect_union(self):
- ffi = FFI()
- ffi.cdef("union foo_s { int a; };")
- assert ffi.list_types() == ([], [], ['foo_s'])
- assert ffi.typeof('union foo_s').kind == 'union'
- assert ffi.typeof('union foo_s').cname == 'union foo_s'
-
- def test_introspect_struct_and_typedef(self):
- ffi = FFI()
- ffi.cdef("typedef struct { int a; } foo_t;")
- assert ffi.list_types() == (['foo_t'], [], [])
- assert ffi.typeof('foo_t').kind == 'struct'
- assert ffi.typeof('foo_t').cname == 'foo_t'
-
- def test_introspect_included_type(self):
- ffi1 = FFI()
- ffi2 = FFI()
- ffi1.cdef("typedef signed char schar_t; struct sint_t { int x; };")
- ffi2.include(ffi1)
- assert ffi1.list_types() == ffi2.list_types() == (
- ['schar_t'], ['sint_t'], [])
-
- def test_introspect_order(self):
- ffi = FFI()
- ffi.cdef("union CFFIaaa { int a; }; typedef struct CFFIccc { int a; } CFFIb;")
- ffi.cdef("union CFFIg { int a; }; typedef struct CFFIcc { int a; } CFFIbbb;")
- ffi.cdef("union CFFIaa { int a; }; typedef struct CFFIa { int a; } CFFIbb;")
- assert ffi.list_types() == (['CFFIb', 'CFFIbb', 'CFFIbbb'],
- ['CFFIa', 'CFFIcc', 'CFFIccc'],
- ['CFFIaa', 'CFFIaaa', 'CFFIg'])
-
- def test_unpack(self):
- ffi = FFI()
- p = ffi.new("char[]", b"abc\x00def")
- assert ffi.unpack(p+1, 7) == b"bc\x00def\x00"
- p = ffi.new("int[]", [-123456789])
- assert ffi.unpack(p, 1) == [-123456789]
-
- def test_negative_array_size(self):
- ffi = FFI()
- py.test.raises(ValueError, ffi.cast, "int[-5]", 0)
-
- def test_cannot_instantiate_manually(self):
- ffi = FFI()
- ct = type(ffi.typeof("void *"))
- py.test.raises(TypeError, ct)
- py.test.raises(TypeError, ct, ffi.NULL)
- for cd in [type(ffi.cast("void *", 0)),
- type(ffi.new("char[]", 3)),
- type(ffi.gc(ffi.NULL, lambda x: None))]:
- py.test.raises(TypeError, cd)
- py.test.raises(TypeError, cd, ffi.NULL)
- py.test.raises(TypeError, cd, ffi.typeof("void *"))
-
- def test_explicitly_defined_char16_t(self):
- ffi = FFI()
- ffi.cdef("typedef uint16_t char16_t;")
- x = ffi.cast("char16_t", 1234)
- assert ffi.typeof(x) is ffi.typeof("uint16_t")
-
- def test_char16_t(self):
- ffi = FFI()
- x = ffi.new("char16_t[]", 5)
- assert len(x) == 5 and ffi.sizeof(x) == 10
- x[2] = u+'\u1324'
- assert x[2] == u+'\u1324'
- y = ffi.new("char16_t[]", u+'\u1234\u5678')
- assert len(y) == 3
- assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00']
- assert ffi.string(y) == u+'\u1234\u5678'
- z = ffi.new("char16_t[]", u+'\U00012345')
- assert len(z) == 3
- assert list(z) == [u+'\ud808', u+'\udf45', u+'\x00']
- assert ffi.string(z) == u+'\U00012345'
-
- def test_char32_t(self):
- ffi = FFI()
- x = ffi.new("char32_t[]", 5)
- assert len(x) == 5 and ffi.sizeof(x) == 20
- x[3] = u+'\U00013245'
- assert x[3] == u+'\U00013245'
- y = ffi.new("char32_t[]", u+'\u1234\u5678')
- assert len(y) == 3
- assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00']
- py_uni = u+'\U00012345'
- z = ffi.new("char32_t[]", py_uni)
- assert len(z) == 2
- assert list(z) == [py_uni, u+'\x00'] # maybe a 2-unichars string
- assert ffi.string(z) == py_uni
- if len(py_uni) == 1: # 4-bytes unicodes in Python
- s = ffi.new("char32_t[]", u+'\ud808\udf00')
- assert len(s) == 3
- assert list(s) == [u+'\ud808', u+'\udf00', u+'\x00']
diff --git a/testing/cffi0/test_function.py b/testing/cffi0/test_function.py
deleted file mode 100644
index b4bb23d..0000000
--- a/testing/cffi0/test_function.py
+++ /dev/null
@@ -1,548 +0,0 @@
-import py
-import pytest
-from cffi import FFI, CDefError
-import math, os, sys
-import ctypes.util
-from cffi.backend_ctypes import CTypesBackend
-from testing.udir import udir
-from testing.support import FdWriteCapture, StdErrCapture
-from .backend_tests import needs_dlopen_none
-
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-
-lib_m = 'm'
-if sys.platform == 'win32':
- #there is a small chance this fails on Mingw via environ $CC
- import distutils.ccompiler
- if distutils.ccompiler.get_default_compiler() == 'msvc':
- lib_m = 'msvcrt'
-
-class TestFunction(object):
- Backend = CTypesBackend
-
- def test_sin(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- double sin(double x);
- """)
- m = ffi.dlopen(lib_m)
- x = m.sin(1.23)
- assert x == math.sin(1.23)
-
- def test_sinf(self):
- if sys.platform == 'win32':
- py.test.skip("no sinf found in the Windows stdlib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- float sinf(float x);
- """)
- m = ffi.dlopen(lib_m)
- x = m.sinf(1.23)
- assert type(x) is float
- assert x != math.sin(1.23) # rounding effects
- assert abs(x - math.sin(1.23)) < 1E-6
-
- def test_getenv_no_return_value(self):
- # check that 'void'-returning functions work too
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- void getenv(char *);
- """)
- needs_dlopen_none()
- m = ffi.dlopen(None)
- x = m.getenv(b"FOO")
- assert x is None
-
- def test_dlopen_filename(self):
- path = ctypes.util.find_library(lib_m)
- if not path:
- py.test.skip("%s not found" % lib_m)
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- double cos(double x);
- """)
- m = ffi.dlopen(path)
- x = m.cos(1.23)
- assert x == math.cos(1.23)
-
- m = ffi.dlopen(os.path.basename(path))
- x = m.cos(1.23)
- assert x == math.cos(1.23)
-
- def test_dlopen_flags(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- double cos(double x);
- """)
- m = ffi.dlopen(lib_m, ffi.RTLD_LAZY | ffi.RTLD_LOCAL)
- x = m.cos(1.23)
- assert x == math.cos(1.23)
-
- def test_dlopen_constant(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- #define FOOBAR 42
- static const float baz = 42.5; /* not visible */
- double sin(double x);
- """)
- m = ffi.dlopen(lib_m)
- assert m.FOOBAR == 42
- with pytest.raises(NotImplementedError):
- m.baz
-
- def test_tlsalloc(self):
- if sys.platform != 'win32':
- py.test.skip("win32 only")
- if self.Backend is CTypesBackend:
- py.test.skip("ctypes complains on wrong calling conv")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("long TlsAlloc(void); int TlsFree(long);")
- lib = ffi.dlopen('KERNEL32.DLL')
- x = lib.TlsAlloc()
- assert x != 0
- y = lib.TlsFree(x)
- assert y != 0
-
- def test_fputs(self):
- if not sys.platform.startswith('linux'):
- py.test.skip("probably no symbol 'stderr' in the lib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int fputs(const char *, void *);
- extern void *stderr;
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- ffi.C.fputs # fetch before capturing, for easier debugging
- with FdWriteCapture() as fd:
- ffi.C.fputs(b"hello\n", ffi.C.stderr)
- ffi.C.fputs(b" world\n", ffi.C.stderr)
- res = fd.getvalue()
- assert res == b'hello\n world\n'
-
- def test_fputs_without_const(self):
- if not sys.platform.startswith('linux'):
- py.test.skip("probably no symbol 'stderr' in the lib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int fputs(char *, void *);
- extern void *stderr;
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- ffi.C.fputs # fetch before capturing, for easier debugging
- with FdWriteCapture() as fd:
- ffi.C.fputs(b"hello\n", ffi.C.stderr)
- ffi.C.fputs(b" world\n", ffi.C.stderr)
- res = fd.getvalue()
- assert res == b'hello\n world\n'
-
- def test_vararg(self):
- if not sys.platform.startswith('linux'):
- py.test.skip("probably no symbol 'stderr' in the lib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int fprintf(void *, const char *format, ...);
- extern void *stderr;
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- with FdWriteCapture() as fd:
- ffi.C.fprintf(ffi.C.stderr, b"hello with no arguments\n")
- ffi.C.fprintf(ffi.C.stderr,
- b"hello, %s!\n", ffi.new("char[]", b"world"))
- ffi.C.fprintf(ffi.C.stderr,
- ffi.new("char[]", b"hello, %s!\n"),
- ffi.new("char[]", b"world2"))
- ffi.C.fprintf(ffi.C.stderr,
- b"hello int %d long %ld long long %lld\n",
- ffi.cast("int", 42),
- ffi.cast("long", 84),
- ffi.cast("long long", 168))
- ffi.C.fprintf(ffi.C.stderr, b"hello %p\n", ffi.NULL)
- res = fd.getvalue()
- assert res == (b"hello with no arguments\n"
- b"hello, world!\n"
- b"hello, world2!\n"
- b"hello int 42 long 84 long long 168\n"
- b"hello (nil)\n")
-
- def test_must_specify_type_of_vararg(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int printf(const char *format, ...);
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- e = py.test.raises(TypeError, ffi.C.printf, b"hello %d\n", 42)
- assert str(e.value) == ("argument 2 passed in the variadic part "
- "needs to be a cdata object (got int)")
-
- def test_function_has_a_c_type(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int puts(const char *);
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- fptr = ffi.C.puts
- assert ffi.typeof(fptr) == ffi.typeof("int(*)(const char*)")
- if self.Backend is CTypesBackend:
- assert repr(fptr).startswith("<cdata 'int puts(char *)' 0x")
-
- def test_function_pointer(self):
- ffi = FFI(backend=self.Backend())
- def cb(charp):
- assert repr(charp).startswith("<cdata 'char *' 0x")
- return 42
- fptr = ffi.callback("int(*)(const char *txt)", cb)
- assert fptr != ffi.callback("int(*)(const char *)", cb)
- assert repr(fptr) == "<cdata 'int(*)(char *)' calling %r>" % (cb,)
- res = fptr(b"Hello")
- assert res == 42
- #
- if not sys.platform.startswith('linux'):
- py.test.skip("probably no symbol 'stderr' in the lib")
- ffi.cdef("""
- int fputs(const char *, void *);
- extern void *stderr;
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- fptr = ffi.cast("int(*)(const char *txt, void *)", ffi.C.fputs)
- assert fptr == ffi.C.fputs
- assert repr(fptr).startswith("<cdata 'int(*)(char *, void *)' 0x")
- with FdWriteCapture() as fd:
- fptr(b"world\n", ffi.C.stderr)
- res = fd.getvalue()
- assert res == b'world\n'
-
- def test_callback_returning_void(self):
- ffi = FFI(backend=self.Backend())
- for returnvalue in [None, 42]:
- def cb():
- return returnvalue
- fptr = ffi.callback("void(*)(void)", cb)
- with StdErrCapture() as f:
- returned = fptr()
- printed = f.getvalue()
- assert returned is None
- if returnvalue is None:
- assert printed == ''
- else:
- assert "None" in printed
-
- def test_callback_returning_struct_three_bytes(self):
- if self.Backend is CTypesBackend:
- py.test.skip("not supported with the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- typedef struct {
- unsigned char a, b, c;
- } THREEBYTES;
- """)
- def cb():
- return (12, 34, 56)
- fptr = ffi.callback("THREEBYTES(*)(void)", cb)
- tb = fptr()
- assert tb.a == 12
- assert tb.b == 34
- assert tb.c == 56
-
- def test_passing_array(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int strlen(char[]);
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- p = ffi.new("char[]", b"hello")
- res = ffi.C.strlen(p)
- assert res == 5
-
- def test_write_variable(self):
- if not sys.platform.startswith('linux'):
- py.test.skip("probably no symbol 'stdout' in the lib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- extern void *stdout;
- """)
- needs_dlopen_none()
- C = ffi.dlopen(None)
- pout = C.stdout
- C.stdout = ffi.NULL
- assert C.stdout == ffi.NULL
- C.stdout = pout
- assert C.stdout == pout
-
- def test_strchr(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- char *strchr(const char *s, int c);
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- p = ffi.new("char[]", b"hello world!")
- q = ffi.C.strchr(p, ord('w'))
- assert ffi.string(q) == b"world!"
-
- def test_function_with_struct_argument(self):
- if sys.platform == 'win32':
- py.test.skip("no 'inet_ntoa'")
- if (self.Backend is CTypesBackend and
- '__pypy__' in sys.builtin_module_names):
- py.test.skip("ctypes limitation on pypy")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- struct in_addr { unsigned int s_addr; };
- char *inet_ntoa(struct in_addr in);
- """)
- needs_dlopen_none()
- ffi.C = ffi.dlopen(None)
- ina = ffi.new("struct in_addr *", [0x04040404])
- a = ffi.C.inet_ntoa(ina[0])
- assert ffi.string(a) == b'4.4.4.4'
-
- def test_function_typedef(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- typedef double func_t(double);
- func_t sin;
- """)
- m = ffi.dlopen(lib_m)
- x = m.sin(1.23)
- assert x == math.sin(1.23)
-
- def test_fputs_custom_FILE(self):
- if self.Backend is CTypesBackend:
- py.test.skip("FILE not supported with the ctypes backend")
- filename = str(udir.join('fputs_custom_FILE'))
- ffi = FFI(backend=self.Backend())
- ffi.cdef("int fputs(const char *, FILE *);")
- needs_dlopen_none()
- C = ffi.dlopen(None)
- with open(filename, 'wb') as f:
- f.write(b'[')
- C.fputs(b"hello from custom file", f)
- f.write(b'][')
- C.fputs(b"some more output", f)
- f.write(b']')
- with open(filename, 'rb') as f:
- res = f.read()
- assert res == b'[hello from custom file][some more output]'
-
- def test_constants_on_lib(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""enum foo_e { AA, BB, CC=5, DD };
- typedef enum { EE=-5, FF } some_enum_t;""")
- needs_dlopen_none()
- lib = ffi.dlopen(None)
- assert lib.AA == 0
- assert lib.BB == 1
- assert lib.CC == 5
- assert lib.DD == 6
- assert lib.EE == -5
- assert lib.FF == -4
-
- def test_void_star_accepts_string(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""int strlen(const void *);""")
- needs_dlopen_none()
- lib = ffi.dlopen(None)
- res = lib.strlen(b"hello")
- assert res == 5
-
- def test_signed_char_star_accepts_string(self):
- if self.Backend is CTypesBackend:
- py.test.skip("not supported by the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""int strlen(signed char *);""")
- needs_dlopen_none()
- lib = ffi.dlopen(None)
- res = lib.strlen(b"hello")
- assert res == 5
-
- def test_unsigned_char_star_accepts_string(self):
- if self.Backend is CTypesBackend:
- py.test.skip("not supported by the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""int strlen(unsigned char *);""")
- needs_dlopen_none()
- lib = ffi.dlopen(None)
- res = lib.strlen(b"hello")
- assert res == 5
-
- def test_missing_function(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int nonexistent();
- """)
- m = ffi.dlopen(lib_m)
- assert not hasattr(m, 'nonexistent')
-
- def test_wraps_from_stdlib(self):
- import functools
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- double sin(double x);
- """)
- def my_decorator(f):
- @functools.wraps(f)
- def wrapper(*args):
- return f(*args) + 100
- return wrapper
- m = ffi.dlopen(lib_m)
- sin100 = my_decorator(m.sin)
- x = sin100(1.23)
- assert x == math.sin(1.23) + 100
-
- def test_free_callback_cycle(self):
- if self.Backend is CTypesBackend:
- py.test.skip("seems to fail with the ctypes backend on windows")
- import weakref
- def make_callback(data):
- container = [data]
- callback = ffi.callback('int()', lambda: len(container))
- container.append(callback)
- # Ref cycle: callback -> lambda (closure) -> container -> callback
- return callback
-
- class Data(object):
- pass
- ffi = FFI(backend=self.Backend())
- data = Data()
- callback = make_callback(data)
- wr = weakref.ref(data)
- del callback, data
- for i in range(3):
- if wr() is not None:
- import gc; gc.collect()
- assert wr() is None # 'data' does not leak
-
- def test_windows_stdcall(self):
- if sys.platform != 'win32':
- py.test.skip("Windows-only test")
- if self.Backend is CTypesBackend:
- py.test.skip("not with the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
- """)
- m = ffi.dlopen("Kernel32.dll")
- p_freq = ffi.new("LONGLONG *")
- res = m.QueryPerformanceFrequency(p_freq)
- assert res != 0
- assert p_freq[0] != 0
-
- def test_explicit_cdecl_stdcall(self):
- if sys.platform != 'win32':
- py.test.skip("Windows-only test")
- if self.Backend is CTypesBackend:
- py.test.skip("not with the ctypes backend")
- win64 = (sys.maxsize > 2**32)
- #
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
- """)
- m = ffi.dlopen("Kernel32.dll")
- tp = ffi.typeof(m.QueryPerformanceFrequency)
- assert str(tp) == "<ctype 'int(*)(long long *)'>"
- #
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- BOOL __cdecl QueryPerformanceFrequency(LONGLONG *lpFrequency);
- """)
- m = ffi.dlopen("Kernel32.dll")
- tpc = ffi.typeof(m.QueryPerformanceFrequency)
- assert tpc is tp
- #
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- BOOL WINAPI QueryPerformanceFrequency(LONGLONG *lpFrequency);
- """)
- m = ffi.dlopen("Kernel32.dll")
- tps = ffi.typeof(m.QueryPerformanceFrequency)
- if win64:
- assert tps is tpc
- else:
- assert tps is not tpc
- assert str(tps) == "<ctype 'int(__stdcall *)(long long *)'>"
- #
- ffi = FFI(backend=self.Backend())
- ffi.cdef("typedef int (__cdecl *fnc_t)(int);")
- ffi.cdef("typedef int (__stdcall *fns_t)(int);")
- tpc = ffi.typeof("fnc_t")
- tps = ffi.typeof("fns_t")
- assert str(tpc) == "<ctype 'int(*)(int)'>"
- if win64:
- assert tps is tpc
- else:
- assert str(tps) == "<ctype 'int(__stdcall *)(int)'>"
- #
- fnc = ffi.cast("fnc_t", 0)
- fns = ffi.cast("fns_t", 0)
- ffi.new("fnc_t[]", [fnc])
- if not win64:
- py.test.raises(TypeError, ffi.new, "fnc_t[]", [fns])
- py.test.raises(TypeError, ffi.new, "fns_t[]", [fnc])
- ffi.new("fns_t[]", [fns])
-
- def test_stdcall_only_on_windows(self):
- 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.maxsize < 2**32 and
- self.Backend is not CTypesBackend):
- assert "double(__stdcall *)(double)" in str(ffi.typeof(m.sin))
- else:
- assert "double(*)(double)" in str(ffi.typeof(m.sin))
- x = m.sin(1.23)
- assert x == math.sin(1.23)
-
- def test_dir_on_dlopen_lib(self):
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- typedef enum { MYE1, MYE2 } myenum_t;
- double myfunc(double);
- extern double myvar;
- const double myconst;
- #define MYFOO 42
- """)
- m = ffi.dlopen(lib_m)
- assert dir(m) == ['MYE1', 'MYE2', 'MYFOO', 'myconst', 'myfunc', 'myvar']
-
- def test_dlclose(self):
- if self.Backend is CTypesBackend:
- py.test.skip("not with the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("int foobar(void); extern int foobaz;")
- lib = ffi.dlopen(lib_m)
- ffi.dlclose(lib)
- e = py.test.raises(ValueError, getattr, lib, 'foobar')
- assert str(e.value).startswith("library '")
- assert str(e.value).endswith("' has already been closed")
- e = py.test.raises(ValueError, getattr, lib, 'foobaz')
- assert str(e.value).startswith("library '")
- assert str(e.value).endswith("' has already been closed")
- e = py.test.raises(ValueError, setattr, lib, 'foobaz', 42)
- assert str(e.value).startswith("library '")
- assert str(e.value).endswith("' has already been closed")
- ffi.dlclose(lib) # does not raise
-
- def test_passing_large_list(self):
- if self.Backend is CTypesBackend:
- py.test.skip("the ctypes backend doesn't support this")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- void getenv(char *);
- """)
- needs_dlopen_none()
- m = ffi.dlopen(None)
- arg = [b"F", b"O", b"O"] + [b"\x00"] * 20000000
- x = m.getenv(arg)
- assert x is None
diff --git a/testing/cffi0/test_model.py b/testing/cffi0/test_model.py
deleted file mode 100644
index bb653ca..0000000
--- a/testing/cffi0/test_model.py
+++ /dev/null
@@ -1,111 +0,0 @@
-from cffi.model import *
-
-
-def test_void_type():
- assert void_type.get_c_name() == "void"
- assert void_type.get_c_name("foo") == "void foo"
- assert void_type.get_c_name("*foo") == "void *foo"
-
-def test_primitive_type():
- int_type = PrimitiveType("int")
- assert int_type.get_c_name() == "int"
- assert int_type.get_c_name("foo") == "int foo"
- assert int_type.get_c_name("*foo") == "int *foo"
- assert int_type.get_c_name("[5]") == "int[5]"
-
-def test_raw_function_type():
- int_type = PrimitiveType("int")
- fn_type = RawFunctionType([], int_type, False)
- assert fn_type.get_c_name() == "int()(void)"
- assert fn_type.get_c_name("*") == "int( *)(void)"
- assert fn_type.get_c_name("*foo") == "int( *foo)(void)"
- fn_type = RawFunctionType([int_type], int_type, False)
- assert fn_type.get_c_name() == "int()(int)"
- fn_type = RawFunctionType([int_type] * 2, int_type, False)
- assert fn_type.get_c_name() == "int()(int, int)"
- #
- fn_type = RawFunctionType([int_type], int_type, True)
- assert fn_type.get_c_name() == "int()(int, ...)"
- assert fn_type.get_c_name("*foo") == "int( *foo)(int, ...)"
- #
- res_type = FunctionPtrType([int_type], int_type, True)
- fn_type = RawFunctionType([int_type], res_type, True)
- assert fn_type.get_c_name("x") == "int(*( x)(int, ...))(int, ...)"
-
-def test_function_ptr_type():
- int_type = PrimitiveType("int")
- fn_type = FunctionPtrType([], int_type, False)
- assert fn_type.get_c_name() == "int(*)(void)"
- assert fn_type.get_c_name("*") == "int(* *)(void)"
- assert fn_type.get_c_name("*foo") == "int(* *foo)(void)"
- fn_type = FunctionPtrType([int_type], int_type, False)
- assert fn_type.get_c_name() == "int(*)(int)"
- fn_type = FunctionPtrType([int_type] * 2, int_type, False)
- assert fn_type.get_c_name() == "int(*)(int, int)"
- #
- fn_type = FunctionPtrType([int_type], int_type, True)
- assert fn_type.get_c_name() == "int(*)(int, ...)"
-
-def test_pointer_type():
- ptr_type = PointerType(PrimitiveType("int"))
- assert ptr_type.get_c_name("x") == "int * x"
-
-def test_const_pointer_type():
- ptr_type = ConstPointerType(PrimitiveType("int"))
- assert ptr_type.get_c_name("x") == "int const * x"
- ptr_type = ConstPointerType(ArrayType(PrimitiveType("int"), 5))
- assert ptr_type.get_c_name("") == "int(const *)[5]"
- assert ptr_type.get_c_name("*x") == "int(const * *x)[5]"
-
-def test_qual_pointer_type():
- ptr_type = PointerType(PrimitiveType("long long"), Q_RESTRICT)
- assert ptr_type.get_c_name("") == "long long __restrict *"
- assert const_voidp_type.get_c_name("") == "void const *"
-
-def test_unknown_pointer_type():
- ptr_type = unknown_ptr_type("foo_p")
- assert ptr_type.get_c_name("") == "foo_p"
- assert ptr_type.get_c_name("x") == "foo_p x"
-
-def test_unknown_type():
- u_type = unknown_type("foo_t")
- assert u_type.get_c_name("") == "foo_t"
- assert u_type.get_c_name("x") == "foo_t x"
-
-def test_array_type():
- a_type = ArrayType(PrimitiveType("int"), None)
- assert a_type.get_c_name("") == "int[]"
- assert a_type.get_c_name("x") == "int x[]"
- assert a_type.get_c_name("*x") == "int(*x)[]"
- assert a_type.get_c_name(" *x") == "int(*x)[]"
- assert a_type.get_c_name("[5]") == "int[5][]"
- a_type = ArrayType(unknown_type("foo_t"), 5)
- assert a_type.get_c_name("") == "foo_t[5]"
- assert a_type.get_c_name("x") == "foo_t x[5]"
- assert a_type.get_c_name("*x") == "foo_t(*x)[5]"
- a_type = ArrayType(unknown_ptr_type("foo_p"), None)
- assert a_type.get_c_name("") == "foo_p[]"
- assert a_type.get_c_name("x") == "foo_p x[]"
- assert a_type.get_c_name("*x") == "foo_p(*x)[]"
- a_type = ArrayType(ConstPointerType(PrimitiveType("int")), None)
- assert a_type.get_c_name("") == "int const *[]"
- assert a_type.get_c_name("x") == "int const * x[]"
- assert a_type.get_c_name("*x") == "int const *(*x)[]"
- fn_type = FunctionPtrType([], PrimitiveType("int"), False)
- a_type = ArrayType(fn_type, 5)
- assert a_type.get_c_name("") == "int(*[5])(void)"
- assert a_type.get_c_name("x") == "int(* x[5])(void)"
- assert a_type.get_c_name("*x") == "int(*(*x)[5])(void)"
-
-def test_struct_type():
- struct_type = StructType("foo_s", None, None, None)
- assert struct_type.get_c_name() == "struct foo_s"
- assert struct_type.get_c_name("*x") == "struct foo_s *x"
-
-def test_union_type():
- union_type = UnionType("foo_s", None, None, None)
- assert union_type.get_c_name() == "union foo_s"
-
-def test_enum_type():
- enum_type = EnumType("foo_e", [], [])
- assert enum_type.get_c_name() == "enum foo_e"
diff --git a/testing/cffi0/test_ownlib.py b/testing/cffi0/test_ownlib.py
deleted file mode 100644
index ffad879..0000000
--- a/testing/cffi0/test_ownlib.py
+++ /dev/null
@@ -1,431 +0,0 @@
-import py, sys, os
-import subprocess, weakref
-from cffi import FFI
-from cffi.backend_ctypes import CTypesBackend
-from testing.support import u
-
-
-SOURCE = """\
-#include <errno.h>
-
-#ifdef _WIN32
-#define EXPORT __declspec(dllexport)
-#else
-#define EXPORT
-#endif
-
-EXPORT int test_getting_errno(void) {
- errno = 123;
- return -1;
-}
-
-EXPORT int test_setting_errno(void) {
- return errno;
-};
-
-typedef struct {
- long x;
- long y;
-} POINT;
-
-typedef struct {
- long left;
- long top;
- long right;
- long bottom;
-} RECT;
-
-typedef struct {
- unsigned char a, b, c;
-} THREEBYTES;
-
-
-EXPORT int PointInRect(RECT *prc, POINT pt)
-{
- if (pt.x < prc->left)
- return 0;
- if (pt.x > prc->right)
- return 0;
- if (pt.y < prc->top)
- return 0;
- if (pt.y > prc->bottom)
- return 0;
- return 1;
-};
-
-EXPORT long left = 10;
-EXPORT long top = 20;
-EXPORT long right = 30;
-EXPORT long bottom = 40;
-
-EXPORT RECT ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr,
- RECT *er, POINT fp, RECT gr)
-{
- /*Check input */
- if (ar.left + br->left + dr.left + er->left + gr.left != left * 5)
- {
- ar.left = 100;
- return ar;
- }
- if (ar.right + br->right + dr.right + er->right + gr.right != right * 5)
- {
- ar.right = 100;
- return ar;
- }
- if (cp.x != fp.x)
- {
- ar.left = -100;
- }
- if (cp.y != fp.y)
- {
- ar.left = -200;
- }
- switch(i)
- {
- case 0:
- return ar;
- break;
- case 1:
- return dr;
- break;
- case 2:
- return gr;
- break;
-
- }
- return ar;
-}
-
-EXPORT int my_array[7] = {0, 1, 2, 3, 4, 5, 6};
-
-EXPORT unsigned short foo_2bytes(unsigned short a)
-{
- return (unsigned short)(a + 42);
-}
-EXPORT unsigned int foo_4bytes(unsigned int a)
-{
- return (unsigned int)(a + 42);
-}
-
-EXPORT void modify_struct_value(RECT r)
-{
- r.left = r.right = r.top = r.bottom = 500;
-}
-
-EXPORT THREEBYTES return_three_bytes(void)
-{
- THREEBYTES result;
- result.a = 12;
- result.b = 34;
- result.c = 56;
- return result;
-}
-"""
-
-class TestOwnLib(object):
- Backend = CTypesBackend
-
- def setup_class(cls):
- cls.module = None
- from testing.udir import udir
- udir.join('testownlib.c').write(SOURCE)
- if sys.platform == 'win32':
- # did we already build it?
- if cls.Backend is CTypesBackend:
- dll_path = str(udir) + '\\testownlib1.dll' # only ascii for the ctypes backend
- else:
- dll_path = str(udir) + '\\' + (u+'testownlib\u03be.dll') # non-ascii char
- if os.path.exists(dll_path):
- cls.module = dll_path
- return
- # try (not too hard) to find the version used to compile this python
- # no mingw
- from distutils.msvc9compiler import get_build_version
- version = get_build_version()
- toolskey = "VS%0.f0COMNTOOLS" % version
- toolsdir = os.environ.get(toolskey, None)
- if toolsdir is None:
- return
- productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
- productdir = os.path.abspath(productdir)
- vcvarsall = os.path.join(productdir, "vcvarsall.bat")
- # 64?
- arch = 'x86'
- if sys.maxsize > 2**32:
- arch = 'amd64'
- if os.path.isfile(vcvarsall):
- cmd = '"%s" %s' % (vcvarsall, arch) + ' & cl.exe testownlib.c ' \
- ' /LD /Fetestownlib.dll'
- subprocess.check_call(cmd, cwd = str(udir), shell=True)
- os.rename(str(udir) + '\\testownlib.dll', dll_path)
- cls.module = dll_path
- else:
- encoded = None
- if cls.Backend is not CTypesBackend:
- try:
- unicode_name = u+'testownlibcaf\xe9'
- encoded = unicode_name.encode(sys.getfilesystemencoding())
- if sys.version_info >= (3,):
- encoded = str(unicode_name)
- except UnicodeEncodeError:
- pass
- if encoded is None:
- unicode_name = u+'testownlib'
- encoded = str(unicode_name)
- subprocess.check_call(
- "cc testownlib.c -shared -fPIC -o '%s.so'" % (encoded,),
- cwd=str(udir), shell=True)
- cls.module = os.path.join(str(udir), unicode_name + (u+'.so'))
- print(repr(cls.module))
-
- def test_getting_errno(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- if sys.platform == 'win32':
- py.test.skip("fails, errno at multiple addresses")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int test_getting_errno(void);
- """)
- ownlib = ffi.dlopen(self.module)
- res = ownlib.test_getting_errno()
- assert res == -1
- assert ffi.errno == 123
-
- def test_setting_errno(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- if sys.platform == 'win32':
- py.test.skip("fails, errno at multiple addresses")
- if self.Backend is CTypesBackend and '__pypy__' in sys.modules:
- py.test.skip("XXX errno issue with ctypes on pypy?")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int test_setting_errno(void);
- """)
- ownlib = ffi.dlopen(self.module)
- ffi.errno = 42
- res = ownlib.test_setting_errno()
- assert res == 42
- assert ffi.errno == 42
-
- def test_my_array_7(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- extern int my_array[7];
- """)
- ownlib = ffi.dlopen(self.module)
- for i in range(7):
- assert ownlib.my_array[i] == i
- assert len(ownlib.my_array) == 7
- if self.Backend is CTypesBackend:
- py.test.skip("not supported by the ctypes backend")
- ownlib.my_array = list(range(10, 17))
- for i in range(7):
- assert ownlib.my_array[i] == 10 + i
- ownlib.my_array = list(range(7))
- for i in range(7):
- assert ownlib.my_array[i] == i
-
- def test_my_array_no_length(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- if self.Backend is CTypesBackend:
- py.test.skip("not supported by the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- extern int my_array[];
- """)
- ownlib = ffi.dlopen(self.module)
- for i in range(7):
- assert ownlib.my_array[i] == i
- py.test.raises(TypeError, len, ownlib.my_array)
- ownlib.my_array = list(range(10, 17))
- for i in range(7):
- assert ownlib.my_array[i] == 10 + i
- ownlib.my_array = list(range(7))
- for i in range(7):
- assert ownlib.my_array[i] == i
-
- def test_keepalive_lib(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int test_getting_errno(void);
- """)
- ownlib = ffi.dlopen(self.module)
- ffi_r = weakref.ref(ffi)
- ownlib_r = weakref.ref(ownlib)
- func = ownlib.test_getting_errno
- del ffi
- import gc; gc.collect() # ownlib stays alive
- assert ownlib_r() is not None
- assert ffi_r() is not None # kept alive by ownlib
- res = func()
- assert res == -1
-
- def test_keepalive_ffi(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- int test_getting_errno(void);
- """)
- ownlib = ffi.dlopen(self.module)
- ffi_r = weakref.ref(ffi)
- ownlib_r = weakref.ref(ownlib)
- func = ownlib.test_getting_errno
- del ownlib
- import gc; gc.collect() # ffi stays alive
- assert ffi_r() is not None
- assert ownlib_r() is not None # kept alive by ffi
- res = func()
- assert res == -1
- if sys.platform != 'win32': # else, errno at multiple addresses
- assert ffi.errno == 123
-
- def test_struct_by_value(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- typedef struct {
- long x;
- long y;
- } POINT;
-
- typedef struct {
- long left;
- long top;
- long right;
- long bottom;
- } RECT;
-
- extern long left, top, right, bottom;
-
- RECT ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr,
- RECT *er, POINT fp, RECT gr);
- """)
- ownlib = ffi.dlopen(self.module)
-
- rect = ffi.new('RECT[1]')
- pt = ffi.new('POINT[1]')
- pt[0].x = 15
- pt[0].y = 25
- rect[0].left = ownlib.left
- rect[0].right = ownlib.right
- rect[0].top = ownlib.top
- rect[0].bottom = ownlib.bottom
-
- for i in range(4):
- ret = ownlib.ReturnRect(i, rect[0], rect, pt[0], rect[0],
- rect, pt[0], rect[0])
- assert ret.left == ownlib.left
- assert ret.right == ownlib.right
- assert ret.top == ownlib.top
- assert ret.bottom == ownlib.bottom
-
- def test_addressof_lib(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- if self.Backend is CTypesBackend:
- py.test.skip("not implemented with the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("extern long left; int test_getting_errno(void);")
- lib = ffi.dlopen(self.module)
- lib.left = 123456
- p = ffi.addressof(lib, "left")
- assert ffi.typeof(p) == ffi.typeof("long *")
- assert p[0] == 123456
- p[0] += 1
- assert lib.left == 123457
- pfn = ffi.addressof(lib, "test_getting_errno")
- assert ffi.typeof(pfn) == ffi.typeof("int(*)(void)")
- assert pfn == lib.test_getting_errno
-
- def test_char16_char32_t(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- if self.Backend is CTypesBackend:
- py.test.skip("not implemented with the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- char16_t foo_2bytes(char16_t);
- char32_t foo_4bytes(char32_t);
- """)
- lib = ffi.dlopen(self.module)
- assert lib.foo_2bytes(u+'\u1234') == u+'\u125e'
- assert lib.foo_4bytes(u+'\u1234') == u+'\u125e'
- assert lib.foo_4bytes(u+'\U00012345') == u+'\U0001236f'
-
- def test_modify_struct_value(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- if self.Backend is CTypesBackend:
- py.test.skip("fails with the ctypes backend on some architectures")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- typedef struct {
- long left;
- long top;
- long right;
- long bottom;
- } RECT;
-
- void modify_struct_value(RECT r);
- """)
- lib = ffi.dlopen(self.module)
- s = ffi.new("RECT *", [11, 22, 33, 44])
- lib.modify_struct_value(s[0])
- assert s.left == 11
- assert s.top == 22
- assert s.right == 33
- assert s.bottom == 44
-
- def test_dlopen_handle(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- if sys.platform == 'win32':
- py.test.skip("uses 'dl' explicitly")
- if self.__class__.Backend is CTypesBackend:
- py.test.skip("not for the ctypes backend")
- backend = self.Backend()
- ffi1 = FFI(backend=backend)
- ffi1.cdef("""void *dlopen(const char *filename, int flags);
- int dlclose(void *handle);""")
- lib1 = ffi1.dlopen('dl')
- handle = lib1.dlopen(self.module.encode(sys.getfilesystemencoding()),
- backend.RTLD_LAZY)
- assert ffi1.typeof(handle) == ffi1.typeof("void *")
- assert handle
-
- ffi = FFI(backend=backend)
- ffi.cdef("""unsigned short foo_2bytes(unsigned short a);""")
- lib = ffi.dlopen(handle)
- x = lib.foo_2bytes(1000)
- assert x == 1042
-
- err = lib1.dlclose(handle)
- assert err == 0
-
- def test_return_three_bytes(self):
- if self.module is None:
- py.test.skip("fix the auto-generation of the tiny test lib")
- if self.__class__.Backend is CTypesBackend:
- py.test.skip("not working on win32 on the ctypes backend")
- ffi = FFI(backend=self.Backend())
- ffi.cdef("""
- typedef struct {
- unsigned char a, b, c;
- } THREEBYTES;
-
- THREEBYTES return_three_bytes(void);
- """)
- lib = ffi.dlopen(self.module)
- tb = lib.return_three_bytes()
- assert tb.a == 12
- assert tb.b == 34
- assert tb.c == 56
diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py
deleted file mode 100644
index a5e4587..0000000
--- a/testing/cffi0/test_parsing.py
+++ /dev/null
@@ -1,610 +0,0 @@
-import py, sys, re
-from cffi import FFI, FFIError, CDefError, VerificationError
-from .backend_tests import needs_dlopen_none
-
-
-class FakeBackend(object):
-
- def nonstandard_integer_types(self):
- return {}
-
- def sizeof(self, name):
- return 1
-
- def load_library(self, name, flags):
- if sys.platform == 'win32':
- assert name is None or "msvcr" in name
- else:
- assert name is None or "libc" in name or "libm" in name
- return FakeLibrary()
-
- def new_function_type(self, args, result, has_varargs):
- args = [arg.cdecl for arg in args]
- result = result.cdecl
- return FakeType(
- '<func (%s), %s, %s>' % (', '.join(args), result, has_varargs))
-
- def new_primitive_type(self, name):
- assert name == name.lower()
- return FakeType('<%s>' % name)
-
- def new_pointer_type(self, itemtype):
- return FakeType('<pointer to %s>' % (itemtype,))
-
- def new_struct_type(self, name):
- return FakeStruct(name)
-
- def complete_struct_or_union(self, s, fields, tp=None,
- totalsize=-1, totalalignment=-1, sflags=0):
- assert isinstance(s, FakeStruct)
- s.fields = fields
-
- def new_array_type(self, ptrtype, length):
- return FakeType('<array %s x %s>' % (ptrtype, length))
-
- def new_void_type(self):
- return FakeType("<void>")
- def cast(self, x, y):
- return 'casted!'
- def _get_types(self):
- return "CData", "CType"
-
- buffer = "buffer type"
-
-class FakeType(object):
- def __init__(self, cdecl):
- self.cdecl = cdecl
- def __str__(self):
- return self.cdecl
-
-class FakeStruct(object):
- def __init__(self, name):
- self.name = name
- def __str__(self):
- return ', '.join([str(y) + str(x) for x, y, z in self.fields])
-
-class FakeLibrary(object):
-
- def load_function(self, BType, name):
- return FakeFunction(BType, name)
-
-class FakeFunction(object):
-
- def __init__(self, BType, name):
- self.BType = str(BType)
- self.name = name
-
-lib_m = "m"
-if sys.platform == 'win32':
- #there is a small chance this fails on Mingw via environ $CC
- import distutils.ccompiler
- if distutils.ccompiler.get_default_compiler() == 'msvc':
- lib_m = 'msvcrt'
-
-def test_simple():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("double sin(double x);")
- m = ffi.dlopen(lib_m)
- func = m.sin # should be a callable on real backends
- assert func.name == 'sin'
- assert func.BType == '<func (<double>), <double>, False>'
-
-def test_pipe():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("int pipe(int pipefd[2]);")
- needs_dlopen_none()
- C = ffi.dlopen(None)
- func = C.pipe
- assert func.name == 'pipe'
- assert func.BType == '<func (<pointer to <int>>), <int>, False>'
-
-def test_vararg():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("short foo(int, ...);")
- needs_dlopen_none()
- C = ffi.dlopen(None)
- func = C.foo
- assert func.name == 'foo'
- assert func.BType == '<func (<int>), <short>, True>'
-
-def test_no_args():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("""
- int foo(void);
- """)
- needs_dlopen_none()
- C = ffi.dlopen(None)
- assert C.foo.BType == '<func (), <int>, False>'
-
-def test_typedef():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("""
- typedef unsigned int UInt;
- typedef UInt UIntReally;
- UInt foo(void);
- """)
- needs_dlopen_none()
- C = ffi.dlopen(None)
- assert str(ffi.typeof("UIntReally")) == '<unsigned int>'
- assert C.foo.BType == '<func (), <unsigned int>, False>'
-
-def test_typedef_more_complex():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("""
- typedef struct { int a, b; } foo_t, *foo_p;
- int foo(foo_p[]);
- """)
- needs_dlopen_none()
- C = ffi.dlopen(None)
- assert str(ffi.typeof("foo_t")) == '<int>a, <int>b'
- assert str(ffi.typeof("foo_p")) == '<pointer to <int>a, <int>b>'
- assert C.foo.BType == ('<func (<pointer to <pointer to '
- '<int>a, <int>b>>), <int>, False>')
-
-def test_typedef_array_convert_array_to_pointer():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("""
- typedef int (*fn_t)(int[5]);
- """)
- with ffi._lock:
- type = ffi._parser.parse_type("fn_t")
- BType = ffi._get_cached_btype(type)
- assert str(BType) == '<func (<pointer to <int>>), <int>, False>'
-
-def test_remove_comments():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("""
- double /*comment here*/ sin // blah blah
- /* multi-
- line-
- //comment */ (
- // foo
- double // bar /* <- ignored, because it's in a comment itself
- x, double/*several*//*comment*/y) /*on the same line*/
- ;
- """)
- m = ffi.dlopen(lib_m)
- func = m.sin
- assert func.name == 'sin'
- assert func.BType == '<func (<double>, <double>), <double>, False>'
-
-def test_remove_line_continuation_comments():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("""
- double // blah \\
- more comments
- x(void);
- double // blah // blah\\\\
- y(void);
- double // blah\\ \
- etc
- z(void);
- """)
- m = ffi.dlopen(lib_m)
- m.x
- m.y
- m.z
-
-def test_dont_remove_comment_in_line_directives():
- ffi = FFI(backend=FakeBackend())
- e = py.test.raises(CDefError, ffi.cdef, """
- \t # \t line \t 8 \t "baz.c" \t
-
- some syntax error here
- """)
- assert str(e.value) == "parse error\nbaz.c:9:14: before: syntax"
- #
- e = py.test.raises(CDefError, ffi.cdef, """
- #line 7 "foo//bar.c"
-
- some syntax error here
- """)
- #
- assert str(e.value) == "parse error\nfoo//bar.c:8:14: before: syntax"
- ffi = FFI(backend=FakeBackend())
- e = py.test.raises(CDefError, ffi.cdef, """
- \t # \t 8 \t "baz.c" \t
-
- some syntax error here
- """)
- assert str(e.value) == "parse error\nbaz.c:9:14: before: syntax"
- #
- e = py.test.raises(CDefError, ffi.cdef, """
- # 7 "foo//bar.c"
-
- some syntax error here
- """)
- assert str(e.value) == "parse error\nfoo//bar.c:8:14: before: syntax"
-
-def test_multiple_line_directives():
- ffi = FFI(backend=FakeBackend())
- e = py.test.raises(CDefError, ffi.cdef,
- """ #line 5 "foo.c"
- extern int xx;
- #line 6 "bar.c"
- extern int yy;
- #line 7 "baz.c"
- some syntax error here
- #line 8 "yadda.c"
- extern int zz;
- """)
- assert str(e.value) == "parse error\nbaz.c:7:14: before: syntax"
- #
- e = py.test.raises(CDefError, ffi.cdef,
- """ # 5 "foo.c"
- extern int xx;
- # 6 "bar.c"
- extern int yy;
- # 7 "baz.c"
- some syntax error here
- # 8 "yadda.c"
- extern int zz;
- """)
- assert str(e.value) == "parse error\nbaz.c:7:14: before: syntax"
-
-def test_commented_line_directive():
- ffi = FFI(backend=FakeBackend())
- e = py.test.raises(CDefError, ffi.cdef, """
- /*
- #line 5 "foo.c"
- */
- void xx(void);
-
- #line 6 "bar.c"
- /*
- #line 35 "foo.c"
- */
- some syntax error
- """)
- #
- assert str(e.value) == "parse error\nbar.c:9:14: before: syntax"
- e = py.test.raises(CDefError, ffi.cdef, """
- /*
- # 5 "foo.c"
- */
- void xx(void);
-
- # 6 "bar.c"
- /*
- # 35 "foo.c"
- */
- some syntax error
- """)
- assert str(e.value) == "parse error\nbar.c:9:14: before: syntax"
-
-def test_line_continuation_in_defines():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("""
- #define ABC\\
- 42
- #define BCD \\
- 43
- """)
- m = ffi.dlopen(lib_m)
- assert m.ABC == 42
- assert m.BCD == 43
-
-def test_define_not_supported_for_now():
- ffi = FFI(backend=FakeBackend())
- e = py.test.raises(CDefError, ffi.cdef, '#define FOO "blah"')
- assert str(e.value) == (
- 'only supports one of the following syntax:\n'
- ' #define FOO ... (literally dot-dot-dot)\n'
- ' #define FOO NUMBER (with NUMBER an integer'
- ' constant, decimal/hex/octal)\n'
- 'got:\n'
- ' #define FOO "blah"')
-
-def test_unnamed_struct():
- ffi = FFI(backend=FakeBackend())
- ffi.cdef("typedef struct { int x; } foo_t;\n"
- "typedef struct { int y; } *bar_p;\n")
- assert 'typedef foo_t' in ffi._parser._declarations
- assert 'typedef bar_p' in ffi._parser._declarations
- assert 'anonymous foo_t' in ffi._parser._declarations
- type_foo = ffi._parser.parse_type("foo_t")
- type_bar = ffi._parser.parse_type("bar_p").totype
- assert repr(type_foo) == "<foo_t>"
- assert repr(type_bar) == "<struct $1>"
- py.test.raises(VerificationError, type_bar.get_c_name)
- assert type_foo.get_c_name() == "foo_t"
-
-def test_override():
- ffi = FFI(backend=FakeBackend())
- needs_dlopen_none()
- C = ffi.dlopen(None)
- ffi.cdef("int foo(void);")
- py.test.raises(FFIError, ffi.cdef, "long foo(void);")
- assert C.foo.BType == '<func (), <int>, False>'
- ffi.cdef("long foo(void);", override=True)
- assert C.foo.BType == '<func (), <long>, False>'
-
-def test_cannot_have_only_variadic_part():
- # this checks that we get a sensible error if we try "int foo(...);"
- ffi = FFI()
- e = py.test.raises(CDefError, ffi.cdef, "int foo(...);")
- assert str(e.value) == (
- "<cdef source string>:1: foo: a function with only '(...)' "
- "as argument is not correct C")
-
-def test_parse_error():
- ffi = FFI()
- e = py.test.raises(CDefError, ffi.cdef, " x y z ")
- assert str(e.value).startswith(
- 'cannot parse "x y z"\n<cdef source string>:1:')
- e = py.test.raises(CDefError, ffi.cdef, "\n\n\n x y z ")
- assert str(e.value).startswith(
- 'cannot parse "x y z"\n<cdef source string>:4:')
-
-def test_error_custom_lineno():
- ffi = FFI()
- e = py.test.raises(CDefError, ffi.cdef, """
-# 42 "foobar"
-
- a b c d
- """)
- assert str(e.value).startswith('parse error\nfoobar:43:')
-
-def test_cannot_declare_enum_later():
- ffi = FFI()
- e = py.test.raises(NotImplementedError, ffi.cdef,
- "typedef enum foo_e foo_t; enum foo_e { AA, BB };")
- assert str(e.value) == (
- "enum foo_e: the '{}' declaration should appear on the "
- "first time the enum is mentioned, not later")
-
-def test_unknown_name():
- ffi = FFI()
- e = py.test.raises(CDefError, ffi.cast, "foobarbazunknown", 0)
- assert str(e.value) == "unknown identifier 'foobarbazunknown'"
- e = py.test.raises(CDefError, ffi.cast, "foobarbazunknown*", 0)
- assert str(e.value).startswith('cannot parse "foobarbazunknown*"')
- e = py.test.raises(CDefError, ffi.cast, "int(*)(foobarbazunknown)", 0)
- assert str(e.value).startswith('cannot parse "int(*)(foobarbazunknown)"')
-
-def test_redefine_common_type():
- prefix = "" if sys.version_info < (3,) else "b"
- ffi = FFI()
- ffi.cdef("typedef char FILE;")
- assert repr(ffi.cast("FILE", 123)) == "<cdata 'char' %s'{'>" % prefix
- ffi.cdef("typedef char int32_t;")
- assert repr(ffi.cast("int32_t", 123)) == "<cdata 'char' %s'{'>" % prefix
- ffi = FFI()
- ffi.cdef("typedef int bool, *FILE;")
- assert repr(ffi.cast("bool", 123)) == "<cdata 'int' 123>"
- 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 "( )"
-
-def test_bool():
- ffi = FFI()
- ffi.cdef("void f(bool);")
- #
- 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) == ("<cdef source string>:1: 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;"
- "typedef void_t1 void_t;"
- "typedef int (*func_t)(void_t);")
- assert ffi.typeof("func_t").args == ()
-
-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():
- import warnings
- for input, expected_output in [
- ("int a;", False),
- ("const int a;", True),
- ("int *a;", False),
- ("const int *a;", False),
- ("int const *a;", False),
- ("int *const a;", True),
- ("int a[5];", False),
- ("const int a[5];", False),
- ("int *a[5];", False),
- ("const int *a[5];", False),
- ("int const *a[5];", False),
- ("int *const a[5];", False),
- ("int a[5][6];", False),
- ("const int a[5][6];", False),
- ]:
- ffi = FFI()
- with warnings.catch_warnings(record=True) as log:
- warnings.simplefilter("always")
- ffi.cdef(input)
- declarations = ffi._parser._declarations
- assert ('constant a' in declarations) == expected_output
- assert ('variable a' in declarations) == (not expected_output)
- assert len(log) == (1 - expected_output)
-
-def test_restrict():
- from cffi import model
- for input, expected_output in [
- ("int a;", False),
- ("restrict int a;", True),
- ("int *a;", False),
- ]:
- ffi = FFI()
- ffi.cdef("extern " + input)
- tp, quals = ffi._parser._declarations['variable a']
- assert bool(quals & model.Q_RESTRICT) == expected_output
-
-def test_different_const_funcptr_types():
- lst = []
- for input in [
- "int(*)(int *a)",
- "int(*)(int const *a)",
- "int(*)(int * const a)",
- "int(*)(int const a[])"]:
- ffi = FFI(backend=FakeBackend())
- lst.append(ffi._parser.parse_type(input))
- assert lst[0] != lst[1]
- 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("""
- enum Enum {
- POS = +1,
- TWO = 2,
- NIL = 0,
- NEG = -1,
- ADDSUB = (POS+TWO)-1,
- DIVMULINT = (3 * 3) / 2,
- SHIFT = (1 << 3) >> 1,
- BINOPS = (0x7 & 0x1) | 0x8,
- XOR = 0xf ^ 0xa
- };
- """)
- needs_dlopen_none()
- C = ffi.dlopen(None)
- assert C.POS == 1
- assert C.TWO == 2
- assert C.NIL == 0
- assert C.NEG == -1
- assert C.ADDSUB == 2
- assert C.DIVMULINT == 4
- assert C.SHIFT == 4
- assert C.BINOPS == 0b1001
- assert C.XOR == 0b0101
-
-def test_stdcall():
- ffi = FFI()
- tp = ffi.typeof("int(*)(int __stdcall x(int),"
- " long (__cdecl*y)(void),"
- " short(WINAPI *z)(short))")
- if sys.platform == 'win32' and sys.maxsize < 2**32:
- stdcall = '__stdcall '
- else:
- stdcall = ''
- assert str(tp) == (
- "<ctype 'int(*)(int(%s*)(int), "
- "long(*)(), "
- "short(%s*)(short))'>" % (stdcall, stdcall))
-
-def test_extern_python():
- ffi = FFI()
- ffi.cdef("""
- int bok(int, int);
- extern "Python" int foobar(int, int);
- int baz(int, int);
- """)
- assert sorted(ffi._parser._declarations) == [
- 'extern_python foobar', 'function baz', 'function bok']
- assert (ffi._parser._declarations['function bok'] ==
- ffi._parser._declarations['extern_python foobar'] ==
- ffi._parser._declarations['function baz'])
-
-def test_extern_python_group():
- ffi = FFI()
- ffi.cdef("""
- int bok(int);
- extern "Python" {int foobar(int, int);int bzrrr(int);}
- int baz(int, int);
- """)
- assert sorted(ffi._parser._declarations) == [
- 'extern_python bzrrr', 'extern_python foobar',
- 'function baz', 'function bok']
- assert (ffi._parser._declarations['function baz'] ==
- ffi._parser._declarations['extern_python foobar'] !=
- ffi._parser._declarations['function bok'] ==
- ffi._parser._declarations['extern_python bzrrr'])
-
-def test_error_invalid_syntax_for_cdef():
- ffi = FFI()
- e = py.test.raises(CDefError, ffi.cdef, 'void foo(void) {}')
- assert str(e.value) == ('<cdef source string>:1: unexpected <FuncDef>: '
- 'this construct is valid C but not valid in cdef()')
-
-def test_unsigned_int_suffix_for_constant():
- ffi = FFI()
- ffi.cdef("""enum e {
- bin_0=0b10,
- bin_1=0b10u,
- bin_2=0b10U,
- bin_3=0b10l,
- bin_4=0b10L,
- bin_5=0b10ll,
- bin_6=0b10LL,
- oct_0=010,
- oct_1=010u,
- oct_2=010U,
- oct_3=010l,
- oct_4=010L,
- oct_5=010ll,
- oct_6=010LL,
- dec_0=10,
- dec_1=10u,
- dec_2=10U,
- dec_3=10l,
- dec_4=10L,
- dec_5=10ll,
- dec_6=10LL,
- hex_0=0x10,
- hex_1=0x10u,
- hex_2=0x10U,
- hex_3=0x10l,
- hex_4=0x10L,
- hex_5=0x10ll,
- hex_6=0x10LL,};""")
- needs_dlopen_none()
- C = ffi.dlopen(None)
- for base, expected_result in (('bin', 2), ('oct', 8), ('dec', 10), ('hex', 16)):
- for index in range(7):
- assert getattr(C, '{base}_{index}'.format(base=base, index=index)) == expected_result
diff --git a/testing/cffi0/test_platform.py b/testing/cffi0/test_platform.py
deleted file mode 100644
index 55446ec..0000000
--- a/testing/cffi0/test_platform.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import os
-from cffi.ffiplatform import maybe_relative_path, flatten
-
-
-def test_not_absolute():
- assert maybe_relative_path('foo/bar') == 'foo/bar'
- assert maybe_relative_path('test_platform.py') == 'test_platform.py'
-
-def test_different_absolute():
- p = os.path.join('..', 'baz.py')
- assert maybe_relative_path(p) == p
-
-def test_absolute_mapping():
- p = os.path.abspath('baz.py')
- assert maybe_relative_path(p) == 'baz.py'
- foobaz = os.path.join('foo', 'baz.py')
- assert maybe_relative_path(os.path.abspath(foobaz)) == foobaz
-
-def test_flatten():
- assert flatten("foo") == "3sfoo"
- assert flatten(-10000000000000000000000000000) == \
- "-10000000000000000000000000000i"
- assert flatten([4, 5]) == "2l4i5i"
- assert flatten({4: 5}) == "1d4i5i"
- assert flatten({"foo": ("bar", "baaz")}) == "1d3sfoo2l3sbar4sbaaz"
diff --git a/testing/cffi0/test_unicode_literals.py b/testing/cffi0/test_unicode_literals.py
deleted file mode 100644
index 7b0a5cc..0000000
--- a/testing/cffi0/test_unicode_literals.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# ----------------------------------------------
-# WARNING, ALL LITERALS IN THIS FILE ARE UNICODE
-# ----------------------------------------------
-#
-from __future__ import unicode_literals
-#
-#
-#
-import sys, math
-from cffi import FFI
-
-lib_m = "m"
-if sys.platform == 'win32':
- #there is a small chance this fails on Mingw via environ $CC
- import distutils.ccompiler
- if distutils.ccompiler.get_default_compiler() == 'msvc':
- lib_m = 'msvcrt'
-
-
-def test_cast():
- ffi = FFI()
- assert int(ffi.cast("int", 3.14)) == 3 # unicode literal
-
-def test_new():
- ffi = FFI()
- assert ffi.new("int[]", [3, 4, 5])[2] == 5 # unicode literal
-
-def test_typeof():
- ffi = FFI()
- tp = ffi.typeof("int[51]") # unicode literal
- assert tp.length == 51
-
-def test_sizeof():
- ffi = FFI()
- assert ffi.sizeof("int[51]") == 51 * 4 # unicode literal
-
-def test_alignof():
- ffi = FFI()
- assert ffi.alignof("int[51]") == 4 # unicode literal
-
-def test_getctype():
- ffi = FFI()
- assert ffi.getctype("int**") == "int * *" # unicode literal
- assert type(ffi.getctype("int**")) is str
-
-def test_cdef():
- ffi = FFI()
- ffi.cdef("typedef int foo_t[50];") # unicode literal
-
-def test_offsetof():
- ffi = FFI()
- ffi.cdef("typedef struct { int x, y; } foo_t;")
- assert ffi.offsetof("foo_t", "y") == 4 # unicode literal
-
-def test_enum():
- ffi = FFI()
- ffi.cdef("enum foo_e { AA, BB, CC };") # unicode literal
- x = ffi.cast("enum foo_e", 1)
- assert int(ffi.cast("int", x)) == 1
-
-def test_dlopen():
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- m = ffi.dlopen(lib_m) # unicode literal
- x = m.sin(1.23)
- assert x == math.sin(1.23)
-
-def test_verify():
- ffi = FFI()
- ffi.cdef("double test_verify_1(double x);") # unicode literal
- lib = ffi.verify("double test_verify_1(double x) { return x * 42.0; }")
- assert lib.test_verify_1(-1.5) == -63.0
-
-def test_callback():
- ffi = FFI()
- cb = ffi.callback("int(int)", # unicode literal
- lambda x: x + 42)
- assert cb(5) == 47
diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py
deleted file mode 100644
index 3a1c0b9..0000000
--- a/testing/cffi0/test_verify.py
+++ /dev/null
@@ -1,2562 +0,0 @@
-import py, re
-import pytest
-import sys, os, math, weakref
-from cffi import FFI, VerificationError, VerificationMissing, model, FFIError
-from testing.support import *
-from testing.support import extra_compile_args
-
-
-lib_m = ['m']
-if sys.platform == 'win32':
- #there is a small chance this fails on Mingw via environ $CC
- import distutils.ccompiler
- if distutils.ccompiler.get_default_compiler() == 'msvc':
- lib_m = ['msvcrt']
- pass # no obvious -Werror equivalent on MSVC
-else:
- class FFI(FFI):
- def verify(self, *args, **kwds):
- return super(FFI, self).verify(
- *args, extra_compile_args=extra_compile_args, **kwds)
-
-def setup_module():
- import cffi.verifier
- cffi.verifier.cleanup_tmpdir()
- #
- # check that no $ sign is produced in the C file; it used to be the
- # case that anonymous enums would produce '$enum_$1', which was
- # used as part of a function name. GCC accepts such names, but it's
- # apparently non-standard.
- _r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE)
- _r_string = re.compile(r'\".*?\"')
- def _write_source_and_check(self, file=None):
- base_write_source(self, file)
- if file is None:
- f = open(self.sourcefilename)
- data = f.read()
- f.close()
- data = _r_comment.sub(' ', data)
- data = _r_string.sub('"skipped"', data)
- assert '$' not in data
- base_write_source = cffi.verifier.Verifier._write_source
- cffi.verifier.Verifier._write_source = _write_source_and_check
-
-
-def test_module_type():
- import cffi.verifier
- ffi = FFI()
- lib = ffi.verify()
- if hasattr(lib, '_cffi_python_module'):
- print('verify got a PYTHON module')
- if hasattr(lib, '_cffi_generic_module'):
- print('verify got a GENERIC module')
- expected_generic = (cffi.verifier._FORCE_GENERIC_ENGINE or
- '__pypy__' in sys.builtin_module_names)
- assert hasattr(lib, '_cffi_python_module') == (not expected_generic)
- assert hasattr(lib, '_cffi_generic_module') == expected_generic
-
-def test_missing_function(ffi=None):
- # uses the FFI hacked above with '-Werror'
- if ffi is None:
- ffi = FFI()
- ffi.cdef("void some_completely_unknown_function();")
- try:
- lib = ffi.verify()
- except (VerificationError, OSError):
- pass # expected case: we get a VerificationError
- else:
- # but depending on compiler and loader details, maybe
- # 'lib' could actually be imported but will fail if we
- # actually try to call the unknown function... Hard
- # to test anything more.
- pass
-
-def test_missing_function_import_error():
- # uses the original FFI that just gives a warning during compilation
- import cffi
- test_missing_function(ffi=cffi.FFI())
-
-def test_simple_case():
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- assert lib.sin(1.23) == math.sin(1.23)
-
-def _Wconversion(cdef, source, **kargs):
- if sys.platform in ('win32', 'darwin'):
- py.test.skip("needs GCC")
- ffi = FFI()
- ffi.cdef(cdef)
- py.test.raises(VerificationError, ffi.verify, source, **kargs)
- extra_compile_args_orig = extra_compile_args[:]
- extra_compile_args.remove('-Wconversion')
- try:
- lib = ffi.verify(source, **kargs)
- finally:
- extra_compile_args[:] = extra_compile_args_orig
- return lib
-
-def test_Wconversion_unsigned():
- _Wconversion("unsigned foo(void);",
- "int foo(void) { return -1;}")
-
-def test_Wconversion_integer():
- _Wconversion("short foo(void);",
- "long long foo(void) { return 1<<sizeof(short);}")
-
-def test_Wconversion_floating():
- lib = _Wconversion("float sin(double);",
- "#include <math.h>", libraries=lib_m)
- res = lib.sin(1.23)
- assert res != math.sin(1.23) # not exact, because of double->float
- assert abs(res - math.sin(1.23)) < 1E-5
-
-def test_Wconversion_float2int():
- _Wconversion("int sinf(float);",
- "#include <math.h>", libraries=lib_m)
-
-def test_Wconversion_double2int():
- _Wconversion("int sin(double);",
- "#include <math.h>", libraries=lib_m)
-
-def test_rounding_1():
- ffi = FFI()
- ffi.cdef("double sinf(float x);")
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- res = lib.sinf(1.23)
- assert res != math.sin(1.23) # not exact, because of double->float
- assert abs(res - math.sin(1.23)) < 1E-5
-
-def test_rounding_2():
- ffi = FFI()
- ffi.cdef("double sin(float x);")
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- res = lib.sin(1.23)
- assert res != math.sin(1.23) # not exact, because of double->float
- assert abs(res - math.sin(1.23)) < 1E-5
-
-def test_strlen_exact():
- ffi = FFI()
- ffi.cdef("size_t strlen(const char *s);")
- lib = ffi.verify("#include <string.h>")
- assert lib.strlen(b"hi there!") == 9
-
-def test_strlen_approximate():
- lib = _Wconversion("int strlen(char *s);",
- "#include <string.h>")
- assert lib.strlen(b"hi there!") == 9
-
-def test_return_approximate():
- for typename in ['short', 'int', 'long', 'long long']:
- ffi = FFI()
- ffi.cdef("%s foo(signed char x);" % typename)
- lib = ffi.verify("signed char foo(signed char x) { return x;}")
- assert lib.foo(-128) == -128
- assert lib.foo(+127) == +127
-
-def test_strlen_array_of_char():
- ffi = FFI()
- ffi.cdef("size_t strlen(char[]);")
- lib = ffi.verify("#include <string.h>")
- assert lib.strlen(b"hello") == 5
-
-def test_longdouble():
- ffi = FFI()
- ffi.cdef("long double sinl(long double x);")
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- for input in [1.23,
- ffi.cast("double", 1.23),
- ffi.cast("long double", 1.23)]:
- x = lib.sinl(input)
- assert repr(x).startswith("<cdata 'long double'")
- assert (float(x) - math.sin(1.23)) < 1E-10
-
-def test_longdouble_precision():
- # Test that we don't loose any precision of 'long double' when
- # passing through Python and CFFI.
- ffi = FFI()
- ffi.cdef("long double step1(long double x);")
- SAME_SIZE = ffi.sizeof("long double") == ffi.sizeof("double")
- lib = ffi.verify("""
- long double step1(long double x)
- {
- return 4*x-x*x;
- }
- """)
- def do(cast_to_double):
- x = 0.9789
- for i in range(10000):
- x = lib.step1(x)
- if cast_to_double:
- x = float(x)
- return float(x)
-
- more_precise = do(False)
- less_precise = do(True)
- if SAME_SIZE:
- assert more_precise == less_precise
- else:
- assert abs(more_precise - less_precise) > 0.1
- # Check the particular results on Intel
- import platform
- if (platform.machine().startswith('i386') or
- platform.machine().startswith('i486') or
- platform.machine().startswith('i586') or
- platform.machine().startswith('i686') or
- platform.machine().startswith('x86')):
- assert abs(more_precise - 0.656769) < 0.001
- assert abs(less_precise - 3.99091) < 0.001
- else:
- py.test.skip("don't know the very exact precision of 'long double'")
-
-
-all_primitive_types = model.PrimitiveType.ALL_PRIMITIVE_TYPES
-if sys.platform == 'win32':
- all_primitive_types = all_primitive_types.copy()
- del all_primitive_types['ssize_t']
-all_integer_types = sorted(tp for tp in all_primitive_types
- if all_primitive_types[tp] == 'i')
-all_float_types = sorted(tp for tp in all_primitive_types
- if all_primitive_types[tp] == 'f')
-
-def all_signed_integer_types(ffi):
- return [x for x in all_integer_types if int(ffi.cast(x, -1)) < 0]
-
-def all_unsigned_integer_types(ffi):
- return [x for x in all_integer_types if int(ffi.cast(x, -1)) > 0]
-
-
-def test_primitive_category():
- for typename in all_primitive_types:
- tp = model.PrimitiveType(typename)
- C = tp.is_char_type()
- F = tp.is_float_type()
- X = tp.is_complex_type()
- I = tp.is_integer_type()
- assert C == (typename in ('char', 'wchar_t', 'char16_t', 'char32_t'))
- assert F == (typename in ('float', 'double', 'long double'))
- assert X == (typename in ('float _Complex', 'double _Complex'))
- assert I + F + C + X == 1 # one and only one of them is true
-
-def test_all_integer_and_float_types():
- typenames = []
- for typename in all_primitive_types:
- if (all_primitive_types[typename] == 'c' or
- all_primitive_types[typename] == 'j' or # complex
- typename == '_Bool' or typename == 'long double'):
- pass
- else:
- typenames.append(typename)
- #
- ffi = FFI()
- ffi.cdef('\n'.join(["%s foo_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
- for tp in typenames]))
- lib = ffi.verify('\n'.join(["%s foo_%s(%s x) { return (%s)(x+1); }" %
- (tp, tp.replace(' ', '_'), tp, tp)
- for tp in typenames]))
- for typename in typenames:
- foo = getattr(lib, 'foo_%s' % typename.replace(' ', '_'))
- assert foo(42) == 43
- if sys.version < '3':
- assert foo(long(44)) == 45
- assert foo(ffi.cast(typename, 46)) == 47
- py.test.raises(TypeError, foo, ffi.NULL)
- #
- # check for overflow cases
- if all_primitive_types[typename] == 'f':
- continue
- for value in [-2**80, -2**40, -2**20, -2**10, -2**5, -1,
- 2**5, 2**10, 2**20, 2**40, 2**80]:
- overflows = int(ffi.cast(typename, value)) != value
- if overflows:
- py.test.raises(OverflowError, foo, value)
- else:
- assert foo(value) == value + 1
-
-def test_var_signed_integer_types():
- ffi = FFI()
- lst = all_signed_integer_types(ffi)
- csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
- for tp in lst])
- ffi.cdef(csource)
- lib = ffi.verify(csource)
- for tp in lst:
- varname = 'somevar_%s' % tp.replace(' ', '_')
- sz = ffi.sizeof(tp)
- max = (1 << (8*sz-1)) - 1
- min = -(1 << (8*sz-1))
- setattr(lib, varname, max)
- assert getattr(lib, varname) == max
- setattr(lib, varname, min)
- assert getattr(lib, varname) == min
- py.test.raises(OverflowError, setattr, lib, varname, max+1)
- py.test.raises(OverflowError, setattr, lib, varname, min-1)
-
-def test_var_unsigned_integer_types():
- ffi = FFI()
- lst = all_unsigned_integer_types(ffi)
- csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
- for tp in lst])
- ffi.cdef(csource)
- lib = ffi.verify(csource)
- for tp in lst:
- varname = 'somevar_%s' % tp.replace(' ', '_')
- sz = ffi.sizeof(tp)
- if tp != '_Bool':
- max = (1 << (8*sz)) - 1
- else:
- max = 1
- setattr(lib, varname, max)
- assert getattr(lib, varname) == max
- setattr(lib, varname, 0)
- assert getattr(lib, varname) == 0
- py.test.raises(OverflowError, setattr, lib, varname, max+1)
- py.test.raises(OverflowError, setattr, lib, varname, -1)
-
-def test_fn_signed_integer_types():
- ffi = FFI()
- lst = all_signed_integer_types(ffi)
- cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
- for tp in lst])
- ffi.cdef(cdefsrc)
- verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
- (tp, tp.replace(' ', '_'), tp) for tp in lst])
- lib = ffi.verify(verifysrc)
- for tp in lst:
- fnname = 'somefn_%s' % tp.replace(' ', '_')
- sz = ffi.sizeof(tp)
- max = (1 << (8*sz-1)) - 1
- min = -(1 << (8*sz-1))
- fn = getattr(lib, fnname)
- assert fn(max) == max
- assert fn(min) == min
- py.test.raises(OverflowError, fn, max + 1)
- py.test.raises(OverflowError, fn, min - 1)
-
-def test_fn_unsigned_integer_types():
- ffi = FFI()
- lst = all_unsigned_integer_types(ffi)
- cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
- for tp in lst])
- ffi.cdef(cdefsrc)
- verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
- (tp, tp.replace(' ', '_'), tp) for tp in lst])
- lib = ffi.verify(verifysrc)
- for tp in lst:
- fnname = 'somefn_%s' % tp.replace(' ', '_')
- sz = ffi.sizeof(tp)
- if tp != '_Bool':
- max = (1 << (8*sz)) - 1
- else:
- max = 1
- fn = getattr(lib, fnname)
- assert fn(max) == max
- assert fn(0) == 0
- py.test.raises(OverflowError, fn, max + 1)
- py.test.raises(OverflowError, fn, -1)
-
-def test_char_type():
- ffi = FFI()
- ffi.cdef("char foo(char);")
- lib = ffi.verify("char foo(char x) { return ++x; }")
- assert lib.foo(b"A") == b"B"
- py.test.raises(TypeError, lib.foo, b"bar")
- py.test.raises(TypeError, lib.foo, "bar")
-
-def test_wchar_type():
- ffi = FFI()
- if ffi.sizeof('wchar_t') == 2:
- uniexample1 = u+'\u1234'
- uniexample2 = u+'\u1235'
- else:
- uniexample1 = u+'\U00012345'
- uniexample2 = u+'\U00012346'
- #
- ffi.cdef("wchar_t foo(wchar_t);")
- lib = ffi.verify("wchar_t foo(wchar_t x) { return x+1; }")
- assert lib.foo(uniexample1) == uniexample2
-
-def test_char16_char32_type():
- py.test.skip("XXX test or fully prevent char16_t and char32_t from "
- "working in ffi.verify() mode")
-
-def test_no_argument():
- ffi = FFI()
- ffi.cdef("int foo(void);")
- lib = ffi.verify("int foo(void) { return 42; }")
- assert lib.foo() == 42
-
-def test_two_arguments():
- ffi = FFI()
- ffi.cdef("int foo(int, int);")
- lib = ffi.verify("int foo(int a, int b) { return a - b; }")
- assert lib.foo(40, -2) == 42
-
-def test_macro():
- ffi = FFI()
- ffi.cdef("int foo(int, int);")
- lib = ffi.verify("#define foo(a, b) ((a) * (b))")
- assert lib.foo(-6, -7) == 42
-
-def test_ptr():
- ffi = FFI()
- ffi.cdef("int *foo(int *);")
- lib = ffi.verify("int *foo(int *a) { return a; }")
- assert lib.foo(ffi.NULL) == ffi.NULL
- p = ffi.new("int *", 42)
- q = ffi.new("int *", 42)
- assert lib.foo(p) == p
- assert lib.foo(q) != p
-
-def test_bogus_ptr():
- ffi = FFI()
- ffi.cdef("int *foo(int *);")
- lib = ffi.verify("int *foo(int *a) { return a; }")
- py.test.raises(TypeError, lib.foo, ffi.new("short *", 42))
-
-
-def test_verify_typedefs():
- py.test.skip("ignored so far")
- types = ['signed char', 'unsigned char', 'int', 'long']
- for cdefed in types:
- for real in types:
- ffi = FFI()
- ffi.cdef("typedef %s foo_t;" % cdefed)
- if cdefed == real:
- ffi.verify("typedef %s foo_t;" % real)
- else:
- py.test.raises(VerificationError, ffi.verify,
- "typedef %s foo_t;" % real)
-
-def test_nondecl_struct():
- ffi = FFI()
- ffi.cdef("typedef struct foo_s foo_t; int bar(foo_t *);")
- lib = ffi.verify("typedef struct foo_s foo_t;\n"
- "int bar(foo_t *f) { (void)f; return 42; }\n")
- assert lib.bar(ffi.NULL) == 42
-
-def test_ffi_full_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { char x; int y; long *z; };")
- ffi.verify("struct foo_s { char x; int y; long *z; };")
- #
- if sys.platform != 'win32': # XXX fixme: only gives warnings
- py.test.raises(VerificationError, ffi.verify,
- "struct foo_s { char x; int y; int *z; };")
- #
- py.test.raises(VerificationError, ffi.verify,
- "struct foo_s { int y; long *z; };")
- #
- e = py.test.raises(VerificationError, ffi.verify,
- "struct foo_s { int y; char x; long *z; };")
- assert str(e.value) == (
- "struct foo_s: wrong offset for field 'x'"
- " (we have 0, but C compiler says 4)")
- #
- e = py.test.raises(VerificationError, ffi.verify,
- "struct foo_s { char x; int y; long *z; char extra; };")
- assert str(e.value) == (
- "struct foo_s: wrong total size"
- " (we have %d, but C compiler says %d)" % (
- ffi.sizeof("struct foo_s"),
- ffi.sizeof("struct foo_s") + ffi.sizeof("long*")))
- #
- # a corner case that we cannot really detect, but where it has no
- # bad consequences: the size is the same, but there is an extra field
- # that replaces what is just padding in our declaration above
- ffi.verify("struct foo_s { char x, extra; int y; long *z; };")
- #
- e = py.test.raises(VerificationError, ffi.verify,
- "struct foo_s { char x; short pad; short y; long *z; };")
- assert str(e.value) == (
- "struct foo_s: wrong size for field 'y'"
- " (we have 4, but C compiler says 2)")
-
-def test_ffi_nonfull_struct():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s {
- int x;
- ...;
- };
- """)
- py.test.raises(VerificationMissing, ffi.sizeof, 'struct foo_s')
- py.test.raises(VerificationMissing, ffi.offsetof, 'struct foo_s', 'x')
- py.test.raises(VerificationMissing, ffi.new, 'struct foo_s *')
- ffi.verify("""
- struct foo_s {
- int a, b, x, c, d, e;
- };
- """)
- assert ffi.sizeof('struct foo_s') == 6 * ffi.sizeof('int')
- assert ffi.offsetof('struct foo_s', 'x') == 2 * ffi.sizeof('int')
-
-def test_ffi_nonfull_alignment():
- ffi = FFI()
- ffi.cdef("struct foo_s { char x; ...; };")
- ffi.verify("struct foo_s { int a, b; char x; };")
- assert ffi.sizeof('struct foo_s') == 3 * ffi.sizeof('int')
- assert ffi.alignof('struct foo_s') == ffi.sizeof('int')
-
-def _check_field_match(typename, real, expect_mismatch):
- ffi = FFI()
- testing_by_size = (expect_mismatch == 'by_size')
- if testing_by_size:
- expect_mismatch = ffi.sizeof(typename) != ffi.sizeof(real)
- ffi.cdef("struct foo_s { %s x; ...; };" % typename)
- try:
- ffi.verify("struct foo_s { %s x; };" % real)
- except VerificationError:
- if not expect_mismatch:
- if testing_by_size and typename != real:
- print("ignoring mismatch between %s* and %s* even though "
- "they have the same size" % (typename, real))
- return
- raise AssertionError("unexpected mismatch: %s should be accepted "
- "as equal to %s" % (typename, real))
- else:
- if expect_mismatch:
- raise AssertionError("mismatch not detected: "
- "%s != %s" % (typename, real))
-
-def test_struct_bad_sized_integer():
- for typename in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
- for real in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
- _check_field_match(typename, real, "by_size")
-
-def test_struct_bad_sized_float():
- for typename in all_float_types:
- for real in all_float_types:
- _check_field_match(typename, real, "by_size")
-
-def test_struct_signedness_ignored():
- _check_field_match("int", "unsigned int", expect_mismatch=False)
- _check_field_match("unsigned short", "signed short", expect_mismatch=False)
-
-def test_struct_float_vs_int():
- if sys.platform == 'win32':
- py.test.skip("XXX fixme: only gives warnings")
- ffi = FFI()
- for typename in all_signed_integer_types(ffi):
- for real in all_float_types:
- _check_field_match(typename, real, expect_mismatch=True)
- for typename in all_float_types:
- for real in all_signed_integer_types(ffi):
- _check_field_match(typename, real, expect_mismatch=True)
-
-def test_struct_array_field():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[17]; ...; };")
- ffi.verify("struct foo_s { int x; int a[17]; int y; };")
- assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
-
-def test_struct_array_no_length():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[]; int y; ...; };\n"
- "int bar(struct foo_s *);\n")
- lib = ffi.verify("struct foo_s { int x; int a[17]; int y; };\n"
- "int bar(struct foo_s *f) { return f->a[14]; }\n")
- assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *")
- assert ffi.typeof(s.a) is ffi.typeof('int[]') # implicit max length
- assert len(s.a) == 18 # max length, computed from the size and start offset
- s.a[14] = 4242
- assert lib.bar(s) == 4242
- # with no declared length, out-of-bound accesses are not detected
- s.a[17] = -521
- assert s.y == s.a[17] == -521
- #
- s = ffi.new("struct foo_s *", {'a': list(range(17))})
- assert s.a[16] == 16
- # overflows at construction time not detected either
- s = ffi.new("struct foo_s *", {'a': list(range(18))})
- assert s.y == s.a[17] == 17
-
-def test_struct_array_guess_length():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[...]; };")
- ffi.verify("struct foo_s { int x; int a[17]; int y; };")
- assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
- with pytest.raises(IndexError):
- s.a[17]
-
-def test_struct_array_c99_1():
- if sys.platform == 'win32':
- py.test.skip("requires C99")
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; int a[]; };")
- ffi.verify("struct foo_s { int x; int a[]; };")
- assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *", [424242, 4])
- assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
- assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
- # ^^^ explanation: if you write in C: "char x[5];", then
- # "sizeof(x)" will evaluate to 5. The behavior above is
- # a generalization of that to "struct foo_s[len(a)=5] x;"
- # if you could do that in C.
- assert s.a[3] == 0
- s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
- assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
- assert s.a[3] == -10
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *", [424242])
- assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
-
-def test_struct_array_c99_2():
- if sys.platform == 'win32':
- py.test.skip("requires C99")
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; int a[]; ...; };")
- ffi.verify("struct foo_s { int x, y; int a[]; };")
- assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *", [424242, 4])
- assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
- assert s.a[3] == 0
- s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
- assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
- assert s.a[3] == -10
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *", [424242])
- assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
-
-def test_struct_ptr_to_array_field():
- ffi = FFI()
- ffi.cdef("struct foo_s { int (*a)[17]; ...; }; struct bar_s { ...; };")
- ffi.verify("struct foo_s { int x; int (*a)[17]; int y; };\n"
- "struct bar_s { int x; int *a; int y; };")
- assert ffi.sizeof('struct foo_s') == ffi.sizeof("struct bar_s")
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s.a) == ffi.sizeof('int(*)[17]') == ffi.sizeof("int *")
-
-def test_struct_with_bitfield_exact():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a:2, b:3; };")
- ffi.verify("struct foo_s { int a:2, b:3; };")
- s = ffi.new("struct foo_s *")
- s.b = 3
- with pytest.raises(OverflowError):
- s.b = 4
- assert s.b == 3
-
-def test_struct_with_bitfield_enum():
- ffi = FFI()
- code = """
- typedef enum { AA, BB, CC } foo_e;
- typedef struct { foo_e f:2; } foo_s;
- """
- ffi.cdef(code)
- ffi.verify(code)
- s = ffi.new("foo_s *")
- s.f = 2
- assert s.f == 2
-
-def test_unsupported_struct_with_bitfield_ellipsis():
- ffi = FFI()
- py.test.raises(NotImplementedError, ffi.cdef,
- "struct foo_s { int a:2, b:3; ...; };")
-
-def test_global_constants():
- ffi = FFI()
- # use 'static const int', as generally documented, although in this
- # case the 'static' is completely ignored.
- ffi.cdef("static const int AA, BB, CC, DD;")
- lib = ffi.verify("#define AA 42\n"
- "#define BB (-43) // blah\n"
- "#define CC (22*2) /* foobar */\n"
- "#define DD ((unsigned int)142) /* foo\nbar */\n")
- assert lib.AA == 42
- assert lib.BB == -43
- assert lib.CC == 44
- assert lib.DD == 142
-
-def test_global_const_int_size():
- # integer constants: ignore the declared type, always just use the value
- for value in [-2**63, -2**31, -2**15,
- 2**15-1, 2**15, 2**31-1, 2**31, 2**32-1, 2**32,
- 2**63-1, 2**63, 2**64-1]:
- ffi = FFI()
- if value == int(ffi.cast("long long", value)):
- if value < 0:
- vstr = '(-%dLL-1)' % (~value,)
- else:
- vstr = '%dLL' % value
- elif value == int(ffi.cast("unsigned long long", value)):
- vstr = '%dULL' % value
- else:
- raise AssertionError(value)
- ffi.cdef("static const unsigned short AA;")
- lib = ffi.verify("#define AA %s\n" % vstr)
- assert lib.AA == value
- assert type(lib.AA) is type(int(lib.AA))
-
-def test_global_constants_non_int():
- ffi = FFI()
- ffi.cdef("static char *const PP;")
- lib = ffi.verify('static char *const PP = "testing!";\n')
- assert ffi.typeof(lib.PP) == ffi.typeof("char *")
- assert ffi.string(lib.PP) == b"testing!"
-
-def test_nonfull_enum():
- ffi = FFI()
- ffi.cdef("enum ee { EE1, EE2, EE3, ... \n \t };")
- py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE2')
- ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
- assert ffi.string(ffi.cast('enum ee', 11)) == "EE2"
- assert ffi.string(ffi.cast('enum ee', -10)) == "EE3"
- #
- # try again
- ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
- assert ffi.string(ffi.cast('enum ee', 11)) == "EE2"
- #
- assert ffi.typeof("enum ee").relements == {'EE1': 10, 'EE2': 11, 'EE3': -10}
- assert ffi.typeof("enum ee").elements == {10: 'EE1', 11: 'EE2', -10: 'EE3'}
-
-def test_full_enum():
- ffi = FFI()
- ffi.cdef("enum ee { EE1, EE2, EE3 };")
- ffi.verify("enum ee { EE1, EE2, EE3 };")
- py.test.raises(VerificationError, ffi.verify, "enum ee { EE1, EE2 };")
- e = py.test.raises(VerificationError, ffi.verify,
- "enum ee { EE1, EE3, EE2 };")
- assert str(e.value) == 'enum ee: EE2 has the real value 2, not 1'
- # extra items cannot be seen and have no bad consequence anyway
- lib = ffi.verify("enum ee { EE1, EE2, EE3, EE4 };")
- assert lib.EE3 == 2
-
-def test_enum_usage():
- ffi = FFI()
- ffi.cdef("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;")
- lib = ffi.verify("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;")
- assert lib.EE2 == 1
- s = ffi.new("sp", [lib.EE2])
- assert s.x == 1
- s.x = 17
- assert s.x == 17
-
-def test_anonymous_enum():
- ffi = FFI()
- ffi.cdef("enum { EE1 }; enum { EE2, EE3 };")
- lib = ffi.verify("enum { EE1 }; enum { EE2, EE3 };")
- assert lib.EE1 == 0
- assert lib.EE2 == 0
- assert lib.EE3 == 1
-
-def test_nonfull_anonymous_enum():
- ffi = FFI()
- ffi.cdef("enum { EE1, ... }; enum { EE3, ... };")
- lib = ffi.verify("enum { EE2, EE1 }; enum { EE3 };")
- assert lib.EE1 == 1
- assert lib.EE3 == 0
-
-def test_nonfull_enum_syntax2():
- ffi = FFI()
- ffi.cdef("enum ee { EE1, EE2=\t..., EE3 };")
- py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1')
- ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
- assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2'
- assert ffi.string(ffi.cast('enum ee', -10)) == 'EE3'
- #
- ffi = FFI()
- ffi.cdef("enum ee { EE1, EE2=\t... };")
- py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1')
- ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
- assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2'
- #
- ffi = FFI()
- ffi.cdef("enum ee2 { EE4=..., EE5=..., ... };")
- ffi.verify("enum ee2 { EE4=-1234-5, EE5 }; ")
- assert ffi.string(ffi.cast('enum ee2', -1239)) == 'EE4'
- assert ffi.string(ffi.cast('enum ee2', -1238)) == 'EE5'
-
-def test_nonfull_enum_bug3():
- ffi = FFI()
- ffi.cdef("enum ee2 { EE4=..., EE5=... };")
- ffi.cdef("enum ee6 { EE7=10, EE8=..., EE9=... };")
-
-def test_get_set_errno():
- ffi = FFI()
- ffi.cdef("int foo(int);")
- lib = ffi.verify("""
- static int foo(int x)
- {
- errno += 1;
- return x * 7;
- }
- """)
- ffi.errno = 15
- assert lib.foo(6) == 42
- assert ffi.errno == 16
-
-def test_define_int():
- ffi = FFI()
- ffi.cdef("#define FOO ...\n"
- "\t#\tdefine\tBAR\t...\t\n"
- "#define BAZ ...\n")
- lib = ffi.verify("#define FOO 42\n"
- "#define BAR (-44)\n"
- "#define BAZ 0xffffffffffffffffULL\n")
- assert lib.FOO == 42
- assert lib.BAR == -44
- assert lib.BAZ == 0xffffffffffffffff
-
-def test_access_variable():
- ffi = FFI()
- ffi.cdef("static int foo(void);\n"
- "static int somenumber;")
- lib = ffi.verify("""
- static int somenumber = 2;
- static int foo(void) {
- return somenumber * 7;
- }
- """)
- assert lib.somenumber == 2
- assert lib.foo() == 14
- lib.somenumber = -6
- assert lib.foo() == -42
- assert lib.somenumber == -6
- lib.somenumber = 2 # reset for the next run, if any
-
-def test_access_address_of_variable():
- # access the address of 'somenumber': need a trick
- ffi = FFI()
- ffi.cdef("static int somenumber; static int *const somenumberptr;")
- lib = ffi.verify("""
- static int somenumber = 2;
- #define somenumberptr (&somenumber)
- """)
- assert lib.somenumber == 2
- lib.somenumberptr[0] = 42
- assert lib.somenumber == 42
- lib.somenumber = 2 # reset for the next run, if any
-
-def test_access_array_variable(length=5):
- ffi = FFI()
- ffi.cdef("int foo(int);\n"
- "static int somenumber[%s];" % (length,))
- lib = ffi.verify("""
- static int somenumber[] = {2, 2, 3, 4, 5};
- static int foo(int i) {
- return somenumber[i] * 7;
- }
- """)
- if length == '':
- # a global variable of an unknown array length is implicitly
- # transformed into a global pointer variable, because we can only
- # work with array instances whose length we know. using a pointer
- # instead of an array gives the correct effects.
- assert repr(lib.somenumber).startswith("<cdata 'int *' 0x")
- py.test.raises(TypeError, len, lib.somenumber)
- else:
- assert repr(lib.somenumber).startswith("<cdata 'int[%s]' 0x" % length)
- assert len(lib.somenumber) == 5
- assert lib.somenumber[3] == 4
- assert lib.foo(3) == 28
- lib.somenumber[3] = -6
- assert lib.foo(3) == -42
- assert lib.somenumber[3] == -6
- assert lib.somenumber[4] == 5
- lib.somenumber[3] = 4 # reset for the next run, if any
-
-def test_access_array_variable_length_hidden():
- test_access_array_variable(length='')
-
-def test_access_struct_variable():
- ffi = FFI()
- ffi.cdef("struct foo { int x; ...; };\n"
- "int foo(int);\n"
- "static struct foo stuff;")
- lib = ffi.verify("""
- struct foo { int x, y, z; };
- static struct foo stuff = {2, 5, 8};
- static int foo(int i) {
- switch (i) {
- case 0: return stuff.x * 7;
- case 1: return stuff.y * 7;
- case 2: return stuff.z * 7;
- }
- return -1;
- }
- """)
- assert lib.stuff.x == 2
- assert lib.foo(0) == 14
- assert lib.foo(1) == 35
- assert lib.foo(2) == 56
- lib.stuff.x = -6
- assert lib.foo(0) == -42
- assert lib.foo(1) == 35
- lib.stuff.x = 2 # reset for the next run, if any
-
-def test_access_callback():
- ffi = FFI()
- ffi.cdef("static int (*cb)(int);\n"
- "static int foo(int);\n"
- "static void reset_cb(void);")
- lib = ffi.verify("""
- static int g(int x) { return x * 7; }
- static int (*cb)(int);
- static int foo(int i) { return cb(i) - 1; }
- static void reset_cb(void) { cb = g; }
- """)
- lib.reset_cb()
- assert lib.foo(6) == 41
- my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
- lib.cb = my_callback
- assert lib.foo(4) == 887
-
-def test_access_callback_function_typedef():
- ffi = FFI()
- ffi.cdef("typedef int mycallback_t(int);\n"
- "static mycallback_t *cb;\n"
- "static int foo(int);\n"
- "static void reset_cb(void);")
- lib = ffi.verify("""
- static int g(int x) { return x * 7; }
- static int (*cb)(int);
- static int foo(int i) { return cb(i) - 1; }
- static void reset_cb(void) { cb = g; }
- """)
- lib.reset_cb()
- assert lib.foo(6) == 41
- my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
- lib.cb = my_callback
- assert lib.foo(4) == 887
-
-def test_ctypes_backend_forces_generic_engine():
- from cffi.backend_ctypes import CTypesBackend
- ffi = FFI(backend=CTypesBackend())
- ffi.cdef("int func(int a);")
- lib = ffi.verify("int func(int a) { return a * 42; }")
- assert not hasattr(lib, '_cffi_python_module')
- assert hasattr(lib, '_cffi_generic_module')
- assert lib.func(100) == 4200
-
-def test_call_with_struct_ptr():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; ...; } foo_t; int foo(foo_t *);")
- lib = ffi.verify("""
- typedef struct { int y, x; } foo_t;
- static int foo(foo_t *f) { return f->x * 7; }
- """)
- f = ffi.new("foo_t *")
- f.x = 6
- assert lib.foo(f) == 42
-
-def test_unknown_type():
- ffi = FFI()
- ffi.cdef("""
- typedef ... token_t;
- int foo(token_t *);
- #define TOKEN_SIZE ...
- """)
- lib = ffi.verify("""
- typedef float token_t;
- static int foo(token_t *tk) {
- if (!tk)
- return -42;
- *tk += 1.601f;
- return (int)*tk;
- }
- #define TOKEN_SIZE sizeof(token_t)
- """)
- # we cannot let ffi.new("token_t *") work, because we don't know ahead of
- # time if it's ok to ask 'sizeof(token_t)' in the C code or not.
- # See test_unknown_type_2. Workaround.
- tkmem = ffi.new("char[]", lib.TOKEN_SIZE) # zero-initialized
- tk = ffi.cast("token_t *", tkmem)
- results = [lib.foo(tk) for i in range(6)]
- assert results == [1, 3, 4, 6, 8, 9]
- assert lib.foo(ffi.NULL) == -42
-
-def test_unknown_type_2():
- ffi = FFI()
- ffi.cdef("typedef ... token_t;")
- lib = ffi.verify("typedef struct token_s token_t;")
- # assert did not crash, even though 'sizeof(token_t)' is not valid in C.
-
-def test_unknown_type_3():
- ffi = FFI()
- ffi.cdef("""
- typedef ... *token_p;
- token_p foo(token_p);
- """)
- lib = ffi.verify("""
- typedef struct _token_s *token_p;
- token_p foo(token_p arg) {
- if (arg)
- return (token_p)0x12347;
- else
- return (token_p)0x12345;
- }
- """)
- p = lib.foo(ffi.NULL)
- assert int(ffi.cast("intptr_t", p)) == 0x12345
- q = lib.foo(p)
- assert int(ffi.cast("intptr_t", q)) == 0x12347
-
-def test_varargs():
- ffi = FFI()
- ffi.cdef("int foo(int x, ...);")
- lib = ffi.verify("""
- int foo(int x, ...) {
- va_list vargs;
- va_start(vargs, x);
- x -= va_arg(vargs, int);
- x -= va_arg(vargs, int);
- va_end(vargs);
- return x;
- }
- """)
- assert lib.foo(50, ffi.cast("int", 5), ffi.cast("int", 3)) == 42
-
-def test_varargs_exact():
- if sys.platform == 'win32':
- py.test.skip("XXX fixme: only gives warnings")
- ffi = FFI()
- ffi.cdef("int foo(int x, ...);")
- py.test.raises(VerificationError, ffi.verify, """
- int foo(long long x, ...) {
- return x;
- }
- """)
-
-def test_varargs_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { char a; int b; }; int foo(int x, ...);")
- lib = ffi.verify("""
- struct foo_s {
- char a; int b;
- };
- int foo(int x, ...) {
- va_list vargs;
- struct foo_s s;
- va_start(vargs, x);
- s = va_arg(vargs, struct foo_s);
- va_end(vargs);
- return s.a - s.b;
- }
- """)
- s = ffi.new("struct foo_s *", [b'B', 1])
- assert lib.foo(50, s[0]) == ord('A')
-
-def test_autofilled_struct_as_argument():
- ffi = FFI()
- ffi.cdef("struct foo_s { long a; double b; ...; };\n"
- "int foo(struct foo_s);")
- lib = ffi.verify("""
- struct foo_s {
- double b;
- long a;
- };
- int foo(struct foo_s s) {
- return (int)s.a - (int)s.b;
- }
- """)
- s = ffi.new("struct foo_s *", [100, 1])
- assert lib.foo(s[0]) == 99
- assert lib.foo([100, 1]) == 99
-
-def test_autofilled_struct_as_argument_dynamic():
- ffi = FFI()
- ffi.cdef("struct foo_s { long a; ...; };\n"
- "static int (*foo)(struct foo_s);")
- lib = ffi.verify("""
- struct foo_s {
- double b;
- long a;
- };
- int foo1(struct foo_s s) {
- return (int)s.a - (int)s.b;
- }
- static int (*foo)(struct foo_s s) = &foo1;
- """)
- e = py.test.raises(NotImplementedError, lib.foo, "?")
- msg = ("ctype 'struct foo_s' 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. "
- "Such structs are only supported as argument "
- "if the function is '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_func_returns_struct():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { int aa, bb; };
- struct foo_s foo(int a, int b);
- """)
- lib = ffi.verify("""
- struct foo_s { int aa, bb; };
- struct foo_s foo(int a, int b) {
- struct foo_s r;
- r.aa = a*a;
- r.bb = b*b;
- return r;
- }
- """)
- s = lib.foo(6, 7)
- assert repr(s) == "<cdata 'struct foo_s' owning 8 bytes>"
- assert s.aa == 36
- assert s.bb == 49
-
-def test_func_as_funcptr():
- ffi = FFI()
- ffi.cdef("int *(*const fooptr)(void);")
- lib = ffi.verify("""
- int *foo(void) {
- return (int*)"foobar";
- }
- int *(*fooptr)(void) = foo;
- """)
- foochar = ffi.cast("char *(*)(void)", lib.fooptr)
- s = foochar()
- assert ffi.string(s) == b"foobar"
-
-def test_funcptr_as_argument():
- ffi = FFI()
- ffi.cdef("""
- void qsort(void *base, size_t nel, size_t width,
- int (*compar)(const void *, const void *));
- """)
- ffi.verify("#include <stdlib.h>")
-
-def test_func_as_argument():
- ffi = FFI()
- ffi.cdef("""
- void qsort(void *base, size_t nel, size_t width,
- int compar(const void *, const void *));
- """)
- ffi.verify("#include <stdlib.h>")
-
-def test_array_as_argument():
- ffi = FFI()
- ffi.cdef("""
- size_t strlen(char string[]);
- """)
- ffi.verify("#include <string.h>")
-
-def test_enum_as_argument():
- ffi = FFI()
- ffi.cdef("""
- enum foo_e { AA, BB, ... };
- int foo_func(enum foo_e);
- """)
- lib = ffi.verify("""
- enum foo_e { AA, CC, BB };
- int foo_func(enum foo_e e) { return (int)e; }
- """)
- assert lib.foo_func(lib.BB) == 2
- py.test.raises(TypeError, lib.foo_func, "BB")
-
-def test_enum_as_function_result():
- ffi = FFI()
- ffi.cdef("""
- enum foo_e { AA, BB, ... };
- enum foo_e foo_func(int x);
- """)
- lib = ffi.verify("""
- enum foo_e { AA, CC, BB };
- enum foo_e foo_func(int x) { return (enum foo_e)x; }
- """)
- assert lib.foo_func(lib.BB) == lib.BB == 2
-
-def test_enum_values():
- ffi = FFI()
- ffi.cdef("enum enum1_e { AA, BB };")
- lib = ffi.verify("enum enum1_e { AA, BB };")
- assert lib.AA == 0
- assert lib.BB == 1
- assert ffi.string(ffi.cast("enum enum1_e", 1)) == 'BB'
-
-def test_typedef_complete_enum():
- ffi = FFI()
- ffi.cdef("typedef enum { AA, BB } enum1_t;")
- lib = ffi.verify("typedef enum { AA, BB } enum1_t;")
- assert ffi.string(ffi.cast("enum1_t", 1)) == 'BB'
- assert lib.AA == 0
- assert lib.BB == 1
-
-def test_typedef_broken_complete_enum():
- ffi = FFI()
- ffi.cdef("typedef enum { AA, BB } enum1_t;")
- py.test.raises(VerificationError, ffi.verify,
- "typedef enum { AA, CC, BB } enum1_t;")
-
-def test_typedef_incomplete_enum():
- ffi = FFI()
- ffi.cdef("typedef enum { AA, BB, ... } enum1_t;")
- lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;")
- assert ffi.string(ffi.cast("enum1_t", 1)) == '1'
- assert ffi.string(ffi.cast("enum1_t", 2)) == 'BB'
- assert lib.AA == 0
- assert lib.BB == 2
-
-def test_typedef_enum_as_argument():
- ffi = FFI()
- ffi.cdef("""
- typedef enum { AA, BB, ... } foo_t;
- int foo_func(foo_t);
- """)
- lib = ffi.verify("""
- typedef enum { AA, CC, BB } foo_t;
- int foo_func(foo_t e) { return (int)e; }
- """)
- assert lib.foo_func(lib.BB) == lib.BB == 2
- py.test.raises(TypeError, lib.foo_func, "BB")
-
-def test_typedef_enum_as_function_result():
- ffi = FFI()
- ffi.cdef("""
- typedef enum { AA, BB, ... } foo_t;
- foo_t foo_func(int x);
- """)
- lib = ffi.verify("""
- typedef enum { AA, CC, BB } foo_t;
- foo_t foo_func(int x) { return (foo_t)x; }
- """)
- assert lib.foo_func(lib.BB) == lib.BB == 2
-
-def test_function_typedef():
- ffi = FFI()
- ffi.cdef("""
- typedef double func_t(double);
- func_t sin;
- """)
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- assert lib.sin(1.23) == math.sin(1.23)
-
-def test_opaque_integer_as_function_result():
- #import platform
- #if platform.machine().startswith('sparc'):
- # py.test.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
- #elif platform.machine() == 'mips64' and sys.maxsize > 2**32:
- # py.test.skip('Segfaults on mips64el')
- # XXX bad abuse of "struct { ...; }". It only works a bit by chance
- # anyway. XXX think about something better :-(
- ffi = FFI()
- ffi.cdef("""
- typedef struct { ...; } myhandle_t;
- myhandle_t foo(void);
- """)
- lib = ffi.verify("""
- typedef short myhandle_t;
- myhandle_t foo(void) { return 42; }
- """)
- h = lib.foo()
- assert ffi.sizeof(h) == ffi.sizeof("short")
-
-def test_return_partial_struct():
- ffi = FFI()
- ffi.cdef("""
- typedef struct { int x; ...; } foo_t;
- foo_t foo(void);
- """)
- lib = ffi.verify("""
- typedef struct { int y, x; } foo_t;
- foo_t foo(void) { foo_t r = { 45, 81 }; return r; }
- """)
- h = lib.foo()
- assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
- assert h.x == 81
-
-def test_take_and_return_partial_structs():
- ffi = FFI()
- ffi.cdef("""
- typedef struct { int x; ...; } foo_t;
- foo_t foo(foo_t, foo_t);
- """)
- lib = ffi.verify("""
- typedef struct { int y, x; } foo_t;
- foo_t foo(foo_t a, foo_t b) {
- foo_t r = { 100, a.x * 5 + b.x * 7 };
- return r;
- }
- """)
- args = ffi.new("foo_t[3]")
- args[0].x = 1000
- args[2].x = -498
- h = lib.foo(args[0], args[2])
- assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
- assert h.x == 1000 * 5 - 498 * 7
-
-def test_cannot_name_struct_type():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; } **sp; void foo(sp);")
- e = py.test.raises(VerificationError, ffi.verify,
- "typedef struct { int x; } **sp; void foo(sp x) { }")
- assert 'in argument of foo: unknown type name' in str(e.value)
-
-def test_dont_check_unnamable_fields():
- ffi = FFI()
- ffi.cdef("struct foo_s { struct { int x; } someone; };")
- ffi.verify("struct foo_s { struct { int x; } someone; };")
- # assert did not crash
-
-def test_nested_anonymous_struct_exact():
- if sys.platform == 'win32':
- py.test.skip("nested anonymous struct/union")
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { struct { int a; char b; }; union { char c, d; }; };
- """)
- ffi.verify("""
- struct foo_s { struct { int a; char b; }; union { char c, d; }; };
- """)
- p = ffi.new("struct foo_s *")
- assert ffi.sizeof(p[0]) == 3 * ffi.sizeof("int") # with alignment
- p.a = 1234567
- p.b = b'X'
- p.c = b'Y'
- assert p.a == 1234567
- assert p.b == b'X'
- assert p.c == b'Y'
- assert p.d == b'Y'
-
-def test_nested_anonymous_struct_exact_error():
- if sys.platform == 'win32':
- py.test.skip("nested anonymous struct/union")
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { struct { int a; char b; }; union { char c, d; }; };
- """)
- py.test.raises(VerificationError, ffi.verify, """
- struct foo_s { struct { int a; short b; }; union { char c, d; }; };
- """)
- py.test.raises(VerificationError, ffi.verify, """
- struct foo_s { struct { int a; char e, b; }; union { char c, d; }; };
- """)
-
-def test_nested_anonymous_struct_inexact_1():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { struct { char b; ...; }; union { char c, d; }; };
- """)
- ffi.verify("""
- struct foo_s { int a, padding; char c, d, b; };
- """)
- assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")
-
-def test_nested_anonymous_struct_inexact_2():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { union { char c, d; }; struct { int a; char b; }; ...; };
- """)
- ffi.verify("""
- struct foo_s { int a, padding; char c, d, b; };
- """)
- assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")
-
-def test_ffi_union():
- ffi = FFI()
- ffi.cdef("union foo_u { char x; long *z; };")
- ffi.verify("union foo_u { char x; int y; long *z; };")
-
-def test_ffi_union_partial():
- ffi = FFI()
- ffi.cdef("union foo_u { char x; ...; };")
- ffi.verify("union foo_u { char x; int y; };")
- assert ffi.sizeof("union foo_u") == 4
-
-def test_ffi_union_with_partial_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; ...; }; union foo_u { struct foo_s s; };")
- ffi.verify("struct foo_s { int a; int x; }; "
- "union foo_u { char b[32]; struct foo_s s; };")
- assert ffi.sizeof("struct foo_s") == 8
- assert ffi.sizeof("union foo_u") == 32
-
-def test_ffi_union_partial_2():
- ffi = FFI()
- ffi.cdef("typedef union { char x; ...; } u1;")
- ffi.verify("typedef union { char x; int y; } u1;")
- assert ffi.sizeof("u1") == 4
-
-def test_ffi_union_with_partial_struct_2():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; ...; } s1;"
- "typedef union { s1 s; } u1;")
- ffi.verify("typedef struct { int a; int x; } s1; "
- "typedef union { char b[32]; s1 s; } u1;")
- assert ffi.sizeof("s1") == 8
- assert ffi.sizeof("u1") == 32
- assert ffi.offsetof("u1", "s") == 0
-
-def test_ffi_struct_packed():
- if sys.platform == 'win32':
- py.test.skip("needs a GCC extension")
- ffi = FFI()
- ffi.cdef("struct foo_s { int b; ...; };")
- ffi.verify("""
- struct foo_s {
- char a;
- int b;
- } __attribute__((packed));
- """)
-
-def test_tmpdir():
- import tempfile, os
- from testing.udir import udir
- tmpdir = tempfile.mkdtemp(dir=str(udir))
- ffi = FFI()
- ffi.cdef("int foo(int);")
- lib = ffi.verify("int foo(int a) { return a + 42; }", tmpdir=tmpdir)
- assert os.listdir(tmpdir)
- assert lib.foo(100) == 142
-
-def test_relative_to():
- import tempfile, os
- from testing.udir import udir
- tmpdir = tempfile.mkdtemp(dir=str(udir))
- ffi = FFI()
- ffi.cdef("int foo(int);")
- f = open(os.path.join(tmpdir, 'foo.h'), 'w')
- f.write("int foo(int a) { return a + 42; }\n")
- f.close()
- lib = ffi.verify('#include "foo.h"',
- include_dirs=['.'],
- relative_to=os.path.join(tmpdir, 'x'))
- assert lib.foo(100) == 142
-
-def test_bug1():
- ffi = FFI()
- ffi.cdef("""
- typedef struct tdlhandle_s { ...; } *tdl_handle_t;
- typedef struct my_error_code_ {
- tdl_handle_t *rh;
- } my_error_code_t;
- """)
- ffi.verify("""
- typedef struct tdlhandle_s { int foo; } *tdl_handle_t;
- typedef struct my_error_code_ {
- tdl_handle_t *rh;
- } my_error_code_t;
- """)
-
-def test_bool():
- if sys.platform == 'win32':
- py.test.skip("_Bool not in MSVC")
- ffi = FFI()
- ffi.cdef("struct foo_s { _Bool x; };"
- "_Bool foo(_Bool); static _Bool (*foop)(_Bool);")
- lib = ffi.verify("""
- struct foo_s { _Bool x; };
- int foo(int arg) {
- return !arg;
- }
- _Bool _foofunc(_Bool x) {
- return !x;
- }
- static _Bool (*foop)(_Bool) = _foofunc;
- """)
- p = ffi.new("struct foo_s *")
- p.x = 1
- assert p.x is True
- with pytest.raises(OverflowError):
- p.x = -1
- with pytest.raises(TypeError):
- p.x = 0.0
- assert lib.foop(1) is False
- assert lib.foop(True) is False
- assert lib.foop(0) is True
- py.test.raises(OverflowError, lib.foop, 42)
- py.test.raises(TypeError, lib.foop, 0.0)
- assert lib.foo(1) is False
- assert lib.foo(True) is False
- assert lib.foo(0) is True
- py.test.raises(OverflowError, lib.foo, 42)
- py.test.raises(TypeError, lib.foo, 0.0)
- assert int(ffi.cast("_Bool", long(1))) == 1
- assert int(ffi.cast("_Bool", long(0))) == 0
- assert int(ffi.cast("_Bool", long(-1))) == 1
- assert int(ffi.cast("_Bool", 10**200)) == 1
- assert int(ffi.cast("_Bool", 10**40000)) == 1
- #
- class Foo(object):
- def __int__(self):
- self.seen = 1
- return result
- f = Foo()
- f.seen = 0
- result = 42
- assert int(ffi.cast("_Bool", f)) == 1
- assert f.seen
- f.seen = 0
- result = 0
- assert int(ffi.cast("_Bool", f)) == 0
- assert f.seen
- #
- py.test.raises(TypeError, ffi.cast, "_Bool", [])
-
-def test_bool_on_long_double():
- if sys.platform == 'win32':
- py.test.skip("_Bool not in MSVC")
- f = 1E-250
- if f == 0.0 or f*f != 0.0:
- py.test.skip("unexpected precision")
- ffi = FFI()
- ffi.cdef("long double square(long double f); _Bool opposite(_Bool);")
- lib = ffi.verify("long double square(long double f) { return f*f; }\n"
- "_Bool opposite(_Bool x) { return !x; }")
- f0 = lib.square(0.0)
- f2 = lib.square(f)
- f3 = lib.square(f * 2.0)
- if repr(f2) == repr(f3):
- py.test.skip("long double doesn't have enough precision")
- assert float(f0) == float(f2) == float(f3) == 0.0 # too tiny for 'double'
- assert int(ffi.cast("_Bool", f2)) == 1
- assert int(ffi.cast("_Bool", f3)) == 1
- assert int(ffi.cast("_Bool", f0)) == 0
- py.test.raises(TypeError, lib.opposite, f2)
-
-def test_cannot_pass_float():
- for basetype in ['char', 'short', 'int', 'long', 'long long']:
- for sign in ['signed', 'unsigned']:
- type = '%s %s' % (sign, basetype)
- ffi = FFI()
- ffi.cdef("struct foo_s { %s x; };\n"
- "int foo(%s);" % (type, type))
- lib = ffi.verify("""
- struct foo_s { %s x; };
- int foo(%s arg) {
- return !arg;
- }
- """ % (type, type))
- p = ffi.new("struct foo_s *")
- with pytest.raises(TypeError):
- p.x = 0.0
- assert lib.foo(42) == 0
- 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("""
- struct point_s { int x, y; };
- struct foo_s { int z; struct point_s point; };
- struct point_s sum_coord(struct point_s *);
- """)
- lib = ffi.verify("""
- struct point_s { int x, y; };
- struct foo_s { int z; struct point_s point; };
- struct point_s sum_coord(struct point_s *point) {
- struct point_s r;
- r.x = point->x + point->y;
- r.y = point->x - point->y;
- return r;
- }
- """)
- p = ffi.new("struct foo_s *")
- p.point.x = 16
- p.point.y = 9
- py.test.raises(TypeError, lib.sum_coord, p.point)
- res = lib.sum_coord(ffi.addressof(p.point))
- assert res.x == 25
- assert res.y == 7
- res2 = lib.sum_coord(ffi.addressof(res))
- assert res2.x == 32
- assert res2.y == 18
- py.test.raises(TypeError, lib.sum_coord, res2)
-
-def test_callback_in_thread():
- if sys.platform == 'win32':
- py.test.skip("pthread only")
- import os, subprocess, imp
- arg = os.path.join(os.path.dirname(__file__), 'callback_in_thread.py')
- g = subprocess.Popen([sys.executable, arg,
- os.path.dirname(imp.find_module('cffi')[1])])
- result = g.wait()
- assert result == 0
-
-def test_keepalive_lib():
- ffi = FFI()
- ffi.cdef("int foobar(void);")
- lib = ffi.verify("int foobar(void) { return 42; }")
- func = lib.foobar
- ffi_r = weakref.ref(ffi)
- lib_r = weakref.ref(lib)
- del ffi
- import gc; gc.collect() # lib stays alive
- assert lib_r() is not None
- assert ffi_r() is not None
- assert func() == 42
-
-def test_keepalive_ffi():
- ffi = FFI()
- ffi.cdef("int foobar(void);")
- lib = ffi.verify("int foobar(void) { return 42; }")
- func = lib.foobar
- ffi_r = weakref.ref(ffi)
- lib_r = weakref.ref(lib)
- del lib
- import gc; gc.collect() # ffi stays alive
- assert ffi_r() is not None
- assert lib_r() is not None
- assert func() == 42
-
-def test_FILE_stored_in_stdout():
- if not sys.platform.startswith('linux'):
- py.test.skip("likely, we cannot assign to stdout")
- ffi = FFI()
- ffi.cdef("int printf(const char *, ...); FILE *setstdout(FILE *);")
- lib = ffi.verify("""
- #include <stdio.h>
- FILE *setstdout(FILE *f) {
- FILE *result = stdout;
- stdout = f;
- return result;
- }
- """)
- import os
- fdr, fdw = os.pipe()
- fw1 = os.fdopen(fdw, 'wb', 256)
- old_stdout = lib.setstdout(fw1)
- try:
- #
- fw1.write(b"X")
- r = lib.printf(b"hello, %d!\n", ffi.cast("int", 42))
- fw1.close()
- assert r == len("hello, 42!\n")
- #
- finally:
- lib.setstdout(old_stdout)
- #
- result = os.read(fdr, 256)
- os.close(fdr)
- # the 'X' might remain in the user-level buffer of 'fw1' and
- # end up showing up after the 'hello, 42!\n'
- assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
-
-def test_FILE_stored_explicitly():
- ffi = FFI()
- ffi.cdef("int myprintf11(const char *, int); extern FILE *myfile;")
- lib = ffi.verify("""
- #include <stdio.h>
- FILE *myfile;
- int myprintf11(const char *out, int value) {
- return fprintf(myfile, out, value);
- }
- """)
- import os
- fdr, fdw = os.pipe()
- fw1 = os.fdopen(fdw, 'wb', 256)
- lib.myfile = ffi.cast("FILE *", fw1)
- #
- fw1.write(b"X")
- r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42))
- fw1.close()
- assert r == len("hello, 42!\n")
- #
- result = os.read(fdr, 256)
- os.close(fdr)
- # the 'X' might remain in the user-level buffer of 'fw1' and
- # end up showing up after the 'hello, 42!\n'
- assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
-
-def test_global_array_with_missing_length():
- ffi = FFI()
- ffi.cdef("extern int fooarray[];")
- lib = ffi.verify("int fooarray[50];")
- assert repr(lib.fooarray).startswith("<cdata 'int *'")
-
-def test_global_array_with_dotdotdot_length():
- ffi = FFI()
- ffi.cdef("extern int fooarray[...];")
- lib = ffi.verify("int fooarray[50];")
- assert repr(lib.fooarray).startswith("<cdata 'int[50]'")
-
-def test_bad_global_array_with_dotdotdot_length():
- ffi = FFI()
- ffi.cdef("extern int fooarray[...];")
- py.test.raises(VerificationError, ffi.verify, "char fooarray[23];")
-
-def test_struct_containing_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { ...; }; struct bar_s { struct foo_s f; ...; };")
- ffi.verify("struct foo_s { int x; }; struct bar_s { struct foo_s f; };")
- #
- ffi = FFI()
- ffi.cdef("struct foo_s { struct bar_s f; ...; }; struct bar_s { ...; };")
- ffi.verify("struct bar_s { int x; }; struct foo_s { struct bar_s f; };")
-
-def test_struct_returned_by_func():
- ffi = FFI()
- ffi.cdef("typedef ... foo_t; foo_t myfunc(void);")
- e = py.test.raises(TypeError, ffi.verify,
- "typedef struct { int x; } foo_t; "
- "foo_t myfunc(void) { foo_t x = { 42 }; return x; }")
- assert str(e.value) == (
- "function myfunc: 'foo_t' is used as result type, but is opaque")
-
-def test_include():
- ffi1 = FFI()
- ffi1.cdef("typedef struct { int x; ...; } foo_t;")
- ffi1.verify("typedef struct { int y, x; } foo_t;")
- ffi2 = FFI()
- ffi2.include(ffi1)
- ffi2.cdef("int myfunc(foo_t *);")
- lib = ffi2.verify("typedef struct { int y, x; } foo_t;"
- "int myfunc(foo_t *p) { return 42 * p->x; }")
- res = lib.myfunc(ffi2.new("foo_t *", {'x': 10}))
- assert res == 420
- res = lib.myfunc(ffi1.new("foo_t *", {'x': -10}))
- assert res == -420
-
-def test_include_enum():
- ffi1 = FFI()
- ffi1.cdef("enum foo_e { AA, ... };")
- lib1 = ffi1.verify("enum foo_e { CC, BB, AA };")
- ffi2 = FFI()
- ffi2.include(ffi1)
- ffi2.cdef("int myfunc(enum foo_e);")
- lib2 = ffi2.verify("enum foo_e { CC, BB, AA };"
- "int myfunc(enum foo_e x) { return (int)x; }")
- res = lib2.myfunc(lib2.AA)
- assert res == 2
-
-def test_named_pointer_as_argument():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; } *mystruct_p;\n"
- "mystruct_p ff5a(mystruct_p);")
- lib = ffi.verify("typedef struct { int x; } *mystruct_p;\n"
- "mystruct_p ff5a(mystruct_p p) { p->x += 40; return p; }")
- p = ffi.new("mystruct_p", [-2])
- q = lib.ff5a(p)
- assert q == p
- assert p.x == 38
-
-def test_enum_size():
- cases = [('123', 4, 4294967295),
- ('4294967295U', 4, 4294967295),
- ('-123', 4, -1),
- ('-2147483647-1', 4, -1),
- ]
- if FFI().sizeof("long") == 8:
- cases += [('4294967296L', 8, 2**64-1),
- ('%dUL' % (2**64-1), 8, 2**64-1),
- ('-2147483649L', 8, -1),
- ('%dL-1L' % (1-2**63), 8, -1)]
- for hidden_value, expected_size, expected_minus1 in cases:
- if sys.platform == 'win32' and 'U' in hidden_value:
- continue # skipped on Windows
- ffi = FFI()
- ffi.cdef("enum foo_e { AA, BB, ... };")
- lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value)
- assert lib.AA == 0
- assert lib.BB == eval(hidden_value.replace('U', '').replace('L', ''))
- assert ffi.sizeof("enum foo_e") == expected_size
- assert int(ffi.cast("enum foo_e", -1)) == expected_minus1
- # test with the large value hidden:
- # disabled so far, doesn't work
-## for hidden_value, expected_size, expected_minus1 in cases:
-## ffi = FFI()
-## ffi.cdef("enum foo_e { AA, BB, ... };")
-## lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value)
-## assert lib.AA == 0
-## assert ffi.sizeof("enum foo_e") == expected_size
-## assert int(ffi.cast("enum foo_e", -1)) == expected_minus1
-
-def test_enum_bug118():
- maxulong = 256 ** FFI().sizeof("unsigned long") - 1
- for c1, c2, c2c in [(0xffffffff, -1, ''),
- (maxulong, -1, ''),
- (-1, 0xffffffff, 'U'),
- (-1, maxulong, 'UL')]:
- if c2c and sys.platform == 'win32':
- continue # enums may always be signed with MSVC
- ffi = FFI()
- ffi.cdef("enum foo_e { AA=%s };" % c1)
- e = py.test.raises(VerificationError, ffi.verify,
- "enum foo_e { AA=%s%s };" % (c2, c2c))
- assert str(e.value) == ('enum foo_e: AA has the real value %d, not %d'
- % (c2, c1))
-
-def test_string_to_voidp_arg():
- ffi = FFI()
- ffi.cdef("int myfunc(void *);")
- lib = ffi.verify("int myfunc(void *p) { return ((signed char *)p)[0]; }")
- res = lib.myfunc(b"hi!")
- assert res == ord(b"h")
- p = ffi.new("char[]", b"gah")
- res = lib.myfunc(p)
- assert res == ord(b"g")
- res = lib.myfunc(ffi.cast("void *", p))
- assert res == ord(b"g")
- res = lib.myfunc(ffi.cast("int *", p))
- assert res == ord(b"g")
-
-def test_callback_indirection():
- ffi = FFI()
- ffi.cdef("""
- static int (*python_callback)(int how_many, int *values);
- int (*const c_callback)(int,...); /* pass this ptr to C routines */
- int some_c_function(int(*cb)(int,...));
- """)
- lib = ffi.verify("""
- #include <stdarg.h>
- #ifdef _WIN32
- #include <malloc.h>
- #define alloca _alloca
- #else
- # ifdef __FreeBSD__
- # include <stdlib.h>
- # else
- # include <alloca.h>
- # endif
- #endif
- static int (*python_callback)(int how_many, int *values);
- static int c_callback(int how_many, ...) {
- va_list ap;
- /* collect the "..." arguments into the values[] array */
- int i, *values = alloca((size_t)how_many * sizeof(int));
- va_start(ap, how_many);
- for (i=0; i<how_many; i++)
- values[i] = va_arg(ap, int);
- va_end(ap);
- return python_callback(how_many, values);
- }
- int some_c_function(int(*cb)(int,...)) {
- int result = cb(2, 10, 20);
- result += cb(3, 30, 40, 50);
- return result;
- }
- """)
- seen = []
- @ffi.callback("int(int, int*)")
- def python_callback(how_many, values):
- seen.append([values[i] for i in range(how_many)])
- return 42
- lib.python_callback = python_callback
-
- res = lib.some_c_function(lib.c_callback)
- assert res == 84
- assert seen == [[10, 20], [30, 40, 50]]
-
-def test_floatstar_argument():
- ffi = FFI()
- ffi.cdef("float sum3floats(float *);")
- lib = ffi.verify("""
- float sum3floats(float *f) {
- return f[0] + f[1] + f[2];
- }
- """)
- assert lib.sum3floats((1.5, 2.5, 3.5)) == 7.5
- p = ffi.new("float[]", (1.5, 2.5, 3.5))
- assert lib.sum3floats(p) == 7.5
-
-def test_charstar_argument():
- ffi = FFI()
- ffi.cdef("char sum3chars(char *);")
- lib = ffi.verify("""
- char sum3chars(char *f) {
- return (char)(f[0] + f[1] + f[2]);
- }
- """)
- assert lib.sum3chars((b'\x10', b'\x20', b'\x30')) == b'\x60'
- p = ffi.new("char[]", b'\x10\x20\x30')
- assert lib.sum3chars(p) == b'\x60'
-
-def test_passing_string_or_NULL():
- ffi = FFI()
- ffi.cdef("int seeme1(char *); int seeme2(int *);")
- lib = ffi.verify("""
- int seeme1(char *x) {
- return (x == NULL);
- }
- int seeme2(int *x) {
- return (x == NULL);
- }
- """)
- assert lib.seeme1(b"foo") == 0
- assert lib.seeme1(ffi.NULL) == 1
- assert lib.seeme2([42, 43]) == 0
- assert lib.seeme2(ffi.NULL) == 1
- py.test.raises(TypeError, lib.seeme1, None)
- py.test.raises(TypeError, lib.seeme2, None)
- py.test.raises(TypeError, lib.seeme1, 0.0)
- py.test.raises(TypeError, lib.seeme2, 0.0)
- py.test.raises(TypeError, lib.seeme1, 0)
- py.test.raises(TypeError, lib.seeme2, 0)
- zeroL = 99999999999999999999
- zeroL -= 99999999999999999999
- py.test.raises(TypeError, lib.seeme2, zeroL)
-
-def test_typeof_function():
- ffi = FFI()
- ffi.cdef("int foo(int, char);")
- lib = ffi.verify("int foo(int x, char y) { (void)x; (void)y; return 42; }")
- ctype = ffi.typeof(lib.foo)
- assert len(ctype.args) == 2
- assert ctype.result == ffi.typeof("int")
-
-def test_call_with_voidstar_arg():
- ffi = FFI()
- ffi.cdef("int f(void *);")
- lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }")
- assert lib.f(b"foobar") == ord(b"f")
-
-def test_dir():
- ffi = FFI()
- ffi.cdef("""void somefunc(void);
- extern int somevar, somearray[2];
- static char *const sv2;
- enum my_e { AA, BB, ... };
- #define FOO ...""")
- lib = ffi.verify("""void somefunc(void) { }
- int somevar, somearray[2];
- #define sv2 "text"
- enum my_e { AA, BB };
- #define FOO 42""")
- assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray',
- 'somefunc', 'somevar', 'sv2']
-
-def test_typeof_func_with_struct_argument():
- ffi = FFI()
- ffi.cdef("""struct s { int a; }; int foo(struct s);""")
- lib = ffi.verify("""struct s { int a; };
- int foo(struct s x) { return x.a; }""")
- s = ffi.new("struct s *", [-1234])
- m = lib.foo(s[0])
- assert m == -1234
- assert repr(ffi.typeof(lib.foo)) == "<ctype 'int(*)(struct s)'>"
-
-def test_bug_const_char_ptr_array_1():
- ffi = FFI()
- ffi.cdef("""extern const char *a[...];""")
- lib = ffi.verify("""const char *a[5];""")
- assert repr(ffi.typeof(lib.a)) == "<ctype 'char *[5]'>"
-
-def test_bug_const_char_ptr_array_2():
- from cffi import FFI # ignore warnings
- ffi = FFI()
- ffi.cdef("""extern const int a[];""")
- lib = ffi.verify("""const int a[5];""")
- assert repr(ffi.typeof(lib.a)) == "<ctype 'int *'>"
-
-def _test_various_calls(force_libffi):
- cdef_source = """
- extern int xvalue;
- extern long long ivalue, rvalue;
- extern float fvalue;
- extern double dvalue;
- extern long double Dvalue;
- signed char tf_bb(signed char x, signed char c);
- unsigned char tf_bB(signed char x, unsigned char c);
- short tf_bh(signed char x, short c);
- unsigned short tf_bH(signed char x, unsigned short c);
- int tf_bi(signed char x, int c);
- unsigned int tf_bI(signed char x, unsigned int c);
- long tf_bl(signed char x, long c);
- unsigned long tf_bL(signed char x, unsigned long c);
- long long tf_bq(signed char x, long long c);
- unsigned long long tf_bQ(signed char x, unsigned long long c);
- float tf_bf(signed char x, float c);
- double tf_bd(signed char x, double c);
- long double tf_bD(signed char x, long double c);
- """
- if force_libffi:
- cdef_source = (cdef_source
- .replace('tf_', '(*const tf_')
- .replace('(signed char x', ')(signed char x'))
- ffi = FFI()
- ffi.cdef(cdef_source)
- lib = ffi.verify("""
- int xvalue;
- long long ivalue, rvalue;
- float fvalue;
- double dvalue;
- long double Dvalue;
-
- typedef signed char b_t;
- typedef unsigned char B_t;
- typedef short h_t;
- typedef unsigned short H_t;
- typedef int i_t;
- typedef unsigned int I_t;
- typedef long l_t;
- typedef unsigned long L_t;
- typedef long long q_t;
- typedef unsigned long long Q_t;
- typedef float f_t;
- typedef double d_t;
- typedef long double D_t;
- #define S(letter) xvalue = (int)x; letter##value = (letter##_t)c;
- #define R(letter) return (letter##_t)rvalue;
-
- signed char tf_bb(signed char x, signed char c) { S(i) R(b) }
- unsigned char tf_bB(signed char x, unsigned char c) { S(i) R(B) }
- short tf_bh(signed char x, short c) { S(i) R(h) }
- unsigned short tf_bH(signed char x, unsigned short c) { S(i) R(H) }
- int tf_bi(signed char x, int c) { S(i) R(i) }
- unsigned int tf_bI(signed char x, unsigned int c) { S(i) R(I) }
- long tf_bl(signed char x, long c) { S(i) R(l) }
- unsigned long tf_bL(signed char x, unsigned long c) { S(i) R(L) }
- long long tf_bq(signed char x, long long c) { S(i) R(q) }
- unsigned long long tf_bQ(signed char x, unsigned long long c) { S(i) R(Q) }
- float tf_bf(signed char x, float c) { S(f) R(f) }
- double tf_bd(signed char x, double c) { S(d) R(d) }
- long double tf_bD(signed char x, long double c) { S(D) R(D) }
- """)
- lib.rvalue = 0x7182838485868788
- for kind, cname in [('b', 'signed char'),
- ('B', 'unsigned char'),
- ('h', 'short'),
- ('H', 'unsigned short'),
- ('i', 'int'),
- ('I', 'unsigned int'),
- ('l', 'long'),
- ('L', 'unsigned long'),
- ('q', 'long long'),
- ('Q', 'unsigned long long'),
- ('f', 'float'),
- ('d', 'double'),
- ('D', 'long double')]:
- sign = +1 if 'unsigned' in cname else -1
- lib.xvalue = 0
- lib.ivalue = 0
- lib.fvalue = 0
- lib.dvalue = 0
- lib.Dvalue = 0
- fun = getattr(lib, 'tf_b' + kind)
- res = fun(-42, sign * 99)
- if kind == 'D':
- res = float(res)
- assert res == int(ffi.cast(cname, 0x7182838485868788))
- assert lib.xvalue == -42
- if kind in 'fdD':
- assert float(getattr(lib, kind + 'value')) == -99.0
- else:
- assert lib.ivalue == sign * 99
-
-def test_various_calls_direct():
- _test_various_calls(force_libffi=False)
-
-def test_various_calls_libffi():
- _test_various_calls(force_libffi=True)
-
-def test_ptr_to_opaque():
- ffi = FFI()
- ffi.cdef("typedef ... foo_t; int f1(foo_t*); foo_t *f2(int);")
- lib = ffi.verify("""
- #include <stdlib.h>
- typedef struct { int x; } foo_t;
- int f1(foo_t* p) {
- int x = p->x;
- free(p);
- return x;
- }
- foo_t *f2(int x) {
- foo_t *p = malloc(sizeof(foo_t));
- p->x = x;
- return p;
- }
- """)
- p = lib.f2(42)
- x = lib.f1(p)
- assert x == 42
-
-def _run_in_multiple_threads(test1):
- test1()
- import sys
- try:
- import thread
- except ImportError:
- import _thread as thread
- errors = []
- def wrapper(lock):
- try:
- test1()
- except:
- errors.append(sys.exc_info())
- lock.release()
- locks = []
- for i in range(10):
- _lock = thread.allocate_lock()
- _lock.acquire()
- thread.start_new_thread(wrapper, (_lock,))
- locks.append(_lock)
- for _lock in locks:
- _lock.acquire()
- if errors:
- raise errors[0][1]
-
-def test_errno_working_even_with_pypys_jit():
- # NOTE: on some platforms, to work correctly, this test needs to be
- # compiled with -pthread. Otherwise, the accesses to errno done from f()
- # are compiled by assuming this small library won't be used from multiple
- # threads, which is wrong. If you see failures _and_ if you pass your
- # own CFLAGS environment variable, please make sure "-pthread" is in it.
- ffi = FFI()
- ffi.cdef("int f(int);")
- lib = ffi.verify("""
- #include <errno.h>
- int f(int x) { return (errno = errno + x); }
- """)
- @_run_in_multiple_threads
- def test1():
- ffi.errno = 0
- for i in range(10000):
- e = lib.f(1)
- assert e == i + 1
- assert ffi.errno == e
- for i in range(10000):
- ffi.errno = i
- e = lib.f(42)
- assert e == i + 42
-
-def test_getlasterror_working_even_with_pypys_jit():
- if sys.platform != 'win32':
- py.test.skip("win32-only test")
- ffi = FFI()
- ffi.cdef("void SetLastError(DWORD);")
- lib = ffi.dlopen("Kernel32.dll")
- @_run_in_multiple_threads
- def test1():
- for i in range(10000):
- n = (1 << 29) + i
- lib.SetLastError(n)
- assert ffi.getwinerror()[0] == n
-
-def test_verify_dlopen_flags():
- # Careful with RTLD_GLOBAL. If by chance the FFI is not deleted
- # promptly, like on PyPy, then other tests may see the same
- # exported symbols as well. So we must not export a simple name
- # like 'foo'!
- ffi1 = FFI()
- ffi1.cdef("extern int foo_verify_dlopen_flags;")
-
- lib1 = ffi1.verify("int foo_verify_dlopen_flags;",
- flags=ffi1.RTLD_GLOBAL | ffi1.RTLD_LAZY)
- lib2 = get_second_lib()
-
- lib1.foo_verify_dlopen_flags = 42
- assert lib2.foo_verify_dlopen_flags == 42
- lib2.foo_verify_dlopen_flags += 1
- assert lib1.foo_verify_dlopen_flags == 43
-
-def get_second_lib():
- # Hack, using modulename makes the test fail
- ffi2 = FFI()
- ffi2.cdef("extern int foo_verify_dlopen_flags;")
- lib2 = ffi2.verify("int foo_verify_dlopen_flags;",
- flags=ffi2.RTLD_GLOBAL | ffi2.RTLD_LAZY)
- return lib2
-
-def test_consider_not_implemented_function_type():
- ffi = FFI()
- ffi.cdef("typedef union { int a; float b; } Data;"
- "typedef struct { int a:2; } MyStr;"
- "typedef void (*foofunc_t)(Data);"
- "typedef Data (*bazfunc_t)(void);"
- "typedef MyStr (*barfunc_t)(void);")
- fooptr = ffi.cast("foofunc_t", 123)
- bazptr = ffi.cast("bazfunc_t", 123)
- barptr = ffi.cast("barfunc_t", 123)
- # assert did not crash so far
- e = py.test.raises(NotImplementedError, fooptr, ffi.new("Data *"))
- assert str(e.value) == (
- "ctype 'Data' not supported as argument by libffi. Unions are only "
- "supported as argument if the function is 'API mode' and "
- "non-variadic (i.e. declared inside ffibuilder.cdef()+"
- "ffibuilder.set_source() and not taking a final '...' argument)")
- e = py.test.raises(NotImplementedError, bazptr)
- assert str(e.value) == (
- "ctype 'Data' not supported as return value by libffi. Unions are "
- "only supported as return value if the function is 'API mode' and "
- "non-variadic (i.e. declared inside ffibuilder.cdef()+"
- "ffibuilder.set_source() and not taking a final '...' argument)")
- e = py.test.raises(NotImplementedError, barptr)
- assert str(e.value) == (
- "ctype 'MyStr' not supported as return value. It is a struct with "
- "bit fields, which libffi does not support. Such structs are only "
- "supported as return value if the function is 'API mode' and non-"
- "variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
- "set_source() and not taking a final '...' argument)")
-
-def test_verify_extra_arguments():
- ffi = FFI()
- ffi.cdef("#define ABA ...")
- lib = ffi.verify("", define_macros=[('ABA', '42')])
- assert lib.ABA == 42
-
-def test_implicit_unicode_on_windows():
- if sys.platform != 'win32':
- py.test.skip("win32-only test")
- ffi = FFI()
- e = py.test.raises(FFIError, ffi.cdef, "int foo(LPTSTR);")
- assert str(e.value) == ("The Windows type 'LPTSTR' is only available after"
- " you call ffi.set_unicode()")
- for with_unicode in [True, False]:
- ffi = FFI()
- ffi.set_unicode(with_unicode)
- ffi.cdef("""
- DWORD GetModuleFileName(HMODULE hModule, LPTSTR lpFilename,
- DWORD nSize);
- """)
- lib = ffi.verify("""
- #include <windows.h>
- """, libraries=['Kernel32'])
- outbuf = ffi.new("TCHAR[]", 200)
- n = lib.GetModuleFileName(ffi.NULL, outbuf, 500)
- assert 0 < n < 500
- for i in range(n):
- #print repr(outbuf[i])
- assert ord(outbuf[i]) != 0
- assert ord(outbuf[n]) == 0
- assert ord(outbuf[0]) < 128 # should be a letter, or '\'
-
-def test_use_local_dir():
- ffi = FFI()
- lib = ffi.verify("", modulename="test_use_local_dir")
- this_dir = os.path.dirname(__file__)
- pycache_files = os.listdir(os.path.join(this_dir, '__pycache__'))
- assert any('test_use_local_dir' in s for s in pycache_files)
-
-def test_define_known_value():
- ffi = FFI()
- ffi.cdef("#define FOO 0x123")
- lib = ffi.verify("#define FOO 0x123")
- assert lib.FOO == 0x123
-
-def test_define_wrong_value():
- ffi = FFI()
- ffi.cdef("#define FOO 123")
- e = py.test.raises(VerificationError, ffi.verify, "#define FOO 124")
- assert str(e.value).endswith("FOO has the real value 124, not 123")
-
-def test_static_const_int_known_value():
- ffi = FFI()
- ffi.cdef("static const int FOO = 0x123;")
- lib = ffi.verify("#define FOO 0x123")
- assert lib.FOO == 0x123
-
-def test_static_const_int_wrong_value():
- ffi = FFI()
- ffi.cdef("static const int FOO = 123;")
- e = py.test.raises(VerificationError, ffi.verify, "#define FOO 124")
- assert str(e.value).endswith("FOO has the real value 124, not 123")
-
-def test_const_struct_global():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; ...; } T; const T myglob;")
- lib = ffi.verify("typedef struct { double y; int x; } T;"
- "const T myglob = { 0.1, 42 };")
- assert ffi.typeof(lib.myglob) == ffi.typeof("T")
- assert lib.myglob.x == 42
-
-def test_dont_support_int_dotdotdot():
- ffi = FFI()
- ffi.cdef("typedef int... t1;")
- e = py.test.raises(VerificationError, ffi.verify, "")
- assert str(e.value) == ("feature not supported with ffi.verify(), but only "
- "with ffi.set_source(): 'typedef int... t1'")
- ffi = FFI()
- ffi.cdef("typedef double ... t1;")
- e = py.test.raises(VerificationError, ffi.verify, "")
- assert str(e.value) == ("feature not supported with ffi.verify(), but only "
- "with ffi.set_source(): 'typedef float... t1'")
-
-def test_const_fields():
- ffi = FFI()
- ffi.cdef("""struct foo_s { const int a; void *const b; };""")
- ffi.verify("""struct foo_s { const int a; void *const b; };""")
- foo_s = ffi.typeof("struct foo_s")
- assert foo_s.fields[0][0] == 'a'
- assert foo_s.fields[0][1].type is ffi.typeof("int")
- assert foo_s.fields[1][0] == 'b'
- assert foo_s.fields[1][1].type is ffi.typeof("void *")
-
-def test_win32_calling_convention_0():
- ffi = FFI()
- ffi.cdef("""
- int call1(int(__cdecl *cb)(int));
- int (*const call2)(int(__stdcall *cb)(int));
- """)
- lib = ffi.verify(r"""
- #ifndef _MSC_VER
- # define __stdcall /* nothing */
- #endif
- int call1(int(*cb)(int)) {
- int i, result = 0;
- //printf("call1: cb = %p\n", cb);
- for (i = 0; i < 1000; i++)
- result += cb(i);
- //printf("result = %d\n", result);
- return result;
- }
- int call2(int(__stdcall *cb)(int)) {
- int i, result = 0;
- //printf("call2: cb = %p\n", cb);
- for (i = 0; i < 1000; i++)
- result += cb(-i);
- //printf("result = %d\n", result);
- return result;
- }
- """)
- @ffi.callback("int(int)")
- def cb1(x):
- return x * 2
- @ffi.callback("int __stdcall(int)")
- def cb2(x):
- return x * 3
- #print 'cb1 =', cb1
- res = lib.call1(cb1)
- assert res == 500*999*2
- #print 'cb2 =', cb2
- #print ffi.typeof(lib.call2)
- #print 'call2 =', lib.call2
- res = lib.call2(cb2)
- #print '...'
- assert res == -500*999*3
- #print 'done'
- if sys.platform == 'win32' and sys.maxsize < 2**32:
- assert '__stdcall' in str(ffi.typeof(cb2))
- assert '__stdcall' not in str(ffi.typeof(cb1))
- py.test.raises(TypeError, lib.call1, cb2)
- py.test.raises(TypeError, lib.call2, cb1)
- else:
- assert '__stdcall' not in str(ffi.typeof(cb2))
- assert ffi.typeof(cb2) is ffi.typeof(cb1)
-
-def test_win32_calling_convention_1():
- ffi = FFI()
- ffi.cdef("""
- int __cdecl call1(int(__cdecl *cb)(int));
- int __stdcall call2(int(__stdcall *cb)(int));
- int (__cdecl *const cb1)(int);
- int (__stdcall *const cb2)(int);
- """)
- lib = ffi.verify(r"""
- #ifndef _MSC_VER
- # define __cdecl
- # define __stdcall
- #endif
- int __cdecl cb1(int x) { return x * 2; }
- int __stdcall cb2(int x) { return x * 3; }
-
- int __cdecl call1(int(__cdecl *cb)(int)) {
- int i, result = 0;
- //printf("here1\n");
- //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
- for (i = 0; i < 1000; i++)
- result += cb(i);
- //printf("result = %d\n", result);
- return result;
- }
- int __stdcall call2(int(__stdcall *cb)(int)) {
- int i, result = 0;
- //printf("here1\n");
- //printf("cb = %p, cb2 = %p\n", cb, (void *)cb2);
- for (i = 0; i < 1000; i++)
- result += cb(-i);
- //printf("result = %d\n", result);
- return result;
- }
- """)
- assert lib.call1(lib.cb1) == 500*999*2
- assert lib.call2(lib.cb2) == -500*999*3
-
-def test_win32_calling_convention_2():
- # any mistake in the declaration of plain function (including the
- # precise argument types and, here, the calling convention) are
- # automatically corrected. But this does not apply to the 'cb'
- # function pointer argument.
- ffi = FFI()
- ffi.cdef("""
- int __stdcall call1(int(__cdecl *cb)(int));
- int __cdecl call2(int(__stdcall *cb)(int));
- int (__cdecl *const cb1)(int);
- int (__stdcall *const cb2)(int);
- """)
- lib = ffi.verify(r"""
- #ifndef _MSC_VER
- # define __cdecl
- # define __stdcall
- #endif
- int __cdecl call1(int(__cdecl *cb)(int)) {
- int i, result = 0;
- for (i = 0; i < 1000; i++)
- result += cb(i);
- return result;
- }
- int __stdcall call2(int(__stdcall *cb)(int)) {
- int i, result = 0;
- for (i = 0; i < 1000; i++)
- result += cb(-i);
- return result;
- }
- int __cdecl cb1(int x) { return x * 2; }
- int __stdcall cb2(int x) { return x * 3; }
- """)
- assert lib.call1(lib.cb1) == 500*999*2
- assert lib.call2(lib.cb2) == -500*999*3
-
-def test_win32_calling_convention_3():
- ffi = FFI()
- ffi.cdef("""
- struct point { int x, y; };
-
- int (*const cb1)(struct point);
- int (__stdcall *const cb2)(struct point);
-
- struct point __stdcall call1(int(*cb)(struct point));
- struct point call2(int(__stdcall *cb)(struct point));
- """)
- lib = ffi.verify(r"""
- #ifndef _MSC_VER
- # define __cdecl
- # define __stdcall
- #endif
- struct point { int x, y; };
- int cb1(struct point pt) { return pt.x + 10 * pt.y; }
- int __stdcall cb2(struct point pt) { return pt.x + 100 * pt.y; }
- struct point __stdcall call1(int(__cdecl *cb)(struct point)) {
- int i;
- struct point result = { 0, 0 };
- //printf("here1\n");
- //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
- for (i = 0; i < 1000; i++) {
- struct point p = { i, -i };
- int r = cb(p);
- result.x += r;
- result.y -= r;
- }
- return result;
- }
- struct point __cdecl call2(int(__stdcall *cb)(struct point)) {
- int i;
- struct point result = { 0, 0 };
- for (i = 0; i < 1000; i++) {
- struct point p = { -i, i };
- int r = cb(p);
- result.x += r;
- result.y -= r;
- }
- return result;
- }
- """)
- if sys.platform == 'win32' and sys.maxsize < 2**32:
- py.test.raises(TypeError, lib.call1, lib.cb2)
- py.test.raises(TypeError, lib.call2, lib.cb1)
- pt = lib.call1(lib.cb1)
- assert (pt.x, pt.y) == (-9*500*999, 9*500*999)
- pt = lib.call2(lib.cb2)
- assert (pt.x, pt.y) == (99*500*999, -99*500*999)
-
-def _only_test_on_linux_intel():
- if not sys.platform.startswith('linux'):
- py.test.skip('only running the memory-intensive test on Linux')
- import platform
- machine = platform.machine()
- if 'x86' not in machine and 'x64' not in machine:
- py.test.skip('only running the memory-intensive test on x86/x64')
-
-def test_ffi_gc_size_arg():
- # with PyPy's GC, these calls to ffi.gc() would rapidly consume
- # 40 GB of RAM without the third argument
- _only_test_on_linux_intel()
- ffi = FFI()
- ffi.cdef("void *malloc(size_t); void free(void *);")
- lib = ffi.verify(r"""
- #include <stdlib.h>
- """)
- for i in range(2000):
- p = lib.malloc(20*1024*1024) # 20 MB
- p1 = ffi.cast("char *", p)
- for j in range(0, 20*1024*1024, 4096):
- p1[j] = b'!'
- p = ffi.gc(p, lib.free, 20*1024*1024)
- del p
-
-def test_ffi_gc_size_arg_2():
- # a variant of the above: this "attack" works on cpython's cyclic gc too
- # and I found no obvious way to prevent that. So for now, this test
- # is skipped on CPython, where it eats all the memory.
- if '__pypy__' not in sys.builtin_module_names:
- py.test.skip("find a way to tweak the cyclic GC of CPython")
- _only_test_on_linux_intel()
- ffi = FFI()
- ffi.cdef("void *malloc(size_t); void free(void *);")
- lib = ffi.verify(r"""
- #include <stdlib.h>
- """)
- class X(object):
- pass
- for i in range(2000):
- p = lib.malloc(50*1024*1024) # 50 MB
- p1 = ffi.cast("char *", p)
- for j in range(0, 50*1024*1024, 4096):
- p1[j] = b'!'
- p = ffi.gc(p, lib.free, 50*1024*1024)
- x = X()
- x.p = p
- x.cyclic = x
- del p, x
-
-def test_ffi_new_with_cycles():
- # still another variant, with ffi.new()
- if '__pypy__' not in sys.builtin_module_names:
- py.test.skip("find a way to tweak the cyclic GC of CPython")
- ffi = FFI()
- ffi.cdef("")
- lib = ffi.verify("")
- class X(object):
- pass
- for i in range(2000):
- p = ffi.new("char[]", 50*1024*1024) # 50 MB
- for j in range(0, 50*1024*1024, 4096):
- p[j] = b'!'
- x = X()
- x.p = p
- x.cyclic = x
- del p, x
-
-def test_arithmetic_in_cdef():
- for a in [0, 11, 15]:
- ffi = FFI()
- ffi.cdef("""
- enum FOO {
- DIVNN = ((-?) / (-3)),
- DIVNP = ((-?) / (+3)),
- DIVPN = ((+?) / (-3)),
- MODNN = ((-?) % (-3)),
- MODNP = ((-?) % (+3)),
- MODPN = ((+?) % (-3)),
- };
- """.replace('?', str(a)))
- lib = ffi.verify("""
- enum FOO {
- DIVNN = ((-?) / (-3)),
- DIVNP = ((-?) / (+3)),
- DIVPN = ((+?) / (-3)),
- MODNN = ((-?) % (-3)),
- MODNP = ((-?) % (+3)),
- MODPN = ((+?) % (-3)),
- };
- """.replace('?', str(a)))
- # the verify() crashes if the values in the enum are different from
- # the values we computed ourselves from the cdef()
-
-def test_passing_large_list():
- ffi = FFI()
- ffi.cdef("""void passing_large_list(long[]);""")
- lib = ffi.verify("""
- static void passing_large_list(long a[]) { }
- """)
- arg = list(range(20000000))
- lib.passing_large_list(arg)
- # assert did not segfault
diff --git a/testing/cffi0/test_verify2.py b/testing/cffi0/test_verify2.py
deleted file mode 100644
index a4af6d6..0000000
--- a/testing/cffi0/test_verify2.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from .test_verify import *
-
-# This test file runs normally after test_verify. We only clean up the .c
-# sources, to check that it also works when we have only the .so. The
-# tests should run much faster than test_verify.
-
-def setup_module():
- import cffi.verifier
- cffi.verifier.cleanup_tmpdir(keep_so=True)
diff --git a/testing/cffi0/test_version.py b/testing/cffi0/test_version.py
deleted file mode 100644
index facb84c..0000000
--- a/testing/cffi0/test_version.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import py, os, sys
-import cffi, _cffi_backend
-
-def setup_module(mod):
- if '_cffi_backend' in sys.builtin_module_names:
- py.test.skip("this is embedded version")
-
-#BACKEND_VERSIONS = {
-# '0.4.2': '0.4', # did not change
-# '0.7.1': '0.7', # did not change
-# '0.7.2': '0.7', # did not change
-# '0.8.1': '0.8', # did not change (essentially)
-# '0.8.4': '0.8.3', # did not change
-# }
-
-def test_version():
- v = cffi.__version__
- version_info = '.'.join(str(i) for i in cffi.__version_info__)
- version_info = version_info.replace('.beta.', 'b')
- version_info = version_info.replace('.plus', '+')
- version_info = version_info.replace('.rc', 'rc')
- assert v == version_info
- #v = BACKEND_VERSIONS.get(v, v)
- assert v == _cffi_backend.__version__
-
-def test_doc_version():
- parent = os.path.dirname(os.path.dirname(cffi.__file__))
- p = os.path.join(parent, 'doc', 'source', 'conf.py')
- content = open(p).read()
- #
- v = cffi.__version__
- assert ("version = '%s'\n" % v[:4]) in content
- assert ("release = '%s'\n" % v) in content
-
-def test_doc_version_file():
- parent = os.path.dirname(os.path.dirname(cffi.__file__))
- v = cffi.__version__.replace('+', '')
- p = os.path.join(parent, 'doc', 'source', 'installation.rst')
- content = open(p).read()
- if " package version %s:" % v not in content:
- for i in range(5):
- if " package version %s-%d:" % (v, i) in content:
- break
- else:
- assert 0, "doc/source/installation.rst needs updating"
-
-def test_setup_version():
- parent = os.path.dirname(os.path.dirname(cffi.__file__))
- p = os.path.join(parent, 'setup.py')
- content = open(p).read()
- #
- v = cffi.__version__.replace('+', '')
- assert ("version='%s'" % v) in content
-
-def test_c_version():
- parent = os.path.dirname(os.path.dirname(cffi.__file__))
- v = cffi.__version__
- p = os.path.join(parent, 'c', 'test_c.py')
- content = open(p).read()
- #v = BACKEND_VERSIONS.get(v, v)
- assert (('assert __version__ == "%s"' % v) in content)
-
-def test_embedding_h():
- parent = os.path.dirname(os.path.dirname(cffi.__file__))
- v = cffi.__version__
- p = os.path.join(parent, 'cffi', '_embedding.h')
- content = open(p).read()
- assert ('cffi version: %s"' % (v,)) in content
diff --git a/testing/cffi0/test_vgen.py b/testing/cffi0/test_vgen.py
deleted file mode 100644
index 1a7e05d..0000000
--- a/testing/cffi0/test_vgen.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import cffi.verifier
-from .test_verify import *
-
-
-def setup_module():
- cffi.verifier.cleanup_tmpdir()
- cffi.verifier._FORCE_GENERIC_ENGINE = True
- # Runs all tests with _FORCE_GENERIC_ENGINE = True, to make sure we
- # also test vengine_gen.py.
-
-def teardown_module():
- cffi.verifier._FORCE_GENERIC_ENGINE = False
diff --git a/testing/cffi0/test_vgen2.py b/testing/cffi0/test_vgen2.py
deleted file mode 100644
index 34147c8..0000000
--- a/testing/cffi0/test_vgen2.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import cffi.verifier
-from .test_vgen import *
-
-# This test file runs normally after test_vgen. We only clean up the .c
-# sources, to check that it also works when we have only the .so. The
-# tests should run much faster than test_vgen.
-
-def setup_module():
- cffi.verifier.cleanup_tmpdir(keep_so=True)
- cffi.verifier._FORCE_GENERIC_ENGINE = True
-
-def teardown_module():
- cffi.verifier._FORCE_GENERIC_ENGINE = False
diff --git a/testing/cffi0/test_zdistutils.py b/testing/cffi0/test_zdistutils.py
deleted file mode 100644
index 35b3d0c..0000000
--- a/testing/cffi0/test_zdistutils.py
+++ /dev/null
@@ -1,288 +0,0 @@
-import sys, os, imp, math, shutil
-import py
-from cffi import FFI, FFIError
-from cffi.verifier import Verifier, _locate_engine_class, _get_so_suffixes
-from cffi.ffiplatform import maybe_relative_path
-from testing.udir import udir
-
-
-class DistUtilsTest(object):
- def setup_class(self):
- self.lib_m = "m"
- if sys.platform == 'win32':
- #there is a small chance this fails on Mingw via environ $CC
- import distutils.ccompiler
- if distutils.ccompiler.get_default_compiler() == 'msvc':
- self.lib_m = 'msvcrt'
-
- def teardown_class(self):
- if udir.isdir():
- udir.remove(ignore_errors=True)
- udir.ensure(dir=1)
-
- def test_locate_engine_class(self):
- cls = _locate_engine_class(FFI(), self.generic)
- if self.generic:
- # asked for the generic engine, which must not generate a
- # CPython extension module
- assert not cls._gen_python_module
- else:
- # asked for the CPython engine: check that we got it, unless
- # we are running on top of PyPy, where the generic engine is
- # always better
- if '__pypy__' not in sys.builtin_module_names:
- assert cls._gen_python_module
-
- def test_write_source(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
- v = Verifier(ffi, csrc, force_generic_engine=self.generic,
- libraries=[self.lib_m])
- v.write_source()
- with open(v.sourcefilename, 'r') as f:
- data = f.read()
- assert csrc in data
-
- def test_write_source_explicit_filename(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
- v = Verifier(ffi, csrc, force_generic_engine=self.generic,
- libraries=[self.lib_m])
- v.sourcefilename = filename = str(udir.join('write_source.c'))
- v.write_source()
- assert filename == v.sourcefilename
- with open(filename, 'r') as f:
- data = f.read()
- assert csrc in data
-
- def test_write_source_to_file_obj(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
- v = Verifier(ffi, csrc, force_generic_engine=self.generic,
- libraries=[self.lib_m])
- try:
- from StringIO import StringIO
- except ImportError:
- from io import StringIO
- f = StringIO()
- v.write_source(file=f)
- assert csrc in f.getvalue()
-
- def test_compile_module(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
- v = Verifier(ffi, csrc, force_generic_engine=self.generic,
- libraries=[self.lib_m])
- v.compile_module()
- assert v.get_module_name().startswith('_cffi_')
- if v.generates_python_module():
- mod = imp.load_dynamic(v.get_module_name(), v.modulefilename)
- assert hasattr(mod, '_cffi_setup')
-
- def test_compile_module_explicit_filename(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*hi there %s!2*/\n#include <math.h>\n' % self
- v = Verifier(ffi, csrc, force_generic_engine=self.generic,
- libraries=[self.lib_m])
- basename = self.__class__.__name__[:10] + '_test_compile_module'
- v.modulefilename = filename = str(udir.join(basename + '.so'))
- v.compile_module()
- assert filename == v.modulefilename
- assert v.get_module_name() == basename
- if v.generates_python_module():
- mod = imp.load_dynamic(v.get_module_name(), v.modulefilename)
- assert hasattr(mod, '_cffi_setup')
-
- def test_name_from_checksum_of_cdef(self):
- names = []
- for csrc in ['double', 'double', 'float']:
- ffi = FFI()
- ffi.cdef("%s sin(double x);" % csrc)
- v = Verifier(ffi, "#include <math.h>",
- force_generic_engine=self.generic,
- libraries=[self.lib_m])
- names.append(v.get_module_name())
- assert names[0] == names[1] != names[2]
-
- def test_name_from_checksum_of_csrc(self):
- names = []
- for csrc in ['123', '123', '1234']:
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- v = Verifier(ffi, csrc, force_generic_engine=self.generic)
- names.append(v.get_module_name())
- assert names[0] == names[1] != names[2]
-
- def test_load_library(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*hi there %s!3*/\n#include <math.h>\n' % self
- v = Verifier(ffi, csrc, force_generic_engine=self.generic,
- libraries=[self.lib_m])
- library = v.load_library()
- assert library.sin(12.3) == math.sin(12.3)
-
- def test_verifier_args(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*hi there %s!4*/#include "test_verifier_args.h"\n' % self
- udir.join('test_verifier_args.h').write('#include <math.h>\n')
- v = Verifier(ffi, csrc, include_dirs=[str(udir)],
- force_generic_engine=self.generic,
- libraries=[self.lib_m])
- library = v.load_library()
- assert library.sin(12.3) == math.sin(12.3)
-
- def test_verifier_object_from_ffi(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = "/*6%s*/\n#include <math.h>" % self
- lib = ffi.verify(csrc, force_generic_engine=self.generic,
- libraries=[self.lib_m])
- assert lib.sin(12.3) == math.sin(12.3)
- assert isinstance(ffi.verifier, Verifier)
- with open(ffi.verifier.sourcefilename, 'r') as f:
- data = f.read()
- assert csrc in data
-
- def test_extension_object(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*7%s*/' % self + '''
- #include <math.h>
- #ifndef TEST_EXTENSION_OBJECT
- # error "define_macros missing"
- #endif
- '''
- lib = ffi.verify(csrc, define_macros=[('TEST_EXTENSION_OBJECT', '1')],
- force_generic_engine=self.generic,
- libraries=[self.lib_m])
- assert lib.sin(12.3) == math.sin(12.3)
- v = ffi.verifier
- ext = v.get_extension()
- assert 'distutils.extension.Extension' in str(ext.__class__) or \
- 'setuptools.extension.Extension' in str(ext.__class__)
- assert ext.sources == [maybe_relative_path(v.sourcefilename)]
- assert ext.name == v.get_module_name()
- assert ext.define_macros == [('TEST_EXTENSION_OBJECT', '1')]
-
- def test_extension_forces_write_source(self):
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- csrc = '/*hi there9!%s*/\n#include <math.h>\n' % self
- v = Verifier(ffi, csrc, force_generic_engine=self.generic,
- libraries=[self.lib_m])
- assert not os.path.exists(v.sourcefilename)
- v.get_extension()
- assert os.path.exists(v.sourcefilename)
-
- def test_extension_object_extra_sources(self):
- ffi = FFI()
- ffi.cdef("double test1eoes(double x);")
- extra_source = str(udir.join('extension_extra_sources.c'))
- with open(extra_source, 'w') as f:
- f.write('double test1eoes(double x) { return x * 6.0; }\n')
- csrc = '/*9%s*/' % self + '''
- double test1eoes(double x); /* or #include "extra_sources.h" */
- '''
- lib = ffi.verify(csrc, sources=[extra_source],
- force_generic_engine=self.generic)
- assert lib.test1eoes(7.0) == 42.0
- v = ffi.verifier
- ext = v.get_extension()
- assert 'distutils.extension.Extension' in str(ext.__class__) or \
- 'setuptools.extension.Extension' in str(ext.__class__)
- assert ext.sources == [maybe_relative_path(v.sourcefilename),
- extra_source]
- assert ext.name == v.get_module_name()
-
- def test_install_and_reload_module(self, targetpackage='', ext_package=''):
- KEY = repr(self)
- if not hasattr(os, 'fork'):
- py.test.skip("test requires os.fork()")
-
- if targetpackage:
- udir.ensure(targetpackage, dir=1).ensure('__init__.py')
- sys.path.insert(0, str(udir))
-
- def make_ffi(**verifier_args):
- ffi = FFI()
- ffi.cdef("/* %s, %s, %s */" % (KEY, targetpackage, ext_package))
- ffi.cdef("double test1iarm(double x);")
- csrc = "double test1iarm(double x) { return x * 42.0; }"
- lib = ffi.verify(csrc, force_generic_engine=self.generic,
- ext_package=ext_package,
- **verifier_args)
- return ffi, lib
-
- childpid = os.fork()
- if childpid == 0:
- # in the child
- ffi, lib = make_ffi()
- assert lib.test1iarm(1.5) == 63.0
- # "install" the module by moving it into udir (/targetpackage)
- if targetpackage:
- target = udir.join(targetpackage)
- else:
- target = udir
- shutil.move(ffi.verifier.modulefilename, str(target))
- os._exit(0)
- # in the parent
- _, status = os.waitpid(childpid, 0)
- if not (os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0):
- raise AssertionError # see error above in subprocess
-
- from cffi import ffiplatform
- prev_compile = ffiplatform.compile
- try:
- if targetpackage == ext_package:
- ffiplatform.compile = lambda *args: dont_call_me_any_more
- # won't find it in tmpdir, but should find it correctly
- # installed in udir
- ffi, lib = make_ffi()
- assert lib.test1iarm(0.5) == 21.0
- finally:
- ffiplatform.compile = prev_compile
-
- def test_install_and_reload_module_package(self):
- self.test_install_and_reload_module(targetpackage='foo_iarmp',
- ext_package='foo_iarmp')
-
- def test_install_and_reload_module_ext_package_not_found(self):
- self.test_install_and_reload_module(targetpackage='foo_epnf',
- ext_package='not_found')
-
- def test_tag(self):
- ffi = FFI()
- ffi.cdef("/* %s test_tag */ double test1tag(double x);" % self)
- csrc = "double test1tag(double x) { return x - 42.0; }"
- lib = ffi.verify(csrc, force_generic_engine=self.generic,
- tag='xxtest_tagxx')
- assert lib.test1tag(143) == 101.0
- assert '_cffi_xxtest_tagxx_' in ffi.verifier.modulefilename
-
- def test_modulename(self):
- ffi = FFI()
- ffi.cdef("/* %s test_modulename */ double test1foo(double x);" % self)
- csrc = "double test1foo(double x) { return x - 63.0; }"
- modname = 'xxtest_modulenamexx%d' % (self.generic,)
- lib = ffi.verify(csrc, force_generic_engine=self.generic,
- modulename=modname)
- assert lib.test1foo(143) == 80.0
- suffix = _get_so_suffixes()[0]
- fn1 = os.path.join(ffi.verifier.tmpdir, modname + '.c')
- fn2 = os.path.join(ffi.verifier.tmpdir, modname + suffix)
- assert ffi.verifier.sourcefilename == fn1
- assert ffi.verifier.modulefilename == fn2
-
-
-class TestDistUtilsCPython(DistUtilsTest):
- generic = False
-
-class TestDistUtilsGeneric(DistUtilsTest):
- generic = True
diff --git a/testing/cffi0/test_zintegration.py b/testing/cffi0/test_zintegration.py
deleted file mode 100644
index ce925b8..0000000
--- a/testing/cffi0/test_zintegration.py
+++ /dev/null
@@ -1,181 +0,0 @@
-import py, os, sys, shutil
-import subprocess
-from testing.udir import udir
-import pytest
-
-if sys.platform == 'win32':
- pytestmark = pytest.mark.skip('snippets do not run on win32')
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip(
- 'fails e.g. on a Debian/Ubuntu which patches virtualenv'
- ' in a non-2.6-friendly way')
-
-def create_venv(name):
- tmpdir = udir.join(name)
- try:
- subprocess.check_call(['virtualenv',
- #'--never-download', <= could be added, but causes failures
- # in random cases on random machines
- '-p', os.path.abspath(sys.executable),
- str(tmpdir)])
- except OSError as e:
- py.test.skip("Cannot execute virtualenv: %s" % (e,))
-
- site_packages = None
- for dirpath, dirnames, filenames in os.walk(str(tmpdir)):
- if os.path.basename(dirpath) == 'site-packages':
- site_packages = dirpath
- break
- paths = ""
- if site_packages:
- try:
- from cffi import _pycparser
- modules = ('cffi', '_cffi_backend')
- except ImportError:
- modules = ('cffi', '_cffi_backend', 'pycparser')
- try:
- import ply
- except ImportError:
- pass
- else:
- modules += ('ply',) # needed for older versions of pycparser
- paths = []
- for module in modules:
- target = __import__(module, None, None, [])
- if not hasattr(target, '__file__'): # for _cffi_backend on pypy
- continue
- src = os.path.abspath(target.__file__)
- for end in ['__init__.pyc', '__init__.pyo', '__init__.py']:
- if src.lower().endswith(end):
- src = src[:-len(end)-1]
- break
- paths.append(os.path.dirname(src))
- paths = os.pathsep.join(paths)
- return tmpdir, paths
-
-SNIPPET_DIR = py.path.local(__file__).join('..', 'snippets')
-
-def really_run_setup_and_program(dirname, venv_dir_and_paths, python_snippet):
- venv_dir, paths = venv_dir_and_paths
- def remove(dir):
- dir = str(SNIPPET_DIR.join(dirname, dir))
- shutil.rmtree(dir, ignore_errors=True)
- remove('build')
- remove('__pycache__')
- for basedir in os.listdir(str(SNIPPET_DIR.join(dirname))):
- remove(os.path.join(basedir, '__pycache__'))
- olddir = os.getcwd()
- python_f = udir.join('x.py')
- python_f.write(py.code.Source(python_snippet))
- try:
- os.chdir(str(SNIPPET_DIR.join(dirname)))
- if os.name == 'nt':
- bindir = 'Scripts'
- else:
- bindir = 'bin'
- vp = str(venv_dir.join(bindir).join('python'))
- env = os.environ.copy()
- env['PYTHONPATH'] = paths
- subprocess.check_call((vp, 'setup.py', 'clean'), env=env)
- # there's a setuptools/easy_install bug that causes this to fail when the build/install occur together and
- # we're in the same directory with the build (it tries to look up dependencies for itself on PyPI);
- # subsequent runs will succeed because this test doesn't properly clean up the build- use pip for now.
- subprocess.check_call((vp, '-m', 'pip', 'install', '.'), env=env)
- subprocess.check_call((vp, str(python_f)), env=env)
- finally:
- os.chdir(olddir)
-
-def run_setup_and_program(dirname, python_snippet):
- venv_dir = create_venv(dirname + '-cpy')
- really_run_setup_and_program(dirname, venv_dir, python_snippet)
- #
- sys._force_generic_engine_ = True
- try:
- venv_dir = create_venv(dirname + '-gen')
- really_run_setup_and_program(dirname, venv_dir, python_snippet)
- finally:
- del sys._force_generic_engine_
- # the two files lextab.py and yacctab.py are created by not-correctly-
- # installed versions of pycparser.
- assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'lextab.py')))
- assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'yacctab.py')))
-
-class TestZIntegration(object):
- def teardown_class(self):
- if udir.isdir():
- udir.remove(ignore_errors=True)
- udir.ensure(dir=1)
-
- def test_infrastructure(self):
- run_setup_and_program('infrastructure', '''
- import snip_infrastructure
- assert snip_infrastructure.func() == 42
- ''')
-
- def test_distutils_module(self):
- run_setup_and_program("distutils_module", '''
- import snip_basic_verify
- p = snip_basic_verify.C.getpwuid(0)
- assert snip_basic_verify.ffi.string(p.pw_name) == b"root"
- ''')
-
- def test_distutils_package_1(self):
- run_setup_and_program("distutils_package_1", '''
- import snip_basic_verify1
- p = snip_basic_verify1.C.getpwuid(0)
- assert snip_basic_verify1.ffi.string(p.pw_name) == b"root"
- ''')
-
- def test_distutils_package_2(self):
- run_setup_and_program("distutils_package_2", '''
- import snip_basic_verify2
- p = snip_basic_verify2.C.getpwuid(0)
- assert snip_basic_verify2.ffi.string(p.pw_name) == b"root"
- ''')
-
- def test_setuptools_module(self):
- run_setup_and_program("setuptools_module", '''
- import snip_setuptools_verify
- p = snip_setuptools_verify.C.getpwuid(0)
- assert snip_setuptools_verify.ffi.string(p.pw_name) == b"root"
- ''')
-
- def test_setuptools_package_1(self):
- run_setup_and_program("setuptools_package_1", '''
- import snip_setuptools_verify1
- p = snip_setuptools_verify1.C.getpwuid(0)
- assert snip_setuptools_verify1.ffi.string(p.pw_name) == b"root"
- ''')
-
- def test_setuptools_package_2(self):
- run_setup_and_program("setuptools_package_2", '''
- import snip_setuptools_verify2
- p = snip_setuptools_verify2.C.getpwuid(0)
- assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root"
- ''')
-
- def test_set_py_limited_api(self):
- from cffi.setuptools_ext import _set_py_limited_api
- try:
- import setuptools
- except ImportError as e:
- py.test.skip(str(e))
- orig_version = setuptools.__version__
- expecting_limited_api = not hasattr(sys, 'gettotalrefcount')
- try:
- setuptools.__version__ = '26.0.0'
- from setuptools import Extension
-
- kwds = _set_py_limited_api(Extension, {})
- assert kwds.get('py_limited_api', False) == expecting_limited_api
-
- setuptools.__version__ = '25.0'
- kwds = _set_py_limited_api(Extension, {})
- assert kwds.get('py_limited_api', False) == False
-
- setuptools.__version__ = 'development'
- kwds = _set_py_limited_api(Extension, {})
- assert kwds.get('py_limited_api', False) == expecting_limited_api
-
- finally:
- setuptools.__version__ = orig_version
diff --git a/testing/cffi1/__init__.py b/testing/cffi1/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/testing/cffi1/__init__.py
+++ /dev/null
diff --git a/testing/cffi1/test_cffi_binary.py b/testing/cffi1/test_cffi_binary.py
deleted file mode 100644
index 7cfbace..0000000
--- a/testing/cffi1/test_cffi_binary.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import py, sys, os
-import _cffi_backend
-
-def test_no_unknown_exported_symbols():
- if not hasattr(_cffi_backend, '__file__'):
- py.test.skip("_cffi_backend module is built-in")
- if not sys.platform.startswith('linux'):
- py.test.skip("linux-only")
- g = os.popen("objdump -T '%s'" % _cffi_backend.__file__, 'r')
- for line in g:
- if not line.startswith('0'):
- continue
- if line[line.find(' ') + 1] == 'l':
- continue
- if '*UND*' in line:
- continue
- name = line.split()[-1]
- if name.startswith('_') or name.startswith('.'):
- continue
- if name not in ('init_cffi_backend', 'PyInit__cffi_backend'):
- raise Exception("Unexpected exported name %r" % (name,))
- g.close()
diff --git a/testing/cffi1/test_commontypes.py b/testing/cffi1/test_commontypes.py
deleted file mode 100644
index ea7ffde..0000000
--- a/testing/cffi1/test_commontypes.py
+++ /dev/null
@@ -1,34 +0,0 @@
-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 --git a/testing/cffi1/test_dlopen.py b/testing/cffi1/test_dlopen.py
deleted file mode 100644
index 26a2717..0000000
--- a/testing/cffi1/test_dlopen.py
+++ /dev/null
@@ -1,225 +0,0 @@
-import py
-from cffi import FFI, VerificationError, CDefError
-from cffi.recompiler import make_py_source
-from testing.udir import udir
-
-
-def test_simple():
- ffi = FFI()
- ffi.cdef("int close(int); static const int BB = 42; extern int somevar;")
- target = udir.join('test_simple.py')
- make_py_source(ffi, 'test_simple', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_simple',
- _version = 0x2601,
- _types = b'\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x00\x0F',
- _globals = (b'\xFF\xFF\xFF\x1FBB',42,b'\x00\x00\x00\x23close',0,b'\x00\x00\x01\x21somevar',0),
-)
-"""
-
-def test_global_constant():
- ffi = FFI()
- ffi.cdef("static const long BB; static const float BF = 12;")
- target = udir.join('test_valid_global_constant.py')
- make_py_source(ffi, 'test_valid_global_constant', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_valid_global_constant',
- _version = 0x2601,
- _types = b'\x00\x00\x0D\x01\x00\x00\x09\x01',
- _globals = (b'\x00\x00\x01\x25BB',0,b'\x00\x00\x00\x25BF',0),
-)
-"""
-
-def test_invalid_global_constant_3():
- ffi = FFI()
- e = py.test.raises(CDefError, ffi.cdef, "#define BB 12.34")
- assert str(e.value).startswith(
- "only supports one of the following syntax:")
-
-def test_invalid_dotdotdot_in_macro():
- ffi = FFI()
- ffi.cdef("#define FOO ...")
- target = udir.join('test_invalid_dotdotdot_in_macro.py')
- e = py.test.raises(VerificationError, make_py_source, ffi,
- 'test_invalid_dotdotdot_in_macro', str(target))
- assert str(e.value) == ("macro FOO: cannot use the syntax '...' in "
- "'#define FOO ...' when using the ABI mode")
-
-def test_typename():
- ffi = FFI()
- ffi.cdef("typedef int foobar_t;")
- target = udir.join('test_typename.py')
- make_py_source(ffi, 'test_typename', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_typename',
- _version = 0x2601,
- _types = b'\x00\x00\x07\x01',
- _typenames = (b'\x00\x00\x00\x00foobar_t',),
-)
-"""
-
-def test_enum():
- ffi = FFI()
- ffi.cdef("enum myenum_e { AA, BB, CC=-42 };")
- target = udir.join('test_enum.py')
- make_py_source(ffi, 'test_enum', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_enum',
- _version = 0x2601,
- _types = b'\x00\x00\x00\x0B',
- _globals = (b'\xFF\xFF\xFF\x0BAA',0,b'\xFF\xFF\xFF\x0BBB',1,b'\xFF\xFF\xFF\x0BCC',-42),
- _enums = (b'\x00\x00\x00\x00\x00\x00\x00\x15myenum_e\x00AA,BB,CC',),
-)
-"""
-
-def test_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a; signed char b[]; }; struct bar_s;")
- target = udir.join('test_struct.py')
- make_py_source(ffi, 'test_struct', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_struct',
- _version = 0x2601,
- _types = b'\x00\x00\x07\x01\x00\x00\x03\x01\x00\x00\x01\x07\x00\x00\x00\x09\x00\x00\x01\x09',
- _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x10bar_s',),(b'\x00\x00\x00\x04\x00\x00\x00\x02foo_s',b'\x00\x00\x00\x11a',b'\x00\x00\x02\x11b')),
-)
-"""
-
-def test_include():
- ffi = FFI()
- ffi.cdef("#define ABC 123")
- ffi.set_source('test_include', None)
- target = udir.join('test_include.py')
- make_py_source(ffi, 'test_include', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_include',
- _version = 0x2601,
- _types = b'',
- _globals = (b'\xFF\xFF\xFF\x1FABC',123,),
-)
-"""
- #
- ffi2 = FFI()
- ffi2.include(ffi)
- target2 = udir.join('test2_include.py')
- make_py_source(ffi2, 'test2_include', str(target2))
- assert target2.read() == r"""# auto-generated file
-import _cffi_backend
-from test_include import ffi as _ffi0
-
-ffi = _cffi_backend.FFI('test2_include',
- _version = 0x2601,
- _types = b'',
- _includes = (_ffi0,),
-)
-"""
-
-def test_negative_constant():
- ffi = FFI()
- ffi.cdef("static const int BB = -42;")
- target = udir.join('test_negative_constant.py')
- make_py_source(ffi, 'test_negative_constant', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_negative_constant',
- _version = 0x2601,
- _types = b'',
- _globals = (b'\xFF\xFF\xFF\x1FBB',-42,),
-)
-"""
-
-def test_struct_included():
- baseffi = FFI()
- baseffi.cdef("struct foo_s { int x; };")
- baseffi.set_source('test_struct_included_base', None)
- #
- ffi = FFI()
- ffi.include(baseffi)
- target = udir.join('test_struct_included.py')
- make_py_source(ffi, 'test_struct_included', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-from test_struct_included_base import ffi as _ffi0
-
-ffi = _cffi_backend.FFI('test_struct_included',
- _version = 0x2601,
- _types = b'\x00\x00\x00\x09',
- _struct_unions = ((b'\x00\x00\x00\x00\x00\x00\x00\x08foo_s',),),
- _includes = (_ffi0,),
-)
-"""
-
-def test_no_cross_include():
- baseffi = FFI()
- baseffi.set_source('test_no_cross_include_base', "..source..")
- #
- ffi = FFI()
- ffi.include(baseffi)
- target = udir.join('test_no_cross_include.py')
- py.test.raises(VerificationError, make_py_source,
- ffi, 'test_no_cross_include', str(target))
-
-def test_array():
- ffi = FFI()
- ffi.cdef("typedef int32_t my_array_t[42];")
- target = udir.join('test_array.py')
- make_py_source(ffi, 'test_array', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_array',
- _version = 0x2601,
- _types = b'\x00\x00\x15\x01\x00\x00\x00\x05\x00\x00\x00\x2A',
- _typenames = (b'\x00\x00\x00\x01my_array_t',),
-)
-"""
-
-def test_array_overflow():
- ffi = FFI()
- ffi.cdef("typedef int32_t my_array_t[3000000000];")
- target = udir.join('test_array_overflow.py')
- py.test.raises(OverflowError, make_py_source,
- ffi, 'test_array_overflow', str(target))
-
-def test_global_var():
- ffi = FFI()
- ffi.cdef("extern int myglob;")
- target = udir.join('test_global_var.py')
- make_py_source(ffi, 'test_global_var', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_global_var',
- _version = 0x2601,
- _types = b'\x00\x00\x07\x01',
- _globals = (b'\x00\x00\x00\x21myglob',0,),
-)
-"""
-
-def test_bitfield():
- ffi = FFI()
- ffi.cdef("struct foo_s { int y:10; short x:5; };")
- target = udir.join('test_bitfield.py')
- make_py_source(ffi, 'test_bitfield', str(target))
- assert target.read() == r"""# auto-generated file
-import _cffi_backend
-
-ffi = _cffi_backend.FFI('test_bitfield',
- _version = 0x2601,
- _types = b'\x00\x00\x07\x01\x00\x00\x05\x01\x00\x00\x00\x09',
- _struct_unions = ((b'\x00\x00\x00\x02\x00\x00\x00\x02foo_s',b'\x00\x00\x00\x13\x00\x00\x00\x0Ay',b'\x00\x00\x01\x13\x00\x00\x00\x05x'),),
-)
-"""
diff --git a/testing/cffi1/test_dlopen_unicode_literals.py b/testing/cffi1/test_dlopen_unicode_literals.py
deleted file mode 100644
index e792866..0000000
--- a/testing/cffi1/test_dlopen_unicode_literals.py
+++ /dev/null
@@ -1,9 +0,0 @@
-import py, os
-
-s = """from __future__ import unicode_literals
-"""
-
-with open(os.path.join(os.path.dirname(__file__), 'test_dlopen.py')) as f:
- s += f.read()
-
-exec(py.code.compile(s))
diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py
deleted file mode 100644
index 0d29290..0000000
--- a/testing/cffi1/test_ffi_obj.py
+++ /dev/null
@@ -1,536 +0,0 @@
-import py, sys
-import pytest
-import _cffi_backend as _cffi1_backend
-
-
-def test_ffi_new():
- ffi = _cffi1_backend.FFI()
- p = ffi.new("int *")
- p[0] = -42
- assert p[0] == -42
- assert type(ffi) is ffi.__class__ is _cffi1_backend.FFI
-
-def test_ffi_subclass():
- class FOO(_cffi1_backend.FFI):
- def __init__(self, x):
- self.x = x
- foo = FOO(42)
- assert foo.x == 42
- p = foo.new("int *")
- assert p[0] == 0
- assert type(foo) is foo.__class__ is FOO
-
-def test_ffi_no_argument():
- py.test.raises(TypeError, _cffi1_backend.FFI, 42)
-
-def test_ffi_cache_type():
- ffi = _cffi1_backend.FFI()
- t1 = ffi.typeof("int **")
- t2 = ffi.typeof("int *")
- assert t2.item is t1.item.item
- assert t2 is t1.item
- assert ffi.typeof("int[][10]") is ffi.typeof("int[][10]")
- assert ffi.typeof("int(*)()") is ffi.typeof("int(*)()")
-
-def test_ffi_type_not_immortal():
- import weakref, gc
- ffi = _cffi1_backend.FFI()
- t1 = ffi.typeof("int **")
- t2 = ffi.typeof("int *")
- w1 = weakref.ref(t1)
- w2 = weakref.ref(t2)
- del t1, ffi
- gc.collect()
- assert w1() is None
- assert w2() is t2
- ffi = _cffi1_backend.FFI()
- assert ffi.typeof(ffi.new("int **")[0]) is t2
- #
- ffi = _cffi1_backend.FFI()
- t1 = ffi.typeof("int ***")
- t2 = ffi.typeof("int **")
- w1 = weakref.ref(t1)
- w2 = weakref.ref(t2)
- del t2, ffi
- gc.collect()
- assert w1() is t1
- assert w2() is not None # kept alive by t1
- ffi = _cffi1_backend.FFI()
- assert ffi.typeof("int * *") is t1.item
-
-def test_ffi_cache_type_globally():
- ffi1 = _cffi1_backend.FFI()
- ffi2 = _cffi1_backend.FFI()
- t1 = ffi1.typeof("int *")
- t2 = ffi2.typeof("int *")
- assert t1 is t2
-
-def test_ffi_invalid():
- ffi = _cffi1_backend.FFI()
- # array of 10 times an "int[]" is invalid
- py.test.raises(ValueError, ffi.typeof, "int[10][]")
-
-def test_ffi_docstrings():
- # check that all methods of the FFI class have a docstring.
- check_type = type(_cffi1_backend.FFI.new)
- for methname in dir(_cffi1_backend.FFI):
- if not methname.startswith('_'):
- method = getattr(_cffi1_backend.FFI, methname)
- if isinstance(method, check_type):
- assert method.__doc__, "method FFI.%s() has no docstring" % (
- methname,)
-
-def test_ffi_NULL():
- NULL = _cffi1_backend.FFI.NULL
- assert _cffi1_backend.FFI().typeof(NULL).cname == "void *"
-
-def test_ffi_no_attr():
- ffi = _cffi1_backend.FFI()
- with pytest.raises(AttributeError):
- ffi.no_such_name
- with pytest.raises(AttributeError):
- ffi.no_such_name = 42
- with pytest.raises(AttributeError):
- del ffi.no_such_name
-
-def test_ffi_string():
- ffi = _cffi1_backend.FFI()
- p = ffi.new("char[]", init=b"foobar\x00baz")
- assert ffi.string(p) == b"foobar"
- assert ffi.string(cdata=p, maxlen=3) == b"foo"
-
-def test_ffi_errno():
- # xxx not really checking errno, just checking that we can read/write it
- ffi = _cffi1_backend.FFI()
- ffi.errno = 42
- assert ffi.errno == 42
-
-def test_ffi_alignof():
- ffi = _cffi1_backend.FFI()
- assert ffi.alignof("int") == 4
- assert ffi.alignof("int[]") == 4
- assert ffi.alignof("int[41]") == 4
- assert ffi.alignof("short[41]") == 2
- assert ffi.alignof(ffi.new("int[41]")) == 4
- assert ffi.alignof(ffi.new("int[]", 41)) == 4
-
-def test_ffi_sizeof():
- ffi = _cffi1_backend.FFI()
- assert ffi.sizeof("int") == 4
- py.test.raises(ffi.error, ffi.sizeof, "int[]")
- assert ffi.sizeof("int[41]") == 41 * 4
- assert ffi.sizeof(ffi.new("int[41]")) == 41 * 4
- assert ffi.sizeof(ffi.new("int[]", 41)) == 41 * 4
-
-def test_ffi_callback():
- ffi = _cffi1_backend.FFI()
- assert ffi.callback("int(int)", lambda x: x + 42)(10) == 52
- assert ffi.callback("int(*)(int)", lambda x: x + 42)(10) == 52
- assert ffi.callback("int(int)", lambda x: x + "", -66)(10) == -66
- assert ffi.callback("int(int)", lambda x: x + "", error=-66)(10) == -66
-
-def test_ffi_callback_decorator():
- ffi = _cffi1_backend.FFI()
- assert ffi.callback(ffi.typeof("int(*)(int)"))(lambda x: x + 42)(10) == 52
- deco = ffi.callback("int(int)", error=-66)
- assert deco(lambda x: x + "")(10) == -66
- assert deco(lambda x: x + 42)(10) == 52
-
-def test_ffi_callback_onerror():
- ffi = _cffi1_backend.FFI()
- seen = []
- def oops(*args):
- seen.append(args)
-
- @ffi.callback("int(int)", onerror=oops)
- def fn1(x):
- return x + ""
- assert fn1(10) == 0
-
- @ffi.callback("int(int)", onerror=oops, error=-66)
- def fn2(x):
- return x + ""
- assert fn2(10) == -66
-
- assert len(seen) == 2
- exc, val, tb = seen[0]
- assert exc is TypeError
- assert isinstance(val, TypeError)
- assert tb.tb_frame.f_code.co_name == "fn1"
- exc, val, tb = seen[1]
- assert exc is TypeError
- assert isinstance(val, TypeError)
- assert tb.tb_frame.f_code.co_name == "fn2"
- #
- py.test.raises(TypeError, ffi.callback, "int(int)",
- lambda x: x, onerror=42) # <- not callable
-
-def test_ffi_getctype():
- ffi = _cffi1_backend.FFI()
- assert ffi.getctype("int") == "int"
- assert ffi.getctype("int", 'x') == "int x"
- assert ffi.getctype("int*") == "int *"
- assert ffi.getctype("int*", '') == "int *"
- assert ffi.getctype("int*", 'x') == "int * x"
- assert ffi.getctype("int", '*') == "int *"
- assert ffi.getctype("int", replace_with=' * x ') == "int * x"
- assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *"
- assert ffi.getctype("int", '[5]') == "int[5]"
- assert ffi.getctype("int[5]", '[6]') == "int[6][5]"
- assert ffi.getctype("int[5]", '(*)') == "int(*)[5]"
- # special-case for convenience: automatically put '()' around '*'
- assert ffi.getctype("int[5]", '*') == "int(*)[5]"
- assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]"
- assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"
-
-def test_addressof():
- ffi = _cffi1_backend.FFI()
- a = ffi.new("int[10]")
- b = ffi.addressof(a, 5)
- b[2] = -123
- assert a[7] == -123
-
-def test_handle():
- ffi = _cffi1_backend.FFI()
- x = [2, 4, 6]
- xp = ffi.new_handle(x)
- assert ffi.typeof(xp) == ffi.typeof("void *")
- assert ffi.from_handle(xp) is x
- yp = ffi.new_handle([6, 4, 2])
- assert ffi.from_handle(yp) == [6, 4, 2]
-
-def test_handle_unique():
- ffi = _cffi1_backend.FFI()
- assert ffi.new_handle(None) is not ffi.new_handle(None)
- assert ffi.new_handle(None) != ffi.new_handle(None)
-
-def test_ffi_cast():
- ffi = _cffi1_backend.FFI()
- assert ffi.cast("int(*)(int)", 0) == ffi.NULL
- ffi.callback("int(int)") # side-effect of registering this string
- py.test.raises(ffi.error, ffi.cast, "int(int)", 0)
-
-def test_ffi_invalid_type():
- ffi = _cffi1_backend.FFI()
- e = py.test.raises(ffi.error, ffi.cast, "", 0)
- assert str(e.value) == ("identifier expected\n"
- "\n"
- "^")
- e = py.test.raises(ffi.error, ffi.cast, "struct struct", 0)
- assert str(e.value) == ("struct or union name expected\n"
- "struct struct\n"
- " ^")
- e = py.test.raises(ffi.error, ffi.cast, "struct never_heard_of_s", 0)
- assert str(e.value) == ("undefined struct/union name\n"
- "struct never_heard_of_s\n"
- " ^")
- e = py.test.raises(ffi.error, ffi.cast, "\t\n\x01\x1f~\x7f\x80\xff", 0)
- marks = "?" if sys.version_info < (3,) else "??"
- assert str(e.value) == ("identifier expected\n"
- " ??~?%s%s\n"
- " ^" % (marks, marks))
- e = py.test.raises(ffi.error, ffi.cast, "X" * 600, 0)
- assert str(e.value) == ("undefined type name")
-
-def test_ffi_buffer():
- ffi = _cffi1_backend.FFI()
- a = ffi.new("signed char[]", [5, 6, 7])
- assert ffi.buffer(a)[:] == b'\x05\x06\x07'
- assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06'
- assert type(ffi.buffer(a)) is ffi.buffer
-
-def test_ffi_from_buffer():
- import array
- ffi = _cffi1_backend.FFI()
- a = array.array('H', [10000, 20000, 30000, 40000])
- c = ffi.from_buffer(a)
- assert ffi.typeof(c) is ffi.typeof("char[]")
- assert len(c) == 8
- ffi.cast("unsigned short *", c)[1] += 500
- assert list(a) == [10000, 20500, 30000, 40000]
- py.test.raises(TypeError, ffi.from_buffer, a, True)
- assert c == ffi.from_buffer("char[]", a, True)
- assert c == ffi.from_buffer(a, require_writable=True)
- #
- c = ffi.from_buffer("unsigned short[]", a)
- assert len(c) == 4
- assert c[1] == 20500
- #
- c = ffi.from_buffer("unsigned short[2][2]", a)
- assert len(c) == 2
- assert len(c[0]) == 2
- assert c[0][1] == 20500
- #
- p = ffi.from_buffer(b"abcd")
- assert p[2] == b"c"
- #
- assert p == ffi.from_buffer(b"abcd", require_writable=False)
- py.test.raises((TypeError, BufferError), ffi.from_buffer,
- "char[]", b"abcd", True)
- py.test.raises((TypeError, BufferError), ffi.from_buffer, b"abcd",
- require_writable=True)
-
-def test_memmove():
- ffi = _cffi1_backend.FFI()
- p = ffi.new("short[]", [-1234, -2345, -3456, -4567, -5678])
- ffi.memmove(p, p + 1, 4)
- assert list(p) == [-2345, -3456, -3456, -4567, -5678]
- p[2] = 999
- ffi.memmove(p + 2, p, 6)
- assert list(p) == [-2345, -3456, -2345, -3456, 999]
- ffi.memmove(p + 4, ffi.new("char[]", 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
- ffi = _cffi1_backend.FFI()
- a = array.array('H', [10000, 20000, 30000])
- p = ffi.new("short[]", 5)
- ffi.memmove(p, a, 6)
- assert list(p) == [10000, 20000, 30000, 0, 0]
- ffi.memmove(p + 1, a, 6)
- assert list(p) == [10000, 10000, 20000, 30000, 0]
- b = array.array('h', [-1000, -2000, -3000])
- ffi.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
- ffi.memmove(b, p, 2)
- assert b.tolist() == [999, 20000, -3000]
- ffi.memmove(b, p + 2, 4)
- assert b.tolist() == [997, 996, -3000]
- p[2] = -p[2]
- p[3] = -p[3]
- ffi.memmove(b, p + 2, 6)
- assert b.tolist() == [-997, -996, 995]
-
-def test_memmove_readonly_readwrite():
- ffi = _cffi1_backend.FFI()
- p = ffi.new("signed char[]", 5)
- ffi.memmove(p, b"abcde", 3)
- assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0]
- ffi.memmove(p, bytearray(b"ABCDE"), 2)
- assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0]
- py.test.raises((TypeError, BufferError), ffi.memmove, b"abcde", p, 3)
- ba = bytearray(b"xxxxx")
- ffi.memmove(dest=ba, src=p, n=3)
- assert ba == bytearray(b"ABcxx")
-
-def test_ffi_types():
- CData = _cffi1_backend.FFI.CData
- CType = _cffi1_backend.FFI.CType
- ffi = _cffi1_backend.FFI()
- assert isinstance(ffi.cast("int", 42), CData)
- assert isinstance(ffi.typeof("int"), CType)
-
-def test_ffi_getwinerror():
- if sys.platform != "win32":
- py.test.skip("for windows")
- ffi = _cffi1_backend.FFI()
- n = (1 << 29) + 42
- code, message = ffi.getwinerror(code=n)
- assert code == n
-
-def test_ffi_new_allocator_1():
- ffi = _cffi1_backend.FFI()
- alloc1 = ffi.new_allocator()
- alloc2 = ffi.new_allocator(should_clear_after_alloc=False)
- for retry in range(100):
- p1 = alloc1("int[10]")
- p2 = alloc2("int[10]")
- combination = 0
- for i in range(10):
- assert p1[i] == 0
- combination |= p2[i]
- p1[i] = -42
- p2[i] = -43
- if combination != 0:
- break
- del p1, p2
- import gc; gc.collect()
- else:
- raise AssertionError("cannot seem to get an int[10] not "
- "completely cleared")
-
-def test_ffi_new_allocator_2():
- ffi = _cffi1_backend.FFI()
- seen = []
- def myalloc(size):
- seen.append(size)
- return ffi.new("char[]", b"X" * size)
- def myfree(raw):
- seen.append(raw)
- alloc1 = ffi.new_allocator(myalloc, myfree)
- alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree,
- should_clear_after_alloc=False)
- p1 = alloc1("int[10]")
- p2 = alloc2("int[]", 10)
- assert seen == [40, 40]
- assert ffi.typeof(p1) == ffi.typeof("int[10]")
- assert ffi.sizeof(p1) == 40
- assert ffi.typeof(p2) == ffi.typeof("int[]")
- assert ffi.sizeof(p2) == 40
- assert p1[5] == 0
- assert p2[6] == ord('X') * 0x01010101
- raw1 = ffi.cast("char *", p1)
- raw2 = ffi.cast("char *", p2)
- del p1, p2
- retries = 0
- while len(seen) != 4:
- retries += 1
- assert retries <= 5
- import gc; gc.collect()
- assert (seen == [40, 40, raw1, raw2] or
- seen == [40, 40, raw2, raw1])
- assert repr(seen[2]) == "<cdata 'char[]' owning 41 bytes>"
- assert repr(seen[3]) == "<cdata 'char[]' owning 41 bytes>"
-
-def test_ffi_new_allocator_3():
- ffi = _cffi1_backend.FFI()
- seen = []
- def myalloc(size):
- seen.append(size)
- return ffi.new("char[]", b"X" * size)
- alloc1 = ffi.new_allocator(myalloc) # no 'free'
- p1 = alloc1("int[10]")
- assert seen == [40]
- assert ffi.typeof(p1) == ffi.typeof("int[10]")
- assert ffi.sizeof(p1) == 40
- assert p1[5] == 0
-
-def test_ffi_new_allocator_4():
- ffi = _cffi1_backend.FFI()
- py.test.raises(TypeError, ffi.new_allocator, free=lambda x: None)
- #
- def myalloc2(size):
- raise LookupError
- alloc2 = ffi.new_allocator(myalloc2)
- py.test.raises(LookupError, alloc2, "int[5]")
- #
- def myalloc3(size):
- return 42
- alloc3 = ffi.new_allocator(myalloc3)
- e = py.test.raises(TypeError, alloc3, "int[5]")
- assert str(e.value) == "alloc() must return a cdata object (got int)"
- #
- def myalloc4(size):
- return ffi.cast("int", 42)
- alloc4 = ffi.new_allocator(myalloc4)
- e = py.test.raises(TypeError, alloc4, "int[5]")
- assert str(e.value) == "alloc() must return a cdata pointer, not 'int'"
- #
- def myalloc5(size):
- 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
-
-def test_init_once():
- def do_init():
- seen.append(1)
- return 42
- ffi = _cffi1_backend.FFI()
- seen = []
- for i in range(3):
- res = ffi.init_once(do_init, "tag1")
- assert res == 42
- assert seen == [1]
- for i in range(3):
- res = ffi.init_once(do_init, "tag2")
- assert res == 42
- assert seen == [1, 1]
-
-def test_init_once_multithread():
- if sys.version_info < (3,):
- import thread
- else:
- import _thread as thread
- import time
- #
- def do_init():
- print('init!')
- seen.append('init!')
- time.sleep(1)
- seen.append('init done')
- print('init done')
- return 7
- ffi = _cffi1_backend.FFI()
- seen = []
- for i in range(6):
- def f():
- res = ffi.init_once(do_init, "tag")
- seen.append(res)
- thread.start_new_thread(f, ())
- time.sleep(1.5)
- assert seen == ['init!', 'init done'] + 6 * [7]
-
-def test_init_once_failure():
- def do_init():
- seen.append(1)
- raise ValueError
- ffi = _cffi1_backend.FFI()
- seen = []
- for i in range(5):
- py.test.raises(ValueError, ffi.init_once, do_init, "tag")
- assert seen == [1] * (i + 1)
-
-def test_init_once_multithread_failure():
- if sys.version_info < (3,):
- import thread
- else:
- import _thread as thread
- import time
- def do_init():
- seen.append('init!')
- time.sleep(1)
- seen.append('oops')
- raise ValueError
- ffi = _cffi1_backend.FFI()
- seen = []
- for i in range(3):
- def f():
- py.test.raises(ValueError, ffi.init_once, do_init, "tag")
- thread.start_new_thread(f, ())
- i = 0
- while len(seen) < 6:
- i += 1
- assert i < 20
- time.sleep(0.51)
- assert seen == ['init!', 'oops'] * 3
-
-def test_unpack():
- ffi = _cffi1_backend.FFI()
- p = ffi.new("char[]", b"abc\x00def")
- assert ffi.unpack(p+1, 7) == b"bc\x00def\x00"
- p = ffi.new("int[]", [-123456789])
- assert ffi.unpack(p, 1) == [-123456789]
-
-def test_negative_array_size():
- ffi = _cffi1_backend.FFI()
- py.test.raises(ffi.error, ffi.cast, "int[-5]", 0)
diff --git a/testing/cffi1/test_function_args.py b/testing/cffi1/test_function_args.py
deleted file mode 100644
index 30c6fed..0000000
--- a/testing/cffi1/test_function_args.py
+++ /dev/null
@@ -1,208 +0,0 @@
-import pytest, sys
-try:
- # comment out the following line to run this test.
- # the latest on x86-64 linux: https://github.com/libffi/libffi/issues/574
- if sys.platform != 'win32':
- raise ImportError("this test is skipped because it keeps finding "
- "failures in libffi, instead of cffi")
-
- from hypothesis import given, settings, example
- from hypothesis import strategies as st
-except ImportError as e:
- e1 = e
- def test_types():
- pytest.skip(str(e1))
-else:
-
- from cffi import FFI
- import sys, random
- from .test_recompiler import verify
-
- ALL_PRIMITIVES = [
- 'unsigned char',
- 'short',
- 'int',
- 'long',
- 'long long',
- 'float',
- 'double',
- #'long double', --- on x86 it can give libffi crashes
- ]
- def _make_struct(s):
- return st.lists(s, min_size=1)
- types = st.one_of(st.sampled_from(ALL_PRIMITIVES),
- st.lists(st.sampled_from(ALL_PRIMITIVES), min_size=1))
- # NB. 'types' could be st.recursive instead, but it doesn't
- # really seem useful
-
- def draw_primitive(ffi, typename):
- value = random.random() * 2**40
- if typename != 'long double':
- return ffi.cast(typename, value)
- else:
- return value
-
- TEST_RUN_COUNTER = 0
-
-
- @given(st.lists(types), types)
- @settings(max_examples=100, deadline=5000) # 5000ms
- def test_types(tp_args, tp_result):
- global TEST_RUN_COUNTER
- print(tp_args, tp_result)
- cdefs = []
- structs = {}
-
- def build_type(tp):
- if type(tp) is list:
- field_types = [build_type(tp1) for tp1 in tp]
- fields = ['%s f%d;' % (ftp, j)
- for (j, ftp) in enumerate(field_types)]
- fields = '\n '.join(fields)
- name = 's%d' % len(cdefs)
- cdefs.append("typedef struct {\n %s\n} %s;" % (fields, name))
- structs[name] = field_types
- return name
- else:
- return tp
-
- args = [build_type(tp) for tp in tp_args]
- result = build_type(tp_result)
-
- TEST_RUN_COUNTER += 1
- signature = "%s testfargs(%s)" % (result,
- ', '.join(['%s a%d' % (arg, i) for (i, arg) in enumerate(args)])
- or 'void')
-
- source = list(cdefs)
-
- cdefs.append("%s;" % signature)
- cdefs.append("extern %s testfargs_result;" % result)
- for i, arg in enumerate(args):
- cdefs.append("extern %s testfargs_arg%d;" % (arg, i))
- source.append("%s testfargs_result;" % result)
- for i, arg in enumerate(args):
- source.append("%s testfargs_arg%d;" % (arg, i))
- source.append(signature)
- source.append("{")
- for i, arg in enumerate(args):
- source.append(" testfargs_arg%d = a%d;" % (i, i))
- source.append(" return testfargs_result;")
- source.append("}")
-
- typedef_line = "typedef %s;" % (signature.replace('testfargs',
- '(*mycallback_t)'),)
- assert signature.endswith(')')
- sig_callback = "%s testfcallback(mycallback_t callback)" % result
- cdefs.append(typedef_line)
- cdefs.append("%s;" % sig_callback)
- source.append(typedef_line)
- source.append(sig_callback)
- source.append("{")
- source.append(" return callback(%s);" %
- ', '.join(["testfargs_arg%d" % i for i in range(len(args))]))
- source.append("}")
-
- ffi = FFI()
- ffi.cdef("\n".join(cdefs))
- lib = verify(ffi, 'test_function_args_%d' % TEST_RUN_COUNTER,
- "\n".join(source), no_cpp=True)
-
- # when getting segfaults, enable this:
- if False:
- from testing.udir import udir
- import subprocess
- f = open(str(udir.join('run1.py')), 'w')
- f.write('import sys; sys.path = %r\n' % (sys.path,))
- f.write('from _CFFI_test_function_args_%d import ffi, lib\n' %
- TEST_RUN_COUNTER)
- for i in range(len(args)):
- f.write('a%d = ffi.new("%s *")\n' % (i, args[i]))
- aliststr = ', '.join(['a%d[0]' % i for i in range(len(args))])
- f.write('lib.testfargs(%s)\n' % aliststr)
- f.write('ffi.addressof(lib, "testfargs")(%s)\n' % aliststr)
- f.close()
- print("checking for segfault for direct call...")
- rc = subprocess.call([sys.executable, 'run1.py'], cwd=str(udir))
- assert rc == 0, rc
-
- def make_arg(tp):
- if tp in structs:
- return [make_arg(tp1) for tp1 in structs[tp]]
- else:
- return draw_primitive(ffi, tp)
-
- passed_args = [make_arg(arg) for arg in args]
- returned_value = make_arg(result)
-
- def write(p, v):
- if type(v) is list:
- for i, v1 in enumerate(v):
- write(ffi.addressof(p, 'f%d' % i), v1)
- else:
- p[0] = v
-
- write(ffi.addressof(lib, 'testfargs_result'), returned_value)
-
- ## CALL forcing libffi
- print("CALL forcing libffi")
- received_return = ffi.addressof(lib, 'testfargs')(*passed_args)
- ##
-
- _tp_long_double = ffi.typeof("long double")
- def check(p, v):
- if type(v) is list:
- for i, v1 in enumerate(v):
- check(ffi.addressof(p, 'f%d' % i), v1)
- else:
- if ffi.typeof(p).item is _tp_long_double:
- assert ffi.cast("double", p[0]) == v
- else:
- assert p[0] == v
-
- for i, arg in enumerate(passed_args):
- check(ffi.addressof(lib, 'testfargs_arg%d' % i), arg)
- ret = ffi.new(result + "*", received_return)
- check(ret, returned_value)
-
- ## CALLBACK
- def expand(value):
- if isinstance(value, ffi.CData):
- t = ffi.typeof(value)
- if t is _tp_long_double:
- return float(ffi.cast("double", value))
- return [expand(getattr(value, 'f%d' % i))
- for i in range(len(t.fields))]
- else:
- return value
-
- # when getting segfaults, enable this:
- if False:
- from testing.udir import udir
- import subprocess
- f = open(str(udir.join('run1.py')), 'w')
- f.write('import sys; sys.path = %r\n' % (sys.path,))
- f.write('from _CFFI_test_function_args_%d import ffi, lib\n' %
- TEST_RUN_COUNTER)
- f.write('def callback(*args): return ffi.new("%s *")[0]\n' % result)
- f.write('fptr = ffi.callback("%s(%s)", callback)\n' % (result,
- ','.join(args)))
- f.write('print(lib.testfcallback(fptr))\n')
- f.close()
- print("checking for segfault for callback...")
- rc = subprocess.call([sys.executable, 'run1.py'], cwd=str(udir))
- assert rc == 0, rc
-
- seen_args = []
- def callback(*args):
- seen_args.append([expand(arg) for arg in args])
- return returned_value
-
- fptr = ffi.callback("%s(%s)" % (result, ','.join(args)), callback)
- print("CALL with callback")
- received_return = lib.testfcallback(fptr)
-
- assert len(seen_args) == 1
- assert passed_args == seen_args[0]
- ret = ffi.new(result + "*", received_return)
- check(ret, returned_value)
diff --git a/testing/cffi1/test_new_ffi_1.py b/testing/cffi1/test_new_ffi_1.py
deleted file mode 100644
index 640830b..0000000
--- a/testing/cffi1/test_new_ffi_1.py
+++ /dev/null
@@ -1,1831 +0,0 @@
-import py
-import pytest
-import platform, imp
-import sys, os, ctypes
-import cffi
-from testing.udir import udir
-from testing.support import *
-from cffi.recompiler import recompile
-from cffi.cffi_opcode import PRIMITIVE_TO_INDEX
-
-SIZE_OF_INT = ctypes.sizeof(ctypes.c_int)
-SIZE_OF_LONG = ctypes.sizeof(ctypes.c_long)
-SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short)
-SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p)
-SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
-
-
-def setup_module():
- global ffi, construction_params
- ffi1 = cffi.FFI()
- DEFS = r"""
- struct repr { short a, b, c; };
- struct simple { int a; short b, c; };
- struct array { int a[2]; char b[3]; };
- struct recursive { int value; struct recursive *next; };
- union simple_u { int a; short b, c; };
- union init_u { char a; int b; };
- struct four_s { int a; short b, c, d; };
- union four_u { int a; short b, c, d; };
- struct string { const char *name; };
- struct ustring { const wchar_t *name; };
- struct voidp { void *p; int *q; short *r; };
- struct ab { int a, b; };
- struct abc { int a, b, c; };
-
- /* don't use A0, B0, CC0, D0 because termios.h might be included
- and it has its own #defines for these names */
- enum foq { cffiA0, cffiB0, cffiCC0, cffiD0 };
- enum bar { A1, B1=-2, CC1, D1, E1 };
- enum baz { A2=0x1000, B2=0x2000 };
- enum foo2 { A3, B3, C3, D3 };
- struct bar_with_e { enum foo2 e; };
- enum noncont { A4, B4=42, C4 };
- enum etypes {A5='!', B5='\'', C5=0x10, D5=010, E5=- 0x10, F5=-010};
- typedef enum { Value0 = 0 } e_t, *pe_t;
- enum e_noninj { AA3=0, BB3=0, CC3=0, DD3=0 };
- enum e_prev { AA4, BB4=2, CC4=4, DD4=BB4, EE4, FF4=CC4, GG4=FF4 };
-
- struct nesting { struct abc d, e; };
- struct array2 { int a, b; int c[99]; };
- struct align { char a; short b; char c; };
- struct bitfield { int a:10, b:20, c:3; };
- typedef enum { AA2, BB2, CC2 } foo_e_t;
- typedef struct { foo_e_t f:2; } bfenum_t;
- typedef struct { int a; } anon_foo_t;
- typedef struct { char b, c; } anon_bar_t;
- typedef struct named_foo_s { int a; } named_foo_t, *named_foo_p;
- typedef struct { int a; } unnamed_foo_t, *unnamed_foo_p;
- struct nonpacked { char a; int b; };
- struct array0 { int len; short data[0]; };
- struct array_no_length { int x; int a[]; };
-
- struct nested_anon {
- struct { int a, b; };
- union { int c, d; };
- };
- struct nested_field_ofs_s {
- struct { int a; char b; };
- union { char c; };
- };
- union nested_anon_u {
- struct { int a, b; };
- union { int c, d; };
- };
- struct abc50 { int a, b; int c[50]; };
- struct ints_and_bitfield { int a,b,c,d,e; int x:1; };
- """
- DEFS_PACKED = """
- struct is_packed { char a; int b; } /*here*/;
- """
- if sys.platform == "win32":
- DEFS = DEFS.replace('data[0]', 'data[1]') # not supported
- CCODE = (DEFS + "\n#pragma pack(push,1)\n" + DEFS_PACKED +
- "\n#pragma pack(pop)\n")
- else:
- CCODE = (DEFS +
- DEFS_PACKED.replace('/*here*/', '__attribute__((packed))'))
-
- ffi1.cdef(DEFS)
- ffi1.cdef(DEFS_PACKED, packed=True)
- ffi1.set_source("test_new_ffi_1", CCODE)
-
- outputfilename = recompile(ffi1, "test_new_ffi_1", CCODE,
- tmpdir=str(udir))
- module = imp.load_dynamic("test_new_ffi_1", outputfilename)
- ffi = module.ffi
- construction_params = (ffi1, CCODE)
-
-
-class TestNewFFI1:
-
- def test_integer_ranges(self):
- for (c_type, size) in [('char', 1),
- ('short', 2),
- ('short int', 2),
- ('', 4),
- ('int', 4),
- ('long', SIZE_OF_LONG),
- ('long int', SIZE_OF_LONG),
- ('long long', 8),
- ('long long int', 8),
- ]:
- for unsigned in [None, False, True]:
- c_decl = {None: '',
- False: 'signed ',
- True: 'unsigned '}[unsigned] + c_type
- if c_decl == 'char' or c_decl == '':
- continue
- self._test_int_type(ffi, c_decl, size, unsigned)
-
- def test_fixedsize_int(self):
- for size in [1, 2, 4, 8]:
- self._test_int_type(ffi, 'int%d_t' % (8*size), size, False)
- self._test_int_type(ffi, 'uint%d_t' % (8*size), size, True)
- self._test_int_type(ffi, 'intptr_t', SIZE_OF_PTR, False)
- self._test_int_type(ffi, 'uintptr_t', SIZE_OF_PTR, True)
- self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False)
- self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True)
- self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False)
-
- def _test_int_type(self, ffi, c_decl, size, unsigned):
- if unsigned:
- min = 0
- max = (1 << (8*size)) - 1
- else:
- min = -(1 << (8*size-1))
- max = (1 << (8*size-1)) - 1
- min = int(min)
- max = int(max)
- p = ffi.cast(c_decl, min)
- assert p == min
- assert bool(p) is bool(min)
- assert int(p) == min
- p = ffi.cast(c_decl, max)
- assert int(p) == max
- p = ffi.cast(c_decl, long(max))
- assert int(p) == max
- q = ffi.cast(c_decl, min - 1)
- assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
- q = ffi.cast(c_decl, long(min - 1))
- assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
- assert q == p
- assert int(q) == int(p)
- assert hash(q) == hash(p)
- c_decl_ptr = '%s *' % c_decl
- py.test.raises(OverflowError, ffi.new, c_decl_ptr, min - 1)
- py.test.raises(OverflowError, ffi.new, c_decl_ptr, max + 1)
- py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1))
- py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1))
- assert ffi.new(c_decl_ptr, min)[0] == min
- assert ffi.new(c_decl_ptr, max)[0] == max
- assert ffi.new(c_decl_ptr, long(min))[0] == min
- assert ffi.new(c_decl_ptr, long(max))[0] == max
-
- def test_new_unsupported_type(self):
- e = py.test.raises(TypeError, ffi.new, "int")
- assert str(e.value) == "expected a pointer or array ctype, got 'int'"
-
- def test_new_single_integer(self):
- p = ffi.new("int *") # similar to ffi.new("int[1]")
- assert p[0] == 0
- p[0] = -123
- assert p[0] == -123
- p = ffi.new("int *", -42)
- assert p[0] == -42
- assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT
-
- def test_new_array_no_arg(self):
- p = ffi.new("int[10]")
- # the object was zero-initialized:
- for i in range(10):
- assert p[i] == 0
-
- def test_array_indexing(self):
- p = ffi.new("int[10]")
- p[0] = 42
- p[9] = 43
- assert p[0] == 42
- assert p[9] == 43
- with pytest.raises(IndexError):
- p[10]
- with pytest.raises(IndexError):
- p[10] = 44
- with pytest.raises(IndexError):
- p[-1]
- with pytest.raises(IndexError):
- p[-1] = 44
-
- def test_new_array_args(self):
- # this tries to be closer to C: where we say "int x[5] = {10, 20, ..}"
- # then here we must enclose the items in a list
- p = ffi.new("int[5]", [10, 20, 30, 40, 50])
- assert p[0] == 10
- assert p[1] == 20
- assert p[2] == 30
- assert p[3] == 40
- assert p[4] == 50
- p = ffi.new("int[4]", [25])
- assert p[0] == 25
- assert p[1] == 0 # follow C convention rather than LuaJIT's
- assert p[2] == 0
- assert p[3] == 0
- p = ffi.new("int[4]", [ffi.cast("int", -5)])
- assert p[0] == -5
- assert repr(p) == "<cdata 'int[4]' owning %d bytes>" % (4*SIZE_OF_INT)
-
- def test_new_array_varsize(self):
- p = ffi.new("int[]", 10) # a single integer is the length
- assert p[9] == 0
- with pytest.raises(IndexError):
- p[10]
- #
- py.test.raises(TypeError, ffi.new, "int[]")
- #
- p = ffi.new("int[]", [-6, -7]) # a list is all the items, like C
- assert p[0] == -6
- assert p[1] == -7
- with pytest.raises(IndexError):
- p[2]
- assert repr(p) == "<cdata 'int[]' owning %d bytes>" % (2*SIZE_OF_INT)
- #
- p = ffi.new("int[]", 0)
- with pytest.raises(IndexError):
- p[0]
- py.test.raises(ValueError, ffi.new, "int[]", -1)
- assert repr(p) == "<cdata 'int[]' owning 0 bytes>"
-
- def test_pointer_init(self):
- n = ffi.new("int *", 24)
- a = ffi.new("int *[10]", [ffi.NULL, ffi.NULL, n, n, ffi.NULL])
- for i in range(10):
- if i not in (2, 3):
- assert a[i] == ffi.NULL
- assert a[2] == a[3] == n
-
- def test_cannot_cast(self):
- a = ffi.new("short int[10]")
- e = py.test.raises(TypeError, ffi.new, "long int **", a)
- msg = str(e.value)
- assert "'short[10]'" in msg and "'long *'" in msg
-
- def test_new_pointer_to_array(self):
- a = ffi.new("int[4]", [100, 102, 104, 106])
- p = ffi.new("int **", a)
- assert p[0] == ffi.cast("int *", a)
- assert p[0][2] == 104
- p = ffi.cast("int *", a)
- assert p[0] == 100
- assert p[1] == 102
- assert p[2] == 104
- assert p[3] == 106
- # keepalive: a
-
- def test_pointer_direct(self):
- p = ffi.cast("int*", 0)
- assert p is not None
- assert bool(p) is False
- assert p == ffi.cast("int*", 0)
- assert p != None
- assert repr(p) == "<cdata 'int *' NULL>"
- a = ffi.new("int[]", [123, 456])
- p = ffi.cast("int*", a)
- assert bool(p) is True
- assert p == ffi.cast("int*", a)
- assert p != ffi.cast("int*", 0)
- assert p[0] == 123
- assert p[1] == 456
-
- def test_repr(self):
- typerepr = "<ctype '%s'>"
- p = ffi.cast("short unsigned int", 0)
- assert repr(p) == "<cdata 'unsigned short' 0>"
- assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
- p = ffi.cast("unsigned short int", 0)
- assert repr(p) == "<cdata 'unsigned short' 0>"
- assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
- p = ffi.cast("int*", 0)
- assert repr(p) == "<cdata 'int *' NULL>"
- assert repr(ffi.typeof(p)) == typerepr % "int *"
- #
- p = ffi.new("int*")
- assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT
- assert repr(ffi.typeof(p)) == typerepr % "int *"
- p = ffi.new("int**")
- assert repr(p) == "<cdata 'int * *' owning %d bytes>" % SIZE_OF_PTR
- assert repr(ffi.typeof(p)) == typerepr % "int * *"
- p = ffi.new("int [2]")
- assert repr(p) == "<cdata 'int[2]' owning %d bytes>" % (2*SIZE_OF_INT)
- assert repr(ffi.typeof(p)) == typerepr % "int[2]"
- p = ffi.new("int*[2][3]")
- assert repr(p) == "<cdata 'int *[2][3]' owning %d bytes>" % (
- 6*SIZE_OF_PTR)
- assert repr(ffi.typeof(p)) == typerepr % "int *[2][3]"
- p = ffi.new("struct repr *")
- assert repr(p) == "<cdata 'struct repr *' owning %d bytes>" % (
- 3*SIZE_OF_SHORT)
- assert repr(ffi.typeof(p)) == typerepr % "struct repr *"
- #
- q = ffi.cast("short", -123)
- assert repr(q) == "<cdata 'short' -123>"
- assert repr(ffi.typeof(q)) == typerepr % "short"
- p = ffi.new("int*")
- q = ffi.cast("short*", p)
- assert repr(q).startswith("<cdata 'short *' 0x")
- assert repr(ffi.typeof(q)) == typerepr % "short *"
- p = ffi.new("int [2]")
- q = ffi.cast("int*", p)
- assert repr(q).startswith("<cdata 'int *' 0x")
- assert repr(ffi.typeof(q)) == typerepr % "int *"
- p = ffi.new("struct repr*")
- q = ffi.cast("struct repr *", p)
- assert repr(q).startswith("<cdata 'struct repr *' 0x")
- assert repr(ffi.typeof(q)) == typerepr % "struct repr *"
- prevrepr = repr(q)
- q = q[0]
- assert repr(q) == prevrepr.replace(' *', ' &')
- assert repr(ffi.typeof(q)) == typerepr % "struct repr"
-
- def test_new_array_of_array(self):
- p = ffi.new("int[3][4]")
- p[0][0] = 10
- p[2][3] = 33
- assert p[0][0] == 10
- assert p[2][3] == 33
- with pytest.raises(IndexError):
- p[1][-1]
-
- def test_constructor_array_of_array(self):
- p = ffi.new("int[3][2]", [[10, 11], [12, 13], [14, 15]])
- assert p[2][1] == 15
-
- def test_new_array_of_pointer_1(self):
- n = ffi.new("int*", 99)
- p = ffi.new("int*[4]")
- p[3] = n
- a = p[3]
- assert repr(a).startswith("<cdata 'int *' 0x")
- assert a[0] == 99
-
- def test_new_array_of_pointer_2(self):
- n = ffi.new("int[1]", [99])
- p = ffi.new("int*[4]")
- p[3] = n
- a = p[3]
- assert repr(a).startswith("<cdata 'int *' 0x")
- assert a[0] == 99
-
- def test_char(self):
- assert ffi.new("char*", b"\xff")[0] == b'\xff'
- assert ffi.new("char*")[0] == b'\x00'
- assert int(ffi.cast("char", 300)) == 300 - 256
- assert not bool(ffi.cast("char", 0))
- assert bool(ffi.cast("char", 1))
- assert bool(ffi.cast("char", 255))
- py.test.raises(TypeError, ffi.new, "char*", 32)
- py.test.raises(TypeError, ffi.new, "char*", u+"x")
- py.test.raises(TypeError, ffi.new, "char*", b"foo")
- #
- p = ffi.new("char[]", [b'a', b'b', b'\x9c'])
- assert len(p) == 3
- assert p[0] == b'a'
- assert p[1] == b'b'
- assert p[2] == b'\x9c'
- p[0] = b'\xff'
- assert p[0] == b'\xff'
- p = ffi.new("char[]", b"abcd")
- assert len(p) == 5
- assert p[4] == b'\x00' # like in C, with: char[] p = "abcd";
- #
- p = ffi.new("char[4]", b"ab")
- assert len(p) == 4
- assert [p[i] for i in range(4)] == [b'a', b'b', b'\x00', b'\x00']
- p = ffi.new("char[2]", b"ab")
- assert len(p) == 2
- assert [p[i] for i in range(2)] == [b'a', b'b']
- py.test.raises(IndexError, ffi.new, "char[2]", b"abc")
-
- def check_wchar_t(self, ffi):
- try:
- ffi.cast("wchar_t", 0)
- except NotImplementedError:
- py.test.skip("NotImplementedError: wchar_t")
-
- def test_wchar_t(self):
- self.check_wchar_t(ffi)
- assert ffi.new("wchar_t*", u+'x')[0] == u+'x'
- assert ffi.new("wchar_t*", u+'\u1234')[0] == u+'\u1234'
- if SIZE_OF_WCHAR > 2:
- assert ffi.new("wchar_t*", u+'\U00012345')[0] == u+'\U00012345'
- else:
- py.test.raises(TypeError, ffi.new, "wchar_t*", u+'\U00012345')
- assert ffi.new("wchar_t*")[0] == u+'\x00'
- assert int(ffi.cast("wchar_t", 300)) == 300
- assert not bool(ffi.cast("wchar_t", 0))
- assert bool(ffi.cast("wchar_t", 1))
- assert bool(ffi.cast("wchar_t", 65535))
- if SIZE_OF_WCHAR > 2:
- assert bool(ffi.cast("wchar_t", 65536))
- py.test.raises(TypeError, ffi.new, "wchar_t*", 32)
- py.test.raises(TypeError, ffi.new, "wchar_t*", "foo")
- #
- p = ffi.new("wchar_t[]", [u+'a', u+'b', u+'\u1234'])
- assert len(p) == 3
- assert p[0] == u+'a'
- assert p[1] == u+'b' and type(p[1]) is unicode
- assert p[2] == u+'\u1234'
- p[0] = u+'x'
- assert p[0] == u+'x' and type(p[0]) is unicode
- p[1] = u+'\u1357'
- assert p[1] == u+'\u1357'
- p = ffi.new("wchar_t[]", u+"abcd")
- assert len(p) == 5
- assert p[4] == u+'\x00'
- p = ffi.new("wchar_t[]", u+"a\u1234b")
- assert len(p) == 4
- assert p[1] == u+'\u1234'
- #
- p = ffi.new("wchar_t[]", u+'\U00023456')
- if SIZE_OF_WCHAR == 2:
- assert len(p) == 3
- assert p[0] == u+'\ud84d'
- assert p[1] == u+'\udc56'
- assert p[2] == u+'\x00'
- else:
- assert len(p) == 2
- assert p[0] == u+'\U00023456'
- assert p[1] == u+'\x00'
- #
- p = ffi.new("wchar_t[4]", u+"ab")
- assert len(p) == 4
- assert [p[i] for i in range(4)] == [u+'a', u+'b', u+'\x00', u+'\x00']
- p = ffi.new("wchar_t[2]", u+"ab")
- assert len(p) == 2
- assert [p[i] for i in range(2)] == [u+'a', u+'b']
- py.test.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc")
-
- def test_none_as_null_doesnt_work(self):
- p = ffi.new("int*[1]")
- assert p[0] is not None
- assert p[0] != None
- assert p[0] == ffi.NULL
- assert repr(p[0]) == "<cdata 'int *' NULL>"
- #
- n = ffi.new("int*", 99)
- p = ffi.new("int*[]", [n])
- assert p[0][0] == 99
- with pytest.raises(TypeError):
- p[0] = None
- p[0] = ffi.NULL
- assert p[0] == ffi.NULL
-
- def test_float(self):
- p = ffi.new("float[]", [-2, -2.5])
- assert p[0] == -2.0
- assert p[1] == -2.5
- p[1] += 17.75
- assert p[1] == 15.25
- #
- p = ffi.new("float*", 15.75)
- assert p[0] == 15.75
- py.test.raises(TypeError, int, p)
- py.test.raises(TypeError, float, p)
- p[0] = 0.0
- assert bool(p) is True
- #
- p = ffi.new("float*", 1.1)
- f = p[0]
- assert f != 1.1 # because of rounding effect
- assert abs(f - 1.1) < 1E-7
- #
- INF = 1E200 * 1E200
- assert 1E200 != INF
- p[0] = 1E200
- assert p[0] == INF # infinite, not enough precision
-
- def test_struct_simple(self):
- s = ffi.new("struct simple*")
- assert s.a == s.b == s.c == 0
- s.b = -23
- assert s.b == -23
- with pytest.raises(OverflowError):
- s.b = 32768
- #
- s = ffi.new("struct simple*", [-2, -3])
- assert s.a == -2
- assert s.b == -3
- assert s.c == 0
- with pytest.raises((AttributeError, TypeError)):
- del s.a
- assert repr(s) == "<cdata 'struct simple *' owning %d bytes>" % (
- SIZE_OF_INT + 2 * SIZE_OF_SHORT)
- #
- py.test.raises(ValueError, ffi.new, "struct simple*", [1, 2, 3, 4])
-
- def test_constructor_struct_from_dict(self):
- s = ffi.new("struct simple*", {'b': 123, 'c': 456})
- assert s.a == 0
- assert s.b == 123
- assert s.c == 456
- py.test.raises(KeyError, ffi.new, "struct simple*", {'d': 456})
-
- def test_struct_pointer(self):
- s = ffi.new("struct simple*")
- assert s[0].a == s[0].b == s[0].c == 0
- s[0].b = -23
- assert s[0].b == s.b == -23
- with pytest.raises(OverflowError):
- s[0].b = -32769
- with pytest.raises(IndexError):
- s[1]
-
- def test_struct_opaque(self):
- py.test.raises(ffi.error, ffi.new, "struct baz*")
- # should 'ffi.new("struct baz **") work? it used to, but it was
- # not particularly useful...
- py.test.raises(ffi.error, ffi.new, "struct baz**")
-
- def test_pointer_to_struct(self):
- s = ffi.new("struct simple *")
- s.a = -42
- assert s[0].a == -42
- p = ffi.new("struct simple **", s)
- assert p[0].a == -42
- assert p[0][0].a == -42
- p[0].a = -43
- assert s.a == -43
- assert s[0].a == -43
- p[0][0].a = -44
- assert s.a == -44
- assert s[0].a == -44
- s.a = -45
- assert p[0].a == -45
- assert p[0][0].a == -45
- s[0].a = -46
- assert p[0].a == -46
- assert p[0][0].a == -46
-
- def test_constructor_struct_of_array(self):
- s = ffi.new("struct array *", [[10, 11], [b'a', b'b', b'c']])
- assert s.a[1] == 11
- assert s.b[2] == b'c'
- s.b[1] = b'X'
- assert s.b[0] == b'a'
- assert s.b[1] == b'X'
- assert s.b[2] == b'c'
-
- def test_recursive_struct(self):
- s = ffi.new("struct recursive*")
- t = ffi.new("struct recursive*")
- s.value = 123
- s.next = t
- t.value = 456
- assert s.value == 123
- assert s.next.value == 456
-
- def test_union_simple(self):
- u = ffi.new("union simple_u*")
- assert u.a == u.b == u.c == 0
- u.b = -23
- assert u.b == -23
- assert u.a != 0
- with pytest.raises(OverflowError):
- u.b = 32768
- #
- u = ffi.new("union simple_u*", [-2])
- assert u.a == -2
- with pytest.raises((AttributeError, TypeError)):
- del u.a
- assert repr(u) == "<cdata 'union simple_u *' owning %d bytes>" % (
- SIZE_OF_INT,)
-
- def test_union_opaque(self):
- py.test.raises(ffi.error, ffi.new, "union baz*")
- # should 'ffi.new("union baz **") work? it used to, but it was
- # not particularly useful...
- py.test.raises(ffi.error, ffi.new, "union baz**")
-
- def test_union_initializer(self):
- py.test.raises(TypeError, ffi.new, "union init_u*", b'A')
- py.test.raises(TypeError, ffi.new, "union init_u*", 5)
- py.test.raises(ValueError, ffi.new, "union init_u*", [b'A', 5])
- u = ffi.new("union init_u*", [b'A'])
- assert u.a == b'A'
- py.test.raises(TypeError, ffi.new, "union init_u*", [1005])
- u = ffi.new("union init_u*", {'b': 12345})
- assert u.b == 12345
- u = ffi.new("union init_u*", [])
- assert u.a == b'\x00'
- assert u.b == 0
-
- def test_sizeof_type(self):
- for c_type, expected_size in [
- ('char', 1),
- ('unsigned int', 4),
- ('char *', SIZE_OF_PTR),
- ('int[5]', 20),
- ('struct four_s', 12),
- ('union four_u', 4),
- ]:
- size = ffi.sizeof(c_type)
- assert size == expected_size, (size, expected_size, ctype)
-
- def test_sizeof_cdata(self):
- assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR
- assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT
- #
- a = ffi.new("int[]", [10, 11, 12, 13, 14])
- assert len(a) == 5
- assert ffi.sizeof(a) == 5 * SIZE_OF_INT
-
- def test_string_from_char_pointer(self):
- x = ffi.new("char*", b"x")
- assert str(x) == repr(x)
- assert ffi.string(x) == b"x"
- assert ffi.string(ffi.new("char*", b"\x00")) == b""
- py.test.raises(TypeError, ffi.new, "char*", unicode("foo"))
-
- def test_unicode_from_wchar_pointer(self):
- self.check_wchar_t(ffi)
- x = ffi.new("wchar_t*", u+"x")
- assert unicode(x) == unicode(repr(x))
- assert ffi.string(x) == u+"x"
- assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+""
-
- def test_string_from_char_array(self):
- p = ffi.new("char[]", b"hello.")
- p[5] = b'!'
- assert ffi.string(p) == b"hello!"
- p[6] = b'?'
- assert ffi.string(p) == b"hello!?"
- p[3] = b'\x00'
- assert ffi.string(p) == b"hel"
- assert ffi.string(p, 2) == b"he"
- with pytest.raises(IndexError):
- p[7] = b'X'
- #
- a = ffi.new("char[]", b"hello\x00world")
- assert len(a) == 12
- p = ffi.cast("char *", a)
- assert ffi.string(p) == b'hello'
-
- def test_string_from_wchar_array(self):
- self.check_wchar_t(ffi)
- assert ffi.string(ffi.cast("wchar_t", "x")) == u+"x"
- assert ffi.string(ffi.cast("wchar_t", u+"x")) == u+"x"
- x = ffi.cast("wchar_t", "x")
- assert str(x) == repr(x)
- assert ffi.string(x) == u+"x"
- #
- p = ffi.new("wchar_t[]", u+"hello.")
- p[5] = u+'!'
- assert ffi.string(p) == u+"hello!"
- p[6] = u+'\u04d2'
- assert ffi.string(p) == u+"hello!\u04d2"
- p[3] = u+'\x00'
- assert ffi.string(p) == u+"hel"
- assert ffi.string(p, 123) == u+"hel"
- with pytest.raises(IndexError):
- p[7] = u+'X'
- #
- a = ffi.new("wchar_t[]", u+"hello\x00world")
- assert len(a) == 12
- p = ffi.cast("wchar_t *", a)
- assert ffi.string(p) == u+'hello'
- assert ffi.string(p, 123) == u+'hello'
- assert ffi.string(p, 5) == u+'hello'
- assert ffi.string(p, 2) == u+'he'
-
- def test_fetch_const_char_p_field(self):
- # 'const' is ignored so far, in the declaration of 'struct string'
- t = ffi.new("const char[]", b"testing")
- s = ffi.new("struct string*", [t])
- assert type(s.name) not in (bytes, str, unicode)
- assert ffi.string(s.name) == b"testing"
- with pytest.raises(TypeError):
- s.name = None
- s.name = ffi.NULL
- assert s.name == ffi.NULL
-
- def test_fetch_const_wchar_p_field(self):
- # 'const' is ignored so far
- self.check_wchar_t(ffi)
- t = ffi.new("const wchar_t[]", u+"testing")
- s = ffi.new("struct ustring*", [t])
- assert type(s.name) not in (bytes, str, unicode)
- assert ffi.string(s.name) == u+"testing"
- s.name = ffi.NULL
- assert s.name == ffi.NULL
-
- def test_voidp(self):
- py.test.raises(TypeError, ffi.new, "void*")
- p = ffi.new("void **")
- assert p[0] == ffi.NULL
- a = ffi.new("int[]", [10, 11, 12])
- p = ffi.new("void **", a)
- vp = p[0]
- with pytest.raises(TypeError):
- vp[0]
- py.test.raises(TypeError, ffi.new, "short **", a)
- #
- s = ffi.new("struct voidp *")
- s.p = a # works
- s.q = a # works
- with pytest.raises(TypeError):
- s.r = a # fails
- b = ffi.cast("int *", a)
- s.p = b # works
- s.q = b # works
- with pytest.raises(TypeError):
- s.r = b # fails
-
- def test_functionptr_simple(self):
- py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0)
- def cb(n):
- return n + 1
- cb.__qualname__ = 'cb'
- p = ffi.callback("int(*)(int)", cb)
- res = p(41) # calling an 'int(*)(int)', i.e. a function pointer
- assert res == 42 and type(res) is int
- res = p(ffi.cast("int", -41))
- assert res == -40 and type(res) is int
- assert repr(p).startswith(
- "<cdata 'int(*)(int)' calling <function cb at 0x")
- assert ffi.typeof(p) is ffi.typeof("int(*)(int)")
- q = ffi.new("int(**)(int)", p)
- assert repr(q) == "<cdata 'int(* *)(int)' owning %d bytes>" % (
- SIZE_OF_PTR)
- with pytest.raises(TypeError):
- q(43)
- res = q[0](43)
- assert res == 44
- q = ffi.cast("int(*)(int)", p)
- assert repr(q).startswith("<cdata 'int(*)(int)' 0x")
- res = q(45)
- assert res == 46
-
- def test_functionptr_advanced(self):
- t = ffi.typeof("int(*(*)(int))(int)")
- assert repr(t) == "<ctype '%s'>" % "int(*(*)(int))(int)"
-
- def test_functionptr_voidptr_return(self):
- def cb():
- return ffi.NULL
- p = ffi.callback("void*(*)()", cb)
- res = p()
- assert res is not None
- assert res == ffi.NULL
- int_ptr = ffi.new('int*')
- void_ptr = ffi.cast('void*', int_ptr)
- def cb():
- return void_ptr
- p = ffi.callback("void*(*)()", cb)
- res = p()
- assert res == void_ptr
-
- def test_functionptr_intptr_return(self):
- def cb():
- return ffi.NULL
- p = ffi.callback("int*(*)()", cb)
- res = p()
- assert res == ffi.NULL
- int_ptr = ffi.new('int*')
- def cb():
- return int_ptr
- p = ffi.callback("int*(*)()", cb)
- res = p()
- assert repr(res).startswith("<cdata 'int *' 0x")
- assert res == int_ptr
- int_array_ptr = ffi.new('int[1]')
- def cb():
- return int_array_ptr
- p = ffi.callback("int*(*)()", cb)
- res = p()
- assert repr(res).startswith("<cdata 'int *' 0x")
- assert res == int_array_ptr
-
- def test_functionptr_void_return(self):
- def foo():
- pass
- foo_cb = ffi.callback("void foo()", foo)
- result = foo_cb()
- assert result is None
-
- def test_char_cast(self):
- p = ffi.cast("int", b'\x01')
- assert ffi.typeof(p) is ffi.typeof("int")
- assert int(p) == 1
- p = ffi.cast("int", ffi.cast("char", b"a"))
- assert int(p) == ord("a")
- p = ffi.cast("int", ffi.cast("char", b"\x80"))
- assert int(p) == 0x80 # "char" is considered unsigned in this case
- p = ffi.cast("int", b"\x81")
- assert int(p) == 0x81
-
- def test_wchar_cast(self):
- self.check_wchar_t(ffi)
- p = ffi.cast("int", ffi.cast("wchar_t", u+'\u1234'))
- assert int(p) == 0x1234
- p = ffi.cast("long long", ffi.cast("wchar_t", -1))
- if SIZE_OF_WCHAR == 2: # 2 bytes, unsigned
- assert int(p) == 0xffff
- 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
-
- def test_cast_array_to_charp(self):
- a = ffi.new("short int[]", [0x1234, 0x5678])
- p = ffi.cast("char*", a)
- data = b''.join([p[i] for i in range(4)])
- if sys.byteorder == 'little':
- assert data == b'\x34\x12\x78\x56'
- else:
- assert data == b'\x12\x34\x56\x78'
-
- def test_cast_between_pointers(self):
- a = ffi.new("short int[]", [0x1234, 0x5678])
- p = ffi.cast("short*", a)
- p2 = ffi.cast("int*", p)
- q = ffi.cast("char*", p2)
- data = b''.join([q[i] for i in range(4)])
- if sys.byteorder == 'little':
- assert data == b'\x34\x12\x78\x56'
- else:
- assert data == b'\x12\x34\x56\x78'
-
- def test_cast_pointer_and_int(self):
- a = ffi.new("short int[]", [0x1234, 0x5678])
- l1 = ffi.cast("intptr_t", a)
- p = ffi.cast("short*", a)
- l2 = ffi.cast("intptr_t", p)
- assert int(l1) == int(l2) != 0
- q = ffi.cast("short*", l1)
- assert q == ffi.cast("short*", int(l1))
- assert q[0] == 0x1234
- assert int(ffi.cast("intptr_t", ffi.NULL)) == 0
-
- def test_cast_functionptr_and_int(self):
- def cb(n):
- return n + 1
- a = ffi.callback("int(*)(int)", cb)
- p = ffi.cast("void *", a)
- assert p
- b = ffi.cast("int(*)(int)", p)
- assert b(41) == 42
- assert a == b
- assert hash(a) == hash(b)
-
- def test_callback_crash(self):
- def cb(n):
- raise Exception
- a = ffi.callback("int(*)(int)", cb, error=42)
- res = a(1) # and the error reported to stderr
- assert res == 42
-
- def test_structptr_argument(self):
- def cb(p):
- return p[0].a * 1000 + p[0].b * 100 + p[1].a * 10 + p[1].b
- a = ffi.callback("int(*)(struct ab[])", cb)
- res = a([[5, 6], {'a': 7, 'b': 8}])
- assert res == 5678
- res = a([[5], {'b': 8}])
- assert res == 5008
-
- def test_array_argument_as_list(self):
- seen = []
- def cb(argv):
- seen.append(ffi.string(argv[0]))
- seen.append(ffi.string(argv[1]))
- a = ffi.callback("void(*)(char *[])", cb)
- a([ffi.new("char[]", b"foobar"), ffi.new("char[]", b"baz")])
- assert seen == [b"foobar", b"baz"]
-
- def test_cast_float(self):
- a = ffi.cast("float", 12)
- assert float(a) == 12.0
- a = ffi.cast("float", 12.5)
- assert float(a) == 12.5
- a = ffi.cast("float", b"A")
- assert float(a) == ord("A")
- a = ffi.cast("int", 12.9)
- assert int(a) == 12
- a = ffi.cast("char", 66.9 + 256)
- assert ffi.string(a) == b"B"
- #
- a = ffi.cast("float", ffi.cast("int", 12))
- assert float(a) == 12.0
- a = ffi.cast("float", ffi.cast("double", 12.5))
- assert float(a) == 12.5
- a = ffi.cast("float", ffi.cast("char", b"A"))
- assert float(a) == ord("A")
- a = ffi.cast("int", ffi.cast("double", 12.9))
- assert int(a) == 12
- a = ffi.cast("char", ffi.cast("double", 66.9 + 256))
- assert ffi.string(a) == b"B"
-
- def test_enum(self):
- # enum foq { A0, B0, CC0, D0 };
- assert ffi.string(ffi.cast("enum foq", 0)) == "cffiA0"
- assert ffi.string(ffi.cast("enum foq", 2)) == "cffiCC0"
- assert ffi.string(ffi.cast("enum foq", 3)) == "cffiD0"
- assert ffi.string(ffi.cast("enum foq", 4)) == "4"
- # enum bar { A1, B1=-2, CC1, D1, E1 };
- assert ffi.string(ffi.cast("enum bar", 0)) == "A1"
- assert ffi.string(ffi.cast("enum bar", -2)) == "B1"
- assert ffi.string(ffi.cast("enum bar", -1)) == "CC1"
- assert ffi.string(ffi.cast("enum bar", 1)) == "E1"
- assert ffi.cast("enum bar", -2) == ffi.cast("enum bar", -2)
- assert ffi.cast("enum foq", 0) == ffi.cast("enum bar", 0)
- assert ffi.cast("enum bar", 0) == ffi.cast("int", 0)
- assert repr(ffi.cast("enum bar", -1)) == "<cdata 'enum bar' -1: CC1>"
- assert repr(ffi.cast("enum foq", -1)) == ( # enums are unsigned, if
- "<cdata 'enum foq' 4294967295>") or ( # they contain no neg value
- sys.platform == "win32") # (but not on msvc)
- # enum baz { A2=0x1000, B2=0x2000 };
- assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2"
- assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2"
-
- def test_enum_in_struct(self):
- # enum foo2 { A3, B3, C3, D3 };
- # struct bar_with_e { enum foo2 e; };
- s = ffi.new("struct bar_with_e *")
- s.e = 0
- assert s.e == 0
- s.e = 3
- assert s.e == 3
- assert s[0].e == 3
- s[0].e = 2
- assert s.e == 2
- assert s[0].e == 2
- s.e = ffi.cast("enum foo2", -1)
- assert s.e in (4294967295, -1) # two choices
- assert s[0].e in (4294967295, -1)
- s.e = s.e
- with pytest.raises(TypeError):
- s.e = 'B3'
- with pytest.raises(TypeError):
- s.e = '2'
- with pytest.raises(TypeError):
- s.e = '#2'
- with pytest.raises(TypeError):
- s.e = '#7'
-
- def test_enum_non_contiguous(self):
- # enum noncont { A4, B4=42, C4 };
- assert ffi.string(ffi.cast("enum noncont", 0)) == "A4"
- assert ffi.string(ffi.cast("enum noncont", 42)) == "B4"
- assert ffi.string(ffi.cast("enum noncont", 43)) == "C4"
- invalid_value = ffi.cast("enum noncont", 2)
- assert int(invalid_value) == 2
- assert ffi.string(invalid_value) == "2"
-
- def test_enum_char_hex_oct(self):
- # enum etypes {A5='!', B5='\'', C5=0x10, D5=010, E5=- 0x10, F5=-010};
- assert ffi.string(ffi.cast("enum etypes", ord('!'))) == "A5"
- assert ffi.string(ffi.cast("enum etypes", ord("'"))) == "B5"
- assert ffi.string(ffi.cast("enum etypes", 16)) == "C5"
- assert ffi.string(ffi.cast("enum etypes", 8)) == "D5"
- assert ffi.string(ffi.cast("enum etypes", -16)) == "E5"
- assert ffi.string(ffi.cast("enum etypes", -8)) == "F5"
-
- def test_array_of_struct(self):
- s = ffi.new("struct ab[1]")
- with pytest.raises(AttributeError):
- s.b
- with pytest.raises(AttributeError):
- s.b = 412
- s[0].b = 412
- assert s[0].b == 412
- with pytest.raises(IndexError):
- s[1]
-
- def test_pointer_to_array(self):
- p = ffi.new("int(**)[5]")
- assert repr(p) == "<cdata 'int(* *)[5]' owning %d bytes>" % SIZE_OF_PTR
-
- def test_iterate_array(self):
- a = ffi.new("char[]", b"hello")
- assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
- assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
- #
- py.test.raises(TypeError, iter, ffi.cast("char *", a))
- py.test.raises(TypeError, list, ffi.cast("char *", a))
- py.test.raises(TypeError, iter, ffi.new("int *"))
- py.test.raises(TypeError, list, ffi.new("int *"))
-
- def test_offsetof(self):
- # struct abc { int a, b, c; };
- assert ffi.offsetof("struct abc", "a") == 0
- assert ffi.offsetof("struct abc", "b") == 4
- assert ffi.offsetof("struct abc", "c") == 8
-
- def test_offsetof_nested(self):
- # struct nesting { struct abc d, e; };
- assert ffi.offsetof("struct nesting", "e") == 12
- py.test.raises(KeyError, ffi.offsetof, "struct nesting", "e.a")
- assert ffi.offsetof("struct nesting", "e", "a") == 12
- assert ffi.offsetof("struct nesting", "e", "b") == 16
- assert ffi.offsetof("struct nesting", "e", "c") == 20
-
- def test_offsetof_array(self):
- assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int")
- assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int")
- # struct array2 { int a, b; int c[99]; };
- assert ffi.offsetof("struct array2", "c") == 2 * ffi.sizeof("int")
- assert ffi.offsetof("struct array2", "c", 0) == 2 * ffi.sizeof("int")
- assert ffi.offsetof("struct array2", "c", 51) == 53 * ffi.sizeof("int")
-
- def test_alignof(self):
- # struct align { char a; short b; char c; };
- assert ffi.alignof("int") == 4
- assert ffi.alignof("double") in (4, 8)
- assert ffi.alignof("struct align") == 2
-
- def test_bitfield(self):
- # struct bitfield { int a:10, b:20, c:3; };
- assert ffi.sizeof("struct bitfield") == 8
- s = ffi.new("struct bitfield *")
- s.a = 511
- with pytest.raises(OverflowError):
- s.a = 512
- with pytest.raises(OverflowError):
- s[0].a = 512
- assert s.a == 511
- s.a = -512
- with pytest.raises(OverflowError):
- s.a = -513
- with pytest.raises(OverflowError):
- s[0].a = -513
- assert s.a == -512
- s.c = 3
- assert s.c == 3
- with pytest.raises(OverflowError):
- s.c = 4
- with pytest.raises(OverflowError):
- s[0].c = 4
- s.c = -4
- assert s.c == -4
-
- def test_bitfield_enum(self):
- # typedef enum { AA1, BB1, CC1 } foo_e_t;
- # typedef struct { foo_e_t f:2; } bfenum_t;
- if sys.platform == "win32":
- py.test.skip("enums are not unsigned")
- s = ffi.new("bfenum_t *")
- s.f = 2
- assert s.f == 2
-
- def test_anonymous_struct(self):
- # typedef struct { int a; } anon_foo_t;
- # typedef struct { char b, c; } anon_bar_t;
- f = ffi.new("anon_foo_t *", [12345])
- b = ffi.new("anon_bar_t *", [b"B", b"C"])
- assert f.a == 12345
- assert b.b == b"B"
- assert b.c == b"C"
- assert repr(b).startswith("<cdata 'anon_bar_t *'")
-
- def test_struct_with_two_usages(self):
- # typedef struct named_foo_s { int a; } named_foo_t, *named_foo_p;
- # typedef struct { int a; } unnamed_foo_t, *unnamed_foo_p;
- f = ffi.new("named_foo_t *", [12345])
- ps = ffi.new("named_foo_p[]", [f])
- f = ffi.new("unnamed_foo_t *", [12345])
- ps = ffi.new("unnamed_foo_p[]", [f])
-
- def test_pointer_arithmetic(self):
- s = ffi.new("short[]", list(range(100, 110)))
- p = ffi.cast("short *", s)
- assert p[2] == 102
- assert p+1 == p+1
- assert p+1 != p+0
- assert p == p+0 == p-0
- assert (p+1)[0] == 101
- assert (p+19)[-10] == 109
- assert (p+5) - (p+1) == 4
- assert p == s+0
- assert p+1 == s+1
-
- def test_pointer_comparison(self):
- s = ffi.new("short[]", list(range(100)))
- p = ffi.cast("short *", s)
- assert (p < s) is False
- assert (p <= s) is True
- assert (p == s) is True
- assert (p != s) is False
- assert (p > s) is False
- assert (p >= s) is True
- assert (s < p) is False
- assert (s <= p) is True
- assert (s == p) is True
- assert (s != p) is False
- assert (s > p) is False
- assert (s >= p) is True
- q = p + 1
- assert (q < s) is False
- assert (q <= s) is False
- assert (q == s) is False
- assert (q != s) is True
- assert (q > s) is True
- assert (q >= s) is True
- assert (s < q) is True
- assert (s <= q) is True
- assert (s == q) is False
- assert (s != q) is True
- assert (s > q) is False
- assert (s >= q) is False
- assert (q < p) is False
- assert (q <= p) is False
- assert (q == p) is False
- assert (q != p) is True
- assert (q > p) is True
- assert (q >= p) is True
- assert (p < q) is True
- assert (p <= q) is True
- assert (p == q) is False
- assert (p != q) is True
- assert (p > q) is False
- assert (p >= q) is False
- #
- assert (None == s) is False
- assert (None != s) is True
- assert (s == None) is False
- assert (s != None) is True
- assert (None == q) is False
- assert (None != q) is True
- assert (q == None) is False
- assert (q != None) is True
-
- def test_integer_comparison(self):
- x = ffi.cast("int", 123)
- y = ffi.cast("int", 456)
- assert x < y
- #
- z = ffi.cast("double", 78.9)
- assert x > z
- assert y > z
-
- def test_ffi_buffer_ptr(self):
- a = ffi.new("short *", 100)
- try:
- b = ffi.buffer(a)
- except NotImplementedError as e:
- py.test.skip(str(e))
- content = b[:]
- assert len(content) == len(b) == 2
- if sys.byteorder == 'little':
- assert content == b'\x64\x00'
- assert b[0] == b'\x64'
- b[0] = b'\x65'
- else:
- assert content == b'\x00\x64'
- assert b[1] == b'\x64'
- b[1] = b'\x65'
- assert a[0] == 101
-
- def test_ffi_buffer_array(self):
- a = ffi.new("int[]", list(range(100, 110)))
- try:
- b = ffi.buffer(a)
- except NotImplementedError as e:
- py.test.skip(str(e))
- content = b[:]
- if sys.byteorder == 'little':
- assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00')
- b[4] = b'\x45'
- else:
- assert content.startswith(b'\x00\x00\x00\x64\x00\x00\x00\x65')
- b[7] = b'\x45'
- assert len(content) == 4 * 10
- assert a[1] == 0x45
-
- def test_ffi_buffer_ptr_size(self):
- a = ffi.new("short *", 0x4243)
- try:
- b = ffi.buffer(a, 1)
- except NotImplementedError as e:
- py.test.skip(str(e))
- content = b[:]
- assert len(content) == 1
- if sys.byteorder == 'little':
- assert content == b'\x43'
- b[0] = b'\x62'
- assert a[0] == 0x4262
- else:
- assert content == b'\x42'
- b[0] = b'\x63'
- assert a[0] == 0x6343
-
- def test_ffi_buffer_array_size(self):
- a1 = ffi.new("int[]", list(range(100, 110)))
- a2 = ffi.new("int[]", list(range(100, 115)))
- try:
- ffi.buffer(a1)
- except NotImplementedError as e:
- py.test.skip(str(e))
- assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:]
-
- def test_ffi_buffer_with_file(self):
- import tempfile, os, array
- fd, filename = tempfile.mkstemp()
- f = os.fdopen(fd, 'r+b')
- a = ffi.new("int[]", list(range(1005)))
- try:
- ffi.buffer(a, 512)
- except NotImplementedError as e:
- py.test.skip(str(e))
- f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
- f.seek(0)
- assert f.read() == arraytostring(array.array('i', range(1000)))
- f.seek(0)
- b = ffi.new("int[]", 1005)
- f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
- assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
- f.close()
- os.unlink(filename)
-
- def test_ffi_buffer_with_io(self):
- import io, array
- f = io.BytesIO()
- a = ffi.new("int[]", list(range(1005)))
- try:
- ffi.buffer(a, 512)
- except NotImplementedError as e:
- py.test.skip(str(e))
- f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
- f.seek(0)
- assert f.read() == arraytostring(array.array('i', range(1000)))
- f.seek(0)
- b = ffi.new("int[]", 1005)
- f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
- assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
- f.close()
-
- def test_array_in_struct(self):
- # struct array { int a[2]; char b[3]; };
- p = ffi.new("struct array *")
- p.a[1] = 5
- assert p.a[1] == 5
- assert repr(p.a).startswith("<cdata 'int[2]' 0x")
-
- def test_struct_containing_array_varsize_workaround(self):
- if sys.platform == "win32":
- py.test.skip("array of length 0 not supported")
- # struct array0 { int len; short data[0]; };
- p = ffi.new("char[]", ffi.sizeof("struct array0") + 7 * SIZE_OF_SHORT)
- q = ffi.cast("struct array0 *", p)
- assert q.len == 0
- # 'q.data' gets not a 'short[0]', but just a 'short *' instead
- assert repr(q.data).startswith("<cdata 'short *' 0x")
- assert q.data[6] == 0
- q.data[6] = 15
- assert q.data[6] == 15
-
- def test_new_struct_containing_array_varsize(self):
- py.test.skip("later?")
- ffi.cdef("struct foo_s { int len; short data[]; };")
- p = ffi.new("struct foo_s *", 10) # a single integer is the length
- assert p.len == 0
- assert p.data[9] == 0
- with pytest.raises(IndexError):
- p.data[10]
-
- def test_ffi_typeof_getcname(self):
- assert ffi.getctype("int") == "int"
- assert ffi.getctype("int", 'x') == "int x"
- assert ffi.getctype("int*") == "int *"
- assert ffi.getctype("int*", '') == "int *"
- assert ffi.getctype("int*", 'x') == "int * x"
- assert ffi.getctype("int", '*') == "int *"
- assert ffi.getctype("int", ' * x ') == "int * x"
- assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *"
- assert ffi.getctype("int", '[5]') == "int[5]"
- assert ffi.getctype("int[5]", '[6]') == "int[6][5]"
- assert ffi.getctype("int[5]", '(*)') == "int(*)[5]"
- # special-case for convenience: automatically put '()' around '*'
- assert ffi.getctype("int[5]", '*') == "int(*)[5]"
- assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]"
- assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"
-
- def test_array_of_func_ptr(self):
- f = ffi.cast("int(*)(int)", 42)
- assert f != ffi.NULL
- py.test.raises(ffi.error, ffi.cast, "int(int)", 42)
- py.test.raises(ffi.error, ffi.new, "int([5])(int)")
- a = ffi.new("int(*[5])(int)", [f])
- assert ffi.getctype(ffi.typeof(a)) == "int(*[5])(int)"
- assert len(a) == 5
- assert a[0] == f
- assert a[1] == ffi.NULL
- py.test.raises(TypeError, ffi.cast, "int(*)(int)[5]", 0)
- #
- def cb(n):
- return n + 1
- f = ffi.callback("int(*)(int)", cb)
- a = ffi.new("int(*[5])(int)", [f, f])
- assert a[1](42) == 43
-
- def test_callback_as_function_argument(self):
- # In C, function arguments can be declared with a function type,
- # which is automatically replaced with the ptr-to-function type.
- def cb(a, b):
- return chr(ord(a) + ord(b)).encode()
- f = ffi.callback("char cb(char, char)", cb)
- assert f(b'A', b'\x01') == b'B'
- def g(callback):
- return callback(b'A', b'\x01')
- g = ffi.callback("char g(char cb(char, char))", g)
- assert g(f) == b'B'
-
- def test_vararg_callback(self):
- py.test.skip("callback with '...'")
- def cb(i, va_list):
- j = ffi.va_arg(va_list, "int")
- k = ffi.va_arg(va_list, "long long")
- return i * 2 + j * 3 + k * 5
- f = ffi.callback("long long cb(long i, ...)", cb)
- res = f(10, ffi.cast("int", 100), ffi.cast("long long", 1000))
- assert res == 20 + 300 + 5000
-
- def test_callback_decorator(self):
- #
- @ffi.callback("long(long, long)", error=42)
- def cb(a, b):
- return a - b
- #
- assert cb(-100, -10) == -90
- sz = ffi.sizeof("long")
- assert cb((1 << (sz*8-1)) - 1, -10) == 42
-
- def test_anonymous_enum(self):
- # typedef enum { Value0 = 0 } e_t, *pe_t;
- assert ffi.getctype("e_t*") == 'e_t *'
- assert ffi.getctype("pe_t") == 'e_t *'
- assert ffi.getctype("foo_e_t*") == 'foo_e_t *'
-
- def test_new_ctype(self):
- p = ffi.new("int *")
- py.test.raises(TypeError, ffi.new, p)
- p = ffi.new(ffi.typeof("int *"), 42)
- assert p[0] == 42
-
- def test_enum_with_non_injective_mapping(self):
- # enum e_noninj { AA3=0, BB3=0, CC3=0, DD3=0 };
- e = ffi.cast("enum e_noninj", 0)
- assert ffi.string(e) == "AA3" # pick the first one arbitrarily
-
- def test_enum_refer_previous_enum_value(self):
- # enum e_prev { AA4, BB4=2, CC4=4, DD4=BB4, EE4, FF4=CC4, GG4=FF4 };
- assert ffi.string(ffi.cast("enum e_prev", 2)) == "BB4"
- assert ffi.string(ffi.cast("enum e_prev", 3)) == "EE4"
- assert ffi.sizeof("char[DD4]") == 2
- assert ffi.sizeof("char[EE4]") == 3
- assert ffi.sizeof("char[FF4]") == 4
- assert ffi.sizeof("char[GG4]") == 4
-
- def test_nested_anonymous_struct(self):
- # struct nested_anon {
- # struct { int a, b; };
- # union { int c, d; };
- # };
- assert ffi.sizeof("struct nested_anon") == 3 * SIZE_OF_INT
- p = ffi.new("struct nested_anon *", [1, 2, 3])
- assert p.a == 1
- assert p.b == 2
- assert p.c == 3
- assert p.d == 3
- p.d = 17
- assert p.c == 17
- p.b = 19
- assert p.a == 1
- assert p.b == 19
- assert p.c == 17
- assert p.d == 17
- p = ffi.new("struct nested_anon *", {'b': 12, 'd': 14})
- assert p.a == 0
- assert p.b == 12
- assert p.c == 14
- assert p.d == 14
-
- def test_nested_field_offset_align(self):
- # struct nested_field_ofs_s {
- # struct { int a; char b; };
- # union { char c; };
- # };
- assert ffi.offsetof("struct nested_field_ofs_s", "c") == 2 * SIZE_OF_INT
- assert ffi.sizeof("struct nested_field_ofs_s") == 3 * SIZE_OF_INT
-
- def test_nested_anonymous_union(self):
- # union nested_anon_u {
- # struct { int a, b; };
- # union { int c, d; };
- # };
- assert ffi.sizeof("union nested_anon_u") == 2 * SIZE_OF_INT
- p = ffi.new("union nested_anon_u *", [5])
- assert p.a == 5
- assert p.b == 0
- assert p.c == 5
- assert p.d == 5
- p.d = 17
- assert p.c == 17
- assert p.a == 17
- p.b = 19
- assert p.a == 17
- assert p.b == 19
- assert p.c == 17
- assert p.d == 17
- p = ffi.new("union nested_anon_u *", {'d': 14})
- assert p.a == 14
- assert p.b == 0
- assert p.c == 14
- assert p.d == 14
- p = ffi.new("union nested_anon_u *", {'b': 12})
- assert p.a == 0
- assert p.b == 12
- assert p.c == 0
- assert p.d == 0
- # we cannot specify several items in the dict, even though
- # in theory in this particular case it would make sense
- # to give both 'a' and 'b'
-
- def test_cast_to_array_type(self):
- p = ffi.new("int[4]", [-5])
- q = ffi.cast("int[3]", p)
- assert q[0] == -5
- assert repr(q).startswith("<cdata 'int[3]' 0x")
-
- def test_gc(self):
- p = ffi.new("int *", 123)
- seen = []
- def destructor(p1):
- assert p1 is p
- assert p1[0] == 123
- seen.append(1)
- q = ffi.gc(p, destructor=destructor)
- import gc; gc.collect()
- assert seen == []
- del q
- import gc; gc.collect(); gc.collect(); gc.collect()
- assert seen == [1]
-
- def test_gc_2(self):
- p = ffi.new("int *", 123)
- seen = []
- q1 = ffi.gc(p, lambda p: seen.append(1))
- q2 = ffi.gc(q1, lambda p: seen.append(2))
- import gc; gc.collect()
- assert seen == []
- del q1, q2
- import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
- assert seen == [2, 1]
-
- def test_gc_3(self):
- p = ffi.new("int *", 123)
- r = ffi.new("int *", 123)
- seen = []
- seen_r = []
- q1 = ffi.gc(p, lambda p: seen.append(1))
- s1 = ffi.gc(r, lambda r: seen_r.append(4))
- q2 = ffi.gc(q1, lambda p: seen.append(2))
- s2 = ffi.gc(s1, lambda r: seen_r.append(5))
- q3 = ffi.gc(q2, lambda p: seen.append(3))
- import gc; gc.collect()
- assert seen == []
- assert seen_r == []
- del q1, q2, q3, s2, s1
- import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
- assert seen == [3, 2, 1]
- assert seen_r == [5, 4]
-
- def test_gc_4(self):
- p = ffi.new("int *", 123)
- seen = []
- q1 = ffi.gc(p, lambda p: seen.append(1))
- q2 = ffi.gc(q1, lambda p: seen.append(2))
- q3 = ffi.gc(q2, lambda p: seen.append(3))
- import gc; gc.collect()
- assert seen == []
- del q1, q3 # q2 remains, and has a hard ref to q1
- import gc; gc.collect(); gc.collect(); gc.collect()
- assert seen == [3]
-
- def test_release(self):
- p = ffi.new("int[]", 123)
- ffi.release(p)
- # here, reading p[0] might give garbage or segfault...
- ffi.release(p) # no effect
-
- def test_release_new_allocator(self):
- seen = []
- def myalloc(size):
- seen.append(size)
- return ffi.new("char[]", b"X" * size)
- def myfree(raw):
- seen.append(raw)
- alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree)
- p = alloc2("int[]", 15)
- assert seen == [15 * 4]
- ffi.release(p)
- assert seen == [15 * 4, p]
- ffi.release(p) # no effect
- assert seen == [15 * 4, p]
- #
- del seen[:]
- p = alloc2("struct ab *")
- assert seen == [2 * 4]
- ffi.release(p)
- assert seen == [2 * 4, p]
- ffi.release(p) # no effect
- assert seen == [2 * 4, p]
-
- def test_CData_CType(self):
- assert isinstance(ffi.cast("int", 0), ffi.CData)
- assert isinstance(ffi.new("int *"), ffi.CData)
- assert not isinstance(ffi.typeof("int"), ffi.CData)
- assert not isinstance(ffi.cast("int", 0), ffi.CType)
- assert not isinstance(ffi.new("int *"), ffi.CType)
-
- def test_CData_CType_2(self):
- assert isinstance(ffi.typeof("int"), ffi.CType)
-
- def test_bool(self):
- assert int(ffi.cast("_Bool", 0.1)) == 1
- assert int(ffi.cast("_Bool", -0.0)) == 0
- assert int(ffi.cast("_Bool", b'\x02')) == 1
- assert int(ffi.cast("_Bool", b'\x00')) == 0
- assert int(ffi.cast("_Bool", b'\x80')) == 1
- assert ffi.new("_Bool *", False)[0] == 0
- assert ffi.new("_Bool *", 1)[0] == 1
- py.test.raises(OverflowError, ffi.new, "_Bool *", 2)
- py.test.raises(TypeError, ffi.string, ffi.cast("_Bool", 2))
-
- def test_addressof(self):
- p = ffi.new("struct ab *")
- a = ffi.addressof(p[0])
- assert repr(a).startswith("<cdata 'struct ab *' 0x")
- assert a == p
- py.test.raises(TypeError, ffi.addressof, p)
- py.test.raises((AttributeError, TypeError), ffi.addressof, 5)
- py.test.raises(TypeError, ffi.addressof, ffi.cast("int", 5))
-
- def test_addressof_field(self):
- p = ffi.new("struct ab *")
- b = ffi.addressof(p[0], 'b')
- assert repr(b).startswith("<cdata 'int *' 0x")
- assert int(ffi.cast("uintptr_t", b)) == (
- int(ffi.cast("uintptr_t", p)) + ffi.sizeof("int"))
- assert b == ffi.addressof(p, 'b')
- assert b != ffi.addressof(p, 'a')
-
- def test_addressof_field_nested(self):
- # struct nesting { struct abc d, e; };
- p = ffi.new("struct nesting *")
- py.test.raises(KeyError, ffi.addressof, p[0], 'e.b')
- a = ffi.addressof(p[0], 'e', 'b')
- assert int(ffi.cast("uintptr_t", a)) == (
- int(ffi.cast("uintptr_t", p)) +
- ffi.sizeof("struct abc") + ffi.sizeof("int"))
-
- def test_addressof_anonymous_struct(self):
- # typedef struct { int a; } anon_foo_t;
- p = ffi.new("anon_foo_t *")
- a = ffi.addressof(p[0])
- assert a == p
-
- def test_addressof_array(self):
- p = ffi.new("int[52]")
- p0 = ffi.addressof(p)
- assert p0 == p
- assert ffi.typeof(p0) is ffi.typeof("int(*)[52]")
- py.test.raises(TypeError, ffi.addressof, p0)
- #
- p1 = ffi.addressof(p, 25)
- assert ffi.typeof(p1) is ffi.typeof("int *")
- assert (p1 - p) == 25
- assert ffi.addressof(p, 0) == p
-
- def test_addressof_pointer(self):
- array = ffi.new("int[50]")
- p = ffi.cast("int *", array)
- py.test.raises(TypeError, ffi.addressof, p)
- assert ffi.addressof(p, 0) == p
- assert ffi.addressof(p, 25) == p + 25
- assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)
- #
- array = ffi.new("struct ab[50]")
- p = ffi.cast("int *", array)
- py.test.raises(TypeError, ffi.addressof, p)
- assert ffi.addressof(p, 0) == p
- assert ffi.addressof(p, 25) == p + 25
- assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)
-
- def test_addressof_array_in_struct(self):
- # struct abc50 { int a, b; int c[50]; };
- p = ffi.new("struct abc50 *")
- p1 = ffi.addressof(p, "c", 25)
- assert ffi.typeof(p1) is ffi.typeof("int *")
- assert p1 == ffi.cast("int *", p) + 27
- assert ffi.addressof(p, "c") == ffi.cast("int *", p) + 2
- assert ffi.addressof(p, "c", 0) == ffi.cast("int *", p) + 2
- p2 = ffi.addressof(p, 1)
- assert ffi.typeof(p2) is ffi.typeof("struct abc50 *")
- assert p2 == p + 1
-
- def test_multiple_independent_structs(self):
- CDEF2 = "struct ab { int x; };"
- ffi2 = cffi.FFI(); ffi2.cdef(CDEF2)
- outputfilename = recompile(ffi2, "test_multiple_independent_structs",
- CDEF2, tmpdir=str(udir))
- module = imp.load_dynamic("test_multiple_independent_structs",
- outputfilename)
- ffi1 = module.ffi
- foo1 = ffi1.new("struct ab *", [10])
- foo2 = ffi .new("struct ab *", [20, 30])
- assert foo1.x == 10
- assert foo2.a == 20
- assert foo2.b == 30
-
- def test_include_struct_union_enum_typedef(self):
- ffi1, CCODE = construction_params
- ffi2 = cffi.FFI()
- ffi2.include(ffi1)
- outputfilename = recompile(ffi2,
- "test_include_struct_union_enum_typedef",
- CCODE, tmpdir=str(udir))
- module = imp.load_dynamic("test_include_struct_union_enum_typedef",
- outputfilename)
- ffi2 = module.ffi
- #
- p = ffi2.new("struct nonpacked *", [b'A', -43141])
- assert p.a == b'A'
- assert p.b == -43141
- #
- p = ffi.new("union simple_u *", [-52525])
- assert p.a == -52525
- #
- p = ffi.cast("enum foq", 2)
- assert ffi.string(p) == "cffiCC0"
- assert ffi2.sizeof("char[cffiCC0]") == 2
- #
- p = ffi.new("anon_foo_t *", [-52526])
- assert p.a == -52526
- p = ffi.new("named_foo_p", [-52527])
- assert p.a == -52527
-
- def test_struct_packed(self):
- # struct nonpacked { char a; int b; };
- # struct is_packed { char a; int b; } __attribute__((packed));
- assert ffi.sizeof("struct nonpacked") == 8
- assert ffi.sizeof("struct is_packed") == 5
- assert ffi.alignof("struct nonpacked") == 4
- assert ffi.alignof("struct is_packed") == 1
- s = ffi.new("struct is_packed[2]")
- s[0].b = 42623381
- s[0].a = b'X'
- s[1].b = -4892220
- s[1].a = b'Y'
- assert s[0].b == 42623381
- assert s[0].a == b'X'
- assert s[1].b == -4892220
- assert s[1].a == b'Y'
-
- def test_not_supported_bitfield_in_result(self):
- # struct ints_and_bitfield { int a,b,c,d,e; int x:1; };
- e = py.test.raises(NotImplementedError, ffi.callback,
- "struct ints_and_bitfield foo(void)", lambda: 42)
- assert str(e.value) == ("struct ints_and_bitfield(*)(): "
- "callback with unsupported argument or return type or with '...'")
-
- def test_inspecttype(self):
- assert ffi.typeof("long").kind == "primitive"
- assert ffi.typeof("long(*)(long, long**, ...)").cname == (
- "long(*)(long, long * *, ...)")
- assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True
-
- def test_new_handle(self):
- o = [2, 3, 4]
- p = ffi.new_handle(o)
- assert ffi.typeof(p) == ffi.typeof("void *")
- assert ffi.from_handle(p) is o
- assert ffi.from_handle(ffi.cast("char *", p)) is o
- py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
-
- def test_struct_array_no_length(self):
- # struct array_no_length { int x; int a[]; };
- p = ffi.new("struct array_no_length *", [100, [200, 300, 400]])
- assert p.x == 100
- assert ffi.typeof(p.a) is ffi.typeof("int[]") # length available
- assert p.a[0] == 200
- assert p.a[1] == 300
- assert p.a[2] == 400
- assert len(p.a) == 3
- assert list(p.a) == [200, 300, 400]
- q = ffi.cast("struct array_no_length *", p)
- assert ffi.typeof(q.a) is ffi.typeof("int *") # no length available
- assert q.a[0] == 200
- assert q.a[1] == 300
- assert q.a[2] == 400
- py.test.raises(TypeError, len, q.a)
- py.test.raises(TypeError, list, q.a)
-
- def test_all_primitives(self):
- assert set(PRIMITIVE_TO_INDEX) == set([
- "char",
- "short",
- "int",
- "long",
- "long long",
- "signed char",
- "unsigned char",
- "unsigned short",
- "unsigned int",
- "unsigned long",
- "unsigned long long",
- "float",
- "double",
- "long double",
- "wchar_t",
- "char16_t",
- "char32_t",
- "_Bool",
- "int8_t",
- "uint8_t",
- "int16_t",
- "uint16_t",
- "int32_t",
- "uint32_t",
- "int64_t",
- "uint64_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",
- "intptr_t",
- "uintptr_t",
- "intmax_t",
- "uintmax_t",
- "ptrdiff_t",
- "size_t",
- "ssize_t",
- 'float _Complex',
- 'double _Complex',
- ])
- for name in PRIMITIVE_TO_INDEX:
- x = ffi.sizeof(name)
- assert 1 <= x <= 16
-
- def test_emit_c_code(self):
- ffi = cffi.FFI()
- ffi.set_source("foobar", "??")
- c_file = str(udir.join('test_emit_c_code'))
- ffi.emit_c_code(c_file)
- assert os.path.isfile(c_file)
-
- def test_import_from_lib(self):
- ffi2 = cffi.FFI()
- ffi2.cdef("int myfunc(int); extern int myvar;\n#define MYFOO ...\n")
- outputfilename = recompile(ffi2, "_test_import_from_lib",
- "int myfunc(int x) { return x + 1; }\n"
- "int myvar = -5;\n"
- "#define MYFOO 42", tmpdir=str(udir))
- imp.load_dynamic("_test_import_from_lib", outputfilename)
- from _test_import_from_lib.lib import myfunc, myvar, MYFOO
- assert MYFOO == 42
- assert myfunc(43) == 44
- assert myvar == -5 # but can't be changed, so not very useful
- with pytest.raises(ImportError):
- from _test_import_from_lib.lib import bar
- d = {}
- exec("from _test_import_from_lib.lib import *", d)
- assert (set(key for key in d if not key.startswith('_')) ==
- set(['myfunc', 'MYFOO']))
- #
- # also test "import *" on the module itself, which should be
- # equivalent to "import ffi, lib"
- d = {}
- exec("from _test_import_from_lib import *", d)
- assert (sorted([x for x in d.keys() if not x.startswith('__')]) ==
- ['ffi', 'lib'])
-
- def test_char16_t(self):
- x = ffi.new("char16_t[]", 5)
- assert len(x) == 5 and ffi.sizeof(x) == 10
- x[2] = u+'\u1324'
- assert x[2] == u+'\u1324'
- y = ffi.new("char16_t[]", u+'\u1234\u5678')
- assert len(y) == 3
- assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00']
- assert ffi.string(y) == u+'\u1234\u5678'
- z = ffi.new("char16_t[]", u+'\U00012345')
- assert len(z) == 3
- assert list(z) == [u+'\ud808', u+'\udf45', u+'\x00']
- assert ffi.string(z) == u+'\U00012345'
-
- def test_char32_t(self):
- x = ffi.new("char32_t[]", 5)
- assert len(x) == 5 and ffi.sizeof(x) == 20
- x[3] = u+'\U00013245'
- assert x[3] == u+'\U00013245'
- y = ffi.new("char32_t[]", u+'\u1234\u5678')
- assert len(y) == 3
- assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00']
- z = ffi.new("char32_t[]", u+'\U00012345')
- assert len(z) == 2
- assert list(z) == [u+'\U00012345', u+'\x00'] # maybe a 2-unichars strin
- assert ffi.string(z) == u+'\U00012345'
diff --git a/testing/cffi1/test_parse_c_type.py b/testing/cffi1/test_parse_c_type.py
deleted file mode 100644
index a9f5fcb..0000000
--- a/testing/cffi1/test_parse_c_type.py
+++ /dev/null
@@ -1,372 +0,0 @@
-import sys, re, os, py
-import cffi
-from cffi import cffi_opcode
-
-if '__pypy__' in sys.builtin_module_names:
- try:
- # pytest >= 4.0
- py.test.skip("not available on pypy", allow_module_level=True)
- except TypeError:
- # older pytest
- py.test.skip("not available on pypy")
-
-cffi_dir = os.path.dirname(cffi_opcode.__file__)
-
-r_macro = re.compile(r"#define \w+[(][^\n]*|#include [^\n]*")
-r_define = re.compile(r"(#define \w+) [^\n]*")
-r_ifdefs = re.compile(r"(#ifdef |#endif)[^\n]*")
-header = open(os.path.join(cffi_dir, 'parse_c_type.h')).read()
-header = r_macro.sub(r"", header)
-header = r_define.sub(r"\1 ...", header)
-header = r_ifdefs.sub(r"", header)
-
-ffi = cffi.FFI()
-ffi.cdef(header)
-
-lib = ffi.verify(
- 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
-
-struct_names = ["bar_s", "foo", "foo_", "foo_s", "foo_s1", "foo_s12"]
-assert struct_names == sorted(struct_names)
-
-enum_names = ["ebar_s", "efoo", "efoo_", "efoo_s", "efoo_s1", "efoo_s12"]
-assert enum_names == sorted(enum_names)
-
-identifier_names = ["id", "id0", "id05", "id05b", "tail"]
-assert identifier_names == sorted(identifier_names)
-
-global_names = ["FIVE", "NEG", "ZERO"]
-assert global_names == sorted(global_names)
-
-ctx = ffi.new("struct _cffi_type_context_s *")
-c_struct_names = [ffi.new("char[]", _n.encode('ascii')) for _n in struct_names]
-ctx_structs = ffi.new("struct _cffi_struct_union_s[]", len(struct_names))
-for _i in range(len(struct_names)):
- ctx_structs[_i].name = c_struct_names[_i]
-ctx_structs[3].flags = lib._CFFI_F_UNION
-ctx.struct_unions = ctx_structs
-ctx.num_struct_unions = len(struct_names)
-
-c_enum_names = [ffi.new("char[]", _n.encode('ascii')) for _n in enum_names]
-ctx_enums = ffi.new("struct _cffi_enum_s[]", len(enum_names))
-for _i in range(len(enum_names)):
- ctx_enums[_i].name = c_enum_names[_i]
-ctx.enums = ctx_enums
-ctx.num_enums = len(enum_names)
-
-c_identifier_names = [ffi.new("char[]", _n.encode('ascii'))
- for _n in identifier_names]
-ctx_identifiers = ffi.new("struct _cffi_typename_s[]", len(identifier_names))
-for _i in range(len(identifier_names)):
- ctx_identifiers[_i].name = c_identifier_names[_i]
- ctx_identifiers[_i].type_index = 100 + _i
-ctx.typenames = ctx_identifiers
-ctx.num_typenames = len(identifier_names)
-
-@ffi.callback("int(unsigned long long *)")
-def fetch_constant_five(p):
- p[0] = 5
- return 0
-@ffi.callback("int(unsigned long long *)")
-def fetch_constant_zero(p):
- p[0] = 0
- return 1
-@ffi.callback("int(unsigned long long *)")
-def fetch_constant_neg(p):
- p[0] = 123321
- return 1
-
-ctx_globals = ffi.new("struct _cffi_global_s[]", len(global_names))
-c_glob_names = [ffi.new("char[]", _n.encode('ascii')) for _n in global_names]
-for _i, _fn in enumerate([fetch_constant_five,
- fetch_constant_neg,
- fetch_constant_zero]):
- ctx_globals[_i].name = c_glob_names[_i]
- ctx_globals[_i].address = _fn
- ctx_globals[_i].type_op = ffi.cast("_cffi_opcode_t",
- cffi_opcode.OP_CONSTANT_INT if _i != 1
- else cffi_opcode.OP_ENUM)
-ctx.globals = ctx_globals
-ctx.num_globals = len(global_names)
-
-
-def parse(input):
- out = ffi.new("_cffi_opcode_t[]", 100)
- info = ffi.new("struct _cffi_parse_info_s *")
- info.ctx = ctx
- info.output = out
- info.output_size = len(out)
- for j in range(len(out)):
- out[j] = ffi.cast("void *", -424242)
- res = lib.parse_c_type(info, input.encode('ascii'))
- if res < 0:
- raise ParseError(ffi.string(info.error_message).decode('ascii'),
- info.error_location)
- assert 0 <= res < len(out)
- result = []
- for j in range(len(out)):
- if out[j] == ffi.cast("void *", -424242):
- assert res < j
- break
- i = int(ffi.cast("intptr_t", out[j]))
- if j == res:
- result.append('->')
- result.append(i)
- return result
-
-def parsex(input):
- result = parse(input)
- def str_if_int(x):
- if isinstance(x, str):
- return x
- return '%d,%d' % (x & 255, x >> 8)
- return ' '.join(map(str_if_int, result))
-
-def parse_error(input, expected_msg, expected_location):
- e = py.test.raises(ParseError, parse, input)
- assert e.value.args[0] == expected_msg
- assert e.value.args[1] == expected_location
-
-def make_getter(name):
- opcode = getattr(lib, '_CFFI_OP_' + name)
- def getter(value):
- return opcode | (value << 8)
- return getter
-
-Prim = make_getter('PRIMITIVE')
-Pointer = make_getter('POINTER')
-Array = make_getter('ARRAY')
-OpenArray = make_getter('OPEN_ARRAY')
-NoOp = make_getter('NOOP')
-Func = make_getter('FUNCTION')
-FuncEnd = make_getter('FUNCTION_END')
-Struct = make_getter('STRUCT_UNION')
-Enum = make_getter('ENUM')
-Typename = make_getter('TYPENAME')
-
-
-def test_simple():
- for simple_type, expected in [
- ("int", lib._CFFI_PRIM_INT),
- ("signed int", lib._CFFI_PRIM_INT),
- (" long ", lib._CFFI_PRIM_LONG),
- ("long int", lib._CFFI_PRIM_LONG),
- ("unsigned short", lib._CFFI_PRIM_USHORT),
- ("long double", lib._CFFI_PRIM_LONGDOUBLE),
- (" float _Complex", lib._CFFI_PRIM_FLOATCOMPLEX),
- ("double _Complex ", lib._CFFI_PRIM_DOUBLECOMPLEX),
- ]:
- assert parse(simple_type) == ['->', Prim(expected)]
-
-def test_array():
- assert parse("int[5]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 5]
- assert parse("int[]") == [Prim(lib._CFFI_PRIM_INT), '->', OpenArray(0)]
- assert parse("int[5][8]") == [Prim(lib._CFFI_PRIM_INT),
- '->', Array(3),
- 5,
- Array(0),
- 8]
- assert parse("int[][8]") == [Prim(lib._CFFI_PRIM_INT),
- '->', OpenArray(2),
- Array(0),
- 8]
-
-def test_pointer():
- assert parse("int*") == [Prim(lib._CFFI_PRIM_INT), '->', Pointer(0)]
- assert parse("int***") == [Prim(lib._CFFI_PRIM_INT),
- Pointer(0), Pointer(1), '->', Pointer(2)]
-
-def test_grouping():
- assert parse("int*[]") == [Prim(lib._CFFI_PRIM_INT),
- Pointer(0), '->', OpenArray(1)]
- assert parse("int**[][8]") == [Prim(lib._CFFI_PRIM_INT),
- Pointer(0), Pointer(1),
- '->', OpenArray(4), Array(2), 8]
- assert parse("int(*)[]") == [Prim(lib._CFFI_PRIM_INT),
- NoOp(3), '->', Pointer(1), OpenArray(0)]
- assert parse("int(*)[][8]") == [Prim(lib._CFFI_PRIM_INT),
- NoOp(3), '->', Pointer(1),
- OpenArray(4), Array(0), 8]
- assert parse("int**(**)") == [Prim(lib._CFFI_PRIM_INT),
- Pointer(0), Pointer(1),
- NoOp(2), Pointer(3), '->', Pointer(4)]
- assert parse("int**(**)[]") == [Prim(lib._CFFI_PRIM_INT),
- Pointer(0), Pointer(1),
- NoOp(6), Pointer(3), '->', Pointer(4),
- OpenArray(2)]
-
-def test_simple_function():
- assert parse("int()") == [Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), FuncEnd(0), 0]
- assert parse("int(int)") == [Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), NoOp(4), FuncEnd(0),
- Prim(lib._CFFI_PRIM_INT)]
- assert parse("int(long, char)") == [
- Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), NoOp(5), NoOp(6), FuncEnd(0),
- Prim(lib._CFFI_PRIM_LONG),
- Prim(lib._CFFI_PRIM_CHAR)]
- assert parse("int(int*)") == [Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), NoOp(5), FuncEnd(0),
- Prim(lib._CFFI_PRIM_INT),
- Pointer(4)]
- assert parse("int*(void)") == [Prim(lib._CFFI_PRIM_INT),
- Pointer(0),
- '->', Func(1), FuncEnd(0), 0]
- assert parse("int(int, ...)") == [Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), NoOp(5), FuncEnd(1), 0,
- Prim(lib._CFFI_PRIM_INT)]
-
-def test_internal_function():
- assert parse("int(*)()") == [Prim(lib._CFFI_PRIM_INT),
- NoOp(3), '->', Pointer(1),
- Func(0), FuncEnd(0), 0]
- assert parse("int(*())[]") == [Prim(lib._CFFI_PRIM_INT),
- NoOp(6), Pointer(1),
- '->', Func(2), FuncEnd(0), 0,
- OpenArray(0)]
- assert parse("int(char(*)(long, short))") == [
- Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), NoOp(6), FuncEnd(0),
- Prim(lib._CFFI_PRIM_CHAR),
- NoOp(7), Pointer(5),
- Func(4), NoOp(11), NoOp(12), FuncEnd(0),
- Prim(lib._CFFI_PRIM_LONG),
- Prim(lib._CFFI_PRIM_SHORT)]
-
-def test_fix_arg_types():
- assert parse("int(char(long, short))") == [
- Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), Pointer(5), FuncEnd(0),
- Prim(lib._CFFI_PRIM_CHAR),
- Func(4), NoOp(9), NoOp(10), FuncEnd(0),
- Prim(lib._CFFI_PRIM_LONG),
- Prim(lib._CFFI_PRIM_SHORT)]
- assert parse("int(char[])") == [
- Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), Pointer(4), FuncEnd(0),
- Prim(lib._CFFI_PRIM_CHAR),
- OpenArray(4)]
-
-def test_enum():
- for i in range(len(enum_names)):
- assert parse("enum %s" % (enum_names[i],)) == ['->', Enum(i)]
- assert parse("enum %s*" % (enum_names[i],)) == [Enum(i),
- '->', Pointer(0)]
-
-def test_error():
- parse_error("short short int", "'short' after another 'short' or 'long'", 6)
- parse_error("long long long", "'long long long' is too long", 10)
- parse_error("short long", "'long' after 'short'", 6)
- parse_error("signed unsigned int", "multiple 'signed' or 'unsigned'", 7)
- parse_error("unsigned signed int", "multiple 'signed' or 'unsigned'", 9)
- parse_error("long char", "invalid combination of types", 5)
- parse_error("short char", "invalid combination of types", 6)
- parse_error("signed void", "invalid combination of types", 7)
- parse_error("unsigned struct", "invalid combination of types", 9)
- #
- parse_error("", "identifier expected", 0)
- parse_error("]", "identifier expected", 0)
- parse_error("*", "identifier expected", 0)
- parse_error("int ]**", "unexpected symbol", 4)
- parse_error("char char", "unexpected symbol", 5)
- parse_error("int(int]", "expected ')'", 7)
- parse_error("int(*]", "expected ')'", 5)
- parse_error("int(]", "identifier expected", 4)
- parse_error("int[?]", "expected a positive integer constant", 4)
- parse_error("int[24)", "expected ']'", 6)
- parse_error("struct", "struct or union name expected", 6)
- parse_error("struct 24", "struct or union name expected", 7)
- parse_error("int[5](*)", "unexpected symbol", 6)
- parse_error("int a(*)", "identifier expected", 6)
- parse_error("int[123456789012345678901234567890]", "number too large", 4)
- #
- parse_error("_Complex", "identifier expected", 0)
- parse_error("int _Complex", "_Complex type combination unsupported", 4)
- parse_error("long double _Complex", "_Complex type combination unsupported",
- 12)
-
-def test_number_too_large():
- num_max = sys.maxsize
- assert parse("char[%d]" % num_max) == [Prim(lib._CFFI_PRIM_CHAR),
- '->', Array(0), num_max]
- parse_error("char[%d]" % (num_max + 1), "number too large", 5)
-
-def test_complexity_limit():
- parse_error("int" + "[]" * 2500, "internal type complexity limit reached",
- 202)
-
-def test_struct():
- for i in range(len(struct_names)):
- if i == 3:
- tag = "union"
- else:
- tag = "struct"
- assert parse("%s %s" % (tag, struct_names[i])) == ['->', Struct(i)]
- assert parse("%s %s*" % (tag, struct_names[i])) == [Struct(i),
- '->', Pointer(0)]
-
-def test_exchanging_struct_union():
- parse_error("union %s" % (struct_names[0],),
- "wrong kind of tag: struct vs union", 6)
- parse_error("struct %s" % (struct_names[3],),
- "wrong kind of tag: struct vs union", 7)
-
-def test_identifier():
- for i in range(len(identifier_names)):
- assert parse("%s" % (identifier_names[i])) == ['->', Typename(i)]
- assert parse("%s*" % (identifier_names[i])) == [Typename(i),
- '->', Pointer(0)]
-
-def test_cffi_opcode_sync():
- import cffi.model
- for name in dir(lib):
- if name.startswith('_CFFI_'):
- assert getattr(cffi_opcode, name[6:]) == getattr(lib, name)
- assert sorted(cffi_opcode.PRIMITIVE_TO_INDEX.keys()) == (
- sorted(cffi.model.PrimitiveType.ALL_PRIMITIVE_TYPES.keys()))
-
-def test_array_length_from_constant():
- parse_error("int[UNKNOWN]", "expected a positive integer constant", 4)
- assert parse("int[FIVE]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 5]
- assert parse("int[ZERO]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 0]
- parse_error("int[NEG]", "expected a positive integer constant", 4)
-
-def test_various_constant_exprs():
- def array(n):
- return [Prim(lib._CFFI_PRIM_CHAR), '->', Array(0), n]
- assert parse("char[21]") == array(21)
- assert parse("char[0x10]") == array(16)
- assert parse("char[0X21]") == array(33)
- assert parse("char[0Xb]") == array(11)
- assert parse("char[0x1C]") == array(0x1C)
- assert parse("char[0xc6]") == array(0xC6)
- assert parse("char[010]") == array(8)
- assert parse("char[021]") == array(17)
- parse_error("char[08]", "invalid number", 5)
- parse_error("char[1C]", "invalid number", 5)
- parse_error("char[0C]", "invalid number", 5)
- # not supported (really obscure):
- # "char[+5]"
- # "char['A']"
-
-def test_stdcall_cdecl():
- assert parse("int __stdcall(int)") == [Prim(lib._CFFI_PRIM_INT),
- '->', Func(0), NoOp(4), FuncEnd(2),
- Prim(lib._CFFI_PRIM_INT)]
- assert parse("int __stdcall func(int)") == parse("int __stdcall(int)")
- assert parse("int (__stdcall *)()") == [Prim(lib._CFFI_PRIM_INT),
- NoOp(3), '->', Pointer(1),
- Func(0), FuncEnd(2), 0]
- assert parse("int (__stdcall *p)()") == parse("int (__stdcall*)()")
- parse_error("__stdcall int", "identifier expected", 0)
- parse_error("__cdecl int", "identifier expected", 0)
- parse_error("int __stdcall", "expected '('", 13)
- parse_error("int __cdecl", "expected '('", 11)
diff --git a/testing/cffi1/test_pkgconfig.py b/testing/cffi1/test_pkgconfig.py
deleted file mode 100644
index c725cca..0000000
--- a/testing/cffi1/test_pkgconfig.py
+++ /dev/null
@@ -1,94 +0,0 @@
-import sys
-import subprocess
-import py
-import cffi.pkgconfig as pkgconfig
-from cffi import PkgConfigError
-
-
-def mock_call(libname, flag):
- assert libname=="foobarbaz"
- flags = {
- "--cflags": "-I/usr/include/python3.6m -DABCD -DCFFI_TEST=1 -O42\n",
- "--libs": "-L/usr/lib64 -lpython3.6 -shared\n",
- }
- return flags[flag]
-
-
-def test_merge_flags():
- d1 = {"ham": [1, 2, 3], "spam" : ["a", "b", "c"], "foo" : []}
- d2 = {"spam" : ["spam", "spam", "spam"], "bar" : ["b", "a", "z"]}
-
- pkgconfig.merge_flags(d1, d2)
- assert d1 == {
- "ham": [1, 2, 3],
- "spam" : ["a", "b", "c", "spam", "spam", "spam"],
- "bar" : ["b", "a", "z"],
- "foo" : []}
-
-
-def test_pkgconfig():
- assert pkgconfig.flags_from_pkgconfig([]) == {}
-
- saved = pkgconfig.call
- try:
- pkgconfig.call = mock_call
- flags = pkgconfig.flags_from_pkgconfig(["foobarbaz"])
- finally:
- pkgconfig.call = saved
- assert flags == {
- 'include_dirs': ['/usr/include/python3.6m'],
- 'library_dirs': ['/usr/lib64'],
- 'libraries': ['python3.6'],
- 'define_macros': [('ABCD', None), ('CFFI_TEST', '1')],
- 'extra_compile_args': ['-O42'],
- 'extra_link_args': ['-shared']
- }
-
-class mock_subprocess:
- PIPE = Ellipsis
- class Popen:
- def __init__(self, cmd, stdout, stderr):
- if mock_subprocess.RESULT is None:
- raise OSError("oops can't run")
- assert cmd == ['pkg-config', '--print-errors', '--cflags', 'libfoo']
- def communicate(self):
- bout, berr, rc = mock_subprocess.RESULT
- self.returncode = rc
- return bout, berr
-
-def test_call():
- saved = pkgconfig.subprocess
- try:
- pkgconfig.subprocess = mock_subprocess
-
- mock_subprocess.RESULT = None
- e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
- assert str(e.value) == "cannot run pkg-config: oops can't run"
-
- mock_subprocess.RESULT = b"", "Foo error!\n", 1
- e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
- assert str(e.value) == "Foo error!"
-
- mock_subprocess.RESULT = b"abc\\def\n", "", 0
- e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
- assert str(e.value).startswith("pkg-config --cflags libfoo returned an "
- "unsupported backslash-escaped output:")
-
- mock_subprocess.RESULT = b"abc def\n", "", 0
- result = pkgconfig.call("libfoo", "--cflags")
- assert result == "abc def\n"
-
- mock_subprocess.RESULT = b"abc def\n", "", 0
- result = pkgconfig.call("libfoo", "--cflags")
- assert result == "abc def\n"
-
- if sys.version_info >= (3,):
- mock_subprocess.RESULT = b"\xff\n", "", 0
- e = py.test.raises(PkgConfigError, pkgconfig.call,
- "libfoo", "--cflags", encoding="utf-8")
- assert str(e.value) == (
- "pkg-config --cflags libfoo returned bytes that cannot be "
- "decoded with encoding 'utf-8':\nb'\\xff\\n'")
-
- finally:
- pkgconfig.subprocess = saved
diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py
deleted file mode 100644
index 2ae0dd1..0000000
--- a/testing/cffi1/test_re_python.py
+++ /dev/null
@@ -1,288 +0,0 @@
-import sys, os
-import py
-from cffi import FFI
-from cffi import recompiler, ffiplatform, VerificationMissing
-from testing.udir import udir
-from testing.support import u
-
-
-def setup_module(mod):
- SRC = """
- #include <string.h>
- #define FOOBAR (-42)
- static const int FOOBAZ = -43;
- #define BIGPOS 420000000000L
- #define BIGNEG -420000000000L
- int add42(int x) { return x + 42; }
- int add43(int x, ...) { return x; }
- int globalvar42 = 1234;
- const int globalconst42 = 4321;
- const char *const globalconsthello = "hello";
- struct foo_s;
- typedef struct bar_s { int x; signed char a[]; } bar_t;
- enum foo_e { AA, BB, CC };
-
- void init_test_re_python(void) { } /* windows hack */
- void PyInit__test_re_python(void) { } /* windows hack */
- """
- tmpdir = udir.join('test_re_python')
- tmpdir.ensure(dir=1)
- c_file = tmpdir.join('_test_re_python.c')
- c_file.write(SRC)
- ext = ffiplatform.get_extension(
- str(c_file),
- '_test_re_python',
- export_symbols=['add42', 'add43', 'globalvar42',
- 'globalconst42', 'globalconsthello']
- )
- outputfilename = ffiplatform.compile(str(tmpdir), ext)
-
- # test with a non-ascii char
- ofn, oext = os.path.splitext(outputfilename)
- if sys.platform == "win32":
- unicode_name = ofn + (u+'\u03be') + oext
- else:
- unicode_name = ofn + (u+'\xe9') + oext
- try:
- unicode_name.encode(sys.getfilesystemencoding())
- except UnicodeEncodeError:
- unicode_name = None
- if unicode_name is not None:
- print(repr(outputfilename) + ' ==> ' + repr(unicode_name))
- os.rename(outputfilename, unicode_name)
- outputfilename = unicode_name
-
- mod.extmod = outputfilename
- mod.tmpdir = tmpdir
- #
- ffi = FFI()
- ffi.cdef("""
- #define FOOBAR -42
- static const int FOOBAZ = -43;
- #define BIGPOS 420000000000L
- #define BIGNEG -420000000000L
- int add42(int);
- int add43(int, ...);
- extern int globalvar42;
- const int globalconst42;
- const char *const globalconsthello;
- int no_such_function(int);
- extern int no_such_globalvar;
- struct foo_s;
- typedef struct bar_s { int x; signed char a[]; } bar_t;
- enum foo_e { AA, BB, CC };
- int strlen(const char *);
- struct with_union { union { int a; char b; }; };
- union with_struct { struct { int a; char b; }; };
- struct with_struct_with_union { struct { union { int x; }; } cp; };
- struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; };
- typedef struct selfref { struct selfref *next; } *selfref_ptr_t;
- """)
- ffi.set_source('re_python_pysrc', None)
- ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py')))
- mod.original_ffi = ffi
- #
- sys.path.insert(0, str(tmpdir))
-
-
-def test_constant():
- from re_python_pysrc import ffi
- assert ffi.integer_const('FOOBAR') == -42
- assert ffi.integer_const('FOOBAZ') == -43
-
-def test_large_constant():
- from re_python_pysrc import ffi
- assert ffi.integer_const('BIGPOS') == 420000000000
- assert ffi.integer_const('BIGNEG') == -420000000000
-
-def test_function():
- import _cffi_backend
- from re_python_pysrc import ffi
- lib = ffi.dlopen(extmod)
- assert lib.add42(-10) == 32
- assert type(lib.add42) is _cffi_backend.FFI.CData
-
-def test_function_with_varargs():
- import _cffi_backend
- from re_python_pysrc import ffi
- lib = ffi.dlopen(extmod, 0)
- assert lib.add43(45, ffi.cast("int", -5)) == 45
- assert type(lib.add43) is _cffi_backend.FFI.CData
-
-def test_dlopen_none():
- import _cffi_backend
- from re_python_pysrc import ffi
- name = None
- if sys.platform == 'win32':
- import ctypes.util
- name = ctypes.util.find_msvcrt()
- if name is None:
- py.test.skip("dlopen(None) cannot work on Windows with Python 3")
- lib = ffi.dlopen(name)
- assert lib.strlen(b"hello") == 5
-
-def test_dlclose():
- import _cffi_backend
- from re_python_pysrc import ffi
- lib = ffi.dlopen(extmod)
- ffi.dlclose(lib)
- if type(extmod) is not str: # unicode, on python 2
- str_extmod = extmod.encode('utf-8')
- else:
- str_extmod = extmod
- e = py.test.raises(ffi.error, getattr, lib, 'add42')
- assert str(e.value) == (
- "library '%s' has been closed" % (str_extmod,))
- ffi.dlclose(lib) # does not raise
-
-def test_constant_via_lib():
- from re_python_pysrc import ffi
- lib = ffi.dlopen(extmod)
- assert lib.FOOBAR == -42
- assert lib.FOOBAZ == -43
-
-def test_opaque_struct():
- from re_python_pysrc import ffi
- ffi.cast("struct foo_s *", 0)
- py.test.raises(TypeError, ffi.new, "struct foo_s *")
-
-def test_nonopaque_struct():
- from re_python_pysrc import ffi
- for p in [ffi.new("struct bar_s *", [5, b"foobar"]),
- ffi.new("bar_t *", [5, b"foobar"])]:
- assert p.x == 5
- assert p.a[0] == ord('f')
- assert p.a[5] == ord('r')
-
-def test_enum():
- from re_python_pysrc import ffi
- assert ffi.integer_const("BB") == 1
- e = ffi.cast("enum foo_e", 2)
- assert ffi.string(e) == "CC"
-
-def test_include_1():
- sub_ffi = FFI()
- sub_ffi.cdef("static const int k2 = 121212;")
- sub_ffi.include(original_ffi)
- assert 'macro FOOBAR' in original_ffi._parser._declarations
- assert 'macro FOOBAZ' in original_ffi._parser._declarations
- sub_ffi.set_source('re_python_pysrc', None)
- sub_ffi.emit_python_code(str(tmpdir.join('_re_include_1.py')))
- #
- if sys.version_info[:2] >= (3, 3):
- import importlib
- importlib.invalidate_caches() # issue 197 (but can't reproduce myself)
- #
- from _re_include_1 import ffi
- assert ffi.integer_const('FOOBAR') == -42
- assert ffi.integer_const('FOOBAZ') == -43
- assert ffi.integer_const('k2') == 121212
- lib = ffi.dlopen(extmod) # <- a random unrelated library would be fine
- assert lib.FOOBAR == -42
- assert lib.FOOBAZ == -43
- assert lib.k2 == 121212
- #
- p = ffi.new("bar_t *", [5, b"foobar"])
- assert p.a[4] == ord('a')
-
-def test_global_var():
- from re_python_pysrc import ffi
- lib = ffi.dlopen(extmod)
- assert lib.globalvar42 == 1234
- p = ffi.addressof(lib, 'globalvar42')
- lib.globalvar42 += 5
- assert p[0] == 1239
- p[0] -= 1
- assert lib.globalvar42 == 1238
-
-def test_global_const_int():
- from re_python_pysrc import ffi
- lib = ffi.dlopen(extmod)
- assert lib.globalconst42 == 4321
- py.test.raises(AttributeError, ffi.addressof, lib, 'globalconst42')
-
-def test_global_const_nonint():
- from re_python_pysrc import ffi
- lib = ffi.dlopen(extmod)
- assert ffi.string(lib.globalconsthello, 8) == b"hello"
- py.test.raises(AttributeError, ffi.addressof, lib, 'globalconsthello')
-
-def test_rtld_constants():
- from re_python_pysrc import ffi
- ffi.RTLD_NOW # check that we have the attributes
- ffi.RTLD_LAZY
- ffi.RTLD_GLOBAL
-
-def test_no_such_function_or_global_var():
- from re_python_pysrc import ffi
- lib = ffi.dlopen(extmod)
- e = py.test.raises(ffi.error, getattr, lib, 'no_such_function')
- assert str(e.value).startswith(
- "symbol 'no_such_function' not found in library '")
- e = py.test.raises(ffi.error, getattr, lib, 'no_such_globalvar')
- assert str(e.value).startswith(
- "symbol 'no_such_globalvar' not found in library '")
-
-def test_check_version():
- import _cffi_backend
- e = py.test.raises(ImportError, _cffi_backend.FFI,
- "foobar", _version=0x2594)
- assert str(e.value).startswith(
- "cffi out-of-line Python module 'foobar' has unknown version")
-
-def test_partial_enum():
- ffi = FFI()
- ffi.cdef("enum foo { A, B, ... };")
- ffi.set_source('test_partial_enum', None)
- py.test.raises(VerificationMissing, ffi.emit_python_code,
- str(tmpdir.join('test_partial_enum.py')))
-
-def test_anonymous_union_inside_struct():
- # based on issue #357
- from re_python_pysrc import ffi
- INT = ffi.sizeof("int")
- assert ffi.offsetof("struct with_union", "a") == 0
- assert ffi.offsetof("struct with_union", "b") == 0
- assert ffi.sizeof("struct with_union") == INT
- #
- assert ffi.offsetof("union with_struct", "a") == 0
- assert ffi.offsetof("union with_struct", "b") == INT
- assert ffi.sizeof("union with_struct") >= INT + 1
- #
- assert ffi.sizeof("struct with_struct_with_union") == INT
- p = ffi.new("struct with_struct_with_union *")
- assert p.cp.x == 0
- #
- FLOAT = ffi.sizeof("float")
- assert ffi.sizeof("struct NVGcolor") == FLOAT * 4
- assert ffi.offsetof("struct NVGcolor", "rgba") == 0
- assert ffi.offsetof("struct NVGcolor", "r") == 0
- assert ffi.offsetof("struct NVGcolor", "g") == FLOAT
- assert ffi.offsetof("struct NVGcolor", "b") == FLOAT * 2
- assert ffi.offsetof("struct NVGcolor", "a") == FLOAT * 3
-
-def test_selfref():
- # based on issue #429
- from re_python_pysrc import ffi
- ffi.new("selfref_ptr_t")
-
-def test_dlopen_handle():
- import _cffi_backend
- from re_python_pysrc import ffi
- if sys.platform == 'win32':
- py.test.skip("uses 'dl' explicitly")
- ffi1 = FFI()
- ffi1.cdef("""void *dlopen(const char *filename, int flags);
- int dlclose(void *handle);""")
- lib1 = ffi1.dlopen('dl')
- handle = lib1.dlopen(extmod.encode(sys.getfilesystemencoding()),
- _cffi_backend.RTLD_LAZY)
- assert ffi1.typeof(handle) == ffi1.typeof("void *")
- assert handle
-
- lib = ffi.dlopen(handle)
- assert lib.add42(-10) == 32
- assert type(lib.add42) is _cffi_backend.FFI.CData
-
- err = lib1.dlclose(handle)
- assert err == 0
diff --git a/testing/cffi1/test_realize_c_type.py b/testing/cffi1/test_realize_c_type.py
deleted file mode 100644
index a1f31e6..0000000
--- a/testing/cffi1/test_realize_c_type.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import py, sys
-from cffi import cffi_opcode
-
-
-def check(input, expected_output=None, expected_ffi_error=False):
- import _cffi_backend
- ffi = _cffi_backend.FFI()
- if not expected_ffi_error:
- ct = ffi.typeof(input)
- assert isinstance(ct, ffi.CType)
- assert ct.cname == (expected_output or input)
- else:
- e = py.test.raises(ffi.error, ffi.typeof, input)
- if isinstance(expected_ffi_error, str):
- assert str(e.value) == expected_ffi_error
-
-def test_void():
- check("void", "void")
- check(" void ", "void")
-
-def test_int_star():
- check("int")
- check("int *")
- check("int*", "int *")
- check("long int", "long")
- check("long")
-
-def test_noop():
- check("int(*)", "int *")
-
-def test_array():
- check("int[6]")
-
-def test_funcptr():
- check("int(*)(long)")
- check("int(long)", expected_ffi_error="the type 'int(long)' is a"
- " function type, not a pointer-to-function type")
- check("int(void)", expected_ffi_error="the type 'int()' is a"
- " function type, not a pointer-to-function type")
-
-def test_funcptr_rewrite_args():
- check("int(*)(int(int))", "int(*)(int(*)(int))")
- check("int(*)(long[])", "int(*)(long *)")
- check("int(*)(long[5])", "int(*)(long *)")
-
-def test_all_primitives():
- for name in cffi_opcode.PRIMITIVE_TO_INDEX:
- check(name, name)
-
-def check_func(input, expected_output=None):
- import _cffi_backend
- ffi = _cffi_backend.FFI()
- ct = ffi.typeof(ffi.callback(input, lambda: None))
- assert isinstance(ct, ffi.CType)
- if sys.platform != 'win32' or sys.maxsize > 2**32:
- expected_output = expected_output.replace('__stdcall *', '*')
- assert ct.cname == expected_output
-
-def test_funcptr_stdcall():
- check_func("int(int)", "int(*)(int)")
- check_func("int foobar(int)", "int(*)(int)")
- check_func("int __stdcall(int)", "int(__stdcall *)(int)")
- check_func("int __stdcall foobar(int)", "int(__stdcall *)(int)")
- check_func("void __cdecl(void)", "void(*)()")
- check_func("void __cdecl foobar(void)", "void(*)()")
- check_func("void __stdcall(void)", "void(__stdcall *)()")
- check_func("void __stdcall foobar(long, short)",
- "void(__stdcall *)(long, short)")
- check_func("void(void __cdecl(void), void __stdcall(void))",
- "void(*)(void(*)(), void(__stdcall *)())")
-
-def test_variadic_overrides_stdcall():
- check("void (__stdcall*)(int, ...)", "void(*)(int, ...)")
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
deleted file mode 100644
index fdb4d5a..0000000
--- a/testing/cffi1/test_recompiler.py
+++ /dev/null
@@ -1,2495 +0,0 @@
-
-import sys, os, py
-import pytest
-from cffi import FFI, VerificationError, FFIError, CDefError
-from cffi import recompiler
-from testing.udir import udir
-from testing.support import u, long
-from testing.support import FdWriteCapture, StdErrCapture, _verify
-
-try:
- import importlib
-except ImportError:
- importlib = None
-
-
-def check_type_table(input, expected_output, included=None):
- ffi = FFI()
- if included:
- ffi1 = FFI()
- ffi1.cdef(included)
- ffi.include(ffi1)
- ffi.cdef(input)
- recomp = recompiler.Recompiler(ffi, 'testmod')
- recomp.collect_type_table()
- assert ''.join(map(str, recomp.cffi_types)) == expected_output
-
-def verify(ffi, module_name, source, *args, **kwds):
- no_cpp = kwds.pop('no_cpp', False)
- ignore_warnings = kwds.pop('ignore_warnings', False)
- kwds.setdefault('undef_macros', ['NDEBUG'])
- module_name = '_CFFI_' + module_name
- ffi.set_source(module_name, source)
- if not os.environ.get('NO_CPP') and not no_cpp: # test the .cpp mode too
- kwds.setdefault('source_extension', '.cpp')
- source = 'extern "C" {\n%s\n}' % (source,)
- elif sys.platform != 'win32' and not ignore_warnings:
- # add '-Werror' to the existing 'extra_compile_args' flags
- from testing.support import extra_compile_args
- kwds['extra_compile_args'] = (kwds.get('extra_compile_args', []) +
- extra_compile_args)
- if sys.platform == 'darwin':
- kwds['extra_link_args'] = (kwds.get('extra_link_args', []) +
- ['-stdlib=libc++'])
- return _verify(ffi, module_name, source, *args, **kwds)
-
-def test_set_source_no_slashes():
- ffi = FFI()
- py.test.raises(ValueError, ffi.set_source, "abc/def", None)
- py.test.raises(ValueError, ffi.set_source, "abc/def", "C code")
-
-
-def test_type_table_func():
- check_type_table("double sin(double);",
- "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)")
- check_type_table("float sin(double);",
- "(FUNCTION 3)(PRIMITIVE 14)(FUNCTION_END 0)(PRIMITIVE 13)")
- check_type_table("float sin(void);",
- "(FUNCTION 2)(FUNCTION_END 0)(PRIMITIVE 13)")
- check_type_table("double sin(float); double cos(float);",
- "(FUNCTION 3)(PRIMITIVE 13)(FUNCTION_END 0)(PRIMITIVE 14)")
- check_type_table("double sin(float); double cos(double);",
- "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)" # cos
- "(FUNCTION 1)(PRIMITIVE 13)(FUNCTION_END 0)") # sin
- check_type_table("float sin(double); float cos(float);",
- "(FUNCTION 4)(PRIMITIVE 14)(FUNCTION_END 0)" # sin
- "(FUNCTION 4)(PRIMITIVE 13)(FUNCTION_END 0)") # cos
-
-def test_type_table_use_noop_for_repeated_args():
- check_type_table("double sin(double *, double *);",
- "(FUNCTION 4)(POINTER 4)(NOOP 1)(FUNCTION_END 0)"
- "(PRIMITIVE 14)")
- check_type_table("double sin(double *, double *, double);",
- "(FUNCTION 3)(POINTER 3)(NOOP 1)(PRIMITIVE 14)"
- "(FUNCTION_END 0)")
-
-def test_type_table_dont_use_noop_for_primitives():
- check_type_table("double sin(double, double);",
- "(FUNCTION 1)(PRIMITIVE 14)(PRIMITIVE 14)(FUNCTION_END 0)")
-
-def test_type_table_funcptr_as_argument():
- check_type_table("int sin(double(float));",
- "(FUNCTION 6)(PRIMITIVE 13)(FUNCTION_END 0)"
- "(FUNCTION 7)(POINTER 0)(FUNCTION_END 0)"
- "(PRIMITIVE 14)(PRIMITIVE 7)")
-
-def test_type_table_variadic_function():
- check_type_table("int sin(int, ...);",
- "(FUNCTION 1)(PRIMITIVE 7)(FUNCTION_END 1)(POINTER 0)")
-
-def test_type_table_array():
- check_type_table("extern int a[100];",
- "(PRIMITIVE 7)(ARRAY 0)(None 100)")
-
-def test_type_table_typedef():
- check_type_table("typedef int foo_t;",
- "(PRIMITIVE 7)")
-
-def test_type_table_prebuilt_type():
- check_type_table("int32_t f(void);",
- "(FUNCTION 2)(FUNCTION_END 0)(PRIMITIVE 21)")
-
-def test_type_table_struct_opaque():
- check_type_table("struct foo_s;",
- "(STRUCT_UNION 0)")
-
-def test_type_table_struct():
- check_type_table("struct foo_s { int a; long b; };",
- "(PRIMITIVE 7)(PRIMITIVE 9)(STRUCT_UNION 0)")
-
-def test_type_table_union():
- check_type_table("union foo_u { int a; long b; };",
- "(PRIMITIVE 7)(PRIMITIVE 9)(STRUCT_UNION 0)")
-
-def test_type_table_struct_used():
- check_type_table("struct foo_s { int a; long b; }; int f(struct foo_s*);",
- "(FUNCTION 3)(POINTER 5)(FUNCTION_END 0)"
- "(PRIMITIVE 7)(PRIMITIVE 9)"
- "(STRUCT_UNION 0)")
-
-def test_type_table_anonymous_struct_with_typedef():
- check_type_table("typedef struct { int a; long b; } foo_t;",
- "(STRUCT_UNION 0)(PRIMITIVE 7)(PRIMITIVE 9)")
-
-def test_type_table_enum():
- check_type_table("enum foo_e { AA, BB, ... };",
- "(ENUM 0)")
-
-def test_type_table_include_1():
- check_type_table("foo_t sin(foo_t);",
- "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)",
- included="typedef double foo_t;")
-
-def test_type_table_include_2():
- check_type_table("struct foo_s *sin(struct foo_s *);",
- "(FUNCTION 1)(POINTER 3)(FUNCTION_END 0)(STRUCT_UNION 0)",
- included="struct foo_s { int x, y; };")
-
-
-def test_math_sin():
- import math
- ffi = FFI()
- ffi.cdef("float sin(double); double cos(double);")
- lib = verify(ffi, 'test_math_sin', '#include <math.h>',
- ignore_warnings=True)
- assert lib.cos(1.43) == math.cos(1.43)
-
-def test_repr_lib():
- ffi = FFI()
- lib = verify(ffi, 'test_repr_lib', '')
- assert repr(lib) == "<Lib object for '_CFFI_test_repr_lib'>"
-
-def test_funcarg_ptr():
- ffi = FFI()
- ffi.cdef("int foo(int *);")
- lib = verify(ffi, 'test_funcarg_ptr', 'int foo(int *p) { return *p; }')
- assert lib.foo([-12345]) == -12345
-
-def test_funcres_ptr():
- ffi = FFI()
- ffi.cdef("int *foo(void);")
- lib = verify(ffi, 'test_funcres_ptr',
- 'int *foo(void) { static int x=-12345; return &x; }')
- assert lib.foo()[0] == -12345
-
-def test_global_var_array():
- ffi = FFI()
- ffi.cdef("extern int a[100];")
- lib = verify(ffi, 'test_global_var_array', 'int a[100] = { 9999 };')
- lib.a[42] = 123456
- assert lib.a[42] == 123456
- assert lib.a[0] == 9999
-
-def test_verify_typedef():
- ffi = FFI()
- ffi.cdef("typedef int **foo_t;")
- lib = verify(ffi, 'test_verify_typedef', 'typedef int **foo_t;')
- assert ffi.sizeof("foo_t") == ffi.sizeof("void *")
-
-def test_verify_typedef_dotdotdot():
- ffi = FFI()
- ffi.cdef("typedef ... foo_t;")
- verify(ffi, 'test_verify_typedef_dotdotdot', 'typedef int **foo_t;')
-
-def test_verify_typedef_star_dotdotdot():
- ffi = FFI()
- ffi.cdef("typedef ... *foo_t;")
- verify(ffi, 'test_verify_typedef_star_dotdotdot', 'typedef int **foo_t;')
-
-def test_global_var_int():
- ffi = FFI()
- ffi.cdef("extern int a, b, c;")
- lib = verify(ffi, 'test_global_var_int', 'int a = 999, b, c;')
- assert lib.a == 999
- lib.a -= 1001
- assert lib.a == -2
- lib.a = -2147483648
- assert lib.a == -2147483648
- with pytest.raises(OverflowError):
- lib.a = 2147483648
- with pytest.raises(OverflowError):
- lib.a = -2147483649
- lib.b = 525 # try with the first access being in setattr, too
- assert lib.b == 525
- with pytest.raises(AttributeError):
- del lib.a
- with pytest.raises(AttributeError):
- del lib.c
- with pytest.raises(AttributeError):
- del lib.foobarbaz
-
-def test_macro():
- ffi = FFI()
- ffi.cdef("#define FOOBAR ...")
- lib = verify(ffi, 'test_macro', "#define FOOBAR (-6912)")
- assert lib.FOOBAR == -6912
- with pytest.raises(AttributeError):
- lib.FOOBAR = 2
-
-def test_macro_check_value():
- # the value '-0x80000000' in C sources does not have a clear meaning
- # to me; it appears to have a different effect than '-2147483648'...
- # Moreover, on 32-bits, -2147483648 is actually equal to
- # -2147483648U, which in turn is equal to 2147483648U and so positive.
- vals = ['42', '-42', '0x80000000', '-2147483648',
- '0', '9223372036854775809ULL',
- '-9223372036854775807LL']
- if sys.maxsize <= 2**32 or sys.platform == 'win32':
- vals.remove('-2147483648')
- ffi = FFI()
- cdef_lines = ['#define FOO_%d_%d %s' % (i, j, vals[i])
- for i in range(len(vals))
- for j in range(len(vals))]
- ffi.cdef('\n'.join(cdef_lines))
-
- verify_lines = ['#define FOO_%d_%d %s' % (i, j, vals[j]) # [j], not [i]
- for i in range(len(vals))
- for j in range(len(vals))]
- lib = verify(ffi, 'test_macro_check_value_ok',
- '\n'.join(verify_lines))
- #
- for j in range(len(vals)):
- c_got = int(vals[j].replace('U', '').replace('L', ''), 0)
- c_compiler_msg = str(c_got)
- if c_got > 0:
- c_compiler_msg += ' (0x%x)' % (c_got,)
- #
- for i in range(len(vals)):
- attrname = 'FOO_%d_%d' % (i, j)
- if i == j:
- x = getattr(lib, attrname)
- assert x == c_got
- else:
- e = py.test.raises(ffi.error, getattr, lib, attrname)
- assert str(e.value) == (
- "the C compiler says '%s' is equal to "
- "%s, but the cdef disagrees" % (attrname, c_compiler_msg))
-
-def test_constant():
- ffi = FFI()
- ffi.cdef("static const int FOOBAR;")
- lib = verify(ffi, 'test_constant', "#define FOOBAR (-6912)")
- assert lib.FOOBAR == -6912
- with pytest.raises(AttributeError):
- lib.FOOBAR = 2
-
-def test_check_value_of_static_const():
- ffi = FFI()
- ffi.cdef("static const int FOOBAR = 042;")
- lib = verify(ffi, 'test_check_value_of_static_const',
- "#define FOOBAR (-6912)")
- e = py.test.raises(ffi.error, getattr, lib, 'FOOBAR')
- assert str(e.value) == (
- "the C compiler says 'FOOBAR' is equal to -6912, but the cdef disagrees")
-
-def test_constant_nonint():
- ffi = FFI()
- ffi.cdef("static const double FOOBAR;")
- lib = verify(ffi, 'test_constant_nonint', "#define FOOBAR (-6912.5)")
- assert lib.FOOBAR == -6912.5
- with pytest.raises(AttributeError):
- lib.FOOBAR = 2
-
-def test_constant_ptr():
- ffi = FFI()
- ffi.cdef("static double *const FOOBAR;")
- lib = verify(ffi, 'test_constant_ptr', "#define FOOBAR NULL")
- assert lib.FOOBAR == ffi.NULL
- assert ffi.typeof(lib.FOOBAR) == ffi.typeof("double *")
-
-def test_dir():
- ffi = FFI()
- ffi.cdef("int ff(int); extern int aa; static const int my_constant;")
- lib = verify(ffi, 'test_dir', """
- #define my_constant (-45)
- int aa;
- int ff(int x) { return x+aa; }
- """)
- lib.aa = 5
- assert dir(lib) == ['aa', 'ff', 'my_constant']
- #
- aaobj = lib.__dict__['aa']
- assert not isinstance(aaobj, int) # some internal object instead
- assert lib.__dict__ == {
- 'ff': lib.ff,
- 'aa': aaobj,
- 'my_constant': -45}
- lib.__dict__['ff'] = "??"
- assert lib.ff(10) == 15
-
-def test_verify_opaque_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s;")
- lib = verify(ffi, 'test_verify_opaque_struct', "struct foo_s;")
- assert ffi.typeof("struct foo_s").cname == "struct foo_s"
-
-def test_verify_opaque_union():
- ffi = FFI()
- ffi.cdef("union foo_s;")
- lib = verify(ffi, 'test_verify_opaque_union', "union foo_s;")
- assert ffi.typeof("union foo_s").cname == "union foo_s"
-
-def test_verify_struct():
- ffi = FFI()
- ffi.cdef("""struct foo_s { int b; short a; ...; };
- struct bar_s { struct foo_s *f; };""")
- lib = verify(ffi, 'test_verify_struct',
- """struct foo_s { short a; int b; };
- struct bar_s { struct foo_s *f; };""")
- ffi.typeof("struct bar_s *")
- p = ffi.new("struct foo_s *", {'a': -32768, 'b': -2147483648})
- assert p.a == -32768
- assert p.b == -2147483648
- with pytest.raises(OverflowError):
- p.a -= 1
- with pytest.raises(OverflowError):
- p.b -= 1
- q = ffi.new("struct bar_s *", {'f': p})
- assert q.f == p
- #
- assert ffi.offsetof("struct foo_s", "a") == 0
- assert ffi.offsetof("struct foo_s", "b") == 4
- assert ffi.offsetof(u+"struct foo_s", u+"b") == 4
- #
- py.test.raises(TypeError, ffi.addressof, p)
- assert ffi.addressof(p[0]) == p
- assert ffi.typeof(ffi.addressof(p[0])) is ffi.typeof("struct foo_s *")
- assert ffi.typeof(ffi.addressof(p, "b")) is ffi.typeof("int *")
- assert ffi.addressof(p, "b")[0] == p.b
-
-def test_verify_exact_field_offset():
- ffi = FFI()
- ffi.cdef("""struct foo_s { int b; short a; };""")
- lib = verify(ffi, 'test_verify_exact_field_offset',
- """struct foo_s { short a; int b; };""")
- e = py.test.raises(ffi.error, ffi.new, "struct foo_s *", []) # lazily
- assert str(e.value).startswith(
- "struct foo_s: wrong offset for field 'b' (cdef "
- 'says 0, but C compiler says 4). fix it or use "...;" ')
-
-def test_type_caching():
- ffi1 = FFI(); ffi1.cdef("struct foo_s;")
- ffi2 = FFI(); ffi2.cdef("struct foo_s;") # different one!
- lib1 = verify(ffi1, 'test_type_caching_1', 'struct foo_s;')
- lib2 = verify(ffi2, 'test_type_caching_2', 'struct foo_s;')
- # shared types
- assert ffi1.typeof("long") is ffi2.typeof("long")
- assert ffi1.typeof("long**") is ffi2.typeof("long * *")
- assert ffi1.typeof("long(*)(int, ...)") is ffi2.typeof("long(*)(int, ...)")
- # non-shared types
- assert ffi1.typeof("struct foo_s") is not ffi2.typeof("struct foo_s")
- assert ffi1.typeof("struct foo_s *") is not ffi2.typeof("struct foo_s *")
- assert ffi1.typeof("struct foo_s*(*)()") is not (
- ffi2.typeof("struct foo_s*(*)()"))
- assert ffi1.typeof("void(*)(struct foo_s*)") is not (
- ffi2.typeof("void(*)(struct foo_s*)"))
-
-def test_verify_enum():
- ffi = FFI()
- ffi.cdef("""enum e1 { B1, A1, ... }; enum e2 { B2, A2, ... };""")
- lib = verify(ffi, 'test_verify_enum',
- "enum e1 { A1, B1, C1=%d };" % sys.maxsize +
- "enum e2 { A2, B2, C2 };")
- ffi.typeof("enum e1")
- ffi.typeof("enum e2")
- assert lib.A1 == 0
- assert lib.B1 == 1
- assert lib.A2 == 0
- assert lib.B2 == 1
- assert ffi.sizeof("enum e1") == ffi.sizeof("long")
- assert ffi.sizeof("enum e2") == ffi.sizeof("int")
- assert repr(ffi.cast("enum e1", 0)) == "<cdata 'enum e1' 0: A1>"
-
-def test_duplicate_enum():
- ffi = FFI()
- ffi.cdef("enum e1 { A1, ... }; enum e2 { A1, ... };")
- py.test.raises(VerificationError, verify, ffi, 'test_duplicate_enum',
- "enum e1 { A1 }; enum e2 { B1 };")
-
-def test_dotdotdot_length_of_array_field():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[...]; int b[...]; };")
- verify(ffi, 'test_dotdotdot_length_of_array_field',
- "struct foo_s { int a[42]; int b[11]; };")
- assert ffi.sizeof("struct foo_s") == (42 + 11) * 4
- p = ffi.new("struct foo_s *")
- assert p.a[41] == p.b[10] == 0
- with pytest.raises(IndexError):
- p.a[42]
- with pytest.raises(IndexError):
- p.b[11]
-
-def test_dotdotdot_global_array():
- ffi = FFI()
- ffi.cdef("extern int aa[...]; extern int bb[...];")
- lib = verify(ffi, 'test_dotdotdot_global_array',
- "int aa[41]; int bb[12];")
- assert ffi.sizeof(lib.aa) == 41 * 4
- assert ffi.sizeof(lib.bb) == 12 * 4
- assert lib.aa[40] == lib.bb[11] == 0
- with pytest.raises(IndexError):
- lib.aa[41]
- with pytest.raises(IndexError):
- lib.bb[12]
-
-def test_misdeclared_field_1():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[5]; };")
- try:
- verify(ffi, 'test_misdeclared_field_1',
- "struct foo_s { int a[6]; };")
- except VerificationError:
- pass # ok, fail during compilation already (e.g. C++)
- else:
- assert ffi.sizeof("struct foo_s") == 24 # found by the actual C code
- try:
- # lazily build the fields and boom:
- p = ffi.new("struct foo_s *")
- p.a
- assert False, "should have raised"
- except ffi.error as e:
- assert str(e).startswith("struct foo_s: wrong size for field 'a' "
- "(cdef says 20, but C compiler says 24)")
-
-def test_open_array_in_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { int b; int a[]; };")
- verify(ffi, 'test_open_array_in_struct',
- "struct foo_s { int b; int a[]; };")
- assert ffi.sizeof("struct foo_s") == 4
- p = ffi.new("struct foo_s *", [5, [10, 20, 30, 40]])
- assert p.a[2] == 30
- assert ffi.sizeof(p) == ffi.sizeof("void *")
- assert ffi.sizeof(p[0]) == 5 * ffi.sizeof("int")
-
-def test_math_sin_type():
- ffi = FFI()
- ffi.cdef("double sin(double); void *xxtestfunc();")
- lib = verify(ffi, 'test_math_sin_type', """
- #include <math.h>
- void *xxtestfunc(void) { return 0; }
- """)
- # 'lib.sin' is typed as a <built-in method> object on lib
- assert ffi.typeof(lib.sin).cname == "double(*)(double)"
- # 'x' is another <built-in method> object on lib, made very indirectly
- x = type(lib).__dir__.__get__(lib)
- py.test.raises(TypeError, ffi.typeof, x)
- #
- # present on built-in functions on CPython; must be emulated on PyPy:
- assert lib.sin.__name__ == 'sin'
- assert lib.sin.__module__ == '_CFFI_test_math_sin_type'
- assert lib.sin.__doc__ == (
- "double sin(double);\n"
- "\n"
- "CFFI C function from _CFFI_test_math_sin_type.lib")
-
- assert ffi.typeof(lib.xxtestfunc).cname == "void *(*)()"
- assert lib.xxtestfunc.__doc__ == (
- "void *xxtestfunc();\n"
- "\n"
- "CFFI C function from _CFFI_test_math_sin_type.lib")
-
-def test_verify_anonymous_struct_with_typedef():
- ffi = FFI()
- ffi.cdef("typedef struct { int a; long b; ...; } foo_t;")
- verify(ffi, 'test_verify_anonymous_struct_with_typedef',
- "typedef struct { long b; int hidden, a; } foo_t;")
- p = ffi.new("foo_t *", {'b': 42})
- assert p.b == 42
- assert repr(p).startswith("<cdata 'foo_t *' ")
-
-def test_verify_anonymous_struct_with_star_typedef():
- ffi = FFI()
- ffi.cdef("typedef struct { int a; long b; } *foo_t;")
- verify(ffi, 'test_verify_anonymous_struct_with_star_typedef',
- "typedef struct { int a; long b; } *foo_t;")
- p = ffi.new("foo_t", {'b': 42})
- assert p.b == 42
-
-def test_verify_anonymous_enum_with_typedef():
- ffi = FFI()
- ffi.cdef("typedef enum { AA, ... } e1;")
- lib = verify(ffi, 'test_verify_anonymous_enum_with_typedef1',
- "typedef enum { BB, CC, AA } e1;")
- assert lib.AA == 2
- assert ffi.sizeof("e1") == ffi.sizeof("int")
- assert repr(ffi.cast("e1", 2)) == "<cdata 'e1' 2: AA>"
- #
- ffi = FFI()
- ffi.cdef("typedef enum { AA=%d } e1;" % sys.maxsize)
- lib = verify(ffi, 'test_verify_anonymous_enum_with_typedef2',
- "typedef enum { AA=%d } e1;" % sys.maxsize)
- assert lib.AA == int(ffi.cast("long", sys.maxsize))
- assert ffi.sizeof("e1") == ffi.sizeof("long")
-
-def test_unique_types():
- CDEF = "struct foo_s; union foo_u; enum foo_e { AA };"
- ffi1 = FFI(); ffi1.cdef(CDEF); verify(ffi1, "test_unique_types_1", CDEF)
- ffi2 = FFI(); ffi2.cdef(CDEF); verify(ffi2, "test_unique_types_2", CDEF)
- #
- assert ffi1.typeof("char") is ffi2.typeof("char ")
- assert ffi1.typeof("long") is ffi2.typeof("signed long int")
- assert ffi1.typeof("double *") is ffi2.typeof("double*")
- assert ffi1.typeof("int ***") is ffi2.typeof(" int * * *")
- assert ffi1.typeof("int[]") is ffi2.typeof("signed int[]")
- assert ffi1.typeof("signed int*[17]") is ffi2.typeof("int *[17]")
- assert ffi1.typeof("void") is ffi2.typeof("void")
- assert ffi1.typeof("int(*)(int,int)") is ffi2.typeof("int(*)(int,int)")
- #
- # these depend on user-defined data, so should not be shared
- for name in ["struct foo_s",
- "union foo_u *",
- "enum foo_e",
- "struct foo_s *(*)()",
- "void(*)(struct foo_s *)",
- "struct foo_s *(*[5])[8]",
- ]:
- assert ffi1.typeof(name) is not ffi2.typeof(name)
- # sanity check: twice 'ffi1'
- assert ffi1.typeof("struct foo_s*") is ffi1.typeof("struct foo_s *")
-
-def test_module_name_in_package():
- ffi = FFI()
- ffi.cdef("int foo(int);")
- recompiler.recompile(ffi, "test_module_name_in_package.mymod",
- "int foo(int x) { return x + 32; }",
- tmpdir=str(udir))
- old_sys_path = sys.path[:]
- try:
- package_dir = udir.join('test_module_name_in_package')
- for name in os.listdir(str(udir)):
- assert not name.startswith('test_module_name_in_package.')
- assert os.path.isdir(str(package_dir))
- assert len(os.listdir(str(package_dir))) > 0
- assert os.path.exists(str(package_dir.join('mymod.c')))
- package_dir.join('__init__.py').write('')
- #
- getattr(importlib, 'invalidate_caches', object)()
- #
- sys.path.insert(0, str(udir))
- import test_module_name_in_package.mymod
- assert test_module_name_in_package.mymod.lib.foo(10) == 42
- assert test_module_name_in_package.mymod.__name__ == (
- 'test_module_name_in_package.mymod')
- finally:
- sys.path[:] = old_sys_path
-
-def test_bad_size_of_global_1():
- ffi = FFI()
- ffi.cdef("extern short glob;")
- py.test.raises(VerificationError, verify, ffi,
- "test_bad_size_of_global_1", "long glob;")
-
-def test_bad_size_of_global_2():
- ffi = FFI()
- ffi.cdef("extern int glob[10];")
- py.test.raises(VerificationError, verify, ffi,
- "test_bad_size_of_global_2", "int glob[9];")
-
-def test_unspecified_size_of_global_1():
- ffi = FFI()
- ffi.cdef("extern int glob[];")
- lib = verify(ffi, "test_unspecified_size_of_global_1", "int glob[10];")
- assert ffi.typeof(lib.glob) == ffi.typeof("int *")
-
-def test_unspecified_size_of_global_2():
- ffi = FFI()
- ffi.cdef("extern int glob[][5];")
- lib = verify(ffi, "test_unspecified_size_of_global_2", "int glob[10][5];")
- assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
-
-def test_unspecified_size_of_global_3():
- ffi = FFI()
- ffi.cdef("extern int glob[][...];")
- lib = verify(ffi, "test_unspecified_size_of_global_3", "int glob[10][5];")
- assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
-
-def test_unspecified_size_of_global_4():
- ffi = FFI()
- ffi.cdef("extern int glob[...][...];")
- lib = verify(ffi, "test_unspecified_size_of_global_4", "int glob[10][5];")
- assert ffi.typeof(lib.glob) == ffi.typeof("int[10][5]")
-
-def test_include_1():
- ffi1 = FFI()
- ffi1.cdef("typedef double foo_t;")
- verify(ffi1, "test_include_1_parent", "typedef double foo_t;")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("foo_t ff1(foo_t);")
- lib = verify(ffi, "test_include_1", "double ff1(double x) { return 42.5; }")
- assert lib.ff1(0) == 42.5
- assert ffi1.typeof("foo_t") is ffi.typeof("foo_t") is ffi.typeof("double")
-
-def test_include_1b():
- ffi1 = FFI()
- ffi1.cdef("int foo1(int);")
- lib1 = verify(ffi1, "test_include_1b_parent",
- "int foo1(int x) { return x + 10; }")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("int foo2(int);")
- lib = verify(ffi, "test_include_1b", "int foo2(int x) { return x - 5; }")
- assert lib.foo2(42) == 37
- assert lib.foo1(42) == 52
- assert lib.foo1 is lib1.foo1
-
-def test_include_2():
- ffi1 = FFI()
- ffi1.cdef("struct foo_s { int x, y; };")
- verify(ffi1, "test_include_2_parent", "struct foo_s { int x, y; };")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("struct foo_s *ff2(struct foo_s *);")
- lib = verify(ffi, "test_include_2",
- "struct foo_s { int x, y; }; //usually from a #include\n"
- "struct foo_s *ff2(struct foo_s *p) { p->y++; return p; }")
- p = ffi.new("struct foo_s *")
- p.y = 41
- q = lib.ff2(p)
- assert q == p
- assert p.y == 42
- assert ffi1.typeof("struct foo_s") is ffi.typeof("struct foo_s")
-
-def test_include_3():
- ffi1 = FFI()
- ffi1.cdef("typedef short sshort_t;")
- verify(ffi1, "test_include_3_parent", "typedef short sshort_t;")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("sshort_t ff3(sshort_t);")
- lib = verify(ffi, "test_include_3",
- "typedef short sshort_t; //usually from a #include\n"
- "sshort_t ff3(sshort_t x) { return (sshort_t)(x + 42); }")
- assert lib.ff3(10) == 52
- assert ffi.typeof(ffi.cast("sshort_t", 42)) is ffi.typeof("short")
- assert ffi1.typeof("sshort_t") is ffi.typeof("sshort_t")
-
-def test_include_4():
- ffi1 = FFI()
- ffi1.cdef("typedef struct { int x; } mystruct_t;")
- verify(ffi1, "test_include_4_parent",
- "typedef struct { int x; } mystruct_t;")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("mystruct_t *ff4(mystruct_t *);")
- lib = verify(ffi, "test_include_4",
- "typedef struct {int x; } mystruct_t; //usually from a #include\n"
- "mystruct_t *ff4(mystruct_t *p) { p->x += 42; return p; }")
- p = ffi.new("mystruct_t *", [10])
- q = lib.ff4(p)
- assert q == p
- assert p.x == 52
- assert ffi1.typeof("mystruct_t") is ffi.typeof("mystruct_t")
-
-def test_include_5():
- ffi1 = FFI()
- ffi1.cdef("typedef struct { int x[2]; int y; } *mystruct_p;")
- verify(ffi1, "test_include_5_parent",
- "typedef struct { int x[2]; int y; } *mystruct_p;")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("mystruct_p ff5(mystruct_p);")
- lib = verify(ffi, "test_include_5",
- "typedef struct {int x[2]; int y; } *mystruct_p; //usually #include\n"
- "mystruct_p ff5(mystruct_p p) { p->x[1] += 42; return p; }")
- assert ffi.alignof(ffi.typeof("mystruct_p").item) == 4
- assert ffi1.typeof("mystruct_p") is ffi.typeof("mystruct_p")
- p = ffi.new("mystruct_p", [[5, 10], -17])
- q = lib.ff5(p)
- assert q == p
- assert p.x[0] == 5
- assert p.x[1] == 52
- assert p.y == -17
- assert ffi.alignof(ffi.typeof(p[0])) == 4
-
-def test_include_6():
- ffi1 = FFI()
- ffi1.cdef("typedef ... mystruct_t;")
- verify(ffi1, "test_include_6_parent",
- "typedef struct _mystruct_s mystruct_t;")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("mystruct_t *ff6(void); int ff6b(mystruct_t *);")
- lib = verify(ffi, "test_include_6",
- "typedef struct _mystruct_s mystruct_t; //usually from a #include\n"
- "struct _mystruct_s { int x; };\n"
- "static mystruct_t result_struct = { 42 };\n"
- "mystruct_t *ff6(void) { return &result_struct; }\n"
- "int ff6b(mystruct_t *p) { return p->x; }")
- p = lib.ff6()
- assert ffi.cast("int *", p)[0] == 42
- assert lib.ff6b(p) == 42
-
-def test_include_7():
- ffi1 = FFI()
- ffi1.cdef("typedef ... mystruct_t;\n"
- "int ff7b(mystruct_t *);")
- verify(ffi1, "test_include_7_parent",
- "typedef struct { int x; } mystruct_t;\n"
- "int ff7b(mystruct_t *p) { return p->x; }")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("mystruct_t *ff7(void);")
- lib = verify(ffi, "test_include_7",
- "typedef struct { int x; } mystruct_t; //usually from a #include\n"
- "static mystruct_t result_struct = { 42 };"
- "mystruct_t *ff7(void) { return &result_struct; }")
- p = lib.ff7()
- assert ffi.cast("int *", p)[0] == 42
- assert lib.ff7b(p) == 42
-
-def test_include_8():
- ffi1 = FFI()
- ffi1.cdef("struct foo_s;")
- verify(ffi1, "test_include_8_parent", "struct foo_s;")
- ffi = FFI()
- ffi.include(ffi1)
- ffi.cdef("struct foo_s { int x, y; };")
- verify(ffi, "test_include_8", "struct foo_s { int x, y; };")
- e = py.test.raises(NotImplementedError, ffi.new, "struct foo_s *")
- assert str(e.value) == (
- "'struct foo_s' 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 struct foo_s)")
-
-def test_unicode_libraries():
- try:
- unicode
- except NameError:
- py.test.skip("for python 2.x")
- #
- import math
- lib_m = "m"
- if sys.platform == 'win32':
- #there is a small chance this fails on Mingw via environ $CC
- import distutils.ccompiler
- if distutils.ccompiler.get_default_compiler() == 'msvc':
- lib_m = 'msvcrt'
- ffi = FFI()
- ffi.cdef(unicode("float sin(double); double cos(double);"))
- lib = verify(ffi, 'test_math_sin_unicode', unicode('#include <math.h>'),
- libraries=[unicode(lib_m)], ignore_warnings=True)
- assert lib.cos(1.43) == math.cos(1.43)
-
-def test_incomplete_struct_as_arg():
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; ...; }; int f(int, struct foo_s);")
- lib = verify(ffi, "test_incomplete_struct_as_arg",
- "struct foo_s { int a, x, z; };\n"
- "int f(int b, struct foo_s s) { return s.x * b; }")
- s = ffi.new("struct foo_s *", [21])
- assert s.x == 21
- assert ffi.sizeof(s[0]) == 12
- assert ffi.offsetof(ffi.typeof(s), 'x') == 4
- assert lib.f(2, s[0]) == 42
- assert ffi.typeof(lib.f) == ffi.typeof("int(*)(int, struct foo_s)")
-
-def test_incomplete_struct_as_result():
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; ...; }; struct foo_s f(int);")
- lib = verify(ffi, "test_incomplete_struct_as_result",
- "struct foo_s { int a, x, z; };\n"
- "struct foo_s f(int x) { struct foo_s r; r.x = x * 2; return r; }")
- s = lib.f(21)
- assert s.x == 42
- assert ffi.typeof(lib.f) == ffi.typeof("struct foo_s(*)(int)")
-
-def test_incomplete_struct_as_both():
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; ...; }; struct bar_s { int y; ...; };\n"
- "struct foo_s f(int, struct bar_s);")
- lib = verify(ffi, "test_incomplete_struct_as_both",
- "struct foo_s { int a, x, z; };\n"
- "struct bar_s { int b, c, y, d; };\n"
- "struct foo_s f(int x, struct bar_s b) {\n"
- " struct foo_s r; r.x = x * b.y; return r;\n"
- "}")
- b = ffi.new("struct bar_s *", [7])
- s = lib.f(6, b[0])
- assert s.x == 42
- assert ffi.typeof(lib.f) == ffi.typeof(
- "struct foo_s(*)(int, struct bar_s)")
- s = lib.f(14, {'y': -3})
- assert s.x == -42
-
-def test_name_of_unnamed_struct():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; } foo_t;\n"
- "typedef struct { int y; } *bar_p;\n"
- "typedef struct { int y; } **baz_pp;\n")
- verify(ffi, "test_name_of_unnamed_struct",
- "typedef struct { int x; } foo_t;\n"
- "typedef struct { int y; } *bar_p;\n"
- "typedef struct { int y; } **baz_pp;\n")
- assert repr(ffi.typeof("foo_t")) == "<ctype 'foo_t'>"
- assert repr(ffi.typeof("bar_p")) == "<ctype 'struct $1 *'>"
- assert repr(ffi.typeof("baz_pp")) == "<ctype 'struct $2 * *'>"
-
-def test_address_of_global_var():
- ffi = FFI()
- ffi.cdef("""
- extern long bottom, bottoms[2];
- long FetchRectBottom(void);
- long FetchRectBottoms1(void);
- #define FOOBAR 42
- """)
- lib = verify(ffi, "test_address_of_global_var", """
- long bottom, bottoms[2];
- long FetchRectBottom(void) { return bottom; }
- long FetchRectBottoms1(void) { return bottoms[1]; }
- #define FOOBAR 42
- """)
- lib.bottom = 300
- assert lib.FetchRectBottom() == 300
- lib.bottom += 1
- assert lib.FetchRectBottom() == 301
- lib.bottoms[1] = 500
- assert lib.FetchRectBottoms1() == 500
- lib.bottoms[1] += 2
- assert lib.FetchRectBottoms1() == 502
- #
- p = ffi.addressof(lib, 'bottom')
- assert ffi.typeof(p) == ffi.typeof("long *")
- assert p[0] == 301
- p[0] += 1
- assert lib.FetchRectBottom() == 302
- p = ffi.addressof(lib, 'bottoms')
- assert ffi.typeof(p) == ffi.typeof("long(*)[2]")
- assert p[0] == lib.bottoms
- #
- py.test.raises(AttributeError, ffi.addressof, lib, 'unknown_var')
- py.test.raises(AttributeError, ffi.addressof, lib, "FOOBAR")
-
-def test_defines__CFFI_():
- # Check that we define the macro _CFFI_ automatically.
- # It should be done before including Python.h, so that PyPy's Python.h
- # can check for it.
- ffi = FFI()
- ffi.cdef("""
- #define CORRECT 1
- """)
- lib = verify(ffi, "test_defines__CFFI_", """
- #ifdef _CFFI_
- # define CORRECT 1
- #endif
- """)
- assert lib.CORRECT == 1
-
-def test_unpack_args():
- ffi = FFI()
- ffi.cdef("void foo0(void); void foo1(int); void foo2(int, int);")
- lib = verify(ffi, "test_unpack_args", """
- void foo0(void) { }
- void foo1(int x) { }
- void foo2(int x, int y) { }
- """)
- assert 'foo0' in repr(lib.foo0)
- assert 'foo1' in repr(lib.foo1)
- assert 'foo2' in repr(lib.foo2)
- lib.foo0()
- lib.foo1(42)
- lib.foo2(43, 44)
- e1 = py.test.raises(TypeError, lib.foo0, 42)
- e2 = py.test.raises(TypeError, lib.foo0, 43, 44)
- e3 = py.test.raises(TypeError, lib.foo1)
- e4 = py.test.raises(TypeError, lib.foo1, 43, 44)
- e5 = py.test.raises(TypeError, lib.foo2)
- e6 = py.test.raises(TypeError, lib.foo2, 42)
- e7 = py.test.raises(TypeError, lib.foo2, 45, 46, 47)
- def st1(s):
- s = str(s)
- if s.startswith("_CFFI_test_unpack_args.Lib."):
- s = s[len("_CFFI_test_unpack_args.Lib."):]
- return s
- assert st1(e1.value) == "foo0() takes no arguments (1 given)"
- assert st1(e2.value) == "foo0() takes no arguments (2 given)"
- assert st1(e3.value) == "foo1() takes exactly one argument (0 given)"
- assert st1(e4.value) == "foo1() takes exactly one argument (2 given)"
- assert st1(e5.value) in ["foo2 expected 2 arguments, got 0",
- "foo2() takes exactly 2 arguments (0 given)"]
- assert st1(e6.value) in ["foo2 expected 2 arguments, got 1",
- "foo2() takes exactly 2 arguments (1 given)"]
- assert st1(e7.value) in ["foo2 expected 2 arguments, got 3",
- "foo2() takes exactly 2 arguments (3 given)"]
-
-def test_address_of_function():
- ffi = FFI()
- ffi.cdef("long myfunc(long x);")
- lib = verify(ffi, "test_addressof_function", """
- char myfunc(char x) { return (char)(x + 42); }
- """, ignore_warnings=True)
- assert lib.myfunc(5) == 47
- assert lib.myfunc(0xABC05) == 47
- assert not isinstance(lib.myfunc, ffi.CData)
- assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(long)")
- addr = ffi.addressof(lib, 'myfunc')
- assert addr(5) == 47
- assert addr(0xABC05) == 47
- assert isinstance(addr, ffi.CData)
- assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
-
-def test_address_of_function_with_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; }; long myfunc(struct foo_s);")
- lib = verify(ffi, "test_addressof_function_with_struct", """
- struct foo_s { int x; };
- char myfunc(struct foo_s input) { return (char)(input.x + 42); }
- """)
- s = ffi.new("struct foo_s *", [5])[0]
- assert lib.myfunc(s) == 47
- assert not isinstance(lib.myfunc, ffi.CData)
- assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(struct foo_s)")
- addr = ffi.addressof(lib, 'myfunc')
- assert addr(s) == 47
- assert isinstance(addr, ffi.CData)
- assert ffi.typeof(addr) == ffi.typeof("long(*)(struct foo_s)")
-
-def test_issue198():
- ffi = FFI()
- ffi.cdef("""
- typedef struct{...;} opaque_t;
- const opaque_t CONSTANT;
- int toint(opaque_t);
- """)
- lib = verify(ffi, 'test_issue198', """
- typedef int opaque_t;
- #define CONSTANT ((opaque_t)42)
- static int toint(opaque_t o) { return o; }
- """)
- def random_stuff():
- pass
- assert lib.toint(lib.CONSTANT) == 42
- random_stuff()
- assert lib.toint(lib.CONSTANT) == 42
-
-def test_constant_is_not_a_compiler_constant():
- ffi = FFI()
- ffi.cdef("static const float almost_forty_two;")
- lib = verify(ffi, 'test_constant_is_not_a_compiler_constant', """
- static float f(void) { return 42.25; }
- #define almost_forty_two (f())
- """)
- assert lib.almost_forty_two == 42.25
-
-def test_constant_of_unknown_size():
- ffi = FFI()
- ffi.cdef("""
- typedef ... opaque_t;
- const opaque_t CONSTANT;
- """)
- lib = verify(ffi, 'test_constant_of_unknown_size',
- "typedef int opaque_t;"
- "const int CONSTANT = 42;")
- e = py.test.raises(ffi.error, getattr, lib, 'CONSTANT')
- assert str(e.value) == ("constant 'CONSTANT' is of "
- "type 'opaque_t', whose size is not known")
-
-def test_variable_of_unknown_size():
- ffi = FFI()
- ffi.cdef("""
- typedef ... opaque_t;
- extern opaque_t globvar;
- """)
- lib = verify(ffi, 'test_variable_of_unknown_size', """
- typedef char opaque_t[6];
- opaque_t globvar = "hello";
- """)
- # can't read or write it at all
- e = py.test.raises(TypeError, getattr, lib, 'globvar')
- assert str(e.value) in ["cdata 'opaque_t' is opaque",
- "'opaque_t' is opaque or not completed yet"] #pypy
- e = py.test.raises(TypeError, setattr, lib, 'globvar', [])
- assert str(e.value) in ["'opaque_t' is opaque",
- "'opaque_t' is opaque or not completed yet"] #pypy
- # but we can get its address
- p = ffi.addressof(lib, 'globvar')
- assert ffi.typeof(p) == ffi.typeof('opaque_t *')
- assert ffi.string(ffi.cast("char *", p), 8) == b"hello"
-
-def test_constant_of_value_unknown_to_the_compiler():
- extra_c_source = udir.join(
- 'extra_test_constant_of_value_unknown_to_the_compiler.c')
- extra_c_source.write('const int external_foo = 42;\n')
- ffi = FFI()
- ffi.cdef("const int external_foo;")
- lib = verify(ffi, 'test_constant_of_value_unknown_to_the_compiler', """
- extern const int external_foo;
- """, sources=[str(extra_c_source)])
- assert lib.external_foo == 42
-
-def test_dotdot_in_source_file_names():
- extra_c_source = udir.join(
- 'extra_test_dotdot_in_source_file_names.c')
- extra_c_source.write('const int external_foo = 42;\n')
- ffi = FFI()
- ffi.cdef("const int external_foo;")
- lib = verify(ffi, 'test_dotdot_in_source_file_names', """
- extern const int external_foo;
- """, sources=[os.path.join(os.path.dirname(str(extra_c_source)),
- 'foobar', '..',
- os.path.basename(str(extra_c_source)))])
- assert lib.external_foo == 42
-
-def test_call_with_incomplete_structs():
- ffi = FFI()
- ffi.cdef("typedef struct {...;} foo_t; "
- "extern foo_t myglob; "
- "foo_t increment(foo_t s); "
- "double getx(foo_t s);")
- lib = verify(ffi, 'test_call_with_incomplete_structs', """
- typedef double foo_t;
- double myglob = 42.5;
- double getx(double x) { return x; }
- double increment(double x) { return x + 1; }
- """)
- assert lib.getx(lib.myglob) == 42.5
- assert lib.getx(lib.increment(lib.myglob)) == 43.5
-
-def test_struct_array_guess_length_2():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[...][...]; };")
- lib = verify(ffi, 'test_struct_array_guess_length_2',
- "struct foo_s { int x; int a[5][8]; int y; };")
- assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *")
- assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
- assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int')
- assert s.a[4][7] == 0
- with pytest.raises(IndexError):
- s.a[4][8]
- with pytest.raises(IndexError):
- s.a[5][0]
- assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
- assert ffi.typeof(s.a[0]) == ffi.typeof("int[8]")
-
-def test_struct_array_guess_length_3():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[][...]; };")
- lib = verify(ffi, 'test_struct_array_guess_length_3',
- "struct foo_s { int x; int a[5][7]; int y; };")
- assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *")
- assert ffi.typeof(s.a) == ffi.typeof("int[][7]")
- assert s.a[4][6] == 0
- with pytest.raises(IndexError):
- s.a[4][7]
- assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]")
-
-def test_global_var_array_2():
- ffi = FFI()
- ffi.cdef("extern int a[...][...];")
- lib = verify(ffi, 'test_global_var_array_2', 'int a[10][8];')
- lib.a[9][7] = 123456
- assert lib.a[9][7] == 123456
- with pytest.raises(IndexError):
- lib.a[0][8]
- with pytest.raises(IndexError):
- lib.a[10][0]
- assert ffi.typeof(lib.a) == ffi.typeof("int[10][8]")
- assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]")
-
-def test_global_var_array_3():
- ffi = FFI()
- ffi.cdef("extern int a[][...];")
- lib = verify(ffi, 'test_global_var_array_3', 'int a[10][8];')
- lib.a[9][7] = 123456
- assert lib.a[9][7] == 123456
- with pytest.raises(IndexError):
- lib.a[0][8]
- assert ffi.typeof(lib.a) == ffi.typeof("int(*)[8]")
- assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]")
-
-def test_global_var_array_4():
- ffi = FFI()
- ffi.cdef("extern int a[10][...];")
- lib = verify(ffi, 'test_global_var_array_4', 'int a[10][8];')
- lib.a[9][7] = 123456
- assert lib.a[9][7] == 123456
- with pytest.raises(IndexError):
- lib.a[0][8]
- with pytest.raises(IndexError):
- lib.a[10][8]
- assert ffi.typeof(lib.a) == ffi.typeof("int[10][8]")
- assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]")
-
-def test_some_integer_type():
- ffi = FFI()
- ffi.cdef("""
- typedef int... foo_t;
- typedef unsigned long... bar_t;
- typedef struct { foo_t a, b; } mystruct_t;
- foo_t foobar(bar_t, mystruct_t);
- static const bar_t mu = -20;
- static const foo_t nu = 20;
- """)
- lib = verify(ffi, 'test_some_integer_type', """
- typedef unsigned long long foo_t;
- typedef short bar_t;
- typedef struct { foo_t a, b; } mystruct_t;
- static foo_t foobar(bar_t x, mystruct_t s) {
- return (foo_t)x + s.a + s.b;
- }
- static const bar_t mu = -20;
- static const foo_t nu = 20;
- """)
- assert ffi.sizeof("foo_t") == ffi.sizeof("unsigned long long")
- assert ffi.sizeof("bar_t") == ffi.sizeof("short")
- maxulonglong = 2 ** 64 - 1
- assert int(ffi.cast("foo_t", -1)) == maxulonglong
- assert int(ffi.cast("bar_t", -1)) == -1
- assert lib.foobar(-1, [0, 0]) == maxulonglong
- assert lib.foobar(2 ** 15 - 1, [0, 0]) == 2 ** 15 - 1
- assert lib.foobar(10, [20, 31]) == 61
- assert lib.foobar(0, [0, maxulonglong]) == maxulonglong
- py.test.raises(OverflowError, lib.foobar, 2 ** 15, [0, 0])
- py.test.raises(OverflowError, lib.foobar, -(2 ** 15) - 1, [0, 0])
- py.test.raises(OverflowError, ffi.new, "mystruct_t *", [0, -1])
- assert lib.mu == -20
- assert lib.nu == 20
-
-def test_some_float_type():
- ffi = FFI()
- ffi.cdef("""
- typedef double... foo_t;
- typedef float... bar_t;
- foo_t sum(foo_t[]);
- bar_t neg(bar_t);
- """)
- lib = verify(ffi, 'test_some_float_type', """
- typedef float foo_t;
- static foo_t sum(foo_t x[]) { return x[0] + x[1]; }
- typedef double bar_t;
- static double neg(double x) { return -x; }
- """)
- assert lib.sum([40.0, 2.25]) == 42.25
- assert lib.sum([12.3, 45.6]) != 12.3 + 45.6 # precision loss
- assert lib.neg(12.3) == -12.3 # no precision loss
- assert ffi.sizeof("foo_t") == ffi.sizeof("float")
- assert ffi.sizeof("bar_t") == ffi.sizeof("double")
-
-def test_some_float_invalid_1():
- ffi = FFI()
- py.test.raises((FFIError, # with pycparser <= 2.17
- CDefError), # with pycparser >= 2.18
- ffi.cdef, "typedef long double... foo_t;")
-
-def test_some_float_invalid_2():
- ffi = FFI()
- ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);")
- lib = verify(ffi, 'test_some_float_invalid_2', """
- typedef unsigned long foo_t;
- foo_t neg(foo_t x) { return -x; }
- """)
- e = py.test.raises(ffi.error, getattr, lib, 'neg')
- assert str(e.value) == ("primitive floating-point type with an unexpected "
- "size (or not a float type at all)")
-
-def test_some_float_invalid_3():
- ffi = FFI()
- ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);")
- lib = verify(ffi, 'test_some_float_invalid_3', """
- typedef long double foo_t;
- foo_t neg(foo_t x) { return -x; }
- """, ignore_warnings=True)
- if ffi.sizeof("long double") == ffi.sizeof("double"):
- assert lib.neg(12.3) == -12.3
- else:
- e = py.test.raises(ffi.error, getattr, lib, 'neg')
- assert str(e.value) == ("primitive floating-point type is "
- "'long double', not supported for now with "
- "the syntax 'typedef double... xxx;'")
-
-def test_issue200():
- ffi = FFI()
- ffi.cdef("""
- typedef void (function_t)(void*);
- void function(void *);
- """)
- lib = verify(ffi, 'test_issue200', """
- static void function(void *p) { (void)p; }
- """)
- ffi.typeof('function_t*')
- lib.function(ffi.NULL)
- # assert did not crash
-
-def test_alignment_of_longlong():
- ffi = FFI()
- x1 = ffi.alignof('unsigned long long')
- assert x1 in [4, 8]
- ffi.cdef("struct foo_s { unsigned long long x; };")
- lib = verify(ffi, 'test_alignment_of_longlong',
- "struct foo_s { unsigned long long x; };")
- assert ffi.alignof('unsigned long long') == x1
- assert ffi.alignof('struct foo_s') == x1
-
-def test_import_from_lib():
- ffi = FFI()
- ffi.cdef("int mybar(int); static int myvar;\n#define MYFOO ...")
- lib = verify(ffi, 'test_import_from_lib',
- "#define MYFOO 42\n"
- "static int mybar(int x) { return x + 1; }\n"
- "static int myvar = -5;")
- assert sys.modules['_CFFI_test_import_from_lib'].lib is lib
- assert sys.modules['_CFFI_test_import_from_lib.lib'] is lib
- from _CFFI_test_import_from_lib.lib import MYFOO
- assert MYFOO == 42
- assert hasattr(lib, '__dict__')
- assert lib.__all__ == ['MYFOO', 'mybar'] # but not 'myvar'
- assert lib.__name__ == '_CFFI_test_import_from_lib.lib'
- assert lib.__class__ is type(sys) # !! hack for help()
-
-def test_macro_var_callback():
- ffi = FFI()
- ffi.cdef("extern int my_value; extern int *(*get_my_value)(void);")
- lib = verify(ffi, 'test_macro_var_callback',
- "int *(*get_my_value)(void);\n"
- "#define my_value (*get_my_value())")
- #
- values = ffi.new("int[50]")
- def it():
- for i in range(50):
- yield i
- it = it()
- #
- @ffi.callback("int *(*)(void)")
- def get_my_value():
- for nextvalue in it:
- return values + nextvalue
- lib.get_my_value = get_my_value
- #
- values[0] = 41
- assert lib.my_value == 41 # [0]
- p = ffi.addressof(lib, 'my_value') # [1]
- assert p == values + 1
- assert p[-1] == 41
- assert p[+1] == 0
- lib.my_value = 42 # [2]
- assert values[2] == 42
- assert p[-1] == 41
- assert p[+1] == 42
- #
- # if get_my_value raises or returns nonsense, the exception is printed
- # to stderr like with any callback, but then the C expression 'my_value'
- # expand to '*NULL'. We assume here that '&my_value' will return NULL
- # without segfaulting, and check for NULL when accessing the variable.
- @ffi.callback("int *(*)(void)")
- def get_my_value():
- raise LookupError
- lib.get_my_value = get_my_value
- py.test.raises(ffi.error, getattr, lib, 'my_value')
- py.test.raises(ffi.error, setattr, lib, 'my_value', 50)
- py.test.raises(ffi.error, ffi.addressof, lib, 'my_value')
- @ffi.callback("int *(*)(void)")
- def get_my_value():
- return "hello"
- lib.get_my_value = get_my_value
- py.test.raises(ffi.error, getattr, lib, 'my_value')
- e = py.test.raises(ffi.error, setattr, lib, 'my_value', 50)
- assert str(e.value) == "global variable 'my_value' is at address NULL"
-
-def test_const_fields():
- ffi = FFI()
- ffi.cdef("""struct foo_s { const int a; void *const b; };""")
- lib = verify(ffi, 'test_const_fields', """
- struct foo_s { const int a; void *const b; };""")
- foo_s = ffi.typeof("struct foo_s")
- assert foo_s.fields[0][0] == 'a'
- assert foo_s.fields[0][1].type is ffi.typeof("int")
- assert foo_s.fields[1][0] == 'b'
- assert foo_s.fields[1][1].type is ffi.typeof("void *")
-
-def test_restrict_fields():
- ffi = FFI()
- ffi.cdef("""struct foo_s { void * restrict b; };""")
- lib = verify(ffi, 'test_restrict_fields', """
- 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 *")
-
-def test_const_array_fields():
- ffi = FFI()
- ffi.cdef("""struct foo_s { const int a[4]; };""")
- lib = verify(ffi, 'test_const_array_fields', """
- struct foo_s { const int a[4]; };""")
- foo_s = ffi.typeof("struct foo_s")
- assert foo_s.fields[0][0] == 'a'
- assert foo_s.fields[0][1].type is ffi.typeof("int[4]")
-
-def test_const_array_fields_varlength():
- ffi = FFI()
- ffi.cdef("""struct foo_s { const int a[]; ...; };""")
- lib = verify(ffi, 'test_const_array_fields_varlength', """
- struct foo_s { const int a[4]; };""")
- foo_s = ffi.typeof("struct foo_s")
- assert foo_s.fields[0][0] == 'a'
- assert foo_s.fields[0][1].type is ffi.typeof("int[]")
-
-def test_const_array_fields_unknownlength():
- ffi = FFI()
- ffi.cdef("""struct foo_s { const int a[...]; ...; };""")
- lib = verify(ffi, 'test_const_array_fields_unknownlength', """
- struct foo_s { const int a[4]; };""")
- foo_s = ffi.typeof("struct foo_s")
- assert foo_s.fields[0][0] == 'a'
- assert foo_s.fields[0][1].type is ffi.typeof("int[4]")
-
-def test_const_function_args():
- ffi = FFI()
- ffi.cdef("""int foobar(const int a, const int *b, const int c[]);""")
- lib = verify(ffi, 'test_const_function_args', """
- int foobar(const int a, const int *b, const int c[]) {
- return a + *b + *c;
- }
- """)
- assert lib.foobar(100, ffi.new("int *", 40), ffi.new("int *", 2)) == 142
-
-def test_const_function_type_args():
- ffi = FFI()
- ffi.cdef("""extern int(*foobar)(const int a,const int*b,const int c[]);""")
- lib = verify(ffi, 'test_const_function_type_args', """
- int (*foobar)(const int a, const int *b, const int c[]);
- """)
- t = ffi.typeof(lib.foobar)
- assert t.args[0] is ffi.typeof("int")
- assert t.args[1] is ffi.typeof("int *")
- assert t.args[2] is ffi.typeof("int *")
-
-def test_const_constant():
- ffi = FFI()
- ffi.cdef("""struct foo_s { int x,y; }; const struct foo_s myfoo;""")
- lib = verify(ffi, 'test_const_constant', """
- struct foo_s { int x,y; }; const struct foo_s myfoo = { 40, 2 };
- """)
- assert lib.myfoo.x == 40
- assert lib.myfoo.y == 2
-
-def test_const_via_typedef():
- ffi = FFI()
- ffi.cdef("""typedef const int const_t; const_t aaa;""")
- lib = verify(ffi, 'test_const_via_typedef', """
- typedef const int const_t;
- #define aaa 42
- """)
- assert lib.aaa == 42
- with pytest.raises(AttributeError):
- lib.aaa = 43
-
-def test_win32_calling_convention_0():
- ffi = FFI()
- ffi.cdef("""
- int call1(int(__cdecl *cb)(int));
- int (*const call2)(int(__stdcall *cb)(int));
- """)
- lib = verify(ffi, 'test_win32_calling_convention_0', r"""
- #ifndef _MSC_VER
- # define __stdcall /* nothing */
- #endif
- int call1(int(*cb)(int)) {
- int i, result = 0;
- //printf("call1: cb = %p\n", cb);
- for (i = 0; i < 1000; i++)
- result += cb(i);
- //printf("result = %d\n", result);
- return result;
- }
- int call2(int(__stdcall *cb)(int)) {
- int i, result = 0;
- //printf("call2: cb = %p\n", cb);
- for (i = 0; i < 1000; i++)
- result += cb(-i);
- //printf("result = %d\n", result);
- return result;
- }
- """)
- @ffi.callback("int(int)")
- def cb1(x):
- return x * 2
- @ffi.callback("int __stdcall(int)")
- def cb2(x):
- return x * 3
- res = lib.call1(cb1)
- assert res == 500*999*2
- assert res == ffi.addressof(lib, 'call1')(cb1)
- res = lib.call2(cb2)
- assert res == -500*999*3
- assert res == ffi.addressof(lib, 'call2')(cb2)
- if sys.platform == 'win32' and not sys.maxsize > 2**32:
- assert '__stdcall' in str(ffi.typeof(cb2))
- assert '__stdcall' not in str(ffi.typeof(cb1))
- py.test.raises(TypeError, lib.call1, cb2)
- py.test.raises(TypeError, lib.call2, cb1)
- else:
- assert '__stdcall' not in str(ffi.typeof(cb2))
- assert ffi.typeof(cb2) is ffi.typeof(cb1)
-
-def test_win32_calling_convention_1():
- ffi = FFI()
- ffi.cdef("""
- int __cdecl call1(int(__cdecl *cb)(int));
- int __stdcall call2(int(__stdcall *cb)(int));
- int (__cdecl *const cb1)(int);
- int (__stdcall *const cb2)(int);
- """)
- lib = verify(ffi, 'test_win32_calling_convention_1', r"""
- #ifndef _MSC_VER
- # define __cdecl
- # define __stdcall
- #endif
- int __cdecl cb1(int x) { return x * 2; }
- int __stdcall cb2(int x) { return x * 3; }
-
- int __cdecl call1(int(__cdecl *cb)(int)) {
- int i, result = 0;
- //printf("here1\n");
- //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
- for (i = 0; i < 1000; i++)
- result += cb(i);
- //printf("result = %d\n", result);
- return result;
- }
- int __stdcall call2(int(__stdcall *cb)(int)) {
- int i, result = 0;
- //printf("here1\n");
- //printf("cb = %p, cb2 = %p\n", cb, (void *)cb2);
- for (i = 0; i < 1000; i++)
- result += cb(-i);
- //printf("result = %d\n", result);
- return result;
- }
- """)
- #print '<<< cb1 =', ffi.addressof(lib, 'cb1')
- ptr_call1 = ffi.addressof(lib, 'call1')
- assert lib.call1(ffi.addressof(lib, 'cb1')) == 500*999*2
- assert ptr_call1(ffi.addressof(lib, 'cb1')) == 500*999*2
- #print '<<< cb2 =', ffi.addressof(lib, 'cb2')
- ptr_call2 = ffi.addressof(lib, 'call2')
- assert lib.call2(ffi.addressof(lib, 'cb2')) == -500*999*3
- assert ptr_call2(ffi.addressof(lib, 'cb2')) == -500*999*3
- #print '<<< done'
-
-def test_win32_calling_convention_2():
- # any mistake in the declaration of plain function (including the
- # precise argument types and, here, the calling convention) are
- # automatically corrected. But this does not apply to the 'cb'
- # function pointer argument.
- ffi = FFI()
- ffi.cdef("""
- int __stdcall call1(int(__cdecl *cb)(int));
- int __cdecl call2(int(__stdcall *cb)(int));
- int (__cdecl *const cb1)(int);
- int (__stdcall *const cb2)(int);
- """)
- lib = verify(ffi, 'test_win32_calling_convention_2', """
- #ifndef _MSC_VER
- # define __cdecl
- # define __stdcall
- #endif
- int __cdecl call1(int(__cdecl *cb)(int)) {
- int i, result = 0;
- for (i = 0; i < 1000; i++)
- result += cb(i);
- return result;
- }
- int __stdcall call2(int(__stdcall *cb)(int)) {
- int i, result = 0;
- for (i = 0; i < 1000; i++)
- result += cb(-i);
- return result;
- }
- int __cdecl cb1(int x) { return x * 2; }
- int __stdcall cb2(int x) { return x * 3; }
- """)
- ptr_call1 = ffi.addressof(lib, 'call1')
- ptr_call2 = ffi.addressof(lib, 'call2')
- if sys.platform == 'win32' and not sys.maxsize > 2**32:
- py.test.raises(TypeError, lib.call1, ffi.addressof(lib, 'cb2'))
- py.test.raises(TypeError, ptr_call1, ffi.addressof(lib, 'cb2'))
- py.test.raises(TypeError, lib.call2, ffi.addressof(lib, 'cb1'))
- py.test.raises(TypeError, ptr_call2, ffi.addressof(lib, 'cb1'))
- assert lib.call1(ffi.addressof(lib, 'cb1')) == 500*999*2
- assert ptr_call1(ffi.addressof(lib, 'cb1')) == 500*999*2
- assert lib.call2(ffi.addressof(lib, 'cb2')) == -500*999*3
- assert ptr_call2(ffi.addressof(lib, 'cb2')) == -500*999*3
-
-def test_win32_calling_convention_3():
- ffi = FFI()
- ffi.cdef("""
- struct point { int x, y; };
-
- int (*const cb1)(struct point);
- int (__stdcall *const cb2)(struct point);
-
- struct point __stdcall call1(int(*cb)(struct point));
- struct point call2(int(__stdcall *cb)(struct point));
- """)
- lib = verify(ffi, 'test_win32_calling_convention_3', r"""
- #ifndef _MSC_VER
- # define __cdecl
- # define __stdcall
- #endif
- struct point { int x, y; };
- int cb1(struct point pt) { return pt.x + 10 * pt.y; }
- int __stdcall cb2(struct point pt) { return pt.x + 100 * pt.y; }
- struct point __stdcall call1(int(__cdecl *cb)(struct point)) {
- int i;
- struct point result = { 0, 0 };
- //printf("here1\n");
- //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
- for (i = 0; i < 1000; i++) {
- struct point p = { i, -i };
- int r = cb(p);
- result.x += r;
- result.y -= r;
- }
- return result;
- }
- struct point __cdecl call2(int(__stdcall *cb)(struct point)) {
- int i;
- struct point result = { 0, 0 };
- for (i = 0; i < 1000; i++) {
- struct point p = { -i, i };
- int r = cb(p);
- result.x += r;
- result.y -= r;
- }
- return result;
- }
- """)
- ptr_call1 = ffi.addressof(lib, 'call1')
- ptr_call2 = ffi.addressof(lib, 'call2')
- if sys.platform == 'win32' and not sys.maxsize > 2**32:
- py.test.raises(TypeError, lib.call1, ffi.addressof(lib, 'cb2'))
- py.test.raises(TypeError, ptr_call1, ffi.addressof(lib, 'cb2'))
- py.test.raises(TypeError, lib.call2, ffi.addressof(lib, 'cb1'))
- py.test.raises(TypeError, ptr_call2, ffi.addressof(lib, 'cb1'))
- pt = lib.call1(ffi.addressof(lib, 'cb1'))
- assert (pt.x, pt.y) == (-9*500*999, 9*500*999)
- pt = ptr_call1(ffi.addressof(lib, 'cb1'))
- assert (pt.x, pt.y) == (-9*500*999, 9*500*999)
- pt = lib.call2(ffi.addressof(lib, 'cb2'))
- assert (pt.x, pt.y) == (99*500*999, -99*500*999)
- pt = ptr_call2(ffi.addressof(lib, 'cb2'))
- assert (pt.x, pt.y) == (99*500*999, -99*500*999)
-
-def test_extern_python_1():
- import warnings
- ffi = FFI()
- with warnings.catch_warnings(record=True) as log:
- ffi.cdef("""
- extern "Python" {
- int bar(int, int);
- void baz(int, int);
- int bok(void);
- void boz(void);
- }
- """)
- assert len(log) == 0, "got a warning: %r" % (log,)
- lib = verify(ffi, 'test_extern_python_1', """
- static void baz(int, int); /* forward */
- """)
- assert ffi.typeof(lib.bar) == ffi.typeof("int(*)(int, int)")
- with FdWriteCapture() as f:
- res = lib.bar(4, 5)
- assert res == 0
- assert f.getvalue() == (
- b"extern \"Python\": function _CFFI_test_extern_python_1.bar() called, "
- b"but no code was attached "
- b"to it yet with @ffi.def_extern(). Returning 0.\n")
-
- @ffi.def_extern("bar")
- def my_bar(x, y):
- seen.append(("Bar", x, y))
- return x * y
- assert my_bar != lib.bar
- seen = []
- res = lib.bar(6, 7)
- assert seen == [("Bar", 6, 7)]
- assert res == 42
-
- def baz(x, y):
- seen.append(("Baz", x, y))
- baz1 = ffi.def_extern()(baz)
- assert baz1 is baz
- seen = []
- baz(long(40), long(4))
- res = lib.baz(long(50), long(8))
- assert res is None
- assert seen == [("Baz", 40, 4), ("Baz", 50, 8)]
- assert type(seen[0][1]) is type(seen[0][2]) is long
- assert type(seen[1][1]) is type(seen[1][2]) is int
-
- @ffi.def_extern(name="bok")
- def bokk():
- seen.append("Bok")
- return 42
- seen = []
- assert lib.bok() == 42
- assert seen == ["Bok"]
-
- @ffi.def_extern()
- def boz():
- seen.append("Boz")
- seen = []
- assert lib.boz() is None
- assert seen == ["Boz"]
-
-def test_extern_python_bogus_name():
- ffi = FFI()
- ffi.cdef("extern int abc;")
- lib = verify(ffi, 'test_extern_python_bogus_name', "int abc;")
- def fn():
- pass
- py.test.raises(ffi.error, ffi.def_extern("unknown_name"), fn)
- py.test.raises(ffi.error, ffi.def_extern("abc"), fn)
- assert lib.abc == 0
- e = py.test.raises(ffi.error, ffi.def_extern("abc"), fn)
- assert str(e.value) == ("ffi.def_extern('abc'): no 'extern \"Python\"' "
- "function with this name")
- e = py.test.raises(ffi.error, ffi.def_extern(), fn)
- assert str(e.value) == ("ffi.def_extern('fn'): no 'extern \"Python\"' "
- "function with this name")
- #
- py.test.raises(TypeError, ffi.def_extern(42), fn)
- py.test.raises((TypeError, AttributeError), ffi.def_extern(), "foo")
- class X:
- pass
- x = X()
- x.__name__ = x
- py.test.raises(TypeError, ffi.def_extern(), x)
-
-def test_extern_python_bogus_result_type():
- ffi = FFI()
- ffi.cdef("""extern "Python" void bar(int);""")
- lib = verify(ffi, 'test_extern_python_bogus_result_type', "")
- #
- @ffi.def_extern()
- def bar(n):
- return n * 10
- with StdErrCapture() as f:
- res = lib.bar(321)
- assert res is None
- msg = f.getvalue()
- assert "rom cffi callback %r" % (bar,) in msg
- assert "rying to convert the result back to C:\n" in msg
- assert msg.endswith(
- "TypeError: callback with the return type 'void' must return None\n")
-
-def test_extern_python_redefine():
- ffi = FFI()
- ffi.cdef("""extern "Python" int bar(int);""")
- lib = verify(ffi, 'test_extern_python_redefine', "")
- #
- @ffi.def_extern()
- def bar(n):
- return n * 10
- assert lib.bar(42) == 420
- #
- @ffi.def_extern()
- def bar(n):
- return -n
- assert lib.bar(42) == -42
-
-def test_extern_python_struct():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { int a, b, c; };
- extern "Python" int bar(int, struct foo_s, int);
- extern "Python" { struct foo_s baz(int, int);
- struct foo_s bok(void); }
- """)
- lib = verify(ffi, 'test_extern_python_struct',
- "struct foo_s { int a, b, c; };")
- #
- @ffi.def_extern()
- def bar(x, s, z):
- return x + s.a + s.b + s.c + z
- res = lib.bar(1000, [1001, 1002, 1004], 1008)
- assert res == 5015
- #
- @ffi.def_extern()
- def baz(x, y):
- return [x + y, x - y, x * y]
- res = lib.baz(1000, 42)
- assert res.a == 1042
- assert res.b == 958
- assert res.c == 42000
- #
- @ffi.def_extern()
- def bok():
- return [10, 20, 30]
- res = lib.bok()
- assert [res.a, res.b, res.c] == [10, 20, 30]
-
-def test_extern_python_long_double():
- ffi = FFI()
- ffi.cdef("""
- extern "Python" int bar(int, long double, int);
- extern "Python" long double baz(int, int);
- extern "Python" long double bok(void);
- """)
- lib = verify(ffi, 'test_extern_python_long_double', "")
- #
- @ffi.def_extern()
- def bar(x, l, z):
- seen.append((x, l, z))
- return 6
- seen = []
- lib.bar(10, 3.5, 20)
- expected = ffi.cast("long double", 3.5)
- assert repr(seen) == repr([(10, expected, 20)])
- #
- @ffi.def_extern()
- def baz(x, z):
- assert x == 10 and z == 20
- return expected
- res = lib.baz(10, 20)
- assert repr(res) == repr(expected)
- #
- @ffi.def_extern()
- def bok():
- return expected
- res = lib.bok()
- assert repr(res) == repr(expected)
-
-def test_extern_python_signature():
- ffi = FFI()
- lib = verify(ffi, 'test_extern_python_signature', "")
- py.test.raises(TypeError, ffi.def_extern(425), None)
- py.test.raises(TypeError, ffi.def_extern, 'a', 'b', 'c', 'd')
-
-def test_extern_python_errors():
- ffi = FFI()
- ffi.cdef("""
- extern "Python" int bar(int);
- """)
- lib = verify(ffi, 'test_extern_python_errors', "")
-
- seen = []
- def oops(*args):
- seen.append(args)
-
- @ffi.def_extern(onerror=oops)
- def bar(x):
- return x + ""
- assert lib.bar(10) == 0
-
- @ffi.def_extern(name="bar", onerror=oops, error=-66)
- def bar2(x):
- return x + ""
- assert lib.bar(10) == -66
-
- assert len(seen) == 2
- exc, val, tb = seen[0]
- assert exc is TypeError
- assert isinstance(val, TypeError)
- assert tb.tb_frame.f_code.co_name == "bar"
- exc, val, tb = seen[1]
- assert exc is TypeError
- assert isinstance(val, TypeError)
- assert tb.tb_frame.f_code.co_name == "bar2"
- #
- # a case where 'onerror' is not callable
- py.test.raises(TypeError, ffi.def_extern(name='bar', onerror=42),
- lambda x: x)
-
-def test_extern_python_stdcall():
- ffi = FFI()
- ffi.cdef("""
- extern "Python" int __stdcall foo(int);
- extern "Python" int WINAPI bar(int);
- static int (__stdcall * mycb1)(int);
- static int indirect_call(int);
- """)
- lib = verify(ffi, 'test_extern_python_stdcall', """
- #ifndef _MSC_VER
- # define __stdcall
- #endif
- static int (__stdcall * mycb1)(int);
- static int indirect_call(int x) {
- return mycb1(x);
- }
- """)
- #
- @ffi.def_extern()
- def foo(x):
- return x + 42
- @ffi.def_extern()
- def bar(x):
- return x + 43
- assert lib.foo(100) == 142
- assert lib.bar(100) == 143
- lib.mycb1 = lib.foo
- assert lib.mycb1(200) == 242
- assert lib.indirect_call(300) == 342
-
-def test_extern_python_plus_c():
- ffi = FFI()
- ffi.cdef("""
- extern "Python+C" int foo(int);
- extern "C +\tPython" int bar(int);
- int call_me(int);
- """)
- lib = verify(ffi, 'test_extern_python_plus_c', """
- int foo(int);
- #ifdef __GNUC__
- __attribute__((visibility("hidden")))
- #endif
- int bar(int);
-
- static int call_me(int x) {
- return foo(x) - bar(x);
- }
- """)
- #
- @ffi.def_extern()
- def foo(x):
- return x * 42
- @ffi.def_extern()
- def bar(x):
- return x * 63
- assert lib.foo(100) == 4200
- assert lib.bar(100) == 6300
- assert lib.call_me(100) == -2100
-
-def test_introspect_function():
- ffi = FFI()
- ffi.cdef("float f1(double);")
- lib = verify(ffi, 'test_introspect_function', """
- float f1(double x) { return (float)x; }
- """)
- assert dir(lib) == ['f1']
- FUNC = ffi.typeof(lib.f1)
- assert FUNC.kind == 'function'
- assert FUNC.args[0].cname == 'double'
- assert FUNC.result.cname == 'float'
- assert ffi.typeof(ffi.addressof(lib, 'f1')) is FUNC
-
-def test_introspect_global_var():
- ffi = FFI()
- ffi.cdef("extern float g1;")
- lib = verify(ffi, 'test_introspect_global_var', """
- float g1;
- """)
- assert dir(lib) == ['g1']
- FLOATPTR = ffi.typeof(ffi.addressof(lib, 'g1'))
- assert FLOATPTR.kind == 'pointer'
- assert FLOATPTR.item.cname == 'float'
-
-def test_introspect_global_var_array():
- ffi = FFI()
- ffi.cdef("extern float g1[100];")
- lib = verify(ffi, 'test_introspect_global_var_array', """
- float g1[100];
- """)
- assert dir(lib) == ['g1']
- FLOATARRAYPTR = ffi.typeof(ffi.addressof(lib, 'g1'))
- assert FLOATARRAYPTR.kind == 'pointer'
- assert FLOATARRAYPTR.item.kind == 'array'
- assert FLOATARRAYPTR.item.length == 100
- assert ffi.typeof(lib.g1) is FLOATARRAYPTR.item
-
-def test_introspect_integer_const():
- ffi = FFI()
- ffi.cdef("#define FOO 42")
- lib = verify(ffi, 'test_introspect_integer_const', """
- #define FOO 42
- """)
- assert dir(lib) == ['FOO']
- assert lib.FOO == ffi.integer_const('FOO') == 42
-
-def test_introspect_typedef():
- ffi = FFI()
- ffi.cdef("typedef int foo_t;")
- lib = verify(ffi, 'test_introspect_typedef', """
- typedef int foo_t;
- """)
- assert ffi.list_types() == (['foo_t'], [], [])
- assert ffi.typeof('foo_t').kind == 'primitive'
- assert ffi.typeof('foo_t').cname == 'int'
-
-def test_introspect_typedef_multiple():
- ffi = FFI()
- ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;")
- lib = verify(ffi, 'test_introspect_typedef_multiple', """
- typedef signed char a_t, c_t, g_t, b_t;
- """)
- assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'g_t'], [], [])
-
-def test_introspect_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a; };")
- lib = verify(ffi, 'test_introspect_struct', """
- struct foo_s { int a; };
- """)
- assert ffi.list_types() == ([], ['foo_s'], [])
- assert ffi.typeof('struct foo_s').kind == 'struct'
- assert ffi.typeof('struct foo_s').cname == 'struct foo_s'
-
-def test_introspect_union():
- ffi = FFI()
- ffi.cdef("union foo_s { int a; };")
- lib = verify(ffi, 'test_introspect_union', """
- union foo_s { int a; };
- """)
- assert ffi.list_types() == ([], [], ['foo_s'])
- assert ffi.typeof('union foo_s').kind == 'union'
- assert ffi.typeof('union foo_s').cname == 'union foo_s'
-
-def test_introspect_struct_and_typedef():
- ffi = FFI()
- ffi.cdef("typedef struct { int a; } foo_t;")
- lib = verify(ffi, 'test_introspect_struct_and_typedef', """
- typedef struct { int a; } foo_t;
- """)
- assert ffi.list_types() == (['foo_t'], [], [])
- assert ffi.typeof('foo_t').kind == 'struct'
- assert ffi.typeof('foo_t').cname == 'foo_t'
-
-def test_introspect_included_type():
- SOURCE = """
- typedef signed char schar_t;
- struct sint_t { int x; };
- """
- ffi1 = FFI()
- ffi1.cdef(SOURCE)
- ffi2 = FFI()
- ffi2.include(ffi1)
- verify(ffi1, "test_introspect_included_type_parent", SOURCE)
- verify(ffi2, "test_introspect_included_type", SOURCE)
- assert ffi1.list_types() == ffi2.list_types() == (
- ['schar_t'], ['sint_t'], [])
-
-def test_introspect_order():
- ffi = FFI()
- ffi.cdef("union CFFIaaa { int a; }; typedef struct CFFIccc { int a; } CFFIb;")
- ffi.cdef("union CFFIg { int a; }; typedef struct CFFIcc { int a; } CFFIbbb;")
- ffi.cdef("union CFFIaa { int a; }; typedef struct CFFIa { int a; } CFFIbb;")
- verify(ffi, "test_introspect_order", """
- union CFFIaaa { int a; }; typedef struct CFFIccc { int a; } CFFIb;
- union CFFIg { int a; }; typedef struct CFFIcc { int a; } CFFIbbb;
- union CFFIaa { int a; }; typedef struct CFFIa { int a; } CFFIbb;
- """)
- assert ffi.list_types() == (['CFFIb', 'CFFIbb', 'CFFIbbb'],
- ['CFFIa', 'CFFIcc', 'CFFIccc'],
- ['CFFIaa', 'CFFIaaa', 'CFFIg'])
-
-def test_bool_in_cpp():
- # this works when compiled as C, but in cffi < 1.7 it fails as C++
- ffi = FFI()
- ffi.cdef("bool f(void);")
- lib = verify(ffi, "test_bool_in_cpp", "char f(void) { return 2; }")
- assert lib.f() is True
-
-def test_bool_in_cpp_2():
- ffi = FFI()
- ffi.cdef('int add(int a, int b);')
- lib = verify(ffi, "test_bool_bug_cpp", '''
- typedef bool _Bool; /* there is a Windows header with this line */
- int add(int a, int b)
- {
- return a + b;
- }''', source_extension='.cpp')
- c = lib.add(2, 3)
- assert c == 5
-
-def test_struct_field_opaque():
- ffi = FFI()
- ffi.cdef("struct a { struct b b; };")
- e = py.test.raises(TypeError, verify,
- ffi, "test_struct_field_opaque", "?")
- assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
- " type (not declared in cdef())")
- ffi = FFI()
- ffi.cdef("struct a { struct b b[2]; };")
- e = py.test.raises(TypeError, verify,
- ffi, "test_struct_field_opaque", "?")
- assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
- " type (not declared in cdef())")
- ffi = FFI()
- ffi.cdef("struct a { struct b b[]; };")
- e = py.test.raises(TypeError, verify,
- ffi, "test_struct_field_opaque", "?")
- assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
- " type (not declared in cdef())")
-
-def test_function_arg_opaque():
- py.test.skip("can currently declare a function with an opaque struct "
- "as argument, but AFAICT it's impossible to call it later")
-
-def test_function_returns_opaque():
- ffi = FFI()
- ffi.cdef("struct a foo(int);")
- e = py.test.raises(TypeError, verify,
- ffi, "test_function_returns_opaque", "?")
- assert str(e.value) == ("function foo: 'struct a' is used as result type,"
- " but is opaque")
-
-def test_function_returns_union():
- ffi = FFI()
- ffi.cdef("union u1 { int a, b; }; union u1 f1(int);")
- lib = verify(ffi, "test_function_returns_union", """
- union u1 { int a, b; };
- static union u1 f1(int x) { union u1 u; u.b = x; return u; }
- """)
- assert lib.f1(51).a == 51
-
-def test_function_returns_partial_struct():
- ffi = FFI()
- ffi.cdef("struct aaa { int a; ...; }; struct aaa f1(int);")
- lib = verify(ffi, "test_function_returns_partial_struct", """
- struct aaa { int b, a, c; };
- static struct aaa f1(int x) { struct aaa s = {0}; s.a = x; return s; }
- """)
- assert lib.f1(52).a == 52
-
-def test_function_returns_float_complex():
- if sys.platform == 'win32':
- py.test.skip("MSVC may not support _Complex")
- ffi = FFI()
- ffi.cdef("float _Complex f1(float a, float b);");
- lib = verify(ffi, "test_function_returns_float_complex", """
- #include <complex.h>
- static float _Complex f1(float a, float b) { return a + I*2.0f*b; }
- """, no_cpp=True) # <complex.h> fails on some systems with C++
- result = lib.f1(1.25, 5.1)
- assert type(result) == complex
- assert result.real == 1.25 # exact
- assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact
-
-def test_function_returns_double_complex():
- if sys.platform == 'win32':
- py.test.skip("MSVC may not support _Complex")
- ffi = FFI()
- ffi.cdef("double _Complex f1(double a, double b);");
- lib = verify(ffi, "test_function_returns_double_complex", """
- #include <complex.h>
- static double _Complex f1(double a, double b) { return a + I*2.0*b; }
- """, no_cpp=True) # <complex.h> fails on some systems with C++
- result = lib.f1(1.25, 5.1)
- assert type(result) == complex
- assert result.real == 1.25 # exact
- assert result.imag == 2*5.1 # exact
-
-def test_function_argument_float_complex():
- if sys.platform == 'win32':
- py.test.skip("MSVC may not support _Complex")
- ffi = FFI()
- ffi.cdef("float f1(float _Complex x);");
- lib = verify(ffi, "test_function_argument_float_complex", """
- #include <complex.h>
- static float f1(float _Complex x) { return cabsf(x); }
- """, no_cpp=True) # <complex.h> fails on some systems with C++
- x = complex(12.34, 56.78)
- result = lib.f1(x)
- assert abs(result - abs(x)) < 1e-5
-
-def test_function_argument_double_complex():
- if sys.platform == 'win32':
- py.test.skip("MSVC may not support _Complex")
- ffi = FFI()
- ffi.cdef("double f1(double _Complex);");
- lib = verify(ffi, "test_function_argument_double_complex", """
- #include <complex.h>
- static double f1(double _Complex x) { return cabs(x); }
- """, no_cpp=True) # <complex.h> fails on some systems with C++
- x = complex(12.34, 56.78)
- result = lib.f1(x)
- assert abs(result - abs(x)) < 1e-11
-
-def test_typedef_array_dotdotdot():
- ffi = FFI()
- ffi.cdef("""
- typedef int foo_t[...], bar_t[...];
- extern int gv[...];
- typedef int mat_t[...][...];
- typedef int vmat_t[][...];
- """)
- lib = verify(ffi, "test_typedef_array_dotdotdot", """
- typedef int foo_t[50], bar_t[50];
- int gv[23];
- typedef int mat_t[6][7];
- typedef int vmat_t[][8];
- """)
- assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int")
- assert ffi.sizeof("bar_t") == 50 * ffi.sizeof("int")
- assert len(ffi.new("foo_t")) == 50
- assert len(ffi.new("bar_t")) == 50
- assert ffi.sizeof(lib.gv) == 23 * ffi.sizeof("int")
- assert ffi.sizeof("mat_t") == 6 * 7 * ffi.sizeof("int")
- assert len(ffi.new("mat_t")) == 6
- assert len(ffi.new("mat_t")[3]) == 7
- py.test.raises(ffi.error, ffi.sizeof, "vmat_t")
- p = ffi.new("vmat_t", 4)
- assert ffi.sizeof(p[3]) == 8 * ffi.sizeof("int")
-
-def test_typedef_array_dotdotdot_usage():
- ffi = FFI()
- ffi.cdef("""
- typedef int foo_t[...];
- typedef int mat_t[...][...];
- struct s { foo_t a; foo_t *b; foo_t **c; };
- int myfunc(foo_t a, foo_t *b, foo_t **c);
- struct sm { mat_t a; mat_t *b; mat_t **c; };
- int myfuncm(mat_t a, mat_t *b, mat_t **c);
- """)
- lib = verify(ffi, "test_typedef_array_dotdotdot_usage", """
- typedef int foo_t[50];
- typedef int mat_t[6][7];
- struct s { foo_t a; foo_t *b; foo_t **c; };
- static int myfunc(foo_t a, foo_t *b, foo_t **c) { return (**c)[49]; }
- struct sm { mat_t a; mat_t *b; mat_t **c; };
- static int myfuncm(mat_t a, mat_t *b, mat_t **c) { return (**c)[5][6]; }
- """)
- assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int")
- p = ffi.new("struct s *")
- assert ffi.sizeof(p[0]) == 50 * ffi.sizeof("int") + 2 * ffi.sizeof("void *")
- p.a[49] = 321
- p.b = ffi.addressof(p, 'a')
- p.c = ffi.addressof(p, 'b')
- assert lib.myfunc(ffi.NULL, ffi.NULL, p.c) == 321
- #
- assert ffi.sizeof("mat_t") == 42 * ffi.sizeof("int")
- p = ffi.new("struct sm *")
- assert ffi.sizeof(p[0]) == 42 * ffi.sizeof("int") + 2 * ffi.sizeof("void *")
- p.a[5][6] = -321
- p.b = ffi.addressof(p, 'a')
- p.c = ffi.addressof(p, 'b')
- assert lib.myfuncm(ffi.NULL, ffi.NULL, p.c) == -321
-
-def test_call_with_custom_field_pos():
- ffi = FFI()
- ffi.cdef("""
- struct foo { int x; ...; };
- struct foo f(void);
- struct foo g(int, ...);
- """)
- lib = verify(ffi, "test_call_with_custom_field_pos", """
- struct foo { int y, x; };
- struct foo f(void) {
- struct foo s = { 40, 200 };
- return s;
- }
- struct foo g(int a, ...) { return f(); }
- """)
- assert lib.f().x == 200
- e = py.test.raises(NotImplementedError, lib.g, 0)
- assert str(e.value) == (
- 'ctype \'struct foo\' not supported as return value. It is a '
- 'struct declared with "...;", but the C calling convention may '
- 'depend on the missing fields; or, it contains anonymous '
- 'struct/unions. Such structs are only supported '
- 'as return value if the function is \'API mode\' and non-variadic '
- '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() '
- 'and not taking a final \'...\' argument)')
-
-def test_call_with_nested_anonymous_struct():
- if sys.platform == 'win32':
- py.test.skip("needs a GCC extension")
- ffi = FFI()
- ffi.cdef("""
- struct foo { int a; union { int b, c; }; };
- struct foo f(void);
- struct foo g(int, ...);
- """)
- lib = verify(ffi, "test_call_with_nested_anonymous_struct", """
- struct foo { int a; union { int b, c; }; };
- struct foo f(void) {
- struct foo s;
- s.a = 40;
- s.b = 200;
- return s;
- }
- struct foo g(int a, ...) { return f(); }
- """)
- assert lib.f().b == 200
- e = py.test.raises(NotImplementedError, lib.g, 0)
- assert str(e.value) == (
- 'ctype \'struct foo\' not supported as return value. It is a '
- 'struct declared with "...;", but the C calling convention may '
- 'depend on the missing fields; or, it contains anonymous '
- 'struct/unions. Such structs are only supported '
- 'as return value if the function is \'API mode\' and non-variadic '
- '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() '
- 'and not taking a final \'...\' argument)')
-
-def test_call_with_bitfield():
- ffi = FFI()
- ffi.cdef("""
- struct foo { int x:5; };
- struct foo f(void);
- struct foo g(int, ...);
- """)
- lib = verify(ffi, "test_call_with_bitfield", """
- struct foo { int x:5; };
- struct foo f(void) {
- struct foo s = { 11 };
- return s;
- }
- struct foo g(int a, ...) { return f(); }
- """)
- assert lib.f().x == 11
- e = py.test.raises(NotImplementedError, lib.g, 0)
- assert str(e.value) == (
- "ctype 'struct foo' not supported as return value. It is a struct "
- "with bit fields, which libffi does not support. Such structs are "
- "only supported as return value if the function is 'API mode' and "
- "non-variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
- "set_source() and not taking a final '...' argument)")
-
-def test_call_with_zero_length_field():
- if sys.platform == 'win32':
- py.test.skip("zero-length field not supported by MSVC")
- ffi = FFI()
- ffi.cdef("""
- struct foo { int a; int x[0]; };
- struct foo f(void);
- struct foo g(int, ...);
- """)
- lib = verify(ffi, "test_call_with_zero_length_field", """
- struct foo { int a; int x[0]; };
- struct foo f(void) {
- struct foo s = { 42 };
- return s;
- }
- struct foo g(int a, ...) { return f(); }
- """)
- assert lib.f().a == 42
- e = py.test.raises(NotImplementedError, lib.g, 0)
- assert str(e.value) == (
- "ctype 'struct foo' not supported as return value. It is a "
- "struct with a zero-length array, which libffi does not support."
- " Such structs are only supported as return value if the function is "
- "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
- "+ffibuilder.set_source() and not taking a final '...' argument)")
-
-def test_call_with_union():
- ffi = FFI()
- ffi.cdef("""
- union foo { int a; char b; };
- union foo f(void);
- union foo g(int, ...);
- """)
- lib = verify(ffi, "test_call_with_union", """
- union foo { int a; char b; };
- union foo f(void) {
- union foo s = { 42 };
- return s;
- }
- union foo g(int a, ...) { return f(); }
- """)
- assert lib.f().a == 42
- e = py.test.raises(NotImplementedError, lib.g, 0)
- assert str(e.value) == (
- "ctype 'union foo' not supported as return value by libffi. "
- "Unions are only supported as return value if the function is "
- "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
- "+ffibuilder.set_source() and not taking a final '...' argument)")
-
-def test_call_with_packed_struct():
- if sys.platform == 'win32':
- py.test.skip("needs a GCC extension")
- ffi = FFI()
- ffi.cdef("""
- struct foo { char y; int x; };
- struct foo f(void);
- struct foo g(int, ...);
- """, packed=True)
- lib = verify(ffi, "test_call_with_packed_struct", """
- struct foo { char y; int x; } __attribute__((packed));
- struct foo f(void) {
- struct foo s = { 40, 200 };
- return s;
- }
- struct foo g(int a, ...) {
- struct foo s = { 41, 201 };
- return s;
- }
- """)
- assert ord(lib.f().y) == 40
- assert lib.f().x == 200
- e = py.test.raises(NotImplementedError, lib.g, 0)
- assert str(e.value) == (
- "ctype 'struct foo' not supported as return value. It is a "
- "'packed' structure, with a different layout than expected by libffi."
- " Such structs are only supported as return value if the function is "
- "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
- "+ffibuilder.set_source() and not taking a final '...' argument)")
-
-def test_pack_not_supported():
- ffi = FFI()
- ffi.cdef("""struct foo { char y; int x; };""", pack=2)
- py.test.raises(NotImplementedError, verify,
- ffi, "test_pack_not_supported", "")
-
-def test_gcc_visibility_hidden():
- if sys.platform == 'win32':
- py.test.skip("test for gcc/clang")
- ffi = FFI()
- ffi.cdef("""
- int f(int);
- """)
- lib = verify(ffi, "test_gcc_visibility_hidden", """
- int f(int a) { return a + 40; }
- """, extra_compile_args=['-fvisibility=hidden'])
- assert lib.f(2) == 42
-
-def test_override_default_definition():
- ffi = FFI()
- ffi.cdef("typedef long int16_t, char16_t;")
- lib = verify(ffi, "test_override_default_definition", "")
- assert ffi.typeof("int16_t") is ffi.typeof("char16_t") is ffi.typeof("long")
-
-def test_char16_char32_type(no_cpp=False):
- if no_cpp is False and sys.platform == "win32":
- py.test.skip("aaaaaaa why do modern MSVC compilers still define "
- "a very old __cplusplus value")
- ffi = FFI()
- ffi.cdef("""
- char16_t foo_2bytes(char16_t);
- char32_t foo_4bytes(char32_t);
- """)
- lib = verify(ffi, "test_char16_char32_type" + no_cpp * "_nocpp", """
- #if !defined(__cplusplus) || (!defined(_LIBCPP_VERSION) && __cplusplus < 201103L)
- typedef uint_least16_t char16_t;
- typedef uint_least32_t char32_t;
- #endif
-
- char16_t foo_2bytes(char16_t a) { return (char16_t)(a + 42); }
- char32_t foo_4bytes(char32_t a) { return (char32_t)(a + 42); }
- """, no_cpp=no_cpp)
- assert lib.foo_2bytes(u+'\u1234') == u+'\u125e'
- assert lib.foo_4bytes(u+'\u1234') == u+'\u125e'
- assert lib.foo_4bytes(u+'\U00012345') == u+'\U0001236f'
- py.test.raises(TypeError, lib.foo_2bytes, u+'\U00012345')
- py.test.raises(TypeError, lib.foo_2bytes, 1234)
- py.test.raises(TypeError, lib.foo_4bytes, 1234)
-
-def test_char16_char32_plain_c():
- test_char16_char32_type(no_cpp=True)
-
-def test_loader_spec():
- ffi = FFI()
- lib = verify(ffi, "test_loader_spec", "")
- if sys.version_info < (3,):
- assert not hasattr(lib, '__loader__')
- assert not hasattr(lib, '__spec__')
- else:
- assert lib.__loader__ is None
- assert lib.__spec__ is None
-
-def test_realize_struct_error():
- ffi = FFI()
- ffi.cdef("""typedef ... foo_t; struct foo_s { void (*x)(foo_t); };""")
- lib = verify(ffi, "test_realize_struct_error", """
- typedef int foo_t; struct foo_s { void (*x)(foo_t); };
- """)
- py.test.raises(TypeError, ffi.new, "struct foo_s *")
-
-def test_from_buffer_struct():
- ffi = FFI()
- ffi.cdef("""struct foo_s { int a, b; };""")
- lib = verify(ffi, "test_from_buffer_struct_p", """
- struct foo_s { int a, b; };
- """)
- p = ffi.new("struct foo_s *", [-219239, 58974983])
- q = ffi.from_buffer("struct foo_s[]", ffi.buffer(p))
- assert ffi.typeof(q) == ffi.typeof("struct foo_s[]")
- assert len(q) == 1
- assert q[0].a == p.a
- assert q[0].b == p.b
- assert q == p
- q = ffi.from_buffer("struct foo_s *", ffi.buffer(p))
- assert ffi.typeof(q) == ffi.typeof("struct foo_s *")
- assert q.a == p.a
- assert q.b == p.b
- assert q[0].a == p.a
- assert q[0].b == p.b
- assert q == p
-
-def test_unnamed_bitfield_1():
- ffi = FFI()
- ffi.cdef("""struct A { char : 1; };""")
- lib = verify(ffi, "test_unnamed_bitfield_1", """
- struct A { char : 1; };
- """)
- p = ffi.new("struct A *")
- assert ffi.sizeof(p[0]) == 1
- # Note: on gcc, the type name is ignored for anonymous bitfields
- # and that's why the result is 1. On MSVC, the result is
- # sizeof("char") which is also 1.
-
-def test_unnamed_bitfield_2():
- ffi = FFI()
- ffi.cdef("""struct A {
- short c : 1; short : 1; short d : 1; short : 1; };""")
- lib = verify(ffi, "test_unnamed_bitfield_2", """
- struct A {
- short c : 1; short : 1; short d : 1; short : 1;
- };
- """)
- p = ffi.new("struct A *")
- assert ffi.sizeof(p[0]) == ffi.sizeof("short")
-
-def test_unnamed_bitfield_3():
- ffi = FFI()
- ffi.cdef("""struct A { struct { char : 1; char : 1; } b; };""")
- lib = verify(ffi, "test_unnamed_bitfield_3", """
- struct A { struct { char : 1; char : 1; } b; };
- """)
- p = ffi.new("struct A *")
- assert ffi.sizeof(p[0]) == 1
- # Note: on gcc, the type name is ignored for anonymous bitfields
- # and that's why the result is 1. On MSVC, the result is
- # sizeof("char") which is also 1.
-
-def test_unnamed_bitfield_4():
- ffi = FFI()
- ffi.cdef("""struct A { struct {
- unsigned c : 1; unsigned : 1; unsigned d : 1; unsigned : 1; } a;
- };
- struct B { struct A a; };""")
- lib = verify(ffi, "test_unnamed_bitfield_4", """
- struct A { struct {
- unsigned c : 1; unsigned : 1; unsigned d : 1; unsigned : 1; } a;
- };
- struct B { struct A a; };
- """)
- b = ffi.new("struct B *")
- a = ffi.new("struct A *")
- assert ffi.sizeof(a[0]) == ffi.sizeof("unsigned")
- assert ffi.sizeof(b[0]) == ffi.sizeof(a[0])
-
-def test_struct_with_func_with_struct_pointer_arg():
- ffi = FFI()
- ffi.cdef("""struct BinaryTree {
- int (* CompareKey)(struct BinaryTree *tree);
- };""")
- lib = verify(ffi, "test_struct_with_func_with_struct_pointer_arg", """
- struct BinaryTree {
- int (* CompareKey)(struct BinaryTree *tree);
- };
- """)
- ffi.new("struct BinaryTree *")
-
-def test_struct_with_func_with_struct_arg():
- ffi = FFI()
- ffi.cdef("""struct BinaryTree {
- int (* CompareKey)(struct BinaryTree tree);
- };""")
- lib = verify(ffi, "test_struct_with_func_with_struct_arg", """
- struct BinaryTree {
- int (* CompareKey)(struct BinaryTree tree);
- };
- """)
- py.test.raises(RuntimeError, ffi.new, "struct BinaryTree *")
-
-def test_passing_large_list():
- ffi = FFI()
- ffi.cdef("""void passing_large_list(long[]);""")
- lib = verify(ffi, "test_passing_large_list", """
- static void passing_large_list(long a[]) { }
- """)
- arg = list(range(20000000))
- lib.passing_large_list(arg)
- # assert did not segfault
diff --git a/testing/cffi1/test_unicode_literals.py b/testing/cffi1/test_unicode_literals.py
deleted file mode 100644
index e9825db..0000000
--- a/testing/cffi1/test_unicode_literals.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# ----------------------------------------------
-# WARNING, ALL LITERALS IN THIS FILE ARE UNICODE
-# ----------------------------------------------
-#
-from __future__ import unicode_literals
-#
-#
-#
-from _cffi_backend import FFI
-
-
-def test_cast():
- ffi = FFI()
- assert int(ffi.cast("int", 3.14)) == 3 # unicode literal
-
-def test_new():
- ffi = FFI()
- assert ffi.new("int[]", [3, 4, 5])[2] == 5 # unicode literal
-
-def test_typeof():
- ffi = FFI()
- tp = ffi.typeof("int[51]") # unicode literal
- assert tp.length == 51
-
-def test_sizeof():
- ffi = FFI()
- assert ffi.sizeof("int[51]") == 51 * 4 # unicode literal
-
-def test_alignof():
- ffi = FFI()
- assert ffi.alignof("int[51]") == 4 # unicode literal
-
-def test_getctype():
- ffi = FFI()
- assert ffi.getctype("int**") == "int * *" # unicode literal
- assert type(ffi.getctype("int**")) is str
-
-def test_callback():
- ffi = FFI()
- cb = ffi.callback("int(int)", # unicode literal
- lambda x: x + 42)
- assert cb(5) == 47
diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py
deleted file mode 100644
index 33244cc..0000000
--- a/testing/cffi1/test_verify1.py
+++ /dev/null
@@ -1,2359 +0,0 @@
-import os, sys, math, py
-import pytest
-from cffi import FFI, FFIError, VerificationError, VerificationMissing, model
-from cffi import CDefError
-from cffi import recompiler
-from testing.support import *
-from testing.support import _verify, extra_compile_args
-import _cffi_backend
-
-lib_m = ['m']
-if sys.platform == 'win32':
- #there is a small chance this fails on Mingw via environ $CC
- import distutils.ccompiler
- if distutils.ccompiler.get_default_compiler() == 'msvc':
- lib_m = ['msvcrt']
-
-class FFI(FFI):
- error = _cffi_backend.FFI.error
- _extra_compile_args = extra_compile_args
- _verify_counter = 0
-
- def verify(self, preamble='', *args, **kwds):
- # HACK to reuse the tests from ../cffi0/test_verify.py
- FFI._verify_counter += 1
- module_name = 'verify%d' % FFI._verify_counter
- try:
- del self._assigned_source
- except AttributeError:
- pass
- self.set_source(module_name, preamble)
- return _verify(self, module_name, preamble, *args,
- extra_compile_args=self._extra_compile_args, **kwds)
-
-class FFI_warnings_not_error(FFI):
- _extra_compile_args = []
-
-
-def test_missing_function(ffi=None):
- # uses the FFI hacked above with '-Werror'
- if ffi is None:
- ffi = FFI()
- ffi.cdef("void some_completely_unknown_function();")
- try:
- lib = ffi.verify()
- except (VerificationError, OSError, ImportError):
- pass # expected case: we get a VerificationError
- else:
- # but depending on compiler and loader details, maybe
- # 'lib' could actually be imported but will fail if we
- # actually try to call the unknown function... Hard
- # to test anything more.
- pass
-
-def test_missing_function_import_error():
- # uses the original FFI that just gives a warning during compilation
- test_missing_function(ffi=FFI_warnings_not_error())
-
-def test_simple_case():
- ffi = FFI()
- ffi.cdef("double sin(double x);")
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- assert lib.sin(1.23) == math.sin(1.23)
-
-def _Wconversion(cdef, source, **kargs):
- if sys.platform in ('win32', 'darwin'):
- py.test.skip("needs GCC")
- ffi = FFI()
- ffi.cdef(cdef)
- py.test.raises(VerificationError, ffi.verify, source, **kargs)
- extra_compile_args_orig = extra_compile_args[:]
- extra_compile_args.remove('-Wconversion')
- try:
- lib = ffi.verify(source, **kargs)
- finally:
- extra_compile_args[:] = extra_compile_args_orig
- return lib
-
-def test_Wconversion_unsigned():
- _Wconversion("unsigned foo(void);",
- "int foo(void) { return -1;}")
-
-def test_Wconversion_integer():
- _Wconversion("short foo(void);",
- "long long foo(void) { return 1<<sizeof(short);}")
-
-def test_Wconversion_floating():
- lib = _Wconversion("float sin(double);",
- "#include <math.h>", libraries=lib_m)
- res = lib.sin(1.23)
- assert res != math.sin(1.23) # not exact, because of double->float
- assert abs(res - math.sin(1.23)) < 1E-5
-
-def test_Wconversion_float2int():
- _Wconversion("int sinf(float);",
- "#include <math.h>", libraries=lib_m)
-
-def test_Wconversion_double2int():
- _Wconversion("int sin(double);",
- "#include <math.h>", libraries=lib_m)
-
-def test_rounding_1():
- ffi = FFI()
- ffi.cdef("double sinf(float x);")
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- res = lib.sinf(1.23)
- assert res != math.sin(1.23) # not exact, because of double->float
- assert abs(res - math.sin(1.23)) < 1E-5
-
-def test_rounding_2():
- ffi = FFI()
- ffi.cdef("double sin(float x);")
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- res = lib.sin(1.23)
- assert res != math.sin(1.23) # not exact, because of double->float
- assert abs(res - math.sin(1.23)) < 1E-5
-
-def test_strlen_exact():
- ffi = FFI()
- ffi.cdef("size_t strlen(const char *s);")
- lib = ffi.verify("#include <string.h>")
- assert lib.strlen(b"hi there!") == 9
-
-def test_strlen_approximate():
- lib = _Wconversion("int strlen(char *s);",
- "#include <string.h>")
- assert lib.strlen(b"hi there!") == 9
-
-def test_return_approximate():
- for typename in ['short', 'int', 'long', 'long long']:
- ffi = FFI()
- ffi.cdef("%s foo(signed char x);" % typename)
- lib = ffi.verify("signed char foo(signed char x) { return x;}")
- assert lib.foo(-128) == -128
- assert lib.foo(+127) == +127
-
-def test_strlen_array_of_char():
- ffi = FFI()
- ffi.cdef("size_t strlen(char[]);")
- lib = ffi.verify("#include <string.h>")
- assert lib.strlen(b"hello") == 5
-
-def test_longdouble():
- ffi = FFI()
- ffi.cdef("long double sinl(long double x);")
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- for input in [1.23,
- ffi.cast("double", 1.23),
- ffi.cast("long double", 1.23)]:
- x = lib.sinl(input)
- assert repr(x).startswith("<cdata 'long double'")
- assert (float(x) - math.sin(1.23)) < 1E-10
-
-def test_longdouble_precision():
- # Test that we don't loose any precision of 'long double' when
- # passing through Python and CFFI.
- ffi = FFI()
- ffi.cdef("long double step1(long double x);")
- SAME_SIZE = ffi.sizeof("long double") == ffi.sizeof("double")
- lib = ffi.verify("""
- long double step1(long double x)
- {
- return 4*x-x*x;
- }
- """)
- def do(cast_to_double):
- x = 0.9789
- for i in range(10000):
- x = lib.step1(x)
- if cast_to_double:
- x = float(x)
- return float(x)
-
- more_precise = do(False)
- less_precise = do(True)
- if SAME_SIZE:
- assert more_precise == less_precise
- else:
- assert abs(more_precise - less_precise) > 0.1
- # Check the particular results on Intel
- import platform
- if (platform.machine().startswith('i386') or
- platform.machine().startswith('i486') or
- platform.machine().startswith('i586') or
- platform.machine().startswith('i686') or
- platform.machine().startswith('x86')):
- assert abs(more_precise - 0.656769) < 0.001
- assert abs(less_precise - 3.99091) < 0.001
- else:
- py.test.skip("don't know the very exact precision of 'long double'")
-
-
-all_primitive_types = model.PrimitiveType.ALL_PRIMITIVE_TYPES
-if sys.platform == 'win32':
- all_primitive_types = all_primitive_types.copy()
- del all_primitive_types['ssize_t']
-all_integer_types = sorted(tp for tp in all_primitive_types
- if all_primitive_types[tp] == 'i')
-all_float_types = sorted(tp for tp in all_primitive_types
- if all_primitive_types[tp] == 'f')
-
-def all_signed_integer_types(ffi):
- return [x for x in all_integer_types if int(ffi.cast(x, -1)) < 0]
-
-def all_unsigned_integer_types(ffi):
- return [x for x in all_integer_types if int(ffi.cast(x, -1)) > 0]
-
-
-def test_primitive_category():
- for typename in all_primitive_types:
- tp = model.PrimitiveType(typename)
- C = tp.is_char_type()
- F = tp.is_float_type()
- X = tp.is_complex_type()
- I = tp.is_integer_type()
- assert C == (typename in ('char', 'wchar_t', 'char16_t', 'char32_t'))
- assert F == (typename in ('float', 'double', 'long double'))
- assert X == (typename in ('float _Complex', 'double _Complex'))
- assert I + F + C + X == 1 # one and only one of them is true
-
-def test_all_integer_and_float_types():
- typenames = []
- for typename in all_primitive_types:
- if (all_primitive_types[typename] == 'c' or
- all_primitive_types[typename] == 'j' or # complex
- typename == '_Bool' or typename == 'long double'):
- pass
- else:
- typenames.append(typename)
- #
- ffi = FFI()
- ffi.cdef('\n'.join(["%s foo_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
- for tp in typenames]))
- lib = ffi.verify('\n'.join(["%s foo_%s(%s x) { return (%s)(x+1); }" %
- (tp, tp.replace(' ', '_'), tp, tp)
- for tp in typenames]))
- for typename in typenames:
- foo = getattr(lib, 'foo_%s' % typename.replace(' ', '_'))
- assert foo(42) == 43
- if sys.version < '3':
- assert foo(long(44)) == 45
- assert foo(ffi.cast(typename, 46)) == 47
- py.test.raises(TypeError, foo, ffi.NULL)
- #
- # check for overflow cases
- if all_primitive_types[typename] == 'f':
- continue
- for value in [-2**80, -2**40, -2**20, -2**10, -2**5, -1,
- 2**5, 2**10, 2**20, 2**40, 2**80]:
- overflows = int(ffi.cast(typename, value)) != value
- if overflows:
- py.test.raises(OverflowError, foo, value)
- else:
- assert foo(value) == value + 1
-
-def test_var_signed_integer_types():
- ffi = FFI()
- lst = all_signed_integer_types(ffi)
- csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
- for tp in lst])
- ffi.cdef(csource)
- lib = ffi.verify(csource)
- for tp in lst:
- varname = 'somevar_%s' % tp.replace(' ', '_')
- sz = ffi.sizeof(tp)
- max = (1 << (8*sz-1)) - 1
- min = -(1 << (8*sz-1))
- setattr(lib, varname, max)
- assert getattr(lib, varname) == max
- setattr(lib, varname, min)
- assert getattr(lib, varname) == min
- py.test.raises(OverflowError, setattr, lib, varname, max+1)
- py.test.raises(OverflowError, setattr, lib, varname, min-1)
-
-def test_var_unsigned_integer_types():
- ffi = FFI()
- lst = all_unsigned_integer_types(ffi)
- csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
- for tp in lst])
- ffi.cdef(csource)
- lib = ffi.verify(csource)
- for tp in lst:
- varname = 'somevar_%s' % tp.replace(' ', '_')
- sz = ffi.sizeof(tp)
- if tp != '_Bool':
- max = (1 << (8*sz)) - 1
- else:
- max = 1
- setattr(lib, varname, max)
- assert getattr(lib, varname) == max
- setattr(lib, varname, 0)
- assert getattr(lib, varname) == 0
- py.test.raises(OverflowError, setattr, lib, varname, max+1)
- py.test.raises(OverflowError, setattr, lib, varname, -1)
-
-def test_fn_signed_integer_types():
- ffi = FFI()
- lst = all_signed_integer_types(ffi)
- cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
- for tp in lst])
- ffi.cdef(cdefsrc)
- verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
- (tp, tp.replace(' ', '_'), tp) for tp in lst])
- lib = ffi.verify(verifysrc)
- for tp in lst:
- fnname = 'somefn_%s' % tp.replace(' ', '_')
- sz = ffi.sizeof(tp)
- max = (1 << (8*sz-1)) - 1
- min = -(1 << (8*sz-1))
- fn = getattr(lib, fnname)
- assert fn(max) == max
- assert fn(min) == min
- py.test.raises(OverflowError, fn, max + 1)
- py.test.raises(OverflowError, fn, min - 1)
-
-def test_fn_unsigned_integer_types():
- ffi = FFI()
- lst = all_unsigned_integer_types(ffi)
- cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
- for tp in lst])
- ffi.cdef(cdefsrc)
- verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
- (tp, tp.replace(' ', '_'), tp) for tp in lst])
- lib = ffi.verify(verifysrc)
- for tp in lst:
- fnname = 'somefn_%s' % tp.replace(' ', '_')
- sz = ffi.sizeof(tp)
- if tp != '_Bool':
- max = (1 << (8*sz)) - 1
- else:
- max = 1
- fn = getattr(lib, fnname)
- assert fn(max) == max
- assert fn(0) == 0
- py.test.raises(OverflowError, fn, max + 1)
- py.test.raises(OverflowError, fn, -1)
-
-def test_char_type():
- ffi = FFI()
- ffi.cdef("char foo(char);")
- lib = ffi.verify("char foo(char x) { return ++x; }")
- assert lib.foo(b"A") == b"B"
- py.test.raises(TypeError, lib.foo, b"bar")
- py.test.raises(TypeError, lib.foo, "bar")
-
-def test_wchar_type():
- ffi = FFI()
- if ffi.sizeof('wchar_t') == 2:
- uniexample1 = u+'\u1234'
- uniexample2 = u+'\u1235'
- else:
- uniexample1 = u+'\U00012345'
- uniexample2 = u+'\U00012346'
- #
- ffi.cdef("wchar_t foo(wchar_t);")
- lib = ffi.verify("wchar_t foo(wchar_t x) { return x+1; }")
- assert lib.foo(uniexample1) == uniexample2
-
-def test_no_argument():
- ffi = FFI()
- ffi.cdef("int foo(void);")
- lib = ffi.verify("int foo(void) { return 42; }")
- assert lib.foo() == 42
-
-def test_two_arguments():
- ffi = FFI()
- ffi.cdef("int foo(int, int);")
- lib = ffi.verify("int foo(int a, int b) { return a - b; }")
- assert lib.foo(40, -2) == 42
-
-def test_macro():
- ffi = FFI()
- ffi.cdef("int foo(int, int);")
- lib = ffi.verify("#define foo(a, b) ((a) * (b))")
- assert lib.foo(-6, -7) == 42
-
-def test_ptr():
- ffi = FFI()
- ffi.cdef("int *foo(int *);")
- lib = ffi.verify("int *foo(int *a) { return a; }")
- assert lib.foo(ffi.NULL) == ffi.NULL
- p = ffi.new("int *", 42)
- q = ffi.new("int *", 42)
- assert lib.foo(p) == p
- assert lib.foo(q) != p
-
-def test_bogus_ptr():
- ffi = FFI()
- ffi.cdef("int *foo(int *);")
- lib = ffi.verify("int *foo(int *a) { return a; }")
- py.test.raises(TypeError, lib.foo, ffi.new("short *", 42))
-
-
-def test_verify_typedefs():
- py.test.skip("ignored so far")
- types = ['signed char', 'unsigned char', 'int', 'long']
- for cdefed in types:
- for real in types:
- ffi = FFI()
- ffi.cdef("typedef %s foo_t;" % cdefed)
- if cdefed == real:
- ffi.verify("typedef %s foo_t;" % real)
- else:
- py.test.raises(VerificationError, ffi.verify,
- "typedef %s foo_t;" % real)
-
-def test_nondecl_struct():
- ffi = FFI()
- ffi.cdef("typedef struct foo_s foo_t; int bar(foo_t *);")
- lib = ffi.verify("typedef struct foo_s foo_t;\n"
- "int bar(foo_t *f) { (void)f; return 42; }\n")
- assert lib.bar(ffi.NULL) == 42
-
-def test_ffi_full_struct():
- def check(verified_code):
- ffi = FFI()
- ffi.cdef("struct foo_s { char x; int y; long *z; };")
- ffi.verify(verified_code)
- ffi.new("struct foo_s *", {})
-
- check("struct foo_s { char x; int y; long *z; };")
- #
- if sys.platform != 'win32': # XXX fixme: only gives warnings
- py.test.raises(VerificationError, check,
- "struct foo_s { char x; int y; int *z; };")
- #
- py.test.raises(VerificationError, check,
- "struct foo_s { int y; long *z; };") # cdef'ed field x is missing
- #
- e = py.test.raises(FFI.error, check,
- "struct foo_s { int y; char x; long *z; };")
- assert str(e.value).startswith(
- "struct foo_s: wrong offset for field 'x'"
- " (cdef says 0, but C compiler says 4)")
- #
- e = py.test.raises(FFI.error, check,
- "struct foo_s { char x; int y; long *z; char extra; };")
- assert str(e.value).startswith(
- "struct foo_s: wrong total size"
- " (cdef says %d, but C compiler says %d)" % (
- 8 + FFI().sizeof('long *'),
- 8 + FFI().sizeof('long *') * 2))
- #
- # a corner case that we cannot really detect, but where it has no
- # bad consequences: the size is the same, but there is an extra field
- # that replaces what is just padding in our declaration above
- check("struct foo_s { char x, extra; int y; long *z; };")
- #
- e = py.test.raises(FFI.error, check,
- "struct foo_s { char x; short pad; short y; long *z; };")
- assert str(e.value).startswith(
- "struct foo_s: wrong size for field 'y'"
- " (cdef says 4, but C compiler says 2)")
-
-def test_ffi_nonfull_struct():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s {
- int x;
- ...;
- };
- """)
- py.test.raises(VerificationMissing, ffi.sizeof, 'struct foo_s')
- py.test.raises(VerificationMissing, ffi.offsetof, 'struct foo_s', 'x')
- py.test.raises(VerificationMissing, ffi.new, 'struct foo_s *')
- ffi.verify("""
- struct foo_s {
- int a, b, x, c, d, e;
- };
- """)
- assert ffi.sizeof('struct foo_s') == 6 * ffi.sizeof('int')
- assert ffi.offsetof('struct foo_s', 'x') == 2 * ffi.sizeof('int')
-
-def test_ffi_nonfull_alignment():
- ffi = FFI()
- ffi.cdef("struct foo_s { char x; ...; };")
- ffi.verify("struct foo_s { int a, b; char x; };")
- assert ffi.sizeof('struct foo_s') == 3 * ffi.sizeof('int')
- assert ffi.alignof('struct foo_s') == ffi.sizeof('int')
-
-def _check_field_match(typename, real, expect_mismatch):
- ffi = FFI()
- testing_by_size = (expect_mismatch == 'by_size')
- if testing_by_size:
- expect_mismatch = ffi.sizeof(typename) != ffi.sizeof(real)
- ffi.cdef("struct foo_s { %s x; ...; };" % typename)
- try:
- ffi.verify("struct foo_s { %s x; };" % real)
- ffi.new("struct foo_s *", []) # because some mismatches show up lazily
- except (VerificationError, ffi.error):
- if not expect_mismatch:
- if testing_by_size and typename != real:
- print("ignoring mismatch between %s* and %s* even though "
- "they have the same size" % (typename, real))
- return
- raise AssertionError("unexpected mismatch: %s should be accepted "
- "as equal to %s" % (typename, real))
- else:
- if expect_mismatch:
- raise AssertionError("mismatch not detected: "
- "%s != %s" % (typename, real))
-
-def test_struct_bad_sized_integer():
- for typename in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
- for real in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
- _check_field_match(typename, real, "by_size")
-
-def test_struct_bad_sized_float():
- for typename in all_float_types:
- for real in all_float_types:
- _check_field_match(typename, real, "by_size")
-
-def test_struct_signedness_ignored():
- _check_field_match("int", "unsigned int", expect_mismatch=False)
- _check_field_match("unsigned short", "signed short", expect_mismatch=False)
-
-def test_struct_float_vs_int():
- if sys.platform == 'win32':
- py.test.skip("XXX fixme: only gives warnings")
- ffi = FFI()
- for typename in all_signed_integer_types(ffi):
- for real in all_float_types:
- _check_field_match(typename, real, expect_mismatch=True)
- for typename in all_float_types:
- for real in all_signed_integer_types(ffi):
- _check_field_match(typename, real, expect_mismatch=True)
-
-def test_struct_array_field():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[17]; ...; };")
- ffi.verify("struct foo_s { int x; int a[17]; int y; };")
- assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
-
-def test_struct_array_no_length():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[]; int y; ...; };\n"
- "int bar(struct foo_s *);\n")
- lib = ffi.verify("struct foo_s { int x; int a[17]; int y; };\n"
- "int bar(struct foo_s *f) { return f->a[14]; }\n")
- assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *")
- assert ffi.typeof(s.a) is ffi.typeof('int[]') # implicit max length
- assert len(s.a) == 18 # max length, computed from the size and start offset
- s.a[14] = 4242
- assert lib.bar(s) == 4242
- # with no declared length, out-of-bound accesses are not detected
- s.a[17] = -521
- assert s.y == s.a[17] == -521
- #
- s = ffi.new("struct foo_s *", {'a': list(range(17))})
- assert s.a[16] == 16
- # overflows at construction time not detected either
- s = ffi.new("struct foo_s *", {'a': list(range(18))})
- assert s.y == s.a[17] == 17
-
-def test_struct_array_guess_length():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a[...]; };")
- ffi.verify("struct foo_s { int x; int a[17]; int y; };")
- assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
- with pytest.raises(IndexError):
- s.a[17]
-
-def test_struct_array_c99_1():
- if sys.platform == 'win32':
- py.test.skip("requires C99")
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; int a[]; };")
- ffi.verify("struct foo_s { int x; int a[]; };")
- assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *", [424242, 4])
- assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
- assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
- # ^^^ explanation: if you write in C: "char x[5];", then
- # "sizeof(x)" will evaluate to 5. The behavior above is
- # a generalization of that to "struct foo_s[len(a)=5] x;"
- # if you could do that in C.
- assert s.a[3] == 0
- s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
- assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
- assert s.a[3] == -10
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *", [424242])
- assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
-
-def test_struct_array_c99_2():
- if sys.platform == 'win32':
- py.test.skip("requires C99")
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; int a[]; ...; };")
- ffi.verify("struct foo_s { int x, y; int a[]; };")
- assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *", [424242, 4])
- assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
- assert s.a[3] == 0
- s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
- assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
- assert s.a[3] == -10
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
- s = ffi.new("struct foo_s *", [424242])
- assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
-
-def test_struct_ptr_to_array_field():
- ffi = FFI()
- ffi.cdef("struct foo_s { int (*a)[17]; ...; }; struct bar_s { ...; };")
- ffi.verify("struct foo_s { int x; int (*a)[17]; int y; };\n"
- "struct bar_s { int x; int *a; int y; };")
- assert ffi.sizeof('struct foo_s') == ffi.sizeof("struct bar_s")
- s = ffi.new("struct foo_s *")
- assert ffi.sizeof(s.a) == ffi.sizeof('int(*)[17]') == ffi.sizeof("int *")
-
-def test_struct_with_bitfield_exact():
- ffi = FFI()
- ffi.cdef("struct foo_s { int a:2, b:3; };")
- ffi.verify("struct foo_s { int a:2, b:3; };")
- s = ffi.new("struct foo_s *")
- s.b = 3
- with pytest.raises(OverflowError):
- s.b = 4
- assert s.b == 3
-
-def test_struct_with_bitfield_enum():
- ffi = FFI()
- code = """
- typedef enum { AA, BB, CC } foo_e;
- typedef struct { foo_e f:2; } foo_s;
- """
- ffi.cdef(code)
- ffi.verify(code)
- s = ffi.new("foo_s *")
- s.f = 1
- assert s.f == 1
- if int(ffi.cast("foo_e", -1)) < 0:
- two = -2
- else:
- two = 2
- s.f = two
- assert s.f == two
-
-def test_unsupported_struct_with_bitfield_ellipsis():
- ffi = FFI()
- py.test.raises(NotImplementedError, ffi.cdef,
- "struct foo_s { int a:2, b:3; ...; };")
-
-def test_global_constants():
- ffi = FFI()
- # use 'static const int', as generally documented, although in this
- # case the 'static' is completely ignored.
- ffi.cdef("static const int AA, BB, CC, DD;")
- lib = ffi.verify("#define AA 42\n"
- "#define BB (-43) // blah\n"
- "#define CC (22*2) /* foobar */\n"
- "#define DD ((unsigned int)142) /* foo\nbar */\n")
- assert lib.AA == 42
- assert lib.BB == -43
- assert lib.CC == 44
- assert lib.DD == 142
-
-def test_global_const_int_size():
- # integer constants: ignore the declared type, always just use the value
- for value in [-2**63, -2**31, -2**15,
- 2**15-1, 2**15, 2**31-1, 2**31, 2**32-1, 2**32,
- 2**63-1, 2**63, 2**64-1]:
- ffi = FFI()
- if value == int(ffi.cast("long long", value)):
- if value < 0:
- vstr = '(-%dLL-1)' % (~value,)
- else:
- vstr = '%dLL' % value
- elif value == int(ffi.cast("unsigned long long", value)):
- vstr = '%dULL' % value
- else:
- raise AssertionError(value)
- ffi.cdef("static const unsigned short AA;")
- lib = ffi.verify("#define AA %s\n" % vstr)
- assert lib.AA == value
- assert type(lib.AA) is type(int(lib.AA))
-
-def test_global_constants_non_int():
- ffi = FFI()
- ffi.cdef("static char *const PP;")
- lib = ffi.verify('static char *const PP = "testing!";\n')
- assert ffi.typeof(lib.PP) == ffi.typeof("char *")
- assert ffi.string(lib.PP) == b"testing!"
-
-def test_nonfull_enum():
- ffi = FFI()
- ffi.cdef("enum ee { EE1, EE2, EE3, ... \n \t };")
- py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE2')
- ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
- assert ffi.string(ffi.cast('enum ee', 11)) == "EE2"
- assert ffi.string(ffi.cast('enum ee', -10)) == "EE3"
- #
- assert ffi.typeof("enum ee").relements == {'EE1': 10, 'EE2': 11, 'EE3': -10}
- assert ffi.typeof("enum ee").elements == {10: 'EE1', 11: 'EE2', -10: 'EE3'}
-
-def test_full_enum():
- ffi = FFI()
- ffi.cdef("enum ee { EE1, EE2, EE3 };")
- lib = ffi.verify("enum ee { EE1, EE2, EE3 };")
- assert [lib.EE1, lib.EE2, lib.EE3] == [0, 1, 2]
-
-def test_enum_usage():
- ffi = FFI()
- ffi.cdef("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;")
- lib = ffi.verify("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;")
- assert lib.EE2 == 1
- s = ffi.new("sp", [lib.EE2])
- assert s.x == 1
- s.x = 17
- assert s.x == 17
-
-def test_anonymous_enum():
- ffi = FFI()
- ffi.cdef("enum { EE1 }; enum { EE2, EE3 };")
- lib = ffi.verify("enum { EE1 }; enum { EE2, EE3 };")
- assert lib.EE1 == 0
- assert lib.EE2 == 0
- assert lib.EE3 == 1
-
-def test_nonfull_anonymous_enum():
- ffi = FFI()
- ffi.cdef("enum { EE1, ... }; enum { EE3, ... };")
- lib = ffi.verify("enum { EE2, EE1 }; enum { EE3 };")
- assert lib.EE1 == 1
- assert lib.EE3 == 0
-
-def test_nonfull_enum_syntax2():
- ffi = FFI()
- ffi.cdef("enum ee { EE1, EE2=\t..., EE3 };")
- py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1')
- ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
- assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2'
- assert ffi.string(ffi.cast('enum ee', -10)) == 'EE3'
- #
- ffi = FFI()
- ffi.cdef("enum ee { EE1, EE2=\t... };")
- py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1')
- ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
- assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2'
- #
- ffi = FFI()
- ffi.cdef("enum ee2 { EE4=..., EE5=..., ... };")
- ffi.verify("enum ee2 { EE4=-1234-5, EE5 }; ")
- assert ffi.string(ffi.cast('enum ee2', -1239)) == 'EE4'
- assert ffi.string(ffi.cast('enum ee2', -1238)) == 'EE5'
-
-def test_get_set_errno():
- ffi = FFI()
- ffi.cdef("int foo(int);")
- lib = ffi.verify("""
- static int foo(int x)
- {
- errno += 1;
- return x * 7;
- }
- """)
- ffi.errno = 15
- assert lib.foo(6) == 42
- assert ffi.errno == 16
-
-def test_define_int():
- ffi = FFI()
- ffi.cdef("#define FOO ...\n"
- "\t#\tdefine\tBAR\t...\t\n"
- "#define BAZ ...\n")
- lib = ffi.verify("#define FOO 42\n"
- "#define BAR (-44)\n"
- "#define BAZ 0xffffffffffffffffULL\n")
- assert lib.FOO == 42
- assert lib.BAR == -44
- assert lib.BAZ == 0xffffffffffffffff
-
-def test_access_variable():
- ffi = FFI()
- ffi.cdef("static int foo(void);\n"
- "static int somenumber;")
- lib = ffi.verify("""
- static int somenumber = 2;
- static int foo(void) {
- return somenumber * 7;
- }
- """)
- assert lib.somenumber == 2
- assert lib.foo() == 14
- lib.somenumber = -6
- assert lib.foo() == -42
- assert lib.somenumber == -6
- lib.somenumber = 2 # reset for the next run, if any
-
-def test_access_address_of_variable():
- # access the address of 'somenumber': need a trick
- ffi = FFI()
- ffi.cdef("static int somenumber; static int *const somenumberptr;")
- lib = ffi.verify("""
- static int somenumber = 2;
- #define somenumberptr (&somenumber)
- """)
- assert lib.somenumber == 2
- lib.somenumberptr[0] = 42
- assert lib.somenumber == 42
- lib.somenumber = 2 # reset for the next run, if any
-
-def test_access_array_variable(length=5):
- ffi = FFI()
- ffi.cdef("static int foo(int);\n"
- "static int somenumber[%s];" % (length,))
- lib = ffi.verify("""
- static int somenumber[] = {2, 2, 3, 4, 5};
- static int foo(int i) {
- return somenumber[i] * 7;
- }
- """)
- if length == '':
- # a global variable of an unknown array length is implicitly
- # transformed into a global pointer variable, because we can only
- # work with array instances whose length we know. using a pointer
- # instead of an array gives the correct effects.
- assert repr(lib.somenumber).startswith("<cdata 'int *' 0x")
- py.test.raises(TypeError, len, lib.somenumber)
- else:
- assert repr(lib.somenumber).startswith("<cdata 'int[%s]' 0x" % length)
- assert len(lib.somenumber) == 5
- assert lib.somenumber[3] == 4
- assert lib.foo(3) == 28
- lib.somenumber[3] = -6
- assert lib.foo(3) == -42
- assert lib.somenumber[3] == -6
- assert lib.somenumber[4] == 5
- lib.somenumber[3] = 4 # reset for the next run, if any
-
-def test_access_array_variable_length_hidden():
- test_access_array_variable(length='')
-
-def test_access_struct_variable():
- ffi = FFI()
- ffi.cdef("struct foo { int x; ...; };\n"
- "static int foo(int);\n"
- "static struct foo stuff;")
- lib = ffi.verify("""
- struct foo { int x, y, z; };
- static struct foo stuff = {2, 5, 8};
- static int foo(int i) {
- switch (i) {
- case 0: return stuff.x * 7;
- case 1: return stuff.y * 7;
- case 2: return stuff.z * 7;
- }
- return -1;
- }
- """)
- assert lib.stuff.x == 2
- assert lib.foo(0) == 14
- assert lib.foo(1) == 35
- assert lib.foo(2) == 56
- lib.stuff.x = -6
- assert lib.foo(0) == -42
- assert lib.foo(1) == 35
- lib.stuff.x = 2 # reset for the next run, if any
-
-def test_access_callback():
- ffi = FFI()
- ffi.cdef("static int (*cb)(int);\n"
- "static int foo(int);\n"
- "static void reset_cb(void);")
- lib = ffi.verify("""
- static int g(int x) { return x * 7; }
- static int (*cb)(int);
- static int foo(int i) { return cb(i) - 1; }
- static void reset_cb(void) { cb = g; }
- """)
- lib.reset_cb()
- assert lib.foo(6) == 41
- my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
- lib.cb = my_callback
- assert lib.foo(4) == 887
-
-def test_access_callback_function_typedef():
- ffi = FFI()
- ffi.cdef("typedef int mycallback_t(int);\n"
- "static mycallback_t *cb;\n"
- "static int foo(int);\n"
- "static void reset_cb(void);")
- lib = ffi.verify("""
- static int g(int x) { return x * 7; }
- static int (*cb)(int);
- static int foo(int i) { return cb(i) - 1; }
- static void reset_cb(void) { cb = g; }
- """)
- lib.reset_cb()
- assert lib.foo(6) == 41
- my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
- lib.cb = my_callback
- assert lib.foo(4) == 887
-
-def test_call_with_struct_ptr():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; ...; } foo_t; int foo(foo_t *);")
- lib = ffi.verify("""
- typedef struct { int y, x; } foo_t;
- static int foo(foo_t *f) { return f->x * 7; }
- """)
- f = ffi.new("foo_t *")
- f.x = 6
- assert lib.foo(f) == 42
-
-def test_unknown_type():
- ffi = FFI()
- ffi.cdef("""
- typedef ... token_t;
- int foo(token_t *);
- #define TOKEN_SIZE ...
- """)
- lib = ffi.verify("""
- typedef float token_t;
- static int foo(token_t *tk) {
- if (!tk)
- return -42;
- *tk += 1.601f;
- return (int)*tk;
- }
- #define TOKEN_SIZE sizeof(token_t)
- """)
- # we cannot let ffi.new("token_t *") work, because we don't know ahead of
- # time if it's ok to ask 'sizeof(token_t)' in the C code or not.
- # See test_unknown_type_2. Workaround.
- tkmem = ffi.new("char[]", lib.TOKEN_SIZE) # zero-initialized
- tk = ffi.cast("token_t *", tkmem)
- results = [lib.foo(tk) for i in range(6)]
- assert results == [1, 3, 4, 6, 8, 9]
- assert lib.foo(ffi.NULL) == -42
-
-def test_unknown_type_2():
- ffi = FFI()
- ffi.cdef("typedef ... token_t;")
- lib = ffi.verify("typedef struct token_s token_t;")
- # assert did not crash, even though 'sizeof(token_t)' is not valid in C.
-
-def test_unknown_type_3():
- ffi = FFI()
- ffi.cdef("""
- typedef ... *token_p;
- token_p foo(token_p);
- """)
- lib = ffi.verify("""
- typedef struct _token_s *token_p;
- token_p foo(token_p arg) {
- if (arg)
- return (token_p)0x12347;
- else
- return (token_p)0x12345;
- }
- """)
- p = lib.foo(ffi.NULL)
- assert int(ffi.cast("intptr_t", p)) == 0x12345
- q = lib.foo(p)
- assert int(ffi.cast("intptr_t", q)) == 0x12347
-
-def test_varargs():
- ffi = FFI()
- ffi.cdef("int foo(int x, ...);")
- lib = ffi.verify("""
- int foo(int x, ...) {
- va_list vargs;
- va_start(vargs, x);
- x -= va_arg(vargs, int);
- x -= va_arg(vargs, int);
- va_end(vargs);
- return x;
- }
- """)
- assert lib.foo(50, ffi.cast("int", 5), ffi.cast("int", 3)) == 42
-
-def test_varargs_exact():
- if sys.platform == 'win32':
- py.test.skip("XXX fixme: only gives warnings")
- ffi = FFI()
- ffi.cdef("int foo(int x, ...);")
- py.test.raises(VerificationError, ffi.verify, """
- int foo(long long x, ...) {
- return x;
- }
- """)
-
-def test_varargs_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { char a; int b; }; int foo(int x, ...);")
- lib = ffi.verify("""
- struct foo_s {
- char a; int b;
- };
- int foo(int x, ...) {
- va_list vargs;
- struct foo_s s;
- va_start(vargs, x);
- s = va_arg(vargs, struct foo_s);
- va_end(vargs);
- return s.a - s.b;
- }
- """)
- s = ffi.new("struct foo_s *", [b'B', 1])
- assert lib.foo(50, s[0]) == ord('A')
-
-def test_autofilled_struct_as_argument():
- ffi = FFI()
- ffi.cdef("struct foo_s { long a; double b; ...; };\n"
- "int foo(struct foo_s);")
- lib = ffi.verify("""
- struct foo_s {
- double b;
- long a;
- };
- int foo(struct foo_s s) {
- return (int)s.a - (int)s.b;
- }
- """)
- s = ffi.new("struct foo_s *", [100, 1])
- assert lib.foo(s[0]) == 99
- assert lib.foo([100, 1]) == 99
-
-def test_autofilled_struct_as_argument_dynamic():
- ffi = FFI()
- ffi.cdef("struct foo_s { long a; ...; };\n"
- "static int (*foo)(struct foo_s);")
- lib = ffi.verify("""
- struct foo_s {
- double b;
- long a;
- };
- int foo1(struct foo_s s) {
- return (int)s.a - (int)s.b;
- }
- static int (*foo)(struct foo_s s) = &foo1;
- """)
- e = py.test.raises(NotImplementedError, lib.foo, "?")
- msg = ("ctype 'struct foo_s' 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. "
- "Such structs are only supported as argument "
- "if the function is '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_func_returns_struct():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { int aa, bb; };
- struct foo_s foo(int a, int b);
- """)
- lib = ffi.verify("""
- struct foo_s { int aa, bb; };
- struct foo_s foo(int a, int b) {
- struct foo_s r;
- r.aa = a*a;
- r.bb = b*b;
- return r;
- }
- """)
- s = lib.foo(6, 7)
- assert repr(s) == "<cdata 'struct foo_s' owning 8 bytes>"
- assert s.aa == 36
- assert s.bb == 49
-
-def test_func_as_funcptr():
- ffi = FFI()
- ffi.cdef("int *(*const fooptr)(void);")
- lib = ffi.verify("""
- int *foo(void) {
- return (int*)"foobar";
- }
- int *(*fooptr)(void) = foo;
- """)
- foochar = ffi.cast("char *(*)(void)", lib.fooptr)
- s = foochar()
- assert ffi.string(s) == b"foobar"
-
-def test_funcptr_as_argument():
- ffi = FFI()
- ffi.cdef("""
- void qsort(void *base, size_t nel, size_t width,
- int (*compar)(const void *, const void *));
- """)
- ffi.verify("#include <stdlib.h>")
-
-def test_func_as_argument():
- ffi = FFI()
- ffi.cdef("""
- void qsort(void *base, size_t nel, size_t width,
- int compar(const void *, const void *));
- """)
- ffi.verify("#include <stdlib.h>")
-
-def test_array_as_argument():
- ffi = FFI()
- ffi.cdef("""
- size_t strlen(char string[]);
- """)
- ffi.verify("#include <string.h>")
-
-def test_enum_as_argument():
- ffi = FFI()
- ffi.cdef("""
- enum foo_e { AA, BB, ... };
- int foo_func(enum foo_e);
- """)
- lib = ffi.verify("""
- enum foo_e { AA, CC, BB };
- int foo_func(enum foo_e e) { return (int)e; }
- """)
- assert lib.foo_func(lib.BB) == 2
- py.test.raises(TypeError, lib.foo_func, "BB")
-
-def test_enum_as_function_result():
- ffi = FFI()
- ffi.cdef("""
- enum foo_e { AA, BB, ... };
- enum foo_e foo_func(int x);
- """)
- lib = ffi.verify("""
- enum foo_e { AA, CC, BB };
- enum foo_e foo_func(int x) { return (enum foo_e)x; }
- """)
- assert lib.foo_func(lib.BB) == lib.BB == 2
-
-def test_enum_values():
- ffi = FFI()
- ffi.cdef("enum enum1_e { AA, BB };")
- lib = ffi.verify("enum enum1_e { AA, BB };")
- assert lib.AA == 0
- assert lib.BB == 1
- assert ffi.string(ffi.cast("enum enum1_e", 1)) == 'BB'
-
-def test_typedef_complete_enum():
- ffi = FFI()
- ffi.cdef("typedef enum { AA, BB } enum1_t;")
- lib = ffi.verify("typedef enum { AA, BB } enum1_t;")
- assert ffi.string(ffi.cast("enum1_t", 1)) == 'BB'
- assert lib.AA == 0
- assert lib.BB == 1
-
-def test_typedef_broken_complete_enum():
- # xxx this is broken in old cffis, but works with recompiler.py
- ffi = FFI()
- ffi.cdef("typedef enum { AA, BB } enum1_t;")
- lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;")
- assert lib.AA == 0
- assert lib.BB == 2
-
-def test_typedef_incomplete_enum():
- ffi = FFI()
- ffi.cdef("typedef enum { AA, BB, ... } enum1_t;")
- lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;")
- assert ffi.string(ffi.cast("enum1_t", 1)) == '1'
- assert ffi.string(ffi.cast("enum1_t", 2)) == 'BB'
- assert lib.AA == 0
- assert lib.BB == 2
-
-def test_typedef_enum_as_argument():
- ffi = FFI()
- ffi.cdef("""
- typedef enum { AA, BB, ... } foo_t;
- int foo_func(foo_t);
- """)
- lib = ffi.verify("""
- typedef enum { AA, CC, BB } foo_t;
- int foo_func(foo_t e) { return (int)e; }
- """)
- assert lib.foo_func(lib.BB) == lib.BB == 2
- py.test.raises(TypeError, lib.foo_func, "BB")
-
-def test_typedef_enum_as_function_result():
- ffi = FFI()
- ffi.cdef("""
- typedef enum { AA, BB, ... } foo_t;
- foo_t foo_func(int x);
- """)
- lib = ffi.verify("""
- typedef enum { AA, CC, BB } foo_t;
- foo_t foo_func(int x) { return (foo_t)x; }
- """)
- assert lib.foo_func(lib.BB) == lib.BB == 2
-
-def test_function_typedef():
- ffi = FFI()
- ffi.cdef("""
- typedef double func_t(double);
- func_t sin;
- """)
- lib = ffi.verify('#include <math.h>', libraries=lib_m)
- assert lib.sin(1.23) == math.sin(1.23)
-
-def test_opaque_integer_as_function_result():
- #import platform
- #if platform.machine().startswith('sparc'):
- # py.test.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
- #elif platform.machine() == 'mips64' and sys.maxsize > 2**32:
- # py.test.skip('Segfaults on mips64el')
- # XXX bad abuse of "struct { ...; }". It only works a bit by chance
- # anyway. XXX think about something better :-(
- ffi = FFI()
- ffi.cdef("""
- typedef struct { ...; } myhandle_t;
- myhandle_t foo(void);
- """)
- lib = ffi.verify("""
- typedef short myhandle_t;
- myhandle_t foo(void) { return 42; }
- """)
- h = lib.foo()
- assert ffi.sizeof(h) == ffi.sizeof("short")
-
-def test_return_partial_struct():
- ffi = FFI()
- ffi.cdef("""
- typedef struct { int x; ...; } foo_t;
- foo_t foo(void);
- """)
- lib = ffi.verify("""
- typedef struct { int y, x; } foo_t;
- foo_t foo(void) { foo_t r = { 45, 81 }; return r; }
- """)
- h = lib.foo()
- assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
- assert h.x == 81
-
-def test_take_and_return_partial_structs():
- ffi = FFI()
- ffi.cdef("""
- typedef struct { int x; ...; } foo_t;
- foo_t foo(foo_t, foo_t);
- """)
- lib = ffi.verify("""
- typedef struct { int y, x; } foo_t;
- foo_t foo(foo_t a, foo_t b) {
- foo_t r = { 100, a.x * 5 + b.x * 7 };
- return r;
- }
- """)
- args = ffi.new("foo_t[3]")
- args[0].x = 1000
- args[2].x = -498
- h = lib.foo(args[0], args[2])
- assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
- assert h.x == 1000 * 5 - 498 * 7
-
-def test_cannot_name_struct_type():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; } **sp; void foo(sp);")
- e = py.test.raises(VerificationError, ffi.verify,
- "typedef struct { int x; } **sp; void foo(sp x) { }")
- assert 'in argument of foo: unknown type name' in str(e.value)
-
-def test_dont_check_unnamable_fields():
- ffi = FFI()
- ffi.cdef("struct foo_s { struct { int x; } someone; };")
- ffi.verify("struct foo_s { struct { int x; } someone; };")
- # assert did not crash
-
-def test_nested_anonymous_struct_exact():
- if sys.platform == 'win32':
- py.test.skip("nested anonymous struct/union")
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { struct { int a; char b; }; union { char c, d; }; };
- """)
- assert ffi.offsetof("struct foo_s", "c") == 2 * ffi.sizeof("int")
- assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")
- ffi.verify("""
- struct foo_s { struct { int a; char b; }; union { char c, d; }; };
- """)
- p = ffi.new("struct foo_s *")
- assert ffi.sizeof(p[0]) == 3 * ffi.sizeof("int") # with alignment
- p.a = 1234567
- p.b = b'X'
- p.c = b'Y'
- assert p.a == 1234567
- assert p.b == b'X'
- assert p.c == b'Y'
- assert p.d == b'Y'
-
-def test_nested_anonymous_struct_exact_error():
- if sys.platform == 'win32':
- py.test.skip("nested anonymous struct/union")
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { struct { int a; char b; }; union { char c, d; }; };
- """)
- py.test.raises(VerificationError, ffi.verify, """
- struct foo_s { struct { int a; short b; }; union { char c, d; }; };
- """)
- # works fine now
- #py.test.raises(VerificationError, ffi.verify, """
- # struct foo_s { struct { int a; char e, b; }; union { char c, d; }; };
- #""")
-
-def test_nested_anonymous_struct_inexact_1():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { struct { char b; ...; }; union { char c, d; }; };
- """)
- ffi.verify("""
- struct foo_s { int a, padding; char c, d, b; };
- """)
- assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")
-
-def test_nested_anonymous_struct_inexact_2():
- ffi = FFI()
- ffi.cdef("""
- struct foo_s { union { char c, d; }; struct { int a; char b; }; ...; };
- """)
- ffi.verify("""
- struct foo_s { int a, padding; char c, d, b; };
- """)
- assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")
-
-def test_ffi_union():
- ffi = FFI()
- ffi.cdef("union foo_u { char x; long *z; };")
- ffi.verify("union foo_u { char x; int y; long *z; };")
-
-def test_ffi_union_partial():
- ffi = FFI()
- ffi.cdef("union foo_u { char x; ...; };")
- ffi.verify("union foo_u { char x; int y; };")
- assert ffi.sizeof("union foo_u") == 4
-
-def test_ffi_union_with_partial_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { int x; ...; }; union foo_u { struct foo_s s; };")
- ffi.verify("struct foo_s { int a; int x; }; "
- "union foo_u { char b[32]; struct foo_s s; };")
- assert ffi.sizeof("struct foo_s") == 8
- assert ffi.sizeof("union foo_u") == 32
-
-def test_ffi_union_partial_2():
- ffi = FFI()
- ffi.cdef("typedef union { char x; ...; } u1;")
- ffi.verify("typedef union { char x; int y; } u1;")
- assert ffi.sizeof("u1") == 4
-
-def test_ffi_union_with_partial_struct_2():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; ...; } s1;"
- "typedef union { s1 s; } u1;")
- ffi.verify("typedef struct { int a; int x; } s1; "
- "typedef union { char b[32]; s1 s; } u1;")
- assert ffi.sizeof("s1") == 8
- assert ffi.sizeof("u1") == 32
- assert ffi.offsetof("u1", "s") == 0
-
-def test_ffi_struct_packed():
- if sys.platform == 'win32':
- py.test.skip("needs a GCC extension")
- ffi = FFI()
- ffi.cdef("struct foo_s { int b; ...; };")
- ffi.verify("""
- struct foo_s {
- char a;
- int b;
- } __attribute__((packed));
- """)
-
-def test_tmpdir():
- import tempfile, os
- from testing.udir import udir
- tmpdir = tempfile.mkdtemp(dir=str(udir))
- ffi = FFI()
- ffi.cdef("int foo(int);")
- lib = ffi.verify("int foo(int a) { return a + 42; }", tmpdir=tmpdir)
- assert os.listdir(tmpdir)
- assert lib.foo(100) == 142
-
-def test_relative_to():
- py.test.skip("not available")
- import tempfile, os
- from testing.udir import udir
- tmpdir = tempfile.mkdtemp(dir=str(udir))
- ffi = FFI()
- ffi.cdef("int foo(int);")
- f = open(os.path.join(tmpdir, 'foo.h'), 'w')
- f.write("int foo(int a) { return a + 42; }\n")
- f.close()
- lib = ffi.verify('#include "foo.h"',
- include_dirs=['.'],
- relative_to=os.path.join(tmpdir, 'x'))
- assert lib.foo(100) == 142
-
-def test_bug1():
- ffi = FFI()
- ffi.cdef("""
- typedef struct tdlhandle_s { ...; } *tdl_handle_t;
- typedef struct my_error_code_ {
- tdl_handle_t *rh;
- } my_error_code_t;
- """)
- ffi.verify("""
- typedef struct tdlhandle_s { int foo; } *tdl_handle_t;
- typedef struct my_error_code_ {
- tdl_handle_t *rh;
- } my_error_code_t;
- """)
-
-def test_bool():
- if sys.platform == 'win32':
- py.test.skip("_Bool not in MSVC")
- ffi = FFI()
- ffi.cdef("struct foo_s { _Bool x; };"
- "_Bool foo(_Bool); static _Bool (*foop)(_Bool);")
- lib = ffi.verify("""
- struct foo_s { _Bool x; };
- int foo(int arg) {
- return !arg;
- }
- _Bool _foofunc(_Bool x) {
- return !x;
- }
- static _Bool (*foop)(_Bool) = _foofunc;
- """)
- p = ffi.new("struct foo_s *")
- p.x = 1
- assert p.x is True
- with pytest.raises(OverflowError):
- p.x = -1
- with pytest.raises(TypeError):
- p.x = 0.0
- assert lib.foop(1) is False
- assert lib.foop(True) is False
- assert lib.foop(0) is True
- py.test.raises(OverflowError, lib.foop, 42)
- py.test.raises(TypeError, lib.foop, 0.0)
- assert lib.foo(1) is False
- assert lib.foo(True) is False
- assert lib.foo(0) is True
- py.test.raises(OverflowError, lib.foo, 42)
- py.test.raises(TypeError, lib.foo, 0.0)
- assert int(ffi.cast("_Bool", long(1))) == 1
- assert int(ffi.cast("_Bool", long(0))) == 0
- assert int(ffi.cast("_Bool", long(-1))) == 1
- assert int(ffi.cast("_Bool", 10**200)) == 1
- assert int(ffi.cast("_Bool", 10**40000)) == 1
- #
- class Foo(object):
- def __int__(self):
- self.seen = 1
- return result
- f = Foo()
- f.seen = 0
- result = 42
- assert int(ffi.cast("_Bool", f)) == 1
- assert f.seen
- f.seen = 0
- result = 0
- assert int(ffi.cast("_Bool", f)) == 0
- assert f.seen
- #
- py.test.raises(TypeError, ffi.cast, "_Bool", [])
-
-def test_bool_on_long_double():
- if sys.platform == 'win32':
- py.test.skip("_Bool not in MSVC")
- f = 1E-250
- if f == 0.0 or f*f != 0.0:
- py.test.skip("unexpected precision")
- ffi = FFI()
- ffi.cdef("long double square(long double f); _Bool opposite(_Bool);")
- lib = ffi.verify("long double square(long double f) { return f*f; }\n"
- "_Bool opposite(_Bool x) { return !x; }")
- f0 = lib.square(0.0)
- f2 = lib.square(f)
- f3 = lib.square(f * 2.0)
- if repr(f2) == repr(f3):
- py.test.skip("long double doesn't have enough precision")
- assert float(f0) == float(f2) == float(f3) == 0.0 # too tiny for 'double'
- assert int(ffi.cast("_Bool", f2)) == 1
- assert int(ffi.cast("_Bool", f3)) == 1
- assert int(ffi.cast("_Bool", f0)) == 0
- py.test.raises(TypeError, lib.opposite, f2)
-
-def test_cannot_pass_float():
- for basetype in ['char', 'short', 'int', 'long', 'long long']:
- for sign in ['signed', 'unsigned']:
- type = '%s %s' % (sign, basetype)
- ffi = FFI()
- ffi.cdef("struct foo_s { %s x; };\n"
- "int foo(%s);" % (type, type))
- lib = ffi.verify("""
- struct foo_s { %s x; };
- int foo(%s arg) {
- return !arg;
- }
- """ % (type, type))
- p = ffi.new("struct foo_s *")
- with pytest.raises(TypeError):
- p.x = 0.0
- assert lib.foo(42) == 0
- assert lib.foo(0) == 1
- py.test.raises(TypeError, lib.foo, 0.0)
-
-def test_addressof():
- ffi = FFI()
- ffi.cdef("""
- struct point_s { int x, y; };
- struct foo_s { int z; struct point_s point; };
- struct point_s sum_coord(struct point_s *);
- """)
- lib = ffi.verify("""
- struct point_s { int x, y; };
- struct foo_s { int z; struct point_s point; };
- struct point_s sum_coord(struct point_s *point) {
- struct point_s r;
- r.x = point->x + point->y;
- r.y = point->x - point->y;
- return r;
- }
- """)
- p = ffi.new("struct foo_s *")
- p.point.x = 16
- p.point.y = 9
- py.test.raises(TypeError, lib.sum_coord, p.point)
- res = lib.sum_coord(ffi.addressof(p.point))
- assert res.x == 25
- assert res.y == 7
- res2 = lib.sum_coord(ffi.addressof(res))
- assert res2.x == 32
- assert res2.y == 18
- py.test.raises(TypeError, lib.sum_coord, res2)
-
-def test_callback_in_thread():
- py.test.xfail("adapt or remove")
- if sys.platform == 'win32':
- py.test.skip("pthread only")
- import os, subprocess, imp
- arg = os.path.join(os.path.dirname(__file__), 'callback_in_thread.py')
- g = subprocess.Popen([sys.executable, arg,
- os.path.dirname(imp.find_module('cffi')[1])])
- result = g.wait()
- assert result == 0
-
-def test_keepalive_lib():
- py.test.xfail("adapt or remove")
- ffi = FFI()
- ffi.cdef("int foobar(void);")
- lib = ffi.verify("int foobar(void) { return 42; }")
- func = lib.foobar
- ffi_r = weakref.ref(ffi)
- lib_r = weakref.ref(lib)
- del ffi
- import gc; gc.collect() # lib stays alive
- assert lib_r() is not None
- assert ffi_r() is not None
- assert func() == 42
-
-def test_keepalive_ffi():
- py.test.xfail("adapt or remove")
- ffi = FFI()
- ffi.cdef("int foobar(void);")
- lib = ffi.verify("int foobar(void) { return 42; }")
- func = lib.foobar
- ffi_r = weakref.ref(ffi)
- lib_r = weakref.ref(lib)
- del lib
- import gc; gc.collect() # ffi stays alive
- assert ffi_r() is not None
- assert lib_r() is not None
- assert func() == 42
-
-def test_FILE_stored_in_stdout():
- if not sys.platform.startswith('linux'):
- py.test.skip("likely, we cannot assign to stdout")
- ffi = FFI()
- ffi.cdef("int printf(const char *, ...); FILE *setstdout(FILE *);")
- lib = ffi.verify("""
- #include <stdio.h>
- FILE *setstdout(FILE *f) {
- FILE *result = stdout;
- stdout = f;
- return result;
- }
- """)
- import os
- fdr, fdw = os.pipe()
- fw1 = os.fdopen(fdw, 'wb', 256)
- old_stdout = lib.setstdout(fw1)
- try:
- #
- fw1.write(b"X")
- r = lib.printf(b"hello, %d!\n", ffi.cast("int", 42))
- fw1.close()
- assert r == len("hello, 42!\n")
- #
- finally:
- lib.setstdout(old_stdout)
- #
- result = os.read(fdr, 256)
- os.close(fdr)
- # the 'X' might remain in the user-level buffer of 'fw1' and
- # end up showing up after the 'hello, 42!\n'
- assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
-
-def test_FILE_stored_explicitly():
- ffi = FFI()
- ffi.cdef("int myprintf11(const char *, int); extern FILE *myfile;")
- lib = ffi.verify("""
- #include <stdio.h>
- FILE *myfile;
- int myprintf11(const char *out, int value) {
- return fprintf(myfile, out, value);
- }
- """)
- import os
- fdr, fdw = os.pipe()
- fw1 = os.fdopen(fdw, 'wb', 256)
- lib.myfile = ffi.cast("FILE *", fw1)
- #
- fw1.write(b"X")
- r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42))
- fw1.close()
- assert r == len("hello, 42!\n")
- #
- result = os.read(fdr, 256)
- os.close(fdr)
- # the 'X' might remain in the user-level buffer of 'fw1' and
- # end up showing up after the 'hello, 42!\n'
- assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
-
-def test_global_array_with_missing_length():
- ffi = FFI()
- ffi.cdef("extern int fooarray[];")
- lib = ffi.verify("int fooarray[50];")
- assert repr(lib.fooarray).startswith("<cdata 'int *'")
-
-def test_global_array_with_dotdotdot_length():
- ffi = FFI()
- ffi.cdef("extern int fooarray[...];")
- lib = ffi.verify("int fooarray[50];")
- assert repr(lib.fooarray).startswith("<cdata 'int[50]'")
-
-def test_bad_global_array_with_dotdotdot_length():
- py.test.xfail("was detected only because 23 bytes cannot be divided by 4; "
- "redo more generally")
- ffi = FFI()
- ffi.cdef("extern int fooarray[...];")
- py.test.raises(VerificationError, ffi.verify, "char fooarray[23];")
-
-def test_struct_containing_struct():
- ffi = FFI()
- ffi.cdef("struct foo_s { ...; }; struct bar_s { struct foo_s f; ...; };")
- ffi.verify("struct foo_s { int x; }; struct bar_s { struct foo_s f; };")
- #
- ffi = FFI()
- ffi.cdef("struct foo_s { struct bar_s f; ...; }; struct bar_s { ...; };")
- ffi.verify("struct bar_s { int x; }; struct foo_s { struct bar_s f; };")
-
-def test_struct_returned_by_func():
- ffi = FFI()
- ffi.cdef("typedef ... foo_t; foo_t myfunc(void);")
- e = py.test.raises(TypeError, ffi.verify,
- "typedef struct { int x; } foo_t; "
- "foo_t myfunc(void) { foo_t x = { 42 }; return x; }")
- assert str(e.value) == (
- "function myfunc: 'foo_t' is used as result type, but is opaque")
-
-def test_include():
- ffi1 = FFI()
- ffi1.cdef("typedef struct { int x; ...; } foo_t;")
- ffi1.verify("typedef struct { int y, x; } foo_t;")
- ffi2 = FFI()
- ffi2.include(ffi1)
- ffi2.cdef("int myfunc(foo_t *);")
- lib = ffi2.verify("typedef struct { int y, x; } foo_t;"
- "int myfunc(foo_t *p) { return 42 * p->x; }")
- res = lib.myfunc(ffi2.new("foo_t *", {'x': 10}))
- assert res == 420
- res = lib.myfunc(ffi1.new("foo_t *", {'x': -10}))
- assert res == -420
-
-def test_include_enum():
- ffi1 = FFI()
- ffi1.cdef("enum foo_e { AA, ... };")
- lib1 = ffi1.verify("enum foo_e { CC, BB, AA };")
- ffi2 = FFI()
- ffi2.include(ffi1)
- ffi2.cdef("int myfunc(enum foo_e);")
- lib2 = ffi2.verify("enum foo_e { CC, BB, AA };"
- "int myfunc(enum foo_e x) { return (int)x; }")
- res = lib2.myfunc(lib2.AA)
- assert res == 2
-
-def test_named_pointer_as_argument():
- ffi = FFI()
- ffi.cdef("typedef struct { int x; } *mystruct_p;\n"
- "mystruct_p ff5a(mystruct_p);")
- lib = ffi.verify("typedef struct { int x; } *mystruct_p;\n"
- "mystruct_p ff5a(mystruct_p p) { p->x += 40; return p; }")
- p = ffi.new("mystruct_p", [-2])
- q = lib.ff5a(p)
- assert q == p
- assert p.x == 38
-
-def test_enum_size():
- cases = [('123', 4, 4294967295),
- ('4294967295U', 4, 4294967295),
- ('-123', 4, -1),
- ('-2147483647-1', 4, -1),
- ]
- if FFI().sizeof("long") == 8:
- cases += [('4294967296L', 8, 2**64-1),
- ('%dUL' % (2**64-1), 8, 2**64-1),
- ('-2147483649L', 8, -1),
- ('%dL-1L' % (1-2**63), 8, -1)]
- for hidden_value, expected_size, expected_minus1 in cases:
- if sys.platform == 'win32' and 'U' in hidden_value:
- continue # skipped on Windows
- ffi = FFI()
- ffi.cdef("enum foo_e { AA, BB, ... };")
- lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value)
- assert lib.AA == 0
- assert lib.BB == eval(hidden_value.replace('U', '').replace('L', ''))
- assert ffi.sizeof("enum foo_e") == expected_size
- if sys.platform != 'win32':
- assert int(ffi.cast("enum foo_e", -1)) == expected_minus1
- # test with the large value hidden:
- # disabled so far, doesn't work
-## for hidden_value, expected_size, expected_minus1 in cases:
-## ffi = FFI()
-## ffi.cdef("enum foo_e { AA, BB, ... };")
-## lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value)
-## assert lib.AA == 0
-## assert ffi.sizeof("enum foo_e") == expected_size
-## assert int(ffi.cast("enum foo_e", -1)) == expected_minus1
-
-def test_enum_bug118():
- maxulong = 256 ** FFI().sizeof("unsigned long") - 1
- for c2, c2c in [(-1, ''),
- (-1, ''),
- (0xffffffff, 'U'),
- (maxulong, 'UL'),
- (-int(maxulong / 3), 'L')]:
- if c2c and sys.platform == 'win32':
- continue # enums may always be signed with MSVC
- ffi = FFI()
- ffi.cdef("enum foo_e { AA };")
- lib = ffi.verify("enum foo_e { AA=%s%s };" % (c2, c2c))
- assert lib.AA == c2
-
-def test_string_to_voidp_arg():
- ffi = FFI()
- ffi.cdef("int myfunc(void *);")
- lib = ffi.verify("int myfunc(void *p) { return ((signed char *)p)[0]; }")
- res = lib.myfunc(b"hi!")
- assert res == ord(b"h")
- p = ffi.new("char[]", b"gah")
- res = lib.myfunc(p)
- assert res == ord(b"g")
- res = lib.myfunc(ffi.cast("void *", p))
- assert res == ord(b"g")
- res = lib.myfunc(ffi.cast("int *", p))
- assert res == ord(b"g")
-
-def test_callback_indirection():
- ffi = FFI()
- ffi.cdef("""
- static int (*python_callback)(int how_many, int *values);
- int (*const c_callback)(int,...); /* pass this ptr to C routines */
- int some_c_function(int(*cb)(int,...));
- """)
- lib = ffi.verify("""
- #include <stdarg.h>
- #ifdef _WIN32
- #include <malloc.h>
- #define alloca _alloca
- #else
- # ifdef __FreeBSD__
- # include <stdlib.h>
- # else
- # include <alloca.h>
- # endif
- #endif
- static int (*python_callback)(int how_many, int *values);
- static int c_callback(int how_many, ...) {
- va_list ap;
- /* collect the "..." arguments into the values[] array */
- int i, *values = alloca((size_t)how_many * sizeof(int));
- va_start(ap, how_many);
- for (i=0; i<how_many; i++)
- values[i] = va_arg(ap, int);
- va_end(ap);
- return python_callback(how_many, values);
- }
- int some_c_function(int(*cb)(int,...)) {
- int result = cb(2, 10, 20);
- result += cb(3, 30, 40, 50);
- return result;
- }
- """)
- seen = []
- @ffi.callback("int(int, int*)")
- def python_callback(how_many, values):
- seen.append([values[i] for i in range(how_many)])
- return 42
- lib.python_callback = python_callback
-
- res = lib.some_c_function(lib.c_callback)
- assert res == 84
- assert seen == [[10, 20], [30, 40, 50]]
-
-def test_floatstar_argument():
- ffi = FFI()
- ffi.cdef("float sum3floats(float *);")
- lib = ffi.verify("""
- float sum3floats(float *f) {
- return f[0] + f[1] + f[2];
- }
- """)
- assert lib.sum3floats((1.5, 2.5, 3.5)) == 7.5
- p = ffi.new("float[]", (1.5, 2.5, 3.5))
- assert lib.sum3floats(p) == 7.5
-
-def test_charstar_argument():
- ffi = FFI()
- ffi.cdef("char sum3chars(char *);")
- lib = ffi.verify("""
- char sum3chars(char *f) {
- return (char)(f[0] + f[1] + f[2]);
- }
- """)
- assert lib.sum3chars((b'\x10', b'\x20', b'\x30')) == b'\x60'
- p = ffi.new("char[]", b'\x10\x20\x30')
- assert lib.sum3chars(p) == b'\x60'
-
-def test_passing_string_or_NULL():
- ffi = FFI()
- ffi.cdef("int seeme1(char *); int seeme2(int *);")
- lib = ffi.verify("""
- int seeme1(char *x) {
- return (x == NULL);
- }
- int seeme2(int *x) {
- return (x == NULL);
- }
- """)
- assert lib.seeme1(b"foo") == 0
- assert lib.seeme1(ffi.NULL) == 1
- assert lib.seeme2([42, 43]) == 0
- assert lib.seeme2(ffi.NULL) == 1
- py.test.raises(TypeError, lib.seeme1, None)
- py.test.raises(TypeError, lib.seeme2, None)
- py.test.raises(TypeError, lib.seeme1, 0.0)
- py.test.raises(TypeError, lib.seeme2, 0.0)
- py.test.raises(TypeError, lib.seeme1, 0)
- py.test.raises(TypeError, lib.seeme2, 0)
- zeroL = 99999999999999999999
- zeroL -= 99999999999999999999
- py.test.raises(TypeError, lib.seeme2, zeroL)
-
-def test_typeof_function():
- ffi = FFI()
- ffi.cdef("int foo(int, char);")
- lib = ffi.verify("int foo(int x, char y) { (void)x; (void)y; return 42; }")
- ctype = ffi.typeof(lib.foo)
- assert len(ctype.args) == 2
- assert ctype.result == ffi.typeof("int")
-
-def test_call_with_voidstar_arg():
- ffi = FFI()
- ffi.cdef("int f(void *);")
- lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }")
- assert lib.f(b"foobar") == ord(b"f")
-
-def test_dir():
- ffi = FFI()
- ffi.cdef("""void somefunc(void);
- extern int somevar, somearray[2];
- static char *const sv2;
- enum my_e { AA, BB, ... };
- #define FOO ...""")
- lib = ffi.verify("""void somefunc(void) { }
- int somevar, somearray[2];
- #define sv2 "text"
- enum my_e { AA, BB };
- #define FOO 42""")
- assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray',
- 'somefunc', 'somevar', 'sv2']
-
-def test_typeof_func_with_struct_argument():
- ffi = FFI()
- ffi.cdef("""struct s { int a; }; int foo(struct s);""")
- lib = ffi.verify("""struct s { int a; };
- int foo(struct s x) { return x.a; }""")
- s = ffi.new("struct s *", [-1234])
- m = lib.foo(s[0])
- assert m == -1234
- assert repr(ffi.typeof(lib.foo)) == "<ctype 'int(*)(struct s)'>"
-
-def test_bug_const_char_ptr_array_1():
- ffi = FFI()
- ffi.cdef("""extern const char *a[...];""")
- lib = ffi.verify("""const char *a[5];""")
- assert repr(ffi.typeof(lib.a)) == "<ctype 'char *[5]'>"
-
-def test_bug_const_char_ptr_array_2():
- ffi = FFI()
- ffi.cdef("""extern const int a[];""")
- lib = ffi.verify("""const int a[5];""")
- assert repr(ffi.typeof(lib.a)) == "<ctype 'int *'>"
-
-def _test_various_calls(force_libffi):
- cdef_source = """
- extern int xvalue;
- extern long long ivalue, rvalue;
- extern float fvalue;
- extern double dvalue;
- extern long double Dvalue;
- signed char tf_bb(signed char x, signed char c);
- unsigned char tf_bB(signed char x, unsigned char c);
- short tf_bh(signed char x, short c);
- unsigned short tf_bH(signed char x, unsigned short c);
- int tf_bi(signed char x, int c);
- unsigned int tf_bI(signed char x, unsigned int c);
- long tf_bl(signed char x, long c);
- unsigned long tf_bL(signed char x, unsigned long c);
- long long tf_bq(signed char x, long long c);
- unsigned long long tf_bQ(signed char x, unsigned long long c);
- float tf_bf(signed char x, float c);
- double tf_bd(signed char x, double c);
- long double tf_bD(signed char x, long double c);
- """
- if force_libffi:
- cdef_source = (cdef_source
- .replace('tf_', '(*const tf_')
- .replace('(signed char x', ')(signed char x'))
- ffi = FFI()
- ffi.cdef(cdef_source)
- lib = ffi.verify("""
- int xvalue;
- long long ivalue, rvalue;
- float fvalue;
- double dvalue;
- long double Dvalue;
-
- typedef signed char b_t;
- typedef unsigned char B_t;
- typedef short h_t;
- typedef unsigned short H_t;
- typedef int i_t;
- typedef unsigned int I_t;
- typedef long l_t;
- typedef unsigned long L_t;
- typedef long long q_t;
- typedef unsigned long long Q_t;
- typedef float f_t;
- typedef double d_t;
- typedef long double D_t;
- #define S(letter) xvalue = (int)x; letter##value = (letter##_t)c;
- #define R(letter) return (letter##_t)rvalue;
-
- signed char tf_bb(signed char x, signed char c) { S(i) R(b) }
- unsigned char tf_bB(signed char x, unsigned char c) { S(i) R(B) }
- short tf_bh(signed char x, short c) { S(i) R(h) }
- unsigned short tf_bH(signed char x, unsigned short c) { S(i) R(H) }
- int tf_bi(signed char x, int c) { S(i) R(i) }
- unsigned int tf_bI(signed char x, unsigned int c) { S(i) R(I) }
- long tf_bl(signed char x, long c) { S(i) R(l) }
- unsigned long tf_bL(signed char x, unsigned long c) { S(i) R(L) }
- long long tf_bq(signed char x, long long c) { S(i) R(q) }
- unsigned long long tf_bQ(signed char x, unsigned long long c) { S(i) R(Q) }
- float tf_bf(signed char x, float c) { S(f) R(f) }
- double tf_bd(signed char x, double c) { S(d) R(d) }
- long double tf_bD(signed char x, long double c) { S(D) R(D) }
- """)
- lib.rvalue = 0x7182838485868788
- for kind, cname in [('b', 'signed char'),
- ('B', 'unsigned char'),
- ('h', 'short'),
- ('H', 'unsigned short'),
- ('i', 'int'),
- ('I', 'unsigned int'),
- ('l', 'long'),
- ('L', 'unsigned long'),
- ('q', 'long long'),
- ('Q', 'unsigned long long'),
- ('f', 'float'),
- ('d', 'double'),
- ('D', 'long double')]:
- sign = +1 if 'unsigned' in cname else -1
- lib.xvalue = 0
- lib.ivalue = 0
- lib.fvalue = 0
- lib.dvalue = 0
- lib.Dvalue = 0
- fun = getattr(lib, 'tf_b' + kind)
- res = fun(-42, sign * 99)
- if kind == 'D':
- res = float(res)
- assert res == int(ffi.cast(cname, 0x7182838485868788))
- assert lib.xvalue == -42
- if kind in 'fdD':
- assert float(getattr(lib, kind + 'value')) == -99.0
- else:
- assert lib.ivalue == sign * 99
-
-def test_various_calls_direct():
- _test_various_calls(force_libffi=False)
-
-def test_various_calls_libffi():
- _test_various_calls(force_libffi=True)
-
-def test_ptr_to_opaque():
- ffi = FFI()
- ffi.cdef("typedef ... foo_t; int f1(foo_t*); foo_t *f2(int);")
- lib = ffi.verify("""
- #include <stdlib.h>
- typedef struct { int x; } foo_t;
- int f1(foo_t* p) {
- int x = p->x;
- free(p);
- return x;
- }
- foo_t *f2(int x) {
- foo_t *p = malloc(sizeof(foo_t));
- p->x = x;
- return p;
- }
- """)
- p = lib.f2(42)
- x = lib.f1(p)
- assert x == 42
-
-def _run_in_multiple_threads(test1):
- test1()
- import sys
- try:
- import thread
- except ImportError:
- import _thread as thread
- errors = []
- def wrapper(lock):
- try:
- test1()
- except:
- errors.append(sys.exc_info())
- lock.release()
- locks = []
- for i in range(10):
- _lock = thread.allocate_lock()
- _lock.acquire()
- thread.start_new_thread(wrapper, (_lock,))
- locks.append(_lock)
- for _lock in locks:
- _lock.acquire()
- if errors:
- raise errors[0][1]
-
-def test_errno_working_even_with_pypys_jit():
- ffi = FFI()
- ffi.cdef("int f(int);")
- lib = ffi.verify("""
- #include <errno.h>
- int f(int x) { return (errno = errno + x); }
- """)
- @_run_in_multiple_threads
- def test1():
- ffi.errno = 0
- for i in range(10000):
- e = lib.f(1)
- assert e == i + 1
- assert ffi.errno == e
- for i in range(10000):
- ffi.errno = i
- e = lib.f(42)
- assert e == i + 42
-
-def test_getlasterror_working_even_with_pypys_jit():
- if sys.platform != 'win32':
- py.test.skip("win32-only test")
- ffi = FFI()
- ffi.cdef("void SetLastError(DWORD);")
- lib = ffi.dlopen("Kernel32.dll")
- @_run_in_multiple_threads
- def test1():
- for i in range(10000):
- n = (1 << 29) + i
- lib.SetLastError(n)
- assert ffi.getwinerror()[0] == n
-
-def test_verify_dlopen_flags():
- if not hasattr(sys, 'setdlopenflags'):
- py.test.skip("requires sys.setdlopenflags()")
- # Careful with RTLD_GLOBAL. If by chance the FFI is not deleted
- # promptly, like on PyPy, then other tests may see the same
- # exported symbols as well. So we must not export a simple name
- # like 'foo'!
- old = sys.getdlopenflags()
- try:
- ffi1 = FFI()
- ffi1.cdef("extern int foo_verify_dlopen_flags_1;")
- sys.setdlopenflags(ffi1.RTLD_GLOBAL | ffi1.RTLD_NOW)
- lib1 = ffi1.verify("int foo_verify_dlopen_flags_1;")
- finally:
- sys.setdlopenflags(old)
-
- ffi2 = FFI()
- ffi2.cdef("int *getptr(void);")
- lib2 = ffi2.verify("""
- extern int foo_verify_dlopen_flags_1;
- static int *getptr(void) { return &foo_verify_dlopen_flags_1; }
- """)
- p = lib2.getptr()
- assert ffi1.addressof(lib1, 'foo_verify_dlopen_flags_1') == p
-
-def test_consider_not_implemented_function_type():
- ffi = FFI()
- ffi.cdef("typedef union { int a; float b; } Data;"
- "typedef struct { int a:2; } MyStr;"
- "typedef void (*foofunc_t)(Data);"
- "typedef Data (*bazfunc_t)(void);"
- "typedef MyStr (*barfunc_t)(void);")
- fooptr = ffi.cast("foofunc_t", 123)
- bazptr = ffi.cast("bazfunc_t", 123)
- barptr = ffi.cast("barfunc_t", 123)
- # assert did not crash so far
- e = py.test.raises(NotImplementedError, fooptr, ffi.new("Data *"))
- assert str(e.value) == (
- "ctype 'Data' not supported as argument by libffi. Unions are only "
- "supported as argument if the function is 'API mode' and "
- "non-variadic (i.e. declared inside ffibuilder.cdef()+"
- "ffibuilder.set_source() and not taking a final '...' argument)")
- e = py.test.raises(NotImplementedError, bazptr)
- assert str(e.value) == (
- "ctype 'Data' not supported as return value by libffi. Unions are "
- "only supported as return value if the function is 'API mode' and "
- "non-variadic (i.e. declared inside ffibuilder.cdef()+"
- "ffibuilder.set_source() and not taking a final '...' argument)")
- e = py.test.raises(NotImplementedError, barptr)
- assert str(e.value) == (
- "ctype 'MyStr' not supported as return value. It is a struct with "
- "bit fields, which libffi does not support. Such structs are only "
- "supported as return value if the function is 'API mode' and non-"
- "variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
- "set_source() and not taking a final '...' argument)")
-
-def test_verify_extra_arguments():
- ffi = FFI()
- ffi.cdef("#define ABA ...")
- lib = ffi.verify("", define_macros=[('ABA', '42')])
- assert lib.ABA == 42
-
-def test_implicit_unicode_on_windows():
- from cffi import FFIError
- if sys.platform != 'win32':
- py.test.skip("win32-only test")
- ffi = FFI()
- e = py.test.raises(FFIError, ffi.cdef, "int foo(LPTSTR);")
- assert str(e.value) == ("The Windows type 'LPTSTR' is only available after"
- " you call ffi.set_unicode()")
- for with_unicode in [True, False]:
- ffi = FFI()
- ffi.set_unicode(with_unicode)
- ffi.cdef("""
- DWORD GetModuleFileName(HMODULE hModule, LPTSTR lpFilename,
- DWORD nSize);
- """)
- lib = ffi.verify("""
- #include <windows.h>
- """, libraries=['Kernel32'])
- outbuf = ffi.new("TCHAR[]", 200)
- n = lib.GetModuleFileName(ffi.NULL, outbuf, 500)
- assert 0 < n < 500
- for i in range(n):
- #print repr(outbuf[i])
- assert ord(outbuf[i]) != 0
- assert ord(outbuf[n]) == 0
- assert ord(outbuf[0]) < 128 # should be a letter, or '\'
-
-def test_define_known_value():
- ffi = FFI()
- ffi.cdef("#define FOO 0x123")
- lib = ffi.verify("#define FOO 0x123")
- assert lib.FOO == 0x123
-
-def test_define_wrong_value():
- ffi = FFI()
- ffi.cdef("#define FOO 123")
- lib = ffi.verify("#define FOO 124") # used to complain
- with pytest.raises(ffi.error) as e:
- lib.FOO
- assert str(e.value) == ("the C compiler says 'FOO' is equal to 124 (0x7c),"
- " but the cdef disagrees")
-
-def test_some_integer_type_for_issue73():
- ffi = FFI()
- ffi.cdef("""
- typedef int... AnIntegerWith32Bits;
- typedef AnIntegerWith32Bits (*AFunctionReturningInteger) (void);
- AnIntegerWith32Bits InvokeFunction(AFunctionReturningInteger);
- """)
- lib = ffi.verify("""
- #ifdef __LP64__
- typedef int AnIntegerWith32Bits;
- #else
- typedef long AnIntegerWith32Bits;
- #endif
- typedef AnIntegerWith32Bits (*AFunctionReturningInteger) (void);
- AnIntegerWith32Bits InvokeFunction(AFunctionReturningInteger f) {
- return f();
- }
- """)
- @ffi.callback("AFunctionReturningInteger")
- def add():
- return 3 + 4
- x = lib.InvokeFunction(add)
- assert x == 7
-
-def test_unsupported_some_primitive_types():
- ffi = FFI()
- py.test.raises((FFIError, # with pycparser <= 2.17
- CDefError), # with pycparser >= 2.18
- ffi.cdef, """typedef void... foo_t;""")
- #
- ffi.cdef("typedef int... foo_t;")
- py.test.raises(VerificationError, ffi.verify, "typedef float foo_t;")
-
-def test_windows_dllimport_data():
- if sys.platform != 'win32':
- py.test.skip("Windows only")
- from testing.udir import udir
- tmpfile = udir.join('dllimport_data.c')
- tmpfile.write('int my_value = 42;\n')
- ffi = FFI()
- ffi.cdef("int my_value;")
- lib = ffi.verify("extern __declspec(dllimport) int my_value;",
- sources = [str(tmpfile)])
- assert lib.my_value == 42
-
-def test_macro_var():
- ffi = FFI()
- ffi.cdef("extern int myarray[50], my_value;")
- lib = ffi.verify("""
- int myarray[50];
- int *get_my_value(void) {
- static int index = 0;
- return &myarray[index++];
- }
- #define my_value (*get_my_value())
- """)
- assert lib.my_value == 0 # [0]
- lib.my_value = 42 # [1]
- assert lib.myarray[1] == 42
- assert lib.my_value == 0 # [2]
- lib.myarray[3] = 63
- assert lib.my_value == 63 # [3]
- p = ffi.addressof(lib, 'my_value') # [4]
- assert p[-1] == 63
- assert p[0] == 0
- 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 *")
-
-def _only_test_on_linux_intel():
- if not sys.platform.startswith('linux'):
- py.test.skip('only running the memory-intensive test on Linux')
- import platform
- machine = platform.machine()
- if 'x86' not in machine and 'x64' not in machine:
- py.test.skip('only running the memory-intensive test on x86/x64')
-
-def test_ffi_gc_size_arg():
- _only_test_on_linux_intel()
- ffi = FFI()
- ffi.cdef("void *malloc(size_t); void free(void *);")
- lib = ffi.verify(r"""
- #include <stdlib.h>
- """)
- for i in range(2000):
- p = lib.malloc(20*1024*1024) # 20 MB
- p1 = ffi.cast("char *", p)
- for j in range(0, 20*1024*1024, 4096):
- p1[j] = b'!'
- p = ffi.gc(p, lib.free, 20*1024*1024)
- del p
- # with PyPy's GC, the above would rapidly consume 40 GB of RAM
- # without the third argument to ffi.gc()
-
-def test_ffi_gc_size_arg_2():
- # a variant of the above: this "attack" works on cpython's cyclic gc too
- # and I found no obvious way to prevent that. So for now, this test
- # is skipped on CPython, where it eats all the memory.
- if '__pypy__' not in sys.builtin_module_names:
- py.test.skip("find a way to tweak the cyclic GC of CPython")
- _only_test_on_linux_intel()
- ffi = FFI()
- ffi.cdef("void *malloc(size_t); void free(void *);")
- lib = ffi.verify(r"""
- #include <stdlib.h>
- """)
- class X(object):
- pass
- for i in range(2000):
- p = lib.malloc(50*1024*1024) # 50 MB
- p1 = ffi.cast("char *", p)
- for j in range(0, 50*1024*1024, 4096):
- p1[j] = b'!'
- p = ffi.gc(p, lib.free, 50*1024*1024)
- x = X()
- x.p = p
- x.cyclic = x
- del p, x
-
-def test_ffi_new_with_cycles():
- # still another variant, with ffi.new()
- if '__pypy__' not in sys.builtin_module_names:
- py.test.skip("find a way to tweak the cyclic GC of CPython")
- ffi = FFI()
- ffi.cdef("")
- lib = ffi.verify("")
- class X(object):
- pass
- for i in range(2000):
- p = ffi.new("char[]", 50*1024*1024) # 50 MB
- for j in range(0, 50*1024*1024, 4096):
- p[j] = b'!'
- x = X()
- x.p = p
- x.cyclic = x
- del p, x
diff --git a/testing/cffi1/test_zdist.py b/testing/cffi1/test_zdist.py
deleted file mode 100644
index efc1d86..0000000
--- a/testing/cffi1/test_zdist.py
+++ /dev/null
@@ -1,426 +0,0 @@
-import sys, os, py
-import subprocess
-import cffi
-from testing.udir import udir
-from shutil import rmtree
-from tempfile import mkdtemp
-
-
-def chdir_to_tmp(f):
- f.chdir_to_tmp = True
- return f
-
-def from_outside(f):
- f.chdir_to_tmp = False
- return f
-
-
-class TestDist(object):
-
- def setup_method(self, meth):
- self.executable = os.path.abspath(sys.executable)
- self.rootdir = os.path.abspath(os.path.dirname(os.path.dirname(
- cffi.__file__)))
- self.udir = udir.join(meth.__name__)
- os.mkdir(str(self.udir))
- if meth.chdir_to_tmp:
- self.saved_cwd = os.getcwd()
- os.chdir(str(self.udir))
-
- def teardown_method(self, meth):
- if hasattr(self, 'saved_cwd'):
- os.chdir(self.saved_cwd)
-
- def run(self, args, cwd=None):
- env = os.environ.copy()
- # a horrible hack to prevent distutils from finding ~/.pydistutils.cfg
- # (there is the --no-user-cfg option, but not in Python 2.6...)
- # NOTE: pointing $HOME to a nonexistent directory can break certain things
- # that look there for configuration (like ccache).
- tmp_home = mkdtemp()
- assert tmp_home != None, "cannot create temporary homedir"
- env['HOME'] = tmp_home
- if cwd is None:
- newpath = self.rootdir
- if 'PYTHONPATH' in env:
- newpath += os.pathsep + env['PYTHONPATH']
- env['PYTHONPATH'] = newpath
- try:
- subprocess.check_call([self.executable] + args, cwd=cwd, env=env)
- finally:
- rmtree(tmp_home)
-
- def _prepare_setuptools(self):
- if hasattr(TestDist, '_setuptools_ready'):
- return
- try:
- import setuptools
- except ImportError:
- py.test.skip("setuptools not found")
- if os.path.exists(os.path.join(self.rootdir, 'setup.py')):
- self.run(['setup.py', 'egg_info'], cwd=self.rootdir)
- TestDist._setuptools_ready = True
-
- def check_produced_files(self, content, curdir=None):
- if curdir is None:
- curdir = str(self.udir)
- found_so = None
- for name in os.listdir(curdir):
- if (name.endswith('.so') or name.endswith('.pyd') or
- name.endswith('.dylib') or name.endswith('.dll')):
- found_so = os.path.join(curdir, name)
- # foo.so => foo
- parts = name.split('.')
- del parts[-1]
- if len(parts) > 1 and parts[-1] != 'bar':
- # foo.cpython-34m.so => foo, but foo.bar.so => foo.bar
- del parts[-1]
- name = '.'.join(parts)
- # foo_d => foo (Python 2 debug builds)
- if name.endswith('_d') and hasattr(sys, 'gettotalrefcount'):
- name = name[:-2]
- name += '.SO'
- if name.startswith('pycparser') and name.endswith('.egg'):
- continue # no clue why this shows up sometimes and not others
- if name == '.eggs':
- continue # seems new in 3.5, ignore it
- assert name in content, "found unexpected file %r" % (
- os.path.join(curdir, name),)
- value = content.pop(name)
- if value is None:
- assert name.endswith('.SO') or (
- os.path.isfile(os.path.join(curdir, name)))
- else:
- subdir = os.path.join(curdir, name)
- assert os.path.isdir(subdir)
- if value == '?':
- continue
- found_so = self.check_produced_files(value, subdir) or found_so
- assert content == {}, "files or dirs not produced in %r: %r" % (
- curdir, content.keys())
- return found_so
-
- @chdir_to_tmp
- def test_empty(self):
- self.check_produced_files({})
-
- @chdir_to_tmp
- def test_abi_emit_python_code_1(self):
- ffi = cffi.FFI()
- ffi.set_source("package_name_1.mymod", None)
- ffi.emit_python_code('xyz.py')
- self.check_produced_files({'xyz.py': None})
-
- @chdir_to_tmp
- def test_abi_emit_python_code_2(self):
- ffi = cffi.FFI()
- ffi.set_source("package_name_1.mymod", None)
- py.test.raises(IOError, ffi.emit_python_code, 'unexisting/xyz.py')
-
- @from_outside
- def test_abi_emit_python_code_3(self):
- ffi = cffi.FFI()
- ffi.set_source("package_name_1.mymod", None)
- ffi.emit_python_code(str(self.udir.join('xyt.py')))
- self.check_produced_files({'xyt.py': None})
-
- @chdir_to_tmp
- def test_abi_compile_1(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", None)
- x = ffi.compile()
- self.check_produced_files({'mod_name_in_package': {'mymod.py': None}})
- assert x == os.path.join('.', 'mod_name_in_package', 'mymod.py')
-
- @chdir_to_tmp
- def test_abi_compile_2(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", None)
- x = ffi.compile('build2')
- self.check_produced_files({'build2': {
- 'mod_name_in_package': {'mymod.py': None}}})
- assert x == os.path.join('build2', 'mod_name_in_package', 'mymod.py')
-
- @from_outside
- def test_abi_compile_3(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", None)
- tmpdir = str(self.udir.join('build3'))
- x = ffi.compile(tmpdir)
- self.check_produced_files({'build3': {
- 'mod_name_in_package': {'mymod.py': None}}})
- assert x == os.path.join(tmpdir, 'mod_name_in_package', 'mymod.py')
-
- @chdir_to_tmp
- def test_api_emit_c_code_1(self):
- ffi = cffi.FFI()
- ffi.set_source("package_name_1.mymod", "/*code would be here*/")
- ffi.emit_c_code('xyz.c')
- self.check_produced_files({'xyz.c': None})
-
- @chdir_to_tmp
- def test_api_emit_c_code_2(self):
- ffi = cffi.FFI()
- ffi.set_source("package_name_1.mymod", "/*code would be here*/")
- py.test.raises(IOError, ffi.emit_c_code, 'unexisting/xyz.c')
-
- @from_outside
- def test_api_emit_c_code_3(self):
- ffi = cffi.FFI()
- ffi.set_source("package_name_1.mymod", "/*code would be here*/")
- ffi.emit_c_code(str(self.udir.join('xyu.c')))
- self.check_produced_files({'xyu.c': None})
-
- @chdir_to_tmp
- def test_api_compile_1(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
- x = ffi.compile()
- if sys.platform != 'win32':
- sofile = self.check_produced_files({
- 'mod_name_in_package': {'mymod.SO': None,
- 'mymod.c': None,
- 'mymod.o': None}})
- assert os.path.isabs(x) and os.path.samefile(x, sofile)
- else:
- self.check_produced_files({
- 'mod_name_in_package': {'mymod.SO': None,
- 'mymod.c': None},
- 'Release': '?'})
-
- @chdir_to_tmp
- def test_api_compile_2(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
- x = ffi.compile('output')
- if sys.platform != 'win32':
- sofile = self.check_produced_files({
- 'output': {'mod_name_in_package': {'mymod.SO': None,
- 'mymod.c': None,
- 'mymod.o': None}}})
- assert os.path.isabs(x) and os.path.samefile(x, sofile)
- else:
- self.check_produced_files({
- 'output': {'mod_name_in_package': {'mymod.SO': None,
- 'mymod.c': None},
- 'Release': '?'}})
-
- @from_outside
- def test_api_compile_3(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
- x = ffi.compile(str(self.udir.join('foo')))
- if sys.platform != 'win32':
- sofile = self.check_produced_files({
- 'foo': {'mod_name_in_package': {'mymod.SO': None,
- 'mymod.c': None,
- 'mymod.o': None}}})
- assert os.path.isabs(x) and os.path.samefile(x, sofile)
- else:
- self.check_produced_files({
- 'foo': {'mod_name_in_package': {'mymod.SO': None,
- 'mymod.c': None},
- 'Release': '?'}})
-
- @chdir_to_tmp
- def test_api_compile_explicit_target_1(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
- x = ffi.compile(target="foo.bar.*")
- if sys.platform != 'win32':
- sofile = self.check_produced_files({
- 'mod_name_in_package': {'foo.bar.SO': None,
- 'mymod.c': None,
- 'mymod.o': None}})
- assert os.path.isabs(x) and os.path.samefile(x, sofile)
- else:
- self.check_produced_files({
- 'mod_name_in_package': {'foo.bar.SO': None,
- 'mymod.c': None},
- 'Release': '?'})
-
- @chdir_to_tmp
- def test_api_compile_explicit_target_3(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
- x = ffi.compile(target="foo.bar.baz")
- if sys.platform != 'win32':
- self.check_produced_files({
- 'mod_name_in_package': {'foo.bar.baz': None,
- 'mymod.c': None,
- 'mymod.o': None}})
- sofile = os.path.join(str(self.udir),
- 'mod_name_in_package', 'foo.bar.baz')
- assert os.path.isabs(x) and os.path.samefile(x, sofile)
- else:
- self.check_produced_files({
- 'mod_name_in_package': {'foo.bar.baz': None,
- 'mymod.c': None},
- 'Release': '?'})
-
- @chdir_to_tmp
- def test_api_distutils_extension_1(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
- ext = ffi.distutils_extension()
- self.check_produced_files({'build': {
- 'mod_name_in_package': {'mymod.c': None}}})
- if hasattr(os.path, 'samefile'):
- assert os.path.samefile(ext.sources[0],
- 'build/mod_name_in_package/mymod.c')
-
- @from_outside
- def test_api_distutils_extension_2(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
- ext = ffi.distutils_extension(str(self.udir.join('foo')))
- self.check_produced_files({'foo': {
- 'mod_name_in_package': {'mymod.c': None}}})
- if hasattr(os.path, 'samefile'):
- assert os.path.samefile(ext.sources[0],
- str(self.udir.join('foo/mod_name_in_package/mymod.c')))
-
-
- def _make_distutils_api(self):
- os.mkdir("src")
- os.mkdir(os.path.join("src", "pack1"))
- with open(os.path.join("src", "pack1", "__init__.py"), "w") as f:
- pass
- with open("setup.py", "w") as f:
- f.write("""if 1:
- # https://bugs.python.org/issue23246
- import sys
- if sys.platform == 'win32':
- try:
- import setuptools
- except ImportError:
- pass
-
- import cffi
- ffi = cffi.FFI()
- ffi.set_source("pack1.mymod", "/*code would be here*/")
-
- from distutils.core import setup
- setup(name='example1',
- version='0.1',
- packages=['pack1'],
- package_dir={'': 'src'},
- ext_modules=[ffi.distutils_extension()])
- """)
-
- @chdir_to_tmp
- def test_distutils_api_1(self):
- self._make_distutils_api()
- self.run(["setup.py", "build"])
- self.check_produced_files({'setup.py': None,
- 'build': '?',
- 'src': {'pack1': {'__init__.py': None}}})
-
- @chdir_to_tmp
- def test_distutils_api_2(self):
- self._make_distutils_api()
- self.run(["setup.py", "build_ext", "-i"])
- self.check_produced_files({'setup.py': None,
- 'build': '?',
- 'src': {'pack1': {'__init__.py': None,
- 'mymod.SO': None}}})
-
- def _make_setuptools_abi(self):
- self._prepare_setuptools()
- os.mkdir("src0")
- os.mkdir(os.path.join("src0", "pack2"))
- with open(os.path.join("src0", "pack2", "__init__.py"), "w") as f:
- pass
- with open(os.path.join("src0", "pack2", "_build.py"), "w") as f:
- f.write("""if 1:
- import cffi
- ffi = cffi.FFI()
- ffi.set_source("pack2.mymod", None)
- """)
- with open("setup.py", "w") as f:
- f.write("""if 1:
- from setuptools import setup
- setup(name='example1',
- version='0.1',
- packages=['pack2'],
- package_dir={'': 'src0'},
- cffi_modules=["src0/pack2/_build.py:ffi"])
- """)
-
- @chdir_to_tmp
- def test_setuptools_abi_1(self):
- self._make_setuptools_abi()
- self.run(["setup.py", "build"])
- self.check_produced_files({'setup.py': None,
- 'build': '?',
- 'src0': {'pack2': {'__init__.py': None,
- '_build.py': None}}})
-
- @chdir_to_tmp
- def test_setuptools_abi_2(self):
- self._make_setuptools_abi()
- self.run(["setup.py", "build_ext", "-i"])
- self.check_produced_files({'setup.py': None,
- 'src0': {'pack2': {'__init__.py': None,
- '_build.py': None,
- 'mymod.py': None}}})
-
- def _make_setuptools_api(self):
- self._prepare_setuptools()
- os.mkdir("src1")
- os.mkdir(os.path.join("src1", "pack3"))
- with open(os.path.join("src1", "pack3", "__init__.py"), "w") as f:
- pass
- with open(os.path.join("src1", "pack3", "_build.py"), "w") as f:
- f.write("""if 1:
- import cffi
- ffi = cffi.FFI()
- ffi.set_source("pack3.mymod", "/*code would be here*/")
- ffi._hi_there = 42
- """)
- with open("setup.py", "w") as f:
- f.write("from __future__ import print_function\n"
- """if 1:
- from setuptools import setup
- from distutils.command.build_ext import build_ext
- import os
-
- class TestBuildExt(build_ext):
- def pre_run(self, ext, ffi):
- print('_make_setuptools_api: in pre_run:', end=" ")
- assert ffi._hi_there == 42
- assert ext.name == "pack3.mymod"
- fn = os.path.join(os.path.dirname(self.build_lib),
- '..', 'see_me')
- print('creating %r' % (fn,))
- open(fn, 'w').close()
-
- setup(name='example1',
- version='0.1',
- packages=['pack3'],
- package_dir={'': 'src1'},
- cffi_modules=["src1/pack3/_build.py:ffi"],
- cmdclass={'build_ext': TestBuildExt},
- )
- """)
-
- @chdir_to_tmp
- def test_setuptools_api_1(self):
- self._make_setuptools_api()
- self.run(["setup.py", "build"])
- self.check_produced_files({'setup.py': None,
- 'build': '?',
- 'see_me': None,
- 'src1': {'pack3': {'__init__.py': None,
- '_build.py': None}}})
-
- @chdir_to_tmp
- def test_setuptools_api_2(self):
- self._make_setuptools_api()
- self.run(["setup.py", "build_ext", "-i"])
- self.check_produced_files({'setup.py': None,
- 'build': '?',
- 'see_me': None,
- 'src1': {'pack3': {'__init__.py': None,
- '_build.py': None,
- 'mymod.SO': None}}})
diff --git a/testing/embedding/__init__.py b/testing/embedding/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/testing/embedding/__init__.py
+++ /dev/null
diff --git a/testing/embedding/add1-test.c b/testing/embedding/add1-test.c
deleted file mode 100644
index b9ede18..0000000
--- a/testing/embedding/add1-test.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <stdio.h>
-
-#ifdef _MSC_VER
-#include <windows.h>
-#endif
-
-extern int add1(int, int);
-
-
-int main(void)
-{
- int x, y;
- x = add1(40, 2);
- y = add1(100, -5);
- printf("got: %d %d\n", x, y);
-#ifdef _MSC_VER
- if (x == 0 && y == 0)
- Sleep(2000);
-#endif
- return 0;
-}
diff --git a/testing/embedding/add1.py b/testing/embedding/add1.py
deleted file mode 100644
index 6f89ae9..0000000
--- a/testing/embedding/add1.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.embedding_api("""
- int add1(int, int);
-""")
-
-ffi.embedding_init_code(r"""
- import sys, time
- sys.stdout.write("preparing")
- for i in range(3):
- sys.stdout.flush()
- # Windows: sometimes time.sleep() doesn't sleep at all.
- # This appears to occur on recent versions of python only.
- t_end = time.time() + 0.19
- while time.time() < t_end:
- time.sleep(0.2)
- sys.stdout.write(".")
- sys.stdout.write("\n")
-
- from _add1_cffi import ffi
-
- int(ord("A")) # check that built-ins are there
-
- @ffi.def_extern()
- def add1(x, y):
- sys.stdout.write("adding %d and %d\n" % (x, y))
- sys.stdout.flush()
- return x + y
-""")
-
-ffi.set_source("_add1_cffi", """
-""")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
diff --git a/testing/embedding/add2-test.c b/testing/embedding/add2-test.c
deleted file mode 100644
index 9620843..0000000
--- a/testing/embedding/add2-test.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <stdio.h>
-
-extern int add1(int, int);
-extern int add2(int, int, int);
-
-
-int main(void)
-{
- int x, y;
- x = add1(40, 2);
- y = add2(100, -5, -20);
- printf("got: %d %d\n", x, y);
- return 0;
-}
diff --git a/testing/embedding/add2.py b/testing/embedding/add2.py
deleted file mode 100644
index 311a464..0000000
--- a/testing/embedding/add2.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.embedding_api("""
- int add2(int, int, int);
-""")
-
-ffi.embedding_init_code(r"""
- import sys
- sys.stdout.write("prepADD2\n")
-
- assert '_add2_cffi' in sys.modules
- m = sys.modules['_add2_cffi']
- import _add2_cffi
- ffi = _add2_cffi.ffi
-
- @ffi.def_extern()
- def add2(x, y, z):
- sys.stdout.write("adding %d and %d and %d\n" % (x, y, z))
- sys.stdout.flush()
- return x + y + z
-""")
-
-ffi.set_source("_add2_cffi", """
-""")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
diff --git a/testing/embedding/add3.py b/testing/embedding/add3.py
deleted file mode 100644
index 1361912..0000000
--- a/testing/embedding/add3.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.embedding_api("""
- int add3(int, int, int, int);
-""")
-
-ffi.embedding_init_code(r"""
- from _add3_cffi import ffi
- import sys
-
- @ffi.def_extern()
- def add3(x, y, z, t):
- sys.stdout.write("adding %d, %d, %d, %d\n" % (x, y, z, t))
- sys.stdout.flush()
- return x + y + z + t
-""")
-
-ffi.set_source("_add3_cffi", """
-""")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
diff --git a/testing/embedding/add_recursive-test.c b/testing/embedding/add_recursive-test.c
deleted file mode 100644
index cd29b79..0000000
--- a/testing/embedding/add_recursive-test.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <stdio.h>
-
-#ifdef _MSC_VER
-# define DLLIMPORT __declspec(dllimport)
-#else
-# define DLLIMPORT extern
-#endif
-
-DLLIMPORT int add_rec(int, int);
-DLLIMPORT int (*my_callback)(int);
-
-static int some_callback(int x)
-{
- printf("some_callback(%d)\n", x);
- fflush(stdout);
- return add_rec(x, 9);
-}
-
-int main(void)
-{
- int x, y;
- my_callback = some_callback;
- x = add_rec(40, 2);
- y = add_rec(100, -5);
- printf("got: %d %d\n", x, y);
- return 0;
-}
diff --git a/testing/embedding/add_recursive.py b/testing/embedding/add_recursive.py
deleted file mode 100644
index a88aa8f..0000000
--- a/testing/embedding/add_recursive.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.embedding_api("""
- extern int (*my_callback)(int);
- int add_rec(int, int);
-""")
-
-ffi.embedding_init_code(r"""
- from _add_recursive_cffi import ffi, lib
- import sys
- print("preparing REC")
- sys.stdout.flush()
-
- @ffi.def_extern()
- def add_rec(x, y):
- print("adding %d and %d" % (x, y))
- sys.stdout.flush()
- return x + y
-
- x = lib.my_callback(400)
- print('<<< %d >>>' % (x,))
-""")
-
-ffi.set_source("_add_recursive_cffi", """
-/* use CFFI_DLLEXPORT: on windows, it expands to __declspec(dllexport),
- which is needed to export a variable from a dll */
-CFFI_DLLEXPORT int (*my_callback)(int);
-""")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
diff --git a/testing/embedding/empty.py b/testing/embedding/empty.py
deleted file mode 100644
index aa8d830..0000000
--- a/testing/embedding/empty.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.embedding_api("")
-
-ffi.set_source("_empty_cffi", "")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
diff --git a/testing/embedding/initerror.py b/testing/embedding/initerror.py
deleted file mode 100644
index 775cf56..0000000
--- a/testing/embedding/initerror.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.embedding_api("""
- int add1(int, int);
-""")
-
-ffi.embedding_init_code(r"""
- raise KeyError
-""")
-
-ffi.set_source("_initerror_cffi", """
-""")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
-
diff --git a/testing/embedding/perf-test.c b/testing/embedding/perf-test.c
deleted file mode 100644
index 2195bf5..0000000
--- a/testing/embedding/perf-test.c
+++ /dev/null
@@ -1,90 +0,0 @@
-#include <stdio.h>
-#include <assert.h>
-#include <sys/time.h>
-#ifdef PTEST_USE_THREAD
-# include <pthread.h>
-static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
-static int remaining;
-#endif
-
-
-extern int add1(int, int);
-
-
-static double time_delta(struct timeval *stop, struct timeval *start)
-{
- return (stop->tv_sec - start->tv_sec) +
- 1e-6 * (stop->tv_usec - start->tv_usec);
-}
-
-static double measure(void)
-{
- long long i, iterations;
- int result;
- struct timeval start, stop;
- double elapsed;
-
- add1(0, 0); /* prepare off-line */
-
- i = 0;
- iterations = 1000;
- result = gettimeofday(&start, NULL);
- assert(result == 0);
-
- while (1) {
- for (; i < iterations; i++) {
- add1(((int)i) & 0xaaaaaa, ((int)i) & 0x555555);
- }
- result = gettimeofday(&stop, NULL);
- assert(result == 0);
-
- elapsed = time_delta(&stop, &start);
- assert(elapsed >= 0.0);
- if (elapsed > 2.5)
- break;
- iterations = iterations * 3 / 2;
- }
-
- return elapsed / (double)iterations;
-}
-
-static void *start_routine(void *arg)
-{
- double t = measure();
- printf("time per call: %.3g\n", t);
-
-#ifdef PTEST_USE_THREAD
- pthread_mutex_lock(&mutex1);
- remaining -= 1;
- if (!remaining)
- pthread_cond_signal(&cond1);
- pthread_mutex_unlock(&mutex1);
-#endif
-
- return arg;
-}
-
-
-int main(void)
-{
-#ifndef PTEST_USE_THREAD
- start_routine(0);
-#else
- pthread_t th;
- int i, status;
-
- add1(0, 0); /* this is the main thread */
-
- remaining = PTEST_USE_THREAD;
- for (i = 0; i < PTEST_USE_THREAD; i++) {
- status = pthread_create(&th, NULL, start_routine, NULL);
- assert(status == 0);
- }
- pthread_mutex_lock(&mutex1);
- while (remaining)
- pthread_cond_wait(&cond1, &mutex1);
- pthread_mutex_unlock(&mutex1);
-#endif
- return 0;
-}
diff --git a/testing/embedding/perf.py b/testing/embedding/perf.py
deleted file mode 100644
index a8d20f4..0000000
--- a/testing/embedding/perf.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.embedding_api("""
- int add1(int, int);
-""")
-
-ffi.embedding_init_code(r"""
- from _perf_cffi import ffi
-
- @ffi.def_extern()
- def add1(x, y):
- return x + y
-""")
-
-ffi.set_source("_perf_cffi", """
-""")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
diff --git a/testing/embedding/test_basic.py b/testing/embedding/test_basic.py
deleted file mode 100644
index 8d2e776..0000000
--- a/testing/embedding/test_basic.py
+++ /dev/null
@@ -1,214 +0,0 @@
-import py
-import sys, os, re
-import shutil, subprocess, time
-from testing.udir import udir
-import cffi
-
-
-local_dir = os.path.dirname(os.path.abspath(__file__))
-_link_error = '?'
-
-def check_lib_python_found(tmpdir):
- global _link_error
- if _link_error == '?':
- ffi = cffi.FFI()
- kwds = {}
- ffi._apply_embedding_fix(kwds)
- ffi.set_source("_test_lib_python_found", "", **kwds)
- try:
- ffi.compile(tmpdir=tmpdir, verbose=True)
- except cffi.VerificationError as e:
- _link_error = e
- else:
- _link_error = None
- if _link_error:
- py.test.skip(str(_link_error))
-
-
-def prefix_pythonpath():
- cffi_base = os.path.dirname(os.path.dirname(local_dir))
- pythonpath = org_env.get('PYTHONPATH', '').split(os.pathsep)
- if cffi_base not in pythonpath:
- pythonpath.insert(0, cffi_base)
- return os.pathsep.join(pythonpath)
-
-def copy_away_env():
- global org_env
- try:
- org_env
- except NameError:
- org_env = os.environ.copy()
-
-
-class EmbeddingTests:
- _compiled_modules = {}
-
- def setup_method(self, meth):
- check_lib_python_found(str(udir.ensure('embedding', dir=1)))
- self._path = udir.join('embedding', meth.__name__)
- if sys.platform == "win32" or sys.platform == "darwin":
- self._compiled_modules.clear() # workaround
-
- def get_path(self):
- return str(self._path.ensure(dir=1))
-
- def _run_base(self, args, **kwds):
- print('RUNNING:', args, kwds)
- return subprocess.Popen(args, **kwds)
-
- def _run(self, args):
- popen = self._run_base(args, cwd=self.get_path(),
- stdout=subprocess.PIPE,
- universal_newlines=True)
- output = popen.stdout.read()
- err = popen.wait()
- if err:
- raise OSError(("popen failed with exit code %r: %r\n\n%s" % (
- err, args, output)).rstrip())
- print(output.rstrip())
- return output
-
- def prepare_module(self, name):
- self.patch_environment()
- if name not in self._compiled_modules:
- path = self.get_path()
- filename = '%s.py' % name
- # NOTE: if you have an .egg globally installed with an older
- # version of cffi, this will not work, because sys.path ends
- # up with the .egg before the PYTHONPATH entries. I didn't
- # find a solution to that: we could hack sys.path inside the
- # script run here, but we can't hack it in the same way in
- # execute().
- pathname = os.path.join(path, filename)
- with open(pathname, 'w') as g:
- g.write('''
-# https://bugs.python.org/issue23246
-import sys
-if sys.platform == 'win32':
- try:
- import setuptools
- except ImportError:
- pass
-''')
- with open(os.path.join(local_dir, filename), 'r') as f:
- g.write(f.read())
-
- output = self._run([sys.executable, pathname])
- match = re.compile(r"\bFILENAME: (.+)").search(output)
- assert match
- dynamic_lib_name = match.group(1)
- if sys.platform == 'win32':
- assert dynamic_lib_name.endswith('_cffi.dll')
- elif sys.platform == 'darwin':
- assert dynamic_lib_name.endswith('_cffi.dylib')
- else:
- assert dynamic_lib_name.endswith('_cffi.so')
- self._compiled_modules[name] = dynamic_lib_name
- return self._compiled_modules[name]
-
- def compile(self, name, modules, opt=False, threads=False, defines={}):
- path = self.get_path()
- filename = '%s.c' % name
- shutil.copy(os.path.join(local_dir, filename), path)
- shutil.copy(os.path.join(local_dir, 'thread-test.h'), path)
- import distutils.ccompiler
- curdir = os.getcwd()
- try:
- os.chdir(self.get_path())
- c = distutils.ccompiler.new_compiler()
- print('compiling %s with %r' % (name, modules))
- extra_preargs = []
- debug = True
- if sys.platform == 'win32':
- libfiles = []
- for m in modules:
- m = os.path.basename(m)
- assert m.endswith('.dll')
- libfiles.append('Release\\%s.lib' % m[:-4])
- modules = libfiles
- extra_preargs.append('/MANIFEST')
- debug = False # you need to install extra stuff
- # for this to work
- elif threads:
- extra_preargs.append('-pthread')
- objects = c.compile([filename], macros=sorted(defines.items()),
- debug=debug)
- c.link_executable(objects + modules, name, extra_preargs=extra_preargs)
- finally:
- os.chdir(curdir)
-
- def patch_environment(self):
- copy_away_env()
- path = self.get_path()
- # for libpypy-c.dll or Python27.dll
- path = os.path.split(sys.executable)[0] + os.path.pathsep + path
- env_extra = {'PYTHONPATH': prefix_pythonpath()}
- if sys.platform == 'win32':
- envname = 'PATH'
- else:
- envname = 'LD_LIBRARY_PATH'
- libpath = org_env.get(envname)
- if libpath:
- libpath = path + os.path.pathsep + libpath
- else:
- libpath = path
- env_extra[envname] = libpath
- for key, value in sorted(env_extra.items()):
- if os.environ.get(key) != value:
- print('* setting env var %r to %r' % (key, value))
- os.environ[key] = value
-
- def execute(self, name):
- path = self.get_path()
- print('running %r in %r' % (name, path))
- executable_name = name
- if sys.platform == 'win32':
- executable_name = os.path.join(path, executable_name + '.exe')
- else:
- executable_name = os.path.join('.', executable_name)
- popen = self._run_base([executable_name], cwd=path,
- stdout=subprocess.PIPE,
- universal_newlines=True)
- result = popen.stdout.read()
- err = popen.wait()
- if err:
- raise OSError("%r failed with exit code %r" % (
- os.path.join(path, executable_name), err))
- return result
-
-
-class TestBasic(EmbeddingTests):
- def test_empty(self):
- empty_cffi = self.prepare_module('empty')
-
- def test_basic(self):
- add1_cffi = self.prepare_module('add1')
- self.compile('add1-test', [add1_cffi])
- output = self.execute('add1-test')
- assert output == ("preparing...\n"
- "adding 40 and 2\n"
- "adding 100 and -5\n"
- "got: 42 95\n")
-
- def test_two_modules(self):
- add1_cffi = self.prepare_module('add1')
- add2_cffi = self.prepare_module('add2')
- self.compile('add2-test', [add1_cffi, add2_cffi])
- output = self.execute('add2-test')
- assert output == ("preparing...\n"
- "adding 40 and 2\n"
- "prepADD2\n"
- "adding 100 and -5 and -20\n"
- "got: 42 75\n")
-
- def test_init_time_error(self):
- initerror_cffi = self.prepare_module('initerror')
- self.compile('add1-test', [initerror_cffi])
- output = self.execute('add1-test')
- assert output == "got: 0 0\n" # plus lots of info to stderr
-
- def test_embedding_with_unicode(self):
- withunicode_cffi = self.prepare_module('withunicode')
- self.compile('add1-test', [withunicode_cffi])
- output = self.execute('add1-test')
- assert output == "255\n4660\n65244\ngot: 0 0\n"
diff --git a/testing/embedding/test_performance.py b/testing/embedding/test_performance.py
deleted file mode 100644
index a0e8458..0000000
--- a/testing/embedding/test_performance.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import sys
-from testing.embedding.test_basic import EmbeddingTests
-
-if sys.platform == 'win32':
- import pytest
- pytestmark = pytest.mark.skip("written with POSIX functions")
-
-
-class TestPerformance(EmbeddingTests):
- def test_perf_single_threaded(self):
- perf_cffi = self.prepare_module('perf')
- self.compile('perf-test', [perf_cffi], opt=True)
- output = self.execute('perf-test')
- print('='*79)
- print(output.rstrip())
- print('='*79)
-
- def test_perf_in_1_thread(self):
- perf_cffi = self.prepare_module('perf')
- self.compile('perf-test', [perf_cffi], opt=True, threads=True,
- defines={'PTEST_USE_THREAD': '1'})
- output = self.execute('perf-test')
- print('='*79)
- print(output.rstrip())
- print('='*79)
-
- def test_perf_in_2_threads(self):
- perf_cffi = self.prepare_module('perf')
- self.compile('perf-test', [perf_cffi], opt=True, threads=True,
- defines={'PTEST_USE_THREAD': '2'})
- output = self.execute('perf-test')
- print('='*79)
- print(output.rstrip())
- print('='*79)
-
- def test_perf_in_4_threads(self):
- perf_cffi = self.prepare_module('perf')
- self.compile('perf-test', [perf_cffi], opt=True, threads=True,
- defines={'PTEST_USE_THREAD': '4'})
- output = self.execute('perf-test')
- print('='*79)
- print(output.rstrip())
- print('='*79)
-
- def test_perf_in_8_threads(self):
- perf_cffi = self.prepare_module('perf')
- self.compile('perf-test', [perf_cffi], opt=True, threads=True,
- defines={'PTEST_USE_THREAD': '8'})
- output = self.execute('perf-test')
- print('='*79)
- print(output.rstrip())
- print('='*79)
diff --git a/testing/embedding/test_recursive.py b/testing/embedding/test_recursive.py
deleted file mode 100644
index b85e7ed..0000000
--- a/testing/embedding/test_recursive.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from testing.embedding.test_basic import EmbeddingTests
-
-
-class TestRecursive(EmbeddingTests):
- def test_recursive(self):
- add_recursive_cffi = self.prepare_module('add_recursive')
- self.compile('add_recursive-test', [add_recursive_cffi])
- output = self.execute('add_recursive-test')
- assert output == ("preparing REC\n"
- "some_callback(400)\n"
- "adding 400 and 9\n"
- "<<< 409 >>>\n"
- "adding 40 and 2\n"
- "adding 100 and -5\n"
- "got: 42 95\n")
diff --git a/testing/embedding/test_thread.py b/testing/embedding/test_thread.py
deleted file mode 100644
index 9a5936d..0000000
--- a/testing/embedding/test_thread.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from testing.embedding.test_basic import EmbeddingTests
-
-
-class TestThread(EmbeddingTests):
- def test_first_calls_in_parallel(self):
- add1_cffi = self.prepare_module('add1')
- self.compile('thread1-test', [add1_cffi], threads=True)
- for i in range(20):
- output = self.execute('thread1-test')
- assert output == ("starting\n"
- "preparing...\n" +
- "adding 40 and 2\n" * 10 +
- "done\n")
-
- def _take_out(self, text, content):
- assert content in text
- i = text.index(content)
- return text[:i] + text[i+len(content):]
-
- def test_init_different_modules_in_different_threads(self):
- add1_cffi = self.prepare_module('add1')
- add2_cffi = self.prepare_module('add2')
- self.compile('thread2-test', [add1_cffi, add2_cffi], threads=True)
- for i in range(3):
- output = self.execute('thread2-test')
- print('='*79)
- print(output)
- print('='*79)
- output = self._take_out(output, "preparing")
- output = self._take_out(output, ".")
- output = self._take_out(output, ".")
- # at least the 3rd dot should be after everything from ADD2
- assert output == ("starting\n"
- "prepADD2\n"
- "adding 1000 and 200 and 30\n"
- ".\n"
- "adding 40 and 2\n"
- "done\n")
-
- def test_alt_issue(self):
- add1_cffi = self.prepare_module('add1')
- add2_cffi = self.prepare_module('add2')
- self.compile('thread2-test', [add1_cffi, add2_cffi],
- threads=True, defines={'T2TEST_AGAIN_ADD1': '1'})
- output = self.execute('thread2-test')
- output = self._take_out(output, "adding 40 and 2\n")
- assert output == ("starting\n"
- "preparing...\n"
- "adding -1 and -1\n"
- "prepADD2\n"
- "adding 1000 and 200 and 30\n"
- "done\n")
-
- def test_load_in_parallel_more(self):
- add2_cffi = self.prepare_module('add2')
- add3_cffi = self.prepare_module('add3')
- self.compile('thread3-test', [add2_cffi, add3_cffi], threads=True)
- for i in range(150):
- output = self.execute('thread3-test')
- for j in range(10):
- output = self._take_out(output, "adding 40 and 2 and 100\n")
- output = self._take_out(output, "adding 1000, 200, 30, 4\n")
- assert output == ("starting\n"
- "prepADD2\n"
- "done\n")
diff --git a/testing/embedding/test_tlocal.py b/testing/embedding/test_tlocal.py
deleted file mode 100644
index 6e7c5af..0000000
--- a/testing/embedding/test_tlocal.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from testing.embedding.test_basic import EmbeddingTests
-
-
-class TestThreadLocal(EmbeddingTests):
- def test_thread_local(self):
- tlocal_cffi = self.prepare_module('tlocal')
- self.compile('tlocal-test', [tlocal_cffi], threads=True)
- for i in range(10):
- output = self.execute('tlocal-test')
- assert output == "done\n"
diff --git a/testing/embedding/thread-test.h b/testing/embedding/thread-test.h
deleted file mode 100644
index f66cf70..0000000
--- a/testing/embedding/thread-test.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/************************************************************/
-#ifndef _MSC_VER
-/************************************************************/
-
-
-#include <pthread.h>
-
-/* don't include <semaphore.h>, it is not available on OS/X */
-
-typedef struct {
- pthread_mutex_t mutex1;
- pthread_cond_t cond1;
- unsigned int value;
-} sem_t;
-
-static int sem_init(sem_t *sem, int pshared, unsigned int value)
-{
- assert(pshared == 0);
- sem->value = value;
- return (pthread_mutex_init(&sem->mutex1, NULL) ||
- pthread_cond_init(&sem->cond1, NULL));
-}
-
-static int sem_post(sem_t *sem)
-{
- pthread_mutex_lock(&sem->mutex1);
- sem->value += 1;
- pthread_cond_signal(&sem->cond1);
- pthread_mutex_unlock(&sem->mutex1);
- return 0;
-}
-
-static int sem_wait(sem_t *sem)
-{
- pthread_mutex_lock(&sem->mutex1);
- while (sem->value == 0)
- pthread_cond_wait(&sem->cond1, &sem->mutex1);
- sem->value -= 1;
- pthread_mutex_unlock(&sem->mutex1);
- return 0;
-}
-
-
-/************************************************************/
-#else
-/************************************************************/
-
-
-/* Very quick and dirty, just what I need for these tests.
- Don't use directly in any real code!
-*/
-
-#include <Windows.h>
-#include <assert.h>
-
-typedef HANDLE sem_t;
-typedef HANDLE pthread_t;
-
-static int sem_init(sem_t *sem, int pshared, unsigned int value)
-{
- assert(pshared == 0);
- assert(value == 0);
- *sem = CreateSemaphore(NULL, 0, 999, NULL);
- return *sem ? 0 : -1;
-}
-
-static int sem_post(sem_t *sem)
-{
- return ReleaseSemaphore(*sem, 1, NULL) ? 0 : -1;
-}
-
-static int sem_wait(sem_t *sem)
-{
- WaitForSingleObject(*sem, INFINITE);
- return 0;
-}
-
-static DWORD WINAPI myThreadProc(LPVOID lpParameter)
-{
- void *(* start_routine)(void *) = (void *(*)(void *))lpParameter;
- start_routine(NULL);
- return 0;
-}
-
-static int pthread_create(pthread_t *thread, void *attr,
- void *start_routine(void *), void *arg)
-{
- assert(arg == NULL);
- *thread = CreateThread(NULL, 0, myThreadProc, start_routine, 0, NULL);
- return *thread ? 0 : -1;
-}
-
-
-/************************************************************/
-#endif
-/************************************************************/
diff --git a/testing/embedding/thread1-test.c b/testing/embedding/thread1-test.c
deleted file mode 100644
index 70bb861..0000000
--- a/testing/embedding/thread1-test.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <stdio.h>
-#include <assert.h>
-#include "thread-test.h"
-
-#define NTHREADS 10
-
-
-extern int add1(int, int);
-
-static sem_t done;
-
-
-static void *start_routine(void *arg)
-{
- int x, status;
- x = add1(40, 2);
- assert(x == 42);
-
- status = sem_post(&done);
- assert(status == 0);
-
- return arg;
-}
-
-int main(void)
-{
- pthread_t th;
- int i, status = sem_init(&done, 0, 0);
- assert(status == 0);
-
- printf("starting\n");
- fflush(stdout);
- for (i = 0; i < NTHREADS; i++) {
- status = pthread_create(&th, NULL, start_routine, NULL);
- assert(status == 0);
- }
- for (i = 0; i < NTHREADS; i++) {
- status = sem_wait(&done);
- assert(status == 0);
- }
- printf("done\n");
- return 0;
-}
diff --git a/testing/embedding/thread2-test.c b/testing/embedding/thread2-test.c
deleted file mode 100644
index 62f5ec8..0000000
--- a/testing/embedding/thread2-test.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include <stdio.h>
-#include <assert.h>
-#include "thread-test.h"
-
-extern int add1(int, int);
-extern int add2(int, int, int);
-
-static sem_t done;
-
-
-static void *start_routine_1(void *arg)
-{
- int x, status;
- x = add1(40, 2);
- assert(x == 42);
-
- status = sem_post(&done);
- assert(status == 0);
-
- return arg;
-}
-
-static void *start_routine_2(void *arg)
-{
- int x, status;
-#ifdef T2TEST_AGAIN_ADD1
- add1(-1, -1);
-#endif
- x = add2(1000, 200, 30);
- assert(x == 1230);
-
- status = sem_post(&done);
- assert(status == 0);
-
- return arg;
-}
-
-int main(void)
-{
- pthread_t th;
- int i, status = sem_init(&done, 0, 0);
- assert(status == 0);
-
- printf("starting\n");
- fflush(stdout);
- status = pthread_create(&th, NULL, start_routine_1, NULL);
- assert(status == 0);
- status = pthread_create(&th, NULL, start_routine_2, NULL);
- assert(status == 0);
-
- for (i = 0; i < 2; i++) {
- status = sem_wait(&done);
- assert(status == 0);
- }
- printf("done\n");
- return 0;
-}
diff --git a/testing/embedding/thread3-test.c b/testing/embedding/thread3-test.c
deleted file mode 100644
index 69ada27..0000000
--- a/testing/embedding/thread3-test.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include <stdio.h>
-#include <assert.h>
-#include "thread-test.h"
-
-extern int add2(int, int, int);
-extern int add3(int, int, int, int);
-
-static sem_t done;
-
-
-static void *start_routine_2(void *arg)
-{
- int x, status;
- x = add2(40, 2, 100);
- assert(x == 142);
-
- status = sem_post(&done);
- assert(status == 0);
-
- return arg;
-}
-
-static void *start_routine_3(void *arg)
-{
- int x, status;
- x = add3(1000, 200, 30, 4);
- assert(x == 1234);
-
- status = sem_post(&done);
- assert(status == 0);
-
- return arg;
-}
-
-int main(void)
-{
- pthread_t th;
- int i, status = sem_init(&done, 0, 0);
- assert(status == 0);
-
- printf("starting\n");
- fflush(stdout);
- for (i = 0; i < 10; i++) {
- status = pthread_create(&th, NULL, start_routine_2, NULL);
- assert(status == 0);
- status = pthread_create(&th, NULL, start_routine_3, NULL);
- assert(status == 0);
- }
- for (i = 0; i < 20; i++) {
- status = sem_wait(&done);
- assert(status == 0);
- }
- printf("done\n");
- fflush(stdout); /* this is occasionally needed on Windows */
- return 0;
-}
diff --git a/testing/embedding/tlocal-test.c b/testing/embedding/tlocal-test.c
deleted file mode 100644
index b78a03d..0000000
--- a/testing/embedding/tlocal-test.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <stdio.h>
-#include <assert.h>
-#include "thread-test.h"
-
-#define NTHREADS 10
-
-
-extern int add1(int, int);
-
-static sem_t done;
-
-
-static void *start_routine(void *arg)
-{
- int i, x, expected, status;
-
- expected = add1(40, 2);
- assert((expected % 1000) == 42);
-
- for (i=0; i<10; i++) {
- x = add1(50, i);
- assert(x == expected + 8 + i);
- }
-
- status = sem_post(&done);
- assert(status == 0);
-
- return arg;
-}
-
-int main(void)
-{
- pthread_t th;
- int i, status = sem_init(&done, 0, 0);
- assert(status == 0);
-
- for (i = 0; i < NTHREADS; i++) {
- status = pthread_create(&th, NULL, start_routine, NULL);
- assert(status == 0);
- }
- for (i = 0; i < NTHREADS; i++) {
- status = sem_wait(&done);
- assert(status == 0);
- }
- printf("done\n");
- return 0;
-}
diff --git a/testing/embedding/tlocal.py b/testing/embedding/tlocal.py
deleted file mode 100644
index 7800dff..0000000
--- a/testing/embedding/tlocal.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import cffi
-
-ffi = cffi.FFI()
-
-ffi.embedding_api("""
- int add1(int, int);
-""")
-
-ffi.embedding_init_code(r"""
- from _tlocal_cffi import ffi
- import itertools
- try:
- import thread
- g_seen = itertools.count().next
- except ImportError:
- import _thread as thread # py3
- g_seen = itertools.count().__next__
- tloc = thread._local()
-
- @ffi.def_extern()
- def add1(x, y):
- try:
- num = tloc.num
- except AttributeError:
- num = tloc.num = g_seen() * 1000
- return x + y + num
-""")
-
-ffi.set_source("_tlocal_cffi", """
-""")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
diff --git a/testing/embedding/withunicode.py b/testing/embedding/withunicode.py
deleted file mode 100644
index 839c6cd..0000000
--- a/testing/embedding/withunicode.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import sys, cffi
-if sys.version_info < (3,):
- u_prefix = "u"
-else:
- u_prefix = ""
- unichr = chr
-
-
-ffi = cffi.FFI()
-
-ffi.embedding_api(u"""
- int add1(int, int);
-""")
-
-ffi.embedding_init_code(("""
- import sys, time
- for c in %s'""" + unichr(0x00ff) + unichr(0x1234) + unichr(0xfedc) + """':
- sys.stdout.write(str(ord(c)) + '\\n')
- sys.stdout.flush()
-""") % u_prefix)
-
-ffi.set_source("_withunicode_cffi", """
-""")
-
-fn = ffi.compile(verbose=True)
-print('FILENAME: %s' % (fn,))
diff --git a/testing/support.py b/testing/support.py
deleted file mode 100644
index 6339a94..0000000
--- a/testing/support.py
+++ /dev/null
@@ -1,119 +0,0 @@
-import sys, os
-
-if sys.version_info < (3,):
- __all__ = ['u', 'arraytostring']
-
- class U(object):
- def __add__(self, other):
- return eval('u'+repr(other).replace(r'\\u', r'\u')
- .replace(r'\\U', r'\U'))
- u = U()
- long = long # for further "from testing.support import long"
- assert u+'a\x00b' == eval(r"u'a\x00b'")
- assert u+'a\u1234b' == eval(r"u'a\u1234b'")
- assert u+'a\U00012345b' == eval(r"u'a\U00012345b'")
- def arraytostring(a):
- return a.tostring()
-
-else:
- __all__ = ['u', 'unicode', 'long', 'arraytostring']
- u = ""
- unicode = str
- long = int
- def arraytostring(a):
- return a.tobytes()
-
-
-class StdErrCapture(object):
- """Capture writes to sys.stderr (not to the underlying file descriptor)."""
- def __enter__(self):
- try:
- from StringIO import StringIO
- except ImportError:
- from io import StringIO
- self.old_stderr = sys.stderr
- sys.stderr = f = StringIO()
- if hasattr(sys, '__unraisablehook__'): # work around pytest
- self.old_unraisablebook = sys.unraisablehook # on recent CPythons
- sys.unraisablehook = sys.__unraisablehook__
- return f
- def __exit__(self, *args):
- sys.stderr = self.old_stderr
- if hasattr(self, 'old_unraisablebook'):
- sys.unraisablehook = self.old_unraisablebook
-
-
-class FdWriteCapture(object):
- """xxx limited to capture at most 512 bytes of output, according
- to the Posix manual."""
-
- def __init__(self, capture_fd=2): # stderr by default
- if sys.platform == 'win32':
- import py
- py.test.skip("seems not to work, too bad")
- self.capture_fd = capture_fd
-
- def __enter__(self):
- import os
- self.read_fd, self.write_fd = os.pipe()
- self.copy_fd = os.dup(self.capture_fd)
- os.dup2(self.write_fd, self.capture_fd)
- return self
-
- def __exit__(self, *args):
- import os
- os.dup2(self.copy_fd, self.capture_fd)
- os.close(self.copy_fd)
- os.close(self.write_fd)
- self._value = os.read(self.read_fd, 512)
- os.close(self.read_fd)
-
- def getvalue(self):
- return self._value
-
-def _verify(ffi, module_name, preamble, *args, **kwds):
- import imp
- from cffi.recompiler import recompile
- from .udir import udir
- assert module_name not in sys.modules, "module name conflict: %r" % (
- module_name,)
- kwds.setdefault('tmpdir', str(udir))
- outputfilename = recompile(ffi, module_name, preamble, *args, **kwds)
- module = imp.load_dynamic(module_name, outputfilename)
- #
- # hack hack hack: copy all *bound methods* from module.ffi back to the
- # ffi instance. Then calls like ffi.new() will invoke module.ffi.new().
- for name in dir(module.ffi):
- if not name.startswith('_'):
- attr = getattr(module.ffi, name)
- if attr is not getattr(ffi, name, object()):
- setattr(ffi, name, attr)
- def typeof_disabled(*args, **kwds):
- raise NotImplementedError
- ffi._typeof = typeof_disabled
- for name in dir(ffi):
- if not name.startswith('_') and not hasattr(module.ffi, name):
- setattr(ffi, name, NotImplemented)
- return module.lib
-
-
-# For testing, we call gcc with "-Werror". This is fragile because newer
-# versions of gcc are always better at producing warnings, particularly for
-# auto-generated code. We need here to adapt and silence them as needed.
-
-if sys.platform == 'win32':
- extra_compile_args = [] # no obvious -Werror equivalent on MSVC
-else:
- if (sys.platform == 'darwin' and
- [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]):
- # assume a standard clang or gcc
- extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion',
- '-Wno-unused-parameter',
- '-Wno-unreachable-code']
- # special things for clang
- extra_compile_args.append('-Qunused-arguments')
- else:
- # assume a standard gcc
- extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion',
- '-Wno-unused-parameter',
- '-Wno-unreachable-code']
diff --git a/testing/udir.py b/testing/udir.py
deleted file mode 100644
index 59db1c4..0000000
--- a/testing/udir.py
+++ /dev/null
@@ -1,140 +0,0 @@
-import py
-import sys, os, atexit
-
-
-# This is copied from PyPy's vendored py lib. The latest py lib release
-# (1.8.1) contains a bug and crashes if it sees another temporary directory
-# in which we don't have write permission (e.g. because it's owned by someone
-# else).
-def make_numbered_dir(prefix='session-', rootdir=None, keep=3,
- lock_timeout = 172800, # two days
- min_timeout = 300): # five minutes
- """ return unique directory with a number greater than the current
- maximum one. The number is assumed to start directly after prefix.
- if keep is true directories with a number less than (maxnum-keep)
- will be removed.
- """
- if rootdir is None:
- rootdir = py.path.local.get_temproot()
-
- def parse_num(path):
- """ parse the number out of a path (if it matches the prefix) """
- bn = path.basename
- if bn.startswith(prefix):
- try:
- return int(bn[len(prefix):])
- except ValueError:
- pass
-
- # compute the maximum number currently in use with the
- # prefix
- lastmax = None
- while True:
- maxnum = -1
- for path in rootdir.listdir():
- num = parse_num(path)
- if num is not None:
- maxnum = max(maxnum, num)
-
- # make the new directory
- try:
- udir = rootdir.mkdir(prefix + str(maxnum+1))
- except py.error.EEXIST:
- # race condition: another thread/process created the dir
- # in the meantime. Try counting again
- if lastmax == maxnum:
- raise
- lastmax = maxnum
- continue
- break
-
- # put a .lock file in the new directory that will be removed at
- # process exit
- if lock_timeout:
- lockfile = udir.join('.lock')
- mypid = os.getpid()
- if hasattr(lockfile, 'mksymlinkto'):
- lockfile.mksymlinkto(str(mypid))
- else:
- lockfile.write(str(mypid))
- def try_remove_lockfile():
- # in a fork() situation, only the last process should
- # remove the .lock, otherwise the other processes run the
- # risk of seeing their temporary dir disappear. For now
- # we remove the .lock in the parent only (i.e. we assume
- # that the children finish before the parent).
- if os.getpid() != mypid:
- return
- try:
- lockfile.remove()
- except py.error.Error:
- pass
- atexit.register(try_remove_lockfile)
-
- # prune old directories
- if keep:
- for path in rootdir.listdir():
- num = parse_num(path)
- if num is not None and num <= (maxnum - keep):
- if min_timeout:
- # NB: doing this is needed to prevent (or reduce
- # a lot the chance of) the following situation:
- # 'keep+1' processes call make_numbered_dir() at
- # the same time, they create dirs, but then the
- # last process notices the first dir doesn't have
- # (yet) a .lock in it and kills it.
- try:
- t1 = path.lstat().mtime
- t2 = lockfile.lstat().mtime
- if abs(t2-t1) < min_timeout:
- continue # skip directories too recent
- except py.error.Error:
- continue # failure to get a time, better skip
- lf = path.join('.lock')
- try:
- t1 = lf.lstat().mtime
- t2 = lockfile.lstat().mtime
- if not lock_timeout or abs(t2-t1) < lock_timeout:
- continue # skip directories still locked
- except py.error.Error:
- pass # assume that it means that there is no 'lf'
- try:
- path.remove(rec=1)
- except KeyboardInterrupt:
- raise
- except: # this might be py.error.Error, WindowsError ...
- pass
-
- # make link...
- try:
- username = os.environ['USER'] #linux, et al
- except KeyError:
- try:
- username = os.environ['USERNAME'] #windows
- except KeyError:
- username = 'current'
-
- src = str(udir)
- dest = src[:src.rfind('-')] + '-' + username
- try:
- os.unlink(dest)
- except OSError:
- pass
- try:
- os.symlink(src, dest)
- except (OSError, AttributeError, NotImplementedError):
- pass
-
- return udir
-
-
-udir = make_numbered_dir(prefix = 'ffi-')
-
-
-# Windows-only workaround for some configurations: see
-# https://bugs.python.org/issue23246 (Python 2.7.9)
-if sys.platform == 'win32':
- try:
- import setuptools
- except ImportError:
- pass